163
162
def adjust_path(self, name, parent, trans_id):
164
163
"""Change the path that is assigned to a transaction id."""
166
raise ValueError("Parent trans-id may not be None")
167
164
if trans_id == self._new_root:
168
165
raise CantMoveRoot
169
166
self._new_name[trans_id] = name
170
167
self._new_parent[trans_id] = parent
168
if parent == ROOT_PARENT:
169
if self._new_root is not None:
170
raise ValueError("Cannot have multiple roots.")
171
self._new_root = trans_id
172
173
def adjust_root_path(self, name, parent):
173
174
"""Emulate moving the root by moving all children, instead.
201
202
self.version_file(old_root_file_id, old_root)
202
203
self.unversion_file(self._new_root)
204
def fixup_new_roots(self):
205
"""Reinterpret requests to change the root directory
207
Instead of creating a root directory, or moving an existing directory,
208
all the attributes and children of the new root are applied to the
209
existing root directory.
211
This means that the old root trans-id becomes obsolete, so it is
212
recommended only to invoke this after the root trans-id has become
215
new_roots = [k for k, v in self._new_parent.iteritems() if v is
217
if len(new_roots) < 1:
219
if len(new_roots) != 1:
220
raise ValueError('A tree cannot have two roots!')
221
if self._new_root is None:
222
self._new_root = new_roots[0]
224
old_new_root = new_roots[0]
225
# TODO: What to do if a old_new_root is present, but self._new_root is
226
# not listed as being removed? This code explicitly unversions
227
# the old root and versions it with the new file_id. Though that
228
# seems like an incomplete delta
230
# unversion the new root's directory.
231
file_id = self.final_file_id(old_new_root)
232
if old_new_root in self._new_id:
233
self.cancel_versioning(old_new_root)
235
self.unversion_file(old_new_root)
236
# if, at this stage, root still has an old file_id, zap it so we can
237
# stick a new one in.
238
if (self.tree_file_id(self._new_root) is not None and
239
self._new_root not in self._removed_id):
240
self.unversion_file(self._new_root)
241
self.version_file(file_id, self._new_root)
243
# Now move children of new root into old root directory.
244
# Ensure all children are registered with the transaction, but don't
245
# use directly-- some tree children have new parents
246
list(self.iter_tree_children(old_new_root))
247
# Move all children of new root into old root directory.
248
for child in self.by_parent().get(old_new_root, []):
249
self.adjust_path(self.final_name(child), self._new_root, child)
251
# Ensure old_new_root has no directory.
252
if old_new_root in self._new_contents:
253
self.cancel_creation(old_new_root)
255
self.delete_contents(old_new_root)
257
# prevent deletion of root directory.
258
if self._new_root in self._removed_contents:
259
self.cancel_deletion(self._new_root)
261
# destroy path info for old_new_root.
262
del self._new_parent[old_new_root]
263
del self._new_name[old_new_root]
265
205
def trans_id_tree_file_id(self, inventory_id):
266
206
"""Determine the transaction id of a working tree file.
1138
1075
if (trans_id in self._limbo_files and
1139
1076
trans_id not in self._needs_rename):
1140
1077
self._rename_in_limbo([trans_id])
1141
if previous_parent != parent:
1142
self._limbo_children[previous_parent].remove(trans_id)
1143
if previous_parent != parent or previous_name != name:
1144
del self._limbo_children_names[previous_parent][previous_name]
1078
self._limbo_children[previous_parent].remove(trans_id)
1079
del self._limbo_children_names[previous_parent][previous_name]
1146
1081
def _rename_in_limbo(self, trans_ids):
1147
1082
"""Fix limbo names so that the right final path is produced.
1211
1145
def _read_symlink_target(self, trans_id):
1212
1146
return os.readlink(self._limbo_name(trans_id))
1214
def _set_mtime(self, path):
1215
"""All files that are created get the same mtime.
1217
This time is set by the first object to be created.
1219
if self._creation_mtime is None:
1220
self._creation_mtime = time.time()
1221
os.utime(path, (self._creation_mtime, self._creation_mtime))
1223
1148
def create_hardlink(self, path, trans_id):
1224
1149
"""Schedule creation of a hard link"""
1225
1150
name = self._limbo_name(trans_id)
1628
1553
child_pb.update('removing file', num, len(tree_paths))
1629
1554
full_path = self._tree.abspath(path)
1630
1555
if trans_id in self._removed_contents:
1631
delete_path = os.path.join(self._deletiondir, trans_id)
1632
mover.pre_delete(full_path, delete_path)
1633
elif (trans_id in self._new_name
1634
or trans_id in self._new_parent):
1556
mover.pre_delete(full_path, os.path.join(self._deletiondir,
1558
elif trans_id in self._new_name or trans_id in \
1636
1561
mover.rename(full_path, self._limbo_name(trans_id))
1637
1562
except OSError, e:
2375
2300
new_desired_files = desired_files
2377
2302
iter = accelerator_tree.iter_changes(tree, include_unchanged=True)
2378
unchanged = [(f, p[1]) for (f, p, c, v, d, n, k, e)
2379
in iter if not (c or e[0] != e[1])]
2380
if accelerator_tree.supports_content_filtering():
2381
unchanged = [(f, p) for (f, p) in unchanged
2382
if not accelerator_tree.iter_search_rules([p]).next()]
2383
unchanged = dict(unchanged)
2303
unchanged = dict((f, p[1]) for (f, p, c, v, d, n, k, e)
2304
in iter if not (c or e[0] != e[1]))
2384
2305
new_desired_files = []
2386
2307
for file_id, (trans_id, tree_path) in desired_files:
2509
2430
tt.create_directory(trans_id)
2512
def create_from_tree(tt, trans_id, tree, file_id, bytes=None,
2513
filter_tree_path=None):
2514
"""Create new file contents according to tree contents.
2516
:param filter_tree_path: the tree path to use to lookup
2517
content filters to apply to the bytes output in the working tree.
2518
This only applies if the working tree supports content filtering.
2433
def create_from_tree(tt, trans_id, tree, file_id, bytes=None):
2434
"""Create new file contents according to tree contents."""
2520
2435
kind = tree.kind(file_id)
2521
2436
if kind == 'directory':
2522
2437
tt.create_directory(trans_id)
2527
2442
bytes = tree_file.readlines()
2529
2444
tree_file.close()
2531
if wt.supports_content_filtering() and filter_tree_path is not None:
2532
filters = wt._content_filter_stack(filter_tree_path)
2533
bytes = filtered_output_bytes(bytes, filters,
2534
ContentFilterContext(filter_tree_path, tree))
2535
2445
tt.create_file(bytes, trans_id)
2536
2446
elif kind == "symlink":
2537
2447
tt.create_symlink(tree.get_symlink_target(file_id), trans_id)
2725
2635
parent_trans = ROOT_PARENT
2727
2637
parent_trans = tt.trans_id_file_id(parent[1])
2728
if parent[0] is None and versioned[0]:
2729
tt.adjust_root_path(name[1], parent_trans)
2731
tt.adjust_path(name[1], parent_trans, trans_id)
2638
tt.adjust_path(name[1], parent_trans, trans_id)
2732
2639
if executable[0] != executable[1] and kind[1] == "file":
2733
2640
tt.set_executability(executable[1], trans_id)
2734
2641
if working_tree.supports_content_filtering():