mirror of https://github.com/1Panel-dev/1Panel
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
207 lines
5.9 KiB
207 lines
5.9 KiB
package docs
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"go/ast"
|
|
"go/parser"
|
|
"go/token"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestGenerateXlog(t *testing.T) {
|
|
fset := token.NewFileSet()
|
|
|
|
apiDirs := []string{"../../../agent/app/api/v2", "../../../core/app/api/v2", "../../../agent/xpack/app/api/v2", "../../../core/xpack/app/api/v2"}
|
|
|
|
xlogMap := make(map[string]operationJson)
|
|
for _, dir := range apiDirs {
|
|
if err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if info.IsDir() {
|
|
return nil
|
|
}
|
|
fileItem, err := parser.ParseFile(fset, path, nil, parser.ParseComments)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for _, decl := range fileItem.Decls {
|
|
switch d := decl.(type) {
|
|
case *ast.FuncDecl:
|
|
if d.Doc != nil {
|
|
routerContent := ""
|
|
logContent := ""
|
|
for _, comment := range d.Doc.List {
|
|
if strings.HasPrefix(comment.Text, "// @Router") {
|
|
routerContent = replaceStr(comment.Text, "// @Router", "[post]", "[get]", " ")
|
|
}
|
|
if strings.HasPrefix(comment.Text, "// @x-panel-log") {
|
|
logContent = replaceStr(comment.Text, "// @x-panel-log", " ")
|
|
}
|
|
}
|
|
if len(routerContent) != 0 && len(logContent) != 0 {
|
|
var item operationJson
|
|
if err := json.Unmarshal([]byte(logContent), &item); err != nil {
|
|
panic(fmt.Sprintf("json unamrshal failed, err: %v", err))
|
|
}
|
|
xlogMap[routerContent] = item
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}); err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
newJson, err := json.MarshalIndent(xlogMap, "", "\t")
|
|
if err != nil {
|
|
panic(fmt.Sprintf("json marshal for new file failed, err: %v", err))
|
|
}
|
|
if err := os.WriteFile("x-log.json", newJson, 0640); err != nil {
|
|
panic(fmt.Sprintf("write new swagger.json failed, err: %v", err))
|
|
}
|
|
}
|
|
|
|
func TestGenerateSwaggerDoc(t *testing.T) {
|
|
workDir := "/usr/songliu/1Panel"
|
|
swagBin := "/root/go/bin/swag"
|
|
|
|
cmd1 := exec.Command(swagBin, "init", "-o", workDir+"/cmd/server/docs/docs_agent", "-d", workDir+"/agent", "-g", "./cmd/server/main.go")
|
|
cmd1.Dir = workDir
|
|
std1, err := cmd1.CombinedOutput()
|
|
if err != nil {
|
|
fmt.Printf("generate swagger doc of agent failed, std1: %v, err: %v", string(std1), err)
|
|
return
|
|
}
|
|
cmd2 := exec.Command(swagBin, "init", "-o", workDir+"/cmd/server/docs/docs_core", "-d", workDir+"/core", "-g", "../cmd/server/main.go")
|
|
cmd2.Dir = workDir
|
|
std2, err := cmd2.CombinedOutput()
|
|
if err != nil {
|
|
fmt.Printf("generate swagger doc of core failed, std1: %v, err: %v", string(std2), err)
|
|
return
|
|
}
|
|
|
|
agentJson := workDir + "/cmd/server/docs/docs_agent/swagger.json"
|
|
agentFile, err := os.ReadFile(agentJson)
|
|
if err != nil {
|
|
fmt.Printf("read file docs_agent failed, err: %v", err)
|
|
return
|
|
}
|
|
var agentSwagger Swagger
|
|
if err := json.Unmarshal(agentFile, &agentSwagger); err != nil {
|
|
fmt.Printf("agent json unmarshal failed, err: %v", err)
|
|
return
|
|
}
|
|
|
|
coreJson := workDir + "/cmd/server/docs/docs_core/swagger.json"
|
|
coreFile, err := os.ReadFile(coreJson)
|
|
if err != nil {
|
|
fmt.Printf("read file docs_core failed, err: %v", err)
|
|
return
|
|
}
|
|
var coreSwagger Swagger
|
|
if err := json.Unmarshal(coreFile, &coreSwagger); err != nil {
|
|
fmt.Printf("core json unmarshal failed, err: %v", err)
|
|
return
|
|
}
|
|
|
|
newSwagger := Swagger{
|
|
Swagger: agentSwagger.Swagger,
|
|
Info: agentSwagger.Info,
|
|
Host: agentSwagger.Host,
|
|
BasePath: agentSwagger.BasePath,
|
|
Paths: agentSwagger.Paths,
|
|
Definitions: agentSwagger.Definitions,
|
|
}
|
|
|
|
for key, val := range coreSwagger.Paths {
|
|
if _, ok := newSwagger.Paths[key]; ok {
|
|
fmt.Printf("duplicate interfaces were found: %s \n", key)
|
|
}
|
|
newSwagger.Paths[key] = val
|
|
}
|
|
|
|
newJson, err := json.MarshalIndent(newSwagger, "", "\t")
|
|
if err != nil {
|
|
fmt.Printf("json marshal for new file failed, err: %v", err)
|
|
return
|
|
}
|
|
if err := os.WriteFile("swagger.json", newJson, 0640); err != nil {
|
|
fmt.Printf("write new swagger.json failed, err: %v", err)
|
|
return
|
|
}
|
|
docTemplate := strings.ReplaceAll(loadDefaultDocs(), "const docTemplate = \"aa\"", fmt.Sprintf("const docTemplate = `%s`", string(newJson)))
|
|
if err := os.WriteFile(workDir+"/cmd/server/docs/docs.go", []byte(docTemplate), 0640); err != nil {
|
|
fmt.Printf("write new docs.go failed, err: %v", err)
|
|
return
|
|
}
|
|
|
|
_ = os.RemoveAll(workDir + "/cmd/server/docs/docs_agent")
|
|
_ = os.RemoveAll(workDir + "/cmd/server/docs/docs_core")
|
|
}
|
|
|
|
type Swagger struct {
|
|
Swagger string `json:"swagger"`
|
|
Info interface{} `json:"info"`
|
|
Host string `json:"host"`
|
|
BasePath string `json:"basePath"`
|
|
Paths map[string]interface{} `json:"paths"`
|
|
Definitions interface{} `json:"definitions"`
|
|
}
|
|
|
|
func loadDefaultDocs() string {
|
|
return `package docs
|
|
|
|
import "github.com/swaggo/swag"
|
|
|
|
const docTemplate = "aa"
|
|
|
|
var SwaggerInfo = &swag.Spec{
|
|
Version: "2.0",
|
|
Host: "localhost",
|
|
BasePath: "/api/v2",
|
|
Schemes: []string{},
|
|
Title: "1Panel",
|
|
Description: "开源Linux面板",
|
|
InfoInstanceName: "swagger",
|
|
SwaggerTemplate: docTemplate,
|
|
LeftDelim: "{{",
|
|
RightDelim: "}}",
|
|
}
|
|
|
|
func init() {
|
|
swag.Register(SwaggerInfo.InstanceName(), SwaggerInfo)
|
|
}`
|
|
}
|
|
|
|
func replaceStr(val string, rep ...string) string {
|
|
for _, item := range rep {
|
|
val = strings.ReplaceAll(val, item, "")
|
|
}
|
|
return val
|
|
}
|
|
|
|
type operationJson struct {
|
|
BodyKeys []string `json:"bodyKeys"`
|
|
ParamKeys []string `json:"paramKeys"`
|
|
BeforeFunctions []functionInfo `json:"beforeFunctions"`
|
|
FormatZH string `json:"formatZH"`
|
|
FormatEN string `json:"formatEN"`
|
|
}
|
|
type functionInfo struct {
|
|
InputColumn string `json:"input_column"`
|
|
InputValue string `json:"input_value"`
|
|
IsList bool `json:"isList"`
|
|
DB string `json:"db"`
|
|
OutputColumn string `json:"output_column"`
|
|
OutputValue string `json:"output_value"`
|
|
}
|