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)
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()
#!/bin/sh
set -e
+
+if [ -z "$BUP_DIR" ]; then
+ BUP_DIR="$HOME/.bup"
+fi
+
export GIT_DIR="$BUP_DIR"
get_one()
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, '')
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()
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
"""
'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.
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))
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()
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):
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):
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):