fetch_ml/cli/src/main.zig
Jeremie Fraeys b75bd24bba Add CLI jupyter command for transparent Jupyter management
- Add jupyter.zig command with start/stop/status actions
- Update main.zig to include jupyter command in CLI
- CLI now handles all Jupyter setup transparently
- Data scientists only need: ml jupyter start
- Auto-detects container runtime (Podman/Docker)
- Manages container lifecycle automatically
- Provides clear status and error messages
2025-12-06 16:07:09 -05:00

129 lines
5.2 KiB
Zig

const std = @import("std");
const errors = @import("errors.zig");
const colors = @import("utils/colors.zig");
// Global verbosity level
var verbose_mode: bool = false;
var quiet_mode: bool = false;
const commands = struct {
const init = @import("commands/init.zig");
const sync = @import("commands/sync.zig");
const queue = @import("commands/queue.zig");
const status = @import("commands/status.zig");
const monitor = @import("commands/monitor.zig");
const cancel = @import("commands/cancel.zig");
const prune = @import("commands/prune.zig");
const watch = @import("commands/watch.zig");
const dataset = @import("commands/dataset.zig");
const experiment = @import("commands/experiment.zig");
const jupyter = @import("commands/jupyter.zig");
};
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
// Parse command line arguments
var args_iter = std.process.args();
_ = args_iter.next(); // Skip executable name
var command_args = std.ArrayList([]const u8).initCapacity(allocator, 10) catch |err| {
colors.printError("Failed to allocate command args: {}\n", .{err});
return err;
};
defer command_args.deinit(allocator);
// Parse global flags first
while (args_iter.next()) |arg| {
if (std.mem.eql(u8, arg, "--help") or std.mem.eql(u8, arg, "-h")) {
printUsage();
return;
} else if (std.mem.eql(u8, arg, "--verbose") or std.mem.eql(u8, arg, "-v")) {
verbose_mode = true;
quiet_mode = false;
} else if (std.mem.eql(u8, arg, "--quiet") or std.mem.eql(u8, arg, "-q")) {
quiet_mode = true;
verbose_mode = false;
} else {
command_args.append(allocator, arg) catch |err| {
colors.printError("Failed to append argument: {}\n", .{err});
return err;
};
}
}
const args = command_args.items;
if (args.len < 1) {
colors.printError("No command specified.\n", .{});
printUsage();
return;
}
const command = args[0];
// Handle commands with proper error handling
if (std.mem.eql(u8, command, "--help") or std.mem.eql(u8, command, "help")) {
printUsage();
return;
}
const command_result = if (std.mem.eql(u8, command, "init"))
commands.init.run(allocator, args[1..])
else if (std.mem.eql(u8, command, "sync"))
commands.sync.run(allocator, args[1..])
else if (std.mem.eql(u8, command, "queue"))
commands.queue.run(allocator, args[1..])
else if (std.mem.eql(u8, command, "status"))
commands.status.run(allocator, args[1..])
else if (std.mem.eql(u8, command, "monitor"))
commands.monitor.run(allocator, args[1..])
else if (std.mem.eql(u8, command, "cancel"))
commands.cancel.run(allocator, args[1..])
else if (std.mem.eql(u8, command, "prune"))
commands.prune.run(allocator, args[1..])
else if (std.mem.eql(u8, command, "watch"))
commands.watch.run(allocator, args[1..])
else if (std.mem.eql(u8, command, "dataset"))
commands.dataset.run(allocator, args[1..])
else if (std.mem.eql(u8, command, "experiment"))
commands.experiment.execute(allocator, args[1..])
else if (std.mem.eql(u8, command, "jupyter"))
commands.jupyter.run(allocator, args[1..])
else
error.InvalidArguments;
// Handle any errors that occur during command execution
command_result catch |err| {
errors.ErrorHandler.handleCommandError(err, command);
};
}
pub fn printUsage() void {
colors.printInfo("ML Experiment Manager\n\n", .{});
std.debug.print("Usage: ml <command> [options]\n\n", .{});
std.debug.print("Commands:\n", .{});
std.debug.print(" init Setup configuration interactively\n", .{});
std.debug.print(" sync <path> Sync project to server\n", .{});
std.debug.print(" queue <job> Queue job for execution\n", .{});
std.debug.print(" status Get system status\n", .{});
std.debug.print(" monitor Launch TUI via SSH\n", .{});
std.debug.print(" cancel <job> Cancel running job\n", .{});
std.debug.print(" prune --keep N Keep N most recent experiments\n", .{});
std.debug.print(" prune --older-than D Remove experiments older than D days\n", .{});
std.debug.print(" watch <path> Watch directory for auto-sync\n", .{});
std.debug.print(" dataset <action> Manage datasets (list, upload, download, delete)\n", .{});
std.debug.print(" experiment <action> Manage experiments (log, show)\n", .{});
std.debug.print(" jupyter <action> Manage Jupyter notebooks (start, stop, status)\n\n", .{});
std.debug.print("Options:\n", .{});
std.debug.print(" --help Show this help message\n", .{});
std.debug.print(" --verbose Enable verbose output\n", .{});
std.debug.print(" --quiet Suppress non-error output\n", .{});
std.debug.print(" --monitor Monitor progress of long-running operations\n", .{});
}
test "basic test" {
try std.testing.expectEqual(@as(i32, 10), 10);
}