450
450
del self._new_id[trans_id]
451
451
del self._r_new_id[file_id]
454
"""Determine the paths of all new and changed files"""
453
def new_paths(self, filesystem_only=False):
454
"""Determine the paths of all new and changed files.
456
:param filesystem_only: if True, only calculate values for files
457
that require renames or execute bit changes.
456
fp = FinalPaths(self)
457
for id_set in (self._new_name, self._new_parent, self._new_contents,
458
self._new_id, self._new_executability):
461
id_sets = (self._needs_rename, self._new_executability)
463
id_sets = (self._new_name, self._new_parent, self._new_contents,
464
self._new_id, self._new_executability)
465
for id_set in id_sets:
459
466
new_ids.update(id_set)
460
new_paths = [(fp.get_path(t), t) for t in new_ids]
467
return sorted(FinalPaths(self).get_paths(new_ids))
464
469
def tree_kind(self, trans_id):
465
470
"""Determine the file kind in the working tree.
1256
1269
That is, create any files that need to be created, and restore from
1257
1270
limbo any files that needed renaming. This must be done in strict
1258
1271
parent-to-child order.
1273
If inventory_delta is None, no inventory delta is calculated, and
1274
no list of modified paths is returned.
1260
new_paths = self.new_paths()
1276
new_paths = self.new_paths(filesystem_only=(inventory_delta is None))
1261
1277
modified_paths = []
1262
child_pb = bzrlib.ui.ui_factory.nested_progress_bar()
1263
1278
completed_new = []
1279
new_path_file_ids = dict((t, self.final_file_id(t)) for p, t in
1281
if inventory_delta is not None:
1282
entries = self._tree.iter_entries_by_dir(
1283
new_path_file_ids.values())
1284
old_paths = dict((e.file_id, p) for p, e in entries)
1285
child_pb = bzrlib.ui.ui_factory.nested_progress_bar()
1265
1287
for num, (path, trans_id) in enumerate(new_paths):
1266
1288
new_entry = None
1267
child_pb.update('adding file', num, len(new_paths))
1268
if trans_id in self._new_contents or \
1269
self.path_changed(trans_id):
1270
full_path = self._tree.abspath(path)
1271
if trans_id in self._needs_rename:
1290
child_pb.update('adding file', num, len(new_paths))
1291
full_path = self._tree.abspath(path)
1292
if trans_id in self._needs_rename:
1294
mover.rename(self._limbo_name(trans_id), full_path)
1296
# We may be renaming a dangling inventory id
1297
if e.errno != errno.ENOENT:
1300
self.rename_count += 1
1301
if inventory_delta is not None:
1302
if (trans_id in self._new_contents or
1303
self.path_changed(trans_id)):
1304
if trans_id in self._new_contents:
1305
modified_paths.append(full_path)
1306
completed_new.append(trans_id)
1307
file_id = new_path_file_ids[trans_id]
1308
if file_id is not None and (trans_id in self._new_id or
1309
trans_id in self._new_name or
1310
trans_id in self._new_parent
1311
or trans_id in self._new_executability):
1273
mover.rename(self._limbo_name(trans_id), full_path)
1275
# We may be renaming a dangling inventory id
1276
if e.errno != errno.ENOENT:
1313
kind = self.final_kind(trans_id)
1315
kind = self._tree.stored_kind(file_id)
1316
parent_trans_id = self.final_parent(trans_id)
1317
parent_file_id = new_path_file_ids.get(parent_trans_id)
1318
if parent_file_id is None:
1319
parent_file_id = self.final_file_id(
1321
if trans_id in self._new_reference_revision:
1322
new_entry = inventory.TreeReference(
1324
self._new_name[trans_id],
1325
self.final_file_id(self._new_parent[trans_id]),
1326
None, self._new_reference_revision[trans_id])
1279
self.rename_count += 1
1280
if trans_id in self._new_contents:
1281
modified_paths.append(full_path)
1282
completed_new.append(trans_id)
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)
1291
if trans_id in self._new_reference_revision:
1292
new_entry = inventory.TreeReference(
1293
self.final_file_id(trans_id),
1294
self._new_name[trans_id],
1295
self.final_file_id(self._new_parent[trans_id]),
1296
None, self._new_reference_revision[trans_id])
1298
new_entry = inventory.make_entry(kind,
1299
self.final_name(trans_id),
1300
self.final_file_id(self.final_parent(trans_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,
1328
new_entry = inventory.make_entry(kind,
1329
self.final_name(trans_id),
1330
parent_file_id, file_id)
1331
old_path = old_paths.get(new_entry.file_id)
1332
inventory_delta.append(
1333
(old_path, path, new_entry.file_id, new_entry))
1309
1335
if trans_id in self._new_executability:
1310
1336
self._set_executability(path, new_entry, trans_id)
1312
1338
child_pb.finished()
1313
for trans_id in completed_new:
1314
del self._new_contents[trans_id]
1339
if inventory_delta is None:
1340
self._new_contents.clear()
1342
for trans_id in completed_new:
1343
del self._new_contents[trans_id]
1315
1344
return modified_paths
1359
1388
yield self.trans_id_tree_path(childpath)
1362
class _PreviewTree(object):
1391
class _PreviewTree(tree.Tree):
1363
1392
"""Partial implementation of Tree to support show_diff_trees"""
1365
1394
def __init__(self, transform):
1366
1395
self._transform = transform
1396
self._final_paths = FinalPaths(transform)
1398
def _changes(self, file_id):
1399
for changes in self._transform.iter_changes():
1400
if changes[0] == file_id:
1403
def _content_change(self, file_id):
1404
"""Return True if the content of this file changed"""
1405
changes = self._changes(file_id)
1406
# changes[2] is true if the file content changed. See
1407
# InterTree.iter_changes.
1408
return (changes is not None and changes[2])
1410
def _get_file_revision(self, file_id, vf, tree_revision):
1411
return self._transform._tree._get_file_revision(file_id, vf,
1414
def _stat_limbo_file(self, file_id):
1415
trans_id = self._transform.trans_id_file_id(file_id)
1416
name = self._transform._limbo_name(trans_id)
1417
return os.lstat(name)
1368
1419
def lock_read(self):
1369
1420
# Perhaps in theory, this should lock the TreeTransform?
1372
1423
def unlock(self):
1427
def inventory(self):
1428
"""This Tree does not use inventory as its backing data."""
1429
raise NotImplementedError(_PreviewTree.inventory)
1431
def get_root_id(self):
1432
return self._transform.final_file_id(self._transform.root)
1434
def all_file_ids(self):
1435
return self._transform._tree.all_file_ids()
1438
return iter(self.all_file_ids())
1440
def paths2ids(self, specific_files, trees=None, require_versioned=False):
1441
"""See Tree.paths2ids"""
1442
to_find = set(specific_files)
1444
for (file_id, paths, changed, versioned, parent, name, kind,
1445
executable) in self._transform.iter_changes():
1446
if paths[1] in to_find:
1447
result.append(file_id)
1448
to_find.remove(paths[1])
1449
result.update(self._transform._tree.paths2ids(to_find,
1450
trees=[], require_versioned=require_versioned))
1453
def path2id(self, path):
1454
return self._transform._tree.path2id(path)
1456
def id2path(self, file_id):
1457
trans_id = self._transform.trans_id_file_id(file_id)
1459
return self._final_paths._determine_path(trans_id)
1461
raise errors.NoSuchId(self, file_id)
1463
def iter_entries_by_dir(self, specific_file_ids=None):
1464
return self._transform._tree.iter_entries_by_dir(specific_file_ids)
1466
def kind(self, file_id):
1467
trans_id = self._transform.trans_id_file_id(file_id)
1468
return self._transform.final_kind(trans_id)
1470
def stored_kind(self, file_id):
1471
return self._transform._tree.stored_kind(file_id)
1473
def get_file_mtime(self, file_id, path=None):
1474
"""See Tree.get_file_mtime"""
1475
if not self._content_change(file_id):
1476
return self._transform._tree.get_file_mtime(file_id, path)
1477
return self._stat_limbo_file(file_id).st_mtime
1479
def get_file_size(self, file_id):
1480
"""See Tree.get_file_size"""
1481
if self.kind(file_id) == 'file':
1482
return self._transform._tree.get_file_size(file_id)
1486
def get_file_sha1(self, file_id, path=None, stat_value=None):
1487
return self._transform._tree.get_file_sha1(file_id)
1489
def is_executable(self, file_id, path=None):
1490
return self._transform._tree.is_executable(file_id, path)
1492
def path_content_summary(self, path):
1493
return self._transform._tree.path_content_summary(path)
1375
1495
def iter_changes(self, from_tree, include_unchanged=False,
1376
1496
specific_files=None, pb=None, extra_trees=None,
1377
1497
require_versioned=True, want_unversioned=False):
1391
1511
raise ValueError('want_unversioned is not supported')
1392
1512
return self._transform.iter_changes()
1394
def kind(self, file_id):
1395
trans_id = self._transform.trans_id_file_id(file_id)
1396
return self._transform.final_kind(trans_id)
1398
def get_file_mtime(self, file_id, path=None):
1399
"""See Tree.get_file_mtime"""
1400
trans_id = self._transform.trans_id_file_id(file_id)
1401
name = self._transform._limbo_name(trans_id)
1402
return os.stat(name).st_mtime
1404
def get_file(self, file_id):
1514
def get_file(self, file_id, path=None):
1405
1515
"""See Tree.get_file"""
1516
if not self._content_change(file_id):
1517
return self._transform._tree.get_file(file_id, path)
1406
1518
trans_id = self._transform.trans_id_file_id(file_id)
1407
1519
name = self._transform._limbo_name(trans_id)
1408
1520
return open(name, 'rb')
1522
def get_file_text(self, file_id):
1523
text_file = self.get_file(file_id)
1525
return text_file.read()
1529
def annotate_iter(self, file_id,
1530
default_revision=_mod_revision.CURRENT_REVISION):
1531
return self._transform._tree.annotate_iter(file_id,
1532
default_revision=default_revision)
1410
1534
def get_symlink_target(self, file_id):
1411
1535
"""See Tree.get_symlink_target"""
1536
if not self._content_change(file_id):
1537
return self._transform._tree.get_symlink_target(file_id)
1412
1538
trans_id = self._transform.trans_id_file_id(file_id)
1413
1539
name = self._transform._limbo_name(trans_id)
1414
1540
return os.readlink(name)
1416
def paths2ids(self, specific_files, trees=None, require_versioned=False):
1417
"""See Tree.paths2ids"""
1542
def list_files(self, include_root=False):
1543
return self._transform._tree.list_files(include_root)
1545
def walkdirs(self, prefix=""):
1546
return self._transform._tree.walkdirs(prefix)
1548
def get_parent_ids(self):
1549
return self._transform._tree.get_parent_ids()
1551
def get_revision_tree(self, revision_id):
1552
return self._transform._tree.get_revision_tree(revision_id)
1421
1555
def joinpath(parent, child):
1557
1705
tt.delete_contents(tt.trans_id_tree_path(tree_path))
1558
1706
if kind == 'directory':
1559
1707
reparent = True
1560
if entry.parent_id not in file_trans_id:
1561
raise AssertionError(
1562
'entry %s parent id %r is not in file_trans_id %r'
1563
% (entry, entry.parent_id, file_trans_id))
1564
1708
parent_id = file_trans_id[entry.parent_id]
1565
1709
if entry.kind == 'file':
1566
1710
# We *almost* replicate new_by_entry, so that we can defer
1567
1711
# getting the file text, and get them all at once.
1568
1712
trans_id = tt.create_path(entry.name, parent_id)
1569
1713
file_trans_id[file_id] = trans_id
1570
tt.version_file(entry.file_id, trans_id)
1571
executable = tree.is_executable(entry.file_id, tree_path)
1572
if executable is not None:
1714
tt.version_file(file_id, trans_id)
1715
executable = tree.is_executable(file_id, tree_path)
1573
1717
tt.set_executability(executable, trans_id)
1574
deferred_contents.append((entry.file_id, trans_id))
1718
deferred_contents.append((file_id, trans_id))
1576
1720
file_trans_id[file_id] = new_by_entry(tt, entry, parent_id,
1727
1876
tt.set_executability(entry.executable, trans_id)
1730
@deprecated_function(zero_fifteen)
1731
def find_interesting(working_tree, target_tree, filenames):
1732
"""Find the ids corresponding to specified filenames.
1734
Deprecated: Please use tree1.paths2ids(filenames, [tree2]).
1736
working_tree.lock_read()
1738
target_tree.lock_read()
1740
return working_tree.paths2ids(filenames, [target_tree])
1742
target_tree.unlock()
1744
working_tree.unlock()
1747
@deprecated_function(zero_ninety)
1748
def change_entry(tt, file_id, working_tree, target_tree,
1749
trans_id_file_id, backups, trans_id, by_parent):
1750
"""Replace a file_id's contents with those from a target tree."""
1751
if file_id is None and target_tree is None:
1752
# skip the logic altogether in the deprecation test
1754
e_trans_id = trans_id_file_id(file_id)
1755
entry = target_tree.inventory[file_id]
1756
has_contents, contents_mod, meta_mod, = _entry_changes(file_id, entry,
1759
mode_id = e_trans_id
1762
tt.delete_contents(e_trans_id)
1764
parent_trans_id = trans_id_file_id(entry.parent_id)
1765
backup_name = get_backup_name(entry, by_parent,
1766
parent_trans_id, tt)
1767
tt.adjust_path(backup_name, parent_trans_id, e_trans_id)
1768
tt.unversion_file(e_trans_id)
1769
e_trans_id = tt.create_path(entry.name, parent_trans_id)
1770
tt.version_file(file_id, e_trans_id)
1771
trans_id[file_id] = e_trans_id
1772
create_by_entry(tt, entry, target_tree, e_trans_id, mode_id=mode_id)
1773
create_entry_executability(tt, entry, e_trans_id)
1776
tt.set_executability(entry.executable, e_trans_id)
1777
if tt.final_name(e_trans_id) != entry.name:
1780
parent_id = tt.final_parent(e_trans_id)
1781
parent_file_id = tt.final_file_id(parent_id)
1782
if parent_file_id != entry.parent_id:
1787
parent_trans_id = trans_id_file_id(entry.parent_id)
1788
tt.adjust_path(entry.name, parent_trans_id, e_trans_id)
1791
1879
def get_backup_name(entry, by_parent, parent_trans_id, tt):
1792
1880
return _get_backup_name(entry.name, by_parent, parent_trans_id, tt)
2019
2107
new_conflicts.add(('deleting parent', 'Not deleting',
2021
2109
except KeyError:
2022
tt.create_directory(trans_id)
2023
new_conflicts.add((c_type, 'Created directory', trans_id))
2025
2112
tt.final_name(trans_id)
2026
2113
except NoFinalPath:
2027
2114
if path_tree is not None:
2028
2115
file_id = tt.final_file_id(trans_id)
2117
file_id = tt.inactive_file_id(trans_id)
2029
2118
entry = path_tree.inventory[file_id]
2030
parent_trans_id = tt.trans_id_file_id(entry.parent_id)
2031
tt.adjust_path(entry.name, parent_trans_id, trans_id)
2119
# special-case the other tree root (move its
2120
# children to current root)
2121
if entry.parent_id is None:
2123
moved = _reparent_transform_children(
2124
tt, trans_id, tt.root)
2126
new_conflicts.add((c_type, 'Moved to root',
2129
parent_trans_id = tt.trans_id_file_id(
2131
tt.adjust_path(entry.name, parent_trans_id,
2134
tt.create_directory(trans_id)
2135
new_conflicts.add((c_type, 'Created directory', trans_id))
2032
2136
elif c_type == 'unversioned parent':
2033
tt.version_file(tt.inactive_file_id(conflict[1]), conflict[1])
2137
file_id = tt.inactive_file_id(conflict[1])
2138
# special-case the other tree root (move its children instead)
2139
if path_tree and file_id in path_tree:
2140
if path_tree.inventory[file_id].parent_id is None:
2142
tt.version_file(file_id, conflict[1])
2034
2143
new_conflicts.add((c_type, 'Versioned directory', conflict[1]))
2035
2144
elif c_type == 'non-directory parent':
2036
2145
parent_id = conflict[1]