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
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)
148
# is this scan needed ? it makes things kinda slow.
155
138
self._dirty = None
157
140
# during a read or write lock these objects are set, and are
255
238
def current_dirstate(self):
256
"""Return the current dirstate object.
239
"""Return the current dirstate object.
258
241
This is not part of the tree interface and only exposed for ease of
261
:raises errors.NotWriteLocked: when not in a lock.
244
:raises errors.NotWriteLocked: when not in a lock.
263
246
self._must_be_locked()
264
247
return self._current_dirstate()
266
249
def _current_dirstate(self):
267
250
"""Internal function that does not check lock status.
269
252
This is needed for break_lock which also needs the dirstate.
271
254
if self._dirstate is not None:
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'
386
369
# if row stat is valid, use cached sha1, else, get a new sha1.
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')
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':
391
381
def _get_inventory(self):
392
382
"""Get the inventory for the tree. This is only valid within a lock."""
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()
479
self._control_files.lock_read()
481
state = self.current_dirstate()
482
if not state._lock_token:
485
self._control_files.unlock()
491
def _lock_self_write(self):
492
"""This should be called after the branch is locked."""
494
self._control_files.lock_write()
496
state = self.current_dirstate()
497
if not state._lock_token:
500
self._control_files.unlock()
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()
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()
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':
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.
1337
1354
return self._repository.get_revision(last_changed_revision).timestamp
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":
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]
1347
1364
def get_file(self, file_id):
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.
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.
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
1662
1685
# TODO: when a parent has been renamed, dont emit path renames for children,
1663
1686
if source_index is None:
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]
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
1717
# has it changed? fast path: size, slow path: sha1.
1718
if source_details[2] != path_info[3].st_size:
1719
content_change = True
1721
# maybe the same. Get the hash
1722
new_hash = self.target._hashcache.get_sha1(
1724
content_change = (new_hash != source_details[1])
1749
# We could check the size, but we already have the
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
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
1738
1763
raise Exception, "unknown kind %s" % path_info[2]
1769
1794
last_target_parent[2] = target_parent_entry
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,
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
1789
new_executable = 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,
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)),)
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,
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.
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
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
1897
result = (result[0],
1898
utf8_decode(result[1])[0]) + result[2:]
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)
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
1981
# yield (None, current_path_info[0], True,
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.
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
2025
result = (result[0],
2026
utf8_decode(result[1])[0]) + result[2:]
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
2016
2043
if (include_unchanged
2017
2044
or result[2] # content change
2018
2045
or result[3][0] != result[3][1] # versioned status
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
2031
2061
if (include_unchanged
2032
2062
or result[2] # content change
2033
2063
or result[3][0] != result[3][1] # versioned status
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,
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
2096
if current_path_info[2] == 'directory':
2097
del current_dir_info[1][path_index]
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]
2053
2103
current_path_info = None
2104
path_handled = False
2055
2106
advance_path = True # reset the advance flagg.
2056
2107
if current_block is not None: