876
876
return link_or_sha1
879
cdef char _minikind_from_string(object string):
880
"""Convert a python string to a char."""
881
return PyString_AsString(string)[0]
884
cdef object _minikind_to_kind(char minikind):
885
"""Create a string kind for minikind."""
886
cdef char _minikind[1]
887
_minikind[0] = minikind
888
return DirState._minikind_to_kind[PyString_FromStringAndSize(_minikind, 1)]
891
cdef int _versioned_minikind(char minikind):
892
"""Return non-zero if minikind is in fltd"""
893
return (minikind == c'f' or
879
899
cdef class ProcessEntryC:
881
901
cdef object old_dirname_to_file_id # dict
901
921
self.use_filesystem_for_exec = use_filesystem_for_exec
902
922
self.utf8_decode = cache_utf8._utf8_decode
904
def _process_entry(self, entry, path_info, source_index, target_index, state):
924
def _process_entry(self, entry, path_info, source_index, int target_index, state):
905
925
"""Compare an entry and real disk to generate delta information.
907
927
:param path_info: top_relpath, basename, kind, lstat, abspath for
916
936
basically identical.
918
938
cdef char target_minikind
939
cdef char source_minikind
919
940
if source_index is None:
920
941
source_details = DirState.NULL_PARENT_DETAILS
922
943
source_details = entry[1][source_index]
923
944
target_details = entry[1][target_index]
924
target_minikind_str = target_details[0]
925
target_minikind = PyString_AsString(target_minikind_str)[0]
926
if (path_info is not None and (
927
target_minikind == c'f' or
928
target_minikind == c'd' or
929
target_minikind == c'l' or
930
target_minikind == c't')):
931
if not (target_index == 0):
932
raise AssertionError()
945
target_minikind = _minikind_from_string(target_details[0])
946
if path_info is not None and _versioned_minikind(target_minikind):
947
if target_index != 0:
948
raise AssertionError("Unsupported target index %d" % target_index)
933
949
link_or_sha1 = _update_entry(state, entry, path_info[4], path_info[3])
934
950
# The entry may have been modified by update_entry
935
951
target_details = entry[1][target_index]
936
target_minikind_str = target_details[0]
937
target_minikind = PyString_AsString(target_minikind_str)[0]
952
target_minikind = _minikind_from_string(target_details[0])
939
954
link_or_sha1 = None
955
# the rest of this function is 0.3 seconds on 50K paths, or
956
# 0.000006 seconds per call.
940
957
file_id = entry[0][2]
941
source_minikind = source_details[0]
942
if (source_minikind in 'fdltr' and (
943
target_minikind == c'f' or
944
target_minikind == c'd' or
945
target_minikind == c'l' or
946
target_minikind == c't')):
958
source_minikind = _minikind_from_string(source_details[0])
959
if ((_versioned_minikind(source_minikind) or source_minikind == c'r')
960
and _versioned_minikind(target_minikind)):
947
961
# claimed content in both: diff
948
962
# r | fdlt | | add source to search, add id path move and perform
949
963
# | | | diff check on source-target
950
964
# r | fdlt | a | dangling file that was present in the basis.
952
if source_minikind in 'r':
966
if source_minikind == c'r':
953
967
# add the source to the search path to find any children it
954
968
# has. TODO ? : only add if it is a container ?
955
969
if not osutils.is_inside_any(searched_specific_files,
970
984
" but source does not exist\n"
971
985
"entry: %s" % (entry[0][0], entry[0][1], old_path, entry))
972
986
source_details = old_entry[1][source_index]
973
source_minikind = source_details[0]
987
source_minikind = _minikind_from_string(source_details[0])
975
989
old_dirname = entry[0][0]
976
990
old_basename = entry[0][1]
987
1001
if path is None:
988
1002
old_path = path = pathjoin(old_dirname, old_basename)
989
1003
self.new_dirname_to_file_id[path] = file_id
990
if source_minikind != 'd':
1004
if source_minikind != c'd':
991
1005
content_change = True
993
1007
# directories have no fingerprint
994
1008
content_change = False
995
1009
target_exec = False
996
1010
elif target_kind == 'file':
997
if source_minikind != 'f':
1011
if source_minikind != c'f':
998
1012
content_change = True
1000
1014
# We could check the size, but we already have the
1009
1023
target_exec = target_details[3]
1010
1024
elif target_kind == 'symlink':
1011
if source_minikind != 'l':
1025
if source_minikind != c'l':
1012
1026
content_change = True
1014
1028
content_change = (link_or_sha1 != source_details[1])
1015
1029
target_exec = False
1016
1030
elif target_kind == 'tree-reference':
1017
if source_minikind != 't':
1031
if source_minikind != c't':
1018
1032
content_change = True
1020
1034
content_change = False
1021
1035
target_exec = False
1023
1037
raise Exception, "unknown kind %s" % path_info[2]
1024
if source_minikind == 'd':
1038
if source_minikind == c'd':
1025
1039
if path is None:
1026
1040
old_path = path = pathjoin(old_dirname, old_basename)
1027
1041
self.old_dirname_to_file_id[old_path] = file_id
1092
1106
(source_exec, target_exec))
1094
1108
return self.uninteresting
1095
elif (source_minikind in 'a' and (
1096
target_minikind == c'f' or
1097
target_minikind == c'd' or
1098
target_minikind == c'l' or
1099
target_minikind == c't')):
1109
elif source_minikind == c'a' and _versioned_minikind(target_minikind):
1100
1110
# looks like a new file
1101
1111
path = pathjoin(entry[0][0], entry[0][1])
1102
1112
# parent id is the entry for the path in the target tree
1133
1143
(None, self.utf8_decode(entry[0][1])[0]),
1136
elif source_minikind in 'fdlt' and target_minikind == c'a':
1146
elif _versioned_minikind(source_minikind) and target_minikind == c'a':
1137
1147
# unversioned, possibly, or possibly not deleted: we dont care.
1138
1148
# if its still on disk, *and* theres no other entry at this
1139
1149
# path [we dont know this in this routine at the moment -
1150
1160
(parent_id, None),
1151
1161
(self.utf8_decode(entry[0][1])[0], None),
1152
(DirState._minikind_to_kind[source_minikind], None),
1162
(_minikind_to_kind(source_minikind), None),
1153
1163
(source_details[3], None))
1154
elif source_minikind in 'fdlt' and target_minikind == c'r':
1164
elif _versioned_minikind(source_minikind) and target_minikind == c'r':
1155
1165
# a rename; could be a true rename, or a rename inherited from
1156
1166
# a renamed parent. TODO: handle this efficiently. Its not
1157
1167
# common case to rename dirs though, so a correct but slow
1158
1168
# implementation will do.
1159
1169
if not osutils.is_inside_any(searched_specific_files, target_details[1]):
1160
1170
search_specific_files.add(target_details[1])
1161
elif (source_minikind in 'ra' and (
1162
target_minikind == c'r' or
1163
target_minikind == c'a')):
1171
elif ((source_minikind == c'r' or source_minikind == c'a') and
1172
(target_minikind == c'r' or target_minikind == c'a')):
1164
1173
# neither of the selected trees contain this file,
1165
1174
# so skip over it. This is not currently directly tested, but
1166
1175
# is indirectly via test_too_much.TestCommands.test_conflicts.