forked from swiftlang/swift-java
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathSwiftJavaBaseAsyncParsableCommand.swift
More file actions
188 lines (162 loc) · 6.25 KB
/
SwiftJavaBaseAsyncParsableCommand.swift
File metadata and controls
188 lines (162 loc) · 6.25 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2024 Apple Inc. and the Swift.org project authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
// See CONTRIBUTORS.txt for the list of Swift.org project authors
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//
import ArgumentParser
import Foundation
import JExtractSwiftLib
import JavaLangReflect
import JavaNet
import JavaUtilJar
import Logging
import SwiftJava
import SwiftJavaConfigurationShared
import SwiftJavaShared
import SwiftJavaToolLib
import SwiftSyntax
import SwiftSyntaxBuilder
protocol SwiftJavaBaseAsyncParsableCommand: AsyncParsableCommand {
var log: Logging.Logger { get }
var logLevel: JExtractSwiftLib.Logger.Level { get set }
/// Must be implemented with an `@OptionGroup` in Command implementations
var commonOptions: SwiftJava.CommonOptions { get set }
var effectiveSwiftModule: String { get }
mutating func runSwiftJavaCommand(config: inout Configuration) async throws
}
extension SwiftJavaBaseAsyncParsableCommand {
var outputDirectory: String? {
self.commonOptions.outputDirectory
}
}
extension SwiftJavaBaseAsyncParsableCommand {
public mutating func run() async {
self.log.info("Run \(Self.self): \(CommandLine.arguments.joined(separator: " "))")
self.log.info("Current work directory: \(URL(fileURLWithPath: ".").path)")
do {
var config = try readInitialConfiguration(command: self)
try await runSwiftJavaCommand(config: &config)
} catch {
// We fail like this since throwing out of the run often ends up hiding the failure reason when it is executed as SwiftPM plugin (!)
let message = "Failed with error: \(error)"
self.log.error("\(message)")
fatalError(message)
}
// Just for debugging so it is clear which command has finished
self.log.debug("\("Done: ".green) \(CommandLine.arguments.joined(separator: " ").green)")
}
}
extension SwiftJavaBaseAsyncParsableCommand {
mutating func writeContents(
_ contents: String,
outputDirectory: Foundation.URL?,
to filename: String,
description: String
) throws {
guard let outputDir = outputDirectory else {
print("// \(filename) - \(description)")
print(contents)
return
}
// If we haven't tried to create the output directory yet, do so now before
// we write any files to it.
// if !createdOutputDirectory {
try FileManager.default.createDirectory(
at: outputDir,
withIntermediateDirectories: true
)
// createdOutputDirectory = true
//}
// Write the file:
let file = outputDir.appendingPathComponent(filename)
print("[trace][swift-java] Writing \(description) to '\(file.path)'... ", terminator: "")
try contents.write(to: file, atomically: true, encoding: .utf8)
print("done.".green)
}
}
extension SwiftJavaBaseAsyncParsableCommand {
var log: Logging.Logger { // FIXME: replace with stored property inside specific commands
.init(label: "swift-java")
}
var logLevel: JExtractSwiftLib.Logger.Level {
get {
self.commonOptions.logLevel
}
set {
self.commonOptions.logLevel = newValue
}
}
var effectiveSwiftModuleURL: Foundation.URL {
let fm = FileManager.default
return URL(fileURLWithPath: fm.currentDirectoryPath + "/Sources/\(self.effectiveSwiftModule)")
}
}
extension SwiftJavaBaseAsyncParsableCommand {
var moduleBaseDir: Foundation.URL? {
if let outputDirectory = commonOptions.outputDirectory {
if outputDirectory == "-" {
return nil
}
// print("[debug][swift-java] Module base directory based on outputDirectory!")
// return URL(fileURLWithPath: outputDirectory)
}
// Put the result into Sources/\(swiftModule).
let baseDir = URL(fileURLWithPath: ".")
.appendingPathComponent("Sources", isDirectory: true)
.appendingPathComponent(self.effectiveSwiftModule, isDirectory: true)
return baseDir
}
/// The output directory in which to place the generated files, which will
/// be the specified directory (--output-directory or -o option) if given,
/// or a default directory derived from the other command-line arguments.
///
/// Returns `nil` only when we should emit the files to standard output.
var actualOutputDirectory: Foundation.URL? {
if let outputDirectory = self.commonOptions.outputDirectory {
if outputDirectory == "-" {
return nil
}
return URL(fileURLWithPath: outputDirectory)
}
// Put the result into Sources/\(swiftModule).
let baseDir = URL(fileURLWithPath: ".")
.appendingPathComponent("Sources", isDirectory: true)
.appendingPathComponent(effectiveSwiftModule, isDirectory: true)
// For generated Swift sources, put them into a "generated" subdirectory.
// The configuration file goes at the top level.
let outputDir: Foundation.URL = baseDir
return outputDir
}
func readInitialConfiguration(command: some SwiftJavaBaseAsyncParsableCommand) throws -> Configuration {
var earlyConfig: Configuration?
if let configPath = commonOptions.config {
let configURL = URL(filePath: configPath, directoryHint: .notDirectory)
print("[debug][swift-java] Load config from passed in path: \(configURL)")
earlyConfig = try readConfiguration(configPath: configURL)
} else if let moduleBaseDir {
print("[debug][swift-java] Load config from module base directory: \(moduleBaseDir.path)")
earlyConfig = try readConfiguration(sourceDir: moduleBaseDir)
} else if let inputSwift = commonOptions.inputSwift {
print("[debug][swift-java] Load config from module swift input directory: \(inputSwift)")
earlyConfig = try readConfiguration(sourceDir: URL(fileURLWithPath: inputSwift))
}
var config: Configuration
if let earlyConfig {
config = earlyConfig
} else {
log.warning("[swift-java] Failed to load initial configuration. Proceeding with empty configuration.")
config = Configuration()
}
// override configuration with options from command line
config.logLevel = command.logLevel
return config
}
}