| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189 |
- // +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 meet 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()
- }
|