138
137
# A counter of how many files have been renamed
139
138
self.rename_count = 0
142
"""Support Context Manager API."""
145
def __exit__(self, exc_type, exc_val, exc_tb):
146
"""Support Context Manager API."""
149
140
def finalize(self):
150
141
"""Release the working tree lock, if held.
226
217
This means that the old root trans-id becomes obsolete, so it is
227
218
recommended only to invoke this after the root trans-id has become
231
221
new_roots = [k for k, v in self._new_parent.iteritems() if v is
233
223
if len(new_roots) < 1:
234
if self.final_kind(self.root) is None:
235
self.cancel_deletion(self.root)
236
if self.final_file_id(self.root) is None:
237
self.version_file(self.tree_file_id(self.root),
240
225
if len(new_roots) != 1:
241
226
raise ValueError('A tree cannot have two roots!')
243
228
self._new_root = new_roots[0]
245
230
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
246
236
# unversion the new root's directory.
247
if self.final_kind(self._new_root) is None:
248
file_id = self.final_file_id(old_new_root)
250
file_id = self.final_file_id(self._new_root)
237
file_id = self.final_file_id(old_new_root)
251
238
if old_new_root in self._new_id:
252
239
self.cancel_versioning(old_new_root)
257
244
if (self.tree_file_id(self._new_root) is not None and
258
245
self._new_root not in self._removed_id):
259
246
self.unversion_file(self._new_root)
260
if file_id is not None:
261
self.version_file(file_id, self._new_root)
247
self.version_file(file_id, self._new_root)
263
249
# Now move children of new root into old root directory.
264
250
# Ensure all children are registered with the transaction, but don't
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.
1213
1172
if self._tree is None:
1216
limbo_paths = self._limbo_files.values() + list(
1217
self._possibly_stale_limbo_files)
1218
limbo_paths = sorted(limbo_paths, reverse=True)
1219
for path in limbo_paths:
1223
if e.errno != errno.ENOENT:
1225
# XXX: warn? perhaps we just got interrupted at an
1226
# inconvenient moment, but perhaps files are disappearing
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:
1229
1181
delete_any(self._limbodir)
1230
1182
except OSError:
1279
1231
entries from _limbo_files, because they are now stale.
1281
1233
for trans_id in trans_ids:
1282
old_path = self._limbo_files[trans_id]
1283
self._possibly_stale_limbo_files.add(old_path)
1284
del self._limbo_files[trans_id]
1234
old_path = self._limbo_files.pop(trans_id)
1285
1235
if trans_id not in self._new_contents:
1287
1237
new_path = self._limbo_name(trans_id)
1288
1238
os.rename(old_path, new_path)
1289
self._possibly_stale_limbo_files.remove(old_path)
1290
1239
for descendant in self._limbo_descendants(trans_id):
1291
1240
desc_path = self._limbo_files[descendant]
1292
1241
desc_path = new_path + desc_path[len(old_path):]
1316
1265
name = self._limbo_name(trans_id)
1317
1266
f = open(name, 'wb')
1319
unique_add(self._new_contents, trans_id, 'file')
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.
1320
1276
f.writelines(contents)
1832
1788
tree_paths.sort(reverse=True)
1833
1789
child_pb = ui.ui_factory.nested_progress_bar()
1835
for num, (path, trans_id) in enumerate(tree_paths):
1836
# do not attempt to move root into a subdirectory of itself.
1791
for num, data in enumerate(tree_paths):
1792
path, trans_id = data
1839
1793
child_pb.update('removing file', num, len(tree_paths))
1840
1794
full_path = self._tree.abspath(path)
1841
1795
if trans_id in self._removed_contents:
1897
1851
self._observed_sha1s[trans_id] = (o_sha1, st)
1899
1853
child_pb.finished()
1900
for path, trans_id in new_paths:
1901
# new_paths includes stuff like workingtree conflicts. Only the
1902
# stuff in new_contents actually comes from limbo.
1903
if trans_id in self._limbo_files:
1904
del self._limbo_files[trans_id]
1905
1854
self._new_contents.clear()
1906
1855
return modified_paths
2979
2928
basis_tree = working_tree.basis_tree()
2980
2929
basis_tree.lock_read()
2981
2930
new_sha1 = target_tree.get_file_sha1(file_id)
2982
if (basis_tree.has_id(file_id) and
2983
new_sha1 == basis_tree.get_file_sha1(file_id)):
2931
if (file_id in basis_tree and new_sha1 ==
2932
basis_tree.get_file_sha1(file_id)):
2984
2933
if file_id in merge_modified:
2985
2934
del merge_modified[file_id]
3137
3086
elif c_type == 'unversioned parent':
3138
3087
file_id = tt.inactive_file_id(conflict[1])
3139
3088
# special-case the other tree root (move its children instead)
3140
if path_tree and path_tree.has_id(file_id):
3089
if path_tree and file_id in path_tree:
3141
3090
if path_tree.path2id('') == file_id:
3142
3091
# This is the root entry, skip it
3162
3111
def cook_conflicts(raw_conflicts, tt):
3163
3112
"""Generate a list of cooked conflicts, sorted by file path"""
3113
from bzrlib.conflicts import Conflict
3164
3114
conflict_iter = iter_cook_conflicts(raw_conflicts, tt)
3165
return sorted(conflict_iter, key=conflicts.Conflict.sort_key)
3115
return sorted(conflict_iter, key=Conflict.sort_key)
3168
3118
def iter_cook_conflicts(raw_conflicts, tt):
3119
from bzrlib.conflicts import Conflict
3169
3120
fp = FinalPaths(tt)
3170
3121
for conflict in raw_conflicts:
3171
3122
c_type = conflict[0]
3173
3124
modified_path = fp.get_path(conflict[2])
3174
3125
modified_id = tt.final_file_id(conflict[2])
3175
3126
if len(conflict) == 3:
3176
yield conflicts.Conflict.factory(
3177
c_type, action=action, path=modified_path, file_id=modified_id)
3127
yield Conflict.factory(c_type, action=action, path=modified_path,
3128
file_id=modified_id)
3180
3131
conflicting_path = fp.get_path(conflict[3])
3181
3132
conflicting_id = tt.final_file_id(conflict[3])
3182
yield conflicts.Conflict.factory(
3183
c_type, action=action, path=modified_path,
3184
file_id=modified_id,
3185
conflict_path=conflicting_path,
3186
conflict_file_id=conflicting_id)
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)
3189
3139
class _FileMover(object):