From c0158f5418b679d1af358ce6f7f9a9d3ecf4fcf0 Mon Sep 17 00:00:00 2001 From: Adam Scarr Date: Sat, 23 Jun 2018 13:16:38 +1000 Subject: [PATCH] make sure colliding imports are stable --- codegen/build.go | 4 +-- codegen/codegen.go | 7 +++++ codegen/import.go | 1 + codegen/import_build.go | 54 +++++++++++++++++------------------ codegen/import_test.go | 18 ++++++++++++ example/scalars/generated.go | 2 +- example/scalars/models_gen.go | 2 +- test/generated.go | 2 +- 8 files changed, 57 insertions(+), 33 deletions(-) diff --git a/codegen/build.go b/codegen/build.go index 872ce5f9ead..9319c4448c4 100644 --- a/codegen/build.go +++ b/codegen/build.go @@ -49,7 +49,7 @@ func (cfg *Config) models() (*ModelBuild, error) { PackageName: cfg.ModelPackageName, Models: models, Enums: cfg.buildEnums(namedTypes), - Imports: imports.imports, + Imports: imports.finalize(), }, nil } @@ -80,7 +80,7 @@ func (cfg *Config) bind() (*Build, error) { Objects: objects, Interfaces: cfg.buildInterfaces(namedTypes, prog), Inputs: inputs, - Imports: imports.imports, + Imports: imports.finalize(), } if qr, ok := cfg.schema.EntryPoints["query"]; ok { diff --git a/codegen/codegen.go b/codegen/codegen.go index 0fd36ef5dc6..e36f3226cec 100644 --- a/codegen/codegen.go +++ b/codegen/codegen.go @@ -7,6 +7,7 @@ import ( "io/ioutil" "os" "path/filepath" + "regexp" "strings" "syscall" @@ -136,6 +137,12 @@ func (cfg *Config) normalize() error { return cfg.schema.Parse(cfg.SchemaStr) } +var invalidPackageNameChar = regexp.MustCompile(`[^\w]`) + +func sanitizePackageName(pkg string) string { + return invalidPackageNameChar.ReplaceAllLiteralString(filepath.Base(pkg), "_") +} + func abs(path string) string { absPath, err := filepath.Abs(path) if err != nil { diff --git a/codegen/import.go b/codegen/import.go index 53f1888c2d4..123d310f6d9 100644 --- a/codegen/import.go +++ b/codegen/import.go @@ -5,6 +5,7 @@ import ( ) type Import struct { + Name string Alias string Path string } diff --git a/codegen/import_build.go b/codegen/import_build.go index f81f6fd5e56..245a213f0fe 100644 --- a/codegen/import_build.go +++ b/codegen/import_build.go @@ -1,9 +1,8 @@ package codegen import ( + "fmt" "go/build" - "path/filepath" - "regexp" "sort" "strconv" "strings" @@ -44,12 +43,6 @@ func buildImports(types NamedTypes, destDir string) *Imports { return &imports } -var invalidPackageNameChar = regexp.MustCompile(`[^\w]`) - -func sanitizePackageName(pkg string) string { - return invalidPackageNameChar.ReplaceAllLiteralString(filepath.Base(pkg), "_") -} - func (s *Imports) add(path string) *Import { if path == "" { return nil @@ -64,35 +57,40 @@ func (s *Imports) add(path string) *Import { panic(err) } - alias := "" - if !strings.HasSuffix(s.destDir, path) { - if pkg == nil { - panic(path + " was not loaded") + imp := &Import{ + Name: pkg.Name, + Path: path, + } + s.imports = append(s.imports, imp) + + return imp +} + +func (s Imports) finalize() []*Import { + // ensure stable ordering by sorting + sort.Slice(s.imports, func(i, j int) bool { + return s.imports[i].Path > s.imports[j].Path + }) + + for _, imp := range s.imports { + if strings.HasSuffix(s.destDir, imp.Path) { + imp.Alias = "" + continue } + alias := imp.Name - alias = pkg.Name i := 1 - imp := s.findByAlias(alias) - for imp != nil && imp.Path != path { - alias = pkg.Name + strconv.Itoa(i) - imp = s.findByAlias(alias) + for s.findByAlias(alias) != nil { + alias = imp.Name + strconv.Itoa(i) i++ if i > 10 { - panic("too many collisions") + panic(fmt.Errorf("too many collisions, last attempt was %s", imp.Alias)) } } + imp.Alias = alias } - imp := &Import{ - Alias: alias, - Path: path, - } - s.imports = append(s.imports, imp) - sort.Slice(s.imports, func(i, j int) bool { - return s.imports[i].Alias > s.imports[j].Alias - }) - - return imp + return s.imports } func (s Imports) findByPath(importPath string) *Import { diff --git a/codegen/import_test.go b/codegen/import_test.go index 3a0704f07e6..6e7c497a613 100644 --- a/codegen/import_test.go +++ b/codegen/import_test.go @@ -36,3 +36,21 @@ func TestImportCollisions(t *testing.T) { require.NoError(t, err) } + +func TestDeterministicDecollisioning(t *testing.T) { + a := Imports{ + imports: []*Import{ + {Name: "types", Path: "foobar/types"}, + {Name: "types", Path: "bazfoo/types"}, + }, + }.finalize() + + b := Imports{ + imports: []*Import{ + {Name: "types", Path: "bazfoo/types"}, + {Name: "types", Path: "foobar/types"}, + }, + }.finalize() + + require.EqualValues(t, a, b) +} diff --git a/example/scalars/generated.go b/example/scalars/generated.go index a3c79811ac9..e176b3e04db 100644 --- a/example/scalars/generated.go +++ b/example/scalars/generated.go @@ -5,10 +5,10 @@ package scalars import ( "bytes" context "context" + external "external" strconv "strconv" time "time" - external "github.com/vektah/gqlgen/example/scalars/vendor/external" graphql "github.com/vektah/gqlgen/graphql" introspection "github.com/vektah/gqlgen/neelance/introspection" query "github.com/vektah/gqlgen/neelance/query" diff --git a/example/scalars/models_gen.go b/example/scalars/models_gen.go index 07705d9274d..4a13829c15c 100644 --- a/example/scalars/models_gen.go +++ b/example/scalars/models_gen.go @@ -3,7 +3,7 @@ package scalars import ( - external "github.com/vektah/gqlgen/example/scalars/vendor/external" + external "external" ) type Address struct { diff --git a/test/generated.go b/test/generated.go index e3eabeb372c..2336ac610c7 100644 --- a/test/generated.go +++ b/test/generated.go @@ -5,6 +5,7 @@ package test import ( "bytes" context "context" + remote_api "remote_api" strconv "strconv" graphql "github.com/vektah/gqlgen/graphql" @@ -12,7 +13,6 @@ import ( query "github.com/vektah/gqlgen/neelance/query" schema "github.com/vektah/gqlgen/neelance/schema" models "github.com/vektah/gqlgen/test/models" - remote_api "github.com/vektah/gqlgen/test/vendor/remote_api" ) func MakeExecutableSchema(resolvers Resolvers) graphql.ExecutableSchema {