267
251
def __init__(self, repository, revision_id):
268
252
self._revision_id = revision_id
269
253
self._repository = repository
270
self._submodules = None
271
254
self.store = repository._git.object_store
272
255
if not isinstance(revision_id, bytes):
273
256
raise TypeError(revision_id)
274
self.commit_id, self.mapping = repository.lookup_bzr_revision_id(
257
self.commit_id, self.mapping = repository.lookup_bzr_revision_id(revision_id)
276
258
if revision_id == NULL_REVISION:
278
260
self.mapping = default_mapping
261
self._fileid_map = GitFileIdMap(
281
266
commit = self.store[self.commit_id]
283
268
raise errors.NoSuchRevision(repository, revision_id)
284
269
self.tree = commit.tree
286
def _submodule_info(self):
287
if self._submodules is None:
289
with self.get_file('.gitmodules') as f:
290
config = GitConfigFile.from_file(f)
293
for path, url, section in parse_submodules(config)}
294
except errors.NoSuchFile:
295
self._submodules = {}
296
return self._submodules
298
def _get_submodule_repository(self, relpath):
299
if not isinstance(relpath, bytes):
300
raise TypeError(relpath)
302
info = self._submodule_info()[relpath]
304
nested_repo_transport = self._repository.controldir.user_transport.clone(
305
relpath.decode('utf-8'))
307
nested_repo_transport = self._repository.controldir.control_transport.clone(
308
posixpath.join('modules', info[1].decode('utf-8')))
309
nested_controldir = _mod_controldir.ControlDir.open_from_transport(
310
nested_repo_transport)
270
self._fileid_map = self.mapping.get_fileid_map(self.store.__getitem__, self.tree)
272
def _get_nested_repository(self, path):
273
nested_repo_transport = self._repository.user_transport.clone(path)
274
nested_controldir = _mod_controldir.ControlDir.open_from_transport(nested_repo_transport)
311
275
return nested_controldir.find_repository()
313
def _get_submodule_store(self, relpath):
314
return self._get_submodule_repository(relpath)._git.object_store
316
def get_nested_tree(self, path):
317
encoded_path = path.encode('utf-8')
318
nested_repo = self._get_submodule_repository(encoded_path)
319
ref_rev = self.get_reference_revision(path)
320
return nested_repo.revision_tree(ref_rev)
322
277
def supports_rename_tracking(self):
325
def get_file_revision(self, path):
280
def get_file_revision(self, path, file_id=None):
326
281
change_scanner = self._repository._file_change_scanner
327
282
if self.commit_id == ZERO_SHA:
328
283
return NULL_REVISION
329
(unused_path, commit_id) = change_scanner.find_last_change_revision(
284
(path, commit_id) = change_scanner.find_last_change_revision(
330
285
path.encode('utf-8'), self.commit_id)
331
return self._repository.lookup_foreign_revision_id(
332
commit_id, self.mapping)
286
return self._repository.lookup_foreign_revision_id(commit_id, self.mapping)
334
def get_file_mtime(self, path):
288
def get_file_mtime(self, path, file_id=None):
336
revid = self.get_file_revision(path)
290
revid = self.get_file_revision(path, file_id)
338
raise errors.NoSuchFile(path)
292
raise _mod_tree.FileTimestampUnavailable(path)
340
294
rev = self._repository.get_revision(revid)
341
295
except errors.NoSuchRevision:
342
296
raise _mod_tree.FileTimestampUnavailable(path)
343
297
return rev.timestamp
345
def id2path(self, file_id, recurse='down'):
299
def id2path(self, file_id):
347
path = self.mapping.parse_file_id(file_id)
301
path = self._fileid_map.lookup_path(file_id)
348
302
except ValueError:
349
303
raise errors.NoSuchId(self, file_id)
304
path = path.decode('utf-8')
350
305
if self.is_versioned(path):
352
307
raise errors.NoSuchId(self, file_id)
374
327
tree = store[tree_id]
375
328
for name, mode, hexsha in tree.items():
376
329
subpath = posixpath.join(path, name)
377
ret.add(subpath.decode('utf-8'))
378
330
if stat.S_ISDIR(mode):
379
todo.append((store, subpath, hexsha))
331
todo.add((store, subpath, hexsha))
336
def get_root_id(self):
337
if self.tree is None:
339
return self.path2id("")
341
def has_or_had_id(self, file_id):
343
path = self.id2path(file_id)
344
except errors.NoSuchId:
348
def has_id(self, file_id):
350
path = self.id2path(file_id)
351
except errors.NoSuchId:
353
return self.has_filename(path)
382
355
def _lookup_path(self, path):
383
356
if self.tree is None:
384
357
raise errors.NoSuchFile(path)
386
encoded_path = path.encode('utf-8')
387
parts = encoded_path.split(b'/')
391
for i, p in enumerate(parts):
395
if not isinstance(obj, Tree):
396
raise NotTreeError(hexsha)
398
mode, hexsha = obj[p]
400
raise errors.NoSuchFile(path)
401
if S_ISGITLINK(mode) and i != len(parts) - 1:
402
store = self._get_submodule_store(b'/'.join(parts[:i + 1]))
403
hexsha = store[hexsha].tree
404
return (store, mode, hexsha)
406
def is_executable(self, path):
359
(mode, hexsha) = tree_lookup_path(self.store.__getitem__, self.tree,
360
path.encode('utf-8'))
362
raise errors.NoSuchFile(self, path)
364
return (self.store, mode, hexsha)
366
def is_executable(self, path, file_id=None):
407
367
(store, mode, hexsha) = self._lookup_path(path)
409
369
# the tree root is a directory
411
371
return mode_is_executable(mode)
413
def kind(self, path):
373
def kind(self, path, file_id=None):
414
374
(store, mode, hexsha) = self._lookup_path(path)
416
376
# the tree root is a directory
428
def _submodule_info(self):
429
if self._submodules is None:
431
with self.get_file('.gitmodules') as f:
432
config = GitConfigFile.from_file(f)
435
for path, url, section in parse_submodules(config)}
436
except errors.NoSuchFile:
437
self._submodules = {}
438
return self._submodules
440
def list_files(self, include_root=False, from_dir=None, recursive=True,
441
recurse_nested=False):
388
def list_files(self, include_root=False, from_dir=None, recursive=True):
442
389
if self.tree is None:
444
if from_dir is None or from_dir == '.':
446
393
(store, mode, hexsha) = self._lookup_path(from_dir)
447
if mode is None: # Root
394
if mode is None: # Root
448
395
root_ie = self._get_dir_ie(b"", None)
450
parent_path = posixpath.dirname(from_dir)
451
parent_id = self.mapping.generate_file_id(parent_path)
397
parent_path = posixpath.dirname(from_dir.encode("utf-8"))
398
parent_id = self._fileid_map.lookup_file_id(parent_path)
452
399
if mode_kind(mode) == 'directory':
453
400
root_ie = self._get_dir_ie(from_dir.encode("utf-8"), parent_id)
455
root_ie = self._get_file_ie(
456
store, from_dir.encode("utf-8"),
402
root_ie = self._get_file_ie(store, from_dir.encode("utf-8"),
457
403
posixpath.basename(from_dir), mode, hexsha)
459
yield (from_dir, "V", root_ie.kind, root_ie)
404
if from_dir != "" or include_root:
405
yield (from_dir, "V", root_ie.kind, root_ie.file_id, root_ie)
461
407
if root_ie.kind == 'directory':
462
todo.append((store, from_dir.encode("utf-8"),
463
b"", hexsha, root_ie.file_id))
408
todo.add((store, from_dir.encode("utf-8"), hexsha, root_ie.file_id))
465
(store, path, relpath, hexsha, parent_id) = todo.pop()
410
(store, path, hexsha, parent_id) = todo.pop()
466
411
tree = store[hexsha]
467
412
for name, mode, hexsha in tree.iteritems():
468
413
if self.mapping.is_special_file(name):
470
415
child_path = posixpath.join(path, name)
471
child_relpath = posixpath.join(relpath, name)
472
if S_ISGITLINK(mode) and recurse_nested:
474
store = self._get_submodule_store(child_relpath)
475
hexsha = store[hexsha].tree
476
416
if stat.S_ISDIR(mode):
477
417
ie = self._get_dir_ie(child_path, parent_id)
480
(store, child_path, child_relpath, hexsha,
419
todo.add((store, child_path, hexsha, ie.file_id))
483
ie = self._get_file_ie(
484
store, child_path, name, mode, hexsha, parent_id)
485
yield (child_relpath.decode('utf-8'), "V", ie.kind, ie)
421
ie = self._get_file_ie(store, child_path, name, mode, hexsha, parent_id)
422
yield child_path.decode('utf-8'), "V", ie.kind, ie.file_id, ie
487
424
def _get_file_ie(self, store, path, name, mode, hexsha, parent_id):
488
if not isinstance(path, bytes):
425
if type(path) is not bytes:
489
426
raise TypeError(path)
490
if not isinstance(name, bytes):
427
if type(name) is not bytes:
491
428
raise TypeError(name)
492
429
kind = mode_kind(mode)
493
path = path.decode('utf-8')
494
name = name.decode("utf-8")
495
file_id = self.mapping.generate_file_id(path)
496
ie = entry_factory[kind](file_id, name, parent_id)
430
file_id = self._fileid_map.lookup_file_id(path)
431
ie = entry_factory[kind](file_id, name.decode("utf-8"), parent_id)
497
432
if kind == 'symlink':
498
433
ie.symlink_target = store[hexsha].data.decode('utf-8')
499
434
elif kind == 'tree-reference':
500
ie.reference_revision = self.mapping.revision_id_foreign_to_bzr(
435
ie.reference_revision = self.mapping.revision_id_foreign_to_bzr(hexsha)
503
437
data = store[hexsha].data
504
438
ie.text_sha1 = osutils.sha_string(data)
530
464
yield self._get_file_ie(store, child_path, name, mode, hexsha,
533
def iter_entries_by_dir(self, specific_files=None,
534
recurse_nested=False):
467
def iter_entries_by_dir(self, specific_files=None, yield_parents=False):
535
468
if self.tree is None:
471
# TODO(jelmer): Support yield parents
472
raise NotImplementedError
537
473
if specific_files is not None:
538
474
if specific_files in ([""], []):
539
475
specific_files = None
541
specific_files = set([p.encode('utf-8')
542
for p in specific_files])
543
todo = deque([(self.store, b"", self.tree, self.path2id(''))])
544
if specific_files is None or u"" in specific_files:
545
yield u"", self._get_dir_ie(b"", None)
477
specific_files = set([p.encode('utf-8') for p in specific_files])
478
todo = set([(self.store, "", self.tree, None)])
547
store, path, tree_sha, parent_id = todo.popleft()
480
store, path, tree_sha, parent_id = todo.pop()
481
ie = self._get_dir_ie(path, parent_id)
482
if specific_files is None or path in specific_files:
483
yield path.decode("utf-8"), ie
548
484
tree = store[tree_sha]
550
485
for name, mode, hexsha in tree.iteritems():
551
486
if self.mapping.is_special_file(name):
553
488
child_path = posixpath.join(path, name)
554
child_path_decoded = child_path.decode('utf-8')
555
if recurse_nested and S_ISGITLINK(mode):
557
store = self._get_submodule_store(child_path)
558
hexsha = store[hexsha].tree
559
489
if stat.S_ISDIR(mode):
560
490
if (specific_files is None or
561
any([p for p in specific_files if p.startswith(
564
(store, child_path, hexsha,
565
self.path2id(child_path_decoded)))
566
if specific_files is None or child_path in specific_files:
567
if stat.S_ISDIR(mode):
568
yield (child_path_decoded,
569
self._get_dir_ie(child_path, parent_id))
571
yield (child_path_decoded,
572
self._get_file_ie(store, child_path, name, mode,
574
todo.extendleft(reversed(extradirs))
576
def iter_references(self):
577
if self.supports_tree_reference():
578
for path, entry in self.iter_entries_by_dir():
579
if entry.kind == 'tree-reference':
491
any(filter(lambda p: p.startswith(child_path), specific_files))):
492
todo.add((store, child_path, hexsha, ie.file_id))
493
elif specific_files is None or child_path in specific_files:
494
yield (child_path.decode("utf-8"),
495
self._get_file_ie(store, child_path, name, mode, hexsha,
582
498
def get_revision_id(self):
583
499
"""See RevisionTree.get_revision_id."""
584
500
return self._revision_id
586
def get_file_sha1(self, path, stat_value=None):
502
def get_file_sha1(self, path, file_id=None, stat_value=None):
587
503
if self.tree is None:
588
504
raise errors.NoSuchFile(path)
589
return osutils.sha_string(self.get_file_text(path))
505
return osutils.sha_string(self.get_file_text(path, file_id))
591
def get_file_verifier(self, path, stat_value=None):
507
def get_file_verifier(self, path, file_id=None, stat_value=None):
592
508
(store, mode, hexsha) = self._lookup_path(path)
593
509
return ("GIT", hexsha)
595
def get_file_size(self, path):
596
(store, mode, hexsha) = self._lookup_path(path)
597
if stat.S_ISREG(mode):
598
return len(store[hexsha].data)
601
def get_file_text(self, path):
511
def get_file_text(self, path, file_id=None):
602
512
"""See RevisionTree.get_file_text."""
603
513
(store, mode, hexsha) = self._lookup_path(path)
604
514
if stat.S_ISREG(mode):
697
604
for key, line in annotator.annotate_flat(this_key)]
698
605
return annotations
700
def _get_rules_searcher(self, default_searcher):
701
return default_searcher
703
def walkdirs(self, prefix=u""):
704
(store, mode, hexsha) = self._lookup_path(prefix)
706
[(store, prefix.encode('utf-8'), hexsha, self.path2id(prefix))])
708
store, path, tree_sha, parent_id = todo.popleft()
709
path_decoded = path.decode('utf-8')
710
tree = store[tree_sha]
712
for name, mode, hexsha in tree.iteritems():
713
if self.mapping.is_special_file(name):
715
child_path = posixpath.join(path, name)
716
file_id = self.path2id(child_path.decode('utf-8'))
717
if stat.S_ISDIR(mode):
718
todo.append((store, child_path, hexsha, file_id))
720
(child_path.decode('utf-8'), name.decode('utf-8'),
721
mode_kind(mode), None,
722
file_id, mode_kind(mode)))
723
yield (path_decoded, parent_id), children
726
def tree_delta_from_git_changes(changes, mappings,
728
require_versioned=False, include_root=False,
608
def tree_delta_from_git_changes(changes, mapping,
609
fileid_maps, specific_files=None,
610
require_versioned=False, include_root=False,
730
612
"""Create a TreeDelta from two git trees.
732
614
source and target are iterators over tuples with:
733
615
(filename, sha, mode)
735
(old_mapping, new_mapping) = mappings
617
(old_fileid_map, new_fileid_map) = fileid_maps
736
618
if target_extras is None:
737
619
target_extras = set()
738
620
ret = delta.TreeDelta()
740
621
for (oldpath, newpath), (oldmode, newmode), (oldsha, newsha) in changes:
741
if newpath == b'' and not include_root:
622
if newpath == u'' and not include_root:
743
if oldpath is not None:
744
oldpath_decoded = oldpath.decode('utf-8')
746
oldpath_decoded = None
747
if newpath is not None:
748
newpath_decoded = newpath.decode('utf-8')
750
newpath_decoded = None
751
624
if not (specific_files is None or
752
(oldpath is not None and
753
osutils.is_inside_or_parent_of_any(
754
specific_files, oldpath_decoded)) or
755
(newpath is not None and
756
osutils.is_inside_or_parent_of_any(
757
specific_files, newpath_decoded))):
625
(oldpath is not None and osutils.is_inside_or_parent_of_any(specific_files, oldpath)) or
626
(newpath is not None and osutils.is_inside_or_parent_of_any(specific_files, newpath))):
760
if oldpath_decoded is None:
761
fileid = new_mapping.generate_file_id(newpath_decoded)
770
oldexe = mode_is_executable(oldmode)
771
oldkind = mode_kind(oldmode)
775
if oldpath_decoded == u'':
779
(oldparentpath, oldname) = osutils.split(oldpath_decoded)
780
oldparent = old_mapping.generate_file_id(oldparentpath)
781
fileid = old_mapping.generate_file_id(oldpath_decoded)
782
if newpath_decoded is None:
789
newversioned = (newpath_decoded not in target_extras)
791
newexe = mode_is_executable(newmode)
792
newkind = mode_kind(newmode)
796
if newpath_decoded == u'':
800
newparentpath, newname = osutils.split(newpath_decoded)
801
newparent = new_mapping.generate_file_id(newparentpath)
802
if old_mapping.is_special_file(oldpath):
628
if mapping.is_special_file(oldpath):
804
if new_mapping.is_special_file(newpath):
630
if mapping.is_special_file(newpath):
806
632
if oldpath is None and newpath is None:
808
change = _mod_tree.TreeChange(
809
fileid, (oldpath_decoded, newpath_decoded), (oldsha != newsha),
810
(oldversioned, newversioned),
811
(oldparent, newparent), (oldname, newname),
812
(oldkind, newkind), (oldexe, newexe))
813
634
if oldpath is None:
814
added.append((newpath, newkind))
635
if newpath in target_extras:
636
ret.unversioned.append(
637
(osutils.normalized_filename(newpath)[0], None, mode_kind(newmode)))
639
file_id = new_fileid_map.lookup_file_id(newpath)
640
ret.added.append((newpath.decode('utf-8'), file_id, mode_kind(newmode)))
815
641
elif newpath is None or newmode == 0:
816
ret.removed.append(change)
642
file_id = old_fileid_map.lookup_file_id(oldpath)
643
ret.removed.append((oldpath.decode('utf-8'), file_id, mode_kind(oldmode)))
817
644
elif oldpath != newpath:
818
ret.renamed.append(change)
645
file_id = old_fileid_map.lookup_file_id(oldpath)
647
(oldpath.decode('utf-8'), newpath.decode('utf-8'), file_id,
648
mode_kind(newmode), (oldsha != newsha),
649
(oldmode != newmode)))
819
650
elif mode_kind(oldmode) != mode_kind(newmode):
820
ret.kind_changed.append(change)
651
file_id = new_fileid_map.lookup_file_id(newpath)
652
ret.kind_changed.append(
653
(newpath.decode('utf-8'), file_id, mode_kind(oldmode),
821
655
elif oldsha != newsha or oldmode != newmode:
822
656
if stat.S_ISDIR(oldmode) and stat.S_ISDIR(newmode):
824
ret.modified.append(change)
826
ret.unchanged.append(change)
828
implicit_dirs = {b''}
829
for path, kind in added:
830
if kind == 'directory' or path in target_extras:
832
implicit_dirs.update(osutils.parent_directories(path))
834
for path, kind in added:
835
if kind == 'directory' and path not in implicit_dirs:
837
path_decoded = osutils.normalized_filename(path)[0]
838
parent_path, basename = osutils.split(path_decoded)
839
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),
844
(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)))
658
file_id = new_fileid_map.lookup_file_id(newpath)
660
(newpath.decode('utf-8'), file_id, mode_kind(newmode),
661
(oldsha != newsha), (oldmode != newmode)))
663
file_id = new_fileid_map.lookup_file_id(newpath)
664
ret.unchanged.append((newpath.decode('utf-8'), file_id, mode_kind(newmode)))
857
def changes_from_git_changes(changes, mapping, specific_files=None,
858
include_unchanged=False, target_extras=None):
669
def changes_from_git_changes(changes, mapping, specific_files=None, include_unchanged=False,
859
671
"""Create a iter_changes-like generator from a git stream.
861
673
source and target are iterators over tuples with:
893
694
oldversioned = False
895
696
oldversioned = True
697
oldpath = oldpath.decode("utf-8")
897
699
oldexe = mode_is_executable(oldmode)
898
700
oldkind = mode_kind(oldmode)
902
if oldpath_decoded == u'':
906
(oldparentpath, oldname) = osutils.split(oldpath_decoded)
708
(oldparentpath, oldname) = osutils.split(oldpath)
907
709
oldparent = mapping.generate_file_id(oldparentpath)
908
fileid = mapping.generate_file_id(oldpath_decoded)
909
if newpath_decoded is None:
710
fileid = mapping.generate_file_id(oldpath)
914
716
newversioned = False
916
newversioned = (newpath_decoded not in target_extras)
718
newversioned = (newpath not in target_extras)
918
720
newexe = mode_is_executable(newmode)
919
721
newkind = mode_kind(newmode)
923
if newpath_decoded == u'':
725
newpath = newpath.decode("utf-8")
927
newparentpath, newname = osutils.split(newpath_decoded)
730
newparentpath, newname = osutils.split(newpath)
928
731
newparent = mapping.generate_file_id(newparentpath)
929
732
if (not include_unchanged and
930
733
oldkind == 'directory' and newkind == 'directory' and
931
oldpath_decoded == newpath_decoded):
933
yield _mod_tree.TreeChange(
934
fileid, (oldpath_decoded, newpath_decoded), (oldsha != newsha),
935
(oldversioned, newversioned),
936
(oldparent, newparent), (oldname, newname),
937
(oldkind, newkind), (oldexe, newexe))
736
yield (fileid, (oldpath, newpath), (oldsha != newsha),
737
(oldversioned, newversioned),
738
(oldparent, newparent), (oldname, newname),
739
(oldkind, newkind), (oldexe, newexe))
940
742
class InterGitTrees(_mod_tree.InterTree):
954
756
want_unversioned=False):
955
757
with self.lock_read():
956
758
changes, target_extras = self._iter_git_changes(
957
want_unchanged=want_unchanged,
958
require_versioned=require_versioned,
959
specific_files=specific_files,
960
extra_trees=extra_trees,
961
want_unversioned=want_unversioned)
962
return tree_delta_from_git_changes(
963
changes, (self.source.mapping, self.target.mapping),
964
specific_files=specific_files,
965
include_root=include_root, target_extras=target_extras)
759
want_unchanged=want_unchanged,
760
require_versioned=require_versioned,
761
specific_files=specific_files,
762
extra_trees=extra_trees,
763
want_unversioned=want_unversioned)
764
source_fileid_map = self.source._fileid_map
765
target_fileid_map = self.target._fileid_map
766
return tree_delta_from_git_changes(changes, self.target.mapping,
767
(source_fileid_map, target_fileid_map),
768
specific_files=specific_files, include_root=include_root,
769
target_extras=target_extras)
967
771
def iter_changes(self, include_unchanged=False, specific_files=None,
968
772
pb=None, extra_trees=[], require_versioned=True,
969
773
want_unversioned=False):
970
774
with self.lock_read():
971
775
changes, target_extras = self._iter_git_changes(
972
want_unchanged=include_unchanged,
973
require_versioned=require_versioned,
974
specific_files=specific_files,
975
extra_trees=extra_trees,
976
want_unversioned=want_unversioned)
776
want_unchanged=include_unchanged,
777
require_versioned=require_versioned,
778
specific_files=specific_files,
779
extra_trees=extra_trees,
780
want_unversioned=want_unversioned)
977
781
return changes_from_git_changes(
978
changes, self.target.mapping,
979
specific_files=specific_files,
980
include_unchanged=include_unchanged,
981
target_extras=target_extras)
782
changes, self.target.mapping,
783
specific_files=specific_files,
784
include_unchanged=include_unchanged,
785
target_extras=target_extras)
983
787
def _iter_git_changes(self, want_unchanged=False, specific_files=None,
984
require_versioned=False, extra_trees=None,
985
want_unversioned=False):
788
require_versioned=False, extra_trees=None,
789
want_unversioned=False):
986
790
raise NotImplementedError(self._iter_git_changes)
988
def find_target_path(self, path, recurse='none'):
989
ret = self.find_target_paths([path], recurse=recurse)
992
def find_source_path(self, path, recurse='none'):
993
ret = self.find_source_paths([path], recurse=recurse)
996
def find_target_paths(self, paths, recurse='none'):
999
changes = self._iter_git_changes(specific_files=paths)[0]
1000
for (oldpath, newpath), (oldmode, newmode), (oldsha, newsha) in changes:
1001
if oldpath in paths:
1002
ret[oldpath] = newpath
1005
if self.source.has_filename(path):
1006
if self.target.has_filename(path):
1011
raise errors.NoSuchFile(path)
1014
def find_source_paths(self, paths, recurse='none'):
1017
changes = self._iter_git_changes(specific_files=paths)[0]
1018
for (oldpath, newpath), (oldmode, newmode), (oldsha, newsha) in changes:
1019
if newpath in paths:
1020
ret[newpath] = oldpath
1023
if self.target.has_filename(path):
1024
if self.source.has_filename(path):
1029
raise errors.NoSuchFile(path)
1033
793
class InterGitRevisionTrees(InterGitTrees):
1034
794
"""InterTree that works between two git revision trees."""
1043
803
isinstance(target, GitRevisionTree))
1045
805
def _iter_git_changes(self, want_unchanged=False, specific_files=None,
1046
require_versioned=True, extra_trees=None,
1047
want_unversioned=False):
806
require_versioned=True, extra_trees=None,
807
want_unversioned=False):
1048
808
trees = [self.source]
1049
809
if extra_trees is not None:
1050
810
trees.extend(extra_trees)
1051
811
if specific_files is not None:
1052
812
specific_files = self.target.find_related_paths_across_trees(
1053
specific_files, trees,
1054
require_versioned=require_versioned)
813
specific_files, trees,
814
require_versioned=require_versioned)
1056
if (self.source._repository._git.object_store !=
1057
self.target._repository._git.object_store):
1058
store = OverlayObjectStore(
1059
[self.source._repository._git.object_store,
1060
self.target._repository._git.object_store])
816
if self.source._repository._git.object_store != self.target._repository._git.object_store:
817
store = OverlayObjectStore([self.source._repository._git.object_store,
818
self.target._repository._git.object_store])
1062
820
store = self.source._repository._git.object_store
1063
return store.tree_changes(
821
return self.source._repository._git.object_store.tree_changes(
1064
822
self.source.tree, self.target.tree, want_unchanged=want_unchanged,
1065
823
include_trees=True, change_type_same=True), set()
1145
910
def _read_submodule_head(self, path):
1146
911
raise NotImplementedError(self._read_submodule_head)
1148
def _submodule_info(self):
1149
if self._submodules is None:
1151
with self.get_file('.gitmodules') as f:
1152
config = GitConfigFile.from_file(f)
1153
self._submodules = {
1154
path: (url, section)
1155
for path, url, section in parse_submodules(config)}
1156
except errors.NoSuchFile:
1157
self._submodules = {}
1158
return self._submodules
1160
913
def _lookup_index(self, encoded_path):
1161
914
if not isinstance(encoded_path, bytes):
1162
915
raise TypeError(encoded_path)
1164
if encoded_path in self.index:
1165
return self.index, encoded_path
1166
# TODO(jelmer): Perhaps have a cache with paths under which some
1169
remaining_path = encoded_path
1171
parts = remaining_path.split(b'/')
1172
for i in range(1, len(parts)):
1173
basepath = b'/'.join(parts[:i])
1175
(ctime, mtime, dev, ino, mode, uid, gid, size, sha,
1176
flags) = index[basepath]
1180
if S_ISGITLINK(mode):
1181
index = self._get_submodule_index(basepath)
1182
remaining_path = b'/'.join(parts[i:])
1185
return index, remaining_path
1187
return index, remaining_path
1188
return index, remaining_path
916
# TODO(jelmer): Look in other indexes
917
return self.index, encoded_path
1190
919
def _index_del_entry(self, index, path):
1256
982
if self._versioned_dirs is not None:
1257
983
self._ensure_versioned_dir(index_path)
1259
def _recurse_index_entries(self, index=None, basepath=b"",
1260
recurse_nested=False):
985
def _recurse_index_entries(self, index=None, basepath=""):
1261
986
# Iterate over all index entries
1262
987
with self.lock_read():
1263
988
if index is None:
1264
989
index = self.index
1265
990
for path, value in index.items():
1266
(ctime, mtime, dev, ino, mode, uid, gid, size, sha,
1268
if S_ISGITLINK(mode) and recurse_nested:
1269
subindex = self._get_submodule_index(path)
1270
for entry in self._recurse_index_entries(
1271
index=subindex, basepath=path,
1272
recurse_nested=recurse_nested):
1275
yield (posixpath.join(basepath, path), value)
1277
def iter_entries_by_dir(self, specific_files=None,
1278
recurse_nested=False):
991
yield (posixpath.join(basepath, path), value)
992
(ctime, mtime, dev, ino, mode, uid, gid, size, sha, flags) = value
993
if S_ISGITLINK(mode):
994
pass # TODO(jelmer): dive into submodule
997
def iter_entries_by_dir(self, specific_files=None, yield_parents=False):
999
raise NotImplementedError(self.iter_entries_by_dir)
1279
1000
with self.lock_read():
1280
1001
if specific_files is not None:
1281
1002
specific_files = set(specific_files)
1284
1005
root_ie = self._get_dir_ie(u"", None)
1286
1007
if specific_files is None or u"" in specific_files:
1287
ret[(u"", u"")] = root_ie
1008
ret[(None, u"")] = root_ie
1288
1009
dir_ids = {u"": root_ie.file_id}
1289
for path, value in self._recurse_index_entries(
1290
recurse_nested=recurse_nested):
1010
for path, value in self._recurse_index_entries():
1291
1011
if self.mapping.is_special_file(path):
1293
1013
path = path.decode("utf-8")
1294
if specific_files is not None and path not in specific_files:
1014
if specific_files is not None and not path in specific_files:
1296
1016
(parent, name) = posixpath.split(path)
1298
1018
file_ie = self._get_file_ie(name, path, value, None)
1299
1019
except errors.NoSuchFile:
1301
if specific_files is None:
1302
for (dir_path, dir_ie) in self._add_missing_parent_ids(
1021
if yield_parents or specific_files is None:
1022
for (dir_path, dir_ie) in self._add_missing_parent_ids(parent,
1304
1024
ret[(posixpath.dirname(dir_path), dir_path)] = dir_ie
1305
1025
file_ie.parent_id = self.path2id(parent)
1306
1026
ret[(posixpath.dirname(path), path)] = file_ie
1307
# Special casing for directories
1309
for path in specific_files:
1310
key = (posixpath.dirname(path), path)
1311
if key not in ret and self.is_versioned(path):
1312
ret[key] = self._get_dir_ie(path, self.path2id(key[0]))
1313
return ((path, ie) for ((_, path), ie) in sorted(viewitems(ret)))
1027
return ((path, ie) for ((_, path), ie) in sorted(ret.items()))
1315
1029
def iter_references(self):
1316
if self.supports_tree_reference():
1317
# TODO(jelmer): Implement a more efficient version of this
1318
for path, entry in self.iter_entries_by_dir():
1319
if entry.kind == 'tree-reference':
1030
# TODO(jelmer): Implement a more efficient version of this
1031
for path, entry in self.iter_entries_by_dir():
1032
if entry.kind == 'tree-reference':
1033
yield path, self.mapping.generate_file_id(b'')
1322
1035
def _get_dir_ie(self, path, parent_id):
1323
1036
file_id = self.path2id(path)
1324
1037
return GitTreeDirectory(file_id,
1325
posixpath.basename(path).strip("/"), parent_id)
1038
posixpath.basename(path).strip("/"), parent_id)
1327
1040
def _get_file_ie(self, name, path, value, parent_id):
1328
1041
if not isinstance(name, text_type):