19
19
from stat import S_ISREG
21
from bzrlib import bzrdir, errors
22
21
from bzrlib.errors import (DuplicateKey, MalformedTransform, NoSuchFile,
23
22
ReusingTransform, NotVersionedError, CantMoveRoot,
24
ExistingLimbo, ImmortalLimbo, NoFinalPath)
23
ExistingLimbo, ImmortalLimbo)
25
24
from bzrlib.inventory import InventoryEntry
26
25
from bzrlib.osutils import (file_kind, supports_executable, pathjoin, lexists,
28
27
from bzrlib.progress import DummyProgress, ProgressPhase
29
28
from bzrlib.trace import mutter, warning
30
from bzrlib import tree
32
import bzrlib.urlutils as urlutils
35
32
ROOT_PARENT = "root-parent"
945
918
file_ids.sort(key=tree.id2path)
949
921
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
if len(wt.inventory) > 1: # more than just a root
964
raise errors.WorkingTreeAlreadyPopulated(base=wt.basedir)
922
"""Create working tree for a branch, using a Transaction."""
965
923
file_trans_id = {}
966
924
top_pb = bzrlib.ui.ui_factory.nested_progress_bar()
967
925
pp = ProgressPhase("Build phase", 2, top_pb)
968
if tree.inventory.root is not None:
969
wt.set_root_id(tree.inventory.root.file_id)
970
926
tt = TreeTransform(wt)
974
file_trans_id[wt.get_root_id()] = \
975
tt.trans_id_tree_file_id(wt.get_root_id())
929
file_trans_id[wt.get_root_id()] = tt.trans_id_tree_file_id(wt.get_root_id())
930
file_ids = topology_sorted_ids(tree)
976
931
pb = bzrlib.ui.ui_factory.nested_progress_bar()
978
for num, (tree_path, entry) in \
979
enumerate(tree.inventory.iter_entries_by_dir()):
980
pb.update("Building tree", num, len(tree.inventory))
933
for num, file_id in enumerate(file_ids):
934
pb.update("Building tree", num, len(file_ids))
935
entry = tree.inventory[file_id]
981
936
if entry.parent_id is None:
984
file_id = entry.file_id
985
target_path = wt.abspath(tree_path)
987
kind = file_kind(target_path)
991
if kind == "directory":
993
bzrdir.BzrDir.open(target_path)
994
except errors.NotBranchError:
998
if (file_id not in divert and
999
_content_match(tree, entry, file_id, kind,
1001
tt.delete_contents(tt.trans_id_tree_path(tree_path))
1002
if kind == 'directory':
1004
938
if entry.parent_id not in file_trans_id:
1005
939
raise repr(entry.parent_id)
1006
940
parent_id = file_trans_id[entry.parent_id]
1007
file_trans_id[file_id] = new_by_entry(tt, entry, parent_id,
941
file_trans_id[file_id] = new_by_entry(tt, entry, parent_id,
1010
new_trans_id = file_trans_id[file_id]
1011
old_parent = tt.trans_id_tree_path(tree_path)
1012
_reparent_children(tt, old_parent, new_trans_id)
1016
divert_trans = set(file_trans_id[f] for f in divert)
1017
resolver = lambda t, c: resolve_checkout(t, c, divert_trans)
1018
raw_conflicts = resolve_conflicts(tt, pass_func=resolver)
1019
conflicts = cook_conflicts(raw_conflicts, tt)
1020
for conflict in conflicts:
1023
wt.add_conflicts(conflicts)
1024
except errors.UnsupportedOperation:
1029
949
top_pb.finished()
1032
def _reparent_children(tt, old_parent, new_parent):
1033
for child in tt.iter_tree_children(old_parent):
1034
tt.adjust_path(tt.final_name(child), new_parent, child)
1037
def _content_match(tree, entry, file_id, kind, target_path):
1038
if entry.kind != kind:
1040
if entry.kind == "directory":
1042
if entry.kind == "file":
1043
if tree.get_file(file_id).read() == file(target_path, 'rb').read():
1045
elif entry.kind == "symlink":
1046
if tree.get_symlink_target(file_id) == os.readlink(target_path):
1051
def resolve_checkout(tt, conflicts, divert):
1052
new_conflicts = set()
1053
for c_type, conflict in ((c[0], c) for c in conflicts):
1054
# Anything but a 'duplicate' would indicate programmer error
1055
assert c_type == 'duplicate', c_type
1056
# Now figure out which is new and which is old
1057
if tt.new_contents(conflict[1]):
1058
new_file = conflict[1]
1059
old_file = conflict[2]
1061
new_file = conflict[2]
1062
old_file = conflict[1]
1064
# We should only get here if the conflict wasn't completely
1066
final_parent = tt.final_parent(old_file)
1067
if new_file in divert:
1068
new_name = tt.final_name(old_file)+'.diverted'
1069
tt.adjust_path(new_name, final_parent, new_file)
1070
new_conflicts.add((c_type, 'Diverted to',
1071
new_file, old_file))
1073
new_name = tt.final_name(old_file)+'.moved'
1074
tt.adjust_path(new_name, final_parent, old_file)
1075
new_conflicts.add((c_type, 'Moved existing file to',
1076
old_file, new_file))
1077
return new_conflicts
1080
951
def new_by_entry(tt, entry, parent_id, tree):
1081
952
"""Create a new file according to its inventory entry"""
1082
953
name = entry.name
1238
1126
pp.next_phase()
1239
1127
wt_interesting = [i for i in working_tree.inventory if interesting(i)]
1240
1128
child_pb = bzrlib.ui.ui_factory.nested_progress_bar()
1243
1130
for id_num, file_id in enumerate(wt_interesting):
1244
if (working_tree.inventory.is_root(file_id) and
1245
len(target_tree.inventory) == 0):
1247
1131
child_pb.update("New file check", id_num+1,
1248
1132
len(sorted_interesting))
1249
1133
if file_id not in target_tree:
1250
1134
trans_id = tt.trans_id_tree_file_id(file_id)
1251
1135
tt.unversion_file(trans_id)
1253
file_kind = working_tree.kind(file_id)
1256
delete_merge_modified = (file_id in merge_modified)
1257
if file_kind != 'file' and file_kind is not None:
1258
keep_contents = False
1260
if basis_tree is None:
1261
basis_tree = working_tree.basis_tree()
1262
wt_sha1 = working_tree.get_file_sha1(file_id)
1263
if (file_id in merge_modified and
1264
merge_modified[file_id] == wt_sha1):
1265
keep_contents = False
1266
elif (file_id in basis_tree and
1267
basis_tree.get_file_sha1(file_id) == wt_sha1):
1268
keep_contents = False
1270
keep_contents = True
1271
if not keep_contents:
1136
if file_id in merge_modified:
1272
1137
tt.delete_contents(trans_id)
1273
if delete_merge_modified:
1274
1138
del merge_modified[file_id]
1276
1140
child_pb.finished()