398
384
return sorted(FinalPaths(self).get_paths(new_ids))
400
386
def _inventory_altered(self):
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,
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,
419
390
self._new_executability]:
420
changed_ids.update(id_set)
421
# removing implies a kind change
391
new_ids.update(id_set)
422
392
changed_kind = set(self._removed_contents)
424
393
changed_kind.intersection_update(self._new_contents)
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
394
changed_kind.difference_update(new_ids)
428
395
changed_kind = (t for t in changed_kind
429
396
if self.tree_kind(t) != self.final_kind(t))
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))
397
new_ids.update(changed_kind)
398
return sorted(FinalPaths(self).get_paths(new_ids))
440
400
def final_kind(self, trans_id):
441
401
"""Determine the final file kind, after any changes applied.
1401
1359
delete_any(self._limbo_name(trans_id))
1403
1361
def new_orphan(self, trans_id, parent_id):
1404
conf = self._tree.get_config_stack()
1405
handle_orphan = conf.get('bzr.transform.orphan_policy')
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)
1406
1377
handle_orphan(self, trans_id, parent_id)
2260
2200
def get_file_size(self, file_id):
2261
2201
"""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
2268
2202
if self.kind(file_id) == 'file':
2269
2203
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))
2285
2207
def get_file_sha1(self, file_id, path=None, stat_value=None):
2286
2208
trans_id = self._transform.trans_id_file_id(file_id)
2287
2209
kind = self._transform._new_contents.get(trans_id)
2832
2745
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
2835
2793
def revert(working_tree, target_tree, filenames, backups=False,
2836
2794
pb=None, change_reporter=None):
2837
2795
"""Revert a working tree's contents to those of a target tree."""
2898
2852
deferred_files = []
2899
2853
for id_num, (file_id, path, changed_content, versioned, parent, name,
2900
2854
kind, executable) in enumerate(change_list):
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:
2855
if skip_root and file_id[0] is not None and parent[0] is None:
2909
2857
trans_id = tt.trans_id_file_id(file_id)
2911
2859
if changed_content:
2912
2860
keep_content = False
2913
if wt_kind == 'file' and (backups or target_kind is None):
2861
if kind[0] == 'file' and (backups or kind[1] is None):
2914
2862
wt_sha1 = working_tree.get_file_sha1(file_id)
2915
2863
if merge_modified.get(file_id) != wt_sha1:
2916
2864
# acquire the basis tree lazily to prevent the
2919
2867
if basis_tree is None:
2920
2868
basis_tree = working_tree.basis_tree()
2921
2869
basis_tree.lock_read()
2922
if basis_tree.has_id(file_id):
2870
if file_id in basis_tree:
2923
2871
if wt_sha1 != basis_tree.get_file_sha1(file_id):
2924
2872
keep_content = True
2925
elif target_kind is None and not target_versioned:
2873
elif kind[1] is None and not versioned[1]:
2926
2874
keep_content = True
2927
if wt_kind is not None:
2875
if kind[0] is not None:
2928
2876
if not keep_content:
2929
2877
tt.delete_contents(trans_id)
2930
elif target_kind is not None:
2931
parent_trans_id = tt.trans_id_file_id(wt_parent)
2878
elif kind[1] is not None:
2879
parent_trans_id = tt.trans_id_file_id(parent[0])
2932
2880
backup_name = tt._available_backup_name(
2933
wt_name, parent_trans_id)
2881
name[0], parent_trans_id)
2934
2882
tt.adjust_path(backup_name, parent_trans_id, trans_id)
2935
new_trans_id = tt.create_path(wt_name, parent_trans_id)
2936
if wt_versioned and target_versioned:
2883
new_trans_id = tt.create_path(name[0], parent_trans_id)
2884
if versioned == (True, True):
2937
2885
tt.unversion_file(trans_id)
2938
2886
tt.version_file(file_id, new_trans_id)
2939
2887
# New contents should have the same unix perms as old
2941
2889
mode_id = trans_id
2942
2890
trans_id = new_trans_id
2943
if target_kind in ('directory', 'tree-reference'):
2891
if kind[1] in ('directory', 'tree-reference'):
2944
2892
tt.create_directory(trans_id)
2945
if target_kind == 'tree-reference':
2893
if kind[1] == 'tree-reference':
2946
2894
revision = target_tree.get_reference_revision(file_id,
2948
2896
tt.set_tree_reference(revision, trans_id)
2949
elif target_kind == 'symlink':
2897
elif kind[1] == 'symlink':
2950
2898
tt.create_symlink(target_tree.get_symlink_target(file_id),
2952
elif target_kind == 'file':
2900
elif kind[1] == 'file':
2953
2901
deferred_files.append((file_id, (trans_id, mode_id)))
2954
2902
if basis_tree is None:
2955
2903
basis_tree = working_tree.basis_tree()
2956
2904
basis_tree.lock_read()
2957
2905
new_sha1 = target_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)):
2906
if (file_id in basis_tree and new_sha1 ==
2907
basis_tree.get_file_sha1(file_id)):
2960
2908
if file_id in merge_modified:
2961
2909
del merge_modified[file_id]
2963
2911
merge_modified[file_id] = new_sha1
2965
2913
# preserve the execute bit when backing up
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:
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):
2971
2919
tt.version_file(file_id, trans_id)
2972
if wt_versioned and not target_versioned:
2920
if versioned == (True, False):
2973
2921
tt.unversion_file(trans_id)
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:
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:
2977
2925
parent_trans = ROOT_PARENT
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)
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)
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)
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)
2986
2934
if working_tree.supports_content_filtering():
2987
2935
for index, ((trans_id, mode_id), bytes) in enumerate(
2988
2936
target_tree.iter_files_bytes(deferred_files)):
3149
3099
modified_path = fp.get_path(conflict[2])
3150
3100
modified_id = tt.final_file_id(conflict[2])
3151
3101
if len(conflict) == 3:
3152
yield conflicts.Conflict.factory(
3153
c_type, action=action, path=modified_path, file_id=modified_id)
3102
yield Conflict.factory(c_type, action=action, path=modified_path,
3103
file_id=modified_id)
3156
3106
conflicting_path = fp.get_path(conflict[3])
3157
3107
conflicting_id = tt.final_file_id(conflict[3])
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)
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)
3165
3114
class _FileMover(object):