1// Copyright © 2015 Steve Francia <spf@spf13.com>.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
14package cmd
15
16import (
17	"fmt"
18	"os"
19	"unicode"
20
21	"github.com/spf13/cobra"
22)
23
24var (
25	packageName string
26	parentName  string
27
28	addCmd = &cobra.Command{
29		Use:     "add [command name]",
30		Aliases: []string{"command"},
31		Short:   "Add a command to a Cobra Application",
32		Long: `Add (cobra add) will create a new command, with a license and
33the appropriate structure for a Cobra-based CLI application,
34and register it to its parent (default rootCmd).
35
36If you want your command to be public, pass in the command name
37with an initial uppercase letter.
38
39Example: cobra add server -> resulting in a new cmd/server.go`,
40
41		Run: func(cmd *cobra.Command, args []string) {
42			if len(args) < 1 {
43				er("add needs a name for the command")
44			}
45
46			wd, err := os.Getwd()
47			if err != nil {
48				er(err)
49			}
50
51			commandName := validateCmdName(args[0])
52			command := &Command{
53				CmdName:   commandName,
54				CmdParent: parentName,
55				Project: &Project{
56					AbsolutePath: wd,
57					Legal:        getLicense(),
58					Copyright:    copyrightLine(),
59				},
60			}
61
62			err = command.Create()
63			if err != nil {
64				er(err)
65			}
66
67			fmt.Printf("%s created at %s\n", command.CmdName, command.AbsolutePath)
68		},
69	}
70)
71
72func init() {
73	addCmd.Flags().StringVarP(&packageName, "package", "t", "", "target package name (e.g. github.com/spf13/hugo)")
74	addCmd.Flags().StringVarP(&parentName, "parent", "p", "rootCmd", "variable name of parent command for this command")
75	addCmd.Flags().MarkDeprecated("package", "this operation has been removed.")
76}
77
78// validateCmdName returns source without any dashes and underscore.
79// If there will be dash or underscore, next letter will be uppered.
80// It supports only ASCII (1-byte character) strings.
81// https://github.com/spf13/cobra/issues/269
82func validateCmdName(source string) string {
83	i := 0
84	l := len(source)
85	// The output is initialized on demand, then first dash or underscore
86	// occurs.
87	var output string
88
89	for i < l {
90		if source[i] == '-' || source[i] == '_' {
91			if output == "" {
92				output = source[:i]
93			}
94
95			// If it's last rune and it's dash or underscore,
96			// don't add it output and break the loop.
97			if i == l-1 {
98				break
99			}
100
101			// If next character is dash or underscore,
102			// just skip the current character.
103			if source[i+1] == '-' || source[i+1] == '_' {
104				i++
105				continue
106			}
107
108			// If the current character is dash or underscore,
109			// upper next letter and add to output.
110			output += string(unicode.ToUpper(rune(source[i+1])))
111			// We know, what source[i] is dash or underscore and source[i+1] is
112			// uppered character, so make i = i+2.
113			i += 2
114			continue
115		}
116
117		// If the current character isn't dash or underscore,
118		// just add it.
119		if output != "" {
120			output += string(source[i])
121		}
122		i++
123	}
124
125	if output == "" {
126		return source // source is initially valid name.
127	}
128	return output
129}
130