Skip to content

Commit

Permalink
replace generator code with text/template
Browse files Browse the repository at this point in the history
  • Loading branch information
fujiwara committed May 9, 2024
1 parent 1b8a886 commit 6bb7205
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 55 deletions.
54 changes: 35 additions & 19 deletions cmd/aws-sdk-client-gen-gen/main.go
Original file line number Diff line number Diff line change
@@ -1,47 +1,63 @@
package main

import (
"fmt"
"bytes"
"log"
"os"
"text/template"

"github.com/goccy/go-yaml"
)

const templateStr = `// Code generated by cmd/aws-sdk-client-gen-gen/main.go; DO NOT EDIT.
package main
import (
"reflect"
{{ range $key, $value := .Services }}
"github.com/aws/aws-sdk-go-v2/service/{{ $key }}"
{{- end }}
)
func generateAll() {
{{ range $key, $value := .Services }}
{{- if eq (len $value) 0 }}
gen("{{ $key }}", reflect.TypeOf({{ $key }}.New({{ $key }}.Options{})), nil)
{{- else }}
gen("{{ $key }}", reflect.TypeOf({{ $key }}.New({{ $key }}.Options{})), {{ printf "%#v" $value }})
{{- end }}
{{ end }}
}
`

type GenerateConfig struct {
Services map[string][]string `json:"services"`
}

func main() {
log.Println("generating gen.go")
o, err := os.Create("gen.go")
if err != nil {
log.Fatalf("failed to create gen.go: %v", err)
}

f, err := os.Open("../../gen.yaml")
if err != nil {
log.Fatalf("failed to open gen.yaml: %v", err)
}
defer f.Close()

cfg := GenerateConfig{}
if err := yaml.NewDecoder(f).Decode(&cfg); err != nil {
log.Fatalf("failed to decode gen.yaml: %v", err)
}

fmt.Fprintln(o, "// Code generated by cmd/aws-sdk-client-gen-gen/main.go; DO NOT EDIT.")
fmt.Fprintln(o, "package main")
fmt.Fprintln(o, "import \"reflect\"")
for k := range cfg.Services {
fmt.Fprintf(o, "import \"github.com/aws/aws-sdk-go-v2/service/%s\"\n", k)
tmpl, err := template.New("gen").Parse(templateStr)
if err != nil {
log.Fatalf("failed to parse template: %v", err)
}
buf := &bytes.Buffer{}
if err := tmpl.Execute(buf, cfg); err != nil {
log.Fatalf("failed to execute template: %v", err)
}
fmt.Fprintln(o, "func generateAll() {")
for k, v := range cfg.Services {
if len(v) == 0 {
fmt.Fprintf(o, " gen(\"%s\", reflect.TypeOf(%s.New(%s.Options{})), nil)\n", k, k, k)
} else {
fmt.Fprintf(o, " gen(\"%s\", reflect.TypeOf(%s.New(%s.Options{})), %#v)\n", k, k, k, v)
}

if err := os.WriteFile("gen.go", buf.Bytes(), 0644); err != nil {
log.Fatalf("failed to write gen.go: %v", err)
}
fmt.Fprintln(o, "}")
log.Println("generated gen.go")
}
88 changes: 52 additions & 36 deletions cmd/aws-sdk-client-gen/main.go
Original file line number Diff line number Diff line change
@@ -1,36 +1,57 @@
package main

import (
"bytes"
"fmt"
"log"
"os"
"reflect"
"strings"
"text/template"
)

//go:generate go run ../aws-sdk-client-gen-gen/main.go
//go:generate go get ./...

const templateStr = `// Code generated by cmd/aws-sdk-client-gen/main.go; DO NOT EDIT.
package sdkclient
import (
"context"
"encoding/json"
"fmt"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/{{ .PkgName }}"
)
{{ range .Methods }}
func {{ $.PkgName }}_{{ .Name }}(ctx context.Context, awsCfg aws.Config, b json.RawMessage) (any, error) {
svc := {{ $.PkgName }}.NewFromConfig(awsCfg)
var in {{ .Input }}
if err := json.Unmarshal(b, &in); err != nil {
return nil, fmt.Errorf("failed to unmarshal request: %w", err)
}
return svc.{{ .Name }}(ctx, &in)
}
{{ end }}
func init() {
{{- range .Methods }}
clientMethods["{{ $.PkgName }}#Client.{{ .Name }}"] = {{ $.PkgName }}_{{ .Name }}
{{- end }}
}
`

func main() {
generateAll()
}

func gen(pkgName string, clientType reflect.Type, genNames []string) error {
log.Printf("generating %s_gen.go", pkgName)
buf := &strings.Builder{}
fmt.Fprintln(buf, "// Code generated by cmd/aws-sdk-client-gen/main.go; DO NOT EDIT.")
fmt.Fprintln(buf, "package sdkclient")
fmt.Fprintln(buf)
fmt.Fprintf(buf, `import (
"context"
"encoding/json"
"fmt"

"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/%s"
)
`, pkgName)
var methodNames []string
methods := make([]map[string]string, 0)
for i := 0; i < clientType.NumMethod(); i++ {
method := clientType.Method(i)
if len(genNames) > 0 && !contains(genNames, method.Name) {
Expand All @@ -44,32 +65,27 @@ func gen(pkgName string, clientType reflect.Type, genNames []string) error {
log.Printf("no params func %s", method.Name)
continue
}
methodNames = append(methodNames, method.Name)
log.Printf("generating %s_%s", pkgName, method.Name)
fmt.Fprintf(buf, `func %s_%s(ctx context.Context, awsCfg aws.Config, b json.RawMessage) (any, error) {
svc := %s.NewFromConfig(awsCfg)
var in %s
if err := json.Unmarshal(b, &in); err != nil {
return nil, fmt.Errorf("failed to unmarshal request: %%w", err)
}
return svc.%s(ctx, &in)
}
`,
pkgName,
method.Name,
pkgName,
strings.TrimPrefix(params[2], "*"), // (receiver, context.Context, *Request, ...)
method.Name,
)
fmt.Fprintln(buf)
methods = append(methods, map[string]string{
"Name": method.Name,
"Input": strings.TrimPrefix(params[2], "*"),
})
}
fmt.Fprintln(buf, `func init() {`)
for _, name := range methodNames {
fmt.Fprintf(buf, " clientMethods[\"%s#Client.%s\"] = %s_%s\n", pkgName, name, pkgName, name)

tmpl, err := template.New("clientGen").Parse(templateStr)
if err != nil {
return fmt.Errorf("failed to parse template: %w", err)
}

data := map[string]interface{}{
"PkgName": pkgName,
"Methods": methods,
}
fmt.Fprintln(buf, "}")

if err := os.WriteFile(pkgName+"_gen.go", []byte(buf.String()), 0644); err != nil {
buf := &bytes.Buffer{}
if err := tmpl.Execute(buf, data); err != nil {
return fmt.Errorf("failed to execute template: %w", err)
}
if err := os.WriteFile(pkgName+"_gen.go", buf.Bytes(), 0644); err != nil {
return err
}
log.Printf("generated %s_gen.go", pkgName)
Expand Down

0 comments on commit 6bb7205

Please sign in to comment.