352 lines
9.2 KiB
Go
352 lines
9.2 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"embed"
|
|
_ "embed"
|
|
"fmt"
|
|
"github.com/urfave/cli/v2"
|
|
"golang.org/x/text/cases"
|
|
"golang.org/x/text/language"
|
|
vue_gen "masonry/vue-gen"
|
|
"os"
|
|
"os/exec"
|
|
"runtime"
|
|
"strings"
|
|
"text/template"
|
|
)
|
|
|
|
//go:embed templates/proto/application.proto.tmpl
|
|
var protoTemplateSrc string
|
|
|
|
//go:embed templates/backend/main.go.tmpl
|
|
var mainGoTemplateSrc string
|
|
|
|
//go:embed templates/backend/gitignore.tmpl
|
|
var gitignoreTemplateSrc string
|
|
|
|
//go:embed proto_include/*
|
|
var protoInclude embed.FS
|
|
|
|
func createCmd() *cli.Command {
|
|
return &cli.Command{
|
|
Name: "create",
|
|
Aliases: []string{"c"},
|
|
Usage: "Create a new app in a directory with the given name",
|
|
Description: "This command will create a new folder with the given name and generate a new app in that folder.",
|
|
Category: "generator",
|
|
Flags: []cli.Flag{
|
|
&cli.StringFlag{
|
|
Name: "name",
|
|
Usage: "The name of the app to create",
|
|
Required: true,
|
|
Aliases: []string{"n"},
|
|
},
|
|
},
|
|
Action: func(c *cli.Context) error {
|
|
applicationName := c.String("name")
|
|
|
|
fmt.Printf("Creating app: %v\n", applicationName)
|
|
|
|
// make a directory with the given name from the working directory
|
|
err := os.Mkdir(applicationName, 0755)
|
|
if err != nil {
|
|
return fmt.Errorf("error creating app directory | %w", err)
|
|
}
|
|
|
|
// generate the app in the new directory
|
|
// cd into the new directory
|
|
err = os.Chdir(applicationName)
|
|
if err != nil {
|
|
return fmt.Errorf("error changing directory | %w", err)
|
|
}
|
|
|
|
// initialize a go module
|
|
cmd := exec.Command("go", "mod", "init", applicationName)
|
|
err = cmd.Run()
|
|
if err != nil {
|
|
return fmt.Errorf("error initializing go module | %w", err)
|
|
}
|
|
|
|
// create a directory to proto files
|
|
err = os.Mkdir("proto", 0755)
|
|
if err != nil {
|
|
return fmt.Errorf("error creating proto directory | %w", err)
|
|
}
|
|
|
|
// create a directory to store the generated code
|
|
err = os.Mkdir("gen", 0755)
|
|
if err != nil {
|
|
return fmt.Errorf("error creating gen directory | %w", err)
|
|
}
|
|
|
|
// create a directory for generated go code
|
|
err = os.Mkdir("gen/go", 0755)
|
|
if err != nil {
|
|
return fmt.Errorf("error creating gen/go directory | %w", err)
|
|
}
|
|
|
|
// create a directory for generated openapi code
|
|
err = os.Mkdir("gen/openapi", 0755)
|
|
if err != nil {
|
|
return fmt.Errorf("error creating gen/openapi directory | %w", err)
|
|
}
|
|
|
|
// create a main.go file
|
|
mainFile, err := os.Create("main.go")
|
|
if err != nil {
|
|
return fmt.Errorf("error creating main.go file | %w", err)
|
|
}
|
|
defer mainFile.Close()
|
|
|
|
titleMaker := cases.Title(language.English)
|
|
|
|
// render the main.go file from the template
|
|
goTemplate := template.Must(template.New("main").Parse(mainGoTemplateSrc))
|
|
err = goTemplate.Execute(mainFile, map[string]string{"AppName": strings.ToLower(applicationName), "AppNameCaps": titleMaker.String(applicationName)})
|
|
if err != nil {
|
|
return fmt.Errorf("error rendering main.go file | %w", err)
|
|
}
|
|
|
|
// create a gitignore file
|
|
gitignoreFile, err := os.Create(".gitignore")
|
|
if err != nil {
|
|
return fmt.Errorf("error creating gitignore file | %w", err)
|
|
}
|
|
defer gitignoreFile.Close()
|
|
|
|
// render the gitignore file from the template
|
|
gitignoreTemplate := template.Must(template.New("gitignore").Parse(gitignoreTemplateSrc))
|
|
err = gitignoreTemplate.Execute(gitignoreFile, nil)
|
|
if err != nil {
|
|
return fmt.Errorf("error rendering gitignore file | %w", err)
|
|
}
|
|
|
|
// create a proto file
|
|
protoFile, err := os.Create("proto/service.proto")
|
|
if err != nil {
|
|
return fmt.Errorf("error creating proto file | %w", err)
|
|
}
|
|
defer protoFile.Close()
|
|
|
|
// render the proto file from the template
|
|
t := template.Must(template.New("proto").Parse(protoTemplateSrc))
|
|
err = t.Execute(protoFile, map[string]string{"AppName": strings.ToLower(applicationName), "AppNameCaps": titleMaker.String(applicationName), "ObjName": "Product"})
|
|
if err != nil {
|
|
return fmt.Errorf("error rendering proto file | %w", err)
|
|
}
|
|
|
|
err = os.CopyFS("./", protoInclude)
|
|
if err != nil {
|
|
return fmt.Errorf("error copying proto include files | %w", err)
|
|
}
|
|
|
|
// set up the webapp
|
|
err = setupWebapp("webapp") // since the app is already in its own named folder, we name it webapp
|
|
if err != nil {
|
|
return fmt.Errorf("error setting up webapp | %w", err)
|
|
}
|
|
|
|
return nil
|
|
},
|
|
}
|
|
}
|
|
|
|
func generateCmd() *cli.Command {
|
|
return &cli.Command{
|
|
Name: "generate",
|
|
Aliases: []string{"g"},
|
|
Usage: "Generate code from proto files",
|
|
Category: "generator",
|
|
Description: "This command will generate code from the proto files in the proto directory and place them in a language folder in the gen folder.",
|
|
Action: func(c *cli.Context) error {
|
|
fmt.Println("Generating code...")
|
|
|
|
protocArgs := []string{
|
|
"-I",
|
|
".",
|
|
"--go_out",
|
|
"gen/go",
|
|
"--go-grpc_out",
|
|
"gen/go",
|
|
"--go-grpc_opt=require_unimplemented_servers=false",
|
|
"--gorm_out",
|
|
"gen/go",
|
|
"--grpc-gateway_out",
|
|
"gen/go",
|
|
"--grpc-gateway_opt",
|
|
"logtostderr=true",
|
|
"--openapiv2_out",
|
|
"gen/openapi",
|
|
"--openapiv2_opt",
|
|
"logtostderr=true",
|
|
"--proto_path=./proto_include",
|
|
"proto/*.proto",
|
|
}
|
|
|
|
// generate go code
|
|
cmd := exec.Command(
|
|
"protoc",
|
|
protocArgs...,
|
|
)
|
|
cmd.Stdout = os.Stdout
|
|
cmd.Stderr = os.Stderr
|
|
err := cmd.Run()
|
|
if err != nil {
|
|
|
|
var buff bytes.Buffer
|
|
cmd.Stderr = &buff
|
|
fmt.Println(buff.String())
|
|
|
|
return fmt.Errorf("error generating go code | %w", err)
|
|
}
|
|
|
|
// Generate ts code
|
|
// if webapp folder is present, generate typescript code
|
|
if _, err := os.Stat("webapp"); err == nil {
|
|
err = os.Chdir("webapp")
|
|
if err != nil {
|
|
return fmt.Errorf("error changing directory to webapp | %w", err)
|
|
}
|
|
|
|
cmd = exec.Command("npx",
|
|
"openapi-typescript-codegen",
|
|
"--input",
|
|
"../gen/openapi/proto/service.swagger.json",
|
|
"--output",
|
|
"src/generated",
|
|
"--client",
|
|
"fetch",
|
|
)
|
|
cmd.Stdout = os.Stdout
|
|
cmd.Stderr = os.Stderr
|
|
err = cmd.Run()
|
|
if err != nil {
|
|
return fmt.Errorf("error generating typescript code | %w", err)
|
|
}
|
|
|
|
// make sure src/generated-sample-components exists
|
|
err = os.Mkdir("src/generated-sample-components", 0755)
|
|
if err != nil {
|
|
return fmt.Errorf("error creating src/generated-components directory | %w", err)
|
|
}
|
|
|
|
// generate vue components
|
|
err = vue_gen.GenVueFromSwagger("../gen/openapi/proto/service.swagger.json", "src/generated-sample-components")
|
|
if err != nil {
|
|
return fmt.Errorf("error generating vue components | %w", err)
|
|
}
|
|
|
|
cmd := exec.Command("npm", "install", "@masonitestudios/dynamic-vue")
|
|
err = cmd.Run()
|
|
if err != nil {
|
|
return fmt.Errorf("error installing @masonitestudios/dynamic-vue | %w", err)
|
|
}
|
|
|
|
err = os.Chdir("..")
|
|
if err != nil {
|
|
return fmt.Errorf("error changing directory back to root | %w", err)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
},
|
|
}
|
|
}
|
|
|
|
func webappCmd() *cli.Command {
|
|
return &cli.Command{
|
|
Name: "webapp",
|
|
Aliases: []string{"w"},
|
|
Flags: []cli.Flag{
|
|
&cli.StringFlag{
|
|
Name: "name",
|
|
Aliases: []string{"n"},
|
|
Usage: "The name of the webapp to create, this will be the name of the directory",
|
|
Required: true,
|
|
},
|
|
},
|
|
Usage: "Set up a webapp",
|
|
Description: "This command will set up a webapp ",
|
|
Category: "generator",
|
|
Action: func(c *cli.Context) error {
|
|
fmt.Println("Setting up webapp named: ", c.String("name"))
|
|
name := c.String("name")
|
|
|
|
err := setupWebapp(name)
|
|
if err != nil {
|
|
return fmt.Errorf("error setting up webapp | %w", err)
|
|
}
|
|
|
|
return nil
|
|
},
|
|
}
|
|
}
|
|
|
|
func tailwindCmd() *cli.Command {
|
|
return &cli.Command{
|
|
Name: "tailwind",
|
|
Aliases: []string{"t"},
|
|
Usage: "Set up tailwindcss in a vite webapp, if you built using masonry then this is already done for you",
|
|
Action: func(c *cli.Context) error {
|
|
fmt.Println("Setting up tailwindcss")
|
|
err := setupTailwind()
|
|
if err != nil {
|
|
return fmt.Errorf("error setting up tailwindcss | %w", err)
|
|
}
|
|
|
|
return nil
|
|
},
|
|
}
|
|
}
|
|
|
|
func setupCmd() *cli.Command {
|
|
return &cli.Command{
|
|
Name: "setup",
|
|
Aliases: []string{"s"},
|
|
Usage: "Set up masonry, makes sure all dependencies are installed so Masonry can do its job.",
|
|
Action: func(c *cli.Context) error {
|
|
fmt.Printf("Running on %s/%s\n", runtime.GOOS, runtime.GOARCH)
|
|
|
|
if err := ensureDependencies(); err != nil {
|
|
return fmt.Errorf("error ensuring dependencies | %w", err)
|
|
}
|
|
return nil
|
|
},
|
|
}
|
|
}
|
|
|
|
func vueGenCmd() *cli.Command {
|
|
return &cli.Command{
|
|
Name: "vuegen",
|
|
Aliases: []string{"vg"},
|
|
Usage: "Generate vue components based on a swagger file",
|
|
Flags: []cli.Flag{
|
|
&cli.StringFlag{
|
|
Name: "input",
|
|
Aliases: []string{"i"},
|
|
Usage: "The input swagger file",
|
|
Required: true,
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "output",
|
|
Aliases: []string{"o"},
|
|
Usage: "The output directory",
|
|
Required: true,
|
|
},
|
|
},
|
|
Action: func(c *cli.Context) error {
|
|
fmt.Println("Generating vue components")
|
|
input := c.String("input")
|
|
output := c.String("output")
|
|
|
|
err := vue_gen.GenVueFromSwagger(input, output)
|
|
if err != nil {
|
|
return fmt.Errorf("error generating vue components | %w", err)
|
|
}
|
|
|
|
return nil
|
|
},
|
|
}
|
|
}
|