Skip to content
This repository has been archived by the owner on May 6, 2022. It is now read-only.

Commit

Permalink
make it generic
Browse files Browse the repository at this point in the history
Signed-off-by: Doug Davis <dug@us.ibm.com>
  • Loading branch information
Doug Davis committed Jul 26, 2018
1 parent b9a47ba commit 53becd4
Show file tree
Hide file tree
Showing 11 changed files with 139 additions and 65 deletions.
21 changes: 1 addition & 20 deletions cmd/svcat/output/class.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,31 +34,12 @@ func getClassStatusText(status v1beta1.ClusterServiceClassStatus) string {
func writeClassListTable(w io.Writer, classes []servicecatalog.Class) {
t := NewListTable(w)

// Pre-parse the data so we allow the last column to be really wide.
// We can't set the MinWidth after data has been loaded
maxNameWidth := len("Name")
maxNSWidth := len("Namespace")
maxDescWidth := len("Description")
for _, class := range classes {
if tmp := len(class.GetExternalName()); tmp > maxNameWidth {
maxNameWidth = tmp
}
if tmp := len(class.GetNamespace()); tmp > maxNSWidth {
maxNSWidth = tmp
}
if tmp := len(class.GetDescription()); tmp > maxDescWidth {
maxDescWidth = tmp
}
}
if tmp := (80 - (maxNameWidth + maxNSWidth + 11)); tmp > maxDescWidth {
t.SetColMinWidth(2, tmp)
}

t.SetHeader([]string{
"Name",
"Namespace",
"Description",
})
t.SetVariableColumn(3)

for _, class := range classes {
t.Append([]string{
Expand Down
24 changes: 1 addition & 23 deletions cmd/svcat/output/plan.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,36 +57,14 @@ func writePlanListTable(w io.Writer, plans []v1beta1.ClusterServicePlan, classNa
"Class",
"Description",
})

// Pre-parse the data so we allow the last column to be really wide.
// We can't set the MinWidth after data has been loaded
maxNameWidth := len("Name")
maxClassWidth := len("Class")
maxDescWidth := len("Description")

for _, plan := range plans {
if tmp := len(plan.Spec.ExternalName); tmp > maxNameWidth {
maxNameWidth = tmp
}
tmp := len(classNames[plan.Spec.ClusterServiceClassRef.Name])
if tmp > maxClassWidth {
maxClassWidth = tmp
}
if tmp := len(plan.Spec.Description); tmp > maxDescWidth {
maxDescWidth = tmp
}
}
if tmp := (80 - (maxNameWidth + maxClassWidth + 11)); tmp > maxDescWidth {
t.SetColMinWidth(2, tmp)
}

for _, plan := range plans {
t.Append([]string{
plan.Spec.ExternalName,
classNames[plan.Spec.ClusterServiceClassRef.Name],
plan.Spec.Description,
})
}
t.SetVariableColumn(3)

t.Render()
}
Expand Down
116 changes: 114 additions & 2 deletions cmd/svcat/output/table.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,124 @@ import (
"github.com/olekukonko/tablewriter"
)

// DefaultPageWidth is the page (screen) width to use when we need to twiddle
// the width of some table columns for better viewing. For now assume its only
// 80, but if we can figure out a nice (quick) way to determine this for all
// platforms, include Windows, then we should probably use that value instead.
const DefaultPageWidth = 80

// ListTable is a proxy for 'tablewriter.Table' so we can support variable a
// width column that tries to fill up extra space.
// For each func on tablewriter.Table we'll need a proxy func.
// We save the headers and rows and only send them on when Render() is called
// because the tablewriter stuff won't process the call to SetColMinWidth
// if its called after some rows have been added. So we need to calc the
// value of our special column first, call SetColMinWidth and then add the
// headers/rows.
type ListTable struct {
table *tablewriter.Table

columnWidths []int // Max width of data in column we've seen
variableColumn int // 0 == not set
pageWidth int // Defaults to 80
headers []string
rows [][]string
}

// SetBorder is a proxy/pass-thru to the tablewriter.Table's func
func (lt *ListTable) SetBorder(b bool) { lt.table.SetBorder(b) }

// SetVariableColumn tells us which column, if any, should be of variable
// width so that the table takes up the width of the screen rather than
// wrapping cells in this column prematurely.
func (lt *ListTable) SetVariableColumn(c int) { lt.variableColumn = c }

// SetColMinWidth is a proxy/pass-thru to the tablewriter.Table's func
func (lt *ListTable) SetColMinWidth(c, w int) { lt.table.SetColMinWidth(c, w) }

// SetPageWidth tell us how wide the screen is.
func (lt *ListTable) SetPageWidth(w int) { lt.pageWidth = w }

// SetHeader tracks the width of each header value as we save them.
func (lt *ListTable) SetHeader(keys []string) {
if tmp := (len(keys) - len(lt.columnWidths)); tmp > 0 {
lt.columnWidths = append(lt.columnWidths, make([]int, tmp)...)
}

for i, header := range keys {
if tmp := len(header); tmp > lt.columnWidths[i] {
lt.columnWidths[i] = tmp
}
}

// Save the headers for when we call Render
lt.headers = keys
}

// Append will look at each column in the row to see if its longer than any
// previous value, and save it if so. Then it saves the data for later
// rendering.
func (lt *ListTable) Append(row []string) {
// Expand our slice if needed
if tmp := (len(row) - len(lt.columnWidths)); tmp > 0 {
lt.columnWidths = append(lt.columnWidths, make([]int, tmp)...)
}

// Look for a wider cell than what we've seen before
for i, cell := range row {
if tmp := len(cell); tmp > lt.columnWidths[i] {
lt.columnWidths[i] = tmp
}
}

// Just save the row for when we call Render
lt.rows = append(lt.rows, row)
}

// Render will calc the width of the variable column if asked to.
// Then pass our headers and rows to the real Render func to display it.
func (lt *ListTable) Render() {
if lt.variableColumn > 0 && lt.variableColumn <= len(lt.columnWidths)+1 {
// Add up the width of all columns except our special one
total := 2 // 2 == left border + space
for i, w := range lt.columnWidths {
if i+1 != lt.variableColumn {
total = total + 3 + w // 2 == space before/after text + col-sep
}
}

// Space left for our special column if we use the full page width
remaining := lt.pageWidth - total - 3 // 3 == space+border of this col

// If this column doesn't push us past the page width then just
// set it to the max cell width so Render() doesn't chop it on us.
// Otherwise, chop it so we don't go page the page width.
colWidth := lt.columnWidths[lt.variableColumn-1]
if remaining >= colWidth {
lt.SetColMinWidth(lt.variableColumn-1, colWidth)
} else {
lt.SetColMinWidth(lt.variableColumn-1, remaining)
}
}

// Pass along all of the data (header and rows) to the real tablewriter
lt.table.SetHeader(lt.headers)
for _, row := range lt.rows {
lt.table.Append(row)
}
lt.table.Render()
}

// NewListTable builds a table formatted to list a set of results.
func NewListTable(w io.Writer) *tablewriter.Table {
func NewListTable(w io.Writer) *ListTable {
t := tablewriter.NewWriter(w)
t.SetBorder(false)
t.SetColumnSeparator(" ")
return t

return &ListTable{
table: t,
pageWidth: DefaultPageWidth,
}
}

// NewDetailsTable builds a table formatted to list details for a single result.
Expand Down
6 changes: 3 additions & 3 deletions cmd/svcat/testdata/output/get-class.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
NAME NAMESPACE DESCRIPTION
+-----------------------+-----------+-----------------------------------------+
user-provided-service A user provided service
NAME NAMESPACE DESCRIPTION
+-----------------------+-----------+-------------------------+
user-provided-service A user provided service
12 changes: 6 additions & 6 deletions cmd/svcat/testdata/output/get-classes.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
NAME NAMESPACE DESCRIPTION
+--------------------------+-----------+--------------------------------------+
user-provided-service A user provided service
another-provided-service Another provided service
user-provided-service default A user provided service
another-provided-service default Another provided service
NAME NAMESPACE DESCRIPTION
+--------------------------+-----------+--------------------------+
user-provided-service A user provided service
another-provided-service Another provided service
user-provided-service default A user provided service
another-provided-service default Another provided service
6 changes: 3 additions & 3 deletions cmd/svcat/testdata/output/get-plan.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
NAME CLASS DESCRIPTION
+---------+-----------------------+-------------------------------------------+
default user-provided-service Sample plan description
NAME CLASS DESCRIPTION
+---------+-----------------------+-------------------------+
default user-provided-service Sample plan description
8 changes: 4 additions & 4 deletions cmd/svcat/testdata/output/get-plans-by-class.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
NAME CLASS DESCRIPTION
+---------+-----------------------+-------------------------------------------+
default user-provided-service Sample plan description
premium user-provided-service Premium plan
NAME CLASS DESCRIPTION
+---------+-----------------------+-------------------------+
default user-provided-service Sample plan description
premium user-provided-service Premium plan
2 changes: 1 addition & 1 deletion cmd/svcat/testdata/output/get-plans.json
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@
"spec": {
"externalName": "default",
"externalID": "090b5eac-dfa4-49f3-827d-8bcaf3a5bd7c",
"description": "Another sample plan description",
"description": "Another sample plan description that's really really really really really, kinda, wide",
"free": true,
"clusterServiceBrokerName": "ups-broker",
"clusterServiceClassRef": {
Expand Down
4 changes: 3 additions & 1 deletion cmd/svcat/testdata/output/get-plans.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,7 @@
+---------+--------------------------+----------------------------------------+
default user-provided-service Sample plan description
premium user-provided-service Premium plan
default another-provided-service Another sample plan description
default another-provided-service Another sample plan description that's
really really really really really,
kinda, wide
premium another-provided-service Another premium plan
3 changes: 2 additions & 1 deletion cmd/svcat/testdata/output/get-plans.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ items:
clusterServiceBrokerName: ups-broker
clusterServiceClassRef:
name: f1a80068-e366-494e-92d6-a0782337945b
description: Another sample plan description
description: Another sample plan description that's really really really really
really, kinda, wide
externalID: 090b5eac-dfa4-49f3-827d-8bcaf3a5bd7c
externalName: default
free: true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@
"clusterServiceBrokerName": "ups-broker",
"externalName": "default",
"externalID": "090b5eac-dfa4-49f3-827d-8bcaf3a5bd7c",
"description": "Another sample plan description",
"description": "Another sample plan description that's really really really really really, kinda, wide",
"free": true,
"clusterServiceClassRef": {
"name": "f1a80068-e366-494e-92d6-a0782337945b"
Expand Down

0 comments on commit 53becd4

Please sign in to comment.