]> arthur.barton.de Git - bup.git/commitdiff
Fix compatibility with git 1.5.4.3 (Ubuntu Hardy).
authorAvery Pennarun <apenwarr@gmail.com>
Wed, 6 Jan 2010 03:21:18 +0000 (22:21 -0500)
committerAvery Pennarun <apenwarr@gmail.com>
Wed, 6 Jan 2010 03:21:18 +0000 (22:21 -0500)
Thanks to Andy Chong for reporting the problem.

Basically it comes down to two things that are missing in that version but
exist in git 1.5.6:

  - git init --bare doesn't work, but git --bare init does.
  - git cat-file --batch doesn't exist in that version.

Unfortunately, the latter problem is pretty serious; bup join is really slow
without it.  I guess it might be time to implement an internal version of
cat-file.

git.py
test-sh

diff --git a/git.py b/git.py
index a7e81c5c3f0b4afbfb9f5551b84db1385a9fb5cd..3138f6eb80f5dc7056b461f7ccfdce2f9c7b6745 100644 (file)
--- a/git.py
+++ b/git.py
@@ -1,4 +1,4 @@
-import os, errno, zlib, time, sha, subprocess, struct, mmap, stat
+import os, errno, zlib, time, sha, subprocess, struct, mmap, stat, re
 from helpers import *
 
 verbose = 0
@@ -237,8 +237,9 @@ class PackWriter:
                              preexec_fn = _gitenv,
                              stdout = subprocess.PIPE)
         out = p.stdout.read().strip()
-        if p.wait() or not out:
-            raise GitError('git index-pack returned an error')
+        _git_wait('git index-pack', p)
+        if not out:
+            raise GitError('git index-pack produced no output')
         nameprefix = repo('objects/pack/%s' % out)
         os.rename(self.filename + '.pack', nameprefix + '.pack')
         os.rename(self.filename + '.idx', nameprefix + '.idx')
@@ -285,7 +286,7 @@ def read_ref(refname):
                          preexec_fn = _gitenv,
                          stdout = subprocess.PIPE)
     out = p.stdout.read().strip()
-    rv = p.wait()
+    rv = p.wait()  # not fatal
     if rv:
         assert(not out)
     if out:
@@ -300,9 +301,7 @@ def update_ref(refname, newval, oldval):
     p = subprocess.Popen(['git', 'update-ref', '--', refname,
                           newval.encode('hex'), oldval.encode('hex')],
                          preexec_fn = _gitenv)
-    rv = p.wait()
-    if rv:
-        raise GitError('update_ref returned error code %d' % rv)
+    _git_wait('git update-ref', p)
 
 
 def guess_repo(path=None):
@@ -322,9 +321,10 @@ def init_repo(path=None):
         raise GitError('"%d" exists but is not a directory\n' % d)
     p = subprocess.Popen(['git', '--bare', 'init'], stdout=sys.stderr,
                          preexec_fn = _gitenv)
-    rv = p.wait()
-    if rv != 0:
-        raise GitError('git init returned %d\n' % rv)
+    _git_wait('git init', p)
+    p = subprocess.Popen(['git', 'config', 'pack.indexVersion', '2'],
+                         stdout=sys.stderr, preexec_fn = _gitenv)
+    _git_wait('git config', p)
 
 
 def check_repo_or_die(path=None):
@@ -348,17 +348,60 @@ def _treeparse(buf):
         ofs += z+1+20
         yield (spl[0], spl[1], sha)
 
+_ver = None
+def ver():
+    global _ver
+    if not _ver:
+        p = subprocess.Popen(['git', '--version'],
+                             stdout=subprocess.PIPE)
+        gvs = p.stdout.read()
+        _git_wait('git --version', p)
+        m = re.match(r'git version (\S+.\S+)', gvs)
+        if not m:
+            raise GitError('git --version weird output: %r' % gvs)
+        _ver = tuple(m.group(1).split('.'))
+    needed = ('1','5','4')
+    if _ver < needed:
+        raise GitError('git version %s or higher is required; you have %s'
+                       % ('.'.join(needed), '.'.join(_ver)))
+    return _ver
+
+
+def _git_wait(cmd, p):
+    rv = p.wait()
+    if rv != 0:
+        raise GitError('%s returned %d' % (cmd, rv))
+
+
+def _git_capture(argv):
+    p = subprocess.Popen(argv, stdout=subprocess.PIPE, preexec_fn = _gitenv)
+    r = p.stdout.read()
+    _git_wait(repr(argv), p)
+    return r
 
+
+_ver_warned = 0
 class CatPipe:
     def __init__(self):
-        self.p = subprocess.Popen(['git', 'cat-file', '--batch'],
-                                  stdin=subprocess.PIPE, 
-                                  stdout=subprocess.PIPE,
-                                  preexec_fn = _gitenv)
+        global _ver_warned
+        wanted = ('1','5','6')
+        if ver() < wanted:
+            if not _ver_warned:
+                log('warning: git version < %s; bup will be slow.\n'
+                    % '.'.join(wanted))
+                _ver_warned = 1
+            self.get = self._slow_get
+        else:
+            self.p = subprocess.Popen(['git', 'cat-file', '--batch'],
+                                      stdin=subprocess.PIPE, 
+                                      stdout=subprocess.PIPE,
+                                      preexec_fn = _gitenv)
+            self.get = self._fast_get
 
-    def get(self, id):
+    def _fast_get(self, id):
         assert(id.find('\n') < 0)
         assert(id.find('\r') < 0)
+        assert(id[0] != '-')
         self.p.stdin.write('%s\n' % id)
         hdr = self.p.stdout.readline()
         spl = hdr.split(' ')
@@ -370,6 +413,20 @@ class CatPipe:
             yield blob
         assert(self.p.stdout.readline() == '\n')
 
+    def _slow_get(self, id):
+        assert(id.find('\n') < 0)
+        assert(id.find('\r') < 0)
+        assert(id[0] != '-')
+        type = _git_capture(['git', 'cat-file', '-t', id]).strip()
+        yield type
+
+        p = subprocess.Popen(['git', 'cat-file', type, id],
+                             stdout=subprocess.PIPE,
+                             preexec_fn = _gitenv)
+        for blob in chunkyreader(p.stdout):
+            yield blob
+        _git_wait('git cat-file', p)
+
     def _join(self, it):
         type = it.next()
         if type == 'blob':
diff --git a/test-sh b/test-sh
index 0cb868284947778c46dd952d9f9b2c024c5fc60f..cdf94658bc7f3e8de0936d84dd1ecfc93fcc46c3 100755 (executable)
--- a/test-sh
+++ b/test-sh
@@ -7,7 +7,7 @@ export BUP_DIR="$TOP/buptest.tmp"
 
 bup()
 {
-       "$TOP/bup" "$@"
+    "$TOP/bup" "$@"
 }
 
 set -x
@@ -35,7 +35,10 @@ diff -u testfile2 out2c.tmp
     git repack -Ad
     git prune
     (cd "$TOP/t/sampledata" && bup save -vvn master .) || exit 1
-    n=$(git fsck --full --strict 2>&1 | tee -a /dev/stderr | wc -l)
+    n=$(git fsck --full --strict 2>&1 | 
+         grep -v 'dangling commit' |
+         tee -a /dev/stderr | 
+         wc -l)
     if [ "$n" != 0 ]; then
         echo "git fsck error."
         exit 5