github.com/myhau/pulumi/pkg/v3@v3.70.2-0.20221116134521-f2775972e587/backend/display/query.go (about) 1 // Copyright 2016-2018, Pulumi Corporation. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package display 16 17 import ( 18 "fmt" 19 "math" 20 "os" 21 "time" 22 23 "github.com/pulumi/pulumi/pkg/v3/engine" 24 "github.com/pulumi/pulumi/sdk/v3/go/common/diag" 25 "github.com/pulumi/pulumi/sdk/v3/go/common/util/cmdutil" 26 "github.com/pulumi/pulumi/sdk/v3/go/common/util/contract" 27 ) 28 29 // ShowQueryEvents displays query events on the CLI. 30 func ShowQueryEvents(op string, events <-chan engine.Event, 31 done chan<- bool, opts Options) { 32 33 prefix := fmt.Sprintf("%s%s...", cmdutil.EmojiOr("✨ ", "@ "), op) 34 35 var spinner cmdutil.Spinner 36 var ticker *time.Ticker 37 38 if opts.IsInteractive { 39 spinner, ticker = cmdutil.NewSpinnerAndTicker(prefix, nil, opts.Color, 8 /*timesPerSecond*/) 40 } else { 41 spinner = &nopSpinner{} 42 ticker = time.NewTicker(math.MaxInt64) 43 } 44 45 defer func() { 46 spinner.Reset() 47 ticker.Stop() 48 close(done) 49 }() 50 51 for { 52 select { 53 case <-ticker.C: 54 spinner.Tick() 55 case event := <-events: 56 spinner.Reset() 57 58 out := os.Stdout 59 if event.Type == engine.DiagEvent { 60 payload := event.Payload().(engine.DiagEventPayload) 61 if payload.Severity == diag.Error || payload.Severity == diag.Warning { 62 out = os.Stderr 63 } 64 } 65 66 msg := renderQueryEvent(event, opts) 67 if msg != "" && out != nil { 68 fprintIgnoreError(out, msg) 69 } 70 71 if event.Type == engine.CancelEvent { 72 return 73 } 74 } 75 } 76 } 77 78 func renderQueryEvent(event engine.Event, opts Options) string { 79 switch event.Type { 80 case engine.CancelEvent: 81 return "" 82 83 case engine.StdoutColorEvent: 84 return renderStdoutColorEvent(event.Payload().(engine.StdoutEventPayload), opts) 85 86 // Includes stdout of the query process. 87 case engine.DiagEvent: 88 return renderQueryDiagEvent(event.Payload().(engine.DiagEventPayload), opts) 89 90 case engine.PreludeEvent, engine.SummaryEvent, engine.ResourceOperationFailed, 91 engine.ResourceOutputsEvent, engine.ResourcePreEvent: 92 93 contract.Failf("query mode does not support resource operations") 94 return "" 95 96 default: 97 contract.Failf("unknown event type '%s'", event.Type) 98 return "" 99 } 100 } 101 102 func renderQueryDiagEvent(payload engine.DiagEventPayload, opts Options) string { 103 // Ignore debug messages unless we're in debug mode. 104 if payload.Severity == diag.Debug && !opts.Debug { 105 return "" 106 } 107 108 // Ignore error messages reported through diag events -- these are reported as errors later. 109 if payload.Severity == diag.Infoerr { 110 return "" 111 } 112 113 // For stdout messages, trim ONLY the last newline character. 114 if payload.Severity == diag.Info { 115 payload.Message = cmdutil.RemoveTrailingNewline(payload.Message) 116 } 117 118 return opts.Color.Colorize(payload.Prefix + payload.Message) 119 }