Skip to content

Commit 20dc0bc

Browse files
authored
Parser: Support relative paths for --volume (apple#1013)
1 parent 028e7e1 commit 20dc0bc

File tree

2 files changed

+57
-2
lines changed

2 files changed

+57
-2
lines changed

Sources/ContainerClient/Parser.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -487,8 +487,8 @@ public struct Parser {
487487
let src = String(parts[0])
488488
let dst = String(parts[1])
489489

490-
// Check if it's an absolute directory path first
491-
guard src.hasPrefix("/") else {
490+
// Check if it's a filesystem path
491+
guard src.contains("/") else {
492492
// Named volume - validate name syntax only
493493
guard VolumeStorage.isValidVolumeName(src) else {
494494
throw ContainerizationError(.invalidArgument, message: "invalid volume name '\(src)': must match \(VolumeStorage.volumeNamePattern)")

Tests/ContainerClientTests/ParserTest.swift

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,61 @@ struct ParserTest {
382382
}
383383
}
384384

385+
@Test
386+
func testVolumeRelativePath() throws {
387+
let tempDir = FileManager.default.temporaryDirectory.appendingPathComponent("test-volume-rel-\(UUID().uuidString)")
388+
try FileManager.default.createDirectory(at: tempDir, withIntermediateDirectories: true)
389+
defer {
390+
try? FileManager.default.removeItem(at: tempDir)
391+
}
392+
393+
let originalDir = FileManager.default.currentDirectoryPath
394+
FileManager.default.changeCurrentDirectoryPath(tempDir.path)
395+
defer {
396+
FileManager.default.changeCurrentDirectoryPath(originalDir)
397+
}
398+
399+
let result = try Parser.volume("./:/foo")
400+
401+
switch result {
402+
case .filesystem(let fs):
403+
let expectedPath = URL(filePath: ".").absoluteURL.path
404+
// Normalize trailing slashes for comparison
405+
#expect(fs.source.trimmingCharacters(in: CharacterSet(charactersIn: "/")) == expectedPath.trimmingCharacters(in: CharacterSet(charactersIn: "/")))
406+
#expect(fs.destination == "/foo")
407+
case .volume:
408+
#expect(Bool(false), "Expected filesystem mount, got volume")
409+
}
410+
}
411+
412+
@Test
413+
func testVolumeRelativePathNested() throws {
414+
let tempDir = FileManager.default.temporaryDirectory.appendingPathComponent("test-volume-rel-nested-\(UUID().uuidString)")
415+
let nestedDir = tempDir.appendingPathComponent("subdir")
416+
try FileManager.default.createDirectory(at: nestedDir, withIntermediateDirectories: true)
417+
defer {
418+
try? FileManager.default.removeItem(at: tempDir)
419+
}
420+
421+
let originalDir = FileManager.default.currentDirectoryPath
422+
FileManager.default.changeCurrentDirectoryPath(tempDir.path)
423+
defer {
424+
FileManager.default.changeCurrentDirectoryPath(originalDir)
425+
}
426+
427+
let result = try Parser.volume("./subdir:/foo")
428+
429+
switch result {
430+
case .filesystem(let fs):
431+
let expectedPath = URL(filePath: "./subdir").absoluteURL.path
432+
// Normalize trailing slashes for comparison
433+
#expect(fs.source.trimmingCharacters(in: CharacterSet(charactersIn: "/")) == expectedPath.trimmingCharacters(in: CharacterSet(charactersIn: "/")))
434+
#expect(fs.destination == "/foo")
435+
case .volume:
436+
#expect(Bool(false), "Expected filesystem mount, got volume")
437+
}
438+
}
439+
385440
@Test
386441
func testIsValidDomainNameOk() throws {
387442
let names = [

0 commit comments

Comments
 (0)