Skip to content

Commit 76179dd

Browse files
committed
Deduplicate shared configuration between swiftpm plugins
wip
1 parent 82b5e60 commit 76179dd

File tree

25 files changed

+252
-257
lines changed

25 files changed

+252
-257
lines changed

.licenseignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,4 @@ gradlew.bat
4141
**/gradlew.bat
4242
**/ci-validate.sh
4343
**/DO_NOT_EDIT.txt
44+
Plugins/**/_PluginsShared

Package.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -128,9 +128,9 @@ let package = Package(
128128

129129
// ==== Plugin for wrapping Java classes in Swift
130130
.plugin(
131-
name: "JExtractSwiftPlugin",
131+
name: "SwiftJavaPlugin",
132132
targets: [
133-
"JExtractSwiftPlugin"
133+
"SwiftJavaPlugin"
134134
]
135135
),
136136
.plugin(
@@ -347,7 +347,7 @@ let package = Package(
347347
),
348348

349349
.plugin(
350-
name: "JExtractSwiftPlugin",
350+
name: "SwiftJavaPlugin",
351351
capability: .buildTool(),
352352
dependencies: [
353353
"JExtractSwiftTool"

Plugins/JExtractSwiftCommandPlugin/JExtractSwiftCommandPlugin.swift

Lines changed: 30 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,10 @@ import Foundation
1616
import PackagePlugin
1717

1818
@main
19-
final class JExtractSwiftCommandPlugin: BuildToolPlugin, CommandPlugin {
19+
final class JExtractSwiftCommandPlugin: SwiftJavaPluginProtocol, BuildToolPlugin, CommandPlugin {
2020

21-
var verbose: Bool = false
21+
var pluginName: String = "swift-java-command"
22+
var verbose: Bool = getEnvironmentBool("SWIFT_JAVA_VERBOSE")
2223

2324
/// Build the target before attempting to extract from it.
2425
/// This avoids trying to extract from broken sources.
@@ -48,8 +49,8 @@ final class JExtractSwiftCommandPlugin: BuildToolPlugin, CommandPlugin {
4849
}
4950

5051
for target in context.package.targets {
51-
guard let configPath = getSwiftJavaConfig(target: target) else {
52-
log("Skipping target '\(target.name)', has no 'swift-java.config' file")
52+
guard getSwiftJavaConfigPath(target: target) != nil else {
53+
log("[swift-java-command] Skipping jextract step: Missing swift-java.config for target '\(target.name)'")
5354
continue
5455
}
5556

@@ -73,21 +74,15 @@ final class JExtractSwiftCommandPlugin: BuildToolPlugin, CommandPlugin {
7374
let sourceDir = target.directory.string
7475

7576
let configuration = try readConfiguration(sourceDir: "\(sourceDir)")
76-
77-
// We use the the usual maven-style structure of "src/[generated|main|test]/java/..."
78-
// that is common in JVM ecosystem
79-
let outputDirectoryJava = context.pluginWorkDirectoryURL
80-
.appending(path: "src")
81-
.appending(path: "generated")
82-
.appending(path: "java")
83-
let outputDirectorySwift = context.pluginWorkDirectoryURL
84-
.appending(path: "Sources")
77+
guard let javaPackage = configuration.javaPackage else {
78+
throw SwiftJavaPluginError.missingConfiguration(sourceDir: "\(sourceDir)", key: "javaPackage")
79+
}
8580

8681
var arguments: [String] = [
8782
"--swift-module", sourceModule.name,
88-
"--package-name", configuration.javaPackage,
89-
"--output-directory-java", outputDirectoryJava.path(percentEncoded: false),
90-
"--output-directory-swift", outputDirectorySwift.path(percentEncoded: false),
83+
"--package-name", javaPackage,
84+
"--output-directory-java", context.outputDirectoryJava.path(percentEncoded: false),
85+
"--output-directory-swift", context.outputDirectorySwift.path(percentEncoded: false),
9186
// TODO: "--build-cache-directory", ...
9287
// Since plugins cannot depend on libraries we cannot detect what the output files will be,
9388
// as it depends on the contents of the input files. Therefore we have to implement this as a prebuild plugin.
@@ -100,14 +95,17 @@ final class JExtractSwiftCommandPlugin: BuildToolPlugin, CommandPlugin {
10095

10196
/// Perform the command on a specific target.
10297
func performCommand(context: PluginContext, target: Target, extraArguments _: [String]) throws {
103-
// Make sure the target can builds properly
104-
try self.packageManager.build(.target(target.name), parameters: .init())
105-
10698
guard let sourceModule = target.sourceModule else { return }
10799

108100
if self.buildInputs {
101+
// Make sure the target can builds properly
109102
log("Pre-building target '\(target.name)' before extracting sources...")
110-
try self.packageManager.build(.target(target.name), parameters: .init())
103+
let targetBuildResult = try self.packageManager.build(.target(target.name), parameters: .init())
104+
105+
guard targetBuildResult.succeeded else {
106+
print("[swift-java-command] Build of '\(target.name)' failed: \(targetBuildResult.logText)")
107+
return
108+
}
111109
}
112110

113111
let arguments = try prepareJExtractArguments(context: context, target: target)
@@ -124,7 +122,13 @@ final class JExtractSwiftCommandPlugin: BuildToolPlugin, CommandPlugin {
124122
log("Post-extract building products with target '\(target.name)'...")
125123
for product in context.package.products where product.targets.contains(where: { $0.id == target.id }) {
126124
log("Post-extract building product '\(product.name)'...")
127-
try self.packageManager.build(.product(product.name), parameters: .init())
125+
let buildResult = try self.packageManager.build(.product(product.name), parameters: .init())
126+
127+
if buildResult.succeeded {
128+
log("Post-extract build: " + "done".green + ".")
129+
} else {
130+
log("Post-extract build: " + "done".red + "!")
131+
}
128132
}
129133
}
130134
}
@@ -146,16 +150,15 @@ final class JExtractSwiftCommandPlugin: BuildToolPlugin, CommandPlugin {
146150
}
147151
}
148152

149-
func log(_ message: @autoclosure () -> String, terminator: String = "\n") {
150-
if self.verbose {
151-
print("[swift-java-command] \(message())", terminator: terminator)
152-
}
153-
}
154153
}
155154

156155
// Mini coloring helper, since we cannot have dependencies we keep it minimal here
157156
extension String {
157+
var red: String {
158+
"\u{001B}[0;31m" + "\(self)" + "\u{001B}[0;0m"
159+
}
158160
var green: String {
159161
"\u{001B}[0;32m" + "\(self)" + "\u{001B}[0;0m"
160162
}
161-
}
163+
}
164+

Plugins/JExtractSwiftCommandPlugin/PluginsShared/Configuration.swift

Lines changed: 0 additions & 36 deletions
This file was deleted.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../PluginsShared

Plugins/JExtractSwiftPlugin/PluginsShared/Configuration.swift

Lines changed: 0 additions & 36 deletions
This file was deleted.

Plugins/JExtractSwiftPlugin/PluginsShared/PluginUtils.swift

Lines changed: 0 additions & 37 deletions
This file was deleted.

Plugins/Java2SwiftPlugin/Configuration.swift

Lines changed: 0 additions & 36 deletions
This file was deleted.

Plugins/Java2SwiftPlugin/Java2SwiftPlugin.swift

Lines changed: 17 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,11 @@ import PackagePlugin
1818
fileprivate let Java2SwiftConfigFileName = "Java2Swift.config"
1919

2020
@main
21-
struct Java2SwiftBuildToolPlugin: BuildToolPlugin {
21+
struct Java2SwiftBuildToolPlugin: SwiftJavaPluginProtocol, BuildToolPlugin {
22+
23+
var pluginName: String = "swift-java-javac"
24+
var verbose: Bool = getEnvironmentBool("SWIFT_JAVA_VERBOSE")
25+
2226
func createBuildCommands(context: PluginContext, target: Target) throws -> [Command] {
2327
guard let sourceModule = target.sourceModule else { return [] }
2428

@@ -87,9 +91,14 @@ struct Java2SwiftBuildToolPlugin: BuildToolPlugin {
8791
}
8892
arguments.append(configFile.path(percentEncoded: false))
8993

94+
guard let classes = config.classes else {
95+
log("Config at \(configFile) did not have 'classes' configured, skipping java2swift step.")
96+
return []
97+
}
98+
9099
/// Determine the set of Swift files that will be emitted by the Java2Swift
91100
/// tool.
92-
let outputSwiftFiles = config.classes.map { (javaClassName, swiftName) in
101+
let outputSwiftFiles = classes.map { (javaClassName, swiftName) in
93102
let swiftNestedName = swiftName.replacingOccurrences(of: ".", with: "+")
94103
return outputDirectory.appending(path: "\(swiftNestedName).swift")
95104
}
@@ -125,10 +134,15 @@ struct Java2SwiftBuildToolPlugin: BuildToolPlugin {
125134
arguments += [ "--swift-native-implementation", className]
126135
}
127136
}
137+
138+
guard let classes = config.classes else {
139+
log("Skipping java2swift step: Missing 'classes' key in swift-java.config at '\(configFile.path)'")
140+
return []
141+
}
128142

129143
return [
130144
.buildCommand(
131-
displayName: "Wrapping \(config.classes.count) Java classes target \(sourceModule.name) in Swift",
145+
displayName: "Wrapping \(classes.count) Java classes target \(sourceModule.name) in Swift",
132146
executable: try context.tool(named: "Java2Swift").url,
133147
arguments: arguments,
134148
inputFiles: [ configFile ] + compiledClassFiles,
@@ -137,25 +151,3 @@ struct Java2SwiftBuildToolPlugin: BuildToolPlugin {
137151
]
138152
}
139153
}
140-
141-
// Note: the JAVA_HOME environment variable must be set to point to where
142-
// Java is installed, e.g.,
143-
// Library/Java/JavaVirtualMachines/openjdk-21.jdk/Contents/Home.
144-
func findJavaHome() -> String {
145-
if let home = ProcessInfo.processInfo.environment["JAVA_HOME"] {
146-
return home
147-
}
148-
149-
// This is a workaround for envs (some IDEs) which have trouble with
150-
// picking up env variables during the build process
151-
let path = "\(FileManager.default.homeDirectoryForCurrentUser.path()).java_home"
152-
if let home = try? String(contentsOfFile: path, encoding: .utf8) {
153-
if let lastChar = home.last, lastChar.isNewline {
154-
return String(home.dropLast())
155-
}
156-
157-
return home
158-
}
159-
160-
fatalError("Please set the JAVA_HOME environment variable to point to where Java is installed.")
161-
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../PluginsShared

0 commit comments

Comments
 (0)