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: To generate an SBOM for a Docker or OCI image:
``` ```
syft packages <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). 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 ( import (
"fmt" "fmt"
"os" "os"
"strings"
"github.com/spf13/cobra" "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() { func Execute() {
if err := rootCmd.Execute(); err != nil { if err := rootCmd.Execute(); err != nil {
fmt.Fprintln(os.Stderr, color.Red.Sprint(err.Error())) 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 // 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). // shared concerns (the root-packages alias).
func initCmdAliasBindings() { func initCmdAliasBindings() {
// TODO: when the root alias command is removed, this function (hack) can be removed activeCmd, _, err := rootCmd.Find(os.Args[1:])
if err != nil {
// map of all commands except for root panic(err)
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"))
} }
if activeCmd == packagesCmd || activeCmd == rootCmd { 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 // 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 // initialization structure against typical patterns used with cobra, which is somewhat extreme for a
// temporary alias) // temporary alias)
if err := bindConfigOptions(activeCmd.Flags()); err != nil { if err = bindPackagesConfigOptions(activeCmd.Flags()); err != nil {
panic(err) panic(err)
} }
} else { } 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) 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 ////////////////////////////////////////////// ///////// Formatting & Input options //////////////////////////////////////////////
if err := viper.BindPFlag("package.cataloger.scope", flags.Lookup("scope")); err != nil { if err := viper.BindPFlag("package.cataloger.scope", flags.Lookup("scope")); err != nil {

View File

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