fetch_ml/cli/src/utils/rsync_embedded.zig
Jeremie Fraeys d225ea1f00 feat: implement Zig CLI with comprehensive ML experiment management
- Add modern CLI interface built with Zig for performance
- Include TUI (Terminal User Interface) with bubbletea-like features
- Implement ML experiment commands (run, status, manage)
- Add configuration management and validation
- Include shell completion scripts for bash and zsh
- Add comprehensive CLI testing framework
- Support for multiple ML frameworks and project types

CLI provides fast, efficient interface for ML experiment management
with modern terminal UI and comprehensive feature set.
2025-12-04 16:53:58 -05:00

107 lines
3.8 KiB
Zig

const std = @import("std");
/// Embedded rsync binary functionality
pub const EmbeddedRsync = struct {
allocator: std.mem.Allocator,
const Self = @This();
/// Extract embedded rsync binary to temporary location
pub fn extractRsyncBinary(self: Self) ![]const u8 {
const rsync_path = "/tmp/ml_rsync";
// Check if rsync binary already exists
if (std.fs.cwd().openFile(rsync_path, .{})) |file| {
file.close();
// Check if it's executable
const stat = try std.fs.cwd().statFile(rsync_path);
if (stat.mode & 0o111 != 0) {
return try self.allocator.dupe(u8, rsync_path);
}
} else |_| {
// Need to extract the binary
try self.extractAndSetExecutable(rsync_path);
}
return try self.allocator.dupe(u8, rsync_path);
}
/// Extract rsync binary from embedded data and set executable permissions
fn extractAndSetExecutable(self: Self, path: []const u8) !void {
// Import embedded binary data
const embedded_binary = @import("rsync_embedded_binary.zig");
// Get the embedded rsync binary data
const binary_data = embedded_binary.getRsyncBinary();
// Debug output to show we're using embedded binary
const debug_msg = try std.fmt.allocPrint(self.allocator, "Extracting embedded rsync binary to {s} (size: {d} bytes)", .{ path, binary_data.len });
defer self.allocator.free(debug_msg);
std.log.debug("{s}", .{debug_msg});
// Write embedded binary to file system
try std.fs.cwd().writeFile(.{ .sub_path = path, .data = binary_data });
// Set executable permissions using OS API
const mode = 0o755; // rwxr-xr-x
std.posix.fchmodat(std.fs.cwd().fd, path, mode, 0) catch |err| {
std.log.warn("Failed to set executable permissions on {s}: {}", .{ path, err });
// Continue anyway - the script might still work
};
}
/// Sync using embedded rsync
pub fn sync(self: Self, local_path: []const u8, remote_path: []const u8, ssh_port: u16) !void {
const rsync_path = try self.extractRsyncBinary();
defer self.allocator.free(rsync_path);
const port_str = try std.fmt.allocPrint(self.allocator, "{d}", .{ssh_port});
defer self.allocator.free(port_str);
const ssh_opt = try std.fmt.allocPrint(self.allocator, "ssh -p {s}", .{port_str});
defer self.allocator.free(ssh_opt);
// Build rsync command using embedded binary
var child = std.process.Child.init(
&[_][]const u8{
rsync_path,
"-avz",
"--delete",
"-e",
ssh_opt,
local_path,
remote_path,
},
self.allocator,
);
child.stdin_behavior = .Ignore;
child.stdout_behavior = .Inherit;
child.stderr_behavior = .Inherit;
const term = try child.spawnAndWait();
switch (term) {
.Exited => |code| {
if (code != 0) {
std.debug.print("rsync failed with exit code {d}\n", .{code});
return error.RsyncFailed;
}
},
.Signal => {
return error.RsyncKilled;
},
else => {
return error.RsyncUnknownError;
},
}
}
};
/// Public sync function that uses embedded rsync
pub fn sync(allocator: std.mem.Allocator, local_path: []const u8, remote_path: []const u8, ssh_port: u16) !void {
var embedded_rsync = EmbeddedRsync{ .allocator = allocator };
try embedded_rsync.sync(local_path, remote_path, ssh_port);
std.debug.print("Synced {s} to {s} using embedded rsync\n", .{ local_path, remote_path });
}