Skip to content

Commit 5d8ae67

Browse files
authored
fix: fixed Path deprecation warnings in package plugin (#140)
1 parent cc5416f commit 5d8ae67

File tree

143 files changed

+729
-589
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

143 files changed

+729
-589
lines changed

Plugins/MetaProtocolCodable/Config.swift

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,15 +80,56 @@ extension Config: Codable {
8080
/// - Returns: The file path URL.
8181
static func url(forFilePath filePath: String) -> URL {
8282
#if canImport(Darwin)
83-
if #available(macOS 13, iOS 16, macCatalyst 16, tvOS 16, watchOS 9, *) {
84-
return URL(filePath: filePath)
85-
} else {
83+
guard
84+
#available(macOS 13, iOS 16, macCatalyst 16, tvOS 16, watchOS 9, *)
85+
else {
8686
return URL(fileURLWithPath: filePath)
8787
}
88+
return URL(filePath: filePath)
8889
#else
8990
return URL(fileURLWithPath: filePath)
9091
#endif
9192
}
93+
94+
/// Returns file path as string converting provided URL.
95+
///
96+
/// Uses platform and version specific API to create string file path.
97+
///
98+
/// - Parameter url: The path to file as URL.
99+
/// - Returns: The file path string.
100+
static func filePath(forURL url: URL) -> String {
101+
#if canImport(Darwin)
102+
guard
103+
#available(macOS 13, iOS 16, macCatalyst 16, tvOS 16, watchOS 9, *)
104+
else {
105+
return url.path
106+
}
107+
return url.path(percentEncoded: false)
108+
#else
109+
return url.path
110+
#endif
111+
}
112+
113+
/// Returns a URL by appending the specified path to the URL.
114+
///
115+
/// This method doesn’t percent-encode any path separators.
116+
///
117+
/// - Parameters:
118+
/// - path: The path component to append to the URL.
119+
/// - url: The base URL to which the path will be appended.
120+
/// - Returns: A new URL with the path component appended.
121+
static func appending(path: String, to url: URL) -> URL {
122+
#if canImport(Darwin)
123+
guard
124+
#available(macOS 13, iOS 16, macCatalyst 16, tvOS 16, watchOS 9, *)
125+
else {
126+
return url.appendingPathComponent(path)
127+
}
128+
return url.appending(path: path)
129+
#else
130+
return url.appendingPathComponent(path)
131+
#endif
132+
}
92133
}
93134

94135
extension KeyedDecodingContainerProtocol {
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
import Foundation
2+
import PackagePlugin
3+
4+
#if swift(<6)
5+
extension PluginContext.Tool {
6+
/// Full path of the built or provided tool in the file system.
7+
var url: URL {
8+
Config.url(forFilePath: path.string)
9+
}
10+
}
11+
12+
extension PackagePlugin.File {
13+
/// The path of the file.
14+
var url: URL {
15+
Config.url(forFilePath: path.string)
16+
}
17+
}
18+
19+
extension PluginContext {
20+
/// The path of a writable directory into which the plugin or the build
21+
/// commands it constructs can write anything it wants. This could include
22+
/// any generated source files that should be processed further, and it
23+
/// could include any caches used by the build tool or the plugin itself.
24+
/// The plugin is in complete control of what is written under this di-
25+
/// rectory, and the contents are preserved between builds.
26+
///
27+
/// A plugin would usually create a separate subdirectory of this directory
28+
/// for each command it creates, and the command would be configured to
29+
/// write its outputs to that directory. The plugin may also create other
30+
/// directories for cache files and other file system content that either
31+
/// it or the command will need.
32+
var pluginWorkDirectoryURL: URL {
33+
Config.url(forFilePath: pluginWorkDirectory.string)
34+
}
35+
}
36+
37+
extension Command {
38+
/// Returns a command that runs when any of its output files are needed by
39+
/// the build, but out-of-date.
40+
///
41+
/// An output file is out-of-date if it doesn't exist, or if any input files
42+
/// have changed since the command was last run.
43+
///
44+
/// - Note: the paths in the list of output files may depend on the list of
45+
/// input file paths, but **must not** depend on reading the contents of
46+
/// any input files. Such cases must be handled using a `prebuildCommand`.
47+
///
48+
/// - parameters:
49+
/// - displayName: An optional string to show in build logs and other
50+
/// status areas.
51+
/// - executable: The absolute path to the executable to be invoked.
52+
/// - arguments: Command-line arguments to be passed to the executable.
53+
/// - environment: Environment variable assignments visible to the
54+
/// executable.
55+
/// - inputFiles: Files on which the contents of output files may depend.
56+
/// Any paths passed as `arguments` should typically be passed here as
57+
/// well.
58+
/// - outputFiles: Files to be generated or updated by the executable.
59+
/// Any files recognizable by their extension as source files
60+
/// (e.g. `.swift`) are compiled into the target for which this command
61+
/// was generated as if in its source directory; other files are treated
62+
/// as resources as if explicitly listed in `Package.swift` using
63+
/// `.process(...)`.
64+
static func buildCommand(
65+
displayName: String?, executable: URL, arguments: [String],
66+
environment: [String: String] = [:], inputFiles: [URL] = [],
67+
outputFiles: [URL] = []
68+
) -> Self {
69+
.buildCommand(
70+
displayName: displayName,
71+
executable: .init(Config.filePath(forURL: executable)),
72+
arguments: arguments,
73+
environment: environment,
74+
inputFiles: inputFiles.map { .init(Config.filePath(forURL: $0)) },
75+
outputFiles: outputFiles.map { .init(Config.filePath(forURL: $0)) }
76+
)
77+
}
78+
}
79+
80+
#if canImport(XcodeProjectPlugin)
81+
extension XcodePluginContext {
82+
/// The path of a writable directory into which the plugin or the build
83+
/// commands it constructs can write anything it wants. This could include
84+
/// any generated source files that should be processed further, and it
85+
/// could include any caches used by the build tool or the plugin itself.
86+
/// The plugin is in complete control of what is written under this di-
87+
/// rectory, and the contents are preserved between builds.
88+
///
89+
/// A plugin would usually create a separate subdirectory of this directory
90+
/// for each command it creates, and the command would be configured to
91+
/// write its outputs to that directory. The plugin may also create other
92+
/// directories for cache files and other file system content that either
93+
/// it or the command will need.
94+
var pluginWorkDirectoryURL: URL {
95+
Config.url(forFilePath: pluginWorkDirectory.string)
96+
}
97+
}
98+
#endif
99+
#endif
100+
101+
extension SourceModuleTarget {
102+
/// The absolute path of the target directory in the local file system.
103+
var directoryURL: URL {
104+
#if swift(<6)
105+
return Config.url(forFilePath: directory.string)
106+
#else
107+
switch self {
108+
case let target as ClangSourceModuleTarget:
109+
return target.directoryURL
110+
case let target as SwiftSourceModuleTarget:
111+
return target.directoryURL
112+
default:
113+
fatalError("Unsupported target type")
114+
}
115+
#endif
116+
}
117+
}

Plugins/MetaProtocolCodable/Plugin.swift

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,8 @@ struct MetaProtocolCodable: BuildToolPlugin {
2020
func fetchConfig<Target: MetaProtocolCodableSourceTarget>(
2121
for target: Target
2222
) throws -> Config {
23-
let pathStr = try target.configPath(named: "metacodableconfig")
24-
guard let pathStr else { return .init(scan: .target) }
25-
let path = Config.url(forFilePath: pathStr)
23+
let path = try target.configPath(named: "metacodableconfig")
24+
guard let path = path else { return .init(scan: .target) }
2625
let conf = try Data(contentsOf: path)
2726
let pConf = try? PropertyListDecoder().decode(Config.self, from: conf)
2827
let config = try pConf ?? JSONDecoder().decode(Config.self, from: conf)
@@ -50,32 +49,35 @@ struct MetaProtocolCodable: BuildToolPlugin {
5049
let (allTargets, imports) = config.scanInput(for: target, in: context)
5150

5251
// Setup folder
53-
let genFolder = context.pluginWorkDirectory.appending(["ProtocolGen"])
52+
let genFolder = Config.appending(
53+
path: "ProtocolGen", to: context.pluginWorkDirectoryURL
54+
)
5455
try FileManager.default.createDirectory(
55-
atPath: genFolder.string, withIntermediateDirectories: true
56+
at: genFolder, withIntermediateDirectories: true
5657
)
5758

5859
// Create source scan commands
59-
var intermFiles: [Path] = []
60+
var intermFiles: [URL] = []
6061
var buildCommands = allTargets.flatMap { target in
6162
return target.sourceFiles(withSuffix: "swift").map { file in
6263
let moduleName = target.moduleName
63-
let fileName = file.path.stem
64+
let fileName = file.url.deletingPathExtension()
65+
.lastPathComponent
6466
let genFileName = "\(moduleName)-\(fileName)-gen.json"
65-
let genFile = genFolder.appending([genFileName])
67+
let genFile = Config.appending(path: genFileName, to: genFolder)
6668
intermFiles.append(genFile)
6769
return Command.buildCommand(
6870
displayName: """
6971
Parse source file "\(fileName)" in module "\(moduleName)"
7072
""",
71-
executable: tool.path,
73+
executable: tool.url,
7274
arguments: [
7375
"parse",
74-
file.path.string,
76+
Config.filePath(forURL: file.url),
7577
"--output",
76-
genFile.string,
78+
Config.filePath(forURL: genFile),
7779
],
78-
inputFiles: [file.path],
80+
inputFiles: [file.url],
7981
outputFiles: [genFile]
8082
)
8183
}
@@ -84,20 +86,22 @@ struct MetaProtocolCodable: BuildToolPlugin {
8486
// Create syntax generation command
8587
let moduleName = target.moduleName
8688
let genFileName = "\(moduleName)+ProtocolHelperCoders.swift"
87-
let genPath = genFolder.appending(genFileName)
88-
var genArgs = ["generate", "--output", genPath.string]
89+
let genPath = Config.appending(path: genFileName, to: genFolder)
90+
var genArgs = [
91+
"generate", "--output", Config.filePath(forURL: genPath),
92+
]
8993
for `import` in imports {
9094
genArgs.append(contentsOf: ["--module", `import`])
9195
}
9296
for file in intermFiles {
93-
genArgs.append(file.string)
97+
genArgs.append(Config.filePath(forURL: file))
9498
}
9599
buildCommands.append(
96100
.buildCommand(
97101
displayName: """
98102
Generate protocol decoding/encoding syntax for "\(moduleName)"
99103
""",
100-
executable: tool.path,
104+
executable: tool.url,
101105
arguments: genArgs,
102106
inputFiles: intermFiles,
103107
outputFiles: [genPath]
@@ -147,7 +151,7 @@ extension MetaProtocolCodable: XcodeBuildToolPlugin {
147151
func createBuildCommands(
148152
context: XcodePluginContext, target: XcodeTarget
149153
) throws -> [Command] {
150-
return try self.createBuildCommands(
154+
try self.createBuildCommands(
151155
in: context, for: target
152156
)
153157
}

Plugins/MetaProtocolCodable/PluginContext.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import Foundation
12
import PackagePlugin
23

34
/// Provides information about the package for which the plugin is invoked,
@@ -23,7 +24,7 @@ protocol MetaProtocolCodablePluginContext {
2324
/// write its outputs to that directory. The plugin may also create other
2425
/// directories for cache files and other file system content that either
2526
/// it or the command will need.
26-
var pluginWorkDirectory: Path { get }
27+
var pluginWorkDirectoryURL: URL { get }
2728
/// The targets which are local to current context.
2829
///
2930
/// These targets are included in the same package/project as this context.
@@ -45,7 +46,7 @@ extension PluginContext: MetaProtocolCodablePluginContext {
4546
///
4647
/// Includes all the source code targets of the package.
4748
var localTargets: [SwiftPackageTarget] {
48-
return `package`.targets.compactMap { target in
49+
`package`.targets.compactMap { target in
4950
guard let sourceModule = target.sourceModule else { return nil }
5051
return SwiftPackageTarget(module: sourceModule)
5152
}

Plugins/MetaProtocolCodable/SourceTarget/MetaProtocolCodableSourceTarget.swift

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import Foundation
12
import PackagePlugin
23

34
/// Represents a target consisting of a source code module,
@@ -42,7 +43,7 @@ protocol MetaProtocolCodableSourceTarget {
4243
///
4344
/// - Parameter name: The config file name.
4445
/// - Returns: The config file path.
45-
func configPath(named name: String) throws -> String?
46+
func configPath(named name: String) throws -> URL?
4647
}
4748

4849
extension Config {
@@ -71,12 +72,12 @@ extension Config {
7172
allTargets = targets
7273
case .local:
7374
allTargets = context.localTargets.filter { localTarget in
74-
return target.recursiveTargets.contains { target in
75-
return target.moduleName == localTarget.moduleName
75+
target.recursiveTargets.contains { target in
76+
target.moduleName == localTarget.moduleName
7677
}
7778
}
7879
modules = allTargets.lazy.map(\.moduleName).filter { module in
79-
return module != target.moduleName
80+
module != target.moduleName
8081
}
8182
case .recursive:
8283
var targets = target.recursiveTargets

Plugins/MetaProtocolCodable/SourceTarget/SwiftPackageTarget.swift

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ extension SwiftPackageTarget: MetaProtocolCodableSourceTarget {
2222
///
2323
/// Represents direct dependencies of the target.
2424
var dependencyTargets: [Self] {
25-
return module.dependencies.lazy.compactMap { dependency in
25+
module.dependencies.lazy.compactMap { dependency in
2626
return switch dependency {
2727
case .target(let target):
2828
target.sourceModule
@@ -36,7 +36,7 @@ extension SwiftPackageTarget: MetaProtocolCodableSourceTarget {
3636
///
3737
/// Represents direct and transient dependencies of the target.
3838
var recursiveTargets: [Self] {
39-
return module.recursiveTargetDependencies.lazy
39+
module.recursiveTargetDependencies.lazy
4040
.compactMap { $0.sourceModule }
4141
.map { Self.init(module: $0) }
4242
}
@@ -49,7 +49,7 @@ extension SwiftPackageTarget: MetaProtocolCodableSourceTarget {
4949
/// - Parameter suffix: The name suffix.
5050
/// - Returns: The matching files.
5151
func sourceFiles(withSuffix suffix: String) -> FileList {
52-
return module.sourceFiles(withSuffix: suffix)
52+
module.sourceFiles(withSuffix: suffix)
5353
}
5454

5555
/// The absolute path to config file if provided.
@@ -62,19 +62,18 @@ extension SwiftPackageTarget: MetaProtocolCodableSourceTarget {
6262
///
6363
/// - Parameter name: The config file name.
6464
/// - Returns: The config file path.
65-
func configPath(named name: String) throws -> String? {
65+
func configPath(named name: String) throws -> URL? {
6666
let fileManager = FileManager.default
67-
let directory = module.directory.string
68-
let contents = try fileManager.contentsOfDirectory(atPath: directory)
69-
let file = contents.first { file in
70-
let path = Path(file)
71-
return name.lowercased()
72-
== path.stem
67+
let directory = module.directoryURL
68+
let contents = try fileManager.contentsOfDirectory(
69+
at: directory, includingPropertiesForKeys: nil
70+
)
71+
return contents.first { file in
72+
name.lowercased()
73+
== file.deletingPathExtension().lastPathComponent
7374
.components(separatedBy: .alphanumerics.inverted)
7475
.joined(separator: "")
7576
.lowercased()
7677
}
77-
guard let file else { return nil }
78-
return module.directory.appending([file]).string
7978
}
8079
}

0 commit comments

Comments
 (0)