Skip to content

Commit 0f57141

Browse files
Add --output option to PackageToJS plugin
1 parent 0687544 commit 0f57141

File tree

1 file changed

+48
-18
lines changed

1 file changed

+48
-18
lines changed

Diff for: Plugins/PackageToJS/PackageToJS.swift

+48-18
Original file line numberDiff line numberDiff line change
@@ -6,26 +6,38 @@ struct PackageToJS: CommandPlugin {
66
struct Options {
77
/// Product to build (default: executable target if there's only one)
88
var product: String?
9+
/// Path to the output directory
10+
var outputPath: String?
911
/// Name of the package (default: lowercased Package.swift name)
1012
var packageName: String?
1113
/// Whether to explain the build plan
1214
var explain: Bool = false
1315

1416
static func parse(from extractor: inout ArgumentExtractor) -> Options {
1517
let product = extractor.extractOption(named: "product").last
18+
let outputPath = extractor.extractOption(named: "output").last
1619
let packageName = extractor.extractOption(named: "package-name").last
1720
let explain = extractor.extractFlag(named: "explain")
18-
return Options(product: product, packageName: packageName, explain: explain != 0)
21+
return Options(
22+
product: product, outputPath: outputPath, packageName: packageName,
23+
explain: explain != 0
24+
)
1925
}
2026

2127
static func help() -> String {
2228
return """
23-
Usage: swift package --swift-sdk <swift-sdk> plugin run PackageToJS [options]
29+
Usage: swift package --swift-sdk <swift-sdk> [swift-package options] plugin run PackageToJS [options]
2430
2531
Options:
26-
--product <product> Product to build (default: executable target if there's only one)
27-
--package-name <name> Name of the package (default: lowercased Package.swift name)
28-
--explain Whether to explain the build plan
32+
--product <product> Product to build (default: executable target if there's only one)
33+
--output <path> Path to the output directory (default: .build/plugins/PackageToJS/outputs/Package)
34+
--package-name <name> Name of the package (default: lowercased Package.swift name)
35+
--explain Whether to explain the build plan
36+
37+
Examples:
38+
$ swift package --swift-sdk wasm32-unknown-wasi plugin js
39+
$ swift package --swift-sdk wasm32-unknown-wasi plugin js --product Example
40+
$ swift package --swift-sdk wasm32-unknown-wasi -c release plugin js
2941
"""
3042
}
3143
}
@@ -74,26 +86,38 @@ struct PackageToJS: CommandPlugin {
7486

7587
func performCommand(context: PluginContext, arguments: [String]) throws {
7688
if arguments.contains(where: { ["-h", "--help"].contains($0) }) {
77-
print(Options.help())
89+
printStderr(Options.help())
7890
return
7991
}
8092

8193
var extractor = ArgumentExtractor(arguments)
8294
let options = Options.parse(from: &extractor)
8395

96+
if extractor.remainingArguments.count > 0 {
97+
printStderr(
98+
"Unexpected arguments: \(extractor.remainingArguments.joined(separator: " "))")
99+
printStderr(Options.help())
100+
exit(1)
101+
}
102+
84103
// Build products
85104
let (build, productName) = try buildWasm(options: options, context: context)
86105
guard build.succeeded else {
87106
for diagnostic in Self.friendlyBuildDiagnostics {
88107
if let message = diagnostic(build, arguments) {
89-
fputs("\n" + message + "\n", stderr)
108+
printStderr("\n" + message)
90109
}
91110
}
92111
exit(1)
93112
}
94113

95114
let productArtifact = try build.findWasmArtifact(for: productName)
96-
let outputDir = context.pluginWorkDirectory.appending(subpath: "Package")
115+
let outputDir =
116+
if let outputPath = options.outputPath {
117+
URL(fileURLWithPath: outputPath)
118+
} else {
119+
context.pluginWorkDirectoryURL.appending(path: "Package")
120+
}
97121
guard
98122
let selfPackage = findPackageInDependencies(
99123
package: context.package, id: "javascriptkit")
@@ -128,7 +152,9 @@ struct PackageToJS: CommandPlugin {
128152
parameters.otherSwiftcFlags = [
129153
"-static-stdlib", "-Xclang-linker", "-mexec-model=reactor",
130154
]
131-
parameters.otherLinkerFlags = ["--export-if-defined=__main_argc_argv"]
155+
parameters.otherLinkerFlags = [
156+
"--export-if-defined=__main_argc_argv"
157+
]
132158
}
133159
let productName = try options.product ?? deriveDefaultProduct(package: context.package)
134160
let build = try self.packageManager.build(.product(productName), parameters: parameters)
@@ -142,14 +168,14 @@ struct PackageToJS: CommandPlugin {
142168
context: PluginContext,
143169
wasmProductArtifact: PackageManager.BuildResult.BuiltArtifact,
144170
selfPackage: Package,
145-
outputDir: Path
171+
outputDir: URL
146172
) -> MiniMake.TaskKey {
147-
let selfPackageURL = selfPackage.directory
173+
let selfPackageURL = selfPackage.directoryURL
148174
let selfPath = String(#filePath)
149175

150176
// Prepare output directory
151177
let outputDirTask = make.addTask(
152-
inputFiles: [selfPath], output: outputDir.string, attributes: [.silent]
178+
inputFiles: [selfPath], output: outputDir.path, attributes: [.silent]
153179
) {
154180
guard !FileManager.default.fileExists(atPath: $0.output) else { return }
155181
try FileManager.default.createDirectory(
@@ -169,7 +195,7 @@ struct PackageToJS: CommandPlugin {
169195
let wasmFilename = "main.wasm"
170196
let wasm = make.addTask(
171197
inputFiles: [selfPath, wasmProductArtifact.path.string], inputTasks: [outputDirTask],
172-
output: outputDir.appending(subpath: wasmFilename).string
198+
output: outputDir.appending(path: wasmFilename).path
173199
) {
174200
try syncFile(from: wasmProductArtifact.path.string, to: $0.output)
175201
}
@@ -178,7 +204,7 @@ struct PackageToJS: CommandPlugin {
178204
// Write package.json
179205
let packageJSON = make.addTask(
180206
inputFiles: [selfPath], inputTasks: [outputDirTask],
181-
output: outputDir.appending(subpath: "package.json").string
207+
output: outputDir.appending(path: "package.json").path
182208
) {
183209
let packageJSON = """
184210
{
@@ -207,12 +233,12 @@ struct PackageToJS: CommandPlugin {
207233
("Plugins/PackageToJS/Templates/index.d.ts", "index.d.ts"),
208234
("Sources/JavaScriptKit/Runtime/index.mjs", "runtime.js"),
209235
] {
210-
let inputPath = selfPackageURL.appending(subpath: file).string
236+
let inputPath = selfPackageURL.appending(path: file)
211237
let copied = make.addTask(
212-
inputFiles: [selfPath, inputPath], inputTasks: [outputDirTask],
213-
output: outputDir.appending(subpath: output).string
238+
inputFiles: [selfPath, inputPath.path], inputTasks: [outputDirTask],
239+
output: outputDir.appending(path: output).path
214240
) {
215-
var content = try String(contentsOfFile: inputPath)
241+
var content = try String(contentsOf: inputPath)
216242
for (key, value) in substitutions {
217243
content = content.replacingOccurrences(of: key, with: value)
218244
}
@@ -306,6 +332,10 @@ private func findPackageInDependencies(package: Package, id: Package.ID) -> Pack
306332
return visit(package: package)
307333
}
308334

335+
private func printStderr(_ message: String) {
336+
fputs(message + "\n", stderr)
337+
}
338+
309339
private struct PackageToJSError: Swift.Error, CustomStringConvertible {
310340
let description: String
311341

0 commit comments

Comments
 (0)