diff --git a/cmd/generate.go b/cmd/generate.go index 065eb68..7efb28a 100644 --- a/cmd/generate.go +++ b/cmd/generate.go @@ -6,8 +6,13 @@ package cmd import ( "fmt" + "os" + "git.home.m-and-m.ovh/mderasse/gouick/helpers" + "git.home.m-and-m.ovh/mderasse/gouick/models" "github.com/spf13/cobra" + + log "github.com/sirupsen/logrus" ) // generateCmd represents the generate command. @@ -24,3 +29,48 @@ You can also generate files for each 'modules' by using the command bellows`, func init() { rootCmd.AddCommand(generateCmd) } + +func loadProjectAndConfig() (string, *models.Config, error) { + + log.Debugf("Checking dependencies") + + if !checkDependencies() { + return "", nil, fmt.Errorf("failed to check dependencies") + } + + // Get current path + currentPath, err := os.Getwd() + if err != nil { + log.Errorf("Fail to get current path. The following error happen: %s", err.Error()) + return "", nil, err + } + + log.Debugf("Working in directory: %s", currentPath) + + // Check if we are in a gouick project + log.Debug("Checking if we are in a gouick project") + + isGouickProject, err := helpers.IsGouickProject(currentPath) + if err != nil { + log.Errorf("Fail to check if we are in a gouick project. The following error happen: %s", err.Error()) + return "", nil, err + } + + if !isGouickProject { + log.Error("That command need to be executed in a Gouick Project Directory") + return "", nil, fmt.Errorf("that command need to be executed in a gouick project directory") + } + + // Reading project configuration + log.Debug("Reading project configuration") + + config, err := helpers.ReadConfig(currentPath) + if err != nil { + log.Errorf("Failed to read configuration file. The following error happen: %s", err.Error()) + return "", nil, err + } + + log.Debugf("Using api type : %s", string(config.ProjectType)) + + return currentPath, config, nil +} diff --git a/cmd/generateLauncher.go b/cmd/generateLauncher.go index 7024068..3e870c7 100644 --- a/cmd/generateLauncher.go +++ b/cmd/generateLauncher.go @@ -5,20 +5,43 @@ Copyright © 2022 Matthieu Derasse package cmd import ( - "fmt" - + "git.home.m-and-m.ovh/mderasse/gouick/helpers/api_types" "github.com/spf13/cobra" + + log "github.com/sirupsen/logrus" ) // launcherCmd represents the launcher command. var launcherCmd = &cobra.Command{ Use: "launcher", - Short: "Generate Launcher Bash script", - Run: func(cmd *cobra.Command, args []string) { - fmt.Println("launcher called") - }, + Short: "Generate Launcher entrypoint bash script", + Run: runGenerateLauncherAction, } func init() { generateCmd.AddCommand(launcherCmd) } + +// runGenerateLauncherAction will generate the entrypoint for the current project. +func runGenerateLauncherAction(cmd *cobra.Command, args []string) { + log.Debugf("Starting command GenerateLauncher") + + currentPath, config, err := loadProjectAndConfig() + if err != nil { + return + } + + apiType, err := api_types.GetAPIType(config.ProjectType) + if err != nil { + log.Error("Impossible to load that API Type generator") + return + } + + // Generate Launcher + log.Info("Generating Launcher") + err = apiType.GenerateLauncher(currentPath, config) + if err != nil { + log.Errorf("Fail to generate Launcher. The following error happen: %s", err.Error()) + return + } +} diff --git a/cmd/generateMakefile.go b/cmd/generateMakefile.go index 25a0e86..fd39606 100644 --- a/cmd/generateMakefile.go +++ b/cmd/generateMakefile.go @@ -5,20 +5,43 @@ Copyright © 2022 Matthieu Derasse package cmd import ( - "fmt" - + "git.home.m-and-m.ovh/mderasse/gouick/helpers/api_types" "github.com/spf13/cobra" + + log "github.com/sirupsen/logrus" ) // makefileCmd represents the makefile command. var makefileCmd = &cobra.Command{ Use: "makefile", Short: "Generate Makefile", - Run: func(cmd *cobra.Command, args []string) { - fmt.Println("makefile called") - }, + Run: runGenerateMakefileAction, } func init() { generateCmd.AddCommand(makefileCmd) } + +// runGenerateMakefileAction will generate the Makefile for the current project. +func runGenerateMakefileAction(cmd *cobra.Command, args []string) { + log.Debugf("Starting command GenerateMakefile") + + currentPath, config, err := loadProjectAndConfig() + if err != nil { + return + } + + apiType, err := api_types.GetAPIType(config.ProjectType) + if err != nil { + log.Error("Impossible to load that API Type generator") + return + } + + // Generate Makefile + log.Info("Generating Makefile") + err = apiType.GenerateMakefile(currentPath, config) + if err != nil { + log.Errorf("Fail to generate Makefile. The following error happen: %s", err.Error()) + return + } +} diff --git a/cmd/generateReadme.go b/cmd/generateReadme.go new file mode 100644 index 0000000..3b2be1f --- /dev/null +++ b/cmd/generateReadme.go @@ -0,0 +1,46 @@ +/* +Copyright © 2022 Matthieu Derasse + +*/ +package cmd + +import ( + "git.home.m-and-m.ovh/mderasse/gouick/helpers/api_types" + "github.com/spf13/cobra" + + log "github.com/sirupsen/logrus" +) + +// readmeCmd represents the readme command. +var readmeCmd = &cobra.Command{ + Use: "readme", + Short: "Generate Readme", + Run: runGenerateReadmeAction, +} + +func init() { + generateCmd.AddCommand(readmeCmd) +} + +// runGenerateReadmeAction will generate the Readme for the current project. +func runGenerateReadmeAction(cmd *cobra.Command, args []string) { + log.Debugf("Starting command GenerateReadme") + currentPath, config, err := loadProjectAndConfig() + if err != nil { + return + } + + apiType, err := api_types.GetAPIType(config.ProjectType) + if err != nil { + log.Error("Impossible to load that API Type generator") + return + } + + // Generate ReadMe + log.Info("Generating ReadMe") + err = apiType.GenerateReadme(currentPath, config) + if err != nil { + log.Errorf("Fail to generate ReadMe. The following error happen: %s", err.Error()) + return + } +} diff --git a/cmd/init.go b/cmd/init.go index 65a2019..73773f7 100644 --- a/cmd/init.go +++ b/cmd/init.go @@ -39,11 +39,7 @@ func init() { rootCmd.AddCommand(initCmd) } -// runInitAction -// Steps: -// 1 - Check that we have the dependencies. -// 2 - Check that we are not in project directory. -// 3 - Ask info to the user. +// runInitAction will init a project. func runInitAction(cmd *cobra.Command, args []string) { log.Debugf("Starting command Init") @@ -107,6 +103,7 @@ func runInitAction(cmd *cobra.Command, args []string) { apiType, err := api_types.GetAPIType(apiTypeName) if err != nil { log.Error("Impossible to load that API Type generator") + return } config.ProjectType = apiTypeName @@ -196,6 +193,23 @@ func runInitAction(cmd *cobra.Command, args []string) { return } + // Generate Makefile + log.Info("Generating Makefile") + err = apiType.GenerateMakefile(projectDirPath, config) + if err != nil { + log.Errorf("Fail to generate Makefile. The following error happen: %s", err.Error()) + return + } + + // Generate Readme + log.Info("Generating Readme") + err = apiType.GenerateReadme(projectDirPath, config) + if err != nil { + log.Errorf("Fail to generate Readme.md. The following error happen: %s", err.Error()) + return + } + + // Create API Skeleton log.Info("Creating API skeleton") err = apiType.CreateProjectSkeleton(projectDirPath, config) if err != nil { diff --git a/helpers/api_types/base/generate_launcher.go b/helpers/api_types/base/generate_launcher.go new file mode 100644 index 0000000..d501b28 --- /dev/null +++ b/helpers/api_types/base/generate_launcher.go @@ -0,0 +1,13 @@ +package base + +import ( + "github.com/juju/errors" + + "git.home.m-and-m.ovh/mderasse/gouick/helpers" + "git.home.m-and-m.ovh/mderasse/gouick/models" +) + +// GenerateLauncher will generate a launcher entrypoint based on the given config. +func (a APIType) GenerateLauncher(path string, config *models.Config) error { + return errors.NotImplementedf("%s not implemented for %s", helpers.GetCurrentFuncName(), a.GetName()) +} diff --git a/helpers/api_types/base/generate_makefile.go b/helpers/api_types/base/generate_makefile.go new file mode 100644 index 0000000..09c19b3 --- /dev/null +++ b/helpers/api_types/base/generate_makefile.go @@ -0,0 +1,14 @@ +package base + +import ( + "github.com/juju/errors" + + "git.home.m-and-m.ovh/mderasse/gouick/helpers" + "git.home.m-and-m.ovh/mderasse/gouick/models" +) + +// GenerateMakefile will generate makefile based on the given config. +// Launched only at project init or with generate makefile command. +func (a APIType) GenerateMakefile(path string, config *models.Config) error { + return errors.NotImplementedf("%s not implemented for %s", helpers.GetCurrentFuncName(), a.GetName()) +} diff --git a/helpers/api_types/base/generate_readme.go b/helpers/api_types/base/generate_readme.go new file mode 100644 index 0000000..32079dc --- /dev/null +++ b/helpers/api_types/base/generate_readme.go @@ -0,0 +1,14 @@ +package base + +import ( + "github.com/juju/errors" + + "git.home.m-and-m.ovh/mderasse/gouick/helpers" + "git.home.m-and-m.ovh/mderasse/gouick/models" +) + +// GenerateReadme will generate a readme based on the given config. +// Launched only at project init and with generate readme command. +func (a APIType) GenerateReadme(path string, config *models.Config) error { + return errors.NotImplementedf("%s not implemented for %s", helpers.GetCurrentFuncName(), a.GetName()) +} diff --git a/helpers/api_types/go_swagger/create_project_skeleton.go b/helpers/api_types/go_swagger/create_project_skeleton.go index 8368108..8c38349 100644 --- a/helpers/api_types/go_swagger/create_project_skeleton.go +++ b/helpers/api_types/go_swagger/create_project_skeleton.go @@ -19,21 +19,8 @@ func (a APIType) CreateProjectSkeleton(path string, config *models.Config) error return errors.Trace(err) } - // Generate Makefile - err = a.GenerateMakefile(path, config) - if err != nil { - log.Error("Fail to generate Makefile") - return errors.Trace(err) - } - // Generate Readme - err = a.generateReadme(path, config) - if err != nil { - log.Error("Fail to generate Readme.md") - return errors.Trace(err) - } - // Generate api yaml files - err = a.generateAPIYamls(path, config) + err = a.createDefaultAPIYamls(path, config) if err != nil { log.Error("Fail to generate API Yaml files") return errors.Trace(err) diff --git a/helpers/api_types/go_swagger/generate_launcher.go b/helpers/api_types/go_swagger/generate_launcher.go new file mode 100644 index 0000000..b347ef5 --- /dev/null +++ b/helpers/api_types/go_swagger/generate_launcher.go @@ -0,0 +1,69 @@ +package go_swagger + +import ( + "fmt" + "path/filepath" + "strings" + + "github.com/juju/errors" + + "git.home.m-and-m.ovh/mderasse/gouick/helpers" + "git.home.m-and-m.ovh/mderasse/gouick/models" + + log "github.com/sirupsen/logrus" +) + +type launcherProcess struct { + Binary string + Name string +} + +type launcherTemplate struct { + APIs []*launcherProcess + Workers []*launcherProcess +} + +// GenerateLauncher will generate a launcher.sh based on the files found in cmd directory. +func (a APIType) GenerateLauncher(path string, config *models.Config) error { + log.Debugf("Starting %s - %s", a.GetName(), helpers.GetCurrentFuncName()) + + cmdPath := filepath.Join(path, "cmd") + templatePath := filepath.Join(templateDirectory, "launcher.sh.tmpl") + savePath := filepath.Join(path, "launcher.sh") + + data := launcherTemplate{ + APIs: []*launcherProcess{}, + Workers: []*launcherProcess{}, + } + + cmdDirectories, err := filepath.Glob(filepath.Join(cmdPath, "*")) + if err != nil { + log.Error("Fail to list cmd directory") + return errors.Trace(err) + } + + for _, absDir := range cmdDirectories { + dir := strings.TrimPrefix(absDir, fmt.Sprintf("%s%c", cmdPath, filepath.Separator)) + + // if we have a suffix -server or -api we are on an API. + // if we have a prefix worker- we are on a worker. + if strings.HasSuffix(dir, "-server") || strings.HasSuffix(dir, "-api") { + data.APIs = append(data.APIs, &launcherProcess{ + Binary: dir, + Name: dir, + }) + } else if strings.HasPrefix(dir, "worker-") { + data.APIs = append(data.Workers, &launcherProcess{ + Binary: dir, + Name: strings.TrimPrefix(dir, "worker-"), + }) + } + } + + err = helpers.WriteTemplate(templatePath, savePath, data) + if err != nil { + return errors.Trace(err) + } + + return nil +} diff --git a/helpers/api_types/go_swagger/generate_readme.go b/helpers/api_types/go_swagger/generate_readme.go index c1f6e53..97d92ad 100644 --- a/helpers/api_types/go_swagger/generate_readme.go +++ b/helpers/api_types/go_swagger/generate_readme.go @@ -16,9 +16,9 @@ type readmeTemplate struct { ProjectName string } -// generateReadme will generate a readme based on the given config. +// GenerateReadme will generate a readme based on the given config. // Launched only at project init. -func (a APIType) generateReadme(path string, config *models.Config) error { +func (a APIType) GenerateReadme(path string, config *models.Config) error { log.Debugf("Starting %s - %s", a.GetName(), helpers.GetCurrentFuncName()) templatePath := filepath.Join(templateDirectory, "Readme.md.tmpl") diff --git a/helpers/api_types/go_swagger/get_user_input.go b/helpers/api_types/go_swagger/get_initialize_user_input.go similarity index 100% rename from helpers/api_types/go_swagger/get_user_input.go rename to helpers/api_types/go_swagger/get_initialize_user_input.go diff --git a/helpers/api_types/go_swagger/yaml.go b/helpers/api_types/go_swagger/yaml.go index e18e0c1..915820c 100644 --- a/helpers/api_types/go_swagger/yaml.go +++ b/helpers/api_types/go_swagger/yaml.go @@ -24,9 +24,9 @@ type apiYamlContact struct { URL string } -// generateAPIYamls will generate the main api yaml file based on the given config. +// createDefaultAPIYamls will generate the main api yaml file based on the given config. // Launched only at project init. -func (a APIType) generateAPIYamls(path string, config *models.Config) error { +func (a APIType) createDefaultAPIYamls(path string, config *models.Config) error { log.Debugf("Starting %s - %s", a.GetName(), helpers.GetCurrentFuncName()) type templateFileStruct struct { diff --git a/helpers/api_types/interface.go b/helpers/api_types/interface.go index 5573f71..3eecac8 100644 --- a/helpers/api_types/interface.go +++ b/helpers/api_types/interface.go @@ -6,6 +6,9 @@ import "git.home.m-and-m.ovh/mderasse/gouick/models" type APITypeInterface interface { CheckInitialize() error CreateProjectSkeleton(path string, config *models.Config) error + GenerateLauncher(path string, config *models.Config) error + GenerateMakefile(path string, config *models.Config) error + GenerateReadme(path string, config *models.Config) error GetInitializeUserInput(params *models.Config) (*models.Config, error) GetName() models.APITypeName } diff --git a/templates/go-swagger/launcher.sh.tmpl b/templates/go-swagger/launcher.sh.tmpl new file mode 100644 index 0000000..e7261df --- /dev/null +++ b/templates/go-swagger/launcher.sh.tmpl @@ -0,0 +1,41 @@ +#!/bin/sh + +# the launcher file will launch the correct app / worker based on the given env variable +# the main goal of that launcher is to be used as a Docker entrypoint +# APP_TYPE: Can be api or worker + +case "$APP_TYPE" in +{{ if eq (len .APIs) 1 }} + # API + api) exec /app/{{ (index .APIs 0).Binary }} ;; +{{ else if gt (len .APIs) 1 }} + {{range .APIs}} + # API {{.Name}} + {{.Name}}) exec /app/{{.Binary}} ;; + {{end}} +{{end}} + +{{- if ne (len .Workers) 0 }} + # Workers + worker) + case "$WORKER_NAME" in + + {{range .Workers}} + # Worker {{.Name}} + {{.Name}}) exec /app/{{.Binary}} ;; + {{end}} + + # otherwise + *) + echo "** invalid WORKER_NAME='$WORKER_NAME'. Please use a valid worker name!" + exit 1 + ;; + esac + ;; +{{end}} + # otherwise + *) + echo "** invalid APP_TYPE='$APP_TYPE' ! Please use API or WORKER!" + exit 1 + ;; +esac