diff options
Diffstat (limited to 'mach')
-rwxr-xr-x | mach | 195 |
1 files changed, 195 insertions, 0 deletions
@@ -0,0 +1,195 @@ +#!/bin/sh +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# The beginning of this script is both valid POSIX shell and valid Python, +# such that the script starts with the shell and is reexecuted with +# the right Python. + +# Embeds a shell script inside a Python triple quote. This pattern is valid +# shell because `''':'`, `':'` and `:` are all equivalent, and `:` is a no-op. +''':' +# Commands that are to be run with Python 2. +py2commands=" + awsy-test + firefox-ui-functional + jsshell-bench + marionette-test + jstests + mozharness + raptor + raptor-test + telemetry-tests-client + test + wpt-metadata-merge +" + +# Commands that are to be run with the system Python 3 instead of the +# virtualenv. +nativecmds=" + bootstrap + create-mach-environment + install-moz-phab +" + +run_py() { + # Try to run a specific Python interpreter. + py_executable="$1" + shift + if command -v "$py_executable" > /dev/null + then + exec "$py_executable" "$0" "$@" + else + echo "This mach command requires $py_executable, which wasn't found on the system!" + case "$py_executable" in + python2.7|python3) ;; + *) + echo "Consider running 'mach bootstrap' or 'mach create-mach-environment' to create the mach virtualenvs, or set MACH_USE_SYSTEM_PYTHON to use the system Python installation over a virtualenv." + ;; + esac + exit 1 + fi +} + +get_command() { + # Parse the name of the mach command out of the arguments. This is necessary + # in the presence of global mach arguments that come before the name of the + # command, e.g. `mach -v build`. We dispatch to the correct Python + # interpreter depending on the command. + while true; do + case $1 in + -v|--verbose) shift;; + -l|--log-file) + if [ "$#" -lt 2 ] + then + echo + break + else + shift 2 + fi + ;; + --log-interval) shift;; + --log-no-times) shift;; + -h) shift;; + --debug-command) shift;; + --settings) + if [ "$#" -lt 2 ] + then + echo + break + else + shift 2 + fi + ;; + # When running `./mach help <command>`, the correct Python for <command> + # needs to be used. + help) echo $2; break;; + # When running `./mach mach-completion /path/to/mach <command>`, the + # correct Python for <command> needs to be used. + mach-completion) echo $3; break;; + "") echo; break;; + *) echo $1; break;; + esac + done +} + +state_dir=${MOZBUILD_STATE_PATH:-~/.mozbuild} +command=$(get_command "$@") + +# If MACH_USE_SYSTEM_PYTHON or MOZ_AUTOMATION are set, always use the +# python{2.7,3} executables and not the virtualenv locations. +if [ -z ${MACH_USE_SYSTEM_PYTHON} ] && [ -z ${MOZ_AUTOMATION} ] +then + case "$OSTYPE" in + cygwin|msys|win32) bin_path=Scripts;; + *) bin_path=bin;; + esac + py2executable=$state_dir/_virtualenvs/mach_py2/$bin_path/python + py3executable=$state_dir/_virtualenvs/mach/$bin_path/python +else + py2executable=python2.7 + py3executable=python3 +fi + +# Check whether we need to run with the native Python 3 interpreter. +case " $(echo $nativecmds) " in + *\ $command\ *) + run_py python3 "$@" + ;; +esac + +# Check for the mach subcommand in the Python 2 commands list and run it +# with the correct interpreter. +case " $(echo $py2commands) " in + *\ $command\ *) + run_py "$py2executable" "$@" + ;; + *) + if [ -z ${MACH_PY2} ] + then + run_py "$py3executable" "$@" + else + if [ $command != "python-test" ] + then + echo "MACH_PY2 is only valid for mach python-test; please unset MACH_PY2 to continue." + exit 1 + fi + run_py "$py2executable" "$@" + fi + ;; +esac + +# Run Python 3 for everything else. +run_py "$py3executable" "$@" +''' + +from __future__ import absolute_import, print_function, unicode_literals + +import os +import sys + +def load_mach(dir_path, mach_path): + if sys.version_info < (3, 5): + import imp + mach_bootstrap = imp.load_source('mach_bootstrap', mach_path) + else: + import importlib.util + spec = importlib.util.spec_from_file_location('mach_bootstrap', mach_path) + mach_bootstrap = importlib.util.module_from_spec(spec) + spec.loader.exec_module(mach_bootstrap) + + return mach_bootstrap.bootstrap(dir_path) + + +def check_and_get_mach(dir_path): + bootstrap_paths = ( + 'build/mach_bootstrap.py', + # test package bootstrap + 'tools/mach_bootstrap.py', + ) + for bootstrap_path in bootstrap_paths: + mach_path = os.path.join(dir_path, bootstrap_path) + if os.path.isfile(mach_path): + return load_mach(dir_path, mach_path) + return None + + +def main(args): + # XCode python sets __PYVENV_LAUNCHER__, which overrides the executable + # used when a python subprocess is created. This is an issue when we want + # to run using our virtualenv python executables. + # In future Python relases, __PYVENV_LAUNCHER__ will be cleared before + # application code (mach) is started. + # https://github.com/python/cpython/pull/9516 + os.environ.pop("__PYVENV_LAUNCHER__", None) + + mach = check_and_get_mach(os.path.dirname(os.path.realpath(__file__))) + if not mach: + print('Could not run mach: No mach source directory found.') + sys.exit(1) + sys.exit(mach.run(args)) + + +if __name__ == '__main__': + main(sys.argv[1:]) |