@@ -198,6 +198,8 @@ public final class BuildDelegate: BuildSystemDelegate, SwiftCompilerOutputParser
198198
199199 /// Swift parsers keyed by llbuild command name.
200200 private var swiftParsers : [ String : SwiftCompilerOutputParser ] = [ : ]
201+ /// Target name keyed by llbuild command name.
202+ private let targetNames : [ String : String ]
201203
202204 public init (
203205 plan: BuildPlan ,
@@ -212,9 +214,15 @@ public final class BuildDelegate: BuildSystemDelegate, SwiftCompilerOutputParser
212214 self . progressAnimation = progressAnimation
213215
214216 let buildConfig = plan. buildParameters. configuration. dirname
217+
218+ targetNames = Dictionary ( uniqueKeysWithValues: plan. targetMap. map ( { ( target, description) in
219+ return ( target. getCommandName ( config: buildConfig) , target. name)
220+ } ) )
221+
215222 swiftParsers = Dictionary ( uniqueKeysWithValues: plan. targetMap. compactMap ( { ( target, description) in
216223 guard case . swift = description else { return nil }
217- return ( target. getCommandName ( config: buildConfig) , SwiftCompilerOutputParser ( delegate: self ) )
224+ let parser = SwiftCompilerOutputParser ( targetName: target. name, delegate: self )
225+ return ( target. getCommandName ( config: buildConfig) , parser)
218226 } ) )
219227 }
220228
@@ -235,6 +243,14 @@ public final class BuildDelegate: BuildSystemDelegate, SwiftCompilerOutputParser
235243 }
236244
237245 public func commandStatusChanged( _ command: SPMLLBuild . Command , kind: CommandStatusKind ) {
246+ guard !isVerbose else { return }
247+ guard command. shouldShowStatus else { return }
248+ guard !swiftParsers. keys. contains ( command. name) else { return }
249+
250+ queue. async {
251+ self . taskTracker. commandStatusChanged ( command, kind: kind)
252+ self . updateProgress ( )
253+ }
238254 }
239255
240256 public func commandPreparing( _ command: SPMLLBuild . Command ) {
@@ -243,13 +259,10 @@ public final class BuildDelegate: BuildSystemDelegate, SwiftCompilerOutputParser
243259 public func commandStarted( _ command: SPMLLBuild . Command ) {
244260 guard command. shouldShowStatus else { return }
245261
246- queue. sync {
247- if isVerbose {
248- outputStream <<< command. verboseDescription <<< " \n "
249- outputStream. flush ( )
250- } else if !swiftParsers. keys. contains ( command. name) {
251- taskTracker. commandStarted ( command)
252- updateProgress ( )
262+ queue. async {
263+ if self . isVerbose {
264+ self . outputStream <<< command. verboseDescription <<< " \n "
265+ self . outputStream. flush ( )
253266 }
254267 }
255268 }
@@ -259,13 +272,14 @@ public final class BuildDelegate: BuildSystemDelegate, SwiftCompilerOutputParser
259272 }
260273
261274 public func commandFinished( _ command: SPMLLBuild . Command , result: CommandResult ) {
275+ guard !isVerbose else { return }
262276 guard command. shouldShowStatus else { return }
263277 guard !swiftParsers. keys. contains ( command. name) else { return }
264- guard !isVerbose else { return }
265278
266- queue. sync {
267- taskTracker. commandFinished ( command, result: result)
268- updateProgress ( )
279+ queue. async {
280+ let targetName = self . targetNames [ command. name]
281+ self . taskTracker. commandFinished ( command, result: result, targetName: targetName)
282+ self . updateProgress ( )
269283 }
270284 }
271285
@@ -306,9 +320,11 @@ public final class BuildDelegate: BuildSystemDelegate, SwiftCompilerOutputParser
306320 if let swiftParser = swiftParsers [ command. name] {
307321 swiftParser. parse ( bytes: data)
308322 } else {
309- progressAnimation. clear ( )
310- outputStream <<< data
311- outputStream. flush ( )
323+ queue. async {
324+ self . progressAnimation. clear ( )
325+ self . outputStream <<< data
326+ self . outputStream. flush ( )
327+ }
312328 }
313329 }
314330
@@ -327,37 +343,37 @@ public final class BuildDelegate: BuildSystemDelegate, SwiftCompilerOutputParser
327343 return false
328344 }
329345
330- func swiftCompilerDidOutputMessage ( _ message: SwiftCompilerMessage ) {
331- queue. sync {
332- if isVerbose {
346+ func swiftCompilerOutputParser ( _ parser : SwiftCompilerOutputParser , didParse message: SwiftCompilerMessage ) {
347+ queue. async {
348+ if self . isVerbose {
333349 if let text = message. verboseProgressText {
334- outputStream <<< text <<< " \n "
335- outputStream. flush ( )
350+ self . outputStream <<< text <<< " \n "
351+ self . outputStream. flush ( )
336352 }
337353 } else {
338- taskTracker. swiftCompilerDidOuputMessage ( message)
339- updateProgress ( )
354+ self . taskTracker. swiftCompilerDidOuputMessage ( message, targetName : parser . targetName )
355+ self . updateProgress ( )
340356 }
341357
342358 if let output = message. standardOutput {
343- if !isVerbose {
344- progressAnimation. clear ( )
359+ if !self . isVerbose {
360+ self . progressAnimation. clear ( )
345361 }
346362
347- outputStream <<< output
348- outputStream. flush ( )
363+ self . outputStream <<< output
364+ self . outputStream. flush ( )
349365 }
350366 }
351367 }
352368
353- func swiftCompilerOutputParserDidFail ( withError error: Error ) {
369+ func swiftCompilerOutputParser ( _ parser : SwiftCompilerOutputParser , didFailWith error: Error ) {
354370 let message = ( error as? LocalizedError ) ? . errorDescription ?? error. localizedDescription
355371 diagnostics. emit ( data: SwiftCompilerOutputParsingError ( message: message) )
356372 onCommmandFailure ? ( )
357373 }
358374
359375 private func updateProgress( ) {
360- if let progressText = taskTracker. latestRunningText {
376+ if let progressText = taskTracker. latestFinishedText {
361377 progressAnimation. update (
362378 step: taskTracker. finishedCount,
363379 total: taskTracker. totalCount,
@@ -368,103 +384,101 @@ public final class BuildDelegate: BuildSystemDelegate, SwiftCompilerOutputParser
368384
369385/// Tracks tasks based on command status and swift compiler output.
370386fileprivate struct CommandTaskTracker {
371- private struct Task {
372- let identifier : String
373- let text : String
374- }
375-
376- private var tasks : [ Task ] = [ ]
377- private( set) var finishedCount = 0
378387 private( set) var totalCount = 0
388+ private( set) var finishedCount = 0
389+ private var swiftTaskProgressTexts : [ Int : String ] = [ : ]
379390
380391 /// The last task text before the task list was emptied.
381- private var lastText : String ?
382-
383- var latestRunningText : String ? {
384- return tasks. last? . text ?? lastText
385- }
386-
387- mutating func commandStarted( _ command: SPMLLBuild . Command ) {
388- addTask ( identifier: command. name, text: command. description)
389- totalCount += 1
392+ private( set) var latestFinishedText : String ?
393+
394+ mutating func commandStatusChanged( _ command: SPMLLBuild . Command , kind: CommandStatusKind ) {
395+ switch kind {
396+ case . isScanning:
397+ totalCount += 1
398+ break
399+ case . isUpToDate:
400+ totalCount -= 1
401+ break
402+ case . isComplete:
403+ break
404+ }
390405 }
391406
392- mutating func commandFinished( _ command: SPMLLBuild . Command , result: CommandResult ) {
393- removeTask ( identifier : command. name )
407+ mutating func commandFinished( _ command: SPMLLBuild . Command , result: CommandResult , targetName : String ? ) {
408+ latestFinishedText = progressText ( of : command, targetName : targetName )
394409
395410 switch result {
396- case . succeeded:
411+ case . succeeded, . skipped :
397412 finishedCount += 1
398- case . cancelled, . failed, . skipped :
413+ case . cancelled, . failed:
399414 break
400415 }
401416 }
402417
403- mutating func swiftCompilerDidOuputMessage( _ message: SwiftCompilerMessage ) {
418+ mutating func swiftCompilerDidOuputMessage( _ message: SwiftCompilerMessage , targetName : String ) {
404419 switch message. kind {
405420 case . began( let info) :
406- if let text = message . progressText {
407- addTask ( identifier : info. pid. description , text : text)
421+ if let text = progressText ( of : message , targetName : targetName ) {
422+ swiftTaskProgressTexts [ info. pid] = text
408423 }
409424
410425 totalCount += 1
411426 case . finished( let info) :
412- removeTask ( identifier: info. pid. description)
427+ if let progressText = swiftTaskProgressTexts [ info. pid] {
428+ latestFinishedText = progressText
429+ swiftTaskProgressTexts [ info. pid] = nil
430+ }
431+
413432 finishedCount += 1
414- case . signalled( let info) :
415- removeTask ( identifier: info. pid. description)
416- case . skipped:
433+ case . signalled, . skipped:
417434 break
418435 }
419436 }
420-
421- private mutating func addTask( identifier: String , text: String ) {
422- tasks. append ( Task ( identifier: identifier, text: text) )
423- }
424-
425- private mutating func removeTask( identifier: String ) {
426- if let index = tasks. index ( where: { $0. identifier == identifier } ) {
427- if tasks. count == 1 {
428- lastText = tasks [ 0 ] . text
429- }
430437
431- tasks. remove ( at: index)
438+ private func progressText( of command: SPMLLBuild . Command , targetName: String ? ) -> String {
439+ // Transforms descriptions like "Linking ./.build/x86_64-apple-macosx/debug/foo" into "Linking foo".
440+ if let firstSpaceIndex = command. description. firstIndex ( of: " " ) ,
441+ let lastDirectorySeperatorIndex = command. description. lastIndex ( of: " / " )
442+ {
443+ let action = command. description [ ..< firstSpaceIndex]
444+ let fileNameStartIndex = command. description. index ( after: lastDirectorySeperatorIndex)
445+ let fileName = command. description [ fileNameStartIndex... ]
446+
447+ if let targetName = targetName {
448+ return " \( action) \( targetName) \( fileName) "
449+ } else {
450+ return " \( action) \( fileName) "
451+ }
452+ } else {
453+ return command. description
432454 }
433455 }
434- }
435456
436- extension SwiftCompilerMessage {
437- fileprivate var progressText : String ? {
438- if case . began( let info) = kind {
439- switch name {
457+ private func progressText( of message: SwiftCompilerMessage , targetName: String ) -> String ? {
458+ if case . began( let info) = message. kind {
459+ switch message. name {
440460 case " compile " :
441461 if let sourceFile = info. inputs. first {
442- return generateProgressText ( prefix : " Compiling " , file : sourceFile)
462+ return " Compiling \( targetName ) \( AbsolutePath ( sourceFile) . components . last! ) "
443463 }
444464 case " link " :
445- if let imageFile = info. outputs. first ( where: { $0. type == " image " } ) ? . path {
446- return generateProgressText ( prefix: " Linking " , file: imageFile)
447- }
465+ return " Linking \( targetName) "
448466 case " merge-module " :
449- if let moduleFile = info. outputs. first ( where: { $0. type == " swiftmodule " } ) ? . path {
450- return generateProgressText ( prefix: " Merging module " , file: moduleFile)
451- }
467+ return " Merging module \( targetName) "
452468 case " generate-dsym " :
453- if let dSYMFile = info. outputs. first ( where: { $0. type == " dSYM " } ) ? . path {
454- return generateProgressText ( prefix: " Generating dSYM " , file: dSYMFile)
455- }
469+ return " Generating \( targetName) dSYM "
456470 case " generate-pch " :
457- if let pchFile = info. outputs. first ( where: { $0. type == " pch " } ) ? . path {
458- return generateProgressText ( prefix: " Generating PCH " , file: pchFile)
459- }
471+ return " Generating \( targetName) PCH "
460472 default :
461473 break
462474 }
463475 }
464476
465477 return nil
466478 }
479+ }
467480
481+ extension SwiftCompilerMessage {
468482 fileprivate var verboseProgressText : String ? {
469483 if case . began( let info) = kind {
470484 return ( [ info. commandExecutable] + info. commandArguments) . joined ( separator: " " )
@@ -482,10 +496,4 @@ extension SwiftCompilerMessage {
482496 return nil
483497 }
484498 }
485-
486- private func generateProgressText( prefix: String , file: String ) -> String {
487- // FIXME: Eliminate cwd from here.
488- let relativePath = AbsolutePath ( file) . relative ( to: localFileSystem. currentWorkingDirectory!)
489- return " \( prefix) \( relativePath) "
490- }
491499}
0 commit comments