766
766
tt.set_executability(entry.executable, trans_id)
769
def revert(working_tree, target_tree, filenames, backups=False,
770
pb=None, change_reporter=None):
771
"""Revert a working tree's contents to those of a target tree."""
772
pb = ui.ui_factory.nested_progress_bar()
774
with target_tree.lock_read(), working_tree.transform(pb) as tt:
775
pp = ProgressPhase("Revert phase", 3, pb)
776
conflicts, merge_modified = _prepare_revert_transform(
777
working_tree, target_tree, tt, filenames, backups, pp)
780
change_reporter = delta._ChangeReporter(
781
unversioned_filter=working_tree.is_ignored)
782
delta.report_changes(tt.iter_changes(), change_reporter)
783
for conflict in conflicts:
784
trace.warning(text_type(conflict))
787
if working_tree.supports_merge_modified():
788
working_tree.set_merge_modified(merge_modified)
794
def _prepare_revert_transform(working_tree, target_tree, tt, filenames,
769
def _prepare_revert_transform(es, working_tree, target_tree, tt, filenames,
795
770
backups, pp, basis_tree=None,
796
771
merge_modified=None):
797
772
with ui.ui_factory.nested_progress_bar() as child_pb:
798
773
if merge_modified is None:
799
774
merge_modified = working_tree.merge_modified()
800
merge_modified = _alter_files(working_tree, target_tree, tt,
775
merge_modified = _alter_files(es, working_tree, target_tree, tt,
801
776
child_pb, filenames, backups,
802
777
merge_modified, basis_tree)
803
778
with ui.ui_factory.nested_progress_bar() as child_pb:
807
782
return conflicts, merge_modified
810
def _alter_files(working_tree, target_tree, tt, pb, specific_files,
785
def revert(working_tree, target_tree, filenames, backups=False,
786
pb=None, change_reporter=None, merge_modified=None, basis_tree=None):
787
"""Revert a working tree's contents to those of a target tree."""
788
with cleanup.ExitStack() as es:
789
pb = es.enter_context(ui.ui_factory.nested_progress_bar())
790
es.enter_context(target_tree.lock_read())
791
tt = es.enter_context(working_tree.transform(pb))
792
pp = ProgressPhase("Revert phase", 3, pb)
793
conflicts, merge_modified = _prepare_revert_transform(
794
es, working_tree, target_tree, tt, filenames, backups, pp)
797
change_reporter = delta._ChangeReporter(
798
unversioned_filter=working_tree.is_ignored)
799
delta.report_changes(tt.iter_changes(), change_reporter)
800
for conflict in conflicts:
801
trace.warning(text_type(conflict))
804
if working_tree.supports_merge_modified():
805
working_tree.set_merge_modified(merge_modified)
809
def _alter_files(es, working_tree, target_tree, tt, pb, specific_files,
811
810
backups, merge_modified, basis_tree=None):
812
811
if basis_tree is not None:
813
basis_tree.lock_read()
812
es.enter_context(basis_tree.lock_read())
814
813
# We ask the working_tree for its changes relative to the target, rather
815
814
# than the target changes relative to the working tree. Because WT4 has an
816
815
# optimizer to compare itself to a target, but no optimizer for the
823
822
skip_root = False
826
for id_num, change in enumerate(change_list):
827
target_path, wt_path = change.path
828
target_versioned, wt_versioned = change.versioned
829
target_parent = change.parent_id[0]
830
target_name, wt_name = change.name
831
target_kind, wt_kind = change.kind
832
target_executable, wt_executable = change.executable
833
if skip_root and wt_path == '':
835
trans_id = tt.trans_id_file_id(change.file_id)
837
if change.changed_content:
839
if wt_kind == 'file' and (backups or target_kind is None):
840
wt_sha1 = working_tree.get_file_sha1(wt_path)
841
if merge_modified.get(wt_path) != wt_sha1:
842
# acquire the basis tree lazily to prevent the
843
# expense of accessing it when it's not needed ?
844
# (Guessing, RBC, 200702)
845
if basis_tree is None:
846
basis_tree = working_tree.basis_tree()
847
basis_tree.lock_read()
848
basis_inter = InterTree.get(basis_tree, working_tree)
849
basis_path = basis_inter.find_source_path(wt_path)
850
if basis_path is None:
851
if target_kind is None and not target_versioned:
854
if wt_sha1 != basis_tree.get_file_sha1(basis_path):
856
if wt_kind is not None:
858
tt.delete_contents(trans_id)
859
elif target_kind is not None:
860
parent_trans_id = tt.trans_id_tree_path(osutils.dirname(wt_path))
861
backup_name = tt._available_backup_name(
862
wt_name, parent_trans_id)
863
tt.adjust_path(backup_name, parent_trans_id, trans_id)
864
new_trans_id = tt.create_path(wt_name, parent_trans_id)
865
if wt_versioned and target_versioned:
866
tt.unversion_file(trans_id)
868
new_trans_id, file_id=getattr(change, 'file_id', None))
869
# New contents should have the same unix perms as old
872
trans_id = new_trans_id
873
if target_kind in ('directory', 'tree-reference'):
874
tt.create_directory(trans_id)
875
if target_kind == 'tree-reference':
876
revision = target_tree.get_reference_revision(
878
tt.set_tree_reference(revision, trans_id)
879
elif target_kind == 'symlink':
880
tt.create_symlink(target_tree.get_symlink_target(
881
target_path), trans_id)
882
elif target_kind == 'file':
883
deferred_files.append(
884
(target_path, (trans_id, mode_id, target_path)))
824
for id_num, change in enumerate(change_list):
825
target_path, wt_path = change.path
826
target_versioned, wt_versioned = change.versioned
827
target_parent = change.parent_id[0]
828
target_name, wt_name = change.name
829
target_kind, wt_kind = change.kind
830
target_executable, wt_executable = change.executable
831
if skip_root and wt_path == '':
833
trans_id = tt.trans_id_file_id(change.file_id)
835
if change.changed_content:
837
if wt_kind == 'file' and (backups or target_kind is None):
838
wt_sha1 = working_tree.get_file_sha1(wt_path)
839
if merge_modified.get(wt_path) != wt_sha1:
840
# acquire the basis tree lazily to prevent the
841
# expense of accessing it when it's not needed ?
842
# (Guessing, RBC, 200702)
885
843
if basis_tree is None:
886
844
basis_tree = working_tree.basis_tree()
887
basis_tree.lock_read()
888
new_sha1 = target_tree.get_file_sha1(target_path)
889
basis_inter = InterTree.get(basis_tree, target_tree)
890
basis_path = basis_inter.find_source_path(target_path)
891
if (basis_path is not None and
892
new_sha1 == basis_tree.get_file_sha1(basis_path)):
893
# If the new contents of the file match what is in basis,
894
# then there is no need to store in merge_modified.
895
if basis_path in merge_modified:
896
del merge_modified[basis_path]
845
es.enter_context(basis_tree.lock_read())
846
basis_inter = InterTree.get(basis_tree, working_tree)
847
basis_path = basis_inter.find_source_path(wt_path)
848
if basis_path is None:
849
if target_kind is None and not target_versioned:
898
merge_modified[target_path] = new_sha1
900
# preserve the execute bit when backing up
901
if keep_content and wt_executable == target_executable:
902
tt.set_executability(target_executable, trans_id)
852
if wt_sha1 != basis_tree.get_file_sha1(basis_path):
854
if wt_kind is not None:
856
tt.delete_contents(trans_id)
903
857
elif target_kind is not None:
904
raise AssertionError(target_kind)
905
if not wt_versioned and target_versioned:
907
trans_id, file_id=getattr(change, 'file_id', None))
908
if wt_versioned and not target_versioned:
909
tt.unversion_file(trans_id)
910
if (target_name is not None
911
and (wt_name != target_name or change.is_reparented())):
912
if target_path == '':
913
parent_trans = ROOT_PARENT
915
parent_trans = tt.trans_id_file_id(target_parent)
916
if wt_path == '' and wt_versioned:
917
tt.adjust_root_path(target_name, parent_trans)
919
tt.adjust_path(target_name, parent_trans, trans_id)
920
if wt_executable != target_executable and target_kind == "file":
921
tt.set_executability(target_executable, trans_id)
922
if working_tree.supports_content_filtering():
923
for (trans_id, mode_id, target_path), bytes in (
924
target_tree.iter_files_bytes(deferred_files)):
925
# We're reverting a tree to the target tree so using the
926
# target tree to find the file path seems the best choice
927
# here IMO - Ian C 27/Oct/2009
928
filters = working_tree._content_filter_stack(target_path)
929
bytes = filtered_output_bytes(
931
ContentFilterContext(target_path, working_tree))
932
tt.create_file(bytes, trans_id, mode_id)
934
for (trans_id, mode_id, target_path), bytes in target_tree.iter_files_bytes(
936
tt.create_file(bytes, trans_id, mode_id)
939
if basis_tree is not None:
858
parent_trans_id = tt.trans_id_tree_path(osutils.dirname(wt_path))
859
backup_name = tt._available_backup_name(
860
wt_name, parent_trans_id)
861
tt.adjust_path(backup_name, parent_trans_id, trans_id)
862
new_trans_id = tt.create_path(wt_name, parent_trans_id)
863
if wt_versioned and target_versioned:
864
tt.unversion_file(trans_id)
866
new_trans_id, file_id=getattr(change, 'file_id', None))
867
# New contents should have the same unix perms as old
870
trans_id = new_trans_id
871
if target_kind in ('directory', 'tree-reference'):
872
tt.create_directory(trans_id)
873
if target_kind == 'tree-reference':
874
revision = target_tree.get_reference_revision(
876
tt.set_tree_reference(revision, trans_id)
877
elif target_kind == 'symlink':
878
tt.create_symlink(target_tree.get_symlink_target(
879
target_path), trans_id)
880
elif target_kind == 'file':
881
deferred_files.append(
882
(target_path, (trans_id, mode_id, target_path)))
883
if basis_tree is None:
884
basis_tree = working_tree.basis_tree()
885
es.enter_context(basis_tree.lock_read())
886
new_sha1 = target_tree.get_file_sha1(target_path)
887
basis_inter = InterTree.get(basis_tree, target_tree)
888
basis_path = basis_inter.find_source_path(target_path)
889
if (basis_path is not None and
890
new_sha1 == basis_tree.get_file_sha1(basis_path)):
891
# If the new contents of the file match what is in basis,
892
# then there is no need to store in merge_modified.
893
if basis_path in merge_modified:
894
del merge_modified[basis_path]
896
merge_modified[target_path] = new_sha1
898
# preserve the execute bit when backing up
899
if keep_content and wt_executable == target_executable:
900
tt.set_executability(target_executable, trans_id)
901
elif target_kind is not None:
902
raise AssertionError(target_kind)
903
if not wt_versioned and target_versioned:
905
trans_id, file_id=getattr(change, 'file_id', None))
906
if wt_versioned and not target_versioned:
907
tt.unversion_file(trans_id)
908
if (target_name is not None
909
and (wt_name != target_name or change.is_reparented())):
910
if target_path == '':
911
parent_trans = ROOT_PARENT
913
parent_trans = tt.trans_id_file_id(target_parent)
914
if wt_path == '' and wt_versioned:
915
tt.adjust_root_path(target_name, parent_trans)
917
tt.adjust_path(target_name, parent_trans, trans_id)
918
if wt_executable != target_executable and target_kind == "file":
919
tt.set_executability(target_executable, trans_id)
920
if working_tree.supports_content_filtering():
921
for (trans_id, mode_id, target_path), bytes in (
922
target_tree.iter_files_bytes(deferred_files)):
923
# We're reverting a tree to the target tree so using the
924
# target tree to find the file path seems the best choice
925
# here IMO - Ian C 27/Oct/2009
926
filters = working_tree._content_filter_stack(target_path)
927
bytes = filtered_output_bytes(
929
ContentFilterContext(target_path, working_tree))
930
tt.create_file(bytes, trans_id, mode_id)
932
for (trans_id, mode_id, target_path), bytes in target_tree.iter_files_bytes(
934
tt.create_file(bytes, trans_id, mode_id)
941
936
return merge_modified