]> arthur.barton.de Git - bup.git/blob - cmd/split-cmd.py
44c3cdc0b960b8e7b6589c05f1ddb0d1bc72480c
[bup.git] / cmd / split-cmd.py
1 #!/usr/bin/env python
2 import sys, time
3 from bup import hashsplit, git, options, client
4 from bup.helpers import *
5
6
7 optspec = """
8 bup split [-tcb] [-n name] [--bench] [filenames...]
9 --
10 r,remote=  remote repository path
11 b,blobs    output a series of blob ids
12 t,tree     output a tree id
13 c,commit   output a commit id
14 n,name=    name of backup set to update (if any)
15 d,date=    date for the commit (seconds since the epoch)
16 q,quiet    don't print progress messages
17 v,verbose  increase log output (can be used more than once)
18 keep-boundaries  don't let one chunk span two input files
19 noop       don't actually save the data anywhere
20 copy       just copy input to output, hashsplitting along the way
21 bench      print benchmark timings to stderr
22 max-pack-size=  maximum bytes in a single pack
23 max-pack-objects=  maximum number of objects in a single pack
24 fanout=    maximum number of blobs in a single tree
25 bwlimit=   maximum bytes/sec to transmit to server
26 """
27 o = options.Options('bup split', optspec)
28 (opt, flags, extra) = o.parse(sys.argv[1:])
29
30 handle_ctrl_c()
31 git.check_repo_or_die()
32 if not (opt.blobs or opt.tree or opt.commit or opt.name or
33         opt.noop or opt.copy):
34     o.fatal("use one or more of -b, -t, -c, -n, -N, --copy")
35 if (opt.noop or opt.copy) and (opt.blobs or opt.tree or 
36                                opt.commit or opt.name):
37     o.fatal('-N and --copy are incompatible with -b, -t, -c, -n')
38
39 if opt.verbose >= 2:
40     git.verbose = opt.verbose - 1
41     opt.bench = 1
42 if opt.max_pack_size:
43     hashsplit.max_pack_size = parse_num(opt.max_pack_size)
44 if opt.max_pack_objects:
45     hashsplit.max_pack_objects = parse_num(opt.max_pack_objects)
46 if opt.fanout:
47     hashsplit.fanout = parse_num(opt.fanout)
48 if opt.blobs:
49     hashsplit.fanout = 0
50 if opt.bwlimit:
51     client.bwlimit = parse_num(opt.bwlimit)
52 if opt.date:
53     date = parse_date_or_fatal(opt.date, o.fatal)
54 else:
55     date = time.time()
56
57
58 is_reverse = os.environ.get('BUP_SERVER_REVERSE')
59 if is_reverse and opt.remote:
60     o.fatal("don't use -r in reverse mode; it's automatic")
61 start_time = time.time()
62
63 refname = opt.name and 'refs/heads/%s' % opt.name or None
64 if opt.noop or opt.copy:
65     cli = pack_writer = oldref = None
66 elif opt.remote or is_reverse:
67     if opt.remote and opt.remote.find(":") == -1:
68         o.fatal("--remote argument must contain a colon")
69     try:
70         cli = client.Client(opt.remote)
71     except client.ClientError:
72         o.fatal("server exited unexpectedly; see errors above")
73     oldref = refname and cli.read_ref(refname) or None
74     pack_writer = cli.new_packwriter()
75 else:
76     cli = None
77     oldref = refname and git.read_ref(refname) or None
78     pack_writer = git.PackWriter()
79
80 files = extra and (open(fn) for fn in extra) or [sys.stdin]
81 if pack_writer:
82     shalist = hashsplit.split_to_shalist(pack_writer, files,
83                                          keep_boundaries=opt.keep_boundaries)
84     tree = pack_writer.new_tree(shalist)
85 else:
86     last = 0
87     for (blob, bits) in hashsplit.hashsplit_iter(files,
88                                     keep_boundaries=opt.keep_boundaries):
89         hashsplit.total_split += len(blob)
90         if opt.copy:
91             sys.stdout.write(str(blob))
92         megs = hashsplit.total_split/1024/1024
93         if not opt.quiet and last != megs:
94             progress('%d Mbytes read\r' % megs)
95             last = megs
96     progress('%d Mbytes read, done.\n' % megs)
97
98 if opt.verbose:
99     log('\n')
100 if opt.blobs:
101     for (mode,name,bin) in shalist:
102         print bin.encode('hex')
103 if opt.tree:
104     print tree.encode('hex')
105 if opt.commit or opt.name:
106     msg = 'bup split\n\nGenerated by command:\n%r' % sys.argv
107     ref = opt.name and ('refs/heads/%s' % opt.name) or None
108     commit = pack_writer.new_commit(oldref, tree, date, msg)
109     if opt.commit:
110         print commit.encode('hex')
111
112 if pack_writer:
113     pack_writer.close()  # must close before we can update the ref
114
115 if opt.name:
116     if cli:
117         cli.update_ref(refname, commit, oldref)
118     else:
119         git.update_ref(refname, commit, oldref)
120
121 if cli:
122     cli.close()
123
124 secs = time.time() - start_time
125 size = hashsplit.total_split
126 if opt.bench:
127     log('\nbup: %.2fkbytes in %.2f secs = %.2f kbytes/sec\n'
128         % (size/1024., secs, size/1024./secs))