mirror of
https://github.com/spf13/cobra
synced 2024-11-24 22:57:12 +00:00
cmd: Rewrite
This commit is contained in:
parent
4061f41c9a
commit
32756eb440
9 changed files with 388 additions and 478 deletions
|
@ -79,11 +79,11 @@ A few good real world examples may better illustrate this point.
|
||||||
|
|
||||||
In the following example, 'server' is a command, and 'port' is a flag:
|
In the following example, 'server' is a command, and 'port' is a flag:
|
||||||
|
|
||||||
> hugo server --port=1313
|
hugo server --port=1313
|
||||||
|
|
||||||
In this command we are telling Git to clone the url bare.
|
In this command we are telling Git to clone the url bare.
|
||||||
|
|
||||||
> git clone URL --bare
|
git clone URL --bare
|
||||||
|
|
||||||
## Commands
|
## Commands
|
||||||
|
|
||||||
|
@ -130,7 +130,7 @@ Using Cobra is easy. First, use `go get` to install the latest version
|
||||||
of the library. This command will install the `cobra` generator executible
|
of the library. This command will install the `cobra` generator executible
|
||||||
along with the library:
|
along with the library:
|
||||||
|
|
||||||
> go get -v github.com/spf13/cobra/cobra
|
go get -v github.com/spf13/cobra/cobra
|
||||||
|
|
||||||
Next, include Cobra in your application:
|
Next, include Cobra in your application:
|
||||||
|
|
||||||
|
@ -180,7 +180,7 @@ commands you want. It's the easiest way to incorporate Cobra into your applicati
|
||||||
|
|
||||||
In order to use the cobra command, compile it using the following command:
|
In order to use the cobra command, compile it using the following command:
|
||||||
|
|
||||||
> go get github.com/spf13/cobra/cobra
|
go get github.com/spf13/cobra/cobra
|
||||||
|
|
||||||
This will create the cobra executable under your `$GOPATH/bin` directory.
|
This will create the cobra executable under your `$GOPATH/bin` directory.
|
||||||
|
|
||||||
|
|
|
@ -15,8 +15,8 @@ package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
|
@ -26,9 +26,8 @@ func init() {
|
||||||
RootCmd.AddCommand(addCmd)
|
RootCmd.AddCommand(addCmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
var pName string
|
var parentName string
|
||||||
|
|
||||||
// initialize Command
|
|
||||||
var addCmd = &cobra.Command{
|
var addCmd = &cobra.Command{
|
||||||
Use: "add [command name]",
|
Use: "add [command name]",
|
||||||
Aliases: []string{"command"},
|
Aliases: []string{"command"},
|
||||||
|
@ -40,35 +39,28 @@ and register it to its parent (default RootCmd).
|
||||||
If you want your command to be public, pass in the command name
|
If you want your command to be public, pass in the command name
|
||||||
with an initial uppercase letter.
|
with an initial uppercase letter.
|
||||||
|
|
||||||
Example: cobra add server -> resulting in a new cmd/server.go
|
Example: cobra add server -> resulting in a new cmd/server.go`,
|
||||||
`,
|
|
||||||
|
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
if len(args) != 1 {
|
if len(args) < 1 {
|
||||||
er("add needs a name for the command")
|
er("add needs a name for the command")
|
||||||
}
|
}
|
||||||
guessProjectPath()
|
wd, err := os.Getwd()
|
||||||
createCmdFile(args[0])
|
if err != nil {
|
||||||
|
er(err)
|
||||||
|
}
|
||||||
|
project := NewProjectFromPath(wd)
|
||||||
|
createCmdFile(project, args[0])
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
addCmd.Flags().StringVarP(&pName, "parent", "p", "RootCmd", "name of parent command for this command")
|
addCmd.Flags().StringVarP(&parentName, "parent", "p", "RootCmd", "name of parent command for this command")
|
||||||
}
|
}
|
||||||
|
|
||||||
func parentName() string {
|
func createCmdFile(project *Project, cmdName string) {
|
||||||
if !strings.HasSuffix(strings.ToLower(pName), "cmd") {
|
template := `{{comment .copyright}}
|
||||||
return pName + "Cmd"
|
{{comment .license}}
|
||||||
}
|
|
||||||
|
|
||||||
return pName
|
|
||||||
}
|
|
||||||
|
|
||||||
func createCmdFile(cmdName string) {
|
|
||||||
lic := getLicense()
|
|
||||||
|
|
||||||
template := `{{ comment .copyright }}
|
|
||||||
{{ comment .license }}
|
|
||||||
|
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
|
@ -79,8 +71,8 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// {{.cmdName}}Cmd represents the {{.cmdName}} command
|
// {{.cmdName}}Cmd represents the {{.cmdName}} command
|
||||||
var {{ .cmdName }}Cmd = &cobra.Command{
|
var {{.cmdName}}Cmd = &cobra.Command{
|
||||||
Use: "{{ .cmdName }}",
|
Use: "{{.cmdName}}",
|
||||||
Short: "A brief description of your command",
|
Short: "A brief description of your command",
|
||||||
Long: ` + "`" + `A longer description that spans multiple lines and likely contains examples
|
Long: ` + "`" + `A longer description that spans multiple lines and likely contains examples
|
||||||
and usage of using your command. For example:
|
and usage of using your command. For example:
|
||||||
|
@ -89,13 +81,12 @@ Cobra is a CLI library for Go that empowers applications.
|
||||||
This application is a tool to generate the needed files
|
This application is a tool to generate the needed files
|
||||||
to quickly create a Cobra application.` + "`" + `,
|
to quickly create a Cobra application.` + "`" + `,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
// TODO: Work your own magic here
|
fmt.Println("{{.cmdName}} called")
|
||||||
fmt.Println("{{ .cmdName }} called")
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
{{ .parentName }}.AddCommand({{ .cmdName }}Cmd)
|
{{.parentName}}.AddCommand({{.cmdName}}Cmd)
|
||||||
|
|
||||||
// Here you will define your flags and configuration settings.
|
// Here you will define your flags and configuration settings.
|
||||||
|
|
||||||
|
@ -106,23 +97,26 @@ func init() {
|
||||||
// Cobra supports local flags which will only run when this command
|
// Cobra supports local flags which will only run when this command
|
||||||
// is called directly, e.g.:
|
// is called directly, e.g.:
|
||||||
// {{.cmdName}}Cmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
|
// {{.cmdName}}Cmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
|
||||||
|
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
var data map[string]interface{}
|
data := make(map[string]interface{})
|
||||||
data = make(map[string]interface{})
|
|
||||||
|
|
||||||
data["copyright"] = copyrightLine()
|
data["copyright"] = copyrightLine()
|
||||||
data["license"] = lic.Header
|
data["license"] = project.License().Header
|
||||||
data["appName"] = projectName()
|
|
||||||
data["viper"] = viper.GetBool("useViper")
|
data["viper"] = viper.GetBool("useViper")
|
||||||
data["parentName"] = parentName()
|
data["parentName"] = parentName
|
||||||
data["cmdName"] = cmdName
|
data["cmdName"] = cmdName
|
||||||
|
|
||||||
err := writeTemplateToFile(filepath.Join(ProjectPath(), guessCmdDir()), cmdName+".go", template, data)
|
filePath := filepath.Join(project.AbsPath(), project.CmdDir(), cmdName+".go")
|
||||||
|
|
||||||
|
cmdScript, err := executeTemplate(template, data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
er(err)
|
er(err)
|
||||||
}
|
}
|
||||||
fmt.Println(cmdName, "created at", filepath.Join(ProjectPath(), guessCmdDir(), cmdName+".go"))
|
err = writeStringToFile(filePath, cmdScript)
|
||||||
|
if err != nil {
|
||||||
|
er(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(cmdName, "created at", filePath)
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,266 +23,103 @@ import (
|
||||||
"text/template"
|
"text/template"
|
||||||
)
|
)
|
||||||
|
|
||||||
// var BaseDir = ""
|
var funcMap = template.FuncMap{
|
||||||
// var AppName = ""
|
"comment": commentifyString,
|
||||||
// var CommandDir = ""
|
}
|
||||||
|
|
||||||
var funcMap template.FuncMap
|
var projectPath string
|
||||||
var projectPath = ""
|
|
||||||
var inputPath = ""
|
|
||||||
var projectBase = ""
|
|
||||||
|
|
||||||
// for testing only
|
var cmdDirs = [...]string{"cmd", "cmds", "command", "commands"}
|
||||||
var testWd = ""
|
var goPaths, srcPaths []string
|
||||||
|
|
||||||
var cmdDirs = []string{"cmd", "cmds", "command", "commands"}
|
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
funcMap = template.FuncMap{
|
// Initialize goPaths and srcPaths
|
||||||
"comment": commentifyString,
|
envGoPath := os.Getenv("GOPATH")
|
||||||
|
if envGoPath == "" {
|
||||||
|
er("$GOPATH is not set")
|
||||||
|
}
|
||||||
|
|
||||||
|
goPaths = filepath.SplitList(envGoPath)
|
||||||
|
srcPaths = make([]string, 0, len(goPaths))
|
||||||
|
for _, goPath := range goPaths {
|
||||||
|
srcPaths = append(srcPaths, filepath.Join(goPath, "src"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func er(msg interface{}) {
|
func er(msg interface{}) {
|
||||||
fmt.Println("Error:", msg)
|
fmt.Println("Error:", msg)
|
||||||
os.Exit(-1)
|
os.Exit(1)
|
||||||
}
|
|
||||||
|
|
||||||
// Check if a file or directory exists.
|
|
||||||
func exists(path string) (bool, error) {
|
|
||||||
_, err := os.Stat(path)
|
|
||||||
if err == nil {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
if os.IsNotExist(err) {
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func ProjectPath() string {
|
|
||||||
if projectPath == "" {
|
|
||||||
guessProjectPath()
|
|
||||||
}
|
|
||||||
|
|
||||||
return projectPath
|
|
||||||
}
|
|
||||||
|
|
||||||
// wrapper of the os package so we can test better
|
|
||||||
func getWd() (string, error) {
|
|
||||||
if testWd == "" {
|
|
||||||
return os.Getwd()
|
|
||||||
}
|
|
||||||
return testWd, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func guessCmdDir() string {
|
|
||||||
guessProjectPath()
|
|
||||||
if b, _ := isEmpty(projectPath); b {
|
|
||||||
return "cmd"
|
|
||||||
}
|
|
||||||
|
|
||||||
files, _ := filepath.Glob(projectPath + string(os.PathSeparator) + "c*")
|
|
||||||
for _, f := range files {
|
|
||||||
for _, c := range cmdDirs {
|
|
||||||
if f == c {
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return "cmd"
|
|
||||||
}
|
|
||||||
|
|
||||||
func guessImportPath() string {
|
|
||||||
guessProjectPath()
|
|
||||||
|
|
||||||
if !strings.HasPrefix(projectPath, getSrcPath()) {
|
|
||||||
er("Cobra only supports project within $GOPATH")
|
|
||||||
}
|
|
||||||
|
|
||||||
return filepath.ToSlash(filepath.Clean(strings.TrimPrefix(projectPath, getSrcPath())))
|
|
||||||
}
|
|
||||||
|
|
||||||
func getSrcPath() string {
|
|
||||||
return filepath.Join(os.Getenv("GOPATH"), "src") + string(os.PathSeparator)
|
|
||||||
}
|
|
||||||
|
|
||||||
func projectName() string {
|
|
||||||
return filepath.Base(ProjectPath())
|
|
||||||
}
|
|
||||||
|
|
||||||
func guessProjectPath() {
|
|
||||||
// if no path is provided... assume CWD.
|
|
||||||
if inputPath == "" {
|
|
||||||
x, err := getWd()
|
|
||||||
if err != nil {
|
|
||||||
er(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// inspect CWD
|
|
||||||
base := filepath.Base(x)
|
|
||||||
|
|
||||||
// if we are in the cmd directory.. back up
|
|
||||||
for _, c := range cmdDirs {
|
|
||||||
if base == c {
|
|
||||||
projectPath = filepath.Dir(x)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if projectPath == "" {
|
|
||||||
projectPath = filepath.Clean(x)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
srcPath := getSrcPath()
|
|
||||||
// if provided, inspect for logical locations
|
|
||||||
if strings.ContainsRune(inputPath, os.PathSeparator) {
|
|
||||||
if filepath.IsAbs(inputPath) || filepath.HasPrefix(inputPath, string(os.PathSeparator)) {
|
|
||||||
// if Absolute, use it
|
|
||||||
projectPath = filepath.Clean(inputPath)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// If not absolute but contains slashes,
|
|
||||||
// assuming it means create it from $GOPATH
|
|
||||||
count := strings.Count(inputPath, string(os.PathSeparator))
|
|
||||||
|
|
||||||
switch count {
|
|
||||||
// If only one directory deep, assume "github.com"
|
|
||||||
case 1:
|
|
||||||
projectPath = filepath.Join(srcPath, "github.com", inputPath)
|
|
||||||
return
|
|
||||||
case 2:
|
|
||||||
projectPath = filepath.Join(srcPath, inputPath)
|
|
||||||
return
|
|
||||||
default:
|
|
||||||
er("Unknown directory")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// hardest case.. just a word.
|
|
||||||
if projectBase == "" {
|
|
||||||
x, err := getWd()
|
|
||||||
if err == nil {
|
|
||||||
projectPath = filepath.Join(x, inputPath)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
er(err)
|
|
||||||
} else {
|
|
||||||
projectPath = filepath.Join(srcPath, projectBase, inputPath)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// isEmpty checks if a given path is empty.
|
// isEmpty checks if a given path is empty.
|
||||||
func isEmpty(path string) (bool, error) {
|
func isEmpty(path string) bool {
|
||||||
if b, _ := exists(path); !b {
|
|
||||||
return false, fmt.Errorf("%q path does not exist", path)
|
|
||||||
}
|
|
||||||
fi, err := os.Stat(path)
|
fi, err := os.Stat(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
er(err)
|
||||||
}
|
}
|
||||||
if fi.IsDir() {
|
if fi.IsDir() {
|
||||||
f, err := os.Open(path)
|
f, err := os.Open(path)
|
||||||
// FIX: Resource leak - f.close() should be called here by defer or is missed
|
|
||||||
// if the err != nil branch is taken.
|
|
||||||
defer f.Close()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
er(err)
|
||||||
}
|
}
|
||||||
list, _ := f.Readdir(-1)
|
defer f.Close()
|
||||||
// f.Close() - see bug fix above
|
dirs, err := f.Readdirnames(1)
|
||||||
return len(list) == 0, nil
|
if err != nil && err != io.EOF {
|
||||||
|
er(err)
|
||||||
|
}
|
||||||
|
return len(dirs) == 0
|
||||||
}
|
}
|
||||||
return fi.Size() == 0, nil
|
return fi.Size() == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// isDir checks if a given path is a directory.
|
// exists checks if a file or directory exists.
|
||||||
func isDir(path string) (bool, error) {
|
func exists(path string) bool {
|
||||||
fi, err := os.Stat(path)
|
if path == "" {
|
||||||
if err != nil {
|
return false
|
||||||
return false, err
|
|
||||||
}
|
}
|
||||||
return fi.IsDir(), nil
|
_, err := os.Stat(path)
|
||||||
|
if err == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if !os.IsNotExist(err) {
|
||||||
|
er(err)
|
||||||
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// dirExists checks if a path exists and is a directory.
|
func executeTemplate(tmplStr string, data interface{}) (string, error) {
|
||||||
func dirExists(path string) (bool, error) {
|
tmpl, err := template.New("").Funcs(funcMap).Parse(tmplStr)
|
||||||
fi, err := os.Stat(path)
|
|
||||||
if err == nil && fi.IsDir() {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
if os.IsNotExist(err) {
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeTemplateToFile(path string, file string, template string, data interface{}) error {
|
|
||||||
filename := filepath.Join(path, file)
|
|
||||||
|
|
||||||
r, err := templateToReader(template, data)
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = safeWriteToDisk(filename, r)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeStringToFile(path, file, text string) error {
|
|
||||||
filename := filepath.Join(path, file)
|
|
||||||
|
|
||||||
r := strings.NewReader(text)
|
|
||||||
err := safeWriteToDisk(filename, r)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func templateToReader(tpl string, data interface{}) (io.Reader, error) {
|
|
||||||
tmpl := template.New("")
|
|
||||||
tmpl.Funcs(funcMap)
|
|
||||||
tmpl, err := tmpl.Parse(tpl)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
err = tmpl.Execute(buf, data)
|
err = tmpl.Execute(buf, data)
|
||||||
|
return buf.String(), err
|
||||||
return buf, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Same as WriteToDisk but checks to see if file/directory already exists.
|
func writeStringToFile(path string, s string) error {
|
||||||
|
return safeWriteToDisk(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) {
|
func safeWriteToDisk(inpath string, r io.Reader) (err error) {
|
||||||
dir, _ := filepath.Split(inpath)
|
dir := filepath.Dir(inpath)
|
||||||
ospath := filepath.FromSlash(dir)
|
ospath := filepath.FromSlash(dir)
|
||||||
|
|
||||||
if ospath != "" {
|
if ospath != "" {
|
||||||
err = os.MkdirAll(ospath, 0777) // rwx, rw, r
|
err = os.MkdirAll(ospath, 0777)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ex, err := exists(inpath)
|
if exists(inpath) {
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if ex {
|
|
||||||
return fmt.Errorf("%v already 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(inpath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -297,15 +134,15 @@ func safeWriteToDisk(inpath string, r io.Reader) (err error) {
|
||||||
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")
|
||||||
for _, x := range lines {
|
for _, line := range lines {
|
||||||
if !strings.HasPrefix(x, "//") {
|
if strings.HasPrefix(line, "//") {
|
||||||
if x != "" {
|
newlines = append(newlines, line)
|
||||||
newlines = append(newlines, "// "+x)
|
|
||||||
} else {
|
|
||||||
newlines = append(newlines, "//")
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
newlines = append(newlines, x)
|
if line == "" {
|
||||||
|
newlines = append(newlines, "//")
|
||||||
|
} else {
|
||||||
|
newlines = append(newlines, "// "+line)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return strings.Join(newlines, "\n")
|
return strings.Join(newlines, "\n")
|
||||||
|
|
|
@ -1,35 +0,0 @@
|
||||||
package cmd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"path/filepath"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func checkGuess(t *testing.T, wd, input, expected string) {
|
|
||||||
testWd = wd
|
|
||||||
inputPath = input
|
|
||||||
guessProjectPath()
|
|
||||||
|
|
||||||
if projectPath != expected {
|
|
||||||
t.Errorf("Unexpected Project Path. \n Got: %q\nExpected: %q\n", projectPath, expected)
|
|
||||||
}
|
|
||||||
|
|
||||||
reset()
|
|
||||||
}
|
|
||||||
|
|
||||||
func reset() {
|
|
||||||
testWd = ""
|
|
||||||
inputPath = ""
|
|
||||||
projectPath = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestProjectPath(t *testing.T) {
|
|
||||||
checkGuess(t, "", filepath.Join("github.com", "spf13", "hugo"), filepath.Join(getSrcPath(), "github.com", "spf13", "hugo"))
|
|
||||||
checkGuess(t, "", filepath.Join("spf13", "hugo"), filepath.Join(getSrcPath(), "github.com", "spf13", "hugo"))
|
|
||||||
checkGuess(t, "", filepath.Join("/", "bar", "foo"), filepath.Join("/", "bar", "foo"))
|
|
||||||
checkGuess(t, "/bar/foo", "baz", filepath.Join("/", "bar", "foo", "baz"))
|
|
||||||
checkGuess(t, "/bar/foo/cmd", "", filepath.Join("/", "bar", "foo"))
|
|
||||||
checkGuess(t, "/bar/foo/command", "", filepath.Join("/", "bar", "foo"))
|
|
||||||
checkGuess(t, "/bar/foo/commands", "", filepath.Join("/", "bar", "foo"))
|
|
||||||
checkGuess(t, "github.com/spf13/hugo/../hugo", "", filepath.Join("github.com", "spf13", "hugo"))
|
|
||||||
}
|
|
|
@ -14,10 +14,10 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"path"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
|
@ -45,79 +45,60 @@ and the appropriate structure for a Cobra-based CLI application.
|
||||||
Init will not use an existing directory with contents.`,
|
Init will not use an existing directory with contents.`,
|
||||||
|
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
switch len(args) {
|
var project *Project
|
||||||
case 0:
|
if len(args) == 0 {
|
||||||
inputPath = ""
|
wd, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
case 1:
|
er(err)
|
||||||
inputPath = args[0]
|
}
|
||||||
|
project = NewProjectFromPath(wd)
|
||||||
default:
|
} else if len(args) == 1 {
|
||||||
er("init doesn't support more than 1 parameter")
|
project = NewProject(args[0])
|
||||||
|
} else {
|
||||||
|
er("please enter the name")
|
||||||
}
|
}
|
||||||
guessProjectPath()
|
|
||||||
initializePath(projectPath)
|
initializePath(project)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func initializePath(path string) {
|
func initializePath(project *Project) {
|
||||||
b, err := exists(path)
|
if !exists(project.AbsPath()) { // If path doesn't yet exist, create it
|
||||||
|
err := os.MkdirAll(project.AbsPath(), os.ModePerm)
|
||||||
|
if err != nil {
|
||||||
|
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")
|
||||||
|
}
|
||||||
|
|
||||||
|
// We have a directory and it's empty.. Time to initialize it.
|
||||||
|
createLicenseFile(project)
|
||||||
|
createMainFile(project)
|
||||||
|
createRootCmdFile(project)
|
||||||
|
}
|
||||||
|
|
||||||
|
func createLicenseFile(project *Project) {
|
||||||
|
data := make(map[string]interface{})
|
||||||
|
data["copyright"] = copyrightLine()
|
||||||
|
|
||||||
|
// Generate license template from text and data.
|
||||||
|
text, err := executeTemplate(project.License().Text, data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
er(err)
|
er(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !b { // If path doesn't yet exist, create it
|
// Write license text to LICENSE file.
|
||||||
err := os.MkdirAll(path, os.ModePerm)
|
err = writeStringToFile(filepath.Join(project.AbsPath(), "LICENSE"), text)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
er(err)
|
er(err)
|
||||||
}
|
|
||||||
} else { // If path exists and is not empty don't use it
|
|
||||||
empty, err := exists(path)
|
|
||||||
if err != nil {
|
|
||||||
er(err)
|
|
||||||
}
|
|
||||||
if !empty {
|
|
||||||
er("Cobra will not create a new project in a non empty directory")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// We have a directory and it's empty.. Time to initialize it.
|
|
||||||
|
|
||||||
createLicenseFile()
|
|
||||||
createMainFile()
|
|
||||||
createRootCmdFile()
|
|
||||||
}
|
|
||||||
|
|
||||||
func createLicenseFile() {
|
|
||||||
lic := getLicense()
|
|
||||||
|
|
||||||
// Don't bother writing a LICENSE file if there is no text.
|
|
||||||
if lic.Text != "" {
|
|
||||||
data := make(map[string]interface{})
|
|
||||||
|
|
||||||
// Try to remove the email address, if any
|
|
||||||
data["copyright"] = strings.Split(copyrightLine(), " <")[0]
|
|
||||||
|
|
||||||
data["appName"] = projectName()
|
|
||||||
|
|
||||||
// Generate license template from text and data.
|
|
||||||
r, _ := templateToReader(lic.Text, data)
|
|
||||||
buf := new(bytes.Buffer)
|
|
||||||
buf.ReadFrom(r)
|
|
||||||
|
|
||||||
err := writeTemplateToFile(ProjectPath(), "LICENSE", buf.String(), data)
|
|
||||||
_ = err
|
|
||||||
// if err != nil {
|
|
||||||
// er(err)
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func createMainFile() {
|
func createMainFile(project *Project) {
|
||||||
lic := getLicense()
|
mainTemplate := `{{ comment .copyright }}
|
||||||
|
{{if .license}}{{ comment .license }}{{end}}
|
||||||
|
|
||||||
template := `{{ comment .copyright }}
|
|
||||||
{{if .license}}{{ comment .license }}
|
|
||||||
{{end}}
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import "{{ .importpath }}"
|
import "{{ .importpath }}"
|
||||||
|
@ -127,31 +108,25 @@ func main() {
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
data := make(map[string]interface{})
|
data := make(map[string]interface{})
|
||||||
|
|
||||||
data["copyright"] = copyrightLine()
|
data["copyright"] = copyrightLine()
|
||||||
data["appName"] = projectName()
|
data["license"] = project.License().Header
|
||||||
|
data["importpath"] = path.Join(project.Name(), project.CmdDir())
|
||||||
|
|
||||||
// Generate license template from header and data.
|
mainScript, err := executeTemplate(mainTemplate, data)
|
||||||
r, _ := templateToReader(lic.Header, data)
|
if err != nil {
|
||||||
buf := new(bytes.Buffer)
|
er(err)
|
||||||
buf.ReadFrom(r)
|
}
|
||||||
data["license"] = buf.String()
|
|
||||||
|
|
||||||
data["importpath"] = guessImportPath() + "/" + guessCmdDir()
|
err = writeStringToFile(filepath.Join(project.AbsPath(), "main.go"), mainScript)
|
||||||
|
if err != nil {
|
||||||
err := writeTemplateToFile(ProjectPath(), "main.go", template, data)
|
er(err)
|
||||||
_ = err
|
}
|
||||||
// if err != nil {
|
|
||||||
// er(err)
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func createRootCmdFile() {
|
func createRootCmdFile(project *Project) {
|
||||||
lic := getLicense()
|
template := `{{comment .copyright}}
|
||||||
|
{{if .license}}{{comment .license}}{{end}}
|
||||||
|
|
||||||
template := `{{ comment .copyright }}
|
|
||||||
{{if .license}}{{ comment .license }}
|
|
||||||
{{end}}
|
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -159,14 +134,14 @@ import (
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
{{ if .viper }} "github.com/spf13/viper"
|
{{if .viper}} "github.com/spf13/viper"{{end}}
|
||||||
{{ end }})
|
)
|
||||||
{{if .viper}}
|
|
||||||
var cfgFile string
|
{{if .viper}}var cfgFile string{{end}}
|
||||||
{{ end }}
|
|
||||||
// RootCmd represents the base command when called without any subcommands
|
// RootCmd represents the base command when called without any subcommands
|
||||||
var RootCmd = &cobra.Command{
|
var RootCmd = &cobra.Command{
|
||||||
Use: "{{ .appName }}",
|
Use: "{{.appName}}",
|
||||||
Short: "A brief description of your application",
|
Short: "A brief description of your application",
|
||||||
Long: ` + "`" + `A longer description that spans multiple lines and likely contains
|
Long: ` + "`" + `A longer description that spans multiple lines and likely contains
|
||||||
examples and usage of using your application. For example:
|
examples and usage of using your application. For example:
|
||||||
|
@ -174,9 +149,9 @@ examples and usage of using your application. For example:
|
||||||
Cobra is a CLI library for Go that empowers applications.
|
Cobra is a CLI library for Go that empowers applications.
|
||||||
This application is a tool to generate the needed files
|
This application is a tool to generate the needed files
|
||||||
to quickly create a Cobra application.` + "`" + `,
|
to quickly create a Cobra application.` + "`" + `,
|
||||||
// Uncomment the following line if your bare application
|
// Uncomment the following line if your bare application
|
||||||
// has an action associated with it:
|
// has an action associated with it:
|
||||||
// Run: func(cmd *cobra.Command, args []string) { },
|
// Run: func(cmd *cobra.Command, args []string) { },
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute adds all child commands to the root command sets flags appropriately.
|
// Execute adds all child commands to the root command sets flags appropriately.
|
||||||
|
@ -189,57 +164,54 @@ func Execute() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
{{ if .viper }} cobra.OnInitialize(initConfig)
|
{{if .viper}} cobra.OnInitialize(initConfig){{end}}
|
||||||
|
|
||||||
{{ end }} // Here you will define your flags and configuration settings.
|
// Here you will define your flags and configuration settings.
|
||||||
// Cobra supports Persistent Flags, which, if defined here,
|
// Cobra supports Persistent Flags, which, if defined here,
|
||||||
// will be global for your application.
|
// will be global for your application.{{ if .viper }}
|
||||||
{{ if .viper }}
|
RootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.{{ .appName }}.yaml)"){{ else }}
|
||||||
RootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.{{ .appName }}.yaml)")
|
// RootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.{{ .appName }}.yaml)"){{ end }}
|
||||||
{{ else }}
|
|
||||||
// RootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.{{ .appName }}.yaml)")
|
// Cobra also supports local flags, which will only run
|
||||||
{{ end }} // Cobra also supports local flags, which will only run
|
|
||||||
// when this action is called directly.
|
// when this action is called directly.
|
||||||
RootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
|
RootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
|
||||||
}
|
}{{ if .viper }}
|
||||||
{{ if .viper }}
|
|
||||||
// initConfig reads in config file and ENV variables if set.
|
// initConfig reads in config file and ENV variables if set.
|
||||||
func initConfig() {
|
func initConfig() {
|
||||||
if cfgFile != "" { // enable ability to specify config file via flag
|
if cfgFile != "" { // enable ability to specify config file via flag
|
||||||
viper.SetConfigFile(cfgFile)
|
viper.SetConfigFile(cfgFile)
|
||||||
|
} else {
|
||||||
|
viper.SetConfigName(".{{ .appName }}") // name of config file (without extension)
|
||||||
|
viper.AddConfigPath(os.Getenv("HOME")) // adding home directory as first search path
|
||||||
}
|
}
|
||||||
|
|
||||||
viper.SetConfigName(".{{ .appName }}") // name of config file (without extension)
|
|
||||||
viper.AddConfigPath(os.Getenv("HOME")) // adding home directory as first search path
|
|
||||||
viper.AutomaticEnv() // read in environment variables that match
|
viper.AutomaticEnv() // read in environment variables that match
|
||||||
|
|
||||||
// If a config file is found, read it in.
|
// If a config file is found, read it in.
|
||||||
if err := viper.ReadInConfig(); err == nil {
|
if err := viper.ReadInConfig(); err == nil {
|
||||||
fmt.Println("Using config file:", viper.ConfigFileUsed())
|
fmt.Println("Using config file:", viper.ConfigFileUsed())
|
||||||
}
|
}
|
||||||
}
|
}{{ end }}
|
||||||
{{ end }}`
|
`
|
||||||
|
|
||||||
data := make(map[string]interface{})
|
data := make(map[string]interface{})
|
||||||
|
|
||||||
data["copyright"] = copyrightLine()
|
data["copyright"] = copyrightLine()
|
||||||
data["appName"] = projectName()
|
|
||||||
|
|
||||||
// Generate license template from header and data.
|
|
||||||
r, _ := templateToReader(lic.Header, data)
|
|
||||||
buf := new(bytes.Buffer)
|
|
||||||
buf.ReadFrom(r)
|
|
||||||
data["license"] = buf.String()
|
|
||||||
|
|
||||||
data["viper"] = viper.GetBool("useViper")
|
data["viper"] = viper.GetBool("useViper")
|
||||||
|
data["license"] = project.License().Header
|
||||||
|
|
||||||
err := writeTemplateToFile(ProjectPath()+string(os.PathSeparator)+guessCmdDir(), "root.go", template, data)
|
rootCmdScript, err := executeTemplate(template, data)
|
||||||
|
if err != nil {
|
||||||
|
er(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = writeStringToFile(filepath.Join(project.AbsPath(), project.CmdDir(), "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(ProjectPath())
|
fmt.Println(project.AbsPath() + "\n")
|
||||||
fmt.Println("Give it a try by going there and running `go run main.go`")
|
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("Add commands to it by running `cobra add [cmdname]`")
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,18 +19,17 @@ func initApache2() {
|
||||||
Licenses["apache"] = License{
|
Licenses["apache"] = License{
|
||||||
Name: "Apache 2.0",
|
Name: "Apache 2.0",
|
||||||
PossibleMatches: []string{"apache", "apache20", "apache 2.0", "apache2.0", "apache-2.0"},
|
PossibleMatches: []string{"apache", "apache20", "apache 2.0", "apache2.0", "apache-2.0"},
|
||||||
Header: `
|
Header: `Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
you may not use this file except in compliance with the License.
|
||||||
// you may not use this file except in compliance with the License.
|
You may obtain a copy of the License at
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
Unless required by applicable law or agreed to in writing, software
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
See the License for the specific language governing permissions and
|
||||||
// See the License for the specific language governing permissions and
|
limitations under the License.`,
|
||||||
// limitations under the License.`,
|
|
||||||
Text: `
|
Text: `
|
||||||
Apache License
|
Apache License
|
||||||
Version 2.0, January 2004
|
Version 2.0, January 2004
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -42,9 +43,6 @@ func init() {
|
||||||
// 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"}, "", ""}
|
||||||
|
|
||||||
// Allows a user to use config for a custom license.
|
|
||||||
Licenses["custom"] = License{"Custom", []string{}, "", ""}
|
|
||||||
|
|
||||||
initApache2()
|
initApache2()
|
||||||
initMit()
|
initMit()
|
||||||
initBsdClause3()
|
initBsdClause3()
|
||||||
|
@ -53,49 +51,29 @@ func init() {
|
||||||
initGpl3()
|
initGpl3()
|
||||||
initLgpl()
|
initLgpl()
|
||||||
initAgpl()
|
initAgpl()
|
||||||
|
|
||||||
// Licenses["apache20"] = License{
|
|
||||||
// Name: "Apache 2.0",
|
|
||||||
// PossibleMatches: []string{"apache", "apache20", ""},
|
|
||||||
// Header: `
|
|
||||||
// `,
|
|
||||||
// Text: `
|
|
||||||
// `,
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Inspect project for existing license
|
||||||
func getLicense() License {
|
func getLicense() License {
|
||||||
l := whichLicense()
|
// If explicitly flagged, use that.
|
||||||
if l != "" {
|
|
||||||
if x, ok := Licenses[l]; ok {
|
|
||||||
return x
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Licenses["apache"]
|
|
||||||
}
|
|
||||||
|
|
||||||
func whichLicense() string {
|
|
||||||
// if explicitly flagged, use that
|
|
||||||
if userLicense != "" {
|
if userLicense != "" {
|
||||||
return matchLicense(userLicense)
|
return findLicense(userLicense)
|
||||||
}
|
}
|
||||||
|
|
||||||
// if already present in the project, use that
|
// If user wants to have custom license, use that.
|
||||||
// TODO: Inspect project for existing license
|
|
||||||
|
|
||||||
// default to viper's setting
|
|
||||||
|
|
||||||
if viper.IsSet("license.header") || viper.IsSet("license.text") {
|
if viper.IsSet("license.header") || viper.IsSet("license.text") {
|
||||||
if custom, ok := Licenses["custom"]; ok {
|
return License{Header: viper.GetString("license.header"),
|
||||||
custom.Header = viper.GetString("license.header")
|
Text: "license.text"}
|
||||||
custom.Text = viper.GetString("license.text")
|
|
||||||
Licenses["custom"] = custom
|
|
||||||
return "custom"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return matchLicense(viper.GetString("license"))
|
// If user wants to have built-in license, use that.
|
||||||
|
if viper.IsSet("license") {
|
||||||
|
return findLicense(viper.GetString("license"))
|
||||||
|
}
|
||||||
|
|
||||||
|
// If user didn't set any license, use Apache 2.0 by default.
|
||||||
|
fmt.Println("apache")
|
||||||
|
return Licenses["apache"]
|
||||||
}
|
}
|
||||||
|
|
||||||
func copyrightLine() string {
|
func copyrightLine() string {
|
||||||
|
@ -105,14 +83,27 @@ func copyrightLine() string {
|
||||||
return "Copyright © " + year + " " + author
|
return "Copyright © " + year + " " + author
|
||||||
}
|
}
|
||||||
|
|
||||||
// given a license name (in), try to match the license indicated
|
func findLicense(name string) License {
|
||||||
func matchLicense(in string) string {
|
found := matchLicense(name)
|
||||||
|
if found == "" {
|
||||||
|
er(fmt.Errorf("unknown license %q", name))
|
||||||
|
}
|
||||||
|
return Licenses[found]
|
||||||
|
}
|
||||||
|
|
||||||
|
// given a license name, try to match the license indicated
|
||||||
|
func matchLicense(name string) string {
|
||||||
|
if name == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
for key, lic := range Licenses {
|
for key, lic := range Licenses {
|
||||||
for _, match := range lic.PossibleMatches {
|
for _, match := range lic.PossibleMatches {
|
||||||
if strings.EqualFold(in, match) {
|
if strings.EqualFold(name, match) {
|
||||||
return key
|
return key
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
154
cobra/cmd/project.go
Normal file
154
cobra/cmd/project.go
Normal file
|
@ -0,0 +1,154 @@
|
||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Project struct {
|
||||||
|
absPath string
|
||||||
|
cmdDir string
|
||||||
|
srcPath string
|
||||||
|
license License
|
||||||
|
name string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewProject(projectName string) *Project {
|
||||||
|
if projectName == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
p := new(Project)
|
||||||
|
p.name = projectName
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
if p.absPath == "" {
|
||||||
|
wd, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
er(err)
|
||||||
|
}
|
||||||
|
for _, goPath := range goPaths {
|
||||||
|
if filepath.HasPrefix(wd, goPath) {
|
||||||
|
p.absPath = filepath.Join(goPath, projectName)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. If user is not in GOPATH, then use (first GOPATH)+projectName.
|
||||||
|
if p.absPath == "" {
|
||||||
|
p.absPath = filepath.Join(srcPaths[0], projectName)
|
||||||
|
}
|
||||||
|
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
// findPackage returns full path to go package. It supports multiple 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"
|
||||||
|
func findPackage(packageName string) string {
|
||||||
|
if packageName == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, srcPath := range srcPaths {
|
||||||
|
packagePath := filepath.Join(srcPath, packageName)
|
||||||
|
if exists(packagePath) {
|
||||||
|
return packagePath
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewProjectFromPath(absPath string) *Project {
|
||||||
|
if absPath == "" || !filepath.IsAbs(absPath) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
p := new(Project)
|
||||||
|
p.absPath = absPath
|
||||||
|
p.absPath = strings.TrimSuffix(p.absPath, p.CmdDir())
|
||||||
|
p.name = filepath.ToSlash(trimSrcPath(p.absPath, p.SrcPath()))
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func trimSrcPath(absPath, srcPath string) string {
|
||||||
|
relPath, err := filepath.Rel(srcPath, absPath)
|
||||||
|
if err != nil {
|
||||||
|
er("Cobra only supports project within $GOPATH")
|
||||||
|
}
|
||||||
|
return relPath
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Project) License() License {
|
||||||
|
if p.license.Text == "" { // check if license is not blank
|
||||||
|
p.license = getLicense()
|
||||||
|
}
|
||||||
|
|
||||||
|
return p.license
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p Project) Name() string {
|
||||||
|
return p.name
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Project) CmdDir() string {
|
||||||
|
if p.absPath == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
if p.cmdDir == "" {
|
||||||
|
p.cmdDir = findCmdDir(p.absPath)
|
||||||
|
}
|
||||||
|
return p.cmdDir
|
||||||
|
}
|
||||||
|
|
||||||
|
func findCmdDir(absPath string) string {
|
||||||
|
if !exists(absPath) || isEmpty(absPath) {
|
||||||
|
return "cmd"
|
||||||
|
}
|
||||||
|
|
||||||
|
files, _ := filepath.Glob(filepath.Join(absPath, "c*"))
|
||||||
|
for _, f := range files {
|
||||||
|
for _, c := range cmdDirs {
|
||||||
|
if f == c {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "cmd"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p Project) AbsPath() string {
|
||||||
|
return p.absPath
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Project) SrcPath() string {
|
||||||
|
if p.srcPath != "" {
|
||||||
|
return p.srcPath
|
||||||
|
}
|
||||||
|
if p.absPath == "" {
|
||||||
|
p.srcPath = srcPaths[0]
|
||||||
|
return p.srcPath
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, srcPath := range srcPaths {
|
||||||
|
if strings.HasPrefix(p.absPath, srcPath) {
|
||||||
|
p.srcPath = srcPath
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return p.srcPath
|
||||||
|
}
|
|
@ -21,8 +21,7 @@ import (
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
)
|
)
|
||||||
|
|
||||||
var cfgFile string
|
var cfgFile, projectBase, userLicense string // are used for flags
|
||||||
var userLicense string
|
|
||||||
|
|
||||||
// RootCmd represents the base command when called without any subcommands
|
// RootCmd represents the base command when called without any subcommands
|
||||||
var RootCmd = &cobra.Command{
|
var RootCmd = &cobra.Command{
|
||||||
|
@ -42,7 +41,7 @@ func Execute() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
cobra.OnInitialize(initConfig)
|
initViper()
|
||||||
RootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.cobra.yaml)")
|
RootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.cobra.yaml)")
|
||||||
RootCmd.PersistentFlags().StringVarP(&projectBase, "projectbase", "b", "", "base project directory, e.g. github.com/spf13/")
|
RootCmd.PersistentFlags().StringVarP(&projectBase, "projectbase", "b", "", "base project directory, e.g. github.com/spf13/")
|
||||||
RootCmd.PersistentFlags().StringP("author", "a", "YOUR NAME", "Author name for copyright attribution")
|
RootCmd.PersistentFlags().StringP("author", "a", "YOUR NAME", "Author name for copyright attribution")
|
||||||
|
@ -55,17 +54,16 @@ func init() {
|
||||||
viper.SetDefault("license", "apache")
|
viper.SetDefault("license", "apache")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read in config file and ENV variables if set.
|
func initViper() {
|
||||||
func initConfig() {
|
|
||||||
if cfgFile != "" { // enable ability to specify config file via flag
|
if cfgFile != "" { // enable ability to specify config file via flag
|
||||||
viper.SetConfigFile(cfgFile)
|
viper.SetConfigFile(cfgFile)
|
||||||
|
} else {
|
||||||
|
viper.AddConfigPath(os.Getenv("HOME"))
|
||||||
|
viper.SetConfigName(".cobra")
|
||||||
}
|
}
|
||||||
|
|
||||||
viper.SetConfigName(".cobra") // name of config file (without extension)
|
viper.AutomaticEnv()
|
||||||
viper.AddConfigPath(os.Getenv("HOME")) // adding home directory as first search path
|
|
||||||
viper.AutomaticEnv() // read in environment variables that match
|
|
||||||
|
|
||||||
// If a config file is found, read it in.
|
|
||||||
if err := viper.ReadInConfig(); err == nil {
|
if err := viper.ReadInConfig(); err == nil {
|
||||||
fmt.Println("Using config file:", viper.ConfigFileUsed())
|
fmt.Println("Using config file:", viper.ConfigFileUsed())
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue