5
5
@preconcurrency import class Foundation. Process
6
6
@preconcurrency import class Foundation. ProcessInfo
7
7
@preconcurrency import class Foundation. FileManager
8
+ @preconcurrency import struct Foundation. CocoaError
8
9
@preconcurrency import func Foundation. fputs
9
10
@preconcurrency import func Foundation. exit
10
11
@preconcurrency import var Foundation. stderr
@@ -27,10 +28,10 @@ struct PackageToJSPlugin: CommandPlugin {
27
28
" swift " , " package " , " --swift-sdk " , " wasm32-unknown-wasi " , " js " ,
28
29
] + arguments
29
30
return """
30
- Please pass the `--swift-sdk` option to the " swift package " command .
31
+ Please pass `--swift-sdk` to " swift package " .
31
32
32
- Did you mean:
33
- \( didYouMean. joined ( separator: " " ) )
33
+ Did you mean this?
34
+ \( didYouMean. joined ( separator: " " ) )
34
35
"""
35
36
} ) ,
36
37
(
@@ -67,22 +68,70 @@ struct PackageToJSPlugin: CommandPlugin {
67
68
"""
68
69
} ) ,
69
70
]
71
+
72
+ private func emitHintMessage( _ message: String ) {
73
+ printStderr ( " \n " + " \u{001B} [1m \u{001B} [97mHint: \u{001B} [0m " + message)
74
+ }
75
+
70
76
private func reportBuildFailure(
71
77
_ build: PackageManager . BuildResult , _ arguments: [ String ]
72
78
) {
73
79
for diagnostic in Self . friendlyBuildDiagnostics {
74
80
if let message = diagnostic ( build, arguments) {
75
- printStderr ( " \n " + " \u{001B} [1m \u{001B} [97mHint: \u{001B} [0m " + message)
81
+ emitHintMessage ( message)
82
+ return
76
83
}
77
84
}
78
85
}
79
86
80
87
func performCommand( context: PluginContext , arguments: [ String ] ) throws {
81
- if arguments. first == " test " {
82
- return try performTestCommand ( context: context, arguments: Array ( arguments. dropFirst ( ) ) )
83
- }
88
+ do {
89
+ if arguments. first == " test " {
90
+ return try performTestCommand ( context: context, arguments: Array ( arguments. dropFirst ( ) ) )
91
+ }
92
+
93
+ return try performBuildCommand ( context: context, arguments: arguments)
94
+ } catch let error as CocoaError where error. code == . fileWriteNoPermission {
95
+ guard let filePath = error. filePath else { throw error }
84
96
85
- return try performBuildCommand ( context: context, arguments: arguments)
97
+ let packageDir = context. package . directoryURL
98
+ printStderr ( " \n \u{001B} [1m \u{001B} [91merror: \u{001B} [0m \( error. localizedDescription) " )
99
+
100
+ if filePath. hasPrefix ( packageDir. path) {
101
+ // Emit hint for --allow-writing-to-package-directory if the destination path
102
+ // is under the package directory
103
+ let didYouMean = [
104
+ " swift " , " package " , " --swift-sdk " , " wasm32-unknown-wasi " ,
105
+ " plugin " , " --allow-writing-to-package-directory " ,
106
+ " js " ,
107
+ ] + arguments
108
+ emitHintMessage (
109
+ """
110
+ Please pass `--allow-writing-to-package-directory` to " swift package " .
111
+
112
+ Did you mean this?
113
+ \( didYouMean. joined ( separator: " " ) )
114
+ """
115
+ )
116
+ } else {
117
+ // Emit hint for --allow-writing-to-directory <directory>
118
+ // if the destination path is outside the package directory
119
+ let didYouMean = [
120
+ " swift " , " package " , " --swift-sdk " , " wasm32-unknown-wasi " ,
121
+ " plugin " , " --allow-writing-to-directory " , " \( filePath) " ,
122
+ " js " ,
123
+ ] + arguments
124
+ emitHintMessage (
125
+ """
126
+ Please pass `--allow-writing-to-directory <directory>` to " swift package " .
127
+
128
+ Did you mean this?
129
+ \( didYouMean. joined ( separator: " " ) )
130
+ """
131
+ )
132
+ }
133
+ exit ( 1 )
134
+ }
86
135
}
87
136
88
137
static let JAVASCRIPTKIT_PACKAGE_ID : Package . ID = " javascriptkit "
0 commit comments