Bug 894197 - Define state directory in mach context object; r=jhammel
authorGregory Szorc <gps@mozilla.com>
Mon, 15 Jul 2013 19:56:15 -0700
changeset 138524 5976b9c673f8e9eb4e91ddc6fa670d333196d28a
parent 138523 e5d74eebd0e2b3020988bfe3a774b515720d1b3e
child 138609 41ed26826acb94f3dd56aae6a16e13d9faf2c7d1
push idunknown
push userunknown
push dateunknown
reviewersjhammel
bugs894197
milestone25.0a1
Bug 894197 - Define state directory in mach context object; r=jhammel DONTBUILD (NPOTB)
build/mach_bootstrap.py
python/mach/mach/base.py
python/mach/mach/main.py
--- a/build/mach_bootstrap.py
+++ b/build/mach_bootstrap.py
@@ -126,39 +126,46 @@ def bootstrap(topsrcdir, mozilla_dir=Non
     state_env_dir = os.environ.get('MOZBUILD_STATE_PATH', None)
     if state_env_dir:
         if not os.path.exists(state_env_dir):
             print('Creating global state directory from environment variable: %s'
                 % state_env_dir)
             os.makedirs(state_env_dir, mode=0o770)
             print('Please re-run mach.')
             sys.exit(1)
+        state_dir = state_env_dir
     else:
         if not os.path.exists(state_user_dir):
             print(STATE_DIR_FIRST_RUN.format(userdir=state_user_dir))
             try:
                 for i in range(20, -1, -1):
                     time.sleep(1)
                     sys.stdout.write('%d ' % i)
                     sys.stdout.flush()
             except KeyboardInterrupt:
                 sys.exit(1)
 
             print('\nCreating default state directory: %s' % state_user_dir)
             os.mkdir(state_user_dir)
             print('Please re-run mach.')
             sys.exit(1)
+        state_dir = state_user_dir
 
     try:
         import mach.main
     except ImportError:
         sys.path[0:0] = [os.path.join(mozilla_dir, path) for path in SEARCH_PATHS]
         import mach.main
 
+    def populate_context(context):
+        context.state_dir = state_dir
+
     mach = mach.main.Mach(topsrcdir)
+    mach.populate_context_handler = populate_context
+
     for category, meta in CATEGORIES.items():
         mach.define_category(category, meta['short'], meta['long'],
             meta['priority'])
 
     for path in MACH_MODULES:
         mach.load_commands_from_file(os.path.join(mozilla_dir, path))
 
     return mach
--- a/python/mach/mach/base.py
+++ b/python/mach/mach/base.py
@@ -1,19 +1,24 @@
 # 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/.
 
 from __future__ import unicode_literals
 
-from collections import namedtuple
 
-# Holds mach run-time state so it can easily be passed to command providers.
-CommandContext = namedtuple('CommandContext', ['topdir', 'cwd',
-    'settings', 'log_manager', 'commands'])
+class CommandContext(object):
+    """Holds run-time state so it can easily be passed to command providers."""
+    def __init__(self, topdir=None, cwd=None, settings=None, log_manager=None,
+        commands=None):
+        self.topdir = topdir
+        self.cwd = cwd
+        self.settings = settings
+        self.log_manager = log_manager
+        self.commands = commands
 
 
 class MachError(Exception):
     """Base class for all errors raised by mach itself."""
 
 
 class NoCommandError(MachError):
     """No command was passed into mach."""
--- a/python/mach/mach/main.py
+++ b/python/mach/mach/main.py
@@ -122,17 +122,30 @@ class ArgumentParser(argparse.ArgumentPa
 
             text = text[0:real_start] + text[real_end:]
 
         return text
 
 
 @CommandProvider
 class Mach(object):
-    """Contains code for the command-line `mach` interface."""
+    """Main mach driver type.
+
+    This type is responsible for holding global mach state and dispatching
+    a command from arguments.
+
+    The following attributes may be assigned to the instance to influence
+    behavior:
+
+        populate_context_handler -- If defined, it must be a callable. The
+            callable will be called with the mach.base.CommandContext instance
+            as its single argument right before command dispatch. This allows
+            modification of the context instance and thus passing of
+            arbitrary data to command handlers.
+    """
 
     USAGE = """%(prog)s [global arguments] command [command arguments]
 
 mach (German for "do") is the main interface to the Mozilla build system and
 common developer tasks.
 
 You tell mach the command you want to perform and it does it for you.
 
@@ -149,16 +162,18 @@ To see more help for a specific command,
     def __init__(self, cwd):
         assert os.path.isdir(cwd)
 
         self.cwd = cwd
         self.log_manager = LoggingManager()
         self.logger = logging.getLogger(__name__)
         self.settings = ConfigSettings()
 
+        self.populate_context_handler = None
+
         self.log_manager.register_structured_logger(self.logger)
 
     def load_commands_from_directory(self, path):
         """Scan for mach commands from modules in a directory.
 
         This takes a path to a directory, loads the .py files in it, and
         registers and found mach command providers with this mach instance.
         """
@@ -298,16 +313,19 @@ To see more help for a specific command,
 
         if not hasattr(args, 'mach_handler'):
             raise MachError('ArgumentParser result missing mach handler info.')
 
         context = CommandContext(topdir=self.cwd, cwd=self.cwd,
             settings=self.settings, log_manager=self.log_manager,
             commands=Registrar)
 
+        if self.populate_context_handler:
+            self.populate_context_handler(context)
+
         handler = getattr(args, 'mach_handler')
         cls = handler.cls
 
         if handler.pass_context:
             instance = cls(context)
         else:
             instance = cls()