mirror of
https://github.com/aptly-dev/aptly.git
synced 2026-05-07 22:20:24 +00:00
Upgrade AWS SDK to the latest version
This commit is contained in:
+101
-30
@@ -23,6 +23,7 @@ type API struct {
|
||||
Shapes map[string]*Shape
|
||||
Waiters []Waiter
|
||||
Documentation string
|
||||
Examples Examples
|
||||
|
||||
// Set to true to avoid removing unused shapes
|
||||
NoRemoveUnusedShapes bool
|
||||
@@ -290,36 +291,93 @@ func (a *API) APIGoCode() string {
|
||||
}
|
||||
|
||||
var noCrossLinkServices = map[string]struct{}{
|
||||
"apigateway": struct{}{},
|
||||
"budgets": struct{}{},
|
||||
"cloudsearch": struct{}{},
|
||||
"cloudsearchdomain": struct{}{},
|
||||
"discovery": struct{}{},
|
||||
"elastictranscoder": struct{}{},
|
||||
"es": struct{}{},
|
||||
"glacier": struct{}{},
|
||||
"importexport": struct{}{},
|
||||
"iot": struct{}{},
|
||||
"iot-data": struct{}{},
|
||||
"lambda": struct{}{},
|
||||
"machinelearning": struct{}{},
|
||||
"rekognition": struct{}{},
|
||||
"sdb": struct{}{},
|
||||
"swf": struct{}{},
|
||||
"apigateway": {},
|
||||
"budgets": {},
|
||||
"cloudsearch": {},
|
||||
"cloudsearchdomain": {},
|
||||
"elastictranscoder": {},
|
||||
"es": {},
|
||||
"glacier": {},
|
||||
"importexport": {},
|
||||
"iot": {},
|
||||
"iot-data": {},
|
||||
"machinelearning": {},
|
||||
"rekognition": {},
|
||||
"sdb": {},
|
||||
"swf": {},
|
||||
}
|
||||
|
||||
func GetCrosslinkURL(baseURL, name, uid string, params ...string) string {
|
||||
_, ok := noCrossLinkServices[strings.ToLower(name)]
|
||||
if uid != "" && baseURL != "" && !ok {
|
||||
return strings.Join(append([]string{baseURL, "goto", "WebAPI", uid}, params...), "/")
|
||||
// GetCrosslinkURL returns the crosslinking URL for the shape based on the name and
|
||||
// uid provided. Empty string is returned if no crosslink link could be determined.
|
||||
func GetCrosslinkURL(baseURL, uid string, params ...string) string {
|
||||
if uid == "" || baseURL == "" {
|
||||
return ""
|
||||
}
|
||||
return ""
|
||||
|
||||
if _, ok := noCrossLinkServices[strings.ToLower(serviceIDFromUID(uid))]; ok {
|
||||
return ""
|
||||
}
|
||||
|
||||
return strings.Join(append([]string{baseURL, "goto", "WebAPI", uid}, params...), "/")
|
||||
}
|
||||
|
||||
func serviceIDFromUID(uid string) string {
|
||||
found := 0
|
||||
i := len(uid) - 1
|
||||
for ; i >= 0; i-- {
|
||||
if uid[i] == '-' {
|
||||
found++
|
||||
}
|
||||
// Terminate after the date component is found, e.g. es-2017-11-11
|
||||
if found == 3 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return uid[0:i]
|
||||
}
|
||||
|
||||
// APIName returns the API's service name.
|
||||
func (a *API) APIName() string {
|
||||
return a.name
|
||||
}
|
||||
|
||||
var tplServiceDoc = template.Must(template.New("service docs").Funcs(template.FuncMap{
|
||||
"GetCrosslinkURL": GetCrosslinkURL,
|
||||
}).
|
||||
Parse(`
|
||||
// Package {{ .PackageName }} provides the client and types for making API
|
||||
// requests to {{ .Metadata.ServiceFullName }}.
|
||||
{{ if .Documentation -}}
|
||||
//
|
||||
{{ .Documentation }}
|
||||
{{ end -}}
|
||||
{{ $crosslinkURL := GetCrosslinkURL $.BaseCrosslinkURL $.Metadata.UID -}}
|
||||
{{ if $crosslinkURL -}}
|
||||
//
|
||||
// See {{ $crosslinkURL }} for more information on this service.
|
||||
{{ end -}}
|
||||
//
|
||||
// See {{ .PackageName }} package documentation for more information.
|
||||
// https://docs.aws.amazon.com/sdk-for-go/api/service/{{ .PackageName }}/
|
||||
//
|
||||
// Using the Client
|
||||
//
|
||||
// To {{ .Metadata.ServiceFullName }} with the SDK use the New function to create
|
||||
// a new service client. With that client you can make API requests to the service.
|
||||
// These clients are safe to use concurrently.
|
||||
//
|
||||
// See the SDK's documentation for more information on how to use the SDK.
|
||||
// https://docs.aws.amazon.com/sdk-for-go/api/
|
||||
//
|
||||
// See aws.Config documentation for more information on configuring SDK clients.
|
||||
// https://docs.aws.amazon.com/sdk-for-go/api/aws/#Config
|
||||
//
|
||||
// See the {{ .Metadata.ServiceFullName }} client {{ .StructName }} for more
|
||||
// information on creating client for this service.
|
||||
// https://docs.aws.amazon.com/sdk-for-go/api/service/{{ .PackageName }}/#New
|
||||
`))
|
||||
|
||||
// A tplService defines the template for the service generated code.
|
||||
var tplService = template.Must(template.New("service").Funcs(template.FuncMap{
|
||||
"ServiceNameValue": func(a *API) string {
|
||||
@@ -328,7 +386,6 @@ var tplService = template.Must(template.New("service").Funcs(template.FuncMap{
|
||||
}
|
||||
return "ServiceName"
|
||||
},
|
||||
"GetCrosslinkURL": GetCrosslinkURL,
|
||||
"EndpointsIDConstValue": func(a *API) string {
|
||||
if a.NoConstServiceNames {
|
||||
return fmt.Sprintf("%q", a.Metadata.EndpointPrefix)
|
||||
@@ -346,12 +403,12 @@ var tplService = template.Must(template.New("service").Funcs(template.FuncMap{
|
||||
return "EndpointsID"
|
||||
},
|
||||
}).Parse(`
|
||||
{{ .Documentation }}// The service client's operations are safe to be used concurrently.
|
||||
// It is not safe to mutate any of the client's properties though.
|
||||
{{ $crosslinkURL := GetCrosslinkURL $.BaseCrosslinkURL $.APIName $.Metadata.UID -}}
|
||||
{{ if ne $crosslinkURL "" -}}
|
||||
// Please also see {{ $crosslinkURL }}
|
||||
{{ end -}}
|
||||
// {{ .StructName }} provides the API operation methods for making requests to
|
||||
// {{ .Metadata.ServiceFullName }}. See this package's package overview docs
|
||||
// for details on the service.
|
||||
//
|
||||
// {{ .StructName }} methods are safe to use concurrently. It is not safe to
|
||||
// modify mutate any of the struct's properties though.
|
||||
type {{ .StructName }} struct {
|
||||
*client.Client
|
||||
}
|
||||
@@ -457,6 +514,20 @@ func (c *{{ .StructName }}) newRequest(op *request.Operation, params, data inter
|
||||
}
|
||||
`))
|
||||
|
||||
// ServicePackageDoc generates the contents of the doc file for the service.
|
||||
//
|
||||
// Will also read in the custom doc templates for the service if found.
|
||||
func (a *API) ServicePackageDoc() string {
|
||||
a.imports = map[string]bool{}
|
||||
|
||||
var buf bytes.Buffer
|
||||
if err := tplServiceDoc.Execute(&buf, a); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// ServiceGoCode renders service go code. Returning it as a string.
|
||||
func (a *API) ServiceGoCode() string {
|
||||
a.resetImports()
|
||||
@@ -501,7 +572,7 @@ func (a *API) ExampleGoCode() string {
|
||||
"github.com/aws/aws-sdk-go/aws/session",
|
||||
path.Join(a.SvcClientImportPath, a.PackageName()),
|
||||
)
|
||||
for k, _ := range imports {
|
||||
for k := range imports {
|
||||
code += fmt.Sprintf("%q\n", k)
|
||||
}
|
||||
code += ")\n\n"
|
||||
@@ -519,7 +590,7 @@ var tplInterface = template.Must(template.New("interface").Parse(`
|
||||
//
|
||||
// The best way to use this interface is so the SDK's service client's calls
|
||||
// can be stubbed out for unit testing your code with the SDK without needing
|
||||
// to inject custom request handlers into the the SDK's request pipeline.
|
||||
// to inject custom request handlers into the SDK's request pipeline.
|
||||
//
|
||||
// // myFunc uses an SDK service client to make a request to
|
||||
// // {{.Metadata.ServiceFullName}}. {{ $opts := .OperationList }}{{ $opt := index $opts 0 }}
|
||||
|
||||
+16
-6
@@ -4,8 +4,6 @@ package api
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestStructNameWithFullName(t *testing.T) {
|
||||
@@ -14,7 +12,9 @@ func TestStructNameWithFullName(t *testing.T) {
|
||||
ServiceFullName: "Amazon Service Name-100",
|
||||
},
|
||||
}
|
||||
assert.Equal(t, a.StructName(), "ServiceName100")
|
||||
if a.StructName() != "ServiceName100" {
|
||||
t.Errorf("API struct name should have been %s, but received %s", "ServiceName100", a.StructName())
|
||||
}
|
||||
}
|
||||
|
||||
func TestStructNameWithAbbreviation(t *testing.T) {
|
||||
@@ -24,21 +24,31 @@ func TestStructNameWithAbbreviation(t *testing.T) {
|
||||
ServiceAbbreviation: "AWS SN100",
|
||||
},
|
||||
}
|
||||
assert.Equal(t, a.StructName(), "SN100")
|
||||
if a.StructName() != "SN100" {
|
||||
t.Errorf("API struct name should have been %s, but received %s", "SN100", a.StructName())
|
||||
}
|
||||
}
|
||||
|
||||
func TestStructNameForExceptions(t *testing.T) {
|
||||
serviceAliases = map[string]string{}
|
||||
serviceAliases["elasticloadbalancing"] = "ELB"
|
||||
serviceAliases["config"] = "ConfigService"
|
||||
|
||||
a := API{
|
||||
Metadata: Metadata{
|
||||
ServiceFullName: "Elastic Load Balancing",
|
||||
},
|
||||
}
|
||||
assert.Equal(t, a.StructName(), "ELB")
|
||||
if a.StructName() != "ELB" {
|
||||
t.Errorf("API struct name should have been %s, but received %s", "ELB", a.StructName())
|
||||
}
|
||||
|
||||
a = API{
|
||||
Metadata: Metadata{
|
||||
ServiceFullName: "AWS Config",
|
||||
},
|
||||
}
|
||||
assert.Equal(t, a.StructName(), "ConfigService")
|
||||
if a.StructName() != "ConfigService" {
|
||||
t.Errorf("API struct name should have been %s, but received %s", "ConfigService", a.StructName())
|
||||
}
|
||||
}
|
||||
|
||||
+28
-32
@@ -3,7 +3,6 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
@@ -17,11 +16,11 @@ type service struct {
|
||||
}
|
||||
|
||||
var mergeServices = map[string]service{
|
||||
"dynamodbstreams": service{
|
||||
"dynamodbstreams": {
|
||||
dstName: "dynamodb",
|
||||
srcName: "streams.dynamodb",
|
||||
},
|
||||
"wafregional": service{
|
||||
"wafregional": {
|
||||
dstName: "waf",
|
||||
srcName: "waf-regional",
|
||||
serviceVersion: "2015-08-24",
|
||||
@@ -41,41 +40,13 @@ func (a *API) customizationPasses() {
|
||||
"iotdataplane": disableEndpointResolving,
|
||||
}
|
||||
|
||||
for k, _ := range mergeServices {
|
||||
for k := range mergeServices {
|
||||
svcCustomizations[k] = mergeServicesCustomizations
|
||||
}
|
||||
|
||||
if fn := svcCustomizations[a.PackageName()]; fn != nil {
|
||||
fn(a)
|
||||
}
|
||||
|
||||
blobDocStringCustomizations(a)
|
||||
}
|
||||
|
||||
const base64MarshalDocStr = "// %s is automatically base64 encoded/decoded by the SDK.\n"
|
||||
|
||||
func blobDocStringCustomizations(a *API) {
|
||||
for _, s := range a.Shapes {
|
||||
payloadMemberName := s.Payload
|
||||
|
||||
for refName, ref := range s.MemberRefs {
|
||||
if refName == payloadMemberName {
|
||||
// Payload members have their own encoding and may
|
||||
// be raw bytes or io.Reader
|
||||
continue
|
||||
}
|
||||
if ref.Shape.Type == "blob" {
|
||||
docStr := fmt.Sprintf(base64MarshalDocStr, refName)
|
||||
if len(strings.TrimSpace(ref.Shape.Documentation)) != 0 {
|
||||
ref.Shape.Documentation += "//\n" + docStr
|
||||
} else if len(strings.TrimSpace(ref.Documentation)) != 0 {
|
||||
ref.Documentation += "//\n" + docStr
|
||||
} else {
|
||||
ref.Documentation = docStr
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// s3Customizations customizes the API generation to replace values specific to S3.
|
||||
@@ -88,6 +59,12 @@ func s3Customizations(a *API) {
|
||||
delete(s.MemberRefs, "ContentMD5")
|
||||
}
|
||||
|
||||
for _, refName := range []string{"Bucket", "SSECustomerKey", "CopySourceSSECustomerKey"} {
|
||||
if ref, ok := s.MemberRefs[refName]; ok {
|
||||
ref.GenerateGetter = true
|
||||
}
|
||||
}
|
||||
|
||||
// Expires should be a string not time.Time since the format is not
|
||||
// enforced by S3, and any value can be set to this field outside of the SDK.
|
||||
if strings.HasSuffix(name, "Output") {
|
||||
@@ -104,6 +81,25 @@ func s3Customizations(a *API) {
|
||||
}
|
||||
}
|
||||
}
|
||||
s3CustRemoveHeadObjectModeledErrors(a)
|
||||
}
|
||||
|
||||
// S3 HeadObject API call incorrect models NoSuchKey as valid
|
||||
// error code that can be returned. This operation does not
|
||||
// return error codes, all error codes are derived from HTTP
|
||||
// status codes.
|
||||
//
|
||||
// aws/aws-sdk-go#1208
|
||||
func s3CustRemoveHeadObjectModeledErrors(a *API) {
|
||||
op, ok := a.Operations["HeadObject"]
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
op.Documentation += `
|
||||
//
|
||||
// See http://docs.aws.amazon.com/AmazonS3/latest/API/ErrorResponses.html#RESTErrorResponses
|
||||
// for more information on returned errors.`
|
||||
op.ErrorRefs = []ShapeRef{}
|
||||
}
|
||||
|
||||
// cloudfrontCustomizations customized the API generation to replace values
|
||||
|
||||
+40
-13
@@ -46,13 +46,9 @@ func (a *API) AttachDocs(filename string) {
|
||||
|
||||
func (d *apiDocumentation) setup() {
|
||||
d.API.Documentation = docstring(d.Service)
|
||||
if d.Service == "" {
|
||||
d.API.Documentation =
|
||||
fmt.Sprintf("// %s is a client for %s.\n", d.API.StructName(), d.API.NiceName())
|
||||
}
|
||||
|
||||
for op, doc := range d.Operations {
|
||||
d.API.Operations[op].Documentation = strings.TrimSpace(docstring(doc))
|
||||
d.API.Operations[op].Documentation = docstring(doc)
|
||||
}
|
||||
|
||||
for shape, info := range d.Shapes {
|
||||
@@ -66,6 +62,10 @@ func (d *apiDocumentation) setup() {
|
||||
}
|
||||
|
||||
parts := strings.Split(ref, "$")
|
||||
if len(parts) != 2 {
|
||||
fmt.Fprintf(os.Stderr, "Shape Doc %s has unexpected reference format, %q\n", shape, ref)
|
||||
continue
|
||||
}
|
||||
if sh := d.API.Shapes[parts[0]]; sh != nil {
|
||||
if m := sh.MemberRefs[parts[1]]; m != nil {
|
||||
m.Documentation = docstring(doc)
|
||||
@@ -78,24 +78,41 @@ func (d *apiDocumentation) setup() {
|
||||
var reNewline = regexp.MustCompile(`\r?\n`)
|
||||
var reMultiSpace = regexp.MustCompile(`\s+`)
|
||||
var reComments = regexp.MustCompile(`<!--.*?-->`)
|
||||
var reFullname = regexp.MustCompile(`\s*<fullname?>.+?<\/fullname?>\s*`)
|
||||
var reFullnameBlock = regexp.MustCompile(`<fullname>(.+?)<\/fullname>`)
|
||||
var reFullname = regexp.MustCompile(`<fullname>(.*?)</fullname>`)
|
||||
var reExamples = regexp.MustCompile(`<examples?>.+?<\/examples?>`)
|
||||
var reEndNL = regexp.MustCompile(`\n+$`)
|
||||
|
||||
// docstring rewrites a string to insert godocs formatting.
|
||||
func docstring(doc string) string {
|
||||
doc = strings.TrimSpace(doc)
|
||||
if doc == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
doc = reNewline.ReplaceAllString(doc, "")
|
||||
doc = reMultiSpace.ReplaceAllString(doc, " ")
|
||||
doc = reComments.ReplaceAllString(doc, "")
|
||||
|
||||
var fullname string
|
||||
parts := reFullnameBlock.FindStringSubmatch(doc)
|
||||
if len(parts) > 1 {
|
||||
fullname = parts[1]
|
||||
}
|
||||
// Remove full name block from doc string
|
||||
doc = reFullname.ReplaceAllString(doc, "")
|
||||
|
||||
doc = reExamples.ReplaceAllString(doc, "")
|
||||
doc = generateDoc(doc)
|
||||
doc = reEndNL.ReplaceAllString(doc, "")
|
||||
if doc == "" {
|
||||
return "\n"
|
||||
doc = html.UnescapeString(doc)
|
||||
|
||||
// Replace doc with full name if doc is empty.
|
||||
doc = strings.TrimSpace(doc)
|
||||
if len(doc) == 0 {
|
||||
doc = fullname
|
||||
}
|
||||
|
||||
doc = html.UnescapeString(doc)
|
||||
return commentify(doc)
|
||||
}
|
||||
|
||||
@@ -116,16 +133,26 @@ var style = map[string]string{
|
||||
|
||||
// commentify converts a string to a Go comment
|
||||
func commentify(doc string) string {
|
||||
if len(doc) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
lines := strings.Split(doc, "\n")
|
||||
out := []string{}
|
||||
for i, line := range lines {
|
||||
out := make([]string, 0, len(lines))
|
||||
for i := 0; i < len(lines); i++ {
|
||||
line := lines[i]
|
||||
|
||||
if i > 0 && line == "" && lines[i-1] == "" {
|
||||
continue
|
||||
}
|
||||
out = append(out, "// "+line)
|
||||
out = append(out, line)
|
||||
}
|
||||
|
||||
return strings.Join(out, "\n") + "\n"
|
||||
if len(out) > 0 {
|
||||
out[0] = "// " + out[0]
|
||||
return strings.Join(out, "\n// ")
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// wrap returns a rewritten version of text to have line breaks
|
||||
|
||||
+31
-13
@@ -1,11 +1,9 @@
|
||||
// +build codegen
|
||||
// +build 1.6,codegen
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestNonHTMLDocGen(t *testing.T) {
|
||||
@@ -13,7 +11,9 @@ func TestNonHTMLDocGen(t *testing.T) {
|
||||
expected := "// Testing 1 2 3\n"
|
||||
doc = docstring(doc)
|
||||
|
||||
assert.Equal(t, expected, doc)
|
||||
if expected != doc {
|
||||
t.Errorf("Expected %s, but received %s", expected, doc)
|
||||
}
|
||||
}
|
||||
|
||||
func TestListsHTMLDocGen(t *testing.T) {
|
||||
@@ -21,24 +21,32 @@ func TestListsHTMLDocGen(t *testing.T) {
|
||||
expected := "// * Testing 1 2 3\n// * FooBar\n"
|
||||
doc = docstring(doc)
|
||||
|
||||
assert.Equal(t, expected, doc)
|
||||
if expected != doc {
|
||||
t.Errorf("Expected %s, but received %s", expected, doc)
|
||||
}
|
||||
|
||||
doc = "<ul> <li>Testing 1 2 3</li> <li>FooBar</li> </ul>"
|
||||
expected = "// * Testing 1 2 3\n// * FooBar\n"
|
||||
doc = docstring(doc)
|
||||
|
||||
assert.Equal(t, expected, doc)
|
||||
if expected != doc {
|
||||
t.Errorf("Expected %s, but received %s", expected, doc)
|
||||
}
|
||||
|
||||
// Test leading spaces
|
||||
doc = " <ul> <li>Testing 1 2 3</li> <li>FooBar</li> </ul>"
|
||||
doc = docstring(doc)
|
||||
assert.Equal(t, expected, doc)
|
||||
if expected != doc {
|
||||
t.Errorf("Expected %s, but received %s", expected, doc)
|
||||
}
|
||||
|
||||
// Paragraph check
|
||||
doc = "<ul> <li> <p>Testing 1 2 3</p> </li><li> <p>FooBar</p></li></ul>"
|
||||
expected = "// * Testing 1 2 3\n// \n// * FooBar\n"
|
||||
doc = docstring(doc)
|
||||
assert.Equal(t, expected, doc)
|
||||
if expected != doc {
|
||||
t.Errorf("Expected %s, but received %s", expected, doc)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInlineCodeHTMLDocGen(t *testing.T) {
|
||||
@@ -46,7 +54,9 @@ func TestInlineCodeHTMLDocGen(t *testing.T) {
|
||||
expected := "// * Testing: 1 2 3\n// * FooBar\n"
|
||||
doc = docstring(doc)
|
||||
|
||||
assert.Equal(t, expected, doc)
|
||||
if expected != doc {
|
||||
t.Errorf("Expected %s, but received %s", expected, doc)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInlineCodeInParagraphHTMLDocGen(t *testing.T) {
|
||||
@@ -54,7 +64,9 @@ func TestInlineCodeInParagraphHTMLDocGen(t *testing.T) {
|
||||
expected := "// Testing: 1 2 3\n"
|
||||
doc = docstring(doc)
|
||||
|
||||
assert.Equal(t, expected, doc)
|
||||
if expected != doc {
|
||||
t.Errorf("Expected %s, but received %s", expected, doc)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEmptyPREInlineCodeHTMLDocGen(t *testing.T) {
|
||||
@@ -62,7 +74,9 @@ func TestEmptyPREInlineCodeHTMLDocGen(t *testing.T) {
|
||||
expected := "// Testing\n"
|
||||
doc = docstring(doc)
|
||||
|
||||
assert.Equal(t, expected, doc)
|
||||
if expected != doc {
|
||||
t.Errorf("Expected %s, but received %s", expected, doc)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParagraph(t *testing.T) {
|
||||
@@ -70,7 +84,9 @@ func TestParagraph(t *testing.T) {
|
||||
expected := "// Testing 1 2 3\n"
|
||||
doc = docstring(doc)
|
||||
|
||||
assert.Equal(t, expected, doc)
|
||||
if expected != doc {
|
||||
t.Errorf("Expected %s, but received %s", expected, doc)
|
||||
}
|
||||
}
|
||||
|
||||
func TestComplexListParagraphCode(t *testing.T) {
|
||||
@@ -78,5 +94,7 @@ func TestComplexListParagraphCode(t *testing.T) {
|
||||
expected := "// * FOO Bar\n// \n// * Xyz ABC\n"
|
||||
doc = docstring(doc)
|
||||
|
||||
assert.Equal(t, expected, doc)
|
||||
if expected != doc {
|
||||
t.Errorf("Expected %s, but received %s", expected, doc)
|
||||
}
|
||||
}
|
||||
|
||||
+318
@@ -0,0 +1,318 @@
|
||||
// +build codegen
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"github.com/aws/aws-sdk-go/private/util"
|
||||
)
|
||||
|
||||
type Examples map[string][]Example
|
||||
|
||||
// ExamplesDefinition is the structural representation of the examples-1.json file
|
||||
type ExamplesDefinition struct {
|
||||
*API `json:"-"`
|
||||
Examples Examples `json:"examples"`
|
||||
}
|
||||
|
||||
// Example is a single entry within the examples-1.json file.
|
||||
type Example struct {
|
||||
API *API `json:"-"`
|
||||
Operation *Operation `json:"-"`
|
||||
OperationName string `json:"-"`
|
||||
Index string `json:"-"`
|
||||
Builder examplesBuilder `json:"-"`
|
||||
VisitedErrors map[string]struct{} `json:"-"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
ID string `json:"id"`
|
||||
Comments Comments `json:"comments"`
|
||||
Input map[string]interface{} `json:"input"`
|
||||
Output map[string]interface{} `json:"output"`
|
||||
}
|
||||
|
||||
type Comments struct {
|
||||
Input map[string]interface{} `json:"input"`
|
||||
Output map[string]interface{} `json:"output"`
|
||||
}
|
||||
|
||||
var exampleFuncMap = template.FuncMap{
|
||||
"commentify": commentify,
|
||||
"wrap": wrap,
|
||||
"generateExampleInput": generateExampleInput,
|
||||
"generateTypes": generateTypes,
|
||||
}
|
||||
|
||||
var exampleCustomizations = map[string]template.FuncMap{}
|
||||
|
||||
var exampleTmpls = template.Must(template.New("example").Funcs(exampleFuncMap).Parse(`
|
||||
{{ generateTypes . }}
|
||||
{{ commentify (wrap .Title 80 false) }}
|
||||
//
|
||||
{{ commentify (wrap .Description 80 false) }}
|
||||
func Example{{ .API.StructName }}_{{ .MethodName }}() {
|
||||
svc := {{ .API.PackageName }}.New(session.New())
|
||||
input := &{{ .Operation.InputRef.Shape.GoTypeWithPkgNameElem }} {
|
||||
{{ generateExampleInput . -}}
|
||||
}
|
||||
|
||||
result, err := svc.{{ .OperationName }}(input)
|
||||
if err != nil {
|
||||
if aerr, ok := err.(awserr.Error); ok {
|
||||
switch aerr.Code() {
|
||||
{{ range $_, $ref := .Operation.ErrorRefs -}}
|
||||
{{ if not ($.HasVisitedError $ref) -}}
|
||||
case {{ .API.PackageName }}.{{ $ref.Shape.ErrorCodeName }}:
|
||||
fmt.Println({{ .API.PackageName }}.{{ $ref.Shape.ErrorCodeName }}, aerr.Error())
|
||||
{{ end -}}
|
||||
{{ end -}}
|
||||
default:
|
||||
fmt.Println(aerr.Error())
|
||||
}
|
||||
} else {
|
||||
// Print the error, cast err to awserr.Error to get the Code and
|
||||
// Message from an error.
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(result)
|
||||
}
|
||||
`))
|
||||
|
||||
// Names will return the name of the example. This will also be the name of the operation
|
||||
// that is to be tested.
|
||||
func (exs Examples) Names() []string {
|
||||
names := make([]string, 0, len(exs))
|
||||
for k := range exs {
|
||||
names = append(names, k)
|
||||
}
|
||||
|
||||
sort.Strings(names)
|
||||
return names
|
||||
}
|
||||
|
||||
func (exs Examples) GoCode() string {
|
||||
buf := bytes.NewBuffer(nil)
|
||||
for _, opName := range exs.Names() {
|
||||
examples := exs[opName]
|
||||
for _, ex := range examples {
|
||||
buf.WriteString(util.GoFmt(ex.GoCode()))
|
||||
buf.WriteString("\n")
|
||||
}
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// ExampleCode will generate the example code for the given Example shape.
|
||||
// TODO: Can delete
|
||||
func (ex Example) GoCode() string {
|
||||
var buf bytes.Buffer
|
||||
m := exampleFuncMap
|
||||
if fMap, ok := exampleCustomizations[ex.API.PackageName()]; ok {
|
||||
m = fMap
|
||||
}
|
||||
tmpl := exampleTmpls.Funcs(m)
|
||||
if err := tmpl.ExecuteTemplate(&buf, "example", &ex); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return strings.TrimSpace(buf.String())
|
||||
}
|
||||
|
||||
func generateExampleInput(ex Example) string {
|
||||
if ex.Operation.HasInput() {
|
||||
return ex.Builder.BuildShape(&ex.Operation.InputRef, ex.Input, false)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// generateTypes will generate no types for default examples, but customizations may
|
||||
// require their own defined types.
|
||||
func generateTypes(ex Example) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// correctType will cast the value to the correct type when printing the string.
|
||||
// This is due to the json decoder choosing numbers to be floats, but the shape may
|
||||
// actually be an int. To counter this, we pass the shape's type and properly do the
|
||||
// casting here.
|
||||
func correctType(memName string, t string, value interface{}) string {
|
||||
if value == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
v := ""
|
||||
switch value.(type) {
|
||||
case string:
|
||||
v = value.(string)
|
||||
case int:
|
||||
v = fmt.Sprintf("%d", value.(int))
|
||||
case float64:
|
||||
if t == "integer" || t == "long" || t == "int64" {
|
||||
v = fmt.Sprintf("%d", int(value.(float64)))
|
||||
} else {
|
||||
v = fmt.Sprintf("%f", value.(float64))
|
||||
}
|
||||
case bool:
|
||||
v = fmt.Sprintf("%t", value.(bool))
|
||||
}
|
||||
|
||||
return convertToCorrectType(memName, t, v)
|
||||
}
|
||||
|
||||
func convertToCorrectType(memName, t, v string) string {
|
||||
return fmt.Sprintf("%s: %s,\n", memName, getValue(t, v))
|
||||
}
|
||||
|
||||
func getValue(t, v string) string {
|
||||
if t[0] == '*' {
|
||||
t = t[1:]
|
||||
}
|
||||
switch t {
|
||||
case "string":
|
||||
return fmt.Sprintf("aws.String(%q)", v)
|
||||
case "integer", "long", "int64":
|
||||
return fmt.Sprintf("aws.Int64(%s)", v)
|
||||
case "float", "float64", "double":
|
||||
return fmt.Sprintf("aws.Float64(%s)", v)
|
||||
case "boolean":
|
||||
return fmt.Sprintf("aws.Bool(%s)", v)
|
||||
default:
|
||||
panic("Unsupported type: " + t)
|
||||
}
|
||||
}
|
||||
|
||||
// AttachExamples will create a new ExamplesDefinition from the examples file
|
||||
// and reference the API object.
|
||||
func (a *API) AttachExamples(filename string) {
|
||||
p := ExamplesDefinition{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()
|
||||
}
|
||||
|
||||
var examplesBuilderCustomizations = map[string]examplesBuilder{
|
||||
"wafregional": wafregionalExamplesBuilder{},
|
||||
}
|
||||
|
||||
func (p *ExamplesDefinition) setup() {
|
||||
var builder examplesBuilder
|
||||
ok := false
|
||||
if builder, ok = examplesBuilderCustomizations[p.API.PackageName()]; !ok {
|
||||
builder = defaultExamplesBuilder{}
|
||||
}
|
||||
|
||||
keys := p.Examples.Names()
|
||||
for _, n := range keys {
|
||||
examples := p.Examples[n]
|
||||
for i, e := range examples {
|
||||
n = p.ExportableName(n)
|
||||
e.OperationName = n
|
||||
e.API = p.API
|
||||
e.Index = fmt.Sprintf("shared%02d", i)
|
||||
|
||||
e.Builder = builder
|
||||
|
||||
e.VisitedErrors = map[string]struct{}{}
|
||||
op := p.API.Operations[e.OperationName]
|
||||
e.OperationName = p.ExportableName(e.OperationName)
|
||||
e.Operation = op
|
||||
p.Examples[n][i] = e
|
||||
}
|
||||
}
|
||||
|
||||
p.API.Examples = p.Examples
|
||||
}
|
||||
|
||||
var exampleHeader = template.Must(template.New("exampleHeader").Parse(`
|
||||
import (
|
||||
{{ .Builder.Imports .API }}
|
||||
)
|
||||
|
||||
var _ time.Duration
|
||||
var _ strings.Reader
|
||||
var _ aws.Config
|
||||
|
||||
func parseTime(layout, value string) *time.Time {
|
||||
t, err := time.Parse(layout, value)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return &t
|
||||
}
|
||||
|
||||
`))
|
||||
|
||||
type exHeader struct {
|
||||
Builder examplesBuilder
|
||||
API *API
|
||||
}
|
||||
|
||||
// ExamplesGoCode will return a code representation of the entry within the
|
||||
// examples.json file.
|
||||
func (a *API) ExamplesGoCode() string {
|
||||
var buf bytes.Buffer
|
||||
var builder examplesBuilder
|
||||
ok := false
|
||||
if builder, ok = examplesBuilderCustomizations[a.PackageName()]; !ok {
|
||||
builder = defaultExamplesBuilder{}
|
||||
}
|
||||
|
||||
if err := exampleHeader.ExecuteTemplate(&buf, "exampleHeader", &exHeader{builder, a}); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
code := a.Examples.GoCode()
|
||||
if len(code) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
buf.WriteString(code)
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// TODO: In the operation docuentation where we list errors, this needs to be done
|
||||
// there as well.
|
||||
func (ex *Example) HasVisitedError(errRef *ShapeRef) bool {
|
||||
errName := errRef.Shape.ErrorCodeName()
|
||||
_, ok := ex.VisitedErrors[errName]
|
||||
ex.VisitedErrors[errName] = struct{}{}
|
||||
return ok
|
||||
}
|
||||
|
||||
func parseTimeString(ref *ShapeRef, memName, v string) string {
|
||||
if ref.Location == "header" {
|
||||
return fmt.Sprintf("%s: parseTime(%q, %q),\n", memName, "Mon, 2 Jan 2006 15:04:05 GMT", v)
|
||||
} else {
|
||||
switch ref.API.Metadata.Protocol {
|
||||
case "json", "rest-json":
|
||||
return fmt.Sprintf("%s: parseTime(%q, %q),\n", memName, "2006-01-02T15:04:05Z", v)
|
||||
case "rest-xml", "ec2", "query":
|
||||
return fmt.Sprintf("%s: parseTime(%q, %q),\n", memName, "2006-01-02T15:04:05Z", v)
|
||||
default:
|
||||
panic("Unsupported time type: " + ref.API.Metadata.Protocol)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (ex *Example) MethodName() string {
|
||||
return fmt.Sprintf("%s_%s", ex.OperationName, ex.Index)
|
||||
}
|
||||
+206
@@ -0,0 +1,206 @@
|
||||
// +build 1.6,codegen
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func buildAPI() *API {
|
||||
a := &API{}
|
||||
|
||||
stringShape := &Shape{
|
||||
API: a,
|
||||
ShapeName: "string",
|
||||
Type: "string",
|
||||
}
|
||||
stringShapeRef := &ShapeRef{
|
||||
API: a,
|
||||
ShapeName: "string",
|
||||
Shape: stringShape,
|
||||
}
|
||||
|
||||
intShape := &Shape{
|
||||
API: a,
|
||||
ShapeName: "int",
|
||||
Type: "int",
|
||||
}
|
||||
intShapeRef := &ShapeRef{
|
||||
API: a,
|
||||
ShapeName: "int",
|
||||
Shape: intShape,
|
||||
}
|
||||
|
||||
input := &Shape{
|
||||
API: a,
|
||||
ShapeName: "FooInput",
|
||||
MemberRefs: map[string]*ShapeRef{
|
||||
"BarShape": stringShapeRef,
|
||||
},
|
||||
Type: "structure",
|
||||
}
|
||||
output := &Shape{
|
||||
API: a,
|
||||
ShapeName: "FooOutput",
|
||||
MemberRefs: map[string]*ShapeRef{
|
||||
"BazShape": intShapeRef,
|
||||
},
|
||||
Type: "structure",
|
||||
}
|
||||
|
||||
inputRef := ShapeRef{
|
||||
API: a,
|
||||
ShapeName: "FooInput",
|
||||
Shape: input,
|
||||
}
|
||||
outputRef := ShapeRef{
|
||||
API: a,
|
||||
ShapeName: "Foooutput",
|
||||
Shape: output,
|
||||
}
|
||||
|
||||
operations := map[string]*Operation{
|
||||
"Foo": {
|
||||
API: a,
|
||||
Name: "Foo",
|
||||
ExportedName: "Foo",
|
||||
InputRef: inputRef,
|
||||
OutputRef: outputRef,
|
||||
},
|
||||
}
|
||||
|
||||
a.Operations = operations
|
||||
a.Shapes = map[string]*Shape{
|
||||
"FooInput": input,
|
||||
"FooOutput": output,
|
||||
}
|
||||
a.Metadata = Metadata{
|
||||
ServiceAbbreviation: "FooService",
|
||||
}
|
||||
|
||||
a.Setup()
|
||||
return a
|
||||
}
|
||||
|
||||
func TestExampleGeneration(t *testing.T) {
|
||||
example := `
|
||||
{
|
||||
"version": "1.0",
|
||||
"examples": {
|
||||
"Foo": [
|
||||
{
|
||||
"input": {
|
||||
"BarShape": "Hello world"
|
||||
},
|
||||
"output": {
|
||||
"BazShape": 1
|
||||
},
|
||||
"comments": {
|
||||
"input": {
|
||||
},
|
||||
"output": {
|
||||
}
|
||||
},
|
||||
"description": "Foo bar baz qux",
|
||||
"title": "I pity the foo"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
`
|
||||
a := buildAPI()
|
||||
def := &ExamplesDefinition{}
|
||||
err := json.Unmarshal([]byte(example), def)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
def.API = a
|
||||
|
||||
def.setup()
|
||||
expected := `
|
||||
import (
|
||||
"fmt"
|
||||
"bytes"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/service/fooservice"
|
||||
)
|
||||
|
||||
var _ time.Duration
|
||||
var _ bytes.Buffer
|
||||
var _ aws.Config
|
||||
|
||||
func parseTime(layout, value string) *time.Time {
|
||||
t, err := time.Parse(layout, value)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return &t
|
||||
}
|
||||
|
||||
// I pity the foo
|
||||
//
|
||||
// Foo bar baz qux
|
||||
func ExampleFooService_Foo_shared00() {
|
||||
svc := fooservice.New(session.New())
|
||||
input := &fooservice.FooInput{
|
||||
BarShape: aws.String("Hello world"),
|
||||
}
|
||||
|
||||
result, err := svc.Foo(input)
|
||||
if err != nil {
|
||||
if aerr, ok := err.(awserr.Error); ok {
|
||||
switch aerr.Code() {
|
||||
default:
|
||||
fmt.Println(aerr.Error())
|
||||
}
|
||||
} else {
|
||||
// Print the error, cast err to awserr.Error to get the Code and
|
||||
// Message from an error.
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(result)
|
||||
}
|
||||
`
|
||||
if expected != a.ExamplesGoCode() {
|
||||
t.Log([]byte(expected))
|
||||
t.Log([]byte(a.ExamplesGoCode()))
|
||||
t.Errorf("Expected:\n%s\nReceived:\n%s\n", expected, a.ExamplesGoCode())
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildShape(t *testing.T) {
|
||||
a := buildAPI()
|
||||
cases := []struct {
|
||||
defs map[string]interface{}
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
defs: map[string]interface{}{
|
||||
"barShape": "Hello World",
|
||||
},
|
||||
expected: "BarShape: aws.String(\"Hello World\"),\n",
|
||||
},
|
||||
{
|
||||
defs: map[string]interface{}{
|
||||
"BarShape": "Hello World",
|
||||
},
|
||||
expected: "BarShape: aws.String(\"Hello World\"),\n",
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
ref := a.Operations["Foo"].InputRef
|
||||
shapeStr := defaultExamplesBuilder{}.BuildShape(&ref, c.defs, false)
|
||||
if c.expected != shapeStr {
|
||||
t.Errorf("Expected:\n%s\nReceived:\n%s", c.expected, shapeStr)
|
||||
}
|
||||
}
|
||||
}
|
||||
+256
@@ -0,0 +1,256 @@
|
||||
// +build codegen
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type examplesBuilder interface {
|
||||
BuildShape(*ShapeRef, map[string]interface{}, bool) string
|
||||
BuildList(string, string, *ShapeRef, []interface{}) string
|
||||
BuildComplex(string, string, *ShapeRef, map[string]interface{}) string
|
||||
Imports(*API) string
|
||||
}
|
||||
|
||||
type defaultExamplesBuilder struct{}
|
||||
|
||||
// BuildShape will recursively build the referenced shape based on the json object
|
||||
// provided.
|
||||
// isMap will dictate how the field name is specified. If isMap is true, we will expect
|
||||
// the member name to be quotes like "Foo".
|
||||
func (builder defaultExamplesBuilder) BuildShape(ref *ShapeRef, shapes map[string]interface{}, isMap bool) string {
|
||||
order := make([]string, len(shapes))
|
||||
for k := range shapes {
|
||||
order = append(order, k)
|
||||
}
|
||||
sort.Strings(order)
|
||||
|
||||
ret := ""
|
||||
for _, name := range order {
|
||||
if name == "" {
|
||||
continue
|
||||
}
|
||||
shape := shapes[name]
|
||||
|
||||
// If the shape isn't a map, we want to export the value, since every field
|
||||
// defined in our shapes are exported.
|
||||
if len(name) > 0 && !isMap && strings.ToLower(name[0:1]) == name[0:1] {
|
||||
name = strings.Title(name)
|
||||
}
|
||||
|
||||
memName := name
|
||||
if isMap {
|
||||
memName = fmt.Sprintf("%q", memName)
|
||||
}
|
||||
|
||||
switch v := shape.(type) {
|
||||
case map[string]interface{}:
|
||||
ret += builder.BuildComplex(name, memName, ref, v)
|
||||
case []interface{}:
|
||||
ret += builder.BuildList(name, memName, ref, v)
|
||||
default:
|
||||
ret += builder.BuildScalar(name, memName, ref, v)
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// BuildList will construct a list shape based off the service's definition
|
||||
// of that list.
|
||||
func (builder defaultExamplesBuilder) BuildList(name, memName string, ref *ShapeRef, v []interface{}) string {
|
||||
ret := ""
|
||||
|
||||
if len(v) == 0 || ref == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
t := ""
|
||||
dataType := ""
|
||||
format := ""
|
||||
isComplex := false
|
||||
passRef := ref
|
||||
isMap := false
|
||||
|
||||
if ref.Shape.MemberRefs[name] != nil {
|
||||
t = builder.GoType(&ref.Shape.MemberRefs[name].Shape.MemberRef, false)
|
||||
dataType = ref.Shape.MemberRefs[name].Shape.MemberRef.Shape.Type
|
||||
passRef = ref.Shape.MemberRefs[name]
|
||||
if dataType == "map" {
|
||||
t = fmt.Sprintf("map[string]%s", builder.GoType(&ref.Shape.MemberRefs[name].Shape.MemberRef.Shape.ValueRef, false))
|
||||
passRef = &ref.Shape.MemberRefs[name].Shape.MemberRef.Shape.ValueRef
|
||||
isMap = true
|
||||
}
|
||||
} else if ref.Shape.MemberRef.Shape != nil && ref.Shape.MemberRef.Shape.MemberRefs[name] != nil {
|
||||
t = builder.GoType(&ref.Shape.MemberRef.Shape.MemberRefs[name].Shape.MemberRef, false)
|
||||
dataType = ref.Shape.MemberRef.Shape.MemberRefs[name].Shape.MemberRef.Shape.Type
|
||||
passRef = &ref.Shape.MemberRef.Shape.MemberRefs[name].Shape.MemberRef
|
||||
} else {
|
||||
t = builder.GoType(&ref.Shape.MemberRef, false)
|
||||
dataType = ref.Shape.MemberRef.Shape.Type
|
||||
passRef = &ref.Shape.MemberRef
|
||||
}
|
||||
|
||||
switch v[0].(type) {
|
||||
case string:
|
||||
format = "%s"
|
||||
case bool:
|
||||
format = "%t"
|
||||
case float64:
|
||||
if dataType == "integer" || dataType == "int64" {
|
||||
format = "%d"
|
||||
} else {
|
||||
format = "%f"
|
||||
}
|
||||
default:
|
||||
if ref.Shape.MemberRefs[name] != nil {
|
||||
} else {
|
||||
passRef = ref.Shape.MemberRef.Shape.MemberRefs[name]
|
||||
|
||||
// if passRef is nil that means we are either in a map or within a nested array
|
||||
if passRef == nil {
|
||||
passRef = &ref.Shape.MemberRef
|
||||
}
|
||||
}
|
||||
isComplex = true
|
||||
}
|
||||
ret += fmt.Sprintf("%s: []%s {\n", memName, t)
|
||||
for _, elem := range v {
|
||||
if isComplex {
|
||||
ret += fmt.Sprintf("{\n%s\n},\n", builder.BuildShape(passRef, elem.(map[string]interface{}), isMap))
|
||||
} else {
|
||||
if dataType == "integer" || dataType == "int64" || dataType == "long" {
|
||||
elem = int(elem.(float64))
|
||||
}
|
||||
ret += fmt.Sprintf("%s,\n", getValue(t, fmt.Sprintf(format, elem)))
|
||||
}
|
||||
}
|
||||
ret += "},\n"
|
||||
return ret
|
||||
}
|
||||
|
||||
// BuildScalar will build atomic Go types.
|
||||
func (builder defaultExamplesBuilder) BuildScalar(name, memName string, ref *ShapeRef, shape interface{}) string {
|
||||
if ref == nil || ref.Shape == nil {
|
||||
return ""
|
||||
} else if ref.Shape.MemberRefs[name] == nil {
|
||||
if ref.Shape.MemberRef.Shape != nil && ref.Shape.MemberRef.Shape.MemberRefs[name] != nil {
|
||||
return correctType(memName, ref.Shape.MemberRef.Shape.MemberRefs[name].Shape.Type, shape)
|
||||
}
|
||||
if ref.Shape.Type != "structure" && ref.Shape.Type != "map" {
|
||||
return correctType(memName, ref.Shape.Type, shape)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
switch v := shape.(type) {
|
||||
case bool:
|
||||
return convertToCorrectType(memName, ref.Shape.MemberRefs[name].Shape.Type, fmt.Sprintf("%t", v))
|
||||
case int:
|
||||
if ref.Shape.MemberRefs[name].Shape.Type == "timestamp" {
|
||||
return parseTimeString(ref, memName, fmt.Sprintf("%d", v))
|
||||
}
|
||||
return convertToCorrectType(memName, ref.Shape.MemberRefs[name].Shape.Type, fmt.Sprintf("%d", v))
|
||||
case float64:
|
||||
dataType := ref.Shape.MemberRefs[name].Shape.Type
|
||||
if dataType == "integer" || dataType == "int64" || dataType == "long" {
|
||||
return convertToCorrectType(memName, ref.Shape.MemberRefs[name].Shape.Type, fmt.Sprintf("%d", int(shape.(float64))))
|
||||
}
|
||||
return convertToCorrectType(memName, ref.Shape.MemberRefs[name].Shape.Type, fmt.Sprintf("%f", v))
|
||||
case string:
|
||||
t := ref.Shape.MemberRefs[name].Shape.Type
|
||||
switch t {
|
||||
case "timestamp":
|
||||
return parseTimeString(ref, memName, fmt.Sprintf("%s", v))
|
||||
case "blob":
|
||||
if (ref.Shape.MemberRefs[name].Streaming || ref.Shape.MemberRefs[name].Shape.Streaming) && ref.Shape.Payload == name {
|
||||
return fmt.Sprintf("%s: aws.ReadSeekCloser(strings.NewReader(%q)),\n", memName, v)
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%s: []byte(%q),\n", memName, v)
|
||||
default:
|
||||
return convertToCorrectType(memName, t, v)
|
||||
}
|
||||
default:
|
||||
panic(fmt.Errorf("Unsupported scalar type: %v", reflect.TypeOf(v)))
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (builder defaultExamplesBuilder) BuildComplex(name, memName string, ref *ShapeRef, v map[string]interface{}) string {
|
||||
t := ""
|
||||
if ref == nil {
|
||||
return builder.BuildShape(nil, v, true)
|
||||
}
|
||||
|
||||
member := ref.Shape.MemberRefs[name]
|
||||
|
||||
if member != nil && member.Shape != nil {
|
||||
t = ref.Shape.MemberRefs[name].Shape.Type
|
||||
} else {
|
||||
t = ref.Shape.Type
|
||||
}
|
||||
|
||||
switch t {
|
||||
case "structure":
|
||||
passRef := ref.Shape.MemberRefs[name]
|
||||
// passRef will be nil if the entry is a map. In that case
|
||||
// we want to pass the reference, because the previous call
|
||||
// passed the value reference.
|
||||
if passRef == nil {
|
||||
passRef = ref
|
||||
}
|
||||
return fmt.Sprintf(`%s: &%s{
|
||||
%s
|
||||
},
|
||||
`, memName, builder.GoType(passRef, true), builder.BuildShape(passRef, v, false))
|
||||
case "map":
|
||||
return fmt.Sprintf(`%s: %s{
|
||||
%s
|
||||
},
|
||||
`, name, builder.GoType(ref.Shape.MemberRefs[name], false), builder.BuildShape(&ref.Shape.MemberRefs[name].Shape.ValueRef, v, true))
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
func (builder defaultExamplesBuilder) GoType(ref *ShapeRef, elem bool) string {
|
||||
prefix := ""
|
||||
if ref.Shape.Type == "list" {
|
||||
ref = &ref.Shape.MemberRef
|
||||
prefix = "[]*"
|
||||
}
|
||||
|
||||
name := ref.GoTypeWithPkgName()
|
||||
if elem {
|
||||
name = ref.GoTypeElem()
|
||||
if !strings.Contains(name, ".") {
|
||||
name = strings.Join([]string{ref.API.PackageName(), name}, ".")
|
||||
}
|
||||
}
|
||||
|
||||
if ref.Shape.Type != "structure" && ref.Shape.Type != "list" {
|
||||
return name
|
||||
}
|
||||
|
||||
return prefix + name
|
||||
}
|
||||
|
||||
func (builder defaultExamplesBuilder) Imports(a *API) string {
|
||||
buf := bytes.NewBuffer(nil)
|
||||
buf.WriteString(`"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
`)
|
||||
|
||||
buf.WriteString(fmt.Sprintf("\"%s/%s\"", "github.com/aws/aws-sdk-go/service", a.PackageName()))
|
||||
return buf.String()
|
||||
}
|
||||
Generated
Vendored
+28
@@ -0,0 +1,28 @@
|
||||
// +build codegen
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type wafregionalExamplesBuilder struct {
|
||||
defaultExamplesBuilder
|
||||
}
|
||||
|
||||
func (builder wafregionalExamplesBuilder) Imports(a *API) string {
|
||||
buf := bytes.NewBuffer(nil)
|
||||
buf.WriteString(`"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/service/waf"
|
||||
`)
|
||||
|
||||
buf.WriteString(fmt.Sprintf("\"%s/%s\"", "github.com/aws/aws-sdk-go/service", a.PackageName()))
|
||||
return buf.String()
|
||||
}
|
||||
+495
@@ -0,0 +1,495 @@
|
||||
package api
|
||||
|
||||
// shamelist is used to not rename certain operation's input and output shapes.
|
||||
// We need to maintain backwards compatibility with pre-existing services. Since
|
||||
// not generating unique input/output shapes is not desired, we will generate
|
||||
// unique input/output shapes for new operations.
|
||||
var shamelist = map[string]map[string]struct {
|
||||
input bool
|
||||
output bool
|
||||
}{
|
||||
"APIGateway": {
|
||||
"CreateApiKey": {
|
||||
output: true,
|
||||
},
|
||||
"CreateAuthorizer": {
|
||||
output: true,
|
||||
},
|
||||
"CreateBasePathMapping": {
|
||||
output: true,
|
||||
},
|
||||
"CreateDeployment": {
|
||||
output: true,
|
||||
},
|
||||
"CreateDocumentationPart": {
|
||||
output: true,
|
||||
},
|
||||
"CreateDocumentationVersion": {
|
||||
output: true,
|
||||
},
|
||||
"CreateDomainName": {
|
||||
output: true,
|
||||
},
|
||||
"CreateModel": {
|
||||
output: true,
|
||||
},
|
||||
"CreateResource": {
|
||||
output: true,
|
||||
},
|
||||
"CreateRestApi": {
|
||||
output: true,
|
||||
},
|
||||
"CreateStage": {
|
||||
output: true,
|
||||
},
|
||||
"CreateUsagePlan": {
|
||||
output: true,
|
||||
},
|
||||
"CreateUsagePlanKey": {
|
||||
output: true,
|
||||
},
|
||||
"GenerateClientCertificate": {
|
||||
output: true,
|
||||
},
|
||||
"GetAccount": {
|
||||
output: true,
|
||||
},
|
||||
"GetApiKey": {
|
||||
output: true,
|
||||
},
|
||||
"GetAuthorizer": {
|
||||
output: true,
|
||||
},
|
||||
"GetBasePathMapping": {
|
||||
output: true,
|
||||
},
|
||||
"GetClientCertificate": {
|
||||
output: true,
|
||||
},
|
||||
"GetDeployment": {
|
||||
output: true,
|
||||
},
|
||||
"GetDocumentationPart": {
|
||||
output: true,
|
||||
},
|
||||
"GetDocumentationVersion": {
|
||||
output: true,
|
||||
},
|
||||
"GetDomainName": {
|
||||
output: true,
|
||||
},
|
||||
"GetIntegration": {
|
||||
output: true,
|
||||
},
|
||||
"GetIntegrationResponse": {
|
||||
output: true,
|
||||
},
|
||||
"GetMethod": {
|
||||
output: true,
|
||||
},
|
||||
"GetMethodResponse": {
|
||||
output: true,
|
||||
},
|
||||
"GetModel": {
|
||||
output: true,
|
||||
},
|
||||
"GetResource": {
|
||||
output: true,
|
||||
},
|
||||
"GetRestApi": {
|
||||
output: true,
|
||||
},
|
||||
"GetSdkType": {
|
||||
output: true,
|
||||
},
|
||||
"GetStage": {
|
||||
output: true,
|
||||
},
|
||||
"GetUsage": {
|
||||
output: true,
|
||||
},
|
||||
"GetUsagePlan": {
|
||||
output: true,
|
||||
},
|
||||
"GetUsagePlanKey": {
|
||||
output: true,
|
||||
},
|
||||
"ImportRestApi": {
|
||||
output: true,
|
||||
},
|
||||
"PutIntegration": {
|
||||
output: true,
|
||||
},
|
||||
"PutIntegrationResponse": {
|
||||
output: true,
|
||||
},
|
||||
"PutMethod": {
|
||||
output: true,
|
||||
},
|
||||
"PutMethodResponse": {
|
||||
output: true,
|
||||
},
|
||||
"PutRestApi": {
|
||||
output: true,
|
||||
},
|
||||
"UpdateAccount": {
|
||||
output: true,
|
||||
},
|
||||
"UpdateApiKey": {
|
||||
output: true,
|
||||
},
|
||||
"UpdateAuthorizer": {
|
||||
output: true,
|
||||
},
|
||||
"UpdateBasePathMapping": {
|
||||
output: true,
|
||||
},
|
||||
"UpdateClientCertificate": {
|
||||
output: true,
|
||||
},
|
||||
"UpdateDeployment": {
|
||||
output: true,
|
||||
},
|
||||
"UpdateDocumentationPart": {
|
||||
output: true,
|
||||
},
|
||||
"UpdateDocumentationVersion": {
|
||||
output: true,
|
||||
},
|
||||
"UpdateDomainName": {
|
||||
output: true,
|
||||
},
|
||||
"UpdateIntegration": {
|
||||
output: true,
|
||||
},
|
||||
"UpdateIntegrationResponse": {
|
||||
output: true,
|
||||
},
|
||||
"UpdateMethod": {
|
||||
output: true,
|
||||
},
|
||||
"UpdateMethodResponse": {
|
||||
output: true,
|
||||
},
|
||||
"UpdateModel": {
|
||||
output: true,
|
||||
},
|
||||
"UpdateResource": {
|
||||
output: true,
|
||||
},
|
||||
"UpdateRestApi": {
|
||||
output: true,
|
||||
},
|
||||
"UpdateStage": {
|
||||
output: true,
|
||||
},
|
||||
"UpdateUsage": {
|
||||
output: true,
|
||||
},
|
||||
"UpdateUsagePlan": {
|
||||
output: true,
|
||||
},
|
||||
},
|
||||
"AutoScaling": {
|
||||
"ResumeProcesses": {
|
||||
input: true,
|
||||
},
|
||||
"SuspendProcesses": {
|
||||
input: true,
|
||||
},
|
||||
},
|
||||
"CognitoIdentity": {
|
||||
"CreateIdentityPool": {
|
||||
output: true,
|
||||
},
|
||||
"DescribeIdentity": {
|
||||
output: true,
|
||||
},
|
||||
"DescribeIdentityPool": {
|
||||
output: true,
|
||||
},
|
||||
"UpdateIdentityPool": {
|
||||
input: true,
|
||||
output: true,
|
||||
},
|
||||
},
|
||||
"DirectConnect": {
|
||||
"AllocateConnectionOnInterconnect": {
|
||||
output: true,
|
||||
},
|
||||
"AllocateHostedConnection": {
|
||||
output: true,
|
||||
},
|
||||
"AllocatePrivateVirtualInterface": {
|
||||
output: true,
|
||||
},
|
||||
"AllocatePublicVirtualInterface": {
|
||||
output: true,
|
||||
},
|
||||
"AssociateConnectionWithLag": {
|
||||
output: true,
|
||||
},
|
||||
"AssociateHostedConnection": {
|
||||
output: true,
|
||||
},
|
||||
"AssociateVirtualInterface": {
|
||||
output: true,
|
||||
},
|
||||
"CreateConnection": {
|
||||
output: true,
|
||||
},
|
||||
"CreateInterconnect": {
|
||||
output: true,
|
||||
},
|
||||
"CreateLag": {
|
||||
output: true,
|
||||
},
|
||||
"CreatePrivateVirtualInterface": {
|
||||
output: true,
|
||||
},
|
||||
"CreatePublicVirtualInterface": {
|
||||
output: true,
|
||||
},
|
||||
"DeleteConnection": {
|
||||
output: true,
|
||||
},
|
||||
"DeleteLag": {
|
||||
output: true,
|
||||
},
|
||||
"DescribeConnections": {
|
||||
output: true,
|
||||
},
|
||||
"DescribeConnectionsOnInterconnect": {
|
||||
output: true,
|
||||
},
|
||||
"DescribeHostedConnections": {
|
||||
output: true,
|
||||
},
|
||||
"DescribeLoa": {
|
||||
output: true,
|
||||
},
|
||||
"DisassociateConnectionFromLag": {
|
||||
output: true,
|
||||
},
|
||||
"UpdateLag": {
|
||||
output: true,
|
||||
},
|
||||
},
|
||||
"EC2": {
|
||||
"AttachVolume": {
|
||||
output: true,
|
||||
},
|
||||
"CreateSnapshot": {
|
||||
output: true,
|
||||
},
|
||||
"CreateVolume": {
|
||||
output: true,
|
||||
},
|
||||
"DetachVolume": {
|
||||
output: true,
|
||||
},
|
||||
"RunInstances": {
|
||||
output: true,
|
||||
},
|
||||
},
|
||||
"EFS": {
|
||||
"CreateFileSystem": {
|
||||
output: true,
|
||||
},
|
||||
"CreateMountTarget": {
|
||||
output: true,
|
||||
},
|
||||
},
|
||||
"ElastiCache": {
|
||||
"AddTagsToResource": {
|
||||
output: true,
|
||||
},
|
||||
"ListTagsForResource": {
|
||||
output: true,
|
||||
},
|
||||
"ModifyCacheParameterGroup": {
|
||||
output: true,
|
||||
},
|
||||
"RemoveTagsFromResource": {
|
||||
output: true,
|
||||
},
|
||||
"ResetCacheParameterGroup": {
|
||||
output: true,
|
||||
},
|
||||
},
|
||||
"ElasticBeanstalk": {
|
||||
"ComposeEnvironments": {
|
||||
output: true,
|
||||
},
|
||||
"CreateApplication": {
|
||||
output: true,
|
||||
},
|
||||
"CreateApplicationVersion": {
|
||||
output: true,
|
||||
},
|
||||
"CreateConfigurationTemplate": {
|
||||
output: true,
|
||||
},
|
||||
"CreateEnvironment": {
|
||||
output: true,
|
||||
},
|
||||
"DescribeEnvironments": {
|
||||
output: true,
|
||||
},
|
||||
"TerminateEnvironment": {
|
||||
output: true,
|
||||
},
|
||||
"UpdateApplication": {
|
||||
output: true,
|
||||
},
|
||||
"UpdateApplicationVersion": {
|
||||
output: true,
|
||||
},
|
||||
"UpdateConfigurationTemplate": {
|
||||
output: true,
|
||||
},
|
||||
"UpdateEnvironment": {
|
||||
output: true,
|
||||
},
|
||||
},
|
||||
"Glacier": {
|
||||
"DescribeJob": {
|
||||
output: true,
|
||||
},
|
||||
"UploadArchive": {
|
||||
output: true,
|
||||
},
|
||||
"CompleteMultipartUpload": {
|
||||
output: true,
|
||||
},
|
||||
},
|
||||
"IAM": {
|
||||
"GetContextKeysForCustomPolicy": {
|
||||
output: true,
|
||||
},
|
||||
"GetContextKeysForPrincipalPolicy": {
|
||||
output: true,
|
||||
},
|
||||
"SimulateCustomPolicy": {
|
||||
output: true,
|
||||
},
|
||||
"SimulatePrincipalPolicy": {
|
||||
output: true,
|
||||
},
|
||||
},
|
||||
"Kinesis": {
|
||||
"DisableEnhancedMonitoring": {
|
||||
output: true,
|
||||
},
|
||||
"EnableEnhancedMonitoring": {
|
||||
output: true,
|
||||
},
|
||||
},
|
||||
"KMS": {
|
||||
"ListGrants": {
|
||||
output: true,
|
||||
},
|
||||
"ListRetirableGrants": {
|
||||
output: true,
|
||||
},
|
||||
},
|
||||
"Lambda": {
|
||||
"CreateAlias": {
|
||||
output: true,
|
||||
},
|
||||
"CreateEventSourceMapping": {
|
||||
output: true,
|
||||
},
|
||||
"CreateFunction": {
|
||||
output: true,
|
||||
},
|
||||
"DeleteEventSourceMapping": {
|
||||
output: true,
|
||||
},
|
||||
"GetAlias": {
|
||||
output: true,
|
||||
},
|
||||
"GetEventSourceMapping": {
|
||||
output: true,
|
||||
},
|
||||
"GetFunctionConfiguration": {
|
||||
output: true,
|
||||
},
|
||||
"PublishVersion": {
|
||||
output: true,
|
||||
},
|
||||
"UpdateAlias": {
|
||||
output: true,
|
||||
},
|
||||
"UpdateEventSourceMapping": {
|
||||
output: true,
|
||||
},
|
||||
"UpdateFunctionCode": {
|
||||
output: true,
|
||||
},
|
||||
"UpdateFunctionConfiguration": {
|
||||
output: true,
|
||||
},
|
||||
},
|
||||
"RDS": {
|
||||
"ModifyDBClusterParameterGroup": {
|
||||
output: true,
|
||||
},
|
||||
"ModifyDBParameterGroup": {
|
||||
output: true,
|
||||
},
|
||||
"ResetDBClusterParameterGroup": {
|
||||
output: true,
|
||||
},
|
||||
"ResetDBParameterGroup": {
|
||||
output: true,
|
||||
},
|
||||
},
|
||||
"Redshift": {
|
||||
"DescribeLoggingStatus": {
|
||||
output: true,
|
||||
},
|
||||
"DisableLogging": {
|
||||
output: true,
|
||||
},
|
||||
"EnableLogging": {
|
||||
output: true,
|
||||
},
|
||||
"ModifyClusterParameterGroup": {
|
||||
output: true,
|
||||
},
|
||||
"ResetClusterParameterGroup": {
|
||||
output: true,
|
||||
},
|
||||
},
|
||||
"S3": {
|
||||
"GetBucketNotification": {
|
||||
input: true,
|
||||
output: true,
|
||||
},
|
||||
"GetBucketNotificationConfiguration": {
|
||||
input: true,
|
||||
output: true,
|
||||
},
|
||||
},
|
||||
"SWF": {
|
||||
"CountClosedWorkflowExecutions": {
|
||||
output: true,
|
||||
},
|
||||
"CountOpenWorkflowExecutions": {
|
||||
output: true,
|
||||
},
|
||||
"CountPendingActivityTasks": {
|
||||
output: true,
|
||||
},
|
||||
"CountPendingDecisionTasks": {
|
||||
output: true,
|
||||
},
|
||||
"ListClosedWorkflowExecutions": {
|
||||
output: true,
|
||||
},
|
||||
"ListOpenWorkflowExecutions": {
|
||||
output: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
+3
-3
@@ -4,8 +4,6 @@ package api
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestResolvedReferences(t *testing.T) {
|
||||
@@ -28,5 +26,7 @@ func TestResolvedReferences(t *testing.T) {
|
||||
}`
|
||||
a := API{}
|
||||
a.AttachString(json)
|
||||
assert.Equal(t, len(a.Shapes["OtherTest"].refs), 2)
|
||||
if len(a.Shapes["OtherTest"].refs) != 2 {
|
||||
t.Errorf("Expected %d, but received %d", 2, len(a.Shapes["OtherTest"].refs))
|
||||
}
|
||||
}
|
||||
|
||||
+17
-14
@@ -72,19 +72,18 @@ const op{{ .ExportedName }} = "{{ .Name }}"
|
||||
|
||||
// {{ .ExportedName }}Request generates a "aws/request.Request" representing the
|
||||
// client's request for the {{ .ExportedName }} operation. The "output" return
|
||||
// value can be used to capture response data after the request's "Send" method
|
||||
// is called.
|
||||
// value will be populated with the request's response once the request complets
|
||||
// successfuly.
|
||||
//
|
||||
// See {{ .ExportedName }} for usage and error information.
|
||||
// Use "Send" method on the returned Request to send the API call to the service.
|
||||
// the "output" return value is not valid until after Send returns without error.
|
||||
//
|
||||
// Creating a request object using this method should be used when you want to inject
|
||||
// custom logic into the request's lifecycle using a custom handler, or if you want to
|
||||
// access properties on the request object before or after sending the request. If
|
||||
// you just want the service response, call the {{ .ExportedName }} method directly
|
||||
// instead.
|
||||
// See {{ .ExportedName }} for more information on using the {{ .ExportedName }}
|
||||
// API call, and error handling.
|
||||
//
|
||||
// This method is useful when you want to inject custom logic or configuration
|
||||
// into the SDK's request lifecycle. Such as custom headers, or retry logic.
|
||||
//
|
||||
// Note: You must call the "Send" method on the returned request object in order
|
||||
// to execute the request.
|
||||
//
|
||||
// // Example sending a request using the {{ .ExportedName }}Request method.
|
||||
// req, resp := client.{{ .ExportedName }}Request(params)
|
||||
@@ -93,7 +92,7 @@ const op{{ .ExportedName }} = "{{ .Name }}"
|
||||
// if err == nil { // resp is now filled
|
||||
// fmt.Println(resp)
|
||||
// }
|
||||
{{ $crosslinkURL := GetCrosslinkURL $.API.BaseCrosslinkURL $.API.APIName $.API.Metadata.UID $.ExportedName -}}
|
||||
{{ $crosslinkURL := GetCrosslinkURL $.API.BaseCrosslinkURL $.API.Metadata.UID $.ExportedName -}}
|
||||
{{ if ne $crosslinkURL "" -}}
|
||||
//
|
||||
// Please also see {{ $crosslinkURL }}
|
||||
@@ -151,7 +150,7 @@ func (c *{{ .API.StructName }}) {{ .ExportedName }}Request(` +
|
||||
//
|
||||
{{ end -}}
|
||||
{{ end -}}
|
||||
{{ $crosslinkURL := GetCrosslinkURL $.API.BaseCrosslinkURL $.API.APIName $.API.Metadata.UID $.ExportedName -}}
|
||||
{{ $crosslinkURL := GetCrosslinkURL $.API.BaseCrosslinkURL $.API.Metadata.UID $.ExportedName -}}
|
||||
{{ if ne $crosslinkURL "" -}}
|
||||
// Please also see {{ $crosslinkURL }}
|
||||
{{ end -}}
|
||||
@@ -216,8 +215,12 @@ func (c *{{ .API.StructName }}) {{ .ExportedName }}PagesWithContext(` +
|
||||
`opts ...request.Option) error {
|
||||
p := request.Pagination {
|
||||
NewRequest: func() (*request.Request, error) {
|
||||
inCpy := *input
|
||||
req, _ := c.{{ .ExportedName }}Request(&inCpy)
|
||||
var inCpy {{ .InputRef.GoType }}
|
||||
if input != nil {
|
||||
tmp := *input
|
||||
inCpy = &tmp
|
||||
}
|
||||
req, _ := c.{{ .ExportedName }}Request(inCpy)
|
||||
req.SetContext(ctx)
|
||||
req.ApplyOptions(opts...)
|
||||
return req, nil
|
||||
|
||||
+15
-5
@@ -121,18 +121,28 @@ func (r *referenceResolver) resolveShape(shape *Shape) {
|
||||
// exportable variant. The shapes are also updated to include notations
|
||||
// if they are Input or Outputs.
|
||||
func (a *API) renameToplevelShapes() {
|
||||
for _, v := range a.Operations {
|
||||
for _, v := range a.OperationList() {
|
||||
if v.HasInput() {
|
||||
name := v.ExportedName + "Input"
|
||||
switch n := len(v.InputRef.Shape.refs); {
|
||||
case n == 1 && a.Shapes[name] == nil:
|
||||
switch {
|
||||
case a.Shapes[name] == nil:
|
||||
if service, ok := shamelist[a.name]; ok {
|
||||
if check, ok := service[v.Name]; ok && check.input {
|
||||
break
|
||||
}
|
||||
}
|
||||
v.InputRef.Shape.Rename(name)
|
||||
}
|
||||
}
|
||||
if v.HasOutput() {
|
||||
name := v.ExportedName + "Output"
|
||||
switch n := len(v.OutputRef.Shape.refs); {
|
||||
case n == 1 && a.Shapes[name] == nil:
|
||||
switch {
|
||||
case a.Shapes[name] == nil:
|
||||
if service, ok := shamelist[a.name]; ok {
|
||||
if check, ok := service[v.Name]; ok && check.output {
|
||||
break
|
||||
}
|
||||
}
|
||||
v.OutputRef.Shape.Rename(name)
|
||||
}
|
||||
}
|
||||
|
||||
+169
@@ -0,0 +1,169 @@
|
||||
// +build 1.6,codegen
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestUniqueInputAndOutputs(t *testing.T) {
|
||||
shamelist["FooService"] = map[string]struct {
|
||||
input bool
|
||||
output bool
|
||||
}{}
|
||||
v := shamelist["FooService"]["OpOutputNoRename"]
|
||||
v.output = true
|
||||
shamelist["FooService"]["OpOutputNoRename"] = v
|
||||
v = shamelist["FooService"]["InputNoRename"]
|
||||
v.input = true
|
||||
shamelist["FooService"]["OpInputNoRename"] = v
|
||||
v = shamelist["FooService"]["BothNoRename"]
|
||||
v.input = true
|
||||
v.output = true
|
||||
shamelist["FooService"]["OpBothNoRename"] = v
|
||||
|
||||
testCases := [][]struct {
|
||||
expectedInput string
|
||||
expectedOutput string
|
||||
operation string
|
||||
input string
|
||||
inputRef string
|
||||
output string
|
||||
outputRef string
|
||||
}{
|
||||
{
|
||||
{
|
||||
expectedInput: "FooOperationInput",
|
||||
expectedOutput: "FooOperationOutput",
|
||||
operation: "FooOperation",
|
||||
input: "FooInputShape",
|
||||
inputRef: "FooInputShapeRef",
|
||||
output: "FooOutputShape",
|
||||
outputRef: "FooOutputShapeRef",
|
||||
},
|
||||
{
|
||||
expectedInput: "BarOperationInput",
|
||||
expectedOutput: "BarOperationOutput",
|
||||
operation: "BarOperation",
|
||||
input: "FooInputShape",
|
||||
inputRef: "FooInputShapeRef",
|
||||
output: "FooOutputShape",
|
||||
outputRef: "FooOutputShapeRef",
|
||||
},
|
||||
},
|
||||
{
|
||||
{
|
||||
expectedInput: "FooOperationInput",
|
||||
expectedOutput: "FooOperationOutput",
|
||||
operation: "FooOperation",
|
||||
input: "FooInputShape",
|
||||
inputRef: "FooInputShapeRef",
|
||||
output: "FooOutputShape",
|
||||
outputRef: "FooOutputShapeRef",
|
||||
},
|
||||
{
|
||||
expectedInput: "OpOutputNoRenameInput",
|
||||
expectedOutput: "OpOutputNoRenameOutputShape",
|
||||
operation: "OpOutputNoRename",
|
||||
input: "OpOutputNoRenameInputShape",
|
||||
inputRef: "OpOutputNoRenameInputRef",
|
||||
output: "OpOutputNoRenameOutputShape",
|
||||
outputRef: "OpOutputNoRenameOutputRef",
|
||||
},
|
||||
},
|
||||
{
|
||||
{
|
||||
expectedInput: "FooOperationInput",
|
||||
expectedOutput: "FooOperationOutput",
|
||||
operation: "FooOperation",
|
||||
input: "FooInputShape",
|
||||
inputRef: "FooInputShapeRef",
|
||||
output: "FooOutputShape",
|
||||
outputRef: "FooOutputShapeRef",
|
||||
},
|
||||
{
|
||||
expectedInput: "OpInputNoRenameInputShape",
|
||||
expectedOutput: "OpInputNoRenameOutput",
|
||||
operation: "OpInputNoRename",
|
||||
input: "OpInputNoRenameInputShape",
|
||||
inputRef: "OpInputNoRenameInputRef",
|
||||
output: "OpInputNoRenameOutputShape",
|
||||
outputRef: "OpInputNoRenameOutputRef",
|
||||
},
|
||||
},
|
||||
{
|
||||
{
|
||||
expectedInput: "FooOperationInput",
|
||||
expectedOutput: "FooOperationOutput",
|
||||
operation: "FooOperation",
|
||||
input: "FooInputShape",
|
||||
inputRef: "FooInputShapeRef",
|
||||
output: "FooOutputShape",
|
||||
outputRef: "FooOutputShapeRef",
|
||||
},
|
||||
{
|
||||
expectedInput: "OpInputNoRenameInputShape",
|
||||
expectedOutput: "OpInputNoRenameOutputShape",
|
||||
operation: "OpBothNoRename",
|
||||
input: "OpInputNoRenameInputShape",
|
||||
inputRef: "OpInputNoRenameInputRef",
|
||||
output: "OpInputNoRenameOutputShape",
|
||||
outputRef: "OpInputNoRenameOutputRef",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range testCases {
|
||||
a := &API{
|
||||
name: "FooService",
|
||||
Operations: map[string]*Operation{},
|
||||
}
|
||||
|
||||
expected := map[string][]string{}
|
||||
a.Shapes = map[string]*Shape{}
|
||||
for _, op := range c {
|
||||
a.Operations[op.operation] = &Operation{
|
||||
ExportedName: op.operation,
|
||||
}
|
||||
a.Operations[op.operation].Name = op.operation
|
||||
a.Operations[op.operation].InputRef = ShapeRef{
|
||||
API: a,
|
||||
ShapeName: op.inputRef,
|
||||
Shape: &Shape{
|
||||
API: a,
|
||||
ShapeName: op.input,
|
||||
},
|
||||
}
|
||||
a.Operations[op.operation].OutputRef = ShapeRef{
|
||||
API: a,
|
||||
ShapeName: op.outputRef,
|
||||
Shape: &Shape{
|
||||
API: a,
|
||||
ShapeName: op.output,
|
||||
},
|
||||
}
|
||||
|
||||
a.Shapes[op.input] = &Shape{
|
||||
ShapeName: op.input,
|
||||
}
|
||||
a.Shapes[op.output] = &Shape{
|
||||
ShapeName: op.output,
|
||||
}
|
||||
|
||||
expected[op.operation] = append(expected[op.operation], op.expectedInput)
|
||||
expected[op.operation] = append(expected[op.operation], op.expectedOutput)
|
||||
}
|
||||
|
||||
a.fixStutterNames()
|
||||
a.renameToplevelShapes()
|
||||
for k, v := range expected {
|
||||
if a.Operations[k].InputRef.Shape.ShapeName != v[0] {
|
||||
t.Errorf("Error %d case: Expected %q, but received %q", k, v[0], a.Operations[k].InputRef.Shape.ShapeName)
|
||||
}
|
||||
if a.Operations[k].OutputRef.Shape.ShapeName != v[1] {
|
||||
t.Errorf("Error %d case: Expected %q, but received %q", k, v[1], a.Operations[k].OutputRef.Shape.ShapeName)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
+64
-16
@@ -33,6 +33,8 @@ type ShapeRef struct {
|
||||
Deprecated bool `json:"deprecated"`
|
||||
|
||||
OrigShapeName string `json:"-"`
|
||||
|
||||
GenerateGetter bool
|
||||
}
|
||||
|
||||
// ErrorInfo represents the error block of a shape's structure
|
||||
@@ -145,6 +147,14 @@ func (s *Shape) GoTypeWithPkgName() string {
|
||||
return goType(s, true)
|
||||
}
|
||||
|
||||
func (s *Shape) GoTypeWithPkgNameElem() string {
|
||||
t := goType(s, true)
|
||||
if strings.HasPrefix(t, "*") {
|
||||
return t[1:]
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
// GenAccessors returns if the shape's reference should have setters generated.
|
||||
func (s *ShapeRef) UseIndirection() bool {
|
||||
switch s.Shape.Type {
|
||||
@@ -244,11 +254,11 @@ func goType(s *Shape, withPkgName bool) string {
|
||||
}
|
||||
return "*" + s.ShapeName
|
||||
case "map":
|
||||
return "map[string]" + s.ValueRef.GoType()
|
||||
return "map[string]" + goType(s.ValueRef.Shape, withPkgName)
|
||||
case "jsonvalue":
|
||||
return "aws.JSONValue"
|
||||
case "list":
|
||||
return "[]" + s.MemberRef.GoType()
|
||||
return "[]" + goType(s.MemberRef.Shape, withPkgName)
|
||||
case "boolean":
|
||||
return "*bool"
|
||||
case "string", "character":
|
||||
@@ -392,16 +402,18 @@ func (ref *ShapeRef) GoTags(toplevel bool, isRequired bool) string {
|
||||
if ref.Shape.Payload != "" {
|
||||
tags = append(tags, ShapeTag{"payload", ref.Shape.Payload})
|
||||
}
|
||||
if ref.XMLNamespace.Prefix != "" {
|
||||
tags = append(tags, ShapeTag{"xmlPrefix", ref.XMLNamespace.Prefix})
|
||||
} else if ref.Shape.XMLNamespace.Prefix != "" {
|
||||
tags = append(tags, ShapeTag{"xmlPrefix", ref.Shape.XMLNamespace.Prefix})
|
||||
}
|
||||
if ref.XMLNamespace.URI != "" {
|
||||
tags = append(tags, ShapeTag{"xmlURI", ref.XMLNamespace.URI})
|
||||
} else if ref.Shape.XMLNamespace.URI != "" {
|
||||
tags = append(tags, ShapeTag{"xmlURI", ref.Shape.XMLNamespace.URI})
|
||||
}
|
||||
}
|
||||
|
||||
if ref.XMLNamespace.Prefix != "" {
|
||||
tags = append(tags, ShapeTag{"xmlPrefix", ref.XMLNamespace.Prefix})
|
||||
} else if ref.Shape.XMLNamespace.Prefix != "" {
|
||||
tags = append(tags, ShapeTag{"xmlPrefix", ref.Shape.XMLNamespace.Prefix})
|
||||
}
|
||||
|
||||
if ref.XMLNamespace.URI != "" {
|
||||
tags = append(tags, ShapeTag{"xmlURI", ref.XMLNamespace.URI})
|
||||
} else if ref.Shape.XMLNamespace.URI != "" {
|
||||
tags = append(tags, ShapeTag{"xmlURI", ref.Shape.XMLNamespace.URI})
|
||||
}
|
||||
|
||||
if ref.IdempotencyToken || ref.Shape.IdempotencyToken {
|
||||
@@ -505,12 +517,12 @@ var structShapeTmpl = template.Must(template.New("StructShape").Funcs(template.F
|
||||
}).Parse(`
|
||||
{{ .Docstring }}
|
||||
{{ if ne $.OrigShapeName "" -}}
|
||||
{{ $crosslinkURL := GetCrosslinkURL $.API.BaseCrosslinkURL $.API.APIName $.API.Metadata.UID $.OrigShapeName -}}
|
||||
{{ $crosslinkURL := GetCrosslinkURL $.API.BaseCrosslinkURL $.API.Metadata.UID $.OrigShapeName -}}
|
||||
{{ if ne $crosslinkURL "" -}}
|
||||
// Please also see {{ $crosslinkURL }}
|
||||
{{ end -}}
|
||||
{{ else -}}
|
||||
{{ $crosslinkURL := GetCrosslinkURL $.API.BaseCrosslinkURL $.API.APIName $.API.Metadata.UID $.ShapeName -}}
|
||||
{{ $crosslinkURL := GetCrosslinkURL $.API.BaseCrosslinkURL $.API.Metadata.UID $.ShapeName -}}
|
||||
{{ if ne $crosslinkURL "" -}}
|
||||
// Please also see {{ $crosslinkURL }}
|
||||
{{ end -}}
|
||||
@@ -521,14 +533,23 @@ type {{ .ShapeName }} struct {
|
||||
|
||||
{{ range $_, $name := $context.MemberNames -}}
|
||||
{{ $elem := index $context.MemberRefs $name -}}
|
||||
{{ $isBlob := $context.WillRefBeBase64Encoded $name -}}
|
||||
{{ $isRequired := $context.IsRequired $name -}}
|
||||
{{ $doc := $elem.Docstring -}}
|
||||
|
||||
{{ $doc }}
|
||||
{{ if $isRequired -}}
|
||||
{{ if $doc -}}
|
||||
{{ $doc }}
|
||||
{{ end -}}
|
||||
{{ if $isBlob -}}
|
||||
{{ if $doc -}}
|
||||
//
|
||||
{{ end -}}
|
||||
// {{ $name }} is automatically base64 encoded/decoded by the SDK.
|
||||
{{ end -}}
|
||||
{{ if $isRequired -}}
|
||||
{{ if or $doc $isBlob -}}
|
||||
//
|
||||
{{ end -}}
|
||||
// {{ $name }} is a required field
|
||||
{{ end -}}
|
||||
{{ $name }} {{ $context.GoStructType $name $elem }} {{ $elem.GoTags false $isRequired }}
|
||||
@@ -561,6 +582,19 @@ func (s *{{ $builderShapeName }}) Set{{ $name }}(v {{ $context.GoStructValueType
|
||||
return s
|
||||
}
|
||||
|
||||
{{ if $elem.GenerateGetter -}}
|
||||
func (s *{{ $builderShapeName }}) get{{ $name }}() (v {{ $context.GoStructValueType $name $elem }}) {
|
||||
{{ if $elem.UseIndirection -}}
|
||||
if s.{{ $name }} == nil {
|
||||
return v
|
||||
}
|
||||
return *s.{{ $name }}
|
||||
{{ else -}}
|
||||
return s.{{ $name }}
|
||||
{{ end -}}
|
||||
}
|
||||
{{- end }}
|
||||
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
`))
|
||||
@@ -634,3 +668,17 @@ func (s *Shape) removeRef(ref *ShapeRef) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Shape) WillRefBeBase64Encoded(refName string) bool {
|
||||
payloadRefName := s.Payload
|
||||
if payloadRefName == refName {
|
||||
return false
|
||||
}
|
||||
|
||||
ref, ok := s.MemberRefs[refName]
|
||||
if !ok {
|
||||
panic(fmt.Sprintf("shape %s does not contain %q refName", s.ShapeName, refName))
|
||||
}
|
||||
|
||||
return ref.Shape.Type == "blob"
|
||||
}
|
||||
|
||||
+6
-3
@@ -6,7 +6,6 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/private/model/api"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestShapeTagJoin(t *testing.T) {
|
||||
@@ -20,6 +19,10 @@ func TestShapeTagJoin(t *testing.T) {
|
||||
|
||||
o := s.Join(" ")
|
||||
o2 := s.String()
|
||||
assert.Equal(t, expected, o)
|
||||
assert.Equal(t, expected, o2)
|
||||
if expected != o {
|
||||
t.Errorf("Expected %s, but received %s", expected, o)
|
||||
}
|
||||
if expected != o2 {
|
||||
t.Errorf("Expected %s, but received %s", expected, o2)
|
||||
}
|
||||
}
|
||||
|
||||
+7
-2
@@ -113,7 +113,7 @@ var waiterTmpls = template.Must(template.New("waiterTmpls").Funcs(
|
||||
{{ 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
|
||||
// If the condition is not met 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)
|
||||
@@ -144,7 +144,12 @@ func (c *{{ .Operation.API.StructName }}) WaitUntil{{ .Name }}WithContext(` +
|
||||
},
|
||||
Logger: c.Config.Logger,
|
||||
NewRequest: func(opts []request.Option) (*request.Request, error) {
|
||||
req, _ := c.{{ .OperationName }}Request(input)
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user