package cli import ( "fmt" "os" "github.com/spf13/cobra" "github.com/spf13/pflag" "github.com/zrepl/zrepl/config" ) var rootArgs struct { configPath string } var rootCmd = &cobra.Command{ Use: "zrepl", Short: "One-stop ZFS replication solution", } var bashcompCmd = &cobra.Command{ Use: "bashcomp path/to/out/file", Short: "generate bash completions", Run: func(cmd *cobra.Command, args []string) { if len(args) != 1 { fmt.Fprintf(os.Stderr, "specify exactly one positional agument\n") err := cmd.Usage() if err != nil { panic(err) } os.Exit(1) } if err := rootCmd.GenBashCompletionFile(args[0]); err != nil { fmt.Fprintf(os.Stderr, "error generating bash completion: %s", err) os.Exit(1) } }, Hidden: true, } func init() { rootCmd.PersistentFlags().StringVar(&rootArgs.configPath, "config", "", "config file path") rootCmd.AddCommand(bashcompCmd) } type Subcommand struct { Use string Short string Example string NoRequireConfig bool Run func(subcommand *Subcommand, args []string) error SetupFlags func(f *pflag.FlagSet) SetupSubcommands func() []*Subcommand config *config.Config configErr error } func (s *Subcommand) ConfigParsingError() error { return s.configErr } func (s *Subcommand) Config() *config.Config { if !s.NoRequireConfig && s.config == nil { panic("command that requires config is running and has no config set") } return s.config } func (s *Subcommand) run(cmd *cobra.Command, args []string) { s.tryParseConfig() err := s.Run(s, args) if err != nil { fmt.Fprintf(os.Stderr, "%s\n", err) os.Exit(1) } } func (s *Subcommand) tryParseConfig() { config, err := config.ParseConfig(rootArgs.configPath) s.configErr = err if err != nil { if s.NoRequireConfig { // doesn't matter return } else { fmt.Fprintf(os.Stderr, "could not parse config: %s\n", err) os.Exit(1) } } s.config = config } func AddSubcommand(s *Subcommand) { addSubcommandToCobraCmd(rootCmd, s) } func addSubcommandToCobraCmd(c *cobra.Command, s *Subcommand) { cmd := cobra.Command{ Use: s.Use, Short: s.Short, Example: s.Example, } if s.SetupSubcommands == nil { cmd.Run = s.run } else { for _, sub := range s.SetupSubcommands() { addSubcommandToCobraCmd(&cmd, sub) } } if s.SetupFlags != nil { s.SetupFlags(cmd.Flags()) } c.AddCommand(&cmd) } func Run() { if err := rootCmd.Execute(); err != nil { os.Exit(1) } }