3 # https://sourceware.org/bugzilla/show_bug.cgi?id=26034
4 export "BUP_ARGV_0"="$0"
7 export "BUP_ARGV_${arg_i}"="$arg"
11 bup_python="$(dirname "$0")/../lib/cmd/bup-python" || exit $?
12 exec "$bup_python" "$0"
16 from __future__ import print_function
17 from errno import ENOENT
18 from os import chdir, mkdir, rename
19 from os.path import abspath, dirname
20 from shutil import rmtree
21 from subprocess import PIPE
24 # For buptest, wvtest, ...
25 sys.path[:0] = (abspath(os.path.dirname(__file__) + '/..'),)
27 from bup import compat, path
28 from bup.compat import environ, getcwd, items
29 from bup.helpers import bquote, merge_dict, unlink
30 from bup.io import byte_stream
31 from buptest import ex, exo, test_tempdir
32 from wvtest import wvcheck, wvfail, wvmsg, wvpass, wvpasseq, wvpassne, wvstart
36 stdout = byte_stream(sys.stdout)
38 # FIXME: per-test function
39 environ[b'GIT_AUTHOR_NAME'] = b'bup test-get'
40 environ[b'GIT_COMMITTER_NAME'] = b'bup test-get'
41 environ[b'GIT_AUTHOR_EMAIL'] = b'bup@85430dcca2b611e4b2c3-8f5691723476'
42 environ[b'GIT_COMMITTER_EMAIL'] = b'bup@85430dcca2b611e4b2c3-8f5691723476'
44 # The clean-repo test can probably be applied more broadly. It was
45 # initially just applied to test-pick to catch a bug.
48 bup_cmd = bup.path.exe()
51 err = [] # because python's scoping mess...
52 def onerror(function, path, excinfo):
53 err.append((function, path, excinfo))
54 rmtree(path, onerror=onerror)
56 function, path, excinfo = err[0]
57 ex_type, ex, traceback = excinfo
58 if (not isinstance(ex, OSError)) or ex.errno != ENOENT:
61 def verify_trees_match(path1, path2):
63 exr = exo((top + b'/t/compare-trees', b'-c', path1, path2), check=False)
66 wvcheck(exr.rc == 0, 'process exit %d == 0' % exr.rc)
68 def verify_rcz(cmd, **kwargs):
69 assert not kwargs.get('check')
70 kwargs['check'] = False
71 result = exo(cmd, **kwargs)
72 stdout.write(result.out)
73 rc = result.proc.returncode
74 wvcheck(rc == 0, 'process exit %d == 0' % rc)
77 # FIXME: multline, or allow opts generally?
79 def verify_rx(rx, string):
80 wvcheck(re.search(rx, string), 'rx %r matches %r' % (rx, string))
82 def verify_nrx(rx, string):
83 wvcheck(not re.search(rx, string), "rx %r doesn't match %r" % (rx, string))
85 def validate_clean_repo():
86 out = verify_rcz((b'git', b'--git-dir', b'get-dest', b'fsck')).out
87 verify_nrx(br'dangling|mismatch|missing|unreachable', out)
89 def validate_blob(src_id, dest_id):
93 cat_tree = top + b'/t/git-cat-tree'
94 src_blob = verify_rcz((cat_tree, b'--git-dir', b'get-src', src_id)).out
95 dest_blob = verify_rcz((cat_tree, b'--git-dir', b'get-src', src_id)).out
96 wvpasseq(src_blob, dest_blob)
98 def validate_tree(src_id, dest_id):
101 rmrf(b'restore-dest')
102 mkdir(b'restore-src')
103 mkdir(b'restore-dest')
105 commit_env = merge_dict(environ, {b'GIT_COMMITTER_DATE': b'2014-01-01 01:01'})
107 # Create a commit so the archive contents will have matching timestamps.
108 src_c = exo((b'git', b'--git-dir', b'get-src',
109 b'commit-tree', b'-m', b'foo', src_id),
110 env=commit_env).out.strip()
111 dest_c = exo((b'git', b'--git-dir', b'get-dest',
112 b'commit-tree', b'-m', b'foo', dest_id),
113 env=commit_env).out.strip()
114 exr = verify_rcz(b'git --git-dir get-src archive %s | tar xvf - -C restore-src'
117 if exr.rc != 0: return False
118 exr = verify_rcz(b'git --git-dir get-dest archive %s | tar xvf - -C restore-dest'
121 if exr.rc != 0: return False
123 # git archive doesn't include an entry for ./.
124 unlink(b'restore-src/pax_global_header')
125 unlink(b'restore-dest/pax_global_header')
126 ex((b'touch', b'-r', b'restore-src', b'restore-dest'))
127 verify_trees_match(b'restore-src/', b'restore-dest/')
129 rmrf(b'restore-dest')
131 def validate_commit(src_id, dest_id):
132 exr = verify_rcz((b'git', b'--git-dir', b'get-src', b'cat-file', b'commit', src_id))
133 if exr.rc != 0: return False
135 exr = verify_rcz((b'git', b'--git-dir', b'get-dest', b'cat-file', b'commit', dest_id))
136 if exr.rc != 0: return False
138 wvpasseq(src_cat, dest_cat)
139 if src_cat != dest_cat: return False
142 rmrf(b'restore-dest')
143 mkdir(b'restore-src')
144 mkdir(b'restore-dest')
145 qsrc = bquote(src_id)
146 qdest = bquote(dest_id)
147 exr = verify_rcz((b'git --git-dir get-src archive ' + qsrc
148 + b' | tar xf - -C restore-src'),
150 if exr.rc != 0: return False
151 exr = verify_rcz((b'git --git-dir get-dest archive ' + qdest +
152 b' | tar xf - -C restore-dest'),
154 if exr.rc != 0: return False
156 # git archive doesn't include an entry for ./.
157 ex((b'touch', b'-r', b'restore-src', b'restore-dest'))
158 verify_trees_match(b'restore-src/', b'restore-dest/')
160 rmrf(b'restore-dest')
162 def _validate_save(orig_dir, save_path, commit_id, tree_id):
165 exr = verify_rcz((bup_cmd, b'-d', b'get-dest',
166 b'restore', b'-C', b'restore', save_path + b'/.'))
167 if exr.rc: return False
168 verify_trees_match(orig_dir + b'/', b'restore/')
170 # FIXME: double check that get-dest is correct
171 exr = verify_rcz((b'git', b'--git-dir', b'get-dest', b'ls-tree', tree_id))
172 if exr.rc: return False
173 cat = verify_rcz((b'git', b'--git-dir', b'get-dest',
174 b'cat-file', b'commit', commit_id))
175 if cat.rc: return False
176 wvpasseq(b'tree ' + tree_id, cat.out.splitlines()[0])
178 # FIXME: re-merge save and new_save?
180 def validate_save(dest_name, restore_subpath, commit_id, tree_id, orig_value,
182 out = get_out.splitlines()
183 print('blarg: out', repr(out), file=sys.stderr)
184 wvpasseq(2, len(out))
186 get_commit_id = out[1]
187 wvpasseq(tree_id, get_tree_id)
188 wvpasseq(commit_id, get_commit_id)
189 _validate_save(orig_value, dest_name + restore_subpath, commit_id, tree_id)
191 def validate_new_save(dest_name, restore_subpath, commit_id, tree_id, orig_value,
193 out = get_out.splitlines()
194 wvpasseq(2, len(out))
196 get_commit_id = out[1]
197 wvpasseq(tree_id, get_tree_id)
198 wvpassne(commit_id, get_commit_id)
199 _validate_save(orig_value, dest_name + restore_subpath, get_commit_id, tree_id)
201 def validate_tagged_save(tag_name, restore_subpath,
202 commit_id, tree_id, orig_value, get_out):
203 out = get_out.splitlines()
204 wvpasseq(1, len(out))
206 wvpasseq(commit_id, get_tag_id)
207 # Make sure tmp doesn't already exist.
208 exr = exo((b'git', b'--git-dir', b'get-dest', b'show-ref', b'tmp-branch-for-tag'),
212 ex((b'git', b'--git-dir', b'get-dest', b'branch', b'tmp-branch-for-tag',
213 b'refs/tags/' + tag_name))
214 _validate_save(orig_value, b'tmp-branch-for-tag/latest' + restore_subpath,
216 ex((b'git', b'--git-dir', b'get-dest', b'branch', b'-D', b'tmp-branch-for-tag'))
218 def validate_new_tagged_commit(tag_name, commit_id, tree_id, get_out):
219 out = get_out.splitlines()
220 wvpasseq(1, len(out))
222 wvpassne(commit_id, get_tag_id)
223 validate_tree(tree_id, tag_name + b':')
228 def _run_get(disposition, method, what):
229 print('run_get:', repr((disposition, method, what)), file=sys.stderr)
232 if disposition == 'get':
233 get_cmd = (bup_cmd, b'-d', b'get-dest',
234 b'get', b'-vvct', b'--print-tags', b'-s', b'get-src')
235 elif disposition == 'get-on':
236 get_cmd = (bup_cmd, b'-d', b'get-dest',
237 b'on', b'-', b'get', b'-vvct', b'--print-tags', b'-s', b'get-src')
238 elif disposition == 'get-to':
239 get_cmd = (bup_cmd, b'-d', b'get-dest',
240 b'get', b'-vvct', b'--print-tags', b'-s', b'get-src',
241 b'-r', b'-:' + getcwd() + b'/get-dest')
243 raise Exception('error: unexpected get disposition ' + repr(disposition))
245 global get_cases_tested
246 if isinstance(what, bytes):
247 cmd = get_cmd + (method, what)
249 assert not isinstance(what, str) # python 3 sanity check
250 if method in (b'--ff', b'--append', b'--pick', b'--force-pick', b'--new-tag',
254 cmd = get_cmd + (method, src, dest)
255 result = exo(cmd, check=False, stderr=PIPE)
256 get_cases_tested += 1
257 fsck = ex((bup_cmd, b'-d', b'get-dest', b'fsck'), check=False)
261 def run_get(disposition, method, what=None, given=None):
264 ex((bup_cmd, b'-d', b'get-dest', b'init'))
267 # FIXME: replace bup-get with independent commands as is feasible
268 exr = _run_get(disposition, b'--replace', given)
270 return _run_get(disposition, method, what)
272 def test_universal_behaviors(get_disposition):
273 methods = (b'--ff', b'--append', b'--pick', b'--force-pick', b'--new-tag',
274 b'--replace', b'--unnamed')
275 for method in methods:
276 mmsg = method.decode('ascii')
277 wvstart(get_disposition + ' ' + mmsg + ', missing source, fails')
278 exr = run_get(get_disposition, method, b'not-there')
280 verify_rx(br'cannot find source', exr.err)
281 for method in methods:
282 mmsg = method.decode('ascii')
283 wvstart(get_disposition + ' ' + mmsg + ' / fails')
284 exr = run_get(get_disposition, method, b'/')
286 verify_rx(b'cannot fetch entire repository', exr.err)
288 def verify_only_refs(**kwargs):
289 for kind, refs in items(kwargs):
291 abs_refs = [b'refs/heads/' + ref for ref in refs]
294 abs_refs = [b'refs/tags/' + ref for ref in refs]
297 raise TypeError('unexpected keyword argument %r' % kind)
299 verify_rcz([b'git', b'--git-dir', b'get-dest',
300 b'show-ref', b'--verify', karg] + abs_refs)
301 exr = exo((b'git', b'--git-dir', b'get-dest', b'show-ref', karg),
304 expected_refs = sorted(abs_refs)
305 repo_refs = sorted([x.split()[1] for x in exr.out.splitlines()])
306 wvpasseq(expected_refs, repo_refs)
308 # FIXME: can we just check "git show-ref --heads == ''"?
309 exr = exo((b'git', b'--git-dir', b'get-dest', b'show-ref', karg),
312 wvpasseq(b'', exr.out.strip())
314 def test_replace(get_disposition, src_info):
315 print('blarg:', repr(src_info), file=sys.stderr)
317 wvstart(get_disposition + ' --replace to root fails')
318 for item in (b'.tag/tinyfile',
319 b'src/latest' + src_info['tinyfile-path'],
321 b'src/latest' + src_info['subtree-vfs-path'],
325 exr = run_get(get_disposition, b'--replace', (item, b'/'))
327 verify_rx(br'impossible; can only overwrite branch or tag', exr.err)
329 tinyfile_id = src_info['tinyfile-id']
330 tinyfile_path = src_info['tinyfile-path']
331 subtree_vfs_path = src_info['subtree-vfs-path']
332 subtree_id = src_info['subtree-id']
333 commit_2_id = src_info['commit-2-id']
334 tree_2_id = src_info['tree-2-id']
337 existing_items = {'nothing' : None,
338 'blob' : (b'.tag/tinyfile', b'.tag/obj'),
339 'tree' : (b'.tag/tree-1', b'.tag/obj'),
340 'commit': (b'.tag/commit-1', b'.tag/obj')}
341 for ex_type, ex_ref in items(existing_items):
342 wvstart(get_disposition + ' --replace ' + ex_type + ' with blob tag')
343 for item in (b'.tag/tinyfile', b'src/latest' + tinyfile_path):
344 exr = run_get(get_disposition, b'--replace', (item ,b'.tag/obj'),
347 validate_blob(tinyfile_id, tinyfile_id)
348 verify_only_refs(heads=[], tags=(b'obj',))
349 wvstart(get_disposition + ' --replace ' + ex_type + ' with tree tag')
350 for item in (b'.tag/subtree', b'src/latest' + subtree_vfs_path):
351 exr = run_get(get_disposition, b'--replace', (item, b'.tag/obj'),
353 validate_tree(subtree_id, subtree_id)
354 verify_only_refs(heads=[], tags=(b'obj',))
355 wvstart(get_disposition + ' --replace ' + ex_type + ' with commitish tag')
356 for item in (b'.tag/commit-2', b'src/latest', b'src'):
357 exr = run_get(get_disposition, b'--replace', (item, b'.tag/obj'),
359 validate_tagged_save(b'obj', getcwd() + b'/src',
360 commit_2_id, tree_2_id, b'src-2', exr.out)
361 verify_only_refs(heads=[], tags=(b'obj',))
363 # Committish to branch.
364 existing_items = (('nothing', None),
365 ('branch', (b'.tag/commit-1', b'obj')))
366 for ex_type, ex_ref in existing_items:
367 for item_type, item in (('commit', b'.tag/commit-2'),
368 ('save', b'src/latest'),
370 wvstart(get_disposition + ' --replace '
371 + ex_type + ' with ' + item_type)
372 exr = run_get(get_disposition, b'--replace', (item, b'obj'),
374 validate_save(b'obj/latest', getcwd() + b'/src',
375 commit_2_id, tree_2_id, b'src-2', exr.out)
376 verify_only_refs(heads=(b'obj',), tags=[])
378 # Not committish to branch
379 existing_items = (('nothing', None),
380 ('branch', (b'.tag/commit-1', b'obj')))
381 for ex_type, ex_ref in existing_items:
382 for item_type, item in (('blob', b'.tag/tinyfile'),
383 ('blob', b'src/latest' + tinyfile_path),
384 ('tree', b'.tag/subtree'),
385 ('tree', b'src/latest' + subtree_vfs_path)):
386 wvstart(get_disposition + ' --replace branch with '
387 + item_type + ' given ' + ex_type + ' fails')
389 exr = run_get(get_disposition, b'--replace', (item, b'obj'),
392 verify_rx(br'cannot overwrite branch with .+ for', exr.err)
394 wvstart(get_disposition + ' --replace, implicit destinations')
396 exr = run_get(get_disposition, b'--replace', b'src')
397 validate_save(b'src/latest', getcwd() + b'/src',
398 commit_2_id, tree_2_id, b'src-2', exr.out)
399 verify_only_refs(heads=(b'src',), tags=[])
401 exr = run_get(get_disposition, b'--replace', b'.tag/commit-2')
402 validate_tagged_save(b'commit-2', getcwd() + b'/src',
403 commit_2_id, tree_2_id, b'src-2', exr.out)
404 verify_only_refs(heads=[], tags=(b'commit-2',))
406 def test_ff(get_disposition, src_info):
408 wvstart(get_disposition + ' --ff to root fails')
409 tinyfile_path = src_info['tinyfile-path']
410 for item in (b'.tag/tinyfile', b'src/latest' + tinyfile_path):
411 exr = run_get(get_disposition, b'--ff', (item, b'/'))
413 verify_rx(br'source for .+ must be a branch, save, or commit', exr.err)
414 subtree_vfs_path = src_info['subtree-vfs-path']
415 for item in (b'.tag/subtree', b'src/latest' + subtree_vfs_path):
416 exr = run_get(get_disposition, b'--ff', (item, b'/'))
418 verify_rx(br'is impossible; can only --append a tree to a branch',
420 for item in (b'.tag/commit-1', b'src/latest', b'src'):
421 exr = run_get(get_disposition, b'--ff', (item, b'/'))
423 verify_rx(br'destination for .+ is a root, not a branch', exr.err)
425 wvstart(get_disposition + ' --ff of not-committish fails')
426 for src in (b'.tag/tinyfile', b'src/latest' + tinyfile_path):
427 # FIXME: use get_item elsewhere?
428 for given, get_item in ((None, (src, b'obj')),
429 (None, (src, b'.tag/obj')),
430 ((b'.tag/tinyfile', b'.tag/obj'), (src, b'.tag/obj')),
431 ((b'.tag/tree-1', b'.tag/obj'), (src, b'.tag/obj')),
432 ((b'.tag/commit-1', b'.tag/obj'), (src, b'.tag/obj')),
433 ((b'.tag/commit-1', b'obj'), (src, b'obj'))):
434 exr = run_get(get_disposition, b'--ff', get_item, given=given)
436 verify_rx(br'must be a branch, save, or commit', exr.err)
437 for src in (b'.tag/subtree', b'src/latest' + subtree_vfs_path):
438 for given, get_item in ((None, (src, b'obj')),
439 (None, (src, b'.tag/obj')),
440 ((b'.tag/tinyfile', b'.tag/obj'), (src, b'.tag/obj')),
441 ((b'.tag/tree-1', b'.tag/obj'), (src, b'.tag/obj')),
442 ((b'.tag/commit-1', b'.tag/obj'), (src, b'.tag/obj')),
443 ((b'.tag/commit-1', b'obj'), (src, b'obj'))):
444 exr = run_get(get_disposition, b'--ff', get_item, given=given)
446 verify_rx(br'can only --append a tree to a branch', exr.err)
448 wvstart(get_disposition + ' --ff committish, ff possible')
449 save_2 = src_info['save-2']
450 for src in (b'.tag/commit-2', b'src/' + save_2, b'src'):
451 for given, get_item, complaint in \
452 ((None, (src, b'.tag/obj'),
453 br'destination .+ must be a valid branch name'),
454 ((b'.tag/tinyfile', b'.tag/obj'), (src, b'.tag/obj'),
455 br'destination .+ is a blob, not a branch'),
456 ((b'.tag/tree-1', b'.tag/obj'), (src, b'.tag/obj'),
457 br'destination .+ is a tree, not a branch'),
458 ((b'.tag/commit-1', b'.tag/obj'), (src, b'.tag/obj'),
459 br'destination .+ is a tagged commit, not a branch'),
460 ((b'.tag/commit-2', b'.tag/obj'), (src, b'.tag/obj'),
461 br'destination .+ is a tagged commit, not a branch')):
462 exr = run_get(get_disposition, b'--ff', get_item, given=given)
464 verify_rx(complaint, exr.err)
465 # FIXME: use src or item and given or existing consistently in loops...
466 commit_2_id = src_info['commit-2-id']
467 tree_2_id = src_info['tree-2-id']
468 for src in (b'.tag/commit-2', b'src/' + save_2, b'src'):
469 for given in (None, (b'.tag/commit-1', b'obj'), (b'.tag/commit-2', b'obj')):
470 exr = run_get(get_disposition, b'--ff', (src, b'obj'), given=given)
472 validate_save(b'obj/latest', getcwd() + b'/src',
473 commit_2_id, tree_2_id, b'src-2', exr.out)
474 verify_only_refs(heads=(b'obj',), tags=[])
476 wvstart(get_disposition + ' --ff, implicit destinations')
477 for item in (b'src', b'src/latest'):
478 exr = run_get(get_disposition, b'--ff', item)
481 ex((b'find', b'get-dest/refs'))
482 ex((bup_cmd, b'-d', b'get-dest', b'ls'))
484 validate_save(b'src/latest', getcwd() + b'/src',
485 commit_2_id, tree_2_id, b'src-2', exr.out)
486 #verify_only_refs(heads=('src',), tags=[])
488 wvstart(get_disposition + ' --ff, ff impossible')
489 for given, get_item in (((b'unrelated-branch', b'src'), b'src'),
490 ((b'.tag/commit-2', b'src'), (b'.tag/commit-1', b'src'))):
491 exr = run_get(get_disposition, b'--ff', get_item, given=given)
493 verify_rx(br'destination is not an ancestor of source', exr.err)
495 def test_append(get_disposition, src_info):
496 tinyfile_path = src_info['tinyfile-path']
497 subtree_vfs_path = src_info['subtree-vfs-path']
499 wvstart(get_disposition + ' --append to root fails')
500 for item in (b'.tag/tinyfile', b'src/latest' + tinyfile_path):
501 exr = run_get(get_disposition, b'--append', (item, b'/'))
503 verify_rx(br'source for .+ must be a branch, save, commit, or tree',
505 for item in (b'.tag/subtree', b'src/latest' + subtree_vfs_path,
506 b'.tag/commit-1', b'src/latest', b'src'):
507 exr = run_get(get_disposition, b'--append', (item, b'/'))
509 verify_rx(br'destination for .+ is a root, not a branch', exr.err)
511 wvstart(get_disposition + ' --append of not-treeish fails')
512 for src in (b'.tag/tinyfile', b'src/latest' + tinyfile_path):
513 for given, item in ((None, (src, b'obj')),
514 (None, (src, b'.tag/obj')),
515 ((b'.tag/tinyfile', b'.tag/obj'), (src, b'.tag/obj')),
516 ((b'.tag/tree-1', b'.tag/obj'), (src, b'.tag/obj')),
517 ((b'.tag/commit-1', b'.tag/obj'), (src, b'.tag/obj')),
518 ((b'.tag/commit-1', b'obj'), (src, b'obj'))):
519 exr = run_get(get_disposition, b'--append', item, given=given)
521 verify_rx(br'must be a branch, save, commit, or tree', exr.err)
523 wvstart(get_disposition + ' --append committish failure cases')
524 save_2 = src_info['save-2']
525 for src in (b'.tag/subtree', b'src/latest' + subtree_vfs_path,
526 b'.tag/commit-2', b'src/' + save_2, b'src'):
527 for given, item, complaint in \
528 ((None, (src, b'.tag/obj'),
529 br'destination .+ must be a valid branch name'),
530 ((b'.tag/tinyfile', b'.tag/obj'), (src, b'.tag/obj'),
531 br'destination .+ is a blob, not a branch'),
532 ((b'.tag/tree-1', b'.tag/obj'), (src, b'.tag/obj'),
533 br'destination .+ is a tree, not a branch'),
534 ((b'.tag/commit-1', b'.tag/obj'), (src, b'.tag/obj'),
535 br'destination .+ is a tagged commit, not a branch'),
536 ((b'.tag/commit-2', b'.tag/obj'), (src, b'.tag/obj'),
537 br'destination .+ is a tagged commit, not a branch')):
538 exr = run_get(get_disposition, b'--append', item, given=given)
540 verify_rx(complaint, exr.err)
542 wvstart(get_disposition + ' --append committish')
543 commit_2_id = src_info['commit-2-id']
544 tree_2_id = src_info['tree-2-id']
545 for item in (b'.tag/commit-2', b'src/' + save_2, b'src'):
546 for existing in (None, (b'.tag/commit-1', b'obj'),
547 (b'.tag/commit-2', b'obj'),
548 (b'unrelated-branch', b'obj')):
549 exr = run_get(get_disposition, b'--append', (item, b'obj'),
552 validate_new_save(b'obj/latest', getcwd() + b'/src',
553 commit_2_id, tree_2_id, b'src-2', exr.out)
554 verify_only_refs(heads=(b'obj',), tags=[])
556 save_1 = src_info['save-1']
557 commit_1_id = src_info['commit-1-id']
558 tree_1_id = src_info['tree-1-id']
559 for item in (b'.tag/commit-1', b'src/' + save_1, b'src-1'):
560 exr = run_get(get_disposition, b'--append', (item, b'obj'),
561 given=(b'.tag/commit-2', b'obj'))
563 validate_new_save(b'obj/latest', getcwd() + b'/src',
564 commit_1_id, tree_1_id, b'src-1', exr.out)
565 verify_only_refs(heads=(b'obj',), tags=[])
567 wvstart(get_disposition + ' --append tree')
568 subtree_path = src_info['subtree-path']
569 subtree_id = src_info['subtree-id']
570 for item in (b'.tag/subtree', b'src/latest' + subtree_vfs_path):
571 for existing in (None,
572 (b'.tag/commit-1', b'obj'),
573 (b'.tag/commit-2', b'obj')):
574 exr = run_get(get_disposition, b'--append', (item, b'obj'),
577 validate_new_save(b'obj/latest', b'/', None, subtree_id, subtree_path,
579 verify_only_refs(heads=(b'obj',), tags=[])
581 wvstart(get_disposition + ' --append, implicit destinations')
583 for item in (b'src', b'src/latest'):
584 exr = run_get(get_disposition, b'--append', item)
586 validate_new_save(b'src/latest', getcwd() + b'/src', commit_2_id, tree_2_id,
588 verify_only_refs(heads=(b'src',), tags=[])
590 def test_pick(get_disposition, src_info, force=False):
591 flavor = b'--force-pick' if force else b'--pick'
592 flavormsg = flavor.decode('ascii')
593 tinyfile_path = src_info['tinyfile-path']
594 subtree_vfs_path = src_info['subtree-vfs-path']
596 wvstart(get_disposition + ' ' + flavormsg + ' to root fails')
597 for item in (b'.tag/tinyfile', b'src/latest' + tinyfile_path, b'src'):
598 exr = run_get(get_disposition, flavor, (item, b'/'))
600 verify_rx(br'can only pick a commit or save', exr.err)
601 for item in (b'.tag/commit-1', b'src/latest'):
602 exr = run_get(get_disposition, flavor, (item, b'/'))
604 verify_rx(br'destination is not a tag or branch', exr.err)
605 for item in (b'.tag/subtree', b'src/latest' + subtree_vfs_path):
606 exr = run_get(get_disposition, flavor, (item, b'/'))
608 verify_rx(br'is impossible; can only --append a tree', exr.err)
610 wvstart(get_disposition + ' ' + flavormsg + ' of blob or branch fails')
611 for item in (b'.tag/tinyfile', b'src/latest' + tinyfile_path, b'src'):
612 for given, get_item in ((None, (item, b'obj')),
613 (None, (item, b'.tag/obj')),
614 ((b'.tag/tinyfile', b'.tag/obj'), (item, b'.tag/obj')),
615 ((b'.tag/tree-1', b'.tag/obj'), (item, b'.tag/obj')),
616 ((b'.tag/commit-1', b'.tag/obj'), (item, b'.tag/obj')),
617 ((b'.tag/commit-1', b'obj'), (item, b'obj'))):
618 exr = run_get(get_disposition, flavor, get_item, given=given)
620 verify_rx(br'impossible; can only pick a commit or save', exr.err)
622 wvstart(get_disposition + ' ' + flavormsg + ' of tree fails')
623 for item in (b'.tag/subtree', b'src/latest' + subtree_vfs_path):
624 for given, get_item in ((None, (item, b'obj')),
625 (None, (item, b'.tag/obj')),
626 ((b'.tag/tinyfile', b'.tag/obj'), (item, b'.tag/obj')),
627 ((b'.tag/tree-1', b'.tag/obj'), (item, b'.tag/obj')),
628 ((b'.tag/commit-1', b'.tag/obj'), (item, b'.tag/obj')),
629 ((b'.tag/commit-1', b'obj'), (item, b'obj'))):
630 exr = run_get(get_disposition, flavor, get_item, given=given)
632 verify_rx(br'impossible; can only --append a tree', exr.err)
634 save_2 = src_info['save-2']
635 commit_2_id = src_info['commit-2-id']
636 tree_2_id = src_info['tree-2-id']
637 # FIXME: these two wvstart texts?
639 wvstart(get_disposition + ' ' + flavormsg + ' commit/save to existing tag')
640 for item in (b'.tag/commit-2', b'src/' + save_2):
641 for given in ((b'.tag/tinyfile', b'.tag/obj'),
642 (b'.tag/tree-1', b'.tag/obj'),
643 (b'.tag/commit-1', b'.tag/obj')):
644 exr = run_get(get_disposition, flavor, (item, b'.tag/obj'),
647 validate_new_tagged_commit(b'obj', commit_2_id, tree_2_id,
649 verify_only_refs(heads=[], tags=(b'obj',))
651 wvstart(get_disposition + ' ' + flavormsg
652 + ' commit/save to existing tag fails')
653 for item in (b'.tag/commit-2', b'src/' + save_2):
654 for given in ((b'.tag/tinyfile', b'.tag/obj'),
655 (b'.tag/tree-1', b'.tag/obj'),
656 (b'.tag/commit-1', b'.tag/obj')):
657 exr = run_get(get_disposition, flavor, (item, b'.tag/obj'), given=given)
659 verify_rx(br'cannot overwrite existing tag', exr.err)
661 wvstart(get_disposition + ' ' + flavormsg + ' commit/save to tag')
662 for item in (b'.tag/commit-2', b'src/' + save_2):
663 exr = run_get(get_disposition, flavor, (item, b'.tag/obj'))
665 validate_clean_repo()
666 validate_new_tagged_commit(b'obj', commit_2_id, tree_2_id, exr.out)
667 verify_only_refs(heads=[], tags=(b'obj',))
669 wvstart(get_disposition + ' ' + flavormsg + ' commit/save to branch')
670 for item in (b'.tag/commit-2', b'src/' + save_2):
671 for given in (None, (b'.tag/commit-1', b'obj'), (b'.tag/commit-2', b'obj')):
672 exr = run_get(get_disposition, flavor, (item, b'obj'), given=given)
674 validate_clean_repo()
675 validate_new_save(b'obj/latest', getcwd() + b'/src',
676 commit_2_id, tree_2_id, b'src-2', exr.out)
677 verify_only_refs(heads=(b'obj',), tags=[])
679 wvstart(get_disposition + ' ' + flavormsg
680 + ' commit/save unrelated commit to branch')
681 for item in(b'.tag/commit-2', b'src/' + save_2):
682 exr = run_get(get_disposition, flavor, (item, b'obj'),
683 given=(b'unrelated-branch', b'obj'))
685 validate_clean_repo()
686 validate_new_save(b'obj/latest', getcwd() + b'/src',
687 commit_2_id, tree_2_id, b'src-2', exr.out)
688 verify_only_refs(heads=(b'obj',), tags=[])
690 wvstart(get_disposition + ' ' + flavormsg + ' commit/save ancestor to branch')
691 save_1 = src_info['save-1']
692 commit_1_id = src_info['commit-1-id']
693 tree_1_id = src_info['tree-1-id']
694 for item in (b'.tag/commit-1', b'src/' + save_1):
695 exr = run_get(get_disposition, flavor, (item, b'obj'),
696 given=(b'.tag/commit-2', b'obj'))
698 validate_clean_repo()
699 validate_new_save(b'obj/latest', getcwd() + b'/src',
700 commit_1_id, tree_1_id, b'src-1', exr.out)
701 verify_only_refs(heads=(b'obj',), tags=[])
704 wvstart(get_disposition + ' ' + flavormsg + ', implicit destinations')
705 exr = run_get(get_disposition, flavor, b'.tag/commit-2')
707 validate_clean_repo()
708 validate_new_tagged_commit(b'commit-2', commit_2_id, tree_2_id, exr.out)
709 verify_only_refs(heads=[], tags=(b'commit-2',))
711 exr = run_get(get_disposition, flavor, b'src/latest')
713 validate_clean_repo()
714 validate_new_save(b'src/latest', getcwd() + b'/src',
715 commit_2_id, tree_2_id, b'src-2', exr.out)
716 verify_only_refs(heads=(b'src',), tags=[])
718 def test_new_tag(get_disposition, src_info):
719 tinyfile_id = src_info['tinyfile-id']
720 tinyfile_path = src_info['tinyfile-path']
721 commit_2_id = src_info['commit-2-id']
722 tree_2_id = src_info['tree-2-id']
723 subtree_id = src_info['subtree-id']
724 subtree_vfs_path = src_info['subtree-vfs-path']
726 wvstart(get_disposition + ' --new-tag to root fails')
727 for item in (b'.tag/tinyfile',
728 b'src/latest' + tinyfile_path,
730 b'src/latest' + subtree_vfs_path,
734 exr = run_get(get_disposition, b'--new-tag', (item, b'/'))
736 verify_rx(br'destination for .+ must be a VFS tag', exr.err)
738 # Anything to new tag.
739 wvstart(get_disposition + ' --new-tag, blob tag')
740 for item in (b'.tag/tinyfile', b'src/latest' + tinyfile_path):
741 exr = run_get(get_disposition, b'--new-tag', (item, b'.tag/obj'))
743 validate_blob(tinyfile_id, tinyfile_id)
744 verify_only_refs(heads=[], tags=(b'obj',))
746 wvstart(get_disposition + ' --new-tag, tree tag')
747 for item in (b'.tag/subtree', b'src/latest' + subtree_vfs_path):
748 exr = run_get(get_disposition, b'--new-tag', (item, b'.tag/obj'))
750 validate_tree(subtree_id, subtree_id)
751 verify_only_refs(heads=[], tags=(b'obj',))
753 wvstart(get_disposition + ' --new-tag, committish tag')
754 for item in (b'.tag/commit-2', b'src/latest', b'src'):
755 exr = run_get(get_disposition, b'--new-tag', (item, b'.tag/obj'))
757 validate_tagged_save(b'obj', getcwd() + b'/src/', commit_2_id, tree_2_id,
759 verify_only_refs(heads=[], tags=(b'obj',))
761 # Anything to existing tag (fails).
762 for ex_type, ex_tag in (('blob', (b'.tag/tinyfile', b'.tag/obj')),
763 ('tree', (b'.tag/tree-1', b'.tag/obj')),
764 ('commit', (b'.tag/commit-1', b'.tag/obj'))):
765 for item_type, item in (('blob tag', b'.tag/tinyfile'),
766 ('blob path', b'src/latest' + tinyfile_path),
767 ('tree tag', b'.tag/subtree'),
768 ('tree path', b'src/latest' + subtree_vfs_path),
769 ('commit tag', b'.tag/commit-2'),
770 ('save', b'src/latest'),
772 wvstart(get_disposition + ' --new-tag of ' + item_type
773 + ', given existing ' + ex_type + ' tag, fails')
774 exr = run_get(get_disposition, b'--new-tag', (item, b'.tag/obj'),
777 verify_rx(br'cannot overwrite existing tag .* \(requires --replace\)',
780 # Anything to branch (fails).
781 for ex_type, ex_tag in (('nothing', None),
782 ('blob', (b'.tag/tinyfile', b'.tag/obj')),
783 ('tree', (b'.tag/tree-1', b'.tag/obj')),
784 ('commit', (b'.tag/commit-1', b'.tag/obj'))):
785 for item_type, item in (('blob tag', b'.tag/tinyfile'),
786 ('blob path', b'src/latest' + tinyfile_path),
787 ('tree tag', b'.tag/subtree'),
788 ('tree path', b'src/latest' + subtree_vfs_path),
789 ('commit tag', b'.tag/commit-2'),
790 ('save', b'src/latest'),
792 wvstart(get_disposition + ' --new-tag to branch of ' + item_type
793 + ', given existing ' + ex_type + ' tag, fails')
794 exr = run_get(get_disposition, b'--new-tag', (item, b'obj'),
797 verify_rx(br'destination for .+ must be a VFS tag', exr.err)
799 wvstart(get_disposition + ' --new-tag, implicit destinations')
800 exr = run_get(get_disposition, b'--new-tag', b'.tag/commit-2')
802 validate_tagged_save(b'commit-2', getcwd() + b'/src/', commit_2_id, tree_2_id,
804 verify_only_refs(heads=[], tags=(b'commit-2',))
806 def test_unnamed(get_disposition, src_info):
807 tinyfile_id = src_info['tinyfile-id']
808 tinyfile_path = src_info['tinyfile-path']
809 subtree_vfs_path = src_info['subtree-vfs-path']
810 wvstart(get_disposition + ' --unnamed to root fails')
811 for item in (b'.tag/tinyfile',
812 b'src/latest' + tinyfile_path,
814 b'src/latest' + subtree_vfs_path,
818 for ex_ref in (None, (item, b'.tag/obj')):
819 exr = run_get(get_disposition, b'--unnamed', (item, b'/'),
822 verify_rx(br'usage: bup get ', exr.err)
824 wvstart(get_disposition + ' --unnamed file')
825 for item in (b'.tag/tinyfile', b'src/latest' + tinyfile_path):
826 exr = run_get(get_disposition, b'--unnamed', item)
828 validate_blob(tinyfile_id, tinyfile_id)
829 verify_only_refs(heads=[], tags=[])
831 exr = run_get(get_disposition, b'--unnamed', item,
832 given=(item, b'.tag/obj'))
834 validate_blob(tinyfile_id, tinyfile_id)
835 verify_only_refs(heads=[], tags=(b'obj',))
837 wvstart(get_disposition + ' --unnamed tree')
838 subtree_id = src_info['subtree-id']
839 for item in (b'.tag/subtree', b'src/latest' + subtree_vfs_path):
840 exr = run_get(get_disposition, b'--unnamed', item)
842 validate_tree(subtree_id, subtree_id)
843 verify_only_refs(heads=[], tags=[])
845 exr = run_get(get_disposition, b'--unnamed', item,
846 given=(item, b'.tag/obj'))
848 validate_tree(subtree_id, subtree_id)
849 verify_only_refs(heads=[], tags=(b'obj',))
851 wvstart(get_disposition + ' --unnamed committish')
852 save_2 = src_info['save-2']
853 commit_2_id = src_info['commit-2-id']
854 for item in (b'.tag/commit-2', b'src/' + save_2, b'src'):
855 exr = run_get(get_disposition, b'--unnamed', item)
857 validate_commit(commit_2_id, commit_2_id)
858 verify_only_refs(heads=[], tags=[])
860 exr = run_get(get_disposition, b'--unnamed', item,
861 given=(item, b'.tag/obj'))
863 validate_commit(commit_2_id, commit_2_id)
864 verify_only_refs(heads=[], tags=(b'obj',))
866 def create_get_src():
867 global bup_cmd, src_info
869 ex((bup_cmd, b'-d', b'get-src', b'init'))
872 open(b'src/unrelated', 'a').close()
873 ex((bup_cmd, b'-d', b'get-src', b'index', b'src'))
874 ex((bup_cmd, b'-d', b'get-src', b'save', b'-tcn', b'unrelated-branch', b'src'))
876 ex((bup_cmd, b'-d', b'get-src', b'index', b'--clear'))
879 open(b'src/zero', 'a').close()
880 ex((bup_cmd, b'-d', b'get-src', b'index', b'src'))
881 exr = exo((bup_cmd, b'-d', b'get-src', b'save', b'-tcn', b'src', b'src'))
882 out = exr.out.splitlines()
884 commit_0_id = out[-1]
885 exr = exo((bup_cmd, b'-d', b'get-src', b'ls', b'src'))
886 save_0 = exr.out.splitlines()[0]
887 ex((b'git', b'--git-dir', b'get-src', b'branch', b'src-0', b'src'))
888 ex((b'cp', b'-RPp', b'src', b'src-0'))
894 ex((bup_cmd + b' -d get-src random 1k > src/1'), shell=True)
895 ex((bup_cmd + b' -d get-src random 1k > src/x/2'), shell=True)
896 ex((bup_cmd, b'-d', b'get-src', b'index', b'src'))
897 exr = exo((bup_cmd, b'-d', b'get-src', b'save', b'-tcn', b'src', b'src'))
898 out = exr.out.splitlines()
900 commit_1_id = out[-1]
901 exr = exo((bup_cmd, b'-d', b'get-src', b'ls', b'src'))
902 save_1 = exr.out.splitlines()[1]
903 ex((b'git', b'--git-dir', b'get-src', b'branch', b'src-1', b'src'))
904 ex((b'cp', b'-RPp', b'src', b'src-1'))
906 # Make a copy the current state of src so we'll have an ancestor.
908 b'get-src/refs/heads/src', b'get-src/refs/heads/src-ancestor'))
910 with open(b'src/tiny-file', 'ab') as f: f.write(b'xyzzy')
911 ex((bup_cmd, b'-d', b'get-src', b'index', b'src'))
912 ex((bup_cmd, b'-d', b'get-src', b'tick')) # Ensure the save names differ
913 exr = exo((bup_cmd, b'-d', b'get-src', b'save', b'-tcn', b'src', b'src'))
914 out = exr.out.splitlines()
916 commit_2_id = out[-1]
917 exr = exo((bup_cmd, b'-d', b'get-src', b'ls', b'src'))
918 save_2 = exr.out.splitlines()[2]
919 rename(b'src', b'src-2')
921 src_root = getcwd() + b'/src'
923 subtree_path = b'src-2/x'
924 subtree_vfs_path = src_root + b'/x'
926 # No support for "ls -d", so grep...
927 exr = exo((bup_cmd, b'-d', b'get-src', b'ls', b'-s', b'src/latest' + src_root))
928 out = exr.out.splitlines()
932 subtree_id = line.split()[0]
935 # With a tiny file, we'll get a single blob, not a chunked tree
936 tinyfile_path = src_root + b'/tiny-file'
937 exr = exo((bup_cmd, b'-d', b'get-src', b'ls', b'-s', b'src/latest' + tinyfile_path))
938 tinyfile_id = exr.out.splitlines()[0].split()[0]
940 ex((bup_cmd, b'-d', b'get-src', b'tag', b'tinyfile', tinyfile_id))
941 ex((bup_cmd, b'-d', b'get-src', b'tag', b'subtree', subtree_id))
942 ex((bup_cmd, b'-d', b'get-src', b'tag', b'tree-0', tree_0_id))
943 ex((bup_cmd, b'-d', b'get-src', b'tag', b'tree-1', tree_1_id))
944 ex((bup_cmd, b'-d', b'get-src', b'tag', b'tree-2', tree_2_id))
945 ex((bup_cmd, b'-d', b'get-src', b'tag', b'commit-0', commit_0_id))
946 ex((bup_cmd, b'-d', b'get-src', b'tag', b'commit-1', commit_1_id))
947 ex((bup_cmd, b'-d', b'get-src', b'tag', b'commit-2', commit_2_id))
948 ex((b'git', b'--git-dir', b'get-src', b'branch', b'commit-1', commit_1_id))
949 ex((b'git', b'--git-dir', b'get-src', b'branch', b'commit-2', commit_2_id))
951 return {'tinyfile-path' : tinyfile_path,
952 'tinyfile-id' : tinyfile_id,
953 'subtree-id' : subtree_id,
954 'tree-0-id' : tree_0_id,
955 'tree-1-id' : tree_1_id,
956 'tree-2-id' : tree_2_id,
957 'commit-0-id' : commit_0_id,
958 'commit-1-id' : commit_1_id,
959 'commit-2-id' : commit_2_id,
962 'subtree-path' : subtree_path,
963 'subtree-vfs-path' : subtree_vfs_path}
965 # FIXME: this fails in a strange way:
966 # WVPASS given nothing get --ff not-there
968 dispositions_to_test = ('get',)
970 if int(environ.get(b'BUP_TEST_LEVEL', b'0')) >= 11:
971 dispositions_to_test += ('get-on', 'get-to')
973 if len(compat.argv) == 1:
974 categories = ('replace', 'universal', 'ff', 'append', 'pick', 'new-tag',
977 categories = compat.argv[1:]
979 with test_tempdir(b'get-') as tmpdir:
982 src_info = create_get_src()
983 for category in categories:
984 for disposition in dispositions_to_test:
985 # given=FOO depends on --replace, so test it early
986 if category == 'replace':
987 test_replace(disposition, src_info)
988 elif category == 'universal':
989 test_universal_behaviors(disposition)
990 elif category == 'ff':
991 test_ff(disposition, src_info)
992 elif category == 'append':
993 test_append(disposition, src_info)
994 elif category == 'pick':
995 test_pick(disposition, src_info, force=False)
996 test_pick(disposition, src_info, force=True)
997 elif category == 'new-tag':
998 test_new_tag(disposition, src_info)
999 elif category == 'unnamed':
1000 test_unnamed(disposition, src_info)
1002 raise Exception('unrecognized get test category')
1003 except Exception as ex:
1008 wvmsg('checked %d cases' % get_cases_tested)