]> git.wh0rd.org - home.git/blobdiff - .bin/git-repack
git-repack: make it python3-only
[home.git] / .bin / git-repack
index d218a99944482f651032c924596f3172e2b18708..82f8f17ced5c86d72f726eba77fc430b0beae739 100755 (executable)
@@ -1,4 +1,7 @@
-#!/usr/bin/python
+#!/usr/bin/python3
+
+# pylint: disable=fixme,invalid-name
+# pylint: disable=too-many-branches,too-many-locals,too-many-statements
 
 """Repack git repos fully the way I like them."""
 
@@ -23,6 +26,13 @@ def mount_settings():
     return ret
 
 
+def is_git_dir(path):
+    """Whether |path| is a .git dir"""
+    return (os.path.isdir(os.path.join(path, 'refs')) and
+            os.path.isdir(os.path.join(path, 'objects')) and
+            os.path.isfile(os.path.join(path, 'config')))
+
+
 def find_git_dir(path):
     """Try to find the .git dir to operate on"""
     orig_path = path
@@ -32,9 +42,7 @@ def find_git_dir(path):
         if os.path.isdir(os.path.join(path, '.git')):
             curr_path = os.path.join(path, '.git')
 
-        if (os.path.isdir(os.path.join(curr_path, 'refs')) and
-            os.path.isdir(os.path.join(curr_path, 'objects')) and
-            os.path.isfile(os.path.join(curr_path, 'config'))):
+        if is_git_dir(curr_path):
             return curr_path
 
         path = os.path.dirname(path)
@@ -62,7 +70,9 @@ def find_temp_dir():
 def readfile(path):
     """Read |path| and return its data"""
     if os.path.isfile(path):
-        return open(path).read()
+        with open(path) as fp:
+            return fp.read()
+    return ''
 
 
 def unlink(path):
@@ -89,9 +99,11 @@ def clean_packs(path):
 
 def is_packed(path):
     """See if the git repo is already packed"""
-    if set(('info', 'pack')) != set(os.listdir(path)):
+    obj_path = os.path.join(path, 'objects')
+    paths = set(os.listdir(obj_path))
+    if paths not in ({'info', 'pack'}, {'pack'}):
         return False
-    packs = os.listdir(os.path.join(path, 'pack'))
+    packs = os.listdir(os.path.join(obj_path, 'pack'))
     if len(packs) != 2:
         return False
     return True
@@ -102,11 +114,23 @@ def repack(path):
     path = find_git_dir(path)
     print('Repacking %s' % path)
 
+    # Repack any submodules this project might use.
+    modules_path = os.path.join(path, 'modules')
+    if os.path.isdir(modules_path):
+        for root, dirs, _ in os.walk(modules_path):
+            dirs.sort()
+            for d in dirs:
+                mod_path = os.path.join(root, d)
+                if is_git_dir(mod_path):
+                    repack(mod_path)
+
     tmpdir = find_temp_dir()
     if tmpdir:
         tmpdir = tempfile.mkdtemp(prefix='git-repack.', dir=tmpdir)
         print('Using tempdir: %s' % tmpdir)
         os.rmdir(tmpdir)
+        # Doesn't matter for these needs.
+        os.environ['GIT_WORK_TREE'] = tmpdir
 
     grafts = alts = None
     try:
@@ -122,11 +146,12 @@ def repack(path):
 
         clean_hooks(path)
 
+        # XXX: Should do this for all remotes?
         origin_path = os.path.join(path, 'refs', 'remotes', 'origin')
         packed_refs = readfile(os.path.join(path, 'packed-refs'))
         if os.path.exists(origin_path) or 'refs/remotes/origin/' in packed_refs:
             cmd = ['git', '--git-dir', path, 'remote', 'prune', 'origin']
-            subprocess.check_call(cmd, cwd='/')
+            subprocess.run(cmd, cwd='/', check=True)
 
         clean_packs(path)
 
@@ -141,25 +166,39 @@ def repack(path):
         else:
             rundir = path
 
+        cmd = ['git', '--git-dir', rundir, 'reflog', 'expire', '--all', '--stale-fix']
+        print('Cleaning reflog: %s' % ' '.join(cmd))
+        subprocess.run(cmd, cwd='/', check=True)
+
         # This also packs refs/tags for us.
         cmd = ['git', '--git-dir', rundir, 'gc', '--aggressive', '--prune=all']
         print('Repacking git repo: %s' % ' '.join(cmd))
-        subprocess.check_call(cmd, cwd='/')
+        subprocess.run(cmd, cwd='/', check=True)
+
+        # Clean empty dirs.
+        cmd = ['find', rundir, '-depth', '-type', 'd', '-exec', 'rmdir', '{}', '+']
+        subprocess.call(cmd, stderr=subprocess.DEVNULL)
+
+        # There's a few dirs we need to exist even if they're empty.
+        refdir = os.path.join(rundir, 'refs')
+        os.makedirs(refdir, exist_ok=True)
 
         if tmpdir:
             cmd = ['rsync', '-a', '--delete', tmpdir + '/', path + '/']
             print('Syncing back git repo: %s' % ' '.join(cmd))
-            subprocess.check_call(cmd, cwd='/')
+            subprocess.run(cmd, cwd='/', check=True)
             cmd = ['find', path + '/', '-exec', 'chmod', 'u+rw', '{}', '+']
-            subprocess.check_call(cmd, cwd='/')
+            subprocess.run(cmd, cwd='/', check=True)
 
     finally:
         if grafts:
-            open(graft_file, 'w').write(grafts)
+            with open(graft_file, 'w') as fp:
+                fp.write(grafts)
         if alts:
-            open(alt_file, 'w').write(alts)
+            with open(alt_file, 'w') as fp:
+                fp.write(alts)
         if tmpdir:
-            shutil.rmtree(tmpdir)
+            shutil.rmtree(tmpdir, ignore_errors=True)
 
 
 def get_parser():