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 "path" 20 "path/filepath" 21 22 "github.com/spf13/cobra" 23 "github.com/spf13/viper" 24) 25 26var initCmd = &cobra.Command{ 27 Use: "init [name]", 28 Aliases: []string{"initialize", "initialise", "create"}, 29 Short: "Initialize a Cobra Application", 30 Long: `Initialize (cobra init) will create a new application, with a license 31and the appropriate structure for a Cobra-based CLI application. 32 33 * If a name is provided, it will be created in the current directory; 34 * If no name is provided, the current directory will be assumed; 35 * If a relative path is provided, it will be created inside $GOPATH 36 (e.g. github.com/spf13/hugo); 37 * If an absolute path is provided, it will be created; 38 * If the directory already exists but is empty, it will be used. 39 40Init will not use an existing directory with contents.`, 41 42 Run: func(cmd *cobra.Command, args []string) { 43 wd, err := os.Getwd() 44 if err != nil { 45 er(err) 46 } 47 48 var project *Project 49 if len(args) == 0 { 50 project = NewProjectFromPath(wd) 51 } else if len(args) == 1 { 52 arg := args[0] 53 if arg[0] == '.' { 54 arg = filepath.Join(wd, arg) 55 } 56 if filepath.IsAbs(arg) { 57 project = NewProjectFromPath(arg) 58 } else { 59 project = NewProject(arg) 60 } 61 } else { 62 er("please provide only one argument") 63 } 64 65 initializeProject(project) 66 67 fmt.Fprintln(cmd.OutOrStdout(), `Your Cobra application is ready at 68`+project.AbsPath()+`. 69 70Give it a try by going there and running `+"`go run main.go`."+` 71Add commands to it by running `+"`cobra add [cmdname]`.") 72 }, 73} 74 75func initializeProject(project *Project) { 76 if !exists(project.AbsPath()) { // If path doesn't yet exist, create it 77 err := os.MkdirAll(project.AbsPath(), os.ModePerm) 78 if err != nil { 79 er(err) 80 } 81 } else if !isEmpty(project.AbsPath()) { // If path exists and is not empty don't use it 82 er("Cobra will not create a new project in a non empty directory: " + project.AbsPath()) 83 } 84 85 // We have a directory and it's empty. Time to initialize it. 86 createLicenseFile(project.License(), project.AbsPath()) 87 createMainFile(project) 88 createRootCmdFile(project) 89} 90 91func createLicenseFile(license License, path string) { 92 data := make(map[string]interface{}) 93 data["copyright"] = copyrightLine() 94 95 // Generate license template from text and data. 96 text, err := executeTemplate(license.Text, data) 97 if err != nil { 98 er(err) 99 } 100 101 // Write license text to LICENSE file. 102 err = writeStringToFile(filepath.Join(path, "LICENSE"), text) 103 if err != nil { 104 er(err) 105 } 106} 107 108func createMainFile(project *Project) { 109 mainTemplate := `{{ comment .copyright }} 110{{if .license}}{{ comment .license }}{{end}} 111 112package main 113 114import "{{ .importpath }}" 115 116func main() { 117 cmd.Execute() 118} 119` 120 data := make(map[string]interface{}) 121 data["copyright"] = copyrightLine() 122 data["license"] = project.License().Header 123 data["importpath"] = path.Join(project.Name(), filepath.Base(project.CmdPath())) 124 125 mainScript, err := executeTemplate(mainTemplate, data) 126 if err != nil { 127 er(err) 128 } 129 130 err = writeStringToFile(filepath.Join(project.AbsPath(), "main.go"), mainScript) 131 if err != nil { 132 er(err) 133 } 134} 135 136func createRootCmdFile(project *Project) { 137 template := `{{comment .copyright}} 138{{if .license}}{{comment .license}}{{end}} 139 140package cmd 141 142import ( 143 "fmt" 144 "os" 145{{if .viper}} 146 homedir "github.com/mitchellh/go-homedir"{{end}} 147 "github.com/spf13/cobra"{{if .viper}} 148 "github.com/spf13/viper"{{end}} 149){{if .viper}} 150 151var cfgFile string{{end}} 152 153// rootCmd represents the base command when called without any subcommands 154var rootCmd = &cobra.Command{ 155 Use: "{{.appName}}", 156 Short: "A brief description of your application", 157 Long: ` + "`" + `A longer description that spans multiple lines and likely contains 158examples and usage of using your application. For example: 159 160Cobra is a CLI library for Go that empowers applications. 161This application is a tool to generate the needed files 162to quickly create a Cobra application.` + "`" + `, 163 // Uncomment the following line if your bare application 164 // has an action associated with it: 165 // Run: func(cmd *cobra.Command, args []string) { }, 166} 167 168// Execute adds all child commands to the root command and sets flags appropriately. 169// This is called by main.main(). It only needs to happen once to the rootCmd. 170func Execute() { 171 if err := rootCmd.Execute(); err != nil { 172 fmt.Println(err) 173 os.Exit(1) 174 } 175} 176 177func init() { {{- if .viper}} 178 cobra.OnInitialize(initConfig) 179{{end}} 180 // Here you will define your flags and configuration settings. 181 // Cobra supports persistent flags, which, if defined here, 182 // will be global for your application.{{ if .viper }} 183 rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.{{ .appName }}.yaml)"){{ else }} 184 // rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.{{ .appName }}.yaml)"){{ end }} 185 186 // Cobra also supports local flags, which will only run 187 // when this action is called directly. 188 rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") 189}{{ if .viper }} 190 191// initConfig reads in config file and ENV variables if set. 192func initConfig() { 193 if cfgFile != "" { 194 // Use config file from the flag. 195 viper.SetConfigFile(cfgFile) 196 } else { 197 // Find home directory. 198 home, err := homedir.Dir() 199 if err != nil { 200 fmt.Println(err) 201 os.Exit(1) 202 } 203 204 // Search config in home directory with name ".{{ .appName }}" (without extension). 205 viper.AddConfigPath(home) 206 viper.SetConfigName(".{{ .appName }}") 207 } 208 209 viper.AutomaticEnv() // read in environment variables that match 210 211 // If a config file is found, read it in. 212 if err := viper.ReadInConfig(); err == nil { 213 fmt.Println("Using config file:", viper.ConfigFileUsed()) 214 } 215}{{ end }} 216` 217 218 data := make(map[string]interface{}) 219 data["copyright"] = copyrightLine() 220 data["viper"] = viper.GetBool("useViper") 221 data["license"] = project.License().Header 222 data["appName"] = path.Base(project.Name()) 223 224 rootCmdScript, err := executeTemplate(template, data) 225 if err != nil { 226 er(err) 227 } 228 229 err = writeStringToFile(filepath.Join(project.CmdPath(), "root.go"), rootCmdScript) 230 if err != nil { 231 er(err) 232 } 233 234} 235