diff --git a/Sources/ContainerCommands/Image/ImageLoad.swift b/Sources/ContainerCommands/Image/ImageLoad.swift index e5b4f497..265e89ff 100644 --- a/Sources/ContainerCommands/Image/ImageLoad.swift +++ b/Sources/ContainerCommands/Image/ImageLoad.swift @@ -34,14 +34,35 @@ extension Application { transform: { str in URL(fileURLWithPath: str, relativeTo: .currentDirectory()).absoluteURL.path(percentEncoded: false) }) - var input: String + var input: String? @OptionGroup var global: Flags.Global public func run() async throws { - guard FileManager.default.fileExists(atPath: input) else { - print("File does not exist \(input)") + let tempFile = FileManager.default.temporaryDirectory.appendingPathComponent("temp-file.tar") + if input == nil { + guard FileManager.default.createFile(atPath: tempFile.path(), contents: nil) else { + throw ContainerizationError(.internalError, message: "unable to create temporary file") + } + + guard let outputHandle = try? FileHandle(forWritingTo: tempFile) else { + throw ContainerizationError(.internalError, message: "unable to open temporary file for writing") + } + + let bufferSize = 4096 + while true { + let chunk = FileHandle.standardInput.readData(ofLength: bufferSize) + if chunk.isEmpty { break } + outputHandle.write(chunk) + } + } + defer { + try? FileManager.default.removeItem(at: tempFile) + } + + guard FileManager.default.fileExists(atPath: input ?? tempFile.path()) else { + print("File does not exist \(input ?? tempFile.path())") Application.exit(withError: ArgumentParser.ExitCode(1)) } @@ -57,7 +78,7 @@ extension Application { progress.start() progress.set(description: "Loading tar archive") - let loaded = try await ClientImage.load(from: input) + let loaded = try await ClientImage.load(from: input ?? tempFile.path()) let taskManager = ProgressTaskCoordinator() let unpackTask = await taskManager.startTask() diff --git a/Sources/ContainerCommands/Image/ImageSave.swift b/Sources/ContainerCommands/Image/ImageSave.swift index 3ef7c41e..515a9354 100644 --- a/Sources/ContainerCommands/Image/ImageSave.swift +++ b/Sources/ContainerCommands/Image/ImageSave.swift @@ -46,7 +46,7 @@ extension Application { transform: { str in URL(fileURLWithPath: str, relativeTo: .currentDirectory()).absoluteURL.path(percentEncoded: false) }) - var output: String + var output: String? @Option( help: "Platform for the saved image (format: os/arch[/variant], takes precedence over --os and --arch)" @@ -90,7 +90,30 @@ extension Application { throw ContainerizationError(.invalidArgument, message: "failed to save image(s)") } - try await ClientImage.save(references: references, out: output, platform: p) + + let tempFile = FileManager.default.temporaryDirectory.appendingPathComponent("temp-file.tar") + guard FileManager.default.createFile(atPath: tempFile.path(), contents: nil) else { + throw ContainerizationError(.internalError, message: "unable to create temporary file") + } + + defer { + try? FileManager.default.removeItem(at: tempFile) + } + + try await ClientImage.save(references: references, out: output ?? tempFile.path(), platform: p) + + if output == nil { + guard let outputHandle = try? FileHandle(forReadingFrom: tempFile) else { + throw ContainerizationError(.internalError, message: "unable to open temporary file for reading") + } + + let bufferSize = 4096 + while true { + let chunk = outputHandle.readData(ofLength: bufferSize) + if chunk.isEmpty { break } + FileHandle.standardOutput.write(chunk) + } + } progress.finish() for reference in references {