196 lines
4.3 KiB
Go
196 lines
4.3 KiB
Go
|
package errcode
|
|||
|
|
|||
|
import (
|
|||
|
"flag"
|
|||
|
"fmt"
|
|||
|
"go/ast"
|
|||
|
"go/token"
|
|||
|
"golang.org/x/tools/go/packages"
|
|||
|
"log"
|
|||
|
"os"
|
|||
|
"path/filepath"
|
|||
|
"strconv"
|
|||
|
"strings"
|
|||
|
)
|
|||
|
|
|||
|
type File struct {
|
|||
|
pkg *Package
|
|||
|
fileName string
|
|||
|
rawAstFile *ast.File
|
|||
|
content string
|
|||
|
importList map[string]struct{}
|
|||
|
errcodeList *ErrCodeList
|
|||
|
}
|
|||
|
|
|||
|
type Package struct {
|
|||
|
Name string
|
|||
|
rawAstPkg *packages.Package
|
|||
|
rawAstFileSet *token.FileSet
|
|||
|
files []*File
|
|||
|
ImportList []string
|
|||
|
}
|
|||
|
|
|||
|
func Generate() {
|
|||
|
flag.Parse()
|
|||
|
|
|||
|
curRootDir, err := os.Getwd()
|
|||
|
if err != nil {
|
|||
|
log.Fatal(err)
|
|||
|
}
|
|||
|
|
|||
|
log.Printf("================================================")
|
|||
|
log.Printf("args: %v", os.Args[1:])
|
|||
|
log.Printf("pwd: %v", curRootDir)
|
|||
|
|
|||
|
cfg := &packages.Config{
|
|||
|
Mode: packages.NeedName | packages.NeedTypes | packages.NeedTypesInfo | packages.NeedSyntax | packages.NeedFiles,
|
|||
|
Tests: true,
|
|||
|
BuildFlags: []string{fmt.Sprintf("-tags=%s", strings.Join([]string{}, " "))},
|
|||
|
Logf: func(format string, args ...interface{}) {
|
|||
|
//log.Printf(format, args...)
|
|||
|
},
|
|||
|
}
|
|||
|
|
|||
|
rawPkgs, err := packages.Load(cfg, ".")
|
|||
|
if err != nil {
|
|||
|
log.Fatal(err)
|
|||
|
}
|
|||
|
if len(rawPkgs) == 0 {
|
|||
|
log.Fatalf("当前包居然读取不到ast信息,尝试项目根目录执行go mod tidy,解决报错")
|
|||
|
}
|
|||
|
|
|||
|
pkgs := make([]*Package, 0, len(rawPkgs))
|
|||
|
firstPkgPath := ""
|
|||
|
for i, pkg := range rawPkgs {
|
|||
|
if i == 0 {
|
|||
|
firstPkgPath = pkg.PkgPath
|
|||
|
} else {
|
|||
|
if strings.Contains(pkg.PkgPath, firstPkgPath) {
|
|||
|
continue
|
|||
|
}
|
|||
|
}
|
|||
|
p := &Package{
|
|||
|
Name: pkg.Name,
|
|||
|
rawAstPkg: pkg,
|
|||
|
rawAstFileSet: pkg.Fset,
|
|||
|
files: make([]*File, 0, len(pkg.Syntax)),
|
|||
|
}
|
|||
|
|
|||
|
for j, file := range pkg.Syntax {
|
|||
|
goFile := pkg.GoFiles[j]
|
|||
|
|
|||
|
if strings.HasSuffix(goFile, ".gen.go") {
|
|||
|
continue
|
|||
|
}
|
|||
|
|
|||
|
content, err := os.ReadFile(goFile)
|
|||
|
if err != nil {
|
|||
|
panic(err)
|
|||
|
}
|
|||
|
|
|||
|
p.files = append(p.files, &File{
|
|||
|
pkg: p,
|
|||
|
fileName: filepath.Base(goFile),
|
|||
|
rawAstFile: file,
|
|||
|
content: string(content),
|
|||
|
importList: make(map[string]struct{}),
|
|||
|
})
|
|||
|
}
|
|||
|
pkgs = append(pkgs, p)
|
|||
|
}
|
|||
|
|
|||
|
if len(pkgs) > 1 {
|
|||
|
s := ""
|
|||
|
for _, v := range pkgs {
|
|||
|
s += v.rawAstPkg.Name + ","
|
|||
|
log.Printf("pak:%v, gofiles:%v", v.rawAstPkg.PkgPath, v.rawAstPkg.GoFiles)
|
|||
|
}
|
|||
|
log.Fatalf("居然发现%v个包(%v),联系@李坤支持:", len(pkgs), s)
|
|||
|
}
|
|||
|
|
|||
|
for _, pkg := range pkgs {
|
|||
|
for _, file := range pkg.files {
|
|||
|
file.errcodeList = &ErrCodeList{
|
|||
|
List: make([]*ErrCode, 0),
|
|||
|
}
|
|||
|
ast.Inspect(file.rawAstFile, file.genDecl)
|
|||
|
|
|||
|
//log.Printf("after gen, file %v list len:%v", file.fileName, len(file.errcodeList.List))
|
|||
|
|
|||
|
if len(file.errcodeList.List) > 0 {
|
|||
|
fileName := "code_content.gen.go"
|
|||
|
outputFile := filepath.Join(curRootDir, fileName)
|
|||
|
err := renderFile(file.errcodeList, tpl, outputFile)
|
|||
|
if err != nil {
|
|||
|
log.Printf("render file %v error:%v", fileName, err)
|
|||
|
os.Exit(1)
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
// genDecl processes one declaration clause.
|
|||
|
func (f *File) genDecl(node ast.Node) bool {
|
|||
|
//log.Printf("node:%+v", node)
|
|||
|
if f.pkg.Name != "errcode" {
|
|||
|
return true
|
|||
|
}
|
|||
|
if f.fileName != "code.go" {
|
|||
|
return true
|
|||
|
}
|
|||
|
|
|||
|
if node == nil {
|
|||
|
return true
|
|||
|
}
|
|||
|
|
|||
|
fileSet := f.pkg.rawAstFileSet
|
|||
|
fpos := fileSet.File(node.Pos())
|
|||
|
|
|||
|
fileNode, ok := node.(*ast.File)
|
|||
|
if !ok {
|
|||
|
return true
|
|||
|
}
|
|||
|
|
|||
|
for _, v := range fileNode.Decls {
|
|||
|
d := v.(*ast.GenDecl)
|
|||
|
|
|||
|
if d.Tok.String() != "const" {
|
|||
|
continue
|
|||
|
}
|
|||
|
|
|||
|
// 静态错误码
|
|||
|
for _, spec := range d.Specs {
|
|||
|
specValue := spec.(*ast.ValueSpec)
|
|||
|
|
|||
|
specContent := f.content[fpos.Offset(specValue.Pos()):fpos.Offset(specValue.End())]
|
|||
|
specContent = strings.ReplaceAll(specContent, " ", "")
|
|||
|
values := strings.Split(specContent, "=")
|
|||
|
if len(values) != 2 {
|
|||
|
log.Printf("错误码:%v 按等号分隔字符串之后不满足var=value格式", specContent)
|
|||
|
os.Exit(1)
|
|||
|
}
|
|||
|
|
|||
|
commentContent := specValue.Comment.Text()
|
|||
|
commentContent = strings.ReplaceAll(commentContent, "\n", "")
|
|||
|
if commentContent == "" {
|
|||
|
log.Printf("错误码:%v 没有定义文本内容,格式为:ErrCode = 123 // <文本内容>", specContent)
|
|||
|
os.Exit(1)
|
|||
|
}
|
|||
|
|
|||
|
code, _ := strconv.Atoi(values[1])
|
|||
|
f.errcodeList.List = append(f.errcodeList.List, &ErrCode{
|
|||
|
Name: values[0],
|
|||
|
Value: code,
|
|||
|
Comment: commentContent,
|
|||
|
})
|
|||
|
|
|||
|
//log.Printf("错误码:%v 值:%v --> 注释:%v\n", values[0], values[1], commentContent)
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
return true
|
|||
|
}
|