internal/runner_cli の設計
設計目標
適合性ランナーは tools/*.py から並列のシャードで何千回も呼び出され、その出力はスクリプトによって解析されます。そのため、オプションの構文、終了コード、診断の形式、JSON の形について一致している必要があり、どのマシンでも同じ入力に対して同じ出力を生成しなければなりません。internal/runner_cli はこれらの規約を実装する唯一の場所であり、cli/ の各ランナーは独自のオプションを追加してフロントエンドを呼び出すだけです。
数学的背景
ここにはほとんど数学はありません。重要な性質は決定性の 1 つだけです。実行は(引数ベクトル、ファイル内容)の関数です。ファイルリストはソートされ、ドキュメントはその順序で解析され、ケースはその順序で番号付けされ、シャード は を満たす序数 を選択します(internal/conformance の設計)。したがって、実行されるケースの集合と出力中のすべてのカウンタは、ディレクトリの列挙順序や並列に動くプロセス数に依存しません。
設計上の判断
完全な引数ベクトル
すべてのランナーはプログラム名を含む引数ベクトル全体を受け取り、parse_common_options は要素 0 をスキップします。cli/ のディスパッチャはプログラム名と、自身が消費しなかった引数を転送するため、ランナーはディスパッチャ経由で到達した場合でも、テストから直接呼び出された場合でも同じように動作します。
共通オプションを先に、残りは順序どおりに
parse_common_options は --json とシャードのオプションのみを消費し、それ以外はすべて順序を保って残します。ランナー固有のオプションとパスは、その後 remaining() から解析されます。これにより、共通の構文をランナー間で同一に保ちつつ、各ランナーが未知のオプションを拒否できます。
検証済みのシャード
シャードのオプションは ShardSpec::try_new で検証されるため、不正な組はフロントエンドでの中断(abort)ではなく、使用法のエラー(終了コード 2)になります。
ソート済みで非再帰的なファイル収集
collect_files は展開したリストをソートし、サブディレクトリには降りません。ソートによってケースの序数、ひいてはシャードが再現可能になります。再帰しないことで、選択されるコーパスが明示的に保たれます。Python のツール群は各コーパスフェーズの正確なファイルを渡します。
小さな JSON 層
ヘルパーはコアの Json 型をラップします。json_int は正確な 10 進表現を格納するのでカウントは整数として出力され、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 未満の行や列を出力しません。
却下した代替案
- 汎用の引数解析ライブラリ。 ランナーに必要なオプションは 4 つです。依存を追加すると、削減できる分よりも多くの表面積が増えてしまいます。
- 再帰的なディレクトリ走査。 サブディレクトリに置かれた無関係なファイルを取り込んでしまい、選択されるコーパスが暗黙的になります。
- ツール向けの自由形式のテキスト出力。 スクリプトが散文を解析しなければならなくなります。JSON オブジェクトが安定したインターフェースであり、テキスト出力は人間向けです。
境界
- コーパスの解析や数値的な意味論は扱いません。それらはフロントエンドが担います。
- プロセスを終了しません。ランナーは終了コードを返し、
exitを呼び出すのはcliだけです。 - 再帰的なファイル検索、グロブ展開、エンコーディングの検出は行いません。
- 内部用です。
Luna-Flow/floatingの外部からはインポートできず、安定性の約束もありません。