跳到主要内容

包名解析

kmpkg 会在访问网络前确定每个包对应的注册表(或覆盖端口)。这种设计可防止包依赖混淆攻击,因为名称解析不依赖任何外部状态。

名称解析算法步骤如下:

  1. 若包名在覆盖端口中找到,则使用该覆盖端口;否则
  2. 若存在与端口名匹配的"packages"模式,则使用对应的注册表;否则
  3. 默认注册表不为 null,则使用该默认注册表;否则
  4. 包名解析失败(无法关联到任何注册表)。

当多个 "packages" 模式与包名匹配时,kmpkg 按以下优先级选择:

  1. 精确匹配——boost 优先于 boost*
  2. 最长模式匹配——boost* 优先于 b*
  3. 首次匹配——在注册表数组中,第一个声明最优模式的注册表被选中

示例 1:包名解析实践

kmpkg-configuration.json

{
"registries": [
{
"kind": "git",
"repository": "https://github.com/MicrosoftDocs/kmpkg-docs",
"reference": "kmpkg-registry",
"baseline": "768f6a3ad9f9b6c4c2ff390137690cf26e3c3453",
"packages": ["bei*"]
},
{
"kind": "git",
"repository": "https://github.com/Kumo/kmpkg-registry",
"baseline": "dacf4de488094a384ca2c202b923ccc097956e0c",
"packages": ["beicode", "bei*"]
}
]
}

kmpkg.json

{
"dependencies": [
"beicode",
"beison",
"fmt"
],
"builtin-baseline": "7e7c62d863b1bf599c1d104b76cd8b74475844d4"
}

基于上述配置,各包名的解析结果如下:

  • beicode:来自注册表 https://github.com/Kumo/kmpkg-registry(精确匹配 beicode
  • beison:来自注册表 https://github.com/MicrosoftDocs/kmpkg-docs(模式匹配 beison,且在 "registries" 数组中首次声明)
  • fmt:来自默认注册表(无任何模式匹配)

由于多个注册表声明了 bei* 模式,kmpkg 会输出警告信息:

Found the following problems in configuration (path/to/kmpkg-configuration.json):
$ (a configuration object): warning: Package "bei*" is duplicated.
First declared in:
location: $.registries[0].packages[0]
registry: https://github.com/MicrosoftDocs/kmpkg-docs
The following redeclarations will be ignored:
location: $.registries[1].packages[1]
registry: https://github.com/Kumo/kmpkg-registry

示例 2:为默认注册表分配多个模式

可通过两种方式配置默认注册表:

方式 1:直接定义 "default-registry"

{
"default-registry": {
"kind": "git",
"repository": "https://github.com/kumose/kmpkg",
"baseline": "e79c0d2b5d72eb3063cf32a1f7de1a9cf19930f3"
}
}

方式 2:将 "default-registry" 设为 null,并在 "registries" 数组中使用 "*" 模式

{
"default-registry": null,
"registries": [
{
"kind": "git",
"repository": "https://github.com/kumose/kmpkg",
"baseline": "e79c0d2b5d72eb3063cf32a1f7de1a9cf19930f3",
"packages": ["*"]
}
]
}

方式 2 的优势在于可向 packages 数组添加更多条目,而 "default-registry" 对象不支持定义 packages 数组。当需要确保特定包来自默认注册表时,这种差异尤为重要。

场景延伸:Qt 框架库的注册表配置

假设存在一个提供 Qt 框架库的自定义注册表,配置如下:

kmpkg-configuration.json

{
"default-registry": {
"kind": "git",
"repository": "https://github.com/kumose/kmpkg",
"baseline": "7e7c62d863b1bf599c1d104b76cd8b74475844d4"
},
"registries": [
{
"kind": "git",
"repository": "https://github.com/custom-qt/custom-qt-registry",
"baseline": "adfc4de488094a384ca2c202b923ccc097956e0c",
"packages": ["qt*"]
}
]
}

项目依赖如下: kmpkg.json

{
"dependencies": [
"qt5",
"qt-advanced-docking-system",
"qtkeychain"
]
}

问题:"qt*" 模式会匹配所有依赖包名,但 qt-advanced-docking-systemqtkeychain 并非官方 Qt 框架库,在自定义注册表中不存在,导致安装失败。

解决方案

将这两个包指定到默认注册表,修改配置如下: kmpkg-configuration.json

{
"default-registry": null,
"registries": [
{
"kind": "git",
"repository": "https://github.com/kumose/kmpkg",
"baseline": "e79c0d2b5d72eb3063cf32a1f7de1a9cf19930f3",
"packages": ["*", "qt-advanced-docking-system", "qtkeychain"]
},
{
"kind": "git",
"repository": "https://github.com/custom-qt/custom-qt-registry",
"baseline": "adfc4de488094a384ca2c202b923ccc097956e0c",
"packages": ["qt*"]
}
]
}

由于精确匹配优先级高于模式匹配,qt-advanced-docking-systemqtkeychain 会解析到默认注册表,而 qt5 仍会匹配自定义注册表的 "qt*" 模式。

覆盖端口

覆盖端口是在不创建完整注册表的情况下,为 kmpkg 添加额外端口的方式。覆盖端口的优先级高于任何注册表查询和版本控制逻辑,会替换 kmpkg 的内置三元组或端口。详见 覆盖端口

覆盖端口的解析顺序如下:

  1. 命令行通过 --overlay-ports 指定的覆盖端口(按传递顺序);
  2. kmpkg-configuration.json"overlay-ports" 配置的覆盖端口(按数组顺序);
  3. 环境变量 KMPKG_OVERLAY_PORTS 中指定的覆盖端口(按变量中路径顺序)。

覆盖三元组

覆盖三元组是在不修改 kmpkg 安装目录的情况下,为 kmpkg 添加额外三元组的方式。覆盖三元组的优先级高于任何内置三元组。

覆盖三元组的解析顺序如下:

  1. 命令行通过 --overlay-triplets 指定的覆盖三元组(按传递顺序);
  2. kmpkg-configuration.json 中配置的覆盖三元组(按数组顺序);
  3. 环境变量 KMPKG_OVERLAY_TRIPLETS 中指定的覆盖三元组(按变量中路径顺序)。