Skip to content

Commit 18d1452

Browse files
committed
Consolidate plugin accessible tools
Until now, we had two almost identical code paths for processing accessible tools and e.g. the command plugin code didn't get the fixes from #5945. This PR consolidates the two and also fixes a bug regarding executable path handling of vended tools.
1 parent dd7e9cc commit 18d1452

File tree

3 files changed

+40
-40
lines changed

3 files changed

+40
-40
lines changed

Sources/Commands/PackageTools/PluginCommand.swift

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -160,22 +160,14 @@ struct PluginCommand: SwiftCommand {
160160
+ getEnvSearchPaths(pathString: ProcessEnv.path, currentWorkingDirectory: .none)
161161

162162
// Build or bring up-to-date any executable host-side tools on which this plugin depends. Add them and any binary dependencies to the tool-names-to-path map.
163-
var toolNamesToPaths: [String: AbsolutePath] = [:]
164-
// Add supported triples info per tool so they can be looked up when running the tool
165-
var toolNamesToTriples: [String: [String]] = [:]
166-
for dep in try plugin.accessibleTools(packageGraph: packageGraph, fileSystem: swiftTool.fileSystem, environment: try swiftTool.buildParameters().buildEnvironment, for: try pluginScriptRunner.hostTriple) {
163+
let (toolNamesToPaths, toolNamesToTriples) = try plugin.processAccessibleTools(packageGraph: packageGraph, fileSystem: swiftTool.fileSystem, environment: try swiftTool.buildParameters().buildEnvironment, for: try pluginScriptRunner.hostTriple) { name, path in
167164
let buildSystem = try swiftTool.createBuildSystem(explicitBuildSystem: .native, cacheBuildManifest: false)
168-
switch dep {
169-
case .builtTool(let name, _):
170-
// Build the product referenced by the tool, and add the executable to the tool map. Product dependencies are not supported within a package, so if the tool happens to be from the same package, we instead find the executable that corresponds to the product. There is always one, because of autogeneration of implicit executables with the same name as the target if there isn't an explicit one.
171-
try buildSystem.build(subset: .product(name))
172-
if let builtTool = try buildSystem.buildPlan.buildProducts.first(where: { $0.product.name == name}) {
173-
toolNamesToPaths[name] = builtTool.binaryPath
174-
}
175-
case .vendedTool(let name, let path, let triples):
176-
toolNamesToPaths[name] = path
177-
// Need triples info for .vendedTool
178-
toolNamesToTriples[name] = triples
165+
// Build the product referenced by the tool, and add the executable to the tool map. Product dependencies are not supported within a package, so if the tool happens to be from the same package, we instead find the executable that corresponds to the product. There is always one, because of autogeneration of implicit executables with the same name as the target if there isn't an explicit one.
166+
try buildSystem.build(subset: .product(name))
167+
if let builtTool = try buildSystem.buildPlan.buildProducts.first(where: { $0.product.name == name}) {
168+
return builtTool.binaryPath
169+
} else {
170+
return nil
179171
}
180172
}
181173

Sources/SPMBuildCore/PluginInvocation.swift

Lines changed: 30 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -364,33 +364,15 @@ extension PackageGraph {
364364
for pluginTarget in pluginTargets {
365365
// Determine the tools to which this plugin has access, and create a name-to-path mapping from tool
366366
// names to the corresponding paths. Built tools are assumed to be in the build tools directory.
367-
let accessibleTools = try pluginTarget.accessibleTools(packageGraph: self, fileSystem: fileSystem, environment: buildEnvironment, for: try pluginScriptRunner.hostTriple)
368-
let toolNamesToPaths = accessibleTools.reduce(into: [String: AbsolutePath](), { dict, tool in
369-
switch tool {
370-
case .builtTool(let name, let path):
371-
dict[name] = builtToolsDir.appending(path)
372-
case .vendedTool(let name, let path, _):
373-
dict[name] = path
374-
}
375-
})
376-
let builtToolNames = accessibleTools.compactMap { (accTool) -> String? in
377-
if case .builtTool(let name, _) = accTool {
378-
return name
379-
}
380-
return nil
367+
var builtToolNames: [String] = []
368+
let (toolNamesToPaths, toolNamesToTriples) = try pluginTarget.processAccessibleTools(packageGraph: self, fileSystem: fileSystem, environment: buildEnvironment, for: try pluginScriptRunner.hostTriple) { name, path in
369+
builtToolNames.append(name)
370+
return builtToolsDir.appending(path)
381371
}
382372

383373
// Determine additional input dependencies for any plugin commands, based on any executables the plugin target depends on.
384374
let toolPaths = toolNamesToPaths.values.sorted()
385375

386-
let toolNamesToTriples = accessibleTools.reduce(into: [String: [String]](), { dict, tool in
387-
switch tool {
388-
case .vendedTool(let name, _, let triples):
389-
dict[name, default: []].append(contentsOf: triples)
390-
default: break
391-
}
392-
})
393-
394376
// Assign a plugin working directory based on the package, target, and plugin.
395377
let pluginOutputDir = outputDir.appending(components: package.identity.description, target.name, pluginTarget.name)
396378

@@ -529,7 +511,7 @@ public extension PluginTarget {
529511
}
530512

531513
/// The set of tools that are accessible to this plugin.
532-
func accessibleTools(packageGraph: PackageGraph, fileSystem: FileSystem, environment: BuildEnvironment, for hostTriple: Triple) throws -> Set<PluginAccessibleTool> {
514+
private func accessibleTools(packageGraph: PackageGraph, fileSystem: FileSystem, environment: BuildEnvironment, for hostTriple: Triple) throws -> Set<PluginAccessibleTool> {
533515
return try Set(self.dependencies(satisfying: environment).flatMap { dependency -> [PluginAccessibleTool] in
534516
let builtToolName: String
535517
let executableOrBinaryTarget: Target
@@ -560,6 +542,31 @@ public extension PluginTarget {
560542
}
561543
})
562544
}
545+
546+
func processAccessibleTools(packageGraph: PackageGraph, fileSystem: FileSystem, environment: BuildEnvironment, for hostTriple: Triple, builtToolHandler: (_ name: String, _ path: RelativePath) throws -> AbsolutePath?) throws -> (toolNamesToPaths: [String: AbsolutePath], toolNamesToTriples: [String: [String]]) {
547+
var toolNamesToPaths: [String: AbsolutePath] = [:]
548+
// Add supported triples info per tool so they can be looked up when running the tool
549+
var toolNamesToTriples: [String: [String]] = [:]
550+
551+
for dep in try accessibleTools(packageGraph: packageGraph, fileSystem: fileSystem, environment: environment, for: hostTriple) {
552+
switch dep {
553+
case .builtTool(let name, let path):
554+
if let path = try builtToolHandler(name, path) {
555+
toolNamesToPaths[name] = path
556+
}
557+
case .vendedTool(let name, let path, let triples):
558+
// Avoid having the path of an unsupported tool overwrite a supported one.
559+
guard !triples.isEmpty || toolNamesToPaths[name] == nil else {
560+
continue
561+
}
562+
toolNamesToPaths[name] = path
563+
// Need triples info for .vendedTool
564+
toolNamesToTriples[name, default: []].append(contentsOf: triples)
565+
}
566+
}
567+
568+
return (toolNamesToPaths, toolNamesToTriples)
569+
}
563570
}
564571

565572
fileprivate extension Target.Dependency {

Tests/SPMBuildCoreTests/PluginInvocationTests.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1113,14 +1113,14 @@ class PluginInvocationTests: XCTestCase {
11131113
print("Looking for LocalBinaryTool...")
11141114
let localBinaryTool = try context.tool(named: "LocalBinaryTool")
11151115
print("... found it at \\(localBinaryTool.path)")
1116-
return []
1116+
return [.buildCommand(displayName: "", executable: localBinaryTool.path, arguments: [], inputFiles: [], outputFiles: [])]
11171117
}
11181118
}
11191119
"""
11201120
try localFileSystem.writeFileContents(myPluginTargetDir.appending(component: "plugin.swift"), string: content)
11211121
let artifactVariants = artifactSupportedTriples.map {
11221122
"""
1123-
{ "path": "LocalBinaryTool.sh", "supportedTriples": ["\($0.tripleString)"] }
1123+
{ "path": "LocalBinaryTool\($0.tripleString).sh", "supportedTriples": ["\($0.tripleString)"] }
11241124
"""
11251125
}
11261126

@@ -1238,6 +1238,7 @@ class PluginInvocationTests: XCTestCase {
12381238
$0.value.forEach {
12391239
XCTAssertTrue($0.succeeded, "plugin unexpectedly failed")
12401240
XCTAssertEqual($0.diagnostics.map { $0.message }, [], "plugin produced unexpected diagnostics")
1241+
XCTAssertEqual($0.buildCommands.first?.configuration.executable.basename, "LocalBinaryTool\(hostTriple.tripleString).sh")
12411242
}
12421243
}
12431244
}

0 commit comments

Comments
 (0)