720
720
def tree_delta_from_git_changes(changes, mappings,
721
721
specific_files=None,
722
722
require_versioned=False, include_root=False,
723
source_extras=None, target_extras=None):
724
724
"""Create a TreeDelta from two git trees.
726
726
source and target are iterators over tuples with:
729
729
(old_mapping, new_mapping) = mappings
730
730
if target_extras is None:
731
731
target_extras = set()
732
if source_extras is None:
733
source_extras = set()
732
734
ret = delta.TreeDelta()
734
736
for (change_type, old, new) in changes:
736
738
(newpath, newmode, newsha) = new
737
739
if newpath == b'' and not include_root:
741
copied = (change_type == 'copy')
739
742
if oldpath is not None:
740
743
oldpath_decoded = oldpath.decode('utf-8')
753
756
specific_files, newpath_decoded))):
756
if oldpath_decoded is None:
757
fileid = new_mapping.generate_file_id(newpath_decoded)
762
764
oldversioned = False
766
oldversioned = (oldpath not in source_extras)
766
768
oldexe = mode_is_executable(oldmode)
767
769
oldkind = mode_kind(oldmode)
771
if oldpath_decoded == u'':
775
777
(oldparentpath, oldname) = osutils.split(oldpath_decoded)
776
778
oldparent = old_mapping.generate_file_id(oldparentpath)
786
newversioned = (newpath not in target_extras)
788
newexe = mode_is_executable(newmode)
789
newkind = mode_kind(newmode)
793
if newpath_decoded == u'':
797
newparentpath, newname = osutils.split(newpath_decoded)
798
newparent = new_mapping.generate_file_id(newparentpath)
799
if oldversioned and not copied:
777
800
fileid = old_mapping.generate_file_id(oldpath_decoded)
778
if newpath_decoded is None:
802
fileid = new_mapping.generate_file_id(newpath_decoded)
785
newversioned = (newpath_decoded not in target_extras)
787
newexe = mode_is_executable(newmode)
788
newkind = mode_kind(newmode)
792
if newpath_decoded == u'':
796
newparentpath, newname = osutils.split(newpath_decoded)
797
newparent = new_mapping.generate_file_id(newparentpath)
798
805
if old_mapping.is_special_file(oldpath):
800
807
if new_mapping.is_special_file(newpath):
806
813
(oldversioned, newversioned),
807
814
(oldparent, newparent), (oldname, newname),
808
815
(oldkind, newkind), (oldexe, newexe),
809
copied=(change_type == 'copy'))
817
if newpath is not None and not newversioned and newkind != 'directory':
818
change.file_id = None
819
ret.unversioned.append(change)
820
elif change_type == 'add':
811
821
added.append((newpath, newkind))
812
822
elif newpath is None or newmode == 0:
813
823
ret.removed.append(change)
814
elif oldpath != newpath:
815
if change_type == 'copy':
816
ret.copied.append(change)
818
ret.renamed.append(change)
824
elif change_type == 'delete':
825
ret.removed.append(change)
826
elif change_type == 'copy':
827
if stat.S_ISDIR(oldmode) and stat.S_ISDIR(newmode):
829
ret.copied.append(change)
830
elif change_type == 'rename':
831
if stat.S_ISDIR(oldmode) and stat.S_ISDIR(newmode):
833
ret.renamed.append(change)
819
834
elif mode_kind(oldmode) != mode_kind(newmode):
820
835
ret.kind_changed.append(change)
821
836
elif oldsha != newsha or oldmode != newmode:
837
852
path_decoded = osutils.normalized_filename(path)[0]
838
853
parent_path, basename = osutils.split(path_decoded)
839
854
parent_id = new_mapping.generate_file_id(parent_path)
840
if path in target_extras:
841
ret.unversioned.append(_mod_tree.TreeChange(
842
None, (None, path_decoded),
843
True, (False, False), (None, parent_id),
855
file_id = new_mapping.generate_file_id(path_decoded)
857
_mod_tree.TreeChange(
858
file_id, (None, path_decoded), True,
844
861
(None, basename), (None, kind), (None, False)))
846
file_id = new_mapping.generate_file_id(path_decoded)
848
_mod_tree.TreeChange(
849
file_id, (None, path_decoded), True,
852
(None, basename), (None, kind), (None, False)))
857
866
def changes_from_git_changes(changes, mapping, specific_files=None,
858
include_unchanged=False, target_extras=None):
867
include_unchanged=False, source_extras=None,
859
869
"""Create a iter_changes-like generator from a git stream.
861
871
source and target are iterators over tuples with:
864
874
if target_extras is None:
865
875
target_extras = set()
876
if source_extras is None:
877
source_extras = set()
866
878
for (change_type, old, new) in changes:
879
if change_type == 'unchanged' and not include_unchanged:
867
881
(oldpath, oldmode, oldsha) = old
868
882
(newpath, newmode, newsha) = new
869
883
if oldpath is not None:
887
901
if newpath is not None and mapping.is_special_file(newpath):
889
if oldpath_decoded is None:
890
fileid = mapping.generate_file_id(newpath_decoded)
895
908
oldversioned = False
910
oldversioned = (oldpath not in source_extras)
899
912
oldexe = mode_is_executable(oldmode)
900
913
oldkind = mode_kind(oldmode)
908
921
(oldparentpath, oldname) = osutils.split(oldpath_decoded)
909
922
oldparent = mapping.generate_file_id(oldparentpath)
910
fileid = mapping.generate_file_id(oldpath_decoded)
911
if newpath_decoded is None:
916
928
newversioned = False
918
newversioned = (newpath_decoded not in target_extras)
930
newversioned = (newpath not in target_extras)
920
932
newexe = mode_is_executable(newmode)
921
933
newkind = mode_kind(newmode)
929
941
newparentpath, newname = osutils.split(newpath_decoded)
930
942
newparent = mapping.generate_file_id(newparentpath)
931
943
if (not include_unchanged and
932
oldkind == 'directory' and newkind == 'directory' and
944
oldkind == 'directory' and newkind == 'directory' and
933
945
oldpath_decoded == newpath_decoded):
947
if oldversioned and change_type != 'copy':
948
fileid = mapping.generate_file_id(oldpath_decoded)
950
fileid = mapping.generate_file_id(newpath_decoded)
935
953
yield _mod_tree.TreeChange(
936
954
fileid, (oldpath_decoded, newpath_decoded), (oldsha != newsha),
937
955
(oldversioned, newversioned),
956
974
extra_trees=None, require_versioned=False, include_root=False,
957
975
want_unversioned=False):
958
976
with self.lock_read():
959
changes, target_extras = self._iter_git_changes(
977
changes, source_extras, target_extras = self._iter_git_changes(
960
978
want_unchanged=want_unchanged,
961
979
require_versioned=require_versioned,
962
980
specific_files=specific_files,
965
983
return tree_delta_from_git_changes(
966
984
changes, (self.source.mapping, self.target.mapping),
967
985
specific_files=specific_files,
968
include_root=include_root, target_extras=target_extras)
986
include_root=include_root,
987
source_extras=source_extras, target_extras=target_extras)
970
989
def iter_changes(self, include_unchanged=False, specific_files=None,
971
990
pb=None, extra_trees=[], require_versioned=True,
972
991
want_unversioned=False):
973
992
with self.lock_read():
974
changes, target_extras = self._iter_git_changes(
993
changes, source_extras, target_extras = self._iter_git_changes(
975
994
want_unchanged=include_unchanged,
976
995
require_versioned=require_versioned,
977
996
specific_files=specific_files,
981
1000
changes, self.target.mapping,
982
1001
specific_files=specific_files,
983
1002
include_unchanged=include_unchanged,
1003
source_extras=source_extras,
984
1004
target_extras=target_extras)
986
1006
def _iter_git_changes(self, want_unchanged=False, specific_files=None,
1069
1089
store = self.source._repository._git.object_store
1070
1090
rename_detector = RenameDetector(store)
1071
return tree_changes(
1072
store, self.source.tree, self.target.tree, want_unchanged=want_unchanged,
1073
include_trees=True, change_type_same=True, rename_detector=rename_detector), set()
1091
changes = tree_changes(
1092
store, self.source.tree, self.target.tree,
1093
want_unchanged=want_unchanged, include_trees=True,
1094
change_type_same=True, rename_detector=rename_detector)
1095
return changes, set(), set()
1076
1098
_mod_tree.InterTree.register_optimiser(InterGitRevisionTrees)
1633
1655
require_versioned=require_versioned)
1634
1656
# TODO(jelmer): Restrict to specific_files, for performance reasons.
1635
1657
with self.lock_read():
1636
return changes_between_git_tree_and_working_copy(
1658
changes, target_extras = changes_between_git_tree_and_working_copy(
1637
1659
self.source.store, self.source.tree,
1638
1660
self.target, want_unchanged=want_unchanged,
1639
1661
want_unversioned=want_unversioned,
1640
1662
rename_detector=self.rename_detector)
1663
return changes, set(), target_extras
1643
1666
_mod_tree.InterTree.register_optimiser(InterIndexGitTree)
1696
1719
target.store.add_object(blob)
1697
1720
blobs[path] = (live_entry.sha, cleanup_mode(live_entry.mode))
1698
1721
if want_unversioned:
1699
for e in target.extras():
1700
st = target._lstat(e)
1722
for e in target._iter_files_recursive(include_dirs=False):
1702
np, accessible = osutils.normalized_filename(e)
1724
e, accessible = osutils.normalized_filename(e)
1703
1725
except UnicodeDecodeError:
1704
1726
raise errors.BadFilenameEncoding(
1705
1727
e, osutils._fs_enc)
1728
np = e.encode('utf-8')
1731
st = target._lstat(e)
1706
1732
if stat.S_ISDIR(st.st_mode):
1708
1734
elif stat.S_ISREG(st.st_mode) or stat.S_ISLNK(st.st_mode):