// Copyright © 2021 Steve Francia . // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package cmd import ( "encoding/json" "fmt" "os" "os/exec" "path" "path/filepath" "strings" "github.com/spf13/cobra" "github.com/spf13/viper" ) var ( initCmd = &cobra.Command{ Use: "init [path]", Aliases: []string{"initialize", "initialise", "create"}, Short: "Initialize a Cobra Application", Long: `Initialize (cobra init) will create a new application, with a license and the appropriate structure for a Cobra-based CLI application. Cobra init must be run inside of a go module (please run "go mod init " first) `, Run: func(_ *cobra.Command, args []string) { projectPath, err := initializeProject(args) cobra.CheckErr(err) cobra.CheckErr(goGet("github.com/spf13/cobra")) if viper.GetBool("useViper") { cobra.CheckErr(goGet("github.com/spf13/viper")) } fmt.Printf("Your Cobra application is ready at\n%s\n", projectPath) }, } ) func initializeProject(args []string) (string, error) { wd, err := os.Getwd() if err != nil { return "", err } if len(args) > 0 { if args[0] != "." { wd = fmt.Sprintf("%s/%s", wd, args[0]) } } modName := getModImportPath() project := &Project{ AbsolutePath: wd, PkgName: modName, Legal: getLicense(), Copyright: copyrightLine(), Viper: viper.GetBool("useViper"), AppName: path.Base(modName), } if err := project.Create(); err != nil { return "", err } return project.AbsolutePath, nil } func getModImportPath() string { mod, cd := parseModInfo() return path.Join(mod.Path, fileToURL(strings.TrimPrefix(cd.Dir, mod.Dir))) } func fileToURL(in string) string { i := strings.Split(in, string(filepath.Separator)) return path.Join(i...) } func parseModInfo() (Mod, CurDir) { var mod Mod var dir CurDir m := modInfoJSON("-m") cobra.CheckErr(json.Unmarshal(m, &mod)) // Unsure why, but if no module is present Path is set to this string. if mod.Path == "command-line-arguments" { cobra.CheckErr("Please run `go mod init ` before `cobra init`") } e := modInfoJSON("-e") cobra.CheckErr(json.Unmarshal(e, &dir)) return mod, dir } type Mod struct { Path, Dir, GoMod string } type CurDir struct { Dir string } func goGet(mod string) error { return exec.Command("go", "get", mod).Run() } func modInfoJSON(args ...string) []byte { cmdArgs := append([]string{"list", "-json"}, args...) out, err := exec.Command("go", cmdArgs...).Output() cobra.CheckErr(err) return out }