Skip to content

Commit 8ee0e20

Browse files
authored
Support swift package migrate with --build-system swiftbuild (#8888)
Similar to the API digester integration, pass along a build system delegate to capture serialized diagnostic paths from the build and pass them to the fix-it application infra. Builds on the changes in #8857, only the second commit is new
1 parent d78246c commit 8ee0e20

File tree

17 files changed

+239
-61
lines changed

17 files changed

+239
-61
lines changed
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// swift-tools-version:5.8
2+
3+
import PackageDescription
4+
5+
let package = Package(
6+
name: "ExistentialAnyMigration",
7+
targets: [
8+
.target(name: "Library", dependencies: ["CommonLibrary"], plugins: [.plugin(name: "Plugin")]),
9+
.plugin(name: "Plugin", capability: .buildTool, dependencies: ["Tool"]),
10+
.executableTarget(name: "Tool", dependencies: ["CommonLibrary"]),
11+
.target(name: "CommonLibrary"),
12+
]
13+
)
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import PackagePlugin
2+
import Foundation
3+
4+
@main struct Plugin: BuildToolPlugin {
5+
func createBuildCommands(context: PluginContext, target: Target) throws -> [Command] {
6+
let tool = try context.tool(named: "Tool")
7+
let output = context.pluginWorkDirectory.appending(["generated.swift"])
8+
return [
9+
.buildCommand(
10+
displayName: "Plugin",
11+
executable: tool.path,
12+
arguments: [output],
13+
inputFiles: [],
14+
outputFiles: [output])
15+
]
16+
}
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
public func common() {}
2+
3+
4+
protocol P {}
5+
6+
func needsMigration(_ p: P) {}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import CommonLibrary
2+
3+
func bar() {
4+
generatedFunction()
5+
common()
6+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import Foundation
2+
import CommonLibrary
3+
4+
@main struct Entry {
5+
public static func main() async throws {
6+
common()
7+
let outputPath = CommandLine.arguments[1]
8+
let contents = """
9+
func generatedFunction() {}
10+
"""
11+
FileManager.default.createFile(atPath: outputPath, contents: contents.data(using: .utf8))
12+
}
13+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// swift-tools-version:5.8
2+
3+
import PackageDescription
4+
5+
let package = Package(
6+
name: "ExistentialAnyMigration",
7+
targets: [
8+
.target(name: "Library", plugins: [.plugin(name: "Plugin")]),
9+
.plugin(name: "Plugin", capability: .buildTool, dependencies: ["Tool"]),
10+
.executableTarget(name: "Tool"),
11+
]
12+
)
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import PackagePlugin
2+
import Foundation
3+
4+
@main struct Plugin: BuildToolPlugin {
5+
func createBuildCommands(context: PluginContext, target: Target) throws -> [Command] {
6+
let tool = try context.tool(named: "Tool")
7+
let output = context.pluginWorkDirectory.appending(["generated.swift"])
8+
return [
9+
.buildCommand(
10+
displayName: "Plugin",
11+
executable: tool.path,
12+
arguments: [output],
13+
inputFiles: [],
14+
outputFiles: [output])
15+
]
16+
}
17+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
protocol P {
2+
}
3+
4+
func test1(_: P) {
5+
}
6+
7+
func test2(_: P.Protocol) {
8+
}
9+
10+
func test3() {
11+
let _: [P?] = []
12+
}
13+
14+
func test4() {
15+
var x = 42
16+
}
17+
18+
func bar() {
19+
generatedFunction()
20+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import Foundation
2+
3+
@main struct Entry {
4+
public static func main() async throws {
5+
let outputPath = CommandLine.arguments[1]
6+
let contents = """
7+
func generatedFunction() {}
8+
func dontmodifyme(_: P) {}
9+
"""
10+
FileManager.default.createFile(atPath: outputPath, contents: contents.data(using: .utf8))
11+
}
12+
}

Sources/Build/BuildOperation.swift

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -396,9 +396,9 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS
396396
}
397397

398398
/// Perform a build using the given build description and subset.
399-
public func build(subset: BuildSubset) async throws {
399+
public func build(subset: BuildSubset) async throws -> BuildResult {
400400
guard !self.config.shouldSkipBuilding(for: .target) else {
401-
return
401+
return BuildResult(serializedDiagnosticPathsByTargetName: .failure(StringError("Building was skipped")))
402402
}
403403

404404
let buildStartTime = DispatchTime.now()
@@ -422,7 +422,7 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS
422422
// any errors up-front. Returns true if we should proceed with the build
423423
// or false if not. It will already have thrown any appropriate error.
424424
guard try await self.compilePlugins(in: subset) else {
425-
return
425+
return BuildResult(serializedDiagnosticPathsByTargetName: .failure(StringError("Plugin compilation failed")))
426426
}
427427

428428
let configuration = self.config.configuration(for: .target)
@@ -452,6 +452,17 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS
452452
)
453453
guard success else { throw Diagnostics.fatalError }
454454

455+
let serializedDiagnosticResult: Result<[String: [AbsolutePath]], Error>
456+
var serializedDiagnosticPaths: [String: [AbsolutePath]] = [:]
457+
do {
458+
for module in try buildPlan.buildModules {
459+
serializedDiagnosticPaths[module.module.name, default: []].append(contentsOf: module.diagnosticFiles)
460+
}
461+
serializedDiagnosticResult = .success(serializedDiagnosticPaths)
462+
} catch {
463+
serializedDiagnosticResult = .failure(error)
464+
}
465+
455466
// Create backwards-compatibility symlink to old build path.
456467
let oldBuildPath = self.config.dataPath(for: .target).parentDirectory.appending(
457468
component: configuration.dirname
@@ -463,7 +474,7 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS
463474
warning: "unable to delete \(oldBuildPath), skip creating symbolic link",
464475
underlyingError: error
465476
)
466-
return
477+
return BuildResult(serializedDiagnosticPathsByTargetName: serializedDiagnosticResult)
467478
}
468479
}
469480

@@ -479,6 +490,8 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS
479490
underlyingError: error
480491
)
481492
}
493+
494+
return BuildResult(serializedDiagnosticPathsByTargetName: serializedDiagnosticResult)
482495
}
483496

484497
/// Compiles any plugins specified or implied by the build subset, returning

0 commit comments

Comments
 (0)