859
859
def get_preview_tree(self):
860
860
"""Return a tree representing the result of the transform.
862
This tree only supports the subset of Tree functionality required
863
by show_diff_trees. It must only be compared to tt._tree.
862
The tree is a snapshot, and altering the TreeTransform will invalidate
865
865
return _PreviewTree(self)
1054
1054
def _limbo_name(self, trans_id):
1055
1055
"""Generate the limbo name of a file"""
1056
1056
limbo_name = self._limbo_files.get(trans_id)
1057
if limbo_name is not None:
1059
parent = self._new_parent.get(trans_id)
1060
# if the parent directory is already in limbo (e.g. when building a
1061
# tree), choose a limbo name inside the parent, to reduce further
1063
use_direct_path = False
1064
if self._new_contents.get(parent) == 'directory':
1065
filename = self._new_name.get(trans_id)
1066
if filename is not None:
1067
if parent not in self._limbo_children:
1068
self._limbo_children[parent] = set()
1069
self._limbo_children_names[parent] = {}
1070
use_direct_path = True
1071
# the direct path can only be used if no other file has
1072
# already taken this pathname, i.e. if the name is unused, or
1073
# if it is already associated with this trans_id.
1074
elif self._case_sensitive_target:
1075
if (self._limbo_children_names[parent].get(filename)
1076
in (trans_id, None)):
1077
use_direct_path = True
1079
for l_filename, l_trans_id in\
1080
self._limbo_children_names[parent].iteritems():
1081
if l_trans_id == trans_id:
1083
if l_filename.lower() == filename.lower():
1086
use_direct_path = True
1089
limbo_name = pathjoin(self._limbo_files[parent], filename)
1090
self._limbo_children[parent].add(trans_id)
1091
self._limbo_children_names[parent][filename] = trans_id
1093
limbo_name = pathjoin(self._limbodir, trans_id)
1094
self._needs_rename.add(trans_id)
1095
self._limbo_files[trans_id] = limbo_name
1057
if limbo_name is None:
1058
limbo_name = self._generate_limbo_path(trans_id)
1059
self._limbo_files[trans_id] = limbo_name
1096
1060
return limbo_name
1062
def _generate_limbo_path(self, trans_id):
1063
"""Generate a limbo path using the trans_id as the relative path.
1065
This is suitable as a fallback, and when the transform should not be
1066
sensitive to the path encoding of the limbo directory.
1068
self._needs_rename.add(trans_id)
1069
return pathjoin(self._limbodir, trans_id)
1098
1071
def adjust_path(self, name, parent, trans_id):
1099
1072
previous_parent = self._new_parent.get(trans_id)
1100
1073
previous_name = self._new_name.get(trans_id)
1397
1370
yield self.trans_id_tree_path(childpath)
1372
def _generate_limbo_path(self, trans_id):
1373
"""Generate a limbo path using the final path if possible.
1375
This optimizes the performance of applying the tree transform by
1376
avoiding renames. These renames can be avoided only when the parent
1377
directory is already scheduled for creation.
1379
If the final path cannot be used, falls back to using the trans_id as
1382
parent = self._new_parent.get(trans_id)
1383
# if the parent directory is already in limbo (e.g. when building a
1384
# tree), choose a limbo name inside the parent, to reduce further
1386
use_direct_path = False
1387
if self._new_contents.get(parent) == 'directory':
1388
filename = self._new_name.get(trans_id)
1389
if filename is not None:
1390
if parent not in self._limbo_children:
1391
self._limbo_children[parent] = set()
1392
self._limbo_children_names[parent] = {}
1393
use_direct_path = True
1394
# the direct path can only be used if no other file has
1395
# already taken this pathname, i.e. if the name is unused, or
1396
# if it is already associated with this trans_id.
1397
elif self._case_sensitive_target:
1398
if (self._limbo_children_names[parent].get(filename)
1399
in (trans_id, None)):
1400
use_direct_path = True
1402
for l_filename, l_trans_id in\
1403
self._limbo_children_names[parent].iteritems():
1404
if l_trans_id == trans_id:
1406
if l_filename.lower() == filename.lower():
1409
use_direct_path = True
1411
if not use_direct_path:
1412
return DiskTreeTransform._generate_limbo_path(self, trans_id)
1414
limbo_name = pathjoin(self._limbo_files[parent], filename)
1415
self._limbo_children[parent].add(trans_id)
1416
self._limbo_children_names[parent][filename] = trans_id
1399
1420
def apply(self, no_conflicts=False, precomputed_delta=None, _mover=None):
1400
1421
"""Apply all changes to the inventory and filesystem.
1635
1656
self._all_children_cache = {}
1636
1657
self._path2trans_id_cache = {}
1637
1658
self._final_name_cache = {}
1639
def _changes(self, file_id):
1640
for changes in self._transform.iter_changes():
1641
if changes[0] == file_id:
1659
self._iter_changes_cache = dict((c[0], c) for c in
1660
self._transform.iter_changes())
1644
1662
def _content_change(self, file_id):
1645
1663
"""Return True if the content of this file changed"""
1646
changes = self._changes(file_id)
1664
changes = self._iter_changes_cache.get(file_id)
1647
1665
# changes[2] is true if the file content changed. See
1648
1666
# InterTree.iter_changes.
1649
1667
return (changes is not None and changes[2])
2402
2420
tt.create_directory(trans_id)
2405
def create_from_tree(tt, trans_id, tree, file_id, bytes=None):
2406
"""Create new file contents according to tree contents."""
2423
def create_from_tree(tt, trans_id, tree, file_id, bytes=None,
2424
filter_tree_path=None):
2425
"""Create new file contents according to tree contents.
2427
:param filter_tree_path: the tree path to use to lookup
2428
content filters to apply to the bytes output in the working tree.
2429
This only applies if the working tree supports content filtering.
2407
2431
kind = tree.kind(file_id)
2408
2432
if kind == 'directory':
2409
2433
tt.create_directory(trans_id)
2414
2438
bytes = tree_file.readlines()
2416
2440
tree_file.close()
2442
if wt.supports_content_filtering() and filter_tree_path is not None:
2443
filters = wt._content_filter_stack(filter_tree_path)
2444
bytes = filtered_output_bytes(bytes, filters,
2445
ContentFilterContext(filter_tree_path, tree))
2417
2446
tt.create_file(bytes, trans_id)
2418
2447
elif kind == "symlink":
2419
2448
tt.create_symlink(tree.get_symlink_target(file_id), trans_id)
2610
2639
tt.adjust_path(name[1], parent_trans, trans_id)
2611
2640
if executable[0] != executable[1] and kind[1] == "file":
2612
2641
tt.set_executability(executable[1], trans_id)
2613
for (trans_id, mode_id), bytes in target_tree.iter_files_bytes(
2615
tt.create_file(bytes, trans_id, mode_id)
2642
if working_tree.supports_content_filtering():
2643
for index, ((trans_id, mode_id), bytes) in enumerate(
2644
target_tree.iter_files_bytes(deferred_files)):
2645
file_id = deferred_files[index][0]
2646
# We're reverting a tree to the target tree so using the
2647
# target tree to find the file path seems the best choice
2648
# here IMO - Ian C 27/Oct/2009
2649
filter_tree_path = target_tree.id2path(file_id)
2650
filters = working_tree._content_filter_stack(filter_tree_path)
2651
bytes = filtered_output_bytes(bytes, filters,
2652
ContentFilterContext(filter_tree_path, working_tree))
2653
tt.create_file(bytes, trans_id, mode_id)
2655
for (trans_id, mode_id), bytes in target_tree.iter_files_bytes(
2657
tt.create_file(bytes, trans_id, mode_id)
2617
2659
if basis_tree is not None:
2618
2660
basis_tree.unlock()