~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/mutabletree.py

  • Committer: John Arbash Meinel
  • Date: 2011-05-11 11:35:28 UTC
  • mto: This revision was merged to the branch mainline in revision 5851.
  • Revision ID: john@arbash-meinel.com-20110511113528-qepibuwxicjrbb2h
Break compatibility with python <2.6.

This includes auditing the code for places where we were doing
explicit 'sys.version' checks and removing them as appropriate.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006-2010 Canonical Ltd
 
1
# Copyright (C) 2006-2011 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,
33
34
    osutils,
34
35
    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
 
82
94
    @needs_tree_write_lock
83
95
    def add(self, files, ids=None, kinds=None):
84
96
        """Add paths to the set of versioned paths.
148
160
        if sub_tree_id == self.get_root_id():
149
161
            raise errors.BadReferenceTarget(self, sub_tree,
150
162
                                     'Trees have the same root id.')
151
 
        if sub_tree_id in self.inventory:
 
163
        if sub_tree_id in self:
152
164
            raise errors.BadReferenceTarget(self, sub_tree,
153
165
                                            'Root id already present in tree')
154
166
        self._add([sub_tree_path], [sub_tree_id], ['tree-reference'])
163
175
        """
164
176
        raise NotImplementedError(self._add)
165
177
 
166
 
    @needs_tree_write_lock
167
178
    def apply_inventory_delta(self, changes):
168
179
        """Apply changes to the inventory as an atomic operation.
169
180
 
172
183
        :return None:
173
184
        :seealso Inventory.apply_delta: For details on the changes parameter.
174
185
        """
175
 
        self.flush()
176
 
        inv = self.inventory
177
 
        inv.apply_delta(changes)
178
 
        self._write_inventory(inv)
 
186
        raise NotImplementedError(self.apply_inventory_delta)
179
187
 
180
188
    @needs_write_lock
181
189
    def commit(self, message=None, revprops=None, *args,
182
190
               **kwargs):
183
191
        # avoid circular imports
184
192
        from bzrlib import commit
185
 
        if revprops is None:
186
 
            revprops = {}
187
193
        possible_master_transports=[]
188
 
        if not 'branch-nick' in revprops:
189
 
            revprops['branch-nick'] = self.branch._get_nick(
 
194
        revprops = commit.Commit.update_revprops(
 
195
                revprops,
 
196
                self.branch,
 
197
                kwargs.pop('authors', None),
 
198
                kwargs.pop('author', None),
190
199
                kwargs.get('local', False),
191
200
                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
218
201
        # args for wt.commit start at message from the Commit.commit method,
219
202
        args = (message, ) + args
220
203
        for hook in MutableTree.hooks['start_commit']:
358
341
        :return: None
359
342
        """
360
343
 
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
 
 
367
344
    @needs_write_lock
368
345
    def put_file_bytes_non_atomic(self, file_id, bytes):
369
346
        """Update the content of a file in the tree.
393
370
        """
394
371
        raise NotImplementedError(self.set_parent_trees)
395
372
 
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
 
 
 
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.)
403
453
        :param action: A reporter to be called with the inventory, parent_ie,
404
454
            path and kind of the path being added. It may return a file_id if
405
455
            a specific one should be used.
436
486
            for c in self.conflicts():
437
487
                conflicts_related.update(c.associated_filenames())
438
488
 
 
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
 
439
495
        # validate user file paths and convert all paths to tree
440
496
        # relative : it's cheaper to make a tree relative path an abspath
441
497
        # than to convert an abspath to tree relative, and it's cheaper to
561
617
                        this_ie = None
562
618
                    else:
563
619
                        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)
564
627
 
565
628
                for subf in sorted(os.listdir(abspath)):
566
629
                    # here we could use TreeDirectory rather than
630
693
        # TODO: Consider re-evaluating the need for this with CHKInventory
631
694
        # we don't strictly need to mutate an inventory for this
632
695
        # it only makes sense when apply_delta is cheaper than get_inventory()
633
 
        inventory = basis.inventory._get_mutable_inventory()
 
696
        inventory = _mod_inventory.mutable_inventory_from_tree(basis)
634
697
        basis.unlock()
635
698
        inventory.apply_delta(delta)
636
 
        rev_tree = revisiontree.RevisionTree(self.branch.repository,
 
699
        rev_tree = revisiontree.InventoryRevisionTree(self.branch.repository,
637
700
                                             inventory, new_revid)
638
701
        self.set_parent_trees([(new_revid, rev_tree)])
639
702
 
647
710
        """Create the default hooks.
648
711
 
649
712
        """
650
 
        hooks.Hooks.__init__(self)
651
 
        self.create_hook(hooks.HookPoint('start_commit',
 
713
        hooks.Hooks.__init__(self, "bzrlib.mutabletree", "MutableTree.hooks")
 
714
        self.add_hook('start_commit',
652
715
            "Called before a commit is performed on a tree. The start commit "
653
716
            "hook is able to change the tree before the commit takes place. "
654
717
            "start_commit is called with the bzrlib.mutabletree.MutableTree "
655
 
            "that the commit is being performed on.", (1, 4), None))
656
 
        self.create_hook(hooks.HookPoint('post_commit',
 
718
            "that the commit is being performed on.", (1, 4))
 
719
        self.add_hook('post_commit',
657
720
            "Called after a commit is performed on a tree. The hook is "
658
721
            "called with a bzrlib.mutabletree.PostCommitHookParams object. "
659
722
            "The mutable tree the commit was performed on is available via "
660
 
            "the mutable_tree attribute of that object.", (2, 0), None))
 
723
            "the mutable_tree attribute of that object.", (2, 0))
661
724
 
662
725
 
663
726
# install the default hooks into the MutableTree class.
740
803
        file_id or None to generate a new file id
741
804
    :returns: None
742
805
    """
 
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
743
817
    file_id = file_id_callback(inv, parent_ie, path, kind)
744
818
    entry = inv.make_entry(kind, path.base_path, parent_ie.file_id,
745
819
        file_id=file_id)