@@ -48,7 +48,7 @@ public enum ReloadPackageStatus {
48
48
/// This class implements the `BuildSystem` interface to provide the build settings for a Swift
49
49
/// Package Manager (SwiftPM) package. The settings are determined by loading the Package.swift
50
50
/// manifest using `libSwiftPM` and constructing a build plan using the default (debug) parameters.
51
- public final class SwiftPMWorkspace {
51
+ public actor SwiftPMWorkspace {
52
52
53
53
public enum Error : Swift . Error {
54
54
@@ -82,14 +82,6 @@ public final class SwiftPMWorkspace {
82
82
/// mapped to the language the delegate specified when registering for change notifications.
83
83
var watchedFiles : [ DocumentURI : Language ] = [ : ]
84
84
85
- /// Queue guarding the following properties:
86
- /// - `delegate`
87
- /// - `watchedFiles`
88
- /// - `packageGraph`
89
- /// - `fileToTarget`
90
- /// - `sourceDirToTarget`
91
- let queue : DispatchQueue = . init( label: " SwiftPMWorkspace.queue " , qos: . utility)
92
-
93
85
/// This callback is informed when `reloadPackage` starts and ends executing.
94
86
var reloadPackageStatusCallback : ( ReloadPackageStatus ) -> Void
95
87
@@ -108,8 +100,7 @@ public final class SwiftPMWorkspace {
108
100
fileSystem: FileSystem = localFileSystem,
109
101
buildSetup: BuildSetup ,
110
102
reloadPackageStatusCallback: @escaping ( ReloadPackageStatus ) -> Void = { _ in }
111
- ) throws
112
- {
103
+ ) async throws {
113
104
self . workspacePath = workspacePath
114
105
self . fileSystem = fileSystem
115
106
@@ -169,15 +160,14 @@ public final class SwiftPMWorkspace {
169
160
/// - Parameters:
170
161
/// - reloadPackageStatusCallback: Will be informed when `reloadPackage` starts and ends executing.
171
162
/// - Returns: nil if `workspacePath` is not part of a package or there is an error.
172
- public convenience init ? (
163
+ public init ? (
173
164
url: URL ,
174
165
toolchainRegistry: ToolchainRegistry ,
175
166
buildSetup: BuildSetup ,
176
167
reloadPackageStatusCallback: @escaping ( ReloadPackageStatus ) -> Void
177
- )
178
- {
168
+ ) async {
179
169
do {
180
- try self . init (
170
+ try await self . init (
181
171
workspacePath: try TSCAbsolutePath ( validating: url. path) ,
182
172
toolchainRegistry: toolchainRegistry,
183
173
fileSystem: localFileSystem,
@@ -198,7 +188,6 @@ extension SwiftPMWorkspace {
198
188
199
189
/// (Re-)load the package settings by parsing the manifest and resolving all the targets and
200
190
/// dependencies.
201
- /// Must only be called on `queue` or from the initializer.
202
191
func reloadPackage( ) throws {
203
192
reloadPackageStatusCallback ( . start)
204
193
defer {
@@ -256,7 +245,7 @@ extension SwiftPMWorkspace {
256
245
var changedFiles : [ DocumentURI : FileBuildSettingsChange ] = [ : ]
257
246
for (uri, language) in self . watchedFiles {
258
247
orLog {
259
- if let settings = try self . settings ( for: uri, language) {
248
+ if let settings = try self . buildSettings ( for: uri, language : language) {
260
249
changedFiles [ uri] = FileBuildSettingsChange ( settings)
261
250
} else {
262
251
changedFiles [ uri] = . removedOrUnavailable
@@ -289,29 +278,10 @@ extension SwiftPMWorkspace: SKCore.BuildSystem {
289
278
for uri: DocumentURI ,
290
279
_ language: Language ) throws -> FileBuildSettings ?
291
280
{
292
- return try queue. sync {
293
- try self . settings ( for: uri, language)
294
- }
281
+ try self . buildSettings ( for: uri, language: language)
295
282
}
296
283
297
- public func buildSettings( for document: DocumentURI , language: Language ) async throws -> FileBuildSettings ? {
298
- return try await withCheckedThrowingContinuation { continuation in
299
- queue. async {
300
- do {
301
- continuation. resume ( returning: try self . settings ( for: document, language) )
302
- } catch {
303
- continuation. resume ( throwing: error)
304
- }
305
- }
306
- }
307
- }
308
-
309
- /// Must only be called on `queue`.
310
- private func settings(
311
- for uri: DocumentURI ,
312
- _ language: Language ) throws -> FileBuildSettings ?
313
- {
314
- dispatchPrecondition ( condition: . onQueue( queue) )
284
+ public func buildSettings( for uri: DocumentURI , language: Language ) throws -> FileBuildSettings ? {
315
285
guard let url = uri. fileURL else {
316
286
// We can't determine build settings for non-file URIs.
317
287
return nil
@@ -336,37 +306,31 @@ extension SwiftPMWorkspace: SKCore.BuildSystem {
336
306
}
337
307
338
308
public func registerForChangeNotifications( for uri: DocumentURI , language: Language ) {
339
- queue. async {
340
- assert ( self . watchedFiles [ uri] == nil , " Registered twice for change notifications of the same URI " )
341
- guard let delegate = self . delegate else { return }
342
- self . watchedFiles [ uri] = language
343
-
344
- var settings : FileBuildSettings ? = nil
345
- do {
346
- settings = try self . settings ( for: uri, language)
347
- } catch {
348
- log ( " error computing settings: \( error) " )
349
- }
350
- if let settings = settings {
351
- delegate. fileBuildSettingsChanged ( [ uri: FileBuildSettingsChange ( settings) ] )
352
- } else {
353
- delegate. fileBuildSettingsChanged ( [ uri: . removedOrUnavailable] )
354
- }
309
+ assert ( self . watchedFiles [ uri] == nil , " Registered twice for change notifications of the same URI " )
310
+ guard let delegate = self . delegate else { return }
311
+ self . watchedFiles [ uri] = language
312
+
313
+ var settings : FileBuildSettings ? = nil
314
+ do {
315
+ settings = try self . buildSettings ( for: uri, language: language)
316
+ } catch {
317
+ log ( " error computing settings: \( error) " )
318
+ }
319
+ if let settings = settings {
320
+ delegate. fileBuildSettingsChanged ( [ uri: FileBuildSettingsChange ( settings) ] )
321
+ } else {
322
+ delegate. fileBuildSettingsChanged ( [ uri: . removedOrUnavailable] )
355
323
}
356
324
}
357
325
358
326
/// Unregister the given file for build-system level change notifications, such as command
359
327
/// line flag changes, dependency changes, etc.
360
328
public func unregisterForChangeNotifications( for uri: DocumentURI ) {
361
- queue. async {
362
- self . watchedFiles [ uri] = nil
363
- }
329
+ self . watchedFiles [ uri] = nil
364
330
}
365
331
366
332
/// Returns the resolved target description for the given file, if one is known.
367
- /// Must only be called on `queue`.
368
333
private func targetDescription( for file: AbsolutePath ) throws -> TargetBuildDescription ? {
369
- dispatchPrecondition ( condition: . onQueue( queue) )
370
334
if let td = fileToTarget [ file] {
371
335
return td
372
336
}
@@ -403,12 +367,10 @@ extension SwiftPMWorkspace: SKCore.BuildSystem {
403
367
}
404
368
405
369
public func filesDidChange( _ events: [ FileEvent ] ) {
406
- queue. async {
407
- if events. contains ( where: { self . fileEventShouldTriggerPackageReload ( event: $0) } ) {
408
- orLog {
409
- // TODO: It should not be necessary to reload the entire package just to get build settings for one file.
410
- try self . reloadPackage ( )
411
- }
370
+ if events. contains ( where: { self . fileEventShouldTriggerPackageReload ( event: $0) } ) {
371
+ orLog {
372
+ // TODO: It should not be necessary to reload the entire package just to get build settings for one file.
373
+ try self . reloadPackage ( )
412
374
}
413
375
}
414
376
}
@@ -417,12 +379,10 @@ extension SwiftPMWorkspace: SKCore.BuildSystem {
417
379
guard let fileUrl = uri. fileURL else {
418
380
return . unhandled
419
381
}
420
- return self . queue. sync {
421
- if ( try ? targetDescription ( for: AbsolutePath ( validating: fileUrl. path) ) ) != nil {
422
- return . handled
423
- } else {
424
- return . unhandled
425
- }
382
+ if ( try ? targetDescription ( for: AbsolutePath ( validating: fileUrl. path) ) ) != nil {
383
+ return . handled
384
+ } else {
385
+ return . unhandled
426
386
}
427
387
}
428
388
}
@@ -450,9 +410,7 @@ extension SwiftPMWorkspace {
450
410
}
451
411
452
412
/// Retrieve settings for a package manifest (Package.swift).
453
- /// Must only be called on `queue`.
454
413
private func settings( forPackageManifest path: AbsolutePath ) throws -> FileBuildSettings ? {
455
- dispatchPrecondition ( condition: . onQueue( queue) )
456
414
func impl( _ path: AbsolutePath ) -> FileBuildSettings ? {
457
415
for package in packageGraph. packages where path == package . manifest. path {
458
416
let compilerArgs = workspace. interpreterFlags ( for: package . path) + [ path. pathString]
@@ -470,9 +428,7 @@ extension SwiftPMWorkspace {
470
428
}
471
429
472
430
/// Retrieve settings for a given header file.
473
- /// Must only be called on `queue`.
474
431
private func settings( forHeader path: AbsolutePath , _ language: Language ) throws -> FileBuildSettings ? {
475
- dispatchPrecondition ( condition: . onQueue( queue) )
476
432
func impl( _ path: AbsolutePath ) throws -> FileBuildSettings ? {
477
433
var dir = path. parentDirectory
478
434
while !dir. isRoot {
0 commit comments