diff --git a/Sources/Plugins/CoreImages/ImagesHelper.swift b/Sources/Plugins/CoreImages/ImagesHelper.swift index 6ba3318b5..656b9265a 100644 --- a/Sources/Plugins/CoreImages/ImagesHelper.swift +++ b/Sources/Plugins/CoreImages/ImagesHelper.swift @@ -25,6 +25,7 @@ import ContainerXPC import Containerization import Foundation import Logging +import SystemPackage @main struct ImagesHelper: AsyncParsableCommand { @@ -113,7 +114,7 @@ extension ImagesHelper { } private func initializeContentService(root: URL, log: Logger, routes: inout [String: XPCServer.RouteHandler]) throws { - let service = try ContentStoreService(root: root, log: log) + let service = try ContentStoreService(root: FilePath(root.path(percentEncoded: false)), log: log) let harness = ContentServiceHarness(service: service, log: log) routes[ImagesServiceXPCRoute.contentClean.rawValue] = XPCServer.route(harness.clean) diff --git a/Sources/Services/ContainerImagesService/Client/RemoteContentStoreClient.swift b/Sources/Services/ContainerImagesService/Client/RemoteContentStoreClient.swift index 9c92c4d0e..0e15fc5a2 100644 --- a/Sources/Services/ContainerImagesService/Client/RemoteContentStoreClient.swift +++ b/Sources/Services/ContainerImagesService/Client/RemoteContentStoreClient.swift @@ -20,6 +20,7 @@ import ContainerizationError import Foundation import ContainerizationOCI import ContainerXPC +import SystemPackage public struct RemoteContentStoreClient: ContentStore { private static let serviceIdentifier = "com.apple.container.core.container-core-images" @@ -31,7 +32,7 @@ public struct RemoteContentStoreClient: ContentStore { public init() {} - private func _get(digest: String) async throws -> URL? { + private func _get(digest: String) async throws -> FilePath? { let client = Self.newClient() let request = XPCMessage(route: .contentGet) request.set(key: .digest, value: digest) @@ -40,7 +41,7 @@ public struct RemoteContentStoreClient: ContentStore { guard let path = response.string(key: .contentPath) else { return nil } - return URL(filePath: path) + return FilePath(path) } catch let error as ContainerizationError { if error.code == .notFound { return nil @@ -50,10 +51,11 @@ public struct RemoteContentStoreClient: ContentStore { } public func get(digest: String) async throws -> Content? { - guard let url = try await self._get(digest: digest) else { + guard let path = try await self._get(digest: digest) else { return nil } - return try LocalContent(path: url) + // LocalContent is defined upstream in Containerization and only accepts URL. + return try LocalContent(path: URL(filePath: path.string)) } public func get(digest: String) async throws -> T? { diff --git a/Sources/Services/ContainerImagesService/Server/ContentServiceHarness.swift b/Sources/Services/ContainerImagesService/Server/ContentServiceHarness.swift index f9a3ea377..d2e1544cb 100644 --- a/Sources/Services/ContainerImagesService/Server/ContentServiceHarness.swift +++ b/Sources/Services/ContainerImagesService/Server/ContentServiceHarness.swift @@ -43,7 +43,7 @@ public struct ContentServiceHarness: Sendable { return reply } let reply = message.reply() - reply.set(key: .contentPath, value: path.path(percentEncoded: false)) + reply.set(key: .contentPath, value: path.string) return reply } @@ -83,7 +83,7 @@ public struct ContentServiceHarness: Sendable { let id = session.id let dir = session.ingestDir let reply = message.reply() - reply.set(key: .directory, value: dir.path(percentEncoded: false)) + reply.set(key: .directory, value: dir.string) reply.set(key: .ingestSessionId, value: id) return reply } diff --git a/Sources/Services/ContainerImagesService/Server/ContentStoreService.swift b/Sources/Services/ContainerImagesService/Server/ContentStoreService.swift index 9332428b9..26ecd13e5 100644 --- a/Sources/Services/ContainerImagesService/Server/ContentStoreService.swift +++ b/Sources/Services/ContainerImagesService/Server/ContentStoreService.swift @@ -19,20 +19,22 @@ import Containerization import ContainerizationOCI import Foundation import Logging +import SystemPackage public actor ContentStoreService { private let log: Logger private let contentStore: LocalContentStore - private let root: URL + private let root: FilePath - public init(root: URL, log: Logger) throws { - try FileManager.default.createDirectory(at: root, withIntermediateDirectories: true) - self.root = root.appendingPathComponent("content") - self.contentStore = try LocalContentStore(path: self.root) + public init(root: FilePath, log: Logger) throws { + try FileManager.default.createDirectory(atPath: root.string, withIntermediateDirectories: true) + self.root = root.appending("content") + // LocalContentStore is defined upstream in Containerization and only accepts URL. + self.contentStore = try LocalContentStore(path: URL(filePath: self.root.string)) self.log = log } - public func get(digest: String) async throws -> URL? { + public func get(digest: String) async throws -> FilePath? { self.log.trace( "ContentStoreService: enter", metadata: [ @@ -50,7 +52,10 @@ public actor ContentStoreService { ) } - return try await self.contentStore.get(digest: digest)?.path + guard let url = try await self.contentStore.get(digest: digest)?.path else { + return nil + } + return FilePath(url.path(percentEncoded: false)) } @discardableResult @@ -97,7 +102,7 @@ public actor ContentStoreService { return try await self.contentStore.delete(keeping: keeping) } - public func newIngestSession() async throws -> (id: String, ingestDir: URL) { + public func newIngestSession() async throws -> (id: String, ingestDir: FilePath) { self.log.debug( "ContentStoreService: enter", metadata: [ @@ -112,7 +117,8 @@ public actor ContentStoreService { ] ) } - return try await self.contentStore.newIngestSession() + let session = try await self.contentStore.newIngestSession() + return (session.id, FilePath(session.ingestDir.path(percentEncoded: false))) } public func completeIngestSession(_ id: String) async throws -> [String] {