164
198
def adjust_path(self, name, parent, trans_id):
165
199
"""Change the path that is assigned to a transaction id."""
167
raise ValueError("Parent trans-id may not be None")
168
200
if trans_id == self._new_root:
169
201
raise CantMoveRoot
202
previous_parent = self._new_parent.get(trans_id)
203
previous_name = self._new_name.get(trans_id)
170
204
self._new_name[trans_id] = name
171
205
self._new_parent[trans_id] = parent
206
if parent == ROOT_PARENT:
207
if self._new_root is not None:
208
raise ValueError("Cannot have multiple roots.")
209
self._new_root = trans_id
210
if (trans_id in self._limbo_files and
211
trans_id not in self._needs_rename):
212
self._rename_in_limbo([trans_id])
213
self._limbo_children[previous_parent].remove(trans_id)
214
del self._limbo_children_names[previous_parent][previous_name]
216
def _rename_in_limbo(self, trans_ids):
217
"""Fix limbo names so that the right final path is produced.
219
This means we outsmarted ourselves-- we tried to avoid renaming
220
these files later by creating them with their final names in their
221
final parents. But now the previous name or parent is no longer
222
suitable, so we have to rename them.
224
Even for trans_ids that have no new contents, we must remove their
225
entries from _limbo_files, because they are now stale.
227
for trans_id in trans_ids:
228
old_path = self._limbo_files.pop(trans_id)
229
if trans_id not in self._new_contents:
231
new_path = self._limbo_name(trans_id)
232
os.rename(old_path, new_path)
173
234
def adjust_root_path(self, name, parent):
174
235
"""Emulate moving the root by moving all children, instead.
202
263
self.version_file(old_root_file_id, old_root)
203
264
self.unversion_file(self._new_root)
205
def fixup_new_roots(self):
206
"""Reinterpret requests to change the root directory
208
Instead of creating a root directory, or moving an existing directory,
209
all the attributes and children of the new root are applied to the
210
existing root directory.
212
This means that the old root trans-id becomes obsolete, so it is
213
recommended only to invoke this after the root trans-id has become
216
new_roots = [k for k, v in self._new_parent.iteritems() if v is
218
if len(new_roots) < 1:
220
if len(new_roots) != 1:
221
raise ValueError('A tree cannot have two roots!')
222
if self._new_root is None:
223
self._new_root = new_roots[0]
225
old_new_root = new_roots[0]
226
# TODO: What to do if a old_new_root is present, but self._new_root is
227
# not listed as being removed? This code explicitly unversions
228
# the old root and versions it with the new file_id. Though that
229
# seems like an incomplete delta
231
# unversion the new root's directory.
232
file_id = self.final_file_id(old_new_root)
233
if old_new_root in self._new_id:
234
self.cancel_versioning(old_new_root)
236
self.unversion_file(old_new_root)
237
# if, at this stage, root still has an old file_id, zap it so we can
238
# stick a new one in.
239
if (self.tree_file_id(self._new_root) is not None and
240
self._new_root not in self._removed_id):
241
self.unversion_file(self._new_root)
242
self.version_file(file_id, self._new_root)
244
# Now move children of new root into old root directory.
245
# Ensure all children are registered with the transaction, but don't
246
# use directly-- some tree children have new parents
247
list(self.iter_tree_children(old_new_root))
248
# Move all children of new root into old root directory.
249
for child in self.by_parent().get(old_new_root, []):
250
self.adjust_path(self.final_name(child), self._new_root, child)
252
# Ensure old_new_root has no directory.
253
if old_new_root in self._new_contents:
254
self.cancel_creation(old_new_root)
256
self.delete_contents(old_new_root)
258
# prevent deletion of root directory.
259
if self._new_root in self._removed_contents:
260
self.cancel_deletion(self._new_root)
262
# destroy path info for old_new_root.
263
del self._new_parent[old_new_root]
264
del self._new_name[old_new_root]
266
266
def trans_id_tree_file_id(self, inventory_id):
267
267
"""Determine the transaction id of a working tree file.
312
331
return ROOT_PARENT
313
332
return self.trans_id_tree_path(os.path.dirname(path))
334
def create_file(self, contents, trans_id, mode_id=None):
335
"""Schedule creation of a new file.
339
Contents is an iterator of strings, all of which will be written
340
to the target destination.
342
New file takes the permissions of any existing file with that id,
343
unless mode_id is specified.
345
name = self._limbo_name(trans_id)
349
unique_add(self._new_contents, trans_id, 'file')
351
# Clean up the file, it never got registered so
352
# TreeTransform.finalize() won't clean it up.
357
f.writelines(contents)
360
self._set_mode(trans_id, mode_id, S_ISREG)
362
def _set_mode(self, trans_id, mode_id, typefunc):
363
"""Set the mode of new file contents.
364
The mode_id is the existing file to get the mode from (often the same
365
as trans_id). The operation is only performed if there's a mode match
366
according to typefunc.
371
old_path = self._tree_id_paths[mode_id]
375
mode = os.stat(self._tree.abspath(old_path)).st_mode
377
if e.errno in (errno.ENOENT, errno.ENOTDIR):
378
# Either old_path doesn't exist, or the parent of the
379
# target is not a directory (but will be one eventually)
380
# Either way, we know it doesn't exist *right now*
381
# See also bug #248448
386
os.chmod(self._limbo_name(trans_id), mode)
388
def create_hardlink(self, path, trans_id):
389
"""Schedule creation of a hard link"""
390
name = self._limbo_name(trans_id)
394
if e.errno != errno.EPERM:
396
raise errors.HardLinkNotSupported(path)
398
unique_add(self._new_contents, trans_id, 'file')
400
# Clean up the file, it never got registered so
401
# TreeTransform.finalize() won't clean it up.
405
def create_directory(self, trans_id):
406
"""Schedule creation of a new directory.
408
See also new_directory.
410
os.mkdir(self._limbo_name(trans_id))
411
unique_add(self._new_contents, trans_id, 'directory')
413
def create_symlink(self, target, trans_id):
414
"""Schedule creation of a new symbolic link.
416
target is a bytestring.
417
See also new_symlink.
420
os.symlink(target, self._limbo_name(trans_id))
421
unique_add(self._new_contents, trans_id, 'symlink')
424
path = FinalPaths(self).get_path(trans_id)
427
raise UnableCreateSymlink(path=path)
429
def cancel_creation(self, trans_id):
430
"""Cancel the creation of new file contents."""
431
del self._new_contents[trans_id]
432
children = self._limbo_children.get(trans_id)
433
# if this is a limbo directory with children, move them before removing
435
if children is not None:
436
self._rename_in_limbo(children)
437
del self._limbo_children[trans_id]
438
del self._limbo_children_names[trans_id]
439
delete_any(self._limbo_name(trans_id))
315
441
def delete_contents(self, trans_id):
316
442
"""Schedule the contents of a path entry for deletion"""
317
# Ensure that the object exists in the WorkingTree, this will raise an
318
# exception if there is a problem
319
443
self.tree_kind(trans_id)
320
444
self._removed_contents.add(trans_id)
869
def _limbo_name(self, trans_id):
870
"""Generate the limbo name of a file"""
871
limbo_name = self._limbo_files.get(trans_id)
872
if limbo_name is not None:
874
parent = self._new_parent.get(trans_id)
875
# if the parent directory is already in limbo (e.g. when building a
876
# tree), choose a limbo name inside the parent, to reduce further
878
use_direct_path = False
879
if self._new_contents.get(parent) == 'directory':
880
filename = self._new_name.get(trans_id)
881
if filename is not None:
882
if parent not in self._limbo_children:
883
self._limbo_children[parent] = set()
884
self._limbo_children_names[parent] = {}
885
use_direct_path = True
886
# the direct path can only be used if no other file has
887
# already taken this pathname, i.e. if the name is unused, or
888
# if it is already associated with this trans_id.
889
elif self._case_sensitive_target:
890
if (self._limbo_children_names[parent].get(filename)
891
in (trans_id, None)):
892
use_direct_path = True
894
for l_filename, l_trans_id in\
895
self._limbo_children_names[parent].iteritems():
896
if l_trans_id == trans_id:
898
if l_filename.lower() == filename.lower():
901
use_direct_path = True
904
limbo_name = pathjoin(self._limbo_files[parent], filename)
905
self._limbo_children[parent].add(trans_id)
906
self._limbo_children_names[parent][filename] = trans_id
908
limbo_name = pathjoin(self._limbodir, trans_id)
909
self._needs_rename.add(trans_id)
910
self._limbo_files[trans_id] = limbo_name
714
913
def _set_executability(self, path, trans_id):
715
914
"""Set the executability of versioned files """
716
915
if supports_executable():
922
1121
def get_preview_tree(self):
923
1122
"""Return a tree representing the result of the transform.
925
The tree is a snapshot, and altering the TreeTransform will invalidate
1124
This tree only supports the subset of Tree functionality required
1125
by show_diff_trees. It must only be compared to tt._tree.
928
1127
return _PreviewTree(self)
930
def commit(self, branch, message, merge_parents=None, strict=False):
931
"""Commit the result of this TreeTransform to a branch.
933
:param branch: The branch to commit to.
934
:param message: The message to attach to the commit.
935
:param merge_parents: Additional parents specified by pending merges.
936
:return: The revision_id of the revision committed.
938
self._check_malformed()
940
unversioned = set(self._new_contents).difference(set(self._new_id))
941
for trans_id in unversioned:
942
if self.final_file_id(trans_id) is None:
943
raise errors.StrictCommitFailed()
945
revno, last_rev_id = branch.last_revision_info()
946
if last_rev_id == _mod_revision.NULL_REVISION:
947
if merge_parents is not None:
948
raise ValueError('Cannot supply merge parents for first'
952
parent_ids = [last_rev_id]
953
if merge_parents is not None:
954
parent_ids.extend(merge_parents)
955
if self._tree.get_revision_id() != last_rev_id:
956
raise ValueError('TreeTransform not based on branch basis: %s' %
957
self._tree.get_revision_id())
958
builder = branch.get_commit_builder(parent_ids)
959
preview = self.get_preview_tree()
960
list(builder.record_iter_changes(preview, last_rev_id,
961
self.iter_changes()))
962
builder.finish_inventory()
963
revision_id = builder.commit(message)
964
branch.set_last_revision_info(revno + 1, revision_id)
967
1129
def _text_parent(self, trans_id):
968
1130
file_id = self.tree_file_id(trans_id)
1060
1226
self.create_symlink(content.decode('utf-8'), trans_id)
1063
class DiskTreeTransform(TreeTransformBase):
1064
"""Tree transform storing its contents on disk."""
1066
def __init__(self, tree, limbodir, pb=None,
1067
case_sensitive=True):
1069
:param tree: The tree that will be transformed, but not necessarily
1071
:param limbodir: A directory where new files can be stored until
1072
they are installed in their proper places
1074
:param case_sensitive: If True, the target of the transform is
1075
case sensitive, not just case preserving.
1077
TreeTransformBase.__init__(self, tree, pb, case_sensitive)
1078
self._limbodir = limbodir
1079
self._deletiondir = None
1080
# A mapping of transform ids to their limbo filename
1081
self._limbo_files = {}
1082
# A mapping of transform ids to a set of the transform ids of children
1083
# that their limbo directory has
1084
self._limbo_children = {}
1085
# Map transform ids to maps of child filename to child transform id
1086
self._limbo_children_names = {}
1087
# List of transform ids that need to be renamed from limbo into place
1088
self._needs_rename = set()
1089
self._creation_mtime = None
1092
"""Release the working tree lock, if held, clean up limbo dir.
1094
This is required if apply has not been invoked, but can be invoked
1097
if self._tree is None:
1100
entries = [(self._limbo_name(t), t, k) for t, k in
1101
self._new_contents.iteritems()]
1102
entries.sort(reverse=True)
1103
for path, trans_id, kind in entries:
1106
delete_any(self._limbodir)
1108
# We don't especially care *why* the dir is immortal.
1109
raise ImmortalLimbo(self._limbodir)
1111
if self._deletiondir is not None:
1112
delete_any(self._deletiondir)
1114
raise errors.ImmortalPendingDeletion(self._deletiondir)
1116
TreeTransformBase.finalize(self)
1118
def _limbo_name(self, trans_id):
1119
"""Generate the limbo name of a file"""
1120
limbo_name = self._limbo_files.get(trans_id)
1121
if limbo_name is None:
1122
limbo_name = self._generate_limbo_path(trans_id)
1123
self._limbo_files[trans_id] = limbo_name
1126
def _generate_limbo_path(self, trans_id):
1127
"""Generate a limbo path using the trans_id as the relative path.
1129
This is suitable as a fallback, and when the transform should not be
1130
sensitive to the path encoding of the limbo directory.
1132
self._needs_rename.add(trans_id)
1133
return pathjoin(self._limbodir, trans_id)
1135
def adjust_path(self, name, parent, trans_id):
1136
previous_parent = self._new_parent.get(trans_id)
1137
previous_name = self._new_name.get(trans_id)
1138
TreeTransformBase.adjust_path(self, name, parent, trans_id)
1139
if (trans_id in self._limbo_files and
1140
trans_id not in self._needs_rename):
1141
self._rename_in_limbo([trans_id])
1142
if previous_parent != parent:
1143
self._limbo_children[previous_parent].remove(trans_id)
1144
if previous_parent != parent or previous_name != name:
1145
del self._limbo_children_names[previous_parent][previous_name]
1147
def _rename_in_limbo(self, trans_ids):
1148
"""Fix limbo names so that the right final path is produced.
1150
This means we outsmarted ourselves-- we tried to avoid renaming
1151
these files later by creating them with their final names in their
1152
final parents. But now the previous name or parent is no longer
1153
suitable, so we have to rename them.
1155
Even for trans_ids that have no new contents, we must remove their
1156
entries from _limbo_files, because they are now stale.
1158
for trans_id in trans_ids:
1159
old_path = self._limbo_files.pop(trans_id)
1160
if trans_id not in self._new_contents:
1162
new_path = self._limbo_name(trans_id)
1163
os.rename(old_path, new_path)
1164
for descendant in self._limbo_descendants(trans_id):
1165
desc_path = self._limbo_files[descendant]
1166
desc_path = new_path + desc_path[len(old_path):]
1167
self._limbo_files[descendant] = desc_path
1169
def _limbo_descendants(self, trans_id):
1170
"""Return the set of trans_ids whose limbo paths descend from this."""
1171
descendants = set(self._limbo_children.get(trans_id, []))
1172
for descendant in list(descendants):
1173
descendants.update(self._limbo_descendants(descendant))
1176
def create_file(self, contents, trans_id, mode_id=None):
1177
"""Schedule creation of a new file.
1181
Contents is an iterator of strings, all of which will be written
1182
to the target destination.
1184
New file takes the permissions of any existing file with that id,
1185
unless mode_id is specified.
1187
name = self._limbo_name(trans_id)
1188
f = open(name, 'wb')
1191
unique_add(self._new_contents, trans_id, 'file')
1193
# Clean up the file, it never got registered so
1194
# TreeTransform.finalize() won't clean it up.
1199
f.writelines(contents)
1202
self._set_mtime(name)
1203
self._set_mode(trans_id, mode_id, S_ISREG)
1205
def _read_file_chunks(self, trans_id):
1206
cur_file = open(self._limbo_name(trans_id), 'rb')
1208
return cur_file.readlines()
1212
def _read_symlink_target(self, trans_id):
1213
return os.readlink(self._limbo_name(trans_id))
1215
def _set_mtime(self, path):
1216
"""All files that are created get the same mtime.
1218
This time is set by the first object to be created.
1220
if self._creation_mtime is None:
1221
self._creation_mtime = time.time()
1222
os.utime(path, (self._creation_mtime, self._creation_mtime))
1224
def create_hardlink(self, path, trans_id):
1225
"""Schedule creation of a hard link"""
1226
name = self._limbo_name(trans_id)
1230
if e.errno != errno.EPERM:
1232
raise errors.HardLinkNotSupported(path)
1234
unique_add(self._new_contents, trans_id, 'file')
1236
# Clean up the file, it never got registered so
1237
# TreeTransform.finalize() won't clean it up.
1241
def create_directory(self, trans_id):
1242
"""Schedule creation of a new directory.
1244
See also new_directory.
1246
os.mkdir(self._limbo_name(trans_id))
1247
unique_add(self._new_contents, trans_id, 'directory')
1249
def create_symlink(self, target, trans_id):
1250
"""Schedule creation of a new symbolic link.
1252
target is a bytestring.
1253
See also new_symlink.
1256
os.symlink(target, self._limbo_name(trans_id))
1257
unique_add(self._new_contents, trans_id, 'symlink')
1260
path = FinalPaths(self).get_path(trans_id)
1263
raise UnableCreateSymlink(path=path)
1265
def cancel_creation(self, trans_id):
1266
"""Cancel the creation of new file contents."""
1267
del self._new_contents[trans_id]
1268
children = self._limbo_children.get(trans_id)
1269
# if this is a limbo directory with children, move them before removing
1271
if children is not None:
1272
self._rename_in_limbo(children)
1273
del self._limbo_children[trans_id]
1274
del self._limbo_children_names[trans_id]
1275
delete_any(self._limbo_name(trans_id))
1278
class TreeTransform(DiskTreeTransform):
1229
class TreeTransform(TreeTransformBase):
1279
1230
"""Represent a tree transformation.
1281
1232
This object is designed to support incremental generation of the transform,
1370
# Cache of realpath results, to speed up canonical_path
1371
self._realpaths = {}
1372
# Cache of relpath results, to speed up canonical_path
1374
DiskTreeTransform.__init__(self, tree, limbodir, pb,
1321
TreeTransformBase.__init__(self, tree, limbodir, pb,
1375
1322
tree.case_sensitive)
1376
1323
self._deletiondir = deletiondir
1378
def canonical_path(self, path):
1379
"""Get the canonical tree-relative path"""
1380
# don't follow final symlinks
1381
abs = self._tree.abspath(path)
1382
if abs in self._relpaths:
1383
return self._relpaths[abs]
1384
dirname, basename = os.path.split(abs)
1385
if dirname not in self._realpaths:
1386
self._realpaths[dirname] = os.path.realpath(dirname)
1387
dirname = self._realpaths[dirname]
1388
abs = pathjoin(dirname, basename)
1389
if dirname in self._relpaths:
1390
relpath = pathjoin(self._relpaths[dirname], basename)
1391
relpath = relpath.rstrip('/\\')
1393
relpath = self._tree.relpath(abs)
1394
self._relpaths[abs] = relpath
1397
def tree_kind(self, trans_id):
1398
"""Determine the file kind in the working tree.
1400
Raises NoSuchFile if the file does not exist
1402
path = self._tree_id_paths.get(trans_id)
1404
raise NoSuchFile(None)
1406
return file_kind(self._tree.abspath(path))
1408
if e.errno != errno.ENOENT:
1411
raise NoSuchFile(path)
1413
def _set_mode(self, trans_id, mode_id, typefunc):
1414
"""Set the mode of new file contents.
1415
The mode_id is the existing file to get the mode from (often the same
1416
as trans_id). The operation is only performed if there's a mode match
1417
according to typefunc.
1422
old_path = self._tree_id_paths[mode_id]
1426
mode = os.stat(self._tree.abspath(old_path)).st_mode
1428
if e.errno in (errno.ENOENT, errno.ENOTDIR):
1429
# Either old_path doesn't exist, or the parent of the
1430
# target is not a directory (but will be one eventually)
1431
# Either way, we know it doesn't exist *right now*
1432
# See also bug #248448
1437
os.chmod(self._limbo_name(trans_id), mode)
1439
def iter_tree_children(self, parent_id):
1440
"""Iterate through the entry's tree children, if any"""
1442
path = self._tree_id_paths[parent_id]
1446
children = os.listdir(self._tree.abspath(path))
1448
if not (osutils._is_error_enotdir(e)
1449
or e.errno in (errno.ENOENT, errno.ESRCH)):
1453
for child in children:
1454
childpath = joinpath(path, child)
1455
if self._tree.is_control_filename(childpath):
1457
yield self.trans_id_tree_path(childpath)
1459
def _generate_limbo_path(self, trans_id):
1460
"""Generate a limbo path using the final path if possible.
1462
This optimizes the performance of applying the tree transform by
1463
avoiding renames. These renames can be avoided only when the parent
1464
directory is already scheduled for creation.
1466
If the final path cannot be used, falls back to using the trans_id as
1469
parent = self._new_parent.get(trans_id)
1470
# if the parent directory is already in limbo (e.g. when building a
1471
# tree), choose a limbo name inside the parent, to reduce further
1473
use_direct_path = False
1474
if self._new_contents.get(parent) == 'directory':
1475
filename = self._new_name.get(trans_id)
1476
if filename is not None:
1477
if parent not in self._limbo_children:
1478
self._limbo_children[parent] = set()
1479
self._limbo_children_names[parent] = {}
1480
use_direct_path = True
1481
# the direct path can only be used if no other file has
1482
# already taken this pathname, i.e. if the name is unused, or
1483
# if it is already associated with this trans_id.
1484
elif self._case_sensitive_target:
1485
if (self._limbo_children_names[parent].get(filename)
1486
in (trans_id, None)):
1487
use_direct_path = True
1489
for l_filename, l_trans_id in\
1490
self._limbo_children_names[parent].iteritems():
1491
if l_trans_id == trans_id:
1493
if l_filename.lower() == filename.lower():
1496
use_direct_path = True
1498
if not use_direct_path:
1499
return DiskTreeTransform._generate_limbo_path(self, trans_id)
1501
limbo_name = pathjoin(self._limbo_files[parent], filename)
1502
self._limbo_children[parent].add(trans_id)
1503
self._limbo_children_names[parent][filename] = trans_id
1507
1325
def apply(self, no_conflicts=False, precomputed_delta=None, _mover=None):
1508
1326
"""Apply all changes to the inventory and filesystem.
1937
1753
ordered_ids = self._list_files_by_dir()
1938
1754
for entry, trans_id in self._make_inv_entries(ordered_ids,
1939
specific_file_ids, yield_parents=yield_parents):
1940
yield unicode(self._final_paths.get_path(trans_id)), entry
1942
def _iter_entries_for_dir(self, dir_path):
1943
"""Return path, entry for items in a directory without recursing down."""
1944
dir_file_id = self.path2id(dir_path)
1946
for file_id in self.iter_children(dir_file_id):
1947
trans_id = self._transform.trans_id_file_id(file_id)
1948
ordered_ids.append((trans_id, file_id))
1949
for entry, trans_id in self._make_inv_entries(ordered_ids):
1950
yield unicode(self._final_paths.get_path(trans_id)), entry
1952
def list_files(self, include_root=False, from_dir=None, recursive=True):
1953
"""See WorkingTree.list_files."""
1756
yield unicode(self._final_paths.get_path(trans_id)), entry
1758
def list_files(self, include_root=False):
1759
"""See Tree.list_files."""
1954
1760
# XXX This should behave like WorkingTree.list_files, but is really
1955
1761
# more like RevisionTree.list_files.
1959
prefix = from_dir + '/'
1960
entries = self.iter_entries_by_dir()
1961
for path, entry in entries:
1962
if entry.name == '' and not include_root:
1965
if not path.startswith(prefix):
1967
path = path[len(prefix):]
1968
yield path, 'V', entry.kind, entry.file_id, entry
1970
if from_dir is None and include_root is True:
1971
root_entry = inventory.make_entry('directory', '',
1972
ROOT_PARENT, self.get_root_id())
1973
yield '', 'V', 'directory', root_entry.file_id, root_entry
1974
entries = self._iter_entries_for_dir(from_dir or '')
1975
for path, entry in entries:
1976
yield path, 'V', entry.kind, entry.file_id, entry
1762
for path, entry in self.iter_entries_by_dir():
1763
if entry.name == '' and not include_root:
1765
yield path, 'V', entry.kind, entry.file_id, entry
1978
1767
def kind(self, file_id):
1979
1768
trans_id = self._transform.trans_id_file_id(file_id)
2371
2150
def _create_files(tt, tree, desired_files, pb, offset, accelerator_tree,
2373
2152
total = len(desired_files) + offset
2375
2153
if accelerator_tree is None:
2376
2154
new_desired_files = desired_files
2378
2156
iter = accelerator_tree.iter_changes(tree, include_unchanged=True)
2379
unchanged = [(f, p[1]) for (f, p, c, v, d, n, k, e)
2380
in iter if not (c or e[0] != e[1])]
2381
if accelerator_tree.supports_content_filtering():
2382
unchanged = [(f, p) for (f, p) in unchanged
2383
if not accelerator_tree.iter_search_rules([p]).next()]
2384
unchanged = dict(unchanged)
2157
unchanged = dict((f, p[1]) for (f, p, c, v, d, n, k, e)
2158
in iter if not (c or e[0] != e[1]))
2385
2159
new_desired_files = []
2387
for file_id, (trans_id, tree_path) in desired_files:
2161
for file_id, trans_id in desired_files:
2388
2162
accelerator_path = unchanged.get(file_id)
2389
2163
if accelerator_path is None:
2390
new_desired_files.append((file_id, (trans_id, tree_path)))
2164
new_desired_files.append((file_id, trans_id))
2392
2166
pb.update('Adding file contents', count + offset, total)
2725
2477
parent_trans = ROOT_PARENT
2727
2479
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)
2480
tt.adjust_path(name[1], parent_trans, trans_id)
2732
2481
if executable[0] != executable[1] and kind[1] == "file":
2733
2482
tt.set_executability(executable[1], trans_id)
2734
if working_tree.supports_content_filtering():
2735
for index, ((trans_id, mode_id), bytes) in enumerate(
2736
target_tree.iter_files_bytes(deferred_files)):
2737
file_id = deferred_files[index][0]
2738
# We're reverting a tree to the target tree so using the
2739
# target tree to find the file path seems the best choice
2740
# here IMO - Ian C 27/Oct/2009
2741
filter_tree_path = target_tree.id2path(file_id)
2742
filters = working_tree._content_filter_stack(filter_tree_path)
2743
bytes = filtered_output_bytes(bytes, filters,
2744
ContentFilterContext(filter_tree_path, working_tree))
2745
tt.create_file(bytes, trans_id, mode_id)
2747
for (trans_id, mode_id), bytes in target_tree.iter_files_bytes(
2749
tt.create_file(bytes, trans_id, mode_id)
2750
tt.fixup_new_roots()
2483
for (trans_id, mode_id), bytes in target_tree.iter_files_bytes(
2485
tt.create_file(bytes, trans_id, mode_id)
2752
2487
if basis_tree is not None:
2753
2488
basis_tree.unlock()
2754
2489
return merge_modified
2757
def resolve_conflicts(tt, pb=None, pass_func=None):
2492
def resolve_conflicts(tt, pb=DummyProgress(), pass_func=None):
2758
2493
"""Make many conflict-resolution attempts, but die if they fail"""
2759
2494
if pass_func is None:
2760
2495
pass_func = conflict_pass
2761
2496
new_conflicts = set()
2762
pb = ui.ui_factory.nested_progress_bar()
2764
2498
for n in range(10):
2765
2499
pb.update('Resolution pass', n+1, 10)