250
250
This reflects only files that already exist, not ones that will be
251
251
added by transactions.
253
path = self._tree.inventory.id2path(inventory_id)
253
path = self._tree.id2path(inventory_id)
254
254
return self.trans_id_tree_path(path)
256
256
def trans_id_file_id(self, file_id):
354
354
if typefunc(mode):
355
355
os.chmod(self._limbo_name(trans_id), mode)
357
def create_hardlink(self, path, trans_id):
358
"""Schedule creation of a hard link"""
359
name = self._limbo_name(trans_id)
363
if e.errno != errno.EPERM:
365
raise errors.HardLinkNotSupported(path)
367
unique_add(self._new_contents, trans_id, 'file')
369
# Clean up the file, it never got registered so
370
# TreeTransform.finalize() won't clean it up.
357
374
def create_directory(self, trans_id):
358
375
"""Schedule creation of a new directory.
754
771
removed_tree_ids = set((self.tree_file_id(trans_id) for trans_id in
755
772
self._removed_id))
756
active_tree_ids = set((f for f in self._tree.inventory if
757
f not in removed_tree_ids))
773
all_ids = self._tree.all_file_ids()
774
active_tree_ids = all_ids.difference(removed_tree_ids)
758
775
for trans_id, file_id in self._new_id.iteritems():
759
776
if file_id in active_tree_ids:
760
777
old_trans_id = self.trans_id_tree_file_id(file_id)
985
1002
to_executable = False
986
1003
return to_name, to_parent, to_kind, to_executable
988
def _iter_changes(self):
989
"""Produce output in the same format as Tree._iter_changes.
1005
def iter_changes(self):
1006
"""Produce output in the same format as Tree.iter_changes.
991
1008
Will produce nonsensical results if invoked while inventory/filesystem
992
1009
conflicts (as reported by TreeTransform.find_conflicts()) are present.
1181
1197
child_pb.update('Apply phase', 0, 2)
1182
self._apply_removals(inv, inventory_delta, mover)
1198
self._apply_removals(inventory_delta, mover)
1183
1199
child_pb.update('Apply phase', 1, 2)
1184
modified_paths = self._apply_insertions(inv, inventory_delta,
1200
modified_paths = self._apply_insertions(inventory_delta, mover)
1187
1202
mover.rollback()
1195
1210
self.finalize()
1196
1211
return _TransformResults(modified_paths, self.rename_count)
1198
def _apply_removals(self, inv, inventory_delta, mover):
1213
def _apply_removals(self, inventory_delta, mover):
1199
1214
"""Perform tree operations that remove directory/inventory names.
1201
1216
That is, delete files that are to be deleted, and put any files that
1227
1242
file_id = self._tree.get_root_id()
1229
1244
file_id = self.tree_file_id(trans_id)
1230
if file_id is not None:
1231
inventory_delta.append((path, None, file_id, None))
1245
assert file_id is not None
1246
# File-id isn't really being deleted, just moved
1247
if file_id in self._r_new_id:
1249
inventory_delta.append((path, None, file_id, None))
1233
1251
child_pb.finished()
1235
def _apply_insertions(self, inv, inventory_delta, mover):
1253
def _apply_insertions(self, inventory_delta, mover):
1236
1254
"""Perform tree operations that insert directory/inventory names.
1238
1256
That is, create any files that need to be created, and restore from
1247
1265
for num, (path, trans_id) in enumerate(new_paths):
1248
1266
new_entry = None
1249
1267
child_pb.update('adding file', num, len(new_paths))
1251
kind = self._new_contents[trans_id]
1253
kind = contents = None
1254
1268
if trans_id in self._new_contents or \
1255
1269
self.path_changed(trans_id):
1256
1270
full_path = self._tree.abspath(path)
1266
1280
if trans_id in self._new_contents:
1267
1281
modified_paths.append(full_path)
1268
1282
completed_new.append(trans_id)
1270
if trans_id in self._new_id:
1272
kind = file_kind(self._tree.abspath(path))
1283
file_id = self.final_file_id(trans_id)
1284
if file_id is not None and (trans_id in self._new_id or
1285
trans_id in self._new_name or trans_id in self._new_parent
1286
or trans_id in self._new_executability):
1288
kind = self.final_kind(trans_id)
1290
kind = self._tree.stored_kind(file_id)
1273
1291
if trans_id in self._new_reference_revision:
1274
1292
new_entry = inventory.TreeReference(
1275
self._new_id[trans_id],
1293
self.final_file_id(trans_id),
1276
1294
self._new_name[trans_id],
1277
1295
self.final_file_id(self._new_parent[trans_id]),
1278
1296
None, self._new_reference_revision[trans_id])
1280
1298
new_entry = inventory.make_entry(kind,
1281
1299
self.final_name(trans_id),
1282
1300
self.final_file_id(self.final_parent(trans_id)),
1283
self._new_id[trans_id])
1285
if trans_id in self._new_name or trans_id in\
1286
self._new_parent or\
1287
trans_id in self._new_executability:
1288
file_id = self.final_file_id(trans_id)
1289
if file_id is not None:
1290
entry = inv[file_id]
1291
new_entry = entry.copy()
1293
if trans_id in self._new_name or trans_id in\
1295
if new_entry is not None:
1296
new_entry.name = self.final_name(trans_id)
1297
parent = self.final_parent(trans_id)
1298
parent_id = self.final_file_id(parent)
1299
new_entry.parent_id = parent_id
1301
self.final_file_id(trans_id))
1303
old_path = self._tree.id2path(new_entry.file_id)
1304
except errors.NoSuchId:
1306
inventory_delta.append((old_path, path, new_entry.file_id,
1301
1309
if trans_id in self._new_executability:
1302
1310
self._set_executability(path, new_entry, trans_id)
1303
if new_entry is not None:
1304
if new_entry.file_id in inv:
1305
old_path = inv.id2path(new_entry.file_id)
1308
inventory_delta.append((old_path, path,
1312
1312
child_pb.finished()
1313
1313
for trans_id in completed_new:
1372
1372
def unlock(self):
1375
def _iter_changes(self, from_tree, include_unchanged=False,
1375
def iter_changes(self, from_tree, include_unchanged=False,
1376
1376
specific_files=None, pb=None, extra_trees=None,
1377
1377
require_versioned=True, want_unversioned=False):
1378
"""See InterTree._iter_changes.
1378
"""See InterTree.iter_changes.
1380
1380
This implementation does not support include_unchanged, specific_files,
1381
1381
or want_unversioned. extra_trees, require_versioned, and pb are
1407
1407
name = self._transform._limbo_name(trans_id)
1408
1408
return open(name, 'rb')
1410
def get_symlink_target(self, file_id):
1411
"""See Tree.get_symlink_target"""
1412
trans_id = self._transform.trans_id_file_id(file_id)
1413
name = self._transform._limbo_name(trans_id)
1414
return os.readlink(name)
1410
1416
def paths2ids(self, specific_files, trees=None, require_versioned=False):
1411
1417
"""See Tree.paths2ids"""
1412
1418
return 'not_empty'
1455
1461
return file_ids
1458
def build_tree(tree, wt, accelerator_tree=None):
1464
def build_tree(tree, wt, accelerator_tree=None, hardlink=False):
1459
1465
"""Create working tree for a branch, using a TreeTransform.
1461
1467
This function should be used on empty trees, having a tree root at most.
1474
1480
:param accelerator_tree: A tree which can be used for retrieving file
1475
1481
contents more quickly than tree itself, i.e. a workingtree. tree
1476
1482
will be used for cases where accelerator_tree's content is different.
1483
:param hardlink: If true, hard-link files to accelerator_tree, where
1484
possible. accelerator_tree must implement abspath, i.e. be a
1478
1487
wt.lock_tree_write()
1482
1491
if accelerator_tree is not None:
1483
1492
accelerator_tree.lock_read()
1485
return _build_tree(tree, wt, accelerator_tree)
1494
return _build_tree(tree, wt, accelerator_tree, hardlink)
1487
1496
if accelerator_tree is not None:
1488
1497
accelerator_tree.unlock()
1495
def _build_tree(tree, wt, accelerator_tree):
1504
def _build_tree(tree, wt, accelerator_tree, hardlink):
1496
1505
"""See build_tree."""
1497
if len(wt.inventory) > 1: # more than just a root
1498
raise errors.WorkingTreeAlreadyPopulated(base=wt.basedir)
1506
for num, _unused in enumerate(wt.all_file_ids()):
1507
if num > 0: # more than just a root
1508
raise errors.WorkingTreeAlreadyPopulated(base=wt.basedir)
1499
1509
file_trans_id = {}
1500
1510
top_pb = bzrlib.ui.ui_factory.nested_progress_bar()
1501
1511
pp = ProgressPhase("Build phase", 2, top_pb)
1519
1529
pb = bzrlib.ui.ui_factory.nested_progress_bar()
1521
1531
deferred_contents = []
1522
1533
for num, (tree_path, entry) in \
1523
1534
enumerate(tree.inventory.iter_entries_by_dir()):
1524
1535
pb.update("Building tree", num - len(deferred_contents),
1568
1579
new_trans_id = file_trans_id[file_id]
1569
1580
old_parent = tt.trans_id_tree_path(tree_path)
1570
1581
_reparent_children(tt, old_parent, new_trans_id)
1571
for num, (trans_id, bytes) in enumerate(
1572
_iter_files_bytes_accelerated(tree, accelerator_tree,
1573
deferred_contents)):
1574
tt.create_file(bytes, trans_id)
1575
pb.update('Adding file contents',
1576
(num + len(tree.inventory) - len(deferred_contents)),
1577
len(tree.inventory))
1582
offset = num + 1 - len(deferred_contents)
1583
_create_files(tt, tree, deferred_contents, pb, offset,
1584
accelerator_tree, hardlink)
1580
1587
pp.next_phase()
1598
def _iter_files_bytes_accelerated(tree, accelerator_tree, desired_files):
1605
def _create_files(tt, tree, desired_files, pb, offset, accelerator_tree,
1607
total = len(desired_files) + offset
1599
1608
if accelerator_tree is None:
1600
1609
new_desired_files = desired_files
1602
iter = accelerator_tree._iter_changes(tree, include_unchanged=True)
1611
iter = accelerator_tree.iter_changes(tree, include_unchanged=True)
1603
1612
unchanged = dict((f, p[1]) for (f, p, c, v, d, n, k, e)
1613
in iter if not (c or e[0] != e[1]))
1605
1614
new_desired_files = []
1606
for file_id, identifier in desired_files:
1616
for file_id, trans_id in desired_files:
1607
1617
accelerator_path = unchanged.get(file_id)
1608
1618
if accelerator_path is None:
1609
new_desired_files.append((file_id, identifier))
1619
new_desired_files.append((file_id, trans_id))
1611
contents = accelerator_tree.get_file(file_id, accelerator_path)
1614
contents_bytes = (contents.read(),)
1617
yield identifier, contents_bytes
1618
for result in tree.iter_files_bytes(new_desired_files):
1621
pb.update('Adding file contents', count + offset, total)
1623
tt.create_hardlink(accelerator_tree.abspath(accelerator_path),
1626
contents = accelerator_tree.get_file(file_id, accelerator_path)
1628
tt.create_file(contents, trans_id)
1633
for count, (trans_id, contents) in enumerate(tree.iter_files_bytes(
1634
new_desired_files)):
1635
tt.create_file(contents, trans_id)
1636
pb.update('Adding file contents', count + offset, total)
1622
1639
def _reparent_children(tt, old_parent, new_parent):
1839
1856
if change_reporter:
1840
1857
change_reporter = delta._ChangeReporter(
1841
1858
unversioned_filter=working_tree.is_ignored)
1842
delta.report_changes(tt._iter_changes(), change_reporter)
1859
delta.report_changes(tt.iter_changes(), change_reporter)
1843
1860
for conflict in conflicts:
1844
1861
warning(conflict)
1845
1862
pp.next_phase()
1855
1872
def _alter_files(working_tree, target_tree, tt, pb, specific_files,
1857
1874
merge_modified = working_tree.merge_modified()
1858
change_list = target_tree._iter_changes(working_tree,
1875
change_list = target_tree.iter_changes(working_tree,
1859
1876
specific_files=specific_files, pb=pb)
1860
1877
if target_tree.inventory.root is None:
1861
1878
skip_root = True
2023
2040
new_parent_id = tt.new_directory(parent_name + '.new',
2024
2041
parent_parent, parent_file_id)
2025
2042
_reparent_transform_children(tt, parent_id, new_parent_id)
2026
tt.unversion_file(parent_id)
2043
if parent_file_id is not None:
2044
tt.unversion_file(parent_id)
2027
2045
new_conflicts.add((c_type, 'Created directory', new_parent_id))
2028
2046
return new_conflicts