├── LICENSE ├── Makefile ├── README.md ├── cmd ├── build.go ├── clean.go ├── example.go ├── frame.go ├── fswatch.go ├── genc.go ├── gencdemo.go ├── gens.go ├── gensdemo.go ├── new.go ├── restart.go ├── reverse.go ├── shell.go ├── start.go ├── status.go ├── stop.go ├── tag.go └── tree.go ├── common └── dir.go ├── config ├── config.go ├── template.go └── tree.go ├── go.mod ├── go.sum ├── internal ├── genc_go.go ├── genc_php.go ├── gencdemo.go ├── gens.go └── gensdemo.go ├── main.go └── xorm ├── c++.go ├── go.go ├── lang.go ├── objc.go ├── render.go └── reverse.go /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | build: 3 | go build -o bin/rigger 4 | clean: 5 | rm bin/* 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rigger 2 | Very convenient scaffold components, support Gaea, Odin framework code generation, support process management, support code management 3 | 4 | ### 安装 5 | 6 | ```shell 7 | go get github.com/tal-tech/rigger 8 | ``` 9 | 10 | ### 命令介绍 11 | 12 | #### build 13 | * 用途: 14 | 15 | 编译当前项目 16 | 17 | * 命令: 18 | ```shell 19 | rigger build 20 | ``` 21 | * 说明: 22 | 23 | 命令为在当前路径下执行make,需在项目根路径下执行,且要求Makefile一定存在 24 | 25 | 26 | #### clean 27 | * 用途: 28 | 29 | 清理当前项目编译产生文件 30 | 31 | * 命令: 32 | ```shell 33 | rigger clean 34 | ``` 35 | * 说明: 36 | 37 | 命令为在当前路径下执行make clean,Makefile应设置clean target 38 | 39 | #### example 40 | * 用途: 41 | 42 | 执行项目路径下examples的实例代码 43 | 44 | * 命令: 45 | ```shell 46 | rigger example [tags] 47 | ``` 48 | * 说明: 49 | 50 | 命令为在当前路径下执行go run examles/main.go,需要存在main.go文件,且执行时自动使用项目下conf部分项目,如xesMicro,编译时需要加入tags,此时指定第三个参数 51 | 52 | #### genc 53 | * 用途: 54 | 55 | 生成rpc服务sdk代码 56 | 57 | * 命令: 58 | ```shell 59 | rigger genc [go|php] yourservice [flags] 60 | ``` 61 | * 说明: 62 | 63 | * 命令通过Micro服务项目下指定路径app/rpc内的Service定义,生成对应调用sdk 64 | 65 | * 可生成go和php两种语言sdk,yourservice为rpc服务的项目名 66 | 67 | * 生成sdk路径为当前路径下rpc文件夹内,部分代码如下图: 68 | 69 |           70 | flag说明 71 | 72 | * -b, --basepath string service BasePath (default "xes_xueyan_hudong") 73 | 74 | * -i, --importpath string service proto import path (default "git.100tal.com/wangxiao_xueyan_hudong/common") 75 | 76 | * -p, --projectpath string your project path 77 | ``` 78 | BasePath为在注册中心中注册服务的前缀,可区分服务组,-b 参数修改默认值 79 | 80 | Importpath是sdk内引用服务公共代码,参数结构体proto路径,如图,为importpath/[servicename]/proto,-i 参数修改默认值 81 | 82 | projectpath为指定Micro服务端项目路径,默认值为$GOPATH/[servicename],如不在此路径下,需通过-p 参数指定 83 | ``` 84 | 85 | #### gens 86 | * 用途: 87 | 88 | 生成rpc服务层代码 89 | 90 | * 命令: 91 | ```shell 92 | rigger gens yourservice [flags] 93 | ``` 94 | * 说明: 95 | 96 | * rpc项目目录下执行,根据app/serviceInterfece/interface.go定义对外方法,一键生成项目代码,只填入逻辑代码即可 97 | 98 | 99 | #### help 100 | * 用途: 101 | 102 | 同 -h 103 | 104 | * 命令: 105 | 106 | ```shell 107 | rigger help 108 | ``` 109 | 110 | #### new 111 | * 用途: 112 | 113 | 根据工程模板创建项目 114 | 115 | * 命令: 116 | ```shell 117 | rigger new [rpc|api|async|proxy|custom] servicename [flags] 118 | ``` 119 | * 说明: 120 | * 命令可通过clone模板生成新的项目 121 | 122 | * servicename为新生成项目名,生成路径为$GOPATH/servicename 123 | 124 | * 目前模板可支持rpc服务odin(rpc)、api服务gaea(api)、异步消费服务asyncworker(async)、MQProxy服务(proxy) 125 | 126 | * 新生成项目内都附有简单demo,可通过rigger start、rigger example测试 127 | 128 | * custom生成自定义模板项目,-g gitlib地址,-d 默认项目待替换名称 -t 默认项目待替换为大写名称 129 | 130 | #### start 131 | * 用途: 132 | 133 | 启动项目 134 | 135 | * 命令: 136 | ```shell 137 | rigger start 138 | ``` 139 | * 说明: 140 | 141 | * 命令需在项目根路径下执行,启动服务为后台启动 142 | 143 | * 启动后会在当前路径下创建run/servername.pid文件,stop、status命令均通过pid进行操作 144 | 145 | * -f foreground 指定在前台运行 146 | 147 | 148 | 149 | #### status 150 | * 用途: 151 | 152 | 当前服务的运行状态 153 | 154 | * 命令: 155 | ```shell 156 | rigger status 157 | ``` 158 | * 说明: 159 | 160 | 命令执行路径下需存在run/servername.pid文件 161 | 162 | #### stop 163 | * 用途: 164 | 165 | 停止项目 166 | 167 | * 命令: 168 | ```shell 169 | rigger stop 170 | ``` 171 | * 说明: 172 | 173 | 命令执行路径下需存在run/servername.pid文件 174 | 175 | 176 | #### restart 177 | * 用途: 178 | 179 | 重启项目 180 | 181 | * 命令: 182 | ```shell 183 | rigger restart [flags] 184 | ``` 185 | 186 | * 说明: 187 | 188 | 命令执行路径下需存在run/servername.pid文件 189 | 190 | -r flag执行顺序为stop、build、start,方便调试 191 | 192 | 193 | 194 | #### tag 195 | * 用途: 196 | 197 | 用git tag对项目进行标签操作 198 | 199 | * 命令: 200 | ```shell 201 | rigger tag [subcommand] [flags] 202 | ``` 203 | * 说明: 204 | 205 | tag命令,需指定子命令 206 | 207 | * init 初始化一个tag 208 | 209 | * now 展示当前tag 210 | 211 | * push 推送到远端 212 | 213 | * up 升级tag,使用up x或up y或up z 214 | 215 | `up子命令,项目推荐使用go标准tag格式,为vX.Y.Z,如v1.1.1,up命令后跟x、y、z,升级指定位置` 216 | 217 | 218 | #### fswatch 219 | * 用途: 220 | 221 | 开发过程,watch文件变化,自动重新编译、重启 222 | 223 | * 命令: 224 | ``` 225 | rigger fswatch 226 | ``` 227 | 228 | * 说明: 229 | 230 | 需先安装fswatch,go get github.com/codeskyblue/fswatch 231 | 232 | 目前支持gaea和odin框架,请确认版本,可用版本为目录下有.fsw.yml,或从最新版内copy 233 | 234 | 停止命令使用rigger stop 235 | 236 | #### frame 237 | * 用途: 238 | 239 | gaea&odin 启动项插件化管理,命令添加可选插件 240 | 241 | * 命令: 242 | ``` 243 | rigger frame [Plugin|Middleware] (pprof/perf/expvar/maxfd|perf/trace) 244 | ``` 245 | 246 | * 说明: 247 | 248 | 支持gaea&odin的启动插件,以及gaea框架中的http中间件 249 | 250 | 插件包括pprof性能分析插件、perf耗时打点插件、expvr内存分析插件、maxfd最大文件打开数管理 251 | 252 | 253 | #### reverse 254 | * 用途: 255 | 256 | 一键生成MySQL表对象实体文件 257 | 258 | * 命令: 259 | ``` 260 | rigger reverse [-s] [-t tmplPath] driverName datasourceName [generatedPath] [tableFilterReg] 261 | ``` 262 | 263 | * 说明: 264 | 265 | -s 指定是否生成单一文件 266 | 267 | -t 指定生成模板,不指定使用默认模板 268 | 269 | generatedPath 生成文件目录 270 | 271 | tableFilterReg 表名匹配过滤 272 | 273 | #### tree 274 | * 用途: 275 | 276 | 查看golang生态组件 277 | 278 | * 命令: 279 | ``` 280 | rigger tree 281 | rigger trem [name] 282 | ``` 283 | 284 | * 说明: 285 | 286 | rigger tree命令查看所有golang组件 287 | 288 | rigger tree 组件名,可查看组件详情并下载组件 289 | 290 | 291 | ### 联系我们 292 |

293 | 294 | Contact Us 295 | 296 |

297 |

298 | (微信扫一扫,申请加入开发讨论微信群) 299 |

300 | -------------------------------------------------------------------------------- /cmd/build.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "os" 7 | osexec "os/exec" 8 | 9 | "github.com/spf13/cobra" 10 | "github.com/tal-tech/rigger/common" 11 | ) 12 | 13 | var Build = &cobra.Command{ 14 | Use: "build", 15 | Short: "使用makefile编译项目", 16 | Run: build, 17 | SilenceUsage: true, 18 | SilenceErrors: true, 19 | } 20 | 21 | func build(c *cobra.Command, args []string) { 22 | exists, err := common.PathExists("Makefile") 23 | if err != nil { 24 | fmt.Fprintln(os.Stdout, err) 25 | return 26 | } 27 | if !exists { 28 | fmt.Fprintln(os.Stdout, "没有发现makefile文件") 29 | return 30 | } 31 | 32 | cmd := osexec.Command("make", args...) 33 | 34 | var buffer bytes.Buffer 35 | cmd.Stderr = &buffer 36 | 37 | output, err := cmd.Output() 38 | 39 | handlerCmdOutput(output, err, buffer) 40 | return 41 | } 42 | -------------------------------------------------------------------------------- /cmd/clean.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "os" 7 | osexec "os/exec" 8 | 9 | "github.com/spf13/cobra" 10 | "github.com/tal-tech/rigger/common" 11 | ) 12 | 13 | var Clean = &cobra.Command{ 14 | Use: "clean", 15 | Short: "清理编译产生的文件", 16 | Run: clean, 17 | SilenceUsage: true, 18 | SilenceErrors: true, 19 | } 20 | 21 | func clean(c *cobra.Command, args []string) { 22 | exists, err := common.PathExists("Makefile") 23 | if err != nil { 24 | fmt.Fprintln(os.Stdout, err) 25 | return 26 | } 27 | if !exists { 28 | fmt.Fprintln(os.Stdout, "没有发现makefile文件") 29 | return 30 | } 31 | 32 | cmd := osexec.Command("make", "clean") 33 | 34 | var buffer bytes.Buffer 35 | cmd.Stderr = &buffer 36 | 37 | output, err := cmd.Output() 38 | 39 | handlerCmdOutput(output, err, buffer) 40 | return 41 | } 42 | -------------------------------------------------------------------------------- /cmd/example.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "bytes" 5 | osexec "os/exec" 6 | 7 | "github.com/spf13/cobra" 8 | "github.com/tal-tech/rigger/common" 9 | ) 10 | 11 | var Example = &cobra.Command{ 12 | Use: "example [tags]", 13 | Short: "运行example目录中的调用示例", 14 | Run: example, 15 | SilenceUsage: true, 16 | SilenceErrors: true, 17 | } 18 | 19 | func example(c *cobra.Command, args []string) { 20 | 21 | var tag string 22 | 23 | if len(args) > 0 { 24 | tag = args[0] 25 | } 26 | 27 | serviceName, _ := common.GetServiceName() 28 | 29 | arg := `go run -tags "` + tag + `" ` + getServiceDir(serviceName) + `/examples/main.go` + 30 | ` -p=` + getServiceDir(serviceName) + ` -c=conf/conf.ini` 31 | 32 | cmd := osexec.Command("/bin/sh", "-c", arg) 33 | 34 | var buffer bytes.Buffer 35 | cmd.Stderr = &buffer 36 | 37 | output, err := cmd.Output() 38 | 39 | handlerCmdOutput(output, err, buffer) 40 | return 41 | } 42 | -------------------------------------------------------------------------------- /cmd/frame.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "os" 7 | osexec "os/exec" 8 | 9 | "github.com/spf13/cobra" 10 | "github.com/tal-tech/rigger/common" 11 | ) 12 | 13 | var Frame = &cobra.Command{ 14 | Use: "frame", 15 | Short: "管理框架插件", 16 | Long: "请使用rigger frame [Plugin|Middleware] name(pprof/perf/expvar/maxfd|perf/trace)", 17 | Run: frame, 18 | SilenceUsage: true, 19 | SilenceErrors: true, 20 | } 21 | 22 | func frame(c *cobra.Command, args []string) { 23 | if len(args) <= 1 { 24 | fmt.Fprintln(os.Stdout, "请使用rigger frame [Plugin|Middleware] name(pprof/perf/expvar/maxfd|perf/trace)") 25 | return 26 | } 27 | 28 | serviceName, _ := common.GetServiceName() 29 | 30 | addType := args[0] 31 | 32 | name := args[1] 33 | 34 | var replaceContent string 35 | switch addType { 36 | case "Plugin": 37 | replaceContent = getPlugin(name) 38 | case "Middleware": 39 | replaceContent = getMiddleware(name) 40 | default: 41 | fmt.Fprintln(os.Stdout, "请使用rigger frame [Plugin|Middleware] name(pprof/perf/expvar/maxfd|perf/trace)") 42 | return 43 | } 44 | 45 | if replaceContent == "" { 46 | fmt.Fprintln(os.Stdout, "请使用rigger frame [Plugin|Middleware] name(pprof/perf/expvar/maxfd|perf/trace)") 47 | return 48 | } 49 | 50 | command := sedI() + ` '\/\/Optional ` + addType + `/a\\t` + replaceContent + `' cmd/` + serviceName + `/main.go` 51 | 52 | cmd := osexec.Command("/bin/sh", "-c", command) 53 | 54 | var buffer bytes.Buffer 55 | cmd.Stderr = &buffer 56 | 57 | output, err := cmd.Output() 58 | 59 | handlerCmdOutput(output, err, buffer) 60 | return 61 | } 62 | 63 | func getPlugin(name string) string { 64 | switch name { 65 | case "pprof": 66 | return `s.AddBeforeServerStartFunc(bs.InitPprof())` 67 | case "perf": 68 | return `s.AddBeforeServerStartFunc(bs.InitPerfutil())` 69 | case "expvar": 70 | return `s.AddBeforeServerStartFunc(bs.InitExpvar())` 71 | case "maxfd": 72 | return `s.AddBeforeServerStartFunc(bs.InitMaxFd())` 73 | default: 74 | return "" 75 | } 76 | } 77 | 78 | func getMiddleware(name string) string { 79 | switch name { 80 | case "trace": 81 | return `engine.Use(middleware.TraceMiddleware())` 82 | case "perf": 83 | return `engine.Use(middleware.PerfMiddleware())` 84 | default: 85 | return "" 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /cmd/fswatch.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "os" 7 | osexec "os/exec" 8 | "strconv" 9 | "time" 10 | 11 | "github.com/spf13/cobra" 12 | "github.com/tal-tech/rigger/common" 13 | ) 14 | 15 | var Fswatch = &cobra.Command{ 16 | Use: "fswatch", 17 | Short: "启动项目并watch", 18 | Run: fswatch, 19 | SilenceUsage: true, 20 | SilenceErrors: true, 21 | } 22 | 23 | func fswatch(c *cobra.Command, args []string) { 24 | var buffer bytes.Buffer 25 | cmd := osexec.Command("which", "fswatch") 26 | cmd.Stdout = &buffer 27 | cmd.Stderr = os.Stdout 28 | err := cmd.Run() 29 | if err != nil { 30 | fmt.Fprintf(os.Stdout, "未找到fswatch,请先安装fswatch(go get github.com/codeskyblue/fswatch)\n") 31 | return 32 | } 33 | fsPath := buffer.String() 34 | if fsPath == "" { 35 | fmt.Fprintf(os.Stdout, "请先安装fswatch(go get github.com/codeskyblue/fswatch)\n") 36 | return 37 | } 38 | curdir, err := common.GetCurPath() 39 | 40 | if err != nil { 41 | fmt.Fprintln(os.Stdout, err) 42 | } 43 | 44 | serviceName, err := common.GetServiceName() 45 | if err != nil { 46 | fmt.Fprintln(os.Stdout, err) 47 | } 48 | 49 | detail, exist := processExistByName(serviceName) 50 | if exist { 51 | fmt.Fprintf(os.Stdout, "服务:%s 已启动,详细信息如下\n===============================\n%s", 52 | serviceName, detail) 53 | return 54 | } 55 | 56 | cmd = osexec.Command("fswatch") 57 | cmd.Stdout = os.Stdout 58 | cmd.Stderr = os.Stdout 59 | err = cmd.Start() 60 | if err != nil { 61 | fmt.Fprintf(os.Stdout, "启动失败 %v\n", err) 62 | return 63 | } 64 | pid := strconv.Itoa(cmd.Process.Pid) 65 | 66 | if Foreground { 67 | fmt.Fprintf(os.Stdout, "启动成功pid:%s\n", pid) 68 | cmd.Wait() 69 | } 70 | 71 | pinfo, _ := getProcessByPid(pid) 72 | if pinfo != "" { 73 | fmt.Fprintf(os.Stdout, "启动失败\n") 74 | return 75 | } 76 | 77 | pidFile, _ := getPidFile() 78 | 79 | err = common.CreateDir(curdir + "/run/") 80 | 81 | if err != nil { 82 | fmt.Fprintf(os.Stdout, "创建run目录失败 %v\n", err) 83 | return 84 | } 85 | 86 | f, err := os.OpenFile(pidFile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600) 87 | if err != nil { 88 | fmt.Fprintf(os.Stdout, "创建pid文件失败 %v\n", err) 89 | return 90 | } 91 | defer f.Close() 92 | 93 | f.WriteString(pid) 94 | time.Sleep(time.Second) 95 | fmt.Fprintf(os.Stdout, "启动成功pid:%s\n", pid) 96 | } 97 | -------------------------------------------------------------------------------- /cmd/genc.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "os" 7 | "strings" 8 | 9 | "github.com/spf13/cobra" 10 | "github.com/tal-tech/rigger/common" 11 | "github.com/tal-tech/rigger/internal" 12 | ) 13 | 14 | var BasePath string 15 | 16 | var ProjectPath string 17 | 18 | var ImportPath string 19 | 20 | var Genc = &cobra.Command{ 21 | Use: "genc [go|php] yourservice", 22 | Short: "生成sdk代码", 23 | Run: genc, 24 | SilenceUsage: true, 25 | SilenceErrors: true, 26 | } 27 | 28 | func genc(c *cobra.Command, args []string) { 29 | if len(args) < 2 { 30 | fmt.Fprintln(os.Stdout, "请使用rigger genc php yourservice 或rigger genc go yourservice 命令来生成客户端代码") 31 | return 32 | } 33 | 34 | code := args[0] 35 | 36 | serviceName := args[1] 37 | 38 | curDir, _ := common.GetCurPath() 39 | 40 | newrpcfile := "service/service.go" 41 | 42 | oldrpcfile := "rpc/" + serviceName + ".go" 43 | 44 | rpcFile := os.Getenv("GOPATH") + "/src/" + serviceName + "/app/" 45 | if ProjectPath != "" { 46 | rpcFile = strings.TrimRight(ProjectPath, serviceName) + "/" + serviceName + "/app/" 47 | } 48 | if ok, _ := common.PathExists(rpcFile + oldrpcfile); ok { 49 | rpcFile = rpcFile + oldrpcfile 50 | } else { 51 | // Support search current path 52 | if ok, _ := common.PathExists(curDir + "/app/" + newrpcfile); ok { 53 | rpcFile = curDir + "/app/" + newrpcfile 54 | } else { 55 | rpcFile = rpcFile + newrpcfile 56 | } 57 | } 58 | ImportPath = strings.TrimRight(ImportPath, serviceName) 59 | 60 | var buffer *bytes.Buffer 61 | 62 | var outputFile string 63 | 64 | var err error 65 | 66 | if code == "php" { 67 | common.CreateDir(curDir + "/http/") 68 | outputFile = curDir + "/http/" + serviceName + ".go" 69 | buffer, err = internal.GenPHPHttpClient(rpcFile) 70 | outputFile = strings.TrimRight(outputFile, ".go") 71 | outputFile = outputFile + ".php" 72 | } else if code == "go" { 73 | common.CreateDir(curDir + "/rpc/") 74 | outputFile = curDir + "/rpc/" + serviceName + ".go" 75 | buffer, err = internal.GenGoRpcClient(rpcFile, BasePath, ImportPath) 76 | } 77 | 78 | if err != nil { 79 | fmt.Fprintf(os.Stdout, "生成代码失败 %v\n", err) 80 | } 81 | 82 | err = common.WriteToFile(buffer, outputFile, false) 83 | 84 | if err != nil { 85 | fmt.Fprintf(os.Stdout, "生成代码失败 %v\n", err) 86 | } 87 | 88 | fmt.Fprintln(os.Stdout, "客户端代码生成成功:"+outputFile) 89 | return 90 | 91 | } 92 | -------------------------------------------------------------------------------- /cmd/gencdemo.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | 7 | "github.com/spf13/cobra" 8 | "github.com/tal-tech/rigger/common" 9 | "github.com/tal-tech/rigger/internal" 10 | ) 11 | 12 | var Gencdemo = &cobra.Command{ 13 | Use: "gencdemo yourservice", 14 | Short: "生成client端proto及api调用代码", 15 | Run: gencdemo, 16 | SilenceUsage: true, 17 | SilenceErrors: true, 18 | } 19 | 20 | func gencdemo(c *cobra.Command, args []string) { 21 | if len(args) < 1 { 22 | fmt.Fprintln(os.Stdout, "请使用rigger gencdemo yourservice") 23 | return 24 | } 25 | 26 | serviceName := args[0] 27 | 28 | curDir, _ := common.GetCurPath() 29 | 30 | interfaceFile := curDir + "/app/serviceInterface/interface.go" 31 | if ProjectPath != "" { 32 | interfaceFile = ProjectPath + "/app/serviceInterface/interface.go" 33 | } 34 | 35 | parseResult, err := internal.GenParseResult(interfaceFile) 36 | if err != nil { 37 | fmt.Fprintf(os.Stdout, "解析interface.go文件失败:%v,请在项目根目录下执行rigger gensproto", err) 38 | return 39 | } 40 | 41 | common.CreateDir(curDir + "/proto") 42 | buffer := internal.GenClientProto(parseResult, serviceName) 43 | serviceFile := curDir + "/proto/rpc.go" 44 | common.WriteToFile(buffer, serviceFile, true) 45 | 46 | buffer = internal.GenApiRouter(parseResult, serviceName) 47 | serviceFile = curDir + "/app/router/router.go" 48 | common.WriteToFile(buffer, serviceFile, true) 49 | 50 | buffer = internal.GenApiController(parseResult, serviceName) 51 | serviceFile = curDir + "/app/controller/demo/rpc.go" 52 | common.WriteToFile(buffer, serviceFile, true) 53 | 54 | buffer = internal.GenApiService(parseResult, serviceName) 55 | serviceFile = curDir + "/app/service/demo/rpc.go" 56 | common.WriteToFile(buffer, serviceFile, true) 57 | return 58 | 59 | } 60 | -------------------------------------------------------------------------------- /cmd/gens.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "os" 7 | "strings" 8 | 9 | "github.com/spf13/cobra" 10 | "github.com/tal-tech/rigger/common" 11 | "github.com/tal-tech/rigger/internal" 12 | ) 13 | 14 | var Gens = &cobra.Command{ 15 | Use: "gens yourservice", 16 | Short: "生成service代码", 17 | Run: gens, 18 | SilenceUsage: true, 19 | SilenceErrors: true, 20 | } 21 | 22 | func gens(c *cobra.Command, args []string) { 23 | if len(args) < 1 { 24 | fmt.Fprintln(os.Stdout, "请使用rigger gens yourservice") 25 | return 26 | } 27 | 28 | serviceName := args[0] 29 | 30 | curDir, _ := common.GetCurPath() 31 | 32 | interfaceFile := curDir + "/app/serviceInterface/interface.go" 33 | 34 | parseResult, err := internal.GenParseResult(interfaceFile) 35 | if err != nil { 36 | fmt.Fprintf(os.Stdout, "解析interface.go文件失败:%v,请在项目根目录下执行rigger gens", err) 37 | return 38 | } 39 | 40 | common.CreateDir(curDir + "/app/service/") 41 | buffer := internal.GenService(parseResult, serviceName) 42 | serviceFile := curDir + "/app/service/service.go" 43 | common.WriteToFile(buffer, serviceFile, true) 44 | buffer = internal.GenServiceBridge(parseResult) 45 | serviceBridgeFile := curDir + "/app/service/serviceBridge.go" 46 | common.WriteToFile(buffer, serviceBridgeFile, true) 47 | buffer = internal.GenServiceInit(parseResult, serviceName) 48 | serviceInitFile := curDir + "/app/serviceInit.go" 49 | common.WriteToFile(buffer, serviceInitFile, true) 50 | 51 | //Impl File 52 | fileBuffer := make(map[string]*bytes.Buffer, 0) 53 | for _, fn := range parseResult.Fns { 54 | buffer, ok := fileBuffer[fn.Comment] 55 | if !ok { 56 | buffer = internal.GenImplFile(parseResult.Imports, fn) 57 | fileBuffer[fn.Comment] = buffer 58 | } 59 | buffer.WriteString(internal.GenImplFunc(fn)) 60 | } 61 | for k, b := range fileBuffer { 62 | filename := strings.TrimLeft(k, "//") 63 | filename = strings.Replace(filename, ".", "/", -1) 64 | last := strings.LastIndex(filename, "/") 65 | if last > 0 { 66 | common.CreateDir(curDir + "/app/serviceImpl/" + filename[:last]) 67 | filename = filename[:last] + "/" + string((filename[last+1] + 32)) + filename[last+2:] 68 | } else { 69 | filename = string((filename[0] + 32)) + filename[1:] 70 | } 71 | filename = filename + ".go" 72 | common.WriteToFile(b, curDir+"/app/serviceImpl/"+filename, false) 73 | } 74 | return 75 | 76 | } 77 | -------------------------------------------------------------------------------- /cmd/gensdemo.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | 7 | "github.com/spf13/cobra" 8 | "github.com/tal-tech/rigger/common" 9 | "github.com/tal-tech/rigger/internal" 10 | ) 11 | 12 | var Gensdemo = &cobra.Command{ 13 | Use: "gensdemo yourservice", 14 | Short: "生成server端proto代码", 15 | Run: gensdemo, 16 | SilenceUsage: true, 17 | SilenceErrors: true, 18 | } 19 | 20 | func gensdemo(c *cobra.Command, args []string) { 21 | if len(args) < 1 { 22 | fmt.Fprintln(os.Stdout, "请使用rigger gensdemo yourservice") 23 | return 24 | } 25 | 26 | serviceName := args[0] 27 | 28 | curDir, _ := common.GetCurPath() 29 | 30 | interfaceFile := curDir + "/app/serviceInterface/interface.go" 31 | 32 | parseResult, err := internal.GenParseResult(interfaceFile) 33 | if err != nil { 34 | fmt.Fprintf(os.Stdout, "解析interface.go文件失败:%v,请在项目根目录下执行rigger gensproto", err) 35 | return 36 | } 37 | 38 | common.CreateDir(curDir + "/proto") 39 | buffer := internal.GenServerProto(parseResult, serviceName) 40 | serviceFile := curDir + "/proto/demo.go" 41 | common.WriteToFile(buffer, serviceFile, true) 42 | return 43 | 44 | } 45 | -------------------------------------------------------------------------------- /cmd/new.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "os" 7 | osexec "os/exec" 8 | "runtime" 9 | "strings" 10 | 11 | "github.com/spf13/cobra" 12 | "github.com/tal-tech/rigger/common" 13 | "github.com/tal-tech/rigger/config" 14 | ) 15 | 16 | var New = &cobra.Command{ 17 | Use: "new [rpc|api|async|proxy|job|custom] [servicename]", 18 | Short: "根据工程模板创建项目(job会在当前目录下生成)", 19 | Long: "请使用rigger new templateName(rpc/api/async/proxy/job/custom) yourServiceName", 20 | Run: new, 21 | SilenceUsage: true, 22 | SilenceErrors: true, 23 | } 24 | 25 | var DefaultName string 26 | 27 | var TitleName string 28 | 29 | var GitUrl string 30 | 31 | var DefaultReplacer *strings.Replacer 32 | 33 | func init() { 34 | DefaultReplacer = strings.NewReplacer("\t", "", "\r", "", "\n", "", ".", "", "-", "") 35 | } 36 | 37 | func Filter(msg string) string { 38 | replacer := DefaultReplacer 39 | return replacer.Replace(msg) 40 | } 41 | 42 | var newProjectInfo config.NewProjectInfo 43 | 44 | func new(c *cobra.Command, args []string) { 45 | if len(args) <= 1 { 46 | fmt.Fprintln(os.Stdout, "请使用rigger new templateName(rpc/api/async/proxy/custom) yourServiceName") 47 | return 48 | } 49 | serviceName := Filter(args[1]) 50 | templatename := args[0] 51 | 52 | switch templatename { 53 | case "rpc": 54 | newProjectInfo = config.NewOdinInfo 55 | case "api": 56 | newProjectInfo = config.NewGaeaInfo 57 | case "async": 58 | newProjectInfo = config.NewTritonInfo 59 | case "proxy": 60 | newProjectInfo = config.NewPanInfo 61 | case "job": 62 | newProjectInfo = config.NewJobInfo 63 | newJobPro(serviceName) 64 | return 65 | case "custom": 66 | if GitUrl == "" { 67 | fmt.Fprintln(os.Stdout, "请通过-g指定模板项目git地址") 68 | return 69 | } 70 | newProjectInfo.TplRepo = GitUrl 71 | if DefaultName != "" { 72 | newProjectInfo.ReplaceContent = append(newProjectInfo.ReplaceContent, config.ReplaceContentItem{DefaultName, config.DefaultReplaceName}) 73 | } 74 | if TitleName != "" { 75 | newProjectInfo.ReplaceContent = append(newProjectInfo.ReplaceContent, config.ReplaceContentItem{TitleName, config.TitleReplaceName}) 76 | } 77 | 78 | default: 79 | fmt.Fprintln(os.Stdout, "请使用rigger new templateName(rpc/api/async/proxy/custom) yourServiceName") 80 | return 81 | } 82 | 83 | exists, _ := common.PathExists(getServiceDir(serviceName)) 84 | 85 | if exists { 86 | fmt.Fprintf(os.Stdout, "项目(%s)已存在\n", getServiceDir(serviceName)) 87 | } 88 | 89 | if err := cloneTpl(serviceName); err != nil { 90 | fmt.Println(err) 91 | return 92 | } 93 | 94 | if err := cleanGitFile(serviceName); err != nil { 95 | fmt.Println(err) 96 | return 97 | } 98 | 99 | if err := replaceContent(serviceName); err != nil { 100 | fmt.Println(err) 101 | return 102 | } 103 | 104 | if err := replaceDir(serviceName); err != nil { 105 | fmt.Println(err) 106 | return 107 | } 108 | 109 | replaceFile(serviceName) 110 | 111 | fmt.Fprintln(os.Stdout, serviceName+"项目已创建完成, 使用:\n cd "+getServiceDir(serviceName)+" && rigger build \n开始你的微服务之旅!") 112 | return 113 | } 114 | 115 | func cloneTpl(serviceName string) error { 116 | //todo 放入gopath 117 | arg := "git clone " + newProjectInfo.TplRepo + " " + getServiceDir(serviceName) 118 | cmd := osexec.Command("/bin/sh", "-c", arg) 119 | 120 | var buffer bytes.Buffer 121 | cmd.Stderr = &buffer 122 | 123 | output, err := cmd.Output() 124 | handlerCmdOutput(output, err, buffer) 125 | 126 | return err 127 | } 128 | 129 | func cleanGitFile(serviceName string) error { 130 | arg := "pushd " + getServiceDir(serviceName) + "&& rm -rf .git && popd" 131 | cmd := osexec.Command("/bin/sh", "-c", arg) 132 | 133 | var buffer bytes.Buffer 134 | cmd.Stderr = &buffer 135 | 136 | _, err := cmd.Output() 137 | 138 | handlerCmdOutput([]byte{}, err, buffer) 139 | 140 | return err 141 | } 142 | 143 | func replaceContent(serviceName string) error { 144 | for _, item := range newProjectInfo.ReplaceContent { 145 | arg := `grep '` + item.Key + `' -rl ` + getServiceDir(serviceName) + `|xargs ` + sedI() + ` 's/` + item.Key + `/` + item.Fn(serviceName) + `/g'` 146 | 147 | cmd := osexec.Command("/bin/sh", "-c", arg) 148 | 149 | var buffer bytes.Buffer 150 | cmd.Stderr = &buffer 151 | 152 | output, err := cmd.Output() 153 | 154 | handlerCmdOutput(output, err, buffer) 155 | 156 | if err != nil { 157 | return err 158 | } 159 | } 160 | return nil 161 | } 162 | 163 | func replaceFile(serviceName string) error { 164 | for key, _ := range newProjectInfo.ReplaceFile { 165 | arg := `pushd ` + getServiceDir(serviceName) + 166 | `&&find . -name '` + key + `.go' |awk -F "` + key + `.go" '{print $1}' |` + 167 | `xargs -I'{}' mv {}` + key + `.go {}` + serviceName + `.go&&popd` 168 | 169 | cmd := osexec.Command("/bin/sh", "-c", arg) 170 | 171 | var buffer bytes.Buffer 172 | cmd.Stderr = &buffer 173 | 174 | _, err := cmd.Output() 175 | 176 | handlerCmdOutput([]byte{}, err, buffer) 177 | } 178 | return nil 179 | } 180 | 181 | func replaceDir(serviceName string) error { 182 | for key, _ := range newProjectInfo.ReplaceDir { 183 | arg := `pushd ` + getServiceDir(serviceName) + 184 | `&&find . -name '` + key + `' -type d |awk -F "` + key + `" '{print $1}'| ` + 185 | `xargs -I'{}' mv {}` + key + ` {}` + serviceName + `&&popd` 186 | 187 | cmd := osexec.Command("/bin/sh", "-c", arg) 188 | 189 | var buffer bytes.Buffer 190 | cmd.Stderr = &buffer 191 | 192 | _, err := cmd.Output() 193 | 194 | handlerCmdOutput([]byte{}, err, buffer) 195 | } 196 | return nil 197 | } 198 | 199 | func sedI() string { 200 | if runtime.GOOS == config.MacOS { 201 | return `sed -i ""` 202 | } else { 203 | return `sed -i` 204 | } 205 | } 206 | 207 | func getServiceDir(serviceName string) string { 208 | if strings.TrimSpace(os.Getenv("GOPATH")) != "" { 209 | return os.Getenv("GOPATH") + "/src/" + serviceName 210 | } 211 | return "./" + serviceName 212 | } 213 | 214 | func newJobPro(serviceName string) { 215 | //仅克隆jobWorker 216 | exist, _ := pathExists(serviceName) 217 | if exist { 218 | handlerCmdOutput([]byte("["+serviceName+"] 此目录已存在!\n"), nil, bytes.Buffer{}) 219 | return 220 | } 221 | 222 | tempDir := "/tmp/" + serviceName 223 | arg := "git clone " + newProjectInfo.TplRepo + " " + tempDir 224 | cmd := osexec.Command("/bin/sh", "-c", arg) 225 | 226 | var buffer bytes.Buffer 227 | cmd.Stderr = &buffer 228 | output, err := cmd.Output() 229 | handlerCmdOutput(output, err, buffer) 230 | if err != nil { 231 | return 232 | } 233 | 234 | buffer.Reset() 235 | shellCmd := `mv ` + tempDir + `/clijob/jobWorker ` + serviceName + " && rm -rf " + tempDir 236 | cmd = osexec.Command("/bin/sh", "-c", shellCmd) 237 | output, err = cmd.Output() 238 | handlerCmdOutput(output, err, buffer) 239 | if err != nil { 240 | return 241 | } 242 | 243 | fmt.Fprintln(os.Stdout, serviceName+" Job server 已生成!") 244 | } 245 | 246 | func pathExists(path string) (bool, error) { 247 | _, err := os.Stat(path) 248 | if err == nil { 249 | return true, nil 250 | } 251 | if os.IsNotExist(err) { 252 | return false, nil 253 | } 254 | return false, err 255 | } 256 | -------------------------------------------------------------------------------- /cmd/restart.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/spf13/cobra" 7 | ) 8 | 9 | var Restart = &cobra.Command{ 10 | Use: "restart", 11 | Short: "重启项目", 12 | Run: restart, 13 | SilenceUsage: true, 14 | SilenceErrors: true, 15 | } 16 | 17 | var Rebuild bool 18 | 19 | func restart(c *cobra.Command, args []string) { 20 | stop(c, args) 21 | time.Sleep(time.Millisecond * 500) 22 | if Rebuild { 23 | args = []string{} 24 | build(c, args) 25 | } 26 | time.Sleep(time.Millisecond * 500) 27 | start(c, args) 28 | } 29 | -------------------------------------------------------------------------------- /cmd/reverse.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | 7 | "github.com/spf13/cobra" 8 | "github.com/tal-tech/rigger/xorm" 9 | ) 10 | 11 | var ( 12 | ReverseSingle bool 13 | ReverseTmplPath string 14 | ) 15 | 16 | var Reverse = &cobra.Command{ 17 | Use: "reverse", 18 | Short: "一键生成MySQL表对象实体文件", 19 | Long: "reverse [-s] [-t tmplPath] driverName datasourceName [generatedPath] [tableFilterReg]", 20 | Run: runReverse, 21 | SilenceUsage: true, 22 | SilenceErrors: true, 23 | //Args: cobra.MinimumNArgs(2), 24 | } 25 | 26 | func runReverse(cmd *cobra.Command, args []string) { 27 | if len(args) < 2 { 28 | fmt.Fprintln(os.Stdout, "请使用rigger reverse [-s] [-t tmplPath] driverName datasourceName [generatedPath] [tableFilterReg]") 29 | return 30 | } 31 | c := xorm.NewReverse( 32 | xorm.SetReverseSingle(ReverseSingle), 33 | xorm.SetReverseTmplPath(ReverseTmplPath), 34 | ) 35 | c.Run(cmd, args) 36 | } 37 | -------------------------------------------------------------------------------- /cmd/shell.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "bytes" 5 | osexec "os/exec" 6 | ) 7 | 8 | func shell(args []string) { 9 | cmdargs := "" 10 | for _, arg := range args { 11 | cmdargs = cmdargs + " " + arg 12 | } 13 | cmd := osexec.Command("/bin/bash", "-c", cmdargs) 14 | 15 | var buffer bytes.Buffer 16 | cmd.Stderr = &buffer 17 | 18 | output, err := cmd.Output() 19 | 20 | handlerCmdOutput(output, err, buffer) 21 | } 22 | -------------------------------------------------------------------------------- /cmd/start.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "os" 7 | osexec "os/exec" 8 | "strconv" 9 | "time" 10 | 11 | "github.com/spf13/cobra" 12 | "github.com/tal-tech/rigger/common" 13 | ) 14 | 15 | var Start = &cobra.Command{ 16 | Use: "start", 17 | Short: "启动项目", 18 | Run: start, 19 | SilenceUsage: true, 20 | SilenceErrors: true, 21 | } 22 | 23 | var Foreground bool 24 | 25 | func start(c *cobra.Command, args []string) { 26 | curdir, err := common.GetCurPath() 27 | 28 | if err != nil { 29 | fmt.Fprintln(os.Stdout, err) 30 | } 31 | 32 | serviceName, err := common.GetServiceName() 33 | if err != nil { 34 | fmt.Fprintln(os.Stdout, err) 35 | } 36 | 37 | pfile, _ := getPidFile() 38 | pidstr, err := ioutil.ReadFile(pfile) 39 | if err == nil { 40 | pid := string(pidstr) 41 | detail, err := getProcessByPid(pid) 42 | if detail != "" && err == nil { 43 | fmt.Fprintf(os.Stdout, "服务:%s 已启动,详细信息如下\n===============================\n%s", 44 | serviceName, detail) 45 | return 46 | } 47 | } 48 | 49 | arg := curdir + `/bin/` + serviceName 50 | 51 | if len(args) == 0 { 52 | args = append(args, "-p="+curdir, "-c=conf/conf.ini") 53 | } else { 54 | arg = args[0] 55 | args = args[1:] 56 | } 57 | 58 | cmd := osexec.Command(arg, args...) 59 | cmd.Stdout = os.Stdout 60 | cmd.Stderr = os.Stdout 61 | err = cmd.Start() 62 | if err != nil { 63 | fmt.Fprintf(os.Stdout, "启动失败 %v\n", err) 64 | return 65 | } 66 | pid := strconv.Itoa(cmd.Process.Pid) 67 | 68 | if Foreground { 69 | fmt.Fprintf(os.Stdout, "启动成功pid:%s\n", pid) 70 | cmd.Wait() 71 | } 72 | 73 | pinfo, _ := getProcessByPid(pid) 74 | if pinfo == "" { 75 | fmt.Fprintf(os.Stdout, "启动失败\n") 76 | return 77 | } 78 | 79 | pidFile, _ := getPidFile() 80 | 81 | err = common.CreateDir(curdir + "/run/") 82 | 83 | if err != nil { 84 | fmt.Fprintf(os.Stdout, "创建run目录失败 %v\n", err) 85 | return 86 | } 87 | 88 | f, err := os.OpenFile(pidFile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600) 89 | if err != nil { 90 | fmt.Fprintf(os.Stdout, "创建pid文件失败 %v\n", err) 91 | return 92 | } 93 | defer f.Close() 94 | 95 | f.WriteString(pid) 96 | time.Sleep(time.Second) 97 | fmt.Fprintf(os.Stdout, "启动成功pid:%s\n", pid) 98 | } 99 | 100 | func getProcessByPid(pid string) (string, error) { 101 | arg := `ps aux |grep ` + pid + ` |grep -v grep` 102 | 103 | cmd := osexec.Command("/bin/sh", "-c", arg) 104 | 105 | output, err := cmd.Output() 106 | 107 | return string(output), err 108 | } 109 | 110 | func processExistByName(name string) (string, bool) { 111 | arg := `ps aux |grep ` + name + ` |grep -v grep` 112 | 113 | cmd := osexec.Command("/bin/sh", "-c", arg) 114 | 115 | output, err := cmd.Output() 116 | 117 | return string(output), err == nil 118 | } 119 | -------------------------------------------------------------------------------- /cmd/status.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | osexec "os/exec" 7 | 8 | "github.com/spf13/cobra" 9 | ) 10 | 11 | var Status = &cobra.Command{ 12 | Use: "status", 13 | Short: "当前服务的运行状态", 14 | Run: status, 15 | SilenceUsage: true, 16 | SilenceErrors: true, 17 | } 18 | 19 | func status(c *cobra.Command, args []string) { 20 | pidFile, _ := getPidFile() 21 | 22 | pid, err := readPid(pidFile) 23 | 24 | if err != nil { 25 | fmt.Fprint(os.Stdout, "读取pid失败 %v\n", err) 26 | return 27 | } 28 | 29 | arg := `ps aux |grep ` + pid + ` |grep -v grep` 30 | 31 | cmd := osexec.Command("/bin/sh", "-c", arg) 32 | 33 | output, err := cmd.Output() 34 | 35 | if err != nil { 36 | fmt.Fprintln(os.Stdout, "服务未启动,可以使用rigger start 启动你的服务") 37 | return 38 | } 39 | fmt.Fprint(os.Stdout, string(output)) 40 | return 41 | } 42 | -------------------------------------------------------------------------------- /cmd/stop.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "os" 7 | osexec "os/exec" 8 | "strings" 9 | 10 | "github.com/spf13/cobra" 11 | "github.com/tal-tech/rigger/common" 12 | ) 13 | 14 | var Stop = &cobra.Command{ 15 | Use: "stop", 16 | Short: "停止项目", 17 | Run: stop, 18 | SilenceUsage: true, 19 | SilenceErrors: true, 20 | } 21 | 22 | func stop(c *cobra.Command, args []string) { 23 | pidFile, err := getPidFile() 24 | if err != nil { 25 | fmt.Fprintf(os.Stdout, "获取pid文件失败 %v\n", err) 26 | return 27 | } 28 | 29 | pid, err := readPid(pidFile) 30 | if err != nil { 31 | fmt.Fprintf(os.Stdout, "读取pid失败 %v\n", err) 32 | return 33 | } 34 | 35 | cmd := osexec.Command("kill", pid) 36 | cmd.Stdout = os.Stdout 37 | cmd.Stderr = os.Stdout 38 | 39 | err = cmd.Start() 40 | 41 | if err != nil { 42 | fmt.Fprintf(os.Stdout, "停止失败 %v\n", err) 43 | return 44 | } 45 | err = cmd.Wait() 46 | if err != nil { 47 | fmt.Fprintf(os.Stdout, "停止失败 %v\n", err) 48 | return 49 | } 50 | 51 | serviceName, _ := common.GetServiceName() 52 | fmt.Fprintln(os.Stdout, "进程"+serviceName+"(pid:"+string(pid)+")已停止") 53 | return 54 | } 55 | 56 | func getPidFile() (string, error) { 57 | curdir, err := common.GetCurPath() 58 | 59 | if err != nil { 60 | return "", err 61 | } 62 | 63 | serviceName, err := common.GetServiceName() 64 | if err != nil { 65 | return "", err 66 | } 67 | 68 | pidFile := curdir + "/run/" + serviceName + ".pid" 69 | 70 | return pidFile, nil 71 | } 72 | 73 | func readPid(pidFile string) (string, error) { 74 | f, err := os.OpenFile(pidFile, os.O_RDONLY, 0600) 75 | if err != nil { 76 | //fmt.Fprintf(os.Stdout, "读取pid文件失败 %v\n", err) 77 | return "", err 78 | } 79 | 80 | defer f.Close() 81 | 82 | pid, err := ioutil.ReadAll(f) 83 | if err != nil { 84 | //fmt.Fprintf(os.Stdout, "获取pid失败 %v", err) 85 | return "", err 86 | } 87 | 88 | return strings.TrimSpace(string(pid)), nil 89 | } 90 | -------------------------------------------------------------------------------- /cmd/tag.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "bytes" 5 | "errors" 6 | "fmt" 7 | "os" 8 | osexec "os/exec" 9 | "strconv" 10 | "strings" 11 | 12 | "github.com/spf13/cobra" 13 | ) 14 | 15 | var Tag = &cobra.Command{ 16 | Use: "tag", 17 | Short: "使用git tag给项目打标签", 18 | //Run: printHelpInfo, 19 | RunE: func(c *cobra.Command, args []string) error { 20 | return c.Usage() 21 | }, 22 | } 23 | 24 | var TagNow = &cobra.Command{ 25 | Use: "now", 26 | Short: "展示当前tag", 27 | Run: showVersionNow, 28 | SilenceUsage: true, 29 | SilenceErrors: true, 30 | } 31 | 32 | var TagUp = &cobra.Command{ 33 | Use: "up", 34 | Short: "升级tag,使用up x或up y或up z", 35 | Run: upgradeVersion, 36 | SilenceUsage: true, 37 | SilenceErrors: true, 38 | } 39 | 40 | var TagPush = &cobra.Command{ 41 | Use: "push", 42 | Short: "推送到远端", 43 | Run: pushToRemote, 44 | SilenceUsage: true, 45 | SilenceErrors: true, 46 | } 47 | 48 | var TagInit = &cobra.Command{ 49 | Use: "init", 50 | Short: "初始化一个tag", 51 | Run: initTag, 52 | SilenceUsage: true, 53 | SilenceErrors: true, 54 | } 55 | 56 | func init() { 57 | Tag.AddCommand(TagNow) 58 | Tag.AddCommand(TagUp) 59 | Tag.AddCommand(TagPush) 60 | Tag.AddCommand(TagInit) 61 | } 62 | 63 | /* 64 | var ( 65 | prompt = "rigger-tag > " 66 | tagCmds = map[string]*Command{ 67 | "now": &Command{"now", "展示当前tag", showVersionNow}, 68 | "up": &Command{"up", "升级tag,使用up x或up y或up z", upgradeVersion}, 69 | "push": &Command{"push", "推送到远端", pushToRemote}, 70 | "exit": &Command{"exit", "退出命令行模式", exitCli}, 71 | "init": &Command{"init", "初始化一个tag", initTag}, 72 | } 73 | ) 74 | 75 | func tag(args []string) { 76 | printHelpInfo() 77 | r, err := readline.New(prompt) 78 | 79 | if err != nil { 80 | fmt.Fprint(os.Stdout, err) 81 | os.Exit(1) 82 | } 83 | 84 | defer r.Close() 85 | 86 | if err := fetch(); err != nil { 87 | os.Exit(1) 88 | } 89 | 90 | for { 91 | 92 | args, err := r.Readline() 93 | if err != nil { 94 | fmt.Fprint(os.Stdout, err) 95 | 96 | return 97 | } 98 | 99 | args = strings.TrimSpace(args) 100 | 101 | // skip no args 102 | if len(args) == 0 { 103 | continue 104 | } 105 | 106 | parts := strings.Split(args, " ") 107 | if len(parts) == 0 { 108 | continue 109 | } 110 | 111 | name := parts[0] 112 | 113 | // get alias 114 | if n, ok := alias[name]; ok { 115 | name = n 116 | } 117 | 118 | if cmd, ok := tagCmds[name]; ok { 119 | cmd.exec(parts[1:]) 120 | } else { 121 | helpTagCmd(parts[1:]) 122 | } 123 | } 124 | } 125 | */ 126 | 127 | func printHelpInfo(c *cobra.Command, args []string) { 128 | fmt.Fprintln(os.Stdout, "=====================================================") 129 | fmt.Fprintln(os.Stdout, " version format v1.0.0") 130 | fmt.Fprintln(os.Stdout, " x.y.z") 131 | fmt.Fprintln(os.Stdout, " | | |--->修复bug或者添加小功能") 132 | fmt.Fprintln(os.Stdout, " | |----->添加较大功能") 133 | fmt.Fprintln(os.Stdout, " |------->重构项目或项目有重大更新") 134 | fmt.Fprintln(os.Stdout, "=====================================================") 135 | } 136 | 137 | /* 138 | func helpTagCmd(args []string) { 139 | w := tabwriter.NewWriter(os.Stdout, 0, 8, 1, '\t', 0) 140 | 141 | fmt.Fprintln(os.Stdout, "Commands(用于管理tag号):") 142 | 143 | var keys []string 144 | for k, _ := range tagCmds { 145 | keys = append(keys, k) 146 | } 147 | sort.Strings(keys) 148 | 149 | for _, k := range keys { 150 | cmd := tagCmds[k] 151 | fmt.Fprintln(w, "\t", cmd.name, "\t\t", cmd.usage) 152 | } 153 | 154 | w.Flush() 155 | } 156 | */ 157 | // version v1.0.0 158 | func showNextVersion(next string) { 159 | fmt.Fprintf(os.Stdout, "即将更新tag到%s\n", next) 160 | } 161 | 162 | func upgradeVersion(c *cobra.Command, args []string) { 163 | if len(args) == 0 { 164 | fmt.Fprintln(os.Stdout, errors.New("请使用up x,up y或up z")) 165 | return 166 | } 167 | 168 | output, err := getVersionNow() 169 | 170 | if err != nil { 171 | fmt.Fprint(os.Stdout, err) 172 | return 173 | } 174 | 175 | if err := checkVersionFormat(output); err != nil { 176 | fmt.Fprintln(os.Stdout, err) 177 | return 178 | } 179 | 180 | branch, err := getBranch() 181 | if err != nil { 182 | fmt.Fprintf(os.Stdout, "获取当前分支失败 %v\n", err) 183 | return 184 | } 185 | if strings.Trim(string(branch), "\n") != "master" { 186 | fmt.Fprintln(os.Stdout, errors.New("必须在master分支更新tag")) 187 | return 188 | } 189 | next, err := getNextVersion(output, args[0]) 190 | if err != nil { 191 | fmt.Fprintln(os.Stdout, err) 192 | return 193 | } 194 | showNextVersion(next) 195 | 196 | arg := `git tag -a ` + next + ` -m "更新版本到"` + next 197 | cmd := osexec.Command("/bin/sh", "-c", arg) 198 | var buffer bytes.Buffer 199 | cmd.Stderr = &buffer 200 | 201 | output, err = cmd.Output() 202 | 203 | handlerCmdOutput(output, err, buffer) 204 | 205 | nowversion, _ := getVersionNow() 206 | 207 | fmt.Fprintf(os.Stdout, "当前tag已更新到%s\n", nowversion) 208 | } 209 | 210 | func getNextVersion(now []byte, arg string) (string, error) { 211 | var next string 212 | //去掉换行符 213 | now = bytes.Trim(now, "\n") 214 | //去掉v 215 | version := fmt.Sprintf("%s", now[1:]) 216 | //分割 217 | vers := strings.Split(version, ".") 218 | 219 | if len(vers) != 3 { 220 | return "", errors.New("tag格式错误") 221 | } 222 | 223 | var err error 224 | var x, y, z int 225 | if arg == "x" { 226 | x, err = strconv.Atoi(vers[0]) 227 | x++ 228 | vers[0] = strconv.Itoa(x) 229 | } else if arg == "y" { 230 | y, err = strconv.Atoi(vers[1]) 231 | y++ 232 | vers[1] = strconv.Itoa(y) 233 | } else if arg == "z" { 234 | z, err = strconv.Atoi(vers[2]) 235 | z++ 236 | vers[2] = strconv.Itoa(z) 237 | } 238 | 239 | if err != nil { 240 | return "", err 241 | } 242 | 243 | next = "v" + vers[0] + "." + vers[1] + "." + vers[2] 244 | 245 | return next, nil 246 | } 247 | 248 | func pushToRemote(c *cobra.Command, args []string) { 249 | arg := `git push origin --tags` 250 | cmd := osexec.Command("/bin/sh", "-c", arg) 251 | 252 | var buffer bytes.Buffer 253 | cmd.Stderr = &buffer 254 | 255 | output, err := cmd.Output() 256 | 257 | handlerCmdOutput(output, err, buffer) 258 | 259 | fmt.Fprintln(os.Stdout, "已推送所有tag到远端仓库") 260 | } 261 | 262 | func exitCli(args []string) { 263 | os.Exit(0) 264 | } 265 | 266 | func showVersionNow(c *cobra.Command, args []string) { 267 | output, err := getVersionNow() 268 | 269 | handlerCmdOutput(output, err, bytes.Buffer{}) 270 | } 271 | 272 | func initTag(c *cobra.Command, args []string) { 273 | output, err := getVersionNow() 274 | if err != nil { 275 | fmt.Fprintln(os.Stdout, err) 276 | return 277 | } 278 | 279 | if len(output) > 0 { 280 | fmt.Fprintf(os.Stdout, "tag已经存在,无需初始化\n") 281 | return 282 | } 283 | 284 | arg := `git tag -a v0.0.1 -m "初始化tag"` 285 | cmd := osexec.Command("/bin/sh", "-c", arg) 286 | 287 | var buffer bytes.Buffer 288 | cmd.Stderr = &buffer 289 | 290 | output, err = cmd.Output() 291 | 292 | handlerCmdOutput(output, err, buffer) 293 | 294 | fmt.Fprintln(os.Stdout, "tag已经初始完成") 295 | } 296 | 297 | func getVersionNow() ([]byte, error) { 298 | arg := "git tag -l | sort -rV|head -n 1" 299 | //arg := "git tag -l --sort=-v:refname |head -n 1" 300 | cmd := osexec.Command("/bin/sh", "-c", arg) 301 | output, err := cmd.Output() 302 | 303 | return output, err 304 | } 305 | 306 | func handlerCmdOutput(output []byte, err error, buffer bytes.Buffer) { 307 | 308 | if err != nil { 309 | fmt.Fprintln(os.Stdout, err) 310 | fmt.Fprintln(os.Stdout, buffer.String()) 311 | return 312 | } 313 | 314 | fmt.Fprint(os.Stdout, string(output)) 315 | } 316 | 317 | func checkVersionFormat(version []byte) error { 318 | if len(version) == 0 { 319 | return errors.New("当前还没有tag") 320 | } 321 | 322 | if string(version[0]) != "v" { 323 | return errors.New("tag格式非法") 324 | } 325 | 326 | return nil 327 | } 328 | 329 | func fetch() error { 330 | arg := "git fetch -p" 331 | cmd := osexec.Command("/bin/sh", "-c", arg) 332 | var buffer bytes.Buffer 333 | cmd.Stderr = &buffer 334 | 335 | output, err := cmd.Output() 336 | 337 | handlerCmdOutput(output, err, buffer) 338 | 339 | if err != nil { 340 | return err 341 | } 342 | 343 | return nil 344 | } 345 | 346 | func getBranch() ([]byte, error) { 347 | arg := `git branch |grep \* |awk '{print $2}'` 348 | //arg := "git symbolic-ref --short -q HEAD" 349 | 350 | cmd := osexec.Command("/bin/sh", "-c", arg) 351 | output, err := cmd.Output() 352 | 353 | return output, err 354 | } 355 | -------------------------------------------------------------------------------- /cmd/tree.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "os" 7 | osexec "os/exec" 8 | 9 | "github.com/spf13/cobra" 10 | "github.com/tal-tech/rigger/config" 11 | ) 12 | 13 | var Tree = &cobra.Command{ 14 | Use: "tree", 15 | Short: "查看golang生态组件", 16 | Run: tree, 17 | SilenceUsage: true, 18 | SilenceErrors: true, 19 | } 20 | 21 | func tree(c *cobra.Command, args []string) { 22 | if len(args) == 0 { 23 | printAll() 24 | fmt.Fprintln(os.Stdout, "-----------------------------------") 25 | fmt.Fprintln(os.Stdout, "请使用rigger tree name查看详情") 26 | } else { 27 | name := args[0] 28 | var module config.ModuleInfo 29 | for _, m := range config.Modules { 30 | if m.Name == name { 31 | module = m 32 | break 33 | } 34 | } 35 | if module.Name != "" { 36 | fmt.Printf("%s:%s\n", module.Name, module.Describe) 37 | if module.MainPage != "" { 38 | fmt.Printf("文档地址:%s\n", module.MainPage) 39 | } 40 | fmt.Printf("git地址:%s\n", module.GitPath) 41 | if module.Summary != "" { 42 | fmt.Printf("%s\n", module.Summary) 43 | } 44 | } 45 | if module.GoGet != "" { 46 | fmt.Fprintln(os.Stdout, "------------------------") 47 | fmt.Fprintln(os.Stdout, "确认是否下载(go get)当前组件 y/n ?") 48 | var input string 49 | fmt.Scanln(&input) 50 | 51 | if input == "y" { 52 | cmd := osexec.Command("go", "get", module.GoGet) 53 | 54 | var buffer bytes.Buffer 55 | cmd.Stderr = &buffer 56 | 57 | output, err := cmd.Output() 58 | 59 | handlerCmdOutput(output, err, buffer) 60 | } 61 | } 62 | } 63 | return 64 | } 65 | 66 | func printAll() { 67 | for _, m := range config.Modules { 68 | fmt.Printf("%s: %s\n", m.Name, m.Describe) 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /common/dir.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "os" 7 | "path/filepath" 8 | ) 9 | 10 | func GetServiceName() (string, error) { 11 | cur, err := GetCurPath() 12 | if err != nil { 13 | return "", err 14 | } 15 | 16 | return filepath.Base(cur), nil 17 | } 18 | 19 | func GetCurPath() (string, error) { 20 | dir, err := os.Getwd() 21 | if err != nil { 22 | return "", err 23 | } 24 | 25 | return dir, nil 26 | } 27 | 28 | func PathExists(path string) (bool, error) { 29 | _, err := os.Stat(path) 30 | if err == nil { 31 | return true, nil 32 | } 33 | if os.IsNotExist(err) { 34 | return false, nil 35 | } 36 | return false, err 37 | } 38 | 39 | func CreateDir(path string) error { 40 | exist, err := PathExists(path) 41 | if err != nil { 42 | return err 43 | } 44 | 45 | if exist { 46 | return nil 47 | } 48 | 49 | return os.MkdirAll(path, os.ModePerm) 50 | } 51 | 52 | func WriteToFile(buffer *bytes.Buffer, outputFile string, force bool) error { 53 | exists, _ := PathExists(outputFile) 54 | if exists && !force { 55 | var override string 56 | fmt.Fprint(os.Stdout, "文件("+outputFile+")已存在,是否需要覆盖(Y/y,默认不覆盖)? ") 57 | fmt.Scanln(&override) 58 | 59 | if override != "Y" && override != "y" { 60 | fmt.Fprintln(os.Stdout, "略过"+outputFile) 61 | return nil 62 | } 63 | } 64 | 65 | f, err := os.OpenFile(outputFile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600) 66 | 67 | if err != nil { 68 | return err 69 | } 70 | defer f.Close() 71 | 72 | f.WriteString(buffer.String()) 73 | 74 | return nil 75 | } 76 | -------------------------------------------------------------------------------- /config/config.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import "strings" 4 | 5 | const ( 6 | MacOS = "darwin" 7 | ) 8 | 9 | type GetReplaceNameFn func(string) string 10 | 11 | type ReplaceContentItem struct { 12 | Key string 13 | Fn GetReplaceNameFn 14 | } 15 | 16 | type NewProjectInfo struct { 17 | TplRepo string 18 | ReplaceContent []ReplaceContentItem 19 | ReplaceFile map[string]string 20 | ReplaceDir map[string]string 21 | } 22 | 23 | var NewOdinInfo NewProjectInfo = NewProjectInfo{ 24 | TplRepo: "https://github.com/tal-tech/odin.git", 25 | ReplaceContent: []ReplaceContentItem{ReplaceContentItem{"encoding", skipTemplateName}, ReplaceContentItem{"odinPlugin", skipTemplateNameOdin}, ReplaceContentItem{"odin", DefaultReplaceName}, ReplaceContentItem{"Odin", TitleReplaceName}, ReplaceContentItem{"#TemplateName#", recoverEncoding}, ReplaceContentItem{"#TemplateName2#", recoverOdinPlugin}}, 26 | ReplaceFile: map[string]string{"odin": ""}, 27 | ReplaceDir: map[string]string{"odin": ""}, 28 | } 29 | 30 | var NewGaeaInfo NewProjectInfo = NewProjectInfo{ 31 | TplRepo: "https://github.com/tal-tech/gaea.git", 32 | ReplaceContent: []ReplaceContentItem{ReplaceContentItem{"gaea", DefaultReplaceName}, ReplaceContentItem{"Gaea", TitleReplaceName}}, 33 | ReplaceFile: map[string]string{"gaea": ""}, 34 | ReplaceDir: map[string]string{"gaea": ""}, 35 | } 36 | 37 | var NewTritonInfo NewProjectInfo = NewProjectInfo{ 38 | TplRepo: "https://github.com/tal-tech/triton.git", 39 | ReplaceContent: []ReplaceContentItem{ReplaceContentItem{"triton", DefaultReplaceName}}, 40 | ReplaceFile: map[string]string{}, 41 | ReplaceDir: map[string]string{}, 42 | } 43 | 44 | var NewPanInfo NewProjectInfo = NewProjectInfo{ 45 | TplRepo: "https://github.com/tal-tech/pan.git", 46 | ReplaceContent: []ReplaceContentItem{{"panic", skipTemplateName}, {"pan", DefaultReplaceName}, {"#TemplateName#", recoverPanic}}, 47 | ReplaceFile: map[string]string{}, 48 | ReplaceDir: map[string]string{}, 49 | } 50 | 51 | var NewJobInfo NewProjectInfo = NewProjectInfo{ 52 | TplRepo: "https://github.com/tal-tech/hera.git", 53 | ReplaceContent: []ReplaceContentItem{}, 54 | ReplaceFile: map[string]string{}, 55 | ReplaceDir: map[string]string{}, 56 | } 57 | 58 | func DefaultReplaceName(in string) string { 59 | return in 60 | } 61 | 62 | func TitleReplaceName(in string) string { 63 | return strings.Title(in) 64 | } 65 | 66 | func skipTemplateName(in string) string { 67 | return "#TemplateName#" 68 | } 69 | 70 | func skipTemplateNameOdin(in string) string { 71 | return "#TemplateName2#" 72 | } 73 | 74 | func recoverEncoding(in string) string { 75 | return "encoding" 76 | } 77 | 78 | func recoverPanic(in string) string { 79 | return "panic" 80 | } 81 | 82 | func recoverOdinPlugin(in string) string { 83 | return "odinPlugin" 84 | } 85 | 86 | func DefaultXormConfig() map[string]string { 87 | return map[string]string{ 88 | "lang": "go", 89 | "genJson": "1", 90 | "prefix": "cos_", 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /config/template.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | type XormTpl struct { 4 | FileName string 5 | Ext string 6 | Content string 7 | } 8 | 9 | func GetDefaultXormTpl() []XormTpl { 10 | return []XormTpl{ 11 | XormTpl{ 12 | FileName: "struct.go", 13 | Ext: ".go", 14 | Content: GetXormGOTpl(), 15 | }, 16 | } 17 | } 18 | 19 | func GetXormGOTpl() string { 20 | return `package torm 21 | 22 | {{$ilen := len .Imports}} 23 | import ( 24 | {{range .Imports}}"{{.}}"{{end}} 25 | "github.com/tal-tech/torm" 26 | ) 27 | 28 | {{range .Tables}} 29 | {{$tb := Mapper .Name}} 30 | {{$table := .}} 31 | {{$dao := printf "%sDao" $tb}} 32 | 33 | type {{$tb}} struct { 34 | {{range .ColumnsSeq}}{{$col := $table.GetColumn .}} {{Mapper $col.Name}} {{Type $col}} {{Tag $table $col}} 35 | {{end}} 36 | } 37 | 38 | type {{$dao}} struct { 39 | torm.DbBaseDao 40 | } 41 | 42 | func New{{$dao}}(v ...interface{}) *{{$dao}} { 43 | this := new({{$dao}}) 44 | if ins := torm.GetDbInstance("default", "writer"); ins != nil { 45 | this.UpdateEngine(ins.Engine) 46 | } else { 47 | return nil 48 | } 49 | if len(v) != 0 { 50 | this.UpdateEngine(v...) 51 | } 52 | return this 53 | } 54 | 55 | {{$pl := len .PrimaryKeys}} 56 | {{if gt $pl 0}} 57 | func (this *{{$dao}})Get({{genParams $table .PrimaryKeys true}}) (ret []{{$tb}}, err error) { 58 | ret = make([]{{$tb}},0) 59 | this.InitSession() 60 | {{range .PrimaryKeys}} 61 | {{$p := Mapper .}} 62 | this.BuildQuery(m{{$p}}, "{{.}}") 63 | {{end}} 64 | err = this.Session.Find(&ret) 65 | return 66 | } 67 | func (this *{{$dao}})GetLimit({{genParams $table .PrimaryKeys true}}, pn, rn int) (ret []{{$tb}}, err error) { 68 | ret = make([]{{$tb}},0) 69 | this.InitSession() 70 | {{range .PrimaryKeys}} 71 | {{$p := Mapper .}} 72 | this.BuildQuery(m{{$p}}, "{{.}}") 73 | {{end}} 74 | err = this.Session.Limit(rn,pn).Find(&ret) 75 | return 76 | } 77 | func (this *{{$dao}})GetCount({{genParams $table .PrimaryKeys true}}) (ret int64, err error) { 78 | this.InitSession() 79 | {{range .PrimaryKeys}} 80 | {{$p := Mapper .}} 81 | this.BuildQuery(m{{$p}}, "{{.}}") 82 | {{end}} 83 | ret, err = this.Session.Count(new({{$tb}})) 84 | return 85 | } 86 | {{end}} 87 | 88 | {{range .Indexes}} 89 | func (this *{{$dao}})GetByIdx{{getMethodName .Name}}({{genParams $table .Cols true}}) (ret []{{$tb}}, err error) { 90 | ret = make([]{{$tb}},0) 91 | this.InitSession() 92 | {{range .Cols}} 93 | {{$p := Mapper .}} 94 | this.BuildQuery(m{{$p}}, "{{.}}") 95 | {{end}} 96 | err = this.Session.Find(&ret) 97 | return 98 | } 99 | func (this *{{$dao}})GetByIdx{{getMethodName .Name}}Count({{genParams $table .Cols true}}) (ret int64, err error) { 100 | this.InitSession() 101 | {{range .Cols}} 102 | {{$p := Mapper .}} 103 | this.BuildQuery(m{{$p}}, "{{.}}") 104 | {{end}} 105 | ret, err = this.Session.Count(new({{$tb}})) 106 | return 107 | } 108 | func (this *{{$dao}})GetByIdx{{getMethodName .Name}}Limit({{genParams $table .Cols true}}, pn,rn int) (ret []{{$tb}}, err error) { 109 | ret = make([]{{$tb}},0) 110 | this.InitSession() 111 | {{range .Cols}} 112 | {{$p := Mapper .}} 113 | this.BuildQuery(m{{$p}}, "{{.}}") 114 | {{end}} 115 | err = this.Session.Limit(rn,pn).Find(&ret) 116 | return 117 | } 118 | {{end}} 119 | 120 | {{end}} 121 | 122 | ` 123 | } 124 | -------------------------------------------------------------------------------- /config/tree.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | type ModuleInfo struct { 4 | Name string 5 | Describe string 6 | Summary string 7 | MainPage string 8 | GitPath string 9 | GoGet string 10 | } 11 | 12 | var Modules []ModuleInfo 13 | 14 | func init() { 15 | Modules = make([]ModuleInfo, 0) 16 | Modules = append(Modules, gaea) 17 | Modules = append(Modules, odin) 18 | Modules = append(Modules, pan) 19 | Modules = append(Modules, triton) 20 | Modules = append(Modules, redis) 21 | Modules = append(Modules, mysql) 22 | Modules = append(Modules, logger) 23 | Modules = append(Modules, hera) 24 | Modules = append(Modules, tools) 25 | Modules = append(Modules, microPlugin) 26 | } 27 | 28 | var gaea ModuleInfo = ModuleInfo{Name: "gaea", Describe: "简单好用,高性能Web框架", MainPage: "", GitPath: "https://github.com/tal-tech/gaea", Summary: "请使用:rigger new api yourservicename 创建新的API项目"} 29 | var odin ModuleInfo = ModuleInfo{Name: "odin", Describe: "高性能RPC服务框架,使用简单,功能强大,界面化管理", MainPage: "", GitPath: "https://github.com/tal-tech/odin", Summary: "请使用:rigger new micro yourservicename 创建新的RPC项目"} 30 | var pan ModuleInfo = ModuleInfo{Name: "pan", Describe: "[MQ生产管家]高性能高稳定MQ代理服务", MainPage: "", GitPath: "https://github.com/tal-tech/pan"} 31 | var triton ModuleInfo = ModuleInfo{Name: "triton", Describe: "[MQ消费管家]高性能,高稳定,模板化配置,插件化接入,多样化处理机制,分布式支持", MainPage: "", GitPath: "https://github.com/tal-tech/triton", Summary: "请使用:rigger new async yourservicename 创建新的队列消费项目"} 32 | var redis ModuleInfo = ModuleInfo{Name: "xredis", Describe: "[redis管家,redis客户端]高性能,高稳定,简单接入,灵活管理", MainPage: "", GitPath: "https://github.com/tal-tech/xredis", GoGet: "github.com/tal-tech/xredis"} 33 | var mysql ModuleInfo = ModuleInfo{Name: "torm", Describe: "[mysql管家,mysql客户端]高性能,高稳定,配置灵活,上手简单", MainPage: "", GitPath: "https://github.com/tal-tech/torm", GoGet: "github.com/tal-tech/torm"} 34 | var logger ModuleInfo = ModuleInfo{Name: "loggerX", Describe: "强大的日志组件,高性能磁盘写入,配置多样化,插件化支持,多种落地方案", MainPage: "", GitPath: "https://github.com/tal-tech/loggerX", GoGet: "github.com/tal-tech/loggerX"} 35 | var hera ModuleInfo = ModuleInfo{Name: "hera", Describe: "[服务孵化组件]快速搭建http,rpc,kafka服务框架", MainPage: "", GitPath: "https://github.com/tal-tech/hera", GoGet: "github.com/tal-tech/hera"} 36 | var tools ModuleInfo = ModuleInfo{Name: "xtools", Describe: "超齐全的golang工具库,限流库,打点工具......", MainPage: "", GitPath: "https://github.com/tal-tech/xtools", GoGet: "github.com/tal-tech/xtools"} 37 | var microPlugin ModuleInfo = ModuleInfo{Name: "odinPugin", Describe: "odin插件管理,例如监控,限流......", MainPage: "", GitPath: "https://github.com/tal-tech/odinPlugin", GoGet: "github.com/tal-tech/odinPlugin"} 38 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/tal-tech/rigger 2 | 3 | go 1.12 4 | 5 | require ( 6 | github.com/denisenkom/go-mssqldb v0.0.0-20200206145737-bbfc9a55622e 7 | github.com/go-sql-driver/mysql v1.4.1 8 | github.com/go-xorm/core v0.6.2 9 | github.com/go-xorm/xorm v0.7.3 10 | github.com/lib/pq v1.3.0 11 | github.com/lunny/log v0.0.0-20160921050905-7887c61bf0de 12 | github.com/spf13/cobra v1.0.0 13 | github.com/ziutek/mymysql v1.5.4 14 | ) 15 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 2 | cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 3 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 4 | github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= 5 | github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= 6 | github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= 7 | github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= 8 | github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= 9 | github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= 10 | github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= 11 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 12 | github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= 13 | github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= 14 | github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= 15 | github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= 16 | github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= 17 | github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= 18 | github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= 19 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 20 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 21 | github.com/denisenkom/go-mssqldb v0.0.0-20190121005146-b04fd42d9952/go.mod h1:xN/JuLBIz4bjkxNmByTiV1IbhfnYb6oo99phBn4Eqhc= 22 | github.com/denisenkom/go-mssqldb v0.0.0-20200206145737-bbfc9a55622e h1:LzwWXEScfcTu7vUZNlDDWDARoSGEtvlDKK2BYHowNeE= 23 | github.com/denisenkom/go-mssqldb v0.0.0-20200206145737-bbfc9a55622e/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= 24 | github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= 25 | github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= 26 | github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= 27 | github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= 28 | github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= 29 | github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= 30 | github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= 31 | github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA= 32 | github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= 33 | github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= 34 | github.com/go-xorm/builder v0.3.3 h1:v8grgrwOGv/iHXIEhIvOwHZIPLrpxRKSX8yWSMLFn/4= 35 | github.com/go-xorm/builder v0.3.3/go.mod h1:v8mE3MFBgtL+RGFNfUnAMUqqfk/Y4W5KuwCFQIEpQLk= 36 | github.com/go-xorm/core v0.6.2 h1:EJLcSxf336POJr670wKB55Mah9f93xzvGYzNRgnT8/Y= 37 | github.com/go-xorm/core v0.6.2/go.mod h1:bwPIfLdm/FzWgVUH8WPVlr+uJhscvNGFcaZKXsI3n2c= 38 | github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:56xuuqnHyryaerycW3BfssRdxQstACi0Epw/yC5E2xM= 39 | github.com/go-xorm/xorm v0.7.3 h1:8J9usPYWSezem1fsep0scOrYpSaZUVQF0dVhUaAePZ8= 40 | github.com/go-xorm/xorm v0.7.3/go.mod h1:npNkX0GgFcODSSKHj7nhJPobHwa5E7usBBZUFaxCsXA= 41 | github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= 42 | github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= 43 | github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY= 44 | github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= 45 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 46 | github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 47 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 48 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 49 | github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 50 | github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 51 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 52 | github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= 53 | github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= 54 | github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= 55 | github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= 56 | github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= 57 | github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= 58 | github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ= 59 | github.com/jackc/pgx v3.3.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I= 60 | github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= 61 | github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= 62 | github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= 63 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 64 | github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 65 | github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= 66 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 67 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 68 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 69 | github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= 70 | github.com/lib/pq v1.3.0 h1:/qkRGz8zljWiDcFvgpwUpwIAPu3r07TDvs3Rws+o/pU= 71 | github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= 72 | github.com/lunny/log v0.0.0-20160921050905-7887c61bf0de h1:nyxwRdWHAVxpFcDThedEgQ07DbcRc5xgNObtbTp76fk= 73 | github.com/lunny/log v0.0.0-20160921050905-7887c61bf0de/go.mod h1:3q8WtuPQsoRbatJuy3nvq/hRSvuBJrHHr+ybPPiNvHQ= 74 | github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= 75 | github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= 76 | github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= 77 | github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= 78 | github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= 79 | github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= 80 | github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= 81 | github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= 82 | github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 83 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 84 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 85 | github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= 86 | github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= 87 | github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= 88 | github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 89 | github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= 90 | github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= 91 | github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= 92 | github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= 93 | github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= 94 | github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= 95 | github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= 96 | github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= 97 | github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= 98 | github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= 99 | github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= 100 | github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= 101 | github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= 102 | github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= 103 | github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= 104 | github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8= 105 | github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= 106 | github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= 107 | github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= 108 | github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= 109 | github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= 110 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 111 | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 112 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 113 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 114 | github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= 115 | github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= 116 | github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= 117 | github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= 118 | github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs= 119 | github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= 120 | go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= 121 | go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= 122 | go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= 123 | go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= 124 | golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 125 | golang.org/x/crypto v0.0.0-20190122013713-64072686203f/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 126 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 127 | golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c h1:Vj5n4GlwjmQteupaxJ9+0FNOmBrHfq7vN4btdGoDZgI= 128 | golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 129 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 130 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 131 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 132 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 133 | golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 134 | golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 135 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 136 | golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= 137 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 138 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 139 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 140 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 141 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 142 | golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 143 | golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 144 | golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 145 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 146 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 147 | golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 148 | golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 149 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 150 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 151 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 152 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 153 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 154 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 155 | google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= 156 | gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= 157 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 158 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 159 | gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= 160 | gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= 161 | gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 162 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 163 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 164 | -------------------------------------------------------------------------------- /internal/genc_go.go: -------------------------------------------------------------------------------- 1 | package internal 2 | 3 | import ( 4 | "bytes" 5 | "errors" 6 | "fmt" 7 | "go/ast" 8 | "go/parser" 9 | "go/token" 10 | "strings" 11 | 12 | "github.com/tal-tech/rigger/common" 13 | ) 14 | 15 | type Fn struct { 16 | Args []Arg 17 | Name string 18 | } 19 | 20 | type Arg struct { 21 | Star string 22 | Name string 23 | X string 24 | Sel string 25 | } 26 | 27 | func GenGoRpcClient(input string, basePath string, importPath string) (*bytes.Buffer, error) { 28 | exists, err := common.PathExists(input) 29 | if err != nil { 30 | return nil, err 31 | } 32 | if !exists { 33 | return nil, errors.New("file " + input + " not exist") 34 | } 35 | 36 | fset := token.NewFileSet() 37 | 38 | fs, err := parser.ParseFile(fset, input, nil, parser.ParseComments) 39 | 40 | if err != nil { 41 | return nil, err 42 | } 43 | 44 | buffer := bytes.NewBufferString(genImport(importPath, strings.ToLower(getServiceName(fs))) + "\n") 45 | buffer.WriteString(genVar(getServiceName(fs), basePath) + "\n" + genStruct() + "\n") 46 | buffer.WriteString(genNewFunc() + "\n") 47 | 48 | for _, decl := range fs.Decls { 49 | fn := parseFunc(decl) 50 | 51 | if fn == nil { 52 | continue 53 | 54 | } 55 | if len(fn.Args) != 3 { 56 | continue 57 | } 58 | 59 | buffer.WriteString(genFunc(fn.Args[0], fn.Name, fn.Args[1], fn.Args[2]) + "\n") 60 | } 61 | 62 | return buffer, nil 63 | } 64 | 65 | func GenEtcdDiscovery() *bytes.Buffer { 66 | tpl := `//+build etcd 67 | 68 | package rpc 69 | 70 | import ( 71 | rpcxClient "github.com/smallnest/rpcx/client" 72 | ) 73 | 74 | func NewDiscovery(basePath string, serviceName string, addrs []string) rpcxClient.ServiceDiscovery { 75 | 76 | return rpcxClient.NewEtcdDiscovery(basePath, serviceName, addrs, nil) 77 | 78 | }` 79 | 80 | return bytes.NewBufferString(tpl) 81 | } 82 | 83 | func GenZkDiscovery() *bytes.Buffer { 84 | tpl := `//+build zookeeper 85 | 86 | package rpc 87 | 88 | import ( 89 | rpcxClient "github.com/smallnest/rpcx/client" 90 | ) 91 | 92 | func NewDiscovery(basePath string, serviceName string, addrs []string) rpcxClient.ServiceDiscovery { 93 | 94 | return rpcxClient.NewZookeeperDiscovery(basePath, serviceName, addrs, nil) 95 | 96 | }` 97 | 98 | return bytes.NewBufferString(tpl) 99 | } 100 | 101 | func getFieldType(field interface{}) string { 102 | return fmt.Sprintf("%T", field) 103 | } 104 | 105 | func genImport(importPath, serviceName string) string { 106 | importTpl := `package rpc 107 | 108 | import ( 109 | "%s/proto" 110 | "github.com/tal-tech/xtools/rpcxutil" 111 | "context" 112 | "sync" 113 | )` 114 | 115 | return fmt.Sprintf(importTpl, importPath) 116 | } 117 | 118 | func genVar(serviceName string, basePath string) string { 119 | varTpl := ` 120 | var ( 121 | client *Client 122 | once sync.Once 123 | ) 124 | 125 | const ( 126 | ServiceName = "%s" 127 | BasePath = "/%s" 128 | )` 129 | 130 | return fmt.Sprintf(varTpl, serviceName, basePath) 131 | } 132 | 133 | func genStruct() string { 134 | structTpl := ` 135 | 136 | type Client struct { 137 | wrapclient *rpcxutil.WrapClient 138 | 139 | //使用本地服务发现的client,仅当注册中心故障时启用 140 | localWrapclient *rpcxutil.WrapClient 141 | lock sync.RWMutex 142 | }` 143 | 144 | return structTpl 145 | } 146 | 147 | func genNewFunc() string { 148 | funcTpl := fmt.Sprintf(` 149 | // NewClient 只是获取一个client对象,此时并没有连接服务发现中心 150 | // 调用时才会去连接服务发现中心 151 | // 不需传入注册中心addr,默认读取ini配置 152 | //[Registration] 153 | //addrs=127.0.0.1:2379 127.0.0.1:2379 154 | //group=online/gray/release/dev 155 | func NewClient() (*Client,error) { 156 | if client != nil { 157 | return client, nil 158 | } 159 | 160 | once.Do(func(){ 161 | client = &Client{} 162 | }) 163 | 164 | return client, nil 165 | } 166 | 167 | func GetClient() *Client { 168 | return client 169 | } 170 | 171 | func (c *Client) getRpcxClient() (wrapc *rpcxutil.WrapClient) { 172 | if c.wrapclient != nil { 173 | return c.wrapclient 174 | } 175 | 176 | //logger.D("rpcClient", "获取rpcxclient:%v", rpcxutil.REGMonitor.IsInFault()) 177 | if c.localWrapclient != nil && rpcxutil.REGMonitor.IsInFault() { 178 | //logger.I("rpcClient", "启用本地服务发现") 179 | return c.localWrapclient 180 | } 181 | 182 | c.lock.Lock() 183 | defer c.lock.Unlock() 184 | 185 | //防止重复实例化, 获得锁之后再次检查 186 | if c.wrapclient != nil { 187 | return c.wrapclient 188 | } 189 | 190 | if c.localWrapclient != nil && rpcxutil.REGMonitor.IsInFault() { 191 | return c.localWrapclient 192 | } 193 | 194 | opt := rpcxutil.GetClientOption() 195 | defer func() { 196 | if r := recover(); r != nil { 197 | if rpcxutil.REGMonitor.IsInFault() { 198 | c.localWrapclient = rpcxutil.NewLocalWrapClient(BasePath, ServiceName, rpcxutil.GetFailMode(), rpcxutil.GetSelectMode(), opt) 199 | wrapc = c.localWrapclient 200 | return 201 | } 202 | 203 | //未启用服务发现兜底,则保持原先控制逻辑,抛出异常阻止服务启动 204 | panic("注册中心故障!") 205 | } 206 | }() 207 | 208 | c.wrapclient = rpcxutil.NewWrapClient(BasePath, ServiceName, rpcxutil.GetFailMode(), rpcxutil.GetSelectMode(), opt) 209 | 210 | return c.wrapclient 211 | }`) 212 | 213 | return funcTpl 214 | } 215 | 216 | func genFunc(ctx Arg, fn string, arg Arg, reply Arg) string { 217 | argCtx := fmt.Sprintf("%s %s%s.%s", ctx.Name, ctx.Star, ctx.X, ctx.Sel) 218 | argArg := fmt.Sprintf("%s %s%s.%s", arg.Name, arg.Star, arg.X, arg.Sel) 219 | argReply := fmt.Sprintf("%s %s%s.%s", reply.Name, reply.Star, arg.X, reply.Sel) 220 | 221 | as := fmt.Sprintf("%s, %s, %s", argCtx, argArg, argReply) 222 | 223 | body := fmt.Sprintf(` 224 | func (c *Client) %s(%s) error{ 225 | wrapclient := c.getRpcxClient() 226 | return wrapclient.WrapCall(%s, "%s", %s, %s) 227 | }`, fn, as, ctx.Name, fn, arg.Name, reply.Name) 228 | 229 | return body 230 | } 231 | 232 | func getServiceName(fs *ast.File) string { 233 | serviceName := "" 234 | for _, v := range fs.Scope.Objects { 235 | if v.Kind != ast.Typ { 236 | continue 237 | } 238 | serviceName = v.Name 239 | break 240 | } 241 | 242 | return serviceName 243 | } 244 | 245 | func parseFunc(decl ast.Decl) *Fn { 246 | fn := &Fn{} 247 | 248 | fd, ok := decl.(*ast.FuncDecl) 249 | if ok { 250 | fn.Name = fd.Name.Name 251 | for _, field := range fd.Type.Params.List { 252 | switch getFieldType(field.Type) { 253 | case "*ast.SelectorExpr": 254 | ft, _ := field.Type.(*ast.SelectorExpr) 255 | arg := Arg{ 256 | Star: "", 257 | X: fmt.Sprintf("%s", ft.X), 258 | Name: field.Names[0].Name, 259 | Sel: fmt.Sprintf("%s", ft.Sel), 260 | } 261 | fn.Args = append(fn.Args, arg) 262 | case "*ast.StarExpr": 263 | ft, _ := field.Type.(*ast.StarExpr) 264 | ftx, _ := ft.X.(*ast.SelectorExpr) 265 | arg := Arg{ 266 | Star: "*", 267 | Name: field.Names[0].Name, 268 | X: fmt.Sprintf("%s", ftx.X), 269 | Sel: fmt.Sprintf("%s", ftx.Sel), 270 | } 271 | fn.Args = append(fn.Args, arg) 272 | } 273 | } 274 | return fn 275 | } else { 276 | return nil 277 | } 278 | } 279 | -------------------------------------------------------------------------------- /internal/genc_php.go: -------------------------------------------------------------------------------- 1 | package internal 2 | 3 | import ( 4 | "bytes" 5 | "errors" 6 | "fmt" 7 | "go/parser" 8 | "go/token" 9 | 10 | "github.com/tal-tech/rigger/common" 11 | ) 12 | 13 | var ( 14 | phpCodeTpl = `SayHello('php client'); 19 | 20 | //if ($resp->getHttpStatus() != '200') { 21 | // echo 'http error'; 22 | //} else if($resp->hasError()) { 23 | // echo $resp->getErrorMessage(); 24 | //} else { 25 | // echo $resp->getData(); 26 | //} 27 | 28 | class Response { 29 | private $_hasError = false; 30 | private $_errmsg; 31 | private $_body; 32 | private $_status; 33 | private $_protocal; 34 | private $_messageId; 35 | 36 | public function __construct($response, $mid) { 37 | $this->parse($response); 38 | $this->_messageId = $mid; 39 | } 40 | 41 | private function parse($response) { 42 | list($header, $body) = explode("\r\n\r\n", $response, 2); 43 | 44 | $headerArray = explode("\r\n", $header); 45 | 46 | list($protocal,$status, $message) = explode(" ", $headerArray[0]); 47 | 48 | $this->_status = $status; 49 | $this->_protocal = $protocal; 50 | 51 | unset($headerArray[0]); 52 | 53 | foreach ($headerArray as $value) { 54 | list($headerKey, $headerValue) = explode(":", $value, 2); 55 | $this->_header[trim($headerKey)] = trim($headerValue); 56 | } 57 | 58 | if ($this->_header["X-Rpcx-Messagestatustype"] == "Error") { 59 | $this->_hasError = true; 60 | $this->_errmsg = $this->_header["X-Rpcx-Errormessage"]; 61 | } 62 | 63 | $this->_body = $body; 64 | } 65 | 66 | public function hasError() { 67 | return $this->_hasError; 68 | } 69 | 70 | public function getData() { 71 | return $this->_body; 72 | } 73 | 74 | public function getErrorMessage() { 75 | return $this->_errmsg; 76 | } 77 | 78 | public function getHttpStatus() { 79 | return $this->_status; 80 | } 81 | } 82 | 83 | class %sClient { 84 | 85 | const ServiceName = "%s"; 86 | 87 | private $_url; 88 | private $_httpClient; 89 | private $_timeout; 90 | 91 | public function __construct($url, $timeout = 3) { 92 | $this->_url = $url; 93 | $this->_timeout = $timeout; 94 | } 95 | 96 | private function call($uri, $data) { 97 | $curl = curl_init(); 98 | $msgId = $this->getUuid(); 99 | 100 | $headers = [ 101 | "Content-type:application/json", 102 | ]; 103 | 104 | $curlOpt = [ 105 | CURLOPT_URL => $this->_url . $uri, 106 | CURLOPT_USERAGENT => 'Xes-Micro HttpClient/Curl', 107 | CURLOPT_CONNECTTIMEOUT => $this->_timeout, 108 | CURLOPT_POST => true, 109 | CURLOPT_RETURNTRANSFER => 1, 110 | CURLOPT_HTTPHEADER => $headers, 111 | CURLOPT_POSTFIELDS => json_encode($data), 112 | CURLOPT_HEADER => true, 113 | CURLOPT_NOBODY => false, 114 | ]; 115 | 116 | curl_setopt_array($curl, $curlOpt); 117 | 118 | $response = curl_exec($curl); 119 | 120 | curl_close($curl); 121 | 122 | return (new Response($response, $msgId)); 123 | } 124 | ` 125 | ) 126 | 127 | func GenPHPHttpClient(serviceFile string) (*bytes.Buffer, error) { 128 | exists, err := common.PathExists(serviceFile) 129 | if err != nil { 130 | return nil, err 131 | } 132 | if !exists { 133 | return nil, errors.New("file " + serviceFile + " not exist") 134 | } 135 | 136 | fset := token.NewFileSet() 137 | 138 | fs, err := parser.ParseFile(fset, serviceFile, nil, parser.ParseComments) 139 | 140 | if err != nil { 141 | return nil, err 142 | } 143 | 144 | serviceName := getServiceName(fs) 145 | 146 | buffer := bytes.NewBufferString(genPhpClass(serviceName) + "\n") 147 | 148 | for _, decl := range fs.Decls { 149 | fn := parseFunc(decl) 150 | 151 | if fn == nil { 152 | continue 153 | 154 | } 155 | if len(fn.Args) != 3 { 156 | continue 157 | } 158 | 159 | buffer.WriteString(genPhpFunc(serviceName, fn.Name) + "\n") 160 | } 161 | 162 | buffer.WriteString("}\n") 163 | 164 | return buffer, nil 165 | } 166 | 167 | func genPhpFunc(serviceName string, fn string) string { 168 | body := fmt.Sprintf(` 169 | // todo 将arg替换为真实的输入参数 170 | public function %s($arg) { 171 | $data = [ 172 | 'arg' => $arg, 173 | ]; 174 | return $this->call("/%s/%s", $data); 175 | }`, fn, serviceName, fn) 176 | 177 | return body 178 | } 179 | 180 | func genPhpClass(serviceName string) string { 181 | return fmt.Sprintf(phpCodeTpl, serviceName, serviceName, serviceName) 182 | } 183 | -------------------------------------------------------------------------------- /internal/gencdemo.go: -------------------------------------------------------------------------------- 1 | package internal 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "strings" 7 | ) 8 | 9 | func GenClientProto(parse *ParseResult, serviceName string) *bytes.Buffer { 10 | //imports 11 | buffer := bytes.NewBufferString("package proto\n\n") 12 | buffer.WriteString(`type SayHelloRequest struct { 13 | Greeting string 14 | } 15 | type SayHelloResponse struct { 16 | Reply string 17 | } 18 | 19 | type UserInfoRequest struct { 20 | Id int 21 | } 22 | type UserInfoResponse struct { 23 | Name string 24 | Age int 25 | City string 26 | } 27 | 28 | type AddUserRequest struct { 29 | Name string 30 | Age int 31 | City string 32 | } 33 | type AddUserResponse struct { 34 | Id int 35 | } 36 | 37 | type UpdateUserRequest struct { 38 | Id int 39 | Name string 40 | Age int 41 | City string 42 | } 43 | 44 | type UpdateUserResponse struct { 45 | } 46 | 47 | `) 48 | 49 | //struct 50 | for _, fn := range parse.Fns { 51 | paths := parseComment(fn.Comment) 52 | if len(paths) <= 0 { 53 | continue 54 | } 55 | if paths[0] != "DemoService" { 56 | continue 57 | } 58 | buffer.WriteString(fmt.Sprintf("type %sRequest struct {\n}\n", fn.Name)) 59 | buffer.WriteString(fmt.Sprintf("type %sResponse struct {\n Reply []interface{}\n}\n\n", fn.Name)) 60 | } 61 | 62 | return buffer 63 | } 64 | 65 | func GenApiRouter(parse *ParseResult, serviceName string) *bytes.Buffer { 66 | //imports 67 | buffer := bytes.NewBufferString("package router\n\n") 68 | buffer.WriteString(fmt.Sprintf(`import ( 69 | "%s/app/controller/demo" 70 | "github.com/gin-gonic/gin" 71 | ) 72 | 73 | //The routing method is exactly the same as Gin 74 | func RegisterRouter(router *gin.Engine) { 75 | entry := router.Group("/demo") 76 | entry.GET("/test", demo.%sDemo) 77 | 78 | `, serviceName, strings.Title(serviceName))) 79 | 80 | //struct 81 | for _, fn := range parse.Fns { 82 | buffer.WriteString(fmt.Sprintf(" entry.GET(\"/%v\", demo.%v)\n", strings.ToLower(fn.Name), fn.Name)) 83 | } 84 | buffer.WriteString(`}`) 85 | return buffer 86 | } 87 | 88 | func GenApiController(parse *ParseResult, serviceName string) *bytes.Buffer { 89 | //imports 90 | buffer := bytes.NewBufferString("package demo\n\n") 91 | buffer.WriteString(fmt.Sprintf(`import ( 92 | "net/http" 93 | 94 | "%s/app/service/demo" 95 | "%s/utils" 96 | 97 | "github.com/gin-gonic/gin" 98 | ) 99 | 100 | `, serviceName, serviceName)) 101 | 102 | //struct 103 | for _, fn := range parse.Fns { 104 | buffer.WriteString(fmt.Sprintf(`func %s(ctx *gin.Context) { 105 | goCtx := utils.TransferToContext(ctx) 106 | ret, err := demo.%s(goCtx) 107 | if err != nil { 108 | resp := utils.Error(err) 109 | ctx.JSON(http.StatusOK, resp) 110 | } else { 111 | resp := utils.Success(ret) 112 | ctx.JSON(http.StatusOK, resp) 113 | } 114 | }`, fn.Name, fn.Name)) 115 | buffer.WriteString("\n\n") 116 | } 117 | return buffer 118 | } 119 | 120 | func GenApiService(parse *ParseResult, serviceName string) *bytes.Buffer { 121 | //imports 122 | buffer := bytes.NewBufferString("package demo\n\n") 123 | buffer.WriteString(fmt.Sprintf(`import ( 124 | "context" 125 | "%s/proto" 126 | "%s/rpc" 127 | 128 | logger "github.com/tal-tech/loggerX" 129 | ) 130 | 131 | `, serviceName, serviceName)) 132 | 133 | //struct 134 | for _, fn := range parse.Fns { 135 | buffer.WriteString(fmt.Sprintf(`func %s(ctx context.Context) (interface{}, error) { 136 | ins, _ := rpc.NewClient() 137 | req := proto.%sRequest{} 138 | resp := proto.%sResponse{} 139 | err := ins.%s(ctx, &req, &resp) 140 | if err != nil { 141 | logger.Ex(ctx, "service error:%%v", err) 142 | } 143 | return resp, err 144 | }`, fn.Name, fn.Name, fn.Name, fn.Name)) 145 | buffer.WriteString("\n\n") 146 | } 147 | return buffer 148 | } 149 | -------------------------------------------------------------------------------- /internal/gens.go: -------------------------------------------------------------------------------- 1 | package internal 2 | 3 | import ( 4 | "bytes" 5 | "errors" 6 | "fmt" 7 | "go/ast" 8 | "go/parser" 9 | "go/token" 10 | "strings" 11 | 12 | "github.com/tal-tech/rigger/common" 13 | ) 14 | 15 | type Imports struct { 16 | Text []string 17 | } 18 | 19 | type ServiceFn struct { 20 | Args []Arg 21 | Name string 22 | Comment string 23 | } 24 | 25 | type ParseResult struct { 26 | Imports []string 27 | Fns []ServiceFn 28 | } 29 | 30 | func GenParseResult(input string) (*ParseResult, error) { 31 | exists, err := common.PathExists(input) 32 | if err != nil { 33 | return nil, err 34 | } 35 | if !exists { 36 | return nil, errors.New("file " + input + " not exist") 37 | } 38 | 39 | fset := token.NewFileSet() 40 | 41 | fs, err := parser.ParseFile(fset, input, nil, parser.ParseComments) 42 | 43 | if err != nil { 44 | return nil, err 45 | } 46 | 47 | result := new(ParseResult) 48 | 49 | imports := parseRpcImport(fs.Imports) 50 | 51 | result.Imports = imports 52 | 53 | for _, decl := range fs.Decls { 54 | fns := parseRpcFunc(decl) 55 | if len(fns) > 0 { 56 | result.Fns = fns 57 | } 58 | } 59 | if len(result.Fns) <= 0 { 60 | return nil, errors.New("Parse Error") 61 | } 62 | return result, nil 63 | } 64 | 65 | func GenService(parse *ParseResult, serviceName string) *bytes.Buffer { 66 | //imports 67 | buffer := bytes.NewBufferString(genServiceImport(parse.Imports, []string{`rpcxplugin "github.com/tal-tech/odinPlugin"`, `"github.com/tal-tech/odinPlugin/wrap"`, fmt.Sprintf(`"%s/app/serviceInterface"`, serviceName)})) 68 | 69 | //struct 70 | structTpl := `//rpcx服务注册类型 71 | type %s struct { 72 | *rpcxplugin.RpcxPlugin 73 | service serviceInterface.Service 74 | }` 75 | buffer.WriteString(fmt.Sprintf(structTpl+"\n\n", strings.Title(serviceName))) 76 | 77 | //Newstruct 78 | newStructTpl := `//传入实现Service接口的类型 79 | func New%s(service serviceInterface.Service) *%s { 80 | this := new(%s) 81 | this.service = service 82 | return this 83 | }` 84 | buffer.WriteString(fmt.Sprintf(newStructTpl+"\n\n", strings.Title(serviceName), strings.Title(serviceName), strings.Title(serviceName))) 85 | 86 | //func 87 | for _, fn := range parse.Fns { 88 | buffer.WriteString(genServiceFunc(serviceName, fn.Name, fn.Args[0], fn.Args[1], fn.Args[2])) 89 | } 90 | 91 | return buffer 92 | } 93 | 94 | func GenServiceBridge(parse *ParseResult) *bytes.Buffer { 95 | //imports 96 | buffer := bytes.NewBufferString(genServiceImport(parse.Imports, []string{})) 97 | 98 | //interface 99 | for _, fn := range parse.Fns { 100 | buffer.WriteString(genServiceBridgeInterface(fn.Name, fn.Args[0], fn.Args[1], fn.Args[2])) 101 | } 102 | 103 | //struct 104 | buffer.WriteString("type serviceBridge struct {\n") 105 | for _, fn := range parse.Fns { 106 | buffer.WriteString(fmt.Sprintf(" %sImpl %s\n", fn.Name, fn.Name)) 107 | } 108 | buffer.WriteString("}\n\n") 109 | 110 | //newStruct 111 | buffer.WriteString(`func NewServiceBridge() *serviceBridge { 112 | return new(serviceBridge) 113 | }`) 114 | buffer.WriteString("\n\n") 115 | 116 | //func 117 | for _, fn := range parse.Fns { 118 | buffer.WriteString(genServiceBridgeFunc(fn.Name, fn.Args[0], fn.Args[1], fn.Args[2])) 119 | } 120 | 121 | return buffer 122 | } 123 | 124 | func GenServiceInit(parse *ParseResult, serviceName string) *bytes.Buffer { 125 | //import 126 | buffer := bytes.NewBufferString("package app\n\n") 127 | buffer.WriteString("import (\n") 128 | buffer.WriteString(fmt.Sprintf(" \"%s/app/service\"\n", serviceName)) 129 | importFilter := make(map[string]bool, 0) 130 | for _, fn := range parse.Fns { 131 | impl := fmt.Sprintf(" \"%s/app/serviceImpl", serviceName) 132 | paths := parseComment(fn.Comment) 133 | for i := 1; i < len(paths); i++ { 134 | impl = impl + "/" + paths[i-1] 135 | } 136 | if _, ok := importFilter[impl]; !ok { 137 | importFilter[impl] = true 138 | buffer.WriteString(impl + "\"\n") 139 | } 140 | } 141 | buffer.WriteString(")\n\n") 142 | 143 | //newService 144 | buffer.WriteString(fmt.Sprintf("func NewService() *service.%s {\n", strings.Title(serviceName))) 145 | buffer.WriteString(" s := service.NewServiceBridge()\n") 146 | newFilter := make(map[string]bool, 0) 147 | for _, fn := range parse.Fns { 148 | paths := parseComment(fn.Comment) 149 | serviceName := paths[len(paths)-1] 150 | packageName := "serviceImpl" 151 | if len(paths) > 1 { 152 | packageName = paths[len(paths)-2] 153 | } 154 | if _, ok := newFilter[fn.Comment]; !ok { 155 | newFilter[fn.Comment] = true 156 | buffer.WriteString(fmt.Sprintf(" %s := %s.New%s()\n", serviceName, packageName, strings.Title(serviceName))) 157 | } 158 | buffer.WriteString(fmt.Sprintf(" s.%sImpl = %s\n", fn.Name, serviceName)) 159 | } 160 | buffer.WriteString(fmt.Sprintf(" return service.New%s(s)\n", strings.Title(serviceName))) 161 | buffer.WriteString("}") 162 | 163 | return buffer 164 | } 165 | 166 | func GenImplFile(imports []string, fn ServiceFn) *bytes.Buffer { 167 | paths := parseComment(fn.Comment) 168 | serviceName := paths[len(paths)-1] 169 | packageName := "serviceImpl" 170 | if len(paths) > 1 { 171 | packageName = paths[len(paths)-2] 172 | } 173 | //imports 174 | buffer := bytes.NewBufferString("package " + packageName + "\n\n") 175 | buffer.WriteString("import (\n") 176 | for _, path := range imports { 177 | buffer.WriteString(" " + path + "\n") 178 | } 179 | buffer.WriteString(")\n\n") 180 | 181 | //struct 182 | buffer.WriteString(fmt.Sprintf("type %s struct {\n", strings.Title(serviceName))) 183 | buffer.WriteString("}\n\n") 184 | 185 | //newstruct 186 | buffer.WriteString(fmt.Sprintf("func New%s() *%s {\n", strings.Title(serviceName), strings.Title(serviceName))) 187 | buffer.WriteString(fmt.Sprintf(" return new(%s)\n", strings.Title(serviceName))) 188 | buffer.WriteString("}\n\n") 189 | return buffer 190 | } 191 | 192 | func GenImplFunc(fn ServiceFn) string { 193 | paths := parseComment(fn.Comment) 194 | serviceName := paths[len(paths)-1] 195 | return genServiceImplFunc(serviceName, fn.Name, fn.Args[0], fn.Args[1], fn.Args[2]) 196 | } 197 | 198 | func parseComment(in string) []string { 199 | in = strings.TrimLeft(in, "//") 200 | return strings.Split(in, ".") 201 | } 202 | 203 | func genServiceImport(parseImports, otherImports []string) string { 204 | ret := `package service 205 | 206 | import ( 207 | ` 208 | for _, path := range parseImports { 209 | ret = ret + " " + path + "\n" 210 | } 211 | for _, path := range otherImports { 212 | ret = ret + " " + path + "\n" 213 | } 214 | return ret + ")\n\n" 215 | } 216 | 217 | func parseRpcImport(specs []*ast.ImportSpec) []string { 218 | ret := make([]string, 0) 219 | for _, spec := range specs { 220 | ret = append(ret, spec.Path.Value) 221 | } 222 | return ret 223 | } 224 | 225 | func parseRpcFunc(decl ast.Decl) []ServiceFn { 226 | fns := make([]ServiceFn, 0) 227 | var comment string 228 | fd, ok := decl.(*ast.GenDecl) 229 | if ok { 230 | for _, spec := range fd.Specs { 231 | s, ok := spec.(*ast.TypeSpec) 232 | if ok { 233 | inter, ok := s.Type.(*ast.InterfaceType) 234 | if ok { 235 | for _, method := range inter.Methods.List { 236 | var fn ServiceFn 237 | fn.Name = method.Names[0].Name 238 | if method.Doc != nil { 239 | for _, item := range method.Doc.List { 240 | comment = item.Text 241 | } 242 | } 243 | fn.Comment = comment 244 | funcType, ok := method.Type.(*ast.FuncType) 245 | if ok { 246 | for _, field := range funcType.Params.List { 247 | switch getFieldType(field.Type) { 248 | case "*ast.SelectorExpr": 249 | ft, _ := field.Type.(*ast.SelectorExpr) 250 | arg := Arg{ 251 | Star: "", 252 | X: fmt.Sprintf("%s", ft.X), 253 | Name: field.Names[0].Name, 254 | Sel: fmt.Sprintf("%s", ft.Sel), 255 | } 256 | fn.Args = append(fn.Args, arg) 257 | case "*ast.StarExpr": 258 | ft, _ := field.Type.(*ast.StarExpr) 259 | ftx, _ := ft.X.(*ast.SelectorExpr) 260 | arg := Arg{ 261 | Star: "*", 262 | Name: field.Names[0].Name, 263 | X: fmt.Sprintf("%s", ftx.X), 264 | Sel: fmt.Sprintf("%s", ftx.Sel), 265 | } 266 | fn.Args = append(fn.Args, arg) 267 | } 268 | } 269 | } 270 | if len(fn.Args) != 3 { 271 | continue 272 | } 273 | fns = append(fns, fn) 274 | } 275 | } else { 276 | return nil 277 | } 278 | } else { 279 | return nil 280 | } 281 | } 282 | } else { 283 | return nil 284 | } 285 | return fns 286 | } 287 | 288 | func genServiceFunc(serviceName, fnName string, ctx Arg, arg Arg, reply Arg) string { 289 | argCtx := fmt.Sprintf("%s %s%s.%s", ctx.Name, ctx.Star, ctx.X, ctx.Sel) 290 | argArg := fmt.Sprintf("%s %s%s.%s", arg.Name, arg.Star, arg.X, arg.Sel) 291 | argReply := fmt.Sprintf("%s %s%s.%s", reply.Name, reply.Star, arg.X, reply.Sel) 292 | 293 | args := fmt.Sprintf("%s, %s, %s", argCtx, argArg, argReply) 294 | callArgs := fmt.Sprintf("%s, %s, %s", ctx.Name, arg.Name, reply.Name) 295 | 296 | fnTpl := `//服务方法调用入口,先通过Wrapcall执行plugin方法,后调用service实现业务方法 297 | func (this *%s) %s(%s) error { 298 | fn := func(w *wrap.Wrap) error { 299 | ctx := w.GetCtx() 300 | err := this.service.%s(%s) 301 | return err 302 | } 303 | return this.Wrapcall(ctx, "%s", fn) 304 | }` 305 | return fmt.Sprintf(fnTpl+"\n\n", strings.Title(serviceName), fnName, args, fnName, callArgs, fnName) 306 | } 307 | 308 | func genServiceBridgeInterface(fnName string, ctx Arg, arg Arg, reply Arg) string { 309 | argCtx := fmt.Sprintf("%s%s.%s", ctx.Star, ctx.X, ctx.Sel) 310 | argArg := fmt.Sprintf("%s%s.%s", arg.Star, arg.X, arg.Sel) 311 | argReply := fmt.Sprintf("%s%s.%s", reply.Star, arg.X, reply.Sel) 312 | 313 | args := fmt.Sprintf("%s, %s, %s", argCtx, argArg, argReply) 314 | 315 | interfaceTpl := `type %s interface { 316 | %s(%s) error 317 | }` 318 | return fmt.Sprintf(interfaceTpl+"\n\n", fnName, fnName, args) 319 | } 320 | 321 | func genServiceBridgeFunc(fnName string, ctx Arg, arg Arg, reply Arg) string { 322 | argCtx := fmt.Sprintf("%s %s%s.%s", ctx.Name, ctx.Star, ctx.X, ctx.Sel) 323 | argArg := fmt.Sprintf("%s %s%s.%s", arg.Name, arg.Star, arg.X, arg.Sel) 324 | argReply := fmt.Sprintf("%s %s%s.%s", reply.Name, reply.Star, arg.X, reply.Sel) 325 | 326 | args := fmt.Sprintf("%s, %s, %s", argCtx, argArg, argReply) 327 | callArgs := fmt.Sprintf("%s, %s, %s", ctx.Name, arg.Name, reply.Name) 328 | 329 | fnTpl := `func (s *serviceBridge) %s(%s) error { 330 | return s.%sImpl.%s(%s) 331 | }` 332 | return fmt.Sprintf(fnTpl+"\n\n", fnName, args, fnName, fnName, callArgs) 333 | } 334 | 335 | func genServiceImplFunc(serviceName, fnName string, ctx Arg, arg Arg, reply Arg) string { 336 | argCtx := fmt.Sprintf("%s %s%s.%s", ctx.Name, ctx.Star, ctx.X, ctx.Sel) 337 | argArg := fmt.Sprintf("%s %s%s.%s", arg.Name, arg.Star, arg.X, arg.Sel) 338 | argReply := fmt.Sprintf("%s %s%s.%s", reply.Name, reply.Star, arg.X, reply.Sel) 339 | 340 | args := fmt.Sprintf("%s, %s, %s", argCtx, argArg, argReply) 341 | funcTpl := `func (this *%s) %s(%s) error { 342 | return nil 343 | }` 344 | return fmt.Sprintf(funcTpl+"\n\n", strings.Title(serviceName), fnName, args) 345 | } 346 | -------------------------------------------------------------------------------- /internal/gensdemo.go: -------------------------------------------------------------------------------- 1 | package internal 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | ) 7 | 8 | func GenServerProto(parse *ParseResult, serviceName string) *bytes.Buffer { 9 | //imports 10 | buffer := bytes.NewBufferString("package proto\n\n") 11 | 12 | //struct 13 | for _, fn := range parse.Fns { 14 | paths := parseComment(fn.Comment) 15 | if len(paths) <= 0 { 16 | continue 17 | } 18 | if paths[0] != "DemoService" { 19 | continue 20 | } 21 | buffer.WriteString(fmt.Sprintf("type %sRequest struct {\n}\n", fn.Name)) 22 | buffer.WriteString(fmt.Sprintf("type %sResponse struct {\n Reply []interface{}\n}\n\n", fn.Name)) 23 | } 24 | 25 | return buffer 26 | } 27 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | 7 | "github.com/spf13/cobra" 8 | "github.com/tal-tech/rigger/cmd" 9 | ) 10 | 11 | var version bool 12 | 13 | const VERSION = "v1.0.4" 14 | 15 | var RootCmd = &cobra.Command{ 16 | Use: "rigger", 17 | RunE: func(c *cobra.Command, args []string) error { 18 | if version { 19 | fmt.Println(VERSION) 20 | return nil 21 | } 22 | return c.Usage() 23 | }, 24 | } 25 | 26 | func init() { 27 | RootCmd.AddCommand(cmd.Build) 28 | RootCmd.AddCommand(cmd.Clean) 29 | RootCmd.AddCommand(cmd.Example) 30 | RootCmd.AddCommand(cmd.Genc) 31 | RootCmd.AddCommand(cmd.Gens) 32 | RootCmd.AddCommand(cmd.Gensdemo) 33 | RootCmd.AddCommand(cmd.Gencdemo) 34 | RootCmd.AddCommand(cmd.New) 35 | //RootCmd.AddCommand(cmd.Help) 36 | RootCmd.AddCommand(cmd.Start) 37 | RootCmd.AddCommand(cmd.Restart) 38 | RootCmd.AddCommand(cmd.Status) 39 | RootCmd.AddCommand(cmd.Stop) 40 | RootCmd.AddCommand(cmd.Tag) 41 | RootCmd.AddCommand(cmd.Fswatch) 42 | RootCmd.AddCommand(cmd.Frame) 43 | RootCmd.AddCommand(cmd.Tree) 44 | RootCmd.AddCommand(cmd.Reverse) 45 | cmd.Genc.Flags().StringVarP(&cmd.BasePath, "basepath", "b", "tal_tech", "service BasePath") 46 | cmd.Genc.Flags().StringVarP(&cmd.ProjectPath, "projectpath", "p", "", "your rpc project path") 47 | cmd.Genc.Flags().StringVarP(&cmd.ImportPath, "importpath", "i", "", "service proto import path") 48 | cmd.Gencdemo.Flags().StringVarP(&cmd.ProjectPath, "projectpath", "p", "", "your rpc project path") 49 | cmd.Restart.Flags().BoolVarP(&cmd.Rebuild, "rebuild", "r", false, "build before start") 50 | cmd.Start.Flags().BoolVarP(&cmd.Foreground, "foreground", "f", false, "run at foreground") 51 | cmd.Fswatch.Flags().BoolVarP(&cmd.Foreground, "foreground", "f", false, "run at foreground") 52 | cmd.New.Flags().StringVarP(&cmd.DefaultName, "defaultnamereplace", "d", "", "template project name to replace(gaea->myproject)") 53 | cmd.New.Flags().StringVarP(&cmd.TitleName, "titlenamereplace", "t", "", "template project name to replace(Gaea->Myproject)") 54 | cmd.New.Flags().StringVarP(&cmd.GitUrl, "giturl", "g", "", "template project git url(git@github.com/tal-tech/gaea.git)") 55 | RootCmd.Flags().BoolVarP(&version, "version", "v", false, "show version") 56 | cmd.Reverse.Flags().BoolVarP(&cmd.ReverseSingle, "single", "s", false, "Generated one go file for every table") 57 | cmd.Reverse.Flags().StringVarP(&cmd.ReverseTmplPath, "tmplpath", "t", "", "Template dir for generated. the default templates dir has provide 1 template") 58 | } 59 | 60 | func main() { 61 | if err := RootCmd.Execute(); err != nil { 62 | fmt.Println(err) 63 | os.Exit(1) 64 | } 65 | //cmd.Run() 66 | } 67 | -------------------------------------------------------------------------------- /xorm/c++.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 The Xorm Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package xorm 6 | 7 | import ( 8 | "strings" 9 | "text/template" 10 | 11 | "github.com/go-xorm/core" 12 | ) 13 | 14 | var ( 15 | CPlusTmpl LangTmpl = LangTmpl{ 16 | template.FuncMap{"Mapper": mapper.Table2Obj, 17 | "Type": cPlusTypeStr, 18 | "UnTitle": unTitle, 19 | }, 20 | nil, 21 | genCPlusImports, 22 | } 23 | ) 24 | 25 | func cPlusTypeStr(col *core.Column) string { 26 | tp := col.SQLType 27 | name := strings.ToUpper(tp.Name) 28 | switch name { 29 | case core.Bit, core.TinyInt, core.SmallInt, core.MediumInt, core.Int, core.Integer, core.Serial: 30 | return "int" 31 | case core.BigInt, core.BigSerial: 32 | return "__int64" 33 | case core.Char, core.Varchar, core.TinyText, core.Text, core.MediumText, core.LongText: 34 | return "tstring" 35 | case core.Date, core.DateTime, core.Time, core.TimeStamp: 36 | return "time_t" 37 | case core.Decimal, core.Numeric: 38 | return "tstring" 39 | case core.Real, core.Float: 40 | return "float" 41 | case core.Double: 42 | return "double" 43 | case core.TinyBlob, core.Blob, core.MediumBlob, core.LongBlob, core.Bytea: 44 | return "tstring" 45 | case core.Bool: 46 | return "bool" 47 | default: 48 | return "tstring" 49 | } 50 | return "" 51 | } 52 | 53 | func genCPlusImports(tables []*core.Table) map[string]string { 54 | imports := make(map[string]string) 55 | 56 | for _, table := range tables { 57 | for _, col := range table.Columns() { 58 | switch cPlusTypeStr(col) { 59 | case "time_t": 60 | imports[``] = `` 61 | case "tstring": 62 | imports[""] = "" 63 | //case "__int64": 64 | // imports[""] = "" 65 | } 66 | } 67 | } 68 | return imports 69 | } 70 | -------------------------------------------------------------------------------- /xorm/go.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 The Xorm Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package xorm 6 | 7 | import ( 8 | "errors" 9 | "fmt" 10 | "go/format" 11 | "reflect" 12 | "sort" 13 | "strings" 14 | "text/template" 15 | 16 | "github.com/go-xorm/core" 17 | ) 18 | 19 | var ( 20 | supportComment bool 21 | GoLangTmpl LangTmpl = LangTmpl{ 22 | template.FuncMap{"Mapper": mapper.Table2Obj, 23 | "Type": typestring, 24 | "Tag": tag, 25 | "UnTitle": unTitle, 26 | "gt": gt, 27 | "getCol": getCol, 28 | "genParams": func(v ...interface{}) (ret interface{}, err error) { 29 | col := v[1].([]string) 30 | str := make([]string, 0) 31 | for _, c := range col { 32 | if v[2].(bool) { 33 | str = append(str, "m"+mapper.Table2Obj(c)+" torm.Param") 34 | } else { 35 | str = append(str, "m"+mapper.Table2Obj(c)) 36 | } 37 | } 38 | return strings.Join(str, ","), nil 39 | }, 40 | "getMethodName": func(v ...interface{}) (ret interface{}, err error) { 41 | col := v[0].(string) 42 | cols := strings.Split(col, "_") 43 | str := "" 44 | for _, c := range cols { 45 | str = str + mapper.Table2Obj(c) 46 | } 47 | return str, nil 48 | }, 49 | }, 50 | formatGo, 51 | genGoImports, 52 | } 53 | ) 54 | 55 | var ( 56 | errBadComparisonType = errors.New("invalid type for comparison") 57 | errBadComparison = errors.New("incompatible types for comparison") 58 | errNoComparison = errors.New("missing argument for comparison") 59 | ) 60 | 61 | type kind int 62 | 63 | const ( 64 | invalidKind kind = iota 65 | boolKind 66 | complexKind 67 | intKind 68 | floatKind 69 | integerKind 70 | stringKind 71 | uintKind 72 | ) 73 | 74 | func basicKind(v reflect.Value) (kind, error) { 75 | switch v.Kind() { 76 | case reflect.Bool: 77 | return boolKind, nil 78 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 79 | return intKind, nil 80 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 81 | return uintKind, nil 82 | case reflect.Float32, reflect.Float64: 83 | return floatKind, nil 84 | case reflect.Complex64, reflect.Complex128: 85 | return complexKind, nil 86 | case reflect.String: 87 | return stringKind, nil 88 | } 89 | return invalidKind, errBadComparisonType 90 | } 91 | 92 | // eq evaluates the comparison a == b || a == c || ... 93 | func eq(arg1 interface{}, arg2 ...interface{}) (bool, error) { 94 | v1 := reflect.ValueOf(arg1) 95 | k1, err := basicKind(v1) 96 | if err != nil { 97 | return false, err 98 | } 99 | if len(arg2) == 0 { 100 | return false, errNoComparison 101 | } 102 | for _, arg := range arg2 { 103 | v2 := reflect.ValueOf(arg) 104 | k2, err := basicKind(v2) 105 | if err != nil { 106 | return false, err 107 | } 108 | if k1 != k2 { 109 | return false, errBadComparison 110 | } 111 | truth := false 112 | switch k1 { 113 | case boolKind: 114 | truth = v1.Bool() == v2.Bool() 115 | case complexKind: 116 | truth = v1.Complex() == v2.Complex() 117 | case floatKind: 118 | truth = v1.Float() == v2.Float() 119 | case intKind: 120 | truth = v1.Int() == v2.Int() 121 | case stringKind: 122 | truth = v1.String() == v2.String() 123 | case uintKind: 124 | truth = v1.Uint() == v2.Uint() 125 | default: 126 | panic("invalid kind") 127 | } 128 | if truth { 129 | return true, nil 130 | } 131 | } 132 | return false, nil 133 | } 134 | 135 | // lt evaluates the comparison a < b. 136 | func lt(arg1, arg2 interface{}) (bool, error) { 137 | v1 := reflect.ValueOf(arg1) 138 | k1, err := basicKind(v1) 139 | if err != nil { 140 | return false, err 141 | } 142 | v2 := reflect.ValueOf(arg2) 143 | k2, err := basicKind(v2) 144 | if err != nil { 145 | return false, err 146 | } 147 | if k1 != k2 { 148 | return false, errBadComparison 149 | } 150 | truth := false 151 | switch k1 { 152 | case boolKind, complexKind: 153 | return false, errBadComparisonType 154 | case floatKind: 155 | truth = v1.Float() < v2.Float() 156 | case intKind: 157 | truth = v1.Int() < v2.Int() 158 | case stringKind: 159 | truth = v1.String() < v2.String() 160 | case uintKind: 161 | truth = v1.Uint() < v2.Uint() 162 | default: 163 | panic("invalid kind") 164 | } 165 | return truth, nil 166 | } 167 | 168 | // le evaluates the comparison <= b. 169 | func le(arg1, arg2 interface{}) (bool, error) { 170 | // <= is < or ==. 171 | lessThan, err := lt(arg1, arg2) 172 | if lessThan || err != nil { 173 | return lessThan, err 174 | } 175 | return eq(arg1, arg2) 176 | } 177 | 178 | // gt evaluates the comparison a > b. 179 | func gt(arg1, arg2 interface{}) (bool, error) { 180 | // > is the inverse of <=. 181 | lessOrEqual, err := le(arg1, arg2) 182 | if err != nil { 183 | return false, err 184 | } 185 | return !lessOrEqual, nil 186 | } 187 | 188 | func getCol(cols map[string]*core.Column, name string) *core.Column { 189 | return cols[strings.ToLower(name)] 190 | } 191 | 192 | func formatGo(src string) (string, error) { 193 | source, err := format.Source([]byte(src)) 194 | if err != nil { 195 | return "", err 196 | } 197 | return string(source), nil 198 | } 199 | 200 | func genGoImports(tables []*core.Table) map[string]string { 201 | imports := make(map[string]string) 202 | 203 | for _, table := range tables { 204 | for _, col := range table.Columns() { 205 | if typestring(col) == "time.Time" { 206 | imports["time"] = "time" 207 | } 208 | } 209 | } 210 | return imports 211 | } 212 | 213 | func typestring(col *core.Column) string { 214 | st := col.SQLType 215 | t := core.SQLType2Type(st) 216 | s := t.String() 217 | if s == "[]uint8" { 218 | return "[]byte" 219 | } 220 | return s 221 | } 222 | 223 | func tag(table *core.Table, col *core.Column) string { 224 | isNameId := (mapper.Table2Obj(col.Name) == "Id") 225 | isIdPk := isNameId && typestring(col) == "int64" 226 | 227 | var res []string 228 | if !col.Nullable { 229 | if !isIdPk { 230 | res = append(res, "not null") 231 | } 232 | } 233 | if col.IsPrimaryKey { 234 | res = append(res, "pk") 235 | } 236 | if col.Default != "" { 237 | res = append(res, "default "+col.Default) 238 | } 239 | if col.IsAutoIncrement { 240 | res = append(res, "autoincr") 241 | } 242 | if col.IsCreated { 243 | res = append(res, "created") 244 | } 245 | if col.IsUpdated { 246 | res = append(res, "updated") 247 | } 248 | if supportComment && col.Comment != "" { 249 | res = append(res, fmt.Sprintf("comment('%s')", col.Comment)) 250 | } 251 | 252 | names := make([]string, 0, len(col.Indexes)) 253 | for name := range col.Indexes { 254 | names = append(names, name) 255 | } 256 | sort.Strings(names) 257 | 258 | for _, name := range names { 259 | index := table.Indexes[name] 260 | var uistr string 261 | if index.Type == core.UniqueType { 262 | uistr = "unique" 263 | } else if index.Type == core.IndexType { 264 | uistr = "index" 265 | } 266 | if len(index.Cols) > 1 { 267 | uistr += "(" + index.Name + ")" 268 | } 269 | res = append(res, uistr) 270 | } 271 | 272 | nstr := col.SQLType.Name 273 | if col.Length != 0 { 274 | if col.Length2 != 0 { 275 | nstr += fmt.Sprintf("(%v,%v)", col.Length, col.Length2) 276 | } else { 277 | nstr += fmt.Sprintf("(%v)", col.Length) 278 | } 279 | } else if len(col.EnumOptions) > 0 { //enum 280 | nstr += "(" 281 | opts := "" 282 | 283 | enumOptions := make([]string, 0, len(col.EnumOptions)) 284 | for enumOption := range col.EnumOptions { 285 | enumOptions = append(enumOptions, enumOption) 286 | } 287 | sort.Strings(enumOptions) 288 | 289 | for _, v := range enumOptions { 290 | opts += fmt.Sprintf(",'%v'", v) 291 | } 292 | nstr += strings.TrimLeft(opts, ",") 293 | nstr += ")" 294 | } else if len(col.SetOptions) > 0 { //enum 295 | nstr += "(" 296 | opts := "" 297 | 298 | setOptions := make([]string, 0, len(col.SetOptions)) 299 | for setOption := range col.SetOptions { 300 | setOptions = append(setOptions, setOption) 301 | } 302 | sort.Strings(setOptions) 303 | 304 | for _, v := range setOptions { 305 | opts += fmt.Sprintf(",'%v'", v) 306 | } 307 | nstr += strings.TrimLeft(opts, ",") 308 | nstr += ")" 309 | } 310 | res = append(res, nstr) 311 | 312 | var tags []string 313 | if genJson { 314 | tags = append(tags, "json:\""+col.Name+"\"") 315 | } 316 | if len(res) > 0 { 317 | tags = append(tags, "xorm:\""+strings.Join(res, " ")+"\"") 318 | } 319 | if len(tags) > 0 { 320 | return "`" + strings.Join(tags, " ") + "`" 321 | } else { 322 | return "" 323 | } 324 | } 325 | -------------------------------------------------------------------------------- /xorm/lang.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 The Xorm Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package xorm 6 | 7 | import ( 8 | "io/ioutil" 9 | "strings" 10 | "text/template" 11 | 12 | "github.com/go-xorm/core" 13 | ) 14 | 15 | type LangTmpl struct { 16 | Funcs template.FuncMap 17 | Formater func(string) (string, error) 18 | GenImports func([]*core.Table) map[string]string 19 | } 20 | 21 | var ( 22 | mapper = &core.SnakeMapper{} 23 | langTmpls = map[string]LangTmpl{ 24 | "go": GoLangTmpl, 25 | "c++": CPlusTmpl, 26 | "objc": ObjcTmpl, 27 | } 28 | ) 29 | 30 | func loadConfig(f string) map[string]string { 31 | bts, err := ioutil.ReadFile(f) 32 | if err != nil { 33 | return nil 34 | } 35 | configs := make(map[string]string) 36 | lines := strings.Split(string(bts), "\n") 37 | for _, line := range lines { 38 | line = strings.TrimRight(line, "\r") 39 | vs := strings.Split(line, "=") 40 | if len(vs) == 2 { 41 | configs[strings.TrimSpace(vs[0])] = strings.TrimSpace(vs[1]) 42 | } 43 | } 44 | return configs 45 | } 46 | 47 | func unTitle(src string) string { 48 | if src == "" { 49 | return "" 50 | } 51 | 52 | if len(src) == 1 { 53 | return strings.ToLower(string(src[0])) 54 | } else { 55 | return strings.ToLower(string(src[0])) + src[1:] 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /xorm/objc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 The Xorm Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package xorm 6 | 7 | import ( 8 | //"fmt" 9 | "strings" 10 | "text/template" 11 | 12 | "github.com/go-xorm/core" 13 | ) 14 | 15 | var ( 16 | ObjcTmpl LangTmpl = LangTmpl{ 17 | template.FuncMap{"Mapper": mapper.Table2Obj, 18 | "Type": objcTypeStr, 19 | "UnTitle": unTitle, 20 | }, 21 | nil, 22 | genCPlusImports, 23 | } 24 | ) 25 | 26 | func objcTypeStr(col *core.Column) string { 27 | tp := col.SQLType 28 | name := strings.ToUpper(tp.Name) 29 | switch name { 30 | case core.Bit, core.TinyInt, core.SmallInt, core.MediumInt, core.Int, core.Integer, core.Serial: 31 | return "int" 32 | case core.BigInt, core.BigSerial: 33 | return "long" 34 | case core.Char, core.Varchar, core.TinyText, core.Text, core.MediumText, core.LongText: 35 | return "NSString*" 36 | case core.Date, core.DateTime, core.Time, core.TimeStamp: 37 | return "NSString*" 38 | case core.Decimal, core.Numeric: 39 | return "NSString*" 40 | case core.Real, core.Float: 41 | return "float" 42 | case core.Double: 43 | return "double" 44 | case core.TinyBlob, core.Blob, core.MediumBlob, core.LongBlob, core.Bytea: 45 | return "NSString*" 46 | case core.Bool: 47 | return "BOOL" 48 | default: 49 | return "NSString*" 50 | } 51 | return "" 52 | } 53 | 54 | func genObjcImports(tables []*core.Table) map[string]string { 55 | imports := make(map[string]string) 56 | 57 | for _, table := range tables { 58 | for _, col := range table.Columns() { 59 | switch objcTypeStr(col) { 60 | case "time_t": 61 | imports[``] = `` 62 | case "tstring": 63 | imports[""] = "" 64 | //case "__int64": 65 | // imports[""] = "" 66 | } 67 | } 68 | } 69 | return imports 70 | } 71 | -------------------------------------------------------------------------------- /xorm/render.go: -------------------------------------------------------------------------------- 1 | package xorm 2 | 3 | import ( 4 | "bytes" 5 | "io/ioutil" 6 | "os" 7 | "path" 8 | "strings" 9 | "text/template" 10 | 11 | "github.com/go-xorm/core" 12 | "github.com/lunny/log" 13 | ) 14 | 15 | type Render struct { 16 | isMultiFile bool 17 | genDir string 18 | prefix string 19 | model string 20 | tables []*core.Table 21 | langTmpl LangTmpl 22 | } 23 | 24 | func (r *Render) Do(tmpl *template.Template, newFileName, ext string) error { 25 | var ( 26 | w *os.File 27 | err error 28 | ) 29 | if !r.isMultiFile { 30 | w, err = os.Create(path.Join(r.genDir, newFileName)) 31 | if err != nil { 32 | log.Errorf("%v", err) 33 | return err 34 | } 35 | 36 | imports := r.langTmpl.GenImports(r.tables) 37 | 38 | tbls := make([]*core.Table, 0) 39 | for _, table := range r.tables { 40 | //[SWH|+] 41 | if r.prefix != "" { 42 | table.Name = strings.TrimPrefix(table.Name, r.prefix) 43 | } 44 | tbls = append(tbls, table) 45 | } 46 | 47 | newbytes := bytes.NewBufferString("") 48 | 49 | t := &Tmpl{Tables: tbls, Imports: imports, Models: r.model} 50 | err = tmpl.Execute(newbytes, t) 51 | if err != nil { 52 | log.Errorf("%v", err) 53 | return err 54 | } 55 | 56 | tplcontent, err := ioutil.ReadAll(newbytes) 57 | if err != nil { 58 | log.Errorf("%v", err) 59 | return err 60 | } 61 | var source string 62 | if r.langTmpl.Formater != nil { 63 | source, err = r.langTmpl.Formater(string(tplcontent)) 64 | if err != nil { 65 | log.Errorf("%v", err) 66 | return err 67 | } 68 | } else { 69 | source = string(tplcontent) 70 | } 71 | 72 | w.WriteString(source) 73 | w.Close() 74 | } else { 75 | for _, table := range r.tables { 76 | //[SWH|+] 77 | if r.prefix != "" { 78 | table.Name = strings.TrimPrefix(table.Name, r.prefix) 79 | } 80 | filename := table2Obj(table.Name) 81 | // imports 82 | tbs := []*core.Table{table} 83 | imports := r.langTmpl.GenImports(tbs) 84 | 85 | w, err := os.Create(path.Join(r.genDir, filename+ext)) 86 | if err != nil { 87 | log.Errorf("%v", err) 88 | return err 89 | } 90 | defer w.Close() 91 | 92 | newbytes := bytes.NewBufferString("") 93 | 94 | t := &Tmpl{Tables: tbs, Imports: imports, Models: r.model} 95 | err = tmpl.Execute(newbytes, t) 96 | if err != nil { 97 | log.Errorf("%v", err) 98 | return err 99 | } 100 | 101 | tplcontent, err := ioutil.ReadAll(newbytes) 102 | if err != nil { 103 | log.Errorf("%v", err) 104 | return err 105 | } 106 | var source string 107 | if r.langTmpl.Formater != nil { 108 | source, err = r.langTmpl.Formater(string(tplcontent)) 109 | if err != nil { 110 | log.Errorf("%v-%v", err, string(tplcontent)) 111 | //return err 112 | } 113 | } else { 114 | source = string(tplcontent) 115 | } 116 | 117 | w.WriteString(source) 118 | w.Close() 119 | } 120 | } 121 | return nil 122 | } 123 | -------------------------------------------------------------------------------- /xorm/reverse.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 The Xorm Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package xorm 6 | 7 | import ( 8 | "fmt" 9 | "io/ioutil" 10 | "os" 11 | "path" 12 | "path/filepath" 13 | "regexp" 14 | "strconv" 15 | "strings" 16 | "text/template" 17 | 18 | "github.com/go-xorm/core" 19 | "github.com/go-xorm/xorm" 20 | "github.com/lunny/log" 21 | "github.com/spf13/cobra" 22 | "github.com/tal-tech/rigger/config" 23 | 24 | _ "github.com/denisenkom/go-mssqldb" 25 | _ "github.com/go-sql-driver/mysql" 26 | _ "github.com/lib/pq" 27 | _ "github.com/ziutek/mymysql/godrv" 28 | ) 29 | 30 | type Reverse struct { 31 | single bool 32 | tmplPath string 33 | } 34 | 35 | type ReverseOption func(r *Reverse) error 36 | 37 | func NewReverse(option ...ReverseOption) *Reverse { 38 | r := new(Reverse) 39 | for _, f := range option { 40 | if err := f(r); err != nil { 41 | return nil 42 | } 43 | } 44 | return r 45 | } 46 | 47 | func SetReverseSingle(s bool) ReverseOption { 48 | return func(r *Reverse) error { 49 | r.single = s 50 | return nil 51 | } 52 | } 53 | 54 | func SetReverseTmplPath(path string) ReverseOption { 55 | return func(r *Reverse) error { 56 | r.tmplPath = path 57 | return nil 58 | } 59 | } 60 | 61 | var ( 62 | genJson bool = false 63 | ) 64 | 65 | func printReversePrompt(flag string) { 66 | } 67 | 68 | type Tmpl struct { 69 | Tables []*core.Table 70 | Imports map[string]string 71 | Models string 72 | } 73 | 74 | func dirExists(dir string) bool { 75 | d, e := os.Stat(dir) 76 | switch { 77 | case e != nil: 78 | return false 79 | case !d.IsDir(): 80 | return false 81 | } 82 | 83 | return true 84 | } 85 | 86 | func (r *Reverse) Run(cmd *cobra.Command, args []string) { 87 | isMultiFile := !r.single 88 | 89 | curPath, err := os.Getwd() 90 | if err != nil { 91 | fmt.Println(err) 92 | return 93 | } 94 | 95 | var genDir string 96 | var model string 97 | var filterPat *regexp.Regexp 98 | var dir string 99 | if len(args) >= 3 { 100 | genDir, err = filepath.Abs(args[2]) 101 | if err != nil { 102 | fmt.Println(err) 103 | return 104 | } 105 | 106 | //[SWH|+] 经测试,path.Base不能解析windows下的“\”,需要替换为“/” 107 | genDir = strings.Replace(genDir, "\\", "/", -1) 108 | model = path.Base(genDir) 109 | 110 | if len(args) >= 4 { 111 | filterPat, err = regexp.Compile(args[3]) 112 | if err != nil { 113 | fmt.Println(err) 114 | return 115 | } 116 | } 117 | } else { 118 | model = "models" 119 | genDir = path.Join(curPath, model) 120 | } 121 | 122 | var configs map[string]string 123 | if r.tmplPath == "" { 124 | configs = config.DefaultXormConfig() 125 | } else { 126 | dir, err = filepath.Abs(r.tmplPath) 127 | if err != nil { 128 | log.Errorf("%v", err) 129 | return 130 | } 131 | 132 | if !dirExists(dir) { 133 | log.Errorf("Template %v path is not exist", dir) 134 | return 135 | } 136 | cfgPath := path.Join(dir, "config") 137 | info, err := os.Stat(cfgPath) 138 | if err == nil && !info.IsDir() { 139 | configs = loadConfig(cfgPath) 140 | } 141 | } 142 | 143 | var langTmpl LangTmpl 144 | var ok bool 145 | var lang string = "go" 146 | var prefix string = "" //[SWH|+] 147 | 148 | if l, ok := configs["lang"]; ok { 149 | lang = l 150 | } 151 | if j, ok := configs["genJson"]; ok { 152 | genJson, err = strconv.ParseBool(j) 153 | } 154 | 155 | //[SWH|+] 156 | if j, ok := configs["prefix"]; ok { 157 | prefix = j 158 | } 159 | 160 | if langTmpl, ok = langTmpls[lang]; !ok { 161 | fmt.Println("Unsupported programing language", lang) 162 | return 163 | } 164 | 165 | os.MkdirAll(genDir, os.ModePerm) 166 | 167 | supportComment = (args[0] == "mysql" || args[0] == "mymysql") 168 | 169 | Orm, err := xorm.NewEngine(args[0], args[1]) 170 | if err != nil { 171 | log.Errorf("%v", err) 172 | return 173 | } 174 | 175 | tables, err := Orm.DBMetas() 176 | if err != nil { 177 | log.Errorf("%v", err) 178 | return 179 | } 180 | if filterPat != nil && len(tables) > 0 { 181 | size := 0 182 | for _, t := range tables { 183 | if filterPat.MatchString(t.Name) { 184 | tables[size] = t 185 | size++ 186 | } 187 | } 188 | tables = tables[:size] 189 | } 190 | 191 | commonRender := &Render{ 192 | isMultiFile: isMultiFile, 193 | genDir: genDir, 194 | prefix: prefix, 195 | model: model, 196 | tables: tables, 197 | langTmpl: langTmpl, 198 | } 199 | 200 | if r.tmplPath == "" { 201 | defaultTpl := config.GetDefaultXormTpl() 202 | for _, cfg := range defaultTpl { 203 | t := template.New(cfg.FileName) 204 | t.Funcs(langTmpl.Funcs) 205 | 206 | tmpl, err := t.Parse(cfg.Content) 207 | if err != nil { 208 | log.Errorf("%v", err) 209 | return 210 | } 211 | commonRender.Do(tmpl, cfg.FileName, cfg.Ext) 212 | } 213 | } else { 214 | filepath.Walk(dir, func(f string, info os.FileInfo, err error) error { 215 | if info.IsDir() { 216 | return nil 217 | } 218 | 219 | if info.Name() == "config" { 220 | return nil 221 | } 222 | 223 | bs, err := ioutil.ReadFile(f) 224 | if err != nil { 225 | log.Errorf("%v", err) 226 | return err 227 | } 228 | t := template.New(f) 229 | t.Funcs(langTmpl.Funcs) 230 | 231 | tmpl, err := t.Parse(string(bs)) 232 | if err != nil { 233 | log.Errorf("%v", err) 234 | return err 235 | } 236 | 237 | fileName := info.Name() 238 | newFileName := fileName[:len(fileName)-4] 239 | ext := path.Ext(newFileName) 240 | 241 | err = commonRender.Do(tmpl, newFileName, ext) 242 | if err != nil { 243 | return err 244 | } 245 | return nil 246 | }) 247 | } 248 | 249 | } 250 | 251 | func table2Obj(name string) string { 252 | newstr := make([]rune, 0) 253 | upNextChar := false 254 | 255 | name = strings.ToLower(name) 256 | 257 | for _, chr := range name { 258 | switch { 259 | case upNextChar: 260 | upNextChar = false 261 | if 'a' <= chr && chr <= 'z' { 262 | chr -= ('a' - 'A') 263 | } 264 | case chr == '_': 265 | upNextChar = true 266 | continue 267 | } 268 | 269 | newstr = append(newstr, chr) 270 | } 271 | 272 | return string(newstr) 273 | } 274 | --------------------------------------------------------------------------------