diff --git a/cmd/root.go b/cmd/root.go index f1cd4a0..d7d4e92 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -5,7 +5,6 @@ import ( "os" "github.com/anchore/elastic-container-gatherer/ecg" - "github.com/anchore/elastic-container-gatherer/ecg/presenter" "github.com/spf13/cobra" "github.com/spf13/viper" ) @@ -44,18 +43,7 @@ var rootCmd = &cobra.Command{ } func init() { - // output & formatting options - opt := "output" - rootCmd.Flags().StringP( - opt, "o", presenter.JSONPresenter.String(), - fmt.Sprintf("report output formatter, options=%v", presenter.Options), - ) - if err := viper.BindPFlag(opt, rootCmd.Flags().Lookup(opt)); err != nil { - fmt.Printf("unable to bind flag '%s': %+v", opt, err) - os.Exit(1) - } - - opt = "polling-interval-seconds" + opt := "polling-interval-seconds" rootCmd.Flags().StringP(opt, "p", "300", "This specifies the polling interval of the ECS API in seconds") if err := viper.BindPFlag(opt, rootCmd.Flags().Lookup(opt)); err != nil { fmt.Printf("unable to bind flag '%s': %+v", opt, err) diff --git a/ecg/lib.go b/ecg/lib.go index 4f889ea..c182751 100644 --- a/ecg/lib.go +++ b/ecg/lib.go @@ -1,13 +1,13 @@ package ecg import ( + "encoding/json" "fmt" "os" "time" "github.com/anchore/elastic-container-gatherer/ecg/inventory" "github.com/anchore/elastic-container-gatherer/ecg/logger" - "github.com/anchore/elastic-container-gatherer/ecg/presenter" "github.com/anchore/elastic-container-gatherer/ecg/reporter" "github.com/anchore/elastic-container-gatherer/internal/config" "github.com/aws/aws-sdk-go/aws" @@ -17,6 +17,18 @@ import ( var log logger.Logger +// Output the JSON formatted report to stdout +func reportToStdout(report inventory.Report) error { + enc := json.NewEncoder(os.Stdout) + // prevent > and < from being escaped in the payload + enc.SetEscapeHTML(false) + enc.SetIndent("", " ") + if err := enc.Encode(report); err != nil { + return fmt.Errorf("unable to show inventory: %w", err) + } + return nil +} + func HandleReport(report inventory.Report, cfg *config.Application) error { if cfg.AnchoreDetails.IsValid() { if err := reporter.Post(report, cfg.AnchoreDetails, cfg); err != nil { @@ -26,10 +38,8 @@ func HandleReport(report inventory.Report, cfg *config.Application) error { log.Debug("Anchore details not specified, not reporting inventory") } - if err := presenter.GetPresenter(cfg.PresenterOpt, report).Present(os.Stdout); err != nil { - return fmt.Errorf("unable to show inventory: %w", err) - } - return nil + // Encode the report to JSON and output to stdout (maintains same behaviour as when multiple presenters were supported) + return reportToStdout(report) } // PeriodicallyGetInventoryReport periodically retrieve image results and report/output them according to the configuration. diff --git a/ecg/presenter/json/presenter.go b/ecg/presenter/json/presenter.go deleted file mode 100644 index d44f557..0000000 --- a/ecg/presenter/json/presenter.go +++ /dev/null @@ -1,30 +0,0 @@ -// If Output == "json" this presenter is used -package json - -import ( - "encoding/json" - "io" - - "github.com/anchore/elastic-container-gatherer/ecg/inventory" -) - -// Presenter is a generic struct for holding fields needed for reporting -type Presenter struct { - report inventory.Report -} - -// NewPresenter is a *Presenter constructor -func NewPresenter(report inventory.Report) *Presenter { - return &Presenter{ - report: report, - } -} - -// Present creates a JSON-based reporting -func (pres *Presenter) Present(output io.Writer) error { - enc := json.NewEncoder(output) - // prevent > and < from being escaped in the payload - enc.SetEscapeHTML(false) - enc.SetIndent("", " ") - return enc.Encode(pres.report) -} diff --git a/ecg/presenter/option.go b/ecg/presenter/option.go deleted file mode 100644 index 3624406..0000000 --- a/ecg/presenter/option.go +++ /dev/null @@ -1,44 +0,0 @@ -// These are the supported Presenters for outputting In-Use-Image results -package presenter - -import "strings" - -const ( - UnknownPresenter Option = iota - JSONPresenter - TablePresenter -) - -var optionStr = []string{ - "UnknownPresenter", - "json", - "table", -} - -var Options = []Option{ - JSONPresenter, - TablePresenter, -} - -type Option int - -// Parse the Presenter option from a string -func ParseOption(userStr string) Option { - switch strings.ToLower(userStr) { - case strings.ToLower(JSONPresenter.String()): - return JSONPresenter - case strings.ToLower(TablePresenter.String()): - return TablePresenter - default: - return UnknownPresenter - } -} - -// Convert the Presenter option to a string -func (o Option) String() string { - if int(o) >= len(optionStr) || o < 0 { - return optionStr[0] - } - - return optionStr[o] -} diff --git a/ecg/presenter/presenter.go b/ecg/presenter/presenter.go deleted file mode 100644 index dadd703..0000000 --- a/ecg/presenter/presenter.go +++ /dev/null @@ -1,27 +0,0 @@ -// This package represents the presenters used to print Image Results to STDOut -package presenter - -import ( - "io" - - "github.com/anchore/elastic-container-gatherer/ecg/inventory" - "github.com/anchore/elastic-container-gatherer/ecg/presenter/json" - "github.com/anchore/elastic-container-gatherer/ecg/presenter/table" -) - -// Presenter is the main interface other Presenters need to implement -type Presenter interface { - Present(io.Writer) error -} - -// GetPresenter retrieves a Presenter that matches a CLI option -func GetPresenter(option Option, report inventory.Report) Presenter { - switch option { - case JSONPresenter: - return json.NewPresenter(report) - case TablePresenter: - return table.NewPresenter(report) - default: - return nil - } -} diff --git a/ecg/presenter/table/presenter.go b/ecg/presenter/table/presenter.go deleted file mode 100644 index 3ffc091..0000000 --- a/ecg/presenter/table/presenter.go +++ /dev/null @@ -1,73 +0,0 @@ -// If Output == "table" this presenter is used -package table - -import ( - "io" - "sort" - - "github.com/anchore/elastic-container-gatherer/ecg/inventory" - - "github.com/olekukonko/tablewriter" -) - -// Presenter is a generic struct for holding fields needed for reporting -type Presenter struct { - report inventory.Report -} - -// NewPresenter is a *Presenter constructor -func NewPresenter(report inventory.Report) *Presenter { - return &Presenter{ - report: report, - } -} - -// Present creates a JSON-based reporting -func (pres *Presenter) Present(output io.Writer) error { - rows := make([][]string, 0) - - columns := []string{"Image Tag", "Repo Digest", "Cluster"} - for _, n := range pres.report.Results { - cluster := n.Namespace - for _, image := range n.Images { - row := []string{image.Tag, image.RepoDigest, cluster} - rows = append(rows, row) - } - } - - if len(rows) == 0 { - _, err := io.WriteString(output, "No Images found\n") - return err - } - - // 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.SetAutoWrapText(false) - table.SetHeaderAlignment(tablewriter.ALIGN_LEFT) - table.SetAlignment(tablewriter.ALIGN_LEFT) - - table.SetHeaderLine(false) - table.SetBorder(false) - table.SetAutoFormatHeaders(true) - table.SetCenterSeparator("") - table.SetColumnSeparator("") - table.SetRowSeparator("") - table.SetTablePadding(" ") - table.SetNoWhiteSpace(true) - - table.AppendBulk(rows) - table.Render() - - return nil -} diff --git a/internal/config/config.go b/internal/config/config.go index 93c8931..17e9a64 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -16,7 +16,6 @@ import ( "gopkg.in/yaml.v2" "github.com/adrg/xdg" - "github.com/anchore/elastic-container-gatherer/ecg/presenter" "github.com/anchore/elastic-container-gatherer/internal" "github.com/mitchellh/go-homedir" "github.com/spf13/viper" @@ -36,8 +35,6 @@ type CliOnlyOptions struct { // All Application configurations type Application struct { ConfigPath string - PresenterOpt presenter.Option - Output string `mapstructure:"output"` Log Logging `mapstructure:"log"` CliOptions CliOnlyOptions MissingTagPolicy MissingTagConf `mapstructure:"missing-tag-policy"` @@ -121,13 +118,6 @@ func LoadConfigFromFile(v *viper.Viper, cliOpts *CliOnlyOptions) (*Application, // Build the configuration object (to be used as a singleton) func (cfg *Application) Build() error { - // set the presenter - presenterOption := presenter.ParseOption(cfg.Output) - if presenterOption == presenter.UnknownPresenter { - return fmt.Errorf("bad --output value '%s'", cfg.Output) - } - cfg.PresenterOpt = presenterOption - if cfg.Log.Level != "" { if cfg.CliOptions.Verbosity > 0 { return fmt.Errorf("cannot explicitly set log level (cfg file or env var) and use -v flag together")