1 #!/usr/bin/env python2.5
2 import sys, re, errno, stat, client
3 import hashsplit, git, options, index
14 bup save [-tc] [-n name] <filenames...>
16 r,remote= remote repository path
17 t,tree output a tree id
18 c,commit output a commit id
19 n,name= name of backup set to update (if any)
20 v,verbose increase log output (can be used more than once)
22 o = options.Options('bup save', optspec)
23 (opt, flags, extra) = o.parse(sys.argv[1:])
25 git.check_repo_or_die()
26 if not (opt.tree or opt.commit or opt.name):
27 log("bup save: use one or more of -t, -c, -n\n")
30 log("bup save: no filenames given.\n")
34 git.verbose = opt.verbose - 1
35 hashsplit.split_verbosely = opt.verbose - 1
37 refname = opt.name and 'refs/heads/%s' % opt.name or None
39 cli = client.Client(opt.remote)
40 oldref = refname and cli.read_ref(refname) or None
41 w = cli.new_packwriter()
44 oldref = refname and git.read_ref(refname) or None
64 assert(len(parts) > 1)
66 shalist = shalists.pop()
67 tree = w.new_tree(shalist)
68 shalists[-1].append(('40000', part, tree))
71 for (transname,ent) in index.Reader(git.repo('bupindex')).filter(extra):
72 (dir, file) = os.path.split(ent.name)
73 exists = (ent.flags & index.IX_EXISTS)
74 hashvalid = (ent.flags & index.IX_HASHVALID) and w.exists(ent.sha)
79 if ent.sha == index.EMPTY_SHA:
85 log('\n%s %s ' % (status, ent.name))
90 assert(dir.startswith('/'))
95 for part in dirp[len(parts):]:
99 # directory already handled.
100 # FIXME: not using the indexed tree sha1's for anything, which is
101 # a waste. That's a potential optimization...
106 mode = '%o' % ent.mode
108 shalists[-1].append((mode, file, id))
111 if stat.S_ISREG(ent.mode):
113 (mode, id) = hashsplit.split_to_blob_or_tree(w, [f])
114 elif stat.S_ISDIR(ent.mode):
115 assert(0) # handled above
116 elif stat.S_ISLNK(ent.mode):
117 (mode, id) = ('120000', w.new_blob(os.readlink(ent.name)))
119 add_error(Exception('skipping special file "%s"' % ent.name))
127 shalists[-1].append((mode, file, id))
128 #log('parts out: %r\n' % parts)
129 #log('stk out: %r\n' % shalists)
130 while len(parts) > 1:
132 #log('parts out: %r\n' % parts)
133 #log('stk out: %r\n' % shalists)
134 assert(len(shalists) == 1)
135 tree = w.new_tree(shalists[-1])
139 print tree.encode('hex')
140 if opt.commit or opt.name:
141 msg = 'bup save\n\nGenerated by command:\n%r' % sys.argv
142 ref = opt.name and ('refs/heads/%s' % opt.name) or None
143 commit = w.new_commit(oldref, tree, msg)
147 print commit.encode('hex')
149 w.close() # must close before we can update the ref
153 cli.update_ref(refname, commit, oldref)
155 git.update_ref(refname, commit, oldref)
161 log('WARNING: %d errors encountered while saving.\n' % len(saved_errors))