Rev 5952: (jelmer) (jelmer) Bug #146165, in file:///home/pqm/archives/thelove/bzr/%2Btrunk/
Canonical.com Patch Queue Manager
pqm at pqm.ubuntu.com
Wed Jun 1 14:59:20 UTC 2011
At file:///home/pqm/archives/thelove/bzr/%2Btrunk/
------------------------------------------------------------
revno: 5952 [merge]
revision-id: pqm at pqm.ubuntu.com-20110601145916-5uuwhu9e764po62d
parent: pqm at pqm.ubuntu.com-20110601123104-ldhru7h1z82ee5xv
parent: jelmer at samba.org-20110601134312-nor5sp8eeassrzeo
committer: Canonical.com Patch Queue Manager <pqm at pqm.ubuntu.com>
branch nick: +trunk
timestamp: Wed 2011-06-01 14:59:16 +0000
message:
(jelmer) (jelmer) Bug #146165,
use apply_inventory_delta instead of _write_inventory for 'bzr add'" (Jelmer
Vernooij)
modified:
bzrlib/add.py add.py-20050323030017-3a77d63feda58e33
bzrlib/mutabletree.py mutabletree.py-20060906023413-4wlkalbdpsxi2r4y-2
bzrlib/tests/test_smart_add.py test_smart_add.py-20050824235919-c60dcdb0c8e999ce
doc/en/release-notes/bzr-2.4.txt bzr2.4.txt-20110114053217-k7ym9jfz243fddjm-1
=== modified file 'bzrlib/add.py'
--- a/bzrlib/add.py 2010-06-23 08:19:28 +0000
+++ b/bzrlib/add.py 2011-05-23 12:30:49 +0000
@@ -18,7 +18,9 @@
import sys
-import bzrlib.osutils
+from bzrlib import (
+ osutils,
+ )
class AddAction(object):
@@ -38,7 +40,7 @@
if should_print is not None:
self.should_print = should_print
- def __call__(self, inv, parent_ie, path, kind, _quote=bzrlib.osutils.quotefn):
+ def __call__(self, inv, parent_ie, path, kind, _quote=osutils.quotefn):
"""Add path to inventory.
The default action does nothing.
@@ -48,7 +50,7 @@
:param kind: The kind of the object being added.
"""
if self.should_print:
- self._to_file.write('adding %s\n' % _quote(path.raw_path))
+ self._to_file.write('adding %s\n' % _quote(path))
return None
@@ -68,7 +70,7 @@
if file_id is not None:
if self.should_print:
self._to_file.write('adding %s w/ file id from %s\n'
- % (path.raw_path, base_path))
+ % (path, base_path))
else:
# we aren't doing anything special, so let the default
# reporter happen
@@ -86,10 +88,11 @@
if (parent_ie.file_id in self.base_tree):
base_parent_ie = self.base_tree.inventory[parent_ie.file_id]
- base_child_ie = base_parent_ie.children.get(path.base_path)
+ base_child_ie = base_parent_ie.children.get(
+ osutils.basename(path))
if base_child_ie is not None:
return (base_child_ie.file_id,
self.base_tree.id2path(base_child_ie.file_id))
- full_base_path = bzrlib.osutils.pathjoin(self.base_path, path.raw_path)
+ full_base_path = osutils.pathjoin(self.base_path, path)
# This may return None, but it is our last attempt
return self.base_tree.path2id(full_base_path), full_base_path
=== modified file 'bzrlib/mutabletree.py'
--- a/bzrlib/mutabletree.py 2011-05-18 16:42:48 +0000
+++ b/bzrlib/mutabletree.py 2011-05-20 15:27:35 +0000
@@ -22,18 +22,20 @@
from bzrlib.lazy_import import lazy_import
lazy_import(globals(), """
+import operator
import os
import re
from bzrlib import (
add,
- bzrdir,
+ controldir,
errors,
hooks,
inventory as _mod_inventory,
osutils,
revisiontree,
trace,
+ transport as _mod_transport,
tree,
)
""")
@@ -392,32 +394,8 @@
"""
raise NotImplementedError(self.smart_add)
- def update_basis_by_delta(self, new_revid, delta):
- """Update the parents of this tree after a commit.
-
- This gives the tree one parent, with revision id new_revid. The
- inventory delta is applied to the current basis tree to generate the
- inventory for the parent new_revid, and all other parent trees are
- discarded.
-
- All the changes in the delta should be changes synchronising the basis
- tree with some or all of the working tree, with a change to a directory
- requiring that its contents have been recursively included. That is,
- this is not a general purpose tree modification routine, but a helper
- for commit which is not required to handle situations that do not arise
- outside of commit.
-
- See the inventory developers documentation for the theory behind
- inventory deltas.
-
- :param new_revid: The new revision id for the trees parent.
- :param delta: An inventory delta (see apply_inventory_delta) describing
- the changes from the current left most parent revision to new_revid.
- """
- raise NotImplementedError(self.update_basis_by_delta)
-
-
-class MutableInventoryTree(MutableTree,tree.InventoryTree):
+
+class MutableInventoryTree(MutableTree, tree.InventoryTree):
@needs_tree_write_lock
def apply_inventory_delta(self, changes):
@@ -460,31 +438,216 @@
of added files, and ignored_files is a dict mapping files that were
ignored to the rule that caused them to be ignored.
"""
- # not in an inner loop; and we want to remove direct use of this,
- # so here as a reminder for now. RBC 20070703
- from bzrlib.inventory import InventoryEntry
- if action is None:
- action = add.AddAction()
-
- if not file_list:
- # no paths supplied: add the entire tree.
- # FIXME: this assumes we are running in a working tree subdir :-/
- # -- vila 20100208
- file_list = [u'.']
- # mutter("smart add of %r")
- inv = self.inventory
- added = []
- ignored = {}
- dirs_to_add = []
- user_dirs = set()
- conflicts_related = set()
# Not all mutable trees can have conflicts
if getattr(self, 'conflicts', None) is not None:
# Collect all related files without checking whether they exist or
# are versioned. It's cheaper to do that once for all conflicts
# than trying to find the relevant conflict for each added file.
+ conflicts_related = set()
for c in self.conflicts():
conflicts_related.update(c.associated_filenames())
+ else:
+ conflicts_related = None
+ adder = _SmartAddHelper(self, action, conflicts_related)
+ adder.add(file_list, recurse=recurse)
+ if save:
+ invdelta = adder.get_inventory_delta()
+ self.apply_inventory_delta(invdelta)
+ return adder.added, adder.ignored
+
+ def update_basis_by_delta(self, new_revid, delta):
+ """Update the parents of this tree after a commit.
+
+ This gives the tree one parent, with revision id new_revid. The
+ inventory delta is applied to the current basis tree to generate the
+ inventory for the parent new_revid, and all other parent trees are
+ discarded.
+
+ All the changes in the delta should be changes synchronising the basis
+ tree with some or all of the working tree, with a change to a directory
+ requiring that its contents have been recursively included. That is,
+ this is not a general purpose tree modification routine, but a helper
+ for commit which is not required to handle situations that do not arise
+ outside of commit.
+
+ See the inventory developers documentation for the theory behind
+ inventory deltas.
+
+ :param new_revid: The new revision id for the trees parent.
+ :param delta: An inventory delta (see apply_inventory_delta) describing
+ the changes from the current left most parent revision to new_revid.
+ """
+ # if the tree is updated by a pull to the branch, as happens in
+ # WorkingTree2, when there was no separation between branch and tree,
+ # then just clear merges, efficiency is not a concern for now as this
+ # is legacy environments only, and they are slow regardless.
+ if self.last_revision() == new_revid:
+ self.set_parent_ids([new_revid])
+ return
+ # generic implementation based on Inventory manipulation. See
+ # WorkingTree classes for optimised versions for specific format trees.
+ basis = self.basis_tree()
+ basis.lock_read()
+ # TODO: Consider re-evaluating the need for this with CHKInventory
+ # we don't strictly need to mutate an inventory for this
+ # it only makes sense when apply_delta is cheaper than get_inventory()
+ inventory = _mod_inventory.mutable_inventory_from_tree(basis)
+ basis.unlock()
+ inventory.apply_delta(delta)
+ rev_tree = revisiontree.InventoryRevisionTree(self.branch.repository,
+ inventory, new_revid)
+ self.set_parent_trees([(new_revid, rev_tree)])
+
+
+class MutableTreeHooks(hooks.Hooks):
+ """A dictionary mapping a hook name to a list of callables for mutabletree
+ hooks.
+ """
+
+ def __init__(self):
+ """Create the default hooks.
+
+ """
+ hooks.Hooks.__init__(self, "bzrlib.mutabletree", "MutableTree.hooks")
+ self.add_hook('start_commit',
+ "Called before a commit is performed on a tree. The start commit "
+ "hook is able to change the tree before the commit takes place. "
+ "start_commit is called with the bzrlib.mutabletree.MutableTree "
+ "that the commit is being performed on.", (1, 4))
+ self.add_hook('post_commit',
+ "Called after a commit is performed on a tree. The hook is "
+ "called with a bzrlib.mutabletree.PostCommitHookParams object. "
+ "The mutable tree the commit was performed on is available via "
+ "the mutable_tree attribute of that object.", (2, 0))
+
+
+# install the default hooks into the MutableTree class.
+MutableTree.hooks = MutableTreeHooks()
+
+
+class PostCommitHookParams(object):
+ """Parameters for the post_commit hook.
+
+ To access the parameters, use the following attributes:
+
+ * mutable_tree - the MutableTree object
+ """
+
+ def __init__(self, mutable_tree):
+ """Create the parameters for the post_commit hook."""
+ self.mutable_tree = mutable_tree
+
+
+class _SmartAddHelper(object):
+ """Helper for MutableTree.smart_add."""
+
+ def get_inventory_delta(self):
+ return self._invdelta.values()
+
+ def _get_ie(self, inv_path):
+ """Retrieve the most up to date inventory entry for a path.
+
+ :param inv_path: Normalized inventory path
+ :return: Inventory entry (with possibly invalid .children for
+ directories)
+ """
+ entry = self._invdelta.get(inv_path)
+ if entry is not None:
+ return entry[3]
+ file_id = self.tree.path2id(inv_path)
+ if file_id is not None:
+ return self.tree.iter_entries_by_dir([file_id]).next()[1]
+ return None
+
+ def _convert_to_directory(self, this_ie, inv_path):
+ """Convert an entry to a directory.
+
+ :param this_ie: Inventory entry
+ :param inv_path: Normalized path for the inventory entry
+ :return: The new inventory entry
+ """
+ # Same as in _add_one below, if the inventory doesn't
+ # think this is a directory, update the inventory
+ this_ie = _mod_inventory.InventoryDirectory(
+ this_ie.file_id, this_ie.name, this_ie.parent_id)
+ self._invdelta[inv_path] = (inv_path, inv_path, this_ie.file_id,
+ this_ie)
+ return this_ie
+
+ def _add_one_and_parent(self, parent_ie, path, kind, inv_path):
+ """Add a new entry to the inventory and automatically add unversioned parents.
+
+ :param parent_ie: Parent inventory entry if known, or None. If
+ None, the parent is looked up by name and used if present, otherwise it
+ is recursively added.
+ :param kind: Kind of new entry (file, directory, etc)
+ :param action: callback(tree, parent_ie, path, kind); can return file_id
+ :return: Inventory entry for path and a list of paths which have been added.
+ """
+ # Nothing to do if path is already versioned.
+ # This is safe from infinite recursion because the tree root is
+ # always versioned.
+ inv_dirname = osutils.dirname(inv_path)
+ dirname, basename = osutils.split(path)
+ if parent_ie is None:
+ # slower but does not need parent_ie
+ this_ie = self._get_ie(inv_path)
+ if this_ie is not None:
+ return this_ie
+ # its really not there : add the parent
+ # note that the dirname use leads to some extra str copying etc but as
+ # there are a limited number of dirs we can be nested under, it should
+ # generally find it very fast and not recurse after that.
+ parent_ie = self._add_one_and_parent(None,
+ dirname, 'directory',
+ inv_dirname)
+ # if the parent exists, but isn't a directory, we have to do the
+ # kind change now -- really the inventory shouldn't pretend to know
+ # the kind of wt files, but it does.
+ if parent_ie.kind != 'directory':
+ # nb: this relies on someone else checking that the path we're using
+ # doesn't contain symlinks.
+ parent_ie = self._convert_to_directory(parent_ie, inv_dirname)
+ file_id = self.action(self.tree.inventory, parent_ie, path, kind)
+ entry = _mod_inventory.make_entry(kind, basename, parent_ie.file_id,
+ file_id=file_id)
+ self._invdelta[inv_path] = (None, inv_path, entry.file_id, entry)
+ self.added.append(inv_path)
+ return entry
+
+ def _gather_dirs_to_add(self, user_dirs):
+ # only walk the minimal parents needed: we have user_dirs to override
+ # ignores.
+ prev_dir = None
+
+ is_inside = osutils.is_inside_or_parent_of_any
+ for path, (inv_path, this_ie) in sorted(
+ user_dirs.iteritems(), key=operator.itemgetter(0)):
+ if (prev_dir is None or not is_inside([prev_dir], path)):
+ yield (path, inv_path, this_ie, None)
+ prev_dir = path
+
+ def __init__(self, tree, action, conflicts_related=None):
+ self.tree = tree
+ if action is None:
+ self.action = add.AddAction()
+ else:
+ self.action = action
+ self._invdelta = {}
+ self.added = []
+ self.ignored = {}
+ if conflicts_related is None:
+ self.conflicts_related = frozenset()
+ else:
+ self.conflicts_related = conflicts_related
+
+ def add(self, file_list, recurse=True):
+ from bzrlib.inventory import InventoryEntry
+ if not file_list:
+ # no paths supplied: add the entire tree.
+ # FIXME: this assumes we are running in a working tree subdir :-/
+ # -- vila 20100208
+ file_list = [u'.']
# expand any symlinks in the directory part, while leaving the
# filename alone
@@ -492,72 +655,58 @@
if osutils.has_symlinks():
file_list = map(osutils.normalizepath, file_list)
+ user_dirs = {}
# validate user file paths and convert all paths to tree
# relative : it's cheaper to make a tree relative path an abspath
# than to convert an abspath to tree relative, and it's cheaper to
# perform the canonicalization in bulk.
- for filepath in osutils.canonical_relpaths(self.basedir, file_list):
- rf = _FastPath(filepath)
+ for filepath in osutils.canonical_relpaths(self.tree.basedir, file_list):
# validate user parameters. Our recursive code avoids adding new
# files that need such validation
- if self.is_control_filename(rf.raw_path):
- raise errors.ForbiddenControlFileError(filename=rf.raw_path)
+ if self.tree.is_control_filename(filepath):
+ raise errors.ForbiddenControlFileError(filename=filepath)
- abspath = self.abspath(rf.raw_path)
+ abspath = self.tree.abspath(filepath)
kind = osutils.file_kind(abspath)
- if kind == 'directory':
- # schedule the dir for scanning
- user_dirs.add(rf)
- else:
- if not InventoryEntry.versionable_kind(kind):
- raise errors.BadFileKindError(filename=abspath, kind=kind)
# ensure the named path is added, so that ignore rules in the later
# directory walk dont skip it.
# we dont have a parent ie known yet.: use the relatively slower
# inventory probing method
- versioned = inv.has_filename(rf.raw_path)
- if versioned:
- continue
- added.extend(_add_one_and_parent(self, inv, None, rf, kind, action))
+ inv_path, _ = osutils.normalized_filename(filepath)
+ this_ie = self._get_ie(inv_path)
+ if this_ie is None:
+ this_ie = self._add_one_and_parent(None, filepath, kind, inv_path)
+ if kind == 'directory':
+ # schedule the dir for scanning
+ user_dirs[filepath] = (inv_path, this_ie)
if not recurse:
# no need to walk any directories at all.
- if len(added) > 0 and save:
- self._write_inventory(inv)
- return added, ignored
-
- # only walk the minimal parents needed: we have user_dirs to override
- # ignores.
- prev_dir = None
-
- is_inside = osutils.is_inside_or_parent_of_any
- for path in sorted(user_dirs):
- if (prev_dir is None or not is_inside([prev_dir], path.raw_path)):
- dirs_to_add.append((path, None))
- prev_dir = path.raw_path
+ return
+
+ things_to_add = list(self._gather_dirs_to_add(user_dirs))
illegalpath_re = re.compile(r'[\r\n]')
- # dirs_to_add is initialised to a list of directories, but as we scan
- # directories we append files to it.
- # XXX: We should determine kind of files when we scan them rather than
- # adding to this list. RBC 20070703
- for directory, parent_ie in dirs_to_add:
+ for directory, inv_path, this_ie, parent_ie in things_to_add:
# directory is tree-relative
- abspath = self.abspath(directory.raw_path)
+ abspath = self.tree.abspath(directory)
# get the contents of this directory.
# find the kind of the path being added.
- kind = osutils.file_kind(abspath)
+ if this_ie is None:
+ kind = osutils.file_kind(abspath)
+ else:
+ kind = this_ie.kind
if not InventoryEntry.versionable_kind(kind):
trace.warning("skipping %s (can't add file of kind '%s')",
abspath, kind)
continue
- if illegalpath_re.search(directory.raw_path):
+ if illegalpath_re.search(directory):
trace.warning("skipping %r (contains \\n or \\r)" % abspath)
continue
- if directory.raw_path in conflicts_related:
+ if directory in self.conflicts_related:
# If the file looks like one generated for a conflict, don't
# add it.
trace.warning(
@@ -565,17 +714,10 @@
abspath)
continue
- if parent_ie is not None:
- versioned = directory.base_path in parent_ie.children
- else:
- # without the parent ie, use the relatively slower inventory
- # probing method
- versioned = inv.has_filename(
- self._fix_case_of_inventory_path(directory.raw_path))
-
- if kind == 'directory':
+ if kind == 'directory' and directory != '':
try:
- sub_branch = bzrdir.BzrDir.open(abspath)
+ transport = _mod_transport.get_transport(abspath)
+ controldir.ControlDirFormat.find_format(transport)
sub_tree = True
except errors.NotBranchError:
sub_tree = False
@@ -584,12 +726,8 @@
else:
sub_tree = False
- if directory.raw_path == '':
- # mutter("tree root doesn't need to be added")
- sub_tree = False
- elif versioned:
+ if this_ie is not None:
pass
- # mutter("%r is already versioned", abspath)
elif sub_tree:
# XXX: This is wrong; people *might* reasonably be trying to
# add subtrees as subtrees. This should probably only be done
@@ -601,220 +739,39 @@
# 20070306
trace.mutter("%r is a nested bzr tree", abspath)
else:
- _add_one(self, inv, parent_ie, directory, kind, action)
- added.append(directory.raw_path)
+ this_ie = self._add_one_and_parent(parent_ie, directory, kind, inv_path)
if kind == 'directory' and not sub_tree:
- if parent_ie is not None:
- # must be present:
- this_ie = parent_ie.children[directory.base_path]
- else:
- # without the parent ie, use the relatively slower inventory
- # probing method
- this_id = inv.path2id(
- self._fix_case_of_inventory_path(directory.raw_path))
- if this_id is None:
- this_ie = None
- else:
- this_ie = inv[this_id]
- # Same as in _add_one below, if the inventory doesn't
- # think this is a directory, update the inventory
- if this_ie.kind != 'directory':
- this_ie = _mod_inventory.make_entry('directory',
- this_ie.name, this_ie.parent_id, this_id)
- del inv[this_id]
- inv.add(this_ie)
+ if this_ie.kind != 'directory':
+ this_ie = self._convert_to_directory(this_ie, inv_path)
for subf in sorted(os.listdir(abspath)):
+ inv_f, _ = osutils.normalized_filename(subf)
# here we could use TreeDirectory rather than
# string concatenation.
- subp = osutils.pathjoin(directory.raw_path, subf)
+ subp = osutils.pathjoin(directory, subf)
# TODO: is_control_filename is very slow. Make it faster.
# TreeDirectory.is_control_filename could also make this
# faster - its impossible for a non root dir to have a
# control file.
- if self.is_control_filename(subp):
+ if self.tree.is_control_filename(subp):
trace.mutter("skip control directory %r", subp)
- elif subf in this_ie.children:
+ continue
+ sub_invp = osutils.pathjoin(inv_path, inv_f)
+ entry = self._invdelta.get(sub_invp)
+ if entry is not None:
+ sub_ie = entry[3]
+ else:
+ sub_ie = this_ie.children.get(inv_f)
+ if sub_ie is not None:
# recurse into this already versioned subdir.
- dirs_to_add.append((_FastPath(subp, subf), this_ie))
+ things_to_add.append((subp, sub_invp, sub_ie, this_ie))
else:
# user selection overrides ignoes
# ignore while selecting files - if we globbed in the
# outer loop we would ignore user files.
- ignore_glob = self.is_ignored(subp)
+ ignore_glob = self.tree.is_ignored(subp)
if ignore_glob is not None:
- # mutter("skip ignored sub-file %r", subp)
- ignored.setdefault(ignore_glob, []).append(subp)
+ self.ignored.setdefault(ignore_glob, []).append(subp)
else:
- #mutter("queue to add sub-file %r", subp)
- dirs_to_add.append((_FastPath(subp, subf), this_ie))
-
- if len(added) > 0:
- if save:
- self._write_inventory(inv)
- else:
- self.read_working_inventory()
- return added, ignored
-
- def update_basis_by_delta(self, new_revid, delta):
- """Update the parents of this tree after a commit.
-
- This gives the tree one parent, with revision id new_revid. The
- inventory delta is applied to the current basis tree to generate the
- inventory for the parent new_revid, and all other parent trees are
- discarded.
-
- All the changes in the delta should be changes synchronising the basis
- tree with some or all of the working tree, with a change to a directory
- requiring that its contents have been recursively included. That is,
- this is not a general purpose tree modification routine, but a helper
- for commit which is not required to handle situations that do not arise
- outside of commit.
-
- See the inventory developers documentation for the theory behind
- inventory deltas.
-
- :param new_revid: The new revision id for the trees parent.
- :param delta: An inventory delta (see apply_inventory_delta) describing
- the changes from the current left most parent revision to new_revid.
- """
- # if the tree is updated by a pull to the branch, as happens in
- # WorkingTree2, when there was no separation between branch and tree,
- # then just clear merges, efficiency is not a concern for now as this
- # is legacy environments only, and they are slow regardless.
- if self.last_revision() == new_revid:
- self.set_parent_ids([new_revid])
- return
- # generic implementation based on Inventory manipulation. See
- # WorkingTree classes for optimised versions for specific format trees.
- basis = self.basis_tree()
- basis.lock_read()
- # TODO: Consider re-evaluating the need for this with CHKInventory
- # we don't strictly need to mutate an inventory for this
- # it only makes sense when apply_delta is cheaper than get_inventory()
- inventory = _mod_inventory.mutable_inventory_from_tree(basis)
- basis.unlock()
- inventory.apply_delta(delta)
- rev_tree = revisiontree.InventoryRevisionTree(self.branch.repository,
- inventory, new_revid)
- self.set_parent_trees([(new_revid, rev_tree)])
-
-
-class MutableTreeHooks(hooks.Hooks):
- """A dictionary mapping a hook name to a list of callables for mutabletree
- hooks.
- """
-
- def __init__(self):
- """Create the default hooks.
-
- """
- hooks.Hooks.__init__(self, "bzrlib.mutabletree", "MutableTree.hooks")
- self.add_hook('start_commit',
- "Called before a commit is performed on a tree. The start commit "
- "hook is able to change the tree before the commit takes place. "
- "start_commit is called with the bzrlib.mutabletree.MutableTree "
- "that the commit is being performed on.", (1, 4))
- self.add_hook('post_commit',
- "Called after a commit is performed on a tree. The hook is "
- "called with a bzrlib.mutabletree.PostCommitHookParams object. "
- "The mutable tree the commit was performed on is available via "
- "the mutable_tree attribute of that object.", (2, 0))
-
-
-# install the default hooks into the MutableTree class.
-MutableTree.hooks = MutableTreeHooks()
-
-
-class PostCommitHookParams(object):
- """Parameters for the post_commit hook.
-
- To access the parameters, use the following attributes:
-
- * mutable_tree - the MutableTree object
- """
-
- def __init__(self, mutable_tree):
- """Create the parameters for the post_commit hook."""
- self.mutable_tree = mutable_tree
-
-
-class _FastPath(object):
- """A path object with fast accessors for things like basename."""
-
- __slots__ = ['raw_path', 'base_path']
-
- def __init__(self, path, base_path=None):
- """Construct a FastPath from path."""
- if base_path is None:
- self.base_path = osutils.basename(path)
- else:
- self.base_path = base_path
- self.raw_path = path
-
- def __cmp__(self, other):
- return cmp(self.raw_path, other.raw_path)
-
- def __hash__(self):
- return hash(self.raw_path)
-
-
-def _add_one_and_parent(tree, inv, parent_ie, path, kind, action):
- """Add a new entry to the inventory and automatically add unversioned parents.
-
- :param inv: Inventory which will receive the new entry.
- :param parent_ie: Parent inventory entry if known, or None. If
- None, the parent is looked up by name and used if present, otherwise it
- is recursively added.
- :param kind: Kind of new entry (file, directory, etc)
- :param action: callback(inv, parent_ie, path, kind); return ignored.
- :return: A list of paths which have been added.
- """
- # Nothing to do if path is already versioned.
- # This is safe from infinite recursion because the tree root is
- # always versioned.
- if parent_ie is not None:
- # we have a parent ie already
- added = []
- else:
- # slower but does not need parent_ie
- if inv.has_filename(tree._fix_case_of_inventory_path(path.raw_path)):
- return []
- # its really not there : add the parent
- # note that the dirname use leads to some extra str copying etc but as
- # there are a limited number of dirs we can be nested under, it should
- # generally find it very fast and not recurse after that.
- added = _add_one_and_parent(tree, inv, None,
- _FastPath(osutils.dirname(path.raw_path)), 'directory', action)
- parent_id = inv.path2id(osutils.dirname(path.raw_path))
- parent_ie = inv[parent_id]
- _add_one(tree, inv, parent_ie, path, kind, action)
- return added + [path.raw_path]
-
-
-def _add_one(tree, inv, parent_ie, path, kind, file_id_callback):
- """Add a new entry to the inventory.
-
- :param inv: Inventory which will receive the new entry.
- :param parent_ie: Parent inventory entry.
- :param kind: Kind of new entry (file, directory, etc)
- :param file_id_callback: callback(inv, parent_ie, path, kind); return a
- file_id or None to generate a new file id
- :returns: None
- """
- # if the parent exists, but isn't a directory, we have to do the
- # kind change now -- really the inventory shouldn't pretend to know
- # the kind of wt files, but it does.
- if parent_ie.kind != 'directory':
- # nb: this relies on someone else checking that the path we're using
- # doesn't contain symlinks.
- new_parent_ie = _mod_inventory.make_entry('directory', parent_ie.name,
- parent_ie.parent_id, parent_ie.file_id)
- del inv[parent_ie.file_id]
- inv.add(new_parent_ie)
- parent_ie = new_parent_ie
- file_id = file_id_callback(inv, parent_ie, path, kind)
- entry = inv.make_entry(kind, path.base_path, parent_ie.file_id,
- file_id=file_id)
- inv.add(entry)
+ things_to_add.append((subp, sub_invp, None, this_ie))
=== modified file 'bzrlib/tests/test_smart_add.py'
--- a/bzrlib/tests/test_smart_add.py 2011-05-13 12:51:05 +0000
+++ b/bzrlib/tests/test_smart_add.py 2011-05-20 12:16:57 +0000
@@ -30,11 +30,11 @@
# The first part just logs if appropriate
# Now generate a custom id
file_id = osutils.safe_file_id(kind + '-'
- + path.raw_path.replace('/', '%'),
+ + path.replace('/', '%'),
warn=False)
if self.should_print:
self._to_file.write('added %s with id %s\n'
- % (path.raw_path, file_id))
+ % (path, file_id))
return file_id
@@ -152,11 +152,10 @@
self.run_action("adding path\n")
def run_action(self, output):
- from bzrlib.mutabletree import _FastPath
inv = inventory.Inventory()
stdout = StringIO()
action = add.AddAction(to_file=stdout, should_print=bool(output))
self.apply_redirected(None, stdout, None, action, inv, None,
- _FastPath('path'), 'file')
+ 'path', 'file')
self.assertEqual(stdout.getvalue(), output)
=== modified file 'doc/en/release-notes/bzr-2.4.txt'
--- a/doc/en/release-notes/bzr-2.4.txt 2011-06-01 10:47:14 +0000
+++ b/doc/en/release-notes/bzr-2.4.txt 2011-06-01 13:43:12 +0000
@@ -286,6 +286,9 @@
.. Major internal changes, unlikely to be visible to users or plugin
developers, but interesting for bzr developers.
+* ``MutableTree.smart_add`` now uses inventory deltas.
+ (Jelmer Vernooij, #146165)
+
* Removed ``bzrlib.branch._run_with_write_locked_target`` as
``bzrlib.cleanup`` provides the same functionality in a more general
way. (Andrew Bennetts)
More information about the bazaar-commits
mailing list