From 15b36c59749ec0061c6caa5f0cd665529b12f2f5 Mon Sep 17 00:00:00 2001 From: Evan Wallace Date: Thu, 4 Mar 2021 20:58:26 -0800 Subject: [PATCH] flush deferred warnings before writing to stdout --- internal/logger/logger.go | 59 +++++++++++++++++++++++++++------------ pkg/api/api_impl.go | 3 ++ 2 files changed, 44 insertions(+), 18 deletions(-) diff --git a/internal/logger/logger.go b/internal/logger/logger.go index 96b9e0f317b..ed5c8cad968 100644 --- a/internal/logger/logger.go +++ b/internal/logger/logger.go @@ -21,7 +21,13 @@ const defaultTerminalWidth = 80 type Log struct { AddMsg func(Msg) HasErrors func() bool - Done func() []Msg + + // This is called after the build has finished but before writing to stdout. + // It exists to ensure that deferred warning messages end up in the terminal + // before the data written to stdout. + AlmostDone func() + + Done func() []Msg } type LogLevel int8 @@ -351,6 +357,31 @@ func NewStderrLog(options OutputOptions) Log { remainingMessagesBeforeLimit = 0x7FFFFFFF } var deferredWarnings []Msg + didFinalizeLog := false + + finalizeLog := func() { + if didFinalizeLog { + return + } + didFinalizeLog = true + + // Print the deferred warning now if there was no error after all + for remainingMessagesBeforeLimit > 0 && len(deferredWarnings) > 0 { + shownWarnings++ + writeStringWithColor(os.Stderr, deferredWarnings[0].String(options, terminalInfo)) + deferredWarnings = deferredWarnings[1:] + remainingMessagesBeforeLimit-- + } + + // Print out a summary + if options.MessageLimit > 0 && errors+warnings > options.MessageLimit { + writeStringWithColor(os.Stderr, fmt.Sprintf("%s shown (disable the message limit with --error-limit=0)\n", + errorAndWarningSummary(errors, warnings, shownErrors, shownWarnings))) + } else if options.LogLevel <= LevelInfo && (warnings != 0 || errors != 0) { + writeStringWithColor(os.Stderr, fmt.Sprintf("%s\n", + errorAndWarningSummary(errors, warnings, shownErrors, shownWarnings))) + } + } switch options.Color { case ColorNever: @@ -411,27 +442,17 @@ func NewStderrLog(options OutputOptions) Log { defer mutex.Unlock() return hasErrors }, - Done: func() []Msg { + AlmostDone: func() { mutex.Lock() defer mutex.Unlock() - // Print the deferred warning now if there was no error after all - for remainingMessagesBeforeLimit > 0 && len(deferredWarnings) > 0 { - shownWarnings++ - writeStringWithColor(os.Stderr, deferredWarnings[0].String(options, terminalInfo)) - deferredWarnings = deferredWarnings[1:] - remainingMessagesBeforeLimit-- - } - - // Print out a summary - if options.MessageLimit > 0 && errors+warnings > options.MessageLimit { - writeStringWithColor(os.Stderr, fmt.Sprintf("%s shown (disable the message limit with --error-limit=0)\n", - errorAndWarningSummary(errors, warnings, shownErrors, shownWarnings))) - } else if options.LogLevel <= LevelInfo && (warnings != 0 || errors != 0) { - writeStringWithColor(os.Stderr, fmt.Sprintf("%s\n", - errorAndWarningSummary(errors, warnings, shownErrors, shownWarnings))) - } + finalizeLog() + }, + Done: func() []Msg { + mutex.Lock() + defer mutex.Unlock() + finalizeLog() sort.Stable(msgs) return msgs }, @@ -759,6 +780,8 @@ func NewDeferLog() Log { defer mutex.Unlock() return hasErrors }, + AlmostDone: func() { + }, Done: func() []Msg { mutex.Lock() defer mutex.Unlock() diff --git a/pkg/api/api_impl.go b/pkg/api/api_impl.go index bf6a631d640..ef17a3ed567 100644 --- a/pkg/api/api_impl.go +++ b/pkg/api/api_impl.go @@ -774,6 +774,9 @@ func rebuildImpl( // Stop now if there were errors if !log.HasErrors() { + // Flush any deferred warnings now + log.AlmostDone() + if buildOpts.Write { // Special-case writing to stdout if options.WriteToStdout {