forks/sorcery

git clone https://git.gae.moe/forks/sorcery

Charlotte Somsorcery-ssh: refactor3356bff

darwin-flake
2.6 KiB71 linesraw
1const std = @import("std");
2const shlex = @import("shlex");
3const describe = @import("describe.zig");
4const git = @import("git.zig");
5
6pub fn main(init: std.process.Init) !void {
7    const allocator = init.gpa;
8    const io = init.io;
9
10    const cmd = init.environ_map.get("SSH_ORIGINAL_COMMAND") orelse
11        return launchTui(io, init.environ_map);
12    const tokens = shlex.split(allocator, cmd, false, true) catch |err|
13        std.process.fatal("failed to parse SSH_ORIGINAL_COMMAND: {}", .{err});
14    defer {
15        for (tokens) |token| allocator.free(token);
16        allocator.free(tokens);
17    }
18
19    if (tokens.len == 0) return launchTui(io, init.environ_map);
20    if (std.mem.eql(u8, tokens[0], "describe")) {
21        return describe.run(allocator, io, init.environ_map, tokens[1..]);
22    }
23    const service = std.meta.stringToEnum(git.Service, tokens[0]) orelse
24        std.process.fatal("unknown command: {s}", .{tokens[0]});
25    if (tokens.len != 2) std.process.fatal("invalid git command: {s}", .{cmd});
26    return git.serve(allocator, io, init.environ_map, service, tokens[1]);
27}
28
29fn launchTui(io: std.Io, environ: *const std.process.Environ.Map) !void {
30    const tui = environ.get("SORCERY_SSH_TUI") orelse "sorcery-ssh-tui";
31    const err = std.process.replace(io, .{ .argv = &.{tui} });
32    return switch (err) {
33        error.FileNotFound => printWelcome(io, environ),
34        else => err,
35    };
36}
37
38fn printWelcome(io: std.Io, environ: *const std.process.Environ.Map) !void {
39    var buffer: [1024]u8 = undefined;
40    var stdout = std.Io.File.stdout().writer(io, &buffer);
41
42    // the clone URL is the only address we know of; the instance name is for humans
43    var host_buffer: [std.Io.net.HostName.max_len]u8 = undefined;
44    const server = server: {
45        const base = environ.get("SORCERY_CLONE_URL_BASE") orelse break :server "<server>";
46        const uri = std.Uri.parse(base) catch break :server "<server>";
47        const host = uri.getHost(&host_buffer) catch break :server "<server>";
48        break :server host.bytes;
49    };
50
51    try stdout.interface.print(
52        \\welcome to sorcery-ssh on {[instance]s}!
53        \\
54        \\usage:
55        \\  ssh {[user]s}@{[server]s} describe USER/REPOSITORY
56        \\  ssh {[user]s}@{[server]s} describe USER/REPOSITORY DESCRIPTION...
57        \\
58        \\install sorcery-ssh-tui for interactive repository management.
59        \\
60    , .{
61        .instance = environ.get("SORCERY_INSTANCE_NAME") orelse "this Sorcery instance",
62        .user = environ.get("USER") orelse "<user>",
63        .server = server,
64    });
65    try stdout.interface.flush();
66}
67
68test {
69    _ = describe;
70    _ = git;
71}