53
52
def __repr__(self):
54
53
return 'DictParentsProvider(%r)' % self.ancestry
56
@symbol_versioning.deprecated_method(symbol_versioning.one_one)
57
55
def get_parents(self, revisions):
58
56
return [self.ancestry.get(r, None) for r in revisions]
60
def get_parent_map(self, keys):
61
"""See _StackedParentsProvider.get_parent_map"""
62
ancestry = self.ancestry
63
return dict((k, ancestry[k]) for k in keys if k in ancestry)
66
59
class _StackedParentsProvider(object):
84
76
If the revision is not present (i.e. a ghost), None is used in place
85
77
of the list of parents.
87
found = self.get_parent_map(revision_ids)
88
return [found.get(r, None) for r in revision_ids]
90
def get_parent_map(self, keys):
91
"""Get a mapping of keys => parents
93
A dictionary is returned with an entry for each key present in this
94
source. If this source doesn't have information about a key, it should
97
[NULL_REVISION] is used as the parent of the first user-committed
98
revision. Its parent list is empty.
100
:param keys: An iterable returning keys to check (eg revision_ids)
101
:return: A dictionary mapping each key to its parents
104
remaining = set(keys)
105
80
for parents_provider in self._parent_providers:
106
new_found = parents_provider.get_parent_map(remaining)
81
pending_revisions = [r for r in revision_ids if r not in found]
82
parent_list = parents_provider.get_parents(pending_revisions)
83
new_found = dict((k, v) for k, v in zip(pending_revisions,
84
parent_list) if v is not None)
107
85
found.update(new_found)
108
remaining.difference_update(new_found)
86
if len(found) == len(revision_ids):
114
class CachingParentsProvider(object):
115
"""A parents provider which will cache the revision => parents in a dict.
117
This is useful for providers that have an expensive lookup.
120
def __init__(self, parent_provider):
121
self._real_provider = parent_provider
122
# Theoretically we could use an LRUCache here
126
return "%s(%r)" % (self.__class__.__name__, self._real_provider)
128
@symbol_versioning.deprecated_method(symbol_versioning.one_one)
129
def get_parents(self, revision_ids):
130
"""See _StackedParentsProvider.get_parents"""
131
found = self.get_parent_map(revision_ids)
132
88
return [found.get(r, None) for r in revision_ids]
134
def get_parent_map(self, keys):
135
"""See _StackedParentsProvider.get_parent_map"""
137
# If the _real_provider doesn't have a key, we cache a value of None,
138
# which we then later use to realize we cannot provide a value for that
145
if value is not None:
146
parent_map[key] = value
151
new_parents = self._real_provider.get_parent_map(needed)
152
cache.update(new_parents)
153
parent_map.update(new_parents)
154
needed.difference_update(new_parents)
155
cache.update(dict.fromkeys(needed, None))
159
91
class Graph(object):
160
92
"""Provide incremental access to revision graphs.
423
354
An ancestor may sort after a descendant if the relationship is not
424
355
visible in the supplied list of revisions.
426
sorter = tsort.TopoSorter(self.get_parent_map(revisions))
357
sorter = tsort.TopoSorter(zip(revisions, self.get_parents(revisions)))
427
358
return sorter.iter_topo_order()
429
360
def is_ancestor(self, candidate_ancestor, candidate_descendant):
501
432
self._start = set(revisions)
502
433
self._search_revisions = None
503
434
self.seen = set(revisions)
504
self._parents_provider = parents_provider
435
self._parents_provider = parents_provider
506
437
def __repr__(self):
507
if self._search_revisions is not None:
508
search = 'searching=%r' % (list(self._search_revisions),)
510
search = 'starting=%r' % (list(self._start),)
511
return ('_BreadthFirstSearcher(%s,'
512
' seen=%r)' % (search, list(self.seen)))
438
return ('_BreadthFirstSearcher(self._search_revisions=%r,'
439
' self.seen=%r)' % (self._search_revisions, self.seen))
515
442
"""Return the next ancestors of this revision.
521
448
self._search_revisions = self._start
523
450
new_search_revisions = set()
524
parent_map = self._parents_provider.get_parent_map(
525
self._search_revisions)
526
for parents in parent_map.itervalues():
451
for parents in self._parents_provider.get_parents(
452
self._search_revisions):
527
455
new_search_revisions.update(p for p in parents if
528
456
p not in self.seen)
529
457
self._search_revisions = new_search_revisions