mirror of
https://github.com/spf13/cobra
synced 2024-11-24 22:57:12 +00:00
cmd: Add more docs
This commit is contained in:
parent
32756eb440
commit
0dd1c429a3
6 changed files with 90 additions and 67 deletions
|
@ -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 {
|
||||||
|
|
|
@ -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 exists(path) {
|
||||||
|
return fmt.Errorf("%v already exists", path)
|
||||||
|
}
|
||||||
|
|
||||||
if ospath != "" {
|
dir := filepath.Dir(path)
|
||||||
err = os.MkdirAll(ospath, 0777)
|
if dir != "" {
|
||||||
if err != nil {
|
if err := os.MkdirAll(dir, 0777); err != nil {
|
||||||
return
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if exists(inpath) {
|
file, err := os.Create(path)
|
||||||
return fmt.Errorf("%v already exists", inpath)
|
|
||||||
}
|
|
||||||
if _, err := os.Stat(inpath); err != nil && !os.IsNotExist(err) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
file, err := os.Create(inpath)
|
|
||||||
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")
|
||||||
|
|
|
@ -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]`.")
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 ""
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in a new issue