~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/mutabletree.py

(gz) Change minimum required testtools version for selftest to 0.9.5 for
 unicode fixes (Martin [gz])

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006-2011 Canonical Ltd
 
1
# Copyright (C) 2006-2010 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
30
30
    bzrdir,
31
31
    errors,
32
32
    hooks,
33
 
    inventory as _mod_inventory,
34
33
    osutils,
35
34
    revisiontree,
 
35
    inventory,
 
36
    symbol_versioning,
36
37
    trace,
37
38
    tree,
38
39
    )
79
80
        # used on media which doesn't differentiate the case of names.
80
81
        self.case_sensitive = True
81
82
 
82
 
    def is_control_filename(self, filename):
83
 
        """True if filename is the name of a control file in this tree.
84
 
 
85
 
        :param filename: A filename within the tree. This is a relative path
86
 
        from the root of this tree.
87
 
 
88
 
        This is true IF and ONLY IF the filename is part of the meta data
89
 
        that bzr controls in this tree. I.E. a random .bzr directory placed
90
 
        on disk will not be a control file for this tree.
91
 
        """
92
 
        raise NotImplementedError(self.is_control_filename)
93
 
 
94
83
    @needs_tree_write_lock
95
84
    def add(self, files, ids=None, kinds=None):
96
85
        """Add paths to the set of versioned paths.
160
149
        if sub_tree_id == self.get_root_id():
161
150
            raise errors.BadReferenceTarget(self, sub_tree,
162
151
                                     'Trees have the same root id.')
163
 
        if sub_tree_id in self:
 
152
        if sub_tree_id in self.inventory:
164
153
            raise errors.BadReferenceTarget(self, sub_tree,
165
154
                                            'Root id already present in tree')
166
155
        self._add([sub_tree_path], [sub_tree_id], ['tree-reference'])
175
164
        """
176
165
        raise NotImplementedError(self._add)
177
166
 
 
167
    @needs_tree_write_lock
178
168
    def apply_inventory_delta(self, changes):
179
169
        """Apply changes to the inventory as an atomic operation.
180
170
 
183
173
        :return None:
184
174
        :seealso Inventory.apply_delta: For details on the changes parameter.
185
175
        """
186
 
        raise NotImplementedError(self.apply_inventory_delta)
 
176
        self.flush()
 
177
        inv = self.inventory
 
178
        inv.apply_delta(changes)
 
179
        self._write_inventory(inv)
187
180
 
188
181
    @needs_write_lock
189
182
    def commit(self, message=None, revprops=None, *args,
341
334
        :return: None
342
335
        """
343
336
 
 
337
    def _fix_case_of_inventory_path(self, path):
 
338
        """If our tree isn't case sensitive, return the canonical path"""
 
339
        if not self.case_sensitive:
 
340
            path = self.get_canonical_inventory_path(path)
 
341
        return path
 
342
 
344
343
    @needs_write_lock
345
344
    def put_file_bytes_non_atomic(self, file_id, bytes):
346
345
        """Update the content of a file in the tree.
370
369
        """
371
370
        raise NotImplementedError(self.set_parent_trees)
372
371
 
373
 
    def smart_add(self, file_list, recurse=True, action=None, save=True):
374
 
        """Version file_list, optionally recursing into directories.
375
 
 
376
 
        This is designed more towards DWIM for humans than API clarity.
377
 
        For the specific behaviour see the help for cmd_add().
378
 
 
379
 
        :param file_list: List of zero or more paths.  *NB: these are 
380
 
            interpreted relative to the process cwd, not relative to the 
381
 
            tree.*  (Add and most other tree methods use tree-relative
382
 
            paths.)
383
 
        :param action: A reporter to be called with the inventory, parent_ie,
384
 
            path and kind of the path being added. It may return a file_id if
385
 
            a specific one should be used.
386
 
        :param save: Save the inventory after completing the adds. If False
387
 
            this provides dry-run functionality by doing the add and not saving
388
 
            the inventory.
389
 
        :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 were
391
 
            ignored to the rule that caused them to be ignored.
392
 
        """
393
 
        raise NotImplementedError(self.smart_add)
394
 
 
395
 
    def update_basis_by_delta(self, new_revid, delta):
396
 
        """Update the parents of this tree after a commit.
397
 
 
398
 
        This gives the tree one parent, with revision id new_revid. The
399
 
        inventory delta is applied to the current basis tree to generate the
400
 
        inventory for the parent new_revid, and all other parent trees are
401
 
        discarded.
402
 
 
403
 
        All the changes in the delta should be changes synchronising the basis
404
 
        tree with some or all of the working tree, with a change to a directory
405
 
        requiring that its contents have been recursively included. That is,
406
 
        this is not a general purpose tree modification routine, but a helper
407
 
        for commit which is not required to handle situations that do not arise
408
 
        outside of commit.
409
 
 
410
 
        See the inventory developers documentation for the theory behind
411
 
        inventory deltas.
412
 
 
413
 
        :param new_revid: The new revision id for the trees parent.
414
 
        :param delta: An inventory delta (see apply_inventory_delta) describing
415
 
            the changes from the current left most parent revision to new_revid.
416
 
        """
417
 
        raise NotImplementedError(self.update_basis_by_delta)
418
 
 
419
 
 
420
 
class MutableInventoryTree(MutableTree,tree.InventoryTree):
421
 
 
422
 
    @needs_tree_write_lock
423
 
    def apply_inventory_delta(self, changes):
424
 
        """Apply changes to the inventory as an atomic operation.
425
 
 
426
 
        :param changes: An inventory delta to apply to the working tree's
427
 
            inventory.
428
 
        :return None:
429
 
        :seealso Inventory.apply_delta: For details on the changes parameter.
430
 
        """
431
 
        self.flush()
432
 
        inv = self.inventory
433
 
        inv.apply_delta(changes)
434
 
        self._write_inventory(inv)
435
 
 
436
 
    def _fix_case_of_inventory_path(self, path):
437
 
        """If our tree isn't case sensitive, return the canonical path"""
438
 
        if not self.case_sensitive:
439
 
            path = self.get_canonical_inventory_path(path)
440
 
        return path
441
 
 
442
372
    @needs_tree_write_lock
443
373
    def smart_add(self, file_list, recurse=True, action=None, save=True):
444
374
        """Version file_list, optionally recursing into directories.
488
418
 
489
419
        # expand any symlinks in the directory part, while leaving the
490
420
        # filename alone
491
 
        # only expanding if symlinks are supported avoids windows path bugs
492
 
        if osutils.has_symlinks():
493
 
            file_list = map(osutils.normalizepath, file_list)
 
421
        file_list = map(osutils.normalizepath, file_list)
494
422
 
495
423
        # validate user file paths and convert all paths to tree
496
424
        # relative : it's cheaper to make a tree relative path an abspath
620
548
                        # Same as in _add_one below, if the inventory doesn't
621
549
                        # think this is a directory, update the inventory
622
550
                        if this_ie.kind != 'directory':
623
 
                            this_ie = _mod_inventory.make_entry('directory',
 
551
                            this_ie = inventory.make_entry('directory',
624
552
                                this_ie.name, this_ie.parent_id, this_id)
625
553
                            del inv[this_id]
626
554
                            inv.add(this_ie)
693
621
        # TODO: Consider re-evaluating the need for this with CHKInventory
694
622
        # we don't strictly need to mutate an inventory for this
695
623
        # it only makes sense when apply_delta is cheaper than get_inventory()
696
 
        inventory = _mod_inventory.mutable_inventory_from_tree(basis)
 
624
        inventory = basis.inventory._get_mutable_inventory()
697
625
        basis.unlock()
698
626
        inventory.apply_delta(delta)
699
 
        rev_tree = revisiontree.InventoryRevisionTree(self.branch.repository,
 
627
        rev_tree = revisiontree.RevisionTree(self.branch.repository,
700
628
                                             inventory, new_revid)
701
629
        self.set_parent_trees([(new_revid, rev_tree)])
702
630
 
710
638
        """Create the default hooks.
711
639
 
712
640
        """
713
 
        hooks.Hooks.__init__(self, "bzrlib.mutabletree", "MutableTree.hooks")
714
 
        self.add_hook('start_commit',
 
641
        hooks.Hooks.__init__(self)
 
642
        self.create_hook(hooks.HookPoint('start_commit',
715
643
            "Called before a commit is performed on a tree. The start commit "
716
644
            "hook is able to change the tree before the commit takes place. "
717
645
            "start_commit is called with the bzrlib.mutabletree.MutableTree "
718
 
            "that the commit is being performed on.", (1, 4))
719
 
        self.add_hook('post_commit',
 
646
            "that the commit is being performed on.", (1, 4), None))
 
647
        self.create_hook(hooks.HookPoint('post_commit',
720
648
            "Called after a commit is performed on a tree. The hook is "
721
649
            "called with a bzrlib.mutabletree.PostCommitHookParams object. "
722
650
            "The mutable tree the commit was performed on is available via "
723
 
            "the mutable_tree attribute of that object.", (2, 0))
 
651
            "the mutable_tree attribute of that object.", (2, 0), None))
724
652
 
725
653
 
726
654
# install the default hooks into the MutableTree class.
809
737
    if parent_ie.kind != 'directory':
810
738
        # nb: this relies on someone else checking that the path we're using
811
739
        # doesn't contain symlinks.
812
 
        new_parent_ie = _mod_inventory.make_entry('directory', parent_ie.name,
 
740
        new_parent_ie = inventory.make_entry('directory', parent_ie.name,
813
741
            parent_ie.parent_id, parent_ie.file_id)
814
742
        del inv[parent_ie.file_id]
815
743
        inv.add(new_parent_ie)