From: Rob Browning Date: Sun, 26 Sep 2021 21:20:06 +0000 (-0500) Subject: index.Reader.__del__: replace with context management X-Git-Url: https://arthur.ath.cx/gitweb/?a=commitdiff_plain;h=ce50c0b3537327b2ec0bfda031cc4ec99e2ca870;p=bup.git index.Reader.__del__: replace with context management Signed-off-by: Rob Browning Tested-by: Rob Browning --- diff --git a/lib/bup/cmd/index.py b/lib/bup/cmd/index.py index d79cb21..cc542e6 100755 --- a/lib/bup/cmd/index.py +++ b/lib/bup/cmd/index.py @@ -73,12 +73,12 @@ def update_index(top, excluded_paths, exclude_rxs, indexfile, out=None, verbose=0): # tmax must be epoch nanoseconds. tmax = (time.time() - 1) * 10**9 - ri = index.Reader(indexfile) - rig = IterHelper(ri.iter(name=top)) with index.MetaStoreWriter(indexfile + b'.meta') as msw, \ - hlinkdb.HLinkDB(indexfile + b'.hlink') as hlinks: + hlinkdb.HLinkDB(indexfile + b'.hlink') as hlinks, \ + index.Reader(indexfile) as ri: + rig = IterHelper(ri.iter(name=top)) wi = index.Writer(indexfile, msw, tmax) fake_hash = None @@ -180,22 +180,20 @@ def update_index(top, excluded_paths, exclude_rxs, indexfile, ri.save() wi.flush() if wi.count: - wr = wi.new_reader() - if check: - log('check: before merging: oldfile\n') - check_index(ri, verbose) - log('check: before merging: newfile\n') - check_index(wr, verbose) - mi = index.Writer(indexfile, msw, tmax) - - for e in index.merge(ri, wr): - # FIXME: shouldn't we remove deleted entries - # eventually? When? - mi.add_ixentry(e) - - ri.close() - mi.close() - wr.close() + with wi.new_reader() as wr: + if check: + log('check: before merging: oldfile\n') + check_index(ri, verbose) + log('check: before merging: newfile\n') + check_index(wr, verbose) + mi = index.Writer(indexfile, msw, tmax) + + for e in index.merge(ri, wr): + # FIXME: shouldn't we remove deleted entries + # eventually? When? + mi.add_ixentry(e) + + mi.close() wi.abort() else: wi.close() @@ -267,7 +265,8 @@ def main(argv): if opt.check: log('check: starting initial check.\n') - check_index(index.Reader(indexfile), opt.verbose) + with index.Reader(indexfile) as reader: + check_index(reader, opt.verbose) if opt.clear: log('clear: clearing index.\n') @@ -293,31 +292,33 @@ def main(argv): if opt['print'] or opt.status or opt.modified: extra = [argv_bytes(x) for x in extra] - for name, ent in index.Reader(indexfile).filter(extra or [b'']): - if (opt.modified - and (ent.is_valid() or ent.is_deleted() or not ent.mode)): - continue - line = b'' - if opt.status: - if ent.is_deleted(): - line += b'D ' - elif not ent.is_valid(): - if ent.sha == index.EMPTY_SHA: - line += b'A ' + with index.Reader(indexfile) as reader: + for name, ent in reader.filter(extra or [b'']): + if (opt.modified + and (ent.is_valid() or ent.is_deleted() or not ent.mode)): + continue + line = b'' + if opt.status: + if ent.is_deleted(): + line += b'D ' + elif not ent.is_valid(): + if ent.sha == index.EMPTY_SHA: + line += b'A ' + else: + line += b'M ' else: - line += b'M ' - else: - line += b' ' - if opt.hash: - line += hexlify(ent.sha) + b' ' - if opt.long: - line += b'%7s %7s ' % (oct(ent.mode).encode('ascii'), - oct(ent.gitmode).encode('ascii')) - out.write(line + (name or b'./') + b'\n') + line += b' ' + if opt.hash: + line += hexlify(ent.sha) + b' ' + if opt.long: + line += b'%7s %7s ' % (oct(ent.mode).encode('ascii'), + oct(ent.gitmode).encode('ascii')) + out.write(line + (name or b'./') + b'\n') if opt.check and (opt['print'] or opt.status or opt.modified or opt.update): log('check: starting final check.\n') - check_index(index.Reader(indexfile), opt.verbose) + with index.Reader(indexfile) as reader: + check_index(reader, opt.verbose) if saved_errors: log('WARNING: %d errors encountered.\n' % len(saved_errors)) diff --git a/lib/bup/cmd/save.py b/lib/bup/cmd/save.py index 1153cd5..4deef5d 100755 --- a/lib/bup/cmd/save.py +++ b/lib/bup/cmd/save.py @@ -109,7 +109,7 @@ def opts_from_cmdline(argv): return opt -def save_tree(opt, indexfile, hlink_db, msr, w): +def save_tree(opt, reader, hlink_db, msr, w): # Metadata is stored in a file named .bupm in each directory. The # first metadata entry will be the metadata for the current directory. # The remaining entries will be for each of the other directory @@ -241,11 +241,10 @@ def save_tree(opt, indexfile, hlink_db, msr, w): return link_paths[0] return None - r = index.Reader(indexfile) total = ftotal = 0 if opt.progress: - for transname, ent in r.filter(opt.sources, - wantrecurse=wantrecurse_pre): + for transname, ent in reader.filter(opt.sources, + wantrecurse=wantrecurse_pre): if not (ftotal % 10024): qprogress('Reading index: %d\r' % ftotal) exists = ent.exists() @@ -275,7 +274,8 @@ def save_tree(opt, indexfile, hlink_db, msr, w): fcount = 0 lastskip_name = None lastdir = b'' - for transname, ent in r.filter(opt.sources, wantrecurse=wantrecurse_during): + for transname, ent in reader.filter(opt.sources, + wantrecurse=wantrecurse_during): (dir, file) = os.path.split(ent.name) exists = (ent.flags & index.IX_EXISTS) hashvalid = already_saved(ent) @@ -518,8 +518,10 @@ def main(argv): log('error: cannot access %r; have you run bup index?' % path_msg(indexfile)) sys.exit(1) - with msr, hlinkdb.HLinkDB(indexfile + b'.hlink') as hlink_db: - tree = save_tree(opt, indexfile, hlink_db, msr, w) + with msr, \ + hlinkdb.HLinkDB(indexfile + b'.hlink') as hlink_db, \ + index.Reader(indexfile) as reader: + tree = save_tree(opt, reader, hlink_db, msr, w) if opt.tree: out.write(hexlify(tree)) out.write(b'\n') diff --git a/lib/bup/index.py b/lib/bup/index.py index d0df52a..e7214d1 100644 --- a/lib/bup/index.py +++ b/lib/bup/index.py @@ -439,8 +439,12 @@ class Reader: self.m[st.st_size - FOOTLEN : st.st_size])[0] - def __del__(self): - self.close() + def __enter__(self): + return self + + def __exit__(self, type, value, traceback): + with pending_raise(value, rethrow=False): + self.close() def __len__(self): return int(self.count) diff --git a/test/int/test_index.py b/test/int/test_index.py index c71b90f..6d97127 100644 --- a/test/int/test_index.py +++ b/test/int/test_index.py @@ -118,57 +118,54 @@ def test_index_dirty(tmpdir): #w3.close() WVPASS() - r1 = w1.new_reader() - r2 = w2.new_reader() - r3 = w3.new_reader() - WVPASS() - - r1all = [e.name for e in r1] - WVPASSEQ(r1all, - [b'/a/b/x', b'/a/b/c', b'/a/b/', b'/a/', b'/']) - r2all = [e.name for e in r2] - WVPASSEQ(r2all, - [b'/a/b/n/2', b'/a/b/n/', b'/a/b/', b'/a/', b'/']) - r3all = [e.name for e in r3] - WVPASSEQ(r3all, - [b'/a/c/n/3', b'/a/c/n/', b'/a/c/', b'/a/', b'/']) - all = [e.name for e in index.merge(r2, r1, r3)] - WVPASSEQ(all, - [b'/a/c/n/3', b'/a/c/n/', b'/a/c/', - b'/a/b/x', b'/a/b/n/2', b'/a/b/n/', b'/a/b/c', - b'/a/b/', b'/a/', b'/']) - fake_validate(r1) - dump(r1) - - print([hex(e.flags) for e in r1]) - WVPASSEQ([e.name for e in r1 if e.is_valid()], r1all) - WVPASSEQ([e.name for e in r1 if not e.is_valid()], []) - WVPASSEQ([e.name for e in index.merge(r2, r1, r3) if not e.is_valid()], - [b'/a/c/n/3', b'/a/c/n/', b'/a/c/', - b'/a/b/n/2', b'/a/b/n/', b'/a/b/', b'/a/', b'/']) - - expect_invalid = [b'/'] + r2all + r3all - expect_real = (set(r1all) - set(r2all) - set(r3all)) \ - | set([b'/a/b/n/2', b'/a/c/n/3']) - dump(index.merge(r2, r1, r3)) - for e in index.merge(r2, r1, r3): - print(e.name, hex(e.flags), e.ctime) - eiv = e.name in expect_invalid - er = e.name in expect_real - WVPASSEQ(eiv, not e.is_valid()) - WVPASSEQ(er, e.is_real()) - fake_validate(r2, r3) - dump(index.merge(r2, r1, r3)) - WVPASSEQ([e.name for e in index.merge(r2, r1, r3) if not e.is_valid()], []) - - e = eget(index.merge(r2, r1, r3), b'/a/b/c') - e.invalidate() - e.repack() - dump(index.merge(r2, r1, r3)) - WVPASSEQ([e.name for e in index.merge(r2, r1, r3) if not e.is_valid()], - [b'/a/b/c', b'/a/b/', b'/a/', b'/']) - w1.close() - w2.close() - w3.close() + with w1.new_reader() as r1, \ + w2.new_reader() as r2, \ + w3.new_reader() as r3: + WVPASS() + + r1all = [e.name for e in r1] + WVPASSEQ(r1all, + [b'/a/b/x', b'/a/b/c', b'/a/b/', b'/a/', b'/']) + r2all = [e.name for e in r2] + WVPASSEQ(r2all, + [b'/a/b/n/2', b'/a/b/n/', b'/a/b/', b'/a/', b'/']) + r3all = [e.name for e in r3] + WVPASSEQ(r3all, + [b'/a/c/n/3', b'/a/c/n/', b'/a/c/', b'/a/', b'/']) + all = [e.name for e in index.merge(r2, r1, r3)] + WVPASSEQ(all, + [b'/a/c/n/3', b'/a/c/n/', b'/a/c/', + b'/a/b/x', b'/a/b/n/2', b'/a/b/n/', b'/a/b/c', + b'/a/b/', b'/a/', b'/']) + fake_validate(r1) + dump(r1) + + print([hex(e.flags) for e in r1]) + WVPASSEQ([e.name for e in r1 if e.is_valid()], r1all) + WVPASSEQ([e.name for e in r1 if not e.is_valid()], []) + WVPASSEQ([e.name for e in index.merge(r2, r1, r3) if not e.is_valid()], + [b'/a/c/n/3', b'/a/c/n/', b'/a/c/', + b'/a/b/n/2', b'/a/b/n/', b'/a/b/', b'/a/', b'/']) + + expect_invalid = [b'/'] + r2all + r3all + expect_real = (set(r1all) - set(r2all) - set(r3all)) \ + | set([b'/a/b/n/2', b'/a/c/n/3']) + dump(index.merge(r2, r1, r3)) + for e in index.merge(r2, r1, r3): + print(e.name, hex(e.flags), e.ctime) + eiv = e.name in expect_invalid + er = e.name in expect_real + WVPASSEQ(eiv, not e.is_valid()) + WVPASSEQ(er, e.is_real()) + fake_validate(r2, r3) + dump(index.merge(r2, r1, r3)) + WVPASSEQ([e.name for e in index.merge(r2, r1, r3) if not e.is_valid()], []) + + e = eget(index.merge(r2, r1, r3), b'/a/b/c') + e.invalidate() + e.repack() + dump(index.merge(r2, r1, r3)) + WVPASSEQ([e.name for e in index.merge(r2, r1, r3) if not e.is_valid()], + [b'/a/b/c', b'/a/b/', b'/a/', b'/']) finally: os.chdir(orig_cwd)