simplify command alias logic + remove deprecation warning for root command

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
This commit is contained in:
Alex Goodman 2021-03-22 15:25:04 -04:00
parent 36e4af1953
commit 46636ccb3c
No known key found for this signature in database
GPG Key ID: 5CB45AE22BAB7EA7
4 changed files with 50 additions and 46 deletions

View File

@ -22,6 +22,9 @@ If you encounter an issue, please [let us know using the issue tracker](https://
To generate an SBOM for a Docker or OCI image:
```
syft packages <image>
# note: this is the same as not providing the "packages" subcommand
syft <image>
```
The above output includes only software that is visible in the container (i.e., the squashed representation of the image).

View File

@ -3,7 +3,6 @@ package cmd
import (
"fmt"
"os"
"strings"
"github.com/spf13/cobra"
@ -33,10 +32,6 @@ func init() {
)
}
// provided to disambiguate the root vs packages command, whichever is indicated by the cli args will be set here.
// TODO: when the root alias command is removed, this variable can be removed
var activeCmd *cobra.Command
func Execute() {
if err := rootCmd.Execute(); err != nil {
fmt.Fprintln(os.Stderr, color.Red.Sprint(err.Error()))
@ -48,30 +43,9 @@ func Execute() {
// be done without determining what the primary command that the config options should be bound to since there are
// shared concerns (the root-packages alias).
func initCmdAliasBindings() {
// TODO: when the root alias command is removed, this function (hack) can be removed
// map of all commands except for root
commands := make(map[string]*cobra.Command)
for _, c := range rootCmd.Commands() {
name := strings.Split(c.Use, " ")[0]
commands[name] = c
}
activeCmd = rootCmd
for i, a := range os.Args {
if i == 0 {
// don't consider the bin
continue
}
// check to see if this argument may be a command
if c, exists := commands[a]; exists {
activeCmd = c
}
}
if activeCmd == rootCmd {
// note: cobra supports command deprecation, however the command name is empty and does not report to stderr
fmt.Fprintln(os.Stderr, color.New(color.Bold, color.Red).Sprintf("The root command is deprecated, please use the 'packages' subcommand"))
activeCmd, _, err := rootCmd.Find(os.Args[1:])
if err != nil {
panic(err)
}
if activeCmd == packagesCmd || activeCmd == rootCmd {
@ -81,11 +55,13 @@ func initCmdAliasBindings() {
// reading the application configuration, which implies that it must be an initializer (or rewrite the command
// initialization structure against typical patterns used with cobra, which is somewhat extreme for a
// temporary alias)
if err := bindConfigOptions(activeCmd.Flags()); err != nil {
if err = bindPackagesConfigOptions(activeCmd.Flags()); err != nil {
panic(err)
}
} else {
if err := bindConfigOptions(packagesCmd.Flags()); err != nil {
// even though the root command or packages command is NOT being run, we still need default bindings
// such that application config parsing passes.
if err = bindPackagesConfigOptions(packagesCmd.Flags()); err != nil {
panic(err)
}
}

View File

@ -138,7 +138,7 @@ func setPackageFlags(flags *pflag.FlagSet) {
)
}
func bindConfigOptions(flags *pflag.FlagSet) error {
func bindPackagesConfigOptions(flags *pflag.FlagSet) error {
///////// Formatting & Input options //////////////////////////////////////////////
if err := viper.BindPFlag("package.cataloger.scope", flags.Lookup("scope")); err != nil {

View File

@ -9,25 +9,50 @@ import (
func TestRootCmdAliasesToPackagesSubcommand(t *testing.T) {
request := "docker-archive:" + getFixtureImage(t, "image-pkg-coverage")
deprecationWarning := "The root command is deprecated"
_, aliasStdout, aliasStderr := runSyftCommand(t, nil, request)
if !strings.Contains(aliasStderr, deprecationWarning) {
t.Errorf("missing root-packages alias deprecation warning")
tests := []struct {
name string
env map[string]string
assertions []traitAssertion
}{
{
name: "go-case",
assertions: []traitAssertion{
assertTableReport,
assertSuccessfulReturnCode,
},
},
{
name: "respond-to-output-binding",
env: map[string]string{
"SYFT_OUTPUT": "text",
},
assertions: []traitAssertion{
assertInOutput("[Image]"),
assertSuccessfulReturnCode,
},
},
}
_, pkgsStdout, pkgsStderr := runSyftCommand(t, nil, "packages", request)
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
aliasCmd, aliasStdout, aliasStderr := runSyftCommand(t, test.env, request)
for _, traitFn := range test.assertions {
traitFn(t, aliasStdout, aliasStderr, aliasCmd.ProcessState.ExitCode())
}
if strings.Contains(pkgsStderr, deprecationWarning) {
t.Errorf("packages command should not have deprecation warning")
}
pkgCmd, pkgsStdout, pkgsStderr := runSyftCommand(t, test.env, "packages", request)
for _, traitFn := range test.assertions {
traitFn(t, pkgsStdout, pkgsStderr, pkgCmd.ProcessState.ExitCode())
}
if aliasStdout != pkgsStdout {
t.Errorf("packages and root command should have same report output but do not!")
dmp := diffmatchpatch.New()
diffs := dmp.DiffMain(aliasStdout, pkgsStdout, true)
t.Error(dmp.DiffPrettyText(diffs))
if aliasStdout != pkgsStdout {
t.Errorf("packages and root command should have same report output but do not!")
dmp := diffmatchpatch.New()
diffs := dmp.DiffMain(aliasStdout, pkgsStdout, true)
t.Error(dmp.DiffPrettyText(diffs))
}
})
}
}