3 # https://sourceware.org/bugzilla/show_bug.cgi?id=26034
4 export "BUP_ARGV_0"="$0"
7 export "BUP_ARGV_${arg_i}"="$arg"
11 bup_python="$(dirname "$0")/../lib/cmd/bup-python" || exit $?
12 exec "$bup_python" "$0"
16 from __future__ import print_function
17 from errno import ENOENT
18 from os import chdir, mkdir, rename
19 from os.path import abspath, dirname
20 from shutil import rmtree
21 from subprocess import PIPE
24 # For buptest, wvtest, ...
25 sys.path[:0] = (abspath(os.path.dirname(__file__) + '/..'),)
26 sys.path[:0] = [os.path.dirname(os.path.realpath(__file__)) + '/../lib']
29 from bup import compat, path
30 from bup.compat import environ, getcwd, items
31 from bup.helpers import bquote, merge_dict, unlink
32 from bup.io import byte_stream
33 from buptest import ex, exo, test_tempdir
34 from wvtest import wvcheck, wvfail, wvmsg, wvpass, wvpasseq, wvpassne, wvstart
38 stdout = byte_stream(sys.stdout)
40 # FIXME: per-test function
41 environ[b'GIT_AUTHOR_NAME'] = b'bup test-get'
42 environ[b'GIT_COMMITTER_NAME'] = b'bup test-get'
43 environ[b'GIT_AUTHOR_EMAIL'] = b'bup@85430dcca2b611e4b2c3-8f5691723476'
44 environ[b'GIT_COMMITTER_EMAIL'] = b'bup@85430dcca2b611e4b2c3-8f5691723476'
46 # The clean-repo test can probably be applied more broadly. It was
47 # initially just applied to test-pick to catch a bug.
50 bup_cmd = bup.path.exe()
53 err = [] # because python's scoping mess...
54 def onerror(function, path, excinfo):
55 err.append((function, path, excinfo))
56 rmtree(path, onerror=onerror)
58 function, path, excinfo = err[0]
59 ex_type, ex, traceback = excinfo
60 if (not isinstance(ex, OSError)) or ex.errno != ENOENT:
63 def verify_trees_match(path1, path2):
65 exr = exo((top + b'/t/compare-trees', b'-c', path1, path2), check=False)
68 wvcheck(exr.rc == 0, 'process exit %d == 0' % exr.rc)
70 def verify_rcz(cmd, **kwargs):
71 assert not kwargs.get('check')
72 kwargs['check'] = False
73 result = exo(cmd, **kwargs)
74 stdout.write(result.out)
75 rc = result.proc.returncode
76 wvcheck(rc == 0, 'process exit %d == 0' % rc)
79 # FIXME: multline, or allow opts generally?
81 def verify_rx(rx, string):
82 wvcheck(re.search(rx, string), 'rx %r matches %r' % (rx, string))
84 def verify_nrx(rx, string):
85 wvcheck(not re.search(rx, string), "rx %r doesn't match %r" % (rx, string))
87 def validate_clean_repo():
88 out = verify_rcz((b'git', b'--git-dir', b'get-dest', b'fsck')).out
89 verify_nrx(br'dangling|mismatch|missing|unreachable', out)
91 def validate_blob(src_id, dest_id):
95 cat_tree = top + b'/t/git-cat-tree'
96 src_blob = verify_rcz((cat_tree, b'--git-dir', b'get-src', src_id)).out
97 dest_blob = verify_rcz((cat_tree, b'--git-dir', b'get-src', src_id)).out
98 wvpasseq(src_blob, dest_blob)
100 def validate_tree(src_id, dest_id):
103 rmrf(b'restore-dest')
104 mkdir(b'restore-src')
105 mkdir(b'restore-dest')
107 commit_env = merge_dict(environ, {b'GIT_COMMITTER_DATE': b'2014-01-01 01:01'})
109 # Create a commit so the archive contents will have matching timestamps.
110 src_c = exo((b'git', b'--git-dir', b'get-src',
111 b'commit-tree', b'-m', b'foo', src_id),
112 env=commit_env).out.strip()
113 dest_c = exo((b'git', b'--git-dir', b'get-dest',
114 b'commit-tree', b'-m', b'foo', dest_id),
115 env=commit_env).out.strip()
116 exr = verify_rcz(b'git --git-dir get-src archive %s | tar xvf - -C restore-src'
119 if exr.rc != 0: return False
120 exr = verify_rcz(b'git --git-dir get-dest archive %s | tar xvf - -C restore-dest'
123 if exr.rc != 0: return False
125 # git archive doesn't include an entry for ./.
126 unlink(b'restore-src/pax_global_header')
127 unlink(b'restore-dest/pax_global_header')
128 ex((b'touch', b'-r', b'restore-src', b'restore-dest'))
129 verify_trees_match(b'restore-src/', b'restore-dest/')
131 rmrf(b'restore-dest')
133 def validate_commit(src_id, dest_id):
134 exr = verify_rcz((b'git', b'--git-dir', b'get-src', b'cat-file', b'commit', src_id))
135 if exr.rc != 0: return False
137 exr = verify_rcz((b'git', b'--git-dir', b'get-dest', b'cat-file', b'commit', dest_id))
138 if exr.rc != 0: return False
140 wvpasseq(src_cat, dest_cat)
141 if src_cat != dest_cat: return False
144 rmrf(b'restore-dest')
145 mkdir(b'restore-src')
146 mkdir(b'restore-dest')
147 qsrc = bquote(src_id)
148 qdest = bquote(dest_id)
149 exr = verify_rcz((b'git --git-dir get-src archive ' + qsrc
150 + b' | tar xf - -C restore-src'),
152 if exr.rc != 0: return False
153 exr = verify_rcz((b'git --git-dir get-dest archive ' + qdest +
154 b' | tar xf - -C restore-dest'),
156 if exr.rc != 0: return False
158 # git archive doesn't include an entry for ./.
159 ex((b'touch', b'-r', b'restore-src', b'restore-dest'))
160 verify_trees_match(b'restore-src/', b'restore-dest/')
162 rmrf(b'restore-dest')
164 def _validate_save(orig_dir, save_path, commit_id, tree_id):
167 exr = verify_rcz((bup_cmd, b'-d', b'get-dest',
168 b'restore', b'-C', b'restore', save_path + b'/.'))
169 if exr.rc: return False
170 verify_trees_match(orig_dir + b'/', b'restore/')
172 # FIXME: double check that get-dest is correct
173 exr = verify_rcz((b'git', b'--git-dir', b'get-dest', b'ls-tree', tree_id))
174 if exr.rc: return False
175 cat = verify_rcz((b'git', b'--git-dir', b'get-dest',
176 b'cat-file', b'commit', commit_id))
177 if cat.rc: return False
178 wvpasseq(b'tree ' + tree_id, cat.out.splitlines()[0])
180 # FIXME: re-merge save and new_save?
182 def validate_save(dest_name, restore_subpath, commit_id, tree_id, orig_value,
184 out = get_out.splitlines()
185 print('blarg: out', repr(out), file=sys.stderr)
186 wvpasseq(2, len(out))
188 get_commit_id = out[1]
189 wvpasseq(tree_id, get_tree_id)
190 wvpasseq(commit_id, get_commit_id)
191 _validate_save(orig_value, dest_name + restore_subpath, commit_id, tree_id)
193 def validate_new_save(dest_name, restore_subpath, commit_id, tree_id, orig_value,
195 out = get_out.splitlines()
196 wvpasseq(2, len(out))
198 get_commit_id = out[1]
199 wvpasseq(tree_id, get_tree_id)
200 wvpassne(commit_id, get_commit_id)
201 _validate_save(orig_value, dest_name + restore_subpath, get_commit_id, tree_id)
203 def validate_tagged_save(tag_name, restore_subpath,
204 commit_id, tree_id, orig_value, get_out):
205 out = get_out.splitlines()
206 wvpasseq(1, len(out))
208 wvpasseq(commit_id, get_tag_id)
209 # Make sure tmp doesn't already exist.
210 exr = exo((b'git', b'--git-dir', b'get-dest', b'show-ref', b'tmp-branch-for-tag'),
214 ex((b'git', b'--git-dir', b'get-dest', b'branch', b'tmp-branch-for-tag',
215 b'refs/tags/' + tag_name))
216 _validate_save(orig_value, b'tmp-branch-for-tag/latest' + restore_subpath,
218 ex((b'git', b'--git-dir', b'get-dest', b'branch', b'-D', b'tmp-branch-for-tag'))
220 def validate_new_tagged_commit(tag_name, commit_id, tree_id, get_out):
221 out = get_out.splitlines()
222 wvpasseq(1, len(out))
224 wvpassne(commit_id, get_tag_id)
225 validate_tree(tree_id, tag_name + b':')
230 def _run_get(disposition, method, what):
231 print('run_get:', repr((disposition, method, what)), file=sys.stderr)
234 if disposition == 'get':
235 get_cmd = (bup_cmd, b'-d', b'get-dest',
236 b'get', b'-vvct', b'--print-tags', b'-s', b'get-src')
237 elif disposition == 'get-on':
238 get_cmd = (bup_cmd, b'-d', b'get-dest',
239 b'on', b'-', b'get', b'-vvct', b'--print-tags', b'-s', b'get-src')
240 elif disposition == 'get-to':
241 get_cmd = (bup_cmd, b'-d', b'get-dest',
242 b'get', b'-vvct', b'--print-tags', b'-s', b'get-src',
243 b'-r', b'-:' + getcwd() + b'/get-dest')
245 raise Exception('error: unexpected get disposition ' + repr(disposition))
247 global get_cases_tested
248 if isinstance(what, bytes):
249 cmd = get_cmd + (method, what)
251 assert not isinstance(what, str) # python 3 sanity check
252 if method in (b'--ff', b'--append', b'--pick', b'--force-pick', b'--new-tag',
256 cmd = get_cmd + (method, src, dest)
257 result = exo(cmd, check=False, stderr=PIPE)
258 get_cases_tested += 1
259 fsck = ex((bup_cmd, b'-d', b'get-dest', b'fsck'), check=False)
263 def run_get(disposition, method, what=None, given=None):
266 ex((bup_cmd, b'-d', b'get-dest', b'init'))
269 # FIXME: replace bup-get with independent commands as is feasible
270 exr = _run_get(disposition, b'--replace', given)
272 return _run_get(disposition, method, what)
274 def test_universal_behaviors(get_disposition):
275 methods = (b'--ff', b'--append', b'--pick', b'--force-pick', b'--new-tag',
276 b'--replace', b'--unnamed')
277 for method in methods:
278 mmsg = method.decode('ascii')
279 wvstart(get_disposition + ' ' + mmsg + ', missing source, fails')
280 exr = run_get(get_disposition, method, b'not-there')
282 verify_rx(br'cannot find source', exr.err)
283 for method in methods:
284 mmsg = method.decode('ascii')
285 wvstart(get_disposition + ' ' + mmsg + ' / fails')
286 exr = run_get(get_disposition, method, b'/')
288 verify_rx(b'cannot fetch entire repository', exr.err)
290 def verify_only_refs(**kwargs):
291 for kind, refs in items(kwargs):
293 abs_refs = [b'refs/heads/' + ref for ref in refs]
296 abs_refs = [b'refs/tags/' + ref for ref in refs]
299 raise TypeError('unexpected keyword argument %r' % kind)
301 verify_rcz([b'git', b'--git-dir', b'get-dest',
302 b'show-ref', b'--verify', karg] + abs_refs)
303 exr = exo((b'git', b'--git-dir', b'get-dest', b'show-ref', karg),
306 expected_refs = sorted(abs_refs)
307 repo_refs = sorted([x.split()[1] for x in exr.out.splitlines()])
308 wvpasseq(expected_refs, repo_refs)
310 # FIXME: can we just check "git show-ref --heads == ''"?
311 exr = exo((b'git', b'--git-dir', b'get-dest', b'show-ref', karg),
314 wvpasseq(b'', exr.out.strip())
316 def test_replace(get_disposition, src_info):
317 print('blarg:', repr(src_info), file=sys.stderr)
319 wvstart(get_disposition + ' --replace to root fails')
320 for item in (b'.tag/tinyfile',
321 b'src/latest' + src_info['tinyfile-path'],
323 b'src/latest' + src_info['subtree-vfs-path'],
327 exr = run_get(get_disposition, b'--replace', (item, b'/'))
329 verify_rx(br'impossible; can only overwrite branch or tag', exr.err)
331 tinyfile_id = src_info['tinyfile-id']
332 tinyfile_path = src_info['tinyfile-path']
333 subtree_vfs_path = src_info['subtree-vfs-path']
334 subtree_id = src_info['subtree-id']
335 commit_2_id = src_info['commit-2-id']
336 tree_2_id = src_info['tree-2-id']
339 existing_items = {'nothing' : None,
340 'blob' : (b'.tag/tinyfile', b'.tag/obj'),
341 'tree' : (b'.tag/tree-1', b'.tag/obj'),
342 'commit': (b'.tag/commit-1', b'.tag/obj')}
343 for ex_type, ex_ref in items(existing_items):
344 wvstart(get_disposition + ' --replace ' + ex_type + ' with blob tag')
345 for item in (b'.tag/tinyfile', b'src/latest' + tinyfile_path):
346 exr = run_get(get_disposition, b'--replace', (item ,b'.tag/obj'),
349 validate_blob(tinyfile_id, tinyfile_id)
350 verify_only_refs(heads=[], tags=(b'obj',))
351 wvstart(get_disposition + ' --replace ' + ex_type + ' with tree tag')
352 for item in (b'.tag/subtree', b'src/latest' + subtree_vfs_path):
353 exr = run_get(get_disposition, b'--replace', (item, b'.tag/obj'),
355 validate_tree(subtree_id, subtree_id)
356 verify_only_refs(heads=[], tags=(b'obj',))
357 wvstart(get_disposition + ' --replace ' + ex_type + ' with commitish tag')
358 for item in (b'.tag/commit-2', b'src/latest', b'src'):
359 exr = run_get(get_disposition, b'--replace', (item, b'.tag/obj'),
361 validate_tagged_save(b'obj', getcwd() + b'/src',
362 commit_2_id, tree_2_id, b'src-2', exr.out)
363 verify_only_refs(heads=[], tags=(b'obj',))
365 # Committish to branch.
366 existing_items = (('nothing', None),
367 ('branch', (b'.tag/commit-1', b'obj')))
368 for ex_type, ex_ref in existing_items:
369 for item_type, item in (('commit', b'.tag/commit-2'),
370 ('save', b'src/latest'),
372 wvstart(get_disposition + ' --replace '
373 + ex_type + ' with ' + item_type)
374 exr = run_get(get_disposition, b'--replace', (item, b'obj'),
376 validate_save(b'obj/latest', getcwd() + b'/src',
377 commit_2_id, tree_2_id, b'src-2', exr.out)
378 verify_only_refs(heads=(b'obj',), tags=[])
380 # Not committish to branch
381 existing_items = (('nothing', None),
382 ('branch', (b'.tag/commit-1', b'obj')))
383 for ex_type, ex_ref in existing_items:
384 for item_type, item in (('blob', b'.tag/tinyfile'),
385 ('blob', b'src/latest' + tinyfile_path),
386 ('tree', b'.tag/subtree'),
387 ('tree', b'src/latest' + subtree_vfs_path)):
388 wvstart(get_disposition + ' --replace branch with '
389 + item_type + ' given ' + ex_type + ' fails')
391 exr = run_get(get_disposition, b'--replace', (item, b'obj'),
394 verify_rx(br'cannot overwrite branch with .+ for', exr.err)
396 wvstart(get_disposition + ' --replace, implicit destinations')
398 exr = run_get(get_disposition, b'--replace', b'src')
399 validate_save(b'src/latest', getcwd() + b'/src',
400 commit_2_id, tree_2_id, b'src-2', exr.out)
401 verify_only_refs(heads=(b'src',), tags=[])
403 exr = run_get(get_disposition, b'--replace', b'.tag/commit-2')
404 validate_tagged_save(b'commit-2', getcwd() + b'/src',
405 commit_2_id, tree_2_id, b'src-2', exr.out)
406 verify_only_refs(heads=[], tags=(b'commit-2',))
408 def test_ff(get_disposition, src_info):
410 wvstart(get_disposition + ' --ff to root fails')
411 tinyfile_path = src_info['tinyfile-path']
412 for item in (b'.tag/tinyfile', b'src/latest' + tinyfile_path):
413 exr = run_get(get_disposition, b'--ff', (item, b'/'))
415 verify_rx(br'source for .+ must be a branch, save, or commit', exr.err)
416 subtree_vfs_path = src_info['subtree-vfs-path']
417 for item in (b'.tag/subtree', b'src/latest' + subtree_vfs_path):
418 exr = run_get(get_disposition, b'--ff', (item, b'/'))
420 verify_rx(br'is impossible; can only --append a tree to a branch',
422 for item in (b'.tag/commit-1', b'src/latest', b'src'):
423 exr = run_get(get_disposition, b'--ff', (item, b'/'))
425 verify_rx(br'destination for .+ is a root, not a branch', exr.err)
427 wvstart(get_disposition + ' --ff of not-committish fails')
428 for src in (b'.tag/tinyfile', b'src/latest' + tinyfile_path):
429 # FIXME: use get_item elsewhere?
430 for given, get_item in ((None, (src, b'obj')),
431 (None, (src, b'.tag/obj')),
432 ((b'.tag/tinyfile', b'.tag/obj'), (src, b'.tag/obj')),
433 ((b'.tag/tree-1', b'.tag/obj'), (src, b'.tag/obj')),
434 ((b'.tag/commit-1', b'.tag/obj'), (src, b'.tag/obj')),
435 ((b'.tag/commit-1', b'obj'), (src, b'obj'))):
436 exr = run_get(get_disposition, b'--ff', get_item, given=given)
438 verify_rx(br'must be a branch, save, or commit', exr.err)
439 for src in (b'.tag/subtree', b'src/latest' + subtree_vfs_path):
440 for given, get_item in ((None, (src, b'obj')),
441 (None, (src, b'.tag/obj')),
442 ((b'.tag/tinyfile', b'.tag/obj'), (src, b'.tag/obj')),
443 ((b'.tag/tree-1', b'.tag/obj'), (src, b'.tag/obj')),
444 ((b'.tag/commit-1', b'.tag/obj'), (src, b'.tag/obj')),
445 ((b'.tag/commit-1', b'obj'), (src, b'obj'))):
446 exr = run_get(get_disposition, b'--ff', get_item, given=given)
448 verify_rx(br'can only --append a tree to a branch', exr.err)
450 wvstart(get_disposition + ' --ff committish, ff possible')
451 save_2 = src_info['save-2']
452 for src in (b'.tag/commit-2', b'src/' + save_2, b'src'):
453 for given, get_item, complaint in \
454 ((None, (src, b'.tag/obj'),
455 br'destination .+ must be a valid branch name'),
456 ((b'.tag/tinyfile', b'.tag/obj'), (src, b'.tag/obj'),
457 br'destination .+ is a blob, not a branch'),
458 ((b'.tag/tree-1', b'.tag/obj'), (src, b'.tag/obj'),
459 br'destination .+ is a tree, not a branch'),
460 ((b'.tag/commit-1', b'.tag/obj'), (src, b'.tag/obj'),
461 br'destination .+ is a tagged commit, not a branch'),
462 ((b'.tag/commit-2', b'.tag/obj'), (src, b'.tag/obj'),
463 br'destination .+ is a tagged commit, not a branch')):
464 exr = run_get(get_disposition, b'--ff', get_item, given=given)
466 verify_rx(complaint, exr.err)
467 # FIXME: use src or item and given or existing consistently in loops...
468 commit_2_id = src_info['commit-2-id']
469 tree_2_id = src_info['tree-2-id']
470 for src in (b'.tag/commit-2', b'src/' + save_2, b'src'):
471 for given in (None, (b'.tag/commit-1', b'obj'), (b'.tag/commit-2', b'obj')):
472 exr = run_get(get_disposition, b'--ff', (src, b'obj'), given=given)
474 validate_save(b'obj/latest', getcwd() + b'/src',
475 commit_2_id, tree_2_id, b'src-2', exr.out)
476 verify_only_refs(heads=(b'obj',), tags=[])
478 wvstart(get_disposition + ' --ff, implicit destinations')
479 for item in (b'src', b'src/latest'):
480 exr = run_get(get_disposition, b'--ff', item)
483 ex((b'find', b'get-dest/refs'))
484 ex((bup_cmd, b'-d', b'get-dest', b'ls'))
486 validate_save(b'src/latest', getcwd() + b'/src',
487 commit_2_id, tree_2_id, b'src-2', exr.out)
488 #verify_only_refs(heads=('src',), tags=[])
490 wvstart(get_disposition + ' --ff, ff impossible')
491 for given, get_item in (((b'unrelated-branch', b'src'), b'src'),
492 ((b'.tag/commit-2', b'src'), (b'.tag/commit-1', b'src'))):
493 exr = run_get(get_disposition, b'--ff', get_item, given=given)
495 verify_rx(br'destination is not an ancestor of source', exr.err)
497 def test_append(get_disposition, src_info):
498 tinyfile_path = src_info['tinyfile-path']
499 subtree_vfs_path = src_info['subtree-vfs-path']
501 wvstart(get_disposition + ' --append to root fails')
502 for item in (b'.tag/tinyfile', b'src/latest' + tinyfile_path):
503 exr = run_get(get_disposition, b'--append', (item, b'/'))
505 verify_rx(br'source for .+ must be a branch, save, commit, or tree',
507 for item in (b'.tag/subtree', b'src/latest' + subtree_vfs_path,
508 b'.tag/commit-1', b'src/latest', b'src'):
509 exr = run_get(get_disposition, b'--append', (item, b'/'))
511 verify_rx(br'destination for .+ is a root, not a branch', exr.err)
513 wvstart(get_disposition + ' --append of not-treeish fails')
514 for src in (b'.tag/tinyfile', b'src/latest' + tinyfile_path):
515 for given, item in ((None, (src, b'obj')),
516 (None, (src, b'.tag/obj')),
517 ((b'.tag/tinyfile', b'.tag/obj'), (src, b'.tag/obj')),
518 ((b'.tag/tree-1', b'.tag/obj'), (src, b'.tag/obj')),
519 ((b'.tag/commit-1', b'.tag/obj'), (src, b'.tag/obj')),
520 ((b'.tag/commit-1', b'obj'), (src, b'obj'))):
521 exr = run_get(get_disposition, b'--append', item, given=given)
523 verify_rx(br'must be a branch, save, commit, or tree', exr.err)
525 wvstart(get_disposition + ' --append committish failure cases')
526 save_2 = src_info['save-2']
527 for src in (b'.tag/subtree', b'src/latest' + subtree_vfs_path,
528 b'.tag/commit-2', b'src/' + save_2, b'src'):
529 for given, item, complaint in \
530 ((None, (src, b'.tag/obj'),
531 br'destination .+ must be a valid branch name'),
532 ((b'.tag/tinyfile', b'.tag/obj'), (src, b'.tag/obj'),
533 br'destination .+ is a blob, not a branch'),
534 ((b'.tag/tree-1', b'.tag/obj'), (src, b'.tag/obj'),
535 br'destination .+ is a tree, not a branch'),
536 ((b'.tag/commit-1', b'.tag/obj'), (src, b'.tag/obj'),
537 br'destination .+ is a tagged commit, not a branch'),
538 ((b'.tag/commit-2', b'.tag/obj'), (src, b'.tag/obj'),
539 br'destination .+ is a tagged commit, not a branch')):
540 exr = run_get(get_disposition, b'--append', item, given=given)
542 verify_rx(complaint, exr.err)
544 wvstart(get_disposition + ' --append committish')
545 commit_2_id = src_info['commit-2-id']
546 tree_2_id = src_info['tree-2-id']
547 for item in (b'.tag/commit-2', b'src/' + save_2, b'src'):
548 for existing in (None, (b'.tag/commit-1', b'obj'),
549 (b'.tag/commit-2', b'obj'),
550 (b'unrelated-branch', b'obj')):
551 exr = run_get(get_disposition, b'--append', (item, b'obj'),
554 validate_new_save(b'obj/latest', getcwd() + b'/src',
555 commit_2_id, tree_2_id, b'src-2', exr.out)
556 verify_only_refs(heads=(b'obj',), tags=[])
558 save_1 = src_info['save-1']
559 commit_1_id = src_info['commit-1-id']
560 tree_1_id = src_info['tree-1-id']
561 for item in (b'.tag/commit-1', b'src/' + save_1, b'src-1'):
562 exr = run_get(get_disposition, b'--append', (item, b'obj'),
563 given=(b'.tag/commit-2', b'obj'))
565 validate_new_save(b'obj/latest', getcwd() + b'/src',
566 commit_1_id, tree_1_id, b'src-1', exr.out)
567 verify_only_refs(heads=(b'obj',), tags=[])
569 wvstart(get_disposition + ' --append tree')
570 subtree_path = src_info['subtree-path']
571 subtree_id = src_info['subtree-id']
572 for item in (b'.tag/subtree', b'src/latest' + subtree_vfs_path):
573 for existing in (None,
574 (b'.tag/commit-1', b'obj'),
575 (b'.tag/commit-2', b'obj')):
576 exr = run_get(get_disposition, b'--append', (item, b'obj'),
579 validate_new_save(b'obj/latest', b'/', None, subtree_id, subtree_path,
581 verify_only_refs(heads=(b'obj',), tags=[])
583 wvstart(get_disposition + ' --append, implicit destinations')
585 for item in (b'src', b'src/latest'):
586 exr = run_get(get_disposition, b'--append', item)
588 validate_new_save(b'src/latest', getcwd() + b'/src', commit_2_id, tree_2_id,
590 verify_only_refs(heads=(b'src',), tags=[])
592 def test_pick(get_disposition, src_info, force=False):
593 flavor = b'--force-pick' if force else b'--pick'
594 flavormsg = flavor.decode('ascii')
595 tinyfile_path = src_info['tinyfile-path']
596 subtree_vfs_path = src_info['subtree-vfs-path']
598 wvstart(get_disposition + ' ' + flavormsg + ' to root fails')
599 for item in (b'.tag/tinyfile', b'src/latest' + tinyfile_path, b'src'):
600 exr = run_get(get_disposition, flavor, (item, b'/'))
602 verify_rx(br'can only pick a commit or save', exr.err)
603 for item in (b'.tag/commit-1', b'src/latest'):
604 exr = run_get(get_disposition, flavor, (item, b'/'))
606 verify_rx(br'destination is not a tag or branch', exr.err)
607 for item in (b'.tag/subtree', b'src/latest' + subtree_vfs_path):
608 exr = run_get(get_disposition, flavor, (item, b'/'))
610 verify_rx(br'is impossible; can only --append a tree', exr.err)
612 wvstart(get_disposition + ' ' + flavormsg + ' of blob or branch fails')
613 for item in (b'.tag/tinyfile', b'src/latest' + tinyfile_path, b'src'):
614 for given, get_item in ((None, (item, b'obj')),
615 (None, (item, b'.tag/obj')),
616 ((b'.tag/tinyfile', b'.tag/obj'), (item, b'.tag/obj')),
617 ((b'.tag/tree-1', b'.tag/obj'), (item, b'.tag/obj')),
618 ((b'.tag/commit-1', b'.tag/obj'), (item, b'.tag/obj')),
619 ((b'.tag/commit-1', b'obj'), (item, b'obj'))):
620 exr = run_get(get_disposition, flavor, get_item, given=given)
622 verify_rx(br'impossible; can only pick a commit or save', exr.err)
624 wvstart(get_disposition + ' ' + flavormsg + ' of tree fails')
625 for item in (b'.tag/subtree', b'src/latest' + subtree_vfs_path):
626 for given, get_item in ((None, (item, b'obj')),
627 (None, (item, b'.tag/obj')),
628 ((b'.tag/tinyfile', b'.tag/obj'), (item, b'.tag/obj')),
629 ((b'.tag/tree-1', b'.tag/obj'), (item, b'.tag/obj')),
630 ((b'.tag/commit-1', b'.tag/obj'), (item, b'.tag/obj')),
631 ((b'.tag/commit-1', b'obj'), (item, b'obj'))):
632 exr = run_get(get_disposition, flavor, get_item, given=given)
634 verify_rx(br'impossible; can only --append a tree', exr.err)
636 save_2 = src_info['save-2']
637 commit_2_id = src_info['commit-2-id']
638 tree_2_id = src_info['tree-2-id']
639 # FIXME: these two wvstart texts?
641 wvstart(get_disposition + ' ' + flavormsg + ' commit/save to existing tag')
642 for item in (b'.tag/commit-2', b'src/' + save_2):
643 for given in ((b'.tag/tinyfile', b'.tag/obj'),
644 (b'.tag/tree-1', b'.tag/obj'),
645 (b'.tag/commit-1', b'.tag/obj')):
646 exr = run_get(get_disposition, flavor, (item, b'.tag/obj'),
649 validate_new_tagged_commit(b'obj', commit_2_id, tree_2_id,
651 verify_only_refs(heads=[], tags=(b'obj',))
653 wvstart(get_disposition + ' ' + flavormsg
654 + ' commit/save to existing tag fails')
655 for item in (b'.tag/commit-2', b'src/' + save_2):
656 for given in ((b'.tag/tinyfile', b'.tag/obj'),
657 (b'.tag/tree-1', b'.tag/obj'),
658 (b'.tag/commit-1', b'.tag/obj')):
659 exr = run_get(get_disposition, flavor, (item, b'.tag/obj'), given=given)
661 verify_rx(br'cannot overwrite existing tag', exr.err)
663 wvstart(get_disposition + ' ' + flavormsg + ' commit/save to tag')
664 for item in (b'.tag/commit-2', b'src/' + save_2):
665 exr = run_get(get_disposition, flavor, (item, b'.tag/obj'))
667 validate_clean_repo()
668 validate_new_tagged_commit(b'obj', commit_2_id, tree_2_id, exr.out)
669 verify_only_refs(heads=[], tags=(b'obj',))
671 wvstart(get_disposition + ' ' + flavormsg + ' commit/save to branch')
672 for item in (b'.tag/commit-2', b'src/' + save_2):
673 for given in (None, (b'.tag/commit-1', b'obj'), (b'.tag/commit-2', b'obj')):
674 exr = run_get(get_disposition, flavor, (item, b'obj'), given=given)
676 validate_clean_repo()
677 validate_new_save(b'obj/latest', getcwd() + b'/src',
678 commit_2_id, tree_2_id, b'src-2', exr.out)
679 verify_only_refs(heads=(b'obj',), tags=[])
681 wvstart(get_disposition + ' ' + flavormsg
682 + ' commit/save unrelated commit to branch')
683 for item in(b'.tag/commit-2', b'src/' + save_2):
684 exr = run_get(get_disposition, flavor, (item, b'obj'),
685 given=(b'unrelated-branch', b'obj'))
687 validate_clean_repo()
688 validate_new_save(b'obj/latest', getcwd() + b'/src',
689 commit_2_id, tree_2_id, b'src-2', exr.out)
690 verify_only_refs(heads=(b'obj',), tags=[])
692 wvstart(get_disposition + ' ' + flavormsg + ' commit/save ancestor to branch')
693 save_1 = src_info['save-1']
694 commit_1_id = src_info['commit-1-id']
695 tree_1_id = src_info['tree-1-id']
696 for item in (b'.tag/commit-1', b'src/' + save_1):
697 exr = run_get(get_disposition, flavor, (item, b'obj'),
698 given=(b'.tag/commit-2', b'obj'))
700 validate_clean_repo()
701 validate_new_save(b'obj/latest', getcwd() + b'/src',
702 commit_1_id, tree_1_id, b'src-1', exr.out)
703 verify_only_refs(heads=(b'obj',), tags=[])
706 wvstart(get_disposition + ' ' + flavormsg + ', implicit destinations')
707 exr = run_get(get_disposition, flavor, b'.tag/commit-2')
709 validate_clean_repo()
710 validate_new_tagged_commit(b'commit-2', commit_2_id, tree_2_id, exr.out)
711 verify_only_refs(heads=[], tags=(b'commit-2',))
713 exr = run_get(get_disposition, flavor, b'src/latest')
715 validate_clean_repo()
716 validate_new_save(b'src/latest', getcwd() + b'/src',
717 commit_2_id, tree_2_id, b'src-2', exr.out)
718 verify_only_refs(heads=(b'src',), tags=[])
720 def test_new_tag(get_disposition, src_info):
721 tinyfile_id = src_info['tinyfile-id']
722 tinyfile_path = src_info['tinyfile-path']
723 commit_2_id = src_info['commit-2-id']
724 tree_2_id = src_info['tree-2-id']
725 subtree_id = src_info['subtree-id']
726 subtree_vfs_path = src_info['subtree-vfs-path']
728 wvstart(get_disposition + ' --new-tag to root fails')
729 for item in (b'.tag/tinyfile',
730 b'src/latest' + tinyfile_path,
732 b'src/latest' + subtree_vfs_path,
736 exr = run_get(get_disposition, b'--new-tag', (item, b'/'))
738 verify_rx(br'destination for .+ must be a VFS tag', exr.err)
740 # Anything to new tag.
741 wvstart(get_disposition + ' --new-tag, blob tag')
742 for item in (b'.tag/tinyfile', b'src/latest' + tinyfile_path):
743 exr = run_get(get_disposition, b'--new-tag', (item, b'.tag/obj'))
745 validate_blob(tinyfile_id, tinyfile_id)
746 verify_only_refs(heads=[], tags=(b'obj',))
748 wvstart(get_disposition + ' --new-tag, tree tag')
749 for item in (b'.tag/subtree', b'src/latest' + subtree_vfs_path):
750 exr = run_get(get_disposition, b'--new-tag', (item, b'.tag/obj'))
752 validate_tree(subtree_id, subtree_id)
753 verify_only_refs(heads=[], tags=(b'obj',))
755 wvstart(get_disposition + ' --new-tag, committish tag')
756 for item in (b'.tag/commit-2', b'src/latest', b'src'):
757 exr = run_get(get_disposition, b'--new-tag', (item, b'.tag/obj'))
759 validate_tagged_save(b'obj', getcwd() + b'/src/', commit_2_id, tree_2_id,
761 verify_only_refs(heads=[], tags=(b'obj',))
763 # Anything to existing tag (fails).
764 for ex_type, ex_tag in (('blob', (b'.tag/tinyfile', b'.tag/obj')),
765 ('tree', (b'.tag/tree-1', b'.tag/obj')),
766 ('commit', (b'.tag/commit-1', b'.tag/obj'))):
767 for item_type, item in (('blob tag', b'.tag/tinyfile'),
768 ('blob path', b'src/latest' + tinyfile_path),
769 ('tree tag', b'.tag/subtree'),
770 ('tree path', b'src/latest' + subtree_vfs_path),
771 ('commit tag', b'.tag/commit-2'),
772 ('save', b'src/latest'),
774 wvstart(get_disposition + ' --new-tag of ' + item_type
775 + ', given existing ' + ex_type + ' tag, fails')
776 exr = run_get(get_disposition, b'--new-tag', (item, b'.tag/obj'),
779 verify_rx(br'cannot overwrite existing tag .* \(requires --replace\)',
782 # Anything to branch (fails).
783 for ex_type, ex_tag in (('nothing', None),
784 ('blob', (b'.tag/tinyfile', b'.tag/obj')),
785 ('tree', (b'.tag/tree-1', b'.tag/obj')),
786 ('commit', (b'.tag/commit-1', b'.tag/obj'))):
787 for item_type, item in (('blob tag', b'.tag/tinyfile'),
788 ('blob path', b'src/latest' + tinyfile_path),
789 ('tree tag', b'.tag/subtree'),
790 ('tree path', b'src/latest' + subtree_vfs_path),
791 ('commit tag', b'.tag/commit-2'),
792 ('save', b'src/latest'),
794 wvstart(get_disposition + ' --new-tag to branch of ' + item_type
795 + ', given existing ' + ex_type + ' tag, fails')
796 exr = run_get(get_disposition, b'--new-tag', (item, b'obj'),
799 verify_rx(br'destination for .+ must be a VFS tag', exr.err)
801 wvstart(get_disposition + ' --new-tag, implicit destinations')
802 exr = run_get(get_disposition, b'--new-tag', b'.tag/commit-2')
804 validate_tagged_save(b'commit-2', getcwd() + b'/src/', commit_2_id, tree_2_id,
806 verify_only_refs(heads=[], tags=(b'commit-2',))
808 def test_unnamed(get_disposition, src_info):
809 tinyfile_id = src_info['tinyfile-id']
810 tinyfile_path = src_info['tinyfile-path']
811 subtree_vfs_path = src_info['subtree-vfs-path']
812 wvstart(get_disposition + ' --unnamed to root fails')
813 for item in (b'.tag/tinyfile',
814 b'src/latest' + tinyfile_path,
816 b'src/latest' + subtree_vfs_path,
820 for ex_ref in (None, (item, b'.tag/obj')):
821 exr = run_get(get_disposition, b'--unnamed', (item, b'/'),
824 verify_rx(br'usage: bup get ', exr.err)
826 wvstart(get_disposition + ' --unnamed file')
827 for item in (b'.tag/tinyfile', b'src/latest' + tinyfile_path):
828 exr = run_get(get_disposition, b'--unnamed', item)
830 validate_blob(tinyfile_id, tinyfile_id)
831 verify_only_refs(heads=[], tags=[])
833 exr = run_get(get_disposition, b'--unnamed', item,
834 given=(item, b'.tag/obj'))
836 validate_blob(tinyfile_id, tinyfile_id)
837 verify_only_refs(heads=[], tags=(b'obj',))
839 wvstart(get_disposition + ' --unnamed tree')
840 subtree_id = src_info['subtree-id']
841 for item in (b'.tag/subtree', b'src/latest' + subtree_vfs_path):
842 exr = run_get(get_disposition, b'--unnamed', item)
844 validate_tree(subtree_id, subtree_id)
845 verify_only_refs(heads=[], tags=[])
847 exr = run_get(get_disposition, b'--unnamed', item,
848 given=(item, b'.tag/obj'))
850 validate_tree(subtree_id, subtree_id)
851 verify_only_refs(heads=[], tags=(b'obj',))
853 wvstart(get_disposition + ' --unnamed committish')
854 save_2 = src_info['save-2']
855 commit_2_id = src_info['commit-2-id']
856 for item in (b'.tag/commit-2', b'src/' + save_2, b'src'):
857 exr = run_get(get_disposition, b'--unnamed', item)
859 validate_commit(commit_2_id, commit_2_id)
860 verify_only_refs(heads=[], tags=[])
862 exr = run_get(get_disposition, b'--unnamed', item,
863 given=(item, b'.tag/obj'))
865 validate_commit(commit_2_id, commit_2_id)
866 verify_only_refs(heads=[], tags=(b'obj',))
868 def create_get_src():
869 global bup_cmd, src_info
871 ex((bup_cmd, b'-d', b'get-src', b'init'))
874 open(b'src/unrelated', 'a').close()
875 ex((bup_cmd, b'-d', b'get-src', b'index', b'src'))
876 ex((bup_cmd, b'-d', b'get-src', b'save', b'-tcn', b'unrelated-branch', b'src'))
878 ex((bup_cmd, b'-d', b'get-src', b'index', b'--clear'))
881 open(b'src/zero', 'a').close()
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_0_id = out[-1]
887 exr = exo((bup_cmd, b'-d', b'get-src', b'ls', b'src'))
888 save_0 = exr.out.splitlines()[0]
889 ex((b'git', b'--git-dir', b'get-src', b'branch', b'src-0', b'src'))
890 ex((b'cp', b'-RPp', b'src', b'src-0'))
896 ex((bup_cmd + b' -d get-src random 1k > src/1'), shell=True)
897 ex((bup_cmd + b' -d get-src random 1k > src/x/2'), shell=True)
898 ex((bup_cmd, b'-d', b'get-src', b'index', b'src'))
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_1_id = out[-1]
903 exr = exo((bup_cmd, b'-d', b'get-src', b'ls', b'src'))
904 save_1 = exr.out.splitlines()[1]
905 ex((b'git', b'--git-dir', b'get-src', b'branch', b'src-1', b'src'))
906 ex((b'cp', b'-RPp', b'src', b'src-1'))
908 # Make a copy the current state of src so we'll have an ancestor.
910 b'get-src/refs/heads/src', b'get-src/refs/heads/src-ancestor'))
912 with open(b'src/tiny-file', 'ab') as f: f.write(b'xyzzy')
913 ex((bup_cmd, b'-d', b'get-src', b'index', b'src'))
914 ex((bup_cmd, b'-d', b'get-src', b'tick')) # Ensure the save names differ
915 exr = exo((bup_cmd, b'-d', b'get-src', b'save', b'-tcn', b'src', b'src'))
916 out = exr.out.splitlines()
918 commit_2_id = out[-1]
919 exr = exo((bup_cmd, b'-d', b'get-src', b'ls', b'src'))
920 save_2 = exr.out.splitlines()[2]
921 rename(b'src', b'src-2')
923 src_root = getcwd() + b'/src'
925 subtree_path = b'src-2/x'
926 subtree_vfs_path = src_root + b'/x'
928 # No support for "ls -d", so grep...
929 exr = exo((bup_cmd, b'-d', b'get-src', b'ls', b'-s', b'src/latest' + src_root))
930 out = exr.out.splitlines()
934 subtree_id = line.split()[0]
937 # With a tiny file, we'll get a single blob, not a chunked tree
938 tinyfile_path = src_root + b'/tiny-file'
939 exr = exo((bup_cmd, b'-d', b'get-src', b'ls', b'-s', b'src/latest' + tinyfile_path))
940 tinyfile_id = exr.out.splitlines()[0].split()[0]
942 ex((bup_cmd, b'-d', b'get-src', b'tag', b'tinyfile', tinyfile_id))
943 ex((bup_cmd, b'-d', b'get-src', b'tag', b'subtree', subtree_id))
944 ex((bup_cmd, b'-d', b'get-src', b'tag', b'tree-0', tree_0_id))
945 ex((bup_cmd, b'-d', b'get-src', b'tag', b'tree-1', tree_1_id))
946 ex((bup_cmd, b'-d', b'get-src', b'tag', b'tree-2', tree_2_id))
947 ex((bup_cmd, b'-d', b'get-src', b'tag', b'commit-0', commit_0_id))
948 ex((bup_cmd, b'-d', b'get-src', b'tag', b'commit-1', commit_1_id))
949 ex((bup_cmd, b'-d', b'get-src', b'tag', b'commit-2', commit_2_id))
950 ex((b'git', b'--git-dir', b'get-src', b'branch', b'commit-1', commit_1_id))
951 ex((b'git', b'--git-dir', b'get-src', b'branch', b'commit-2', commit_2_id))
953 return {'tinyfile-path' : tinyfile_path,
954 'tinyfile-id' : tinyfile_id,
955 'subtree-id' : subtree_id,
956 'tree-0-id' : tree_0_id,
957 'tree-1-id' : tree_1_id,
958 'tree-2-id' : tree_2_id,
959 'commit-0-id' : commit_0_id,
960 'commit-1-id' : commit_1_id,
961 'commit-2-id' : commit_2_id,
964 'subtree-path' : subtree_path,
965 'subtree-vfs-path' : subtree_vfs_path}
967 # FIXME: this fails in a strange way:
968 # WVPASS given nothing get --ff not-there
970 dispositions_to_test = ('get',)
972 if int(environ.get(b'BUP_TEST_LEVEL', b'0')) >= 11:
973 dispositions_to_test += ('get-on', 'get-to')
975 if len(compat.argv) == 1:
976 categories = ('replace', 'universal', 'ff', 'append', 'pick', 'new-tag',
979 categories = compat.argv[1:]
981 with test_tempdir(b'get-') as tmpdir:
984 src_info = create_get_src()
985 for category in categories:
986 for disposition in dispositions_to_test:
987 # given=FOO depends on --replace, so test it early
988 if category == 'replace':
989 test_replace(disposition, src_info)
990 elif category == 'universal':
991 test_universal_behaviors(disposition)
992 elif category == 'ff':
993 test_ff(disposition, src_info)
994 elif category == 'append':
995 test_append(disposition, src_info)
996 elif category == 'pick':
997 test_pick(disposition, src_info, force=False)
998 test_pick(disposition, src_info, force=True)
999 elif category == 'new-tag':
1000 test_new_tag(disposition, src_info)
1001 elif category == 'unnamed':
1002 test_unnamed(disposition, src_info)
1004 raise Exception('unrecognized get test category')
1005 except Exception as ex:
1010 wvmsg('checked %d cases' % get_cases_tested)