* Update docs on ebs encrypt_boot to clarify that packer will not override global account settings * Update struct-markdown generator and regenerate partials with new website location. This overwrites some linting that got automatically applied when the files got moved
179 lines
4.0 KiB
Go
179 lines
4.0 KiB
Go
package main
|
|
|
|
import (
|
|
"flag"
|
|
"fmt"
|
|
"go/ast"
|
|
"go/parser"
|
|
"go/token"
|
|
"io/ioutil"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/fatih/camelcase"
|
|
"github.com/fatih/structtag"
|
|
)
|
|
|
|
func main() {
|
|
args := flag.Args()
|
|
if len(args) == 0 {
|
|
// Default: process the file
|
|
args = []string{os.Getenv("GOFILE")}
|
|
}
|
|
fname := args[0]
|
|
|
|
absFilePath, err := filepath.Abs(fname)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
projectRoot := os.Getenv("PROJECT_ROOT")
|
|
var paths []string
|
|
if projectRoot == "" {
|
|
// fall back to the packer root.
|
|
paths = strings.SplitAfter(absFilePath, "packer"+string(os.PathSeparator))
|
|
projectRoot = paths[0]
|
|
} else {
|
|
paths = strings.SplitAfter(absFilePath, projectRoot+string(os.PathSeparator))
|
|
}
|
|
builderName, _ := filepath.Split(paths[1])
|
|
builderName = strings.Trim(builderName, string(os.PathSeparator))
|
|
|
|
b, err := ioutil.ReadFile(fname)
|
|
if err != nil {
|
|
fmt.Printf("ReadFile: %+v", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
fset := token.NewFileSet()
|
|
f, err := parser.ParseFile(fset, fname, b, parser.ParseComments)
|
|
if err != nil {
|
|
fmt.Printf("ParseFile: %+v", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
for _, decl := range f.Decls {
|
|
typeDecl, ok := decl.(*ast.GenDecl)
|
|
if !ok {
|
|
continue
|
|
}
|
|
typeSpec, ok := typeDecl.Specs[0].(*ast.TypeSpec)
|
|
if !ok {
|
|
continue
|
|
}
|
|
structDecl, ok := typeSpec.Type.(*ast.StructType)
|
|
if !ok {
|
|
continue
|
|
}
|
|
|
|
fields := structDecl.Fields.List
|
|
sourcePath := filepath.ToSlash(paths[1])
|
|
header := Struct{
|
|
SourcePath: sourcePath,
|
|
Name: typeSpec.Name.Name,
|
|
Filename: typeSpec.Name.Name + ".mdx",
|
|
Header: strings.TrimSpace(typeDecl.Doc.Text()),
|
|
}
|
|
required := Struct{
|
|
SourcePath: sourcePath,
|
|
Name: typeSpec.Name.Name,
|
|
Filename: typeSpec.Name.Name + "-required.mdx",
|
|
}
|
|
notRequired := Struct{
|
|
SourcePath: sourcePath,
|
|
Name: typeSpec.Name.Name,
|
|
Filename: typeSpec.Name.Name + "-not-required.mdx",
|
|
}
|
|
|
|
for _, field := range fields {
|
|
if len(field.Names) == 0 || field.Tag == nil {
|
|
continue
|
|
}
|
|
tag := field.Tag.Value[1:]
|
|
tag = tag[:len(tag)-1]
|
|
tags, err := structtag.Parse(tag)
|
|
if err != nil {
|
|
fmt.Printf("structtag.Parse(%s): err: %v", field.Tag.Value, err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
// Leave undocumented tags out of markdown. This is useful for
|
|
// fields which exist for backwards compatability, or internal-use
|
|
// only fields
|
|
undocumented, _ := tags.Get("undocumented")
|
|
if undocumented != nil {
|
|
if undocumented.Name == "true" {
|
|
continue
|
|
}
|
|
}
|
|
mstr, err := tags.Get("mapstructure")
|
|
if err != nil {
|
|
continue
|
|
}
|
|
name := mstr.Name
|
|
|
|
if name == "" {
|
|
continue
|
|
}
|
|
|
|
var docs string
|
|
if field.Doc != nil {
|
|
docs = field.Doc.Text()
|
|
} else {
|
|
docs = strings.Join(camelcase.Split(field.Names[0].Name), " ")
|
|
}
|
|
|
|
if strings.Contains(docs, "TODO") {
|
|
continue
|
|
}
|
|
fieldType := string(b[field.Type.Pos()-1 : field.Type.End()-1])
|
|
fieldType = strings.ReplaceAll(fieldType, "*", `\*`)
|
|
switch fieldType {
|
|
case "time.Duration":
|
|
fieldType = `duration string | ex: "1h5m2s"`
|
|
case "config.Trilean":
|
|
fieldType = `boolean`
|
|
case "config.NameValues":
|
|
fieldType = `[]{name string, value string}`
|
|
case "config.KeyValues":
|
|
fieldType = `[]{key string, value string}`
|
|
}
|
|
|
|
field := Field{
|
|
Name: name,
|
|
Type: fieldType,
|
|
Docs: docs,
|
|
}
|
|
if req, err := tags.Get("required"); err == nil && req.Value() == "true" {
|
|
required.Fields = append(required.Fields, field)
|
|
} else {
|
|
notRequired.Fields = append(notRequired.Fields, field)
|
|
}
|
|
}
|
|
|
|
dir := filepath.Join(projectRoot, "website", "content", "partials", builderName)
|
|
os.MkdirAll(dir, 0755)
|
|
|
|
for _, str := range []Struct{header, required, notRequired} {
|
|
if len(str.Fields) == 0 && len(str.Header) == 0 {
|
|
continue
|
|
}
|
|
outputPath := filepath.Join(dir, str.Filename)
|
|
|
|
outputFile, err := os.Create(outputPath)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
defer outputFile.Close()
|
|
|
|
err = structDocsTemplate.Execute(outputFile, str)
|
|
if err != nil {
|
|
fmt.Printf("%v", err)
|
|
os.Exit(1)
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|