diff --git a/cmd/create.go b/cmd/create.go index 3e0875400..6b25fa4d3 100644 --- a/cmd/create.go +++ b/cmd/create.go @@ -4,8 +4,10 @@ import ( "log" "os" "path" + "sync" "github.com/commitdev/commit0/internal/templator" + "github.com/commitdev/commit0/internal/util" "github.com/gobuffalo/packr/v2" "github.com/spf13/cobra" ) @@ -24,23 +26,12 @@ func Create(projectName string, outDir string, t *templator.Templator) string { } else if err != nil { log.Fatalf("Error creating root: %v ", err) } + var wg sync.WaitGroup - commit0ConfigPath := path.Join(rootDir, "commit0.yml") - log.Printf("%s", commit0ConfigPath) - - f, err := os.Create(commit0ConfigPath) - if err != nil { - log.Printf("Error creating commit0 config: %v", err) - } - t.Commit0.Execute(f, projectName) - - gitIgnorePath := path.Join(rootDir, ".gitignore") - f, err = os.Create(gitIgnorePath) - if err != nil { - log.Printf("Error creating commit0 config: %v", err) - } - t.GitIgnore.Execute(f, projectName) + util.TemplateFileIfDoesNotExist(rootDir, "commit0.yml", t.Commit0, &wg, projectName) + util.TemplateFileIfDoesNotExist(rootDir, ".gitignore", t.GitIgnore, &wg, projectName) + wg.Wait() return rootDir } diff --git a/cmd/generate.go b/cmd/generate.go index d51eed7d7..3ae64c052 100644 --- a/cmd/generate.go +++ b/cmd/generate.go @@ -2,6 +2,7 @@ package cmd import ( "log" + "sync" "github.com/commitdev/commit0/internal/config" "github.com/commitdev/commit0/internal/generate/docker" @@ -10,6 +11,7 @@ import ( "github.com/commitdev/commit0/internal/generate/proto" "github.com/commitdev/commit0/internal/generate/react" "github.com/commitdev/commit0/internal/templator" + "github.com/commitdev/commit0/internal/util" "github.com/gobuffalo/packr/v2" "github.com/spf13/cobra" ) @@ -47,20 +49,26 @@ var generateCmd = &cobra.Command{ cfg.Language = language cfg.Print() + var wg sync.WaitGroup switch language { case Go: - proto.Generate(t, cfg) - golang.Generate(t, cfg) - docker.GenerateGoAppDockerFile(t, cfg) - docker.GenerateGoDockerCompose(t, cfg) + proto.Generate(t, cfg, &wg) + golang.Generate(t, cfg, &wg) + + docker.GenerateGoAppDockerFile(t, cfg, &wg) + docker.GenerateGoDockerCompose(t, cfg, &wg) case React: - react.Generate(t, cfg) + react.Generate(t, cfg, &wg) } + util.TemplateFileIfDoesNotExist("", "README.md", t.Readme, &wg, cfg) + if cfg.Network.Http.Enabled { - http.GenerateHttpGW(t, cfg) - docker.GenerateGoHttpGWDockerFile(t, cfg) + http.GenerateHTTPGW(t, cfg, &wg) + docker.GenerateGoHTTPGWDockerFile(t, cfg, &wg) } + + wg.Wait() }, } diff --git a/internal/generate/docker/generate.go b/internal/generate/docker/generate.go index 4e2ab613d..932acc204 100644 --- a/internal/generate/docker/generate.go +++ b/internal/generate/docker/generate.go @@ -1,19 +1,21 @@ package docker import ( + "sync" + "github.com/commitdev/commit0/internal/config" "github.com/commitdev/commit0/internal/templator" "github.com/commitdev/commit0/internal/util" ) -func GenerateGoAppDockerFile(templator *templator.Templator, config *config.Commit0Config) { - util.TemplateFileIfDoesNotExist("docker/app", "Dockerfile", templator.Docker.ApplicationDocker, config) +func GenerateGoAppDockerFile(templator *templator.Templator, config *config.Commit0Config, wg *sync.WaitGroup) { + util.TemplateFileIfDoesNotExist("docker/app", "Dockerfile", templator.Docker.ApplicationDocker, wg, config) } -func GenerateGoHttpGWDockerFile(templator *templator.Templator, config *config.Commit0Config) { - util.TemplateFileIfDoesNotExist("docker/http", "Dockerfile", templator.Docker.HttpGatewayDocker, config) +func GenerateGoHTTPGWDockerFile(templator *templator.Templator, config *config.Commit0Config, wg *sync.WaitGroup) { + util.TemplateFileIfDoesNotExist("docker/http", "Dockerfile", templator.Docker.HttpGatewayDocker, wg, config) } -func GenerateGoDockerCompose(templator *templator.Templator, config *config.Commit0Config) { - util.TemplateFileIfDoesNotExist("", "docker-compose.yml", templator.Docker.DockerCompose, config) +func GenerateGoDockerCompose(templator *templator.Templator, config *config.Commit0Config, wg *sync.WaitGroup) { + util.TemplateFileIfDoesNotExist("", "docker-compose.yml", templator.Docker.DockerCompose, wg, config) } diff --git a/internal/generate/golang/generate.go b/internal/generate/golang/generate.go index 88b0eed0d..87ce8b8df 100644 --- a/internal/generate/golang/generate.go +++ b/internal/generate/golang/generate.go @@ -3,46 +3,22 @@ package golang import ( "fmt" "log" - "os" + "path/filepath" + "sync" "github.com/commitdev/commit0/internal/config" "github.com/commitdev/commit0/internal/templator" "github.com/commitdev/commit0/internal/util" ) -func Generate(templator *templator.Templator, config *config.Commit0Config) { - GenerateGoMain(templator, config) - GenerateGoMod(templator, config) - GenerateHealthServer(templator, config) - GenerateServers(templator, config) +func Generate(templator *templator.Templator, config *config.Commit0Config, wg *sync.WaitGroup) { + util.TemplateFileIfDoesNotExist("", "main.go", templator.Go.GoMain, wg, config) + util.TemplateFileIfDoesNotExist("", "go.mod", templator.Go.GoMod, wg, config) + util.TemplateFileIfDoesNotExist("server/health", "health.go", templator.Go.GoHealthServer, wg, config) + GenerateServers(templator, config, wg) } -func GenerateGoMain(templator *templator.Templator, config *config.Commit0Config) { - if _, err := os.Stat("main.go"); os.IsNotExist(err) { - - f, err := os.Create("main.go") - - if err != nil { - log.Printf("Error: %v", err) - } - - templator.Go.GoMain.Execute(f, config) - } else { - log.Printf("main.go already exists. skipping.") - } -} - -func GenerateGoMod(templator *templator.Templator, config *config.Commit0Config) { - f, err := os.Create("go.mod") - - if err != nil { - log.Printf("Error: %v", err) - } - - templator.Go.GoMod.Execute(f, config) -} - -func GenerateServers(templator *templator.Templator, config *config.Commit0Config) { +func GenerateServers(templator *templator.Templator, config *config.Commit0Config, wg *sync.WaitGroup) { serverDirPath := "server" err := util.CreateDirIfDoesNotExist(serverDirPath) if err != nil { @@ -50,23 +26,8 @@ func GenerateServers(templator *templator.Templator, config *config.Commit0Confi } for _, s := range config.Services { - serverLibPath := fmt.Sprintf("%s/%s", serverDirPath, s.Name) - err := os.Mkdir(serverLibPath, os.ModePerm) - if os.IsExist(err) { - log.Printf("%s server exists skipping.", s.Name) - continue - } - log.Printf("generating %s", s.Name) - if err != nil { - log.Printf("Error generating server: %v", err) - } - - serverFilePath := fmt.Sprintf("%s/%s.go", serverLibPath, s.Name) - f, err := os.Create(serverFilePath) - - if err != nil { - log.Printf("Error: %v", err) - } + path := filepath.Join("server", s.Name) + file := fmt.Sprintf("%s.go", s.Name) data := map[string]string{ "ProjectName": config.Name, @@ -74,30 +35,7 @@ func GenerateServers(templator *templator.Templator, config *config.Commit0Confi "GitRepo": config.GitRepo, } - templator.Go.GoServer.Execute(f, data) - } - -} - -func GenerateHealthServer(templator *templator.Templator, config *config.Commit0Config) { - serverDirPath := "server" - err := util.CreateDirIfDoesNotExist(serverDirPath) - if err != nil { - log.Printf("Error creating server path: %v", err) - } - - serverLibPath := fmt.Sprintf("%s/%s", serverDirPath, "health") - err = util.CreateDirIfDoesNotExist(serverLibPath) - if err != nil { - log.Printf("Error generating server: %v", err) - } - - serverFilePath := fmt.Sprintf("%s/%s.go", serverLibPath, "health") - f, err := os.Create(serverFilePath) - - if err != nil { - log.Printf("Error: %v", err) + util.TemplateFileIfDoesNotExist(path, file, templator.Go.GoServer, wg, data) } - templator.Go.GoHealthServer.Execute(f, config) } diff --git a/internal/generate/http/generate.go b/internal/generate/http/generate.go index 02da1a483..06afe36c4 100644 --- a/internal/generate/http/generate.go +++ b/internal/generate/http/generate.go @@ -1,11 +1,13 @@ package http import ( + "sync" + "github.com/commitdev/commit0/internal/config" "github.com/commitdev/commit0/internal/templator" "github.com/commitdev/commit0/internal/util" ) -func GenerateHttpGW(templator *templator.Templator, config *config.Commit0Config) { - util.TemplateFileAndOverwrite("http", "main.go", templator.Go.GoHttpGW, config) +func GenerateHTTPGW(templator *templator.Templator, config *config.Commit0Config, wg *sync.WaitGroup) { + util.TemplateFileAndOverwrite("http", "main.go", templator.Go.GoHTTPGW, wg, config) } diff --git a/internal/generate/proto/generate.go b/internal/generate/proto/generate.go index 838e7f60b..3eaaad8c5 100644 --- a/internal/generate/proto/generate.go +++ b/internal/generate/proto/generate.go @@ -4,81 +4,31 @@ import ( "bytes" "fmt" "log" - "os" "os/exec" + "sync" "github.com/commitdev/commit0/internal/config" "github.com/commitdev/commit0/internal/templator" "github.com/commitdev/commit0/internal/util" ) -func Generate(templator *templator.Templator, config *config.Commit0Config) { - GenerateIDLMakefile(templator, config) - GenerateProtoHealth(templator, config) - GenerateServiceProtobufFiles(templator, config) - GenerateProtoServiceLibs(config) - GenerateGoModIDL(templator, config) -} - -func GenerateGoModIDL(templator *templator.Templator, config *config.Commit0Config) { +func Generate(templator *templator.Templator, config *config.Commit0Config, wg *sync.WaitGroup) { idlPath := fmt.Sprintf("%s-idl", config.Name) - idlOutput := fmt.Sprintf("%s/go.mod", idlPath) - err := util.CreateDirIfDoesNotExist(idlPath) - f, err := os.Create(idlOutput) - - if err != nil { - log.Printf("Error: %v", err) - } - - templator.Go.GoModIDL.Execute(f, config) -} - -func GenerateIDLMakefile(templator *templator.Templator, config *config.Commit0Config) { - makeFilePath := fmt.Sprintf("%s-idl", config.Name) - makeFileOutput := fmt.Sprintf("%s/Makefile", makeFilePath) + idlHealthPath := fmt.Sprintf("%s/proto/health", idlPath) - err := util.CreateDirIfDoesNotExist(makeFilePath) - if err != nil { - log.Printf("Error generating prototool config: %v", err) - } + util.TemplateFileIfDoesNotExist(idlPath, "go.mod", templator.Go.GoModIDL, wg, config) + util.TemplateFileIfDoesNotExist(idlPath, "Makefile", templator.MakefileTemplate, wg, config) + GenerateServiceProtobufFiles(templator, config, wg) + util.TemplateFileIfDoesNotExist(idlHealthPath, "health.proto", templator.ProtoHealthTemplate, wg, config) - f, err := os.Create(makeFileOutput) - if err != nil { - log.Printf("Error: %v", err) - } - templator.MakefileTemplate.Execute(f, config) -} - -func GenerateProtoHealth(templator *templator.Templator, config *config.Commit0Config) { - protoHealthPath := fmt.Sprintf("%s-idl/proto/health", config.Name) - protoHealthOutput := fmt.Sprintf("%s/health.proto", protoHealthPath) - - err := util.CreateDirIfDoesNotExist(protoHealthPath) - if err != nil { - log.Printf("Error: %v", err) - } - - f, err := os.Create(protoHealthOutput) - if err != nil { - log.Printf("Error: %v", err) - } - - templator.ProtoHealthTemplate.Execute(f, config) + GenerateProtoServiceLibs(config) } -func GenerateServiceProtobufFiles(templator *templator.Templator, cfg *config.Commit0Config) { +func GenerateServiceProtobufFiles(templator *templator.Templator, cfg *config.Commit0Config, wg *sync.WaitGroup) { protoPath := fmt.Sprintf("%s-idl/proto", cfg.Name) for _, s := range cfg.Services { serviceProtoDir := fmt.Sprintf("%s/%s", protoPath, s.Name) - err := os.Mkdir(serviceProtoDir, os.ModePerm) - if os.IsExist(err) { - log.Printf("%s service proto exists skipping.", s.Name) - continue - } - - serviceProtoFilePath := fmt.Sprintf("%s/%s.proto", serviceProtoDir, s.Name) - - f, err := os.Create(serviceProtoFilePath) + file := fmt.Sprintf("%s.proto", s.Name) data := struct { *config.Commit0Config @@ -88,9 +38,8 @@ func GenerateServiceProtobufFiles(templator *templator.Templator, cfg *config.Co s.Name, } - templator.ProtoServiceTemplate.Execute(f, data) + util.TemplateFileIfDoesNotExist(serviceProtoDir, file, templator.ProtoServiceTemplate, wg, data) } - } func GenerateProtoServiceLibs(config *config.Commit0Config) { diff --git a/internal/generate/react/generate.go b/internal/generate/react/generate.go index 289206623..15dff478b 100644 --- a/internal/generate/react/generate.go +++ b/internal/generate/react/generate.go @@ -1,10 +1,12 @@ package react import ( + "sync" + "github.com/commitdev/commit0/internal/config" "github.com/commitdev/commit0/internal/templator" ) -func Generate(templator *templator.Templator, config *config.Commit0Config) { - templator.React.TemplateFiles(config, false) +func Generate(templator *templator.Templator, config *config.Commit0Config, wg *sync.WaitGroup) { + templator.React.TemplateFiles(config, false, wg) } diff --git a/internal/templator/templator.go b/internal/templator/templator.go index 9f053e655..2369164ab 100644 --- a/internal/templator/templator.go +++ b/internal/templator/templator.go @@ -3,6 +3,7 @@ package templator import ( "path/filepath" "strings" + "sync" "text/template" "github.com/commitdev/commit0/internal/config" @@ -11,6 +12,7 @@ import ( "github.com/gobuffalo/packr/v2/file" ) +// DockerTemplator contains the templates relevent to docker type DockerTemplator struct { ApplicationDocker *template.Template HttpGatewayDocker *template.Template @@ -18,18 +20,21 @@ type DockerTemplator struct { DockerCompose *template.Template } +// GoTemplator contains the templates relevant to a go project type GoTemplator struct { GoMain *template.Template GoMod *template.Template GoModIDL *template.Template GoServer *template.Template GoHealthServer *template.Template - GoHttpGW *template.Template + GoHTTPGW *template.Template } +// Templator contains all the templates type Templator struct { Commit0 *template.Template GitIgnore *template.Template + Readme *template.Template MakefileTemplate *template.Template ProtoHealthTemplate *template.Template ProtoServiceTemplate *template.Template @@ -39,105 +44,69 @@ type Templator struct { } func NewTemplator(box *packr.Box) *Templator { - makeFileTemplateSource, _ := box.FindString("proto/makefile.tmpl") - makeFileTemplate, _ := template.New("ProtoToolTemplate").Parse(makeFileTemplateSource) - - protoHealthTemplateSource, _ := box.FindString("proto/health_proto.tmpl") - protoHealthTemplate, _ := template.New("ProtoHealthTemplate").Parse(protoHealthTemplateSource) - - protoServiceTemplateSource, _ := box.FindString("proto/service_proto.tmpl") - protoServiceTemplate, _ := template.New("ProtoServiceTemplate").Funcs(util.FuncMap).Parse(protoServiceTemplateSource) - return &Templator{ - MakefileTemplate: makeFileTemplate, - ProtoHealthTemplate: protoHealthTemplate, - ProtoServiceTemplate: protoServiceTemplate, + MakefileTemplate: NewSingleFileTemplator(box, "proto/makefile.tmpl"), + ProtoHealthTemplate: NewSingleFileTemplator(box, "proto/health_proto.tmpl"), + ProtoServiceTemplate: NewSingleFileTemplator(box, "proto/service_proto.tmpl"), Go: NewGoTemplator(box), - Commit0: NewCommit0Templator(box), - GitIgnore: NewGitIgnoreTemplator(box), + Commit0: NewSingleFileTemplator(box, "commit0/commit0.tmpl"), + GitIgnore: NewSingleFileTemplator(box, "util/gitignore.tmpl"), + Readme: NewSingleFileTemplator(box, "util/README.tmpl"), Docker: NewDockerFileTemplator(box), React: NewDirectoryTemplator(box, "react"), } } func NewGoTemplator(box *packr.Box) *GoTemplator { - goServerTemplateSource, _ := box.FindString("golang/server.tmpl") - goServerTemplate, _ := template.New("GoServerTemplate").Funcs(util.FuncMap).Parse(goServerTemplateSource) - - goHealthTemplateSource, _ := box.FindString("golang/health_server.tmpl") - goHealthServerTemplate, _ := template.New("GoHealthServerTemplate").Parse(goHealthTemplateSource) - - goModTemplateSource, _ := box.FindString("golang/go_mod.tmpl") - goModTemplate, _ := template.New("GoModTemplate").Parse(goModTemplateSource) - - goModIDLTemplateSource, _ := box.FindString("golang/go_mod_idl.tmpl") - goModIDLTemplate, _ := template.New("GoModTemplate").Parse(goModIDLTemplateSource) - - goMainTemplateSource, _ := box.FindString("golang/main.tmpl") - goMainTemplate, _ := template.New("GoMainTemplate").Funcs(util.FuncMap).Parse(goMainTemplateSource) - - goHttpTemplateSource, _ := box.FindString("golang/http_gw.tmpl") - goHttpTemplate, _ := template.New("GoHttpGWTemplate").Funcs(util.FuncMap).Parse(goHttpTemplateSource) - return &GoTemplator{ - GoMain: goMainTemplate, - GoMod: goModTemplate, - GoModIDL: goModIDLTemplate, - GoServer: goServerTemplate, - GoHealthServer: goHealthServerTemplate, - GoHttpGW: goHttpTemplate, + GoMain: NewSingleFileTemplator(box, "golang/main.tmpl"), + GoMod: NewSingleFileTemplator(box, "golang/go_mod.tmpl"), + GoModIDL: NewSingleFileTemplator(box, "golang/go_mod_idl.tmpl"), + GoServer: NewSingleFileTemplator(box, "golang/server.tmpl"), + GoHealthServer: NewSingleFileTemplator(box, "golang/health_server.tmpl"), + GoHTTPGW: NewSingleFileTemplator(box, "golang/http_gw.tmpl"), } } -func NewCommit0Templator(box *packr.Box) *template.Template { - templateSource, _ := box.FindString("commit0/commit0.tmpl") - template, _ := template.New("Commit0Template").Funcs(util.FuncMap).Parse(templateSource) - - return template -} - -func NewGitIgnoreTemplator(box *packr.Box) *template.Template { - templateSource, _ := box.FindString("util/gitignore.tmpl") - template, _ := template.New("GitIgnore").Parse(templateSource) - return template -} - func NewDockerFileTemplator(box *packr.Box) *DockerTemplator { - appTemplateSource, _ := box.FindString("docker/dockerfile_app.tmpl") - appTemplate, _ := template.New("AppDockerfile").Parse(appTemplateSource) - - httpTemplateSource, _ := box.FindString("docker/dockerfile_http.tmpl") - httpTemplate, _ := template.New("HttpDockerfile").Parse(httpTemplateSource) - - ignoreTemplateSource, _ := box.FindString("docker/dockerignore.tmpl") - ignoreTemplate, _ := template.New("Dockerignore").Parse(ignoreTemplateSource) + return &DockerTemplator{ + ApplicationDocker: NewSingleFileTemplator(box, "docker/dockerfile_app.tmpl"), + HttpGatewayDocker: NewSingleFileTemplator(box, "docker/dockerfile_http.tmpl"), + DockerIgnore: NewSingleFileTemplator(box, "docker/dockerignore.tmpl"), + DockerCompose: NewSingleFileTemplator(box, "docker/dockercompose.tmpl"), + } +} - composeTemplateSource, _ := box.FindString("docker/dockercompose.tmpl") - composeTemplate, _ := template.New("Dockercompose").Parse(composeTemplateSource) +// NewSingleFileTemplator returns a template struct for a given template file +func NewSingleFileTemplator(box *packr.Box, file string) *template.Template { + source, err := box.FindString(file) + if err != nil { + panic(err) + } - return &DockerTemplator{ - ApplicationDocker: appTemplate, - HttpGatewayDocker: httpTemplate, - DockerIgnore: ignoreTemplate, - DockerCompose: composeTemplate, + t, err := template.New(file).Funcs(util.FuncMap).Parse(source) + if err != nil { + panic(err) } + + return t } type DirectoryTemplator struct { Templates []*template.Template } -func (d *DirectoryTemplator) TemplateFiles(config *config.Commit0Config, overwrite bool) { +func (d *DirectoryTemplator) TemplateFiles(config *config.Commit0Config, overwrite bool, wg *sync.WaitGroup) { for _, template := range d.Templates { d, f := filepath.Split(template.Name()) if strings.HasSuffix(f, ".tmpl") { f = strings.Replace(f, ".tmpl", "", -1) } if overwrite { - util.TemplateFileAndOverwrite(d, f, template, config) + util.TemplateFileAndOverwrite(d, f, template, wg, config) } else { - util.TemplateFileIfDoesNotExist(d, f, template, config) + util.TemplateFileIfDoesNotExist(d, f, template, wg, config) } } } diff --git a/internal/util/util.go b/internal/util/util.go index 850d2c4bd..dc4c887ec 100644 --- a/internal/util/util.go +++ b/internal/util/util.go @@ -6,6 +6,7 @@ import ( "os" "path" "strings" + "sync" "text/template" ) @@ -21,28 +22,33 @@ var FuncMap = template.FuncMap{ "Title": strings.Title, } -func createTemplatedFile(fullFilePath string, template *template.Template, data interface{}) { +func createTemplatedFile(fullFilePath string, template *template.Template, wg *sync.WaitGroup, data interface{}) { f, err := os.Create(fullFilePath) if err != nil { log.Printf("Error creating file: %v", err) } - err = template.Execute(f, data) - if err != nil { - log.Printf("Error templating: %v", err) - } + wg.Add(1) + go func() { + err = template.Execute(f, data) + if err != nil { + log.Printf("Error templating: %v", err) + } + log.Printf("Finished templating : %v", fullFilePath) + wg.Done() + }() } -func TemplateFileAndOverwrite(fileDir string, fileName string, template *template.Template, data interface{}) { +func TemplateFileAndOverwrite(fileDir string, fileName string, template *template.Template, wg *sync.WaitGroup, data interface{}) { fullFilePath := fmt.Sprintf("%v/%v", fileDir, fileName) err := os.MkdirAll(fileDir, os.ModePerm) if err != nil { log.Printf("Error creating directory %v: %v", fullFilePath, err) } - createTemplatedFile(fullFilePath, template, data) + createTemplatedFile(fullFilePath, template, wg, data) } -func TemplateFileIfDoesNotExist(fileDir string, fileName string, template *template.Template, data interface{}) { +func TemplateFileIfDoesNotExist(fileDir string, fileName string, template *template.Template, wg *sync.WaitGroup, data interface{}) { fullFilePath := path.Join(fileDir, fileName) if _, err := os.Stat(fullFilePath); os.IsNotExist(err) { @@ -52,7 +58,7 @@ func TemplateFileIfDoesNotExist(fileDir string, fileName string, template *templ log.Printf("Error creating directory %v: %v", fullFilePath, err) } } - createTemplatedFile(fullFilePath, template, data) + createTemplatedFile(fullFilePath, template, wg, data) } else { log.Printf("%v already exists. skipping.", fullFilePath) } diff --git a/templates/util/README.tmpl b/templates/util/README.tmpl new file mode 100644 index 000000000..c3e480c2a --- /dev/null +++ b/templates/util/README.tmpl @@ -0,0 +1,3 @@ +# {{.Name}} + +@TODO : Fill in readme about how to use all the components the user configured