-
Notifications
You must be signed in to change notification settings - Fork 524
[image-save-load]: support for stdin/stdout #734
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -34,14 +34,38 @@ 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("\(UUID().uuidString).tar") | ||
| defer { | ||
| try? FileManager.default.removeItem(at: tempFile) | ||
| } | ||
|
|
||
| // Read from stdin | ||
| 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) | ||
| } | ||
| try outputHandle.close() | ||
| } | ||
|
|
||
| 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 +81,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()) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: What do you think about restructuring load like to only run the code that's needed for each case? The only bit of code that repeats is the ClientImage.load line, and we would be removing a conditional from that. var loaded: ClientImage
if input == nil {
// create tmpfile, defer delete, copy stdin to file
loaded = try await ClientImage.load(from: tempFile.path())
} else {
// ensure input exists
loaded = loaded = try await ClientImage.load(from: input)
}
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Any reason for this update besides readability (coding standards, etc)? I thought using the ternary operator makes sense in that it is clear to use the input path first, if not nil, and the temp file path otherwise. Just thought calling load once makes more sense and is cleaner. Not 100% adamant on one way but will defer to you for the final decision. |
||
|
|
||
| let taskManager = ProgressTaskCoordinator() | ||
| let unpackTask = await taskManager.startTask() | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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,32 @@ 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("\(UUID().uuidString).tar") | ||
| defer { | ||
| try? FileManager.default.removeItem(at: tempFile) | ||
| } | ||
|
|
||
| guard FileManager.default.createFile(atPath: tempFile.path(), contents: nil) else { | ||
| throw ContainerizationError(.internalError, message: "unable to create temporary file") | ||
| } | ||
|
|
||
| try await ClientImage.save(references: references, out: output ?? tempFile.path(), platform: p) | ||
|
|
||
| // Write to stdout | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same for this one, we could put an |
||
| 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) | ||
| } | ||
| try outputHandle.close() | ||
| } | ||
saehejkang marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| progress.finish() | ||
| for reference in references { | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.