// Package cli implements the sutil command tree. // // The tree is built by New rather than assembled in init functions, so // the package holds no global state and tests can construct it repeatedly // with captured input and output. package cli import ( "github.com/spf13/cobra" "github.com/spf13/viper" ) // Params configures New. type Params struct { // Version is the version string embedded at build time. It is shown // by `sutil version`, `sutil --version`, and `sutil info`. Version string // ConfigDir is the directory searched for the optional .sneak // configuration file. Empty means the user's home directory; tests set // it to a temporary directory so the real home is never consulted. ConfigDir string } // app carries the state shared by every command: the build parameters, // the --config flag, and the configuration loaded before any command runs. type app struct { params Params configFile string config *viper.Viper } // New builds the root sutil command with every subcommand attached. func New(p Params) *cobra.Command { a := &app{params: p, configFile: "", config: nil} root := &cobra.Command{ Use: "sutil", Short: "sneak's shell utility", Long: `sutil is a small collection of shell utilities worth having on every machine: a fast pseudorandom byte stream and a memorable password generator. Before any command runs, sutil loads the optional configuration file named by --config, or else ~/.sneak.yaml (or .json, .toml, ...) if it exists, and makes environment variables available alongside it.`, Version: p.Version, SilenceUsage: true, PersistentPreRunE: a.loadConfig, } root.PersistentFlags().StringVar( &a.configFile, "config", "", "config file (default is "+configName+".* in the home directory)", ) root.AddCommand( newVersionCommand(p), newInfoCommand(a), newGenerateCommand(), ) return root }