Fix CLI hangs when errors occur

The change to use a Goroutine for pumping output causes a hang
when an error occurs.  This is because we unconditionally block
on the <-done channel, even though the failure means the done
will actually never occur.  This changes the logic to only wait
on the channel if we successfully began the operation in question.
This commit is contained in:
joeduffy 2017-10-20 17:28:35 -07:00
parent 60c566a35a
commit 9e20f15adf
5 changed files with 31 additions and 18 deletions

View file

@ -41,14 +41,15 @@ func newDestroyCmd() *cobra.Command {
go displayEvents(events, done, debug)
err := lumiEngine.Destroy(stackName, events, engine.DestroyOptions{
if err = lumiEngine.Destroy(stackName, events, engine.DestroyOptions{
DryRun: preview,
Parallel: parallel,
Summary: summary,
})
}); err != nil {
return err
}
<-done
return err
}
return nil

View file

@ -43,17 +43,19 @@ func newPreviewCmd() *cobra.Command {
go displayEvents(events, done, debug)
err = lumiEngine.Preview(stackName, events, engine.PreviewOptions{
if err = lumiEngine.Preview(stackName, events, engine.PreviewOptions{
Analyzers: analyzers,
Parallel: parallel,
ShowConfig: showConfig,
ShowReplacementSteps: showReplacementSteps,
ShowSames: showSames,
Summary: summary,
})
}); err != nil {
return err
}
<-done
return err
return nil
}),
}

View file

@ -45,7 +45,7 @@ func newUpdateCmd() *cobra.Command {
go displayEvents(events, done, debug)
err = lumiEngine.Deploy(stackName, events, engine.DeployOptions{
if err = lumiEngine.Deploy(stackName, events, engine.DeployOptions{
DryRun: dryRun,
Analyzers: analyzers,
Parallel: parallel,
@ -53,10 +53,12 @@ func newUpdateCmd() *cobra.Command {
ShowReplacementSteps: showReplacementSteps,
ShowSames: showSames,
Summary: summary,
})
}); err != nil {
return err
}
<-done
return err
return nil
}),
}

View file

@ -78,9 +78,9 @@ func displayEvents(events <-chan engine.Event, done chan bool, debug bool) {
for event := range events {
switch event.Type {
case "stdoutcolor":
case engine.StdoutColorEvent:
fmt.Print(colors.ColorizeText(event.Payload.(string)))
case "diag":
case engine.DiagEvent:
payload := event.Payload.(engine.DiagEventPayload)
var out io.Writer
out = os.Stdout

View file

@ -11,10 +11,18 @@ import (
// Event represents an event generated by the engine during an operation. The underlying
// type for the `Payload` field will differ depending on the value of the `Type` field
type Event struct {
Type string
Type EventType
Payload interface{}
}
// EventType is the kind of event being emitted.
type EventType string
const (
StdoutColorEvent EventType = "stdoutcolor"
DiagEvent EventType = "Diag"
)
// DiagEventPayload is the payload for an event with type `diag`
type DiagEventPayload struct {
Severity diag.Severity
@ -23,12 +31,12 @@ type DiagEventPayload struct {
}
func stdOutEventWithColor(s fmt.Stringer) Event {
return Event{Type: "stdoutcolor", Payload: s.String()}
return Event{Type: StdoutColorEvent, Payload: s.String()}
}
func diagDebugEvent(useColor bool, msg string) Event {
return Event{
Type: "diag",
Type: DiagEvent,
Payload: DiagEventPayload{
Severity: diag.Debug,
UseColor: useColor,
@ -39,7 +47,7 @@ func diagDebugEvent(useColor bool, msg string) Event {
func diagInfoEvent(useColor bool, msg string) Event {
return Event{
Type: "diag",
Type: DiagEvent,
Payload: DiagEventPayload{
Severity: diag.Info,
UseColor: useColor,
@ -50,7 +58,7 @@ func diagInfoEvent(useColor bool, msg string) Event {
func diagInfoerrEvent(useColor bool, msg string) Event {
return Event{
Type: "diag",
Type: DiagEvent,
Payload: DiagEventPayload{
Severity: diag.Infoerr,
UseColor: useColor,
@ -61,7 +69,7 @@ func diagInfoerrEvent(useColor bool, msg string) Event {
func diagErrorEvent(useColor bool, msg string) Event {
return Event{
Type: "diag",
Type: DiagEvent,
Payload: DiagEventPayload{
Severity: diag.Error,
UseColor: useColor,
@ -72,7 +80,7 @@ func diagErrorEvent(useColor bool, msg string) Event {
func diagWarningEvent(useColor bool, msg string) Event {
return Event{
Type: "diag",
Type: DiagEvent,
Payload: DiagEventPayload{
Severity: diag.Warning,
UseColor: useColor,