const std = @import("std"); const shlex = @import("shlex"); const describe = @import("describe.zig"); const git = @import("git.zig"); pub fn main(init: std.process.Init) !void { const allocator = init.gpa; const io = init.io; const cmd = init.environ_map.get("SSH_ORIGINAL_COMMAND") orelse return launchTui(io, init.environ_map); const tokens = shlex.split(allocator, cmd, false, true) catch |err| std.process.fatal("failed to parse SSH_ORIGINAL_COMMAND: {}", .{err}); defer { for (tokens) |token| allocator.free(token); allocator.free(tokens); } if (tokens.len == 0) return launchTui(io, init.environ_map); if (std.mem.eql(u8, tokens[0], "describe")) { return describe.run(allocator, io, init.environ_map, tokens[1..]); } const service = std.meta.stringToEnum(git.Service, tokens[0]) orelse std.process.fatal("unknown command: {s}", .{tokens[0]}); if (tokens.len != 2) std.process.fatal("invalid git command: {s}", .{cmd}); return git.serve(allocator, io, init.environ_map, service, tokens[1]); } fn launchTui(io: std.Io, environ: *const std.process.Environ.Map) !void { const tui = environ.get("SORCERY_SSH_TUI") orelse "sorcery-ssh-tui"; const err = std.process.replace(io, .{ .argv = &.{tui} }); return switch (err) { error.FileNotFound => printWelcome(io, environ), else => err, }; } fn printWelcome(io: std.Io, environ: *const std.process.Environ.Map) !void { var buffer: [1024]u8 = undefined; var stdout = std.Io.File.stdout().writer(io, &buffer); // the clone URL is the only address we know of; the instance name is for humans var host_buffer: [std.Io.net.HostName.max_len]u8 = undefined; const server = server: { const base = environ.get("SORCERY_CLONE_URL_BASE") orelse break :server ""; const uri = std.Uri.parse(base) catch break :server ""; const host = uri.getHost(&host_buffer) catch break :server ""; break :server host.bytes; }; try stdout.interface.print( \\welcome to sorcery-ssh on {[instance]s}! \\ \\usage: \\ ssh {[user]s}@{[server]s} describe USER/REPOSITORY \\ ssh {[user]s}@{[server]s} describe USER/REPOSITORY DESCRIPTION... \\ \\install sorcery-ssh-tui for interactive repository management. \\ , .{ .instance = environ.get("SORCERY_INSTANCE_NAME") orelse "this Sorcery instance", .user = environ.get("USER") orelse "", .server = server, }); try stdout.interface.flush(); } test { _ = describe; _ = git; }