639
639
return [(self.get_path(t), t) for t in trans_ids]
642
def build_tree(tree, wt, accelerator_tree=None, hardlink=False,
643
delta_from_tree=False):
644
"""Create working tree for a branch, using a TreeTransform.
646
This function should be used on empty trees, having a tree root at most.
647
(see merge and revert functionality for working with existing trees)
649
Existing files are handled like so:
651
- Existing bzrdirs take precedence over creating new items. They are
652
created as '%s.diverted' % name.
653
- Otherwise, if the content on disk matches the content we are building,
654
it is silently replaced.
655
- Otherwise, conflict resolution will move the old file to 'oldname.moved'.
657
:param tree: The tree to convert wt into a copy of
658
:param wt: The working tree that files will be placed into
659
:param accelerator_tree: A tree which can be used for retrieving file
660
contents more quickly than tree itself, i.e. a workingtree. tree
661
will be used for cases where accelerator_tree's content is different.
662
:param hardlink: If true, hard-link files to accelerator_tree, where
663
possible. accelerator_tree must implement abspath, i.e. be a
665
:param delta_from_tree: If true, build_tree may use the input Tree to
666
generate the inventory delta.
668
with contextlib.ExitStack() as exit_stack:
669
exit_stack.enter_context(wt.lock_tree_write())
670
exit_stack.enter_context(tree.lock_read())
671
if accelerator_tree is not None:
672
exit_stack.enter_context(accelerator_tree.lock_read())
673
return _build_tree(tree, wt, accelerator_tree, hardlink,
677
def _build_tree(tree, wt, accelerator_tree, hardlink, delta_from_tree):
678
"""See build_tree."""
679
for num, _unused in enumerate(wt.all_versioned_paths()):
680
if num > 0: # more than just a root
681
raise errors.WorkingTreeAlreadyPopulated(base=wt.basedir)
683
top_pb = ui.ui_factory.nested_progress_bar()
684
pp = ProgressPhase("Build phase", 2, top_pb)
685
if tree.path2id('') is not None:
686
# This is kind of a hack: we should be altering the root
687
# as part of the regular tree shape diff logic.
688
# The conditional test here is to avoid doing an
689
# expensive operation (flush) every time the root id
690
# is set within the tree, nor setting the root and thus
691
# marking the tree as dirty, because we use two different
692
# idioms here: tree interfaces and inventory interfaces.
693
if wt.path2id('') != tree.path2id(''):
694
wt.set_root_id(tree.path2id(''))
700
file_trans_id[find_previous_path(wt, tree, '')] = tt.trans_id_tree_path('')
701
with ui.ui_factory.nested_progress_bar() as pb:
702
deferred_contents = []
704
total = len(tree.all_versioned_paths())
706
precomputed_delta = []
708
precomputed_delta = None
709
# Check if tree inventory has content. If so, we populate
710
# existing_files with the directory content. If there are no
711
# entries we skip populating existing_files as its not used.
712
# This improves performance and unncessary work on large
713
# directory trees. (#501307)
715
existing_files = set()
716
for dir, files in wt.walkdirs():
717
existing_files.update(f[0] for f in files)
718
for num, (tree_path, entry) in \
719
enumerate(tree.iter_entries_by_dir()):
720
pb.update(gettext("Building tree"), num
721
- len(deferred_contents), total)
722
if entry.parent_id is None:
725
file_id = entry.file_id
727
precomputed_delta.append((None, tree_path, file_id, entry))
728
if tree_path in existing_files:
729
target_path = wt.abspath(tree_path)
730
kind = file_kind(target_path)
731
if kind == "directory":
733
controldir.ControlDir.open(target_path)
734
except errors.NotBranchError:
737
divert.add(tree_path)
738
if (tree_path not in divert
740
tree, entry, tree_path, kind, target_path)):
741
tt.delete_contents(tt.trans_id_tree_path(tree_path))
742
if kind == 'directory':
744
parent_id = file_trans_id[osutils.dirname(tree_path)]
745
if entry.kind == 'file':
746
# We *almost* replicate new_by_entry, so that we can defer
747
# getting the file text, and get them all at once.
748
trans_id = tt.create_path(entry.name, parent_id)
749
file_trans_id[tree_path] = trans_id
750
tt.version_file(trans_id, file_id=file_id)
751
executable = tree.is_executable(tree_path)
753
tt.set_executability(executable, trans_id)
754
trans_data = (trans_id, tree_path, entry.text_sha1)
755
deferred_contents.append((tree_path, trans_data))
757
file_trans_id[tree_path] = new_by_entry(
758
tree_path, tt, entry, parent_id, tree)
760
new_trans_id = file_trans_id[tree_path]
761
old_parent = tt.trans_id_tree_path(tree_path)
762
_reparent_children(tt, old_parent, new_trans_id)
763
offset = num + 1 - len(deferred_contents)
764
_create_files(tt, tree, deferred_contents, pb, offset,
765
accelerator_tree, hardlink)
767
divert_trans = set(file_trans_id[f] for f in divert)
770
return resolve_checkout(t, c, divert_trans)
771
raw_conflicts = resolve_conflicts(tt, pass_func=resolver)
772
if len(raw_conflicts) > 0:
773
precomputed_delta = None
774
conflicts = tt.cook_conflicts(raw_conflicts)
775
for conflict in conflicts:
776
trace.warning(str(conflict))
778
wt.add_conflicts(conflicts)
779
except errors.UnsupportedOperation:
781
result = tt.apply(no_conflicts=True,
782
precomputed_delta=precomputed_delta)
789
def _create_files(tt, tree, desired_files, pb, offset, accelerator_tree,
791
total = len(desired_files) + offset
793
if accelerator_tree is None:
794
new_desired_files = desired_files
796
iter = accelerator_tree.iter_changes(tree, include_unchanged=True)
798
change.path for change in iter
799
if not (change.changed_content or change.executable[0] != change.executable[1])]
800
if accelerator_tree.supports_content_filtering():
801
unchanged = [(tp, ap) for (tp, ap) in unchanged
802
if not next(accelerator_tree.iter_search_rules([ap]))]
803
unchanged = dict(unchanged)
804
new_desired_files = []
806
for unused_tree_path, (trans_id, tree_path, text_sha1) in desired_files:
807
accelerator_path = unchanged.get(tree_path)
808
if accelerator_path is None:
809
new_desired_files.append((tree_path,
810
(trans_id, tree_path, text_sha1)))
812
pb.update(gettext('Adding file contents'), count + offset, total)
814
tt.create_hardlink(accelerator_tree.abspath(accelerator_path),
817
with accelerator_tree.get_file(accelerator_path) as f:
818
chunks = osutils.file_iterator(f)
819
if wt.supports_content_filtering():
820
filters = wt._content_filter_stack(tree_path)
821
chunks = filtered_output_bytes(chunks, filters,
822
ContentFilterContext(tree_path, tree))
823
tt.create_file(chunks, trans_id, sha1=text_sha1)
826
for count, ((trans_id, tree_path, text_sha1), contents) in enumerate(
827
tree.iter_files_bytes(new_desired_files)):
828
if wt.supports_content_filtering():
829
filters = wt._content_filter_stack(tree_path)
830
contents = filtered_output_bytes(contents, filters,
831
ContentFilterContext(tree_path, tree))
832
tt.create_file(contents, trans_id, sha1=text_sha1)
833
pb.update(gettext('Adding file contents'), count + offset, total)
836
642
def _reparent_children(tt, old_parent, new_parent):
837
643
for child in tt.iter_tree_children(old_parent):
838
644
tt.adjust_path(tt.final_name(child), new_parent, child)
953
713
tt.set_executability(entry.executable, trans_id)
956
def revert(working_tree, target_tree, filenames, backups=False,
957
pb=None, change_reporter=None):
958
"""Revert a working tree's contents to those of a target tree."""
959
pb = ui.ui_factory.nested_progress_bar()
961
with target_tree.lock_read(), working_tree.transform(pb) as tt:
962
pp = ProgressPhase("Revert phase", 3, pb)
963
conflicts, merge_modified = _prepare_revert_transform(
964
working_tree, target_tree, tt, filenames, backups, pp)
967
change_reporter = delta._ChangeReporter(
968
unversioned_filter=working_tree.is_ignored)
969
delta.report_changes(tt.iter_changes(), change_reporter)
970
for conflict in conflicts:
971
trace.warning(str(conflict))
974
if working_tree.supports_merge_modified():
975
working_tree.set_merge_modified(merge_modified)
981
def _prepare_revert_transform(working_tree, target_tree, tt, filenames,
716
def _prepare_revert_transform(es, working_tree, target_tree, tt, filenames,
982
717
backups, pp, basis_tree=None,
983
718
merge_modified=None):
984
719
with ui.ui_factory.nested_progress_bar() as child_pb:
985
720
if merge_modified is None:
986
721
merge_modified = working_tree.merge_modified()
987
merge_modified = _alter_files(working_tree, target_tree, tt,
722
merge_modified = _alter_files(es, working_tree, target_tree, tt,
988
723
child_pb, filenames, backups,
989
724
merge_modified, basis_tree)
990
725
with ui.ui_factory.nested_progress_bar() as child_pb:
994
729
return conflicts, merge_modified
997
def _alter_files(working_tree, target_tree, tt, pb, specific_files,
732
def revert(working_tree, target_tree, filenames, backups=False,
733
pb=None, change_reporter=None, merge_modified=None, basis_tree=None):
734
"""Revert a working tree's contents to those of a target tree."""
735
with contextlib.ExitStack() as es:
736
pb = es.enter_context(ui.ui_factory.nested_progress_bar())
737
es.enter_context(target_tree.lock_read())
738
tt = es.enter_context(working_tree.transform(pb))
739
pp = ProgressPhase("Revert phase", 3, pb)
740
conflicts, merge_modified = _prepare_revert_transform(
741
es, working_tree, target_tree, tt, filenames, backups, pp)
744
change_reporter = delta._ChangeReporter(
745
unversioned_filter=working_tree.is_ignored)
746
delta.report_changes(tt.iter_changes(), change_reporter)
747
for conflict in conflicts:
748
trace.warning(str(conflict))
751
if working_tree.supports_merge_modified():
752
working_tree.set_merge_modified(merge_modified)
756
def _alter_files(es, working_tree, target_tree, tt, pb, specific_files,
998
757
backups, merge_modified, basis_tree=None):
999
758
if basis_tree is not None:
1000
basis_tree.lock_read()
759
es.enter_context(basis_tree.lock_read())
1001
760
# We ask the working_tree for its changes relative to the target, rather
1002
761
# than the target changes relative to the working tree. Because WT4 has an
1003
762
# optimizer to compare itself to a target, but no optimizer for the
1008
767
skip_root = True
1010
769
skip_root = False
1013
for id_num, change in enumerate(change_list):
1014
target_path, wt_path = change.path
1015
target_versioned, wt_versioned = change.versioned
1016
target_parent = change.parent_id[0]
1017
target_name, wt_name = change.name
1018
target_kind, wt_kind = change.kind
1019
target_executable, wt_executable = change.executable
1020
if skip_root and wt_path == '':
1022
trans_id = tt.trans_id_file_id(change.file_id)
1024
if change.changed_content:
1025
keep_content = False
1026
if wt_kind == 'file' and (backups or target_kind is None):
1027
wt_sha1 = working_tree.get_file_sha1(wt_path)
1028
if merge_modified.get(wt_path) != wt_sha1:
1029
# acquire the basis tree lazily to prevent the
1030
# expense of accessing it when it's not needed ?
1031
# (Guessing, RBC, 200702)
1032
if basis_tree is None:
1033
basis_tree = working_tree.basis_tree()
1034
basis_tree.lock_read()
1035
basis_inter = InterTree.get(basis_tree, working_tree)
1036
basis_path = basis_inter.find_source_path(wt_path)
1037
if basis_path is None:
1038
if target_kind is None and not target_versioned:
1041
if wt_sha1 != basis_tree.get_file_sha1(basis_path):
1043
if wt_kind is not None:
1044
if not keep_content:
1045
tt.delete_contents(trans_id)
1046
elif target_kind is not None:
1047
parent_trans_id = tt.trans_id_tree_path(osutils.dirname(wt_path))
1048
backup_name = tt._available_backup_name(
1049
wt_name, parent_trans_id)
1050
tt.adjust_path(backup_name, parent_trans_id, trans_id)
1051
new_trans_id = tt.create_path(wt_name, parent_trans_id)
1052
if wt_versioned and target_versioned:
1053
tt.unversion_file(trans_id)
1055
new_trans_id, file_id=getattr(change, 'file_id', None))
1056
# New contents should have the same unix perms as old
1059
trans_id = new_trans_id
1060
if target_kind in ('directory', 'tree-reference'):
1061
tt.create_directory(trans_id)
1062
if target_kind == 'tree-reference':
1063
revision = target_tree.get_reference_revision(
1065
tt.set_tree_reference(revision, trans_id)
1066
elif target_kind == 'symlink':
1067
tt.create_symlink(target_tree.get_symlink_target(
1068
target_path), trans_id)
1069
elif target_kind == 'file':
1070
deferred_files.append(
1071
(target_path, (trans_id, mode_id, target_path)))
771
for id_num, change in enumerate(change_list):
772
target_path, wt_path = change.path
773
target_versioned, wt_versioned = change.versioned
774
target_parent = change.parent_id[0]
775
target_name, wt_name = change.name
776
target_kind, wt_kind = change.kind
777
target_executable, wt_executable = change.executable
778
if skip_root and wt_path == '':
781
if wt_path is not None:
782
trans_id = tt.trans_id_tree_path(wt_path)
784
trans_id = tt.assign_id()
785
if change.changed_content:
787
if wt_kind == 'file' and (backups or target_kind is None):
788
wt_sha1 = working_tree.get_file_sha1(wt_path)
789
if merge_modified.get(wt_path) != wt_sha1:
790
# acquire the basis tree lazily to prevent the
791
# expense of accessing it when it's not needed ?
792
# (Guessing, RBC, 200702)
1072
793
if basis_tree is None:
1073
794
basis_tree = working_tree.basis_tree()
1074
basis_tree.lock_read()
1075
new_sha1 = target_tree.get_file_sha1(target_path)
1076
basis_inter = InterTree.get(basis_tree, target_tree)
1077
basis_path = basis_inter.find_source_path(target_path)
1078
if (basis_path is not None and
1079
new_sha1 == basis_tree.get_file_sha1(basis_path)):
1080
# If the new contents of the file match what is in basis,
1081
# then there is no need to store in merge_modified.
1082
if basis_path in merge_modified:
1083
del merge_modified[basis_path]
795
es.enter_context(basis_tree.lock_read())
796
basis_inter = InterTree.get(basis_tree, working_tree)
797
basis_path = basis_inter.find_source_path(wt_path)
798
if basis_path is None:
799
if target_kind is None and not target_versioned:
1085
merge_modified[target_path] = new_sha1
1087
# preserve the execute bit when backing up
1088
if keep_content and wt_executable == target_executable:
1089
tt.set_executability(target_executable, trans_id)
802
if wt_sha1 != basis_tree.get_file_sha1(basis_path):
804
if wt_kind is not None:
806
tt.delete_contents(trans_id)
1090
807
elif target_kind is not None:
1091
raise AssertionError(target_kind)
1092
if not wt_versioned and target_versioned:
1094
trans_id, file_id=getattr(change, 'file_id', None))
1095
if wt_versioned and not target_versioned:
1096
tt.unversion_file(trans_id)
1097
if (target_name is not None
1098
and (wt_name != target_name or change.is_reparented())):
1099
if target_path == '':
1100
parent_trans = ROOT_PARENT
1102
parent_trans = tt.trans_id_file_id(target_parent)
1103
if wt_path == '' and wt_versioned:
1104
tt.adjust_root_path(target_name, parent_trans)
1106
tt.adjust_path(target_name, parent_trans, trans_id)
1107
if wt_executable != target_executable and target_kind == "file":
1108
tt.set_executability(target_executable, trans_id)
1109
if working_tree.supports_content_filtering():
1110
for (trans_id, mode_id, target_path), bytes in (
1111
target_tree.iter_files_bytes(deferred_files)):
1112
# We're reverting a tree to the target tree so using the
1113
# target tree to find the file path seems the best choice
1114
# here IMO - Ian C 27/Oct/2009
1115
filters = working_tree._content_filter_stack(target_path)
1116
bytes = filtered_output_bytes(
1118
ContentFilterContext(target_path, working_tree))
1119
tt.create_file(bytes, trans_id, mode_id)
1121
for (trans_id, mode_id, target_path), bytes in target_tree.iter_files_bytes(
1123
tt.create_file(bytes, trans_id, mode_id)
1124
tt.fixup_new_roots()
1126
if basis_tree is not None:
808
parent_trans_id = tt.trans_id_tree_path(osutils.dirname(wt_path))
809
backup_name = tt._available_backup_name(
810
wt_name, parent_trans_id)
811
tt.adjust_path(backup_name, parent_trans_id, trans_id)
812
new_trans_id = tt.create_path(wt_name, parent_trans_id)
813
if wt_versioned and target_versioned:
814
tt.unversion_file(trans_id)
816
new_trans_id, file_id=getattr(change, 'file_id', None))
817
# New contents should have the same unix perms as old
820
trans_id = new_trans_id
821
if target_kind in ('directory', 'tree-reference'):
822
tt.create_directory(trans_id)
823
if target_kind == 'tree-reference':
824
revision = target_tree.get_reference_revision(
826
tt.set_tree_reference(revision, trans_id)
827
elif target_kind == 'symlink':
828
tt.create_symlink(target_tree.get_symlink_target(
829
target_path), trans_id)
830
elif target_kind == 'file':
831
deferred_files.append(
832
(target_path, (trans_id, mode_id, target_path)))
833
if basis_tree is None:
834
basis_tree = working_tree.basis_tree()
835
es.enter_context(basis_tree.lock_read())
836
new_sha1 = target_tree.get_file_sha1(target_path)
837
basis_inter = InterTree.get(basis_tree, target_tree)
838
basis_path = basis_inter.find_source_path(target_path)
839
if (basis_path is not None and
840
new_sha1 == basis_tree.get_file_sha1(basis_path)):
841
# If the new contents of the file match what is in basis,
842
# then there is no need to store in merge_modified.
843
if basis_path in merge_modified:
844
del merge_modified[basis_path]
846
merge_modified[target_path] = new_sha1
848
# preserve the execute bit when backing up
849
if keep_content and wt_executable == target_executable:
850
tt.set_executability(target_executable, trans_id)
851
elif target_kind is not None:
852
raise AssertionError(target_kind)
853
if not wt_versioned and target_versioned:
855
trans_id, file_id=getattr(change, 'file_id', None))
856
if wt_versioned and not target_versioned:
857
tt.unversion_file(trans_id)
858
if (target_name is not None
859
and (wt_name != target_name or change.is_reparented())):
860
if target_path == '':
861
parent_trans = ROOT_PARENT
863
parent_trans = tt.trans_id_file_id(target_parent)
864
if wt_path == '' and wt_versioned:
865
tt.adjust_root_path(target_name, parent_trans)
867
tt.adjust_path(target_name, parent_trans, trans_id)
868
if wt_executable != target_executable and target_kind == "file":
869
tt.set_executability(target_executable, trans_id)
870
if working_tree.supports_content_filtering():
871
for (trans_id, mode_id, target_path), bytes in (
872
target_tree.iter_files_bytes(deferred_files)):
873
# We're reverting a tree to the target tree so using the
874
# target tree to find the file path seems the best choice
875
# here IMO - Ian C 27/Oct/2009
876
filters = working_tree._content_filter_stack(target_path)
877
bytes = filtered_output_bytes(
879
ContentFilterContext(target_path, working_tree))
880
tt.create_file(bytes, trans_id, mode_id)
882
for (trans_id, mode_id, target_path), bytes in target_tree.iter_files_bytes(
884
tt.create_file(bytes, trans_id, mode_id)
1128
886
return merge_modified