mirror of
https://github.com/roc-lang/roc.git
synced 2025-12-23 08:48:03 +00:00
start re-organizing, leave a plan for future PR's
This commit is contained in:
parent
6a1086e0a9
commit
d0b451fb78
9 changed files with 152 additions and 127 deletions
|
|
@ -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;
|
||||
90
src/cli/REORGANIZATION.md
Normal file
90
src/cli/REORGANIZATION.md
Normal file
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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"));
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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.",
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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(.{}){};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue