Files
go-unifi/codegen/generator.go
Mateusz Filipowicz 6016a3d34a feat: add code generation for Unifi client interface (#11)
* feat: add code generation for Unifi client interface

* chore: apply linter hints

* chore: add tests

* fix: nondeterministic client function signature due to iteration of map params

* chore: add move version tests

* chore: add more generator tests

* chore: lint
2025-02-11 16:28:29 +01:00

84 lines
2.2 KiB
Go

package main
import (
"bytes"
_ "embed"
"fmt"
"go/format"
"io"
"os"
"path/filepath"
"text/template"
"github.com/iancoleman/strcase"
log "github.com/sirupsen/logrus"
)
// Generatable is the interface for generation sources.
type Generatable interface {
Name() string
GenerateCode() (string, error)
}
// generateCodeFromTemplate renders a template with provided content and formats the source.
func generateCodeFromTemplate(templateName, templateContent string, toWrite any) (string, error) {
var err error
var buf bytes.Buffer
writer := io.Writer(&buf)
tpl := template.Must(template.New(templateName).Parse(templateContent))
err = tpl.Execute(writer, toWrite)
if err != nil {
return "", fmt.Errorf("failed to render template: %w", err)
}
src, err := format.Source(buf.Bytes())
if err != nil {
return "", fmt.Errorf("failed to format source: %w", err)
}
return string(src), err
}
// generateCode generates code for each generation source and writes it to file.
func generateCode(fieldsDir string, outDir string) error {
generators := make([]Generatable, 0)
resources, err := buildResourcesFromDownloadedFields(fieldsDir)
if err != nil {
return fmt.Errorf("failed to build resources from downloaded fields: %w", err)
}
client := newClientInfo(resources)
for _, resource := range resources {
generators = append(generators, resource)
}
generators = append(generators, client)
for _, g := range generators {
var code string
if code, err = g.GenerateCode(); err != nil {
log.Errorf("failed to generate code for %s: %s", g.Name(), err)
continue
}
filename, err := writeGeneratedFile(outDir, g.Name(), code)
if err != nil {
log.Errorf("failed to write file %s: %s", g.Name(), err)
continue
}
log.Debugf("Generated %s with resource %s\n\n", filename, g.Name())
}
return nil
}
// writeGeneratedFile writes generated file content to a file.
func writeGeneratedFile(outDir string, name string, content string) (string, error) {
goFile := strcase.ToSnake(name) + ".generated.go"
goFilePath := filepath.Join(outDir, goFile)
_ = os.Remove(goFilePath)
if err := os.WriteFile(goFilePath, []byte(content), 0o644); err != nil {
return goFile, fmt.Errorf("failed to write file %s: %w", goFile, err)
}
return goFile, nil
}