945
934
file_ids.sort(key=tree.id2path)
949
937
def build_tree(tree, wt):
950
"""Create working tree for a branch, using a TreeTransform.
952
This function should be used on empty trees, having a tree root at most.
953
(see merge and revert functionality for working with existing trees)
955
Existing files are handled like so:
957
- Existing bzrdirs take precedence over creating new items. They are
958
created as '%s.diverted' % name.
959
- Otherwise, if the content on disk matches the content we are building,
960
it is silently replaced.
961
- Otherwise, conflict resolution will move the old file to 'oldname.moved'.
963
assert 2 > len(wt.inventory)
938
"""Create working tree for a branch, using a Transaction."""
964
939
file_trans_id = {}
965
940
top_pb = bzrlib.ui.ui_factory.nested_progress_bar()
966
941
pp = ProgressPhase("Build phase", 2, top_pb)
967
if tree.inventory.root is not None:
968
wt.set_root_id(tree.inventory.root.file_id)
969
942
tt = TreeTransform(wt)
973
file_trans_id[wt.get_root_id()] = \
974
tt.trans_id_tree_file_id(wt.get_root_id())
945
file_trans_id[wt.get_root_id()] = tt.trans_id_tree_file_id(wt.get_root_id())
946
file_ids = topology_sorted_ids(tree)
975
947
pb = bzrlib.ui.ui_factory.nested_progress_bar()
977
for num, (tree_path, entry) in \
978
enumerate(tree.inventory.iter_entries_by_dir()):
979
pb.update("Building tree", num, len(tree.inventory))
949
for num, file_id in enumerate(file_ids):
950
pb.update("Building tree", num, len(file_ids))
951
entry = tree.inventory[file_id]
980
952
if entry.parent_id is None:
983
file_id = entry.file_id
984
target_path = wt.abspath(tree_path)
986
kind = file_kind(target_path)
990
if kind == "directory":
992
bzrdir.BzrDir.open(target_path)
993
except errors.NotBranchError:
997
if (file_id not in divert and
998
_content_match(tree, entry, file_id, kind,
1000
tt.delete_contents(tt.trans_id_tree_path(tree_path))
1001
if kind == 'directory':
1003
954
if entry.parent_id not in file_trans_id:
1004
955
raise repr(entry.parent_id)
1005
956
parent_id = file_trans_id[entry.parent_id]
1006
file_trans_id[file_id] = new_by_entry(tt, entry, parent_id,
957
file_trans_id[file_id] = new_by_entry(tt, entry, parent_id,
1009
new_trans_id = file_trans_id[file_id]
1010
old_parent = tt.trans_id_tree_path(tree_path)
1011
_reparent_children(tt, old_parent, new_trans_id)
1015
divert_trans = set(file_trans_id[f] for f in divert)
1016
resolver = lambda t, c: resolve_checkout(t, c, divert_trans)
1017
raw_conflicts = resolve_conflicts(tt, pass_func=resolver)
1018
conflicts = cook_conflicts(raw_conflicts, tt)
1019
for conflict in conflicts:
1022
wt.add_conflicts(conflicts)
1023
except errors.UnsupportedOperation:
1028
965
top_pb.finished()
1031
def _reparent_children(tt, old_parent, new_parent):
1032
for child in tt.iter_tree_children(old_parent):
1033
tt.adjust_path(tt.final_name(child), new_parent, child)
1036
def _content_match(tree, entry, file_id, kind, target_path):
1037
if entry.kind != kind:
1039
if entry.kind == "directory":
1041
if entry.kind == "file":
1042
if tree.get_file(file_id).read() == file(target_path, 'rb').read():
1044
elif entry.kind == "symlink":
1045
if tree.get_symlink_target(file_id) == os.readlink(target_path):
1050
def resolve_checkout(tt, conflicts, divert):
1051
new_conflicts = set()
1052
for c_type, conflict in ((c[0], c) for c in conflicts):
1053
# Anything but a 'duplicate' would indicate programmer error
1054
assert c_type == 'duplicate', c_type
1055
# Now figure out which is new and which is old
1056
if tt.new_contents(conflict[1]):
1057
new_file = conflict[1]
1058
old_file = conflict[2]
1060
new_file = conflict[2]
1061
old_file = conflict[1]
1063
# We should only get here if the conflict wasn't completely
1065
final_parent = tt.final_parent(old_file)
1066
if new_file in divert:
1067
new_name = tt.final_name(old_file)+'.diverted'
1068
tt.adjust_path(new_name, final_parent, new_file)
1069
new_conflicts.add((c_type, 'Diverted to',
1070
new_file, old_file))
1072
new_name = tt.final_name(old_file)+'.moved'
1073
tt.adjust_path(new_name, final_parent, old_file)
1074
new_conflicts.add((c_type, 'Moved existing file to',
1075
old_file, new_file))
1076
return new_conflicts
1079
967
def new_by_entry(tt, entry, parent_id, tree):
1080
968
"""Create a new file according to its inventory entry"""
1081
969
name = entry.name
1237
1125
pp.next_phase()
1238
1126
wt_interesting = [i for i in working_tree.inventory if interesting(i)]
1239
1127
child_pb = bzrlib.ui.ui_factory.nested_progress_bar()
1242
1129
for id_num, file_id in enumerate(wt_interesting):
1243
if (working_tree.inventory.is_root(file_id) and
1244
len(target_tree.inventory) == 0):
1246
1130
child_pb.update("New file check", id_num+1,
1247
1131
len(sorted_interesting))
1248
1132
if file_id not in target_tree:
1249
1133
trans_id = tt.trans_id_tree_file_id(file_id)
1250
1134
tt.unversion_file(trans_id)
1252
file_kind = working_tree.kind(file_id)
1255
delete_merge_modified = (file_id in merge_modified)
1256
if file_kind != 'file' and file_kind is not None:
1257
keep_contents = False
1259
if basis_tree is None:
1260
basis_tree = working_tree.basis_tree()
1261
wt_sha1 = working_tree.get_file_sha1(file_id)
1262
if (file_id in merge_modified and
1263
merge_modified[file_id] == wt_sha1):
1264
keep_contents = False
1265
elif (file_id in basis_tree and
1266
basis_tree.get_file_sha1(file_id) == wt_sha1):
1267
keep_contents = False
1269
keep_contents = True
1270
if not keep_contents:
1135
if file_id in merge_modified:
1271
1136
tt.delete_contents(trans_id)
1272
if delete_merge_modified:
1273
1137
del merge_modified[file_id]
1275
1139
child_pb.finished()