github.com/unionj-cloud/go-doudou@v1.3.8-0.20221011095552-0088008e5b31/cmd/internal/svc/codegen/init.go (about)

     1  package codegen
     2  
     3  import (
     4  	"bufio"
     5  	"fmt"
     6  	"github.com/go-git/go-billy/v5/osfs"
     7  	"github.com/go-git/go-git/v5"
     8  	"github.com/go-git/go-git/v5/plumbing/cache"
     9  	"github.com/go-git/go-git/v5/storage/filesystem"
    10  	"github.com/iancoleman/strcase"
    11  	"github.com/sirupsen/logrus"
    12  	"github.com/unionj-cloud/go-doudou/cmd/internal/executils"
    13  	"github.com/unionj-cloud/go-doudou/toolkit/sliceutils"
    14  	"github.com/unionj-cloud/go-doudou/toolkit/stringutils"
    15  	"github.com/unionj-cloud/go-doudou/version"
    16  	"os"
    17  	"path/filepath"
    18  	"runtime"
    19  	"strings"
    20  	"text/template"
    21  )
    22  
    23  const svcTmpl = `/**
    24  * Generated by go-doudou {{.Version}}.
    25  * You can edit it as your need.
    26  */
    27  package service
    28  
    29  import (
    30  	"context"
    31  	"{{.VoPackage}}"
    32  )
    33  
    34  //go:generate go-doudou svc http --handler -c --doc
    35  //go:generate go-doudou svc grpc
    36  
    37  type {{.SvcName}} interface {
    38  	// You can define your service methods as your need. Below is an example.
    39  	// You can also add annotations here like @role(admin) to add meta data to routes for 
    40  	// implementing your own middlewares
    41  	PageUsers(ctx context.Context, query vo.PageQuery) (data vo.PageRet, err error)
    42  }
    43  `
    44  
    45  const voTmpl = `/**
    46  * Generated by go-doudou {{.Version}}.
    47  * You can edit it as your need.
    48  */
    49  package vo
    50  
    51  //go:generate go-doudou name --file $GOFILE
    52  
    53  type PageFilter struct {
    54  	// 真实姓名,前缀匹配
    55  	Name string
    56  	// 所属部门ID
    57  	Dept int
    58  }
    59  
    60  type Order struct {
    61  	Col  string
    62  	Sort string
    63  }
    64  
    65  type Page struct {
    66  	// 排序规则
    67  	Orders []Order
    68  	// 页码
    69  	PageNo int
    70  	// 每页行数
    71  	Size int
    72  }
    73  
    74  // 分页筛选条件
    75  type PageQuery struct {
    76  	Filter PageFilter
    77  	Page   Page
    78  }
    79  
    80  type PageRet struct {
    81  	Items    interface{}
    82  	PageNo   int
    83  	PageSize int
    84  	Total    int
    85  	HasNext  bool
    86  }
    87  
    88  type UserVo struct {
    89  	Id    int
    90  	Name  string
    91  	Phone string
    92  	Dept  string
    93  }
    94  `
    95  
    96  const modTmpl = `module {{.ModName}}
    97  
    98  go {{.GoVersion}}
    99  
   100  require (
   101  	github.com/ascarter/requestid v0.0.0-20170313220838-5b76ab3d4aee
   102  	github.com/brianvoe/gofakeit/v6 v6.10.0
   103  	github.com/go-resty/resty/v2 v2.6.0
   104  	github.com/go-sql-driver/mysql v1.6.0
   105  	github.com/gorilla/handlers v1.5.1
   106  	github.com/iancoleman/strcase v0.1.3
   107  	github.com/jmoiron/sqlx v1.3.1
   108  	github.com/kelseyhightower/envconfig v1.4.0
   109  	github.com/opentracing-contrib/go-stdlib v1.0.0
   110  	github.com/opentracing/opentracing-go v1.2.0
   111  	github.com/pkg/errors v0.9.1
   112  	github.com/rs/zerolog v1.28.0
   113  	github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4
   114  	github.com/grpc-ecosystem/go-grpc-middleware/providers/zerolog/v2 v2.0.0-rc.2
   115  	github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.0-rc.2
   116  	github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0
   117  	github.com/prometheus/client_golang v1.11.0
   118  	google.golang.org/grpc v1.38.0
   119  	google.golang.org/protobuf v1.26.0
   120  	github.com/unionj-cloud/go-doudou ` + version.Release + `
   121  )`
   122  
   123  const gitignoreTmpl = `# Binaries for programs and plugins
   124  *.exe
   125  *.exe~
   126  *.dll
   127  *.so
   128  *.dylib
   129  
   130  # Output of the go coverage tool, specifically when used with LiteIDE
   131  *.out
   132  
   133  # Dependency directories (remove the comment below to include it)
   134  # vendor/
   135  **/*.local
   136  .DS_Store
   137  .idea`
   138  
   139  const envTmpl = ``
   140  
   141  const dockerignorefileTmpl = `**/*.local
   142  `
   143  
   144  const dockerfileTmpl = `FROM devopsworks/golang-upx:1.18 AS builder
   145  
   146  ENV GO111MODULE=on
   147  ENV GOPROXY=https://goproxy.cn,direct
   148  ARG user
   149  ENV HOST_USER=$user
   150  
   151  WORKDIR /repo
   152  
   153  # all the steps are cached
   154  ADD go.mod .
   155  ADD go.sum .
   156  # if go.mod/go.sum not changed, this step is also cached
   157  RUN go mod download
   158  
   159  ADD . ./
   160  RUN go mod vendor
   161  
   162  RUN export GDD_VER=$(go list -mod=vendor -m -f '{{` + "`" + `{{` + "`" + `}} .Version {{` + "`" + `}}` + "`" + `}}' github.com/unionj-cloud/go-doudou) && \
   163  CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -v -ldflags="-s -w -X 'github.com/unionj-cloud/go-doudou/framework/buildinfo.BuildUser=$HOST_USER' -X 'github.com/unionj-cloud/go-doudou/framework/buildinfo.BuildTime=$(date)' -X 'github.com/unionj-cloud/go-doudou/framework/buildinfo.GddVer=$GDD_VER'" -mod vendor -o api cmd/main.go && \
   164  strip api && /usr/local/bin/upx api
   165  
   166  FROM alpine:3.14
   167  
   168  COPY --from=builder /usr/share/zoneinfo/Asia/Shanghai /usr/share/zoneinfo/Asia/Shanghai
   169  ENV TZ="Asia/Shanghai"
   170  
   171  WORKDIR /repo
   172  
   173  COPY --from=builder /repo/api ./
   174  
   175  COPY .env* ./
   176  
   177  ENTRYPOINT ["/repo/api"]
   178  `
   179  
   180  func getGoVersionNum(goVersion string) string {
   181  	vnums := sliceutils.StringSlice2InterfaceSlice(strings.Split(strings.TrimPrefix(strings.TrimSpace(goVersion), "go"), "."))
   182  	nums := make([]interface{}, 2)
   183  	copy(nums, vnums)
   184  	return fmt.Sprintf("%s.%s", nums...)
   185  }
   186  
   187  // InitProj inits a service project
   188  // dir is root path
   189  // modName is module name
   190  func InitProj(dir string, modName string, runner executils.Runner) {
   191  	var (
   192  		err       error
   193  		svcName   string
   194  		svcfile   string
   195  		modfile   string
   196  		vodir     string
   197  		vofile    string
   198  		goVersion string
   199  		firstLine string
   200  		f         *os.File
   201  		tpl       *template.Template
   202  		envfile   string
   203  		out       []byte
   204  	)
   205  	if stringutils.IsEmpty(dir) {
   206  		dir, _ = os.Getwd()
   207  	}
   208  	_ = os.MkdirAll(dir, os.ModePerm)
   209  
   210  	gitInit(dir)
   211  	gitIgnore(dir)
   212  
   213  	if out, err = runner.Output("go", "version"); err != nil {
   214  		panic(err)
   215  	}
   216  	// go version go1.13 darwin/amd64
   217  	goVersion = getGoVersionNum(strings.Split(strings.TrimSpace(string(out)), " ")[2])
   218  	if stringutils.IsEmpty(modName) {
   219  		modName = filepath.Base(dir)
   220  	}
   221  	modfile = filepath.Join(dir, "go.mod")
   222  	if _, err = os.Stat(modfile); os.IsNotExist(err) {
   223  		if f, err = os.Create(modfile); err != nil {
   224  			panic(err)
   225  		}
   226  		defer f.Close()
   227  
   228  		tpl, _ = template.New("go.mod.tmpl").Parse(modTmpl)
   229  		_ = tpl.Execute(f, struct {
   230  			ModName   string
   231  			GoVersion string
   232  		}{
   233  			ModName:   modName,
   234  			GoVersion: goVersion,
   235  		})
   236  	} else {
   237  		logrus.Warnf("file %s already exists", modfile)
   238  	}
   239  
   240  	envfile = filepath.Join(dir, ".env")
   241  	if _, err = os.Stat(envfile); os.IsNotExist(err) {
   242  		if f, err = os.Create(envfile); err != nil {
   243  			panic(err)
   244  		}
   245  		defer f.Close()
   246  
   247  		tpl, _ = template.New(".env.tmpl").Parse(envTmpl)
   248  		_ = tpl.Execute(f, struct {
   249  			SvcName string
   250  		}{
   251  			SvcName: modName,
   252  		})
   253  	} else {
   254  		logrus.Warnf("file %s already exists", envfile)
   255  	}
   256  
   257  	vodir = filepath.Join(dir, "vo")
   258  	if err = os.MkdirAll(vodir, os.ModePerm); err != nil {
   259  		panic(err)
   260  	}
   261  	vofile = filepath.Join(vodir, "vo.go")
   262  	if _, err = os.Stat(vofile); os.IsNotExist(err) {
   263  		if f, err = os.Create(vofile); err != nil {
   264  			panic(err)
   265  		}
   266  		defer f.Close()
   267  
   268  		tpl, _ = template.New("vo.go.tmpl").Parse(voTmpl)
   269  		_ = tpl.Execute(f, struct {
   270  			Version string
   271  		}{
   272  			Version: version.Release,
   273  		})
   274  	} else {
   275  		logrus.Warnf("file %s already exists", vofile)
   276  	}
   277  
   278  	svcName = strcase.ToCamel(filepath.Base(dir))
   279  	svcfile = filepath.Join(dir, "svc.go")
   280  	if _, err = os.Stat(svcfile); os.IsNotExist(err) {
   281  		if f, err = os.Open(modfile); err != nil {
   282  			panic(err)
   283  		}
   284  		defer f.Close()
   285  		reader := bufio.NewReader(f)
   286  		firstLine, _ = reader.ReadString('\n')
   287  		modName = strings.TrimSpace(strings.TrimPrefix(firstLine, "module"))
   288  
   289  		if f, err = os.Create(svcfile); err != nil {
   290  			panic(err)
   291  		}
   292  		defer f.Close()
   293  
   294  		tpl, _ = template.New("svc.go.tmpl").Parse(svcTmpl)
   295  		_ = tpl.Execute(f, struct {
   296  			VoPackage string
   297  			SvcName   string
   298  			Version   string
   299  		}{
   300  			VoPackage: modName + "/vo",
   301  			SvcName:   svcName,
   302  			Version:   version.Release,
   303  		})
   304  	} else {
   305  		logrus.Warnf("file %s already exists", svcfile)
   306  	}
   307  
   308  	dockerfile := filepath.Join(dir, "Dockerfile")
   309  	if _, err = os.Stat(dockerfile); os.IsNotExist(err) {
   310  		if f, err = os.Create(dockerfile); err != nil {
   311  			panic(err)
   312  		}
   313  		defer f.Close()
   314  
   315  		tpl, _ = template.New("dockerfile.tmpl").Parse(dockerfileTmpl)
   316  		_ = tpl.Execute(f, nil)
   317  	} else {
   318  		logrus.Warnf("file %s already exists", dockerfile)
   319  	}
   320  
   321  	dockerignorefile := filepath.Join(dir, ".dockerignore")
   322  	if _, err = os.Stat(dockerignorefile); os.IsNotExist(err) {
   323  		if f, err = os.Create(dockerignorefile); err != nil {
   324  			panic(err)
   325  		}
   326  		defer f.Close()
   327  
   328  		tpl, _ = template.New("dockerignorefile.tmpl").Parse(dockerignorefileTmpl)
   329  		_ = tpl.Execute(f, nil)
   330  	} else {
   331  		logrus.Warnf("file %s already exists", dockerignorefile)
   332  	}
   333  }
   334  
   335  // InitSvc inits a service project, test purpose only
   336  func InitSvc(dir string) {
   337  	var (
   338  		err       error
   339  		modName   string
   340  		svcName   string
   341  		svcfile   string
   342  		modfile   string
   343  		vodir     string
   344  		vofile    string
   345  		goVersion string
   346  		firstLine string
   347  		f         *os.File
   348  		tpl       *template.Template
   349  		envfile   string
   350  	)
   351  	if stringutils.IsEmpty(dir) {
   352  		dir, _ = os.Getwd()
   353  	}
   354  	_ = os.MkdirAll(dir, os.ModePerm)
   355  
   356  	gitInit(dir)
   357  	gitIgnore(dir)
   358  
   359  	goVersion = getGoVersionNum(runtime.Version())
   360  	modName = filepath.Base(dir)
   361  	modfile = filepath.Join(dir, "go.mod")
   362  	if _, err = os.Stat(modfile); os.IsNotExist(err) {
   363  		if f, err = os.Create(modfile); err != nil {
   364  			panic(err)
   365  		}
   366  		defer f.Close()
   367  
   368  		tpl, _ = template.New("go.mod.tmpl").Parse(modTmpl)
   369  		_ = tpl.Execute(f, struct {
   370  			ModName   string
   371  			GoVersion string
   372  		}{
   373  			ModName:   modName,
   374  			GoVersion: goVersion,
   375  		})
   376  	} else {
   377  		logrus.Warnf("file %s already exists", "go.mod")
   378  	}
   379  
   380  	envfile = filepath.Join(dir, ".env")
   381  	if _, err = os.Stat(envfile); os.IsNotExist(err) {
   382  		if f, err = os.Create(envfile); err != nil {
   383  			panic(err)
   384  		}
   385  		defer f.Close()
   386  
   387  		tpl, _ = template.New(".env.tmpl").Parse(envTmpl)
   388  		_ = tpl.Execute(f, struct {
   389  			SvcName string
   390  		}{
   391  			SvcName: modName,
   392  		})
   393  	} else {
   394  		logrus.Warnf("file %s already exists", vofile)
   395  	}
   396  
   397  	vodir = filepath.Join(dir, "vo")
   398  	if err = os.MkdirAll(vodir, os.ModePerm); err != nil {
   399  		panic(err)
   400  	}
   401  	vofile = filepath.Join(vodir, "vo.go")
   402  	if _, err = os.Stat(vofile); os.IsNotExist(err) {
   403  		if f, err = os.Create(vofile); err != nil {
   404  			panic(err)
   405  		}
   406  		defer f.Close()
   407  
   408  		tpl, _ = template.New("vo.go.tmpl").Parse(voTmpl)
   409  		_ = tpl.Execute(f, struct {
   410  			Version string
   411  		}{
   412  			Version: version.Release,
   413  		})
   414  	} else {
   415  		logrus.Warnf("file %s already exists", vofile)
   416  	}
   417  
   418  	svcName = strcase.ToCamel(filepath.Base(dir))
   419  	svcfile = filepath.Join(dir, "svc.go")
   420  	if _, err = os.Stat(svcfile); os.IsNotExist(err) {
   421  		if f, err = os.Open(modfile); err != nil {
   422  			panic(err)
   423  		}
   424  		reader := bufio.NewReader(f)
   425  		firstLine, _ = reader.ReadString('\n')
   426  		modName = strings.TrimSpace(strings.TrimPrefix(firstLine, "module"))
   427  		fmt.Println(modName)
   428  
   429  		if f, err = os.Create(svcfile); err != nil {
   430  			panic(err)
   431  		}
   432  		defer f.Close()
   433  
   434  		tpl, _ = template.New("svc.go.tmpl").Parse(svcTmpl)
   435  		_ = tpl.Execute(f, struct {
   436  			VoPackage string
   437  			SvcName   string
   438  			Version   string
   439  		}{
   440  			VoPackage: modName + "/vo",
   441  			SvcName:   svcName,
   442  			Version:   version.Release,
   443  		})
   444  	} else {
   445  		logrus.Warnf("file %s already exists", svcfile)
   446  	}
   447  
   448  	dockerfile := filepath.Join(dir, "Dockerfile")
   449  	if _, err = os.Stat(dockerfile); os.IsNotExist(err) {
   450  		if f, err = os.Create(dockerfile); err != nil {
   451  			panic(err)
   452  		}
   453  		defer f.Close()
   454  
   455  		tpl, _ = template.New("dockerfile.tmpl").Parse(dockerfileTmpl)
   456  		_ = tpl.Execute(f, nil)
   457  	} else {
   458  		logrus.Warnf("file %s already exists", dockerfile)
   459  	}
   460  }
   461  
   462  // gitIgnore adds .gitignore file
   463  func gitIgnore(dir string) {
   464  	var (
   465  		gitignorefile string
   466  		err           error
   467  		f             *os.File
   468  		tpl           *template.Template
   469  	)
   470  	gitignorefile = filepath.Join(dir, ".gitignore")
   471  	if _, err = os.Stat(gitignorefile); os.IsNotExist(err) {
   472  		if f, err = os.Create(gitignorefile); err != nil {
   473  			panic(err)
   474  		}
   475  		defer f.Close()
   476  
   477  		tpl, _ = template.New(".gitignore.tmpl").Parse(gitignoreTmpl)
   478  		_ = tpl.Execute(f, nil)
   479  	} else {
   480  		logrus.Warnf("file %s already exists", ".gitignore")
   481  	}
   482  }
   483  
   484  // gitInit inits git repository
   485  func gitInit(dir string) {
   486  	fs := osfs.New(dir)
   487  	dot, _ := fs.Chroot(".git")
   488  	storage := filesystem.NewStorage(dot, cache.NewObjectLRUDefault())
   489  
   490  	_, _ = git.Init(storage, fs)
   491  }