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 bup.helpers import unlink
22 from buptest import ex, exo, test_tempdir
23 from wvtest import wvcheck, wvfail, wvmsg, wvpass, wvpasseq, wvpassne, wvstart
25 # FIXME: per-test function
26 environ['GIT_AUTHOR_NAME'] = 'bup test-get'
27 environ['GIT_COMMITTER_NAME'] = 'bup test-get'
28 environ['GIT_AUTHOR_EMAIL'] = 'bup@85430dcca2b611e4b2c3-8f5691723476'
29 environ['GIT_COMMITTER_EMAIL'] = 'bup@85430dcca2b611e4b2c3-8f5691723476'
31 # The clean-repo test can probably be applied more broadly. It was
32 # initially just applied to test-pick to catch a bug.
35 bup_cmd = top + '/bup'
38 err = [] # because python's scoping mess...
39 def onerror(function, path, excinfo):
40 err.append((function, path, excinfo))
41 rmtree(path, onerror=onerror)
43 function, path, excinfo = err[0]
44 ex_type, ex, traceback = excinfo
45 if (not isinstance(ex, OSError)) or ex.errno != ENOENT:
48 def verify_trees_match(path1, path2):
50 exr = exo((top + '/t/compare-trees', '-c', path1, path2), check=False)
53 wvcheck(exr.rc == 0, 'process exit %d == 0' % exr.rc)
55 def verify_rcz(cmd, **kwargs):
56 assert not kwargs.get('check')
57 kwargs['check'] = False
58 result = exo(cmd, **kwargs)
60 rc = result.proc.returncode
61 wvcheck(rc == 0, 'process exit %d == 0' % rc)
64 # FIXME: multline, or allow opts generally?
66 def verify_rx(rx, string):
67 wvcheck(re.search(rx, string), 'rx %r matches %r' % (rx, string))
69 def verify_nrx(rx, string):
70 wvcheck(not re.search(rx, string), "rx %r doesn't match %r" % (rx, string))
72 def validate_clean_repo():
73 out = verify_rcz(('git', '--git-dir', 'get-dest', 'fsck')).out
74 verify_nrx(r'dangling|mismatch|missing|unreachable', out)
76 def validate_blob(src_id, dest_id):
80 cat_tree = top + '/t/git-cat-tree'
81 src_blob = verify_rcz((cat_tree, '--git-dir', 'get-src', src_id)).out
82 dest_blob = verify_rcz((cat_tree, '--git-dir', 'get-src', src_id)).out
83 wvpasseq(src_blob, dest_blob)
85 def validate_tree(src_id, dest_id):
87 def set_committer_date():
88 environ['GIT_COMMITTER_DATE'] = "2014-01-01 01:01"
95 # Create a commit so the archive contents will have matching timestamps.
96 src_c = exo(('git', '--git-dir', 'get-src',
97 'commit-tree', '-m', 'foo', src_id),
98 preexec_fn=set_committer_date).out.strip()
99 dest_c = exo(('git', '--git-dir', 'get-dest',
100 'commit-tree', '-m', 'foo', dest_id),
101 preexec_fn=set_committer_date).out.strip()
102 exr = verify_rcz('git --git-dir get-src archive %s | tar xvf - -C restore-src'
105 if exr.rc != 0: return False
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 unlink('restore-src/pax_global_header')
113 unlink('restore-dest/pax_global_header')
114 ex(('touch', '-r', 'restore-src', 'restore-dest'))
115 verify_trees_match('restore-src/', 'restore-dest/')
119 def validate_commit(src_id, dest_id):
120 exr = verify_rcz(('git', '--git-dir', 'get-src', 'cat-file', 'commit', src_id))
121 if exr.rc != 0: return False
123 exr = verify_rcz(('git', '--git-dir', 'get-dest', 'cat-file', 'commit', dest_id))
124 if exr.rc != 0: return False
126 wvpasseq(src_cat, dest_cat)
127 if src_cat != dest_cat: return False
132 mkdir('restore-dest')
134 qdest = quote(dest_id)
135 exr = verify_rcz(('git --git-dir get-src archive ' + qsrc
136 + ' | tar xf - -C restore-src'),
138 if exr.rc != 0: return False
139 exr = verify_rcz(('git --git-dir get-dest archive ' + qdest +
140 ' | tar xf - -C restore-dest'),
142 if exr.rc != 0: return False
144 # git archive doesn't include an entry for ./.
145 ex(('touch', '-r', 'restore-src', 'restore-dest'))
146 verify_trees_match('restore-src/', 'restore-dest/')
150 def _validate_save(orig_dir, save_path, commit_id, tree_id):
153 exr = verify_rcz((bup_cmd, '-d', 'get-dest',
154 'restore', '-C', 'restore', save_path + '/.'))
155 if exr.rc: return False
156 verify_trees_match(orig_dir + '/', 'restore/')
158 # FIXME: double check that get-dest is correct
159 exr = verify_rcz(('git', '--git-dir', 'get-dest', 'ls-tree', tree_id))
160 if exr.rc: return False
161 cat = verify_rcz(('git', '--git-dir', 'get-dest',
162 'cat-file', 'commit', commit_id))
163 if cat.rc: return False
164 wvpasseq('tree ' + tree_id, cat.out.splitlines()[0])
166 # FIXME: re-merge save and new_save?
168 def validate_save(dest_name, restore_subpath, commit_id, tree_id, orig_value,
170 out = get_out.splitlines()
171 wvpasseq(2, len(out))
173 get_commit_id = out[1]
174 wvpasseq(tree_id, get_tree_id)
175 wvpasseq(commit_id, get_commit_id)
176 _validate_save(orig_value, dest_name + restore_subpath, commit_id, tree_id)
178 def validate_new_save(dest_name, restore_subpath, commit_id, tree_id, orig_value,
180 out = get_out.splitlines()
181 wvpasseq(2, len(out))
183 get_commit_id = out[1]
184 wvpasseq(tree_id, get_tree_id)
185 wvpassne(commit_id, get_commit_id)
186 _validate_save(orig_value, dest_name + restore_subpath, get_commit_id, tree_id)
188 def validate_tagged_save(tag_name, restore_subpath,
189 commit_id, tree_id, orig_value, get_out):
190 out = get_out.splitlines()
191 wvpasseq(1, len(out))
193 wvpasseq(commit_id, get_tag_id)
194 # Make sure tmp doesn't already exist.
195 exr = exo(('git', '--git-dir', 'get-dest', 'show-ref', 'tmp-branch-for-tag'),
199 ex(('git', '--git-dir', 'get-dest', 'branch', 'tmp-branch-for-tag',
200 'refs/tags/' + tag_name))
201 _validate_save(orig_value, 'tmp-branch-for-tag/latest' + restore_subpath,
203 ex(('git', '--git-dir', 'get-dest', 'branch', '-D', 'tmp-branch-for-tag'))
205 def validate_new_tagged_commit(tag_name, commit_id, tree_id, get_out):
206 out = get_out.splitlines()
207 wvpasseq(1, len(out))
209 wvpassne(commit_id, get_tag_id)
210 validate_tree(tree_id, tag_name + ':')
216 def _run_get(disposition, method, what):
219 if disposition == 'get':
220 get_cmd = (bup_cmd, '-d', 'get-dest',
221 'get', '-vvct', '--print-tags', '-s', 'get-src')
222 elif disposition == 'get-on':
223 get_cmd = (bup_cmd, '-d', 'get-dest',
224 'on', '-', 'get', '-vvct', '--print-tags', '-s', 'get-src')
225 elif disposition == 'get-to':
226 get_cmd = (bup_cmd, '-d', 'get-dest',
227 'get', '-vvct', '--print-tags', '-s', 'get-src',
228 '-r', '-:' + getcwd() + '/get-dest')
230 raise Exception('error: unexpected get disposition ' + disposition)
232 global get_cases_tested
233 if isinstance(what, compat.str_type):
234 cmd = get_cmd + (method, what)
236 if method in ('--ff', '--append', '--pick', '--force-pick', '--new-tag',
240 cmd = get_cmd + (method, src, dest)
241 result = exo(cmd, check=False, stderr=PIPE)
242 get_cases_tested += 1
243 fsck = ex((bup_cmd, '-d', 'get-dest', 'fsck'), check=False)
247 def run_get(disposition, method, what=None, given=None):
250 ex((bup_cmd, '-d', 'get-dest', 'init'))
253 # FIXME: replace bup-get with independent commands as is feasible
254 exr = _run_get(disposition, '--replace', given)
256 return _run_get(disposition, method, what)
258 def test_universal_behaviors(get_disposition):
259 methods = ('--ff', '--append', '--pick', '--force-pick', '--new-tag',
260 '--replace', '--unnamed')
261 for method in methods:
262 wvstart(get_disposition + ' ' + method + ', missing source, fails')
263 exr = run_get(get_disposition, method, 'not-there')
265 verify_rx(r'cannot find source', exr.err)
266 for method in methods:
267 wvstart(get_disposition + ' ' + method + ' / fails')
268 exr = run_get(get_disposition, method, '/')
270 verify_rx('cannot fetch entire repository', exr.err)
272 def verify_only_refs(**kwargs):
273 for kind, refs in kwargs.iteritems():
275 abs_refs = ['refs/heads/' + ref for ref in refs]
278 abs_refs = ['refs/tags/' + ref for ref in refs]
281 raise TypeError('unexpected keyword argument %r' % kind)
283 verify_rcz(['git', '--git-dir', 'get-dest',
284 'show-ref', '--verify', karg] + abs_refs)
285 exr = exo(('git', '--git-dir', 'get-dest', 'show-ref', karg),
288 expected_refs = sorted(abs_refs)
289 repo_refs = sorted([x.split()[1] for x in exr.out.splitlines()])
290 wvpasseq(expected_refs, repo_refs)
292 # FIXME: can we just check "git show-ref --heads == ''"?
293 exr = exo(('git', '--git-dir', 'get-dest', 'show-ref', karg),
296 wvpasseq('', exr.out.strip())
298 def test_replace(get_disposition, src_info):
300 wvstart(get_disposition + ' --replace to root fails')
301 for item in ('.tag/tinyfile',
302 'src/latest' + src_info['tinyfile-path'],
304 'src/latest' + src_info['subtree-vfs-path'],
308 exr = run_get(get_disposition, '--replace', (item, '/'))
310 verify_rx(r'impossible; can only overwrite branch or tag', exr.err)
312 tinyfile_id = src_info['tinyfile-id']
313 tinyfile_path = src_info['tinyfile-path']
314 subtree_vfs_path = src_info['subtree-vfs-path']
315 subtree_id = src_info['subtree-id']
316 commit_2_id = src_info['commit-2-id']
317 tree_2_id = src_info['tree-2-id']
320 existing_items = {'nothing' : None,
321 'blob' : ('.tag/tinyfile', '.tag/obj'),
322 'tree' : ('.tag/tree-1', '.tag/obj'),
323 'commit': ('.tag/commit-1', '.tag/obj')}
324 for ex_type, ex_ref in existing_items.iteritems():
325 wvstart(get_disposition + ' --replace ' + ex_type + ' with blob tag')
326 for item in ('.tag/tinyfile', 'src/latest' + tinyfile_path):
327 exr = run_get(get_disposition, '--replace', (item ,'.tag/obj'),
330 validate_blob(tinyfile_id, tinyfile_id)
331 verify_only_refs(heads=[], tags=('obj',))
332 wvstart(get_disposition + ' --replace ' + ex_type + ' with tree tag')
333 for item in ('.tag/subtree', 'src/latest' + subtree_vfs_path):
334 exr = run_get(get_disposition, '--replace', (item, '.tag/obj'),
336 validate_tree(subtree_id, subtree_id)
337 verify_only_refs(heads=[], tags=('obj',))
338 wvstart(get_disposition + ' --replace ' + ex_type + ' with commitish tag')
339 for item in ('.tag/commit-2', 'src/latest', 'src'):
340 exr = run_get(get_disposition, '--replace', (item, '.tag/obj'),
342 validate_tagged_save('obj', getcwd() + '/src',
343 commit_2_id, tree_2_id, 'src-2', exr.out)
344 verify_only_refs(heads=[], tags=('obj',))
346 # Committish to branch.
347 existing_items = (('nothing', None),
348 ('branch', ('.tag/commit-1', 'obj')))
349 for ex_type, ex_ref in existing_items:
350 for item_type, item in (('commit', '.tag/commit-2'),
351 ('save', 'src/latest'),
353 wvstart(get_disposition + ' --replace '
354 + ex_type + ' with ' + item_type)
355 exr = run_get(get_disposition, '--replace', (item, 'obj'),
357 validate_save('obj/latest', getcwd() + '/src',
358 commit_2_id, tree_2_id, 'src-2', exr.out)
359 verify_only_refs(heads=('obj',), tags=[])
361 # Not committish to branch
362 existing_items = (('nothing', None),
363 ('branch', ('.tag/commit-1', 'obj')))
364 for ex_type, ex_ref in existing_items:
365 for item_type, item in (('blob', '.tag/tinyfile'),
366 ('blob', 'src/latest' + tinyfile_path),
367 ('tree', '.tag/subtree'),
368 ('tree', 'src/latest' + subtree_vfs_path)):
369 wvstart(get_disposition + ' --replace branch with '
370 + item_type + ' given ' + ex_type + ' fails')
372 exr = run_get(get_disposition, '--replace', (item, 'obj'),
375 verify_rx(r'cannot overwrite branch with .+ for', exr.err)
377 wvstart(get_disposition + ' --replace, implicit destinations')
379 exr = run_get(get_disposition, '--replace', 'src')
380 validate_save('src/latest', getcwd() + '/src',
381 commit_2_id, tree_2_id, 'src-2', exr.out)
382 verify_only_refs(heads=('src',), tags=[])
384 exr = run_get(get_disposition, '--replace', '.tag/commit-2')
385 validate_tagged_save('commit-2', getcwd() + '/src',
386 commit_2_id, tree_2_id, 'src-2', exr.out)
387 verify_only_refs(heads=[], tags=('commit-2',))
389 def test_ff(get_disposition, src_info):
391 wvstart(get_disposition + ' --ff to root fails')
392 tinyfile_path = src_info['tinyfile-path']
393 for item in ('.tag/tinyfile', 'src/latest' + tinyfile_path):
394 exr = run_get(get_disposition, '--ff', (item, '/'))
396 verify_rx(r'source for .+ must be a branch, save, or commit', exr.err)
397 subtree_vfs_path = src_info['subtree-vfs-path']
398 for item in ('.tag/subtree', 'src/latest' + subtree_vfs_path):
399 exr = run_get(get_disposition, '--ff', (item, '/'))
401 verify_rx(r'is impossible; can only --append a tree to a branch',
403 for item in ('.tag/commit-1', 'src/latest', 'src'):
404 exr = run_get(get_disposition, '--ff', (item, '/'))
406 verify_rx(r'destination for .+ is a root, not a branch', exr.err)
408 wvstart(get_disposition + ' --ff of not-committish fails')
409 for src in ('.tag/tinyfile', 'src/latest' + tinyfile_path):
410 # FIXME: use get_item elsewhere?
411 for given, get_item in ((None, (src, 'obj')),
412 (None, (src, '.tag/obj')),
413 (('.tag/tinyfile', '.tag/obj'), (src, '.tag/obj')),
414 (('.tag/tree-1', '.tag/obj'), (src, '.tag/obj')),
415 (('.tag/commit-1', '.tag/obj'), (src, '.tag/obj')),
416 (('.tag/commit-1', 'obj'), (src, 'obj'))):
417 exr = run_get(get_disposition, '--ff', get_item, given=given)
419 verify_rx(r'must be a branch, save, or commit', exr.err)
420 for src in ('.tag/subtree', 'src/latest' + subtree_vfs_path):
421 for given, get_item in ((None, (src, 'obj')),
422 (None, (src, '.tag/obj')),
423 (('.tag/tinyfile', '.tag/obj'), (src, '.tag/obj')),
424 (('.tag/tree-1', '.tag/obj'), (src, '.tag/obj')),
425 (('.tag/commit-1', '.tag/obj'), (src, '.tag/obj')),
426 (('.tag/commit-1', 'obj'), (src, 'obj'))):
427 exr = run_get(get_disposition, '--ff', get_item, given=given)
429 verify_rx(r'can only --append a tree to a branch', exr.err)
431 wvstart(get_disposition + ' --ff committish, ff possible')
432 save_2 = src_info['save-2']
433 for src in ('.tag/commit-2', 'src/' + save_2, 'src'):
434 for given, get_item, complaint in \
435 ((None, (src, '.tag/obj'),
436 r'destination .+ must be a valid branch name'),
437 (('.tag/tinyfile', '.tag/obj'), (src, '.tag/obj'),
438 r'destination .+ is a blob, not a branch'),
439 (('.tag/tree-1', '.tag/obj'), (src, '.tag/obj'),
440 r'destination .+ is a tree, not a branch'),
441 (('.tag/commit-1', '.tag/obj'), (src, '.tag/obj'),
442 r'destination .+ is a tagged commit, not a branch'),
443 (('.tag/commit-2', '.tag/obj'), (src, '.tag/obj'),
444 r'destination .+ is a tagged commit, not a branch')):
445 exr = run_get(get_disposition, '--ff', get_item, given=given)
447 verify_rx(complaint, exr.err)
448 # FIXME: use src or item and given or existing consistently in loops...
449 commit_2_id = src_info['commit-2-id']
450 tree_2_id = src_info['tree-2-id']
451 for src in ('.tag/commit-2', 'src/' + save_2, 'src'):
452 for given in (None, ('.tag/commit-1', 'obj'), ('.tag/commit-2', 'obj')):
453 exr = run_get(get_disposition, '--ff', (src, 'obj'), given=given)
455 validate_save('obj/latest', getcwd() + '/src',
456 commit_2_id, tree_2_id, 'src-2', exr.out)
457 verify_only_refs(heads=('obj',), tags=[])
459 wvstart(get_disposition + ' --ff, implicit destinations')
460 for item in ('src', 'src/latest'):
461 exr = run_get(get_disposition, '--ff', item)
464 ex(('find', 'get-dest/refs'))
465 ex((bup_cmd, '-d', 'get-dest', 'ls'))
467 validate_save('src/latest', getcwd() + '/src',
468 commit_2_id, tree_2_id, 'src-2', exr.out)
469 #verify_only_refs(heads=('src',), tags=[])
471 wvstart(get_disposition + ' --ff, ff impossible')
472 for given, get_item in ((('unrelated-branch', 'src'), 'src'),
473 (('.tag/commit-2', 'src'), ('.tag/commit-1', 'src'))):
474 exr = run_get(get_disposition, '--ff', get_item, given=given)
476 verify_rx(r'destination is not an ancestor of source', exr.err)
478 def test_append(get_disposition, src_info):
479 tinyfile_path = src_info['tinyfile-path']
480 subtree_vfs_path = src_info['subtree-vfs-path']
482 wvstart(get_disposition + ' --append to root fails')
483 for item in ('.tag/tinyfile', 'src/latest' + tinyfile_path):
484 exr = run_get(get_disposition, '--append', (item, '/'))
486 verify_rx(r'source for .+ must be a branch, save, commit, or tree',
488 for item in ('.tag/subtree', 'src/latest' + subtree_vfs_path,
489 '.tag/commit-1', 'src/latest', 'src'):
490 exr = run_get(get_disposition, '--append', (item, '/'))
492 verify_rx(r'destination for .+ is a root, not a branch', exr.err)
494 wvstart(get_disposition + ' --append of not-treeish fails')
495 for src in ('.tag/tinyfile', 'src/latest' + tinyfile_path):
496 for given, item in ((None, (src, 'obj')),
497 (None, (src, '.tag/obj')),
498 (('.tag/tinyfile', '.tag/obj'), (src, '.tag/obj')),
499 (('.tag/tree-1', '.tag/obj'), (src, '.tag/obj')),
500 (('.tag/commit-1', '.tag/obj'), (src, '.tag/obj')),
501 (('.tag/commit-1', 'obj'), (src, 'obj'))):
502 exr = run_get(get_disposition, '--append', item, given=given)
504 verify_rx(r'must be a branch, save, commit, or tree', exr.err)
506 wvstart(get_disposition + ' --append committish failure cases')
507 save_2 = src_info['save-2']
508 for src in ('.tag/subtree', 'src/latest' + subtree_vfs_path,
509 '.tag/commit-2', 'src/' + save_2, 'src'):
510 for given, item, complaint in \
511 ((None, (src, '.tag/obj'),
512 r'destination .+ must be a valid branch name'),
513 (('.tag/tinyfile', '.tag/obj'), (src, '.tag/obj'),
514 r'destination .+ is a blob, not a branch'),
515 (('.tag/tree-1', '.tag/obj'), (src, '.tag/obj'),
516 r'destination .+ is a tree, not a branch'),
517 (('.tag/commit-1', '.tag/obj'), (src, '.tag/obj'),
518 r'destination .+ is a tagged commit, not a branch'),
519 (('.tag/commit-2', '.tag/obj'), (src, '.tag/obj'),
520 r'destination .+ is a tagged commit, not a branch')):
521 exr = run_get(get_disposition, '--append', item, given=given)
523 verify_rx(complaint, exr.err)
525 wvstart(get_disposition + ' --append committish')
526 commit_2_id = src_info['commit-2-id']
527 tree_2_id = src_info['tree-2-id']
528 for item in ('.tag/commit-2', 'src/' + save_2, 'src'):
529 for existing in (None, ('.tag/commit-1', 'obj'),
530 ('.tag/commit-2', 'obj'),
531 ('unrelated-branch', 'obj')):
532 exr = run_get(get_disposition, '--append', (item, 'obj'),
535 validate_new_save('obj/latest', getcwd() + '/src',
536 commit_2_id, tree_2_id, 'src-2', exr.out)
537 verify_only_refs(heads=('obj',), tags=[])
539 save_1 = src_info['save-1']
540 commit_1_id = src_info['commit-1-id']
541 tree_1_id = src_info['tree-1-id']
542 for item in ('.tag/commit-1', 'src/' + save_1, 'src-1'):
543 exr = run_get(get_disposition, '--append', (item, 'obj'),
544 given=('.tag/commit-2', 'obj'))
546 validate_new_save('obj/latest', getcwd() + '/src',
547 commit_1_id, tree_1_id, 'src-1', exr.out)
548 verify_only_refs(heads=('obj',), tags=[])
550 wvstart(get_disposition + ' --append tree')
551 subtree_path = src_info['subtree-path']
552 subtree_id = src_info['subtree-id']
553 for item in ('.tag/subtree', 'src/latest' + subtree_vfs_path):
554 for existing in (None, ('.tag/commit-1', 'obj'), ('.tag/commit-2','obj')):
555 exr = run_get(get_disposition, '--append', (item, 'obj'),
558 validate_new_save('obj/latest', '/', None, subtree_id, subtree_path,
560 verify_only_refs(heads=('obj',), tags=[])
562 wvstart(get_disposition + ' --append, implicit destinations')
564 for item in ('src', 'src/latest'):
565 exr = run_get(get_disposition, '--append', item)
567 validate_new_save('src/latest', getcwd() + '/src', commit_2_id, tree_2_id,
569 verify_only_refs(heads=('src',), tags=[])
571 def test_pick(get_disposition, src_info, force=False):
572 flavor = '--force-pick' if force else '--pick'
573 tinyfile_path = src_info['tinyfile-path']
574 subtree_vfs_path = src_info['subtree-vfs-path']
576 wvstart(get_disposition + ' ' + flavor + ' to root fails')
577 for item in ('.tag/tinyfile', 'src/latest' + tinyfile_path, 'src'):
578 exr = run_get(get_disposition, flavor, (item, '/'))
580 verify_rx(r'can only pick a commit or save', exr.err)
581 for item in ('.tag/commit-1', 'src/latest'):
582 exr = run_get(get_disposition, flavor, (item, '/'))
584 verify_rx(r'destination is not a tag or branch', exr.err)
585 for item in ('.tag/subtree', 'src/latest' + subtree_vfs_path):
586 exr = run_get(get_disposition, flavor, (item, '/'))
588 verify_rx(r'is impossible; can only --append a tree', exr.err)
590 wvstart(get_disposition + ' ' + flavor + ' of blob or branch fails')
591 for item in ('.tag/tinyfile', 'src/latest' + tinyfile_path, 'src'):
592 for given, get_item in ((None, (item, 'obj')),
593 (None, (item, '.tag/obj')),
594 (('.tag/tinyfile', '.tag/obj'), (item, '.tag/obj')),
595 (('.tag/tree-1', '.tag/obj'), (item, '.tag/obj')),
596 (('.tag/commit-1', '.tag/obj'), (item, '.tag/obj')),
597 (('.tag/commit-1', 'obj'), (item, 'obj'))):
598 exr = run_get(get_disposition, flavor, get_item, given=given)
600 verify_rx(r'impossible; can only pick a commit or save', exr.err)
602 wvstart(get_disposition + ' ' + flavor + ' of tree fails')
603 for item in ('.tag/subtree', 'src/latest' + subtree_vfs_path):
604 for given, get_item in ((None, (item, 'obj')),
605 (None, (item, '.tag/obj')),
606 (('.tag/tinyfile', '.tag/obj'), (item, '.tag/obj')),
607 (('.tag/tree-1', '.tag/obj'), (item, '.tag/obj')),
608 (('.tag/commit-1', '.tag/obj'), (item, '.tag/obj')),
609 (('.tag/commit-1', 'obj'), (item, 'obj'))):
610 exr = run_get(get_disposition, flavor, get_item, given=given)
612 verify_rx(r'impossible; can only --append a tree', exr.err)
614 save_2 = src_info['save-2']
615 commit_2_id = src_info['commit-2-id']
616 tree_2_id = src_info['tree-2-id']
617 # FIXME: these two wvstart texts?
619 wvstart(get_disposition + ' ' + flavor + ' commit/save to existing tag')
620 for item in ('.tag/commit-2', 'src/' + save_2):
621 for given in (('.tag/tinyfile', '.tag/obj'),
622 ('.tag/tree-1', '.tag/obj'),
623 ('.tag/commit-1', '.tag/obj')):
624 exr = run_get(get_disposition, flavor, (item, '.tag/obj'),
627 validate_new_tagged_commit('obj', commit_2_id, tree_2_id,
629 verify_only_refs(heads=[], tags=('obj',))
631 wvstart(get_disposition + ' ' + flavor
632 + ' commit/save to existing tag fails')
633 for item in ('.tag/commit-2', 'src/' + save_2):
634 for given in (('.tag/tinyfile', '.tag/obj'),
635 ('.tag/tree-1', '.tag/obj'),
636 ('.tag/commit-1', '.tag/obj')):
637 exr = run_get(get_disposition, flavor, (item, '.tag/obj'), given=given)
639 verify_rx(r'cannot overwrite existing tag', exr.err)
641 wvstart(get_disposition + ' ' + flavor + ' commit/save to tag')
642 for item in ('.tag/commit-2', 'src/' + save_2):
643 exr = run_get(get_disposition, flavor, (item, '.tag/obj'))
645 validate_clean_repo()
646 validate_new_tagged_commit('obj', commit_2_id, tree_2_id, exr.out)
647 verify_only_refs(heads=[], tags=('obj',))
649 wvstart(get_disposition + ' ' + flavor + ' commit/save to branch')
650 for item in ('.tag/commit-2', 'src/' + save_2):
651 for given in (None, ('.tag/commit-1', 'obj'), ('.tag/commit-2', 'obj')):
652 exr = run_get(get_disposition, flavor, (item, 'obj'), given=given)
654 validate_clean_repo()
655 validate_new_save('obj/latest', getcwd() + '/src',
656 commit_2_id, tree_2_id, 'src-2', exr.out)
657 verify_only_refs(heads=('obj',), tags=[])
659 wvstart(get_disposition + ' ' + flavor
660 + ' commit/save unrelated commit to branch')
661 for item in('.tag/commit-2', 'src/' + save_2):
662 exr = run_get(get_disposition, flavor, (item, 'obj'),
663 given=('unrelated-branch', 'obj'))
665 validate_clean_repo()
666 validate_new_save('obj/latest', getcwd() + '/src',
667 commit_2_id, tree_2_id, 'src-2', exr.out)
668 verify_only_refs(heads=('obj',), tags=[])
670 wvstart(get_disposition + ' ' + flavor + ' commit/save ancestor to branch')
671 save_1 = src_info['save-1']
672 commit_1_id = src_info['commit-1-id']
673 tree_1_id = src_info['tree-1-id']
674 for item in ('.tag/commit-1', 'src/' + save_1):
675 exr = run_get(get_disposition, flavor, (item, 'obj'),
676 given=('.tag/commit-2', 'obj'))
678 validate_clean_repo()
679 validate_new_save('obj/latest', getcwd() + '/src',
680 commit_1_id, tree_1_id, 'src-1', exr.out)
681 verify_only_refs(heads=('obj',), tags=[])
684 wvstart(get_disposition + ' ' + flavor + ', implicit destinations')
685 exr = run_get(get_disposition, flavor, '.tag/commit-2')
687 validate_clean_repo()
688 validate_new_tagged_commit('commit-2', commit_2_id, tree_2_id, exr.out)
689 verify_only_refs(heads=[], tags=('commit-2',))
691 exr = run_get(get_disposition, flavor, 'src/latest')
693 validate_clean_repo()
694 validate_new_save('src/latest', getcwd() + '/src',
695 commit_2_id, tree_2_id, 'src-2', exr.out)
696 verify_only_refs(heads=('src',), tags=[])
698 def test_new_tag(get_disposition, src_info):
699 tinyfile_id = src_info['tinyfile-id']
700 tinyfile_path = src_info['tinyfile-path']
701 commit_2_id = src_info['commit-2-id']
702 tree_2_id = src_info['tree-2-id']
703 subtree_id = src_info['subtree-id']
704 subtree_vfs_path = src_info['subtree-vfs-path']
706 wvstart(get_disposition + ' --new-tag to root fails')
707 for item in ('.tag/tinyfile',
708 'src/latest' + tinyfile_path,
710 'src/latest' + subtree_vfs_path,
714 exr = run_get(get_disposition, '--new-tag', (item, '/'))
716 verify_rx(r'destination for .+ must be a VFS tag', exr.err)
718 # Anything to new tag.
719 wvstart(get_disposition + ' --new-tag, blob tag')
720 for item in ('.tag/tinyfile', 'src/latest' + tinyfile_path):
721 exr = run_get(get_disposition, '--new-tag', (item, '.tag/obj'))
723 validate_blob(tinyfile_id, tinyfile_id)
724 verify_only_refs(heads=[], tags=('obj',))
726 wvstart(get_disposition + ' --new-tag, tree tag')
727 for item in ('.tag/subtree', 'src/latest' + subtree_vfs_path):
728 exr = run_get(get_disposition, '--new-tag', (item, '.tag/obj'))
730 validate_tree(subtree_id, subtree_id)
731 verify_only_refs(heads=[], tags=('obj',))
733 wvstart(get_disposition + ' --new-tag, committish tag')
734 for item in ('.tag/commit-2', 'src/latest', 'src'):
735 exr = run_get(get_disposition, '--new-tag', (item, '.tag/obj'))
737 validate_tagged_save('obj', getcwd() + '/src/', commit_2_id, tree_2_id,
739 verify_only_refs(heads=[], tags=('obj',))
741 # Anything to existing tag (fails).
742 for ex_type, ex_tag in (('blob', ('.tag/tinyfile', '.tag/obj')),
743 ('tree', ('.tag/tree-1', '.tag/obj')),
744 ('commit', ('.tag/commit-1', '.tag/obj'))):
745 for item_type, item in (('blob tag', '.tag/tinyfile'),
746 ('blob path', 'src/latest' + tinyfile_path),
747 ('tree tag', '.tag/subtree'),
748 ('tree path', 'src/latest' + subtree_vfs_path),
749 ('commit tag', '.tag/commit-2'),
750 ('save', 'src/latest'),
752 wvstart(get_disposition + ' --new-tag of ' + item_type
753 + ', given existing ' + ex_type + ' tag, fails')
754 exr = run_get(get_disposition, '--new-tag', (item, '.tag/obj'),
757 verify_rx(r'cannot overwrite existing tag .* \(requires --replace\)',
760 # Anything to branch (fails).
761 for ex_type, ex_tag in (('nothing', None),
762 ('blob', ('.tag/tinyfile', '.tag/obj')),
763 ('tree', ('.tag/tree-1', '.tag/obj')),
764 ('commit', ('.tag/commit-1', '.tag/obj'))):
765 for item_type, item in (('blob tag', '.tag/tinyfile'),
766 ('blob path', 'src/latest' + tinyfile_path),
767 ('tree tag', '.tag/subtree'),
768 ('tree path', 'src/latest' + subtree_vfs_path),
769 ('commit tag', '.tag/commit-2'),
770 ('save', 'src/latest'),
772 wvstart(get_disposition + ' --new-tag to branch of ' + item_type
773 + ', given existing ' + ex_type + ' tag, fails')
774 exr = run_get(get_disposition, '--new-tag', (item, 'obj'),
777 verify_rx(r'destination for .+ must be a VFS tag', exr.err)
779 wvstart(get_disposition + ' --new-tag, implicit destinations')
780 exr = run_get(get_disposition, '--new-tag', '.tag/commit-2')
782 validate_tagged_save('commit-2', getcwd() + '/src/', commit_2_id, tree_2_id,
784 verify_only_refs(heads=[], tags=('commit-2',))
786 def test_unnamed(get_disposition, src_info):
787 tinyfile_id = src_info['tinyfile-id']
788 tinyfile_path = src_info['tinyfile-path']
789 subtree_vfs_path = src_info['subtree-vfs-path']
790 wvstart(get_disposition + ' --unnamed to root fails')
791 for item in ('.tag/tinyfile',
792 'src/latest' + tinyfile_path,
794 'src/latest' + subtree_vfs_path,
798 for ex_ref in (None, (item, '.tag/obj')):
799 exr = run_get(get_disposition, '--unnamed', (item, '/'),
802 verify_rx(r'usage: bup get ', exr.err)
804 wvstart(get_disposition + ' --unnamed file')
805 for item in ('.tag/tinyfile', 'src/latest' + tinyfile_path):
806 exr = run_get(get_disposition, '--unnamed', item)
808 validate_blob(tinyfile_id, tinyfile_id)
809 verify_only_refs(heads=[], tags=[])
811 exr = run_get(get_disposition, '--unnamed', item,
812 given=(item, '.tag/obj'))
814 validate_blob(tinyfile_id, tinyfile_id)
815 verify_only_refs(heads=[], tags=('obj',))
817 wvstart(get_disposition + ' --unnamed tree')
818 subtree_id = src_info['subtree-id']
819 for item in ('.tag/subtree', 'src/latest' + subtree_vfs_path):
820 exr = run_get(get_disposition, '--unnamed', item)
822 validate_tree(subtree_id, subtree_id)
823 verify_only_refs(heads=[], tags=[])
825 exr = run_get(get_disposition, '--unnamed', item,
826 given=(item, '.tag/obj'))
828 validate_tree(subtree_id, subtree_id)
829 verify_only_refs(heads=[], tags=('obj',))
831 wvstart(get_disposition + ' --unnamed committish')
832 save_2 = src_info['save-2']
833 commit_2_id = src_info['commit-2-id']
834 for item in ('.tag/commit-2', 'src/' + save_2, 'src'):
835 exr = run_get(get_disposition, '--unnamed', item)
837 validate_commit(commit_2_id, commit_2_id)
838 verify_only_refs(heads=[], tags=[])
840 exr = run_get(get_disposition, '--unnamed', item,
841 given=(item, '.tag/obj'))
843 validate_commit(commit_2_id, commit_2_id)
844 verify_only_refs(heads=[], tags=('obj',))
846 def create_get_src():
847 global bup_cmd, src_info
849 ex((bup_cmd, '-d', 'get-src', 'init'))
852 open('src/unrelated', 'a').close()
853 ex((bup_cmd, '-d', 'get-src', 'index', 'src'))
854 ex((bup_cmd, '-d', 'get-src', 'save', '-tcn', 'unrelated-branch', 'src'))
856 ex((bup_cmd, '-d', 'get-src', 'index', '--clear'))
859 open('src/zero', 'a').close()
860 ex((bup_cmd, '-d', 'get-src', 'index', 'src'))
861 exr = exo((bup_cmd, '-d', 'get-src', 'save', '-tcn', 'src', 'src'))
862 out = exr.out.splitlines()
864 commit_0_id = out[-1]
865 exr = exo((bup_cmd, '-d', 'get-src', 'ls', 'src'))
866 save_0 = exr.out.splitlines()[0]
867 ex(('git', '--git-dir', 'get-src', 'branch', 'src-0', 'src'))
868 ex(('cp', '-RPp', 'src', 'src-0'))
874 ex((bup_cmd + ' -d get-src random 1k > src/1'), shell=True)
875 ex((bup_cmd + ' -d get-src random 1k > src/x/2'), shell=True)
876 ex((bup_cmd, '-d', 'get-src', 'index', 'src'))
877 exr = exo((bup_cmd, '-d', 'get-src', 'save', '-tcn', 'src', 'src'))
878 out = exr.out.splitlines()
880 commit_1_id = out[-1]
881 exr = exo((bup_cmd, '-d', 'get-src', 'ls', 'src'))
882 save_1 = exr.out.splitlines()[1]
883 ex(('git', '--git-dir', 'get-src', 'branch', 'src-1', 'src'))
884 ex(('cp', '-RPp', 'src', 'src-1'))
886 # Make a copy the current state of src so we'll have an ancestor.
888 'get-src/refs/heads/src', 'get-src/refs/heads/src-ancestor'))
890 with open('src/tiny-file', 'a') as f: f.write('xyzzy')
891 ex((bup_cmd, '-d', 'get-src', 'index', 'src'))
892 ex((bup_cmd, '-d', 'get-src', 'tick')) # Ensure the save names differ
893 exr = exo((bup_cmd, '-d', 'get-src', 'save', '-tcn', 'src', 'src'))
894 out = exr.out.splitlines()
896 commit_2_id = out[-1]
897 exr = exo((bup_cmd, '-d', 'get-src', 'ls', 'src'))
898 save_2 = exr.out.splitlines()[2]
899 rename('src', 'src-2')
901 src_root = getcwd() + '/src'
903 subtree_path = 'src-2/x'
904 subtree_vfs_path = src_root + '/x'
906 # No support for "ls -d", so grep...
907 exr = exo((bup_cmd, '-d', 'get-src', 'ls', '-s', 'src/latest' + src_root))
908 out = exr.out.splitlines()
912 subtree_id = line.split()[0]
915 # With a tiny file, we'll get a single blob, not a chunked tree
916 tinyfile_path = src_root + '/tiny-file'
917 exr = exo((bup_cmd, '-d', 'get-src', 'ls', '-s', 'src/latest' + tinyfile_path))
918 tinyfile_id = exr.out.splitlines()[0].split()[0]
920 ex((bup_cmd, '-d', 'get-src', 'tag', 'tinyfile', tinyfile_id))
921 ex((bup_cmd, '-d', 'get-src', 'tag', 'subtree', subtree_id))
922 ex((bup_cmd, '-d', 'get-src', 'tag', 'tree-0', tree_0_id))
923 ex((bup_cmd, '-d', 'get-src', 'tag', 'tree-1', tree_1_id))
924 ex((bup_cmd, '-d', 'get-src', 'tag', 'tree-2', tree_2_id))
925 ex((bup_cmd, '-d', 'get-src', 'tag', 'commit-0', commit_0_id))
926 ex((bup_cmd, '-d', 'get-src', 'tag', 'commit-1', commit_1_id))
927 ex((bup_cmd, '-d', 'get-src', 'tag', 'commit-2', commit_2_id))
928 ex(('git', '--git-dir', 'get-src', 'branch', 'commit-1', commit_1_id))
929 ex(('git', '--git-dir', 'get-src', 'branch', 'commit-2', commit_2_id))
931 return {'tinyfile-path' : tinyfile_path,
932 'tinyfile-id' : tinyfile_id,
933 'subtree-id' : subtree_id,
934 'tree-0-id' : tree_0_id,
935 'tree-1-id' : tree_1_id,
936 'tree-2-id' : tree_2_id,
937 'commit-0-id' : commit_0_id,
938 'commit-1-id' : commit_1_id,
939 'commit-2-id' : commit_2_id,
942 'subtree-path' : subtree_path,
943 'subtree-vfs-path' : subtree_vfs_path}
945 # FIXME: this fails in a strange way:
946 # WVPASS given nothing get --ff not-there
948 dispositions_to_test = ('get',)
950 if int(environ.get('BUP_TEST_LEVEL', '0')) >= 11:
951 dispositions_to_test += ('get-on', 'get-to')
953 if len(sys.argv) == 1:
954 categories = ('replace', 'universal', 'ff', 'append', 'pick', 'new-tag',
957 categories = sys.argv[1:]
959 with test_tempdir('get-') as tmpdir:
962 src_info = create_get_src()
963 for category in categories:
964 for disposition in dispositions_to_test:
965 # given=FOO depends on --replace, so test it early
966 if category == 'replace':
967 test_replace(disposition, src_info)
968 elif category == 'universal':
969 test_universal_behaviors(disposition)
970 elif category == 'ff':
971 test_ff(disposition, src_info)
972 elif category == 'append':
973 test_append(disposition, src_info)
974 elif category == 'pick':
975 test_pick(disposition, src_info, force=False)
976 test_pick(disposition, src_info, force=True)
977 elif category == 'new-tag':
978 test_new_tag(disposition, src_info)
979 elif category == 'unnamed':
980 test_unnamed(disposition, src_info)
982 raise Exception('unrecognized get test category')
983 except Exception, ex:
988 wvmsg('checked %d cases' % get_cases_tested)