自定义命令:清理旧的配方和包版本¶
注意
这主要是一个示例命令。内置的 conan remove *#!latest
语法,表示“除最新版本外的所有版本”,可能足以满足此用例,无需此自定义命令。
请先克隆源代码以重新创建此项目。您可以在 GitHub 上的 examples2 存储库 中找到它们。
$ git clone https://github.com/conan-io/examples2.git
$ cd examples2/examples/extensions/commands/clean
在此示例中,我们将了解如何创建/使用自定义命令:conan clean。它会从本地缓存或远程存储库中删除每个配方及其包版本,除了最新配方中的最新包版本。
注意
为了更好地理解此示例,强烈建议您事先阅读 自定义命令参考。
定位命令¶
将命令文件 cmd_clean.py
复制到您的 [YOUR_CONAN_HOME]/extensions/commands/
文件夹中(如果不存在则创建它)。如果您不知道 [YOUR_CONAN_HOME]
的位置,您可以运行 conan config home 来检查它。
运行它¶
现在,您应该能够在命令提示符中看到新的命令。
$ conan -h
...
Custom commands
clean Deletes (from local cache or remotes) all recipe and package revisions but the
latest package revision from the latest recipe revision.
$ conan clean -h
usage: conan clean [-h] [-r REMOTE] [--force]
Deletes (from local cache or remotes) all recipe and package revisions but
the latest package revision from the latest recipe revision.
optional arguments:
-h, --help show this help message and exit
-r REMOTE, --remote REMOTE
Will remove from the specified remote
--force Remove without requesting a confirmation
最后,如果您执行 conan clean
$ conan clean
Do you want to remove all the recipes revisions and their packages ones, except the latest package revision from the latest recipe one? (yes/no): yes
other/1.0
Removed package revision: other/1.0#31da245c3399e4124e39bd4f77b5261f:da39a3ee5e6b4b0d3255bfef95601890afd80709#a16985deb2e1aa73a8480faad22b722c [Local cache]
Removed recipe revision: other/1.0#721995a35b1a8d840ce634ea1ac71161 and all its package revisions [Local cache]
hello/1.0
Removed package revision: hello/1.0#9a77cdcff3a539b5b077dd811b2ae3b0:da39a3ee5e6b4b0d3255bfef95601890afd80709#cee90a74944125e7e9b4f74210bfec3f [Local cache]
Removed package revision: hello/1.0#9a77cdcff3a539b5b077dd811b2ae3b0:da39a3ee5e6b4b0d3255bfef95601890afd80709#7cddd50952de9935d6c3b5b676a34c48 [Local cache]
libcxx/0.1
如果您再次运行它,则不应该发生任何事情。
$ conan clean
Do you want to remove all the recipes revisions and their packages ones, except the latest package revision from the latest recipe one? (yes/no): yes
other/1.0
hello/1.0
libcxx/0.1
代码导览¶
conan clean
命令具有以下代码
from conan.api.conan_api import ConanAPI
from conan.api.output import ConanOutput, Color
from conan.cli.command import OnceArgument, conan_command
recipe_color = Color.BRIGHT_BLUE
removed_color = Color.BRIGHT_YELLOW
@conan_command(group="Custom commands")
def clean(conan_api: ConanAPI, parser, *args):
"""
Deletes (from local cache or remotes) all recipe and package revisions but
the latest package revision from the latest recipe revision.
"""
parser.add_argument('-r', '--remote', action=OnceArgument,
help='Will remove from the specified remote')
args = parser.parse_args(*args)
out = ConanOutput()
remote = conan_api.remotes.get(args.remote) if args.remote else None
output_remote = remote or "Local cache"
# Getting all the recipes
recipes = conan_api.search.recipes("*/*", remote=remote)
for recipe in recipes:
out.writeln(f"{str(recipe)}", fg=recipe_color)
all_rrevs = conan_api.list.recipe_revisions(recipe, remote=remote)
latest_rrev = all_rrevs[0] if all_rrevs else None
for rrev in all_rrevs:
if rrev != latest_rrev:
conan_api.remove.recipe(rrev, remote=remote)
out.writeln(f"Removed recipe revision: {rrev.repr_notime()} "
f"and all its package revisions [{output_remote}]", fg=removed_color)
else:
packages = conan_api.list.packages_configurations(rrev, remote=remote)
for package_ref in packages:
all_prevs = conan_api.list.package_revisions(package_ref, remote=remote)
latest_prev = all_prevs[0] if all_prevs else None
for prev in all_prevs:
if prev != latest_prev:
conan_api.remove.package(prev, remote=remote)
out.writeln(f"Removed package revision: {prev.repr_notime()} [{output_remote}]", fg=removed_color)
让我们分析最重要的部分。
解析器¶
parser
参数是 Python 命令行解析 argparse.ArgumentParser
的实例,因此如果您想了解更多关于其 API 的信息,请访问 其官方网站。
用户输出¶
ConanOutput()
:用于管理用户输出的类。在此示例中,我们仅使用 out.writeln(message, fg=None, bg=None)
,其中 fg
是字体前景色,bg
是字体背景色。除此之外,您还有一些预定义的方法,例如 out.info()
、out.success()
、out.error()
等。
Conan 公共 API¶
警告
此功能处于实验阶段,可能会发生重大更改。有关更多信息,请参阅 Conan 稳定性 部分。
此示例中最重要的部分是通过 conan_api
参数使用 Conan API。
conan_api.remotes.get(args.remote)
conan_api.search.recipes("*/*", remote=remote)
conan_api.list.recipe_revisions(recipe, remote=remote)
conan_api.remove.recipe(rrev, remote=remote)
conan_api.list.packages_configurations(rrev, remote=remote)
conan_api.list.package_revisions(package_ref, remote=remote)
conan_api.remove.package(prev, remote=remote)
conan_api.remotes.get(...)
:[RemotesAPI]
给定远程名称,返回一个 RemoteRegistry。conan_api.search.recipes(...)
:[SearchAPI]
返回一个包含所有与给定模式匹配的配方的列表。conan_api.list.recipe_revisions(...)
:[ListAPI]
返回一个包含给定配方引用所有配方版本的列表。conan_api.list.packages_configurations(...)
:[ListAPI]
返回给定配方版本的不同配置(package_id)的列表。conan_api.list.package_revisions(...)
:[ListAPI]
返回给定配方版本的所有包版本的列表。conan_api.remove.recipe(...)
:[RemoveAPI]
删除给定的配方版本。conan_api.remove.package(...)
:[RemoveAPI]
删除给定的包版本。
除此之外,以下几行代码值得特别注意
all_rrevs = conan_api.list.recipe_revisions(recipe, remote=remote)
latest_rrev = all_rrevs[0] if all_rrevs else None
...
packages = conan_api.list.packages_configurations(rrev, remote=remote)
...
all_prevs = conan_api.list.package_revisions(package_ref, remote=remote)
latest_prev = all_prevs[0] if all_prevs else None
基本上,这些 API 调用分别返回一个配方版本和包版本的列表,但我们保存第一个元素作为最新版本,因为这些调用始终获取一个有序列表。
如果您想了解更多关于 Conan API 的信息,请访问 ConanAPI 部分