Skip to content

Commit 3527bb7

Browse files
committed
initial
1 parent fee7838 commit 3527bb7

File tree

1 file changed

+52
-45
lines changed

1 file changed

+52
-45
lines changed

CodeGeneration/Sources/generate-swift-syntax/GenerateSwiftSyntax.swift

Lines changed: 52 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ struct TemplateSpec {
6868
}
6969

7070
@main
71-
struct GenerateSwiftSyntax: ParsableCommand {
71+
struct GenerateSwiftSyntax: AsyncParsableCommand {
7272
@Argument(help: "The path to the source directory (i.e. 'swift-syntax/Sources') where the source files are to be generated")
7373
var destination: String = {
7474
let sourcesURL = URL(fileURLWithPath: #filePath)
@@ -83,7 +83,7 @@ struct GenerateSwiftSyntax: ParsableCommand {
8383
@Flag(help: "Enable verbose output")
8484
var verbose: Bool = false
8585

86-
func run() throws {
86+
func run() async throws {
8787
let destination = URL(fileURLWithPath: self.destination).standardizedFileURL
8888

8989
var fileSpecs: [GeneratedFileSpec] = [
@@ -139,7 +139,6 @@ struct GenerateSwiftSyntax: ParsableCommand {
139139

140140
let modules = Set(fileSpecs.compactMap { $0.pathComponents.first })
141141

142-
let previouslyGeneratedFilesLock = NSLock()
143142
var previouslyGeneratedFiles = Set(
144143
modules.flatMap { (module) -> [URL] in
145144
let generatedDir =
@@ -154,32 +153,39 @@ struct GenerateSwiftSyntax: ParsableCommand {
154153
}
155154
)
156155

157-
var errors: [Error] = []
158-
DispatchQueue.concurrentPerform(iterations: fileSpecs.count) { index in
159-
let fileSpec = fileSpecs[index]
160-
do {
161-
var destination = destination
162-
for component in fileSpec.pathComponents {
163-
destination = destination.appendingPathComponent(component)
156+
let specs = fileSpecs
157+
await withTaskGroup(of: (URL, Error?).self) { group in
158+
for index in 0..<fileSpecs.count {
159+
group.addTask {
160+
let fileSpec = specs[index]
161+
do {
162+
var destination = destination
163+
for component in fileSpec.pathComponents {
164+
destination = destination.appendingPathComponent(component)
165+
}
166+
do {
167+
try generateFile(
168+
contents: fileSpec.contents,
169+
destination: destination,
170+
verbose: verbose
171+
)
172+
} catch {
173+
// If we throw from here, we'll lose the URL,
174+
// and we'll end up removing a file that is still
175+
// included in the files we intend to generate,
176+
// even if we failed to do so on this run.
177+
return (destination, error)
178+
}
179+
return (destination, nil)
180+
}
181+
}
182+
}
183+
for await result in group {
184+
_ = previouslyGeneratedFiles.remove(result.0)
185+
if let error = result.1 {
186+
print(error)
164187
}
165-
166-
previouslyGeneratedFilesLock.lock();
167-
_ = previouslyGeneratedFiles.remove(destination)
168-
previouslyGeneratedFilesLock.unlock()
169-
170-
try generateFile(
171-
contents: fileSpec.contents,
172-
destination: destination,
173-
verbose: verbose
174-
)
175-
} catch {
176-
errors.append(error)
177188
}
178-
}
179-
180-
if let firstError = errors.first {
181-
// TODO: It would be nice if we could emit all errors
182-
throw firstError
183189
}
184190

185191
for file in previouslyGeneratedFiles {
@@ -189,24 +195,25 @@ struct GenerateSwiftSyntax: ParsableCommand {
189195
}
190196
}
191197

192-
private func generateFile(
193-
contents: @autoclosure () -> String,
194-
destination: URL,
195-
verbose: Bool
196-
) throws {
197-
try FileManager.default.createDirectory(
198-
atPath: destination.deletingLastPathComponent().path,
199-
withIntermediateDirectories: true,
200-
attributes: nil
201-
)
198+
}
202199

203-
if verbose {
204-
print("Generating \(destination.path)...")
205-
}
206-
let start = Date()
207-
try contents().write(to: destination, atomically: true, encoding: .utf8)
208-
if verbose {
209-
print("Generated \(destination.path) in \((Date().timeIntervalSince(start) * 1000).rounded() / 1000)s")
210-
}
200+
func generateFile(
201+
contents: @autoclosure () -> String,
202+
destination: URL,
203+
verbose: Bool
204+
) throws {
205+
try FileManager.default.createDirectory(
206+
atPath: destination.deletingLastPathComponent().path,
207+
withIntermediateDirectories: true,
208+
attributes: nil
209+
)
210+
211+
if verbose {
212+
print("Generating \(destination.path)...")
213+
}
214+
let start = Date()
215+
try contents().write(to: destination, atomically: true, encoding: .utf8)
216+
if verbose {
217+
print("Generated \(destination.path) in \((Date().timeIntervalSince(start) * 1000).rounded() / 1000)s")
211218
}
212219
}

0 commit comments

Comments
 (0)