From 8294ab0942163e01c7c7198e08e60ba0248e7050 Mon Sep 17 00:00:00 2001 From: saehejkang <20051028+saehejkang@users.noreply.github.com> Date: Sat, 16 May 2026 18:24:38 -0700 Subject: [PATCH 1/2] fix error to write to stderr --- Sources/ContainerCommands/Image/ImageLoad.swift | 15 ++++++++------- .../Subcommands/Images/TestCLIImagesCommand.swift | 9 +++++++++ 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/Sources/ContainerCommands/Image/ImageLoad.swift b/Sources/ContainerCommands/Image/ImageLoad.swift index 118772b39..704b8775d 100644 --- a/Sources/ContainerCommands/Image/ImageLoad.swift +++ b/Sources/ContainerCommands/Image/ImageLoad.swift @@ -49,7 +49,7 @@ extension Application { } // Read from stdin; otherwise read from the input file - if input == nil { + guard let input else { guard FileManager.default.createFile(atPath: tempFile.path(), contents: nil) else { throw ContainerizationError(.internalError, message: "unable to create temporary file") } @@ -65,11 +65,12 @@ extension Application { fileHandle.write(chunk) } try fileHandle.close() - } else { - guard FileManager.default.fileExists(atPath: input!) else { - print("File does not exist \(input!)") - Application.exit(withError: ArgumentParser.ExitCode(1)) - } + return + } + + guard FileManager.default.fileExists(atPath: input) else { + log.error("file does not exist", metadata: ["path": "\(input)"]) + Application.exit(withError: ArgumentParser.ExitCode(1)) } let progressConfig = try ProgressConfig( @@ -85,7 +86,7 @@ extension Application { progress.set(description: "Loading tar archive") let result = try await ClientImage.load( - from: input ?? tempFile.path(), + from: input, force: force) if !result.rejectedMembers.isEmpty { log.warning("archive contains invalid members", metadata: ["paths": "\(result.rejectedMembers)"]) diff --git a/Tests/CLITests/Subcommands/Images/TestCLIImagesCommand.swift b/Tests/CLITests/Subcommands/Images/TestCLIImagesCommand.swift index e3d2aa5b3..28b08304d 100644 --- a/Tests/CLITests/Subcommands/Images/TestCLIImagesCommand.swift +++ b/Tests/CLITests/Subcommands/Images/TestCLIImagesCommand.swift @@ -599,4 +599,13 @@ class TestCLIImagesCommand: CLITest { #expect(status != 0, "Expected non-zero exit for missing image") #expect(error.contains("image not found")) } + + @Test func testImageLoadMissingFileErrorToStderr() throws { + let missingPath = "/path/that/does/not/exist-\(UUID().uuidString)" + let (_, stdout, stderr, status) = try run(arguments: ["image", "load", "-i", missingPath]) + + #expect(status != 0, "Expected non-zero exit for missing file") + #expect(stdout.isEmpty, "Expected stdout to be empty, got: \(stdout)") + #expect(stderr.contains("File does not exist \(missingPath)"), "Expected stderr to contain error message, got: \(stderr)") + } } From b557aee53f665e4ced9b71ab5cf8413c65ead9e5 Mon Sep 17 00:00:00 2001 From: saehejkang <20051028+saehejkang@users.noreply.github.com> Date: Mon, 18 May 2026 18:40:04 -0700 Subject: [PATCH 2/2] transform input string to a filepath --- .../ContainerCommands/Image/ImageLoad.swift | 27 ++++++++++++------- .../Images/TestCLIImagesCommand.swift | 2 +- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/Sources/ContainerCommands/Image/ImageLoad.swift b/Sources/ContainerCommands/Image/ImageLoad.swift index 704b8775d..08e66d4f7 100644 --- a/Sources/ContainerCommands/Image/ImageLoad.swift +++ b/Sources/ContainerCommands/Image/ImageLoad.swift @@ -19,6 +19,7 @@ import ContainerAPIClient import Containerization import ContainerizationError import Foundation +import SystemPackage import TerminalProgress extension Application { @@ -32,9 +33,13 @@ extension Application { @Option( name: .shortAndLong, help: "Path to the image tar archive", completion: .file(), transform: { str in - URL(fileURLWithPath: str, relativeTo: .currentDirectory()).absoluteURL.path(percentEncoded: false) + let path = FilePath(str) + guard path.isRelative else { return path.lexicallyNormalized() } + return FilePath(FileManager.default.currentDirectoryPath) + .pushing(path) + .lexicallyNormalized() }) - var input: String? + var input: FilePath? @Flag(name: .shortAndLong, help: "Load images even if the archive contains invalid files") public var force = false @@ -49,7 +54,14 @@ extension Application { } // Read from stdin; otherwise read from the input file - guard let input else { + let resolvedPath: FilePath + if let input { + guard FileManager.default.fileExists(atPath: input.string) else { + log.error("file does not exist", metadata: ["path": "\(input)"]) + Application.exit(withError: ArgumentParser.ExitCode(1)) + } + resolvedPath = input + } else { guard FileManager.default.createFile(atPath: tempFile.path(), contents: nil) else { throw ContainerizationError(.internalError, message: "unable to create temporary file") } @@ -65,12 +77,7 @@ extension Application { fileHandle.write(chunk) } try fileHandle.close() - return - } - - guard FileManager.default.fileExists(atPath: input) else { - log.error("file does not exist", metadata: ["path": "\(input)"]) - Application.exit(withError: ArgumentParser.ExitCode(1)) + resolvedPath = FilePath(tempFile.path()) } let progressConfig = try ProgressConfig( @@ -86,7 +93,7 @@ extension Application { progress.set(description: "Loading tar archive") let result = try await ClientImage.load( - from: input, + from: resolvedPath.string, force: force) if !result.rejectedMembers.isEmpty { log.warning("archive contains invalid members", metadata: ["paths": "\(result.rejectedMembers)"]) diff --git a/Tests/CLITests/Subcommands/Images/TestCLIImagesCommand.swift b/Tests/CLITests/Subcommands/Images/TestCLIImagesCommand.swift index 28b08304d..307b40767 100644 --- a/Tests/CLITests/Subcommands/Images/TestCLIImagesCommand.swift +++ b/Tests/CLITests/Subcommands/Images/TestCLIImagesCommand.swift @@ -606,6 +606,6 @@ class TestCLIImagesCommand: CLITest { #expect(status != 0, "Expected non-zero exit for missing file") #expect(stdout.isEmpty, "Expected stdout to be empty, got: \(stdout)") - #expect(stderr.contains("File does not exist \(missingPath)"), "Expected stderr to contain error message, got: \(stderr)") + #expect(stderr.contains("file does not exist") && stderr.contains(missingPath), "Expected stderr to contain error message, got: \(stderr)") } }