#!/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. ''':' 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 ;; --no-interactive) shift;; --log-interval) shift;; --log-no-times) shift;; -h) shift;; --debug-command) shift;; --profile-command) py_profile_command="1" shift;; --settings) if [ "$#" -lt 2 ] then echo break else shift 2 fi ;; "") echo; break;; *) echo $1; break;; esac done return ${py_profile_command} } command=$(get_command "$@") py_profile_command=$? if [ ${py_profile_command} -eq 0 ] then py_profile_command_args="" else # We would prefer to use an array variable here, but we're limited to POSIX. # None of our arguments have quoting or spaces so we can safely interpolate # a string instead. py_profile_command_args="-m cProfile -o mach_profile_${command}.cProfile" echo "Running with --profile-command. To visualize, use snakeviz:" echo "python3 -m pip install snakeviz" echo "python3 -m snakeviz mach_profile_${command}.cProfile" fi if command -v python3 > /dev/null then exec python3 $py_profile_command_args "$0" "$@" else echo "This mach command requires 'python3', which wasn't found on the system!" exit 1 fi ''' from __future__ import absolute_import, print_function, unicode_literals import os import sys def load_mach(dir_path, mach_path): import importlib.util spec = importlib.util.spec_from_file_location('mach_initialize', mach_path) mach_initialize = importlib.util.module_from_spec(spec) spec.loader.exec_module(mach_initialize) return mach_initialize.initialize(dir_path) def check_and_get_mach(dir_path): initialize_paths = ( # Run Thunderbird's mach_initialize.py if it exists 'comm/build/mach_initialize.py', 'build/mach_initialize.py', # test package initialize 'tools/mach_initialize.py', ) for initialize_path in initialize_paths: mach_path = os.path.join(dir_path, initialize_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:])