]> arthur.barton.de Git - bup.git/blob - cmd-index.py
Speed up cmd-drecurse by 40%.
[bup.git] / cmd-index.py
1 #!/usr/bin/env python
2 import os, sys, stat, time
3 import options, git, index, drecurse
4 from helpers import *
5
6
7 def merge_indexes(out, r1, r2):
8     log('bup: merging indexes.\n')
9     for e in index._last_writer_wins_iter([r1, r2]):
10         #if e.flags & index.IX_EXISTS:
11             out.add_ixentry(e)
12
13
14 class IterHelper:
15     def __init__(self, l):
16         self.i = iter(l)
17         self.cur = None
18         self.next()
19
20     def next(self):
21         try:
22             self.cur = self.i.next()
23         except StopIteration:
24             self.cur = None
25         return self.cur
26
27
28 def update_index(top):
29     ri = index.Reader(indexfile)
30     wi = index.Writer(indexfile)
31     rig = IterHelper(ri.iter(name=top))
32     tstart = int(time.time())
33
34     hashgen = None
35     if opt.fake_valid:
36         def hashgen(name):
37             return (0, index.FAKE_SHA)
38
39     #log('doing: %r\n' % paths)
40
41     for (path,pst) in drecurse.recursive_dirlist([top], xdev=opt.xdev):
42         #log('got: %r\n' % path)
43         if opt.verbose>=2 or (opt.verbose==1 and stat.S_ISDIR(pst.st_mode)):
44             sys.stdout.write('%s\n' % path)
45             sys.stdout.flush()
46         while rig.cur and rig.cur.name > path:  # deleted paths
47             rig.cur.set_deleted()
48             rig.cur.repack()
49             rig.next()
50         if rig.cur and rig.cur.name == path:    # paths that already existed
51             if pst:
52                 rig.cur.from_stat(pst, tstart)
53             if not (rig.cur.flags & index.IX_HASHVALID):
54                 if hashgen:
55                     (rig.cur.gitmode, rig.cur.sha) = hashgen(path)
56                     rig.cur.flags |= index.IX_HASHVALID
57                 rig.cur.repack()
58             rig.next()
59         else:  # new paths
60             #log('adding: %r\n' % path)
61             wi.add(path, pst, hashgen = hashgen)
62     
63     if ri.exists():
64         ri.save()
65         wi.flush()
66         if wi.count:
67             mi = index.Writer(indexfile)
68             merge_indexes(mi, ri, wi.new_reader())
69             ri.close()
70             mi.close()
71         wi.abort()
72     else:
73         wi.close()
74
75
76 optspec = """
77 bup index <-p|s|m|u> [options...] <filenames...>
78 --
79 p,print    print the index entries for the given names (also works with -u)
80 m,modified print only added/deleted/modified files (implies -p)
81 s,status   print each filename with a status char (A/M/D) (implies -p)
82 H,hash     print the hash for each object next to its name (implies -p)
83 u,update   (recursively) update the index entries for the given filenames
84 x,xdev,one-file-system  don't cross filesystem boundaries
85 fake-valid    mark all index entries as up-to-date even if they aren't
86 f,indexfile=  the name of the index file (default 'index')
87 v,verbose  increase log output (can be used more than once)
88 """
89 o = options.Options('bup index', optspec)
90 (opt, flags, extra) = o.parse(sys.argv[1:])
91
92 if not (opt.modified or opt['print'] or opt.status or opt.update):
93     log('bup index: you must supply one or more of -p, -s, -m, or -u\n')
94     o.usage()
95 if opt.fake_valid and not opt.update:
96     log('bup index: --fake-valid is meaningless without -u\n')
97     o.usage()
98
99 git.check_repo_or_die()
100 indexfile = opt.indexfile or git.repo('bupindex')
101
102 paths = index.reduce_paths(extra)
103
104 if opt.update:
105     if not paths:
106         log('bup index: update (-u) requested but no paths given\n')
107         o.usage()
108     for (rp,path) in paths:
109         update_index(rp)
110
111 if opt['print'] or opt.status or opt.modified:
112     for (name, ent) in index.Reader(indexfile).filter(extra or ['']):
113         if opt.modified and (ent.flags & index.IX_HASHVALID
114                              or stat.S_ISDIR(ent.mode)):
115             continue
116         line = ''
117         if opt.status:
118             if not ent.flags & index.IX_EXISTS:
119                 line += 'D '
120             elif not ent.flags & index.IX_HASHVALID:
121                 if ent.sha == index.EMPTY_SHA:
122                     line += 'A '
123                 else:
124                     line += 'M '
125             else:
126                 line += '  '
127         if opt.hash:
128             line += ent.sha.encode('hex') + ' '
129         print line + (name or './')
130         #print repr(ent)
131
132 if saved_errors:
133     log('WARNING: %d errors encountered.\n' % len(saved_errors))
134     sys.exit(1)