907
882
state._validate()
909
884
state.set_parent_trees([('parent-revid', rt)], ghosts=[])
910
root_entry = (('', '', 'TREE_ROOT'),
911
[('d', '', 0, False, 'x'*32),
912
('d', '', 0, False, 'parent-revid')])
913
self.assertEqual(root_entry, state._get_entry(0, path_utf8=''))
914
self.assertEqual(root_entry,
915
state._get_entry(0, fileid_utf8='TREE_ROOT'))
916
self.assertEqual((None, None),
917
state._get_entry(0, fileid_utf8='Asecond-root-id'))
918
state.set_path_id('', 'Asecond-root-id')
885
state.set_path_id('', 'foobarbaz')
919
886
state._validate()
920
887
# now see that it is what we expected
921
old_root_entry = (('', '', 'TREE_ROOT'),
922
[('a', '', 0, False, ''),
923
('d', '', 0, False, 'parent-revid')])
924
new_root_entry = (('', '', 'Asecond-root-id'),
925
[('d', '', 0, False, ''),
926
('a', '', 0, False, '')])
927
expected_rows = [new_root_entry, old_root_entry]
889
(('', '', 'TREE_ROOT'),
890
[('a', '', 0, False, ''),
891
('d', '', 0, False, 'parent-revid'),
893
(('', '', 'foobarbaz'),
894
[('d', '', 0, False, ''),
895
('a', '', 0, False, ''),
928
898
state._validate()
929
899
self.assertEqual(expected_rows, list(state._iter_entries()))
930
self.assertEqual(new_root_entry, state._get_entry(0, path_utf8=''))
931
self.assertEqual(old_root_entry, state._get_entry(1, path_utf8=''))
932
self.assertEqual((None, None),
933
state._get_entry(0, fileid_utf8='TREE_ROOT'))
934
self.assertEqual(old_root_entry,
935
state._get_entry(1, fileid_utf8='TREE_ROOT'))
936
self.assertEqual(new_root_entry,
937
state._get_entry(0, fileid_utf8='Asecond-root-id'))
938
self.assertEqual((None, None),
939
state._get_entry(1, fileid_utf8='Asecond-root-id'))
940
900
# should work across save too
1735
1665
self.st_ino = ino
1736
1666
self.st_mode = mode
1740
return _FakeStat(st.st_size, st.st_mtime, st.st_ctime, st.st_dev,
1741
st.st_ino, st.st_mode)
1744
class TestPackStat(tests.TestCaseWithTransport):
1669
class TestUpdateEntry(TestCaseWithDirState):
1670
"""Test the DirState.update_entry functions"""
1672
def get_state_with_a(self):
1673
"""Create a DirState tracking a single object named 'a'"""
1674
state = InstrumentedDirState.initialize('dirstate')
1675
self.addCleanup(state.unlock)
1676
state.add('a', 'a-id', 'file', None, '')
1677
entry = state._get_entry(0, path_utf8='a')
1680
def test_observed_sha1_cachable(self):
1681
state, entry = self.get_state_with_a()
1682
atime = time.time() - 10
1683
self.build_tree(['a'])
1684
statvalue = os.lstat('a')
1685
statvalue = _FakeStat(statvalue.st_size, atime, atime,
1686
statvalue.st_dev, statvalue.st_ino, statvalue.st_mode)
1687
state._observed_sha1(entry, "foo", statvalue)
1688
self.assertEqual('foo', entry[1][0][1])
1689
packed_stat = dirstate.pack_stat(statvalue)
1690
self.assertEqual(packed_stat, entry[1][0][4])
1692
def test_observed_sha1_not_cachable(self):
1693
state, entry = self.get_state_with_a()
1694
oldval = entry[1][0][1]
1695
oldstat = entry[1][0][4]
1696
self.build_tree(['a'])
1697
statvalue = os.lstat('a')
1698
state._observed_sha1(entry, "foo", statvalue)
1699
self.assertEqual(oldval, entry[1][0][1])
1700
self.assertEqual(oldstat, entry[1][0][4])
1702
def test_update_entry(self):
1703
state, entry = self.get_state_with_a()
1704
self.build_tree(['a'])
1705
# Add one where we don't provide the stat or sha already
1706
self.assertEqual(('', 'a', 'a-id'), entry[0])
1707
self.assertEqual([('f', '', 0, False, dirstate.DirState.NULLSTAT)],
1709
# Flush the buffers to disk
1711
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1712
state._dirblock_state)
1714
stat_value = os.lstat('a')
1715
packed_stat = dirstate.pack_stat(stat_value)
1716
link_or_sha1 = state.update_entry(entry, abspath='a',
1717
stat_value=stat_value)
1718
self.assertEqual('b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6',
1721
# The dirblock entry should not cache the file's sha1
1722
self.assertEqual([('f', '', 14, False, dirstate.DirState.NULLSTAT)],
1724
self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
1725
state._dirblock_state)
1726
mode = stat_value.st_mode
1727
self.assertEqual([('sha1', 'a'), ('is_exec', mode, False)], state._log)
1730
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1731
state._dirblock_state)
1733
# If we do it again right away, we don't know if the file has changed
1734
# so we will re-read the file. Roll the clock back so the file is
1735
# guaranteed to look too new.
1736
state.adjust_time(-10)
1738
link_or_sha1 = state.update_entry(entry, abspath='a',
1739
stat_value=stat_value)
1740
self.assertEqual([('sha1', 'a'), ('is_exec', mode, False),
1741
('sha1', 'a'), ('is_exec', mode, False),
1743
self.assertEqual('b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6',
1745
self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
1746
state._dirblock_state)
1747
self.assertEqual([('f', '', 14, False, dirstate.DirState.NULLSTAT)],
1751
# However, if we move the clock forward so the file is considered
1752
# "stable", it should just cache the value.
1753
state.adjust_time(+20)
1754
link_or_sha1 = state.update_entry(entry, abspath='a',
1755
stat_value=stat_value)
1756
self.assertEqual('b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6',
1758
self.assertEqual([('sha1', 'a'), ('is_exec', mode, False),
1759
('sha1', 'a'), ('is_exec', mode, False),
1760
('sha1', 'a'), ('is_exec', mode, False),
1762
self.assertEqual([('f', link_or_sha1, 14, False, packed_stat)],
1765
# Subsequent calls will just return the cached value
1766
link_or_sha1 = state.update_entry(entry, abspath='a',
1767
stat_value=stat_value)
1768
self.assertEqual('b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6',
1770
self.assertEqual([('sha1', 'a'), ('is_exec', mode, False),
1771
('sha1', 'a'), ('is_exec', mode, False),
1772
('sha1', 'a'), ('is_exec', mode, False),
1774
self.assertEqual([('f', link_or_sha1, 14, False, packed_stat)],
1777
def test_update_entry_symlink(self):
1778
"""Update entry should read symlinks."""
1779
self.requireFeature(SymlinkFeature)
1780
state, entry = self.get_state_with_a()
1782
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1783
state._dirblock_state)
1784
os.symlink('target', 'a')
1786
state.adjust_time(-10) # Make the symlink look new
1787
stat_value = os.lstat('a')
1788
packed_stat = dirstate.pack_stat(stat_value)
1789
link_or_sha1 = state.update_entry(entry, abspath='a',
1790
stat_value=stat_value)
1791
self.assertEqual('target', link_or_sha1)
1792
self.assertEqual([('read_link', 'a', '')], state._log)
1793
# Dirblock is not updated (the link is too new)
1794
self.assertEqual([('l', '', 6, False, dirstate.DirState.NULLSTAT)],
1796
self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
1797
state._dirblock_state)
1799
# Because the stat_value looks new, we should re-read the target
1800
link_or_sha1 = state.update_entry(entry, abspath='a',
1801
stat_value=stat_value)
1802
self.assertEqual('target', link_or_sha1)
1803
self.assertEqual([('read_link', 'a', ''),
1804
('read_link', 'a', ''),
1806
self.assertEqual([('l', '', 6, False, dirstate.DirState.NULLSTAT)],
1808
state.adjust_time(+20) # Skip into the future, all files look old
1809
link_or_sha1 = state.update_entry(entry, abspath='a',
1810
stat_value=stat_value)
1811
self.assertEqual('target', link_or_sha1)
1812
# We need to re-read the link because only now can we cache it
1813
self.assertEqual([('read_link', 'a', ''),
1814
('read_link', 'a', ''),
1815
('read_link', 'a', ''),
1817
self.assertEqual([('l', 'target', 6, False, packed_stat)],
1820
# Another call won't re-read the link
1821
self.assertEqual([('read_link', 'a', ''),
1822
('read_link', 'a', ''),
1823
('read_link', 'a', ''),
1825
link_or_sha1 = state.update_entry(entry, abspath='a',
1826
stat_value=stat_value)
1827
self.assertEqual('target', link_or_sha1)
1828
self.assertEqual([('l', 'target', 6, False, packed_stat)],
1831
def do_update_entry(self, state, entry, abspath):
1832
stat_value = os.lstat(abspath)
1833
return state.update_entry(entry, abspath, stat_value)
1835
def test_update_entry_dir(self):
1836
state, entry = self.get_state_with_a()
1837
self.build_tree(['a/'])
1838
self.assertIs(None, self.do_update_entry(state, entry, 'a'))
1840
def test_update_entry_dir_unchanged(self):
1841
state, entry = self.get_state_with_a()
1842
self.build_tree(['a/'])
1843
state.adjust_time(+20)
1844
self.assertIs(None, self.do_update_entry(state, entry, 'a'))
1845
self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
1846
state._dirblock_state)
1848
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1849
state._dirblock_state)
1850
self.assertIs(None, self.do_update_entry(state, entry, 'a'))
1851
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1852
state._dirblock_state)
1854
def test_update_entry_file_unchanged(self):
1855
state, entry = self.get_state_with_a()
1856
self.build_tree(['a'])
1857
sha1sum = 'b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6'
1858
state.adjust_time(+20)
1859
self.assertEqual(sha1sum, self.do_update_entry(state, entry, 'a'))
1860
self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
1861
state._dirblock_state)
1863
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1864
state._dirblock_state)
1865
self.assertEqual(sha1sum, self.do_update_entry(state, entry, 'a'))
1866
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1867
state._dirblock_state)
1869
def create_and_test_file(self, state, entry):
1870
"""Create a file at 'a' and verify the state finds it.
1872
The state should already be versioning *something* at 'a'. This makes
1873
sure that state.update_entry recognizes it as a file.
1875
self.build_tree(['a'])
1876
stat_value = os.lstat('a')
1877
packed_stat = dirstate.pack_stat(stat_value)
1879
link_or_sha1 = self.do_update_entry(state, entry, abspath='a')
1880
self.assertEqual('b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6',
1882
self.assertEqual([('f', link_or_sha1, 14, False, packed_stat)],
1886
def create_and_test_dir(self, state, entry):
1887
"""Create a directory at 'a' and verify the state finds it.
1889
The state should already be versioning *something* at 'a'. This makes
1890
sure that state.update_entry recognizes it as a directory.
1892
self.build_tree(['a/'])
1893
stat_value = os.lstat('a')
1894
packed_stat = dirstate.pack_stat(stat_value)
1896
link_or_sha1 = self.do_update_entry(state, entry, abspath='a')
1897
self.assertIs(None, link_or_sha1)
1898
self.assertEqual([('d', '', 0, False, packed_stat)], entry[1])
1902
def create_and_test_symlink(self, state, entry):
1903
"""Create a symlink at 'a' and verify the state finds it.
1905
The state should already be versioning *something* at 'a'. This makes
1906
sure that state.update_entry recognizes it as a symlink.
1908
This should not be called if this platform does not have symlink
1911
# caller should care about skipping test on platforms without symlinks
1912
os.symlink('path/to/foo', 'a')
1914
stat_value = os.lstat('a')
1915
packed_stat = dirstate.pack_stat(stat_value)
1917
link_or_sha1 = self.do_update_entry(state, entry, abspath='a')
1918
self.assertEqual('path/to/foo', link_or_sha1)
1919
self.assertEqual([('l', 'path/to/foo', 11, False, packed_stat)],
1923
def test_update_file_to_dir(self):
1924
"""If a file changes to a directory we return None for the sha.
1925
We also update the inventory record.
1927
state, entry = self.get_state_with_a()
1928
# The file sha1 won't be cached unless the file is old
1929
state.adjust_time(+10)
1930
self.create_and_test_file(state, entry)
1932
self.create_and_test_dir(state, entry)
1934
def test_update_file_to_symlink(self):
1935
"""File becomes a symlink"""
1936
self.requireFeature(SymlinkFeature)
1937
state, entry = self.get_state_with_a()
1938
# The file sha1 won't be cached unless the file is old
1939
state.adjust_time(+10)
1940
self.create_and_test_file(state, entry)
1942
self.create_and_test_symlink(state, entry)
1944
def test_update_dir_to_file(self):
1945
"""Directory becoming a file updates the entry."""
1946
state, entry = self.get_state_with_a()
1947
# The file sha1 won't be cached unless the file is old
1948
state.adjust_time(+10)
1949
self.create_and_test_dir(state, entry)
1951
self.create_and_test_file(state, entry)
1953
def test_update_dir_to_symlink(self):
1954
"""Directory becomes a symlink"""
1955
self.requireFeature(SymlinkFeature)
1956
state, entry = self.get_state_with_a()
1957
# The symlink target won't be cached if it isn't old
1958
state.adjust_time(+10)
1959
self.create_and_test_dir(state, entry)
1961
self.create_and_test_symlink(state, entry)
1963
def test_update_symlink_to_file(self):
1964
"""Symlink becomes a file"""
1965
self.requireFeature(SymlinkFeature)
1966
state, entry = self.get_state_with_a()
1967
# The symlink and file info won't be cached unless old
1968
state.adjust_time(+10)
1969
self.create_and_test_symlink(state, entry)
1971
self.create_and_test_file(state, entry)
1973
def test_update_symlink_to_dir(self):
1974
"""Symlink becomes a directory"""
1975
self.requireFeature(SymlinkFeature)
1976
state, entry = self.get_state_with_a()
1977
# The symlink target won't be cached if it isn't old
1978
state.adjust_time(+10)
1979
self.create_and_test_symlink(state, entry)
1981
self.create_and_test_dir(state, entry)
1983
def test__is_executable_win32(self):
1984
state, entry = self.get_state_with_a()
1985
self.build_tree(['a'])
1987
# Make sure we are using the win32 implementation of _is_executable
1988
state._is_executable = state._is_executable_win32
1990
# The file on disk is not executable, but we are marking it as though
1991
# it is. With _is_executable_win32 we ignore what is on disk.
1992
entry[1][0] = ('f', '', 0, True, dirstate.DirState.NULLSTAT)
1994
stat_value = os.lstat('a')
1995
packed_stat = dirstate.pack_stat(stat_value)
1997
state.adjust_time(-10) # Make sure everything is new
1998
state.update_entry(entry, abspath='a', stat_value=stat_value)
2000
# The row is updated, but the executable bit stays set.
2001
self.assertEqual([('f', '', 14, True, dirstate.DirState.NULLSTAT)],
2004
# Make the disk object look old enough to cache
2005
state.adjust_time(+20)
2006
digest = 'b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6'
2007
state.update_entry(entry, abspath='a', stat_value=stat_value)
2008
self.assertEqual([('f', digest, 14, True, packed_stat)], entry[1])
2011
class TestPackStat(TestCaseWithTransport):
1746
2013
def assertPackStat(self, expected, stat_value):
1747
2014
"""Check the packed and serialized form of a stat value."""