diff --git a/.envrc b/.envrc index 193c1ea..6ecf723 100644 --- a/.envrc +++ b/.envrc @@ -1,4 +1,4 @@ use flake -ROOT="." +ROOT="/home/spencer/github.com/envr-zig" export PATH=".:${ROOT}/deps/zig:${ROOT}/deps/zls:$PATH" diff --git a/src/Config.zig b/src/Config.zig index a5efb64..1e36b1d 100644 --- a/src/Config.zig +++ b/src/Config.zig @@ -61,6 +61,7 @@ pub const ScanConfig = struct { }; /// Load the Config from the file at path +/// TODO: Use a concrete error set pub fn load( io: std.Io, gpa: std.mem.Allocator, diff --git a/src/main.zig b/src/main.zig index a4bc9eb..d1014d1 100644 --- a/src/main.zig +++ b/src/main.zig @@ -34,13 +34,6 @@ fn run( return envr.root.help(stdout_writer); }, - .version => { - var stdout_buffer: [1024]u8 = undefined; - var stdout_file_writer: Io.File.Writer = .init(.stdout(), io, &stdout_buffer); - const stdout_writer = &stdout_file_writer.interface; - - return version(stdout_writer); - }, .deps => { var stdout_buffer: [1024]u8 = undefined; var stdout_file_writer: Io.File.Writer = .init(.stdout(), io, &stdout_buffer); @@ -52,6 +45,22 @@ fn run( environ_map.get("PATH").?, ); }, + .init => { + var stdout_buffer: [1024]u8 = undefined; + var stdout_file_writer: Io.File.Writer = .init(.stdout(), io, &stdout_buffer); + const stdout_writer = &stdout_file_writer.interface; + + try envr.init_cmd( + io, + arena, + stdout_writer, + environ_map.get("HOME").?, + .{ + // TODO: Actually parse this + .force = false, + }, + ); + }, .list => { var stdout_buffer: [page_size]u8 = undefined; var stdout_file_writer: Io.File.Writer = .init(.stdout(), io, &stdout_buffer); @@ -66,6 +75,13 @@ fn run( "/tmp", ); }, + .version => { + var stdout_buffer: [1024]u8 = undefined; + var stdout_file_writer: Io.File.Writer = .init(.stdout(), io, &stdout_buffer); + const stdout_writer = &stdout_file_writer.interface; + + return version(stdout_writer); + }, .unknown => { return fallback_to_go(io, arena, args); }, diff --git a/src/root.zig b/src/root.zig index b2812e1..e8a2bcf 100644 --- a/src/root.zig +++ b/src/root.zig @@ -52,6 +52,19 @@ pub const root: Command = .new(.{ \\ The deps command reports which binaries are available and which are not." , }, + .{ + .name = "init", + .short = "Set up envr", + .long = + \\The init command generates your initial config and saves it to + \\~/.envr/config in JSON format. + \\ + \\During setup, you will be prompted to select one or more ssh keys with which to + \\encrypt your databse. **Make 100% sure** that you have **a remote copy** of this + \\key somewhere, otherwise your data could be lost forever. + , + //.flags = struct { force: bool } + }, .{ .name = "list", .short = "View your tracked files", @@ -120,6 +133,50 @@ const Features = packed struct { } }; +pub fn init_cmd( + io: Io, + arena: std.mem.Allocator, + out: *std.Io.Writer, + home: []const u8, + flags: struct { force: bool }, +) !void { + // TODO: Don't hardcode + const cfgPath = try std.fs.path.join(arena, &.{ home, ".envr", "config.json" }); + defer arena.free(cfgPath); + + if (flags.force or !file_exists(io, cfgPath)) { + // Setup + const keys = try select_ssh_keys(); + + const cfg: Config = .{ .keys = keys }; + // TODO: How to handle this error? + try cfg.save(io, cfgPath); + + try out.print( + "Config initialized with %d SSH key(s). You are ready to use envr.\n", + .{keys.len}, + ); + } else { + try out.writeAll( + \\You have already initialized envr. + \\Run again with the --force flag if you want to reinitialize. + \\ + , + ); + } +} + +/// Returns true if the file exists +fn file_exists(io: std.Io, path: []const u8) bool { + if (std.Io.Dir.cwd().access(io, path, .{ .read = true })) { + return true; + } else |_| { + return false; + } +} + +fn select_ssh_keys() ![]Config.SSHKeyPair {} + pub fn list( io: Io, arena: std.mem.Allocator,