261
261
if revision_id == NULL_REVISION:
263
263
self.mapping = default_mapping
264
self._fileid_map = GitFileIdMap(
269
266
commit = self.store[self.commit_id]
271
268
raise errors.NoSuchRevision(repository, revision_id)
272
269
self.tree = commit.tree
273
self._fileid_map = self.mapping.get_fileid_map(
274
self.store.__getitem__, self.tree)
276
def _get_nested_repository(self, path):
277
nested_repo_transport = self._repository.user_transport.clone(path)
271
def _submodule_info(self):
272
if self._submodules is None:
274
with self.get_file('.gitmodules') as f:
275
config = GitConfigFile.from_file(f)
278
for path, url, section in parse_submodules(config)}
279
except errors.NoSuchFile:
280
self._submodules = {}
281
return self._submodules
283
def _get_submodule_repository(self, relpath):
284
if not isinstance(relpath, bytes):
285
raise TypeError(relpath)
287
info = self._submodule_info()[relpath]
289
nested_repo_transport = self._repository.user_transport.clone(relpath.decode('utf-8'))
291
nested_repo_transport = self._repository.control_transport.clone(
292
posixpath.join('modules', info[0]))
278
293
nested_controldir = _mod_controldir.ControlDir.open_from_transport(
279
294
nested_repo_transport)
280
295
return nested_controldir.find_repository()
297
def get_nested_tree(self, path):
298
encoded_path = path.encode('utf-8')
299
nested_repo = self._get_submodule_repository(encoded_path)
300
ref_rev = self.get_reference_revision(path)
301
return nested_repo.revision_tree(ref_rev)
282
303
def supports_rename_tracking(self):
479
481
yield self._get_file_ie(store, child_path, name, mode, hexsha,
482
def iter_entries_by_dir(self, specific_files=None, yield_parents=False):
484
def iter_entries_by_dir(self, specific_files=None):
483
485
if self.tree is None:
486
# TODO(jelmer): Support yield parents
487
raise NotImplementedError
488
487
if specific_files is not None:
489
488
if specific_files in ([""], []):
490
489
specific_files = None
492
491
specific_files = set([p.encode('utf-8')
493
492
for p in specific_files])
494
todo = deque([(self.store, b"", self.tree, self.get_root_id())])
493
todo = deque([(self.store, b"", self.tree, self.path2id(''))])
495
494
if specific_files is None or u"" in specific_files:
496
495
yield u"", self._get_dir_ie(b"", None)
666
665
yield (path_decoded, parent_id), children
669
def tree_delta_from_git_changes(changes, mapping,
670
fileid_maps, specific_files=None,
668
def tree_delta_from_git_changes(changes, mappings,
671
670
require_versioned=False, include_root=False,
672
671
target_extras=None):
673
672
"""Create a TreeDelta from two git trees.
683
682
for (oldpath, newpath), (oldmode, newmode), (oldsha, newsha) in changes:
684
683
if newpath == b'' and not include_root:
685
if oldpath is not None:
686
oldpath_decoded = oldpath.decode('utf-8')
687
688
oldpath_decoded = None
689
if newpath is not None:
690
newpath_decoded = newpath.decode('utf-8')
689
oldpath_decoded = oldpath.decode('utf-8')
691
692
newpath_decoded = None
693
newpath_decoded = newpath.decode('utf-8')
694
693
if not (specific_files is None or
695
694
(oldpath is not None and
696
695
osutils.is_inside_or_parent_of_any(
699
698
osutils.is_inside_or_parent_of_any(
700
699
specific_files, newpath_decoded))):
702
if mapping.is_special_file(oldpath):
702
if oldpath_decoded is None:
703
fileid = new_mapping.generate_file_id(newpath_decoded)
712
oldexe = mode_is_executable(oldmode)
713
oldkind = mode_kind(oldmode)
717
if oldpath_decoded == u'':
721
(oldparentpath, oldname) = osutils.split(oldpath_decoded)
722
oldparent = old_mapping.generate_file_id(oldparentpath)
723
fileid = old_mapping.generate_file_id(oldpath_decoded)
724
if newpath_decoded is None:
731
newversioned = (newpath_decoded not in target_extras)
733
newexe = mode_is_executable(newmode)
734
newkind = mode_kind(newmode)
738
if newpath_decoded == u'':
742
newparentpath, newname = osutils.split(newpath_decoded)
743
newparent = new_mapping.generate_file_id(newparentpath)
744
if old_mapping.is_special_file(oldpath):
704
if mapping.is_special_file(newpath):
746
if new_mapping.is_special_file(newpath):
706
748
if oldpath is None and newpath is None:
750
change = _mod_tree.TreeChange(
751
fileid, (oldpath_decoded, newpath_decoded), (oldsha != newsha),
752
(oldversioned, newversioned),
753
(oldparent, newparent), (oldname, newname),
754
(oldkind, newkind), (oldexe, newexe))
708
755
if oldpath is None:
709
added.append((newpath, mode_kind(newmode)))
756
added.append((newpath, newkind))
710
757
elif newpath is None or newmode == 0:
711
file_id = old_fileid_map.lookup_file_id(oldpath_decoded)
712
ret.removed.append((oldpath_decoded, file_id, mode_kind(oldmode)))
758
ret.removed.append(change)
713
759
elif oldpath != newpath:
714
file_id = old_fileid_map.lookup_file_id(oldpath_decoded)
716
(oldpath_decoded, newpath.decode('utf-8'), file_id,
717
mode_kind(newmode), (oldsha != newsha),
718
(oldmode != newmode)))
760
ret.renamed.append(change)
719
761
elif mode_kind(oldmode) != mode_kind(newmode):
720
file_id = new_fileid_map.lookup_file_id(newpath_decoded)
721
ret.kind_changed.append(
722
(newpath_decoded, file_id, mode_kind(oldmode),
762
ret.kind_changed.append(change)
724
763
elif oldsha != newsha or oldmode != newmode:
725
764
if stat.S_ISDIR(oldmode) and stat.S_ISDIR(newmode):
727
file_id = new_fileid_map.lookup_file_id(newpath_decoded)
729
(newpath_decoded, file_id, mode_kind(newmode),
730
(oldsha != newsha), (oldmode != newmode)))
766
ret.modified.append(change)
732
file_id = new_fileid_map.lookup_file_id(newpath_decoded)
733
ret.unchanged.append(
734
(newpath_decoded, file_id, mode_kind(newmode)))
768
ret.unchanged.append(change)
736
770
implicit_dirs = {b''}
737
771
for path, kind in added:
743
777
if kind == 'directory' and path not in implicit_dirs:
745
779
path_decoded = osutils.normalized_filename(path)[0]
780
parent_path, basename = osutils.split(path_decoded)
781
parent_id = new_mapping.generate_file_id(parent_path)
746
782
if path in target_extras:
747
ret.unversioned.append((path_decoded, None, kind))
783
ret.unversioned.append(_mod_tree.TreeChange(
784
None, (None, path_decoded),
785
True, (False, False), (None, parent_id),
786
(None, basename), (None, kind), (None, False)))
749
file_id = new_fileid_map.lookup_file_id(path_decoded)
750
ret.added.append((path_decoded, file_id, kind))
788
file_id = new_mapping.generate_file_id(path_decoded)
790
_mod_tree.TreeChange(
791
file_id, (None, path_decoded), True,
794
(None, basename), (None, kind), (None, False)))
828
872
oldkind == 'directory' and newkind == 'directory' and
829
873
oldpath_decoded == newpath_decoded):
831
yield (fileid, (oldpath_decoded, newpath_decoded), (oldsha != newsha),
832
(oldversioned, newversioned),
833
(oldparent, newparent), (oldname, newname),
834
(oldkind, newkind), (oldexe, newexe))
875
yield _mod_tree.TreeChange(
876
fileid, (oldpath_decoded, newpath_decoded), (oldsha != newsha),
877
(oldversioned, newversioned),
878
(oldparent, newparent), (oldname, newname),
879
(oldkind, newkind), (oldexe, newexe))
837
882
class InterGitTrees(_mod_tree.InterTree):
856
901
specific_files=specific_files,
857
902
extra_trees=extra_trees,
858
903
want_unversioned=want_unversioned)
859
source_fileid_map = self.source._fileid_map
860
target_fileid_map = self.target._fileid_map
861
904
return tree_delta_from_git_changes(
862
changes, self.target.mapping,
863
(source_fileid_map, target_fileid_map),
905
changes, (self.source.mapping, self.target.mapping),
864
906
specific_files=specific_files,
865
907
include_root=include_root, target_extras=target_extras)
1123
1152
file_ie = self._get_file_ie(name, path, value, None)
1124
1153
except errors.NoSuchFile:
1126
if yield_parents or specific_files is None:
1155
if specific_files is None:
1127
1156
for (dir_path, dir_ie) in self._add_missing_parent_ids(
1128
1157
parent, dir_ids):
1129
1158
ret[(posixpath.dirname(dir_path), dir_path)] = dir_ie
1130
1159
file_ie.parent_id = self.path2id(parent)
1131
1160
ret[(posixpath.dirname(path), path)] = file_ie
1161
# Special casing for directories
1163
for path in specific_files:
1164
key = (posixpath.dirname(path), path)
1165
if key not in ret and self.is_versioned(path):
1166
ret[key] = self._get_dir_ie(path, self.path2id(key[0]))
1132
1167
return ((path, ie) for ((_, path), ie) in sorted(viewitems(ret)))
1134
1169
def iter_references(self):
1135
1170
# TODO(jelmer): Implement a more efficient version of this
1136
1171
for path, entry in self.iter_entries_by_dir():
1137
1172
if entry.kind == 'tree-reference':
1138
yield path, self.mapping.generate_file_id(b'')
1140
1175
def _get_dir_ie(self, path, parent_id):
1141
1176
file_id = self.path2id(path)