478
478
"""Return True if a trans_id's path has changed."""
479
479
return trans_id in self._new_name or trans_id in self._new_parent
481
def new_contents(self, trans_id):
482
return (trans_id in self._new_contents)
481
484
def find_conflicts(self):
482
485
"""Find any violations of inventory or filesystem invariants"""
483
486
if self.__done is True:
940
943
def build_tree(tree, wt):
941
944
"""Create working tree for a branch, using a TreeTransform.
946
This function should be used on empty trees, having a tree root at most.
947
(see merge and revert functionality for working with existing trees)
943
949
Existing files are handled like so:
945
- Existing bzrdirs take precedence over creating directories. New
946
directory contents are silently dropped.
951
- Existing bzrdirs take precedence over creating new items. They are
952
created as '%s.diverted' % name.
947
953
- Otherwise, if the content on disk matches the content we are building,
948
954
it is silently replaced.
949
955
- Otherwise, conflict resolution will move the old file to 'oldname.moved'.
957
assert 2 > len(wt.inventory)
951
958
file_trans_id = {}
952
959
top_pb = bzrlib.ui.ui_factory.nested_progress_bar()
953
960
pp = ProgressPhase("Build phase", 2, top_pb)
954
961
tt = TreeTransform(wt)
957
965
file_trans_id[wt.get_root_id()] = \
958
966
tt.trans_id_tree_file_id(wt.get_root_id())
959
file_ids = topology_sorted_ids(tree)
960
967
pb = bzrlib.ui.ui_factory.nested_progress_bar()
961
suppress_children = None
963
for num, file_id in enumerate(file_ids):
964
pb.update("Building tree", num, len(file_ids))
965
entry = tree.inventory[file_id]
969
for num, (tree_path, entry) in \
970
enumerate(tree.inventory.iter_entries_by_dir()):
971
pb.update("Building tree", num, len(tree.inventory))
966
972
if entry.parent_id is None:
969
tree_path = tree.id2path(file_id)
970
if (suppress_children is not None and
971
tree_path.startswith(suppress_children)):
973
target_path = wt.abspath(tree.id2path(file_id))
975
file_id = entry.file_id
976
target_path = wt.abspath(tree_path)
975
978
kind = file_kind(target_path)
976
979
except NoSuchFile:
982
985
except errors.NotBranchError:
985
suppress_children = tree_path + '/'
987
if _content_match(tree, entry, file_id,
989
if (file_id not in divert and
990
_content_match(tree, entry, file_id, kind,
989
992
tt.delete_contents(tt.trans_id_tree_path(tree_path))
990
993
if kind == 'directory':
992
995
if entry.parent_id not in file_trans_id:
993
996
raise repr(entry.parent_id)
994
997
parent_id = file_trans_id[entry.parent_id]
995
file_trans_id[file_id] = new_by_entry(tt, entry, parent_id,
998
file_trans_id[file_id] = new_by_entry(tt, entry, parent_id,
998
1001
new_trans_id = file_trans_id[file_id]
1003
1006
pp.next_phase()
1004
raw_conflicts = resolve_conflicts(tt, pass_func=resolve_checkout)
1007
divert_trans = set(file_trans_id[f] for f in divert)
1008
resolver = lambda t, c: resolve_checkout(t, c, divert_trans)
1009
raw_conflicts = resolve_conflicts(tt, pass_func=resolver)
1005
1010
conflicts = cook_conflicts(raw_conflicts, tt)
1006
1011
for conflict in conflicts:
1007
1012
warning(conflict)
1037
def resolve_checkout(tt, conflicts):
1042
def resolve_checkout(tt, conflicts, divert):
1038
1043
new_conflicts = set()
1039
1044
for c_type, conflict in ((c[0], c) for c in conflicts):
1040
1045
# Anything but a 'duplicate' would indicate programmer error
1041
1046
assert c_type == 'duplicate', c_type
1042
1047
# Now figure out which is new and which is old
1043
if tt.path_changed(conflict[1]):
1048
if tt.new_contents(conflict[1]):
1044
1049
new_file = conflict[1]
1045
1050
old_file = conflict[2]
1050
1055
# We should only get here if the conflict wasn't completely
1052
1057
final_parent = tt.final_parent(old_file)
1053
new_name = tt.final_name(old_file)+'.moved'
1054
tt.adjust_path(new_name, final_parent, old_file)
1055
new_conflicts.add((c_type, 'Moved existing file to',
1056
old_file, new_file))
1058
if new_file in divert:
1059
new_name = tt.final_name(old_file)+'.diverted'
1060
tt.adjust_path(new_name, final_parent, new_file)
1061
new_conflicts.add((c_type, 'Diverted to',
1062
new_file, old_file))
1064
new_name = tt.final_name(old_file)+'.moved'
1065
tt.adjust_path(new_name, final_parent, old_file)
1066
new_conflicts.add((c_type, 'Moved existing file to',
1067
old_file, new_file))
1057
1068
return new_conflicts