418e2291a2
Certain operations in `engine/diff` mutate engine events during display. This mutation can occur concurrently with the serialization of the event for persistence, which causes a panic in the CLI. These changes fix the offending code and add code that copies each engine event before persisteing it in order to guard against future issues.
119 lines
3.1 KiB
Go
119 lines
3.1 KiB
Go
// Copyright 2016-2018, Pulumi Corporation.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package display
|
|
|
|
import (
|
|
"fmt"
|
|
"math"
|
|
"os"
|
|
"time"
|
|
|
|
"github.com/pulumi/pulumi/pkg/v2/engine"
|
|
"github.com/pulumi/pulumi/sdk/v2/go/common/diag"
|
|
"github.com/pulumi/pulumi/sdk/v2/go/common/util/cmdutil"
|
|
"github.com/pulumi/pulumi/sdk/v2/go/common/util/contract"
|
|
)
|
|
|
|
// ShowQueryEvents displays query events on the CLI.
|
|
func ShowQueryEvents(op string, events <-chan engine.Event,
|
|
done chan<- bool, opts Options) {
|
|
|
|
prefix := fmt.Sprintf("%s%s...", cmdutil.EmojiOr("✨ ", "@ "), op)
|
|
|
|
var spinner cmdutil.Spinner
|
|
var ticker *time.Ticker
|
|
|
|
if opts.IsInteractive {
|
|
spinner, ticker = cmdutil.NewSpinnerAndTicker(prefix, nil, 8 /*timesPerSecond*/)
|
|
} else {
|
|
spinner = &nopSpinner{}
|
|
ticker = time.NewTicker(math.MaxInt64)
|
|
}
|
|
|
|
defer func() {
|
|
spinner.Reset()
|
|
ticker.Stop()
|
|
close(done)
|
|
}()
|
|
|
|
for {
|
|
select {
|
|
case <-ticker.C:
|
|
spinner.Tick()
|
|
case event := <-events:
|
|
spinner.Reset()
|
|
|
|
out := os.Stdout
|
|
if event.Type == engine.DiagEvent {
|
|
payload := event.Payload().(engine.DiagEventPayload)
|
|
if payload.Severity == diag.Error || payload.Severity == diag.Warning {
|
|
out = os.Stderr
|
|
}
|
|
}
|
|
|
|
msg := renderQueryEvent(event, opts)
|
|
if msg != "" && out != nil {
|
|
fprintIgnoreError(out, msg)
|
|
}
|
|
|
|
if event.Type == engine.CancelEvent {
|
|
return
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func renderQueryEvent(event engine.Event, opts Options) string {
|
|
switch event.Type {
|
|
case engine.CancelEvent:
|
|
return ""
|
|
|
|
case engine.StdoutColorEvent:
|
|
return renderStdoutColorEvent(event.Payload().(engine.StdoutEventPayload), opts)
|
|
|
|
// Includes stdout of the query process.
|
|
case engine.DiagEvent:
|
|
return renderQueryDiagEvent(event.Payload().(engine.DiagEventPayload), opts)
|
|
|
|
case engine.PreludeEvent, engine.SummaryEvent, engine.ResourceOperationFailed,
|
|
engine.ResourceOutputsEvent, engine.ResourcePreEvent:
|
|
|
|
contract.Failf("query mode does not support resource operations")
|
|
return ""
|
|
|
|
default:
|
|
contract.Failf("unknown event type '%s'", event.Type)
|
|
return ""
|
|
}
|
|
}
|
|
|
|
func renderQueryDiagEvent(payload engine.DiagEventPayload, opts Options) string {
|
|
// Ignore debug messages unless we're in debug mode.
|
|
if payload.Severity == diag.Debug && !opts.Debug {
|
|
return ""
|
|
}
|
|
|
|
// Ignore error messages reported through diag events -- these are reported as errors later.
|
|
if payload.Severity == diag.Infoerr {
|
|
return ""
|
|
}
|
|
|
|
// For stdout messages, trim ONLY the last newline character.
|
|
if payload.Severity == diag.Info {
|
|
payload.Message = cmdutil.RemoveTrailingNewline(payload.Message)
|
|
}
|
|
|
|
return opts.Color.Colorize(payload.Prefix + payload.Message)
|
|
}
|