Factor code template into a file.
This allows code regeneration without rebuilding the generator binary.
This commit is contained in:
@ -1,175 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"html/template"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
var templateFuncs = template.FuncMap{
|
||||
"base": filepath.Base,
|
||||
}
|
||||
|
||||
var packageTmpl = template.Must(template.New("package").Funcs(templateFuncs).Parse(`{{$name := .Metadata.Name}}
|
||||
// Client for UPnP Device Control Protocol {{.Metadata.OfficialName}}.
|
||||
// {{if .DocURLs}}
|
||||
// This DCP is documented in detail at: {{range .DocURLs}}
|
||||
// - {{.}}{{end}}{{end}}
|
||||
//
|
||||
// Typically, use one of the New* functions to create clients for services.
|
||||
package {{$name | base}}
|
||||
|
||||
// ***********************************************************
|
||||
// GENERATED FILE - DO NOT EDIT BY HAND. See README.md
|
||||
// ***********************************************************
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/huin/goupnp"
|
||||
"github.com/huin/goupnp/soap"
|
||||
)
|
||||
|
||||
// Hack to avoid Go complaining if time isn't used.
|
||||
var _ time.Time
|
||||
|
||||
// Device URNs:
|
||||
const ({{range .OrderedDeviceTypes}}
|
||||
{{.Const}} = "{{.URN}}"{{end}}
|
||||
)
|
||||
|
||||
// Service URNs:
|
||||
const ({{range .OrderedServiceTypes}}
|
||||
{{.Const}} = "{{.URN}}"{{end}}
|
||||
)
|
||||
|
||||
{{range .OrderedServices}}
|
||||
{{$srv := .}}
|
||||
{{$srvIdent := printf "%s%s" .Name .Version}}
|
||||
|
||||
// {{$srvIdent}} is a client for UPnP SOAP service with URN "{{.URN}}". See
|
||||
// goupnp.ServiceClient, which contains RootDevice and Service attributes which
|
||||
// are provided for informational value.
|
||||
type {{$srvIdent}} struct {
|
||||
goupnp.ServiceClient
|
||||
}
|
||||
|
||||
// New{{$srvIdent}}Clients discovers instances of the service on the network,
|
||||
// and returns clients to any that are found. errors will contain an error for
|
||||
// any devices that replied but which could not be queried, and err will be set
|
||||
// if the discovery process failed outright.
|
||||
//
|
||||
// This is a typical entry calling point into this package.
|
||||
func New{{$srvIdent}}Clients() (clients []*{{$srvIdent}}, errors []error, err error) {
|
||||
var genericClients []goupnp.ServiceClient
|
||||
if genericClients, errors, err = goupnp.NewServiceClients({{$srv.Const}}); err != nil {
|
||||
return
|
||||
}
|
||||
clients = new{{$srvIdent}}ClientsFromGenericClients(genericClients)
|
||||
return
|
||||
}
|
||||
|
||||
// New{{$srvIdent}}ClientsByURL discovers instances of the service at the given
|
||||
// URL, and returns clients to any that are found. An error is returned if
|
||||
// there was an error probing the service.
|
||||
//
|
||||
// This is a typical entry calling point into this package when reusing an
|
||||
// previously discovered service URL.
|
||||
func New{{$srvIdent}}ClientsByURL(loc *url.URL) ([]*{{$srvIdent}}, error) {
|
||||
genericClients, err := goupnp.NewServiceClientsByURL(loc, {{$srv.Const}})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return new{{$srvIdent}}ClientsFromGenericClients(genericClients), nil
|
||||
}
|
||||
|
||||
// New{{$srvIdent}}ClientsFromRootDevice discovers instances of the service in
|
||||
// a given root device, and returns clients to any that are found. An error is
|
||||
// returned if there was not at least one instance of the service within the
|
||||
// device. The location parameter is simply assigned to the Location attribute
|
||||
// of the wrapped ServiceClient(s).
|
||||
//
|
||||
// This is a typical entry calling point into this package when reusing an
|
||||
// previously discovered root device.
|
||||
func New{{$srvIdent}}ClientsFromRootDevice(rootDevice *goupnp.RootDevice, loc *url.URL) ([]*{{$srvIdent}}, error) {
|
||||
genericClients, err := goupnp.NewServiceClientsFromRootDevice(rootDevice, loc, {{$srv.Const}})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return new{{$srvIdent}}ClientsFromGenericClients(genericClients), nil
|
||||
}
|
||||
|
||||
func new{{$srvIdent}}ClientsFromGenericClients(genericClients []goupnp.ServiceClient) []*{{$srvIdent}} {
|
||||
clients := make([]*{{$srvIdent}}, len(genericClients))
|
||||
for i := range genericClients {
|
||||
clients[i] = &{{$srvIdent}}{genericClients[i]}
|
||||
}
|
||||
return clients
|
||||
}
|
||||
|
||||
{{range .SCPD.OrderedActions}}{{/* loops over *SCPDWithURN values */}}
|
||||
|
||||
{{$winargs := $srv.WrapArguments .InputArguments}}
|
||||
{{$woutargs := $srv.WrapArguments .OutputArguments}}
|
||||
{{if $winargs.HasDoc}}
|
||||
//
|
||||
// Arguments:{{range $winargs}}{{if .HasDoc}}
|
||||
//
|
||||
// * {{.Name}}: {{.Document}}{{end}}{{end}}{{end}}
|
||||
{{if $woutargs.HasDoc}}
|
||||
//
|
||||
// Return values:{{range $woutargs}}{{if .HasDoc}}
|
||||
//
|
||||
// * {{.Name}}: {{.Document}}{{end}}{{end}}{{end}}
|
||||
func (client *{{$srvIdent}}) {{.Name}}Ctx(
|
||||
ctx context.Context,
|
||||
{{range $winargs }} {{.AsParameter}},
|
||||
{{end -}}
|
||||
) ({{range $woutargs -}}
|
||||
{{.AsParameter}}, {{end}} err error) {
|
||||
// Request structure.
|
||||
request := {{if $winargs}}&{{template "argstruct" $winargs}}{{"{}"}}{{else}}{{"interface{}(nil)"}}{{end}}
|
||||
// BEGIN Marshal arguments into request.
|
||||
{{range $winargs}}
|
||||
if request.{{.Name}}, err = {{.Marshal}}; err != nil {
|
||||
return
|
||||
}{{end}}
|
||||
// END Marshal arguments into request.
|
||||
|
||||
// Response structure.
|
||||
response := {{if $woutargs}}&{{template "argstruct" $woutargs}}{{"{}"}}{{else}}{{"interface{}(nil)"}}{{end}}
|
||||
|
||||
// Perform the SOAP call.
|
||||
if err = client.SOAPClient.PerformActionCtx(ctx, {{$srv.URNParts.Const}}, "{{.Name}}", request, response); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// BEGIN Unmarshal arguments from response.
|
||||
{{range $woutargs}}
|
||||
if {{.Name}}, err = {{.Unmarshal "response"}}; err != nil {
|
||||
return
|
||||
}{{end}}
|
||||
// END Unmarshal arguments from response.
|
||||
return
|
||||
}
|
||||
|
||||
// {{.Name}} is the legacy version of {{.Name}}Ctx, but uses
|
||||
// context.Background() as the context.
|
||||
func (client *{{$srvIdent}}) {{.Name}}({{range $winargs -}}
|
||||
{{.AsParameter}}, {{end -}}
|
||||
) ({{range $woutargs -}}
|
||||
{{.AsParameter}}, {{end}} err error) {
|
||||
return client.{{.Name}}Ctx(context.Background(),
|
||||
{{range $winargs }}{{.Name}},
|
||||
{{end}}
|
||||
)
|
||||
}
|
||||
|
||||
{{end}}
|
||||
{{end}}
|
||||
|
||||
{{define "argstruct"}}struct {{"{"}}
|
||||
{{range .}}{{.Name}} string
|
||||
{{end}}{{"}"}}{{end}}
|
||||
`))
|
@ -7,10 +7,10 @@ import (
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"github.com/huin/goupnp"
|
||||
"github.com/huin/goupnp/scpd"
|
||||
"github.com/huin/goutil/codegen"
|
||||
)
|
||||
|
||||
// DCP collects together information about a UPnP Device Control Protocol.
|
||||
@ -86,20 +86,13 @@ func (dcp *DCP) processDeviceFile(file *zip.File) error {
|
||||
return mainErr
|
||||
}
|
||||
|
||||
func (dcp *DCP) writeCode(outFile string, useGofmt bool) error {
|
||||
func (dcp *DCP) writeCode(outFile string, codeTmpl *template.Template) error {
|
||||
packageFile, err := os.Create(outFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var output io.WriteCloser = packageFile
|
||||
if useGofmt {
|
||||
if output, err = codegen.NewGofmtWriteCloser(output); err != nil {
|
||||
packageFile.Close()
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err = packageTmpl.Execute(output, dcp); err != nil {
|
||||
if err = codeTmpl.Execute(output, dcp); err != nil {
|
||||
output.Close()
|
||||
return err
|
||||
}
|
||||
|
@ -6,7 +6,9 @@ import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -22,15 +24,23 @@ func main() {
|
||||
useGofmt = flag.Bool("gofmt", true, "Pass the generated code through gofmt. "+
|
||||
"Disable this if debugging code generation and needing to see the generated code "+
|
||||
"prior to being passed through gofmt.")
|
||||
codeTmplFile = flag.String("code_tmpl_file", "", "Path to Go template to generate code from.")
|
||||
)
|
||||
flag.Parse()
|
||||
|
||||
if err := run(*dcpName, *specsDir, *useGofmt); err != nil {
|
||||
if err := run(*dcpName, *specsDir, *useGofmt, *codeTmplFile); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func run(dcpName, specsDir string, useGofmt bool) error {
|
||||
func run(dcpName, specsDir string, useGofmt bool, codeTmplFile string) error {
|
||||
codeTmpl, err := template.New(filepath.Base(codeTmplFile)).Funcs(template.FuncMap{
|
||||
"base": filepath.Base,
|
||||
}).ParseFiles(codeTmplFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error parsing template from file: %w", err)
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(specsDir, os.ModePerm); err != nil {
|
||||
return fmt.Errorf("could not create specs-dir %q: %v", specsDir, err)
|
||||
}
|
||||
@ -47,12 +57,22 @@ func run(dcpName, specsDir string, useGofmt bool) error {
|
||||
return fmt.Errorf("error processing spec %s: %v", metadata.Name, err)
|
||||
}
|
||||
|
||||
if err := dcp.writeCode(filepath.Base(metadata.Name)+".go", useGofmt); err != nil {
|
||||
filename := filepath.Base(metadata.Name) + ".go"
|
||||
if err := dcp.writeCode(filename, codeTmpl); err != nil {
|
||||
return fmt.Errorf("error writing package %q: %v", dcp.Metadata.Name, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
if !useGofmt {
|
||||
return nil
|
||||
}
|
||||
|
||||
return gofmt(filename)
|
||||
}
|
||||
|
||||
return fmt.Errorf("could not find DCP with name %q", dcpName)
|
||||
}
|
||||
|
||||
func gofmt(filename string) error {
|
||||
cmd := exec.Command("gofmt", "-w", filename)
|
||||
return cmd.Run()
|
||||
}
|
||||
|
Reference in New Issue
Block a user