Mercurial > hg
comparison hgext/hbisect.py @ 5721:8d63fa48d44a
bisect: clarify some bisection code
- rename __ancestors... to candidates
- remove head parameter (it's always badrev)
- eliminate comprehensions to shrink parents
- num_ancestors -> n_child name fix
- clarify node selection
author | Matt Mackall <mpm@selenic.com> |
---|---|
date | Thu, 27 Dec 2007 23:55:39 -0600 |
parents | bd86c9f2f697 |
children | 862239055c2e |
comparison
equal
deleted
inserted
replaced
5720:bd86c9f2f697 | 5721:8d63fa48d44a |
---|---|
64 #self.ui.write("Going back to tip\n") | 64 #self.ui.write("Going back to tip\n") |
65 #self.repo.update(self.repo.changelog.tip()) | 65 #self.repo.update(self.repo.changelog.tip()) |
66 self.is_reset = True | 66 self.is_reset = True |
67 return 0 | 67 return 0 |
68 | 68 |
69 def __ancestors_and_nb_ancestors(self, head): | 69 def candidates(self): |
70 """ | 70 """ |
71 returns (anc, n_child) where anc is the set of the ancestors of head | 71 returns (anc, n_child) where anc is the set of the ancestors of head |
72 and n_child is a dictionary with the following mapping: | 72 and n_child is a dictionary with the following mapping: |
73 node -> number of ancestors (self included) | 73 node -> number of ancestors (self included) |
74 | 74 |
75 ancestors of goodrevs are used as lower limit. | 75 ancestors of goodrevs are used as lower limit. |
76 """ | 76 """ |
77 cl = self.repo.changelog | 77 cl = self.repo.changelog |
78 stop = {} | 78 stop = {} |
79 bad = self.badrev | |
79 for i in xrange(len(self.goodrevs)-1, -1, -1): | 80 for i in xrange(len(self.goodrevs)-1, -1, -1): |
80 g = self.goodrevs[i] | 81 g = self.goodrevs[i] |
81 if g in stop: | 82 if g in stop: |
82 continue | 83 continue |
83 stop.update(cl.reachable(g)) | 84 stop.update(cl.reachable(g)) |
84 | 85 |
85 if head in stop: | 86 if bad in stop: |
86 raise util.Abort(_("Inconsistent state, %s:%s is good and bad") | 87 raise util.Abort(_("Inconsistent state, %s:%s is good and bad") |
87 % (cl.rev(head), hg.short(head))) | 88 % (cl.rev(bad), hg.short(bad))) |
88 | 89 |
89 # build a dict of node -> [number of children, {}] | 90 # build a dict of node -> [number of children, {}] |
90 n_child = {head: [0, {}]} | 91 n_child = {bad: [0, {}]} |
91 for i in xrange(cl.rev(head)+1): | 92 for i in xrange(cl.rev(bad)+1): |
92 n = cl.node(i) | 93 n = cl.node(i) |
93 if n not in d: | 94 if n not in n_child: |
94 n_child[n] = [0, {}] | 95 n_child[n] = [0, {}] |
95 parents = [p for p in cl.parents(n) if p != hg.nullid] | 96 # increment count of each parent |
96 for p in parents: | 97 for p in cl.parents(n): |
97 n_child[p][0] += 1 | 98 if p != hg.nullid: |
98 | 99 n_child[p][0] += 1 |
99 for i in xrange(cl.rev(head)+1): | 100 |
101 for i in xrange(cl.rev(bad)+1): | |
100 n = cl.node(i) | 102 n = cl.node(i) |
101 parents = [p for p in cl.parents(n) if p != hg.nullid] | 103 for p in cl.parents(n): |
102 for p in parents: | 104 if p != hg.nullid: |
103 n_child[p][0] -= 1 | 105 n_child[p][0] -= 1 |
104 if not n in stop: | 106 if not n in stop: |
105 n_child[n][1].update(n_child[p][1]) | 107 n_child[n][1].update(n_child[p][1]) |
106 if n_child[p][0] == 0: | 108 if n_child[p][0] == 0: |
107 n_child[p] = len(n_child[p][1]) | 109 n_child[p] = len(n_child[p][1]) |
108 if not n in stop: | 110 if not n in stop: |
109 n_child[n][1][n] = 1 | 111 n_child[n][1][n] = 1 |
110 if n_child[n][0] == 0: | 112 if n_child[n][0] == 0: |
111 if n == head: | 113 if n == bad: |
112 anc = n_child[n][1] | 114 anc = n_child[n][1] |
113 n_child[n] = len(n_child[n][1]) | 115 n_child[n] = len(n_child[n][1]) |
114 return anc, n_child | 116 return anc, n_child |
115 | 117 |
116 def next(self): | 118 def next(self): |
117 if not self.badrev: | 119 if not self.badrev: |
118 raise util.Abort(_("You should give at least one bad revision")) | 120 raise util.Abort(_("You should give at least one bad revision")) |
119 if not self.goodrevs: | 121 if not self.goodrevs: |
120 self.ui.warn(_("No good revision given\n")) | 122 self.ui.warn(_("No good revision given\n")) |
121 self.ui.warn(_("Marking the first revision as good\n")) | 123 self.ui.warn(_("Marking the first revision as good\n")) |
122 ancestors, num_ancestors = self.__ancestors_and_nb_ancestors( | 124 ancestors, n_child = self.candidates() |
123 self.badrev) | 125 |
126 # have we narrowed it down to one entry? | |
124 tot = len(ancestors) | 127 tot = len(ancestors) |
125 if tot == 1: | 128 if tot == 1: |
126 if self.badrev not in ancestors: | 129 if self.badrev not in ancestors: |
127 raise util.Abort(_("Could not find the first bad revision")) | 130 raise util.Abort(_("Could not find the first bad revision")) |
128 self.ui.write(_("The first bad revision is:\n")) | 131 self.ui.write(_("The first bad revision is:\n")) |
129 displayer = cmdutil.show_changeset(self.ui, self.repo, {}) | 132 displayer = cmdutil.show_changeset(self.ui, self.repo, {}) |
130 displayer.show(changenode=self.badrev) | 133 displayer.show(changenode=self.badrev) |
131 return None | 134 return None |
135 | |
136 # find the best node to test | |
132 best_rev = None | 137 best_rev = None |
133 best_len = -1 | 138 best_len = -1 |
134 for n in ancestors: | 139 for n in ancestors: |
135 l = num_ancestors[n] | 140 a = n_child[n] # number of children |
136 l = min(l, tot - l) | 141 b = tot - a # number of ancestors |
137 if l > best_len: | 142 value = min(a, b) # how good is this test? |
138 best_len = l | 143 if value > best_len: |
144 best_len = value | |
139 best_rev = n | 145 best_rev = n |
140 assert best_rev is not None | 146 assert best_rev is not None |
147 | |
148 # compute the approximate number of remaining tests | |
141 nb_tests = 0 | 149 nb_tests = 0 |
142 q, r = divmod(tot, 2) | 150 q, r = divmod(tot, 2) |
143 while q: | 151 while q: |
144 nb_tests += 1 | 152 nb_tests += 1 |
145 q, r = divmod(q, 2) | 153 q, r = divmod(q, 2) |
154 | |
146 msg = _("Testing changeset %s:%s (%s changesets remaining, " | 155 msg = _("Testing changeset %s:%s (%s changesets remaining, " |
147 "~%s tests)\n") % (self.repo.changelog.rev(best_rev), | 156 "~%s tests)\n") % (self.repo.changelog.rev(best_rev), |
148 hg.short(best_rev), tot, nb_tests) | 157 hg.short(best_rev), tot, nb_tests) |
149 self.ui.write(msg) | 158 self.ui.write(msg) |
150 return best_rev | 159 return best_rev |