]> arthur.barton.de Git - bup.git/blobdiff - lib/bup/cmd/midx.py
PackMidx.__del__: replace with context management
[bup.git] / lib / bup / cmd / midx.py
index 3e764e6a9082793b5f5ec56f2fc1992702c054e6..9d3b6372bacdbfe622da205513c49006e91465bf 100755 (executable)
@@ -1,12 +1,12 @@
 
 from __future__ import absolute_import, print_function
 from binascii import hexlify
-import glob, os, math, resource, struct, sys, tempfile
+import glob, os, math, resource, struct, sys
 
 from bup import options, git, midx, _helpers, xstat
-from bup.compat import argv_bytes, hexstr, range
+from bup.compat import ExitStack, argv_bytes, hexstr, range
 from bup.helpers import (Sha1, add_error, atomically_replaced_file, debug1, fdatasync,
-                         handle_ctrl_c, log, mmap_readwrite, qprogress,
+                         log, mmap_readwrite, qprogress,
                          saved_errors, unlink)
 from bup.io import byte_stream, path_msg
 
@@ -51,32 +51,34 @@ def check_midx(name):
     except git.GitError as e:
         add_error('%s: %s' % (path_msg(name), e))
         return
-    for count,subname in enumerate(ix.idxnames):
-        sub = git.open_idx(os.path.join(os.path.dirname(name), subname))
-        for ecount,e in enumerate(sub):
+    with ix:
+        for count,subname in enumerate(ix.idxnames):
+            with git.open_idx(os.path.join(os.path.dirname(name), subname)) \
+                 as sub:
+                for ecount,e in enumerate(sub):
+                    if not (ecount % 1234):
+                        qprogress('  %d/%d: %s %d/%d\r'
+                                  % (count, len(ix.idxnames),
+                                     git.shorten_hash(subname).decode('ascii'),
+                                     ecount, len(sub)))
+                    if not sub.exists(e):
+                        add_error("%s: %s: %s missing from idx"
+                                  % (path_msg(nicename),
+                                     git.shorten_hash(subname).decode('ascii'),
+                                     hexstr(e)))
+                    if not ix.exists(e):
+                        add_error("%s: %s: %s missing from midx"
+                                  % (path_msg(nicename),
+                                     git.shorten_hash(subname).decode('ascii'),
+                                     hexstr(e)))
+        prev = None
+        for ecount,e in enumerate(ix):
             if not (ecount % 1234):
-                qprogress('  %d/%d: %s %d/%d\r' 
-                          % (count, len(ix.idxnames),
-                             git.shorten_hash(subname).decode('ascii'),
-                             ecount, len(sub)))
-            if not sub.exists(e):
-                add_error("%s: %s: %s missing from idx"
-                          % (path_msg(nicename),
-                             git.shorten_hash(subname).decode('ascii'),
-                             hexstr(e)))
-            if not ix.exists(e):
-                add_error("%s: %s: %s missing from midx"
-                          % (path_msg(nicename),
-                             git.shorten_hash(subname).decode('ascii'),
-                             hexstr(e)))
-    prev = None
-    for ecount,e in enumerate(ix):
-        if not (ecount % 1234):
-            qprogress('  Ordering: %d/%d\r' % (ecount, len(ix)))
-        if e and prev and not e >= prev:
-            add_error('%s: ordering error: %s < %s'
-                      % (nicename, hexstr(e), hexstr(prev)))
-        prev = e
+                qprogress('  Ordering: %d/%d\r' % (ecount, len(ix)))
+            if e and prev and not e >= prev:
+                add_error('%s: ordering error: %s < %s'
+                          % (nicename, hexstr(e), hexstr(prev)))
+            prev = e
 
 
 _first = None
@@ -87,15 +89,14 @@ def _do_midx(outdir, outfilename, infilenames, prefixstr,
         assert(outdir)
         sum = hexlify(Sha1(b'\0'.join(infilenames)).digest())
         outfilename = b'%s/midx-%s.midx' % (outdir, sum)
-    
+
     inp = []
     total = 0
     allfilenames = []
-    midxs = []
-    try:
+    with ExitStack() as contexts:
         for name in infilenames:
             ix = git.open_idx(name)
-            midxs.append(ix)
+            contexts.enter_context(ix)
             inp.append((
                 ix.map,
                 len(ix),
@@ -116,7 +117,7 @@ def _do_midx(outdir, outfilename, infilenames, prefixstr,
            or ((auto or force) and len(infilenames) < 2) \
            or (force and not total):
             debug1('midx: nothing to do.\n')
-            return
+            return None
 
         pages = int(total/SHA_PER_PAGE) or 1
         bits = int(math.ceil(math.log(pages, 2)))
@@ -133,29 +134,21 @@ def _do_midx(outdir, outfilename, infilenames, prefixstr,
             f.flush()
             fdatasync(f.fileno())
 
-            fmap = mmap_readwrite(f, close=False)
-            count = merge_into(fmap, bits, total, inp)
-            del fmap # Assume this calls msync() now.
+            with mmap_readwrite(f, close=False) as fmap:
+                count = merge_into(fmap, bits, total, inp)
             f.seek(0, os.SEEK_END)
             f.write(b'\0'.join(allfilenames))
-    finally:
-        for ix in midxs:
-            if isinstance(ix, midx.PackMidx):
-                ix.close()
-        midxs = None
-        inp = None
-
 
     # This is just for testing (if you enable this, don't clear inp above)
-    if 0:
-        p = midx.PackMidx(outfilename)
-        assert(len(p.idxnames) == len(infilenames))
-        log(repr(p.idxnames) + '\n')
-        assert(len(p) == total)
-        for pe, e in p, git.idxmerge(inp, final_progress=False):
-            pin = next(pi)
-            assert(i == pin)
-            assert(p.exists(i))
+    if 0:
+        p = midx.PackMidx(outfilename)
+        assert(len(p.idxnames) == len(infilenames))
+        log(repr(p.idxnames) + '\n')
+        assert(len(p) == total)
+        for pe, e in p, git.idxmerge(inp, final_progress=False):
+            pin = next(pi)
+            assert(i == pin)
+            assert(p.exists(i))
 
     return total, outfilename
 
@@ -178,14 +171,14 @@ def do_midx_dir(path, outfilename, prout, auto=False, force=False,
         midxs = glob.glob(b'%s/*.midx' % path)
         contents = {}
         for mname in midxs:
-            m = git.open_idx(mname)
-            contents[mname] = [(b'%s/%s' % (path,i)) for i in m.idxnames]
-            sizes[mname] = len(m)
-                    
+            with git.open_idx(mname) as m:
+                contents[mname] = [(b'%s/%s' % (path,i)) for i in m.idxnames]
+                sizes[mname] = len(m)
+
         # sort the biggest+newest midxes first, so that we can eliminate
         # smaller (or older) redundant ones that come later in the list
         midxs.sort(key=lambda ix: (-sizes[ix], -xstat.stat(ix).st_mtime))
-        
+
         for mname in midxs:
             any = 0
             for iname in contents[mname]:
@@ -201,16 +194,16 @@ def do_midx_dir(path, outfilename, prout, auto=False, force=False,
     idxs = [k for k in glob.glob(b'%s/*.idx' % path) if not already.get(k)]
 
     for iname in idxs:
-        i = git.open_idx(iname)
-        sizes[iname] = len(i)
+        with git.open_idx(iname) as i:
+            sizes[iname] = len(i)
 
     all = [(sizes[n],n) for n in (midxs + idxs)]
-    
+
     # FIXME: what are the optimal values?  Does this make sense?
     DESIRED_HWM = force and 1 or 5
     DESIRED_LWM = force and 1 or 2
     existed = dict((name,1) for sz,name in all)
-    debug1('midx: %d indexes; want no more than %d.\n' 
+    debug1('midx: %d indexes; want no more than %d.\n'
            % (len(all), DESIRED_HWM))
     if len(all) <= DESIRED_HWM:
         debug1('midx: nothing to do.\n')
@@ -247,7 +240,6 @@ def do_midx_group(outdir, outfilename, infiles, auto=False, force=False,
 def main(argv):
     o = options.Options(optspec)
     opt, flags, extra = o.parse_bytes(argv[1:])
-    opt.dir = argv_bytes(opt.dir) if opt.dir else None
     opt.output = argv_bytes(opt.output) if opt.output else None
 
     if extra and (opt.auto or opt.force):
@@ -261,6 +253,8 @@ def main(argv):
         opt.max_files = max_files()
     assert(opt.max_files >= 5)
 
+    path = opt.dir and argv_bytes(opt.dir) or git.repo(b'objects/pack')
+
     extra = [argv_bytes(x) for x in extra]
 
     if opt.check:
@@ -268,7 +262,6 @@ def main(argv):
         if extra:
             midxes = extra
         else:
-            path = opt.dir or git.repo(b'objects/pack')
             debug1('midx: scanning %s\n' % path)
             midxes = glob.glob(os.path.join(path, b'*.midx'))
         for name in midxes:
@@ -278,12 +271,11 @@ def main(argv):
     else:
         if extra:
             sys.stdout.flush()
-            do_midx(git.repo(b'objects/pack'), opt.output, extra, b'',
+            do_midx(path, opt.output, extra, b'',
                     byte_stream(sys.stdout), auto=opt.auto, force=opt.force,
                     print_names=opt.print)
         elif opt.auto or opt.force:
             sys.stdout.flush()
-            path = opt.dir or git.repo(b'objects/pack')
             debug1('midx: scanning %s\n' % path_msg(path))
             do_midx_dir(path, opt.output, byte_stream(sys.stdout),
                         auto=opt.auto, force=opt.force,