~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/workingtree_4.py

merge dirstate

Show diffs side-by-side

added added

removed removed

Lines of Context:
121
121
        """
122
122
        self._format = _format
123
123
        self.bzrdir = _bzrdir
124
 
        from bzrlib.hashcache import HashCache
125
124
        from bzrlib.trace import note, mutter
126
125
        assert isinstance(basedir, basestring), \
127
126
            "base directory %r is not a string" % basedir
136
135
        assert isinstance(_control_files, LockableFiles), \
137
136
            "_control_files must be a LockableFiles, not %r" % _control_files
138
137
        self._control_files = _control_files
139
 
        # update the whole cache up front and write to disk if anything changed;
140
 
        # in the future we might want to do this more selectively
141
 
        # two possible ways offer themselves : in self._unlock, write the cache
142
 
        # if needed, or, when the cache sees a change, append it to the hash
143
 
        # cache file, and have the parser take the most recent entry for a
144
 
        # given path only.
145
 
        cache_filename = self.bzrdir.get_workingtree_transport(None).local_abspath('stat-cache')
146
 
        hc = self._hashcache = HashCache(basedir, cache_filename, self._control_files._file_mode)
147
 
        hc.read()
148
 
        # is this scan needed ? it makes things kinda slow.
149
 
        #hc.scan()
150
 
 
151
 
        if hc.needs_write:
152
 
            mutter("write hc")
153
 
            hc.write()
154
 
 
155
138
        self._dirty = None
156
139
        #-------------
157
140
        # during a read or write lock these objects are set, and are
253
236
        return result
254
237
 
255
238
    def current_dirstate(self):
256
 
        """Return the current dirstate object. 
 
239
        """Return the current dirstate object.
257
240
 
258
241
        This is not part of the tree interface and only exposed for ease of
259
242
        testing.
260
243
 
261
 
        :raises errors.NotWriteLocked: when not in a lock. 
 
244
        :raises errors.NotWriteLocked: when not in a lock.
262
245
        """
263
246
        self._must_be_locked()
264
247
        return self._current_dirstate()
265
248
 
266
249
    def _current_dirstate(self):
267
250
        """Internal function that does not check lock status.
268
 
        
 
251
 
269
252
        This is needed for break_lock which also needs the dirstate.
270
253
        """
271
254
        if self._dirstate is not None:
380
363
 
381
364
    def get_file_sha1(self, file_id, path=None, stat_value=None):
382
365
        # check file id is valid unconditionally.
383
 
        key, details = self._get_entry(file_id=file_id, path=path)
384
 
        assert key is not None, 'what error should this raise'
 
366
        entry = self._get_entry(file_id=file_id, path=path)
 
367
        assert entry[0] is not None, 'what error should this raise'
385
368
        # TODO:
386
369
        # if row stat is valid, use cached sha1, else, get a new sha1.
387
370
        if path is None:
388
 
            path = pathjoin(key[0], key[1]).decode('utf8')
389
 
        return self._hashcache.get_sha1(path, stat_value)
 
371
            path = pathjoin(entry[0][0], entry[0][1]).decode('utf8')
 
372
 
 
373
        file_abspath = self.abspath(path)
 
374
        state = self.current_dirstate()
 
375
        link_or_sha1 = state.update_entry(entry, file_abspath,
 
376
                                          stat_value=stat_value)
 
377
        if entry[1][0][0] == 'f':
 
378
            return link_or_sha1
 
379
        return None
390
380
 
391
381
    def _get_inventory(self):
392
382
        """Get the inventory for the tree. This is only valid within a lock."""
483
473
            return None
484
474
 
485
475
    def lock_read(self):
486
 
        super(WorkingTree4, self).lock_read()
487
 
        if self._dirstate is None:
488
 
            self.current_dirstate()
489
 
            self._dirstate.lock_read()
 
476
        """See Branch.lock_read, and WorkingTree.unlock."""
 
477
        self.branch.lock_read()
 
478
        try:
 
479
            self._control_files.lock_read()
 
480
            try:
 
481
                state = self.current_dirstate()
 
482
                if not state._lock_token:
 
483
                    state.lock_read()
 
484
            except:
 
485
                self._control_files.unlock()
 
486
                raise
 
487
        except:
 
488
            self.branch.unlock()
 
489
            raise
 
490
 
 
491
    def _lock_self_write(self):
 
492
        """This should be called after the branch is locked."""
 
493
        try:
 
494
            self._control_files.lock_write()
 
495
            try:
 
496
                state = self.current_dirstate()
 
497
                if not state._lock_token:
 
498
                    state.lock_write()
 
499
            except:
 
500
                self._control_files.unlock()
 
501
                raise
 
502
        except:
 
503
            self.branch.unlock()
 
504
            raise
490
505
 
491
506
    def lock_tree_write(self):
492
 
        super(WorkingTree4, self).lock_tree_write()
493
 
        if self._dirstate is None:
494
 
            self.current_dirstate()
495
 
            self._dirstate.lock_write()
 
507
        """See MutableTree.lock_tree_write, and WorkingTree.unlock."""
 
508
        self.branch.lock_read()
 
509
        self._lock_self_write()
496
510
 
497
511
    def lock_write(self):
498
 
        super(WorkingTree4, self).lock_write()
499
 
        if self._dirstate is None:
500
 
            self.current_dirstate()
501
 
            self._dirstate.lock_write()
 
512
        """See MutableTree.lock_write, and WorkingTree.unlock."""
 
513
        self.branch.lock_write()
 
514
        self._lock_self_write()
502
515
 
503
516
    @needs_tree_write_lock
504
517
    def move(self, from_paths, to_dir, after=False):
982
995
    def unlock(self):
983
996
        """Unlock in format 4 trees needs to write the entire dirstate."""
984
997
        if self._control_files._lock_count == 1:
985
 
            self._write_hashcache_if_dirty()
986
998
            # eventually we should do signature checking during read locks for
987
999
            # dirstate updates.
988
1000
            if self._control_files._lock_mode == 'w':
989
1001
                if self._dirty:
990
1002
                    self.flush()
991
1003
            if self._dirstate is not None:
 
1004
                # This is a no-op if there are no modifications.
 
1005
                self._dirstate.save()
992
1006
                self._dirstate.unlock()
 
1007
            # TODO: jam 20070301 We shouldn't have to wipe the dirstate at this
 
1008
            #       point. Instead, it could check if the header has been
 
1009
            #       modified when it is locked, and if not, it can hang on to
 
1010
            #       the data it has in memory.
993
1011
            self._dirstate = None
994
1012
            self._inventory = None
995
1013
        # reverse order of locking.
1090
1108
        self.flush()
1091
1109
 
1092
1110
 
1093
 
 
1094
1111
class WorkingTreeFormat4(WorkingTreeFormat3):
1095
1112
    """The first consolidated dirstate working tree format.
1096
1113
 
1337
1354
        return self._repository.get_revision(last_changed_revision).timestamp
1338
1355
 
1339
1356
    def get_file_sha1(self, file_id, path=None, stat_value=None):
1340
 
        # TODO: if path is present, fast-path on that, as inventory
1341
 
        # might not be present
1342
 
        ie = self.inventory[file_id]
1343
 
        if ie.kind == "file":
1344
 
            return ie.text_sha1
 
1357
        entry = self._get_entry(file_id=file_id, path=path)
 
1358
        parent_index = self._get_parent_index()
 
1359
        parent_details = entry[1][parent_index]
 
1360
        if parent_details[0] == 'f':
 
1361
            return parent_details[1]
1345
1362
        return None
1346
1363
 
1347
1364
    def get_file(self, file_id):
1498
1515
 
1499
1516
    def _iter_changes(self, include_unchanged=False,
1500
1517
                      specific_files=None, pb=None, extra_trees=[],
1501
 
                      require_versioned=True):
 
1518
                      require_versioned=True, want_unversioned=False):
1502
1519
        """Return the changes from source to target.
1503
1520
 
1504
1521
        :return: An iterator that yields tuples. See InterTree._iter_changes
1514
1531
        :param require_versioned: If True, all files in specific_files must be
1515
1532
            versioned in one of source, target, extra_trees or
1516
1533
            PathsNotVersionedError is raised.
 
1534
        :param want_unversioned: Should unversioned files be returned in the
 
1535
            output. An unversioned file is defined as one with (False, False)
 
1536
            for the versioned pair.
1517
1537
        """
1518
1538
        utf8_decode = cache_utf8._utf8_decode
1519
1539
        _minikind_to_kind = dirstate.DirState._minikind_to_kind
1658
1678
            :param path_info: top_relpath, basename, kind, lstat, abspath for
1659
1679
                the path of entry. If None, then the path is considered absent.
1660
1680
                (Perhaps we should pass in a concrete entry for this ?)
 
1681
                Basename is returned as a utf8 string because we expect this
 
1682
                tuple will be ignored, and don't want to take the time to
 
1683
                decode.
1661
1684
            """
1662
1685
            # TODO: when a parent has been renamed, dont emit path renames for children,
1663
1686
            if source_index is None:
1665
1688
            else:
1666
1689
                source_details = entry[1][source_index]
1667
1690
            target_details = entry[1][target_index]
 
1691
            target_minikind = target_details[0]
 
1692
            if path_info is not None and target_minikind in 'fdl':
 
1693
                assert target_index == 0
 
1694
                link_or_sha1 = state.update_entry(entry, abspath=path_info[4],
 
1695
                                                  stat_value=path_info[3])
 
1696
                # The entry may have been modified by update_entry
 
1697
                target_details = entry[1][target_index]
 
1698
                target_minikind = target_details[0]
 
1699
            else:
 
1700
                link_or_sha1 = None
1668
1701
            source_minikind = source_details[0]
1669
 
            target_minikind = target_details[0]
1670
1702
            if source_minikind in 'fdlr' and target_minikind in 'fdl':
1671
1703
                # claimed content in both: diff
1672
1704
                #   r    | fdl    |      | add source to search, add id path move and perform
1714
1746
                        if source_minikind != 'f':
1715
1747
                            content_change = True
1716
1748
                        else:
1717
 
                            # has it changed? fast path: size, slow path: sha1.
1718
 
                            if source_details[2] != path_info[3].st_size:
1719
 
                                content_change = True
1720
 
                            else:
1721
 
                                # maybe the same. Get the hash
1722
 
                                new_hash = self.target._hashcache.get_sha1(
1723
 
                                                            path, path_info[3])
1724
 
                                content_change = (new_hash != source_details[1])
 
1749
                            # We could check the size, but we already have the
 
1750
                            # sha1 hash.
 
1751
                            content_change = (link_or_sha1 != source_details[1])
 
1752
                        # Target details is updated at update_entry time
1725
1753
                        target_exec = bool(
1726
1754
                            stat.S_ISREG(path_info[3].st_mode)
1727
1755
                            and stat.S_IEXEC & path_info[3].st_mode)
1729
1757
                        if source_minikind != 'l':
1730
1758
                            content_change = True
1731
1759
                        else:
1732
 
                            # TODO: check symlink supported for windows users
1733
 
                            # and grab from target state here.
1734
 
                            link_target = os.readlink(path_info[4])
1735
 
                            content_change = (link_target != source_details[1])
 
1760
                            content_change = (link_or_sha1 != source_details[1])
1736
1761
                        target_exec = False
1737
1762
                    else:
1738
1763
                        raise Exception, "unknown kind %s" % path_info[2]
1769
1794
                        last_target_parent[2] = target_parent_entry
1770
1795
 
1771
1796
                source_exec = source_details[3]
1772
 
                path_unicode = utf8_decode(path)[0]
1773
 
                return ((entry[0][2], path_unicode, content_change,
 
1797
                return ((entry[0][2], path, content_change,
1774
1798
                        (True, True),
1775
1799
                        (source_parent_id, target_parent_id),
1776
1800
                        (old_basename, entry[0][1]),
1782
1806
                    path = pathjoin(entry[0][0], entry[0][1])
1783
1807
                    # parent id is the entry for the path in the target tree
1784
1808
                    # TODO: these are the same for an entire directory: cache em.
1785
 
                    parent_id = state._get_entry(target_index, path_utf8=entry[0][0])[0][2]
 
1809
                    parent_id = state._get_entry(target_index,
 
1810
                                                 path_utf8=entry[0][0])[0][2]
1786
1811
                    if parent_id == entry[0][2]:
1787
1812
                        parent_id = None
1788
 
                    # basename
1789
 
                    new_executable = bool(
 
1813
                    target_exec = bool(
1790
1814
                        stat.S_ISREG(path_info[3].st_mode)
1791
1815
                        and stat.S_IEXEC & path_info[3].st_mode)
1792
 
                    path_unicode = utf8_decode(path)[0]
1793
 
                    return ((entry[0][2], path_unicode, True,
 
1816
                    return ((entry[0][2], path, True,
1794
1817
                            (False, True),
1795
1818
                            (None, parent_id),
1796
1819
                            (None, entry[0][1]),
1797
1820
                            (None, path_info[2]),
1798
 
                            (None, new_executable)),)
 
1821
                            (None, target_exec)),)
1799
1822
                else:
1800
1823
                    # but its not on disk: we deliberately treat this as just
1801
1824
                    # never-present. (Why ?! - RBC 20070224)
1810
1833
                parent_id = state._get_entry(source_index, path_utf8=entry[0][0])[0][2]
1811
1834
                if parent_id == entry[0][2]:
1812
1835
                    parent_id = None
1813
 
                old_path_unicode = utf8_decode(old_path)[0]
1814
 
                return ((entry[0][2], old_path_unicode, True,
 
1836
                return ((entry[0][2], old_path, True,
1815
1837
                        (True, False),
1816
1838
                        (parent_id, None),
1817
1839
                        (entry[0][1], None),
1857
1879
            if not root_entries and not root_dir_info:
1858
1880
                # this specified path is not present at all, skip it.
1859
1881
                continue
 
1882
            path_handled = False
1860
1883
            for entry in root_entries:
1861
1884
                for result in _process_entry(entry, root_dir_info):
1862
1885
                    # this check should probably be outside the loop: one
1863
1886
                    # 'iterate two trees' api, and then _iter_changes filters
1864
1887
                    # unchanged pairs. - RBC 20070226
 
1888
                    path_handled = True
1865
1889
                    if (include_unchanged
1866
1890
                        or result[2]                    # content change
1867
1891
                        or result[3][0] != result[3][1] # versioned status
1870
1894
                        or result[6][0] != result[6][1] # kind
1871
1895
                        or result[7][0] != result[7][1] # executable
1872
1896
                        ):
 
1897
                        result = (result[0],
 
1898
                                  utf8_decode(result[1])[0]) + result[2:]
1873
1899
                        yield result
 
1900
            if want_unversioned and not path_handled:
 
1901
                new_executable = bool(
 
1902
                    stat.S_ISREG(root_dir_info[3].st_mode)
 
1903
                    and stat.S_IEXEC & root_dir_info[3].st_mode)
 
1904
                yield (None, current_root, True, (False, False), (None, None),
 
1905
                    (None, splitpath(current_root)[-1]),
 
1906
                    (None, root_dir_info[2]), (None, new_executable))
1874
1907
            dir_iterator = osutils._walkdirs_utf8(root_abspath, prefix=current_root)
1875
1908
            initial_key = (current_root, '', '')
1876
1909
            block_index, _ = state._find_block_index_from_key(initial_key)
1945
1978
                                    or result[6][0] != result[6][1] # kind
1946
1979
                                    or result[7][0] != result[7][1] # executable
1947
1980
                                    ):
 
1981
                                    result = (result[0],
 
1982
                                              utf8_decode(result[1])[0]) + result[2:]
1948
1983
                                    yield result
1949
1984
                        block_index +=1
1950
1985
                        if (block_index < len(state._dirblocks) and
1966
2001
                else:
1967
2002
                    current_path_info = None
1968
2003
                advance_path = True
 
2004
                path_handled = False
1969
2005
                while (current_entry is not None or
1970
2006
                    current_path_info is not None):
1971
2007
                    if current_entry is None:
1972
 
                        # no more entries: yield current_pathinfo as an
1973
 
                        # unversioned file: its not the same as a path in any
1974
 
                        # tree in the dirstate.
1975
 
                        new_executable = bool(
1976
 
                            stat.S_ISREG(current_path_info[3].st_mode)
1977
 
                            and stat.S_IEXEC & current_path_info[3].st_mode)
1978
 
                        pass # unversioned file support not added to the
1979
 
                        # _iter_changes api yet - breaks status amongst other
1980
 
                        # things.
1981
 
#                        yield (None, current_path_info[0], True,
1982
 
#                               (False, False),
1983
 
#                               (None, None),
1984
 
#                               (None, current_path_info[1]),
1985
 
#                               (None, current_path_info[2]),
1986
 
#                               (None, new_executable))
 
2008
                        # the check for path_handled when the path is adnvaced
 
2009
                        # will yield this path if needed.
 
2010
                        pass
1987
2011
                    elif current_path_info is None:
1988
2012
                        # no path is fine: the per entry code will handle it.
1989
2013
                        for result in _process_entry(current_entry, current_path_info):
1998
2022
                                or result[6][0] != result[6][1] # kind
1999
2023
                                or result[7][0] != result[7][1] # executable
2000
2024
                                ):
 
2025
                                result = (result[0],
 
2026
                                          utf8_decode(result[1])[0]) + result[2:]
2001
2027
                                yield result
2002
2028
                    elif current_entry[0][1] != current_path_info[1]:
2003
2029
                        if current_path_info[1] < current_entry[0][1]:
2013
2039
                                # this check should probably be outside the loop: one
2014
2040
                                # 'iterate two trees' api, and then _iter_changes filters
2015
2041
                                # unchanged pairs. - RBC 20070226
 
2042
                                path_handled = True
2016
2043
                                if (include_unchanged
2017
2044
                                    or result[2]                    # content change
2018
2045
                                    or result[3][0] != result[3][1] # versioned status
2021
2048
                                    or result[6][0] != result[6][1] # kind
2022
2049
                                    or result[7][0] != result[7][1] # executable
2023
2050
                                    ):
 
2051
                                    result = (result[0],
 
2052
                                              utf8_decode(result[1])[0]) + result[2:]
2024
2053
                                    yield result
2025
2054
                            advance_path = False
2026
2055
                    else:
2028
2057
                            # this check should probably be outside the loop: one
2029
2058
                            # 'iterate two trees' api, and then _iter_changes filters
2030
2059
                            # unchanged pairs. - RBC 20070226
 
2060
                            path_handled = True
2031
2061
                            if (include_unchanged
2032
2062
                                or result[2]                    # content change
2033
2063
                                or result[3][0] != result[3][1] # versioned status
2036
2066
                                or result[6][0] != result[6][1] # kind
2037
2067
                                or result[7][0] != result[7][1] # executable
2038
2068
                                ):
 
2069
                                result = (result[0],
 
2070
                                          utf8_decode(result[1])[0]) + result[2:]
2039
2071
                                yield result
2040
2072
                    if advance_entry and current_entry is not None:
2041
2073
                        entry_index += 1
2046
2078
                    else:
2047
2079
                        advance_entry = True # reset the advance flaga
2048
2080
                    if advance_path and current_path_info is not None:
 
2081
                        if not path_handled:
 
2082
                            # unversioned in all regards
 
2083
                            if want_unversioned:
 
2084
                                new_executable = bool(
 
2085
                                    stat.S_ISREG(current_path_info[3].st_mode)
 
2086
                                    and stat.S_IEXEC & current_path_info[3].st_mode)
 
2087
                                if want_unversioned:
 
2088
                                    yield (None, current_path_info[0], True,
 
2089
                                           (False, False),
 
2090
                                           (None, None),
 
2091
                                           (None, current_path_info[1]),
 
2092
                                           (None, current_path_info[2]),
 
2093
                                           (None, new_executable))
 
2094
                            # dont descend into this unversioned path if it is
 
2095
                            # a dir
 
2096
                            if current_path_info[2] == 'directory':
 
2097
                                del current_dir_info[1][path_index]
 
2098
                                path_index -= 1
2049
2099
                        path_index += 1
2050
2100
                        if path_index < len(current_dir_info[1]):
2051
2101
                            current_path_info = current_dir_info[1][path_index]
2052
2102
                        else:
2053
2103
                            current_path_info = None
 
2104
                        path_handled = False
2054
2105
                    else:
2055
2106
                        advance_path = True # reset the advance flagg.
2056
2107
                if current_block is not None: