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 @@
packages = ["."]
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]]
name = "github.com/onsi/ginkgo"
packages = [
......@@ -622,6 +610,6 @@
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "cb1ea2fcb93a4e383a77524868cca62997ccf5e8b862f2d8250c388870c4da49"
inputs-digest = "e99bb34d06691779ec855657a6aa077e80428aee4db1141c5849a84420033170"
solver-name = "gps-cdcl"
solver-version = 1
......@@ -32,6 +32,10 @@
name = "github.com/emicklei/go-restful-swagger12"
revision = "7524189396c68dc4b04d53852f9edc00f816b123"
[[constraint]]
name = "github.com/fatih/color"
revision = "5df930a27be2502f99b292b7cc09ebad4d0891f4"
[[constraint]]
name = "github.com/ghodss/yaml"
revision = "0ca9ea5df5451ffdf184b4428c902747c2c11cd7"
......
......@@ -24,10 +24,10 @@ import (
"strconv"
"strings"
"github.com/fatih/color"
"github.com/ksonnet/ksonnet/component"
param "github.com/ksonnet/ksonnet/metadata/params"
str "github.com/ksonnet/ksonnet/strings"
"github.com/olekukonko/tablewriter"
"github.com/pkg/errors"
"github.com/spf13/afero"
......@@ -247,6 +247,11 @@ type paramDiffRecord struct {
// Run executes the diffing of environment params.
func (c *ParamDiffCmd) Run(out io.Writer) error {
const (
componentHeader = "COMPONENT"
paramHeader = "PARAM"
)
manager, err := manager()
if err != nil {
return err
......@@ -276,35 +281,68 @@ func (c *ParamDiffCmd) Run(out io.Writer) error {
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 {
paramNames := collectParams(params1[componentName], params2[componentName])
for _, paramName := range paramNames {
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]
}
if p, ok = params2[componentName]; ok {
if p, ok := params2[componentName]; ok {
v2 = p[paramName]
}
row := []string{
var bgColor *color.Color
if v1 == "" {
bgColor = color.New(color.BgGreen)
} else if v2 == "" {
bgColor = color.New(color.BgRed)
} else if v1 != v2 {
bgColor = color.New(color.BgYellow)
}
body = append(body, str.Row{
Content: []string{
componentName,
paramName,
v1,
v2,
},
Color: bgColor,
})
}
}
rows = append(rows, row)
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
}
......@@ -347,24 +385,3 @@ func collectParams(param1, param2 param.Params) []string {
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 (
"strings"
"github.com/PuerkitoBio/purell"
"github.com/fatih/color"
)
// IsASCIIIdentifier takes a string and returns true if the string does not
......@@ -53,10 +54,70 @@ func NormalizeURL(s string) (string, error) {
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) {
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
for _, row := range rows {
if rowLen := len(row); rowLen > maxRowLen {
if rowLen := len(row.Content); rowLen > maxRowLen {
maxRowLen = rowLen
}
}
......@@ -64,12 +125,12 @@ func PadRows(rows [][]string) (string, error) {
colMaxes := make([]int, maxRowLen)
for currCol := 0; currCol < maxRowLen; currCol++ {
for _, row := range rows {
rowLen := len(row)
rowLen := len(row.Content)
if currCol >= rowLen {
continue
}
cellLen := len(row[currCol])
cellLen := len(row.Content[currCol])
if currCol < rowLen && colMaxes[currCol] < cellLen {
colMaxes[currCol] = cellLen
}
......@@ -77,36 +138,30 @@ func PadRows(rows [][]string) (string, error) {
}
var err error
var buf bytes.Buffer
for _, row := range rows {
rowLen := len(row)
for j, col := range row {
var buf bytes.Buffer
for j, col := range row.Content {
_, err = buf.WriteString(col)
if err != nil {
return "", err
return nil, err
}
// Don't add space to the end of the last column.
if j >= rowLen-1 {
if j >= len(row.Content)-1 {
continue
}
padSize := colMaxes[j] + 1 - len(col)
_, err = buf.WriteString(strings.Repeat(" ", padSize))
if err != nil {
return "", err
return nil, err
}
}
// Add a newline to the end of the row (but only if there is more
// than 0 rows).
_, err = buf.WriteString("\n")
if err != nil {
return "", err
}
result = append(result, FormattedRow{Content: buf.String(), Color: row.Color})
}
return buf.String(), nil
return result, nil
}
// AppendToPath appends one or more paths to the specified original path.
......
......@@ -16,7 +16,6 @@
package strings
import (
"fmt"
"testing"
"github.com/stretchr/testify/require"
......@@ -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) {
tests := []struct {
input [][]string
......@@ -174,7 +225,6 @@ Hi World
},
}
for _, test := range tests {
fmt.Println(test.expected)
padded, err := PadRows(test.input)
if err != nil {
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
}
return isEastAsian(locale)
}
package runewidth
import (
"syscall"
)
var (
kernel32 = syscall.NewLazyDLL("kernel32")
procGetConsoleOutputCP = kernel32.NewProc("GetConsoleOutputCP")
)
// IsEastAsian return true if the current locale is CJK
func IsEastAsian() bool {
r1, _, _ := procGetConsoleOutputCP.Call()
if r1 == 0 {
return false
}
switch int(r1) {
case 932, 51932, 936, 949, 950:
return true
}
return false
}
language: go
go:
- 1.1
- 1.2
- 1.3
- 1.4
- 1.5
- 1.6
- 1.7
- 1.8
- tip
Copyright (C) 2014 by Oleku Konko
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.
\ No newline at end of file
ASCII Table Writer
=========
[![Build Status](https://travis-ci.org/olekukonko/tablewriter.png?branch=master)](https://travis-ci.org/olekukonko/tablewriter)
[![Total views](https://img.shields.io/sourcegraph/rrc/github.com/olekukonko/tablewriter.svg)](https://sourcegraph.com/github.com/olekukonko/tablewriter)
[![Godoc](https://godoc.org/github.com/olekukonko/tablewriter?status.svg)](https://godoc.org/github.com/olekukonko/tablewriter)
Generate ASCII table on the fly ... Installation is simple as
go get github.com/olekukonko/tablewriter
#### Features
- Automatic Padding
- Support Multiple Lines
- Supports Alignment
- Support Custom Separators
- Automatic Alignment of numbers & percentage
- Write directly to http , file etc via `io.Writer`
- Read directly from CSV file
- Optional row line via `SetRowLine`
- Normalise table header
- Make CSV Headers optional
- Enable or disable table border
- Set custom footer support
- Optional identical cells merging
- Set custom caption