为什么 PIG 保持扁平的 Cobra 命令层
一个顶层命令对应 cmd 中一个文件,具体行为进入 cli 与 internal 包的源码布局决策。
一个顶层命令对应 cmd 中一个文件,具体行为进入 cli 与 internal 包的源码布局决策。
决策日期: 2026-06-30
状态: 当前仍在执行的仓库架构。
当前参考:pig命令总览与源码仓库
范围: Go 源码归属与命令注册方式,而不是公开命令分类本身。
决策
cmd 包保持扁平。一个顶层命令对应一个顶层 Go 文件:pg.go、pb.go、pt.go、
pe.go、sty.go、do.go、repo.go 等。即使命令树很复杂,也继续留在这个入口文件中,
除非另有明确的布局决策。
文件可以很长,但只应包含 Cobra 关注点:名称、别名、注解、参数、实参校验、帮助、注册和选项映射。
具体工作放入 cli/*、internal/* 或其它实现包。
背景
早期命令增长产生了很多以子命令命名的小文件,也出现了多套确认、结构化输出、计划渲染和旧接口包装实现。 一些简单问题因此难以回答:顶层命令在哪里注册,某个别名由谁拥有,两段辅助代码是否在执行同一策略?
PIG 的命令族很大,但它们的公开语法是一个整体。把语法集中在一个位置更容易审查冲突, 实现包则继续按职责拆分。
考虑过的方案
- 在
cmd下为每个命令建目录。 普通命令不采用,因为一个公开语法会散落在多个包中,也容易把业务逻辑放到 Cobra 附近。 - 每个子命令一个文件。 注册、别名和继承参数将难以作为整体审阅。
- 把所有逻辑都放进
cmd。 操作逻辑依赖 Cobra 状态后,测试与复用都会变差。 - 抽象每一行重复代码。 猜测式框架会遮蔽命令语法;只有已经稳定、跨命令复用的胶水才应共享。
契约
cmd/root.go负责根命令、全局参数和顶层注册;cmd/utils.go负责共享的命令层辅助函数;- 每个普通顶层命令有一个对应的顶层源码文件,可以配一个同名测试文件;
- Cobra 层校验语法和映射选项,但不执行具体操作;
- 确认、注解、结构化输出与计划辅助逻辑只有一套实现;
- 实现包接收普通选项并返回类型化结果或错误,不依赖 Cobra 全局状态。
影响
部分命令文件会有意保持较长。这个取舍是可接受的,因为公开接口可以作为整体审阅,而实现仍然在下层拆分。 规则也减少了别名或参数移动时的文件震荡,为 Agent 提供确定的阅读起点。
边界是架构性的,不是外观性的:把业务逻辑藏在闭包里的短 cmd 文件仍然违规;
只包含声明式命令胶水的长文件则没有问题。
验证与演进
约定记录在 9eb70db,
随后由大型命令面整合提交 fb93602 落实。
Guard 测试检查别名冲突与命令注册,实现层行为则由各包测试验证。
当前状态
这仍是新工作的仓库规则。公开命令文档统一放在本站;源码布局约束继续靠近代码保留, 确保贡献者与编码 Agent 在修改前就能看到。