268
269
raise errors.NoSuchRevision(repository, revision_id)
269
270
self.tree = commit.tree
270
self._fileid_map = self.mapping.get_fileid_map(self.store.__getitem__, self.tree)
271
self._fileid_map = self.mapping.get_fileid_map(
272
self.store.__getitem__, self.tree)
272
274
def _get_nested_repository(self, path):
273
275
nested_repo_transport = self._repository.user_transport.clone(path)
274
nested_controldir = _mod_controldir.ControlDir.open_from_transport(nested_repo_transport)
276
nested_controldir = _mod_controldir.ControlDir.open_from_transport(
277
nested_repo_transport)
275
278
return nested_controldir.find_repository()
277
280
def supports_rename_tracking(self):
400
403
root_ie = self._get_dir_ie(from_dir.encode("utf-8"), parent_id)
402
405
root_ie = self._get_file_ie(store, from_dir.encode("utf-8"),
403
posixpath.basename(from_dir), mode, hexsha)
406
posixpath.basename(from_dir), mode, hexsha)
405
408
yield (from_dir, "V", root_ie.kind, root_ie.file_id, root_ie)
407
410
if root_ie.kind == 'directory':
408
todo.append((store, from_dir.encode("utf-8"), b"", hexsha, root_ie.file_id))
411
todo.append((store, from_dir.encode("utf-8"),
412
b"", hexsha, root_ie.file_id))
410
414
(store, path, relpath, hexsha, parent_id) = todo.pop()
411
415
tree = store[hexsha]
417
421
if stat.S_ISDIR(mode):
418
422
ie = self._get_dir_ie(child_path, parent_id)
420
todo.append((store, child_path, child_relpath, hexsha, ie.file_id))
425
(store, child_path, child_relpath, hexsha, ie.file_id))
422
ie = self._get_file_ie(store, child_path, name, mode, hexsha, parent_id)
427
ie = self._get_file_ie(
428
store, child_path, name, mode, hexsha, parent_id)
423
429
yield child_relpath.decode('utf-8'), "V", ie.kind, ie.file_id, ie
425
431
def _get_file_ie(self, store, path, name, mode, hexsha, parent_id):
477
484
if specific_files in ([""], []):
478
485
specific_files = None
480
specific_files = set([p.encode('utf-8') for p in specific_files])
487
specific_files = set([p.encode('utf-8')
488
for p in specific_files])
481
489
todo = deque([(self.store, b"", self.tree, self.get_root_id())])
482
490
if specific_files is None or u"" in specific_files:
483
491
yield u"", self._get_dir_ie(b"", None)
492
500
child_path_decoded = child_path.decode('utf-8')
493
501
if stat.S_ISDIR(mode):
494
502
if (specific_files is None or
495
any(filter(lambda p: p.startswith(child_path), specific_files))):
503
any(filter(lambda p: p.startswith(child_path), specific_files))):
496
504
extradirs.append(
497
505
(store, child_path, hexsha, self.path2id(child_path_decoded)))
498
506
if specific_files is None or child_path in specific_files:
632
640
def walkdirs(self, prefix=u""):
633
641
(store, mode, hexsha) = self._lookup_path(prefix)
634
todo = deque([(store, prefix.encode('utf-8'), hexsha, self.path2id(prefix))])
643
[(store, prefix.encode('utf-8'), hexsha, self.path2id(prefix))])
636
645
store, path, tree_sha, parent_id = todo.popleft()
637
646
path_decoded = path.decode('utf-8')
654
663
def tree_delta_from_git_changes(changes, mapping,
655
fileid_maps, specific_files=None,
656
require_versioned=False, include_root=False,
664
fileid_maps, specific_files=None,
665
require_versioned=False, include_root=False,
658
667
"""Create a TreeDelta from two git trees.
660
669
source and target are iterators over tuples with:
691
700
(osutils.normalized_filename(newpath)[0], None, mode_kind(newmode)))
693
702
file_id = new_fileid_map.lookup_file_id(newpath_decoded)
694
ret.added.append((newpath_decoded, file_id, mode_kind(newmode)))
704
(newpath_decoded, file_id, mode_kind(newmode)))
695
705
elif newpath is None or newmode == 0:
696
706
file_id = old_fileid_map.lookup_file_id(oldpath_decoded)
697
707
ret.removed.append((oldpath_decoded, file_id, mode_kind(oldmode)))
699
709
file_id = old_fileid_map.lookup_file_id(oldpath_decoded)
700
710
ret.renamed.append(
701
711
(oldpath_decoded, newpath.decode('utf-8'), file_id,
702
mode_kind(newmode), (oldsha != newsha),
703
(oldmode != newmode)))
712
mode_kind(newmode), (oldsha != newsha),
713
(oldmode != newmode)))
704
714
elif mode_kind(oldmode) != mode_kind(newmode):
705
715
file_id = new_fileid_map.lookup_file_id(newpath_decoded)
706
716
ret.kind_changed.append(
707
717
(newpath_decoded, file_id, mode_kind(oldmode),
709
719
elif oldsha != newsha or oldmode != newmode:
710
720
if stat.S_ISDIR(oldmode) and stat.S_ISDIR(newmode):
712
722
file_id = new_fileid_map.lookup_file_id(newpath_decoded)
713
723
ret.modified.append(
714
724
(newpath_decoded, file_id, mode_kind(newmode),
715
(oldsha != newsha), (oldmode != newmode)))
725
(oldsha != newsha), (oldmode != newmode)))
717
727
file_id = new_fileid_map.lookup_file_id(newpath_decoded)
718
ret.unchanged.append((newpath_decoded, file_id, mode_kind(newmode)))
728
ret.unchanged.append(
729
(newpath_decoded, file_id, mode_kind(newmode)))
790
801
newparent = mapping.generate_file_id(newparentpath)
791
802
if (not include_unchanged and
792
803
oldkind == 'directory' and newkind == 'directory' and
793
oldpath_decoded == newpath_decoded):
804
oldpath_decoded == newpath_decoded):
795
806
yield (fileid, (oldpath_decoded, newpath_decoded), (oldsha != newsha),
796
(oldversioned, newversioned),
797
(oldparent, newparent), (oldname, newname),
798
(oldkind, newkind), (oldexe, newexe))
807
(oldversioned, newversioned),
808
(oldparent, newparent), (oldname, newname),
809
(oldkind, newkind), (oldexe, newexe))
801
812
class InterGitTrees(_mod_tree.InterTree):
815
826
want_unversioned=False):
816
827
with self.lock_read():
817
828
changes, target_extras = self._iter_git_changes(
818
want_unchanged=want_unchanged,
819
require_versioned=require_versioned,
820
specific_files=specific_files,
821
extra_trees=extra_trees,
822
want_unversioned=want_unversioned)
829
want_unchanged=want_unchanged,
830
require_versioned=require_versioned,
831
specific_files=specific_files,
832
extra_trees=extra_trees,
833
want_unversioned=want_unversioned)
823
834
source_fileid_map = self.source._fileid_map
824
835
target_fileid_map = self.target._fileid_map
825
836
return tree_delta_from_git_changes(changes, self.target.mapping,
826
(source_fileid_map, target_fileid_map),
827
specific_files=specific_files, include_root=include_root,
828
target_extras=target_extras)
839
specific_files=specific_files, include_root=include_root,
840
target_extras=target_extras)
830
842
def iter_changes(self, include_unchanged=False, specific_files=None,
831
843
pb=None, extra_trees=[], require_versioned=True,
832
844
want_unversioned=False):
833
845
with self.lock_read():
834
846
changes, target_extras = self._iter_git_changes(
835
want_unchanged=include_unchanged,
836
require_versioned=require_versioned,
837
specific_files=specific_files,
838
extra_trees=extra_trees,
839
want_unversioned=want_unversioned)
847
want_unchanged=include_unchanged,
848
require_versioned=require_versioned,
849
specific_files=specific_files,
850
extra_trees=extra_trees,
851
want_unversioned=want_unversioned)
840
852
return changes_from_git_changes(
841
changes, self.target.mapping,
842
specific_files=specific_files,
843
include_unchanged=include_unchanged,
844
target_extras=target_extras)
853
changes, self.target.mapping,
854
specific_files=specific_files,
855
include_unchanged=include_unchanged,
856
target_extras=target_extras)
846
858
def _iter_git_changes(self, want_unchanged=False, specific_files=None,
847
require_versioned=False, extra_trees=None,
848
want_unversioned=False):
859
require_versioned=False, extra_trees=None,
860
want_unversioned=False):
849
861
raise NotImplementedError(self._iter_git_changes)
862
874
isinstance(target, GitRevisionTree))
864
876
def _iter_git_changes(self, want_unchanged=False, specific_files=None,
865
require_versioned=True, extra_trees=None,
866
want_unversioned=False):
877
require_versioned=True, extra_trees=None,
878
want_unversioned=False):
867
879
trees = [self.source]
868
880
if extra_trees is not None:
869
881
trees.extend(extra_trees)
870
882
if specific_files is not None:
871
883
specific_files = self.target.find_related_paths_across_trees(
872
specific_files, trees,
873
require_versioned=require_versioned)
884
specific_files, trees,
885
require_versioned=require_versioned)
875
887
if self.source._repository._git.object_store != self.target._repository._git.object_store:
876
888
store = OverlayObjectStore([self.source._repository._git.object_store,
1054
1067
yield (posixpath.join(basepath, path), value)
1055
1068
(ctime, mtime, dev, ino, mode, uid, gid, size, sha, flags) = value
1056
1069
if S_ISGITLINK(mode):
1057
pass # TODO(jelmer): dive into submodule
1070
pass # TODO(jelmer): dive into submodule
1060
1072
def iter_entries_by_dir(self, specific_files=None, yield_parents=False):
1061
1073
if yield_parents:
1098
1110
def _get_dir_ie(self, path, parent_id):
1099
1111
file_id = self.path2id(path)
1100
1112
return GitTreeDirectory(file_id,
1101
posixpath.basename(path).strip("/"), parent_id)
1113
posixpath.basename(path).strip("/"), parent_id)
1103
1115
def _get_file_ie(self, name, path, value, parent_id):
1104
1116
if not isinstance(name, text_type):
1184
1196
# TODO(jelmer): This shouldn't be called, it's inventory specific.
1185
1197
for (old_path, new_path, file_id, ie) in delta:
1186
1198
if old_path is not None:
1187
(index, old_subpath) = self._lookup_index(old_path.encode('utf-8'))
1199
(index, old_subpath) = self._lookup_index(
1200
old_path.encode('utf-8'))
1188
1201
if old_subpath in index:
1189
1202
self._index_del_entry(index, old_subpath)
1190
1203
self._versioned_dirs = None
1226
1239
if not self.has_filename(to_rel):
1227
1240
raise errors.BzrMoveFailedError(from_rel, to_rel,
1228
errors.NoSuchFile(to_rel))
1241
errors.NoSuchFile(to_rel))
1229
1242
if self.basis_tree().is_versioned(to_rel):
1230
1243
raise errors.BzrMoveFailedError(from_rel, to_rel,
1231
errors.AlreadyVersionedError(to_rel))
1244
errors.AlreadyVersionedError(to_rel))
1233
1246
kind = self.kind(to_rel)
1241
1254
exc_type = errors.BzrMoveFailedError
1242
1255
if self.is_versioned(to_rel):
1243
1256
raise exc_type(from_rel, to_rel,
1244
errors.AlreadyVersionedError(to_rel))
1257
errors.AlreadyVersionedError(to_rel))
1245
1258
if not self.has_filename(from_rel):
1246
1259
raise errors.BzrMoveFailedError(from_rel, to_rel,
1247
errors.NoSuchFile(from_rel))
1260
errors.NoSuchFile(from_rel))
1248
1261
kind = self.kind(from_rel)
1249
1262
if not self.is_versioned(from_rel) and kind != 'directory':
1250
1263
raise exc_type(from_rel, to_rel,
1251
errors.NotVersionedError(from_rel))
1264
errors.NotVersionedError(from_rel))
1252
1265
if self.has_filename(to_rel):
1253
1266
raise errors.RenameFailedFilesExist(
1254
1267
from_rel, to_rel, errors.FileExists(to_rel))
1279
1292
self._index_add_entry(to_rel, kind)
1281
todo = [(p, i) for (p, i) in self._recurse_index_entries() if p.startswith(from_path+b'/')]
1294
todo = [(p, i) for (p, i) in self._recurse_index_entries()
1295
if p.startswith(from_path + b'/')]
1282
1296
for child_path, child_value in todo:
1283
1297
(child_to_index, child_to_index_path) = self._lookup_index(
1284
posixpath.join(to_path, posixpath.relpath(child_path, from_path)))
1298
posixpath.join(to_path, posixpath.relpath(child_path, from_path)))
1285
1299
child_to_index[child_to_index_path] = child_value
1286
1300
# TODO(jelmer): Mark individual index as dirty
1287
1301
self._index_dirty = True
1288
(child_from_index, child_from_index_path) = self._lookup_index(child_path)
1289
self._index_del_entry(child_from_index, child_from_index_path)
1302
(child_from_index, child_from_index_path) = self._lookup_index(
1304
self._index_del_entry(
1305
child_from_index, child_from_index_path)
1291
1307
self._versioned_dirs = None
1294
1310
def find_related_paths_across_trees(self, paths, trees=[],
1295
require_versioned=True):
1311
require_versioned=True):
1296
1312
if paths is None:
1369
1385
isinstance(target, MutableGitIndexTree))
1371
1387
def _iter_git_changes(self, want_unchanged=False, specific_files=None,
1372
require_versioned=False, extra_trees=None,
1373
want_unversioned=False):
1388
require_versioned=False, extra_trees=None,
1389
want_unversioned=False):
1374
1390
trees = [self.source]
1375
1391
if extra_trees is not None:
1376
1392
trees.extend(extra_trees)
1377
1393
if specific_files is not None:
1378
1394
specific_files = self.target.find_related_paths_across_trees(
1379
specific_files, trees,
1380
require_versioned=require_versioned)
1395
specific_files, trees,
1396
require_versioned=require_versioned)
1381
1397
# TODO(jelmer): Restrict to specific_files, for performance reasons.
1382
1398
with self.lock_read():
1383
1399
return changes_between_git_tree_and_working_copy(
1425
1441
if stat.S_ISDIR(st.st_mode):
1428
blob = blob_from_path_and_stat(target.abspath(e).encode(osutils._fs_enc), st)
1444
blob = blob_from_path_and_stat(
1445
target.abspath(e).encode(osutils._fs_enc), st)
1429
1446
store.add_object(blob)
1430
1447
np = np.encode('utf-8')
1431
1448
blobs[np] = (blob.id, cleanup_mode(st.st_mode))
1433
to_tree_sha = commit_tree(store, dirified + [(p, s, m) for (p, (s, m)) in blobs.items()])
1450
to_tree_sha = commit_tree(
1451
store, dirified + [(p, s, m) for (p, (s, m)) in blobs.items()])
1434
1452
return store.tree_changes(
1435
1453
from_tree_sha, to_tree_sha, include_trees=True,
1436
1454
want_unchanged=want_unchanged, change_type_same=True), extras