vikunja-api/vendor/github.com/swaggo/swag/gen/gen.go

283 lines
6.4 KiB
Go
Raw Normal View History

package gen
import (
2019-10-16 22:52:29 +02:00
"bytes"
"encoding/json"
2019-05-07 21:42:24 +02:00
"fmt"
2019-10-16 22:52:29 +02:00
"go/format"
"io"
"log"
"os"
"path"
2019-10-16 22:52:29 +02:00
"strings"
"text/template"
"time"
2019-10-16 22:52:29 +02:00
"github.com/go-openapi/spec"
"github.com/ghodss/yaml"
"github.com/swaggo/swag"
)
// Gen presents a generate tool for swag.
2019-10-16 22:52:29 +02:00
type Gen struct{}
// New creates a new Gen.
func New() *Gen {
return &Gen{}
}
2019-05-07 21:42:24 +02:00
// Config presents Gen configurations.
type Config struct {
// SearchDir the swag would be parse
SearchDir string
2019-10-16 22:52:29 +02:00
// OutputDir represents the output directory for al the generated files
2019-05-07 21:42:24 +02:00
OutputDir string
2019-10-16 22:52:29 +02:00
// MainAPIFile the Go file path in which 'swagger general API Info' is written
2019-05-07 21:42:24 +02:00
MainAPIFile string
2019-10-16 22:52:29 +02:00
// PropNamingStrategy represents property naming strategy like snakecase,camelcase,pascalcase
2019-05-07 21:42:24 +02:00
PropNamingStrategy string
2019-10-16 22:52:29 +02:00
// ParseVendor whether swag should be parse vendor folder
2019-05-07 21:42:24 +02:00
ParseVendor bool
2019-10-16 22:52:29 +02:00
// ParseDependencies whether swag should be parse outside dependency folder
ParseDependency bool
// MarkdownFilesDir used to find markdownfiles, which can be used for tag descriptions
MarkdownFilesDir string
2019-05-07 21:42:24 +02:00
}
2019-10-16 22:52:29 +02:00
// Build builds swagger json file for given searchDir and mainAPIFile. Returns json
2019-05-07 21:42:24 +02:00
func (g *Gen) Build(config *Config) error {
if _, err := os.Stat(config.SearchDir); os.IsNotExist(err) {
return fmt.Errorf("dir: %s is not exist", config.SearchDir)
}
log.Println("Generate swagger docs....")
2019-10-16 22:52:29 +02:00
p := swag.New(swag.SetMarkdownFileDirectory(config.MarkdownFilesDir))
2019-05-07 21:42:24 +02:00
p.PropNamingStrategy = config.PropNamingStrategy
p.ParseVendor = config.ParseVendor
2019-10-16 22:52:29 +02:00
p.ParseDependency = config.ParseDependency
2019-05-07 21:42:24 +02:00
if err := p.ParseAPI(config.SearchDir, config.MainAPIFile); err != nil {
return err
}
swagger := p.GetSwagger()
2019-10-16 22:52:29 +02:00
b, err := g.jsonIndent(swagger)
if err != nil {
return err
}
2019-10-16 22:52:29 +02:00
if err := os.MkdirAll(config.OutputDir, os.ModePerm); err != nil {
return err
}
2019-05-07 21:42:24 +02:00
docs, err := os.Create(path.Join(config.OutputDir, "docs.go"))
if err != nil {
return err
}
defer docs.Close()
2019-05-07 21:42:24 +02:00
swaggerJSON, err := os.Create(path.Join(config.OutputDir, "swagger.json"))
if err != nil {
return err
}
defer swaggerJSON.Close()
2019-10-16 22:52:29 +02:00
if _, err := swaggerJSON.Write(b); err != nil {
return err
}
2019-05-07 21:42:24 +02:00
swaggerYAML, err := os.Create(path.Join(config.OutputDir, "swagger.yaml"))
if err != nil {
return err
}
defer swaggerYAML.Close()
y, err := yaml.JSONToYAML(b)
if err != nil {
2019-10-16 22:52:29 +02:00
return fmt.Errorf("cannot covert json to yaml error: %s", err)
}
2019-10-16 22:52:29 +02:00
if _, err := swaggerYAML.Write(y); err != nil {
return err
}
2019-10-16 22:52:29 +02:00
// Write doc
err = g.writeGoDoc(docs, swagger)
if err != nil {
return err
}
log.Printf("create docs.go at %+v", docs.Name())
2019-05-07 21:42:24 +02:00
log.Printf("create swagger.json at %+v", swaggerJSON.Name())
log.Printf("create swagger.yaml at %+v", swaggerYAML.Name())
return nil
}
2019-10-16 22:52:29 +02:00
func (g *Gen) jsonIndent(data interface{}) ([]byte, error) {
return json.MarshalIndent(data, "", " ")
}
func (g *Gen) formatSource(src []byte) []byte {
code, err := format.Source(src)
if err != nil {
code = src // Output the unformated code anyway
}
return code
}
func (g *Gen) writeGoDoc(output io.Writer, swagger *spec.Swagger) error {
generator, err := template.New("swagger_info").Funcs(template.FuncMap{
"printDoc": func(v string) string {
// Add schemes
v = "{\n \"schemes\": {{ marshal .Schemes }}," + v[1:]
// Sanitize backticks
return strings.Replace(v, "`", "`+\"`\"+`", -1)
},
}).Parse(packageTemplate)
if err != nil {
return err
}
swaggerSpec := &spec.Swagger{
VendorExtensible: swagger.VendorExtensible,
SwaggerProps: spec.SwaggerProps{
ID: swagger.ID,
Consumes: swagger.Consumes,
Produces: swagger.Produces,
Swagger: swagger.Swagger,
Info: &spec.Info{
VendorExtensible: swagger.Info.VendorExtensible,
InfoProps: spec.InfoProps{
Description: "{{.Description}}",
Title: "{{.Title}}",
TermsOfService: swagger.Info.TermsOfService,
Contact: swagger.Info.Contact,
License: swagger.Info.License,
Version: "{{.Version}}",
},
},
Host: "{{.Host}}",
BasePath: "{{.BasePath}}",
Paths: swagger.Paths,
Definitions: swagger.Definitions,
Parameters: swagger.Parameters,
Responses: swagger.Responses,
SecurityDefinitions: swagger.SecurityDefinitions,
Security: swagger.Security,
Tags: swagger.Tags,
ExternalDocs: swagger.ExternalDocs,
},
}
// crafted docs.json
buf, err := g.jsonIndent(swaggerSpec)
if err != nil {
return err
}
buffer := &bytes.Buffer{}
err = generator.Execute(buffer, struct {
Timestamp time.Time
Doc string
Host string
BasePath string
Schemes []string
Title string
Description string
Version string
}{
Timestamp: time.Now(),
Doc: string(buf),
Host: swagger.Host,
BasePath: swagger.BasePath,
Schemes: swagger.Schemes,
Title: swagger.Info.Title,
Description: swagger.Info.Description,
Version: swagger.Info.Version,
})
if err != nil {
return err
}
code := g.formatSource(buffer.Bytes())
// write
_, err = output.Write(code)
return err
}
var packageTemplate = `// GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
// This file was generated by swaggo/swag at
// {{ .Timestamp }}
package docs
import (
"bytes"
2019-10-16 22:52:29 +02:00
"encoding/json"
"strings"
"github.com/alecthomas/template"
"github.com/swaggo/swag"
)
2019-10-16 22:52:29 +02:00
var doc = ` + "`{{ printDoc .Doc}}`" + `
type swaggerInfo struct {
Version string
Host string
BasePath string
2019-10-16 22:52:29 +02:00
Schemes []string
Title string
Description string
}
// SwaggerInfo holds exported Swagger Info so clients can modify it
2019-10-16 22:52:29 +02:00
var SwaggerInfo = swaggerInfo{
Version: {{ printf "%q" .Version}},
Host: {{ printf "%q" .Host}},
BasePath: {{ printf "%q" .BasePath}},
Schemes: []string{ {{ range $index, $schema := .Schemes}}{{if gt $index 0}},{{end}}{{printf "%q" $schema}}{{end}} },
Title: {{ printf "%q" .Title}},
Description: {{ printf "%q" .Description}},
}
type s struct{}
func (s *s) ReadDoc() string {
2019-10-16 22:52:29 +02:00
sInfo := SwaggerInfo
sInfo.Description = strings.Replace(sInfo.Description, "\n", "\\n", -1)
t, err := template.New("swagger_info").Funcs(template.FuncMap{
"marshal": func(v interface{}) string {
a, _ := json.Marshal(v)
return string(a)
},
}).Parse(doc)
if err != nil {
return doc
}
var tpl bytes.Buffer
2019-10-16 22:52:29 +02:00
if err := t.Execute(&tpl, sInfo); err != nil {
return doc
}
return tpl.String()
}
func init() {
swag.Register(swag.Name, &s{})
}
2019-10-16 22:52:29 +02:00
`