覆盖依赖

多种情境下都可能需要覆盖依赖。不过,大多数情况归根结底都是希望在 crate 发布到 crates.io 之前使用它。例如:

  • 你正在开发的 crate 也被你正在开发的一个更大型应用使用,你希望在这个大型应用中测试该库的错误修复。
  • 你没有参与开发的某个上游 crate,在其 Git 仓库的 master 分支中加入了新功能或错误修复,你想试一试。
  • 你即将发布 crate 的新主版本,但希望对整个包进行集成测试,以确认这个新主版本能够正常工作。
  • 你发现了上游 crate 的一个错误并提交了修复,但希望应用立即依赖修复后的版本,避免等待修复合并而受阻。

这些情境都可以通过清单中的 [patch] 节解决。

本章介绍几个不同的用例,并详细说明覆盖依赖的不同方式。

  • 用例
  • 参考
    • [patch] 节
    • [replace] 节
    • paths 覆盖

注意:另请参阅“为依赖指定多个位置”,它可以用来覆盖本地包中单个依赖声明的来源。

测试错误修复

假设你正在使用 uuid crate,并在使用时发现一个错误。你很有行动力,决定尝试修复它!原来的清单如下:

[package]
name = "my-library"
version = "0.1.0"

[dependencies]
uuid = "1.0"

首先,通过以下命令将 uuid 仓库克隆到本地:

$ git clone https://github.com/uuid-rs/uuid.git

接下来,编辑 my-library 的清单,加入:

[patch.crates-io]
uuid = { path = "../path/to/uuid" }

这里声明用一个新依赖修补 crates-io 来源。这实际上会为本地包把本地检出的 uuid 版本添加到 crates.io 注册表中。

接下来需要确保锁文件已经更新并使用这个新的 uuid 版本,让包使用本地检出的副本,而不是来自 crates.io 的副本。[patch] 的工作方式是加载 ../path/to/uuid 中的依赖;此后每当查询 crates.io 上的 uuid 版本时,也会返回这个本地版本。

这意味着本地检出副本的版本号非常重要,会影响补丁是否生效。清单声明了 uuid = “1.0”,因此只会解析到 >= 1.0.0, < 2.0.0 的版本;Cargo 的贪心解析算法还意味着会选择这个范围内的最高版本。通常这不成问题,因为 Git 仓库版本通常已经高于或等于 crates.io 上发布的最高版本,但仍须记住这一点!

无论如何,现在通常只需要执行:

$ cargo build
   Compiling uuid v1.0.0 (.../uuid)
   Compiling my-library v0.1.0 (.../my-library)
    Finished dev [unoptimized + debuginfo] target(s) in 0.32 secs

这样就完成了!现在构建使用的是本地 uuid 版本,注意构建输出括号中的路径。如果没有看到本地路径版本被构建,可能需要运行 cargo update uuid –precise $version,其中 $version 是本地检出的 uuid 副本的版本号。

修复最初发现的错误后,你很可能会将修复作为拉取请求提交给 uuid crate。完成这一步后,也可以更新 [patch] 节。[patch] 中的条目与 [dependencies] 节一样,因此在拉取请求合并后,可以将路径依赖改为:

[patch.crates-io]
uuid = { git = 'https://github.com/uuid-rs/uuid.git' }

使用尚未发布的次版本

现在从修复错误转向添加功能。开发 my-library 时,你发现 uuid crate 需要一个全新功能。你已经实现了它,按上文使用 [patch] 在本地测试,并提交了拉取请求。下面看看在它正式发布前如何继续使用和测试。

再假设 crates.io 上 uuid 的当前版本是 1.0.0,但此后 Git 仓库的 master 分支已更新到 1.0.1。这个分支包含你之前提交的新功能。要使用这个仓库,将 Cargo.toml 编辑为:

[package]
name = "my-library"
version = "0.1.0"

[dependencies]
uuid = "1.0.1"

[patch.crates-io]
uuid = { git = 'https://github.com/uuid-rs/uuid.git' }

注意,本地对 uuid 的依赖已更新为 1.0.1,因为 crate 发布后实际需要的就是这个版本。不过 crates.io 上尚不存在这个版本,因此通过清单的 [patch] 节提供它。

现在构建库时,会从 Git 仓库获取 uuid,并解析到仓库中的 1.0.1,而不是尝试从 crates.io 下载版本。1.0.1 在 crates.io 发布后,就可以删除 [patch] 节。

还要注意,[patch] 会传递性地生效。假设你在一个更大的包中使用 my-library,例如:

[package]
name = "my-binary"
version = "0.1.0"

[dependencies]
my-library = { git = 'https://example.com/git/my-library' }
uuid = "1.0"

[patch.crates-io]
uuid = { git = 'https://github.com/uuid-rs/uuid.git' }

记住,[patch] 具有传递性,但只能在顶层定义,因此 my-library 的使用者在必要时必须重复声明 [patch] 节。在这里,新的 uuid crate 同时应用于我们对 uuid 的依赖和 my-library -> uuid 依赖。整个 crate 依赖图中的 uuid 会解析为同一个版本 1.0.1,并从 Git 仓库获取。

覆盖仓库 URL

如果希望覆盖的依赖不是从 crates.io 加载的,就需要稍微调整 [patch] 的用法。例如,如果依赖是 Git 依赖,可以用以下方式将其覆盖为本地路径:

[patch."https://github.com/your/repository"]
my-library = { path = "../my-library/path" }

这样就完成了!

预先使用含有破坏性变更的版本

下面看看如何使用 crate 的新主版本,它通常伴随破坏性变更。继续使用前面的 crate,这意味着要创建 uuid crate 的 2.0.0 版本。将所有变更提交到上游后,可以把 my-library 的清单更新为:

[dependencies]
uuid = "2.0"

[patch.crates-io]
uuid = { git = "https://github.com/uuid-rs/uuid.git", branch = "2.0.0" }

这样就完成了!和前面的例子一样,2.0.0 实际上还不存在于 crates.io,但仍能借助 [patch] 节,通过 Git 依赖引入它。作为思考练习,再看看上文 my-binary 的清单:

[package]
name = "my-binary"
version = "0.1.0"

[dependencies]
my-library = { git = 'https://example.com/git/my-library' }
uuid = "1.0"

[patch.crates-io]
uuid = { git = 'https://github.com/uuid-rs/uuid.git', branch = '2.0.0' }

注意,这实际上会解析到 uuid crate 的两个版本。my-binary crate 继续使用 uuid 的 1.x.y 系列,而 my-library crate 使用 uuid 2.0.0。这样就能沿依赖图逐步推广 crate 的破坏性变更,不必一次性更新所有内容。

对多个版本使用 [patch]

可以利用用于重命名依赖的 package 键,修补同一个 crate 的多个版本。例如,假设希望使用 serde crate 的 1.* 系列中的一个错误修复,同时还希望试用 Git 仓库中 serde 2.0.0 的原型。配置如下:

[patch.crates-io]
serde = { git = 'https://github.com/serde-rs/serde.git' }
serde2 = { git = 'https://github.com/example/serde.git', package = 'serde', branch = 'v2' }

第一条 serde = … 指令表示 serde 1.* 应从 Git 仓库使用,取得所需的错误修复;第二条 serde2 = … 指令表示 serde 包也应从 https://github.com/example/serde 的 v2 分支获取。这里假设该分支的 Cargo.toml 声明了版本 2.0.0。

注意,使用 package 键时,这里的 serde2 标识符实际上会被忽略。我们只需要一个不与其他被修补 crate 冲突的唯一名称。

[patch] 节

Cargo.toml 的 [patch] 节可以用其他副本覆盖依赖,语法类似于 [dependencies] 节:

[patch.crates-io]
foo = { git = 'https://github.com/example/foo.git' }
bar = { path = 'my/local/bar' }

[dependencies.baz]
git = 'https://github.com/example/baz.git'

[patch.'https://github.com/example/baz']
baz = { git = 'https://github.com/example/patched-baz.git', branch = 'my-branch' }

注意:[patch] 表也可以作为配置选项指定,例如放在 .cargo/config.toml 文件中,或使用 –config ‘patch.crates-io.rand.path=”rand”‘ 这样的命令行选项。这适用于不希望提交的仅限本地的变更,或临时测试补丁。

[patch] 表由类似依赖声明的子表组成。[patch] 后的每个键都是被修补来源的 URL,或者注册表名称。crates-io 这个名称可以用来覆盖默认注册表 crates.io。上例的第一个 [patch] 演示覆盖 crates.io,第二个 [patch] 演示覆盖 Git 来源。

这些表中的每个条目都是普通的依赖规范,与清单 [dependencies] 节中的规范相同。[patch] 节列出的依赖会被解析,并用来修补指定 URL 的来源。上面的清单片段用 foo 和 bar crate 修补 crates-io 来源,即 crates.io 本身;还用来自其他位置的 my-branch 修补 https://github.com/example/baz 来源。

可以用来源中尚不存在的 crate 版本进行修补,也可以用来源中已经存在的版本。如果用来源中已有的 crate 版本修补该来源,那么该来源的原始 crate 就会被替换。

Cargo 只查看工作区根目录 Cargo.toml 清单中的 patch 设置。依赖中定义的 patch 设置会被忽略。

[replace] 节

注意:[replace] 已弃用,应改用 [patch] 表。

Cargo.toml 的这一节可以用其他副本覆盖依赖,语法类似于 [dependencies] 节:

[replace]
"foo:0.1.0" = { git = 'https://github.com/example/foo.git' }
"bar:1.0.2" = { path = 'my/local/bar' }

[replace] 表中的每个键都是包 ID 规范,可以任意选择依赖图中的一个节点进行覆盖,必须提供三段式版本号。每个键的值与 [dependencies] 中指定依赖的语法相同,但不能指定 features。注意,覆盖 crate 时,用于覆盖的副本必须具有相同的名称和版本,但可以来自其他来源,例如 Git 或本地路径。

Cargo 只查看工作区根目录 Cargo.toml 清单中的 replace 设置。依赖中定义的 replace 设置会被忽略。

paths 覆盖

有时你只是暂时修改一个 crate,不想像上文 [patch] 的做法那样修改 Cargo.toml。针对这种情况,Cargo 提供了一种限制更多的覆盖方式,称为路径覆盖。

路径覆盖通过 .cargo/config.toml 指定,而不是 Cargo.toml。在 .cargo/config.toml 中指定名为 paths 的键:

paths = ["/path/to/uuid"]

这个数组应填写包含 Cargo.toml 的目录。在此例中只添加 uuid,因此只有它会被覆盖。路径既可以是绝对路径,也可以相对于包含 .cargo 文件夹的目录。

不过,路径覆盖比 [patch] 节限制更多,因为它不能改变依赖图的结构。使用路径替换时,原来的依赖集合必须与新 Cargo.toml 中的规范完全一致。例如,不能用路径覆盖来测试为 crate 添加依赖;这种情况下必须使用 [patch]。因此,路径覆盖通常只用于快速修复错误,而不是较大的变更。

注意:使用本地配置覆盖路径,只适用于已经发布到 crates.io 的 crate。不能用这个功能告诉 Cargo 如何找到本地尚未发布的 crate。

来源与许可

原文:Overriding Dependencies。作者及权利人:Rust / Cargo 项目贡献者。中文翻译基于用户提供的完整原文缓存,代码和示例输出保留原文;本文未实际执行示例。

许可依据:Apache License 2.0。

原文引用链接

许可文本

Apache License
Version 2.0, January 2004
https://www.apache.org/licenses/LICENSE-2.0

TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

1. Definitions.

“License” shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.

“Licensor” shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.

“Legal Entity” shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
“control” means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.

“You” (or “Your”) shall mean an individual or Legal Entity
exercising permissions granted by this License.

“Source” form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.

“Object” form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.

“Work” shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).

“Derivative Works” shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.

“Contribution” shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, “submitted”
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as “Not a Contribution.”

“Contributor” shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.

2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.

3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.

4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:

(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and

(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and

(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and

(d) If the Work includes a “NOTICE” text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.

You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.

5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.

6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.

7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an “AS IS” BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.

8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.

9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.

END OF TERMS AND CONDITIONS

APPENDIX: How to apply the Apache License to your work.

To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets “[]”
replaced with your own identifying information. (Don’t include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same “printed page” as the copyright notice for easier
identification within third-party archives.

Copyright [yyyy] [name of copyright owner]

Licensed under the Apache License, Version 2.0 (the “License”);
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an “AS IS” BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容