Unverified Commit e428442c authored by Bryan Liles's avatar Bryan Liles Committed by GitHub
Browse files

Merge pull request #344 from jessicayuen/param-diff

Fix formatting for param diff
parents aed92832 52af3f6f
...@@ -255,18 +255,6 @@ ...@@ -255,18 +255,6 @@
packages = ["."] packages = ["."]
revision = "fc9e8d8ef48496124e79ae0df75490096eccf6fe" revision = "fc9e8d8ef48496124e79ae0df75490096eccf6fe"
[[projects]]
name = "github.com/mattn/go-runewidth"
packages = ["."]
revision = "9e777a8366cce605130a531d2cd6363d07ad7317"
version = "v0.0.2"
[[projects]]
branch = "master"
name = "github.com/olekukonko/tablewriter"
packages = ["."]
revision = "b8a9be070da40449e501c3c4730a889e42d87a9e"
[[projects]] [[projects]]
name = "github.com/onsi/ginkgo" name = "github.com/onsi/ginkgo"
packages = [ packages = [
...@@ -622,6 +610,6 @@ ...@@ -622,6 +610,6 @@
[solve-meta] [solve-meta]
analyzer-name = "dep" analyzer-name = "dep"
analyzer-version = 1 analyzer-version = 1
inputs-digest = "cb1ea2fcb93a4e383a77524868cca62997ccf5e8b862f2d8250c388870c4da49" inputs-digest = "e99bb34d06691779ec855657a6aa077e80428aee4db1141c5849a84420033170"
solver-name = "gps-cdcl" solver-name = "gps-cdcl"
solver-version = 1 solver-version = 1
...@@ -32,6 +32,10 @@ ...@@ -32,6 +32,10 @@
name = "github.com/emicklei/go-restful-swagger12" name = "github.com/emicklei/go-restful-swagger12"
revision = "7524189396c68dc4b04d53852f9edc00f816b123" revision = "7524189396c68dc4b04d53852f9edc00f816b123"
[[constraint]]
name = "github.com/fatih/color"
revision = "5df930a27be2502f99b292b7cc09ebad4d0891f4"
[[constraint]] [[constraint]]
name = "github.com/ghodss/yaml" name = "github.com/ghodss/yaml"
revision = "0ca9ea5df5451ffdf184b4428c902747c2c11cd7" revision = "0ca9ea5df5451ffdf184b4428c902747c2c11cd7"
......
...@@ -24,10 +24,10 @@ import ( ...@@ -24,10 +24,10 @@ import (
"strconv" "strconv"
"strings" "strings"
"github.com/fatih/color"
"github.com/ksonnet/ksonnet/component" "github.com/ksonnet/ksonnet/component"
param "github.com/ksonnet/ksonnet/metadata/params" param "github.com/ksonnet/ksonnet/metadata/params"
str "github.com/ksonnet/ksonnet/strings" str "github.com/ksonnet/ksonnet/strings"
"github.com/olekukonko/tablewriter"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/spf13/afero" "github.com/spf13/afero"
...@@ -247,6 +247,11 @@ type paramDiffRecord struct { ...@@ -247,6 +247,11 @@ type paramDiffRecord struct {
// Run executes the diffing of environment params. // Run executes the diffing of environment params.
func (c *ParamDiffCmd) Run(out io.Writer) error { func (c *ParamDiffCmd) Run(out io.Writer) error {
const (
componentHeader = "COMPONENT"
paramHeader = "PARAM"
)
manager, err := manager() manager, err := manager()
if err != nil { if err != nil {
return err return err
...@@ -276,35 +281,68 @@ func (c *ParamDiffCmd) Run(out io.Writer) error { ...@@ -276,35 +281,68 @@ func (c *ParamDiffCmd) Run(out io.Writer) error {
componentNames := collectComponents(params1, params2) componentNames := collectComponents(params1, params2)
var rows [][]string headers := str.Row{
Content: []string{componentHeader, paramHeader, c.env1, c.env2},
}
var body []str.Row
for _, componentName := range componentNames { for _, componentName := range componentNames {
paramNames := collectParams(params1[componentName], params2[componentName]) paramNames := collectParams(params1[componentName], params2[componentName])
for _, paramName := range paramNames { for _, paramName := range paramNames {
var v1, v2 string var v1, v2 string
var ok bool
var p param.Params
if p, ok = params1[componentName]; ok { if p, ok := params1[componentName]; ok {
v1 = p[paramName] v1 = p[paramName]
} }
if p, ok = params2[componentName]; ok { if p, ok := params2[componentName]; ok {
v2 = p[paramName] v2 = p[paramName]
} }
row := []string{ var bgColor *color.Color
componentName, if v1 == "" {
paramName, bgColor = color.New(color.BgGreen)
v1, } else if v2 == "" {
v2, bgColor = color.New(color.BgRed)
} else if v1 != v2 {
bgColor = color.New(color.BgYellow)
} }
rows = append(rows, row) body = append(body, str.Row{
Content: []string{
componentName,
paramName,
v1,
v2,
},
Color: bgColor,
})
}
}
formatted, err := str.Table(headers, body)
if err != nil {
return err
}
for _, row := range formatted {
if row.Color != nil {
_, err = row.Color.Fprint(out, row.Content)
if err != nil {
return err
}
// Must print new line separately otherwise color alignment will be
// incorrect.
fmt.Println()
} else {
_, err = fmt.Fprintln(out, row.Content)
if err != nil {
return err
}
} }
} }
printTable([]string{"COMPONENT", "PARAM", c.env1, c.env2}, rows)
return nil return nil
} }
...@@ -347,24 +385,3 @@ func collectParams(param1, param2 param.Params) []string { ...@@ -347,24 +385,3 @@ func collectParams(param1, param2 param.Params) []string {
return names return names
} }
func printTable(headers []string, data [][]string) {
headerLens := make([]int, len(headers))
for i := range headers {
headerLens[i] = len(headers[i])
}
for i := range headerLens {
headers[i] = fmt.Sprintf("%s\n%s", headers[i], strings.Repeat("=", headerLens[i]))
}
table := tablewriter.NewWriter(os.Stdout)
table.SetHeader(headers)
table.SetCenterSeparator("")
table.SetColumnSeparator("")
table.SetRowSeparator("")
table.SetRowLine(false)
table.SetBorder(false)
table.AppendBulk(data)
table.Render()
}
...@@ -22,6 +22,7 @@ import ( ...@@ -22,6 +22,7 @@ import (
"strings" "strings"
"github.com/PuerkitoBio/purell" "github.com/PuerkitoBio/purell"
"github.com/fatih/color"
) )
// IsASCIIIdentifier takes a string and returns true if the string does not // IsASCIIIdentifier takes a string and returns true if the string does not
...@@ -53,10 +54,70 @@ func NormalizeURL(s string) (string, error) { ...@@ -53,10 +54,70 @@ func NormalizeURL(s string) (string, error) {
return purell.NormalizeURLString(s, purell.FlagsUsuallySafeGreedy) return purell.NormalizeURLString(s, purell.FlagsUsuallySafeGreedy)
} }
// Row represents a table row.
type Row struct {
Content []string
Color *color.Color
}
// FormattedRow represents a formatted table row.
type FormattedRow struct {
Content string
Color *color.Color
}
// Table outputs a properly-aligned table.
func Table(headers Row, body []Row) ([]FormattedRow, error) {
var dividers []string
for _, header := range headers.Content {
dividers = append(dividers, strings.Repeat("=", len(header)))
}
var rows []Row
rows = append(rows, headers)
rows = append(rows, Row{Content: dividers})
for _, row := range body {
rows = append(rows, row)
}
return padRows(rows)
}
// PadRows takes a string matrix and returns a string representation of a
// properly-aligned table.
func PadRows(rows [][]string) (string, error) { func PadRows(rows [][]string) (string, error) {
var tableRows []Row
for _, row := range rows {
var tableRow Row
for _, col := range row {
tableRow.Content = append(tableRow.Content, col)
}
tableRows = append(tableRows, tableRow)
}
formattedRows, err := padRows(tableRows)
if err != nil {
return "", err
}
var buf bytes.Buffer
for _, row := range formattedRows {
_, err := buf.WriteString(fmt.Sprintln(row.Content))
if err != nil {
return "", err
}
}
return buf.String(), nil
}
func padRows(rows []Row) ([]FormattedRow, error) {
var result []FormattedRow
maxRowLen := 0 maxRowLen := 0
for _, row := range rows { for _, row := range rows {
if rowLen := len(row); rowLen > maxRowLen { if rowLen := len(row.Content); rowLen > maxRowLen {
maxRowLen = rowLen maxRowLen = rowLen
} }
} }
...@@ -64,12 +125,12 @@ func PadRows(rows [][]string) (string, error) { ...@@ -64,12 +125,12 @@ func PadRows(rows [][]string) (string, error) {
colMaxes := make([]int, maxRowLen) colMaxes := make([]int, maxRowLen)
for currCol := 0; currCol < maxRowLen; currCol++ { for currCol := 0; currCol < maxRowLen; currCol++ {
for _, row := range rows { for _, row := range rows {
rowLen := len(row) rowLen := len(row.Content)
if currCol >= rowLen { if currCol >= rowLen {
continue continue
} }
cellLen := len(row[currCol]) cellLen := len(row.Content[currCol])
if currCol < rowLen && colMaxes[currCol] < cellLen { if currCol < rowLen && colMaxes[currCol] < cellLen {
colMaxes[currCol] = cellLen colMaxes[currCol] = cellLen
} }
...@@ -77,36 +138,30 @@ func PadRows(rows [][]string) (string, error) { ...@@ -77,36 +138,30 @@ func PadRows(rows [][]string) (string, error) {
} }
var err error var err error
var buf bytes.Buffer
for _, row := range rows { for _, row := range rows {
rowLen := len(row) var buf bytes.Buffer
for j, col := range row { for j, col := range row.Content {
_, err = buf.WriteString(col) _, err = buf.WriteString(col)
if err != nil { if err != nil {
return "", err return nil, err
} }
// Don't add space to the end of the last column. // Don't add space to the end of the last column.
if j >= rowLen-1 { if j >= len(row.Content)-1 {
continue continue
} }
padSize := colMaxes[j] + 1 - len(col) padSize := colMaxes[j] + 1 - len(col)
_, err = buf.WriteString(strings.Repeat(" ", padSize)) _, err = buf.WriteString(strings.Repeat(" ", padSize))
if err != nil { if err != nil {
return "", err return nil, err
} }
} }
// Add a newline to the end of the row (but only if there is more result = append(result, FormattedRow{Content: buf.String(), Color: row.Color})
// than 0 rows).
_, err = buf.WriteString("\n")
if err != nil {
return "", err
}
} }
return buf.String(), nil return result, nil
} }
// AppendToPath appends one or more paths to the specified original path. // AppendToPath appends one or more paths to the specified original path.
......
...@@ -16,7 +16,6 @@ ...@@ -16,7 +16,6 @@
package strings package strings
import ( import (
"fmt"
"testing" "testing"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
...@@ -112,6 +111,58 @@ func TestNormalizeURL(t *testing.T) { ...@@ -112,6 +111,58 @@ func TestNormalizeURL(t *testing.T) {
} }
} }
func TestTable(t *testing.T) {
tests := []struct {
header Row
body []Row
expected []FormattedRow
}{
{
header: Row{
Content: []string{
"FOO-HEADER",
"BAR-HEADER",
},
},
body: []Row{
Row{
Content: []string{
"foo",
"bar",
},
},
Row{
Content: []string{
"another-foo",
"another-bar",
},
},
},
expected: []FormattedRow{
FormattedRow{
Content: "FOO-HEADER BAR-HEADER",
},
FormattedRow{
Content: "========== ==========",
},
FormattedRow{
Content: "foo bar",
},
FormattedRow{
Content: "another-foo another-bar",
},
},
},
}
for _, test := range tests {
formatted, err := Table(test.header, test.body)
if err != nil {
t.Error(err)
}
require.EqualValues(t, test.expected, formatted)
}
}
func TestPadRows(t *testing.T) { func TestPadRows(t *testing.T) {
tests := []struct { tests := []struct {
input [][]string input [][]string
...@@ -174,7 +225,6 @@ Hi World ...@@ -174,7 +225,6 @@ Hi World
}, },
} }
for _, test := range tests { for _, test := range tests {
fmt.Println(test.expected)
padded, err := PadRows(test.input) padded, err := PadRows(test.input)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
......
language: go
go:
- tip
before_install:
- go get github.com/mattn/goveralls
- go get golang.org/x/tools/cmd/cover
script:
- $HOME/gopath/bin/goveralls -repotoken lAKAWPzcGsD3A8yBX3BGGtRUdJ6CaGERL
The MIT License (MIT)
Copyright (c) 2016 Yasuhiro Matsumoto
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
go-runewidth
============
[![Build Status](https://travis-ci.org/mattn/go-runewidth.png?branch=master)](https://travis-ci.org/mattn/go-runewidth)
[![Coverage Status](https://coveralls.io/repos/mattn/go-runewidth/badge.png?branch=HEAD)](https://coveralls.io/r/mattn/go-runewidth?branch=HEAD)
[![GoDoc](https://godoc.org/github.com/mattn/go-runewidth?status.svg)](http://godoc.org/github.com/mattn/go-runewidth)
[![Go Report Card](https://goreportcard.com/badge/github.com/mattn/go-runewidth)](https://goreportcard.com/report/github.com/mattn/go-runewidth)
Provides functions to get fixed width of the character or string.
Usage
-----
```go
runewidth.StringWidth("つのだ☆HIRO") == 12
```
Author
------
Yasuhiro Matsumoto
License
-------
under the MIT License: http://mattn.mit-license.org/2013
This diff is collapsed.
// +build js
package runewidth
func IsEastAsian() bool {
// TODO: Implement this for the web. Detect east asian in a compatible way, and return true.
return false
}
// +build !windows,!js
package runewidth
import (
"os"
"regexp"
"strings"
)
var reLoc = regexp.MustCompile(`^[a-z][a-z][a-z]?(?:_[A-Z][A-Z])?\.(.+)`)
var mblenTable = map[string]int{
"utf-8": 6,
"utf8": 6,
"jis": 8,
"eucjp": 3,
"euckr": 2,
"euccn": 2,
"sjis": 2,
"cp932": 2,
"cp51932": 2,
"cp936": 2,
"cp949": 2,
"cp950": 2,
"big5": 2,
"gbk": 2,
"gb2312": 2,
}
func isEastAsian(locale string) bool {
charset := strings.ToLower(locale)
r := reLoc.FindStringSubmatch(locale)
if len(r) == 2 {
charset = strings.ToLower(r[1])
}
if strings.HasSuffix(charset, "@cjk_narrow") {
return false
}
for pos, b := range []byte(charset) {
if b == '@' {
charset = charset[:pos]
break
}
}
max := 1
if m, ok := mblenTable[charset]; ok {
max = m
}
if max > 1 && (charset[0] != 'u' ||
strings.HasPrefix(locale, "ja") ||
strings.HasPrefix(locale, "ko") ||
strings.HasPrefix(locale, "zh")) {
return true
}
return false
}
// IsEastAsian return true if the current locale is CJK
func IsEastAsian() bool {
locale := os.Getenv("LC_CTYPE")
if locale == "" {
locale = os.Getenv("LANG")
}
// ignore C locale
if locale == "POSIX" || locale == "C" {
return false
}
if len(locale) > 1 && locale[0] == 'C' && (locale[1] == '.' || locale[1] == '-') {
return false