X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=cmd%2Fserver-cmd.py;h=0de6694f5f58d375cabcdc0f2a1d0a399a100aec;hb=7e1f05fe8b8d580d61c6a233ec1440adc248c97c;hp=6ec2de3cb9a48a200899426d94b476774a87c0b6;hpb=394b6481819db91742bfdc25e8d5e374c87845ca;p=bup.git diff --git a/cmd/server-cmd.py b/cmd/server-cmd.py index 6ec2de3..0de6694 100755 --- a/cmd/server-cmd.py +++ b/cmd/server-cmd.py @@ -1,39 +1,59 @@ -#!/usr/bin/env python +#!/bin/sh +"""": # -*-python-*- +bup_python="$(dirname "$0")/bup-python" || exit $? +exec "$bup_python" "$0" ${1+"$@"} +""" +# end of bup preamble + import os, sys, struct + from bup import options, git -from bup.helpers import * +from bup.helpers import Conn, debug1, debug2, linereader, log + suspended_w = None -server_mode = 'smart' +dumb_server_mode = False + + +def do_help(conn, junk): + conn.write('Commands:\n %s\n' % '\n '.join(sorted(commands))) + conn.ok() + def _set_mode(): - global server_mode - if os.path.exists(git.repo('bup-dumb-server')): - server_mode = 'dumb' - else: - server_mode = 'smart' - debug1('bup server: serving in %s mode\n' % server_mode) + global dumb_server_mode + dumb_server_mode = os.path.exists(git.repo('bup-dumb-server')) + debug1('bup server: serving in %s mode\n' + % (dumb_server_mode and 'dumb' or 'smart')) + + +def _init_session(reinit_with_new_repopath=None): + if reinit_with_new_repopath is None and git.repodir: + return + git.check_repo_or_die(reinit_with_new_repopath) + # 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) + _set_mode() def init_dir(conn, arg): git.init_repo(arg) debug1('bup server: bupdir initialized: %r\n' % git.repodir) - _set_mode() + _init_session(arg) conn.ok() def set_dir(conn, arg): - git.check_repo_or_die(arg) - debug1('bup server: bupdir is %r\n' % git.repodir) - _set_mode() + _init_session(arg) conn.ok() def list_indexes(conn, junk): - global server_mode - git.check_repo_or_die() + _init_session() suffix = '' - if server_mode == 'dumb': + if dumb_server_mode: suffix = ' load' for f in os.listdir(git.repo('objects/pack')): if f.endswith('.idx'): @@ -42,7 +62,7 @@ def list_indexes(conn, junk): def send_index(conn, name): - git.check_repo_or_die() + _init_session() assert(name.find('/') < 0) assert(name.endswith('.idx')) idx = git.open_idx(git.repo('objects/pack/%s' % name)) @@ -53,13 +73,16 @@ def send_index(conn, name): def receive_objects_v2(conn, junk): global suspended_w - git.check_repo_or_die() - suggested = {} + _init_session() + suggested = set() if suspended_w: w = suspended_w suspended_w = None else: - w = git.PackWriter() + if dumb_server_mode: + w = git.PackWriter(objcache_maker=None) + else: + w = git.PackWriter() while 1: ns = conn.read(4) if not ns: @@ -70,7 +93,7 @@ def receive_objects_v2(conn, junk): if not n: debug1('bup server: received %d object%s.\n' % (w.count, w.count!=1 and "s" or '')) - fullpath = w.close() + fullpath = w.close(run_midx=not dumb_server_mode) if fullpath: (dir, name) = os.path.split(fullpath) conn.write('%s.idx\n' % name) @@ -87,43 +110,23 @@ def receive_objects_v2(conn, junk): n -= 20 + 4 buf = conn.read(n) # object sizes in bup are reasonably small #debug2('read %d bytes\n' % n) - if len(buf) < n: - w.abort() - raise Exception('object read: expected %d bytes, got %d\n' - % (n, len(buf))) - if server_mode == 'smart': - oldpack = w.exists(shar) - else: - oldpack = None - # FIXME: we only suggest a single index per cycle, because the client - # is currently too dumb to download more than one per cycle anyway. - # Actually we should fix the client, but this is a minor optimization - # on the server side. - if not suggested and \ - oldpack and (oldpack == True or oldpack.endswith('.midx')): - # FIXME: we shouldn't really have to know about midx files - # at this layer. But exists() on a midx doesn't return the - # packname (since it doesn't know)... probably we should just - # fix that deficiency of midx files eventually, although it'll - # make the files bigger. This method is certainly not very - # efficient. - oldpack = w.objcache.packname_containing(shar) - debug2('new suggestion: %r\n' % oldpack) - assert(oldpack) - assert(oldpack != True) - assert(not oldpack.endswith('.midx')) - w.objcache.refresh() - if not suggested and oldpack: - assert(oldpack.endswith('.idx')) - (dir,name) = os.path.split(oldpack) - if not (name in suggested): - debug1("bup server: suggesting index %s\n" % name) - conn.write('index %s\n' % name) - suggested[name] = 1 - else: - nw, crc = w._raw_write([buf], sha=shar) - _check(w, crcr, crc, 'object read: expected crc %d, got %d\n') - _check(w, n, nw, 'object read: expected %d bytes, got %d\n') + _check(w, n, len(buf), 'object read: expected %d bytes, got %d\n') + if not dumb_server_mode: + oldpack = w.exists(shar, want_source=True) + if oldpack: + assert(not oldpack == True) + assert(oldpack.endswith('.idx')) + (dir,name) = os.path.split(oldpack) + if not (name in suggested): + debug1("bup server: suggesting index %s\n" + % git.shorten_hash(name)) + debug1("bup server: because of object %s\n" + % shar.encode('hex')) + conn.write('index %s\n' % name) + suggested.add(name) + continue + nw, crc = w._raw_write((buf,), sha=shar) + _check(w, crcr, crc, 'object read: expected crc %d, got %d\n') # NOTREACHED @@ -134,14 +137,14 @@ def _check(w, expected, actual, msg): def read_ref(conn, refname): - git.check_repo_or_die() + _init_session() 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() + _init_session() newval = conn.readline().strip() oldval = conn.readline().strip() git.update_ref(refname, newval.decode('hex'), oldval.decode('hex')) @@ -151,14 +154,14 @@ def update_ref(conn, refname): cat_pipe = None def cat(conn, id): global cat_pipe - git.check_repo_or_die() + _init_session() if not cat_pipe: cat_pipe = git.CatPipe() try: for blob in cat_pipe.join(id): conn.write(struct.pack('!I', len(blob))) conn.write(blob) - except KeyError, e: + except KeyError as e: log('server: error: %s\n' % e) conn.write('\0\0\0\0') conn.error(e) @@ -170,7 +173,7 @@ def cat(conn, id): optspec = """ bup server """ -o = options.Options('bup server', optspec) +o = options.Options(optspec) (opt, flags, extra) = o.parse(sys.argv[1:]) if extra: @@ -179,6 +182,8 @@ if extra: 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,