136
135
self.executable == other.executable)
138
137
def __repr__(self):
139
return "%s(file_id=%r, name=%r, parent_id=%r, text_size=%r, text_sha1=%r, executable=%r)" % (
138
return ("%s(file_id=%r, name=%r, parent_id=%r, text_size=%r, "
139
"text_sha1=%r, executable=%r)") % (
140
140
type(self).__name__, self.file_id, self.name, self.parent_id,
141
141
self.text_size, self.text_sha1, self.executable)
144
144
ret = self.__class__(
145
self.file_id, self.name, self.parent_id)
145
self.file_id, self.name, self.parent_id)
146
146
ret.text_sha1 = self.text_sha1
147
147
ret.text_size = self.text_size
148
148
ret.executable = self.executable
269
271
raise errors.NoSuchRevision(repository, revision_id)
270
272
self.tree = commit.tree
271
self._fileid_map = self.mapping.get_fileid_map(self.store.__getitem__, self.tree)
273
self._fileid_map = self.mapping.get_fileid_map(
274
self.store.__getitem__, self.tree)
273
276
def _get_nested_repository(self, path):
274
277
nested_repo_transport = self._repository.user_transport.clone(path)
275
nested_controldir = _mod_controldir.ControlDir.open_from_transport(nested_repo_transport)
278
nested_controldir = _mod_controldir.ControlDir.open_from_transport(
279
nested_repo_transport)
276
280
return nested_controldir.find_repository()
278
282
def supports_rename_tracking(self):
281
def get_file_revision(self, path, file_id=None):
285
def get_file_revision(self, path):
282
286
change_scanner = self._repository._file_change_scanner
283
287
if self.commit_id == ZERO_SHA:
284
288
return NULL_REVISION
285
289
(unused_path, commit_id) = change_scanner.find_last_change_revision(
286
290
path.encode('utf-8'), self.commit_id)
287
return self._repository.lookup_foreign_revision_id(commit_id, self.mapping)
291
return self._repository.lookup_foreign_revision_id(
292
commit_id, self.mapping)
289
def get_file_mtime(self, path, file_id=None):
294
def get_file_mtime(self, path):
291
revid = self.get_file_revision(path, file_id)
296
revid = self.get_file_revision(path)
293
298
raise errors.NoSuchFile(path)
357
362
if self.tree is None:
358
363
raise errors.NoSuchFile(path)
360
(mode, hexsha) = tree_lookup_path(self.store.__getitem__, self.tree,
361
path.encode('utf-8'))
365
(mode, hexsha) = tree_lookup_path(
366
self.store.__getitem__, self.tree, path.encode('utf-8'))
363
368
raise errors.NoSuchFile(self, path)
365
370
return (self.store, mode, hexsha)
367
def is_executable(self, path, file_id=None):
372
def is_executable(self, path):
368
373
(store, mode, hexsha) = self._lookup_path(path)
370
375
# the tree root is a directory
372
377
return mode_is_executable(mode)
374
def kind(self, path, file_id=None):
379
def kind(self, path):
375
380
(store, mode, hexsha) = self._lookup_path(path)
377
382
# the tree root is a directory
400
405
if mode_kind(mode) == 'directory':
401
406
root_ie = self._get_dir_ie(from_dir.encode("utf-8"), parent_id)
403
root_ie = self._get_file_ie(store, from_dir.encode("utf-8"),
408
root_ie = self._get_file_ie(
409
store, from_dir.encode("utf-8"),
404
410
posixpath.basename(from_dir), mode, hexsha)
406
yield (from_dir, "V", root_ie.kind, root_ie.file_id, root_ie)
412
yield (from_dir, "V", root_ie.kind, root_ie)
408
414
if root_ie.kind == 'directory':
409
todo.append((store, from_dir.encode("utf-8"), b"", hexsha, root_ie.file_id))
415
todo.append((store, from_dir.encode("utf-8"),
416
b"", hexsha, root_ie.file_id))
411
418
(store, path, relpath, hexsha, parent_id) = todo.pop()
412
419
tree = store[hexsha]
418
425
if stat.S_ISDIR(mode):
419
426
ie = self._get_dir_ie(child_path, parent_id)
421
todo.append((store, child_path, child_relpath, hexsha, ie.file_id))
429
(store, child_path, child_relpath, hexsha,
423
ie = self._get_file_ie(store, child_path, name, mode, hexsha, parent_id)
424
yield child_relpath.decode('utf-8'), "V", ie.kind, ie.file_id, ie
432
ie = self._get_file_ie(
433
store, child_path, name, mode, hexsha, parent_id)
434
yield (child_relpath.decode('utf-8'), "V", ie.kind, ie)
426
436
def _get_file_ie(self, store, path, name, mode, hexsha, parent_id):
427
437
if not isinstance(path, bytes):
449
460
file_id = self._fileid_map.lookup_file_id(path)
450
461
return GitTreeDirectory(file_id, posixpath.basename(path), parent_id)
452
def iter_child_entries(self, path, file_id=None):
463
def iter_child_entries(self, path):
453
464
(store, mode, tree_sha) = self._lookup_path(path)
455
466
if mode is not None and not stat.S_ISDIR(mode):
478
489
if specific_files in ([""], []):
479
490
specific_files = None
481
specific_files = set([p.encode('utf-8') for p in specific_files])
492
specific_files = set([p.encode('utf-8')
493
for p in specific_files])
482
494
todo = deque([(self.store, b"", self.tree, self.get_root_id())])
483
495
if specific_files is None or u"" in specific_files:
484
496
yield u"", self._get_dir_ie(b"", None)
493
505
child_path_decoded = child_path.decode('utf-8')
494
506
if stat.S_ISDIR(mode):
495
507
if (specific_files is None or
496
any(filter(lambda p: p.startswith(child_path), specific_files))):
508
any([p for p in specific_files if p.startswith(
497
510
extradirs.append(
498
(store, child_path, hexsha, self.path2id(child_path_decoded)))
511
(store, child_path, hexsha,
512
self.path2id(child_path_decoded)))
499
513
if specific_files is None or child_path in specific_files:
500
514
if stat.S_ISDIR(mode):
501
515
yield (child_path_decoded,
516
530
"""See RevisionTree.get_revision_id."""
517
531
return self._revision_id
519
def get_file_sha1(self, path, file_id=None, stat_value=None):
533
def get_file_sha1(self, path, stat_value=None):
520
534
if self.tree is None:
521
535
raise errors.NoSuchFile(path)
522
return osutils.sha_string(self.get_file_text(path, file_id))
536
return osutils.sha_string(self.get_file_text(path))
524
def get_file_verifier(self, path, file_id=None, stat_value=None):
538
def get_file_verifier(self, path, stat_value=None):
525
539
(store, mode, hexsha) = self._lookup_path(path)
526
540
return ("GIT", hexsha)
528
def get_file_size(self, path, file_id=None):
542
def get_file_size(self, path):
529
543
(store, mode, hexsha) = self._lookup_path(path)
530
544
if stat.S_ISREG(mode):
531
545
return len(store[hexsha].data)
534
def get_file_text(self, path, file_id=None):
548
def get_file_text(self, path):
535
549
"""See RevisionTree.get_file_text."""
536
550
(store, mode, hexsha) = self._lookup_path(path)
537
551
if stat.S_ISREG(mode):
571
585
if kind == 'file':
572
586
executable = mode_is_executable(mode)
573
587
contents = store[hexsha].data
574
return (kind, len(contents), executable, osutils.sha_string(contents))
588
return (kind, len(contents), executable,
589
osutils.sha_string(contents))
575
590
elif kind == 'symlink':
576
591
return (kind, None, None, store[hexsha].data.decode('utf-8'))
577
592
elif kind == 'tree-reference':
602
617
if self.tree is None:
604
619
return self.store.iter_tree_contents(
605
self.tree, include_trees=include_trees)
620
self.tree, include_trees=include_trees)
607
def annotate_iter(self, path, file_id=None,
608
default_revision=CURRENT_REVISION):
622
def annotate_iter(self, path, default_revision=CURRENT_REVISION):
609
623
"""Return an iterator of revision_id, line tuples.
611
625
For working trees (and mutable trees in general), the special
612
626
revision_id 'current:' will be used for lines that are new in this
613
627
tree, e.g. uncommitted changes.
614
:param file_id: The file to produce an annotated version from
615
628
:param default_revision: For lines that don't match a basis, mark them
616
629
with this revision id. Not all implementations will make use of
633
646
def walkdirs(self, prefix=u""):
634
647
(store, mode, hexsha) = self._lookup_path(prefix)
635
todo = deque([(store, prefix.encode('utf-8'), hexsha, self.path2id(prefix))])
649
[(store, prefix.encode('utf-8'), hexsha, self.path2id(prefix))])
637
651
store, path, tree_sha, parent_id = todo.popleft()
638
652
path_decoded = path.decode('utf-8')
655
669
def tree_delta_from_git_changes(changes, mapping,
656
fileid_maps, specific_files=None,
657
require_versioned=False, include_root=False,
670
fileid_maps, specific_files=None,
671
require_versioned=False, include_root=False,
659
673
"""Create a TreeDelta from two git trees.
661
675
source and target are iterators over tuples with:
678
693
newpath_decoded = newpath.decode('utf-8')
679
694
if not (specific_files is None or
680
(oldpath is not None and osutils.is_inside_or_parent_of_any(specific_files, oldpath_decoded)) or
681
(newpath is not None and osutils.is_inside_or_parent_of_any(specific_files, newpath_decoded))):
695
(oldpath is not None and
696
osutils.is_inside_or_parent_of_any(
697
specific_files, oldpath_decoded)) or
698
(newpath is not None and
699
osutils.is_inside_or_parent_of_any(
700
specific_files, newpath_decoded))):
683
702
if mapping.is_special_file(oldpath):
687
706
if oldpath is None and newpath is None:
689
708
if oldpath is None:
690
if newpath in target_extras:
691
ret.unversioned.append(
692
(osutils.normalized_filename(newpath)[0], None, mode_kind(newmode)))
694
file_id = new_fileid_map.lookup_file_id(newpath_decoded)
695
ret.added.append((newpath_decoded, file_id, mode_kind(newmode)))
709
added.append((newpath, mode_kind(newmode)))
696
710
elif newpath is None or newmode == 0:
697
711
file_id = old_fileid_map.lookup_file_id(oldpath_decoded)
698
712
ret.removed.append((oldpath_decoded, file_id, mode_kind(oldmode)))
700
714
file_id = old_fileid_map.lookup_file_id(oldpath_decoded)
701
715
ret.renamed.append(
702
716
(oldpath_decoded, newpath.decode('utf-8'), file_id,
703
mode_kind(newmode), (oldsha != newsha),
704
(oldmode != newmode)))
717
mode_kind(newmode), (oldsha != newsha),
718
(oldmode != newmode)))
705
719
elif mode_kind(oldmode) != mode_kind(newmode):
706
720
file_id = new_fileid_map.lookup_file_id(newpath_decoded)
707
721
ret.kind_changed.append(
708
722
(newpath_decoded, file_id, mode_kind(oldmode),
710
724
elif oldsha != newsha or oldmode != newmode:
711
725
if stat.S_ISDIR(oldmode) and stat.S_ISDIR(newmode):
713
727
file_id = new_fileid_map.lookup_file_id(newpath_decoded)
714
728
ret.modified.append(
715
729
(newpath_decoded, file_id, mode_kind(newmode),
716
(oldsha != newsha), (oldmode != newmode)))
730
(oldsha != newsha), (oldmode != newmode)))
718
732
file_id = new_fileid_map.lookup_file_id(newpath_decoded)
719
ret.unchanged.append((newpath_decoded, file_id, mode_kind(newmode)))
733
ret.unchanged.append(
734
(newpath_decoded, file_id, mode_kind(newmode)))
736
implicit_dirs = {b''}
737
for path, kind in added:
738
if kind == 'directory' or path in target_extras:
740
implicit_dirs.update(osutils.parent_directories(path))
742
for path, kind in added:
743
if kind == 'directory' and path not in implicit_dirs:
745
path_decoded = osutils.normalized_filename(path)[0]
746
if path in target_extras:
747
ret.unversioned.append((path_decoded, None, kind))
749
file_id = new_fileid_map.lookup_file_id(path_decoded)
750
ret.added.append((path_decoded, file_id, kind))
724
def changes_from_git_changes(changes, mapping, specific_files=None, include_unchanged=False,
755
def changes_from_git_changes(changes, mapping, specific_files=None,
756
include_unchanged=False, target_extras=None):
726
757
"""Create a iter_changes-like generator from a git stream.
728
759
source and target are iterators over tuples with:
741
772
newpath_decoded = None
742
773
if not (specific_files is None or
743
(oldpath_decoded is not None and osutils.is_inside_or_parent_of_any(specific_files, oldpath_decoded)) or
744
(newpath_decoded is not None and osutils.is_inside_or_parent_of_any(specific_files, newpath_decoded))):
774
(oldpath_decoded is not None and
775
osutils.is_inside_or_parent_of_any(
776
specific_files, oldpath_decoded)) or
777
(newpath_decoded is not None and
778
osutils.is_inside_or_parent_of_any(
779
specific_files, newpath_decoded))):
746
781
if oldpath is not None and mapping.is_special_file(oldpath):
791
826
newparent = mapping.generate_file_id(newparentpath)
792
827
if (not include_unchanged and
793
828
oldkind == 'directory' and newkind == 'directory' and
794
oldpath_decoded == newpath_decoded):
829
oldpath_decoded == newpath_decoded):
796
831
yield (fileid, (oldpath_decoded, newpath_decoded), (oldsha != newsha),
797
(oldversioned, newversioned),
798
(oldparent, newparent), (oldname, newname),
799
(oldkind, newkind), (oldexe, newexe))
832
(oldversioned, newversioned),
833
(oldparent, newparent), (oldname, newname),
834
(oldkind, newkind), (oldexe, newexe))
802
837
class InterGitTrees(_mod_tree.InterTree):
816
851
want_unversioned=False):
817
852
with self.lock_read():
818
853
changes, target_extras = self._iter_git_changes(
819
want_unchanged=want_unchanged,
820
require_versioned=require_versioned,
821
specific_files=specific_files,
822
extra_trees=extra_trees,
823
want_unversioned=want_unversioned)
854
want_unchanged=want_unchanged,
855
require_versioned=require_versioned,
856
specific_files=specific_files,
857
extra_trees=extra_trees,
858
want_unversioned=want_unversioned)
824
859
source_fileid_map = self.source._fileid_map
825
860
target_fileid_map = self.target._fileid_map
826
return tree_delta_from_git_changes(changes, self.target.mapping,
861
return tree_delta_from_git_changes(
862
changes, self.target.mapping,
827
863
(source_fileid_map, target_fileid_map),
828
specific_files=specific_files, include_root=include_root,
829
target_extras=target_extras)
864
specific_files=specific_files,
865
include_root=include_root, target_extras=target_extras)
831
867
def iter_changes(self, include_unchanged=False, specific_files=None,
832
868
pb=None, extra_trees=[], require_versioned=True,
833
869
want_unversioned=False):
834
870
with self.lock_read():
835
871
changes, target_extras = self._iter_git_changes(
836
want_unchanged=include_unchanged,
837
require_versioned=require_versioned,
838
specific_files=specific_files,
839
extra_trees=extra_trees,
840
want_unversioned=want_unversioned)
872
want_unchanged=include_unchanged,
873
require_versioned=require_versioned,
874
specific_files=specific_files,
875
extra_trees=extra_trees,
876
want_unversioned=want_unversioned)
841
877
return changes_from_git_changes(
842
changes, self.target.mapping,
843
specific_files=specific_files,
844
include_unchanged=include_unchanged,
845
target_extras=target_extras)
878
changes, self.target.mapping,
879
specific_files=specific_files,
880
include_unchanged=include_unchanged,
881
target_extras=target_extras)
847
883
def _iter_git_changes(self, want_unchanged=False, specific_files=None,
848
require_versioned=False, extra_trees=None,
849
want_unversioned=False):
884
require_versioned=False, extra_trees=None,
885
want_unversioned=False):
850
886
raise NotImplementedError(self._iter_git_changes)
863
899
isinstance(target, GitRevisionTree))
865
901
def _iter_git_changes(self, want_unchanged=False, specific_files=None,
866
require_versioned=True, extra_trees=None,
867
want_unversioned=False):
902
require_versioned=True, extra_trees=None,
903
want_unversioned=False):
868
904
trees = [self.source]
869
905
if extra_trees is not None:
870
906
trees.extend(extra_trees)
871
907
if specific_files is not None:
872
908
specific_files = self.target.find_related_paths_across_trees(
873
specific_files, trees,
874
require_versioned=require_versioned)
909
specific_files, trees,
910
require_versioned=require_versioned)
876
if self.source._repository._git.object_store != self.target._repository._git.object_store:
877
store = OverlayObjectStore([self.source._repository._git.object_store,
878
self.target._repository._git.object_store])
912
if (self.source._repository._git.object_store !=
913
self.target._repository._git.object_store):
914
store = OverlayObjectStore(
915
[self.source._repository._git.object_store,
916
self.target._repository._git.object_store])
880
918
store = self.source._repository._git.object_store
881
return self.source._repository._git.object_store.tree_changes(
919
return store.tree_changes(
882
920
self.source.tree, self.target.tree, want_unchanged=want_unchanged,
883
921
include_trees=True, change_type_same=True), set()
994
1033
file, stat_val = self.get_file_with_stat(path)
995
1034
except (errors.NoSuchFile, IOError):
996
# TODO: Rather than come up with something here, use the old index
1035
# TODO: Rather than come up with something here, use the old
997
1037
file = BytesIO()
998
1038
stat_val = os.stat_result(
999
1039
(stat.S_IFREG | 0o644, 0, 0, 0, 0, 0, 0, 0, 0, 0))
1001
1041
blob.set_raw_string(file.read())
1002
1042
# Add object to the repository if it didn't exist yet
1003
if not blob.id in self.store:
1043
if blob.id not in self.store:
1004
1044
self.store.add_object(blob)
1005
1045
hexsha = blob.id
1006
1046
elif kind == "symlink":
1015
1055
blob.set_raw_string(
1016
1056
self.get_symlink_target(path).encode("utf-8"))
1017
1057
# Add object to the repository if it didn't exist yet
1018
if not blob.id in self.store:
1058
if blob.id not in self.store:
1019
1059
self.store.add_object(blob)
1020
1060
hexsha = blob.id
1021
1061
elif kind == "tree-reference":
1022
1062
if reference_revision is not None:
1023
hexsha = self.branch.lookup_bzr_revision_id(reference_revision)[0]
1063
hexsha = self.branch.lookup_bzr_revision_id(
1064
reference_revision)[0]
1025
1066
hexsha = self._read_submodule_head(path)
1026
1067
if hexsha is None:
1053
1094
index = self.index
1054
1095
for path, value in index.items():
1055
1096
yield (posixpath.join(basepath, path), value)
1056
(ctime, mtime, dev, ino, mode, uid, gid, size, sha, flags) = value
1097
(ctime, mtime, dev, ino, mode, uid, gid, size, sha,
1057
1099
if S_ISGITLINK(mode):
1058
pass # TODO(jelmer): dive into submodule
1100
pass # TODO(jelmer): dive into submodule
1061
1102
def iter_entries_by_dir(self, specific_files=None, yield_parents=False):
1062
1103
if yield_parents:
1083
1124
except errors.NoSuchFile:
1085
1126
if yield_parents or specific_files is None:
1086
for (dir_path, dir_ie) in self._add_missing_parent_ids(parent,
1127
for (dir_path, dir_ie) in self._add_missing_parent_ids(
1088
1129
ret[(posixpath.dirname(dir_path), dir_path)] = dir_ie
1089
1130
file_ie.parent_id = self.path2id(parent)
1090
1131
ret[(posixpath.dirname(path), path)] = file_ie
1099
1140
def _get_dir_ie(self, path, parent_id):
1100
1141
file_id = self.path2id(path)
1101
1142
return GitTreeDirectory(file_id,
1102
posixpath.basename(path).strip("/"), parent_id)
1143
posixpath.basename(path).strip("/"), parent_id)
1104
1145
def _get_file_ie(self, name, path, value, parent_id):
1105
1146
if not isinstance(name, text_type):
1115
1156
kind = mode_kind(mode)
1116
1157
ie = entry_factory[kind](file_id, name, parent_id)
1117
1158
if kind == 'symlink':
1118
ie.symlink_target = self.get_symlink_target(path, file_id)
1159
ie.symlink_target = self.get_symlink_target(path)
1119
1160
elif kind == 'tree-reference':
1120
ie.reference_revision = self.get_reference_revision(path, file_id)
1161
ie.reference_revision = self.get_reference_revision(path)
1123
data = self.get_file_text(path, file_id)
1164
data = self.get_file_text(path)
1124
1165
except errors.NoSuchFile:
1126
1167
except IOError as e:
1185
1226
# TODO(jelmer): This shouldn't be called, it's inventory specific.
1186
1227
for (old_path, new_path, file_id, ie) in delta:
1187
1228
if old_path is not None:
1188
(index, old_subpath) = self._lookup_index(old_path.encode('utf-8'))
1229
(index, old_subpath) = self._lookup_index(
1230
old_path.encode('utf-8'))
1189
1231
if old_subpath in index:
1190
1232
self._index_del_entry(index, old_subpath)
1191
1233
self._versioned_dirs = None
1225
1267
not self.is_versioned(to_rel))
1227
1269
if not self.has_filename(to_rel):
1228
raise errors.BzrMoveFailedError(from_rel, to_rel,
1229
errors.NoSuchFile(to_rel))
1270
raise errors.BzrMoveFailedError(
1271
from_rel, to_rel, errors.NoSuchFile(to_rel))
1230
1272
if self.basis_tree().is_versioned(to_rel):
1231
raise errors.BzrMoveFailedError(from_rel, to_rel,
1232
errors.AlreadyVersionedError(to_rel))
1273
raise errors.BzrMoveFailedError(
1274
from_rel, to_rel, errors.AlreadyVersionedError(to_rel))
1234
1276
kind = self.kind(to_rel)
1242
1284
exc_type = errors.BzrMoveFailedError
1243
1285
if self.is_versioned(to_rel):
1244
1286
raise exc_type(from_rel, to_rel,
1245
errors.AlreadyVersionedError(to_rel))
1287
errors.AlreadyVersionedError(to_rel))
1246
1288
if not self.has_filename(from_rel):
1247
raise errors.BzrMoveFailedError(from_rel, to_rel,
1248
errors.NoSuchFile(from_rel))
1289
raise errors.BzrMoveFailedError(
1290
from_rel, to_rel, errors.NoSuchFile(from_rel))
1249
1291
kind = self.kind(from_rel)
1250
1292
if not self.is_versioned(from_rel) and kind != 'directory':
1251
1293
raise exc_type(from_rel, to_rel,
1252
errors.NotVersionedError(from_rel))
1294
errors.NotVersionedError(from_rel))
1253
1295
if self.has_filename(to_rel):
1254
1296
raise errors.RenameFailedFilesExist(
1255
1297
from_rel, to_rel, errors.FileExists(to_rel))
1268
1311
self._rename_one(from_rel, to_rel)
1269
1312
except OSError as e:
1270
1313
if e.errno == errno.ENOENT:
1271
raise errors.BzrMoveFailedError(from_rel, to_rel,
1272
errors.NoSuchFile(to_rel))
1314
raise errors.BzrMoveFailedError(
1315
from_rel, to_rel, errors.NoSuchFile(to_rel))
1274
1317
if kind != 'directory':
1275
1318
(index, from_index_path) = self._lookup_index(from_path)
1280
1323
self._index_add_entry(to_rel, kind)
1282
todo = [(p, i) for (p, i) in self._recurse_index_entries() if p.startswith(from_path+b'/')]
1325
todo = [(p, i) for (p, i) in self._recurse_index_entries()
1326
if p.startswith(from_path + b'/')]
1283
1327
for child_path, child_value in todo:
1284
1328
(child_to_index, child_to_index_path) = self._lookup_index(
1285
posixpath.join(to_path, posixpath.relpath(child_path, from_path)))
1329
posixpath.join(to_path, posixpath.relpath(child_path, from_path)))
1286
1330
child_to_index[child_to_index_path] = child_value
1287
1331
# TODO(jelmer): Mark individual index as dirty
1288
1332
self._index_dirty = True
1289
(child_from_index, child_from_index_path) = self._lookup_index(child_path)
1290
self._index_del_entry(child_from_index, child_from_index_path)
1333
(child_from_index, child_from_index_path) = self._lookup_index(
1335
self._index_del_entry(
1336
child_from_index, child_from_index_path)
1292
1338
self._versioned_dirs = None
1295
1341
def find_related_paths_across_trees(self, paths, trees=[],
1296
require_versioned=True):
1342
require_versioned=True):
1297
1343
if paths is None:
1370
1416
isinstance(target, MutableGitIndexTree))
1372
1418
def _iter_git_changes(self, want_unchanged=False, specific_files=None,
1373
require_versioned=False, extra_trees=None,
1374
want_unversioned=False):
1419
require_versioned=False, extra_trees=None,
1420
want_unversioned=False):
1375
1421
trees = [self.source]
1376
1422
if extra_trees is not None:
1377
1423
trees.extend(extra_trees)
1378
1424
if specific_files is not None:
1379
1425
specific_files = self.target.find_related_paths_across_trees(
1380
specific_files, trees,
1381
require_versioned=require_versioned)
1426
specific_files, trees,
1427
require_versioned=require_versioned)
1382
1428
# TODO(jelmer): Restrict to specific_files, for performance reasons.
1383
1429
with self.lock_read():
1384
1430
return changes_between_git_tree_and_working_copy(
1409
1456
# Entry was removed; keep it listed, but mark it as gone.
1410
1457
blobs[path] = (ZERO_SHA, 0)
1411
1458
elif e.errno == errno.EISDIR:
1412
# Entry was turned into a directory
1413
dirified.append((path, Tree().id, stat.S_IFDIR))
1414
store.add_object(Tree())
1459
# TODO(jelmer): Only do this if 'path' appears in .gitmodules?
1460
if S_ISGITLINK(index_entry.mode):
1461
blobs[path] = (index_entry.sha, index_entry.mode)
1463
# Entry was turned into a directory
1464
dirified.append((path, Tree().id, stat.S_IFDIR))
1465
store.add_object(Tree())
1433
1484
if stat.S_ISDIR(st.st_mode):
1436
blob = blob_from_path_and_stat(target.abspath(e).encode(osutils._fs_enc), st)
1487
blob = blob_from_path_and_stat(
1488
target.abspath(e).encode(osutils._fs_enc), st)
1437
1489
store.add_object(blob)
1438
1490
np = np.encode('utf-8')
1439
1491
blobs[np] = (blob.id, cleanup_mode(st.st_mode))
1441
to_tree_sha = commit_tree(store, dirified + [(p, s, m) for (p, (s, m)) in blobs.items()])
1493
to_tree_sha = commit_tree(
1494
store, dirified + [(p, s, m) for (p, (s, m)) in blobs.items()])
1442
1495
return store.tree_changes(
1443
1496
from_tree_sha, to_tree_sha, include_trees=True,
1444
1497
want_unchanged=want_unchanged, change_type_same=True), extras