]> arthur.barton.de Git - bup.git/blob - cmd-server.py
Older git needs 'git --bare init' instead of 'git init --bare'
[bup.git] / cmd-server.py
1 #!/usr/bin/env python2.5
2 import sys, struct, mmap
3 import options, git
4 from helpers import *
5
6
7 def init_dir(conn, arg):
8     git.init_repo(arg)
9     log('bup server: bupdir initialized: %r\n' % git.repodir)
10     conn.ok()
11
12
13 def set_dir(conn, arg):
14     git.check_repo_or_die(arg)
15     log('bup server: bupdir is %r\n' % git.repodir)
16     conn.ok()
17
18     
19 def list_indexes(conn, junk):
20     git.check_repo_or_die()
21     for f in os.listdir(git.repo('objects/pack')):
22         if f.endswith('.idx'):
23             conn.write('%s\n' % f)
24     conn.ok()
25
26
27 def send_index(conn, name):
28     git.check_repo_or_die()
29     assert(name.find('/') < 0)
30     assert(name.endswith('.idx'))
31     idx = git.PackIndex(git.repo('objects/pack/%s' % name))
32     conn.write(struct.pack('!I', len(idx.map)))
33     conn.write(idx.map)
34     conn.ok()
35     
36             
37 def receive_objects(conn, junk):
38     git.check_repo_or_die()
39     w = git.PackWriter()
40     while 1:
41         ns = conn.read(4)
42         if not ns:
43             w.abort()
44             raise Exception('object read: expected length header, got EOF\n')
45         n = struct.unpack('!I', ns)[0]
46         #log('expecting %d bytes\n' % n)
47         if not n:
48             log('bup server: received %d object%s.\n' 
49                 % (w.count, w.count!=1 and "s" or ''))
50             w.close()
51             return
52         buf = conn.read(n)  # object sizes in bup are reasonably small
53         #log('read %d bytes\n' % n)
54         if len(buf) < n:
55             w.abort()
56             raise Exception('object read: expected %d bytes, got %d\n'
57                             % (n, len(buf)))
58         w._raw_write(buf)
59     w.close()
60     conn.ok()
61
62
63 def read_ref(conn, refname):
64     git.check_repo_or_die()
65     r = git.read_ref(refname)
66     conn.write('%s\n' % (r or '').encode('hex'))
67     conn.ok()
68
69
70 def update_ref(conn, refname):
71     git.check_repo_or_die()
72     newval = conn.readline().strip()
73     oldval = conn.readline().strip()
74     git.update_ref(refname, newval.decode('hex'), oldval.decode('hex'))
75     conn.ok()
76
77
78 def cat(conn, id):
79     git.check_repo_or_die()
80     for blob in git.cat(id):
81         conn.write(struct.pack('!I', len(blob)))
82         conn.write(blob)
83     conn.write('\0\0\0\0')
84     conn.ok()
85
86
87 optspec = """
88 bup server
89 """
90 o = options.Options('bup server', optspec)
91 (opt, flags, extra) = o.parse(sys.argv[1:])
92
93 if extra:
94     log('bup server: no arguments expected\n')
95     o.usage()
96
97 log('bup server: reading from stdin.\n')
98
99 commands = {
100     'init-dir': init_dir,
101     'set-dir': set_dir,
102     'list-indexes': list_indexes,
103     'send-index': send_index,
104     'receive-objects': receive_objects,
105     'read-ref': read_ref,
106     'update-ref': update_ref,
107     'cat': cat,
108 }
109
110 # FIXME: this protocol is totally lame and not at all future-proof.
111 # (Especially since we abort completely as soon as *anything* bad happens)
112 conn = Conn(sys.stdin, sys.stdout)
113 lr = linereader(conn)
114 for _line in lr:
115     line = _line.strip()
116     if not line:
117         continue
118     log('bup server: command: %r\n' % line)
119     words = line.split(' ', 1)
120     cmd = words[0]
121     rest = len(words)>1 and words[1] or ''
122     if cmd == 'quit':
123         break
124     else:
125         cmd = commands.get(cmd)
126         if cmd:
127             cmd(conn, rest)
128         else:
129             raise Exception('unknown server command: %r\n' % line)
130
131 log('bup server: done\n')