github.com/senomas/gqlgen@v0.17.11-0.20220626120754-9aee61b0716a/main.go (about)

     1  package main
     2  
     3  import (
     4  	"bytes"
     5  	_ "embed"
     6  	"errors"
     7  	"fmt"
     8  	"html/template"
     9  	"io"
    10  	"io/fs"
    11  	"log"
    12  	"os"
    13  	"path/filepath"
    14  
    15  	"github.com/99designs/gqlgen/api"
    16  	"github.com/99designs/gqlgen/codegen/config"
    17  	"github.com/99designs/gqlgen/graphql"
    18  	"github.com/99designs/gqlgen/internal/code"
    19  	"github.com/99designs/gqlgen/plugin/servergen"
    20  	"github.com/urfave/cli/v2"
    21  )
    22  
    23  //go:embed init-templates/schema.graphqls
    24  var schemaFileContent string
    25  
    26  //go:embed init-templates/gqlgen.yml.gotmpl
    27  var configFileTemplate string
    28  
    29  func getConfigFileContent(pkgName string) string {
    30  	var buf bytes.Buffer
    31  	if err := template.Must(template.New("gqlgen.yml").Parse(configFileTemplate)).Execute(&buf, pkgName); err != nil {
    32  		panic(err)
    33  	}
    34  	return buf.String()
    35  }
    36  
    37  func fileExists(filename string) bool {
    38  	_, err := os.Stat(filename)
    39  	return !errors.Is(err, fs.ErrNotExist)
    40  }
    41  
    42  func initFile(filename, contents string) error {
    43  	if err := os.MkdirAll(filepath.Dir(filename), 0o755); err != nil {
    44  		return fmt.Errorf("unable to create directory for file '%s': %w\n", filename, err)
    45  	}
    46  	if err := os.WriteFile(filename, []byte(contents), 0o644); err != nil {
    47  		return fmt.Errorf("unable to write file '%s': %w\n", filename, err)
    48  	}
    49  
    50  	return nil
    51  }
    52  
    53  var initCmd = &cli.Command{
    54  	Name:  "init",
    55  	Usage: "create a new gqlgen project",
    56  	Flags: []cli.Flag{
    57  		&cli.BoolFlag{Name: "verbose, v", Usage: "show logs"},
    58  		&cli.StringFlag{Name: "config, c", Usage: "the config filename", Value: "gqlgen.yml"},
    59  		&cli.StringFlag{Name: "server", Usage: "where to write the server stub to", Value: "server.go"},
    60  		&cli.StringFlag{Name: "schema", Usage: "where to write the schema stub to", Value: "graph/schema.graphqls"},
    61  	},
    62  	Action: func(ctx *cli.Context) error {
    63  		configFilename := ctx.String("config")
    64  		serverFilename := ctx.String("server")
    65  		schemaFilename := ctx.String("schema")
    66  
    67  		pkgName := code.ImportPathForDir(".")
    68  		if pkgName == "" {
    69  			return fmt.Errorf("unable to determine import path for current directory, you probably need to run 'go mod init' first")
    70  		}
    71  
    72  		// check schema and config don't already exist
    73  		for _, filename := range []string{configFilename, schemaFilename, serverFilename} {
    74  			if fileExists(filename) {
    75  				return fmt.Errorf("%s already exists", filename)
    76  			}
    77  		}
    78  		_, err := config.LoadConfigFromDefaultLocations()
    79  		if err == nil {
    80  			return fmt.Errorf("gqlgen.yml already exists in a parent directory\n")
    81  		}
    82  
    83  		// create config
    84  		fmt.Println("Creating", configFilename)
    85  		if err := initFile(configFilename, getConfigFileContent(pkgName)); err != nil {
    86  			return err
    87  		}
    88  
    89  		// create schema
    90  		fmt.Println("Creating", schemaFilename)
    91  
    92  		if err := initFile(schemaFilename, schemaFileContent); err != nil {
    93  			return err
    94  		}
    95  
    96  		// create the package directory with a temporary file so that go recognises it as a package
    97  		// and autobinding doesn't error out
    98  		tmpPackageNameFile := "graph/model/_tmp_gqlgen_init.go"
    99  		if err := initFile(tmpPackageNameFile, "package model"); err != nil {
   100  			return err
   101  		}
   102  		defer os.Remove(tmpPackageNameFile)
   103  
   104  		var cfg *config.Config
   105  		if cfg, err = config.LoadConfig(configFilename); err != nil {
   106  			panic(err)
   107  		}
   108  
   109  		fmt.Println("Creating", serverFilename)
   110  		fmt.Println("Generating...")
   111  		if err := api.Generate(cfg, api.AddPlugin(servergen.New(serverFilename))); err != nil {
   112  			return err
   113  		}
   114  
   115  		fmt.Printf("\nExec \"go run ./%s\" to start GraphQL server\n", serverFilename)
   116  		return nil
   117  	},
   118  }
   119  
   120  var generateCmd = &cli.Command{
   121  	Name:  "generate",
   122  	Usage: "generate a graphql server based on schema",
   123  	Flags: []cli.Flag{
   124  		&cli.BoolFlag{Name: "verbose, v", Usage: "show logs"},
   125  		&cli.StringFlag{Name: "config, c", Usage: "the config filename"},
   126  	},
   127  	Action: func(ctx *cli.Context) error {
   128  		var cfg *config.Config
   129  		var err error
   130  		if configFilename := ctx.String("config"); configFilename != "" {
   131  			cfg, err = config.LoadConfig(configFilename)
   132  			if err != nil {
   133  				return err
   134  			}
   135  		} else {
   136  			cfg, err = config.LoadConfigFromDefaultLocations()
   137  			if errors.Is(err, fs.ErrNotExist) {
   138  				cfg, err = config.LoadDefaultConfig()
   139  			}
   140  
   141  			if err != nil {
   142  				return err
   143  			}
   144  		}
   145  
   146  		if err = api.Generate(cfg); err != nil {
   147  			return err
   148  		}
   149  		return nil
   150  	},
   151  }
   152  
   153  var versionCmd = &cli.Command{
   154  	Name:  "version",
   155  	Usage: "print the version string",
   156  	Action: func(ctx *cli.Context) error {
   157  		fmt.Println(graphql.Version)
   158  		return nil
   159  	},
   160  }
   161  
   162  func main() {
   163  	app := cli.NewApp()
   164  	app.Name = "gqlgen"
   165  	app.Usage = generateCmd.Usage
   166  	app.Description = "This is a library for quickly creating strictly typed graphql servers in golang. See https://gqlgen.com/ for a getting started guide."
   167  	app.HideVersion = true
   168  	app.Flags = generateCmd.Flags
   169  	app.Version = graphql.Version
   170  	app.Before = func(context *cli.Context) error {
   171  		if context.Bool("verbose") {
   172  			log.SetFlags(0)
   173  		} else {
   174  			log.SetOutput(io.Discard)
   175  		}
   176  		return nil
   177  	}
   178  
   179  	app.Action = generateCmd.Action
   180  	app.Commands = []*cli.Command{
   181  		generateCmd,
   182  		initCmd,
   183  		versionCmd,
   184  	}
   185  
   186  	if err := app.Run(os.Args); err != nil {
   187  		fmt.Fprint(os.Stderr, err.Error()+"\n")
   188  		os.Exit(1)
   189  	}
   190  }