Skip to content

Commit d031cd2

Browse files
committed
Wrap all incoming errors for diagnostic purposes.
1 parent a99d762 commit d031cd2

File tree

4 files changed

+36
-6
lines changed

4 files changed

+36
-6
lines changed

.cursorrules

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ Avoid conditional compilation as it makes code that runs on other platforms impo
3636

3737
Never swallow errors. When a function can fail, use `throws` to propagate descriptive errors rather than returning optionals or silently failing. This ensures failures are visible and debuggable.
3838

39+
When system APIs or external processes throw errors, wrap them in `Failure` with contextual information about what operation was being performed. This makes errors easier to diagnose, especially on different platforms. For example, wrap file I/O errors with the path being accessed, and process execution errors with the command being run.
40+
3941
When invoking `swiftc`, pass `-module-cache-path` with a temporary directory to avoid conflicts when running in parallel (e.g., during `swift test`).
4042

4143
## Naming Guidelines

Sources/gyb-swift/ExecutionContext.swift

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,11 @@ struct CodeGenerator {
134134
try? FileManager.default.removeItem(at: temp)
135135
}
136136

137-
try swiftCode.write(to: temp, atomically: true, encoding: .utf8)
137+
do {
138+
try swiftCode.write(to: temp, atomically: true, encoding: .utf8)
139+
} catch {
140+
throw Failure("Failed to write temporary Swift file to '\(temp.path)'", error)
141+
}
138142

139143
let result = try runProcess("swift", arguments: [temp.platformString])
140144

@@ -150,7 +154,11 @@ struct CodeGenerator {
150154
let tempFiles = createTempFiles()
151155
defer { cleanupTempFiles(tempFiles) }
152156

153-
try swiftCode.write(to: tempFiles.source, atomically: true, encoding: .utf8)
157+
do {
158+
try swiftCode.write(to: tempFiles.source, atomically: true, encoding: .utf8)
159+
} catch {
160+
throw Failure("Failed to write temporary Swift file to '\(tempFiles.source.path)'", error)
161+
}
154162
try compileSwiftCode(
155163
source: tempFiles.source, output: tempFiles.executable, moduleCache: tempFiles.moduleCache)
156164
return try runCompiledExecutable(tempFiles.actualExecutable)

Sources/gyb-swift/ProcessUtilities.swift

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,21 @@ private func runProcessForOutput(
3838
return result.stdout.trimmingCharacters(in: .whitespacesAndNewlines)
3939
}
4040

41-
struct Failure: Error {
41+
struct Failure: Error, CustomStringConvertible {
4242
let reason: String
4343
let error: (any Error)?
44+
4445
init(_ reason: String, _ error: (any Error)? = nil) {
4546
self.reason = reason
4647
self.error = error
4748
}
49+
50+
var description: String {
51+
if let error = error {
52+
return "\(reason): \(error)"
53+
}
54+
return reason
55+
}
4856
}
4957

5058
/// Searches for an executable in PATH on Windows using `where.exe`.
@@ -133,7 +141,11 @@ func runProcess(_ command: String, arguments: [String]) throws -> ProcessOutput
133141
process.standardOutput = stdoutPipe
134142
process.standardError = stderrPipe
135143

136-
try process.run()
144+
do {
145+
try process.run()
146+
} catch {
147+
throw Failure("Failed to run '\(command) \(arguments.joined(separator: " "))'", error)
148+
}
137149

138150
// Read pipes on background threads to prevent deadlock if output exceeds pipe buffer size.
139151
// The child process will block if pipe buffers fill up, so we must drain them continuously.

Sources/gyb-swift/gyb_swift.swift

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,11 @@ struct GYBSwift: ParsableCommand {
142142
} else {
143143
// Read from file
144144
let source = URL(fileURLWithPath: file)
145-
templateText = try String(contentsOf: source, encoding: .utf8)
145+
do {
146+
templateText = try String(contentsOf: source, encoding: .utf8)
147+
} catch {
148+
throw Failure("Failed to read template file '\(file)'", error)
149+
}
146150
filename = file
147151
}
148152

@@ -190,7 +194,11 @@ struct GYBSwift: ParsableCommand {
190194
print(result, terminator: "")
191195
} else {
192196
let destination = URL(fileURLWithPath: output)
193-
try result.write(to: destination, atomically: true, encoding: .utf8)
197+
do {
198+
try result.write(to: destination, atomically: true, encoding: .utf8)
199+
} catch {
200+
throw Failure("Failed to write output to '\(output)'", error)
201+
}
194202
}
195203
}
196204
}

0 commit comments

Comments
 (0)