Skip to content

Commit 386fd87

Browse files
Enumerate using relative paths to avoid mismatch with symlink resolution of special paths like /tmp (apple#613)
## Type of Change - [x] Bug fix - [ ] New feature - [ ] Breaking change - [ ] Documentation update ## Motivation and Context Fixes apple#588. This PR changes the archiver compression file enumeration to use the [enumerator(atPath:)](https://developer.apple.com/documentation/foundation/filemanager/enumerator(atpath:)) version. This version returns relative paths instead of full file paths from the filesystem. /tmp is symlinked to /private/tmp and some swift packages will handle that path differently. While a call to Foundation's `URL.resolvingSymlinksInPath()` will return "/tmp", a call to `FileManager.enumerator(at:)` will return "/private/tmp". This difference causes a container image build to fail when the user is using a path under /tmp or other special case paths as the context directory. ## Testing - [x] Tested locally - [x] Added/updated tests - [ ] Added/updated docs Signed-off-by: Kathryn Baldauf <k_baldauf@apple.com>
1 parent 79cc363 commit 386fd87

File tree

2 files changed

+24
-5
lines changed

2 files changed

+24
-5
lines changed

Sources/ContainerClient/Archiver.swift

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,10 +60,7 @@ public final class Archiver: Sendable {
6060
try fileManager.createDirectory(at: directory, withIntermediateDirectories: true)
6161

6262
guard
63-
let enumerator = FileManager.default.enumerator(
64-
at: source,
65-
includingPropertiesForKeys: [.isDirectoryKey, .isRegularFileKey, .isSymbolicLinkKey]
66-
)
63+
let enumerator = FileManager.default.enumerator(atPath: source.path)
6764
else {
6865
throw Error.fileDoesNotExist(source)
6966
}
@@ -74,7 +71,8 @@ public final class Archiver: Sendable {
7471
entryInfo.append(info)
7572
}
7673
} else {
77-
while let url = enumerator.nextObject() as? URL {
74+
while let relPath = enumerator.nextObject() as? String {
75+
let url = source.appending(path: relPath).standardizedFileURL
7876
guard let info = closure(url) else {
7977
continue
8078
}

Tests/CLITests/Subcommands/Build/CLIBuilderTest.swift

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,27 @@ extension TestCLIBuildBase {
9494
#expect(try self.inspectImage(newImageName) == newImageName, "expected to have successfully built \(newImageName)")
9595
}
9696

97+
@Test func testBuildAddFromSpecialDirs() throws {
98+
let tempDir = URL(filePath: "/tmp/container/.clitests" + testUUID)
99+
try! FileManager.default.createDirectory(at: tempDir, withIntermediateDirectories: true)
100+
101+
defer {
102+
try! FileManager.default.removeItem(at: tempDir)
103+
}
104+
105+
let dockerfile: String =
106+
"""
107+
FROM scratch
108+
109+
ADD emptyFile /
110+
"""
111+
let context: [FileSystemEntry] = [.file("emptyFile", content: .zeroFilled(size: 1))]
112+
try createContext(tempDir: tempDir, dockerfile: dockerfile, context: context)
113+
let imageName = "registry.local/scratch-add-special-dir:\(UUID().uuidString)"
114+
try self.build(tag: imageName, tempDir: tempDir)
115+
#expect(try self.inspectImage(imageName) == imageName, "expected to have successfully built \(imageName)")
116+
}
117+
97118
@Test func testBuildScratchAdd() throws {
98119
let tempDir: URL = try createTempDir()
99120
let dockerfile: String =

0 commit comments

Comments
 (0)