Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge develop #872

Merged
merged 10 commits into from
Nov 28, 2024
2 changes: 1 addition & 1 deletion cmd/commands/api/apiapp.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ var CmdApiapp = &commands.Command{
Short: "Creates a Beego API application",
Long: `
The command 'api' creates a Beego API application.
now default supoort generate a go modules project.
now default support generate a go modules project.

{{"Example:"|bold}}
$ bee api [appname] [-tables=""] [-driver=mysql] [-conn="root:@tcp(127.0.0.1:3306)/test"] [-gopath=false] [-beego=v1.12.3]
Expand Down
3 changes: 2 additions & 1 deletion cmd/commands/migrate/migrate.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
// 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
// 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
Expand Down Expand Up @@ -300,6 +300,7 @@ func writeMigrationSourceFile(dir, source, driver, connStr string, latestTime in
// buildMigrationBinary changes directory to database/migrations folder and go-build the source
func buildMigrationBinary(dir, binary string) {
changeDir(dir)
_ = exec.Command("go", "mod", "tidy").Run()
cmd := exec.Command("go", "build", "-o", binary)
if out, err := cmd.CombinedOutput(); err != nil {
beeLogger.Log.Errorf("Could not build migration binary: %s", err)
Expand Down
2 changes: 1 addition & 1 deletion config/conf.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import (
const confVer = 0

const (
Version = "2.1.0"
Version = "2.3.0"
GitRemotePath = "github.com/beego/bee/v2"
)

Expand Down
2 changes: 1 addition & 1 deletion generate/g_scaffold.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,5 +46,5 @@ func GenerateScaffold(sname, fields, currpath, driver, conn string) {
if utils.AskForConfirmation() {
migrate.MigrateUpdate(currpath, driver, conn, "")
}
beeLogger.Log.Successf("All done! Don't forget to add beego.Router(\"/%s\" ,&controllers.%sController{}) to routers/route.go\n", sname, strings.Title(sname))
beeLogger.Log.Successf("All done! Don't forget to add beego.AutoPrefix(\"/%s\" ,&controllers.%sController{}) to routers/route.go\n", sname, strings.Title(sname))
}
180 changes: 146 additions & 34 deletions generate/swaggergen/g_docs.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,15 @@
package swaggergen

import (
"bufio"
"encoding/json"
"errors"
"fmt"
"go/ast"
"go/build"
"go/parser"
"go/token"
"io"
"os"
"path"
"path/filepath"
Expand Down Expand Up @@ -56,12 +58,17 @@ const (
astTypeMap = "map"
)

const defaultNamespacePrefix = ""

var pkgCache map[string]struct{} //pkg:controller:function:comments comments: key:value
var controllerComments map[string]string
var importlist map[string]string
var controllerList map[string]map[string]*swagger.Item //controllername Paths items
var modelsList map[string]map[string]swagger.Schema
var rootapi swagger.Swagger

var rootapiSingle = false
var rootapiDefault swagger.Swagger
var rootapiMap map[string]*swagger.Swagger // version, swagger
var astPkgs []*ast.Package
var pkgLoadedCache map[string]struct{}

Expand Down Expand Up @@ -106,6 +113,7 @@ func init() {
importlist = make(map[string]string)
controllerList = make(map[string]map[string]*swagger.Item)
modelsList = make(map[string]map[string]swagger.Schema)
rootapiMap = make(map[string]*swagger.Swagger)
astPkgs = make([]*ast.Package, 0)
pkgLoadedCache = make(map[string]struct{})
}
Expand Down Expand Up @@ -188,14 +196,21 @@ func GenerateDocs(curpath string) {
beeLogger.Log.Fatalf("Error while parsing router.go: %s", err)
}

rootapi.Infos = swagger.Information{}
rootapi.SwaggerVersion = "2.0"

// Analyse API comments
if f.Comments != nil {
for _, c := range f.Comments {
var namespacePrefix string
rootapi := swagger.Swagger{
Infos: swagger.Information{},
SwaggerVersion: "2.0",
}
for _, s := range strings.Split(c.Text(), "\n") {
if strings.HasPrefix(s, "@APIVersion") {
if strings.HasPrefix(s, "@NamespacePrefix") {
namespacePrefix = strings.TrimSpace(s[len("@NamespacePrefix"):])
if _, exist := rootapiMap[namespacePrefix]; !exist {
rootapiMap[namespacePrefix] = &rootapi
}
} else if strings.HasPrefix(s, "@APIVersion") {
rootapi.Infos.Version = strings.TrimSpace(s[len("@APIVersion"):])
} else if strings.HasPrefix(s, "@Title") {
rootapi.Infos.Title = strings.TrimSpace(s[len("@Title"):])
Expand Down Expand Up @@ -279,6 +294,12 @@ func GenerateDocs(curpath string) {
rootapi.Security = append(rootapi.Security, getSecurity(s))
}
}

_, namespacePrefixExist := rootapiMap[namespacePrefix]
if !namespacePrefixExist && !rootapiSingle {
rootapiSingle = true
rootapiDefault = rootapi
}
}
}
// Analyse controller package
Expand All @@ -289,6 +310,7 @@ func GenerateDocs(curpath string) {
}
analyseControllerPkg(localName, im.Path.Value)
}

for _, d := range f.Decls {
switch specDecl := d.(type) {
case *ast.FuncDecl:
Expand All @@ -302,21 +324,43 @@ func GenerateDocs(curpath string) {
if !selOK || selExpr.Sel.Name != "NewNamespace" {
continue
}

version, params := analyseNewNamespace(v)
if rootapi.BasePath == "" && version != "" {
var rootapi *swagger.Swagger
if rootapiSingle {
rootapi = &rootapiDefault
} else {
_rootapi, rootapiExist := rootapiMap[version]
if !rootapiExist {
rootapi = &swagger.Swagger{
Infos: swagger.Information{},
SwaggerVersion: "2.0",
}
rootapiMap[version] = rootapi
} else {
rootapi = _rootapi
}
}

if rootapi.BasePath == "" {
rootapi.BasePath = version
}

for _, p := range params {
switch pp := p.(type) {
case *ast.CallExpr:
var controllerName string
if selname := pp.Fun.(*ast.SelectorExpr).Sel.String(); selname == "NSNamespace" {
s, params := analyseNewNamespace(pp)
if rootapi.BasePath == "" {
s = path.Join(version, s)
}

for _, sp := range params {
switch pp := sp.(type) {
case *ast.CallExpr:
if pp.Fun.(*ast.SelectorExpr).Sel.String() == "NSInclude" {
controllerName = analyseNSInclude(s, pp)
controllerName = analyseNSInclude(s, pp, rootapi)
if v, ok := controllerComments[controllerName]; ok {
rootapi.Tags = append(rootapi.Tags, swagger.Tag{
Name: strings.Trim(s, "/"),
Expand All @@ -327,7 +371,7 @@ func GenerateDocs(curpath string) {
}
}
} else if selname == "NSInclude" {
controllerName = analyseNSInclude("", pp)
controllerName = analyseNSInclude("", pp, rootapi)
if v, ok := controllerComments[controllerName]; ok {
rootapi.Tags = append(rootapi.Tags, swagger.Tag{
Name: controllerName, // if the NSInclude has no prefix, we use the controllername as the tag
Expand All @@ -344,27 +388,42 @@ func GenerateDocs(curpath string) {
}
}
}
os.Mkdir(path.Join(curpath, "swagger"), 0755)
fd, err := os.Create(path.Join(curpath, "swagger", "swagger.json"))
if err != nil {
panic(err)
}
fdyml, err := os.Create(path.Join(curpath, "swagger", "swagger.yml"))
if err != nil {
panic(err)
}
defer fdyml.Close()
defer fd.Close()
dt, err := json.MarshalIndent(rootapi, "", " ")
dtyml, erryml := yaml.Marshal(rootapi)
if err != nil || erryml != nil {
panic(err)

if rootapiSingle {
rootapiMap[defaultNamespacePrefix] = &rootapiDefault
}
_, err = fd.Write(dt)
_, erryml = fdyml.Write(dtyml)
if err != nil || erryml != nil {
panic(err)

for version, api := range rootapiMap {
api.Definitions = rootapiDefault.Definitions

dir := path.Join(curpath, "swagger", version)
os.MkdirAll(dir, 0755)

fd, err := os.Create(path.Join(dir, "swagger.json"))
if err != nil {
panic(err)
}
defer fd.Close()

fdyml, err := os.Create(path.Join(dir, "swagger.yml"))
if err != nil {
panic(err)
}
defer fdyml.Close()

dt, err := json.MarshalIndent(api, "", " ")
dtyml, erryml := yaml.Marshal(api)
if err != nil || erryml != nil {
panic(err)
}
_, err = fd.Write(dt)
_, erryml = fdyml.Write(dtyml)
if err != nil || erryml != nil {
panic(err)
}
}

modifySwaggerIndexFile(curpath, rootapiSingle, rootapiMap)
}

// analyseNewNamespace returns version and the others params
Expand All @@ -382,7 +441,7 @@ func analyseNewNamespace(ce *ast.CallExpr) (first string, others []ast.Expr) {
return
}

func analyseNSInclude(baseurl string, ce *ast.CallExpr) string {
func analyseNSInclude(baseurl string, ce *ast.CallExpr, rootapi *swagger.Swagger) string {
cname := ""
for _, p := range ce.Args {
var x *ast.SelectorExpr
Expand Down Expand Up @@ -558,7 +617,7 @@ func parserComments(f *ast.FuncDecl, controllerName, pkgpath string) error {
elements := strings.TrimSpace(t[len("@router"):])
e1 := strings.SplitN(elements, " ", 2)
if len(e1) < 1 {
return errors.New("you should has router infomation")
return errors.New("you should has router information")
}
routerPath = e1[0]
if len(e1) == 2 && e1[1] != "" {
Expand Down Expand Up @@ -964,16 +1023,16 @@ L:

if m.Title == "" {
// Don't log when error has already been logged
if _, found := rootapi.Definitions[str]; !found {
if _, found := rootapiDefault.Definitions[str]; !found {
beeLogger.Log.Warnf("Cannot find the object: %s", str)
}
m.Title = objectname
// TODO remove when all type have been supported
}
if len(rootapi.Definitions) == 0 {
rootapi.Definitions = make(map[string]swagger.Schema)
if len(rootapiDefault.Definitions) == 0 {
rootapiDefault.Definitions = make(map[string]swagger.Schema)
}
rootapi.Definitions[str] = m
rootapiDefault.Definitions[str] = m
return str, m, realTypes
}

Expand All @@ -992,7 +1051,7 @@ func parseObject(imports []*ast.ImportSpec, d *ast.Object, k string, m *swagger.
m.Format = typeFormat[0]
} else {
objectName := packageName + "." + fmt.Sprint(t.Elt)
if _, ok := rootapi.Definitions[objectName]; !ok {
if _, ok := rootapiDefault.Definitions[objectName]; !ok {
objectName, _, _ = getModel(objectName)
}
m.Items = &swagger.Schema{
Expand Down Expand Up @@ -1453,3 +1512,56 @@ func checkAndLoadPackage(imports []*ast.ImportSpec, realType, curPkgName string)

pkgLoadedCache[pkgPath] = struct{}{}
}

func modifySwaggerIndexFile(curpath string, rootapiSingle bool, rootapiMap map[string]*swagger.Swagger) {
swaggerIndexFilename := "index.html"
swaggerIndexFullname := path.Join(curpath, "swagger", swaggerIndexFilename)

swaggerJsonFilename := "swagger.json"
swaggerUIBundleSign := `SwaggerUIBundle(`
var swaggerUIBundleSignPass bool

if _, err := os.Stat(swaggerIndexFullname); !os.IsNotExist(err) {
var swaggerJsonUrl string
if rootapiSingle {
swaggerJsonUrl = fmt.Sprintf(` url: "%s",`, swaggerJsonFilename)
} else {
urls := make([]string, 0)
for namespace, _ := range rootapiMap {
namespace = strings.TrimLeft(namespace, "/")
urls = append(urls, fmt.Sprintf(`{url: "%s", name: "%s"}`, path.Join(namespace, swaggerJsonFilename), namespace))
}
swaggerJsonUrl = fmt.Sprintf(` urls: [%s],`, strings.Join(urls, ", "))
}

var indexFileContent string
if f, err := os.Open(swaggerIndexFullname); err == nil {
defer f.Close()

buf := bufio.NewReader(f)
for {
line, _, c := buf.ReadLine()
if c == io.EOF {
break
}

if strings.Contains(string(line), swaggerUIBundleSign) {
swaggerUIBundleSignPass = true
}
if swaggerUIBundleSignPass && (strings.Contains(string(line), "url:") || strings.Contains(string(line), "urls:")) {
indexFileContent += swaggerJsonUrl + "\n"
} else {
indexFileContent += string(line) + "\n"
}
}
}

if fw, err := os.OpenFile(swaggerIndexFullname, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666); err == nil {
defer fw.Close()

w := bufio.NewWriter(fw)
w.WriteString(indexFileContent)
w.Flush()
}
}
}
14 changes: 7 additions & 7 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ require (
github.com/shopspring/decimal v1.3.1
github.com/smartwalle/pongo2render v1.0.1
github.com/spf13/viper v1.7.0
golang.org/x/tools v0.1.12
golang.org/x/tools v0.6.0
gopkg.in/yaml.v2 v2.4.0
)

Expand Down Expand Up @@ -52,12 +52,12 @@ require (
github.com/subosito/gotenv v1.2.0 // indirect
go.starlark.net v0.0.0-20220816155156-cfacd8902214 // indirect
golang.org/x/arch v0.0.0-20190927153633-4e8777c89be4 // indirect
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd // indirect
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
golang.org/x/net v0.7.0 // indirect
golang.org/x/sys v0.6.0 // indirect
golang.org/x/text v0.7.0 // indirect
google.golang.org/protobuf v1.30.0 // indirect
golang.org/x/crypto v0.21.0 // indirect
golang.org/x/mod v0.8.0 // indirect
golang.org/x/net v0.23.0 // indirect
golang.org/x/sys v0.18.0 // indirect
golang.org/x/text v0.14.0 // indirect
google.golang.org/protobuf v1.33.0 // indirect
gopkg.in/ini.v1 v1.51.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
Loading