~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/workingtree.py

(robertc) Partial fix for bug #39542 - allow lightweight checkouts over http.

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
 
609
622
            mode = os.lstat(self.abspath(path)).st_mode
610
623
            return bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
611
624
 
612
 
    @needs_write_lock
 
625
    @needs_tree_write_lock
613
626
    def add(self, files, ids=None):
614
627
        """Make files versioned.
615
628
 
670
683
 
671
684
        self._write_inventory(inv)
672
685
 
673
 
    @needs_write_lock
 
686
    @needs_tree_write_lock
674
687
    def add_parent_tree_id(self, revision_id, allow_leftmost_as_ghost=False):
675
688
        """Add revision_id as a parent.
676
689
 
686
699
        self.set_parent_ids(parents,
687
700
            allow_leftmost_as_ghost=len(parents) > 1 or allow_leftmost_as_ghost)
688
701
 
689
 
    @needs_write_lock
 
702
    @needs_tree_write_lock
690
703
    def add_parent_tree(self, parent_tuple, allow_leftmost_as_ghost=False):
691
704
        """Add revision_id, tree tuple as a parent.
692
705
 
708
721
        self.set_parent_ids(parent_ids,
709
722
            allow_leftmost_as_ghost=allow_leftmost_as_ghost)
710
723
 
711
 
    @needs_write_lock
 
724
    @needs_tree_write_lock
712
725
    def add_pending_merge(self, *revision_ids):
713
726
        # TODO: Perhaps should check at this point that the
714
727
        # history of the revision is actually present?
735
748
        """
736
749
        return self.get_parent_ids()[1:]
737
750
 
738
 
    @needs_write_lock
 
751
    @needs_tree_write_lock
739
752
    def set_parent_ids(self, revision_ids, allow_leftmost_as_ghost=False):
740
753
        """Set the parent ids to revision_ids.
741
754
        
759
772
        merges = revision_ids[1:]
760
773
        self._control_files.put_utf8('pending-merges', '\n'.join(merges))
761
774
 
762
 
    @needs_write_lock
 
775
    @needs_tree_write_lock
763
776
    def set_parent_trees(self, parents_list, allow_leftmost_as_ghost=False):
764
777
        """Set the parents of the working tree.
765
778
 
772
785
        self.set_parent_ids([rev for (rev, tree) in parents_list],
773
786
            allow_leftmost_as_ghost=allow_leftmost_as_ghost)
774
787
 
775
 
    @needs_write_lock
 
788
    @needs_tree_write_lock
776
789
    def set_pending_merges(self, rev_list):
777
790
        parents = self.get_parent_ids()
778
791
        leftmost = parents[:1]
779
792
        new_parents = leftmost + rev_list
780
793
        self.set_parent_ids(new_parents)
781
794
 
782
 
    @needs_write_lock
 
795
    @needs_tree_write_lock
783
796
    def set_merge_modified(self, modified_hashes):
784
797
        def iter_stanzas():
785
798
            for file_id, hash in modified_hashes.iteritems():
786
799
                yield Stanza(file_id=file_id, hash=hash)
787
800
        self._put_rio('merge-hashes', iter_stanzas(), MERGE_MODIFIED_HEADER_1)
788
801
 
789
 
    @needs_write_lock
 
802
    @needs_tree_write_lock
790
803
    def _put_rio(self, filename, stanzas, header):
791
804
        my_file = rio_file(stanzas, header)
792
805
        self._control_files.put(filename, my_file)
793
806
 
794
 
    @needs_write_lock
 
807
    @needs_write_lock # because merge pulls data into the branch.
795
808
    def merge_from_branch(self, branch, to_revision=None):
796
809
        """Merge from a branch into this working tree.
797
810
 
975
988
                # if we finished all children, pop it off the stack
976
989
                stack.pop()
977
990
 
978
 
 
979
 
    @needs_write_lock
 
991
    @needs_tree_write_lock
980
992
    def move(self, from_paths, to_name):
981
993
        """Rename files.
982
994
 
1045
1057
        self._write_inventory(inv)
1046
1058
        return result
1047
1059
 
1048
 
    @needs_write_lock
 
1060
    @needs_tree_write_lock
1049
1061
    def rename_one(self, from_rel, to_rel):
1050
1062
        """Rename one file.
1051
1063
 
1104
1116
            if not self.is_ignored(subp):
1105
1117
                yield subp
1106
1118
    
1107
 
    @needs_write_lock
 
1119
    @needs_tree_write_lock
1108
1120
    def unversion(self, file_ids):
1109
1121
        """Remove the file ids in file_ids from the current versioned set.
1110
1122
 
1386
1398
            self.branch.unlock()
1387
1399
            raise
1388
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
 
1389
1417
    def lock_write(self):
1390
1418
        """See Branch.lock_write, and WorkingTree.unlock."""
1391
1419
        self.branch.lock_write()
1401
1429
    def _basis_inventory_name(self):
1402
1430
        return 'basis-inventory-cache'
1403
1431
 
1404
 
    @needs_write_lock
 
1432
    @needs_tree_write_lock
1405
1433
    def set_last_revision(self, new_revision):
1406
1434
        """Change the last revision in the working tree."""
1407
1435
        if self._change_last_revision(new_revision):
1469
1497
        self._set_inventory(result)
1470
1498
        return result
1471
1499
 
1472
 
    @needs_write_lock
 
1500
    @needs_tree_write_lock
1473
1501
    def remove(self, files, verbose=False, to_file=None):
1474
1502
        """Remove nominated files from the working inventory..
1475
1503
 
1509
1537
 
1510
1538
        self._write_inventory(inv)
1511
1539
 
1512
 
    @needs_write_lock
 
1540
    @needs_tree_write_lock
1513
1541
    def revert(self, filenames, old_tree=None, backups=True, 
1514
1542
               pb=DummyProgress()):
1515
1543
        from transform import revert
1526
1554
 
1527
1555
    # XXX: This method should be deprecated in favour of taking in a proper
1528
1556
    # new Inventory object.
1529
 
    @needs_write_lock
 
1557
    @needs_tree_write_lock
1530
1558
    def set_inventory(self, new_inventory_list):
1531
1559
        from bzrlib.inventory import (Inventory,
1532
1560
                                      InventoryDirectory,
1549
1577
                raise BzrError("unknown kind %r" % kind)
1550
1578
        self._write_inventory(inv)
1551
1579
 
1552
 
    @needs_write_lock
 
1580
    @needs_tree_write_lock
1553
1581
    def set_root_id(self, file_id):
1554
1582
        """Set the root id for this tree."""
1555
1583
        inv = self.read_working_inventory()
1661
1689
                                  this_tree=self)
1662
1690
        return result
1663
1691
 
1664
 
    @needs_write_lock
 
1692
    @needs_tree_write_lock
1665
1693
    def _write_inventory(self, inv):
1666
1694
        """Write inventory as the current inventory."""
1667
1695
        sio = StringIO()
1711
1739
     - uses the branch last-revision.
1712
1740
    """
1713
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
 
1714
1755
    def unlock(self):
1715
1756
        # we share control files:
1716
1757
        if self._hashcache.needs_write and self._control_files._lock_count==3:
1752
1793
            self._control_files.put_utf8('last-revision', revision_id)
1753
1794
            return True
1754
1795
 
1755
 
    @needs_write_lock
 
1796
    @needs_tree_write_lock
1756
1797
    def set_conflicts(self, conflicts):
1757
1798
        self._put_rio('conflicts', conflicts.to_stanzas(), 
1758
1799
                      CONFLICT_HEADER_1)
1759
1800
 
1760
 
    @needs_write_lock
 
1801
    @needs_tree_write_lock
1761
1802
    def add_conflicts(self, new_conflicts):
1762
1803
        conflict_set = set(self.conflicts())
1763
1804
        conflict_set.update(set(list(new_conflicts)))
2011
2052
                         _format=self,
2012
2053
                         _bzrdir=a_bzrdir,
2013
2054
                         _control_files=control_files)
2014
 
        wt.lock_write()
 
2055
        wt.lock_tree_write()
2015
2056
        try:
2016
2057
            wt._write_inventory(inv)
2017
2058
            wt.set_root_id(inv.root.file_id)