Merge lp:~jelmer/brz/extract-paths2ids into lp:brz

Proposed by Jelmer Vernooij
Status: Merged
Approved by: Jelmer Vernooij
Approved revision: no longer in the source branch.
Merge reported by: The Breezy Bot
Merged at revision: not available
Proposed branch: lp:~jelmer/brz/extract-paths2ids
Merge into: lp:brz
Prerequisite: lp:~jelmer/brz/find-previous-paths
Diff against target: 1340 lines (+329/-267)
20 files modified
breezy/builtins.py (+13/-14)
breezy/bzr/inventory.py (+2/-2)
breezy/bzr/inventorytree.py (+138/-12)
breezy/bzr/workingtree.py (+4/-7)
breezy/filter_tree.py (+2/-2)
breezy/merge.py (+15/-31)
breezy/rename_map.py (+9/-1)
breezy/tests/per_intertree/test_compare.py (+3/-1)
breezy/tests/per_tree/test_inv.py (+10/-4)
breezy/tests/per_tree/test_test_trees.py (+2/-8)
breezy/tests/per_workingtree/test_inv.py (+1/-1)
breezy/tests/per_workingtree/test_nested_specifics.py (+1/-1)
breezy/tests/per_workingtree/test_paths2ids.py (+37/-0)
breezy/tests/test_merge.py (+5/-9)
breezy/tests/test_merge_core.py (+5/-5)
breezy/tests/test_shelf.py (+2/-2)
breezy/tests/test_transform.py (+5/-4)
breezy/tests/test_workingtree.py (+2/-1)
breezy/transform.py (+22/-22)
breezy/tree.py (+51/-140)
To merge this branch: bzr merge lp:~jelmer/brz/extract-paths2ids
Reviewer Review Type Date Requested Status
Martin Packman Approve
Review via email: mp+341923@code.launchpad.net

Commit message

Add a new Tree.find_related_paths_across_trees() method and pass files rather than file ids in various places.

Description of the change

Add a new Tree.find_related_paths_across_trees() method.

This finds a set of paths in a specific tree that are related to a set of specified paths in trees to look up in.

This allows further eliminating the use of file ids in public APIs:

* Tree.paths2ids can now be InventoryTree-specific.
* Merge now only takes a list of interesting files rather than a list of interesting file ids or interesting files.
* Tree.iter_entries_by_dir() now takes a list of specific_files

To post a comment you must log in.
Revision history for this message
Martin Packman (gz) wrote :

Thanks, all looks sensible.

review: Approve
Revision history for this message
The Breezy Bot (the-breezy-bot) wrote :
Revision history for this message
The Breezy Bot (the-breezy-bot) wrote :
Revision history for this message
The Breezy Bot (the-breezy-bot) wrote :

Running landing tests failed
https://ci.breezy-vcs.org/job/brz-dev/31/

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'breezy/builtins.py'
--- breezy/builtins.py 2018-03-24 00:39:56 +0000
+++ breezy/builtins.py 2018-03-24 01:23:20 +0000
@@ -53,6 +53,7 @@
53 symbol_versioning,53 symbol_versioning,
54 timestamp,54 timestamp,
55 transport,55 transport,
56 tree as _mod_tree,
56 ui,57 ui,
57 urlutils,58 urlutils,
58 views,59 views,
@@ -960,11 +961,11 @@
960961
961 self.add_cleanup(tree.lock_read().unlock)962 self.add_cleanup(tree.lock_read().unlock)
962 if file_list is not None:963 if file_list is not None:
963 file_ids = tree.paths2ids(file_list, trees=extra_trees,964 paths = tree.find_related_paths_across_trees(
964 require_versioned=True)965 file_list, extra_trees, require_versioned=True)
965 # find_ids_across_trees may include some paths that don't966 # find_ids_across_trees may include some paths that don't
966 # exist in 'tree'.967 # exist in 'tree'.
967 entries = tree.iter_entries_by_dir(specific_file_ids=file_ids)968 entries = tree.iter_entries_by_dir(specific_files=paths)
968 else:969 else:
969 entries = tree.iter_entries_by_dir()970 entries = tree.iter_entries_by_dir()
970971
@@ -4775,29 +4776,27 @@
4775 " merges. Not cherrypicking or"4776 " merges. Not cherrypicking or"
4776 " multi-merges."))4777 " multi-merges."))
4777 repository = tree.branch.repository4778 repository = tree.branch.repository
4778 interesting_ids = None4779 interesting_files = None
4779 new_conflicts = []4780 new_conflicts = []
4780 conflicts = tree.conflicts()4781 conflicts = tree.conflicts()
4781 if file_list is not None:4782 if file_list is not None:
4782 interesting_ids = set()4783 interesting_files = set()
4783 for filename in file_list:4784 for filename in file_list:
4784 file_id = tree.path2id(filename)4785 if not tree.is_versioned(filename):
4785 if file_id is None:
4786 raise errors.NotVersionedError(filename)4786 raise errors.NotVersionedError(filename)
4787 interesting_ids.add(file_id)4787 interesting_files.add(filename)
4788 if tree.kind(filename, file_id) != "directory":4788 if tree.kind(filename) != "directory":
4789 continue4789 continue
47904790
4791 # FIXME: Support nested trees4791 for path, ie in tree.iter_entries_by_dir(specific_files=[filename]):
4792 for name, ie in tree.root_inventory.iter_entries(file_id):4792 interesting_files.add(path)
4793 interesting_ids.add(ie.file_id)
4794 new_conflicts = conflicts.select_conflicts(tree, file_list)[0]4793 new_conflicts = conflicts.select_conflicts(tree, file_list)[0]
4795 else:4794 else:
4796 # Remerge only supports resolving contents conflicts4795 # Remerge only supports resolving contents conflicts
4797 allowed_conflicts = ('text conflict', 'contents conflict')4796 allowed_conflicts = ('text conflict', 'contents conflict')
4798 restore_files = [c.path for c in conflicts4797 restore_files = [c.path for c in conflicts
4799 if c.typestring in allowed_conflicts]4798 if c.typestring in allowed_conflicts]
4800 _mod_merge.transform_tree(tree, tree.basis_tree(), interesting_ids)4799 _mod_merge.transform_tree(tree, tree.basis_tree(), interesting_files)
4801 tree.set_conflicts(ConflictList(new_conflicts))4800 tree.set_conflicts(ConflictList(new_conflicts))
4802 if file_list is not None:4801 if file_list is not None:
4803 restore_files = file_list4802 restore_files = file_list
@@ -4814,7 +4813,7 @@
4814 tree.set_parent_ids(parents[:1])4813 tree.set_parent_ids(parents[:1])
4815 try:4814 try:
4816 merger = _mod_merge.Merger.from_revision_ids(tree, parents[1])4815 merger = _mod_merge.Merger.from_revision_ids(tree, parents[1])
4817 merger.interesting_ids = interesting_ids4816 merger.interesting_files = interesting_files
4818 merger.merge_type = merge_type4817 merger.merge_type = merge_type
4819 merger.show_base = show_base4818 merger.show_base = show_base
4820 merger.reprocess = reprocess4819 merger.reprocess = reprocess
48214820
=== modified file 'breezy/bzr/inventory.py'
--- breezy/bzr/inventory.py 2018-03-10 15:17:30 +0000
+++ breezy/bzr/inventory.py 2018-03-24 01:23:20 +0000
@@ -720,12 +720,12 @@
720720
721 def _preload_cache(self):721 def _preload_cache(self):
722 """Populate any caches, we are about to access all items.722 """Populate any caches, we are about to access all items.
723 723
724 The default implementation does nothing, because CommonInventory doesn't724 The default implementation does nothing, because CommonInventory doesn't
725 have a cache.725 have a cache.
726 """726 """
727 pass727 pass
728 728
729 def iter_entries_by_dir(self, from_dir=None, specific_file_ids=None,729 def iter_entries_by_dir(self, from_dir=None, specific_file_ids=None,
730 yield_parents=False):730 yield_parents=False):
731 """Iterate over the entries in a directory first order.731 """Iterate over the entries in a directory first order.
732732
=== modified file 'breezy/bzr/inventorytree.py'
--- breezy/bzr/inventorytree.py 2018-03-24 00:16:27 +0000
+++ breezy/bzr/inventorytree.py 2018-03-24 01:23:20 +0000
@@ -170,6 +170,53 @@
170 file_id = file_id[0]170 file_id = file_id[0]
171 return self.root_inventory, file_id171 return self.root_inventory, file_id
172172
173 def find_related_paths_across_trees(self, paths, trees=[],
174 require_versioned=True):
175 """Find related paths in tree corresponding to specified filenames in any
176 of `lookup_trees`.
177
178 All matches in all trees will be used, and all children of matched
179 directories will be used.
180
181 :param paths: The filenames to find related paths for (if None, returns
182 None)
183 :param trees: The trees to find file_ids within
184 :param require_versioned: if true, all specified filenames must occur in
185 at least one tree.
186 :return: a set of paths for the specified filenames and their children
187 in `tree`
188 """
189 if paths is None:
190 return None;
191 file_ids = self.paths2ids(
192 paths, trees, require_versioned=require_versioned)
193 ret = set()
194 for file_id in file_ids:
195 try:
196 ret.add(self.id2path(file_id))
197 except errors.NoSuchId:
198 pass
199 return ret
200
201 def paths2ids(self, paths, trees=[], require_versioned=True):
202 """Return all the ids that can be reached by walking from paths.
203
204 Each path is looked up in this tree and any extras provided in
205 trees, and this is repeated recursively: the children in an extra tree
206 of a directory that has been renamed under a provided path in this tree
207 are all returned, even if none exist under a provided path in this
208 tree, and vice versa.
209
210 :param paths: An iterable of paths to start converting to ids from.
211 Alternatively, if paths is None, no ids should be calculated and None
212 will be returned. This is offered to make calling the api unconditional
213 for code that *might* take a list of files.
214 :param trees: Additional trees to consider.
215 :param require_versioned: If False, do not raise NotVersionedError if
216 an element of paths is not versioned in this tree and all of trees.
217 """
218 return find_ids_across_trees(paths, [self] + list(trees), require_versioned)
219
173 def path2id(self, path):220 def path2id(self, path):
174 """Return the id for path in this tree."""221 """Return the id for path in this tree."""
175 with self.lock_read():222 with self.lock_read():
@@ -222,7 +269,7 @@
222 # are not versioned.269 # are not versioned.
223 return set((p for p in paths if self.path2id(p) is None))270 return set((p for p in paths if self.path2id(p) is None))
224271
225 def iter_entries_by_dir(self, specific_file_ids=None, yield_parents=False):272 def iter_entries_by_dir(self, specific_files=None, yield_parents=False):
226 """Walk the tree in 'by_dir' order.273 """Walk the tree in 'by_dir' order.
227274
228 This will yield each entry in the tree as a (path, entry) tuple.275 This will yield each entry in the tree as a (path, entry) tuple.
@@ -231,20 +278,20 @@
231 See Tree.iter_entries_by_dir for details.278 See Tree.iter_entries_by_dir for details.
232279
233 :param yield_parents: If True, yield the parents from the root leading280 :param yield_parents: If True, yield the parents from the root leading
234 down to specific_file_ids that have been requested. This has no281 down to specific_files that have been requested. This has no
235 impact if specific_file_ids is None.282 impact if specific_files is None.
236 """283 """
237 with self.lock_read():284 with self.lock_read():
238 if specific_file_ids is None:285 if specific_files is not None:
239 inventory_file_ids = None
240 else:
241 inventory_file_ids = []286 inventory_file_ids = []
242 for tree_file_id in specific_file_ids:287 for path in specific_files:
243 inventory, inv_file_id = self._unpack_file_id(tree_file_id)288 inventory, inv_file_id = self._path2inv_file_id(path)
244 if not inventory is self.root_inventory: # for now289 if not inventory is self.root_inventory: # for now
245 raise AssertionError("%r != %r" % (290 raise AssertionError("%r != %r" % (
246 inventory, self.root_inventory))291 inventory, self.root_inventory))
247 inventory_file_ids.append(inv_file_id)292 inventory_file_ids.append(inv_file_id)
293 else:
294 inventory_file_ids = None
248 # FIXME: Handle nested trees295 # FIXME: Handle nested trees
249 return self.root_inventory.iter_entries_by_dir(296 return self.root_inventory.iter_entries_by_dir(
250 specific_file_ids=inventory_file_ids, yield_parents=yield_parents)297 specific_file_ids=inventory_file_ids, yield_parents=yield_parents)
@@ -319,6 +366,84 @@
319 return last_revision366 return last_revision
320367
321368
369def find_ids_across_trees(filenames, trees, require_versioned=True):
370 """Find the ids corresponding to specified filenames.
371
372 All matches in all trees will be used, and all children of matched
373 directories will be used.
374
375 :param filenames: The filenames to find file_ids for (if None, returns
376 None)
377 :param trees: The trees to find file_ids within
378 :param require_versioned: if true, all specified filenames must occur in
379 at least one tree.
380 :return: a set of file ids for the specified filenames and their children.
381 """
382 if not filenames:
383 return None
384 specified_path_ids = _find_ids_across_trees(filenames, trees,
385 require_versioned)
386 return _find_children_across_trees(specified_path_ids, trees)
387
388
389def _find_ids_across_trees(filenames, trees, require_versioned):
390 """Find the ids corresponding to specified filenames.
391
392 All matches in all trees will be used, but subdirectories are not scanned.
393
394 :param filenames: The filenames to find file_ids for
395 :param trees: The trees to find file_ids within
396 :param require_versioned: if true, all specified filenames must occur in
397 at least one tree.
398 :return: a set of file ids for the specified filenames
399 """
400 not_versioned = []
401 interesting_ids = set()
402 for tree_path in filenames:
403 not_found = True
404 for tree in trees:
405 file_id = tree.path2id(tree_path)
406 if file_id is not None:
407 interesting_ids.add(file_id)
408 not_found = False
409 if not_found:
410 not_versioned.append(tree_path)
411 if len(not_versioned) > 0 and require_versioned:
412 raise errors.PathsNotVersionedError(not_versioned)
413 return interesting_ids
414
415
416def _find_children_across_trees(specified_ids, trees):
417 """Return a set including specified ids and their children.
418
419 All matches in all trees will be used.
420
421 :param trees: The trees to find file_ids within
422 :return: a set containing all specified ids and their children
423 """
424 interesting_ids = set(specified_ids)
425 pending = interesting_ids
426 # now handle children of interesting ids
427 # we loop so that we handle all children of each id in both trees
428 while len(pending) > 0:
429 new_pending = set()
430 for file_id in pending:
431 for tree in trees:
432 try:
433 path = tree.id2path(file_id)
434 except errors.NoSuchId:
435 continue
436 try:
437 for child in tree.iter_child_entries(path, file_id):
438 if child.file_id not in interesting_ids:
439 new_pending.add(child.file_id)
440 except errors.NotADirectory:
441 pass
442 interesting_ids.update(new_pending)
443 pending = new_pending
444 return interesting_ids
445
446
322class MutableInventoryTree(MutableTree, InventoryTree):447class MutableInventoryTree(MutableTree, InventoryTree):
323448
324 def apply_inventory_delta(self, changes):449 def apply_inventory_delta(self, changes):
@@ -442,10 +567,11 @@
442 return entry[3]567 return entry[3]
443 # Find a 'best fit' match if the filesystem is case-insensitive568 # Find a 'best fit' match if the filesystem is case-insensitive
444 inv_path = self.tree._fix_case_of_inventory_path(inv_path)569 inv_path = self.tree._fix_case_of_inventory_path(inv_path)
445 file_id = self.tree.path2id(inv_path)570 try:
446 if file_id is not None:571 return self.tree.iter_entries_by_dir(
447 return self.tree.iter_entries_by_dir([file_id]).next()[1]572 specific_files=[inv_path]).next()[1]
448 return None573 except StopIteration:
574 return None
449575
450 def _convert_to_directory(self, this_ie, inv_path):576 def _convert_to_directory(self, this_ie, inv_path):
451 """Convert an entry to a directory.577 """Convert an entry to a directory.
452578
=== modified file 'breezy/bzr/workingtree.py'
--- breezy/bzr/workingtree.py 2018-03-04 19:11:21 +0000
+++ breezy/bzr/workingtree.py 2018-03-24 01:23:20 +0000
@@ -652,10 +652,7 @@
652 file_ids are in a WorkingTree if they are in the working inventory652 file_ids are in a WorkingTree if they are in the working inventory
653 and the working file exists.653 and the working file exists.
654 """654 """
655 ret = set()655 return {ie.file_id for path, ie in self.iter_entries_by_dir()}
656 for path, ie in self.iter_entries_by_dir():
657 ret.add(ie.file_id)
658 return ret
659656
660 def all_versioned_paths(self):657 def all_versioned_paths(self):
661 return {path for path, ie in self.iter_entries_by_dir()}658 return {path for path, ie in self.iter_entries_by_dir()}
@@ -1699,13 +1696,13 @@
1699 blocked_parent_ids.add(ie.file_id)1696 blocked_parent_ids.add(ie.file_id)
1700 yield path, ie1697 yield path, ie
17011698
1702 def iter_entries_by_dir(self, specific_file_ids=None, yield_parents=False):1699 def iter_entries_by_dir(self, specific_files=None,
1700 yield_parents=False):
1703 """See Tree.iter_entries_by_dir()"""1701 """See Tree.iter_entries_by_dir()"""
1704 # The only trick here is that if we supports_tree_reference then we1702 # The only trick here is that if we supports_tree_reference then we
1705 # need to detect if a directory becomes a tree-reference.1703 # need to detect if a directory becomes a tree-reference.
1706 iterator = super(WorkingTree, self).iter_entries_by_dir(1704 iterator = super(WorkingTree, self).iter_entries_by_dir(
1707 specific_file_ids=specific_file_ids,1705 specific_files=specific_files, yield_parents=yield_parents)
1708 yield_parents=yield_parents)
1709 if not self.supports_tree_reference():1706 if not self.supports_tree_reference():
1710 return iterator1707 return iterator
1711 else:1708 else:
17121709
=== modified file 'breezy/filter_tree.py'
--- breezy/filter_tree.py 2018-03-23 23:32:28 +0000
+++ breezy/filter_tree.py 2018-03-24 01:23:20 +0000
@@ -58,14 +58,14 @@
58 def is_executable(self, path, file_id=None):58 def is_executable(self, path, file_id=None):
59 return self.backing_tree.is_executable(path, file_id)59 return self.backing_tree.is_executable(path, file_id)
6060
61 def iter_entries_by_dir(self, specific_file_ids=None, yield_parents=None):61 def iter_entries_by_dir(self, specific_files=None, yield_parents=None):
62 # NB: This simply returns the parent tree's entries; the length may be62 # NB: This simply returns the parent tree's entries; the length may be
63 # wrong but it can't easily be calculated without filtering the whole63 # wrong but it can't easily be calculated without filtering the whole
64 # text. Currently all callers cope with this; perhaps they should be64 # text. Currently all callers cope with this; perhaps they should be
65 # updated to a narrower interface that only provides things guaranteed65 # updated to a narrower interface that only provides things guaranteed
66 # cheaply available across all trees. -- mbp 2011070566 # cheaply available across all trees. -- mbp 20110705
67 return self.backing_tree.iter_entries_by_dir(67 return self.backing_tree.iter_entries_by_dir(
68 specific_file_ids=specific_file_ids,68 specific_files=specific_files,
69 yield_parents=yield_parents)69 yield_parents=yield_parents)
7070
71 def lock_read(self):71 def lock_read(self):
7272
=== modified file 'breezy/merge.py'
--- breezy/merge.py 2018-03-24 00:39:56 +0000
+++ breezy/merge.py 2018-03-24 01:23:20 +0000
@@ -56,12 +56,13 @@
56# TODO: Report back as changes are merged in56# TODO: Report back as changes are merged in
5757
5858
59def transform_tree(from_tree, to_tree, interesting_ids=None):59def transform_tree(from_tree, to_tree, interesting_files=None):
60 from_tree.lock_tree_write()60 from_tree.lock_tree_write()
61 operation = cleanup.OperationWithCleanups(merge_inner)61 operation = cleanup.OperationWithCleanups(merge_inner)
62 operation.add_cleanup(from_tree.unlock)62 operation.add_cleanup(from_tree.unlock)
63 operation.run_simple(from_tree.branch, to_tree, from_tree,63 operation.run_simple(from_tree.branch, to_tree, from_tree,
64 ignore_zero=True, interesting_ids=interesting_ids, this_tree=from_tree)64 ignore_zero=True, this_tree=from_tree,
65 interesting_files=interesting_files)
6566
6667
67class MergeHooks(hooks.Hooks):68class MergeHooks(hooks.Hooks):
@@ -295,7 +296,6 @@
295 self.base_tree = base_tree296 self.base_tree = base_tree
296 self.ignore_zero = False297 self.ignore_zero = False
297 self.backup_files = False298 self.backup_files = False
298 self.interesting_ids = None
299 self.interesting_files = None299 self.interesting_files = None
300 self.show_base = False300 self.show_base = False
301 self.reprocess = False301 self.reprocess = False
@@ -610,7 +610,6 @@
610 def make_merger(self):610 def make_merger(self):
611 kwargs = {'working_tree': self.this_tree, 'this_tree': self.this_tree,611 kwargs = {'working_tree': self.this_tree, 'this_tree': self.this_tree,
612 'other_tree': self.other_tree,612 'other_tree': self.other_tree,
613 'interesting_ids': self.interesting_ids,
614 'interesting_files': self.interesting_files,613 'interesting_files': self.interesting_files,
615 'this_branch': self.this_branch,614 'this_branch': self.this_branch,
616 'other_branch': self.other_branch,615 'other_branch': self.other_branch,
@@ -722,7 +721,7 @@
722 requires_file_merge_plan = False721 requires_file_merge_plan = False
723722
724 def __init__(self, working_tree, this_tree, base_tree, other_tree,723 def __init__(self, working_tree, this_tree, base_tree, other_tree,
725 interesting_ids=None, reprocess=False, show_base=False,724 reprocess=False, show_base=False,
726 change_reporter=None, interesting_files=None, do_merge=True,725 change_reporter=None, interesting_files=None, do_merge=True,
727 cherrypick=False, lca_trees=None, this_branch=None,726 cherrypick=False, lca_trees=None, this_branch=None,
728 other_branch=None):727 other_branch=None):
@@ -735,30 +734,22 @@
735 :param this_branch: The branch associated with this_tree. Defaults to734 :param this_branch: The branch associated with this_tree. Defaults to
736 this_tree.branch if not supplied.735 this_tree.branch if not supplied.
737 :param other_branch: The branch associated with other_tree, if any.736 :param other_branch: The branch associated with other_tree, if any.
738 :param interesting_ids: The file_ids of files that should be
739 participate in the merge. May not be combined with
740 interesting_files.
741 :param: reprocess If True, perform conflict-reduction processing.737 :param: reprocess If True, perform conflict-reduction processing.
742 :param show_base: If True, show the base revision in text conflicts.738 :param show_base: If True, show the base revision in text conflicts.
743 (incompatible with reprocess)739 (incompatible with reprocess)
744 :param change_reporter: An object that should report changes made740 :param change_reporter: An object that should report changes made
745 :param interesting_files: The tree-relative paths of files that should741 :param interesting_files: The tree-relative paths of files that should
746 participate in the merge. If these paths refer to directories,742 participate in the merge. If these paths refer to directories,
747 the contents of those directories will also be included. May not743 the contents of those directories will also be included. If not
748 be combined with interesting_ids. If neither interesting_files nor744 specified, all files may participate in the
749 interesting_ids is specified, all files may participate in the
750 merge.745 merge.
751 :param lca_trees: Can be set to a dictionary of {revision_id:rev_tree}746 :param lca_trees: Can be set to a dictionary of {revision_id:rev_tree}
752 if the ancestry was found to include a criss-cross merge.747 if the ancestry was found to include a criss-cross merge.
753 Otherwise should be None.748 Otherwise should be None.
754 """749 """
755 object.__init__(self)750 object.__init__(self)
756 if interesting_files is not None and interesting_ids is not None:
757 raise ValueError(
758 'specify either interesting_ids or interesting_files')
759 if this_branch is None:751 if this_branch is None:
760 this_branch = this_tree.branch752 this_branch = this_tree.branch
761 self.interesting_ids = interesting_ids
762 self.interesting_files = interesting_files753 self.interesting_files = interesting_files
763 self.working_tree = working_tree754 self.working_tree = working_tree
764 self.this_tree = this_tree755 self.this_tree = this_tree
@@ -874,14 +865,13 @@
874 iterator = self.other_tree.iter_changes(self.base_tree,865 iterator = self.other_tree.iter_changes(self.base_tree,
875 specific_files=self.interesting_files,866 specific_files=self.interesting_files,
876 extra_trees=[self.this_tree])867 extra_trees=[self.this_tree])
868 this_interesting_files = self.this_tree.find_related_paths_across_trees(
869 self.interesting_files, trees=[self.other_tree])
877 this_entries = dict((e.file_id, e) for p, e in870 this_entries = dict((e.file_id, e) for p, e in
878 self.this_tree.iter_entries_by_dir(871 self.this_tree.iter_entries_by_dir(
879 self.interesting_ids))872 specific_files=this_interesting_files))
880 for (file_id, paths, changed, versioned, parents, names, kind,873 for (file_id, paths, changed, versioned, parents, names, kind,
881 executable) in iterator:874 executable) in iterator:
882 if (self.interesting_ids is not None and
883 file_id not in self.interesting_ids):
884 continue
885 entry = this_entries.get(file_id)875 entry = this_entries.get(file_id)
886 if entry is not None:876 if entry is not None:
887 this_name = entry.name877 this_name = entry.name
@@ -919,10 +909,10 @@
919 lookup_trees = [self.this_tree, self.base_tree]909 lookup_trees = [self.this_tree, self.base_tree]
920 lookup_trees.extend(self._lca_trees)910 lookup_trees.extend(self._lca_trees)
921 # I think we should include the lca trees as well911 # I think we should include the lca trees as well
922 interesting_ids = self.other_tree.paths2ids(self.interesting_files,912 interesting_files = self.other_tree.find_related_paths_across_trees(
923 lookup_trees)913 self.interesting_files, lookup_trees)
924 else:914 else:
925 interesting_ids = self.interesting_ids915 interesting_files = None
926 result = []916 result = []
927 walker = _mod_tree.MultiWalker(self.other_tree, self._lca_trees)917 walker = _mod_tree.MultiWalker(self.other_tree, self._lca_trees)
928918
@@ -932,7 +922,7 @@
932 # Is this modified at all from any of the other trees?922 # Is this modified at all from any of the other trees?
933 if other_ie is None:923 if other_ie is None:
934 other_ie = _none_entry924 other_ie = _none_entry
935 if interesting_ids is not None and file_id not in interesting_ids:925 if interesting_files is not None and path not in interesting_files:
936 continue926 continue
937927
938 # If other_revision is found in any of the lcas, that means this928 # If other_revision is found in any of the lcas, that means this
@@ -1815,7 +1805,7 @@
1815 self.merge_type = Merge3Merger1805 self.merge_type = Merge3Merger
1816 self.show_base = False1806 self.show_base = False
1817 self.reprocess = False1807 self.reprocess = False
1818 self.interesting_ids = None1808 self.interesting_files = None
1819 self.merge_type = _MergeTypeParameterizer(MergeIntoMergeType,1809 self.merge_type = _MergeTypeParameterizer(MergeIntoMergeType,
1820 target_subdir=self._target_subdir,1810 target_subdir=self._target_subdir,
1821 source_subpath=self._source_subpath)1811 source_subpath=self._source_subpath)
@@ -1926,7 +1916,6 @@
1926def merge_inner(this_branch, other_tree, base_tree, ignore_zero=False,1916def merge_inner(this_branch, other_tree, base_tree, ignore_zero=False,
1927 backup_files=False,1917 backup_files=False,
1928 merge_type=Merge3Merger,1918 merge_type=Merge3Merger,
1929 interesting_ids=None,
1930 show_base=False,1919 show_base=False,
1931 reprocess=False,1920 reprocess=False,
1932 other_rev_id=None,1921 other_rev_id=None,
@@ -1947,13 +1936,8 @@
1947 change_reporter=change_reporter)1936 change_reporter=change_reporter)
1948 merger.backup_files = backup_files1937 merger.backup_files = backup_files
1949 merger.merge_type = merge_type1938 merger.merge_type = merge_type
1950 merger.interesting_ids = interesting_ids
1951 merger.ignore_zero = ignore_zero1939 merger.ignore_zero = ignore_zero
1952 if interesting_files:1940 merger.interesting_files = interesting_files
1953 if interesting_ids:
1954 raise ValueError('Only supply interesting_ids'
1955 ' or interesting_files')
1956 merger.interesting_files = interesting_files
1957 merger.show_base = show_base1941 merger.show_base = show_base
1958 merger.reprocess = reprocess1942 merger.reprocess = reprocess
1959 merger.other_rev_id = other_rev_id1943 merger.other_rev_id = other_rev_id
19601944
=== modified file 'breezy/rename_map.py'
--- breezy/rename_map.py 2018-03-12 01:24:43 +0000
+++ breezy/rename_map.py 2018-03-24 01:23:20 +0000
@@ -26,6 +26,7 @@
26from .sixish import (26from .sixish import (
27 BytesIO,27 BytesIO,
28 viewitems,28 viewitems,
29 viewvalues,
29 )30 )
30from .ui import ui_factory31from .ui import ui_factory
3132
@@ -237,7 +238,14 @@
237 def _make_inventory_delta(self, matches):238 def _make_inventory_delta(self, matches):
238 delta = []239 delta = []
239 file_id_matches = dict((f, p) for p, f in viewitems(matches))240 file_id_matches = dict((f, p) for p, f in viewitems(matches))
240 for old_path, entry in self.tree.iter_entries_by_dir(file_id_matches):241 file_id_query = []
242 for f in viewvalues(matches):
243 try:
244 file_id_query.append(self.tree.id2path(f))
245 except errors.NoSuchId:
246 pass
247 for old_path, entry in self.tree.iter_entries_by_dir(
248 specific_files=file_id_query):
241 new_path = file_id_matches[entry.file_id]249 new_path = file_id_matches[entry.file_id]
242 parent_path, new_name = osutils.split(new_path)250 parent_path, new_name = osutils.split(new_path)
243 parent_id = matches.get(parent_path)251 parent_id = matches.get(parent_path)
244252
=== modified file 'breezy/tests/per_intertree/test_compare.py'
--- breezy/tests/per_intertree/test_compare.py 2017-11-21 20:37:41 +0000
+++ breezy/tests/per_intertree/test_compare.py 2018-03-24 01:23:20 +0000
@@ -557,7 +557,9 @@
557557
558 @staticmethod558 @staticmethod
559 def get_path_entry(tree, file_id):559 def get_path_entry(tree, file_id):
560 iterator = tree.iter_entries_by_dir(specific_file_ids=[file_id])560 with tree.lock_read():
561 path = tree.id2path(file_id)
562 iterator = tree.iter_entries_by_dir(specific_files=[path])
561 try:563 try:
562 return next(iterator)564 return next(iterator)
563 except StopIteration:565 except StopIteration:
564566
=== modified file 'breezy/tests/per_tree/test_inv.py'
--- breezy/tests/per_tree/test_inv.py 2017-08-01 01:44:41 +0000
+++ breezy/tests/per_tree/test_inv.py 2018-03-24 01:23:20 +0000
@@ -33,8 +33,8 @@
33 )33 )
3434
3535
36def get_entry(tree, file_id):36def get_entry(tree, path):
37 return tree.iter_entries_by_dir([file_id]).next()[1]37 return tree.iter_entries_by_dir(specific_files=[path]).next()[1]
3838
3939
40class TestInventoryWithSymlinks(per_tree.TestCaseWithTree):40class TestInventoryWithSymlinks(per_tree.TestCaseWithTree):
@@ -52,7 +52,7 @@
52 raise TestSkipped(52 raise TestSkipped(
53 'symlinks not accurately represented in working trees and'53 'symlinks not accurately represented in working trees and'
54 ' preview trees')54 ' preview trees')
55 entry = get_entry(self.tree, self.tree.path2id('symlink'))55 entry = get_entry(self.tree, 'symlink')
56 self.assertEqual(entry.symlink_target, 'link-target')56 self.assertEqual(entry.symlink_target, 'link-target')
5757
58 def test_symlink_target_tree(self):58 def test_symlink_target_tree(self):
@@ -64,7 +64,7 @@
64 self.assertIs(None, self.tree.get_file_size('symlink'))64 self.assertIs(None, self.tree.get_file_size('symlink'))
6565
66 def test_symlink(self):66 def test_symlink(self):
67 entry = get_entry(self.tree, self.tree.path2id('symlink'))67 entry = get_entry(self.tree, 'symlink')
68 self.assertEqual(entry.kind, 'symlink')68 self.assertEqual(entry.kind, 'symlink')
69 self.assertEqual(None, entry.text_size)69 self.assertEqual(None, entry.text_size)
7070
@@ -76,6 +76,9 @@
76 self.build_tree(['tree/dir/', 'tree/dir/file'])76 self.build_tree(['tree/dir/', 'tree/dir/file'])
77 work_tree.add(['dir', 'dir/file'])77 work_tree.add(['dir', 'dir/file'])
78 tree = self._convert_tree(work_tree)78 tree = self._convert_tree(work_tree)
79 if not isinstance(tree, InventoryTree):
80 raise tests.TestNotApplicable(
81 "test not applicable on non-inventory tests")
79 tree.lock_read()82 tree.lock_read()
80 self.addCleanup(tree.unlock)83 self.addCleanup(tree.unlock)
81 self.assertEqual({tree.path2id('dir'), tree.path2id('dir/file')},84 self.assertEqual({tree.path2id('dir'), tree.path2id('dir/file')},
@@ -88,6 +91,9 @@
88 work_tree.commit('commit old state')91 work_tree.commit('commit old state')
89 work_tree.remove('file')92 work_tree.remove('file')
90 tree = self._convert_tree(work_tree)93 tree = self._convert_tree(work_tree)
94 if not isinstance(tree, InventoryTree):
95 raise tests.TestNotApplicable(
96 "test not applicable on non-inventory tests")
91 tree.lock_read()97 tree.lock_read()
92 self.addCleanup(tree.unlock)98 self.addCleanup(tree.unlock)
93 self.assertEqual(set([]), tree.paths2ids(['file'],99 self.assertEqual(set([]), tree.paths2ids(['file'],
94100
=== modified file 'breezy/tests/per_tree/test_test_trees.py'
--- breezy/tests/per_tree/test_test_trees.py 2018-02-26 13:36:15 +0000
+++ breezy/tests/per_tree/test_test_trees.py 2018-03-24 01:23:20 +0000
@@ -228,11 +228,8 @@
228 (u'ba\N{Euro Sign}r/ba\N{Euro Sign}z',228 (u'ba\N{Euro Sign}r/ba\N{Euro Sign}z',
229 baz_id, bar_id, revision_id),229 baz_id, bar_id, revision_id),
230 ]230 ]
231 tree.lock_read()231 with tree.lock_read():
232 try:
233 path_entries = list(tree.iter_entries_by_dir())232 path_entries = list(tree.iter_entries_by_dir())
234 finally:
235 tree.unlock()
236233
237 for expected, (path, ie) in zip(path_and_ids, path_entries):234 for expected, (path, ie) in zip(path_and_ids, path_entries):
238 self.assertEqual(expected[0], path) # Paths should match235 self.assertEqual(expected[0], path) # Paths should match
@@ -276,11 +273,8 @@
276 (u'ba\N{Euro Sign}r/qu\N{Euro Sign}x',273 (u'ba\N{Euro Sign}r/qu\N{Euro Sign}x',
277 qux_id, bar_id, revision_id_2),274 qux_id, bar_id, revision_id_2),
278 ]275 ]
279 tree.lock_read()276 with tree.lock_read():
280 try:
281 path_entries = list(tree.iter_entries_by_dir())277 path_entries = list(tree.iter_entries_by_dir())
282 finally:
283 tree.unlock()
284278
285 for (epath, efid, eparent, erev), (path, ie) in zip(path_and_ids,279 for (epath, efid, eparent, erev), (path, ie) in zip(path_and_ids,
286 path_entries):280 path_entries):
287281
=== modified file 'breezy/tests/per_workingtree/test_inv.py'
--- breezy/tests/per_workingtree/test_inv.py 2018-02-15 19:38:33 +0000
+++ breezy/tests/per_workingtree/test_inv.py 2018-03-24 01:23:20 +0000
@@ -178,6 +178,6 @@
178 # wt.current_dirstate()'s idea about what files are where.178 # wt.current_dirstate()'s idea about what files are where.
179 ie = base.inventory['subdir-id']179 ie = base.inventory['subdir-id']
180 self.assertEqual('directory', ie.kind)180 self.assertEqual('directory', ie.kind)
181 path, ie = next(base.iter_entries_by_dir(['subdir-id']))181 path, ie = next(base.iter_entries_by_dir(specific_files=['subdir']))
182 self.assertEqual('subdir', path)182 self.assertEqual('subdir', path)
183 self.assertEqual('tree-reference', ie.kind)183 self.assertEqual('tree-reference', ie.kind)
184184
=== modified file 'breezy/tests/per_workingtree/test_nested_specifics.py'
--- breezy/tests/per_workingtree/test_nested_specifics.py 2018-02-16 19:38:39 +0000
+++ breezy/tests/per_workingtree/test_nested_specifics.py 2018-03-24 01:23:20 +0000
@@ -79,5 +79,5 @@
7979
80 def test_iter_entries_by_dir_autodetects_subtree(self):80 def test_iter_entries_by_dir_autodetects_subtree(self):
81 tree = self.prepare_with_subtree()81 tree = self.prepare_with_subtree()
82 path, ie = next(tree.iter_entries_by_dir(['subtree-id']))82 path, ie = next(tree.iter_entries_by_dir(specific_files=['subtree']))
83 self.assertEqual('tree-reference', ie.kind)83 self.assertEqual('tree-reference', ie.kind)
8484
=== modified file 'breezy/tests/per_workingtree/test_paths2ids.py'
--- breezy/tests/per_workingtree/test_paths2ids.py 2018-02-03 13:39:29 +0000
+++ breezy/tests/per_workingtree/test_paths2ids.py 2018-03-24 01:23:20 +0000
@@ -22,6 +22,7 @@
22"""22"""
2323
24from breezy import errors24from breezy import errors
25from breezy.bzr.inventorytree import InventoryTree
25from breezy.tests import (26from breezy.tests import (
26 features,27 features,
27 TestNotApplicable,28 TestNotApplicable,
@@ -62,16 +63,30 @@
6263
63 def test_paths_none_result_none(self):64 def test_paths_none_result_none(self):
64 tree = self.make_branch_and_tree('tree')65 tree = self.make_branch_and_tree('tree')
66 if not isinstance(tree, InventoryTree):
67 raise TestNotApplicable(
68 "test not applicable on non-inventory tests")
69
65 tree.lock_read()70 tree.lock_read()
66 self.assertEqual(None, tree.paths2ids(None))71 self.assertEqual(None, tree.paths2ids(None))
67 tree.unlock()72 tree.unlock()
6873
69 def test_find_single_root(self):74 def test_find_single_root(self):
70 tree = self.make_branch_and_tree('tree')75 tree = self.make_branch_and_tree('tree')
76 if not isinstance(tree, InventoryTree):
77 raise TestNotApplicable(
78 "test not applicable on non-inventory tests")
79
80
71 self.assertExpectedIds([tree.path2id('')], tree, [''])81 self.assertExpectedIds([tree.path2id('')], tree, [''])
7282
73 def test_find_tree_and_clone_roots(self):83 def test_find_tree_and_clone_roots(self):
74 tree = self.make_branch_and_tree('tree')84 tree = self.make_branch_and_tree('tree')
85 if not isinstance(tree, InventoryTree):
86 raise TestNotApplicable(
87 "test not applicable on non-inventory tests")
88
89
75 clone = tree.controldir.clone('clone').open_workingtree()90 clone = tree.controldir.clone('clone').open_workingtree()
76 clone.lock_tree_write()91 clone.lock_tree_write()
77 clone_root_id = 'new-id'92 clone_root_id = 'new-id'
@@ -136,6 +151,11 @@
136 new-child because its under dir in new.151 new-child because its under dir in new.
137 """152 """
138 tree = self.make_branch_and_tree('tree')153 tree = self.make_branch_and_tree('tree')
154 if not isinstance(tree, InventoryTree):
155 raise TestNotApplicable(
156 "test not applicable on non-inventory tests")
157
158
139 self.build_tree(159 self.build_tree(
140 ['tree/dir/', 'tree/dir/child-moves', 'tree/dir/child-stays',160 ['tree/dir/', 'tree/dir/child-moves', 'tree/dir/child-stays',
141 'tree/dir/child-goes'])161 'tree/dir/child-goes'])
@@ -161,6 +181,11 @@
161181
162 def test_unversioned_one_tree(self):182 def test_unversioned_one_tree(self):
163 tree = self.make_branch_and_tree('tree')183 tree = self.make_branch_and_tree('tree')
184 if not isinstance(tree, InventoryTree):
185 raise TestNotApplicable(
186 "test not applicable on non-inventory tests")
187
188
164 self.build_tree(['tree/unversioned'])189 self.build_tree(['tree/unversioned'])
165 self.assertExpectedIds([], tree, ['unversioned'], require_versioned=False)190 self.assertExpectedIds([], tree, ['unversioned'], require_versioned=False)
166 tree.lock_read()191 tree.lock_read()
@@ -172,6 +197,10 @@
172 # should not raise an error: it must be unversioned in *all* trees to197 # should not raise an error: it must be unversioned in *all* trees to
173 # error.198 # error.
174 tree = self.make_branch_and_tree('tree')199 tree = self.make_branch_and_tree('tree')
200 if not isinstance(tree, InventoryTree):
201 raise TestNotApplicable(
202 "test not applicable on non-inventory tests")
203
175 if not tree.supports_setting_file_ids():204 if not tree.supports_setting_file_ids():
176 raise TestNotApplicable('tree does not support setting file ids')205 raise TestNotApplicable('tree does not support setting file ids')
177 tree.commit('make basis')206 tree.commit('make basis')
@@ -185,6 +214,10 @@
185 # should not raise an error: it must be unversioned in *all* trees to214 # should not raise an error: it must be unversioned in *all* trees to
186 # error.215 # error.
187 tree = self.make_branch_and_tree('tree')216 tree = self.make_branch_and_tree('tree')
217 if not isinstance(tree, InventoryTree):
218 raise TestNotApplicable(
219 "test not applicable on non-inventory tests")
220
188 tree.commit('make basis')221 tree.commit('make basis')
189 basis = tree.basis_tree()222 basis = tree.basis_tree()
190 self.assertExpectedIds([], tree, ['unversioned'], [basis],223 self.assertExpectedIds([], tree, ['unversioned'], [basis],
@@ -201,6 +234,10 @@
201 def test_unversioned_non_ascii_one_tree(self):234 def test_unversioned_non_ascii_one_tree(self):
202 self.requireFeature(features.UnicodeFilenameFeature)235 self.requireFeature(features.UnicodeFilenameFeature)
203 tree = self.make_branch_and_tree('.')236 tree = self.make_branch_and_tree('.')
237 if not isinstance(tree, InventoryTree):
238 raise TestNotApplicable(
239 "test not applicable on non-inventory tests")
240
204 self.build_tree([u"\xa7"])241 self.build_tree([u"\xa7"])
205 self.assertExpectedIds([], tree, [u"\xa7"], require_versioned=False)242 self.assertExpectedIds([], tree, [u"\xa7"], require_versioned=False)
206 self.addCleanup(tree.lock_read().unlock)243 self.addCleanup(tree.lock_read().unlock)
207244
=== modified file 'breezy/tests/test_merge.py'
--- breezy/tests/test_merge.py 2018-03-20 00:30:39 +0000
+++ breezy/tests/test_merge.py 2018-03-24 01:23:20 +0000
@@ -1265,8 +1265,7 @@
1265 builder.build_snapshot(['B-id', 'C-id'], [], revision_id='D-id')1265 builder.build_snapshot(['B-id', 'C-id'], [], revision_id='D-id')
1266 return builder1266 return builder
12671267
1268 def make_Merger(self, builder, other_revision_id,1268 def make_Merger(self, builder, other_revision_id, interesting_files=None):
1269 interesting_files=None, interesting_ids=None):
1270 """Make a Merger object from a branch builder"""1269 """Make a Merger object from a branch builder"""
1271 mem_tree = memorytree.MemoryTree.create_on_branch(builder.get_branch())1270 mem_tree = memorytree.MemoryTree.create_on_branch(builder.get_branch())
1272 mem_tree.lock_write()1271 mem_tree.lock_write()
@@ -1274,8 +1273,6 @@
1274 merger = _mod_merge.Merger.from_revision_ids(1273 merger = _mod_merge.Merger.from_revision_ids(
1275 mem_tree, other_revision_id)1274 mem_tree, other_revision_id)
1276 merger.set_interesting_files(interesting_files)1275 merger.set_interesting_files(interesting_files)
1277 # It seems there is no matching function for set_interesting_ids
1278 merger.interesting_ids = interesting_ids
1279 merger.merge_type = _mod_merge.Merge3Merger1276 merger.merge_type = _mod_merge.Merge3Merger
1280 return merger1277 return merger
12811278
@@ -1400,10 +1397,9 @@
1400class TestMergerEntriesLCA(TestMergerBase):1397class TestMergerEntriesLCA(TestMergerBase):
14011398
1402 def make_merge_obj(self, builder, other_revision_id,1399 def make_merge_obj(self, builder, other_revision_id,
1403 interesting_files=None, interesting_ids=None):1400 interesting_files=None):
1404 merger = self.make_Merger(builder, other_revision_id,1401 merger = self.make_Merger(builder, other_revision_id,
1405 interesting_files=interesting_files,1402 interesting_files=interesting_files)
1406 interesting_ids=interesting_ids)
1407 return merger.make_merger()1403 return merger.make_merger()
14081404
1409 def test_simple(self):1405 def test_simple(self):
@@ -2099,7 +2095,7 @@
2099 ((False, [False, False]), False, False)),2095 ((False, [False, False]), False, False)),
2100 ], entries)2096 ], entries)
21012097
2102 def test_interesting_ids(self):2098 def test_interesting_files(self):
2103 # Two files modified, but we should filter one of them2099 # Two files modified, but we should filter one of them
2104 builder = self.get_builder()2100 builder = self.get_builder()
2105 builder.build_snapshot(None,2101 builder.build_snapshot(None,
@@ -2114,7 +2110,7 @@
2114 ('modify', ('b-id', 'new-content\n'))], revision_id='E-id')2110 ('modify', ('b-id', 'new-content\n'))], revision_id='E-id')
2115 builder.build_snapshot(['B-id', 'C-id'], [], revision_id='D-id')2111 builder.build_snapshot(['B-id', 'C-id'], [], revision_id='D-id')
2116 merge_obj = self.make_merge_obj(builder, 'E-id',2112 merge_obj = self.make_merge_obj(builder, 'E-id',
2117 interesting_ids=['b-id'])2113 interesting_files=['b'])
2118 entries = list(merge_obj._entries_lca())2114 entries = list(merge_obj._entries_lca())
2119 root_id = 'a-root-id'2115 root_id = 'a-root-id'
2120 self.assertEqual([('b-id', True,2116 self.assertEqual([('b-id', True,
21212117
=== modified file 'breezy/tests/test_merge_core.py'
--- breezy/tests/test_merge_core.py 2018-03-09 19:52:32 +0000
+++ breezy/tests/test_merge_core.py 2018-03-24 01:23:20 +0000
@@ -77,8 +77,8 @@
77 if option is True:77 if option is True:
78 new_file(tt)78 new_file(tt)
7979
80 def merge(self, merge_type=Merge3Merger, interesting_ids=None, **kwargs):80 def merge(self, merge_type=Merge3Merger, interesting_files=None, **kwargs):
81 merger = self.make_merger(merge_type, interesting_ids, **kwargs)81 merger = self.make_merger(merge_type, interesting_files, **kwargs)
82 merger.do_merge()82 merger.do_merge()
83 return merger.cooked_conflicts83 return merger.cooked_conflicts
8484
@@ -86,7 +86,7 @@
86 merger = self.make_merger(Merge3Merger, None, this_revision_tree=True)86 merger = self.make_merger(Merge3Merger, None, this_revision_tree=True)
87 return merger.make_preview_transform()87 return merger.make_preview_transform()
8888
89 def make_merger(self, merge_type, interesting_ids,89 def make_merger(self, merge_type, interesting_files,
90 this_revision_tree=False, **kwargs):90 this_revision_tree=False, **kwargs):
91 self.base_tt.apply()91 self.base_tt.apply()
92 self.base.commit('base commit')92 self.base.commit('base commit')
@@ -110,7 +110,7 @@
110 else:110 else:
111 this_tree = self.this111 this_tree = self.this
112 merger = merge_type(this_tree, self.this, self.base, other_basis,112 merger = merge_type(this_tree, self.this, self.base, other_basis,
113 interesting_ids=interesting_ids, do_merge=False,113 interesting_files=interesting_files, do_merge=False,
114 this_branch=self.this.branch, **kwargs)114 this_branch=self.this.branch, **kwargs)
115 return merger115 return merger
116116
@@ -251,7 +251,7 @@
251 builder.change_contents("1", other="text4")251 builder.change_contents("1", other="text4")
252 builder.add_file("2", builder.tree_root, "name2", "hello1", True)252 builder.add_file("2", builder.tree_root, "name2", "hello1", True)
253 builder.change_contents("2", other="text4")253 builder.change_contents("2", other="text4")
254 builder.merge(interesting_ids=["1"])254 builder.merge(interesting_files=["name1"])
255 self.assertEqual(builder.this.get_file("name1").read(), "text4" )255 self.assertEqual(builder.this.get_file("name1").read(), "text4" )
256 self.assertEqual(builder.this.get_file("name2").read(), "hello1" )256 self.assertEqual(builder.this.get_file("name2").read(), "hello1" )
257 builder.cleanup()257 builder.cleanup()
258258
=== modified file 'breezy/tests/test_shelf.py'
--- breezy/tests/test_shelf.py 2017-12-12 01:19:18 +0000
+++ breezy/tests/test_shelf.py 2018-03-24 01:23:20 +0000
@@ -206,7 +206,7 @@
206206
207 def check_shelve_creation(self, creator, tree):207 def check_shelve_creation(self, creator, tree):
208 self.assertRaises(StopIteration,208 self.assertRaises(StopIteration,
209 next, tree.iter_entries_by_dir(['foo-id']))209 next, tree.iter_entries_by_dir(specific_files=['foo']))
210 s_trans_id = creator.shelf_transform.trans_id_file_id('foo-id')210 s_trans_id = creator.shelf_transform.trans_id_file_id('foo-id')
211 self.assertEqual('foo-id',211 self.assertEqual('foo-id',
212 creator.shelf_transform.final_file_id(s_trans_id))212 creator.shelf_transform.final_file_id(s_trans_id))
@@ -349,7 +349,7 @@
349 creator.shelve_creation('foo-id')349 creator.shelve_creation('foo-id')
350 creator.transform()350 creator.transform()
351 self.assertRaises(StopIteration,351 self.assertRaises(StopIteration,
352 next, tree.iter_entries_by_dir(['foo-id']))352 next, tree.iter_entries_by_dir(specific_files=['foo']))
353 self.assertShelvedFileEqual('', creator, 'foo-id')353 self.assertShelvedFileEqual('', creator, 'foo-id')
354 s_trans_id = creator.shelf_transform.trans_id_file_id('foo-id')354 s_trans_id = creator.shelf_transform.trans_id_file_id('foo-id')
355 self.assertEqual('foo-id',355 self.assertEqual('foo-id',
356356
=== modified file 'breezy/tests/test_transform.py'
--- breezy/tests/test_transform.py 2018-03-24 00:39:56 +0000
+++ breezy/tests/test_transform.py 2018-03-24 01:23:20 +0000
@@ -2937,13 +2937,14 @@
2937 self.assertFalse(preview_tree.is_versioned('old_name/child'))2937 self.assertFalse(preview_tree.is_versioned('old_name/child'))
2938 self.assertEqual('child-id', preview_tree.path2id('new_name/child'))2938 self.assertEqual('child-id', preview_tree.path2id('new_name/child'))
29392939
2940 def assertMatchingIterEntries(self, tt, specific_file_ids=None):2940 def assertMatchingIterEntries(self, tt, specific_files=None):
2941 preview_tree = tt.get_preview_tree()2941 preview_tree = tt.get_preview_tree()
2942 preview_result = list(preview_tree.iter_entries_by_dir(2942 preview_result = list(preview_tree.iter_entries_by_dir(
2943 specific_file_ids))2943 specific_files=specific_files))
2944 tree = tt._tree2944 tree = tt._tree
2945 tt.apply()2945 tt.apply()
2946 actual_result = list(tree.iter_entries_by_dir(specific_file_ids))2946 actual_result = list(tree.iter_entries_by_dir(
2947 specific_files=specific_files))
2947 self.assertEqual(actual_result, preview_result)2948 self.assertEqual(actual_result, preview_result)
29482949
2949 def test_iter_entries_by_dir_new(self):2950 def test_iter_entries_by_dir_new(self):
@@ -2983,7 +2984,7 @@
2983 self.build_tree(['tree/parent/', 'tree/parent/child'])2984 self.build_tree(['tree/parent/', 'tree/parent/child'])
2984 tree.add(['parent', 'parent/child'], ['parent-id', 'child-id'])2985 tree.add(['parent', 'parent/child'], ['parent-id', 'child-id'])
2985 tt = TreeTransform(tree)2986 tt = TreeTransform(tree)
2986 self.assertMatchingIterEntries(tt, ['tree-root-id', 'child-id'])2987 self.assertMatchingIterEntries(tt, ['', 'parent/child'])
29872988
2988 def test_symlink_content_summary(self):2989 def test_symlink_content_summary(self):
2989 self.requireFeature(SymlinkFeature)2990 self.requireFeature(SymlinkFeature)
29902991
=== modified file 'breezy/tests/test_workingtree.py'
--- breezy/tests/test_workingtree.py 2018-02-11 17:07:38 +0000
+++ breezy/tests/test_workingtree.py 2018-03-24 01:23:20 +0000
@@ -257,7 +257,8 @@
257 subtree = self.make_branch_and_tree('tree/a/b')257 subtree = self.make_branch_and_tree('tree/a/b')
258 self.assertEqual([('tree-reference', 'b-id')],258 self.assertEqual([('tree-reference', 'b-id')],
259 [(ie.kind, ie.file_id)259 [(ie.kind, ie.file_id)
260 for path, ie in tree.iter_entries_by_dir(['b-id'])])260 for path, ie in tree.iter_entries_by_dir(
261 specific_files=['a/b'])])
261262
262 def test_direct_subtree(self):263 def test_direct_subtree(self):
263 tree = self.make_simple_tree()264 tree = self.make_simple_tree()
264265
=== modified file 'breezy/transform.py'
--- breezy/transform.py 2018-03-24 00:39:56 +0000
+++ breezy/transform.py 2018-03-24 01:23:20 +0000
@@ -894,7 +894,7 @@
894 to_trans_ids[to_file_id] = trans_id894 to_trans_ids[to_file_id] = trans_id
895 return from_trans_ids, to_trans_ids895 return from_trans_ids, to_trans_ids
896896
897 def _from_file_data(self, from_trans_id, from_versioned, file_id):897 def _from_file_data(self, from_trans_id, from_versioned, from_path):
898 """Get data about a file in the from (tree) state898 """Get data about a file in the from (tree) state
899899
900 Return a (name, parent, kind, executable) tuple900 Return a (name, parent, kind, executable) tuple
@@ -902,7 +902,8 @@
902 from_path = self._tree_id_paths.get(from_trans_id)902 from_path = self._tree_id_paths.get(from_trans_id)
903 if from_versioned:903 if from_versioned:
904 # get data from working tree if versioned904 # get data from working tree if versioned
905 from_entry = self._tree.iter_entries_by_dir([file_id]).next()[1]905 from_entry = self._tree.iter_entries_by_dir(
906 specific_files=[from_path]).next()[1]
906 from_name = from_entry.name907 from_name = from_entry.name
907 from_parent = from_entry.parent_id908 from_parent = from_entry.parent_id
908 else:909 else:
@@ -971,12 +972,6 @@
971 else:972 else:
972 to_versioned = True973 to_versioned = True
973974
974 from_name, from_parent, from_kind, from_executable = \
975 self._from_file_data(from_trans_id, from_versioned, file_id)
976
977 to_name, to_parent, to_kind, to_executable = \
978 self._to_file_data(to_trans_id, from_trans_id, from_executable)
979
980 if not from_versioned:975 if not from_versioned:
981 from_path = None976 from_path = None
982 else:977 else:
@@ -985,6 +980,13 @@
985 to_path = None980 to_path = None
986 else:981 else:
987 to_path = final_paths.get_path(to_trans_id)982 to_path = final_paths.get_path(to_trans_id)
983
984 from_name, from_parent, from_kind, from_executable = \
985 self._from_file_data(from_trans_id, from_versioned, from_path)
986
987 to_name, to_parent, to_kind, to_executable = \
988 self._to_file_data(to_trans_id, from_trans_id, from_executable)
989
988 if from_kind != to_kind:990 if from_kind != to_kind:
989 modified = True991 modified = True
990 elif to_kind in ('file', 'symlink') and (992 elif to_kind in ('file', 'symlink') and (
@@ -1763,9 +1765,6 @@
1763 inventory_delta.append((path, None, file_id, None))1765 inventory_delta.append((path, None, file_id, None))
1764 new_path_file_ids = dict((t, self.final_file_id(t)) for p, t in1766 new_path_file_ids = dict((t, self.final_file_id(t)) for p, t in
1765 new_paths)1767 new_paths)
1766 entries = self._tree.iter_entries_by_dir(
1767 viewvalues(new_path_file_ids))
1768 old_paths = dict((e.file_id, p) for p, e in entries)
1769 final_kinds = {}1768 final_kinds = {}
1770 for num, (path, trans_id) in enumerate(new_paths):1769 for num, (path, trans_id) in enumerate(new_paths):
1771 if (num % 10) == 0:1770 if (num % 10) == 0:
@@ -1793,7 +1792,10 @@
1793 new_entry = inventory.make_entry(kind,1792 new_entry = inventory.make_entry(kind,
1794 self.final_name(trans_id),1793 self.final_name(trans_id),
1795 parent_file_id, file_id)1794 parent_file_id, file_id)
1796 old_path = old_paths.get(new_entry.file_id)1795 try:
1796 old_path = self._tree.id2path(new_entry.file_id)
1797 except errors.NoSuchId:
1798 old_path = None
1797 new_executability = self._new_executability.get(trans_id)1799 new_executability = self._new_executability.get(trans_id)
1798 if new_executability is not None:1800 if new_executability is not None:
1799 new_entry.executable = new_executability1801 new_entry.executable = new_executability
@@ -1944,10 +1946,8 @@
1944 path = self._tree_id_paths[parent_id]1946 path = self._tree_id_paths[parent_id]
1945 except KeyError:1947 except KeyError:
1946 return1948 return
1947 file_id = self.tree_file_id(parent_id)1949 entry = self._tree.iter_entries_by_dir(
1948 if file_id is None:1950 specific_files=[path]).next()[1]
1949 return
1950 entry = self._tree.iter_entries_by_dir([file_id]).next()[1]
1951 children = getattr(entry, 'children', {})1951 children = getattr(entry, 'children', {})
1952 for child in children:1952 for child in children:
1953 childpath = joinpath(path, child)1953 childpath = joinpath(path, child)
@@ -2127,14 +2127,14 @@
2127 if self._transform.final_file_id(trans_id) is None:2127 if self._transform.final_file_id(trans_id) is None:
2128 yield self._final_paths._determine_path(trans_id)2128 yield self._final_paths._determine_path(trans_id)
21292129
2130 def _make_inv_entries(self, ordered_entries, specific_file_ids=None,2130 def _make_inv_entries(self, ordered_entries, specific_files=None,
2131 yield_parents=False):2131 yield_parents=False):
2132 for trans_id, parent_file_id in ordered_entries:2132 for trans_id, parent_file_id in ordered_entries:
2133 file_id = self._transform.final_file_id(trans_id)2133 file_id = self._transform.final_file_id(trans_id)
2134 if file_id is None:2134 if file_id is None:
2135 continue2135 continue
2136 if (specific_file_ids is not None2136 if (specific_files is not None and
2137 and file_id not in specific_file_ids):2137 unicode(self._final_paths.get_path(trans_id)) not in specific_files):
2138 continue2138 continue
2139 kind = self._transform.final_kind(trans_id)2139 kind = self._transform.final_kind(trans_id)
2140 if kind is None:2140 if kind is None:
@@ -2172,7 +2172,7 @@
2172 for entry, trans_id in self._make_inv_entries(todo):2172 for entry, trans_id in self._make_inv_entries(todo):
2173 yield entry2173 yield entry
21742174
2175 def iter_entries_by_dir(self, specific_file_ids=None, yield_parents=False):2175 def iter_entries_by_dir(self, specific_files=None, yield_parents=False):
2176 # This may not be a maximally efficient implementation, but it is2176 # This may not be a maximally efficient implementation, but it is
2177 # reasonably straightforward. An implementation that grafts the2177 # reasonably straightforward. An implementation that grafts the
2178 # TreeTransform changes onto the tree's iter_entries_by_dir results2178 # TreeTransform changes onto the tree's iter_entries_by_dir results
@@ -2180,7 +2180,7 @@
2180 # position.2180 # position.
2181 ordered_ids = self._list_files_by_dir()2181 ordered_ids = self._list_files_by_dir()
2182 for entry, trans_id in self._make_inv_entries(ordered_ids,2182 for entry, trans_id in self._make_inv_entries(ordered_ids,
2183 specific_file_ids, yield_parents=yield_parents):2183 specific_files, yield_parents=yield_parents):
2184 yield unicode(self._final_paths.get_path(trans_id)), entry2184 yield unicode(self._final_paths.get_path(trans_id)), entry
21852185
2186 def _iter_entries_for_dir(self, dir_path):2186 def _iter_entries_for_dir(self, dir_path):
@@ -3081,7 +3081,7 @@
3081 if file_id is None:3081 if file_id is None:
3082 file_id = tt.inactive_file_id(trans_id)3082 file_id = tt.inactive_file_id(trans_id)
3083 _, entry = next(path_tree.iter_entries_by_dir(3083 _, entry = next(path_tree.iter_entries_by_dir(
3084 [file_id]))3084 specific_files=[path_tree.id2path(file_id)]))
3085 # special-case the other tree root (move its3085 # special-case the other tree root (move its
3086 # children to current root)3086 # children to current root)
3087 if entry.parent_id is None:3087 if entry.parent_id is None:
30883088
=== modified file 'breezy/tree.py'
--- breezy/tree.py 2018-03-24 00:39:56 +0000
+++ breezy/tree.py 2018-03-24 01:23:20 +0000
@@ -213,7 +213,7 @@
213 """213 """
214 raise NotImplementedError(self.id2path)214 raise NotImplementedError(self.id2path)
215215
216 def iter_entries_by_dir(self, specific_file_ids=None, yield_parents=False):216 def iter_entries_by_dir(self, specific_files=None, yield_parents=False):
217 """Walk the tree in 'by_dir' order.217 """Walk the tree in 'by_dir' order.
218218
219 This will yield each entry in the tree as a (path, entry) tuple.219 This will yield each entry in the tree as a (path, entry) tuple.
@@ -239,8 +239,8 @@
239 a, f, a/b, a/d, a/b/c, a/d/e, f/g239 a, f, a/b, a/d, a/b/c, a/d/e, f/g
240240
241 :param yield_parents: If True, yield the parents from the root leading241 :param yield_parents: If True, yield the parents from the root leading
242 down to specific_file_ids that have been requested. This has no242 down to specific_files that have been requested. This has no
243 impact if specific_file_ids is None.243 impact if specific_files is None.
244 """244 """
245 raise NotImplementedError(self.iter_entries_by_dir)245 raise NotImplementedError(self.iter_entries_by_dir)
246246
@@ -501,24 +501,23 @@
501 """501 """
502 return self.path2id(path) is not None502 return self.path2id(path) is not None
503503
504 def paths2ids(self, paths, trees=[], require_versioned=True):504 def find_related_paths_across_trees(self, paths, trees=[],
505 """Return all the ids that can be reached by walking from paths.505 require_versioned=True):
506506 """Find related paths in tree corresponding to specified filenames in any
507 Each path is looked up in this tree and any extras provided in507 of `lookup_trees`.
508 trees, and this is repeated recursively: the children in an extra tree508
509 of a directory that has been renamed under a provided path in this tree509 All matches in all trees will be used, and all children of matched
510 are all returned, even if none exist under a provided path in this510 directories will be used.
511 tree, and vice versa.511
512512 :param paths: The filenames to find related paths for (if None, returns
513 :param paths: An iterable of paths to start converting to ids from.513 None)
514 Alternatively, if paths is None, no ids should be calculated and None514 :param trees: The trees to find file_ids within
515 will be returned. This is offered to make calling the api unconditional515 :param require_versioned: if true, all specified filenames must occur in
516 for code that *might* take a list of files.516 at least one tree.
517 :param trees: Additional trees to consider.517 :return: a set of paths for the specified filenames and their children
518 :param require_versioned: If False, do not raise NotVersionedError if518 in `tree`
519 an element of paths is not versioned in this tree and all of trees.
520 """519 """
521 return find_ids_across_trees(paths, [self] + list(trees), require_versioned)520 raise NotImplementedError(self.find_related_paths_across_trees)
522521
523 def lock_read(self):522 def lock_read(self):
524 """Lock this tree for multiple read only operations.523 """Lock this tree for multiple read only operations.
@@ -657,84 +656,6 @@
657 return searcher656 return searcher
658657
659658
660def find_ids_across_trees(filenames, trees, require_versioned=True):
661 """Find the ids corresponding to specified filenames.
662
663 All matches in all trees will be used, and all children of matched
664 directories will be used.
665
666 :param filenames: The filenames to find file_ids for (if None, returns
667 None)
668 :param trees: The trees to find file_ids within
669 :param require_versioned: if true, all specified filenames must occur in
670 at least one tree.
671 :return: a set of file ids for the specified filenames and their children.
672 """
673 if not filenames:
674 return None
675 specified_path_ids = _find_ids_across_trees(filenames, trees,
676 require_versioned)
677 return _find_children_across_trees(specified_path_ids, trees)
678
679
680def _find_ids_across_trees(filenames, trees, require_versioned):
681 """Find the ids corresponding to specified filenames.
682
683 All matches in all trees will be used, but subdirectories are not scanned.
684
685 :param filenames: The filenames to find file_ids for
686 :param trees: The trees to find file_ids within
687 :param require_versioned: if true, all specified filenames must occur in
688 at least one tree.
689 :return: a set of file ids for the specified filenames
690 """
691 not_versioned = []
692 interesting_ids = set()
693 for tree_path in filenames:
694 not_found = True
695 for tree in trees:
696 file_id = tree.path2id(tree_path)
697 if file_id is not None:
698 interesting_ids.add(file_id)
699 not_found = False
700 if not_found:
701 not_versioned.append(tree_path)
702 if len(not_versioned) > 0 and require_versioned:
703 raise errors.PathsNotVersionedError(not_versioned)
704 return interesting_ids
705
706
707def _find_children_across_trees(specified_ids, trees):
708 """Return a set including specified ids and their children.
709
710 All matches in all trees will be used.
711
712 :param trees: The trees to find file_ids within
713 :return: a set containing all specified ids and their children
714 """
715 interesting_ids = set(specified_ids)
716 pending = interesting_ids
717 # now handle children of interesting ids
718 # we loop so that we handle all children of each id in both trees
719 while len(pending) > 0:
720 new_pending = set()
721 for tree in trees:
722 for file_id in pending:
723 try:
724 path = tree.id2path(file_id)
725 except errors.NoSuchId:
726 continue
727 try:
728 for child in tree.iter_child_entries(path, file_id):
729 if child.file_id not in interesting_ids:
730 new_pending.add(child.file_id)
731 except errors.NotADirectory:
732 pass
733 interesting_ids.update(new_pending)
734 pending = new_pending
735 return interesting_ids
736
737
738class InterTree(InterObject):659class InterTree(InterObject):
739 """This class represents operations taking place between two Trees.660 """This class represents operations taking place between two Trees.
740661
@@ -854,18 +775,6 @@
854 if extra_trees is not None:775 if extra_trees is not None:
855 trees = trees + tuple(extra_trees)776 trees = trees + tuple(extra_trees)
856 with self.lock_read():777 with self.lock_read():
857 # target is usually the newer tree:
858 specific_file_ids = self.target.paths2ids(specific_files, trees,
859 require_versioned=require_versioned)
860 if specific_files and not specific_file_ids:
861 # All files are unversioned, so just return an empty delta
862 # _compare_trees would think we want a complete delta
863 result = delta.TreeDelta()
864 fake_entry = inventory.InventoryFile('unused', 'unused', 'unused')
865 result.unversioned = [(path, None,
866 self.target._comparison_data(fake_entry, path)[0]) for path in
867 specific_files]
868 return result
869 return delta._compare_trees(self.source, self.target, want_unchanged,778 return delta._compare_trees(self.source, self.target, want_unchanged,
870 specific_files, include_root, extra_trees=extra_trees,779 specific_files, include_root, extra_trees=extra_trees,
871 require_versioned=require_versioned,780 require_versioned=require_versioned,
@@ -907,17 +816,23 @@
907 output. An unversioned file is defined as one with (False, False)816 output. An unversioned file is defined as one with (False, False)
908 for the versioned pair.817 for the versioned pair.
909 """818 """
910 lookup_trees = [self.source]819 if not extra_trees:
911 if extra_trees:820 extra_trees = []
912 lookup_trees.extend(extra_trees)821 else:
822 extra_trees = list(extra_trees)
913 # The ids of items we need to examine to insure delta consistency.823 # The ids of items we need to examine to insure delta consistency.
914 precise_file_ids = set()824 precise_file_ids = set()
915 changed_file_ids = []825 changed_file_ids = []
916 if specific_files == []:826 if specific_files == []:
917 specific_file_ids = []827 target_specific_files = []
828 source_specific_files = []
918 else:829 else:
919 specific_file_ids = self.target.paths2ids(specific_files,830 target_specific_files = self.target.find_related_paths_across_trees(
920 lookup_trees, require_versioned=require_versioned)831 specific_files, [self.source] + extra_trees,
832 require_versioned=require_versioned)
833 source_specific_files = self.source.find_related_paths_across_trees(
834 specific_files, [self.target] + extra_trees,
835 require_versioned=require_versioned)
921 if specific_files is not None:836 if specific_files is not None:
922 # reparented or added entries must have their parents included837 # reparented or added entries must have their parents included
923 # so that valid deltas can be created. The seen_parents set838 # so that valid deltas can be created. The seen_parents set
@@ -937,10 +852,10 @@
937 all_unversioned = collections.deque()852 all_unversioned = collections.deque()
938 to_paths = {}853 to_paths = {}
939 from_entries_by_dir = list(self.source.iter_entries_by_dir(854 from_entries_by_dir = list(self.source.iter_entries_by_dir(
940 specific_file_ids=specific_file_ids))855 specific_files=source_specific_files))
941 from_data = dict((e.file_id, (p, e)) for p, e in from_entries_by_dir)856 from_data = dict((e.file_id, (p, e)) for p, e in from_entries_by_dir)
942 to_entries_by_dir = list(self.target.iter_entries_by_dir(857 to_entries_by_dir = list(self.target.iter_entries_by_dir(
943 specific_file_ids=specific_file_ids))858 specific_files=target_specific_files))
944 num_entries = len(from_entries_by_dir) + len(to_entries_by_dir)859 num_entries = len(from_entries_by_dir) + len(to_entries_by_dir)
945 entry_count = 0860 entry_count = 0
946 # the unversioned path lookup only occurs on real trees - where there861 # the unversioned path lookup only occurs on real trees - where there
@@ -969,7 +884,7 @@
969 if pb is not None:884 if pb is not None:
970 pb.update('comparing files', entry_count, num_entries)885 pb.update('comparing files', entry_count, num_entries)
971 if changes or include_unchanged:886 if changes or include_unchanged:
972 if specific_file_ids is not None:887 if specific_files is not None:
973 new_parent_id = result[4][1]888 new_parent_id = result[4][1]
974 precise_file_ids.add(new_parent_id)889 precise_file_ids.add(new_parent_id)
975 changed_file_ids.append(result[0])890 changed_file_ids.append(result[0])
@@ -1017,12 +932,12 @@
1017 yield(file_id, (path, to_path), changed_content, versioned, parent,932 yield(file_id, (path, to_path), changed_content, versioned, parent,
1018 name, kind, executable)933 name, kind, executable)
1019 changed_file_ids = set(changed_file_ids)934 changed_file_ids = set(changed_file_ids)
1020 if specific_file_ids is not None:935 if specific_files is not None:
1021 for result in self._handle_precise_ids(precise_file_ids,936 for result in self._handle_precise_ids(precise_file_ids,
1022 changed_file_ids):937 changed_file_ids):
1023 yield result938 yield result
1024939
1025 def _get_entry(self, tree, file_id):940 def _get_entry(self, tree, path):
1026 """Get an inventory entry from a tree, with missing entries as None.941 """Get an inventory entry from a tree, with missing entries as None.
1027942
1028 If the tree raises NotImplementedError on accessing .inventory, then943 If the tree raises NotImplementedError on accessing .inventory, then
@@ -1032,20 +947,12 @@
1032 :param tree: The tree to lookup the entry in.947 :param tree: The tree to lookup the entry in.
1033 :param file_id: The file_id to lookup.948 :param file_id: The file_id to lookup.
1034 """949 """
950 # No inventory available.
1035 try:951 try:
1036 inventory = tree.root_inventory952 iterator = tree.iter_entries_by_dir(specific_files=[path])
1037 except (AttributeError, NotImplementedError):953 return iterator.next()[1]
1038 # No inventory available.954 except StopIteration:
1039 try:955 return None
1040 iterator = tree.iter_entries_by_dir(specific_file_ids=[file_id])
1041 return iterator.next()[1]
1042 except StopIteration:
1043 return None
1044 else:
1045 try:
1046 return inventory[file_id]
1047 except errors.NoSuchId:
1048 return None
1049956
1050 def _handle_precise_ids(self, precise_file_ids, changed_file_ids,957 def _handle_precise_ids(self, precise_file_ids, changed_file_ids,
1051 discarded_changes=None):958 discarded_changes=None):
@@ -1093,22 +1000,26 @@
1093 # Examine file_id1000 # Examine file_id
1094 if discarded_changes:1001 if discarded_changes:
1095 result = discarded_changes.get(file_id)1002 result = discarded_changes.get(file_id)
1096 old_entry = None1003 source_entry = None
1097 else:1004 else:
1098 result = None1005 result = None
1099 if result is None:1006 if result is None:
1100 old_entry = self._get_entry(self.source, file_id)
1101 new_entry = self._get_entry(self.target, file_id)
1102 try:1007 try:
1103 source_path = self.source.id2path(file_id)1008 source_path = self.source.id2path(file_id)
1104 except errors.NoSuchId:1009 except errors.NoSuchId:
1105 source_path = None1010 source_path = None
1011 source_entry = None
1012 else:
1013 source_entry = self._get_entry(self.source, source_path)
1106 try:1014 try:
1107 target_path = self.target.id2path(file_id)1015 target_path = self.target.id2path(file_id)
1108 except errors.NoSuchId:1016 except errors.NoSuchId:
1109 target_path = None1017 target_path = None
1018 target_entry = None
1019 else:
1020 target_entry = self._get_entry(self.target, target_path)
1110 result, changes = self._changes_from_entries(1021 result, changes = self._changes_from_entries(
1111 old_entry, new_entry, source_path, target_path)1022 source_entry, target_entry, source_path, target_path)
1112 else:1023 else:
1113 changes = True1024 changes = True
1114 # Get this parents parent to examine.1025 # Get this parents parent to examine.
@@ -1119,9 +1030,9 @@
1119 result[6][1] != 'directory'):1030 result[6][1] != 'directory'):
1120 # This stopped being a directory, the old children have1031 # This stopped being a directory, the old children have
1121 # to be included.1032 # to be included.
1122 if old_entry is None:1033 if source_entry is None:
1123 # Reusing a discarded change.1034 # Reusing a discarded change.
1124 old_entry = self._get_entry(self.source, file_id)1035 source_entry = self._get_entry(self.source, result[1][0])
1125 precise_file_ids.update(1036 precise_file_ids.update(
1126 child.file_id1037 child.file_id
1127 for child in self.source.iter_child_entries(result[1][0]))1038 for child in self.source.iter_child_entries(result[1][0]))

Subscribers

People subscribed via source and target branches