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.
--- 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())
+
+