# Bazaar revision bundle v0.7 # # message: # Add RepositoryFile and let InventoryEntry.find_previous_heads use it. # committer: Johan Rydberg # date: Mon 2006-06-19 18:32:30.467787981 +0200 === modified file bzrlib/bzrdir.py --- bzrlib/bzrdir.py +++ bzrlib/bzrdir.py @@ -1664,10 +1664,7 @@ w = Weave(file_id) self.text_weaves[file_id] = w text_changed = False - previous_entries = ie.find_previous_heads(parent_invs, - None, - None, - entry_vf=w) + previous_entries = ie.find_previous_heads(parent_invs, None, w) for old_revision in previous_entries: # if this fails, its a ghost ? assert old_revision in self.converted_revs === modified file bzrlib/inventory.py --- bzrlib/inventory.py +++ bzrlib/inventory.py @@ -155,9 +155,7 @@ """Perform a diff between two entries of the same kind.""" def find_previous_heads(self, previous_inventories, - versioned_file_store, - transaction, - entry_vf=None): + repository, repository_file=None): """Return the revisions and entries that directly precede this. Returned as a map from revision to inventory entry. @@ -165,15 +163,12 @@ This is a map containing the file revisions in all parents for which the file exists, and its revision is not a parent of any other. If the file is new, the set will be empty. - - :param versioned_file_store: A store where ancestry data on this - file id can be queried. - :param transaction: The transaction that queries to the versioned - file store should be completed under. - :param entry_vf: The entry versioned file, if its already available. + + :param repository: A repository where a RepositoryFile object can + be retrieved from if needed. + :param repository_file: Optional RepositoryFile object, if already + available. """ - def get_ancestors(weave, entry): - return set(weave.get_ancestry(entry.revision)) # revision:ie mapping for each ie found in previous_inventories. candidates = {} # revision:ie mapping with one revision for each head. @@ -211,34 +206,13 @@ heads[ie.revision] = ie return heads - # eliminate ancestors amongst the available candidates: - # heads are those that are not an ancestor of any other candidate - # - this provides convergence at a per-file level. - for ie in candidates.values(): - # may be an ancestor of a known head: - already_present = 0 != len( - [head for head in heads - if ie.revision in head_ancestors[head]]) - if already_present: - # an ancestor of an analyzed candidate. - continue - # not an ancestor of a known head: - # load the versioned file for this file id if needed - if entry_vf is None: - entry_vf = versioned_file_store.get_weave_or_empty( - self.file_id, transaction) - ancestors = get_ancestors(entry_vf, ie) - # may knock something else out: - check_heads = list(heads.keys()) - for head in check_heads: - if head in ancestors: - # this previously discovered 'head' is not - # really a head - its an ancestor of the newly - # found head, - heads.pop(head) - head_ancestors[ie.revision] = ancestors - heads[ie.revision] = ie - return heads + if repository_file is None: + repository_file = repository.get_repository_file(self.file_id) + + suggested_heads = repository_file.find_heads( + [ie.revision for ie in candidates.values()]) + + return dict([(head, candidates[head]) for head in suggested_heads]) def get_tar_item(self, root, dp, now, tree): """Get a tarfile item and a file stream for its content.""" === modified file bzrlib/repository.py --- bzrlib/repository.py +++ bzrlib/repository.py @@ -647,6 +647,20 @@ result.check() return result + def get_repository_file(self, file_id): + """Return a RepositoryFile object associated with file id + file_id.""" + return self.text_store.get_weave_or_empty(file_id, + self.get_transaction()) + + +class RepositoryFile(object): + """Representation of a file in a repository.""" + + def find_heads(self, versions): + """Return the revisions and entries that directly preceed this.""" + raise NotImplementedError(self.find_heads) + class AllInOneRepository(Repository): """Legacy support - the repository behaviour for all-in-one branches.""" @@ -2043,10 +2057,7 @@ # which may be the sole parent if it is untouched. if ie.revision is not None: return - previous_entries = ie.find_previous_heads( - parent_invs, - self.repository.weave_store, - self.repository.get_transaction()) + previous_entries = ie.find_previous_heads(parent_invs, self.repository) # we are creating a new revision for ie in the history store # and inventory. ie.snapshot(self._new_revision_id, path, previous_entries, tree, self) === modified file bzrlib/tests/test_inv.py --- bzrlib/tests/test_inv.py +++ bzrlib/tests/test_inv.py @@ -426,9 +426,7 @@ def get_previous_heads(self, inventories): return self.file_active.find_previous_heads( - inventories, - self.branch.repository.weave_store, - self.branch.repository.get_transaction()) + inventories, self.branch.repository) def test_fileid_in_no_inventory(self): self.assertEqual({}, self.get_previous_heads([self.inv_A])) === modified file bzrlib/versionedfile.py --- bzrlib/versionedfile.py +++ bzrlib/versionedfile.py @@ -45,6 +45,8 @@ do not have a newline at the end of the file. Texts are identified by a version-id string. + + VersionedFile extends the RepositoryFile interface. """ def __init__(self, access_mode): @@ -458,6 +460,37 @@ b_marker=TextMerge.B_MARKER): return PlanWeaveMerge(plan, a_marker, b_marker).merge_lines()[0] + def find_heads(self, versions): + """See RepositoryFile.find_heads.""" + # list of revisions, one for each head. + heads = [] + # revision: ancestor list for each head + head_ancestors = {} + # eliminate ancestors amongst the available candidates: + # heads are those that are not an ancestor of any other candidate + # - this provides convergence at a per-file level. + for version_id in versions: + # may be an ancestor of a known head: + already_present = bool([head for head in heads + if version_id in head_ancestors[head]]) + if already_present: + # an ancestor of an analyzed candidate. + continue + # not an ancestor of a known head: + # load the versioned file for this file id if needed + ancestors = self.get_ancestry([version_id]) + # may knock something else out: + check_heads = list(heads) + for head in check_heads: + if head in ancestors: + # this previously discovered 'head' is not + # really a head - its an ancestor of the newly + # found head, + heads.remove(head) + head_ancestors[version_id] = ancestors + heads.append(version_id) + return heads + class PlanWeaveMerge(TextMerge): """Weave merge that takes a plan as its input. # revision id: jrydberg@gnu.org-20060619163230-f8da2a204615d5ec # sha1: 7baa0fb6e197280fc54157598b2135241329aefb # inventory sha1: 3d4636f04e779a7e15d2f5dbf7b30ca1efe5c4f1 # parent ids: # pqm@pqm.ubuntu.com-20060618160241-5b3082bb8de0192a # base id: pqm@pqm.ubuntu.com-20060618160241-5b3082bb8de0192a # properties: # branch-nick: bzr.jrydberg.unaware