Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Validate gopath when running gqlgen #312

Merged
merged 1 commit into from
Aug 23, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"log"
"os"

"github.com/99designs/gqlgen/internal/gopath"
"github.com/spf13/cobra"
)

Expand Down Expand Up @@ -39,6 +40,16 @@ var rootCmd = &cobra.Command{
Long: `This is a library for quickly creating strictly typed graphql servers in golang.
See https://gqlgen.com/ for a getting started guide.`,
PersistentPreRun: func(cmd *cobra.Command, args []string) {
pwd, err := os.Getwd()
if err != nil {
fmt.Fprintf(os.Stderr, "unable to determine current workding dir: %s\n", err.Error())
os.Exit(1)
}

if !gopath.Contains(pwd) {
fmt.Fprintf(os.Stderr, "gqlgen must be run from inside your $GOPATH\n")
os.Exit(1)
}
if verbose {
log.SetFlags(0)
} else {
Expand Down
16 changes: 3 additions & 13 deletions codegen/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"path/filepath"
"strings"

"github.com/99designs/gqlgen/internal/gopath"
"github.com/pkg/errors"
"github.com/vektah/gqlparser/ast"
"gopkg.in/yaml.v2"
Expand Down Expand Up @@ -107,22 +108,11 @@ func (c *PackageConfig) normalize() error {
}

func (c *PackageConfig) ImportPath() string {
dir := filepath.ToSlash(c.Dir())
for _, gopath := range filepath.SplitList(build.Default.GOPATH) {
gopath = filepath.ToSlash(gopath) + "/src/"
if len(gopath) > len(dir) {
continue
}
if strings.EqualFold(gopath, dir[0:len(gopath)]) {
dir = dir[len(gopath):]
break
}
}
return dir
return gopath.MustDir2Import(c.Dir())
}

func (c *PackageConfig) Dir() string {
return filepath.ToSlash(filepath.Dir(c.Filename))
return filepath.Dir(c.Filename)
}

func (c *PackageConfig) Check() error {
Expand Down
26 changes: 0 additions & 26 deletions codegen/config_test.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
package codegen

import (
"go/build"
"os"
"path/filepath"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

Expand Down Expand Up @@ -58,27 +56,3 @@ func TestLoadDefaultConfig(t *testing.T) {
require.True(t, os.IsNotExist(err))
})
}

func Test_fullPackageName(t *testing.T) {
origBuildContext := build.Default
defer func() { build.Default = origBuildContext }()

t.Run("gopath longer than package name", func(t *testing.T) {
p := PackageConfig{Filename: "/b/src/y/foo/bar/baz.go"}
build.Default.GOPATH = "/a/src/xxxxxxxxxxxxxxxxxxxxxxxx:/b/src/y"
var got string
ok := assert.NotPanics(t, func() { got = p.ImportPath() })
if ok {
assert.Equal(t, "/b/src/y/foo/bar", got)
}
})
t.Run("stop searching on first hit", func(t *testing.T) {
p := PackageConfig{Filename: "/a/src/x/foo/bar/baz.go"}
build.Default.GOPATH = "/a/src/x:/b/src/y"
var got string
ok := assert.NotPanics(t, func() { got = p.ImportPath() })
if ok {
assert.Equal(t, "/a/src/x/foo/bar", got)
}
})
}
10 changes: 3 additions & 7 deletions codegen/import_build.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,11 @@ import (
"go/build"
"sort"
"strconv"
"strings"

// Import and ignore the ambient imports listed below so dependency managers
// don't prune unused code for us. Both lists should be kept in sync.
_ "github.com/99designs/gqlgen/graphql"
_ "github.com/99designs/gqlgen/graphql/introspection"
"github.com/99designs/gqlgen/internal/gopath"
_ "github.com/vektah/gqlparser"
_ "github.com/vektah/gqlparser/ast"
)
Expand Down Expand Up @@ -55,7 +54,8 @@ func (s *Imports) add(path string) *Import {
return nil
}

if stringHasSuffixFold(s.destDir, path) {
// if we are referencing our own package we dont need an import
if gopath.MustDir2Import(s.destDir) == path {
return nil
}

Expand All @@ -77,10 +77,6 @@ func (s *Imports) add(path string) *Import {
return imp
}

func stringHasSuffixFold(s, suffix string) bool {
return len(s) >= len(suffix) && strings.EqualFold(s[len(s)-len(suffix):], suffix)
}

func (s Imports) finalize() []*Import {
// ensure stable ordering by sorting
sort.Slice(s.imports, func(i, j int) bool {
Expand Down
37 changes: 37 additions & 0 deletions internal/gopath/gopath.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package gopath

import (
"fmt"
"go/build"
"path/filepath"
"strings"
)

var NotFound = fmt.Errorf("not on GOPATH")

// Contains returns true if the given directory is in the GOPATH
func Contains(dir string) bool {
_, err := Dir2Import(dir)
return err == nil
}

// Dir2Import takes an *absolute* path and returns a golang import path for the package, and returns an error if it isn't on the gopath
func Dir2Import(dir string) (string, error) {
dir = filepath.ToSlash(dir)
for _, gopath := range filepath.SplitList(build.Default.GOPATH) {
gopath = filepath.ToSlash(filepath.Join(gopath, "src"))
if len(gopath) < len(dir) && strings.EqualFold(gopath, dir[0:len(gopath)]) {
return dir[len(gopath)+1:], nil
}
}
return "", NotFound
}

// MustDir2Import takes an *absolute* path and returns a golang import path for the package, and panics if it isn't on the gopath
func MustDir2Import(dir string) string {
pkg, err := Dir2Import(dir)
if err != nil {
panic(err)
}
return pkg
}
62 changes: 62 additions & 0 deletions internal/gopath/gopath_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package gopath

import (
"go/build"
"runtime"
"testing"

"github.com/stretchr/testify/assert"
)

func TestContains(t *testing.T) {
origBuildContext := build.Default
defer func() { build.Default = origBuildContext }()

if runtime.GOOS == "windows" {
build.Default.GOPATH = `C:\go;C:\Users\user\go`

assert.True(t, Contains(`C:\go\src\github.com\vektah\gqlgen`))
assert.True(t, Contains(`C:\go\src\fpp`))
assert.True(t, Contains(`C:/go/src/github.com/vektah/gqlgen`))
assert.True(t, Contains(`C:\Users\user\go\src\foo`))
assert.False(t, Contains(`C:\tmp`))
assert.False(t, Contains(`C:\Users\user`))
assert.False(t, Contains(`C:\Users\another\go`))
} else {
build.Default.GOPATH = "/go:/home/user/go"

assert.True(t, Contains("/go/src/github.com/vektah/gqlgen"))
assert.True(t, Contains("/go/src/foo"))
assert.True(t, Contains("/home/user/go/src/foo"))
assert.False(t, Contains("/tmp"))
assert.False(t, Contains("/home/user"))
assert.False(t, Contains("/home/another/go"))
}
}

func TestDir2Package(t *testing.T) {
origBuildContext := build.Default
defer func() { build.Default = origBuildContext }()

if runtime.GOOS == "windows" {
build.Default.GOPATH = "C:/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;C:/a/y;C:/b/"

assert.Equal(t, "foo/bar", MustDir2Import("C:/a/y/src/foo/bar"))
assert.Equal(t, "foo/bar", MustDir2Import(`C:\a\y\src\foo\bar`))
assert.Equal(t, "foo/bar", MustDir2Import("C:/b/src/foo/bar"))
assert.Equal(t, "foo/bar", MustDir2Import(`C:\b\src\foo\bar`))

assert.PanicsWithValue(t, NotFound, func() {
MustDir2Import("C:/tmp/foo")
})
} else {
build.Default.GOPATH = "/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx:/a/y:/b/"

assert.Equal(t, "foo/bar", MustDir2Import("/a/y/src/foo/bar"))
assert.Equal(t, "foo/bar", MustDir2Import("/b/src/foo/bar"))

assert.PanicsWithValue(t, NotFound, func() {
MustDir2Import("/tmp/foo")
})
}
}