Skip to main content
Version: 1.1.1

版本控制

了解 kmpkg 如何管理版本控制。

最低版本控制

kmpkg 使用最小选择方法进行版本控制,受到 Go 使用的方法的启发(https://research.swtch.com/vgo-mvs),但在某些方面进行了修改:

  • 始终从全新安装开始,无需升级/降级操作。
  • 通过引入基线允许不受约束的依赖关系。

然而,最小选择原则保持不变。给定一组约束,kmpkg 将使用可以满足所有约束的“最旧的”可能版本的包。

使用最小版本方法具有以下优点:

  • 这是可预测且易于理解的。
  • 用户控制何时进行升级,例如,发布新版本时不会自动执行升级。
  • 避免使用 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

由于 kmpkg 必须满足所有约束,因此已安装的软件包集变为:

  • A 1.1,即使存在 A 1.2,也没有高于 1.1 的约束,因此 kmpkg 选择可能的最低版本。
  • “B 1.0”,“A 1.1”传递要求。
  • “C 3.0”,通过“B 1.0”添加的传递约束进行升级,以满足版本约束。

约束解析

给定一个包含一组版本依赖项的清单,kmpkg 将尝试计算满足所有约束的包安装计划。

版本约束有以下几种:

  • 声明的约束:使用 version>= 在顶级清单中显式声明的约束。
  • 基线约束:由“内置基线”隐式添加的约束。
  • 传递约束:由依赖项的依赖项间接添加的约束。
  • 重写约束:使用“overrides”声明在顶级清单中重写的约束。

为了计算安装计划,kmpkg 大致遵循以下步骤:

  • 将所有顶级约束添加到计划中。
  • 递归地向计划添加传递约束。
    • 每次将新包添加到计划中时,也将其基线约束添加到计划中。
    • 每次添加约束时:
    • 如果包存在覆盖
      • 选择覆盖中的版本。
    • 否则:
      • 如果没有选择以前的版本。
        • 选择满足约束的最小版本。
      • 如果选择了以前的版本:
        • 如果新约束的版本控制方案与之前选择的版本不匹配:
          • 添加版本冲突。
        • 如果约束的版本与先前选择的版本不可比较。例如,将“版本字符串:apple”与“版本字符串:orange”进行比较:
          • 添加版本冲突。
        • 如果约束版本高于先前选择的版本:
          • 选择最高版本。
        • 否则:
          • 保留之前的选择。
  • 检查计划:
    • 如果没有冲突的话
      • 安装选定的软件包
    • 否则:
      • 向用户报告冲突

获取端口版本

虽然包版本的概念一直存在于 kmpkg 中,但版本约束的概念却一直没有。

随着版本控制约束的引入,现在软件包可能依赖于与本地可用版本不匹配的端口版本。这会产生一个问题,因为 kmpkg 需要知道如何获取所请求版本的端口文件。

为了解决这个问题,引入了一组新的元数据文件。这些文件位于 kmpkg 存储库根级别的“versions/”目录中。

versions/ 目录将包含注册表中每个可用端口的 JSON 文件。每个文件将列出包的所有可用版本,并包含一个 Git 树状对象,kmpkg 可以检查该对象以获得该版本的端口文件。

例如: 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/{端口名称的首字母}-/{端口名称}.json中。 例如,zlib 的版本文件将位于 versions/z-/zlib.json 中。除了端口版本文件之外,当前基线文件位于versions/baseline.json中。