add default table presenter

This commit is contained in:
Alex Goodman 2020-07-23 21:48:12 -04:00
parent 0a0bc68e95
commit 32071b0bf1
No known key found for this signature in database
GPG key ID: 86E2870463D5E890
12 changed files with 162 additions and 1 deletions

View file

@ -59,7 +59,7 @@ func setGlobalCliOptions() {
// output & formatting options
flag = "output"
rootCmd.Flags().StringP(
flag, "o", presenter.TextPresenter.String(),
flag, "o", presenter.TablePresenter.String(),
fmt.Sprintf("report output formatter, options=%v", presenter.Options),
)
if err := viper.BindPFlag(flag, rootCmd.Flags().Lookup(flag)); err != nil {

1
go.mod
View file

@ -16,6 +16,7 @@ require (
github.com/hashicorp/go-version v1.2.0
github.com/mitchellh/go-homedir v1.1.0
github.com/mitchellh/mapstructure v1.3.1
github.com/olekukonko/tablewriter v0.0.4
github.com/rogpeppe/go-internal v1.5.2
github.com/sergi/go-diff v1.1.0
github.com/spf13/cobra v1.0.0

4
go.sum
View file

@ -587,6 +587,8 @@ github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOA
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54=
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-shellwords v1.0.10 h1:Y7Xqm8piKOO3v10Thp7Z36h4FYFjt5xB//6XvOrs2Gw=
github.com/mattn/go-shellwords v1.0.10/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y=
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
@ -632,6 +634,8 @@ github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWb
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
github.com/olekukonko/tablewriter v0.0.4 h1:vHD/YYe1Wolo78koG299f7V/VAS08c6IpCLn+Ejf/w8=
github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA=
github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=

View file

@ -6,17 +6,20 @@ const (
UnknownPresenter Option = iota
JSONPresenter
TextPresenter
TablePresenter
)
var optionStr = []string{
"UnknownPresenter",
"json",
"text",
"table",
}
var Options = []Option{
JSONPresenter,
TextPresenter,
TablePresenter,
}
type Option int
@ -27,6 +30,8 @@ func ParseOption(userStr string) Option {
return JSONPresenter
case strings.ToLower(TextPresenter.String()):
return TextPresenter
case strings.ToLower(TablePresenter.String()):
return TablePresenter
default:
return UnknownPresenter
}

View file

@ -5,6 +5,7 @@ import (
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/presenter/json"
"github.com/anchore/syft/syft/presenter/table"
"github.com/anchore/syft/syft/presenter/text"
"github.com/anchore/syft/syft/scope"
)
@ -20,6 +21,8 @@ func GetPresenter(option Option, s scope.Scope, catalog *pkg.Catalog) Presenter
return json.NewPresenter(catalog, s)
case TextPresenter:
return text.NewPresenter(catalog, s)
case TablePresenter:
return table.NewPresenter(catalog, s)
default:
return nil
}

View file

@ -0,0 +1,67 @@
package table
import (
"io"
"sort"
"github.com/olekukonko/tablewriter"
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/scope"
)
type Presenter struct {
catalog *pkg.Catalog
scope scope.Scope
}
func NewPresenter(catalog *pkg.Catalog, s scope.Scope) *Presenter {
return &Presenter{
catalog: catalog,
scope: s,
}
}
func (pres *Presenter) Present(output io.Writer) error {
rows := make([][]string, 0)
columns := []string{"Name", "Version", "Type"}
for p := range pres.catalog.Enumerate() {
row := []string{
p.Name,
p.Version,
p.Type.String(),
}
rows = append(rows, row)
}
// sort by name, version, then type
sort.SliceStable(rows, func(i, j int) bool {
for col := 0; col < len(columns); col++ {
if rows[i][0] != rows[j][0] {
return rows[i][col] < rows[j][col]
}
}
return false
})
table := tablewriter.NewWriter(output)
table.SetHeader(columns)
table.SetHeaderLine(false)
table.SetBorder(false)
table.SetAutoWrapText(false)
table.SetAutoFormatHeaders(true)
table.SetHeaderAlignment(tablewriter.ALIGN_LEFT)
table.SetAlignment(tablewriter.ALIGN_LEFT)
table.SetCenterSeparator("")
table.SetColumnSeparator("")
table.SetRowSeparator("")
table.SetTablePadding("\t")
table.SetNoWhiteSpace(true)
table.AppendBulk(rows)
table.Render()
return nil
}

View file

@ -0,0 +1,68 @@
package table
import (
"bytes"
"flag"
"testing"
"github.com/anchore/go-testutils"
"github.com/anchore/stereoscope/pkg/file"
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/scope"
"github.com/sergi/go-diff/diffmatchpatch"
)
var update = flag.Bool("update", false, "update the *.golden files for table presenters")
func TestTablePresenter(t *testing.T) {
var buffer bytes.Buffer
testImage := "image-simple"
catalog := pkg.NewCatalog()
img, cleanup := testutils.GetFixtureImage(t, "docker-archive", testImage)
defer cleanup()
// populate catalog with test data
catalog.Add(pkg.Package{
Name: "package-1",
Version: "1.0.1",
Source: []file.Reference{
*img.SquashedTree().File("/somefile-1.txt"),
},
Type: pkg.DebPkg,
})
catalog.Add(pkg.Package{
Name: "package-2",
Version: "2.0.1",
Source: []file.Reference{
*img.SquashedTree().File("/somefile-2.txt"),
},
Type: pkg.DebPkg,
})
s, err := scope.NewScopeFromImage(img, scope.AllLayersScope)
pres := NewPresenter(catalog, s)
// run presenter
err = pres.Present(&buffer)
if err != nil {
t.Fatal(err)
}
actual := buffer.Bytes()
if *update {
testutils.UpdateGoldenFileContents(t, actual)
}
var expected = testutils.GetGoldenFileContents(t)
if !bytes.Equal(expected, actual) {
dmp := diffmatchpatch.New()
diffs := dmp.DiffMain(string(actual), string(expected), true)
t.Errorf("mismatched output:\n%s", dmp.DiffPrettyText(diffs))
}
// TODO: add me back in when there is a JSON schema
// validateAgainstV1Schema(t, string(actual))
}

View file

@ -0,0 +1,6 @@
# Note: changes to this file will result in updating several test values. Consider making a new image fixture instead of editing this one.
FROM scratch
ADD file-1.txt /somefile-1.txt
ADD file-2.txt /somefile-2.txt
# note: adding a directory will behave differently on docker engine v18 vs v19
ADD target /

View file

@ -0,0 +1 @@
this file has contents

View file

@ -0,0 +1 @@
file-2 contents!

View file

@ -0,0 +1,2 @@
another file!
with lines...

View file

@ -0,0 +1,3 @@
NAME VERSION TYPE
package-1 1.0.1 deb
package-2 2.0.1 deb