diff --git a/cmd/common.go b/cmd/common.go new file mode 100755 index 0000000..df953f8 --- /dev/null +++ b/cmd/common.go @@ -0,0 +1,15 @@ +package cmd + +import "github.com/keenmate/db-gen/common" + +const ( + keyDebug = "debug" + keyConnectionString = "connectionString" + keyConfig = "config" +) + +var commonFlags = []common.FlagArgument{ + common.NewBoolFlag(keyDebug, "d", false, "Print debug logs and create debug files"), + common.NewStringFlag(keyConfig, "s", "", "Connection string used to connect to database"), + common.NewStringFlag(keyConnectionString, "c", "", "Path to configuration file"), +} diff --git a/cmd/completion.go b/cmd/completion.go new file mode 100755 index 0000000..e179dfb --- /dev/null +++ b/cmd/completion.go @@ -0,0 +1,66 @@ +package cmd + +import ( + "fmt" + "github.com/spf13/cobra" + "os" +) + +var completionCmd = &cobra.Command{ + Use: "completion [bash|zsh|fish|powershell]", + Short: "Generate completion script", + Long: fmt.Sprintf(`To load completions: + +Bash: + + $ source <(%[1]s completion bash) + + # To load completions for each session, execute once: + # Linux: + $ %[1]s completion bash > /etc/bash_completion.d/%[1]s + # macOS: + $ %[1]s completion bash > $(brew --prefix)/etc/bash_completion.d/%[1]s + +Zsh: + + # If shell completion is not already enabled in your environment, + # you will need to enable it. You can execute the following once: + + $ echo "autoload -U compinit; compinit" >> ~/.zshrc + + # To load completions for each session, execute once: + $ %[1]s completion zsh > "${fpath[1]}/_%[1]s" + + # You will need to start a new shell for this setup to take effect. + +fish: + + $ %[1]s completion fish | source + + # To load completions for each session, execute once: + $ %[1]s completion fish > ~/.config/fish/completions/%[1]s.fish + +PowerShell: + + PS> %[1]s completion powershell | Out-String | Invoke-Expression + + # To load completions for every new session, run: + PS> %[1]s completion powershell > %[1]s.ps1 + # and source this file from your PowerShell profile. +`, rootCmd.Root().Name()), + DisableFlagsInUseLine: true, + ValidArgs: []string{"bash", "zsh", "fish", "powershell"}, + Args: cobra.MatchAll(cobra.ExactArgs(1), cobra.OnlyValidArgs), + Run: func(cmd *cobra.Command, args []string) { + switch args[0] { + case "bash": + cmd.Root().GenBashCompletion(os.Stdout) + case "zsh": + cmd.Root().GenZshCompletion(os.Stdout) + case "fish": + cmd.Root().GenFishCompletion(os.Stdout, true) + case "powershell": + cmd.Root().GenPowerShellCompletionWithDesc(os.Stdout) + } + }, +} diff --git a/cmd/generate.go b/cmd/generate.go index 96a748f..8e8a694 100755 --- a/cmd/generate.go +++ b/cmd/generate.go @@ -9,12 +9,11 @@ import ( "log" ) -const ( - keyDebug = "debug" - keyConnectionString = "connectionString" - keyConfig = "config" - keyUseRoutinesFile = "useRoutinesFile" -) +const keyUseRoutinesFile = "useRoutinesFile" + +var generateFlags = []common.FlagArgument{ + common.NewBoolFlag(keyUseRoutinesFile, "", false, "Use routines file to generate code"), +} var generateCmd = &cobra.Command{ Use: "generate", @@ -28,11 +27,7 @@ var generateCmd = &cobra.Command{ `, Run: func(cmd *cobra.Command, args []string) { - common.BindBoolFlag(cmd, keyDebug) - common.BindBoolFlag(cmd, keyUseRoutinesFile) - common.BindStringFlag(cmd, keyConnectionString) - common.BindStringFlag(cmd, keyConfig) - + common.BindFlags(cmd, append(commonFlags, generateFlags...)) _, err := dbGen.ReadConfig(viper.GetString(keyConfig)) if err != nil { common.Exit("configuration error: %s", err) @@ -50,11 +45,7 @@ var generateCmd = &cobra.Command{ func init() { rootCmd.AddCommand(generateCmd) - // set cli flags - common.DefineBoolFlag(generateCmd, keyDebug, "d", false, "Print debug logs and create debug files") - common.DefineBoolFlag(generateCmd, keyUseRoutinesFile, "", false, "Use routines file to generate code") - common.DefineStringFlag(generateCmd, keyConnectionString, "s", "", "Connection string used to connect to database") - common.DefineStringFlag(generateCmd, keyConfig, "c", "", "Path to configuration file") + common.DefineFlags(generateCmd, append(commonFlags, generateFlags...)) } func doGenerate() error { diff --git a/cmd/root.go b/cmd/root.go index 5ba2cd0..b090a3e 100755 --- a/cmd/root.go +++ b/cmd/root.go @@ -18,7 +18,7 @@ For more information, see github.com/keenmate/db-gen `, } -// Execute adds all child commands to the root command and sets flags appropriately. +// Execute adds all child commands to the root command and sets generateCmdFlags appropriately. // This is called by main.main(). It only needs to happen once to the rootCmd. func Execute(versionStringFile string) { // because this is a top level file, we have to pass it like this @@ -33,8 +33,8 @@ func Execute(versionStringFile string) { func init() { cobra.OnInitialize(initConfig) - // Here you will define your flags and configuration settings. - // Cobra supports persistent flags, which, if defined here, + // Here you will define your generateCmdFlags and configuration settings. + // Cobra supports persistent generateCmdFlags, which, if defined here, // will be global for your application. //common.ConfigurationString(rootCmd, "config", "c", "", "Path to configuration file") diff --git a/cmd/routines.go b/cmd/routines.go index 3ddf8e0..cd70b89 100755 --- a/cmd/routines.go +++ b/cmd/routines.go @@ -14,10 +14,7 @@ var getRoutinesCmd = &cobra.Command{ Short: "Get routines", Long: "Get routines from database and save them to file to generate later", Run: func(cmd *cobra.Command, args []string) { - common.BindBoolFlag(cmd, keyDebug) - common.BindBoolFlag(cmd, keyUseRoutinesFile) - common.BindStringFlag(cmd, keyConnectionString) - common.BindStringFlag(cmd, keyConfig) + common.BindFlags(cmd, commonFlags) configLocation := viper.GetString("config") @@ -30,6 +27,10 @@ var getRoutinesCmd = &cobra.Command{ viper.AutomaticEnv() // read in environment variables that match + if args[0] != "" { + viper.Set("routinesFile", args[0]) + } + err = doGetRoutines() if err != nil { @@ -41,11 +42,7 @@ var getRoutinesCmd = &cobra.Command{ func init() { rootCmd.AddCommand(getRoutinesCmd) - // set cli flags - common.DefineBoolFlag(getRoutinesCmd, keyDebug, "d", false, "Print debug logs and create debug files") - common.DefineBoolFlag(getRoutinesCmd, keyUseRoutinesFile, "", false, "Use routines file to generate code") - common.DefineStringFlag(getRoutinesCmd, keyConnectionString, "s", "", "Connection string used to connect to database") - common.DefineStringFlag(getRoutinesCmd, keyConfig, "c", "", "Path to configuration file") + common.DefineFlags(getRoutinesCmd, commonFlags) } func doGetRoutines() error { diff --git a/common/configuration.go b/common/configuration.go deleted file mode 100755 index 3dc5eeb..0000000 --- a/common/configuration.go +++ /dev/null @@ -1,24 +0,0 @@ -package common - -import ( - "github.com/spf13/cobra" - "github.com/spf13/viper" -) - -func DefineStringFlag(command *cobra.Command, key string, shorthand string, defaultValue string, usage string) { - command.Flags().StringP(key, shorthand, defaultValue, usage) -} - -func DefineBoolFlag(command *cobra.Command, key string, shorthand string, defaultValue bool, usage string) { - command.Flags().BoolP(key, shorthand, defaultValue, usage) -} - -// Due to bug/design flaw in viper, we need to bind flags only after we run function - -func BindStringFlag(command *cobra.Command, key string) { - _ = viper.BindPFlag(key, command.Flags().Lookup(key)) -} - -func BindBoolFlag(command *cobra.Command, key string) { - _ = viper.BindPFlag(key, command.Flags().Lookup(key)) -} diff --git a/common/flagHelper.go b/common/flagHelper.go new file mode 100755 index 0000000..08006af --- /dev/null +++ b/common/flagHelper.go @@ -0,0 +1,73 @@ +package common + +import ( + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +type FlagArgument interface { + DefineFlag(command *cobra.Command) + BindFlag(command *cobra.Command) +} + +type StringFlag struct { + key string + shorthand string + defaultValue string + usage string +} + +func (f *StringFlag) DefineFlag(command *cobra.Command) { + command.Flags().StringP(f.key, f.shorthand, f.defaultValue, f.usage) + +} + +func (f *StringFlag) BindFlag(command *cobra.Command) { + _ = viper.BindPFlag(f.key, command.Flags().Lookup(f.key)) +} + +func NewStringFlag(key string, shorthand string, defaultValue string, usage string) *StringFlag { + return &StringFlag{ + key: key, + shorthand: shorthand, + defaultValue: defaultValue, + usage: usage, + } +} + +type BoolFlag struct { + key string + shorthand string + defaultValue bool + usage string +} + +func (f *BoolFlag) DefineFlag(command *cobra.Command) { + command.Flags().BoolP(f.key, f.shorthand, f.defaultValue, f.usage) +} + +func (f *BoolFlag) BindFlag(command *cobra.Command) { + _ = viper.BindPFlag(f.key, command.Flags().Lookup(f.key)) +} + +func NewBoolFlag(key string, shorthand string, defaultValue bool, usage string) *BoolFlag { + return &BoolFlag{ + key: key, + shorthand: shorthand, + defaultValue: defaultValue, + usage: usage, + } +} + +// BindFlags we nned to separate binding from declaration if we dont have unique name for each flag +func BindFlags(command *cobra.Command, flags []FlagArgument) { + for _, flag := range flags { + flag.BindFlag(command) + } +} + +func DefineFlags(command *cobra.Command, flags []FlagArgument) { + for _, flag := range flags { + flag.DefineFlag(command) + } +}