一个 C 或 C++ 包通常包含多个 C 和 C++ 构件、头文件、编译后的库和可执行文件。但还有一些文件对于正常使用该包可能不是必需的,但出于技术或业务原因(如法规、合规性、安全性、可重复性和可追溯性)可能非常重要。一些示例包括:

  • 完整构建日志
  • 测试可执行文件
  • 运行测试套件得到的测试结果
  • 调试构件,例如大型 .pdb 文件
  • 覆盖率、sanitizers 或其他源代码或二进制分析工具的结果
  • 关于构建、确切机器、环境、作者、CI 数据的上下文和元数据
  • 其他合规性和安全相关文件

这些文件的问题在于它们可能很大/很重,如果我们将其存储在包内(只需将构件复制到 package() 方法中),这将使包变得更大,并会影响下载、解压缩和一般使用包的速度。这种情况通常发生很多次,无论是在开发人员机器上还是在 CI 中,它都会对开发人员体验和基础设施成本产生影响。此外,包是不可变的,也就是说,一旦创建了包,就不应该对其进行修改。如果我们希望在创建包之后或甚至在上传包之后添加额外的元数据文件,这可能是一个问题。

新的 **元数据文件** 功能允许以集成和统一的方式创建、上传、追加和存储与包关联的元数据,同时避免对开发人员和 CI 速度和成本造成影响,因为默认情况下,使用包时不会下载和解压缩元数据文件。

创建元数据

配方可以直接定义元数据,一个常见的用例是将构建日志作为元数据显式存储在配方中,这可以通过将文件或文件夹复制到 self.package_metadata_folder 来完成。

import os
from conan import ConanFile
from conan.tools.files import copy


class Pkg(ConanFile):
  name = "pkg"
  version = "0.1"

  def build(self):
      # logs originated at build() step, the most common ones
      # assume that "mylogs.txt" is the output of some build steps 
      copy(self, "mylogs.txt", src=self.build_folder,
          dst=os.path.join(self.package_metadata_folder, "logs"))

当此配方从源代码构建时,无论是在 Conan 缓存中使用 conan create 还是在本地使用 conan build,它都会将这些日志复制到“metadata”文件夹。当包在缓存中创建时,我们可以借助 conan cache path 命令轻松检查 metadata 文件夹。

$ conan create .
$ conan cache path pkg/0.1:package_id --folder=metadata
# folder containing the specific "package_id" binary metadata

如果在多个包的构建中创建了相同的文件,我们也可以使用钩子。让我们来看这个更简单的配方,它没有显式存储构建日志的元数据,而只是在构建时生成文件。

from conan import ConanFile
from conan.tools.files import save


class Pkg(ConanFile):
  name = "pkg"
  version = "0.1"

  def build(self):
      # logs originated at build() step, the most common ones
      # assume that "mylogs.txt" is the output of some build steps
      save(self, "mylogs.txt", "some logs!!!")

可以定义一个 post_build 钩子,它与配方内的版本具有相同的效果,主要区别在于钩子适用于所有包。

import os
from conan.tools.files import copy


def post_build(conanfile):
      conanfile.output.info("post_build")
      copy(conanfile, "*", src=conanfile.build_folder,
        dst=os.path.join(conanfile.package_metadata_folder, "logs"))

也可以在创建包之后添加或修改元数据文件。为此,使用 conan cache path 命令将返回执行该操作的文件夹,因此在该位置复制、创建或修改文件将实现此目的。与修改包文件相反,允许进行此操作,因为包必须是不可变的。

$ conan create . --name=pkg --version=0.1
$ conan cache path pkg/0.1:package_id --folder=metadata
# we can copy and put files in that folder

上传元数据

到目前为止,元数据已在本地创建并存储在 Conan 缓存中。将元数据上传到服务器已与现有的 conan upload 命令集成。

$ conan upload "*" -c -r=myremote
# Uploads recipes, packages and metadata to the "myremote" remote
...
pkg/0.1: Recipe metadata: 1 files
pkg/0.1:da39a3ee5e6b4b0d3255bfef95601890afd80709: Package metadata: 1 files

默认情况下,conan upload 会在将配方或包上传到服务器时上传配方和包元数据。

但在某些情况下,Conan 将完全避免此上传,如果它检测到修订版已存在于服务器中,则不会上传配方或包。如果元数据已在本地修改或添加了新文件,我们可以使用 --metadata 参数显式强制上传元数据。

# We added some metadata to the packages in the cache
# But those packages already exist in the server
$ conan upload "*" -c -r=myremote --metadata="*"
...
pkg/0.1: Recipe metadata: 1 files
pkg/0.1:da39a3ee5e6b4b0d3255bfef95601890afd80709: Package metadata: 1 files

--metadata 参数允许我们指定要上传的元数据文件。如果我们将其结构化到文件夹中,例如,我们可以指定 --metadata=logs* 以仅上传日志元数据。

# Upload only the logs metadata of the zlib/1.2.13 binaries
# This will upload the logs even if zlib/1.2.13 is already in the server
$ conan upload "zlib/1.2.13:*" -r=myremote -c --metadata="logs/*"
# Multiple patterns are allowed:
$ conan upload "*" -r=myremote -c --metadata="logs/*" --metadata="tests/*"

下载元数据

如引言中所述,默认情况下不会下载元数据。当使用 conan installconan create 从服务器获取依赖项下载包时,不会下载来自这些服务器的元数据。

从服务器恢复元数据的方法是使用 conan download 命令显式指定它。

# Get the metadata of the "pkg/0.1" package
$ conan download pkg/0.1 -r=myremote --metadata="*"
...
$ conan cache path pkg/0.1:package_id --folder=metadata
# Inspect the package metadata for binary "package_id"

元数据的检索是通过每个包的 download 完成的。如果我们想下载整个依赖关系图的元数据,则需要使用“包列表”。

$ conan install . --format=json -r=myremote > graph.json
$ conan list --graph=graph.json --format=json > pkglist.json
# the list will contain the "myremote" origin of downloaded packages
$ conan download --list=pkglist.json --metadata="*" -r=myremote

请注意,“包列表”仅包含与已下载的“myremote”来源关联的包。如果它们以前存在于缓存中,则它们不会在“myremote”来源下列出,并且不会下载元数据。如果要收集依赖项元数据,请在从服务器安装包时将其下载。还有其他可能性,例如自定义命令,可以自动从服务器收集和下载依赖项元数据。

结论

**元数据文件** 一直是人们期待已久的功能请求,我们非常高兴能够发布它。我们相信它将帮助许多用户更好地管理其元数据文件和资产,简化这些文件的管理、存储、跟踪和检索。这可以减少实施更好的合规性、可重复性、可追溯性和安全性的工作量和成本。

需要强调的是,添加此新功能要归功于新的 Conan 2.0 架构和功能。Conan 2.0 这个新的主要版本之所以必要,其中一个原因是为了解锁这些期待已久的功能,而这些功能在 Conan 1.X 中无法实现。

有关元数据文件和其他相关功能的更多信息,请查看新的文档 Devops 指南

我们期待收到您的反馈、用例和需求,以便不断改进此功能。请在 Github 问题 中报告。