Bug 1845017 - Disable the TestPHCExhaustion test r=glandium
[gecko.git] / python / mach / docs / commands.rst
blob754719300040ff2dc4fbef431a78d5693cff97f9
1 .. _mach_commands:
3 =====================
4 Implementing Commands
5 =====================
7 Mach commands are defined via Python decorators.
9 All the relevant decorators are defined in the *mach.decorators* module.
10 The important decorators are as follows:
12 :py:func:`Command <mach.decorators.Command>`
13   A function decorator that denotes that the function should be called when
14   the specified command is requested. The decorator takes a command name
15   as its first argument and a number of additional arguments to
16   configure the behavior of the command. The decorated function must take a
17   ``command_context`` argument as its first.
18   ``command_context`` is a properly configured instance of a ``MozbuildObject``
19   subclass, meaning it can be used for accessing things like the current config
20   and running processes.
22 :py:func:`CommandArgument <mach.decorators.CommandArgument>`
23   A function decorator that defines an argument to the command. Its
24   arguments are essentially proxied to ArgumentParser.add_argument()
26 :py:func:`SubCommand <mach.decorators.SubCommand>`
27   A function decorator that denotes that the function should be a
28   sub-command to an existing ``@Command``. The decorator takes the
29   parent command name as its first argument and the sub-command name
30   as its second argument.
32   ``@CommandArgument`` can be used on ``@SubCommand`` instances just
33   like they can on ``@Command`` instances.
36 Here is a complete example:
38 .. code-block:: python
40    from mach.decorators import (
41        CommandArgument,
42        Command,
43    )
45     @Command('doit', help='Do ALL OF THE THINGS.')
46     @CommandArgument('--force', '-f', action='store_true',
47         help='Force doing it.')
48     def doit(command_context, force=False):
49         # Do stuff here.
51 When the module is loaded, the decorators tell mach about all handlers.
52 When mach runs, it takes the assembled metadata from these handlers and
53 hooks it up to the command line driver. Under the hood, arguments passed
54 to the decorators are being used to help mach parse command arguments,
55 formulate arguments to the methods, etc. See the documentation in the
56 :py:mod:`mach.base` module for more.
58 The Python modules defining mach commands do not need to live inside the
59 main mach source tree.
61 Conditionally Filtering Commands
62 ================================
64 Sometimes it might only make sense to run a command given a certain
65 context. For example, running tests only makes sense if the product
66 they are testing has been built, and said build is available. To make
67 sure a command is only runnable from within a correct context, you can
68 define a series of conditions on the
69 :py:func:`Command <mach.decorators.Command>` decorator.
71 A condition is simply a function that takes an instance of the
72 :py:func:`mozbuild.base.MachCommandBase` class as an argument, and
73 returns ``True`` or ``False``. If any of the conditions defined on a
74 command return ``False``, the command will not be runnable. The
75 docstring of a condition function is used in error messages, to explain
76 why the command cannot currently be run.
78 Here is an example:
80 .. code-block:: python
82    from mach.decorators import (
83        Command,
84    )
86    def build_available(cls):
87        """The build needs to be available."""
88        return cls.build_path is not None
90    @Command('run_tests', conditions=[build_available])
91    def run_tests(command_context):
92        # Do stuff here.
94 By default all commands without any conditions applied will be runnable,
95 but it is possible to change this behaviour by setting
96 ``require_conditions`` to ``True``:
98 .. code-block:: python
100    m = mach.main.Mach()
101    m.require_conditions = True
103 Minimizing Code in Commands
104 ===========================
106 Mach command modules, classes, and methods work best when they are
107 minimal dispatchers. The reason is import bloat. Currently, the mach
108 core needs to import every Python file potentially containing mach
109 commands for every command invocation. If you have dozens of commands or
110 commands in modules that import a lot of Python code, these imports
111 could slow mach down and waste memory.
113 It is thus recommended that mach modules, classes, and methods do as
114 little work as possible. Ideally the module should only import from
115 the :py:mod:`mach` package. If you need external modules, you should
116 import them from within the command method.
118 To keep code size small, the body of a command method should be limited
121 1. Obtaining user input (parsing arguments, prompting, etc)
122 2. Calling into some other Python package
123 3. Formatting output
125 Of course, these recommendations can be ignored if you want to risk
126 slower performance.
128 In the future, the mach driver may cache the dispatching information or
129 have it intelligently loaded to facilitate lazy loading.