Add a summary to the apply command

This commit is contained in:
joeduffy 2017-02-20 18:00:36 -08:00
parent 60a51f1222
commit dcb6c958b3
2 changed files with 59 additions and 16 deletions

View file

@ -5,6 +5,7 @@ package cmd
import (
"bytes"
"fmt"
"time"
"github.com/spf13/cobra"
@ -34,6 +35,8 @@ func newApplyCmd() *cobra.Command {
"a path to a blueprint elsewhere can be provided as the [blueprint] argument.",
Run: func(cmd *cobra.Command, args []string) {
if comp, plan := plan(cmd, args, delete); plan != nil {
// Create an object to track progress and perform the actual operations.
start := time.Now()
progress := newProgress(detailed)
if err, _, _ := plan.Apply(progress); err != nil {
// TODO: we want richer diagnostics in the event that a plan apply fails. For instance, we want to
@ -41,6 +44,31 @@ func newApplyCmd() *cobra.Command {
// probably want to plumb diag.Sink through apply so it can issue its own rich diagnostics.
comp.Diag().Errorf(errors.ErrorPlanApplyFailed, err)
}
// Print out the total number of steps performed (and their kinds), if any succeeded.
var b bytes.Buffer
if progress.Steps > 0 {
b.WriteString(fmt.Sprintf("%v total operations in %v:\n", progress.Steps, time.Since(start)))
if c := progress.Ops[resource.OpCreate]; c > 0 {
b.WriteString(fmt.Sprintf(" %v%v resources created%v\n",
opPrefix(resource.OpCreate), c, colors.Reset))
}
if c := progress.Ops[resource.OpUpdate]; c > 0 {
b.WriteString(fmt.Sprintf(" %v%v resources updated%v\n",
opPrefix(resource.OpUpdate), c, colors.Reset))
}
if c := progress.Ops[resource.OpDelete]; c > 0 {
b.WriteString(fmt.Sprintf(" %v%v resources deleted%v\n",
opPrefix(resource.OpDelete), c, colors.Reset))
}
}
if progress.MaybeCorrupt {
b.WriteString(fmt.Sprintf(
"%vfatal: A catastrophic error occurred; resources states may be unknown%v\n",
colors.Red, colors.Reset))
}
s := b.String()
fmt.Printf(colors.Colorize(s))
}
},
}
@ -58,28 +86,40 @@ func newApplyCmd() *cobra.Command {
// applyProgress pretty-prints the plan application process as it goes.
type applyProgress struct {
c int
detailed bool
Steps int
Ops map[resource.StepOp]int
MaybeCorrupt bool
Detailed bool
}
func newProgress(detailed bool) *applyProgress {
return &applyProgress{detailed: detailed}
return &applyProgress{
Steps: 0,
Ops: make(map[resource.StepOp]int),
Detailed: detailed,
}
}
func (prog *applyProgress) Before(step resource.Step) {
// Print the step.
var b bytes.Buffer
prog.c++
b.WriteString(fmt.Sprintf("Applying step #%v\n", prog.c))
printStep(&b, step, !prog.detailed, " ")
stepnum := prog.Steps + 1
b.WriteString(fmt.Sprintf("Applying step #%v\n", stepnum))
printStep(&b, step, !prog.Detailed, " ")
s := colors.Colorize(b.String())
fmt.Printf(s)
}
func (prog *applyProgress) After(step resource.Step, err error, state resource.ResourceState) {
if err != nil {
if err == nil {
// Increment the counters.
prog.Steps++
prog.Ops[step.Op()]++
} else {
var b bytes.Buffer
// Print the state of the resource; we don't issue the error, because the apply above will do that.
b.WriteString(fmt.Sprintf("Step #%v failed: ", prog.c))
stepnum := prog.Steps + 1
b.WriteString(fmt.Sprintf("Step #%v failed: ", stepnum))
switch state {
case resource.StateOK:
b.WriteString(colors.BrightYellow)
@ -87,6 +127,7 @@ func (prog *applyProgress) After(step resource.Step, err error, state resource.R
case resource.StateUnknown:
b.WriteString(colors.BrightRed)
b.WriteString("this failure was catastrophic and the provider cannot guarantee recovery")
prog.MaybeCorrupt = true
default:
contract.Failf("Unrecognized resource state: %v", state)
}

View file

@ -67,18 +67,20 @@ func printPlan(plan resource.Plan, summary bool) {
}
}
func printStep(b *bytes.Buffer, step resource.Step, summary bool, indent string) {
// First print out the operation.
switch step.Op() {
func opPrefix(op resource.StepOp) string {
switch op {
case resource.OpCreate:
b.WriteString(colors.Green)
b.WriteString("+ ")
return colors.Green + "+ "
case resource.OpDelete:
b.WriteString(colors.Red)
b.WriteString("- ")
return colors.Red + "- "
default:
b.WriteString(" ")
return " "
}
}
func printStep(b *bytes.Buffer, step resource.Step, summary bool, indent string) {
// First print out the operation's prefix.
b.WriteString(opPrefix(step.Op()))
// Next print the resource moniker, properties, etc.
printResource(b, step.Resource(), summary, indent)