129
128
# Cache of relpath results, to speed up canonical_path
130
129
self._relpaths = {}
131
130
# The trans_id that will be used as the tree root
132
self._new_root = self.trans_id_tree_file_id(tree.get_root_id())
131
root_id = tree.get_root_id()
132
if root_id is not None:
133
self._new_root = self.trans_id_tree_file_id(root_id)
135
self._new_root = None
133
136
# Indictor of whether the transform has been applied
134
137
self._done = False
196
199
previous_name = self._new_name.get(trans_id)
197
200
self._new_name[trans_id] = name
198
201
self._new_parent[trans_id] = parent
202
if parent == ROOT_PARENT:
203
if self._new_root is not None:
204
raise ValueError("Cannot have multiple roots.")
205
self._new_root = trans_id
199
206
if (trans_id in self._limbo_files and
200
207
trans_id not in self._needs_rename):
201
208
self._rename_in_limbo([trans_id])
258
265
This reflects only files that already exist, not ones that will be
259
266
added by transactions.
268
if inventory_id is None:
269
raise ValueError('None is not a valid file id')
261
270
path = self._tree.id2path(inventory_id)
262
271
return self.trans_id_tree_path(path)
267
276
a transaction has been unversioned, it is deliberately still returned.
268
277
(this will likely lead to an unversioned parent conflict.)
280
raise ValueError('None is not a valid file id')
270
281
if file_id in self._r_new_id and self._r_new_id[file_id] is not None:
271
282
return self._r_new_id[file_id]
272
283
elif file_id in self._tree.inventory:
1325
1336
tree_paths = list(self._tree_path_ids.iteritems())
1326
1337
tree_paths.sort(reverse=True)
1327
kind_changes = set()
1328
1338
child_pb = bzrlib.ui.ui_factory.nested_progress_bar()
1330
1340
for num, data in enumerate(tree_paths):
1357
1366
If inventory_delta is None, no inventory delta is calculated, and
1358
1367
no list of modified paths is returned.
1360
kind_changes is a set of trans ids where the entry has changed
1361
kind, and so an inventory delta entry should be created for them.
1363
1369
new_paths = self.new_paths(filesystem_only=True)
1364
1370
modified_paths = []
1402
1408
def __init__(self, tree, pb=DummyProgress(), case_sensitive=True):
1403
1409
tree.lock_read()
1404
limbodir = tempfile.mkdtemp(prefix='bzr-limbo-')
1410
limbodir = osutils.mkdtemp(prefix='bzr-limbo-')
1405
1411
TreeTransformBase.__init__(self, tree, limbodir, pb, case_sensitive)
1407
1413
def canonical_path(self, path):
1526
1532
for (file_id, paths, changed, versioned, parent, name, kind,
1527
1533
executable) in self._transform.iter_changes():
1528
1534
if paths[1] in to_find:
1529
result.append(file_id)
1530
1536
to_find.remove(paths[1])
1531
1537
result.update(self._transform._tree.paths2ids(to_find,
1532
1538
trees=[], require_versioned=require_versioned))
1579
1585
parent_file_id, file_id)
1580
1586
yield new_entry, trans_id
1582
def iter_entries_by_dir(self, specific_file_ids=None):
1583
# This may not be a maximally efficient implementation, but it is
1584
# reasonably straightforward. An implementation that grafts the
1585
# TreeTransform changes onto the tree's iter_entries_by_dir results
1586
# might be more efficient, but requires tricky inferences about stack
1588
def _list_files_by_dir(self):
1588
1589
todo = [ROOT_PARENT]
1589
1590
ordered_ids = []
1590
1591
while len(todo) > 0:
1596
1597
todo.extend(reversed(children))
1597
1598
for trans_id in children:
1598
1599
ordered_ids.append((trans_id, parent_file_id))
1602
def iter_entries_by_dir(self, specific_file_ids=None):
1603
# This may not be a maximally efficient implementation, but it is
1604
# reasonably straightforward. An implementation that grafts the
1605
# TreeTransform changes onto the tree's iter_entries_by_dir results
1606
# might be more efficient, but requires tricky inferences about stack
1608
ordered_ids = self._list_files_by_dir()
1599
1609
for entry, trans_id in self._make_inv_entries(ordered_ids,
1600
1610
specific_file_ids):
1601
1611
yield unicode(self._final_paths.get_path(trans_id)), entry
1613
def list_files(self, include_root=False):
1614
"""See Tree.list_files."""
1615
# XXX This should behave like WorkingTree.list_files, but is really
1616
# more like RevisionTree.list_files.
1617
for path, entry in self.iter_entries_by_dir():
1618
if entry.name == '' and not include_root:
1620
yield path, 'V', entry.kind, entry.file_id, entry
1603
1622
def kind(self, file_id):
1604
1623
trans_id = self._transform.trans_id_file_id(file_id)
1605
1624
return self._transform.final_kind(trans_id)
1731
1750
name = self._transform._limbo_name(trans_id)
1732
1751
return os.readlink(name)
1734
def list_files(self, include_root=False):
1735
return self._transform._tree.list_files(include_root)
1737
def walkdirs(self, prefix=""):
1738
return self._transform._tree.walkdirs(prefix)
1753
def walkdirs(self, prefix=''):
1754
pending = [self._transform.root]
1755
while len(pending) > 0:
1756
parent_id = pending.pop()
1759
prefix = prefix.rstrip('/')
1760
parent_path = self._final_paths.get_path(parent_id)
1761
parent_file_id = self._transform.final_file_id(parent_id)
1762
for child_id in self._all_children(parent_id):
1763
path_from_root = self._final_paths.get_path(child_id)
1764
basename = self._transform.final_name(child_id)
1765
file_id = self._transform.final_file_id(child_id)
1767
kind = self._transform.final_kind(child_id)
1768
versioned_kind = kind
1771
versioned_kind = self._transform._tree.stored_kind(file_id)
1772
if versioned_kind == 'directory':
1773
subdirs.append(child_id)
1774
children.append((path_from_root, basename, kind, None,
1775
file_id, versioned_kind))
1777
if parent_path.startswith(prefix):
1778
yield (parent_path, parent_file_id), children
1779
pending.extend(sorted(subdirs, key=self._final_paths.get_path,
1740
1782
def get_parent_ids(self):
1741
1783
return self._parent_ids
2121
2163
tt = TreeTransform(working_tree, pb)
2123
2165
pp = ProgressPhase("Revert phase", 3, pb)
2125
child_pb = bzrlib.ui.ui_factory.nested_progress_bar()
2127
merge_modified = _alter_files(working_tree, target_tree, tt,
2128
child_pb, filenames, backups)
2132
child_pb = bzrlib.ui.ui_factory.nested_progress_bar()
2134
raw_conflicts = resolve_conflicts(tt, child_pb,
2135
lambda t, c: conflict_pass(t, c, target_tree))
2138
conflicts = cook_conflicts(raw_conflicts, tt)
2166
conflicts, merge_modified = _prepare_revert_transform(
2167
working_tree, target_tree, tt, filenames, backups, pp)
2139
2168
if change_reporter:
2140
2169
change_reporter = delta._ChangeReporter(
2141
2170
unversioned_filter=working_tree.is_ignored)
2152
2181
return conflicts
2184
def _prepare_revert_transform(working_tree, target_tree, tt, filenames,
2185
backups, pp, basis_tree=None,
2186
merge_modified=None):
2188
child_pb = bzrlib.ui.ui_factory.nested_progress_bar()
2190
if merge_modified is None:
2191
merge_modified = working_tree.merge_modified()
2192
merge_modified = _alter_files(working_tree, target_tree, tt,
2193
child_pb, filenames, backups,
2194
merge_modified, basis_tree)
2198
child_pb = bzrlib.ui.ui_factory.nested_progress_bar()
2200
raw_conflicts = resolve_conflicts(tt, child_pb,
2201
lambda t, c: conflict_pass(t, c, target_tree))
2204
conflicts = cook_conflicts(raw_conflicts, tt)
2205
return conflicts, merge_modified
2155
2208
def _alter_files(working_tree, target_tree, tt, pb, specific_files,
2157
merge_modified = working_tree.merge_modified()
2209
backups, merge_modified, basis_tree=None):
2210
if basis_tree is not None:
2211
basis_tree.lock_read()
2158
2212
change_list = target_tree.iter_changes(working_tree,
2159
2213
specific_files=specific_files, pb=pb)
2160
if target_tree.inventory.root is None:
2214
if target_tree.get_root_id() is None:
2161
2215
skip_root = True
2163
2217
skip_root = False
2166
2219
deferred_files = []
2167
2220
for id_num, (file_id, path, changed_content, versioned, parent, name,
2204
2257
mode_id = trans_id
2205
2258
trans_id = new_trans_id
2206
if kind[1] == 'directory':
2259
if kind[1] in ('directory', 'tree-reference'):
2207
2260
tt.create_directory(trans_id)
2261
if kind[1] == 'tree-reference':
2262
revision = target_tree.get_reference_revision(file_id,
2264
tt.set_tree_reference(revision, trans_id)
2208
2265
elif kind[1] == 'symlink':
2209
2266
tt.create_symlink(target_tree.get_symlink_target(file_id),
2230
2287
tt.version_file(file_id, trans_id)
2231
2288
if versioned == (True, False):
2232
2289
tt.unversion_file(trans_id)
2233
if (name[1] is not None and
2290
if (name[1] is not None and
2234
2291
(name[0] != name[1] or parent[0] != parent[1])):
2236
name[1], tt.trans_id_file_id(parent[1]), trans_id)
2292
if name[1] == '' and parent[1] is None:
2293
parent_trans = ROOT_PARENT
2295
parent_trans = tt.trans_id_file_id(parent[1])
2296
tt.adjust_path(name[1], parent_trans, trans_id)
2237
2297
if executable[0] != executable[1] and kind[1] == "file":
2238
2298
tt.set_executability(executable[1], trans_id)
2239
2299
for (trans_id, mode_id), bytes in target_tree.iter_files_bytes(
2347
2407
if parent_file_id is not None:
2348
2408
tt.unversion_file(parent_id)
2349
2409
new_conflicts.add((c_type, 'Created directory', new_parent_id))
2410
elif c_type == 'versioning no contents':
2411
tt.cancel_versioning(conflict[1])
2350
2412
return new_conflicts