diff options
Diffstat (limited to 'vendor/github.com/99designs/gqlgen/codegen/config.go')
-rw-r--r-- | vendor/github.com/99designs/gqlgen/codegen/config.go | 195 |
1 files changed, 195 insertions, 0 deletions
diff --git a/vendor/github.com/99designs/gqlgen/codegen/config.go b/vendor/github.com/99designs/gqlgen/codegen/config.go new file mode 100644 index 00000000..db0e467b --- /dev/null +++ b/vendor/github.com/99designs/gqlgen/codegen/config.go @@ -0,0 +1,195 @@ +package codegen + +import ( + "fmt" + "go/build" + "io/ioutil" + "os" + "path/filepath" + "strings" + + "github.com/99designs/gqlgen/internal/gopath" + "github.com/pkg/errors" + "github.com/vektah/gqlparser/ast" + "gopkg.in/yaml.v2" +) + +var cfgFilenames = []string{".gqlgen.yml", "gqlgen.yml", "gqlgen.yaml"} + +// DefaultConfig creates a copy of the default config +func DefaultConfig() *Config { + return &Config{ + SchemaFilename: "schema.graphql", + Model: PackageConfig{Filename: "models_gen.go"}, + Exec: PackageConfig{Filename: "generated.go"}, + } +} + +// LoadConfigFromDefaultLocations looks for a config file in the current directory, and all parent directories +// walking up the tree. The closest config file will be returned. +func LoadConfigFromDefaultLocations() (*Config, error) { + cfgFile, err := findCfg() + if err != nil { + return nil, err + } + + err = os.Chdir(filepath.Dir(cfgFile)) + if err != nil { + return nil, errors.Wrap(err, "unable to enter config dir") + } + return LoadConfig(cfgFile) +} + +// LoadConfig reads the gqlgen.yml config file +func LoadConfig(filename string) (*Config, error) { + config := DefaultConfig() + + b, err := ioutil.ReadFile(filename) + if err != nil { + return nil, errors.Wrap(err, "unable to read config") + } + + if err := yaml.UnmarshalStrict(b, config); err != nil { + return nil, errors.Wrap(err, "unable to parse config") + } + + config.FilePath = filename + + return config, nil +} + +type Config struct { + SchemaFilename string `yaml:"schema,omitempty"` + SchemaStr string `yaml:"-"` + Exec PackageConfig `yaml:"exec"` + Model PackageConfig `yaml:"model"` + Resolver PackageConfig `yaml:"resolver,omitempty"` + Models TypeMap `yaml:"models,omitempty"` + StructTag string `yaml:"struct_tag,omitempty"` + + FilePath string `yaml:"-"` + + schema *ast.Schema `yaml:"-"` +} + +type PackageConfig struct { + Filename string `yaml:"filename,omitempty"` + Package string `yaml:"package,omitempty"` + Type string `yaml:"type,omitempty"` +} + +type TypeMapEntry struct { + Model string `yaml:"model"` + Fields map[string]TypeMapField `yaml:"fields,omitempty"` +} + +type TypeMapField struct { + Resolver bool `yaml:"resolver"` + FieldName string `yaml:"fieldName"` +} + +func (c *PackageConfig) normalize() error { + if c.Filename == "" { + return errors.New("Filename is required") + } + c.Filename = abs(c.Filename) + // If Package is not set, first attempt to load the package at the output dir. If that fails + // fallback to just the base dir name of the output filename. + if c.Package == "" { + cwd, _ := os.Getwd() + pkg, _ := build.Default.Import(c.ImportPath(), cwd, 0) + if pkg.Name != "" { + c.Package = pkg.Name + } else { + c.Package = filepath.Base(c.Dir()) + } + } + c.Package = sanitizePackageName(c.Package) + return nil +} + +func (c *PackageConfig) ImportPath() string { + return gopath.MustDir2Import(c.Dir()) +} + +func (c *PackageConfig) Dir() string { + return filepath.Dir(c.Filename) +} + +func (c *PackageConfig) Check() error { + if strings.ContainsAny(c.Package, "./\\") { + return fmt.Errorf("package should be the output package name only, do not include the output filename") + } + if c.Filename != "" && !strings.HasSuffix(c.Filename, ".go") { + return fmt.Errorf("filename should be path to a go source file") + } + return nil +} + +func (c *PackageConfig) IsDefined() bool { + return c.Filename != "" +} + +func (cfg *Config) Check() error { + if err := cfg.Models.Check(); err != nil { + return errors.Wrap(err, "config.models") + } + if err := cfg.Exec.Check(); err != nil { + return errors.Wrap(err, "config.exec") + } + if err := cfg.Model.Check(); err != nil { + return errors.Wrap(err, "config.model") + } + if err := cfg.Resolver.Check(); err != nil { + return errors.Wrap(err, "config.resolver") + } + return nil +} + +type TypeMap map[string]TypeMapEntry + +func (tm TypeMap) Exists(typeName string) bool { + _, ok := tm[typeName] + return ok +} + +func (tm TypeMap) Check() error { + for typeName, entry := range tm { + if strings.LastIndex(entry.Model, ".") < strings.LastIndex(entry.Model, "/") { + return fmt.Errorf("model %s: invalid type specifier \"%s\" - you need to specify a struct to map to", typeName, entry.Model) + } + } + return nil +} + +// findCfg searches for the config file in this directory and all parents up the tree +// looking for the closest match +func findCfg() (string, error) { + dir, err := os.Getwd() + if err != nil { + return "", errors.Wrap(err, "unable to get working dir to findCfg") + } + + cfg := findCfgInDir(dir) + + for cfg == "" && dir != filepath.Dir(dir) { + dir = filepath.Dir(dir) + cfg = findCfgInDir(dir) + } + + if cfg == "" { + return "", os.ErrNotExist + } + + return cfg, nil +} + +func findCfgInDir(dir string) string { + for _, cfgName := range cfgFilenames { + path := filepath.Join(dir, cfgName) + if _, err := os.Stat(path); err == nil { + return path + } + } + return "" +} |