mercurial/revlog.py
changeset 1457 518da3c3b6ce
parent 1351 0e2be889ccd7
child 1458 1033892bbb87
equal deleted inserted replaced
1389:9b3ef6f3cef5 1457:518da3c3b6ce
   244                 if p not in reachable:
   244                 if p not in reachable:
   245                     reachable[p] = 1
   245                     reachable[p] = 1
   246                     visit.append(p)
   246                     visit.append(p)
   247         return reachable
   247         return reachable
   248 
   248 
       
   249     def nodesbetween(self, roots=None, heads=None):
       
   250         """Return a tuple containing three elements. Elements 1 and 2 contain
       
   251         a final list bases and heads after all the unreachable ones have been
       
   252         pruned.  Element 0 contains a topologically sorted list of all
       
   253 
       
   254         nodes that satisfy these constraints:
       
   255         1. All nodes must be descended from a node in roots (the nodes on
       
   256            roots are considered descended from themselves).
       
   257         2. All nodes must also be ancestors of a node in heads (the nodes in
       
   258            heads are considered to be their own ancestors).
       
   259 
       
   260         If roots is unspecified, nullid is assumed as the only root.
       
   261         If heads is unspecified, it is taken to be the output of the
       
   262         heads method (i.e. a list of all nodes in the repository that
       
   263         have no children)."""
       
   264         if roots is not None:
       
   265             roots = list(roots)
       
   266             lowestrev = min([self.rev(n) for n in roots])
       
   267         else:
       
   268             roots = [nullid] # Everybody's a descendent of nullid
       
   269             lowestrev = -1
       
   270         if (lowestrev == -1) and (heads is None):
       
   271             # We want _all_ the nodes!
       
   272             return ([self.node(r) for r in xrange(0, self.count())],
       
   273                     [nullid], list(self.heads()))
       
   274         if heads is None:
       
   275             # All nodes are ancestors, so the latest ancestor is the last
       
   276             # node.
       
   277             highestrev = self.count() - 1
       
   278             # Set ancestors to None to signal that every node is an ancestor.
       
   279             ancestors = None
       
   280             # Set heads to an empty dictionary for later discovery of heads
       
   281             heads = {}
       
   282         else:
       
   283             ancestors = {}
       
   284             # Start at the top and keep marking parents until we're done.
       
   285             nodestotag = list(heads)
       
   286             # Turn heads into a dictionary so we can remove 'fake' heads.
       
   287             # Also, later we will be using it to filter out the heads we can't
       
   288             # find from roots.
       
   289             heads = dict.fromkeys(heads, 0)
       
   290             # Remember where the top was so we can use it as a limit later.
       
   291             highestrev = max([self.rev(n) for n in nodestotag])
       
   292             while nodestotag:
       
   293                 # grab a node to tag
       
   294                 n = nodestotag.pop()
       
   295                 # Never tag nullid
       
   296                 if n == nullid:
       
   297                     continue
       
   298                 # A node's revision number represents its place in a
       
   299                 # topologically sorted list of nodes.
       
   300                 r = self.rev(n)
       
   301                 if r >= lowestrev:
       
   302                     if n not in ancestors:
       
   303                         # If we are possibly a descendent of one of the roots
       
   304                         # and we haven't already been marked as an ancestor
       
   305                         ancestors[n] = 1 # Mark as ancestor
       
   306                         # Add non-nullid parents to list of nodes to tag.
       
   307                         nodestotag.extend([p for p in self.parents(n) if
       
   308                                            p != nullid])
       
   309                     elif n in heads: # We've seen it before, is it a fake head?
       
   310                         # So it is, real heads should not be the ancestors of
       
   311                         # any other heads.
       
   312                         heads.pop(n)
       
   313             # Now that we have our set of ancestors, we want to remove any
       
   314             # roots that are not ancestors.
       
   315 
       
   316             # If one of the roots was nullid, everything is included anyway.
       
   317             if lowestrev > -1:
       
   318                 # But, since we weren't, let's recompute the lowest rev to not
       
   319                 # include roots that aren't ancestors.
       
   320 
       
   321                 # Filter out roots that aren't ancestors of heads
       
   322                 roots = [n for n in roots if n in ancestors]
       
   323                 # Recompute the lowest revision
       
   324                 if roots:
       
   325                     lowestrev = min([self.rev(n) for n in roots])
       
   326                 else:
       
   327                     # No more roots?  Return empty list
       
   328                     return ([], [], [])
       
   329             else:
       
   330                 # We are descending from nullid, and don't need to care about
       
   331                 # any other roots.
       
   332                 lowestrev = -1
       
   333                 roots = [nullid]
       
   334         # Transform our roots list into a 'set' (i.e. a dictionary where the
       
   335         # values don't matter.
       
   336         descendents = dict.fromkeys(roots, 1)
       
   337         # Also, keep the original roots so we can filter out roots that aren't
       
   338         # 'real' roots (i.e. are descended from other roots).
       
   339         roots = descendents.copy()
       
   340         # Our topologically sorted list of output nodes.
       
   341         orderedout = []
       
   342         # Don't start at nullid since we don't want nullid in our output list,
       
   343         # and if nullid shows up in descedents, empty parents will look like
       
   344         # they're descendents.
       
   345         for r in xrange(max(lowestrev, 0), highestrev + 1):
       
   346             n = self.node(r)
       
   347             isdescendent = False
       
   348             if lowestrev == -1:  # Everybody is a descendent of nullid
       
   349                 isdescendent = True
       
   350             elif n in descendents:
       
   351                 # n is already a descendent
       
   352                 isdescendent = True
       
   353                 # This check only needs to be done here because all the roots
       
   354                 # will start being marked is descendents before the loop.
       
   355                 if n in roots:
       
   356                     # If n was a root, check if it's a 'real' root.
       
   357                     p = tuple(self.parents(n))
       
   358                     # If any of its parents are descendents, it's not a root.
       
   359                     if (p[0] in descendents) or (p[1] in descendents):
       
   360                         roots.pop(n)
       
   361             else:
       
   362                 p = tuple(self.parents(n))
       
   363                 # A node is a descendent if either of its parents are
       
   364                 # descendents.  (We seeded the dependents list with the roots
       
   365                 # up there, remember?)
       
   366                 if (p[0] in descendents) or (p[1] in descendents):
       
   367                     descendents[n] = 1
       
   368                     isdescendent = True
       
   369             if isdescendent and ((ancestors is None) or (n in ancestors)):
       
   370                 # Only include nodes that are both descendents and ancestors.
       
   371                 orderedout.append(n)
       
   372                 if (ancestors is not None) and (n in heads):
       
   373                     # We're trying to figure out which heads are reachable
       
   374                     # from roots.
       
   375                     # Mark this head as having been reached
       
   376                     heads[n] = 1
       
   377                 elif ancestors is None:
       
   378                     # Otherwise, we're trying to discover the heads.
       
   379                     # Assume this is a head because if it isn't, the next step
       
   380                     # will eventually remove it.
       
   381                     heads[n] = 1
       
   382                     # But, obviously its parents aren't.
       
   383                     for p in self.parents(n):
       
   384                         heads.pop(p, None)
       
   385         heads = [n for n in heads.iterkeys() if heads[n] != 0]
       
   386         roots = roots.keys()
       
   387         assert orderedout
       
   388         assert roots
       
   389         assert heads
       
   390         return (orderedout, roots, heads)
       
   391 
   249     def heads(self, stop=None):
   392     def heads(self, stop=None):
   250         """return the list of all nodes that have no children"""
   393         """return the list of all nodes that have no children"""
   251         p = {}
   394         p = {}
   252         h = []
   395         h = []
   253         stoprev = 0
   396         stoprev = 0