Skip to content

Replace custom path type with URL in plugin API #7184

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Dec 15, 2023
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
@@ -0,0 +1,78 @@
// swift-tools-version: 5.11
import PackageDescription

let package = Package(
name: "MySourceGenPlugin",
products: [
// The product that vends MySourceGenBuildToolPlugin to client packages.
.plugin(
name: "MySourceGenBuildToolPlugin",
targets: ["MySourceGenBuildToolPlugin"]
),
// The product that vends the MySourceGenBuildTool executable to client packages.
.executable(
name: "MySourceGenBuildTool",
targets: ["MySourceGenBuildTool"]
),
// The product that vends MySourceGenPrebuildPlugin to client packages.
.plugin(
name: "MySourceGenPrebuildPlugin",
targets: ["MySourceGenPrebuildPlugin"]
),
],
targets: [
// A local tool that uses a build tool plugin.
.executableTarget(
name: "MyLocalTool",
plugins: [
"MySourceGenBuildToolPlugin",
]
),
// A local tool that uses a prebuild plugin.
.executableTarget(
name: "MyOtherLocalTool",
plugins: [
"MySourceGenPrebuildPlugin",
]
),
// The plugin that generates build tool commands to invoke MySourceGenBuildTool.
.plugin(
name: "MySourceGenBuildToolPlugin",
capability: .buildTool(),
dependencies: [
"MySourceGenBuildTool",
]
),
// The plugin that generates prebuild commands (currently to invoke a system tool).
.plugin(
name: "MySourceGenPrebuildPlugin",
capability: .buildTool()
),
// The command line tool that generates source files.
.executableTarget(
name: "MySourceGenBuildTool",
dependencies: [
"MySourceGenBuildToolLib",
]
),
// A library used by MySourceGenBuildTool (not the client).
.target(
name: "MySourceGenBuildToolLib"
),
// A runtime library that the client needs to link against.
.target(
name: "MySourceGenRuntimeLib"
),
// Unit tests for the plugin.
.testTarget(
name: "MySourceGenPluginTests",
dependencies: [
"MySourceGenRuntimeLib",
],
plugins: [
"MySourceGenBuildToolPlugin",
"MySourceGenPrebuildPlugin",
]
)
]
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import PackagePlugin

@main
struct MyPlugin: BuildToolPlugin {
#if USE_CREATE
let verb = "Creating"
#else
let verb = "Generating"
#endif

func createBuildCommands(context: PluginContext, target: Target) throws -> [Command] {
print("Hello from the Build Tool Plugin!")
guard let target = target as? SourceModuleTarget else { return [] }
return try target.sourceFiles.map{ $0.url }.compactMap {
guard $0.pathExtension == "dat" else { return .none }
let outputName = $0.deletingPathExtension().lastPathComponent + ".swift"
let outputPath = context.pluginWorkDirectoryURL.appendingPathComponent(outputName)
return .buildCommand(
displayName:
"\(verb) \(outputName) from \($0.lastPathComponent)",
executable:
try context.tool(named: "MySourceGenBuildTool").url,
arguments: [
"\($0)",
"\(outputPath.path)"
],
inputFiles: [
$0,
],
outputFiles: [
outputPath
]
)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import Foundation
import PackagePlugin

@main
struct MyPlugin: BuildToolPlugin {

func createBuildCommands(context: PluginContext, target: Target) throws -> [Command] {
print("Hello from the Prebuild Plugin!")
guard let target = target as? SourceModuleTarget else { return [] }
let outputPaths: [URL] = target.sourceFiles.filter{ $0.url.pathExtension == "dat" }.map { file in
context.pluginWorkDirectoryURL.appendingPathComponent(file.url.lastPathComponent + ".swift")
}
var commands: [Command] = []
if !outputPaths.isEmpty {
commands.append(.prebuildCommand(
displayName:
"Running prebuild command for target \(target.name)",
executable:
URL(fileURLWithPath: "/usr/bin/touch"),
arguments:
outputPaths.map{ $0.path },
outputFilesDirectory:
context.pluginWorkDirectoryURL
))
}
return commands
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
I am Foo!
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
print("Generated string Foo: '\(foo)'")
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
I am Bar!
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
I am Baz!
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// print("Generated string Bar: '\(bar)'")
// print("Generated string Baz: '\(baz)'")
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import Foundation
import MySourceGenBuildToolLib

// Sample source generator tool that emits a Swift variable declaration of a string containing the hex representation of the contents of a file as a quoted string. The variable name is the base name of the input file. The input file is the first argument and the output file is the second.
if ProcessInfo.processInfo.arguments.count != 3 {
print("usage: MySourceGenBuildTool <input> <output>")
exit(1)
}
let inputFile = ProcessInfo.processInfo.arguments[1]
let outputFile = ProcessInfo.processInfo.arguments[2]

let variableName = URL(fileURLWithPath: inputFile).deletingPathExtension().lastPathComponent

let inputData = FileManager.default.contents(atPath: inputFile) ?? Data()
let dataAsHex = inputData.map { String(format: "%02hhx", $0) }.joined()
let outputString = "public var \(variableName) = \(dataAsHex.quotedForSourceCode)\n"
let outputData = outputString.data(using: .utf8)
FileManager.default.createFile(atPath: outputFile, contents: outputData)
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import Foundation

extension String {

public var quotedForSourceCode: String {
return "\"" + self
.replacingOccurrences(of: "\\", with: "\\\\")
.replacingOccurrences(of: "\"", with: "\\\"")
+ "\""
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
public func GetLibraryName() -> String {
return "MySourceGenRuntimeLib"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import XCTest
import class Foundation.Bundle

final class SwiftyProtobufTests: XCTestCase {
func testExample() throws {
// This is an example of a functional test case.
// Use XCTAssert and related functions to verify your tests produce the correct
// results.

// Some of the APIs that we use below are available in macOS 10.13 and above.
guard #available(macOS 10.13, *) else {
return
}

// Mac Catalyst won't have `Process`, but it is supported for executables.
#if !targetEnvironment(macCatalyst)

let fooBinary = productsDirectory.appendingPathComponent("MySourceGenTool")

let process = Process()
process.executableURL = fooBinary

let pipe = Pipe()
process.standardOutput = pipe

try process.run()
process.waitUntilExit()

let data = pipe.fileHandleForReading.readDataToEndOfFile()
let output = String(data: data, encoding: .utf8)

XCTAssertEqual(output, "Hello, world!\n")
#endif
}

/// Returns path to the built products directory.
var productsDirectory: URL {
#if os(macOS)
for bundle in Bundle.allBundles where bundle.bundlePath.hasSuffix(".xctest") {
return bundle.bundleURL.deletingLastPathComponent()
}
fatalError("couldn't find the products directory")
#else
return Bundle.main.bundleURL
#endif
}
}
2 changes: 1 addition & 1 deletion Sources/Basics/SwiftVersion.swift
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public struct SwiftVersion {
extension SwiftVersion {
/// The current version of the package manager.
public static let current = SwiftVersion(
version: (5, 10, 0),
version: (5, 11, 0),
isDevelopment: true,
buildIdentifier: getBuildIdentifier()
)
Expand Down
Loading