From f12b41a26a55cc3d8acb7edc9190146c4da84228 Mon Sep 17 00:00:00 2001 From: Yuta Saito <kateinoigakukun@gmail.com> Date: Tue, 18 Mar 2025 13:16:40 +0900 Subject: [PATCH] PackageToJS: Emit hints for permission denied errors --- .../Sources/PackageToJSPlugin.swift | 65 ++++++++++++++++--- 1 file changed, 57 insertions(+), 8 deletions(-) diff --git a/Plugins/PackageToJS/Sources/PackageToJSPlugin.swift b/Plugins/PackageToJS/Sources/PackageToJSPlugin.swift index 3795ffaa..7dc2a684 100644 --- a/Plugins/PackageToJS/Sources/PackageToJSPlugin.swift +++ b/Plugins/PackageToJS/Sources/PackageToJSPlugin.swift @@ -5,6 +5,7 @@ @preconcurrency import class Foundation.Process @preconcurrency import class Foundation.ProcessInfo @preconcurrency import class Foundation.FileManager +@preconcurrency import struct Foundation.CocoaError @preconcurrency import func Foundation.fputs @preconcurrency import func Foundation.exit @preconcurrency import var Foundation.stderr @@ -27,10 +28,10 @@ struct PackageToJSPlugin: CommandPlugin { "swift", "package", "--swift-sdk", "wasm32-unknown-wasi", "js", ] + arguments return """ - Please pass the `--swift-sdk` option to the "swift package" command. + Please pass `--swift-sdk` to "swift package". - Did you mean: - \(didYouMean.joined(separator: " ")) + Did you mean this? + \(didYouMean.joined(separator: " ")) """ }), ( @@ -67,22 +68,70 @@ struct PackageToJSPlugin: CommandPlugin { """ }), ] + + private func emitHintMessage(_ message: String) { + printStderr("\n" + "\u{001B}[1m\u{001B}[97mHint:\u{001B}[0m " + message) + } + private func reportBuildFailure( _ build: PackageManager.BuildResult, _ arguments: [String] ) { for diagnostic in Self.friendlyBuildDiagnostics { if let message = diagnostic(build, arguments) { - printStderr("\n" + "\u{001B}[1m\u{001B}[97mHint:\u{001B}[0m " + message) + emitHintMessage(message) + return } } } func performCommand(context: PluginContext, arguments: [String]) throws { - if arguments.first == "test" { - return try performTestCommand(context: context, arguments: Array(arguments.dropFirst())) - } + do { + if arguments.first == "test" { + return try performTestCommand(context: context, arguments: Array(arguments.dropFirst())) + } + + return try performBuildCommand(context: context, arguments: arguments) + } catch let error as CocoaError where error.code == .fileWriteNoPermission { + guard let filePath = error.filePath else { throw error } - return try performBuildCommand(context: context, arguments: arguments) + let packageDir = context.package.directoryURL + printStderr("\n\u{001B}[1m\u{001B}[91merror:\u{001B}[0m \(error.localizedDescription)") + + if filePath.hasPrefix(packageDir.path) { + // Emit hint for --allow-writing-to-package-directory if the destination path + // is under the package directory + let didYouMean = [ + "swift", "package", "--swift-sdk", "wasm32-unknown-wasi", + "plugin", "--allow-writing-to-package-directory", + "js", + ] + arguments + emitHintMessage( + """ + Please pass `--allow-writing-to-package-directory` to "swift package". + + Did you mean this? + \(didYouMean.joined(separator: " ")) + """ + ) + } else { + // Emit hint for --allow-writing-to-directory <directory> + // if the destination path is outside the package directory + let didYouMean = [ + "swift", "package", "--swift-sdk", "wasm32-unknown-wasi", + "plugin", "--allow-writing-to-directory", "\(filePath)", + "js", + ] + arguments + emitHintMessage( + """ + Please pass `--allow-writing-to-directory <directory>` to "swift package". + + Did you mean this? + \(didYouMean.joined(separator: " ")) + """ + ) + } + exit(1) + } } static let JAVASCRIPTKIT_PACKAGE_ID: Package.ID = "javascriptkit"