bzr branch
http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
| 2255.2.158
by Martin Pool Most of the integration of dirstate and subtree | 1 | # Copyright (C) 2006, 2007 Canonical Ltd
 | 
| 1986.1.2
by Robert Collins Various changes to allow non-workingtree specific tests to run entirely | 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 | |
| 16 | ||
| 17 | """MutableTree object.
 | |
| 18 | ||
| 19 | See MutableTree for more details.
 | |
| 20 | """
 | |
| 21 | ||
| 22 | ||
| 2568.2.4
by Robert Collins * ``bzrlib.add.smart_add`` and ``bzrlib.add.smart_add_tree`` are now | 23 | from bzrlib.lazy_import import lazy_import | 
| 24 | lazy_import(globals(), """ | |
| 25 | import os
 | |
| 26 | ||
| 2568.2.6
by Robert Collins Review feedback. | 27 | from bzrlib import (
 | 
| 28 |     add,
 | |
| 29 |     bzrdir,
 | |
| 3335.1.2
by Jelmer Vernooij Add mutabletree hooks class and start_commit hook. | 30 |     hooks,
 | 
| 2568.2.6
by Robert Collins Review feedback. | 31 |     )
 | 
| 2568.2.4
by Robert Collins * ``bzrlib.add.smart_add`` and ``bzrlib.add.smart_add_tree`` are now | 32 | from bzrlib.osutils import dirname
 | 
| 2865.1.1
by Robert Collins Create new mutable tree method update_to_one_parent_via_delta for eventual use by commit. | 33 | from bzrlib.revisiontree import RevisionTree
 | 
| 2568.2.9
by Robert Collins Really honestly finally fix tests. | 34 | from bzrlib.trace import mutter, warning
 | 
| 2568.2.4
by Robert Collins * ``bzrlib.add.smart_add`` and ``bzrlib.add.smart_add_tree`` are now | 35 | """) | 
| 36 | ||
| 2100.3.27
by Aaron Bentley Enable nested commits | 37 | from bzrlib import ( | 
| 38 | errors, | |
| 2294.1.10
by John Arbash Meinel Switch all apis over to utf8 file ids. All tests pass | 39 | osutils, | 
| 2100.3.27
by Aaron Bentley Enable nested commits | 40 | tree, | 
| 41 |     )
 | |
| 1986.1.2
by Robert Collins Various changes to allow non-workingtree specific tests to run entirely | 42 | from bzrlib.decorators import needs_read_lock, needs_write_lock | 
| 43 | from bzrlib.osutils import splitpath | |
| 44 | from bzrlib.symbol_versioning import DEPRECATED_PARAMETER | |
| 45 | ||
| 46 | ||
| 1986.1.8
by Robert Collins Update to bzr.dev, which involves adding lock_tree_write to MutableTree and MemoryTree. | 47 | def needs_tree_write_lock(unbound): | 
| 48 | """Decorate unbound to take out and release a tree_write lock.""" | |
| 49 | def tree_write_locked(self, *args, **kwargs): | |
| 50 | self.lock_tree_write() | |
| 51 | try: | |
| 52 | return unbound(self, *args, **kwargs) | |
| 53 | finally: | |
| 54 | self.unlock() | |
| 55 | tree_write_locked.__doc__ = unbound.__doc__ | |
| 56 | tree_write_locked.__name__ = unbound.__name__ | |
| 57 | return tree_write_locked | |
| 58 | ||
| 59 | ||
| 1986.1.2
by Robert Collins Various changes to allow non-workingtree specific tests to run entirely | 60 | class MutableTree(tree.Tree): | 
| 61 | """A MutableTree is a specialisation of Tree which is able to be mutated. | |
| 62 | ||
| 63 |     Generally speaking these mutations are only possible within a lock_write
 | |
| 64 |     context, and will revert if the lock is broken abnormally - but this cannot
 | |
| 65 |     be guaranteed - depending on the exact implementation of the mutable state.
 | |
| 66 | ||
| 67 |     The most common form of Mutable Tree is WorkingTree, see bzrlib.workingtree.
 | |
| 68 |     For tests we also have MemoryTree which is a MutableTree whose contents are
 | |
| 69 |     entirely in memory.
 | |
| 70 | ||
| 71 |     For now, we are not treating MutableTree as an interface to provide
 | |
| 72 |     conformance tests for - rather we are testing MemoryTree specifically, and 
 | |
| 73 |     interface testing implementations of WorkingTree.
 | |
| 74 | ||
| 75 |     A mutable tree always has an associated Branch and BzrDir object - the
 | |
| 76 |     branch and bzrdir attributes.
 | |
| 77 |     """
 | |
| 78 | ||
| 2255.7.66
by Robert Collins MutableTree.add only needs a tree write lock. | 79 |     @needs_tree_write_lock
 | 
| 1986.1.2
by Robert Collins Various changes to allow non-workingtree specific tests to run entirely | 80 | def add(self, files, ids=None, kinds=None): | 
| 81 | """Add paths to the set of versioned paths. | |
| 82 | ||
| 83 |         Note that the command line normally calls smart_add instead,
 | |
| 84 |         which can automatically recurse.
 | |
| 85 | ||
| 86 |         This adds the files to the inventory, so that they will be
 | |
| 87 |         recorded by the next commit.
 | |
| 88 | ||
| 89 |         :param files: List of paths to add, relative to the base of the tree.
 | |
| 90 |         :param ids: If set, use these instead of automatically generated ids.
 | |
| 91 |             Must be the same length as the list of files, but may
 | |
| 92 |             contain None for ids that are to be autogenerated.
 | |
| 93 |         :param kinds: Optional parameter to specify the kinds to be used for
 | |
| 94 |             each file.
 | |
| 95 | ||
| 96 |         TODO: Perhaps callback with the ids and paths as they're added.
 | |
| 97 |         """
 | |
| 98 | if isinstance(files, basestring): | |
| 3376.2.4
by Martin Pool Remove every assert statement from bzrlib! | 99 |             # XXX: Passing a single string is inconsistent and should be
 | 
| 100 |             # deprecated.
 | |
| 101 | if not (ids is None or isinstance(ids, basestring)): | |
| 102 | raise AssertionError() | |
| 103 | if not (kinds is None or isinstance(kinds, basestring)): | |
| 104 | raise AssertionError() | |
| 1986.1.2
by Robert Collins Various changes to allow non-workingtree specific tests to run entirely | 105 | files = [files] | 
| 106 | if ids is not None: | |
| 107 | ids = [ids] | |
| 108 | if kinds is not None: | |
| 109 | kinds = [kinds] | |
| 110 | ||
| 2323.4.2
by Robert Collins Fix the behaviour of dirstate optimised iter_changes recursing its disk iterator into subtrees inappropriately. | 111 | files = [path.strip('/') for path in files] | 
| 112 | ||
| 1986.1.2
by Robert Collins Various changes to allow non-workingtree specific tests to run entirely | 113 | if ids is None: | 
| 114 | ids = [None] * len(files) | |
| 115 | else: | |
| 3376.2.4
by Martin Pool Remove every assert statement from bzrlib! | 116 | if not (len(ids) == len(files)): | 
| 117 | raise AssertionError() | |
| 1986.1.2
by Robert Collins Various changes to allow non-workingtree specific tests to run entirely | 118 | if kinds is None: | 
| 119 | kinds = [None] * len(files) | |
| 3376.2.4
by Martin Pool Remove every assert statement from bzrlib! | 120 | elif not len(kinds) == len(files): | 
| 121 | raise AssertionError() | |
| 1986.1.2
by Robert Collins Various changes to allow non-workingtree specific tests to run entirely | 122 | for f in files: | 
| 123 |             # generic constraint checks:
 | |
| 124 | if self.is_control_filename(f): | |
| 125 | raise errors.ForbiddenControlFileError(filename=f) | |
| 126 | fp = splitpath(f) | |
| 127 |         # fill out file kinds for all files [not needed when we stop 
 | |
| 128 |         # caring about the instantaneous file kind within a uncommmitted tree
 | |
| 129 |         #
 | |
| 130 | self._gather_kinds(files, kinds) | |
| 131 | self._add(files, ids, kinds) | |
| 132 | ||
| 2255.6.8
by Aaron Bentley Merge refactoring of add_reference | 133 | def add_reference(self, sub_tree): | 
| 134 | """Add a TreeReference to the tree, pointing at sub_tree""" | |
| 135 | raise errors.UnsupportedOperation(self.add_reference, self) | |
| 136 | ||
| 137 | def _add_reference(self, sub_tree): | |
| 138 | """Standard add_reference implementation, for use by subclasses""" | |
| 139 | try: | |
| 140 | sub_tree_path = self.relpath(sub_tree.basedir) | |
| 141 | except errors.PathNotChild: | |
| 142 | raise errors.BadReferenceTarget(self, sub_tree, | |
| 143 | 'Target not inside tree.') | |
| 144 | sub_tree_id = sub_tree.get_root_id() | |
| 145 | if sub_tree_id == self.get_root_id(): | |
| 146 | raise errors.BadReferenceTarget(self, sub_tree, | |
| 147 | 'Trees have the same root id.') | |
| 148 | if sub_tree_id in self.inventory: | |
| 149 | raise errors.BadReferenceTarget(self, sub_tree, | |
| 150 | 'Root id already present in tree') | |
| 151 | self._add([sub_tree_path], [sub_tree_id], ['tree-reference']) | |
| 152 | ||
| 1986.1.2
by Robert Collins Various changes to allow non-workingtree specific tests to run entirely | 153 | def _add(self, files, ids, kinds): | 
| 2255.6.8
by Aaron Bentley Merge refactoring of add_reference | 154 | """Helper function for add - updates the inventory. | 
| 155 | ||
| 156 |         :param files: sequence of pathnames, relative to the tree root
 | |
| 157 |         :param ids: sequence of suggested ids for the files (may be None)
 | |
| 158 |         :param kinds: sequence of  inventory kinds of the files (i.e. may
 | |
| 159 |             contain "tree-reference")
 | |
| 160 |         """
 | |
| 1986.1.2
by Robert Collins Various changes to allow non-workingtree specific tests to run entirely | 161 | raise NotImplementedError(self._add) | 
| 162 | ||
| 2376.2.2
by Aaron Bentley Reduce lock to tree lock | 163 |     @needs_tree_write_lock
 | 
| 2376.2.1
by Aaron Bentley Implement MutableTree.apply_inventory_delta | 164 | def apply_inventory_delta(self, changes): | 
| 165 | """Apply changes to the inventory as an atomic operation. | |
| 166 | ||
| 2865.1.1
by Robert Collins Create new mutable tree method update_to_one_parent_via_delta for eventual use by commit. | 167 |         :param changes: An inventory delta to apply to the working tree's
 | 
| 168 |             inventory.
 | |
| 169 |         :return None:
 | |
| 170 |         :seealso Inventory.apply_delta: For details on the changes parameter.
 | |
| 2376.2.9
by Aaron Bentley Cleanup from review | 171 |         """
 | 
| 2376.2.1
by Aaron Bentley Implement MutableTree.apply_inventory_delta | 172 | self.flush() | 
| 173 | inv = self.inventory | |
| 2865.1.1
by Robert Collins Create new mutable tree method update_to_one_parent_via_delta for eventual use by commit. | 174 | inv.apply_delta(changes) | 
| 2376.2.1
by Aaron Bentley Implement MutableTree.apply_inventory_delta | 175 | self._write_inventory(inv) | 
| 176 | ||
| 177 |     @needs_write_lock
 | |
| 2255.2.218
by Robert Collins Make the nested tree commit smoke test be more rigourous. | 178 | def commit(self, message=None, revprops=None, *args, | 
| 2100.3.27
by Aaron Bentley Enable nested commits | 179 | **kwargs): | 
| 1986.1.3
by Robert Collins Merge bzr.dev. | 180 |         # avoid circular imports
 | 
| 1986.1.2
by Robert Collins Various changes to allow non-workingtree specific tests to run entirely | 181 | from bzrlib import commit | 
| 182 | if revprops is None: | |
| 183 | revprops = {} | |
| 3565.6.9
by Marius Kruger Jump through hoops not to open multiple connections when committing to a bound branch. | 184 | possible_master_transports=[] | 
| 1986.1.2
by Robert Collins Various changes to allow non-workingtree specific tests to run entirely | 185 | if not 'branch-nick' in revprops: | 
| 3565.6.9
by Marius Kruger Jump through hoops not to open multiple connections when committing to a bound branch. | 186 | revprops['branch-nick'] = self.branch._get_nick( | 
| 3815.3.4
by Marius Kruger When doing a `commit --local`, don't try to connect to the master branch. | 187 | kwargs.get('local', False), | 
| 3565.6.9
by Marius Kruger Jump through hoops not to open multiple connections when committing to a bound branch. | 188 | possible_master_transports) | 
| 2671.2.2
by Lukáš Lalinský Move setting of the author revision property to MutableTree.commit. Don't use try/except KeyError in LongLogFormatter to display authors and branch-nicks. Removed warning about missing e-mail in the authors name. | 189 | author = kwargs.pop('author', None) | 
| 2671.2.5
by Lukáš Lalinský Fixes for comments from the mailing list. | 190 | if author is not None: | 
| 3376.2.4
by Martin Pool Remove every assert statement from bzrlib! | 191 | if 'author' in revprops: | 
| 192 |                 # XXX: maybe we should just accept one of them?
 | |
| 193 | raise AssertionError('author property given twice') | |
| 2671.2.2
by Lukáš Lalinský Move setting of the author revision property to MutableTree.commit. Don't use try/except KeyError in LongLogFormatter to display authors and branch-nicks. Removed warning about missing e-mail in the authors name. | 194 | revprops['author'] = author | 
| 1986.1.2
by Robert Collins Various changes to allow non-workingtree specific tests to run entirely | 195 |         # args for wt.commit start at message from the Commit.commit method,
 | 
| 2367.2.1
by Robert Collins Remove bzrlib 0.8 compatability where it was making the code unclear or messy. (Robert Collins) | 196 | args = (message, ) + args | 
| 3335.1.2
by Jelmer Vernooij Add mutabletree hooks class and start_commit hook. | 197 | for hook in MutableTree.hooks['start_commit']: | 
| 198 | hook(self) | |
| 1986.1.2
by Robert Collins Various changes to allow non-workingtree specific tests to run entirely | 199 | committed_id = commit.Commit().commit(working_tree=self, | 
| 3565.6.9
by Marius Kruger Jump through hoops not to open multiple connections when committing to a bound branch. | 200 | revprops=revprops, | 
| 201 | possible_master_transports=possible_master_transports, | |
| 202 | *args, **kwargs) | |
| 1986.1.2
by Robert Collins Various changes to allow non-workingtree specific tests to run entirely | 203 | return committed_id | 
| 204 | ||
| 205 | def _gather_kinds(self, files, kinds): | |
| 206 | """Helper function for add - sets the entries of kinds.""" | |
| 207 | raise NotImplementedError(self._gather_kinds) | |
| 208 | ||
| 3709.3.2
by Robert Collins Race-free stat-fingerprint updating during commit via a new method get_file_with_stat. | 209 | def get_file_with_stat(self, file_id, path=None): | 
| 210 | """Get a file handle and stat object for file_id. | |
| 211 | ||
| 212 |         The default implementation returns (self.get_file, None) for backwards
 | |
| 213 |         compatibility.
 | |
| 214 | ||
| 215 |         :param file_id: The file id to read.
 | |
| 216 |         :param path: The path of the file, if it is known.
 | |
| 217 |         :return: A tuple (file_handle, stat_value_or_None). If the tree has
 | |
| 218 |             no stat facility, or need for a stat cache feedback during commit,
 | |
| 219 |             it may return None for the second element of the tuple.
 | |
| 220 |         """
 | |
| 221 | return (self.get_file(file_id, path), None) | |
| 222 | ||
| 1986.1.6
by Robert Collins Add MemoryTree.last_revision. | 223 |     @needs_read_lock
 | 
| 224 | def last_revision(self): | |
| 1986.1.7
by Robert Collins Merge bzr.dev. | 225 | """Return the revision id of the last commit performed in this tree. | 
| 226 | ||
| 227 |         In early tree formats the result of last_revision is the same as the
 | |
| 228 |         branch last_revision, but that is no longer the case for modern tree
 | |
| 229 |         formats.
 | |
| 230 |         
 | |
| 231 |         last_revision returns the left most parent id, or None if there are no
 | |
| 232 |         parents.
 | |
| 233 | ||
| 234 |         last_revision was deprecated as of 0.11. Please use get_parent_ids
 | |
| 235 |         instead.
 | |
| 236 |         """
 | |
| 1986.1.6
by Robert Collins Add MemoryTree.last_revision. | 237 | raise NotImplementedError(self.last_revision) | 
| 238 | ||
| 1986.1.8
by Robert Collins Update to bzr.dev, which involves adding lock_tree_write to MutableTree and MemoryTree. | 239 | def lock_tree_write(self): | 
| 240 | """Lock the working tree for write, and the branch for read. | |
| 241 | ||
| 242 |         This is useful for operations which only need to mutate the working
 | |
| 243 |         tree. Taking out branch write locks is a relatively expensive process
 | |
| 244 |         and may fail if the branch is on read only media. So branch write locks
 | |
| 245 |         should only be taken out when we are modifying branch data - such as in
 | |
| 246 |         operations like commit, pull, uncommit and update.
 | |
| 247 |         """
 | |
| 248 | raise NotImplementedError(self.lock_tree_write) | |
| 249 | ||
| 1986.1.2
by Robert Collins Various changes to allow non-workingtree specific tests to run entirely | 250 | def lock_write(self): | 
| 251 | """Lock the tree and its branch. This allows mutating calls to be made. | |
| 252 | ||
| 253 |         Some mutating methods will take out implicit write locks, but in 
 | |
| 254 |         general you should always obtain a write lock before calling mutating
 | |
| 255 |         methods on a tree.
 | |
| 256 |         """
 | |
| 257 | raise NotImplementedError(self.lock_write) | |
| 258 | ||
| 259 |     @needs_write_lock
 | |
| 260 | def mkdir(self, path, file_id=None): | |
| 261 | """Create a directory in the tree. if file_id is None, one is assigned. | |
| 262 | ||
| 263 |         :param path: A unicode file path.
 | |
| 264 |         :param file_id: An optional file-id.
 | |
| 265 |         :return: the file id of the new directory.
 | |
| 266 |         """
 | |
| 267 | raise NotImplementedError(self.mkdir) | |
| 268 | ||
| 3709.3.2
by Robert Collins Race-free stat-fingerprint updating during commit via a new method get_file_with_stat. | 269 | def _observed_sha1(self, file_id, path, (sha1, stat_value)): | 
| 3709.3.1
by Robert Collins First cut - make it work - at updating the tree stat cache during commit. | 270 | """Tell the tree we have observed a paths sha1. | 
| 271 | ||
| 272 |         The intent of this function is to allow trees that have a hashcache to
 | |
| 3709.3.2
by Robert Collins Race-free stat-fingerprint updating during commit via a new method get_file_with_stat. | 273 |         update the hashcache during commit. If the observed file is too new
 | 
| 274 |         (based on the stat_value) to be safely hash-cached the tree will ignore
 | |
| 275 |         it. 
 | |
| 3709.3.1
by Robert Collins First cut - make it work - at updating the tree stat cache during commit. | 276 | |
| 277 |         The default implementation does nothing.
 | |
| 278 | ||
| 279 |         :param file_id: The file id
 | |
| 280 |         :param path: The file path
 | |
| 281 |         :param sha1: The sha 1 that was observed.
 | |
| 3709.3.2
by Robert Collins Race-free stat-fingerprint updating during commit via a new method get_file_with_stat. | 282 |         :param stat_value: A stat result for the file the sha1 was read from.
 | 
| 3709.3.1
by Robert Collins First cut - make it work - at updating the tree stat cache during commit. | 283 |         :return: None
 | 
| 284 |         """
 | |
| 285 | ||
| 3394.2.1
by Ian Clatworthy add docstring for put_file_bytes_non_atomic | 286 |     @needs_write_lock
 | 
| 287 | def put_file_bytes_non_atomic(self, file_id, bytes): | |
| 288 | """Update the content of a file in the tree. | |
| 289 |         
 | |
| 290 |         Note that the file is written in-place rather than being
 | |
| 291 |         written to a temporary location and renamed. As a consequence,
 | |
| 292 |         readers can potentially see the file half-written.
 | |
| 293 | ||
| 294 |         :param file_id: file-id of the file
 | |
| 295 |         :param bytes: the new file contents
 | |
| 296 |         """
 | |
| 297 | raise NotImplementedError(self.put_file_bytes_non_atomic) | |
| 298 | ||
| 2418.5.1
by John Arbash Meinel Make a Branch helper which can create a very basic MemoryTree with history. | 299 | def set_parent_ids(self, revision_ids, allow_leftmost_as_ghost=False): | 
| 300 | """Set the parents ids of the working tree. | |
| 301 | ||
| 302 |         :param revision_ids: A list of revision_ids.
 | |
| 303 |         """
 | |
| 304 | raise NotImplementedError(self.set_parent_ids) | |
| 305 | ||
| 1986.1.2
by Robert Collins Various changes to allow non-workingtree specific tests to run entirely | 306 | def set_parent_trees(self, parents_list, allow_leftmost_as_ghost=False): | 
| 307 | """Set the parents of the working tree. | |
| 308 | ||
| 309 |         :param parents_list: A list of (revision_id, tree) tuples. 
 | |
| 310 |             If tree is None, then that element is treated as an unreachable
 | |
| 311 |             parent tree - i.e. a ghost.
 | |
| 312 |         """
 | |
| 313 | raise NotImplementedError(self.set_parent_trees) | |
| 2568.2.4
by Robert Collins * ``bzrlib.add.smart_add`` and ``bzrlib.add.smart_add_tree`` are now | 314 | |
| 315 |     @needs_tree_write_lock
 | |
| 316 | def smart_add(self, file_list, recurse=True, action=None, save=True): | |
| 317 | """Version file_list, optionally recursing into directories. | |
| 318 | ||
| 319 |         This is designed more towards DWIM for humans than API clarity.
 | |
| 320 |         For the specific behaviour see the help for cmd_add().
 | |
| 321 | ||
| 322 |         :param action: A reporter to be called with the inventory, parent_ie,
 | |
| 323 |             path and kind of the path being added. It may return a file_id if 
 | |
| 324 |             a specific one should be used.
 | |
| 325 |         :param save: Save the inventory after completing the adds. If False
 | |
| 326 |             this provides dry-run functionality by doing the add and not saving
 | |
| 2585.1.1
by Aaron Bentley Unify MutableTree.smart_add behavior by disabling quirky memory-only Inventory | 327 |             the inventory.
 | 
| 2568.2.6
by Robert Collins Review feedback. | 328 |         :return: A tuple - files_added, ignored_files. files_added is the count
 | 
| 329 |             of added files, and ignored_files is a dict mapping files that were
 | |
| 330 |             ignored to the rule that caused them to be ignored.
 | |
| 2568.2.4
by Robert Collins * ``bzrlib.add.smart_add`` and ``bzrlib.add.smart_add_tree`` are now | 331 |         """
 | 
| 332 |         # not in an inner loop; and we want to remove direct use of this,
 | |
| 333 |         # so here as a reminder for now. RBC 20070703
 | |
| 334 | from bzrlib.inventory import InventoryEntry | |
| 335 | if action is None: | |
| 336 | action = add.AddAction() | |
| 337 | ||
| 338 | if not file_list: | |
| 339 |             # no paths supplied: add the entire tree.
 | |
| 340 | file_list = [u'.'] | |
| 341 |         # mutter("smart add of %r")
 | |
| 342 | inv = self.inventory | |
| 343 | added = [] | |
| 344 | ignored = {} | |
| 345 | dirs_to_add = [] | |
| 346 | user_dirs = set() | |
| 347 | ||
| 348 |         # validate user file paths and convert all paths to tree 
 | |
| 2568.2.6
by Robert Collins Review feedback. | 349 |         # relative : it's cheaper to make a tree relative path an abspath
 | 
| 2568.2.4
by Robert Collins * ``bzrlib.add.smart_add`` and ``bzrlib.add.smart_add_tree`` are now | 350 |         # than to convert an abspath to tree relative.
 | 
| 351 | for filepath in file_list: | |
| 2568.2.5
by Robert Collins * ``bzrlib.add.FastPath`` is now private and moved to | 352 | rf = _FastPath(self.relpath(filepath)) | 
| 2568.2.4
by Robert Collins * ``bzrlib.add.smart_add`` and ``bzrlib.add.smart_add_tree`` are now | 353 |             # validate user parameters. Our recursive code avoids adding new files
 | 
| 354 |             # that need such validation 
 | |
| 355 | if self.is_control_filename(rf.raw_path): | |
| 356 | raise errors.ForbiddenControlFileError(filename=rf.raw_path) | |
| 357 | ||
| 358 | abspath = self.abspath(rf.raw_path) | |
| 359 | kind = osutils.file_kind(abspath) | |
| 360 | if kind == 'directory': | |
| 361 |                 # schedule the dir for scanning
 | |
| 362 | user_dirs.add(rf) | |
| 363 | else: | |
| 364 | if not InventoryEntry.versionable_kind(kind): | |
| 365 | raise errors.BadFileKindError(filename=abspath, kind=kind) | |
| 366 |             # ensure the named path is added, so that ignore rules in the later directory
 | |
| 367 |             # walk dont skip it.
 | |
| 368 |             # we dont have a parent ie known yet.: use the relatively slower inventory 
 | |
| 369 |             # probing method
 | |
| 370 | versioned = inv.has_filename(rf.raw_path) | |
| 371 | if versioned: | |
| 372 |                 continue
 | |
| 373 | added.extend(_add_one_and_parent(self, inv, None, rf, kind, action)) | |
| 374 | ||
| 375 | if not recurse: | |
| 376 |             # no need to walk any directories at all.
 | |
| 377 | if len(added) > 0 and save: | |
| 378 | self._write_inventory(inv) | |
| 379 | return added, ignored | |
| 380 | ||
| 381 |         # only walk the minimal parents needed: we have user_dirs to override
 | |
| 382 |         # ignores.
 | |
| 383 | prev_dir = None | |
| 384 | ||
| 385 | is_inside = osutils.is_inside_or_parent_of_any | |
| 386 | for path in sorted(user_dirs): | |
| 387 | if (prev_dir is None or not is_inside([prev_dir], path.raw_path)): | |
| 388 | dirs_to_add.append((path, None)) | |
| 389 | prev_dir = path.raw_path | |
| 390 | ||
| 391 |         # dirs_to_add is initialised to a list of directories, but as we scan
 | |
| 392 |         # directories we append files to it.
 | |
| 393 |         # XXX: We should determine kind of files when we scan them rather than
 | |
| 394 |         # adding to this list. RBC 20070703
 | |
| 395 | for directory, parent_ie in dirs_to_add: | |
| 396 |             # directory is tree-relative
 | |
| 397 | abspath = self.abspath(directory.raw_path) | |
| 398 | ||
| 399 |             # get the contents of this directory.
 | |
| 400 | ||
| 401 |             # find the kind of the path being added.
 | |
| 402 | kind = osutils.file_kind(abspath) | |
| 403 | ||
| 404 | if not InventoryEntry.versionable_kind(kind): | |
| 405 | warning("skipping %s (can't add file of kind '%s')", abspath, kind) | |
| 406 |                 continue
 | |
| 407 | ||
| 408 | if parent_ie is not None: | |
| 409 | versioned = directory.base_path in parent_ie.children | |
| 410 | else: | |
| 411 |                 # without the parent ie, use the relatively slower inventory 
 | |
| 412 |                 # probing method
 | |
| 413 | versioned = inv.has_filename(directory.raw_path) | |
| 414 | ||
| 415 | if kind == 'directory': | |
| 416 | try: | |
| 417 | sub_branch = bzrdir.BzrDir.open(abspath) | |
| 418 | sub_tree = True | |
| 419 | except errors.NotBranchError: | |
| 420 | sub_tree = False | |
| 421 | except errors.UnsupportedFormatError: | |
| 422 | sub_tree = True | |
| 423 | else: | |
| 424 | sub_tree = False | |
| 425 | ||
| 426 | if directory.raw_path == '': | |
| 427 |                 # mutter("tree root doesn't need to be added")
 | |
| 428 | sub_tree = False | |
| 429 | elif versioned: | |
| 430 |                 pass
 | |
| 431 |                 # mutter("%r is already versioned", abspath)
 | |
| 432 | elif sub_tree: | |
| 433 |                 # XXX: This is wrong; people *might* reasonably be trying to add
 | |
| 434 |                 # subtrees as subtrees.  This should probably only be done in formats 
 | |
| 435 |                 # which can represent subtrees, and even then perhaps only when
 | |
| 436 |                 # the user asked to add subtrees.  At the moment you can add them
 | |
| 437 |                 # specially through 'join --reference', which is perhaps
 | |
| 438 |                 # reasonable: adding a new reference is a special operation and
 | |
| 439 |                 # can have a special behaviour.  mbp 20070306
 | |
| 440 | mutter("%r is a nested bzr tree", abspath) | |
| 441 | else: | |
| 442 | _add_one(self, inv, parent_ie, directory, kind, action) | |
| 443 | added.append(directory.raw_path) | |
| 444 | ||
| 445 | if kind == 'directory' and not sub_tree: | |
| 446 | if parent_ie is not None: | |
| 447 |                     # must be present:
 | |
| 448 | this_ie = parent_ie.children[directory.base_path] | |
| 449 | else: | |
| 450 |                     # without the parent ie, use the relatively slower inventory 
 | |
| 451 |                     # probing method
 | |
| 452 | this_id = inv.path2id(directory.raw_path) | |
| 453 | if this_id is None: | |
| 454 | this_ie = None | |
| 455 | else: | |
| 456 | this_ie = inv[this_id] | |
| 457 | ||
| 458 | for subf in sorted(os.listdir(abspath)): | |
| 459 |                     # here we could use TreeDirectory rather than 
 | |
| 460 |                     # string concatenation.
 | |
| 461 | subp = osutils.pathjoin(directory.raw_path, subf) | |
| 462 |                     # TODO: is_control_filename is very slow. Make it faster. 
 | |
| 463 |                     # TreeDirectory.is_control_filename could also make this 
 | |
| 464 |                     # faster - its impossible for a non root dir to have a 
 | |
| 465 |                     # control file.
 | |
| 466 | if self.is_control_filename(subp): | |
| 467 | mutter("skip control directory %r", subp) | |
| 468 | elif subf in this_ie.children: | |
| 469 |                         # recurse into this already versioned subdir.
 | |
| 2568.2.5
by Robert Collins * ``bzrlib.add.FastPath`` is now private and moved to | 470 | dirs_to_add.append((_FastPath(subp, subf), this_ie)) | 
| 2568.2.4
by Robert Collins * ``bzrlib.add.smart_add`` and ``bzrlib.add.smart_add_tree`` are now | 471 | else: | 
| 472 |                         # user selection overrides ignoes
 | |
| 473 |                         # ignore while selecting files - if we globbed in the
 | |
| 474 |                         # outer loop we would ignore user files.
 | |
| 475 | ignore_glob = self.is_ignored(subp) | |
| 476 | if ignore_glob is not None: | |
| 477 |                             # mutter("skip ignored sub-file %r", subp)
 | |
| 478 | ignored.setdefault(ignore_glob, []).append(subp) | |
| 479 | else: | |
| 480 |                             #mutter("queue to add sub-file %r", subp)
 | |
| 2568.2.5
by Robert Collins * ``bzrlib.add.FastPath`` is now private and moved to | 481 | dirs_to_add.append((_FastPath(subp, subf), this_ie)) | 
| 2568.2.4
by Robert Collins * ``bzrlib.add.smart_add`` and ``bzrlib.add.smart_add_tree`` are now | 482 | |
| 2585.1.1
by Aaron Bentley Unify MutableTree.smart_add behavior by disabling quirky memory-only Inventory | 483 | if len(added) > 0: | 
| 484 | if save: | |
| 485 | self._write_inventory(inv) | |
| 486 | else: | |
| 487 | self.read_working_inventory() | |
| 2568.2.4
by Robert Collins * ``bzrlib.add.smart_add`` and ``bzrlib.add.smart_add_tree`` are now | 488 | return added, ignored | 
| 489 | ||
| 2903.2.7
by Martin Pool Rename update_to_one_parent_via_delta to more wieldy update_basis_by_delta | 490 | def update_basis_by_delta(self, new_revid, delta): | 
| 2865.1.1
by Robert Collins Create new mutable tree method update_to_one_parent_via_delta for eventual use by commit. | 491 | """Update the parents of this tree after a commit. | 
| 492 | ||
| 493 |         This gives the tree one parent, with revision id new_revid. The
 | |
| 2903.2.1
by Martin Pool Commit now tells the working tree about the new basis by passing the an inventory delta from the previous basis | 494 |         inventory delta is applied to the current basis tree to generate the
 | 
| 2865.1.3
by Robert Collins Review feedback. | 495 |         inventory for the parent new_revid, and all other parent trees are
 | 
| 2865.1.1
by Robert Collins Create new mutable tree method update_to_one_parent_via_delta for eventual use by commit. | 496 |         discarded.
 | 
| 497 | ||
| 2929.2.1
by Robert Collins * Commit updates the state of the working tree via a delta rather than | 498 |         All the changes in the delta should be changes synchronising the basis
 | 
| 499 |         tree with some or all of the working tree, with a change to a directory
 | |
| 500 |         requiring that its contents have been recursively included. That is,
 | |
| 501 |         this is not a general purpose tree modification routine, but a helper
 | |
| 502 |         for commit which is not required to handle situations that do not arise
 | |
| 503 |         outside of commit.
 | |
| 504 | ||
| 2865.1.1
by Robert Collins Create new mutable tree method update_to_one_parent_via_delta for eventual use by commit. | 505 |         :param new_revid: The new revision id for the trees parent.
 | 
| 506 |         :param delta: An inventory delta (see apply_inventory_delta) describing
 | |
| 507 |             the changes from the current left most parent revision to new_revid.
 | |
| 508 |         """
 | |
| 509 |         # if the tree is updated by a pull to the branch, as happens in
 | |
| 510 |         # WorkingTree2, when there was no separation between branch and tree,
 | |
| 511 |         # then just clear merges, efficiency is not a concern for now as this
 | |
| 512 |         # is legacy environments only, and they are slow regardless.
 | |
| 513 | if self.last_revision() == new_revid: | |
| 514 | self.set_parent_ids([new_revid]) | |
| 515 |             return
 | |
| 516 |         # generic implementation based on Inventory manipulation. See
 | |
| 517 |         # WorkingTree classes for optimised versions for specific format trees.
 | |
| 518 | basis = self.basis_tree() | |
| 519 | basis.lock_read() | |
| 520 | inventory = basis.inventory | |
| 521 | basis.unlock() | |
| 522 | inventory.apply_delta(delta) | |
| 523 | rev_tree = RevisionTree(self.branch.repository, inventory, new_revid) | |
| 524 | self.set_parent_trees([(new_revid, rev_tree)]) | |
| 525 | ||
| 2568.2.4
by Robert Collins * ``bzrlib.add.smart_add`` and ``bzrlib.add.smart_add_tree`` are now | 526 | |
| 3335.1.2
by Jelmer Vernooij Add mutabletree hooks class and start_commit hook. | 527 | class MutableTreeHooks(hooks.Hooks): | 
| 3335.1.4
by Jelmer Vernooij Fix indentation, add version number. | 528 | """A dictionary mapping a hook name to a list of callables for mutabletree | 
| 529 |     hooks.
 | |
| 3335.1.2
by Jelmer Vernooij Add mutabletree hooks class and start_commit hook. | 530 |     """
 | 
| 531 | ||
| 532 | def __init__(self): | |
| 533 | """Create the default hooks. | |
| 534 | ||
| 535 |         """
 | |
| 536 | hooks.Hooks.__init__(self) | |
| 3335.1.4
by Jelmer Vernooij Fix indentation, add version number. | 537 |         # Invoked before a commit is done in a tree. New in 1.4
 | 
| 3335.1.2
by Jelmer Vernooij Add mutabletree hooks class and start_commit hook. | 538 | self['start_commit'] = [] | 
| 539 | ||
| 540 | ||
| 541 | # install the default hooks into the MutableTree class.
 | |
| 542 | MutableTree.hooks = MutableTreeHooks() | |
| 543 | ||
| 544 | ||
| 2568.2.5
by Robert Collins * ``bzrlib.add.FastPath`` is now private and moved to | 545 | class _FastPath(object): | 
| 2568.2.4
by Robert Collins * ``bzrlib.add.smart_add`` and ``bzrlib.add.smart_add_tree`` are now | 546 | """A path object with fast accessors for things like basename.""" | 
| 547 | ||
| 548 | __slots__ = ['raw_path', 'base_path'] | |
| 549 | ||
| 550 | def __init__(self, path, base_path=None): | |
| 551 | """Construct a FastPath from path.""" | |
| 552 | if base_path is None: | |
| 553 | self.base_path = osutils.basename(path) | |
| 554 | else: | |
| 555 | self.base_path = base_path | |
| 556 | self.raw_path = path | |
| 557 | ||
| 558 | def __cmp__(self, other): | |
| 559 | return cmp(self.raw_path, other.raw_path) | |
| 560 | ||
| 561 | def __hash__(self): | |
| 562 | return hash(self.raw_path) | |
| 563 | ||
| 564 | ||
| 565 | def _add_one_and_parent(tree, inv, parent_ie, path, kind, action): | |
| 566 | """Add a new entry to the inventory and automatically add unversioned parents. | |
| 567 | ||
| 568 |     :param inv: Inventory which will receive the new entry.
 | |
| 569 |     :param parent_ie: Parent inventory entry if known, or None.  If
 | |
| 570 |         None, the parent is looked up by name and used if present, otherwise it
 | |
| 571 |         is recursively added.
 | |
| 572 |     :param kind: Kind of new entry (file, directory, etc)
 | |
| 573 |     :param action: callback(inv, parent_ie, path, kind); return ignored.
 | |
| 574 |     :return: A list of paths which have been added.
 | |
| 575 |     """
 | |
| 576 |     # Nothing to do if path is already versioned.
 | |
| 577 |     # This is safe from infinite recursion because the tree root is
 | |
| 578 |     # always versioned.
 | |
| 579 | if parent_ie is not None: | |
| 580 |         # we have a parent ie already
 | |
| 581 | added = [] | |
| 582 | else: | |
| 583 |         # slower but does not need parent_ie
 | |
| 584 | if inv.has_filename(path.raw_path): | |
| 585 | return [] | |
| 586 |         # its really not there : add the parent
 | |
| 587 |         # note that the dirname use leads to some extra str copying etc but as
 | |
| 588 |         # there are a limited number of dirs we can be nested under, it should
 | |
| 589 |         # generally find it very fast and not recurse after that.
 | |
| 2568.2.5
by Robert Collins * ``bzrlib.add.FastPath`` is now private and moved to | 590 | added = _add_one_and_parent(tree, inv, None, | 
| 591 | _FastPath(dirname(path.raw_path)), 'directory', action) | |
| 2568.2.4
by Robert Collins * ``bzrlib.add.smart_add`` and ``bzrlib.add.smart_add_tree`` are now | 592 | parent_id = inv.path2id(dirname(path.raw_path)) | 
| 593 | parent_ie = inv[parent_id] | |
| 594 | _add_one(tree, inv, parent_ie, path, kind, action) | |
| 595 | return added + [path.raw_path] | |
| 596 | ||
| 597 | ||
| 598 | def _add_one(tree, inv, parent_ie, path, kind, file_id_callback): | |
| 599 | """Add a new entry to the inventory. | |
| 600 | ||
| 601 |     :param inv: Inventory which will receive the new entry.
 | |
| 602 |     :param parent_ie: Parent inventory entry.
 | |
| 603 |     :param kind: Kind of new entry (file, directory, etc)
 | |
| 604 |     :param file_id_callback: callback(inv, parent_ie, path, kind); return a
 | |
| 605 |         file_id or None to generate a new file id
 | |
| 606 |     :returns: None
 | |
| 607 |     """
 | |
| 608 | file_id = file_id_callback(inv, parent_ie, path, kind) | |
| 609 | entry = inv.make_entry(kind, path.base_path, parent_ie.file_id, | |
| 610 | file_id=file_id) | |
| 611 | inv.add(entry) |