自定义命令¶
借助 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
是将处理命令返回信息的函数实例。
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
,但此装饰器用于声明现有自定义命令的子命令。例如
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}
命令参数¶
这些是传递给任何自定义命令及其子命令函数的参数
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_api
:ConanAPI
类的实例。有关详细信息,请参阅 conan.api.conan_api.ConanAPI 部分parser
:Pythonargparse.ArgumentParser
类的根实例,供主命令函数使用。有关更多信息,请参阅 argparse 官方网站。subparser
(仅用于子命令):每个子命令函数的 Pythonargparse.ArgumentParser
类的子实例。*args
:通过命令行传递的所有参数的列表,将在命令函数内部进行解析和使用。通常,它们将被解析为args = parser.parse_args(*args)
。例如,运行 conan mycommand arg1 arg2 arg3,命令函数将接收它们作为类似 Python 列表的["arg1", "arg2", "arg3"]
。
另请参阅
您可以在 conan-extensions 存储库中查看更多 Conan 自定义命令的示例 https://github.com/conan-io/conan-extensions