mercurial/revlog.py
changeset 1469 0847c45ffee6
parent 1403 bc3e66edb04c
parent 1463 26e73acc0cdf
child 1493 1a216cb4ee64
equal deleted inserted replaced
1456:214f42f23a3b 1469:0847c45ffee6
   247                 if p not in reachable:
   247                 if p not in reachable:
   248                     reachable[p] = 1
   248                     reachable[p] = 1
   249                     visit.append(p)
   249                     visit.append(p)
   250         return reachable
   250         return reachable
   251 
   251 
       
   252     def nodesbetween(self, roots=None, heads=None):
       
   253         """Return a tuple containing three elements. Elements 1 and 2 contain
       
   254         a final list bases and heads after all the unreachable ones have been
       
   255         pruned.  Element 0 contains a topologically sorted list of all
       
   256 
       
   257         nodes that satisfy these constraints:
       
   258         1. All nodes must be descended from a node in roots (the nodes on
       
   259            roots are considered descended from themselves).
       
   260         2. All nodes must also be ancestors of a node in heads (the nodes in
       
   261            heads are considered to be their own ancestors).
       
   262 
       
   263         If roots is unspecified, nullid is assumed as the only root.
       
   264         If heads is unspecified, it is taken to be the output of the
       
   265         heads method (i.e. a list of all nodes in the repository that
       
   266         have no children)."""
       
   267         nonodes = ([], [], [])
       
   268         if roots is not None:
       
   269             roots = list(roots)
       
   270             if not roots:
       
   271                 return nonodes
       
   272             lowestrev = min([self.rev(n) for n in roots])
       
   273         else:
       
   274             roots = [nullid] # Everybody's a descendent of nullid
       
   275             lowestrev = -1
       
   276         if (lowestrev == -1) and (heads is None):
       
   277             # We want _all_ the nodes!
       
   278             return ([self.node(r) for r in xrange(0, self.count())],
       
   279                     [nullid], list(self.heads()))
       
   280         if heads is None:
       
   281             # All nodes are ancestors, so the latest ancestor is the last
       
   282             # node.
       
   283             highestrev = self.count() - 1
       
   284             # Set ancestors to None to signal that every node is an ancestor.
       
   285             ancestors = None
       
   286             # Set heads to an empty dictionary for later discovery of heads
       
   287             heads = {}
       
   288         else:
       
   289             heads = list(heads)
       
   290             if not heads:
       
   291                 return nonodes
       
   292             ancestors = {}
       
   293             # Start at the top and keep marking parents until we're done.
       
   294             nodestotag = heads[:]
       
   295             # Turn heads into a dictionary so we can remove 'fake' heads.
       
   296             # Also, later we will be using it to filter out the heads we can't
       
   297             # find from roots.
       
   298             heads = dict.fromkeys(heads, 0)
       
   299             # Remember where the top was so we can use it as a limit later.
       
   300             highestrev = max([self.rev(n) for n in nodestotag])
       
   301             while nodestotag:
       
   302                 # grab a node to tag
       
   303                 n = nodestotag.pop()
       
   304                 # Never tag nullid
       
   305                 if n == nullid:
       
   306                     continue
       
   307                 # A node's revision number represents its place in a
       
   308                 # topologically sorted list of nodes.
       
   309                 r = self.rev(n)
       
   310                 if r >= lowestrev:
       
   311                     if n not in ancestors:
       
   312                         # If we are possibly a descendent of one of the roots
       
   313                         # and we haven't already been marked as an ancestor
       
   314                         ancestors[n] = 1 # Mark as ancestor
       
   315                         # Add non-nullid parents to list of nodes to tag.
       
   316                         nodestotag.extend([p for p in self.parents(n) if
       
   317                                            p != nullid])
       
   318                     elif n in heads: # We've seen it before, is it a fake head?
       
   319                         # So it is, real heads should not be the ancestors of
       
   320                         # any other heads.
       
   321                         heads.pop(n)
       
   322             if not ancestors:
       
   323                 return nonodes
       
   324             # Now that we have our set of ancestors, we want to remove any
       
   325             # roots that are not ancestors.
       
   326 
       
   327             # If one of the roots was nullid, everything is included anyway.
       
   328             if lowestrev > -1:
       
   329                 # But, since we weren't, let's recompute the lowest rev to not
       
   330                 # include roots that aren't ancestors.
       
   331 
       
   332                 # Filter out roots that aren't ancestors of heads
       
   333                 roots = [n for n in roots if n in ancestors]
       
   334                 # Recompute the lowest revision
       
   335                 if roots:
       
   336                     lowestrev = min([self.rev(n) for n in roots])
       
   337                 else:
       
   338                     # No more roots?  Return empty list
       
   339                     return nonodes
       
   340             else:
       
   341                 # We are descending from nullid, and don't need to care about
       
   342                 # any other roots.
       
   343                 lowestrev = -1
       
   344                 roots = [nullid]
       
   345         # Transform our roots list into a 'set' (i.e. a dictionary where the
       
   346         # values don't matter.
       
   347         descendents = dict.fromkeys(roots, 1)
       
   348         # Also, keep the original roots so we can filter out roots that aren't
       
   349         # 'real' roots (i.e. are descended from other roots).
       
   350         roots = descendents.copy()
       
   351         # Our topologically sorted list of output nodes.
       
   352         orderedout = []
       
   353         # Don't start at nullid since we don't want nullid in our output list,
       
   354         # and if nullid shows up in descedents, empty parents will look like
       
   355         # they're descendents.
       
   356         for r in xrange(max(lowestrev, 0), highestrev + 1):
       
   357             n = self.node(r)
       
   358             isdescendent = False
       
   359             if lowestrev == -1:  # Everybody is a descendent of nullid
       
   360                 isdescendent = True
       
   361             elif n in descendents:
       
   362                 # n is already a descendent
       
   363                 isdescendent = True
       
   364                 # This check only needs to be done here because all the roots
       
   365                 # will start being marked is descendents before the loop.
       
   366                 if n in roots:
       
   367                     # If n was a root, check if it's a 'real' root.
       
   368                     p = tuple(self.parents(n))
       
   369                     # If any of its parents are descendents, it's not a root.
       
   370                     if (p[0] in descendents) or (p[1] in descendents):
       
   371                         roots.pop(n)
       
   372             else:
       
   373                 p = tuple(self.parents(n))
       
   374                 # A node is a descendent if either of its parents are
       
   375                 # descendents.  (We seeded the dependents list with the roots
       
   376                 # up there, remember?)
       
   377                 if (p[0] in descendents) or (p[1] in descendents):
       
   378                     descendents[n] = 1
       
   379                     isdescendent = True
       
   380             if isdescendent and ((ancestors is None) or (n in ancestors)):
       
   381                 # Only include nodes that are both descendents and ancestors.
       
   382                 orderedout.append(n)
       
   383                 if (ancestors is not None) and (n in heads):
       
   384                     # We're trying to figure out which heads are reachable
       
   385                     # from roots.
       
   386                     # Mark this head as having been reached
       
   387                     heads[n] = 1
       
   388                 elif ancestors is None:
       
   389                     # Otherwise, we're trying to discover the heads.
       
   390                     # Assume this is a head because if it isn't, the next step
       
   391                     # will eventually remove it.
       
   392                     heads[n] = 1
       
   393                     # But, obviously its parents aren't.
       
   394                     for p in self.parents(n):
       
   395                         heads.pop(p, None)
       
   396         heads = [n for n in heads.iterkeys() if heads[n] != 0]
       
   397         roots = roots.keys()
       
   398         assert orderedout
       
   399         assert roots
       
   400         assert heads
       
   401         return (orderedout, roots, heads)
       
   402 
   252     def heads(self, stop=None):
   403     def heads(self, stop=None):
   253         """return the list of all nodes that have no children"""
   404         """return the list of all nodes that have no children"""
   254         p = {}
   405         p = {}
   255         h = []
   406         h = []
   256         stoprev = 0
   407         stoprev = 0
   480                 gy = y.next()
   631                 gy = y.next()
   481             else:
   632             else:
   482                 #print "next x"
   633                 #print "next x"
   483                 gx = x.next()
   634                 gx = x.next()
   484 
   635 
   485     def group(self, linkmap):
   636     def group(self, nodelist, lookup, infocollect = None):
   486         """calculate a delta group
   637         """calculate a delta group
   487 
   638 
   488         Given a list of changeset revs, return a set of deltas and
   639         Given a list of changeset revs, return a set of deltas and
   489         metadata corresponding to nodes. the first delta is
   640         metadata corresponding to nodes. the first delta is
   490         parent(nodes[0]) -> nodes[0] the receiver is guaranteed to
   641         parent(nodes[0]) -> nodes[0] the receiver is guaranteed to
   491         have this parent as it has all history before these
   642         have this parent as it has all history before these
   492         changesets. parent is parent[0]
   643         changesets. parent is parent[0]
   493         """
   644         """
   494         revs = []
   645         revs = [self.rev(n) for n in nodelist]
   495         needed = {}
   646         needed = dict.fromkeys(revs, 1)
   496 
       
   497         # find file nodes/revs that match changeset revs
       
   498         for i in xrange(0, self.count()):
       
   499             if self.index[i][3] in linkmap:
       
   500                 revs.append(i)
       
   501                 needed[i] = 1
       
   502 
   647 
   503         # if we don't have any revisions touched by these changesets, bail
   648         # if we don't have any revisions touched by these changesets, bail
   504         if not revs:
   649         if not revs:
   505             yield struct.pack(">l", 0)
   650             yield struct.pack(">l", 0)
   506             return
   651             return
   564         deltas = []
   709         deltas = []
   565         for d in xrange(0, len(revs) - 1):
   710         for d in xrange(0, len(revs) - 1):
   566             a, b = revs[d], revs[d + 1]
   711             a, b = revs[d], revs[d + 1]
   567             n = self.node(b)
   712             n = self.node(b)
   568 
   713 
       
   714             if infocollect is not None:
       
   715                 infocollect(n)
       
   716 
   569             # do we need to construct a new delta?
   717             # do we need to construct a new delta?
   570             if a + 1 != b or self.base(b) == b:
   718             if a + 1 != b or self.base(b) == b:
   571                 if a >= 0:
   719                 if a >= 0:
   572                     base = self.base(a)
   720                     base = self.base(a)
   573                     ta = chunks[self.base(a)]
   721                     ta = chunks[self.base(a)]
   585                 d = self.diff(ta, tb)
   733                 d = self.diff(ta, tb)
   586             else:
   734             else:
   587                 d = chunks[b]
   735                 d = chunks[b]
   588 
   736 
   589             p = self.parents(n)
   737             p = self.parents(n)
   590             meta = n + p[0] + p[1] + linkmap[self.linkrev(n)]
   738             meta = n + p[0] + p[1] + lookup(n)
   591             l = struct.pack(">l", len(meta) + len(d) + 4)
   739             l = struct.pack(">l", len(meta) + len(d) + 4)
   592             yield l
   740             yield l
   593             yield meta
   741             yield meta
   594             yield d
   742             yield d
   595 
   743