Compatibility for multiple GOPATH workspaces

This commit adds the necessary changes to support users with multiple
`GOPATH` workspaces. Previously the `getSrcPath()` function in
`cobra/cmd/helpers.go` would not take into account the fact the the
system `GOPATH` returns a colon-separated list if system was configured
with multiple GOPATH workspaces. If the GOPATH was set to be
`/foo/a:/bar/b`, it would simply append `src/` to the end of the string
literal giving `/foo/a:/bar/b/src` which resulted in undesired behavior.

Following the specs the changeset here adds support for multiple GOPATH
workspaces and if a given package directory is not to be found in any of
the workspaces the first one is chosen, i.e. for `cobra init` it will
first check all workspaces for the specified project and settling on the
first (`/foo/a`) if nothing found.
This preserves backwards compatibility as single workspace environments
are provably unaffected by these changes.
This commit is contained in:
irfan sharif 2016-10-01 20:51:36 -04:00
parent 9c28e4bbd7
commit 40d25d2c31
3 changed files with 46 additions and 21 deletions

View file

@ -26,10 +26,6 @@ import (
"github.com/spf13/viper" "github.com/spf13/viper"
) )
// var BaseDir = ""
// var AppName = ""
// var CommandDir = ""
var funcMap template.FuncMap var funcMap template.FuncMap
var projectPath = "" var projectPath = ""
var inputPath = "" var inputPath = ""
@ -99,16 +95,24 @@ func guessCmdDir() string {
func guessImportPath() string { func guessImportPath() string {
guessProjectPath() guessProjectPath()
srcPaths := getSrcPaths()
if !strings.HasPrefix(projectPath, getSrcPath()) { for _, srcPath := range srcPaths {
er("Cobra only supports project within $GOPATH") if strings.HasPrefix(projectPath, srcPath) {
return filepath.ToSlash(filepath.Clean(strings.TrimPrefix(projectPath, srcPath)))
}
} }
return filepath.ToSlash(filepath.Clean(strings.TrimPrefix(projectPath, getSrcPath()))) er("Cobra only supports project within $GOPATH")
return ""
} }
func getSrcPath() string { func getSrcPaths() []string {
return filepath.Join(os.Getenv("GOPATH"), "src") + string(os.PathSeparator) paths := strings.Split(os.Getenv("GOPATH"), string(os.PathListSeparator))
for i, gopath := range paths {
srcPath := filepath.Join(gopath, "src") + string(os.PathSeparator)
paths[i] = srcPath
}
return paths
} }
func projectName() string { func projectName() string {
@ -140,7 +144,7 @@ func guessProjectPath() {
} }
} }
srcPath := getSrcPath() srcPaths := getSrcPaths()
// if provided, inspect for logical locations // if provided, inspect for logical locations
if strings.ContainsRune(inputPath, os.PathSeparator) { if strings.ContainsRune(inputPath, os.PathSeparator) {
if filepath.IsAbs(inputPath) || filepath.HasPrefix(inputPath, string(os.PathSeparator)) { if filepath.IsAbs(inputPath) || filepath.HasPrefix(inputPath, string(os.PathSeparator)) {
@ -155,10 +159,24 @@ func guessProjectPath() {
switch count { switch count {
// If only one directory deep, assume "github.com" // If only one directory deep, assume "github.com"
case 1: case 1:
projectPath = filepath.Join(srcPath, "github.com", inputPath) for _, srcPath := range srcPaths {
fpath := filepath.Join(srcPath, "github.com", inputPath)
if b, _ := exists(fpath); b {
projectPath = fpath
return
}
}
projectPath = filepath.Join(srcPaths[0], "github.com", inputPath)
return return
case 2: case 2:
projectPath = filepath.Join(srcPath, inputPath) for _, srcPath := range srcPaths {
fpath := filepath.Join(srcPath, inputPath)
if b, _ := exists(fpath); b {
projectPath = fpath
return
}
}
projectPath = filepath.Join(srcPaths[0], inputPath)
return return
default: default:
er("Unknown directory") er("Unknown directory")
@ -167,13 +185,20 @@ func guessProjectPath() {
// hardest case.. just a word. // hardest case.. just a word.
if projectBase == "" { if projectBase == "" {
x, err := getWd() x, err := getWd()
if err == nil { if err != nil {
er(err)
}
projectPath = filepath.Join(x, inputPath) projectPath = filepath.Join(x, inputPath)
return return
}
er(err)
} else { } else {
projectPath = filepath.Join(srcPath, projectBase, inputPath) for _, srcPath := range srcPaths {
fpath := filepath.Join(srcPath, projectBase, inputPath)
if b, _ := exists(fpath); b {
projectPath = fpath
return
}
}
projectPath = filepath.Join(srcPaths[0], projectBase, inputPath)
return return
} }
} }

View file

@ -29,8 +29,8 @@ func reset() {
} }
func TestProjectPath(t *testing.T) { func TestProjectPath(t *testing.T) {
checkGuess(t, "", filepath.Join("github.com", "spf13", "hugo"), filepath.Join(getSrcPath(), "github.com", "spf13", "hugo")) checkGuess(t, "", filepath.Join("github.com", "spf13", "hugo"), filepath.Join(getSrcPaths()[0], "github.com", "spf13", "hugo"))
checkGuess(t, "", filepath.Join("spf13", "hugo"), filepath.Join(getSrcPath(), "github.com", "spf13", "hugo")) checkGuess(t, "", filepath.Join("spf13", "hugo"), filepath.Join(getSrcPaths()[0], "github.com", "spf13", "hugo"))
checkGuess(t, "", filepath.Join("/", "bar", "foo"), filepath.Join("/", "bar", "foo")) checkGuess(t, "", filepath.Join("/", "bar", "foo"), filepath.Join("/", "bar", "foo"))
checkGuess(t, "/bar/foo", "baz", filepath.Join("/", "bar", "foo", "baz")) checkGuess(t, "/bar/foo", "baz", filepath.Join("/", "bar", "foo", "baz"))
checkGuess(t, "/bar/foo/cmd", "", filepath.Join("/", "bar", "foo")) checkGuess(t, "/bar/foo/cmd", "", filepath.Join("/", "bar", "foo"))

View file

@ -33,7 +33,7 @@ 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. // 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)