40
48
ExistingLimbo, ImmortalLimbo, NoFinalPath,
41
49
UnableCreateSymlink)
42
50
from bzrlib.filters import filtered_output_bytes, ContentFilterContext
43
from bzrlib.inventory import InventoryEntry
44
51
from bzrlib.osutils import (
52
58
supports_executable,
54
60
from bzrlib.progress import ProgressPhase
55
61
from bzrlib.symbol_versioning import (
59
from bzrlib.trace import mutter, warning
60
from bzrlib import tree
62
import bzrlib.urlutils as urlutils
65
68
ROOT_PARENT = "root-parent"
68
70
def unique_add(map, key, value):
70
72
raise DuplicateKey(key=key)
74
77
class _TransformResults(object):
75
78
def __init__(self, modified_paths, rename_count):
76
79
object.__init__(self)
380
398
return sorted(FinalPaths(self).get_paths(new_ids))
382
400
def _inventory_altered(self):
383
"""Get the trans_ids and paths of files needing new inv entries."""
385
for id_set in [self._new_name, self._new_parent, self._new_id,
401
"""Determine which trans_ids need new Inventory entries.
403
An new entry is needed when anything that would be reflected by an
404
inventory entry changes, including file name, file_id, parent file_id,
405
file kind, and the execute bit.
407
Some care is taken to return entries with real changes, not cases
408
where the value is deleted and then restored to its original value,
409
but some actually unchanged values may be returned.
411
:returns: A list of (path, trans_id) for all items requiring an
412
inventory change. Ordered by path.
415
# Find entries whose file_ids are new (or changed).
416
new_file_id = set(t for t in self._new_id
417
if self._new_id[t] != self.tree_file_id(t))
418
for id_set in [self._new_name, self._new_parent, new_file_id,
386
419
self._new_executability]:
387
new_ids.update(id_set)
420
changed_ids.update(id_set)
421
# removing implies a kind change
388
422
changed_kind = set(self._removed_contents)
389
424
changed_kind.intersection_update(self._new_contents)
390
changed_kind.difference_update(new_ids)
425
# Ignore entries that are already known to have changed.
426
changed_kind.difference_update(changed_ids)
427
# to keep only the truly changed ones
391
428
changed_kind = (t for t in changed_kind
392
429
if self.tree_kind(t) != self.final_kind(t))
393
new_ids.update(changed_kind)
394
return sorted(FinalPaths(self).get_paths(new_ids))
430
# all kind changes will alter the inventory
431
changed_ids.update(changed_kind)
432
# To find entries with changed parent_ids, find parents which existed,
433
# but changed file_id.
434
changed_file_id = set(t for t in new_file_id if t in self._removed_id)
435
# Now add all their children to the set.
436
for parent_trans_id in new_file_id:
437
changed_ids.update(self.iter_tree_children(parent_trans_id))
438
return sorted(FinalPaths(self).get_paths(changed_ids))
396
440
def final_kind(self, trans_id):
397
441
"""Determine the final file kind, after any changes applied.
531
577
# ensure that all children are registered with the transaction
532
578
list(self.iter_tree_children(parent_id))
580
@deprecated_method(deprecated_in((2, 3, 0)))
534
581
def has_named_child(self, by_parent, parent_id, name):
536
children = by_parent[parent_id]
539
for child in children:
582
return self._has_named_child(
583
name, parent_id, known_children=by_parent.get(parent_id, []))
585
def _has_named_child(self, name, parent_id, known_children):
586
"""Does a parent already have a name child.
588
:param name: The searched for name.
590
:param parent_id: The parent for which the check is made.
592
:param known_children: The already known children. This should have
593
been recently obtained from `self.by_parent.get(parent_id)`
594
(or will be if None is passed).
596
if known_children is None:
597
known_children = self.by_parent().get(parent_id, [])
598
for child in known_children:
540
599
if self.final_name(child) == name:
543
path = self._tree_id_paths[parent_id]
601
parent_path = self._tree_id_paths.get(parent_id, None)
602
if parent_path is None:
603
# No parent... no children
546
childpath = joinpath(path, name)
547
child_id = self._tree_path_ids.get(childpath)
605
child_path = joinpath(parent_path, name)
606
child_id = self._tree_path_ids.get(child_path, None)
548
607
if child_id is None:
549
return lexists(self._tree.abspath(childpath))
608
# Not known by the tree transform yet, check the filesystem
609
return osutils.lexists(self._tree.abspath(child_path))
551
if self.final_parent(child_id) != parent_id:
553
if child_id in self._removed_contents:
554
# XXX What about dangling file-ids?
611
raise AssertionError('child_id is missing: %s, %s, %s'
612
% (name, parent_id, child_id))
614
def _available_backup_name(self, name, target_id):
615
"""Find an available backup name.
617
:param name: The basename of the file.
619
:param target_id: The directory trans_id where the backup should
622
known_children = self.by_parent().get(target_id, [])
623
return osutils.available_backup_name(
625
lambda base: self._has_named_child(
626
base, target_id, known_children))
559
628
def _parent_loops(self):
560
629
"""No entry should be its own ancestor"""
671
745
def _parent_type_conflicts(self, by_parent):
672
"""parents must have directory 'contents'."""
746
"""Children must have a directory parent"""
674
748
for parent_id, children in by_parent.iteritems():
675
749
if parent_id is ROOT_PARENT:
677
if not self._any_contents(children):
752
for child_id in children:
753
if self.final_kind(child_id) is not None:
758
# There is at least a child, so we need an existing directory to
679
760
kind = self.final_kind(parent_id)
762
# The directory will be deleted
681
763
conflicts.append(('missing parent', parent_id))
682
764
elif kind != "directory":
765
# Meh, we need a *directory* to put something in it
683
766
conflicts.append(('non-directory parent', parent_id))
686
def _any_contents(self, trans_ids):
687
"""Return true if any of the trans_ids, will have contents."""
688
for trans_id in trans_ids:
689
if self.final_kind(trans_id) is not None:
693
769
def _set_executability(self, path, trans_id):
694
770
"""Set the executability of versioned files """
695
771
if supports_executable():
759
835
self.create_symlink(target, trans_id)
838
def new_orphan(self, trans_id, parent_id):
839
"""Schedule an item to be orphaned.
841
When a directory is about to be removed, its children, if they are not
842
versioned are moved out of the way: they don't have a parent anymore.
844
:param trans_id: The trans_id of the existing item.
845
:param parent_id: The parent trans_id of the item.
847
raise NotImplementedError(self.new_orphan)
849
def _get_potential_orphans(self, dir_id):
850
"""Find the potential orphans in a directory.
852
A directory can't be safely deleted if there are versioned files in it.
853
If all the contained files are unversioned then they can be orphaned.
855
The 'None' return value means that the directory contains at least one
856
versioned file and should not be deleted.
858
:param dir_id: The directory trans id.
860
:return: A list of the orphan trans ids or None if at least one
861
versioned file is present.
864
# Find the potential orphans, stop if one item should be kept
865
for child_tid in self.by_parent()[dir_id]:
866
if child_tid in self._removed_contents:
867
# The child is removed as part of the transform. Since it was
868
# versioned before, it's not an orphan
870
elif self.final_file_id(child_tid) is None:
871
# The child is not versioned
872
orphans.append(child_tid)
874
# We have a versioned file here, searching for orphans is
762
880
def _affected_ids(self):
763
881
"""Return the set of transform ids affected by the transform"""
764
882
trans_ids = set(self._removed_id)
1170
1299
descendants.update(self._limbo_descendants(descendant))
1171
1300
return descendants
1173
def create_file(self, contents, trans_id, mode_id=None):
1302
def create_file(self, contents, trans_id, mode_id=None, sha1=None):
1174
1303
"""Schedule creation of a new file.
1178
Contents is an iterator of strings, all of which will be written
1179
to the target destination.
1181
New file takes the permissions of any existing file with that id,
1182
unless mode_id is specified.
1307
:param contents: an iterator of strings, all of which will be written
1308
to the target destination.
1309
:param trans_id: TreeTransform handle
1310
:param mode_id: If not None, force the mode of the target file to match
1311
the mode of the object referenced by mode_id.
1312
Otherwise, we will try to preserve mode bits of an existing file.
1313
:param sha1: If the sha1 of this content is already known, pass it in.
1314
We can use it to prevent future sha1 computations.
1184
1316
name = self._limbo_name(trans_id)
1185
1317
f = open(name, 'wb')
1188
unique_add(self._new_contents, trans_id, 'file')
1190
# Clean up the file, it never got registered so
1191
# TreeTransform.finalize() won't clean it up.
1319
unique_add(self._new_contents, trans_id, 'file')
1196
1320
f.writelines(contents)
1199
1323
self._set_mtime(name)
1200
1324
self._set_mode(trans_id, mode_id, S_ISREG)
1325
# It is unfortunate we have to use lstat instead of fstat, but we just
1326
# used utime and chmod on the file, so we need the accurate final
1328
if sha1 is not None:
1329
self._observed_sha1s[trans_id] = (sha1, osutils.lstat(name))
1202
1331
def _read_file_chunks(self, trans_id):
1203
1332
cur_file = open(self._limbo_name(trans_id), 'rb')
1271
1402
del self._limbo_children_names[trans_id]
1272
1403
delete_any(self._limbo_name(trans_id))
1405
def new_orphan(self, trans_id, parent_id):
1406
# FIXME: There is no tree config, so we use the branch one (it's weird
1407
# to define it this way as orphaning can only occur in a working tree,
1408
# but that's all we have (for now). It will find the option in
1409
# locations.conf or bazaar.conf though) -- vila 20100916
1410
conf = self._tree.branch.get_config()
1411
conf_var_name = 'bzr.transform.orphan_policy'
1412
orphan_policy = conf.get_user_option(conf_var_name)
1413
default_policy = orphaning_registry.default_key
1414
if orphan_policy is None:
1415
orphan_policy = default_policy
1416
if orphan_policy not in orphaning_registry:
1417
trace.warning('%s (from %s) is not a known policy, defaulting '
1418
'to %s' % (orphan_policy, conf_var_name, default_policy))
1419
orphan_policy = default_policy
1420
handle_orphan = orphaning_registry.get(orphan_policy)
1421
handle_orphan(self, trans_id, parent_id)
1424
class OrphaningError(errors.BzrError):
1426
# Only bugs could lead to such exception being seen by the user
1427
internal_error = True
1428
_fmt = "Error while orphaning %s in %s directory"
1430
def __init__(self, orphan, parent):
1431
errors.BzrError.__init__(self)
1432
self.orphan = orphan
1433
self.parent = parent
1436
class OrphaningForbidden(OrphaningError):
1438
_fmt = "Policy: %s doesn't allow creating orphans."
1440
def __init__(self, policy):
1441
errors.BzrError.__init__(self)
1442
self.policy = policy
1445
def move_orphan(tt, orphan_id, parent_id):
1446
"""See TreeTransformBase.new_orphan.
1448
This creates a new orphan in the `bzr-orphans` dir at the root of the
1451
:param tt: The TreeTransform orphaning `trans_id`.
1453
:param orphan_id: The trans id that should be orphaned.
1455
:param parent_id: The orphan parent trans id.
1457
# Add the orphan dir if it doesn't exist
1458
orphan_dir_basename = 'bzr-orphans'
1459
od_id = tt.trans_id_tree_path(orphan_dir_basename)
1460
if tt.final_kind(od_id) is None:
1461
tt.create_directory(od_id)
1462
parent_path = tt._tree_id_paths[parent_id]
1463
# Find a name that doesn't exist yet in the orphan dir
1464
actual_name = tt.final_name(orphan_id)
1465
new_name = tt._available_backup_name(actual_name, od_id)
1466
tt.adjust_path(new_name, od_id, orphan_id)
1467
trace.warning('%s has been orphaned in %s'
1468
% (joinpath(parent_path, actual_name), orphan_dir_basename))
1471
def refuse_orphan(tt, orphan_id, parent_id):
1472
"""See TreeTransformBase.new_orphan.
1474
This refuses to create orphan, letting the caller handle the conflict.
1476
raise OrphaningForbidden('never')
1479
orphaning_registry = registry.Registry()
1480
orphaning_registry.register(
1481
'conflict', refuse_orphan,
1482
'Leave orphans in place and create a conflict on the directory.')
1483
orphaning_registry.register(
1484
'move', move_orphan,
1485
'Move orphans into the bzr-orphans directory.')
1486
orphaning_registry._set_default_key('conflict')
1275
1489
class TreeTransform(DiskTreeTransform):
1276
1490
"""Represent a tree transformation.
1667
1880
self.rename_count += 1
1881
# TODO: if trans_id in self._observed_sha1s, we should
1882
# re-stat the final target, since ctime will be
1883
# updated by the change.
1668
1884
if (trans_id in self._new_contents or
1669
1885
self.path_changed(trans_id)):
1670
1886
if trans_id in self._new_contents:
1671
1887
modified_paths.append(full_path)
1672
1888
if trans_id in self._new_executability:
1673
1889
self._set_executability(path, trans_id)
1890
if trans_id in self._observed_sha1s:
1891
o_sha1, o_st_val = self._observed_sha1s[trans_id]
1892
st = osutils.lstat(full_path)
1893
self._observed_sha1s[trans_id] = (o_sha1, st)
1675
1895
child_pb.finished()
1896
for path, trans_id in new_paths:
1897
# new_paths includes stuff like workingtree conflicts. Only the
1898
# stuff in new_contents actually comes from limbo.
1899
if trans_id in self._limbo_files:
1900
del self._limbo_files[trans_id]
1676
1901
self._new_contents.clear()
1677
1902
return modified_paths
1904
def _apply_observed_sha1s(self):
1905
"""After we have finished renaming everything, update observed sha1s
1907
This has to be done after self._tree.apply_inventory_delta, otherwise
1908
it doesn't know anything about the files we are updating. Also, we want
1909
to do this as late as possible, so that most entries end up cached.
1911
# TODO: this doesn't update the stat information for directories. So
1912
# the first 'bzr status' will still need to rewrite
1913
# .bzr/checkout/dirstate. However, we at least don't need to
1914
# re-read all of the files.
1915
# TODO: If the operation took a while, we could do a time.sleep(3) here
1916
# to allow the clock to tick over and ensure we won't have any
1917
# problems. (we could observe start time, and finish time, and if
1918
# it is less than eg 10% overhead, add a sleep call.)
1919
paths = FinalPaths(self)
1920
for trans_id, observed in self._observed_sha1s.iteritems():
1921
path = paths.get_path(trans_id)
1922
# We could get the file_id, but dirstate prefers to use the path
1923
# anyway, and it is 'cheaper' to determine.
1924
# file_id = self._new_id[trans_id]
1925
self._tree._observed_sha1(None, path, observed)
1680
1928
class TransformPreview(DiskTreeTransform):
1681
1929
"""A TreeTransform for generating preview trees.
2415
2682
offset += count
2416
for count, ((trans_id, tree_path), contents) in enumerate(
2683
for count, ((trans_id, tree_path, text_sha1), contents) in enumerate(
2417
2684
tree.iter_files_bytes(new_desired_files)):
2418
2685
if wt.supports_content_filtering():
2419
2686
filters = wt._content_filter_stack(tree_path)
2420
2687
contents = filtered_output_bytes(contents, filters,
2421
2688
ContentFilterContext(tree_path, tree))
2422
tt.create_file(contents, trans_id)
2689
tt.create_file(contents, trans_id, sha1=text_sha1)
2423
2690
pb.update('Adding file contents', count + offset, total)
2643
2918
deferred_files = []
2644
2919
for id_num, (file_id, path, changed_content, versioned, parent, name,
2645
2920
kind, executable) in enumerate(change_list):
2646
if skip_root and file_id[0] is not None and parent[0] is None:
2921
target_path, wt_path = path
2922
target_versioned, wt_versioned = versioned
2923
target_parent, wt_parent = parent
2924
target_name, wt_name = name
2925
target_kind, wt_kind = kind
2926
target_executable, wt_executable = executable
2927
if skip_root and wt_parent is None:
2648
2929
trans_id = tt.trans_id_file_id(file_id)
2650
2931
if changed_content:
2651
2932
keep_content = False
2652
if kind[0] == 'file' and (backups or kind[1] is None):
2933
if wt_kind == 'file' and (backups or target_kind is None):
2653
2934
wt_sha1 = working_tree.get_file_sha1(file_id)
2654
2935
if merge_modified.get(file_id) != wt_sha1:
2655
2936
# acquire the basis tree lazily to prevent the
2658
2939
if basis_tree is None:
2659
2940
basis_tree = working_tree.basis_tree()
2660
2941
basis_tree.lock_read()
2661
if file_id in basis_tree:
2942
if basis_tree.has_id(file_id):
2662
2943
if wt_sha1 != basis_tree.get_file_sha1(file_id):
2663
2944
keep_content = True
2664
elif kind[1] is None and not versioned[1]:
2945
elif target_kind is None and not target_versioned:
2665
2946
keep_content = True
2666
if kind[0] is not None:
2947
if wt_kind is not None:
2667
2948
if not keep_content:
2668
2949
tt.delete_contents(trans_id)
2669
elif kind[1] is not None:
2670
parent_trans_id = tt.trans_id_file_id(parent[0])
2671
by_parent = tt.by_parent()
2672
backup_name = _get_backup_name(name[0], by_parent,
2673
parent_trans_id, tt)
2950
elif target_kind is not None:
2951
parent_trans_id = tt.trans_id_file_id(wt_parent)
2952
backup_name = tt._available_backup_name(
2953
wt_name, parent_trans_id)
2674
2954
tt.adjust_path(backup_name, parent_trans_id, trans_id)
2675
new_trans_id = tt.create_path(name[0], parent_trans_id)
2676
if versioned == (True, True):
2955
new_trans_id = tt.create_path(wt_name, parent_trans_id)
2956
if wt_versioned and target_versioned:
2677
2957
tt.unversion_file(trans_id)
2678
2958
tt.version_file(file_id, new_trans_id)
2679
2959
# New contents should have the same unix perms as old
2681
2961
mode_id = trans_id
2682
2962
trans_id = new_trans_id
2683
if kind[1] in ('directory', 'tree-reference'):
2963
if target_kind in ('directory', 'tree-reference'):
2684
2964
tt.create_directory(trans_id)
2685
if kind[1] == 'tree-reference':
2965
if target_kind == 'tree-reference':
2686
2966
revision = target_tree.get_reference_revision(file_id,
2688
2968
tt.set_tree_reference(revision, trans_id)
2689
elif kind[1] == 'symlink':
2969
elif target_kind == 'symlink':
2690
2970
tt.create_symlink(target_tree.get_symlink_target(file_id),
2692
elif kind[1] == 'file':
2972
elif target_kind == 'file':
2693
2973
deferred_files.append((file_id, (trans_id, mode_id)))
2694
2974
if basis_tree is None:
2695
2975
basis_tree = working_tree.basis_tree()
2696
2976
basis_tree.lock_read()
2697
2977
new_sha1 = target_tree.get_file_sha1(file_id)
2698
if (file_id in basis_tree and new_sha1 ==
2699
basis_tree.get_file_sha1(file_id)):
2978
if (basis_tree.has_id(file_id) and
2979
new_sha1 == basis_tree.get_file_sha1(file_id)):
2700
2980
if file_id in merge_modified:
2701
2981
del merge_modified[file_id]
2703
2983
merge_modified[file_id] = new_sha1
2705
2985
# preserve the execute bit when backing up
2706
if keep_content and executable[0] == executable[1]:
2707
tt.set_executability(executable[1], trans_id)
2708
elif kind[1] is not None:
2709
raise AssertionError(kind[1])
2710
if versioned == (False, True):
2986
if keep_content and wt_executable == target_executable:
2987
tt.set_executability(target_executable, trans_id)
2988
elif target_kind is not None:
2989
raise AssertionError(target_kind)
2990
if not wt_versioned and target_versioned:
2711
2991
tt.version_file(file_id, trans_id)
2712
if versioned == (True, False):
2992
if wt_versioned and not target_versioned:
2713
2993
tt.unversion_file(trans_id)
2714
if (name[1] is not None and
2715
(name[0] != name[1] or parent[0] != parent[1])):
2716
if name[1] == '' and parent[1] is None:
2994
if (target_name is not None and
2995
(wt_name != target_name or wt_parent != target_parent)):
2996
if target_name == '' and target_parent is None:
2717
2997
parent_trans = ROOT_PARENT
2719
parent_trans = tt.trans_id_file_id(parent[1])
2720
if parent[0] is None and versioned[0]:
2721
tt.adjust_root_path(name[1], parent_trans)
2999
parent_trans = tt.trans_id_file_id(target_parent)
3000
if wt_parent is None and wt_versioned:
3001
tt.adjust_root_path(target_name, parent_trans)
2723
tt.adjust_path(name[1], parent_trans, trans_id)
2724
if executable[0] != executable[1] and kind[1] == "file":
2725
tt.set_executability(executable[1], trans_id)
3003
tt.adjust_path(target_name, parent_trans, trans_id)
3004
if wt_executable != target_executable and target_kind == "file":
3005
tt.set_executability(target_executable, trans_id)
2726
3006
if working_tree.supports_content_filtering():
2727
3007
for index, ((trans_id, mode_id), bytes) in enumerate(
2728
3008
target_tree.iter_files_bytes(deferred_files)):
2800
3080
elif c_type == 'missing parent':
2801
3081
trans_id = conflict[1]
2803
tt.cancel_deletion(trans_id)
2804
new_conflicts.add(('deleting parent', 'Not deleting',
3082
if trans_id in tt._removed_contents:
3083
cancel_deletion = True
3084
orphans = tt._get_potential_orphans(trans_id)
3086
cancel_deletion = False
3087
# All children are orphans
3090
tt.new_orphan(o, trans_id)
3091
except OrphaningError:
3092
# Something bad happened so we cancel the directory
3093
# deletion which will leave it in place with a
3094
# conflict. The user can deal with it from there.
3095
# Note that this also catch the case where we don't
3096
# want to create orphans and leave the directory in
3098
cancel_deletion = True
3101
# Cancel the directory deletion
3102
tt.cancel_deletion(trans_id)
3103
new_conflicts.add(('deleting parent', 'Not deleting',
2809
3108
tt.final_name(trans_id)
2870
3169
modified_path = fp.get_path(conflict[2])
2871
3170
modified_id = tt.final_file_id(conflict[2])
2872
3171
if len(conflict) == 3:
2873
yield Conflict.factory(c_type, action=action, path=modified_path,
2874
file_id=modified_id)
3172
yield conflicts.Conflict.factory(
3173
c_type, action=action, path=modified_path, file_id=modified_id)
2877
3176
conflicting_path = fp.get_path(conflict[3])
2878
3177
conflicting_id = tt.final_file_id(conflict[3])
2879
yield Conflict.factory(c_type, action=action, path=modified_path,
2880
file_id=modified_id,
2881
conflict_path=conflicting_path,
2882
conflict_file_id=conflicting_id)
3178
yield conflicts.Conflict.factory(
3179
c_type, action=action, path=modified_path,
3180
file_id=modified_id,
3181
conflict_path=conflicting_path,
3182
conflict_file_id=conflicting_id)
2885
3185
class _FileMover(object):