milestone 8: web server, rest api, sse, auth, metrics and static assets
This commit is contained in:
+48
-10
@@ -57,8 +57,12 @@ pub const CheckArgs = struct { paths: Paths = .{}, config_explicit: bool = false
|
||||
pub const ExportArgs = struct { paths: Paths = .{}, out: ?[]const u8 = null };
|
||||
pub const ImportArgs = struct { paths: Paths = .{}, file: []const u8, force: bool = false };
|
||||
|
||||
/// `web_dev` is milestone-8 ruling 24's `--web-dev <dir>`: serve the web
|
||||
/// interface from that directory instead of the embedded assets.
|
||||
pub const RunArgs = struct { paths: Paths = .{}, web_dev: ?[]const u8 = null };
|
||||
|
||||
pub const Command = union(enum) {
|
||||
run: Paths,
|
||||
run: RunArgs,
|
||||
check: CheckArgs,
|
||||
export_: ExportArgs,
|
||||
import_: ImportArgs,
|
||||
@@ -89,7 +93,7 @@ pub fn parseArgs(argv: []const []const u8) ParseError!Command {
|
||||
if (rest.len != 0) return error.TooManyArguments;
|
||||
return .help;
|
||||
}
|
||||
if (eql(command, "run")) return .{ .run = (try parseCheckArgs(rest)).paths };
|
||||
if (eql(command, "run")) return .{ .run = try parseRunArgs(rest) };
|
||||
if (eql(command, "check")) return .{ .check = try parseCheckArgs(rest) };
|
||||
if (eql(command, "export")) return .{ .export_ = try parseExportArgs(rest) };
|
||||
if (eql(command, "import")) return .{ .import_ = try parseImportArgs(rest) };
|
||||
@@ -124,8 +128,24 @@ fn flagValue(flag: Flag, argv: []const []const u8, i: *usize) ParseError![]const
|
||||
return argv[i.*];
|
||||
}
|
||||
|
||||
/// `run` and `check` take the same two flags. `run` throws away
|
||||
/// `config_explicit`; bootstrap reads the path either way.
|
||||
/// `run` takes `check`'s two flags plus `--web-dev`, which only a process that
|
||||
/// serves has any use for; `check` deliberately rejects it.
|
||||
fn parseRunArgs(argv: []const []const u8) ParseError!RunArgs {
|
||||
var args: RunArgs = .{};
|
||||
var i: usize = 0;
|
||||
while (i < argv.len) : (i += 1) {
|
||||
const flag = splitFlag(argv[i]) orelse return error.TooManyArguments;
|
||||
if (eql(flag.name, "data-dir")) {
|
||||
args.paths.data_dir = try flagValue(flag, argv, &i);
|
||||
} else if (eql(flag.name, "config")) {
|
||||
args.paths.config = try flagValue(flag, argv, &i);
|
||||
} else if (eql(flag.name, "web-dev")) {
|
||||
args.web_dev = try flagValue(flag, argv, &i);
|
||||
} else return error.UnknownFlag;
|
||||
}
|
||||
return args;
|
||||
}
|
||||
|
||||
fn parseCheckArgs(argv: []const []const u8) ParseError!CheckArgs {
|
||||
var args: CheckArgs = .{};
|
||||
var i: usize = 0;
|
||||
@@ -324,6 +344,8 @@ const usage_text =
|
||||
\\ --config FILE configuration file (default /etc/nxdns/config.zon)
|
||||
\\ --out FILE write the export to FILE instead of stdout
|
||||
\\ --force let import replace a database that already has content
|
||||
\\ --web-dev DIR run only: serve the web interface from DIR instead of
|
||||
\\ the embedded assets
|
||||
\\
|
||||
;
|
||||
|
||||
@@ -375,8 +397,8 @@ pub fn runVersion(r: Runner) u8 {
|
||||
/// Serves DNS until SIGINT or SIGTERM. The whole of it lives in `app.zig`,
|
||||
/// which is where the composition root belongs; this stays the entry point so
|
||||
/// that `main` dispatches every command the same way.
|
||||
pub fn runRun(r: Runner, paths: Paths) u8 {
|
||||
return app.run(r, paths);
|
||||
pub fn runRun(r: Runner, args: RunArgs) u8 {
|
||||
return app.run(r, args);
|
||||
}
|
||||
|
||||
pub fn runExport(r: Runner, args: ExportArgs) u8 {
|
||||
@@ -742,14 +764,30 @@ const testing = std.testing;
|
||||
|
||||
test "parseArgs accepts run with no flags" {
|
||||
const command = try parseArgs(&.{"run"});
|
||||
try testing.expectEqualStrings("/var/lib/nxdns", command.run.data_dir);
|
||||
try testing.expectEqualStrings("/etc/nxdns/config.zon", command.run.config);
|
||||
try testing.expectEqualStrings("/var/lib/nxdns", command.run.paths.data_dir);
|
||||
try testing.expectEqualStrings("/etc/nxdns/config.zon", command.run.paths.config);
|
||||
try testing.expectEqual(@as(?[]const u8, null), command.run.web_dev);
|
||||
}
|
||||
|
||||
test "parseArgs accepts run with --data-dir and --config" {
|
||||
const command = try parseArgs(&.{ "run", "--data-dir", "/srv/nx", "--config", "/tmp/c.zon" });
|
||||
try testing.expectEqualStrings("/srv/nx", command.run.data_dir);
|
||||
try testing.expectEqualStrings("/tmp/c.zon", command.run.config);
|
||||
try testing.expectEqualStrings("/srv/nx", command.run.paths.data_dir);
|
||||
try testing.expectEqualStrings("/tmp/c.zon", command.run.paths.config);
|
||||
}
|
||||
|
||||
test "parseArgs accepts run with --web-dev in both spellings" {
|
||||
const attached = try parseArgs(&.{ "run", "--web-dev=web/dist" });
|
||||
try testing.expectEqualStrings("web/dist", attached.run.web_dev.?);
|
||||
|
||||
const separate = try parseArgs(&.{ "run", "--web-dev", "web/dist" });
|
||||
try testing.expectEqualStrings("web/dist", separate.run.web_dev.?);
|
||||
}
|
||||
|
||||
test "parseArgs rejects --web-dev without a value and outside run" {
|
||||
try testing.expectError(error.MissingValue, parseArgs(&.{ "run", "--web-dev" }));
|
||||
try testing.expectError(error.MissingValue, parseArgs(&.{ "run", "--web-dev=" }));
|
||||
try testing.expectError(error.UnknownFlag, parseArgs(&.{ "check", "--web-dev", "web/dist" }));
|
||||
try testing.expectError(error.UnknownFlag, parseArgs(&.{ "export", "--web-dev", "web/dist" }));
|
||||
}
|
||||
|
||||
test "parseArgs accepts --data-dir with and without an equals sign" {
|
||||
|
||||
Reference in New Issue
Block a user