mercurial/hbisect.py
changeset 15146 b39d85be78a8
parent 15138 883d28233a4d
child 15147 395ca8cd2669
equal deleted inserted replaced
15145:ff26712a0c50 15146:b39d85be78a8
   158     """
   158     """
   159     Return a list of revision(s) that match the given status:
   159     Return a list of revision(s) that match the given status:
   160 
   160 
   161     - ``good``, ``bad``, ``skip``: as the names imply
   161     - ``good``, ``bad``, ``skip``: as the names imply
   162     - ``range``              : all csets taking part in the bisection
   162     - ``range``              : all csets taking part in the bisection
   163     - ``pruned``             : good|bad|skip, excluding out-of-range csets
   163     - ``pruned``             : csets that are good, bad or skipped
   164     - ``untested``           : csets whose fate is yet unknown
   164     - ``untested``           : csets whose fate is yet unknown
   165     """
   165     """
   166     state = load_state(repo)
   166     state = load_state(repo)
   167     if status in ('good', 'bad', 'skip'):
   167     if status in ('good', 'bad', 'skip'):
   168         return [repo.changelog.rev(n) for n in state[status]]
   168         return [repo.changelog.rev(n) for n in state[status]]
   169     else:
   169     else:
   170         # Build sets of good, bad, and skipped csets
   170         # In the floowing sets, we do *not* call 'bisect()' with more
   171         goods = set(repo.changelog.rev(n) for n in state['good'])
   171         # than one level of recusrsion, because that can be very, very
   172         bads  = set(repo.changelog.rev(n) for n in state['bad'])
   172         # time consuming. Instead, we always develop the expression as
   173         skips = set(repo.changelog.rev(n) for n in state['skip'])
   173         # much as possible.
   174 
   174 
   175         # Build kinship of good csets
   175         # 'range' is all csets that make the bisection:
   176         ga = goods.copy()   # Goods' Ancestors
   176         #   - have a good ancestor and a bad descendant, or conversely
   177         gd = goods.copy()   # Goods' Descendants
   177         # that's because the bisection can go either way
   178         for g in goods:
   178         range = '( bisect(bad)::bisect(good) | bisect(good)::bisect(bad) )'
   179             ga |= set(repo.changelog.ancestors(g))
   179 
   180             gd |= set(repo.changelog.descendants(g))
   180         # 'pruned' is all csets whose fate is already known:
   181 
   181         #   - a good ancestor and a good ascendant, or
   182         # Build kinship of bad csets
   182         #   - a bad ancestor and a bad descendant, or
   183         ba = bads.copy()    # Bads' Ancestors
   183         #   - skipped
   184         bd = bads.copy()    # Bads' Descendants
   184         # But in case of irrelevant goods/bads, we also need to
   185         for b in bads:
   185         # include them.
   186             ba |= set(repo.changelog.ancestors(b))
   186         pg = 'bisect(good)::bisect(good)'   # Pruned goods
   187             bd |= set(repo.changelog.descendants(b))
   187         pb = 'bisect(bad)::bisect(bad)'     # Pruned bads
   188 
   188         ps = 'bisect(skip)'                 # Pruned skipped
   189         # Build the range of the bisection
   189         pruned = '( (%s) | (%s) | (%s) )' % (pg, pb, ps)
   190         range  = set(c for c in ba if c in gd)
   190 
   191         range |= set(c for c in ga if c in bd)
   191         # 'untested' is all cset that are- in 'range', but not in 'pruned'
       
   192         untested = '( (%s) - (%s) )' % (range, pruned)
   192 
   193 
   193         if status == 'range':
   194         if status == 'range':
   194             return [c for c in range]
   195             return [c.rev() for c in repo.set(range)]
   195         elif status == 'pruned':
   196         elif status == 'pruned':
   196             # We do not want skipped csets that are out-of-range
   197             return [c.rev() for c in repo.set(pruned)]
   197             return [c for c in range if c in (goods | bads | skips)]
       
   198         elif status == 'untested':
   198         elif status == 'untested':
   199             # Return the csets in range that are not pruned
   199             return [c.rev() for c in repo.set(untested)]
   200             return [c for c in range if not c in (goods | bads | skips)]
       
   201 
   200 
   202         else:
   201         else:
   203             raise error.ParseError(_('invalid bisect state'))
   202             raise error.ParseError(_('invalid bisect state'))