Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@ let package = Package(
description: "Writes diagnostic messages for testing"
))
),
.plugin(
name: "targetbuild-stub",
capability: .command(intent: .custom(
verb: "build-target",
description: "Build a target for testing"
))
),
.executableTarget(
name: "placeholder"
),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import Foundation
import PackagePlugin

@main
struct targetbuild_stub: CommandPlugin {
// This is a helper for testing target builds performed on behalf of plugins.
// It sends asks SwiftPM to build a target with different options depending on its arguments.
func performCommand(context: PluginContext, arguments: [String]) async throws {
// Build a target
var parameters = PackageManager.BuildParameters()
if arguments.contains("build-debug") {
parameters.configuration = .debug
} else if arguments.contains("build-release") {
parameters.configuration = .release
} else if arguments.contains("build-inherit") {
parameters.configuration = .inherit
}
// If no 'build-*' argument is present, the default (.debug) will be used.

let _ = try packageManager.build(
.product("placeholder"),
parameters: parameters
)
}
}
4 changes: 4 additions & 0 deletions Sources/Commands/Utilities/PluginDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,10 @@ final class PluginDelegate: PluginInvocationDelegate {
buildParameters.configuration = .debug
case .release:
buildParameters.configuration = .release
case .inherit:
// The top level argument parser set buildParameters.configuration according to the
// --configuration command line parameter. We don't need to do anything to inherit it.
break
}
buildParameters.flags.cCompilerFlags.append(contentsOf: parameters.otherCFlags)
buildParameters.flags.cxxCompilerFlags.append(contentsOf: parameters.otherCxxFlags)
Expand Down
4 changes: 3 additions & 1 deletion Sources/PackagePlugin/PackageManagerProxy.swift
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ public struct PackageManager {
/// Represents an overall purpose of the build, which affects such things
/// as optimization and generation of debug symbols.
public enum BuildConfiguration: String {
case debug, release
case debug, release, inherit
}

/// Represents the amount of detail in a build log.
Expand Down Expand Up @@ -328,6 +328,8 @@ fileprivate extension PluginToHostMessage.BuildParameters.Configuration {
self = .debug
case .release:
self = .release
case .inherit:
self = .inherit
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion Sources/PackagePlugin/PluginMessages.swift
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ enum PluginToHostMessage: Codable {
struct BuildParameters: Codable {
var configuration: Configuration
enum Configuration: String, Codable {
case debug, release
case debug, release, inherit
}
var logging: LogVerbosity
enum LogVerbosity: String, Codable {
Expand Down
4 changes: 3 additions & 1 deletion Sources/SPMBuildCore/Plugins/PluginInvocation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -861,7 +861,7 @@ public enum PluginInvocationBuildSubset {
public struct PluginInvocationBuildParameters {
public var configuration: Configuration
public enum Configuration: String {
case debug, release
case debug, release, inherit
}
public var logging: LogVerbosity
public enum LogVerbosity: String {
Expand Down Expand Up @@ -993,6 +993,8 @@ fileprivate extension PluginInvocationBuildParameters.Configuration {
self = .debug
case .release:
self = .release
case .inherit:
self = .inherit
}
}
}
Expand Down
64 changes: 63 additions & 1 deletion Tests/CommandsTests/PackageToolTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1890,7 +1890,7 @@ final class PackageToolTests: CommandsTestCase {
let containsWarning = StringPattern.contains("command plugin: Diagnostics.warning")
let containsError = StringPattern.contains("command plugin: Diagnostics.error")

try fixture(name: "Miscellaneous/Plugins/CommandPluginDiagnosticsStub") { fixturePath in
try fixture(name: "Miscellaneous/Plugins/CommandPluginTestStub") { fixturePath in
func runPlugin(flags: [String], diagnostics: [String], completion: (String, String) -> Void) throws {
let (stdout, stderr) = try SwiftPM.Package.execute(flags + ["print-diagnostics"] + diagnostics, packagePath: fixturePath)
completion(stdout, stderr)
Expand Down Expand Up @@ -1987,6 +1987,68 @@ final class PackageToolTests: CommandsTestCase {
}
}

// Test target builds requested by a command plugin
func testCommandPluginTargetBuilds() throws {
// Only run the test if the environment in which we're running actually supports Swift concurrency (which the plugin APIs require).
try XCTSkipIf(!UserToolchain.default.supportsSwiftConcurrency(), "skipping because test environment doesn't support concurrency")

let debugTarget = [".build", "debug", "placeholder"]
let releaseTarget = [".build", "release", "placeholder"]

func AssertIsExecutableFile(_ fixturePath: AbsolutePath, file: StaticString = #filePath, line: UInt = #line) {
XCTAssert(
localFileSystem.isExecutableFile(fixturePath),
"\(fixturePath) does not exist",
file: file,
line: line
)
}

func AssertNotExists(_ fixturePath: AbsolutePath, file: StaticString = #filePath, line: UInt = #line) {
XCTAssertFalse(
localFileSystem.exists(fixturePath),
"\(fixturePath) should not exist",
file: file,
line: line
)
}

// By default, a plugin-requested build produces a debug binary
try fixture(name: "Miscellaneous/Plugins/CommandPluginTestStub") { fixturePath in
let _ = try SwiftPM.Package.execute(["-c", "release", "build-target"], packagePath: fixturePath)
AssertIsExecutableFile(fixturePath.appending(components: debugTarget))
AssertNotExists(fixturePath.appending(components: releaseTarget))
}

// If the plugin specifies a debug binary, that is what will be built, regardless of overall configuration
try fixture(name: "Miscellaneous/Plugins/CommandPluginTestStub") { fixturePath in
let _ = try SwiftPM.Package.execute(["-c", "release", "build-target", "build-debug"], packagePath: fixturePath)
AssertIsExecutableFile(fixturePath.appending(components: debugTarget))
AssertNotExists(fixturePath.appending(components: releaseTarget))
}

// If the plugin requests a release binary, that is what will be built, regardless of overall configuration
try fixture(name: "Miscellaneous/Plugins/CommandPluginTestStub") { fixturePath in
let _ = try SwiftPM.Package.execute(["-c", "debug", "build-target", "build-release"], packagePath: fixturePath)
AssertNotExists(fixturePath.appending(components: debugTarget))
AssertIsExecutableFile(fixturePath.appending(components: releaseTarget))
}

// If the plugin inherits the overall build configuration, that is what will be built
try fixture(name: "Miscellaneous/Plugins/CommandPluginTestStub") { fixturePath in
let _ = try SwiftPM.Package.execute(["-c", "debug", "build-target", "build-inherit"], packagePath: fixturePath)
AssertIsExecutableFile(fixturePath.appending(components: debugTarget))
AssertNotExists(fixturePath.appending(components: releaseTarget))
}

// If the plugin inherits the overall build configuration, that is what will be built
try fixture(name: "Miscellaneous/Plugins/CommandPluginTestStub") { fixturePath in
let _ = try SwiftPM.Package.execute(["-c", "release", "build-target", "build-inherit"], packagePath: fixturePath)
AssertNotExists(fixturePath.appending(components: debugTarget))
AssertIsExecutableFile(fixturePath.appending(components: releaseTarget))
}
}

func testCommandPluginNetworkingPermissions(permissionsManifestFragment: String, permissionError: String, reason: String, remedy: [String]) throws {
// Only run the test if the environment in which we're running actually supports Swift concurrency (which the plugin APIs require).
try XCTSkipIf(!UserToolchain.default.supportsSwiftConcurrency(), "skipping because test environment doesn't support concurrency")
Expand Down