From a5f8ecf9d8118f674b97c6199adfc908f7069f2c Mon Sep 17 00:00:00 2001 From: Manuel Dewald Date: Thu, 22 May 2025 12:03:41 +0200 Subject: [PATCH 1/3] templates with local vars --- cmd/add.go | 5 ++++ cmd/init.go | 5 ++-- cmd/project.go | 26 +++++++++++++++--- go.mod | 1 + tpl/main.go | 73 +++++++++++++++++++++++++++++++------------------- 5 files changed, 76 insertions(+), 34 deletions(-) diff --git a/cmd/add.go b/cmd/add.go index 207c651..462c53d 100644 --- a/cmd/add.go +++ b/cmd/add.go @@ -24,6 +24,7 @@ import ( var ( packageName string parentName string + dirName string addCmd = &cobra.Command{ Use: "add [command name]", @@ -54,6 +55,9 @@ Example: cobra-cli add server -> resulting in a new cmd/server.go`, } wd, err := os.Getwd() + if dirName != "" { + wd += "/" + dirName + } cobra.CheckErr(err) commandName := validateCmdName(args[0]) @@ -77,6 +81,7 @@ Example: cobra-cli add server -> resulting in a new cmd/server.go`, func init() { addCmd.Flags().StringVarP(&packageName, "package", "t", "", "target package name (e.g. github.com/spf13/hugo)") addCmd.Flags().StringVarP(&parentName, "parent", "p", "rootCmd", "variable name of parent command for this command") + addCmd.Flags().StringVarP(&dirName, "dir", "d", "", "relative path to the command's main package") cobra.CheckErr(addCmd.Flags().MarkDeprecated("package", "this operation has been removed.")) } diff --git a/cmd/init.go b/cmd/init.go index aeda40a..c7340fd 100644 --- a/cmd/init.go +++ b/cmd/init.go @@ -69,14 +69,15 @@ func initializeProject(args []string) (string, error) { return "", err } + modName := getModImportPath() + if len(args) > 0 { if args[0] != "." { wd = fmt.Sprintf("%s/%s", wd, args[0]) + modName = fmt.Sprintf("%s/%s", modName, args[0]) } } - modName := getModImportPath() - project := &Project{ AbsolutePath: wd, PkgName: modName, diff --git a/cmd/project.go b/cmd/project.go index ec8980e..832f511 100644 --- a/cmd/project.go +++ b/cmd/project.go @@ -3,6 +3,7 @@ package cmd import ( "fmt" "os" + "strings" "text/template" "github.com/spf13/cobra" @@ -30,7 +31,7 @@ func (p *Project) Create() error { // check if AbsolutePath exists if _, err := os.Stat(p.AbsolutePath); os.IsNotExist(err) { // create directory - if err := os.Mkdir(p.AbsolutePath, 0754); err != nil { + if err := os.MkdirAll(p.AbsolutePath, 0754); err != nil { return err } } @@ -50,7 +51,7 @@ func (p *Project) Create() error { // create cmd/root.go if _, err = os.Stat(fmt.Sprintf("%s/cmd", p.AbsolutePath)); os.IsNotExist(err) { - cobra.CheckErr(os.Mkdir(fmt.Sprintf("%s/cmd", p.AbsolutePath), 0751)) + cobra.CheckErr(os.MkdirAll(fmt.Sprintf("%s/cmd", p.AbsolutePath), 0751)) } rootFile, err := os.Create(fmt.Sprintf("%s/cmd/root.go", p.AbsolutePath)) if err != nil { @@ -83,13 +84,30 @@ func (p *Project) createLicenseFile() error { } func (c *Command) Create() error { - cmdFile, err := os.Create(fmt.Sprintf("%s/cmd/%s.go", c.AbsolutePath, c.CmdName)) + filename := c.CmdName + if c.CmdParent != "rootCmd" { + filename = fmt.Sprintf("%s-%s", strings.TrimSuffix(c.CmdParent, "Cmd"), c.CmdName) + } + cmdFile, err := os.Create(fmt.Sprintf("%s/cmd/%s.go", c.AbsolutePath, filename)) if err != nil { return err } defer cmdFile.Close() - commandTemplate := template.Must(template.New("sub").Parse(string(tpl.AddCommandTemplate()))) + funcMap := template.FuncMap{ + // The name "title" is what the function will be called in the template text. + "typeName": func(cmd string, parent string) string { + name := strings.Title(cmd) + if parent != "rootCmd" { + name = strings.Title(strings.TrimSuffix(parent, "Cmd")) + name + } + name += "Cmd" + return name + }, + "title": strings.Title, + } + + commandTemplate := template.Must(template.New("sub").Funcs(funcMap).Parse(string(tpl.AddCommandTemplate()))) err = commandTemplate.Execute(cmdFile, c) if err != nil { return err diff --git a/go.mod b/go.mod index 4acdff1..bf78b4a 100644 --- a/go.mod +++ b/go.mod @@ -5,4 +5,5 @@ go 1.15 require ( github.com/spf13/cobra v1.6.1 github.com/spf13/viper v1.12.0 + golang.org/x/text v0.3.7 ) diff --git a/tpl/main.go b/tpl/main.go index 009524c..c61183e 100644 --- a/tpl/main.go +++ b/tpl/main.go @@ -49,8 +49,12 @@ import ( var cfgFile string {{- end }} + +// Execute adds all child commands to the root command and sets flags appropriately. +// This is called by main.main(). It only needs to happen once to the rootCmd. +func Execute() { // rootCmd represents the base command when called without any subcommands -var rootCmd = &cobra.Command{ + rootCmd := &cobra.Command{ Use: "{{ .AppName }}", Short: "A brief description of your application", Long: ` + "`" + `A longer description that spans multiple lines and likely contains @@ -63,17 +67,6 @@ to quickly create a Cobra application.` + "`" + `, // has an action associated with it: // Run: func(cmd *cobra.Command, args []string) { }, } - -// Execute adds all child commands to the root command and sets flags appropriately. -// This is called by main.main(). It only needs to happen once to the rootCmd. -func Execute() { - err := rootCmd.Execute() - if err != nil { - os.Exit(1) - } -} - -func init() { {{- if .Viper }} cobra.OnInitialize(initConfig) {{ end }} @@ -87,7 +80,17 @@ func init() { {{ end }} // Cobra also supports local flags, which will only run // when this action is called directly. - rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") + // rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") + + + // Add child commands here + // AddChildCmd(rootCmd) + + + err := rootCmd.Execute() + if err != nil { + os.Exit(1) + } } {{ if .Viper -}} @@ -131,33 +134,47 @@ import ( "github.com/spf13/cobra" ) -// {{ .CmdName }}Cmd represents the {{ .CmdName }} command -var {{ .CmdName }}Cmd = &cobra.Command{ - Use: "{{ .CmdName }}", - Short: "A brief description of your command", - Long: ` + "`" + `A longer description that spans multiple lines and likely contains examples +// {{ typeName .CmdName .CmdParent }} represents the {{ .CmdName }} command +type {{ typeName .CmdName .CmdParent }} struct { + cmd *cobra.Command +} + +func (c *{{ typeName .CmdName .CmdParent }}) RunE(_ *cobra.Command, args []string) error { + //Command execution goes here + + fmt.Printf("running %s", c.cmd.Use) + + return nil +} + +func Add{{ typeName .CmdName .CmdParent }}({{.CmdParent}} *cobra.Command) { + {{.CmdName}} := {{ typeName .CmdName .CmdParent }}{ + cmd: &cobra.Command{ + Use: "{{ .CmdName }}", + Short: "A brief description of your command", + Long: ` + "`" + `A longer description that spans multiple lines and likely contains examples and usage of using your command. For example: Cobra is a CLI library for Go that empowers applications. This application is a tool to generate the needed files to quickly create a Cobra application.` + "`" + `, - Run: func(cmd *cobra.Command, args []string) { - fmt.Println("{{ .CmdName }} called") - }, -} - -func init() { - {{ .CmdParent }}.AddCommand({{ .CmdName }}Cmd) - + }, + } // Here you will define your flags and configuration settings. // Cobra supports Persistent Flags which will work for this command // and all subcommands, e.g.: - // {{ .CmdName }}Cmd.PersistentFlags().String("foo", "", "A help for foo") + // {{.CmdName}}.cmd.PersistentFlags().String("foo", "", "A help for foo") // Cobra supports local flags which will only run when this command // is called directly, e.g.: - // {{ .CmdName }}Cmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") + // {{.CmdName}}.cmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") + {{.CmdParent}}.AddCommand({{.CmdName}}.cmd) + {{.CmdName}}.cmd.RunE = {{.CmdName}}.RunE + + // Add child commands here + // Add{{title .CmdName}}ChildCmd({{.CmdName}}.cmd) } + `) } From 168cb7b59fd3b247b1daf7e8f005ce6bbbb32622 Mon Sep 17 00:00:00 2001 From: Manuel Dewald Date: Thu, 22 May 2025 12:49:40 +0200 Subject: [PATCH 2/3] add flag for local scope --- cmd/add.go | 1 + cmd/init.go | 1 + cmd/project.go | 13 ++- cmd/root.go | 2 + go.mod | 3 +- tpl/add-command.global.tmpl | 40 +++++++++ tpl/add-command.local.tmpl | 54 ++++++++++++ tpl/main.go | 159 +++++------------------------------- tpl/root.global.tmpl | 86 +++++++++++++++++++ tpl/root.local.tmpl | 90 ++++++++++++++++++++ 10 files changed, 306 insertions(+), 143 deletions(-) create mode 100644 tpl/add-command.global.tmpl create mode 100644 tpl/add-command.local.tmpl create mode 100644 tpl/root.global.tmpl create mode 100644 tpl/root.local.tmpl diff --git a/cmd/add.go b/cmd/add.go index 462c53d..e96ab78 100644 --- a/cmd/add.go +++ b/cmd/add.go @@ -68,6 +68,7 @@ Example: cobra-cli add server -> resulting in a new cmd/server.go`, AbsolutePath: wd, Legal: getLicense(), Copyright: copyrightLine(), + LocalVars: localVars, }, } diff --git a/cmd/init.go b/cmd/init.go index c7340fd..c7ab565 100644 --- a/cmd/init.go +++ b/cmd/init.go @@ -85,6 +85,7 @@ func initializeProject(args []string) (string, error) { Copyright: copyrightLine(), Viper: viper.GetBool("useViper"), AppName: path.Base(modName), + LocalVars: localVars, } if err := project.Create(); err != nil { diff --git a/cmd/project.go b/cmd/project.go index 832f511..953d539 100644 --- a/cmd/project.go +++ b/cmd/project.go @@ -19,6 +19,7 @@ type Project struct { Legal License Viper bool AppName string + LocalVars bool } type Command struct { @@ -59,7 +60,11 @@ func (p *Project) Create() error { } defer rootFile.Close() - rootTemplate := template.Must(template.New("root").Parse(string(tpl.RootTemplate()))) + tmpl := tpl.RootTemplateGlobal() + if p.LocalVars { + tmpl = tpl.RootTemplateLocal() + } + rootTemplate := template.Must(template.New("root").Parse(string(tmpl))) err = rootTemplate.Execute(rootFile, p) if err != nil { return err @@ -107,7 +112,11 @@ func (c *Command) Create() error { "title": strings.Title, } - commandTemplate := template.Must(template.New("sub").Funcs(funcMap).Parse(string(tpl.AddCommandTemplate()))) + tmpl := tpl.AddCommandTemplateGlobal() + if c.LocalVars { + tmpl = tpl.AddCommandTemplateLocal() + } + commandTemplate := template.Must(template.New("sub").Funcs(funcMap).Parse(string(tmpl))) err = commandTemplate.Execute(cmdFile, c) if err != nil { return err diff --git a/cmd/root.go b/cmd/root.go index d1fa407..4feefb8 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -26,6 +26,7 @@ var ( // Used for flags. cfgFile string userLicense string + localVars bool rootCmd = &cobra.Command{ Use: "cobra-cli", @@ -48,6 +49,7 @@ func init() { rootCmd.PersistentFlags().StringP("author", "a", "YOUR NAME", "author name for copyright attribution") rootCmd.PersistentFlags().StringVarP(&userLicense, "license", "l", "", "name of license for the project") rootCmd.PersistentFlags().Bool("viper", false, "use Viper for configuration") + rootCmd.PersistentFlags().BoolVarP(&localVars, "local", "L", false, "project uses local-scoped variables") cobra.CheckErr(viper.BindPFlag("author", rootCmd.PersistentFlags().Lookup("author"))) cobra.CheckErr(viper.BindPFlag("useViper", rootCmd.PersistentFlags().Lookup("viper"))) viper.SetDefault("author", "NAME HERE ") diff --git a/go.mod b/go.mod index bf78b4a..8a77e02 100644 --- a/go.mod +++ b/go.mod @@ -1,9 +1,8 @@ module github.com/spf13/cobra-cli -go 1.15 +go 1.16 require ( github.com/spf13/cobra v1.6.1 github.com/spf13/viper v1.12.0 - golang.org/x/text v0.3.7 ) diff --git a/tpl/add-command.global.tmpl b/tpl/add-command.global.tmpl new file mode 100644 index 0000000..c0b7eff --- /dev/null +++ b/tpl/add-command.global.tmpl @@ -0,0 +1,40 @@ +/* +{{ .Project.Copyright }} +{{ if .Legal.Header }}{{ .Legal.Header }}{{ end }} +*/ +package cmd + +import ( + "fmt" + + "github.com/spf13/cobra" +) + +// {{ .CmdName }}Cmd represents the {{ .CmdName }} command +var {{ .CmdName }}Cmd = &cobra.Command{ + Use: "{{ .CmdName }}", + Short: "A brief description of your command", + Long: `A longer description that spans multiple lines and likely contains examples +and usage of using your command. For example: + +Cobra is a CLI library for Go that empowers applications. +This application is a tool to generate the needed files +to quickly create a Cobra application.`, + Run: func(cmd *cobra.Command, args []string) { + fmt.Println("{{ .CmdName }} called") + }, +} + +func init() { + {{ .CmdParent }}.AddCommand({{ .CmdName }}Cmd) + + // Here you will define your flags and configuration settings. + + // Cobra supports Persistent Flags which will work for this command + // and all subcommands, e.g.: + // {{ .CmdName }}Cmd.PersistentFlags().String("foo", "", "A help for foo") + + // Cobra supports local flags which will only run when this command + // is called directly, e.g.: + // {{ .CmdName }}Cmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") +} diff --git a/tpl/add-command.local.tmpl b/tpl/add-command.local.tmpl new file mode 100644 index 0000000..abf5e02 --- /dev/null +++ b/tpl/add-command.local.tmpl @@ -0,0 +1,54 @@ +/* +{{ .Project.Copyright }} +{{ if .Legal.Header }}{{ .Legal.Header }}{{ end }} +*/ +package cmd + +import ( + "fmt" + + "github.com/spf13/cobra" +) + +// {{ typeName .CmdName .CmdParent }} represents the {{ .CmdName }} command +type {{ typeName .CmdName .CmdParent }} struct { + cmd *cobra.Command +} + +func (c *{{ typeName .CmdName .CmdParent }}) RunE(_ *cobra.Command, args []string) error { + //Command execution goes here + + fmt.Printf("running %s", c.cmd.Use) + + return nil +} + +func Add{{ typeName .CmdName .CmdParent }}({{.CmdParent}} *cobra.Command) { + {{.CmdName}} := {{ typeName .CmdName .CmdParent }}{ + cmd: &cobra.Command{ + Use: "{{ .CmdName }}", + Short: "A brief description of your command", + Long: `A longer description that spans multiple lines and likely contains examples +and usage of using your command. For example: + +Cobra is a CLI library for Go that empowers applications. +This application is a tool to generate the needed files +to quickly create a Cobra application.`, + }, + } + // Here you will define your flags and configuration settings. + + // Cobra supports Persistent Flags which will work for this command + // and all subcommands, e.g.: + // {{.CmdName}}.cmd.PersistentFlags().String("foo", "", "A help for foo") + + // Cobra supports local flags which will only run when this command + // is called directly, e.g.: + // {{.CmdName}}.cmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") + {{.CmdParent}}.AddCommand({{.CmdName}}.cmd) + {{.CmdName}}.cmd.RunE = {{.CmdName}}.RunE + + // Add child commands here + // Add{{title .CmdName}}ChildCmd({{.CmdName}}.cmd) +} + diff --git a/tpl/main.go b/tpl/main.go index c61183e..84c9702 100644 --- a/tpl/main.go +++ b/tpl/main.go @@ -13,6 +13,10 @@ package tpl +import ( + _ "embed" +) + func MainTemplate() []byte { return []byte(`/* {{ .Copyright }} @@ -28,153 +32,30 @@ func main() { `) } -func RootTemplate() []byte { - return []byte(`/* -{{ .Copyright }} -{{ if .Legal.Header }}{{ .Legal.Header }}{{ end }} -*/ -package cmd - -import ( -{{- if .Viper }} - "fmt"{{ end }} - "os" - - "github.com/spf13/cobra" -{{- if .Viper }} - "github.com/spf13/viper"{{ end }} -) - -{{ if .Viper -}} -var cfgFile string -{{- end }} - - -// Execute adds all child commands to the root command and sets flags appropriately. -// This is called by main.main(). It only needs to happen once to the rootCmd. -func Execute() { -// rootCmd represents the base command when called without any subcommands - rootCmd := &cobra.Command{ - Use: "{{ .AppName }}", - Short: "A brief description of your application", - Long: ` + "`" + `A longer description that spans multiple lines and likely contains -examples and usage of using your application. For example: - -Cobra is a CLI library for Go that empowers applications. -This application is a tool to generate the needed files -to quickly create a Cobra application.` + "`" + `, - // Uncomment the following line if your bare application - // has an action associated with it: - // Run: func(cmd *cobra.Command, args []string) { }, -} -{{- if .Viper }} - cobra.OnInitialize(initConfig) -{{ end }} - // Here you will define your flags and configuration settings. - // Cobra supports persistent flags, which, if defined here, - // will be global for your application. -{{ if .Viper }} - rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.{{ .AppName }}.yaml)") -{{ else }} - // rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.{{ .AppName }}.yaml)") -{{ end }} - // Cobra also supports local flags, which will only run - // when this action is called directly. - // rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") - - - // Add child commands here - // AddChildCmd(rootCmd) - - - err := rootCmd.Execute() - if err != nil { - os.Exit(1) - } -} - -{{ if .Viper -}} -// initConfig reads in config file and ENV variables if set. -func initConfig() { - if cfgFile != "" { - // Use config file from the flag. - viper.SetConfigFile(cfgFile) - } else { - // Find home directory. - home, err := os.UserHomeDir() - cobra.CheckErr(err) - - // Search config in home directory with name ".{{ .AppName }}" (without extension). - viper.AddConfigPath(home) - viper.SetConfigType("yaml") - viper.SetConfigName(".{{ .AppName }}") - } +//go:embed root.local.tmpl +var rootLocalTemplate []byte - viper.AutomaticEnv() // read in environment variables that match - - // If a config file is found, read it in. - if err := viper.ReadInConfig(); err == nil { - fmt.Fprintln(os.Stderr, "Using config file:", viper.ConfigFileUsed()) - } -} -{{- end }} -`) +func RootTemplateLocal() []byte { + return rootLocalTemplate } -func AddCommandTemplate() []byte { - return []byte(`/* -{{ .Project.Copyright }} -{{ if .Legal.Header }}{{ .Legal.Header }}{{ end }} -*/ -package cmd - -import ( - "fmt" - - "github.com/spf13/cobra" -) +//go:embed root.global.tmpl +var rootGlobalTemplate []byte -// {{ typeName .CmdName .CmdParent }} represents the {{ .CmdName }} command -type {{ typeName .CmdName .CmdParent }} struct { - cmd *cobra.Command +func RootTemplateGlobal() []byte { + return rootGlobalTemplate } -func (c *{{ typeName .CmdName .CmdParent }}) RunE(_ *cobra.Command, args []string) error { - //Command execution goes here +//go:embed add-command.local.tmpl +var localAddCommandTemplate []byte - fmt.Printf("running %s", c.cmd.Use) - - return nil +func AddCommandTemplateLocal() []byte { + return localAddCommandTemplate } -func Add{{ typeName .CmdName .CmdParent }}({{.CmdParent}} *cobra.Command) { - {{.CmdName}} := {{ typeName .CmdName .CmdParent }}{ - cmd: &cobra.Command{ - Use: "{{ .CmdName }}", - Short: "A brief description of your command", - Long: ` + "`" + `A longer description that spans multiple lines and likely contains examples -and usage of using your command. For example: - -Cobra is a CLI library for Go that empowers applications. -This application is a tool to generate the needed files -to quickly create a Cobra application.` + "`" + `, - }, - } - // Here you will define your flags and configuration settings. +//go:embed add-command.global.tmpl +var globalAddCommandTemplate []byte - // Cobra supports Persistent Flags which will work for this command - // and all subcommands, e.g.: - // {{.CmdName}}.cmd.PersistentFlags().String("foo", "", "A help for foo") - - // Cobra supports local flags which will only run when this command - // is called directly, e.g.: - // {{.CmdName}}.cmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") - {{.CmdParent}}.AddCommand({{.CmdName}}.cmd) - {{.CmdName}}.cmd.RunE = {{.CmdName}}.RunE - - // Add child commands here - // Add{{title .CmdName}}ChildCmd({{.CmdName}}.cmd) -} - -`) +func AddCommandTemplateGlobal() []byte { + return globalAddCommandTemplate } diff --git a/tpl/root.global.tmpl b/tpl/root.global.tmpl new file mode 100644 index 0000000..e37ccf6 --- /dev/null +++ b/tpl/root.global.tmpl @@ -0,0 +1,86 @@ +/* +{{ .Copyright }} +{{ if .Legal.Header }}{{ .Legal.Header }}{{ end }} +*/ +package cmd + +import ( +{{- if .Viper }} + "fmt"{{ end }} + "os" + + "github.com/spf13/cobra" +{{- if .Viper }} + "github.com/spf13/viper"{{ end }} +) + +{{ if .Viper -}} +var cfgFile string +{{- end }} + +// rootCmd represents the base command when called without any subcommands +var rootCmd = &cobra.Command{ + Use: "{{ .AppName }}", + Short: "A brief description of your application", + Long: `A longer description that spans multiple lines and likely contains +examples and usage of using your application. For example: + +Cobra is a CLI library for Go that empowers applications. +This application is a tool to generate the needed files +to quickly create a Cobra application.`, + // Uncomment the following line if your bare application + // has an action associated with it: + // Run: func(cmd *cobra.Command, args []string) { }, +} + +// Execute adds all child commands to the root command and sets flags appropriately. +// This is called by main.main(). It only needs to happen once to the rootCmd. +func Execute() { + err := rootCmd.Execute() + if err != nil { + os.Exit(1) + } +} + +func init() { +{{- if .Viper }} + cobra.OnInitialize(initConfig) +{{ end }} + // Here you will define your flags and configuration settings. + // Cobra supports persistent flags, which, if defined here, + // will be global for your application. +{{ if .Viper }} + rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.{{ .AppName }}.yaml)") +{{ else }} + // rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.{{ .AppName }}.yaml)") +{{ end }} + // Cobra also supports local flags, which will only run + // when this action is called directly. + rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") +} + +{{ if .Viper -}} +// initConfig reads in config file and ENV variables if set. +func initConfig() { + if cfgFile != "" { + // Use config file from the flag. + viper.SetConfigFile(cfgFile) + } else { + // Find home directory. + home, err := os.UserHomeDir() + cobra.CheckErr(err) + + // Search config in home directory with name ".{{ .AppName }}" (without extension). + viper.AddConfigPath(home) + viper.SetConfigType("yaml") + viper.SetConfigName(".{{ .AppName }}") + } + + viper.AutomaticEnv() // read in environment variables that match + + // If a config file is found, read it in. + if err := viper.ReadInConfig(); err == nil { + fmt.Fprintln(os.Stderr, "Using config file:", viper.ConfigFileUsed()) + } +} +{{- end }} diff --git a/tpl/root.local.tmpl b/tpl/root.local.tmpl new file mode 100644 index 0000000..60ce617 --- /dev/null +++ b/tpl/root.local.tmpl @@ -0,0 +1,90 @@ +/* +{{ .Copyright }} +{{ if .Legal.Header }}{{ .Legal.Header }}{{ end }} +*/ +package cmd + +import ( +{{- if .Viper }} + "fmt"{{ end }} + "os" + + "github.com/spf13/cobra" +{{- if .Viper }} + "github.com/spf13/viper"{{ end }} +) + +{{ if .Viper -}} +var cfgFile string +{{- end }} + + +// Execute adds all child commands to the root command and sets flags appropriately. +// This is called by main.main(). It only needs to happen once to the rootCmd. +func Execute() { +// rootCmd represents the base command when called without any subcommands + rootCmd := &cobra.Command{ + Use: "{{ .AppName }}", + Short: "A brief description of your application", + Long: `A longer description that spans multiple lines and likely contains +examples and usage of using your application. For example: + +Cobra is a CLI library for Go that empowers applications. +This application is a tool to generate the needed files +to quickly create a Cobra application.`, + // Uncomment the following line if your bare application + // has an action associated with it: + // Run: func(cmd *cobra.Command, args []string) { }, +} +{{- if .Viper }} + cobra.OnInitialize(initConfig) +{{ end }} + // Here you will define your flags and configuration settings. + // Cobra supports persistent flags, which, if defined here, + // will be global for your application. +{{ if .Viper }} + rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.{{ .AppName }}.yaml)") +{{ else }} + // rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.{{ .AppName }}.yaml)") +{{ end }} + // Cobra also supports local flags, which will only run + // when this action is called directly. + // rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") + + + // Add child commands here + // AddChildCmd(rootCmd) + + + err := rootCmd.Execute() + if err != nil { + os.Exit(1) + } +} + +{{ if .Viper -}} +// initConfig reads in config file and ENV variables if set. +func initConfig() { + if cfgFile != "" { + // Use config file from the flag. + viper.SetConfigFile(cfgFile) + } else { + // Find home directory. + home, err := os.UserHomeDir() + cobra.CheckErr(err) + + // Search config in home directory with name ".{{ .AppName }}" (without extension). + viper.AddConfigPath(home) + viper.SetConfigType("yaml") + viper.SetConfigName(".{{ .AppName }}") + } + + viper.AutomaticEnv() // read in environment variables that match + + // If a config file is found, read it in. + if err := viper.ReadInConfig(); err == nil { + fmt.Fprintln(os.Stderr, "Using config file:", viper.ConfigFileUsed()) + } +} +{{- end }} + From 18d92841a7a66e74409e27e63d57de5325b02968 Mon Sep 17 00:00:00 2001 From: Manuel Dewald Date: Tue, 10 Jun 2025 09:53:59 +0200 Subject: [PATCH 3/3] Change filename of child commands to snake case, add option to skip copyrightline --- cmd/add.go | 12 ++++++++---- cmd/project.go | 2 +- tpl/add-command.local.tmpl | 3 ++- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/cmd/add.go b/cmd/add.go index e96ab78..dee98cd 100644 --- a/cmd/add.go +++ b/cmd/add.go @@ -22,9 +22,10 @@ import ( ) var ( - packageName string - parentName string - dirName string + packageName string + parentName string + dirName string + addCopyrightLine bool addCmd = &cobra.Command{ Use: "add [command name]", @@ -67,10 +68,12 @@ Example: cobra-cli add server -> resulting in a new cmd/server.go`, Project: &Project{ AbsolutePath: wd, Legal: getLicense(), - Copyright: copyrightLine(), LocalVars: localVars, }, } + if addCopyrightLine { + command.Copyright = copyrightLine() + } cobra.CheckErr(command.Create()) @@ -83,6 +86,7 @@ func init() { addCmd.Flags().StringVarP(&packageName, "package", "t", "", "target package name (e.g. github.com/spf13/hugo)") addCmd.Flags().StringVarP(&parentName, "parent", "p", "rootCmd", "variable name of parent command for this command") addCmd.Flags().StringVarP(&dirName, "dir", "d", "", "relative path to the command's main package") + addCmd.Flags().BoolVarP(&addCopyrightLine, "copyright", "c", true, "add copyright line to generated command file") cobra.CheckErr(addCmd.Flags().MarkDeprecated("package", "this operation has been removed.")) } diff --git a/cmd/project.go b/cmd/project.go index 953d539..569c9cd 100644 --- a/cmd/project.go +++ b/cmd/project.go @@ -91,7 +91,7 @@ func (p *Project) createLicenseFile() error { func (c *Command) Create() error { filename := c.CmdName if c.CmdParent != "rootCmd" { - filename = fmt.Sprintf("%s-%s", strings.TrimSuffix(c.CmdParent, "Cmd"), c.CmdName) + filename = fmt.Sprintf("%s_%s", strings.TrimSuffix(c.CmdParent, "Cmd"), c.CmdName) } cmdFile, err := os.Create(fmt.Sprintf("%s/cmd/%s.go", c.AbsolutePath, filename)) if err != nil { diff --git a/tpl/add-command.local.tmpl b/tpl/add-command.local.tmpl index abf5e02..81b4785 100644 --- a/tpl/add-command.local.tmpl +++ b/tpl/add-command.local.tmpl @@ -1,8 +1,9 @@ +{{ if or ( ne .Project.Copyright "" ) .Legal.Header }} /* {{ .Project.Copyright }} {{ if .Legal.Header }}{{ .Legal.Header }}{{ end }} */ -package cmd +{{ end }}package cmd import ( "fmt"