gr_hz/generator/package.go

200 lines
5.7 KiB
Go
Raw Normal View History

2024-04-30 19:30:09 +08:00
/*
* Copyright 2022 CloudWeGo Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package generator
import (
"errors"
"fmt"
"io/ioutil"
"path/filepath"
"reflect"
"text/template"
"gopkg.in/yaml.v2"
2024-04-30 20:22:44 +08:00
"gr_hz/generator/model"
"gr_hz/meta"
"gr_hz/util"
2024-04-30 19:30:09 +08:00
)
type HttpPackage struct {
IdlName string
Package string
Services []*Service
Models []*model.Model
RouterInfo *Router
}
type Service struct {
Name string
Methods []*HttpMethod
ClientMethods []*ClientMethod
Models []*model.Model // all dependency models
BaseDomain string // base domain for client code
ServiceGroup string // service level router group
ServiceGenDir string // handler_dir for handler_by_service
}
// HttpPackageGenerator is used to record the configuration related to generating hertz http code.
type HttpPackageGenerator struct {
ConfigPath string // package template path
Backend meta.Backend // model template
Options []Option
CmdType string
ProjPackage string // go module for project
HandlerDir string
RouterDir string
ModelDir string
UseDir string // model dir for third repo
ClientDir string // client dir for "new"/"update" command
IdlClientDir string // client dir for "client" command
ForceClientDir string // client dir without namespace for "client" command
BaseDomain string // request domain for "client" command
ServiceGenDir string
NeedModel bool
HandlerByMethod bool // generate handler files with method dimension
SnakeStyleMiddleware bool // use snake name style for middleware
loadedBackend Backend
curModel *model.Model
processedModels map[*model.Model]bool
TemplateGenerator
}
func (pkgGen *HttpPackageGenerator) Init() error {
defaultConfig := packageConfig
customConfig := TemplateConfig{}
// unmarshal from user-defined config file if it exists
if pkgGen.ConfigPath != "" {
cdata, err := ioutil.ReadFile(pkgGen.ConfigPath)
if err != nil {
return fmt.Errorf("read layout config from %s failed, err: %v", pkgGen.ConfigPath, err.Error())
}
if err = yaml.Unmarshal(cdata, &customConfig); err != nil {
return fmt.Errorf("unmarshal layout config failed, err: %v", err.Error())
}
if reflect.DeepEqual(customConfig, TemplateConfig{}) {
return errors.New("empty config")
}
}
if pkgGen.tpls == nil {
pkgGen.tpls = make(map[string]*template.Template, len(defaultConfig.Layouts))
}
if pkgGen.tplsInfo == nil {
pkgGen.tplsInfo = make(map[string]*Template, len(defaultConfig.Layouts))
}
// extract routerTplName/middlewareTplName/handlerTplName/registerTplName/modelTplName/clientTplName directories
// load default template
for _, layout := range defaultConfig.Layouts {
// default template use "fileName" as template name
path := filepath.Base(layout.Path)
err := pkgGen.loadLayout(layout, path, true)
if err != nil {
return err
}
}
// override the default template, other customized file template will be loaded by "TemplateGenerator.Init"
for _, layout := range customConfig.Layouts {
if !IsDefaultPackageTpl(layout.Path) {
continue
}
err := pkgGen.loadLayout(layout, layout.Path, true)
if err != nil {
return err
}
}
pkgGen.Config = &customConfig
// load Model tpl if need
if pkgGen.Backend != "" {
if err := pkgGen.LoadBackend(pkgGen.Backend); err != nil {
return fmt.Errorf("load model template failed, err: %v", err.Error())
}
}
pkgGen.processedModels = make(map[*model.Model]bool)
pkgGen.TemplateGenerator.isPackageTpl = true
return pkgGen.TemplateGenerator.Init()
}
func (pkgGen *HttpPackageGenerator) checkInited() (bool, error) {
if pkgGen.tpls == nil {
if err := pkgGen.Init(); err != nil {
return false, fmt.Errorf("init layout config failed, err: %v", err.Error())
}
}
return pkgGen.ConfigPath == "", nil
}
func (pkgGen *HttpPackageGenerator) Generate(pkg *HttpPackage) error {
if _, err := pkgGen.checkInited(); err != nil {
return err
}
if len(pkg.Models) != 0 {
for _, m := range pkg.Models {
if err := pkgGen.GenModel(m, pkgGen.NeedModel); err != nil {
return fmt.Errorf("generate model %s failed, err: %v", m.FilePath, err.Error())
}
}
}
if pkgGen.CmdType == meta.CmdClient {
// default client dir
clientDir := pkgGen.IdlClientDir
// user specify client dir
if len(pkgGen.ClientDir) != 0 {
clientDir = pkgGen.ClientDir
}
if err := pkgGen.genClient(pkg, clientDir); err != nil {
return err
}
if err := pkgGen.genCustomizedFile(pkg); err != nil {
return err
}
return nil
}
// this is for handler_by_service, the handler_dir is {$HANDLER_DIR}/{$PKG}
handlerDir := util.SubDir(pkgGen.HandlerDir, pkg.Package)
if pkgGen.HandlerByMethod {
handlerDir = pkgGen.HandlerDir
}
handlerPackage := util.SubPackage(pkgGen.ProjPackage, handlerDir)
routerDir := util.SubDir(pkgGen.RouterDir, pkg.Package)
routerPackage := util.SubPackage(pkgGen.ProjPackage, routerDir)
root := NewRouterTree()
if err := pkgGen.genHandler(pkg, handlerDir, handlerPackage, root); err != nil {
return err
}
if err := pkgGen.genRouter(pkg, root, handlerPackage, routerDir, routerPackage); err != nil {
return err
}
if err := pkgGen.genCustomizedFile(pkg); err != nil {
return err
}
return nil
}