2 import sys, stat, time, os
3 from bup import options, git, index, drecurse
4 from bup.helpers import *
5 from bup.hashsplit import GIT_MODE_TREE, GIT_MODE_FILE
15 self.cur = self.i.next()
21 def check_index(reader):
23 log('check: checking forward iteration...\n')
26 for e in reader.forward_iter():
29 log('%08x+%-4d %r\n' % (e.children_ofs, e.children_n,
31 assert(e.children_ofs)
32 assert(e.name.endswith('/'))
33 assert(not d.get(e.children_ofs))
35 if e.flags & index.IX_HASHVALID:
36 assert(e.sha != index.EMPTY_SHA)
38 assert(not e or e.name == '/') # last entry is *always* /
39 log('check: checking normal iteration...\n')
46 log('index error! at %r\n' % e)
48 log('check: passed.\n')
51 def update_index(top, excluded_paths):
52 tmax = time.time() - 1
53 ri = index.Reader(indexfile)
54 wi = index.Writer(indexfile, tmax)
55 rig = IterHelper(ri.iter(name=top))
56 tstart = int(time.time())
61 return (GIT_MODE_FILE, index.FAKE_SHA)
64 bup_dir = os.path.abspath(git.repo())
65 for (path,pst) in drecurse.recursive_dirlist([top], xdev=opt.xdev,
67 excluded_paths=excluded_paths):
68 if opt.verbose>=2 or (opt.verbose==1 and stat.S_ISDIR(pst.st_mode)):
69 sys.stdout.write('%s\n' % path)
71 qprogress('Indexing: %d\r' % total)
72 elif not (total % 128):
73 qprogress('Indexing: %d\r' % total)
75 while rig.cur and rig.cur.name > path: # deleted paths
80 if rig.cur and rig.cur.name == path: # paths that already existed
82 rig.cur.from_stat(pst, tstart)
83 if not (rig.cur.flags & index.IX_HASHVALID):
85 (rig.cur.gitmode, rig.cur.sha) = hashgen(path)
86 rig.cur.flags |= index.IX_HASHVALID
92 wi.add(path, pst, hashgen = hashgen)
93 progress('Indexing: %d, done.\n' % total)
101 log('check: before merging: oldfile\n')
103 log('check: before merging: newfile\n')
105 mi = index.Writer(indexfile, tmax)
107 for e in index.merge(ri, wr):
108 # FIXME: shouldn't we remove deleted entries eventually? When?
120 bup index <-p|m|s|u> [options...] <filenames...>
123 p,print print the index entries for the given names (also works with -u)
124 m,modified print only added/deleted/modified files (implies -p)
125 s,status print each filename with a status char (A/M/D) (implies -p)
126 u,update recursively update the index entries for the given file/dir names (default if no mode is specified)
127 check carefully check index file integrity
129 H,hash print the hash for each object next to its name
130 l,long print more information about each file
131 fake-valid mark all index entries as up-to-date even if they aren't
132 fake-invalid mark all index entries as invalid
133 f,indexfile= the name of the index file (normally BUP_DIR/bupindex)
134 exclude= a path to exclude from the backup (can be used more than once)
135 exclude-from= a file that contains exclude paths (can be used more than once)
136 v,verbose increase log output (can be used more than once)
137 x,xdev,one-file-system don't cross filesystem boundaries
139 o = options.Options(optspec)
140 (opt, flags, extra) = o.parse(sys.argv[1:])
142 if not (opt.modified or opt['print'] or opt.status or opt.update or opt.check):
144 if (opt.fake_valid or opt.fake_invalid) and not opt.update:
145 o.fatal('--fake-{in,}valid are meaningless without -u')
146 if opt.fake_valid and opt.fake_invalid:
147 o.fatal('--fake-valid is incompatible with --fake-invalid')
149 git.check_repo_or_die()
150 indexfile = opt.indexfile or git.repo('bupindex')
155 log('check: starting initial check.\n')
156 check_index(index.Reader(indexfile))
158 excluded_paths = drecurse.parse_excludes(flags)
160 paths = index.reduce_paths(extra)
164 o.fatal('update mode (-u) requested but no paths given')
165 for (rp,path) in paths:
166 update_index(rp, excluded_paths)
168 if opt['print'] or opt.status or opt.modified:
169 for (name, ent) in index.Reader(indexfile).filter(extra or ['']):
171 and (ent.is_valid() or ent.is_deleted() or not ent.mode)):
177 elif not ent.is_valid():
178 if ent.sha == index.EMPTY_SHA:
185 line += ent.sha.encode('hex') + ' '
187 line += "%7s %7s " % (oct(ent.mode), oct(ent.gitmode))
188 print line + (name or './')
190 if opt.check and (opt['print'] or opt.status or opt.modified or opt.update):
191 log('check: starting final check.\n')
192 check_index(index.Reader(indexfile))
195 log('WARNING: %d errors encountered.\n' % len(saved_errors))