Move summary printing out of the engine
The engine now emits a special type of summary event, which the CLI displays.
This commit is contained in:
parent
4e2f94df95
commit
02c45f9f10
|
@ -7,11 +7,13 @@ import (
|
|||
"io"
|
||||
"os"
|
||||
"sort"
|
||||
"strconv"
|
||||
|
||||
"github.com/pulumi/pulumi/pkg/backend"
|
||||
"github.com/pulumi/pulumi/pkg/diag"
|
||||
"github.com/pulumi/pulumi/pkg/diag/colors"
|
||||
"github.com/pulumi/pulumi/pkg/engine"
|
||||
"github.com/pulumi/pulumi/pkg/resource/deploy"
|
||||
"github.com/pulumi/pulumi/pkg/util/cmdutil"
|
||||
"github.com/pulumi/pulumi/pkg/util/contract"
|
||||
)
|
||||
|
@ -42,6 +44,8 @@ func displayEvents(action string,
|
|||
return
|
||||
case engine.PreludeEvent:
|
||||
displayPreludeEvent(os.Stdout, event.Payload.(engine.PreludeEventPayload), opts)
|
||||
case engine.SummaryEvent:
|
||||
displaySummaryEvent(os.Stdout, event.Payload.(engine.SummaryEventPayload), opts)
|
||||
case engine.StdoutColorEvent:
|
||||
payload := event.Payload.(engine.StdoutEventPayload)
|
||||
out = os.Stdout
|
||||
|
@ -67,6 +71,75 @@ func displayEvents(action string,
|
|||
}
|
||||
}
|
||||
|
||||
// nolint: gas
|
||||
func displaySummaryEvent(out io.Writer, event engine.SummaryEventPayload, opts backend.DisplayOptions) {
|
||||
changes := event.ResourceChanges
|
||||
|
||||
changeCount := 0
|
||||
for op, c := range changes {
|
||||
if op != deploy.OpSame {
|
||||
changeCount += c
|
||||
}
|
||||
}
|
||||
var kind string
|
||||
if event.IsPreview {
|
||||
kind = "previewed"
|
||||
} else {
|
||||
kind = "performed"
|
||||
}
|
||||
|
||||
var changesLabel string
|
||||
if changeCount == 0 {
|
||||
kind = "required"
|
||||
changesLabel = "no"
|
||||
} else {
|
||||
changesLabel = strconv.Itoa(changeCount)
|
||||
}
|
||||
|
||||
if changeCount > 0 || changes[deploy.OpSame] > 0 {
|
||||
kind += ":"
|
||||
}
|
||||
|
||||
fmt.Fprint(out, opts.Color.Colorize(fmt.Sprintf("%vinfo%v: %v %v %v\n",
|
||||
colors.SpecInfo, colors.Reset, changesLabel, plural("change", changeCount), kind)))
|
||||
|
||||
var planTo string
|
||||
if event.IsPreview {
|
||||
planTo = "to "
|
||||
}
|
||||
|
||||
// Now summarize all of the changes; we print sames a little differently.
|
||||
for _, op := range deploy.StepOps {
|
||||
if op != deploy.OpSame {
|
||||
if c := changes[op]; c > 0 {
|
||||
opDescription := string(op)
|
||||
if !event.IsPreview {
|
||||
opDescription = op.PastTense()
|
||||
}
|
||||
fmt.Fprint(out, opts.Color.Colorize(fmt.Sprintf(" %v%v %v %v%v%v\n",
|
||||
op.Prefix(), c, plural("resource", c), planTo, opDescription, colors.Reset)))
|
||||
}
|
||||
}
|
||||
}
|
||||
if c := changes[deploy.OpSame]; c > 0 {
|
||||
fmt.Fprintf(out, " %v %v unchanged\n", c, plural("resource", c))
|
||||
}
|
||||
|
||||
// For actual deploys, we print some additional summary information
|
||||
if !event.IsPreview {
|
||||
if changeCount > 0 {
|
||||
fmt.Fprint(out, opts.Color.Colorize(fmt.Sprintf("%vUpdate duration: %v%v\n",
|
||||
colors.SpecUnimportant, event.Duration, colors.Reset)))
|
||||
}
|
||||
|
||||
if event.MaybeCorrupt {
|
||||
fmt.Fprint(out, opts.Color.Colorize(fmt.Sprintf(
|
||||
"%vA catastrophic error occurred; resources states may be unknown%v\n",
|
||||
colors.SpecAttention, colors.Reset)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// nolint: gas
|
||||
func displayPreludeEvent(out io.Writer, event engine.PreludeEventPayload, opts backend.DisplayOptions) {
|
||||
if opts.ShowConfig {
|
||||
|
@ -89,3 +162,10 @@ func displayPreludeEvent(out io.Writer, event engine.PreludeEventPayload, opts b
|
|||
|
||||
fmt.Fprint(out, opts.Color.Colorize(fmt.Sprintf("%v%v changes:%v\n", colors.SpecUnimportant, action, colors.Reset)))
|
||||
}
|
||||
|
||||
func plural(s string, c int) string {
|
||||
if c != 1 {
|
||||
s += "s"
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
|
|
@ -99,23 +99,9 @@ func deployLatest(info *planContext, opts deployOptions) (ResourceChanges, error
|
|||
}
|
||||
contract.Assert(summary != nil)
|
||||
|
||||
// Print a summary.
|
||||
var footer bytes.Buffer
|
||||
|
||||
// Print out the total number of steps performed (and their kinds), the duration, and any summary info.
|
||||
resourceChanges = ResourceChanges(actions.Ops)
|
||||
if c := printChangeSummary(&footer, resourceChanges, false); c != 0 {
|
||||
footer.WriteString(fmt.Sprintf("%vUpdate duration: %v%v\n",
|
||||
colors.SpecUnimportant, time.Since(start), colors.Reset))
|
||||
}
|
||||
|
||||
if actions.MaybeCorrupt {
|
||||
footer.WriteString(fmt.Sprintf(
|
||||
"%vA catastrophic error occurred; resources states may be unknown%v\n",
|
||||
colors.SpecAttention, colors.Reset))
|
||||
}
|
||||
|
||||
opts.Events <- stdOutEventWithColor(&footer)
|
||||
opts.Events <- updateSummaryEvent(actions.MaybeCorrupt, time.Since(start), resourceChanges)
|
||||
|
||||
if err != nil {
|
||||
return resourceChanges, err
|
||||
|
|
|
@ -4,6 +4,7 @@ package engine
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/pulumi/pulumi/pkg/diag"
|
||||
"github.com/pulumi/pulumi/pkg/diag/colors"
|
||||
|
@ -26,6 +27,7 @@ const (
|
|||
StdoutColorEvent EventType = "stdoutcolor"
|
||||
DiagEvent EventType = "diag"
|
||||
PreludeEvent EventType = "prelude"
|
||||
SummaryEvent EventType = "summary"
|
||||
)
|
||||
|
||||
func cancelEvent() Event {
|
||||
|
@ -49,6 +51,13 @@ type PreludeEventPayload struct {
|
|||
Config map[string]string // the keys and values for config. For encrypted config, the values may be blinded
|
||||
}
|
||||
|
||||
type SummaryEventPayload struct {
|
||||
IsPreview bool // true if this summary is for a plan operation
|
||||
MaybeCorrupt bool // true if one or more resources may be corrupt
|
||||
Duration time.Duration // the duration of the entire update operation (zero values for previews)
|
||||
ResourceChanges ResourceChanges // count of changed resources, useful for reporting
|
||||
}
|
||||
|
||||
func preludeEvent(isPreview bool, cfg config.Map) Event {
|
||||
configStringMap := make(map[string]string, len(cfg))
|
||||
for k, v := range cfg {
|
||||
|
@ -67,6 +76,30 @@ func preludeEvent(isPreview bool, cfg config.Map) Event {
|
|||
}
|
||||
}
|
||||
|
||||
func previewSummaryEvent(resourceChanges ResourceChanges) Event {
|
||||
return Event{
|
||||
Type: SummaryEvent,
|
||||
Payload: SummaryEventPayload{
|
||||
IsPreview: true,
|
||||
MaybeCorrupt: false,
|
||||
Duration: 0,
|
||||
ResourceChanges: resourceChanges,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func updateSummaryEvent(maybeCorrupt bool, duration time.Duration, resourceChanges ResourceChanges) Event {
|
||||
return Event{
|
||||
Type: SummaryEvent,
|
||||
Payload: SummaryEventPayload{
|
||||
IsPreview: false,
|
||||
MaybeCorrupt: maybeCorrupt,
|
||||
Duration: duration,
|
||||
ResourceChanges: resourceChanges,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func stdOutEventWithColor(s fmt.Stringer) Event {
|
||||
return Event{
|
||||
Type: StdoutColorEvent,
|
||||
|
|
|
@ -198,11 +198,9 @@ func printPlan(result *planResult) (ResourceChanges, error) {
|
|||
return nil, errors.New("One or more errors occurred during this preview")
|
||||
}
|
||||
|
||||
// Print a summary of operation counts.
|
||||
var summary bytes.Buffer
|
||||
// Emit an event with a summary of operation counts.
|
||||
changes := ResourceChanges(actions.Ops)
|
||||
printChangeSummary(&summary, changes, true)
|
||||
result.Options.Events <- stdOutEventWithColor(&summary)
|
||||
result.Options.Events <- previewSummaryEvent(changes)
|
||||
return changes, nil
|
||||
}
|
||||
|
||||
|
@ -231,69 +229,6 @@ func isRootStack(step deploy.Step) bool {
|
|||
return step.URN().Type() == resource.RootStackType
|
||||
}
|
||||
|
||||
// printChangeSummary writes summary informatiom about the resoures changed to the provided buffer.
|
||||
// Returns the total number of resources changed regardless of operation type.
|
||||
func printChangeSummary(b *bytes.Buffer, changes ResourceChanges, preview bool) int {
|
||||
changeCount := 0
|
||||
for op, c := range changes {
|
||||
if op != deploy.OpSame {
|
||||
changeCount += c
|
||||
}
|
||||
}
|
||||
var kind string
|
||||
if preview {
|
||||
kind = "previewed"
|
||||
} else {
|
||||
kind = "performed"
|
||||
}
|
||||
|
||||
var changesLabel string
|
||||
if changeCount == 0 {
|
||||
kind = "required"
|
||||
changesLabel = "no"
|
||||
} else {
|
||||
changesLabel = strconv.Itoa(changeCount)
|
||||
}
|
||||
|
||||
if changeCount > 0 || changes[deploy.OpSame] > 0 {
|
||||
kind += ":"
|
||||
}
|
||||
|
||||
b.WriteString(fmt.Sprintf("%vinfo%v: %v %v %v\n",
|
||||
colors.SpecInfo, colors.Reset, changesLabel, plural("change", changeCount), kind))
|
||||
|
||||
var planTo string
|
||||
if preview {
|
||||
planTo = "to "
|
||||
}
|
||||
|
||||
// Now summarize all of the changes; we print sames a little differently.
|
||||
for _, op := range deploy.StepOps {
|
||||
if op != deploy.OpSame {
|
||||
if c := changes[op]; c > 0 {
|
||||
opDescription := string(op)
|
||||
if !preview {
|
||||
opDescription = op.PastTense()
|
||||
}
|
||||
b.WriteString(fmt.Sprintf(" %v%v %v %v%v%v\n",
|
||||
op.Prefix(), c, plural("resource", c), planTo, opDescription, colors.Reset))
|
||||
}
|
||||
}
|
||||
}
|
||||
if c := changes[deploy.OpSame]; c > 0 {
|
||||
b.WriteString(fmt.Sprintf(" %v %v unchanged\n", c, plural("resource", c)))
|
||||
}
|
||||
|
||||
return changeCount
|
||||
}
|
||||
|
||||
func plural(s string, c int) string {
|
||||
if c != 1 {
|
||||
s += "s"
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// stepParentIndent computes a step's parent indentation. If print is true, it also prints parents as it goes.
|
||||
func stepParentIndent(b *bytes.Buffer, step deploy.Step,
|
||||
seen map[resource.URN]deploy.Step, shown map[resource.URN]bool,
|
||||
|
|
Loading…
Reference in a new issue