Merge lp:~jelmer/brz/extract-paths2ids into lp:brz
- extract-paths2ids
- Merge into trunk
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 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Martin Packman | Approve | ||
Review via email: mp+341923@code.launchpad.net |
Commit message
Add a new Tree.find_
Description of the change
Add a new Tree.find_
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-
* Merge now only takes a list of interesting files rather than a list of interesting file ids or interesting files.
* Tree.iter_
The Breezy Bot (the-breezy-bot) wrote : | # |
Merging failed
https:/
The Breezy Bot (the-breezy-bot) wrote : | # |
Merging failed
https:/
The Breezy Bot (the-breezy-bot) wrote : | # |
Running landing tests failed
https:/
Preview Diff
1 | === modified file 'breezy/builtins.py' |
2 | --- breezy/builtins.py 2018-03-24 00:39:56 +0000 |
3 | +++ breezy/builtins.py 2018-03-24 01:23:20 +0000 |
4 | @@ -53,6 +53,7 @@ |
5 | symbol_versioning, |
6 | timestamp, |
7 | transport, |
8 | + tree as _mod_tree, |
9 | ui, |
10 | urlutils, |
11 | views, |
12 | @@ -960,11 +961,11 @@ |
13 | |
14 | self.add_cleanup(tree.lock_read().unlock) |
15 | if file_list is not None: |
16 | - file_ids = tree.paths2ids(file_list, trees=extra_trees, |
17 | - require_versioned=True) |
18 | + paths = tree.find_related_paths_across_trees( |
19 | + file_list, extra_trees, require_versioned=True) |
20 | # find_ids_across_trees may include some paths that don't |
21 | # exist in 'tree'. |
22 | - entries = tree.iter_entries_by_dir(specific_file_ids=file_ids) |
23 | + entries = tree.iter_entries_by_dir(specific_files=paths) |
24 | else: |
25 | entries = tree.iter_entries_by_dir() |
26 | |
27 | @@ -4775,29 +4776,27 @@ |
28 | " merges. Not cherrypicking or" |
29 | " multi-merges.")) |
30 | repository = tree.branch.repository |
31 | - interesting_ids = None |
32 | + interesting_files = None |
33 | new_conflicts = [] |
34 | conflicts = tree.conflicts() |
35 | if file_list is not None: |
36 | - interesting_ids = set() |
37 | + interesting_files = set() |
38 | for filename in file_list: |
39 | - file_id = tree.path2id(filename) |
40 | - if file_id is None: |
41 | + if not tree.is_versioned(filename): |
42 | raise errors.NotVersionedError(filename) |
43 | - interesting_ids.add(file_id) |
44 | - if tree.kind(filename, file_id) != "directory": |
45 | + interesting_files.add(filename) |
46 | + if tree.kind(filename) != "directory": |
47 | continue |
48 | |
49 | - # FIXME: Support nested trees |
50 | - for name, ie in tree.root_inventory.iter_entries(file_id): |
51 | - interesting_ids.add(ie.file_id) |
52 | + for path, ie in tree.iter_entries_by_dir(specific_files=[filename]): |
53 | + interesting_files.add(path) |
54 | new_conflicts = conflicts.select_conflicts(tree, file_list)[0] |
55 | else: |
56 | # Remerge only supports resolving contents conflicts |
57 | allowed_conflicts = ('text conflict', 'contents conflict') |
58 | restore_files = [c.path for c in conflicts |
59 | if c.typestring in allowed_conflicts] |
60 | - _mod_merge.transform_tree(tree, tree.basis_tree(), interesting_ids) |
61 | + _mod_merge.transform_tree(tree, tree.basis_tree(), interesting_files) |
62 | tree.set_conflicts(ConflictList(new_conflicts)) |
63 | if file_list is not None: |
64 | restore_files = file_list |
65 | @@ -4814,7 +4813,7 @@ |
66 | tree.set_parent_ids(parents[:1]) |
67 | try: |
68 | merger = _mod_merge.Merger.from_revision_ids(tree, parents[1]) |
69 | - merger.interesting_ids = interesting_ids |
70 | + merger.interesting_files = interesting_files |
71 | merger.merge_type = merge_type |
72 | merger.show_base = show_base |
73 | merger.reprocess = reprocess |
74 | |
75 | === modified file 'breezy/bzr/inventory.py' |
76 | --- breezy/bzr/inventory.py 2018-03-10 15:17:30 +0000 |
77 | +++ breezy/bzr/inventory.py 2018-03-24 01:23:20 +0000 |
78 | @@ -720,12 +720,12 @@ |
79 | |
80 | def _preload_cache(self): |
81 | """Populate any caches, we are about to access all items. |
82 | - |
83 | + |
84 | The default implementation does nothing, because CommonInventory doesn't |
85 | have a cache. |
86 | """ |
87 | pass |
88 | - |
89 | + |
90 | def iter_entries_by_dir(self, from_dir=None, specific_file_ids=None, |
91 | yield_parents=False): |
92 | """Iterate over the entries in a directory first order. |
93 | |
94 | === modified file 'breezy/bzr/inventorytree.py' |
95 | --- breezy/bzr/inventorytree.py 2018-03-24 00:16:27 +0000 |
96 | +++ breezy/bzr/inventorytree.py 2018-03-24 01:23:20 +0000 |
97 | @@ -170,6 +170,53 @@ |
98 | file_id = file_id[0] |
99 | return self.root_inventory, file_id |
100 | |
101 | + def find_related_paths_across_trees(self, paths, trees=[], |
102 | + require_versioned=True): |
103 | + """Find related paths in tree corresponding to specified filenames in any |
104 | + of `lookup_trees`. |
105 | + |
106 | + All matches in all trees will be used, and all children of matched |
107 | + directories will be used. |
108 | + |
109 | + :param paths: The filenames to find related paths for (if None, returns |
110 | + None) |
111 | + :param trees: The trees to find file_ids within |
112 | + :param require_versioned: if true, all specified filenames must occur in |
113 | + at least one tree. |
114 | + :return: a set of paths for the specified filenames and their children |
115 | + in `tree` |
116 | + """ |
117 | + if paths is None: |
118 | + return None; |
119 | + file_ids = self.paths2ids( |
120 | + paths, trees, require_versioned=require_versioned) |
121 | + ret = set() |
122 | + for file_id in file_ids: |
123 | + try: |
124 | + ret.add(self.id2path(file_id)) |
125 | + except errors.NoSuchId: |
126 | + pass |
127 | + return ret |
128 | + |
129 | + def paths2ids(self, paths, trees=[], require_versioned=True): |
130 | + """Return all the ids that can be reached by walking from paths. |
131 | + |
132 | + Each path is looked up in this tree and any extras provided in |
133 | + trees, and this is repeated recursively: the children in an extra tree |
134 | + of a directory that has been renamed under a provided path in this tree |
135 | + are all returned, even if none exist under a provided path in this |
136 | + tree, and vice versa. |
137 | + |
138 | + :param paths: An iterable of paths to start converting to ids from. |
139 | + Alternatively, if paths is None, no ids should be calculated and None |
140 | + will be returned. This is offered to make calling the api unconditional |
141 | + for code that *might* take a list of files. |
142 | + :param trees: Additional trees to consider. |
143 | + :param require_versioned: If False, do not raise NotVersionedError if |
144 | + an element of paths is not versioned in this tree and all of trees. |
145 | + """ |
146 | + return find_ids_across_trees(paths, [self] + list(trees), require_versioned) |
147 | + |
148 | def path2id(self, path): |
149 | """Return the id for path in this tree.""" |
150 | with self.lock_read(): |
151 | @@ -222,7 +269,7 @@ |
152 | # are not versioned. |
153 | return set((p for p in paths if self.path2id(p) is None)) |
154 | |
155 | - def iter_entries_by_dir(self, specific_file_ids=None, yield_parents=False): |
156 | + def iter_entries_by_dir(self, specific_files=None, yield_parents=False): |
157 | """Walk the tree in 'by_dir' order. |
158 | |
159 | This will yield each entry in the tree as a (path, entry) tuple. |
160 | @@ -231,20 +278,20 @@ |
161 | See Tree.iter_entries_by_dir for details. |
162 | |
163 | :param yield_parents: If True, yield the parents from the root leading |
164 | - down to specific_file_ids that have been requested. This has no |
165 | - impact if specific_file_ids is None. |
166 | + down to specific_files that have been requested. This has no |
167 | + impact if specific_files is None. |
168 | """ |
169 | with self.lock_read(): |
170 | - if specific_file_ids is None: |
171 | - inventory_file_ids = None |
172 | - else: |
173 | + if specific_files is not None: |
174 | inventory_file_ids = [] |
175 | - for tree_file_id in specific_file_ids: |
176 | - inventory, inv_file_id = self._unpack_file_id(tree_file_id) |
177 | + for path in specific_files: |
178 | + inventory, inv_file_id = self._path2inv_file_id(path) |
179 | if not inventory is self.root_inventory: # for now |
180 | raise AssertionError("%r != %r" % ( |
181 | inventory, self.root_inventory)) |
182 | inventory_file_ids.append(inv_file_id) |
183 | + else: |
184 | + inventory_file_ids = None |
185 | # FIXME: Handle nested trees |
186 | return self.root_inventory.iter_entries_by_dir( |
187 | specific_file_ids=inventory_file_ids, yield_parents=yield_parents) |
188 | @@ -319,6 +366,84 @@ |
189 | return last_revision |
190 | |
191 | |
192 | +def find_ids_across_trees(filenames, trees, require_versioned=True): |
193 | + """Find the ids corresponding to specified filenames. |
194 | + |
195 | + All matches in all trees will be used, and all children of matched |
196 | + directories will be used. |
197 | + |
198 | + :param filenames: The filenames to find file_ids for (if None, returns |
199 | + None) |
200 | + :param trees: The trees to find file_ids within |
201 | + :param require_versioned: if true, all specified filenames must occur in |
202 | + at least one tree. |
203 | + :return: a set of file ids for the specified filenames and their children. |
204 | + """ |
205 | + if not filenames: |
206 | + return None |
207 | + specified_path_ids = _find_ids_across_trees(filenames, trees, |
208 | + require_versioned) |
209 | + return _find_children_across_trees(specified_path_ids, trees) |
210 | + |
211 | + |
212 | +def _find_ids_across_trees(filenames, trees, require_versioned): |
213 | + """Find the ids corresponding to specified filenames. |
214 | + |
215 | + All matches in all trees will be used, but subdirectories are not scanned. |
216 | + |
217 | + :param filenames: The filenames to find file_ids for |
218 | + :param trees: The trees to find file_ids within |
219 | + :param require_versioned: if true, all specified filenames must occur in |
220 | + at least one tree. |
221 | + :return: a set of file ids for the specified filenames |
222 | + """ |
223 | + not_versioned = [] |
224 | + interesting_ids = set() |
225 | + for tree_path in filenames: |
226 | + not_found = True |
227 | + for tree in trees: |
228 | + file_id = tree.path2id(tree_path) |
229 | + if file_id is not None: |
230 | + interesting_ids.add(file_id) |
231 | + not_found = False |
232 | + if not_found: |
233 | + not_versioned.append(tree_path) |
234 | + if len(not_versioned) > 0 and require_versioned: |
235 | + raise errors.PathsNotVersionedError(not_versioned) |
236 | + return interesting_ids |
237 | + |
238 | + |
239 | +def _find_children_across_trees(specified_ids, trees): |
240 | + """Return a set including specified ids and their children. |
241 | + |
242 | + All matches in all trees will be used. |
243 | + |
244 | + :param trees: The trees to find file_ids within |
245 | + :return: a set containing all specified ids and their children |
246 | + """ |
247 | + interesting_ids = set(specified_ids) |
248 | + pending = interesting_ids |
249 | + # now handle children of interesting ids |
250 | + # we loop so that we handle all children of each id in both trees |
251 | + while len(pending) > 0: |
252 | + new_pending = set() |
253 | + for file_id in pending: |
254 | + for tree in trees: |
255 | + try: |
256 | + path = tree.id2path(file_id) |
257 | + except errors.NoSuchId: |
258 | + continue |
259 | + try: |
260 | + for child in tree.iter_child_entries(path, file_id): |
261 | + if child.file_id not in interesting_ids: |
262 | + new_pending.add(child.file_id) |
263 | + except errors.NotADirectory: |
264 | + pass |
265 | + interesting_ids.update(new_pending) |
266 | + pending = new_pending |
267 | + return interesting_ids |
268 | + |
269 | + |
270 | class MutableInventoryTree(MutableTree, InventoryTree): |
271 | |
272 | def apply_inventory_delta(self, changes): |
273 | @@ -442,10 +567,11 @@ |
274 | return entry[3] |
275 | # Find a 'best fit' match if the filesystem is case-insensitive |
276 | inv_path = self.tree._fix_case_of_inventory_path(inv_path) |
277 | - file_id = self.tree.path2id(inv_path) |
278 | - if file_id is not None: |
279 | - return self.tree.iter_entries_by_dir([file_id]).next()[1] |
280 | - return None |
281 | + try: |
282 | + return self.tree.iter_entries_by_dir( |
283 | + specific_files=[inv_path]).next()[1] |
284 | + except StopIteration: |
285 | + return None |
286 | |
287 | def _convert_to_directory(self, this_ie, inv_path): |
288 | """Convert an entry to a directory. |
289 | |
290 | === modified file 'breezy/bzr/workingtree.py' |
291 | --- breezy/bzr/workingtree.py 2018-03-04 19:11:21 +0000 |
292 | +++ breezy/bzr/workingtree.py 2018-03-24 01:23:20 +0000 |
293 | @@ -652,10 +652,7 @@ |
294 | file_ids are in a WorkingTree if they are in the working inventory |
295 | and the working file exists. |
296 | """ |
297 | - ret = set() |
298 | - for path, ie in self.iter_entries_by_dir(): |
299 | - ret.add(ie.file_id) |
300 | - return ret |
301 | + return {ie.file_id for path, ie in self.iter_entries_by_dir()} |
302 | |
303 | def all_versioned_paths(self): |
304 | return {path for path, ie in self.iter_entries_by_dir()} |
305 | @@ -1699,13 +1696,13 @@ |
306 | blocked_parent_ids.add(ie.file_id) |
307 | yield path, ie |
308 | |
309 | - def iter_entries_by_dir(self, specific_file_ids=None, yield_parents=False): |
310 | + def iter_entries_by_dir(self, specific_files=None, |
311 | + yield_parents=False): |
312 | """See Tree.iter_entries_by_dir()""" |
313 | # The only trick here is that if we supports_tree_reference then we |
314 | # need to detect if a directory becomes a tree-reference. |
315 | iterator = super(WorkingTree, self).iter_entries_by_dir( |
316 | - specific_file_ids=specific_file_ids, |
317 | - yield_parents=yield_parents) |
318 | + specific_files=specific_files, yield_parents=yield_parents) |
319 | if not self.supports_tree_reference(): |
320 | return iterator |
321 | else: |
322 | |
323 | === modified file 'breezy/filter_tree.py' |
324 | --- breezy/filter_tree.py 2018-03-23 23:32:28 +0000 |
325 | +++ breezy/filter_tree.py 2018-03-24 01:23:20 +0000 |
326 | @@ -58,14 +58,14 @@ |
327 | def is_executable(self, path, file_id=None): |
328 | return self.backing_tree.is_executable(path, file_id) |
329 | |
330 | - def iter_entries_by_dir(self, specific_file_ids=None, yield_parents=None): |
331 | + def iter_entries_by_dir(self, specific_files=None, yield_parents=None): |
332 | # NB: This simply returns the parent tree's entries; the length may be |
333 | # wrong but it can't easily be calculated without filtering the whole |
334 | # text. Currently all callers cope with this; perhaps they should be |
335 | # updated to a narrower interface that only provides things guaranteed |
336 | # cheaply available across all trees. -- mbp 20110705 |
337 | return self.backing_tree.iter_entries_by_dir( |
338 | - specific_file_ids=specific_file_ids, |
339 | + specific_files=specific_files, |
340 | yield_parents=yield_parents) |
341 | |
342 | def lock_read(self): |
343 | |
344 | === modified file 'breezy/merge.py' |
345 | --- breezy/merge.py 2018-03-24 00:39:56 +0000 |
346 | +++ breezy/merge.py 2018-03-24 01:23:20 +0000 |
347 | @@ -56,12 +56,13 @@ |
348 | # TODO: Report back as changes are merged in |
349 | |
350 | |
351 | -def transform_tree(from_tree, to_tree, interesting_ids=None): |
352 | +def transform_tree(from_tree, to_tree, interesting_files=None): |
353 | from_tree.lock_tree_write() |
354 | operation = cleanup.OperationWithCleanups(merge_inner) |
355 | operation.add_cleanup(from_tree.unlock) |
356 | operation.run_simple(from_tree.branch, to_tree, from_tree, |
357 | - ignore_zero=True, interesting_ids=interesting_ids, this_tree=from_tree) |
358 | + ignore_zero=True, this_tree=from_tree, |
359 | + interesting_files=interesting_files) |
360 | |
361 | |
362 | class MergeHooks(hooks.Hooks): |
363 | @@ -295,7 +296,6 @@ |
364 | self.base_tree = base_tree |
365 | self.ignore_zero = False |
366 | self.backup_files = False |
367 | - self.interesting_ids = None |
368 | self.interesting_files = None |
369 | self.show_base = False |
370 | self.reprocess = False |
371 | @@ -610,7 +610,6 @@ |
372 | def make_merger(self): |
373 | kwargs = {'working_tree': self.this_tree, 'this_tree': self.this_tree, |
374 | 'other_tree': self.other_tree, |
375 | - 'interesting_ids': self.interesting_ids, |
376 | 'interesting_files': self.interesting_files, |
377 | 'this_branch': self.this_branch, |
378 | 'other_branch': self.other_branch, |
379 | @@ -722,7 +721,7 @@ |
380 | requires_file_merge_plan = False |
381 | |
382 | def __init__(self, working_tree, this_tree, base_tree, other_tree, |
383 | - interesting_ids=None, reprocess=False, show_base=False, |
384 | + reprocess=False, show_base=False, |
385 | change_reporter=None, interesting_files=None, do_merge=True, |
386 | cherrypick=False, lca_trees=None, this_branch=None, |
387 | other_branch=None): |
388 | @@ -735,30 +734,22 @@ |
389 | :param this_branch: The branch associated with this_tree. Defaults to |
390 | this_tree.branch if not supplied. |
391 | :param other_branch: The branch associated with other_tree, if any. |
392 | - :param interesting_ids: The file_ids of files that should be |
393 | - participate in the merge. May not be combined with |
394 | - interesting_files. |
395 | :param: reprocess If True, perform conflict-reduction processing. |
396 | :param show_base: If True, show the base revision in text conflicts. |
397 | (incompatible with reprocess) |
398 | :param change_reporter: An object that should report changes made |
399 | :param interesting_files: The tree-relative paths of files that should |
400 | participate in the merge. If these paths refer to directories, |
401 | - the contents of those directories will also be included. May not |
402 | - be combined with interesting_ids. If neither interesting_files nor |
403 | - interesting_ids is specified, all files may participate in the |
404 | + the contents of those directories will also be included. If not |
405 | + specified, all files may participate in the |
406 | merge. |
407 | :param lca_trees: Can be set to a dictionary of {revision_id:rev_tree} |
408 | if the ancestry was found to include a criss-cross merge. |
409 | Otherwise should be None. |
410 | """ |
411 | object.__init__(self) |
412 | - if interesting_files is not None and interesting_ids is not None: |
413 | - raise ValueError( |
414 | - 'specify either interesting_ids or interesting_files') |
415 | if this_branch is None: |
416 | this_branch = this_tree.branch |
417 | - self.interesting_ids = interesting_ids |
418 | self.interesting_files = interesting_files |
419 | self.working_tree = working_tree |
420 | self.this_tree = this_tree |
421 | @@ -874,14 +865,13 @@ |
422 | iterator = self.other_tree.iter_changes(self.base_tree, |
423 | specific_files=self.interesting_files, |
424 | extra_trees=[self.this_tree]) |
425 | + this_interesting_files = self.this_tree.find_related_paths_across_trees( |
426 | + self.interesting_files, trees=[self.other_tree]) |
427 | this_entries = dict((e.file_id, e) for p, e in |
428 | self.this_tree.iter_entries_by_dir( |
429 | - self.interesting_ids)) |
430 | + specific_files=this_interesting_files)) |
431 | for (file_id, paths, changed, versioned, parents, names, kind, |
432 | executable) in iterator: |
433 | - if (self.interesting_ids is not None and |
434 | - file_id not in self.interesting_ids): |
435 | - continue |
436 | entry = this_entries.get(file_id) |
437 | if entry is not None: |
438 | this_name = entry.name |
439 | @@ -919,10 +909,10 @@ |
440 | lookup_trees = [self.this_tree, self.base_tree] |
441 | lookup_trees.extend(self._lca_trees) |
442 | # I think we should include the lca trees as well |
443 | - interesting_ids = self.other_tree.paths2ids(self.interesting_files, |
444 | - lookup_trees) |
445 | + interesting_files = self.other_tree.find_related_paths_across_trees( |
446 | + self.interesting_files, lookup_trees) |
447 | else: |
448 | - interesting_ids = self.interesting_ids |
449 | + interesting_files = None |
450 | result = [] |
451 | walker = _mod_tree.MultiWalker(self.other_tree, self._lca_trees) |
452 | |
453 | @@ -932,7 +922,7 @@ |
454 | # Is this modified at all from any of the other trees? |
455 | if other_ie is None: |
456 | other_ie = _none_entry |
457 | - if interesting_ids is not None and file_id not in interesting_ids: |
458 | + if interesting_files is not None and path not in interesting_files: |
459 | continue |
460 | |
461 | # If other_revision is found in any of the lcas, that means this |
462 | @@ -1815,7 +1805,7 @@ |
463 | self.merge_type = Merge3Merger |
464 | self.show_base = False |
465 | self.reprocess = False |
466 | - self.interesting_ids = None |
467 | + self.interesting_files = None |
468 | self.merge_type = _MergeTypeParameterizer(MergeIntoMergeType, |
469 | target_subdir=self._target_subdir, |
470 | source_subpath=self._source_subpath) |
471 | @@ -1926,7 +1916,6 @@ |
472 | def merge_inner(this_branch, other_tree, base_tree, ignore_zero=False, |
473 | backup_files=False, |
474 | merge_type=Merge3Merger, |
475 | - interesting_ids=None, |
476 | show_base=False, |
477 | reprocess=False, |
478 | other_rev_id=None, |
479 | @@ -1947,13 +1936,8 @@ |
480 | change_reporter=change_reporter) |
481 | merger.backup_files = backup_files |
482 | merger.merge_type = merge_type |
483 | - merger.interesting_ids = interesting_ids |
484 | merger.ignore_zero = ignore_zero |
485 | - if interesting_files: |
486 | - if interesting_ids: |
487 | - raise ValueError('Only supply interesting_ids' |
488 | - ' or interesting_files') |
489 | - merger.interesting_files = interesting_files |
490 | + merger.interesting_files = interesting_files |
491 | merger.show_base = show_base |
492 | merger.reprocess = reprocess |
493 | merger.other_rev_id = other_rev_id |
494 | |
495 | === modified file 'breezy/rename_map.py' |
496 | --- breezy/rename_map.py 2018-03-12 01:24:43 +0000 |
497 | +++ breezy/rename_map.py 2018-03-24 01:23:20 +0000 |
498 | @@ -26,6 +26,7 @@ |
499 | from .sixish import ( |
500 | BytesIO, |
501 | viewitems, |
502 | + viewvalues, |
503 | ) |
504 | from .ui import ui_factory |
505 | |
506 | @@ -237,7 +238,14 @@ |
507 | def _make_inventory_delta(self, matches): |
508 | delta = [] |
509 | file_id_matches = dict((f, p) for p, f in viewitems(matches)) |
510 | - for old_path, entry in self.tree.iter_entries_by_dir(file_id_matches): |
511 | + file_id_query = [] |
512 | + for f in viewvalues(matches): |
513 | + try: |
514 | + file_id_query.append(self.tree.id2path(f)) |
515 | + except errors.NoSuchId: |
516 | + pass |
517 | + for old_path, entry in self.tree.iter_entries_by_dir( |
518 | + specific_files=file_id_query): |
519 | new_path = file_id_matches[entry.file_id] |
520 | parent_path, new_name = osutils.split(new_path) |
521 | parent_id = matches.get(parent_path) |
522 | |
523 | === modified file 'breezy/tests/per_intertree/test_compare.py' |
524 | --- breezy/tests/per_intertree/test_compare.py 2017-11-21 20:37:41 +0000 |
525 | +++ breezy/tests/per_intertree/test_compare.py 2018-03-24 01:23:20 +0000 |
526 | @@ -557,7 +557,9 @@ |
527 | |
528 | @staticmethod |
529 | def get_path_entry(tree, file_id): |
530 | - iterator = tree.iter_entries_by_dir(specific_file_ids=[file_id]) |
531 | + with tree.lock_read(): |
532 | + path = tree.id2path(file_id) |
533 | + iterator = tree.iter_entries_by_dir(specific_files=[path]) |
534 | try: |
535 | return next(iterator) |
536 | except StopIteration: |
537 | |
538 | === modified file 'breezy/tests/per_tree/test_inv.py' |
539 | --- breezy/tests/per_tree/test_inv.py 2017-08-01 01:44:41 +0000 |
540 | +++ breezy/tests/per_tree/test_inv.py 2018-03-24 01:23:20 +0000 |
541 | @@ -33,8 +33,8 @@ |
542 | ) |
543 | |
544 | |
545 | -def get_entry(tree, file_id): |
546 | - return tree.iter_entries_by_dir([file_id]).next()[1] |
547 | +def get_entry(tree, path): |
548 | + return tree.iter_entries_by_dir(specific_files=[path]).next()[1] |
549 | |
550 | |
551 | class TestInventoryWithSymlinks(per_tree.TestCaseWithTree): |
552 | @@ -52,7 +52,7 @@ |
553 | raise TestSkipped( |
554 | 'symlinks not accurately represented in working trees and' |
555 | ' preview trees') |
556 | - entry = get_entry(self.tree, self.tree.path2id('symlink')) |
557 | + entry = get_entry(self.tree, 'symlink') |
558 | self.assertEqual(entry.symlink_target, 'link-target') |
559 | |
560 | def test_symlink_target_tree(self): |
561 | @@ -64,7 +64,7 @@ |
562 | self.assertIs(None, self.tree.get_file_size('symlink')) |
563 | |
564 | def test_symlink(self): |
565 | - entry = get_entry(self.tree, self.tree.path2id('symlink')) |
566 | + entry = get_entry(self.tree, 'symlink') |
567 | self.assertEqual(entry.kind, 'symlink') |
568 | self.assertEqual(None, entry.text_size) |
569 | |
570 | @@ -76,6 +76,9 @@ |
571 | self.build_tree(['tree/dir/', 'tree/dir/file']) |
572 | work_tree.add(['dir', 'dir/file']) |
573 | tree = self._convert_tree(work_tree) |
574 | + if not isinstance(tree, InventoryTree): |
575 | + raise tests.TestNotApplicable( |
576 | + "test not applicable on non-inventory tests") |
577 | tree.lock_read() |
578 | self.addCleanup(tree.unlock) |
579 | self.assertEqual({tree.path2id('dir'), tree.path2id('dir/file')}, |
580 | @@ -88,6 +91,9 @@ |
581 | work_tree.commit('commit old state') |
582 | work_tree.remove('file') |
583 | tree = self._convert_tree(work_tree) |
584 | + if not isinstance(tree, InventoryTree): |
585 | + raise tests.TestNotApplicable( |
586 | + "test not applicable on non-inventory tests") |
587 | tree.lock_read() |
588 | self.addCleanup(tree.unlock) |
589 | self.assertEqual(set([]), tree.paths2ids(['file'], |
590 | |
591 | === modified file 'breezy/tests/per_tree/test_test_trees.py' |
592 | --- breezy/tests/per_tree/test_test_trees.py 2018-02-26 13:36:15 +0000 |
593 | +++ breezy/tests/per_tree/test_test_trees.py 2018-03-24 01:23:20 +0000 |
594 | @@ -228,11 +228,8 @@ |
595 | (u'ba\N{Euro Sign}r/ba\N{Euro Sign}z', |
596 | baz_id, bar_id, revision_id), |
597 | ] |
598 | - tree.lock_read() |
599 | - try: |
600 | + with tree.lock_read(): |
601 | path_entries = list(tree.iter_entries_by_dir()) |
602 | - finally: |
603 | - tree.unlock() |
604 | |
605 | for expected, (path, ie) in zip(path_and_ids, path_entries): |
606 | self.assertEqual(expected[0], path) # Paths should match |
607 | @@ -276,11 +273,8 @@ |
608 | (u'ba\N{Euro Sign}r/qu\N{Euro Sign}x', |
609 | qux_id, bar_id, revision_id_2), |
610 | ] |
611 | - tree.lock_read() |
612 | - try: |
613 | + with tree.lock_read(): |
614 | path_entries = list(tree.iter_entries_by_dir()) |
615 | - finally: |
616 | - tree.unlock() |
617 | |
618 | for (epath, efid, eparent, erev), (path, ie) in zip(path_and_ids, |
619 | path_entries): |
620 | |
621 | === modified file 'breezy/tests/per_workingtree/test_inv.py' |
622 | --- breezy/tests/per_workingtree/test_inv.py 2018-02-15 19:38:33 +0000 |
623 | +++ breezy/tests/per_workingtree/test_inv.py 2018-03-24 01:23:20 +0000 |
624 | @@ -178,6 +178,6 @@ |
625 | # wt.current_dirstate()'s idea about what files are where. |
626 | ie = base.inventory['subdir-id'] |
627 | self.assertEqual('directory', ie.kind) |
628 | - path, ie = next(base.iter_entries_by_dir(['subdir-id'])) |
629 | + path, ie = next(base.iter_entries_by_dir(specific_files=['subdir'])) |
630 | self.assertEqual('subdir', path) |
631 | self.assertEqual('tree-reference', ie.kind) |
632 | |
633 | === modified file 'breezy/tests/per_workingtree/test_nested_specifics.py' |
634 | --- breezy/tests/per_workingtree/test_nested_specifics.py 2018-02-16 19:38:39 +0000 |
635 | +++ breezy/tests/per_workingtree/test_nested_specifics.py 2018-03-24 01:23:20 +0000 |
636 | @@ -79,5 +79,5 @@ |
637 | |
638 | def test_iter_entries_by_dir_autodetects_subtree(self): |
639 | tree = self.prepare_with_subtree() |
640 | - path, ie = next(tree.iter_entries_by_dir(['subtree-id'])) |
641 | + path, ie = next(tree.iter_entries_by_dir(specific_files=['subtree'])) |
642 | self.assertEqual('tree-reference', ie.kind) |
643 | |
644 | === modified file 'breezy/tests/per_workingtree/test_paths2ids.py' |
645 | --- breezy/tests/per_workingtree/test_paths2ids.py 2018-02-03 13:39:29 +0000 |
646 | +++ breezy/tests/per_workingtree/test_paths2ids.py 2018-03-24 01:23:20 +0000 |
647 | @@ -22,6 +22,7 @@ |
648 | """ |
649 | |
650 | from breezy import errors |
651 | +from breezy.bzr.inventorytree import InventoryTree |
652 | from breezy.tests import ( |
653 | features, |
654 | TestNotApplicable, |
655 | @@ -62,16 +63,30 @@ |
656 | |
657 | def test_paths_none_result_none(self): |
658 | tree = self.make_branch_and_tree('tree') |
659 | + if not isinstance(tree, InventoryTree): |
660 | + raise TestNotApplicable( |
661 | + "test not applicable on non-inventory tests") |
662 | + |
663 | tree.lock_read() |
664 | self.assertEqual(None, tree.paths2ids(None)) |
665 | tree.unlock() |
666 | |
667 | def test_find_single_root(self): |
668 | tree = self.make_branch_and_tree('tree') |
669 | + if not isinstance(tree, InventoryTree): |
670 | + raise TestNotApplicable( |
671 | + "test not applicable on non-inventory tests") |
672 | + |
673 | + |
674 | self.assertExpectedIds([tree.path2id('')], tree, ['']) |
675 | |
676 | def test_find_tree_and_clone_roots(self): |
677 | tree = self.make_branch_and_tree('tree') |
678 | + if not isinstance(tree, InventoryTree): |
679 | + raise TestNotApplicable( |
680 | + "test not applicable on non-inventory tests") |
681 | + |
682 | + |
683 | clone = tree.controldir.clone('clone').open_workingtree() |
684 | clone.lock_tree_write() |
685 | clone_root_id = 'new-id' |
686 | @@ -136,6 +151,11 @@ |
687 | new-child because its under dir in new. |
688 | """ |
689 | tree = self.make_branch_and_tree('tree') |
690 | + if not isinstance(tree, InventoryTree): |
691 | + raise TestNotApplicable( |
692 | + "test not applicable on non-inventory tests") |
693 | + |
694 | + |
695 | self.build_tree( |
696 | ['tree/dir/', 'tree/dir/child-moves', 'tree/dir/child-stays', |
697 | 'tree/dir/child-goes']) |
698 | @@ -161,6 +181,11 @@ |
699 | |
700 | def test_unversioned_one_tree(self): |
701 | tree = self.make_branch_and_tree('tree') |
702 | + if not isinstance(tree, InventoryTree): |
703 | + raise TestNotApplicable( |
704 | + "test not applicable on non-inventory tests") |
705 | + |
706 | + |
707 | self.build_tree(['tree/unversioned']) |
708 | self.assertExpectedIds([], tree, ['unversioned'], require_versioned=False) |
709 | tree.lock_read() |
710 | @@ -172,6 +197,10 @@ |
711 | # should not raise an error: it must be unversioned in *all* trees to |
712 | # error. |
713 | tree = self.make_branch_and_tree('tree') |
714 | + if not isinstance(tree, InventoryTree): |
715 | + raise TestNotApplicable( |
716 | + "test not applicable on non-inventory tests") |
717 | + |
718 | if not tree.supports_setting_file_ids(): |
719 | raise TestNotApplicable('tree does not support setting file ids') |
720 | tree.commit('make basis') |
721 | @@ -185,6 +214,10 @@ |
722 | # should not raise an error: it must be unversioned in *all* trees to |
723 | # error. |
724 | tree = self.make_branch_and_tree('tree') |
725 | + if not isinstance(tree, InventoryTree): |
726 | + raise TestNotApplicable( |
727 | + "test not applicable on non-inventory tests") |
728 | + |
729 | tree.commit('make basis') |
730 | basis = tree.basis_tree() |
731 | self.assertExpectedIds([], tree, ['unversioned'], [basis], |
732 | @@ -201,6 +234,10 @@ |
733 | def test_unversioned_non_ascii_one_tree(self): |
734 | self.requireFeature(features.UnicodeFilenameFeature) |
735 | tree = self.make_branch_and_tree('.') |
736 | + if not isinstance(tree, InventoryTree): |
737 | + raise TestNotApplicable( |
738 | + "test not applicable on non-inventory tests") |
739 | + |
740 | self.build_tree([u"\xa7"]) |
741 | self.assertExpectedIds([], tree, [u"\xa7"], require_versioned=False) |
742 | self.addCleanup(tree.lock_read().unlock) |
743 | |
744 | === modified file 'breezy/tests/test_merge.py' |
745 | --- breezy/tests/test_merge.py 2018-03-20 00:30:39 +0000 |
746 | +++ breezy/tests/test_merge.py 2018-03-24 01:23:20 +0000 |
747 | @@ -1265,8 +1265,7 @@ |
748 | builder.build_snapshot(['B-id', 'C-id'], [], revision_id='D-id') |
749 | return builder |
750 | |
751 | - def make_Merger(self, builder, other_revision_id, |
752 | - interesting_files=None, interesting_ids=None): |
753 | + def make_Merger(self, builder, other_revision_id, interesting_files=None): |
754 | """Make a Merger object from a branch builder""" |
755 | mem_tree = memorytree.MemoryTree.create_on_branch(builder.get_branch()) |
756 | mem_tree.lock_write() |
757 | @@ -1274,8 +1273,6 @@ |
758 | merger = _mod_merge.Merger.from_revision_ids( |
759 | mem_tree, other_revision_id) |
760 | merger.set_interesting_files(interesting_files) |
761 | - # It seems there is no matching function for set_interesting_ids |
762 | - merger.interesting_ids = interesting_ids |
763 | merger.merge_type = _mod_merge.Merge3Merger |
764 | return merger |
765 | |
766 | @@ -1400,10 +1397,9 @@ |
767 | class TestMergerEntriesLCA(TestMergerBase): |
768 | |
769 | def make_merge_obj(self, builder, other_revision_id, |
770 | - interesting_files=None, interesting_ids=None): |
771 | + interesting_files=None): |
772 | merger = self.make_Merger(builder, other_revision_id, |
773 | - interesting_files=interesting_files, |
774 | - interesting_ids=interesting_ids) |
775 | + interesting_files=interesting_files) |
776 | return merger.make_merger() |
777 | |
778 | def test_simple(self): |
779 | @@ -2099,7 +2095,7 @@ |
780 | ((False, [False, False]), False, False)), |
781 | ], entries) |
782 | |
783 | - def test_interesting_ids(self): |
784 | + def test_interesting_files(self): |
785 | # Two files modified, but we should filter one of them |
786 | builder = self.get_builder() |
787 | builder.build_snapshot(None, |
788 | @@ -2114,7 +2110,7 @@ |
789 | ('modify', ('b-id', 'new-content\n'))], revision_id='E-id') |
790 | builder.build_snapshot(['B-id', 'C-id'], [], revision_id='D-id') |
791 | merge_obj = self.make_merge_obj(builder, 'E-id', |
792 | - interesting_ids=['b-id']) |
793 | + interesting_files=['b']) |
794 | entries = list(merge_obj._entries_lca()) |
795 | root_id = 'a-root-id' |
796 | self.assertEqual([('b-id', True, |
797 | |
798 | === modified file 'breezy/tests/test_merge_core.py' |
799 | --- breezy/tests/test_merge_core.py 2018-03-09 19:52:32 +0000 |
800 | +++ breezy/tests/test_merge_core.py 2018-03-24 01:23:20 +0000 |
801 | @@ -77,8 +77,8 @@ |
802 | if option is True: |
803 | new_file(tt) |
804 | |
805 | - def merge(self, merge_type=Merge3Merger, interesting_ids=None, **kwargs): |
806 | - merger = self.make_merger(merge_type, interesting_ids, **kwargs) |
807 | + def merge(self, merge_type=Merge3Merger, interesting_files=None, **kwargs): |
808 | + merger = self.make_merger(merge_type, interesting_files, **kwargs) |
809 | merger.do_merge() |
810 | return merger.cooked_conflicts |
811 | |
812 | @@ -86,7 +86,7 @@ |
813 | merger = self.make_merger(Merge3Merger, None, this_revision_tree=True) |
814 | return merger.make_preview_transform() |
815 | |
816 | - def make_merger(self, merge_type, interesting_ids, |
817 | + def make_merger(self, merge_type, interesting_files, |
818 | this_revision_tree=False, **kwargs): |
819 | self.base_tt.apply() |
820 | self.base.commit('base commit') |
821 | @@ -110,7 +110,7 @@ |
822 | else: |
823 | this_tree = self.this |
824 | merger = merge_type(this_tree, self.this, self.base, other_basis, |
825 | - interesting_ids=interesting_ids, do_merge=False, |
826 | + interesting_files=interesting_files, do_merge=False, |
827 | this_branch=self.this.branch, **kwargs) |
828 | return merger |
829 | |
830 | @@ -251,7 +251,7 @@ |
831 | builder.change_contents("1", other="text4") |
832 | builder.add_file("2", builder.tree_root, "name2", "hello1", True) |
833 | builder.change_contents("2", other="text4") |
834 | - builder.merge(interesting_ids=["1"]) |
835 | + builder.merge(interesting_files=["name1"]) |
836 | self.assertEqual(builder.this.get_file("name1").read(), "text4" ) |
837 | self.assertEqual(builder.this.get_file("name2").read(), "hello1" ) |
838 | builder.cleanup() |
839 | |
840 | === modified file 'breezy/tests/test_shelf.py' |
841 | --- breezy/tests/test_shelf.py 2017-12-12 01:19:18 +0000 |
842 | +++ breezy/tests/test_shelf.py 2018-03-24 01:23:20 +0000 |
843 | @@ -206,7 +206,7 @@ |
844 | |
845 | def check_shelve_creation(self, creator, tree): |
846 | self.assertRaises(StopIteration, |
847 | - next, tree.iter_entries_by_dir(['foo-id'])) |
848 | + next, tree.iter_entries_by_dir(specific_files=['foo'])) |
849 | s_trans_id = creator.shelf_transform.trans_id_file_id('foo-id') |
850 | self.assertEqual('foo-id', |
851 | creator.shelf_transform.final_file_id(s_trans_id)) |
852 | @@ -349,7 +349,7 @@ |
853 | creator.shelve_creation('foo-id') |
854 | creator.transform() |
855 | self.assertRaises(StopIteration, |
856 | - next, tree.iter_entries_by_dir(['foo-id'])) |
857 | + next, tree.iter_entries_by_dir(specific_files=['foo'])) |
858 | self.assertShelvedFileEqual('', creator, 'foo-id') |
859 | s_trans_id = creator.shelf_transform.trans_id_file_id('foo-id') |
860 | self.assertEqual('foo-id', |
861 | |
862 | === modified file 'breezy/tests/test_transform.py' |
863 | --- breezy/tests/test_transform.py 2018-03-24 00:39:56 +0000 |
864 | +++ breezy/tests/test_transform.py 2018-03-24 01:23:20 +0000 |
865 | @@ -2937,13 +2937,14 @@ |
866 | self.assertFalse(preview_tree.is_versioned('old_name/child')) |
867 | self.assertEqual('child-id', preview_tree.path2id('new_name/child')) |
868 | |
869 | - def assertMatchingIterEntries(self, tt, specific_file_ids=None): |
870 | + def assertMatchingIterEntries(self, tt, specific_files=None): |
871 | preview_tree = tt.get_preview_tree() |
872 | preview_result = list(preview_tree.iter_entries_by_dir( |
873 | - specific_file_ids)) |
874 | + specific_files=specific_files)) |
875 | tree = tt._tree |
876 | tt.apply() |
877 | - actual_result = list(tree.iter_entries_by_dir(specific_file_ids)) |
878 | + actual_result = list(tree.iter_entries_by_dir( |
879 | + specific_files=specific_files)) |
880 | self.assertEqual(actual_result, preview_result) |
881 | |
882 | def test_iter_entries_by_dir_new(self): |
883 | @@ -2983,7 +2984,7 @@ |
884 | self.build_tree(['tree/parent/', 'tree/parent/child']) |
885 | tree.add(['parent', 'parent/child'], ['parent-id', 'child-id']) |
886 | tt = TreeTransform(tree) |
887 | - self.assertMatchingIterEntries(tt, ['tree-root-id', 'child-id']) |
888 | + self.assertMatchingIterEntries(tt, ['', 'parent/child']) |
889 | |
890 | def test_symlink_content_summary(self): |
891 | self.requireFeature(SymlinkFeature) |
892 | |
893 | === modified file 'breezy/tests/test_workingtree.py' |
894 | --- breezy/tests/test_workingtree.py 2018-02-11 17:07:38 +0000 |
895 | +++ breezy/tests/test_workingtree.py 2018-03-24 01:23:20 +0000 |
896 | @@ -257,7 +257,8 @@ |
897 | subtree = self.make_branch_and_tree('tree/a/b') |
898 | self.assertEqual([('tree-reference', 'b-id')], |
899 | [(ie.kind, ie.file_id) |
900 | - for path, ie in tree.iter_entries_by_dir(['b-id'])]) |
901 | + for path, ie in tree.iter_entries_by_dir( |
902 | + specific_files=['a/b'])]) |
903 | |
904 | def test_direct_subtree(self): |
905 | tree = self.make_simple_tree() |
906 | |
907 | === modified file 'breezy/transform.py' |
908 | --- breezy/transform.py 2018-03-24 00:39:56 +0000 |
909 | +++ breezy/transform.py 2018-03-24 01:23:20 +0000 |
910 | @@ -894,7 +894,7 @@ |
911 | to_trans_ids[to_file_id] = trans_id |
912 | return from_trans_ids, to_trans_ids |
913 | |
914 | - def _from_file_data(self, from_trans_id, from_versioned, file_id): |
915 | + def _from_file_data(self, from_trans_id, from_versioned, from_path): |
916 | """Get data about a file in the from (tree) state |
917 | |
918 | Return a (name, parent, kind, executable) tuple |
919 | @@ -902,7 +902,8 @@ |
920 | from_path = self._tree_id_paths.get(from_trans_id) |
921 | if from_versioned: |
922 | # get data from working tree if versioned |
923 | - from_entry = self._tree.iter_entries_by_dir([file_id]).next()[1] |
924 | + from_entry = self._tree.iter_entries_by_dir( |
925 | + specific_files=[from_path]).next()[1] |
926 | from_name = from_entry.name |
927 | from_parent = from_entry.parent_id |
928 | else: |
929 | @@ -971,12 +972,6 @@ |
930 | else: |
931 | to_versioned = True |
932 | |
933 | - from_name, from_parent, from_kind, from_executable = \ |
934 | - self._from_file_data(from_trans_id, from_versioned, file_id) |
935 | - |
936 | - to_name, to_parent, to_kind, to_executable = \ |
937 | - self._to_file_data(to_trans_id, from_trans_id, from_executable) |
938 | - |
939 | if not from_versioned: |
940 | from_path = None |
941 | else: |
942 | @@ -985,6 +980,13 @@ |
943 | to_path = None |
944 | else: |
945 | to_path = final_paths.get_path(to_trans_id) |
946 | + |
947 | + from_name, from_parent, from_kind, from_executable = \ |
948 | + self._from_file_data(from_trans_id, from_versioned, from_path) |
949 | + |
950 | + to_name, to_parent, to_kind, to_executable = \ |
951 | + self._to_file_data(to_trans_id, from_trans_id, from_executable) |
952 | + |
953 | if from_kind != to_kind: |
954 | modified = True |
955 | elif to_kind in ('file', 'symlink') and ( |
956 | @@ -1763,9 +1765,6 @@ |
957 | inventory_delta.append((path, None, file_id, None)) |
958 | new_path_file_ids = dict((t, self.final_file_id(t)) for p, t in |
959 | new_paths) |
960 | - entries = self._tree.iter_entries_by_dir( |
961 | - viewvalues(new_path_file_ids)) |
962 | - old_paths = dict((e.file_id, p) for p, e in entries) |
963 | final_kinds = {} |
964 | for num, (path, trans_id) in enumerate(new_paths): |
965 | if (num % 10) == 0: |
966 | @@ -1793,7 +1792,10 @@ |
967 | new_entry = inventory.make_entry(kind, |
968 | self.final_name(trans_id), |
969 | parent_file_id, file_id) |
970 | - old_path = old_paths.get(new_entry.file_id) |
971 | + try: |
972 | + old_path = self._tree.id2path(new_entry.file_id) |
973 | + except errors.NoSuchId: |
974 | + old_path = None |
975 | new_executability = self._new_executability.get(trans_id) |
976 | if new_executability is not None: |
977 | new_entry.executable = new_executability |
978 | @@ -1944,10 +1946,8 @@ |
979 | path = self._tree_id_paths[parent_id] |
980 | except KeyError: |
981 | return |
982 | - file_id = self.tree_file_id(parent_id) |
983 | - if file_id is None: |
984 | - return |
985 | - entry = self._tree.iter_entries_by_dir([file_id]).next()[1] |
986 | + entry = self._tree.iter_entries_by_dir( |
987 | + specific_files=[path]).next()[1] |
988 | children = getattr(entry, 'children', {}) |
989 | for child in children: |
990 | childpath = joinpath(path, child) |
991 | @@ -2127,14 +2127,14 @@ |
992 | if self._transform.final_file_id(trans_id) is None: |
993 | yield self._final_paths._determine_path(trans_id) |
994 | |
995 | - def _make_inv_entries(self, ordered_entries, specific_file_ids=None, |
996 | + def _make_inv_entries(self, ordered_entries, specific_files=None, |
997 | yield_parents=False): |
998 | for trans_id, parent_file_id in ordered_entries: |
999 | file_id = self._transform.final_file_id(trans_id) |
1000 | if file_id is None: |
1001 | continue |
1002 | - if (specific_file_ids is not None |
1003 | - and file_id not in specific_file_ids): |
1004 | + if (specific_files is not None and |
1005 | + unicode(self._final_paths.get_path(trans_id)) not in specific_files): |
1006 | continue |
1007 | kind = self._transform.final_kind(trans_id) |
1008 | if kind is None: |
1009 | @@ -2172,7 +2172,7 @@ |
1010 | for entry, trans_id in self._make_inv_entries(todo): |
1011 | yield entry |
1012 | |
1013 | - def iter_entries_by_dir(self, specific_file_ids=None, yield_parents=False): |
1014 | + def iter_entries_by_dir(self, specific_files=None, yield_parents=False): |
1015 | # This may not be a maximally efficient implementation, but it is |
1016 | # reasonably straightforward. An implementation that grafts the |
1017 | # TreeTransform changes onto the tree's iter_entries_by_dir results |
1018 | @@ -2180,7 +2180,7 @@ |
1019 | # position. |
1020 | ordered_ids = self._list_files_by_dir() |
1021 | for entry, trans_id in self._make_inv_entries(ordered_ids, |
1022 | - specific_file_ids, yield_parents=yield_parents): |
1023 | + specific_files, yield_parents=yield_parents): |
1024 | yield unicode(self._final_paths.get_path(trans_id)), entry |
1025 | |
1026 | def _iter_entries_for_dir(self, dir_path): |
1027 | @@ -3081,7 +3081,7 @@ |
1028 | if file_id is None: |
1029 | file_id = tt.inactive_file_id(trans_id) |
1030 | _, entry = next(path_tree.iter_entries_by_dir( |
1031 | - [file_id])) |
1032 | + specific_files=[path_tree.id2path(file_id)])) |
1033 | # special-case the other tree root (move its |
1034 | # children to current root) |
1035 | if entry.parent_id is None: |
1036 | |
1037 | === modified file 'breezy/tree.py' |
1038 | --- breezy/tree.py 2018-03-24 00:39:56 +0000 |
1039 | +++ breezy/tree.py 2018-03-24 01:23:20 +0000 |
1040 | @@ -213,7 +213,7 @@ |
1041 | """ |
1042 | raise NotImplementedError(self.id2path) |
1043 | |
1044 | - def iter_entries_by_dir(self, specific_file_ids=None, yield_parents=False): |
1045 | + def iter_entries_by_dir(self, specific_files=None, yield_parents=False): |
1046 | """Walk the tree in 'by_dir' order. |
1047 | |
1048 | This will yield each entry in the tree as a (path, entry) tuple. |
1049 | @@ -239,8 +239,8 @@ |
1050 | a, f, a/b, a/d, a/b/c, a/d/e, f/g |
1051 | |
1052 | :param yield_parents: If True, yield the parents from the root leading |
1053 | - down to specific_file_ids that have been requested. This has no |
1054 | - impact if specific_file_ids is None. |
1055 | + down to specific_files that have been requested. This has no |
1056 | + impact if specific_files is None. |
1057 | """ |
1058 | raise NotImplementedError(self.iter_entries_by_dir) |
1059 | |
1060 | @@ -501,24 +501,23 @@ |
1061 | """ |
1062 | return self.path2id(path) is not None |
1063 | |
1064 | - def paths2ids(self, paths, trees=[], require_versioned=True): |
1065 | - """Return all the ids that can be reached by walking from paths. |
1066 | - |
1067 | - Each path is looked up in this tree and any extras provided in |
1068 | - trees, and this is repeated recursively: the children in an extra tree |
1069 | - of a directory that has been renamed under a provided path in this tree |
1070 | - are all returned, even if none exist under a provided path in this |
1071 | - tree, and vice versa. |
1072 | - |
1073 | - :param paths: An iterable of paths to start converting to ids from. |
1074 | - Alternatively, if paths is None, no ids should be calculated and None |
1075 | - will be returned. This is offered to make calling the api unconditional |
1076 | - for code that *might* take a list of files. |
1077 | - :param trees: Additional trees to consider. |
1078 | - :param require_versioned: If False, do not raise NotVersionedError if |
1079 | - an element of paths is not versioned in this tree and all of trees. |
1080 | + def find_related_paths_across_trees(self, paths, trees=[], |
1081 | + require_versioned=True): |
1082 | + """Find related paths in tree corresponding to specified filenames in any |
1083 | + of `lookup_trees`. |
1084 | + |
1085 | + All matches in all trees will be used, and all children of matched |
1086 | + directories will be used. |
1087 | + |
1088 | + :param paths: The filenames to find related paths for (if None, returns |
1089 | + None) |
1090 | + :param trees: The trees to find file_ids within |
1091 | + :param require_versioned: if true, all specified filenames must occur in |
1092 | + at least one tree. |
1093 | + :return: a set of paths for the specified filenames and their children |
1094 | + in `tree` |
1095 | """ |
1096 | - return find_ids_across_trees(paths, [self] + list(trees), require_versioned) |
1097 | + raise NotImplementedError(self.find_related_paths_across_trees) |
1098 | |
1099 | def lock_read(self): |
1100 | """Lock this tree for multiple read only operations. |
1101 | @@ -657,84 +656,6 @@ |
1102 | return searcher |
1103 | |
1104 | |
1105 | -def find_ids_across_trees(filenames, trees, require_versioned=True): |
1106 | - """Find the ids corresponding to specified filenames. |
1107 | - |
1108 | - All matches in all trees will be used, and all children of matched |
1109 | - directories will be used. |
1110 | - |
1111 | - :param filenames: The filenames to find file_ids for (if None, returns |
1112 | - None) |
1113 | - :param trees: The trees to find file_ids within |
1114 | - :param require_versioned: if true, all specified filenames must occur in |
1115 | - at least one tree. |
1116 | - :return: a set of file ids for the specified filenames and their children. |
1117 | - """ |
1118 | - if not filenames: |
1119 | - return None |
1120 | - specified_path_ids = _find_ids_across_trees(filenames, trees, |
1121 | - require_versioned) |
1122 | - return _find_children_across_trees(specified_path_ids, trees) |
1123 | - |
1124 | - |
1125 | -def _find_ids_across_trees(filenames, trees, require_versioned): |
1126 | - """Find the ids corresponding to specified filenames. |
1127 | - |
1128 | - All matches in all trees will be used, but subdirectories are not scanned. |
1129 | - |
1130 | - :param filenames: The filenames to find file_ids for |
1131 | - :param trees: The trees to find file_ids within |
1132 | - :param require_versioned: if true, all specified filenames must occur in |
1133 | - at least one tree. |
1134 | - :return: a set of file ids for the specified filenames |
1135 | - """ |
1136 | - not_versioned = [] |
1137 | - interesting_ids = set() |
1138 | - for tree_path in filenames: |
1139 | - not_found = True |
1140 | - for tree in trees: |
1141 | - file_id = tree.path2id(tree_path) |
1142 | - if file_id is not None: |
1143 | - interesting_ids.add(file_id) |
1144 | - not_found = False |
1145 | - if not_found: |
1146 | - not_versioned.append(tree_path) |
1147 | - if len(not_versioned) > 0 and require_versioned: |
1148 | - raise errors.PathsNotVersionedError(not_versioned) |
1149 | - return interesting_ids |
1150 | - |
1151 | - |
1152 | -def _find_children_across_trees(specified_ids, trees): |
1153 | - """Return a set including specified ids and their children. |
1154 | - |
1155 | - All matches in all trees will be used. |
1156 | - |
1157 | - :param trees: The trees to find file_ids within |
1158 | - :return: a set containing all specified ids and their children |
1159 | - """ |
1160 | - interesting_ids = set(specified_ids) |
1161 | - pending = interesting_ids |
1162 | - # now handle children of interesting ids |
1163 | - # we loop so that we handle all children of each id in both trees |
1164 | - while len(pending) > 0: |
1165 | - new_pending = set() |
1166 | - for tree in trees: |
1167 | - for file_id in pending: |
1168 | - try: |
1169 | - path = tree.id2path(file_id) |
1170 | - except errors.NoSuchId: |
1171 | - continue |
1172 | - try: |
1173 | - for child in tree.iter_child_entries(path, file_id): |
1174 | - if child.file_id not in interesting_ids: |
1175 | - new_pending.add(child.file_id) |
1176 | - except errors.NotADirectory: |
1177 | - pass |
1178 | - interesting_ids.update(new_pending) |
1179 | - pending = new_pending |
1180 | - return interesting_ids |
1181 | - |
1182 | - |
1183 | class InterTree(InterObject): |
1184 | """This class represents operations taking place between two Trees. |
1185 | |
1186 | @@ -854,18 +775,6 @@ |
1187 | if extra_trees is not None: |
1188 | trees = trees + tuple(extra_trees) |
1189 | with self.lock_read(): |
1190 | - # target is usually the newer tree: |
1191 | - specific_file_ids = self.target.paths2ids(specific_files, trees, |
1192 | - require_versioned=require_versioned) |
1193 | - if specific_files and not specific_file_ids: |
1194 | - # All files are unversioned, so just return an empty delta |
1195 | - # _compare_trees would think we want a complete delta |
1196 | - result = delta.TreeDelta() |
1197 | - fake_entry = inventory.InventoryFile('unused', 'unused', 'unused') |
1198 | - result.unversioned = [(path, None, |
1199 | - self.target._comparison_data(fake_entry, path)[0]) for path in |
1200 | - specific_files] |
1201 | - return result |
1202 | return delta._compare_trees(self.source, self.target, want_unchanged, |
1203 | specific_files, include_root, extra_trees=extra_trees, |
1204 | require_versioned=require_versioned, |
1205 | @@ -907,17 +816,23 @@ |
1206 | output. An unversioned file is defined as one with (False, False) |
1207 | for the versioned pair. |
1208 | """ |
1209 | - lookup_trees = [self.source] |
1210 | - if extra_trees: |
1211 | - lookup_trees.extend(extra_trees) |
1212 | + if not extra_trees: |
1213 | + extra_trees = [] |
1214 | + else: |
1215 | + extra_trees = list(extra_trees) |
1216 | # The ids of items we need to examine to insure delta consistency. |
1217 | precise_file_ids = set() |
1218 | changed_file_ids = [] |
1219 | if specific_files == []: |
1220 | - specific_file_ids = [] |
1221 | + target_specific_files = [] |
1222 | + source_specific_files = [] |
1223 | else: |
1224 | - specific_file_ids = self.target.paths2ids(specific_files, |
1225 | - lookup_trees, require_versioned=require_versioned) |
1226 | + target_specific_files = self.target.find_related_paths_across_trees( |
1227 | + specific_files, [self.source] + extra_trees, |
1228 | + require_versioned=require_versioned) |
1229 | + source_specific_files = self.source.find_related_paths_across_trees( |
1230 | + specific_files, [self.target] + extra_trees, |
1231 | + require_versioned=require_versioned) |
1232 | if specific_files is not None: |
1233 | # reparented or added entries must have their parents included |
1234 | # so that valid deltas can be created. The seen_parents set |
1235 | @@ -937,10 +852,10 @@ |
1236 | all_unversioned = collections.deque() |
1237 | to_paths = {} |
1238 | from_entries_by_dir = list(self.source.iter_entries_by_dir( |
1239 | - specific_file_ids=specific_file_ids)) |
1240 | + specific_files=source_specific_files)) |
1241 | from_data = dict((e.file_id, (p, e)) for p, e in from_entries_by_dir) |
1242 | to_entries_by_dir = list(self.target.iter_entries_by_dir( |
1243 | - specific_file_ids=specific_file_ids)) |
1244 | + specific_files=target_specific_files)) |
1245 | num_entries = len(from_entries_by_dir) + len(to_entries_by_dir) |
1246 | entry_count = 0 |
1247 | # the unversioned path lookup only occurs on real trees - where there |
1248 | @@ -969,7 +884,7 @@ |
1249 | if pb is not None: |
1250 | pb.update('comparing files', entry_count, num_entries) |
1251 | if changes or include_unchanged: |
1252 | - if specific_file_ids is not None: |
1253 | + if specific_files is not None: |
1254 | new_parent_id = result[4][1] |
1255 | precise_file_ids.add(new_parent_id) |
1256 | changed_file_ids.append(result[0]) |
1257 | @@ -1017,12 +932,12 @@ |
1258 | yield(file_id, (path, to_path), changed_content, versioned, parent, |
1259 | name, kind, executable) |
1260 | changed_file_ids = set(changed_file_ids) |
1261 | - if specific_file_ids is not None: |
1262 | + if specific_files is not None: |
1263 | for result in self._handle_precise_ids(precise_file_ids, |
1264 | changed_file_ids): |
1265 | yield result |
1266 | |
1267 | - def _get_entry(self, tree, file_id): |
1268 | + def _get_entry(self, tree, path): |
1269 | """Get an inventory entry from a tree, with missing entries as None. |
1270 | |
1271 | If the tree raises NotImplementedError on accessing .inventory, then |
1272 | @@ -1032,20 +947,12 @@ |
1273 | :param tree: The tree to lookup the entry in. |
1274 | :param file_id: The file_id to lookup. |
1275 | """ |
1276 | + # No inventory available. |
1277 | try: |
1278 | - inventory = tree.root_inventory |
1279 | - except (AttributeError, NotImplementedError): |
1280 | - # No inventory available. |
1281 | - try: |
1282 | - iterator = tree.iter_entries_by_dir(specific_file_ids=[file_id]) |
1283 | - return iterator.next()[1] |
1284 | - except StopIteration: |
1285 | - return None |
1286 | - else: |
1287 | - try: |
1288 | - return inventory[file_id] |
1289 | - except errors.NoSuchId: |
1290 | - return None |
1291 | + iterator = tree.iter_entries_by_dir(specific_files=[path]) |
1292 | + return iterator.next()[1] |
1293 | + except StopIteration: |
1294 | + return None |
1295 | |
1296 | def _handle_precise_ids(self, precise_file_ids, changed_file_ids, |
1297 | discarded_changes=None): |
1298 | @@ -1093,22 +1000,26 @@ |
1299 | # Examine file_id |
1300 | if discarded_changes: |
1301 | result = discarded_changes.get(file_id) |
1302 | - old_entry = None |
1303 | + source_entry = None |
1304 | else: |
1305 | result = None |
1306 | if result is None: |
1307 | - old_entry = self._get_entry(self.source, file_id) |
1308 | - new_entry = self._get_entry(self.target, file_id) |
1309 | try: |
1310 | source_path = self.source.id2path(file_id) |
1311 | except errors.NoSuchId: |
1312 | source_path = None |
1313 | + source_entry = None |
1314 | + else: |
1315 | + source_entry = self._get_entry(self.source, source_path) |
1316 | try: |
1317 | target_path = self.target.id2path(file_id) |
1318 | except errors.NoSuchId: |
1319 | target_path = None |
1320 | + target_entry = None |
1321 | + else: |
1322 | + target_entry = self._get_entry(self.target, target_path) |
1323 | result, changes = self._changes_from_entries( |
1324 | - old_entry, new_entry, source_path, target_path) |
1325 | + source_entry, target_entry, source_path, target_path) |
1326 | else: |
1327 | changes = True |
1328 | # Get this parents parent to examine. |
1329 | @@ -1119,9 +1030,9 @@ |
1330 | result[6][1] != 'directory'): |
1331 | # This stopped being a directory, the old children have |
1332 | # to be included. |
1333 | - if old_entry is None: |
1334 | + if source_entry is None: |
1335 | # Reusing a discarded change. |
1336 | - old_entry = self._get_entry(self.source, file_id) |
1337 | + source_entry = self._get_entry(self.source, result[1][0]) |
1338 | precise_file_ids.update( |
1339 | child.file_id |
1340 | for child in self.source.iter_child_entries(result[1][0])) |
Thanks, all looks sensible.