3 bup_python="$(dirname "$0")/../cmd/bup-python" || exit $?
4 exec "$bup_python" "$0" ${1+"$@"}
8 from __future__ import print_function
9 from errno import ENOENT
10 from os import chdir, environ, getcwd, mkdir, rename
11 from os.path import abspath, dirname
12 from pipes import quote
13 from shutil import rmtree
14 from subprocess import PIPE
17 script_home = abspath(dirname(sys.argv[0] or '.'))
18 sys.path[:0] = [abspath(script_home + '/../lib'), abspath(script_home + '/..')]
20 from bup import compat
21 from buptest import ex, exo, test_tempdir
22 from wvtest import wvcheck, wvfail, wvmsg, wvpass, wvpasseq, wvpassne, wvstart
24 # FIXME: per-test function
25 environ['GIT_AUTHOR_NAME'] = 'bup test-get'
26 environ['GIT_COMMITTER_NAME'] = 'bup test-get'
27 environ['GIT_AUTHOR_EMAIL'] = 'bup@85430dcca2b611e4b2c3-8f5691723476'
28 environ['GIT_COMMITTER_EMAIL'] = 'bup@85430dcca2b611e4b2c3-8f5691723476'
30 # The clean-repo test can probably be applied more broadly. It was
31 # initially just applied to test-pick to catch a bug.
34 bup_cmd = top + '/bup'
37 err = [] # because python's scoping mess...
38 def onerror(function, path, excinfo):
39 err.append((function, path, excinfo))
40 rmtree(path, onerror=onerror)
42 function, path, excinfo = err[0]
43 ex_type, ex, traceback = excinfo
44 if (not isinstance(ex, OSError)) or ex.errno != ENOENT:
47 def verify_trees_match(path1, path2):
49 exr = exo((top + '/t/compare-trees', '-c', path1, path2), check=False)
52 wvcheck(exr.rc == 0, 'process exit %d == 0' % exr.rc)
54 def verify_rcz(cmd, **kwargs):
55 assert not kwargs.get('check')
56 kwargs['check'] = False
57 result = exo(cmd, **kwargs)
59 rc = result.proc.returncode
60 wvcheck(rc == 0, 'process exit %d == 0' % rc)
63 # FIXME: multline, or allow opts generally?
65 def verify_rx(rx, string):
66 wvcheck(re.search(rx, string), 'rx %r matches %r' % (rx, string))
68 def verify_nrx(rx, string):
69 wvcheck(not re.search(rx, string), "rx %r doesn't match %r" % (rx, string))
71 def validate_clean_repo():
72 out = verify_rcz(('git', '--git-dir', 'get-dest', 'fsck')).out
73 verify_nrx(r'dangling|mismatch|missing|unreachable', out)
75 def validate_blob(src_id, dest_id):
79 cat_tree = top + '/t/git-cat-tree'
80 src_blob = verify_rcz((cat_tree, '--git-dir', 'get-src', src_id)).out
81 dest_blob = verify_rcz((cat_tree, '--git-dir', 'get-src', src_id)).out
82 wvpasseq(src_blob, dest_blob)
84 def validate_tree(src_id, dest_id):
86 def set_committer_date():
87 environ['GIT_COMMITTER_DATE'] = "2014-01-01 01:01"
94 # Create a commit so the archive contents will have matching timestamps.
95 src_c = exo(('git', '--git-dir', 'get-src',
96 'commit-tree', '-m', 'foo', src_id),
97 preexec_fn=set_committer_date).out.strip()
98 dest_c = exo(('git', '--git-dir', 'get-dest',
99 'commit-tree', '-m', 'foo', dest_id),
100 preexec_fn=set_committer_date).out.strip()
101 exr = verify_rcz('git --git-dir get-src archive %s | tar xvf - -C restore-src'
104 if exr.rc != 0: return False
105 ex('cd restore-src && ls --full-time -aR .', shell=True)
106 exr = verify_rcz('git --git-dir get-dest archive %s | tar xvf - -C restore-dest'
109 if exr.rc != 0: return False
111 # git archive doesn't include an entry for ./.
112 ex(('touch', '-r', 'restore-src', 'restore-dest'))
113 verify_trees_match('restore-src/', 'restore-dest/')
117 def validate_commit(src_id, dest_id):
118 exr = verify_rcz(('git', '--git-dir', 'get-src', 'cat-file', 'commit', src_id))
119 if exr.rc != 0: return False
121 exr = verify_rcz(('git', '--git-dir', 'get-dest', 'cat-file', 'commit', dest_id))
122 if exr.rc != 0: return False
124 wvpasseq(src_cat, dest_cat)
125 if src_cat != dest_cat: return False
130 mkdir('restore-dest')
132 qdest = quote(dest_id)
133 exr = verify_rcz(('git --git-dir get-src archive ' + qsrc
134 + ' | tar xf - -C restore-src'),
136 if exr.rc != 0: return False
137 exr = verify_rcz(('git --git-dir get-dest archive ' + qdest +
138 ' | tar xf - -C restore-dest'),
140 if exr.rc != 0: return False
142 # git archive doesn't include an entry for ./.
143 ex(('touch', '-r', 'restore-src', 'restore-dest'))
144 verify_trees_match('restore-src/', 'restore-dest/')
148 def _validate_save(orig_dir, save_path, commit_id, tree_id):
151 exr = verify_rcz((bup_cmd, '-d', 'get-dest',
152 'restore', '-C', 'restore', save_path + '/.'))
153 if exr.rc: return False
154 verify_trees_match(orig_dir + '/', 'restore/')
156 # FIXME: double check that get-dest is correct
157 exr = verify_rcz(('git', '--git-dir', 'get-dest', 'ls-tree', tree_id))
158 if exr.rc: return False
159 cat = verify_rcz(('git', '--git-dir', 'get-dest',
160 'cat-file', 'commit', commit_id))
161 if cat.rc: return False
162 wvpasseq('tree ' + tree_id, cat.out.splitlines()[0])
164 # FIXME: re-merge save and new_save?
166 def validate_save(dest_name, restore_subpath, commit_id, tree_id, orig_value,
168 out = get_out.splitlines()
169 wvpasseq(2, len(out))
171 get_commit_id = out[1]
172 wvpasseq(tree_id, get_tree_id)
173 wvpasseq(commit_id, get_commit_id)
174 _validate_save(orig_value, dest_name + restore_subpath, commit_id, tree_id)
176 def validate_new_save(dest_name, restore_subpath, commit_id, tree_id, orig_value,
178 out = get_out.splitlines()
179 wvpasseq(2, len(out))
181 get_commit_id = out[1]
182 wvpasseq(tree_id, get_tree_id)
183 wvpassne(commit_id, get_commit_id)
184 _validate_save(orig_value, dest_name + restore_subpath, get_commit_id, tree_id)
186 def validate_tagged_save(tag_name, restore_subpath,
187 commit_id, tree_id, orig_value, get_out):
188 out = get_out.splitlines()
189 wvpasseq(1, len(out))
191 wvpasseq(commit_id, get_tag_id)
192 # Make sure tmp doesn't already exist.
193 exr = exo(('git', '--git-dir', 'get-dest', 'show-ref', 'tmp-branch-for-tag'),
197 ex(('git', '--git-dir', 'get-dest', 'branch', 'tmp-branch-for-tag',
198 'refs/tags/' + tag_name))
199 _validate_save(orig_value, 'tmp-branch-for-tag/latest' + restore_subpath,
201 ex(('git', '--git-dir', 'get-dest', 'branch', '-D', 'tmp-branch-for-tag'))
203 def validate_new_tagged_commit(tag_name, commit_id, tree_id, get_out):
204 out = get_out.splitlines()
205 wvpasseq(1, len(out))
207 wvpassne(commit_id, get_tag_id)
208 validate_tree(tree_id, tag_name + ':')
214 def _run_get(disposition, method, what):
217 if disposition == 'get':
218 get_cmd = (bup_cmd, '-d', 'get-dest',
219 'get', '-vvct', '--print-tags', '-s', 'get-src')
220 elif disposition == 'get-on':
221 get_cmd = (bup_cmd, '-d', 'get-dest',
222 'on', '-', 'get', '-vvct', '--print-tags', '-s', 'get-src')
223 elif disposition == 'get-to':
224 get_cmd = (bup_cmd, '-d', 'get-dest',
225 'get', '-vvct', '--print-tags', '-s', 'get-src',
226 '-r', '-:' + getcwd() + '/get-dest')
228 raise Exception('error: unexpected get disposition ' + disposition)
230 global get_cases_tested
231 if isinstance(what, compat.str_type):
232 cmd = get_cmd + (method, what)
234 if method in ('--ff', '--append', '--pick', '--force-pick', '--new-tag',
238 cmd = get_cmd + (method, src, dest)
239 result = exo(cmd, check=False, stderr=PIPE)
240 get_cases_tested += 1
243 def run_get(disposition, method, what=None, given=None):
246 ex((bup_cmd, '-d', 'get-dest', 'init'))
249 # FIXME: replace bup-get with independent commands as is feasible
250 exr = _run_get(disposition, '--replace', given)
252 return _run_get(disposition, method, what)
254 def test_universal_behaviors(get_disposition):
255 methods = ('--ff', '--append', '--pick', '--force-pick', '--new-tag',
256 '--replace', '--unnamed')
257 for method in methods:
258 wvstart(get_disposition + ' ' + method + ', missing source, fails')
259 exr = run_get(get_disposition, method, 'not-there')
261 verify_rx(r'cannot find source', exr.err)
262 for method in methods:
263 wvstart(get_disposition + ' ' + method + ' / fails')
264 exr = run_get(get_disposition, method, '/')
266 verify_rx('cannot fetch entire repository', exr.err)
268 def verify_only_refs(**kwargs):
269 for kind, refs in kwargs.iteritems():
271 abs_refs = ['refs/heads/' + ref for ref in refs]
274 abs_refs = ['refs/tags/' + ref for ref in refs]
277 raise TypeError('unexpected keyword argument %r' % kind)
279 verify_rcz(['git', '--git-dir', 'get-dest',
280 'show-ref', '--verify', karg] + abs_refs)
281 exr = exo(('git', '--git-dir', 'get-dest', 'show-ref', karg),
284 expected_refs = sorted(abs_refs)
285 repo_refs = sorted([x.split()[1] for x in exr.out.splitlines()])
286 wvpasseq(expected_refs, repo_refs)
288 # FIXME: can we just check "git show-ref --heads == ''"?
289 exr = exo(('git', '--git-dir', 'get-dest', 'show-ref', karg),
292 wvpasseq('', exr.out.strip())
294 def test_replace(get_disposition, src_info):
296 wvstart(get_disposition + ' --replace to root fails')
297 for item in ('.tag/tinyfile',
298 'src/latest' + src_info['tinyfile-path'],
300 'src/latest' + src_info['subtree-vfs-path'],
304 exr = run_get(get_disposition, '--replace', (item, '/'))
306 verify_rx(r'impossible; can only overwrite branch or tag', exr.err)
308 tinyfile_id = src_info['tinyfile-id']
309 tinyfile_path = src_info['tinyfile-path']
310 subtree_vfs_path = src_info['subtree-vfs-path']
311 subtree_id = src_info['subtree-id']
312 commit_2_id = src_info['commit-2-id']
313 tree_2_id = src_info['tree-2-id']
316 existing_items = {'nothing' : None,
317 'blob' : ('.tag/tinyfile', '.tag/obj'),
318 'tree' : ('.tag/tree-1', '.tag/obj'),
319 'commit': ('.tag/commit-1', '.tag/obj')}
320 for ex_type, ex_ref in existing_items.iteritems():
321 wvstart(get_disposition + ' --replace ' + ex_type + ' with blob tag')
322 for item in ('.tag/tinyfile', 'src/latest' + tinyfile_path):
323 exr = run_get(get_disposition, '--replace', (item ,'.tag/obj'),
326 validate_blob(tinyfile_id, tinyfile_id)
327 verify_only_refs(heads=[], tags=('obj',))
328 wvstart(get_disposition + ' --replace ' + ex_type + ' with tree tag')
329 for item in ('.tag/subtree', 'src/latest' + subtree_vfs_path):
330 exr = run_get(get_disposition, '--replace', (item, '.tag/obj'),
332 validate_tree(subtree_id, subtree_id)
333 verify_only_refs(heads=[], tags=('obj',))
334 wvstart(get_disposition + ' --replace ' + ex_type + ' with commitish tag')
335 for item in ('.tag/commit-2', 'src/latest', 'src'):
336 exr = run_get(get_disposition, '--replace', (item, '.tag/obj'),
338 validate_tagged_save('obj', getcwd() + '/src',
339 commit_2_id, tree_2_id, 'src-2', exr.out)
340 verify_only_refs(heads=[], tags=('obj',))
342 # Committish to branch.
343 existing_items = (('nothing', None),
344 ('branch', ('.tag/commit-1', 'obj')))
345 for ex_type, ex_ref in existing_items:
346 for item_type, item in (('commit', '.tag/commit-2'),
347 ('save', 'src/latest'),
349 wvstart(get_disposition + ' --replace '
350 + ex_type + ' with ' + item_type)
351 exr = run_get(get_disposition, '--replace', (item, 'obj'),
353 validate_save('obj/latest', getcwd() + '/src',
354 commit_2_id, tree_2_id, 'src-2', exr.out)
355 verify_only_refs(heads=('obj',), tags=[])
357 # Not committish to branch
358 existing_items = (('nothing', None),
359 ('branch', ('.tag/commit-1', 'obj')))
360 for ex_type, ex_ref in existing_items:
361 for item_type, item in (('blob', '.tag/tinyfile'),
362 ('blob', 'src/latest' + tinyfile_path),
363 ('tree', '.tag/subtree'),
364 ('tree', 'src/latest' + subtree_vfs_path)):
365 wvstart(get_disposition + ' --replace branch with '
366 + item_type + ' given ' + ex_type + ' fails')
368 exr = run_get(get_disposition, '--replace', (item, 'obj'),
371 verify_rx(r'cannot overwrite branch with .+ for', exr.err)
373 wvstart(get_disposition + ' --replace, implicit destinations')
375 exr = run_get(get_disposition, '--replace', 'src')
376 validate_save('src/latest', getcwd() + '/src',
377 commit_2_id, tree_2_id, 'src-2', exr.out)
378 verify_only_refs(heads=('src',), tags=[])
380 exr = run_get(get_disposition, '--replace', '.tag/commit-2')
381 validate_tagged_save('commit-2', getcwd() + '/src',
382 commit_2_id, tree_2_id, 'src-2', exr.out)
383 verify_only_refs(heads=[], tags=('commit-2',))
385 def test_ff(get_disposition, src_info):
387 wvstart(get_disposition + ' --ff to root fails')
388 tinyfile_path = src_info['tinyfile-path']
389 for item in ('.tag/tinyfile', 'src/latest' + tinyfile_path):
390 exr = run_get(get_disposition, '--ff', (item, '/'))
392 verify_rx(r'source for .+ must be a branch, save, or commit', exr.err)
393 subtree_vfs_path = src_info['subtree-vfs-path']
394 for item in ('.tag/subtree', 'src/latest' + subtree_vfs_path):
395 exr = run_get(get_disposition, '--ff', (item, '/'))
397 verify_rx(r'is impossible; can only --append a tree to a branch',
399 for item in ('.tag/commit-1', 'src/latest', 'src'):
400 exr = run_get(get_disposition, '--ff', (item, '/'))
402 verify_rx(r'destination for .+ is a root, not a branch', exr.err)
404 wvstart(get_disposition + ' --ff of not-committish fails')
405 for src in ('.tag/tinyfile', 'src/latest' + tinyfile_path):
406 # FIXME: use get_item elsewhere?
407 for given, get_item in ((None, (src, 'obj')),
408 (None, (src, '.tag/obj')),
409 (('.tag/tinyfile', '.tag/obj'), (src, '.tag/obj')),
410 (('.tag/tree-1', '.tag/obj'), (src, '.tag/obj')),
411 (('.tag/commit-1', '.tag/obj'), (src, '.tag/obj')),
412 (('.tag/commit-1', 'obj'), (src, 'obj'))):
413 exr = run_get(get_disposition, '--ff', get_item, given=given)
415 verify_rx(r'must be a branch, save, or commit', exr.err)
416 for src in ('.tag/subtree', 'src/latest' + subtree_vfs_path):
417 for given, get_item in ((None, (src, 'obj')),
418 (None, (src, '.tag/obj')),
419 (('.tag/tinyfile', '.tag/obj'), (src, '.tag/obj')),
420 (('.tag/tree-1', '.tag/obj'), (src, '.tag/obj')),
421 (('.tag/commit-1', '.tag/obj'), (src, '.tag/obj')),
422 (('.tag/commit-1', 'obj'), (src, 'obj'))):
423 exr = run_get(get_disposition, '--ff', get_item, given=given)
425 verify_rx(r'can only --append a tree to a branch', exr.err)
427 wvstart(get_disposition + ' --ff committish, ff possible')
428 save_2 = src_info['save-2']
429 for src in ('.tag/commit-2', 'src/' + save_2, 'src'):
430 for given, get_item, complaint in \
431 ((None, (src, '.tag/obj'),
432 r'destination .+ must be a valid branch name'),
433 (('.tag/tinyfile', '.tag/obj'), (src, '.tag/obj'),
434 r'destination .+ is a blob, not a branch'),
435 (('.tag/tree-1', '.tag/obj'), (src, '.tag/obj'),
436 r'destination .+ is a tree, not a branch'),
437 (('.tag/commit-1', '.tag/obj'), (src, '.tag/obj'),
438 r'destination .+ is a tagged commit, not a branch'),
439 (('.tag/commit-2', '.tag/obj'), (src, '.tag/obj'),
440 r'destination .+ is a tagged commit, not a branch')):
441 exr = run_get(get_disposition, '--ff', get_item, given=given)
443 verify_rx(complaint, exr.err)
444 # FIXME: use src or item and given or existing consistently in loops...
445 commit_2_id = src_info['commit-2-id']
446 tree_2_id = src_info['tree-2-id']
447 for src in ('.tag/commit-2', 'src/' + save_2, 'src'):
448 for given in (None, ('.tag/commit-1', 'obj'), ('.tag/commit-2', 'obj')):
449 exr = run_get(get_disposition, '--ff', (src, 'obj'), given=given)
451 validate_save('obj/latest', getcwd() + '/src',
452 commit_2_id, tree_2_id, 'src-2', exr.out)
453 verify_only_refs(heads=('obj',), tags=[])
455 wvstart(get_disposition + ' --ff, implicit destinations')
456 for item in ('src', 'src/latest'):
457 exr = run_get(get_disposition, '--ff', item)
460 ex(('find', 'get-dest/refs'))
461 ex((bup_cmd, '-d', 'get-dest', 'ls'))
463 validate_save('src/latest', getcwd() + '/src',
464 commit_2_id, tree_2_id, 'src-2', exr.out)
465 #verify_only_refs(heads=('src',), tags=[])
467 wvstart(get_disposition + ' --ff, ff impossible')
468 for given, get_item in ((('unrelated-branch', 'src'), 'src'),
469 (('.tag/commit-2', 'src'), ('.tag/commit-1', 'src'))):
470 exr = run_get(get_disposition, '--ff', get_item, given=given)
472 verify_rx(r'destination is not an ancestor of source', exr.err)
474 def test_append(get_disposition, src_info):
475 tinyfile_path = src_info['tinyfile-path']
476 subtree_vfs_path = src_info['subtree-vfs-path']
478 wvstart(get_disposition + ' --append to root fails')
479 for item in ('.tag/tinyfile', 'src/latest' + tinyfile_path):
480 exr = run_get(get_disposition, '--append', (item, '/'))
482 verify_rx(r'source for .+ must be a branch, save, commit, or tree',
484 for item in ('.tag/subtree', 'src/latest' + subtree_vfs_path,
485 '.tag/commit-1', 'src/latest', 'src'):
486 exr = run_get(get_disposition, '--append', (item, '/'))
488 verify_rx(r'destination for .+ is a root, not a branch', exr.err)
490 wvstart(get_disposition + ' --append of not-treeish fails')
491 for src in ('.tag/tinyfile', 'src/latest' + tinyfile_path):
492 for given, item in ((None, (src, 'obj')),
493 (None, (src, '.tag/obj')),
494 (('.tag/tinyfile', '.tag/obj'), (src, '.tag/obj')),
495 (('.tag/tree-1', '.tag/obj'), (src, '.tag/obj')),
496 (('.tag/commit-1', '.tag/obj'), (src, '.tag/obj')),
497 (('.tag/commit-1', 'obj'), (src, 'obj'))):
498 exr = run_get(get_disposition, '--append', item, given=given)
500 verify_rx(r'must be a branch, save, commit, or tree', exr.err)
502 wvstart(get_disposition + ' --append committish failure cases')
503 save_2 = src_info['save-2']
504 for src in ('.tag/subtree', 'src/latest' + subtree_vfs_path,
505 '.tag/commit-2', 'src/' + save_2, 'src'):
506 for given, item, complaint in \
507 ((None, (src, '.tag/obj'),
508 r'destination .+ must be a valid branch name'),
509 (('.tag/tinyfile', '.tag/obj'), (src, '.tag/obj'),
510 r'destination .+ is a blob, not a branch'),
511 (('.tag/tree-1', '.tag/obj'), (src, '.tag/obj'),
512 r'destination .+ is a tree, not a branch'),
513 (('.tag/commit-1', '.tag/obj'), (src, '.tag/obj'),
514 r'destination .+ is a tagged commit, not a branch'),
515 (('.tag/commit-2', '.tag/obj'), (src, '.tag/obj'),
516 r'destination .+ is a tagged commit, not a branch')):
517 exr = run_get(get_disposition, '--append', item, given=given)
519 verify_rx(complaint, exr.err)
521 wvstart(get_disposition + ' --append committish')
522 commit_2_id = src_info['commit-2-id']
523 tree_2_id = src_info['tree-2-id']
524 for item in ('.tag/commit-2', 'src/' + save_2, 'src'):
525 for existing in (None, ('.tag/commit-1', 'obj'),
526 ('.tag/commit-2', 'obj'),
527 ('unrelated-branch', 'obj')):
528 exr = run_get(get_disposition, '--append', (item, 'obj'),
531 validate_new_save('obj/latest', getcwd() + '/src',
532 commit_2_id, tree_2_id, 'src-2', exr.out)
533 verify_only_refs(heads=('obj',), tags=[])
535 save_1 = src_info['save-1']
536 commit_1_id = src_info['commit-1-id']
537 tree_1_id = src_info['tree-1-id']
538 for item in ('.tag/commit-1', 'src/' + save_1, 'src-1'):
539 exr = run_get(get_disposition, '--append', (item, 'obj'),
540 given=('.tag/commit-2', 'obj'))
542 validate_new_save('obj/latest', getcwd() + '/src',
543 commit_1_id, tree_1_id, 'src-1', exr.out)
544 verify_only_refs(heads=('obj',), tags=[])
546 wvstart(get_disposition + ' --append tree')
547 subtree_path = src_info['subtree-path']
548 subtree_id = src_info['subtree-id']
549 for item in ('.tag/subtree', 'src/latest' + subtree_vfs_path):
550 for existing in (None, ('.tag/commit-1', 'obj'), ('.tag/commit-2','obj')):
551 exr = run_get(get_disposition, '--append', (item, 'obj'),
554 validate_new_save('obj/latest', '/', None, subtree_id, subtree_path,
556 verify_only_refs(heads=('obj',), tags=[])
558 wvstart(get_disposition + ' --append, implicit destinations')
560 for item in ('src', 'src/latest'):
561 exr = run_get(get_disposition, '--append', item)
563 validate_new_save('src/latest', getcwd() + '/src', commit_2_id, tree_2_id,
565 verify_only_refs(heads=('src',), tags=[])
567 def test_pick(get_disposition, src_info, force=False):
568 flavor = '--force-pick' if force else '--pick'
569 tinyfile_path = src_info['tinyfile-path']
570 subtree_vfs_path = src_info['subtree-vfs-path']
572 wvstart(get_disposition + ' ' + flavor + ' to root fails')
573 for item in ('.tag/tinyfile', 'src/latest' + tinyfile_path, 'src'):
574 exr = run_get(get_disposition, flavor, (item, '/'))
576 verify_rx(r'can only pick a commit or save', exr.err)
577 for item in ('.tag/commit-1', 'src/latest'):
578 exr = run_get(get_disposition, flavor, (item, '/'))
580 verify_rx(r'destination is not a tag or branch', exr.err)
581 for item in ('.tag/subtree', 'src/latest' + subtree_vfs_path):
582 exr = run_get(get_disposition, flavor, (item, '/'))
584 verify_rx(r'is impossible; can only --append a tree', exr.err)
586 wvstart(get_disposition + ' ' + flavor + ' of blob or branch fails')
587 for item in ('.tag/tinyfile', 'src/latest' + tinyfile_path, 'src'):
588 for given, get_item in ((None, (item, 'obj')),
589 (None, (item, '.tag/obj')),
590 (('.tag/tinyfile', '.tag/obj'), (item, '.tag/obj')),
591 (('.tag/tree-1', '.tag/obj'), (item, '.tag/obj')),
592 (('.tag/commit-1', '.tag/obj'), (item, '.tag/obj')),
593 (('.tag/commit-1', 'obj'), (item, 'obj'))):
594 exr = run_get(get_disposition, flavor, get_item, given=given)
596 verify_rx(r'impossible; can only pick a commit or save', exr.err)
598 wvstart(get_disposition + ' ' + flavor + ' of tree fails')
599 for item in ('.tag/subtree', 'src/latest' + subtree_vfs_path):
600 for given, get_item in ((None, (item, 'obj')),
601 (None, (item, '.tag/obj')),
602 (('.tag/tinyfile', '.tag/obj'), (item, '.tag/obj')),
603 (('.tag/tree-1', '.tag/obj'), (item, '.tag/obj')),
604 (('.tag/commit-1', '.tag/obj'), (item, '.tag/obj')),
605 (('.tag/commit-1', 'obj'), (item, 'obj'))):
606 exr = run_get(get_disposition, flavor, get_item, given=given)
608 verify_rx(r'impossible; can only --append a tree', exr.err)
610 save_2 = src_info['save-2']
611 commit_2_id = src_info['commit-2-id']
612 tree_2_id = src_info['tree-2-id']
613 # FIXME: these two wvstart texts?
615 wvstart(get_disposition + ' ' + flavor + ' commit/save to existing tag')
616 for item in ('.tag/commit-2', 'src/' + save_2):
617 for given in (('.tag/tinyfile', '.tag/obj'),
618 ('.tag/tree-1', '.tag/obj'),
619 ('.tag/commit-1', '.tag/obj')):
620 exr = run_get(get_disposition, flavor, (item, '.tag/obj'),
623 validate_new_tagged_commit('obj', commit_2_id, tree_2_id,
625 verify_only_refs(heads=[], tags=('obj',))
627 wvstart(get_disposition + ' ' + flavor
628 + ' commit/save to existing tag fails')
629 for item in ('.tag/commit-2', 'src/' + save_2):
630 for given in (('.tag/tinyfile', '.tag/obj'),
631 ('.tag/tree-1', '.tag/obj'),
632 ('.tag/commit-1', '.tag/obj')):
633 exr = run_get(get_disposition, flavor, (item, '.tag/obj'), given=given)
635 verify_rx(r'cannot overwrite existing tag', exr.err)
637 wvstart(get_disposition + ' ' + flavor + ' commit/save to tag')
638 for item in ('.tag/commit-2', 'src/' + save_2):
639 exr = run_get(get_disposition, flavor, (item, '.tag/obj'))
641 validate_clean_repo()
642 validate_new_tagged_commit('obj', commit_2_id, tree_2_id, exr.out)
643 verify_only_refs(heads=[], tags=('obj',))
645 wvstart(get_disposition + ' ' + flavor + ' commit/save to branch')
646 for item in ('.tag/commit-2', 'src/' + save_2):
647 for given in (None, ('.tag/commit-1', 'obj'), ('.tag/commit-2', 'obj')):
648 exr = run_get(get_disposition, flavor, (item, 'obj'), given=given)
650 validate_clean_repo()
651 validate_new_save('obj/latest', getcwd() + '/src',
652 commit_2_id, tree_2_id, 'src-2', exr.out)
653 verify_only_refs(heads=('obj',), tags=[])
655 wvstart(get_disposition + ' ' + flavor
656 + ' commit/save unrelated commit to branch')
657 for item in('.tag/commit-2', 'src/' + save_2):
658 exr = run_get(get_disposition, flavor, (item, 'obj'),
659 given=('unrelated-branch', 'obj'))
661 validate_clean_repo()
662 validate_new_save('obj/latest', getcwd() + '/src',
663 commit_2_id, tree_2_id, 'src-2', exr.out)
664 verify_only_refs(heads=('obj',), tags=[])
666 wvstart(get_disposition + ' ' + flavor + ' commit/save ancestor to branch')
667 save_1 = src_info['save-1']
668 commit_1_id = src_info['commit-1-id']
669 tree_1_id = src_info['tree-1-id']
670 for item in ('.tag/commit-1', 'src/' + save_1):
671 exr = run_get(get_disposition, flavor, (item, 'obj'),
672 given=('.tag/commit-2', 'obj'))
674 validate_clean_repo()
675 validate_new_save('obj/latest', getcwd() + '/src',
676 commit_1_id, tree_1_id, 'src-1', exr.out)
677 verify_only_refs(heads=('obj',), tags=[])
680 wvstart(get_disposition + ' ' + flavor + ', implicit destinations')
681 exr = run_get(get_disposition, flavor, '.tag/commit-2')
683 validate_clean_repo()
684 validate_new_tagged_commit('commit-2', commit_2_id, tree_2_id, exr.out)
685 verify_only_refs(heads=[], tags=('commit-2',))
687 exr = run_get(get_disposition, flavor, 'src/latest')
689 validate_clean_repo()
690 validate_new_save('src/latest', getcwd() + '/src',
691 commit_2_id, tree_2_id, 'src-2', exr.out)
692 verify_only_refs(heads=('src',), tags=[])
694 def test_new_tag(get_disposition, src_info):
695 tinyfile_id = src_info['tinyfile-id']
696 tinyfile_path = src_info['tinyfile-path']
697 commit_2_id = src_info['commit-2-id']
698 tree_2_id = src_info['tree-2-id']
699 subtree_id = src_info['subtree-id']
700 subtree_vfs_path = src_info['subtree-vfs-path']
702 wvstart(get_disposition + ' --new-tag to root fails')
703 for item in ('.tag/tinyfile',
704 'src/latest' + tinyfile_path,
706 'src/latest' + subtree_vfs_path,
710 exr = run_get(get_disposition, '--new-tag', (item, '/'))
712 verify_rx(r'destination for .+ must be a VFS tag', exr.err)
714 # Anything to new tag.
715 wvstart(get_disposition + ' --new-tag, blob tag')
716 for item in ('.tag/tinyfile', 'src/latest' + tinyfile_path):
717 exr = run_get(get_disposition, '--new-tag', (item, '.tag/obj'))
719 validate_blob(tinyfile_id, tinyfile_id)
720 verify_only_refs(heads=[], tags=('obj',))
722 wvstart(get_disposition + ' --new-tag, tree tag')
723 for item in ('.tag/subtree', 'src/latest' + subtree_vfs_path):
724 exr = run_get(get_disposition, '--new-tag', (item, '.tag/obj'))
726 validate_tree(subtree_id, subtree_id)
727 verify_only_refs(heads=[], tags=('obj',))
729 wvstart(get_disposition + ' --new-tag, committish tag')
730 for item in ('.tag/commit-2', 'src/latest', 'src'):
731 exr = run_get(get_disposition, '--new-tag', (item, '.tag/obj'))
733 validate_tagged_save('obj', getcwd() + '/src/', commit_2_id, tree_2_id,
735 verify_only_refs(heads=[], tags=('obj',))
737 # Anything to existing tag (fails).
738 for ex_type, ex_tag in (('blob', ('.tag/tinyfile', '.tag/obj')),
739 ('tree', ('.tag/tree-1', '.tag/obj')),
740 ('commit', ('.tag/commit-1', '.tag/obj'))):
741 for item_type, item in (('blob tag', '.tag/tinyfile'),
742 ('blob path', 'src/latest' + tinyfile_path),
743 ('tree tag', '.tag/subtree'),
744 ('tree path', 'src/latest' + subtree_vfs_path),
745 ('commit tag', '.tag/commit-2'),
746 ('save', 'src/latest'),
748 wvstart(get_disposition + ' --new-tag of ' + item_type
749 + ', given existing ' + ex_type + ' tag, fails')
750 exr = run_get(get_disposition, '--new-tag', (item, '.tag/obj'),
753 verify_rx(r'cannot overwrite existing tag .* \(requires --replace\)',
756 # Anything to branch (fails).
757 for ex_type, ex_tag in (('nothing', None),
758 ('blob', ('.tag/tinyfile', '.tag/obj')),
759 ('tree', ('.tag/tree-1', '.tag/obj')),
760 ('commit', ('.tag/commit-1', '.tag/obj'))):
761 for item_type, item in (('blob tag', '.tag/tinyfile'),
762 ('blob path', 'src/latest' + tinyfile_path),
763 ('tree tag', '.tag/subtree'),
764 ('tree path', 'src/latest' + subtree_vfs_path),
765 ('commit tag', '.tag/commit-2'),
766 ('save', 'src/latest'),
768 wvstart(get_disposition + ' --new-tag to branch of ' + item_type
769 + ', given existing ' + ex_type + ' tag, fails')
770 exr = run_get(get_disposition, '--new-tag', (item, 'obj'),
773 verify_rx(r'destination for .+ must be a VFS tag', exr.err)
775 wvstart(get_disposition + ' --new-tag, implicit destinations')
776 exr = run_get(get_disposition, '--new-tag', '.tag/commit-2')
778 validate_tagged_save('commit-2', getcwd() + '/src/', commit_2_id, tree_2_id,
780 verify_only_refs(heads=[], tags=('commit-2',))
782 def test_unnamed(get_disposition, src_info):
783 tinyfile_id = src_info['tinyfile-id']
784 tinyfile_path = src_info['tinyfile-path']
785 subtree_vfs_path = src_info['subtree-vfs-path']
786 wvstart(get_disposition + ' --unnamed to root fails')
787 for item in ('.tag/tinyfile',
788 'src/latest' + tinyfile_path,
790 'src/latest' + subtree_vfs_path,
794 for ex_ref in (None, (item, '.tag/obj')):
795 exr = run_get(get_disposition, '--unnamed', (item, '/'),
798 verify_rx(r'usage: bup get ', exr.err)
800 wvstart(get_disposition + ' --unnamed file')
801 for item in ('.tag/tinyfile', 'src/latest' + tinyfile_path):
802 exr = run_get(get_disposition, '--unnamed', item)
804 validate_blob(tinyfile_id, tinyfile_id)
805 verify_only_refs(heads=[], tags=[])
807 exr = run_get(get_disposition, '--unnamed', item,
808 given=(item, '.tag/obj'))
810 validate_blob(tinyfile_id, tinyfile_id)
811 verify_only_refs(heads=[], tags=('obj',))
813 wvstart(get_disposition + ' --unnamed tree')
814 subtree_id = src_info['subtree-id']
815 for item in ('.tag/subtree', 'src/latest' + subtree_vfs_path):
816 exr = run_get(get_disposition, '--unnamed', item)
818 validate_tree(subtree_id, subtree_id)
819 verify_only_refs(heads=[], tags=[])
821 exr = run_get(get_disposition, '--unnamed', item,
822 given=(item, '.tag/obj'))
824 validate_tree(subtree_id, subtree_id)
825 verify_only_refs(heads=[], tags=('obj',))
827 wvstart(get_disposition + ' --unnamed committish')
828 save_2 = src_info['save-2']
829 commit_2_id = src_info['commit-2-id']
830 for item in ('.tag/commit-2', 'src/' + save_2, 'src'):
831 exr = run_get(get_disposition, '--unnamed', item)
833 validate_commit(commit_2_id, commit_2_id)
834 verify_only_refs(heads=[], tags=[])
836 exr = run_get(get_disposition, '--unnamed', item,
837 given=(item, '.tag/obj'))
839 validate_commit(commit_2_id, commit_2_id)
840 verify_only_refs(heads=[], tags=('obj',))
842 def create_get_src():
843 global bup_cmd, src_info
845 ex((bup_cmd, '-d', 'get-src', 'init'))
848 open('src/unrelated', 'a').close()
849 ex((bup_cmd, '-d', 'get-src', 'index', 'src'))
850 ex((bup_cmd, '-d', 'get-src', 'save', '-tcn', 'unrelated-branch', 'src'))
852 ex((bup_cmd, '-d', 'get-src', 'index', '--clear'))
855 open('src/zero', 'a').close()
856 ex((bup_cmd, '-d', 'get-src', 'index', 'src'))
857 exr = exo((bup_cmd, '-d', 'get-src', 'save', '-tcn', 'src', 'src'))
858 out = exr.out.splitlines()
860 commit_0_id = out[-1]
861 exr = exo((bup_cmd, '-d', 'get-src', 'ls', 'src'))
862 save_0 = exr.out.splitlines()[0]
863 ex(('git', '--git-dir', 'get-src', 'branch', 'src-0', 'src'))
864 ex(('cp', '-a', 'src', 'src-0'))
870 ex((bup_cmd + ' -d get-src random 1k > src/1'), shell=True)
871 ex((bup_cmd + ' -d get-src random 1k > src/x/2'), shell=True)
872 ex((bup_cmd, '-d', 'get-src', 'index', 'src'))
873 exr = exo((bup_cmd, '-d', 'get-src', 'save', '-tcn', 'src', 'src'))
874 out = exr.out.splitlines()
876 commit_1_id = out[-1]
877 exr = exo((bup_cmd, '-d', 'get-src', 'ls', 'src'))
878 save_1 = exr.out.splitlines()[1]
879 ex(('git', '--git-dir', 'get-src', 'branch', 'src-1', 'src'))
880 ex(('cp', '-a', 'src', 'src-1'))
882 # Make a copy the current state of src so we'll have an ancestor.
884 'get-src/refs/heads/src', 'get-src/refs/heads/src-ancestor'))
886 with open('src/tiny-file', 'a') as f: f.write('xyzzy')
887 ex((bup_cmd, '-d', 'get-src', 'index', 'src'))
888 ex((bup_cmd, '-d', 'get-src', 'tick')) # Ensure the save names differ
889 exr = exo((bup_cmd, '-d', 'get-src', 'save', '-tcn', 'src', 'src'))
890 out = exr.out.splitlines()
892 commit_2_id = out[-1]
893 exr = exo((bup_cmd, '-d', 'get-src', 'ls', 'src'))
894 save_2 = exr.out.splitlines()[2]
895 rename('src', 'src-2')
897 src_root = getcwd() + '/src'
899 subtree_path = 'src-2/x'
900 subtree_vfs_path = src_root + '/x'
902 # No support for "ls -d", so grep...
903 exr = exo((bup_cmd, '-d', 'get-src', 'ls', '-s', 'src/latest' + src_root))
904 out = exr.out.splitlines()
908 subtree_id = line.split()[0]
911 # With a tiny file, we'll get a single blob, not a chunked tree
912 tinyfile_path = src_root + '/tiny-file'
913 exr = exo((bup_cmd, '-d', 'get-src', 'ls', '-s', 'src/latest' + tinyfile_path))
914 tinyfile_id = exr.out.splitlines()[0].split()[0]
916 ex((bup_cmd, '-d', 'get-src', 'tag', 'tinyfile', tinyfile_id))
917 ex((bup_cmd, '-d', 'get-src', 'tag', 'subtree', subtree_id))
918 ex((bup_cmd, '-d', 'get-src', 'tag', 'tree-0', tree_0_id))
919 ex((bup_cmd, '-d', 'get-src', 'tag', 'tree-1', tree_1_id))
920 ex((bup_cmd, '-d', 'get-src', 'tag', 'tree-2', tree_2_id))
921 ex((bup_cmd, '-d', 'get-src', 'tag', 'commit-0', commit_0_id))
922 ex((bup_cmd, '-d', 'get-src', 'tag', 'commit-1', commit_1_id))
923 ex((bup_cmd, '-d', 'get-src', 'tag', 'commit-2', commit_2_id))
924 ex(('git', '--git-dir', 'get-src', 'branch', 'commit-1', commit_1_id))
925 ex(('git', '--git-dir', 'get-src', 'branch', 'commit-2', commit_2_id))
927 return {'tinyfile-path' : tinyfile_path,
928 'tinyfile-id' : tinyfile_id,
929 'subtree-id' : subtree_id,
930 'tree-0-id' : tree_0_id,
931 'tree-1-id' : tree_1_id,
932 'tree-2-id' : tree_2_id,
933 'commit-0-id' : commit_0_id,
934 'commit-1-id' : commit_1_id,
935 'commit-2-id' : commit_2_id,
938 'subtree-path' : subtree_path,
939 'subtree-vfs-path' : subtree_vfs_path}
941 # FIXME: this fails in a strange way:
942 # WVPASS given nothing get --ff not-there
944 dispositions_to_test = ('get',)
946 if int(environ.get('BUP_TEST_LEVEL', '0')) >= 11:
947 dispositions_to_test += ('get-on', 'get-to')
949 if len(sys.argv) == 1:
950 categories = ('replace', 'universal', 'ff', 'append', 'pick', 'new-tag',
953 categories = sys.argv[1:]
955 with test_tempdir('get-') as tmpdir:
958 src_info = create_get_src()
959 for category in categories:
960 for disposition in dispositions_to_test:
961 # given=FOO depends on --replace, so test it early
962 if category == 'replace':
963 test_replace(disposition, src_info)
964 elif category == 'universal':
965 test_universal_behaviors(disposition)
966 elif category == 'ff':
967 test_ff(disposition, src_info)
968 elif category == 'append':
969 test_append(disposition, src_info)
970 elif category == 'pick':
971 test_pick(disposition, src_info, force=False)
972 test_pick(disposition, src_info, force=True)
973 elif category == 'new-tag':
974 test_new_tag(disposition, src_info)
975 elif category == 'unnamed':
976 test_unnamed(disposition, src_info)
978 raise Exception('unrecognized get test category')
979 except Exception, ex:
984 wvmsg('checked %d cases' % get_cases_tested)