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 |