1
# Copyright (C) 2007-2010 Canonical Ltd
1
# Copyright (C) 2007 Canonical Ltd
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
60
60
return 'DictParentsProvider(%r)' % self.ancestry
62
62
def get_parent_map(self, keys):
63
"""See StackedParentsProvider.get_parent_map"""
63
"""See _StackedParentsProvider.get_parent_map"""
64
64
ancestry = self.ancestry
65
65
return dict((k, ancestry[k]) for k in keys if k in ancestry)
67
@deprecated_function(deprecated_in((1, 16, 0)))
68
def _StackedParentsProvider(*args, **kwargs):
69
return StackedParentsProvider(*args, **kwargs)
71
class StackedParentsProvider(object):
72
"""A parents provider which stacks (or unions) multiple providers.
74
The providers are queries in the order of the provided parent_providers.
68
class _StackedParentsProvider(object):
77
70
def __init__(self, parent_providers):
78
71
self._parent_providers = parent_providers
80
73
def __repr__(self):
81
return "%s(%r)" % (self.__class__.__name__, self._parent_providers)
74
return "_StackedParentsProvider(%r)" % self._parent_providers
83
76
def get_parent_map(self, keys):
84
77
"""Get a mapping of keys => parents
155
148
return dict(self._cache)
157
150
def get_parent_map(self, keys):
158
"""See StackedParentsProvider.get_parent_map."""
151
"""See _StackedParentsProvider.get_parent_map."""
159
152
cache = self._cache
160
153
if cache is None:
161
154
cache = self._get_parent_map(keys)
258
251
right = searchers[1].seen
259
252
return (left.difference(right), right.difference(left))
261
def find_descendants(self, old_key, new_key):
262
"""Find descendants of old_key that are ancestors of new_key."""
263
child_map = self.get_child_map(self._find_descendant_ancestors(
265
graph = Graph(DictParentsProvider(child_map))
266
searcher = graph._make_breadth_first_searcher([old_key])
270
def _find_descendant_ancestors(self, old_key, new_key):
271
"""Find ancestors of new_key that may be descendants of old_key."""
272
stop = self._make_breadth_first_searcher([old_key])
273
descendants = self._make_breadth_first_searcher([new_key])
274
for revisions in descendants:
275
old_stop = stop.seen.intersection(revisions)
276
descendants.stop_searching_any(old_stop)
277
seen_stop = descendants.find_seen_ancestors(stop.step())
278
descendants.stop_searching_any(seen_stop)
279
return descendants.seen.difference(stop.seen)
281
def get_child_map(self, keys):
282
"""Get a mapping from parents to children of the specified keys.
284
This is simply the inversion of get_parent_map. Only supplied keys
285
will be discovered as children.
286
:return: a dict of key:child_list for keys.
288
parent_map = self._parents_provider.get_parent_map(keys)
290
for child, parents in sorted(parent_map.items()):
291
for parent in parents:
292
parent_child.setdefault(parent, []).append(child)
295
254
def find_distance_to_null(self, target_revision_id, known_revision_ids):
296
255
"""Find the left-hand distance to the NULL_REVISION.
346
305
return known_revnos[cur_tip] + num_steps
348
def find_lefthand_distances(self, keys):
349
"""Find the distance to null for all the keys in keys.
351
:param keys: keys to lookup.
352
:return: A dict key->distance for all of keys.
354
# Optimisable by concurrent searching, but a random spread should get
355
# some sort of hit rate.
362
(key, self.find_distance_to_null(key, known_revnos)))
363
except errors.GhostRevisionsHaveNoRevno:
366
known_revnos.append((key, -1))
367
return dict(known_revnos)
369
307
def find_unique_ancestors(self, unique_revision, common_revisions):
370
308
"""Find the unique ancestors for a revision versus others.
896
834
stop.add(parent_id)
899
def find_lefthand_merger(self, merged_key, tip_key):
900
"""Find the first lefthand ancestor of tip_key that merged merged_key.
902
We do this by first finding the descendants of merged_key, then
903
walking through the lefthand ancestry of tip_key until we find a key
904
that doesn't descend from merged_key. Its child is the key that
907
:return: The first lefthand ancestor of tip_key to merge merged_key.
908
merged_key if it is a lefthand ancestor of tip_key.
909
None if no ancestor of tip_key merged merged_key.
911
descendants = self.find_descendants(merged_key, tip_key)
912
candidate_iterator = self.iter_lefthand_ancestry(tip_key)
913
last_candidate = None
914
for candidate in candidate_iterator:
915
if candidate not in descendants:
916
return last_candidate
917
last_candidate = candidate
919
837
def find_unique_lca(self, left_revision, right_revision,
920
838
count_steps=False):
921
839
"""Find a unique LCA.
973
891
yield (ghost, None)
974
892
pending = next_pending
976
def iter_lefthand_ancestry(self, start_key, stop_keys=None):
977
if stop_keys is None:
980
def get_parents(key):
982
return self._parents_provider.get_parent_map([key])[key]
984
raise errors.RevisionNotPresent(next_key, self)
986
if next_key in stop_keys:
988
parents = get_parents(next_key)
990
if len(parents) == 0:
993
next_key = parents[0]
995
894
def iter_topo_order(self, revisions):
996
895
"""Iterate through the input revisions in topological order.
1563
1461
The recipe allows reconstruction of the same results at a later date
1564
1462
without knowing all the found keys. The essential elements are a list
1565
of keys to start and to stop at. In order to give reproducible
1463
of keys to start and and to stop at. In order to give reproducible
1566
1464
results when ghosts are encountered by a search they are automatically
1567
1465
added to the exclude list (or else ghost filling may alter the
1658
1556
def _get_keys(self, graph):
1659
1557
NULL_REVISION = revision.NULL_REVISION
1660
1558
keys = [key for (key, parents) in graph.iter_ancestry(self.heads)
1661
if key != NULL_REVISION and parents is not None]
1559
if key != NULL_REVISION]
1664
1562
def is_empty(self):
1750
1648
removed.add(node)
1755
class GraphThunkIdsToKeys(object):
1756
"""Forwards calls about 'ids' to be about keys internally."""
1758
def __init__(self, graph):
1761
def topo_sort(self):
1762
return [r for (r,) in self._graph.topo_sort()]
1764
def heads(self, ids):
1765
"""See Graph.heads()"""
1766
as_keys = [(i,) for i in ids]
1767
head_keys = self._graph.heads(as_keys)
1768
return set([h[0] for h in head_keys])
1770
def merge_sort(self, tip_revision):
1771
return self._graph.merge_sort((tip_revision,))
1774
_counters = [0,0,0,0,0,0,0]
1776
from bzrlib._known_graph_pyx import KnownGraph
1777
except ImportError, e:
1778
osutils.failed_to_load_extension(e)
1779
from bzrlib._known_graph_py import KnownGraph