21
21
from bzrlib import bzrdir, errors
22
22
from bzrlib.errors import (DuplicateKey, MalformedTransform, NoSuchFile,
23
23
ReusingTransform, NotVersionedError, CantMoveRoot,
24
ExistingLimbo, ImmortalLimbo)
24
ExistingLimbo, ImmortalLimbo, NoFinalPath)
25
25
from bzrlib.inventory import InventoryEntry
26
26
from bzrlib.osutils import (file_kind, supports_executable, pathjoin, lexists,
954
960
it is silently replaced.
955
961
- Otherwise, conflict resolution will move the old file to 'oldname.moved'.
957
assert 2 > len(wt.inventory)
963
if len(wt.inventory) > 1: # more than just a root
964
raise errors.WorkingTreeAlreadyPopulated(base=wt.basedir)
958
965
file_trans_id = {}
959
966
top_pb = bzrlib.ui.ui_factory.nested_progress_bar()
960
967
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)
961
970
tt = TreeTransform(wt)
1149
1158
def get_backup_name(entry, by_parent, parent_trans_id, tt):
1159
return _get_backup_name(entry.name, by_parent, parent_trans_id, tt)
1162
def _get_backup_name(name, by_parent, parent_trans_id, tt):
1150
1163
"""Produce a backup-style name that appears to be available"""
1151
1164
def name_gen():
1154
yield "%s.~%d~" % (entry.name, counter)
1167
yield "%s.~%d~" % (name, counter)
1156
for name in name_gen():
1157
if not tt.has_named_child(by_parent, parent_trans_id, name):
1169
for new_name in name_gen():
1170
if not tt.has_named_child(by_parent, parent_trans_id, new_name):
1160
1174
def _entry_changes(file_id, entry, working_tree):
1161
1175
"""Determine in which ways the inventory entry has changed.
1188
1202
pb=DummyProgress()):
1189
1203
"""Revert a working tree's contents to those of a target tree."""
1190
1204
interesting_ids = find_interesting(working_tree, target_tree, filenames)
1191
def interesting(file_id):
1192
return interesting_ids is None or (file_id in interesting_ids)
1194
1205
tt = TreeTransform(working_tree, pb)
1196
merge_modified = working_tree.merge_modified()
1198
def trans_id_file_id(file_id):
1200
return trans_id[file_id]
1202
return tt.trans_id_tree_file_id(file_id)
1204
pp = ProgressPhase("Revert phase", 4, pb)
1206
sorted_interesting = [i for i in topology_sorted_ids(target_tree) if
1208
child_pb = bzrlib.ui.ui_factory.nested_progress_bar()
1210
by_parent = tt.by_parent()
1211
for id_num, file_id in enumerate(sorted_interesting):
1212
child_pb.update("Reverting file", id_num+1,
1213
len(sorted_interesting))
1214
if file_id not in working_tree.inventory:
1215
entry = target_tree.inventory[file_id]
1216
parent_id = trans_id_file_id(entry.parent_id)
1217
e_trans_id = new_by_entry(tt, entry, parent_id, target_tree)
1218
trans_id[file_id] = e_trans_id
1220
backup_this = backups
1221
if file_id in merge_modified:
1223
del merge_modified[file_id]
1224
change_entry(tt, file_id, working_tree, target_tree,
1225
trans_id_file_id, backup_this, trans_id,
1230
wt_interesting = [i for i in working_tree.inventory if interesting(i)]
1231
child_pb = bzrlib.ui.ui_factory.nested_progress_bar()
1234
for id_num, file_id in enumerate(wt_interesting):
1235
child_pb.update("New file check", id_num+1,
1236
len(sorted_interesting))
1237
if file_id not in target_tree:
1238
trans_id = tt.trans_id_tree_file_id(file_id)
1239
tt.unversion_file(trans_id)
1241
file_kind = working_tree.kind(file_id)
1244
delete_merge_modified = (file_id in merge_modified)
1245
if file_kind != 'file' and file_kind is not None:
1246
keep_contents = False
1248
if basis_tree is None:
1249
basis_tree = working_tree.basis_tree()
1250
wt_sha1 = working_tree.get_file_sha1(file_id)
1251
if (file_id in merge_modified and
1252
merge_modified[file_id] == wt_sha1):
1253
keep_contents = False
1254
elif (file_id in basis_tree and
1255
basis_tree.get_file_sha1(file_id) == wt_sha1):
1256
keep_contents = False
1258
keep_contents = True
1259
if not keep_contents:
1260
tt.delete_contents(trans_id)
1261
if delete_merge_modified:
1262
del merge_modified[file_id]
1207
pp = ProgressPhase("Revert phase", 3, pb)
1209
child_pb = bzrlib.ui.ui_factory.nested_progress_bar()
1211
_alter_files(working_tree, target_tree, tt, child_pb,
1212
interesting_ids, backups)
1264
1214
child_pb.finished()
1265
1215
pp.next_phase()
1280
1230
return conflicts
1233
def _alter_files(working_tree, target_tree, tt, pb, interesting_ids, backups):
1234
merge_modified = working_tree.merge_modified()
1235
iterator = target_tree._iter_changes(working_tree,
1236
specific_file_ids=interesting_ids,
1238
if target_tree.inventory.root is None:
1243
for id_num, (file_id, path, changed_content, versioned, parent, name, kind,
1244
executable) in enumerate(iterator):
1245
if skip_root and file_id[0] is not None and parent[0] is None:
1247
trans_id = tt.trans_id_file_id(file_id)
1250
keep_content = False
1251
if kind[0] == 'file' and (backups or kind[1] is None):
1252
wt_sha1 = working_tree.get_file_sha1(file_id)
1253
if merge_modified.get(file_id) != wt_sha1:
1254
if basis_tree is None:
1255
basis_tree = working_tree.basis_tree()
1256
if file_id in basis_tree:
1257
if wt_sha1 != basis_tree.get_file_sha1(file_id):
1259
elif kind[1] is None and not versioned[1]:
1261
if kind[0] is not None:
1262
if not keep_content:
1263
tt.delete_contents(trans_id)
1264
elif kind[1] is not None:
1265
parent_trans_id = tt.trans_id_file_id(parent[0])
1266
by_parent = tt.by_parent()
1267
backup_name = _get_backup_name(name[0], by_parent,
1268
parent_trans_id, tt)
1269
tt.adjust_path(backup_name, parent_trans_id, trans_id)
1270
new_trans_id = tt.create_path(name[0], parent_trans_id)
1271
if versioned == (True, True):
1272
tt.unversion_file(trans_id)
1273
tt.version_file(file_id, new_trans_id)
1274
# New contents should have the same unix perms as old
1277
trans_id = new_trans_id
1278
if kind[1] == 'directory':
1279
tt.create_directory(trans_id)
1280
elif kind[1] == 'symlink':
1281
tt.create_symlink(target_tree.get_symlink_target(file_id),
1283
elif kind[1] == 'file':
1284
tt.create_file(target_tree.get_file_lines(file_id),
1286
# preserve the execute bit when backing up
1287
if keep_content and executable[0] == executable[1]:
1288
tt.set_executability(executable[1], trans_id)
1290
assert kind[1] is None
1291
if versioned == (False, True):
1292
tt.version_file(file_id, trans_id)
1293
if versioned == (True, False):
1294
tt.unversion_file(trans_id)
1295
if (name[1] is not None and
1296
(name[0] != name[1] or parent[0] != parent[1])):
1297
tt.adjust_path(name[1], tt.trans_id_file_id(parent[1]), trans_id)
1298
if executable[0] != executable[1] and kind[1] == "file":
1299
tt.set_executability(executable[1], trans_id)
1283
1302
def resolve_conflicts(tt, pb=DummyProgress(), pass_func=None):
1284
1303
"""Make many conflict-resolution attempts, but die if they fail"""
1285
1304
if pass_func is None: