/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

New method ``WorkingTree.flush()`` which will write the current memory
inventory out to disk. At the same time, read_working_inventory will
no longer trash the current tree inventory if it has been modified within
the current lock, and the tree will now ``flush()`` automatically on
``unlock()``. ``WorkingTree.set_root_id()`` has been updated to take
advantage of this functionality. (Robert Collins, John Arbash Meinel)

Show diffs side-by-side

added added

removed removed

Lines of Context:
260
260
            self.basedir = wt.basedir
261
261
            self._control_files = wt._control_files
262
262
            self._hashcache = wt._hashcache
263
 
            self._set_inventory(wt._inventory)
 
263
            self._set_inventory(wt._inventory, dirty=False)
264
264
            self._format = wt._format
265
265
            self.bzrdir = wt.bzrdir
266
266
        from bzrlib.hashcache import HashCache
308
308
            hc.write()
309
309
 
310
310
        if _inventory is None:
311
 
            self._set_inventory(self.read_working_inventory())
 
311
            self._inventory_is_modified = False
 
312
            self.read_working_inventory()
312
313
        else:
313
 
            self._set_inventory(_inventory)
 
314
            # the caller of __init__ has provided an inventory,
 
315
            # we assume they know what they are doing - as its only
 
316
            # the Format factory and creation methods that are
 
317
            # permitted to do this.
 
318
            self._set_inventory(_inventory, dirty=False)
314
319
 
315
320
    branch = property(
316
321
        fget=lambda self: self._branch,
331
336
        self._control_files.break_lock()
332
337
        self.branch.break_lock()
333
338
 
334
 
    def _set_inventory(self, inv):
 
339
    def _set_inventory(self, inv, dirty):
 
340
        """Set the internal cached inventory.
 
341
 
 
342
        :param inv: The inventory to set.
 
343
        :param dirty: A boolean indicating whether the inventory is the same
 
344
            logical inventory as whats on disk. If True the inventory is not
 
345
            the same and should be written to disk or data will be lost, if
 
346
            False then the inventory is the same as that on disk and any
 
347
            serialisation would be unneeded overhead.
 
348
        """
335
349
        assert inv.root is not None
336
350
        self._inventory = inv
 
351
        self._inventory_is_modified = dirty
337
352
 
338
353
    @staticmethod
339
354
    def open(path=None, _unsupported=False):
850
865
        else:
851
866
            return '?'
852
867
 
 
868
    def flush(self):
 
869
        """Write the in memory inventory to disk."""
 
870
        # TODO: Maybe this should only write on dirty ?
 
871
        if self._control_files._lock_mode != 'w':
 
872
            raise errors.NotWriteLocked(self)
 
873
        sio = StringIO()
 
874
        bzrlib.xml5.serializer_v5.write_inventory(self._inventory, sio)
 
875
        sio.seek(0)
 
876
        self._control_files.put('inventory', sio)
 
877
        self._inventory_is_modified = False
 
878
 
853
879
    def list_files(self, include_root=False):
854
880
        """Recursively list all files as (path, class, kind, id, entry).
855
881
 
1011
1037
        # create a file in this interval and then the rename might be
1012
1038
        # left half-done.  But we should have caught most problems.
1013
1039
        orig_inv = deepcopy(self.inventory)
 
1040
        original_modified = self._inventory_is_modified
1014
1041
        try:
 
1042
            if len(from_paths):
 
1043
                self._inventory_is_modified = True
1015
1044
            for f in from_paths:
1016
1045
                name_tail = splitpath(f)[-1]
1017
1046
                dest_path = pathjoin(to_name, name_tail)
1025
1054
                            ["rename rolled back"])
1026
1055
        except:
1027
1056
            # restore the inventory on error
1028
 
            self._set_inventory(orig_inv)
 
1057
            self._set_inventory(orig_inv, dirty=original_modified)
1029
1058
            raise
1030
1059
        self._write_inventory(inv)
1031
1060
        return result
1471
1500
        
1472
1501
    @needs_read_lock
1473
1502
    def read_working_inventory(self):
1474
 
        """Read the working inventory."""
 
1503
        """Read the working inventory.
 
1504
        
 
1505
        :raises errors.InventoryModified: When the current in memory
 
1506
            inventory has been modified, read_working_inventory will
 
1507
            fail.
 
1508
        """
 
1509
        # conceptually this should be an implementation detail of the tree. 
 
1510
        # XXX: Deprecate this.
1475
1511
        # ElementTree does its own conversion from UTF-8, so open in
1476
1512
        # binary.
 
1513
        if self._inventory_is_modified:
 
1514
            raise errors.InventoryModified(self)
1477
1515
        result = bzrlib.xml5.serializer_v5.read_inventory(
1478
1516
            self._control_files.get('inventory'))
1479
 
        self._set_inventory(result)
 
1517
        self._set_inventory(result, dirty=False)
1480
1518
        return result
1481
1519
 
1482
1520
    @needs_tree_write_lock
1571
1609
            file_id = ROOT_ID
1572
1610
        inv = self._inventory
1573
1611
        orig_root_id = inv.root.file_id
 
1612
        # TODO: it might be nice to exit early if there was nothing
 
1613
        # to do, saving us from trigger a sync on unlock.
 
1614
        self._inventory_is_modified = True
 
1615
        # we preserve the root inventory entry object, but
 
1616
        # unlinkit from the byid index
1574
1617
        del inv._byid[inv.root.file_id]
1575
1618
        inv.root.file_id = file_id
 
1619
        # and link it into the index with the new changed id.
1576
1620
        inv._byid[inv.root.file_id] = inv.root
 
1621
        # and finally update all children to reference the new id.
 
1622
        # XXX: this should be safe to just look at the root.children
 
1623
        # list, not the WHOLE INVENTORY.
1577
1624
        for fid in inv:
1578
1625
            entry = inv[fid]
1579
1626
            if entry.parent_id == orig_root_id:
1580
1627
                entry.parent_id = inv.root.file_id
1581
 
        self._write_inventory(inv)
1582
1628
 
1583
1629
    def unlock(self):
1584
1630
        """See Branch.unlock.
1681
1727
    @needs_tree_write_lock
1682
1728
    def _write_inventory(self, inv):
1683
1729
        """Write inventory as the current inventory."""
1684
 
        sio = StringIO()
1685
 
        bzrlib.xml5.serializer_v5.write_inventory(inv, sio)
1686
 
        sio.seek(0)
1687
 
        self._control_files.put('inventory', sio)
1688
 
        self._set_inventory(inv)
1689
 
        mutter('wrote working inventory')
 
1730
        self._set_inventory(inv, dirty=True)
 
1731
        self.flush()
1690
1732
 
1691
1733
    def set_conflicts(self, arg):
1692
1734
        raise UnsupportedOperation(self.set_conflicts, self)
1743
1785
 
1744
1786
    def unlock(self):
1745
1787
        # we share control files:
1746
 
        if self._hashcache.needs_write and self._control_files._lock_count==3:
1747
 
            self._hashcache.write()
 
1788
        if self._control_files._lock_count == 3:
 
1789
            # _inventory_is_modified is always False during a read lock.
 
1790
            if self._inventory_is_modified:
 
1791
                self.flush()
 
1792
            if self._hashcache.needs_write:
 
1793
                self._hashcache.write()
1748
1794
        # reverse order of locking.
1749
1795
        try:
1750
1796
            return self._control_files.unlock()
1808
1854
        return ConflictList.from_stanzas(RioReader(confile))
1809
1855
 
1810
1856
    def unlock(self):
1811
 
        if self._hashcache.needs_write and self._control_files._lock_count==1:
1812
 
            self._hashcache.write()
 
1857
        if self._control_files._lock_count == 1:
 
1858
            # _inventory_is_modified is always False during a read lock.
 
1859
            if self._inventory_is_modified:
 
1860
                self.flush()
 
1861
            if self._hashcache.needs_write:
 
1862
                self._hashcache.write()
1813
1863
        # reverse order of locking.
1814
1864
        try:
1815
1865
            return self._control_files.unlock()
1961
2011
                         _internal=True,
1962
2012
                         _format=self,
1963
2013
                         _bzrdir=a_bzrdir)
1964
 
        wt._write_inventory(inv)
1965
2014
        wt.set_root_id(inv.root.file_id)
1966
2015
        basis_tree = branch.repository.revision_tree(revision)
1967
2016
        wt.set_parent_trees([(revision, basis_tree)])
2033
2082
        branch = a_bzrdir.open_branch()
2034
2083
        if revision_id is None:
2035
2084
            revision_id = branch.last_revision()
2036
 
        inv = Inventory() 
 
2085
        inv = Inventory()
2037
2086
        wt = WorkingTree3(a_bzrdir.root_transport.local_abspath('.'),
2038
2087
                         branch,
2039
2088
                         inv,
2043
2092
                         _control_files=control_files)
2044
2093
        wt.lock_tree_write()
2045
2094
        try:
2046
 
            wt._write_inventory(inv)
 
2095
            # set_root_id will write the inventory to disk.
2047
2096
            wt.set_root_id(inv.root.file_id)
2048
2097
            basis_tree = branch.repository.revision_tree(revision_id)
2049
2098
            if revision_id == bzrlib.revision.NULL_REVISION: