const std = @import("std"); const c = @cImport({ @cInclude("stdlib.h"); @cInclude("time.h"); }); const log = std.log.scoped(.os); pub fn captureStdout( io: std.Io, command: []const u8, opts: struct { cwd: std.process.Child.Cwd = .inherit, environ_map: ?*const std.process.Environ.Map = null, progress_node: std.Progress.Node = std.Progress.Node.none, }, w: *std.Io.Writer, ) !void { log.debug("Running <<< {s}", .{command}); var p = try std.process.spawn(io, .{ .argv = &.{ "sh", "-c", command }, .cwd = opts.cwd, .stdin = .ignore, .stderr = .ignore, .stdout = .pipe, .environ_map = opts.environ_map, .progress_node = opts.progress_node, }); var buf: [1024]u8 = undefined; var r = p.stdout.?.readerStreaming(io, &buf); _ = try w.sendFileAll(&r, .unlimited); try w.flush(); const result = try p.wait(io); if (result.exited != 0) return error.NonZeroExitCode; } pub fn shell( io: std.Io, command: []const u8, opts: struct { cwd: std.process.Child.Cwd = .inherit, environ_map: ?*const std.process.Environ.Map = null, progress_node: std.Progress.Node = std.Progress.Node.none, }, ) !void { log.debug("Running Shell <<< {s}", .{command}); var p = try std.process.spawn(io, .{ .argv = &.{ "sh", "-c", command }, .cwd = opts.cwd, .stdin = .ignore, .stderr = .inherit, .stdout = .inherit, .environ_map = opts.environ_map, .progress_node = opts.progress_node, }); const result = try p.wait(io); if (result.exited != 0) return error.NonZeroExitCode; } // use libc strftime to format time string pub fn formatTimestamp(alloc: std.mem.Allocator, ts: std.Io.Timestamp, fmt: [*c]const u8) ![]const u8 { const mtime_str = try alloc.alloc(u8, std.os.linux.PATH_MAX); var tm: c.struct_tm = undefined; const sec = ts.toSeconds(); _ = c.localtime_r(&sec, &tm); const rc = c.strftime( mtime_str.ptr, mtime_str.len, fmt, &tm, ); switch (std.posix.errno(rc)) { .SUCCESS => {}, else => |err| return std.posix.unexpectedErrno(err), } return try alloc.realloc(mtime_str, rc); }