1
0
mirror of https://github.com/beego/bee.git synced 2024-11-24 13:30:53 +00:00

load package from ouside of the project

This commit is contained in:
John 2021-02-05 09:44:52 +08:00
parent 100f0af03a
commit 9541046a29

View File

@ -35,6 +35,8 @@ import (
yaml "gopkg.in/yaml.v2" yaml "gopkg.in/yaml.v2"
bu "github.com/beego/bee/v2/utils"
beeLogger "github.com/beego/bee/v2/logger" beeLogger "github.com/beego/bee/v2/logger"
"github.com/beego/beego/v2/core/utils" "github.com/beego/beego/v2/core/utils"
"github.com/beego/beego/v2/server/web/swagger" "github.com/beego/beego/v2/server/web/swagger"
@ -54,13 +56,14 @@ const (
astTypeMap = "map" astTypeMap = "map"
) )
var pkgCache map[string]string //pkg:controller:function:comments comments: key:value var pkgCache map[string]struct{} //pkg:controller:function:comments comments: key:value
var controllerComments map[string]string var controllerComments map[string]string
var importlist map[string]string var importlist map[string]string
var controllerList map[string]map[string]*swagger.Item //controllername Paths items var controllerList map[string]map[string]*swagger.Item //controllername Paths items
var modelsList map[string]map[string]swagger.Schema var modelsList map[string]map[string]swagger.Schema
var rootapi swagger.Swagger var rootapi swagger.Swagger
var astPkgs []*ast.Package var astPkgs []*ast.Package
var pkgLoadedCache map[string]struct{}
// refer to builtin.go // refer to builtin.go
var basicTypes = map[string]string{ var basicTypes = map[string]string{
@ -94,12 +97,13 @@ var stdlibObject = map[string]string{
} }
func init() { func init() {
pkgCache = make(map[string]string) pkgCache = make(map[string]struct{})
controllerComments = make(map[string]string) controllerComments = make(map[string]string)
importlist = make(map[string]string) importlist = make(map[string]string)
controllerList = make(map[string]map[string]*swagger.Item) controllerList = make(map[string]map[string]*swagger.Item)
modelsList = make(map[string]map[string]swagger.Schema) modelsList = make(map[string]map[string]swagger.Schema)
astPkgs = make([]*ast.Package, 0) astPkgs = make([]*ast.Package, 0)
pkgLoadedCache = make(map[string]struct{})
} }
// parsePackagesFromDir parses packages from a given directory // parsePackagesFromDir parses packages from a given directory
@ -152,6 +156,16 @@ func parsePackageFromDir(path string) error {
astPkgs = append(astPkgs, v) astPkgs = append(astPkgs, v)
} }
if len(folderPkgs) != 0 {
workPath := bu.GetBeeWorkPath()
parentPath := filepath.Dir(workPath)
rel, err := filepath.Rel(parentPath, path)
if err != nil {
return err
}
pkgLoadedCache[rel] = struct{}{}
}
return nil return nil
} }
@ -448,7 +462,7 @@ func analyseControllerPkg(localName, pkgpath string) {
if _, ok := pkgCache[pkgpath]; ok { if _, ok := pkgCache[pkgpath]; ok {
return return
} }
pkgCache[pkgpath] = localName pkgCache[pkgpath] = struct{}{}
} else { } else {
beeLogger.Log.Fatalf("Package '%s' does not have source directory", pkgpath) beeLogger.Log.Fatalf("Package '%s' does not have source directory", pkgpath)
} }
@ -934,7 +948,7 @@ L:
continue continue
} }
parseObject(fl.Imports, d, k, &m, &realTypes, packageName) parseObject(fl.Imports, d, k, &m, &realTypes, astPkgs, packageName)
// When we've found the correct object, we can stop searching // When we've found the correct object, we can stop searching
break L break L
@ -959,7 +973,7 @@ L:
return str, m, realTypes return str, m, realTypes
} }
func parseObject(ims []*ast.ImportSpec, d *ast.Object, k string, m *swagger.Schema, realTypes *[]string, packageName string) { func parseObject(imports []*ast.ImportSpec, d *ast.Object, k string, m *swagger.Schema, realTypes *[]string, astPkgs []*ast.Package, packageName string) {
ts, ok := d.Decl.(*ast.TypeSpec) ts, ok := d.Decl.(*ast.TypeSpec)
if !ok { if !ok {
beeLogger.Log.Fatalf("Unknown type without TypeSec: %v", d) beeLogger.Log.Fatalf("Unknown type without TypeSec: %v", d)
@ -984,7 +998,7 @@ func parseObject(ims []*ast.ImportSpec, d *ast.Object, k string, m *swagger.Sche
case *ast.Ident: case *ast.Ident:
parseIdent(t, k, m, astPkgs) parseIdent(t, k, m, astPkgs)
case *ast.StructType: case *ast.StructType:
parseStruct(ims, t, k, m, realTypes, packageName) parseStruct(imports, t, k, m, realTypes, astPkgs, packageName)
} }
} }
@ -1069,7 +1083,7 @@ func parseIdent(st *ast.Ident, k string, m *swagger.Schema, astPkgs []*ast.Packa
} }
func parseStruct(ims []*ast.ImportSpec, st *ast.StructType, k string, m *swagger.Schema, realTypes *[]string, packageName string) { func parseStruct(imports []*ast.ImportSpec, st *ast.StructType, k string, m *swagger.Schema, realTypes *[]string, astPkgs []*ast.Package, packageName string) {
m.Title = k m.Title = k
if st.Fields.List != nil { if st.Fields.List != nil {
m.Properties = make(map[string]swagger.Propertie) m.Properties = make(map[string]swagger.Propertie)
@ -1085,10 +1099,12 @@ func parseStruct(ims []*ast.ImportSpec, st *ast.StructType, k string, m *swagger
realType = packageName + "." + realType realType = packageName + "." + realType
} }
} }
if !isBasicType(realType) && sType == astTypeObject {
checkAndLoadPackage(imports, realType, packageName)
}
*realTypes = append(*realTypes, realType) *realTypes = append(*realTypes, realType)
analyseImportPkg(ims, realType)
mp := swagger.Propertie{} mp := swagger.Propertie{}
isObject := false isObject := false
if isSlice { if isSlice {
@ -1208,7 +1224,7 @@ func parseStruct(ims []*ast.ImportSpec, st *ast.StructType, k string, m *swagger
for _, fl := range pkg.Files { for _, fl := range pkg.Files {
for nameOfObj, obj := range fl.Scope.Objects { for nameOfObj, obj := range fl.Scope.Objects {
if pkg.Name+"."+obj.Name == realType { if pkg.Name+"."+obj.Name == realType {
parseObject(obj, nameOfObj, nm, realTypes, astPkgs, pkg.Name) parseObject(imports, obj, nameOfObj, nm, realTypes, astPkgs, pkg.Name)
} }
} }
} }
@ -1345,61 +1361,68 @@ func str2RealType(s string, typ string) interface{} {
return ret return ret
} }
func analyseImportPkg(ims []*ast.ImportSpec, realType string) error { func checkAndLoadPackage(imports []*ast.ImportSpec, realType, curPkgName string) {
strs := strings.Split(realType, ".") arr := strings.Split(realType, ".")
pkgName := strs[0] if len(arr) != 2 {
return
}
objectPkgName := arr[0]
if objectPkgName == curPkgName {
return
}
pkgPath := ""
for _, im := range imports {
importPath := ""
if im.Path != nil {
importPath = strings.Trim(im.Path.Value, `"`)
}
for _, im := range ims { if importPath == "" {
pkgPath := strings.Trim(im.Path.Value, "\"")
if isSystemPackage(pkgPath) {
continue continue
} }
if val, ok := pkgCache[pkgPath]; ok { if im.Name != nil && im.Name.Name == objectPkgName {
if val == pkgName { pkgPath = importPath
return nil break
}
continue
} }
pkgRealPath := "" _, pkgName := filepath.Split(importPath)
cwd, _ := os.Getwd() if pkgName == objectPkgName {
vendorPath := path.Join(cwd, "vendor") pkgPath = importPath
break
realPath, _ := filepath.EvalSymlinks(filepath.Join(vendorPath, pkgPath))
if bu.IsExist(realPath) {
pkgRealPath = realPath
} else {
ok, _, currentpath := bu.SearchGOPATHs(pkgPath)
if ok {
pkgRealPath, _ = filepath.EvalSymlinks(currentpath)
}
}
if pkgRealPath == "" {
beeLogger.Log.Warnf("Cannot find pkgpath: %s ", pkgPath)
continue
}
fileSet := token.NewFileSet()
folderPkgs, 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 {
beeLogger.Log.Errorf("ParseDir Error, pkgpath:%s error:%s", pkgPath, err)
return err
}
for _, pkg := range folderPkgs {
if pkgName == pkg.Name || pkgName == im.Name.Name {
astPkgs = append(astPkgs, pkg)
pkgCache[pkgPath] = pkgName
}
} }
} }
return nil if pkgPath == "" {
beeLogger.Log.Warnf("%s missing import package", realType)
return
}
if isSystemPackage(pkgPath) {
return
}
if _, ok := pkgLoadedCache[pkgPath]; ok {
return
}
pkg, err := build.Default.Import(pkgPath, ".", build.FindOnly)
if err != nil {
beeLogger.Log.Warnf("Package %s cannot be imported, err:%v", pkgPath, err)
}
pkgRealpath := pkg.Dir
fileSet := token.NewFileSet()
pkgs, 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 {
beeLogger.Log.Fatalf("Error while parsing dir at '%s': %s", pkgRealpath, err)
}
for _, pkg := range pkgs {
astPkgs = append(astPkgs, pkg)
}
pkgLoadedCache[pkgPath] = struct{}{}
} }