Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

plan: pretty-printing terminal output #22

Merged
merged 29 commits into from
Jun 8, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
5414c70
plan: pretty-printing terminal output
langston-barrett Jun 2, 2016
5496941
Address Brian's comments
langston-barrett Jun 2, 2016
7a64675
remove extraneous comment
langston-barrett Jun 2, 2016
ccbe93c
remove fmt.Sprint calls from skittles calls
langston-barrett Jun 2, 2016
3428fca
vendor plan pretty print dependency (skittles)
langston-barrett Jun 2, 2016
dc73111
remove unused global variable `nocolor`
langston-barrett Jun 3, 2016
0a2b859
consolidate PlanResult and planresult_print
langston-barrett Jun 3, 2016
ca5d0ec
separate tests logically
langston-barrett Jun 3, 2016
c8667f7
use String instead of Pretty in sorting test
langston-barrett Jun 3, 2016
5a3f0a0
Use template to pretty print results
langston-barrett Jun 3, 2016
f28e063
make condFmt more general
langston-barrett Jun 3, 2016
0f6732c
give applyresult and planresult a common interface: prettyprinter
langston-barrett Jun 3, 2016
a46f5a5
trim newlines in planresult template as well
langston-barrett Jun 3, 2016
9d9c662
cant trim the newline from a boolean!
langston-barrett Jun 3, 2016
ecb4bfb
add a newline between each printed Result
langston-barrett Jun 3, 2016
c9f289f
Use strings.Join where appropriate
langston-barrett Jun 3, 2016
3839402
move condFmt to a utils file
langston-barrett Jun 3, 2016
c1575c5
Warn on templating errors
langston-barrett Jun 3, 2016
c688a81
Convert to a different output format/coloring
langston-barrett Jun 6, 2016
95a914d
highlight whole path on apply
langston-barrett Jun 6, 2016
bf288e8
Add space after plus/minus
langston-barrett Jun 6, 2016
2740b71
add plus or minus to the output of `plan`
langston-barrett Jun 6, 2016
55b523c
Merge branch 'master' into feature/plan-pretty-printing
langston-barrett Jun 7, 2016
7af2547
Merge branch 'master' into feature/plan-pretty-printing
langston-barrett Jun 7, 2016
abf5f1e
Print shouldn't decide whether or not to use color
langston-barrett Jun 7, 2016
8c68f5c
fix accidental comment
langston-barrett Jun 7, 2016
837284c
Print tests no longer need Viper
langston-barrett Jun 7, 2016
7c1a22e
plan shouldn't print results twice
langston-barrett Jun 7, 2016
27df047
Merge branch 'master' into feature/plan-pretty-printing
langston-barrett Jun 8, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions cmd/apply.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,13 +83,19 @@ var applyCmd = &cobra.Command{
logger.WithError(err).Fatal("applying failed")
}

// giving the results the type exec.Results allows us to pretty-print them
var typedResults exec.Results
for _, result := range results {
typedResults = append(typedResults, result)
}
fmt.Println(typedResults.Print(UseColor()))

// count successes and failures to print summary
var counts struct {
results, success, failures int
}

fmt.Print("\n")
for _, result := range results {
fmt.Println(result)
counts.results++
if result.Success {
counts.success++
Expand Down
10 changes: 8 additions & 2 deletions cmd/plan.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,13 +68,19 @@ var planCmd = &cobra.Command{
logger.WithError(err).Fatal("planning failed")
}

// giving the results the type exec.Results allows us to pretty-print them
var typedResults exec.Results
for _, result := range results {
typedResults = append(typedResults, result)
}
fmt.Println(typedResults.Print(UseColor()))

// count results and changes to print summary
var counts struct {
results, changes int
}

fmt.Print("\n")
for _, result := range results {
fmt.Println(result)
counts.results++
if result.WillChange {
counts.changes++
Expand Down
1 change: 1 addition & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ func init() {
cobra.OnInitialize(initConfig)

RootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.converge.yaml)")
RootCmd.PersistentFlags().BoolP("nocolor", "n", false, "force colorless output")

viperBindPFlags(RootCmd.PersistentFlags())
}
Expand Down
19 changes: 0 additions & 19 deletions exec/apply.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
package exec

import (
"fmt"
"sync"

"golang.org/x/net/context"
Expand All @@ -24,24 +23,6 @@ import (
"github.com/asteris-llc/converge/resource"
)

// ApplyResult contains the result of a resource check
type ApplyResult struct {
Path string
OldStatus string
NewStatus string
Success bool
}

func (p *ApplyResult) String() string {
return fmt.Sprintf(
"%s:\n\tStatus: %q => %q\n\tSuccess: %t",
p.Path,
p.OldStatus,
p.NewStatus,
p.Success,
)
}

// ApplyWithStatus applies the operations checked in plan
func ApplyWithStatus(ctx context.Context, graph *load.Graph, plan []*PlanResult, status chan<- *StatusMessage) (results []*ApplyResult, err error) {
// transform checks into something we can look up easily
Expand Down
67 changes: 67 additions & 0 deletions exec/applyresult.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// Copyright © 2016 Asteris, LLC
//
// 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.

package exec

import (
"bytes"
"strings"
"text/template"

"github.com/Sirupsen/logrus"
"github.com/acmacalister/skittles"
)

// ApplyResult contains the result of a resource check
type ApplyResult struct {
Path string
OldStatus string
NewStatus string
Success bool
}

func (a *ApplyResult) string(pretty bool) string {
funcs := map[string]interface{}{
"plusOrMinus": plusOrMinus(pretty),
"redOrGreen": condFmt(pretty, func(in interface{}) string {
if a.Success {
return skittles.Green(in)
}
return skittles.Red(in)
}),
"trimNewline": func(in string) string { return strings.TrimSuffix(in, "\n") },
}
tmplStr := `{{plusOrMinus .Success}} {{redOrGreen .Path}}:
Status: "{{trimNewline .OldStatus}}" => "{{trimNewline .NewStatus}}"
Success: {{redOrGreen .Success}}`
tmpl := template.Must(template.New("").Funcs(funcs).Parse(tmplStr))

var buf bytes.Buffer
err := tmpl.Execute(&buf, a)
if err != nil {
logrus.WithError(err).Warn("error while outputting the result of `apply`")
}
return buf.String()
}

// Pretty pretty-prints an ApplyResult with ANSI terminal colors.
func (a *ApplyResult) Pretty() string {
return a.string(true)
}

// String satisfies the Stringer interface, and is used to print a string
// representation of a ApplyResult.
func (a *ApplyResult) String() string {
return a.string(false)
}
54 changes: 54 additions & 0 deletions exec/applyresult_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Copyright © 2016 Asteris, LLC
//
// 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.

package exec_test

import (
"testing"

"github.com/asteris-llc/converge/exec"
"github.com/stretchr/testify/assert"
)

var applyResult1 = &exec.ApplyResult{
Path: "moduleC/submodule1",
OldStatus: "old",
NewStatus: "new",
Success: true,
}

var applyResult2 = &exec.ApplyResult{
Path: "moduleD/submodule1",
OldStatus: "old",
NewStatus: "old",
Success: false,
}

func TestApplyResultString(t *testing.T) {
t.Parallel()

expected1 := "+ moduleC/submodule1:\n\tStatus: \"old\" => \"new\"\n\tSuccess: true"
expected2 := "- moduleD/submodule1:\n\tStatus: \"old\" => \"old\"\n\tSuccess: false"
assert.Equal(t, expected1, applyResult1.String())
assert.Equal(t, expected2, applyResult2.String())
}

func TestApplyResultPretty(t *testing.T) {
t.Parallel()

expected1 := "\x1b[32m+\x1b[0m \x1b[32mmoduleC/submodule1\x1b[0m:\n\tStatus: \"old\" => \"new\"\n\tSuccess: \x1b[32mtrue\x1b[0m"
expected2 := "\x1b[31m-\x1b[0m \x1b[31mmoduleD/submodule1\x1b[0m:\n\tStatus: \"old\" => \"old\"\n\tSuccess: \x1b[31mfalse\x1b[0m"
assert.Equal(t, expected1, applyResult1.Pretty())
assert.Equal(t, expected2, applyResult2.Pretty())
}
17 changes: 0 additions & 17 deletions exec/plan.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
package exec

import (
"fmt"
"sync"

"golang.org/x/net/context"
Expand All @@ -24,22 +23,6 @@ import (
"github.com/asteris-llc/converge/resource"
)

// PlanResult contains the result of a resource check
type PlanResult struct {
Path string
CurrentStatus string
WillChange bool
}

func (p *PlanResult) String() string {
return fmt.Sprintf(
"%s:\n\tCurrently: %q\n\tWill Change: %t",
p.Path,
p.CurrentStatus,
p.WillChange,
)
}

// PlanWithStatus plans the operations to be performed and outputs status
func PlanWithStatus(ctx context.Context, graph *load.Graph, status chan<- *StatusMessage) (results []*PlanResult, err error) {
lock := new(sync.Mutex)
Expand Down
66 changes: 66 additions & 0 deletions exec/planresult.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// Copyright © 2016 Asteris, LLC
//
// 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.

package exec

import (
"bytes"
"strings"
"text/template"

"github.com/Sirupsen/logrus"
"github.com/acmacalister/skittles"
)

// PlanResult contains the result of a resource check
type PlanResult struct {
Path string
CurrentStatus string
WillChange bool
}

func (p *PlanResult) string(pretty bool) string {
funcs := map[string]interface{}{
"plusOrMinus": plusOrMinus(pretty),
"blueOrYellow": condFmt(pretty, func(in interface{}) string {
if p.WillChange {
return skittles.Yellow(in)
}
return skittles.Blue(in)
}),
"trimNewline": func(in string) string { return strings.TrimSuffix(in, "\n") },
}
tmplStr := `{{plusOrMinus .WillChange}} {{blueOrYellow (trimNewline .Path)}}:
Currently: {{trimNewline .CurrentStatus}}
Will Change: {{blueOrYellow .WillChange}}`
tmpl := template.Must(template.New("").Funcs(funcs).Parse(tmplStr))

var buf bytes.Buffer
err := tmpl.Execute(&buf, p)
if err != nil {
logrus.WithError(err).Warn("error while outputting the result of `plan`")
}
return buf.String()
}

// Pretty pretty-prints a PlanResult with ANSI terminal colors.
func (p *PlanResult) Pretty() string {
return p.string(true)
}

// String satisfies the Stringer interface, and is used to print a string
// representation of a PlanResult.
func (p *PlanResult) String() string {
return p.string(false)
}
52 changes: 52 additions & 0 deletions exec/planresult_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// Copyright © 2016 Asteris, LLC
//
// 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.

package exec_test

import (
"testing"

"github.com/asteris-llc/converge/exec"
"github.com/stretchr/testify/assert"
)

var planResult1 = &exec.PlanResult{
Path: "moduleA/submodule1",
CurrentStatus: "status",
WillChange: true,
}

var planResult2 = &exec.PlanResult{
Path: "moduleB/submodule1",
CurrentStatus: "status",
WillChange: false,
}

func TestPlanResultString(t *testing.T) {
t.Parallel()

expected1 := "+ moduleA/submodule1:\n\tCurrently: status\n\tWill Change: true"
expected2 := "- moduleB/submodule1:\n\tCurrently: status\n\tWill Change: false"
assert.Equal(t, expected1, planResult1.String())
assert.Equal(t, expected2, planResult2.String())
}

func TestPlanResultPretty(t *testing.T) {
t.Parallel()

expected1 := "\x1b[32m+\x1b[0m \x1b[33mmoduleA/submodule1\x1b[0m:\n\tCurrently: status\n\tWill Change: \x1b[33mtrue\x1b[0m"
expected2 := "\x1b[31m-\x1b[0m \x1b[34mmoduleB/submodule1\x1b[0m:\n\tCurrently: status\n\tWill Change: \x1b[34mfalse\x1b[0m"
assert.Equal(t, expected1, planResult1.Pretty())
assert.Equal(t, expected2, planResult2.Pretty())
}
Loading