# end of bup preamble
from __future__ import absolute_import
+from binascii import hexlify, unhexlify
import os, sys, struct, subprocess
-from bup import options, git
+from bup import options, git, vfs, vint
+from bup.compat import environ, hexstr
from bup.git import MissingObject
from bup.helpers import (Conn, debug1, debug2, linereader, lines_until_sentinel,
log)
+from bup.io import byte_stream, path_msg
from bup.repo import LocalRepo
repo = None
def do_help(conn, junk):
- conn.write('Commands:\n %s\n' % '\n '.join(sorted(commands)))
+ conn.write(b'Commands:\n %s\n' % b'\n '.join(sorted(commands)))
conn.ok()
def _set_mode():
global dumb_server_mode
- dumb_server_mode = os.path.exists(git.repo('bup-dumb-server'))
+ dumb_server_mode = os.path.exists(git.repo(b'bup-dumb-server'))
debug1('bup server: serving in %s mode\n'
% (dumb_server_mode and 'dumb' or 'smart'))
repo = LocalRepo()
# OK. we now know the path is a proper repository. Record this path in the
# environment so that subprocesses inherit it and know where to operate.
- os.environ['BUP_DIR'] = git.repodir
- debug1('bup server: bupdir is %r\n' % git.repodir)
+ environ[b'BUP_DIR'] = git.repodir
+ debug1('bup server: bupdir is %s\n' % path_msg(git.repodir))
_set_mode()
def init_dir(conn, arg):
git.init_repo(arg)
- debug1('bup server: bupdir initialized: %r\n' % git.repodir)
+ debug1('bup server: bupdir initialized: %s\n' % path_msg(git.repodir))
_init_session(arg)
conn.ok()
def list_indexes(conn, junk):
_init_session()
- suffix = ''
+ suffix = b''
if dumb_server_mode:
- suffix = ' load'
- for f in os.listdir(git.repo('objects/pack')):
- if f.endswith('.idx'):
- conn.write('%s%s\n' % (f, suffix))
+ suffix = b' load'
+ for f in os.listdir(git.repo(b'objects/pack')):
+ if f.endswith(b'.idx'):
+ conn.write(b'%s%s\n' % (f, suffix))
conn.ok()
def send_index(conn, name):
_init_session()
- assert(name.find('/') < 0)
- assert(name.endswith('.idx'))
- idx = git.open_idx(git.repo('objects/pack/%s' % name))
+ assert name.find(b'/') < 0
+ assert name.endswith(b'.idx')
+ idx = git.open_idx(git.repo(b'objects/pack/%s' % name))
conn.write(struct.pack('!I', len(idx.map)))
conn.write(idx.map)
conn.ok()
fullpath = w.close(run_midx=not dumb_server_mode)
if fullpath:
(dir, name) = os.path.split(fullpath)
- conn.write('%s.idx\n' % name)
+ conn.write(b'%s.idx\n' % name)
conn.ok()
return
elif n == 0xffffffff:
oldpack = w.exists(shar, want_source=True)
if oldpack:
assert(not oldpack == True)
- assert(oldpack.endswith('.idx'))
+ assert(oldpack.endswith(b'.idx'))
(dir,name) = os.path.split(oldpack)
if not (name in suggested):
debug1("bup server: suggesting index %s\n"
- % git.shorten_hash(name))
+ % git.shorten_hash(name).decode('ascii'))
debug1("bup server: because of object %s\n"
- % shar.encode('hex'))
- conn.write('index %s\n' % name)
+ % hexstr(shar))
+ conn.write(b'index %s\n' % name)
suggested.add(name)
continue
nw, crc = w._raw_write((buf,), sha=shar)
def read_ref(conn, refname):
_init_session()
r = git.read_ref(refname)
- conn.write('%s\n' % (r or '').encode('hex'))
+ conn.write(b'%s\n' % hexlify(r) if r else b'')
conn.ok()
_init_session()
newval = conn.readline().strip()
oldval = conn.readline().strip()
- git.update_ref(refname, newval.decode('hex'), oldval.decode('hex'))
+ git.update_ref(refname, unhexlify(newval), unhexlify(oldval))
conn.ok()
def join(conn, id):
conn.write(blob)
except KeyError as e:
log('server: error: %s\n' % e)
- conn.write('\0\0\0\0')
+ conn.write(b'\0\0\0\0')
conn.error(e)
else:
- conn.write('\0\0\0\0')
+ conn.write(b'\0\0\0\0')
conn.ok()
def cat_batch(conn, dummy):
_init_session()
cat_pipe = git.cp()
# For now, avoid potential deadlock by just reading them all
- for ref in tuple(lines_until_sentinel(conn, '\n', Exception)):
+ for ref in tuple(lines_until_sentinel(conn, b'\n', Exception)):
ref = ref[:-1]
it = cat_pipe.get(ref)
info = next(it)
if not info[0]:
- conn.write('missing\n')
+ conn.write(b'missing\n')
continue
- conn.write('%s %s %d\n' % info)
+ conn.write(b'%s %s %d\n' % info)
for buf in it:
conn.write(buf)
conn.ok()
def refs(conn, args):
limit_to_heads, limit_to_tags = args.split()
- assert limit_to_heads in ('0', '1')
- assert limit_to_tags in ('0', '1')
+ assert limit_to_heads in (b'0', b'1')
+ assert limit_to_tags in (b'0', b'1')
limit_to_heads = int(limit_to_heads)
limit_to_tags = int(limit_to_tags)
_init_session()
- patterns = tuple(x[:-1] for x in lines_until_sentinel(conn, '\n', Exception))
+ patterns = tuple(x[:-1] for x in lines_until_sentinel(conn, b'\n', Exception))
for name, oid in git.list_refs(patterns=patterns,
limit_to_heads=limit_to_heads,
limit_to_tags=limit_to_tags):
- assert '\n' not in name
- conn.write('%s %s\n' % (oid.encode('hex'), name))
- conn.write('\n')
+ assert b'\n' not in name
+ conn.write(b'%s %s\n' % (hexlify(oid), name))
+ conn.write(b'\n')
conn.ok()
def rev_list(conn, _):
count = conn.readline()
if not count:
raise Exception('Unexpected EOF while reading rev-list count')
- count = None if count == '\n' else int(count)
+ count = None if count == b'\n' else int(count)
fmt = conn.readline()
if not fmt:
raise Exception('Unexpected EOF while reading rev-list format')
- fmt = None if fmt == '\n' else fmt[:-1]
- refs = tuple(x[:-1] for x in lines_until_sentinel(conn, '\n', Exception))
+ fmt = None if fmt == b'\n' else fmt[:-1]
+ refs = tuple(x[:-1] for x in lines_until_sentinel(conn, b'\n', Exception))
args = git.rev_list_invocation(refs, count=count, format=fmt)
p = subprocess.Popen(git.rev_list_invocation(refs, count=count, format=fmt),
- preexec_fn=git._gitenv(git.repodir),
+ env=git._gitenv(git.repodir),
stdout=subprocess.PIPE)
while True:
out = p.stdout.read(64 * 1024)
if not out:
break
conn.write(out)
+ conn.write(b'\n')
rv = p.wait() # not fatal
if rv:
msg = 'git rev-list returned error %d' % rv
raise GitError(msg)
conn.ok()
+def resolve(conn, args):
+ _init_session()
+ (flags,) = args.split()
+ flags = int(flags)
+ want_meta = bool(flags & 1)
+ follow = bool(flags & 2)
+ have_parent = bool(flags & 4)
+ parent = vfs.read_resolution(conn) if have_parent else None
+ path = vint.read_bvec(conn)
+ if not len(path):
+ raise Exception('Empty resolve path')
+ try:
+ res = list(vfs.resolve(repo, path, parent=parent, want_meta=want_meta,
+ follow=follow))
+ except vfs.IOError as ex:
+ res = ex
+ if isinstance(res, vfs.IOError):
+ conn.write(b'\x00') # error
+ vfs.write_ioerror(conn, res)
+ else:
+ conn.write(b'\x01') # success
+ vfs.write_resolution(conn, res)
+ conn.ok()
optspec = """
bup server
debug2('bup server: reading from stdin.\n')
commands = {
- 'quit': None,
- 'help': do_help,
- 'init-dir': init_dir,
- 'set-dir': set_dir,
- 'list-indexes': list_indexes,
- 'send-index': send_index,
- 'receive-objects-v2': receive_objects_v2,
- 'read-ref': read_ref,
- 'update-ref': update_ref,
- 'join': join,
- 'cat': join, # apocryphal alias
- 'cat-batch' : cat_batch,
- 'refs': refs,
- 'rev-list': rev_list
+ b'quit': None,
+ b'help': do_help,
+ b'init-dir': init_dir,
+ b'set-dir': set_dir,
+ b'list-indexes': list_indexes,
+ b'send-index': send_index,
+ b'receive-objects-v2': receive_objects_v2,
+ b'read-ref': read_ref,
+ b'update-ref': update_ref,
+ b'join': join,
+ b'cat': join, # apocryphal alias
+ b'cat-batch' : cat_batch,
+ b'refs': refs,
+ b'rev-list': rev_list,
+ b'resolve': resolve
}
# FIXME: this protocol is totally lame and not at all future-proof.
# (Especially since we abort completely as soon as *anything* bad happens)
-conn = Conn(sys.stdin, sys.stdout)
+sys.stdout.flush()
+conn = Conn(byte_stream(sys.stdin), byte_stream(sys.stdout))
lr = linereader(conn)
for _line in lr:
line = _line.strip()
if not line:
continue
debug1('bup server: command: %r\n' % line)
- words = line.split(' ', 1)
+ words = line.split(b' ', 1)
cmd = words[0]
- rest = len(words)>1 and words[1] or ''
- if cmd == 'quit':
+ rest = len(words)>1 and words[1] or b''
+ if cmd == b'quit':
break
else:
cmd = commands.get(cmd)