765
768
from bzrlib._dirstate_helpers_py import _read_dirblocks_py
766
769
self.assertIs(_read_dirblocks_py, dirstate._read_dirblocks)
771
def test_update_entry(self):
772
if CompiledDirstateHelpersFeature.available():
773
from bzrlib._dirstate_helpers_c import update_entry
774
self.assertIs(update_entry, dirstate.update_entry)
776
from bzrlib.dirstate import py_update_entry
777
self.assertIs(py_update_entry, dirstate.py_update_entry)
779
def test_process_entry(self):
780
if CompiledDirstateHelpersFeature.available():
781
from bzrlib._dirstate_helpers_c import ProcessEntryC
782
self.assertIs(ProcessEntryC, dirstate._process_entry)
784
from bzrlib.dirstate import ProcessEntryPython
785
self.assertIs(ProcessEntryPython, dirstate._process_entry)
788
class TestUpdateEntry(test_dirstate.TestCaseWithDirState):
789
"""Test the DirState.update_entry functions"""
791
def get_state_with_a(self):
792
"""Create a DirState tracking a single object named 'a'"""
793
state = test_dirstate.InstrumentedDirState.initialize('dirstate')
794
self.addCleanup(state.unlock)
795
state.add('a', 'a-id', 'file', None, '')
796
entry = state._get_entry(0, path_utf8='a')
797
self.set_update_entry()
800
def set_update_entry(self):
801
self.update_entry = dirstate.py_update_entry
803
def test_update_entry(self):
804
state, entry = self.get_state_with_a()
805
self.build_tree(['a'])
806
# Add one where we don't provide the stat or sha already
807
self.assertEqual(('', 'a', 'a-id'), entry[0])
808
self.assertEqual([('f', '', 0, False, dirstate.DirState.NULLSTAT)],
810
# Flush the buffers to disk
812
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
813
state._dirblock_state)
815
stat_value = os.lstat('a')
816
packed_stat = dirstate.pack_stat(stat_value)
817
link_or_sha1 = self.update_entry(state, entry, abspath='a',
818
stat_value=stat_value)
819
self.assertEqual('b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6',
822
# The dirblock entry should not cache the file's sha1
823
self.assertEqual([('f', '', 14, False, dirstate.DirState.NULLSTAT)],
825
self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
826
state._dirblock_state)
827
mode = stat_value.st_mode
828
self.assertEqual([('sha1', 'a'), ('is_exec', mode, False)], state._log)
831
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
832
state._dirblock_state)
834
# If we do it again right away, we don't know if the file has changed
835
# so we will re-read the file. Roll the clock back so the file is
836
# guaranteed to look too new.
837
state.adjust_time(-10)
839
link_or_sha1 = self.update_entry(state, entry, abspath='a',
840
stat_value=stat_value)
841
self.assertEqual([('sha1', 'a'), ('is_exec', mode, False),
842
('sha1', 'a'), ('is_exec', mode, False),
844
self.assertEqual('b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6',
846
self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
847
state._dirblock_state)
848
self.assertEqual([('f', '', 14, False, dirstate.DirState.NULLSTAT)],
852
# However, if we move the clock forward so the file is considered
853
# "stable", it should just cache the value.
854
state.adjust_time(+20)
855
link_or_sha1 = self.update_entry(state, entry, abspath='a',
856
stat_value=stat_value)
857
self.assertEqual('b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6',
859
self.assertEqual([('sha1', 'a'), ('is_exec', mode, False),
860
('sha1', 'a'), ('is_exec', mode, False),
861
('sha1', 'a'), ('is_exec', mode, False),
863
self.assertEqual([('f', link_or_sha1, 14, False, packed_stat)],
866
# Subsequent calls will just return the cached value
867
link_or_sha1 = self.update_entry(state, entry, abspath='a',
868
stat_value=stat_value)
869
self.assertEqual('b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6',
871
self.assertEqual([('sha1', 'a'), ('is_exec', mode, False),
872
('sha1', 'a'), ('is_exec', mode, False),
873
('sha1', 'a'), ('is_exec', mode, False),
875
self.assertEqual([('f', link_or_sha1, 14, False, packed_stat)],
878
def test_update_entry_symlink(self):
879
"""Update entry should read symlinks."""
880
self.requireFeature(SymlinkFeature)
881
state, entry = self.get_state_with_a()
883
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
884
state._dirblock_state)
885
os.symlink('target', 'a')
887
state.adjust_time(-10) # Make the symlink look new
888
stat_value = os.lstat('a')
889
packed_stat = dirstate.pack_stat(stat_value)
890
link_or_sha1 = self.update_entry(state, entry, abspath='a',
891
stat_value=stat_value)
892
self.assertEqual('target', link_or_sha1)
893
self.assertEqual([('read_link', 'a', '')], state._log)
894
# Dirblock is not updated (the link is too new)
895
self.assertEqual([('l', '', 6, False, dirstate.DirState.NULLSTAT)],
897
self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
898
state._dirblock_state)
900
# Because the stat_value looks new, we should re-read the target
901
link_or_sha1 = self.update_entry(state, entry, abspath='a',
902
stat_value=stat_value)
903
self.assertEqual('target', link_or_sha1)
904
self.assertEqual([('read_link', 'a', ''),
905
('read_link', 'a', ''),
907
self.assertEqual([('l', '', 6, False, dirstate.DirState.NULLSTAT)],
909
state.adjust_time(+20) # Skip into the future, all files look old
910
link_or_sha1 = self.update_entry(state, entry, abspath='a',
911
stat_value=stat_value)
912
self.assertEqual('target', link_or_sha1)
913
# We need to re-read the link because only now can we cache it
914
self.assertEqual([('read_link', 'a', ''),
915
('read_link', 'a', ''),
916
('read_link', 'a', ''),
918
self.assertEqual([('l', 'target', 6, False, packed_stat)],
921
# Another call won't re-read the link
922
self.assertEqual([('read_link', 'a', ''),
923
('read_link', 'a', ''),
924
('read_link', 'a', ''),
926
link_or_sha1 = self.update_entry(state, entry, abspath='a',
927
stat_value=stat_value)
928
self.assertEqual('target', link_or_sha1)
929
self.assertEqual([('l', 'target', 6, False, packed_stat)],
932
def do_update_entry(self, state, entry, abspath):
933
stat_value = os.lstat(abspath)
934
return self.update_entry(state, entry, abspath, stat_value)
936
def test_update_entry_dir(self):
937
state, entry = self.get_state_with_a()
938
self.build_tree(['a/'])
939
self.assertIs(None, self.do_update_entry(state, entry, 'a'))
941
def test_update_entry_dir_unchanged(self):
942
state, entry = self.get_state_with_a()
943
self.build_tree(['a/'])
944
state.adjust_time(+20)
945
self.assertIs(None, self.do_update_entry(state, entry, 'a'))
946
self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
947
state._dirblock_state)
949
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
950
state._dirblock_state)
951
self.assertIs(None, self.do_update_entry(state, entry, 'a'))
952
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
953
state._dirblock_state)
955
def test_update_entry_file_unchanged(self):
956
state, entry = self.get_state_with_a()
957
self.build_tree(['a'])
958
sha1sum = 'b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6'
959
state.adjust_time(+20)
960
self.assertEqual(sha1sum, self.do_update_entry(state, entry, 'a'))
961
self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
962
state._dirblock_state)
964
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
965
state._dirblock_state)
966
self.assertEqual(sha1sum, self.do_update_entry(state, entry, 'a'))
967
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
968
state._dirblock_state)
970
def create_and_test_file(self, state, entry):
971
"""Create a file at 'a' and verify the state finds it.
973
The state should already be versioning *something* at 'a'. This makes
974
sure that state.update_entry recognizes it as a file.
976
self.build_tree(['a'])
977
stat_value = os.lstat('a')
978
packed_stat = dirstate.pack_stat(stat_value)
980
link_or_sha1 = self.do_update_entry(state, entry, abspath='a')
981
self.assertEqual('b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6',
983
self.assertEqual([('f', link_or_sha1, 14, False, packed_stat)],
987
def create_and_test_dir(self, state, entry):
988
"""Create a directory at 'a' and verify the state finds it.
990
The state should already be versioning *something* at 'a'. This makes
991
sure that state.update_entry recognizes it as a directory.
993
self.build_tree(['a/'])
994
stat_value = os.lstat('a')
995
packed_stat = dirstate.pack_stat(stat_value)
997
link_or_sha1 = self.do_update_entry(state, entry, abspath='a')
998
self.assertIs(None, link_or_sha1)
999
self.assertEqual([('d', '', 0, False, packed_stat)], entry[1])
1003
def create_and_test_symlink(self, state, entry):
1004
"""Create a symlink at 'a' and verify the state finds it.
1006
The state should already be versioning *something* at 'a'. This makes
1007
sure that state.update_entry recognizes it as a symlink.
1009
This should not be called if this platform does not have symlink
1012
# caller should care about skipping test on platforms without symlinks
1013
os.symlink('path/to/foo', 'a')
1015
stat_value = os.lstat('a')
1016
packed_stat = dirstate.pack_stat(stat_value)
1018
link_or_sha1 = self.do_update_entry(state, entry, abspath='a')
1019
self.assertEqual('path/to/foo', link_or_sha1)
1020
self.assertEqual([('l', 'path/to/foo', 11, False, packed_stat)],
1024
def test_update_file_to_dir(self):
1025
"""If a file changes to a directory we return None for the sha.
1026
We also update the inventory record.
1028
state, entry = self.get_state_with_a()
1029
# The file sha1 won't be cached unless the file is old
1030
state.adjust_time(+10)
1031
self.create_and_test_file(state, entry)
1033
self.create_and_test_dir(state, entry)
1035
def test_update_file_to_symlink(self):
1036
"""File becomes a symlink"""
1037
self.requireFeature(SymlinkFeature)
1038
state, entry = self.get_state_with_a()
1039
# The file sha1 won't be cached unless the file is old
1040
state.adjust_time(+10)
1041
self.create_and_test_file(state, entry)
1043
self.create_and_test_symlink(state, entry)
1045
def test_update_dir_to_file(self):
1046
"""Directory becoming a file updates the entry."""
1047
state, entry = self.get_state_with_a()
1048
# The file sha1 won't be cached unless the file is old
1049
state.adjust_time(+10)
1050
self.create_and_test_dir(state, entry)
1052
self.create_and_test_file(state, entry)
1054
def test_update_dir_to_symlink(self):
1055
"""Directory becomes a symlink"""
1056
self.requireFeature(SymlinkFeature)
1057
state, entry = self.get_state_with_a()
1058
# The symlink target won't be cached if it isn't old
1059
state.adjust_time(+10)
1060
self.create_and_test_dir(state, entry)
1062
self.create_and_test_symlink(state, entry)
1064
def test_update_symlink_to_file(self):
1065
"""Symlink becomes a file"""
1066
self.requireFeature(SymlinkFeature)
1067
state, entry = self.get_state_with_a()
1068
# The symlink and file info won't be cached unless old
1069
state.adjust_time(+10)
1070
self.create_and_test_symlink(state, entry)
1072
self.create_and_test_file(state, entry)
1074
def test_update_symlink_to_dir(self):
1075
"""Symlink becomes a directory"""
1076
self.requireFeature(SymlinkFeature)
1077
state, entry = self.get_state_with_a()
1078
# The symlink target won't be cached if it isn't old
1079
state.adjust_time(+10)
1080
self.create_and_test_symlink(state, entry)
1082
self.create_and_test_dir(state, entry)
1084
def test__is_executable_win32(self):
1085
state, entry = self.get_state_with_a()
1086
self.build_tree(['a'])
1088
# Make sure we are using the win32 implementation of _is_executable
1089
state._is_executable = state._is_executable_win32
1091
# The file on disk is not executable, but we are marking it as though
1092
# it is. With _is_executable_win32 we ignore what is on disk.
1093
entry[1][0] = ('f', '', 0, True, dirstate.DirState.NULLSTAT)
1095
stat_value = os.lstat('a')
1096
packed_stat = dirstate.pack_stat(stat_value)
1098
state.adjust_time(-10) # Make sure everything is new
1099
self.update_entry(state, entry, abspath='a', stat_value=stat_value)
1101
# The row is updated, but the executable bit stays set.
1102
self.assertEqual([('f', '', 14, True, dirstate.DirState.NULLSTAT)],
1105
# Make the disk object look old enough to cache
1106
state.adjust_time(+20)
1107
digest = 'b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6'
1108
self.update_entry(state, entry, abspath='a', stat_value=stat_value)
1109
self.assertEqual([('f', digest, 14, True, packed_stat)], entry[1])
1112
class TestCompiledUpdateEntry(TestUpdateEntry):
1113
"""Test the pyrex implementation of _read_dirblocks"""
1115
_test_needs_features = [CompiledDirstateHelpersFeature]
1117
def set_update_entry(self):
1118
from bzrlib._dirstate_helpers_c import update_entry
1119
self.update_entry = update_entry