自定义命令

借助 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 是格式化程序的名称,而值是函数实例,该实例将处理命令返回的信息。

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 section 中查看更多相关信息

  • parser:Python argparse.ArgumentParser 类的根实例,供主命令函数使用。 在 argparse 官方网站 中查看更多信息。

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

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