726
726
def tree_delta_from_git_changes(changes, mappings,
727
727
specific_files=None,
728
728
require_versioned=False, include_root=False,
729
source_extras=None, target_extras=None):
730
730
"""Create a TreeDelta from two git trees.
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()
740
742
for (change_type, old, new) in changes:
742
744
(newpath, newmode, newsha) = new
743
745
if newpath == b'' and not include_root:
747
copied = (change_type == 'copy')
745
748
if oldpath is not None:
746
749
oldpath_decoded = oldpath.decode('utf-8')
759
762
specific_files, newpath_decoded))):
762
if oldpath_decoded is None:
763
fileid = new_mapping.generate_file_id(newpath_decoded)
768
770
oldversioned = False
772
oldversioned = (oldpath not in source_extras)
772
774
oldexe = mode_is_executable(oldmode)
773
775
oldkind = mode_kind(oldmode)
777
if oldpath_decoded == u'':
781
783
(oldparentpath, oldname) = osutils.split(oldpath_decoded)
782
784
oldparent = old_mapping.generate_file_id(oldparentpath)
792
newversioned = (newpath not in target_extras)
794
newexe = mode_is_executable(newmode)
795
newkind = mode_kind(newmode)
799
if newpath_decoded == u'':
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:
808
fileid = new_mapping.generate_file_id(newpath_decoded)
791
newversioned = (newpath_decoded not in target_extras)
793
newexe = mode_is_executable(newmode)
794
newkind = mode_kind(newmode)
798
if newpath_decoded == u'':
802
newparentpath, newname = osutils.split(newpath_decoded)
803
newparent = new_mapping.generate_file_id(newparentpath)
804
811
if old_mapping.is_special_file(oldpath):
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'))
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)
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):
835
ret.copied.append(change)
836
elif change_type == 'rename':
837
if stat.S_ISDIR(oldmode) and stat.S_ISDIR(newmode):
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)
863
_mod_tree.TreeChange(
864
file_id, (None, path_decoded), True,
850
867
(None, basename), (None, kind), (None, False)))
852
file_id = new_mapping.generate_file_id(path_decoded)
854
_mod_tree.TreeChange(
855
file_id, (None, path_decoded), True,
858
(None, basename), (None, kind), (None, False)))
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,
865
875
"""Create a iter_changes-like generator from a git stream.
867
877
source and target are iterators over tuples with:
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:
873
887
(oldpath, oldmode, oldsha) = old
874
888
(newpath, newmode, newsha) = new
875
889
if oldpath is not None:
893
907
if newpath is not None and mapping.is_special_file(newpath):
895
if oldpath_decoded is None:
896
fileid = mapping.generate_file_id(newpath_decoded)
901
914
oldversioned = False
916
oldversioned = (oldpath not in source_extras)
905
918
oldexe = mode_is_executable(oldmode)
906
919
oldkind = mode_kind(oldmode)
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:
922
934
newversioned = False
924
newversioned = (newpath_decoded not in target_extras)
936
newversioned = (newpath not in target_extras)
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):
953
if oldversioned and change_type != 'copy':
954
fileid = mapping.generate_file_id(oldpath_decoded)
956
fileid = mapping.generate_file_id(newpath_decoded)
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)
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)
992
1012
def _iter_git_changes(self, want_unchanged=False, specific_files=None,
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()
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
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):
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')
1737
st = target._lstat(e)
1712
1738
if stat.S_ISDIR(st.st_mode):
1714
1740
elif stat.S_ISREG(st.st_mode) or stat.S_ISLNK(st.st_mode):