-#!/usr/bin/env python2.5
-import sys, time, re, struct
-import hashsplit, git, options
+#!/usr/bin/env python
+import sys, time, struct
+import hashsplit, git, options, client
from helpers import *
+from subprocess import PIPE
+
optspec = """
bup split [-tcb] [-n name] [--bench] [filenames...]
n,name= name of backup set to update (if any)
v,verbose increase log output (can be used more than once)
bench print benchmark timings to stderr
+max-pack-size= maximum bytes in a single pack
+max-pack-objects= maximum number of objects in a single pack
+fanout= maximum number of blobs in a single tree
"""
o = options.Options('bup split', optspec)
(opt, flags, extra) = o.parse(sys.argv[1:])
if opt.verbose >= 2:
git.verbose = opt.verbose - 1
opt.bench = 1
+if opt.max_pack_size:
+ hashsplit.max_pack_size = int(opt.max_pack_size)
+if opt.max_pack_objects:
+ hashsplit.max_pack_objects = int(opt.max_pack_objects)
+if opt.fanout:
+ hashsplit.fanout = int(opt.fanout)
+if opt.blobs:
+ hashsplit.fanout = 0
start_time = time.time()
-def server_connect(remote):
- rs = remote.split(':', 1)
- if len(rs) == 1:
- (host, dir) = ('NONE', remote)
- p = subprocess.Popen(['bup', 'server'],
- stdin=subprocess.PIPE, stdout=subprocess.PIPE)
- else:
- (host, dir) = rs
- p = subprocess.Popen(['ssh', host, '--', 'bup', 'server'],
- stdin=subprocess.PIPE, stdout=subprocess.PIPE)
- conn = Conn(p.stdout, p.stdin)
- dir = re.sub(r'[\r\n]', ' ', dir)
- conn.write('set-dir %s\n' % dir)
- conn.check_ok()
-
- conn.write('list-indexes\n')
- cachedir = git.repo('index-cache/%s' % re.sub(r'[^@:\w]', '_',
- "%s:%s" % (host, dir)))
- packdir = git.repo('objects/pack')
- mkdirp(cachedir)
- all = {}
- needed = {}
- for line in linereader(conn):
- if not line:
- break
- all[line] = 1
- assert(line.find('/') < 0)
- if (not os.path.exists(os.path.join(cachedir, line)) and
- not os.path.exists(os.path.join(packdir, line))):
- needed[line] = 1
- conn.check_ok()
-
- for f in os.listdir(cachedir):
- if f.endswith('.idx') and not f in all:
- log('pruning old index: %r\n' % f)
- os.unlink(os.path.join(cachedir, f))
-
- # FIXME this should be pipelined: request multiple indexes at a time, or
- # we waste lots of network turnarounds.
- for name in needed.keys():
- log('requesting %r\n' % name)
- conn.write('send-index %s\n' % name)
- n = struct.unpack('!I', conn.read(4))[0]
- assert(n)
- log(' expect %d bytes\n' % n)
- fn = os.path.join(cachedir, name)
- f = open(fn + '.tmp', 'w')
- for b in chunkyreader(conn, n):
- f.write(b)
- conn.check_ok()
- f.close()
- os.rename(fn + '.tmp', fn)
- return (p, conn, cachedir)
-
+refname = opt.name and 'refs/heads/%s' % opt.name or None
if opt.remote:
- (p, conn, cachedir) = server_connect(opt.remote)
- conn.write('receive-objects\n')
- w = git.PackWriter_Remote(conn, objcache = git.MultiPackIndex(cachedir))
+ cli = client.Client(opt.remote)
+ oldref = refname and cli.read_ref(refname) or None
+ 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))
+shalist = hashsplit.split_to_shalist(w, hashsplit.autofiles(extra))
+tree = w.new_tree(shalist)
if opt.verbose:
log('\n')
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')
-if opt.remote:
- w.close()
- p.stdin.write('quit\n')
- p.wait()
+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()
secs = time.time() - start_time
size = hashsplit.total_split