v3model_codegen.go 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. // +build codegen
  2. package endpoints
  3. import (
  4. "fmt"
  5. "io"
  6. "reflect"
  7. "strings"
  8. "text/template"
  9. "unicode"
  10. )
  11. // A CodeGenOptions are the options for code generating the endpoints into
  12. // Go code from the endpoints model definition.
  13. type CodeGenOptions struct {
  14. // Options for how the model will be decoded.
  15. DecodeModelOptions DecodeModelOptions
  16. // Disables code generation of the service endpoint prefix IDs defined in
  17. // the model.
  18. DisableGenerateServiceIDs bool
  19. }
  20. // Set combines all of the option functions together
  21. func (d *CodeGenOptions) Set(optFns ...func(*CodeGenOptions)) {
  22. for _, fn := range optFns {
  23. fn(d)
  24. }
  25. }
  26. // CodeGenModel given a endpoints model file will decode it and attempt to
  27. // generate Go code from the model definition. Error will be returned if
  28. // the code is unable to be generated, or decoded.
  29. func CodeGenModel(modelFile io.Reader, outFile io.Writer, optFns ...func(*CodeGenOptions)) error {
  30. var opts CodeGenOptions
  31. opts.Set(optFns...)
  32. resolver, err := DecodeModel(modelFile, func(d *DecodeModelOptions) {
  33. *d = opts.DecodeModelOptions
  34. })
  35. if err != nil {
  36. return err
  37. }
  38. v := struct {
  39. Resolver
  40. CodeGenOptions
  41. }{
  42. Resolver: resolver,
  43. CodeGenOptions: opts,
  44. }
  45. tmpl := template.Must(template.New("tmpl").Funcs(funcMap).Parse(v3Tmpl))
  46. if err := tmpl.ExecuteTemplate(outFile, "defaults", v); err != nil {
  47. return fmt.Errorf("failed to execute template, %v", err)
  48. }
  49. return nil
  50. }
  51. func toSymbol(v string) string {
  52. out := []rune{}
  53. for _, c := range strings.Title(v) {
  54. if !(unicode.IsNumber(c) || unicode.IsLetter(c)) {
  55. continue
  56. }
  57. out = append(out, c)
  58. }
  59. return string(out)
  60. }
  61. func quoteString(v string) string {
  62. return fmt.Sprintf("%q", v)
  63. }
  64. func regionConstName(p, r string) string {
  65. return toSymbol(p) + toSymbol(r)
  66. }
  67. func partitionGetter(id string) string {
  68. return fmt.Sprintf("%sPartition", toSymbol(id))
  69. }
  70. func partitionVarName(id string) string {
  71. return fmt.Sprintf("%sPartition", strings.ToLower(toSymbol(id)))
  72. }
  73. func listPartitionNames(ps partitions) string {
  74. names := []string{}
  75. switch len(ps) {
  76. case 1:
  77. return ps[0].Name
  78. case 2:
  79. return fmt.Sprintf("%s and %s", ps[0].Name, ps[1].Name)
  80. default:
  81. for i, p := range ps {
  82. if i == len(ps)-1 {
  83. names = append(names, "and "+p.Name)
  84. } else {
  85. names = append(names, p.Name)
  86. }
  87. }
  88. return strings.Join(names, ", ")
  89. }
  90. }
  91. func boxedBoolIfSet(msg string, v boxedBool) string {
  92. switch v {
  93. case boxedTrue:
  94. return fmt.Sprintf(msg, "boxedTrue")
  95. case boxedFalse:
  96. return fmt.Sprintf(msg, "boxedFalse")
  97. default:
  98. return ""
  99. }
  100. }
  101. func stringIfSet(msg, v string) string {
  102. if len(v) == 0 {
  103. return ""
  104. }
  105. return fmt.Sprintf(msg, v)
  106. }
  107. func stringSliceIfSet(msg string, vs []string) string {
  108. if len(vs) == 0 {
  109. return ""
  110. }
  111. names := []string{}
  112. for _, v := range vs {
  113. names = append(names, `"`+v+`"`)
  114. }
  115. return fmt.Sprintf(msg, strings.Join(names, ","))
  116. }
  117. func endpointIsSet(v endpoint) bool {
  118. return !reflect.DeepEqual(v, endpoint{})
  119. }
  120. func serviceSet(ps partitions) map[string]struct{} {
  121. set := map[string]struct{}{}
  122. for _, p := range ps {
  123. for id := range p.Services {
  124. set[id] = struct{}{}
  125. }
  126. }
  127. return set
  128. }
  129. var funcMap = template.FuncMap{
  130. "ToSymbol": toSymbol,
  131. "QuoteString": quoteString,
  132. "RegionConst": regionConstName,
  133. "PartitionGetter": partitionGetter,
  134. "PartitionVarName": partitionVarName,
  135. "ListPartitionNames": listPartitionNames,
  136. "BoxedBoolIfSet": boxedBoolIfSet,
  137. "StringIfSet": stringIfSet,
  138. "StringSliceIfSet": stringSliceIfSet,
  139. "EndpointIsSet": endpointIsSet,
  140. "ServicesSet": serviceSet,
  141. }
  142. const v3Tmpl = `
  143. {{ define "defaults" -}}
  144. // Code generated by aws/endpoints/v3model_codegen.go. DO NOT EDIT.
  145. package endpoints
  146. import (
  147. "regexp"
  148. )
  149. {{ template "partition consts" $.Resolver }}
  150. {{ range $_, $partition := $.Resolver }}
  151. {{ template "partition region consts" $partition }}
  152. {{ end }}
  153. {{ if not $.DisableGenerateServiceIDs -}}
  154. {{ template "service consts" $.Resolver }}
  155. {{- end }}
  156. {{ template "endpoint resolvers" $.Resolver }}
  157. {{- end }}
  158. {{ define "partition consts" }}
  159. // Partition identifiers
  160. const (
  161. {{ range $_, $p := . -}}
  162. {{ ToSymbol $p.ID }}PartitionID = {{ QuoteString $p.ID }} // {{ $p.Name }} partition.
  163. {{ end -}}
  164. )
  165. {{- end }}
  166. {{ define "partition region consts" }}
  167. // {{ .Name }} partition's regions.
  168. const (
  169. {{ range $id, $region := .Regions -}}
  170. {{ ToSymbol $id }}RegionID = {{ QuoteString $id }} // {{ $region.Description }}.
  171. {{ end -}}
  172. )
  173. {{- end }}
  174. {{ define "service consts" }}
  175. // Service identifiers
  176. const (
  177. {{ $serviceSet := ServicesSet . -}}
  178. {{ range $id, $_ := $serviceSet -}}
  179. {{ ToSymbol $id }}ServiceID = {{ QuoteString $id }} // {{ ToSymbol $id }}.
  180. {{ end -}}
  181. )
  182. {{- end }}
  183. {{ define "endpoint resolvers" }}
  184. // DefaultResolver returns an Endpoint resolver that will be able
  185. // to resolve endpoints for: {{ ListPartitionNames . }}.
  186. //
  187. // Use DefaultPartitions() to get the list of the default partitions.
  188. func DefaultResolver() Resolver {
  189. return defaultPartitions
  190. }
  191. // DefaultPartitions returns a list of the partitions the SDK is bundled
  192. // with. The available partitions are: {{ ListPartitionNames . }}.
  193. //
  194. // partitions := endpoints.DefaultPartitions
  195. // for _, p := range partitions {
  196. // // ... inspect partitions
  197. // }
  198. func DefaultPartitions() []Partition {
  199. return defaultPartitions.Partitions()
  200. }
  201. var defaultPartitions = partitions{
  202. {{ range $_, $partition := . -}}
  203. {{ PartitionVarName $partition.ID }},
  204. {{ end }}
  205. }
  206. {{ range $_, $partition := . -}}
  207. {{ $name := PartitionGetter $partition.ID -}}
  208. // {{ $name }} returns the Resolver for {{ $partition.Name }}.
  209. func {{ $name }}() Partition {
  210. return {{ PartitionVarName $partition.ID }}.Partition()
  211. }
  212. var {{ PartitionVarName $partition.ID }} = {{ template "gocode Partition" $partition }}
  213. {{ end }}
  214. {{ end }}
  215. {{ define "default partitions" }}
  216. func DefaultPartitions() []Partition {
  217. return []partition{
  218. {{ range $_, $partition := . -}}
  219. // {{ ToSymbol $partition.ID}}Partition(),
  220. {{ end }}
  221. }
  222. }
  223. {{ end }}
  224. {{ define "gocode Partition" -}}
  225. partition{
  226. {{ StringIfSet "ID: %q,\n" .ID -}}
  227. {{ StringIfSet "Name: %q,\n" .Name -}}
  228. {{ StringIfSet "DNSSuffix: %q,\n" .DNSSuffix -}}
  229. RegionRegex: {{ template "gocode RegionRegex" .RegionRegex }},
  230. {{ if EndpointIsSet .Defaults -}}
  231. Defaults: {{ template "gocode Endpoint" .Defaults }},
  232. {{- end }}
  233. Regions: {{ template "gocode Regions" .Regions }},
  234. Services: {{ template "gocode Services" .Services }},
  235. }
  236. {{- end }}
  237. {{ define "gocode RegionRegex" -}}
  238. regionRegex{
  239. Regexp: func() *regexp.Regexp{
  240. reg, _ := regexp.Compile({{ QuoteString .Regexp.String }})
  241. return reg
  242. }(),
  243. }
  244. {{- end }}
  245. {{ define "gocode Regions" -}}
  246. regions{
  247. {{ range $id, $region := . -}}
  248. "{{ $id }}": {{ template "gocode Region" $region }},
  249. {{ end -}}
  250. }
  251. {{- end }}
  252. {{ define "gocode Region" -}}
  253. region{
  254. {{ StringIfSet "Description: %q,\n" .Description -}}
  255. }
  256. {{- end }}
  257. {{ define "gocode Services" -}}
  258. services{
  259. {{ range $id, $service := . -}}
  260. "{{ $id }}": {{ template "gocode Service" $service }},
  261. {{ end }}
  262. }
  263. {{- end }}
  264. {{ define "gocode Service" -}}
  265. service{
  266. {{ StringIfSet "PartitionEndpoint: %q,\n" .PartitionEndpoint -}}
  267. {{ BoxedBoolIfSet "IsRegionalized: %s,\n" .IsRegionalized -}}
  268. {{ if EndpointIsSet .Defaults -}}
  269. Defaults: {{ template "gocode Endpoint" .Defaults -}},
  270. {{- end }}
  271. {{ if .Endpoints -}}
  272. Endpoints: {{ template "gocode Endpoints" .Endpoints }},
  273. {{- end }}
  274. }
  275. {{- end }}
  276. {{ define "gocode Endpoints" -}}
  277. endpoints{
  278. {{ range $id, $endpoint := . -}}
  279. "{{ $id }}": {{ template "gocode Endpoint" $endpoint }},
  280. {{ end }}
  281. }
  282. {{- end }}
  283. {{ define "gocode Endpoint" -}}
  284. endpoint{
  285. {{ StringIfSet "Hostname: %q,\n" .Hostname -}}
  286. {{ StringIfSet "SSLCommonName: %q,\n" .SSLCommonName -}}
  287. {{ StringSliceIfSet "Protocols: []string{%s},\n" .Protocols -}}
  288. {{ StringSliceIfSet "SignatureVersions: []string{%s},\n" .SignatureVersions -}}
  289. {{ if or .CredentialScope.Region .CredentialScope.Service -}}
  290. CredentialScope: credentialScope{
  291. {{ StringIfSet "Region: %q,\n" .CredentialScope.Region -}}
  292. {{ StringIfSet "Service: %q,\n" .CredentialScope.Service -}}
  293. },
  294. {{- end }}
  295. {{ BoxedBoolIfSet "HasDualStack: %s,\n" .HasDualStack -}}
  296. {{ StringIfSet "DualStackHostname: %q,\n" .DualStackHostname -}}
  297. }
  298. {{- end }}
  299. `