Status: | Work in progress |
---|---|
Proposed branch: | lp:~mbp/bzr/deprecation |
Merge into: | lp:bzr |
Diff against target: |
503 lines (+119/-179) 7 files modified
bzrlib/add.py (+0/-95) bzrlib/builtins.py (+16/-13) bzrlib/mutabletree.py (+40/-18) bzrlib/tests/per_workingtree/test_smart_add.py (+8/-16) bzrlib/tests/test_smart_add.py (+2/-36) bzrlib/tree.py (+47/-1) doc/en/release-notes/bzr-2.3.txt (+6/-0) |
To merge this branch: | bzr merge lp:~mbp/bzr/deprecation |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
bzr-core | Pending | ||
Review via email: mp+38647@code.launchpad.net |
Commit message
Description of the change
This cleans up some old and pretty crufty code around AddAction and smart_add. The existing api was sufficiently complicated, and as far I can tell not used by plugins, so I think it's better just to delete it. This is a bit cleaner on its own, but also detangles things a bit to allower a larger refactoring of smart_add to be smaller and to use an inventory delta rather than mutating the in-memory inventory. (bug 79336 asked for this a long time ago; it was worked-around in bzr-svn but it would be better to give them a simpler interface).
There are essentially two ways callers might want to customize smart_add: a way to generate file ids (for example to match those in an existing tree) and to report on what's being done (typically to a file). For no good reason they were tied together into a somewhat strange callable object callback. Instead, there are now just plain callables for each.
Before merging this I'll check whether it impacts other things that may be adding files or implementing smart_add, including bzr-svn, the package importer, and bzr builder. Generally things that are mechanically adding files shouldn't need to call smart_add.
It might be nice to have a reporter object that's told about more actions from inside add and can do more than just say the files that were added.
Robert Collins (lifeless) wrote : | # |
It would also be good to check speed; add isn't a hugely common
operation, but benchmarkers do tend to test the time of 'bzr add' in
kernel/openoffice trees.
-Rob
Jelmer Vernooij (jelmer) wrote : | # |
Hi Martin,
I think this is a nice improvement over the previous smart_add() overall.
For bzr-svn this is a useful improvement in that the action argument is no longer necessary. It still wouldn't be able to use the stock smart_add() because that calls _write_inventory().
The file_id_
Martin Pool (mbp) wrote : | # |
On 17 October 2010 21:52, Robert Collins <email address hidden> wrote:
> It would also be good to check speed; add isn't a hugely common
> operation, but benchmarkers do tend to test the time of 'bzr add' in
> kernel/openoffice trees.
Yes, good idea, I will. I may need to dust off usertest...
--
Martin
Martin Pool (mbp) wrote : | # |
On 18 October 2010 10:54, Jelmer Vernooij <email address hidden> wrote:
> Hi Martin,
>
> I think this is a nice improvement over the previous smart_add() overall.
Great.
> For bzr-svn this is a useful improvement in that the action argument is no longer necessary. It still wouldn't be able to use the stock smart_add() because that calls _write_inventory().
Yes, I know. I am heading towards using an inventory delta instead,
which should make things easier for you, and this helps detangle it.
>
> The file_id_
I was wondering about that too. I'll move it.
--
Martin
Unmerged revisions
- 5363. By Martin Pool
-
Move add-from-base-tree into file_id_suggestion method on Tree.
Delete remaining AddAction and all of bzrlib.add.
- 5362. By Martin Pool
-
Delete obsolete AddAction code
- 5361. By Martin Pool
-
Remove specific print-to-file arguments from smart_add in favor of reporter callback
- 5360. By Martin Pool
-
fix broken imports
- 5359. By Martin Pool
-
Document deprecation of smart_add(
action= ...) - 5358. By Martin Pool
-
merge trunk
- 5357. By Martin Pool
-
trim imports
- 5356. By Martin Pool
-
news
- 5355. By Martin Pool
-
Delete obsolete and bad AddAction tests
- 5354. By Martin Pool
-
Don't pass an add action for simple command line add
Preview Diff
1 | === removed file 'bzrlib/add.py' | |||
2 | --- bzrlib/add.py 2010-06-23 08:19:28 +0000 | |||
3 | +++ bzrlib/add.py 1970-01-01 00:00:00 +0000 | |||
4 | @@ -1,95 +0,0 @@ | |||
5 | 1 | # Copyright (C) 2005-2010 Canonical Ltd | ||
6 | 2 | # | ||
7 | 3 | # This program is free software; you can redistribute it and/or modify | ||
8 | 4 | # it under the terms of the GNU General Public License as published by | ||
9 | 5 | # the Free Software Foundation; either version 2 of the License, or | ||
10 | 6 | # (at your option) any later version. | ||
11 | 7 | # | ||
12 | 8 | # This program is distributed in the hope that it will be useful, | ||
13 | 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | 11 | # GNU General Public License for more details. | ||
16 | 12 | # | ||
17 | 13 | # You should have received a copy of the GNU General Public License | ||
18 | 14 | # along with this program; if not, write to the Free Software | ||
19 | 15 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
20 | 16 | |||
21 | 17 | """Helper functions for adding files to working trees.""" | ||
22 | 18 | |||
23 | 19 | import sys | ||
24 | 20 | |||
25 | 21 | import bzrlib.osutils | ||
26 | 22 | |||
27 | 23 | |||
28 | 24 | class AddAction(object): | ||
29 | 25 | """A class which defines what action to take when adding a file.""" | ||
30 | 26 | |||
31 | 27 | def __init__(self, to_file=None, should_print=None): | ||
32 | 28 | """Initialize an action which prints added files to an output stream. | ||
33 | 29 | |||
34 | 30 | :param to_file: The stream to write into. This is expected to take | ||
35 | 31 | Unicode paths. If not supplied, it will default to ``sys.stdout``. | ||
36 | 32 | :param should_print: If False, printing will be suppressed. | ||
37 | 33 | """ | ||
38 | 34 | self._to_file = to_file | ||
39 | 35 | if to_file is None: | ||
40 | 36 | self._to_file = sys.stdout | ||
41 | 37 | self.should_print = False | ||
42 | 38 | if should_print is not None: | ||
43 | 39 | self.should_print = should_print | ||
44 | 40 | |||
45 | 41 | def __call__(self, inv, parent_ie, path, kind, _quote=bzrlib.osutils.quotefn): | ||
46 | 42 | """Add path to inventory. | ||
47 | 43 | |||
48 | 44 | The default action does nothing. | ||
49 | 45 | |||
50 | 46 | :param inv: The inventory we are working with. | ||
51 | 47 | :param path: The FastPath being added | ||
52 | 48 | :param kind: The kind of the object being added. | ||
53 | 49 | """ | ||
54 | 50 | if self.should_print: | ||
55 | 51 | self._to_file.write('adding %s\n' % _quote(path.raw_path)) | ||
56 | 52 | return None | ||
57 | 53 | |||
58 | 54 | |||
59 | 55 | class AddFromBaseAction(AddAction): | ||
60 | 56 | """This class will try to extract file ids from another tree.""" | ||
61 | 57 | |||
62 | 58 | def __init__(self, base_tree, base_path, to_file=None, should_print=None): | ||
63 | 59 | super(AddFromBaseAction, self).__init__(to_file=to_file, | ||
64 | 60 | should_print=should_print) | ||
65 | 61 | self.base_tree = base_tree | ||
66 | 62 | self.base_path = base_path | ||
67 | 63 | |||
68 | 64 | def __call__(self, inv, parent_ie, path, kind): | ||
69 | 65 | # Place the parent call | ||
70 | 66 | # Now check to see if we can extract an id for this file | ||
71 | 67 | file_id, base_path = self._get_base_file_id(path, parent_ie) | ||
72 | 68 | if file_id is not None: | ||
73 | 69 | if self.should_print: | ||
74 | 70 | self._to_file.write('adding %s w/ file id from %s\n' | ||
75 | 71 | % (path.raw_path, base_path)) | ||
76 | 72 | else: | ||
77 | 73 | # we aren't doing anything special, so let the default | ||
78 | 74 | # reporter happen | ||
79 | 75 | file_id = super(AddFromBaseAction, self).__call__( | ||
80 | 76 | inv, parent_ie, path, kind) | ||
81 | 77 | return file_id | ||
82 | 78 | |||
83 | 79 | def _get_base_file_id(self, path, parent_ie): | ||
84 | 80 | """Look for a file id in the base branch. | ||
85 | 81 | |||
86 | 82 | First, if the base tree has the parent directory, | ||
87 | 83 | we look for a file with the same name in that directory. | ||
88 | 84 | Else, we look for an entry in the base tree with the same path. | ||
89 | 85 | """ | ||
90 | 86 | |||
91 | 87 | if (parent_ie.file_id in self.base_tree): | ||
92 | 88 | base_parent_ie = self.base_tree.inventory[parent_ie.file_id] | ||
93 | 89 | base_child_ie = base_parent_ie.children.get(path.base_path) | ||
94 | 90 | if base_child_ie is not None: | ||
95 | 91 | return (base_child_ie.file_id, | ||
96 | 92 | self.base_tree.id2path(base_child_ie.file_id)) | ||
97 | 93 | full_base_path = bzrlib.osutils.pathjoin(self.base_path, path.raw_path) | ||
98 | 94 | # This may return None, but it is our last attempt | ||
99 | 95 | return self.base_tree.path2id(full_base_path), full_base_path | ||
100 | 96 | 0 | ||
101 | === modified file 'bzrlib/builtins.py' | |||
102 | --- bzrlib/builtins.py 2010-10-15 11:30:54 +0000 | |||
103 | +++ bzrlib/builtins.py 2010-10-17 10:21:09 +0000 | |||
104 | @@ -627,9 +627,7 @@ | |||
105 | 627 | 627 | ||
106 | 628 | def run(self, file_list, no_recurse=False, dry_run=False, verbose=False, | 628 | def run(self, file_list, no_recurse=False, dry_run=False, verbose=False, |
107 | 629 | file_ids_from=None): | 629 | file_ids_from=None): |
111 | 630 | import bzrlib.add | 630 | file_id_callback = report_callback = None |
109 | 631 | |||
110 | 632 | base_tree = None | ||
112 | 633 | if file_ids_from is not None: | 631 | if file_ids_from is not None: |
113 | 634 | try: | 632 | try: |
114 | 635 | base_tree, base_path = WorkingTree.open_containing( | 633 | base_tree, base_path = WorkingTree.open_containing( |
115 | @@ -638,18 +636,23 @@ | |||
116 | 638 | base_branch, base_path = Branch.open_containing( | 636 | base_branch, base_path = Branch.open_containing( |
117 | 639 | file_ids_from) | 637 | file_ids_from) |
118 | 640 | base_tree = base_branch.basis_tree() | 638 | base_tree = base_branch.basis_tree() |
119 | 641 | |||
120 | 642 | action = bzrlib.add.AddFromBaseAction(base_tree, base_path, | ||
121 | 643 | to_file=self.outf, should_print=(not is_quiet())) | ||
122 | 644 | else: | ||
123 | 645 | action = bzrlib.add.AddAction(to_file=self.outf, | ||
124 | 646 | should_print=(not is_quiet())) | ||
125 | 647 | |||
126 | 648 | if base_tree: | ||
127 | 649 | self.add_cleanup(base_tree.lock_read().unlock) | 639 | self.add_cleanup(base_tree.lock_read().unlock) |
128 | 640 | if is_quiet(): | ||
129 | 641 | to_file = None | ||
130 | 642 | else: | ||
131 | 643 | to_file = self.outf | ||
132 | 644 | file_id_callback = base_tree.file_id_suggestion( | ||
133 | 645 | base_path, to_file) | ||
134 | 646 | elif not is_quiet(): | ||
135 | 647 | def report_callback(ie, path): | ||
136 | 648 | self.outf.write("adding " + path + "\n") | ||
137 | 650 | tree, file_list = tree_files_for_add(file_list) | 649 | tree, file_list = tree_files_for_add(file_list) |
140 | 651 | added, ignored = tree.smart_add(file_list, not | 650 | added, ignored = tree.smart_add( |
141 | 652 | no_recurse, action=action, save=not dry_run) | 651 | file_list, |
142 | 652 | recurse=(not no_recurse), | ||
143 | 653 | file_id_callback=file_id_callback, | ||
144 | 654 | save=not dry_run, | ||
145 | 655 | report_callback=report_callback) | ||
146 | 653 | self.cleanup_now() | 656 | self.cleanup_now() |
147 | 654 | if len(ignored) > 0: | 657 | if len(ignored) > 0: |
148 | 655 | if verbose: | 658 | if verbose: |
149 | 656 | 659 | ||
150 | === modified file 'bzrlib/mutabletree.py' | |||
151 | --- bzrlib/mutabletree.py 2010-08-17 06:45:33 +0000 | |||
152 | +++ bzrlib/mutabletree.py 2010-10-17 10:21:09 +0000 | |||
153 | @@ -30,9 +30,9 @@ | |||
154 | 30 | bzrdir, | 30 | bzrdir, |
155 | 31 | errors, | 31 | errors, |
156 | 32 | hooks, | 32 | hooks, |
157 | 33 | inventory, | ||
158 | 33 | osutils, | 34 | osutils, |
159 | 34 | revisiontree, | 35 | revisiontree, |
160 | 35 | inventory, | ||
161 | 36 | symbol_versioning, | 36 | symbol_versioning, |
162 | 37 | trace, | 37 | trace, |
163 | 38 | tree, | 38 | tree, |
164 | @@ -370,7 +370,13 @@ | |||
165 | 370 | raise NotImplementedError(self.set_parent_trees) | 370 | raise NotImplementedError(self.set_parent_trees) |
166 | 371 | 371 | ||
167 | 372 | @needs_tree_write_lock | 372 | @needs_tree_write_lock |
169 | 373 | def smart_add(self, file_list, recurse=True, action=None, save=True): | 373 | def smart_add(self, |
170 | 374 | file_list, | ||
171 | 375 | recurse=True, | ||
172 | 376 | action=None, | ||
173 | 377 | save=True, | ||
174 | 378 | file_id_callback=None, | ||
175 | 379 | report_callback=None): | ||
176 | 374 | """Version file_list, optionally recursing into directories. | 380 | """Version file_list, optionally recursing into directories. |
177 | 375 | 381 | ||
178 | 376 | This is designed more towards DWIM for humans than API clarity. | 382 | This is designed more towards DWIM for humans than API clarity. |
179 | @@ -386,15 +392,22 @@ | |||
180 | 386 | :param save: Save the inventory after completing the adds. If False | 392 | :param save: Save the inventory after completing the adds. If False |
181 | 387 | this provides dry-run functionality by doing the add and not saving | 393 | this provides dry-run functionality by doing the add and not saving |
182 | 388 | the inventory. | 394 | the inventory. |
183 | 395 | :param file_id_callback: Optional, | ||
184 | 396 | file_id_callback(parent_ie, path, kind) => file_id. | ||
185 | 397 | :param report_callback: Optional, called after each file is added | ||
186 | 398 | with (ie, path); result ignored. | ||
187 | 389 | :return: A tuple - files_added, ignored_files. files_added is the count | 399 | :return: A tuple - files_added, ignored_files. files_added is the count |
188 | 390 | of added files, and ignored_files is a dict mapping files that were | 400 | of added files, and ignored_files is a dict mapping files that were |
189 | 391 | ignored to the rule that caused them to be ignored. | 401 | ignored to the rule that caused them to be ignored. |
190 | 392 | """ | 402 | """ |
196 | 393 | # not in an inner loop; and we want to remove direct use of this, | 403 | if action is not None: |
197 | 394 | # so here as a reminder for now. RBC 20070703 | 404 | raise ValueError( |
198 | 395 | from bzrlib.inventory import InventoryEntry | 405 | "passing action to smart_add is no longer supported in bzr 2.3") |
199 | 396 | if action is None: | 406 | elif file_id_callback is None: |
200 | 397 | action = add.AddAction() | 407 | file_id_callback = lambda *a: None |
201 | 408 | |||
202 | 409 | if report_callback is None: | ||
203 | 410 | report_callback = lambda *a: None | ||
204 | 398 | 411 | ||
205 | 399 | if not file_list: | 412 | if not file_list: |
206 | 400 | # no paths supplied: add the entire tree. | 413 | # no paths supplied: add the entire tree. |
207 | @@ -437,7 +450,7 @@ | |||
208 | 437 | # schedule the dir for scanning | 450 | # schedule the dir for scanning |
209 | 438 | user_dirs.add(rf) | 451 | user_dirs.add(rf) |
210 | 439 | else: | 452 | else: |
212 | 440 | if not InventoryEntry.versionable_kind(kind): | 453 | if not inventory.InventoryEntry.versionable_kind(kind): |
213 | 441 | raise errors.BadFileKindError(filename=abspath, kind=kind) | 454 | raise errors.BadFileKindError(filename=abspath, kind=kind) |
214 | 442 | # ensure the named path is added, so that ignore rules in the later | 455 | # ensure the named path is added, so that ignore rules in the later |
215 | 443 | # directory walk dont skip it. | 456 | # directory walk dont skip it. |
216 | @@ -446,7 +459,8 @@ | |||
217 | 446 | versioned = inv.has_filename(rf.raw_path) | 459 | versioned = inv.has_filename(rf.raw_path) |
218 | 447 | if versioned: | 460 | if versioned: |
219 | 448 | continue | 461 | continue |
221 | 449 | added.extend(_add_one_and_parent(self, inv, None, rf, kind, action)) | 462 | added.extend(_add_one_and_parent(self, inv, None, rf, kind, |
222 | 463 | file_id_callback, report_callback)) | ||
223 | 450 | 464 | ||
224 | 451 | if not recurse: | 465 | if not recurse: |
225 | 452 | # no need to walk any directories at all. | 466 | # no need to walk any directories at all. |
226 | @@ -478,7 +492,7 @@ | |||
227 | 478 | # find the kind of the path being added. | 492 | # find the kind of the path being added. |
228 | 479 | kind = osutils.file_kind(abspath) | 493 | kind = osutils.file_kind(abspath) |
229 | 480 | 494 | ||
231 | 481 | if not InventoryEntry.versionable_kind(kind): | 495 | if not inventory.InventoryEntry.versionable_kind(kind): |
232 | 482 | trace.warning("skipping %s (can't add file of kind '%s')", | 496 | trace.warning("skipping %s (can't add file of kind '%s')", |
233 | 483 | abspath, kind) | 497 | abspath, kind) |
234 | 484 | continue | 498 | continue |
235 | @@ -529,7 +543,8 @@ | |||
236 | 529 | # 20070306 | 543 | # 20070306 |
237 | 530 | trace.mutter("%r is a nested bzr tree", abspath) | 544 | trace.mutter("%r is a nested bzr tree", abspath) |
238 | 531 | else: | 545 | else: |
240 | 532 | _add_one(self, inv, parent_ie, directory, kind, action) | 546 | _add_one(self, inv, parent_ie, directory, kind, |
241 | 547 | file_id_callback, report_callback) | ||
242 | 533 | added.append(directory.raw_path) | 548 | added.append(directory.raw_path) |
243 | 534 | 549 | ||
244 | 535 | if kind == 'directory' and not sub_tree: | 550 | if kind == 'directory' and not sub_tree: |
245 | @@ -681,7 +696,8 @@ | |||
246 | 681 | return hash(self.raw_path) | 696 | return hash(self.raw_path) |
247 | 682 | 697 | ||
248 | 683 | 698 | ||
250 | 684 | def _add_one_and_parent(tree, inv, parent_ie, path, kind, action): | 699 | def _add_one_and_parent(tree, inv, parent_ie, path, kind, file_id_callback, |
251 | 700 | report_callback): | ||
252 | 685 | """Add a new entry to the inventory and automatically add unversioned parents. | 701 | """Add a new entry to the inventory and automatically add unversioned parents. |
253 | 686 | 702 | ||
254 | 687 | :param inv: Inventory which will receive the new entry. | 703 | :param inv: Inventory which will receive the new entry. |
255 | @@ -689,7 +705,8 @@ | |||
256 | 689 | None, the parent is looked up by name and used if present, otherwise it | 705 | None, the parent is looked up by name and used if present, otherwise it |
257 | 690 | is recursively added. | 706 | is recursively added. |
258 | 691 | :param kind: Kind of new entry (file, directory, etc) | 707 | :param kind: Kind of new entry (file, directory, etc) |
260 | 692 | :param action: callback(inv, parent_ie, path, kind); return ignored. | 708 | :param file_id_callback: callback(inv, parent_ie, path, kind); return a |
261 | 709 | file_id or None to generate a new file id | ||
262 | 693 | :return: A list of paths which have been added. | 710 | :return: A list of paths which have been added. |
263 | 694 | """ | 711 | """ |
264 | 695 | # Nothing to do if path is already versioned. | 712 | # Nothing to do if path is already versioned. |
265 | @@ -707,20 +724,24 @@ | |||
266 | 707 | # there are a limited number of dirs we can be nested under, it should | 724 | # there are a limited number of dirs we can be nested under, it should |
267 | 708 | # generally find it very fast and not recurse after that. | 725 | # generally find it very fast and not recurse after that. |
268 | 709 | added = _add_one_and_parent(tree, inv, None, | 726 | added = _add_one_and_parent(tree, inv, None, |
270 | 710 | _FastPath(osutils.dirname(path.raw_path)), 'directory', action) | 727 | _FastPath(osutils.dirname(path.raw_path)), 'directory', |
271 | 728 | file_id_callback, | ||
272 | 729 | report_callback) | ||
273 | 711 | parent_id = inv.path2id(osutils.dirname(path.raw_path)) | 730 | parent_id = inv.path2id(osutils.dirname(path.raw_path)) |
274 | 712 | parent_ie = inv[parent_id] | 731 | parent_ie = inv[parent_id] |
276 | 713 | _add_one(tree, inv, parent_ie, path, kind, action) | 732 | _add_one(tree, inv, parent_ie, path, kind, file_id_callback, |
277 | 733 | report_callback) | ||
278 | 714 | return added + [path.raw_path] | 734 | return added + [path.raw_path] |
279 | 715 | 735 | ||
280 | 716 | 736 | ||
282 | 717 | def _add_one(tree, inv, parent_ie, path, kind, file_id_callback): | 737 | def _add_one(tree, inv, parent_ie, path, kind, file_id_callback, |
283 | 738 | report_callback): | ||
284 | 718 | """Add a new entry to the inventory. | 739 | """Add a new entry to the inventory. |
285 | 719 | 740 | ||
286 | 720 | :param inv: Inventory which will receive the new entry. | 741 | :param inv: Inventory which will receive the new entry. |
287 | 721 | :param parent_ie: Parent inventory entry. | 742 | :param parent_ie: Parent inventory entry. |
288 | 722 | :param kind: Kind of new entry (file, directory, etc) | 743 | :param kind: Kind of new entry (file, directory, etc) |
290 | 723 | :param file_id_callback: callback(inv, parent_ie, path, kind); return a | 744 | :param file_id_callback: callback(parent_ie, path, kind); return a |
291 | 724 | file_id or None to generate a new file id | 745 | file_id or None to generate a new file id |
292 | 725 | :returns: None | 746 | :returns: None |
293 | 726 | """ | 747 | """ |
294 | @@ -735,7 +756,8 @@ | |||
295 | 735 | del inv[parent_ie.file_id] | 756 | del inv[parent_ie.file_id] |
296 | 736 | inv.add(new_parent_ie) | 757 | inv.add(new_parent_ie) |
297 | 737 | parent_ie = new_parent_ie | 758 | parent_ie = new_parent_ie |
299 | 738 | file_id = file_id_callback(inv, parent_ie, path, kind) | 759 | file_id = file_id_callback(parent_ie, path, kind) |
300 | 739 | entry = inv.make_entry(kind, path.base_path, parent_ie.file_id, | 760 | entry = inv.make_entry(kind, path.base_path, parent_ie.file_id, |
301 | 740 | file_id=file_id) | 761 | file_id=file_id) |
302 | 741 | inv.add(entry) | 762 | inv.add(entry) |
303 | 763 | report_callback(entry, path.raw_path) | ||
304 | 742 | 764 | ||
305 | === modified file 'bzrlib/tests/per_workingtree/test_smart_add.py' | |||
306 | --- bzrlib/tests/per_workingtree/test_smart_add.py 2010-02-23 07:43:11 +0000 | |||
307 | +++ bzrlib/tests/per_workingtree/test_smart_add.py 2010-10-17 10:21:09 +0000 | |||
308 | @@ -20,7 +20,6 @@ | |||
309 | 20 | import sys | 20 | import sys |
310 | 21 | 21 | ||
311 | 22 | from bzrlib import ( | 22 | from bzrlib import ( |
312 | 23 | add, | ||
313 | 24 | errors, | 23 | errors, |
314 | 25 | ignores, | 24 | ignores, |
315 | 26 | osutils, | 25 | osutils, |
316 | @@ -28,12 +27,16 @@ | |||
317 | 28 | workingtree, | 27 | workingtree, |
318 | 29 | ) | 28 | ) |
319 | 30 | from bzrlib.tests import ( | 29 | from bzrlib.tests import ( |
320 | 31 | features, | ||
321 | 32 | test_smart_add, | ||
322 | 33 | per_workingtree, | 30 | per_workingtree, |
323 | 34 | ) | 31 | ) |
324 | 35 | 32 | ||
325 | 36 | 33 | ||
326 | 34 | def _make_custom_file_id(parent_ie, path, kind): | ||
327 | 35 | return osutils.safe_file_id(kind + '-' | ||
328 | 36 | + path.raw_path.replace('/', '%'), | ||
329 | 37 | warn=False) | ||
330 | 38 | |||
331 | 39 | |||
332 | 37 | class TestSmartAddTree(per_workingtree.TestCaseWithWorkingTree): | 40 | class TestSmartAddTree(per_workingtree.TestCaseWithWorkingTree): |
333 | 38 | 41 | ||
334 | 39 | def test_single_file(self): | 42 | def test_single_file(self): |
335 | @@ -203,20 +206,9 @@ | |||
336 | 203 | [path for path, ie in tree.iter_entries_by_dir()]) | 206 | [path for path, ie in tree.iter_entries_by_dir()]) |
337 | 204 | 207 | ||
338 | 205 | def test_custom_ids(self): | 208 | def test_custom_ids(self): |
342 | 206 | sio = StringIO() | 209 | wt = self.make_branch_and_tree('.') |
340 | 207 | action = test_smart_add.AddCustomIDAction(to_file=sio, | ||
341 | 208 | should_print=True) | ||
343 | 209 | self.build_tree(['file1', 'dir1/', 'dir1/file2']) | 210 | self.build_tree(['file1', 'dir1/', 'dir1/file2']) |
354 | 210 | 211 | wt.smart_add(['.'], file_id_callback=_make_custom_file_id) | |
345 | 211 | wt = self.make_branch_and_tree('.') | ||
346 | 212 | wt.smart_add(['.'], action=action) | ||
347 | 213 | # The order of adds is not strictly fixed: | ||
348 | 214 | sio.seek(0) | ||
349 | 215 | lines = sorted(sio.readlines()) | ||
350 | 216 | self.assertEqualDiff(['added dir1 with id directory-dir1\n', | ||
351 | 217 | 'added dir1/file2 with id file-dir1%file2\n', | ||
352 | 218 | 'added file1 with id file-file1\n', | ||
353 | 219 | ], lines) | ||
355 | 220 | wt.lock_read() | 212 | wt.lock_read() |
356 | 221 | self.addCleanup(wt.unlock) | 213 | self.addCleanup(wt.unlock) |
357 | 222 | self.assertEqual([('', wt.path2id('')), | 214 | self.assertEqual([('', wt.path2id('')), |
358 | 223 | 215 | ||
359 | === modified file 'bzrlib/tests/test_smart_add.py' | |||
360 | --- bzrlib/tests/test_smart_add.py 2010-02-10 17:52:08 +0000 | |||
361 | +++ bzrlib/tests/test_smart_add.py 2010-10-17 10:21:09 +0000 | |||
362 | @@ -18,26 +18,10 @@ | |||
363 | 18 | 18 | ||
364 | 19 | from bzrlib import ( | 19 | from bzrlib import ( |
365 | 20 | add, | 20 | add, |
366 | 21 | inventory, | ||
367 | 22 | osutils, | ||
368 | 23 | tests, | 21 | tests, |
369 | 24 | ) | 22 | ) |
370 | 25 | 23 | ||
371 | 26 | 24 | ||
372 | 27 | class AddCustomIDAction(add.AddAction): | ||
373 | 28 | |||
374 | 29 | def __call__(self, inv, parent_ie, path, kind): | ||
375 | 30 | # The first part just logs if appropriate | ||
376 | 31 | # Now generate a custom id | ||
377 | 32 | file_id = osutils.safe_file_id(kind + '-' | ||
378 | 33 | + path.raw_path.replace('/', '%'), | ||
379 | 34 | warn=False) | ||
380 | 35 | if self.should_print: | ||
381 | 36 | self._to_file.write('added %s with id %s\n' | ||
382 | 37 | % (path.raw_path, file_id)) | ||
383 | 38 | return file_id | ||
384 | 39 | |||
385 | 40 | |||
386 | 41 | class TestAddFrom(tests.TestCaseWithTransport): | 25 | class TestAddFrom(tests.TestCaseWithTransport): |
387 | 42 | """Tests for AddFromBaseAction""" | 26 | """Tests for AddFromBaseAction""" |
388 | 43 | 27 | ||
389 | @@ -62,7 +46,8 @@ | |||
390 | 62 | action = add.AddFromBaseAction(base_tree, base_path, | 46 | action = add.AddFromBaseAction(base_tree, base_path, |
391 | 63 | to_file=to_file, | 47 | to_file=to_file, |
392 | 64 | should_print=should_print) | 48 | should_print=should_print) |
394 | 65 | new_tree.smart_add(file_list, action=action) | 49 | new_tree.smart_add( |
395 | 50 | file_list, file_id_callback=action.generate_file_id) | ||
396 | 66 | finally: | 51 | finally: |
397 | 67 | new_tree.unlock() | 52 | new_tree.unlock() |
398 | 68 | finally: | 53 | finally: |
399 | @@ -141,22 +126,3 @@ | |||
400 | 141 | self.base_tree.lock_read() | 126 | self.base_tree.lock_read() |
401 | 142 | self.addCleanup(self.base_tree.unlock) | 127 | self.addCleanup(self.base_tree.unlock) |
402 | 143 | self.failIf(a_id in self.base_tree) | 128 | self.failIf(a_id in self.base_tree) |
403 | 144 | |||
404 | 145 | |||
405 | 146 | class TestAddActions(tests.TestCase): | ||
406 | 147 | |||
407 | 148 | def test_quiet(self): | ||
408 | 149 | self.run_action("") | ||
409 | 150 | |||
410 | 151 | def test__print(self): | ||
411 | 152 | self.run_action("adding path\n") | ||
412 | 153 | |||
413 | 154 | def run_action(self, output): | ||
414 | 155 | from bzrlib.mutabletree import _FastPath | ||
415 | 156 | inv = inventory.Inventory() | ||
416 | 157 | stdout = StringIO() | ||
417 | 158 | action = add.AddAction(to_file=stdout, should_print=bool(output)) | ||
418 | 159 | |||
419 | 160 | self.apply_redirected(None, stdout, None, action, inv, None, | ||
420 | 161 | _FastPath('path'), 'file') | ||
421 | 162 | self.assertEqual(stdout.getvalue(), output) | ||
422 | 163 | 129 | ||
423 | === modified file 'bzrlib/tree.py' | |||
424 | --- bzrlib/tree.py 2010-08-31 07:12:18 +0000 | |||
425 | +++ bzrlib/tree.py 2010-10-17 10:21:09 +0000 | |||
426 | @@ -37,7 +37,10 @@ | |||
427 | 37 | from bzrlib.inter import InterObject | 37 | from bzrlib.inter import InterObject |
428 | 38 | from bzrlib.osutils import fingerprint_file | 38 | from bzrlib.osutils import fingerprint_file |
429 | 39 | from bzrlib.symbol_versioning import deprecated_function, deprecated_in | 39 | from bzrlib.symbol_versioning import deprecated_function, deprecated_in |
431 | 40 | from bzrlib.trace import note | 40 | from bzrlib.trace import ( |
432 | 41 | mutter, | ||
433 | 42 | note, | ||
434 | 43 | ) | ||
435 | 41 | 44 | ||
436 | 42 | 45 | ||
437 | 43 | class Tree(object): | 46 | class Tree(object): |
438 | @@ -588,6 +591,49 @@ | |||
439 | 588 | """ | 591 | """ |
440 | 589 | pass | 592 | pass |
441 | 590 | 593 | ||
442 | 594 | def file_id_suggestion(self, under_dir, print_to_file): | ||
443 | 595 | """Return a callback to use with smart_add file_id_callback. | ||
444 | 596 | |||
445 | 597 | The returned callable tries to guess a file id for a newly added | ||
446 | 598 | file in a mutable tree, based on finding one at the same path in | ||
447 | 599 | this tree. | ||
448 | 600 | |||
449 | 601 | First, if this tree has the same parent directory id, | ||
450 | 602 | we look for a file with the same name in that directory. | ||
451 | 603 | Otherwise, we look for an entry in this tree with the same path. | ||
452 | 604 | |||
453 | 605 | :param under_path: Look for file ids under the given directory. | ||
454 | 606 | :param print_to_file: If non-None, write a message about matched | ||
455 | 607 | files to this stream. | ||
456 | 608 | """ | ||
457 | 609 | def find_one(parent_ie, path, kind): | ||
458 | 610 | # mutter("look up suggestion for %r in parent %r" | ||
459 | 611 | # % (path.raw_path, parent_ie)) | ||
460 | 612 | file_id = None | ||
461 | 613 | if parent_ie.file_id in self: | ||
462 | 614 | # mutter("found parent in %r" % self) | ||
463 | 615 | base_parent_ie = self.inventory[parent_ie.file_id] | ||
464 | 616 | # mutter(" looking for child %r" % path.base_path) | ||
465 | 617 | base_child_ie = base_parent_ie.children.get(path.base_path) | ||
466 | 618 | if base_child_ie is not None: | ||
467 | 619 | # mutter(" found child under it") | ||
468 | 620 | file_id = base_child_ie.file_id | ||
469 | 621 | origin_path = self.id2path(base_child_ie.file_id) | ||
470 | 622 | if file_id is None: | ||
471 | 623 | # Not found yet: try looking for the whole path. | ||
472 | 624 | origin_path = osutils.pathjoin(under_dir, path.raw_path) | ||
473 | 625 | file_id = self.path2id(origin_path) | ||
474 | 626 | if print_to_file is None: | ||
475 | 627 | pass | ||
476 | 628 | elif file_id is not None: | ||
477 | 629 | print_to_file.write( | ||
478 | 630 | 'adding %s w/ file id from %s\n' | ||
479 | 631 | % (path.raw_path, origin_path)) | ||
480 | 632 | else: | ||
481 | 633 | print_to_file.write('adding %s\n' % path.raw_path) | ||
482 | 634 | return file_id | ||
483 | 635 | return find_one | ||
484 | 636 | |||
485 | 591 | def revision_tree(self, revision_id): | 637 | def revision_tree(self, revision_id): |
486 | 592 | """Obtain a revision tree for the revision revision_id. | 638 | """Obtain a revision tree for the revision revision_id. |
487 | 593 | 639 | ||
488 | 594 | 640 | ||
489 | === modified file 'doc/en/release-notes/bzr-2.3.txt' | |||
490 | --- doc/en/release-notes/bzr-2.3.txt 2010-10-15 15:05:09 +0000 | |||
491 | +++ doc/en/release-notes/bzr-2.3.txt 2010-10-17 10:21:09 +0000 | |||
492 | @@ -72,6 +72,12 @@ | |||
493 | 72 | deprecated in favour of ``known_hooks.key_to_parent_and_attribute`` in | 72 | deprecated in favour of ``known_hooks.key_to_parent_and_attribute`` in |
494 | 73 | the same module. (Andrew Bennetts) | 73 | the same module. (Andrew Bennetts) |
495 | 74 | 74 | ||
496 | 75 | * The ``action`` parameter to ``MutableTree.smart_add`` is no longer | ||
497 | 76 | supported and the AddAction classes have been removed. Instead, | ||
498 | 77 | file ids can be generated by passing a ``file_id_callback``, and output | ||
499 | 78 | can be shown through the ``report_callback``. | ||
500 | 79 | (Martin Pool) | ||
501 | 80 | |||
502 | 75 | Internals | 81 | Internals |
503 | 76 | ********* | 82 | ********* |
504 | 77 | 83 |
At the moment bzr-svn implements its own smart_add, which is a shame because I don't think there's anything very svn-specific in it. It ignores the 'action' parameter. This won't fix that but it might get closer to using a common implementation.