Skip to content

Commit 77ed6c5

Browse files
authored
volumes: Allow "." (#1326)
We should allow passing . for the src of a volume.
1 parent f8ba57e commit 77ed6c5

File tree

2 files changed

+44
-2
lines changed

2 files changed

+44
-2
lines changed

Sources/Services/ContainerAPIService/Client/Parser.swift

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

518-
// Check if it's a filesystem path
519-
guard src.contains("/") else {
518+
// Check if it's a filesystem path (absolute, or relative like ".", "..", "./foo", "../foo")
519+
guard src.contains("/") || src == "." || src == ".." else {
520520
// Named volume - validate name syntax only
521521
guard VolumeStorage.isValidVolumeName(src) else {
522522
throw ContainerizationError(.invalidArgument, message: "invalid volume name '\(src)': must match \(VolumeStorage.volumeNamePattern)")

Tests/ContainerAPIClientTests/ParserTest.swift

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,48 @@ struct ParserTest {
392392
#expect(Bool(false), "Expected filesystem mount, got volume")
393393
}
394394
}
395+
396+
// Test volume with bare "." as source (current directory)
397+
do {
398+
let tempDir = FileManager.default.temporaryDirectory.appendingPathComponent("test-volume-dot-\(UUID().uuidString)")
399+
try FileManager.default.createDirectory(at: tempDir, withIntermediateDirectories: true)
400+
defer {
401+
try? FileManager.default.removeItem(at: tempDir)
402+
}
403+
404+
let result = try Parser.volume(".:/docs:ro", relativeTo: tempDir)
405+
406+
switch result {
407+
case .filesystem(let fs):
408+
let expectedPath = tempDir.standardizedFileURL.path
409+
#expect(fs.source.trimmingCharacters(in: CharacterSet(charactersIn: "/")) == expectedPath.trimmingCharacters(in: CharacterSet(charactersIn: "/")))
410+
#expect(fs.destination == "/docs")
411+
#expect(fs.options.contains("ro"))
412+
case .volume:
413+
#expect(Bool(false), "Expected filesystem mount, got volume")
414+
}
415+
}
416+
417+
// Test volume with ".." as source (parent directory)
418+
do {
419+
let tempDir = FileManager.default.temporaryDirectory.appendingPathComponent("test-volume-dotdot-\(UUID().uuidString)")
420+
let childDir = tempDir.appendingPathComponent("child")
421+
try FileManager.default.createDirectory(at: childDir, withIntermediateDirectories: true)
422+
defer {
423+
try? FileManager.default.removeItem(at: tempDir)
424+
}
425+
426+
let result = try Parser.volume("..:/data", relativeTo: childDir)
427+
428+
switch result {
429+
case .filesystem(let fs):
430+
let expectedPath = tempDir.standardizedFileURL.path
431+
#expect(fs.source.trimmingCharacters(in: CharacterSet(charactersIn: "/")) == expectedPath.trimmingCharacters(in: CharacterSet(charactersIn: "/")))
432+
#expect(fs.destination == "/data")
433+
case .volume:
434+
#expect(Bool(false), "Expected filesystem mount, got volume")
435+
}
436+
}
395437
}
396438

397439
@Test

0 commit comments

Comments
 (0)