mirror of
https://github.com/beego/bee.git
synced 2024-12-22 10:00:50 +00:00
Merge pull request #550 from franzwilhelm/develop
Add support for apps outside of GOPATH with go modules, fixes #549
This commit is contained in:
commit
e3e401cadd
@ -79,37 +79,44 @@ func init() {
|
||||
commands.AvailableCommands = append(commands.AvailableCommands, CmdRun)
|
||||
}
|
||||
|
||||
// RunApp locates files to watch, and starts the beego application
|
||||
func RunApp(cmd *commands.Command, args []string) int {
|
||||
if len(args) == 0 || args[0] == "watchall" {
|
||||
currpath, _ = os.Getwd()
|
||||
if found, _gopath, _ := utils.SearchGOPATHs(currpath); found {
|
||||
appname = path.Base(currpath)
|
||||
currentGoPath = _gopath
|
||||
} else {
|
||||
beeLogger.Log.Fatalf("No application '%s' found in your GOPATH", currpath)
|
||||
}
|
||||
} else {
|
||||
// Check if passed Bee application path/name exists in the GOPATH(s)
|
||||
if found, _gopath, _path := utils.SearchGOPATHs(args[0]); found {
|
||||
currpath = _path
|
||||
currentGoPath = _gopath
|
||||
appname = path.Base(currpath)
|
||||
} else {
|
||||
beeLogger.Log.Fatalf("No application '%s' found in your GOPATH", args[0])
|
||||
}
|
||||
// The default app path is the current working directory
|
||||
appPath, _ := os.Getwd()
|
||||
|
||||
if strings.HasSuffix(appname, ".go") && utils.IsExist(currpath) {
|
||||
// If an argument is presented, we use it as the app path
|
||||
if len(args) != 0 && args[0] != "watchall" {
|
||||
if path.IsAbs(args[0]) {
|
||||
appPath = args[0]
|
||||
} else {
|
||||
appPath = path.Join(appPath, args[0])
|
||||
}
|
||||
}
|
||||
|
||||
if utils.IsInGOPATH(appPath) {
|
||||
if found, _gopath, _path := utils.SearchGOPATHs(appPath); found {
|
||||
appPath = _path
|
||||
appname = path.Base(appPath)
|
||||
currentGoPath = _gopath
|
||||
} else {
|
||||
beeLogger.Log.Fatalf("No application '%s' found in your GOPATH", appPath)
|
||||
}
|
||||
if strings.HasSuffix(appname, ".go") && utils.IsExist(appPath) {
|
||||
beeLogger.Log.Warnf("The appname is in conflict with file's current path. Do you want to build appname as '%s'", appname)
|
||||
beeLogger.Log.Info("Do you want to overwrite it? [yes|no] ")
|
||||
if !utils.AskForConfirmation() {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
} else {
|
||||
beeLogger.Log.Warn("Running application outside of GOPATH")
|
||||
appname = path.Base(appPath)
|
||||
currentGoPath = appPath
|
||||
}
|
||||
|
||||
beeLogger.Log.Infof("Using '%s' as 'appname'", appname)
|
||||
|
||||
beeLogger.Log.Debugf("Current path: %s", utils.FILE(), utils.LINE(), currpath)
|
||||
beeLogger.Log.Debugf("Current path: %s", utils.FILE(), utils.LINE(), appPath)
|
||||
|
||||
if runmode == "prod" || runmode == "dev" {
|
||||
os.Setenv("BEEGO_RUNMODE", runmode)
|
||||
@ -122,7 +129,7 @@ func RunApp(cmd *commands.Command, args []string) int {
|
||||
}
|
||||
|
||||
var paths []string
|
||||
readAppDirectories(currpath, &paths)
|
||||
readAppDirectories(appPath, &paths)
|
||||
|
||||
// Because monitor files has some issues, we watch current directory
|
||||
// and ignore non-go files.
|
||||
@ -159,7 +166,7 @@ func RunApp(cmd *commands.Command, args []string) int {
|
||||
}
|
||||
}
|
||||
if downdoc == "true" {
|
||||
if _, err := os.Stat(path.Join(currpath, "swagger", "index.html")); err != nil {
|
||||
if _, err := os.Stat(path.Join(appPath, "swagger", "index.html")); err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
downloadFromURL(swaggerlink, "swagger.zip")
|
||||
unzipAndDelete("swagger.zip")
|
||||
|
@ -48,6 +48,12 @@ const (
|
||||
aform = "multipart/form-data"
|
||||
)
|
||||
|
||||
const (
|
||||
astTypeArray = "array"
|
||||
astTypeObject = "object"
|
||||
astTypeMap = "map"
|
||||
)
|
||||
|
||||
var pkgCache map[string]struct{} //pkg:controller:function:comments comments: key:value
|
||||
var controllerComments map[string]string
|
||||
var importlist map[string]string
|
||||
@ -78,11 +84,13 @@ var basicTypes = map[string]string{
|
||||
"byte": "string:byte",
|
||||
"rune": "string:byte",
|
||||
// builtin golang objects
|
||||
"time.Time": "string:datetime",
|
||||
"time.Time": "string:datetime",
|
||||
"json.RawMessage": "object:",
|
||||
}
|
||||
|
||||
var stdlibObject = map[string]string{
|
||||
"&{time Time}": "time.Time",
|
||||
"&{time Time}": "time.Time",
|
||||
"&{json RawMessage}": "json.RawMessage",
|
||||
}
|
||||
|
||||
func init() {
|
||||
@ -586,7 +594,7 @@ func parserComments(f *ast.FuncDecl, controllerName, pkgpath string) error {
|
||||
}
|
||||
if isArray {
|
||||
rs.Schema = &swagger.Schema{
|
||||
Type: "array",
|
||||
Type: astTypeArray,
|
||||
Items: &schema,
|
||||
}
|
||||
} else {
|
||||
@ -640,7 +648,7 @@ func parserComments(f *ast.FuncDecl, controllerName, pkgpath string) error {
|
||||
m, mod, realTypes := getModel(p[2])
|
||||
if isArray {
|
||||
para.Schema = &swagger.Schema{
|
||||
Type: "array",
|
||||
Type: astTypeArray,
|
||||
Items: &swagger.Schema{
|
||||
Ref: "#/definitions/" + m,
|
||||
},
|
||||
@ -781,7 +789,7 @@ func setParamType(para *swagger.Parameter, typ string, pkgpath, controllerName s
|
||||
isArray = true
|
||||
}
|
||||
if typ == "string" || typ == "number" || typ == "integer" || typ == "boolean" ||
|
||||
typ == "array" || typ == "file" {
|
||||
typ == astTypeArray || typ == "file" {
|
||||
paraType = typ
|
||||
} else if sType, ok := basicTypes[typ]; ok {
|
||||
typeFormat := strings.Split(sType, ":")
|
||||
@ -801,14 +809,14 @@ func setParamType(para *swagger.Parameter, typ string, pkgpath, controllerName s
|
||||
if isArray {
|
||||
if para.In == "body" {
|
||||
para.Schema = &swagger.Schema{
|
||||
Type: "array",
|
||||
Type: astTypeArray,
|
||||
Items: &swagger.Schema{
|
||||
Type: paraType,
|
||||
Format: paraFormat,
|
||||
},
|
||||
}
|
||||
} else {
|
||||
para.Type = "array"
|
||||
para.Type = astTypeArray
|
||||
para.Items = &swagger.ParameterItems{
|
||||
Type: paraType,
|
||||
Format: paraFormat,
|
||||
@ -901,49 +909,60 @@ func getparams(str string) []string {
|
||||
return r
|
||||
}
|
||||
|
||||
func getModel(str string) (objectname string, m swagger.Schema, realTypes []string) {
|
||||
func getModel(str string) (definitionName string, m swagger.Schema, realTypes []string) {
|
||||
strs := strings.Split(str, ".")
|
||||
objectname = strs[len(strs)-1]
|
||||
packageName := ""
|
||||
m.Type = "object"
|
||||
// strs = [packageName].[objectName]
|
||||
packageName := strs[0]
|
||||
objectname := strs[len(strs)-1]
|
||||
|
||||
// Default all swagger schemas to object, if no other type is found
|
||||
m.Type = astTypeObject
|
||||
|
||||
L:
|
||||
for _, pkg := range astPkgs {
|
||||
if strs[0] == pkg.Name {
|
||||
for _, fl := range pkg.Files {
|
||||
for k, d := range fl.Scope.Objects {
|
||||
if d.Kind == ast.Typ {
|
||||
if k != objectname {
|
||||
// Still searching for the right object
|
||||
continue
|
||||
}
|
||||
packageName = pkg.Name
|
||||
parseObject(d, k, &m, &realTypes, astPkgs, pkg.Name)
|
||||
parseObject(d, k, &m, &realTypes, astPkgs, packageName)
|
||||
|
||||
// When we've found the correct object, we can stop searching
|
||||
break L
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if m.Title == "" {
|
||||
beeLogger.Log.Warnf("Cannot find the object: %s", str)
|
||||
// Don't log when error has already been logged
|
||||
if _, found := rootapi.Definitions[str]; !found {
|
||||
beeLogger.Log.Warnf("Cannot find the object: %s", str)
|
||||
}
|
||||
m.Title = objectname
|
||||
// TODO remove when all type have been supported
|
||||
//os.Exit(1)
|
||||
}
|
||||
if len(rootapi.Definitions) == 0 {
|
||||
rootapi.Definitions = make(map[string]swagger.Schema)
|
||||
}
|
||||
objectname = packageName + "." + objectname
|
||||
rootapi.Definitions[objectname] = m
|
||||
return
|
||||
rootapi.Definitions[str] = m
|
||||
return str, m, realTypes
|
||||
}
|
||||
|
||||
func parseObject(d *ast.Object, k string, m *swagger.Schema, realTypes *[]string, astPkgs []*ast.Package, packageName string) {
|
||||
ts, ok := d.Decl.(*ast.TypeSpec)
|
||||
if !ok {
|
||||
beeLogger.Log.Fatalf("Unknown type without TypeSec: %v\n", d)
|
||||
beeLogger.Log.Fatalf("Unknown type without TypeSec: %v", d)
|
||||
}
|
||||
// TODO support other types, such as `ArrayType`, `MapType`, `InterfaceType` etc...
|
||||
// TODO support other types, such as `MapType`, `InterfaceType` etc...
|
||||
switch t := ts.Type.(type) {
|
||||
case *ast.ArrayType:
|
||||
m.Title = k
|
||||
m.Type = "array"
|
||||
m.Type = astTypeArray
|
||||
if isBasicType(fmt.Sprint(t.Elt)) {
|
||||
typeFormat := strings.Split(basicTypes[fmt.Sprint(t.Elt)], ":")
|
||||
m.Format = typeFormat[0]
|
||||
@ -970,8 +989,8 @@ func parseIdent(st *ast.Ident, k string, m *swagger.Schema, astPkgs []*ast.Packa
|
||||
if object, isStdLibObject := stdlibObject[basicType]; isStdLibObject {
|
||||
basicType = object
|
||||
}
|
||||
if k, ok := basicTypes[basicType]; ok {
|
||||
typeFormat := strings.Split(k, ":")
|
||||
if t, ok := basicTypes[basicType]; ok {
|
||||
typeFormat := strings.Split(t, ":")
|
||||
m.Type = typeFormat[0]
|
||||
m.Format = typeFormat[1]
|
||||
}
|
||||
@ -983,7 +1002,7 @@ func parseIdent(st *ast.Ident, k string, m *swagger.Schema, astPkgs []*ast.Packa
|
||||
if obj.Kind == ast.Con {
|
||||
vs, ok := obj.Decl.(*ast.ValueSpec)
|
||||
if !ok {
|
||||
beeLogger.Log.Fatalf("Unknown type without ValueSpec: %v\n", vs)
|
||||
beeLogger.Log.Fatalf("Unknown type without ValueSpec: %v", vs)
|
||||
}
|
||||
|
||||
ti, ok := vs.Type.(*ast.Ident)
|
||||
@ -1000,7 +1019,7 @@ func parseIdent(st *ast.Ident, k string, m *swagger.Schema, astPkgs []*ast.Packa
|
||||
for i, val := range vs.Values {
|
||||
v, ok := val.(*ast.BasicLit)
|
||||
if !ok {
|
||||
beeLogger.Log.Warnf("Unknown type without BasicLit: %v\n", v)
|
||||
beeLogger.Log.Warnf("Unknown type without BasicLit: %v", v)
|
||||
continue
|
||||
}
|
||||
enums[int(val.Pos())] = fmt.Sprintf("%s = %s", vs.Names[i].Name, v.Value)
|
||||
@ -1008,14 +1027,14 @@ func parseIdent(st *ast.Ident, k string, m *swagger.Schema, astPkgs []*ast.Packa
|
||||
case token.INT:
|
||||
vv, err := strconv.Atoi(v.Value)
|
||||
if err != nil {
|
||||
beeLogger.Log.Warnf("Unknown type with BasicLit to int: %v\n", v.Value)
|
||||
beeLogger.Log.Warnf("Unknown type with BasicLit to int: %v", v.Value)
|
||||
continue
|
||||
}
|
||||
enumValues[int(val.Pos())] = vv
|
||||
case token.FLOAT:
|
||||
vv, err := strconv.ParseFloat(v.Value, 64)
|
||||
if err != nil {
|
||||
beeLogger.Log.Warnf("Unknown type with BasicLit to int: %v\n", v.Value)
|
||||
beeLogger.Log.Warnf("Unknown type with BasicLit to int: %v", v.Value)
|
||||
continue
|
||||
}
|
||||
enumValues[int(val.Pos())] = vv
|
||||
@ -1050,7 +1069,7 @@ func parseStruct(st *ast.StructType, k string, m *swagger.Schema, realTypes *[]s
|
||||
m.Properties = make(map[string]swagger.Propertie)
|
||||
for _, field := range st.Fields.List {
|
||||
isSlice, realType, sType := typeAnalyser(field)
|
||||
if (isSlice && isBasicType(realType)) || sType == "object" {
|
||||
if (isSlice && isBasicType(realType)) || sType == astTypeObject {
|
||||
if len(strings.Split(realType, " ")) > 1 {
|
||||
realType = strings.Replace(realType, " ", ".", -1)
|
||||
realType = strings.Replace(realType, "&", "", -1)
|
||||
@ -1064,9 +1083,9 @@ func parseStruct(st *ast.StructType, k string, m *swagger.Schema, realTypes *[]s
|
||||
mp := swagger.Propertie{}
|
||||
isObject := false
|
||||
if isSlice {
|
||||
mp.Type = "array"
|
||||
if sType, ok := basicTypes[(strings.Replace(realType, "[]", "", -1))]; ok {
|
||||
typeFormat := strings.Split(sType, ":")
|
||||
mp.Type = astTypeArray
|
||||
if t, ok := basicTypes[(strings.Replace(realType, "[]", "", -1))]; ok {
|
||||
typeFormat := strings.Split(t, ":")
|
||||
mp.Items = &swagger.Propertie{
|
||||
Type: typeFormat[0],
|
||||
Format: typeFormat[1],
|
||||
@ -1077,14 +1096,14 @@ func parseStruct(st *ast.StructType, k string, m *swagger.Schema, realTypes *[]s
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if sType == "object" {
|
||||
if sType == astTypeObject {
|
||||
isObject = true
|
||||
mp.Ref = "#/definitions/" + realType
|
||||
} else if isBasicType(realType) {
|
||||
typeFormat := strings.Split(sType, ":")
|
||||
mp.Type = typeFormat[0]
|
||||
mp.Format = typeFormat[1]
|
||||
} else if realType == "map" {
|
||||
} else if realType == astTypeMap {
|
||||
typeFormat := strings.Split(sType, ":")
|
||||
mp.AdditionalProperties = &swagger.Propertie{
|
||||
Type: typeFormat[0],
|
||||
@ -1120,7 +1139,6 @@ func parseStruct(st *ast.StructType, k string, m *swagger.Schema, realTypes *[]s
|
||||
}
|
||||
|
||||
tag := stag.Get("json")
|
||||
|
||||
if tag != "" {
|
||||
tagValues = strings.Split(tag, ",")
|
||||
}
|
||||
@ -1202,12 +1220,12 @@ func typeAnalyser(f *ast.Field) (isSlice bool, realType, swaggerType string) {
|
||||
return true, fmt.Sprintf("[]%v", arr.Elt), basicTypes[fmt.Sprint(arr.Elt)]
|
||||
}
|
||||
if mp, ok := arr.Elt.(*ast.MapType); ok {
|
||||
return false, fmt.Sprintf("map[%v][%v]", mp.Key, mp.Value), "object"
|
||||
return false, fmt.Sprintf("map[%v][%v]", mp.Key, mp.Value), astTypeObject
|
||||
}
|
||||
if star, ok := arr.Elt.(*ast.StarExpr); ok {
|
||||
return true, fmt.Sprint(star.X), "object"
|
||||
return true, fmt.Sprint(star.X), astTypeObject
|
||||
}
|
||||
return true, fmt.Sprint(arr.Elt), "object"
|
||||
return true, fmt.Sprint(arr.Elt), astTypeObject
|
||||
}
|
||||
switch t := f.Type.(type) {
|
||||
case *ast.StarExpr:
|
||||
@ -1218,13 +1236,13 @@ func typeAnalyser(f *ast.Field) (isSlice bool, realType, swaggerType string) {
|
||||
if k, ok := basicTypes[basicType]; ok {
|
||||
return false, basicType, k
|
||||
}
|
||||
return false, basicType, "object"
|
||||
return false, basicType, astTypeObject
|
||||
case *ast.MapType:
|
||||
val := fmt.Sprintf("%v", t.Value)
|
||||
if isBasicType(val) {
|
||||
return false, "map", basicTypes[val]
|
||||
return false, astTypeMap, basicTypes[val]
|
||||
}
|
||||
return false, val, "object"
|
||||
return false, val, astTypeObject
|
||||
}
|
||||
basicType := fmt.Sprint(f.Type)
|
||||
if object, isStdLibObject := stdlibObject[basicType]; isStdLibObject {
|
||||
@ -1233,7 +1251,7 @@ func typeAnalyser(f *ast.Field) (isSlice bool, realType, swaggerType string) {
|
||||
if k, ok := basicTypes[basicType]; ok {
|
||||
return false, basicType, k
|
||||
}
|
||||
return false, basicType, "object"
|
||||
return false, basicType, astTypeObject
|
||||
}
|
||||
|
||||
func isBasicType(Type string) bool {
|
||||
@ -1247,7 +1265,7 @@ func isBasicType(Type string) bool {
|
||||
func appendModels(pkgpath, controllerName string, realTypes []string) {
|
||||
for _, realType := range realTypes {
|
||||
if realType != "" && !isBasicType(strings.TrimLeft(realType, "[]")) &&
|
||||
!strings.HasPrefix(realType, "map") && !strings.HasPrefix(realType, "&") {
|
||||
!strings.HasPrefix(realType, astTypeMap) && !strings.HasPrefix(realType, "&") {
|
||||
if _, ok := modelsList[pkgpath+controllerName][realType]; ok {
|
||||
continue
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user