╭─────────────╮ │scroll to top│ ╰─────────────╯ ╭ command.zig ──────────────────────────────────────────────────╮ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╰───────────────────────────────────────────────────────────────╯
╭────╮ ╭ clone ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╮ │http│ ssh │ │ ╰────╯ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╯
205 } 206 207 pub fn contains(self: *CommandArgs, arg: []const u8) bool { 208 _ = self.unused_args.orderedRemove(arg); 209 return self.map_args.contains(arg); 210 } 211 212 pub fn get(self: *CommandArgs, comptime arg: []const u8) ??[]const u8 { 213 comptime std.debug.assert(value_flags.has(arg)); // can only call `get` with flags included in `value_flags` 214 _ = self.unused_args.orderedRemove(arg); 215 return self.map_args.get(arg); 216 } 217 }; 218 219 /// parses the args into a format that can be directly used by a repo. 220 /// if any additional allocation needs to be done, the arena inside the cmd args will be used. 221 pub fn Command(comptime repo_kind: rp.RepoKind, comptime hash_kind: hash.HashKind) type { 222 return union(CommandKind) { 223 upload_pack: struct { 224 dir: []const u8, 225 options: xit.net_server_upload_pack.Options, 226 }, 227 receive_pack: struct { 228 dir: []const u8, 229 options: xit.net_server_receive_pack.Options, 230 }, 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) { 244 const command_kind = cmd_args.command_kind orelse return null; 245 switch (command_kind) { 246 .upload_pack => { 247 if (cmd_args.positional_args.len != 1) return null; 248 249 return .{ .upload_pack = .{ 250 .dir = cmd_args.positional_args[0], 251 .options = .{ 252 .advertise_refs = cmd_args.contains("--http-backend-info-refs"), 253 .is_stateless = cmd_args.contains("--stateless-rpc"), 254 }, 255 } }; 256 }, 257 .receive_pack => { 258 if (cmd_args.positional_args.len != 1) return null; 259 260 return .{ .receive_pack = .{ 261 .dir = cmd_args.positional_args[0], 262 .options = .{ 263 .skip_connectivity_check = cmd_args.contains("--skip-connectivity-check"), 264 .advertise_refs = cmd_args.contains("--http-backend-info-refs"), 265 .is_stateless = cmd_args.contains("--stateless-rpc"), 266 }, 267 } }; 268 }, 269 .http_backend => { 270 if (cmd_args.positional_args.len != 0) return null; 271 272 return .http_backend; 273 }, 274 .serve => { 275 if (cmd_args.positional_args.len != 0) return null; 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 } 293 } 294 }; 295 } 296 297 /// parses the given args into a command if valid, and determines how it should be run 298 /// (via the TUI or CLI). 299 pub fn CommandDispatch(comptime repo_kind: rp.RepoKind, comptime hash_kind: hash.HashKind) type { 300 return union(enum) { 301 invalid: union(enum) { 302 command: []const u8, 303 argument: struct { 304 command: ?CommandKind, 305 value: []const u8, 306 }, 307 }, 308 help: ?CommandKind, 309 cli: Command(repo_kind, hash_kind), 310 311 pub fn init(cmd_args: *CommandArgs) !CommandDispatch(repo_kind, hash_kind) { 312 const dispatch = try initIgnoreUnused(cmd_args); 313 if (cmd_args.unused_args.count() > 0) { 314 return .{ 315 .invalid = .{ 316 .argument = .{ 317 .command = switch (dispatch) { 318 .invalid => return dispatch, // if there was already an error, return it instead 319 .help => |cmd_kind_maybe| cmd_kind_maybe, 320 .cli => |command| command, 321 }, 322 .value = cmd_args.unused_args.keys()[0], 323 }, 324 }, 325 }; 326 } 327 return dispatch; 328 } 329 330 pub fn initIgnoreUnused(cmd_args: *CommandArgs) !CommandDispatch(repo_kind, hash_kind) { 331 const show_help = cmd_args.contains("--help"); 332 333 if (cmd_args.command_kind) |command_kind| { 334 if (show_help) { 335 return .{ .help = command_kind }; 336 } else if (try Command(repo_kind, hash_kind).initMaybe(cmd_args)) |cmd| { 337 return .{ .cli = cmd }; 338 } else { 339 return .{ .help = command_kind }; 340 } 341 } else if (cmd_args.command_name) |command_name| { 342 return .{ .invalid = .{ .command = command_name } }; 343 } else if (show_help) { 344 return .{ .help = null }; 345 } else { 346 return .{ .help = null }; 347 } 348 } 349 }; 350 } 351