@@ -2,6 +2,7 @@ const std = @import("std");
22const builtin = @import ("builtin" );
33const sqlite = @import ("sqlite" );
44const ulid = @import ("ulid" );
5+ const clap = @import ("clap" );
56const IdMigration = @import ("id_migration.zig" );
67
78const 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, ¶ms, 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
21012117fn 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