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
241 fsck = ex((bup_cmd, '-d', 'get-dest', 'fsck'), check=False)
245 def run_get(disposition, method, what=None, given=None):
248 ex((bup_cmd, '-d', 'get-dest', 'init'))
251 # FIXME: replace bup-get with independent commands as is feasible
252 exr = _run_get(disposition, '--replace', given)
254 return _run_get(disposition, method, what)
256 def test_universal_behaviors(get_disposition):
257 methods = ('--ff', '--append', '--pick', '--force-pick', '--new-tag',
258 '--replace', '--unnamed')
259 for method in methods:
260 wvstart(get_disposition + ' ' + method + ', missing source, fails')
261 exr = run_get(get_disposition, method, 'not-there')
263 verify_rx(r'cannot find source', exr.err)
264 for method in methods:
265 wvstart(get_disposition + ' ' + method + ' / fails')
266 exr = run_get(get_disposition, method, '/')
268 verify_rx('cannot fetch entire repository', exr.err)
270 def verify_only_refs(**kwargs):
271 for kind, refs in kwargs.iteritems():
273 abs_refs = ['refs/heads/' + ref for ref in refs]
276 abs_refs = ['refs/tags/' + ref for ref in refs]
279 raise TypeError('unexpected keyword argument %r' % kind)
281 verify_rcz(['git', '--git-dir', 'get-dest',
282 'show-ref', '--verify', karg] + abs_refs)
283 exr = exo(('git', '--git-dir', 'get-dest', 'show-ref', karg),
286 expected_refs = sorted(abs_refs)
287 repo_refs = sorted([x.split()[1] for x in exr.out.splitlines()])
288 wvpasseq(expected_refs, repo_refs)
290 # FIXME: can we just check "git show-ref --heads == ''"?
291 exr = exo(('git', '--git-dir', 'get-dest', 'show-ref', karg),
294 wvpasseq('', exr.out.strip())
296 def test_replace(get_disposition, src_info):
298 wvstart(get_disposition + ' --replace to root fails')
299 for item in ('.tag/tinyfile',
300 'src/latest' + src_info['tinyfile-path'],
302 'src/latest' + src_info['subtree-vfs-path'],
306 exr = run_get(get_disposition, '--replace', (item, '/'))
308 verify_rx(r'impossible; can only overwrite branch or tag', exr.err)
310 tinyfile_id = src_info['tinyfile-id']
311 tinyfile_path = src_info['tinyfile-path']
312 subtree_vfs_path = src_info['subtree-vfs-path']
313 subtree_id = src_info['subtree-id']
314 commit_2_id = src_info['commit-2-id']
315 tree_2_id = src_info['tree-2-id']
318 existing_items = {'nothing' : None,
319 'blob' : ('.tag/tinyfile', '.tag/obj'),
320 'tree' : ('.tag/tree-1', '.tag/obj'),
321 'commit': ('.tag/commit-1', '.tag/obj')}
322 for ex_type, ex_ref in existing_items.iteritems():
323 wvstart(get_disposition + ' --replace ' + ex_type + ' with blob tag')
324 for item in ('.tag/tinyfile', 'src/latest' + tinyfile_path):
325 exr = run_get(get_disposition, '--replace', (item ,'.tag/obj'),
328 validate_blob(tinyfile_id, tinyfile_id)
329 verify_only_refs(heads=[], tags=('obj',))
330 wvstart(get_disposition + ' --replace ' + ex_type + ' with tree tag')
331 for item in ('.tag/subtree', 'src/latest' + subtree_vfs_path):
332 exr = run_get(get_disposition, '--replace', (item, '.tag/obj'),
334 validate_tree(subtree_id, subtree_id)
335 verify_only_refs(heads=[], tags=('obj',))
336 wvstart(get_disposition + ' --replace ' + ex_type + ' with commitish tag')
337 for item in ('.tag/commit-2', 'src/latest', 'src'):
338 exr = run_get(get_disposition, '--replace', (item, '.tag/obj'),
340 validate_tagged_save('obj', getcwd() + '/src',
341 commit_2_id, tree_2_id, 'src-2', exr.out)
342 verify_only_refs(heads=[], tags=('obj',))
344 # Committish to branch.
345 existing_items = (('nothing', None),
346 ('branch', ('.tag/commit-1', 'obj')))
347 for ex_type, ex_ref in existing_items:
348 for item_type, item in (('commit', '.tag/commit-2'),
349 ('save', 'src/latest'),
351 wvstart(get_disposition + ' --replace '
352 + ex_type + ' with ' + item_type)
353 exr = run_get(get_disposition, '--replace', (item, 'obj'),
355 validate_save('obj/latest', getcwd() + '/src',
356 commit_2_id, tree_2_id, 'src-2', exr.out)
357 verify_only_refs(heads=('obj',), tags=[])
359 # Not committish to branch
360 existing_items = (('nothing', None),
361 ('branch', ('.tag/commit-1', 'obj')))
362 for ex_type, ex_ref in existing_items:
363 for item_type, item in (('blob', '.tag/tinyfile'),
364 ('blob', 'src/latest' + tinyfile_path),
365 ('tree', '.tag/subtree'),
366 ('tree', 'src/latest' + subtree_vfs_path)):
367 wvstart(get_disposition + ' --replace branch with '
368 + item_type + ' given ' + ex_type + ' fails')
370 exr = run_get(get_disposition, '--replace', (item, 'obj'),
373 verify_rx(r'cannot overwrite branch with .+ for', exr.err)
375 wvstart(get_disposition + ' --replace, implicit destinations')
377 exr = run_get(get_disposition, '--replace', 'src')
378 validate_save('src/latest', getcwd() + '/src',
379 commit_2_id, tree_2_id, 'src-2', exr.out)
380 verify_only_refs(heads=('src',), tags=[])
382 exr = run_get(get_disposition, '--replace', '.tag/commit-2')
383 validate_tagged_save('commit-2', getcwd() + '/src',
384 commit_2_id, tree_2_id, 'src-2', exr.out)
385 verify_only_refs(heads=[], tags=('commit-2',))
387 def test_ff(get_disposition, src_info):
389 wvstart(get_disposition + ' --ff to root fails')
390 tinyfile_path = src_info['tinyfile-path']
391 for item in ('.tag/tinyfile', 'src/latest' + tinyfile_path):
392 exr = run_get(get_disposition, '--ff', (item, '/'))
394 verify_rx(r'source for .+ must be a branch, save, or commit', exr.err)
395 subtree_vfs_path = src_info['subtree-vfs-path']
396 for item in ('.tag/subtree', 'src/latest' + subtree_vfs_path):
397 exr = run_get(get_disposition, '--ff', (item, '/'))
399 verify_rx(r'is impossible; can only --append a tree to a branch',
401 for item in ('.tag/commit-1', 'src/latest', 'src'):
402 exr = run_get(get_disposition, '--ff', (item, '/'))
404 verify_rx(r'destination for .+ is a root, not a branch', exr.err)
406 wvstart(get_disposition + ' --ff of not-committish fails')
407 for src in ('.tag/tinyfile', 'src/latest' + tinyfile_path):
408 # FIXME: use get_item elsewhere?
409 for given, get_item in ((None, (src, 'obj')),
410 (None, (src, '.tag/obj')),
411 (('.tag/tinyfile', '.tag/obj'), (src, '.tag/obj')),
412 (('.tag/tree-1', '.tag/obj'), (src, '.tag/obj')),
413 (('.tag/commit-1', '.tag/obj'), (src, '.tag/obj')),
414 (('.tag/commit-1', 'obj'), (src, 'obj'))):
415 exr = run_get(get_disposition, '--ff', get_item, given=given)
417 verify_rx(r'must be a branch, save, or commit', exr.err)
418 for src in ('.tag/subtree', 'src/latest' + subtree_vfs_path):
419 for given, get_item in ((None, (src, 'obj')),
420 (None, (src, '.tag/obj')),
421 (('.tag/tinyfile', '.tag/obj'), (src, '.tag/obj')),
422 (('.tag/tree-1', '.tag/obj'), (src, '.tag/obj')),
423 (('.tag/commit-1', '.tag/obj'), (src, '.tag/obj')),
424 (('.tag/commit-1', 'obj'), (src, 'obj'))):
425 exr = run_get(get_disposition, '--ff', get_item, given=given)
427 verify_rx(r'can only --append a tree to a branch', exr.err)
429 wvstart(get_disposition + ' --ff committish, ff possible')
430 save_2 = src_info['save-2']
431 for src in ('.tag/commit-2', 'src/' + save_2, 'src'):
432 for given, get_item, complaint in \
433 ((None, (src, '.tag/obj'),
434 r'destination .+ must be a valid branch name'),
435 (('.tag/tinyfile', '.tag/obj'), (src, '.tag/obj'),
436 r'destination .+ is a blob, not a branch'),
437 (('.tag/tree-1', '.tag/obj'), (src, '.tag/obj'),
438 r'destination .+ is a tree, not a branch'),
439 (('.tag/commit-1', '.tag/obj'), (src, '.tag/obj'),
440 r'destination .+ is a tagged commit, not a branch'),
441 (('.tag/commit-2', '.tag/obj'), (src, '.tag/obj'),
442 r'destination .+ is a tagged commit, not a branch')):
443 exr = run_get(get_disposition, '--ff', get_item, given=given)
445 verify_rx(complaint, exr.err)
446 # FIXME: use src or item and given or existing consistently in loops...
447 commit_2_id = src_info['commit-2-id']
448 tree_2_id = src_info['tree-2-id']
449 for src in ('.tag/commit-2', 'src/' + save_2, 'src'):
450 for given in (None, ('.tag/commit-1', 'obj'), ('.tag/commit-2', 'obj')):
451 exr = run_get(get_disposition, '--ff', (src, 'obj'), given=given)
453 validate_save('obj/latest', getcwd() + '/src',
454 commit_2_id, tree_2_id, 'src-2', exr.out)
455 verify_only_refs(heads=('obj',), tags=[])
457 wvstart(get_disposition + ' --ff, implicit destinations')
458 for item in ('src', 'src/latest'):
459 exr = run_get(get_disposition, '--ff', item)
462 ex(('find', 'get-dest/refs'))
463 ex((bup_cmd, '-d', 'get-dest', 'ls'))
465 validate_save('src/latest', getcwd() + '/src',
466 commit_2_id, tree_2_id, 'src-2', exr.out)
467 #verify_only_refs(heads=('src',), tags=[])
469 wvstart(get_disposition + ' --ff, ff impossible')
470 for given, get_item in ((('unrelated-branch', 'src'), 'src'),
471 (('.tag/commit-2', 'src'), ('.tag/commit-1', 'src'))):
472 exr = run_get(get_disposition, '--ff', get_item, given=given)
474 verify_rx(r'destination is not an ancestor of source', exr.err)
476 def test_append(get_disposition, src_info):
477 tinyfile_path = src_info['tinyfile-path']
478 subtree_vfs_path = src_info['subtree-vfs-path']
480 wvstart(get_disposition + ' --append to root fails')
481 for item in ('.tag/tinyfile', 'src/latest' + tinyfile_path):
482 exr = run_get(get_disposition, '--append', (item, '/'))
484 verify_rx(r'source for .+ must be a branch, save, commit, or tree',
486 for item in ('.tag/subtree', 'src/latest' + subtree_vfs_path,
487 '.tag/commit-1', 'src/latest', 'src'):
488 exr = run_get(get_disposition, '--append', (item, '/'))
490 verify_rx(r'destination for .+ is a root, not a branch', exr.err)
492 wvstart(get_disposition + ' --append of not-treeish fails')
493 for src in ('.tag/tinyfile', 'src/latest' + tinyfile_path):
494 for given, item in ((None, (src, 'obj')),
495 (None, (src, '.tag/obj')),
496 (('.tag/tinyfile', '.tag/obj'), (src, '.tag/obj')),
497 (('.tag/tree-1', '.tag/obj'), (src, '.tag/obj')),
498 (('.tag/commit-1', '.tag/obj'), (src, '.tag/obj')),
499 (('.tag/commit-1', 'obj'), (src, 'obj'))):
500 exr = run_get(get_disposition, '--append', item, given=given)
502 verify_rx(r'must be a branch, save, commit, or tree', exr.err)
504 wvstart(get_disposition + ' --append committish failure cases')
505 save_2 = src_info['save-2']
506 for src in ('.tag/subtree', 'src/latest' + subtree_vfs_path,
507 '.tag/commit-2', 'src/' + save_2, 'src'):
508 for given, item, complaint in \
509 ((None, (src, '.tag/obj'),
510 r'destination .+ must be a valid branch name'),
511 (('.tag/tinyfile', '.tag/obj'), (src, '.tag/obj'),
512 r'destination .+ is a blob, not a branch'),
513 (('.tag/tree-1', '.tag/obj'), (src, '.tag/obj'),
514 r'destination .+ is a tree, not a branch'),
515 (('.tag/commit-1', '.tag/obj'), (src, '.tag/obj'),
516 r'destination .+ is a tagged commit, not a branch'),
517 (('.tag/commit-2', '.tag/obj'), (src, '.tag/obj'),
518 r'destination .+ is a tagged commit, not a branch')):
519 exr = run_get(get_disposition, '--append', item, given=given)
521 verify_rx(complaint, exr.err)
523 wvstart(get_disposition + ' --append committish')
524 commit_2_id = src_info['commit-2-id']
525 tree_2_id = src_info['tree-2-id']
526 for item in ('.tag/commit-2', 'src/' + save_2, 'src'):
527 for existing in (None, ('.tag/commit-1', 'obj'),
528 ('.tag/commit-2', 'obj'),
529 ('unrelated-branch', 'obj')):
530 exr = run_get(get_disposition, '--append', (item, 'obj'),
533 validate_new_save('obj/latest', getcwd() + '/src',
534 commit_2_id, tree_2_id, 'src-2', exr.out)
535 verify_only_refs(heads=('obj',), tags=[])
537 save_1 = src_info['save-1']
538 commit_1_id = src_info['commit-1-id']
539 tree_1_id = src_info['tree-1-id']
540 for item in ('.tag/commit-1', 'src/' + save_1, 'src-1'):
541 exr = run_get(get_disposition, '--append', (item, 'obj'),
542 given=('.tag/commit-2', 'obj'))
544 validate_new_save('obj/latest', getcwd() + '/src',
545 commit_1_id, tree_1_id, 'src-1', exr.out)
546 verify_only_refs(heads=('obj',), tags=[])
548 wvstart(get_disposition + ' --append tree')
549 subtree_path = src_info['subtree-path']
550 subtree_id = src_info['subtree-id']
551 for item in ('.tag/subtree', 'src/latest' + subtree_vfs_path):
552 for existing in (None, ('.tag/commit-1', 'obj'), ('.tag/commit-2','obj')):
553 exr = run_get(get_disposition, '--append', (item, 'obj'),
556 validate_new_save('obj/latest', '/', None, subtree_id, subtree_path,
558 verify_only_refs(heads=('obj',), tags=[])
560 wvstart(get_disposition + ' --append, implicit destinations')
562 for item in ('src', 'src/latest'):
563 exr = run_get(get_disposition, '--append', item)
565 validate_new_save('src/latest', getcwd() + '/src', commit_2_id, tree_2_id,
567 verify_only_refs(heads=('src',), tags=[])
569 def test_pick(get_disposition, src_info, force=False):
570 flavor = '--force-pick' if force else '--pick'
571 tinyfile_path = src_info['tinyfile-path']
572 subtree_vfs_path = src_info['subtree-vfs-path']
574 wvstart(get_disposition + ' ' + flavor + ' to root fails')
575 for item in ('.tag/tinyfile', 'src/latest' + tinyfile_path, 'src'):
576 exr = run_get(get_disposition, flavor, (item, '/'))
578 verify_rx(r'can only pick a commit or save', exr.err)
579 for item in ('.tag/commit-1', 'src/latest'):
580 exr = run_get(get_disposition, flavor, (item, '/'))
582 verify_rx(r'destination is not a tag or branch', exr.err)
583 for item in ('.tag/subtree', 'src/latest' + subtree_vfs_path):
584 exr = run_get(get_disposition, flavor, (item, '/'))
586 verify_rx(r'is impossible; can only --append a tree', exr.err)
588 wvstart(get_disposition + ' ' + flavor + ' of blob or branch fails')
589 for item in ('.tag/tinyfile', 'src/latest' + tinyfile_path, 'src'):
590 for given, get_item in ((None, (item, 'obj')),
591 (None, (item, '.tag/obj')),
592 (('.tag/tinyfile', '.tag/obj'), (item, '.tag/obj')),
593 (('.tag/tree-1', '.tag/obj'), (item, '.tag/obj')),
594 (('.tag/commit-1', '.tag/obj'), (item, '.tag/obj')),
595 (('.tag/commit-1', 'obj'), (item, 'obj'))):
596 exr = run_get(get_disposition, flavor, get_item, given=given)
598 verify_rx(r'impossible; can only pick a commit or save', exr.err)
600 wvstart(get_disposition + ' ' + flavor + ' of tree fails')
601 for item in ('.tag/subtree', 'src/latest' + subtree_vfs_path):
602 for given, get_item in ((None, (item, 'obj')),
603 (None, (item, '.tag/obj')),
604 (('.tag/tinyfile', '.tag/obj'), (item, '.tag/obj')),
605 (('.tag/tree-1', '.tag/obj'), (item, '.tag/obj')),
606 (('.tag/commit-1', '.tag/obj'), (item, '.tag/obj')),
607 (('.tag/commit-1', 'obj'), (item, 'obj'))):
608 exr = run_get(get_disposition, flavor, get_item, given=given)
610 verify_rx(r'impossible; can only --append a tree', exr.err)
612 save_2 = src_info['save-2']
613 commit_2_id = src_info['commit-2-id']
614 tree_2_id = src_info['tree-2-id']
615 # FIXME: these two wvstart texts?
617 wvstart(get_disposition + ' ' + flavor + ' commit/save to existing tag')
618 for item in ('.tag/commit-2', 'src/' + save_2):
619 for given in (('.tag/tinyfile', '.tag/obj'),
620 ('.tag/tree-1', '.tag/obj'),
621 ('.tag/commit-1', '.tag/obj')):
622 exr = run_get(get_disposition, flavor, (item, '.tag/obj'),
625 validate_new_tagged_commit('obj', commit_2_id, tree_2_id,
627 verify_only_refs(heads=[], tags=('obj',))
629 wvstart(get_disposition + ' ' + flavor
630 + ' commit/save to existing tag fails')
631 for item in ('.tag/commit-2', 'src/' + save_2):
632 for given in (('.tag/tinyfile', '.tag/obj'),
633 ('.tag/tree-1', '.tag/obj'),
634 ('.tag/commit-1', '.tag/obj')):
635 exr = run_get(get_disposition, flavor, (item, '.tag/obj'), given=given)
637 verify_rx(r'cannot overwrite existing tag', exr.err)
639 wvstart(get_disposition + ' ' + flavor + ' commit/save to tag')
640 for item in ('.tag/commit-2', 'src/' + save_2):
641 exr = run_get(get_disposition, flavor, (item, '.tag/obj'))
643 validate_clean_repo()
644 validate_new_tagged_commit('obj', commit_2_id, tree_2_id, exr.out)
645 verify_only_refs(heads=[], tags=('obj',))
647 wvstart(get_disposition + ' ' + flavor + ' commit/save to branch')
648 for item in ('.tag/commit-2', 'src/' + save_2):
649 for given in (None, ('.tag/commit-1', 'obj'), ('.tag/commit-2', 'obj')):
650 exr = run_get(get_disposition, flavor, (item, 'obj'), given=given)
652 validate_clean_repo()
653 validate_new_save('obj/latest', getcwd() + '/src',
654 commit_2_id, tree_2_id, 'src-2', exr.out)
655 verify_only_refs(heads=('obj',), tags=[])
657 wvstart(get_disposition + ' ' + flavor
658 + ' commit/save unrelated commit to branch')
659 for item in('.tag/commit-2', 'src/' + save_2):
660 exr = run_get(get_disposition, flavor, (item, 'obj'),
661 given=('unrelated-branch', 'obj'))
663 validate_clean_repo()
664 validate_new_save('obj/latest', getcwd() + '/src',
665 commit_2_id, tree_2_id, 'src-2', exr.out)
666 verify_only_refs(heads=('obj',), tags=[])
668 wvstart(get_disposition + ' ' + flavor + ' commit/save ancestor to branch')
669 save_1 = src_info['save-1']
670 commit_1_id = src_info['commit-1-id']
671 tree_1_id = src_info['tree-1-id']
672 for item in ('.tag/commit-1', 'src/' + save_1):
673 exr = run_get(get_disposition, flavor, (item, 'obj'),
674 given=('.tag/commit-2', 'obj'))
676 validate_clean_repo()
677 validate_new_save('obj/latest', getcwd() + '/src',
678 commit_1_id, tree_1_id, 'src-1', exr.out)
679 verify_only_refs(heads=('obj',), tags=[])
682 wvstart(get_disposition + ' ' + flavor + ', implicit destinations')
683 exr = run_get(get_disposition, flavor, '.tag/commit-2')
685 validate_clean_repo()
686 validate_new_tagged_commit('commit-2', commit_2_id, tree_2_id, exr.out)
687 verify_only_refs(heads=[], tags=('commit-2',))
689 exr = run_get(get_disposition, flavor, 'src/latest')
691 validate_clean_repo()
692 validate_new_save('src/latest', getcwd() + '/src',
693 commit_2_id, tree_2_id, 'src-2', exr.out)
694 verify_only_refs(heads=('src',), tags=[])
696 def test_new_tag(get_disposition, src_info):
697 tinyfile_id = src_info['tinyfile-id']
698 tinyfile_path = src_info['tinyfile-path']
699 commit_2_id = src_info['commit-2-id']
700 tree_2_id = src_info['tree-2-id']
701 subtree_id = src_info['subtree-id']
702 subtree_vfs_path = src_info['subtree-vfs-path']
704 wvstart(get_disposition + ' --new-tag to root fails')
705 for item in ('.tag/tinyfile',
706 'src/latest' + tinyfile_path,
708 'src/latest' + subtree_vfs_path,
712 exr = run_get(get_disposition, '--new-tag', (item, '/'))
714 verify_rx(r'destination for .+ must be a VFS tag', exr.err)
716 # Anything to new tag.
717 wvstart(get_disposition + ' --new-tag, blob tag')
718 for item in ('.tag/tinyfile', 'src/latest' + tinyfile_path):
719 exr = run_get(get_disposition, '--new-tag', (item, '.tag/obj'))
721 validate_blob(tinyfile_id, tinyfile_id)
722 verify_only_refs(heads=[], tags=('obj',))
724 wvstart(get_disposition + ' --new-tag, tree tag')
725 for item in ('.tag/subtree', 'src/latest' + subtree_vfs_path):
726 exr = run_get(get_disposition, '--new-tag', (item, '.tag/obj'))
728 validate_tree(subtree_id, subtree_id)
729 verify_only_refs(heads=[], tags=('obj',))
731 wvstart(get_disposition + ' --new-tag, committish tag')
732 for item in ('.tag/commit-2', 'src/latest', 'src'):
733 exr = run_get(get_disposition, '--new-tag', (item, '.tag/obj'))
735 validate_tagged_save('obj', getcwd() + '/src/', commit_2_id, tree_2_id,
737 verify_only_refs(heads=[], tags=('obj',))
739 # Anything to existing tag (fails).
740 for ex_type, ex_tag in (('blob', ('.tag/tinyfile', '.tag/obj')),
741 ('tree', ('.tag/tree-1', '.tag/obj')),
742 ('commit', ('.tag/commit-1', '.tag/obj'))):
743 for item_type, item in (('blob tag', '.tag/tinyfile'),
744 ('blob path', 'src/latest' + tinyfile_path),
745 ('tree tag', '.tag/subtree'),
746 ('tree path', 'src/latest' + subtree_vfs_path),
747 ('commit tag', '.tag/commit-2'),
748 ('save', 'src/latest'),
750 wvstart(get_disposition + ' --new-tag of ' + item_type
751 + ', given existing ' + ex_type + ' tag, fails')
752 exr = run_get(get_disposition, '--new-tag', (item, '.tag/obj'),
755 verify_rx(r'cannot overwrite existing tag .* \(requires --replace\)',
758 # Anything to branch (fails).
759 for ex_type, ex_tag in (('nothing', None),
760 ('blob', ('.tag/tinyfile', '.tag/obj')),
761 ('tree', ('.tag/tree-1', '.tag/obj')),
762 ('commit', ('.tag/commit-1', '.tag/obj'))):
763 for item_type, item in (('blob tag', '.tag/tinyfile'),
764 ('blob path', 'src/latest' + tinyfile_path),
765 ('tree tag', '.tag/subtree'),
766 ('tree path', 'src/latest' + subtree_vfs_path),
767 ('commit tag', '.tag/commit-2'),
768 ('save', 'src/latest'),
770 wvstart(get_disposition + ' --new-tag to branch of ' + item_type
771 + ', given existing ' + ex_type + ' tag, fails')
772 exr = run_get(get_disposition, '--new-tag', (item, 'obj'),
775 verify_rx(r'destination for .+ must be a VFS tag', exr.err)
777 wvstart(get_disposition + ' --new-tag, implicit destinations')
778 exr = run_get(get_disposition, '--new-tag', '.tag/commit-2')
780 validate_tagged_save('commit-2', getcwd() + '/src/', commit_2_id, tree_2_id,
782 verify_only_refs(heads=[], tags=('commit-2',))
784 def test_unnamed(get_disposition, src_info):
785 tinyfile_id = src_info['tinyfile-id']
786 tinyfile_path = src_info['tinyfile-path']
787 subtree_vfs_path = src_info['subtree-vfs-path']
788 wvstart(get_disposition + ' --unnamed to root fails')
789 for item in ('.tag/tinyfile',
790 'src/latest' + tinyfile_path,
792 'src/latest' + subtree_vfs_path,
796 for ex_ref in (None, (item, '.tag/obj')):
797 exr = run_get(get_disposition, '--unnamed', (item, '/'),
800 verify_rx(r'usage: bup get ', exr.err)
802 wvstart(get_disposition + ' --unnamed file')
803 for item in ('.tag/tinyfile', 'src/latest' + tinyfile_path):
804 exr = run_get(get_disposition, '--unnamed', item)
806 validate_blob(tinyfile_id, tinyfile_id)
807 verify_only_refs(heads=[], tags=[])
809 exr = run_get(get_disposition, '--unnamed', item,
810 given=(item, '.tag/obj'))
812 validate_blob(tinyfile_id, tinyfile_id)
813 verify_only_refs(heads=[], tags=('obj',))
815 wvstart(get_disposition + ' --unnamed tree')
816 subtree_id = src_info['subtree-id']
817 for item in ('.tag/subtree', 'src/latest' + subtree_vfs_path):
818 exr = run_get(get_disposition, '--unnamed', item)
820 validate_tree(subtree_id, subtree_id)
821 verify_only_refs(heads=[], tags=[])
823 exr = run_get(get_disposition, '--unnamed', item,
824 given=(item, '.tag/obj'))
826 validate_tree(subtree_id, subtree_id)
827 verify_only_refs(heads=[], tags=('obj',))
829 wvstart(get_disposition + ' --unnamed committish')
830 save_2 = src_info['save-2']
831 commit_2_id = src_info['commit-2-id']
832 for item in ('.tag/commit-2', 'src/' + save_2, 'src'):
833 exr = run_get(get_disposition, '--unnamed', item)
835 validate_commit(commit_2_id, commit_2_id)
836 verify_only_refs(heads=[], tags=[])
838 exr = run_get(get_disposition, '--unnamed', item,
839 given=(item, '.tag/obj'))
841 validate_commit(commit_2_id, commit_2_id)
842 verify_only_refs(heads=[], tags=('obj',))
844 def create_get_src():
845 global bup_cmd, src_info
847 ex((bup_cmd, '-d', 'get-src', 'init'))
850 open('src/unrelated', 'a').close()
851 ex((bup_cmd, '-d', 'get-src', 'index', 'src'))
852 ex((bup_cmd, '-d', 'get-src', 'save', '-tcn', 'unrelated-branch', 'src'))
854 ex((bup_cmd, '-d', 'get-src', 'index', '--clear'))
857 open('src/zero', 'a').close()
858 ex((bup_cmd, '-d', 'get-src', 'index', 'src'))
859 exr = exo((bup_cmd, '-d', 'get-src', 'save', '-tcn', 'src', 'src'))
860 out = exr.out.splitlines()
862 commit_0_id = out[-1]
863 exr = exo((bup_cmd, '-d', 'get-src', 'ls', 'src'))
864 save_0 = exr.out.splitlines()[0]
865 ex(('git', '--git-dir', 'get-src', 'branch', 'src-0', 'src'))
866 ex(('cp', '-RPp', 'src', 'src-0'))
872 ex((bup_cmd + ' -d get-src random 1k > src/1'), shell=True)
873 ex((bup_cmd + ' -d get-src random 1k > src/x/2'), shell=True)
874 ex((bup_cmd, '-d', 'get-src', 'index', 'src'))
875 exr = exo((bup_cmd, '-d', 'get-src', 'save', '-tcn', 'src', 'src'))
876 out = exr.out.splitlines()
878 commit_1_id = out[-1]
879 exr = exo((bup_cmd, '-d', 'get-src', 'ls', 'src'))
880 save_1 = exr.out.splitlines()[1]
881 ex(('git', '--git-dir', 'get-src', 'branch', 'src-1', 'src'))
882 ex(('cp', '-RPp', 'src', 'src-1'))
884 # Make a copy the current state of src so we'll have an ancestor.
886 'get-src/refs/heads/src', 'get-src/refs/heads/src-ancestor'))
888 with open('src/tiny-file', 'a') as f: f.write('xyzzy')
889 ex((bup_cmd, '-d', 'get-src', 'index', 'src'))
890 ex((bup_cmd, '-d', 'get-src', 'tick')) # Ensure the save names differ
891 exr = exo((bup_cmd, '-d', 'get-src', 'save', '-tcn', 'src', 'src'))
892 out = exr.out.splitlines()
894 commit_2_id = out[-1]
895 exr = exo((bup_cmd, '-d', 'get-src', 'ls', 'src'))
896 save_2 = exr.out.splitlines()[2]
897 rename('src', 'src-2')
899 src_root = getcwd() + '/src'
901 subtree_path = 'src-2/x'
902 subtree_vfs_path = src_root + '/x'
904 # No support for "ls -d", so grep...
905 exr = exo((bup_cmd, '-d', 'get-src', 'ls', '-s', 'src/latest' + src_root))
906 out = exr.out.splitlines()
910 subtree_id = line.split()[0]
913 # With a tiny file, we'll get a single blob, not a chunked tree
914 tinyfile_path = src_root + '/tiny-file'
915 exr = exo((bup_cmd, '-d', 'get-src', 'ls', '-s', 'src/latest' + tinyfile_path))
916 tinyfile_id = exr.out.splitlines()[0].split()[0]
918 ex((bup_cmd, '-d', 'get-src', 'tag', 'tinyfile', tinyfile_id))
919 ex((bup_cmd, '-d', 'get-src', 'tag', 'subtree', subtree_id))
920 ex((bup_cmd, '-d', 'get-src', 'tag', 'tree-0', tree_0_id))
921 ex((bup_cmd, '-d', 'get-src', 'tag', 'tree-1', tree_1_id))
922 ex((bup_cmd, '-d', 'get-src', 'tag', 'tree-2', tree_2_id))
923 ex((bup_cmd, '-d', 'get-src', 'tag', 'commit-0', commit_0_id))
924 ex((bup_cmd, '-d', 'get-src', 'tag', 'commit-1', commit_1_id))
925 ex((bup_cmd, '-d', 'get-src', 'tag', 'commit-2', commit_2_id))
926 ex(('git', '--git-dir', 'get-src', 'branch', 'commit-1', commit_1_id))
927 ex(('git', '--git-dir', 'get-src', 'branch', 'commit-2', commit_2_id))
929 return {'tinyfile-path' : tinyfile_path,
930 'tinyfile-id' : tinyfile_id,
931 'subtree-id' : subtree_id,
932 'tree-0-id' : tree_0_id,
933 'tree-1-id' : tree_1_id,
934 'tree-2-id' : tree_2_id,
935 'commit-0-id' : commit_0_id,
936 'commit-1-id' : commit_1_id,
937 'commit-2-id' : commit_2_id,
940 'subtree-path' : subtree_path,
941 'subtree-vfs-path' : subtree_vfs_path}
943 # FIXME: this fails in a strange way:
944 # WVPASS given nothing get --ff not-there
946 dispositions_to_test = ('get',)
948 if int(environ.get('BUP_TEST_LEVEL', '0')) >= 11:
949 dispositions_to_test += ('get-on', 'get-to')
951 if len(sys.argv) == 1:
952 categories = ('replace', 'universal', 'ff', 'append', 'pick', 'new-tag',
955 categories = sys.argv[1:]
957 with test_tempdir('get-') as tmpdir:
960 src_info = create_get_src()
961 for category in categories:
962 for disposition in dispositions_to_test:
963 # given=FOO depends on --replace, so test it early
964 if category == 'replace':
965 test_replace(disposition, src_info)
966 elif category == 'universal':
967 test_universal_behaviors(disposition)
968 elif category == 'ff':
969 test_ff(disposition, src_info)
970 elif category == 'append':
971 test_append(disposition, src_info)
972 elif category == 'pick':
973 test_pick(disposition, src_info, force=False)
974 test_pick(disposition, src_info, force=True)
975 elif category == 'new-tag':
976 test_new_tag(disposition, src_info)
977 elif category == 'unnamed':
978 test_unnamed(disposition, src_info)
980 raise Exception('unrecognized get test category')
981 except Exception, ex:
986 wvmsg('checked %d cases' % get_cases_tested)