summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xrepo50
-rw-r--r--subcmds/init.py11
-rw-r--r--tests/test_wrapper.py156
3 files changed, 195 insertions, 22 deletions
diff --git a/repo b/repo
index c78fcacd..66a2a07d 100755
--- a/repo
+++ b/repo
@@ -463,6 +463,34 @@ class CloneFailure(Exception):
463 """ 463 """
464 464
465 465
466def check_repo_verify(repo_verify, quiet=False):
467 """Check the --repo-verify state."""
468 if not repo_verify:
469 print('repo: warning: verification of repo code has been disabled;\n'
470 'repo will not be able to verify the integrity of itself.\n',
471 file=sys.stderr)
472 return False
473
474 if NeedSetupGnuPG():
475 return SetupGnuPG(quiet)
476
477 return True
478
479
480def check_repo_rev(dst, rev, repo_verify=True, quiet=False):
481 """Check that |rev| is valid."""
482 do_verify = check_repo_verify(repo_verify, quiet=quiet)
483 remote_ref, local_rev = resolve_repo_rev(dst, rev)
484 if not quiet and not remote_ref.startswith('refs/heads/'):
485 print('warning: repo is not tracking a remote branch, so it will not '
486 'receive updates', file=sys.stderr)
487 if do_verify:
488 rev = verify_rev(dst, remote_ref, local_rev, quiet)
489 else:
490 rev = local_rev
491 return (remote_ref, rev)
492
493
466def _Init(args, gitc_init=False): 494def _Init(args, gitc_init=False):
467 """Installs repo by cloning it over the network. 495 """Installs repo by cloning it over the network.
468 """ 496 """
@@ -510,30 +538,12 @@ def _Init(args, gitc_init=False):
510 538
511 _CheckGitVersion() 539 _CheckGitVersion()
512 try: 540 try:
513 if not opt.repo_verify:
514 do_verify = False
515 print('repo: warning: verification of repo code has been disabled;\n'
516 'repo will not be able to verify the integrity of itself.\n',
517 file=sys.stderr)
518 else:
519 if NeedSetupGnuPG():
520 do_verify = SetupGnuPG(opt.quiet)
521 else:
522 do_verify = True
523
524 if not opt.quiet: 541 if not opt.quiet:
525 print('Downloading Repo source from', url) 542 print('Downloading Repo source from', url)
526 dst = os.path.abspath(os.path.join(repodir, S_repo)) 543 dst = os.path.abspath(os.path.join(repodir, S_repo))
527 _Clone(url, dst, opt.clone_bundle, opt.quiet, opt.verbose) 544 _Clone(url, dst, opt.clone_bundle, opt.quiet, opt.verbose)
528 545
529 remote_ref, local_rev = resolve_repo_rev(dst, rev) 546 remote_ref, rev = check_repo_rev(dst, rev, opt.repo_verify, quiet=opt.quiet)
530 if not opt.quiet and not remote_ref.startswith('refs/heads/'):
531 print('warning: repo is not tracking a remote branch, so it will not '
532 'receive updates', file=sys.stderr)
533 if do_verify:
534 rev = _Verify(dst, remote_ref, local_rev, opt.quiet)
535 else:
536 rev = local_rev
537 _Checkout(dst, remote_ref, rev, opt.quiet) 547 _Checkout(dst, remote_ref, rev, opt.quiet)
538 548
539 if not os.path.isfile(os.path.join(dst, 'repo')): 549 if not os.path.isfile(os.path.join(dst, 'repo')):
@@ -907,7 +917,7 @@ def resolve_repo_rev(cwd, committish):
907 raise CloneFailure() 917 raise CloneFailure()
908 918
909 919
910def _Verify(cwd, remote_ref, rev, quiet): 920def verify_rev(cwd, remote_ref, rev, quiet):
911 """Verify the commit has been signed by a tag.""" 921 """Verify the commit has been signed by a tag."""
912 ret = run_git('describe', rev, cwd=cwd) 922 ret = run_git('describe', rev, cwd=cwd)
913 cur = ret.stdout.strip() 923 cur = ret.stdout.strip()
diff --git a/subcmds/init.py b/subcmds/init.py
index 431165d4..ce8b0187 100644
--- a/subcmds/init.py
+++ b/subcmds/init.py
@@ -38,6 +38,7 @@ from project import SyncBuffer
38from git_config import GitConfig 38from git_config import GitConfig
39from git_command import git_require, MIN_GIT_VERSION_SOFT, MIN_GIT_VERSION_HARD 39from git_command import git_require, MIN_GIT_VERSION_SOFT, MIN_GIT_VERSION_HARD
40import platform_utils 40import platform_utils
41from wrapper import Wrapper
41 42
42 43
43class Init(InteractiveCommand, MirrorSafeCommand): 44class Init(InteractiveCommand, MirrorSafeCommand):
@@ -499,6 +500,16 @@ to update the working directory files.
499 remote.url = opt.repo_url 500 remote.url = opt.repo_url
500 remote.Save() 501 remote.Save()
501 502
503 # Handle new --repo-rev requests.
504 if opt.repo_rev:
505 wrapper = Wrapper()
506 remote_ref, rev = wrapper.check_repo_rev(
507 rp.gitdir, opt.repo_rev, repo_verify=opt.repo_verify, quiet=opt.quiet)
508 branch = rp.GetBranch('default')
509 branch.merge = remote_ref
510 rp.work_git.update_ref('refs/heads/default', rev)
511 branch.Save()
512
502 if opt.worktree: 513 if opt.worktree:
503 # Older versions of git supported worktree, but had dangerous gc bugs. 514 # Older versions of git supported worktree, but had dangerous gc bugs.
504 git_require((2, 15, 0), fail=True, msg='git gc worktree corruption') 515 git_require((2, 15, 0), fail=True, msg='git gc worktree corruption')
diff --git a/tests/test_wrapper.py b/tests/test_wrapper.py
index 73c62cc1..136f7f11 100644
--- a/tests/test_wrapper.py
+++ b/tests/test_wrapper.py
@@ -18,12 +18,14 @@
18 18
19from __future__ import print_function 19from __future__ import print_function
20 20
21import contextlib
21import os 22import os
22import re 23import re
23import shutil 24import shutil
24import tempfile 25import tempfile
25import unittest 26import unittest
26 27
28import platform_utils
27from pyversion import is_python3 29from pyversion import is_python3
28import wrapper 30import wrapper
29 31
@@ -36,6 +38,18 @@ else:
36 from StringIO import StringIO 38 from StringIO import StringIO
37 39
38 40
41@contextlib.contextmanager
42def TemporaryDirectory():
43 """Create a new empty git checkout for testing."""
44 # TODO(vapier): Convert this to tempfile.TemporaryDirectory once we drop
45 # Python 2 support entirely.
46 try:
47 tempdir = tempfile.mkdtemp(prefix='repo-tests')
48 yield tempdir
49 finally:
50 platform_utils.rmtree(tempdir)
51
52
39def fixture(*paths): 53def fixture(*paths):
40 """Return a path relative to tests/fixtures. 54 """Return a path relative to tests/fixtures.
41 """ 55 """
@@ -243,8 +257,93 @@ class CheckGitVersion(RepoWrapperTestCase):
243 self.wrapper._CheckGitVersion() 257 self.wrapper._CheckGitVersion()
244 258
245 259
246class ResolveRepoRev(RepoWrapperTestCase): 260class NeedSetupGnuPG(RepoWrapperTestCase):
247 """Check resolve_repo_rev behavior.""" 261 """Check NeedSetupGnuPG behavior."""
262
263 def test_missing_dir(self):
264 """The ~/.repoconfig tree doesn't exist yet."""
265 with TemporaryDirectory() as tempdir:
266 self.wrapper.home_dot_repo = os.path.join(tempdir, 'foo')
267 self.assertTrue(self.wrapper.NeedSetupGnuPG())
268
269 def test_missing_keyring(self):
270 """The keyring-version file doesn't exist yet."""
271 with TemporaryDirectory() as tempdir:
272 self.wrapper.home_dot_repo = tempdir
273 self.assertTrue(self.wrapper.NeedSetupGnuPG())
274
275 def test_empty_keyring(self):
276 """The keyring-version file exists, but is empty."""
277 with TemporaryDirectory() as tempdir:
278 self.wrapper.home_dot_repo = tempdir
279 with open(os.path.join(tempdir, 'keyring-version'), 'w'):
280 pass
281 self.assertTrue(self.wrapper.NeedSetupGnuPG())
282
283 def test_old_keyring(self):
284 """The keyring-version file exists, but it's old."""
285 with TemporaryDirectory() as tempdir:
286 self.wrapper.home_dot_repo = tempdir
287 with open(os.path.join(tempdir, 'keyring-version'), 'w') as fp:
288 fp.write('1.0\n')
289 self.assertTrue(self.wrapper.NeedSetupGnuPG())
290
291 def test_new_keyring(self):
292 """The keyring-version file exists, and is up-to-date."""
293 with TemporaryDirectory() as tempdir:
294 self.wrapper.home_dot_repo = tempdir
295 with open(os.path.join(tempdir, 'keyring-version'), 'w') as fp:
296 fp.write('1000.0\n')
297 self.assertFalse(self.wrapper.NeedSetupGnuPG())
298
299
300class SetupGnuPG(RepoWrapperTestCase):
301 """Check SetupGnuPG behavior."""
302
303 def test_full(self):
304 """Make sure it works completely."""
305 with TemporaryDirectory() as tempdir:
306 self.wrapper.home_dot_repo = tempdir
307 self.assertTrue(self.wrapper.SetupGnuPG(True))
308 with open(os.path.join(tempdir, 'keyring-version'), 'r') as fp:
309 data = fp.read()
310 self.assertEqual('.'.join(str(x) for x in self.wrapper.KEYRING_VERSION),
311 data.strip())
312
313
314class VerifyRev(RepoWrapperTestCase):
315 """Check verify_rev behavior."""
316
317 def test_verify_passes(self):
318 """Check when we have a valid signed tag."""
319 desc_result = self.wrapper.RunResult(0, 'v1.0\n', '')
320 gpg_result = self.wrapper.RunResult(0, '', '')
321 with mock.patch.object(self.wrapper, 'run_git',
322 side_effect=(desc_result, gpg_result)):
323 ret = self.wrapper.verify_rev('/', 'refs/heads/stable', '1234', True)
324 self.assertEqual('v1.0^0', ret)
325
326 def test_unsigned_commit(self):
327 """Check we fall back to signed tag when we have an unsigned commit."""
328 desc_result = self.wrapper.RunResult(0, 'v1.0-10-g1234\n', '')
329 gpg_result = self.wrapper.RunResult(0, '', '')
330 with mock.patch.object(self.wrapper, 'run_git',
331 side_effect=(desc_result, gpg_result)):
332 ret = self.wrapper.verify_rev('/', 'refs/heads/stable', '1234', True)
333 self.assertEqual('v1.0^0', ret)
334
335 def test_verify_fails(self):
336 """Check we fall back to signed tag when we have an unsigned commit."""
337 desc_result = self.wrapper.RunResult(0, 'v1.0-10-g1234\n', '')
338 gpg_result = Exception
339 with mock.patch.object(self.wrapper, 'run_git',
340 side_effect=(desc_result, gpg_result)):
341 with self.assertRaises(Exception):
342 self.wrapper.verify_rev('/', 'refs/heads/stable', '1234', True)
343
344
345class GitCheckoutTestCase(RepoWrapperTestCase):
346 """Tests that use a real/small git checkout."""
248 347
249 GIT_DIR = None 348 GIT_DIR = None
250 REV_LIST = None 349 REV_LIST = None
@@ -274,6 +373,10 @@ class ResolveRepoRev(RepoWrapperTestCase):
274 373
275 shutil.rmtree(cls.GIT_DIR) 374 shutil.rmtree(cls.GIT_DIR)
276 375
376
377class ResolveRepoRev(GitCheckoutTestCase):
378 """Check resolve_repo_rev behavior."""
379
277 def test_explicit_branch(self): 380 def test_explicit_branch(self):
278 """Check refs/heads/branch argument.""" 381 """Check refs/heads/branch argument."""
279 rrev, lrev = self.wrapper.resolve_repo_rev(self.GIT_DIR, 'refs/heads/stable') 382 rrev, lrev = self.wrapper.resolve_repo_rev(self.GIT_DIR, 'refs/heads/stable')
@@ -328,5 +431,54 @@ class ResolveRepoRev(RepoWrapperTestCase):
328 self.wrapper.resolve_repo_rev(self.GIT_DIR, 'boooooooya') 431 self.wrapper.resolve_repo_rev(self.GIT_DIR, 'boooooooya')
329 432
330 433
434class CheckRepoVerify(RepoWrapperTestCase):
435 """Check check_repo_verify behavior."""
436
437 def test_no_verify(self):
438 """Always fail with --no-repo-verify."""
439 self.assertFalse(self.wrapper.check_repo_verify(False))
440
441 def test_gpg_initialized(self):
442 """Should pass if gpg is setup already."""
443 with mock.patch.object(self.wrapper, 'NeedSetupGnuPG', return_value=False):
444 self.assertTrue(self.wrapper.check_repo_verify(True))
445
446 def test_need_gpg_setup(self):
447 """Should pass/fail based on gpg setup."""
448 with mock.patch.object(self.wrapper, 'NeedSetupGnuPG', return_value=True):
449 with mock.patch.object(self.wrapper, 'SetupGnuPG') as m:
450 m.return_value = True
451 self.assertTrue(self.wrapper.check_repo_verify(True))
452
453 m.return_value = False
454 self.assertFalse(self.wrapper.check_repo_verify(True))
455
456
457class CheckRepoRev(GitCheckoutTestCase):
458 """Check check_repo_rev behavior."""
459
460 def test_verify_works(self):
461 """Should pass when verification passes."""
462 with mock.patch.object(self.wrapper, 'check_repo_verify', return_value=True):
463 with mock.patch.object(self.wrapper, 'verify_rev', return_value='12345'):
464 rrev, lrev = self.wrapper.check_repo_rev(self.GIT_DIR, 'stable')
465 self.assertEqual('refs/heads/stable', rrev)
466 self.assertEqual('12345', lrev)
467
468 def test_verify_fails(self):
469 """Should fail when verification fails."""
470 with mock.patch.object(self.wrapper, 'check_repo_verify', return_value=True):
471 with mock.patch.object(self.wrapper, 'verify_rev', side_effect=Exception):
472 with self.assertRaises(Exception):
473 self.wrapper.check_repo_rev(self.GIT_DIR, 'stable')
474
475 def test_verify_ignore(self):
476 """Should pass when verification is disabled."""
477 with mock.patch.object(self.wrapper, 'verify_rev', side_effect=Exception):
478 rrev, lrev = self.wrapper.check_repo_rev(self.GIT_DIR, 'stable', repo_verify=False)
479 self.assertEqual('refs/heads/stable', rrev)
480 self.assertEqual(self.REV_LIST[1], lrev)
481
482
331if __name__ == '__main__': 483if __name__ == '__main__':
332 unittest.main() 484 unittest.main()