~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/workingtree.py

Merge from bzr.dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
159
159
    return gen_file_id('TREE_ROOT')
160
160
 
161
161
 
 
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
 
162
175
class TreeEntry(object):
163
176
    """An entry that implements the minimum interface used by commands.
164
177
 
410
423
        else:
411
424
            try:
412
425
                xml = self.read_basis_inventory()
413
 
                inv = bzrlib.xml5.serializer_v5.read_inventory_from_string(xml)
414
 
                inv.root.revision = revision_id
415
 
            except NoSuchFile:
416
 
                inv = None
417
 
            if inv is not None and inv.revision_id == revision_id:
418
 
                return bzrlib.tree.RevisionTree(self.branch.repository, inv,
419
 
                                                revision_id)
 
426
                inv = bzrlib.xml6.serializer_v6.read_inventory_from_string(xml)
 
427
                if inv is not None and inv.revision_id == revision_id:
 
428
                    return bzrlib.tree.RevisionTree(self.branch.repository, 
 
429
                                                    inv, revision_id)
 
430
            except (NoSuchFile, errors.BadInventoryFormat):
 
431
                pass
420
432
        # No cached copy available, retrieve from the repository.
421
433
        # FIXME? RBC 20060403 should we cache the inventory locally
422
434
        # at this point ?
610
622
            mode = os.lstat(self.abspath(path)).st_mode
611
623
            return bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
612
624
 
613
 
    @needs_write_lock
 
625
    @needs_tree_write_lock
614
626
    def add(self, files, ids=None):
615
627
        """Make files versioned.
616
628
 
671
683
 
672
684
        self._write_inventory(inv)
673
685
 
674
 
    @needs_write_lock
 
686
    @needs_tree_write_lock
675
687
    def add_parent_tree_id(self, revision_id, allow_leftmost_as_ghost=False):
676
688
        """Add revision_id as a parent.
677
689
 
687
699
        self.set_parent_ids(parents,
688
700
            allow_leftmost_as_ghost=len(parents) > 1 or allow_leftmost_as_ghost)
689
701
 
690
 
    @needs_write_lock
 
702
    @needs_tree_write_lock
691
703
    def add_parent_tree(self, parent_tuple, allow_leftmost_as_ghost=False):
692
704
        """Add revision_id, tree tuple as a parent.
693
705
 
709
721
        self.set_parent_ids(parent_ids,
710
722
            allow_leftmost_as_ghost=allow_leftmost_as_ghost)
711
723
 
712
 
    @needs_write_lock
 
724
    @needs_tree_write_lock
713
725
    def add_pending_merge(self, *revision_ids):
714
726
        # TODO: Perhaps should check at this point that the
715
727
        # history of the revision is actually present?
736
748
        """
737
749
        return self.get_parent_ids()[1:]
738
750
 
739
 
    @needs_write_lock
 
751
    @needs_tree_write_lock
740
752
    def set_parent_ids(self, revision_ids, allow_leftmost_as_ghost=False):
741
753
        """Set the parent ids to revision_ids.
742
754
        
760
772
        merges = revision_ids[1:]
761
773
        self._control_files.put_utf8('pending-merges', '\n'.join(merges))
762
774
 
763
 
    @needs_write_lock
 
775
    @needs_tree_write_lock
764
776
    def set_parent_trees(self, parents_list, allow_leftmost_as_ghost=False):
765
777
        """Set the parents of the working tree.
766
778
 
773
785
        self.set_parent_ids([rev for (rev, tree) in parents_list],
774
786
            allow_leftmost_as_ghost=allow_leftmost_as_ghost)
775
787
 
776
 
    @needs_write_lock
 
788
    @needs_tree_write_lock
777
789
    def set_pending_merges(self, rev_list):
778
790
        parents = self.get_parent_ids()
779
791
        leftmost = parents[:1]
780
792
        new_parents = leftmost + rev_list
781
793
        self.set_parent_ids(new_parents)
782
794
 
783
 
    @needs_write_lock
 
795
    @needs_tree_write_lock
784
796
    def set_merge_modified(self, modified_hashes):
785
797
        def iter_stanzas():
786
798
            for file_id, hash in modified_hashes.iteritems():
787
799
                yield Stanza(file_id=file_id, hash=hash)
788
800
        self._put_rio('merge-hashes', iter_stanzas(), MERGE_MODIFIED_HEADER_1)
789
801
 
790
 
    @needs_write_lock
 
802
    @needs_tree_write_lock
791
803
    def _put_rio(self, filename, stanzas, header):
792
804
        my_file = rio_file(stanzas, header)
793
805
        self._control_files.put(filename, my_file)
794
806
 
795
 
    @needs_write_lock
 
807
    @needs_write_lock # because merge pulls data into the branch.
796
808
    def merge_from_branch(self, branch, to_revision=None):
797
809
        """Merge from a branch into this working tree.
798
810
 
976
988
                # if we finished all children, pop it off the stack
977
989
                stack.pop()
978
990
 
979
 
 
980
 
    @needs_write_lock
 
991
    @needs_tree_write_lock
981
992
    def move(self, from_paths, to_name):
982
993
        """Rename files.
983
994
 
1046
1057
        self._write_inventory(inv)
1047
1058
        return result
1048
1059
 
1049
 
    @needs_write_lock
 
1060
    @needs_tree_write_lock
1050
1061
    def rename_one(self, from_rel, to_rel):
1051
1062
        """Rename one file.
1052
1063
 
1105
1116
            if not self.is_ignored(subp):
1106
1117
                yield subp
1107
1118
    
1108
 
    @needs_write_lock
 
1119
    @needs_tree_write_lock
1109
1120
    def unversion(self, file_ids):
1110
1121
        """Remove the file ids in file_ids from the current versioned set.
1111
1122
 
1387
1398
            self.branch.unlock()
1388
1399
            raise
1389
1400
 
 
1401
    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
        """
 
1410
        self.branch.lock_read()
 
1411
        try:
 
1412
            return self._control_files.lock_write()
 
1413
        except:
 
1414
            self.branch.unlock()
 
1415
            raise
 
1416
 
1390
1417
    def lock_write(self):
1391
1418
        """See Branch.lock_write, and WorkingTree.unlock."""
1392
1419
        self.branch.lock_write()
1400
1427
        return self._control_files.get_physical_lock_status()
1401
1428
 
1402
1429
    def _basis_inventory_name(self):
1403
 
        return 'basis-inventory'
 
1430
        return 'basis-inventory-cache'
1404
1431
 
1405
 
    @needs_write_lock
 
1432
    @needs_tree_write_lock
1406
1433
    def set_last_revision(self, new_revision):
1407
1434
        """Change the last revision in the working tree."""
1408
1435
        if self._change_last_revision(new_revision):
1441
1468
            # root node id can legitimately look like 'revision_id' but cannot
1442
1469
            # contain a '"'.
1443
1470
            xml = self.branch.repository.get_inventory_xml(new_revision)
1444
 
            if not 'revision_id="' in xml.split('\n', 1)[0]:
 
1471
            firstline = xml.split('\n', 1)[0]
 
1472
            if (not 'revision_id="' in firstline or 
 
1473
                'format="6"' not in firstline):
1445
1474
                inv = self.branch.repository.deserialise_inventory(
1446
1475
                    new_revision, xml)
1447
1476
                inv.revision_id = new_revision
1448
 
                xml = bzrlib.xml5.serializer_v5.write_inventory_to_string(inv)
 
1477
                xml = bzrlib.xml6.serializer_v6.write_inventory_to_string(inv)
1449
1478
            assert isinstance(xml, str), 'serialised xml must be bytestring.'
1450
1479
            path = self._basis_inventory_name()
1451
1480
            sio = StringIO(xml)
1468
1497
        self._set_inventory(result)
1469
1498
        return result
1470
1499
 
1471
 
    @needs_write_lock
 
1500
    @needs_tree_write_lock
1472
1501
    def remove(self, files, verbose=False, to_file=None):
1473
1502
        """Remove nominated files from the working inventory..
1474
1503
 
1508
1537
 
1509
1538
        self._write_inventory(inv)
1510
1539
 
1511
 
    @needs_write_lock
 
1540
    @needs_tree_write_lock
1512
1541
    def revert(self, filenames, old_tree=None, backups=True, 
1513
1542
               pb=DummyProgress()):
1514
1543
        from transform import revert
1525
1554
 
1526
1555
    # XXX: This method should be deprecated in favour of taking in a proper
1527
1556
    # new Inventory object.
1528
 
    @needs_write_lock
 
1557
    @needs_tree_write_lock
1529
1558
    def set_inventory(self, new_inventory_list):
1530
1559
        from bzrlib.inventory import (Inventory,
1531
1560
                                      InventoryDirectory,
1548
1577
                raise BzrError("unknown kind %r" % kind)
1549
1578
        self._write_inventory(inv)
1550
1579
 
1551
 
    @needs_write_lock
 
1580
    @needs_tree_write_lock
1552
1581
    def set_root_id(self, file_id):
1553
1582
        """Set the root id for this tree."""
1554
1583
        inv = self.read_working_inventory()
1660
1689
                                  this_tree=self)
1661
1690
        return result
1662
1691
 
1663
 
    @needs_write_lock
 
1692
    @needs_tree_write_lock
1664
1693
    def _write_inventory(self, inv):
1665
1694
        """Write inventory as the current inventory."""
1666
1695
        sio = StringIO()
1710
1739
     - uses the branch last-revision.
1711
1740
    """
1712
1741
 
 
1742
    def lock_tree_write(self):
 
1743
        """See WorkingTree.lock_tree_write().
 
1744
 
 
1745
        In Format2 WorkingTrees we have a single lock for the branch and tree
 
1746
        so lock_tree_write() degrades to lock_write().
 
1747
        """
 
1748
        self.branch.lock_write()
 
1749
        try:
 
1750
            return self._control_files.lock_write()
 
1751
        except:
 
1752
            self.branch.unlock()
 
1753
            raise
 
1754
 
1713
1755
    def unlock(self):
1714
1756
        # we share control files:
1715
1757
        if self._hashcache.needs_write and self._control_files._lock_count==3:
1751
1793
            self._control_files.put_utf8('last-revision', revision_id)
1752
1794
            return True
1753
1795
 
1754
 
    @needs_write_lock
 
1796
    @needs_tree_write_lock
1755
1797
    def set_conflicts(self, conflicts):
1756
1798
        self._put_rio('conflicts', conflicts.to_stanzas(), 
1757
1799
                      CONFLICT_HEADER_1)
1758
1800
 
1759
 
    @needs_write_lock
 
1801
    @needs_tree_write_lock
1760
1802
    def add_conflicts(self, new_conflicts):
1761
1803
        conflict_set = set(self.conflicts())
1762
1804
        conflict_set.update(set(list(new_conflicts)))
2010
2052
                         _format=self,
2011
2053
                         _bzrdir=a_bzrdir,
2012
2054
                         _control_files=control_files)
2013
 
        wt.lock_write()
 
2055
        wt.lock_tree_write()
2014
2056
        try:
2015
2057
            wt._write_inventory(inv)
2016
2058
            wt.set_root_id(inv.root.file_id)