384
398
return sorted(FinalPaths(self).get_paths(new_ids))
386
400
def _inventory_altered(self):
387
"""Get the trans_ids and paths of files needing new inv entries."""
389
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,
390
419
self._new_executability]:
391
new_ids.update(id_set)
420
changed_ids.update(id_set)
421
# removing implies a kind change
392
422
changed_kind = set(self._removed_contents)
393
424
changed_kind.intersection_update(self._new_contents)
394
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
395
428
changed_kind = (t for t in changed_kind
396
429
if self.tree_kind(t) != self.final_kind(t))
397
new_ids.update(changed_kind)
398
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))
400
440
def final_kind(self, trans_id):
401
441
"""Determine the final file kind, after any changes applied.
1359
1401
delete_any(self._limbo_name(trans_id))
1361
1403
def new_orphan(self, trans_id, parent_id):
1362
# FIXME: There is no tree config, so we use the branch one (it's weird
1363
# to define it this way as orphaning can only occur in a working tree,
1364
# but that's all we have (for now). It will find the option in
1365
# locations.conf or bazaar.conf though) -- vila 20100916
1366
conf = self._tree.branch.get_config()
1367
conf_var_name = 'bzr.transform.orphan_policy'
1368
orphan_policy = conf.get_user_option(conf_var_name)
1369
default_policy = orphaning_registry.default_key
1370
if orphan_policy is None:
1371
orphan_policy = default_policy
1372
if orphan_policy not in orphaning_registry:
1373
trace.warning('%s (from %s) is not a known policy, defaulting '
1374
'to %s' % (orphan_policy, conf_var_name, default_policy))
1375
orphan_policy = default_policy
1376
handle_orphan = orphaning_registry.get(orphan_policy)
1404
conf = self._tree.get_config_stack()
1405
handle_orphan = conf.get('bzr.transform.orphan_policy')
1377
1406
handle_orphan(self, trans_id, parent_id)
2200
2260
def get_file_size(self, file_id):
2201
2261
"""See Tree.get_file_size"""
2262
trans_id = self._transform.trans_id_file_id(file_id)
2263
kind = self._transform.final_kind(trans_id)
2266
if trans_id in self._transform._new_contents:
2267
return self._stat_limbo_file(trans_id=trans_id).st_size
2202
2268
if self.kind(file_id) == 'file':
2203
2269
return self._transform._tree.get_file_size(file_id)
2273
def get_file_verifier(self, file_id, path=None, stat_value=None):
2274
trans_id = self._transform.trans_id_file_id(file_id)
2275
kind = self._transform._new_contents.get(trans_id)
2277
return self._transform._tree.get_file_verifier(file_id)
2279
fileobj = self.get_file(file_id)
2281
return ("SHA1", sha_file(fileobj))
2207
2285
def get_file_sha1(self, file_id, path=None, stat_value=None):
2208
2286
trans_id = self._transform.trans_id_file_id(file_id)
2209
2287
kind = self._transform._new_contents.get(trans_id)
2745
2832
tt.set_executability(entry.executable, trans_id)
2748
@deprecated_function(deprecated_in((2, 3, 0)))
2749
def get_backup_name(entry, by_parent, parent_trans_id, tt):
2750
return _get_backup_name(entry.name, by_parent, parent_trans_id, tt)
2753
@deprecated_function(deprecated_in((2, 3, 0)))
2754
def _get_backup_name(name, by_parent, parent_trans_id, tt):
2755
"""Produce a backup-style name that appears to be available"""
2759
yield "%s.~%d~" % (name, counter)
2761
for new_name in name_gen():
2762
if not tt.has_named_child(by_parent, parent_trans_id, new_name):
2766
def _entry_changes(file_id, entry, working_tree):
2767
"""Determine in which ways the inventory entry has changed.
2769
Returns booleans: has_contents, content_mod, meta_mod
2770
has_contents means there are currently contents, but they differ
2771
contents_mod means contents need to be modified
2772
meta_mod means the metadata needs to be modified
2774
cur_entry = working_tree.inventory[file_id]
2776
working_kind = working_tree.kind(file_id)
2779
has_contents = False
2782
if has_contents is True:
2783
if entry.kind != working_kind:
2784
contents_mod, meta_mod = True, False
2786
cur_entry._read_tree_state(working_tree.id2path(file_id),
2788
contents_mod, meta_mod = entry.detect_changes(cur_entry)
2789
cur_entry._forget_tree_state()
2790
return has_contents, contents_mod, meta_mod
2793
2835
def revert(working_tree, target_tree, filenames, backups=False,
2794
2836
pb=None, change_reporter=None):
2795
2837
"""Revert a working tree's contents to those of a target tree."""
2852
2898
deferred_files = []
2853
2899
for id_num, (file_id, path, changed_content, versioned, parent, name,
2854
2900
kind, executable) in enumerate(change_list):
2855
if skip_root and file_id[0] is not None and parent[0] is None:
2901
target_path, wt_path = path
2902
target_versioned, wt_versioned = versioned
2903
target_parent, wt_parent = parent
2904
target_name, wt_name = name
2905
target_kind, wt_kind = kind
2906
target_executable, wt_executable = executable
2907
if skip_root and wt_parent is None:
2857
2909
trans_id = tt.trans_id_file_id(file_id)
2859
2911
if changed_content:
2860
2912
keep_content = False
2861
if kind[0] == 'file' and (backups or kind[1] is None):
2913
if wt_kind == 'file' and (backups or target_kind is None):
2862
2914
wt_sha1 = working_tree.get_file_sha1(file_id)
2863
2915
if merge_modified.get(file_id) != wt_sha1:
2864
2916
# acquire the basis tree lazily to prevent the
2867
2919
if basis_tree is None:
2868
2920
basis_tree = working_tree.basis_tree()
2869
2921
basis_tree.lock_read()
2870
if file_id in basis_tree:
2922
if basis_tree.has_id(file_id):
2871
2923
if wt_sha1 != basis_tree.get_file_sha1(file_id):
2872
2924
keep_content = True
2873
elif kind[1] is None and not versioned[1]:
2925
elif target_kind is None and not target_versioned:
2874
2926
keep_content = True
2875
if kind[0] is not None:
2927
if wt_kind is not None:
2876
2928
if not keep_content:
2877
2929
tt.delete_contents(trans_id)
2878
elif kind[1] is not None:
2879
parent_trans_id = tt.trans_id_file_id(parent[0])
2930
elif target_kind is not None:
2931
parent_trans_id = tt.trans_id_file_id(wt_parent)
2880
2932
backup_name = tt._available_backup_name(
2881
name[0], parent_trans_id)
2933
wt_name, parent_trans_id)
2882
2934
tt.adjust_path(backup_name, parent_trans_id, trans_id)
2883
new_trans_id = tt.create_path(name[0], parent_trans_id)
2884
if versioned == (True, True):
2935
new_trans_id = tt.create_path(wt_name, parent_trans_id)
2936
if wt_versioned and target_versioned:
2885
2937
tt.unversion_file(trans_id)
2886
2938
tt.version_file(file_id, new_trans_id)
2887
2939
# New contents should have the same unix perms as old
2889
2941
mode_id = trans_id
2890
2942
trans_id = new_trans_id
2891
if kind[1] in ('directory', 'tree-reference'):
2943
if target_kind in ('directory', 'tree-reference'):
2892
2944
tt.create_directory(trans_id)
2893
if kind[1] == 'tree-reference':
2945
if target_kind == 'tree-reference':
2894
2946
revision = target_tree.get_reference_revision(file_id,
2896
2948
tt.set_tree_reference(revision, trans_id)
2897
elif kind[1] == 'symlink':
2949
elif target_kind == 'symlink':
2898
2950
tt.create_symlink(target_tree.get_symlink_target(file_id),
2900
elif kind[1] == 'file':
2952
elif target_kind == 'file':
2901
2953
deferred_files.append((file_id, (trans_id, mode_id)))
2902
2954
if basis_tree is None:
2903
2955
basis_tree = working_tree.basis_tree()
2904
2956
basis_tree.lock_read()
2905
2957
new_sha1 = target_tree.get_file_sha1(file_id)
2906
if (file_id in basis_tree and new_sha1 ==
2907
basis_tree.get_file_sha1(file_id)):
2958
if (basis_tree.has_id(file_id) and
2959
new_sha1 == basis_tree.get_file_sha1(file_id)):
2908
2960
if file_id in merge_modified:
2909
2961
del merge_modified[file_id]
2911
2963
merge_modified[file_id] = new_sha1
2913
2965
# preserve the execute bit when backing up
2914
if keep_content and executable[0] == executable[1]:
2915
tt.set_executability(executable[1], trans_id)
2916
elif kind[1] is not None:
2917
raise AssertionError(kind[1])
2918
if versioned == (False, True):
2966
if keep_content and wt_executable == target_executable:
2967
tt.set_executability(target_executable, trans_id)
2968
elif target_kind is not None:
2969
raise AssertionError(target_kind)
2970
if not wt_versioned and target_versioned:
2919
2971
tt.version_file(file_id, trans_id)
2920
if versioned == (True, False):
2972
if wt_versioned and not target_versioned:
2921
2973
tt.unversion_file(trans_id)
2922
if (name[1] is not None and
2923
(name[0] != name[1] or parent[0] != parent[1])):
2924
if name[1] == '' and parent[1] is None:
2974
if (target_name is not None and
2975
(wt_name != target_name or wt_parent != target_parent)):
2976
if target_name == '' and target_parent is None:
2925
2977
parent_trans = ROOT_PARENT
2927
parent_trans = tt.trans_id_file_id(parent[1])
2928
if parent[0] is None and versioned[0]:
2929
tt.adjust_root_path(name[1], parent_trans)
2979
parent_trans = tt.trans_id_file_id(target_parent)
2980
if wt_parent is None and wt_versioned:
2981
tt.adjust_root_path(target_name, parent_trans)
2931
tt.adjust_path(name[1], parent_trans, trans_id)
2932
if executable[0] != executable[1] and kind[1] == "file":
2933
tt.set_executability(executable[1], trans_id)
2983
tt.adjust_path(target_name, parent_trans, trans_id)
2984
if wt_executable != target_executable and target_kind == "file":
2985
tt.set_executability(target_executable, trans_id)
2934
2986
if working_tree.supports_content_filtering():
2935
2987
for index, ((trans_id, mode_id), bytes) in enumerate(
2936
2988
target_tree.iter_files_bytes(deferred_files)):
3099
3149
modified_path = fp.get_path(conflict[2])
3100
3150
modified_id = tt.final_file_id(conflict[2])
3101
3151
if len(conflict) == 3:
3102
yield Conflict.factory(c_type, action=action, path=modified_path,
3103
file_id=modified_id)
3152
yield conflicts.Conflict.factory(
3153
c_type, action=action, path=modified_path, file_id=modified_id)
3106
3156
conflicting_path = fp.get_path(conflict[3])
3107
3157
conflicting_id = tt.final_file_id(conflict[3])
3108
yield Conflict.factory(c_type, action=action, path=modified_path,
3109
file_id=modified_id,
3110
conflict_path=conflicting_path,
3111
conflict_file_id=conflicting_id)
3158
yield conflicts.Conflict.factory(
3159
c_type, action=action, path=modified_path,
3160
file_id=modified_id,
3161
conflict_path=conflicting_path,
3162
conflict_file_id=conflicting_id)
3114
3165
class _FileMover(object):