Merge lp:~mbp/bzr/deprecation into lp:bzr

Proposed by Martin Pool
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
Reviewer Review Type Date Requested Status
bzr-core Pending
Review via email: mp+38647@code.launchpad.net

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.

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

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.

Revision history for this message
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

Revision history for this message
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_suggestion() callback on Tree seems a bit odd to me, mostly because of its signature. I wonder if it really makes sense as a public method on Tree (which already has a fair amount of methods) rather than as a helper method on cmd_add.

Revision history for this message
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

Revision history for this message
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_suggestion() callback on Tree seems a bit odd to me, mostly because of its signature. I wonder if it really makes sense as a public method on Tree (which already has a fair amount of methods) rather than as a helper method on cmd_add.

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

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== removed file 'bzrlib/add.py'
--- bzrlib/add.py 2010-06-23 08:19:28 +0000
+++ bzrlib/add.py 1970-01-01 00:00:00 +0000
@@ -1,95 +0,0 @@
1# Copyright (C) 2005-2010 Canonical Ltd
2#
3# This program is free software; you can redistribute it and/or modify
4# it under the terms of the GNU General Public License as published by
5# the Free Software Foundation; either version 2 of the License, or
6# (at your option) any later version.
7#
8# This program is distributed in the hope that it will be useful,
9# but WITHOUT ANY WARRANTY; without even the implied warranty of
10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11# GNU General Public License for more details.
12#
13# You should have received a copy of the GNU General Public License
14# along with this program; if not, write to the Free Software
15# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
17"""Helper functions for adding files to working trees."""
18
19import sys
20
21import bzrlib.osutils
22
23
24class AddAction(object):
25 """A class which defines what action to take when adding a file."""
26
27 def __init__(self, to_file=None, should_print=None):
28 """Initialize an action which prints added files to an output stream.
29
30 :param to_file: The stream to write into. This is expected to take
31 Unicode paths. If not supplied, it will default to ``sys.stdout``.
32 :param should_print: If False, printing will be suppressed.
33 """
34 self._to_file = to_file
35 if to_file is None:
36 self._to_file = sys.stdout
37 self.should_print = False
38 if should_print is not None:
39 self.should_print = should_print
40
41 def __call__(self, inv, parent_ie, path, kind, _quote=bzrlib.osutils.quotefn):
42 """Add path to inventory.
43
44 The default action does nothing.
45
46 :param inv: The inventory we are working with.
47 :param path: The FastPath being added
48 :param kind: The kind of the object being added.
49 """
50 if self.should_print:
51 self._to_file.write('adding %s\n' % _quote(path.raw_path))
52 return None
53
54
55class AddFromBaseAction(AddAction):
56 """This class will try to extract file ids from another tree."""
57
58 def __init__(self, base_tree, base_path, to_file=None, should_print=None):
59 super(AddFromBaseAction, self).__init__(to_file=to_file,
60 should_print=should_print)
61 self.base_tree = base_tree
62 self.base_path = base_path
63
64 def __call__(self, inv, parent_ie, path, kind):
65 # Place the parent call
66 # Now check to see if we can extract an id for this file
67 file_id, base_path = self._get_base_file_id(path, parent_ie)
68 if file_id is not None:
69 if self.should_print:
70 self._to_file.write('adding %s w/ file id from %s\n'
71 % (path.raw_path, base_path))
72 else:
73 # we aren't doing anything special, so let the default
74 # reporter happen
75 file_id = super(AddFromBaseAction, self).__call__(
76 inv, parent_ie, path, kind)
77 return file_id
78
79 def _get_base_file_id(self, path, parent_ie):
80 """Look for a file id in the base branch.
81
82 First, if the base tree has the parent directory,
83 we look for a file with the same name in that directory.
84 Else, we look for an entry in the base tree with the same path.
85 """
86
87 if (parent_ie.file_id in self.base_tree):
88 base_parent_ie = self.base_tree.inventory[parent_ie.file_id]
89 base_child_ie = base_parent_ie.children.get(path.base_path)
90 if base_child_ie is not None:
91 return (base_child_ie.file_id,
92 self.base_tree.id2path(base_child_ie.file_id))
93 full_base_path = bzrlib.osutils.pathjoin(self.base_path, path.raw_path)
94 # This may return None, but it is our last attempt
95 return self.base_tree.path2id(full_base_path), full_base_path
960
=== modified file 'bzrlib/builtins.py'
--- bzrlib/builtins.py 2010-10-15 11:30:54 +0000
+++ bzrlib/builtins.py 2010-10-17 10:21:09 +0000
@@ -627,9 +627,7 @@
627627
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,
629 file_ids_from=None):629 file_ids_from=None):
630 import bzrlib.add630 file_id_callback = report_callback = None
631
632 base_tree = None
633 if file_ids_from is not None:631 if file_ids_from is not None:
634 try:632 try:
635 base_tree, base_path = WorkingTree.open_containing(633 base_tree, base_path = WorkingTree.open_containing(
@@ -638,18 +636,23 @@
638 base_branch, base_path = Branch.open_containing(636 base_branch, base_path = Branch.open_containing(
639 file_ids_from)637 file_ids_from)
640 base_tree = base_branch.basis_tree()638 base_tree = base_branch.basis_tree()
641
642 action = bzrlib.add.AddFromBaseAction(base_tree, base_path,
643 to_file=self.outf, should_print=(not is_quiet()))
644 else:
645 action = bzrlib.add.AddAction(to_file=self.outf,
646 should_print=(not is_quiet()))
647
648 if base_tree:
649 self.add_cleanup(base_tree.lock_read().unlock)639 self.add_cleanup(base_tree.lock_read().unlock)
640 if is_quiet():
641 to_file = None
642 else:
643 to_file = self.outf
644 file_id_callback = base_tree.file_id_suggestion(
645 base_path, to_file)
646 elif not is_quiet():
647 def report_callback(ie, path):
648 self.outf.write("adding " + path + "\n")
650 tree, file_list = tree_files_for_add(file_list)649 tree, file_list = tree_files_for_add(file_list)
651 added, ignored = tree.smart_add(file_list, not650 added, ignored = tree.smart_add(
652 no_recurse, action=action, save=not dry_run)651 file_list,
652 recurse=(not no_recurse),
653 file_id_callback=file_id_callback,
654 save=not dry_run,
655 report_callback=report_callback)
653 self.cleanup_now()656 self.cleanup_now()
654 if len(ignored) > 0:657 if len(ignored) > 0:
655 if verbose:658 if verbose:
656659
=== modified file 'bzrlib/mutabletree.py'
--- bzrlib/mutabletree.py 2010-08-17 06:45:33 +0000
+++ bzrlib/mutabletree.py 2010-10-17 10:21:09 +0000
@@ -30,9 +30,9 @@
30 bzrdir,30 bzrdir,
31 errors,31 errors,
32 hooks,32 hooks,
33 inventory,
33 osutils,34 osutils,
34 revisiontree,35 revisiontree,
35 inventory,
36 symbol_versioning,36 symbol_versioning,
37 trace,37 trace,
38 tree,38 tree,
@@ -370,7 +370,13 @@
370 raise NotImplementedError(self.set_parent_trees)370 raise NotImplementedError(self.set_parent_trees)
371371
372 @needs_tree_write_lock372 @needs_tree_write_lock
373 def smart_add(self, file_list, recurse=True, action=None, save=True):373 def smart_add(self,
374 file_list,
375 recurse=True,
376 action=None,
377 save=True,
378 file_id_callback=None,
379 report_callback=None):
374 """Version file_list, optionally recursing into directories.380 """Version file_list, optionally recursing into directories.
375381
376 This is designed more towards DWIM for humans than API clarity.382 This is designed more towards DWIM for humans than API clarity.
@@ -386,15 +392,22 @@
386 :param save: Save the inventory after completing the adds. If False392 :param save: Save the inventory after completing the adds. If False
387 this provides dry-run functionality by doing the add and not saving393 this provides dry-run functionality by doing the add and not saving
388 the inventory.394 the inventory.
395 :param file_id_callback: Optional,
396 file_id_callback(parent_ie, path, kind) => file_id.
397 :param report_callback: Optional, called after each file is added
398 with (ie, path); result ignored.
389 :return: A tuple - files_added, ignored_files. files_added is the count399 :return: A tuple - files_added, ignored_files. files_added is the count
390 of added files, and ignored_files is a dict mapping files that were400 of added files, and ignored_files is a dict mapping files that were
391 ignored to the rule that caused them to be ignored.401 ignored to the rule that caused them to be ignored.
392 """402 """
393 # not in an inner loop; and we want to remove direct use of this,403 if action is not None:
394 # so here as a reminder for now. RBC 20070703404 raise ValueError(
395 from bzrlib.inventory import InventoryEntry405 "passing action to smart_add is no longer supported in bzr 2.3")
396 if action is None:406 elif file_id_callback is None:
397 action = add.AddAction()407 file_id_callback = lambda *a: None
408
409 if report_callback is None:
410 report_callback = lambda *a: None
398411
399 if not file_list:412 if not file_list:
400 # no paths supplied: add the entire tree.413 # no paths supplied: add the entire tree.
@@ -437,7 +450,7 @@
437 # schedule the dir for scanning450 # schedule the dir for scanning
438 user_dirs.add(rf)451 user_dirs.add(rf)
439 else:452 else:
440 if not InventoryEntry.versionable_kind(kind):453 if not inventory.InventoryEntry.versionable_kind(kind):
441 raise errors.BadFileKindError(filename=abspath, kind=kind)454 raise errors.BadFileKindError(filename=abspath, kind=kind)
442 # ensure the named path is added, so that ignore rules in the later455 # ensure the named path is added, so that ignore rules in the later
443 # directory walk dont skip it.456 # directory walk dont skip it.
@@ -446,7 +459,8 @@
446 versioned = inv.has_filename(rf.raw_path)459 versioned = inv.has_filename(rf.raw_path)
447 if versioned:460 if versioned:
448 continue461 continue
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,
463 file_id_callback, report_callback))
450464
451 if not recurse:465 if not recurse:
452 # no need to walk any directories at all.466 # no need to walk any directories at all.
@@ -478,7 +492,7 @@
478 # find the kind of the path being added.492 # find the kind of the path being added.
479 kind = osutils.file_kind(abspath)493 kind = osutils.file_kind(abspath)
480494
481 if not InventoryEntry.versionable_kind(kind):495 if not inventory.InventoryEntry.versionable_kind(kind):
482 trace.warning("skipping %s (can't add file of kind '%s')",496 trace.warning("skipping %s (can't add file of kind '%s')",
483 abspath, kind)497 abspath, kind)
484 continue498 continue
@@ -529,7 +543,8 @@
529 # 20070306543 # 20070306
530 trace.mutter("%r is a nested bzr tree", abspath)544 trace.mutter("%r is a nested bzr tree", abspath)
531 else:545 else:
532 _add_one(self, inv, parent_ie, directory, kind, action)546 _add_one(self, inv, parent_ie, directory, kind,
547 file_id_callback, report_callback)
533 added.append(directory.raw_path)548 added.append(directory.raw_path)
534549
535 if kind == 'directory' and not sub_tree:550 if kind == 'directory' and not sub_tree:
@@ -681,7 +696,8 @@
681 return hash(self.raw_path)696 return hash(self.raw_path)
682697
683698
684def _add_one_and_parent(tree, inv, parent_ie, path, kind, action):699def _add_one_and_parent(tree, inv, parent_ie, path, kind, file_id_callback,
700 report_callback):
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.
686702
687 :param inv: Inventory which will receive the new entry.703 :param inv: Inventory which will receive the new entry.
@@ -689,7 +705,8 @@
689 None, the parent is looked up by name and used if present, otherwise it705 None, the parent is looked up by name and used if present, otherwise it
690 is recursively added.706 is recursively added.
691 :param kind: Kind of new entry (file, directory, etc)707 :param kind: Kind of new entry (file, directory, etc)
692 :param action: callback(inv, parent_ie, path, kind); return ignored.708 :param file_id_callback: callback(inv, parent_ie, path, kind); return a
709 file_id or None to generate a new file id
693 :return: A list of paths which have been added.710 :return: A list of paths which have been added.
694 """711 """
695 # Nothing to do if path is already versioned.712 # Nothing to do if path is already versioned.
@@ -707,20 +724,24 @@
707 # there are a limited number of dirs we can be nested under, it should724 # there are a limited number of dirs we can be nested under, it should
708 # generally find it very fast and not recurse after that.725 # generally find it very fast and not recurse after that.
709 added = _add_one_and_parent(tree, inv, None,726 added = _add_one_and_parent(tree, inv, None,
710 _FastPath(osutils.dirname(path.raw_path)), 'directory', action)727 _FastPath(osutils.dirname(path.raw_path)), 'directory',
728 file_id_callback,
729 report_callback)
711 parent_id = inv.path2id(osutils.dirname(path.raw_path))730 parent_id = inv.path2id(osutils.dirname(path.raw_path))
712 parent_ie = inv[parent_id]731 parent_ie = inv[parent_id]
713 _add_one(tree, inv, parent_ie, path, kind, action)732 _add_one(tree, inv, parent_ie, path, kind, file_id_callback,
733 report_callback)
714 return added + [path.raw_path]734 return added + [path.raw_path]
715735
716736
717def _add_one(tree, inv, parent_ie, path, kind, file_id_callback):737def _add_one(tree, inv, parent_ie, path, kind, file_id_callback,
738 report_callback):
718 """Add a new entry to the inventory.739 """Add a new entry to the inventory.
719740
720 :param inv: Inventory which will receive the new entry.741 :param inv: Inventory which will receive the new entry.
721 :param parent_ie: Parent inventory entry.742 :param parent_ie: Parent inventory entry.
722 :param kind: Kind of new entry (file, directory, etc)743 :param kind: Kind of new entry (file, directory, etc)
723 :param file_id_callback: callback(inv, parent_ie, path, kind); return a744 :param file_id_callback: callback(parent_ie, path, kind); return a
724 file_id or None to generate a new file id745 file_id or None to generate a new file id
725 :returns: None746 :returns: None
726 """747 """
@@ -735,7 +756,8 @@
735 del inv[parent_ie.file_id]756 del inv[parent_ie.file_id]
736 inv.add(new_parent_ie)757 inv.add(new_parent_ie)
737 parent_ie = new_parent_ie758 parent_ie = new_parent_ie
738 file_id = file_id_callback(inv, parent_ie, path, kind)759 file_id = file_id_callback(parent_ie, path, kind)
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,
740 file_id=file_id)761 file_id=file_id)
741 inv.add(entry)762 inv.add(entry)
763 report_callback(entry, path.raw_path)
742764
=== modified file 'bzrlib/tests/per_workingtree/test_smart_add.py'
--- bzrlib/tests/per_workingtree/test_smart_add.py 2010-02-23 07:43:11 +0000
+++ bzrlib/tests/per_workingtree/test_smart_add.py 2010-10-17 10:21:09 +0000
@@ -20,7 +20,6 @@
20import sys20import sys
2121
22from bzrlib import (22from bzrlib import (
23 add,
24 errors,23 errors,
25 ignores,24 ignores,
26 osutils,25 osutils,
@@ -28,12 +27,16 @@
28 workingtree,27 workingtree,
29 )28 )
30from bzrlib.tests import (29from bzrlib.tests import (
31 features,
32 test_smart_add,
33 per_workingtree,30 per_workingtree,
34 )31 )
3532
3633
34def _make_custom_file_id(parent_ie, path, kind):
35 return osutils.safe_file_id(kind + '-'
36 + path.raw_path.replace('/', '%'),
37 warn=False)
38
39
37class TestSmartAddTree(per_workingtree.TestCaseWithWorkingTree):40class TestSmartAddTree(per_workingtree.TestCaseWithWorkingTree):
3841
39 def test_single_file(self):42 def test_single_file(self):
@@ -203,20 +206,9 @@
203 [path for path, ie in tree.iter_entries_by_dir()])206 [path for path, ie in tree.iter_entries_by_dir()])
204207
205 def test_custom_ids(self):208 def test_custom_ids(self):
206 sio = StringIO()209 wt = self.make_branch_and_tree('.')
207 action = test_smart_add.AddCustomIDAction(to_file=sio,
208 should_print=True)
209 self.build_tree(['file1', 'dir1/', 'dir1/file2'])210 self.build_tree(['file1', 'dir1/', 'dir1/file2'])
210211 wt.smart_add(['.'], file_id_callback=_make_custom_file_id)
211 wt = self.make_branch_and_tree('.')
212 wt.smart_add(['.'], action=action)
213 # The order of adds is not strictly fixed:
214 sio.seek(0)
215 lines = sorted(sio.readlines())
216 self.assertEqualDiff(['added dir1 with id directory-dir1\n',
217 'added dir1/file2 with id file-dir1%file2\n',
218 'added file1 with id file-file1\n',
219 ], lines)
220 wt.lock_read()212 wt.lock_read()
221 self.addCleanup(wt.unlock)213 self.addCleanup(wt.unlock)
222 self.assertEqual([('', wt.path2id('')),214 self.assertEqual([('', wt.path2id('')),
223215
=== modified file 'bzrlib/tests/test_smart_add.py'
--- bzrlib/tests/test_smart_add.py 2010-02-10 17:52:08 +0000
+++ bzrlib/tests/test_smart_add.py 2010-10-17 10:21:09 +0000
@@ -18,26 +18,10 @@
1818
19from bzrlib import (19from bzrlib import (
20 add,20 add,
21 inventory,
22 osutils,
23 tests,21 tests,
24 )22 )
2523
2624
27class AddCustomIDAction(add.AddAction):
28
29 def __call__(self, inv, parent_ie, path, kind):
30 # The first part just logs if appropriate
31 # Now generate a custom id
32 file_id = osutils.safe_file_id(kind + '-'
33 + path.raw_path.replace('/', '%'),
34 warn=False)
35 if self.should_print:
36 self._to_file.write('added %s with id %s\n'
37 % (path.raw_path, file_id))
38 return file_id
39
40
41class TestAddFrom(tests.TestCaseWithTransport):25class TestAddFrom(tests.TestCaseWithTransport):
42 """Tests for AddFromBaseAction"""26 """Tests for AddFromBaseAction"""
4327
@@ -62,7 +46,8 @@
62 action = add.AddFromBaseAction(base_tree, base_path,46 action = add.AddFromBaseAction(base_tree, base_path,
63 to_file=to_file,47 to_file=to_file,
64 should_print=should_print)48 should_print=should_print)
65 new_tree.smart_add(file_list, action=action)49 new_tree.smart_add(
50 file_list, file_id_callback=action.generate_file_id)
66 finally:51 finally:
67 new_tree.unlock()52 new_tree.unlock()
68 finally:53 finally:
@@ -141,22 +126,3 @@
141 self.base_tree.lock_read()126 self.base_tree.lock_read()
142 self.addCleanup(self.base_tree.unlock)127 self.addCleanup(self.base_tree.unlock)
143 self.failIf(a_id in self.base_tree)128 self.failIf(a_id in self.base_tree)
144
145
146class TestAddActions(tests.TestCase):
147
148 def test_quiet(self):
149 self.run_action("")
150
151 def test__print(self):
152 self.run_action("adding path\n")
153
154 def run_action(self, output):
155 from bzrlib.mutabletree import _FastPath
156 inv = inventory.Inventory()
157 stdout = StringIO()
158 action = add.AddAction(to_file=stdout, should_print=bool(output))
159
160 self.apply_redirected(None, stdout, None, action, inv, None,
161 _FastPath('path'), 'file')
162 self.assertEqual(stdout.getvalue(), output)
163129
=== modified file 'bzrlib/tree.py'
--- bzrlib/tree.py 2010-08-31 07:12:18 +0000
+++ bzrlib/tree.py 2010-10-17 10:21:09 +0000
@@ -37,7 +37,10 @@
37from bzrlib.inter import InterObject37from bzrlib.inter import InterObject
38from bzrlib.osutils import fingerprint_file38from bzrlib.osutils import fingerprint_file
39from bzrlib.symbol_versioning import deprecated_function, deprecated_in39from bzrlib.symbol_versioning import deprecated_function, deprecated_in
40from bzrlib.trace import note40from bzrlib.trace import (
41 mutter,
42 note,
43 )
4144
4245
43class Tree(object):46class Tree(object):
@@ -588,6 +591,49 @@
588 """591 """
589 pass592 pass
590593
594 def file_id_suggestion(self, under_dir, print_to_file):
595 """Return a callback to use with smart_add file_id_callback.
596
597 The returned callable tries to guess a file id for a newly added
598 file in a mutable tree, based on finding one at the same path in
599 this tree.
600
601 First, if this tree has the same parent directory id,
602 we look for a file with the same name in that directory.
603 Otherwise, we look for an entry in this tree with the same path.
604
605 :param under_path: Look for file ids under the given directory.
606 :param print_to_file: If non-None, write a message about matched
607 files to this stream.
608 """
609 def find_one(parent_ie, path, kind):
610 # mutter("look up suggestion for %r in parent %r"
611 # % (path.raw_path, parent_ie))
612 file_id = None
613 if parent_ie.file_id in self:
614 # mutter("found parent in %r" % self)
615 base_parent_ie = self.inventory[parent_ie.file_id]
616 # mutter(" looking for child %r" % path.base_path)
617 base_child_ie = base_parent_ie.children.get(path.base_path)
618 if base_child_ie is not None:
619 # mutter(" found child under it")
620 file_id = base_child_ie.file_id
621 origin_path = self.id2path(base_child_ie.file_id)
622 if file_id is None:
623 # Not found yet: try looking for the whole path.
624 origin_path = osutils.pathjoin(under_dir, path.raw_path)
625 file_id = self.path2id(origin_path)
626 if print_to_file is None:
627 pass
628 elif file_id is not None:
629 print_to_file.write(
630 'adding %s w/ file id from %s\n'
631 % (path.raw_path, origin_path))
632 else:
633 print_to_file.write('adding %s\n' % path.raw_path)
634 return file_id
635 return find_one
636
591 def revision_tree(self, revision_id):637 def revision_tree(self, revision_id):
592 """Obtain a revision tree for the revision revision_id.638 """Obtain a revision tree for the revision revision_id.
593639
594640
=== modified file 'doc/en/release-notes/bzr-2.3.txt'
--- doc/en/release-notes/bzr-2.3.txt 2010-10-15 15:05:09 +0000
+++ doc/en/release-notes/bzr-2.3.txt 2010-10-17 10:21:09 +0000
@@ -72,6 +72,12 @@
72 deprecated in favour of ``known_hooks.key_to_parent_and_attribute`` in72 deprecated in favour of ``known_hooks.key_to_parent_and_attribute`` in
73 the same module. (Andrew Bennetts)73 the same module. (Andrew Bennetts)
7474
75* The ``action`` parameter to ``MutableTree.smart_add`` is no longer
76 supported and the AddAction classes have been removed. Instead,
77 file ids can be generated by passing a ``file_id_callback``, and output
78 can be shown through the ``report_callback``.
79 (Martin Pool)
80
75Internals81Internals
76*********82*********
7783