From 911fde71dee2cfb3ae85d3593e25482aca35e0a7 Mon Sep 17 00:00:00 2001 From: linyyyang Date: Fri, 3 Sep 2021 19:51:29 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20feat:add=20command?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 2 + ginny/command/handle.go | 34 +++++++++++++ ginny/command/proto.go | 40 +++++++++++++++ ginny/command/repo.go | 39 +++++++++++++++ ginny/command/service.go | 34 +++++++++++++ ginny/go.mod | 1 + ginny/go.sum | 2 + ginny/handle/common.go | 102 ++++++++++++++++++++++++++++++++------- ginny/handle/handle.go | 61 +++++++++++++++++++++++ ginny/handle/new.go | 22 ++++----- ginny/handle/proto.go | 55 +++++++++++++++++++++ ginny/handle/repo.go | 93 +++++++++++++++++++++++++++++++++++ ginny/handle/service.go | 59 ++++++++++++++++++++++ ginny/options/option.go | 59 +++++++++++++++++++++- ginny/util/file.go | 10 +++- 15 files changed, 579 insertions(+), 34 deletions(-) create mode 100644 .gitignore create mode 100644 ginny/command/handle.go create mode 100644 ginny/command/proto.go create mode 100644 ginny/command/repo.go create mode 100644 ginny/command/service.go create mode 100644 ginny/handle/handle.go create mode 100644 ginny/handle/proto.go create mode 100644 ginny/handle/repo.go create mode 100644 ginny/handle/service.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..54d5e28 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.ginny +.ginny.yml \ No newline at end of file diff --git a/ginny/command/handle.go b/ginny/command/handle.go new file mode 100644 index 0000000..1306a35 --- /dev/null +++ b/ginny/command/handle.go @@ -0,0 +1,34 @@ +package command + +import ( + "github.com/gorillazer/ginny-cli/ginny/handle" + "github.com/gorillazer/ginny-cli/ginny/util" + "github.com/spf13/cobra" +) + +func init() { + rootCmd.AddCommand(handleCmd) +} + +var handleCmd = &cobra.Command{ + Use: "handle", + Short: "Create handle file", + Long: "Create handle file from template", + PreRunE: func(cmd *cobra.Command, args []string) (err error) { + return nil + }, + RunE: func(cmd *cobra.Command, args []string) (err error) { + if err := CheckArgs(args); err != nil { + return err + } + // 获取参数 + handleName := args[0] + + if err := handle.CreateHandle(handleName); err != nil { + return err + } + + util.Info("Create new handle file success!") + return nil + }, +} diff --git a/ginny/command/proto.go b/ginny/command/proto.go new file mode 100644 index 0000000..8325b87 --- /dev/null +++ b/ginny/command/proto.go @@ -0,0 +1,40 @@ +package command + +import ( + "github.com/gorillazer/ginny-cli/ginny/handle" + "github.com/gorillazer/ginny-cli/ginny/util" + "github.com/spf13/cobra" +) + +func init() { + protoCmd.Flags().BoolP("validate", "v", false, "Added support for parameter verification") + rootCmd.AddCommand(protoCmd) +} + +var protoCmd = &cobra.Command{ + Use: "proto", + Short: "Create proto file", + Long: "Create proto file from template", + PreRunE: func(cmd *cobra.Command, args []string) (err error) { + return nil + }, + RunE: func(cmd *cobra.Command, args []string) (err error) { + if err := CheckArgs(args); err != nil { + return err + } + // 获取参数 + serviceName := args[0] + flags := cmd.Flags() + validate, err := flags.GetBool("validate") + if err != nil { + return err + } + if err := handle.CreateProto(serviceName, validate); err != nil { + return err + } + + util.Info("Create new proto file success!") + util.Info("You can modify the proto file, and then execute `make proto` to generate pb code.") + return nil + }, +} diff --git a/ginny/command/repo.go b/ginny/command/repo.go new file mode 100644 index 0000000..c1d71a6 --- /dev/null +++ b/ginny/command/repo.go @@ -0,0 +1,39 @@ +package command + +import ( + "github.com/gorillazer/ginny-cli/ginny/handle" + "github.com/gorillazer/ginny-cli/ginny/util" + "github.com/spf13/cobra" +) + +func init() { + repoCmd.Flags().StringArrayP("database", "d", []string{}, "Define the database used by the project, support mysql、mongo、redis") + rootCmd.AddCommand(repoCmd) +} + +var repoCmd = &cobra.Command{ + Use: "repo", + Short: "Create repository file", + Long: "Create repository file from template", + PreRunE: func(cmd *cobra.Command, args []string) (err error) { + return nil + }, + RunE: func(cmd *cobra.Command, args []string) (err error) { + if err := CheckArgs(args); err != nil { + return err + } + // 获取参数 + repoName := args[0] + flags := cmd.Flags() + database, err := flags.GetStringArray("database") + if err != nil { + return err + } + if err := handle.CreateRepo(repoName, database); err != nil { + return err + } + + util.Info("Create new repository file success!") + return nil + }, +} diff --git a/ginny/command/service.go b/ginny/command/service.go new file mode 100644 index 0000000..0fb44a2 --- /dev/null +++ b/ginny/command/service.go @@ -0,0 +1,34 @@ +package command + +import ( + "github.com/gorillazer/ginny-cli/ginny/handle" + "github.com/gorillazer/ginny-cli/ginny/util" + "github.com/spf13/cobra" +) + +func init() { + rootCmd.AddCommand(serviceCmd) +} + +var serviceCmd = &cobra.Command{ + Use: "service", + Short: "Create service file", + Long: "Create service file from template", + PreRunE: func(cmd *cobra.Command, args []string) (err error) { + return nil + }, + RunE: func(cmd *cobra.Command, args []string) (err error) { + if err := CheckArgs(args); err != nil { + return err + } + // 获取参数 + serviceName := args[0] + + if err := handle.CreateService(serviceName); err != nil { + return err + } + + util.Info("Create new service file success!") + return nil + }, +} diff --git a/ginny/go.mod b/ginny/go.mod index 5d884af..21162f5 100644 --- a/ginny/go.mod +++ b/ginny/go.mod @@ -5,6 +5,7 @@ go 1.16 require ( github.com/fatih/structs v1.1.0 github.com/go-git/go-git/v5 v5.4.2 + github.com/iancoleman/strcase v0.2.0 github.com/spf13/cobra v1.2.1 gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b ) diff --git a/ginny/go.sum b/ginny/go.sum index 84c9a97..caa4f12 100644 --- a/ginny/go.sum +++ b/ginny/go.sum @@ -186,6 +186,8 @@ github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/iancoleman/strcase v0.2.0 h1:05I4QRnGpI0m37iZQRuskXh+w77mr6Z41lwQzuHLwW0= +github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= diff --git a/ginny/handle/common.go b/ginny/handle/common.go index fd72257..2980248 100644 --- a/ginny/handle/common.go +++ b/ginny/handle/common.go @@ -1,14 +1,16 @@ package handle import ( + "errors" "fmt" + "io/ioutil" "os" "os/exec" - "github.com/fatih/structs" "github.com/go-git/go-git/v5" "github.com/gorillazer/ginny-cli/ginny/options" "github.com/gorillazer/ginny-cli/ginny/util" + "gopkg.in/yaml.v3" ) // GetCurrentDir 获取当前目录 @@ -23,35 +25,99 @@ func GetCurrentDir() (string, error) { } // PullTemplate 拉取模板 -func PullTemplate(dir string) error { - // Clone the given repository to the given directory - util.Info("git clone " + options.TemplateRepo) +func PullTemplate(dir, repo string) error { + if !util.Exists(dir) { + _ = util.MkDir(dir) + // Clone the given repository to the given directory + util.Info("git clone " + repo) + _, err := git.PlainClone(dir, false, &git.CloneOptions{ + URL: repo, + Progress: os.Stdout, + }) + if err != nil { + util.Error("Clone the given repository error:", err.Error()) + return err + } + } else { + if !util.Exists(dir + "/.git") { + return errors.New("The directory is not empty and is not a valid git directory") + } - _, err := git.PlainClone(dir, false, &git.CloneOptions{ - URL: options.TemplateRepo, - Progress: os.Stdout, - }) - if err != nil { - util.Error("Clone the given repository error:", err.Error()) - return err + // We instantiate a new repository targeting the given path (the .git folder) + r, err := git.PlainOpen(dir) + if err != nil { + return err + } + // Get the working directory for the repository + w, err := r.Worktree() + if err != nil { + return err + } + util.Info("git pull origin master ") + err = w.Pull(&git.PullOptions{RemoteName: "origin", Force: true}) + if err != nil { + util.Error(err.Error()) + return nil + } + // Print the latest commit that was just pulled + ref, err := r.Head() + if err != nil { + util.Error(err.Error()) + return nil + } + commit, err := r.CommitObject(ref.Hash()) + if err != nil { + util.Error(err.Error()) + return nil + } + util.Info("git pull success", commit) } + return nil } // GenerateProjectInfo 构造项目标识 -func GenerateProjectInfo() { - +func GenerateProjectInfo(projectDir string, p *options.ProjectInfo) error { + bt, err := yaml.Marshal(p) + if err != nil { + return err + } + return util.WriteToFile(projectDir+"/"+options.ProjectFlag, bt) } // GetProjectInfo 检查当前目录是否ginny项目,并返回项目信息 -func GetProjectInfo() (conf *options.ProjectInfo, err error) { - return nil, nil +func GetProjectInfo() (*options.ProjectInfo, error) { + dir, err := GetCurrentDir() + if err != nil { + return nil, errors.New("Failed to get project directory.") + } + + flagFile := dir + "/" + options.ProjectFlag + if !util.Exists(flagFile) { + return nil, errors.New("Current project is not a Ginny project.\n" + + "Please execute command after enter Ginny project root directory.") + } + + bin, err := ioutil.ReadFile(flagFile) + if err != nil { + return nil, errors.New("Failed to read project flag file.") + } + conf := &options.ProjectInfo{} + err = yaml.Unmarshal(bin, conf) + if err != nil { + return nil, errors.New("Failed Unmarshal projectinfo.") + } + if conf.ProjectName == "" { + return nil, errors.New("The project flags file is corrupted .") + } + conf.ProjectPath = dir + + return conf, nil } // ReplaceFileKeyword -func ReplaceFileKeyword(file []string, r *options.ReplaceKeywords) error { - m := structs.Map(r) - for _, f := range file { +func ReplaceFileKeyword(files []string, m map[string]interface{}) error { + for _, f := range files { if !util.IsFile(f) { continue } diff --git a/ginny/handle/handle.go b/ginny/handle/handle.go new file mode 100644 index 0000000..78e5e04 --- /dev/null +++ b/ginny/handle/handle.go @@ -0,0 +1,61 @@ +package handle + +import ( + "errors" + "fmt" + + "github.com/fatih/structs" + "github.com/gorillazer/ginny-cli/ginny/options" + "github.com/gorillazer/ginny-cli/ginny/util" + "github.com/iancoleman/strcase" +) + +func CreateHandle(handleName string) error { + conf, err := GetProjectInfo() + if err != nil { + util.Error("Failed to get project info, ", err.Error()) + return err + } + + tmpPath := fmt.Sprintf("%s/%s", conf.ProjectPath, options.TempPath) + if err := PullTemplate(tmpPath, options.ComponentTemplateRepo); err != nil { + return err + } + + srcFile := fmt.Sprintf("%s/handlers/test.go", tmpPath) + dstFile := fmt.Sprintf("%s/internal/handlers/%s.go", conf.ProjectPath, handleName) + if util.Exists(dstFile) { + return errors.New("File already exists and overwriting is not allowed") + } + if err := util.CopyFile(srcFile, dstFile); err != nil { + return err + } + // replace handle + caseName := strcase.ToCamel(handleName) + r := &options.ReplaceKeywords{ + APP_NAME: conf.ProjectName, + MODULE_NAME: conf.ProjectModule, + HANDLE_NAME: caseName, + } + + // replace provider + providerFile := fmt.Sprintf("%s/internal/handlers/provider.go", conf.ProjectPath) + if !util.Exists(providerFile) { + if err := util.CopyFile(fmt.Sprintf("%s/handlers/provider.go", tmpPath), providerFile); err != nil { + return err + } + } + m := structs.Map(r) + m[options.HandleReplaceAnchor[1]] = options.HandleReplaceAnchorValue[1]([]string{handleName, caseName}) + m[options.HandleReplaceAnchor[2]] = options.HandleReplaceAnchorValue[2]([]string{caseName}) + + if err := ReplaceFileKeyword([]string{dstFile, providerFile}, m); err != nil { + return err + } + + if err := ExecCommand(conf.ProjectPath, "go", "mod", "tidy"); err != nil { + return err + } + + return nil +} diff --git a/ginny/handle/new.go b/ginny/handle/new.go index 0f94d98..0852098 100644 --- a/ginny/handle/new.go +++ b/ginny/handle/new.go @@ -1,9 +1,9 @@ package handle import ( + "github.com/fatih/structs" "github.com/gorillazer/ginny-cli/ginny/options" "github.com/gorillazer/ginny-cli/ginny/util" - "gopkg.in/yaml.v3" ) // CreateProject 创建项目 @@ -14,7 +14,7 @@ func CreateProject(projectName, moduleName string, args ...string) error { return err } projectDir := d + "/" + projectName - if err := PullTemplate(projectDir); err != nil { + if err := PullTemplate(projectDir, options.TemplateRepo); err != nil { return err } // 删除多余文件 @@ -25,12 +25,12 @@ func CreateProject(projectName, moduleName string, args ...string) error { if moduleName == "" { moduleName = projectName } - kb := &options.ReplaceKeywords{ + r := &options.ReplaceKeywords{ APP_NAME: projectName, MODULE_NAME: moduleName, } // 替换关键字 - if err := ReplaceFileKeyword(util.GetFiles(projectDir), kb); err != nil { + if err := ReplaceFileKeyword(util.GetFiles(projectDir), structs.Map(r)); err != nil { return err } @@ -39,18 +39,14 @@ func CreateProject(projectName, moduleName string, args ...string) error { ProjectName: projectName, ProjectModule: moduleName, } - if err := writeProjectFlag(projectDir, p); err != nil { + if err := GenerateProjectInfo(projectDir, p); err != nil { return err } - return nil -} - -// writeProjectFlag -func writeProjectFlag(projectDir string, p *options.ProjectInfo) error { - bt, err := yaml.Marshal(p) - if err != nil { + // + if err := ExecCommand(projectDir, "go", "mod", "tidy"); err != nil { return err } - return util.WriteToFile(projectDir+"/"+options.ProjectFlag, bt) + + return nil } diff --git a/ginny/handle/proto.go b/ginny/handle/proto.go new file mode 100644 index 0000000..7eec8cf --- /dev/null +++ b/ginny/handle/proto.go @@ -0,0 +1,55 @@ +package handle + +import ( + "errors" + "fmt" + + "github.com/fatih/structs" + "github.com/gorillazer/ginny-cli/ginny/options" + "github.com/gorillazer/ginny-cli/ginny/util" + "github.com/iancoleman/strcase" +) + +// CreateProto +func CreateProto(serviceName string, validate bool) error { + conf, err := GetProjectInfo() + if err != nil { + util.Error("Failed to get project info, ", err.Error()) + return err + } + + tmpPath := fmt.Sprintf("%s/%s", conf.ProjectPath, options.TempPath) + if err := PullTemplate(tmpPath, options.ComponentTemplateRepo); err != nil { + return err + } + protoFile := fmt.Sprintf("%s/demo.proto", tmpPath) + dstFile := fmt.Sprintf("%s/api/proto/%s.proto", conf.ProjectPath, serviceName) + if util.Exists(dstFile) { + return errors.New("File already exists and overwriting is not allowed") + } + if validate { + protoFile = fmt.Sprintf("%s/demo_v.proto", tmpPath) + } + if err := util.CopyFile(protoFile, dstFile); err != nil { + return err + } + // + caseName := strcase.ToCamel(serviceName) + r := &options.ReplaceKeywords{ + APP_NAME: conf.ProjectName, + MODULE_NAME: conf.ProjectModule, + SERVICE_NAME: caseName, + } + if err := ReplaceFileKeyword([]string{dstFile}, structs.Map(r)); err != nil { + return err + } + + if validate { + protoFile = fmt.Sprintf("%s/validate.proto", tmpPath) + dstFile = fmt.Sprintf("%s/api/proto/validate.proto", conf.ProjectPath) + if err := util.CopyFile(protoFile, dstFile); err != nil { + return err + } + } + return nil +} diff --git a/ginny/handle/repo.go b/ginny/handle/repo.go new file mode 100644 index 0000000..7dcfa51 --- /dev/null +++ b/ginny/handle/repo.go @@ -0,0 +1,93 @@ +package handle + +import ( + "errors" + "fmt" + + "github.com/fatih/structs" + "github.com/gorillazer/ginny-cli/ginny/options" + "github.com/gorillazer/ginny-cli/ginny/util" + "github.com/iancoleman/strcase" +) + +func CreateRepo(repoName string, database []string) error { + conf, err := GetProjectInfo() + if err != nil { + util.Error("Failed to get project info, ", err.Error()) + return err + } + + tmpPath := fmt.Sprintf("%s/%s", conf.ProjectPath, options.TempPath) + if err := PullTemplate(tmpPath, options.ComponentTemplateRepo); err != nil { + return err + } + + srcFile := fmt.Sprintf("%s/repositories/test.go", tmpPath) + dstFile := fmt.Sprintf("%s/internal/repositories/%s.go", conf.ProjectPath, repoName) + if util.Exists(dstFile) { + return errors.New("File already exists and overwriting is not allowed") + } + if err := util.CopyFile(srcFile, dstFile); err != nil { + return err + } + // replace + caseName := strcase.ToCamel(repoName) + r := &options.ReplaceKeywords{ + APP_NAME: conf.ProjectName, + MODULE_NAME: conf.ProjectModule, + REPO_NAME: caseName, + } + + // replace provider + providerFile := fmt.Sprintf("%s/internal/repositories/provider.go", conf.ProjectPath) + if !util.Exists(providerFile) { + if err := util.CopyFile(fmt.Sprintf("%s/repositories/provider.go", tmpPath), providerFile); err != nil { + return err + } + } + m := structs.Map(r) + + m[options.RepoReplaceAnchor[1]] = "" + m[options.RepoReplaceAnchor[2]] = "" + m[options.RepoReplaceAnchor[3]] = options.RepoReplaceAnchorValue[3]([]string{caseName}) + m[options.RepoReplaceAnchor[4]] = "" + m[options.RepoReplaceAnchor[5]] = "" + m[options.RepoReplaceAnchor[6]] = "" + + for _, db := range database { + switch db { + case "mysql": + m[options.RepoReplaceAnchor[1]] = fmt.Sprintf("%v\n%s \"%s\"", m[options.RepoReplaceAnchor[1]], "mysql", options.DatabaseRepo["mysql"]) + m[options.RepoReplaceAnchor[2]] = fmt.Sprintf("%v\n%s", m[options.RepoReplaceAnchor[2]], "mysql.Provider,") + m[options.RepoReplaceAnchor[4]] = fmt.Sprintf("%v\n%s %s", m[options.RepoReplaceAnchor[4]], "mysql", options.DatabaseMap["mysql"]) + m[options.RepoReplaceAnchor[5]] = fmt.Sprintf("%v\n%s %s,", m[options.RepoReplaceAnchor[5]], "mysql", options.DatabaseMap["mysql"]) + m[options.RepoReplaceAnchor[6]] = fmt.Sprintf("%v\n%s:%s,", m[options.RepoReplaceAnchor[6]], "mysql", "mysql") + case "mongo": + m[options.RepoReplaceAnchor[1]] = fmt.Sprintf("%v\n%s \"%s\"", m[options.RepoReplaceAnchor[1]], "mongo", options.DatabaseRepo["mongo"]) + m[options.RepoReplaceAnchor[2]] = fmt.Sprintf("%v\n%s", m[options.RepoReplaceAnchor[2]], "mongo.Provider,") + m[options.RepoReplaceAnchor[4]] = fmt.Sprintf("%v\n%s %s", m[options.RepoReplaceAnchor[4]], "mongo", options.DatabaseMap["mongo"]) + m[options.RepoReplaceAnchor[5]] = fmt.Sprintf("%v\n%s %s,", m[options.RepoReplaceAnchor[5]], "mongo", options.DatabaseMap["mongo"]) + m[options.RepoReplaceAnchor[6]] = fmt.Sprintf("%v\n%s:%s,", m[options.RepoReplaceAnchor[6]], "mongo", "mongo") + case "redis": + m[options.RepoReplaceAnchor[1]] = fmt.Sprintf("%v\n%s \"%s\"", m[options.RepoReplaceAnchor[1]], "redis", options.DatabaseRepo["redis"]) + m[options.RepoReplaceAnchor[2]] = fmt.Sprintf("%v\n%s", m[options.RepoReplaceAnchor[2]], "redis.Provider,") + m[options.RepoReplaceAnchor[4]] = fmt.Sprintf("%v\n%s %s", m[options.RepoReplaceAnchor[4]], "redis", options.DatabaseMap["redis"]) + m[options.RepoReplaceAnchor[5]] = fmt.Sprintf("%v\n%s %s,", m[options.RepoReplaceAnchor[5]], "redis", options.DatabaseMap["redis"]) + m[options.RepoReplaceAnchor[6]] = fmt.Sprintf("%v\n%s:%s,", m[options.RepoReplaceAnchor[6]], "redis", "redis") + } + } + m[options.RepoReplaceAnchor[1]] = fmt.Sprintf("%v \n%s", m[options.RepoReplaceAnchor[1]], options.RepoReplaceAnchor[1]) + m[options.RepoReplaceAnchor[2]] = fmt.Sprintf("%v \n%s", m[options.RepoReplaceAnchor[2]], options.RepoReplaceAnchor[2]) + m[options.RepoReplaceAnchor[4]] = fmt.Sprintf("%v \n%s", m[options.RepoReplaceAnchor[4]], options.RepoReplaceAnchor[4]) + m[options.RepoReplaceAnchor[5]] = fmt.Sprintf("%v \n%s", m[options.RepoReplaceAnchor[5]], options.RepoReplaceAnchor[5]) + m[options.RepoReplaceAnchor[6]] = fmt.Sprintf("%v \n%s", m[options.RepoReplaceAnchor[6]], options.RepoReplaceAnchor[6]) + + if err := ReplaceFileKeyword([]string{dstFile, providerFile}, m); err != nil { + return err + } + + // if err := ExecCommand(conf.ProjectPath, "go", "mod", "tidy"); err != nil { + // return err + // } + return nil +} diff --git a/ginny/handle/service.go b/ginny/handle/service.go new file mode 100644 index 0000000..b412bea --- /dev/null +++ b/ginny/handle/service.go @@ -0,0 +1,59 @@ +package handle + +import ( + "errors" + "fmt" + + "github.com/fatih/structs" + "github.com/gorillazer/ginny-cli/ginny/options" + "github.com/gorillazer/ginny-cli/ginny/util" + "github.com/iancoleman/strcase" +) + +func CreateService(serviceName string) error { + conf, err := GetProjectInfo() + if err != nil { + util.Error("Failed to get project info, ", err.Error()) + return err + } + + tmpPath := fmt.Sprintf("%s/%s", conf.ProjectPath, options.TempPath) + if err := PullTemplate(tmpPath, options.ComponentTemplateRepo); err != nil { + return err + } + + srcFile := fmt.Sprintf("%s/services/test.go", tmpPath) + dstFile := fmt.Sprintf("%s/internal/services/%s.go", conf.ProjectPath, serviceName) + if util.Exists(dstFile) { + return errors.New("File already exists and overwriting is not allowed") + } + if err := util.CopyFile(srcFile, dstFile); err != nil { + return err + } + // replace service + caseName := strcase.ToCamel(serviceName) + r := &options.ReplaceKeywords{ + APP_NAME: conf.ProjectName, + MODULE_NAME: conf.ProjectModule, + SERVICE_NAME: caseName, + } + + // replace provider + providerFile := fmt.Sprintf("%s/internal/services/provider.go", conf.ProjectPath) + if !util.Exists(providerFile) { + if err := util.CopyFile(fmt.Sprintf("%s/services/provider.go", tmpPath), providerFile); err != nil { + return err + } + } + m := structs.Map(r) + m[options.ServiceReplaceAnchor[1]] = options.ServiceReplaceAnchorValue[1]([]string{caseName}) + if err := ReplaceFileKeyword([]string{dstFile, providerFile}, m); err != nil { + return err + } + + if err := ExecCommand(conf.ProjectPath, "go", "mod", "tidy"); err != nil { + return err + } + + return nil +} diff --git a/ginny/options/option.go b/ginny/options/option.go index 018e473..2fc6ca8 100644 --- a/ginny/options/option.go +++ b/ginny/options/option.go @@ -1,5 +1,7 @@ package options +import "fmt" + var ( Logo = ` @@ -10,8 +12,58 @@ var ( ` // 模板仓库地址 TemplateRepo = "https://github.com/gorillazer/ginny-template.git" + // 组件模板仓库地址 + ComponentTemplateRepo = "https://github.com/gorillazer/ginny-component-template.git" + // 数据库组件仓库地址 + DatabaseRepo = map[string]string{ + "mongo": "github.com/gorillazer/ginny-mongo", + "mysql": "github.com/gorillazer/ginny-mysql", + "redis": "github.com/gorillazer/ginny-redis", + } + DatabaseMap = map[string]string{ + "mysql": "*mysql.SqlBuilder", + "mongo": "*mongo.Manager", + "redis": "*redis.Manager", + } // 项目标识 ProjectFlag = ".ginny.yml" + // 组件临时缓存目录 + TempPath = ".ginny" + // 替换锚点 + AnchorFlag = " 锚点请勿删除! Do not delete this line!" + HandleReplaceAnchor = map[int]string{ + 1: "// HANDLE" + AnchorFlag, + 2: "// HANDLE_PROVIDER" + AnchorFlag, + } + HandleReplaceAnchorValue = map[int]func(args []string) string{ + 1: func(args []string) string { + return fmt.Sprintf("%s *%sHandler,\n%s", args[0], args[1], HandleReplaceAnchor[1]) + }, + 2: func(args []string) string { + return fmt.Sprintf("%sHandlerProvider,\n%s", args[0], HandleReplaceAnchor[2]) + }, + } + ServiceReplaceAnchor = map[int]string{ + 1: "// SERVICE_PROVIDER" + AnchorFlag, + } + ServiceReplaceAnchorValue = map[int]func(args []string) string{ + 1: func(args []string) string { + return fmt.Sprintf("%sServiceProvider,\n%s", args[0], ServiceReplaceAnchor[1]) + }, + } + RepoReplaceAnchor = map[int]string{ + 1: "// DATABASE_LIB" + AnchorFlag, + 2: "// DATABASE_PROVIDER" + AnchorFlag, + 3: "// REPO_PROVIDER" + AnchorFlag, + 4: "// STRUCT_ATTR" + AnchorFlag, + 5: "// FUNC_PARAM" + AnchorFlag, + 6: "// FUNC_ATTR" + AnchorFlag, + } + RepoReplaceAnchorValue = map[int]func(args []string) string{ + 3: func(args []string) string { + return fmt.Sprintf("%sRepositoryProvider,\n%s", args[0], RepoReplaceAnchor[3]) + }, + } ) // ProjectInfo @@ -23,6 +75,9 @@ type ProjectInfo struct { // ReplaceKeywords 标识字典 type ReplaceKeywords struct { - APP_NAME string - MODULE_NAME string + APP_NAME string + MODULE_NAME string + SERVICE_NAME string + HANDLE_NAME string + REPO_NAME string } diff --git a/ginny/util/file.go b/ginny/util/file.go index d751d0b..eed5040 100644 --- a/ginny/util/file.go +++ b/ginny/util/file.go @@ -7,6 +7,7 @@ import ( "io" "io/ioutil" "os" + "path" "path/filepath" "regexp" ) @@ -37,7 +38,7 @@ func IsFile(path string) bool { // MkDir 创建目录 func MkDir(path string) error { // 创建文件夹 - err := os.Mkdir(path, os.ModePerm) + err := os.MkdirAll(path, os.ModePerm) if err != nil { return err } @@ -83,6 +84,13 @@ func CopyFile(src, dst string) error { } defer source.Close() + dstPath := path.Dir(dst) + if !Exists(dstPath) { + if err := MkDir(dstPath); err != nil { + return err + } + } + destination, err := os.Create(dst) if err != nil { return err