diff --git a/repo b/repo index 29c2fd5bc..a127a1b7f 100755 --- a/repo +++ b/repo @@ -10,6 +10,7 @@ copy of repo in the checkout. from __future__ import print_function +import datetime import os import platform import subprocess @@ -24,7 +25,7 @@ def exec_command(cmd): sys.exit(ret) else: os.execvp(cmd[0], cmd) - except: + except Exception: pass @@ -113,7 +114,7 @@ if not REPO_REV: # limitations under the License. # increment this whenever we make important changes to this script -VERSION = (2, 0) +VERSION = (2, 3) # increment this if the MAINTAINER_KEYS block is modified KEYRING_VERSION = (2, 0) @@ -166,7 +167,12 @@ TACbBS+Up3RpfYVfd63c1cDdlru13pQAn3NQy/SN858MkxN+zym86UBgOad2 """ GIT = 'git' # our git command -MIN_GIT_VERSION = (2, 10, 2) # minimum supported git version +# NB: The version of git that the repo launcher requires may be much older than +# the version of git that the main repo source tree requires. Keeping this at +# an older version also makes it easier for users to upgrade/rollback as needed. +# +# git-1.7 is in (EOL) Ubuntu Precise. +MIN_GIT_VERSION = (1, 7, 2) # minimum supported git version repodir = '.repo' # name of repo's private directory S_repo = 'repo' # special repo repository S_manifests = 'manifests' # special manifest repository @@ -199,88 +205,73 @@ gpg_dir = os.path.join(home_dot_repo, 'gnupg') extra_args = [] init_optparse = optparse.OptionParser(usage="repo init -u url [options]") -# Logging -group = init_optparse.add_option_group('Logging options') -group.add_option('-q', '--quiet', - dest="quiet", action="store_true", default=False, - help="be quiet") - -# Manifest -group = init_optparse.add_option_group('Manifest options') -group.add_option('-u', '--manifest-url', - dest='manifest_url', - help='manifest repository location', metavar='URL') -group.add_option('-b', '--manifest-branch', - dest='manifest_branch', - help='manifest branch or revision', metavar='REVISION') -group.add_option('-m', '--manifest-name', - dest='manifest_name', - help='initial manifest file', metavar='NAME.xml') -group.add_option('--current-branch', - dest='current_branch_only', action='store_true', - help='fetch only current manifest branch from server') -group.add_option('--mirror', - dest='mirror', action='store_true', - help='create a replica of the remote repositories ' - 'rather than a client working directory') -group.add_option('--reference', - dest='reference', - help='location of mirror directory', metavar='DIR') -group.add_option('--dissociate', - dest='dissociate', action='store_true', - help='dissociate from reference mirrors after clone') -group.add_option('--depth', type='int', default=None, - dest='depth', - help='create a shallow clone with given depth; see git clone') -group.add_option('--partial-clone', action='store_true', - dest='partial_clone', - help='perform partial clone (https://git-scm.com/' - 'docs/gitrepository-layout#_code_partialclone_code)') -group.add_option('--clone-filter', action='store', default='blob:none', - dest='clone_filter', - help='filter for use with --partial-clone [default: %default]') -group.add_option('--archive', - dest='archive', action='store_true', - help='checkout an archive instead of a git repository for ' - 'each project. See git archive.') -group.add_option('--submodules', - dest='submodules', action='store_true', - help='sync any submodules associated with the manifest repo') -group.add_option('-g', '--groups', - dest='groups', default='default', - help='restrict manifest projects to ones with specified ' - 'group(s) [default|all|G1,G2,G3|G4,-G5,-G6]', - metavar='GROUP') -group.add_option('-p', '--platform', - dest='platform', default="auto", - help='restrict manifest projects to ones with a specified ' - 'platform group [auto|all|none|linux|darwin|...]', - metavar='PLATFORM') -group.add_option('--no-clone-bundle', - dest='no_clone_bundle', action='store_true', - help='disable use of /clone.bundle on HTTP/HTTPS') -group.add_option('--no-tags', - dest='no_tags', action='store_true', - help="don't fetch tags in the manifest") - - -# Tool -group = init_optparse.add_option_group('repo Version options') -group.add_option('--repo-url', - dest='repo_url', - help='repo repository location ($REPO_URL)', metavar='URL') -group.add_option('--repo-branch', - dest='repo_branch', - help='repo branch or revision ($REPO_REV)', metavar='REVISION') -group.add_option('--no-repo-verify', - dest='no_repo_verify', action='store_true', - help='do not verify repo source code') - -# Other -group = init_optparse.add_option_group('Other options') -group.add_option('--config-name', - dest='config_name', action="store_true", default=False, - help='Always prompt for name/e-mail') +def _InitParser(): + """Setup the init subcommand parser.""" + # Logging. + group = init_optparse.add_option_group('Logging options') + group.add_option('-q', '--quiet', + action='store_true', default=False, + help='be quiet') + + # Manifest. + group = init_optparse.add_option_group('Manifest options') + group.add_option('-u', '--manifest-url', + help='manifest repository location', metavar='URL') + group.add_option('-b', '--manifest-branch', + help='manifest branch or revision', metavar='REVISION') + group.add_option('-m', '--manifest-name', + help='initial manifest file', metavar='NAME.xml') + group.add_option('--current-branch', + dest='current_branch_only', action='store_true', + help='fetch only current manifest branch from server') + group.add_option('--mirror', action='store_true', + help='create a replica of the remote repositories ' + 'rather than a client working directory') + group.add_option('--reference', + help='location of mirror directory', metavar='DIR') + group.add_option('--dissociate', action='store_true', + help='dissociate from reference mirrors after clone') + group.add_option('--depth', type='int', default=None, + help='create a shallow clone with given depth; ' + 'see git clone') + group.add_option('--partial-clone', action='store_true', + help='perform partial clone (https://git-scm.com/' + 'docs/gitrepository-layout#_code_partialclone_code)') + group.add_option('--clone-filter', action='store', default='blob:none', + help='filter for use with --partial-clone ' + '[default: %default]') + group.add_option('--archive', action='store_true', + help='checkout an archive instead of a git repository for ' + 'each project. See git archive.') + group.add_option('--submodules', action='store_true', + help='sync any submodules associated with the manifest repo') + group.add_option('-g', '--groups', default='default', + help='restrict manifest projects to ones with specified ' + 'group(s) [default|all|G1,G2,G3|G4,-G5,-G6]', + metavar='GROUP') + group.add_option('-p', '--platform', default='auto', + help='restrict manifest projects to ones with a specified ' + 'platform group [auto|all|none|linux|darwin|...]', + metavar='PLATFORM') + group.add_option('--no-clone-bundle', action='store_true', + help='disable use of /clone.bundle on HTTP/HTTPS') + group.add_option('--no-tags', action='store_true', + help="don't fetch tags in the manifest") + + # Tool. + group = init_optparse.add_option_group('repo Version options') + group.add_option('--repo-url', metavar='URL', + help='repo repository location ($REPO_URL)') + group.add_option('--repo-branch', metavar='REVISION', + help='repo branch or revision ($REPO_REV)') + group.add_option('--no-repo-verify', action='store_true', + help='do not verify repo source code') + + # Other. + group = init_optparse.add_option_group('Other options') + group.add_option('--config-name', + action='store_true', default=False, + help='Always prompt for name/e-mail') def _GitcInitOptions(init_optparse_arg): @@ -488,6 +479,39 @@ def _CheckGitVersion(): raise CloneFailure() +def SetGitTrace2ParentSid(env=None): + """Set up GIT_TRACE2_PARENT_SID for git tracing.""" + # We roughly follow the format git itself uses in trace2/tr2_sid.c. + # (1) Be unique (2) be valid filename (3) be fixed length. + # + # Since we always export this variable, we try to avoid more expensive calls. + # e.g. We don't attempt hostname lookups or hashing the results. + if env is None: + env = os.environ + + KEY = 'GIT_TRACE2_PARENT_SID' + + now = datetime.datetime.utcnow() + value = 'repo-%s-P%08x' % (now.strftime('%Y%m%dT%H%M%SZ'), os.getpid()) + + # If it's already set, then append ourselves. + if KEY in env: + value = env[KEY] + '/' + value + + _setenv(KEY, value, env=env) + + +def _setenv(key, value, env=None): + """Set |key| in the OS environment |env| to |value|.""" + if env is None: + env = os.environ + # Environment handling across systems is messy. + try: + env[key] = value + except UnicodeEncodeError: + env[key] = value.encode() + + def NeedSetupGnuPG(): if not os.path.isdir(home_dot_repo): return True @@ -524,10 +548,7 @@ def SetupGnuPG(quiet): sys.exit(1) env = os.environ.copy() - try: - env['GNUPGHOME'] = gpg_dir - except UnicodeEncodeError: - env['GNUPGHOME'] = gpg_dir.encode() + _setenv('GNUPGHOME', gpg_dir, env) cmd = ['gpg', '--import'] try: @@ -733,10 +754,7 @@ def _Verify(cwd, branch, quiet): print(file=sys.stderr) env = os.environ.copy() - try: - env['GNUPGHOME'] = gpg_dir - except UnicodeEncodeError: - env['GNUPGHOME'] = gpg_dir.encode() + _setenv('GNUPGHOME', gpg_dir, env) cmd = [GIT, 'tag', '-v', cur] proc = subprocess.Popen(cmd, @@ -801,6 +819,7 @@ def _FindRepo(): class _Options(object): help = False + version = False def _ParseArguments(args): @@ -812,7 +831,8 @@ def _ParseArguments(args): a = args[i] if a == '-h' or a == '--help': opt.help = True - + elif a == '--version': + opt.version = True elif not a.startswith('-'): cmd = a arg = args[i + 1:] @@ -859,6 +879,16 @@ def _Help(args): sys.exit(1) +def _Version(): + """Show version information.""" + print('') + print('repo launcher version %s' % ('.'.join(str(x) for x in VERSION),)) + print(' (from %s)' % (__file__,)) + print('git %s' % (ParseGitVersion().full,)) + print('Python %s' % sys.version) + sys.exit(0) + + def _NotInstalled(): print('error: repo is not installed. Use "repo init" to install it here.', file=sys.stderr) @@ -911,6 +941,9 @@ def _SetDefaultsTo(gitdir): def main(orig_args): cmd, opt, args = _ParseArguments(orig_args) + # We run this early as we run some git commands ourselves. + SetGitTrace2ParentSid() + repo_main, rel_repo_dir = None, None # Don't use the local repo copy, make sure to switch to the gitc client first. if cmd != 'gitc-init': @@ -926,11 +959,14 @@ def main(orig_args): 'command from the corresponding client under /gitc/', file=sys.stderr) sys.exit(1) + _InitParser() if not repo_main: if opt.help: _Usage() if cmd == 'help': _Help(args) + if opt.version or cmd == 'version': + _Version() if not cmd: _NotInstalled() if cmd == 'init' or cmd == 'gitc-init':