Skip to content

Commit 363af15

Browse files
authored
Merge branch 'main' into live-flag-for-container-export
2 parents 0342233 + 984c4c2 commit 363af15

7 files changed

Lines changed: 85 additions & 12 deletions

File tree

Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,8 @@ INTEGRATION_TEST_SUITES ?= \
221221
TestCLISystemDF \
222222
TestCLIMachineCommand \
223223
TestCLIMachineRuntime \
224-
TestCLINoParallelCases
224+
TestCLINoParallelCases \
225+
TestCLICopyCommand
225226

226227
empty :=
227228
space := $(empty) $(empty)

Sources/ContainerCommands/Container/ContainerCopy.swift

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,16 +65,17 @@ extension Application {
6565
switch (srcRef, dstRef) {
6666
case (.container(let id, let path), .local(let localPath)):
6767
let srcPath = FilePath(path)
68-
let destPath = FilePath((localPath as NSString).standardizingPath)
68+
let destPath = FilePath(URL(fileURLWithPath: localPath, relativeTo: .currentDirectory()).absoluteURL.path(percentEncoded: false))
6969
var isDirectory: ObjCBool = false
7070
let exists = FileManager.default.fileExists(atPath: destPath.string, isDirectory: &isDirectory)
7171

72+
var finalDestPath = destPath
7273
if exists && isDirectory.boolValue {
7374
guard let lastComponent = srcPath.lastComponent else {
7475
throw ContainerizationError(.invalidArgument, message: "source path has no last component: \(path)")
7576
}
76-
let finalDest = destPath.appending(lastComponent)
77-
try await client.copyOut(id: id, source: path, destination: finalDest.string)
77+
finalDestPath = destPath.appending(lastComponent)
78+
try await client.copyOut(id: id, source: path, destination: finalDestPath.string)
7879
} else if localPath.hasSuffix("/") {
7980
try await client.copyOut(id: id, source: path, destination: destPath.string)
8081
var resultIsDir: ObjCBool = false
@@ -89,9 +90,15 @@ extension Application {
8990
} else {
9091
try await client.copyOut(id: id, source: path, destination: destPath.string)
9192
}
93+
print(finalDestPath.string)
9294
case (.local(let localPath), .container(let id, let path)):
93-
let srcPath = FilePath((localPath as NSString).standardizingPath)
95+
let srcPath = FilePath(URL(fileURLWithPath: localPath, relativeTo: .currentDirectory()).absoluteURL.path(percentEncoded: false))
9496
var isDirectory: ObjCBool = false
97+
98+
guard let lastComponent = srcPath.lastComponent else {
99+
throw ContainerizationError(.invalidArgument, message: "source path has no last component: \(localPath)")
100+
}
101+
95102
guard FileManager.default.fileExists(atPath: srcPath.string, isDirectory: &isDirectory) else {
96103
throw ContainerizationError(.notFound, message: "source path does not exist: \(localPath)")
97104
}
@@ -100,6 +107,8 @@ extension Application {
100107
}
101108

102109
try await client.copyIn(id: id, source: srcPath.string, destination: path, createParents: true)
110+
let printedDest = path.hasSuffix("/") ? "\(id):\(path)\(lastComponent.string)" : "\(id):\(path)"
111+
print(printedDest)
103112
case (.container, .container):
104113
throw ContainerizationError(.invalidArgument, message: "copying between containers is not supported")
105114
case (.local, .local):

Sources/Services/ContainerAPIService/Client/ProcessIO.swift

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,12 @@ public struct ProcessIO: Sendable {
105105
cc.yield()
106106
return
107107
}
108-
try! pout.write(contentsOf: data)
108+
do {
109+
try pout.write(contentsOf: data)
110+
} catch {
111+
rout.readabilityHandler = nil
112+
cc.yield()
113+
}
109114
}
110115
}
111116

@@ -126,7 +131,12 @@ public struct ProcessIO: Sendable {
126131
cc.yield()
127132
return
128133
}
129-
try! perr.write(contentsOf: data)
134+
do {
135+
try perr.write(contentsOf: data)
136+
} catch {
137+
rerr.readabilityHandler = nil
138+
cc.yield()
139+
}
130140
}
131141
stdio[2] = stderr.fileHandleForWriting
132142
}

Sources/Services/Network/Server/DefaultNetworkService.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -95,13 +95,13 @@ public actor DefaultNetworkService: NetworkService {
9595
}
9696
macAddresses[index] = macAddress
9797

98-
if allocationsBySession[session] == nil {
99-
allocationsBySession[session] = []
98+
let isNewSession = allocationsBySession[session] == nil
99+
allocationsBySession[session, default: []].append((hostname: hostname, index: index))
100+
if isNewSession {
100101
await session.onDisconnect { [weak self] in
101102
await self?.releaseSession(session)
102103
}
103104
}
104-
allocationsBySession[session]!.append((hostname: hostname, index: index))
105105

106106
return (attachment: attachment, additionalData: additionalData)
107107
}

Sources/Services/RuntimeLinux/Server/RuntimeService.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1303,7 +1303,9 @@ public actor RuntimeService {
13031303

13041304
return code
13051305
}
1306-
} catch {}
1306+
} catch {
1307+
self.log.error("graceful stop failed; forcing vm shutdown", metadata: ["error": "\(error)"])
1308+
}
13071309

13081310
// Now actually bring down the vm.
13091311
try await lc.stop()

Tests/CLITests/Subcommands/Containers/TestCLICopy.swift

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -905,4 +905,54 @@ class TestCLICopyCommand: CLITest {
905905
Issue.record("testCopyInDirectoryContentsToExistingDirectoryTrailingSlash failed: \(error)")
906906
}
907907
}
908+
909+
// MARK: - Relative path resolution
910+
911+
@Test func testCopyInRelativeSourcePath() throws {
912+
do {
913+
let name = getTestName()
914+
try doCreate(name: name)
915+
defer { try? doStop(name: name) }
916+
try doStart(name: name)
917+
try waitForContainerRunning(name)
918+
919+
let content = "relative source"
920+
try content.write(to: testDir.appendingPathComponent("relfile.txt"), atomically: true, encoding: .utf8)
921+
922+
let (_, _, error, status) = try run(
923+
arguments: ["copy", "./relfile.txt", "\(name):/tmp/"],
924+
currentDirectory: testDir)
925+
if status != 0 { throw CLIError.executionFailed("copy failed: \(error)") }
926+
927+
let result = try doExec(name: name, cmd: ["cat", "/tmp/relfile.txt"])
928+
#expect(result.trimmingCharacters(in: .whitespacesAndNewlines) == content)
929+
try doStop(name: name)
930+
} catch {
931+
Issue.record("testCopyInRelativeSourcePath failed: \(error)")
932+
}
933+
}
934+
935+
@Test func testCopyOutRelativeDestinationPath() throws {
936+
do {
937+
let name = getTestName()
938+
try doCreate(name: name)
939+
defer { try? doStop(name: name) }
940+
try doStart(name: name)
941+
try waitForContainerRunning(name)
942+
943+
let content = "relative dest"
944+
_ = try doExec(name: name, cmd: ["sh", "-c", "echo -n '\(content)' > /tmp/relfile.txt"])
945+
946+
let (_, _, error, status) = try run(
947+
arguments: ["copy", "\(name):/tmp/relfile.txt", "./"],
948+
currentDirectory: testDir)
949+
if status != 0 { throw CLIError.executionFailed("copy failed: \(error)") }
950+
951+
let result = try String(contentsOfFile: testDir.appendingPathComponent("relfile.txt").path, encoding: .utf8)
952+
#expect(result == content)
953+
try doStop(name: name)
954+
} catch {
955+
Issue.record("testCopyOutRelativeDestinationPath failed: \(error)")
956+
}
957+
}
908958
}

Tests/CLITests/Subcommands/Containers/TestCLIPrune.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ class TestCLIPruneCommand: CLITest {
2323
Test.current!.name.trimmingCharacters(in: ["(", ")"]).lowercased()
2424
}
2525

26-
@Test func testContainerPruneNoContainers() throws {
26+
@Test(.disabled("flaky — prune picks up containers from concurrent suites; tests being rewritten"))
27+
func testContainerPruneNoContainers() throws {
2728
let (_, _, error, status) = try run(arguments: ["prune"])
2829
if status != 0 {
2930
throw CLIError.executionFailed("container prune failed: \(error)")

0 commit comments

Comments
 (0)