实现命令

Mach 命令通过 Python 装饰器定义。

所有相关的装饰器都在 mach.decorators 模块中定义。重要的装饰器如下

Command

一个函数装饰器,表示当请求指定命令时应调用该函数。装饰器将命令名称作为其第一个参数,以及一些其他参数来配置命令的行为。装饰的函数必须将 command_context 参数作为其第一个参数。 command_contextMozbuildObject 子类的正确配置的实例,这意味着它可以用于访问诸如当前配置和运行进程之类的东西。

CommandArgument

一个函数装饰器,用于定义命令的参数。其参数基本上被代理到 ArgumentParser.add_argument()

SubCommand

一个函数装饰器,表示该函数应该是现有 @Command 的子命令。装饰器将父命令名称作为其第一个参数,将子命令名称作为其第二个参数。

@CommandArgument 可以用于 @SubCommand 实例,就像它们可以用于 @Command 实例一样。

这是一个完整的示例

from mach.decorators import (
  CommandArgument,
  Command,
)

@Command('doit', help='Do ALL OF THE THINGS.')
@CommandArgument('--force', '-f', action='store_true',
    help='Force doing it.')
def doit(command_context, force=False):
    # Do stuff here.

当模块加载时,装饰器会告诉 mach 所有处理程序。当 mach 运行时,它会获取来自这些处理程序的组装的元数据,并将其挂接到命令行驱动程序。在后台,传递给装饰器的参数用于帮助 mach 解析命令参数,制定方法的参数等。有关更多信息,请参阅 mach.base 模块中的文档。

定义 mach 命令的 Python 模块不需要位于主 mach 源代码树内。

有条件地筛选命令

有时,只有在特定上下文中运行命令才有意义。例如,运行测试只有在它们正在测试的产品已构建并且该构建可用时才有意义。为了确保命令只能在正确的上下文中运行,可以在 Command 装饰器上定义一系列条件。

条件只是一个函数,它将 mozbuild.base.MachCommandBase() 类的实例作为参数,并返回 TrueFalse。如果命令上定义的任何条件返回 False,则该命令将无法运行。条件函数的文档字符串用于错误消息中,以解释为什么当前无法运行该命令。

这是一个示例

from mach.decorators import (
    Command,
)

def build_available(cls):
    """The build needs to be available."""
    return cls.build_path is not None

@Command('run_tests', conditions=[build_available])
def run_tests(command_context):
    # Do stuff here.

默认情况下,所有未应用任何条件的命令都将可运行,但可以通过将 require_conditions 设置为 True 来更改此行为

m = mach.main.Mach()
m.require_conditions = True

最小化命令中的代码

Mach 命令模块、类和方法在它们是最小调度程序时效果最佳。原因是导入膨胀。目前,mach 核心需要为每次命令调用导入可能包含 mach 命令的每个 Python 文件。如果您有数十个命令或导入大量 Python 代码的模块中的命令,这些导入可能会降低 mach 的速度并浪费内存。

因此建议 mach 模块、类和方法尽可能少地执行工作。理想情况下,模块应该只从 mach 包中导入。如果您需要外部模块,则应在命令方法内部导入它们。

为了保持代码大小较小,命令方法的主体应限于

  1. 获取用户输入(解析参数、提示等)

  2. 调用其他一些 Python 包

  3. 格式化输出

当然,如果您想冒性能下降的风险,可以忽略这些建议。

将来,mach 驱动程序可能会缓存调度信息或使其智能加载以促进延迟加载。