Skip to content

Commit 772c21a

Browse files
committed
Final cleanups connectign jextract to the swift-java tools
1 parent 668cd4b commit 772c21a

File tree

8 files changed

+198
-137
lines changed

8 files changed

+198
-137
lines changed

Plugins/JExtractSwiftCommandPlugin/JExtractSwiftCommandPlugin.swift

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -69,21 +69,21 @@ final class JExtractSwiftCommandPlugin: SwiftJavaPluginProtocol, BuildToolPlugin
6969
let sourceDir = target.directory.string
7070

7171
let configuration = try readConfiguration(sourceDir: "\(sourceDir)")
72-
guard let javaPackage = configuration.javaPackage else {
73-
throw SwiftJavaPluginError.missingConfiguration(sourceDir: "\(sourceDir)", key: "javaPackage")
74-
}
7572

7673
var arguments: [String] = [
77-
"--swift-module", sourceModule.name,
78-
"--package-name", javaPackage,
79-
"--output-directory-java", context.outputDirectoryJava.path(percentEncoded: false),
80-
"--output-directory-swift", context.outputDirectorySwift.path(percentEncoded: false),
74+
"--input-swift", sourceDir,
75+
"--module-name", sourceModule.name,
76+
"--output-java", context.outputJavaDirectory.path(percentEncoded: false),
77+
"--output-swift", context.outputSwiftDirectory.path(percentEncoded: false),
8178
// TODO: "--build-cache-directory", ...
8279
// Since plugins cannot depend on libraries we cannot detect what the output files will be,
8380
// as it depends on the contents of the input files. Therefore we have to implement this as a prebuild plugin.
8481
// We'll have to make up some caching inside the tool so we don't re-parse files which have not changed etc.
8582
]
86-
arguments.append(sourceDir)
83+
// arguments.append(sourceDir) // TODO: we could do this shape maybe? to have the dirs last?
84+
if let package = configuration.javaPackage, !package.isEmpty {
85+
["--java-package", package]
86+
}
8787

8888
return arguments
8989
}

Plugins/JExtractSwiftPlugin/JExtractSwiftPlugin.swift

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -50,20 +50,23 @@ struct JExtractSwiftBuildToolPlugin: SwiftJavaPluginProtocol, BuildToolPlugin {
5050

5151
// We use the the usual maven-style structure of "src/[generated|main|test]/java/..."
5252
// that is common in JVM ecosystem
53-
let outputDirectoryJava = context.outputDirectoryJava
54-
let outputDirectorySwift = context.outputDirectorySwift
53+
let outputJavaDirectory = context.outputJavaDirectory
54+
let outputSwiftDirectory = context.outputSwiftDirectory
5555

5656
var arguments: [String] = [
57-
"--swift-module", sourceModule.name,
58-
"--package-name", javaPackage,
59-
"--output-directory-java", outputDirectoryJava.path(percentEncoded: false),
60-
"--output-directory-swift", outputDirectorySwift.path(percentEncoded: false),
57+
"--input-swift", sourceDir,
58+
"--module-name", sourceModule.name,
59+
"--output-java", outputJavaDirectory.path(percentEncoded: false),
60+
"--output-swift", outputSwiftDirectory.path(percentEncoded: false),
6161
// TODO: "--build-cache-directory", ...
6262
// Since plugins cannot depend on libraries we cannot detect what the output files will be,
6363
// as it depends on the contents of the input files. Therefore we have to implement this as a prebuild plugin.
6464
// We'll have to make up some caching inside the tool so we don't re-parse files which have not changed etc.
6565
]
66-
arguments.append(sourceDir)
66+
// arguments.append(sourceDir)
67+
if !javaPackage.isEmpty {
68+
arguments.append(contentsOf: ["--java-package", javaPackage])
69+
}
6770

6871
return [
6972
.prebuildCommand(
@@ -72,7 +75,7 @@ struct JExtractSwiftBuildToolPlugin: SwiftJavaPluginProtocol, BuildToolPlugin {
7275
arguments: arguments,
7376
// inputFiles: [ configFile ] + swiftFiles,
7477
// outputFiles: outputJavaFiles
75-
outputFilesDirectory: outputDirectorySwift
78+
outputFilesDirectory: outputSwiftDirectory
7679
)
7780
]
7881
}

Plugins/PluginsShared/PluginUtils.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,14 +60,14 @@ func getEnvironmentBool(_ name: String) -> Bool {
6060
}
6161

6262
extension PluginContext {
63-
var outputDirectoryJava: URL {
63+
var outputJavaDirectory: URL {
6464
self.pluginWorkDirectoryURL
6565
.appending(path: "src")
6666
.appending(path: "generated")
6767
.appending(path: "java")
6868
}
6969

70-
var outputDirectorySwift: URL {
70+
var outputSwiftDirectory: URL {
7171
self.pluginWorkDirectoryURL
7272
.appending(path: "Sources")
7373
}

Sources/JExtractSwiftLib/Logger.swift

Lines changed: 9 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414

1515
import Foundation
1616
import SwiftSyntax
17+
import ArgumentParser
18+
import JavaKitConfigurationShared
1719

1820
// Placeholder for some better logger, we could depend on swift-log
1921
public struct Logger {
@@ -95,47 +97,17 @@ public struct Logger {
9597
}
9698

9799
extension Logger {
98-
public enum Level: String, Hashable {
99-
case trace = "trace"
100-
case debug = "debug"
101-
case info = "info"
102-
case notice = "notice"
103-
case warning = "warning"
104-
case error = "error"
105-
case critical = "critical"
106-
}
100+
public typealias Level = JavaKitConfigurationShared.LogLevel
107101
}
108102

109-
extension Logger.Level {
110-
public init(from decoder: any Decoder) throws {
111-
var container = try decoder.unkeyedContainer()
112-
let string = try container.decode(String.self)
113-
switch string {
114-
case "trace": self = .trace
115-
case "debug": self = .debug
116-
case "info": self = .info
117-
case "notice": self = .notice
118-
case "warning": self = .warning
119-
case "error": self = .error
120-
case "critical": self = .critical
121-
default: fatalError("Unknown value for \(Logger.Level.self): \(string)")
122-
}
103+
extension Logger.Level: ExpressibleByArgument {
104+
public var defaultValueDescription: String {
105+
"log level"
123106
}
107+
public private(set) static var allValueStrings: [String] =
108+
["trace", "debug", "info", "notice", "warning", "error", "critical"]
124109

125-
public func encode(to encoder: any Encoder) throws {
126-
var container = encoder.singleValueContainer()
127-
let text =
128-
switch self {
129-
case .trace: "trace"
130-
case .debug: "debug"
131-
case .info: "info"
132-
case .notice: "notice"
133-
case .warning: "warning"
134-
case .error: "error"
135-
case .critical: "critical"
136-
}
137-
try container.encode(text)
138-
}
110+
public private(set) static var defaultCompletionKind: CompletionKind = .default
139111
}
140112

141113
extension Logger.Level {

Sources/JExtractSwiftLib/Swift2Java.swift

Lines changed: 39 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -12,57 +12,49 @@
1212
//
1313
//===----------------------------------------------------------------------===//
1414

15-
import ArgumentParser
1615
import Foundation
1716
import SwiftSyntax
1817
import SwiftSyntaxBuilder
1918
import JavaKitShared
19+
import JavaKitConfigurationShared // TODO: this should become SwiftJavaConfigurationShared
2020

21-
/// Command-line utility, similar to `jextract` to export Swift types to Java.
22-
public struct SwiftToJava: ParsableCommand {
23-
public init() {}
21+
public struct SwiftToJava {
22+
let config: Configuration
2423

25-
public static var _commandName: String {
26-
"jextract-swift"
24+
public init(config: Configuration) {
25+
self.config = config
2726
}
2827

29-
@Option(help: "The package the generated Java code should be emitted into.")
30-
var packageName: String
31-
32-
@Option(
33-
name: .shortAndLong,
34-
help: "The directory in which to output the generated Swift files and manifest.")
35-
var outputDirectoryJava: String = ".build/jextract-swift/generated"
36-
37-
@Option(help: "Swift output directory")
38-
var outputDirectorySwift: String
39-
40-
@Option(
41-
name: .long,
42-
help: "Name of the Swift module to import (and the swift interface files belong to)")
43-
var swiftModule: String
44-
45-
@Option(name: .shortAndLong, help: "Configure the level of lots that should be printed")
46-
var logLevel: Logger.Level = .info
47-
48-
@Argument(help: "The Swift files or directories to recursively export to Java.")
49-
var input: [String]
50-
5128
public func run() throws {
52-
let inputPaths = self.input.dropFirst().map { URL(string: $0)! }
29+
guard let swiftModule = config.swiftModule else {
30+
fatalError("Missing '--swift-module' name.")
31+
}
5332

5433
let translator = Swift2JavaTranslator(
55-
javaPackage: packageName,
34+
javaPackage: config.javaPackage ?? "", // no package is ok, we'd generate all into top level
5635
swiftModuleName: swiftModule
5736
)
58-
translator.log.logLevel = logLevel
37+
translator.log.logLevel = config.logLevel ?? .info
38+
39+
if config.javaPackage == nil || config.javaPackage!.isEmpty {
40+
translator.log.warning("Configured java package is '', consider specifying concrete package for generated sources.")
41+
}
42+
43+
print("===== CONFIG ==== \(config)")
44+
45+
guard let inputSwift = config.inputSwiftDirectory else {
46+
fatalError("Missing '--swift-input' directory!")
47+
}
48+
49+
let inputPaths = inputSwift.split(separator: ",").map { URL(string: String($0))! }
50+
translator.log.info("Input paths = \(inputPaths)")
5951

6052
var allFiles: [URL] = []
6153
let fileManager = FileManager.default
6254
let log = translator.log
63-
55+
6456
for path in inputPaths {
65-
log.debug("Input path: \(path)")
57+
log.info("Input path: \(path)")
6658
if isDirectory(url: path) {
6759
if let enumerator = fileManager.enumerator(at: path, includingPropertiesForKeys: nil) {
6860
for case let fileURL as URL in enumerator {
@@ -88,10 +80,21 @@ public struct SwiftToJava: ParsableCommand {
8880
translator.add(filePath: file.path, text: text)
8981
}
9082

83+
guard let outputSwiftDirectory = config.outputSwiftDirectory else {
84+
fatalError("Missing --output-swift directory!")
85+
}
86+
guard let outputJavaDirectory = config.outputJavaDirectory else {
87+
fatalError("Missing --output-java directory!")
88+
}
89+
9190
try translator.analyze()
92-
try translator.writeSwiftThunkSources(outputDirectory: outputDirectorySwift)
93-
try translator.writeExportedJavaSources(outputDirectory: outputDirectoryJava)
94-
print("[swift-java] Generated Java sources (\(packageName)) in: \(outputDirectoryJava)/")
91+
92+
try translator.writeSwiftThunkSources(outputDirectory: outputSwiftDirectory)
93+
print("[swift-java] Generated Swift sources (module: '\(config.swiftModule ?? "")') in: \(outputSwiftDirectory)/")
94+
95+
try translator.writeExportedJavaSources(outputDirectory: outputJavaDirectory)
96+
print("[swift-java] Generated Java sources (package: '\(config.javaPackage ?? "")') in: \(outputJavaDirectory)/")
97+
9598
print("[swift-java] Imported Swift module '\(swiftModule)': " + "done.".green)
9699
}
97100

@@ -102,16 +105,6 @@ public struct SwiftToJava: ParsableCommand {
102105

103106
}
104107

105-
extension Logger.Level: ExpressibleByArgument {
106-
public var defaultValueDescription: String {
107-
"log level"
108-
}
109-
public private(set) static var allValueStrings: [String] =
110-
["trace", "debug", "info", "notice", "warning", "error", "critical"]
111-
112-
public private(set) static var defaultCompletionKind: CompletionKind = .default
113-
}
114-
115108
func isDirectory(url: URL) -> Bool {
116109
var isDirectory: ObjCBool = false
117110
_ = FileManager.default.fileExists(atPath: url.path, isDirectory: &isDirectory)

Sources/JavaKitConfigurationShared/Configuration.swift

Lines changed: 54 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,22 @@ import Foundation
2121

2222
public typealias JavaVersion = Int
2323

24-
/// Configuration for the SwiftJava plugins, provided on a per-target basis.
24+
/// Configuration for the SwiftJava tools and plugins, provided on a per-target basis.
2525
public struct Configuration: Codable {
26-
// ==== swift 2 java ---------------------------------------------------------
26+
27+
public var logLevel: LogLevel?
28+
29+
// ==== swift 2 java / jextract swift ---------------------------------------
2730

2831
public var javaPackage: String?
2932

30-
public var inputSwift: String?
31-
public var outputSwift: String?
32-
public var outputJava: String?
33+
public var swiftModule: String?
34+
35+
public var inputSwiftDirectory: String?
36+
37+
public var outputSwiftDirectory: String?
38+
39+
public var outputJavaDirectory: String?
3340

3441
// ==== java 2 swift ---------------------------------------------------------
3542

@@ -204,3 +211,45 @@ public struct ConfigurationError: Error {
204211
self.line = line
205212
}
206213
}
214+
215+
public enum LogLevel: String, Codable, Hashable {
216+
case trace = "trace"
217+
case debug = "debug"
218+
case info = "info"
219+
case notice = "notice"
220+
case warning = "warning"
221+
case error = "error"
222+
case critical = "critical"
223+
}
224+
225+
extension LogLevel {
226+
public init(from decoder: any Decoder) throws {
227+
var container = try decoder.unkeyedContainer()
228+
let string = try container.decode(String.self)
229+
switch string {
230+
case "trace": self = .trace
231+
case "debug": self = .debug
232+
case "info": self = .info
233+
case "notice": self = .notice
234+
case "warning": self = .warning
235+
case "error": self = .error
236+
case "critical": self = .critical
237+
default: fatalError("Unknown value for \(LogLevel.self): \(string)")
238+
}
239+
}
240+
241+
public func encode(to encoder: any Encoder) throws {
242+
var container = encoder.singleValueContainer()
243+
let text =
244+
switch self {
245+
case .trace: "trace"
246+
case .debug: "debug"
247+
case .info: "info"
248+
case .notice: "notice"
249+
case .warning: "warning"
250+
case .error: "error"
251+
case .critical: "critical"
252+
}
253+
try container.encode(text)
254+
}
255+
}

Sources/SwiftJavaTool/SwiftJava+JExtract.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ extension SwiftJava {
3434
mutating func jextractSwift(
3535
config: Configuration
3636
) throws {
37-
37+
try SwiftToJava(config: config).run()
3838
}
3939

4040
}

0 commit comments

Comments
 (0)