pulumi/pkg/backend/local/display.go
Matt Ellis ce05cce77f Provide a rudimentary progress spinner
Previously, the `pulumi` tool did not show any indication of progress
when doing a deployment. Combined with the fact that we do not create
resources in parallel it meant that sometime `pulumi` would appear to
hang, when really it was just waiting on some resource to be created
in AWS. In addition, some AWS resources take a long time to create and
CI systems like travis will kill the job if there is no output. This
causes us (and our customers) to have to do crazy dances where we
launch shell scripts that write a dot to the console every once in a
while so we don't get killed. While we plan to overhaul the output
logic (see #617), we take a first step towards interactivity by simply
having a nice little spinner (in the interactive case) and when run
non interactive have `pulumi` print a message that it is still
working.

Fixes #794
2018-01-22 14:21:08 -08:00

60 lines
1.5 KiB
Go

// Copyright 2016-2017, Pulumi Corporation. All rights reserved.
package local
import (
"fmt"
"io"
"io/ioutil"
"os"
"github.com/pulumi/pulumi/pkg/diag"
"github.com/pulumi/pulumi/pkg/engine"
"github.com/pulumi/pulumi/pkg/util/cmdutil"
"github.com/pulumi/pulumi/pkg/util/contract"
)
// displayEvents reads events from the `events` channel until it is closed, displaying each event as it comes in.
// Once all events have been read from the channel and displayed, it closes the `done` channel so the caller can
// await all the events being written.
func displayEvents(events <-chan engine.Event, done chan<- bool, debug bool) {
spinner, ticker := cmdutil.NewSpinnerAndTicker()
defer func() {
ticker.Stop()
done <- true
}()
for {
select {
case <-ticker.C:
spinner.Tick()
case event := <-events:
spinner.Reset()
switch event.Type {
case engine.CancelEvent:
return
case engine.StdoutColorEvent:
payload := event.Payload.(engine.StdoutEventPayload)
fmt.Print(payload.Color.Colorize(payload.Message))
case engine.DiagEvent:
payload := event.Payload.(engine.DiagEventPayload)
var out io.Writer
out = os.Stdout
if payload.Severity == diag.Error || payload.Severity == diag.Warning {
out = os.Stderr
}
if payload.Severity == diag.Debug && !debug {
out = ioutil.Discard
}
msg := payload.Message
msg = payload.Color.Colorize(msg)
_, fmterr := fmt.Fprint(out, msg)
contract.IgnoreError(fmterr)
default:
contract.Failf("unknown event type '%s'", event.Type)
}
}
}
}