01-注册表索引
9 分钟阅读
译文 · 基于 The Cargo Book
索引格式
原文链接: https://doc.rust-lang.org/cargo/reference/registry-index.html
以下定义索引的格式。偶尔会添加新特性,仅从引入它们的 Cargo 版本起才能理解。较旧版本的 Cargo 可能无法使用利用新特性的包。不过,较旧包的格式不应改变,因此较旧版本的 Cargo 应能使用它们。
索引配置
索引的根目录包含名为 config.json 的文件,其中包含 Cargo 用于访问注册表的 JSON 信息。以下是 crates.io 配置文件的示例:
| |
各键为:
dl:用于下载索引中所列 crate 的 URL。该值可包含以下标记,将被替换为对应值:{crate}:crate 的名称。{version}:crate 的版本。{prefix}:根据 crate 名称计算的目录前缀。例如,名为cargo的 crate 前缀为ca/rg。细节见下文。{lowerprefix}:{prefix}的小写变体。{sha256-checksum}:crate 的 sha256 校验和。
若没有任何标记,则在末尾追加
/{crate}/{version}/download。api:Web API 的基 URL。此键可选,但若未指定,cargo publish等命令将无法工作。Web API 见下文。此 URL 不应有尾部斜杠。auth-required:表示这是否为私有注册表,要求所有操作(包括 API 请求、crate 下载与稀疏索引更新)均需认证。
下载端点
下载端点应发送所请求包的 .crate 文件。
Cargo 支持 https、http 与 file URL、HTTP 重定向、HTTP1 与 HTTP2。
TLS 支持的确切细节取决于 Cargo 运行的平台、Cargo 版本及其编译方式。
若在 config.json 中设置了 auth-required: true,http(s) 下载请求将包含 Authorization 头。
索引文件
索引仓库的其余部分为每个包包含一个文件,文件名为包名的小写形式。包的每个版本在文件中占独立一行。文件按分层目录组织:
- 名称长度为 1 个字符的包放在名为
1的目录中。 - 名称长度为 2 个字符的包放在名为
2的目录中。 - 名称长度为 3 个字符的包放在目录
3/{first-character}中,其中{first-character}是包名的第一个字符。 - 所有其他包存放在名为
{first-two}/{second-two}的目录中,顶层目录是包名的前两个字符,下一层子目录是包名的第三、四个字符。例如,cargo会存放在名为ca/rg/cargo的文件中。
注意:尽管索引文件名是小写的,
Cargo.toml与索引 JSON 数据中包含包名的字段是区分大小写的,可包含大小写字符。
上述目录名根据转换为小写的包名计算;由标记 {lowerprefix} 表示。使用未经大小写转换的原始包名时,所得目录名由标记 {prefix} 表示。例如,包 MyCrate 的 {prefix} 为 My/Cr,{lowerprefix} 为 my/cr。一般而言,推荐使用 {prefix} 而非 {lowerprefix},但各有利弊。在大小写不敏感的文件系统上使用 {prefix} 会导致(无害但不优雅的)目录别名。例如,crate 与 CrateTwo 的 {prefix} 值分别为 cr/at 与 Cr/at;在 Unix 机器上它们是不同的,但在 Windows 上会别名到同一目录。使用规范化大小写的目录可避免别名,但在大小写敏感的文件系统上,更难支持缺少 {prefix}/{lowerprefix} 的较旧 Cargo 版本。例如,nginx 重写规则可以轻松构造 {prefix},但无法执行大小写转换来构造 {lowerprefix}。
名称限制
注册表应考虑对加入其索引的包名施加限制。Cargo 本身允许名称包含任意 字母数字、- 或 _ 字符。crates.io 施加了自己的限制,包括以下内容:
- 仅允许 ASCII 字符。
- 仅字母数字、
-与_字符。 - 首字符必须是字母。
- 不区分大小写的冲突检测。
- 防止
-与_的差异。 - 在特定长度以下(最大 64)。
- 拒绝保留名,如 Windows 特殊文件名「nul」。
注册表应考虑纳入类似限制,并考虑安全影响,例如 IDN 同形异义攻击 以及 UTR36 与 UTS39 中的其他问题。
版本唯一性
索引必须确保每个包的每个版本只出现一次。
这包括忽略 SemVer 构建元数据。
例如,索引不得包含版本为 1.0.7 与 1.0.7+extra 的两个条目。
JSON 模式
包文件中的每一行包含一个 JSON 对象,描述该包已发布的一个版本。以下是带注释的美化打印示例,说明条目的格式。
| |
JSON 对象在添加后不应修改,但 yanked 字段除外,其值可随时更改。
注意:索引 JSON 格式与 发布 API 以及
cargo metadata的 JSON 格式有细微差别。 若你使用其中之一作为生成索引条目的来源,鼓励仔细检查它们之间的文档差异。对于 发布 API,差异为:
deps
name—— 当依赖在Cargo.toml中重命名时,发布 API 将原始包名放在name字段,将别名放在explicit_name_in_toml字段。 索引将别名放在name字段,将原始包名放在package字段。req—— 发布 API 字段称为version_req。cksum—— 发布 API 不指定校验和,必须由注册表在加入索引前计算。features—— 某些特性可能放在features2字段中。 注意:这仅是对 crates.io 的遗留要求;其他注册表不必操心修改特性映射。v字段指示features2字段的存在。- 发布 API 包含若干其他字段,如
description与readme,它们不出现在索引中。 这些旨在让注册表更容易获取关于 crate 的元数据以在网站上显示,而无需解压并解析.crate文件。 这些额外信息通常添加到注册表服务器上的数据库中。- 尽管此处包含
rust_version,crates.io 会忽略此字段, 而改为从.crate文件中的Cargo.toml读取。对于
cargo metadata,差异为:
vers——cargo metadata字段称为version。deps
name—— 当依赖在Cargo.toml中重命名时,cargo metadata将原始包名放在name字段,将别名放在rename字段。 索引将别名放在name字段,将原始包名放在package字段。default_features——cargo metadata字段称为uses_default_features。registry——cargo metadata用null表示依赖来自 crates.io。 索引用null表示依赖来自与索引相同的注册表。 创建索引条目时,非 crates.io 的注册表应将null翻译为https://github.com/rust-lang/crates.io-index,并将匹配当前索引的 URL 翻译为null。cargo metadata包含一些额外字段,如source与path。- 索引包含额外字段,如
yanked、cksum与v。
索引协议
Cargo 支持两种远程注册表协议:git 与 sparse。git 协议将索引文件存放在 git 仓库中,sparse 协议通过 HTTP 获取各个文件。
Git 协议
git 协议在索引 URL 中没有协议前缀。例如 crates.io 的 git 索引 URL 为 https://github.com/rust-lang/crates.io-index。
Cargo 将 git 仓库缓存在磁盘上,以便高效地增量获取更新。
Sparse 协议
稀疏协议在注册表 URL 中使用 sparse+ 协议前缀。例如,crates.io 的稀疏索引 URL 为 sparse+https://index.crates.io/。
稀疏协议使用单独的 HTTP 请求下载每个索引文件。由于这会产生大量小型 HTTP 请求,支持流水线与 HTTP/2 的服务器可显著提升性能。
稀疏认证
Cargo 会在获取任何其他文件之前尝试获取 config.json 文件。若服务器以 HTTP 401 响应,则 Cargo 假定注册表需要认证,并在包含认证 token 的情况下重新尝试请求 config.json。
认证失败(或缺少认证 token)时,服务器可包含带有 Cargo login_url="<URL>" 质询的 www-authenticate 头,以指示用户可前往何处获取 token。
需要认证的注册表必须在 config.json 中设置 auth-required: true。
缓存
Cargo 缓存 crate 元数据文件,并捕获服务器对每个条目的 ETag 或 Last-Modified HTTP 头。刷新 crate 元数据时,Cargo 发送 If-None-Match 或 If-Modified-Since 头,以允许服务器在本地缓存有效时以 HTTP 304「Not Modified」响应,从而节省时间与带宽。若同时存在 ETag 与 Last-Modified 头,Cargo 仅使用 ETag。
缓存失效
若注册表使用某种缓存对索引文件访问的 CDN 或代理,则建议注册表在文件更新时实现某种形式的缓存失效。若这些缓存未更新,用户可能在缓存清除前无法访问新 crate。
不存在的 Crate
对于不存在的 crate,注册表应以 404「Not Found」、410「Gone」或 451「Unavailable For Legal Reasons」代码响应。
稀疏限制
由于注册表的 URL 存储在锁文件中,不建议同时以两种协议提供注册表。关于过渡计划的讨论正在 issue #10964 中进行。crates.io 注册表是例外,因为使用稀疏协议时 Cargo 会在内部替换为等效的 git URL。
若注册表确实同时提供两种协议,目前建议选择一种协议作为规范协议,并对另一种协议使用源替换。