From 41964f9d521b57294e1ee55111ea237d01980aec Mon Sep 17 00:00:00 2001 From: Keson Date: Wed, 21 Oct 2020 14:59:35 +0800 Subject: [PATCH] gozero template (#147) * model/rpc generate code from template cache * delete unused(deprecated) code * support template init|update|clean|revert * model: return the execute result for insert and update operation * // deprecated: containsAny * add template test * add default buildVersion * update build version --- tools/goctl/api/gogen/template.go | 26 ++++++ tools/goctl/api/gogen/template_test.go | 92 ++++++++++++++++++ tools/goctl/feature/feature.go | 18 ---- tools/goctl/goctl.go | 57 +++++++++--- tools/goctl/model/sql/CHANGELOG.md | 4 + tools/goctl/model/sql/converter/types_test.go | 20 ++++ tools/goctl/model/sql/example/generator.sh | 2 +- tools/goctl/model/sql/gen/delete.go | 7 +- tools/goctl/model/sql/gen/field.go | 8 +- tools/goctl/model/sql/gen/findone.go | 7 +- tools/goctl/model/sql/gen/findonebyfield.go | 16 +++- tools/goctl/model/sql/gen/imports.go | 16 +++- tools/goctl/model/sql/gen/insert.go | 8 +- tools/goctl/model/sql/gen/keys.go | 2 +- tools/goctl/model/sql/gen/keys_test.go | 77 +++++++++++++++ tools/goctl/model/sql/gen/new.go | 8 +- tools/goctl/model/sql/gen/tag.go | 7 +- tools/goctl/model/sql/gen/template.go | 72 ++++++++++++++ tools/goctl/model/sql/gen/template_test.go | 93 +++++++++++++++++++ tools/goctl/model/sql/gen/types.go | 9 +- tools/goctl/model/sql/gen/update.go | 8 +- tools/goctl/model/sql/gen/vars.go | 7 +- tools/goctl/model/sql/parser/parser_test.go | 10 +- tools/goctl/model/sql/template/import.go | 1 + tools/goctl/model/sql/template/insert.go | 10 +- tools/goctl/model/sql/template/update.go | 8 +- tools/goctl/rpc/CHANGELOG.md | 4 + tools/goctl/rpc/gen/gen.go | 2 +- tools/goctl/rpc/gen/gencall.go | 26 +++++- tools/goctl/rpc/gen/genconfig.go | 8 +- tools/goctl/rpc/gen/genetc.go | 7 +- tools/goctl/rpc/gen/genlogic.go | 14 ++- tools/goctl/rpc/gen/genmain.go | 7 +- tools/goctl/rpc/gen/genpb.go | 1 + tools/goctl/rpc/gen/genserver.go | 16 +++- tools/goctl/rpc/gen/gensvc.go | 7 +- tools/goctl/rpc/gen/rpctemplate.go | 59 ++++++++++++ tools/goctl/rpc/gen/template.go | 83 ++++++++++------- tools/goctl/rpc/gen/template_test.go | 92 ++++++++++++++++++ tools/goctl/rpc/parser/pbast.go | 1 + tools/goctl/rpc/parser/proto.go | 7 +- tools/goctl/tpl/templates.go | 69 ++++++++++++++ tools/goctl/util/files.go | 23 ++++- 43 files changed, 904 insertions(+), 115 deletions(-) create mode 100644 tools/goctl/api/gogen/template_test.go delete mode 100644 tools/goctl/feature/feature.go create mode 100644 tools/goctl/model/sql/converter/types_test.go create mode 100644 tools/goctl/model/sql/gen/keys_test.go create mode 100644 tools/goctl/model/sql/gen/template.go create mode 100644 tools/goctl/model/sql/gen/template_test.go create mode 100644 tools/goctl/rpc/gen/rpctemplate.go create mode 100644 tools/goctl/rpc/gen/template_test.go diff --git a/tools/goctl/api/gogen/template.go b/tools/goctl/api/gogen/template.go index 1ce2c15d..0ea13336 100644 --- a/tools/goctl/api/gogen/template.go +++ b/tools/goctl/api/gogen/template.go @@ -1,6 +1,8 @@ package gogen import ( + "fmt" + "github.com/tal-tech/go-zero/tools/goctl/util" "github.com/urfave/cli" ) @@ -27,3 +29,27 @@ var templates = map[string]string{ func GenTemplates(_ *cli.Context) error { return util.InitTemplates(category, templates) } + +func RevertTemplate(name string) error { + content, ok := templates[name] + if !ok { + return fmt.Errorf("%s: no such file name", name) + } + return util.CreateTemplate(category, name, content) +} + +func Update(category string) error { + err := Clean() + if err != nil { + return err + } + return util.InitTemplates(category, templates) +} + +func Clean() error { + return util.Clean(category) +} + +func GetCategory() string { + return category +} diff --git a/tools/goctl/api/gogen/template_test.go b/tools/goctl/api/gogen/template_test.go new file mode 100644 index 00000000..8f242544 --- /dev/null +++ b/tools/goctl/api/gogen/template_test.go @@ -0,0 +1,92 @@ +package gogen + +import ( + "io/ioutil" + "path/filepath" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/tal-tech/go-zero/tools/goctl/util" +) + +func TestGenTemplates(t *testing.T) { + err := util.InitTemplates(category, templates) + assert.Nil(t, err) + dir, err := util.GetTemplateDir(category) + assert.Nil(t, err) + file := filepath.Join(dir, "main.tpl") + data, err := ioutil.ReadFile(file) + assert.Nil(t, err) + assert.Equal(t, string(data), mainTemplate) +} + +func TestRevertTemplate(t *testing.T) { + name := "main.tpl" + err := util.InitTemplates(category, templates) + assert.Nil(t, err) + + dir, err := util.GetTemplateDir(category) + assert.Nil(t, err) + + file := filepath.Join(dir, name) + data, err := ioutil.ReadFile(file) + assert.Nil(t, err) + + modifyData := string(data) + "modify" + err = util.CreateTemplate(category, name, modifyData) + assert.Nil(t, err) + + data, err = ioutil.ReadFile(file) + assert.Nil(t, err) + + assert.Equal(t, string(data), modifyData) + + assert.Nil(t, RevertTemplate(name)) + + data, err = ioutil.ReadFile(file) + assert.Nil(t, err) + assert.Equal(t, mainTemplate, string(data)) +} + +func TestClean(t *testing.T) { + name := "main.tpl" + err := util.InitTemplates(category, templates) + assert.Nil(t, err) + + assert.Nil(t, Clean()) + + dir, err := util.GetTemplateDir(category) + assert.Nil(t, err) + + file := filepath.Join(dir, name) + _, err = ioutil.ReadFile(file) + assert.NotNil(t, err) +} + +func TestUpdate(t *testing.T) { + name := "main.tpl" + err := util.InitTemplates(category, templates) + assert.Nil(t, err) + + dir, err := util.GetTemplateDir(category) + assert.Nil(t, err) + + file := filepath.Join(dir, name) + data, err := ioutil.ReadFile(file) + assert.Nil(t, err) + + modifyData := string(data) + "modify" + err = util.CreateTemplate(category, name, modifyData) + assert.Nil(t, err) + + data, err = ioutil.ReadFile(file) + assert.Nil(t, err) + + assert.Equal(t, string(data), modifyData) + + assert.Nil(t, Update(category)) + + data, err = ioutil.ReadFile(file) + assert.Nil(t, err) + assert.Equal(t, mainTemplate, string(data)) +} diff --git a/tools/goctl/feature/feature.go b/tools/goctl/feature/feature.go deleted file mode 100644 index 9b950edb..00000000 --- a/tools/goctl/feature/feature.go +++ /dev/null @@ -1,18 +0,0 @@ -package feature - -import ( - "fmt" - - "github.com/logrusorgru/aurora" - "github.com/urfave/cli" -) - -var feature = ` -1、增加goctl model支持 -` - -func Feature(_ *cli.Context) error { - fmt.Println(aurora.Blue("\nFEATURE:")) - fmt.Println(aurora.Blue(feature)) - return nil -} diff --git a/tools/goctl/goctl.go b/tools/goctl/goctl.go index 65023051..dff8487d 100644 --- a/tools/goctl/goctl.go +++ b/tools/goctl/goctl.go @@ -3,6 +3,7 @@ package main import ( "fmt" "os" + "runtime" "github.com/tal-tech/go-zero/core/logx" "github.com/tal-tech/go-zero/tools/goctl/api/apigen" @@ -17,15 +18,15 @@ import ( "github.com/tal-tech/go-zero/tools/goctl/api/validate" "github.com/tal-tech/go-zero/tools/goctl/configgen" "github.com/tal-tech/go-zero/tools/goctl/docker" - "github.com/tal-tech/go-zero/tools/goctl/feature" model "github.com/tal-tech/go-zero/tools/goctl/model/sql/command" rpc "github.com/tal-tech/go-zero/tools/goctl/rpc/command" + "github.com/tal-tech/go-zero/tools/goctl/tpl" "github.com/urfave/cli" ) var ( - BuildTime = "not set" - commands = []cli.Command{ + BuildVersion = "20201021" + commands = []cli.Command{ { Name: "api", Usage: "generate api related files", @@ -328,14 +329,46 @@ var ( Action: configgen.GenConfigCommand, }, { - Name: "feature", - Usage: "the features of the latest version", - Action: feature.Feature, - }, - { - Name: "template", - Usage: "initialize the api templates", - Action: gogen.GenTemplates, + Name: "template", + Usage: "template operation", + Subcommands: []cli.Command{ + { + Name: "init", + Usage: "initialize the all templates(force update)", + Action: tpl.GenTemplates, + }, + { + Name: "clean", + Usage: "clean the all cache templates", + Action: tpl.CleanTemplates, + }, + { + Name: "update", + Usage: "update template of the target category to the latest", + Flags: []cli.Flag{ + cli.StringFlag{ + Name: "category,c", + Usage: "the category of template, enum [api,rpc,model]", + }, + }, + Action: tpl.UpdateTemplates, + }, + { + Name: "revert", + Usage: "revert the target template to the latest", + Flags: []cli.Flag{ + cli.StringFlag{ + Name: "category,c", + Usage: "the category of template, enum [api,rpc,model]", + }, + cli.StringFlag{ + Name: "name,n", + Usage: "the target file name of template", + }, + }, + Action: tpl.RevertTemplates, + }, + }, }, } ) @@ -345,7 +378,7 @@ func main() { app := cli.NewApp() app.Usage = "a cli tool to generate code" - app.Version = BuildTime + app.Version = fmt.Sprintf("%s %s/%s", BuildVersion, runtime.GOOS, runtime.GOARCH) app.Commands = commands // cli already print error messages if err := app.Run(os.Args); err != nil { diff --git a/tools/goctl/model/sql/CHANGELOG.md b/tools/goctl/model/sql/CHANGELOG.md index 93af6678..cdb80068 100644 --- a/tools/goctl/model/sql/CHANGELOG.md +++ b/tools/goctl/model/sql/CHANGELOG.md @@ -1,5 +1,9 @@ # Change log +## 2020-10-19 + +* 增加template + ## 2020-08-20 * 新增支持通过连接数据库生成model diff --git a/tools/goctl/model/sql/converter/types_test.go b/tools/goctl/model/sql/converter/types_test.go new file mode 100644 index 00000000..09ac6175 --- /dev/null +++ b/tools/goctl/model/sql/converter/types_test.go @@ -0,0 +1,20 @@ +package converter + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestConvertDataType(t *testing.T) { + v, err := ConvertDataType("tinyint") + assert.Nil(t, err) + assert.Equal(t, "int64", v) + + v, err = ConvertDataType("timestamp") + assert.Nil(t, err) + assert.Equal(t, "time.Time", v) + + _, err = ConvertDataType("float32") + assert.NotNil(t, err) +} diff --git a/tools/goctl/model/sql/example/generator.sh b/tools/goctl/model/sql/example/generator.sh index fb43430b..3d087e0a 100644 --- a/tools/goctl/model/sql/example/generator.sh +++ b/tools/goctl/model/sql/example/generator.sh @@ -4,4 +4,4 @@ goctl model mysql ddl -src="./sql/user.sql" -dir="./sql/model" -c # generate model with cache from data source -goctl model mysql datasource -url="user:password@tcp(127.0.0.1:3306)/database" -table="table1,table2" -dir="./model" \ No newline at end of file +#goctl model mysql datasource -url="user:password@tcp(127.0.0.1:3306)/database" -table="table1,table2" -dir="./model" \ No newline at end of file diff --git a/tools/goctl/model/sql/gen/delete.go b/tools/goctl/model/sql/gen/delete.go index d6c0701e..4f9bada9 100644 --- a/tools/goctl/model/sql/gen/delete.go +++ b/tools/goctl/model/sql/gen/delete.go @@ -22,8 +22,13 @@ func genDelete(table Table, withCache bool) (string, error) { } camel := table.Name.ToCamel() + text, err := util.LoadTemplate(category, deleteTemplateFile, template.Delete) + if err != nil { + return "", err + } + output, err := util.With("delete"). - Parse(template.Delete). + Parse(text). Execute(map[string]interface{}{ "upperStartCamelObject": camel, "withCache": withCache, diff --git a/tools/goctl/model/sql/gen/field.go b/tools/goctl/model/sql/gen/field.go index 6c45c2c4..d82be07a 100644 --- a/tools/goctl/model/sql/gen/field.go +++ b/tools/goctl/model/sql/gen/field.go @@ -25,8 +25,14 @@ func genField(field parser.Field) (string, error) { if err != nil { return "", err } + + text, err := util.LoadTemplate(category, fieldTemplateFile, template.Field) + if err != nil { + return "", err + } + output, err := util.With("types"). - Parse(template.Field). + Parse(text). Execute(map[string]interface{}{ "name": field.Name.ToCamel(), "type": field.DataType, diff --git a/tools/goctl/model/sql/gen/findone.go b/tools/goctl/model/sql/gen/findone.go index 8f48f873..284967b8 100644 --- a/tools/goctl/model/sql/gen/findone.go +++ b/tools/goctl/model/sql/gen/findone.go @@ -8,8 +8,13 @@ import ( func genFindOne(table Table, withCache bool) (string, error) { camel := table.Name.ToCamel() + text, err := util.LoadTemplate(category, findOneTemplateFile, template.FindOne) + if err != nil { + return "", err + } + output, err := util.With("findOne"). - Parse(template.FindOne). + Parse(text). Execute(map[string]interface{}{ "withCache": withCache, "upperStartCamelObject": camel, diff --git a/tools/goctl/model/sql/gen/findonebyfield.go b/tools/goctl/model/sql/gen/findonebyfield.go index 8bd1d7ba..0bdc778b 100644 --- a/tools/goctl/model/sql/gen/findonebyfield.go +++ b/tools/goctl/model/sql/gen/findonebyfield.go @@ -10,7 +10,12 @@ import ( ) func genFindOneByField(table Table, withCache bool) (string, string, error) { - t := util.With("findOneByField").Parse(template.FindOneByField) + text, err := util.LoadTemplate(category, findOneByFieldTemplateFile, template.FindOneByField) + if err != nil { + return "", "", err + } + + t := util.With("findOneByField").Parse(text) var list []string camelTableName := table.Name.ToCamel() for _, field := range table.Fields { @@ -33,10 +38,16 @@ func genFindOneByField(table Table, withCache bool) (string, string, error) { if err != nil { return "", "", err } + list = append(list, output.String()) } if withCache { - out, err := util.With("findOneByFieldExtraMethod").Parse(template.FindOneByFieldExtraMethod).Execute(map[string]interface{}{ + text, err := util.LoadTemplate(category, findOneByFieldExtraMethodTemplateFile, template.FindOneByFieldExtraMethod) + if err != nil { + return "", "", err + } + + out, err := util.With("findOneByFieldExtraMethod").Parse(text).Execute(map[string]interface{}{ "upperStartCamelObject": camelTableName, "primaryKeyLeft": table.CacheKey[table.PrimaryKey.Name.Source()].Left, "lowerStartCamelObject": stringx.From(camelTableName).UnTitle(), @@ -45,6 +56,7 @@ func genFindOneByField(table Table, withCache bool) (string, string, error) { if err != nil { return "", "", err } + return strings.Join(list, "\n"), out.String(), nil } return strings.Join(list, "\n"), "", nil diff --git a/tools/goctl/model/sql/gen/imports.go b/tools/goctl/model/sql/gen/imports.go index 6d29ca56..95ae514b 100644 --- a/tools/goctl/model/sql/gen/imports.go +++ b/tools/goctl/model/sql/gen/imports.go @@ -7,20 +7,32 @@ import ( func genImports(withCache, timeImport bool) (string, error) { if withCache { - buffer, err := util.With("import").Parse(template.Imports).Execute(map[string]interface{}{ + text, err := util.LoadTemplate(category, importsTemplateFile, template.Imports) + if err != nil { + return "", err + } + + buffer, err := util.With("import").Parse(text).Execute(map[string]interface{}{ "time": timeImport, }) if err != nil { return "", err } + return buffer.String(), nil } else { - buffer, err := util.With("import").Parse(template.ImportsNoCache).Execute(map[string]interface{}{ + text, err := util.LoadTemplate(category, importsWithNoCacheTemplateFile, template.ImportsNoCache) + if err != nil { + return "", err + } + + buffer, err := util.With("import").Parse(text).Execute(map[string]interface{}{ "time": timeImport, }) if err != nil { return "", err } + return buffer.String(), nil } } diff --git a/tools/goctl/model/sql/gen/insert.go b/tools/goctl/model/sql/gen/insert.go index b5600b9d..e302ac6b 100644 --- a/tools/goctl/model/sql/gen/insert.go +++ b/tools/goctl/model/sql/gen/insert.go @@ -34,8 +34,13 @@ func genInsert(table Table, withCache bool) (string, error) { expressionValues = append(expressionValues, "data."+camel) } camel := table.Name.ToCamel() + text, err := util.LoadTemplate(category, insertTemplateFile, template.Insert) + if err != nil { + return "", err + } + output, err := util.With("insert"). - Parse(template.Insert). + Parse(text). Execute(map[string]interface{}{ "withCache": withCache, "containsIndexCache": table.ContainsUniqueKey, @@ -49,5 +54,6 @@ func genInsert(table Table, withCache bool) (string, error) { if err != nil { return "", err } + return output.String(), nil } diff --git a/tools/goctl/model/sql/gen/keys.go b/tools/goctl/model/sql/gen/keys.go index 646c2ca8..b58ae31e 100644 --- a/tools/goctl/model/sql/gen/keys.go +++ b/tools/goctl/model/sql/gen/keys.go @@ -12,7 +12,7 @@ type ( // {{prefix}}=cache // key:id Key struct { - VarExpression string // cacheUserIdPrefix="cache#user#id#" + VarExpression string // cacheUserIdPrefix = "cache#User#id#" Left string // cacheUserIdPrefix Right string // cache#user#id# Variable string // userIdKey diff --git a/tools/goctl/model/sql/gen/keys_test.go b/tools/goctl/model/sql/gen/keys_test.go new file mode 100644 index 00000000..28219cd5 --- /dev/null +++ b/tools/goctl/model/sql/gen/keys_test.go @@ -0,0 +1,77 @@ +package gen + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/tal-tech/go-zero/tools/goctl/model/sql/parser" + "github.com/tal-tech/go-zero/tools/goctl/util/stringx" +) + +func TestGenCacheKeys(t *testing.T) { + m, err := genCacheKeys(parser.Table{ + Name: stringx.From("user"), + PrimaryKey: parser.Primary{ + Field: parser.Field{ + Name: stringx.From("id"), + DataBaseType: "bigint", + DataType: "int64", + IsKey: false, + IsPrimaryKey: true, + IsUniqueKey: false, + Comment: "自增id", + }, + AutoIncrement: true, + }, + Fields: []parser.Field{ + { + Name: stringx.From("mobile"), + DataBaseType: "varchar", + DataType: "string", + IsKey: false, + IsPrimaryKey: false, + IsUniqueKey: true, + Comment: "手机号", + }, + { + Name: stringx.From("name"), + DataBaseType: "varchar", + DataType: "string", + IsKey: false, + IsPrimaryKey: false, + IsUniqueKey: true, + Comment: "姓名", + }, + { + Name: stringx.From("createTime"), + DataBaseType: "timestamp", + DataType: "time.Time", + IsKey: false, + IsPrimaryKey: false, + IsUniqueKey: false, + Comment: "创建时间", + }, + { + Name: stringx.From("updateTime"), + DataBaseType: "timestamp", + DataType: "time.Time", + IsKey: false, + IsPrimaryKey: false, + IsUniqueKey: false, + Comment: "更新时间", + }, + }, + }) + assert.Nil(t, err) + + for fieldName, key := range m { + name := stringx.From(fieldName) + assert.Equal(t, fmt.Sprintf(`cacheUser%sPrefix = "cache#User#%s#"`, name.ToCamel(), name.UnTitle()), key.VarExpression) + assert.Equal(t, fmt.Sprintf(`cacheUser%sPrefix`, name.ToCamel()), key.Left) + assert.Equal(t, fmt.Sprintf(`cache#User#%s#`, name.UnTitle()), key.Right) + assert.Equal(t, fmt.Sprintf(`user%sKey`, name.ToCamel()), key.Variable) + assert.Equal(t, `user`+name.ToCamel()+`Key := fmt.Sprintf("%s%v", cacheUser`+name.ToCamel()+`Prefix,`+name.UnTitle()+`)`, key.KeyExpression) + } + +} diff --git a/tools/goctl/model/sql/gen/new.go b/tools/goctl/model/sql/gen/new.go index e5afe0ea..e3bcf639 100644 --- a/tools/goctl/model/sql/gen/new.go +++ b/tools/goctl/model/sql/gen/new.go @@ -6,8 +6,13 @@ import ( ) func genNew(table Table, withCache bool) (string, error) { + text, err := util.LoadTemplate(category, modelNewTemplateFile, template.New) + if err != nil { + return "", err + } + output, err := util.With("new"). - Parse(template.New). + Parse(text). Execute(map[string]interface{}{ "withCache": withCache, "upperStartCamelObject": table.Name.ToCamel(), @@ -15,5 +20,6 @@ func genNew(table Table, withCache bool) (string, error) { if err != nil { return "", err } + return output.String(), nil } diff --git a/tools/goctl/model/sql/gen/tag.go b/tools/goctl/model/sql/gen/tag.go index 86f15c19..11ce17d6 100644 --- a/tools/goctl/model/sql/gen/tag.go +++ b/tools/goctl/model/sql/gen/tag.go @@ -9,8 +9,13 @@ func genTag(in string) (string, error) { if in == "" { return in, nil } + text, err := util.LoadTemplate(category, tagTemplateFile, template.Tag) + if err != nil { + return "", err + } + output, err := util.With("tag"). - Parse(template.Tag). + Parse(text). Execute(map[string]interface{}{ "field": in, }) diff --git a/tools/goctl/model/sql/gen/template.go b/tools/goctl/model/sql/gen/template.go new file mode 100644 index 00000000..31f2bcf4 --- /dev/null +++ b/tools/goctl/model/sql/gen/template.go @@ -0,0 +1,72 @@ +package gen + +import ( + "fmt" + + "github.com/tal-tech/go-zero/tools/goctl/model/sql/template" + "github.com/tal-tech/go-zero/tools/goctl/util" + "github.com/urfave/cli" +) + +const ( + category = "model" + deleteTemplateFile = "delete.tpl" + fieldTemplateFile = "filed.tpl" + findOneTemplateFile = "find-one.tpl" + findOneByFieldTemplateFile = "find-one-by-field.tpl" + findOneByFieldExtraMethodTemplateFile = "find-one-by-filed-extra-method.tpl" + importsTemplateFile = "import.tpl" + importsWithNoCacheTemplateFile = "import-no-cache.tpl" + insertTemplateFile = "insert.tpl" + modelTemplateFile = "model.tpl" + modelNewTemplateFile = "model-new.tpl" + tagTemplateFile = "tag.tpl" + typesTemplateFile = "types.tpl" + updateTemplateFile = "update.tpl" + varTemplateFile = "var.tpl" +) + +var templates = map[string]string{ + deleteTemplateFile: template.Delete, + fieldTemplateFile: template.Field, + findOneTemplateFile: template.FindOne, + findOneByFieldTemplateFile: template.FindOneByField, + findOneByFieldExtraMethodTemplateFile: template.FindOneByFieldExtraMethod, + importsTemplateFile: template.Imports, + importsWithNoCacheTemplateFile: template.ImportsNoCache, + insertTemplateFile: template.Insert, + modelTemplateFile: template.Model, + modelNewTemplateFile: template.New, + tagTemplateFile: template.Tag, + typesTemplateFile: template.Types, + updateTemplateFile: template.Update, + varTemplateFile: template.Vars, +} + +func GenTemplates(_ *cli.Context) error { + return util.InitTemplates(category, templates) +} + +func RevertTemplate(name string) error { + content, ok := templates[name] + if !ok { + return fmt.Errorf("%s: no such file name", name) + } + return util.CreateTemplate(category, name, content) +} + +func Clean() error { + return util.Clean(category) +} + +func Update(category string) error { + err := Clean() + if err != nil { + return err + } + return util.InitTemplates(category, templates) +} + +func GetCategory() string { + return category +} diff --git a/tools/goctl/model/sql/gen/template_test.go b/tools/goctl/model/sql/gen/template_test.go new file mode 100644 index 00000000..ded461a0 --- /dev/null +++ b/tools/goctl/model/sql/gen/template_test.go @@ -0,0 +1,93 @@ +package gen + +import ( + "io/ioutil" + "path/filepath" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/tal-tech/go-zero/tools/goctl/model/sql/template" + "github.com/tal-tech/go-zero/tools/goctl/util" +) + +func TestGenTemplates(t *testing.T) { + err := util.InitTemplates(category, templates) + assert.Nil(t, err) + dir, err := util.GetTemplateDir(category) + assert.Nil(t, err) + file := filepath.Join(dir, "model-new.tpl") + data, err := ioutil.ReadFile(file) + assert.Nil(t, err) + assert.Equal(t, string(data), template.New) +} + +func TestRevertTemplate(t *testing.T) { + name := "model-new.tpl" + err := util.InitTemplates(category, templates) + assert.Nil(t, err) + + dir, err := util.GetTemplateDir(category) + assert.Nil(t, err) + + file := filepath.Join(dir, name) + data, err := ioutil.ReadFile(file) + assert.Nil(t, err) + + modifyData := string(data) + "modify" + err = util.CreateTemplate(category, name, modifyData) + assert.Nil(t, err) + + data, err = ioutil.ReadFile(file) + assert.Nil(t, err) + + assert.Equal(t, string(data), modifyData) + + assert.Nil(t, RevertTemplate(name)) + + data, err = ioutil.ReadFile(file) + assert.Nil(t, err) + assert.Equal(t, template.New, string(data)) +} + +func TestClean(t *testing.T) { + name := "model-new.tpl" + err := util.InitTemplates(category, templates) + assert.Nil(t, err) + + assert.Nil(t, Clean()) + + dir, err := util.GetTemplateDir(category) + assert.Nil(t, err) + + file := filepath.Join(dir, name) + _, err = ioutil.ReadFile(file) + assert.NotNil(t, err) +} + +func TestUpdate(t *testing.T) { + name := "model-new.tpl" + err := util.InitTemplates(category, templates) + assert.Nil(t, err) + + dir, err := util.GetTemplateDir(category) + assert.Nil(t, err) + + file := filepath.Join(dir, name) + data, err := ioutil.ReadFile(file) + assert.Nil(t, err) + + modifyData := string(data) + "modify" + err = util.CreateTemplate(category, name, modifyData) + assert.Nil(t, err) + + data, err = ioutil.ReadFile(file) + assert.Nil(t, err) + + assert.Equal(t, string(data), modifyData) + + assert.Nil(t, Update(category)) + + data, err = ioutil.ReadFile(file) + assert.Nil(t, err) + assert.Equal(t, template.New, string(data)) +} diff --git a/tools/goctl/model/sql/gen/types.go b/tools/goctl/model/sql/gen/types.go index d6801e6b..98d6e2b2 100644 --- a/tools/goctl/model/sql/gen/types.go +++ b/tools/goctl/model/sql/gen/types.go @@ -11,8 +11,14 @@ func genTypes(table Table, withCache bool) (string, error) { if err != nil { return "", err } + + text, err := util.LoadTemplate(category, typesTemplateFile, template.Types) + if err != nil { + return "", err + } + output, err := util.With("types"). - Parse(template.Types). + Parse(text). Execute(map[string]interface{}{ "withCache": withCache, "upperStartCamelObject": table.Name.ToCamel(), @@ -21,5 +27,6 @@ func genTypes(table Table, withCache bool) (string, error) { if err != nil { return "", err } + return output.String(), nil } diff --git a/tools/goctl/model/sql/gen/update.go b/tools/goctl/model/sql/gen/update.go index 426f8fa8..ba1ba07b 100644 --- a/tools/goctl/model/sql/gen/update.go +++ b/tools/goctl/model/sql/gen/update.go @@ -22,8 +22,13 @@ func genUpdate(table Table, withCache bool) (string, error) { } expressionValues = append(expressionValues, "data."+table.PrimaryKey.Name.ToCamel()) camelTableName := table.Name.ToCamel() + text, err := util.LoadTemplate(category, updateTemplateFile, template.Update) + if err != nil { + return "", err + } + output, err := util.With("update"). - Parse(template.Update). + Parse(text). Execute(map[string]interface{}{ "withCache": withCache, "upperStartCamelObject": camelTableName, @@ -36,5 +41,6 @@ func genUpdate(table Table, withCache bool) (string, error) { if err != nil { return "", nil } + return output.String(), nil } diff --git a/tools/goctl/model/sql/gen/vars.go b/tools/goctl/model/sql/gen/vars.go index 64e043e9..86ae57c1 100644 --- a/tools/goctl/model/sql/gen/vars.go +++ b/tools/goctl/model/sql/gen/vars.go @@ -14,8 +14,13 @@ func genVars(table Table, withCache bool) (string, error) { keys = append(keys, v.VarExpression) } camel := table.Name.ToCamel() + text, err := util.LoadTemplate(category, varTemplateFile, template.Vars) + if err != nil { + return "", err + } + output, err := util.With("var"). - Parse(template.Vars). + Parse(text). GoFmt(true). Execute(map[string]interface{}{ "lowerStartCamelObject": stringx.From(camel).UnTitle(), diff --git a/tools/goctl/model/sql/parser/parser_test.go b/tools/goctl/model/sql/parser/parser_test.go index 4a837766..b64f606c 100644 --- a/tools/goctl/model/sql/parser/parser_test.go +++ b/tools/goctl/model/sql/parser/parser_test.go @@ -17,11 +17,9 @@ func TestParseSelect(t *testing.T) { } func TestParseCreateTable(t *testing.T) { - _, err := Parse("CREATE TABLE `user_snake` (\n `id` bigint(10) NOT NULL AUTO_INCREMENT,\n `name` varchar(255) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '用户名称',\n `password` varchar(255) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '用户密码',\n `mobile` varchar(255) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '手机号',\n `gender` char(5) COLLATE utf8mb4_general_ci NOT NULL COMMENT '男|女|未公开',\n `nickname` varchar(255) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '用户昵称',\n `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP,\n `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,\n PRIMARY KEY (`id`),\n UNIQUE KEY `name_index` (`name`),\n KEY `mobile_index` (`mobile`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;") - assert.Nil(t, err) -} - -func TestParseCreateTable2(t *testing.T) { - _, err := Parse("create table `user_snake` (\n `id` bigint(10) NOT NULL AUTO_INCREMENT,\n `name` varchar(255) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '用户名称',\n `password` varchar(255) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '用户密码',\n `mobile` varchar(255) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '手机号',\n `gender` char(5) COLLATE utf8mb4_general_ci NOT NULL COMMENT '男|女|未公开',\n `nickname` varchar(255) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '用户昵称',\n `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP,\n `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,\n PRIMARY KEY (`id`),\n UNIQUE KEY `name_index` (`name`),\n KEY `mobile_index` (`mobile`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;") + table, err := Parse("CREATE TABLE `user_snake` (\n `id` bigint(10) NOT NULL AUTO_INCREMENT,\n `name` varchar(255) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '用户名称',\n `password` varchar(255) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '用户密码',\n `mobile` varchar(255) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '手机号',\n `gender` char(5) COLLATE utf8mb4_general_ci NOT NULL COMMENT '男|女|未公开',\n `nickname` varchar(255) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '用户昵称',\n `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP,\n `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,\n PRIMARY KEY (`id`),\n UNIQUE KEY `name_index` (`name`),\n KEY `mobile_index` (`mobile`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;") assert.Nil(t, err) + assert.Equal(t, "user_snake", table.Name.Source()) + assert.Equal(t, "id", table.PrimaryKey.Name.Source()) + assert.Equal(t, true, table.ContainsTime()) } diff --git a/tools/goctl/model/sql/template/import.go b/tools/goctl/model/sql/template/import.go index 2320826e..a5d75f8b 100644 --- a/tools/goctl/model/sql/template/import.go +++ b/tools/goctl/model/sql/template/import.go @@ -15,6 +15,7 @@ var ( ) ` ImportsNoCache = `import ( + "database/sql" "strings" {{if .time}}"time"{{end}} diff --git a/tools/goctl/model/sql/template/insert.go b/tools/goctl/model/sql/template/insert.go index 29309422..2277c6bd 100644 --- a/tools/goctl/model/sql/template/insert.go +++ b/tools/goctl/model/sql/template/insert.go @@ -1,15 +1,15 @@ package template var Insert = ` -func (m *{{.upperStartCamelObject}}Model) Insert(data {{.upperStartCamelObject}}) error { +func (m *{{.upperStartCamelObject}}Model) Insert(data {{.upperStartCamelObject}}) (sql.Result,error) { {{if .withCache}}{{if .containsIndexCache}}{{.keys}} - _, err := m.Exec(func(conn sqlx.SqlConn) (result sql.Result, err error) { + ret, err := m.Exec(func(conn sqlx.SqlConn) (result sql.Result, err error) { query := ` + "`" + `insert into ` + "`" + ` + m.table + ` + "` (` + " + `{{.lowerStartCamelObject}}RowsExpectAutoSet` + " + `) values ({{.expression}})` " + ` return conn.Exec(query, {{.expressionValues}}) }, {{.keyValues}}){{else}}query := ` + "`" + `insert into ` + "`" + ` + m.table + ` + "` (` + " + `{{.lowerStartCamelObject}}RowsExpectAutoSet` + " + `) values ({{.expression}})` " + ` - _,err:=m.ExecNoCache(query, {{.expressionValues}}) + ret,err:=m.ExecNoCache(query, {{.expressionValues}}) {{end}}{{else}}query := ` + "`" + `insert into ` + "`" + ` + m.table + ` + "` (` + " + `{{.lowerStartCamelObject}}RowsExpectAutoSet` + " + `) values ({{.expression}})` " + ` - _,err:=m.conn.Exec(query, {{.expressionValues}}){{end}} - return err + ret,err:=m.conn.Exec(query, {{.expressionValues}}){{end}} + return ret,err } ` diff --git a/tools/goctl/model/sql/template/update.go b/tools/goctl/model/sql/template/update.go index 72befc1a..56d6bd03 100644 --- a/tools/goctl/model/sql/template/update.go +++ b/tools/goctl/model/sql/template/update.go @@ -1,13 +1,13 @@ package template var Update = ` -func (m *{{.upperStartCamelObject}}Model) Update(data {{.upperStartCamelObject}}) error { +func (m *{{.upperStartCamelObject}}Model) Update(data {{.upperStartCamelObject}}) (sql.Result,error) { {{if .withCache}}{{.primaryCacheKey}} - _, err := m.Exec(func(conn sqlx.SqlConn) (result sql.Result, err error) { + ret, err := m.Exec(func(conn sqlx.SqlConn) (result sql.Result, err error) { query := ` + "`" + `update ` + "` +" + `m.table +` + "` " + `set ` + "` +" + `{{.lowerStartCamelObject}}RowsWithPlaceHolder` + " + `" + ` where {{.originalPrimaryKey}} = ?` + "`" + ` return conn.Exec(query, {{.expressionValues}}) }, {{.primaryKeyVariable}}){{else}}query := ` + "`" + `update ` + "` +" + `m.table +` + "` " + `set ` + "` +" + `{{.lowerStartCamelObject}}RowsWithPlaceHolder` + " + `" + ` where {{.originalPrimaryKey}} = ?` + "`" + ` - _,err:=m.conn.Exec(query, {{.expressionValues}}){{end}} - return err + ret,err:=m.conn.Exec(query, {{.expressionValues}}){{end}} + return ret,err } ` diff --git a/tools/goctl/rpc/CHANGELOG.md b/tools/goctl/rpc/CHANGELOG.md index d5bf5de7..ee4429eb 100644 --- a/tools/goctl/rpc/CHANGELOG.md +++ b/tools/goctl/rpc/CHANGELOG.md @@ -1,5 +1,9 @@ # Change log +## 2020-10-19 + +* 增加template + ## 2020-09-10 * rpc greet服务一键生成 diff --git a/tools/goctl/rpc/gen/gen.go b/tools/goctl/rpc/gen/gen.go index 8c9f3c0a..172d9013 100644 --- a/tools/goctl/rpc/gen/gen.go +++ b/tools/goctl/rpc/gen/gen.go @@ -32,7 +32,7 @@ func NewDefaultRpcGenerator(ctx *ctx.RpcContext) *defaultRpcGenerator { } func (g *defaultRpcGenerator) Generate() (err error) { - g.Ctx.Info(aurora.Blue("-> goctl rpc reference documents: ").String() + "「https://github.com/tal-tech/go-zero/blob/master/doc/goctl-rpc.md」") + g.Ctx.Info(aurora.Blue("-> goctl rpc reference documents: ").String() + "「https://github.com/tal-tech/zero-doc/blob/main/doc/goctl-rpc.md」") g.Ctx.Warning("-> generating rpc code ...") defer func() { if err == nil { diff --git a/tools/goctl/rpc/gen/gencall.go b/tools/goctl/rpc/gen/gencall.go index feaf534f..d8a62339 100644 --- a/tools/goctl/rpc/gen/gencall.go +++ b/tools/goctl/rpc/gen/gencall.go @@ -123,7 +123,11 @@ func (g *defaultRpcGenerator) genCall() error { filename := filepath.Join(callPath, typesFilename) head := util.GetHead(g.Ctx.ProtoSource) - err = util.With("types").GoFmt(true).Parse(callTemplateTypes).SaveTo(map[string]interface{}{ + text, err := util.LoadTemplate(category, callTypesTemplateFile, callTemplateTypes) + if err != nil { + return err + } + err = util.With("types").GoFmt(true).Parse(text).SaveTo(map[string]interface{}{ "head": head, "const": constLit, "filePackage": service.Name.Lower(), @@ -145,8 +149,11 @@ func (g *defaultRpcGenerator) genCall() error { if err != nil { return err } - - err = util.With("shared").GoFmt(true).Parse(callTemplateText).SaveTo(map[string]interface{}{ + text, err = util.LoadTemplate(category, callTemplateFile, callTemplateText) + if err != nil { + return err + } + err = util.With("shared").GoFmt(true).Parse(text).SaveTo(map[string]interface{}{ "name": service.Name.Lower(), "head": head, "filePackage": service.Name.Lower(), @@ -166,7 +173,11 @@ func (g *defaultRpcGenerator) genFunction(service *parser.RpcService) ([]string, imports.AddStr(fmt.Sprintf(`%v "%v"`, pkgName, g.mustGetPackage(dirPb))) for _, method := range service.Funcs { imports.AddStr(g.ast.Imports[method.ParameterIn.Package]) - buffer, err := util.With("sharedFn").Parse(callFunctionTemplate).Execute(map[string]interface{}{ + text, err := util.LoadTemplate(category, callFunctionTemplateFile, callFunctionTemplate) + if err != nil { + return nil, nil, err + } + buffer, err := util.With("sharedFn").Parse(text).Execute(map[string]interface{}{ "rpcServiceName": service.Name.Title(), "method": method.Name.Title(), "package": pkgName, @@ -189,7 +200,12 @@ func (g *defaultRpcGenerator) getInterfaceFuncs(service *parser.RpcService) ([]s functions := make([]string, 0) for _, method := range service.Funcs { - buffer, err := util.With("interfaceFn").Parse(callInterfaceFunctionTemplate).Execute( + text, err := util.LoadTemplate(category, callInterfaceFunctionTemplateFile, callInterfaceFunctionTemplate) + if err != nil { + return nil, err + } + + buffer, err := util.With("interfaceFn").Parse(text).Execute( map[string]interface{}{ "hasComment": method.HaveDoc(), "comment": method.GetDoc(), diff --git a/tools/goctl/rpc/gen/genconfig.go b/tools/goctl/rpc/gen/genconfig.go index 466a1e11..91daf5c9 100644 --- a/tools/goctl/rpc/gen/genconfig.go +++ b/tools/goctl/rpc/gen/genconfig.go @@ -23,5 +23,11 @@ func (g *defaultRpcGenerator) genConfig() error { if util.FileExists(fileName) { return nil } - return ioutil.WriteFile(fileName, []byte(configTemplate), os.ModePerm) + + text, err := util.LoadTemplate(category, configTemplateFileFile, configTemplate) + if err != nil { + return err + } + + return ioutil.WriteFile(fileName, []byte(text), os.ModePerm) } diff --git a/tools/goctl/rpc/gen/genetc.go b/tools/goctl/rpc/gen/genetc.go index 4a655e42..c2e64b53 100644 --- a/tools/goctl/rpc/gen/genetc.go +++ b/tools/goctl/rpc/gen/genetc.go @@ -22,7 +22,12 @@ func (g *defaultRpcGenerator) genEtc() error { return nil } - return util.With("etc").Parse(etcTemplate).SaveTo(map[string]interface{}{ + text, err := util.LoadTemplate(category, etcTemplateFileFile, etcTemplate) + if err != nil { + return err + } + + return util.With("etc").Parse(text).SaveTo(map[string]interface{}{ "serviceName": g.Ctx.ServiceName.Lower(), }, fileName, false) } diff --git a/tools/goctl/rpc/gen/genlogic.go b/tools/goctl/rpc/gen/genlogic.go index b5e76435..969205ce 100644 --- a/tools/goctl/rpc/gen/genlogic.go +++ b/tools/goctl/rpc/gen/genlogic.go @@ -61,7 +61,11 @@ func (g *defaultRpcGenerator) genLogic() error { svcImport := fmt.Sprintf(`"%v"`, g.mustGetPackage(dirSvc)) imports.AddStr(svcImport) imports.AddStr(importList...) - err = util.With("logic").GoFmt(true).Parse(logicTemplate).SaveTo(map[string]interface{}{ + text, err := util.LoadTemplate(category, logicTemplateFileFile, logicTemplate) + if err != nil { + return err + } + err = util.With("logic").GoFmt(true).Parse(text).SaveTo(map[string]interface{}{ "logicName": fmt.Sprintf("%sLogic", method.Name.Title()), "functions": functions, "imports": strings.Join(imports.KeysStr(), util.NL), @@ -82,7 +86,12 @@ func (g *defaultRpcGenerator) genLogicFunction(packageName string, method *parse } imports.AddStr(g.ast.Imports[method.ParameterIn.Package]) imports.AddStr(g.ast.Imports[method.ParameterOut.Package]) - buffer, err := util.With("fun").Parse(logicFunctionTemplate).Execute(map[string]interface{}{ + text, err := util.LoadTemplate(category, logicFuncTemplateFileFile, logicFunctionTemplate) + if err != nil { + return "", nil, err + } + + buffer, err := util.With("fun").Parse(text).Execute(map[string]interface{}{ "logicName": fmt.Sprintf("%sLogic", method.Name.Title()), "method": method.Name.Title(), "request": method.ParameterIn.StarExpression, @@ -94,6 +103,7 @@ func (g *defaultRpcGenerator) genLogicFunction(packageName string, method *parse if err != nil { return "", nil, err } + functions = append(functions, buffer.String()) return strings.Join(functions, util.NL), imports.KeysStr(), nil } diff --git a/tools/goctl/rpc/gen/genmain.go b/tools/goctl/rpc/gen/genmain.go index 94f1b9f7..82f2dc25 100644 --- a/tools/goctl/rpc/gen/genmain.go +++ b/tools/goctl/rpc/gen/genmain.go @@ -58,7 +58,12 @@ func (g *defaultRpcGenerator) genMain() error { imports = append(imports, configImport, pbImport, remoteImport, svcImport) srv, registers := g.genServer(pkg, file.Service) head := util.GetHead(g.Ctx.ProtoSource) - return util.With("main").GoFmt(true).Parse(mainTemplate).SaveTo(map[string]interface{}{ + text, err := util.LoadTemplate(category, mainTemplateFile, mainTemplate) + if err != nil { + return err + } + + return util.With("main").GoFmt(true).Parse(text).SaveTo(map[string]interface{}{ "head": head, "package": pkg, "serviceName": g.Ctx.ServiceName.Lower(), diff --git a/tools/goctl/rpc/gen/genpb.go b/tools/goctl/rpc/gen/genpb.go index cd55d659..be772e34 100644 --- a/tools/goctl/rpc/gen/genpb.go +++ b/tools/goctl/rpc/gen/genpb.go @@ -18,6 +18,7 @@ const ( func (g *defaultRpcGenerator) genPb() error { pbPath := g.dirM[dirPb] + // deprecated: containsAny will be removed in the feature imports, containsAny, err := parser.ParseImport(g.Ctx.ProtoFileSrc) if err != nil { return err diff --git a/tools/goctl/rpc/gen/genserver.go b/tools/goctl/rpc/gen/genserver.go index c9d61782..a9ef3418 100644 --- a/tools/goctl/rpc/gen/genserver.go +++ b/tools/goctl/rpc/gen/genserver.go @@ -59,8 +59,14 @@ func (g *defaultRpcGenerator) genHandler() error { if err != nil { return err } + imports.AddStr(importList...) - err = util.With("server").GoFmt(true).Parse(serverTemplate).SaveTo(map[string]interface{}{ + text, err := util.LoadTemplate(category, serverTemplateFile, serverTemplate) + if err != nil { + return err + } + + err = util.With("server").GoFmt(true).Parse(text).SaveTo(map[string]interface{}{ "head": head, "types": fmt.Sprintf(typeFmt, service.Name.Title()), "server": service.Name.Title(), @@ -85,7 +91,12 @@ func (g *defaultRpcGenerator) genFunctions(service *parser.RpcService) ([]string } imports.AddStr(g.ast.Imports[method.ParameterIn.Package]) imports.AddStr(g.ast.Imports[method.ParameterOut.Package]) - buffer, err := util.With("func").Parse(functionTemplate).Execute(map[string]interface{}{ + text, err := util.LoadTemplate(category, serverFuncTemplateFile, functionTemplate) + if err != nil { + return nil, nil, err + } + + buffer, err := util.With("func").Parse(text).Execute(map[string]interface{}{ "server": service.Name.Title(), "logicName": fmt.Sprintf("%sLogic", method.Name.Title()), "method": method.Name.Title(), @@ -98,6 +109,7 @@ func (g *defaultRpcGenerator) genFunctions(service *parser.RpcService) ([]string if err != nil { return nil, nil, err } + functionList = append(functionList, buffer.String()) } return functionList, imports.KeysStr(), nil diff --git a/tools/goctl/rpc/gen/gensvc.go b/tools/goctl/rpc/gen/gensvc.go index c2315813..a1dcb3d1 100644 --- a/tools/goctl/rpc/gen/gensvc.go +++ b/tools/goctl/rpc/gen/gensvc.go @@ -25,7 +25,12 @@ func NewServiceContext(c config.Config) *ServiceContext { func (g *defaultRpcGenerator) genSvc() error { svcPath := g.dirM[dirSvc] fileName := filepath.Join(svcPath, fileServiceContext) - return util.With("svc").GoFmt(true).Parse(svcTemplate).SaveTo(map[string]interface{}{ + text, err := util.LoadTemplate(category, svcTemplateFile, svcTemplate) + if err != nil { + return err + } + + return util.With("svc").GoFmt(true).Parse(text).SaveTo(map[string]interface{}{ "imports": fmt.Sprintf(`"%v"`, g.mustGetPackage(dirConfig)), }, fileName, false) } diff --git a/tools/goctl/rpc/gen/rpctemplate.go b/tools/goctl/rpc/gen/rpctemplate.go new file mode 100644 index 00000000..daf9d016 --- /dev/null +++ b/tools/goctl/rpc/gen/rpctemplate.go @@ -0,0 +1,59 @@ +package gen + +import ( + "path/filepath" + "strings" + + "github.com/logrusorgru/aurora" + "github.com/tal-tech/go-zero/tools/goctl/util" + "github.com/tal-tech/go-zero/tools/goctl/util/console" + "github.com/tal-tech/go-zero/tools/goctl/util/stringx" +) + +const rpcTemplateText = `syntax = "proto3"; + +package {{.package}}; + +message Request { + string ping = 1; +} + +message Response { + string pong = 1; +} + +service {{.serviceName}} { + rpc Ping(Request) returns(Response); +} +` + +type rpcTemplate struct { + out string + console.Console +} + +func NewRpcTemplate(out string, idea bool) *rpcTemplate { + return &rpcTemplate{ + out: out, + Console: console.NewConsole(idea), + } +} + +func (r *rpcTemplate) MustGenerate(showState bool) { + r.Info(aurora.Blue("-> goctl rpc reference documents: ").String() + "「https://github.com/tal-tech/zero-doc/blob/main/doc/goctl-rpc.md」") + r.Info("-> generating template...") + protoFilename := filepath.Base(r.out) + serviceName := stringx.From(strings.TrimSuffix(protoFilename, filepath.Ext(protoFilename))) + text, err := util.LoadTemplate(category, rpcTemplateFile, rpcTemplateText) + r.Must(err) + + err = util.With("t").Parse(text).SaveTo(map[string]string{ + "package": serviceName.UnTitle(), + "serviceName": serviceName.Title(), + }, r.out, false) + r.Must(err) + + if showState { + r.Success("Done.") + } +} diff --git a/tools/goctl/rpc/gen/template.go b/tools/goctl/rpc/gen/template.go index ba4753e9..ccbf453f 100644 --- a/tools/goctl/rpc/gen/template.go +++ b/tools/goctl/rpc/gen/template.go @@ -1,54 +1,69 @@ package gen import ( - "path/filepath" - "strings" + "fmt" "github.com/tal-tech/go-zero/tools/goctl/util" - "github.com/tal-tech/go-zero/tools/goctl/util/console" - "github.com/tal-tech/go-zero/tools/goctl/util/stringx" + "github.com/urfave/cli" ) -const rpcTemplateText = `syntax = "proto3"; - -package {{.package}}; +const ( + category = "rpc" + callTemplateFile = "call.tpl" + callTypesTemplateFile = "call-types.tpl" + callInterfaceFunctionTemplateFile = "call-interface-func.tpl" + callFunctionTemplateFile = "call-func.tpl" + configTemplateFileFile = "config.tpl" + etcTemplateFileFile = "etc.tpl" + logicTemplateFileFile = "logic.tpl" + logicFuncTemplateFileFile = "logic-func.tpl" + mainTemplateFile = "main.tpl" + serverTemplateFile = "server.tpl" + serverFuncTemplateFile = "server-func.tpl" + svcTemplateFile = "svc.tpl" + rpcTemplateFile = "template.tpl" +) -message Request { - string ping = 1; +var templates = map[string]string{ + callTemplateFile: callTemplateText, + callTypesTemplateFile: callTemplateTypes, + callInterfaceFunctionTemplateFile: callInterfaceFunctionTemplate, + callFunctionTemplateFile: callFunctionTemplate, + configTemplateFileFile: configTemplate, + etcTemplateFileFile: etcTemplate, + logicTemplateFileFile: logicTemplate, + logicFuncTemplateFileFile: logicFunctionTemplate, + mainTemplateFile: mainTemplate, + serverTemplateFile: serverTemplate, + serverFuncTemplateFile: functionTemplate, + svcTemplateFile: svcTemplate, + rpcTemplateFile: rpcTemplateText, } -message Response { - string pong = 1; +func GenTemplates(_ *cli.Context) error { + return util.InitTemplates(category, templates) } -service {{.serviceName}} { - rpc Ping(Request) returns(Response); +func RevertTemplate(name string) error { + content, ok := templates[name] + if !ok { + return fmt.Errorf("%s: no such file name", name) + } + return util.CreateTemplate(category, name, content) } -` -type rpcTemplate struct { - out string - console.Console +func Clean() error { + return util.Clean(category) } -func NewRpcTemplate(out string, idea bool) *rpcTemplate { - return &rpcTemplate{ - out: out, - Console: console.NewConsole(idea), +func Update(category string) error { + err := Clean() + if err != nil { + return err } + return util.InitTemplates(category, templates) } -func (r *rpcTemplate) MustGenerate(showState bool) { - r.Info("查看rpc生成请移步至「https://github.com/tal-tech/zero-doc/blob/main/doc/goctl-rpc.md」") - r.Info("generating template...") - protoFilename := filepath.Base(r.out) - serviceName := stringx.From(strings.TrimSuffix(protoFilename, filepath.Ext(protoFilename))) - err := util.With("t").Parse(rpcTemplateText).SaveTo(map[string]string{ - "package": serviceName.UnTitle(), - "serviceName": serviceName.Title(), - }, r.out, false) - r.Must(err) - if showState { - r.Success("Done.") - } +func GetCategory() string { + return category } diff --git a/tools/goctl/rpc/gen/template_test.go b/tools/goctl/rpc/gen/template_test.go new file mode 100644 index 00000000..b3f21d8d --- /dev/null +++ b/tools/goctl/rpc/gen/template_test.go @@ -0,0 +1,92 @@ +package gen + +import ( + "io/ioutil" + "path/filepath" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/tal-tech/go-zero/tools/goctl/util" +) + +func TestGenTemplates(t *testing.T) { + err := util.InitTemplates(category, templates) + assert.Nil(t, err) + dir, err := util.GetTemplateDir(category) + assert.Nil(t, err) + file := filepath.Join(dir, "main.tpl") + data, err := ioutil.ReadFile(file) + assert.Nil(t, err) + assert.Equal(t, string(data), mainTemplate) +} + +func TestRevertTemplate(t *testing.T) { + name := "main.tpl" + err := util.InitTemplates(category, templates) + assert.Nil(t, err) + + dir, err := util.GetTemplateDir(category) + assert.Nil(t, err) + + file := filepath.Join(dir, name) + data, err := ioutil.ReadFile(file) + assert.Nil(t, err) + + modifyData := string(data) + "modify" + err = util.CreateTemplate(category, name, modifyData) + assert.Nil(t, err) + + data, err = ioutil.ReadFile(file) + assert.Nil(t, err) + + assert.Equal(t, string(data), modifyData) + + assert.Nil(t, RevertTemplate(name)) + + data, err = ioutil.ReadFile(file) + assert.Nil(t, err) + assert.Equal(t, mainTemplate, string(data)) +} + +func TestClean(t *testing.T) { + name := "main.tpl" + err := util.InitTemplates(category, templates) + assert.Nil(t, err) + + assert.Nil(t, Clean()) + + dir, err := util.GetTemplateDir(category) + assert.Nil(t, err) + + file := filepath.Join(dir, name) + _, err = ioutil.ReadFile(file) + assert.NotNil(t, err) +} + +func TestUpdate(t *testing.T) { + name := "main.tpl" + err := util.InitTemplates(category, templates) + assert.Nil(t, err) + + dir, err := util.GetTemplateDir(category) + assert.Nil(t, err) + + file := filepath.Join(dir, name) + data, err := ioutil.ReadFile(file) + assert.Nil(t, err) + + modifyData := string(data) + "modify" + err = util.CreateTemplate(category, name, modifyData) + assert.Nil(t, err) + + data, err = ioutil.ReadFile(file) + assert.Nil(t, err) + + assert.Equal(t, string(data), modifyData) + + assert.Nil(t, Update(category)) + + data, err = ioutil.ReadFile(file) + assert.Nil(t, err) + assert.Equal(t, mainTemplate, string(data)) +} diff --git a/tools/goctl/rpc/parser/pbast.go b/tools/goctl/rpc/parser/pbast.go index 6a5872f5..7bed50a6 100644 --- a/tools/goctl/rpc/parser/pbast.go +++ b/tools/goctl/rpc/parser/pbast.go @@ -97,6 +97,7 @@ type ( } // parsing for rpc PbAst struct { + // deprecated: containsAny will be removed in the feature ContainsAny bool Imports map[string]string Structure map[string]*Struct diff --git a/tools/goctl/rpc/parser/proto.go b/tools/goctl/rpc/parser/proto.go index e0e6f947..cf5dbea7 100644 --- a/tools/goctl/rpc/parser/proto.go +++ b/tools/goctl/rpc/parser/proto.go @@ -47,9 +47,10 @@ type ( } Proto struct { - Package string - Import []*Import - PbSrc string + Package string + Import []*Import + PbSrc string + // deprecated: containsAny will be removed in the feature ContainsAny bool Message map[string]lang.PlaceholderType Enum map[string]*Enum diff --git a/tools/goctl/tpl/templates.go b/tools/goctl/tpl/templates.go index dc647222..e10d54da 100644 --- a/tools/goctl/tpl/templates.go +++ b/tools/goctl/tpl/templates.go @@ -6,6 +6,8 @@ import ( "github.com/logrusorgru/aurora" "github.com/tal-tech/go-zero/core/errorx" "github.com/tal-tech/go-zero/tools/goctl/api/gogen" + modelgen "github.com/tal-tech/go-zero/tools/goctl/model/sql/gen" + rpcgen "github.com/tal-tech/go-zero/tools/goctl/rpc/gen" "github.com/tal-tech/go-zero/tools/goctl/util" "github.com/urfave/cli" ) @@ -17,6 +19,12 @@ func GenTemplates(ctx *cli.Context) error { func() error { return gogen.GenTemplates(ctx) }, + func() error { + return modelgen.GenTemplates(ctx) + }, + func() error { + return rpcgen.GenTemplates(ctx) + }, ); err != nil { return err } @@ -31,3 +39,64 @@ func GenTemplates(ctx *cli.Context) error { return nil } + +func CleanTemplates(_ *cli.Context) error { + err := errorx.Chain( + func() error { + return gogen.Clean() + }, + func() error { + return modelgen.Clean() + }, + func() error { + return rpcgen.Clean() + }, + ) + if err != nil { + return err + } + + fmt.Printf("%s\n", aurora.Green("template are clean!")) + return nil +} + +func UpdateTemplates(ctx *cli.Context) (err error) { + category := ctx.String("category") + defer func() { + if err == nil { + fmt.Println(aurora.Green(fmt.Sprintf("%s template are update!", category)).String()) + } + }() + switch category { + case gogen.GetCategory(): + return gogen.Update(category) + case rpcgen.GetCategory(): + return rpcgen.Update(category) + case modelgen.GetCategory(): + return modelgen.Update(category) + default: + err = fmt.Errorf("unexpected category: %s", category) + return + } +} + +func RevertTemplates(ctx *cli.Context) (err error) { + category := ctx.String("category") + filename := ctx.String("name") + defer func() { + if err == nil { + fmt.Println(aurora.Green(fmt.Sprintf("%s template are reverted!", filename)).String()) + } + }() + switch category { + case gogen.GetCategory(): + return gogen.RevertTemplate(filename) + case rpcgen.GetCategory(): + return rpcgen.RevertTemplate(filename) + case modelgen.GetCategory(): + return modelgen.RevertTemplate(filename) + default: + err = fmt.Errorf("unexpected category: %s", category) + return + } +} diff --git a/tools/goctl/util/files.go b/tools/goctl/util/files.go index 6ac20b23..3666059b 100644 --- a/tools/goctl/util/files.go +++ b/tools/goctl/util/files.go @@ -28,7 +28,7 @@ func InitTemplates(category string, templates map[string]string) error { } for k, v := range templates { - if err := createTemplate(filepath.Join(dir, k), v); err != nil { + if err := createTemplate(filepath.Join(dir, k), v, false); err != nil { return err } } @@ -36,6 +36,22 @@ func InitTemplates(category string, templates map[string]string) error { return nil } +func CreateTemplate(category, name, content string) error { + dir, err := GetTemplateDir(category) + if err != nil { + return err + } + return createTemplate(filepath.Join(dir, name), content, true) +} + +func Clean(category string) error { + dir, err := GetTemplateDir(category) + if err != nil { + return err + } + return os.RemoveAll(dir) +} + func LoadTemplate(category, file, builtin string) (string, error) { dir, err := GetTemplateDir(category) if err != nil { @@ -55,9 +71,8 @@ func LoadTemplate(category, file, builtin string) (string, error) { return string(content), nil } -func createTemplate(file, content string) error { - if FileExists(file) { - println(1) +func createTemplate(file, content string, force bool) error { + if FileExists(file) && !force { return nil }