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 if opt.verbose >= 2 or (status in ['A','M']
86 and not stat.S_ISDIR(ent.mode)):
87 log('\n%s %s ' % (status, ent.name))
92 assert(dir.startswith('/'))
97 for part in dirp[len(parts):]:
101 # directory already handled.
102 # FIXME: not using the indexed tree sha1's for anything, which is
103 # a waste. That's a potential optimization...
108 mode = '%o' % ent.mode
110 shalists[-1].append((mode, file, id))
113 if stat.S_ISREG(ent.mode):
115 (mode, id) = hashsplit.split_to_blob_or_tree(w, [f])
116 elif stat.S_ISDIR(ent.mode):
117 assert(0) # handled above
118 elif stat.S_ISLNK(ent.mode):
119 (mode, id) = ('120000', w.new_blob(os.readlink(ent.name)))
121 add_error(Exception('skipping special file "%s"' % ent.name))
129 shalists[-1].append((mode, file, id))
130 #log('parts out: %r\n' % parts)
131 #log('stk out: %r\n' % shalists)
132 while len(parts) > 1:
134 #log('parts out: %r\n' % parts)
135 #log('stk out: %r\n' % shalists)
136 assert(len(shalists) == 1)
137 tree = w.new_tree(shalists[-1])
141 print tree.encode('hex')
142 if opt.commit or opt.name:
143 msg = 'bup save\n\nGenerated by command:\n%r' % sys.argv
144 ref = opt.name and ('refs/heads/%s' % opt.name) or None
145 commit = w.new_commit(oldref, tree, msg)
149 print commit.encode('hex')
151 w.close() # must close before we can update the ref
155 cli.update_ref(refname, commit, oldref)
157 git.update_ref(refname, commit, oldref)
163 log('WARNING: %d errors encountered while saving.\n' % len(saved_errors))