lang: funcs: Autogenerated a lot of new functions
Signed-off-by: Julien Pivotto <roidelapluie@inuits.eu>
This commit is contained in:
committed by
James Shubin
parent
9b4d11f220
commit
1685ee1ecb
@@ -18,13 +18,39 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/iancoleman/strcase"
|
||||
yaml "gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
var (
|
||||
validSignature = regexp.MustCompile(`^func (?P<name>[A-Z][a-zA-Z0-9]+)\((?P<args>([a-zA-Z]+( (string|bool|float64|int64|int))?(, )?){0,})\) (?P<return>(string|float64|int64|bool|int)|\((string|float64|int64|bool|int), error\))$`)
|
||||
errExcluded = errors.New("function is excluded")
|
||||
)
|
||||
|
||||
type golangPackages []*golangPackage
|
||||
|
||||
type golangPackage struct {
|
||||
// Name is the name of the go package.
|
||||
Name string `yaml:"name"`
|
||||
// Alias is the alias of the package when imported in golang.
|
||||
// e.g. import rand "os.rand"
|
||||
Alias string `yaml:"alias,omitempty"`
|
||||
// MgmtAlias is the name of the package inside mcl.
|
||||
MgmtAlias string `yaml:"mgmtAlias,omitempty"`
|
||||
// Exclude is a list of golang function names that we do not want.
|
||||
Exclude []string `yaml:"exclude,omitempty"`
|
||||
}
|
||||
|
||||
func parsePkg(path, filename, templates string) error {
|
||||
var c config
|
||||
filePath := filepath.Join(path, filename)
|
||||
@@ -37,9 +63,173 @@ func parsePkg(path, filename, templates string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = parseFuncs(c, path, templates)
|
||||
functions, err := parsePackages(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = parseFuncs(c, functions, path, templates)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func parsePackages(c config) (functions, error) {
|
||||
var funcs []function
|
||||
for _, golangPackage := range c.Packages {
|
||||
fn, err := golangPackage.parsefuncs()
|
||||
if err != nil {
|
||||
return funcs, err
|
||||
}
|
||||
funcs = append(funcs, fn...)
|
||||
}
|
||||
return funcs, nil
|
||||
}
|
||||
|
||||
func (obj *golangPackage) parsefuncs() (functions, error) {
|
||||
var funcs []function
|
||||
cmd := exec.Command("go", "doc", obj.Name)
|
||||
var out bytes.Buffer
|
||||
cmd.Stdout = &out
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
return funcs, err
|
||||
}
|
||||
return obj.extractFuncs(out.String(), true)
|
||||
}
|
||||
|
||||
func (obj *golangPackage) extractFuncs(doc string, getHelp bool) (functions, error) {
|
||||
var funcs []function
|
||||
for _, line := range strings.Split(doc, "\n") {
|
||||
if validSignature.MatchString(line) {
|
||||
f, err := obj.parseFunctionLine(line, getHelp)
|
||||
if err != nil && err != errExcluded {
|
||||
return funcs, err
|
||||
}
|
||||
if f != nil {
|
||||
funcs = append(funcs, *f)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return funcs, nil
|
||||
}
|
||||
|
||||
func (obj *golangPackage) parseFunctionLine(line string, getHelp bool) (*function, error) {
|
||||
match := validSignature.FindStringSubmatch(line)
|
||||
result := make(map[string]string)
|
||||
for i, name := range validSignature.SubexpNames() {
|
||||
if i != 0 && name != "" {
|
||||
result[name] = match[i]
|
||||
}
|
||||
}
|
||||
|
||||
name := result["name"]
|
||||
|
||||
for _, e := range obj.Exclude {
|
||||
if e == name {
|
||||
return nil, errExcluded
|
||||
}
|
||||
}
|
||||
|
||||
errorFul, err := regexp.MatchString(`, error\)$`, result["return"])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
returns := parseReturn(result["return"])
|
||||
if len(returns) == 0 {
|
||||
return nil, errExcluded
|
||||
}
|
||||
|
||||
mgmtpackage := obj.Name
|
||||
if obj.MgmtAlias != "" {
|
||||
mgmtpackage = obj.MgmtAlias
|
||||
}
|
||||
mgmtpackage = fmt.Sprintf("golang/%s", mgmtpackage)
|
||||
|
||||
internalName := fmt.Sprintf("%s%s", strcase.ToCamel(strings.Replace(obj.Name, "/", "", -1)), name)
|
||||
internalName = strings.Replace(internalName, "Html", "HTML", -1)
|
||||
var help string
|
||||
if getHelp {
|
||||
help, err = obj.getHelp(name, internalName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return &function{
|
||||
MgmtPackage: mgmtpackage,
|
||||
MclName: strcase.ToSnake(name),
|
||||
InternalName: internalName,
|
||||
Help: help,
|
||||
GolangPackage: obj,
|
||||
GolangFunc: name,
|
||||
Errorful: errorFul,
|
||||
Args: parseArgs(result["args"]),
|
||||
Return: returns,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func reverseArgs(s []arg) {
|
||||
last := len(s) - 1
|
||||
for i := 0; i < len(s)/2; i++ {
|
||||
s[i], s[last-i] = s[last-i], s[i]
|
||||
}
|
||||
}
|
||||
func reverse(s []string) {
|
||||
last := len(s) - 1
|
||||
for i := 0; i < len(s)/2; i++ {
|
||||
s[i], s[last-i] = s[last-i], s[i]
|
||||
}
|
||||
}
|
||||
|
||||
func parseArgs(str string) []arg {
|
||||
var args []arg
|
||||
s := strings.Split(str, ",")
|
||||
reverse(s)
|
||||
var currentType string
|
||||
for _, currentArg := range s {
|
||||
if currentArg == "" {
|
||||
continue
|
||||
}
|
||||
v := strings.Split(strings.TrimSpace(currentArg), " ")
|
||||
if len(v) == 2 {
|
||||
currentType = v[1]
|
||||
}
|
||||
args = append(args, arg{Name: v[0], Type: currentType})
|
||||
}
|
||||
reverseArgs(args)
|
||||
return args
|
||||
}
|
||||
|
||||
func parseReturn(str string) []arg {
|
||||
var returns []arg
|
||||
re := regexp.MustCompile(`(int64|float64|string|bool|int)`)
|
||||
t := string(re.Find([]byte(str)))
|
||||
returns = append(returns, arg{Type: t})
|
||||
return returns
|
||||
}
|
||||
|
||||
func (obj *golangPackage) getHelp(function, internalName string) (string, error) {
|
||||
cmd := exec.Command("go", "doc", fmt.Sprintf("%s.%s", obj.Name, function))
|
||||
var out bytes.Buffer
|
||||
cmd.Stdout = &out
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
var doc string
|
||||
for i, line := range strings.Split(strings.TrimSpace(out.String()), "\n") {
|
||||
if i > 0 {
|
||||
s := strings.TrimSpace(line)
|
||||
if i == 1 {
|
||||
docs := strings.Split(s, " ")
|
||||
docs[0] = internalName
|
||||
s = strings.Join(docs, " ")
|
||||
}
|
||||
doc = fmt.Sprintf("%s// %s is an autogenerated function.\n", doc, s)
|
||||
}
|
||||
}
|
||||
return doc, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user