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.
238
228
self._new_root = new_roots[0]
240
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
241
236
# unversion the new root's directory.
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)
237
file_id = self.final_file_id(old_new_root)
246
238
if old_new_root in self._new_id:
247
239
self.cancel_versioning(old_new_root)
252
244
if (self.tree_file_id(self._new_root) is not None and
253
245
self._new_root not in self._removed_id):
254
246
self.unversion_file(self._new_root)
255
if file_id is not None:
256
self.version_file(file_id, self._new_root)
247
self.version_file(file_id, self._new_root)
258
249
# Now move children of new root into old root directory.
259
250
# Ensure all children are registered with the transaction, but don't
393
384
return sorted(FinalPaths(self).get_paths(new_ids))
395
386
def _inventory_altered(self):
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,
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,
414
390
self._new_executability]:
415
changed_ids.update(id_set)
416
# removing implies a kind change
391
new_ids.update(id_set)
417
392
changed_kind = set(self._removed_contents)
419
393
changed_kind.intersection_update(self._new_contents)
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
394
changed_kind.difference_update(new_ids)
423
395
changed_kind = (t for t in changed_kind
424
396
if self.tree_kind(t) != self.final_kind(t))
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))
397
new_ids.update(changed_kind)
398
return sorted(FinalPaths(self).get_paths(new_ids))
435
400
def final_kind(self, trans_id):
436
401
"""Determine the final file kind, after any changes applied.
1208
1172
if self._tree is None:
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
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:
1224
1181
delete_any(self._limbodir)
1225
1182
except OSError:
1274
1231
entries from _limbo_files, because they are now stale.
1276
1233
for trans_id in trans_ids:
1277
old_path = self._limbo_files[trans_id]
1278
self._possibly_stale_limbo_files.add(old_path)
1279
del self._limbo_files[trans_id]
1234
old_path = self._limbo_files.pop(trans_id)
1280
1235
if trans_id not in self._new_contents:
1282
1237
new_path = self._limbo_name(trans_id)
1283
1238
os.rename(old_path, new_path)
1284
self._possibly_stale_limbo_files.remove(old_path)
1285
1239
for descendant in self._limbo_descendants(trans_id):
1286
1240
desc_path = self._limbo_files[descendant]
1287
1241
desc_path = new_path + desc_path[len(old_path):]
1311
1265
name = self._limbo_name(trans_id)
1312
1266
f = open(name, 'wb')
1314
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.
1315
1276
f.writelines(contents)
1829
1788
tree_paths.sort(reverse=True)
1830
1789
child_pb = ui.ui_factory.nested_progress_bar()
1832
for num, (path, trans_id) in enumerate(tree_paths):
1833
# do not attempt to move root into a subdirectory of itself.
1791
for num, data in enumerate(tree_paths):
1792
path, trans_id = data
1836
1793
child_pb.update('removing file', num, len(tree_paths))
1837
1794
full_path = self._tree.abspath(path)
1838
1795
if trans_id in self._removed_contents:
1894
1851
self._observed_sha1s[trans_id] = (o_sha1, st)
1896
1853
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]
1902
1854
self._new_contents.clear()
1903
1855
return modified_paths
2261
def get_file_verifier(self, file_id, path=None, stat_value=None):
2262
trans_id = self._transform.trans_id_file_id(file_id)
2263
kind = self._transform._new_contents.get(trans_id)
2265
return self._transform._tree.get_file_verifier(file_id)
2267
fileobj = self.get_file(file_id)
2269
return ("SHA1", sha_file(fileobj))
2273
2213
def get_file_sha1(self, file_id, path=None, stat_value=None):
2274
2214
trans_id = self._transform.trans_id_file_id(file_id)
2275
2215
kind = self._transform._new_contents.get(trans_id)
2400
2340
self.get_file(file_id).readlines(),
2401
2341
default_revision)
2403
def get_symlink_target(self, file_id, path=None):
2343
def get_symlink_target(self, file_id):
2404
2344
"""See Tree.get_symlink_target"""
2405
2345
if not self._content_change(file_id):
2406
2346
return self._transform._tree.get_symlink_target(file_id)
2988
2928
basis_tree = working_tree.basis_tree()
2989
2929
basis_tree.lock_read()
2990
2930
new_sha1 = target_tree.get_file_sha1(file_id)
2991
if (basis_tree.has_id(file_id) and
2992
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)):
2993
2933
if file_id in merge_modified:
2994
2934
del merge_modified[file_id]
3146
3086
elif c_type == 'unversioned parent':
3147
3087
file_id = tt.inactive_file_id(conflict[1])
3148
3088
# special-case the other tree root (move its children instead)
3149
if path_tree and path_tree.has_id(file_id):
3089
if path_tree and file_id in path_tree:
3150
3090
if path_tree.path2id('') == file_id:
3151
3091
# This is the root entry, skip it
3171
3111
def cook_conflicts(raw_conflicts, tt):
3172
3112
"""Generate a list of cooked conflicts, sorted by file path"""
3113
from bzrlib.conflicts import Conflict
3173
3114
conflict_iter = iter_cook_conflicts(raw_conflicts, tt)
3174
return sorted(conflict_iter, key=conflicts.Conflict.sort_key)
3115
return sorted(conflict_iter, key=Conflict.sort_key)
3177
3118
def iter_cook_conflicts(raw_conflicts, tt):
3119
from bzrlib.conflicts import Conflict
3178
3120
fp = FinalPaths(tt)
3179
3121
for conflict in raw_conflicts:
3180
3122
c_type = conflict[0]
3182
3124
modified_path = fp.get_path(conflict[2])
3183
3125
modified_id = tt.final_file_id(conflict[2])
3184
3126
if len(conflict) == 3:
3185
yield conflicts.Conflict.factory(
3186
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)
3189
3131
conflicting_path = fp.get_path(conflict[3])
3190
3132
conflicting_id = tt.final_file_id(conflict[3])
3191
yield conflicts.Conflict.factory(
3192
c_type, action=action, path=modified_path,
3193
file_id=modified_id,
3194
conflict_path=conflicting_path,
3195
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)
3198
3139
class _FileMover(object):