/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/mutabletree.py

  • Committer: Robert Collins
  • Date: 2010-05-06 11:08:10 UTC
  • mto: This revision was merged to the branch mainline in revision 5223.
  • Revision ID: robertc@robertcollins.net-20100506110810-h3j07fh5gmw54s25
Cleaner matcher matching revised unlocking protocol.

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
    symbol_versioning,
36
36
    trace,
37
37
    tree,
38
38
    )
79
79
        # used on media which doesn't differentiate the case of names.
80
80
        self.case_sensitive = True
81
81
 
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
82
    @needs_tree_write_lock
95
83
    def add(self, files, ids=None, kinds=None):
96
84
        """Add paths to the set of versioned paths.
160
148
        if sub_tree_id == self.get_root_id():
161
149
            raise errors.BadReferenceTarget(self, sub_tree,
162
150
                                     'Trees have the same root id.')
163
 
        if sub_tree_id in self:
 
151
        if sub_tree_id in self.inventory:
164
152
            raise errors.BadReferenceTarget(self, sub_tree,
165
153
                                            'Root id already present in tree')
166
154
        self._add([sub_tree_path], [sub_tree_id], ['tree-reference'])
175
163
        """
176
164
        raise NotImplementedError(self._add)
177
165
 
 
166
    @needs_tree_write_lock
178
167
    def apply_inventory_delta(self, changes):
179
168
        """Apply changes to the inventory as an atomic operation.
180
169
 
183
172
        :return None:
184
173
        :seealso Inventory.apply_delta: For details on the changes parameter.
185
174
        """
186
 
        raise NotImplementedError(self.apply_inventory_delta)
 
175
        self.flush()
 
176
        inv = self.inventory
 
177
        inv.apply_delta(changes)
 
178
        self._write_inventory(inv)
187
179
 
188
180
    @needs_write_lock
189
181
    def commit(self, message=None, revprops=None, *args,
190
182
               **kwargs):
191
183
        # avoid circular imports
192
184
        from bzrlib import commit
 
185
        if revprops is None:
 
186
            revprops = {}
193
187
        possible_master_transports=[]
194
 
        revprops = commit.Commit.update_revprops(
195
 
                revprops,
196
 
                self.branch,
197
 
                kwargs.pop('authors', None),
198
 
                kwargs.pop('author', None),
 
188
        if not 'branch-nick' in revprops:
 
189
            revprops['branch-nick'] = self.branch._get_nick(
199
190
                kwargs.get('local', False),
200
191
                possible_master_transports)
 
192
        authors = kwargs.pop('authors', None)
 
193
        author = kwargs.pop('author', None)
 
194
        if authors is not None:
 
195
            if author is not None:
 
196
                raise AssertionError('Specifying both author and authors '
 
197
                        'is not allowed. Specify just authors instead')
 
198
            if 'author' in revprops or 'authors' in revprops:
 
199
                # XXX: maybe we should just accept one of them?
 
200
                raise AssertionError('author property given twice')
 
201
            if authors:
 
202
                for individual in authors:
 
203
                    if '\n' in individual:
 
204
                        raise AssertionError('\\n is not a valid character '
 
205
                                'in an author identity')
 
206
                revprops['authors'] = '\n'.join(authors)
 
207
        if author is not None:
 
208
            symbol_versioning.warn('The parameter author was deprecated'
 
209
                   ' in version 1.13. Use authors instead',
 
210
                   DeprecationWarning)
 
211
            if 'author' in revprops or 'authors' in revprops:
 
212
                # XXX: maybe we should just accept one of them?
 
213
                raise AssertionError('author property given twice')
 
214
            if '\n' in author:
 
215
                raise AssertionError('\\n is not a valid character '
 
216
                        'in an author identity')
 
217
            revprops['authors'] = author
201
218
        # args for wt.commit start at message from the Commit.commit method,
202
219
        args = (message, ) + args
203
220
        for hook in MutableTree.hooks['start_commit']:
341
358
        :return: None
342
359
        """
343
360
 
 
361
    def _fix_case_of_inventory_path(self, path):
 
362
        """If our tree isn't case sensitive, return the canonical path"""
 
363
        if not self.case_sensitive:
 
364
            path = self.get_canonical_inventory_path(path)
 
365
        return path
 
366
 
344
367
    @needs_write_lock
345
368
    def put_file_bytes_non_atomic(self, file_id, bytes):
346
369
        """Update the content of a file in the tree.
370
393
        """
371
394
        raise NotImplementedError(self.set_parent_trees)
372
395
 
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
 
    @needs_tree_write_lock
443
 
    def smart_add(self, file_list, recurse=True, action=None, save=True):
444
 
        """Version file_list, optionally recursing into directories.
445
 
 
446
 
        This is designed more towards DWIM for humans than API clarity.
447
 
        For the specific behaviour see the help for cmd_add().
448
 
 
449
 
        :param file_list: List of zero or more paths.  *NB: these are 
450
 
            interpreted relative to the process cwd, not relative to the 
451
 
            tree.*  (Add and most other tree methods use tree-relative
452
 
            paths.)
 
396
    @needs_tree_write_lock
 
397
    def smart_add(self, file_list, recurse=True, action=None, save=True):
 
398
        """Version file_list, optionally recursing into directories.
 
399
 
 
400
        This is designed more towards DWIM for humans than API clarity.
 
401
        For the specific behaviour see the help for cmd_add().
 
402
 
453
403
        :param action: A reporter to be called with the inventory, parent_ie,
454
404
            path and kind of the path being added. It may return a file_id if
455
405
            a specific one should be used.
486
436
            for c in self.conflicts():
487
437
                conflicts_related.update(c.associated_filenames())
488
438
 
489
 
        # expand any symlinks in the directory part, while leaving the
490
 
        # 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)
494
 
 
495
439
        # validate user file paths and convert all paths to tree
496
440
        # relative : it's cheaper to make a tree relative path an abspath
497
441
        # than to convert an abspath to tree relative, and it's cheaper to
617
561
                        this_ie = None
618
562
                    else:
619
563
                        this_ie = inv[this_id]
620
 
                        # Same as in _add_one below, if the inventory doesn't
621
 
                        # think this is a directory, update the inventory
622
 
                        if this_ie.kind != 'directory':
623
 
                            this_ie = _mod_inventory.make_entry('directory',
624
 
                                this_ie.name, this_ie.parent_id, this_id)
625
 
                            del inv[this_id]
626
 
                            inv.add(this_ie)
627
564
 
628
565
                for subf in sorted(os.listdir(abspath)):
629
566
                    # here we could use TreeDirectory rather than
693
630
        # TODO: Consider re-evaluating the need for this with CHKInventory
694
631
        # we don't strictly need to mutate an inventory for this
695
632
        # it only makes sense when apply_delta is cheaper than get_inventory()
696
 
        inventory = _mod_inventory.mutable_inventory_from_tree(basis)
 
633
        inventory = basis.inventory._get_mutable_inventory()
697
634
        basis.unlock()
698
635
        inventory.apply_delta(delta)
699
 
        rev_tree = revisiontree.InventoryRevisionTree(self.branch.repository,
 
636
        rev_tree = revisiontree.RevisionTree(self.branch.repository,
700
637
                                             inventory, new_revid)
701
638
        self.set_parent_trees([(new_revid, rev_tree)])
702
639
 
710
647
        """Create the default hooks.
711
648
 
712
649
        """
713
 
        hooks.Hooks.__init__(self, "bzrlib.mutabletree", "MutableTree.hooks")
714
 
        self.add_hook('start_commit',
 
650
        hooks.Hooks.__init__(self)
 
651
        self.create_hook(hooks.HookPoint('start_commit',
715
652
            "Called before a commit is performed on a tree. The start commit "
716
653
            "hook is able to change the tree before the commit takes place. "
717
654
            "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',
 
655
            "that the commit is being performed on.", (1, 4), None))
 
656
        self.create_hook(hooks.HookPoint('post_commit',
720
657
            "Called after a commit is performed on a tree. The hook is "
721
658
            "called with a bzrlib.mutabletree.PostCommitHookParams object. "
722
659
            "The mutable tree the commit was performed on is available via "
723
 
            "the mutable_tree attribute of that object.", (2, 0))
 
660
            "the mutable_tree attribute of that object.", (2, 0), None))
724
661
 
725
662
 
726
663
# install the default hooks into the MutableTree class.
803
740
        file_id or None to generate a new file id
804
741
    :returns: None
805
742
    """
806
 
    # if the parent exists, but isn't a directory, we have to do the
807
 
    # kind change now -- really the inventory shouldn't pretend to know
808
 
    # the kind of wt files, but it does.
809
 
    if parent_ie.kind != 'directory':
810
 
        # nb: this relies on someone else checking that the path we're using
811
 
        # doesn't contain symlinks.
812
 
        new_parent_ie = _mod_inventory.make_entry('directory', parent_ie.name,
813
 
            parent_ie.parent_id, parent_ie.file_id)
814
 
        del inv[parent_ie.file_id]
815
 
        inv.add(new_parent_ie)
816
 
        parent_ie = new_parent_ie
817
743
    file_id = file_id_callback(inv, parent_ie, path, kind)
818
744
    entry = inv.make_entry(kind, path.base_path, parent_ie.file_id,
819
745
        file_id=file_id)