cli 设计
设计目标
其他每个包要么是纯的,要么把副作用限制在测量循环内。cli 是文件、标准流、进程执行和退出码所在之处。它让这一适配层保持精简,并使唯一危险的操作——执行记录在产物中的命令——变得显式。
数学背景
命令行是一个从参数向量到请求的小型全函数,后接一个带副作用的解释器:
parse_args 从不失败:每个向量都映射到一个请求,错误记录在某个字段中。这使解析器在每个目标上都可测试,并把“请求了什么”与“发生了什么”分开。退出码把结果划分为成功()、运行时失败(:IO、无效数据、重放失败)和用法错误(),这样脚本就能区分输入有误与调用有误。
设计决策
纯辅助函数,native 副作用
问题。 进程执行和异步标准流只存在于 native 目标上。选择。 解析、帮助文本、JSONL 重放信息提取和报告渲染都是 cli.mbt 中的普通函数;native 的 main.mbt 是异步的,使用 moonbitlang/async 处理 stdin、stdout 和进程;其他目标使用 main_unimplemented.mbt,它支持文件到文件的 report 并拒绝 replay。理由。 同一个包可以在每个目标上构建,逻辑也无需启动任何进程即可测试。
受保护的重放
问题。 重放产物包含一条命令行;从某个 issue 中找到的文件里盲目执行它会运行任意代码。选择。 replay 要求输入文件(不接受 stdin),用 --dry-run 打印命令,只有带 --yes 时才执行,强制使用记录的超时,并在退出码非零时失败。理由。 安全的默认行为是先查看;执行是显式的第二步。
只读取所需内容
replay_spec_from_jsonl 在检查第一个 validation_failure 之前每一行的版本后,停在该事件处,并只读取三个重放字段。包含大量事件和一个失败的流可以正常处理,而来自未知版本的产物会在任何东西运行之前就被拒绝。
可移植的报告
report 读取全部输入,以目标标签 native 构建文档,并写出一个 HTML 文件。输入或输出使用 - 时会连接到管道,因此它能与其他工具组合。
正确性与不变量
parse_args是全函数,且不接触环境。replay没有--yes时从不执行,在非 native 目标上也从不执行。- 用法错误以
2退出;运行时失败以1退出。 - 解析事件失败时,
report不写出任何内容。
被否决的方案
- 标志解析库。 两个命令和四个标志不足以引入一个依赖。
- 默认执行重放。 对来自别处的产物不安全。
- 把 CLI 逻辑嵌入
report。 会把文件 IO 带入一个纯包。
边界
- 没有
run命令:基准测试是 MoonBit 代码,通过对你自己的包执行moon test或moon run来运行。 --open使用 macOS 的open命令。replay只读取文件,只执行第一个失败,并把命令直接传给进程 API(不经过 shell)。- 进度行打印的是一个以微秒计、却标注为
ms的值。 - 版本字符串在源码中固定。