From 3bdfaabb6d590e20531311a8f5b35490535dd9bc Mon Sep 17 00:00:00 2001 From: Chris George Date: Fri, 8 May 2026 15:26:12 -0700 Subject: [PATCH] Use SystemPath for PluginConfig. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert PluginConfig.init from URL to FilePath, following the migration pattern from #1480 (HostDNSResolver), #1518 (PacketFilter), and discussion #1481. - PluginConfig.init?(configURL: URL) → init?(configPath: FilePath) - DefaultPluginFactory.findConfigURL → findConfigPath (returns FilePath?) - Both internal call sites (DefaultPluginFactory, AppBundlePluginFactory) updated; bridge from URL to FilePath stays at the directory boundary since broader PluginFactory conversion is tracked separately. - Tests updated to derive FilePath from temp URL. --- Sources/ContainerPlugin/PluginConfig.swift | 9 +++++---- Sources/ContainerPlugin/PluginFactory.swift | 15 ++++++++------- Tests/ContainerPluginTests/PluginConfigTest.swift | 13 +++++++++---- 3 files changed, 22 insertions(+), 15 deletions(-) diff --git a/Sources/ContainerPlugin/PluginConfig.swift b/Sources/ContainerPlugin/PluginConfig.swift index c7aaf1724..6e667119a 100644 --- a/Sources/ContainerPlugin/PluginConfig.swift +++ b/Sources/ContainerPlugin/PluginConfig.swift @@ -16,6 +16,7 @@ // import Foundation +import SystemPackage import TOML /// PluginConfig details all of the fields to describe and register a plugin. @@ -109,17 +110,17 @@ extension PluginConfig { extension PluginConfig { /// Initialize from a config file, selecting the decoder based on file extension. /// Supports `.toml` (via TOMLDecoder) and `.json` (via JSONDecoder). - public init?(configURL: URL) throws { + public init?(configPath: FilePath) throws { let fm = FileManager.default - if !fm.fileExists(atPath: configURL.path) { + if !fm.fileExists(atPath: configPath.string) { return nil } - guard let data = fm.contents(atPath: configURL.path) else { + guard let data = fm.contents(atPath: configPath.string) else { return nil } - switch configURL.pathExtension { + switch configPath.extension { case "toml": guard let content = String(data: data, encoding: .utf8) else { return nil diff --git a/Sources/ContainerPlugin/PluginFactory.swift b/Sources/ContainerPlugin/PluginFactory.swift index 2a9998b6f..9e76f7773 100644 --- a/Sources/ContainerPlugin/PluginFactory.swift +++ b/Sources/ContainerPlugin/PluginFactory.swift @@ -16,6 +16,7 @@ import Foundation import Logging +import SystemPackage /// Describes the configuration and binary file locations for a plugin. public protocol PluginFactory: Sendable { @@ -35,8 +36,8 @@ public struct DefaultPluginFactory: PluginFactory { self.logger = logger } - /// Returns the URL of the first config file found in `directory`, preferring TOML over JSON. - static func findConfigURL(in directory: URL, logger: Logger) -> URL? { + /// Returns the path of the first config file found in `directory`, preferring TOML over JSON. + static func findConfigPath(in directory: URL, logger: Logger) -> FilePath? { let fm = FileManager.default for filename in configFilenames { let url = directory.appending(path: filename) @@ -47,7 +48,7 @@ public struct DefaultPluginFactory: PluginFactory { metadata: ["path": "\(url.path)"] ) } - return url + return FilePath(url.path) } } return nil @@ -56,11 +57,11 @@ public struct DefaultPluginFactory: PluginFactory { public func create(installURL: URL) throws -> Plugin? { let fm = FileManager.default - guard let configURL = Self.findConfigURL(in: installURL, logger: logger) else { + guard let configPath = Self.findConfigPath(in: installURL, logger: logger) else { return nil } - guard let config = try PluginConfig(configURL: configURL) else { + guard let config = try PluginConfig(configPath: configPath) else { return nil } @@ -99,11 +100,11 @@ public struct AppBundlePluginFactory: PluginFactory { .appending(path: "Contents") .appending(path: "Resources") - guard let configURL = DefaultPluginFactory.findConfigURL(in: contentResources, logger: logger) else { + guard let configPath = DefaultPluginFactory.findConfigPath(in: contentResources, logger: logger) else { return nil } - guard let config = try PluginConfig(configURL: configURL) else { + guard let config = try PluginConfig(configPath: configPath) else { return nil } diff --git a/Tests/ContainerPluginTests/PluginConfigTest.swift b/Tests/ContainerPluginTests/PluginConfigTest.swift index 588049292..163e031be 100644 --- a/Tests/ContainerPluginTests/PluginConfigTest.swift +++ b/Tests/ContainerPluginTests/PluginConfigTest.swift @@ -15,6 +15,7 @@ //===----------------------------------------------------------------------===// import Foundation +import SystemPackage import Testing @testable import ContainerPlugin @@ -35,7 +36,8 @@ struct PluginConfigTest { author = "Apple" """ try configToml.write(to: configURL, atomically: true, encoding: .utf8) - let config = try #require(try PluginConfig(configURL: configURL)) + let configPath = FilePath(configURL.path) + let config = try #require(try PluginConfig(configPath: configPath)) #expect(config.isCLI) #expect(config.abstract == "Default network management service") @@ -67,7 +69,8 @@ struct PluginConfigTest { description = "foo" """ try configToml.write(to: configURL, atomically: true, encoding: .utf8) - let config = try #require(try PluginConfig(configURL: configURL)) + let configPath = FilePath(configURL.path) + let config = try #require(try PluginConfig(configPath: configPath)) #expect(!config.isCLI) #expect(config.abstract == "Default network management service") @@ -97,8 +100,9 @@ struct PluginConfigTest { [invalid """ try malformedToml.write(to: configURL, atomically: true, encoding: .utf8) + let configPath = FilePath(configURL.path) #expect(throws: (any Error).self) { - try PluginConfig(configURL: configURL) + try PluginConfig(configPath: configPath) } } @@ -117,7 +121,8 @@ struct PluginConfigTest { author: "Apple" """ try content.write(to: configURL, atomically: true, encoding: .utf8) - let config = try PluginConfig(configURL: configURL) + let configPath = FilePath(configURL.path) + let config = try PluginConfig(configPath: configPath) #expect(config == nil) } }