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)
2231
2231
if from_dir is None and include_root is True:
2232
2232
root_entry = inventory.make_entry('directory', '',
2233
ROOT_PARENT, self.get_root_id())
2233
ROOT_PARENT, self.get_root_id())
2234
2234
yield '', 'V', 'directory', root_entry.file_id, root_entry
2235
2235
entries = self._iter_entries_for_dir(from_dir or '')
2236
2236
for path, entry in entries:
2237
2237
yield path, 'V', entry.kind, entry.file_id, entry
2239
def kind(self, path, file_id=None):
2239
def kind(self, path):
2240
2240
trans_id = self._path2trans_id(path)
2241
2241
if trans_id is None:
2242
2242
raise errors.NoSuchFile(path)
2243
2243
return self._transform.final_kind(trans_id)
2245
def stored_kind(self, path, file_id=None):
2245
def stored_kind(self, path):
2246
2246
trans_id = self._path2trans_id(path)
2247
2247
if trans_id is None:
2248
2248
raise errors.NoSuchFile(path)
2250
2250
return self._transform._new_contents[trans_id]
2251
2251
except KeyError:
2252
return self._transform._tree.stored_kind(path, file_id)
2252
return self._transform._tree.stored_kind(path)
2254
def get_file_mtime(self, path, file_id=None):
2254
def get_file_mtime(self, path):
2255
2255
"""See Tree.get_file_mtime"""
2257
file_id = self.path2id(path)
2256
file_id = self.path2id(path)
2258
2257
if file_id is None:
2259
2258
raise errors.NoSuchFile(path)
2260
2259
if not self._content_change(file_id):
2261
2260
return self._transform._tree.get_file_mtime(
2262
self._transform._tree.id2path(file_id), file_id)
2261
self._transform._tree.id2path(file_id))
2263
2262
trans_id = self._path2trans_id(path)
2264
2263
return self._stat_limbo_file(trans_id).st_mtime
2266
def get_file_size(self, path, file_id=None):
2265
def get_file_size(self, path):
2267
2266
"""See Tree.get_file_size"""
2268
2267
trans_id = self._path2trans_id(path)
2269
2268
if trans_id is None:
2274
2273
if trans_id in self._transform._new_contents:
2275
2274
return self._stat_limbo_file(trans_id).st_size
2276
if self.kind(path, file_id) == 'file':
2277
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)
2281
def get_file_verifier(self, path, file_id=None, stat_value=None):
2280
def get_file_verifier(self, path, stat_value=None):
2282
2281
trans_id = self._path2trans_id(path)
2283
2282
if trans_id is None:
2284
2283
raise errors.NoSuchFile(path)
2285
2284
kind = self._transform._new_contents.get(trans_id)
2286
2285
if kind is None:
2287
return self._transform._tree.get_file_verifier(path, file_id)
2286
return self._transform._tree.get_file_verifier(path)
2288
2287
if kind == 'file':
2289
with self.get_file(path, file_id) as fileobj:
2288
with self.get_file(path) as fileobj:
2290
2289
return ("SHA1", sha_file(fileobj))
2292
def get_file_sha1(self, path, file_id=None, stat_value=None):
2291
def get_file_sha1(self, path, stat_value=None):
2293
2292
trans_id = self._path2trans_id(path)
2294
2293
if trans_id is None:
2295
2294
raise errors.NoSuchFile(path)
2296
2295
kind = self._transform._new_contents.get(trans_id)
2297
2296
if kind is None:
2298
return self._transform._tree.get_file_sha1(path, file_id)
2297
return self._transform._tree.get_file_sha1(path)
2299
2298
if kind == 'file':
2300
with self.get_file(path, file_id) as fileobj:
2299
with self.get_file(path) as fileobj:
2301
2300
return sha_file(fileobj)
2303
def is_executable(self, path, file_id=None):
2302
def is_executable(self, path):
2304
2303
trans_id = self._path2trans_id(path)
2305
2304
if trans_id is None:
2358
2357
return kind, size, executable, link_or_sha1
2360
2359
def iter_changes(self, from_tree, include_unchanged=False,
2361
specific_files=None, pb=None, extra_trees=None,
2362
require_versioned=True, want_unversioned=False):
2360
specific_files=None, pb=None, extra_trees=None,
2361
require_versioned=True, want_unversioned=False):
2363
2362
"""See InterTree.iter_changes.
2365
2364
This has a fast path that is only used when the from_tree matches
2366
2365
the transform tree, and no fancy options are supplied.
2368
if (from_tree is not self._transform._tree or include_unchanged or
2369
specific_files or want_unversioned):
2367
if (from_tree is not self._transform._tree or include_unchanged
2368
or specific_files or want_unversioned):
2370
2369
return tree.InterTree(from_tree, self).iter_changes(
2371
2370
include_unchanged=include_unchanged,
2372
2371
specific_files=specific_files,
2378
2377
raise ValueError('want_unversioned is not supported')
2379
2378
return self._transform.iter_changes()
2381
def get_file(self, path, file_id=None):
2380
def get_file(self, path):
2382
2381
"""See Tree.get_file"""
2384
file_id = self.path2id(path)
2382
file_id = self.path2id(path)
2385
2383
if not self._content_change(file_id):
2386
return self._transform._tree.get_file(path, file_id)
2384
return self._transform._tree.get_file(path)
2387
2385
trans_id = self._path2trans_id(path)
2388
2386
name = self._transform._limbo_name(trans_id)
2389
2387
return open(name, 'rb')
2391
def get_file_with_stat(self, path, file_id=None):
2392
return self.get_file(path, file_id), None
2389
def get_file_with_stat(self, path):
2390
return self.get_file(path), None
2394
def annotate_iter(self, path, file_id=None,
2392
def annotate_iter(self, path,
2395
2393
default_revision=_mod_revision.CURRENT_REVISION):
2397
file_id = self.path2id(path)
2394
file_id = self.path2id(path)
2398
2395
changes = self._iter_changes_cache.get(file_id)
2399
2396
if changes is None:
2421
2418
# It would be nice to be able to use the new Annotator based
2422
2419
# approach, as well.
2423
2420
return annotate.reannotate([old_annotation],
2424
self.get_file(path, file_id).readlines(),
2421
self.get_file(path).readlines(),
2425
2422
default_revision)
2427
def get_symlink_target(self, path, file_id=None):
2424
def get_symlink_target(self, path):
2428
2425
"""See Tree.get_symlink_target"""
2430
file_id = self.path2id(path)
2426
file_id = self.path2id(path)
2431
2427
if not self._content_change(file_id):
2432
2428
return self._transform._tree.get_symlink_target(path)
2433
2429
trans_id = self._path2trans_id(path)
2447
2443
path_from_root = self._final_paths.get_path(child_id)
2448
2444
basename = self._transform.final_name(child_id)
2449
2445
file_id = self._transform.final_file_id(child_id)
2450
kind = self._transform.final_kind(child_id)
2446
kind = self._transform.final_kind(child_id)
2451
2447
if kind is not None:
2452
2448
versioned_kind = kind
2454
2450
kind = 'unknown'
2455
2451
versioned_kind = self._transform._tree.stored_kind(
2456
self._transform._tree.id2path(file_id),
2452
self._transform._tree.id2path(file_id))
2458
2453
if versioned_kind == 'directory':
2459
2454
subdirs.append(child_id)
2460
2455
children.append((path_from_root, basename, kind, None,
2601
2596
for dir, files in wt.walkdirs():
2602
2597
existing_files.update(f[0] for f in files)
2603
2598
for num, (tree_path, entry) in \
2604
enumerate(tree.iter_entries_by_dir()):
2605
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)
2606
2602
if entry.parent_id is None:
2608
2604
reparent = False
2621
2617
divert.add(file_id)
2622
if (file_id not in divert and
2623
_content_match(tree, entry, tree_path, file_id, kind,
2618
if (file_id not in divert
2620
tree, entry, tree_path, file_id, kind,
2625
2622
tt.delete_contents(tt.trans_id_tree_path(tree_path))
2626
2623
if kind == 'directory':
2627
2624
reparent = True
2632
2629
trans_id = tt.create_path(entry.name, parent_id)
2633
2630
file_trans_id[file_id] = trans_id
2634
2631
tt.version_file(file_id, trans_id)
2635
executable = tree.is_executable(tree_path, file_id)
2632
executable = tree.is_executable(tree_path)
2637
2634
tt.set_executability(executable, trans_id)
2638
trans_data = (trans_id, file_id, tree_path, entry.text_sha1)
2635
trans_data = (trans_id, file_id,
2636
tree_path, entry.text_sha1)
2639
2637
deferred_contents.append((tree_path, trans_data))
2641
2639
file_trans_id[file_id] = new_by_entry(
2642
tree_path, tt, entry, parent_id, tree)
2640
tree_path, tt, entry, parent_id, tree)
2644
2642
new_trans_id = file_trans_id[file_id]
2645
2643
old_parent = tt.trans_id_tree_path(tree_path)
2649
2647
accelerator_tree, hardlink)
2650
2648
pp.next_phase()
2651
2649
divert_trans = set(file_trans_id[f] for f in divert)
2652
resolver = lambda t, c: resolve_checkout(t, c, divert_trans)
2652
return resolve_checkout(t, c, divert_trans)
2653
2653
raw_conflicts = resolve_conflicts(tt, pass_func=resolver)
2654
2654
if len(raw_conflicts) > 0:
2655
2655
precomputed_delta = None
2688
2688
accelerator_path = unchanged.get(tree_path)
2689
2689
if accelerator_path is None:
2690
2690
new_desired_files.append((tree_path,
2691
(trans_id, file_id, tree_path, text_sha1)))
2691
(trans_id, file_id, tree_path, text_sha1)))
2693
2693
pb.update(gettext('Adding file contents'), count + offset, total)
2700
2700
if wt.supports_content_filtering():
2701
2701
filters = wt._content_filter_stack(tree_path)
2702
2702
chunks = filtered_output_bytes(chunks, filters,
2703
ContentFilterContext(tree_path, tree))
2703
ContentFilterContext(tree_path, tree))
2704
2704
tt.create_file(chunks, trans_id, sha1=text_sha1)
2706
2706
offset += count
2709
2709
if wt.supports_content_filtering():
2710
2710
filters = wt._content_filter_stack(tree_path)
2711
2711
contents = filtered_output_bytes(contents, filters,
2712
ContentFilterContext(tree_path, tree))
2712
ContentFilterContext(tree_path, tree))
2713
2713
tt.create_file(contents, trans_id, sha1=text_sha1)
2714
2714
pb.update(gettext('Adding file contents'), count + offset, total)
2734
2734
if entry.kind == "file":
2735
2735
with open(target_path, 'rb') as f1, \
2736
tree.get_file(tree_path, file_id) as f2:
2736
tree.get_file(tree_path) as f2:
2737
2737
if osutils.compare_files(f1, f2):
2739
2739
elif entry.kind == "symlink":
2740
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):
2761
2761
final_parent = tt.final_parent(old_file)
2762
2762
if new_file in divert:
2763
new_name = tt.final_name(old_file)+'.diverted'
2763
new_name = tt.final_name(old_file) + '.diverted'
2764
2764
tt.adjust_path(new_name, final_parent, new_file)
2765
2765
new_conflicts.add((c_type, 'Diverted to',
2766
2766
new_file, old_file))
2768
new_name = tt.final_name(old_file)+'.moved'
2768
new_name = tt.final_name(old_file) + '.moved'
2769
2769
tt.adjust_path(new_name, final_parent, old_file)
2770
2770
new_conflicts.add((c_type, 'Moved existing file to',
2771
2771
old_file, new_file))
2777
2777
name = entry.name
2778
2778
kind = entry.kind
2779
2779
if kind == 'file':
2780
with tree.get_file(path, entry.file_id) as f:
2781
executable = tree.is_executable(path, entry.file_id)
2780
with tree.get_file(path) as f:
2781
executable = tree.is_executable(path)
2782
2782
return tt.new_file(
2783
name, parent_id, osutils.file_iterator(f), entry.file_id,
2783
name, parent_id, osutils.file_iterator(f), entry.file_id,
2785
2785
elif kind in ('directory', 'tree-reference'):
2786
2786
trans_id = tt.new_directory(name, parent_id, entry.file_id)
2787
2787
if kind == 'tree-reference':
2788
2788
tt.set_tree_reference(entry.reference_revision, trans_id)
2789
2789
return trans_id
2790
2790
elif kind == 'symlink':
2791
target = tree.get_symlink_target(path, entry.file_id)
2791
target = tree.get_symlink_target(path)
2792
2792
return tt.new_symlink(name, parent_id, target, entry.file_id)
2794
2794
raise errors.BadFileKindError(name, kind)
2797
2797
def create_from_tree(tt, trans_id, tree, path, file_id=None, chunks=None,
2798
filter_tree_path=None):
2798
filter_tree_path=None):
2799
2799
"""Create new file contents according to tree contents.
2801
2801
:param filter_tree_path: the tree path to use to lookup
2802
2802
content filters to apply to the bytes output in the working tree.
2803
2803
This only applies if the working tree supports content filtering.
2805
kind = tree.kind(path, file_id)
2805
kind = tree.kind(path)
2806
2806
if kind == 'directory':
2807
2807
tt.create_directory(trans_id)
2808
2808
elif kind == "file":
2809
2809
if chunks is None:
2810
f = tree.get_file(path, file_id)
2810
f = tree.get_file(path)
2811
2811
chunks = osutils.file_iterator(f)
2816
2816
if wt.supports_content_filtering() and filter_tree_path is not None:
2817
2817
filters = wt._content_filter_stack(filter_tree_path)
2818
chunks = filtered_output_bytes(chunks, filters,
2818
chunks = filtered_output_bytes(
2819
2820
ContentFilterContext(filter_tree_path, tree))
2820
2821
tt.create_file(chunks, trans_id)
2822
2823
if f is not None:
2824
2825
elif kind == "symlink":
2825
tt.create_symlink(tree.get_symlink_target(path, file_id), trans_id)
2826
tt.create_symlink(tree.get_symlink_target(path), trans_id)
2827
2828
raise AssertionError('Unknown kind %r' % kind)
2867
2868
child_pb, filenames, backups,
2868
2869
merge_modified, basis_tree)
2869
2870
with ui.ui_factory.nested_progress_bar() as child_pb:
2870
raw_conflicts = resolve_conflicts(tt, child_pb,
2871
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))
2872
2873
conflicts = cook_conflicts(raw_conflicts, tt)
2873
2874
return conflicts, merge_modified
2881
2882
# than the target changes relative to the working tree. Because WT4 has an
2882
2883
# optimizer to compare itself to a target, but no optimizer for the
2884
change_list = working_tree.iter_changes(target_tree,
2885
specific_files=specific_files, pb=pb)
2885
change_list = working_tree.iter_changes(
2886
target_tree, specific_files=specific_files, pb=pb)
2886
2887
if not target_tree.is_versioned(u''):
2887
2888
skip_root = True
2891
2892
deferred_files = []
2892
2893
for id_num, (file_id, path, changed_content, versioned, parent, name,
2893
kind, executable) in enumerate(change_list):
2894
kind, executable) in enumerate(change_list):
2894
2895
target_path, wt_path = path
2895
2896
target_versioned, wt_versioned = versioned
2896
2897
target_parent, wt_parent = parent
2904
2905
if changed_content:
2905
2906
keep_content = False
2906
2907
if wt_kind == 'file' and (backups or target_kind is None):
2907
wt_sha1 = working_tree.get_file_sha1(wt_path, file_id)
2908
wt_sha1 = working_tree.get_file_sha1(wt_path)
2908
2909
if merge_modified.get(file_id) != wt_sha1:
2909
2910
# acquire the basis tree lazily to prevent the
2910
2911
# expense of accessing it when it's not needed ?
2912
2913
if basis_tree is None:
2913
2914
basis_tree = working_tree.basis_tree()
2914
2915
basis_tree.lock_read()
2915
basis_path = find_previous_path(working_tree, basis_tree, wt_path)
2916
basis_path = find_previous_path(
2917
working_tree, basis_tree, wt_path)
2916
2918
if basis_path is None:
2917
2919
if target_kind is None and not target_versioned:
2918
2920
keep_content = True
2920
if wt_sha1 != basis_tree.get_file_sha1(basis_path, file_id):
2922
if wt_sha1 != basis_tree.get_file_sha1(basis_path):
2921
2923
keep_content = True
2922
2924
if wt_kind is not None:
2923
2925
if not keep_content:
2939
2941
tt.create_directory(trans_id)
2940
2942
if target_kind == 'tree-reference':
2941
2943
revision = target_tree.get_reference_revision(
2942
target_path, file_id)
2943
2945
tt.set_tree_reference(revision, trans_id)
2944
2946
elif target_kind == 'symlink':
2945
2947
tt.create_symlink(target_tree.get_symlink_target(
2946
target_path, file_id), trans_id)
2948
target_path), trans_id)
2947
2949
elif target_kind == 'file':
2948
deferred_files.append((target_path, (trans_id, mode_id, file_id)))
2950
deferred_files.append(
2951
(target_path, (trans_id, mode_id, file_id)))
2949
2952
if basis_tree is None:
2950
2953
basis_tree = working_tree.basis_tree()
2951
2954
basis_tree.lock_read()
2952
new_sha1 = target_tree.get_file_sha1(target_path, file_id)
2955
new_sha1 = target_tree.get_file_sha1(target_path)
2953
2956
basis_path = find_previous_path(target_tree, basis_tree, target_path)
2954
2957
if (basis_path is not None and
2955
new_sha1 == basis_tree.get_file_sha1(basis_path, file_id)):
2958
new_sha1 == basis_tree.get_file_sha1(basis_path)):
2956
2959
if file_id in merge_modified:
2957
2960
del merge_modified[file_id]
2967
2970
tt.version_file(file_id, trans_id)
2968
2971
if wt_versioned and not target_versioned:
2969
2972
tt.unversion_file(trans_id)
2970
if (target_name is not None and
2971
(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)):
2972
2975
if target_name == '' and target_parent is None:
2973
2976
parent_trans = ROOT_PARENT
2981
2984
tt.set_executability(target_executable, trans_id)
2982
2985
if working_tree.supports_content_filtering():
2983
2986
for (trans_id, mode_id, file_id), bytes in (
2984
target_tree.iter_files_bytes(deferred_files)):
2987
target_tree.iter_files_bytes(deferred_files)):
2985
2988
# We're reverting a tree to the target tree so using the
2986
2989
# target tree to find the file path seems the best choice
2987
2990
# here IMO - Ian C 27/Oct/2009
2988
2991
filter_tree_path = target_tree.id2path(file_id)
2989
2992
filters = working_tree._content_filter_stack(filter_tree_path)
2990
bytes = filtered_output_bytes(bytes, filters,
2993
bytes = filtered_output_bytes(
2991
2995
ContentFilterContext(filter_tree_path, working_tree))
2992
2996
tt.create_file(bytes, trans_id, mode_id)
2994
2998
for (trans_id, mode_id, file_id), bytes in target_tree.iter_files_bytes(
2996
3000
tt.create_file(bytes, trans_id, mode_id)
2997
3001
tt.fixup_new_roots()
3107
3111
# special-case the other tree root (move its children instead)
3108
3112
if path_tree and path_tree.path2id('') == file_id:
3109
3113
# This is the root entry, skip it
3111
3115
tt.version_file(file_id, conflict[1])
3112
3116
new_conflicts.add((c_type, 'Versioned directory', conflict[1]))
3113
3117
elif c_type == 'non-directory parent':
3116
3120
parent_name = tt.final_name(parent_id)
3117
3121
parent_file_id = tt.final_file_id(parent_id)
3118
3122
new_parent_id = tt.new_directory(parent_name + '.new',
3119
parent_parent, parent_file_id)
3123
parent_parent, parent_file_id)
3120
3124
_reparent_transform_children(tt, parent_id, new_parent_id)
3121
3125
if parent_file_id is not None:
3122
3126
tt.unversion_file(parent_id)
3190
3194
except OSError as e:
3191
3195
raise errors.TransformRenameFailed(to, from_, str(e), e.errno)
3192
3196
# after rollback, don't reuse _FileMover
3194
pending_deletions = None
3197
self.past_renames = None
3198
self.pending_deletions = None
3196
3200
def apply_deletions(self):
3197
3201
"""Apply all marked deletions"""
3198
3202
for path in self.pending_deletions:
3199
3203
delete_any(path)
3200
3204
# after apply_deletions, don't reuse _FileMover
3202
pending_deletions = None
3205
self.past_renames = None
3206
self.pending_deletions = None
3205
3209
def link_tree(target_tree, source_tree):
3213
3217
for (file_id, paths, changed_content, versioned, parent, name, kind,
3214
3218
executable) in target_tree.iter_changes(source_tree,
3215
include_unchanged=True):
3219
include_unchanged=True):
3216
3220
if changed_content:
3218
3222
if kind != ('file', 'file'):