mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
104 lines
4.1 KiB
ReStructuredText
104 lines
4.1 KiB
ReStructuredText
The mach Driver
|
|
===============
|
|
|
|
The *mach* driver is the command line interface (CLI) to the source tree.
|
|
|
|
The *mach* driver is invoked by running the *mach* script or from
|
|
instantiating the *Mach* class from the *mach.main* module.
|
|
|
|
Implementing mach Commands
|
|
--------------------------
|
|
|
|
The *mach* driver follows the convention of popular tools like Git,
|
|
Subversion, and Mercurial and provides a common driver for multiple
|
|
sub-commands.
|
|
|
|
Modules inside *mach* typically contain 1 or more classes which
|
|
inherit from *mach.base.ArgumentProvider*. Modules that inherit from
|
|
this class are hooked up to the *mach* CLI driver. So, to add a new
|
|
sub-command/action to *mach*, one simply needs to create a new class in
|
|
the *mach* package which inherits from *ArgumentProvider*.
|
|
|
|
Currently, you also need to hook up some plumbing in
|
|
*mach.main.Mach*. In the future, we hope to have automatic detection
|
|
of submodules.
|
|
|
|
Your command class performs the role of configuring the *mach* frontend
|
|
argument parser as well as providing the methods invoked if a command is
|
|
requested. These methods will take the user-supplied input, do something
|
|
(likely by calling a backend function in a separate module), then format
|
|
output to the terminal.
|
|
|
|
The plumbing to hook up the arguments to the *mach* driver involves
|
|
light magic. At *mach* invocation time, the driver creates a new
|
|
*argparse* instance. For each registered class that provides commands,
|
|
it calls the *populate_argparse* static method, passing it the parser
|
|
instance.
|
|
|
|
Your class's *populate_argparse* function should register sub-commands
|
|
with the parser.
|
|
|
|
For example, say you want to provide the *doitall* command. e.g. *mach
|
|
doitall*. You would create the module *mach.doitall* and this
|
|
module would contain the following class:
|
|
|
|
from mach.base import ArgumentProvider
|
|
|
|
class DoItAll(ArgumentProvider):
|
|
def run(self, more=False):
|
|
print 'I did it!'
|
|
|
|
@staticmethod
|
|
def populate_argparse(parser):
|
|
# Create the parser to handle the sub-command.
|
|
p = parser.add_parser('doitall', help='Do it all!')
|
|
|
|
p.add_argument('more', action='store_true', default=False,
|
|
help='Do more!')
|
|
|
|
# Tell driver that the handler for this sub-command is the
|
|
# method *run* on the class *DoItAll*.
|
|
p.set_defaults(cls=DoItAll, method='run')
|
|
|
|
The most important line here is the call to *set_defaults*.
|
|
Specifically, the *cls* and *method* parameters, which tell the driver
|
|
which class to instantiate and which method to execute if this command
|
|
is requested.
|
|
|
|
The specified method will receive all arguments parsed from the command.
|
|
It is important that you use named - not positional - arguments for your
|
|
handler functions or things will blow up. This is because the mach driver
|
|
is using the ``**kwargs`` notation to call the defined method.
|
|
|
|
In the future, we may provide additional syntactical sugar to make all
|
|
this easier. For example, we may provide decorators on methods to hook
|
|
up commands and handlers.
|
|
|
|
Minimizing Code in Mach
|
|
-----------------------
|
|
|
|
Mach is just a frontend. Therefore, code in this package should pertain to
|
|
one of 3 areas:
|
|
|
|
1. Obtaining user input (parsing arguments, prompting, etc)
|
|
2. Calling into some other Python package
|
|
3. Formatting output
|
|
|
|
Mach should not contain core logic pertaining to the desired task. If you
|
|
find yourself needing to invent some new functionality, you should implement
|
|
it as a generic package outside of mach and then write a mach shim to call
|
|
into it. There are many advantages to this approach, including reusability
|
|
outside of mach (others may want to write other frontends) and easier testing
|
|
(it is easier to test generic libraries than code that interacts with the
|
|
command line or terminal).
|
|
|
|
Keeping Frontend Modules Small
|
|
------------------------------
|
|
|
|
The frontend modules providing mach commands are currently all loaded when
|
|
the mach CLI driver starts. Therefore, there is potential for *import bloat*.
|
|
|
|
We want the CLI driver to load quickly. So, please delay load external modules
|
|
until they are actually required. In other words, don't use a global
|
|
*import* when you can import from inside a specific command's handler.
|