~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/_dirstate_helpers_c.pyx

Fix up inter_changes with dirstate both C and python.

Show diffs side-by-side

added added

removed removed

Lines of Context:
20
20
"""
21
21
 
22
22
import binascii
 
23
import os
23
24
 
24
25
from bzrlib import cache_utf8, errors, osutils
25
26
from bzrlib.dirstate import DirState, pack_stat
881
882
    return PyString_AsString(string)[0]
882
883
 
883
884
 
 
885
cdef object _kind_absent
 
886
cdef object _kind_file
 
887
cdef object _kind_directory
 
888
cdef object _kind_symlink
 
889
cdef object _kind_relocated
 
890
cdef object _kind_tree_reference
 
891
_kind_absent = "absent"
 
892
_kind_file = "file"
 
893
_kind_directory = "directory"
 
894
_kind_symlink = "symlink"
 
895
_kind_relocated = "relocated"
 
896
_kind_tree_reference = "tree-reference"
 
897
 
 
898
 
884
899
cdef object _minikind_to_kind(char minikind):
885
900
    """Create a string kind for minikind."""
886
901
    cdef char _minikind[1]
 
902
    if minikind == c'f':
 
903
        return _kind_file
 
904
    elif minikind == c'd':
 
905
        return _kind_directory
 
906
    elif minikind == c'a':
 
907
        return _kind_absent
 
908
    elif minikind == c'r':
 
909
        return _kind_relocated
 
910
    elif minikind == c'l':
 
911
        return _kind_symlink
 
912
    elif minikind == c't':
 
913
        return _kind_tree_reference
887
914
    _minikind[0] = minikind
888
 
    return DirState._minikind_to_kind[PyString_FromStringAndSize(_minikind, 1)]
 
915
    raise KeyError(PyString_FromStringAndSize(_minikind, 1))
889
916
 
890
917
 
891
918
cdef int _versioned_minikind(char minikind):
906
933
    cdef object include_unchanged
907
934
    cdef object use_filesystem_for_exec
908
935
    cdef object utf8_decode
 
936
    cdef readonly object searched_specific_files
 
937
    cdef object search_specific_files
909
938
 
910
 
    def __init__(self, include_unchanged, use_filesystem_for_exec):
 
939
    def __init__(self, include_unchanged, use_filesystem_for_exec, search_specific_files):
911
940
        self.old_dirname_to_file_id = {}
912
941
        self.new_dirname_to_file_id = {}
913
942
        # Just a sentry, so that _process_entry can say that this
920
949
        self.include_unchanged = include_unchanged
921
950
        self.use_filesystem_for_exec = use_filesystem_for_exec
922
951
        self.utf8_decode = cache_utf8._utf8_decode
 
952
        # for all search_indexs in each path at or under each element of
 
953
        # search_specific_files, if the detail is relocated: add the id, and add the
 
954
        # relocated path as one to search if its not searched already. If the
 
955
        # detail is not relocated, add the id.
 
956
        self.searched_specific_files = set()
 
957
        self.search_specific_files = search_specific_files
923
958
 
924
959
    def _process_entry(self, entry, path_info, source_index, int target_index, state):
925
960
        """Compare an entry and real disk to generate delta information.
937
972
        """
938
973
        cdef char target_minikind
939
974
        cdef char source_minikind
 
975
        cdef object file_id
 
976
        cdef int content_change
 
977
        file_id = None
940
978
        if source_index is None:
941
979
            source_details = DirState.NULL_PARENT_DETAILS
942
980
        else:
954
992
            link_or_sha1 = None
955
993
        # the rest of this function is 0.3 seconds on 50K paths, or
956
994
        # 0.000006 seconds per call.
957
 
        file_id = entry[0][2]
958
995
        source_minikind = _minikind_from_string(source_details[0])
959
996
        if ((_versioned_minikind(source_minikind) or source_minikind == c'r')
960
997
            and _versioned_minikind(target_minikind)):
963
1000
            #        |        |      | diff check on source-target
964
1001
            #   r    | fdlt   |  a   | dangling file that was present in the basis.
965
1002
            #        |        |      | ???
966
 
            if source_minikind == c'r':
 
1003
            if source_minikind != c'r':
 
1004
                old_dirname = entry[0][0]
 
1005
                old_basename = entry[0][1]
 
1006
                old_path = path = None
 
1007
            else:
967
1008
                # add the source to the search path to find any children it
968
1009
                # has.  TODO ? : only add if it is a container ?
969
 
                if not osutils.is_inside_any(searched_specific_files,
 
1010
                if not osutils.is_inside_any(self.searched_specific_files,
970
1011
                                             source_details[1]):
971
 
                    search_specific_files.add(source_details[1])
 
1012
                    self.search_specific_files.add(source_details[1])
972
1013
                # generate the old path; this is needed for stating later
973
1014
                # as well.
974
1015
                old_path = source_details[1]
985
1026
                        "entry: %s" % (entry[0][0], entry[0][1], old_path, entry))
986
1027
                source_details = old_entry[1][source_index]
987
1028
                source_minikind = _minikind_from_string(source_details[0])
988
 
            else:
989
 
                old_dirname = entry[0][0]
990
 
                old_basename = entry[0][1]
991
 
                old_path = path = None
992
1029
            if path_info is None:
993
1030
                # the file is missing on disk, show as removed.
994
 
                content_change = True
 
1031
                content_change = 1
995
1032
                target_kind = None
996
1033
                target_exec = False
997
1034
            else:
1000
1037
                if target_kind == 'directory':
1001
1038
                    if path is None:
1002
1039
                        old_path = path = pathjoin(old_dirname, old_basename)
 
1040
                    file_id = entry[0][2]
1003
1041
                    self.new_dirname_to_file_id[path] = file_id
1004
1042
                    if source_minikind != c'd':
1005
 
                        content_change = True
 
1043
                        content_change = 1
1006
1044
                    else:
1007
1045
                        # directories have no fingerprint
1008
 
                        content_change = False
 
1046
                        content_change = 0
1009
1047
                    target_exec = False
1010
1048
                elif target_kind == 'file':
1011
1049
                    if source_minikind != c'f':
1012
 
                        content_change = True
 
1050
                        content_change = 1
1013
1051
                    else:
1014
1052
                        # We could check the size, but we already have the
1015
1053
                        # sha1 hash.
1023
1061
                        target_exec = target_details[3]
1024
1062
                elif target_kind == 'symlink':
1025
1063
                    if source_minikind != c'l':
1026
 
                        content_change = True
 
1064
                        content_change = 1
1027
1065
                    else:
1028
1066
                        content_change = (link_or_sha1 != source_details[1])
1029
1067
                    target_exec = False
1030
1068
                elif target_kind == 'tree-reference':
1031
1069
                    if source_minikind != c't':
1032
 
                        content_change = True
 
1070
                        content_change = 1
1033
1071
                    else:
1034
 
                        content_change = False
 
1072
                        content_change = 0
1035
1073
                    target_exec = False
1036
1074
                else:
1037
1075
                    raise Exception, "unknown kind %s" % path_info[2]
1038
1076
            if source_minikind == c'd':
1039
1077
                if path is None:
1040
1078
                    old_path = path = pathjoin(old_dirname, old_basename)
 
1079
                if file_id is None:
 
1080
                    file_id = entry[0][2]
1041
1081
                self.old_dirname_to_file_id[old_path] = file_id
1042
1082
            # parent id is the entry for the path in the target tree
1043
1083
            if old_dirname == self.last_source_parent[0]:
1166
1206
            # a renamed parent. TODO: handle this efficiently. Its not
1167
1207
            # common case to rename dirs though, so a correct but slow
1168
1208
            # implementation will do.
1169
 
            if not osutils.is_inside_any(searched_specific_files, target_details[1]):
1170
 
                search_specific_files.add(target_details[1])
 
1209
            if not osutils.is_inside_any(self.searched_specific_files, target_details[1]):
 
1210
                self.search_specific_files.add(target_details[1])
1171
1211
        elif ((source_minikind == c'r' or source_minikind == c'a') and
1172
1212
              (target_minikind == c'r' or target_minikind == c'a')):
1173
1213
            # neither of the selected trees contain this file,