Skip to content

Commit

Permalink
Validate gopath when running gqlgen
Browse files Browse the repository at this point in the history
  • Loading branch information
Adam Scarr committed Aug 23, 2018
1 parent 45adfd1 commit d13ad32
Show file tree
Hide file tree
Showing 6 changed files with 116 additions and 46 deletions.
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")
})
}
}

0 comments on commit d13ad32

Please sign in to comment.