包名解析
kmpkg 会在访问网络前确定每个包对应的注册表(或覆盖端口)。这种设计可防止包依赖混淆攻击,因为名称解析不依赖任何外部状态。
名称解析算法步骤如下:
- 若包名在覆盖端口中找到,则使用该覆盖端口;否则
- 若存在与端口名匹配的
"packages"模式,则使用对应的注册表;否则 - 若默认注册表不为
null,则使用该默认注册表;否则 - 包名解析失败(无法关联到任何注册表)。
当多个 "packages" 模式与包名匹配时,kmpkg 按以下优先级选择:
- 精确匹配——
boost优先于boost* - 最长模式匹配——
boost*优先于b* - 首次匹配——在注册表数组中,第一个声明最优模式的注册表被选中
示例 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-system 和 qtkeychain 并非官方 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-system 和 qtkeychain 会解析到默认注册表,而 qt5 仍会匹配自定义注册表的 "qt*" 模式。
覆盖端口
覆盖端口是在不创建完整注册表的情况下,为 kmpkg 添加额外端口的方式。覆盖端口的优先级高于任何注册表查询和版本控制逻辑,会替换 kmpkg 的内置三元组或端口。详见 覆盖端口。
覆盖端口的解析顺序如下:
- 命令行通过
--overlay-ports指定的覆盖端口(按传递顺序); kmpkg-configuration.json中"overlay-ports"配置的覆盖端口(按数组顺序);- 环境变量
KMPKG_OVERLAY_PORTS中指定的覆盖端口(按变量中路径顺序)。
覆盖三元组
覆盖三元组是在不修改 kmpkg 安装目录的情况下,为 kmpkg 添加额外三元组的方式。覆盖三元组的优先级高于任何内置三元组。
覆盖三元组的解析顺序如下:
- 命令行通过
--overlay-triplets指定的覆盖三元组(按传递顺序); kmpkg-configuration.json中配置的覆盖三元组(按数组顺序);- 环境变量
KMPKG_OVERLAY_TRIPLETS中指定的覆盖三元组(按变量中路径顺序)。