137
138
# A counter of how many files have been renamed
138
139
self.rename_count = 0
142
"""Support Context Manager API."""
145
def __exit__(self, exc_type, exc_val, exc_tb):
146
"""Support Context Manager API."""
140
149
def finalize(self):
141
150
"""Release the working tree lock, if held.
228
238
self._new_root = new_roots[0]
230
240
old_new_root = new_roots[0]
231
# TODO: What to do if a old_new_root is present, but self._new_root is
232
# not listed as being removed? This code explicitly unversions
233
# the old root and versions it with the new file_id. Though that
234
# seems like an incomplete delta
236
241
# unversion the new root's directory.
237
file_id = self.final_file_id(old_new_root)
242
if self.final_kind(self._new_root) is None:
243
file_id = self.final_file_id(old_new_root)
245
file_id = self.final_file_id(self._new_root)
238
246
if old_new_root in self._new_id:
239
247
self.cancel_versioning(old_new_root)
244
252
if (self.tree_file_id(self._new_root) is not None and
245
253
self._new_root not in self._removed_id):
246
254
self.unversion_file(self._new_root)
247
self.version_file(file_id, self._new_root)
255
if file_id is not None:
256
self.version_file(file_id, self._new_root)
249
258
# Now move children of new root into old root directory.
250
259
# Ensure all children are registered with the transaction, but don't
384
393
return sorted(FinalPaths(self).get_paths(new_ids))
386
395
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,
396
"""Determine which trans_ids need new Inventory entries.
398
An new entry is needed when anything that would be reflected by an
399
inventory entry changes, including file name, file_id, parent file_id,
400
file kind, and the execute bit.
402
Some care is taken to return entries with real changes, not cases
403
where the value is deleted and then restored to its original value,
404
but some actually unchanged values may be returned.
406
:returns: A list of (path, trans_id) for all items requiring an
407
inventory change. Ordered by path.
410
# Find entries whose file_ids are new (or changed).
411
new_file_id = set(t for t in self._new_id
412
if self._new_id[t] != self.tree_file_id(t))
413
for id_set in [self._new_name, self._new_parent, new_file_id,
390
414
self._new_executability]:
391
new_ids.update(id_set)
415
changed_ids.update(id_set)
416
# removing implies a kind change
392
417
changed_kind = set(self._removed_contents)
393
419
changed_kind.intersection_update(self._new_contents)
394
changed_kind.difference_update(new_ids)
420
# Ignore entries that are already known to have changed.
421
changed_kind.difference_update(changed_ids)
422
# to keep only the truly changed ones
395
423
changed_kind = (t for t in changed_kind
396
424
if self.tree_kind(t) != self.final_kind(t))
397
new_ids.update(changed_kind)
398
return sorted(FinalPaths(self).get_paths(new_ids))
425
# all kind changes will alter the inventory
426
changed_ids.update(changed_kind)
427
# To find entries with changed parent_ids, find parents which existed,
428
# but changed file_id.
429
changed_file_id = set(t for t in new_file_id if t in self._removed_id)
430
# Now add all their children to the set.
431
for parent_trans_id in new_file_id:
432
changed_ids.update(self.iter_tree_children(parent_trans_id))
433
return sorted(FinalPaths(self).get_paths(changed_ids))
400
435
def final_kind(self, trans_id):
401
436
"""Determine the final file kind, after any changes applied.
1172
1208
if self._tree is None:
1175
entries = [(self._limbo_name(t), t, k) for t, k in
1176
self._new_contents.iteritems()]
1177
entries.sort(reverse=True)
1178
for path, trans_id, kind in entries:
1211
limbo_paths = self._limbo_files.values() + list(
1212
self._possibly_stale_limbo_files)
1213
limbo_paths = sorted(limbo_paths, reverse=True)
1214
for path in limbo_paths:
1218
if e.errno != errno.ENOENT:
1220
# XXX: warn? perhaps we just got interrupted at an
1221
# inconvenient moment, but perhaps files are disappearing
1181
1224
delete_any(self._limbodir)
1182
1225
except OSError:
1231
1274
entries from _limbo_files, because they are now stale.
1233
1276
for trans_id in trans_ids:
1234
old_path = self._limbo_files.pop(trans_id)
1277
old_path = self._limbo_files[trans_id]
1278
self._possibly_stale_limbo_files.add(old_path)
1279
del self._limbo_files[trans_id]
1235
1280
if trans_id not in self._new_contents:
1237
1282
new_path = self._limbo_name(trans_id)
1238
1283
os.rename(old_path, new_path)
1284
self._possibly_stale_limbo_files.remove(old_path)
1239
1285
for descendant in self._limbo_descendants(trans_id):
1240
1286
desc_path = self._limbo_files[descendant]
1241
1287
desc_path = new_path + desc_path[len(old_path):]
1265
1311
name = self._limbo_name(trans_id)
1266
1312
f = open(name, 'wb')
1269
unique_add(self._new_contents, trans_id, 'file')
1271
# Clean up the file, it never got registered so
1272
# TreeTransform.finalize() won't clean it up.
1314
unique_add(self._new_contents, trans_id, 'file')
1276
1315
f.writelines(contents)
1788
1829
tree_paths.sort(reverse=True)
1789
1830
child_pb = ui.ui_factory.nested_progress_bar()
1791
for num, data in enumerate(tree_paths):
1792
path, trans_id = data
1832
for num, (path, trans_id) in enumerate(tree_paths):
1833
# do not attempt to move root into a subdirectory of itself.
1793
1836
child_pb.update('removing file', num, len(tree_paths))
1794
1837
full_path = self._tree.abspath(path)
1795
1838
if trans_id in self._removed_contents:
1851
1894
self._observed_sha1s[trans_id] = (o_sha1, st)
1853
1896
child_pb.finished()
1897
for path, trans_id in new_paths:
1898
# new_paths includes stuff like workingtree conflicts. Only the
1899
# stuff in new_contents actually comes from limbo.
1900
if trans_id in self._limbo_files:
1901
del self._limbo_files[trans_id]
1854
1902
self._new_contents.clear()
1855
1903
return modified_paths
2928
2976
basis_tree = working_tree.basis_tree()
2929
2977
basis_tree.lock_read()
2930
2978
new_sha1 = target_tree.get_file_sha1(file_id)
2931
if (file_id in basis_tree and new_sha1 ==
2932
basis_tree.get_file_sha1(file_id)):
2979
if (basis_tree.has_id(file_id) and
2980
new_sha1 == basis_tree.get_file_sha1(file_id)):
2933
2981
if file_id in merge_modified:
2934
2982
del merge_modified[file_id]
3086
3134
elif c_type == 'unversioned parent':
3087
3135
file_id = tt.inactive_file_id(conflict[1])
3088
3136
# special-case the other tree root (move its children instead)
3089
if path_tree and file_id in path_tree:
3137
if path_tree and path_tree.has_id(file_id):
3090
3138
if path_tree.path2id('') == file_id:
3091
3139
# This is the root entry, skip it
3111
3159
def cook_conflicts(raw_conflicts, tt):
3112
3160
"""Generate a list of cooked conflicts, sorted by file path"""
3113
from bzrlib.conflicts import Conflict
3114
3161
conflict_iter = iter_cook_conflicts(raw_conflicts, tt)
3115
return sorted(conflict_iter, key=Conflict.sort_key)
3162
return sorted(conflict_iter, key=conflicts.Conflict.sort_key)
3118
3165
def iter_cook_conflicts(raw_conflicts, tt):
3119
from bzrlib.conflicts import Conflict
3120
3166
fp = FinalPaths(tt)
3121
3167
for conflict in raw_conflicts:
3122
3168
c_type = conflict[0]
3124
3170
modified_path = fp.get_path(conflict[2])
3125
3171
modified_id = tt.final_file_id(conflict[2])
3126
3172
if len(conflict) == 3:
3127
yield Conflict.factory(c_type, action=action, path=modified_path,
3128
file_id=modified_id)
3173
yield conflicts.Conflict.factory(
3174
c_type, action=action, path=modified_path, file_id=modified_id)
3131
3177
conflicting_path = fp.get_path(conflict[3])
3132
3178
conflicting_id = tt.final_file_id(conflict[3])
3133
yield Conflict.factory(c_type, action=action, path=modified_path,
3134
file_id=modified_id,
3135
conflict_path=conflicting_path,
3136
conflict_file_id=conflicting_id)
3179
yield conflicts.Conflict.factory(
3180
c_type, action=action, path=modified_path,
3181
file_id=modified_id,
3182
conflict_path=conflicting_path,
3183
conflict_file_id=conflicting_id)
3139
3186
class _FileMover(object):