pub const Config = @import("Config.zig"); pub const Installation = @import("Installation.zig"); pub const Installations = Installation.Installations; pub const SubCommand = @import("subcommand.zig").SubCommand; pub const help = SubCommand(Help); pub const install = SubCommand(@import("install.zig")); pub const list = SubCommand(@import("list.zig")); pub const remove = SubCommand(@import("remove.zig")); pub const @"switch" = SubCommand(@import("switch.zig")); pub const update = SubCommand(@import("update.zig")); pub const version = SubCommand(Version); const std = @import("std"); const zelda = @import("zelda"); const zup_config = @import("zup-config"); const ArgIterator = std.process.ArgIterator; const ComptimeStringMap = std.ComptimeStringMap; const GPA = std.heap.GeneralPurposeAllocator(.{}); const Tuple = std.meta.Tuple; pub fn main() !void { var gpa = GPA{}; const allocator = gpa.allocator(); defer _ = gpa.deinit(); // TODO: Make an issue in zelda mentioning this defer zelda.client.global_connection_cache.deinit(); var config = try Config.init(allocator); defer config.deinit(); var args = try std.process.argsWithAllocator(allocator); defer args.deinit(); _ = args.skip(); const cmd = args.next() orelse { return Help.mainHelp(); }; return dispatch(cmd, "main", unknownCmd, .{ cmd, config, &args }); } pub fn printVersion() !void { return std.io.getStdErr().writer().print("{}\n", .{zup_config.version}); } const Command = enum { help, install, list, remove, @"switch", update, version, }; const CommandMap = blk: { const Pair = Tuple(&.{ []const u8, Command }); const commands = @typeInfo(Command).Enum.fields; var map_data: [commands.len + 2]Pair = undefined; map_data[0] = .{ "--help", .help }; map_data[1] = .{ "--version", .version }; var idx: usize = 2; inline for (commands) |command| { map_data[idx] = .{ command.name, @intToEnum(Command, command.value) }; idx += 1; } break :blk ComptimeStringMap(Command, map_data); }; fn dispatch( cmd: []const u8, comptime fn_name: []const u8, comptime default_fn: anytype, args: anytype, ) !void { // TODO: This can still be improved, currently we're looping through all possible values, it could be somehow made // into a switch. const cmd_enum = CommandMap.get(cmd) orelse return @call(.{}, default_fn, args); const commands = @typeInfo(Command).Enum.fields; inline for (commands) |command| { if (@enumToInt(cmd_enum) == command.value) { // TODO: zig-bug it cries about modifying a constant if // I just write `return @call(.{}, fun, args);` const fun = @field(@field(@This(), command.name), fn_name); return call(fun, args); } } unreachable; } inline fn call(fun: anytype, args: anytype) !void { return @call(.{}, fun, args); } fn unknownCmd(cmd: []const u8, _: Config, _: *ArgIterator) !void { std.log.err("Unknown subcommand: {s}", .{cmd}); return error.ArgError; } const Help = struct { pub const params = ""; pub const description = "Displays help for the specified ."; pub const min_args = 0; pub const max_args = 1; pub fn main(comptime Result: type, _: Config, res: Result) !void { if (res.positionals.len == 0) { return mainHelp(); } const cmd = res.positionals[0]; return dispatch(cmd, "help", unknownHelp, .{cmd}); } pub fn mainHelp() !void { const writer = std.io.getStdErr().writer(); try writer.writeAll( \\USAGE: zup \\ \\These are the common Zup commands: \\ \\ install Install a Zig version \\ help See the help for various topics \\ list List Zig versions \\ remove Remove an installed Zig version \\ switch Switch between installed Zig versions \\ update Update installed Zig versions \\ version Print the version of Zup \\ \\You can find out more about a command by running `zup help `. \\ ); } fn unknownHelp(cmd: []const u8) !void { std.log.err("Unknown subcommand: {s}", .{cmd}); try mainHelp(); return error.ArgError; } }; const Version = struct { pub const params = ""; pub const description = "Print the version of Zup and exit."; pub const min_args = 0; pub const max_args = 0; pub fn main(comptime Result: type, _: Config, _: Result) !void { return printVersion(); } }; test "basic test" { try std.testing.expectEqual(10, 3 + 7); }