自定义命令:清理旧配方和包版本

自定义命令:清理旧配方和包版本#

请首先克隆源代码以重新创建此项目。你可以在 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 命令具有以下代码:

列表 58 cmd_clean.py#
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#

parser 参数是 Python 命令行解析 argparse.ArgumentParser 的实例,如果你想了解更多关于它的 API,请访问它的官方网站

用户输出#

ConanOutput() : 管理用户输出的类。在这个示例中,只使用了 out.writeln(message, fg=None, bg=None) ,其中 fg 是字体前景色,bg 是字体背景色。除此之外,还有一些预定义的方法,如 out.info()out.success()out.error() 等。

Conan 公共 API#

这个示例中最重要的部分是通过 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 部分