mirror of
https://github.com/Luzifer/cloudkeys-go.git
synced 2024-11-14 08:52:44 +00:00
190 lines
5 KiB
Go
190 lines
5 KiB
Go
|
// +build codegen
|
||
|
|
||
|
package api
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"encoding/json"
|
||
|
"fmt"
|
||
|
"os"
|
||
|
"sort"
|
||
|
"strings"
|
||
|
"text/template"
|
||
|
)
|
||
|
|
||
|
// WaiterAcceptor is the acceptors defined in the model the SDK will use
|
||
|
// to wait on resource states with.
|
||
|
type WaiterAcceptor struct {
|
||
|
State string
|
||
|
Matcher string
|
||
|
Argument string
|
||
|
Expected interface{}
|
||
|
}
|
||
|
|
||
|
// ExpectedString returns the string that was expected by the WaiterAcceptor
|
||
|
func (a *WaiterAcceptor) ExpectedString() string {
|
||
|
switch a.Expected.(type) {
|
||
|
case string:
|
||
|
return fmt.Sprintf("%q", a.Expected)
|
||
|
default:
|
||
|
return fmt.Sprintf("%v", a.Expected)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// A Waiter is an individual waiter definition.
|
||
|
type Waiter struct {
|
||
|
Name string
|
||
|
Delay int
|
||
|
MaxAttempts int
|
||
|
OperationName string `json:"operation"`
|
||
|
Operation *Operation
|
||
|
Acceptors []WaiterAcceptor
|
||
|
}
|
||
|
|
||
|
// WaitersGoCode generates and returns Go code for each of the waiters of
|
||
|
// this API.
|
||
|
func (a *API) WaitersGoCode() string {
|
||
|
var buf bytes.Buffer
|
||
|
fmt.Fprintf(&buf, "import (\n%q\n\n%q\n%q\n)",
|
||
|
"time",
|
||
|
"github.com/aws/aws-sdk-go/aws",
|
||
|
"github.com/aws/aws-sdk-go/aws/request",
|
||
|
)
|
||
|
|
||
|
for _, w := range a.Waiters {
|
||
|
buf.WriteString(w.GoCode())
|
||
|
}
|
||
|
return buf.String()
|
||
|
}
|
||
|
|
||
|
// used for unmarshaling from the waiter JSON file
|
||
|
type waiterDefinitions struct {
|
||
|
*API
|
||
|
Waiters map[string]Waiter
|
||
|
}
|
||
|
|
||
|
// AttachWaiters reads a file of waiter definitions, and adds those to the API.
|
||
|
// Will panic if an error occurs.
|
||
|
func (a *API) AttachWaiters(filename string) {
|
||
|
p := waiterDefinitions{API: a}
|
||
|
|
||
|
f, err := os.Open(filename)
|
||
|
defer f.Close()
|
||
|
if err != nil {
|
||
|
panic(err)
|
||
|
}
|
||
|
err = json.NewDecoder(f).Decode(&p)
|
||
|
if err != nil {
|
||
|
panic(err)
|
||
|
}
|
||
|
|
||
|
p.setup()
|
||
|
}
|
||
|
|
||
|
func (p *waiterDefinitions) setup() {
|
||
|
p.API.Waiters = []Waiter{}
|
||
|
i, keys := 0, make([]string, len(p.Waiters))
|
||
|
for k := range p.Waiters {
|
||
|
keys[i] = k
|
||
|
i++
|
||
|
}
|
||
|
sort.Strings(keys)
|
||
|
|
||
|
for _, n := range keys {
|
||
|
e := p.Waiters[n]
|
||
|
n = p.ExportableName(n)
|
||
|
e.Name = n
|
||
|
e.OperationName = p.ExportableName(e.OperationName)
|
||
|
e.Operation = p.API.Operations[e.OperationName]
|
||
|
if e.Operation == nil {
|
||
|
panic("unknown operation " + e.OperationName + " for waiter " + n)
|
||
|
}
|
||
|
p.API.Waiters = append(p.API.Waiters, e)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var waiterTmpls = template.Must(template.New("waiterTmpls").Funcs(
|
||
|
template.FuncMap{
|
||
|
"titleCase": func(v string) string {
|
||
|
return strings.Title(v)
|
||
|
},
|
||
|
},
|
||
|
).Parse(`
|
||
|
{{ define "waiter"}}
|
||
|
// WaitUntil{{ .Name }} uses the {{ .Operation.API.NiceName }} API operation
|
||
|
// {{ .OperationName }} to wait for a condition to be met before returning.
|
||
|
// If the condition is not met within the max attempt window, an error will
|
||
|
// be returned.
|
||
|
func (c *{{ .Operation.API.StructName }}) WaitUntil{{ .Name }}(input {{ .Operation.InputRef.GoType }}) error {
|
||
|
return c.WaitUntil{{ .Name }}WithContext(aws.BackgroundContext(), input)
|
||
|
}
|
||
|
|
||
|
// WaitUntil{{ .Name }}WithContext is an extended version of WaitUntil{{ .Name }}.
|
||
|
// With the support for passing in a context and options to configure the
|
||
|
// Waiter and the underlying request options.
|
||
|
//
|
||
|
// The context must be non-nil and will be used for request cancellation. If
|
||
|
// the context is nil a panic will occur. In the future the SDK may create
|
||
|
// sub-contexts for http.Requests. See https://golang.org/pkg/context/
|
||
|
// for more information on using Contexts.
|
||
|
func (c *{{ .Operation.API.StructName }}) WaitUntil{{ .Name }}WithContext(` +
|
||
|
`ctx aws.Context, input {{ .Operation.InputRef.GoType }}, opts ...request.WaiterOption) error {
|
||
|
w := request.Waiter{
|
||
|
Name: "WaitUntil{{ .Name }}",
|
||
|
MaxAttempts: {{ .MaxAttempts }},
|
||
|
Delay: request.ConstantWaiterDelay({{ .Delay }} * time.Second),
|
||
|
Acceptors: []request.WaiterAcceptor{
|
||
|
{{ range $_, $a := .Acceptors }}{
|
||
|
State: request.{{ titleCase .State }}WaiterState,
|
||
|
Matcher: request.{{ titleCase .Matcher }}WaiterMatch,
|
||
|
{{- if .Argument }}Argument: "{{ .Argument }}",{{ end }}
|
||
|
Expected: {{ .ExpectedString }},
|
||
|
},
|
||
|
{{ end }}
|
||
|
},
|
||
|
Logger: c.Config.Logger,
|
||
|
NewRequest: func(opts []request.Option) (*request.Request, error) {
|
||
|
var inCpy {{ .Operation.InputRef.GoType }}
|
||
|
if input != nil {
|
||
|
tmp := *input
|
||
|
inCpy = &tmp
|
||
|
}
|
||
|
req, _ := c.{{ .OperationName }}Request(inCpy)
|
||
|
req.SetContext(ctx)
|
||
|
req.ApplyOptions(opts...)
|
||
|
return req, nil
|
||
|
},
|
||
|
}
|
||
|
w.ApplyOptions(opts...)
|
||
|
|
||
|
return w.WaitWithContext(ctx)
|
||
|
}
|
||
|
{{- end }}
|
||
|
|
||
|
{{ define "waiter interface" }}
|
||
|
WaitUntil{{ .Name }}({{ .Operation.InputRef.GoTypeWithPkgName }}) error
|
||
|
WaitUntil{{ .Name }}WithContext(aws.Context, {{ .Operation.InputRef.GoTypeWithPkgName }}, ...request.WaiterOption) error
|
||
|
{{- end }}
|
||
|
`))
|
||
|
|
||
|
// InterfaceSignature returns a string representing the Waiter's interface
|
||
|
// function signature.
|
||
|
func (w *Waiter) InterfaceSignature() string {
|
||
|
var buf bytes.Buffer
|
||
|
if err := waiterTmpls.ExecuteTemplate(&buf, "waiter interface", w); err != nil {
|
||
|
panic(err)
|
||
|
}
|
||
|
|
||
|
return strings.TrimSpace(buf.String())
|
||
|
}
|
||
|
|
||
|
// GoCode returns the generated Go code for an individual waiter.
|
||
|
func (w *Waiter) GoCode() string {
|
||
|
var buf bytes.Buffer
|
||
|
if err := waiterTmpls.ExecuteTemplate(&buf, "waiter", w); err != nil {
|
||
|
panic(err)
|
||
|
}
|
||
|
|
||
|
return buf.String()
|
||
|
}
|