~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/_dirstate_helpers_c.pyx

More tuning.

Show diffs side-by-side

added added

removed removed

Lines of Context:
876
876
    return link_or_sha1
877
877
 
878
878
 
 
879
cdef char _minikind_from_string(object string):
 
880
    """Convert a python string to a char."""
 
881
    return PyString_AsString(string)[0]
 
882
 
 
883
 
 
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)]
 
889
 
 
890
 
 
891
cdef int _versioned_minikind(char minikind):
 
892
    """Return non-zero if minikind is in fltd"""
 
893
    return (minikind == c'f' or
 
894
            minikind == c'd' or
 
895
            minikind == c'l' or
 
896
            minikind == c't')
 
897
 
 
898
 
879
899
cdef class ProcessEntryC:
880
900
 
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
903
923
 
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.
906
926
 
907
927
        :param path_info: top_relpath, basename, kind, lstat, abspath for
916
936
                 basically identical.
917
937
        """
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
921
942
        else:
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])
938
953
        else:
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.
951
965
            #        |        |      | ???
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])
974
988
            else:
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
992
1006
                    else:
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
999
1013
                    else:
1000
1014
                        # We could check the size, but we already have the
1008
1022
                    else:
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
1013
1027
                    else:
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
1019
1033
                    else:
1020
1034
                        content_change = False
1021
1035
                    target_exec = False
1022
1036
                else:
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
1081
1095
                        path_u = old_path_u
1082
1096
                    else:
1083
1097
                        path_u = self.utf8_decode(path)[0]
1084
 
                source_kind = DirState._minikind_to_kind[source_minikind]
 
1098
                source_kind = _minikind_to_kind(source_minikind)
1085
1099
                return (entry[0][2],
1086
1100
                       (old_path_u, path_u),
1087
1101
                       content_change,
1092
1106
                       (source_exec, target_exec))
1093
1107
            else:
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]),
1134
1144
                       (None, None),
1135
1145
                       (None, False))
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 -
1149
1159
                   (True, False),
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.