From 73642be12c98ca8ec840779b8cc47e606ac6345e Mon Sep 17 00:00:00 2001 From: tiglog Date: Sun, 15 Oct 2023 00:33:48 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=20gen=20=E5=91=BD?= =?UTF-8?q?=E4=BB=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- console/cli_gen.go | 367 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 367 insertions(+) create mode 100644 console/cli_gen.go diff --git a/console/cli_gen.go b/console/cli_gen.go new file mode 100644 index 0000000..ff0f049 --- /dev/null +++ b/console/cli_gen.go @@ -0,0 +1,367 @@ +// +// cli_gen.go +// Copyright (C) 2023 tiglog +// +// Distributed under terms of the MIT license. +// + +package console + +import ( + "errors" + "flag" + "fmt" + "os" + "strings" + "text/template" + + "git.hexq.cn/tiglog/golib/gfile" + "git.hexq.cn/tiglog/golib/helper" +) + +type gen_cmd struct { + BaseCmd +} + +func NewGenCmd(cli IConsole) *gen_cmd { + return &gen_cmd{ + BaseCmd{ + Name: "gen", + Desc: "代码生成", + }, + } +} + +func (c *gen_cmd) Init(args []string) { + if len(args) == 0 { + return + } + name := args[0] + args = args[1:] + cmd := flag.NewFlagSet(name, flag.ExitOnError) + switch name { + case "model": + c.initModelCmd(cmd, args) + case "cmd": + c.initCmdCmd(cmd, args) + case "api": + c.initApiCmd(cmd, args) + } +} + +// model template {{{ +const tpl_ent = `package {{.name}} + +import ( + "time" + "git.hexq.cn/tiglog/golib/helper" + "git.hexq.cn/tiglog/mydb" +) + +const Table = "{{.table_name}}" + +type {{.table_ent}} struct { + Id int64 ` + "`json:\"id\" db:\"id,omitempty\"`" + ` + CreatedAt *time.Time ` + "`json:\"created_at\" db:\"created_at,omitempty\"`" + ` + UpdatedAt *time.Time ` + "`json:\"updated_at\" db:\"updated_at,omitempty\"`" + ` +} + +` + +var tpl_store = `package {{.name}} + +import ( + "git.hexq.cn/tiglog/golib/helper" + "git.hexq.cn/tiglog/mydb" +) + +var _ = interface { + mydb.Record + mydb.BeforeUpdateHook + mydb.BeforeCreateHook +}(&{{.table_ent}}{}) + +func (e *{{.table_ent}}) Store(sess mydb.Session) mydb.Store { + return sess.Collection(Table) +} + +func (e *{{.table_ent}}) BeforeCreate(sess mydb.Session) error { + if err := e.BeforeUpdate(sess); err != nil { + return err + } + e.CreatedAt = helper.GetTimeUTCPointer() + return nil +} +func (e *{{.table_ent}}) BeforeUpdate(sess mydb.Session) error { + e.UpdatedAt = helper.GetTimeUTCPointer() + return nil +} + + +type entStore struct { + mydb.Collection +} + +var _ = interface { + mydb.Store +}(&entStore{}) + +var _store *EntStore + +func RegisterStore(sess mydb.Session) *entStore { + _store = &entStore{sess.Collection(Table)} + return _store +} + +func GetStore() *entStore { + return _store +} +` + +// }}} + +func (c *gen_cmd) initModelCmd(cmd *flag.FlagSet, args []string) { + var ( + name string + table string + ) + cmd.StringVar(&name, "name", "", "实体名称, eg: sys_user") + cmd.StringVar(&table, "table", "", "数据表名称,可空, eg: sys_users") + cmd.Parse(args) + c.Action = func() error { + if name == "" { + return errors.New("name 不能为空") + } + var fp = "./innernal/models/" + name + if !gfile.Exists(fp) { + err := os.Mkdir(fp, 0755) + if err != nil { + return err + } + } + var table_ent string + if table == "" { + table_ent = helper.CamelString(name) + } + var table_names = helper.NewPluralizeClient().Plural(name) + data := map[string]string{ + "name": name, + "table_name": table_names, + "table_ent": table_ent, + } + // 创建 ent + fp_ent := fp + "/ent.go" + if gfile.Exists(fp_ent) { + fmt.Printf("SKIP for ent %s 存在\n", fp_ent) + } else { + tpl, err := template.New("ent").Parse(tpl_ent) + if err != nil { + return err + } + fd_ent, err := os.OpenFile(fp_ent, os.O_CREATE|os.O_WRONLY, os.FileMode(0644)) + if err != nil { + return err + } + defer fd_ent.Close() + err = tpl.Execute(fd_ent, data) + if err != nil { + return err + } + fmt.Printf("成功生成 ent 文件 %s\n", fp_ent) + } + + // 创建 store + fp_store := fp + "/store.go" + if gfile.Exists(fp_store) { + fmt.Printf("SKIP for store %s 存在\n", fp_store) + } else { + tpl, err := template.New("store").Parse(tpl_store) + if err != nil { + return err + } + fd_model, err := os.OpenFile(fp_store, os.O_CREATE|os.O_WRONLY, os.FileMode(0644)) + if err != nil { + return err + } + defer fd_model.Close() + err = tpl.Execute(fd_model, data) + if err != nil { + return err + } + fmt.Printf("成功生成 store 文件 %s\n", fp_store) + } + + return nil + } +} + +// cmd template {{{ +const tpl_cmd = ` +package cmds + +import ( + "flag" + "fmt" + + "git.hexq.cn/tiglog/golib/console" +) + +type {{.name}}_cmd struct { + console.BaseCmd +} + +func New{{.Name}}Cmd(cli console.IConsole) *{{.name}}_cmd { + + return &{{.name}}_cmd{ + console.BaseCmd{ + Name: "{{.name}}", + Desc: "{{.desc}}", + }, + } +} + +func (c *{{.name}}_cmd) Init(args []string) { + if len(args) == 0 { + return + } + name := args[0] + args = args[1:] + cmd := flag.NewFlagSet(name, flag.ExitOnError) + switch name { + case "foo": + c.initFooCmd(cmd, args) + } +} + +func (c *{{.name}}_cmd) initFooCmd(cmd *flag.FlagSet, args []string) { + var ( + name string + ) + cmd.StringVar(&name, "name", "", "姓名") + + cmd.Parse(args) + c.Action = func() error { + fmt.Printf("hello %s", name) + return nil + } +} +func (c *{{.name}}_cmd) GetHelp() string { + out := "{{.name}} [options]\n" + out += "sub actions:\n" + out += " foo hello world\n" + + return out +} +` + +// }}} + +func (c *gen_cmd) initCmdCmd(cmd *flag.FlagSet, args []string) { + var ( + name string + desc string + ) + cmd.StringVar(&name, "name", "", "cmd 名称") + cmd.StringVar(&desc, "desc", "", "描述") + cmd.Parse(args) + c.Action = func() error { + if name == "" || desc == "" { + return errors.New("name 和 desc 不能为空") + } + var fp = "./innernal/console/cmds/" + name + "_cmd.go" + if gfile.Exists(fp) { + return errors.New("文件已存在,不能生成") + } + tpl, err := template.New("cmd").Parse(tpl_cmd) + if err != nil { + return err + } + data := map[string]string{ + "name": name, + "Name": strings.ToUpper(name[0:1]) + name[1:], + "desc": desc, + } + fd, err := os.OpenFile(fp, os.O_CREATE|os.O_WRONLY, os.FileMode(0644)) + if err != nil { + return err + } + defer fd.Close() + err = tpl.Execute(fd, data) + if err != nil { + return err + } + fmt.Printf("成功生成 cmd 文件 %s\n", fp) + return nil + } +} + +// api template {{{ +const tpl_api = ` +package api + +import ( + "git.hexq.cn/tiglog/golib/helper" + "git.hexq.cn/tiglog/golib/gweb" +) + + +type {{.name}}_api struct { +} + +func Init{{.Name}}(app *gweb.Engine) { + ap := &{{.name}}_api{} + app.POST("/api/hello", ap.hello) +} + +func (a *{{.name}}_api) hello(c *gweb.Context) { + helper.RenderOk(c, "world") +} + +` + +// }}} + +func (c *gen_cmd) initApiCmd(cmd *flag.FlagSet, args []string) { + var ( + name string + ) + cmd.StringVar(&name, "name", "", "api 名称") + cmd.Parse(args) + c.Action = func() error { + if name == "" { + return errors.New("name 不能为空") + } + var fp = "./innernal/http/api/" + name + "_api.go" + if gfile.Exists(fp) { + return errors.New("文件已存在,不能生成") + } + tpl, err := template.New("api").Parse(tpl_api) + if err != nil { + return err + } + data := map[string]string{ + "name": name, + "Name": strings.ToUpper(name[0:1]) + name[1:], + } + fd, err := os.OpenFile(fp, os.O_CREATE|os.O_WRONLY, os.FileMode(0644)) + if err != nil { + return err + } + defer fd.Close() + err = tpl.Execute(fd, data) + if err != nil { + return err + } + fmt.Printf("成功生成 api 文件 %s\n", fp) + return nil + } +} + +func (c *gen_cmd) GetHelp() string { + out := "gen [options]\n" + out += "sub actions:\n" + out += " model 生成 model 代码\n" + out += " cmd 生成 cmd 代码\n" + out += " api 生成 api 代码\n" + return out +}