Skip to content

Commit 3432168

Browse files
committed
awtfdb-manage: migrate to clap
1 parent 3127e90 commit 3432168

File tree

1 file changed

+90
-49
lines changed

1 file changed

+90
-49
lines changed

src/main.zig

Lines changed: 90 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ const std = @import("std");
22
const builtin = @import("builtin");
33
const sqlite = @import("sqlite");
44
const ulid = @import("ulid");
5+
const clap = @import("clap");
56
const IdMigration = @import("id_migration.zig");
67

78
const RowID = i64;
@@ -539,11 +540,14 @@ pub fn migrateCommand(args_it: *std.process.ArgIterator, ctx: *Context) !void {
539540
try std.fs.copyFileAbsolute(db_path, backup_db_path, .{});
540541
}
541542

543+
var migration_count: usize = 0;
544+
542545
{
543546
inline for (MIGRATIONS) |migration_decl| {
544547
const migration = Migration.fromTuple(migration_decl);
545548

546549
if (current_version < migration.version) {
550+
migration_count += 1;
547551

548552
// NOTE: i don't think transactions work for
549553
// ALTER TABLE, but i'm using it regardless because
@@ -591,6 +595,8 @@ pub fn migrateCommand(args_it: *std.process.ArgIterator, ctx: *Context) !void {
591595
}
592596
}
593597

598+
logger.info("ran {d} migrations", .{migration_count});
599+
594600
logger.info("running PRAGMA integrity_check...", .{});
595601
const val = (try ctx.db.one(i64, "PRAGMA integrity_check", .{}, .{})) orelse return error.PossiblyFailedIntegrityCheck;
596602
logger.info("integrity check returned {d}", .{val});
@@ -2026,8 +2032,6 @@ pub fn main() anyerror!void {
20262032
return error.ConfigFail;
20272033
}
20282034

2029-
var args_it = std.process.args();
2030-
_ = args_it.skip();
20312035
const stdout = std.io.getStdOut();
20322036

20332037
const Args = struct {
@@ -2038,31 +2042,49 @@ pub fn main() anyerror!void {
20382042
};
20392043

20402044
var given_args = Args{};
2041-
while (args_it.next()) |arg| {
2042-
if (std.mem.eql(u8, arg, "-h")) {
2043-
given_args.help = true;
2044-
} else if (std.mem.eql(u8, arg, "-v")) {
2045-
given_args.verbose = true;
2046-
} else if (std.mem.eql(u8, arg, "-V")) {
2047-
given_args.version = true;
2048-
} else {
2049-
if (std.mem.eql(u8, arg, "create")) {
2050-
given_args.action = .Create;
2051-
} else if (std.mem.eql(u8, arg, "migrate")) {
2052-
given_args.action = .Migrate;
2053-
} else if (std.mem.eql(u8, arg, "config")) {
2054-
given_args.action = .Config;
2055-
} else {
2056-
logger.err("unknown action {s}", .{arg});
2057-
return error.UnknownAction;
2058-
}
2059-
break;
2060-
}
2061-
}
2045+
2046+
const SubCommands = enum {
2047+
create,
2048+
migrate,
2049+
config,
2050+
};
2051+
2052+
const custom_parsers = .{
2053+
.command = clap.parsers.enumeration(SubCommands),
2054+
};
2055+
2056+
const params = comptime clap.parseParamsComptime(
2057+
\\-h, --help display this help and exit.
2058+
\\-V, --version print version and exit.
2059+
\\-v, --verbose enable debug logs.
2060+
\\<command> action (create, migrate, config)
2061+
);
2062+
2063+
//const MainArgs = clap.ResultEx(clap.Help, &params, custom_parsers);
2064+
2065+
var iter = try std.process.ArgIterator.initWithAllocator(allocator);
2066+
defer iter.deinit();
2067+
2068+
_ = iter.next(); // skip args[0] as that's exec name
2069+
2070+
// from https://github.com/Hejsil/zig-clap/blob/master/example/subcommands.zig
2071+
var diag = clap.Diagnostic{};
2072+
var res = clap.parseEx(clap.Help, &params, custom_parsers, &iter, .{
2073+
.diagnostic = &diag,
2074+
.allocator = allocator,
2075+
.terminating_positional = 0,
2076+
}) catch |err| {
2077+
diag.report(std.io.getStdErr().writer(), err) catch {};
2078+
return err;
2079+
};
2080+
defer res.deinit();
2081+
2082+
given_args.help = res.args.help != 0;
2083+
given_args.version = res.args.version != 0;
2084+
given_args.verbose = res.args.verbose != 0;
20622085

20632086
if (given_args.help) {
2064-
try stdout.writer().print(HELPTEXT, .{});
2065-
return;
2087+
return clap.help(std.io.getStdErr().writer(), clap.Help, &params, .{});
20662088
} else if (given_args.version) {
20672089
try stdout.writer().print("awtfdb-manage 0.0.1\n", .{});
20682090
return;
@@ -2072,45 +2094,64 @@ pub fn main() anyerror!void {
20722094
current_log_level = .debug;
20732095
}
20742096

2075-
if (given_args.action == null) {
2076-
logger.err("action argument is required", .{});
2077-
return error.MissingActionArgument;
2078-
}
2079-
2080-
switch (given_args.action.?) {
2081-
.Create => {
2082-
try createCommand(allocator, &args_it);
2083-
},
2084-
.Migrate => {
2097+
const command = res.positionals[0] orelse return error.MissingCommand;
2098+
switch (command) {
2099+
.create => try createCommand(allocator, &iter),
2100+
.migrate => {
20852101
var ctx = try loadDatabase(allocator, .{});
20862102
defer ctx.deinit();
20872103
errdefer ctx.logLastError();
20882104

2089-
try migrateCommand(&args_it, &ctx);
2105+
try migrateCommand(&iter, &ctx);
20902106
},
2091-
.Config => {
2107+
.config => {
20922108
var ctx = try loadDatabase(allocator, .{});
20932109
defer ctx.deinit();
20942110
errdefer ctx.logLastError();
20952111

2096-
try configCommand(&args_it, &ctx);
2112+
try configCommand(&iter, &ctx);
20972113
},
20982114
}
20992115
}
21002116

21012117
fn configCommand(args_it: *std.process.ArgIterator, ctx: *Context) !void {
2102-
const config_action_string = args_it.next() orelse "get";
2103-
const config_action = std.meta.stringToEnum(
2104-
enum { get, set },
2105-
config_action_string,
2106-
) orelse return error.InvalidConfigAction;
2107-
2108-
// get or set
2109-
// cconst action
2110-
const key = args_it.next() orelse return error.ExpectedKeyArgument;
2111-
const maybe_value = args_it.next();
2118+
const Modes = enum {
2119+
get,
2120+
set,
2121+
};
2122+
2123+
const custom_parsers = .{
2124+
.string = clap.parsers.string,
2125+
.u8 = clap.parsers.int(u8, 0),
2126+
.mode = clap.parsers.enumeration(Modes),
2127+
};
2128+
const params = comptime clap.parseParamsComptime(
2129+
\\-h, --help display this help and exit.
2130+
\\<mode> action (get or set)
2131+
\\<string> config key
2132+
\\<string>... config value
2133+
);
2134+
2135+
var diag = clap.Diagnostic{};
2136+
var res = clap.parseEx(clap.Help, &params, custom_parsers, args_it, .{
2137+
.diagnostic = &diag,
2138+
.allocator = ctx.allocator,
2139+
}) catch |err| {
2140+
diag.report(std.io.getStdErr().writer(), err) catch {};
2141+
return err;
2142+
};
2143+
defer res.deinit();
2144+
2145+
if (res.args.help != 0)
2146+
return clap.help(std.io.getStdErr().writer(), clap.Help, &params, .{});
2147+
2148+
const key = res.positionals[1] orelse return error.MissingKey;
2149+
const maybe_value = if (res.positionals[2].len > 1)
2150+
res.positionals[2][0]
2151+
else
2152+
null;
21122153
var stdout = std.io.getStdOut().writer();
2113-
switch (config_action) {
2154+
switch (res.positionals[0] orelse return error.MissingMode) {
21142155
.get => {
21152156
if (std.mem.eql(u8, key, "tag_name_regex")) {
21162157
try ctx.wantConfigFields(.{ .tag_name_regex = true });

0 commit comments

Comments
 (0)