summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMike Frysinger <vapier@google.com>2021-03-15 14:58:52 -0400
committerMike Frysinger <vapier@google.com>2021-04-09 03:16:45 +0000
commit347f9ed393b7a44d775ffb436f8bae304d82729f (patch)
treef25b587abc73703c0ef22d344d6a9bc14b18f9f5
parent9a734a3975c1fc45a43466f1a42e3f2ca588bd19 (diff)
downloadgit-repo-347f9ed393b7a44d775ffb436f8bae304d82729f.tar.gz
sync: rework selfupdate logic
The current logic has a downside in that it doesn't sync to the latest signed version available if the latest commit itself is unsigned. This can come up when using the "main" branch as it is sometimes signed, but often not as it's holding the latest merged commits. When people use the main branch, it's to get early testing on versions tagged but not yet released, and we don't want them to get stuck indefinitely on that old version of repo. For example, this series of events: * "stable" is at v2.12. * "main" is tagged with v2.13. * early testers use --repo-rev main to get v2.13. * new commits are merged to "main". * "main" is tagged with v2.14. * new commits are merged to "main". * devs who had synced in the past to test v2.13 are stuck on v2.13. repo sees "main" is unsigned and so doesn't try to upgrade at all. The only way to get unwedged is to re-run `repo init --repo-rev main`, or to manually sync once with repo verification disabled, or for us to leave "main" signed for a while and hope devs will sync in that window. The new logic is that whenever changes are available, we switch to the latest signed tag. We also replace some of the duplicated verification code in the sync command with the newer wrapper logic. This handles a couple of important scenarios inaddition to above: * rollback (e.g. v2.13.8 -> v2.13.7) * do not trash uncommitted changes (in case of ad-hoc testing) * switch tag histories (e.g. v2.13.8 -> v2.13.8-cr1) Change-Id: I5b45ba1dd26a7c582700ee3711f303dc7538579b Reviewed-on: https://gerrit-review.googlesource.com/c/git-repo/+/300122 Reviewed-by: Jonathan Nieder <jrn@google.com> Reviewed-by: Michael Mortensen <mmortensen@google.com> Tested-by: Mike Frysinger <vapier@google.com>
-rw-r--r--subcmds/sync.py68
1 files changed, 20 insertions, 48 deletions
diff --git a/subcmds/sync.py b/subcmds/sync.py
index bf1369c0..36b1b0ac 100644
--- a/subcmds/sync.py
+++ b/subcmds/sync.py
@@ -20,9 +20,7 @@ import multiprocessing
20import netrc 20import netrc
21from optparse import SUPPRESS_HELP 21from optparse import SUPPRESS_HELP
22import os 22import os
23import re
24import socket 23import socket
25import subprocess
26import sys 24import sys
27import tempfile 25import tempfile
28import time 26import time
@@ -46,7 +44,7 @@ except ImportError:
46 return (256, 256) 44 return (256, 256)
47 45
48import event_log 46import event_log
49from git_command import GIT, git_require 47from git_command import git_require
50from git_config import GetUrlCookieFile 48from git_config import GetUrlCookieFile
51from git_refs import R_HEADS, HEAD 49from git_refs import R_HEADS, HEAD
52import git_superproject 50import git_superproject
@@ -956,12 +954,25 @@ def _PostRepoUpgrade(manifest, quiet=False):
956def _PostRepoFetch(rp, repo_verify=True, verbose=False): 954def _PostRepoFetch(rp, repo_verify=True, verbose=False):
957 if rp.HasChanges: 955 if rp.HasChanges:
958 print('info: A new version of repo is available', file=sys.stderr) 956 print('info: A new version of repo is available', file=sys.stderr)
959 print(file=sys.stderr) 957 wrapper = Wrapper()
960 if not repo_verify or _VerifyTag(rp): 958 try:
961 syncbuf = SyncBuffer(rp.config) 959 rev = rp.bare_git.describe(rp.GetRevisionId())
962 rp.Sync_LocalHalf(syncbuf) 960 except GitError:
963 if not syncbuf.Finish(): 961 rev = None
964 sys.exit(1) 962 _, new_rev = wrapper.check_repo_rev(rp.gitdir, rev, repo_verify=repo_verify)
963 # See if we're held back due to missing signed tag.
964 current_revid = rp.bare_git.rev_parse('HEAD')
965 new_revid = rp.bare_git.rev_parse('--verify', new_rev)
966 if current_revid != new_revid:
967 # We want to switch to the new rev, but also not trash any uncommitted
968 # changes. This helps with local testing/hacking.
969 # If a local change has been made, we will throw that away.
970 # We also have to make sure this will switch to an older commit if that's
971 # the latest tag in order to support release rollback.
972 try:
973 rp.work_git.reset('--keep', new_rev)
974 except GitError as e:
975 sys.exit(str(e))
965 print('info: Restarting repo with latest version', file=sys.stderr) 976 print('info: Restarting repo with latest version', file=sys.stderr)
966 raise RepoChangedException(['--repo-upgraded']) 977 raise RepoChangedException(['--repo-upgraded'])
967 else: 978 else:
@@ -972,45 +983,6 @@ def _PostRepoFetch(rp, repo_verify=True, verbose=False):
972 file=sys.stderr) 983 file=sys.stderr)
973 984
974 985
975def _VerifyTag(project):
976 gpg_dir = os.path.expanduser('~/.repoconfig/gnupg')
977 if not os.path.exists(gpg_dir):
978 print('warning: GnuPG was not available during last "repo init"\n'
979 'warning: Cannot automatically authenticate repo."""',
980 file=sys.stderr)
981 return True
982
983 try:
984 cur = project.bare_git.describe(project.GetRevisionId())
985 except GitError:
986 cur = None
987
988 if not cur \
989 or re.compile(r'^.*-[0-9]{1,}-g[0-9a-f]{1,}$').match(cur):
990 rev = project.revisionExpr
991 if rev.startswith(R_HEADS):
992 rev = rev[len(R_HEADS):]
993
994 print(file=sys.stderr)
995 print("warning: project '%s' branch '%s' is not signed"
996 % (project.name, rev), file=sys.stderr)
997 return False
998
999 env = os.environ.copy()
1000 env['GIT_DIR'] = project.gitdir
1001 env['GNUPGHOME'] = gpg_dir
1002
1003 cmd = [GIT, 'tag', '-v', cur]
1004 result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
1005 env=env, check=False)
1006 if result.returncode:
1007 print(file=sys.stderr)
1008 print(result.stdout, file=sys.stderr)
1009 print(file=sys.stderr)
1010 return False
1011 return True
1012
1013
1014class _FetchTimes(object): 986class _FetchTimes(object):
1015 _ALPHA = 0.5 987 _ALPHA = 0.5
1016 988