78
78
ROOT_PARENT = "root-parent"
80
81
def unique_add(map, key, value):
82
83
raise DuplicateKey(key=key)
87
87
class _TransformResults(object):
88
88
def __init__(self, modified_paths, rename_count):
89
89
object.__init__(self)
259
259
self.unversion_file(old_new_root)
260
260
# if, at this stage, root still has an old file_id, zap it so we can
261
261
# stick a new one in.
262
if (self.tree_file_id(self._new_root) is not None and
263
self._new_root not in self._removed_id):
262
if (self.tree_file_id(self._new_root) is not None
263
and self._new_root not in self._removed_id):
264
264
self.unversion_file(self._new_root)
265
265
if file_id is not None:
266
266
self.version_file(file_id, self._new_root)
425
425
changed_ids.update(changed_kind)
426
426
# To find entries with changed parent_ids, find parents which existed,
427
427
# but changed file_id.
428
changed_file_id = set(t for t in new_file_id if t in self._removed_id)
429
428
# Now add all their children to the set.
430
429
for parent_trans_id in new_file_id:
431
430
changed_ids.update(self.iter_tree_children(parent_trans_id))
513
512
items = list(viewitems(self._new_parent))
514
513
items.extend((t, self.final_parent(t))
515
for t in list(self._tree_id_paths))
514
for t in list(self._tree_id_paths))
516
515
for trans_id, parent_id in items:
517
516
if parent_id not in by_parent:
518
517
by_parent[parent_id] = set()
687
686
if trans_id not in self._removed_contents:
688
687
conflicts.append(('overwrite', trans_id,
689
self.final_name(trans_id)))
688
self.final_name(trans_id)))
692
691
def _duplicate_entries(self, by_parent):
903
902
if from_versioned:
904
903
# get data from working tree if versioned
905
904
from_entry = next(self._tree.iter_entries_by_dir(
906
specific_files=[from_path]))[1]
905
specific_files=[from_path]))[1]
907
906
from_name = from_entry.name
908
907
from_parent = from_entry.parent_id
990
989
if from_kind != to_kind:
992
991
elif to_kind in ('file', 'symlink') and (
993
to_trans_id != from_trans_id or
994
to_trans_id in self._new_contents):
992
to_trans_id != from_trans_id
993
or to_trans_id in self._new_contents):
996
if (not modified and from_versioned == to_versioned and
997
from_parent==to_parent and from_name == to_name and
998
from_executable == to_executable):
995
if (not modified and from_versioned == to_versioned
996
and from_parent == to_parent and from_name == to_name
997
and from_executable == to_executable):
1000
999
results.append((file_id, (from_path, to_path), modified,
1001
(from_versioned, to_versioned),
1002
(from_parent, to_parent),
1003
(from_name, to_name),
1004
(from_kind, to_kind),
1005
(from_executable, to_executable)))
1000
(from_versioned, to_versioned),
1001
(from_parent, to_parent),
1002
(from_name, to_name),
1003
(from_kind, to_kind),
1004
(from_executable, to_executable)))
1007
1006
def path_key(t):
1146
1145
if not isinstance(content, bytes):
1147
1146
content = content.encode('utf-8')
1148
1147
yield serializer.bytes_record(
1149
content, ((trans_id.encode('utf-8'), kind.encode('ascii')),))
1148
content, ((trans_id.encode('utf-8'), kind.encode('ascii')),))
1151
1150
def deserialize(self, records):
1152
1151
"""Deserialize a stored TreeTransform.
1161
1160
for k, v in viewitems(attribs[b'_new_name'])}
1162
1161
self._new_parent = {k.decode('utf-8'): v.decode('utf-8')
1163
1162
for k, v in viewitems(attribs[b'_new_parent'])}
1164
self._new_executability = {k.decode('utf-8'): bool(v)
1163
self._new_executability = {
1164
k.decode('utf-8'): bool(v)
1165
1165
for k, v in viewitems(attribs[b'_new_executability'])}
1166
1166
self._new_id = {k.decode('utf-8'): v
1167
1167
for k, v in viewitems(attribs[b'_new_id'])}
1175
1175
self._tree_id_paths[trans_id] = path
1176
1176
self._removed_id = {trans_id.decode('utf-8')
1177
1177
for trans_id in attribs[b'_removed_id']}
1178
self._removed_contents = set(trans_id.decode('utf-8')
1179
for trans_id in attribs[b'_removed_contents'])
1180
self._non_present_ids = {k: v.decode('utf-8')
1181
for k, v in viewitems(attribs[b'_non_present_ids'])}
1178
self._removed_contents = set(
1179
trans_id.decode('utf-8')
1180
for trans_id in attribs[b'_removed_contents'])
1181
self._non_present_ids = {
1182
k: v.decode('utf-8')
1183
for k, v in viewitems(attribs[b'_non_present_ids'])}
1182
1184
for ((trans_id, kind),), content in records:
1183
1185
trans_id = trans_id.decode('utf-8')
1184
1186
kind = kind.decode('ascii')
1281
1283
previous_parent = self._new_parent.get(trans_id)
1282
1284
previous_name = self._new_name.get(trans_id)
1283
1285
TreeTransformBase.adjust_path(self, name, parent, trans_id)
1284
if (trans_id in self._limbo_files and
1285
trans_id not in self._needs_rename):
1286
if (trans_id in self._limbo_files
1287
and trans_id not in self._needs_rename):
1286
1288
self._rename_in_limbo([trans_id])
1287
1289
if previous_parent != parent:
1288
1290
self._limbo_children[previous_parent].remove(trans_id)
1654
1657
children = os.listdir(self._tree.abspath(path))
1655
1658
except OSError as e:
1656
if not (osutils._is_error_enotdir(e)
1657
or e.errno in (errno.ENOENT, errno.ESRCH)):
1659
if not (osutils._is_error_enotdir(e) or
1660
e.errno in (errno.ENOENT, errno.ESRCH)):
1767
1770
with ui.ui_factory.nested_progress_bar() as child_pb:
1768
1771
for num, trans_id in enumerate(self._removed_id):
1769
1772
if (num % 10) == 0:
1770
child_pb.update(gettext('removing file'), num, total_entries)
1773
child_pb.update(gettext('removing file'),
1771
1775
if trans_id == self._new_root:
1772
1776
file_id = self._tree.get_root_id()
1779
1783
inventory_delta.append((path, None, file_id, None))
1780
1784
new_path_file_ids = dict((t, self.final_file_id(t)) for p, t in
1783
1786
for num, (path, trans_id) in enumerate(new_paths):
1784
1787
if (num % 10) == 0:
1785
1788
child_pb.update(gettext('adding file'),
1787
1790
file_id = new_path_file_ids[trans_id]
1788
1791
if file_id is None:
1791
1793
kind = self.final_kind(trans_id)
1792
1794
if kind is None:
1793
1795
kind = self._tree.stored_kind(
1794
self._tree.id2path(file_id), file_id)
1796
self._tree.id2path(file_id), file_id)
1795
1797
parent_trans_id = self.final_parent(trans_id)
1796
1798
parent_file_id = new_path_file_ids.get(parent_trans_id)
1797
1799
if parent_file_id is None:
1804
1806
None, self._new_reference_revision[trans_id])
1806
1808
new_entry = inventory.make_entry(kind,
1807
self.final_name(trans_id),
1808
parent_file_id, file_id)
1809
self.final_name(trans_id),
1810
parent_file_id, file_id)
1810
1812
old_path = self._tree.id2path(new_entry.file_id)
1811
1813
except errors.NoSuchId:
1837
1839
if trans_id in self._removed_contents:
1838
1840
delete_path = os.path.join(self._deletiondir, trans_id)
1839
1841
mover.pre_delete(full_path, delete_path)
1840
elif (trans_id in self._new_name
1841
or trans_id in self._new_parent):
1842
elif (trans_id in self._new_name or
1843
trans_id in self._new_parent):
1843
1845
mover.rename(full_path, self._limbo_name(trans_id))
1844
1846
except errors.TransformRenameFailed as e:
1860
1862
new_paths = self.new_paths(filesystem_only=True)
1861
1863
modified_paths = []
1862
new_path_file_ids = dict((t, self.final_file_id(t)) for p, t in
1864
1864
with ui.ui_factory.nested_progress_bar() as child_pb:
1865
1865
for num, (path, trans_id) in enumerate(new_paths):
1866
1866
if (num % 10) == 0:
1867
child_pb.update(gettext('adding file'), num, len(new_paths))
1867
child_pb.update(gettext('adding file'),
1868
num, len(new_paths))
1868
1869
full_path = self._tree.abspath(path)
1869
1870
if trans_id in self._needs_rename:
1878
1879
# TODO: if trans_id in self._observed_sha1s, we should
1879
1880
# re-stat the final target, since ctime will be
1880
1881
# updated by the change.
1881
if (trans_id in self._new_contents or
1882
self.path_changed(trans_id)):
1882
if (trans_id in self._new_contents
1883
or self.path_changed(trans_id)):
1883
1884
if trans_id in self._new_contents:
1884
1885
modified_paths.append(full_path)
1885
1886
if trans_id in self._new_executability:
1914
1915
paths = FinalPaths(self)
1915
1916
for trans_id, observed in viewitems(self._observed_sha1s):
1916
1917
path = paths.get_path(trans_id)
1917
# We could get the file_id, but dirstate prefers to use the path
1918
# anyway, and it is 'cheaper' to determine.
1919
# file_id = self._new_id[trans_id]
1920
self._tree._observed_sha1(None, path, observed)
1918
self._tree._observed_sha1(path, observed)
1923
1921
class TransformPreview(DiskTreeTransform):
2011
2009
def _get_file_revision(self, path, file_id, vf, tree_revision):
2012
2010
parent_keys = [
2013
(file_id, t.get_file_revision(t.id2path(file_id), file_id))
2014
for t in self._iter_parent_trees()]
2011
(file_id, t.get_file_revision(t.id2path(file_id)))
2012
for t in self._iter_parent_trees()]
2015
2013
vf.add_lines((file_id, tree_revision), parent_keys,
2016
self.get_file_lines(path, file_id))
2014
self.get_file_lines(path))
2017
2015
repo = self._get_repository()
2018
2016
base_vf = repo.texts
2019
2017
if base_vf not in vf.fallback_versionedfiles:
2149
2147
file_id = self._transform.final_file_id(trans_id)
2150
2148
if file_id is None:
2152
if (specific_files is not None and
2153
self._final_paths.get_path(trans_id) not in specific_files):
2150
if (specific_files is not None
2151
and self._final_paths.get_path(trans_id) not in specific_files):
2155
2153
kind = self._transform.final_kind(trans_id)
2156
2154
if kind is None:
2177
2175
ordered_ids.append((trans_id, parent_file_id))
2178
2176
return ordered_ids
2180
def iter_child_entries(self, path, file_id=None):
2178
def iter_child_entries(self, path):
2181
2179
trans_id = self._path2trans_id(path)
2182
2180
if trans_id is None:
2183
2181
raise errors.NoSuchFile(path)
2233
2231
if from_dir is None and include_root is True:
2234
2232
root_entry = inventory.make_entry('directory', '',
2235
ROOT_PARENT, self.get_root_id())
2233
ROOT_PARENT, self.get_root_id())
2236
2234
yield '', 'V', 'directory', root_entry.file_id, root_entry
2237
2235
entries = self._iter_entries_for_dir(from_dir or '')
2238
2236
for path, entry in entries:
2239
2237
yield path, 'V', entry.kind, entry.file_id, entry
2241
def kind(self, path, file_id=None):
2239
def kind(self, path):
2242
2240
trans_id = self._path2trans_id(path)
2243
2241
if trans_id is None:
2244
2242
raise errors.NoSuchFile(path)
2245
2243
return self._transform.final_kind(trans_id)
2247
def stored_kind(self, path, file_id=None):
2245
def stored_kind(self, path):
2248
2246
trans_id = self._path2trans_id(path)
2249
2247
if trans_id is None:
2250
2248
raise errors.NoSuchFile(path)
2252
2250
return self._transform._new_contents[trans_id]
2253
2251
except KeyError:
2254
return self._transform._tree.stored_kind(path, file_id)
2252
return self._transform._tree.stored_kind(path)
2256
def get_file_mtime(self, path, file_id=None):
2254
def get_file_mtime(self, path):
2257
2255
"""See Tree.get_file_mtime"""
2259
file_id = self.path2id(path)
2256
file_id = self.path2id(path)
2260
2257
if file_id is None:
2261
2258
raise errors.NoSuchFile(path)
2262
2259
if not self._content_change(file_id):
2263
2260
return self._transform._tree.get_file_mtime(
2264
self._transform._tree.id2path(file_id), file_id)
2261
self._transform._tree.id2path(file_id))
2265
2262
trans_id = self._path2trans_id(path)
2266
2263
return self._stat_limbo_file(trans_id).st_mtime
2268
def get_file_size(self, path, file_id=None):
2265
def get_file_size(self, path):
2269
2266
"""See Tree.get_file_size"""
2270
2267
trans_id = self._path2trans_id(path)
2271
2268
if trans_id is None:
2276
2273
if trans_id in self._transform._new_contents:
2277
2274
return self._stat_limbo_file(trans_id).st_size
2278
if self.kind(path, file_id) == 'file':
2279
return self._transform._tree.get_file_size(path, file_id)
2275
if self.kind(path) == 'file':
2276
return self._transform._tree.get_file_size(path)
2283
def get_file_verifier(self, path, file_id=None, stat_value=None):
2280
def get_file_verifier(self, path, stat_value=None):
2284
2281
trans_id = self._path2trans_id(path)
2285
2282
if trans_id is None:
2286
2283
raise errors.NoSuchFile(path)
2287
2284
kind = self._transform._new_contents.get(trans_id)
2288
2285
if kind is None:
2289
return self._transform._tree.get_file_verifier(path, file_id)
2286
return self._transform._tree.get_file_verifier(path)
2290
2287
if kind == 'file':
2291
with self.get_file(path, file_id) as fileobj:
2288
with self.get_file(path) as fileobj:
2292
2289
return ("SHA1", sha_file(fileobj))
2294
def get_file_sha1(self, path, file_id=None, stat_value=None):
2291
def get_file_sha1(self, path, stat_value=None):
2295
2292
trans_id = self._path2trans_id(path)
2296
2293
if trans_id is None:
2297
2294
raise errors.NoSuchFile(path)
2298
2295
kind = self._transform._new_contents.get(trans_id)
2299
2296
if kind is None:
2300
return self._transform._tree.get_file_sha1(path, file_id)
2297
return self._transform._tree.get_file_sha1(path)
2301
2298
if kind == 'file':
2302
with self.get_file(path, file_id) as fileobj:
2299
with self.get_file(path) as fileobj:
2303
2300
return sha_file(fileobj)
2305
def is_executable(self, path, file_id=None):
2302
def is_executable(self, path):
2306
2303
trans_id = self._path2trans_id(path)
2307
2304
if trans_id is None:
2360
2357
return kind, size, executable, link_or_sha1
2362
2359
def iter_changes(self, from_tree, include_unchanged=False,
2363
specific_files=None, pb=None, extra_trees=None,
2364
require_versioned=True, want_unversioned=False):
2360
specific_files=None, pb=None, extra_trees=None,
2361
require_versioned=True, want_unversioned=False):
2365
2362
"""See InterTree.iter_changes.
2367
2364
This has a fast path that is only used when the from_tree matches
2368
2365
the transform tree, and no fancy options are supplied.
2370
if (from_tree is not self._transform._tree or include_unchanged or
2371
specific_files or want_unversioned):
2367
if (from_tree is not self._transform._tree or include_unchanged
2368
or specific_files or want_unversioned):
2372
2369
return tree.InterTree(from_tree, self).iter_changes(
2373
2370
include_unchanged=include_unchanged,
2374
2371
specific_files=specific_files,
2380
2377
raise ValueError('want_unversioned is not supported')
2381
2378
return self._transform.iter_changes()
2383
def get_file(self, path, file_id=None):
2380
def get_file(self, path):
2384
2381
"""See Tree.get_file"""
2386
file_id = self.path2id(path)
2382
file_id = self.path2id(path)
2387
2383
if not self._content_change(file_id):
2388
return self._transform._tree.get_file(path, file_id)
2384
return self._transform._tree.get_file(path)
2389
2385
trans_id = self._path2trans_id(path)
2390
2386
name = self._transform._limbo_name(trans_id)
2391
2387
return open(name, 'rb')
2393
def get_file_with_stat(self, path, file_id=None):
2394
return self.get_file(path, file_id), None
2389
def get_file_with_stat(self, path):
2390
return self.get_file(path), None
2396
def annotate_iter(self, path, file_id=None,
2392
def annotate_iter(self, path,
2397
2393
default_revision=_mod_revision.CURRENT_REVISION):
2399
file_id = self.path2id(path)
2394
file_id = self.path2id(path)
2400
2395
changes = self._iter_changes_cache.get(file_id)
2401
2396
if changes is None:
2423
2418
# It would be nice to be able to use the new Annotator based
2424
2419
# approach, as well.
2425
2420
return annotate.reannotate([old_annotation],
2426
self.get_file(path, file_id).readlines(),
2421
self.get_file(path).readlines(),
2427
2422
default_revision)
2429
def get_symlink_target(self, path, file_id=None):
2424
def get_symlink_target(self, path):
2430
2425
"""See Tree.get_symlink_target"""
2432
file_id = self.path2id(path)
2426
file_id = self.path2id(path)
2433
2427
if not self._content_change(file_id):
2434
2428
return self._transform._tree.get_symlink_target(path)
2435
2429
trans_id = self._path2trans_id(path)
2449
2443
path_from_root = self._final_paths.get_path(child_id)
2450
2444
basename = self._transform.final_name(child_id)
2451
2445
file_id = self._transform.final_file_id(child_id)
2452
kind = self._transform.final_kind(child_id)
2446
kind = self._transform.final_kind(child_id)
2453
2447
if kind is not None:
2454
2448
versioned_kind = kind
2456
2450
kind = 'unknown'
2457
2451
versioned_kind = self._transform._tree.stored_kind(
2458
self._transform._tree.id2path(file_id),
2452
self._transform._tree.id2path(file_id))
2460
2453
if versioned_kind == 'directory':
2461
2454
subdirs.append(child_id)
2462
2455
children.append((path_from_root, basename, kind, None,
2603
2596
for dir, files in wt.walkdirs():
2604
2597
existing_files.update(f[0] for f in files)
2605
2598
for num, (tree_path, entry) in \
2606
enumerate(tree.iter_entries_by_dir()):
2607
pb.update(gettext("Building tree"), num - len(deferred_contents), total)
2599
enumerate(tree.iter_entries_by_dir()):
2600
pb.update(gettext("Building tree"), num
2601
- len(deferred_contents), total)
2608
2602
if entry.parent_id is None:
2610
2604
reparent = False
2623
2617
divert.add(file_id)
2624
if (file_id not in divert and
2625
_content_match(tree, entry, tree_path, file_id, kind,
2618
if (file_id not in divert
2620
tree, entry, tree_path, file_id, kind,
2627
2622
tt.delete_contents(tt.trans_id_tree_path(tree_path))
2628
2623
if kind == 'directory':
2629
2624
reparent = True
2634
2629
trans_id = tt.create_path(entry.name, parent_id)
2635
2630
file_trans_id[file_id] = trans_id
2636
2631
tt.version_file(file_id, trans_id)
2637
executable = tree.is_executable(tree_path, file_id)
2632
executable = tree.is_executable(tree_path)
2639
2634
tt.set_executability(executable, trans_id)
2640
trans_data = (trans_id, file_id, tree_path, entry.text_sha1)
2635
trans_data = (trans_id, file_id,
2636
tree_path, entry.text_sha1)
2641
2637
deferred_contents.append((tree_path, trans_data))
2643
2639
file_trans_id[file_id] = new_by_entry(
2644
tree_path, tt, entry, parent_id, tree)
2640
tree_path, tt, entry, parent_id, tree)
2646
2642
new_trans_id = file_trans_id[file_id]
2647
2643
old_parent = tt.trans_id_tree_path(tree_path)
2651
2647
accelerator_tree, hardlink)
2652
2648
pp.next_phase()
2653
2649
divert_trans = set(file_trans_id[f] for f in divert)
2654
resolver = lambda t, c: resolve_checkout(t, c, divert_trans)
2652
return resolve_checkout(t, c, divert_trans)
2655
2653
raw_conflicts = resolve_conflicts(tt, pass_func=resolver)
2656
2654
if len(raw_conflicts) > 0:
2657
2655
precomputed_delta = None
2690
2688
accelerator_path = unchanged.get(tree_path)
2691
2689
if accelerator_path is None:
2692
2690
new_desired_files.append((tree_path,
2693
(trans_id, file_id, tree_path, text_sha1)))
2691
(trans_id, file_id, tree_path, text_sha1)))
2695
2693
pb.update(gettext('Adding file contents'), count + offset, total)
2702
2700
if wt.supports_content_filtering():
2703
2701
filters = wt._content_filter_stack(tree_path)
2704
2702
chunks = filtered_output_bytes(chunks, filters,
2705
ContentFilterContext(tree_path, tree))
2703
ContentFilterContext(tree_path, tree))
2706
2704
tt.create_file(chunks, trans_id, sha1=text_sha1)
2708
2706
offset += count
2711
2709
if wt.supports_content_filtering():
2712
2710
filters = wt._content_filter_stack(tree_path)
2713
2711
contents = filtered_output_bytes(contents, filters,
2714
ContentFilterContext(tree_path, tree))
2712
ContentFilterContext(tree_path, tree))
2715
2713
tt.create_file(contents, trans_id, sha1=text_sha1)
2716
2714
pb.update(gettext('Adding file contents'), count + offset, total)
2736
2734
if entry.kind == "file":
2737
2735
with open(target_path, 'rb') as f1, \
2738
tree.get_file(tree_path, file_id) as f2:
2736
tree.get_file(tree_path) as f2:
2739
2737
if osutils.compare_files(f1, f2):
2741
2739
elif entry.kind == "symlink":
2742
if tree.get_symlink_target(tree_path, file_id) == os.readlink(target_path):
2740
if tree.get_symlink_target(tree_path) == os.readlink(target_path):
2763
2761
final_parent = tt.final_parent(old_file)
2764
2762
if new_file in divert:
2765
new_name = tt.final_name(old_file)+'.diverted'
2763
new_name = tt.final_name(old_file) + '.diverted'
2766
2764
tt.adjust_path(new_name, final_parent, new_file)
2767
2765
new_conflicts.add((c_type, 'Diverted to',
2768
2766
new_file, old_file))
2770
new_name = tt.final_name(old_file)+'.moved'
2768
new_name = tt.final_name(old_file) + '.moved'
2771
2769
tt.adjust_path(new_name, final_parent, old_file)
2772
2770
new_conflicts.add((c_type, 'Moved existing file to',
2773
2771
old_file, new_file))
2779
2777
name = entry.name
2780
2778
kind = entry.kind
2781
2779
if kind == 'file':
2782
with tree.get_file(path, entry.file_id) as f:
2783
executable = tree.is_executable(path, entry.file_id)
2780
with tree.get_file(path) as f:
2781
executable = tree.is_executable(path)
2784
2782
return tt.new_file(
2785
name, parent_id, osutils.file_iterator(f), entry.file_id,
2783
name, parent_id, osutils.file_iterator(f), entry.file_id,
2787
2785
elif kind in ('directory', 'tree-reference'):
2788
2786
trans_id = tt.new_directory(name, parent_id, entry.file_id)
2789
2787
if kind == 'tree-reference':
2790
2788
tt.set_tree_reference(entry.reference_revision, trans_id)
2791
2789
return trans_id
2792
2790
elif kind == 'symlink':
2793
target = tree.get_symlink_target(path, entry.file_id)
2791
target = tree.get_symlink_target(path)
2794
2792
return tt.new_symlink(name, parent_id, target, entry.file_id)
2796
2794
raise errors.BadFileKindError(name, kind)
2799
2797
def create_from_tree(tt, trans_id, tree, path, file_id=None, chunks=None,
2800
filter_tree_path=None):
2798
filter_tree_path=None):
2801
2799
"""Create new file contents according to tree contents.
2803
2801
:param filter_tree_path: the tree path to use to lookup
2804
2802
content filters to apply to the bytes output in the working tree.
2805
2803
This only applies if the working tree supports content filtering.
2807
kind = tree.kind(path, file_id)
2805
kind = tree.kind(path)
2808
2806
if kind == 'directory':
2809
2807
tt.create_directory(trans_id)
2810
2808
elif kind == "file":
2811
2809
if chunks is None:
2812
f = tree.get_file(path, file_id)
2810
f = tree.get_file(path)
2813
2811
chunks = osutils.file_iterator(f)
2818
2816
if wt.supports_content_filtering() and filter_tree_path is not None:
2819
2817
filters = wt._content_filter_stack(filter_tree_path)
2820
chunks = filtered_output_bytes(chunks, filters,
2818
chunks = filtered_output_bytes(
2821
2820
ContentFilterContext(filter_tree_path, tree))
2822
2821
tt.create_file(chunks, trans_id)
2824
2823
if f is not None:
2826
2825
elif kind == "symlink":
2827
tt.create_symlink(tree.get_symlink_target(path, file_id), trans_id)
2826
tt.create_symlink(tree.get_symlink_target(path), trans_id)
2829
2828
raise AssertionError('Unknown kind %r' % kind)
2869
2868
child_pb, filenames, backups,
2870
2869
merge_modified, basis_tree)
2871
2870
with ui.ui_factory.nested_progress_bar() as child_pb:
2872
raw_conflicts = resolve_conflicts(tt, child_pb,
2873
lambda t, c: conflict_pass(t, c, target_tree))
2871
raw_conflicts = resolve_conflicts(
2872
tt, child_pb, lambda t, c: conflict_pass(t, c, target_tree))
2874
2873
conflicts = cook_conflicts(raw_conflicts, tt)
2875
2874
return conflicts, merge_modified
2883
2882
# than the target changes relative to the working tree. Because WT4 has an
2884
2883
# optimizer to compare itself to a target, but no optimizer for the
2886
change_list = working_tree.iter_changes(target_tree,
2887
specific_files=specific_files, pb=pb)
2885
change_list = working_tree.iter_changes(
2886
target_tree, specific_files=specific_files, pb=pb)
2888
2887
if not target_tree.is_versioned(u''):
2889
2888
skip_root = True
2893
2892
deferred_files = []
2894
2893
for id_num, (file_id, path, changed_content, versioned, parent, name,
2895
kind, executable) in enumerate(change_list):
2894
kind, executable) in enumerate(change_list):
2896
2895
target_path, wt_path = path
2897
2896
target_versioned, wt_versioned = versioned
2898
2897
target_parent, wt_parent = parent
2906
2905
if changed_content:
2907
2906
keep_content = False
2908
2907
if wt_kind == 'file' and (backups or target_kind is None):
2909
wt_sha1 = working_tree.get_file_sha1(wt_path, file_id)
2908
wt_sha1 = working_tree.get_file_sha1(wt_path)
2910
2909
if merge_modified.get(file_id) != wt_sha1:
2911
2910
# acquire the basis tree lazily to prevent the
2912
2911
# expense of accessing it when it's not needed ?
2914
2913
if basis_tree is None:
2915
2914
basis_tree = working_tree.basis_tree()
2916
2915
basis_tree.lock_read()
2917
basis_path = find_previous_path(working_tree, basis_tree, wt_path)
2916
basis_path = find_previous_path(
2917
working_tree, basis_tree, wt_path)
2918
2918
if basis_path is None:
2919
2919
if target_kind is None and not target_versioned:
2920
2920
keep_content = True
2922
if wt_sha1 != basis_tree.get_file_sha1(basis_path, file_id):
2922
if wt_sha1 != basis_tree.get_file_sha1(basis_path):
2923
2923
keep_content = True
2924
2924
if wt_kind is not None:
2925
2925
if not keep_content:
2941
2941
tt.create_directory(trans_id)
2942
2942
if target_kind == 'tree-reference':
2943
2943
revision = target_tree.get_reference_revision(
2944
target_path, file_id)
2945
2945
tt.set_tree_reference(revision, trans_id)
2946
2946
elif target_kind == 'symlink':
2947
2947
tt.create_symlink(target_tree.get_symlink_target(
2948
target_path, file_id), trans_id)
2948
target_path), trans_id)
2949
2949
elif target_kind == 'file':
2950
deferred_files.append((target_path, (trans_id, mode_id, file_id)))
2950
deferred_files.append(
2951
(target_path, (trans_id, mode_id, file_id)))
2951
2952
if basis_tree is None:
2952
2953
basis_tree = working_tree.basis_tree()
2953
2954
basis_tree.lock_read()
2954
new_sha1 = target_tree.get_file_sha1(target_path, file_id)
2955
new_sha1 = target_tree.get_file_sha1(target_path)
2955
2956
basis_path = find_previous_path(target_tree, basis_tree, target_path)
2956
2957
if (basis_path is not None and
2957
new_sha1 == basis_tree.get_file_sha1(basis_path, file_id)):
2958
new_sha1 == basis_tree.get_file_sha1(basis_path)):
2958
2959
if file_id in merge_modified:
2959
2960
del merge_modified[file_id]
2969
2970
tt.version_file(file_id, trans_id)
2970
2971
if wt_versioned and not target_versioned:
2971
2972
tt.unversion_file(trans_id)
2972
if (target_name is not None and
2973
(wt_name != target_name or wt_parent != target_parent)):
2973
if (target_name is not None
2974
and (wt_name != target_name or wt_parent != target_parent)):
2974
2975
if target_name == '' and target_parent is None:
2975
2976
parent_trans = ROOT_PARENT
2983
2984
tt.set_executability(target_executable, trans_id)
2984
2985
if working_tree.supports_content_filtering():
2985
2986
for (trans_id, mode_id, file_id), bytes in (
2986
target_tree.iter_files_bytes(deferred_files)):
2987
target_tree.iter_files_bytes(deferred_files)):
2987
2988
# We're reverting a tree to the target tree so using the
2988
2989
# target tree to find the file path seems the best choice
2989
2990
# here IMO - Ian C 27/Oct/2009
2990
2991
filter_tree_path = target_tree.id2path(file_id)
2991
2992
filters = working_tree._content_filter_stack(filter_tree_path)
2992
bytes = filtered_output_bytes(bytes, filters,
2993
bytes = filtered_output_bytes(
2993
2995
ContentFilterContext(filter_tree_path, working_tree))
2994
2996
tt.create_file(bytes, trans_id, mode_id)
2996
2998
for (trans_id, mode_id, file_id), bytes in target_tree.iter_files_bytes(
2998
3000
tt.create_file(bytes, trans_id, mode_id)
2999
3001
tt.fixup_new_roots()
3109
3111
# special-case the other tree root (move its children instead)
3110
3112
if path_tree and path_tree.path2id('') == file_id:
3111
3113
# This is the root entry, skip it
3113
3115
tt.version_file(file_id, conflict[1])
3114
3116
new_conflicts.add((c_type, 'Versioned directory', conflict[1]))
3115
3117
elif c_type == 'non-directory parent':
3118
3120
parent_name = tt.final_name(parent_id)
3119
3121
parent_file_id = tt.final_file_id(parent_id)
3120
3122
new_parent_id = tt.new_directory(parent_name + '.new',
3121
parent_parent, parent_file_id)
3123
parent_parent, parent_file_id)
3122
3124
_reparent_transform_children(tt, parent_id, new_parent_id)
3123
3125
if parent_file_id is not None:
3124
3126
tt.unversion_file(parent_id)
3192
3194
except OSError as e:
3193
3195
raise errors.TransformRenameFailed(to, from_, str(e), e.errno)
3194
3196
# after rollback, don't reuse _FileMover
3196
pending_deletions = None
3197
self.past_renames = None
3198
self.pending_deletions = None
3198
3200
def apply_deletions(self):
3199
3201
"""Apply all marked deletions"""
3200
3202
for path in self.pending_deletions:
3201
3203
delete_any(path)
3202
3204
# after apply_deletions, don't reuse _FileMover
3204
pending_deletions = None
3205
self.past_renames = None
3206
self.pending_deletions = None
3207
3209
def link_tree(target_tree, source_tree):
3215
3217
for (file_id, paths, changed_content, versioned, parent, name, kind,
3216
3218
executable) in target_tree.iter_changes(source_tree,
3217
include_unchanged=True):
3219
include_unchanged=True):
3218
3220
if changed_content:
3220
3222
if kind != ('file', 'file'):