Mercurial > hg
comparison mercurial/hbisect.py @ 43077:687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Done with
python3.7 contrib/byteify-strings.py -i $(hg files 'set:mercurial/**.py - mercurial/thirdparty/** + hgext/**.py - hgext/fsmonitor/pywatchman/** - mercurial/__init__.py')
black -l 80 -t py33 -S $(hg files 'set:**.py - mercurial/thirdparty/** - "contrib/python-zstandard/**" - hgext/fsmonitor/pywatchman/**')
# skip-blame mass-reformatting only
Differential Revision: https://phab.mercurial-scm.org/D6972
author | Augie Fackler <augie@google.com> |
---|---|
date | Sun, 06 Oct 2019 09:48:39 -0400 |
parents | 2372284d9457 |
children | f37da59a36d9 |
comparison
equal
deleted
inserted
replaced
43076:2372284d9457 | 43077:687b865b95ad |
---|---|
32 """ | 32 """ |
33 | 33 |
34 repo = repo.unfiltered() | 34 repo = repo.unfiltered() |
35 changelog = repo.changelog | 35 changelog = repo.changelog |
36 clparents = changelog.parentrevs | 36 clparents = changelog.parentrevs |
37 skip = {changelog.rev(n) for n in state['skip']} | 37 skip = {changelog.rev(n) for n in state[b'skip']} |
38 | 38 |
39 def buildancestors(bad, good): | 39 def buildancestors(bad, good): |
40 badrev = min([changelog.rev(n) for n in bad]) | 40 badrev = min([changelog.rev(n) for n in bad]) |
41 ancestors = collections.defaultdict(lambda: None) | 41 ancestors = collections.defaultdict(lambda: None) |
42 for rev in repo.revs("descendants(%ln) - ancestors(%ln)", good, good): | 42 for rev in repo.revs(b"descendants(%ln) - ancestors(%ln)", good, good): |
43 ancestors[rev] = [] | 43 ancestors[rev] = [] |
44 if ancestors[badrev] is None: | 44 if ancestors[badrev] is None: |
45 return badrev, None | 45 return badrev, None |
46 return badrev, ancestors | 46 return badrev, ancestors |
47 | 47 |
48 good = False | 48 good = False |
49 badrev, ancestors = buildancestors(state['bad'], state['good']) | 49 badrev, ancestors = buildancestors(state[b'bad'], state[b'good']) |
50 if not ancestors: # looking for bad to good transition? | 50 if not ancestors: # looking for bad to good transition? |
51 good = True | 51 good = True |
52 badrev, ancestors = buildancestors(state['good'], state['bad']) | 52 badrev, ancestors = buildancestors(state[b'good'], state[b'bad']) |
53 bad = changelog.node(badrev) | 53 bad = changelog.node(badrev) |
54 if not ancestors: # now we're confused | 54 if not ancestors: # now we're confused |
55 if ( | 55 if ( |
56 len(state['bad']) == 1 | 56 len(state[b'bad']) == 1 |
57 and len(state['good']) == 1 | 57 and len(state[b'good']) == 1 |
58 and state['bad'] != state['good'] | 58 and state[b'bad'] != state[b'good'] |
59 ): | 59 ): |
60 raise error.Abort(_("starting revisions are not directly related")) | 60 raise error.Abort(_(b"starting revisions are not directly related")) |
61 raise error.Abort( | 61 raise error.Abort( |
62 _("inconsistent state, %d:%s is good and bad") | 62 _(b"inconsistent state, %d:%s is good and bad") |
63 % (badrev, short(bad)) | 63 % (badrev, short(bad)) |
64 ) | 64 ) |
65 | 65 |
66 # build children dict | 66 # build children dict |
67 children = {} | 67 children = {} |
131 # bisect is incomplete when it ends on a merge node and | 131 # bisect is incomplete when it ends on a merge node and |
132 # one of the parent was not checked. | 132 # one of the parent was not checked. |
133 parents = repo[nodes[0]].parents() | 133 parents = repo[nodes[0]].parents() |
134 if len(parents) > 1: | 134 if len(parents) > 1: |
135 if good: | 135 if good: |
136 side = state['bad'] | 136 side = state[b'bad'] |
137 else: | 137 else: |
138 side = state['good'] | 138 side = state[b'good'] |
139 num = len(set(i.node() for i in parents) & set(side)) | 139 num = len(set(i.node() for i in parents) & set(side)) |
140 if num == 1: | 140 if num == 1: |
141 return parents[0].ancestor(parents[1]) | 141 return parents[0].ancestor(parents[1]) |
142 return None | 142 return None |
143 | 143 |
144 | 144 |
145 def load_state(repo): | 145 def load_state(repo): |
146 state = {'current': [], 'good': [], 'bad': [], 'skip': []} | 146 state = {b'current': [], b'good': [], b'bad': [], b'skip': []} |
147 for l in repo.vfs.tryreadlines("bisect.state"): | 147 for l in repo.vfs.tryreadlines(b"bisect.state"): |
148 kind, node = l[:-1].split() | 148 kind, node = l[:-1].split() |
149 node = repo.unfiltered().lookup(node) | 149 node = repo.unfiltered().lookup(node) |
150 if kind not in state: | 150 if kind not in state: |
151 raise error.Abort(_("unknown bisect kind %s") % kind) | 151 raise error.Abort(_(b"unknown bisect kind %s") % kind) |
152 state[kind].append(node) | 152 state[kind].append(node) |
153 return state | 153 return state |
154 | 154 |
155 | 155 |
156 def save_state(repo, state): | 156 def save_state(repo, state): |
157 f = repo.vfs("bisect.state", "w", atomictemp=True) | 157 f = repo.vfs(b"bisect.state", b"w", atomictemp=True) |
158 with repo.wlock(): | 158 with repo.wlock(): |
159 for kind in sorted(state): | 159 for kind in sorted(state): |
160 for node in state[kind]: | 160 for node in state[kind]: |
161 f.write("%s %s\n" % (kind, hex(node))) | 161 f.write(b"%s %s\n" % (kind, hex(node))) |
162 f.close() | 162 f.close() |
163 | 163 |
164 | 164 |
165 def resetstate(repo): | 165 def resetstate(repo): |
166 """remove any bisect state from the repository""" | 166 """remove any bisect state from the repository""" |
167 if repo.vfs.exists("bisect.state"): | 167 if repo.vfs.exists(b"bisect.state"): |
168 repo.vfs.unlink("bisect.state") | 168 repo.vfs.unlink(b"bisect.state") |
169 | 169 |
170 | 170 |
171 def checkstate(state): | 171 def checkstate(state): |
172 """check we have both 'good' and 'bad' to define a range | 172 """check we have both 'good' and 'bad' to define a range |
173 | 173 |
174 Raise Abort exception otherwise.""" | 174 Raise Abort exception otherwise.""" |
175 if state['good'] and state['bad']: | 175 if state[b'good'] and state[b'bad']: |
176 return True | 176 return True |
177 if not state['good']: | 177 if not state[b'good']: |
178 raise error.Abort(_('cannot bisect (no known good revisions)')) | 178 raise error.Abort(_(b'cannot bisect (no known good revisions)')) |
179 else: | 179 else: |
180 raise error.Abort(_('cannot bisect (no known bad revisions)')) | 180 raise error.Abort(_(b'cannot bisect (no known bad revisions)')) |
181 | 181 |
182 | 182 |
183 def get(repo, status): | 183 def get(repo, status): |
184 """ | 184 """ |
185 Return a list of revision(s) that match the given status: | 185 Return a list of revision(s) that match the given status: |
191 - ``untested`` : csets whose fate is yet unknown | 191 - ``untested`` : csets whose fate is yet unknown |
192 - ``ignored`` : csets ignored due to DAG topology | 192 - ``ignored`` : csets ignored due to DAG topology |
193 - ``current`` : the cset currently being bisected | 193 - ``current`` : the cset currently being bisected |
194 """ | 194 """ |
195 state = load_state(repo) | 195 state = load_state(repo) |
196 if status in ('good', 'bad', 'skip', 'current'): | 196 if status in (b'good', b'bad', b'skip', b'current'): |
197 return map(repo.unfiltered().changelog.rev, state[status]) | 197 return map(repo.unfiltered().changelog.rev, state[status]) |
198 else: | 198 else: |
199 # In the following sets, we do *not* call 'bisect()' with more | 199 # In the following sets, we do *not* call 'bisect()' with more |
200 # than one level of recursion, because that can be very, very | 200 # than one level of recursion, because that can be very, very |
201 # time consuming. Instead, we always develop the expression as | 201 # time consuming. Instead, we always develop the expression as |
202 # much as possible. | 202 # much as possible. |
203 | 203 |
204 # 'range' is all csets that make the bisection: | 204 # 'range' is all csets that make the bisection: |
205 # - have a good ancestor and a bad descendant, or conversely | 205 # - have a good ancestor and a bad descendant, or conversely |
206 # that's because the bisection can go either way | 206 # that's because the bisection can go either way |
207 range = '( bisect(bad)::bisect(good) | bisect(good)::bisect(bad) )' | 207 range = b'( bisect(bad)::bisect(good) | bisect(good)::bisect(bad) )' |
208 | 208 |
209 _t = repo.revs('bisect(good)::bisect(bad)') | 209 _t = repo.revs(b'bisect(good)::bisect(bad)') |
210 # The sets of topologically good or bad csets | 210 # The sets of topologically good or bad csets |
211 if len(_t) == 0: | 211 if len(_t) == 0: |
212 # Goods are topologically after bads | 212 # Goods are topologically after bads |
213 goods = 'bisect(good)::' # Pruned good csets | 213 goods = b'bisect(good)::' # Pruned good csets |
214 bads = '::bisect(bad)' # Pruned bad csets | 214 bads = b'::bisect(bad)' # Pruned bad csets |
215 else: | 215 else: |
216 # Goods are topologically before bads | 216 # Goods are topologically before bads |
217 goods = '::bisect(good)' # Pruned good csets | 217 goods = b'::bisect(good)' # Pruned good csets |
218 bads = 'bisect(bad)::' # Pruned bad csets | 218 bads = b'bisect(bad)::' # Pruned bad csets |
219 | 219 |
220 # 'pruned' is all csets whose fate is already known: good, bad, skip | 220 # 'pruned' is all csets whose fate is already known: good, bad, skip |
221 skips = 'bisect(skip)' # Pruned skipped csets | 221 skips = b'bisect(skip)' # Pruned skipped csets |
222 pruned = '( (%s) | (%s) | (%s) )' % (goods, bads, skips) | 222 pruned = b'( (%s) | (%s) | (%s) )' % (goods, bads, skips) |
223 | 223 |
224 # 'untested' is all cset that are- in 'range', but not in 'pruned' | 224 # 'untested' is all cset that are- in 'range', but not in 'pruned' |
225 untested = '( (%s) - (%s) )' % (range, pruned) | 225 untested = b'( (%s) - (%s) )' % (range, pruned) |
226 | 226 |
227 # 'ignored' is all csets that were not used during the bisection | 227 # 'ignored' is all csets that were not used during the bisection |
228 # due to DAG topology, but may however have had an impact. | 228 # due to DAG topology, but may however have had an impact. |
229 # E.g., a branch merged between bads and goods, but whose branch- | 229 # E.g., a branch merged between bads and goods, but whose branch- |
230 # point is out-side of the range. | 230 # point is out-side of the range. |
231 iba = '::bisect(bad) - ::bisect(good)' # Ignored bads' ancestors | 231 iba = b'::bisect(bad) - ::bisect(good)' # Ignored bads' ancestors |
232 iga = '::bisect(good) - ::bisect(bad)' # Ignored goods' ancestors | 232 iga = b'::bisect(good) - ::bisect(bad)' # Ignored goods' ancestors |
233 ignored = '( ( (%s) | (%s) ) - (%s) )' % (iba, iga, range) | 233 ignored = b'( ( (%s) | (%s) ) - (%s) )' % (iba, iga, range) |
234 | 234 |
235 if status == 'range': | 235 if status == b'range': |
236 return repo.revs(range) | 236 return repo.revs(range) |
237 elif status == 'pruned': | 237 elif status == b'pruned': |
238 return repo.revs(pruned) | 238 return repo.revs(pruned) |
239 elif status == 'untested': | 239 elif status == b'untested': |
240 return repo.revs(untested) | 240 return repo.revs(untested) |
241 elif status == 'ignored': | 241 elif status == b'ignored': |
242 return repo.revs(ignored) | 242 return repo.revs(ignored) |
243 elif status == "goods": | 243 elif status == b"goods": |
244 return repo.revs(goods) | 244 return repo.revs(goods) |
245 elif status == "bads": | 245 elif status == b"bads": |
246 return repo.revs(bads) | 246 return repo.revs(bads) |
247 else: | 247 else: |
248 raise error.ParseError(_('invalid bisect state')) | 248 raise error.ParseError(_(b'invalid bisect state')) |
249 | 249 |
250 | 250 |
251 def label(repo, node): | 251 def label(repo, node): |
252 rev = repo.changelog.rev(node) | 252 rev = repo.changelog.rev(node) |
253 | 253 |
254 # Try explicit sets | 254 # Try explicit sets |
255 if rev in get(repo, 'good'): | 255 if rev in get(repo, b'good'): |
256 # i18n: bisect changeset status | 256 # i18n: bisect changeset status |
257 return _('good') | 257 return _(b'good') |
258 if rev in get(repo, 'bad'): | 258 if rev in get(repo, b'bad'): |
259 # i18n: bisect changeset status | 259 # i18n: bisect changeset status |
260 return _('bad') | 260 return _(b'bad') |
261 if rev in get(repo, 'skip'): | 261 if rev in get(repo, b'skip'): |
262 # i18n: bisect changeset status | 262 # i18n: bisect changeset status |
263 return _('skipped') | 263 return _(b'skipped') |
264 if rev in get(repo, 'untested') or rev in get(repo, 'current'): | 264 if rev in get(repo, b'untested') or rev in get(repo, b'current'): |
265 # i18n: bisect changeset status | 265 # i18n: bisect changeset status |
266 return _('untested') | 266 return _(b'untested') |
267 if rev in get(repo, 'ignored'): | 267 if rev in get(repo, b'ignored'): |
268 # i18n: bisect changeset status | 268 # i18n: bisect changeset status |
269 return _('ignored') | 269 return _(b'ignored') |
270 | 270 |
271 # Try implicit sets | 271 # Try implicit sets |
272 if rev in get(repo, 'goods'): | 272 if rev in get(repo, b'goods'): |
273 # i18n: bisect changeset status | 273 # i18n: bisect changeset status |
274 return _('good (implicit)') | 274 return _(b'good (implicit)') |
275 if rev in get(repo, 'bads'): | 275 if rev in get(repo, b'bads'): |
276 # i18n: bisect changeset status | 276 # i18n: bisect changeset status |
277 return _('bad (implicit)') | 277 return _(b'bad (implicit)') |
278 | 278 |
279 return None | 279 return None |
280 | 280 |
281 | 281 |
282 def printresult(ui, repo, state, displayer, nodes, good): | 282 def printresult(ui, repo, state, displayer, nodes, good): |
283 repo = repo.unfiltered() | 283 repo = repo.unfiltered() |
284 if len(nodes) == 1: | 284 if len(nodes) == 1: |
285 # narrowed it down to a single revision | 285 # narrowed it down to a single revision |
286 if good: | 286 if good: |
287 ui.write(_("The first good revision is:\n")) | 287 ui.write(_(b"The first good revision is:\n")) |
288 else: | 288 else: |
289 ui.write(_("The first bad revision is:\n")) | 289 ui.write(_(b"The first bad revision is:\n")) |
290 displayer.show(repo[nodes[0]]) | 290 displayer.show(repo[nodes[0]]) |
291 extendnode = extendrange(repo, state, nodes, good) | 291 extendnode = extendrange(repo, state, nodes, good) |
292 if extendnode is not None: | 292 if extendnode is not None: |
293 ui.write( | 293 ui.write( |
294 _( | 294 _( |
295 'Not all ancestors of this changeset have been' | 295 b'Not all ancestors of this changeset have been' |
296 ' checked.\nUse bisect --extend to continue the ' | 296 b' checked.\nUse bisect --extend to continue the ' |
297 'bisection from\nthe common ancestor, %s.\n' | 297 b'bisection from\nthe common ancestor, %s.\n' |
298 ) | 298 ) |
299 % extendnode | 299 % extendnode |
300 ) | 300 ) |
301 else: | 301 else: |
302 # multiple possible revisions | 302 # multiple possible revisions |
303 if good: | 303 if good: |
304 ui.write( | 304 ui.write( |
305 _( | 305 _( |
306 "Due to skipped revisions, the first " | 306 b"Due to skipped revisions, the first " |
307 "good revision could be any of:\n" | 307 b"good revision could be any of:\n" |
308 ) | 308 ) |
309 ) | 309 ) |
310 else: | 310 else: |
311 ui.write( | 311 ui.write( |
312 _( | 312 _( |
313 "Due to skipped revisions, the first " | 313 b"Due to skipped revisions, the first " |
314 "bad revision could be any of:\n" | 314 b"bad revision could be any of:\n" |
315 ) | 315 ) |
316 ) | 316 ) |
317 for n in nodes: | 317 for n in nodes: |
318 displayer.show(repo[n]) | 318 displayer.show(repo[n]) |
319 displayer.close() | 319 displayer.close() |