diff --git a/cobra/cmd/add.go b/cobra/cmd/add.go index 09e4d9b..8bc8c44 100644 --- a/cobra/cmd/add.go +++ b/cobra/cmd/add.go @@ -107,7 +107,7 @@ func init() { data["parentName"] = parentName data["cmdName"] = cmdName - filePath := filepath.Join(project.AbsPath(), project.CmdDir(), cmdName+".go") + filePath := filepath.Join(project.CmdPath(), cmdName+".go") cmdScript, err := executeTemplate(template, data) if err != nil { diff --git a/cobra/cmd/helpers.go b/cobra/cmd/helpers.go index 3f78f89..e7ae808 100644 --- a/cobra/cmd/helpers.go +++ b/cobra/cmd/helpers.go @@ -99,38 +99,36 @@ func executeTemplate(tmplStr string, data interface{}) (string, error) { } func writeStringToFile(path string, s string) error { - return safeWriteToDisk(path, strings.NewReader(s)) + return writeToFile(path, strings.NewReader(s)) } -// safeWriteToDisk as WriteToDisk but checks to see if file/directory already exists. -func safeWriteToDisk(inpath string, r io.Reader) (err error) { - dir := filepath.Dir(inpath) - ospath := filepath.FromSlash(dir) +// writeToFile writes r to file with path only +// if file/directory on given path doesn't exist. +// If file/directory exists on given path, then +// it terminates app and prints an appropriate error. +func writeToFile(path string, r io.Reader) error { + if exists(path) { + return fmt.Errorf("%v already exists", path) + } - if ospath != "" { - err = os.MkdirAll(ospath, 0777) - if err != nil { - return + dir := filepath.Dir(path) + if dir != "" { + if err := os.MkdirAll(dir, 0777); err != nil { + return err } } - if exists(inpath) { - return fmt.Errorf("%v already exists", inpath) - } - if _, err := os.Stat(inpath); err != nil && !os.IsNotExist(err) { - return err - } - - file, err := os.Create(inpath) + file, err := os.Create(path) if err != nil { - return + return err } defer file.Close() _, err = io.Copy(file, r) - return + return err } +// commentfyString comments every line of in. func commentifyString(in string) string { var newlines []string lines := strings.Split(in, "\n") diff --git a/cobra/cmd/init.go b/cobra/cmd/init.go index 3ff5165..84fc68b 100644 --- a/cobra/cmd/init.go +++ b/cobra/cmd/init.go @@ -27,7 +27,6 @@ func init() { RootCmd.AddCommand(initCmd) } -// initialize Command var initCmd = &cobra.Command{ Use: "init [name]", Aliases: []string{"initialize", "initialise", "create"}, @@ -69,27 +68,27 @@ func initializePath(project *Project) { er(err) } } else if !isEmpty(project.AbsPath()) { // If path exists and is not empty don't use it - er("Cobra will not create a new project in a non empty directory") + er("Cobra will not create a new project in a non empty directory: " + project.AbsPath()) } - // We have a directory and it's empty.. Time to initialize it. - createLicenseFile(project) + // We have a directory and it's empty. Time to initialize it. + createLicenseFile(project.License(), project.AbsPath()) createMainFile(project) createRootCmdFile(project) } -func createLicenseFile(project *Project) { +func createLicenseFile(license License, path string) { data := make(map[string]interface{}) data["copyright"] = copyrightLine() // Generate license template from text and data. - text, err := executeTemplate(project.License().Text, data) + text, err := executeTemplate(license.Text, data) if err != nil { er(err) } // Write license text to LICENSE file. - err = writeStringToFile(filepath.Join(project.AbsPath(), "LICENSE"), text) + err = writeStringToFile(filepath.Join(path, "LICENSE"), text) if err != nil { er(err) } @@ -110,7 +109,7 @@ func main() { data := make(map[string]interface{}) data["copyright"] = copyrightLine() data["license"] = project.License().Header - data["importpath"] = path.Join(project.Name(), project.CmdDir()) + data["importpath"] = path.Join(project.Name(), filepath.Base(project.CmdPath())) mainScript, err := executeTemplate(mainTemplate, data) if err != nil { @@ -199,19 +198,21 @@ func initConfig() { data["copyright"] = copyrightLine() data["viper"] = viper.GetBool("useViper") data["license"] = project.License().Header + data["appName"] = path.Base(project.Name()) rootCmdScript, err := executeTemplate(template, data) if err != nil { er(err) } - err = writeStringToFile(filepath.Join(project.AbsPath(), project.CmdDir(), "root.go"), rootCmdScript) + err = writeStringToFile(filepath.Join(project.CmdPath(), "root.go"), rootCmdScript) if err != nil { er(err) } - fmt.Println("Your Cobra application is ready at") - fmt.Println(project.AbsPath() + "\n") - fmt.Println("Give it a try by going there and running `go run main.go`.") - fmt.Println("Add commands to it by running `cobra add [cmdname]`") + fmt.Println(`Your Cobra application is ready at +` + project.AbsPath() + `. + +Give it a try by going there and running ` + "`go run main.go`." + ` +Add commands to it by running ` + "`cobra add [cmdname]`.") } diff --git a/cobra/cmd/licenses.go b/cobra/cmd/licenses.go index 50659ac..d73e6fb 100644 --- a/cobra/cmd/licenses.go +++ b/cobra/cmd/licenses.go @@ -16,18 +16,17 @@ package cmd import ( - "fmt" "strings" "time" "github.com/spf13/viper" ) -//Licenses contains all possible licenses a user can chose from -var Licenses map[string]License +// Licenses contains all possible licenses a user can choose from. +var Licenses = make(map[string]License) -//License represents a software license agreement, containing the Name of -// the license, its possible matches (on the command line as given to cobra) +// License represents a software license agreement, containing the Name of +// the license, its possible matches (on the command line as given to cobra), // the header to be used with each file on the file's creating, and the text // of the license type License struct { @@ -38,8 +37,6 @@ type License struct { } func init() { - Licenses = make(map[string]License) - // Allows a user to not use a license. Licenses["none"] = License{"None", []string{"none", "false"}, "", ""} @@ -53,6 +50,9 @@ func init() { initAgpl() } +// getLicense returns license specified by user in flag or in config. +// If user didn't specify the license, it returns Apache License 2.0. +// // TODO: Inspect project for existing license func getLicense() License { // If explicitly flagged, use that. @@ -72,7 +72,6 @@ func getLicense() License { } // If user didn't set any license, use Apache 2.0 by default. - fmt.Println("apache") return Licenses["apache"] } @@ -83,15 +82,21 @@ func copyrightLine() string { return "Copyright © " + year + " " + author } +// findLicense looks for License object of built-in licenses. +// If it didn't find license, then the app will be terminated and +// error will be printed. func findLicense(name string) License { found := matchLicense(name) if found == "" { - er(fmt.Errorf("unknown license %q", name)) + er("unknown license: " + name) } return Licenses[found] } -// given a license name, try to match the license indicated +// matchLicense compares the given a license name +// to PossibleMatches of all built-in licenses. +// It returns blank string, if name is blank string or it didn't find +// then appropriate match to name. func matchLicense(name string) string { if name == "" { return "" diff --git a/cobra/cmd/project.go b/cobra/cmd/project.go index eac4d8a..87acae3 100644 --- a/cobra/cmd/project.go +++ b/cobra/cmd/project.go @@ -6,14 +6,17 @@ import ( "strings" ) +// Project contains name, license and paths to projects. type Project struct { absPath string - cmdDir string + cmdPath string srcPath string license License name string } +// NewProject returns Project with specified project name. +// If projectName is blank string, it returns nil. func NewProject(projectName string) *Project { if projectName == "" { return nil @@ -25,8 +28,8 @@ func NewProject(projectName string) *Project { // 1. Find already created protect. p.absPath = findPackage(projectName) - // 2. If there are no created project with this path and user in GOPATH, - // then use GOPATH+projectName. + // 2. If there are no created project with this path, and user is in GOPATH, + // then use GOPATH/src+projectName. if p.absPath == "" { wd, err := os.Getwd() if err != nil { @@ -34,7 +37,7 @@ func NewProject(projectName string) *Project { } for _, goPath := range goPaths { if filepath.HasPrefix(wd, goPath) { - p.absPath = filepath.Join(goPath, projectName) + p.absPath = filepath.Join(goPath, "src", projectName) break } } @@ -48,14 +51,9 @@ func NewProject(projectName string) *Project { return p } -// findPackage returns full path to go package. It supports multiple GOPATHs. +// findPackage returns full path to existing go package in GOPATHs. // findPackage returns "", if it can't find path. -// If packageName is "", findPackage returns "" too. -// -// For example, package "github.com/spf13/hugo" -// is located in /home/user/go/src/github.com/spf13/hugo, -// then `findPackage("github.com/spf13/hugo")` -// will return "/home/user/go/src/github.com/spf13/hugo" +// If packageName is "", findPackage returns "". func findPackage(packageName string) string { if packageName == "" { return "" @@ -71,6 +69,10 @@ func findPackage(packageName string) string { return "" } +// NewProjectFromPath returns Project with specified absolute path to +// package. +// If absPath is blank string or if absPath is not actually absolute, +// it returns nil. func NewProjectFromPath(absPath string) *Project { if absPath == "" || !filepath.IsAbs(absPath) { return nil @@ -78,51 +80,68 @@ func NewProjectFromPath(absPath string) *Project { p := new(Project) p.absPath = absPath - p.absPath = strings.TrimSuffix(p.absPath, p.CmdDir()) + p.absPath = strings.TrimSuffix(p.absPath, findCmdDir(p.absPath)) p.name = filepath.ToSlash(trimSrcPath(p.absPath, p.SrcPath())) return p } +// trimSrcPath trims at the end of absPaththe srcPath. func trimSrcPath(absPath, srcPath string) string { relPath, err := filepath.Rel(srcPath, absPath) if err != nil { - er("Cobra only supports project within $GOPATH") + er("Cobra supports project only within $GOPATH") } return relPath } +// License returns the License object of project. func (p *Project) License() License { - if p.license.Text == "" { // check if license is not blank + if p.license.Text == "" && p.license.Name != "None" { p.license = getLicense() } return p.license } +// Name returns the name of project, e.g. "github.com/spf13/cobra" func (p Project) Name() string { return p.name } -func (p *Project) CmdDir() string { +// CmdPath returns absolute path to directory, where all commands are located. +// +// CmdPath returns blank string, only if p.AbsPath() is a blank string. +func (p *Project) CmdPath() string { if p.absPath == "" { return "" } - if p.cmdDir == "" { - p.cmdDir = findCmdDir(p.absPath) + if p.cmdPath == "" { + p.cmdPath = filepath.Join(p.absPath, findCmdDir(p.absPath)) } - return p.cmdDir + return p.cmdPath } +// findCmdDir checks if base of absPath is cmd dir and returns it or +// looks for existing cmd dir in absPath. +// If the cmd dir doesn't exist, empty, or cannot be found, +// it returns "cmd". func findCmdDir(absPath string) string { if !exists(absPath) || isEmpty(absPath) { return "cmd" } + base := filepath.Base(absPath) + for _, cmdDir := range cmdDirs { + if base == cmdDir { + return cmdDir + } + } + files, _ := filepath.Glob(filepath.Join(absPath, "c*")) - for _, f := range files { - for _, c := range cmdDirs { - if f == c { - return c + for _, file := range files { + for _, cmdDir := range cmdDirs { + if file == cmdDir { + return cmdDir } } } @@ -130,10 +149,12 @@ func findCmdDir(absPath string) string { return "cmd" } +// AbsPath returns absolute path of project. func (p Project) AbsPath() string { return p.absPath } +// SrcPath returns absolute path to $GOPATH/src where project is located. func (p *Project) SrcPath() string { if p.srcPath != "" { return p.srcPath diff --git a/cobra/cmd/root.go b/cobra/cmd/root.go index 89f5ce7..dbfe7be 100644 --- a/cobra/cmd/root.go +++ b/cobra/cmd/root.go @@ -23,7 +23,6 @@ import ( var cfgFile, projectBase, userLicense string // are used for flags -// RootCmd represents the base command when called without any subcommands var RootCmd = &cobra.Command{ Use: "cobra", Short: "A generator for Cobra based Applications", @@ -32,7 +31,6 @@ This application is a tool to generate the needed files to quickly create a Cobra application.`, } -//Execute adds all child commands to the root command sets flags appropriately. func Execute() { if err := RootCmd.Execute(); err != nil { fmt.Println(err)