//! The process shell: build the writers, collect `argv`, dispatch, return an //! exit code. Every command body lives in `cli.zig`, which takes its writers as //! parameters and is therefore testable without a process. const std = @import("std"); const cli = @import("cli.zig"); const logging = @import("platform/logging.zig"); /// Routes every `std.log` call through the sink. Before `logging.install` /// runs (and always under the test runner, which never installs), the sink /// passes through to the stderr default. pub const std_options: std.Options = .{ .logFn = logging.logFn }; // `src/tests.zig` imports this file, and this is how `cli.zig`'s tests reach // the same runner. `src/tests.zig` is the orchestrator's file, not this // session's. comptime { _ = @import("cli.zig"); } pub fn main(init: std.process.Init) u8 { // Both `File.Writer` values are self-referential and must not move, so they // stay in these `var` slots for the whole of `main`. var out_buffer: [4096]u8 = undefined; var err_buffer: [4096]u8 = undefined; var out = std.Io.File.stdout().writer(init.io, &out_buffer); var err = std.Io.File.stderr().writer(init.io, &err_buffer); const runner: cli.Runner = .{ .io = init.io, .gpa = init.gpa, .out = &out.interface, .err = &err.interface, }; var argv: std.ArrayList([]const u8) = .empty; defer argv.deinit(init.gpa); var args = init.minimal.args.iterate(); _ = args.skip(); while (args.next()) |arg| { argv.append(init.gpa, arg) catch return cli.exit_runtime; } const command = cli.parseArgs(argv.items) catch |e| return cli.runUsageError(runner, e); return switch (command) { .run => |paths| cli.runRun(runner, paths), // `true`: the probe leaves the machine, which is right for an operator // running `nxdns check` and wrong for a test. .check => |args_| cli.runCheck(runner, args_, true), .export_ => |args_| cli.runExport(runner, args_), .import_ => |args_| cli.runImport(runner, args_), .version => cli.runVersion(runner), .help => cli.runHelp(runner), }; }