Skip to content

Commit df35f79

Browse files
authored
Update container copy to use FilePath (apple#1580)
- Replace `URL` with `FilePath` in `container copy` (apple#1557). In addition, make `copyIn`/`copyOut` API to use `String` for path as we need to preserve the trailing slash to the `LinuxContainer.copy`---i.e., this trailing slash is used in `LinuxContainer.copy` to determine copy behavior.
1 parent 145867e commit df35f79

3 files changed

Lines changed: 23 additions & 23 deletions

File tree

Package.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ let package = Package(
113113
"ContainerRuntimeClient",
114114
"ContainerRuntimeLinuxClient",
115115
"ContainerVersion",
116+
.product(name: "SystemPackage", package: "swift-system"),
116117
"ContainerXPC",
117118
"TerminalProgress",
118119
"Yams",

Sources/ContainerCommands/Container/ContainerCopy.swift

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import ContainerResource
2020
import Containerization
2121
import ContainerizationError
2222
import Foundation
23+
import SystemPackage
2324

2425
extension Application {
2526
public struct ContainerCopy: AsyncLoggableCommand {
@@ -63,40 +64,42 @@ extension Application {
6364

6465
switch (srcRef, dstRef) {
6566
case (.container(let id, let path), .local(let localPath)):
66-
let srcURL = URL(fileURLWithPath: path)
67-
let destURL = URL(fileURLWithPath: localPath).standardizedFileURL
67+
let srcPath = FilePath(path)
68+
let destPath = FilePath((localPath as NSString).standardizingPath)
6869
var isDirectory: ObjCBool = false
69-
let exists = FileManager.default.fileExists(atPath: destURL.path, isDirectory: &isDirectory)
70+
let exists = FileManager.default.fileExists(atPath: destPath.string, isDirectory: &isDirectory)
7071

7172
if exists && isDirectory.boolValue {
72-
let finalDest = destURL.appendingPathComponent(srcURL.lastPathComponent)
73-
try await client.copyOut(id: id, source: srcURL, destination: finalDest)
73+
guard let lastComponent = srcPath.lastComponent else {
74+
throw ContainerizationError(.invalidArgument, message: "source path has no last component: \(path)")
75+
}
76+
let finalDest = destPath.appending(lastComponent)
77+
try await client.copyOut(id: id, source: path, destination: finalDest.string)
7478
} else if localPath.hasSuffix("/") {
75-
try await client.copyOut(id: id, source: srcURL, destination: destURL)
79+
try await client.copyOut(id: id, source: path, destination: destPath.string)
7680
var resultIsDir: ObjCBool = false
77-
if FileManager.default.fileExists(atPath: destURL.path, isDirectory: &resultIsDir),
81+
if FileManager.default.fileExists(atPath: destPath.string, isDirectory: &resultIsDir),
7882
!resultIsDir.boolValue
7983
{
80-
try? FileManager.default.removeItem(at: destURL)
84+
try? FileManager.default.removeItem(atPath: destPath.string)
8185
throw ContainerizationError(
8286
.invalidArgument,
8387
message: "destination is not a directory: \(localPath)")
8488
}
8589
} else {
86-
try await client.copyOut(id: id, source: srcURL, destination: destURL)
90+
try await client.copyOut(id: id, source: path, destination: destPath.string)
8791
}
8892
case (.local(let localPath), .container(let id, let path)):
89-
let srcURL = URL(fileURLWithPath: localPath).standardizedFileURL
93+
let srcPath = FilePath((localPath as NSString).standardizingPath)
9094
var isDirectory: ObjCBool = false
91-
guard FileManager.default.fileExists(atPath: srcURL.path, isDirectory: &isDirectory) else {
95+
guard FileManager.default.fileExists(atPath: srcPath.string, isDirectory: &isDirectory) else {
9296
throw ContainerizationError(.notFound, message: "source path does not exist: \(localPath)")
9397
}
9498
if localPath.hasSuffix("/") && !isDirectory.boolValue {
9599
throw ContainerizationError(.invalidArgument, message: "source path is not a directory: \(localPath)")
96100
}
97101

98-
let destURL = URL(fileURLWithPath: path)
99-
try await client.copyIn(id: id, source: srcURL, destination: destURL, createParents: true)
102+
try await client.copyIn(id: id, source: srcPath.string, destination: path, createParents: true)
100103
case (.container, .container):
101104
throw ContainerizationError(.invalidArgument, message: "copying between containers is not supported")
102105
case (.local, .local):

Sources/Services/ContainerAPIService/Client/ContainerClient.swift

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -312,15 +312,11 @@ public struct ContainerClient: Sendable {
312312
}
313313

314314
/// Copy a file or directory from the host into the container.
315-
public func copyIn(id: String, source: URL, destination: URL, mode: UInt32 = 0o644, createParents: Bool = true) async throws {
315+
public func copyIn(id: String, source: String, destination: String, mode: UInt32 = 0o644, createParents: Bool = true) async throws {
316316
let request = XPCMessage(route: .containerCopyIn)
317-
let destinationPath =
318-
destination.hasDirectoryPath && !destination.path.hasSuffix("/")
319-
? "\(destination.path)/"
320-
: destination.path
321317
request.set(key: .id, value: id)
322-
request.set(key: .sourcePath, value: source.path)
323-
request.set(key: .destinationPath, value: destinationPath)
318+
request.set(key: .sourcePath, value: source)
319+
request.set(key: .destinationPath, value: destination)
324320
request.set(key: .fileMode, value: UInt64(mode))
325321
request.set(key: .createParents, value: createParents)
326322

@@ -336,11 +332,11 @@ public struct ContainerClient: Sendable {
336332
}
337333

338334
/// Copy a file or directory from the container to the host.
339-
public func copyOut(id: String, source: URL, destination: URL, createParents: Bool = true) async throws {
335+
public func copyOut(id: String, source: String, destination: String, createParents: Bool = true) async throws {
340336
let request = XPCMessage(route: .containerCopyOut)
341337
request.set(key: .id, value: id)
342-
request.set(key: .sourcePath, value: source.path)
343-
request.set(key: .destinationPath, value: destination.path)
338+
request.set(key: .sourcePath, value: source)
339+
request.set(key: .destinationPath, value: destination)
344340
request.set(key: .createParents, value: createParents)
345341

346342
do {

0 commit comments

Comments
 (0)