Skip to content

Commit 33e955a

Browse files
authored
Merge pull request #1632 from ahoppen/lazy-workspace-loading
Don’t block the generation of a build system by build graph generation
2 parents dfbf8f4 + 6e0281f commit 33e955a

14 files changed

+249
-145
lines changed

Sources/BuildSystemIntegration/BuildServerBuildSystem.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,9 @@ extension BuildServerBuildSystem: BuildSystem {
281281
return [ConfiguredTarget(targetID: "dummy", runDestinationID: "dummy")]
282282
}
283283

284-
package func generateBuildGraph(allowFileSystemWrites: Bool) {}
284+
package func generateBuildGraph() {}
285+
286+
package func waitForUpToDateBuildGraph() async {}
285287

286288
package func topologicalSort(of targets: [ConfiguredTarget]) async -> [ConfiguredTarget]? {
287289
return nil

Sources/BuildSystemIntegration/BuildSystem.swift

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -138,13 +138,10 @@ package protocol BuildSystem: AnyObject, Sendable {
138138
func configuredTargets(for document: DocumentURI) async -> [ConfiguredTarget]
139139

140140
/// Re-generate the build graph.
141-
///
142-
/// If `allowFileSystemWrites` is `true`, this should include all the tasks that are necessary for building the entire
143-
/// build graph, like resolving package versions.
144-
///
145-
/// If `allowFileSystemWrites` is `false`, no files must be written to disk. This mode is used to determine whether
146-
/// the build system can handle a source file, and decide whether a workspace should be opened with this build system
147-
func generateBuildGraph(allowFileSystemWrites: Bool) async throws
141+
func generateBuildGraph() async throws
142+
143+
/// Wait until the build graph has been loaded.
144+
func waitForUpToDateBuildGraph() async
148145

149146
/// Sort the targets so that low-level targets occur before high-level targets.
150147
///

Sources/BuildSystemIntegration/BuildSystemManager.swift

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -265,8 +265,12 @@ extension BuildSystemManager {
265265
return settings
266266
}
267267

268-
package func generateBuildGraph(allowFileSystemWrites: Bool) async throws {
269-
try await self.buildSystem?.generateBuildGraph(allowFileSystemWrites: allowFileSystemWrites)
268+
package func generateBuildGraph() async throws {
269+
try await self.buildSystem?.generateBuildGraph()
270+
}
271+
272+
package func waitForUpToDateBuildGraph() async {
273+
await self.buildSystem?.waitForUpToDateBuildGraph()
270274
}
271275

272276
package func topologicalSort(of targets: [ConfiguredTarget]) async throws -> [ConfiguredTarget]? {

Sources/BuildSystemIntegration/CompilationDatabaseBuildSystem.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,9 @@ extension CompilationDatabaseBuildSystem: BuildSystem {
133133
throw PrepareNotSupportedError()
134134
}
135135

136-
package func generateBuildGraph(allowFileSystemWrites: Bool) {}
136+
package func generateBuildGraph() {}
137+
138+
package func waitForUpToDateBuildGraph() async {}
137139

138140
package func topologicalSort(of targets: [ConfiguredTarget]) -> [ConfiguredTarget]? {
139141
return nil

Sources/BuildSystemIntegration/SwiftPMBuildSystem.swift

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,10 @@ package actor SwiftPMBuildSystem {
119119

120120
private let testHooks: SwiftPMTestHooks
121121

122+
/// The queue on which we reload the package to ensure we don't reload it multiple times concurrently, which can cause
123+
/// issues in SwiftPM.
124+
private let packageLoadingQueue = AsyncQueue<Serial>()
125+
122126
/// Delegate to handle any build system events.
123127
package weak var delegate: BuildSystemIntegration.BuildSystemDelegate? = nil
124128

@@ -361,7 +365,14 @@ package actor SwiftPMBuildSystem {
361365
extension SwiftPMBuildSystem {
362366
/// (Re-)load the package settings by parsing the manifest and resolving all the targets and
363367
/// dependencies.
364-
package func reloadPackage(forceResolvedVersions: Bool) async throws {
368+
package func reloadPackage() async throws {
369+
try await packageLoadingQueue.asyncThrowing {
370+
try await self.reloadPackageImpl()
371+
}.valuePropagatingCancellation
372+
}
373+
374+
/// - Important: Must only be called on `packageLoadingQueue`.
375+
private func reloadPackageImpl() async throws {
365376
await reloadPackageStatusCallback(.start)
366377
await testHooks.reloadPackageDidStart?()
367378
defer {
@@ -373,7 +384,7 @@ extension SwiftPMBuildSystem {
373384

374385
let modulesGraph = try await self.workspace.loadPackageGraph(
375386
rootInput: PackageGraphRootInput(packages: [AbsolutePath(projectRoot)]),
376-
forceResolvedVersions: forceResolvedVersions,
387+
forceResolvedVersions: !isForIndexBuild,
377388
observabilityScope: observabilitySystem.topScope
378389
)
379390

@@ -538,8 +549,12 @@ extension SwiftPMBuildSystem: BuildSystemIntegration.BuildSystem {
538549
return []
539550
}
540551

541-
package func generateBuildGraph(allowFileSystemWrites: Bool) async throws {
542-
try await self.reloadPackage(forceResolvedVersions: !isForIndexBuild || !allowFileSystemWrites)
552+
package func generateBuildGraph() async throws {
553+
try await self.reloadPackage()
554+
}
555+
556+
package func waitForUpToDateBuildGraph() async {
557+
await self.packageLoadingQueue.async {}.valuePropagatingCancellation
543558
}
544559

545560
package func topologicalSort(of targets: [ConfiguredTarget]) -> [ConfiguredTarget]? {
@@ -728,7 +743,7 @@ extension SwiftPMBuildSystem: BuildSystemIntegration.BuildSystem {
728743
if events.contains(where: { self.fileEventShouldTriggerPackageReload(event: $0) }) {
729744
logger.log("Reloading package because of file change")
730745
await orLog("Reloading package") {
731-
try await self.reloadPackage(forceResolvedVersions: !isForIndexBuild)
746+
try await self.reloadPackage()
732747
}
733748
}
734749

Sources/SemanticIndex/SemanticIndexManager.swift

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -266,9 +266,7 @@ package final actor SemanticIndexManager {
266266
signposter.endInterval("Preparing", state)
267267
}
268268
await testHooks.buildGraphGenerationDidStart?()
269-
await orLog("Generating build graph") {
270-
try await self.buildSystemManager.generateBuildGraph(allowFileSystemWrites: true)
271-
}
269+
await self.buildSystemManager.waitForUpToDateBuildGraph()
272270
// Ensure that we have an up-to-date indexstore-db. Waiting for the indexstore-db to be updated is cheaper than
273271
// potentially not knowing about unit files, which causes the corresponding source files to be re-indexed.
274272
index.pollForUnitChangesAndWait()

0 commit comments

Comments
 (0)