版本控制概念
最低版本控制
vcpkg 受到 Go 使用的版本控制方法启发,使用最小选择,但在以下一些方面进行了修改:
- 始终以全新安全开始,不需要进行升级/降级操作。
- 通过引入基线来允许不受约束的依赖项。
但是,最小选择原则保持不变。 给定一组约束后,vcpkg 会使用能够满足所有约束的尽可能的“最早”版本的包。
使用最低版本方法具有以下几点优势:
- 可预测并且易于理解。
- 用户可以控制何时进行升级,不会像新版本发布时那样自动执行升级。
- 避免使用 SAT 求解器。
若要提供示例,请考虑以下包关系图:
(A 1.0) -> (B 1.0)
(A 1.1) -> (B 1.0)
-> (C 3.0)
(A 1.2) -> (B 2.0)
-> (C 3.0)
(C 2.0)
以及以下清单:
{
"name": "example",
"version": "1.0.0",
"dependencies": [
{ "name": "A", "version>=": "1.1" },
{ "name": "C", "version>=": "2.0" }
],
"builtin-baseline": "<some git commit with A's baseline at 1.0>"
}
在考虑到转换依赖项之后,即可得到这样一组约束:
- A >= 1.1
- B >= 1.0
- C >= 3.0
- C >= 2.0
由于 vcpkg 必须满足所有约束,安装包集将变为:
A 1.1
,即使当A 1.2
存在时,也没有比1.1
更高的约束,因此 vcpkg 选择可能的最小版本。B 1.0
,A 1.1
转换需要。C 3.0
,由B 1.0
为满足版本约束而添加的转换约束进行升级。
约束解决
给定具有一组版本控制依赖项的清单,vcpkg 将尝试计算满足所有约束的包安装计划。
版本约束具有以下风格:
- 声明的约束:使用
version>=
在顶级清单中明确声明的约束。 - 基线约束:由
builtin-baseline
隐性添加的约束。 - 传递约束:由依赖项的依赖项间接添加的约束。
- 重写约束:使用
overrides
声明在顶级清单中重写的约束。
若要计算安装计划,vcpkg 大致遵循以下步骤:
- 将所有顶级约束添加到计划。
- 以递归方式向计划添加传递约束。
- 每次向计划添加新包时,也会将其基线约束添加到计划。
- 每次添加约束时:
- 如果包存在替代
- 选择替代中的版本。
- 否则:
- 如果没有选择以前的版本。
- 选择满足约束的最低版本。
- 如果选择了以前的版本:
- 如果新约束的版本控制方案与以前选择的版本不匹配:
- 添加版本冲突。
- 如果约束的版本与以前选择的版本不能相比。 例如,将“version-string: apple”与“version-string: orange”进行比较:
- 添加版本冲突。
- 如果约束版本高于以前选择的版本:
- 选择“最高版本”。
- 否则:
- 保留上一个选择。
- 如果新约束的版本控制方案与以前选择的版本不匹配:
- 如果没有选择以前的版本。
- 检查计划:
- 如果没有冲突
- 安装选择的包
- 否则:
- 向用户报告冲突
- 如果没有冲突
获取端口版本
虽然包版本的概念一直存在于 vcpkg 中,但版本约束的概念尚未出现。
随着版本控制约束的引入,包现在可能依赖于与本地可用的端口版本不匹配的端口版本。 由此引发了问题,因为 vcpkg 需要了解如何获取请求的版本的端口文件。
为了解决此问题,引入了一组新的元数据文件。 这些文件位于 vcpkg 存储库根级别的 versions/
目录中。
versions/
目录将包含注册表中可用的每个端口的 JSON 文件。 每个文件都会列出可用于包的所有版本,并包含 vcpkg 可以签出的 Git 树 ish 对象来获取该版本的端口文件。
示例:zlib.json
{
"versions": [
{
"git-tree": "2dfc991c739ab9f2605c2ad91a58a7982eb15687",
"version-string": "1.2.11",
"port-version": 9
},
...
{
"git-tree": "a516e5ee220c8250f21821077d0e3dd517f02631",
"version-string": "1.2.10",
"port-version": 0
},
{
"git-tree": "3309ec82cd96d752ff890c441cb20ef49b52bf94",
"version-string": "1.2.8",
"port-version": 0
}
]
}
每个端口对应的版本文件应位于 versions/{first letter of port name}-/{port name}.json
中。 例如,zlib 的版本文件将位于 versions/z-/zlib.json
中。 除了端口版本文件外,当前基线文件位于 versions/baseline.json
。