3 from bup import hashsplit, git, options, client
4 from bup.helpers import *
8 bup split <-t|-c|-b|-n name|--copy|--noop> [--bench] [filenames...]
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= save the result under the given name
15 noop split the input, but throw away the result
16 copy split the input, copy it to stdout, don't save to repo
18 r,remote= remote repository path
19 d,date= date for the commit (seconds since the epoch)
20 q,quiet don't print progress messages
21 v,verbose increase log output (can be used more than once)
22 git-ids read a list of git object ids from stdin and split their contents
23 keep-boundaries don't let one chunk span two input files
24 bench print benchmark timings to stderr
25 max-pack-size= maximum bytes in a single pack
26 max-pack-objects= maximum number of objects in a single pack
27 fanout= maximum number of blobs in a single tree
28 bwlimit= maximum bytes/sec to transmit to server
30 o = options.Options(optspec)
31 (opt, flags, extra) = o.parse(sys.argv[1:])
34 git.check_repo_or_die()
35 if not (opt.blobs or opt.tree or opt.commit or opt.name or
36 opt.noop or opt.copy):
37 o.fatal("use one or more of -b, -t, -c, -n, -N, --copy")
38 if (opt.noop or opt.copy) and (opt.blobs or opt.tree or
39 opt.commit or opt.name):
40 o.fatal('-N and --copy are incompatible with -b, -t, -c, -n')
41 if opt.blobs and (opt.tree or opt.commit or opt.name):
42 o.fatal('-b is incompatible with -t, -c, -n')
43 if extra and opt.git_ids:
44 o.fatal("don't provide filenames when using --git-ids")
47 git.verbose = opt.verbose - 1
50 git.max_pack_size = parse_num(opt.max_pack_size)
51 if opt.max_pack_objects:
52 git.max_pack_objects = parse_num(opt.max_pack_objects)
54 hashsplit.fanout = parse_num(opt.fanout)
58 client.bwlimit = parse_num(opt.bwlimit)
60 date = parse_date_or_fatal(opt.date, o.fatal)
66 def prog(filenum, nbytes):
70 qprogress('Splitting: file #%d, %d kbytes\r'
71 % (filenum+1, total_bytes/1024))
73 qprogress('Splitting: %d kbytes\r' % (total_bytes/1024))
76 is_reverse = os.environ.get('BUP_SERVER_REVERSE')
77 if is_reverse and opt.remote:
78 o.fatal("don't use -r in reverse mode; it's automatic")
79 start_time = time.time()
81 if opt.name and opt.name.startswith('.'):
82 o.fatal("'%s' is not a valid branch name." % opt.name)
83 refname = opt.name and 'refs/heads/%s' % opt.name or None
84 if opt.noop or opt.copy:
85 cli = pack_writer = oldref = None
86 elif opt.remote or is_reverse:
87 cli = client.Client(opt.remote)
88 oldref = refname and cli.read_ref(refname) or None
89 pack_writer = cli.new_packwriter()
92 oldref = refname and git.read_ref(refname) or None
93 pack_writer = git.PackWriter()
96 # the input is actually a series of git object ids that we should retrieve
99 # This is a bit messy, but basically it converts from a series of
100 # CatPipe.get() iterators into a series of file-type objects.
101 # It would be less ugly if either CatPipe.get() returned a file-like object
102 # (not very efficient), or split_to_shalist() expected an iterator instead
106 def __init__(self, it):
108 def read(self, size):
113 line = sys.stdin.readline()
119 it = cp.get(line.strip())
120 next(it) # skip the file type
122 add_error('error: %s' % e)
127 # the input either comes from a series of files or from stdin.
128 files = extra and (open(fn) for fn in extra) or [sys.stdin]
130 if pack_writer and opt.blobs:
131 shalist = hashsplit.split_to_blobs(pack_writer.new_blob, files,
132 keep_boundaries=opt.keep_boundaries,
134 for (sha, size, level) in shalist:
135 print sha.encode('hex')
137 elif pack_writer: # tree or commit or name
138 shalist = hashsplit.split_to_shalist(pack_writer.new_blob,
139 pack_writer.new_tree,
141 keep_boundaries=opt.keep_boundaries,
143 tree = pack_writer.new_tree(shalist)
146 it = hashsplit.hashsplit_iter(files,
147 keep_boundaries=opt.keep_boundaries,
149 for (blob, level) in it:
150 hashsplit.total_split += len(blob)
152 sys.stdout.write(str(blob))
153 megs = hashsplit.total_split/1024/1024
154 if not opt.quiet and last != megs:
160 print tree.encode('hex')
161 if opt.commit or opt.name:
162 msg = 'bup split\n\nGenerated by command:\n%r' % sys.argv
163 ref = opt.name and ('refs/heads/%s' % opt.name) or None
164 commit = pack_writer.new_commit(oldref, tree, date, msg)
166 print commit.encode('hex')
169 pack_writer.close() # must close before we can update the ref
173 cli.update_ref(refname, commit, oldref)
175 git.update_ref(refname, commit, oldref)
180 secs = time.time() - start_time
181 size = hashsplit.total_split
183 log('bup: %.2fkbytes in %.2f secs = %.2f kbytes/sec\n'
184 % (size/1024., secs, size/1024./secs))
187 log('WARNING: %d errors encountered while saving.\n' % len(saved_errors))