]> arthur.barton.de Git - bup.git/commitdiff
We can now update refs when we do a backup.
authorAvery Pennarun <apenwarr@gmail.com>
Mon, 4 Jan 2010 01:30:25 +0000 (20:30 -0500)
committerAvery Pennarun <apenwarr@gmail.com>
Mon, 4 Jan 2010 01:41:52 +0000 (20:41 -0500)
Supported by both cmd-save and cmd-split, albeit with a disturbing amount of
code duplication.

Also updated bup-join to use a default BUP_DIR if none is specified.

client.py
cmd-join.sh
cmd-save.py
cmd-server.py
cmd-split.py
git.py
helpers.py

index cf9b996169acda0feb7c17e491ae334a48d70cb1..3380956aa7d6b5d02baaf76f53c60adc67b95c8f 100644 (file)
--- a/client.py
+++ b/client.py
@@ -48,7 +48,7 @@ class Client:
                 raise ClientError('server tunnel returned exit code %d' % rv)
         self.conn = None
         self.p = None
-            
+
     def check_busy(self):
         if self._busy:
             raise ClientError('already busy with command %r' % self._busy)
@@ -105,3 +105,21 @@ class Client:
         objcache = git.MultiPackIndex(self.cachedir)
         return git.PackWriter_Remote(self.conn, objcache = objcache,
                                      onclose = self._not_busy)
+
+    def read_ref(self, refname):
+        self.check_busy()
+        self.conn.write('read-ref %s\n' % refname)
+        r = self.conn.readline().strip()
+        self.conn.check_ok()
+        if r:
+            assert(len(r) == 40)   # hexified sha
+            return r.decode('hex')
+        else:
+            return None   # nonexistent ref
+
+    def update_ref(self, refname, newval, oldval):
+        self.check_busy()
+        self.conn.write('update-ref %s\n%s\n%s\n' 
+                        % (refname, newval.encode('hex'),
+                           (oldval or '').encode('hex')))
+        self.conn.check_ok()
index 9fc7e15a334ed2546cf70c2ce9ca1635f0127639..4fe1b4999d6b200fffa92e63e6310ba45c7a7357 100755 (executable)
@@ -1,5 +1,10 @@
 #!/bin/sh
 set -e
+
+if [ -z "$BUP_DIR" ]; then
+    BUP_DIR="$HOME/.bup"
+fi
+
 export GIT_DIR="$BUP_DIR"
 
 get_one()
index dc78ee017ab361db9863366b6df7d7965acd90bc..69d5626954380ba66cb90e4ba651f3e4de639703 100755 (executable)
@@ -115,12 +115,15 @@ if opt.verbose >= 2:
     git.verbose = opt.verbose - 1
     hashsplit.split_verbosely = opt.verbose - 1
 
+refname = opt.name and 'refs/heads/%s' % opt.name or None
 if opt.remote:
     cli = client.Client(opt.remote)
+    oldref = refname and cli.read_ref(refname) or None
     cli.sync_indexes()
     w = cli.new_packwriter()
 else:
     cli = None
+    oldref = refname and git.read_ref(refname) or None
     w = git.PackWriter()
     
 root = Tree(None, '')
@@ -149,13 +152,20 @@ 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 = w.new_commit(ref, tree, msg)
+    commit = w.new_commit(oldref, tree, msg)
     if opt.commit:
         if opt.verbose:
             log('\n')
         print commit.encode('hex')
 
-w.close()
+w.close()  # must close before we can update the ref
+        
+if opt.name:
+    if cli:
+        cli.update_ref(refname, commit, oldref)
+    else:
+        git.update_ref(refname, commit, oldref)
+
 if cli:
     cli.close()
 
index 92aa8072f41bae9beca0ac28dc059a377e69d2ca..6baea700bb7e90114da39ffc0fd64f8fd3fe70b9 100755 (executable)
@@ -60,6 +60,21 @@ def receive_objects(conn, junk):
     conn.ok()
 
 
+def read_ref(conn, refname):
+    git.check_repo_or_die()
+    r = git.read_ref(refname)
+    conn.write('%s\n' % (r or '').encode('hex'))
+    conn.ok()
+
+
+def update_ref(conn, refname):
+    git.check_repo_or_die()
+    newval = conn.readline().strip()
+    oldval = conn.readline().strip()
+    git.update_ref(refname, newval.decode('hex'), oldval.decode('hex'))
+    conn.ok()
+
+
 optspec = """
 bup server
 """
@@ -78,6 +93,8 @@ commands = {
     'list-indexes': list_indexes,
     'send-index': send_index,
     'receive-objects': receive_objects,
+    'read-ref': read_ref,
+    'update-ref': update_ref,
 }
 
 # FIXME: this protocol is totally lame and not at all future-proof.
index 5551c738fd07c347520046e50e9e0e92907ab743..49287338f5bee553db0698e81455e1be9dcb95d1 100755 (executable)
@@ -31,12 +31,15 @@ if opt.verbose >= 2:
 
 start_time = time.time()
 
+refname = opt.name and 'refs/heads/%s' % opt.name or None
 if opt.remote:
     cli = client.Client(opt.remote)
+    oldref = refname and cli.read_ref(refname) or None
     cli.sync_indexes()
     w = cli.new_packwriter()
 else:
     cli = None
+    oldref = refname and git.read_ref(refname) or None
     w = git.PackWriter()
     
 (shalist,tree) = hashsplit.split_to_tree(w, hashsplit.autofiles(extra))
@@ -51,11 +54,18 @@ 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 = w.new_commit(ref, tree, msg)
+    commit = w.new_commit(oldref, tree, msg)
     if opt.commit:
         print commit.encode('hex')
 
-w.close()
+w.close()  # must close before we can update the ref
+        
+if opt.name:
+    if cli:
+        cli.update_ref(refname, commit, oldref)
+    else:
+        git.update_ref(refname, commit, oldref)
+
 if cli:
     cli.close()
 
diff --git a/git.py b/git.py
index 8593f350524163b71bdd28415dcc66aebdb73256..3b758eaee6f4097602d095a068c3023f845cca66 100644 (file)
--- a/git.py
+++ b/git.py
@@ -187,23 +187,19 @@ class PackWriter:
     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 parent: l.append('parent %s' % parent.encode('hex'))
         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):
+    def new_commit(self, parent, 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,
+        commit = self._new_commit(tree, parent,
                                   userline, now, userline, now,
                                   msg)
-        if ref:
-            self.close()  # UGLY: needed so _update_ref can see the new objects
-            _update_ref(ref, commit.encode('hex'), oldref)
         return commit
 
     def abort(self):
@@ -283,25 +279,29 @@ def _gitenv():
     os.environ['GIT_DIR'] = os.path.abspath(repo())
 
 
-def _read_ref(refname):
+def read_ref(refname):
     p = subprocess.Popen(['git', 'show-ref', '--', refname],
                          preexec_fn = _gitenv,
                          stdout = subprocess.PIPE)
     out = p.stdout.read().strip()
-    p.wait()
+    rv = p.wait()
+    if rv:
+        assert(not out)
     if out:
-        return out.split()[0]
+        return out.split()[0].decode('hex')
     else:
         return None
 
 
-def _update_ref(refname, newval, oldval):
+def update_ref(refname, newval, oldval):
     if not oldval:
         oldval = ''
-    p = subprocess.Popen(['git', 'update-ref', '--', refname, newval, oldval],
+    p = subprocess.Popen(['git', 'update-ref', '--', refname,
+                          newval.encode('hex'), oldval.encode('hex')],
                          preexec_fn = _gitenv)
-    p.wait()
-    return newval
+    rv = p.wait()
+    if rv:
+        raise GitError('update_ref returned error code %d' % rv)
 
 
 def guess_repo(path=None):
index c07cd7b5c6eb8035b4adcdc1c4fa907a7abe7cc3..0cb4332968ac8659bb81ffb67b531c603d403613 100644 (file)
@@ -78,13 +78,15 @@ class Conn:
 
     def check_ok(self):
         self.outp.flush()
+        rl = ''
         for rl in linereader(self.inp):
             if not rl:
                 continue
             elif rl == 'ok':
                 return True
             else:
-                raise Exception('expected "ok", got %r' % rl)
+                break
+        raise Exception('expected "ok", got %r' % rl)
 
 
 def linereader(f):