Bug 808336 - Part 2: Discover mach settings providers via decorators; r=jhammel
authorGregory Szorc <gps@mozilla.com>
Tue, 06 Nov 2012 16:58:13 -0800
changeset 112493 4f96fdb5e4f9b9e101e2e3c5f535bff8e0fe8f6c
parent 112492 e0e1220d2c5a1086a4911be8d69e2937b842d116
child 112494 f561a4ffeeb9f523fb59c678b7ac901763e32911
push id17610
push usereakhgari@mozilla.com
push dateWed, 07 Nov 2012 01:16:45 +0000
treeherdermozilla-inbound@4e8873d14ed3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjhammel
bugs808336
milestone19.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 808336 - Part 2: Discover mach settings providers via decorators; r=jhammel With this patch, mach is now decoupled from the build system and is truly a generic command dispatching framework.
mach
python/mach/mach/decorators.py
python/mach/mach/main.py
python/mach/mach/registrar.py
python/mozbuild/mozbuild/base.py
python/mozbuild/mozbuild/config.py
--- a/mach
+++ b/mach
@@ -34,16 +34,17 @@ SEARCH_PATHS = [
     'testing/mozbase/mozprocess',
     'testing/mozbase/mozinfo',
 ]
 
 # Individual files providing mach commands.
 MACH_MODULES = [
     'layout/tools/reftest/mach_commands.py',
     'python/mozboot/mozboot/mach_commands.py',
+    'python/mozbuild/mozbuild/config.py',
     'testing/mochitest/mach_commands.py',
     'testing/xpcshell/mach_commands.py',
 ]
 
 our_dir = os.path.dirname(os.path.abspath(__file__))
 
 try:
     import mach.main
--- a/python/mach/mach/decorators.py
+++ b/python/mach/mach/decorators.py
@@ -3,16 +3,17 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 from __future__ import unicode_literals
 
 import inspect
 import types
 
 from .base import MethodHandler
+from .config import ConfigProvider
 from .registrar import Registrar
 
 
 def CommandProvider(cls):
     """Class decorator to denote that it provides subcommands for Mach.
 
     When this decorator is present, mach looks for commands being defined by
     methods inside the class.
@@ -106,8 +107,26 @@ class CommandArgument(object):
     def __call__(self, func):
         command_args = getattr(func, '_mach_command_args', [])
 
         command_args.append(self._command_args)
 
         func._mach_command_args = command_args
 
         return func
+
+def SettingsProvider(cls):
+    """Class decorator to denote that this class provides Mach settings.
+
+    When this decorator is encountered, the underlying class will automatically
+    be registered with the Mach registrar and will (likely) be hooked up to the
+    mach driver.
+
+    This decorator is only allowed on mach.config.ConfigProvider classes.
+    """
+    if not issubclass(cls, ConfigProvider):
+        raise Exception('@SettingsProvider encountered on class that does ' +
+                        'not derived from mach.config.ConfigProvider.')
+
+    Registrar.register_settings_provider(cls)
+
+    return cls
+
--- a/python/mach/mach/main.py
+++ b/python/mach/mach/main.py
@@ -12,38 +12,30 @@ import codecs
 import imp
 import logging
 import os
 import sys
 import traceback
 import uuid
 import sys
 
-from mozbuild.base import BuildConfig
-
 from .base import CommandContext
 
 from .decorators import (
     CommandArgument,
     CommandProvider,
     Command,
 )
 
 from .config import ConfigSettings
 from .logging import LoggingManager
 
 from .registrar import Registrar
 
 
-# Classes inheriting from ConfigProvider that provide settings.
-# TODO this should come from auto-discovery somehow.
-SETTINGS_PROVIDERS = [
-    BuildConfig,
-]
-
 # Settings for argument parser that don't get proxied to sub-module. i.e. these
 # are things consumed by the driver itself.
 CONSUMED_ARGUMENTS = [
     'settings_file',
     'verbose',
     'logfile',
     'log_interval',
     'command',
@@ -407,17 +399,17 @@ To see more help for a specific command,
           2) Environment variable
           3) Default path
         """
         # Settings are disabled until integration with command providers is
         # worked out.
         self.settings = None
         return False
 
-        for provider in SETTINGS_PROVIDERS:
+        for provider in Registrar.settings_providers:
             provider.register_settings()
             self.settings.register_provider(provider)
 
         p = os.path.join(self.cwd, 'mach.ini')
 
         if args.settings_file:
             p = args.settings_file
         elif 'MACH_SETTINGS_FILE' in os.environ:
--- a/python/mach/mach/registrar.py
+++ b/python/mach/mach/registrar.py
@@ -7,22 +7,26 @@ from __future__ import unicode_literals
 import collections
 
 
 class MachRegistrar(object):
     """Container for mach command and config providers."""
 
     def __init__(self):
         self.command_handlers = {}
+        self.settings_providers = set()
 
     def register_command_handler(self, handler):
         name = handler.parser_args[0][0]
 
         self.command_handlers[name] = handler
 
+    def register_settings_provider(self, cls):
+        self.settings_providers.add(cls)
+
     def populate_argument_parser(self, parser):
         for command in sorted(self.command_handlers.keys()):
             handler = self.command_handlers[command]
             p = parser.add_parser(*handler.parser_args[0],
                 **handler.parser_args[1])
 
             for arg in handler.arguments:
                 p.add_argument(*arg[0], **arg[1])
--- a/python/mozbuild/mozbuild/base.py
+++ b/python/mozbuild/mozbuild/base.py
@@ -1,32 +1,28 @@
 # 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
 
 import logging
-import multiprocessing
 import os
 import pymake.parser
 import subprocess
 import sys
 import which
 
 from pymake.data import Makefile
 
-from mach.config import (
-    ConfigProvider,
-    PositiveIntegerType,
-)
-
 from mach.mixin.logging import LoggingMixin
 from mach.mixin.process import ProcessExecutionMixin
 
+from .config import BuildConfig
+
 
 class MozbuildObject(ProcessExecutionMixin):
     """Base class providing basic functionality useful to many modules.
 
     Modules in this package typically require common functionality such as
     accessing the current config, getting the location of the source directory,
     running processes, etc. This classes provides that functionality. Other
     modules can inherit from this class to obtain this functionality easily.
@@ -277,32 +273,16 @@ class MozbuildObject(ProcessExecutionMix
         MozbuildObject-derived class instances. It can only be used on
         classes that have the same constructor arguments as us.
         """
 
         return cls(self.topsrcdir, self.settings, self.log_manager,
             topobjdir=self.topobjdir)
 
 
-class BuildConfig(ConfigProvider):
-    """The configuration for mozbuild."""
-
-    def __init__(self, settings):
-        self.settings = settings
-
-    @classmethod
-    def _register_settings(cls):
-        def register(section, option, type_cls, **kwargs):
-            cls.register_setting(section, option, type_cls, domain='mozbuild',
-                **kwargs)
-
-        register('build', 'threads', PositiveIntegerType,
-            default=multiprocessing.cpu_count())
-
-
 class MachCommandBase(MozbuildObject):
     """Base class for mach command providers that wish to be MozbuildObjects.
 
     This provides a level of indirection so MozbuildObject can be refactored
     without having to change everything that inherits from it.
     """
 
     def __init__(self, context):
new file mode 100644
--- /dev/null
+++ b/python/mozbuild/mozbuild/config.py
@@ -0,0 +1,33 @@
+# 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
+
+import multiprocessing
+
+from mach.config import (
+    ConfigProvider,
+    PositiveIntegerType,
+)
+
+from mach.decorators import SettingsProvider
+
+
+@SettingsProvider
+class BuildConfig(ConfigProvider):
+    """The configuration for mozbuild."""
+
+    def __init__(self, settings):
+        self.settings = settings
+
+    @classmethod
+    def _register_settings(cls):
+        def register(section, option, type_cls, **kwargs):
+            cls.register_setting(section, option, type_cls, domain='mozbuild',
+                **kwargs)
+
+        register('build', 'threads', PositiveIntegerType,
+            default=multiprocessing.cpu_count())
+
+