Initial version
Extracted from paultyng/terraform-provider-unifi@ef25893f14
This commit is contained in:
377
fields/main.go
Normal file
377
fields/main.go
Normal file
@@ -0,0 +1,377 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/iancoleman/strcase"
|
||||
)
|
||||
|
||||
type replacement struct {
|
||||
Old string
|
||||
New string
|
||||
}
|
||||
|
||||
var fieldReps = []replacement{
|
||||
{"Ipv6", "IPV6"},
|
||||
{"Pd", "PD"},
|
||||
{"Leasetime", "LeaseTime"},
|
||||
{"Networkgroup", "NetworkGroup"},
|
||||
{"Openvpn", "OpenVPN"},
|
||||
{"Nat", "NAT"},
|
||||
{"Wlangroup", "WLANGroup"},
|
||||
{"Dns", "DNS"},
|
||||
{"Tftp", "TFTP"},
|
||||
{"Dhcpdv6", "DHCPDV6"},
|
||||
{"Dhcpd", "DHCPD"},
|
||||
{"Dhcp", "DHCP"},
|
||||
{"Wlan", "WLAN"},
|
||||
{"Idx", "IDX"},
|
||||
{"Id", "ID"},
|
||||
{"Mac", "MAC"},
|
||||
{"Vlan", "VLAN"},
|
||||
{"Wep", "WEP"},
|
||||
{"Dtim", "DTIM"},
|
||||
{"Wpa", "WPA"},
|
||||
{"Usergroup", "UserGroup"},
|
||||
{"Mcastenhance", "MulticastEnhance"},
|
||||
{"Ssid", "SSID"},
|
||||
{"Dpi", "DPI"},
|
||||
{"Bc", "Broadcast"},
|
||||
{"Radius", "RADIUS"},
|
||||
{"Fixedip", "FixedIP"},
|
||||
{"Ipsec", "IPSec"},
|
||||
{"Ip", "IP"},
|
||||
{"Pmf", "PMF"},
|
||||
{"Minrssi", "MinRSSI"},
|
||||
{"Qos", "QOS"},
|
||||
{"Wan", "WAN"},
|
||||
{"Vpn", "VPN"},
|
||||
{"Igmp", "IGMP"},
|
||||
{"Tcp", "TCP"},
|
||||
{"Udp", "UDP"},
|
||||
}
|
||||
|
||||
var fileReps = []replacement{
|
||||
{"WlanConf", "WLAN"},
|
||||
{"Dhcp", "DHCP"},
|
||||
{"Wlan", "WLAN"},
|
||||
{"NetworkConf", "Network"},
|
||||
}
|
||||
|
||||
func cleanName(name string, reps []replacement) string {
|
||||
for _, rep := range reps {
|
||||
name = strings.ReplaceAll(name, rep.Old, rep.New)
|
||||
}
|
||||
|
||||
return name
|
||||
}
|
||||
|
||||
func main() {
|
||||
version := os.Args[1]
|
||||
out := os.Args[2]
|
||||
wd, err := os.Getwd()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
fieldsDir := filepath.Join(wd, version)
|
||||
outDir := filepath.Join(wd, out)
|
||||
|
||||
fieldsFiles, err := ioutil.ReadDir(fieldsDir)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
for _, fieldsFile := range fieldsFiles {
|
||||
name := fieldsFile.Name()
|
||||
|
||||
// if name != "WlanConf.json" {
|
||||
// continue
|
||||
// }
|
||||
|
||||
ext := filepath.Ext(name)
|
||||
|
||||
if filepath.Ext(name) != ".json" {
|
||||
continue
|
||||
}
|
||||
|
||||
if name == "Setting.json" {
|
||||
continue
|
||||
}
|
||||
|
||||
name = name[:len(name)-len(ext)]
|
||||
|
||||
urlPath := strings.ToLower(name)
|
||||
structName := cleanName(name, fileReps)
|
||||
|
||||
goFile := strcase.ToSnake(structName) + ".generated.go"
|
||||
code, err := generateCode(filepath.Join(fieldsDir, fieldsFile.Name()), structName, urlPath)
|
||||
if err != nil {
|
||||
fmt.Printf("skipping file %s: %s", fieldsFile.Name(), err)
|
||||
continue
|
||||
// panic(err)
|
||||
}
|
||||
|
||||
_ = os.Remove(filepath.Join(outDir, goFile))
|
||||
ioutil.WriteFile(filepath.Join(outDir, goFile), ([]byte)(code), 0644)
|
||||
}
|
||||
|
||||
fmt.Printf("%s\n", outDir)
|
||||
}
|
||||
|
||||
func generateCode(fieldsFile string, structName string, urlPath string) (string, error) {
|
||||
b, err := ioutil.ReadFile(fieldsFile)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
var fields map[string]interface{}
|
||||
err = json.Unmarshal(b, &fields)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
code := fmt.Sprintf(`// Code generated from ace.jar fields *.json files
|
||||
// DO NOT EDIT.
|
||||
|
||||
package unifi
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// just to fix compile issues with the import
|
||||
var _ fmt.Formatter
|
||||
|
||||
type %s struct {
|
||||
ID string `+"`json:\"_id,omitempty\"`"+`
|
||||
SiteID string `+"`json:\"site_id,omitempty\"`"+`
|
||||
|
||||
Hidden bool `+"`json:\"attr_hidden,omitempty\"`"+`
|
||||
HiddenID string `+"`json:\"attr_hidden_id,omitempty\"`"+`
|
||||
NoDelete bool `+"`json:\"attr_no_delete,omitempty\"`"+`
|
||||
NoEdit bool `+"`json:\"attr_no_edit,omitempty\"`"+`
|
||||
|
||||
`, structName)
|
||||
|
||||
fieldNames := []string{}
|
||||
for name := range fields {
|
||||
fieldNames = append(fieldNames, name)
|
||||
}
|
||||
|
||||
// TODO: sort by normalized name, not this name
|
||||
sort.Strings(fieldNames)
|
||||
|
||||
for _, name := range fieldNames {
|
||||
switch {
|
||||
case structName == "User" && name == "blocked":
|
||||
code += "\tBlocked bool `json:\"blocked,omitempty\"`\n"
|
||||
continue
|
||||
case structName == "User" && name == "last_seen":
|
||||
code += "\tLastSeen int `json:\"last_seen,omitempty\"`\n"
|
||||
continue
|
||||
case structName == "SettingUsg" && strings.HasSuffix(name, "_timeout"):
|
||||
field := strcase.ToCamel(name)
|
||||
field = cleanName(field, fieldReps)
|
||||
code += fmt.Sprintf("\t%s int `json:\"%s,omitempty\"`\n", field, name)
|
||||
continue
|
||||
}
|
||||
|
||||
validation := fields[name]
|
||||
fieldCode, err := generateField(name, validation)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
code += fieldCode + "\n"
|
||||
}
|
||||
|
||||
code = code + "}\n"
|
||||
|
||||
if strings.HasPrefix(structName, "Setting") {
|
||||
return code, nil
|
||||
}
|
||||
|
||||
code = code + fmt.Sprintf(`
|
||||
func (c *Client) list%[1]s(site string) ([]%[1]s, error) {
|
||||
var respBody struct {
|
||||
Meta meta `+"`"+`json:"meta"`+"`"+`
|
||||
Data []%[1]s `+"`"+`json:"data"`+"`"+`
|
||||
}
|
||||
|
||||
err := c.do("GET", fmt.Sprintf("s/%%s/rest/%[2]s", site), nil, &respBody)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return respBody.Data, nil
|
||||
}
|
||||
|
||||
func (c *Client) get%[1]s(site, id string) (*%[1]s, error) {
|
||||
var respBody struct {
|
||||
Meta meta `+"`"+`json:"meta"`+"`"+`
|
||||
Data []%[1]s `+"`"+`json:"data"`+"`"+`
|
||||
}
|
||||
|
||||
err := c.do("GET", fmt.Sprintf("s/%%s/rest/%[2]s/%%s", site, id), nil, &respBody)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(respBody.Data) != 1 {
|
||||
return nil, &NotFoundError{}
|
||||
}
|
||||
|
||||
d := respBody.Data[0]
|
||||
return &d, nil
|
||||
}
|
||||
|
||||
func (c *Client) delete%[1]s(site, id string) error {
|
||||
err := c.do("DELETE", fmt.Sprintf("s/%%s/rest/%[2]s/%%s", site, id), struct{}{}, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) create%[1]s(site string, d *%[1]s) (*%[1]s, error) {
|
||||
var respBody struct {
|
||||
Meta meta `+"`"+`json:"meta"`+"`"+`
|
||||
Data []%[1]s `+"`"+`json:"data"`+"`"+`
|
||||
}
|
||||
|
||||
err := c.do("POST", fmt.Sprintf("s/%%s/rest/%[2]s", site), d, &respBody)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(respBody.Data) != 1 {
|
||||
return nil, &NotFoundError{}
|
||||
}
|
||||
|
||||
new := respBody.Data[0]
|
||||
|
||||
return &new, nil
|
||||
}
|
||||
|
||||
func (c *Client) update%[1]s(site string, d *%[1]s) (*%[1]s, error) {
|
||||
var respBody struct {
|
||||
Meta meta `+"`"+`json:"meta"`+"`"+`
|
||||
Data []%[1]s `+"`"+`json:"data"`+"`"+`
|
||||
}
|
||||
|
||||
err := c.do("PUT", fmt.Sprintf("s/%%s/rest/%[2]s/%%s", site, d.ID), d, &respBody)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(respBody.Data) != 1 {
|
||||
return nil, &NotFoundError{}
|
||||
}
|
||||
|
||||
new := respBody.Data[0]
|
||||
|
||||
return &new, nil
|
||||
}
|
||||
`, structName, urlPath)
|
||||
|
||||
return code, nil
|
||||
}
|
||||
|
||||
func normalizeValidation(re string) string {
|
||||
re = strings.ReplaceAll(re, "\\d", "[0-9]")
|
||||
re = strings.ReplaceAll(re, "[-+]?", "")
|
||||
re = strings.ReplaceAll(re, "[+-]?", "")
|
||||
re = strings.ReplaceAll(re, "[-]?", "")
|
||||
re = strings.ReplaceAll(re, "\\.", ".")
|
||||
re = strings.ReplaceAll(re, "[.]?", ".")
|
||||
|
||||
quants := regexp.MustCompile(`\{\d*,?\d*\}|\*|\+|\?`)
|
||||
re = quants.ReplaceAllString(re, "")
|
||||
|
||||
control := regexp.MustCompile(`[\(\[\]\)\|\-\$\^]`)
|
||||
re = control.ReplaceAllString(re, "")
|
||||
|
||||
re = strings.TrimPrefix(re, "^")
|
||||
re = strings.TrimSuffix(re, "$")
|
||||
|
||||
return re
|
||||
}
|
||||
|
||||
func typeFromValidation(validation interface{}) (string, string, bool, error) {
|
||||
switch validation := validation.(type) {
|
||||
case []interface{}:
|
||||
if len(validation) == 0 {
|
||||
return "[]string", "", false, nil
|
||||
}
|
||||
if len(validation) > 1 {
|
||||
return "", "", false, fmt.Errorf("unknown validation %#v", validation)
|
||||
}
|
||||
elementType, elementComment, _, err := typeFromValidation(validation[0])
|
||||
if err != nil {
|
||||
return "", "", false, err
|
||||
}
|
||||
return fmt.Sprintf("[]%s", elementType), elementComment, true, nil
|
||||
case string:
|
||||
comment := validation
|
||||
normalized := normalizeValidation(validation)
|
||||
allowEmpty := strings.HasSuffix(validation, "|^$") || strings.HasPrefix(validation, "^$|")
|
||||
switch {
|
||||
case normalized == "falsetrue" || normalized == "truefalse":
|
||||
return "bool", "", false, nil
|
||||
default:
|
||||
if _, err := strconv.ParseFloat(normalized, 64); err == nil {
|
||||
if normalized == "09" || normalized == "09.09" {
|
||||
comment = ""
|
||||
}
|
||||
|
||||
if strings.Contains(normalized, ".") {
|
||||
if strings.Contains(validation, "\\.){3}") {
|
||||
break
|
||||
}
|
||||
|
||||
return "float64", comment, true, nil
|
||||
}
|
||||
|
||||
return "int", comment, true, nil
|
||||
}
|
||||
}
|
||||
if validation != "" && normalized != "" {
|
||||
fmt.Printf("normalize %q to %q\n", validation, normalized)
|
||||
}
|
||||
return "string", validation, !allowEmpty, nil
|
||||
}
|
||||
return "", "", false, fmt.Errorf("unable to determine type from validation %q", validation)
|
||||
}
|
||||
|
||||
func generateField(name string, validation interface{}) (string, error) {
|
||||
field := strcase.ToCamel(name)
|
||||
field = cleanName(field, fieldReps)
|
||||
fieldType, comment, omitempty, err := typeFromValidation(validation)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
comment = strings.TrimSpace(fmt.Sprintf("// %s", comment))
|
||||
if comment == "//" {
|
||||
comment = ""
|
||||
}
|
||||
|
||||
if fieldType == "string" && strings.HasSuffix(field, "ID") {
|
||||
omitempty = false
|
||||
}
|
||||
|
||||
omitemptyCode := ""
|
||||
if omitempty {
|
||||
omitemptyCode = ",omitempty"
|
||||
}
|
||||
|
||||
return fmt.Sprintf("\t%s %s `json:\"%s%s\"` %s", field, fieldType, name, omitemptyCode, comment), nil
|
||||
}
|
||||
Reference in New Issue
Block a user