/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to breezy/git/tree.py

Fix rename tracking for git.

Merged from https://code.launchpad.net/~jelmer/brz/renames2/+merge/386146

Show diffs side-by-side

added added

removed removed

Lines of Context:
726
726
def tree_delta_from_git_changes(changes, mappings,
727
727
                                specific_files=None,
728
728
                                require_versioned=False, include_root=False,
729
 
                                target_extras=None):
 
729
                                source_extras=None, target_extras=None):
730
730
    """Create a TreeDelta from two git trees.
731
731
 
732
732
    source and target are iterators over tuples with:
735
735
    (old_mapping, new_mapping) = mappings
736
736
    if target_extras is None:
737
737
        target_extras = set()
 
738
    if source_extras is None:
 
739
        source_extras = set()
738
740
    ret = delta.TreeDelta()
739
741
    added = []
740
742
    for (change_type, old, new) in changes:
742
744
        (newpath, newmode, newsha) = new
743
745
        if newpath == b'' and not include_root:
744
746
            continue
 
747
        copied = (change_type == 'copy')
745
748
        if oldpath is not None:
746
749
            oldpath_decoded = oldpath.decode('utf-8')
747
750
        else:
759
762
                        specific_files, newpath_decoded))):
760
763
            continue
761
764
 
762
 
        if oldpath_decoded is None:
763
 
            fileid = new_mapping.generate_file_id(newpath_decoded)
 
765
        if oldpath is None:
764
766
            oldexe = None
765
767
            oldkind = None
766
768
            oldname = None
767
769
            oldparent = None
768
770
            oldversioned = False
769
771
        else:
770
 
            oldversioned = True
 
772
            oldversioned = (oldpath not in source_extras)
771
773
            if oldmode:
772
774
                oldexe = mode_is_executable(oldmode)
773
775
                oldkind = mode_kind(oldmode)
774
776
            else:
775
777
                oldexe = False
776
778
                oldkind = None
777
 
            if oldpath_decoded == u'':
 
779
            if oldpath == b'':
778
780
                oldparent = None
779
781
                oldname = u''
780
782
            else:
781
783
                (oldparentpath, oldname) = osutils.split(oldpath_decoded)
782
784
                oldparent = old_mapping.generate_file_id(oldparentpath)
 
785
        if newpath is None:
 
786
            newexe = None
 
787
            newkind = None
 
788
            newname = None
 
789
            newparent = None
 
790
            newversioned = False
 
791
        else:
 
792
            newversioned = (newpath not in target_extras)
 
793
            if newmode:
 
794
                newexe = mode_is_executable(newmode)
 
795
                newkind = mode_kind(newmode)
 
796
            else:
 
797
                newexe = False
 
798
                newkind = None
 
799
            if newpath_decoded == u'':
 
800
                newparent = None
 
801
                newname = u''
 
802
            else:
 
803
                newparentpath, newname = osutils.split(newpath_decoded)
 
804
                newparent = new_mapping.generate_file_id(newparentpath)
 
805
        if oldversioned and not copied:
783
806
            fileid = old_mapping.generate_file_id(oldpath_decoded)
784
 
        if newpath_decoded is None:
785
 
            newexe = None
786
 
            newkind = None
787
 
            newname = None
788
 
            newparent = None
789
 
            newversioned = False
 
807
        elif newversioned:
 
808
            fileid = new_mapping.generate_file_id(newpath_decoded)
790
809
        else:
791
 
            newversioned = (newpath_decoded not in target_extras)
792
 
            if newmode:
793
 
                newexe = mode_is_executable(newmode)
794
 
                newkind = mode_kind(newmode)
795
 
            else:
796
 
                newexe = False
797
 
                newkind = None
798
 
            if newpath_decoded == u'':
799
 
                newparent = None
800
 
                newname = u''
801
 
            else:
802
 
                newparentpath, newname = osutils.split(newpath_decoded)
803
 
                newparent = new_mapping.generate_file_id(newparentpath)
 
810
            fileid = None
804
811
        if old_mapping.is_special_file(oldpath):
805
812
            oldpath = None
806
813
        if new_mapping.is_special_file(newpath):
812
819
            (oldversioned, newversioned),
813
820
            (oldparent, newparent), (oldname, newname),
814
821
            (oldkind, newkind), (oldexe, newexe),
815
 
            copied=(change_type == 'copy'))
816
 
        if oldpath is None:
 
822
            copied=copied)
 
823
        if newpath is not None and not newversioned and newkind != 'directory':
 
824
            change.file_id = None
 
825
            ret.unversioned.append(change)
 
826
        elif change_type == 'add':
817
827
            added.append((newpath, newkind))
818
828
        elif newpath is None or newmode == 0:
819
829
            ret.removed.append(change)
820
 
        elif oldpath != newpath:
821
 
            if change_type == 'copy':
822
 
                ret.copied.append(change)
823
 
            else:
824
 
                ret.renamed.append(change)
 
830
        elif change_type == 'delete':
 
831
            ret.removed.append(change)
 
832
        elif change_type == 'copy':
 
833
            if stat.S_ISDIR(oldmode) and stat.S_ISDIR(newmode):
 
834
                continue
 
835
            ret.copied.append(change)
 
836
        elif change_type == 'rename':
 
837
            if stat.S_ISDIR(oldmode) and stat.S_ISDIR(newmode):
 
838
                continue
 
839
            ret.renamed.append(change)
825
840
        elif mode_kind(oldmode) != mode_kind(newmode):
826
841
            ret.kind_changed.append(change)
827
842
        elif oldsha != newsha or oldmode != newmode:
843
858
        path_decoded = osutils.normalized_filename(path)[0]
844
859
        parent_path, basename = osutils.split(path_decoded)
845
860
        parent_id = new_mapping.generate_file_id(parent_path)
846
 
        if path in target_extras:
847
 
            ret.unversioned.append(_mod_tree.TreeChange(
848
 
                None, (None, path_decoded),
849
 
                True, (False, False), (None, parent_id),
 
861
        file_id = new_mapping.generate_file_id(path_decoded)
 
862
        ret.added.append(
 
863
            _mod_tree.TreeChange(
 
864
                file_id, (None, path_decoded), True,
 
865
                (False, True),
 
866
                (None, parent_id),
850
867
                (None, basename), (None, kind), (None, False)))
851
 
        else:
852
 
            file_id = new_mapping.generate_file_id(path_decoded)
853
 
            ret.added.append(
854
 
                _mod_tree.TreeChange(
855
 
                    file_id, (None, path_decoded), True,
856
 
                    (False, True),
857
 
                    (None, parent_id),
858
 
                    (None, basename), (None, kind), (None, False)))
859
868
 
860
869
    return ret
861
870
 
862
871
 
863
872
def changes_from_git_changes(changes, mapping, specific_files=None,
864
 
                             include_unchanged=False, target_extras=None):
 
873
                             include_unchanged=False, source_extras=None,
 
874
                             target_extras=None):
865
875
    """Create a iter_changes-like generator from a git stream.
866
876
 
867
877
    source and target are iterators over tuples with:
869
879
    """
870
880
    if target_extras is None:
871
881
        target_extras = set()
 
882
    if source_extras is None:
 
883
        source_extras = set()
872
884
    for (change_type, old, new) in changes:
 
885
        if change_type == 'unchanged' and not include_unchanged:
 
886
            continue
873
887
        (oldpath, oldmode, oldsha) = old
874
888
        (newpath, newmode, newsha) = new
875
889
        if oldpath is not None:
892
906
            continue
893
907
        if newpath is not None and mapping.is_special_file(newpath):
894
908
            continue
895
 
        if oldpath_decoded is None:
896
 
            fileid = mapping.generate_file_id(newpath_decoded)
 
909
        if oldpath is None:
897
910
            oldexe = None
898
911
            oldkind = None
899
912
            oldname = None
900
913
            oldparent = None
901
914
            oldversioned = False
902
915
        else:
903
 
            oldversioned = True
 
916
            oldversioned = (oldpath not in source_extras)
904
917
            if oldmode:
905
918
                oldexe = mode_is_executable(oldmode)
906
919
                oldkind = mode_kind(oldmode)
913
926
            else:
914
927
                (oldparentpath, oldname) = osutils.split(oldpath_decoded)
915
928
                oldparent = mapping.generate_file_id(oldparentpath)
916
 
            fileid = mapping.generate_file_id(oldpath_decoded)
917
 
        if newpath_decoded is None:
 
929
        if newpath is None:
918
930
            newexe = None
919
931
            newkind = None
920
932
            newname = None
921
933
            newparent = None
922
934
            newversioned = False
923
935
        else:
924
 
            newversioned = (newpath_decoded not in target_extras)
 
936
            newversioned = (newpath not in target_extras)
925
937
            if newmode:
926
938
                newexe = mode_is_executable(newmode)
927
939
                newkind = mode_kind(newmode)
935
947
                newparentpath, newname = osutils.split(newpath_decoded)
936
948
                newparent = mapping.generate_file_id(newparentpath)
937
949
        if (not include_unchanged and
938
 
            oldkind == 'directory' and newkind == 'directory' and
 
950
                oldkind == 'directory' and newkind == 'directory' and
939
951
                oldpath_decoded == newpath_decoded):
940
952
            continue
 
953
        if oldversioned and change_type != 'copy':
 
954
            fileid = mapping.generate_file_id(oldpath_decoded)
 
955
        elif newversioned:
 
956
            fileid = mapping.generate_file_id(newpath_decoded)
 
957
        else:
 
958
            fileid = None
941
959
        yield _mod_tree.TreeChange(
942
960
            fileid, (oldpath_decoded, newpath_decoded), (oldsha != newsha),
943
961
            (oldversioned, newversioned),
962
980
                extra_trees=None, require_versioned=False, include_root=False,
963
981
                want_unversioned=False):
964
982
        with self.lock_read():
965
 
            changes, target_extras = self._iter_git_changes(
 
983
            changes, source_extras, target_extras = self._iter_git_changes(
966
984
                want_unchanged=want_unchanged,
967
985
                require_versioned=require_versioned,
968
986
                specific_files=specific_files,
971
989
            return tree_delta_from_git_changes(
972
990
                changes, (self.source.mapping, self.target.mapping),
973
991
                specific_files=specific_files,
974
 
                include_root=include_root, target_extras=target_extras)
 
992
                include_root=include_root,
 
993
                source_extras=source_extras, target_extras=target_extras)
975
994
 
976
995
    def iter_changes(self, include_unchanged=False, specific_files=None,
977
996
                     pb=None, extra_trees=[], require_versioned=True,
978
997
                     want_unversioned=False):
979
998
        with self.lock_read():
980
 
            changes, target_extras = self._iter_git_changes(
 
999
            changes, source_extras, target_extras = self._iter_git_changes(
981
1000
                want_unchanged=include_unchanged,
982
1001
                require_versioned=require_versioned,
983
1002
                specific_files=specific_files,
987
1006
                changes, self.target.mapping,
988
1007
                specific_files=specific_files,
989
1008
                include_unchanged=include_unchanged,
 
1009
                source_extras=source_extras,
990
1010
                target_extras=target_extras)
991
1011
 
992
1012
    def _iter_git_changes(self, want_unchanged=False, specific_files=None,
1074
1094
        else:
1075
1095
            store = self.source._repository._git.object_store
1076
1096
        rename_detector = RenameDetector(store)
1077
 
        return tree_changes(
1078
 
            store, self.source.tree, self.target.tree, want_unchanged=want_unchanged,
1079
 
            include_trees=True, change_type_same=True, rename_detector=rename_detector), set()
 
1097
        changes = tree_changes(
 
1098
            store, self.source.tree, self.target.tree,
 
1099
            want_unchanged=want_unchanged, include_trees=True,
 
1100
            change_type_same=True, rename_detector=rename_detector)
 
1101
        return changes, set(), set()
1080
1102
 
1081
1103
 
1082
1104
_mod_tree.InterTree.register_optimiser(InterGitRevisionTrees)
1639
1661
                require_versioned=require_versioned)
1640
1662
        # TODO(jelmer): Restrict to specific_files, for performance reasons.
1641
1663
        with self.lock_read():
1642
 
            return changes_between_git_tree_and_working_copy(
 
1664
            changes, target_extras = changes_between_git_tree_and_working_copy(
1643
1665
                self.source.store, self.source.tree,
1644
1666
                self.target, want_unchanged=want_unchanged,
1645
1667
                want_unversioned=want_unversioned,
1646
1668
                rename_detector=self.rename_detector)
 
1669
            return changes, set(), target_extras
1647
1670
 
1648
1671
 
1649
1672
_mod_tree.InterTree.register_optimiser(InterIndexGitTree)
1702
1725
                        target.store.add_object(blob)
1703
1726
                blobs[path] = (live_entry.sha, cleanup_mode(live_entry.mode))
1704
1727
    if want_unversioned:
1705
 
        for e in target.extras():
1706
 
            st = target._lstat(e)
 
1728
        for e in target._iter_files_recursive(include_dirs=False):
1707
1729
            try:
1708
 
                np, accessible = osutils.normalized_filename(e)
 
1730
                e, accessible = osutils.normalized_filename(e)
1709
1731
            except UnicodeDecodeError:
1710
1732
                raise errors.BadFilenameEncoding(
1711
1733
                    e, osutils._fs_enc)
 
1734
            np = e.encode('utf-8')
 
1735
            if np in blobs:
 
1736
                continue
 
1737
            st = target._lstat(e)
1712
1738
            if stat.S_ISDIR(st.st_mode):
1713
1739
                blob = Tree()
1714
1740
            elif stat.S_ISREG(st.st_mode) or stat.S_ISLNK(st.st_mode):
1717
1743
            else:
1718
1744
                continue
1719
1745
            target.store.add_object(blob)
1720
 
            np = np.encode('utf-8')
1721
1746
            blobs[np] = (blob.id, cleanup_mode(st.st_mode))
1722
1747
            extras.add(np)
1723
1748
    to_tree_sha = commit_tree(