Skip to content

Commit 7363d0e

Browse files
committed
Fix Windows and Linux builds
1 parent a658c10 commit 7363d0e

File tree

10 files changed

+156
-124
lines changed

10 files changed

+156
-124
lines changed

Sources/Subprocess/Error.swift

Lines changed: 41 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public struct SubprocessError: Swift.Error, Sendable {
3737
public let underlyingError: UnderlyingError?
3838

3939
/// Context associated with this error for better error message
40-
private let context: [Code : Context]
40+
private let context: [Code: Context]
4141
}
4242

4343
// MARK: - Error Codes
@@ -117,7 +117,7 @@ extension SubprocessError {
117117
return String(describing: error)
118118
#if os(Windows)
119119
case .internalError(let windowsError):
120-
return windowsError.localizedDescription
120+
return String(describing: windowsError)
121121
#else
122122
case .internalError(let errno):
123123
return errno.description
@@ -150,42 +150,51 @@ extension SubprocessError {
150150
}
151151
}
152152

153-
private enum Context: Sendable, Equatable{
153+
private enum Context: Sendable, Equatable {
154154
case string(String)
155155
case int(Int)
156156
case processControlOperation(ProcessControlOperation)
157157
}
158158

159159
internal enum ProcessControlOperation: Sendable, Equatable {
160-
case sendSignal(Int32) // Unix
161-
case terminate // Windows
162-
case suspend // Windows
163-
case resume // Windows
160+
case sendSignal(Int32) // Unix
161+
case terminate // Windows
162+
case suspend // Windows
163+
case resume // Windows
164164
}
165165
}
166166

167-
168167
// MARK: - Description
169168
extension SubprocessError: CustomStringConvertible, CustomDebugStringConvertible {
170169
/// A textual representation of this subprocess error.
171170
public var description: String {
172171
switch self.code.storage {
173172
case .spawnFailed:
173+
var message = ["Failed to spawn the new process."]
174+
175+
if let context = self.context[self.code],
176+
case .string(let reason) = context
177+
{
178+
message.append("Reason: \(reason)")
179+
}
180+
174181
if let underlying = self.underlyingError {
175-
return "Failed to spawn the new process with underlying error: \(underlying)"
176-
} else {
177-
return "Failed to spawn the new process"
182+
message.append("Underlying error: \(underlying)")
178183
}
184+
185+
return message.joined(separator: " ")
179186
case .executableNotFound:
180187
if let context = self.context[self.code],
181-
case .string(let executableName) = context {
188+
case .string(let executableName) = context
189+
{
182190
return "Executable \"\(executableName)\" is not found or cannot be executed."
183191
} else {
184192
return "Executable is not found or cannot be executed."
185193
}
186194
case .failedToChangeWorkingDirectory:
187195
if let context = self.context[self.code],
188-
case .string(let directory) = context {
196+
case .string(let directory) = context
197+
{
189198
return "Failed to set working directory to \"\(directory)\"."
190199
} else {
191200
return "Failed to change working directory."
@@ -211,7 +220,8 @@ extension SubprocessError: CustomStringConvertible, CustomDebugStringConvertible
211220
}
212221
case .outputLimitExceeded:
213222
if let context = self.context[self.code],
214-
case .int(let limit) = context {
223+
case .int(let limit) = context
224+
{
215225
return "Child process output exceeded the limit of \(limit) bytes."
216226
} else {
217227
return "Child process output exceeded the limit."
@@ -231,7 +241,8 @@ extension SubprocessError: CustomStringConvertible, CustomDebugStringConvertible
231241

232242
case .processControlFailed:
233243
if let context = self.context[self.code],
234-
case .processControlOperation(let operation) = context {
244+
case .processControlOperation(let operation) = context
245+
{
235246
switch operation {
236247
case .sendSignal(let signal):
237248
return "Failed to send signal \(signal) to child process"
@@ -280,7 +291,7 @@ extension SubprocessError {
280291
return SubprocessError(
281292
code: .executableNotFound,
282293
underlyingError: .init(internalError),
283-
context: [.executableNotFound : .string(executable)]
294+
context: [.executableNotFound: .string(executable)]
284295
)
285296
}
286297

@@ -296,7 +307,7 @@ extension SubprocessError {
296307
return SubprocessError(
297308
code: .processControlFailed,
298309
underlyingError: .init(internalError),
299-
context: [.processControlFailed : .processControlOperation(operation)]
310+
context: [.processControlFailed: .processControlOperation(operation)]
300311
)
301312
}
302313

@@ -308,11 +319,18 @@ extension SubprocessError {
308319
)
309320
}
310321

311-
internal static func spawnFailed<E: Swift.Error>(withInternalError internalError: E?) -> Self {
322+
internal static func spawnFailed(
323+
withInternalError internalError: InternalError?,
324+
reason: String? = nil
325+
) -> Self {
326+
var context: [SubprocessError.Code: SubprocessError.Context] = [:]
327+
if let reason = reason {
328+
context[.spawnFailed] = .string(reason)
329+
}
312330
return SubprocessError(
313331
code: .spawnFailed,
314332
underlyingError: .init(internalError),
315-
context: [:]
333+
context: context
316334
)
317335
}
318336

@@ -321,7 +339,7 @@ extension SubprocessError {
321339
code: .outputLimitExceeded,
322340
underlyingError: nil,
323341
context: [
324-
.outputLimitExceeded : .int(limit)
342+
.outputLimitExceeded: .int(limit)
325343
]
326344
)
327345
}
@@ -366,8 +384,8 @@ extension SubprocessError {
366384
)
367385
}
368386

369-
internal static func failedToWriteToProcess<E: Swift.Error>(
370-
withInternalError internalError: E?
387+
internal static func failedToWriteToProcess(
388+
withInternalError internalError: SubprocessError.InternalError?
371389
) -> Self {
372390
return SubprocessError(
373391
code: .failedToWriteToSubprocess,
@@ -390,7 +408,7 @@ extension SubprocessError {
390408
_ target: String?,
391409
internalError: InternalError?
392410
) -> Self {
393-
var context: [SubprocessError.Code : SubprocessError.Context] = [:]
411+
var context: [SubprocessError.Code: SubprocessError.Context] = [:]
394412
if let targetPath = target {
395413
context[.failedToChangeWorkingDirectory] = .string(targetPath)
396414
}
@@ -411,4 +429,3 @@ extension SubprocessError {
411429
)
412430
}
413431
}
414-

Sources/Subprocess/IO/AsyncIO+Dispatch.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,8 @@ final class AsyncIO: Sendable {
5353
) { done, data, error in
5454
if error != 0 {
5555
continuation.resume(
56-
throwing: SubprocessError
56+
throwing:
57+
SubprocessError
5758
.failedToReadFromProcess(
5859
withInternalError: Errno(rawValue: error)
5960
)

Sources/Subprocess/IO/AsyncIO+Linux.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -479,7 +479,9 @@ extension AsyncIO {
479479
} catch {
480480
// Reset error code to .failedToWrite to match other platforms
481481
guard let originalError = error as? SubprocessError else {
482-
throw SubprocessError.failedToWriteToProcess(withInternalError: error)
482+
throw SubprocessError.failedToWriteToProcess(
483+
withInternalError: error as? SubprocessError.InternalError
484+
)
483485
}
484486
throw SubprocessError.failedToWriteToProcess(
485487
withUnderlyingError: originalError.underlyingError
@@ -539,7 +541,7 @@ extension AsyncIO {
539541
// Reset error code to .failedToWrite to match other platforms
540542
guard let originalError = error as? SubprocessError else {
541543
throw SubprocessError.failedToWriteToProcess(
542-
withInternalError: error
544+
withInternalError: error as? SubprocessError.InternalError
543545
)
544546
}
545547
throw SubprocessError.failedToWriteToProcess(

Sources/Subprocess/IO/AsyncIO+Windows.swift

Lines changed: 33 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,9 @@ final class AsyncIO: @unchecked Sendable {
6565
INVALID_HANDLE_VALUE, nil, 0, 0
6666
), ioCompletionPort != INVALID_HANDLE_VALUE
6767
else {
68-
let error = SubprocessError(
69-
code: .init(.asyncIOFailed("CreateIoCompletionPort failed")),
70-
underlyingError: SubprocessError.WindowsError(rawValue: GetLastError())
68+
let error: SubprocessError = .asyncIOFailed(
69+
reason: "CreateIoCompletionPort failed",
70+
internalError: SubprocessError.WindowsError(rawValue: GetLastError())
7171
)
7272
self.ioCompletionPort = .failure(error)
7373
self.monitorThread = .failure(error)
@@ -119,9 +119,9 @@ final class AsyncIO: @unchecked Sendable {
119119
continuation?.finish()
120120
continue
121121
} else {
122-
let error = SubprocessError(
123-
code: .init(.asyncIOFailed("GetQueuedCompletionStatus failed")),
124-
underlyingError: SubprocessError.WindowsError(rawValue: lastError)
122+
let error: SubprocessError = .asyncIOFailed(
123+
reason: "GetQueuedCompletionStatus failed",
124+
internalError: SubprocessError.WindowsError(rawValue: lastError)
125125
)
126126
reportError(error)
127127
break
@@ -145,9 +145,9 @@ final class AsyncIO: @unchecked Sendable {
145145
return 0
146146
}
147147
} catch let underlyingError {
148-
let error = SubprocessError(
149-
code: .init(.asyncIOFailed("Failed to create monitor thread")),
150-
underlyingError: underlyingError
148+
let error: SubprocessError = .asyncIOFailed(
149+
reason: "Failed to create monitor thread",
150+
internalError: underlyingError
151151
)
152152
self.monitorThread = .failure(error)
153153
return
@@ -219,9 +219,9 @@ final class AsyncIO: @unchecked Sendable {
219219
handle, ioPort, completionKey, 0
220220
) == ioPort
221221
else {
222-
let error = SubprocessError(
223-
code: .init(.asyncIOFailed("CreateIoCompletionPort failed")),
224-
underlyingError: SubprocessError.WindowsError(rawValue: GetLastError())
222+
let error: SubprocessError = .asyncIOFailed(
223+
reason: "CreateIoCompletionPort failed",
224+
internalError: SubprocessError.WindowsError(rawValue: GetLastError())
225225
)
226226
continuation.finish(throwing: error)
227227
return
@@ -304,9 +304,8 @@ final class AsyncIO: @unchecked Sendable {
304304
return resultBuffer
305305
}
306306
guard lastError == ERROR_IO_PENDING else {
307-
let error = SubprocessError(
308-
code: .init(.failedToReadFromSubprocess),
309-
underlyingError: SubprocessError.WindowsError(rawValue: lastError)
307+
let error: SubprocessError = .failedToReadFromProcess(
308+
withInternalError: SubprocessError.WindowsError(rawValue: lastError)
310309
)
311310
throw error
312311
}
@@ -317,9 +316,11 @@ final class AsyncIO: @unchecked Sendable {
317316
do {
318317
bytesRead = try await signalStream.next() ?? 0
319318
} catch {
320-
throw SubprocessError(
321-
code: .init(.failedToReadFromSubprocess),
322-
underlyingError: error
319+
if let subprocessError = error as? SubprocessError {
320+
throw subprocessError
321+
}
322+
throw SubprocessError.failedToReadFromProcess(
323+
withInternalError: error as? SubprocessError.InternalError
323324
)
324325
}
325326

@@ -393,9 +394,8 @@ final class AsyncIO: @unchecked Sendable {
393394
// Make sure we only get `ERROR_IO_PENDING`
394395
let lastError = GetLastError()
395396
guard lastError == ERROR_IO_PENDING else {
396-
let error = SubprocessError(
397-
code: .init(.failedToWriteToSubprocess),
398-
underlyingError: SubprocessError.WindowsError(rawValue: lastError)
397+
let error: SubprocessError = .failedToWriteToProcess(
398+
withInternalError: SubprocessError.WindowsError(rawValue: lastError)
399399
)
400400
throw error
401401
}
@@ -407,9 +407,11 @@ final class AsyncIO: @unchecked Sendable {
407407
do {
408408
bytesWritten = try await signalStream.next() ?? 0
409409
} catch {
410-
throw SubprocessError(
411-
code: .init(.failedToWriteToSubprocess),
412-
underlyingError: error
410+
if let subprocessError = error as? SubprocessError {
411+
throw subprocessError
412+
}
413+
throw SubprocessError.failedToWriteToProcess(
414+
withInternalError: error as? SubprocessError.InternalError
413415
)
414416
}
415417

@@ -457,9 +459,8 @@ final class AsyncIO: @unchecked Sendable {
457459
// Make sure we only get `ERROR_IO_PENDING`
458460
let lastError = GetLastError()
459461
guard lastError == ERROR_IO_PENDING else {
460-
let error = SubprocessError(
461-
code: .init(.failedToWriteToSubprocess),
462-
underlyingError: SubprocessError.WindowsError(rawValue: lastError)
462+
let error: SubprocessError = .failedToWriteToProcess(
463+
withInternalError: SubprocessError.WindowsError(rawValue: lastError)
463464
)
464465
throw error
465466
}
@@ -469,9 +470,11 @@ final class AsyncIO: @unchecked Sendable {
469470
do {
470471
bytesWritten = try await signalStream.next() ?? 0
471472
} catch {
472-
throw SubprocessError(
473-
code: .init(.failedToWriteToSubprocess),
474-
underlyingError: error
473+
if let subprocessError = error as? SubprocessError {
474+
throw subprocessError
475+
}
476+
throw SubprocessError.failedToWriteToProcess(
477+
withInternalError: error as? SubprocessError.InternalError
475478
)
476479
}
477480
writtenLength += Int(truncatingIfNeeded: bytesWritten)

Sources/Subprocess/Platforms/Subprocess+Darwin.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -398,7 +398,7 @@ extension Configuration {
398398
do {
399399
try spawnConfig(&spawnAttributes, &fileActions)
400400
} catch {
401-
throw .spawnFailed(withInternalError: error)
401+
throw .executionBodyThrewError(error)
402402
}
403403
}
404404

0 commit comments

Comments
 (0)