Imported from Zongsoft/tools (
packager/AGENTS.md). Install upstream withnpx skills add Zongsoft/tools --skill packager. Copyright stays with the author.
概述
本目录遵循 ../AGENTS.md。本工具生成 tar.gz、deb、rpm 安装包。开始修改前阅读 SKILL.md、双语 README 和 实现说明。
代码规范
生产代码采用既有 MIT 版权头;测试不加版权头,不使用类型或程序集别名。Tab、CRLF、方法间空行、适当中文 region;sh 使用 LF。CodeAnalysis 版本继承根 Directory.Packages.props,严格构建和 IDE0049 验证均需通过。资源经 ResXFileCodeGenerator 生成,不编写本地化测试。
职责与契约
- PackCommand 解析源目录,VersionFile 优先用 Zongsoft.Core ApplicationManifest 读取直属 .edition,仅缺失时以 ApplicationIdentifier 读取 .version;清单按显式 Edition、Current、唯一 Edition 或顶层版本选择。成功后清单输入成组回写 .edition 和 .version,缺失的 .version 创建;标识输入只更新 .version;两者均无则成组创建两者,不覆盖并发创建的文件。保存清单时将选中 Edition 设为 Current,标识保存最终身份。最终身份确定后建立本次命令独立的 Variables 视图,并传给包、脚本和文本来源,不保留进程级变量状态。tar 归档与脚本成组发布,deb/rpm 单文件发布;成功制包后才保存源版本文件,单文件原子保存,双文件失败回滚,保存失败保留包并报错。
- 源直属 .edition 及安装根 .edition 目标不进入载荷。包内 .version 通过 ApplicationIdentifier.Save(Stream) 写入内存,强制替换同目标旧条目;验证解析后的身份,不约束末尾有无换行。所有编码器经 Entry.OpenRead 读取。
- Package 是跨格式模型,Generator 编码容器;ApplicationHost 一次解析宿主、服务来源及最终 listen,Scriptor.Systemd 负责服务与生命周期组合。自动生成的服务文件直接以内存条目入包,先验证文件名和存在的宿主候选目录。tar/deb/rpm 保持路径、排除、权限和阶段意图一致,各自遵循格式规范。
- Web/Definition 通过 Zongsoft.Core Profile 的 Directives = { ProfileDirectiveOptions.Import(ProfileDirectiveBehavior.Strict) } 和读取回调收集声明,先处理覆盖再求值。Configurator.Nginx 生成安装根 .web/nginx/.conf;普通载荷是否包含 Profile 仍由 arguments/exclude 决定,生成目标冲突失败。Delivered 在生命周期之前完成弃用清理与 Tar 重定位,DESTDIR 只交付;HOSTER_WEB_ACTIVATION 控制新链接与 Nginx 操作,弃用和普通卸载仍清理本包文件/匹配链接。Web 步骤独立于自定义主钩子和 daemon 开关。
- Migration 仅按 --migration 输入名称、最终 Edition/Version/Runtime 查找并验证既有 tar.gz 与脚本;先展开变量;无 / 或 \ 时从最终 source 逐级查找父目录至根,每层先查目录本身,再查直属
.migration/,不遍历其他子目录;有分隔符时只定位显式目录,相对目录基于 source。按输入原名定位<name>[-<edition>](migrate)@<version>_<RID>配套文件;只有两文件都缺失才继续查下一位置,半套或元数据/RID 错误立即失败,不能跨目录拼配或选择其他身份。全部缺失报告预期文件名和已检查目录。--migration 空值或全空白视为未指定。升迁输入解析和 Native AOT 发布由独立 migrator 工具负责。 - packager 不引用独立 migrator 项目或共享升迁协议,不分发原生产物;通用变量解析源码由 tools/.shared 链接到三个工具。两个输入文件原样加入安装根 .migration/,脚本 0755、归档 0600,载荷冲突失败。
- 安装调用外部脚本 apply,systemd 门禁调用 check,均明确传入 /var/lib/<包名>/packager。升迁失败阻止启动;无 daemon 也执行,DESTDIR 不执行钩子;卸载保留状态。
- 三格式的安装/升级/覆盖/卸载阶段不同,保留 Debian configure 和 RPM 剩余实例语义。根路径别名、符号链接与安装目录必须规范化,避免越界目标。
- Zongsoft.Core Searcher 处理本地通配与链接,按逻辑来源定位相对路径。变量依次加载默认值、环境、从根到最终 source 的
.env、显式选项;共享 Utility 用 Profile.Load 加载,多级段落与条目以下划线拼名。先解析并固定 source,再加载.env,不反向推导源目录;身份仍仅来自显式选项与源版本文件。TextSource 的 file:/text: 只解释一次。 - --listen 生成宿主 --urls,完整地址保留;已有服务 ExecStart 不改写。仅 Generated 宿主将有效监听地址写入包头:tar PAX Listen、Debian control Listen、RPM 应用字符串标签 1000001;未使用及空值省略,不增加安装文件。--dependencies 统一使用 name[:range]:NuGet 风格区间及 [v) 下限简写,区间外逗号/分号为 AND、| 为 OR;Dependency 保留原生版本端点。Debian 展开为关系组,RPM 双边范围用 with、替代用 or,并声明相应 rpmlib 能力。其他关系选项保留原生语法。
- 主页选项及变量为 homepage;manufacturer 未定义、null 或空字符串默认 Zongsoft,纯空白不触发默认值。厂家分别写入 tar PAX 全局 Manufacturer、Debian 自定义 Manufacturer、RPM VENDOR(1011),与 maintainer 独立;maintainer 选项默认 Zongsoft。
- 安装包来源元数据使用 Packager:程序集名@版本,独立于应用 .version。大载荷使用 DeleteOnClose 临时流和增量摘要,不分配完整包体。
验证与边界
dotnet test test/Zongsoft.Tools.Packager.Tests.csproj -f net10.0;dotnet build Zongsoft.Tools.Packager.slnx -p:ZongsoftCodeStyleStrict=true 覆盖所有 TFM,另执行 IDE0049 verify。
Cake restore/build/test 使用同一 edition,默认 test;build 只构建本工具并制 NuGet 包,不启动容器。pack 会推送 NuGet,未获明确授权不能运行。Debug 引用本地 Zongsoft.Core,Release 使用 NuGet,测试不能混用。
文件系统测试使用临时目录,包内容检查不等于安装;不得擅自执行安装、systemd、sudo 或真实数据库/存储操作。交接集成通过产物或独立进程,不跨工具引用协议类型。公开行为修改同步双语 README、实现说明、资源和测试。
