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
63 assert(len(parts) > 1)
65 shalist = shalists.pop()
66 tree = w.new_tree(shalist)
67 shalists[-1].append(('40000', part, tree))
70 for (transname,ent) in index.Reader(git.repo('bupindex')).filter(extra):
71 (dir, file) = os.path.split(ent.name)
72 exists = (ent.flags & index.IX_EXISTS)
73 hashvalid = (ent.flags & index.IX_HASHVALID) and w.exists(ent.sha)
78 if ent.sha == index.EMPTY_SHA:
84 log('\n%s %s ' % (status, ent.name))
89 assert(dir.startswith('/'))
93 for part in dirp[len(parts):]:
97 # directory already handled.
98 # FIXME: not using the indexed tree sha1's for anything, which is
99 # a waste. That's a potential optimization...
104 mode = '%o' % ent.mode
106 shalists[-1].append((mode, file, id))
109 if stat.S_ISREG(ent.mode):
111 (mode, id) = hashsplit.split_to_blob_or_tree(w, [f])
112 elif stat.S_ISDIR(ent.mode):
113 assert(0) # handled above
114 elif stat.S_ISLNK(ent.mode):
115 (mode, id) = ('120000', w.new_blob(os.readlink(ent.name)))
117 add_error(Exception('skipping special file "%s"' % ent.name))
125 shalists[-1].append((mode, file, id))
126 #log('parts out: %r\n' % parts)
127 #log('stk out: %r\n' % shalists)
128 while len(parts) > 1:
130 #log('parts out: %r\n' % parts)
131 #log('stk out: %r\n' % shalists)
132 assert(len(shalists) == 1)
133 tree = w.new_tree(shalists[-1])
137 print tree.encode('hex')
138 if opt.commit or opt.name:
139 msg = 'bup save\n\nGenerated by command:\n%r' % sys.argv
140 ref = opt.name and ('refs/heads/%s' % opt.name) or None
141 commit = w.new_commit(oldref, tree, msg)
145 print commit.encode('hex')
147 w.close() # must close before we can update the ref
151 cli.update_ref(refname, commit, oldref)
153 git.update_ref(refname, commit, oldref)
159 log('WARNING: %d errors encountered while saving.\n' % len(saved_errors))