waiters.go 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. // +build codegen
  2. package api
  3. import (
  4. "bytes"
  5. "encoding/json"
  6. "fmt"
  7. "os"
  8. "sort"
  9. "strings"
  10. "text/template"
  11. )
  12. // A Waiter is an individual waiter definition.
  13. type Waiter struct {
  14. Name string
  15. Delay int
  16. MaxAttempts int
  17. OperationName string `json:"operation"`
  18. Operation *Operation
  19. Acceptors []WaitAcceptor
  20. }
  21. // A WaitAcceptor is an individual wait acceptor definition.
  22. type WaitAcceptor struct {
  23. Expected interface{}
  24. Matcher string
  25. State string
  26. Argument string
  27. }
  28. // WaitersGoCode generates and returns Go code for each of the waiters of
  29. // this API.
  30. func (a *API) WaitersGoCode() string {
  31. var buf bytes.Buffer
  32. fmt.Fprintf(&buf, "import (\n\t%q\n)",
  33. "github.com/aws/aws-sdk-go/private/waiter")
  34. for _, w := range a.Waiters {
  35. buf.WriteString(w.GoCode())
  36. }
  37. return buf.String()
  38. }
  39. // used for unmarshaling from the waiter JSON file
  40. type waiterDefinitions struct {
  41. *API
  42. Waiters map[string]Waiter
  43. }
  44. // AttachWaiters reads a file of waiter definitions, and adds those to the API.
  45. // Will panic if an error occurs.
  46. func (a *API) AttachWaiters(filename string) {
  47. p := waiterDefinitions{API: a}
  48. f, err := os.Open(filename)
  49. defer f.Close()
  50. if err != nil {
  51. panic(err)
  52. }
  53. err = json.NewDecoder(f).Decode(&p)
  54. if err != nil {
  55. panic(err)
  56. }
  57. p.setup()
  58. }
  59. func (p *waiterDefinitions) setup() {
  60. p.API.Waiters = []Waiter{}
  61. i, keys := 0, make([]string, len(p.Waiters))
  62. for k := range p.Waiters {
  63. keys[i] = k
  64. i++
  65. }
  66. sort.Strings(keys)
  67. for _, n := range keys {
  68. e := p.Waiters[n]
  69. n = p.ExportableName(n)
  70. e.Name = n
  71. e.OperationName = p.ExportableName(e.OperationName)
  72. e.Operation = p.API.Operations[e.OperationName]
  73. if e.Operation == nil {
  74. panic("unknown operation " + e.OperationName + " for waiter " + n)
  75. }
  76. p.API.Waiters = append(p.API.Waiters, e)
  77. }
  78. }
  79. // ExpectedString returns the string that was expected by the WaitAcceptor
  80. func (a *WaitAcceptor) ExpectedString() string {
  81. switch a.Expected.(type) {
  82. case string:
  83. return fmt.Sprintf("%q", a.Expected)
  84. default:
  85. return fmt.Sprintf("%v", a.Expected)
  86. }
  87. }
  88. var waiterTmpls = template.Must(template.New("waiterTmpls").Parse(`
  89. {{ define "docstring" -}}
  90. // WaitUntil{{ .Name }} uses the {{ .Operation.API.NiceName }} API operation
  91. // {{ .OperationName }} to wait for a condition to be met before returning.
  92. // If the condition is not meet within the max attempt window an error will
  93. // be returned.
  94. {{- end }}
  95. {{ define "waiter" }}
  96. {{ template "docstring" . }}
  97. func (c *{{ .Operation.API.StructName }}) WaitUntil{{ .Name }}(input {{ .Operation.InputRef.GoType }}) error {
  98. waiterCfg := waiter.Config{
  99. Operation: "{{ .OperationName }}",
  100. Delay: {{ .Delay }},
  101. MaxAttempts: {{ .MaxAttempts }},
  102. Acceptors: []waiter.WaitAcceptor{
  103. {{ range $_, $a := .Acceptors }}waiter.WaitAcceptor{
  104. State: "{{ .State }}",
  105. Matcher: "{{ .Matcher }}",
  106. Argument: "{{ .Argument }}",
  107. Expected: {{ .ExpectedString }},
  108. },
  109. {{ end }}
  110. },
  111. }
  112. w := waiter.Waiter{
  113. Client: c,
  114. Input: input,
  115. Config: waiterCfg,
  116. }
  117. return w.Wait()
  118. }
  119. {{- end }}
  120. {{ define "waiter interface" }}
  121. WaitUntil{{ .Name }}({{ .Operation.InputRef.GoTypeWithPkgName }}) error
  122. {{- end }}
  123. `))
  124. // InterfaceSignature returns a string representing the Waiter's interface
  125. // function signature.
  126. func (w *Waiter) InterfaceSignature() string {
  127. var buf bytes.Buffer
  128. if err := waiterTmpls.ExecuteTemplate(&buf, "waiter interface", w); err != nil {
  129. panic(err)
  130. }
  131. return strings.TrimSpace(buf.String())
  132. }
  133. // GoCode returns the generated Go code for an individual waiter.
  134. func (w *Waiter) GoCode() string {
  135. var buf bytes.Buffer
  136. if err := waiterTmpls.ExecuteTemplate(&buf, "waiter", w); err != nil {
  137. panic(err)
  138. }
  139. return buf.String()
  140. }