2 import sys, time, re, struct
3 import hashsplit, git, options
7 bup split [-tcb] [-n name] [--bench] [filenames...]
9 r,remote= remote repository path
10 b,blobs output a series of blob ids
11 t,tree output a tree id
12 c,commit output a commit id
13 n,name= name of backup set to update (if any)
14 v,verbose increase log output (can be used more than once)
15 bench print benchmark timings to stderr
17 o = options.Options('bup split', optspec)
18 (opt, flags, extra) = o.parse(sys.argv[1:])
20 git.check_repo_or_die()
21 if not (opt.blobs or opt.tree or opt.commit or opt.name):
22 log("bup split: use one or more of -b, -t, -c, -n\n")
25 hashsplit.split_verbosely = opt.verbose
27 git.verbose = opt.verbose - 1
30 start_time = time.time()
32 def server_connect(remote):
33 rs = remote.split(':', 1)
35 (host, dir) = ('NONE', remote)
36 p = subprocess.Popen(['bup', 'server'],
37 stdin=subprocess.PIPE, stdout=subprocess.PIPE)
40 p = subprocess.Popen(['ssh', host, '--', 'bup', 'server'],
41 stdin=subprocess.PIPE, stdout=subprocess.PIPE)
42 conn = Conn(p.stdout, p.stdin)
43 dir = re.sub(r'[\r\n]', ' ', dir)
44 conn.write('set-dir %s\n' % dir)
47 conn.write('list-indexes\n')
48 cachedir = git.repo('index-cache/%s' % re.sub(r'[^@:\w]', '_',
49 "%s:%s" % (host, dir)))
50 packdir = git.repo('objects/pack')
54 for line in linereader(conn):
58 assert(line.find('/') < 0)
59 if (not os.path.exists(os.path.join(cachedir, line)) and
60 not os.path.exists(os.path.join(packdir, line))):
64 for f in os.listdir(cachedir):
65 if f.endswith('.idx') and not f in all:
66 log('pruning old index: %r\n' % f)
67 os.unlink(os.path.join(cachedir, f))
69 # FIXME this should be pipelined: request multiple indexes at a time, or
70 # we waste lots of network turnarounds.
71 for name in needed.keys():
72 log('requesting %r\n' % name)
73 conn.write('send-index %s\n' % name)
74 n = struct.unpack('!I', conn.read(4))[0]
76 log(' expect %d bytes\n' % n)
77 fn = os.path.join(cachedir, name)
78 f = open(fn + '.tmp', 'w')
79 for b in chunkyreader(conn, n):
83 os.rename(fn + '.tmp', fn)
84 return (p, conn, cachedir)
87 (p, conn, cachedir) = server_connect(opt.remote)
88 conn.write('receive-objects\n')
89 w = git.PackWriter_Remote(conn, objcache = git.MultiPackIndex(cachedir))
93 (shalist,tree) = hashsplit.split_to_tree(w, hashsplit.autofiles(extra))
98 for (mode,name,bin) in shalist:
99 print bin.encode('hex')
101 print tree.encode('hex')
102 if opt.commit or opt.name:
103 msg = 'bup split\n\nGenerated by command:\n%r' % sys.argv
104 ref = opt.name and ('refs/heads/%s' % opt.name) or None
105 commit = w.new_commit(ref, tree, msg)
107 print commit.encode('hex')
111 p.stdin.write('quit\n')
114 secs = time.time() - start_time
115 size = hashsplit.total_split
117 log('\nbup: %.2fkbytes in %.2f secs = %.2f kbytes/sec\n'
118 % (size/1024., secs, size/1024./secs))