Add initialization command to setup new apps
This commit is contained in:
@ -7,6 +7,7 @@ import (
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"path"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
@ -31,20 +32,20 @@ type allowList struct {
|
||||
active bool
|
||||
}
|
||||
|
||||
func initAllowList(path string) {
|
||||
func initAllowList(cpath string) {
|
||||
_allowList = allowList{
|
||||
list: make(map[string]*allowItem),
|
||||
saveChan: make(chan *allowItem),
|
||||
active: true,
|
||||
}
|
||||
|
||||
if len(path) != 0 {
|
||||
fp := fmt.Sprintf("%s/allow.list", path)
|
||||
if len(cpath) != 0 {
|
||||
fp := path.Join(cpath, "allow.list")
|
||||
|
||||
if _, err := os.Stat(fp); err == nil {
|
||||
_allowList.filepath = fp
|
||||
} else if !os.IsNotExist(err) {
|
||||
panic(err)
|
||||
logger.Fatal().Err(err).Send()
|
||||
}
|
||||
}
|
||||
|
||||
@ -54,7 +55,7 @@ func initAllowList(path string) {
|
||||
if _, err := os.Stat(fp); err == nil {
|
||||
_allowList.filepath = fp
|
||||
} else if !os.IsNotExist(err) {
|
||||
panic(err)
|
||||
logger.Fatal().Err(err).Send()
|
||||
}
|
||||
}
|
||||
|
||||
@ -64,15 +65,25 @@ func initAllowList(path string) {
|
||||
if _, err := os.Stat(fp); err == nil {
|
||||
_allowList.filepath = fp
|
||||
} else if !os.IsNotExist(err) {
|
||||
panic(err)
|
||||
logger.Fatal().Err(err).Send()
|
||||
}
|
||||
}
|
||||
|
||||
if len(_allowList.filepath) == 0 {
|
||||
panic("allow.list not found")
|
||||
}
|
||||
if conf.UseAllowList {
|
||||
logger.Fatal().Msg("allow.list not found")
|
||||
}
|
||||
|
||||
_allowList.load()
|
||||
if len(cpath) == 0 {
|
||||
_allowList.filepath = "./config/allow.list"
|
||||
} else {
|
||||
_allowList.filepath = path.Join(cpath, "allow.list")
|
||||
}
|
||||
|
||||
logger.Warn().Msg("allow.list not found")
|
||||
} else {
|
||||
_allowList.load()
|
||||
}
|
||||
|
||||
go func() {
|
||||
for v := range _allowList.saveChan {
|
||||
@ -182,7 +193,7 @@ func (al *allowList) save(item *allowItem) {
|
||||
|
||||
f, err := os.Create(al.filepath)
|
||||
if err != nil {
|
||||
logger.Warn().Err(err).Msg("Failed to write allow list to file")
|
||||
logger.Warn().Err(err).Msgf("Failed to write allow list: %s", al.filepath)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -35,7 +35,7 @@ func jwtHandler(next http.HandlerFunc) http.HandlerFunc {
|
||||
case len(publicKeyFile) != 0:
|
||||
kd, err := ioutil.ReadFile(publicKeyFile)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
logger.Fatal().Err(err).Send()
|
||||
}
|
||||
|
||||
switch conf.Auth.JWT.PubKeyType {
|
||||
@ -51,7 +51,7 @@ func jwtHandler(next http.HandlerFunc) http.HandlerFunc {
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
logger.Fatal().Err(err).Send()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -28,13 +28,13 @@ func railsRedisHandler(next http.HandlerFunc) http.HandlerFunc {
|
||||
Dial: func() (redis.Conn, error) {
|
||||
c, err := redis.DialURL(conf.Auth.Rails.URL)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
logger.Fatal().Err(err).Send()
|
||||
}
|
||||
|
||||
pwd := conf.Auth.Rails.Password
|
||||
if len(pwd) != 0 {
|
||||
if _, err := c.Do("AUTH", pwd); err != nil {
|
||||
panic(err)
|
||||
logger.Fatal().Err(err).Send()
|
||||
}
|
||||
}
|
||||
return c, err
|
||||
|
17
serv/cmd.go
17
serv/cmd.go
@ -17,8 +17,6 @@ import (
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
//go:generate esc -o static.go -ignore \\.DS_Store -prefix ../web/build -private -pkg serv ../web/build
|
||||
|
||||
const (
|
||||
serverName = "Super Graph"
|
||||
|
||||
@ -42,11 +40,10 @@ var (
|
||||
migrateCmd *cobra.Command
|
||||
statusCmd *cobra.Command
|
||||
newMigrationCmd *cobra.Command
|
||||
initCmd *cobra.Command
|
||||
)
|
||||
|
||||
func Init() {
|
||||
var err error
|
||||
|
||||
rootCmd = &cobra.Command{
|
||||
Use: "super-graph",
|
||||
Short: "An instant high-performance GraphQL API. No code needed. https://supergraph.dev",
|
||||
@ -110,6 +107,13 @@ e.g. tern migrate -d last
|
||||
Run: cmdNewMigration,
|
||||
}
|
||||
|
||||
initCmd = &cobra.Command{
|
||||
Use: "init APP-NAME",
|
||||
Short: "Initialize a new application",
|
||||
Long: "Generate all the required files to start on a new Super Graph app",
|
||||
Run: cmdInit,
|
||||
}
|
||||
|
||||
logger = initLog()
|
||||
|
||||
rootCmd.Flags().StringVar(&confPath,
|
||||
@ -118,16 +122,13 @@ e.g. tern migrate -d last
|
||||
//cmdMigrate.Flags().StringVarP(&cliOptions.destinationVersion,
|
||||
// "destination", "d", "last", "destination migration version")
|
||||
|
||||
rootCmd.AddCommand(initCmd)
|
||||
rootCmd.AddCommand(servCmd)
|
||||
rootCmd.AddCommand(seedCmd)
|
||||
rootCmd.AddCommand(migrateCmd)
|
||||
rootCmd.AddCommand(statusCmd)
|
||||
rootCmd.AddCommand(newMigrationCmd)
|
||||
|
||||
if conf, err = initConf(); err != nil {
|
||||
logger.Fatal().Err(err).Msg("failed to read config")
|
||||
}
|
||||
|
||||
if err := rootCmd.Execute(); err != nil {
|
||||
logger.Fatal().Err(err).Send()
|
||||
}
|
||||
|
132
serv/cmd_init.go
Normal file
132
serv/cmd_init.go
Normal file
@ -0,0 +1,132 @@
|
||||
package serv
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
rice "github.com/GeertJohan/go.rice"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func cmdInit(cmd *cobra.Command, args []string) {
|
||||
if len(args) != 1 {
|
||||
cmd.Help()
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
tmpl := newTempl(map[string]string{
|
||||
"app_name": strings.Title(strings.Join(args, " ")),
|
||||
"app_name_slug": strings.ToLower(strings.Join(args, "_")),
|
||||
})
|
||||
|
||||
// Create app folder and add relevant files
|
||||
|
||||
name := args[0]
|
||||
appPath := path.Join("./", name)
|
||||
|
||||
ifNotExists(appPath, func(p string) error {
|
||||
return os.Mkdir(p, os.ModePerm)
|
||||
})
|
||||
|
||||
ifNotExists(path.Join(appPath, "seed.js"), func(p string) error {
|
||||
if v, err := tmpl.get("docker-compose.yml"); err == nil {
|
||||
return ioutil.WriteFile(p, v, 0644)
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
})
|
||||
|
||||
ifNotExists(path.Join(appPath, "docker-compose.yml"), func(p string) error {
|
||||
if v, err := tmpl.get("docker-compose.yml"); err == nil {
|
||||
return ioutil.WriteFile(p, v, 0644)
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
})
|
||||
|
||||
// Create app config folder and add relevant files
|
||||
|
||||
appConfigPath := path.Join(appPath, "config")
|
||||
|
||||
ifNotExists(appConfigPath, func(p string) error {
|
||||
return os.Mkdir(p, os.ModePerm)
|
||||
})
|
||||
|
||||
ifNotExists(path.Join(appConfigPath, "dev.yml"), func(p string) error {
|
||||
if v, err := tmpl.get("dev.yml"); err == nil {
|
||||
return ioutil.WriteFile(p, v, 0644)
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
})
|
||||
|
||||
ifNotExists(path.Join(appConfigPath, "prod.yml"), func(p string) error {
|
||||
if v, err := tmpl.get("prod.yml"); err == nil {
|
||||
return ioutil.WriteFile(p, v, 0644)
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
})
|
||||
|
||||
// Create app migrations folder and add relevant files
|
||||
|
||||
appMigrationsPath := path.Join(appConfigPath, "migrations")
|
||||
|
||||
ifNotExists(appMigrationsPath, func(p string) error {
|
||||
return os.Mkdir(p, os.ModePerm)
|
||||
})
|
||||
|
||||
ifNotExists(path.Join(appMigrationsPath, "100_init.sql"), func(p string) error {
|
||||
if v, err := tmpl.get("100_init.sql"); err == nil {
|
||||
return ioutil.WriteFile(p, v, 0644)
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
})
|
||||
|
||||
logger.Info().Msgf("app '%s' initialized", name)
|
||||
}
|
||||
|
||||
type Templ struct {
|
||||
*rice.Box
|
||||
data map[string]string
|
||||
}
|
||||
|
||||
func newTempl(data map[string]string) *Templ {
|
||||
return &Templ{rice.MustFindBox("../tmpl"), data}
|
||||
}
|
||||
|
||||
func (t *Templ) get(name string) ([]byte, error) {
|
||||
v := t.MustString(name)
|
||||
b := bytes.Buffer{}
|
||||
tm := template.Must(template.New(name).Parse(v))
|
||||
|
||||
if err := tm.Execute(&b, t.data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return b.Bytes(), nil
|
||||
}
|
||||
|
||||
func ifNotExists(filePath string, doFn func(string) error) {
|
||||
_, err := os.Stat(filePath)
|
||||
|
||||
if err == nil {
|
||||
logger.Info().Err(err).Msgf("create skipped '%s' exists", filePath)
|
||||
return
|
||||
}
|
||||
|
||||
if os.IsNotExist(err) == false {
|
||||
logger.Fatal().Err(err).Msgf("unable to check if '%s' exists", filePath)
|
||||
}
|
||||
|
||||
err = doFn(filePath)
|
||||
if err != nil {
|
||||
logger.Fatal().Err(err).Msgf("unable to create '%s'", filePath)
|
||||
}
|
||||
logger.Info().Msgf("created '%s'", filePath)
|
||||
}
|
@ -16,6 +16,11 @@ import (
|
||||
|
||||
func cmdSeed(cmd *cobra.Command, args []string) {
|
||||
var err error
|
||||
|
||||
if conf, err = initConf(); err != nil {
|
||||
logger.Fatal().Err(err).Msg("failed to read config")
|
||||
}
|
||||
|
||||
conf.UseAllowList = false
|
||||
|
||||
db, err = initDBPool(conf)
|
||||
|
@ -7,6 +7,10 @@ import (
|
||||
func cmdServ(cmd *cobra.Command, args []string) {
|
||||
var err error
|
||||
|
||||
if conf, err = initConf(); err != nil {
|
||||
logger.Fatal().Err(err).Msg("failed to read config")
|
||||
}
|
||||
|
||||
db, err = initDBPool(conf)
|
||||
if err != nil {
|
||||
logger.Fatal().Err(err).Msg("failed to connect to database")
|
||||
|
@ -40,6 +40,12 @@ func cmdNewMigration(cmd *cobra.Command, args []string) {
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
var err error
|
||||
|
||||
if conf, err = initConf(); err != nil {
|
||||
logger.Fatal().Err(err).Msg("failed to read config")
|
||||
}
|
||||
|
||||
name := args[0]
|
||||
|
||||
m, err := migrate.FindMigrations(conf.MigrationsPath)
|
||||
@ -64,10 +70,16 @@ func cmdNewMigration(cmd *cobra.Command, args []string) {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
logger.Info().Msgf("created migration '%s'\n", mpath)
|
||||
logger.Info().Msgf("created migration '%s'", mpath)
|
||||
}
|
||||
|
||||
func cmdMigrate(cmd *cobra.Command, args []string) {
|
||||
var err error
|
||||
|
||||
if conf, err = initConf(); err != nil {
|
||||
logger.Fatal().Err(err).Msg("failed to read config")
|
||||
}
|
||||
|
||||
conn, err := initDB(conf)
|
||||
if err != nil {
|
||||
logger.Fatal().Err(err).Msg("failed to connect to database")
|
||||
@ -157,6 +169,12 @@ func cmdMigrate(cmd *cobra.Command, args []string) {
|
||||
}
|
||||
|
||||
func cmdStatus(cmd *cobra.Command, args []string) {
|
||||
var err error
|
||||
|
||||
if conf, err = initConf(); err != nil {
|
||||
logger.Fatal().Err(err).Msg("failed to read config")
|
||||
}
|
||||
|
||||
conn, err := initDB(conf)
|
||||
if err != nil {
|
||||
logger.Fatal().Err(err).Msg("failed to connect to database")
|
||||
|
@ -30,7 +30,7 @@ func initPreparedList() {
|
||||
for k, v := range _allowList.list {
|
||||
err := prepareStmt(k, v.gql, v.vars)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
logger.Fatal().Err(err).Send()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -161,7 +161,7 @@ func Do(log func(string, ...interface{}), additional ...dir) error {
|
||||
func ReExec() {
|
||||
err := syscall.Exec(binSelf, append([]string{binSelf}, os.Args[1:]...), os.Environ())
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("cannot restart: %v", err))
|
||||
logger.Fatal().Err(err).Msg("cannot restart")
|
||||
}
|
||||
}
|
||||
|
||||
|
11
serv/serv.go
11
serv/serv.go
@ -9,6 +9,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
rice "github.com/GeertJohan/go.rice"
|
||||
"github.com/dosco/super-graph/psql"
|
||||
"github.com/dosco/super-graph/qcode"
|
||||
)
|
||||
@ -38,22 +39,22 @@ func initCompilers(c *config) (*qcode.Compiler, *psql.Compiler, error) {
|
||||
return qc, pc, nil
|
||||
}
|
||||
|
||||
func initWatcher(path string) {
|
||||
func initWatcher(cpath string) {
|
||||
if conf.WatchAndReload == false {
|
||||
return
|
||||
}
|
||||
|
||||
var d dir
|
||||
if len(path) == 0 || path == "./" {
|
||||
if len(cpath) == 0 || cpath == "./" {
|
||||
d = Dir("./config", ReExec)
|
||||
} else {
|
||||
d = Dir(path, ReExec)
|
||||
d = Dir(cpath, ReExec)
|
||||
}
|
||||
|
||||
go func() {
|
||||
err := Do(logger.Printf, d)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
logger.Fatal().Err(err).Send()
|
||||
}
|
||||
}()
|
||||
}
|
||||
@ -109,7 +110,7 @@ func routeHandler() http.Handler {
|
||||
|
||||
mux.Handle("/api/v1/graphql", withAuth(apiv1Http))
|
||||
if conf.WebUI {
|
||||
mux.Handle("/", http.FileServer(_escFS(false)))
|
||||
mux.Handle("/", http.FileServer(rice.MustFindBox("../web/build").HTTPBox()))
|
||||
}
|
||||
|
||||
fn := func(w http.ResponseWriter, r *http.Request) {
|
||||
|
Reference in New Issue
Block a user