| // +build codegen |
| |
| package endpoints |
| |
| import ( |
| "fmt" |
| "io" |
| "reflect" |
| "strings" |
| "text/template" |
| "unicode" |
| ) |
| |
| // A CodeGenOptions are the options for code generating the endpoints into |
| // Go code from the endpoints model definition. |
| type CodeGenOptions struct { |
| // Options for how the model will be decoded. |
| DecodeModelOptions DecodeModelOptions |
| |
| // Disables code generation of the service endpoint prefix IDs defined in |
| // the model. |
| DisableGenerateServiceIDs bool |
| } |
| |
| // Set combines all of the option functions together |
| func (d *CodeGenOptions) Set(optFns ...func(*CodeGenOptions)) { |
| for _, fn := range optFns { |
| fn(d) |
| } |
| } |
| |
| // CodeGenModel given a endpoints model file will decode it and attempt to |
| // generate Go code from the model definition. Error will be returned if |
| // the code is unable to be generated, or decoded. |
| func CodeGenModel(modelFile io.Reader, outFile io.Writer, optFns ...func(*CodeGenOptions)) error { |
| var opts CodeGenOptions |
| opts.Set(optFns...) |
| |
| resolver, err := DecodeModel(modelFile, func(d *DecodeModelOptions) { |
| *d = opts.DecodeModelOptions |
| }) |
| if err != nil { |
| return err |
| } |
| |
| v := struct { |
| Resolver |
| CodeGenOptions |
| }{ |
| Resolver: resolver, |
| CodeGenOptions: opts, |
| } |
| |
| tmpl := template.Must(template.New("tmpl").Funcs(funcMap).Parse(v3Tmpl)) |
| if err := tmpl.ExecuteTemplate(outFile, "defaults", v); err != nil { |
| return fmt.Errorf("failed to execute template, %v", err) |
| } |
| |
| return nil |
| } |
| |
| func toSymbol(v string) string { |
| out := []rune{} |
| for _, c := range strings.Title(v) { |
| if !(unicode.IsNumber(c) || unicode.IsLetter(c)) { |
| continue |
| } |
| |
| out = append(out, c) |
| } |
| |
| return string(out) |
| } |
| |
| func quoteString(v string) string { |
| return fmt.Sprintf("%q", v) |
| } |
| |
| func regionConstName(p, r string) string { |
| return toSymbol(p) + toSymbol(r) |
| } |
| |
| func partitionGetter(id string) string { |
| return fmt.Sprintf("%sPartition", toSymbol(id)) |
| } |
| |
| func partitionVarName(id string) string { |
| return fmt.Sprintf("%sPartition", strings.ToLower(toSymbol(id))) |
| } |
| |
| func listPartitionNames(ps partitions) string { |
| names := []string{} |
| switch len(ps) { |
| case 1: |
| return ps[0].Name |
| case 2: |
| return fmt.Sprintf("%s and %s", ps[0].Name, ps[1].Name) |
| default: |
| for i, p := range ps { |
| if i == len(ps)-1 { |
| names = append(names, "and "+p.Name) |
| } else { |
| names = append(names, p.Name) |
| } |
| } |
| return strings.Join(names, ", ") |
| } |
| } |
| |
| func boxedBoolIfSet(msg string, v boxedBool) string { |
| switch v { |
| case boxedTrue: |
| return fmt.Sprintf(msg, "boxedTrue") |
| case boxedFalse: |
| return fmt.Sprintf(msg, "boxedFalse") |
| default: |
| return "" |
| } |
| } |
| |
| func stringIfSet(msg, v string) string { |
| if len(v) == 0 { |
| return "" |
| } |
| |
| return fmt.Sprintf(msg, v) |
| } |
| |
| func stringSliceIfSet(msg string, vs []string) string { |
| if len(vs) == 0 { |
| return "" |
| } |
| |
| names := []string{} |
| for _, v := range vs { |
| names = append(names, `"`+v+`"`) |
| } |
| |
| return fmt.Sprintf(msg, strings.Join(names, ",")) |
| } |
| |
| func endpointIsSet(v endpoint) bool { |
| return !reflect.DeepEqual(v, endpoint{}) |
| } |
| |
| func serviceSet(ps partitions) map[string]struct{} { |
| set := map[string]struct{}{} |
| for _, p := range ps { |
| for id := range p.Services { |
| set[id] = struct{}{} |
| } |
| } |
| |
| return set |
| } |
| |
| var funcMap = template.FuncMap{ |
| "ToSymbol": toSymbol, |
| "QuoteString": quoteString, |
| "RegionConst": regionConstName, |
| "PartitionGetter": partitionGetter, |
| "PartitionVarName": partitionVarName, |
| "ListPartitionNames": listPartitionNames, |
| "BoxedBoolIfSet": boxedBoolIfSet, |
| "StringIfSet": stringIfSet, |
| "StringSliceIfSet": stringSliceIfSet, |
| "EndpointIsSet": endpointIsSet, |
| "ServicesSet": serviceSet, |
| } |
| |
| const v3Tmpl = ` |
| {{ define "defaults" -}} |
| // Code generated by aws/endpoints/v3model_codegen.go. DO NOT EDIT. |
| |
| package endpoints |
| |
| import ( |
| "regexp" |
| ) |
| |
| {{ template "partition consts" $.Resolver }} |
| |
| {{ range $_, $partition := $.Resolver }} |
| {{ template "partition region consts" $partition }} |
| {{ end }} |
| |
| {{ if not $.DisableGenerateServiceIDs -}} |
| {{ template "service consts" $.Resolver }} |
| {{- end }} |
| |
| {{ template "endpoint resolvers" $.Resolver }} |
| {{- end }} |
| |
| {{ define "partition consts" }} |
| // Partition identifiers |
| const ( |
| {{ range $_, $p := . -}} |
| {{ ToSymbol $p.ID }}PartitionID = {{ QuoteString $p.ID }} // {{ $p.Name }} partition. |
| {{ end -}} |
| ) |
| {{- end }} |
| |
| {{ define "partition region consts" }} |
| // {{ .Name }} partition's regions. |
| const ( |
| {{ range $id, $region := .Regions -}} |
| {{ ToSymbol $id }}RegionID = {{ QuoteString $id }} // {{ $region.Description }}. |
| {{ end -}} |
| ) |
| {{- end }} |
| |
| {{ define "service consts" }} |
| // Service identifiers |
| const ( |
| {{ $serviceSet := ServicesSet . -}} |
| {{ range $id, $_ := $serviceSet -}} |
| {{ ToSymbol $id }}ServiceID = {{ QuoteString $id }} // {{ ToSymbol $id }}. |
| {{ end -}} |
| ) |
| {{- end }} |
| |
| {{ define "endpoint resolvers" }} |
| // DefaultResolver returns an Endpoint resolver that will be able |
| // to resolve endpoints for: {{ ListPartitionNames . }}. |
| // |
| // Use DefaultPartitions() to get the list of the default partitions. |
| func DefaultResolver() Resolver { |
| return defaultPartitions |
| } |
| |
| // DefaultPartitions returns a list of the partitions the SDK is bundled |
| // with. The available partitions are: {{ ListPartitionNames . }}. |
| // |
| // partitions := endpoints.DefaultPartitions |
| // for _, p := range partitions { |
| // // ... inspect partitions |
| // } |
| func DefaultPartitions() []Partition { |
| return defaultPartitions.Partitions() |
| } |
| |
| var defaultPartitions = partitions{ |
| {{ range $_, $partition := . -}} |
| {{ PartitionVarName $partition.ID }}, |
| {{ end }} |
| } |
| |
| {{ range $_, $partition := . -}} |
| {{ $name := PartitionGetter $partition.ID -}} |
| // {{ $name }} returns the Resolver for {{ $partition.Name }}. |
| func {{ $name }}() Partition { |
| return {{ PartitionVarName $partition.ID }}.Partition() |
| } |
| var {{ PartitionVarName $partition.ID }} = {{ template "gocode Partition" $partition }} |
| {{ end }} |
| {{ end }} |
| |
| {{ define "default partitions" }} |
| func DefaultPartitions() []Partition { |
| return []partition{ |
| {{ range $_, $partition := . -}} |
| // {{ ToSymbol $partition.ID}}Partition(), |
| {{ end }} |
| } |
| } |
| {{ end }} |
| |
| {{ define "gocode Partition" -}} |
| partition{ |
| {{ StringIfSet "ID: %q,\n" .ID -}} |
| {{ StringIfSet "Name: %q,\n" .Name -}} |
| {{ StringIfSet "DNSSuffix: %q,\n" .DNSSuffix -}} |
| RegionRegex: {{ template "gocode RegionRegex" .RegionRegex }}, |
| {{ if EndpointIsSet .Defaults -}} |
| Defaults: {{ template "gocode Endpoint" .Defaults }}, |
| {{- end }} |
| Regions: {{ template "gocode Regions" .Regions }}, |
| Services: {{ template "gocode Services" .Services }}, |
| } |
| {{- end }} |
| |
| {{ define "gocode RegionRegex" -}} |
| regionRegex{ |
| Regexp: func() *regexp.Regexp{ |
| reg, _ := regexp.Compile({{ QuoteString .Regexp.String }}) |
| return reg |
| }(), |
| } |
| {{- end }} |
| |
| {{ define "gocode Regions" -}} |
| regions{ |
| {{ range $id, $region := . -}} |
| "{{ $id }}": {{ template "gocode Region" $region }}, |
| {{ end -}} |
| } |
| {{- end }} |
| |
| {{ define "gocode Region" -}} |
| region{ |
| {{ StringIfSet "Description: %q,\n" .Description -}} |
| } |
| {{- end }} |
| |
| {{ define "gocode Services" -}} |
| services{ |
| {{ range $id, $service := . -}} |
| "{{ $id }}": {{ template "gocode Service" $service }}, |
| {{ end }} |
| } |
| {{- end }} |
| |
| {{ define "gocode Service" -}} |
| service{ |
| {{ StringIfSet "PartitionEndpoint: %q,\n" .PartitionEndpoint -}} |
| {{ BoxedBoolIfSet "IsRegionalized: %s,\n" .IsRegionalized -}} |
| {{ if EndpointIsSet .Defaults -}} |
| Defaults: {{ template "gocode Endpoint" .Defaults -}}, |
| {{- end }} |
| {{ if .Endpoints -}} |
| Endpoints: {{ template "gocode Endpoints" .Endpoints }}, |
| {{- end }} |
| } |
| {{- end }} |
| |
| {{ define "gocode Endpoints" -}} |
| endpoints{ |
| {{ range $id, $endpoint := . -}} |
| "{{ $id }}": {{ template "gocode Endpoint" $endpoint }}, |
| {{ end }} |
| } |
| {{- end }} |
| |
| {{ define "gocode Endpoint" -}} |
| endpoint{ |
| {{ StringIfSet "Hostname: %q,\n" .Hostname -}} |
| {{ StringIfSet "SSLCommonName: %q,\n" .SSLCommonName -}} |
| {{ StringSliceIfSet "Protocols: []string{%s},\n" .Protocols -}} |
| {{ StringSliceIfSet "SignatureVersions: []string{%s},\n" .SignatureVersions -}} |
| {{ if or .CredentialScope.Region .CredentialScope.Service -}} |
| CredentialScope: credentialScope{ |
| {{ StringIfSet "Region: %q,\n" .CredentialScope.Region -}} |
| {{ StringIfSet "Service: %q,\n" .CredentialScope.Service -}} |
| }, |
| {{- end }} |
| {{ BoxedBoolIfSet "HasDualStack: %s,\n" .HasDualStack -}} |
| {{ StringIfSet "DualStackHostname: %q,\n" .DualStackHostname -}} |
| |
| } |
| {{- end }} |
| ` |