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)
21 smaller= only back up files smaller than n bytes
23 o = options.Options('bup save', optspec)
24 (opt, flags, extra) = o.parse(sys.argv[1:])
26 git.check_repo_or_die()
27 if not (opt.tree or opt.commit or opt.name):
28 log("bup save: use one or more of -t, -c, -n\n")
31 log("bup save: no filenames given.\n")
35 git.verbose = opt.verbose - 1
36 hashsplit.split_verbosely = opt.verbose - 1
38 refname = opt.name and 'refs/heads/%s' % opt.name or None
40 cli = client.Client(opt.remote)
41 oldref = refname and cli.read_ref(refname) or None
42 w = cli.new_packwriter()
45 oldref = refname and git.read_ref(refname) or None
65 assert(len(parts) > 1)
67 shalist = shalists.pop()
68 tree = w.new_tree(shalist)
69 shalists[-1].append(('40000', part, tree))
72 for (transname,ent) in index.Reader(git.repo('bupindex')).filter(extra):
73 (dir, file) = os.path.split(ent.name)
74 exists = (ent.flags & index.IX_EXISTS)
75 hashvalid = (ent.flags & index.IX_HASHVALID) and w.exists(ent.sha)
80 if ent.sha == index.EMPTY_SHA:
86 if opt.verbose >= 2 or (status in ['A','M']
87 and not stat.S_ISDIR(ent.mode)):
88 log('\n%s %s ' % (status, ent.name))
93 assert(dir.startswith('/'))
98 for part in dirp[len(parts):]:
102 # directory already handled.
103 # FIXME: not using the indexed tree sha1's for anything, which is
104 # a waste. That's a potential optimization...
109 mode = '%o' % ent.mode
111 shalists[-1].append((mode, file, id))
112 elif opt.smaller and ent.size >= opt.smaller:
113 add_error('skipping large file "%s"' % ent.name)
116 if stat.S_ISREG(ent.mode):
118 (mode, id) = hashsplit.split_to_blob_or_tree(w, [f])
119 elif stat.S_ISDIR(ent.mode):
120 assert(0) # handled above
121 elif stat.S_ISLNK(ent.mode):
122 (mode, id) = ('120000', w.new_blob(os.readlink(ent.name)))
124 add_error(Exception('skipping special file "%s"' % ent.name))
132 shalists[-1].append((mode, file, id))
133 #log('parts out: %r\n' % parts)
134 #log('stk out: %r\n' % shalists)
135 while len(parts) > 1:
137 #log('parts out: %r\n' % parts)
138 #log('stk out: %r\n' % shalists)
139 assert(len(shalists) == 1)
140 tree = w.new_tree(shalists[-1])
144 print tree.encode('hex')
145 if opt.commit or opt.name:
146 msg = 'bup save\n\nGenerated by command:\n%r' % sys.argv
147 ref = opt.name and ('refs/heads/%s' % opt.name) or None
148 commit = w.new_commit(oldref, tree, msg)
152 print commit.encode('hex')
154 w.close() # must close before we can update the ref
158 cli.update_ref(refname, commit, oldref)
160 git.update_ref(refname, commit, oldref)
166 log('WARNING: %d errors encountered while saving.\n' % len(saved_errors))