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.
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