diff options
Diffstat (limited to 'python/mach/docs/commands.rst')
-rw-r--r-- | python/mach/docs/commands.rst | 145 |
1 files changed, 0 insertions, 145 deletions
diff --git a/python/mach/docs/commands.rst b/python/mach/docs/commands.rst deleted file mode 100644 index af2973dd7e7..00000000000 --- a/python/mach/docs/commands.rst +++ /dev/null @@ -1,145 +0,0 @@ -.. _mach_commands: - -===================== -Implementing Commands -===================== - -Mach commands are defined via Python decorators. - -All the relevant decorators are defined in the *mach.decorators* module. -The important decorators are as follows: - -:py:func:`CommandProvider <mach.decorators.CommandProvider>` - A class decorator that denotes that a class contains mach - commands. The decorator takes no arguments. - -:py:func:`Command <mach.decorators.Command>` - A method decorator that denotes that the method should be called when - the specified command is requested. The decorator takes a command name - as its first argument and a number of additional arguments to - configure the behavior of the command. - -:py:func:`CommandArgument <mach.decorators.CommandArgument>` - A method decorator that defines an argument to the command. Its - arguments are essentially proxied to ArgumentParser.add_argument() - -:py:func:`SubCommand <mach.decorators.SubCommand>` - A method decorator that denotes that the method should be a - sub-command to an existing ``@Command``. The decorator takes the - parent command name as its first argument and the sub-command name - as its second argument. - - ``@CommandArgument`` can be used on ``@SubCommand`` instances just - like they can on ``@Command`` instances. - -Classes with the ``@CommandProvider`` decorator **must** have an -``__init__`` method that accepts 1 or 2 arguments. If it accepts 2 -arguments, the 2nd argument will be a -:py:class:`mach.base.CommandContext` instance. - -Here is a complete example: - -.. code-block:: python - - from mach.decorators import ( - CommandArgument, - CommandProvider, - Command, - ) - - @CommandProvider - class MyClass(object): - @Command('doit', help='Do ALL OF THE THINGS.') - @CommandArgument('--force', '-f', action='store_true', - help='Force doing it.') - def doit(self, force=False): - # Do stuff here. - -When the module is loaded, the decorators tell mach about all handlers. -When mach runs, it takes the assembled metadata from these handlers and -hooks it up to the command line driver. Under the hood, arguments passed -to the decorators are being used to help mach parse command arguments, -formulate arguments to the methods, etc. See the documentation in the -:py:mod:`mach.base` module for more. - -The Python modules defining mach commands do not need to live inside the -main mach source tree. - -Conditionally Filtering Commands -================================ - -Sometimes it might only make sense to run a command given a certain -context. For example, running tests only makes sense if the product -they are testing has been built, and said build is available. To make -sure a command is only runnable from within a correct context, you can -define a series of conditions on the -:py:func:`Command <mach.decorators.Command>` decorator. - -A condition is simply a function that takes an instance of the -:py:func:`mach.decorators.CommandProvider` class as an argument, and -returns ``True`` or ``False``. If any of the conditions defined on a -command return ``False``, the command will not be runnable. The -docstring of a condition function is used in error messages, to explain -why the command cannot currently be run. - -Here is an example: - -.. code-block:: python - - from mach.decorators import ( - CommandProvider, - Command, - ) - - def build_available(cls): - """The build needs to be available.""" - return cls.build_path is not None - - @CommandProvider - class MyClass(MachCommandBase): - def __init__(self, build_path=None): - self.build_path = build_path - - @Command('run_tests', conditions=[build_available]) - def run_tests(self): - # Do stuff here. - -It is important to make sure that any state needed by the condition is -available to instances of the command provider. - -By default all commands without any conditions applied will be runnable, -but it is possible to change this behaviour by setting -``require_conditions`` to ``True``: - -.. code-block:: python - - m = mach.main.Mach() - m.require_conditions = True - -Minimizing Code in Commands -=========================== - -Mach command modules, classes, and methods work best when they are -minimal dispatchers. The reason is import bloat. Currently, the mach -core needs to import every Python file potentially containing mach -commands for every command invocation. If you have dozens of commands or -commands in modules that import a lot of Python code, these imports -could slow mach down and waste memory. - -It is thus recommended that mach modules, classes, and methods do as -little work as possible. Ideally the module should only import from -the :py:mod:`mach` package. If you need external modules, you should -import them from within the command method. - -To keep code size small, the body of a command method should be limited -to: - -1. Obtaining user input (parsing arguments, prompting, etc) -2. Calling into some other Python package -3. Formatting output - -Of course, these recommendations can be ignored if you want to risk -slower performance. - -In the future, the mach driver may cache the dispatching information or -have it intelligently loaded to facilitate lazy loading. |