Skip to content

Commit

Permalink
Wrap plugin list output to window width. Closes #235 (#244)
Browse files Browse the repository at this point in the history
  • Loading branch information
binaek committed Mar 3, 2021
1 parent d40b632 commit 7b4e7fb
Show file tree
Hide file tree
Showing 8 changed files with 121 additions and 113 deletions.
13 changes: 5 additions & 8 deletions cmd/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,12 @@ import (
"errors"
"fmt"
"log"
"os"
"strings"

"github.com/turbot/steampipe/constants"
"github.com/turbot/steampipe/display"
"github.com/turbot/steampipe/statefile"

"github.com/jedib0t/go-pretty/v6/table"
"github.com/spf13/cobra"
"github.com/turbot/steampipe-plugin-sdk/logging"
"github.com/turbot/steampipe/cmdconfig"
Expand Down Expand Up @@ -418,14 +417,12 @@ func runPluginListCmd(cmd *cobra.Command, args []string) {
utils.ShowErrorWithMessage(err,
fmt.Sprintf("Plugin Listing failed"))
}
t := table.NewWriter()
t.SetStyle(table.StyleLight)
t.SetOutputMirror(os.Stdout)
t.AppendHeader(table.Row{"Name", "Version", "Connections"})
headers := []string{"Name", "Version", "Connections"}
rows := [][]string{}
for _, item := range list {
t.AppendRow(table.Row{item.Name, item.Version, strings.Join(item.Connections, ",")})
rows = append(rows, []string{item.Name, item.Version, strings.Join(item.Connections, ",")})
}
t.Render()
display.ShowWrappedTable(headers, rows, false)
}

func runPluginUninstallCmd(cmd *cobra.Command, args []string) {
Expand Down
11 changes: 6 additions & 5 deletions db/client_execute.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,27 +10,28 @@ import (

"github.com/turbot/steampipe/cmdconfig"
"github.com/turbot/steampipe/constants"
"github.com/turbot/steampipe/definitions/results"
"github.com/turbot/steampipe/utils"
)

// ExecuteSync :: execute a query against this client and wait for the result
func (c *Client) ExecuteSync(query string) (*SyncQueryResult, error) {
func (c *Client) ExecuteSync(query string) (*results.SyncQueryResult, error) {
// https://github.com/golang/go/wiki/CodeReviewComments#indent-error-flow
result, err := c.executeQuery(query, false)
if err != nil {
return nil, err
}
syncResult := &SyncQueryResult{ColTypes: result.ColTypes}
syncResult := &results.SyncQueryResult{ColTypes: result.ColTypes}
for row := range *result.RowChan {
syncResult.Rows = append(syncResult.Rows, row)
}
syncResult.Duration = <-result.Duration
return syncResult, nil
}

func (c *Client) executeQuery(query string, countStream bool) (*QueryResult, error) {
func (c *Client) executeQuery(query string, countStream bool) (*results.QueryResult, error) {
if query == "" {
return &QueryResult{}, nil
return &results.QueryResult{}, nil
}

start := time.Now()
Expand Down Expand Up @@ -65,7 +66,7 @@ func (c *Client) executeQuery(query string, countStream bool) (*QueryResult, err
}
cols, err := rows.Columns()

result := newQueryResult(colTypes)
result := results.NewQueryResult(colTypes)

rowCount := 0

Expand Down
11 changes: 6 additions & 5 deletions db/interactive_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (

"github.com/turbot/steampipe/autocomplete"
"github.com/turbot/steampipe/cmdconfig"
"github.com/turbot/steampipe/definitions/results"

"github.com/turbot/steampipe/constants"
"github.com/turbot/steampipe/metaquery"
Expand Down Expand Up @@ -40,7 +41,7 @@ func (c *InteractiveClient) close() {
}

// InteractiveQuery :: start an interactive prompt and return
func (c *InteractiveClient) InteractiveQuery(resultsStreamer *ResultStreamer, onCompleteCallback func()) {
func (c *InteractiveClient) InteractiveQuery(resultsStreamer *results.ResultStreamer, onCompleteCallback func()) {
defer func() {

onCompleteCallback()
Expand All @@ -60,7 +61,7 @@ func (c *InteractiveClient) InteractiveQuery(resultsStreamer *ResultStreamer, on
// this needs to be the last thing we do,
// as the runQueryCmd uses this as an indication
// to quit out of the application
resultsStreamer.close()
resultsStreamer.Close()
}()

fmt.Printf("Welcome to Steampipe v%s\n", version.String())
Expand All @@ -81,7 +82,7 @@ func (c *InteractiveClient) InteractiveQuery(resultsStreamer *ResultStreamer, on
}
}

func (c *InteractiveClient) runInteractivePrompt(resultsStreamer *ResultStreamer) (ret utils.InteractiveExitStatus) {
func (c *InteractiveClient) runInteractivePrompt(resultsStreamer *results.ResultStreamer) (ret utils.InteractiveExitStatus) {
defer func() {
// this is to catch the PANIC that gets raised by
// the executor of go-prompt
Expand Down Expand Up @@ -171,7 +172,7 @@ func (c *InteractiveClient) breakMultilinePrompt(buffer *prompt.Buffer) {
c.interactiveBuffer = []string{}
}

func (c *InteractiveClient) executor(line string, resultsStreamer *ResultStreamer) {
func (c *InteractiveClient) executor(line string, resultsStreamer *results.ResultStreamer) {
line = strings.TrimSpace(line)

// if it's an empty line, then we don't need to do anything
Expand Down Expand Up @@ -210,7 +211,7 @@ func (c *InteractiveClient) executor(line string, resultsStreamer *ResultStreame
utils.ShowError(err)
resultsStreamer.Done()
} else {
resultsStreamer.streamResult(result)
resultsStreamer.StreamResult(result)
}
}

Expand Down
9 changes: 6 additions & 3 deletions db/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@ import (
"github.com/turbot/steampipe-plugin-sdk/logging"

"github.com/turbot/steampipe/constants"
"github.com/turbot/steampipe/definitions/results"
"github.com/turbot/steampipe/utils"
)

// ExecuteQuery :: entry point for executing ad-hoc queries from outside the package
func ExecuteQuery(queryString string) (*ResultStreamer, error) {
func ExecuteQuery(queryString string) (*results.ResultStreamer, error) {
var err error

logging.LogTime("db.ExecuteQuery start")
Expand Down Expand Up @@ -48,7 +49,7 @@ func ExecuteQuery(queryString string) (*ResultStreamer, error) {
return nil, fmt.Errorf("failed to add functions: %v", err)
}

resultsStreamer := newQueryResults()
resultsStreamer := results.NewResultStreamer()

// this is a callback to close the db et-al. when things get done - no matter the mode
onComplete := func() { Shutdown(client, InvokerQuery) }
Expand All @@ -69,13 +70,15 @@ func ExecuteQuery(queryString string) (*ResultStreamer, error) {
onComplete()
return nil, err
}
go resultsStreamer.streamSingleResult(result, onComplete)
go resultsStreamer.StreamSingleResult(result, onComplete)
}

logging.LogTime("db.ExecuteQuery end")
return resultsStreamer, nil
}

// Shutdown :: closes the client connection and stops the
// database instance if the given `invoker` matches
func Shutdown(client *Client, invoker Invoker) {
log.Println("[TRACE] shutdown")
if client != nil {
Expand Down
10 changes: 8 additions & 2 deletions db/query_results.go → definitions/results/queryresult.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
package db
/**
This package is for all interfaces that are imported in multiple packages in the
code base
This package MUST never import any other `steampipe` package
**/
package results

import (
"database/sql"
Expand Down Expand Up @@ -29,7 +35,7 @@ func (r QueryResult) StreamError(err error) {
*r.RowChan <- &RowResult{Error: err}
}

func newQueryResult(colTypes []*sql.ColumnType) *QueryResult {
func NewQueryResult(colTypes []*sql.ColumnType) *QueryResult {
rowChan := make(chan *RowResult)
return &QueryResult{
RowChan: &rowChan,
Expand Down
10 changes: 5 additions & 5 deletions db/results_streamer.go → definitions/results/resultstreamer.go
Original file line number Diff line number Diff line change
@@ -1,30 +1,30 @@
package db
package results

type ResultStreamer struct {
Results chan *QueryResult
displayReady chan string
}

func newQueryResults() *ResultStreamer {
func NewResultStreamer() *ResultStreamer {
return &ResultStreamer{
// make buffered channel so we can always stream a single result
Results: make(chan *QueryResult, 1),
displayReady: make(chan string, 1),
}
}

func (q *ResultStreamer) streamResult(result *QueryResult) {
func (q *ResultStreamer) StreamResult(result *QueryResult) {
q.Results <- result
}

func (q *ResultStreamer) streamSingleResult(result *QueryResult, onComplete func()) {
func (q *ResultStreamer) StreamSingleResult(result *QueryResult, onComplete func()) {
q.Results <- result
q.Wait()
onComplete()
close(q.Results)
}

func (q *ResultStreamer) close() {
func (q *ResultStreamer) Close() {
close(q.Results)
}

Expand Down
92 changes: 80 additions & 12 deletions display/display.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,16 @@ import (

"github.com/jedib0t/go-pretty/v6/table"
"github.com/jedib0t/go-pretty/v6/text"
"github.com/karrick/gows"

"github.com/turbot/steampipe/cmdconfig"
"github.com/turbot/steampipe/constants"
"github.com/turbot/steampipe/db"
"github.com/turbot/steampipe/definitions/results"
"github.com/turbot/steampipe/utils"
)

// ShowOutput :: displays the output using the proper formatter as applicable
func ShowOutput(result *db.QueryResult) {
func ShowOutput(result *results.QueryResult) {
if cmdconfig.Viper().Get(constants.ArgOutput) == constants.ArgJSON {
displayJSON(result)
} else if cmdconfig.Viper().Get(constants.ArgOutput) == constants.ArgCSV {
Expand All @@ -32,7 +33,74 @@ func ShowOutput(result *db.QueryResult) {
}
}

func displayLine(result *db.QueryResult) {
func ShowWrappedTable(headers []string, rows [][]string, autoMerge bool) {
t := table.NewWriter()
t.SetStyle(table.StyleDefault)
t.SetOutputMirror(os.Stdout)

rowConfig := table.RowConfig{AutoMerge: autoMerge}
colConfigs, headerRow := getColumnSettings(headers, rows)

t.SetColumnConfigs(colConfigs)
t.AppendHeader(headerRow)

for _, row := range rows {
rowObj := table.Row{}
for _, col := range row {
rowObj = append(rowObj, col)
}
t.AppendRow(rowObj, rowConfig)
}
t.Render()
}

// calculate and returns column configuration based on header and row content
func getColumnSettings(headers []string, rows [][]string) ([]table.ColumnConfig, table.Row) {
maxCols, _, _ := gows.GetWinSize()
colConfigs := make([]table.ColumnConfig, len(headers))
headerRow := make(table.Row, len(headers))

sumOfAllCols := 0

// account for the spaces around the value of a column and separators
spaceAccounting := ((len(headers) * 3) + 1)

for idx, colName := range headers {
headerRow[idx] = colName

// get the maximum len of strings in this column
maxLen := 0
for _, row := range rows {
colVal := row[idx]
if len(colVal) > maxLen {
maxLen = len(colVal)
}
if len(colName) > maxLen {
maxLen = len(colName)
}
}
colConfigs[idx] = table.ColumnConfig{
Name: colName,
Number: idx + 1,
WidthMax: maxLen,
WidthMin: maxLen,
}
sumOfAllCols += maxLen
}

// now that all columns are set to the widths that they need,
// set the last one to occupy as much as is available - no more - no less
sumOfRest := sumOfAllCols - colConfigs[len(colConfigs)-1].WidthMax

if sumOfAllCols > maxCols {
colConfigs[len(colConfigs)-1].WidthMax = (maxCols - sumOfRest - spaceAccounting)
colConfigs[len(colConfigs)-1].WidthMin = (maxCols - sumOfRest - spaceAccounting)
}

return colConfigs, headerRow
}

func displayLine(result *results.QueryResult) {
colNames := ColumnNames(result.ColTypes)
maxColNameLength := 0
for _, colName := range colNames {
Expand All @@ -44,7 +112,7 @@ func displayLine(result *db.QueryResult) {
itemIdx := 0

// define a function to display each row
rowFunc := func(row []interface{}, result *db.QueryResult) {
rowFunc := func(row []interface{}, result *results.QueryResult) {
recordAsString, _ := ColumnValuesAsString(row, result.ColTypes)
requiredTerminalColumnsForValuesOfRecord := 0
for _, colValue := range recordAsString {
Expand Down Expand Up @@ -98,11 +166,11 @@ func getTerminalColumnsRequiredForString(str string) int {
return colsRequired
}

func displayJSON(result *db.QueryResult) {
func displayJSON(result *results.QueryResult) {
var jsonOutput []map[string]interface{}

// define function to add each row to the JSON output
rowFunc := func(row []interface{}, result *db.QueryResult) {
rowFunc := func(row []interface{}, result *results.QueryResult) {
record := map[string]interface{}{}
for idx, colType := range result.ColTypes {
value, _ := ParseJSONOutputColumnValue(row[idx], colType)
Expand All @@ -125,7 +193,7 @@ func displayJSON(result *db.QueryResult) {
fmt.Printf("%s\n", string(data))
}

func displayCSV(result *db.QueryResult) {
func displayCSV(result *results.QueryResult) {
csvWriter := csv.NewWriter(os.Stdout)
csvWriter.Comma = []rune(cmdconfig.Viper().GetString(constants.ArgSeparator))[0]

Expand All @@ -135,7 +203,7 @@ func displayCSV(result *db.QueryResult) {

// print the data as it comes
// define function display each csv row
rowFunc := func(row []interface{}, result *db.QueryResult) {
rowFunc := func(row []interface{}, result *results.QueryResult) {
rowAsString, _ := ColumnValuesAsString(row, result.ColTypes)
_ = csvWriter.Write(rowAsString)
}
Expand All @@ -152,7 +220,7 @@ func displayCSV(result *db.QueryResult) {
}
}

func displayTable(result *db.QueryResult) {
func displayTable(result *results.QueryResult) {
// the buffer to put the output data in
outbuf := bytes.NewBufferString("")

Expand All @@ -178,7 +246,7 @@ func displayTable(result *db.QueryResult) {
t.AppendHeader(headers)

// define a function to execute for each row
rowFunc := func(row []interface{}, result *db.QueryResult) {
rowFunc := func(row []interface{}, result *results.QueryResult) {
rowAsString, _ := ColumnValuesAsString(row, result.ColTypes)
rowObj := table.Row{}
for _, col := range rowAsString {
Expand All @@ -205,10 +273,10 @@ func displayTable(result *db.QueryResult) {
ShowPaged(outbuf.String())
}

type displayResultsFunc func(row []interface{}, result *db.QueryResult)
type displayResultsFunc func(row []interface{}, result *results.QueryResult)

// call func displayResult for each row of results
func iterateResults(result *db.QueryResult, displayResult displayResultsFunc) error {
func iterateResults(result *results.QueryResult, displayResult displayResultsFunc) error {
for row := range *result.RowChan {
if row == nil {
return nil
Expand Down
Loading

0 comments on commit 7b4e7fb

Please sign in to comment.