michael@0: # This Source Code Form is subject to the terms of the Mozilla Public michael@0: # License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: # file, You can obtain one at http://mozilla.org/MPL/2.0/. michael@0: michael@0: from __future__ import print_function, unicode_literals michael@0: michael@0: import os michael@0: import platform michael@0: import sys michael@0: import time michael@0: michael@0: michael@0: STATE_DIR_FIRST_RUN = ''' michael@0: mach and the build system store shared state in a common directory on the michael@0: filesystem. The following directory will be created: michael@0: michael@0: {userdir} michael@0: michael@0: If you would like to use a different directory, hit CTRL+c and set the michael@0: MOZBUILD_STATE_PATH environment variable to the directory you would like to michael@0: use and re-run mach. For this change to take effect forever, you'll likely michael@0: want to export this environment variable from your shell's init scripts. michael@0: '''.lstrip() michael@0: michael@0: michael@0: # TODO Bug 794506 Integrate with the in-tree virtualenv configuration. michael@0: SEARCH_PATHS = [ michael@0: 'python/mach', michael@0: 'python/mozboot', michael@0: 'python/mozbuild', michael@0: 'python/mozversioncontrol', michael@0: 'python/blessings', michael@0: 'python/configobj', michael@0: 'python/jsmin', michael@0: 'python/psutil', michael@0: 'python/which', michael@0: 'build/pymake', michael@0: 'config', michael@0: 'dom/bindings', michael@0: 'dom/bindings/parser', michael@0: 'other-licenses/ply', michael@0: 'xpcom/idl-parser', michael@0: 'testing', michael@0: 'testing/xpcshell', michael@0: 'testing/marionette/client', michael@0: 'testing/marionette/client/marionette', michael@0: 'testing/marionette/transport', michael@0: 'testing/mozbase/mozcrash', michael@0: 'testing/mozbase/mozdevice', michael@0: 'testing/mozbase/mozfile', michael@0: 'testing/mozbase/mozhttpd', michael@0: 'testing/mozbase/mozlog', michael@0: 'testing/mozbase/moznetwork', michael@0: 'testing/mozbase/mozprocess', michael@0: 'testing/mozbase/mozprofile', michael@0: 'testing/mozbase/mozrunner', michael@0: 'testing/mozbase/mozsystemmonitor', michael@0: 'testing/mozbase/mozinfo', michael@0: 'testing/mozbase/moztest', michael@0: 'testing/mozbase/mozversion', michael@0: 'testing/mozbase/manifestdestiny', michael@0: 'xpcom/idl-parser', michael@0: ] michael@0: michael@0: # Individual files providing mach commands. michael@0: MACH_MODULES = [ michael@0: 'addon-sdk/mach_commands.py', michael@0: 'build/valgrind/mach_commands.py', michael@0: 'dom/bindings/mach_commands.py', michael@0: 'layout/tools/reftest/mach_commands.py', michael@0: 'python/mach_commands.py', michael@0: 'python/mach/mach/commands/commandinfo.py', michael@0: 'python/mozboot/mozboot/mach_commands.py', michael@0: 'python/mozbuild/mozbuild/mach_commands.py', michael@0: 'python/mozbuild/mozbuild/frontend/mach_commands.py', michael@0: 'testing/mach_commands.py', michael@0: 'testing/marionette/mach_commands.py', michael@0: 'testing/mochitest/mach_commands.py', michael@0: 'testing/xpcshell/mach_commands.py', michael@0: 'testing/talos/mach_commands.py', michael@0: 'testing/xpcshell/mach_commands.py', michael@0: 'tools/docs/mach_commands.py', michael@0: 'tools/mercurial/mach_commands.py', michael@0: 'tools/mach_commands.py', michael@0: ] michael@0: michael@0: michael@0: CATEGORIES = { michael@0: 'build': { michael@0: 'short': 'Build Commands', michael@0: 'long': 'Interact with the build system', michael@0: 'priority': 80, michael@0: }, michael@0: 'post-build': { michael@0: 'short': 'Post-build Commands', michael@0: 'long': 'Common actions performed after completing a build.', michael@0: 'priority': 70, michael@0: }, michael@0: 'testing': { michael@0: 'short': 'Testing', michael@0: 'long': 'Run tests.', michael@0: 'priority': 60, michael@0: }, michael@0: 'devenv': { michael@0: 'short': 'Development Environment', michael@0: 'long': 'Set up and configure your development environment.', michael@0: 'priority': 50, michael@0: }, michael@0: 'build-dev': { michael@0: 'short': 'Low-level Build System Interaction', michael@0: 'long': 'Interact with specific parts of the build system.', michael@0: 'priority': 20, michael@0: }, michael@0: 'misc': { michael@0: 'short': 'Potpourri', michael@0: 'long': 'Potent potables and assorted snacks.', michael@0: 'priority': 10, michael@0: }, michael@0: 'disabled': { michael@0: 'short': 'Disabled', michael@0: 'long': 'These commands are unavailable for your current context, run "mach " to see why.', michael@0: 'priority': 0, michael@0: } michael@0: } michael@0: michael@0: michael@0: def bootstrap(topsrcdir, mozilla_dir=None): michael@0: if mozilla_dir is None: michael@0: mozilla_dir = topsrcdir michael@0: michael@0: # Ensure we are running Python 2.7+. We put this check here so we generate a michael@0: # user-friendly error message rather than a cryptic stack trace on module michael@0: # import. michael@0: if sys.version_info[0] != 2 or sys.version_info[1] < 7: michael@0: print('Python 2.7 or above (but not Python 3) is required to run mach.') michael@0: print('You are running Python', platform.python_version()) michael@0: sys.exit(1) michael@0: michael@0: # Global build system and mach state is stored in a central directory. By michael@0: # default, this is ~/.mozbuild. However, it can be defined via an michael@0: # environment variable. We detect first run (by lack of this directory michael@0: # existing) and notify the user that it will be created. The logic for michael@0: # creation is much simpler for the "advanced" environment variable use michael@0: # case. For default behavior, we educate users and give them an opportunity michael@0: # to react. We always exit after creating the directory because users don't michael@0: # like surprises. michael@0: try: michael@0: import mach.main michael@0: except ImportError: michael@0: sys.path[0:0] = [os.path.join(mozilla_dir, path) for path in SEARCH_PATHS] michael@0: import mach.main michael@0: michael@0: def populate_context(context, key=None): michael@0: if key is None: michael@0: return michael@0: if key == 'state_dir': michael@0: state_user_dir = os.path.expanduser('~/.mozbuild') michael@0: state_env_dir = os.environ.get('MOZBUILD_STATE_PATH', None) michael@0: if state_env_dir: michael@0: if not os.path.exists(state_env_dir): michael@0: print('Creating global state directory from environment variable: %s' michael@0: % state_env_dir) michael@0: os.makedirs(state_env_dir, mode=0o770) michael@0: print('Please re-run mach.') michael@0: sys.exit(1) michael@0: state_dir = state_env_dir michael@0: else: michael@0: if not os.path.exists(state_user_dir): michael@0: print(STATE_DIR_FIRST_RUN.format(userdir=state_user_dir)) michael@0: try: michael@0: for i in range(20, -1, -1): michael@0: time.sleep(1) michael@0: sys.stdout.write('%d ' % i) michael@0: sys.stdout.flush() michael@0: except KeyboardInterrupt: michael@0: sys.exit(1) michael@0: michael@0: print('\nCreating default state directory: %s' % state_user_dir) michael@0: os.mkdir(state_user_dir) michael@0: print('Please re-run mach.') michael@0: sys.exit(1) michael@0: state_dir = state_user_dir michael@0: michael@0: return state_dir michael@0: if key == 'topdir': michael@0: return topsrcdir michael@0: raise AttributeError(key) michael@0: michael@0: mach = mach.main.Mach(os.getcwd()) michael@0: mach.populate_context_handler = populate_context michael@0: michael@0: for category, meta in CATEGORIES.items(): michael@0: mach.define_category(category, meta['short'], meta['long'], michael@0: meta['priority']) michael@0: michael@0: for path in MACH_MODULES: michael@0: mach.load_commands_from_file(os.path.join(mozilla_dir, path)) michael@0: michael@0: return mach