From d0b451fb78c6c72a250f9c4e64e90d4dfc512fde Mon Sep 17 00:00:00 2001 From: Luke Boswell Date: Wed, 17 Dec 2025 14:33:52 +1100 Subject: [PATCH] start re-organizing, leave a plan for future PR's --- .../{cli_error/context.zig => CliContext.zig} | 2 +- .../{cli_error/problem.zig => CliProblem.zig} | 0 src/cli/REORGANIZATION.md | 90 +++++++++++++++++++ src/cli/cli_args.zig | 70 +++++++-------- src/cli/cli_error.zig | 70 --------------- src/cli/libc_finder.zig | 2 +- src/cli/linker.zig | 2 +- src/cli/main.zig | 37 ++++---- src/cli/test_shared_memory_system.zig | 6 +- 9 files changed, 152 insertions(+), 127 deletions(-) rename src/cli/{cli_error/context.zig => CliContext.zig} (99%) rename src/cli/{cli_error/problem.zig => CliProblem.zig} (100%) create mode 100644 src/cli/REORGANIZATION.md delete mode 100644 src/cli/cli_error.zig diff --git a/src/cli/cli_error/context.zig b/src/cli/CliContext.zig similarity index 99% rename from src/cli/cli_error/context.zig rename to src/cli/CliContext.zig index 81e7a31964..fd27f53937 100644 --- a/src/cli/cli_error/context.zig +++ b/src/cli/CliContext.zig @@ -37,7 +37,7 @@ const std = @import("std"); const Allocator = std.mem.Allocator; const reporting = @import("reporting"); -const problem_mod = @import("problem.zig"); +const problem_mod = @import("CliProblem.zig"); const CliProblem = problem_mod.CliProblem; const Report = reporting.Report; diff --git a/src/cli/cli_error/problem.zig b/src/cli/CliProblem.zig similarity index 100% rename from src/cli/cli_error/problem.zig rename to src/cli/CliProblem.zig diff --git a/src/cli/REORGANIZATION.md b/src/cli/REORGANIZATION.md new file mode 100644 index 0000000000..760982ecc9 --- /dev/null +++ b/src/cli/REORGANIZATION.md @@ -0,0 +1,90 @@ +# CLI Directory Reorganization Plan + +This document outlines future work to reorganize the CLI module for better maintainability and idiomatic Zig conventions. + +## Design Principles + +1. **Flat structure** - No subdirectories, use descriptive filenames to group related code +2. **TitleCase.zig** for files defining a single primary type (e.g., `CliContext.zig`) +3. **snake_case.zig** for namespace/function modules (e.g., `cli_args.zig`) +4. **cli_roc_* prefix** for command implementation files to avoid conflicts +5. Direct imports rather than re-export hubs + +## Current State + +The CLI module is functional but `main.zig` is ~5,500 lines containing all command implementations. + +## Future Structure + +``` +src/cli/ +├── main.zig # Slim entrypoint (~300 lines): dispatch only +│ +├── CliContext.zig # Main CLI context type (DONE) +├── CliProblem.zig # Runtime error types (DONE) +├── cli_args.zig # Argument parsing (ArgProblem renamed, DONE) +│ +├── cli_roc_run.zig # rocRun command implementation +├── cli_roc_build.zig # rocBuild command implementation +├── cli_roc_check.zig # rocCheck command implementation +├── cli_roc_test.zig # rocTest command implementation +├── cli_roc_format.zig # rocFormat command implementation +├── cli_roc_docs.zig # rocDocs command implementation +├── cli_roc_bundle.zig # rocBundle command implementation +├── cli_roc_unbundle.zig # rocUnbundle command implementation +│ +├── platform_resolution.zig # Platform spec parsing, path resolution +├── platform_cache.zig # getRocCacheDir, URL platform resolution +├── platform_validation.zig # Platform header validation (existing) +│ +├── compile_serialization.zig # compileAndSerializeModulesForEmbedding +├── compile_shared_memory.zig # POSIX/Windows shared memory +│ +├── builder.zig # LLVM bitcode compilation (existing) +├── linker.zig # LLD wrapper (existing) +├── platform_host_shim.zig # LLVM shim generation (existing) +│ +├── target.zig # Target definitions (existing) +├── targets_validator.zig # Targets section validation (existing) +├── cross_compilation.zig # Cross-compilation validation (existing) +├── libc_finder.zig # Linux libc detection (existing) +│ +├── util_windows.zig # Windows console functions +├── util_posix.zig # POSIX shm wrappers +├── util_timing.zig # formatElapsedTime +│ +├── bench.zig # Benchmarking utility (existing) +├── targets/ # Pre-compiled shim libraries (keep) +└── test/ # Test files (keep) +``` + +## Migration Phases + +### Phase 1: Extract Utilities from main.zig +1. Create `util_windows.zig` - Windows console functions +2. Create `util_posix.zig` - POSIX shm wrappers +3. Create `util_timing.zig` - formatElapsedTime, printTimingBreakdown + +### Phase 2: Extract Compilation Infrastructure +1. Create `compile_shared_memory.zig` - SharedMemoryHandle, write functions +2. Create `compile_serialization.zig` - compileAndSerializeModulesForEmbedding + +### Phase 3: Extract Platform Resolution +1. Create `platform_resolution.zig` - extractPlatformSpecFromApp, resolvePlatformPaths +2. Create `platform_cache.zig` - getRocCacheDir, resolveUrlPlatform + +### Phase 4: Extract Commands (Ordered by Complexity) +1. `cli_roc_format.zig` (simplest) +2. `cli_roc_unbundle.zig` +3. `cli_roc_bundle.zig` +4. `cli_roc_test.zig` +5. `cli_roc_check.zig` +6. `cli_roc_docs.zig` +7. `cli_roc_build.zig` +8. `cli_roc_run.zig` (most complex) + +### Phase 5: Slim main.zig +Reduce main.zig to ~300 lines containing only: +- Entry point +- Command dispatch +- Top-level error handling diff --git a/src/cli/cli_args.zig b/src/cli/cli_args.zig index 44ac12541c..7f89ce3b80 100644 --- a/src/cli/cli_args.zig +++ b/src/cli/cli_args.zig @@ -21,7 +21,7 @@ pub const CliArgs = union(enum) { experimental_lsp: ExperimentalLspArgs, help: []const u8, licenses, - problem: CliProblem, + problem: ArgProblem, pub fn deinit(self: CliArgs, alloc: mem.Allocator) void { switch (self) { @@ -35,7 +35,7 @@ pub const CliArgs = union(enum) { }; /// Errors that can occur due to bad input while parsing the arguments -pub const CliProblem = union(enum) { +pub const ArgProblem = union(enum) { missing_flag_value: struct { flag: []const u8, }, @@ -241,7 +241,7 @@ fn parseCheck(args: []const []const u8) CliArgs { if (getFlagValue(arg)) |value| { main = value; } else { - return CliArgs{ .problem = CliProblem{ .missing_flag_value = .{ .flag = "--main" } } }; + return CliArgs{ .problem = ArgProblem{ .missing_flag_value = .{ .flag = "--main" } } }; } } else if (mem.eql(u8, arg, "--time")) { time = true; @@ -251,7 +251,7 @@ fn parseCheck(args: []const []const u8) CliArgs { verbose = true; } else { if (path != null) { - return CliArgs{ .problem = CliProblem{ .unexpected_argument = .{ .cmd = "check", .arg = arg } } }; + return CliArgs{ .problem = ArgProblem{ .unexpected_argument = .{ .cmd = "check", .arg = arg } } }; } path = arg; } @@ -298,35 +298,35 @@ fn parseBuild(args: []const []const u8) CliArgs { if (getFlagValue(arg)) |value| { target = value; } else { - return CliArgs{ .problem = CliProblem{ .missing_flag_value = .{ .flag = "--target" } } }; + return CliArgs{ .problem = ArgProblem{ .missing_flag_value = .{ .flag = "--target" } } }; } } else if (mem.startsWith(u8, arg, "--output")) { if (getFlagValue(arg)) |value| { output = value; } else { - return CliArgs{ .problem = CliProblem{ .missing_flag_value = .{ .flag = "--output" } } }; + return CliArgs{ .problem = ArgProblem{ .missing_flag_value = .{ .flag = "--output" } } }; } } else if (mem.startsWith(u8, arg, "--opt")) { if (getFlagValue(arg)) |value| { if (OptLevel.from_str(value)) |level| { opt = level; } else { - return CliArgs{ .problem = CliProblem{ .invalid_flag_value = .{ .flag = "--opt", .value = value, .valid_options = "speed,size,dev" } } }; + return CliArgs{ .problem = ArgProblem{ .invalid_flag_value = .{ .flag = "--opt", .value = value, .valid_options = "speed,size,dev" } } }; } } else { - return CliArgs{ .problem = CliProblem{ .missing_flag_value = .{ .flag = "--opt" } } }; + return CliArgs{ .problem = ArgProblem{ .missing_flag_value = .{ .flag = "--opt" } } }; } } else if (mem.startsWith(u8, arg, "--z-bench-tokenize")) { if (getFlagValue(arg)) |value| { z_bench_tokenize = value; } else { - return CliArgs{ .problem = CliProblem{ .missing_flag_value = .{ .flag = "--z-bench-tokenize" } } }; + return CliArgs{ .problem = ArgProblem{ .missing_flag_value = .{ .flag = "--z-bench-tokenize" } } }; } } else if (mem.startsWith(u8, arg, "--z-bench-parse")) { if (getFlagValue(arg)) |value| { z_bench_parse = value; } else { - return CliArgs{ .problem = CliProblem{ .missing_flag_value = .{ .flag = "--z-bench-parse" } } }; + return CliArgs{ .problem = ArgProblem{ .missing_flag_value = .{ .flag = "--z-bench-parse" } } }; } } else if (mem.eql(u8, arg, "--debug")) { debug = true; @@ -335,22 +335,22 @@ fn parseBuild(args: []const []const u8) CliArgs { } else if (mem.startsWith(u8, arg, "--wasm-memory")) { if (getFlagValue(arg)) |value| { wasm_memory = std.fmt.parseInt(usize, value, 10) catch { - return CliArgs{ .problem = CliProblem{ .invalid_flag_value = .{ .flag = "--wasm-memory", .value = value, .valid_options = "positive integer (bytes)" } } }; + return CliArgs{ .problem = ArgProblem{ .invalid_flag_value = .{ .flag = "--wasm-memory", .value = value, .valid_options = "positive integer (bytes)" } } }; }; } else { - return CliArgs{ .problem = CliProblem{ .missing_flag_value = .{ .flag = "--wasm-memory" } } }; + return CliArgs{ .problem = ArgProblem{ .missing_flag_value = .{ .flag = "--wasm-memory" } } }; } } else if (mem.startsWith(u8, arg, "--wasm-stack-size")) { if (getFlagValue(arg)) |value| { wasm_stack_size = std.fmt.parseInt(usize, value, 10) catch { - return CliArgs{ .problem = CliProblem{ .invalid_flag_value = .{ .flag = "--wasm-stack-size", .value = value, .valid_options = "positive integer (bytes)" } } }; + return CliArgs{ .problem = ArgProblem{ .invalid_flag_value = .{ .flag = "--wasm-stack-size", .value = value, .valid_options = "positive integer (bytes)" } } }; }; } else { - return CliArgs{ .problem = CliProblem{ .missing_flag_value = .{ .flag = "--wasm-stack-size" } } }; + return CliArgs{ .problem = ArgProblem{ .missing_flag_value = .{ .flag = "--wasm-stack-size" } } }; } } else { if (path != null) { - return CliArgs{ .problem = CliProblem{ .unexpected_argument = .{ .cmd = "build", .arg = arg } } }; + return CliArgs{ .problem = ArgProblem{ .unexpected_argument = .{ .cmd = "build", .arg = arg } } }; } path = arg; } @@ -385,27 +385,27 @@ fn parseBundle(alloc: mem.Allocator, args: []const []const u8) std.mem.Allocator } else if (mem.eql(u8, arg, "--output-dir")) { if (i + 1 >= args.len) { paths.deinit(); - return CliArgs{ .problem = CliProblem{ .missing_flag_value = .{ .flag = "--output-dir" } } }; + return CliArgs{ .problem = ArgProblem{ .missing_flag_value = .{ .flag = "--output-dir" } } }; } i += 1; output_dir = args[i]; } else if (mem.eql(u8, arg, "--compression")) { if (i + 1 >= args.len) { paths.deinit(); - return CliArgs{ .problem = CliProblem{ .missing_flag_value = .{ .flag = "--compression" } } }; + return CliArgs{ .problem = ArgProblem{ .missing_flag_value = .{ .flag = "--compression" } } }; } i += 1; compression_level = std.fmt.parseInt(i32, args[i], 10) catch { paths.deinit(); - return CliArgs{ .problem = CliProblem{ .invalid_flag_value = .{ .value = args[i], .flag = "--compression", .valid_options = "integer between 1 and 22" } } }; + return CliArgs{ .problem = ArgProblem{ .invalid_flag_value = .{ .value = args[i], .flag = "--compression", .valid_options = "integer between 1 and 22" } } }; }; if (compression_level < 1 or compression_level > 22) { paths.deinit(); - return CliArgs{ .problem = CliProblem{ .invalid_flag_value = .{ .value = args[i], .flag = "--compression", .valid_options = "integer between 1 and 22" } } }; + return CliArgs{ .problem = ArgProblem{ .invalid_flag_value = .{ .value = args[i], .flag = "--compression", .valid_options = "integer between 1 and 22" } } }; } } else if (mem.startsWith(u8, arg, "--")) { paths.deinit(); - return CliArgs{ .problem = CliProblem{ .unexpected_argument = .{ .cmd = "bundle", .arg = arg } } }; + return CliArgs{ .problem = ArgProblem{ .unexpected_argument = .{ .cmd = "bundle", .arg = arg } } }; } else { try paths.append(arg); } @@ -444,7 +444,7 @@ fn parseUnbundle(alloc: mem.Allocator, args: []const []const u8) !CliArgs { }; } else if (mem.startsWith(u8, arg, "-")) { paths.deinit(); - return CliArgs{ .problem = CliProblem{ .unexpected_argument = .{ .cmd = "unbundle", .arg = arg } } }; + return CliArgs{ .problem = ArgProblem{ .unexpected_argument = .{ .cmd = "unbundle", .arg = arg } } }; } else { try paths.append(arg); } @@ -552,23 +552,23 @@ fn parseTest(args: []const []const u8) CliArgs { if (getFlagValue(arg)) |value| { main = value; } else { - return CliArgs{ .problem = CliProblem{ .missing_flag_value = .{ .flag = "--main" } } }; + return CliArgs{ .problem = ArgProblem{ .missing_flag_value = .{ .flag = "--main" } } }; } } else if (mem.startsWith(u8, arg, "--opt")) { if (getFlagValue(arg)) |value| { if (OptLevel.from_str(value)) |level| { opt = level; } else { - return CliArgs{ .problem = CliProblem{ .invalid_flag_value = .{ .flag = "--opt", .value = value, .valid_options = "speed,size,dev" } } }; + return CliArgs{ .problem = ArgProblem{ .invalid_flag_value = .{ .flag = "--opt", .value = value, .valid_options = "speed,size,dev" } } }; } } else { - return CliArgs{ .problem = CliProblem{ .missing_flag_value = .{ .flag = "--opt" } } }; + return CliArgs{ .problem = ArgProblem{ .missing_flag_value = .{ .flag = "--opt" } } }; } } else if (mem.eql(u8, arg, "--verbose")) { verbose = true; } else { if (path != null) { - return CliArgs{ .problem = CliProblem{ .unexpected_argument = .{ .cmd = "test", .arg = arg } } }; + return CliArgs{ .problem = ArgProblem{ .unexpected_argument = .{ .cmd = "test", .arg = arg } } }; } path = arg; } @@ -589,7 +589,7 @@ fn parseRepl(args: []const []const u8) CliArgs { \\ }; } else { - return CliArgs{ .problem = CliProblem{ .unexpected_argument = .{ .cmd = "repl", .arg = arg } } }; + return CliArgs{ .problem = ArgProblem{ .unexpected_argument = .{ .cmd = "repl", .arg = arg } } }; } } return CliArgs.repl; @@ -608,7 +608,7 @@ fn parseVersion(args: []const []const u8) CliArgs { \\ }; } else { - return CliArgs{ .problem = CliProblem{ .unexpected_argument = .{ .cmd = "version", .arg = arg } } }; + return CliArgs{ .problem = ArgProblem{ .unexpected_argument = .{ .cmd = "version", .arg = arg } } }; } } return CliArgs.version; @@ -627,7 +627,7 @@ fn parseLicenses(args: []const []const u8) CliArgs { \\ }; } else { - return CliArgs{ .problem = CliProblem{ .unexpected_argument = .{ .cmd = "licenses", .arg = arg } } }; + return CliArgs{ .problem = ArgProblem{ .unexpected_argument = .{ .cmd = "licenses", .arg = arg } } }; } } return CliArgs.licenses; @@ -666,13 +666,13 @@ fn parseDocs(args: []const []const u8) CliArgs { if (getFlagValue(arg)) |value| { main = value; } else { - return CliArgs{ .problem = CliProblem{ .missing_flag_value = .{ .flag = "--main" } } }; + return CliArgs{ .problem = ArgProblem{ .missing_flag_value = .{ .flag = "--main" } } }; } } else if (mem.startsWith(u8, arg, "--output")) { if (getFlagValue(arg)) |value| { output = value; } else { - return CliArgs{ .problem = CliProblem{ .missing_flag_value = .{ .flag = "--output" } } }; + return CliArgs{ .problem = ArgProblem{ .missing_flag_value = .{ .flag = "--output" } } }; } } else if (mem.eql(u8, arg, "--serve")) { serve = true; @@ -684,7 +684,7 @@ fn parseDocs(args: []const []const u8) CliArgs { verbose = true; } else { if (path != null) { - return CliArgs{ .problem = CliProblem{ .unexpected_argument = .{ .cmd = "docs", .arg = arg } } }; + return CliArgs{ .problem = ArgProblem{ .unexpected_argument = .{ .cmd = "docs", .arg = arg } } }; } path = arg; } @@ -723,7 +723,7 @@ fn parseExperimentalLsp(args: []const []const u8) CliArgs { } else if (mem.eql(u8, arg, "--debug-server")) { debug_server = true; } else { - return CliArgs{ .problem = CliProblem{ .unexpected_argument = .{ .cmd = "experimental-lsp", .arg = arg } } }; + return CliArgs{ .problem = ArgProblem{ .unexpected_argument = .{ .cmd = "experimental-lsp", .arg = arg } } }; } } @@ -770,7 +770,7 @@ fn parseRun(alloc: mem.Allocator, args: []const []const u8) std.mem.Allocator.Er target = value; } else { app_args.deinit(); - return CliArgs{ .problem = CliProblem{ .missing_flag_value = .{ .flag = "--target" } } }; + return CliArgs{ .problem = ArgProblem{ .missing_flag_value = .{ .flag = "--target" } } }; } } else if (mem.startsWith(u8, arg, "--opt")) { if (getFlagValue(arg)) |value| { @@ -778,11 +778,11 @@ fn parseRun(alloc: mem.Allocator, args: []const []const u8) std.mem.Allocator.Er opt = level; } else { app_args.deinit(); - return CliArgs{ .problem = CliProblem{ .invalid_flag_value = .{ .flag = "--opt", .value = value, .valid_options = "speed,size,dev" } } }; + return CliArgs{ .problem = ArgProblem{ .invalid_flag_value = .{ .flag = "--opt", .value = value, .valid_options = "speed,size,dev" } } }; } } else { app_args.deinit(); - return CliArgs{ .problem = CliProblem{ .missing_flag_value = .{ .flag = "--opt" } } }; + return CliArgs{ .problem = ArgProblem{ .missing_flag_value = .{ .flag = "--opt" } } }; } } else if (mem.eql(u8, arg, "--no-cache")) { no_cache = true; diff --git a/src/cli/cli_error.zig b/src/cli/cli_error.zig deleted file mode 100644 index 39f1ca570d..0000000000 --- a/src/cli/cli_error.zig +++ /dev/null @@ -1,70 +0,0 @@ -//! CLI Context and Error Handling -//! -//! Provides the shared CLI context and structured error types for CLI operations. -//! -//! The key design principle is that `CliError` is the ONLY error type that -//! CLI functions should return. This ensures: -//! - Every error is properly reported (no silent failures) -//! - Consistent error formatting across all commands -//! - The type system enforces proper error handling -//! -//! This module exports: -//! - `CliContext`: Shared context with allocators, I/O, and error accumulation -//! - `Io`: I/O interface wrapping stdout/stderr with buffered writers -//! - `CliError`: The single error type for CLI operations -//! - `CliProblem`: Union type representing all CLI error conditions -//! - `FileContext`: Context enum for file operation errors -//! - `Command`: CLI command enum -//! -//! Usage: -//! ```zig -//! const cli = @import("cli_error.zig"); -//! -//! fn doSomething(ctx: *cli.CliContext, path: []const u8) cli.CliError!void { -//! const source = std.fs.cwd().readFileAlloc(ctx.gpa, path, ...) catch { -//! return ctx.fail(.{ .file_not_found = .{ .path = path } }); -//! }; -//! defer ctx.gpa.free(source); -//! // Use ctx.arena for temporary allocations... -//! } -//! -//! // At top level: -//! var io = cli.Io.init(); -//! var ctx = cli.CliContext.init(gpa, arena, &io, .build); -//! ctx.initIo(); // Initialize I/O writers after ctx is at its final location -//! defer ctx.deinit(); -//! -//! doSomething(&ctx, "app.roc") catch |err| switch (err) { -//! error.CliError => {}, // Problems already recorded -//! }; -//! -//! try ctx.renderProblemsTo(ctx.io.stderr()); -//! return ctx.exitCode(); -//! ``` - -const problem = @import("cli_error/problem.zig"); -const context = @import("cli_error/context.zig"); - -// Re-export error type -pub const CliError = context.CliError; - -// Re-export main types - CliContext is the primary type -pub const CliContext = context.CliContext; -pub const Io = context.Io; -pub const CliProblem = problem.CliProblem; -pub const FileContext = problem.FileContext; -pub const Command = context.Command; - -// Backward compatibility alias -pub const CliErrorContext = context.CliErrorContext; - -// Re-export helper functions -pub const reportSingleProblem = context.reportSingleProblem; -pub const renderProblem = context.renderProblem; - -const std = @import("std"); - -test "cli_error tests" { - std.testing.refAllDecls(@import("cli_error/problem.zig")); - std.testing.refAllDecls(@import("cli_error/context.zig")); -} diff --git a/src/cli/libc_finder.zig b/src/cli/libc_finder.zig index bc3c30f416..b894841910 100644 --- a/src/cli/libc_finder.zig +++ b/src/cli/libc_finder.zig @@ -10,7 +10,7 @@ const std = @import("std"); const builtin = @import("builtin"); const base = @import("base"); const Allocators = base.Allocators; -const cli_ctx = @import("cli_error/context.zig"); +const cli_ctx = @import("CliContext.zig"); const CliContext = cli_ctx.CliContext; const Io = cli_ctx.Io; const fs = std.fs; diff --git a/src/cli/linker.zig b/src/cli/linker.zig index 490a862caf..91a04163bc 100644 --- a/src/cli/linker.zig +++ b/src/cli/linker.zig @@ -10,7 +10,7 @@ const base = @import("base"); const Allocators = base.Allocators; const libc_finder = @import("libc_finder.zig"); const RocTarget = @import("roc_target").RocTarget; -const cli_ctx = @import("cli_error/context.zig"); +const cli_ctx = @import("CliContext.zig"); const CliContext = cli_ctx.CliContext; const Io = cli_ctx.Io; diff --git a/src/cli/main.zig b/src/cli/main.zig index 7265302976..b9240427f2 100644 --- a/src/cli/main.zig +++ b/src/cli/main.zig @@ -54,18 +54,23 @@ const cli_args = @import("cli_args.zig"); const roc_target = @import("target.zig"); pub const targets_validator = @import("targets_validator.zig"); const platform_validation = @import("platform_validation.zig"); -const cli_error = @import("cli_error.zig"); +const cli_context = @import("CliContext.zig"); +const cli_problem = @import("CliProblem.zig"); -const CliProblem = cli_error.CliProblem; -const CliContext = cli_error.CliContext; -const Io = cli_error.Io; +const CliProblem = cli_problem.CliProblem; +const CliContext = cli_context.CliContext; +const Io = cli_context.Io; +const Command = cli_context.Command; +const CliError = cli_context.CliError; +const renderProblem = cli_context.renderProblem; comptime { if (builtin.is_test) { std.testing.refAllDecls(cli_args); std.testing.refAllDecls(targets_validator); std.testing.refAllDecls(platform_validation); - std.testing.refAllDecls(cli_error); + std.testing.refAllDecls(cli_context); + std.testing.refAllDecls(cli_problem); } } const bench = @import("bench.zig"); @@ -679,7 +684,7 @@ fn mainArgs(allocs: *Allocators, args: []const []const u8) !void { const parsed_args = try cli_args.parse(allocs.arena, args[1..]); // Determine command for context - const command: cli_error.Command = switch (parsed_args) { + const command: Command = switch (parsed_args) { .run => .run, .build => .build, .check => .check, @@ -1261,7 +1266,7 @@ fn appendWindowsQuotedArg(cmd_builder: *std.array_list.Managed(u8), arg: []const } /// Run child process using Windows handle inheritance (idiomatic Windows approach) -fn runWithWindowsHandleInheritance(ctx: *CliContext, exe_path: []const u8, shm_handle: SharedMemoryHandle, app_args: []const []const u8) (cli_error.CliError || error{OutOfMemory})!void { +fn runWithWindowsHandleInheritance(ctx: *CliContext, exe_path: []const u8, shm_handle: SharedMemoryHandle, app_args: []const []const u8) (CliError || error{OutOfMemory})!void { // Make the shared memory handle inheritable if (windows.SetHandleInformation(@ptrCast(shm_handle.fd), windows.HANDLE_FLAG_INHERIT, windows.HANDLE_FLAG_INHERIT) == 0) { return ctx.fail(.{ .shared_memory_failed = .{ @@ -1377,7 +1382,7 @@ fn runWithWindowsHandleInheritance(ctx: *CliContext, exe_path: []const u8, shm_h /// Run child process using POSIX file descriptor inheritance (existing approach for Unix) /// The exe_path should already be in a unique temp directory created by createUniqueTempDir. -fn runWithPosixFdInheritance(ctx: *CliContext, exe_path: []const u8, shm_handle: SharedMemoryHandle, app_args: []const []const u8) (cli_error.CliError || error{OutOfMemory})!void { +fn runWithPosixFdInheritance(ctx: *CliContext, exe_path: []const u8, shm_handle: SharedMemoryHandle, app_args: []const []const u8) (CliError || error{OutOfMemory})!void { // Write the coordination file (.txt) next to the executable // The executable is already in a unique temp directory std.log.debug("Writing fd coordination file for: {s}", .{exe_path}); @@ -1793,7 +1798,7 @@ pub fn setupSharedMemoryWithModuleEnv(ctx: *CliContext, roc_file_path: []const u .err = err, } }, }; - cli_error.renderProblem(ctx.gpa, ctx.io.stderr(), problem); + renderProblem(ctx.gpa, ctx.io.stderr(), problem); return error.FileNotFound; }; defer app_file.close(); @@ -2808,7 +2813,7 @@ pub const PlatformPaths = struct { /// Resolve platform specification from a Roc file to find both host library and platform source. /// Returns PlatformPaths with arena-allocated paths (no need to free). -pub fn resolvePlatformPaths(ctx: *CliContext, roc_file_path: []const u8) cli_error.CliError!PlatformPaths { +pub fn resolvePlatformPaths(ctx: *CliContext, roc_file_path: []const u8) CliError!PlatformPaths { // Use the parser to extract the platform spec const platform_spec = extractPlatformSpecFromApp(ctx, roc_file_path) catch { return ctx.fail(.{ .file_not_found = .{ @@ -2918,7 +2923,7 @@ fn stringFromExpr(ast: *parse.AST, expr_idx: parse.AST.Expr.Idx) ![]const u8 { /// Check if platform spec is an absolute path and reject it. /// Uses CliContext for error reporting. -fn validatePlatformSpec(ctx: *CliContext, platform_spec: []const u8) cli_error.CliError!void { +fn validatePlatformSpec(ctx: *CliContext, platform_spec: []const u8) CliError!void { if (std.fs.path.isAbsolute(platform_spec)) { return ctx.fail(.{ .absolute_platform_path = .{ .platform_spec = platform_spec } }); } @@ -2926,7 +2931,7 @@ fn validatePlatformSpec(ctx: *CliContext, platform_spec: []const u8) cli_error.C /// Resolve a platform specification to a platform source path. /// Uses CliContext for error reporting. -fn resolvePlatformSpecToPaths(ctx: *CliContext, platform_spec: []const u8, base_dir: []const u8) cli_error.CliError!PlatformPaths { +fn resolvePlatformSpecToPaths(ctx: *CliContext, platform_spec: []const u8, base_dir: []const u8) CliError!PlatformPaths { // Handle URL-based platforms if (std.mem.startsWith(u8, platform_spec, "http")) { return resolveUrlPlatform(ctx, platform_spec) catch |err| switch (err) { @@ -3009,7 +3014,7 @@ fn getEnvVar(allocator: std.mem.Allocator, key: []const u8) ?[]const u8 { /// Resolve a URL platform specification by downloading and caching the bundle. /// The URL must point to a .tar.zst bundle with a base58-encoded BLAKE3 hash filename. -fn resolveUrlPlatform(ctx: *CliContext, url: []const u8) (cli_error.CliError || error{OutOfMemory})!PlatformPaths { +fn resolveUrlPlatform(ctx: *CliContext, url: []const u8) (CliError || error{OutOfMemory})!PlatformPaths { const download = unbundle.download; // 1. Validate URL and extract hash @@ -3622,7 +3627,7 @@ fn rocBuildEmbedded(ctx: *CliContext, args: cli_args.BuildArgs) !void { return error.MissingTargetsSection; }, else => { - cli_error.renderProblem(ctx.gpa, ctx.io.stderr(), .{ + renderProblem(ctx.gpa, ctx.io.stderr(), .{ .platform_validation_failed = .{ .message = "Failed to validate platform header", }, @@ -3632,7 +3637,7 @@ fn rocBuildEmbedded(ctx: *CliContext, args: cli_args.BuildArgs) !void { } } else { - cli_error.renderProblem(ctx.gpa, ctx.io.stderr(), .{ + renderProblem(ctx.gpa, ctx.io.stderr(), .{ .no_platform_found = .{ .app_path = args.path }, }); return error.NoPlatformSource; @@ -3674,7 +3679,7 @@ fn rocBuildEmbedded(ctx: *CliContext, args: cli_args.BuildArgs) !void { } else blk: { // No --target provided: find the first compatible target across all link types const compatible = targets_config.getFirstCompatibleTarget() orelse { - cli_error.renderProblem(ctx.gpa, ctx.io.stderr(), .{ + renderProblem(ctx.gpa, ctx.io.stderr(), .{ .platform_validation_failed = .{ .message = "No compatible target found. The platform does not support any target compatible with this system.", }, diff --git a/src/cli/test_shared_memory_system.zig b/src/cli/test_shared_memory_system.zig index 2193468044..6c5d9531db 100644 --- a/src/cli/test_shared_memory_system.zig +++ b/src/cli/test_shared_memory_system.zig @@ -6,9 +6,9 @@ const testing = std.testing; const main = @import("main.zig"); const base = @import("base"); const Allocators = base.Allocators; -const cli_error = @import("cli_error.zig"); -const CliContext = cli_error.CliContext; -const Io = cli_error.Io; +const cli_context = @import("CliContext.zig"); +const CliContext = cli_context.CliContext; +const Io = cli_context.Io; test "platform resolution - basic cli platform" { var gpa_impl = std.heap.GeneralPurposeAllocator(.{}){};