这是本节的多页打印视图。 .
命令
- 1: sow create
- 2: sow init
- 3: sow config
- 4: sow repo
- 5: sow dist
- 6: sow add
- 7: sow rm
- 8: sow ls
- 9: sow show
- 10: sow where
- 11: sow status
- 12: sow build
- 13: sow check
- 14: sow changes
- 15: sow publish
- 16: sow retain
- 17: sow gc
- 18: sow export
- 19: sow log
本节列出命令语法、选择规则、输出与示例。使用 sow help COMMAND 或 sow help COMMAND SUBCOMMAND 查看已安装版本的选项。
本文用 Desired 表示期望状态,用 Built 表示已构建状态。构建快照(Generation)是一次已完成构建的结果。
命令索引
sow create 直接在目录中构建平面仓库。需要通过工作区管理软件包时,先运行 sow init。其他 Managed 命令使用已有工作区。help 与 version 可以在任意目录运行。
| 命令 | 模式 | 用途 |
|---|---|---|
sow create [DIR] |
Plain | 就地生成平面 RPM/DEB 仓库 |
sow init [DIR] |
Managed | 初始化工作区并创建已声明的仓库/Dist |
sow config check|show |
Managed | 校验配置或打印有效配置 |
sow repo ls|new|show|migrate|rm |
Managed | 创建、查看、升级或删除仓库 |
sow dist ls|new|show|rm |
Managed | 管理 Dist |
sow add PATH... |
Managed | 添加软件包并重建索引 |
sow rm PACKAGE... |
Managed | 移除软件包并重建索引 |
sow ls |
Managed | 列出期望成员及其已构建位置 |
sow show PACKAGE |
Managed | 查看一个软件包 |
sow where PACKAGE |
Managed | 在工作区中查找软件包 |
sow status |
Managed | 快速读取仓库状态 |
sow build |
Managed | 按期望状态生成构建快照 |
sow check |
Managed | 在交付前校验仓库 |
sow changes [BASE_GENERATION] |
Managed | 比较两个构建快照的文件差异 |
sow publish TARGET |
Managed | 将构建快照发布到配置目标 |
sow retain add|ls|rm |
Managed | 保留旧构建快照所需的包文件 |
sow gc [TARGET] |
Managed | 回收不再需要的本地包,或维护发布目标 |
sow export rpm-leaf |
Managed | 导出独立 RPM 仓库 |
sow log [OPERATION] |
Managed | 查询、导出和裁剪操作记录 |
全局语法
不带参数运行 sow 会打印命令列表并退出 0。用 sow help COMMAND 或
sow help COMMAND SUBCOMMAND 查看内置帮助。sow version 与 sow --version 打印版本与构建信息。
选项只适用于列出该选项的命令。位置参数以 - 开头时,在它前面加 --。未知选项或重复的单值选项返回退出码 2。
工作区发现
Managed 命令按以下规则寻找最近的 sow.yml:
- 有
-C/--workdir DIR时从DIR开始,否则从当前目录开始。 - 逐级向上查找,在第一个
sow.yml停止。 - 首次查找失败且设置了
SOW_DIR时,再从该目录查找。显式-C会取代当前目录候选, 但不会禁用SOW_DIR回退。 - 仍未发现工作区则退出
2。
--workdir 只改变发现起点,不会切换进程工作目录;相对位置参数仍相对于真实当前目录解析。
sow create 完全不参与工作区发现。
Repository 选择
需要唯一仓库的命令按以下顺序选择:
- 显式
-r/--repo NAME; - 发现起点所在的仓库;
- 工作区中唯一的仓库;
- 否则退出
2并列出候选项。
repo new 与 repo rm 用位置参数接收 NAME,不接受 -r。sow where 默认搜索所有
仓库,-r 只用于收窄范围。发布目标自身绑定仓库,因此 publish TARGET 与
gc TARGET 不再接受额外的仓库选择。
Dist 选择
add、rm、ls 要求明确的 Dist 集合,并按以下顺序选择:
- 一个或多个
-d/--dist NAME; - 发现起点所在的 Dist;
- 所选仓库中唯一的 Dist;
- 否则退出
2并列出候选项。
其他命令采用以下默认范围:
- 未指定
-d时,build、check、status默认作用于全部 Dist; show默认搜索所选仓库,-d只用于收窄;where默认跨工作区搜索全部匹配 Dist,-r/-d用于收窄;changes作用于整个仓库,不接受-d。
锁
create 锁定目标目录。Managed 写操作通过工作区锁和仓库锁协调。init 会等待锁,不提供命令行超时选项。
其他写命令接受 -T/--timeout DUR 与 -N/--no-wait。默认 --timeout 0 表示无限等待。正数时长使用 ms、s、m 或 h,例如 500ms、30s、5m。--no-wait 在锁被占用时立即失败,不能与正数超时同时使用。无法获取锁时返回 4。
大多数 Managed 只读命令使用共享锁,会等待冲突的写操作完成;这些命令不接受等锁选项。status 通常只探测仓库锁,因此可以查看正在运行的写操作。按 Ctrl-C 可以取消等待。
并发
只有需要解析软件包、哈希包体、渲染索引或执行校验的命令才接受 -j/--jobs N:create、
add、rm、build、check 与 repo migrate。默认值是逻辑 CPU 数,且不得小于 1。
JSON 输出
支持 --json 的命令在 stdout 输出一个带版本的封装,诊断信息仍写入 stderr:
任何非零退出都会令 ok 为 false;部分成功的批处理仍会返回已提交项与失败项。完整结果结构见
JSON 输出。
交互操作使用文本输出,脚本使用 --json。config show 默认输出 YAML。log export 是例外:它直接输出 JSONL,不接受 --json。
退出码
| 代码 | 含义 |
|---|---|
0 |
成功或幂等空操作 |
1 |
运行时 I/O、解析、渲染、签名或传输错误 |
2 |
用法、工作区发现或配置错误 |
3 |
批处理部分成功 |
4 |
写锁不可用 |
5 |
完整性/恢复失败,或 check 判定目录不可交付 |
6 |
操作被拒绝:冲突、受保护对象、无匹配或架构不兼容 |
130 |
命令被 SIGINT 或 SIGTERM 中断 |
各命令的精确触发条件见退出码。
1 - sow create
sow create 在软件包所在目录生成 RPM 与 DEB 索引。需要平面仓库时使用此命令,无需创建 Managed 工作区。DIR 默认为当前目录。
语法
说明
create 读取 DIR 顶层的普通文件,按发现的内容渲染对应索引:有 RPM 就生成 repodata/,有 DEB 就
生成 Packages 与 Packages.gz,混合目录两套一起生成。架构全部来自包头——Plain 模式没有架构参数,
也没有架构许可表。
索引使用相对包路径:RPM 使用文件名,DEB 使用 ./<文件名>。可以通过 HTTP 提供整个包目录,也可以将它作为本地 file:// 软件源。
默认情况下,create 只更新索引并保留包文件。--pigsty 会删除符合规则的包,--sign-with 会用签名副本替换 RPM。
参数
| 参数 | 说明 | 默认 |
|---|---|---|
-j, --jobs N |
处理软件包的并发工作线程数 | 逻辑 CPU 数 |
--metadata-timestamp SECONDS |
RPM repomd 的 data 时间戳,取值 0 至 253402300799 的 Unix 秒;不影响 DEB、包时间或 gzip 头 |
0 |
--pigsty |
启用 Pigsty 兼容清理与完成标记 | 关闭 |
-S, --sign-with KEY |
用 GPG 密钥 ID 或指纹为未签名 RPM 补签 | 关闭 |
--overwrite |
重签全部 RPM;必须与 --sign-with 同用 |
关闭 |
-T, --timeout DUR |
等待锁的最长时间;0 表示无限等待 |
0 |
-N, --no-wait |
锁被占用时立即失败 | false |
--json |
输出 JSON | false |
-h, --help |
显示帮助 | — |
扫描规则
- 只考虑顶层、以
.rpm或.deb结尾的普通文件。 - 不递归、不跟随符号链接、不读工作区配置。
- 所有有效版本都进入索引。两个文件对应同一逻辑坐标但内容不同时,命令报错。
- 默认模式要求至少有一个支持的包。
--pigsty允许清理后没有包,并为该空目录写入完成标记。
包 I/O 与最终校验
create 运行期间,保持输入目录不变。SOW 扫描软件包后,会在替换索引前检查文件是否变化。检测到变化时返回退出码 5。使用 --jobs 设置处理软件包的并发数。
确定性输出与幂等
不强制重签软件包时,相同的软件包与时间参数生成相同的元数据。repomd.xml 的 <revision> 和 data 时间戳默认为 0;--metadata-timestamp 只修改 data 时间戳。对未变化的目录使用相同选项重跑时,SOW 不改写文件,并报告 noop=true:
已有 YUM 仓库的发布时间
--metadata-timestamp 设置 RPM repomd 的 data 时间戳,不改变软件包、压缩 XML 文件或 DEB 索引。默认值为 0,范围为 0..253402300799 Unix 秒。此选项从 SOW 0.5.0 开始提供。
EL7 YUM 会拒收最大 data 时间戳早于本地缓存的元数据。替换已有元数据生成器时,选择不低于历史已发布最大值的时间。内容变化时,至少增加一秒,以区分各次更新。
记录发布时间,并在每次更新时传入。省略此选项会重新使用 0。恢复旧包集合也属于新发布,因此仍需递增时间戳。使用秒值,不要传毫秒值或未来日期。
如果客户端验证 repomd.xml.asc,repomd 变化后需要重新生成该签名。create 不签署 repomd,也不更新或删除旧的分离签名。
完整流程见迁移现有 YUM 仓库。
repo_complete 标记
如果目录中有 repo_complete,使用 --pigsty 将它与索引一起更新。不带 --pigsty 运行会返回错误:
需要保留完成标记时,添加 --pigsty 后重跑;不再使用此标记时,先将它移走。
–pigsty
--pigsty 按以下规则清理包文件,并写入完成标记:
- 删除解析架构为
i386的 DEB;RPM 不会仅因为架构是i386/i486/i586/i686而被删除。 - 删除二进制包名恰为
patroni且上游版本恰为3.0.4的 RPM/DEB。RPM 比较VERSION,忽略 epoch 与 release;DEB 先剥掉 epoch 与 Debian revision 再比。3.0.4+foo不算命中。 - 全部索引渲染成功后写出
repo_complete:剩余顶层 RPM/DEB 的 SHA-256,按文件名字节序排序, 格式为<sha256><两个空格><basename>。
清理仅处理解析成功且命中规则的顶层普通包文件。
SOW 先撤下已有的 repo_complete,再替换索引;新元数据安装后删除命中规则的包,
最后写入新的完成标记。调用方看到标记缺失时,应等待构建完成。
RPM 包签名
-S/--sign-with KEY 通过本地 RPM/GPG 环境为 RPM 包签名。使用 16 位十六进制密钥 ID,或 40/64 位指纹;可以带 0x 或 0X 前缀。运行前,在该环境中配置私钥与口令。
- 默认只给没有可解析嵌入 OpenPGP 签名的 RPM 补签;已有签名的包保持原字节。
--overwrite必须与--sign-with同用,改为对全部保留 RPM 执行rpm --resign。- SOW 对临时副本签名,确认包身份与内容未变后替换原 RPM。索引描述最终签名后的文件。
--pigsty清理后至少要保留一个顶层 RPM,且PATH中要有rpm。
锁与中断恢复
create 在更新索引期间锁定目标目录。使用 --timeout 或 --no-wait 控制等待锁的时间。
中断可能使部分索引已更新、部分仍未更新。使用原定选项重新运行 sow create,按当前软件包重新生成全部索引。Plain 模式从头重建,因此结果字段 recovered 始终为 false。
使用 --pigsty 时,在 repo_complete 出现后再对外提供仓库。需要操作日志恢复时,使用 Managed 模式。
示例
给混合目录建索引:
机器可读结果:
用八个工作线程构建 Pigsty 平面仓库,并使用根据发布历史选定的时间:
调用者负责记录该时间,并在客户端要求时为生成的 repomd.xml 签名。
失败时的 JSON 结果:
退出码
| 码 | 触发条件 |
|---|---|
0 |
索引写出成功,或输入未变化产生 no-op |
1 |
目录不可读或不存在、包解析失败、渲染失败、签名工具失败 |
2 |
用法错误——时间戳非法或重复指定、--overwrite 未配 --sign-with、密钥格式非法、--no-wait 与非零 --timeout 同用 |
4 |
目录写锁被占用,且给了 --no-wait 或 --timeout 到期 |
5 |
发布前输入文件发生变化,或受控输出路径未通过完整性检查 |
6 |
未找到受支持的包、已有 repo_complete 但未使用 --pigsty、对 DEB-only 目录用 --sign-with、坐标冲突 |
参见
- Plain 平面仓库 ——
create背后的设计 - 快速上手 —— 五分钟平面仓库演练
- 仓库布局 —— 平面目录树长什么样
- 仓库签名 —— 生成与使用签名密钥
- 迁移现有 YUM 仓库 —— 替换已有的元数据生成流程
2 - sow init
sow init 创建工作区的 sow.yml 与私有状态目录 .sow/。如果配置中已声明仓库和 Dist,它会创建尚未初始化的对象。添加声明后,可再次运行此命令完成初始化。
语法
DIR 默认为当前目录。需要初始化其他目录时,将它的路径作为 DIR 传入。
说明
首次 init 写出最小配置与私有状态目录:
.sow/ 保存私有状态、锁和恢复记录,目录权限为 0700。通过 HTTP 提供仓库目录时,保留 .sow/ 为私有目录。
参数
| 参数 | 说明 | 默认 |
|---|---|---|
--json |
输出 JSON | false |
-h, --help |
显示帮助 | — |
幂等规则
新配置使用 schema: sow/v3,默认架构为 x86_64 与 aarch64,不声明任何仓库。使用 sow repo new 创建仓库,或先编辑 sow.yml 声明仓库。
init 保留已有配置,初始化尚缺的声明对象。非空目录也可以使用,但其中的文件不能与 SOW 保留路径冲突。全部声明对象都已初始化时,本次初始化计数为零。
应用已声明的配置
如果 sow.yml 里已经描述了仓库与 Dist,init 会为它们补齐缺失的目录树、SQLite 数据库与
空索引。已初始化的对象直接跳过,因此计数器准确反映本次运行做了什么。
新 Dist 具有有效的空索引:RPM Dist 的每个架构视图有一份空
repodata/,DEB Dist 有空的 Packages/Packages.gz、by-hash 与 Release。
再次运行时,已有对象保持不变:
锁与恢复
初始化中断后,对同一目录重新运行 sow init。SOW 先完成或回滚被中断的操作,再初始化其余声明对象。有其他工作区写操作时,它会等待该操作结束。
示例
建好工作区后手工添加仓库:
初始化当前目录之外的目录:
使用版本控制中的配置文件初始化:
退出码
| 码 | 触发条件 |
|---|---|
0 |
工作区初始化成功,或已经初始化(no-op) |
1 |
写配置或状态目录时的运行时 I/O 错误 |
2 |
用法错误,或已存在的 sow.yml 解析/校验不通过 |
3 |
部分成功——部分声明的仓库/Dist 已提交,至少一个失败 |
5 |
工作区日志无法恢复到终态 |
6 |
已有文件与 SOW 保留路径冲突 |
参见
- 第一个工作区 —— 逐步操作示例
- Managed 工作区 —— 三层模型
- sow.yml 配置参考 —— 全部配置键
- sow repo 与 sow dist
- 仓库布局 ——
.sow/里有什么
3 - sow config
修改 sow.yml 后,运行 sow config check。它检查配置、签名引用及配置与既有仓库状态是否兼容。使用 sow config show 查看默认值与继承设置展开后的配置。两个命令都只读。
语法
sow config check
解析并校验完整的 sow.yml:schema 版本、名称、路径冲突、架构许可表、Dist 格式、成员策略与签名密钥
引用。它会回报解析到的工作区以及校验了多少对象。
参数
| 参数 | 说明 | 默认 |
|---|---|---|
-C, --workdir DIR |
工作区发现的起始目录 | 当前目录 |
--json |
输出 JSON | false |
-h, --help |
显示帮助 | — |
严格拒绝未知字段
未知配置键会产生配置错误:
使用 schema: sow/v3:
config check 还会验证签名密钥是否可用且适用于签名。从工作区架构列表移除某个架构前,先移除 Dist 配置、成员和已构建状态对该架构的使用。
sow config show
以 YAML 输出所选范围内的生效配置。
对比原始配置文件:
show 补上了 protected: false、每个 Dist 继承来的 architectures、limit: 0 与空的 exclude
列表。架构以 x86_64 和 aarch64 表示;它们在 DEB 中分别写作 amd64 和 arm64。
参数
| 参数 | 说明 | 默认 |
|---|---|---|
--all |
展开整个工作区的默认值与规范化架构 | 关闭 |
-C, --workdir DIR |
工作区发现的起始目录 | 当前目录 |
-r, --repo NAME |
选择一个仓库 | 按选择规则 |
-d, --dist NAME |
选择一个 Dist;可重复 | 按选择规则 |
--json |
输出 JSON | false |
-h, --help |
显示帮助 | — |
用 -r/-d 选择配置范围
使用 -r 与 -d 查看指定 Dist 的实际配置:
不带 --all 时,按一般规则选择仓库。如果发现起点位于某个 Dist 内,默认只显示该 Dist,除非显式传入 -d;否则显示所选仓库的全部 Dist。--all 显示整个工作区,并忽略 -r 与 -d。
签名引用
输出包含密钥引用和解析后的指纹,不包含私钥内容或口令。
示例
在 CI 里先校验再构建:
比较两个 Dist 的有效策略:
退出码
| 码 | 触发条件 |
|---|---|
0 |
配置合法,或输出成功打印 |
1 |
运行时错误或密钥解析失败 |
2 |
用法或发现错误、YAML 无效、未知字段或不支持的 schema |
5 |
既有状态、受控路径或恢复记录不一致 |
6 |
所选对象不存在、签名配置不可用,或配置与既有状态不兼容 |
config check 同时检查 YAML 文件及其与已有仓库状态的兼容性。
参见
- sow.yml 配置参考 —— 全部配置键与完整示例文件
- 成员策略 ——
exclude与limit如何求值 - 签名模型 —— 密钥引用文法与两条信任链
- sow init —— 创建手写配置中声明的对象
- sow check —— 检查包文件、索引与私有状态
4 - sow repo
sow repo 用于创建、列出、查看、升级和删除仓库。每个仓库在 pool/ 中保存包文件,在 dists/ 中保存索引。同一仓库的 Dist 共用包文件。
语法
命名
仓库名必须匹配 [a-z0-9][a-z0-9._-]*,且不能是 .、..、.sow、pool、dists,也不能与工作区
保留文件冲突。
SOW 在 <workspace>/<NAME>/ 创建仓库。
sow repo ls
只读列出工作区里的全部仓库。
| 参数 | 说明 | 默认 |
|---|---|---|
-C, --workdir DIR |
工作区发现的起始目录 | 当前目录 |
--json |
输出 JSON | false |
STATUS 取值为 clean、dirty、recovering 或 error。各状态对客户端意味着什么,见
事务与恢复。
sow repo new
更新 sow.yml,然后创建 <workspace>/<NAME>/{pool,dists}、SQLite 数据库与私有状态目录。新仓库
尚未构建,构建快照编号为 0,状态为 clean。
| 参数 | 说明 | 默认 |
|---|---|---|
-C, --workdir DIR |
工作区发现的起始目录 | 当前目录 |
-T, --timeout DUR |
等待锁的最长时间;0 无限等待 |
0 |
-N, --no-wait |
锁被占用时立即失败 | false |
--json |
输出 JSON | false |
用 NAME 指定新仓库的名称。
对已存在的仓库再次运行时,命令报告当前状态,不会创建第二个仓库。
sow repo show
只读显示一个仓库的细节。省略 NAME 时按 CLI 全局约定 中的仓库选择规则
解析。
| 参数 | 说明 | 默认 |
|---|---|---|
-C, --workdir DIR |
工作区发现的起始目录 | 当前目录 |
-r, --repo NAME |
省略 NAME 时用它选择仓库 |
按选择规则 |
--json |
输出 JSON | false |
同时给出 NAME 与 -r 时,使用相同名称:
sow repo migrate
将既有 v0.3 或 v0.4 工作区升级到 SOW 0.5 时,使用 repo migrate。新建的 0.5 仓库已使用 schema v13,无需迁移。
- 停止工作区写操作。
- 备份整个工作区,并保留硬链接。
- 逐个迁移已配置的仓库。
- 对每个仓库运行
build与check。
对其他仓库重复后三条命令。迁移结果包含 schema_from 与 schema_to;重复迁移报告 13 -> 13。Schema v13 增加包池路径查询索引。从 v0.3 迁移时,还会应用中间版本的状态与发布记录修复。
写操作要求当前 schema。兼容的只读命令可以查看旧状态,但不会升级数据库。迁移后使用 SOW 0.5 或更新版本;需要返回旧 schema 时,恢复备份。
--abort 只能在提交决策前放弃未完成的布局迁移,不能撤销已完成的 schema 升级。开发期 C2 布局需要从原始软件包重新建仓。
| 参数 | 含义 | 默认值 |
|---|---|---|
-j, --jobs N |
并行校验/渲染工作线程 | 逻辑 CPU 数 |
--abort |
在提交决策前放弃维护尝试 | false |
-C, --workdir DIR |
工作区发现起点 | 当前目录 |
-r, --repo NAME |
省略 NAME 时选择仓库 |
选择规则 |
-T, --timeout DUR |
最长锁等待;0 无限等待 |
0 |
-N, --no-wait |
锁被占用时立即失败 | false |
--json |
输出 JSON | false |
sow repo rm
删除整个仓库,包括 sow.yml 条目、数据库、pool/ 中的包文件、dists/ 中的索引与私有状态。
不加 -f 时,只能删除空仓库——没有 Dist、没有成员关系、没有软件包对象:
| 参数 | 说明 | 默认 |
|---|---|---|
-f, --force |
删除非空的、未受保护的仓库 | false |
-C, --workdir DIR |
工作区发现的起始目录 | 当前目录 |
-T, --timeout DUR |
等待锁的最长时间;0 无限等待 |
0 |
-N, --no-wait |
锁被占用时立即失败 | false |
--json |
输出 JSON | false |
强制删除
使用 -f 删除非空仓库。设置了 protected: true 的仓库仍然受到保护。
protected
sow.yml 中的 protected: true 阻止删除仓库,包括使用 -f 的情况:
需要删除受保护仓库时,在 sow.yml 中将它的 protected 设为 false。运行 sow config check,再重试删除。
protected 只作用于仓库删除。add、rm、build 与 dist rm 照常工作:
示例
为两层结构创建仓库:
创建仓库时不等待已被占用的锁:
逐行显示仓库名称、状态与构建快照编号:
退出码
| 码 | 触发条件 |
|---|---|
0 |
列出、创建、显示、迁移、放弃提交前的布局转换或删除成功;或 repo new 报告已存在的仓库 |
1 |
创建或删除目录树时的运行时 I/O 错误 |
2 |
用法错误、工作区未找到,或仓库选择有歧义 |
4 |
工作区锁被占用,且给了 --no-wait 或 --timeout 到期 |
5 |
工作区日志的完整性或恢复错误 |
6 |
名称非法、仓库不存在、非空但未给 -f、protected,或 NAME 与 -r 冲突 |
参见
- sow dist —— 下一层
- Managed 工作区 —— 三层模型与发现规则
- 事务与恢复 —— 锁作用域与
recovering状态 - sow.yml 配置参考 ——
protected与仓库级签名配置 - 仓库布局 —— 固定目录结构
5 - sow dist
sow dist 管理客户端使用的发行版集合。每个 Dist 只包含 RPM 或 DEB 中的一种格式。同一仓库内的 Dist 共用 pool/,在 dists/ 下各有独立索引。
语法
命名
Dist 名与仓库名规则相同:[a-z0-9][a-z0-9._-]*,排除 .、..、.sow、pool、dists。
选择能说明发行版或渠道的名称,例如 el9、trixie 或 el9-beta。SOW 不根据名称推断包格式或策略。
sow dist ls
列出所选仓库的全部 Dist。
DESIRED 与 BUILT 是成员计数。两者不一致时,DIRTY_REASONS 会说明原因:
| 参数 | 说明 | 默认 |
|---|---|---|
-C, --workdir DIR |
工作区发现的起始目录 | 当前目录 |
-r, --repo NAME |
选择一个仓库 | 按选择规则 |
--json |
输出 JSON | false |
表格显示架构族,JSON 还给出包生态使用的架构名。以下摘录展示 result.dists 中一个条目的
architectures 字段,对应的 DEB 视图目录为 binary-amd64 与 binary-arm64:
sow dist new
使用 --format rpm 或 --format deb 创建 Dist。
| 参数 | 说明 | 默认 |
|---|---|---|
--format FORMAT |
必填;rpm 或 deb |
— |
-C, --workdir DIR |
工作区发现的起始目录 | 当前目录 |
-r, --repo NAME |
选择一个仓库 | 按选择规则 |
-T, --timeout DUR |
等待锁的最长时间;0 无限等待 |
0 |
-N, --no-wait |
锁被占用时立即失败 | false |
--json |
输出 JSON | false |
--format 必填,只接受 rpm 或 deb:
新 Dist 继承工作区的架构列表。需要选择架构子集或设置 limit、exclude 时,编辑 sow.yml,再运行 sow config check 与 sow build。
名称与格式已经存在时,dist new 报告当前状态。同名但格式不同会被拒绝:
创建与恢复
dist new 更新 sow.yml 并构建新 Dist。操作中断后,运行 sow build 恢复。
新 Dist 具有有效的空索引。RPM Dist 在每个架构视图下有一份空
repodata/;DEB Dist 有空的 Packages、Packages.gz、by-hash/SHA256/ 条目,
以及 Release;配置签名时再生成 InRelease 与 Release.gpg。
sow dist show
显示一个 Dist 的详细信息。
| 参数 | 说明 | 默认 |
|---|---|---|
-C, --workdir DIR |
工作区发现的起始目录 | 当前目录 |
-r, --repo NAME |
选择一个仓库 | 按选择规则 |
--json |
输出 JSON | false |
JSON 还包含 effective_config_sha256,即解析后的 Dist 配置摘要。
修改 limit、exclude 或签名密钥后,当前配置可能与构建快照不同。
SOW 会将该 Dist 标为 dirty,重新构建后恢复一致。
sow dist rm
删除一个 Dist 的成员关系与衍生索引。
| 参数 | 说明 | 默认 |
|---|---|---|
-f, --force |
删除成员与索引,但保留 pool 中的包 | false |
-C, --workdir DIR |
工作区发现的起始目录 | 当前目录 |
-r, --repo NAME |
选择一个仓库 | 按选择规则 |
-T, --timeout DUR |
等待锁的最长时间;0 无限等待 |
0 |
-N, --no-wait |
锁被占用时立即失败 | false |
--json |
输出 JSON | false |
删除 Dist 不会删除 pool 字节
SOW 删除该 Dist 的配置、成员关系与索引。包文件仍保存在 pool/ 中:
运行 sow gc 可以回收当前状态与保留状态都不再需要的包文件。
如果已配置的目标发布过这个 Dist,移除会被拒绝。详见移除已发布视图。
仓库的 protected: true 只阻止仓库删除;受保护仓库上的常规 Dist 维护照常进行。
示例
在同一个仓库中创建 RPM 与 DEB Dist:
创建 beta Dist,在 sow.yml 中设置包保留策略,再构建:
列出需要构建的 Dist:
退出码
| 码 | 触发条件 |
|---|---|
0 |
列出、创建、显示或删除成功;或 dist new 报告已存在的 Dist |
1 |
创建空索引时的运行时 I/O 或渲染错误 |
2 |
用法错误——--format 缺失或非法、工作区未找到、仓库选择有歧义 |
4 |
工作区或仓库锁被占用,且给了 --no-wait 或 --timeout 到期 |
5 |
操作日志的完整性或恢复错误 |
6 |
名称非法、Dist 不存在、同名不同格式冲突、非空但未给 -f |
参见
6 - sow add
sow add 将软件包导入指定 Dist,并构建本地索引。它从包头读取格式与架构,再应用各 Dist 的成员策略。需要分批导入后统一构建时,使用 --skip。需要更新远程目标时,在构建后运行 sow publish。
语法
参数
| 参数 | 说明 | 默认 |
|---|---|---|
-R, --recursive |
递归进入 PATH 目录的子目录 |
关闭(只扫顶层) |
--skip |
只更新期望状态,不构建 | 关闭 |
-j, --jobs N |
解析、哈希与渲染的并发工作线程数 | 逻辑 CPU 数 |
-C, --workdir DIR |
工作区发现的起始目录 | 当前目录 |
-r, --repo NAME |
选择一个仓库 | 按选择规则 |
-d, --dist NAME |
选择一个 Dist;可重复 | 按选择规则 |
-T, --timeout DUR |
等待锁的最长时间;0 无限等待 |
0 |
-N, --no-wait |
锁被占用时立即失败 | false |
--json |
输出 JSON | false |
输入与目标
PATH 可以是文件或目录。目录默认只扫描顶层,除非你加 -R。
选择一个仓库和一个或多个 Dist。可用 -r、-d 指定,也可按当前目录自动选择。混合添加 RPM 与 DEB 时,每个包只进入格式相同的 Dist。没有兼容目标的包会被拒绝。
根据软件包适用的发行版选择 Dist。SOW 检查包格式与架构,不测试操作系统或依赖兼容性。
汇总行给出操作记录 ID、逐项计数、成员增减、新的期望状态修订号、构建快照,以及仓库是否
留在 dirty 状态。随后是每个输入一行 item,顺序稳定。
逐项状态
每行 item 带一个总体 status,以及 dists= 中的逐 Dist 判定。
| 状态 | 含义 |
|---|---|
accepted |
新建软件包对象,且至少增加一条成员关系 |
reused |
内容已存在于本仓库;可能只是新增了成员关系引用 |
excluded |
策略把它从所有目标 Dist 中移除——看 dists= 区分是 excluded 还是 limited |
failed |
该包被拒绝,error= 字段说明原因 |
reused 表示复用已有内容:同一个文件加两次不会产生第二个对象或重复成员关系。默认重复执行
add 时还会构建所选 Dist。Dist 已是最新状态时,构建快照不变。先前 --skip 或配置变更留下
dirty 状态时,SOW 会补做构建,并可能生成新的构建快照:
把同一个对象加进第二个 Dist 同样是 reused——包池只保留一份,只是多了一条成员关系。
需要继续延后构建时,再次使用 --skip。
软件包架构
add 从包头读取格式与原生架构,再对照工作区许可表。架构不受支持或不在配置的许可表中时,该包会被拒绝:
RPM 的 noarch 与 DEB 的 all 是架构中性(neutral)的。它们只产生一个软件包对象与一条
成员关系,但会渲染进目标 Dist 的每个有效架构视图。只有所选 Dist 会包含这些包。
策略:exclude 与 limit
SOW 将输入包与 Dist 的现有成员合并,先执行 exclude,再执行 limit。被策略移除的包会显示为 excluded,不算解析失败。
这里 trixielim 配了 exclude: [{kind: [dbgsym]}] 与 limit: 1。dbgsym 包被规则排除;
libpq5 18.2-1 因版本上限被移除并报告为 limited,18.3-1 被保留。两者的顶层状态都是 excluded,
用 dists= 字段区分。
limit 按 (二进制包名, 规范架构) 分组,因此 18.3-1:amd64 与 18.3-1:arm64 在 limit: 1 下都能
留下。同一次运行中,一个包可以被某个 Dist 接受、被另一个 Dist 跳过。
放宽 exclude 或 limit 后,需要重新运行 sow add 来恢复软件包。策略作用于期望成员,而不是 pool/ 中的全部残留文件。
部分成功的批次
即使同批有失败项,合法且无冲突的包依然会提交。失败的输入原地不动,各自带自己的错误信息,命令退出
3:
如果每个输入都失败,操作以退出码 6 被拒绝,期望成员与公开内容保持原样。人类输出会列出
每个失败输入及其原因,JSON 则在 result.items 中保留这些信息:
被策略排除不属于输入失败;全部被排除的批次可以正常成功,包括首次向空 Dist 添加时。
使用 SIGINT 或 SIGTERM 中断命令时,命令返回 130。使用原始输入文件重新执行;恢复会保留已经提交的成员变更。
包内容改变时,使用新的版本与文件名。本地 GC 后,已发布的包池路径仍然保留。路径冲突只拒绝对应输入,其他有效输入仍可成功。
重新添加同一个包时,保持文件名大小写一致。仅大小写不同的路径会产生冲突。在大小写不敏感的文件系统上,源码包目录名也必须可以区分,详见工作区文件系统。
–skip
--skip 提交期望成员,保持 pool/、dists/ 与构建快照不变。新包存放在私有待构建目录,供后续构建使用。期望状态与已构建状态不同时,仓库为 dirty;重复添加未变化的成员可以保持 clean。
pending=4/2326 表示有 4 个包、共 2326 字节等待构建。构建成功后,实际采用的包进入公开目录,并出现在 sow changes 的结果中。
批量导入时用 --skip,最后构建一次:
处理顺序
SOW 检查软件包,并按配置为新 RPM 签名。随后执行 exclude 与 limit,记录最终成员;未设置 --skip 时,继续构建。
输入文件保持原样,签名在私有副本上完成。
RPM 签名模式
Managed 模式的 RPM 包签名在 sow.yml 的 signing.rpm.packages.mode 中配置,命令行没有覆盖开关。
| 模式 | 行为 |
|---|---|
never |
完整保留输入字节 |
fill |
无签名或签名不受信任时用配置密钥签名;已有能被 trusted_keys 验证的签名则保持字节。配置了密钥时的默认值 |
always |
确保最终包由配置密钥有效签名;否则对暂存副本重签 |
没有配置密钥时只能用 never。
重复导入时,SOW 复用内容相同的软件包。如果 RPM 只有签名不同,且已有包满足当前签名策略,也可以复用。包内容改变或已有签名不符合策略时,会产生坐标冲突。完整匹配规则见签名模型。
退出码
| 码 | 触发条件 |
|---|---|
0 |
输入处理完成,包括按策略排除的输入;构建完成或已跳过 |
1 |
运行时 I/O、解析器、渲染器或签名失败 |
2 |
用法错误、工作区未找到,或仓库/Dist 选择有歧义 |
3 |
部分批次——至少一项已提交,至少一项失败 |
4 |
仓库锁被占用,且给了 --no-wait 或 --timeout 到期 |
5 |
完整性或恢复错误,包括在 applied 之后构建失败 |
6 |
全部输入失败,或选择范围、签名、状态前提不允许执行操作 |
参见
7 - sow rm
sow rm 从指定 Dist 移除软件包,并重建本地索引。使用 --check 预览删除结果,使用 --skip 延后构建。包文件仍保留在 pool/ 中,由 sow gc 回收不再需要的文件。
语法
参数
| 参数 | 说明 | 默认 |
|---|---|---|
-c, --check |
预览移除结果,不修改仓库 | 关闭 |
--skip |
只更新期望状态,不构建 | 关闭 |
-j, --jobs N |
并发工作线程数 | 逻辑 CPU 数 |
-C, --workdir DIR |
工作区发现的起始目录 | 当前目录 |
-r, --repo NAME |
选择一个仓库 | 按选择规则 |
-d, --dist NAME |
选择一个 Dist;可重复 | 按选择规则 |
-T, --timeout DUR |
等待锁的最长时间;0 无限等待 |
0 |
-N, --no-wait |
锁被占用时立即失败 | false |
--json |
输出 JSON | false |
--check 与 --skip 互斥:
包引用
PACKAGE 支持以下五种写法。完整格式与匹配规则见包引用,简版如下:
| 写法 | 示例 |
|---|---|
| 内容哈希 | sha256:d6f332ed157de1d42058ec785b392a1cc4b5836c27830af8fbf083cce29ef0ab |
| RPM 坐标 | rpm:epel-release-0:7-5.noarch |
| DEB 坐标 | deb:libpq5=18.3-1:amd64 |
| 完整文件名 | epel-release-7-5.noarch.rpm |
| 裸二进制包名 | epel-release |
裸包名匹配所选 Dist 中该名称的全部版本与架构。其他引用形式必须唯一标识一个对象。有歧义时,命令返回错误并列出候选项。
sow ls 会直接打印精确的 sha256: 引用与规范化坐标,你不需要手工
拼接。
引用没有匹配的软件包时,命令返回错误:
默认行为:移除并重建
不带 --check 或 --skip 时,rm 提交期望状态变更,并在返回前重建每个受影响的 Dist。pool 对象
留在磁盘上。
汇总之后会为每个受影响文件输出一行 change(本次运行共八行)。加上 --json 后,同一结果
以稳定的标准封装返回。
移除一个 Dist 的最后一个成员是允许的。SOW 仍会渲染合法的空索引(配了密钥就带签名)——空的
Packages 配可验签的 InRelease,或每架构的空 repodata/。
用 –check 预览
-c/--check 预览移除结果与本地文件变化,不修改仓库。removed 只列出引用匹配到的成员。如果当前策略连带移除了其他成员,changes 会包含相关索引变化;实际执行后,sow log 会将这些成员计入移除数量。
两个 centos-release 版本都被裸包名匹配。change 行描述预期的本地文件变化,按 payload → metadata → pointer → delete 排列。脚本可用 --json 读取 removed[] 与 changes[] 数组。
预览会校验候选配置与既有状态。它使用共享锁,可以等待写操作完成,但不接受 --timeout 或 --no-wait:
–skip
--skip 提交期望变更,公开目录保持不变。结果与已构建状态不同时,仓库为 dirty。如果移除的只是尚未构建的新成员,仓库也可能直接恢复为 clean。
changes 为空是因为什么都没构建。执行 sow build 构建待处理变更。
与策略的交互
移除后,SOW 对剩余成员重新执行策略。如果从 limit: 1 的 Dist 中移除 libpq5 18.3-1,先前被排除的 18.2-1 仍保持排除。需要恢复它时,运行 sow add。
示例
先预览移除结果,再执行:
一次从两个 Dist 中移除同一个精确对象:
批量移除后只重建一次:
将预览结果传给其他工具:
退出码
| 码 | 触发条件 |
|---|---|
0 |
成员已移除并重建,或 --check 预览已打印 |
1 |
运行时 I/O 或渲染失败 |
2 |
用法错误——--check 与 --skip 同用、--check 与锁参数同用、选择有歧义、工作区未找到 |
4 |
仓库锁被占用,且给了 --no-wait 或 --timeout 到期 |
5 |
完整性或恢复错误 |
6 |
引用无匹配,或非裸名的引用有歧义;整批拒绝,不删除任何成员 |
参见
8 - sow ls
sow ls 列出指定 Dist 的期望成员。每行还显示该包在整个仓库中的期望成员位置与已构建位置。可从输出中获取供 show 或 rm 使用的包引用。
语法
| 参数 | 含义 | 默认值 |
|---|---|---|
-C, --workdir DIR |
工作区发现起点 | 当前目录 |
-r, --repo NAME |
选择仓库 | 选择规则 |
-d, --dist NAME |
选择 Dist;可重复 | 选择规则 |
--json |
输出 JSON | false |
输出
| 列 | 含义 |
|---|---|
SHA256 |
包内容的唯一标识,可直接传给 show 或 rm |
COORDINATE |
规范的 rpm: 或 deb: 包引用 |
DISTS |
整个仓库内的期望成员位置 |
BUILT_DISTS |
当前构建快照中的成员关系 |
POOL_PATH |
包文件相对于仓库的路径 |
首行显示所选 Dist 是否为 dirty。即使成员数量相同,配置变化也可能使 Dist 变为 dirty。
-d 按期望成员筛选包行。DISTS 与 BUILT_DISTS 列随后显示每个包在整个仓库中的全部位置。通过 rm --skip 移除的包不会出现在列表中,即使旧索引仍包含它。BUILT_DISTS 为空表示当前没有本地已构建 Dist 包含此包。
每个包只输出一行,多个 Dist 用逗号分隔。空 Dist 返回成功,输出中没有软件包行。
选择范围
ls 要求 Dist 集合无歧义。仓库包含多个 Dist 时,应传入一个或多个 -d,或从
<repo>/dists/<dist>/ 内运行。
加上 --json 后,同一批记录位于 result.packages 中。
示例
列出尚未构建对象的精确引用:
按路径列出包体:
退出码
| 代码 | 触发条件 |
|---|---|
0 |
已输出成员列表,包括空列表 |
1 |
运行时 I/O 错误 |
2 |
用法错误、未发现工作区或隐式仓库/Dist 选择有歧义 |
5 |
仓库状态库不可读或不一致 |
6 |
显式指定的仓库或 Dist 未配置 |
参见
9 - sow show
sow show 查看所选仓库中的一个软件包。文本输出包含包信息、存储位置与成员关系。需要完整的软件包记录时,加上 --json。
语法
| 参数 | 含义 | 默认值 |
|---|---|---|
-C, --workdir DIR |
工作区发现起点 | 当前目录 |
-r, --repo NAME |
选择仓库 | 选择规则 |
-d, --dist NAME |
将候选项收窄到指定 Dist;可重复 | 整个仓库 |
--json |
输出 JSON | false |
包引用
PACKAGE 可使用 sha256:<hex> 内容哈希、规范的 rpm:<NEVRA> 或
deb:<name>=<version>:<arch> 坐标、完整包文件名或裸二进制包名。完整格式见
包引用。
裸包名必须在所选范围内唯一。sow rm foo 会移除所有匹配版本,而 sow show foo 只允许返回
一个对象;有歧义时会列出候选项:
从错误信息或 sow ls 复制精确坐标/SHA-256 后重试。
输出
不带 --json 时,show 输出包信息、存储路径,以及期望与已构建状态中的位置:
加上 --json 后,result.package 会返回完整软件包记录,包括下列规范化字段。
| 字段 | 含义 |
|---|---|
canonical_arch |
x86_64、aarch64,或 RPM noarch / DEB all 对应的 neutral |
kind |
策略分类:main、debuginfo、debugsource、llvmjit、dbgsym、dbg |
source |
标准化源码包名 |
payload_sha256 |
RPM 不含签名部分的摘要,用于判断是否可以复用包文件 |
signature_key |
包内签名的密钥 ID(如有) |
storage |
构建前为 pending,进入仓库树后为 pool |
dists / built_dists |
期望与当前已构建状态中的位置 |
不带 -d 时,查找范围包括当前没有成员关系的已存储对象。带 -d 时,候选包必须属于所选 Dist 的期望成员。返回的 dists 与 built_dists 列表覆盖整个仓库。
退出码
| 代码 | 触发条件 |
|---|---|
0 |
已输出一个软件包对象 |
1 |
运行时 I/O 错误 |
2 |
用法错误、未发现工作区或隐式仓库选择有歧义 |
5 |
仓库状态库不可读或不一致 |
6 |
显式范围未配置,或引用没有匹配/匹配多个对象 |
参见
10 - sow where
sow where 在工作区中查找一个软件包的期望成员位置。默认搜索全部仓库;使用 -r 或 -d 限定范围。
语法
| 参数 | 含义 | 默认值 |
|---|---|---|
-C, --workdir DIR |
工作区发现起点 | 当前目录 |
-r, --repo NAME |
将搜索限制到一个仓库 | 全部仓库 |
-d, --dist NAME |
将搜索限制到指定 Dist;可重复 | 全部 Dist |
--json |
输出 JSON | false |
引用解析
PACKAGE 与 sow show 使用相同格式:SHA-256、规范 RPM/DEB 坐标、
完整文件名或裸包名。
引用必须确定一个软件包,即格式、坐标和 SHA-256 均相同的包。同一个包可以位于多个仓库。如果匹配到不同的包,使用 -r 或 -d 收窄范围,或提供精确坐标、SHA-256。
输出
不带 --json 时,where 先输出摘要,再为每个位置输出一行:
每个位置同时给出该仓库内的期望位置 dists 与已构建位置 built_dists。查找候选包时使用期望成员集。如果包已从全部所选 Dist 中移除,命令将不再找到它,即使旧索引仍包含它。要查看这样的已存储对象,使用 sow show PACKAGE -r NAME,不要加 -d。
加上 --json 后,位置列表位于 result.locations。没有匹配包时,命令返回错误:
示例
列出期望状态中包含此包的 Dist:
退出码
| 代码 | 触发条件 |
|---|---|
0 |
已输出一个解析后的软件包对象及其位置 |
1 |
运行时 I/O 错误 |
2 |
用法错误或未发现工作区 |
5 |
某个仓库状态库不可读或不一致 |
6 |
显式仓库/Dist 未配置,或引用没有匹配/在所选范围内有歧义 |
参见
11 - sow status
sow status 显示仓库是否需要构建、待构建数据量及写锁占用情况。它读取已记录状态,不扫描包文件内容。需要验证文件内容时,使用 sow check。
语法
| 参数 | 含义 | 默认值 |
|---|---|---|
-C, --workdir DIR |
工作区发现起点 | 当前目录 |
-r, --repo NAME |
选择仓库 | 选择规则 |
-d, --dist NAME |
只查看指定 Dist;可重复 | 全部 Dist |
--json |
输出 JSON | false |
仓库状态
SOW 记录期望的软件包集合,以及上一次构建完成的构建快照。
| 状态 | 含义 | 下一步 |
|---|---|---|
clean |
期望状态与已构建状态一致 | 复制仓库前运行 check |
dirty |
两种状态不同,常见于 --skip 或配置变化之后 |
运行 build 应用变更 |
recovering |
本地仓库操作被中断 | 运行 build 恢复 |
error |
状态、文件或恢复记录需要处理 | 查看 dirty_reasons,运行 check 与 log |
输出
人类可读输出包含仓库状态、ready_to_copy、期望状态修订号、构建快照、
受影响 Dist、待处理对象数量/字节数与写锁状态。
JSON 结果还包含 dirty_reasons 与最近一次操作记录:
ready_to_copy 汇总已记录的状态。为 false 时,dirty_reasons 给出原因。文件内容由 sow check 校验。
读取行为
status 读取状态,不迁移或修复数据库。它可以读取 schema v6、v12 与当前 v13 数据库。不支持或无法读取的状态返回 5。对旧工作区执行写操作前,先备份,再逐个运行 sow repo migrate。
退出行为
只要状态可读,status 在 clean、dirty、recovering、error 四种状态下都返回 0。
脚本应读取结构化状态,而不是把后三者当作命令执行失败。
| 代码 | 触发条件 |
|---|---|
0 |
仓库状态可读 |
1 |
运行时 I/O 错误 |
2 |
用法错误、未发现工作区或隐式仓库选择有歧义 |
5 |
状态库不可读或不一致 |
6 |
显式指定的仓库或 Dist 未配置 |
参见
12 - sow build
sow build 更新本地索引,使其与期望成员和当前配置一致。在 add --skip、rm --skip 或修改策略后运行此命令。开始新构建前,它会恢复未完成的本地仓库操作。
语法
| 参数 | 含义 | 默认值 |
|---|---|---|
-j, --jobs N |
并行工作线程数,不得小于 1 |
逻辑 CPU 数 |
-C, --workdir DIR |
工作区发现起点 | 当前目录 |
-r, --repo NAME |
选择仓库 | 选择规则 |
-d, --dist NAME |
构建指定 Dist;可重复 | 全部受影响 Dist |
-T, --timeout DUR |
最长等锁时间;0 表示无限等待 |
0 |
-N, --no-wait |
锁被占用时立即失败 | false |
--json |
输出 JSON | false |
不带 -d 时,SOW 构建所选仓库中全部受影响 Dist;带 -d 时只构建指定 Dist,
未选择的变化继续保持 dirty。
结果
不带 --json 时,build 输出一行人类可读摘要:
脚本读取结果时,使用 --json。
空操作构建
成员关系、相关策略、渲染设置与签名配置均未变化时,build 不执行构建,也不生成新的构建快照:
应用策略变更
build 会重新执行当前 exclude 与 limit 策略。收紧策略可能移除期望成员;
放宽策略不会自动恢复已被移除的包,需要重新运行 sow add。
提交与恢复
SOW 先将所需的待构建包放入 pool/,再写入索引,最后更新 repomd.xml、Release 等客户端入口。一次构建可以包含多个 Dist,它们共用本次构建快照;未选择的 dirty Dist 仍需要构建。
构建中断后,重新运行此命令。SOW 根据操作日志完成或回滚未完成的工作。如果日志、数据库与文件不一致,命令会报告完整性错误。使用 sow check 与 sow log 查看受影响的状态。
进度事件
耗时较长的构建会向操作日志追加结构化 build_progress 记录。每条事件包含 phase、
completed、total 与 jobs。当前阶段为:
rendering;promoting_payload;publishing_dists;normalizing_public_tree;finalizing。
使用 sow log OPERATION
查看明细。
元数据签名
在 sow.yml 中配置元数据签名。配置的密钥引用或指纹改变时,
相关 Dist 变为 dirty,下一次 build 重新签名。
- RPM:总是生成
repodata/repomd.xml;配置签名后额外生成repomd.xml.asc。 - DEB:总是生成
Release;配置签名后额外生成InRelease与Release.gpg。
退出码
| 代码 | 触发条件 |
|---|---|
0 |
构建成功或无需操作 |
1 |
渲染、签名或文件系统错误 |
2 |
用法错误、未发现工作区或隐式仓库选择有歧义 |
4 |
仓库写锁不可用 |
5 |
无法安全完成恢复,或仓库处于 error |
6 |
显式范围未配置,或当前配置拒绝既有状态 |
参见
sow status—— 判断是否需要构建sow check—— 验证构建结果sow changes—— 查看生成的文件差异- 事务与恢复 —— 完整提交协议
13 - sow check
交付 Managed 仓库前,使用 sow check 检查包哈希、状态、索引、签名与构建快照清单。此命令只读;如果期望状态与已构建状态不同,先运行 sow build。
语法
| 参数 | 含义 | 默认值 |
|---|---|---|
-j, --jobs N |
并行校验工作线程数,不得小于 1 |
逻辑 CPU 数 |
-C, --workdir DIR |
工作区发现起点 | 当前目录 |
-r, --repo NAME |
选择仓库 | 选择规则 |
-d, --dist NAME |
校验指定 Dist;可重复 | 全部 Dist |
--json |
输出 JSON | false |
校验层
仓库没有未完成的布局迁移时,check 按顺序报告九层校验:
| 层 | 校验内容 | checked 计数 |
|---|---|---|
config |
sow.yml 能否针对该仓库解析并通过校验 |
配置对象 |
state |
SQLite quick_check、外键、日志与恢复证据 |
一个状态库 |
public-modes |
服务目录中所有文件与目录权限 | 已检查路径 |
retained |
保留记录与保存的构建快照清单;损坏记录的处理方法见 retain rm |
保留记录 |
package-bytes |
包池与私有待构建包文件的 SHA-256 | 软件包对象 |
desired-membership |
成员关系能否在当前策略下解析到真实对象 | 成员关系 |
index |
渲染索引是否与其声明的成员关系一致 | Dist |
signature |
所有已声明元数据/软件包签名是否有效 | 签名 |
generation-manifest |
构建快照清单是否与磁盘文件一致 | 一个清单 |
仓库存在未完成的布局迁移时,check 报告 config、state、public-modes 与 layout-transition,随后停止。按报告中的 repo migrate 指令完成或中止迁移。
软件包校验
每次运行都会重新计算包文件的哈希。同一物理文件的硬链接共用一次哈希结果。带签名的 RPM 还会进行签名校验。checked 统计软件包对象数量,不是文件读取次数。
dirty 不可交付
dirty 仓库需要先构建,才能通过 check。旧构建快照与新的期望状态可以分别通过校验,但二者仍有差异:
此时退出 5。运行 sow build 后,再运行 sow check。
退出码
| 代码 | 触发条件 |
|---|---|
0 |
全部校验层通过,仓库可复制交付 |
1 |
校验期间发生 I/O 错误 |
2 |
用法错误、未发现工作区或隐式仓库选择有歧义 |
5 |
某个校验层失败,或仓库不可交付 |
6 |
显式指定的仓库或 Dist 未配置 |
参见
sow status—— 快速查询状态sow build—— 按期望状态构建索引- 退出码 —— dirty 为什么映射到
5 - 可观测与审计 —— 组合使用校验与审计
14 - sow changes
sow changes 列出基准构建快照与当前构建快照之间的文件差异。路径相对于仓库根目录。需要包含尚未构建的期望变化时,先运行 sow build。
语法
| 参数 | 含义 | 默认值 |
|---|---|---|
-C, --workdir DIR |
工作区发现起点 | 当前目录 |
-r, --repo NAME |
选择仓库 | 选择规则 |
--json |
输出 JSON | false |
该命令作用于整个仓库,不接受 -d/--dist。
输出
各列依次为操作、阶段、仓库相对路径、大小、SHA-256。
| 字段 | 取值 |
|---|---|
| 操作 | add、update、delete |
| 阶段 | payload、metadata、pointer、delete |
此计划用于查看本地文件变化。需要交付时,使用 sow publish,或暂存完整副本后再切换服务目录。
基准构建快照
不带参数时,SOW 比较当前构建快照与前一次构建快照。
BASE_GENERATION 是 0..当前编号 范围内的十进制整数。基准为 0 时输出当前构建快照的完整
交付清单,但不包含私有 sow.yml 与 .sow/。基准等于当前编号时输出空计划;从未构建的
仓库同样输出空的 0 -> 0 计划。
dirty 与恢复状态
期望状态尚未构建时,首行显示 dirty=true。结果仍以当前构建快照为终点,不包含待构建包文件。
仓库为 recovering 或 error 时,先按诊断信息恢复或修复仓库,再运行 changes。
示例
输出当前完整清单:
生成仓库级计划后按路径筛选一个 Dist:
退出码
| 代码 | 触发条件 |
|---|---|
0 |
已输出计划,包括空计划 |
1 |
运行时 I/O 错误 |
2 |
用法错误、传入 -d、未发现工作区或隐式仓库选择有歧义 |
5 |
仓库处于 recovering/error,或状态证据不一致 |
6 |
显式仓库未配置,或基准编号超出有效范围 |
参见
sow build—— 创建新的构建快照sow publish—— 使用受支持的发布协议sow log—— 操作记录及其文件变化- 仓库布局 —— 公开/私有路径边界
15 - sow publish
sow publish 将当前构建快照复制到 sow.yml 的 targets: 中配置的目标。目标配置指定仓库与存储类型。需要发布最新期望状态时,先完成构建。
语法
| 参数 | 含义 | 默认值 |
|---|---|---|
--abort |
放弃尚未进入提交阶段的中断发布 | false |
--rebind |
确认并记录允许修改的目标名称、公共端点或缓存 TTL | false |
-C, --workdir DIR |
工作区发现起点 | 当前目录 |
-T, --timeout DUR |
最长仓库等锁时间;0 表示无限等待 |
0 |
-N, --no-wait |
锁被占用时立即失败 | false |
--json |
输出 JSON | false |
TARGET 必须是已配置的 filesystem 或 r2 发布目标。--abort 与 --rebind 互斥。
发布前准备
需要包含最新软件包与策略变更时,先运行 build。dirty 仓库仍可以发布上一个已完成的构建快照。
配置目标的 Web 服务或存储桶访问权限,使 public_endpoint 能读取发布文件,然后运行 sow publish TARGET。
发布协议
SOW 先核对本地文件与已完成的构建快照清单,再按以下顺序发布:
- 包文件;
- 使用独立内容 URL 的元数据;
repomd.xml、Release等客户端入口;- 验证公共访问并保存发布检查点。
SOW 记录进度,中断后可用同一命令继续发布。目标已包含当前构建快照时,重复运行不产生变化。
重绑定可变目标配置
首次发布会记录仓库与目标绑定。修改目标名称、公共地址或缓存 TTL 后,使用 --rebind 记录新设置并继续发布:
如果修改了 targets: 中的目标名,命令中使用新名称。
| 可以修改 | 不可变;必须配置新目标 |
|---|---|
| 目标名称 | 仓库身份 |
public_endpoint |
存储类型、存储 endpoint 或区域 |
max_cache_ttl |
存储桶或 prefix |
修改 max_cache_ttl 前,先完成目标维护。文件系统目标有未完成的删除操作时,也需先完成删除,再修改 public_endpoint。首次发布到新目标时,直接运行 sow publish TARGET。
Abort 与恢复
发布中断后,重新运行 sow publish TARGET 继续发布。
需要放弃本次发布时,在进入 commit_intent 阶段前运行 sow publish TARGET --abort。SOW 核对已上传的对象,记录放弃结果,并保留远端文件。进入 commit_intent 后,使用普通发布命令完成本次发布。
已发布的包 URL 对应固定内容。内容改变时,使用新的包版本与文件名。如果远端文件与本次发布记录不符,按报告处理冲突,详见故障处理。
公共可见性校验
记录发布检查点前,SOW 会通过 public_endpoint 读取并验证已发布文件。HTTP(S) 校验使用普通 GET 请求。内容过期或缺失时,在 max_cache_ttl 范围内重试。
文件系统目标支持 file:// 或 HTTP(S) 公共地址,R2 目标要求 HTTP(S)。每次 R2 发布都会列出目标前缀并逐个用 HEAD 检查对象;有更新时执行两次清单检查。保留 R2 中的旧对象:目标 GC 只报告、不删除,后续发布还会核对远程前缀与已记录清单。
移除已发布视图
只要目标仍在配置中,SOW 就不允许本地变更移除它已发布的入口,例如整个 Dist、RPM 架构视图或配套签名文件。
需要停用该目标时,先停止向它发布,从 sow.yml 的 targets: 中删除对应配置,再运行 sow config check。随后可以移除本地视图。此操作保留原有远程文件与发布历史。需要发布删减后的仓库时,配置使用不同存储前缀的新目标,并将客户端切换到该目标。
退出行为
| 代码 | 触发条件 |
|---|---|
0 |
发布完成,或目标已经是当前构建快照 |
1 |
文件系统、存储类型、网络、验证或绑定冲突(包括必须 rebind) |
2 |
用法、工作区发现或 sow.yml 无效 |
4 |
仓库写锁不可用 |
5 |
本地/发布恢复证据不一致,或源不可交付 |
6 |
目标不存在/不安全,或其他安全前置条件拒绝 Publish/Abort/Rebind |
参见
sow status与sow check—— 判断当前构建快照是否正是准备交付的版本sow gc—— 回收目标中不再需要的文件sow.yml发布目标 —— 存储类型配置- 发布模型 —— 阶段、回执、恢复与缓存宽限期
16 - sow retain
sow retain 保留指定构建快照所需的包文件,防止本地 GC 回收。保留内容包括包文件与冻结清单;此命令不恢复或发布旧仓库视图。
语法
GENERATION 必须是大于零的十进制整数。
retain add
传入当前构建快照的编号。SOW 校验该快照,保存清单,并记录 GC 需要保留的包文件。应在生成下一个构建快照前添加此记录。
重复添加同一个构建快照时,如果保留记录仍可通过校验,命令不产生变化。
retain ls
列出仓库的保留记录。
空列表也是成功结果。
retain rm
移除指定构建快照的保留记录:
该命令不删除软件包体。指定的构建快照没有保留记录时,命令成功返回,不作修改。只有在其他保留记录与操作也不再
引用这些包体时,后续本地 sow gc 才可能回收。
保留记录损坏时,retain rm、retain ls、本地 gc 与 check 都会报告错误。check 的 retained 层会指出受影响的构建快照。需要丢弃该损坏记录时:
- 停止工作区写操作。
- 将
.sow/<repo>/retained/<GENERATION>移到工作区外的备份位置。 - 再次运行
sow check。
移走记录也会移除它提供的 GC 保护。
参数
| 参数 | 适用命令 | 含义 |
|---|---|---|
-C, --workdir DIR |
全部 | 工作区发现起点 |
-r, --repo NAME |
全部 | 选择仓库 |
-T, --timeout DUR |
add、rm |
最长写锁等待时间 |
-N, --no-wait |
add、rm |
锁被占用时立即失败 |
--json |
全部 | 输出 JSON |
退出行为
| 代码 | 触发条件 |
|---|---|
0 |
操作完成,包括空列表 |
1 |
文件系统或运行时 I/O 错误 |
2 |
构建快照编号格式无效、发现错误或隐式仓库选择有歧义 |
4 |
add/rm 无法获取写锁 |
5 |
构建快照清单或仓库状态不一致 |
6 |
显式仓库未配置、retain add 指定的不是当前构建快照编号,或其他安全规则拒绝请求 |
参见
sow gc—— 回收保留状态不再需要的包文件sow changes—— 查看构建快照差异- 仓库布局 —— 私有保留记录位置
17 - sow gc
使用 sow gc 回收本地不再需要的包文件。使用 sow gc TARGET 维护配置的发布目标。文件系统目标可以删除符合条件的对象;R2 目标只报告候选对象。
语法
| 参数 | 含义 | 默认值 |
|---|---|---|
-C, --workdir DIR |
工作区发现起点 | 当前目录 |
-r, --repo NAME |
仅用于选择本地 GC 的仓库 | 选择规则 |
-T, --timeout DUR |
最长仓库等锁时间;0 表示无限等待 |
0 |
-N, --no-wait |
锁被占用时立即失败 | false |
--json |
输出 JSON | false |
目标自身已绑定仓库,因此 gc TARGET -r NAME 属于用法错误。两种模式都不接受 --dist。
本地 GC
仓库完成构建且状态为 clean 时,可以执行本地 GC。状态为 dirty 时,先运行 sow build。只有以下记录都不再引用某个包时,GC 才会删除它:
- 当前期望成员、已构建成员,以及为旧客户端保留的旧成员记录;
- 显式
retain记录; - 恢复状态与非终态操作记录;
- 发布记录;
- 活跃维护操作。
操作会记入日志。实际删除包文件时,仓库生成新的构建快照;没有符合条件的包时,命令不作修改。
目标 GC
目标 GC 等待配置的缓存宽限期到期,再检查哪些对象仍需保留:
| 存储类型 | 行为 |
|---|---|
filesystem |
宽限期到期后,按条件删除合格对象,再验证公共 URL 已无法访问该对象,并记录结果 |
r2 |
保存候选对象报告,不删除对象 |
空操作表示当前没有到期维护任务。
退出行为
| 代码 | 触发条件 |
|---|---|
0 |
GC 完成或没有合格对象 |
1 |
文件系统、存储服务、网络或其他运行时错误 |
2 |
用法、工作区发现、sow.yml 无效或隐式仓库选择有歧义 |
4 |
仓库写锁不可用 |
5 |
恢复、状态、回执或清单证据不一致 |
6 |
显式仓库/目标未配置或不安全,或删除被安全前置条件拒绝 |
参见
sow retain—— 保护包文件免于本地 GC 回收sow publish—— 创建目标检查点与回执- 发布模型 —— 存储类型保证与缓存宽限期
18 - sow export
sow export rpm-leaf 将一个 Dist 的指定架构导出为独立 RPM 仓库。它把软件包复制到外部目录,并将元数据中的包路径改为本地 pool/... 路径。
语法
| 参数 | 要求 |
|---|---|
DIST |
已配置的规范 RPM Dist 名称 |
ARCH |
x86_64 或 aarch64 |
DIR |
不存在或为空,且不与仓库、私有状态、filesystem 目标根重叠的目录 |
| 选项 | 含义 | 默认值 |
|---|---|---|
--hardlink |
对同一文件系统上的只读输出使用硬链接 | 复制文件 |
-C, --workdir DIR |
工作区发现起点 | 当前目录 |
-r, --repo NAME |
选择仓库 | 选择规则 |
--json |
输出 JSON | false |
输出
目标目录包含:
- 使用本地包路径的 RPM 元数据;
- 所需软件包目录树;
- 导出清单;
.sow-export.json来源记录。
源仓库必须为 clean,有已完成的构建快照,且没有未完成的操作。所选 RPM 视图必须属于当前构建快照。导出物独立于工作区,不会阻止 GC 回收源仓库中的包。
导出失败后,修正报告的问题,再换一个不存在或为空的目录重试。失败的目标目录中可能留有部分文件。
Managed RPM 与 export rpm-leaf 的 repomd data 时间戳固定为 0,没有
--metadata-timestamp 选项。因此它们不能直接接管保留了正数时间戳缓存的同一个 EL7
repository ID;换 baseurl 本身不能解决。需要客户端采用新的 repository ID 或清理元数据缓存。
若必须保留旧 ID 和缓存继续更新,请使用带显式时间戳的 Plain create,按
迁移指南 维护发布时间并重签 repomd。
复制与硬链接
默认复制文件。--hardlink 只适用于同一文件系统上的只读输出。修改硬链接包文件也会修改 SOW 包池中的源文件。
退出行为
| 代码 | 触发条件 |
|---|---|
0 |
独立 RPM 仓库导出完成 |
1 |
文件系统、复制、硬链接或元数据写入错误 |
2 |
命令语法、Dist/架构 Token 无效,或发现/隐式仓库选择有歧义 |
5 |
源构建快照或仓库状态不一致 |
6 |
显式仓库未配置、Dist 不是 RPM、视图/签名者不可用,或目标不安全/非空/重叠 |
参见
- 平台与集成 —— 客户端与工具兼容性
- 仓库布局 —— 源目录与导出边界
sow publish—— 向配置目标执行 Managed 交付
19 - sow log
sow log 列出仓库操作记录,并查看单次操作的详情。使用 log export 将已结束的操作导出为 JSONL,使用 log prune 从数据库中删除符合条件的旧记录。
语法
sow log
不带参数时,按由新到旧打印最近 50 条操作记录。
输出节选,operations 数组中的一个操作记录对象:
payload_json 记录意图——包括当时生效配置的摘要 config_sha256,以及生成的构建快照的
manifest_sha256。result_json 记录结果。失败的操作记录还会带 error_class 与
error_message:
| 参数 | 说明 | 默认 |
|---|---|---|
-C, --workdir DIR |
工作区发现的起始目录 | 当前目录 |
-r, --repo NAME |
选择一个仓库 | 按选择规则 |
-d, --dist NAME |
只显示触及该 Dist 的操作记录 | 全部 |
--json |
输出 JSON | false |
查看单条 Operation
传入操作记录 ID 查看摘要。加上 --json 后,可在 result.detail 中读取完整状态变化、耗时、软件包、成员与文件记录。
输出节选:
files 数组使用与 sow changes 相同的 phase 词表:payload、
metadata、pointer、delete。
Build 操作记录还会包含进度事件。它们保持当前 state,并把版本化对象放入 detail_json:
阶段包括 rendering、promoting_payload、publishing_dists、normalizing_public_tree 与 finalizing。可用这些记录查看长时间构建的进度。
按 Dist 过滤
-d 把列表限制为触及该 Dist 的操作记录——一个仓库服务多个发行版时很有用:
操作状态
state 字段表示操作进行到哪一步:
| 状态 | 含义 |
|---|---|
planned |
命令、参数、目标与预期动作已持久化 |
staged |
新包/元数据已写入临时位置并校验通过 |
applied |
期望状态与所需的私有待构建包文件已提交 |
built |
已切换到新构建快照 |
done |
终态——一次正常成功的命令 |
done_dirty |
操作已结束,仍有变化需要构建,通常出现在 --skip 之后 |
failed |
终态——在 applied 之前失败,什么都没提交 |
rolled_back |
终态——恢复在操作记录改变 Desired 之前放弃了它,例如被中断命令留下的 planned 操作记录 |
recovering |
非终态;下一条写命令必须先完成或回滚它 |
仓库日志包含 dist new 和 dist rm。工作区操作 init、repo new、repo rm 使用独立的恢复记录,不出现在这里。
sow log export
将已结束的操作导出为 JSONL,每行包含一次操作的完整记录,可用于归档或日志分析。
省略 FILE 或传 - 则写到 stdout:
| 参数 | 说明 | 默认 |
|---|---|---|
-C, --workdir DIR |
工作区发现的起始目录 | 当前目录 |
-r, --repo NAME |
选择一个仓库 | 按选择规则 |
-d, --dist NAME |
只导出触及该 Dist 的操作记录 | 全部 |
export 直接输出 JSONL,不需要 --json。
输出路径
在已有目录中选择一个新文件名。文件已存在时,log export 返回 6。直接父目录必须是真实目录,不能是符号链接。在 macOS 上使用 /private/tmp/file.jsonl,不要使用 /tmp/file.jsonl。
sow log prune
删除早于 BEFORE 且符合条件的已结束操作记录,并回收数据库空间。如果其他读连接正在使用数据库,记录可以先删除,空间回收会延后。此时结果显示 compaction_deferred: true。关闭读连接后,再运行 prune 回收空间。
输出以 UTC 显示截止时间(此处工作站时区为 UTC+8)。若有读者使空间回收
被推迟,输出会多一行 log deletion committed; space reclamation deferred while the database is busy;
使用 --json 时,日志 ID 与 compaction_deferred 位于 result 中。
| 参数 | 说明 | 默认 |
|---|---|---|
-C, --workdir DIR |
工作区发现的起始目录 | 当前目录 |
-r, --repo NAME |
选择一个仓库 | 按选择规则 |
-T, --timeout DUR |
等待锁的最长时间;0 无限等待 |
0 |
-N, --no-wait |
锁被占用时立即失败 | false |
--json |
输出 JSON | false |
prune 作用于整个仓库,不接受 -d。
BEFORE 语法
BEFORE 是 ISO-8601 日期 YYYY-MM-DD(按本地时区零点解释),或带时区的 RFC 3339 时间戳。
prune 保留的记录
prune 保留以下记录:
- 非终态的操作记录;
- 当前恢复仍需要的记录;
- 当前的软件包或成员状态;
- 构建快照及其文件差异记录。
pruned 显示已删除的操作记录数。
示例
排查最近一次写入:
从最近 50 条记录中筛选失败的操作:
归档记录,再删除指定日期之前的旧记录:
查看最后修改某个 Dist 的操作:
退出码
| 命令 | 码 | 触发条件 |
|---|---|---|
log |
0 |
记录已打印,包括空账本 |
log |
2 |
用法错误(包括非数字的操作记录 ID)、工作区未找到,或选择有歧义 |
log |
5 |
状态数据库不可读 |
log |
6 |
给定的操作记录 ID 不存在,或给出了多个不同的 -d |
log export |
0 |
导出成功 |
log export |
1 |
写目标时 I/O 失败,或父目录不是真实目录 |
log export |
2 |
用法错误或选择有歧义 |
log export |
6 |
目标已存在 |
log prune |
0 |
清理完成,包括一条都没清 |
log prune |
2 |
BEFORE 格式非法、给了 -d,或选择有歧义 |
log prune |
4 |
仓库锁被占用,且给了 --no-wait 或 --timeout 到期 |
log prune |
5 |
完整性或恢复错误 |
参见
- 可观测与审计 ——
log与status、check、changes的配合 - 事务与恢复 —— 中断后的恢复过程
- sow changes —— 比较构建前后的文件差异
- JSON 输出 —— 完整的日志结果结构