2018-05-22 21:43:36 +02:00
|
|
|
// Copyright 2016-2018, Pulumi Corporation.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
2018-04-10 21:03:11 +02:00
|
|
|
|
2019-07-12 20:12:01 +02:00
|
|
|
// nolint: goconst
|
2018-09-05 00:40:15 +02:00
|
|
|
package display
|
2018-04-10 21:03:11 +02:00
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"fmt"
|
2019-04-01 16:27:21 +02:00
|
|
|
"io"
|
2018-04-12 19:56:39 +02:00
|
|
|
"os"
|
2018-04-10 21:03:11 +02:00
|
|
|
"regexp"
|
2018-04-24 20:13:22 +02:00
|
|
|
"sort"
|
2018-04-10 21:03:11 +02:00
|
|
|
"strings"
|
2018-04-12 19:56:39 +02:00
|
|
|
"time"
|
2018-04-14 07:26:01 +02:00
|
|
|
"unicode"
|
2018-04-24 20:13:22 +02:00
|
|
|
"unicode/utf8"
|
2018-04-10 21:03:11 +02:00
|
|
|
|
2018-08-30 02:06:48 +02:00
|
|
|
"github.com/docker/docker/pkg/term"
|
|
|
|
"golang.org/x/crypto/ssh/terminal"
|
|
|
|
|
|
|
|
"github.com/pulumi/pulumi/pkg/apitype"
|
2018-04-10 21:03:11 +02:00
|
|
|
"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"
|
|
|
|
"github.com/pulumi/pulumi/pkg/resource/deploy"
|
|
|
|
"github.com/pulumi/pulumi/pkg/tokens"
|
|
|
|
"github.com/pulumi/pulumi/pkg/util/cmdutil"
|
|
|
|
"github.com/pulumi/pulumi/pkg/util/contract"
|
|
|
|
)
|
|
|
|
|
2018-04-20 00:55:24 +02:00
|
|
|
// Progress describes a message we want to show in the display. There are two types of messages,
|
|
|
|
// simple 'Messages' which just get printed out as a single uninterpreted line, and 'Actions' which
|
|
|
|
// are placed and updated in the progress-grid based on their ID. Messages do not need an ID, while
|
|
|
|
// Actions must have an ID.
|
|
|
|
type Progress struct {
|
|
|
|
ID string
|
|
|
|
Message string
|
|
|
|
Action string
|
|
|
|
}
|
|
|
|
|
|
|
|
func makeMessageProgress(message string) Progress {
|
|
|
|
return Progress{Message: message}
|
|
|
|
}
|
|
|
|
|
2018-04-24 20:13:22 +02:00
|
|
|
func makeActionProgress(id string, action string) Progress {
|
2018-04-20 00:55:24 +02:00
|
|
|
contract.Assertf(id != "", "id must be non empty for action %s", action)
|
|
|
|
contract.Assertf(action != "", "action must be non empty")
|
|
|
|
|
2018-04-24 20:13:22 +02:00
|
|
|
return Progress{ID: id, Action: action}
|
2018-04-20 00:55:24 +02:00
|
|
|
}
|
|
|
|
|
2018-04-15 21:47:53 +02:00
|
|
|
type DiagInfo struct {
|
|
|
|
ErrorCount, WarningCount, InfoCount, DebugCount int
|
2018-04-10 21:03:11 +02:00
|
|
|
|
2018-07-17 22:00:10 +02:00
|
|
|
// The very last diagnostic event we got for this resource (regardless of severity). We'll print
|
|
|
|
// this out in the non-interactive mode whenever we get new events. Importantly, we don't want
|
|
|
|
// to print out the most significant diagnostic, as that means a flurry of event swill cause us
|
|
|
|
// to keep printing out the most significant diagnostic over and over again.
|
|
|
|
LastDiag *engine.DiagEventPayload
|
|
|
|
|
2019-08-01 19:21:47 +02:00
|
|
|
// The last error we received. If we have an error, and we're in tree-view, we'll prefer to
|
|
|
|
// show this over the last non-error diag so that users know about something bad early on.
|
|
|
|
LastError *engine.DiagEventPayload
|
2018-04-10 21:03:11 +02:00
|
|
|
|
2018-05-08 00:11:52 +02:00
|
|
|
// All the diagnostic events we've heard about this resource. We'll print the last diagnostic
|
|
|
|
// in the status region while a resource is in progress. At the end we'll print out all
|
|
|
|
// diagnostics for a resource.
|
|
|
|
//
|
|
|
|
// Diagnostic events are bucketed by their associated stream ID (with 0 being the default
|
|
|
|
// stream)
|
|
|
|
StreamIDToDiagPayloads map[int32][]engine.DiagEventPayload
|
2018-04-10 21:03:11 +02:00
|
|
|
}
|
|
|
|
|
2018-04-17 08:41:00 +02:00
|
|
|
type ProgressDisplay struct {
|
2018-09-05 00:40:15 +02:00
|
|
|
opts Options
|
2018-04-20 00:55:24 +02:00
|
|
|
progressOutput chan<- Progress
|
2018-04-17 08:41:00 +02:00
|
|
|
|
2018-08-30 02:06:48 +02:00
|
|
|
// action is the kind of action (preview, update, refresh, etc) being performed.
|
|
|
|
action apitype.UpdateKind
|
Make a smattering of CLI UX improvements
Since I was digging around over the weekend after the change to move
away from light black, and the impact it had on less important
information showing more prominently than it used to, I took a step
back and did a deeper tidying up of things. Another side goal of this
exercise was to be a little more respectful of terminal width; when
we could say things with fewer words, I did so.
* Stylize the preview/update summary differently, so that it stands
out as a section. Also highlight the total changes with bold -- it
turns out this has a similar effect to the bright white colorization,
just without the negative effects on e.g. white terminals.
* Eliminate some verbosity in the phrasing of change summaries.
* Make all heading sections stylized consistently. This includes
the color (bright magenta) and the vertical spacing (always a newline
separating headings). We were previously inconsistent on this (e.g.,
outputs were under "---outputs---"). Now the headings are:
Previewing (etc), Diagnostics, Outputs, Resources, Duration, and Permalink.
* Fix an issue where we'd parent things to "global" until the stack
object later showed up. Now we'll simply mock up a stack resource.
* Don't show messages like "no change" or "unchanged". Prior to the
light black removal, these faded into the background of the terminal.
Now they just clutter up the display. Similar to the elision of "*"
for OpSames in a prior commit, just leave these out. Now anything
that's written is actually a meaningful status for the user to note.
* Don't show the "3 info messages," etc. summaries in the Info column
while an update is ongoing. Instead, just show the latest line. This
is more respectful of width -- I often find that the important
messages scroll off the right of my screen before this change.
For discussion:
- I actually wonder if we should eliminate the summary
altogether and always just show the latest line. Or even
blank it out. The summary feels better suited for the
Diagnostics section, and the Status concisely tells us
how a resource's update ended up (failed, succeeded, etc).
- Similarly, I question the idea of showing only the "worst"
message. I'd vote for always showing the latest, and again
leaving it to the Status column for concisely telling the
user about the final state a resource ended up in.
* Stop prepending "info: " to every stdout/stderr message. It adds
no value, clutters up the display, and worsens horizontal usage.
* Lessen the verbosity of update headline messages, so we now instead
of e.g. "Previewing update of stack 'x':", we just say
"Previewing update (x):".
* Eliminate vertical whitespace in the Diagnostics section. Every
independent console.out previously was separated by an entire newline,
which made the section look cluttered to my eyes. These are just
streams of logs, there's no reason for the extra newlines.
* Colorize the resource headers in the Diagnostic section light blue.
Note that this will change various test baselines, which I will
update next. I didn't want those in the same commit.
2018-09-24 17:31:19 +02:00
|
|
|
// stack is the stack this progress pertains to.
|
|
|
|
stack tokens.QName
|
|
|
|
// proj is the project this progress pertains to.
|
|
|
|
proj tokens.PackageName
|
2018-08-30 02:06:48 +02:00
|
|
|
|
2018-04-17 08:41:00 +02:00
|
|
|
// Whether or not we're previewing. We don't know what we are actually doing until
|
|
|
|
// we get the initial 'prelude' event.
|
|
|
|
//
|
|
|
|
// this flag is only used to adjust how we describe what's going on to the user.
|
|
|
|
// i.e. if we're previewing we say things like "Would update" instead of "Updating".
|
|
|
|
isPreview bool
|
|
|
|
|
|
|
|
// The urn of the stack.
|
|
|
|
stackUrn resource.URN
|
|
|
|
|
2018-09-12 01:44:06 +02:00
|
|
|
// Whether or not we've seen outputs for the stack yet.
|
|
|
|
seenStackOutputs bool
|
|
|
|
|
2018-04-17 08:41:00 +02:00
|
|
|
// The summary event from the engine. If we get this, we'll print this after all
|
|
|
|
// normal resource events are heard. That way we don't interfere with all the progress
|
|
|
|
// messages we're outputting for them.
|
2018-04-19 23:44:53 +02:00
|
|
|
summaryEventPayload *engine.SummaryEventPayload
|
|
|
|
|
|
|
|
// Any system events we've received. They will be printed at the bottom of all the status rows
|
|
|
|
systemEventPayloads []engine.StdoutEventPayload
|
2018-04-17 08:41:00 +02:00
|
|
|
|
2018-04-24 20:13:22 +02:00
|
|
|
// Used to record the order that rows are created in. That way, when we present in a tree, we
|
|
|
|
// can keep things ordered so they will not jump around.
|
|
|
|
displayOrderCounter int
|
|
|
|
|
2018-04-17 08:41:00 +02:00
|
|
|
// What tick we're currently on. Used to determine the number of ellipses to concat to
|
|
|
|
// a status message to help indicate that things are still working.
|
|
|
|
currentTick int
|
|
|
|
|
2018-07-12 20:38:44 +02:00
|
|
|
// A spinner to use to show that we're still doing work even when no output has been
|
|
|
|
// printed to the console in a while.
|
|
|
|
nonInteractiveSpinner cmdutil.Spinner
|
2018-07-10 22:44:18 +02:00
|
|
|
|
2018-04-23 03:10:19 +02:00
|
|
|
headerRow Row
|
|
|
|
resourceRows []ResourceRow
|
2018-04-17 08:41:00 +02:00
|
|
|
|
|
|
|
// A mapping from each resource URN we are told about to its current status.
|
|
|
|
eventUrnToResourceRow map[resource.URN]ResourceRow
|
|
|
|
|
|
|
|
// Remember if we're a terminal or not. In a terminal we get a little bit fancier.
|
|
|
|
// For example, we'll go back and update previous status messages to make sure things
|
|
|
|
// align. We don't need to do that in non-terminal situations.
|
|
|
|
isTerminal bool
|
|
|
|
|
2019-07-26 20:36:20 +02:00
|
|
|
// The width and height of the terminal. Used so we can trim resource messages that are too long.
|
|
|
|
terminalWidth int
|
|
|
|
terminalHeight int
|
2018-04-17 08:41:00 +02:00
|
|
|
|
|
|
|
// If all progress messages are done and we can print out the final display.
|
2018-08-02 06:48:14 +02:00
|
|
|
done bool
|
2018-04-17 08:41:00 +02:00
|
|
|
|
|
|
|
// The column that the suffix should be added to
|
|
|
|
suffixColumn int
|
|
|
|
|
|
|
|
// the list of suffixes to rotate through
|
|
|
|
suffixesArray []string
|
|
|
|
|
2018-04-19 21:31:47 +02:00
|
|
|
// Maps used so we can generate short IDs for resource urns.
|
|
|
|
urnToID map[resource.URN]string
|
|
|
|
|
|
|
|
// Cache of colorized to uncolorized text. We go between the two a lot, so caching helps
|
|
|
|
// prevent lots of recomputation
|
|
|
|
colorizedToUncolorized map[string]string
|
2018-04-24 20:13:22 +02:00
|
|
|
|
|
|
|
// Cache of lines we've already printed. We don't print a progress message again if it hasn't
|
|
|
|
// changed between the last time we printed and now.
|
|
|
|
printedProgressCache map[string]Progress
|
2018-04-17 08:41:00 +02:00
|
|
|
}
|
|
|
|
|
2018-04-10 21:03:11 +02:00
|
|
|
var (
|
|
|
|
// simple regex to take our names like "aws:function:Function" and convert to
|
|
|
|
// "aws:Function"
|
2018-04-15 21:47:53 +02:00
|
|
|
typeNameRegex = regexp.MustCompile("^(.*):(.*)/(.*):(.*)$")
|
2018-04-10 21:03:11 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
func simplifyTypeName(typ tokens.Type) string {
|
|
|
|
typeString := string(typ)
|
2018-04-15 21:47:53 +02:00
|
|
|
return typeNameRegex.ReplaceAllString(typeString, "$1:$2:$4")
|
2018-04-10 21:03:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// getEventUrn returns the resource URN associated with an event, or the empty URN if this is not an
|
2018-04-12 19:56:39 +02:00
|
|
|
// event that has a URN. If this is also a 'step' event, then this will return the step metadata as
|
|
|
|
// well.
|
|
|
|
func getEventUrnAndMetadata(event engine.Event) (resource.URN, *engine.StepEventMetadata) {
|
2018-04-10 21:03:11 +02:00
|
|
|
if event.Type == engine.ResourcePreEvent {
|
|
|
|
payload := event.Payload.(engine.ResourcePreEventPayload)
|
2018-04-12 19:56:39 +02:00
|
|
|
return payload.Metadata.URN, &payload.Metadata
|
2018-04-10 21:03:11 +02:00
|
|
|
} else if event.Type == engine.ResourceOutputsEvent {
|
|
|
|
payload := event.Payload.(engine.ResourceOutputsEventPayload)
|
2018-04-12 19:56:39 +02:00
|
|
|
return payload.Metadata.URN, &payload.Metadata
|
|
|
|
} else if event.Type == engine.ResourceOperationFailed {
|
|
|
|
payload := event.Payload.(engine.ResourceOperationFailedPayload)
|
|
|
|
return payload.Metadata.URN, &payload.Metadata
|
2018-04-10 21:03:11 +02:00
|
|
|
} else if event.Type == engine.DiagEvent {
|
2018-04-12 19:56:39 +02:00
|
|
|
return event.Payload.(engine.DiagEventPayload).URN, nil
|
2019-07-22 22:33:54 +02:00
|
|
|
} else if event.Type == engine.PolicyViolationEvent {
|
|
|
|
return event.Payload.(engine.PolicyViolationEventPayload).ResourceURN, nil
|
2018-04-10 21:03:11 +02:00
|
|
|
}
|
|
|
|
|
2018-04-12 19:56:39 +02:00
|
|
|
return "", nil
|
2018-04-10 21:03:11 +02:00
|
|
|
}
|
|
|
|
|
2018-04-12 19:56:39 +02:00
|
|
|
// Converts the colorization tags in a progress message and then actually writes the progress
|
|
|
|
// message to the output stream. This should be the only place in this file where we actually
|
|
|
|
// process colorization tags.
|
2018-04-20 00:55:24 +02:00
|
|
|
func (display *ProgressDisplay) colorizeAndWriteProgress(progress Progress) {
|
2018-04-12 19:56:39 +02:00
|
|
|
if progress.Message != "" {
|
|
|
|
progress.Message = display.opts.Color.Colorize(progress.Message)
|
2018-04-10 21:03:11 +02:00
|
|
|
}
|
|
|
|
|
2018-04-12 19:56:39 +02:00
|
|
|
if progress.Action != "" {
|
|
|
|
progress.Action = display.opts.Color.Colorize(progress.Action)
|
2018-04-10 21:03:11 +02:00
|
|
|
}
|
|
|
|
|
2018-04-24 20:13:22 +02:00
|
|
|
if progress.ID != "" {
|
|
|
|
// don't repeat the same output if there is no difference between the last time we
|
|
|
|
// printed it and now.
|
|
|
|
lastProgress, has := display.printedProgressCache[progress.ID]
|
|
|
|
if has && lastProgress.Message == progress.Message && lastProgress.Action == progress.Action {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
display.printedProgressCache[progress.ID] = progress
|
|
|
|
}
|
|
|
|
|
2018-07-12 20:38:44 +02:00
|
|
|
if !display.isTerminal {
|
|
|
|
// We're about to display something. Reset our spinner so that it will go on the next line.
|
|
|
|
display.nonInteractiveSpinner.Reset()
|
|
|
|
}
|
|
|
|
|
2018-04-20 00:55:24 +02:00
|
|
|
display.progressOutput <- progress
|
2018-04-10 21:03:11 +02:00
|
|
|
}
|
|
|
|
|
2018-04-14 07:26:01 +02:00
|
|
|
func (display *ProgressDisplay) writeSimpleMessage(msg string) {
|
2018-04-20 00:55:24 +02:00
|
|
|
display.colorizeAndWriteProgress(makeMessageProgress(msg))
|
2018-04-14 07:26:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func (display *ProgressDisplay) writeBlankLine() {
|
|
|
|
display.writeSimpleMessage(" ")
|
|
|
|
}
|
|
|
|
|
2018-09-05 17:25:23 +02:00
|
|
|
// ShowProgressEvents displays the engine events with docker's progress view.
|
Make a smattering of CLI UX improvements
Since I was digging around over the weekend after the change to move
away from light black, and the impact it had on less important
information showing more prominently than it used to, I took a step
back and did a deeper tidying up of things. Another side goal of this
exercise was to be a little more respectful of terminal width; when
we could say things with fewer words, I did so.
* Stylize the preview/update summary differently, so that it stands
out as a section. Also highlight the total changes with bold -- it
turns out this has a similar effect to the bright white colorization,
just without the negative effects on e.g. white terminals.
* Eliminate some verbosity in the phrasing of change summaries.
* Make all heading sections stylized consistently. This includes
the color (bright magenta) and the vertical spacing (always a newline
separating headings). We were previously inconsistent on this (e.g.,
outputs were under "---outputs---"). Now the headings are:
Previewing (etc), Diagnostics, Outputs, Resources, Duration, and Permalink.
* Fix an issue where we'd parent things to "global" until the stack
object later showed up. Now we'll simply mock up a stack resource.
* Don't show messages like "no change" or "unchanged". Prior to the
light black removal, these faded into the background of the terminal.
Now they just clutter up the display. Similar to the elision of "*"
for OpSames in a prior commit, just leave these out. Now anything
that's written is actually a meaningful status for the user to note.
* Don't show the "3 info messages," etc. summaries in the Info column
while an update is ongoing. Instead, just show the latest line. This
is more respectful of width -- I often find that the important
messages scroll off the right of my screen before this change.
For discussion:
- I actually wonder if we should eliminate the summary
altogether and always just show the latest line. Or even
blank it out. The summary feels better suited for the
Diagnostics section, and the Status concisely tells us
how a resource's update ended up (failed, succeeded, etc).
- Similarly, I question the idea of showing only the "worst"
message. I'd vote for always showing the latest, and again
leaving it to the Status column for concisely telling the
user about the final state a resource ended up in.
* Stop prepending "info: " to every stdout/stderr message. It adds
no value, clutters up the display, and worsens horizontal usage.
* Lessen the verbosity of update headline messages, so we now instead
of e.g. "Previewing update of stack 'x':", we just say
"Previewing update (x):".
* Eliminate vertical whitespace in the Diagnostics section. Every
independent console.out previously was separated by an entire newline,
which made the section look cluttered to my eyes. These are just
streams of logs, there's no reason for the extra newlines.
* Colorize the resource headers in the Diagnostic section light blue.
Note that this will change various test baselines, which I will
update next. I didn't want those in the same commit.
2018-09-24 17:31:19 +02:00
|
|
|
func ShowProgressEvents(op string, action apitype.UpdateKind, stack tokens.QName, proj tokens.PackageName,
|
2018-10-30 23:42:33 +01:00
|
|
|
events <-chan engine.Event, done chan<- bool, opts Options, isPreview bool) {
|
2018-04-12 19:56:39 +02:00
|
|
|
// Create a ticker that will update all our status messages once a second. Any
|
|
|
|
// in-flight resources will get a varying . .. ... ticker appended to them to
|
|
|
|
// let the user know what is still being worked on.
|
2018-07-12 20:38:44 +02:00
|
|
|
spinner, ticker := cmdutil.NewSpinnerAndTicker(
|
2018-08-30 02:06:48 +02:00
|
|
|
fmt.Sprintf("%s%s...", cmdutil.EmojiOr("✨ ", "@ "), op),
|
2018-04-12 19:56:39 +02:00
|
|
|
nil, 1 /*timesPerSecond*/)
|
|
|
|
|
2018-09-05 17:25:23 +02:00
|
|
|
// The channel we push progress messages into, and which ShowProgressOutput pulls
|
2018-04-20 00:55:24 +02:00
|
|
|
// from to display to the console.
|
|
|
|
progressOutput := make(chan Progress)
|
2018-04-12 19:56:39 +02:00
|
|
|
|
|
|
|
display := &ProgressDisplay{
|
2018-08-30 02:06:48 +02:00
|
|
|
action: action,
|
2018-10-30 23:42:33 +01:00
|
|
|
isPreview: isPreview,
|
2018-04-19 21:31:47 +02:00
|
|
|
opts: opts,
|
Make a smattering of CLI UX improvements
Since I was digging around over the weekend after the change to move
away from light black, and the impact it had on less important
information showing more prominently than it used to, I took a step
back and did a deeper tidying up of things. Another side goal of this
exercise was to be a little more respectful of terminal width; when
we could say things with fewer words, I did so.
* Stylize the preview/update summary differently, so that it stands
out as a section. Also highlight the total changes with bold -- it
turns out this has a similar effect to the bright white colorization,
just without the negative effects on e.g. white terminals.
* Eliminate some verbosity in the phrasing of change summaries.
* Make all heading sections stylized consistently. This includes
the color (bright magenta) and the vertical spacing (always a newline
separating headings). We were previously inconsistent on this (e.g.,
outputs were under "---outputs---"). Now the headings are:
Previewing (etc), Diagnostics, Outputs, Resources, Duration, and Permalink.
* Fix an issue where we'd parent things to "global" until the stack
object later showed up. Now we'll simply mock up a stack resource.
* Don't show messages like "no change" or "unchanged". Prior to the
light black removal, these faded into the background of the terminal.
Now they just clutter up the display. Similar to the elision of "*"
for OpSames in a prior commit, just leave these out. Now anything
that's written is actually a meaningful status for the user to note.
* Don't show the "3 info messages," etc. summaries in the Info column
while an update is ongoing. Instead, just show the latest line. This
is more respectful of width -- I often find that the important
messages scroll off the right of my screen before this change.
For discussion:
- I actually wonder if we should eliminate the summary
altogether and always just show the latest line. Or even
blank it out. The summary feels better suited for the
Diagnostics section, and the Status concisely tells us
how a resource's update ended up (failed, succeeded, etc).
- Similarly, I question the idea of showing only the "worst"
message. I'd vote for always showing the latest, and again
leaving it to the Status column for concisely telling the
user about the final state a resource ended up in.
* Stop prepending "info: " to every stdout/stderr message. It adds
no value, clutters up the display, and worsens horizontal usage.
* Lessen the verbosity of update headline messages, so we now instead
of e.g. "Previewing update of stack 'x':", we just say
"Previewing update (x):".
* Eliminate vertical whitespace in the Diagnostics section. Every
independent console.out previously was separated by an entire newline,
which made the section look cluttered to my eyes. These are just
streams of logs, there's no reason for the extra newlines.
* Colorize the resource headers in the Diagnostic section light blue.
Note that this will change various test baselines, which I will
update next. I didn't want those in the same commit.
2018-09-24 17:31:19 +02:00
|
|
|
stack: stack,
|
|
|
|
proj: proj,
|
2018-04-19 21:31:47 +02:00
|
|
|
progressOutput: progressOutput,
|
|
|
|
eventUrnToResourceRow: make(map[resource.URN]ResourceRow),
|
|
|
|
suffixColumn: int(statusColumn),
|
|
|
|
suffixesArray: []string{"", ".", "..", "..."},
|
|
|
|
urnToID: make(map[resource.URN]string),
|
|
|
|
colorizedToUncolorized: make(map[string]string),
|
2018-04-24 20:13:22 +02:00
|
|
|
printedProgressCache: make(map[string]Progress),
|
|
|
|
displayOrderCounter: 1,
|
2018-07-12 20:38:44 +02:00
|
|
|
nonInteractiveSpinner: spinner,
|
2018-04-17 08:41:00 +02:00
|
|
|
}
|
|
|
|
|
2019-07-26 20:36:20 +02:00
|
|
|
terminalWidth, terminalHeight, err := terminal.GetSize(int(os.Stdout.Fd()))
|
2018-04-20 00:55:24 +02:00
|
|
|
contract.IgnoreError(err)
|
2018-04-24 23:23:08 +02:00
|
|
|
display.isTerminal = opts.IsInteractive
|
2018-04-20 00:55:24 +02:00
|
|
|
display.terminalWidth = terminalWidth
|
2019-07-26 20:36:20 +02:00
|
|
|
display.terminalHeight = terminalHeight
|
2018-04-10 21:03:11 +02:00
|
|
|
|
|
|
|
go func() {
|
2018-04-12 19:56:39 +02:00
|
|
|
display.processEvents(ticker, events)
|
2018-04-10 21:03:11 +02:00
|
|
|
|
2018-04-12 19:56:39 +02:00
|
|
|
// no more progress events from this point on. By closing the pipe, this will then cause
|
|
|
|
// DisplayJSONMessagesToStream to finish once it processes the last message is receives from
|
|
|
|
// pipeReader, causing DisplayEvents to finally complete.
|
2018-04-20 00:55:24 +02:00
|
|
|
close(progressOutput)
|
2018-04-12 19:56:39 +02:00
|
|
|
}()
|
2018-04-10 21:03:11 +02:00
|
|
|
|
Make a smattering of CLI UX improvements
Since I was digging around over the weekend after the change to move
away from light black, and the impact it had on less important
information showing more prominently than it used to, I took a step
back and did a deeper tidying up of things. Another side goal of this
exercise was to be a little more respectful of terminal width; when
we could say things with fewer words, I did so.
* Stylize the preview/update summary differently, so that it stands
out as a section. Also highlight the total changes with bold -- it
turns out this has a similar effect to the bright white colorization,
just without the negative effects on e.g. white terminals.
* Eliminate some verbosity in the phrasing of change summaries.
* Make all heading sections stylized consistently. This includes
the color (bright magenta) and the vertical spacing (always a newline
separating headings). We were previously inconsistent on this (e.g.,
outputs were under "---outputs---"). Now the headings are:
Previewing (etc), Diagnostics, Outputs, Resources, Duration, and Permalink.
* Fix an issue where we'd parent things to "global" until the stack
object later showed up. Now we'll simply mock up a stack resource.
* Don't show messages like "no change" or "unchanged". Prior to the
light black removal, these faded into the background of the terminal.
Now they just clutter up the display. Similar to the elision of "*"
for OpSames in a prior commit, just leave these out. Now anything
that's written is actually a meaningful status for the user to note.
* Don't show the "3 info messages," etc. summaries in the Info column
while an update is ongoing. Instead, just show the latest line. This
is more respectful of width -- I often find that the important
messages scroll off the right of my screen before this change.
For discussion:
- I actually wonder if we should eliminate the summary
altogether and always just show the latest line. Or even
blank it out. The summary feels better suited for the
Diagnostics section, and the Status concisely tells us
how a resource's update ended up (failed, succeeded, etc).
- Similarly, I question the idea of showing only the "worst"
message. I'd vote for always showing the latest, and again
leaving it to the Status column for concisely telling the
user about the final state a resource ended up in.
* Stop prepending "info: " to every stdout/stderr message. It adds
no value, clutters up the display, and worsens horizontal usage.
* Lessen the verbosity of update headline messages, so we now instead
of e.g. "Previewing update of stack 'x':", we just say
"Previewing update (x):".
* Eliminate vertical whitespace in the Diagnostics section. Every
independent console.out previously was separated by an entire newline,
which made the section look cluttered to my eyes. These are just
streams of logs, there's no reason for the extra newlines.
* Colorize the resource headers in the Diagnostic section light blue.
Note that this will change various test baselines, which I will
update next. I didn't want those in the same commit.
2018-09-24 17:31:19 +02:00
|
|
|
_, stdout, _ := term.StdStreams()
|
2018-09-05 17:25:23 +02:00
|
|
|
ShowProgressOutput(progressOutput, stdout, display.isTerminal)
|
2018-04-10 21:03:11 +02:00
|
|
|
|
2018-04-12 19:56:39 +02:00
|
|
|
ticker.Stop()
|
2018-04-10 21:03:11 +02:00
|
|
|
|
2018-04-12 19:56:39 +02:00
|
|
|
// let our caller know we're done.
|
2018-12-14 04:58:26 +01:00
|
|
|
close(done)
|
2018-04-12 19:56:39 +02:00
|
|
|
}
|
2018-04-10 21:03:11 +02:00
|
|
|
|
2018-04-12 19:56:39 +02:00
|
|
|
// Gets the padding necessary to prepend to a message in order to keep it aligned in the
|
|
|
|
// terminal.
|
2018-04-23 03:10:19 +02:00
|
|
|
func (display *ProgressDisplay) getMessagePadding(
|
2018-04-24 20:13:22 +02:00
|
|
|
uncolorizedColumns []string, columnIndex int, maxColumnLengths []int) string {
|
2018-04-23 03:10:19 +02:00
|
|
|
|
2018-04-15 21:47:53 +02:00
|
|
|
extraWhitespace := 1
|
2018-04-12 19:56:39 +02:00
|
|
|
|
|
|
|
// In the terminal we try to align the status messages for each resource.
|
|
|
|
// do not bother with this in the non-terminal case.
|
2018-04-24 20:13:22 +02:00
|
|
|
if columnIndex >= 0 && display.isTerminal {
|
|
|
|
column := uncolorizedColumns[columnIndex]
|
|
|
|
maxLength := maxColumnLengths[columnIndex]
|
2018-04-23 03:10:19 +02:00
|
|
|
|
2018-04-24 20:13:22 +02:00
|
|
|
extraWhitespace = maxLength - utf8.RuneCountInString(column)
|
|
|
|
contract.Assertf(extraWhitespace >= 0, "Neg whitespace. %v %s", maxLength, column)
|
2018-04-15 21:47:53 +02:00
|
|
|
|
2018-04-23 03:10:19 +02:00
|
|
|
// Place two spaces between all columns (except after the first column). The first
|
|
|
|
// column already has a ": " so it doesn't need the extra space.
|
|
|
|
if columnIndex >= 0 {
|
2018-04-17 08:41:00 +02:00
|
|
|
extraWhitespace += 2
|
2018-04-15 21:47:53 +02:00
|
|
|
}
|
2018-04-12 19:56:39 +02:00
|
|
|
}
|
2018-04-10 21:03:11 +02:00
|
|
|
|
2018-04-12 19:56:39 +02:00
|
|
|
return strings.Repeat(" ", extraWhitespace)
|
|
|
|
}
|
2018-04-10 21:03:11 +02:00
|
|
|
|
2018-04-12 19:56:39 +02:00
|
|
|
// Gets the fully padded message to be shown. The message will always include the ID of the
|
|
|
|
// status, then some amount of optional padding, then some amount of msgWithColors, then the
|
|
|
|
// suffix. Importantly, if there isn't enough room to display all of that on the terminal, then
|
|
|
|
// the msg will be truncated to try to make it fit.
|
2018-04-15 21:47:53 +02:00
|
|
|
func (display *ProgressDisplay) getPaddedMessage(
|
2018-04-24 20:13:22 +02:00
|
|
|
colorizedColumns, uncolorizedColumns []string, maxColumnLengths []int) string {
|
2018-04-15 21:47:53 +02:00
|
|
|
|
|
|
|
colorizedMessage := ""
|
|
|
|
|
2018-04-23 03:10:19 +02:00
|
|
|
for i := 0; i < len(colorizedColumns); i++ {
|
2018-04-24 20:13:22 +02:00
|
|
|
padding := display.getMessagePadding(uncolorizedColumns, i-1, maxColumnLengths)
|
2018-04-17 08:41:00 +02:00
|
|
|
colorizedMessage += padding + colorizedColumns[i]
|
2018-04-15 21:47:53 +02:00
|
|
|
}
|
2018-04-12 19:56:39 +02:00
|
|
|
|
|
|
|
if display.isTerminal {
|
|
|
|
// Ensure we don't go past the end of the terminal. Note: this is made complex due to
|
|
|
|
// msgWithColors having the color code information embedded with it. So we need to get
|
|
|
|
// the right substring of it, assuming that embedded colors are just markup and do not
|
|
|
|
// actually contribute to the length
|
2018-04-24 20:13:22 +02:00
|
|
|
maxMsgLength := display.terminalWidth - 1
|
2018-04-12 19:56:39 +02:00
|
|
|
if maxMsgLength < 0 {
|
|
|
|
maxMsgLength = 0
|
2018-04-10 21:03:11 +02:00
|
|
|
}
|
|
|
|
|
2018-04-15 21:47:53 +02:00
|
|
|
colorizedMessage = colors.TrimColorizedString(colorizedMessage, maxMsgLength)
|
2018-04-10 21:03:11 +02:00
|
|
|
}
|
|
|
|
|
2018-04-17 08:41:00 +02:00
|
|
|
return colorizedMessage
|
2018-04-12 19:56:39 +02:00
|
|
|
}
|
2018-04-10 21:03:11 +02:00
|
|
|
|
2018-04-19 21:31:47 +02:00
|
|
|
func (display *ProgressDisplay) uncolorizeString(v string) string {
|
|
|
|
uncolorized, has := display.colorizedToUncolorized[v]
|
|
|
|
if !has {
|
|
|
|
uncolorized = colors.Never.Colorize(v)
|
|
|
|
display.colorizedToUncolorized[v] = uncolorized
|
|
|
|
}
|
|
|
|
|
|
|
|
return uncolorized
|
|
|
|
}
|
|
|
|
|
|
|
|
func (display *ProgressDisplay) uncolorizeColumns(columns []string) []string {
|
2018-04-17 08:41:00 +02:00
|
|
|
uncolorizedColumns := make([]string, len(columns))
|
|
|
|
|
|
|
|
for i, v := range columns {
|
2018-04-19 21:31:47 +02:00
|
|
|
uncolorizedColumns[i] = display.uncolorizeString(v)
|
2018-04-17 08:41:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return uncolorizedColumns
|
|
|
|
}
|
|
|
|
|
2018-04-24 20:13:22 +02:00
|
|
|
func (display *ProgressDisplay) refreshSingleRow(id string, row Row, maxColumnLengths []int) {
|
2018-04-19 21:31:47 +02:00
|
|
|
colorizedColumns := row.ColorizedColumns()
|
2018-04-17 08:41:00 +02:00
|
|
|
colorizedColumns[display.suffixColumn] += row.ColorizedSuffix()
|
2018-04-24 20:13:22 +02:00
|
|
|
display.refreshColumns(id, colorizedColumns, maxColumnLengths)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (display *ProgressDisplay) refreshColumns(
|
|
|
|
id string, colorizedColumns []string, maxColumnLengths []int) {
|
2018-04-17 08:41:00 +02:00
|
|
|
|
2018-04-19 21:31:47 +02:00
|
|
|
uncolorizedColumns := display.uncolorizeColumns(colorizedColumns)
|
2018-04-17 08:41:00 +02:00
|
|
|
|
2018-04-24 20:13:22 +02:00
|
|
|
msg := display.getPaddedMessage(colorizedColumns, uncolorizedColumns, maxColumnLengths)
|
2018-04-10 21:03:11 +02:00
|
|
|
|
2018-04-23 03:10:19 +02:00
|
|
|
if display.isTerminal {
|
2018-04-24 20:13:22 +02:00
|
|
|
display.colorizeAndWriteProgress(makeActionProgress(id, msg))
|
2018-04-23 03:10:19 +02:00
|
|
|
} else {
|
|
|
|
display.writeSimpleMessage(msg)
|
|
|
|
}
|
2018-04-15 21:47:53 +02:00
|
|
|
}
|
2018-04-12 19:56:39 +02:00
|
|
|
|
2018-04-24 20:13:22 +02:00
|
|
|
// Ensure our stored dimension info is up to date.
|
2019-07-26 20:36:20 +02:00
|
|
|
func (display *ProgressDisplay) updateTerminalDimensions() {
|
2018-04-15 21:47:53 +02:00
|
|
|
// don't do any refreshing if we're not in a terminal
|
|
|
|
if display.isTerminal {
|
2019-07-26 20:36:20 +02:00
|
|
|
currentTerminalWidth, currentTerminalHeight, err := terminal.GetSize(int(os.Stdout.Fd()))
|
2018-04-15 21:47:53 +02:00
|
|
|
contract.IgnoreError(err)
|
2018-04-12 19:56:39 +02:00
|
|
|
|
2019-07-26 20:36:20 +02:00
|
|
|
if currentTerminalWidth != display.terminalWidth ||
|
|
|
|
currentTerminalHeight != display.terminalHeight {
|
2018-04-15 21:47:53 +02:00
|
|
|
display.terminalWidth = currentTerminalWidth
|
2019-07-26 20:36:20 +02:00
|
|
|
display.terminalHeight = currentTerminalHeight
|
2018-04-24 20:13:22 +02:00
|
|
|
|
|
|
|
// also clear our display cache as we want to reprint all lines.
|
|
|
|
display.printedProgressCache = make(map[string]Progress)
|
2018-04-10 21:03:11 +02:00
|
|
|
}
|
2018-04-24 20:13:22 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type treeNode struct {
|
|
|
|
row Row
|
|
|
|
|
|
|
|
colorizedColumns []string
|
|
|
|
colorizedSuffix string
|
|
|
|
|
|
|
|
childNodes []*treeNode
|
|
|
|
}
|
|
|
|
|
|
|
|
func (display *ProgressDisplay) getOrCreateTreeNode(
|
|
|
|
result *[]*treeNode, urn resource.URN, row ResourceRow, urnToTreeNode map[resource.URN]*treeNode) *treeNode {
|
|
|
|
|
|
|
|
node, has := urnToTreeNode[urn]
|
|
|
|
if has {
|
|
|
|
return node
|
|
|
|
}
|
|
|
|
|
|
|
|
node = &treeNode{
|
|
|
|
row: row,
|
|
|
|
colorizedColumns: row.ColorizedColumns(),
|
|
|
|
colorizedSuffix: row.ColorizedSuffix(),
|
|
|
|
}
|
|
|
|
|
|
|
|
urnToTreeNode[urn] = node
|
|
|
|
|
2018-06-19 01:03:26 +02:00
|
|
|
// if it's the not the root item, attach it as a child node to an appropriate parent item.
|
2018-04-24 20:13:22 +02:00
|
|
|
if urn != "" && urn != display.stackUrn {
|
|
|
|
var parentURN resource.URN
|
|
|
|
|
|
|
|
res := row.Step().Res
|
|
|
|
if res != nil {
|
|
|
|
parentURN = res.Parent
|
|
|
|
}
|
|
|
|
|
|
|
|
parentRow, hasParentRow := display.eventUrnToResourceRow[parentURN]
|
2018-06-19 01:03:26 +02:00
|
|
|
|
2018-04-24 20:13:22 +02:00
|
|
|
if !hasParentRow {
|
2018-06-19 01:03:26 +02:00
|
|
|
// If we haven't heard about this node's parent, then just parent it to the stack.
|
|
|
|
// Note: getting the parent row for the stack-urn will always succeed as we ensure that
|
|
|
|
// such a row is always there in ensureHeaderAndStackRows
|
2018-04-24 20:13:22 +02:00
|
|
|
parentURN = display.stackUrn
|
2018-06-19 01:03:26 +02:00
|
|
|
parentRow = display.eventUrnToResourceRow[parentURN]
|
2018-04-24 20:13:22 +02:00
|
|
|
}
|
|
|
|
|
2018-06-19 01:03:26 +02:00
|
|
|
parentNode := display.getOrCreateTreeNode(result, parentURN, parentRow, urnToTreeNode)
|
|
|
|
parentNode.childNodes = append(parentNode.childNodes, node)
|
|
|
|
return node
|
2018-04-24 20:13:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
*result = append(*result, node)
|
|
|
|
return node
|
|
|
|
}
|
|
|
|
|
|
|
|
func (display *ProgressDisplay) generateTreeNodes() []*treeNode {
|
|
|
|
result := []*treeNode{}
|
|
|
|
|
|
|
|
result = append(result, &treeNode{
|
|
|
|
row: display.headerRow,
|
|
|
|
colorizedColumns: display.headerRow.ColorizedColumns(),
|
|
|
|
})
|
2018-04-10 21:03:11 +02:00
|
|
|
|
2018-04-24 20:13:22 +02:00
|
|
|
urnToTreeNode := make(map[resource.URN]*treeNode)
|
|
|
|
for urn, row := range display.eventUrnToResourceRow {
|
|
|
|
display.getOrCreateTreeNode(&result, urn, row, urnToTreeNode)
|
|
|
|
}
|
|
|
|
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
|
|
|
func (display *ProgressDisplay) addIndentations(treeNodes []*treeNode, isRoot bool, indentation string) {
|
|
|
|
|
|
|
|
childIndentation := indentation + "│ "
|
|
|
|
lastChildIndentation := indentation + " "
|
2018-04-12 19:56:39 +02:00
|
|
|
|
2018-04-24 20:13:22 +02:00
|
|
|
for i, node := range treeNodes {
|
|
|
|
isLast := i == len(treeNodes)-1
|
|
|
|
|
|
|
|
prefix := indentation
|
|
|
|
|
|
|
|
var nestedIndentation string
|
|
|
|
if !isRoot {
|
|
|
|
if isLast {
|
|
|
|
prefix += "└─ "
|
|
|
|
nestedIndentation = lastChildIndentation
|
|
|
|
} else {
|
|
|
|
prefix += "├─ "
|
|
|
|
nestedIndentation = childIndentation
|
2018-04-15 21:47:53 +02:00
|
|
|
}
|
2018-04-24 20:13:22 +02:00
|
|
|
}
|
2018-04-12 19:56:39 +02:00
|
|
|
|
2018-04-24 20:13:22 +02:00
|
|
|
node.colorizedColumns[typeColumn] = prefix + node.colorizedColumns[typeColumn]
|
|
|
|
display.addIndentations(node.childNodes, false /*isRoot*/, nestedIndentation)
|
|
|
|
}
|
|
|
|
}
|
2018-04-17 08:41:00 +02:00
|
|
|
|
2018-04-24 20:13:22 +02:00
|
|
|
func (display *ProgressDisplay) convertNodesToRows(
|
|
|
|
nodes []*treeNode, maxSuffixLength int, rows *[][]string, maxColumnLengths *[]int) {
|
|
|
|
|
|
|
|
for _, node := range nodes {
|
|
|
|
if len(*maxColumnLengths) == 0 {
|
|
|
|
*maxColumnLengths = make([]int, len(node.colorizedColumns))
|
|
|
|
}
|
|
|
|
|
|
|
|
colorizedColumns := make([]string, len(node.colorizedColumns))
|
|
|
|
uncolorisedColumns := display.uncolorizeColumns(node.colorizedColumns)
|
|
|
|
|
|
|
|
for i, colorizedColumn := range node.colorizedColumns {
|
|
|
|
columnWidth := utf8.RuneCountInString(uncolorisedColumns[i])
|
|
|
|
|
|
|
|
if i == display.suffixColumn {
|
|
|
|
columnWidth += maxSuffixLength
|
|
|
|
colorizedColumns[i] = colorizedColumn + node.colorizedSuffix
|
|
|
|
} else {
|
|
|
|
colorizedColumns[i] = colorizedColumn
|
|
|
|
}
|
|
|
|
|
|
|
|
if columnWidth > (*maxColumnLengths)[i] {
|
|
|
|
(*maxColumnLengths)[i] = columnWidth
|
2018-04-15 21:47:53 +02:00
|
|
|
}
|
|
|
|
}
|
2018-04-24 20:13:22 +02:00
|
|
|
|
|
|
|
*rows = append(*rows, colorizedColumns)
|
|
|
|
|
|
|
|
display.convertNodesToRows(node.childNodes, maxSuffixLength, rows, maxColumnLengths)
|
2018-04-12 19:56:39 +02:00
|
|
|
}
|
2018-04-23 03:10:19 +02:00
|
|
|
}
|
|
|
|
|
2018-04-24 20:13:22 +02:00
|
|
|
type sortable []*treeNode
|
|
|
|
|
|
|
|
func (sortable sortable) Len() int {
|
|
|
|
return len(sortable)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (sortable sortable) Less(i, j int) bool {
|
|
|
|
return sortable[i].row.DisplayOrderIndex() < sortable[j].row.DisplayOrderIndex()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (sortable sortable) Swap(i, j int) {
|
|
|
|
sortable[i], sortable[j] = sortable[j], sortable[i]
|
|
|
|
}
|
|
|
|
|
|
|
|
func sortNodes(nodes []*treeNode) {
|
|
|
|
sort.Sort(sortable(nodes))
|
|
|
|
|
|
|
|
for _, node := range nodes {
|
|
|
|
childNodes := node.childNodes
|
|
|
|
sortNodes(childNodes)
|
|
|
|
node.childNodes = childNodes
|
2018-04-23 03:10:19 +02:00
|
|
|
}
|
2018-04-24 20:13:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func (display *ProgressDisplay) filterOutUnnecessaryNodesAndSetDisplayTimes(nodes []*treeNode) []*treeNode {
|
|
|
|
result := []*treeNode{}
|
|
|
|
|
|
|
|
for _, node := range nodes {
|
|
|
|
node.childNodes = display.filterOutUnnecessaryNodesAndSetDisplayTimes(node.childNodes)
|
|
|
|
|
|
|
|
if node.row.HideRowIfUnnecessary() && len(node.childNodes) == 0 {
|
|
|
|
continue
|
|
|
|
}
|
2018-04-12 19:56:39 +02:00
|
|
|
|
2018-04-24 20:13:22 +02:00
|
|
|
display.displayOrderCounter++
|
|
|
|
node.row.SetDisplayOrderIndex(display.displayOrderCounter)
|
|
|
|
result = append(result, node)
|
2018-04-23 03:10:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return result
|
2018-04-12 19:56:39 +02:00
|
|
|
}
|
2018-04-10 21:03:11 +02:00
|
|
|
|
2018-04-15 21:47:53 +02:00
|
|
|
func (display *ProgressDisplay) refreshAllRowsIfInTerminal() {
|
2018-04-23 03:10:19 +02:00
|
|
|
if display.isTerminal && display.headerRow != nil {
|
2018-04-15 21:47:53 +02:00
|
|
|
// make sure our stored dimension info is up to date
|
2019-07-26 20:36:20 +02:00
|
|
|
display.updateTerminalDimensions()
|
2018-04-24 20:13:22 +02:00
|
|
|
|
|
|
|
rootNodes := display.generateTreeNodes()
|
|
|
|
rootNodes = display.filterOutUnnecessaryNodesAndSetDisplayTimes(rootNodes)
|
|
|
|
sortNodes(rootNodes)
|
|
|
|
display.addIndentations(rootNodes, true /*isRoot*/, "")
|
|
|
|
|
|
|
|
maxSuffixLength := 0
|
|
|
|
for _, v := range display.suffixesArray {
|
|
|
|
runeCount := utf8.RuneCountInString(v)
|
|
|
|
if runeCount > maxSuffixLength {
|
|
|
|
maxSuffixLength = runeCount
|
|
|
|
}
|
|
|
|
}
|
2018-04-12 19:56:39 +02:00
|
|
|
|
2018-04-24 20:13:22 +02:00
|
|
|
var rows [][]string
|
|
|
|
var maxColumnLengths []int
|
|
|
|
display.convertNodesToRows(rootNodes, maxSuffixLength, &rows, &maxColumnLengths)
|
2018-04-23 03:10:19 +02:00
|
|
|
|
2018-10-05 22:03:30 +02:00
|
|
|
removeInfoColumnIfUnneeded(rows)
|
2018-04-23 03:10:19 +02:00
|
|
|
|
2018-10-05 22:03:30 +02:00
|
|
|
for i, row := range rows {
|
|
|
|
display.refreshColumns(fmt.Sprintf("%v", i), row, maxColumnLengths)
|
2018-04-15 21:47:53 +02:00
|
|
|
}
|
2018-04-19 23:44:53 +02:00
|
|
|
|
2018-04-23 03:10:19 +02:00
|
|
|
systemID := len(rows)
|
2018-04-19 23:44:53 +02:00
|
|
|
|
|
|
|
printedHeader := false
|
|
|
|
for _, payload := range display.systemEventPayloads {
|
|
|
|
msg := payload.Color.Colorize(payload.Message)
|
|
|
|
lines := splitIntoDisplayableLines(msg)
|
|
|
|
|
|
|
|
if len(lines) == 0 {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
if !printedHeader {
|
|
|
|
printedHeader = true
|
2018-04-20 00:55:24 +02:00
|
|
|
display.colorizeAndWriteProgress(makeActionProgress(
|
2018-04-24 20:13:22 +02:00
|
|
|
fmt.Sprintf("%v", systemID), " "))
|
2018-04-19 23:44:53 +02:00
|
|
|
systemID++
|
|
|
|
|
2018-04-20 00:55:24 +02:00
|
|
|
display.colorizeAndWriteProgress(makeActionProgress(
|
|
|
|
fmt.Sprintf("%v", systemID),
|
2018-04-24 20:13:22 +02:00
|
|
|
colors.Yellow+"System Messages"+colors.Reset))
|
2018-04-19 23:44:53 +02:00
|
|
|
systemID++
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, line := range lines {
|
2018-04-20 00:55:24 +02:00
|
|
|
display.colorizeAndWriteProgress(makeActionProgress(
|
2018-04-24 20:13:22 +02:00
|
|
|
fmt.Sprintf("%v", systemID), fmt.Sprintf(" %s", line)))
|
2018-04-19 23:44:53 +02:00
|
|
|
systemID++
|
|
|
|
}
|
|
|
|
}
|
2018-04-10 21:03:11 +02:00
|
|
|
}
|
2018-04-12 19:56:39 +02:00
|
|
|
}
|
2018-04-10 21:03:11 +02:00
|
|
|
|
2018-10-05 22:03:30 +02:00
|
|
|
func removeInfoColumnIfUnneeded(rows [][]string) {
|
|
|
|
// If there have been no info messages, then don't print out the info column header.
|
|
|
|
for i := 1; i < len(rows); i++ {
|
|
|
|
row := rows[i]
|
|
|
|
if row[len(row)-1] != "" {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
firstRow := rows[0]
|
|
|
|
firstRow[len(firstRow)-1] = ""
|
|
|
|
}
|
|
|
|
|
2018-04-12 19:56:39 +02:00
|
|
|
// Performs all the work at the end once we've heard about the last message from the engine.
|
|
|
|
// Specifically, this will update the status messages for any resources, and will also then
|
|
|
|
// print out all final diagnostics. and finally will print out the summary.
|
|
|
|
func (display *ProgressDisplay) processEndSteps() {
|
2018-08-02 06:48:14 +02:00
|
|
|
// Figure out the rows that are currently in progress.
|
|
|
|
inProgressRows := []ResourceRow{}
|
2018-04-14 07:26:01 +02:00
|
|
|
|
2018-04-15 21:47:53 +02:00
|
|
|
for _, v := range display.eventUrnToResourceRow {
|
2018-08-02 06:48:14 +02:00
|
|
|
if !v.IsDone() {
|
|
|
|
inProgressRows = append(inProgressRows, v)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// transition the display to the 'done' state. this will transitively cause all
|
|
|
|
// rows to become done.
|
|
|
|
display.done = true
|
|
|
|
|
|
|
|
// Now print out all those rows that were in progress. They will now be 'done'
|
|
|
|
// since the display was marked 'done'.
|
|
|
|
if !display.isTerminal {
|
|
|
|
for _, v := range inProgressRows {
|
|
|
|
display.refreshSingleRow("", v, nil)
|
2018-04-10 21:03:11 +02:00
|
|
|
}
|
2018-04-12 19:56:39 +02:00
|
|
|
}
|
2018-04-10 21:03:11 +02:00
|
|
|
|
2018-04-15 21:47:53 +02:00
|
|
|
// Now refresh everything. this ensures that we go back and remove things like the diagnostic
|
|
|
|
// messages from a status message (since we're going to print them all) below. Note, this will
|
|
|
|
// only do something in a terminal. This i what we want, because if we're not in a terminal we
|
|
|
|
// don't really want to reprint any finished items we've already printed.
|
|
|
|
display.refreshAllRowsIfInTerminal()
|
2018-04-14 07:26:01 +02:00
|
|
|
|
2018-04-12 19:56:39 +02:00
|
|
|
// Print all diagnostics we've seen.
|
|
|
|
|
2018-04-14 07:26:01 +02:00
|
|
|
wroteDiagnosticHeader := false
|
|
|
|
|
2018-04-15 21:47:53 +02:00
|
|
|
for _, row := range display.eventUrnToResourceRow {
|
2018-09-25 19:58:22 +02:00
|
|
|
wroteResourceHeader := false
|
|
|
|
|
2018-05-08 00:11:52 +02:00
|
|
|
for id, payloads := range row.DiagInfo().StreamIDToDiagPayloads {
|
|
|
|
if len(payloads) > 0 {
|
|
|
|
if id != 0 {
|
|
|
|
// for the non-default stream merge all the messages from the stream into a single
|
|
|
|
// message.
|
|
|
|
p := display.mergeStreamPayloadsToSinglePayload(payloads)
|
|
|
|
payloads = []engine.DiagEventPayload{p}
|
2018-04-14 07:26:01 +02:00
|
|
|
}
|
2018-04-10 21:03:11 +02:00
|
|
|
|
Make a smattering of CLI UX improvements
Since I was digging around over the weekend after the change to move
away from light black, and the impact it had on less important
information showing more prominently than it used to, I took a step
back and did a deeper tidying up of things. Another side goal of this
exercise was to be a little more respectful of terminal width; when
we could say things with fewer words, I did so.
* Stylize the preview/update summary differently, so that it stands
out as a section. Also highlight the total changes with bold -- it
turns out this has a similar effect to the bright white colorization,
just without the negative effects on e.g. white terminals.
* Eliminate some verbosity in the phrasing of change summaries.
* Make all heading sections stylized consistently. This includes
the color (bright magenta) and the vertical spacing (always a newline
separating headings). We were previously inconsistent on this (e.g.,
outputs were under "---outputs---"). Now the headings are:
Previewing (etc), Diagnostics, Outputs, Resources, Duration, and Permalink.
* Fix an issue where we'd parent things to "global" until the stack
object later showed up. Now we'll simply mock up a stack resource.
* Don't show messages like "no change" or "unchanged". Prior to the
light black removal, these faded into the background of the terminal.
Now they just clutter up the display. Similar to the elision of "*"
for OpSames in a prior commit, just leave these out. Now anything
that's written is actually a meaningful status for the user to note.
* Don't show the "3 info messages," etc. summaries in the Info column
while an update is ongoing. Instead, just show the latest line. This
is more respectful of width -- I often find that the important
messages scroll off the right of my screen before this change.
For discussion:
- I actually wonder if we should eliminate the summary
altogether and always just show the latest line. Or even
blank it out. The summary feels better suited for the
Diagnostics section, and the Status concisely tells us
how a resource's update ended up (failed, succeeded, etc).
- Similarly, I question the idea of showing only the "worst"
message. I'd vote for always showing the latest, and again
leaving it to the Status column for concisely telling the
user about the final state a resource ended up in.
* Stop prepending "info: " to every stdout/stderr message. It adds
no value, clutters up the display, and worsens horizontal usage.
* Lessen the verbosity of update headline messages, so we now instead
of e.g. "Previewing update of stack 'x':", we just say
"Previewing update (x):".
* Eliminate vertical whitespace in the Diagnostics section. Every
independent console.out previously was separated by an entire newline,
which made the section look cluttered to my eyes. These are just
streams of logs, there's no reason for the extra newlines.
* Colorize the resource headers in the Diagnostic section light blue.
Note that this will change various test baselines, which I will
update next. I didn't want those in the same commit.
2018-09-24 17:31:19 +02:00
|
|
|
wrote := false
|
2018-05-08 00:11:52 +02:00
|
|
|
for _, v := range payloads {
|
Implement status sinks
This commit reverts most of #1853 and replaces it with functionally
identical logic, using the notion of status message-specific sinks.
In other words, where the original commit implemented ephemeral status
messages by adding an `isStatus` parameter to most of the logging
methdos in pulumi/pulumi, this implements ephemeral status messages as a
parallel logging sink, which emits _only_ ephemeral status messages.
The original commit message in that PR was:
> Allow log events to be marked "status" events
>
> This commit will introduce a field, IsStatus to LogRequest. A "status"
> logging event will be displayed in the Info column of the main
> display, but will not be printed out at the end, when resource
> operations complete.
>
> For example, for complex resource initialization, we'd like to display
> a series of intermediate results: [1/4] Service object created, for
> example. We'd like these to appear in the Info column, but not at the
> end, where they are not helpful to the user.
2018-08-31 22:12:40 +02:00
|
|
|
if v.Ephemeral {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2018-05-08 00:11:52 +02:00
|
|
|
msg := display.renderProgressDiagEvent(v, true /*includePrefix:*/)
|
|
|
|
|
|
|
|
lines := splitIntoDisplayableLines(msg)
|
|
|
|
if len(lines) == 0 {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
if !wroteDiagnosticHeader {
|
|
|
|
wroteDiagnosticHeader = true
|
|
|
|
display.writeBlankLine()
|
Make a smattering of CLI UX improvements
Since I was digging around over the weekend after the change to move
away from light black, and the impact it had on less important
information showing more prominently than it used to, I took a step
back and did a deeper tidying up of things. Another side goal of this
exercise was to be a little more respectful of terminal width; when
we could say things with fewer words, I did so.
* Stylize the preview/update summary differently, so that it stands
out as a section. Also highlight the total changes with bold -- it
turns out this has a similar effect to the bright white colorization,
just without the negative effects on e.g. white terminals.
* Eliminate some verbosity in the phrasing of change summaries.
* Make all heading sections stylized consistently. This includes
the color (bright magenta) and the vertical spacing (always a newline
separating headings). We were previously inconsistent on this (e.g.,
outputs were under "---outputs---"). Now the headings are:
Previewing (etc), Diagnostics, Outputs, Resources, Duration, and Permalink.
* Fix an issue where we'd parent things to "global" until the stack
object later showed up. Now we'll simply mock up a stack resource.
* Don't show messages like "no change" or "unchanged". Prior to the
light black removal, these faded into the background of the terminal.
Now they just clutter up the display. Similar to the elision of "*"
for OpSames in a prior commit, just leave these out. Now anything
that's written is actually a meaningful status for the user to note.
* Don't show the "3 info messages," etc. summaries in the Info column
while an update is ongoing. Instead, just show the latest line. This
is more respectful of width -- I often find that the important
messages scroll off the right of my screen before this change.
For discussion:
- I actually wonder if we should eliminate the summary
altogether and always just show the latest line. Or even
blank it out. The summary feels better suited for the
Diagnostics section, and the Status concisely tells us
how a resource's update ended up (failed, succeeded, etc).
- Similarly, I question the idea of showing only the "worst"
message. I'd vote for always showing the latest, and again
leaving it to the Status column for concisely telling the
user about the final state a resource ended up in.
* Stop prepending "info: " to every stdout/stderr message. It adds
no value, clutters up the display, and worsens horizontal usage.
* Lessen the verbosity of update headline messages, so we now instead
of e.g. "Previewing update of stack 'x':", we just say
"Previewing update (x):".
* Eliminate vertical whitespace in the Diagnostics section. Every
independent console.out previously was separated by an entire newline,
which made the section look cluttered to my eyes. These are just
streams of logs, there's no reason for the extra newlines.
* Colorize the resource headers in the Diagnostic section light blue.
Note that this will change various test baselines, which I will
update next. I didn't want those in the same commit.
2018-09-24 17:31:19 +02:00
|
|
|
display.writeSimpleMessage(
|
|
|
|
display.opts.Color.Colorize(colors.SpecHeadline + "Diagnostics:" + colors.Reset))
|
2018-05-08 00:11:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if !wroteResourceHeader {
|
|
|
|
wroteResourceHeader = true
|
|
|
|
columns := row.ColorizedColumns()
|
|
|
|
display.writeSimpleMessage(" " +
|
Make a smattering of CLI UX improvements
Since I was digging around over the weekend after the change to move
away from light black, and the impact it had on less important
information showing more prominently than it used to, I took a step
back and did a deeper tidying up of things. Another side goal of this
exercise was to be a little more respectful of terminal width; when
we could say things with fewer words, I did so.
* Stylize the preview/update summary differently, so that it stands
out as a section. Also highlight the total changes with bold -- it
turns out this has a similar effect to the bright white colorization,
just without the negative effects on e.g. white terminals.
* Eliminate some verbosity in the phrasing of change summaries.
* Make all heading sections stylized consistently. This includes
the color (bright magenta) and the vertical spacing (always a newline
separating headings). We were previously inconsistent on this (e.g.,
outputs were under "---outputs---"). Now the headings are:
Previewing (etc), Diagnostics, Outputs, Resources, Duration, and Permalink.
* Fix an issue where we'd parent things to "global" until the stack
object later showed up. Now we'll simply mock up a stack resource.
* Don't show messages like "no change" or "unchanged". Prior to the
light black removal, these faded into the background of the terminal.
Now they just clutter up the display. Similar to the elision of "*"
for OpSames in a prior commit, just leave these out. Now anything
that's written is actually a meaningful status for the user to note.
* Don't show the "3 info messages," etc. summaries in the Info column
while an update is ongoing. Instead, just show the latest line. This
is more respectful of width -- I often find that the important
messages scroll off the right of my screen before this change.
For discussion:
- I actually wonder if we should eliminate the summary
altogether and always just show the latest line. Or even
blank it out. The summary feels better suited for the
Diagnostics section, and the Status concisely tells us
how a resource's update ended up (failed, succeeded, etc).
- Similarly, I question the idea of showing only the "worst"
message. I'd vote for always showing the latest, and again
leaving it to the Status column for concisely telling the
user about the final state a resource ended up in.
* Stop prepending "info: " to every stdout/stderr message. It adds
no value, clutters up the display, and worsens horizontal usage.
* Lessen the verbosity of update headline messages, so we now instead
of e.g. "Previewing update of stack 'x':", we just say
"Previewing update (x):".
* Eliminate vertical whitespace in the Diagnostics section. Every
independent console.out previously was separated by an entire newline,
which made the section look cluttered to my eyes. These are just
streams of logs, there's no reason for the extra newlines.
* Colorize the resource headers in the Diagnostic section light blue.
Note that this will change various test baselines, which I will
update next. I didn't want those in the same commit.
2018-09-24 17:31:19 +02:00
|
|
|
display.opts.Color.Colorize(
|
|
|
|
colors.BrightBlue+columns[typeColumn]+" ("+columns[nameColumn]+"):"+colors.Reset))
|
2018-05-08 00:11:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
for _, line := range lines {
|
|
|
|
line = strings.TrimRightFunc(line, unicode.IsSpace)
|
|
|
|
display.writeSimpleMessage(" " + line)
|
|
|
|
}
|
2018-04-14 07:26:01 +02:00
|
|
|
|
Make a smattering of CLI UX improvements
Since I was digging around over the weekend after the change to move
away from light black, and the impact it had on less important
information showing more prominently than it used to, I took a step
back and did a deeper tidying up of things. Another side goal of this
exercise was to be a little more respectful of terminal width; when
we could say things with fewer words, I did so.
* Stylize the preview/update summary differently, so that it stands
out as a section. Also highlight the total changes with bold -- it
turns out this has a similar effect to the bright white colorization,
just without the negative effects on e.g. white terminals.
* Eliminate some verbosity in the phrasing of change summaries.
* Make all heading sections stylized consistently. This includes
the color (bright magenta) and the vertical spacing (always a newline
separating headings). We were previously inconsistent on this (e.g.,
outputs were under "---outputs---"). Now the headings are:
Previewing (etc), Diagnostics, Outputs, Resources, Duration, and Permalink.
* Fix an issue where we'd parent things to "global" until the stack
object later showed up. Now we'll simply mock up a stack resource.
* Don't show messages like "no change" or "unchanged". Prior to the
light black removal, these faded into the background of the terminal.
Now they just clutter up the display. Similar to the elision of "*"
for OpSames in a prior commit, just leave these out. Now anything
that's written is actually a meaningful status for the user to note.
* Don't show the "3 info messages," etc. summaries in the Info column
while an update is ongoing. Instead, just show the latest line. This
is more respectful of width -- I often find that the important
messages scroll off the right of my screen before this change.
For discussion:
- I actually wonder if we should eliminate the summary
altogether and always just show the latest line. Or even
blank it out. The summary feels better suited for the
Diagnostics section, and the Status concisely tells us
how a resource's update ended up (failed, succeeded, etc).
- Similarly, I question the idea of showing only the "worst"
message. I'd vote for always showing the latest, and again
leaving it to the Status column for concisely telling the
user about the final state a resource ended up in.
* Stop prepending "info: " to every stdout/stderr message. It adds
no value, clutters up the display, and worsens horizontal usage.
* Lessen the verbosity of update headline messages, so we now instead
of e.g. "Previewing update of stack 'x':", we just say
"Previewing update (x):".
* Eliminate vertical whitespace in the Diagnostics section. Every
independent console.out previously was separated by an entire newline,
which made the section look cluttered to my eyes. These are just
streams of logs, there's no reason for the extra newlines.
* Colorize the resource headers in the Diagnostic section light blue.
Note that this will change various test baselines, which I will
update next. I didn't want those in the same commit.
2018-09-24 17:31:19 +02:00
|
|
|
wrote = true
|
|
|
|
}
|
|
|
|
|
|
|
|
if wrote {
|
2018-05-08 00:11:52 +02:00
|
|
|
display.writeBlankLine()
|
2018-04-14 07:26:01 +02:00
|
|
|
}
|
2018-04-10 21:03:11 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-12 01:44:06 +02:00
|
|
|
// If we get stack outputs, display them at the end.
|
Make a smattering of CLI UX improvements
Since I was digging around over the weekend after the change to move
away from light black, and the impact it had on less important
information showing more prominently than it used to, I took a step
back and did a deeper tidying up of things. Another side goal of this
exercise was to be a little more respectful of terminal width; when
we could say things with fewer words, I did so.
* Stylize the preview/update summary differently, so that it stands
out as a section. Also highlight the total changes with bold -- it
turns out this has a similar effect to the bright white colorization,
just without the negative effects on e.g. white terminals.
* Eliminate some verbosity in the phrasing of change summaries.
* Make all heading sections stylized consistently. This includes
the color (bright magenta) and the vertical spacing (always a newline
separating headings). We were previously inconsistent on this (e.g.,
outputs were under "---outputs---"). Now the headings are:
Previewing (etc), Diagnostics, Outputs, Resources, Duration, and Permalink.
* Fix an issue where we'd parent things to "global" until the stack
object later showed up. Now we'll simply mock up a stack resource.
* Don't show messages like "no change" or "unchanged". Prior to the
light black removal, these faded into the background of the terminal.
Now they just clutter up the display. Similar to the elision of "*"
for OpSames in a prior commit, just leave these out. Now anything
that's written is actually a meaningful status for the user to note.
* Don't show the "3 info messages," etc. summaries in the Info column
while an update is ongoing. Instead, just show the latest line. This
is more respectful of width -- I often find that the important
messages scroll off the right of my screen before this change.
For discussion:
- I actually wonder if we should eliminate the summary
altogether and always just show the latest line. Or even
blank it out. The summary feels better suited for the
Diagnostics section, and the Status concisely tells us
how a resource's update ended up (failed, succeeded, etc).
- Similarly, I question the idea of showing only the "worst"
message. I'd vote for always showing the latest, and again
leaving it to the Status column for concisely telling the
user about the final state a resource ended up in.
* Stop prepending "info: " to every stdout/stderr message. It adds
no value, clutters up the display, and worsens horizontal usage.
* Lessen the verbosity of update headline messages, so we now instead
of e.g. "Previewing update of stack 'x':", we just say
"Previewing update (x):".
* Eliminate vertical whitespace in the Diagnostics section. Every
independent console.out previously was separated by an entire newline,
which made the section look cluttered to my eyes. These are just
streams of logs, there's no reason for the extra newlines.
* Colorize the resource headers in the Diagnostic section light blue.
Note that this will change various test baselines, which I will
update next. I didn't want those in the same commit.
2018-09-24 17:31:19 +02:00
|
|
|
var wroteOutputs bool
|
2018-10-06 23:13:02 +02:00
|
|
|
if display.stackUrn != "" && display.seenStackOutputs && !display.opts.SuppressOutputs {
|
2018-08-25 00:36:55 +02:00
|
|
|
stackStep := display.eventUrnToResourceRow[display.stackUrn].Step()
|
2018-09-12 01:44:06 +02:00
|
|
|
props := engine.GetResourceOutputsPropertiesString(
|
|
|
|
stackStep, 1, display.isPreview, display.opts.Debug, false /* refresh */)
|
2018-08-25 00:36:55 +02:00
|
|
|
if props != "" {
|
|
|
|
if !wroteDiagnosticHeader {
|
|
|
|
display.writeBlankLine()
|
2018-05-05 21:54:57 +02:00
|
|
|
}
|
2018-08-25 00:36:55 +02:00
|
|
|
|
Make a smattering of CLI UX improvements
Since I was digging around over the weekend after the change to move
away from light black, and the impact it had on less important
information showing more prominently than it used to, I took a step
back and did a deeper tidying up of things. Another side goal of this
exercise was to be a little more respectful of terminal width; when
we could say things with fewer words, I did so.
* Stylize the preview/update summary differently, so that it stands
out as a section. Also highlight the total changes with bold -- it
turns out this has a similar effect to the bright white colorization,
just without the negative effects on e.g. white terminals.
* Eliminate some verbosity in the phrasing of change summaries.
* Make all heading sections stylized consistently. This includes
the color (bright magenta) and the vertical spacing (always a newline
separating headings). We were previously inconsistent on this (e.g.,
outputs were under "---outputs---"). Now the headings are:
Previewing (etc), Diagnostics, Outputs, Resources, Duration, and Permalink.
* Fix an issue where we'd parent things to "global" until the stack
object later showed up. Now we'll simply mock up a stack resource.
* Don't show messages like "no change" or "unchanged". Prior to the
light black removal, these faded into the background of the terminal.
Now they just clutter up the display. Similar to the elision of "*"
for OpSames in a prior commit, just leave these out. Now anything
that's written is actually a meaningful status for the user to note.
* Don't show the "3 info messages," etc. summaries in the Info column
while an update is ongoing. Instead, just show the latest line. This
is more respectful of width -- I often find that the important
messages scroll off the right of my screen before this change.
For discussion:
- I actually wonder if we should eliminate the summary
altogether and always just show the latest line. Or even
blank it out. The summary feels better suited for the
Diagnostics section, and the Status concisely tells us
how a resource's update ended up (failed, succeeded, etc).
- Similarly, I question the idea of showing only the "worst"
message. I'd vote for always showing the latest, and again
leaving it to the Status column for concisely telling the
user about the final state a resource ended up in.
* Stop prepending "info: " to every stdout/stderr message. It adds
no value, clutters up the display, and worsens horizontal usage.
* Lessen the verbosity of update headline messages, so we now instead
of e.g. "Previewing update of stack 'x':", we just say
"Previewing update (x):".
* Eliminate vertical whitespace in the Diagnostics section. Every
independent console.out previously was separated by an entire newline,
which made the section look cluttered to my eyes. These are just
streams of logs, there's no reason for the extra newlines.
* Colorize the resource headers in the Diagnostic section light blue.
Note that this will change various test baselines, which I will
update next. I didn't want those in the same commit.
2018-09-24 17:31:19 +02:00
|
|
|
wroteOutputs = true
|
2018-10-03 22:06:20 +02:00
|
|
|
display.writeSimpleMessage(colors.SpecHeadline + "Outputs:" + colors.Reset)
|
2018-08-25 00:36:55 +02:00
|
|
|
display.writeSimpleMessage(props)
|
2018-05-05 21:54:57 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-12 19:56:39 +02:00
|
|
|
// print the summary
|
2018-04-19 23:44:53 +02:00
|
|
|
if display.summaryEventPayload != nil {
|
Make a smattering of CLI UX improvements
Since I was digging around over the weekend after the change to move
away from light black, and the impact it had on less important
information showing more prominently than it used to, I took a step
back and did a deeper tidying up of things. Another side goal of this
exercise was to be a little more respectful of terminal width; when
we could say things with fewer words, I did so.
* Stylize the preview/update summary differently, so that it stands
out as a section. Also highlight the total changes with bold -- it
turns out this has a similar effect to the bright white colorization,
just without the negative effects on e.g. white terminals.
* Eliminate some verbosity in the phrasing of change summaries.
* Make all heading sections stylized consistently. This includes
the color (bright magenta) and the vertical spacing (always a newline
separating headings). We were previously inconsistent on this (e.g.,
outputs were under "---outputs---"). Now the headings are:
Previewing (etc), Diagnostics, Outputs, Resources, Duration, and Permalink.
* Fix an issue where we'd parent things to "global" until the stack
object later showed up. Now we'll simply mock up a stack resource.
* Don't show messages like "no change" or "unchanged". Prior to the
light black removal, these faded into the background of the terminal.
Now they just clutter up the display. Similar to the elision of "*"
for OpSames in a prior commit, just leave these out. Now anything
that's written is actually a meaningful status for the user to note.
* Don't show the "3 info messages," etc. summaries in the Info column
while an update is ongoing. Instead, just show the latest line. This
is more respectful of width -- I often find that the important
messages scroll off the right of my screen before this change.
For discussion:
- I actually wonder if we should eliminate the summary
altogether and always just show the latest line. Or even
blank it out. The summary feels better suited for the
Diagnostics section, and the Status concisely tells us
how a resource's update ended up (failed, succeeded, etc).
- Similarly, I question the idea of showing only the "worst"
message. I'd vote for always showing the latest, and again
leaving it to the Status column for concisely telling the
user about the final state a resource ended up in.
* Stop prepending "info: " to every stdout/stderr message. It adds
no value, clutters up the display, and worsens horizontal usage.
* Lessen the verbosity of update headline messages, so we now instead
of e.g. "Previewing update of stack 'x':", we just say
"Previewing update (x):".
* Eliminate vertical whitespace in the Diagnostics section. Every
independent console.out previously was separated by an entire newline,
which made the section look cluttered to my eyes. These are just
streams of logs, there's no reason for the extra newlines.
* Colorize the resource headers in the Diagnostic section light blue.
Note that this will change various test baselines, which I will
update next. I didn't want those in the same commit.
2018-09-24 17:31:19 +02:00
|
|
|
if !wroteDiagnosticHeader && !wroteOutputs {
|
2018-04-17 08:41:00 +02:00
|
|
|
display.writeBlankLine()
|
|
|
|
}
|
|
|
|
|
Make a smattering of CLI UX improvements
Since I was digging around over the weekend after the change to move
away from light black, and the impact it had on less important
information showing more prominently than it used to, I took a step
back and did a deeper tidying up of things. Another side goal of this
exercise was to be a little more respectful of terminal width; when
we could say things with fewer words, I did so.
* Stylize the preview/update summary differently, so that it stands
out as a section. Also highlight the total changes with bold -- it
turns out this has a similar effect to the bright white colorization,
just without the negative effects on e.g. white terminals.
* Eliminate some verbosity in the phrasing of change summaries.
* Make all heading sections stylized consistently. This includes
the color (bright magenta) and the vertical spacing (always a newline
separating headings). We were previously inconsistent on this (e.g.,
outputs were under "---outputs---"). Now the headings are:
Previewing (etc), Diagnostics, Outputs, Resources, Duration, and Permalink.
* Fix an issue where we'd parent things to "global" until the stack
object later showed up. Now we'll simply mock up a stack resource.
* Don't show messages like "no change" or "unchanged". Prior to the
light black removal, these faded into the background of the terminal.
Now they just clutter up the display. Similar to the elision of "*"
for OpSames in a prior commit, just leave these out. Now anything
that's written is actually a meaningful status for the user to note.
* Don't show the "3 info messages," etc. summaries in the Info column
while an update is ongoing. Instead, just show the latest line. This
is more respectful of width -- I often find that the important
messages scroll off the right of my screen before this change.
For discussion:
- I actually wonder if we should eliminate the summary
altogether and always just show the latest line. Or even
blank it out. The summary feels better suited for the
Diagnostics section, and the Status concisely tells us
how a resource's update ended up (failed, succeeded, etc).
- Similarly, I question the idea of showing only the "worst"
message. I'd vote for always showing the latest, and again
leaving it to the Status column for concisely telling the
user about the final state a resource ended up in.
* Stop prepending "info: " to every stdout/stderr message. It adds
no value, clutters up the display, and worsens horizontal usage.
* Lessen the verbosity of update headline messages, so we now instead
of e.g. "Previewing update of stack 'x':", we just say
"Previewing update (x):".
* Eliminate vertical whitespace in the Diagnostics section. Every
independent console.out previously was separated by an entire newline,
which made the section look cluttered to my eyes. These are just
streams of logs, there's no reason for the extra newlines.
* Colorize the resource headers in the Diagnostic section light blue.
Note that this will change various test baselines, which I will
update next. I didn't want those in the same commit.
2018-09-24 17:31:19 +02:00
|
|
|
msg := renderSummaryEvent(display.action, *display.summaryEventPayload, display.opts)
|
2018-04-14 07:26:01 +02:00
|
|
|
display.writeSimpleMessage(msg)
|
2018-04-12 19:56:39 +02:00
|
|
|
}
|
|
|
|
}
|
2018-04-10 21:03:11 +02:00
|
|
|
|
2018-05-08 00:11:52 +02:00
|
|
|
func (display *ProgressDisplay) mergeStreamPayloadsToSinglePayload(
|
|
|
|
payloads []engine.DiagEventPayload) engine.DiagEventPayload {
|
|
|
|
buf := bytes.Buffer{}
|
|
|
|
|
2018-08-02 16:55:15 +02:00
|
|
|
for _, p := range payloads {
|
2018-05-08 00:11:52 +02:00
|
|
|
buf.WriteString(display.renderProgressDiagEvent(p, false /*includePrefix:*/))
|
|
|
|
}
|
|
|
|
|
|
|
|
firstPayload := payloads[0]
|
|
|
|
msg := buf.String()
|
|
|
|
return engine.DiagEventPayload{
|
Implement status sinks
This commit reverts most of #1853 and replaces it with functionally
identical logic, using the notion of status message-specific sinks.
In other words, where the original commit implemented ephemeral status
messages by adding an `isStatus` parameter to most of the logging
methdos in pulumi/pulumi, this implements ephemeral status messages as a
parallel logging sink, which emits _only_ ephemeral status messages.
The original commit message in that PR was:
> Allow log events to be marked "status" events
>
> This commit will introduce a field, IsStatus to LogRequest. A "status"
> logging event will be displayed in the Info column of the main
> display, but will not be printed out at the end, when resource
> operations complete.
>
> For example, for complex resource initialization, we'd like to display
> a series of intermediate results: [1/4] Service object created, for
> example. We'd like these to appear in the Info column, but not at the
> end, where they are not helpful to the user.
2018-08-31 22:12:40 +02:00
|
|
|
URN: firstPayload.URN,
|
|
|
|
Message: msg,
|
|
|
|
Prefix: firstPayload.Prefix,
|
|
|
|
Color: firstPayload.Color,
|
|
|
|
Severity: firstPayload.Severity,
|
|
|
|
StreamID: firstPayload.StreamID,
|
|
|
|
Ephemeral: firstPayload.Ephemeral,
|
2018-05-08 00:11:52 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-19 23:44:53 +02:00
|
|
|
func splitIntoDisplayableLines(msg string) []string {
|
|
|
|
lines := strings.Split(msg, "\n")
|
|
|
|
|
|
|
|
// Trim off any trailing blank lines in the message.
|
|
|
|
for len(lines) > 0 {
|
|
|
|
lastLine := lines[len(lines)-1]
|
|
|
|
if strings.TrimSpace(colors.Never.Colorize(lastLine)) == "" {
|
|
|
|
lines = lines[0 : len(lines)-1]
|
|
|
|
} else {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return lines
|
|
|
|
}
|
|
|
|
|
2018-04-12 19:56:39 +02:00
|
|
|
func (display *ProgressDisplay) processTick() {
|
2018-07-10 22:44:18 +02:00
|
|
|
// Got a tick. Update the progress display if we're in a terminal. If we're not,
|
|
|
|
// print a hearbeat message every 10 seconds after our last output so that the user
|
|
|
|
// knows something is going on. This is also helpful for hosts like jenkins that
|
|
|
|
// often timeout a process if output is not seen in a while.
|
2018-04-12 19:56:39 +02:00
|
|
|
display.currentTick++
|
2018-04-10 21:03:11 +02:00
|
|
|
|
2018-07-10 22:44:18 +02:00
|
|
|
if display.isTerminal {
|
|
|
|
display.refreshAllRowsIfInTerminal()
|
|
|
|
} else {
|
2018-07-12 20:38:44 +02:00
|
|
|
// Update the spinner to let the user know that that work is still happening.
|
|
|
|
display.nonInteractiveSpinner.Tick()
|
2018-07-10 22:44:18 +02:00
|
|
|
}
|
2018-04-12 19:56:39 +02:00
|
|
|
}
|
2018-04-10 21:03:11 +02:00
|
|
|
|
2018-05-22 22:30:52 +02:00
|
|
|
func (display *ProgressDisplay) getRowForURN(urn resource.URN, metadata *engine.StepEventMetadata) ResourceRow {
|
|
|
|
// If there's already a row for this URN, return it.
|
|
|
|
row, has := display.eventUrnToResourceRow[urn]
|
|
|
|
if has {
|
|
|
|
return row
|
2018-04-12 19:56:39 +02:00
|
|
|
}
|
2018-04-10 21:03:11 +02:00
|
|
|
|
2018-05-22 22:30:52 +02:00
|
|
|
// First time we're hearing about this resource. Create an initial nearly-empty status for it.
|
2018-09-19 23:29:16 +02:00
|
|
|
step := engine.StepEventMetadata{URN: urn, Op: deploy.OpSame}
|
2018-05-22 22:30:52 +02:00
|
|
|
if metadata != nil {
|
|
|
|
step = *metadata
|
|
|
|
}
|
|
|
|
|
|
|
|
// If this is the first time we're seeing an event for the stack resource, check to see if we've already
|
|
|
|
// recorded root events that we want to reassociate with this URN.
|
|
|
|
if isRootURN(urn) {
|
2018-06-19 01:03:26 +02:00
|
|
|
display.stackUrn = urn
|
|
|
|
|
2018-05-22 22:30:52 +02:00
|
|
|
if row, has = display.eventUrnToResourceRow[""]; has {
|
|
|
|
row.SetStep(step)
|
|
|
|
display.eventUrnToResourceRow[urn] = row
|
|
|
|
delete(display.eventUrnToResourceRow, "")
|
|
|
|
return row
|
|
|
|
}
|
2018-04-12 19:56:39 +02:00
|
|
|
}
|
2018-04-10 21:03:11 +02:00
|
|
|
|
2018-05-22 22:30:52 +02:00
|
|
|
row = &resourceRowData{
|
|
|
|
display: display,
|
|
|
|
tick: display.currentTick,
|
|
|
|
diagInfo: &DiagInfo{},
|
|
|
|
step: step,
|
|
|
|
hideRowIfUnnecessary: true,
|
|
|
|
}
|
|
|
|
|
|
|
|
display.eventUrnToResourceRow[urn] = row
|
2018-06-19 01:03:26 +02:00
|
|
|
|
|
|
|
display.ensureHeaderAndStackRows()
|
2018-05-22 22:30:52 +02:00
|
|
|
display.resourceRows = append(display.resourceRows, row)
|
|
|
|
return row
|
|
|
|
}
|
|
|
|
|
|
|
|
func (display *ProgressDisplay) processNormalEvent(event engine.Event) {
|
2018-04-12 19:56:39 +02:00
|
|
|
switch event.Type {
|
|
|
|
case engine.PreludeEvent:
|
|
|
|
// A prelude event can just be printed out directly to the console.
|
|
|
|
// Note: we should probably make sure we don't get any prelude events
|
|
|
|
// once we start hearing about actual resource events.
|
2018-04-10 21:03:11 +02:00
|
|
|
|
2018-04-12 19:56:39 +02:00
|
|
|
payload := event.Payload.(engine.PreludeEventPayload)
|
2018-04-14 07:26:01 +02:00
|
|
|
display.writeSimpleMessage(renderPreludeEvent(payload, display.opts))
|
2018-04-12 19:56:39 +02:00
|
|
|
return
|
|
|
|
case engine.SummaryEvent:
|
|
|
|
// keep track of the summar event so that we can display it after all other
|
|
|
|
// resource-related events we receive.
|
2018-04-19 23:44:53 +02:00
|
|
|
payload := event.Payload.(engine.SummaryEventPayload)
|
|
|
|
display.summaryEventPayload = &payload
|
2018-04-12 19:56:39 +02:00
|
|
|
return
|
|
|
|
case engine.DiagEvent:
|
2018-05-08 00:11:52 +02:00
|
|
|
msg := display.renderProgressDiagEvent(event.Payload.(engine.DiagEventPayload), true /*includePrefix:*/)
|
2018-04-12 19:56:39 +02:00
|
|
|
if msg == "" {
|
|
|
|
return
|
|
|
|
}
|
2018-04-19 23:44:53 +02:00
|
|
|
case engine.StdoutColorEvent:
|
|
|
|
display.handleSystemEvent(event.Payload.(engine.StdoutEventPayload))
|
|
|
|
return
|
2018-04-12 19:56:39 +02:00
|
|
|
}
|
2018-04-10 21:03:11 +02:00
|
|
|
|
2018-04-12 19:56:39 +02:00
|
|
|
// At this point, all events should relate to resources.
|
2018-05-22 22:30:52 +02:00
|
|
|
eventUrn, metadata := getEventUrnAndMetadata(event)
|
2019-06-19 00:38:32 +02:00
|
|
|
if metadata != nil {
|
|
|
|
if metadata.Op == deploy.OpReadDiscard || metadata.Op == deploy.OpReadReplacement {
|
|
|
|
// just flat out ignore read discards/replace. They're only relevant in the context of
|
|
|
|
// 'reads', and we only present reads as an ephemeral diagnostic anyways.
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if metadata.Op == deploy.OpRead {
|
|
|
|
// Don't show reads as operations on a specific resource. It's an underlying detail
|
|
|
|
// that we don't want to clutter up the display with. However, to help users know
|
|
|
|
// what's going on, we can show them as ephemeral diagnostic messages that are
|
|
|
|
// associated at the top level with the stack. That way if things are taking a while,
|
|
|
|
// there's insight in the display as to what's going on.
|
|
|
|
display.processNormalEvent(engine.Event{
|
|
|
|
Type: engine.DiagEvent,
|
|
|
|
Payload: engine.DiagEventPayload{
|
|
|
|
Ephemeral: true,
|
|
|
|
Severity: diag.Info,
|
|
|
|
Color: cmdutil.GetGlobalColorization(),
|
|
|
|
Message: fmt.Sprintf("read %v %v", simplifyTypeName(eventUrn.Type()), eventUrn.Name()),
|
|
|
|
},
|
|
|
|
})
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-22 22:30:52 +02:00
|
|
|
if eventUrn == "" {
|
|
|
|
// If this event has no URN, associate it with the stack. Note that there may not yet be a stack resource, in
|
|
|
|
// which case this is a no-op.
|
|
|
|
eventUrn = display.stackUrn
|
|
|
|
}
|
|
|
|
isRootEvent := eventUrn == display.stackUrn
|
2018-04-12 19:56:39 +02:00
|
|
|
|
2018-05-22 22:30:52 +02:00
|
|
|
row := display.getRowForURN(eventUrn, metadata)
|
2018-04-15 21:47:53 +02:00
|
|
|
|
2018-05-22 22:30:52 +02:00
|
|
|
// Don't bother showing certain events (for example, things that are unchanged). However
|
|
|
|
// always show the root 'stack' resource so we can indicate that it's still running, and
|
|
|
|
// also so we have something to attach unparented diagnostic events to.
|
|
|
|
hideRowIfUnnecessary := metadata != nil && !shouldShow(*metadata, display.opts) && !isRootEvent
|
2019-07-22 22:33:54 +02:00
|
|
|
// Always show row if there's a policy violation event. Policy violations prevent resource
|
|
|
|
// registration, so if we don't show the row, the violation gets attributed to the stack
|
|
|
|
// resource rather than the resources whose policy failed.
|
|
|
|
hideRowIfUnnecessary = hideRowIfUnnecessary || event.Type == engine.PolicyViolationEvent
|
2018-05-22 22:30:52 +02:00
|
|
|
if !hideRowIfUnnecessary {
|
|
|
|
row.SetHideRowIfUnnecessary(false)
|
2018-04-12 19:56:39 +02:00
|
|
|
}
|
2018-04-10 21:03:11 +02:00
|
|
|
|
2018-04-12 19:56:39 +02:00
|
|
|
if event.Type == engine.ResourcePreEvent {
|
2018-04-15 21:47:53 +02:00
|
|
|
step := event.Payload.(engine.ResourcePreEventPayload).Metadata
|
|
|
|
row.SetStep(step)
|
2018-04-12 19:56:39 +02:00
|
|
|
} else if event.Type == engine.ResourceOutputsEvent {
|
2018-08-23 02:52:46 +02:00
|
|
|
isRefresh := display.getStepOp(row.Step()) == deploy.OpRefresh
|
2018-05-12 01:48:05 +02:00
|
|
|
step := event.Payload.(engine.ResourceOutputsEventPayload).Metadata
|
2018-09-12 01:44:06 +02:00
|
|
|
|
|
|
|
// Is this the stack outputs event? If so, we'll need to print it out at the end of the plan.
|
|
|
|
if step.URN == display.stackUrn {
|
|
|
|
display.seenStackOutputs = true
|
|
|
|
}
|
|
|
|
|
2018-05-12 01:48:05 +02:00
|
|
|
row.SetStep(step)
|
2018-08-02 06:48:14 +02:00
|
|
|
row.AddOutputStep(step)
|
2018-05-22 20:31:48 +02:00
|
|
|
|
|
|
|
// If we're not in a terminal, we may not want to display this row again: if we're displaying a preview or if
|
|
|
|
// this step is a no-op for a custom resource, refreshing this row will simply duplicate its earlier output.
|
2018-08-23 02:52:46 +02:00
|
|
|
hasMeaningfulOutput := isRefresh ||
|
|
|
|
!display.isPreview && (step.Res == nil || step.Res.Custom && step.Op != deploy.OpSame)
|
2018-05-22 20:31:48 +02:00
|
|
|
if !display.isTerminal && !hasMeaningfulOutput {
|
|
|
|
return
|
|
|
|
}
|
2018-04-12 19:56:39 +02:00
|
|
|
} else if event.Type == engine.ResourceOperationFailed {
|
2018-04-15 21:47:53 +02:00
|
|
|
row.SetFailed()
|
2018-04-12 19:56:39 +02:00
|
|
|
} else if event.Type == engine.DiagEvent {
|
|
|
|
// also record this diagnostic so we print it at the end.
|
2018-04-15 21:47:53 +02:00
|
|
|
row.RecordDiagEvent(event)
|
2019-06-11 00:20:44 +02:00
|
|
|
} else if event.Type == engine.PolicyViolationEvent {
|
|
|
|
// also record this policy violation so we print it at the end.
|
|
|
|
row.RecordPolicyViolationEvent(event)
|
2018-04-12 19:56:39 +02:00
|
|
|
} else {
|
|
|
|
contract.Failf("Unhandled event type '%s'", event.Type)
|
|
|
|
}
|
|
|
|
|
2018-04-19 21:31:47 +02:00
|
|
|
if display.isTerminal {
|
|
|
|
// if we're in a terminal, then refresh everything so that all our columns line up
|
2018-04-15 21:47:53 +02:00
|
|
|
display.refreshAllRowsIfInTerminal()
|
2018-04-12 19:56:39 +02:00
|
|
|
} else {
|
2018-04-19 21:31:47 +02:00
|
|
|
// otherwise, just print out this single row.
|
2018-04-24 20:13:22 +02:00
|
|
|
display.refreshSingleRow("", row, nil)
|
2018-04-10 21:03:11 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-19 23:44:53 +02:00
|
|
|
func (display *ProgressDisplay) handleSystemEvent(payload engine.StdoutEventPayload) {
|
|
|
|
// Make sure we have a header to display
|
2018-06-19 01:03:26 +02:00
|
|
|
display.ensureHeaderAndStackRows()
|
2018-04-19 23:44:53 +02:00
|
|
|
|
|
|
|
display.systemEventPayloads = append(display.systemEventPayloads, payload)
|
|
|
|
|
|
|
|
if display.isTerminal {
|
|
|
|
// if we're in a terminal, then refresh everything. The system events will come after
|
|
|
|
// all the normal rows
|
|
|
|
display.refreshAllRowsIfInTerminal()
|
|
|
|
} else {
|
|
|
|
// otherwise, in a non-terminal, just print out the actual event.
|
|
|
|
display.writeSimpleMessage(renderStdoutColorEvent(payload, display.opts))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-19 01:03:26 +02:00
|
|
|
func (display *ProgressDisplay) ensureHeaderAndStackRows() {
|
2018-04-23 03:10:19 +02:00
|
|
|
if display.headerRow == nil {
|
2018-04-19 23:44:53 +02:00
|
|
|
// about to make our first status message. make sure we present the header line first.
|
2018-04-23 03:10:19 +02:00
|
|
|
display.headerRow = &headerRowData{display: display}
|
2018-04-19 23:44:53 +02:00
|
|
|
}
|
2018-06-19 01:03:26 +02:00
|
|
|
|
|
|
|
// we've added at least one row to the table. make sure we have a row to designate the
|
|
|
|
// stack if we haven't already heard about it yet. This also ensures that as we build
|
|
|
|
// the tree we can always guarantee there's a 'root' to parent anything to.
|
|
|
|
_, hasStackRow := display.eventUrnToResourceRow[display.stackUrn]
|
|
|
|
if hasStackRow {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
stackRow := &resourceRowData{
|
|
|
|
display: display,
|
|
|
|
tick: display.currentTick,
|
|
|
|
diagInfo: &DiagInfo{},
|
|
|
|
step: engine.StepEventMetadata{Op: deploy.OpSame},
|
|
|
|
hideRowIfUnnecessary: false,
|
|
|
|
}
|
|
|
|
|
|
|
|
display.eventUrnToResourceRow[display.stackUrn] = stackRow
|
|
|
|
display.resourceRows = append(display.resourceRows, stackRow)
|
2018-04-19 23:44:53 +02:00
|
|
|
}
|
|
|
|
|
2018-04-12 19:56:39 +02:00
|
|
|
func (display *ProgressDisplay) processEvents(ticker *time.Ticker, events <-chan engine.Event) {
|
|
|
|
// Main processing loop. The purpose of this func is to read in events from the engine
|
|
|
|
// and translate them into Status objects and progress messages to be presented to the
|
|
|
|
// command line.
|
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case <-ticker.C:
|
|
|
|
display.processTick()
|
|
|
|
|
|
|
|
case event := <-events:
|
|
|
|
if event.Type == "" || event.Type == engine.CancelEvent {
|
|
|
|
// Engine finished sending events. Do all the final processing and return
|
|
|
|
// from this local func. This will print out things like full diagnostic
|
|
|
|
// events, as well as the summary event from the engine.
|
|
|
|
display.processEndSteps()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
display.processNormalEvent(event)
|
2018-04-10 21:03:11 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-08 00:11:52 +02:00
|
|
|
func (display *ProgressDisplay) renderProgressDiagEvent(payload engine.DiagEventPayload, includePrefix bool) string {
|
2018-04-12 19:56:39 +02:00
|
|
|
if payload.Severity == diag.Debug && !display.opts.Debug {
|
2018-04-10 21:03:11 +02:00
|
|
|
return ""
|
|
|
|
}
|
2018-05-08 00:11:52 +02:00
|
|
|
|
|
|
|
msg := payload.Message
|
|
|
|
if includePrefix {
|
|
|
|
msg = payload.Prefix + msg
|
|
|
|
}
|
|
|
|
|
|
|
|
return strings.TrimRightFunc(msg, unicode.IsSpace)
|
2018-04-10 21:03:11 +02:00
|
|
|
}
|
|
|
|
|
2018-04-12 19:56:39 +02:00
|
|
|
func (display *ProgressDisplay) getStepDoneDescription(step engine.StepEventMetadata, failed bool) string {
|
|
|
|
makeError := func(v string) string {
|
|
|
|
return colors.SpecError + "**" + v + "**" + colors.Reset
|
|
|
|
}
|
|
|
|
|
2018-08-02 06:48:14 +02:00
|
|
|
op := display.getStepOp(step)
|
|
|
|
|
2018-04-14 07:26:01 +02:00
|
|
|
if display.isPreview {
|
2018-09-17 19:50:11 +02:00
|
|
|
// During a preview, when we transition to done, we'll print out summary text describing the step instead of a
|
|
|
|
// past-tense verb describing the step that was performed.
|
|
|
|
return op.Color() + display.getPreviewDoneText(step) + colors.Reset
|
2018-04-10 21:03:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
getDescription := func() string {
|
2018-04-12 19:56:39 +02:00
|
|
|
if failed {
|
|
|
|
switch op {
|
|
|
|
case deploy.OpSame:
|
2018-04-14 07:26:01 +02:00
|
|
|
return "failed"
|
2018-04-12 19:56:39 +02:00
|
|
|
case deploy.OpCreate, deploy.OpCreateReplacement:
|
2018-04-14 07:26:01 +02:00
|
|
|
return "creating failed"
|
2018-04-12 19:56:39 +02:00
|
|
|
case deploy.OpUpdate:
|
2018-04-14 07:26:01 +02:00
|
|
|
return "updating failed"
|
2018-04-12 19:56:39 +02:00
|
|
|
case deploy.OpDelete, deploy.OpDeleteReplaced:
|
2018-04-14 07:26:01 +02:00
|
|
|
return "deleting failed"
|
2018-04-12 19:56:39 +02:00
|
|
|
case deploy.OpReplace:
|
2018-04-14 07:26:01 +02:00
|
|
|
return "replacing failed"
|
2018-08-03 23:06:00 +02:00
|
|
|
case deploy.OpRead, deploy.OpReadReplacement:
|
|
|
|
return "reading failed"
|
2018-08-23 02:52:46 +02:00
|
|
|
case deploy.OpRefresh:
|
|
|
|
return "refreshing failed"
|
2019-01-31 22:48:44 +01:00
|
|
|
case deploy.OpReadDiscard, deploy.OpDiscardReplaced:
|
|
|
|
return "discarding failed"
|
2019-07-12 20:12:01 +02:00
|
|
|
case deploy.OpImport, deploy.OpImportReplacement:
|
|
|
|
return "importing failed"
|
2018-04-12 19:56:39 +02:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
switch op {
|
|
|
|
case deploy.OpSame:
|
Make a smattering of CLI UX improvements
Since I was digging around over the weekend after the change to move
away from light black, and the impact it had on less important
information showing more prominently than it used to, I took a step
back and did a deeper tidying up of things. Another side goal of this
exercise was to be a little more respectful of terminal width; when
we could say things with fewer words, I did so.
* Stylize the preview/update summary differently, so that it stands
out as a section. Also highlight the total changes with bold -- it
turns out this has a similar effect to the bright white colorization,
just without the negative effects on e.g. white terminals.
* Eliminate some verbosity in the phrasing of change summaries.
* Make all heading sections stylized consistently. This includes
the color (bright magenta) and the vertical spacing (always a newline
separating headings). We were previously inconsistent on this (e.g.,
outputs were under "---outputs---"). Now the headings are:
Previewing (etc), Diagnostics, Outputs, Resources, Duration, and Permalink.
* Fix an issue where we'd parent things to "global" until the stack
object later showed up. Now we'll simply mock up a stack resource.
* Don't show messages like "no change" or "unchanged". Prior to the
light black removal, these faded into the background of the terminal.
Now they just clutter up the display. Similar to the elision of "*"
for OpSames in a prior commit, just leave these out. Now anything
that's written is actually a meaningful status for the user to note.
* Don't show the "3 info messages," etc. summaries in the Info column
while an update is ongoing. Instead, just show the latest line. This
is more respectful of width -- I often find that the important
messages scroll off the right of my screen before this change.
For discussion:
- I actually wonder if we should eliminate the summary
altogether and always just show the latest line. Or even
blank it out. The summary feels better suited for the
Diagnostics section, and the Status concisely tells us
how a resource's update ended up (failed, succeeded, etc).
- Similarly, I question the idea of showing only the "worst"
message. I'd vote for always showing the latest, and again
leaving it to the Status column for concisely telling the
user about the final state a resource ended up in.
* Stop prepending "info: " to every stdout/stderr message. It adds
no value, clutters up the display, and worsens horizontal usage.
* Lessen the verbosity of update headline messages, so we now instead
of e.g. "Previewing update of stack 'x':", we just say
"Previewing update (x):".
* Eliminate vertical whitespace in the Diagnostics section. Every
independent console.out previously was separated by an entire newline,
which made the section look cluttered to my eyes. These are just
streams of logs, there's no reason for the extra newlines.
* Colorize the resource headers in the Diagnostic section light blue.
Note that this will change various test baselines, which I will
update next. I didn't want those in the same commit.
2018-09-24 17:31:19 +02:00
|
|
|
return ""
|
2018-04-12 19:56:39 +02:00
|
|
|
case deploy.OpCreate:
|
2018-04-14 07:26:01 +02:00
|
|
|
return "created"
|
2018-04-12 19:56:39 +02:00
|
|
|
case deploy.OpUpdate:
|
2018-04-14 07:26:01 +02:00
|
|
|
return "updated"
|
2018-04-12 19:56:39 +02:00
|
|
|
case deploy.OpDelete:
|
2018-04-14 07:26:01 +02:00
|
|
|
return "deleted"
|
2018-04-12 19:56:39 +02:00
|
|
|
case deploy.OpReplace:
|
2018-04-14 07:26:01 +02:00
|
|
|
return "replaced"
|
2018-04-12 19:56:39 +02:00
|
|
|
case deploy.OpCreateReplacement:
|
2018-08-02 06:48:14 +02:00
|
|
|
return "created replacement"
|
2018-04-12 19:56:39 +02:00
|
|
|
case deploy.OpDeleteReplaced:
|
2018-08-02 06:48:14 +02:00
|
|
|
return "deleted original"
|
2018-08-03 23:06:00 +02:00
|
|
|
case deploy.OpRead:
|
2018-09-17 19:50:11 +02:00
|
|
|
// nolint: goconst
|
2018-08-03 23:06:00 +02:00
|
|
|
return "read"
|
|
|
|
case deploy.OpReadReplacement:
|
|
|
|
return "read for replacement"
|
2018-08-23 02:52:46 +02:00
|
|
|
case deploy.OpRefresh:
|
|
|
|
return "refresh"
|
2019-01-31 22:48:44 +01:00
|
|
|
case deploy.OpReadDiscard:
|
|
|
|
return "discarded"
|
|
|
|
case deploy.OpDiscardReplaced:
|
|
|
|
return "discarded original"
|
2019-07-12 20:12:01 +02:00
|
|
|
case deploy.OpImport:
|
|
|
|
return "imported"
|
|
|
|
case deploy.OpImportReplacement:
|
|
|
|
return "imported replacement"
|
2018-04-12 19:56:39 +02:00
|
|
|
}
|
2018-04-10 21:03:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
contract.Failf("Unrecognized resource step op: %v", op)
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
2018-04-12 19:56:39 +02:00
|
|
|
if failed {
|
|
|
|
return makeError(getDescription())
|
|
|
|
}
|
|
|
|
|
2018-04-30 21:31:57 +02:00
|
|
|
return op.Color() + getDescription() + colors.Reset
|
2018-04-10 21:03:11 +02:00
|
|
|
}
|
|
|
|
|
2018-09-11 01:48:14 +02:00
|
|
|
func (display *ProgressDisplay) getPreviewText(step engine.StepEventMetadata) string {
|
|
|
|
switch step.Op {
|
2018-04-14 07:26:01 +02:00
|
|
|
case deploy.OpSame:
|
Make a smattering of CLI UX improvements
Since I was digging around over the weekend after the change to move
away from light black, and the impact it had on less important
information showing more prominently than it used to, I took a step
back and did a deeper tidying up of things. Another side goal of this
exercise was to be a little more respectful of terminal width; when
we could say things with fewer words, I did so.
* Stylize the preview/update summary differently, so that it stands
out as a section. Also highlight the total changes with bold -- it
turns out this has a similar effect to the bright white colorization,
just without the negative effects on e.g. white terminals.
* Eliminate some verbosity in the phrasing of change summaries.
* Make all heading sections stylized consistently. This includes
the color (bright magenta) and the vertical spacing (always a newline
separating headings). We were previously inconsistent on this (e.g.,
outputs were under "---outputs---"). Now the headings are:
Previewing (etc), Diagnostics, Outputs, Resources, Duration, and Permalink.
* Fix an issue where we'd parent things to "global" until the stack
object later showed up. Now we'll simply mock up a stack resource.
* Don't show messages like "no change" or "unchanged". Prior to the
light black removal, these faded into the background of the terminal.
Now they just clutter up the display. Similar to the elision of "*"
for OpSames in a prior commit, just leave these out. Now anything
that's written is actually a meaningful status for the user to note.
* Don't show the "3 info messages," etc. summaries in the Info column
while an update is ongoing. Instead, just show the latest line. This
is more respectful of width -- I often find that the important
messages scroll off the right of my screen before this change.
For discussion:
- I actually wonder if we should eliminate the summary
altogether and always just show the latest line. Or even
blank it out. The summary feels better suited for the
Diagnostics section, and the Status concisely tells us
how a resource's update ended up (failed, succeeded, etc).
- Similarly, I question the idea of showing only the "worst"
message. I'd vote for always showing the latest, and again
leaving it to the Status column for concisely telling the
user about the final state a resource ended up in.
* Stop prepending "info: " to every stdout/stderr message. It adds
no value, clutters up the display, and worsens horizontal usage.
* Lessen the verbosity of update headline messages, so we now instead
of e.g. "Previewing update of stack 'x':", we just say
"Previewing update (x):".
* Eliminate vertical whitespace in the Diagnostics section. Every
independent console.out previously was separated by an entire newline,
which made the section look cluttered to my eyes. These are just
streams of logs, there's no reason for the extra newlines.
* Colorize the resource headers in the Diagnostic section light blue.
Note that this will change various test baselines, which I will
update next. I didn't want those in the same commit.
2018-09-24 17:31:19 +02:00
|
|
|
return ""
|
2018-04-14 07:26:01 +02:00
|
|
|
case deploy.OpCreate:
|
2018-04-17 04:46:57 +02:00
|
|
|
return "create"
|
2018-04-14 07:26:01 +02:00
|
|
|
case deploy.OpUpdate:
|
2018-04-17 04:46:57 +02:00
|
|
|
return "update"
|
2018-04-14 07:26:01 +02:00
|
|
|
case deploy.OpDelete:
|
2018-04-17 04:46:57 +02:00
|
|
|
return "delete"
|
2018-04-14 07:26:01 +02:00
|
|
|
case deploy.OpReplace:
|
2018-04-17 04:46:57 +02:00
|
|
|
return "replace"
|
2018-04-14 07:26:01 +02:00
|
|
|
case deploy.OpCreateReplacement:
|
2018-08-02 06:48:14 +02:00
|
|
|
return "create replacement"
|
2018-04-14 07:26:01 +02:00
|
|
|
case deploy.OpDeleteReplaced:
|
2018-08-02 06:48:14 +02:00
|
|
|
return "delete original"
|
2018-08-03 23:06:00 +02:00
|
|
|
case deploy.OpRead:
|
2018-09-17 19:50:11 +02:00
|
|
|
// nolint: goconst
|
2018-08-03 23:06:00 +02:00
|
|
|
return "read"
|
|
|
|
case deploy.OpReadReplacement:
|
|
|
|
return "read for replacement"
|
2018-08-23 02:52:46 +02:00
|
|
|
case deploy.OpRefresh:
|
|
|
|
return "refreshing"
|
2019-01-31 22:48:44 +01:00
|
|
|
case deploy.OpReadDiscard:
|
|
|
|
return "discard"
|
|
|
|
case deploy.OpDiscardReplaced:
|
2019-07-12 20:12:01 +02:00
|
|
|
return "discard original"
|
|
|
|
case deploy.OpImport:
|
|
|
|
return "import"
|
|
|
|
case deploy.OpImportReplacement:
|
|
|
|
return "import replacement"
|
2018-04-14 07:26:01 +02:00
|
|
|
}
|
|
|
|
|
2018-09-11 01:48:14 +02:00
|
|
|
contract.Failf("Unrecognized resource step op: %v", step.Op)
|
2018-04-14 07:26:01 +02:00
|
|
|
return ""
|
|
|
|
}
|
2018-04-12 19:56:39 +02:00
|
|
|
|
2018-09-17 19:50:11 +02:00
|
|
|
// getPreviewDoneText returns a textual representation for this step, suitable for display during a preview once the
|
|
|
|
// preview has completed.
|
|
|
|
func (display *ProgressDisplay) getPreviewDoneText(step engine.StepEventMetadata) string {
|
|
|
|
switch step.Op {
|
|
|
|
case deploy.OpSame:
|
Make a smattering of CLI UX improvements
Since I was digging around over the weekend after the change to move
away from light black, and the impact it had on less important
information showing more prominently than it used to, I took a step
back and did a deeper tidying up of things. Another side goal of this
exercise was to be a little more respectful of terminal width; when
we could say things with fewer words, I did so.
* Stylize the preview/update summary differently, so that it stands
out as a section. Also highlight the total changes with bold -- it
turns out this has a similar effect to the bright white colorization,
just without the negative effects on e.g. white terminals.
* Eliminate some verbosity in the phrasing of change summaries.
* Make all heading sections stylized consistently. This includes
the color (bright magenta) and the vertical spacing (always a newline
separating headings). We were previously inconsistent on this (e.g.,
outputs were under "---outputs---"). Now the headings are:
Previewing (etc), Diagnostics, Outputs, Resources, Duration, and Permalink.
* Fix an issue where we'd parent things to "global" until the stack
object later showed up. Now we'll simply mock up a stack resource.
* Don't show messages like "no change" or "unchanged". Prior to the
light black removal, these faded into the background of the terminal.
Now they just clutter up the display. Similar to the elision of "*"
for OpSames in a prior commit, just leave these out. Now anything
that's written is actually a meaningful status for the user to note.
* Don't show the "3 info messages," etc. summaries in the Info column
while an update is ongoing. Instead, just show the latest line. This
is more respectful of width -- I often find that the important
messages scroll off the right of my screen before this change.
For discussion:
- I actually wonder if we should eliminate the summary
altogether and always just show the latest line. Or even
blank it out. The summary feels better suited for the
Diagnostics section, and the Status concisely tells us
how a resource's update ended up (failed, succeeded, etc).
- Similarly, I question the idea of showing only the "worst"
message. I'd vote for always showing the latest, and again
leaving it to the Status column for concisely telling the
user about the final state a resource ended up in.
* Stop prepending "info: " to every stdout/stderr message. It adds
no value, clutters up the display, and worsens horizontal usage.
* Lessen the verbosity of update headline messages, so we now instead
of e.g. "Previewing update of stack 'x':", we just say
"Previewing update (x):".
* Eliminate vertical whitespace in the Diagnostics section. Every
independent console.out previously was separated by an entire newline,
which made the section look cluttered to my eyes. These are just
streams of logs, there's no reason for the extra newlines.
* Colorize the resource headers in the Diagnostic section light blue.
Note that this will change various test baselines, which I will
update next. I didn't want those in the same commit.
2018-09-24 17:31:19 +02:00
|
|
|
return ""
|
2018-09-17 19:50:11 +02:00
|
|
|
case deploy.OpCreate:
|
|
|
|
return "create"
|
|
|
|
case deploy.OpUpdate:
|
|
|
|
return "update"
|
|
|
|
case deploy.OpDelete:
|
|
|
|
return "delete"
|
2019-01-31 22:48:44 +01:00
|
|
|
case deploy.OpReplace, deploy.OpCreateReplacement, deploy.OpDeleteReplaced, deploy.OpReadReplacement,
|
|
|
|
deploy.OpDiscardReplaced:
|
2018-09-17 19:50:11 +02:00
|
|
|
return "replace"
|
|
|
|
case deploy.OpRead:
|
|
|
|
// nolint: goconst
|
|
|
|
return "read"
|
|
|
|
case deploy.OpRefresh:
|
|
|
|
return "refresh"
|
2019-01-31 22:48:44 +01:00
|
|
|
case deploy.OpReadDiscard:
|
|
|
|
return "discard"
|
2019-07-12 20:12:01 +02:00
|
|
|
case deploy.OpImport, deploy.OpImportReplacement:
|
|
|
|
return "import"
|
2018-09-17 19:50:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
contract.Failf("Unrecognized resource step op: %v", step.Op)
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
2018-08-02 06:48:14 +02:00
|
|
|
func (display *ProgressDisplay) getStepOp(step engine.StepEventMetadata) deploy.StepOp {
|
|
|
|
op := step.Op
|
|
|
|
|
|
|
|
// We will commonly hear about replacements as an actual series of steps. i.e. 'create
|
|
|
|
// replacement', 'replace', 'delete original'. During the actual application of these steps we
|
|
|
|
// want to see these individual steps. However, both before we apply all of them, and after
|
|
|
|
// they're all done, we want to show this as a single conceptual 'replace'/'replaced' step.
|
|
|
|
//
|
|
|
|
// Note: in non-interactive mode we can show these all as individual steps. This only applies
|
|
|
|
// to interactive mode, where there is only one line shown per resource, and we want it to be as
|
|
|
|
// clear as possible
|
|
|
|
if display.isTerminal {
|
|
|
|
// During preview, show the steps for replacing as a single 'replace' plan.
|
|
|
|
// Once done, show the steps for replacing as a single 'replaced' step.
|
|
|
|
// During update, we'll show these individual steps.
|
|
|
|
if display.isPreview || display.done {
|
2019-01-31 22:48:44 +01:00
|
|
|
if op == deploy.OpCreateReplacement || op == deploy.OpDeleteReplaced || op == deploy.OpDiscardReplaced {
|
2018-08-02 06:48:14 +02:00
|
|
|
return deploy.OpReplace
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return op
|
|
|
|
}
|
|
|
|
|
2018-04-30 21:31:57 +02:00
|
|
|
func (display *ProgressDisplay) getStepOpLabel(step engine.StepEventMetadata) string {
|
2018-08-02 06:48:14 +02:00
|
|
|
return display.getStepOp(step).Prefix() + colors.Reset
|
2018-04-30 21:31:57 +02:00
|
|
|
}
|
|
|
|
|
2018-04-14 07:26:01 +02:00
|
|
|
func (display *ProgressDisplay) getStepInProgressDescription(step engine.StepEventMetadata) string {
|
2018-08-02 06:48:14 +02:00
|
|
|
op := display.getStepOp(step)
|
2018-04-12 19:56:39 +02:00
|
|
|
|
2018-04-14 07:26:01 +02:00
|
|
|
if isRootStack(step) && op == deploy.OpSame {
|
|
|
|
// most of the time a stack is unchanged. in that case we just show it as "running->done".
|
|
|
|
// otherwise, we show what is actually happening to it.
|
|
|
|
return "running"
|
|
|
|
}
|
|
|
|
|
2018-04-10 21:03:11 +02:00
|
|
|
getDescription := func() string {
|
2018-04-12 19:56:39 +02:00
|
|
|
if display.isPreview {
|
2018-09-11 01:48:14 +02:00
|
|
|
return display.getPreviewText(step)
|
2018-04-14 07:26:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
switch op {
|
|
|
|
case deploy.OpSame:
|
Make a smattering of CLI UX improvements
Since I was digging around over the weekend after the change to move
away from light black, and the impact it had on less important
information showing more prominently than it used to, I took a step
back and did a deeper tidying up of things. Another side goal of this
exercise was to be a little more respectful of terminal width; when
we could say things with fewer words, I did so.
* Stylize the preview/update summary differently, so that it stands
out as a section. Also highlight the total changes with bold -- it
turns out this has a similar effect to the bright white colorization,
just without the negative effects on e.g. white terminals.
* Eliminate some verbosity in the phrasing of change summaries.
* Make all heading sections stylized consistently. This includes
the color (bright magenta) and the vertical spacing (always a newline
separating headings). We were previously inconsistent on this (e.g.,
outputs were under "---outputs---"). Now the headings are:
Previewing (etc), Diagnostics, Outputs, Resources, Duration, and Permalink.
* Fix an issue where we'd parent things to "global" until the stack
object later showed up. Now we'll simply mock up a stack resource.
* Don't show messages like "no change" or "unchanged". Prior to the
light black removal, these faded into the background of the terminal.
Now they just clutter up the display. Similar to the elision of "*"
for OpSames in a prior commit, just leave these out. Now anything
that's written is actually a meaningful status for the user to note.
* Don't show the "3 info messages," etc. summaries in the Info column
while an update is ongoing. Instead, just show the latest line. This
is more respectful of width -- I often find that the important
messages scroll off the right of my screen before this change.
For discussion:
- I actually wonder if we should eliminate the summary
altogether and always just show the latest line. Or even
blank it out. The summary feels better suited for the
Diagnostics section, and the Status concisely tells us
how a resource's update ended up (failed, succeeded, etc).
- Similarly, I question the idea of showing only the "worst"
message. I'd vote for always showing the latest, and again
leaving it to the Status column for concisely telling the
user about the final state a resource ended up in.
* Stop prepending "info: " to every stdout/stderr message. It adds
no value, clutters up the display, and worsens horizontal usage.
* Lessen the verbosity of update headline messages, so we now instead
of e.g. "Previewing update of stack 'x':", we just say
"Previewing update (x):".
* Eliminate vertical whitespace in the Diagnostics section. Every
independent console.out previously was separated by an entire newline,
which made the section look cluttered to my eyes. These are just
streams of logs, there's no reason for the extra newlines.
* Colorize the resource headers in the Diagnostic section light blue.
Note that this will change various test baselines, which I will
update next. I didn't want those in the same commit.
2018-09-24 17:31:19 +02:00
|
|
|
return ""
|
2018-04-14 07:26:01 +02:00
|
|
|
case deploy.OpCreate:
|
|
|
|
return "creating"
|
|
|
|
case deploy.OpUpdate:
|
|
|
|
return "updating"
|
|
|
|
case deploy.OpDelete:
|
|
|
|
return "deleting"
|
|
|
|
case deploy.OpReplace:
|
|
|
|
return "replacing"
|
|
|
|
case deploy.OpCreateReplacement:
|
2018-08-02 06:48:14 +02:00
|
|
|
return "creating replacement"
|
2018-04-14 07:26:01 +02:00
|
|
|
case deploy.OpDeleteReplaced:
|
2018-08-02 06:48:14 +02:00
|
|
|
return "deleting original"
|
2018-08-03 23:06:00 +02:00
|
|
|
case deploy.OpRead:
|
|
|
|
return "reading"
|
|
|
|
case deploy.OpReadReplacement:
|
|
|
|
return "reading for replacement"
|
2018-08-23 02:52:46 +02:00
|
|
|
case deploy.OpRefresh:
|
|
|
|
return "refreshing"
|
2019-01-31 22:48:44 +01:00
|
|
|
case deploy.OpReadDiscard:
|
|
|
|
return "discarding"
|
|
|
|
case deploy.OpDiscardReplaced:
|
|
|
|
return "discarding original"
|
2019-07-12 20:12:01 +02:00
|
|
|
case deploy.OpImport:
|
|
|
|
return "importing"
|
|
|
|
case deploy.OpImportReplacement:
|
|
|
|
return "importing replacement"
|
2018-04-10 21:03:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
contract.Failf("Unrecognized resource step op: %v", op)
|
|
|
|
return ""
|
|
|
|
}
|
2018-04-30 21:31:57 +02:00
|
|
|
return op.Color() + getDescription() + colors.Reset
|
2018-04-10 21:03:11 +02:00
|
|
|
}
|
|
|
|
|
2019-04-01 16:27:21 +02:00
|
|
|
func writeString(b io.StringWriter, s string) {
|
2018-04-10 21:03:11 +02:00
|
|
|
_, err := b.WriteString(s)
|
|
|
|
contract.IgnoreError(err)
|
|
|
|
}
|