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()