Skip to content

Commit

Permalink
feat: allow for stdout to be buffered on each command (#2335)
Browse files Browse the repository at this point in the history
* feat: add preRun func to version to restore stdout

Signed-off-by: Christopher Phillips <christopher.phillips@anchore.com>

* test: add test to capture version in output

Signed-off-by: Christopher Phillips <christopher.phillips@anchore.com>

* change stdout buffering to log to be opt-in per command

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>

* fix tests

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>

---------

Signed-off-by: Christopher Phillips <christopher.phillips@anchore.com>
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
Co-authored-by: Alex Goodman <wagoodman@users.noreply.github.com>
  • Loading branch information
spiffcs and wagoodman committed Nov 17, 2023
1 parent 1c787f4 commit ba80e49
Show file tree
Hide file tree
Showing 11 changed files with 62 additions and 75 deletions.
4 changes: 2 additions & 2 deletions cmd/syft/cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ import (
// It also constructs the syft attest command and the syft version command.
// `RunE` is the earliest that the complete application configuration can be loaded.
func Application(id clio.Identification) clio.Application {
app, rootCmd := create(id, os.Stdout)
return ui.StdoutLoggingApplication(app, rootCmd)
app, _ := create(id, os.Stdout)
return app
}

// Command returns the root command for the syft CLI application. This is useful for embedding the entire syft CLI
Expand Down
4 changes: 4 additions & 0 deletions cmd/syft/cli/commands/attest.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"github.com/anchore/clio"
"github.com/anchore/stereoscope/pkg/image"
"github.com/anchore/syft/cmd/syft/cli/options"
"github.com/anchore/syft/cmd/syft/internal/ui"
"github.com/anchore/syft/internal"
"github.com/anchore/syft/internal/bus"
"github.com/anchore/syft/internal/file"
Expand Down Expand Up @@ -78,6 +79,9 @@ func Attest(app clio.Application) *cobra.Command {
Args: validatePackagesArgs,
PreRunE: applicationUpdateCheck(id, &opts.UpdateCheck),
RunE: func(cmd *cobra.Command, args []string) error {
restoreStdout := ui.CaptureStdoutToTraceLog()
defer restoreStdout()

return runAttest(id, opts, args[0])
},
}, opts)
Expand Down
4 changes: 4 additions & 0 deletions cmd/syft/cli/commands/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (

"github.com/anchore/clio"
"github.com/anchore/syft/cmd/syft/cli/options"
"github.com/anchore/syft/cmd/syft/internal/ui"
"github.com/anchore/syft/internal"
"github.com/anchore/syft/internal/log"
"github.com/anchore/syft/syft/format"
Expand Down Expand Up @@ -47,6 +48,9 @@ func Convert(app clio.Application) *cobra.Command {
Args: validateConvertArgs,
PreRunE: applicationUpdateCheck(id, &opts.UpdateCheck),
RunE: func(cmd *cobra.Command, args []string) error {
restoreStdout := ui.CaptureStdoutToTraceLog()
defer restoreStdout()

return RunConvert(opts, args[0])
},
}, opts)
Expand Down
4 changes: 4 additions & 0 deletions cmd/syft/cli/commands/packages.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/anchore/stereoscope/pkg/image"
"github.com/anchore/syft/cmd/syft/cli/eventloop"
"github.com/anchore/syft/cmd/syft/cli/options"
"github.com/anchore/syft/cmd/syft/internal/ui"
"github.com/anchore/syft/internal"
"github.com/anchore/syft/internal/file"
"github.com/anchore/syft/internal/log"
Expand Down Expand Up @@ -84,6 +85,9 @@ func Packages(app clio.Application) *cobra.Command {
Args: validatePackagesArgs,
PreRunE: applicationUpdateCheck(id, &opts.UpdateCheck),
RunE: func(cmd *cobra.Command, args []string) error {
restoreStdout := ui.CaptureStdoutToTraceLog()
defer restoreStdout()

return runPackages(id, opts, args[0])
},
}, opts)
Expand Down
4 changes: 4 additions & 0 deletions cmd/syft/cli/commands/poweruser.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/anchore/stereoscope/pkg/image"
"github.com/anchore/syft/cmd/syft/cli/eventloop"
"github.com/anchore/syft/cmd/syft/cli/options"
"github.com/anchore/syft/cmd/syft/internal/ui"
"github.com/anchore/syft/internal"
"github.com/anchore/syft/syft/artifact"
"github.com/anchore/syft/syft/format/syftjson"
Expand Down Expand Up @@ -58,6 +59,9 @@ func PowerUser(app clio.Application) *cobra.Command {
Hidden: true,
PreRunE: applicationUpdateCheck(id, &opts.UpdateCheck),
RunE: func(cmd *cobra.Command, args []string) error {
restoreStdout := ui.CaptureStdoutToTraceLog()
defer restoreStdout()

return runPowerUser(id, opts, args[0])
},
}, opts)
Expand Down
16 changes: 11 additions & 5 deletions cmd/syft/internal/ui/capture.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,19 @@ import (
"github.com/anchore/syft/internal/log"
)

// capture replaces the provided *os.File and redirects output to the provided writer. The return value is a function,
// which is used to stop the current capturing of output and restore the original file.
const defaultStdoutLogBufferSize = 1024

// CaptureStdoutToTraceLog replaces stdout and redirects output to the log as trace lines. The return value is a
// function, which is used to stop the current capturing of output and restore the original file.
// Example:
//
// restore := capture(&os.Stderr, writer)
// // here, stderr will be captured and redirected to the provided writer
// restore() // block until the output has all been sent to the writer and restore the original stderr
// restore := CaptureStdoutToTraceLog()
// // here, stdout will be captured and redirected to the provided writer
// restore() // block until the output has all been sent to the writer and restore the original stdout
func CaptureStdoutToTraceLog() (close func()) {
return capture(&os.Stdout, newLogWriter(), defaultStdoutLogBufferSize)
}

func capture(target **os.File, writer io.Writer, bufSize int) (close func()) {
original := *target

Expand Down
2 changes: 1 addition & 1 deletion cmd/syft/internal/ui/log_writer.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ func (l *logWriter) Write(data []byte) (n int, err error) {
s, err := l.r.ReadString('\n')
s = strings.TrimRight(s, "\n")
for s != "" {
log.Trace(s)
log.Trace("[unexpected stdout] " + s)
n += len(s)
if err != nil {
break
Expand Down
4 changes: 2 additions & 2 deletions cmd/syft/internal/ui/log_writer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,14 @@ func Test_logWriter(t *testing.T) {

_, _ = w.Write([]byte("a\nvalue"))

expected := []any{"a", "value"}
expected := []any{"[unexpected stdout] a", "[unexpected stdout] value"}
require.Equal(t, expected, bl.values)

bl.values = nil
_, _ = w.Write([]byte("some"))
_, _ = w.Write([]byte("thing"))

expected = []any{"some", "thing"}
expected = []any{"[unexpected stdout] some", "[unexpected stdout] thing"}
require.Equal(t, expected, bl.values)
}

Expand Down
63 changes: 0 additions & 63 deletions cmd/syft/internal/ui/stdout_logging_application.go

This file was deleted.

3 changes: 1 addition & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,6 @@ require (
modernc.org/sqlite v1.27.0
)

require github.com/spf13/pflag v1.0.5

require (
dario.cat/mergo v1.0.0 // indirect
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 // indirect
Expand Down Expand Up @@ -185,6 +183,7 @@ require (
github.com/skeema/knownhosts v1.2.0 // indirect
github.com/spf13/cast v1.5.1 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/spf13/viper v1.16.0 // indirect
github.com/subosito/gotenv v1.4.2 // indirect
github.com/sylabs/sif/v2 v2.11.5 // indirect
Expand Down
29 changes: 29 additions & 0 deletions test/cli/version_cmd_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package cli

import (
"testing"
)

func TestVersionCmdPrintsToStdout(t *testing.T) {
tests := []struct {
name string
env map[string]string
assertions []traitAssertion
}{
{
name: "version command prints to stdout",
assertions: []traitAssertion{
assertInOutput("Version:"),
},
},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
pkgCmd, pkgsStdout, pkgsStderr := runSyft(t, test.env, "version")
for _, traitFn := range test.assertions {
traitFn(t, pkgsStdout, pkgsStderr, pkgCmd.ProcessState.ExitCode())
}
})
}
}

0 comments on commit ba80e49

Please sign in to comment.