/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/workingtree.py

Merge from TestCaseWithMemoryTransport.

Show diffs side-by-side

added added

removed removed

Lines of Context:
72
72
from bzrlib.lockdir import LockDir
73
73
from bzrlib.merge import merge_inner, transform_tree
74
74
import bzrlib.mutabletree
 
75
from bzrlib.mutabletree import needs_tree_write_lock
75
76
from bzrlib.osutils import (
76
77
                            abspath,
77
78
                            compact_date,
98
99
        deprecated_function,
99
100
        DEPRECATED_PARAMETER,
100
101
        zero_eight,
 
102
        zero_eleven,
101
103
        )
102
104
from bzrlib.trace import mutter, note
103
105
from bzrlib.transform import build_tree
387
389
        If the left most parent is a ghost then the returned tree will be an
388
390
        empty tree - one obtained by calling repository.revision_tree(None).
389
391
        """
390
 
        revision_id = self.last_revision()
391
 
        if revision_id is not None:
 
392
        try:
 
393
            revision_id = self.get_parent_ids()[0]
 
394
        except IndexError:
 
395
            # no parents, return an empty revision tree.
 
396
            # in the future this should return the tree for
 
397
            # 'empty:' - the implicit root empty tree.
 
398
            return self.branch.repository.revision_tree(None)
 
399
        else:
392
400
            try:
393
401
                xml = self.read_basis_inventory()
394
 
                inv = bzrlib.xml5.serializer_v5.read_inventory_from_string(xml)
395
 
                inv.root.revision = revision_id
396
 
            except NoSuchFile:
397
 
                inv = None
398
 
            if inv is not None and inv.revision_id == revision_id:
399
 
                return bzrlib.revisiontree.RevisionTree(self.branch.repository,
400
 
                    inv, revision_id)
401
 
        # FIXME? RBC 20060403 should we cache the inventory here ?
 
402
                inv = bzrlib.xml6.serializer_v6.read_inventory_from_string(xml)
 
403
                if inv is not None and inv.revision_id == revision_id:
 
404
                    return bzrlib.tree.RevisionTree(self.branch.repository, 
 
405
                                                    inv, revision_id)
 
406
            except (NoSuchFile, errors.BadInventoryFormat):
 
407
                pass
 
408
        # No cached copy available, retrieve from the repository.
 
409
        # FIXME? RBC 20060403 should we cache the inventory locally
 
410
        # at this point ?
402
411
        try:
403
412
            return self.branch.repository.revision_tree(revision_id)
404
413
        except errors.RevisionNotPresent:
474
483
        This implementation reads the pending merges list and last_revision
475
484
        value and uses that to decide what the parents list should be.
476
485
        """
477
 
        last_rev = self.last_revision()
 
486
        last_rev = self._last_revision()
478
487
        if last_rev is None:
479
488
            parents = []
480
489
        else:
589
598
                inv.add_path(f, kind=kind, file_id=file_id)
590
599
        self._write_inventory(inv)
591
600
 
 
601
    @needs_tree_write_lock
592
602
    def _gather_kinds(self, files, kinds):
593
603
        """See MutableTree._gather_kinds."""
594
604
        for pos, f in enumerate(files):
616
626
        self.set_parent_ids(parents,
617
627
            allow_leftmost_as_ghost=len(parents) > 1 or allow_leftmost_as_ghost)
618
628
 
619
 
    @needs_write_lock
 
629
    @needs_tree_write_lock
620
630
    def add_parent_tree(self, parent_tuple, allow_leftmost_as_ghost=False):
621
631
        """Add revision_id, tree tuple as a parent.
622
632
 
638
648
        self.set_parent_ids(parent_ids,
639
649
            allow_leftmost_as_ghost=allow_leftmost_as_ghost)
640
650
 
641
 
    @needs_write_lock
 
651
    @needs_tree_write_lock
642
652
    def add_pending_merge(self, *revision_ids):
643
653
        # TODO: Perhaps should check at this point that the
644
654
        # history of the revision is actually present?
652
662
        if updated:
653
663
            self.set_parent_ids(parents, allow_leftmost_as_ghost=True)
654
664
 
 
665
    @deprecated_method(zero_eleven)
655
666
    @needs_read_lock
656
667
    def pending_merges(self):
657
668
        """Return a list of pending merges.
658
669
 
659
670
        These are revisions that have been merged into the working
660
671
        directory but not yet committed.
 
672
 
 
673
        As of 0.11 this is deprecated. Please see WorkingTree.get_parent_ids()
 
674
        instead - which is available on all tree objects.
661
675
        """
662
676
        return self.get_parent_ids()[1:]
663
677
 
664
 
    @needs_write_lock
 
678
    @needs_tree_write_lock
665
679
    def set_parent_ids(self, revision_ids, allow_leftmost_as_ghost=False):
666
680
        """Set the parent ids to revision_ids.
667
681
        
685
699
        merges = revision_ids[1:]
686
700
        self._control_files.put_utf8('pending-merges', '\n'.join(merges))
687
701
 
688
 
    @needs_write_lock
 
702
    @needs_tree_write_lock
689
703
    def set_parent_trees(self, parents_list, allow_leftmost_as_ghost=False):
690
704
        """See MutableTree.set_parent_trees."""
691
705
        # parent trees are not used in current format trees, delegate to
693
707
        self.set_parent_ids([rev for (rev, tree) in parents_list],
694
708
            allow_leftmost_as_ghost=allow_leftmost_as_ghost)
695
709
 
696
 
    @needs_write_lock
 
710
    @needs_tree_write_lock
697
711
    def set_pending_merges(self, rev_list):
698
712
        parents = self.get_parent_ids()
699
713
        leftmost = parents[:1]
700
714
        new_parents = leftmost + rev_list
701
715
        self.set_parent_ids(new_parents)
702
716
 
703
 
    @needs_write_lock
 
717
    @needs_tree_write_lock
704
718
    def set_merge_modified(self, modified_hashes):
705
719
        def iter_stanzas():
706
720
            for file_id, hash in modified_hashes.iteritems():
707
721
                yield Stanza(file_id=file_id, hash=hash)
708
722
        self._put_rio('merge-hashes', iter_stanzas(), MERGE_MODIFIED_HEADER_1)
709
723
 
710
 
    @needs_write_lock
 
724
    @needs_tree_write_lock
711
725
    def _put_rio(self, filename, stanzas, header):
712
726
        my_file = rio_file(stanzas, header)
713
727
        self._control_files.put(filename, my_file)
714
728
 
715
 
    @needs_write_lock
 
729
    @needs_write_lock # because merge pulls data into the branch.
716
730
    def merge_from_branch(self, branch, to_revision=None):
717
731
        """Merge from a branch into this working tree.
718
732
 
905
919
                # if we finished all children, pop it off the stack
906
920
                stack.pop()
907
921
 
908
 
 
909
 
    @needs_write_lock
 
922
    @needs_tree_write_lock
910
923
    def move(self, from_paths, to_name):
911
924
        """Rename files.
912
925
 
931
944
        if not self.has_filename(to_name):
932
945
            raise BzrError("destination %r not in working directory" % to_abs)
933
946
        to_dir_id = inv.path2id(to_name)
934
 
        if to_dir_id == None and to_name != '':
 
947
        if to_dir_id is None and to_name != '':
935
948
            raise BzrError("destination %r is not a versioned directory" % to_name)
936
949
        to_dir_ie = inv[to_dir_id]
937
950
        if to_dir_ie.kind != 'directory':
943
956
            if not self.has_filename(f):
944
957
                raise BzrError("%r does not exist in working tree" % f)
945
958
            f_id = inv.path2id(f)
946
 
            if f_id == None:
 
959
            if f_id is None:
947
960
                raise BzrError("%r is not versioned" % f)
948
961
            name_tail = splitpath(f)[-1]
949
962
            dest_path = pathjoin(to_name, name_tail)
975
988
        self._write_inventory(inv)
976
989
        return result
977
990
 
978
 
    @needs_write_lock
 
991
    @needs_tree_write_lock
979
992
    def rename_one(self, from_rel, to_rel):
980
993
        """Rename one file.
981
994
 
988
1001
            raise BzrError("can't rename: new working file %r already exists" % to_rel)
989
1002
 
990
1003
        file_id = inv.path2id(from_rel)
991
 
        if file_id == None:
 
1004
        if file_id is None:
992
1005
            raise BzrError("can't rename: old name %r is not versioned" % from_rel)
993
1006
 
994
1007
        entry = inv[file_id]
1000
1013
 
1001
1014
        to_dir, to_tail = os.path.split(to_rel)
1002
1015
        to_dir_id = inv.path2id(to_dir)
1003
 
        if to_dir_id == None and to_dir != '':
 
1016
        if to_dir_id is None and to_dir != '':
1004
1017
            raise BzrError("can't determine destination directory id for %r" % to_dir)
1005
1018
 
1006
1019
        mutter("rename_one:")
1034
1047
            if not self.is_ignored(subp):
1035
1048
                yield subp
1036
1049
    
1037
 
    @needs_write_lock
 
1050
    @needs_tree_write_lock
1038
1051
    def unversion(self, file_ids):
1039
1052
        """Remove the file ids in file_ids from the current versioned set.
1040
1053
 
1225
1238
        """Yield list of PATH, IGNORE_PATTERN"""
1226
1239
        for subp in self.extras():
1227
1240
            pat = self.is_ignored(subp)
1228
 
            if pat != None:
 
1241
            if pat is not None:
1229
1242
                yield subp, pat
1230
1243
 
1231
1244
    def get_ignore_list(self):
1297
1310
    def kind(self, file_id):
1298
1311
        return file_kind(self.id2abspath(file_id))
1299
1312
 
1300
 
    @needs_read_lock
1301
1313
    def last_revision(self):
1302
1314
        """Return the last revision of the branch for this tree.
1303
1315
 
1306
1318
 
1307
1319
        See MutableTree.last_revision
1308
1320
        """
 
1321
        return self._last_revision()
 
1322
 
 
1323
    @needs_read_lock
 
1324
    def _last_revision(self):
 
1325
        """helper for get_parent_ids."""
1309
1326
        return self.branch.last_revision()
1310
1327
 
1311
1328
    def is_locked(self):
1320
1337
            self.branch.unlock()
1321
1338
            raise
1322
1339
 
 
1340
    def lock_tree_write(self):
 
1341
        """See MutableTree.lock_tree_write, and WorkingTree.unlock."""
 
1342
        self.branch.lock_read()
 
1343
        try:
 
1344
            return self._control_files.lock_write()
 
1345
        except:
 
1346
            self.branch.unlock()
 
1347
            raise
 
1348
 
1323
1349
    def lock_write(self):
1324
1350
        """See MutableTree.lock_write, and WorkingTree.unlock."""
1325
1351
        self.branch.lock_write()
1333
1359
        return self._control_files.get_physical_lock_status()
1334
1360
 
1335
1361
    def _basis_inventory_name(self):
1336
 
        return 'basis-inventory'
 
1362
        return 'basis-inventory-cache'
1337
1363
 
1338
 
    @needs_write_lock
 
1364
    @needs_tree_write_lock
1339
1365
    def set_last_revision(self, new_revision):
1340
1366
        """Change the last revision in the working tree."""
1341
1367
        if self._change_last_revision(new_revision):
1374
1400
            # root node id can legitimately look like 'revision_id' but cannot
1375
1401
            # contain a '"'.
1376
1402
            xml = self.branch.repository.get_inventory_xml(new_revision)
1377
 
            if not 'revision_id="' in xml.split('\n', 1)[0]:
 
1403
            firstline = xml.split('\n', 1)[0]
 
1404
            if (not 'revision_id="' in firstline or 
 
1405
                'format="6"' not in firstline):
1378
1406
                inv = self.branch.repository.deserialise_inventory(
1379
1407
                    new_revision, xml)
1380
1408
                inv.revision_id = new_revision
1381
 
                xml = bzrlib.xml5.serializer_v5.write_inventory_to_string(inv)
 
1409
                xml = bzrlib.xml6.serializer_v6.write_inventory_to_string(inv)
1382
1410
            assert isinstance(xml, str), 'serialised xml must be bytestring.'
1383
1411
            path = self._basis_inventory_name()
1384
1412
            sio = StringIO(xml)
1401
1429
        self._set_inventory(result)
1402
1430
        return result
1403
1431
 
1404
 
    @needs_write_lock
 
1432
    @needs_tree_write_lock
1405
1433
    def remove(self, files, verbose=False, to_file=None):
1406
1434
        """Remove nominated files from the working inventory..
1407
1435
 
1441
1469
 
1442
1470
        self._write_inventory(inv)
1443
1471
 
1444
 
    @needs_write_lock
 
1472
    @needs_tree_write_lock
1445
1473
    def revert(self, filenames, old_tree=None, backups=True, 
1446
1474
               pb=DummyProgress()):
1447
1475
        from transform import revert
1458
1486
 
1459
1487
    # XXX: This method should be deprecated in favour of taking in a proper
1460
1488
    # new Inventory object.
1461
 
    @needs_write_lock
 
1489
    @needs_tree_write_lock
1462
1490
    def set_inventory(self, new_inventory_list):
1463
1491
        from bzrlib.inventory import (Inventory,
1464
1492
                                      InventoryDirectory,
1481
1509
                raise BzrError("unknown kind %r" % kind)
1482
1510
        self._write_inventory(inv)
1483
1511
 
1484
 
    @needs_write_lock
 
1512
    @needs_tree_write_lock
1485
1513
    def set_root_id(self, file_id):
1486
1514
        """Set the root id for this tree."""
1487
1515
        inv = self.read_working_inventory()
1538
1566
        # local work is unreferenced and will appear to have been lost.
1539
1567
        # 
1540
1568
        result = 0
1541
 
        if self.last_revision() != self.branch.last_revision():
 
1569
        try:
 
1570
            last_rev = self.get_parent_ids()[0]
 
1571
        except IndexError:
 
1572
            last_rev = None
 
1573
        if last_rev != self.branch.last_revision():
1542
1574
            # merge tree state up to new branch tip.
1543
1575
            basis = self.basis_tree()
1544
1576
            to_tree = self.branch.basis_tree()
1562
1594
                parent_trees.append(
1563
1595
                    (old_tip, self.branch.repository.revision_tree(old_tip)))
1564
1596
            self.set_parent_trees(parent_trees)
 
1597
            last_rev = parent_trees[0][0]
1565
1598
        else:
1566
1599
            # the working tree had the same last-revision as the master
1567
1600
            # branch did. We may still have pivot local work from the local
1568
1601
            # branch into old_tip:
1569
1602
            if old_tip is not None:
1570
1603
                self.add_parent_tree_id(old_tip)
1571
 
        if old_tip and old_tip != self.last_revision():
 
1604
        if old_tip and old_tip != last_rev:
1572
1605
            # our last revision was not the prior branch last revision
1573
1606
            # and we have converted that last revision to a pending merge.
1574
1607
            # base is somewhere between the branch tip now
1588
1621
                                  this_tree=self)
1589
1622
        return result
1590
1623
 
1591
 
    @needs_write_lock
 
1624
    @needs_tree_write_lock
1592
1625
    def _write_inventory(self, inv):
1593
1626
        """Write inventory as the current inventory."""
1594
1627
        sio = StringIO()
1638
1671
     - uses the branch last-revision.
1639
1672
    """
1640
1673
 
 
1674
    def lock_tree_write(self):
 
1675
        """See WorkingTree.lock_tree_write().
 
1676
 
 
1677
        In Format2 WorkingTrees we have a single lock for the branch and tree
 
1678
        so lock_tree_write() degrades to lock_write().
 
1679
        """
 
1680
        self.branch.lock_write()
 
1681
        try:
 
1682
            return self._control_files.lock_write()
 
1683
        except:
 
1684
            self.branch.unlock()
 
1685
            raise
 
1686
 
1641
1687
    def unlock(self):
1642
1688
        # we share control files:
1643
1689
        if self._hashcache.needs_write and self._control_files._lock_count==3:
1660
1706
    """
1661
1707
 
1662
1708
    @needs_read_lock
1663
 
    def last_revision(self):
 
1709
    def _last_revision(self):
1664
1710
        """See Mutable.last_revision."""
1665
1711
        try:
1666
1712
            return self._control_files.get_utf8('last-revision').read()
1679
1725
            self._control_files.put_utf8('last-revision', revision_id)
1680
1726
            return True
1681
1727
 
1682
 
    @needs_write_lock
 
1728
    @needs_tree_write_lock
1683
1729
    def set_conflicts(self, conflicts):
1684
1730
        self._put_rio('conflicts', conflicts.to_stanzas(), 
1685
1731
                      CONFLICT_HEADER_1)
1686
1732
 
1687
 
    @needs_write_lock
 
1733
    @needs_tree_write_lock
1688
1734
    def add_conflicts(self, new_conflicts):
1689
1735
        conflict_set = set(self.conflicts())
1690
1736
        conflict_set.update(set(list(new_conflicts)))
1938
1984
                         _format=self,
1939
1985
                         _bzrdir=a_bzrdir,
1940
1986
                         _control_files=control_files)
1941
 
        wt.lock_write()
 
1987
        wt.lock_tree_write()
1942
1988
        try:
1943
1989
            wt._write_inventory(inv)
1944
1990
            wt.set_root_id(inv.root.file_id)