@@ -355,12 +355,15 @@ final class CopyCommand: CustomLLBuildCommand {
355
355
}
356
356
}
357
357
358
- public final class BuildDelegate : BuildSystemDelegate , SwiftCompilerOutputParserDelegate {
358
+ /// Convenient llbuild build system delegate implementation
359
+ final class BuildOperationBuildSystemDelegateHandler : llbuildSwift . BuildSystemDelegate , SwiftCompilerOutputParserDelegate {
359
360
private let diagnostics : DiagnosticsEngine
360
- public var outputStream : ThreadSafeOutputByteStream
361
- public var progressAnimation : ProgressAnimationProtocol
362
- public var onCommmandFailure : ( ( ) -> Void ) ?
363
- public var isVerbose : Bool = false
361
+ var outputStream : ThreadSafeOutputByteStream
362
+ var progressAnimation : ProgressAnimationProtocol
363
+ var onCommmandFailure : ( ( ) -> Void ) ?
364
+ var isVerbose : Bool = false
365
+ weak var delegate : SPMBuildCore . BuildSystemDelegate ?
366
+ private let buildSystem : SPMBuildCore . BuildSystem
364
367
private let queue = DispatchQueue ( label: " org.swift.swiftpm.build-delegate " )
365
368
private var taskTracker = CommandTaskTracker ( )
366
369
private var errorMessagesByTarget : [ String : [ String ] ] = [ : ]
@@ -371,30 +374,42 @@ public final class BuildDelegate: BuildSystemDelegate, SwiftCompilerOutputParser
371
374
/// The build execution context.
372
375
private let buildExecutionContext : BuildExecutionContext
373
376
374
- public init (
377
+ init (
378
+ buildSystem: SPMBuildCore . BuildSystem ,
375
379
bctx: BuildExecutionContext ,
376
380
diagnostics: DiagnosticsEngine ,
377
381
outputStream: OutputByteStream ,
378
- progressAnimation: ProgressAnimationProtocol
382
+ progressAnimation: ProgressAnimationProtocol ,
383
+ delegate: SPMBuildCore . BuildSystemDelegate ?
379
384
) {
380
385
self . diagnostics = diagnostics
381
386
// FIXME: Implement a class convenience initializer that does this once they are supported
382
387
// https://forums.swift.org/t/allow-self-x-in-class-convenience-initializers/15924
383
388
self . outputStream = outputStream as? ThreadSafeOutputByteStream ?? ThreadSafeOutputByteStream ( outputStream)
384
389
self . progressAnimation = progressAnimation
385
390
self . buildExecutionContext = bctx
391
+ self . delegate = delegate
392
+ self . buildSystem = buildSystem
386
393
387
394
let swiftParsers = bctx. buildDescription? . swiftCommands. mapValues { tool in
388
395
SwiftCompilerOutputParser ( targetName: tool. moduleName, delegate: self )
389
396
} ?? [ : ]
390
397
self . swiftParsers = swiftParsers
398
+
399
+ self . taskTracker. onTaskProgressUpdateText = { progressText, _ in
400
+ self . queue. async {
401
+ self . delegate? . buildSystem ( self . buildSystem, didUpdateTaskProgress: progressText)
402
+ }
403
+ }
391
404
}
392
405
393
- public var fs : SPMLLBuild . FileSystem ? {
406
+ // MARK: llbuildSwift.BuildSystemDelegate
407
+
408
+ var fs : SPMLLBuild . FileSystem ? {
394
409
return nil
395
410
}
396
411
397
- public func lookupTool( _ name: String ) -> Tool ? {
412
+ func lookupTool( _ name: String ) -> Tool ? {
398
413
switch name {
399
414
case TestDiscoveryTool . name:
400
415
return InProcessTool ( buildExecutionContext, type: TestDiscoveryCommand . self)
@@ -407,11 +422,11 @@ public final class BuildDelegate: BuildSystemDelegate, SwiftCompilerOutputParser
407
422
}
408
423
}
409
424
410
- public func hadCommandFailure( ) {
425
+ func hadCommandFailure( ) {
411
426
onCommmandFailure ? ( )
412
427
}
413
428
414
- public func handleDiagnostic( _ diagnostic: SPMLLBuild . Diagnostic ) {
429
+ func handleDiagnostic( _ diagnostic: SPMLLBuild . Diagnostic ) {
415
430
switch diagnostic. kind {
416
431
case . note:
417
432
diagnostics. emit ( note: diagnostic. message)
@@ -424,7 +439,7 @@ public final class BuildDelegate: BuildSystemDelegate, SwiftCompilerOutputParser
424
439
}
425
440
}
426
441
427
- public func commandStatusChanged( _ command: SPMLLBuild . Command , kind: CommandStatusKind ) {
442
+ func commandStatusChanged( _ command: SPMLLBuild . Command , kind: CommandStatusKind ) {
428
443
guard !isVerbose else { return }
429
444
guard command. shouldShowStatus else { return }
430
445
guard !swiftParsers. keys. contains ( command. name) else { return }
@@ -435,69 +450,75 @@ public final class BuildDelegate: BuildSystemDelegate, SwiftCompilerOutputParser
435
450
}
436
451
}
437
452
438
- public func commandPreparing( _ command: SPMLLBuild . Command ) {
453
+ func commandPreparing( _ command: SPMLLBuild . Command ) {
454
+ queue. async {
455
+ self . delegate? . buildSystem ( self . buildSystem, willStartCommand: BuildSystemCommand ( command) )
456
+ }
439
457
}
440
458
441
- public func commandStarted( _ command: SPMLLBuild . Command ) {
459
+ func commandStarted( _ command: SPMLLBuild . Command ) {
442
460
guard command. shouldShowStatus else { return }
443
461
444
462
queue. async {
463
+ self . delegate? . buildSystem ( self . buildSystem, didStartCommand: BuildSystemCommand ( command) )
445
464
if self . isVerbose {
446
465
self . outputStream <<< command. verboseDescription <<< " \n "
447
466
self . outputStream. flush ( )
448
467
}
449
468
}
450
469
}
451
470
452
- public func shouldCommandStart( _ command: SPMLLBuild . Command ) -> Bool {
471
+ func shouldCommandStart( _ command: SPMLLBuild . Command ) -> Bool {
453
472
return true
454
473
}
455
474
456
- public func commandFinished( _ command: SPMLLBuild . Command , result: CommandResult ) {
457
- guard !isVerbose else { return }
475
+ func commandFinished( _ command: SPMLLBuild . Command , result: CommandResult ) {
458
476
guard command. shouldShowStatus else { return }
459
477
guard !swiftParsers. keys. contains ( command. name) else { return }
460
478
461
479
queue. async {
462
- let targetName = self . swiftParsers [ command. name] ? . targetName
463
- self . taskTracker. commandFinished ( command, result: result, targetName: targetName)
464
- self . updateProgress ( )
480
+ self . delegate? . buildSystem ( self . buildSystem, didFinishCommand: BuildSystemCommand ( command) )
481
+
482
+ if !self . isVerbose {
483
+ let targetName = self . swiftParsers [ command. name] ? . targetName
484
+ self . taskTracker. commandFinished ( command, result: result, targetName: targetName)
485
+ self . updateProgress ( )
486
+ }
465
487
}
466
488
}
467
489
468
- public func commandHadError( _ command: SPMLLBuild . Command , message: String ) {
490
+ func commandHadError( _ command: SPMLLBuild . Command , message: String ) {
469
491
diagnostics. emit ( error: message)
470
492
}
471
493
472
- public func commandHadNote( _ command: SPMLLBuild . Command , message: String ) {
473
- // FIXME: This is wrong.
474
- diagnostics. emit ( warning: message)
494
+ func commandHadNote( _ command: SPMLLBuild . Command , message: String ) {
495
+ diagnostics. emit ( note: message)
475
496
}
476
497
477
- public func commandHadWarning( _ command: SPMLLBuild . Command , message: String ) {
498
+ func commandHadWarning( _ command: SPMLLBuild . Command , message: String ) {
478
499
diagnostics. emit ( warning: message)
479
500
}
480
501
481
- public func commandCannotBuildOutputDueToMissingInputs(
502
+ func commandCannotBuildOutputDueToMissingInputs(
482
503
_ command: SPMLLBuild . Command ,
483
504
output: BuildKey ,
484
505
inputs: [ BuildKey ]
485
506
) {
486
507
diagnostics. emit ( . missingInputs( output: output, inputs: inputs) )
487
508
}
488
509
489
- public func cannotBuildNodeDueToMultipleProducers( output: BuildKey , commands: [ SPMLLBuild . Command ] ) {
510
+ func cannotBuildNodeDueToMultipleProducers( output: BuildKey , commands: [ SPMLLBuild . Command ] ) {
490
511
diagnostics. emit ( . multipleProducers( output: output, commands: commands) )
491
512
}
492
513
493
- public func commandProcessStarted( _ command: SPMLLBuild . Command , process: ProcessHandle ) {
514
+ func commandProcessStarted( _ command: SPMLLBuild . Command , process: ProcessHandle ) {
494
515
}
495
516
496
- public func commandProcessHadError( _ command: SPMLLBuild . Command , process: ProcessHandle , message: String ) {
517
+ func commandProcessHadError( _ command: SPMLLBuild . Command , process: ProcessHandle , message: String ) {
497
518
diagnostics. emit ( . commandError( command: command, message: message) )
498
519
}
499
520
500
- public func commandProcessHadOutput( _ command: SPMLLBuild . Command , process: ProcessHandle , data: [ UInt8 ] ) {
521
+ func commandProcessHadOutput( _ command: SPMLLBuild . Command , process: ProcessHandle , data: [ UInt8 ] ) {
501
522
guard command. shouldShowStatus else { return }
502
523
503
524
if let swiftParser = swiftParsers [ command. name] {
@@ -511,7 +532,7 @@ public final class BuildDelegate: BuildSystemDelegate, SwiftCompilerOutputParser
511
532
}
512
533
}
513
534
514
- public func commandProcessFinished(
535
+ func commandProcessFinished(
515
536
_ command: SPMLLBuild . Command ,
516
537
process: ProcessHandle ,
517
538
result: CommandExtendedResult
@@ -532,15 +553,21 @@ public final class BuildDelegate: BuildSystemDelegate, SwiftCompilerOutputParser
532
553
}
533
554
}
534
555
535
- public func cycleDetected( rules: [ BuildKey ] ) {
556
+ func cycleDetected( rules: [ BuildKey ] ) {
536
557
diagnostics. emit ( . cycleError( rules: rules) )
558
+
559
+ queue. async {
560
+ self . delegate? . buildSystemDidDetectCycleInRules ( self . buildSystem)
561
+ }
537
562
}
538
563
539
- public func shouldResolveCycle( rules: [ BuildKey ] , candidate: BuildKey , action: CycleAction ) -> Bool {
564
+ func shouldResolveCycle( rules: [ BuildKey ] , candidate: BuildKey , action: CycleAction ) -> Bool {
540
565
return false
541
566
}
542
567
543
- public func swiftCompilerOutputParser( _ parser: SwiftCompilerOutputParser , didParse message: SwiftCompilerMessage ) {
568
+ // MARK: SwiftCompilerOutputParserDelegate
569
+
570
+ func swiftCompilerOutputParser( _ parser: SwiftCompilerOutputParser , didParse message: SwiftCompilerMessage ) {
544
571
queue. async {
545
572
if self . isVerbose {
546
573
if let text = message. verboseProgressText {
@@ -569,12 +596,14 @@ public final class BuildDelegate: BuildSystemDelegate, SwiftCompilerOutputParser
569
596
}
570
597
}
571
598
572
- public func swiftCompilerOutputParser( _ parser: SwiftCompilerOutputParser , didFailWith error: Error ) {
599
+ func swiftCompilerOutputParser( _ parser: SwiftCompilerOutputParser , didFailWith error: Error ) {
573
600
let message = ( error as? LocalizedError ) ? . errorDescription ?? error. localizedDescription
574
601
diagnostics. emit ( . swiftCompilerOutputParsingError( message) )
575
602
onCommmandFailure ? ( )
576
603
}
577
604
605
+ // MARK: Private
606
+
578
607
private func updateProgress( ) {
579
608
if let progressText = taskTracker. latestFinishedText {
580
609
progressAnimation. update (
@@ -594,14 +623,14 @@ fileprivate struct CommandTaskTracker {
594
623
/// The last task text before the task list was emptied.
595
624
private( set) var latestFinishedText : String ?
596
625
626
+ var onTaskProgressUpdateText : ( ( _ text: String , _ targetName: String ? ) -> Void ) ?
627
+
597
628
mutating func commandStatusChanged( _ command: SPMLLBuild . Command , kind: CommandStatusKind ) {
598
629
switch kind {
599
630
case . isScanning:
600
631
totalCount += 1
601
- break
602
632
case . isUpToDate:
603
633
totalCount -= 1
604
- break
605
634
case . isComplete:
606
635
if ( totalCount == finishedCount) {
607
636
let latestOutput : String ? = latestFinishedText
@@ -610,15 +639,17 @@ fileprivate struct CommandTaskTracker {
610
639
* Build Completed!
611
640
"""
612
641
}
613
- break
614
642
@unknown default :
615
643
assertionFailure ( " unhandled command status kind \( kind) for command \( command) " )
616
644
break
617
645
}
618
646
}
619
647
620
648
mutating func commandFinished( _ command: SPMLLBuild . Command , result: CommandResult , targetName: String ? ) {
621
- latestFinishedText = progressText ( of: command, targetName: targetName)
649
+ let progressTextValue = progressText ( of: command, targetName: targetName)
650
+ onTaskProgressUpdateText ? ( progressTextValue, targetName)
651
+
652
+ latestFinishedText = progressTextValue
622
653
623
654
switch result {
624
655
case . succeeded, . skipped:
@@ -635,6 +666,7 @@ fileprivate struct CommandTaskTracker {
635
666
case . began( let info) :
636
667
if let text = progressText ( of: message, targetName: targetName) {
637
668
swiftTaskProgressTexts [ info. pid] = text
669
+ onTaskProgressUpdateText ? ( text, targetName)
638
670
}
639
671
640
672
totalCount += 1
@@ -739,3 +771,13 @@ private extension Diagnostic.Message {
739
771
. error( " failed parsing the Swift compiler output: \( error) " )
740
772
}
741
773
}
774
+
775
+ private extension BuildSystemCommand {
776
+ init ( _ command: SPMLLBuild . Command ) {
777
+ self . init (
778
+ name: command. name,
779
+ description: command. description,
780
+ verboseDescription: command. verboseDescription
781
+ )
782
+ }
783
+ }
0 commit comments