fix(cli): Zig 0.15 core API changes
- ArrayList: .init(allocator) → .empty, add allocator param to append/deinit/toOwnedSlice - Atomic: std.atomic.Atomic → std.atomic.Value, lowercase order names (.seq_cst) - Process: execvp instead of execvpe, inline wait status macros for macOS - Time: std.time.sleep → std.Thread.sleep - Error handling: fix isProcessRunning error union comparison
This commit is contained in:
parent
20fde4f79d
commit
ccd1dd7a4d
5 changed files with 55 additions and 36 deletions
|
|
@ -11,8 +11,8 @@ const manifest_lib = @import("../manifest.zig");
|
|||
pub fn run(allocator: std.mem.Allocator, args: []const []const u8) !void {
|
||||
var flags = core.flags.CommonFlags{};
|
||||
var force = false;
|
||||
var targets = std.ArrayList([]const u8).init(allocator);
|
||||
defer targets.deinit();
|
||||
var targets: std.ArrayList([]const u8) = .empty;
|
||||
defer targets.deinit(allocator);
|
||||
|
||||
// Parse arguments
|
||||
var i: usize = 0;
|
||||
|
|
@ -28,7 +28,7 @@ pub fn run(allocator: std.mem.Allocator, args: []const []const u8) !void {
|
|||
core.output.errorMsg("cancel", "Unknown option");
|
||||
return error.InvalidArgs;
|
||||
} else {
|
||||
try targets.append(arg);
|
||||
try targets.append(allocator, arg);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -129,7 +129,7 @@ fn cancelLocal(allocator: std.mem.Allocator, run_id: []const u8, force: bool, js
|
|||
|
||||
if (!force) {
|
||||
// Wait 5 seconds for graceful termination
|
||||
std.time.sleep(5 * std.time.ns_per_s);
|
||||
std.Thread.sleep(5 * std.time.ns_per_s);
|
||||
}
|
||||
|
||||
// Check if still running, send SIGKILL if needed
|
||||
|
|
@ -170,7 +170,7 @@ fn cancelLocal(allocator: std.mem.Allocator, run_id: []const u8, force: bool, js
|
|||
/// Check if process is still running
|
||||
fn isProcessRunning(pid: i32) bool {
|
||||
const result = std.posix.kill(pid, 0);
|
||||
return result == error.PermissionDenied or result == {};
|
||||
return if (result) |_| true else |err| err == error.PermissionDenied;
|
||||
}
|
||||
|
||||
/// Cancel server job
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ const crypto = @import("../utils/crypto.zig");
|
|||
/// Usage:
|
||||
/// ml logs <run_id> # Fetch logs from local file or server
|
||||
/// ml logs <run_id> --follow # Stream logs from server
|
||||
pub fn execute(allocator: std.mem.Allocator, args: []const []const u8) !void {
|
||||
pub fn run(allocator: std.mem.Allocator, args: []const []const u8) !void {
|
||||
var flags = core.flags.CommonFlags{};
|
||||
var command_args = try core.flags.parseCommon(allocator, args, &flags);
|
||||
defer command_args.deinit(allocator);
|
||||
|
|
@ -68,7 +68,7 @@ fn fetchLocalLogs(allocator: std.mem.Allocator, target: []const u8, cfg: *const
|
|||
defer allocator.free(manifest_path);
|
||||
|
||||
// Read manifest to get artifact path
|
||||
const manifest = try manifest_lib.readManifest(manifest_path, allocator);
|
||||
var manifest = try manifest_lib.readManifest(manifest_path, allocator);
|
||||
defer manifest.deinit(allocator);
|
||||
|
||||
// Build output.log path
|
||||
|
|
@ -90,8 +90,8 @@ fn fetchLocalLogs(allocator: std.mem.Allocator, target: []const u8, cfg: *const
|
|||
|
||||
if (json) {
|
||||
// Escape content for JSON
|
||||
var escaped = std.ArrayList(u8).init(allocator);
|
||||
defer escaped.deinit();
|
||||
var escaped: std.ArrayList(u8) = .empty;
|
||||
defer escaped.deinit(allocator);
|
||||
const writer = escaped.writer(allocator);
|
||||
|
||||
for (content) |c| {
|
||||
|
|
@ -130,7 +130,7 @@ fn fetchServerLogs(allocator: std.mem.Allocator, target: []const u8, cfg: config
|
|||
var client = try ws.Client.connect(allocator, ws_url, cfg.api_key);
|
||||
defer client.close();
|
||||
|
||||
try client.sendFetchLogs(target, api_key_hash);
|
||||
try client.sendGetLogs(target, api_key_hash);
|
||||
|
||||
const message = try client.receiveMessage(allocator);
|
||||
defer allocator.free(message);
|
||||
|
|
|
|||
|
|
@ -1,9 +1,29 @@
|
|||
const std = @import("std");
|
||||
const config = @import("../config.zig");
|
||||
const db = @import("../db.zig");
|
||||
const core = @import("../core.zig");
|
||||
const colors = @import("../utils/colors.zig");
|
||||
const manifest_lib = @import("../manifest.zig");
|
||||
const colors = @import("../utils/colors.zig");
|
||||
const core = @import("../core.zig");
|
||||
const config = @import("../config.zig");
|
||||
|
||||
extern fn execvp(path: [*:0]const u8, argv: [*]const ?[*:0]const u8) c_int;
|
||||
extern fn waitpid(pid: c_int, status: *c_int, flags: c_int) c_int;
|
||||
|
||||
// Get current environment from libc
|
||||
extern var environ: [*]const ?[*:0]const u8;
|
||||
|
||||
// Inline macros for wait status parsing (not available as extern on macOS)
|
||||
fn WIFEXITED(status: c_int) c_int {
|
||||
return if ((status & 0x7F) == 0) 1 else 0;
|
||||
}
|
||||
fn WEXITSTATUS(status: c_int) c_int {
|
||||
return (status >> 8) & 0xFF;
|
||||
}
|
||||
fn WIFSIGNALED(status: c_int) c_int {
|
||||
return if (((status & 0x7F) != 0x7F) and ((status & 0x7F) != 0)) 1 else 0;
|
||||
}
|
||||
fn WTERMSIG(status: c_int) c_int {
|
||||
return status & 0x7F;
|
||||
}
|
||||
const Manifest = manifest_lib.RunManifest;
|
||||
|
||||
/// Run command - always executes locally
|
||||
|
|
@ -97,7 +117,7 @@ pub fn execute(allocator: std.mem.Allocator, args: []const []const u8) !void {
|
|||
_ = try db.DB.step(stmt);
|
||||
|
||||
// Write manifest
|
||||
try manifest_lib.writeManifest(manifest, manifest_path);
|
||||
try manifest_lib.writeManifest(manifest, manifest_path, allocator);
|
||||
|
||||
// Fork and execute
|
||||
const output_log_path = try std.fs.path.join(allocator, &[_][]const u8{
|
||||
|
|
@ -176,22 +196,22 @@ fn resolveCommand(allocator: std.mem.Allocator, cfg: *const config.Config, args:
|
|||
if (cfg.experiment) |exp| {
|
||||
if (exp.entrypoint.len > 0) {
|
||||
// Split entrypoint on spaces
|
||||
var argv = std.ArrayList([]const u8).init(allocator);
|
||||
var argv: std.ArrayList([]const u8) = .empty;
|
||||
|
||||
// Parse entrypoint (split on spaces)
|
||||
var iter = std.mem.splitScalar(u8, exp.entrypoint, ' ');
|
||||
while (iter.next()) |part| {
|
||||
if (part.len > 0) {
|
||||
try argv.append(try allocator.dupe(u8, part));
|
||||
try argv.append(allocator, try allocator.dupe(u8, part));
|
||||
}
|
||||
}
|
||||
|
||||
// Append args
|
||||
for (args) |arg| {
|
||||
try argv.append(try allocator.dupe(u8, arg));
|
||||
try argv.append(allocator, try allocator.dupe(u8, arg));
|
||||
}
|
||||
|
||||
return argv.toOwnedSlice();
|
||||
return try argv.toOwnedSlice(allocator);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -246,7 +266,6 @@ fn executeAndCapture(
|
|||
// Create output file
|
||||
var output_file = try std.fs.cwd().createFile(output_path, .{});
|
||||
defer output_file.close();
|
||||
const output_writer = output_file.writer();
|
||||
|
||||
// Create pipe for stdout
|
||||
const pipe = try std.posix.pipe();
|
||||
|
|
@ -263,13 +282,13 @@ fn executeAndCapture(
|
|||
std.posix.close(pipe[0]); // Close read end
|
||||
|
||||
// Redirect stdout to pipe
|
||||
_ = std.posix.dup2(pipe[1], std.posix.STDOUT_FILENO);
|
||||
_ = std.posix.dup2(pipe[1], std.posix.STDERR_FILENO);
|
||||
_ = std.posix.dup2(pipe[1], std.posix.STDOUT_FILENO) catch std.process.exit(1);
|
||||
_ = std.posix.dup2(pipe[1], std.posix.STDERR_FILENO) catch std.process.exit(1);
|
||||
std.posix.close(pipe[1]);
|
||||
|
||||
// Execute command
|
||||
const err = std.posix.execvpe(command[0], command, &[_:null]?[*:0]const u8{null});
|
||||
std.log.err("Failed to execute {s}: {}", .{ command[0], err });
|
||||
// Execute command using execvp (uses current environ)
|
||||
const c_err = execvp(@ptrCast(command[0].ptr), @ptrCast(command.ptr));
|
||||
std.log.err("Failed to execute {s}: {}", .{ command[0], c_err });
|
||||
std.process.exit(1);
|
||||
unreachable;
|
||||
}
|
||||
|
|
@ -299,7 +318,7 @@ fn executeAndCapture(
|
|||
if (bytes_read == 0) break;
|
||||
|
||||
// Write to output file
|
||||
try output_writer.writeAll(buf[0..bytes_read]);
|
||||
try output_file.writeAll(buf[0..bytes_read]);
|
||||
|
||||
// Parse lines
|
||||
for (buf[0..bytes_read]) |byte| {
|
||||
|
|
@ -318,14 +337,14 @@ fn executeAndCapture(
|
|||
}
|
||||
|
||||
// Wait for child
|
||||
var status: u32 = 0;
|
||||
_ = std.posix.waitpid(pid, &status, 0);
|
||||
var status: c_int = 0;
|
||||
_ = waitpid(@intCast(pid), &status, 0);
|
||||
|
||||
// Parse exit code
|
||||
if (std.os.linux.W.IFEXITED(status)) {
|
||||
return std.os.linux.W.EXITSTATUS(status);
|
||||
} else if (std.os.linux.W.IFSIGNALED(status)) {
|
||||
return 128 + std.os.linux.W.TERMSIG(status);
|
||||
if (WIFEXITED(status) != 0) {
|
||||
return WEXITSTATUS(status);
|
||||
} else if (WIFSIGNALED(status) != 0) {
|
||||
return 128 + WTERMSIG(status);
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
|
|
|||
|
|
@ -12,17 +12,17 @@ pub const HashError = error{
|
|||
|
||||
// Global context for reuse across multiple hash operations
|
||||
var global_ctx: ?*c.fh_context_t = null;
|
||||
var ctx_initialized = std.atomic.Atomic(bool).init(false);
|
||||
var ctx_initialized = std.atomic.Value(bool).init(false);
|
||||
var init_mutex = std.Thread.Mutex{};
|
||||
|
||||
/// Initialize global hash context once (thread-safe)
|
||||
pub fn init() !void {
|
||||
if (ctx_initialized.load(.Acquire)) return;
|
||||
if (ctx_initialized.load(.seq_cst)) return;
|
||||
|
||||
init_mutex.lock();
|
||||
defer init_mutex.unlock();
|
||||
|
||||
if (ctx_initialized.load(.Relaxed)) return; // Double-check
|
||||
if (ctx_initialized.load(.seq_cst)) return; // Double-check
|
||||
|
||||
const start = std.time.milliTimestamp();
|
||||
global_ctx = c.fh_init(0); // 0 = auto-detect threads
|
||||
|
|
@ -32,7 +32,7 @@ pub fn init() !void {
|
|||
return HashError.ContextInitFailed;
|
||||
}
|
||||
|
||||
ctx_initialized.store(true, .Release);
|
||||
ctx_initialized.store(true, .seq_cst);
|
||||
std.log.info("[native] hash context initialized: {}ms", .{elapsed});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ const WorkQueue = struct {
|
|||
|
||||
fn init(allocator: std.mem.Allocator) WorkQueue {
|
||||
return .{
|
||||
.items = std.ArrayList(WorkItem).init(allocator),
|
||||
.items = .empty,
|
||||
.mutex = .{},
|
||||
.condition = .{},
|
||||
.done = false,
|
||||
|
|
|
|||
Loading…
Reference in a new issue