@@ -237,6 +237,16 @@ public actor SwiftPMBuildSystem {
237
237
}
238
238
239
239
extension SwiftPMBuildSystem {
240
+ public func generateBuildGraph( ) async throws {
241
+ let observabilitySystem = ObservabilitySystem ( { scope, diagnostic in
242
+ logger. log ( level: diagnostic. severity. asLogLevel, " SwiftPM log: \( diagnostic. description) " )
243
+ } )
244
+ try self . workspace. resolve (
245
+ root: PackageGraphRootInput ( packages: [ AbsolutePath ( projectRoot) ] ) ,
246
+ observabilityScope: observabilitySystem. topScope
247
+ )
248
+ try await self . reloadPackage ( )
249
+ }
240
250
241
251
/// (Re-)load the package settings by parsing the manifest and resolving all the targets and
242
252
/// dependencies.
@@ -368,7 +378,8 @@ extension SwiftPMBuildSystem: SKCore.BuildSystem {
368
378
}
369
379
370
380
public func defaultLanguage( for document: DocumentURI ) async -> Language ? {
371
- // TODO (indexing): Query The SwiftPM build system for the document's language
381
+ // TODO (indexing): Query The SwiftPM build system for the document's language.
382
+ // https://github.com/apple/sourcekit-lsp/issues/1267
372
383
return nil
373
384
}
374
385
@@ -395,6 +406,77 @@ extension SwiftPMBuildSystem: SKCore.BuildSystem {
395
406
return [ ]
396
407
}
397
408
409
+ public func topologicalSort( of targets: [ ConfiguredTarget ] ) -> [ ConfiguredTarget ] ? {
410
+ return targets. sorted { ( lhs: ConfiguredTarget , rhs: ConfiguredTarget ) -> Bool in
411
+ let lhsIndex = self . targets. firstIndex ( where: { $0. name == lhs. targetID } ) ?? self . targets. count
412
+ let rhsIndex = self . targets. firstIndex ( where: { $0. name == rhs. targetID } ) ?? self . targets. count
413
+ return lhsIndex < rhsIndex
414
+ }
415
+ }
416
+
417
+ public func prepare( targets: [ ConfiguredTarget ] ) async throws {
418
+ // TODO (indexing): Support preparation of multiple targets at once.
419
+ // https://github.com/apple/sourcekit-lsp/issues/1262
420
+ for target in targets {
421
+ try await prepare ( singleTarget: target)
422
+ }
423
+ }
424
+
425
+ private func prepare( singleTarget target: ConfiguredTarget ) async throws {
426
+ // TODO (indexing): Add a proper 'prepare' job in SwiftPM instead of building the target.
427
+ // https://github.com/apple/sourcekit-lsp/issues/1254
428
+ guard let toolchain = await toolchainRegistry. default else {
429
+ logger. error ( " Not preparing because not toolchain exists " )
430
+ return
431
+ }
432
+ guard let swift = toolchain. swift else {
433
+ logger. error (
434
+ " Not preparing because toolchain at \( toolchain. identifier) does not contain a Swift compiler "
435
+ )
436
+ return
437
+ }
438
+ let arguments = [
439
+ swift. pathString, " build " ,
440
+ " --scratch-path " , self . workspace. location. scratchDirectory. pathString,
441
+ " --disable-index-store " ,
442
+ " --target " , target. targetID,
443
+ ]
444
+ let process = Process (
445
+ arguments: arguments,
446
+ workingDirectory: try TSCBasic . AbsolutePath ( validating: workspacePath. pathString)
447
+ )
448
+ try process. launch ( )
449
+ let result = try await process. waitUntilExitSendingSigIntOnTaskCancellation ( )
450
+ switch result. exitStatus. exhaustivelySwitchable {
451
+ case . terminated( code: 0 ) :
452
+ break
453
+ case . terminated( code: let code) :
454
+ // This most likely happens if there are compilation errors in the source file. This is nothing to worry about.
455
+ let stdout = ( try ? String ( bytes: result. output. get ( ) , encoding: . utf8) ) ?? " <no stderr> "
456
+ let stderr = ( try ? String ( bytes: result. stderrOutput. get ( ) , encoding: . utf8) ) ?? " <no stderr> "
457
+ logger. debug (
458
+ """
459
+ Preparation of targets \( target. targetID) terminated with non-zero exit code \( code)
460
+ Stderr:
461
+ \( stderr)
462
+ Stdout:
463
+ \( stdout)
464
+ """
465
+ )
466
+ case . signalled( signal: let signal) :
467
+ if !Task. isCancelled {
468
+ // The indexing job finished with a signal. Could be because the compiler crashed.
469
+ // Ignore signal exit codes if this task has been cancelled because the compiler exits with SIGINT if it gets
470
+ // interrupted.
471
+ logger. error ( " Preparation of targets \( target. targetID) signaled \( signal) " )
472
+ }
473
+ case . abnormal( exception: let exception) :
474
+ if !Task. isCancelled {
475
+ logger. error ( " Preparation of targets \( target. targetID) exited abnormally \( exception) " )
476
+ }
477
+ }
478
+ }
479
+
398
480
public func registerForChangeNotifications( for uri: DocumentURI ) async {
399
481
self . watchedFiles. insert ( uri)
400
482
}
@@ -489,14 +571,11 @@ extension SwiftPMBuildSystem: SKCore.BuildSystem {
489
571
490
572
public func sourceFiles( ) -> [ SourceFileInfo ] {
491
573
return fileToTarget. compactMap { ( path, target) -> SourceFileInfo ? in
492
- guard target. isPartOfRootPackage else {
493
- // Don't consider files from package dependencies as possible test files.
494
- return nil
495
- }
496
574
// We should only set mayContainTests to `true` for files from test targets
497
575
// (https://github.com/apple/sourcekit-lsp/issues/1174).
498
576
return SourceFileInfo (
499
577
uri: DocumentURI ( path. asURL) ,
578
+ isPartOfRootProject: target. isPartOfRootPackage,
500
579
mayContainTests: true
501
580
)
502
581
}
0 commit comments