diff --git a/go.mod b/go.mod index ef2c99523..28292c788 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,7 @@ require ( github.com/spf13/viper v1.19.0 github.com/stevenle/topsort v0.2.0 github.com/turbot/go-kit v1.1.0 - github.com/turbot/pipe-fittings/v2 v2.1.1 + github.com/turbot/pipe-fittings/v2 v2.3.0-rc.3 github.com/turbot/steampipe-plugin-sdk/v5 v5.11.3 github.com/turbot/terraform-components v0.0.0-20231213122222-1f3526cab7a7 // indirect github.com/xlab/treeprint v1.2.0 // indirect @@ -42,7 +42,6 @@ require ( github.com/gin-contrib/size v1.0.1 github.com/go-sql-driver/mysql v1.8.1 github.com/jackc/pgx/v5 v5.6.0 - github.com/jedib0t/go-pretty/v6 v6.5.9 github.com/logrusorgru/aurora v2.0.3+incompatible github.com/marcboeker/go-duckdb v1.8.3 github.com/mattn/go-sqlite3 v1.14.22 @@ -158,6 +157,7 @@ require ( github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect github.com/jackc/puddle/v2 v2.2.1 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect + github.com/jedib0t/go-pretty/v6 v6.5.9 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/kevinburke/ssh_config v1.2.0 // indirect @@ -208,7 +208,6 @@ require ( github.com/tklauser/numcpus v0.3.0 // indirect github.com/tkrajina/go-reflector v0.5.6 // indirect github.com/turbot/pipes-sdk-go v0.12.0 // indirect - github.com/turbot/steampipe-plugin-code v1.0.1-alpha.1 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.12 // indirect github.com/ulikunitz/xz v0.5.10 // indirect diff --git a/go.sum b/go.sum index dcfdf4db6..e5b8e8ada 100644 --- a/go.sum +++ b/go.sum @@ -828,12 +828,10 @@ github.com/tkrajina/go-reflector v0.5.6 h1:hKQ0gyocG7vgMD2M3dRlYN6WBBOmdoOzJ6njQ github.com/tkrajina/go-reflector v0.5.6/go.mod h1:ECbqLgccecY5kPmPmXg1MrHW585yMcDkVl6IvJe64T4= github.com/turbot/go-kit v1.1.0 h1:2gW+MFDJD+mN41GcvhAajTrwR8HgN9KKJ8HnYwPGTV0= github.com/turbot/go-kit v1.1.0/go.mod h1:1xmRuQ0cn/10QUMNLNOAFIqN8P6Rz5s3VLT8mkN3nF8= -github.com/turbot/pipe-fittings/v2 v2.1.1 h1:sV6bviX7WH3zivi45n29+ui+I9tJLlFNCNA2rOpw6/U= -github.com/turbot/pipe-fittings/v2 v2.1.1/go.mod h1:mGFH8dfDQOdv+d1fNL2r3ex+qlnVrTi3xGKZRVxoCEU= +github.com/turbot/pipe-fittings/v2 v2.3.0-rc.3 h1:9ZI021HWFrjiL2RplyYcSs7wZjUzwTy4voRYHkpvAXE= +github.com/turbot/pipe-fittings/v2 v2.3.0-rc.3/go.mod h1:wEoN4EseMTXophNlpOe740rAC9Jg0JhGRt5QM5R2ss8= github.com/turbot/pipes-sdk-go v0.12.0 h1:esbbR7bALa5L8n/hqroMPaQSSo3gNM/4X0iTmHa3D6U= github.com/turbot/pipes-sdk-go v0.12.0/go.mod h1:Mb+KhvqqEdRbz/6TSZc2QWDrMa5BN3E4Xw+gPt2TRkc= -github.com/turbot/steampipe-plugin-code v1.0.1-alpha.1 h1:mN0k0SGAN0pqPh92QZfJIzFzXuz6TiMALnLLLgCqnTI= -github.com/turbot/steampipe-plugin-code v1.0.1-alpha.1/go.mod h1:Dhkl99FVa9eHbBbHgyy0Zf6jj7eVjZZujyqore+RHmQ= github.com/turbot/steampipe-plugin-sdk/v5 v5.11.3 h1:/b+ZUVydvkvjtNB0LbzVkDoWy/GB0qrucAxiUg4yznM= github.com/turbot/steampipe-plugin-sdk/v5 v5.11.3/go.mod h1:zI1JuJjVV+tiqK1MbOfEfeyHJzONRQh/NEYVXEOyd4o= github.com/turbot/terraform-components v0.0.0-20231213122222-1f3526cab7a7 h1:qDMxFVd8Zo0rIhnEBdCIbR+T6WgjwkxpFZMN8zZmmjg= diff --git a/internal/cmd/check.go b/internal/cmd/check.go index 42cd49028..0d4743fb6 100644 --- a/internal/cmd/check.go +++ b/internal/cmd/check.go @@ -216,7 +216,7 @@ func runCheckCmd[T controlinit.CheckTarget](cmd *cobra.Command, args []string) { return } if shouldPrintCheckTiming() { - display.PrintTiming(&localqueryresult.TimingMetadata{ + display.PrintTiming(&localqueryresult.CheckTimingMetadata{ Duration: time.Since(startTime), }) } diff --git a/internal/cmd/query.go b/internal/cmd/query.go index 3b5c16137..440533652 100644 --- a/internal/cmd/query.go +++ b/internal/cmd/query.go @@ -17,12 +17,13 @@ import ( "github.com/turbot/pipe-fittings/v2/constants" "github.com/turbot/pipe-fittings/v2/error_helpers" "github.com/turbot/pipe-fittings/v2/export" + pquerydisplay "github.com/turbot/pipe-fittings/v2/querydisplay" + pqueryresult "github.com/turbot/pipe-fittings/v2/queryresult" "github.com/turbot/pipe-fittings/v2/steampipeconfig" "github.com/turbot/pipe-fittings/v2/workspace" localcmdconfig "github.com/turbot/powerpipe/internal/cmdconfig" localconstants "github.com/turbot/powerpipe/internal/constants" "github.com/turbot/powerpipe/internal/dashboardexecute" - "github.com/turbot/powerpipe/internal/display" "github.com/turbot/powerpipe/internal/initialisation" "github.com/turbot/powerpipe/internal/queryresult" "github.com/turbot/powerpipe/internal/resources" @@ -53,7 +54,7 @@ The current mod is the working directory, or the directory specified by the --mo AddStringArrayFlag(constants.ArgArg, nil, "Specify the value of a query argument"). AddStringFlag(constants.ArgDatabase, "", "Turbot Pipes workspace database", localcmdconfig.Deprecated("see https://powerpipe.io/docs/run#selecting-a-database for the new syntax")). AddIntFlag(constants.ArgDatabaseQueryTimeout, localconstants.DatabaseDefaultQueryTimeout, "The query timeout"). - AddStringSliceFlag(constants.ArgExport, nil, "Export output to file, supported formats: csv, html, json, md, nunit3, pps (snapshot), asff"). + AddStringSliceFlag(constants.ArgExport, nil, "Export output to file, supported formats: csv, json, pps (snapshot)"). AddBoolFlag(constants.ArgHeader, true, "Include column headers for csv and table output"). AddBoolFlag(constants.ArgHelp, false, "Help for query", cmdconfig.FlagOptions.WithShortHand("h")). AddBoolFlag(constants.ArgInput, true, "Enable interactive prompts"). @@ -154,10 +155,10 @@ func queryRun(cmd *cobra.Command, args []string) { } fmt.Println(string(jsonOutput)) //nolint:forbidigo // intentional use of fmt default: - // otherwise convert the snapshot into a query result + // convert the snapshot into a query result result, err := snapshotToQueryResult(snap, startTime) error_helpers.FailOnError(err) - display.ShowQueryOutput(ctx, result) + pquerydisplay.ShowOutput(ctx, result) } // share the snapshot if necessary @@ -168,14 +169,48 @@ func queryRun(cmd *cobra.Command, args []string) { } // export the result if necessary - exportArgs := viper.GetStringSlice(constants.ArgExport) - exportMsg, err := initData.ExportManager.DoExport(ctx, snap.FileNameRoot, snap, exportArgs) - error_helpers.FailOnErrorWithMessage(err, "failed to export snapshot") - // print the location where the file is exported - if len(exportMsg) > 0 && viper.GetBool(constants.ArgProgress) { - fmt.Printf("\n") //nolint:forbidigo // intentional use of fmt - fmt.Println(strings.Join(exportMsg, "\n")) //nolint:forbidigo // intentional use of fmt - fmt.Printf("\n") //nolint:forbidigo // intentional use of fmt + if viper.IsSet(constants.ArgExport) { + exportArgs := viper.GetStringSlice(constants.ArgExport) + var exportMsg []string + + // check if export format is csv or json + isCsvOrJson := false + isSnapshot := false + for _, arg := range exportArgs { + argLower := strings.ToLower(arg) + if strings.Contains(argLower, "csv") || strings.Contains(argLower, "json") { + isCsvOrJson = true + } + if strings.Contains(argLower, "pps") { + isSnapshot = true + } + } + + switch { + case isCsvOrJson: + // export csv/json with the query result + // convert the snapshot into a query result (this is needed again since the rowChan has been already closed) + result, err := snapshotToQueryResult(snap, startTime) + error_helpers.FailOnError(err) + exportMsg, err = initData.ExportManager.DoExport(ctx, "query", result, exportArgs) + error_helpers.FailOnErrorWithMessage(err, "failed to export") + + case isSnapshot: + // export snapshot with the snapshot result + exportMsg, err = initData.ExportManager.DoExport(ctx, snap.FileNameRoot, snap, exportArgs) + error_helpers.FailOnErrorWithMessage(err, "failed to export snapshot") + + default: + // not a recognised export format + error_helpers.FailOnError(fmt.Errorf("unsupported export format: %s", exportArgs)) + } + + // print the location where the file is exported + if len(exportMsg) > 0 && viper.GetBool(constants.ArgProgress) { + fmt.Printf("\n") //nolint:forbidigo // intentional use of fmt + fmt.Println(strings.Join(exportMsg, "\n")) //nolint:forbidigo // intentional use of fmt + fmt.Printf("\n") //nolint:forbidigo // intentional use of fmt + } } } @@ -202,7 +237,7 @@ func validateQueryArgs(ctx context.Context) error { } func queryExporters() []export.Exporter { - return []export.Exporter{&export.SnapshotExporter{}} + return []export.Exporter{&export.SnapshotExporter{}, &export.JsonExporter{}, &export.CsvExporter{}} } func setExitCodeForQueryError(err error) { @@ -250,8 +285,19 @@ func snapshotToQueryResult(snap *steampipeconfig.SteampipeSnapshot, startTime ti res.Close() }() - res.Timing = &queryresult.TimingMetadata{ - Duration: time.Since(startTime), + res.Timing = &pqueryresult.QueryTimingMetadata{ + RowsReturned: len(chartRun.Data.Rows), + Duration: getDurationString(time.Since(startTime)), } return res, nil } + +func getDurationString(duration time.Duration) string { + // Calculate duration since startTime and round down to the nearest millisecond + durationInMS := duration / time.Millisecond + //nolint:durationcheck // we want to print the duration in milliseconds + duration = durationInMS * time.Millisecond + + durationString := duration.String() + return durationString +} diff --git a/internal/display/column.go b/internal/display/column.go index 786e1a732..a101fdd96 100644 --- a/internal/display/column.go +++ b/internal/display/column.go @@ -10,21 +10,6 @@ import ( "github.com/turbot/pipe-fittings/v2/queryresult" ) -// columnNames builds a list of name from a slice of column defs - respecting the original name if present -func columnNames(columns []*queryresult.ColumnDef) []string { - var colNames = make([]string, len(columns)) - for i, c := range columns { - // respect original name - if c.OriginalName != "" { - colNames[i] = c.OriginalName - } else { - colNames[i] = c.Name - } - } - - return colNames -} - type columnValueSettings struct{ nullString string } type ColumnValueOption func(opt *columnValueSettings) diff --git a/internal/display/display.go b/internal/display/display.go deleted file mode 100644 index 135736d04..000000000 --- a/internal/display/display.go +++ /dev/null @@ -1,405 +0,0 @@ -package display - -import ( - "bufio" - "bytes" - "context" - "encoding/csv" - "encoding/json" - "fmt" - "os" - "strings" - "unicode" - "unicode/utf8" - - "github.com/jedib0t/go-pretty/v6/table" - "github.com/jedib0t/go-pretty/v6/text" - "github.com/karrick/gows" - "github.com/spf13/viper" - "github.com/turbot/go-kit/helpers" - "github.com/turbot/pipe-fittings/v2/cmdconfig" - "github.com/turbot/pipe-fittings/v2/constants" - "github.com/turbot/pipe-fittings/v2/error_helpers" - pfq "github.com/turbot/pipe-fittings/v2/queryresult" - "github.com/turbot/powerpipe/internal/queryresult" -) - -// ShowQueryOutput displays the output using the proper formatter as applicable -func ShowQueryOutput(ctx context.Context, result *queryresult.Result) int { - rowErrors := 0 - - switch cmdconfig.Viper().GetString(constants.ArgOutput) { - case constants.OutputFormatJSON: - rowErrors = displayJSON(ctx, result) - case constants.OutputFormatCSV: - rowErrors = displayCSV(ctx, result) - case constants.OutputFormatLine: - rowErrors = displayLine(ctx, result) - case constants.OutputFormatTable: - rowErrors = displayTable(ctx, result) - } - - if shouldShowQueryTiming() { - PrintTiming(result.Timing) - } - // return the number of rows that returned errors - return rowErrors -} - -type ShowWrappedTableOptions struct { - AutoMerge bool - HideEmptyColumns bool - Truncate bool -} - -func ShowWrappedTable(headers []string, rows [][]string, opts *ShowWrappedTableOptions) { - if opts == nil { - opts = &ShowWrappedTableOptions{} - } - t := table.NewWriter() - - t.SetStyle(table.StyleDefault) - t.Style().Format.Header = text.FormatDefault - t.SetOutputMirror(os.Stdout) - - rowConfig := table.RowConfig{AutoMerge: opts.AutoMerge} - colConfigs, headerRow := getColumnSettings(headers, rows, opts) - - 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() -} - -func GetMaxCols() int { - colsAvailable, _, _ := gows.GetWinSize() - // check if POWERPIPE_DISPLAY_WIDTH env variable is set - if viper.IsSet(constants.ArgDisplayWidth) { - colsAvailable = viper.GetInt(constants.ArgDisplayWidth) - } - return colsAvailable -} - -// calculate and returns column configuration based on header and row content -func getColumnSettings(headers []string, rows [][]string, opts *ShowWrappedTableOptions) ([]table.ColumnConfig, table.Row) { - 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 := getTerminalColumnsRequiredForString(colName) - colHasValue := false - for _, row := range rows { - colVal := row[idx] - if !colHasValue && len(colVal) > 0 { - // the !colHasValue is necessary in the condition, - // otherwise, even after being set, we will keep - // evaluating the length - colHasValue = true - } - - // get the maximum line length of the value - colLen := getTerminalColumnsRequiredForString(colVal) - if colLen > maxLen { - maxLen = colLen - } - } - colConfigs[idx] = table.ColumnConfig{ - Name: colName, - Number: idx + 1, - WidthMax: maxLen, - WidthMin: maxLen, - } - if opts.HideEmptyColumns && !colHasValue { - colConfigs[idx].Hidden = true - } - 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 - // get the max cols width - maxCols := GetMaxCols() - if sumOfAllCols > maxCols { - colConfigs[len(colConfigs)-1].WidthMax = maxCols - sumOfRest - spaceAccounting - colConfigs[len(colConfigs)-1].WidthMin = maxCols - sumOfRest - spaceAccounting - if opts.Truncate { - colConfigs[len(colConfigs)-1].WidthMaxEnforcer = helpers.TruncateString - } - } - - return colConfigs, headerRow -} - -// getTerminalColumnsRequiredForString returns the length of the longest line in the string -func getTerminalColumnsRequiredForString(str string) int { - colsRequired := 0 - scanner := bufio.NewScanner(bytes.NewBufferString(str)) - for scanner.Scan() { - line := scanner.Text() - runeCount := utf8.RuneCountInString(line) - if runeCount > colsRequired { - colsRequired = runeCount - } - } - return colsRequired -} - -func displayLine(ctx context.Context, result *queryresult.Result) int { - - maxColNameLength, rowErrors := 0, 0 - for _, col := range result.Cols { - thisLength := utf8.RuneCountInString(col.Name) - if thisLength > maxColNameLength { - maxColNameLength = thisLength - } - } - itemIdx := 0 - - // define a function to display each row - rowFunc := func(row []interface{}, result *queryresult.Result) { - recordAsString, _ := ColumnValuesAsString(row, result.Cols) - requiredTerminalColumnsForValuesOfRecord := 0 - for _, colValue := range recordAsString { - colRequired := getTerminalColumnsRequiredForString(colValue) - if requiredTerminalColumnsForValuesOfRecord < colRequired { - requiredTerminalColumnsForValuesOfRecord = colRequired - } - } - - lineFormat := fmt.Sprintf("%%-%ds | %%s\n", maxColNameLength) - multiLineFormat := fmt.Sprintf("%%-%ds | %%-%ds", maxColNameLength, requiredTerminalColumnsForValuesOfRecord) - - fmt.Printf("-[ RECORD %-2d ]%s\n", itemIdx+1, strings.Repeat("-", 75)) //nolint:forbidigo // intentional use of fmt - - // get the column names (this takes into account the original name) - columnNames := columnNames(result.Cols) - - for idx, column := range recordAsString { - lines := strings.Split(column, "\n") - if len(lines) == 1 { - fmt.Printf(lineFormat, columnNames[idx], lines[0]) //nolint:forbidigo // intentional use of fmt - } else { - for lineIdx, line := range lines { - if lineIdx == 0 { - // the first line - fmt.Printf(multiLineFormat, columnNames[idx], line) //nolint:forbidigo // intentional use of fmt - } else { - // next lines - fmt.Printf(multiLineFormat, "", line) //nolint:forbidigo // intentional use of fmt - } - - // is this not the last line of value? - if lineIdx < len(lines)-1 { - fmt.Printf(" +\n") //nolint:forbidigo // intentional use of fmt - } else { - fmt.Printf("\n") //nolint:forbidigo // intentional use of fmt - } - - } - } - } - itemIdx++ - - } - - // call this function for each row - if err := iterateResults(result, rowFunc); err != nil { - error_helpers.ShowError(ctx, err) - rowErrors++ - return rowErrors - } - return rowErrors -} - -type resultMetadata struct { - RowsReturned int `json:"rows_returned"` - Duration string `json:"duration_ms"` -} - -type jsonOutput struct { - Columns []pfq.ColumnDef `json:"columns"` - Rows []map[string]interface{} `json:"rows"` - Metadata resultMetadata `json:"metadata"` -} - -func displayJSON(ctx context.Context, result *queryresult.Result) int { - rowErrors := 0 - var op = jsonOutput{ - Metadata: resultMetadata{ - Duration: getDurationString(result.Timing.Duration), - }, - } - - // add column defs to the JSON output - for _, col := range result.Cols { - // create a new column def, converting the data type to lowercase - c := pfq.ColumnDef{ - Name: col.Name, - OriginalName: col.OriginalName, - DataType: strings.ToLower(col.DataType), - } - // add to the column def array - op.Columns = append(op.Columns, c) - } - - // Define function to add each row to the JSON output - rowFunc := func(row []interface{}, result *queryresult.Result) { - record := map[string]interface{}{} - for idx, col := range result.Cols { - value, _ := ParseJSONOutputColumnValue(row[idx], col) - // get the column def - c := op.Columns[idx] - // add the value under the unique column name - record[c.Name] = value - } - - op.Rows = append(op.Rows, record) - } - - // call this function for each row - if err := iterateResults(result, rowFunc); err != nil { - error_helpers.ShowError(ctx, err) - rowErrors++ - return rowErrors - } - op.Metadata.RowsReturned = len(op.Rows) - - // display the JSON - encoder := json.NewEncoder(os.Stdout) - encoder.SetIndent("", " ") - encoder.SetEscapeHTML(false) - if err := encoder.Encode(op); err != nil { - error_helpers.ShowErrorWithMessage(ctx, err, "Error displaying result as JSON") - return 0 - } - return rowErrors -} - -func displayCSV(ctx context.Context, result *queryresult.Result) int { - rowErrors := 0 - csvWriter := csv.NewWriter(os.Stdout) - csvWriter.Comma = []rune(cmdconfig.Viper().GetString(constants.ArgSeparator))[0] - - if cmdconfig.Viper().GetBool(constants.ArgHeader) { - _ = csvWriter.Write(columnNames(result.Cols)) - } - - // print the data as it comes - // define function display each csv row - rowFunc := func(row []interface{}, result *queryresult.Result) { - rowAsString, _ := ColumnValuesAsString(row, result.Cols, WithNullString("")) - _ = csvWriter.Write(rowAsString) - } - - // call this function for each row - if err := iterateResults(result, rowFunc); err != nil { - error_helpers.ShowError(ctx, err) - rowErrors++ - return rowErrors - } - - csvWriter.Flush() - if csvWriter.Error() != nil { - error_helpers.ShowErrorWithMessage(ctx, csvWriter.Error(), "unable to print csv") - } - return rowErrors -} - -func displayTable(ctx context.Context, result *queryresult.Result) int { - rowErrors := 0 - // the buffer to put the output data in - outbuf := bytes.NewBufferString("") - - // the table - t := table.NewWriter() - t.SetOutputMirror(outbuf) - t.SetStyle(table.StyleDefault) - t.Style().Format.Header = text.FormatDefault - - var colConfigs []table.ColumnConfig - headers := make(table.Row, len(result.Cols)) - - // get the column names (this takes into account the original name) - columnNames := columnNames(result.Cols) - for idx, columnName := range columnNames { - headers[idx] = columnName - colConfigs = append(colConfigs, table.ColumnConfig{ - Name: columnName, - Number: idx + 1, - WidthMax: constants.MaxColumnWidth, - }) - } - - t.SetColumnConfigs(colConfigs) - if viper.GetBool(constants.ArgHeader) { - t.AppendHeader(headers) - } - - // define a function to execute for each row - rowFunc := func(row []interface{}, result *queryresult.Result) { - rowAsString, _ := ColumnValuesAsString(row, result.Cols) - rowObj := table.Row{} - for _, col := range rowAsString { - // trim out non-displayable code-points in string - // exfept white-spaces - col = strings.Map(func(r rune) rune { - if unicode.IsSpace(r) || unicode.IsGraphic(r) { - // return if this is a white space character - return r - } - return -1 - }, col) - rowObj = append(rowObj, col) - } - t.AppendRow(rowObj) - } - - // iterate each row, adding each to the table - err := iterateResults(result, rowFunc) - if err != nil { - // display the error - fmt.Println() //nolint:forbidigo // intentional use of fmt - error_helpers.ShowError(ctx, err) - rowErrors++ - fmt.Println() //nolint:forbidigo // intentional use of fmt - } - // write out the table to the buffer - t.Render() - - // page out the table - ShowPaged(ctx, outbuf.String()) - return rowErrors -} - -type displayResultsFunc func(row []interface{}, result *queryresult.Result) - -// call func displayResult for each row of results -func iterateResults(result *queryresult.Result, displayResult displayResultsFunc) error { - for row := range result.RowChan { - if row == nil { - return nil - } - if row.Error != nil { - return row.Error - } - displayResult(row.Data, result) - } - // we will not get here - return nil -} diff --git a/internal/display/timing.go b/internal/display/timing.go index 625c9b1c1..1e5b15d7b 100644 --- a/internal/display/timing.go +++ b/internal/display/timing.go @@ -2,18 +2,12 @@ package display import ( "fmt" - "github.com/spf13/viper" - "github.com/turbot/pipe-fittings/v2/constants" - "github.com/turbot/powerpipe/internal/queryresult" "time" -) -func shouldShowQueryTiming() bool { - outputFormat := viper.GetString(constants.ArgOutput) - return viper.GetBool(constants.ArgTiming) && outputFormat == constants.OutputFormatTable -} + "github.com/turbot/powerpipe/internal/queryresult" +) -func PrintTiming(timingMetadata *queryresult.TimingMetadata) { +func PrintTiming(timingMetadata *queryresult.CheckTimingMetadata) { durationString := getDurationString(timingMetadata.Duration) fmt.Printf("\nTime: %s\n", durationString) //nolint:forbidigo // intentional use of fmt } diff --git a/internal/queryresult/result.go b/internal/queryresult/result.go index 3a02c8b6a..24b060dc7 100644 --- a/internal/queryresult/result.go +++ b/internal/queryresult/result.go @@ -1,22 +1,23 @@ package queryresult import ( - "github.com/turbot/pipe-fittings/v2/queryresult" "time" + + "github.com/turbot/pipe-fittings/v2/queryresult" ) -type TimingMetadata struct { +type CheckTimingMetadata struct { Duration time.Duration } // GetTiming implements TimingContainer - we implement this interface -// to allow TimingMetadata to be used to parameterize the ResultStreamer -func (t TimingMetadata) GetTiming() any { +// to allow CheckTimingMetadata to be used to parameterize the ResultStreamer +func (t CheckTimingMetadata) GetTiming() any { return t } -type Result = queryresult.Result[*TimingMetadata] +type Result = queryresult.Result[*queryresult.QueryTimingMetadata] func NewResult(cols []*queryresult.ColumnDef) *Result { - return queryresult.NewResult[*TimingMetadata](cols, &TimingMetadata{}) + return queryresult.NewResult[*queryresult.QueryTimingMetadata](cols, &queryresult.QueryTimingMetadata{}) } diff --git a/internal/queryresult/result_streamer.go b/internal/queryresult/result_streamer.go index b1c5c9135..a22dd7fcb 100644 --- a/internal/queryresult/result_streamer.go +++ b/internal/queryresult/result_streamer.go @@ -2,8 +2,8 @@ package queryresult import "github.com/turbot/pipe-fittings/v2/queryresult" -type ResultStreamer = queryresult.ResultStreamer[*TimingMetadata] +type ResultStreamer = queryresult.ResultStreamer[*CheckTimingMetadata] func NewResultStreamer() *ResultStreamer { - return queryresult.NewResultStreamer[*TimingMetadata]() + return queryresult.NewResultStreamer[*CheckTimingMetadata]() }