60
60
def test_fetch(self):
61
61
tree_a = self.make_branch_and_tree('a')
62
62
self.build_tree(['a/foo'])
63
tree_a.add('foo', 'file1')
64
tree_a.commit('rev1', rev_id=b'rev1')
64
rev1 = tree_a.commit('rev1')
65
65
def check_push_rev1(repo):
66
66
# ensure the revision is missing.
67
self.assertRaises(NoSuchRevision, repo.get_revision, b'rev1')
67
self.assertRaises(NoSuchRevision, repo.get_revision, rev1)
68
68
# fetch with a limit of NULL_REVISION
69
69
repo.fetch(tree_a.branch.repository,
70
70
revision_id=NULL_REVISION)
71
71
# nothing should have been pushed
72
self.assertFalse(repo.has_revision(b'rev1'))
72
self.assertFalse(repo.has_revision(rev1))
73
73
# fetch with a default limit (grab everything)
74
repo.fetch(tree_a.branch.repository)
75
repo.fetch(tree_a.branch.repository)
76
except errors.NoRoundtrippingSupport:
77
raise TestNotApplicable('roundtripping not supported')
75
78
# check that b now has all the data from a's first commit.
76
rev = repo.get_revision(b'rev1')
77
tree = repo.revision_tree(b'rev1')
79
rev = repo.get_revision(rev1)
80
tree = repo.revision_tree(rev1)
79
82
self.addCleanup(tree.unlock)
80
83
tree.get_file_text('foo')
81
84
for path in tree.all_versioned_paths():
82
85
if tree.kind(path) == "file":
83
tree.get_file(path).read()
86
with tree.get_file(path) as f:
85
89
# makes a target version repo
86
90
repo_b = self.make_to_repository('b')
205
217
raise TestNotApplicable("Need stacking support in the target.")
206
218
builder = self.make_branch_builder('branch')
207
219
builder.start_series()
208
builder.build_snapshot(None, [
209
('add', ('', b'root-id', 'directory', '')),
210
('add', ('file', b'file-id', 'file', b'content\n'))],
212
builder.build_snapshot([b'base'], [
213
('modify', ('file', b'left content\n'))],
215
builder.build_snapshot([b'base'], [
216
('modify', ('file', b'right content\n'))],
217
revision_id=b'right')
218
builder.build_snapshot([b'left', b'right'], [
219
('modify', ('file', b'left and right content\n'))],
220
revision_id=b'merge')
220
base = builder.build_snapshot(None, [
221
('add', ('', None, 'directory', '')),
222
('add', ('file', None, 'file', b'content\n'))])
223
left = builder.build_snapshot([base], [
224
('modify', ('file', b'left content\n'))])
225
right = builder.build_snapshot([base], [
226
('modify', ('file', b'right content\n'))])
227
merge = builder.build_snapshot([left, right], [
228
('modify', ('file', b'left and right content\n'))])
221
229
builder.finish_series()
222
230
branch = builder.get_branch()
231
revtree = branch.repository.revision_tree(merge)
232
root_id = revtree.path2id('')
233
file_id = revtree.path2id('file')
223
235
repo = self.make_to_repository('trunk')
224
236
trunk = repo.controldir.create_branch()
225
trunk.repository.fetch(branch.repository, b'left')
226
trunk.repository.fetch(branch.repository, b'right')
237
trunk.repository.fetch(branch.repository, left)
238
trunk.repository.fetch(branch.repository, right)
227
239
repo = self.make_to_repository('stacked')
228
240
stacked_branch = repo.controldir.create_branch()
229
241
stacked_branch.set_stacked_on_url(trunk.base)
230
stacked_branch.repository.fetch(branch.repository, b'merge')
242
stacked_branch.repository.fetch(branch.repository, merge)
231
243
unstacked_repo = stacked_branch.controldir.open_repository()
232
244
unstacked_repo.lock_read()
233
245
self.addCleanup(unstacked_repo.unlock)
234
self.assertFalse(unstacked_repo.has_revision(b'left'))
235
self.assertFalse(unstacked_repo.has_revision(b'right'))
246
self.assertFalse(unstacked_repo.has_revision(left))
247
self.assertFalse(unstacked_repo.has_revision(right))
236
248
self.assertEqual(
237
{(b'left',), (b'right',), (b'merge',)},
249
{(left,), (right,), (merge,)},
238
250
unstacked_repo.inventories.keys())
239
251
# And the basis inventories have been copied correctly
240
252
trunk.lock_read()
241
253
self.addCleanup(trunk.unlock)
242
254
left_tree, right_tree = trunk.repository.revision_trees(
244
256
stacked_branch.lock_read()
245
257
self.addCleanup(stacked_branch.unlock)
246
258
(stacked_left_tree,
247
259
stacked_right_tree) = stacked_branch.repository.revision_trees(
249
261
self.assertEqual(
250
262
left_tree.root_inventory, stacked_left_tree.root_inventory)
251
263
self.assertEqual(
255
267
# present. The texts introduced in merge (and only those) should be
256
268
# present, and also generating a stream should succeed without blowing
258
self.assertTrue(unstacked_repo.has_revision(b'merge'))
259
expected_texts = {(b'file-id', b'merge')}
260
if stacked_branch.repository.texts.get_parent_map([(b'root-id',
270
self.assertTrue(unstacked_repo.has_revision(merge))
271
expected_texts = {(file_id, merge)}
272
if stacked_branch.repository.texts.get_parent_map([(root_id,
262
274
# If a (root-id,merge) text exists, it should be in the stacked
264
expected_texts.add((b'root-id', b'merge'))
276
expected_texts.add((root_id, merge))
265
277
self.assertEqual(expected_texts, unstacked_repo.texts.keys())
266
self.assertCanStreamRevision(unstacked_repo, b'merge')
278
self.assertCanStreamRevision(unstacked_repo, merge)
268
280
def assertCanStreamRevision(self, repo, revision_id):
269
281
exclude_keys = set(repo.all_revision_ids()) - {revision_id}
276
288
def test_fetch_across_stacking_boundary_ignores_ghost(self):
277
289
if not self.repository_format_to.supports_external_lookups:
278
290
raise TestNotApplicable("Need stacking support in the target.")
291
if not self.repository_format.supports_ghosts:
292
raise TestNotApplicable("Need ghost support in the source.")
279
293
to_repo = self.make_to_repository('to')
280
294
builder = self.make_branch_builder('branch')
281
295
builder.start_series()
282
builder.build_snapshot(None, [
283
('add', ('', b'root-id', 'directory', '')),
284
('add', ('file', b'file-id', 'file', b'content\n'))],
286
builder.build_snapshot([b'base'], [
287
('modify', ('file', b'second content\n'))],
288
revision_id=b'second')
289
builder.build_snapshot([b'second', b'ghost'], [
290
('modify', ('file', b'third content\n'))],
291
revision_id=b'third')
296
base = builder.build_snapshot(None, [
297
('add', ('', None, 'directory', '')),
298
('add', ('file', None, 'file', b'content\n'))])
299
second = builder.build_snapshot([base], [
300
('modify', ('file', b'second content\n'))])
301
third = builder.build_snapshot([second, b'ghost'], [
302
('modify', ('file', b'third content\n'))])
292
303
builder.finish_series()
293
304
branch = builder.get_branch()
305
revtree = branch.repository.revision_tree(base)
306
root_id = revtree.path2id('')
307
file_id = revtree.path2id('file')
294
308
repo = self.make_to_repository('trunk')
295
309
trunk = repo.controldir.create_branch()
296
trunk.repository.fetch(branch.repository, b'second')
310
trunk.repository.fetch(branch.repository, second)
297
311
repo = self.make_to_repository('stacked')
298
312
stacked_branch = repo.controldir.create_branch()
299
313
stacked_branch.set_stacked_on_url(trunk.base)
300
stacked_branch.repository.fetch(branch.repository, b'third')
314
stacked_branch.repository.fetch(branch.repository, third)
301
315
unstacked_repo = stacked_branch.controldir.open_repository()
302
316
unstacked_repo.lock_read()
303
317
self.addCleanup(unstacked_repo.unlock)
304
self.assertFalse(unstacked_repo.has_revision(b'second'))
318
self.assertFalse(unstacked_repo.has_revision(second))
305
319
self.assertFalse(unstacked_repo.has_revision(b'ghost'))
306
320
self.assertEqual(
307
{(b'second',), (b'third',)},
321
{(second,), (third,)},
308
322
unstacked_repo.inventories.keys())
309
323
# And the basis inventories have been copied correctly
310
324
trunk.lock_read()
311
325
self.addCleanup(trunk.unlock)
312
second_tree = trunk.repository.revision_tree(b'second')
326
second_tree = trunk.repository.revision_tree(second)
313
327
stacked_branch.lock_read()
314
328
self.addCleanup(stacked_branch.unlock)
315
stacked_second_tree = stacked_branch.repository.revision_tree(b'second')
329
stacked_second_tree = stacked_branch.repository.revision_tree(second)
316
330
self.assertEqual(second_tree, stacked_second_tree)
317
331
# Finally, it's not enough to see that the basis inventories are
318
332
# present. The texts introduced in merge (and only those) should be
319
333
# present, and also generating a stream should succeed without blowing
321
self.assertTrue(unstacked_repo.has_revision(b'third'))
322
expected_texts = {(b'file-id', b'third')}
323
if stacked_branch.repository.texts.get_parent_map([(b'root-id',
335
self.assertTrue(unstacked_repo.has_revision(third))
336
expected_texts = {(file_id, third)}
337
if stacked_branch.repository.texts.get_parent_map([(root_id,
325
339
# If a (root-id,third) text exists, it should be in the stacked
327
expected_texts.add((b'root-id', b'third'))
341
expected_texts.add((root_id, third))
328
342
self.assertEqual(expected_texts, unstacked_repo.texts.keys())
329
self.assertCanStreamRevision(unstacked_repo, b'third')
343
self.assertCanStreamRevision(unstacked_repo, third)
331
345
def test_fetch_from_stacked_to_stacked_copies_parent_inventories(self):
332
346
"""Fetch from a stacked branch copies inventories for parents of
420
434
def test_fetch_missing_basis_text(self):
421
435
"""If fetching a delta, we should die if a basis is not present."""
436
if not self.repository_format.supports_full_versioned_files:
437
raise TestNotApplicable('Need full versioned files support')
438
if not self.repository_format_to.supports_full_versioned_files:
439
raise TestNotApplicable('Need full versioned files support')
422
440
tree = self.make_branch_and_tree('tree')
423
441
self.build_tree(['tree/a'])
425
tree.commit('one', rev_id=b'rev-one')
443
rev1 = tree.commit('one')
426
444
self.build_tree_contents([('tree/a', b'new contents\n')])
427
tree.commit('two', rev_id=b'rev-two')
445
rev2 = tree.commit('two')
429
447
to_repo = self.make_to_repository('to_repo')
430
448
# We build a broken revision so that we can test the fetch code dies
514
538
from_repo = from_tree.branch.repository
515
539
check_repo_format_for_funky_id_on_win32(from_repo)
516
540
self.build_tree(['tree/filename'])
541
if not from_tree.supports_setting_file_ids():
542
raise TestNotApplicable('from tree format can not create custom file ids')
517
543
from_tree.add('filename', 'funky-chars<>%&;"\'')
518
544
from_tree.commit('commit filename')
519
545
to_repo = self.make_to_repository('to')
520
to_repo.fetch(from_tree.branch.repository, from_tree.get_parent_ids()[0])
547
to_repo.fetch(from_tree.branch.repository, from_tree.get_parent_ids()[0])
548
except errors.NoRoundtrippingSupport:
549
raise TestNotApplicable('roundtripping not supported')
522
551
def test_fetch_revision_hash(self):
523
552
"""Ensure that inventory hashes are updated by fetch"""
553
if not self.repository_format_to.supports_full_versioned_files:
554
raise TestNotApplicable('Need full versioned files')
524
555
from_tree = self.make_branch_and_tree('tree')
525
from_tree.commit('foo', rev_id=b'foo-id')
556
revid = from_tree.commit('foo')
526
557
to_repo = self.make_to_repository('to')
527
to_repo.fetch(from_tree.branch.repository)
528
recorded_inv_sha1 = to_repo.get_revision(b'foo-id').inventory_sha1
559
to_repo.fetch(from_tree.branch.repository)
560
except errors.NoRoundtrippingSupport:
561
raise TestNotApplicable('roundtripping not supported')
562
recorded_inv_sha1 = to_repo.get_revision(revid).inventory_sha1
529
563
to_repo.lock_read()
530
564
self.addCleanup(to_repo.unlock)
531
stream = to_repo.inventories.get_record_stream([(b'foo-id',)],
565
stream = to_repo.inventories.get_record_stream([(revid,)],
532
566
'unordered', True)
533
567
bytes = stream.next().get_bytes_as('fulltext')
534
568
computed_inv_sha1 = osutils.sha_string(bytes)