Disable ETUI when piping input (#463)

* disable etui when piping input

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* restore jotframe version

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* remove test code

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* raise error from IsPipedInput

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* factor out verbosity check to function

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
This commit is contained in:
Alex Goodman 2021-10-20 12:40:57 -04:00 committed by GitHub
parent 19a513a42a
commit f75889c694
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 63 additions and 29 deletions

View file

@ -183,10 +183,21 @@ func rootExec(_ *cobra.Command, args []string) error {
setupSignals(),
eventSubscription,
stereoscope.Cleanup,
ui.Select(appConfig.CliOptions.Verbosity > 0, appConfig.Quiet, reporter)...,
ui.Select(isVerbose(), appConfig.Quiet, reporter)...,
)
}
func isVerbose() (result bool) {
isPipedInput, err := internal.IsPipedInput()
if err != nil {
// since we can't tell if there was piped input we assume that there could be to disable the ETUI
log.Warnf("unable to determine if there is piped input: %+v", err)
return true
}
// verbosity should consider if there is piped input (in which case we should not show the ETUI)
return appConfig.CliOptions.Verbosity > 0 || isPipedInput
}
// nolint:funlen
func startWorker(userInput string, failOnSeverity *vulnerability.Severity) <-chan error {
errs := make(chan error)
@ -278,7 +289,13 @@ func startWorker(userInput string, failOnSeverity *vulnerability.Severity) <-cha
}
func validateRootArgs(cmd *cobra.Command, args []string) error {
if len(args) == 0 && !internal.IsPipedInput() {
isPipedInput, err := internal.IsPipedInput()
if err != nil {
log.Warnf("unable to determine if there is piped input: %+v", err)
isPipedInput = false
}
if len(args) == 0 && !isPipedInput {
// in the case that no arguments are given and there is no piped input we want to show the help text and return with a non-0 return code.
if err := cmd.Help(); err != nil {
return fmt.Errorf("unable to display help: %w", err)

View file

@ -8,6 +8,8 @@ import (
"io/ioutil"
"os"
"github.com/anchore/grype/internal/log"
"github.com/anchore/grype/internal"
"github.com/anchore/stereoscope/pkg/image"
"github.com/anchore/syft/syft/source"
@ -47,7 +49,13 @@ func Provide(userInput string, scopeOpt source.Scope, registryOptions *image.Reg
}
func bytesFromStdin() []byte {
if internal.IsPipedInput() {
isPipedInput, err := internal.IsPipedInput()
if err != nil {
log.Warnf("unable to determine if there is piped input: %+v", err)
isPipedInput = false
}
if isPipedInput {
capturedStdin, err := ioutil.ReadAll(os.Stdin)
if err != nil {
return nil

View file

@ -132,35 +132,38 @@ func (cfg *Application) parseScopeOption() error {
}
func (cfg *Application) parseLogLevelOption() error {
if cfg.Quiet {
switch {
case cfg.Quiet:
// TODO: this is bad: quiet option trumps all other logging options (such as to a file on disk)
// we should be able to quiet the console logging and leave file logging alone...
// ... this will be an enhancement for later
cfg.Log.LevelOpt = logrus.PanicLevel
} else {
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")
}
case 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")
}
lvl, err := logrus.ParseLevel(strings.ToLower(cfg.Log.Level))
if err != nil {
return fmt.Errorf("bad log level configured (%q): %w", cfg.Log.Level, err)
}
// set the log level explicitly
cfg.Log.LevelOpt = lvl
} else {
// set the log level implicitly
switch v := cfg.CliOptions.Verbosity; {
case v == 1:
cfg.Log.LevelOpt = logrus.InfoLevel
case v >= 2:
cfg.Log.LevelOpt = logrus.DebugLevel
default:
cfg.Log.LevelOpt = logrus.ErrorLevel
}
lvl, err := logrus.ParseLevel(strings.ToLower(cfg.Log.Level))
if err != nil {
return fmt.Errorf("bad log level configured (%q): %w", cfg.Log.Level, err)
}
cfg.Log.LevelOpt = lvl
if cfg.Log.LevelOpt >= logrus.InfoLevel {
cfg.CliOptions.Verbosity = 1
}
default:
switch v := cfg.CliOptions.Verbosity; {
case v == 1:
cfg.Log.LevelOpt = logrus.InfoLevel
case v >= 2:
cfg.Log.LevelOpt = logrus.DebugLevel
default:
cfg.Log.LevelOpt = logrus.ErrorLevel
}
}
return nil
}

View file

@ -1,10 +1,16 @@
package internal
import "os"
import (
"fmt"
"os"
)
// IsPipedInput returns true if there is no input device, which means the user **may** be providing input via a pipe.
func IsPipedInput() bool {
fi, _ := os.Stdin.Stat()
func IsPipedInput() (bool, error) {
fi, err := os.Stdin.Stat()
if err != nil {
return false, fmt.Errorf("unable to determine if there is piped input: %w", err)
}
return fi.Mode()&os.ModeNamedPipe != 0
return fi.Mode()&os.ModeCharDevice == 0, nil
}