Simplifying progress code (#1253)

This commit is contained in:
CyrusNajmabadi 2018-04-22 18:10:19 -07:00 committed by GitHub
parent fe3d854bc5
commit 7807edc166
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 73 additions and 53 deletions

View file

@ -86,7 +86,8 @@ type ProgressDisplay struct {
// a status message to help indicate that things are still working. // a status message to help indicate that things are still working.
currentTick int currentTick int
rows []Row headerRow Row
resourceRows []ResourceRow
// A mapping from each resource URN we are told about to its current status. // A mapping from each resource URN we are told about to its current status.
eventUrnToResourceRow map[resource.URN]ResourceRow eventUrnToResourceRow map[resource.URN]ResourceRow
@ -238,20 +239,30 @@ func DisplayProgressEvents(
// Gets the padding necessary to prepend to a message in order to keep it aligned in the // Gets the padding necessary to prepend to a message in order to keep it aligned in the
// terminal. // terminal.
func (display *ProgressDisplay) getMessagePadding(uncolorizedColumns []string, columnIndex int) string { func (display *ProgressDisplay) getMessagePadding(
id string, maxIDLength int, uncolorizedColumns []string, columnIndex int) string {
extraWhitespace := 1 extraWhitespace := 1
// In the terminal we try to align the status messages for each resource. // In the terminal we try to align the status messages for each resource.
// do not bother with this in the non-terminal case. // do not bother with this in the non-terminal case.
if display.isTerminal { if display.isTerminal {
column := uncolorizedColumns[columnIndex] var column string
maxIDLength := display.maxColumnLengths[columnIndex] var maxLength int
extraWhitespace = maxIDLength - len(column) if columnIndex == -1 {
column = id
maxLength = maxIDLength
} else {
column = uncolorizedColumns[columnIndex]
maxLength = display.maxColumnLengths[columnIndex]
}
extraWhitespace = maxLength - len(column)
contract.Assertf(extraWhitespace >= 0, "Neg whitespace. %v %s", maxIDLength, column) contract.Assertf(extraWhitespace >= 0, "Neg whitespace. %v %s", maxIDLength, column)
if columnIndex > 0 { // Place two spaces between all columns (except after the first column). The first
// 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.
// column already has a ": " so it doesn't need the extra space. if columnIndex >= 0 {
extraWhitespace += 2 extraWhitespace += 2
} }
} }
@ -264,12 +275,12 @@ func (display *ProgressDisplay) getMessagePadding(uncolorizedColumns []string, c
// suffix. Importantly, if there isn't enough room to display all of that on the terminal, then // 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. // the msg will be truncated to try to make it fit.
func (display *ProgressDisplay) getPaddedMessage( func (display *ProgressDisplay) getPaddedMessage(
colorizedColumns, uncolorizedColumns []string) string { id string, maxIDLength int, colorizedColumns, uncolorizedColumns []string) string {
colorizedMessage := "" colorizedMessage := ""
for i := 1; i < len(colorizedColumns); i++ { for i := 0; i < len(colorizedColumns); i++ {
padding := display.getMessagePadding(uncolorizedColumns, i-1) padding := display.getMessagePadding(id, maxIDLength, uncolorizedColumns, i-1)
colorizedMessage += padding + colorizedColumns[i] colorizedMessage += padding + colorizedColumns[i]
} }
@ -278,7 +289,6 @@ func (display *ProgressDisplay) getPaddedMessage(
// msgWithColors having the color code information embedded with it. So we need to get // 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 // the right substring of it, assuming that embedded colors are just markup and do not
// actually contribute to the length // actually contribute to the length
id := uncolorizedColumns[0]
maxMsgLength := display.terminalWidth - len(id) - len(": ") - 1 maxMsgLength := display.terminalWidth - len(id) - len(": ") - 1
if maxMsgLength < 0 { if maxMsgLength < 0 {
maxMsgLength = 0 maxMsgLength = 0
@ -310,23 +320,25 @@ func (display *ProgressDisplay) uncolorizeColumns(columns []string) []string {
return uncolorizedColumns return uncolorizedColumns
} }
func (display *ProgressDisplay) refreshSingleRow(row Row) { func (display *ProgressDisplay) refreshSingleRow(id string, maxIDLength int, row Row) {
colorizedColumns := row.ColorizedColumns() colorizedColumns := row.ColorizedColumns()
colorizedColumns[display.suffixColumn] += row.ColorizedSuffix() colorizedColumns[display.suffixColumn] += row.ColorizedSuffix()
uncolorizedColumns := display.uncolorizeColumns(colorizedColumns) uncolorizedColumns := display.uncolorizeColumns(colorizedColumns)
msg := display.getPaddedMessage(colorizedColumns, uncolorizedColumns) msg := display.getPaddedMessage(id, maxIDLength, colorizedColumns, uncolorizedColumns)
display.colorizeAndWriteProgress(makeActionProgress( if display.isTerminal {
uncolorizedColumns[0], msg, true /*showID*/)) display.colorizeAndWriteProgress(makeActionProgress(
id, msg, true /*showID*/))
} else {
display.writeSimpleMessage(msg)
}
} }
// Ensure our stored dimension info is up to date. Returns 'true' if the stored dimension info is // Ensure our stored dimension info is up to date. Returns 'true' if the stored dimension info is
// updated. // updated.
func (display *ProgressDisplay) updateDimensions() bool { func (display *ProgressDisplay) updateDimensions(rows []Row) {
updated := false
// don't do any refreshing if we're not in a terminal // don't do any refreshing if we're not in a terminal
if display.isTerminal { if display.isTerminal {
currentTerminalWidth, _, err := terminal.GetSize(int(os.Stdout.Fd())) currentTerminalWidth, _, err := terminal.GetSize(int(os.Stdout.Fd()))
@ -335,10 +347,9 @@ func (display *ProgressDisplay) updateDimensions() bool {
if currentTerminalWidth != display.terminalWidth { if currentTerminalWidth != display.terminalWidth {
// terminal width changed. Refresh everything // terminal width changed. Refresh everything
display.terminalWidth = currentTerminalWidth display.terminalWidth = currentTerminalWidth
updated = true
} }
for _, row := range display.rows { for _, row := range rows {
colorizedColumns := row.ColorizedColumns() colorizedColumns := row.ColorizedColumns()
uncolorizedColumns := display.uncolorizeColumns(colorizedColumns) uncolorizedColumns := display.uncolorizeColumns(colorizedColumns)
@ -354,25 +365,47 @@ func (display *ProgressDisplay) updateDimensions() bool {
if columnLength > display.maxColumnLengths[i] { if columnLength > display.maxColumnLengths[i] {
display.maxColumnLengths[i] = columnLength display.maxColumnLengths[i] = columnLength
updated = true
} }
} }
} }
} }
}
return updated func (display *ProgressDisplay) allRows() []Row {
result := []Row{}
if display.headerRow != nil {
result = append(result, display.headerRow)
}
for _, row := range display.resourceRows {
result = append(result, row)
}
return result
} }
func (display *ProgressDisplay) refreshAllRowsIfInTerminal() { func (display *ProgressDisplay) refreshAllRowsIfInTerminal() {
if display.isTerminal { if display.isTerminal && display.headerRow != nil {
// make sure our stored dimension info is up to date // make sure our stored dimension info is up to date
display.updateDimensions()
for _, row := range display.rows { rows := display.allRows()
display.refreshSingleRow(row) display.updateDimensions(rows)
// tree := display.generateTree()
maxIDLength := len(fmt.Sprintf("%v", len(rows)-1))
for i, row := range rows {
var id string
if i == 0 {
id = "#"
} else {
id = fmt.Sprintf("%v", i)
}
display.refreshSingleRow(id, maxIDLength, row)
} }
systemID := len(display.rows) systemID := len(rows)
printedHeader := false printedHeader := false
for _, payload := range display.systemEventPayloads { for _, payload := range display.systemEventPayloads {
@ -421,7 +454,7 @@ func (display *ProgressDisplay) processEndSteps() {
v.SetDone() v.SetDone()
if !display.isTerminal { if !display.isTerminal {
display.refreshSingleRow(v) display.refreshSingleRow("", 0, v)
} }
} else { } else {
// Explicitly transition the status so that we clear out any cached data for it. // Explicitly transition the status so that we clear out any cached data for it.
@ -461,7 +494,7 @@ func (display *ProgressDisplay) processEndSteps() {
wroteResourceHeader = true wroteResourceHeader = true
columns := row.ColorizedColumns() columns := row.ColorizedColumns()
display.writeSimpleMessage(" " + display.writeSimpleMessage(" " +
columns[idColumn] + ": " + // columns[idColumn] + ": " +
columns[typeColumn] + ": " + columns[typeColumn] + ": " +
columns[nameColumn]) columns[nameColumn])
} }
@ -561,13 +594,10 @@ func (display *ProgressDisplay) processNormalEvent(event engine.Event) {
row, has := display.eventUrnToResourceRow[eventUrn] row, has := display.eventUrnToResourceRow[eventUrn]
if !has { if !has {
id := fmt.Sprintf("%v", len(display.eventUrnToResourceRow)+1)
// first time we're hearing about this resource. Create an initial nearly-empty // first time we're hearing about this resource. Create an initial nearly-empty
// status for it, assigning it a nice short ID. // status for it, assigning it a nice short ID.
row = &resourceRowData{ row = &resourceRowData{
display: display, display: display,
id: id,
tick: display.currentTick, tick: display.currentTick,
diagInfo: &DiagInfo{}, diagInfo: &DiagInfo{},
step: engine.StepEventMetadata{Op: deploy.OpSame}, step: engine.StepEventMetadata{Op: deploy.OpSame},
@ -575,7 +605,7 @@ func (display *ProgressDisplay) processNormalEvent(event engine.Event) {
display.eventUrnToResourceRow[eventUrn] = row display.eventUrnToResourceRow[eventUrn] = row
display.ensureHeaderRow() display.ensureHeaderRow()
display.rows = append(display.rows, row) display.resourceRows = append(display.resourceRows, row)
} }
if event.Type == engine.ResourcePreEvent { if event.Type == engine.ResourcePreEvent {
@ -605,7 +635,7 @@ func (display *ProgressDisplay) processNormalEvent(event engine.Event) {
display.refreshAllRowsIfInTerminal() display.refreshAllRowsIfInTerminal()
} else { } else {
// otherwise, just print out this single row. // otherwise, just print out this single row.
display.refreshSingleRow(row) display.refreshSingleRow("", 0, row)
} }
} }
@ -626,9 +656,9 @@ func (display *ProgressDisplay) handleSystemEvent(payload engine.StdoutEventPayl
} }
func (display *ProgressDisplay) ensureHeaderRow() { func (display *ProgressDisplay) ensureHeaderRow() {
if len(display.rows) == 0 { if display.headerRow == nil {
// about to make our first status message. make sure we present the header line first. // about to make our first status message. make sure we present the header line first.
display.rows = append(display.rows, &headerRowData{display: display}) display.headerRow = &headerRowData{display: display}
} }
} }

View file

@ -12,7 +12,6 @@ import (
"github.com/pulumi/pulumi/pkg/engine" "github.com/pulumi/pulumi/pkg/engine"
"github.com/pulumi/pulumi/pkg/resource" "github.com/pulumi/pulumi/pkg/resource"
"github.com/pulumi/pulumi/pkg/resource/deploy" "github.com/pulumi/pulumi/pkg/resource/deploy"
"github.com/pulumi/pulumi/pkg/util/contract"
) )
type Row interface { type Row interface {
@ -61,7 +60,7 @@ func (data *headerRowData) ColorizedColumns() []string {
} else { } else {
statusColumn = header("Status") statusColumn = header("Status")
} }
data.columns = []string{"#", header("Resource Type"), header("Name"), statusColumn, header("Extra Info")} data.columns = []string{header("Resource Type"), header("Name"), statusColumn, header("Extra Info")}
} }
return data.columns return data.columns
@ -75,10 +74,6 @@ func (data *headerRowData) ColorizedSuffix() string {
type resourceRowData struct { type resourceRowData struct {
display *ProgressDisplay display *ProgressDisplay
// The simple short ID we have generated for the resource to present it to the user.
// Usually similar to the form: aws.Function("name")
id string
// The change that the engine wants apply to that resource. // The change that the engine wants apply to that resource.
step engine.StepEventMetadata step engine.StepEventMetadata
@ -151,11 +146,10 @@ func (data *resourceRowData) RecordDiagEvent(event engine.Event) {
type column int type column int
const ( const (
idColumn column = 0 typeColumn column = 0
typeColumn column = 1 nameColumn column = 1
nameColumn column = 2 statusColumn column = 2
statusColumn column = 3 infoColumn column = 3
infoColumn column = 4
) )
func (data *resourceRowData) ColorizedSuffix() string { func (data *resourceRowData) ColorizedSuffix() string {
@ -171,9 +165,6 @@ func (data *resourceRowData) ColorizedSuffix() string {
func (data *resourceRowData) ColorizedColumns() []string { func (data *resourceRowData) ColorizedColumns() []string {
step := data.step step := data.step
if step.Op == "" {
contract.Failf("Finishing a resource we never heard about: '%s'", data.id)
}
var name string var name string
var typ string var typ string
@ -185,8 +176,7 @@ func (data *resourceRowData) ColorizedColumns() []string {
typ = simplifyTypeName(data.step.URN.Type()) typ = simplifyTypeName(data.step.URN.Type())
} }
columns := make([]string, 5) columns := make([]string, 4)
columns[idColumn] = data.id
columns[typeColumn] = typ columns[typeColumn] = typ
columns[nameColumn] = name columns[nameColumn] = name