##// END OF EJS Templates
bisect: keep history of all bad revisions...
Matt Mackall -
r5736:6e79d5e0 default
parent child Browse files
Show More
@@ -15,30 +15,22 b' class bisect(object):'
15 def __init__(self, ui, repo):
15 def __init__(self, ui, repo):
16 self.repo = repo
16 self.repo = repo
17 self.ui = ui
17 self.ui = ui
18 self.goodnodes = []
18 self.state = {'good': [], 'bad': [], 'skip': []}
19 self.skipnodes = []
20 self.badnode = None
21
19
22 p = self.repo.join("bisect.state")
20 p = self.repo.join("bisect.state")
23 if os.path.exists(p):
21 if os.path.exists(p):
24 for l in self.repo.opener("bisect.state"):
22 for l in self.repo.opener("bisect.state"):
25 type, node = l[:-1].split()
23 kind, node = l[:-1].split()
26 node = self.repo.lookup(node)
24 node = self.repo.lookup(node)
27 if type == "good":
25 if kind not in self.state:
28 self.goodnodes.append(node)
26 raise util.Abort(_("unknown bisect kind %s") % kind)
29 elif type == "skip":
27 self.state[kind].append(node)
30 self.skipnodes.append(node)
31 elif type == "bad":
32 self.badnode = node
33
28
34 def write(self):
29 def write(self):
35 f = self.repo.opener("bisect.state", "w")
30 f = self.repo.opener("bisect.state", "w")
36 for n in self.goodnodes:
31 for kind in self.state:
37 f.write("good %s\n" % hg.hex(n))
32 for node in self.state[kind]:
38 for n in self.skipnodes:
33 f.write("%s %s\n" % (kind, hg.hex(node)))
39 f.write("skip %s\n" % hg.hex(n))
40 if self.badnode:
41 f.write("bad %s\n" % hg.hex(self.badnode))
42
34
43 def init(self):
35 def init(self):
44 """start a new bisection"""
36 """start a new bisection"""
@@ -49,15 +41,16 b' class bisect(object):'
49 def bisect(self):
41 def bisect(self):
50 cl = self.repo.changelog
42 cl = self.repo.changelog
51 clparents = cl.parentrevs
43 clparents = cl.parentrevs
52 bad = self.badnode
44 # only the earliest bad revision matters
53 badrev = cl.rev(bad)
45 badrev = min([cl.rev(n) for n in self.state['bad']])
46 bad = cl.node(badrev)
54
47
55 # build ancestors array
48 # build ancestors array
56 ancestors = [[]] * (cl.count() + 1) # an extra for [-1]
49 ancestors = [[]] * (cl.count() + 1) # an extra for [-1]
57
50
58 # clear goodnodes from array
51 # clear good revs from array
59 for good in self.goodnodes:
52 for node in self.state['good']:
60 ancestors[cl.rev(good)] = None
53 ancestors[cl.rev(node)] = None
61 for rev in xrange(cl.count(), -1, -1):
54 for rev in xrange(cl.count(), -1, -1):
62 if ancestors[rev] is None:
55 if ancestors[rev] is None:
63 for prev in clparents(rev):
56 for prev in clparents(rev):
@@ -92,12 +85,12 b' class bisect(object):'
92 # have we narrowed it down to one entry?
85 # have we narrowed it down to one entry?
93 tot = len(ancestors[badrev])
86 tot = len(ancestors[badrev])
94 if tot == 1:
87 if tot == 1:
95 return (self.badnode, 0)
88 return (bad, 0)
96
89
97 # find the best node to test
90 # find the best node to test
98 best_rev = None
91 best_rev = None
99 best_len = -1
92 best_len = -1
100 skip = dict.fromkeys([cl.rev(s) for s in self.skipnodes])
93 skip = dict.fromkeys([cl.rev(n) for n in self.state['skip']])
101 for n in ancestors[badrev]:
94 for n in ancestors[badrev]:
102 if n in skip:
95 if n in skip:
103 continue
96 continue
@@ -114,7 +107,7 b' class bisect(object):'
114
107
115 def next(self):
108 def next(self):
116 """find and update to the next revision to test"""
109 """find and update to the next revision to test"""
117 if self.goodnodes and self.badnode:
110 if self.state['good'] and self.state['bad']:
118 node, changesets = self.bisect()
111 node, changesets = self.bisect()
119
112
120 if changesets == 0:
113 if changesets == 0:
@@ -135,19 +128,19 b' class bisect(object):'
135
128
136 def good(self, rev=None):
129 def good(self, rev=None):
137 """mark revision as good and update to the next revision to test"""
130 """mark revision as good and update to the next revision to test"""
138 self.goodnodes.append(self.repo.lookup(rev or '.'))
131 self.state['good'].append(self.repo.lookup(rev or '.'))
139 self.write()
132 self.write()
140 return self.next()
133 return self.next()
141
134
142 def skip(self, rev=None):
135 def skip(self, rev=None):
143 """mark revision as skipped and update to the next revision to test"""
136 """mark revision as skipped and update to the next revision to test"""
144 self.skipnodes.append(self.repo.lookup(rev or '.'))
137 self.state['skip'].append(self.repo.lookup(rev or '.'))
145 self.write()
138 self.write()
146 return self.next()
139 return self.next()
147
140
148 def bad(self, rev=None):
141 def bad(self, rev=None):
149 """mark revision as bad and update to the next revision to test"""
142 """mark revision as bad and update to the next revision to test"""
150 self.badnode = self.repo.lookup(rev or '.')
143 self.state['bad'].append(self.repo.lookup(rev or '.'))
151 self.write()
144 self.write()
152 return self.next()
145 return self.next()
153
146
General Comments 0
You need to be logged in to leave comments. Login now