github.com/noqcks/syft@v0.0.0-20230920222752-a9e2c4e288e5/cmd/syft/cli/cli.go (about) 1 package cli 2 3 import ( 4 "os" 5 6 cranecmd "github.com/google/go-containerregistry/cmd/crane/cmd" 7 "github.com/spf13/cobra" 8 9 "github.com/anchore/clio" 10 "github.com/anchore/stereoscope" 11 "github.com/anchore/syft/cmd/syft/cli/commands" 12 handler "github.com/anchore/syft/cmd/syft/cli/ui" 13 "github.com/anchore/syft/cmd/syft/internal/ui" 14 "github.com/anchore/syft/internal/bus" 15 "github.com/anchore/syft/internal/log" 16 "github.com/anchore/syft/internal/redact" 17 ) 18 19 // Application constructs the `syft packages` command, aliases the root command to `syft packages`, 20 // and constructs the `syft power-user` command. It is also responsible for 21 // organizing flag usage and injecting the application config for each command. 22 // It also constructs the syft attest command and the syft version command. 23 // `RunE` is the earliest that the complete application configuration can be loaded. 24 func Application(id clio.Identification) clio.Application { 25 app, _ := create(id) 26 return app 27 } 28 29 // Command returns the root command for the syft CLI application. This is useful for embedding the entire syft CLI 30 // into an existing application. 31 func Command(id clio.Identification) *cobra.Command { 32 _, cmd := create(id) 33 return cmd 34 } 35 36 func create(id clio.Identification) (clio.Application, *cobra.Command) { 37 clioCfg := clio.NewSetupConfig(id). 38 WithGlobalConfigFlag(). // add persistent -c <path> for reading an application config from 39 WithGlobalLoggingFlags(). // add persistent -v and -q flags tied to the logging config 40 WithConfigInRootHelp(). // --help on the root command renders the full application config in the help text 41 WithUIConstructor( 42 // select a UI based on the logging configuration and state of stdin (if stdin is a tty) 43 func(cfg clio.Config) ([]clio.UI, error) { 44 noUI := ui.None(cfg.Log.Quiet) 45 if !cfg.Log.AllowUI(os.Stdin) || cfg.Log.Quiet { 46 return []clio.UI{noUI}, nil 47 } 48 49 h := handler.New(handler.DefaultHandlerConfig()) 50 51 return []clio.UI{ 52 ui.New(h, false, cfg.Log.Quiet), 53 noUI, 54 }, nil 55 }, 56 ). 57 WithInitializers( 58 func(state *clio.State) error { 59 // clio is setting up and providing the bus, redact store, and logger to the application. Once loaded, 60 // we can hoist them into the internal packages for global use. 61 stereoscope.SetBus(state.Bus) 62 bus.Set(state.Bus) 63 redact.Set(state.RedactStore) 64 log.Set(state.Logger) 65 stereoscope.SetLogger(state.Logger) 66 67 return nil 68 }, 69 ). 70 WithPostRuns(func(state *clio.State, err error) { 71 stereoscope.Cleanup() 72 }) 73 74 app := clio.New(*clioCfg) 75 76 // since root is aliased as the packages cmd we need to construct this command first 77 // we also need the command to have information about the `root` options because of this alias 78 packagesCmd := commands.Packages(app) 79 80 // rootCmd is currently an alias for the packages command 81 rootCmd := commands.Root(app, packagesCmd) 82 83 // add sub-commands 84 rootCmd.AddCommand( 85 packagesCmd, 86 commands.PowerUser(app), 87 commands.Attest(app), 88 commands.Convert(app), 89 clio.VersionCommand(id), 90 cranecmd.NewCmdAuthLogin(id.Name), // syft login uses the same command as crane 91 ) 92 93 return app, rootCmd 94 }