472
472
if filesystem_only:
473
id_sets = (self._needs_rename, self._new_executability)
473
stale_ids = self._needs_rename.difference(self._new_name)
474
stale_ids.difference_update(self._new_parent)
475
stale_ids.difference_update(self._new_contents)
476
stale_ids.difference_update(self._new_id)
477
needs_rename = self._needs_rename.difference(stale_ids)
478
id_sets = (needs_rename, self._new_executability)
475
480
id_sets = (self._new_name, self._new_parent, self._new_contents,
476
481
self._new_id, self._new_executability)
478
483
new_ids.update(id_set)
479
484
return sorted(FinalPaths(self).get_paths(new_ids))
486
def _inventory_altered(self):
487
"""Get the trans_ids and paths of files needing new inv entries."""
489
for id_set in [self._new_name, self._new_parent, self._new_id,
490
self._new_executability]:
491
new_ids.update(id_set)
492
changed_kind = set(self._removed_contents)
493
changed_kind.intersection_update(self._new_contents)
494
changed_kind.difference_update(new_ids)
495
changed_kind = (t for t in changed_kind if self.tree_kind(t) !=
497
new_ids.update(changed_kind)
498
return sorted(FinalPaths(self).get_paths(new_ids))
481
500
def tree_kind(self, trans_id):
482
501
"""Determine the file kind in the working tree.
870
889
self._limbo_files[trans_id] = limbo_name
871
890
return limbo_name
873
def _set_executability(self, path, entry, trans_id):
892
def _set_executability(self, path, trans_id):
874
893
"""Set the executability of versioned files """
875
new_executability = self._new_executability[trans_id]
876
if entry is not None:
877
entry.executable = new_executability
878
894
if supports_executable():
895
new_executability = self._new_executability[trans_id]
879
896
abspath = self._tree.abspath(path)
880
897
current_mode = os.stat(abspath).st_mode
881
898
if new_executability:
1203
1220
conflicts = self.find_conflicts()
1204
1221
if len(conflicts) != 0:
1205
1222
raise MalformedTransform(conflicts=conflicts)
1206
if precomputed_delta is None:
1207
new_inventory_delta = []
1208
inventory_delta = new_inventory_delta
1210
new_inventory_delta = None
1211
inventory_delta = precomputed_delta
1212
1223
child_pb = bzrlib.ui.ui_factory.nested_progress_bar()
1225
if precomputed_delta is None:
1226
child_pb.update('Apply phase', 0, 2)
1227
inventory_delta = self._generate_inventory_delta()
1230
inventory_delta = precomputed_delta
1214
1232
if _mover is None:
1215
1233
mover = _FileMover()
1219
child_pb.update('Apply phase', 0, 2)
1220
kind_changes = self._apply_removals(new_inventory_delta, mover)
1221
child_pb.update('Apply phase', 1, 2)
1222
modified_paths = self._apply_insertions(new_inventory_delta,
1223
mover, kind_changes)
1237
child_pb.update('Apply phase', 0 + offset, 2 + offset)
1238
self._apply_removals(mover)
1239
child_pb.update('Apply phase', 1 + offset, 2 + offset)
1240
modified_paths = self._apply_insertions(mover)
1225
1242
mover.rollback()
1233
1250
self.finalize()
1234
1251
return _TransformResults(modified_paths, self.rename_count)
1236
def _apply_removals(self, inventory_delta, mover):
1253
def _generate_inventory_delta(self):
1254
"""Generate an inventory delta for the current transform."""
1255
inventory_delta = []
1256
child_pb = bzrlib.ui.ui_factory.nested_progress_bar()
1257
new_paths = self._inventory_altered()
1258
total_entries = len(new_paths) + len(self._removed_id)
1260
for num, trans_id in enumerate(self._removed_id):
1262
child_pb.update('removing file', num, total_entries)
1263
if trans_id == self._new_root:
1264
file_id = self._tree.get_root_id()
1266
file_id = self.tree_file_id(trans_id)
1267
# File-id isn't really being deleted, just moved
1268
if file_id in self._r_new_id:
1270
path = self._tree_id_paths[trans_id]
1271
inventory_delta.append((path, None, file_id, None))
1272
new_path_file_ids = dict((t, self.final_file_id(t)) for p, t in
1274
entries = self._tree.iter_entries_by_dir(
1275
new_path_file_ids.values())
1276
old_paths = dict((e.file_id, p) for p, e in entries)
1278
for num, (path, trans_id) in enumerate(new_paths):
1280
child_pb.update('adding file',
1281
num + len(self._removed_id), total_entries)
1282
file_id = new_path_file_ids[trans_id]
1287
kind = self.final_kind(trans_id)
1289
kind = self._tree.stored_kind(file_id)
1290
parent_trans_id = self.final_parent(trans_id)
1291
parent_file_id = new_path_file_ids.get(parent_trans_id)
1292
if parent_file_id is None:
1293
parent_file_id = self.final_file_id(parent_trans_id)
1294
if trans_id in self._new_reference_revision:
1295
new_entry = inventory.TreeReference(
1297
self._new_name[trans_id],
1298
self.final_file_id(self._new_parent[trans_id]),
1299
None, self._new_reference_revision[trans_id])
1301
new_entry = inventory.make_entry(kind,
1302
self.final_name(trans_id),
1303
parent_file_id, file_id)
1304
old_path = old_paths.get(new_entry.file_id)
1305
new_executability = self._new_executability.get(trans_id)
1306
if new_executability is not None:
1307
new_entry.executable = new_executability
1308
inventory_delta.append(
1309
(old_path, path, new_entry.file_id, new_entry))
1312
return inventory_delta
1314
def _apply_removals(self, mover):
1237
1315
"""Perform tree operations that remove directory/inventory names.
1239
1317
That is, delete files that are to be deleted, and put any files that
1252
1330
child_pb.update('removing file', num, len(tree_paths))
1253
1331
full_path = self._tree.abspath(path)
1254
1332
if trans_id in self._removed_contents:
1256
if (self.tree_kind(trans_id)
1257
!= self.final_kind(trans_id)):
1258
kind_changes.add(trans_id)
1261
1333
mover.pre_delete(full_path, os.path.join(self._deletiondir,
1263
1335
elif trans_id in self._new_name or trans_id in \
1271
1343
self.rename_count += 1
1272
if (trans_id in self._removed_id
1273
and inventory_delta is not None):
1274
if trans_id == self._new_root:
1275
file_id = self._tree.get_root_id()
1277
file_id = self.tree_file_id(trans_id)
1278
# File-id isn't really being deleted, just moved
1279
if file_id in self._r_new_id:
1281
inventory_delta.append((path, None, file_id, None))
1283
1345
child_pb.finished()
1284
1346
return kind_changes
1286
def _apply_insertions(self, inventory_delta, mover, kind_changes):
1348
def _apply_insertions(self, mover):
1287
1349
"""Perform tree operations that insert directory/inventory names.
1289
1351
That is, create any files that need to be created, and restore from
1296
1358
kind_changes is a set of trans ids where the entry has changed
1297
1359
kind, and so an inventory delta entry should be created for them.
1299
new_paths = self.new_paths(filesystem_only=(inventory_delta is None))
1361
new_paths = self.new_paths(filesystem_only=True)
1300
1362
modified_paths = []
1302
1363
new_path_file_ids = dict((t, self.final_file_id(t)) for p, t in
1304
if inventory_delta is not None:
1305
entries = self._tree.iter_entries_by_dir(
1306
new_path_file_ids.values())
1307
old_paths = dict((e.file_id, p) for p, e in entries)
1308
1365
child_pb = bzrlib.ui.ui_factory.nested_progress_bar()
1310
1367
for num, (path, trans_id) in enumerate(new_paths):
1312
1368
if (num % 10) == 0:
1313
1369
child_pb.update('adding file', num, len(new_paths))
1314
1370
full_path = self._tree.abspath(path)
1323
1379
self.rename_count += 1
1324
if inventory_delta is not None:
1325
if (trans_id in self._new_contents or
1326
self.path_changed(trans_id)):
1327
if trans_id in self._new_contents:
1328
modified_paths.append(full_path)
1329
completed_new.append(trans_id)
1330
file_id = new_path_file_ids[trans_id]
1331
if file_id is not None and (trans_id in self._new_id or
1332
trans_id in self._new_name or
1333
trans_id in self._new_parent
1334
or trans_id in self._new_executability
1335
or trans_id in kind_changes):
1337
kind = self.final_kind(trans_id)
1339
kind = self._tree.stored_kind(file_id)
1340
parent_trans_id = self.final_parent(trans_id)
1341
parent_file_id = new_path_file_ids.get(parent_trans_id)
1342
if parent_file_id is None:
1343
parent_file_id = self.final_file_id(
1345
if trans_id in self._new_reference_revision:
1346
new_entry = inventory.TreeReference(
1348
self._new_name[trans_id],
1349
self.final_file_id(self._new_parent[trans_id]),
1350
None, self._new_reference_revision[trans_id])
1352
new_entry = inventory.make_entry(kind,
1353
self.final_name(trans_id),
1354
parent_file_id, file_id)
1355
old_path = old_paths.get(new_entry.file_id)
1356
inventory_delta.append(
1357
(old_path, path, new_entry.file_id, new_entry))
1380
if (trans_id in self._new_contents or
1381
self.path_changed(trans_id)):
1382
if trans_id in self._new_contents:
1383
modified_paths.append(full_path)
1359
1384
if trans_id in self._new_executability:
1360
self._set_executability(path, new_entry, trans_id)
1385
self._set_executability(path, trans_id)
1362
1387
child_pb.finished()
1363
if inventory_delta is None:
1364
self._new_contents.clear()
1366
for trans_id in completed_new:
1367
del self._new_contents[trans_id]
1388
self._new_contents.clear()
1368
1389
return modified_paths