~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/workingtree.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2006-09-16 14:03:54 UTC
  • mfrom: (2017.1.1 integration)
  • Revision ID: pqm@pqm.ubuntu.com-20060916140354-1a9932f525bb7182
(robertc) Add MemoryTree and TreeBuilder test helpers. Also test behavior of transport.has('/') which caused failures in this when merging, and as a result cleanup the sftp path normalisation logic.

Show diffs side-by-side

added added

removed removed

Lines of Context:
71
71
from bzrlib.lockable_files import LockableFiles, TransportLock
72
72
from bzrlib.lockdir import LockDir
73
73
from bzrlib.merge import merge_inner, transform_tree
 
74
import bzrlib.mutabletree
 
75
from bzrlib.mutabletree import needs_tree_write_lock
74
76
from bzrlib.osutils import (
75
77
                            abspath,
76
78
                            compact_date,
90
92
                            )
91
93
from bzrlib.progress import DummyProgress, ProgressPhase
92
94
from bzrlib.revision import NULL_REVISION
 
95
import bzrlib.revisiontree
93
96
from bzrlib.rio import RioReader, rio_file, Stanza
94
97
from bzrlib.symbol_versioning import (deprecated_passed,
95
98
        deprecated_method,
103
106
from bzrlib.transport import get_transport
104
107
from bzrlib.transport.local import LocalTransport
105
108
from bzrlib.textui import show_status
106
 
import bzrlib.tree
107
109
import bzrlib.ui
108
110
import bzrlib.xml5
109
111
 
159
161
    return gen_file_id('TREE_ROOT')
160
162
 
161
163
 
162
 
def needs_tree_write_lock(unbound):
163
 
    """Decorate unbound to take out and release a tree_write lock."""
164
 
    def tree_write_locked(self, *args, **kwargs):
165
 
        self.lock_tree_write()
166
 
        try:
167
 
            return unbound(self, *args, **kwargs)
168
 
        finally:
169
 
            self.unlock()
170
 
    tree_write_locked.__doc__ = unbound.__doc__
171
 
    tree_write_locked.__name__ = unbound.__name__
172
 
    return tree_write_locked
173
 
 
174
 
 
175
164
class TreeEntry(object):
176
165
    """An entry that implements the minimum interface used by commands.
177
166
 
227
216
        return ''
228
217
 
229
218
 
230
 
class WorkingTree(bzrlib.tree.Tree):
 
219
class WorkingTree(bzrlib.mutabletree.MutableTree):
231
220
    """Working copy tree.
232
221
 
233
222
    The inventory is held in the `Branch` working-inventory, and the
338
327
    def _set_inventory(self, inv):
339
328
        assert inv.root is not None
340
329
        self._inventory = inv
341
 
        self.path2id = self._inventory.path2id
342
 
 
343
 
    def is_control_filename(self, filename):
344
 
        """True if filename is the name of a control file in this tree.
345
 
        
346
 
        :param filename: A filename within the tree. This is a relative path
347
 
        from the root of this tree.
348
 
 
349
 
        This is true IF and ONLY IF the filename is part of the meta data
350
 
        that bzr controls in this tree. I.E. a random .bzr directory placed
351
 
        on disk will not be a control file for this tree.
352
 
        """
353
 
        return self.bzrdir.is_control_filename(filename)
354
330
 
355
331
    @staticmethod
356
332
    def open(path=None, _unsupported=False):
564
540
            transform_tree(tree, self)
565
541
            tree.set_parent_ids([revision_id])
566
542
 
567
 
    @needs_write_lock
568
 
    def commit(self, message=None, revprops=None, *args, **kwargs):
569
 
        # avoid circular imports
570
 
        from bzrlib.commit import Commit
571
 
        if revprops is None:
572
 
            revprops = {}
573
 
        if not 'branch-nick' in revprops:
574
 
            revprops['branch-nick'] = self.branch.nick
575
 
        # args for wt.commit start at message from the Commit.commit method,
576
 
        # but with branch a kwarg now, passing in args as is results in the
577
 
        #message being used for the branch
578
 
        args = (DEPRECATED_PARAMETER, message, ) + args
579
 
        committed_id = Commit().commit( working_tree=self, revprops=revprops,
580
 
            *args, **kwargs)
581
 
        return committed_id
582
 
 
583
543
    def id2abspath(self, file_id):
584
544
        return self.abspath(self.id2path(file_id))
585
545
 
622
582
            mode = os.lstat(self.abspath(path)).st_mode
623
583
            return bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
624
584
 
625
 
    @needs_tree_write_lock
626
 
    def add(self, files, ids=None):
627
 
        """Make files versioned.
628
 
 
629
 
        Note that the command line normally calls smart_add instead,
630
 
        which can automatically recurse.
631
 
 
632
 
        This adds the files to the inventory, so that they will be
633
 
        recorded by the next commit.
634
 
 
635
 
        files
636
 
            List of paths to add, relative to the base of the tree.
637
 
 
638
 
        ids
639
 
            If set, use these instead of automatically generated ids.
640
 
            Must be the same length as the list of files, but may
641
 
            contain None for ids that are to be autogenerated.
642
 
 
643
 
        TODO: Perhaps have an option to add the ids even if the files do
644
 
              not (yet) exist.
645
 
 
646
 
        TODO: Perhaps callback with the ids and paths as they're added.
647
 
        """
 
585
    @needs_write_lock
 
586
    def _add(self, files, ids, kinds):
 
587
        """See MutableTree._add."""
648
588
        # TODO: Re-adding a file that is removed in the working copy
649
589
        # should probably put it back with the previous ID.
650
 
        if isinstance(files, basestring):
651
 
            assert(ids is None or isinstance(ids, basestring))
652
 
            files = [files]
653
 
            if ids is not None:
654
 
                ids = [ids]
655
 
 
656
 
        if ids is None:
657
 
            ids = [None] * len(files)
658
 
        else:
659
 
            assert(len(ids) == len(files))
660
 
 
 
590
        # the read and write working inventory should not occur in this 
 
591
        # function - they should be part of lock_write and unlock.
661
592
        inv = self.read_working_inventory()
662
 
        for f,file_id in zip(files, ids):
663
 
            if self.is_control_filename(f):
664
 
                raise errors.ForbiddenControlFileError(filename=f)
665
 
 
666
 
            fp = splitpath(f)
667
 
 
668
 
            if len(fp) == 0:
669
 
                raise BzrError("cannot add top-level %r" % f)
670
 
 
671
 
            fullpath = normpath(self.abspath(f))
672
 
            try:
673
 
                kind = file_kind(fullpath)
674
 
            except OSError, e:
675
 
                if e.errno == errno.ENOENT:
676
 
                    raise NoSuchFile(fullpath)
677
 
            if not InventoryEntry.versionable_kind(kind):
678
 
                raise errors.BadFileKindError(filename=f, kind=kind)
 
593
        for f, file_id, kind in zip(files, ids, kinds):
 
594
            assert kind is not None
679
595
            if file_id is None:
680
596
                inv.add_path(f, kind=kind)
681
597
            else:
682
598
                inv.add_path(f, kind=kind, file_id=file_id)
683
 
 
684
599
        self._write_inventory(inv)
685
600
 
686
601
    @needs_tree_write_lock
 
602
    def _gather_kinds(self, files, kinds):
 
603
        """See MutableTree._gather_kinds."""
 
604
        for pos, f in enumerate(files):
 
605
            if kinds[pos] is None:
 
606
                fullpath = normpath(self.abspath(f))
 
607
                try:
 
608
                    kinds[pos] = file_kind(fullpath)
 
609
                except OSError, e:
 
610
                    if e.errno == errno.ENOENT:
 
611
                        raise NoSuchFile(fullpath)
 
612
 
 
613
    @needs_write_lock
687
614
    def add_parent_tree_id(self, revision_id, allow_leftmost_as_ghost=False):
688
615
        """Add revision_id as a parent.
689
616
 
774
701
 
775
702
    @needs_tree_write_lock
776
703
    def set_parent_trees(self, parents_list, allow_leftmost_as_ghost=False):
777
 
        """Set the parents of the working tree.
778
 
 
779
 
        :param parents_list: A list of (revision_id, tree) tuples. 
780
 
            If tree is None, then that element is treated as an unreachable
781
 
            parent tree - i.e. a ghost.
782
 
        """
 
704
        """See MutableTree.set_parent_trees."""
783
705
        # parent trees are not used in current format trees, delegate to
784
706
        # set_parent_ids
785
707
        self.set_parent_ids([rev for (rev, tree) in parents_list],
868
790
                merge_hashes[file_id] = hash
869
791
        return merge_hashes
870
792
 
 
793
    @needs_write_lock
 
794
    def mkdir(self, path, file_id=None):
 
795
        """See MutableTree.mkdir()."""
 
796
        if file_id is None:
 
797
            file_id = gen_file_id(os.path.basename(path))
 
798
        os.mkdir(self.abspath(path))
 
799
        self.add(path, file_id, 'directory')
 
800
        return file_id
 
801
 
871
802
    def get_symlink_target(self, file_id):
872
803
        return os.readlink(self.id2abspath(file_id))
873
804
 
1204
1135
            source.unlock()
1205
1136
            top_pb.finished()
1206
1137
 
 
1138
    @needs_write_lock
 
1139
    def put_file_bytes_non_atomic(self, file_id, bytes):
 
1140
        """See MutableTree.put_file_bytes_non_atomic."""
 
1141
        stream = file(self.id2abspath(file_id), 'wb')
 
1142
        try:
 
1143
            stream.write(bytes)
 
1144
        finally:
 
1145
            stream.close()
 
1146
        # TODO: update the hashcache here ?
 
1147
 
1207
1148
    def extras(self):
1208
1149
        """Yield all unknown files in this WorkingTree.
1209
1150
 
1370
1311
        return file_kind(self.id2abspath(file_id))
1371
1312
 
1372
1313
    def last_revision(self):
1373
 
        """Return the last revision id of this working tree.
1374
 
 
1375
 
        In early branch formats this was the same as the branch last_revision,
1376
 
        but that cannot be relied upon - for working tree operations,
1377
 
        always use tree.last_revision(). This returns the left most parent id,
1378
 
        or None if there are no parents.
1379
 
 
1380
 
        This was deprecated as of 0.11. Please use get_parent_ids instead.
 
1314
        """Return the last revision of the branch for this tree.
 
1315
 
 
1316
        This format tree does not support a separate marker for last-revision
 
1317
        compared to the branch.
 
1318
 
 
1319
        See MutableTree.last_revision
1381
1320
        """
1382
1321
        return self._last_revision()
1383
1322
 
1399
1338
            raise
1400
1339
 
1401
1340
    def lock_tree_write(self):
1402
 
        """Lock the working tree for write, and the branch for read.
1403
 
 
1404
 
        This is useful for operations which only need to mutate the working
1405
 
        tree. Taking out branch write locks is a relatively expensive process
1406
 
        and may fail if the branch is on read only media. So branch write locks
1407
 
        should only be taken out when we are modifying branch data - such as in
1408
 
        operations like commit, pull, uncommit and update.
1409
 
        """
 
1341
        """See MutableTree.lock_tree_write, and WorkingTree.unlock."""
1410
1342
        self.branch.lock_read()
1411
1343
        try:
1412
1344
            return self._control_files.lock_write()
1415
1347
            raise
1416
1348
 
1417
1349
    def lock_write(self):
1418
 
        """See Branch.lock_write, and WorkingTree.unlock."""
 
1350
        """See MutableTree.lock_write, and WorkingTree.unlock."""
1419
1351
        self.branch.lock_write()
1420
1352
        try:
1421
1353
            return self._control_files.lock_write()
1775
1707
 
1776
1708
    @needs_read_lock
1777
1709
    def _last_revision(self):
1778
 
        """See WorkingTree._last_revision."""
 
1710
        """See Mutable.last_revision."""
1779
1711
        try:
1780
1712
            return self._control_files.get_utf8('last-revision').read()
1781
1713
        except NoSuchFile: