mirror of
https://github.com/spf13/cobra
synced 2025-05-05 12:57:22 +00:00
Fix command name collision on generator
When creating new commands via `cobra add`, it is not possible to add commands with the same name to different parents. They will just overwrite each other. With this patch, the command's object identifier is templated `parentCommandCmd`, the `Use` field `command` and the file name `parent_command.go`. Fixes #1059 Fixes #1131 Signed-off-by: Carlos Marx <me@carlosmarx.com>
This commit is contained in:
parent
de187e874d
commit
b45934648f
4 changed files with 83 additions and 12 deletions
|
@ -46,10 +46,14 @@ Example: cobra add server -> resulting in a new cmd/server.go`,
|
|||
wd, err := os.Getwd()
|
||||
cobra.CheckErr(err)
|
||||
|
||||
commandName := validateCmdName(args[0])
|
||||
commandUse := validateCmdName(args[0])
|
||||
commandName, commandFileName := generateCmdFileName(commandUse, parentName)
|
||||
|
||||
command := &Command{
|
||||
CmdName: commandName,
|
||||
CmdParent: parentName,
|
||||
CmdName: commandName,
|
||||
CmdUse: commandUse,
|
||||
CmdFileName: commandFileName,
|
||||
CmdParent: parentName,
|
||||
Project: &Project{
|
||||
AbsolutePath: wd,
|
||||
Legal: getLicense(),
|
||||
|
@ -122,3 +126,39 @@ func validateCmdName(source string) string {
|
|||
}
|
||||
return output
|
||||
}
|
||||
|
||||
// generateCmdFileName returns a lowerCamelCase command name and a snake_case
|
||||
// file name, combining the given command name and the parent command name.
|
||||
func generateCmdFileName(cmd, parent string) (string, string) {
|
||||
var cmdName string
|
||||
var cmdFileName string
|
||||
|
||||
if parent == "rootCmd" {
|
||||
return cmd, cmd
|
||||
}
|
||||
|
||||
l := len(parent)
|
||||
if parent[l-3:] == "Cmd" {
|
||||
parent = parent[:l-3]
|
||||
}
|
||||
|
||||
upperCmd := string(unicode.ToUpper(rune(cmd[0]))) + cmd[1:]
|
||||
lowerParent := string(unicode.ToLower(rune(parent[0]))) + parent[1:]
|
||||
cmdName = lowerParent + upperCmd
|
||||
|
||||
l = len(cmdName)
|
||||
cmdFileName = string(cmdName[0])
|
||||
for i := 1; i < l; i++ {
|
||||
if unicode.IsUpper(rune(cmdName[i])) {
|
||||
cmdFileName += "_"
|
||||
}
|
||||
cmdFileName += string(unicode.ToLower(rune(cmdName[i])))
|
||||
}
|
||||
|
||||
l = len(cmdFileName)
|
||||
if cmdFileName[l-5:] == "_test" {
|
||||
cmdFileName += "cmd"
|
||||
}
|
||||
|
||||
return cmdName, cmdFileName
|
||||
}
|
||||
|
|
|
@ -8,9 +8,11 @@ import (
|
|||
|
||||
func TestGoldenAddCmd(t *testing.T) {
|
||||
command := &Command{
|
||||
CmdName: "test",
|
||||
CmdParent: parentName,
|
||||
Project: getProject(),
|
||||
CmdName: "test",
|
||||
CmdUse: "test",
|
||||
CmdFileName: "test",
|
||||
CmdParent: parentName,
|
||||
Project: getProject(),
|
||||
}
|
||||
defer os.RemoveAll(command.AbsolutePath)
|
||||
|
||||
|
@ -48,3 +50,30 @@ func TestValidateCmdName(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerateCmdFileName(t *testing.T) {
|
||||
testCases := []struct {
|
||||
inputCmd string
|
||||
inputParent string
|
||||
expectedCmd string
|
||||
expectedFile string
|
||||
}{
|
||||
{"cmdname", "parent", "parentCmdname", "parent_cmdname"},
|
||||
{"cmdname", "parentCmd", "parentCmdname", "parent_cmdname"},
|
||||
{"CmdName", "ParentCmd", "parentCmdName", "parent_cmd_name"},
|
||||
{"cmdname", "granpaParentCmd", "granpaParentCmdname", "granpa_parent_cmdname"},
|
||||
{"test", "granpaParentCmd", "granpaParentTest", "granpa_parent_testcmd"},
|
||||
{"cmdname", "rootCmd", "cmdname", "cmdname"},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
got1, got2 := generateCmdFileName(testCase.inputCmd, testCase.inputParent)
|
||||
if testCase.expectedCmd != got1 || testCase.expectedFile != got2 {
|
||||
t.Errorf(
|
||||
"Expected %q and %q, got %q and %q",
|
||||
testCase.expectedCmd, testCase.expectedFile,
|
||||
got1, got2,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,8 +21,10 @@ type Project struct {
|
|||
}
|
||||
|
||||
type Command struct {
|
||||
CmdName string
|
||||
CmdParent string
|
||||
CmdName string
|
||||
CmdUse string
|
||||
CmdFileName string
|
||||
CmdParent string
|
||||
*Project
|
||||
}
|
||||
|
||||
|
@ -83,7 +85,7 @@ func (p *Project) createLicenseFile() error {
|
|||
}
|
||||
|
||||
func (c *Command) Create() error {
|
||||
cmdFile, err := os.Create(fmt.Sprintf("%s/cmd/%s.go", c.AbsolutePath, c.CmdName))
|
||||
cmdFile, err := os.Create(fmt.Sprintf("%s/cmd/%s.go", c.AbsolutePath, c.CmdFileName))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -113,9 +113,9 @@ import (
|
|||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// {{ .CmdName }}Cmd represents the {{ .CmdName }} command
|
||||
// {{ .CmdName }}Cmd represents the {{ .CmdUse }} command
|
||||
var {{ .CmdName }}Cmd = &cobra.Command{
|
||||
Use: "{{ .CmdName }}",
|
||||
Use: "{{ .CmdUse }}",
|
||||
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:
|
||||
|
@ -124,7 +124,7 @@ 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")
|
||||
fmt.Println("{{ .CmdUse }} called")
|
||||
},
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue