934
936
file_ids.sort(key=tree.id2path)
937
940
def build_tree(tree, wt):
938
"""Create working tree for a branch, using a Transaction."""
941
"""Create working tree for a branch, using a TreeTransform.
943
Existing files are handled like so:
945
- Existing bzrdirs take precedence over creating directories. New
946
directory contents are silently dropped.
947
- Otherwise, if the content on disk matches the content we are building,
948
it is silently replaced.
949
- Otherwise, conflict resolution will move the old file to 'oldname.moved'.
939
951
file_trans_id = {}
940
952
top_pb = bzrlib.ui.ui_factory.nested_progress_bar()
941
953
pp = ProgressPhase("Build phase", 2, top_pb)
942
954
tt = TreeTransform(wt)
945
file_trans_id[wt.get_root_id()] = tt.trans_id_tree_file_id(wt.get_root_id())
957
file_trans_id[wt.get_root_id()] = \
958
tt.trans_id_tree_file_id(wt.get_root_id())
946
959
file_ids = topology_sorted_ids(tree)
947
960
pb = bzrlib.ui.ui_factory.nested_progress_bar()
961
suppress_children = None
949
963
for num, file_id in enumerate(file_ids):
950
964
pb.update("Building tree", num, len(file_ids))
951
965
entry = tree.inventory[file_id]
952
966
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
kind = file_kind(target_path)
979
if kind == "directory":
981
bzrdir.BzrDir.open(target_path)
982
except errors.NotBranchError:
985
suppress_children = tree_path + '/'
987
if _content_match(tree, entry, file_id,
989
tt.delete_contents(tt.trans_id_tree_path(tree_path))
990
if kind == 'directory':
954
992
if entry.parent_id not in file_trans_id:
955
993
raise repr(entry.parent_id)
956
994
parent_id = file_trans_id[entry.parent_id]
957
995
file_trans_id[file_id] = new_by_entry(tt, entry, parent_id,
998
new_trans_id = file_trans_id[file_id]
999
old_parent = tt.trans_id_tree_path(tree_path)
1000
_reparent_children(tt, old_parent, new_trans_id)
1004
raw_conflicts = resolve_conflicts(tt, pass_func=resolve_checkout)
1005
conflicts = cook_conflicts(raw_conflicts, tt)
1006
for conflict in conflicts:
1009
wt.add_conflicts(conflicts)
1010
except errors.UnsupportedOperation:
965
1015
top_pb.finished()
1018
def _reparent_children(tt, old_parent, new_parent):
1019
for child in tt.iter_tree_children(old_parent):
1020
tt.adjust_path(tt.final_name(child), new_parent, child)
1023
def _content_match(tree, entry, file_id, kind, target_path):
1024
if entry.kind != kind:
1026
if entry.kind == "directory":
1028
if entry.kind == "file":
1029
if tree.get_file(file_id).read() == file(target_path, 'rb').read():
1031
elif entry.kind == "symlink":
1032
if tree.get_symlink_target(file_id) == os.readlink(target_path):
1037
def resolve_checkout(tt, conflicts):
1038
new_conflicts = set()
1039
for c_type, conflict in ((c[0], c) for c in conflicts):
1040
# Anything but a 'duplicate' would indicate programmer error
1041
assert c_type == 'duplicate', c_type
1042
# Now figure out which is new and which is old
1043
if tt.path_changed(conflict[1]):
1044
new_file = conflict[1]
1045
old_file = conflict[2]
1047
new_file = conflict[2]
1048
old_file = conflict[1]
1050
# We should only get here if the conflict wasn't completely
1052
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))
1057
return new_conflicts
967
1060
def new_by_entry(tt, entry, parent_id, tree):
968
1061
"""Create a new file according to its inventory entry"""
969
1062
name = entry.name