blob: c17d1b500d4ce7aa270b58598f4319634e48130f [file] [log] [blame]
#!/usr/bin/env python
# Copyright 2017 The LUCI Authors. All rights reserved.
# Use of this source code is governed under the Apache License, Version 2.0
# that can be found in the LICENSE file.
import argparse
import logging
import os
import subprocess
import sys
LOGGER = logging.getLogger(__name__)
IS_WINDOWS = sys.platform == 'win32'
EXE_EXTENSION = '.bat' if IS_WINDOWS else ''
# /path/to/recipes-py
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
CIPD_ROOT = os.path.join(ROOT, '.cipd_root')
VPYTHON_PACKAGE = 'infra/tools/luci/vpython/${platform}'
VPYTHON_VERSION = 'git_revision:4e890ddbd1d716d72696eb9d88be1410bf7b0335'
def _ensure_vpython(cipd_root):
manifest = '%s %s' % (VPYTHON_PACKAGE, VPYTHON_VERSION)
cipd_bin = 'cipd' + EXE_EXTENSION
cmd = [cipd_bin, 'ensure', '-root', cipd_root, '-ensure-file=-']
LOGGER.debug('Running CIPD ensure command (cwd=%s): %s', os.getcwd(), cmd)
try:
proc = subprocess.Popen(
cmd,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
)
except OSError as e:
LOGGER.error(
"Failed to call 'cipd' subprocess for the Recipe Engine bootstrap. Is it "
"on your PATH?\n\n"
"The recipe engine expects certain tooling to be available on PATH\n"
"Please manually install 'cipd', or include it by adding a Chromium\n"
"'depot_tools' checkout to PATH.\n")
raise
stdout, _ = proc.communicate(input=manifest)
if proc.returncode != 0:
raise ValueError('Failed to install CIPD manifest (%d):\n%s' % (
proc.returncode, stdout,))
vpython_path = os.path.join(cipd_root, 'vpython' + EXE_EXTENSION)
if not os.path.isfile(vpython_path):
raise ValueError('`vpython` not found at [%s]' % (vpython_path,))
return vpython_path
def main(args):
parser = argparse.ArgumentParser()
parser.add_argument('--venv-spec', metavar='PATH',
default=os.path.join(ROOT, 'bootstrap', 'venv.cfg'),
help='Path to vpython environment specification file to use (default '
'is %(default)s).')
parser.add_argument('--vpython-path', metavar='PATH',
help='Use "vpython" binary at PATH, instead of the bootstrap default.')
parser.add_argument('-v', '--verbose', action='count', default=0,
help='Increase verbosity. Can be specified multiple times.')
parser.add_argument('--presubmit', action='store_true',
help='Run PRESUBMIT check and exit, zero on success, non-zero on '
'failure.')
parser.add_argument('args', nargs='*',
help='Flags and arguments to pass to the target Python script.')
opts = parser.parse_args(args)
if opts.verbose >= 2:
log_level = logging.DEBUG
vpython_log_level = 'debug'
elif opts.verbose == 1:
log_level = logging.INFO
vpython_log_level = 'info'
else:
log_level = logging.WARNING
vpython_log_level = 'warning'
logging.getLogger().setLevel(log_level)
vpython_path = opts.vpython_path
if not vpython_path:
vpython_path = _ensure_vpython(CIPD_ROOT)
vpython_args = [vpython_path]
if vpython_log_level:
vpython_args += ['-log-level', vpython_log_level]
if opts.venv_spec:
vpython_args += ['-spec', opts.venv_spec]
# If we're configured for PRESUBMIT, run the presubmit command and quit.
if opts.presubmit:
vpython_args += ['-dev', 'verify']
return subprocess.call(vpython_args)
vpython_args += ['--'] + opts.args
LOGGER.debug('Executing bootstrapped Python: %s', vpython_args)
return subprocess.call(vpython_args)
if __name__ == '__main__':
logging.basicConfig()
sys.exit(main(sys.argv[1:]))