hgext/hbisect.py
changeset 5723 e3b09819496b
parent 5722 862239055c2e
child 5724 13653ee67859
equal deleted inserted replaced
5722:862239055c2e 5723:e3b09819496b
    73         node -> number of ancestors (self included)
    73         node -> number of ancestors (self included)
    74 
    74 
    75         ancestors of goodnodes are used as lower limit.
    75         ancestors of goodnodes are used as lower limit.
    76         """
    76         """
    77         cl = self.repo.changelog
    77         cl = self.repo.changelog
    78         stop = {}
    78         clparents = cl.parentrevs
    79         bad = self.badnode
    79         bad = self.badnode
    80         for i in xrange(len(self.goodnodes)-1, -1, -1):
    80         badrev = cl.rev(bad)
    81             g = self.goodnodes[i]
    81 
    82             if g in stop:
    82         # add goodrevs and all ancestors to stop
    83                 continue
    83         stop = dict.fromkeys([cl.rev(n) for n in self.goodnodes])
    84             stop.update(cl.reachable(g))
    84         for rev in xrange(cl.count(), -1, -1):
    85 
    85             if rev in stop:
    86         if bad in stop:
    86                 for prev in clparents(rev):
       
    87                     stop[prev] = None
       
    88 
       
    89         if badrev in stop:
    87             raise util.Abort(_("Inconsistent state, %s:%s is good and bad")
    90             raise util.Abort(_("Inconsistent state, %s:%s is good and bad")
    88                              % (cl.rev(bad), hg.short(bad)))
    91                              % (badrev, hg.short(bad)))
    89 
    92 
    90         # build a dict of node -> [number of children, {}]
    93         # build a dict of node -> [number of children, {}]
    91         n_child = {bad: [0, {}]}
    94         n_child = {badrev: [0, {}]}
    92         for i in xrange(cl.rev(bad)+1):
    95         for rev in xrange(badrev + 1):
    93             n = cl.node(i)
    96             if rev not in n_child:
    94             if n not in n_child:
    97                 n_child[rev] = [0, {}]
    95                 n_child[n] = [0, {}]
       
    96             # increment count of each parent
    98             # increment count of each parent
    97             for p in cl.parents(n):
    99             for p in clparents(rev):
    98                 if p != hg.nullid:
   100                 if p != hg.nullrev:
    99                     n_child[p][0] += 1
   101                     n_child[p][0] += 1
   100 
   102 
   101         for i in xrange(cl.rev(bad)+1):
   103         for rev in xrange(badrev + 1):
   102             n = cl.node(i)
   104             for p in clparents(rev):
   103             for p in cl.parents(n):
   105                 if p != hg.nullrev:
   104                 if p != hg.nullid:
       
   105                     n_child[p][0] -= 1
   106                     n_child[p][0] -= 1
   106                     if not n in stop:
   107                     if not rev in stop:
   107                         n_child[n][1].update(n_child[p][1])
   108                         n_child[rev][1].update(n_child[p][1])
   108                     if n_child[p][0] == 0:
   109                     if n_child[p][0] == 0:
   109                         n_child[p] = len(n_child[p][1])
   110                         n_child[p] = len(n_child[p][1])
   110             if not n in stop:
   111             if not rev in stop:
   111                 n_child[n][1][n] = 1
   112                 n_child[rev][1][rev] = 1
   112             if n_child[n][0] == 0:
   113             if n_child[rev][0] == 0:
   113                 if n == bad:
   114                 if rev == badrev:
   114                     anc = n_child[n][1]
   115                     anc = n_child[rev][1]
   115                 n_child[n] = len(n_child[n][1])
   116                 n_child[rev] = len(n_child[rev][1])
       
   117 
       
   118         if badrev not in anc:
       
   119             raise util.Abort(_("Could not find the first bad revision"))
       
   120 
   116         return anc, n_child
   121         return anc, n_child
   117 
   122 
   118     def next(self):
   123     def next(self):
   119         if not self.badnode:
   124         if not self.badnode:
   120             raise util.Abort(_("You should give at least one bad revision"))
   125             raise util.Abort(_("You should give at least one bad revision"))
   124         ancestors, n_child = self.candidates()
   129         ancestors, n_child = self.candidates()
   125 
   130 
   126         # have we narrowed it down to one entry?
   131         # have we narrowed it down to one entry?
   127         tot = len(ancestors)
   132         tot = len(ancestors)
   128         if tot == 1:
   133         if tot == 1:
   129             if self.badnode not in ancestors:
       
   130                 raise util.Abort(_("Could not find the first bad revision"))
       
   131             self.ui.write(_("The first bad revision is:\n"))
   134             self.ui.write(_("The first bad revision is:\n"))
   132             displayer = cmdutil.show_changeset(self.ui, self.repo, {})
   135             displayer = cmdutil.show_changeset(self.ui, self.repo, {})
   133             displayer.show(changenode=self.badnode)
   136             displayer.show(changenode=self.badnode)
   134             return None
   137             return None
   135 
   138 
   136         # find the best node to test
   139         # find the best node to test
   137         best_node = None
   140         best_rev = None
   138         best_len = -1
   141         best_len = -1
   139         for n in ancestors:
   142         for n in ancestors:
   140             a = n_child[n] # number of children
   143             a = n_child[n] # number of children
   141             b = tot - a # number of ancestors
   144             b = tot - a # number of ancestors
   142             value = min(a, b) # how good is this test?
   145             value = min(a, b) # how good is this test?
   143             if value > best_len:
   146             if value > best_len:
   144                 best_len = value
   147                 best_len = value
   145                 best_node = n
   148                 best_rev = n
   146         assert best_node is not None
   149         assert best_rev is not None
       
   150         best_node = self.repo.changelog.node(best_rev)
   147 
   151 
   148         # compute the approximate number of remaining tests
   152         # compute the approximate number of remaining tests
   149         nb_tests = 0
   153         nb_tests = 0
   150         q, r = divmod(tot, 2)
   154         q, r = divmod(tot, 2)
   151         while q:
   155         while q:
   152             nb_tests += 1
   156             nb_tests += 1
   153             q, r = divmod(q, 2)
   157             q, r = divmod(q, 2)
   154 
   158 
   155         msg = _("Testing changeset %s:%s (%s changesets remaining, "
   159         self.ui.write(_("Testing changeset %s:%s "
   156                 "~%s tests)\n") % (self.repo.changelog.rev(best_node),
   160                         "(%s changesets remaining, ~%s tests)\n")
   157                                    hg.short(best_node), tot, nb_tests)
   161                       % (best_rev, hg.short(best_node), tot, nb_tests))
   158         self.ui.write(msg)
       
   159         return best_node
   162         return best_node
   160 
   163 
   161     def autonext(self):
   164     def autonext(self):
   162         """find and update to the next revision to test"""
   165         """find and update to the next revision to test"""
   163         node = self.next()
   166         node = self.next()