自定义命令

借助 Python 和 Conan 公共 API 的强大功能,可以创建您自己的 Conan 命令来解决自身需求。

位置和命名

所有自定义命令都必须位于 [YOUR_CONAN_HOME]/extensions/commands/ 文件夹中。如果您不知道 [YOUR_CONAN_HOME] 的位置,可以运行 conan config home 进行查看。

如果 _commands_ 子目录尚未创建,则需要创建它。这些自定义命令文件必须是 Python 文件,并且以 cmd_[your_command_name].py 为前缀。自定义命令的调用方式与任何其他现有的 Conan 命令一样: conan your_command_name

作用域

可以添加另一个文件夹层,将一些命令分组到同一主题下。

例如

| - [YOUR_CONAN_HOME]/extensions/commands/greet/
      | - cmd_hello.py
      | - cmd_bye.py

对这些命令的调用略有变化: conan [topic_name]:your_command_name。根据前面的示例

$ conan greet:hello
$ conan greet:bye

注意

仅允许一层文件夹,因此像 [YOUR_CONAN_HOME]/extensions/commands/topic1/topic2/cmd_command.py 这样的结构将无法正常工作。

装饰器

conan_command(group=None, formatters=None)

声明函数为新的 Conan 命令的主要装饰器。参数如下:

  • group 是以相同名称声明的命令组的名称。此分组将在执行 conan -h 命令时显示。

  • formatters 是一个类似字典的 Python 对象,其中 key 是格式化程序名称,value 是将处理命令返回信息的函数实例。

cmd_hello.py
import json

from conan.api.conan_api import ConanAPI
from conan.api.output import ConanOutput
from conan.cli.command import conan_command

def output_json(msg):
    return json.dumps({"greet": msg})


@conan_command(group="Custom commands", formatters={"json": output_json})
def hello(conan_api: ConanAPI, parser, *args):
    """
    Simple command to print "Hello World!" line
    """
    msg = "Hello World!"
    ConanOutput().info(msg)
    return msg

重要

@conan_command(....) 装饰的函数必须与 Python 文件使用的后缀相同。例如,在前面的示例中,文件名是 cmd_hello.py,装饰的命令函数是 def hello(....)

conan_subcommand(formatters=None)

类似于 conan_command,但此装饰器用于声明现有自定义命令的子命令。例如

cmd_hello.py
from conan.api.conan_api import ConanAPI
from conan.api.output import ConanOutput
from conan.cli.command import conan_command, conan_subcommand


@conan_subcommand()
def hello_moon(conan_api, parser, subparser, *args):
    """
    Sub-command of "hello" that prints "Hello Moon!" line
    """
    ConanOutput().info("Hello Moon!")


@conan_command(group="Custom commands")
def hello(conan_api: ConanAPI, parser, *args):
    """
    Simple command "hello"
    """

命令调用方式如下: conan hello moon

注意

请注意,要声明子命令,需要一个空 Python 函数充当主命令。

参数定义和解析

命令可以使用 argparse Python 库定义自己的参数。

@conan_command(group='Creator')
def build(conan_api, parser, *args):
    """
    Command help
    """
    parser.add_argument("path", nargs="?", help='help for command')
    ...
    args = parser.parse_args(*args)
    # Use args.path

当存在子命令时,基命令无法定义参数,只有子命令可以定义。如果有一组对所有子命令都通用的参数,则可以定义一个函数来添加它们。

@conan_command(group="MyGroup")
def mycommand(conan_api, parser, *args):
    """
    Command help
    """
    # Do not define arguments in the base command
    pass

@conan_subcommand()
def mycommand_mysubcommand(conan_api: ConanAPI, parser, subparser, *args):
    """
    Subcommand help
    """
    # Arguments are added to "subparser"
    subparser.add_argument("reference", help="Recipe reference or Package reference")
    # You can add common args with your helper
    # add_my_common_args(subparser)
    # But parsing all of them happens to "parser"
    args = parser.parse_args(*args)
    # use args.reference

格式化程序

命令的返回值将作为参数传递给格式化程序。如果不同的格式化程序需要不同的参数,则可以通过返回一个字典来实现,并让格式化程序选择它们需要的参数。例如,graph info 命令使用几个格式化程序,例如

def format_graph_html(result):
    graph = result["graph"]
    conan_api = result["conan_api"]
    ...

def format_graph_info(result):
    graph = result["graph"]
    field_filter = result["field_filter"]
    package_filter = result["package_filter"]
    ...

@conan_subcommand(formatters={"text": format_graph_info,
                              "html": format_graph_html,
                              "json": format_graph_json,
                              "dot": format_graph_dot})
def graph_info(conan_api, parser, subparser, *args):
    ...
    return {"graph": deps_graph,
            "field_filter": args.filter,
            "package_filter": args.package_filter,
            "conan_api": conan_api}

命令参数

这些是传递给任何自定义命令及其子命令函数的参数

cmd_command.py
from conan.cli.command import conan_command, conan_subcommand


@conan_subcommand()
def command_subcommand(conan_api, parser, subparser, *args):
    """
    subcommand information. This info will appear on ``conan command subcommand -h``.

    :param conan_api: <object conan.api.conan_api.ConanAPI> instance
    :param parser: root <object argparse.ArgumentParser> instance (coming from main command)
    :param subparser: <object argparse.ArgumentParser> instance for sub-command
    :param args: ``list`` of all the arguments passed after sub-command call
    :return: (optional) whatever is returned will be passed to formatters functions (if declared)
    """
    # ...


@conan_command(group="Custom commands")
def command(conan_api, parser, *args):
    """
    command information. This info will appear on ``conan command -h``.

    :param conan_api: <object conan.api.conan_api.ConanAPI> instance
    :param parser: root <object argparse.ArgumentParser> instance
    :param args: ``list`` of all the arguments passed after command call
    :return: (optional) whatever is returned will be passed to formatters functions (if declared)
    """
    # ...
  • conan_apiConanAPI 类的实例。有关详细信息,请参阅 conan.api.conan_api.ConanAPI 部分

  • parser:Python argparse.ArgumentParser 类的根实例,供主命令函数使用。有关更多信息,请参阅 argparse 官方网站

  • subparser(仅用于子命令):每个子命令函数的 Python argparse.ArgumentParser 类的子实例。

  • *args:通过命令行传递的所有参数的列表,将在命令函数内部进行解析和使用。通常,它们将被解析为 args = parser.parse_args(*args)。例如,运行 conan mycommand arg1 arg2 arg3,命令函数将接收它们作为类似 Python 列表的 ["arg1", "arg2", "arg3"]

另请参阅