feat: create project command
This commit is contained in:
parent
0ea42a3d33
commit
15ecf1e90a
|
@ -9,7 +9,7 @@ import (
|
|||
var (
|
||||
rootCmd = &cobra.Command{
|
||||
Use: "coco",
|
||||
Short: "golang project generator",
|
||||
Short: "golang project toolkit",
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -24,6 +24,7 @@ func init() {
|
|||
QuoteEmptyFields: false,
|
||||
})
|
||||
rootCmd.AddCommand(bootstrap.Update())
|
||||
rootCmd.AddCommand(bootstrap.CreateProject())
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
|
|
@ -14,7 +14,7 @@ func Update() *cobra.Command {
|
|||
var configPath string
|
||||
return &cobra.Command{
|
||||
Use: "update",
|
||||
Short: "coco tool update",
|
||||
Short: "coco update",
|
||||
PreRun: func(cmd *cobra.Command, args []string) {
|
||||
configPath = runtime.ReplaceEachSlash(fmt.Sprintf("%s/.coco.yaml", runtime.GetHomeDir()))
|
||||
_ = yaml.Read(configPath, &config)
|
||||
|
@ -38,7 +38,7 @@ func Update() *cobra.Command {
|
|||
// exec update
|
||||
repo := fmt.Sprintf("gitter.top/coco/bootstrap/coco/...@%s", commitID)
|
||||
if _, err := runtime.Exec("go", "install", repo); err != nil {
|
||||
logrus.Errorf("update coco failed: %v", err)
|
||||
logrus.Errorf("update bootstrap failed: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
package bootstrap
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/spf13/cobra"
|
||||
"gitter.top/coco/bootstrap/template"
|
||||
"os"
|
||||
"path"
|
||||
)
|
||||
|
||||
func CreateProject() *cobra.Command {
|
||||
var name, output string
|
||||
cmd := &cobra.Command{
|
||||
Use: "new",
|
||||
Short: "create new project",
|
||||
PreRun: func(cmd *cobra.Command, args []string) {
|
||||
|
||||
},
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
b := &template.Builder{
|
||||
Path: output,
|
||||
Name: name,
|
||||
}
|
||||
b.Path = path.Join(output, b.Name)
|
||||
if err := b.Build(); err != nil {
|
||||
_, _ = fmt.Fprint(os.Stderr, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
cmd.Flags().StringVar(&name, "name", "CocoDemo", "project name")
|
||||
cmd.Flags().StringVar(&output, "path", ".", "project path")
|
||||
|
||||
return cmd
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
package template
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
var (
|
||||
scaffold = map[string]string{
|
||||
"/go.mod": templateModule,
|
||||
"/.coco": TemplateRc,
|
||||
"/.gitignore": templateGitignore,
|
||||
"/module_update.sh": templateModuleUpdate,
|
||||
"/cmd/api.go": templateCmdNewApiServer,
|
||||
"/cmd/exec.go": templateCmdExec,
|
||||
"/config_dev.yaml": templateDevYaml,
|
||||
"/config_prod.yaml": templateProdYaml,
|
||||
"/config/config.go": templateConfig,
|
||||
"/model/model.proto": templateProto,
|
||||
"/internal/logic/demo.go": templateLogic,
|
||||
"/internal/router/router.go": templateRouter,
|
||||
"/internal/services/demo_service.go": templateServices,
|
||||
"/internal/controller/demo_module.proto": templateDemoModuleProtoDefine,
|
||||
}
|
||||
)
|
||||
|
||||
type Builder struct {
|
||||
Name string
|
||||
Path string
|
||||
SSH string
|
||||
}
|
||||
|
||||
func (b *Builder) Build() error {
|
||||
if err := os.MkdirAll(b.Path, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := b.write(b.Path+"/"+b.Name+".go", templateMain); err != nil {
|
||||
return err
|
||||
}
|
||||
for sr, v := range scaffold {
|
||||
i := strings.LastIndex(sr, "/")
|
||||
if i > 0 {
|
||||
dir := sr[:i]
|
||||
if err := os.MkdirAll(b.Path+dir, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := b.write(b.Path+sr, v); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *Builder) write(name, tpl string) (err error) {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
fmt.Println("Failed")
|
||||
}
|
||||
}()
|
||||
fmt.Printf("create %s \n", name)
|
||||
data, err := b.parse(tpl)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return os.WriteFile(name, data, 0644)
|
||||
}
|
||||
|
||||
func (b *Builder) parse(s string) ([]byte, error) {
|
||||
t, err := template.New("").Parse(s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
if err := t.Execute(&buf, b); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return buf.Bytes(), nil
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
package template
|
||||
|
||||
const TemplateRc = `freq_to: .`
|
|
@ -0,0 +1,83 @@
|
|||
package template
|
||||
|
||||
const templateCmdExec = `package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
nested "github.com/antonfisher/nested-logrus-formatter"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
"os"
|
||||
"{{.Name}}/config"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
rootCmd = &cobra.Command{}
|
||||
cfgFile string
|
||||
)
|
||||
|
||||
func Execute() {
|
||||
// 预加载配置文件
|
||||
loadConfig()
|
||||
if err := rootCmd.Execute(); err != nil {
|
||||
_, _ = fmt.Fprintln(os.Stderr, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
var getServeDir = func(path string) string {
|
||||
var run, _ = os.Getwd()
|
||||
return strings.Replace(path, run, ".", -1)
|
||||
}
|
||||
var formatter = &nested.Formatter{
|
||||
NoColors: false,
|
||||
HideKeys: true,
|
||||
TimestampFormat: "2006-01-02 15:04:05",
|
||||
CallerFirst: true,
|
||||
CustomCallerFormatter: func(f *runtime.Frame) string {
|
||||
s := strings.Split(f.Function, ".")
|
||||
funcName := s[len(s)-1]
|
||||
return fmt.Sprintf(" [%s:%d][%s()]", getServeDir(f.File), f.Line, funcName)
|
||||
},
|
||||
}
|
||||
logrus.SetFormatter(formatter)
|
||||
logrus.SetReportCaller(true)
|
||||
|
||||
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "config_local.yaml", "config file")
|
||||
rootCmd.AddCommand(apiServerCommand) // API服务
|
||||
}
|
||||
|
||||
func loadConfig() {
|
||||
// 初始化配置文件
|
||||
config.New(cfgFile)
|
||||
conf := config.Get()
|
||||
if err := conf.Load(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const templateCmdNewApiServer = `package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/spf13/cobra"
|
||||
"os"
|
||||
"{{.Name}}/internal/router"
|
||||
)
|
||||
|
||||
var (
|
||||
apiServerCommand = &cobra.Command{
|
||||
Use: "api",
|
||||
Short: "start api server",
|
||||
Long: "start api server",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
router := router.NewRouter()
|
||||
router.Register()
|
||||
},
|
||||
}
|
||||
)
|
||||
`
|
|
@ -0,0 +1,52 @@
|
|||
package template
|
||||
|
||||
const templateConfig = `package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"gopkg.in/yaml.v3"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
)
|
||||
|
||||
type ServerConfig struct {
|
||||
ServerName string ` + "`" + `yaml:"server-name"` + "`" + `
|
||||
ServerListen string ` + "`" + `yaml:"server-listen"` + "`" + `
|
||||
Environment string ` + "`" + `yaml:"environment"` + "`" + `
|
||||
}
|
||||
|
||||
type ServerConf struct {
|
||||
ConfigFile string
|
||||
ServerConfig ` + "`" + `yaml:",inline"` + "`" + `
|
||||
}
|
||||
|
||||
var conf *ServerConf
|
||||
|
||||
func New(fileName string) {
|
||||
conf = new(ServerConf)
|
||||
conf.ConfigFile = fileName
|
||||
}
|
||||
|
||||
func Get() *ServerConf {
|
||||
if conf == nil {
|
||||
panic(fmt.Errorf("config not init"))
|
||||
}
|
||||
return conf
|
||||
}
|
||||
|
||||
func (receiver *ServerConf) Load() error {
|
||||
f, err := os.Open(receiver.ConfigFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
data, err := ioutil.ReadAll(f)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := yaml.Unmarshal(data, receiver); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
`
|
|
@ -0,0 +1,54 @@
|
|||
package template
|
||||
|
||||
const templateDemoModuleProtoDefine = `syntax = "proto3";
|
||||
|
||||
package controller;
|
||||
|
||||
option go_package = "{{.Name}}/internal/controller";
|
||||
|
||||
|
||||
// @route_group: true
|
||||
// @route_api: /api/test
|
||||
// @gen_to: ./internal/controller/demo_controller.go
|
||||
service DemoAPI {
|
||||
// @desc: echo
|
||||
// @author: 匿名
|
||||
// @method: POST
|
||||
// @api: /ping
|
||||
rpc Ping (PingReq) returns (PingResp);
|
||||
}
|
||||
|
||||
|
||||
message PingReq {
|
||||
string ping = 1; // 输入字符串 我会将该字符串回显给你
|
||||
}
|
||||
|
||||
message PingResp {
|
||||
string pong = 1; // 将输入的字符串原样输出
|
||||
}
|
||||
`
|
||||
|
||||
const templateServices = `package services
|
||||
|
||||
import "context"
|
||||
|
||||
type Test struct {
|
||||
Appid string
|
||||
}
|
||||
|
||||
func (test *Test) Test(c context.Context) error {
|
||||
return nil
|
||||
}
|
||||
`
|
||||
const templateLogic = `package logic
|
||||
|
||||
import "context"
|
||||
|
||||
type Test struct {
|
||||
Appid string
|
||||
}
|
||||
|
||||
func (test *Test) Test(c context.Context) error {
|
||||
return nil
|
||||
}
|
||||
`
|
|
@ -0,0 +1,9 @@
|
|||
package template
|
||||
|
||||
const templateGitignore = `.idea
|
||||
go.sum
|
||||
{{.Name}}
|
||||
{{.Name}}.exe
|
||||
{{.Name}}.exe~
|
||||
config_local.yaml
|
||||
`
|
|
@ -0,0 +1,10 @@
|
|||
package template
|
||||
|
||||
const templateMain = `package main
|
||||
|
||||
import "{{.Name}}/cmd"
|
||||
|
||||
func main() {
|
||||
cmd.Execute()
|
||||
}
|
||||
`
|
|
@ -0,0 +1,8 @@
|
|||
package template
|
||||
|
||||
const templateProto = `syntax = "proto3";
|
||||
|
||||
package model;
|
||||
|
||||
option go_package = "{{.Name}}/model";
|
||||
`
|
|
@ -0,0 +1,22 @@
|
|||
package template
|
||||
|
||||
const templateModule = `module {{.Name}}
|
||||
|
||||
go 1.18
|
||||
`
|
||||
|
||||
const templateModuleUpdate = `#!/bin/bash
|
||||
|
||||
# 该脚本用来自动全量更新该项目中用到的module
|
||||
|
||||
go mod tidy
|
||||
|
||||
match_required=$(cat go.mod | grep -zoE "\((.*?)\)" | grep -zoP "(?<=\()[^\)]*(?=\))" | awk -F ' ' '{if(NF==2){print $1}}')
|
||||
|
||||
for i in $match_required;do
|
||||
echo $i "updating..."
|
||||
go get -u "$i";
|
||||
done
|
||||
|
||||
go mod tidy
|
||||
`
|
|
@ -0,0 +1,32 @@
|
|||
package template
|
||||
|
||||
const templateRouter = `package router
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"gitter.top/coco/coco/core"
|
||||
"github.com/gin-gonic/gin"
|
||||
"os"
|
||||
"{{.Name}}/config"
|
||||
"{{.Name}}/infra/middleware"
|
||||
)
|
||||
|
||||
type Router struct{}
|
||||
|
||||
func NewRouter() *Router {
|
||||
return &Router{}
|
||||
}
|
||||
|
||||
// Register 注册路由
|
||||
func (receiver *Router) Register() error {
|
||||
cfg := config.Get()
|
||||
// 从这里开始实例化路由注册器
|
||||
var register = core.NewRegister()
|
||||
register.DefaultRouter(core.WithListenAddress(cfg.ServerListen),
|
||||
core.WithGinMode(gin.ReleaseMode), core.WithCors(), core.WithRecovery())
|
||||
register.PreRun(nil)
|
||||
//reg.RegisterStruct(AutoGenXXXRouterMap, &XXX{})
|
||||
_, _ = fmt.Fprintf(os.Stdout, "api server: %s\n", cfg.ServerListen)
|
||||
register.Run()
|
||||
}
|
||||
`
|
|
@ -0,0 +1,11 @@
|
|||
package template
|
||||
|
||||
const templateDevYaml = `server-name: {{.Name}}
|
||||
server-listen: 0.0.0.0:12580
|
||||
environment: dev
|
||||
`
|
||||
|
||||
const templateProdYaml = `server-name: {{.Name}}
|
||||
server-listen: 0.0.0.0:12580
|
||||
environment: prod
|
||||
`
|
Loading…
Reference in New Issue