1
0
Fork 0

Vendor main dependencies.

This commit is contained in:
Timo Reimann 2017-02-07 22:33:23 +01:00
parent 49a09ab7dd
commit dd5e3fba01
2738 changed files with 1045689 additions and 0 deletions

View file

@ -0,0 +1,133 @@
package endpoints
import (
"encoding/json"
"fmt"
"io"
"github.com/aws/aws-sdk-go/aws/awserr"
)
type modelDefinition map[string]json.RawMessage
// A DecodeModelOptions are the options for how the endpoints model definition
// are decoded.
type DecodeModelOptions struct {
SkipCustomizations bool
}
// Set combines all of the option functions together.
func (d *DecodeModelOptions) Set(optFns ...func(*DecodeModelOptions)) {
for _, fn := range optFns {
fn(d)
}
}
// DecodeModel unmarshals a Regions and Endpoint model definition file into
// a endpoint Resolver. If the file format is not supported, or an error occurs
// when unmarshaling the model an error will be returned.
//
// Casting the return value of this func to a EnumPartitions will
// allow you to get a list of the partitions in the order the endpoints
// will be resolved in.
//
// resolver, err := endpoints.DecodeModel(reader)
//
// partitions := resolver.(endpoints.EnumPartitions).Partitions()
// for _, p := range partitions {
// // ... inspect partitions
// }
func DecodeModel(r io.Reader, optFns ...func(*DecodeModelOptions)) (Resolver, error) {
var opts DecodeModelOptions
opts.Set(optFns...)
// Get the version of the partition file to determine what
// unmarshaling model to use.
modelDef := modelDefinition{}
if err := json.NewDecoder(r).Decode(&modelDef); err != nil {
return nil, newDecodeModelError("failed to decode endpoints model", err)
}
var version string
if b, ok := modelDef["version"]; ok {
version = string(b)
} else {
return nil, newDecodeModelError("endpoints version not found in model", nil)
}
if version == "3" {
return decodeV3Endpoints(modelDef, opts)
}
return nil, newDecodeModelError(
fmt.Sprintf("endpoints version %s, not supported", version), nil)
}
func decodeV3Endpoints(modelDef modelDefinition, opts DecodeModelOptions) (Resolver, error) {
b, ok := modelDef["partitions"]
if !ok {
return nil, newDecodeModelError("endpoints model missing partitions", nil)
}
ps := partitions{}
if err := json.Unmarshal(b, &ps); err != nil {
return nil, newDecodeModelError("failed to decode endpoints model", err)
}
if opts.SkipCustomizations {
return ps, nil
}
// Customization
for i := 0; i < len(ps); i++ {
p := &ps[i]
custAddEC2Metadata(p)
custAddS3DualStack(p)
custRmIotDataService(p)
}
return ps, nil
}
func custAddS3DualStack(p *partition) {
if p.ID != "aws" {
return
}
s, ok := p.Services["s3"]
if !ok {
return
}
s.Defaults.HasDualStack = boxedTrue
s.Defaults.DualStackHostname = "{service}.dualstack.{region}.{dnsSuffix}"
p.Services["s3"] = s
}
func custAddEC2Metadata(p *partition) {
p.Services["ec2metadata"] = service{
IsRegionalized: boxedFalse,
PartitionEndpoint: "aws-global",
Endpoints: endpoints{
"aws-global": endpoint{
Hostname: "169.254.169.254/latest",
Protocols: []string{"http"},
},
},
}
}
func custRmIotDataService(p *partition) {
delete(p.Services, "data.iot")
}
type decodeModelError struct {
awsError
}
func newDecodeModelError(msg string, err error) decodeModelError {
return decodeModelError{
awsError: awserr.New("DecodeEndpointsModelError", msg, err),
}
}

File diff suppressed because it is too large Load diff

66
vendor/github.com/aws/aws-sdk-go/aws/endpoints/doc.go generated vendored Normal file
View file

@ -0,0 +1,66 @@
// Package endpoints provides the types and functionality for defining regions
// and endpoints, as well as querying those definitions.
//
// The SDK's Regions and Endpoints metadata is code generated into the endpoints
// package, and is accessible via the DefaultResolver function. This function
// returns a endpoint Resolver will search the metadata and build an associated
// endpoint if one is found. The default resolver will search all partitions
// known by the SDK. e.g AWS Standard (aws), AWS China (aws-cn), and
// AWS GovCloud (US) (aws-us-gov).
// .
//
// Enumerating Regions and Endpoint Metadata
//
// Casting the Resolver returned by DefaultResolver to a EnumPartitions interface
// will allow you to get access to the list of underlying Partitions with the
// Partitions method. This is helpful if you want to limit the SDK's endpoint
// resolving to a single partition, or enumerate regions, services, and endpoints
// in the partition.
//
// resolver := endpoints.DefaultResolver()
// partitions := resolver.(endpoints.EnumPartitions).Partitions()
//
// for _, p := range partitions {
// fmt.Println("Regions for", p.Name)
// for id, _ := range p.Regions() {
// fmt.Println("*", id)
// }
//
// fmt.Println("Services for", p.Name)
// for id, _ := range p.Services() {
// fmt.Println("*", id)
// }
// }
//
// Using Custom Endpoints
//
// The endpoints package also gives you the ability to use your own logic how
// endpoints are resolved. This is a great way to define a custom endpoint
// for select services, without passing that logic down through your code.
//
// If a type implements the Resolver interface it can be used to resolve
// endpoints. To use this with the SDK's Session and Config set the value
// of the type to the EndpointsResolver field of aws.Config when initializing
// the session, or service client.
//
// In addition the ResolverFunc is a wrapper for a func matching the signature
// of Resolver.EndpointFor, converting it to a type that satisfies the
// Resolver interface.
//
//
// myCustomResolver := func(service, region string, optFns ...func(*endpoints.Options)) (endpoints.ResolvedEndpoint, error) {
// if service == endpoints.S3ServiceID {
// return endpoints.ResolvedEndpoint{
// URL: "s3.custom.endpoint.com",
// SigningRegion: "custom-signing-region",
// }, nil
// }
//
// return endpoints.DefaultResolver().EndpointFor(service, region, optFns...)
// }
//
// sess := session.Must(session.NewSession(&aws.Config{
// Region: aws.String("us-west-2"),
// EndpointResolver: endpoints.ResolverFunc(myCustomResolver),
// }))
package endpoints

View file

@ -0,0 +1,369 @@
package endpoints
import (
"fmt"
"regexp"
"github.com/aws/aws-sdk-go/aws/awserr"
)
// Options provide the configuration needed to direct how the
// endpoints will be resolved.
type Options struct {
// DisableSSL forces the endpoint to be resolved as HTTP.
// instead of HTTPS if the service supports it.
DisableSSL bool
// Sets the resolver to resolve the endpoint as a dualstack endpoint
// for the service. If dualstack support for a service is not known and
// StrictMatching is not enabled a dualstack endpoint for the service will
// be returned. This endpoint may not be valid. If StrictMatching is
// enabled only services that are known to support dualstack will return
// dualstack endpoints.
UseDualStack bool
// Enables strict matching of services and regions resolved endpoints.
// If the partition doesn't enumerate the exact service and region an
// error will be returned. This option will prevent returning endpoints
// that look valid, but may not resolve to any real endpoint.
StrictMatching bool
}
// Set combines all of the option functions together.
func (o *Options) Set(optFns ...func(*Options)) {
for _, fn := range optFns {
fn(o)
}
}
// DisableSSLOption sets the DisableSSL options. Can be used as a functional
// option when resolving endpoints.
func DisableSSLOption(o *Options) {
o.DisableSSL = true
}
// UseDualStackOption sets the UseDualStack option. Can be used as a functional
// option when resolving endpoints.
func UseDualStackOption(o *Options) {
o.UseDualStack = true
}
// StrictMatchingOption sets the StrictMatching option. Can be used as a functional
// option when resolving endpoints.
func StrictMatchingOption(o *Options) {
o.StrictMatching = true
}
// A Resolver provides the interface for functionality to resolve endpoints.
// The build in Partition and DefaultResolver return value satisfy this interface.
type Resolver interface {
EndpointFor(service, region string, opts ...func(*Options)) (ResolvedEndpoint, error)
}
// ResolverFunc is a helper utility that wraps a function so it satisfies the
// Resolver interface. This is useful when you want to add additional endpoint
// resolving logic, or stub out specific endpoints with custom values.
type ResolverFunc func(service, region string, opts ...func(*Options)) (ResolvedEndpoint, error)
// EndpointFor wraps the ResolverFunc function to satisfy the Resolver interface.
func (fn ResolverFunc) EndpointFor(service, region string, opts ...func(*Options)) (ResolvedEndpoint, error) {
return fn(service, region, opts...)
}
var schemeRE = regexp.MustCompile("^([^:]+)://")
// AddScheme adds the HTTP or HTTPS schemes to a endpoint URL if there is no
// scheme. If disableSSL is true HTTP will set HTTP instead of the default HTTPS.
//
// If disableSSL is set, it will only set the URL's scheme if the URL does not
// contain a scheme.
func AddScheme(endpoint string, disableSSL bool) string {
if !schemeRE.MatchString(endpoint) {
scheme := "https"
if disableSSL {
scheme = "http"
}
endpoint = fmt.Sprintf("%s://%s", scheme, endpoint)
}
return endpoint
}
// EnumPartitions a provides a way to retrieve the underlying partitions that
// make up the SDK's default Resolver, or any resolver decoded from a model
// file.
//
// Use this interface with DefaultResolver and DecodeModels to get the list of
// Partitions.
type EnumPartitions interface {
Partitions() []Partition
}
// A Partition provides the ability to enumerate the partition's regions
// and services.
type Partition struct {
id string
p *partition
}
// ID returns the identifier of the partition.
func (p *Partition) ID() string { return p.id }
// EndpointFor attempts to resolve the endpoint based on service and region.
// See Options for information on configuring how the endpoint is resolved.
//
// If the service cannot be found in the metadata the UnknownServiceError
// error will be returned. This validation will occur regardless if
// StrictMatching is enabled.
//
// When resolving endpoints you can choose to enable StrictMatching. This will
// require the provided service and region to be known by the partition.
// If the endpoint cannot be strictly resolved an error will be returned. This
// mode is useful to ensure the endpoint resolved is valid. Without
// StrictMatching enabled the enpoint returned my look valid but may not work.
// StrictMatching requires the SDK to be updated if you want to take advantage
// of new regions and services expantions.
//
// Errors that can be returned.
// * UnknownServiceError
// * UnknownEndpointError
func (p *Partition) EndpointFor(service, region string, opts ...func(*Options)) (ResolvedEndpoint, error) {
return p.p.EndpointFor(service, region, opts...)
}
// Regions returns a map of Regions indexed by their ID. This is useful for
// enumerating over the regions in a partition.
func (p *Partition) Regions() map[string]Region {
rs := map[string]Region{}
for id := range p.p.Regions {
rs[id] = Region{
id: id,
p: p.p,
}
}
return rs
}
// Services returns a map of Service indexed by their ID. This is useful for
// enumerating over the services in a partition.
func (p *Partition) Services() map[string]Service {
ss := map[string]Service{}
for id := range p.p.Services {
ss[id] = Service{
id: id,
p: p.p,
}
}
return ss
}
// A Region provides information about a region, and ability to resolve an
// endpoint from the context of a region, given a service.
type Region struct {
id, desc string
p *partition
}
// ID returns the region's identifier.
func (r *Region) ID() string { return r.id }
// ResolveEndpoint resolves an endpoint from the context of the region given
// a service. See Partition.EndpointFor for usage and errors that can be returned.
func (r *Region) ResolveEndpoint(service string, opts ...func(*Options)) (ResolvedEndpoint, error) {
return r.p.EndpointFor(service, r.id, opts...)
}
// Services returns a list of all services that are known to be in this region.
func (r *Region) Services() map[string]Service {
ss := map[string]Service{}
for id, s := range r.p.Services {
if _, ok := s.Endpoints[r.id]; ok {
ss[id] = Service{
id: id,
p: r.p,
}
}
}
return ss
}
// A Service provides information about a service, and ability to resolve an
// endpoint from the context of a service, given a region.
type Service struct {
id string
p *partition
}
// ID returns the identifier for the service.
func (s *Service) ID() string { return s.id }
// ResolveEndpoint resolves an endpoint from the context of a service given
// a region. See Partition.EndpointFor for usage and errors that can be returned.
func (s *Service) ResolveEndpoint(region string, opts ...func(*Options)) (ResolvedEndpoint, error) {
return s.p.EndpointFor(s.id, region, opts...)
}
// Endpoints returns a map of Endpoints indexed by their ID for all known
// endpoints for a service.
func (s *Service) Endpoints() map[string]Endpoint {
es := map[string]Endpoint{}
for id := range s.p.Services[s.id].Endpoints {
es[id] = Endpoint{
id: id,
serviceID: s.id,
p: s.p,
}
}
return es
}
// A Endpoint provides information about endpoints, and provides the ability
// to resolve that endpoint for the service, and the region the endpoint
// represents.
type Endpoint struct {
id string
serviceID string
p *partition
}
// ID returns the identifier for an endpoint.
func (e *Endpoint) ID() string { return e.id }
// ServiceID returns the identifier the endpoint belongs to.
func (e *Endpoint) ServiceID() string { return e.serviceID }
// ResolveEndpoint resolves an endpoint from the context of a service and
// region the endpoint represents. See Partition.EndpointFor for usage and
// errors that can be returned.
func (e *Endpoint) ResolveEndpoint(opts ...func(*Options)) (ResolvedEndpoint, error) {
return e.p.EndpointFor(e.serviceID, e.id, opts...)
}
// A ResolvedEndpoint is an endpoint that has been resolved based on a partition
// service, and region.
type ResolvedEndpoint struct {
// The endpoint URL
URL string
// The region that should be used for signing requests.
SigningRegion string
// The service name that should be used for signing requests.
SigningName string
// The signing method that should be used for signing requests.
SigningMethod string
}
// So that the Error interface type can be included as an anonymous field
// in the requestError struct and not conflict with the error.Error() method.
type awsError awserr.Error
// A EndpointNotFoundError is returned when in StrictMatching mode, and the
// endpoint for the service and region cannot be found in any of the partitions.
type EndpointNotFoundError struct {
awsError
Partition string
Service string
Region string
}
//// NewEndpointNotFoundError builds and returns NewEndpointNotFoundError.
//func NewEndpointNotFoundError(p, s, r string) EndpointNotFoundError {
// return EndpointNotFoundError{
// awsError: awserr.New("EndpointNotFoundError", "unable to find endpoint", nil),
// Partition: p,
// Service: s,
// Region: r,
// }
//}
//
//// Error returns string representation of the error.
//func (e EndpointNotFoundError) Error() string {
// extra := fmt.Sprintf("partition: %q, service: %q, region: %q",
// e.Partition, e.Service, e.Region)
// return awserr.SprintError(e.Code(), e.Message(), extra, e.OrigErr())
//}
//
//// String returns the string representation of the error.
//func (e EndpointNotFoundError) String() string {
// return e.Error()
//}
// A UnknownServiceError is returned when the service does not resolve to an
// endpoint. Includes a list of all known services for the partition. Returned
// when a partition does not support the service.
type UnknownServiceError struct {
awsError
Partition string
Service string
Known []string
}
// NewUnknownServiceError builds and returns UnknownServiceError.
func NewUnknownServiceError(p, s string, known []string) UnknownServiceError {
return UnknownServiceError{
awsError: awserr.New("UnknownServiceError",
"could not resolve endpoint for unknown service", nil),
Partition: p,
Service: s,
Known: known,
}
}
// String returns the string representation of the error.
func (e UnknownServiceError) Error() string {
extra := fmt.Sprintf("partition: %q, service: %q",
e.Partition, e.Service)
if len(e.Known) > 0 {
extra += fmt.Sprintf(", known: %v", e.Known)
}
return awserr.SprintError(e.Code(), e.Message(), extra, e.OrigErr())
}
// String returns the string representation of the error.
func (e UnknownServiceError) String() string {
return e.Error()
}
// A UnknownEndpointError is returned when in StrictMatching mode and the
// service is valid, but the region does not resolve to an endpoint. Includes
// a list of all known endpoints for the service.
type UnknownEndpointError struct {
awsError
Partition string
Service string
Region string
Known []string
}
// NewUnknownEndpointError builds and returns UnknownEndpointError.
func NewUnknownEndpointError(p, s, r string, known []string) UnknownEndpointError {
return UnknownEndpointError{
awsError: awserr.New("UnknownEndpointError",
"could not resolve endpoint", nil),
Partition: p,
Service: s,
Region: r,
Known: known,
}
}
// String returns the string representation of the error.
func (e UnknownEndpointError) Error() string {
extra := fmt.Sprintf("partition: %q, service: %q, region: %q",
e.Partition, e.Service, e.Region)
if len(e.Known) > 0 {
extra += fmt.Sprintf(", known: %v", e.Known)
}
return awserr.SprintError(e.Code(), e.Message(), extra, e.OrigErr())
}
// String returns the string representation of the error.
func (e UnknownEndpointError) String() string {
return e.Error()
}

View file

@ -0,0 +1,301 @@
package endpoints
import (
"fmt"
"regexp"
"strconv"
"strings"
)
type partitions []partition
func (ps partitions) EndpointFor(service, region string, opts ...func(*Options)) (ResolvedEndpoint, error) {
var opt Options
opt.Set(opts...)
for i := 0; i < len(ps); i++ {
if !ps[i].canResolveEndpoint(service, region, opt.StrictMatching) {
continue
}
return ps[i].EndpointFor(service, region, opts...)
}
// If loose matching fallback to first partition format to use
// when resolving the endpoint.
if !opt.StrictMatching && len(ps) > 0 {
return ps[0].EndpointFor(service, region, opts...)
}
return ResolvedEndpoint{}, NewUnknownEndpointError("all partitions", service, region, []string{})
}
// Partitions satisfies the EnumPartitions interface and returns a list
// of Partitions representing each partition represented in the SDK's
// endpoints model.
func (ps partitions) Partitions() []Partition {
parts := make([]Partition, 0, len(ps))
for i := 0; i < len(ps); i++ {
parts = append(parts, ps[i].Partition())
}
return parts
}
type partition struct {
ID string `json:"partition"`
Name string `json:"partitionName"`
DNSSuffix string `json:"dnsSuffix"`
RegionRegex regionRegex `json:"regionRegex"`
Defaults endpoint `json:"defaults"`
Regions regions `json:"regions"`
Services services `json:"services"`
}
func (p partition) Partition() Partition {
return Partition{
id: p.ID,
p: &p,
}
}
func (p partition) canResolveEndpoint(service, region string, strictMatch bool) bool {
s, hasService := p.Services[service]
_, hasEndpoint := s.Endpoints[region]
if hasEndpoint && hasService {
return true
}
if strictMatch {
return false
}
return p.RegionRegex.MatchString(region)
}
func (p partition) EndpointFor(service, region string, opts ...func(*Options)) (resolved ResolvedEndpoint, err error) {
var opt Options
opt.Set(opts...)
s, hasService := p.Services[service]
if !hasService {
return resolved, NewUnknownServiceError(p.ID, service, serviceList(p.Services))
}
e, hasEndpoint := s.endpointForRegion(region)
if !hasEndpoint && opt.StrictMatching {
return resolved, NewUnknownEndpointError(p.ID, service, region, endpointList(s.Endpoints))
}
defs := []endpoint{p.Defaults, s.Defaults}
return e.resolve(service, region, p.DNSSuffix, defs, opt), nil
}
func serviceList(ss services) []string {
list := make([]string, 0, len(ss))
for k := range ss {
list = append(list, k)
}
return list
}
func endpointList(es endpoints) []string {
list := make([]string, 0, len(es))
for k := range es {
list = append(list, k)
}
return list
}
type regionRegex struct {
*regexp.Regexp
}
func (rr *regionRegex) UnmarshalJSON(b []byte) (err error) {
// Strip leading and trailing quotes
regex, err := strconv.Unquote(string(b))
if err != nil {
return fmt.Errorf("unable to strip quotes from regex, %v", err)
}
rr.Regexp, err = regexp.Compile(regex)
if err != nil {
return fmt.Errorf("unable to unmarshal region regex, %v", err)
}
return nil
}
type regions map[string]region
type region struct {
Description string `json:"description"`
}
type services map[string]service
type service struct {
PartitionEndpoint string `json:"partitionEndpoint"`
IsRegionalized boxedBool `json:"isRegionalized,omitempty"`
Defaults endpoint `json:"defaults"`
Endpoints endpoints `json:"endpoints"`
}
func (s *service) endpointForRegion(region string) (endpoint, bool) {
if s.IsRegionalized == boxedFalse {
return s.Endpoints[s.PartitionEndpoint], region == s.PartitionEndpoint
}
if e, ok := s.Endpoints[region]; ok {
return e, true
}
// Unable to find any matching endpoint, return
// blank that will be used for generic endpoint creation.
return endpoint{}, false
}
type endpoints map[string]endpoint
type endpoint struct {
Hostname string `json:"hostname"`
Protocols []string `json:"protocols"`
CredentialScope credentialScope `json:"credentialScope"`
// Custom fields not modeled
HasDualStack boxedBool `json:"-"`
DualStackHostname string `json:"-"`
// Signature Version not used
SignatureVersions []string `json:"signatureVersions"`
// SSLCommonName not used.
SSLCommonName string `json:"sslCommonName"`
}
const (
defaultProtocol = "https"
defaultSigner = "v4"
)
var (
protocolPriority = []string{"https", "http"}
signerPriority = []string{"v4", "v2"}
)
func getByPriority(s []string, p []string, def string) string {
if len(s) == 0 {
return def
}
for i := 0; i < len(p); i++ {
for j := 0; j < len(s); j++ {
if s[j] == p[i] {
return s[j]
}
}
}
return s[0]
}
func (e endpoint) resolve(service, region, dnsSuffix string, defs []endpoint, opts Options) ResolvedEndpoint {
var merged endpoint
for _, def := range defs {
merged.mergeIn(def)
}
merged.mergeIn(e)
e = merged
hostname := e.Hostname
// Offset the hostname for dualstack if enabled
if opts.UseDualStack && e.HasDualStack == boxedTrue {
hostname = e.DualStackHostname
}
u := strings.Replace(hostname, "{service}", service, 1)
u = strings.Replace(u, "{region}", region, 1)
u = strings.Replace(u, "{dnsSuffix}", dnsSuffix, 1)
scheme := getEndpointScheme(e.Protocols, opts.DisableSSL)
u = fmt.Sprintf("%s://%s", scheme, u)
signingRegion := e.CredentialScope.Region
if len(signingRegion) == 0 {
signingRegion = region
}
signingName := e.CredentialScope.Service
if len(signingName) == 0 {
signingName = service
}
return ResolvedEndpoint{
URL: u,
SigningRegion: signingRegion,
SigningName: signingName,
SigningMethod: getByPriority(e.SignatureVersions, signerPriority, defaultSigner),
}
}
func getEndpointScheme(protocols []string, disableSSL bool) string {
if disableSSL {
return "http"
}
return getByPriority(protocols, protocolPriority, defaultProtocol)
}
func (e *endpoint) mergeIn(other endpoint) {
if len(other.Hostname) > 0 {
e.Hostname = other.Hostname
}
if len(other.Protocols) > 0 {
e.Protocols = other.Protocols
}
if len(other.SignatureVersions) > 0 {
e.SignatureVersions = other.SignatureVersions
}
if len(other.CredentialScope.Region) > 0 {
e.CredentialScope.Region = other.CredentialScope.Region
}
if len(other.CredentialScope.Service) > 0 {
e.CredentialScope.Service = other.CredentialScope.Service
}
if len(other.SSLCommonName) > 0 {
e.SSLCommonName = other.SSLCommonName
}
if other.HasDualStack != boxedBoolUnset {
e.HasDualStack = other.HasDualStack
}
if len(other.DualStackHostname) > 0 {
e.DualStackHostname = other.DualStackHostname
}
}
type credentialScope struct {
Region string `json:"region"`
Service string `json:"service"`
}
type boxedBool int
func (b *boxedBool) UnmarshalJSON(buf []byte) error {
v, err := strconv.ParseBool(string(buf))
if err != nil {
return err
}
if v {
*b = boxedTrue
} else {
*b = boxedFalse
}
return nil
}
const (
boxedBoolUnset boxedBool = iota
boxedFalse
boxedTrue
)

View file

@ -0,0 +1,334 @@
// +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
}
// 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
}
tmpl := template.Must(template.New("tmpl").Funcs(funcMap).Parse(v3Tmpl))
if err := tmpl.ExecuteTemplate(outFile, "defaults", resolver); 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" -}}
// THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT.
package endpoints
import (
"regexp"
)
{{ template "partition consts" . }}
{{ range $_, $partition := . }}
{{ template "partition region consts" $partition }}
{{ end }}
{{ template "service consts" . }}
{{ template "endpoint resolvers" . }}
{{- 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 . }}.
//
// Casting the return value of this func to a EnumPartitions will
// allow you to get a list of the partitions in the order the endpoints
// will be resolved in.
//
// resolver := endpoints.DefaultResolver()
// partitions := resolver.(endpoints.EnumPartitions).Partitions()
// for _, p := range partitions {
// // ... inspect partitions
// }
func DefaultResolver() Resolver {
return defaultPartitions
}
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 }}
`