beego:AST code

This commit is contained in:
astaxie 2014-06-09 17:33:04 +08:00
parent 6c8a7f1382
commit 21cb8ea4a3
3 changed files with 116 additions and 27 deletions

View File

@ -34,8 +34,8 @@ const (
var (
// custom error when user stop request handler manually.
USERSTOPRUN = errors.New("User stop run")
GlobalControllerRouter map[string]*ControllerComments //pkgpath+controller:comments
USERSTOPRUN = errors.New("User stop run")
GlobalControllerRouter map[string][]ControllerComments = make(map[string][]ControllerComments) //pkgpath+controller:comments
)
// store the comment for the controller method
@ -43,6 +43,7 @@ type ControllerComments struct {
method string
router string
allowHTTPMethods []string
params []map[string]string
}
// Controller defines some basic http request handler operations, such as

132
parser.go
View File

@ -6,11 +6,17 @@
package beego
import (
"errors"
"fmt"
"go/ast"
"go/parser"
"go/token"
"os"
"path/filepath"
"path"
"strings"
)
var globalControllerRouter = `package routers
var globalRouterTemplate = `package routers
import (
"github.com/astaxie/beego"
@ -21,26 +27,106 @@ func init() {
}
`
func parserPkg(pkgpath string) error {
err := filepath.Walk(pkgpath, func(path string, info os.FileInfo, err error) error {
if err != nil {
Error("error scan app Controller source:", err)
return err
}
//if is normal file or name is temp skip
//directory is needed
if !info.IsDir() || info.Name() == "tmp" {
return nil
}
var genInfoList map[string][]ControllerComments
//fileSet := token.NewFileSet()
//astPkgs, err := parser.ParseDir(fileSet, path, func(info os.FileInfo) bool {
// name := info.Name()
// return !info.IsDir() && !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go")
//}, parser.ParseComments)
return nil
})
return err
func init() {
genInfoList = make(map[string][]ControllerComments)
}
func parserPkg(pkgRealpath, pkgpath string) error {
fileSet := token.NewFileSet()
astPkgs, err := parser.ParseDir(fileSet, pkgRealpath, func(info os.FileInfo) bool {
name := info.Name()
return !info.IsDir() && !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go")
}, parser.ParseComments)
if err != nil {
return err
}
for _, pkg := range astPkgs {
for _, fl := range pkg.Files {
for _, d := range fl.Decls {
switch specDecl := d.(type) {
case *ast.FuncDecl:
parserComments(specDecl.Doc, specDecl.Name.String(), fmt.Sprint(specDecl.Recv.List[0].Type.(*ast.StarExpr).X), pkgpath)
}
}
}
}
genRouterCode()
return nil
}
func parserComments(comments *ast.CommentGroup, funcName, controllerName, pkgpath string) error {
if comments != nil && comments.List != nil {
for _, c := range comments.List {
t := strings.TrimSpace(strings.TrimLeft(c.Text, "//"))
if strings.HasPrefix(t, "@router") {
elements := strings.TrimLeft(t, "@router ")
e1 := strings.SplitN(elements, " ", 2)
if len(e1) < 1 {
return errors.New("you should has router infomation")
}
key := pkgpath + ":" + controllerName
cc := ControllerComments{}
cc.method = funcName
cc.router = e1[0]
if len(e1) == 2 && e1[1] != "" {
e1 = strings.SplitN(e1[1], " ", 2)
if len(e1) >= 1 {
cc.allowHTTPMethods = strings.Split(strings.Trim(e1[0], "[]"), ",")
} else {
cc.allowHTTPMethods = append(cc.allowHTTPMethods, "get")
}
} else {
cc.allowHTTPMethods = append(cc.allowHTTPMethods, "get")
}
if len(e1) == 2 && e1[1] != "" {
keyval := strings.Split(strings.Trim(e1[1], "[]"), " ")
for _, kv := range keyval {
kk := strings.Split(kv, ":")
cc.params = append(cc.params, map[string]string{strings.Join(kk[:len(kk)-1], ":"): kk[len(kk)-1]})
}
}
genInfoList[key] = append(genInfoList[key], cc)
}
}
}
return nil
}
func genRouterCode() {
os.Mkdir(path.Join(AppPath, "routers"), 0755)
Info("generate router from comments")
f, err := os.Create(path.Join(AppPath, "routers", "commentsRouter.go"))
if err != nil {
panic(err)
}
defer f.Close()
var globalinfo string
for k, cList := range genInfoList {
for _, c := range cList {
allmethod := "nil"
if len(c.allowHTTPMethods) > 0 {
allmethod = "[]string{"
for _, m := range c.allowHTTPMethods {
allmethod += `"` + m + `",`
}
allmethod = strings.TrimRight(allmethod, ",") + "}"
}
params := "nil"
if len(c.params) > 0 {
params = "[]map[string]string{"
for _, p := range c.params {
for k, v := range p {
params = params + `map[string]string{` + k + `:"` + v + `"},`
}
}
params = strings.TrimRight(params, ",") + "}"
}
globalinfo = globalinfo + fmt.Sprintln(`beego.GlobalControllerRouter["`+k+`"] = &ControllerComments{"`+
strings.TrimSpace(c.method)+`", "`+c.router+`", `+allmethod+", "+params+"}")
}
}
f.WriteString(strings.Replace(globalRouterTemplate, "{{.globalinfo}}", globalinfo, -1))
}

View File

@ -174,7 +174,7 @@ func (p *ControllerRegistor) Include(cList ...ControllerInterface) {
if pkgpath != "" {
if _, ok := skip[pkgpath]; !ok {
skip[pkgpath] = true
parserPkg(pkgpath)
parserPkg(pkgpath, t.PkgPath())
}
}
}
@ -184,7 +184,9 @@ func (p *ControllerRegistor) Include(cList ...ControllerInterface) {
t := reflect.Indirect(reflectVal).Type()
key := t.PkgPath() + ":" + t.Name()
if comm, ok := GlobalControllerRouter[key]; ok {
p.Add(comm.router, c, strings.Join(comm.allowHTTPMethods, ",")+":"+comm.method)
for _, a := range comm {
p.Add(a.router, c, strings.Join(a.allowHTTPMethods, ",")+":"+a.method)
}
}
}
}