cmd: Add more docs

This commit is contained in:
Albert Nigmatzianov 2017-04-29 14:53:52 +02:00
parent 32756eb440
commit 0dd1c429a3
6 changed files with 90 additions and 67 deletions

View File

@ -107,7 +107,7 @@ func init() {
data["parentName"] = parentName data["parentName"] = parentName
data["cmdName"] = cmdName data["cmdName"] = cmdName
filePath := filepath.Join(project.AbsPath(), project.CmdDir(), cmdName+".go") filePath := filepath.Join(project.CmdPath(), cmdName+".go")
cmdScript, err := executeTemplate(template, data) cmdScript, err := executeTemplate(template, data)
if err != nil { if err != nil {

View File

@ -99,38 +99,36 @@ func executeTemplate(tmplStr string, data interface{}) (string, error) {
} }
func writeStringToFile(path string, s 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. // writeToFile writes r to file with path only
func safeWriteToDisk(inpath string, r io.Reader) (err error) { // if file/directory on given path doesn't exist.
dir := filepath.Dir(inpath) // If file/directory exists on given path, then
ospath := filepath.FromSlash(dir) // it terminates app and prints an appropriate error.
func writeToFile(path string, r io.Reader) error {
if ospath != "" { if exists(path) {
err = os.MkdirAll(ospath, 0777) return fmt.Errorf("%v already exists", path)
if err != nil {
return
}
} }
if exists(inpath) { dir := filepath.Dir(path)
return fmt.Errorf("%v already exists", inpath) if dir != "" {
} if err := os.MkdirAll(dir, 0777); err != nil {
if _, err := os.Stat(inpath); err != nil && !os.IsNotExist(err) {
return err return err
} }
}
file, err := os.Create(inpath) file, err := os.Create(path)
if err != nil { if err != nil {
return return err
} }
defer file.Close() defer file.Close()
_, err = io.Copy(file, r) _, err = io.Copy(file, r)
return return err
} }
// commentfyString comments every line of in.
func commentifyString(in string) string { func commentifyString(in string) string {
var newlines []string var newlines []string
lines := strings.Split(in, "\n") lines := strings.Split(in, "\n")

View File

@ -27,7 +27,6 @@ func init() {
RootCmd.AddCommand(initCmd) RootCmd.AddCommand(initCmd)
} }
// initialize Command
var initCmd = &cobra.Command{ var initCmd = &cobra.Command{
Use: "init [name]", Use: "init [name]",
Aliases: []string{"initialize", "initialise", "create"}, Aliases: []string{"initialize", "initialise", "create"},
@ -69,27 +68,27 @@ func initializePath(project *Project) {
er(err) er(err)
} }
} else if !isEmpty(project.AbsPath()) { // If path exists and is not empty don't use it } 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. // We have a directory and it's empty. Time to initialize it.
createLicenseFile(project) createLicenseFile(project.License(), project.AbsPath())
createMainFile(project) createMainFile(project)
createRootCmdFile(project) createRootCmdFile(project)
} }
func createLicenseFile(project *Project) { func createLicenseFile(license License, path string) {
data := make(map[string]interface{}) data := make(map[string]interface{})
data["copyright"] = copyrightLine() data["copyright"] = copyrightLine()
// Generate license template from text and data. // Generate license template from text and data.
text, err := executeTemplate(project.License().Text, data) text, err := executeTemplate(license.Text, data)
if err != nil { if err != nil {
er(err) er(err)
} }
// Write license text to LICENSE file. // Write license text to LICENSE file.
err = writeStringToFile(filepath.Join(project.AbsPath(), "LICENSE"), text) err = writeStringToFile(filepath.Join(path, "LICENSE"), text)
if err != nil { if err != nil {
er(err) er(err)
} }
@ -110,7 +109,7 @@ func main() {
data := make(map[string]interface{}) data := make(map[string]interface{})
data["copyright"] = copyrightLine() data["copyright"] = copyrightLine()
data["license"] = project.License().Header 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) mainScript, err := executeTemplate(mainTemplate, data)
if err != nil { if err != nil {
@ -199,19 +198,21 @@ func initConfig() {
data["copyright"] = copyrightLine() data["copyright"] = copyrightLine()
data["viper"] = viper.GetBool("useViper") data["viper"] = viper.GetBool("useViper")
data["license"] = project.License().Header data["license"] = project.License().Header
data["appName"] = path.Base(project.Name())
rootCmdScript, err := executeTemplate(template, data) rootCmdScript, err := executeTemplate(template, data)
if err != nil { if err != nil {
er(err) 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 { if err != nil {
er(err) er(err)
} }
fmt.Println("Your Cobra application is ready at") fmt.Println(`Your Cobra application is ready at
fmt.Println(project.AbsPath() + "\n") ` + project.AbsPath() + `.
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]`") Give it a try by going there and running ` + "`go run main.go`." + `
Add commands to it by running ` + "`cobra add [cmdname]`.")
} }

View File

@ -16,18 +16,17 @@
package cmd package cmd
import ( import (
"fmt"
"strings" "strings"
"time" "time"
"github.com/spf13/viper" "github.com/spf13/viper"
) )
//Licenses contains all possible licenses a user can chose from // Licenses contains all possible licenses a user can choose from.
var Licenses map[string]License var Licenses = make(map[string]License)
//License represents a software license agreement, containing the Name of // License represents a software license agreement, containing the Name of
// the license, its possible matches (on the command line as given to cobra) // 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 // the header to be used with each file on the file's creating, and the text
// of the license // of the license
type License struct { type License struct {
@ -38,8 +37,6 @@ type License struct {
} }
func init() { func init() {
Licenses = make(map[string]License)
// Allows a user to not use a license. // Allows a user to not use a license.
Licenses["none"] = License{"None", []string{"none", "false"}, "", ""} Licenses["none"] = License{"None", []string{"none", "false"}, "", ""}
@ -53,6 +50,9 @@ func init() {
initAgpl() 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 // TODO: Inspect project for existing license
func getLicense() License { func getLicense() License {
// If explicitly flagged, use that. // 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. // If user didn't set any license, use Apache 2.0 by default.
fmt.Println("apache")
return Licenses["apache"] return Licenses["apache"]
} }
@ -83,15 +82,21 @@ func copyrightLine() string {
return "Copyright © " + year + " " + author 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 { func findLicense(name string) License {
found := matchLicense(name) found := matchLicense(name)
if found == "" { if found == "" {
er(fmt.Errorf("unknown license %q", name)) er("unknown license: " + name)
} }
return Licenses[found] 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 { func matchLicense(name string) string {
if name == "" { if name == "" {
return "" return ""

View File

@ -6,14 +6,17 @@ import (
"strings" "strings"
) )
// Project contains name, license and paths to projects.
type Project struct { type Project struct {
absPath string absPath string
cmdDir string cmdPath string
srcPath string srcPath string
license License license License
name string name string
} }
// NewProject returns Project with specified project name.
// If projectName is blank string, it returns nil.
func NewProject(projectName string) *Project { func NewProject(projectName string) *Project {
if projectName == "" { if projectName == "" {
return nil return nil
@ -25,8 +28,8 @@ func NewProject(projectName string) *Project {
// 1. Find already created protect. // 1. Find already created protect.
p.absPath = findPackage(projectName) p.absPath = findPackage(projectName)
// 2. If there are no created project with this path and user in GOPATH, // 2. If there are no created project with this path, and user is in GOPATH,
// then use GOPATH+projectName. // then use GOPATH/src+projectName.
if p.absPath == "" { if p.absPath == "" {
wd, err := os.Getwd() wd, err := os.Getwd()
if err != nil { if err != nil {
@ -34,7 +37,7 @@ func NewProject(projectName string) *Project {
} }
for _, goPath := range goPaths { for _, goPath := range goPaths {
if filepath.HasPrefix(wd, goPath) { if filepath.HasPrefix(wd, goPath) {
p.absPath = filepath.Join(goPath, projectName) p.absPath = filepath.Join(goPath, "src", projectName)
break break
} }
} }
@ -48,14 +51,9 @@ func NewProject(projectName string) *Project {
return p 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. // findPackage returns "", if it can't find path.
// If packageName is "", findPackage returns "" too. // If packageName is "", findPackage returns "".
//
// 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"
func findPackage(packageName string) string { func findPackage(packageName string) string {
if packageName == "" { if packageName == "" {
return "" return ""
@ -71,6 +69,10 @@ func findPackage(packageName string) string {
return "" 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 { func NewProjectFromPath(absPath string) *Project {
if absPath == "" || !filepath.IsAbs(absPath) { if absPath == "" || !filepath.IsAbs(absPath) {
return nil return nil
@ -78,51 +80,68 @@ func NewProjectFromPath(absPath string) *Project {
p := new(Project) p := new(Project)
p.absPath = absPath 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())) p.name = filepath.ToSlash(trimSrcPath(p.absPath, p.SrcPath()))
return p return p
} }
// trimSrcPath trims at the end of absPaththe srcPath.
func trimSrcPath(absPath, srcPath string) string { func trimSrcPath(absPath, srcPath string) string {
relPath, err := filepath.Rel(srcPath, absPath) relPath, err := filepath.Rel(srcPath, absPath)
if err != nil { if err != nil {
er("Cobra only supports project within $GOPATH") er("Cobra supports project only within $GOPATH")
} }
return relPath return relPath
} }
// License returns the License object of project.
func (p *Project) License() License { 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() p.license = getLicense()
} }
return p.license return p.license
} }
// Name returns the name of project, e.g. "github.com/spf13/cobra"
func (p Project) Name() string { func (p Project) Name() string {
return p.name 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 == "" { if p.absPath == "" {
return "" return ""
} }
if p.cmdDir == "" { if p.cmdPath == "" {
p.cmdDir = findCmdDir(p.absPath) 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 { func findCmdDir(absPath string) string {
if !exists(absPath) || isEmpty(absPath) { if !exists(absPath) || isEmpty(absPath) {
return "cmd" return "cmd"
} }
base := filepath.Base(absPath)
for _, cmdDir := range cmdDirs {
if base == cmdDir {
return cmdDir
}
}
files, _ := filepath.Glob(filepath.Join(absPath, "c*")) files, _ := filepath.Glob(filepath.Join(absPath, "c*"))
for _, f := range files { for _, file := range files {
for _, c := range cmdDirs { for _, cmdDir := range cmdDirs {
if f == c { if file == cmdDir {
return c return cmdDir
} }
} }
} }
@ -130,10 +149,12 @@ func findCmdDir(absPath string) string {
return "cmd" return "cmd"
} }
// AbsPath returns absolute path of project.
func (p Project) AbsPath() string { func (p Project) AbsPath() string {
return p.absPath return p.absPath
} }
// SrcPath returns absolute path to $GOPATH/src where project is located.
func (p *Project) SrcPath() string { func (p *Project) SrcPath() string {
if p.srcPath != "" { if p.srcPath != "" {
return p.srcPath return p.srcPath

View File

@ -23,7 +23,6 @@ import (
var cfgFile, projectBase, userLicense string // are used for flags var cfgFile, projectBase, userLicense string // are used for flags
// RootCmd represents the base command when called without any subcommands
var RootCmd = &cobra.Command{ var RootCmd = &cobra.Command{
Use: "cobra", Use: "cobra",
Short: "A generator for Cobra based Applications", 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.`, to quickly create a Cobra application.`,
} }
//Execute adds all child commands to the root command sets flags appropriately.
func Execute() { func Execute() {
if err := RootCmd.Execute(); err != nil { if err := RootCmd.Execute(); err != nil {
fmt.Println(err) fmt.Println(err)