]> arthur.barton.de Git - bup.git/commitdiff
Moved some git.* globals into PackWriter; use BUP_DIR as repo path.
authorAvery Pennarun <apenwarr@gmail.com>
Sun, 3 Jan 2010 04:19:05 +0000 (23:19 -0500)
committerAvery Pennarun <apenwarr@gmail.com>
Sun, 3 Jan 2010 04:19:37 +0000 (23:19 -0500)
If BUP_DIR isn't set, it defaults to ./.git, which is probably not so smart,
but works for now (and was what we were using *until* now anyway).

cmd-save.py
cmd-split.py
git.py
hashsplit.py
t/tgit.py

index 740a6fd687620283bfd9c53e87140307d8c9fdc0..1dba9b0479fa124681e7953202c665dd41a8d8e5 100755 (executable)
@@ -72,17 +72,17 @@ class Tree:
         (dir, name) = os.path.split(fullname)
         self.getdir(dir).children[name] = (mode, name, id)
         
-    def shalist(self):
+    def shalist(self, w):
         for c in self.children.values():
             if isinstance(c, tuple):  # sha1 entry for a file
                 yield c
             else:  # tree
-                t = ('40000', c.name, c.gen_tree())
+                t = ('40000', c.name, c.gen_tree(w))
                 yield t
         
-    def gen_tree(self):
+    def gen_tree(self, w):
         if not self.sha:
-            self.sha = git.gen_tree(self.shalist())
+            self.sha = w.new_tree(self.shalist(w))
         return self.sha
 
 
@@ -105,6 +105,7 @@ if opt.verbose >= 2:
     git.verbose = opt.verbose - 1
     hashsplit.split_verbosely = opt.verbose - 1
 
+w = git.PackWriter()
 root = Tree(None, '')
 for fn in direxpand(extra):
     if opt.verbose:
@@ -118,9 +119,9 @@ for fn in direxpand(extra):
     except OSError, e:
         add_error(e)
         continue
-    (mode, id) = hashsplit.split_to_blob_or_tree([f])
+    (mode, id) = hashsplit.split_to_blob_or_tree(w, [f])
     root.addfile(mode, fn, id)
-tree = root.gen_tree()
+tree = root.gen_tree(w)
 if opt.verbose:
     log('\n')
 if opt.tree:
@@ -128,11 +129,11 @@ if opt.tree:
 if opt.commit or opt.name:
     msg = 'bup save\n\nGenerated by command:\n%r' % sys.argv
     ref = opt.name and ('refs/heads/%s' % opt.name) or None
-    commit = git.gen_commit_easy(ref, tree, msg)
+    commit = w.new_commit(ref, tree, msg)
     if opt.commit:
         print commit.encode('hex')
 
-git.flush_pack()
+w.close()
 
 if saved_errors:
     log('WARNING: %d errors encountered while saving.\n' % len(saved_errors))
index 2199fb538a6bc858347559e41b25c3a164b41f34..9d3d4851c4711c786b797b3b955b47e6885aecb1 100755 (executable)
@@ -27,7 +27,8 @@ if opt.verbose >= 2:
 
 start_time = time.time()
 
-(shalist,tree) = hashsplit.split_to_tree(hashsplit.autofiles(extra))
+w = git.PackWriter()
+(shalist,tree) = hashsplit.split_to_tree(w, hashsplit.autofiles(extra))
 
 if opt.verbose:
     log('\n')
@@ -39,7 +40,7 @@ if opt.tree:
 if opt.commit or opt.name:
     msg = 'bup split\n\nGenerated by command:\n%r' % sys.argv
     ref = opt.name and ('refs/heads/%s' % opt.name) or None
-    commit = git.gen_commit_easy(ref, tree, msg)
+    commit = w.new_commit(ref, tree, msg)
     if opt.commit:
         print commit.encode('hex')
 
@@ -48,5 +49,3 @@ size = hashsplit.total_split
 if opt.bench:
     log('\nbup: %.2fkbytes in %.2f secs = %.2f kbytes/sec\n'
         % (size/1024., secs, size/1024./secs))
-
-git.flush_pack()
diff --git a/git.py b/git.py
index 720a49543004b134c28c03fc821b0a3579b114a0..832620e6666fe52fbbfec0fb63078b72eac0db2d 100644 (file)
--- a/git.py
+++ b/git.py
@@ -3,6 +3,9 @@ from helpers import *
 
 verbose = 0
 
+def repodir(sub = ''):
+    return os.path.join(os.environ.get('BUP_DIR', '.git'), sub)
+
 
 class PackIndex:
     def __init__(self, filename):
@@ -78,6 +81,9 @@ class MultiPackIndex:
     def add(self, hash):
         self.also[hash] = 1
 
+    def zap_also(self):
+        self.also = {}
+
 
 def calc_hash(type, content):
     header = '%s %d\0' % (type, len(content))
@@ -91,12 +97,23 @@ class PackWriter:
     def __init__(self):
         self.count = 0
         self.binlist = []
-        self.filename = '.git/objects/bup%d' % os.getpid()
+        self.objcache = MultiPackIndex(repodir('objects/pack'))
+        self.filename = None
+        self.file = None
+
+    def __del__(self):
+        self.close()
+
+    def _open(self):
+        assert(not self.file)
+        self.objcache.zap_also()
+        self.filename = repodir('objects/bup%d' % os.getpid())
         self.file = open(self.filename + '.pack', 'w+')
         self.file.write('PACK\0\0\0\2\0\0\0\0')
 
-    def write(self, bin, type, content):
-        global _typemap
+    def _write(self, bin, type, content):
+        if not self.file:
+            self._open()
         f = self.file
 
         if verbose:
@@ -121,15 +138,58 @@ class PackWriter:
         self.binlist.append(bin)
         return bin
 
-    def easy_write(self, type, content):
-        return self.write(calc_hash(type, content), type, content)
+    def write(self, type, content):
+        return self._write(calc_hash(type, content), type, content)
+
+    def maybe_write(self, type, content):
+        bin = calc_hash(type, content)
+        if not self.objcache.exists(bin):
+            self._write(bin, type, content)
+            self.objcache.add(bin)
+        return bin
+
+    def new_blob(self, blob):
+        return self.maybe_write('blob', blob)
+
+    def new_tree(self, shalist):
+        shalist = sorted(shalist, key = lambda x: x[1])
+        l = ['%s %s\0%s' % (mode,name,bin) 
+             for (mode,name,bin) in shalist]
+        return self.maybe_write('tree', ''.join(l))
+
+    def _new_commit(self, tree, parent, author, adate, committer, cdate, msg):
+        l = []
+        if tree: l.append('tree %s' % tree.encode('hex'))
+        if parent: l.append('parent %s' % parent)
+        if author: l.append('author %s %s' % (author, _git_date(adate)))
+        if committer: l.append('committer %s %s' % (committer, _git_date(cdate)))
+        l.append('')
+        l.append(msg)
+        return self.maybe_write('commit', '\n'.join(l))
+
+    def new_commit(self, ref, tree, msg):
+        now = time.time()
+        userline = '%s <%s@%s>' % (userfullname(), username(), hostname())
+        oldref = ref and _read_ref(ref) or None
+        commit = self._new_commit(tree, oldref,
+                                  userline, now, userline, now,
+                                  msg)
+        self.close()  # UGLY: needed so _update_ref can see the new objects
+        if ref:
+            _update_ref(ref, commit.encode('hex'), oldref)
+        return commit
 
     def abort(self):
-        self.file.close()
-        os.unlink(self.filename + '.pack')
+        f = self.file
+        if f:
+            self.file = None
+            f.close()
+            os.unlink(self.filename + '.pack')
 
     def close(self):
         f = self.file
+        if not f: return None
+        self.file = None
 
         # update object count
         f.seek(8)
@@ -150,75 +210,28 @@ class PackWriter:
 
         p = subprocess.Popen(['git', 'index-pack', '-v',
                               self.filename + '.pack'],
-                             preexec_fn = lambda: _gitenv('.git'),
+                             preexec_fn = _gitenv,
                              stdout = subprocess.PIPE)
         out = p.stdout.read().strip()
         if p.wait() or not out:
             raise Exception('git index-pack returned an error')
-        nameprefix = '.git/objects/pack/%s' % out
+        nameprefix = repodir('objects/pack/%s' % out)
         os.rename(self.filename + '.pack', nameprefix + '.pack')
         os.rename(self.filename + '.idx', nameprefix + '.idx')
         return nameprefix
 
 
-_packout = None
-def _write_object(bin, type, content):
-    global _packout
-    if not _packout:
-        _packout = PackWriter()
-    _packout.write(bin, type, content)
-
-
-def flush_pack():
-    global _packout
-    if _packout:
-        _packout.close()
-        _packout = None
-
-
-def abort_pack():
-    global _packout
-    if _packout:
-        _packout.abort()
-        _packout = None
-
-
-_objcache = None
-def hash_raw(type, s):
-    global _objcache
-    if not _objcache:
-        _objcache = MultiPackIndex('.git/objects/pack')
-    bin = calc_hash(type, s)
-    if _objcache.exists(bin):
-        return bin
-    else:
-        _write_object(bin, type, s)
-        _objcache.add(bin)
-        return bin
-
-
-def hash_blob(blob):
-    return hash_raw('blob', blob)
-
-
-def gen_tree(shalist):
-    shalist = sorted(shalist, key = lambda x: x[1])
-    l = ['%s %s\0%s' % (mode,name,bin) 
-         for (mode,name,bin) in shalist]
-    return hash_raw('tree', ''.join(l))
-
-
 def _git_date(date):
     return time.strftime('%s %z', time.localtime(date))
 
 
-def _gitenv(repo):
-    os.environ['GIT_DIR'] = os.path.abspath(repo)
+def _gitenv():
+    os.environ['GIT_DIR'] = os.path.abspath(repodir())
 
 
-def _read_ref(repo, refname):
+def _read_ref(refname):
     p = subprocess.Popen(['git', 'show-ref', '--', refname],
-                         preexec_fn = lambda: _gitenv(repo),
+                         preexec_fn = _gitenv,
                          stdout = subprocess.PIPE)
     out = p.stdout.read().strip()
     p.wait()
@@ -228,32 +241,10 @@ def _read_ref(repo, refname):
         return None
 
 
-def _update_ref(repo, refname, newval, oldval):
+def _update_ref(refname, newval, oldval):
     if not oldval:
         oldval = ''
     p = subprocess.Popen(['git', 'update-ref', '--', refname, newval, oldval],
-                         preexec_fn = lambda: _gitenv(repo))
+                         preexec_fn = _gitenv)
     p.wait()
     return newval
-
-
-def gen_commit(tree, parent, author, adate, committer, cdate, msg):
-    l = []
-    if tree: l.append('tree %s' % tree.encode('hex'))
-    if parent: l.append('parent %s' % parent)
-    if author: l.append('author %s %s' % (author, _git_date(adate)))
-    if committer: l.append('committer %s %s' % (committer, _git_date(cdate)))
-    l.append('')
-    l.append(msg)
-    return hash_raw('commit', '\n'.join(l))
-
-
-def gen_commit_easy(ref, tree, msg):
-    now = time.time()
-    userline = '%s <%s@%s>' % (userfullname(), username(), hostname())
-    oldref = ref and _read_ref('.git', ref) or None
-    commit = gen_commit(tree, oldref, userline, now, userline, now, msg)
-    flush_pack()
-    if ref:
-        _update_ref('.git', ref, commit.encode('hex'), oldref)
-    return commit
index 4565f3a7dbfe21b30e231396e97949e54d8e7f8d..ee38d025c902b2528a75c5351a593932848820e3 100644 (file)
@@ -63,7 +63,7 @@ def autofiles(filenames):
             yield open(n)
             
     
-def hashsplit_iter(files):
+def hashsplit_iter(w, files):
     global split_verbosely
     ofs = 0
     buf = Buf()
@@ -88,7 +88,7 @@ def hashsplit_iter(files):
             continue
 
         if blob:
-            yield (ofs, len(blob), git.hash_blob(blob))
+            yield (ofs, len(blob), w.new_blob(blob))
             ofs += len(blob)
           
         nv = (ofs + buf.used())/1000000
@@ -99,11 +99,11 @@ def hashsplit_iter(files):
 
 
 total_split = 0
-def split_to_shalist(files):
+def split_to_shalist(w, files):
     global total_split
     ofs = 0
     last_ofs = 0
-    for (ofs, size, sha) in hashsplit_iter(files):
+    for (ofs, size, sha) in hashsplit_iter(w, files):
         #log('SPLIT @ %-8d size=%-8d\n' % (ofs, size))
         # this silliness keeps chunk filenames "similar" when a file changes
         # slightly.
@@ -118,17 +118,17 @@ def split_to_shalist(files):
         yield ('100644', 'bup.chunk.%016x' % cn, sha)
 
 
-def split_to_tree(files):
-    shalist = list(split_to_shalist(files))
-    tree = git.gen_tree(shalist)
+def split_to_tree(w, files):
+    shalist = list(split_to_shalist(w, files))
+    tree = w.new_tree(shalist)
     return (shalist, tree)
 
 
-def split_to_blob_or_tree(files):
-    (shalist, tree) = split_to_tree(files)
+def split_to_blob_or_tree(w, files):
+    (shalist, tree) = split_to_tree(w, files)
     if len(shalist) == 1:
         return (shalist[0][0], shalist[0][2])
     elif len(shalist) == 0:
-        return ('100644', git.hash_blob(''))
+        return ('100644', w.new_blob(''))
     else:
         return ('40000', tree)
index 0b3979f2ffd70b3db42292adf3a7bb765f4df16b..db852897a676439906cafd04b44cdeaeaefbbb83 100644 (file)
--- a/t/tgit.py
+++ b/t/tgit.py
@@ -8,16 +8,15 @@ def testpacks():
     git.verbose = 1
 
     now = str(time.time())  # hopefully not in any packs yet
-    git.hash_blob(now)
-    git.hash_blob(now)
-    git.abort_pack()
+    w = git.PackWriter()
+    w.write('blob', now)
+    w.write('blob', now)
+    w.abort()
     
     w = git.PackWriter()
     hashes = []
-    w.easy_write('blob', '0xx')
-    w.easy_write('blob', '0xx')
     for i in range(1000):
-        hashes.append(w.easy_write('blob', str(i)))
+        hashes.append(w.write('blob', str(i)))
     log('\n')
     nameprefix = w.close()
     print repr(nameprefix)