╭ changed ──────╮ │src/command.zig│ ╰───────────────╯ ╭─────────────────────────╮ │ 8 receive_pack, │ │ 9 http_backend, │ │10 serve, │ │11 + ssh_helper, │ │12 }; │ │13 │ │14 const Help = struct {│ ╰─────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │49 .serve => .{ │ │50 .name = "serve", │ │51 .descrip = │ │51 - \\a long-running HTTP server forwarding receive-pack and upload-pack. │ │52 + \\a long-running server forwarding receive-pack and upload-pack. │ │53 + , │ │54 + .example = │ │55 + \\haxy serve --http-listen 127.0.0.1:8080 --ssh-listen 127.0.0.1:8081 --project-root /srv/git│ │56 + , │ │57 + }, │ │58 + .ssh_helper => .{ │ │59 + .name = "ssh-helper", │ │60 + .descrip = │ │61 + \\a helper run by sshd that forwards Git SSH service requests to serve. │ │62 , │ │63 .example = │ │54 - \\haxy serve --http-listen 127.0.0.1:8080 --project-root /srv/git │ │64 + \\haxy ssh-helper --ssh-connect 127.0.0.1:8081 --service upload-pack <directory> │ │65 , │ │66 }, │ │67 }; │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────╮ │125 // must be included here │ │126 const value_flags = std.StaticStringMap(void).initComptime(.{ │ │127 .{"--http-listen"}, │ │128 + .{"--ssh-listen"}, │ │129 + .{"--ssh-connect"}, │ │130 .{"--project-root"}, │ │131 + .{"--service"}, │ │132 }); │ │133 │ │134 pub fn init(allocator: std.mem.Allocator, args: []const []const u8) !CommandArgs {│ ╰───────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────╮ │231 http_backend, │ │232 serve: struct { │ │233 http_listen: []const u8, │ │234 + ssh_listen: ?[]const u8, │ │235 project_root: []const u8, │ │236 + }, │ │237 + ssh_helper: struct { │ │238 + ssh_connect: []const u8, │ │239 + service: ?[]const u8, │ │240 + dir: ?[]const u8, │ │241 }, │ │242 │ │243 pub fn initMaybe(cmd_args: *CommandArgs) !?Command(repo_kind, hash_kind) {│ ╰───────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │276 │ │277 return .{ .serve = .{ │ │278 .http_listen = (cmd_args.get("--http-listen") orelse null) orelse "127.0.0.1:8080", │ │279 + .ssh_listen = (cmd_args.get("--ssh-listen") orelse null), │ │280 .project_root = (cmd_args.get("--project-root") orelse null) orelse ".", │ │281 + } }; │ │282 + }, │ │283 + .ssh_helper => { │ │284 + if (cmd_args.positional_args.len > 1) return null; │ │285 + │ │286 + return .{ .ssh_helper = .{ │ │287 + .ssh_connect = (cmd_args.get("--ssh-connect") orelse null) orelse "127.0.0.1:8081", │ │288 + .service = (cmd_args.get("--service") orelse null), │ │289 + .dir = if (cmd_args.positional_args.len == 1) cmd_args.positional_args[0] else null,│ │290 } }; │ │291 }, │ │292 } │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ───╮ │src/main.zig│ ╰────────────╯ ╭───────────────────────────────────────────────────╮ │ 4 const rp = xit.repo; │ │ 5 const cmd = @import("./command.zig"); │ │ 6 const serve = @import("./serve.zig"); │ │ 7 +const ssh_helper = @import("./ssh_helper.zig");│ │ 8 │ │ 9 pub const RunOpts = struct { │ │10 out: *std.Io.Writer, │ ╰───────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────╮ │78 if (cli_cmd == .serve) { │ │79 try serve.run(repo_kind, any_repo_opts, io, allocator, cwd_path, .{│ │80 .http_listen = cli_cmd.serve.http_listen, │ │81 + .ssh_listen = cli_cmd.serve.ssh_listen, │ │82 .project_root = cli_cmd.serve.project_root, │ │83 }, run_opts.err); │ │84 + return; │ │85 + } │ │86 + if (cli_cmd == .ssh_helper) { │ │87 + try ssh_helper.run(io, allocator, .{ │ │88 + .ssh_connect = cli_cmd.ssh_helper.ssh_connect, │ │89 + .service = cli_cmd.ssh_helper.service, │ │90 + .dir = cli_cmd.ssh_helper.dir, │ │91 + }, run_opts.environ_map); │ │92 return; │ │93 } │ │94 │ ╰───────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────╮ │103 return; │ │104 }, │ │105 .serve => unreachable, │ │106 + .ssh_helper => unreachable, │ │107 }; │ │108 defer allocator.free(work_path);│ │109 │ ╰─────────────────────────────────────────────────╯ ╭────────────────────────────────────────╮ │189 }); │ │190 }, │ │191 .serve => unreachable, │ │192 + .ssh_helper => unreachable,│ │193 } │ │194 } │ │195 │ ╰────────────────────────────────────────╯ ╭ changed ────╮ │src/serve.zig│ ╰─────────────╯ ╭─────────────────────────────────╮ │ 5 │ │ 6 pub const Options = struct { │ │ 7 http_listen: []const u8, │ │ 8 + ssh_listen: ?[]const u8, │ │ 9 project_root: []const u8,│ │10 }; │ │11 │ ╰─────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯