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
959
it is silently replaced.
955
960
- Otherwise, conflict resolution will move the old file to 'oldname.moved'.
957
assert 2 > len(wt.inventory)
962
if len(wt.inventory) > 1: # more than just a root
963
raise errors.WorkingTreeAlreadyPopulated(base=wt.basedir)
958
964
file_trans_id = {}
959
965
top_pb = bzrlib.ui.ui_factory.nested_progress_bar()
960
966
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)
961
969
tt = TreeTransform(wt)
1149
1157
def get_backup_name(entry, by_parent, parent_trans_id, tt):
1158
return _get_backup_name(entry.name, by_parent, parent_trans_id, tt)
1161
def _get_backup_name(name, by_parent, parent_trans_id, tt):
1150
1162
"""Produce a backup-style name that appears to be available"""
1151
1163
def name_gen():
1154
yield "%s.~%d~" % (entry.name, counter)
1166
yield "%s.~%d~" % (name, counter)
1156
for name in name_gen():
1157
if not tt.has_named_child(by_parent, parent_trans_id, name):
1168
for new_name in name_gen():
1169
if not tt.has_named_child(by_parent, parent_trans_id, new_name):
1160
1173
def _entry_changes(file_id, entry, working_tree):
1161
1174
"""Determine in which ways the inventory entry has changed.
1187
1200
def revert(working_tree, target_tree, filenames, backups=False,
1188
pb=DummyProgress()):
1201
pb=DummyProgress(), change_reporter=None):
1189
1202
"""Revert a working tree's contents to those of a target tree."""
1190
1203
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
1204
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]
1206
pp = ProgressPhase("Revert phase", 3, pb)
1208
child_pb = bzrlib.ui.ui_factory.nested_progress_bar()
1210
_alter_files(working_tree, target_tree, tt, child_pb,
1211
interesting_ids, backups, change_reporter)
1264
1213
child_pb.finished()
1265
1214
pp.next_phase()
1280
1229
return conflicts
1232
def _alter_files(working_tree, target_tree, tt, pb, interesting_ids, backups,
1234
from bzrlib import delta
1235
merge_modified = working_tree.merge_modified()
1236
change_list = list(target_tree._iter_changes(working_tree,
1237
specific_file_ids=interesting_ids, pb=pb))
1238
if target_tree.inventory.root is None:
1244
change_reporter = delta.ChangeReporter(working_tree.inventory)
1245
delta.report_changes(change_list, change_reporter)
1246
for id_num, (file_id, path, changed_content, versioned, parent, name, kind,
1247
executable) in enumerate(change_list):
1248
if skip_root and file_id[0] is not None and parent[0] is None:
1250
trans_id = tt.trans_id_file_id(file_id)
1253
keep_content = False
1254
if kind[0] == 'file' and (backups or kind[1] is None):
1255
wt_sha1 = working_tree.get_file_sha1(file_id)
1256
if merge_modified.get(file_id) != wt_sha1:
1257
if basis_tree is None:
1258
basis_tree = working_tree.basis_tree()
1259
if file_id in basis_tree:
1260
if wt_sha1 != basis_tree.get_file_sha1(file_id):
1262
elif kind[1] is None and not versioned[1]:
1264
if kind[0] is not None:
1265
if not keep_content:
1266
tt.delete_contents(trans_id)
1267
elif kind[1] is not None:
1268
parent_trans_id = tt.trans_id_file_id(parent[0])
1269
by_parent = tt.by_parent()
1270
backup_name = _get_backup_name(name[0], by_parent,
1271
parent_trans_id, tt)
1272
tt.adjust_path(backup_name, parent_trans_id, trans_id)
1273
new_trans_id = tt.create_path(name[0], parent_trans_id)
1274
if versioned == (True, True):
1275
tt.unversion_file(trans_id)
1276
tt.version_file(file_id, new_trans_id)
1277
# New contents should have the same unix perms as old
1280
trans_id = new_trans_id
1281
if kind[1] == 'directory':
1282
tt.create_directory(trans_id)
1283
elif kind[1] == 'symlink':
1284
tt.create_symlink(target_tree.get_symlink_target(file_id),
1286
elif kind[1] == 'file':
1287
tt.create_file(target_tree.get_file_lines(file_id),
1289
# preserve the execute bit when backing up
1290
if keep_content and executable[0] == executable[1]:
1291
tt.set_executability(executable[1], trans_id)
1293
assert kind[1] is None
1294
if versioned == (False, True):
1295
tt.version_file(file_id, trans_id)
1296
if versioned == (True, False):
1297
tt.unversion_file(trans_id)
1298
if (name[1] is not None and
1299
(name[0] != name[1] or parent[0] != parent[1])):
1300
tt.adjust_path(name[1], tt.trans_id_file_id(parent[1]), trans_id)
1301
if executable[0] != executable[1] and kind[1] == "file":
1302
tt.set_executability(executable[1], trans_id)
1283
1305
def resolve_conflicts(tt, pb=DummyProgress(), pass_func=None):
1284
1306
"""Make many conflict-resolution attempts, but die if they fail"""
1285
1307
if pass_func is None: