summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMike Frysinger <vapier@google.com>2019-06-13 01:48:12 -0400
committerMike Frysinger <vapier@google.com>2020-02-05 21:32:02 +0000
commit3ba716f3823c010a9788077d9515c26db5d58f11 (patch)
tree0a2aedbda1a4940dec2fe63d513935e847f9e106
parent655aedd7f34d9f2ff6dd3cb77c080addd0f06c4b (diff)
downloadgit-repo-3ba716f3823c010a9788077d9515c26db5d58f11.tar.gz
repo: try to reexec self with Python 3 as needed
We want to start warning about Python 2 usage, but we can't do it simply because the shebang is /usr/bin/python which might be an old version like python2.7. We can't change the shebang because program name usage is spotty at best: on some platforms (like macOS), it's not uncommon to not have a `python3` wrapper, only a major.minor one like `python3.6`. Using python3 wouldn't guarantee a new enough version of Python 3 anyways, and we don't want to require Python 3.6 exactly, just that minimum. So we check the current Python version. If it's older than the ver of Python 3 we want, we search for a `python3.X` version to run. If those don't work, we see if `python3` exists and is a new enough ver. If it's not, we die if the current Python 3 is too old, and we start issuing warnings if the current Python version is 2.7. This should allow the user to take a bit more action by installing Python 3 on their system without having to worry about changing /usr/bin/python. Once we require Python 3 completely, we can simplify this logic a bit by always bootstrapping up to Python 3 and failing with Python 2. We have a few KI with Windows atm though, so keep it disabled there until the fixes are merged. Bug: https://crbug.com/gerrit/10418 Change-Id: I5e157defc788e31efb3e21e93f53fabdc7d75a3c Reviewed-on: https://gerrit-review.googlesource.com/c/git-repo/+/253136 Tested-by: Mike Frysinger <vapier@google.com> Reviewed-by: Mike Frysinger <vapier@google.com>
-rwxr-xr-xrepo105
1 files changed, 81 insertions, 24 deletions
diff --git a/repo b/repo
index 0b870731..95a212db 100755
--- a/repo
+++ b/repo
@@ -10,6 +10,84 @@ copy of repo in the checkout.
10 10
11from __future__ import print_function 11from __future__ import print_function
12 12
13import os
14import platform
15import subprocess
16import sys
17
18
19def exec_command(cmd):
20 """Execute |cmd| or return None on failure."""
21 try:
22 if platform.system() == 'Windows':
23 ret = subprocess.call(cmd)
24 sys.exit(ret)
25 else:
26 os.execvp(cmd[0], cmd)
27 except:
28 pass
29
30
31def check_python_version():
32 """Make sure the active Python version is recent enough."""
33 def reexec(prog):
34 exec_command([prog] + sys.argv)
35
36 MIN_PYTHON_VERSION = (3, 6)
37
38 ver = sys.version_info
39 major = ver.major
40 minor = ver.minor
41
42 # Abort on very old Python 2 versions.
43 if (major, minor) < (2, 7):
44 print('repo: error: Your Python version is too old. '
45 'Please use Python {}.{} or newer instead.'.format(
46 *MIN_PYTHON_VERSION), file=sys.stderr)
47 sys.exit(1)
48
49 # Try to re-exec the version specific Python 3 if needed.
50 if (major, minor) < MIN_PYTHON_VERSION:
51 # Python makes releases ~once a year, so try our min version +10 to help
52 # bridge the gap. This is the fallback anyways so perf isn't critical.
53 min_major, min_minor = MIN_PYTHON_VERSION
54 for inc in range(0, 10):
55 reexec('python{}.{}'.format(min_major, min_minor + inc))
56
57 # Try the generic Python 3 wrapper, but only if it's new enough. We don't
58 # want to go from (still supported) Python 2.7 to (unsupported) Python 3.5.
59 try:
60 proc = subprocess.Popen(
61 ['python3', '-c', 'import sys; '
62 'print(sys.version_info.major, sys.version_info.minor)'],
63 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
64 (output, _) = proc.communicate()
65 python3_ver = tuple(int(x) for x in output.decode('utf-8').split())
66 except (OSError, subprocess.CalledProcessError):
67 python3_ver = None
68
69 # The python3 version looks like it's new enough, so give it a try.
70 if python3_ver and python3_ver >= MIN_PYTHON_VERSION:
71 reexec('python3')
72
73 # We're still here, so diagnose things for the user.
74 if major < 3:
75 print('repo: warning: Python 2 is no longer supported; '
76 'Please upgrade to Python {}.{}+.'.format(*MIN_PYTHON_VERSION),
77 file=sys.stderr)
78 else:
79 print('repo: error: Python 3 version is too old; '
80 'Please use Python {}.{} or newer.'.format(*MIN_PYTHON_VERSION),
81 file=sys.stderr)
82 sys.exit(1)
83
84
85if __name__ == '__main__':
86 # TODO(vapier): Enable this on Windows once we have Python 3 issues fixed.
87 if platform.system() != 'Windows':
88 check_python_version()
89
90
13# repo default configuration 91# repo default configuration
14# 92#
15import os 93import os
@@ -91,7 +169,6 @@ repodir = '.repo' # name of repo's private directory
91S_repo = 'repo' # special repo repository 169S_repo = 'repo' # special repo repository
92S_manifests = 'manifests' # special manifest repository 170S_manifests = 'manifests' # special manifest repository
93REPO_MAIN = S_repo + '/main.py' # main script 171REPO_MAIN = S_repo + '/main.py' # main script
94MIN_PYTHON_VERSION = (2, 7) # minimum supported python version
95GITC_CONFIG_FILE = '/gitc/.config' 172GITC_CONFIG_FILE = '/gitc/.config'
96GITC_FS_ROOT_DIR = '/gitc/manifest-rw/' 173GITC_FS_ROOT_DIR = '/gitc/manifest-rw/'
97 174
@@ -99,12 +176,9 @@ GITC_FS_ROOT_DIR = '/gitc/manifest-rw/'
99import collections 176import collections
100import errno 177import errno
101import optparse 178import optparse
102import platform
103import re 179import re
104import shutil 180import shutil
105import stat 181import stat
106import subprocess
107import sys
108 182
109if sys.version_info[0] == 3: 183if sys.version_info[0] == 3:
110 import urllib.request 184 import urllib.request
@@ -117,17 +191,6 @@ else:
117 urllib.error = urllib2 191 urllib.error = urllib2
118 192
119 193
120# Python version check
121ver = sys.version_info
122if (ver[0], ver[1]) < MIN_PYTHON_VERSION:
123 print('error: Python version {} unsupported.\n'
124 'Please use Python {}.{} instead.'.format(
125 sys.version.split(' ')[0],
126 MIN_PYTHON_VERSION[0],
127 MIN_PYTHON_VERSION[1],
128 ), file=sys.stderr)
129 sys.exit(1)
130
131home_dot_repo = os.path.expanduser('~/.repoconfig') 194home_dot_repo = os.path.expanduser('~/.repoconfig')
132gpg_dir = os.path.join(home_dot_repo, 'gnupg') 195gpg_dir = os.path.join(home_dot_repo, 'gnupg')
133 196
@@ -894,15 +957,9 @@ def main(orig_args):
894 '--'] 957 '--']
895 me.extend(orig_args) 958 me.extend(orig_args)
896 me.extend(extra_args) 959 me.extend(extra_args)
897 try: 960 exec_command(me)
898 if platform.system() == "Windows": 961 print("fatal: unable to start %s" % repo_main, file=sys.stderr)
899 sys.exit(subprocess.call(me)) 962 sys.exit(148)
900 else:
901 os.execv(sys.executable, me)
902 except OSError as e:
903 print("fatal: unable to start %s" % repo_main, file=sys.stderr)
904 print("fatal: %s" % e, file=sys.stderr)
905 sys.exit(148)
906 963
907 964
908if __name__ == '__main__': 965if __name__ == '__main__':