internal/runner_cli 设计
设计目标
符合性运行器由 tools/*.py 以并行分片的方式调用成千上万次,其输出由脚本解析。因此它们必须在选项语法、退出码、诊断格式和 JSON 结构上保持一致,并且在任何机器上对相同输入产生相同输出。internal/runner_cli 是实现这些约定的唯一位置,因此 cli/ 中的每个运行器只需添加自己的选项并调用一个前端。
数学背景
这里几乎没有数学;唯一重要的性质是确定性。一次运行是(参数向量,文件内容)的函数:文件列表经过排序,文档按此顺序解析,用例按此顺序编号,分片 选取满足 的序号 (internal/conformance 设计)。因此,被执行的用例集合以及输出中的每个计数器都与目录列举顺序和并行运行的进程数无关。
设计决策
完整的参数向量
每个运行器都接收完整的参数向量(包括程序名),parse_common_options 会跳过第 0 个元素。cli/ 中的分发器转发程序名以及它未消费的参数,因此无论运行器是经由分发器到达还是在测试中被直接调用,其行为都相同。
先处理公共选项,其余按原顺序保留
parse_common_options 只消费 --json 和分片选项,其余内容按原顺序保留。运行器特有的选项和路径随后从 remaining() 中解析。这使各运行器的公共语法保持一致,同时允许每个运行器拒绝它不认识的选项。
经过校验的分片
分片选项通过 ShardSpec::try_new 校验,因此无效的组合是用法错误(退出码 2),而不会在前端中导致中止。
排序的、非递归的文件收集
collect_files 会对展开后的列表排序,并且不会进入子目录。排序使用例序号以及分片可复现。不递归则使所选语料保持明确:Python 工具链会传入每个语料阶段的确切文件。
小型 JSON 层
这些辅助函数包装了核心的 Json 类型:json_int 存储精确的十进制表示,使计数打印为整数;json_object 保持插入顺序,使报告稳定且便于比较差异。
正确性 / 不变式
- 选项往返。 对于不含公共选项的参数向量,
remaining()等于arguments[1:]。 - 分片有效性。 成功的
parse_common_options总是返回shard_count() > 0且0 <= shard_index() < shard_count()。 - 确定的文件列表。
collect_files(paths, s)是有序的,且恰好包含paths中所列出的、以s结尾的现有文件,以及所列目录中以s结尾的直接条目。 - 诊断位置。
format_diagnostic_at绝不会打印小于 1 的行号或列号。
被否决的替代方案
- 通用参数解析库。 运行器只需要四个选项;引入依赖带来的接口面会多于它所省去的。
- 递归遍历目录。 这会把放在子目录中的无关文件也拉进来,并使所选语料变得隐式。
- 为工具提供自由格式的文本输出。 脚本将不得不解析散文;JSON 对象才是稳定的接口,文本输出是给人看的。
边界
- 不做语料解析,也不涉及数值语义:这些由前端负责。
- 不退出进程:运行器返回退出码;只有
cli调用exit。 - 不支持递归文件搜索、通配符展开或编码检测。
- 内部包:不能在
Luna-Flow/floating之外导入,不提供稳定性承诺。