2 from __future__ import print_function
3 from errno import ENOENT
4 from itertools import product
5 from os import chdir, mkdir, rename
6 from shutil import rmtree
7 from subprocess import PIPE
10 from bup import compat, path
11 from bup.compat import environ, getcwd
12 from bup.helpers import bquote, merge_dict, unlink
13 from bup.io import byte_stream
14 from buptest import ex, exo
15 from wvpytest import wvcheck, wvfail, wvmsg, wvpass, wvpasseq, wvpassne, wvstart
20 stdout = byte_stream(sys.stdout)
22 # FIXME: per-test function
23 environ[b'GIT_AUTHOR_NAME'] = b'bup test-get'
24 environ[b'GIT_COMMITTER_NAME'] = b'bup test-get'
25 environ[b'GIT_AUTHOR_EMAIL'] = b'bup@85430dcca2b611e4b2c3-8f5691723476'
26 environ[b'GIT_COMMITTER_EMAIL'] = b'bup@85430dcca2b611e4b2c3-8f5691723476'
28 # The clean-repo test can probably be applied more broadly. It was
29 # initially just applied to test-pick to catch a bug.
32 bup_cmd = bup.path.exe()
35 err = [] # because python's scoping mess...
36 def onerror(function, path, excinfo):
37 err.append((function, path, excinfo))
38 rmtree(path, onerror=onerror)
40 function, path, excinfo = err[0]
41 ex_type, ex, traceback = excinfo
42 if (not isinstance(ex, OSError)) or ex.errno != ENOENT:
45 def verify_trees_match(path1, path2):
47 exr = exo((top + b'/dev/compare-trees', b'-c', path1, path2), check=False)
50 wvcheck(exr.rc == 0, 'process exit %d == 0' % exr.rc)
52 def verify_rcz(cmd, **kwargs):
53 assert not kwargs.get('check')
54 kwargs['check'] = False
55 result = exo(cmd, **kwargs)
56 stdout.write(result.out)
57 rc = result.proc.returncode
58 wvcheck(rc == 0, 'process exit %d == 0' % rc)
61 # FIXME: multline, or allow opts generally?
63 def verify_rx(rx, string):
64 wvcheck(re.search(rx, string), 'rx %r matches %r' % (rx, string))
66 def verify_nrx(rx, string):
67 wvcheck(not re.search(rx, string), "rx %r doesn't match %r" % (rx, string))
69 def validate_clean_repo():
70 out = verify_rcz((b'git', b'--git-dir', b'get-dest', b'fsck')).out
71 verify_nrx(br'dangling|mismatch|missing|unreachable', out)
73 def validate_blob(src_id, dest_id):
77 cat_tree = top + b'/dev/git-cat-tree'
78 src_blob = verify_rcz((cat_tree, b'--git-dir', b'get-src', src_id)).out
79 dest_blob = verify_rcz((cat_tree, b'--git-dir', b'get-src', src_id)).out
80 wvpasseq(src_blob, dest_blob)
82 def validate_tree(src_id, dest_id):
87 mkdir(b'restore-dest')
89 commit_env = merge_dict(environ, {b'GIT_COMMITTER_DATE': b'2014-01-01 01:01'})
91 # Create a commit so the archive contents will have matching timestamps.
92 src_c = exo((b'git', b'--git-dir', b'get-src',
93 b'commit-tree', b'-m', b'foo', src_id),
94 env=commit_env).out.strip()
95 dest_c = exo((b'git', b'--git-dir', b'get-dest',
96 b'commit-tree', b'-m', b'foo', dest_id),
97 env=commit_env).out.strip()
98 exr = verify_rcz(b'git --git-dir get-src archive %s | tar xvf - -C restore-src'
101 if exr.rc != 0: return False
102 exr = verify_rcz(b'git --git-dir get-dest archive %s | tar xvf - -C restore-dest'
105 if exr.rc != 0: return False
107 # git archive doesn't include an entry for ./.
108 unlink(b'restore-src/pax_global_header')
109 unlink(b'restore-dest/pax_global_header')
110 ex((b'touch', b'-r', b'restore-src', b'restore-dest'))
111 verify_trees_match(b'restore-src/', b'restore-dest/')
113 rmrf(b'restore-dest')
115 def validate_commit(src_id, dest_id):
116 exr = verify_rcz((b'git', b'--git-dir', b'get-src', b'cat-file', b'commit', src_id))
117 if exr.rc != 0: return False
119 exr = verify_rcz((b'git', b'--git-dir', b'get-dest', b'cat-file', b'commit', dest_id))
120 if exr.rc != 0: return False
122 wvpasseq(src_cat, dest_cat)
123 if src_cat != dest_cat: return False
126 rmrf(b'restore-dest')
127 mkdir(b'restore-src')
128 mkdir(b'restore-dest')
129 qsrc = bquote(src_id)
130 qdest = bquote(dest_id)
131 exr = verify_rcz((b'git --git-dir get-src archive ' + qsrc
132 + b' | tar xf - -C restore-src'),
134 if exr.rc != 0: return False
135 exr = verify_rcz((b'git --git-dir get-dest archive ' + qdest +
136 b' | tar xf - -C restore-dest'),
138 if exr.rc != 0: return False
140 # git archive doesn't include an entry for ./.
141 ex((b'touch', b'-r', b'restore-src', b'restore-dest'))
142 verify_trees_match(b'restore-src/', b'restore-dest/')
144 rmrf(b'restore-dest')
146 def _validate_save(orig_dir, save_path, commit_id, tree_id):
149 exr = verify_rcz((bup_cmd, b'-d', b'get-dest',
150 b'restore', b'-C', b'restore', save_path + b'/.'))
151 if exr.rc: return False
152 verify_trees_match(orig_dir + b'/', b'restore/')
154 # FIXME: double check that get-dest is correct
155 exr = verify_rcz((b'git', b'--git-dir', b'get-dest', b'ls-tree', tree_id))
156 if exr.rc: return False
157 cat = verify_rcz((b'git', b'--git-dir', b'get-dest',
158 b'cat-file', b'commit', commit_id))
159 if cat.rc: return False
160 wvpasseq(b'tree ' + tree_id, cat.out.splitlines()[0])
162 # FIXME: re-merge save and new_save?
164 def validate_save(dest_name, restore_subpath, commit_id, tree_id, orig_value,
166 out = get_out.splitlines()
167 print('blarg: out', repr(out), file=sys.stderr)
168 wvpasseq(2, len(out))
170 get_commit_id = out[1]
171 wvpasseq(tree_id, get_tree_id)
172 wvpasseq(commit_id, get_commit_id)
173 _validate_save(orig_value, dest_name + restore_subpath, commit_id, tree_id)
175 def validate_new_save(dest_name, restore_subpath, commit_id, tree_id, orig_value,
177 out = get_out.splitlines()
178 wvpasseq(2, len(out))
180 get_commit_id = out[1]
181 wvpasseq(tree_id, get_tree_id)
182 wvpassne(commit_id, get_commit_id)
183 _validate_save(orig_value, dest_name + restore_subpath, get_commit_id, tree_id)
185 def validate_tagged_save(tag_name, restore_subpath,
186 commit_id, tree_id, orig_value, get_out):
187 out = get_out.splitlines()
188 wvpasseq(1, len(out))
190 wvpasseq(commit_id, get_tag_id)
191 # Make sure tmp doesn't already exist.
192 exr = exo((b'git', b'--git-dir', b'get-dest', b'show-ref', b'tmp-branch-for-tag'),
196 ex((b'git', b'--git-dir', b'get-dest', b'branch', b'tmp-branch-for-tag',
197 b'refs/tags/' + tag_name))
198 _validate_save(orig_value, b'tmp-branch-for-tag/latest' + restore_subpath,
200 ex((b'git', b'--git-dir', b'get-dest', b'branch', b'-D', b'tmp-branch-for-tag'))
202 def validate_new_tagged_commit(tag_name, commit_id, tree_id, get_out):
203 out = get_out.splitlines()
204 wvpasseq(1, len(out))
206 wvpassne(commit_id, get_tag_id)
207 validate_tree(tree_id, tag_name + b':')
210 def _run_get(disposition, method, what):
211 print('run_get:', repr((disposition, method, what)), file=sys.stderr)
214 if disposition == 'get':
215 get_cmd = (bup_cmd, b'-d', b'get-dest',
216 b'get', b'-vvct', b'--print-tags', b'-s', b'get-src')
217 elif disposition == 'get-on':
218 get_cmd = (bup_cmd, b'-d', b'get-dest',
219 b'on', b'-', b'get', b'-vvct', b'--print-tags', b'-s', b'get-src')
220 elif disposition == 'get-to':
221 get_cmd = (bup_cmd, b'-d', b'get-dest',
222 b'get', b'-vvct', b'--print-tags', b'-s', b'get-src',
223 b'-r', b'-:' + getcwd() + b'/get-dest')
225 raise Exception('error: unexpected get disposition ' + repr(disposition))
227 if isinstance(what, bytes):
228 cmd = get_cmd + (method, what)
230 assert not isinstance(what, str) # python 3 sanity check
231 if method in (b'--ff', b'--append', b'--pick', b'--force-pick', b'--new-tag',
235 cmd = get_cmd + (method, src, dest)
236 result = exo(cmd, check=False, stderr=PIPE)
237 fsck = ex((bup_cmd, b'-d', b'get-dest', b'fsck'), check=False)
241 def run_get(disposition, method, what=None, given=None):
244 ex((bup_cmd, b'-d', b'get-dest', b'init'))
247 # FIXME: replace bup-get with independent commands as is feasible
248 exr = _run_get(disposition, b'--replace', given)
250 return _run_get(disposition, method, what)
252 def _test_universal(get_disposition, src_info):
253 methods = (b'--ff', b'--append', b'--pick', b'--force-pick', b'--new-tag',
254 b'--replace', b'--unnamed')
255 for method in methods:
256 mmsg = method.decode('ascii')
257 wvstart(get_disposition + ' ' + mmsg + ', missing source, fails')
258 exr = run_get(get_disposition, method, b'not-there')
260 verify_rx(br'cannot find source', exr.err)
261 for method in methods:
262 mmsg = method.decode('ascii')
263 wvstart(get_disposition + ' ' + mmsg + ' / fails')
264 exr = run_get(get_disposition, method, b'/')
266 verify_rx(b'cannot fetch entire repository', exr.err)
268 def verify_only_refs(**kwargs):
269 for kind, refs in kwargs.items():
271 abs_refs = [b'refs/heads/' + ref for ref in refs]
274 abs_refs = [b'refs/tags/' + ref for ref in refs]
277 raise TypeError('unexpected keyword argument %r' % kind)
279 verify_rcz([b'git', b'--git-dir', b'get-dest',
280 b'show-ref', b'--verify', karg] + abs_refs)
281 exr = exo((b'git', b'--git-dir', b'get-dest', b'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((b'git', b'--git-dir', b'get-dest', b'show-ref', karg),
292 wvpasseq(b'', exr.out.strip())
294 def _test_replace(get_disposition, src_info):
295 print('blarg:', repr(src_info), file=sys.stderr)
297 wvstart(get_disposition + ' --replace to root fails')
298 for item in (b'.tag/tinyfile',
299 b'src/latest' + src_info['tinyfile-path'],
301 b'src/latest' + src_info['subtree-vfs-path'],
305 exr = run_get(get_disposition, b'--replace', (item, b'/'))
307 verify_rx(br'impossible; can only overwrite branch or tag', exr.err)
309 tinyfile_id = src_info['tinyfile-id']
310 tinyfile_path = src_info['tinyfile-path']
311 subtree_vfs_path = src_info['subtree-vfs-path']
312 subtree_id = src_info['subtree-id']
313 commit_2_id = src_info['commit-2-id']
314 tree_2_id = src_info['tree-2-id']
317 existing_items = {'nothing' : None,
318 'blob' : (b'.tag/tinyfile', b'.tag/obj'),
319 'tree' : (b'.tag/tree-1', b'.tag/obj'),
320 'commit': (b'.tag/commit-1', b'.tag/obj')}
321 for ex_type, ex_ref in existing_items.items():
322 wvstart(get_disposition + ' --replace ' + ex_type + ' with blob tag')
323 for item in (b'.tag/tinyfile', b'src/latest' + tinyfile_path):
324 exr = run_get(get_disposition, b'--replace', (item ,b'.tag/obj'),
327 validate_blob(tinyfile_id, tinyfile_id)
328 verify_only_refs(heads=[], tags=(b'obj',))
329 wvstart(get_disposition + ' --replace ' + ex_type + ' with tree tag')
330 for item in (b'.tag/subtree', b'src/latest' + subtree_vfs_path):
331 exr = run_get(get_disposition, b'--replace', (item, b'.tag/obj'),
333 validate_tree(subtree_id, subtree_id)
334 verify_only_refs(heads=[], tags=(b'obj',))
335 wvstart(get_disposition + ' --replace ' + ex_type + ' with commitish tag')
336 for item in (b'.tag/commit-2', b'src/latest', b'src'):
337 exr = run_get(get_disposition, b'--replace', (item, b'.tag/obj'),
339 validate_tagged_save(b'obj', getcwd() + b'/src',
340 commit_2_id, tree_2_id, b'src-2', exr.out)
341 verify_only_refs(heads=[], tags=(b'obj',))
343 # Committish to branch.
344 existing_items = (('nothing', None),
345 ('branch', (b'.tag/commit-1', b'obj')))
346 for ex_type, ex_ref in existing_items:
347 for item_type, item in (('commit', b'.tag/commit-2'),
348 ('save', b'src/latest'),
350 wvstart(get_disposition + ' --replace '
351 + ex_type + ' with ' + item_type)
352 exr = run_get(get_disposition, b'--replace', (item, b'obj'),
354 validate_save(b'obj/latest', getcwd() + b'/src',
355 commit_2_id, tree_2_id, b'src-2', exr.out)
356 verify_only_refs(heads=(b'obj',), tags=[])
358 # Not committish to branch
359 existing_items = (('nothing', None),
360 ('branch', (b'.tag/commit-1', b'obj')))
361 for ex_type, ex_ref in existing_items:
362 for item_type, item in (('blob', b'.tag/tinyfile'),
363 ('blob', b'src/latest' + tinyfile_path),
364 ('tree', b'.tag/subtree'),
365 ('tree', b'src/latest' + subtree_vfs_path)):
366 wvstart(get_disposition + ' --replace branch with '
367 + item_type + ' given ' + ex_type + ' fails')
369 exr = run_get(get_disposition, b'--replace', (item, b'obj'),
372 verify_rx(br'cannot overwrite branch with .+ for', exr.err)
374 wvstart(get_disposition + ' --replace, implicit destinations')
376 exr = run_get(get_disposition, b'--replace', b'src')
377 validate_save(b'src/latest', getcwd() + b'/src',
378 commit_2_id, tree_2_id, b'src-2', exr.out)
379 verify_only_refs(heads=(b'src',), tags=[])
381 exr = run_get(get_disposition, b'--replace', b'.tag/commit-2')
382 validate_tagged_save(b'commit-2', getcwd() + b'/src',
383 commit_2_id, tree_2_id, b'src-2', exr.out)
384 verify_only_refs(heads=[], tags=(b'commit-2',))
386 def _test_ff(get_disposition, src_info):
388 wvstart(get_disposition + ' --ff to root fails')
389 tinyfile_path = src_info['tinyfile-path']
390 for item in (b'.tag/tinyfile', b'src/latest' + tinyfile_path):
391 exr = run_get(get_disposition, b'--ff', (item, b'/'))
393 verify_rx(br'source for .+ must be a branch, save, or commit', exr.err)
394 subtree_vfs_path = src_info['subtree-vfs-path']
395 for item in (b'.tag/subtree', b'src/latest' + subtree_vfs_path):
396 exr = run_get(get_disposition, b'--ff', (item, b'/'))
398 verify_rx(br'is impossible; can only --append a tree to a branch',
400 for item in (b'.tag/commit-1', b'src/latest', b'src'):
401 exr = run_get(get_disposition, b'--ff', (item, b'/'))
403 verify_rx(br'destination for .+ is a root, not a branch', exr.err)
405 wvstart(get_disposition + ' --ff of not-committish fails')
406 for src in (b'.tag/tinyfile', b'src/latest' + tinyfile_path):
407 # FIXME: use get_item elsewhere?
408 for given, get_item in ((None, (src, b'obj')),
409 (None, (src, b'.tag/obj')),
410 ((b'.tag/tinyfile', b'.tag/obj'), (src, b'.tag/obj')),
411 ((b'.tag/tree-1', b'.tag/obj'), (src, b'.tag/obj')),
412 ((b'.tag/commit-1', b'.tag/obj'), (src, b'.tag/obj')),
413 ((b'.tag/commit-1', b'obj'), (src, b'obj'))):
414 exr = run_get(get_disposition, b'--ff', get_item, given=given)
416 verify_rx(br'must be a branch, save, or commit', exr.err)
417 for src in (b'.tag/subtree', b'src/latest' + subtree_vfs_path):
418 for given, get_item in ((None, (src, b'obj')),
419 (None, (src, b'.tag/obj')),
420 ((b'.tag/tinyfile', b'.tag/obj'), (src, b'.tag/obj')),
421 ((b'.tag/tree-1', b'.tag/obj'), (src, b'.tag/obj')),
422 ((b'.tag/commit-1', b'.tag/obj'), (src, b'.tag/obj')),
423 ((b'.tag/commit-1', b'obj'), (src, b'obj'))):
424 exr = run_get(get_disposition, b'--ff', get_item, given=given)
426 verify_rx(br'can only --append a tree to a branch', exr.err)
428 wvstart(get_disposition + ' --ff committish, ff possible')
429 save_2 = src_info['save-2']
430 for src in (b'.tag/commit-2', b'src/' + save_2, b'src'):
431 for given, get_item, complaint in \
432 ((None, (src, b'.tag/obj'),
433 br'destination .+ must be a valid branch name'),
434 ((b'.tag/tinyfile', b'.tag/obj'), (src, b'.tag/obj'),
435 br'destination .+ is a blob, not a branch'),
436 ((b'.tag/tree-1', b'.tag/obj'), (src, b'.tag/obj'),
437 br'destination .+ is a tree, not a branch'),
438 ((b'.tag/commit-1', b'.tag/obj'), (src, b'.tag/obj'),
439 br'destination .+ is a tagged commit, not a branch'),
440 ((b'.tag/commit-2', b'.tag/obj'), (src, b'.tag/obj'),
441 br'destination .+ is a tagged commit, not a branch')):
442 exr = run_get(get_disposition, b'--ff', get_item, given=given)
444 verify_rx(complaint, exr.err)
445 # FIXME: use src or item and given or existing consistently in loops...
446 commit_2_id = src_info['commit-2-id']
447 tree_2_id = src_info['tree-2-id']
448 for src in (b'.tag/commit-2', b'src/' + save_2, b'src'):
449 for given in (None, (b'.tag/commit-1', b'obj'), (b'.tag/commit-2', b'obj')):
450 exr = run_get(get_disposition, b'--ff', (src, b'obj'), given=given)
452 validate_save(b'obj/latest', getcwd() + b'/src',
453 commit_2_id, tree_2_id, b'src-2', exr.out)
454 verify_only_refs(heads=(b'obj',), tags=[])
456 wvstart(get_disposition + ' --ff, implicit destinations')
457 for item in (b'src', b'src/latest'):
458 exr = run_get(get_disposition, b'--ff', item)
461 ex((b'find', b'get-dest/refs'))
462 ex((bup_cmd, b'-d', b'get-dest', b'ls'))
464 validate_save(b'src/latest', getcwd() + b'/src',
465 commit_2_id, tree_2_id, b'src-2', exr.out)
466 #verify_only_refs(heads=('src',), tags=[])
468 wvstart(get_disposition + ' --ff, ff impossible')
469 for given, get_item in (((b'unrelated-branch', b'src'), b'src'),
470 ((b'.tag/commit-2', b'src'), (b'.tag/commit-1', b'src'))):
471 exr = run_get(get_disposition, b'--ff', get_item, given=given)
473 verify_rx(br'destination is not an ancestor of source', exr.err)
475 def _test_append(get_disposition, src_info):
476 tinyfile_path = src_info['tinyfile-path']
477 subtree_vfs_path = src_info['subtree-vfs-path']
479 wvstart(get_disposition + ' --append to root fails')
480 for item in (b'.tag/tinyfile', b'src/latest' + tinyfile_path):
481 exr = run_get(get_disposition, b'--append', (item, b'/'))
483 verify_rx(br'source for .+ must be a branch, save, commit, or tree',
485 for item in (b'.tag/subtree', b'src/latest' + subtree_vfs_path,
486 b'.tag/commit-1', b'src/latest', b'src'):
487 exr = run_get(get_disposition, b'--append', (item, b'/'))
489 verify_rx(br'destination for .+ is a root, not a branch', exr.err)
491 wvstart(get_disposition + ' --append of not-treeish fails')
492 for src in (b'.tag/tinyfile', b'src/latest' + tinyfile_path):
493 for given, item in ((None, (src, b'obj')),
494 (None, (src, b'.tag/obj')),
495 ((b'.tag/tinyfile', b'.tag/obj'), (src, b'.tag/obj')),
496 ((b'.tag/tree-1', b'.tag/obj'), (src, b'.tag/obj')),
497 ((b'.tag/commit-1', b'.tag/obj'), (src, b'.tag/obj')),
498 ((b'.tag/commit-1', b'obj'), (src, b'obj'))):
499 exr = run_get(get_disposition, b'--append', item, given=given)
501 verify_rx(br'must be a branch, save, commit, or tree', exr.err)
503 wvstart(get_disposition + ' --append committish failure cases')
504 save_2 = src_info['save-2']
505 for src in (b'.tag/subtree', b'src/latest' + subtree_vfs_path,
506 b'.tag/commit-2', b'src/' + save_2, b'src'):
507 for given, item, complaint in \
508 ((None, (src, b'.tag/obj'),
509 br'destination .+ must be a valid branch name'),
510 ((b'.tag/tinyfile', b'.tag/obj'), (src, b'.tag/obj'),
511 br'destination .+ is a blob, not a branch'),
512 ((b'.tag/tree-1', b'.tag/obj'), (src, b'.tag/obj'),
513 br'destination .+ is a tree, not a branch'),
514 ((b'.tag/commit-1', b'.tag/obj'), (src, b'.tag/obj'),
515 br'destination .+ is a tagged commit, not a branch'),
516 ((b'.tag/commit-2', b'.tag/obj'), (src, b'.tag/obj'),
517 br'destination .+ is a tagged commit, not a branch')):
518 exr = run_get(get_disposition, b'--append', item, given=given)
520 verify_rx(complaint, exr.err)
522 wvstart(get_disposition + ' --append committish')
523 commit_2_id = src_info['commit-2-id']
524 tree_2_id = src_info['tree-2-id']
525 for item in (b'.tag/commit-2', b'src/' + save_2, b'src'):
526 for existing in (None, (b'.tag/commit-1', b'obj'),
527 (b'.tag/commit-2', b'obj'),
528 (b'unrelated-branch', b'obj')):
529 exr = run_get(get_disposition, b'--append', (item, b'obj'),
532 validate_new_save(b'obj/latest', getcwd() + b'/src',
533 commit_2_id, tree_2_id, b'src-2', exr.out)
534 verify_only_refs(heads=(b'obj',), tags=[])
536 save_1 = src_info['save-1']
537 commit_1_id = src_info['commit-1-id']
538 tree_1_id = src_info['tree-1-id']
539 for item in (b'.tag/commit-1', b'src/' + save_1, b'src-1'):
540 exr = run_get(get_disposition, b'--append', (item, b'obj'),
541 given=(b'.tag/commit-2', b'obj'))
543 validate_new_save(b'obj/latest', getcwd() + b'/src',
544 commit_1_id, tree_1_id, b'src-1', exr.out)
545 verify_only_refs(heads=(b'obj',), tags=[])
547 wvstart(get_disposition + ' --append tree')
548 subtree_path = src_info['subtree-path']
549 subtree_id = src_info['subtree-id']
550 for item in (b'.tag/subtree', b'src/latest' + subtree_vfs_path):
551 for existing in (None,
552 (b'.tag/commit-1', b'obj'),
553 (b'.tag/commit-2', b'obj')):
554 exr = run_get(get_disposition, b'--append', (item, b'obj'),
557 validate_new_save(b'obj/latest', b'/', None, subtree_id, subtree_path,
559 verify_only_refs(heads=(b'obj',), tags=[])
561 wvstart(get_disposition + ' --append, implicit destinations')
563 for item in (b'src', b'src/latest'):
564 exr = run_get(get_disposition, b'--append', item)
566 validate_new_save(b'src/latest', getcwd() + b'/src', commit_2_id, tree_2_id,
568 verify_only_refs(heads=(b'src',), tags=[])
570 def _test_pick_common(get_disposition, src_info, force=False):
571 flavor = b'--force-pick' if force else b'--pick'
572 flavormsg = flavor.decode('ascii')
573 tinyfile_path = src_info['tinyfile-path']
574 subtree_vfs_path = src_info['subtree-vfs-path']
576 wvstart(get_disposition + ' ' + flavormsg + ' to root fails')
577 for item in (b'.tag/tinyfile', b'src/latest' + tinyfile_path, b'src'):
578 exr = run_get(get_disposition, flavor, (item, b'/'))
580 verify_rx(br'can only pick a commit or save', exr.err)
581 for item in (b'.tag/commit-1', b'src/latest'):
582 exr = run_get(get_disposition, flavor, (item, b'/'))
584 verify_rx(br'destination is not a tag or branch', exr.err)
585 for item in (b'.tag/subtree', b'src/latest' + subtree_vfs_path):
586 exr = run_get(get_disposition, flavor, (item, b'/'))
588 verify_rx(br'is impossible; can only --append a tree', exr.err)
590 wvstart(get_disposition + ' ' + flavormsg + ' of blob or branch fails')
591 for item in (b'.tag/tinyfile', b'src/latest' + tinyfile_path, b'src'):
592 for given, get_item in ((None, (item, b'obj')),
593 (None, (item, b'.tag/obj')),
594 ((b'.tag/tinyfile', b'.tag/obj'), (item, b'.tag/obj')),
595 ((b'.tag/tree-1', b'.tag/obj'), (item, b'.tag/obj')),
596 ((b'.tag/commit-1', b'.tag/obj'), (item, b'.tag/obj')),
597 ((b'.tag/commit-1', b'obj'), (item, b'obj'))):
598 exr = run_get(get_disposition, flavor, get_item, given=given)
600 verify_rx(br'impossible; can only pick a commit or save', exr.err)
602 wvstart(get_disposition + ' ' + flavormsg + ' of tree fails')
603 for item in (b'.tag/subtree', b'src/latest' + subtree_vfs_path):
604 for given, get_item in ((None, (item, b'obj')),
605 (None, (item, b'.tag/obj')),
606 ((b'.tag/tinyfile', b'.tag/obj'), (item, b'.tag/obj')),
607 ((b'.tag/tree-1', b'.tag/obj'), (item, b'.tag/obj')),
608 ((b'.tag/commit-1', b'.tag/obj'), (item, b'.tag/obj')),
609 ((b'.tag/commit-1', b'obj'), (item, b'obj'))):
610 exr = run_get(get_disposition, flavor, get_item, given=given)
612 verify_rx(br'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 + ' ' + flavormsg + ' commit/save to existing tag')
620 for item in (b'.tag/commit-2', b'src/' + save_2):
621 for given in ((b'.tag/tinyfile', b'.tag/obj'),
622 (b'.tag/tree-1', b'.tag/obj'),
623 (b'.tag/commit-1', b'.tag/obj')):
624 exr = run_get(get_disposition, flavor, (item, b'.tag/obj'),
627 validate_new_tagged_commit(b'obj', commit_2_id, tree_2_id,
629 verify_only_refs(heads=[], tags=(b'obj',))
631 wvstart(get_disposition + ' ' + flavormsg
632 + ' commit/save to existing tag fails')
633 for item in (b'.tag/commit-2', b'src/' + save_2):
634 for given in ((b'.tag/tinyfile', b'.tag/obj'),
635 (b'.tag/tree-1', b'.tag/obj'),
636 (b'.tag/commit-1', b'.tag/obj')):
637 exr = run_get(get_disposition, flavor, (item, b'.tag/obj'), given=given)
639 verify_rx(br'cannot overwrite existing tag', exr.err)
641 wvstart(get_disposition + ' ' + flavormsg + ' commit/save to tag')
642 for item in (b'.tag/commit-2', b'src/' + save_2):
643 exr = run_get(get_disposition, flavor, (item, b'.tag/obj'))
645 validate_clean_repo()
646 validate_new_tagged_commit(b'obj', commit_2_id, tree_2_id, exr.out)
647 verify_only_refs(heads=[], tags=(b'obj',))
649 wvstart(get_disposition + ' ' + flavormsg + ' commit/save to branch')
650 for item in (b'.tag/commit-2', b'src/' + save_2):
651 for given in (None, (b'.tag/commit-1', b'obj'), (b'.tag/commit-2', b'obj')):
652 exr = run_get(get_disposition, flavor, (item, b'obj'), given=given)
654 validate_clean_repo()
655 validate_new_save(b'obj/latest', getcwd() + b'/src',
656 commit_2_id, tree_2_id, b'src-2', exr.out)
657 verify_only_refs(heads=(b'obj',), tags=[])
659 wvstart(get_disposition + ' ' + flavormsg
660 + ' commit/save unrelated commit to branch')
661 for item in(b'.tag/commit-2', b'src/' + save_2):
662 exr = run_get(get_disposition, flavor, (item, b'obj'),
663 given=(b'unrelated-branch', b'obj'))
665 validate_clean_repo()
666 validate_new_save(b'obj/latest', getcwd() + b'/src',
667 commit_2_id, tree_2_id, b'src-2', exr.out)
668 verify_only_refs(heads=(b'obj',), tags=[])
670 wvstart(get_disposition + ' ' + flavormsg + ' 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 (b'.tag/commit-1', b'src/' + save_1):
675 exr = run_get(get_disposition, flavor, (item, b'obj'),
676 given=(b'.tag/commit-2', b'obj'))
678 validate_clean_repo()
679 validate_new_save(b'obj/latest', getcwd() + b'/src',
680 commit_1_id, tree_1_id, b'src-1', exr.out)
681 verify_only_refs(heads=(b'obj',), tags=[])
684 wvstart(get_disposition + ' ' + flavormsg + ', implicit destinations')
685 exr = run_get(get_disposition, flavor, b'.tag/commit-2')
687 validate_clean_repo()
688 validate_new_tagged_commit(b'commit-2', commit_2_id, tree_2_id, exr.out)
689 verify_only_refs(heads=[], tags=(b'commit-2',))
691 exr = run_get(get_disposition, flavor, b'src/latest')
693 validate_clean_repo()
694 validate_new_save(b'src/latest', getcwd() + b'/src',
695 commit_2_id, tree_2_id, b'src-2', exr.out)
696 verify_only_refs(heads=(b'src',), tags=[])
698 def _test_pick_force(get_disposition, src_info):
699 _test_pick_common(get_disposition, src_info, force=True)
701 def _test_pick_noforce(get_disposition, src_info):
702 _test_pick_common(get_disposition, src_info, force=False)
704 def _test_new_tag(get_disposition, src_info):
705 tinyfile_id = src_info['tinyfile-id']
706 tinyfile_path = src_info['tinyfile-path']
707 commit_2_id = src_info['commit-2-id']
708 tree_2_id = src_info['tree-2-id']
709 subtree_id = src_info['subtree-id']
710 subtree_vfs_path = src_info['subtree-vfs-path']
712 wvstart(get_disposition + ' --new-tag to root fails')
713 for item in (b'.tag/tinyfile',
714 b'src/latest' + tinyfile_path,
716 b'src/latest' + subtree_vfs_path,
720 exr = run_get(get_disposition, b'--new-tag', (item, b'/'))
722 verify_rx(br'destination for .+ must be a VFS tag', exr.err)
724 # Anything to new tag.
725 wvstart(get_disposition + ' --new-tag, blob tag')
726 for item in (b'.tag/tinyfile', b'src/latest' + tinyfile_path):
727 exr = run_get(get_disposition, b'--new-tag', (item, b'.tag/obj'))
729 validate_blob(tinyfile_id, tinyfile_id)
730 verify_only_refs(heads=[], tags=(b'obj',))
732 wvstart(get_disposition + ' --new-tag, tree tag')
733 for item in (b'.tag/subtree', b'src/latest' + subtree_vfs_path):
734 exr = run_get(get_disposition, b'--new-tag', (item, b'.tag/obj'))
736 validate_tree(subtree_id, subtree_id)
737 verify_only_refs(heads=[], tags=(b'obj',))
739 wvstart(get_disposition + ' --new-tag, committish tag')
740 for item in (b'.tag/commit-2', b'src/latest', b'src'):
741 exr = run_get(get_disposition, b'--new-tag', (item, b'.tag/obj'))
743 validate_tagged_save(b'obj', getcwd() + b'/src/', commit_2_id, tree_2_id,
745 verify_only_refs(heads=[], tags=(b'obj',))
747 # Anything to existing tag (fails).
748 for ex_type, ex_tag in (('blob', (b'.tag/tinyfile', b'.tag/obj')),
749 ('tree', (b'.tag/tree-1', b'.tag/obj')),
750 ('commit', (b'.tag/commit-1', b'.tag/obj'))):
751 for item_type, item in (('blob tag', b'.tag/tinyfile'),
752 ('blob path', b'src/latest' + tinyfile_path),
753 ('tree tag', b'.tag/subtree'),
754 ('tree path', b'src/latest' + subtree_vfs_path),
755 ('commit tag', b'.tag/commit-2'),
756 ('save', b'src/latest'),
758 wvstart(get_disposition + ' --new-tag of ' + item_type
759 + ', given existing ' + ex_type + ' tag, fails')
760 exr = run_get(get_disposition, b'--new-tag', (item, b'.tag/obj'),
763 verify_rx(br'cannot overwrite existing tag .* \(requires --replace\)',
766 # Anything to branch (fails).
767 for ex_type, ex_tag in (('nothing', None),
768 ('blob', (b'.tag/tinyfile', b'.tag/obj')),
769 ('tree', (b'.tag/tree-1', b'.tag/obj')),
770 ('commit', (b'.tag/commit-1', b'.tag/obj'))):
771 for item_type, item in (('blob tag', b'.tag/tinyfile'),
772 ('blob path', b'src/latest' + tinyfile_path),
773 ('tree tag', b'.tag/subtree'),
774 ('tree path', b'src/latest' + subtree_vfs_path),
775 ('commit tag', b'.tag/commit-2'),
776 ('save', b'src/latest'),
778 wvstart(get_disposition + ' --new-tag to branch of ' + item_type
779 + ', given existing ' + ex_type + ' tag, fails')
780 exr = run_get(get_disposition, b'--new-tag', (item, b'obj'),
783 verify_rx(br'destination for .+ must be a VFS tag', exr.err)
785 wvstart(get_disposition + ' --new-tag, implicit destinations')
786 exr = run_get(get_disposition, b'--new-tag', b'.tag/commit-2')
788 validate_tagged_save(b'commit-2', getcwd() + b'/src/', commit_2_id, tree_2_id,
790 verify_only_refs(heads=[], tags=(b'commit-2',))
792 def _test_unnamed(get_disposition, src_info):
793 tinyfile_id = src_info['tinyfile-id']
794 tinyfile_path = src_info['tinyfile-path']
795 subtree_vfs_path = src_info['subtree-vfs-path']
796 wvstart(get_disposition + ' --unnamed to root fails')
797 for item in (b'.tag/tinyfile',
798 b'src/latest' + tinyfile_path,
800 b'src/latest' + subtree_vfs_path,
804 for ex_ref in (None, (item, b'.tag/obj')):
805 exr = run_get(get_disposition, b'--unnamed', (item, b'/'),
808 verify_rx(br'usage: bup get ', exr.err)
810 wvstart(get_disposition + ' --unnamed file')
811 for item in (b'.tag/tinyfile', b'src/latest' + tinyfile_path):
812 exr = run_get(get_disposition, b'--unnamed', item)
814 validate_blob(tinyfile_id, tinyfile_id)
815 verify_only_refs(heads=[], tags=[])
817 exr = run_get(get_disposition, b'--unnamed', item,
818 given=(item, b'.tag/obj'))
820 validate_blob(tinyfile_id, tinyfile_id)
821 verify_only_refs(heads=[], tags=(b'obj',))
823 wvstart(get_disposition + ' --unnamed tree')
824 subtree_id = src_info['subtree-id']
825 for item in (b'.tag/subtree', b'src/latest' + subtree_vfs_path):
826 exr = run_get(get_disposition, b'--unnamed', item)
828 validate_tree(subtree_id, subtree_id)
829 verify_only_refs(heads=[], tags=[])
831 exr = run_get(get_disposition, b'--unnamed', item,
832 given=(item, b'.tag/obj'))
834 validate_tree(subtree_id, subtree_id)
835 verify_only_refs(heads=[], tags=(b'obj',))
837 wvstart(get_disposition + ' --unnamed committish')
838 save_2 = src_info['save-2']
839 commit_2_id = src_info['commit-2-id']
840 for item in (b'.tag/commit-2', b'src/' + save_2, b'src'):
841 exr = run_get(get_disposition, b'--unnamed', item)
843 validate_commit(commit_2_id, commit_2_id)
844 verify_only_refs(heads=[], tags=[])
846 exr = run_get(get_disposition, b'--unnamed', item,
847 given=(item, b'.tag/obj'))
849 validate_commit(commit_2_id, commit_2_id)
850 verify_only_refs(heads=[], tags=(b'obj',))
852 def create_get_src():
853 global bup_cmd, src_info
855 ex((bup_cmd, b'-d', b'get-src', b'init'))
858 open(b'src/unrelated', 'a').close()
859 ex((bup_cmd, b'-d', b'get-src', b'index', b'src'))
860 ex((bup_cmd, b'-d', b'get-src', b'save', b'-tcn', b'unrelated-branch', b'src'))
862 ex((bup_cmd, b'-d', b'get-src', b'index', b'--clear'))
865 open(b'src/zero', 'a').close()
866 ex((bup_cmd, b'-d', b'get-src', b'index', b'src'))
867 exr = exo((bup_cmd, b'-d', b'get-src', b'save', b'-tcn', b'src', b'src'))
868 out = exr.out.splitlines()
870 commit_0_id = out[-1]
871 exr = exo((bup_cmd, b'-d', b'get-src', b'ls', b'src'))
872 save_0 = exr.out.splitlines()[0]
873 ex((b'git', b'--git-dir', b'get-src', b'branch', b'src-0', b'src'))
874 ex((b'cp', b'-RPp', b'src', b'src-0'))
880 ex((bup_cmd + b' -d get-src random 1k > src/1'), shell=True)
881 ex((bup_cmd + b' -d get-src random 1k > src/x/2'), shell=True)
882 ex((bup_cmd, b'-d', b'get-src', b'index', b'src'))
883 exr = exo((bup_cmd, b'-d', b'get-src', b'save', b'-tcn', b'src', b'src'))
884 out = exr.out.splitlines()
886 commit_1_id = out[-1]
887 exr = exo((bup_cmd, b'-d', b'get-src', b'ls', b'src'))
888 save_1 = exr.out.splitlines()[1]
889 ex((b'git', b'--git-dir', b'get-src', b'branch', b'src-1', b'src'))
890 ex((b'cp', b'-RPp', b'src', b'src-1'))
892 # Make a copy the current state of src so we'll have an ancestor.
894 b'get-src/refs/heads/src', b'get-src/refs/heads/src-ancestor'))
896 with open(b'src/tiny-file', 'ab') as f: f.write(b'xyzzy')
897 ex((bup_cmd, b'-d', b'get-src', b'index', b'src'))
898 ex((bup_cmd, b'-d', b'get-src', b'tick')) # Ensure the save names differ
899 exr = exo((bup_cmd, b'-d', b'get-src', b'save', b'-tcn', b'src', b'src'))
900 out = exr.out.splitlines()
902 commit_2_id = out[-1]
903 exr = exo((bup_cmd, b'-d', b'get-src', b'ls', b'src'))
904 save_2 = exr.out.splitlines()[2]
905 rename(b'src', b'src-2')
907 src_root = getcwd() + b'/src'
909 subtree_path = b'src-2/x'
910 subtree_vfs_path = src_root + b'/x'
912 # No support for "ls -d", so grep...
913 exr = exo((bup_cmd, b'-d', b'get-src', b'ls', b'-s', b'src/latest' + src_root))
914 out = exr.out.splitlines()
918 subtree_id = line.split()[0]
921 # With a tiny file, we'll get a single blob, not a chunked tree
922 tinyfile_path = src_root + b'/tiny-file'
923 exr = exo((bup_cmd, b'-d', b'get-src', b'ls', b'-s', b'src/latest' + tinyfile_path))
924 tinyfile_id = exr.out.splitlines()[0].split()[0]
926 ex((bup_cmd, b'-d', b'get-src', b'tag', b'tinyfile', tinyfile_id))
927 ex((bup_cmd, b'-d', b'get-src', b'tag', b'subtree', subtree_id))
928 ex((bup_cmd, b'-d', b'get-src', b'tag', b'tree-0', tree_0_id))
929 ex((bup_cmd, b'-d', b'get-src', b'tag', b'tree-1', tree_1_id))
930 ex((bup_cmd, b'-d', b'get-src', b'tag', b'tree-2', tree_2_id))
931 ex((bup_cmd, b'-d', b'get-src', b'tag', b'commit-0', commit_0_id))
932 ex((bup_cmd, b'-d', b'get-src', b'tag', b'commit-1', commit_1_id))
933 ex((bup_cmd, b'-d', b'get-src', b'tag', b'commit-2', commit_2_id))
934 ex((b'git', b'--git-dir', b'get-src', b'branch', b'commit-1', commit_1_id))
935 ex((b'git', b'--git-dir', b'get-src', b'branch', b'commit-2', commit_2_id))
937 return {'tinyfile-path' : tinyfile_path,
938 'tinyfile-id' : tinyfile_id,
939 'subtree-id' : subtree_id,
940 'tree-0-id' : tree_0_id,
941 'tree-1-id' : tree_1_id,
942 'tree-2-id' : tree_2_id,
943 'commit-0-id' : commit_0_id,
944 'commit-1-id' : commit_1_id,
945 'commit-2-id' : commit_2_id,
948 'subtree-path' : subtree_path,
949 'subtree-vfs-path' : subtree_vfs_path}
951 # FIXME: this fails in a strange way:
952 # WVPASS given nothing get --ff not-there
954 dispositions_to_test = ('get',)
956 if int(environ.get(b'BUP_TEST_LEVEL', b'0')) >= 11:
957 dispositions_to_test += ('get-on', 'get-to')
959 categories = ('replace', 'universal', 'ff', 'append', 'pick_force', 'pick_noforce', 'new_tag', 'unnamed')
961 @pytest.mark.parametrize("disposition,category", product(dispositions_to_test, categories))
962 def test_get(tmpdir, disposition, category):
965 src_info = create_get_src()
966 globals().get('_test_' + category)(disposition, src_info)