import_build.go

  1package codegen
  2
  3import (
  4	"fmt"
  5	"go/build"
  6	"sort"
  7	"strconv"
  8	"strings"
  9)
 10
 11// These imports are referenced by the generated code, and are assumed to have the
 12// default alias. So lets make sure they get added first, and any later collisions get
 13// renamed.
 14var ambientImports = []string{
 15	"context",
 16	"fmt",
 17	"io",
 18	"strconv",
 19	"time",
 20	"sync",
 21	"github.com/vektah/gqlgen/neelance/introspection",
 22	"github.com/vektah/gqlgen/neelance/errors",
 23	"github.com/vektah/gqlgen/neelance/query",
 24	"github.com/vektah/gqlgen/neelance/schema",
 25	"github.com/vektah/gqlgen/neelance/validation",
 26	"github.com/vektah/gqlgen/graphql",
 27}
 28
 29func buildImports(types NamedTypes, destDir string) *Imports {
 30	imports := Imports{
 31		destDir: destDir,
 32	}
 33
 34	for _, ambient := range ambientImports {
 35		imports.add(ambient)
 36	}
 37
 38	// Imports from top level user types
 39	for _, t := range types {
 40		t.Import = imports.add(t.Package)
 41	}
 42
 43	return &imports
 44}
 45
 46func (s *Imports) add(path string) *Import {
 47	if path == "" {
 48		return nil
 49	}
 50
 51	if stringHasSuffixFold(s.destDir, path) {
 52		return nil
 53	}
 54
 55	if existing := s.findByPath(path); existing != nil {
 56		return existing
 57	}
 58
 59	pkg, err := build.Default.Import(path, s.destDir, 0)
 60	if err != nil {
 61		panic(err)
 62	}
 63
 64	imp := &Import{
 65		Name: pkg.Name,
 66		Path: path,
 67	}
 68	s.imports = append(s.imports, imp)
 69
 70	return imp
 71}
 72
 73func stringHasSuffixFold(s, suffix string) bool {
 74	return len(s) >= len(suffix) && strings.EqualFold(s[len(s)-len(suffix):], suffix)
 75}
 76
 77func (s Imports) finalize() []*Import {
 78	// ensure stable ordering by sorting
 79	sort.Slice(s.imports, func(i, j int) bool {
 80		return s.imports[i].Path > s.imports[j].Path
 81	})
 82
 83	for _, imp := range s.imports {
 84		alias := imp.Name
 85
 86		i := 1
 87		for s.findByAlias(alias) != nil {
 88			alias = imp.Name + strconv.Itoa(i)
 89			i++
 90			if i > 10 {
 91				panic(fmt.Errorf("too many collisions, last attempt was %s", alias))
 92			}
 93		}
 94		imp.alias = alias
 95	}
 96
 97	return s.imports
 98}
 99
100func (s Imports) findByPath(importPath string) *Import {
101	for _, imp := range s.imports {
102		if imp.Path == importPath {
103			return imp
104		}
105	}
106	return nil
107}
108
109func (s Imports) findByAlias(alias string) *Import {
110	for _, imp := range s.imports {
111		if imp.alias == alias {
112			return imp
113		}
114	}
115	return nil
116}