Merge branch 'master' into mssql_datasource

This commit is contained in:
Marcus Efraimsson
2018-03-13 16:03:02 +01:00
2626 changed files with 339802 additions and 172728 deletions
-5
View File
@@ -1,5 +0,0 @@
TAGS
tags
.*.swp
tomlcheck/tomlcheck
toml.test
-12
View File
@@ -1,12 +0,0 @@
language: go
go:
- 1.1
- 1.2
- tip
install:
- go install ./...
- go get github.com/BurntSushi/toml-test
script:
- export PATH="$PATH:$HOME/gopath/bin"
- make test
-3
View File
@@ -1,3 +0,0 @@
Compatible with TOML version
[v0.2.0](https://github.com/mojombo/toml/blob/master/versions/toml-v0.2.0.md)
-19
View File
@@ -1,19 +0,0 @@
install:
go install ./...
test: install
go test -v
toml-test toml-test-decoder
toml-test -encoder toml-test-encoder
fmt:
gofmt -w *.go */*.go
colcheck *.go */*.go
tags:
find ./ -name '*.go' -print0 | xargs -0 gotags > TAGS
push:
git push origin master
git push github master
-220
View File
@@ -1,220 +0,0 @@
## TOML parser and encoder for Go with reflection
TOML stands for Tom's Obvious, Minimal Language. This Go package provides a
reflection interface similar to Go's standard library `json` and `xml`
packages. This package also supports the `encoding.TextUnmarshaler` and
`encoding.TextMarshaler` interfaces so that you can define custom data
representations. (There is an example of this below.)
Spec: https://github.com/mojombo/toml
Compatible with TOML version
[v0.2.0](https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.2.0.md)
Documentation: http://godoc.org/github.com/BurntSushi/toml
Installation:
```bash
go get github.com/BurntSushi/toml
```
Try the toml validator:
```bash
go get github.com/BurntSushi/toml/cmd/tomlv
tomlv some-toml-file.toml
```
[![Build status](https://api.travis-ci.org/BurntSushi/toml.png)](https://travis-ci.org/BurntSushi/toml)
### Testing
This package passes all tests in
[toml-test](https://github.com/BurntSushi/toml-test) for both the decoder
and the encoder.
### Examples
This package works similarly to how the Go standard library handles `XML`
and `JSON`. Namely, data is loaded into Go values via reflection.
For the simplest example, consider some TOML file as just a list of keys
and values:
```toml
Age = 25
Cats = [ "Cauchy", "Plato" ]
Pi = 3.14
Perfection = [ 6, 28, 496, 8128 ]
DOB = 1987-07-05T05:45:00Z
```
Which could be defined in Go as:
```go
type Config struct {
Age int
Cats []string
Pi float64
Perfection []int
DOB time.Time // requires `import time`
}
```
And then decoded with:
```go
var conf Config
if _, err := toml.Decode(tomlData, &conf); err != nil {
// handle error
}
```
You can also use struct tags if your struct field name doesn't map to a TOML
key value directly:
```toml
some_key_NAME = "wat"
```
```go
type TOML struct {
ObscureKey string `toml:"some_key_NAME"`
}
```
### Using the `encoding.TextUnmarshaler` interface
Here's an example that automatically parses duration strings into
`time.Duration` values:
```toml
[[song]]
name = "Thunder Road"
duration = "4m49s"
[[song]]
name = "Stairway to Heaven"
duration = "8m03s"
```
Which can be decoded with:
```go
type song struct {
Name string
Duration duration
}
type songs struct {
Song []song
}
var favorites songs
if _, err := toml.Decode(blob, &favorites); err != nil {
log.Fatal(err)
}
for _, s := range favorites.Song {
fmt.Printf("%s (%s)\n", s.Name, s.Duration)
}
```
And you'll also need a `duration` type that satisfies the
`encoding.TextUnmarshaler` interface:
```go
type duration struct {
time.Duration
}
func (d *duration) UnmarshalText(text []byte) error {
var err error
d.Duration, err = time.ParseDuration(string(text))
return err
}
```
### More complex usage
Here's an example of how to load the example from the official spec page:
```toml
# This is a TOML document. Boom.
title = "TOML Example"
[owner]
name = "Tom Preston-Werner"
organization = "GitHub"
bio = "GitHub Cofounder & CEO\nLikes tater tots and beer."
dob = 1979-05-27T07:32:00Z # First class dates? Why not?
[database]
server = "192.168.1.1"
ports = [ 8001, 8001, 8002 ]
connection_max = 5000
enabled = true
[servers]
# You can indent as you please. Tabs or spaces. TOML don't care.
[servers.alpha]
ip = "10.0.0.1"
dc = "eqdc10"
[servers.beta]
ip = "10.0.0.2"
dc = "eqdc10"
[clients]
data = [ ["gamma", "delta"], [1, 2] ] # just an update to make sure parsers support it
# Line breaks are OK when inside arrays
hosts = [
"alpha",
"omega"
]
```
And the corresponding Go types are:
```go
type tomlConfig struct {
Title string
Owner ownerInfo
DB database `toml:"database"`
Servers map[string]server
Clients clients
}
type ownerInfo struct {
Name string
Org string `toml:"organization"`
Bio string
DOB time.Time
}
type database struct {
Server string
Ports []int
ConnMax int `toml:"connection_max"`
Enabled bool
}
type server struct {
IP string
DC string
}
type clients struct {
Data [][]interface{}
Hosts []string
}
```
Note that a case insensitive match will be tried if an exact match can't be
found.
A working example of the above can be found in `_examples/example.{go,toml}`.
-14
View File
@@ -1,14 +0,0 @@
# Implements the TOML test suite interface
This is an implementation of the interface expected by
[toml-test](https://github.com/BurntSushi/toml-test) for my
[toml parser written in Go](https://github.com/BurntSushi/toml).
In particular, it maps TOML data on `stdin` to a JSON format on `stdout`.
Compatible with TOML version
[v0.2.0](https://github.com/mojombo/toml/blob/master/versions/toml-v0.2.0.md)
Compatible with `toml-test` version
[v0.2.0](https://github.com/BurntSushi/toml-test/tree/v0.2.0)
-90
View File
@@ -1,90 +0,0 @@
// Command toml-test-decoder satisfies the toml-test interface for testing
// TOML decoders. Namely, it accepts TOML on stdin and outputs JSON on stdout.
package main
import (
"encoding/json"
"flag"
"fmt"
"log"
"os"
"path"
"time"
"github.com/BurntSushi/toml"
)
func init() {
log.SetFlags(0)
flag.Usage = usage
flag.Parse()
}
func usage() {
log.Printf("Usage: %s < toml-file\n", path.Base(os.Args[0]))
flag.PrintDefaults()
os.Exit(1)
}
func main() {
if flag.NArg() != 0 {
flag.Usage()
}
var tmp interface{}
if _, err := toml.DecodeReader(os.Stdin, &tmp); err != nil {
log.Fatalf("Error decoding TOML: %s", err)
}
typedTmp := translate(tmp)
if err := json.NewEncoder(os.Stdout).Encode(typedTmp); err != nil {
log.Fatalf("Error encoding JSON: %s", err)
}
}
func translate(tomlData interface{}) interface{} {
switch orig := tomlData.(type) {
case map[string]interface{}:
typed := make(map[string]interface{}, len(orig))
for k, v := range orig {
typed[k] = translate(v)
}
return typed
case []map[string]interface{}:
typed := make([]map[string]interface{}, len(orig))
for i, v := range orig {
typed[i] = translate(v).(map[string]interface{})
}
return typed
case []interface{}:
typed := make([]interface{}, len(orig))
for i, v := range orig {
typed[i] = translate(v)
}
// We don't really need to tag arrays, but let's be future proof.
// (If TOML ever supports tuples, we'll need this.)
return tag("array", typed)
case time.Time:
return tag("datetime", orig.Format("2006-01-02T15:04:05Z"))
case bool:
return tag("bool", fmt.Sprintf("%v", orig))
case int64:
return tag("integer", fmt.Sprintf("%d", orig))
case float64:
return tag("float", fmt.Sprintf("%v", orig))
case string:
return tag("string", orig)
}
panic(fmt.Sprintf("Unknown type: %T", tomlData))
}
func tag(typeName string, data interface{}) map[string]interface{} {
return map[string]interface{}{
"type": typeName,
"value": data,
}
}
-14
View File
@@ -1,14 +0,0 @@
# Implements the TOML test suite interface for TOML encoders
This is an implementation of the interface expected by
[toml-test](https://github.com/BurntSushi/toml-test) for the
[TOML encoder](https://github.com/BurntSushi/toml).
In particular, it maps JSON data on `stdin` to a TOML format on `stdout`.
Compatible with TOML version
[v0.2.0](https://github.com/mojombo/toml/blob/master/versions/toml-v0.2.0.md)
Compatible with `toml-test` version
[v0.2.0](https://github.com/BurntSushi/toml-test/tree/v0.2.0)
-131
View File
@@ -1,131 +0,0 @@
// Command toml-test-encoder satisfies the toml-test interface for testing
// TOML encoders. Namely, it accepts JSON on stdin and outputs TOML on stdout.
package main
import (
"encoding/json"
"flag"
"log"
"os"
"path"
"strconv"
"time"
"github.com/BurntSushi/toml"
)
func init() {
log.SetFlags(0)
flag.Usage = usage
flag.Parse()
}
func usage() {
log.Printf("Usage: %s < json-file\n", path.Base(os.Args[0]))
flag.PrintDefaults()
os.Exit(1)
}
func main() {
if flag.NArg() != 0 {
flag.Usage()
}
var tmp interface{}
if err := json.NewDecoder(os.Stdin).Decode(&tmp); err != nil {
log.Fatalf("Error decoding JSON: %s", err)
}
tomlData := translate(tmp)
if err := toml.NewEncoder(os.Stdout).Encode(tomlData); err != nil {
log.Fatalf("Error encoding TOML: %s", err)
}
}
func translate(typedJson interface{}) interface{} {
switch v := typedJson.(type) {
case map[string]interface{}:
if len(v) == 2 && in("type", v) && in("value", v) {
return untag(v)
}
m := make(map[string]interface{}, len(v))
for k, v2 := range v {
m[k] = translate(v2)
}
return m
case []interface{}:
tabArray := make([]map[string]interface{}, len(v))
for i := range v {
if m, ok := translate(v[i]).(map[string]interface{}); ok {
tabArray[i] = m
} else {
log.Fatalf("JSON arrays may only contain objects. This " +
"corresponds to only tables being allowed in " +
"TOML table arrays.")
}
}
return tabArray
}
log.Fatalf("Unrecognized JSON format '%T'.", typedJson)
panic("unreachable")
}
func untag(typed map[string]interface{}) interface{} {
t := typed["type"].(string)
v := typed["value"]
switch t {
case "string":
return v.(string)
case "integer":
v := v.(string)
n, err := strconv.Atoi(v)
if err != nil {
log.Fatalf("Could not parse '%s' as integer: %s", v, err)
}
return n
case "float":
v := v.(string)
f, err := strconv.ParseFloat(v, 64)
if err != nil {
log.Fatalf("Could not parse '%s' as float64: %s", v, err)
}
return f
case "datetime":
v := v.(string)
t, err := time.Parse("2006-01-02T15:04:05Z", v)
if err != nil {
log.Fatalf("Could not parse '%s' as a datetime: %s", v, err)
}
return t
case "bool":
v := v.(string)
switch v {
case "true":
return true
case "false":
return false
}
log.Fatalf("Could not parse '%s' as a boolean.", v)
case "array":
v := v.([]interface{})
array := make([]interface{}, len(v))
for i := range v {
if m, ok := v[i].(map[string]interface{}); ok {
array[i] = untag(m)
} else {
log.Fatalf("Arrays may only contain other arrays or "+
"primitive values, but found a '%T'.", m)
}
}
return array
}
log.Fatalf("Unrecognized tag type '%s'.", t)
panic("unreachable")
}
func in(key string, m map[string]interface{}) bool {
_, ok := m[key]
return ok
}
-22
View File
@@ -1,22 +0,0 @@
# TOML Validator
If Go is installed, it's simple to try it out:
```bash
go get github.com/BurntSushi/toml/cmd/tomlv
tomlv some-toml-file.toml
```
You can see the types of every key in a TOML file with:
```bash
tomlv -types some-toml-file.toml
```
At the moment, only one error message is reported at a time. Error messages
include line numbers. No output means that the files given are valid TOML, or
there is a bug in `tomlv`.
Compatible with TOML version
[v0.1.0](https://github.com/mojombo/toml/blob/master/versions/toml-v0.1.0.md)
-61
View File
@@ -1,61 +0,0 @@
// Command tomlv validates TOML documents and prints each key's type.
package main
import (
"flag"
"fmt"
"log"
"os"
"path"
"strings"
"text/tabwriter"
"github.com/BurntSushi/toml"
)
var (
flagTypes = false
)
func init() {
log.SetFlags(0)
flag.BoolVar(&flagTypes, "types", flagTypes,
"When set, the types of every defined key will be shown.")
flag.Usage = usage
flag.Parse()
}
func usage() {
log.Printf("Usage: %s toml-file [ toml-file ... ]\n",
path.Base(os.Args[0]))
flag.PrintDefaults()
os.Exit(1)
}
func main() {
if flag.NArg() < 1 {
flag.Usage()
}
for _, f := range flag.Args() {
var tmp interface{}
md, err := toml.DecodeFile(f, &tmp)
if err != nil {
log.Fatalf("Error in '%s': %s", f, err)
}
if flagTypes {
printTypes(md)
}
}
}
func printTypes(md toml.MetaData) {
tabw := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
for _, key := range md.Keys() {
fmt.Fprintf(tabw, "%s%s\t%s\n",
strings.Repeat(" ", len(key)-1), key, md.Type(key...))
}
tabw.Flush()
}
+42 -25
View File
@@ -10,7 +10,9 @@ import (
"time"
)
var e = fmt.Errorf
func e(format string, args ...interface{}) error {
return fmt.Errorf("toml: "+format, args...)
}
// Unmarshaler is the interface implemented by objects that can unmarshal a
// TOML description of themselves.
@@ -103,6 +105,13 @@ func (md *MetaData) PrimitiveDecode(primValue Primitive, v interface{}) error {
// This decoder will not handle cyclic types. If a cyclic type is passed,
// `Decode` will not terminate.
func Decode(data string, v interface{}) (MetaData, error) {
rv := reflect.ValueOf(v)
if rv.Kind() != reflect.Ptr {
return MetaData{}, e("Decode of non-pointer %s", reflect.TypeOf(v))
}
if rv.IsNil() {
return MetaData{}, e("Decode of nil %s", reflect.TypeOf(v))
}
p, err := parse(data)
if err != nil {
return MetaData{}, err
@@ -111,7 +120,7 @@ func Decode(data string, v interface{}) (MetaData, error) {
p.mapping, p.types, p.ordered,
make(map[string]bool, len(p.ordered)), nil,
}
return md, md.unify(p.mapping, rvalue(v))
return md, md.unify(p.mapping, indirect(rv))
}
// DecodeFile is just like Decode, except it will automatically read the
@@ -211,7 +220,7 @@ func (md *MetaData) unify(data interface{}, rv reflect.Value) error {
case reflect.Interface:
// we only support empty interfaces.
if rv.NumMethod() > 0 {
return e("Unsupported type '%s'.", rv.Kind())
return e("unsupported type %s", rv.Type())
}
return md.unifyAnything(data, rv)
case reflect.Float32:
@@ -219,13 +228,17 @@ func (md *MetaData) unify(data interface{}, rv reflect.Value) error {
case reflect.Float64:
return md.unifyFloat64(data, rv)
}
return e("Unsupported type '%s'.", rv.Kind())
return e("unsupported type %s", rv.Kind())
}
func (md *MetaData) unifyStruct(mapping interface{}, rv reflect.Value) error {
tmap, ok := mapping.(map[string]interface{})
if !ok {
return mismatch(rv, "map", mapping)
if mapping == nil {
return nil
}
return e("type mismatch for %s: expected table but found %T",
rv.Type().String(), mapping)
}
for key, datum := range tmap {
@@ -250,14 +263,13 @@ func (md *MetaData) unifyStruct(mapping interface{}, rv reflect.Value) error {
md.decoded[md.context.add(key).String()] = true
md.context = append(md.context, key)
if err := md.unify(datum, subv); err != nil {
return e("Type mismatch for '%s.%s': %s",
rv.Type().String(), f.name, err)
return err
}
md.context = md.context[0 : len(md.context)-1]
} else if f.name != "" {
// Bad user! No soup for you!
return e("Field '%s.%s' is unexported, and therefore cannot "+
"be loaded with reflection.", rv.Type().String(), f.name)
return e("cannot write unexported field %s.%s",
rv.Type().String(), f.name)
}
}
}
@@ -267,6 +279,9 @@ func (md *MetaData) unifyStruct(mapping interface{}, rv reflect.Value) error {
func (md *MetaData) unifyMap(mapping interface{}, rv reflect.Value) error {
tmap, ok := mapping.(map[string]interface{})
if !ok {
if tmap == nil {
return nil
}
return badtype("map", mapping)
}
if rv.IsNil() {
@@ -292,6 +307,9 @@ func (md *MetaData) unifyMap(mapping interface{}, rv reflect.Value) error {
func (md *MetaData) unifyArray(data interface{}, rv reflect.Value) error {
datav := reflect.ValueOf(data)
if datav.Kind() != reflect.Slice {
if !datav.IsValid() {
return nil
}
return badtype("slice", data)
}
sliceLen := datav.Len()
@@ -305,12 +323,16 @@ func (md *MetaData) unifyArray(data interface{}, rv reflect.Value) error {
func (md *MetaData) unifySlice(data interface{}, rv reflect.Value) error {
datav := reflect.ValueOf(data)
if datav.Kind() != reflect.Slice {
if !datav.IsValid() {
return nil
}
return badtype("slice", data)
}
sliceLen := datav.Len()
if rv.IsNil() {
rv.Set(reflect.MakeSlice(rv.Type(), sliceLen, sliceLen))
n := datav.Len()
if rv.IsNil() || rv.Cap() < n {
rv.Set(reflect.MakeSlice(rv.Type(), n, n))
}
rv.SetLen(n)
return md.unifySliceArray(datav, rv)
}
@@ -365,15 +387,15 @@ func (md *MetaData) unifyInt(data interface{}, rv reflect.Value) error {
// No bounds checking necessary.
case reflect.Int8:
if num < math.MinInt8 || num > math.MaxInt8 {
return e("Value '%d' is out of range for int8.", num)
return e("value %d is out of range for int8", num)
}
case reflect.Int16:
if num < math.MinInt16 || num > math.MaxInt16 {
return e("Value '%d' is out of range for int16.", num)
return e("value %d is out of range for int16", num)
}
case reflect.Int32:
if num < math.MinInt32 || num > math.MaxInt32 {
return e("Value '%d' is out of range for int32.", num)
return e("value %d is out of range for int32", num)
}
}
rv.SetInt(num)
@@ -384,15 +406,15 @@ func (md *MetaData) unifyInt(data interface{}, rv reflect.Value) error {
// No bounds checking necessary.
case reflect.Uint8:
if num < 0 || unum > math.MaxUint8 {
return e("Value '%d' is out of range for uint8.", num)
return e("value %d is out of range for uint8", num)
}
case reflect.Uint16:
if num < 0 || unum > math.MaxUint16 {
return e("Value '%d' is out of range for uint16.", num)
return e("value %d is out of range for uint16", num)
}
case reflect.Uint32:
if num < 0 || unum > math.MaxUint32 {
return e("Value '%d' is out of range for uint32.", num)
return e("value %d is out of range for uint32", num)
}
}
rv.SetUint(unum)
@@ -458,7 +480,7 @@ func rvalue(v interface{}) reflect.Value {
// interest to us (like encoding.TextUnmarshaler).
func indirect(v reflect.Value) reflect.Value {
if v.Kind() != reflect.Ptr {
if v.CanAddr() {
if v.CanSet() {
pv := v.Addr()
if _, ok := pv.Interface().(TextUnmarshaler); ok {
return pv
@@ -483,10 +505,5 @@ func isUnifiable(rv reflect.Value) bool {
}
func badtype(expected string, data interface{}) error {
return e("Expected %s but found '%T'.", expected, data)
}
func mismatch(user reflect.Value, expected string, data interface{}) error {
return e("Type mismatch for %s. Expected %s but found '%T'.",
user.Type().String(), expected, data)
return e("cannot load TOML value of type %T into a Go %s", data, expected)
}
+1 -2
View File
@@ -77,9 +77,8 @@ func (k Key) maybeQuoted(i int) string {
}
if quote {
return "\"" + strings.Replace(k[i], "\"", "\\\"", -1) + "\""
} else {
return k[i]
}
return k[i]
}
func (k Key) add(piece string) Key {
-950
View File
@@ -1,950 +0,0 @@
package toml
import (
"fmt"
"log"
"reflect"
"testing"
"time"
)
func init() {
log.SetFlags(0)
}
func TestDecodeSimple(t *testing.T) {
var testSimple = `
age = 250
andrew = "gallant"
kait = "brady"
now = 1987-07-05T05:45:00Z
yesOrNo = true
pi = 3.14
colors = [
["red", "green", "blue"],
["cyan", "magenta", "yellow", "black"],
]
[My.Cats]
plato = "cat 1"
cauchy = "cat 2"
`
type cats struct {
Plato string
Cauchy string
}
type simple struct {
Age int
Colors [][]string
Pi float64
YesOrNo bool
Now time.Time
Andrew string
Kait string
My map[string]cats
}
var val simple
_, err := Decode(testSimple, &val)
if err != nil {
t.Fatal(err)
}
now, err := time.Parse("2006-01-02T15:04:05", "1987-07-05T05:45:00")
if err != nil {
panic(err)
}
var answer = simple{
Age: 250,
Andrew: "gallant",
Kait: "brady",
Now: now,
YesOrNo: true,
Pi: 3.14,
Colors: [][]string{
{"red", "green", "blue"},
{"cyan", "magenta", "yellow", "black"},
},
My: map[string]cats{
"Cats": cats{Plato: "cat 1", Cauchy: "cat 2"},
},
}
if !reflect.DeepEqual(val, answer) {
t.Fatalf("Expected\n-----\n%#v\n-----\nbut got\n-----\n%#v\n",
answer, val)
}
}
func TestDecodeEmbedded(t *testing.T) {
type Dog struct{ Name string }
type Age int
tests := map[string]struct {
input string
decodeInto interface{}
wantDecoded interface{}
}{
"embedded struct": {
input: `Name = "milton"`,
decodeInto: &struct{ Dog }{},
wantDecoded: &struct{ Dog }{Dog{"milton"}},
},
"embedded non-nil pointer to struct": {
input: `Name = "milton"`,
decodeInto: &struct{ *Dog }{},
wantDecoded: &struct{ *Dog }{&Dog{"milton"}},
},
"embedded nil pointer to struct": {
input: ``,
decodeInto: &struct{ *Dog }{},
wantDecoded: &struct{ *Dog }{nil},
},
"embedded int": {
input: `Age = -5`,
decodeInto: &struct{ Age }{},
wantDecoded: &struct{ Age }{-5},
},
}
for label, test := range tests {
_, err := Decode(test.input, test.decodeInto)
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(test.wantDecoded, test.decodeInto) {
t.Errorf("%s: want decoded == %+v, got %+v",
label, test.wantDecoded, test.decodeInto)
}
}
}
func TestTableArrays(t *testing.T) {
var tomlTableArrays = `
[[albums]]
name = "Born to Run"
[[albums.songs]]
name = "Jungleland"
[[albums.songs]]
name = "Meeting Across the River"
[[albums]]
name = "Born in the USA"
[[albums.songs]]
name = "Glory Days"
[[albums.songs]]
name = "Dancing in the Dark"
`
type Song struct {
Name string
}
type Album struct {
Name string
Songs []Song
}
type Music struct {
Albums []Album
}
expected := Music{[]Album{
{"Born to Run", []Song{{"Jungleland"}, {"Meeting Across the River"}}},
{"Born in the USA", []Song{{"Glory Days"}, {"Dancing in the Dark"}}},
}}
var got Music
if _, err := Decode(tomlTableArrays, &got); err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(expected, got) {
t.Fatalf("\n%#v\n!=\n%#v\n", expected, got)
}
}
// Case insensitive matching tests.
// A bit more comprehensive than needed given the current implementation,
// but implementations change.
// Probably still missing demonstrations of some ugly corner cases regarding
// case insensitive matching and multiple fields.
func TestCase(t *testing.T) {
var caseToml = `
tOpString = "string"
tOpInt = 1
tOpFloat = 1.1
tOpBool = true
tOpdate = 2006-01-02T15:04:05Z
tOparray = [ "array" ]
Match = "i should be in Match only"
MatcH = "i should be in MatcH only"
once = "just once"
[nEst.eD]
nEstedString = "another string"
`
type InsensitiveEd struct {
NestedString string
}
type InsensitiveNest struct {
Ed InsensitiveEd
}
type Insensitive struct {
TopString string
TopInt int
TopFloat float64
TopBool bool
TopDate time.Time
TopArray []string
Match string
MatcH string
Once string
OncE string
Nest InsensitiveNest
}
tme, err := time.Parse(time.RFC3339, time.RFC3339[:len(time.RFC3339)-5])
if err != nil {
panic(err)
}
expected := Insensitive{
TopString: "string",
TopInt: 1,
TopFloat: 1.1,
TopBool: true,
TopDate: tme,
TopArray: []string{"array"},
MatcH: "i should be in MatcH only",
Match: "i should be in Match only",
Once: "just once",
OncE: "",
Nest: InsensitiveNest{
Ed: InsensitiveEd{NestedString: "another string"},
},
}
var got Insensitive
if _, err := Decode(caseToml, &got); err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(expected, got) {
t.Fatalf("\n%#v\n!=\n%#v\n", expected, got)
}
}
func TestPointers(t *testing.T) {
type Object struct {
Type string
Description string
}
type Dict struct {
NamedObject map[string]*Object
BaseObject *Object
Strptr *string
Strptrs []*string
}
s1, s2, s3 := "blah", "abc", "def"
expected := &Dict{
Strptr: &s1,
Strptrs: []*string{&s2, &s3},
NamedObject: map[string]*Object{
"foo": {"FOO", "fooooo!!!"},
"bar": {"BAR", "ba-ba-ba-ba-barrrr!!!"},
},
BaseObject: &Object{"BASE", "da base"},
}
ex1 := `
Strptr = "blah"
Strptrs = ["abc", "def"]
[NamedObject.foo]
Type = "FOO"
Description = "fooooo!!!"
[NamedObject.bar]
Type = "BAR"
Description = "ba-ba-ba-ba-barrrr!!!"
[BaseObject]
Type = "BASE"
Description = "da base"
`
dict := new(Dict)
_, err := Decode(ex1, dict)
if err != nil {
t.Errorf("Decode error: %v", err)
}
if !reflect.DeepEqual(expected, dict) {
t.Fatalf("\n%#v\n!=\n%#v\n", expected, dict)
}
}
type sphere struct {
Center [3]float64
Radius float64
}
func TestDecodeSimpleArray(t *testing.T) {
var s1 sphere
if _, err := Decode(`center = [0.0, 1.5, 0.0]`, &s1); err != nil {
t.Fatal(err)
}
}
func TestDecodeArrayWrongSize(t *testing.T) {
var s1 sphere
if _, err := Decode(`center = [0.1, 2.3]`, &s1); err == nil {
t.Fatal("Expected array type mismatch error")
}
}
func TestDecodeLargeIntoSmallInt(t *testing.T) {
type table struct {
Value int8
}
var tab table
if _, err := Decode(`value = 500`, &tab); err == nil {
t.Fatal("Expected integer out-of-bounds error.")
}
}
func TestDecodeSizedInts(t *testing.T) {
type table struct {
U8 uint8
U16 uint16
U32 uint32
U64 uint64
U uint
I8 int8
I16 int16
I32 int32
I64 int64
I int
}
answer := table{1, 1, 1, 1, 1, -1, -1, -1, -1, -1}
toml := `
u8 = 1
u16 = 1
u32 = 1
u64 = 1
u = 1
i8 = -1
i16 = -1
i32 = -1
i64 = -1
i = -1
`
var tab table
if _, err := Decode(toml, &tab); err != nil {
t.Fatal(err.Error())
}
if answer != tab {
t.Fatalf("Expected %#v but got %#v", answer, tab)
}
}
func TestUnmarshaler(t *testing.T) {
var tomlBlob = `
[dishes.hamboogie]
name = "Hamboogie with fries"
price = 10.99
[[dishes.hamboogie.ingredients]]
name = "Bread Bun"
[[dishes.hamboogie.ingredients]]
name = "Lettuce"
[[dishes.hamboogie.ingredients]]
name = "Real Beef Patty"
[[dishes.hamboogie.ingredients]]
name = "Tomato"
[dishes.eggsalad]
name = "Egg Salad with rice"
price = 3.99
[[dishes.eggsalad.ingredients]]
name = "Egg"
[[dishes.eggsalad.ingredients]]
name = "Mayo"
[[dishes.eggsalad.ingredients]]
name = "Rice"
`
m := &menu{}
if _, err := Decode(tomlBlob, m); err != nil {
log.Fatal(err)
}
if len(m.Dishes) != 2 {
t.Log("two dishes should be loaded with UnmarshalTOML()")
t.Errorf("expected %d but got %d", 2, len(m.Dishes))
}
eggSalad := m.Dishes["eggsalad"]
if _, ok := interface{}(eggSalad).(dish); !ok {
t.Errorf("expected a dish")
}
if eggSalad.Name != "Egg Salad with rice" {
t.Errorf("expected the dish to be named 'Egg Salad with rice'")
}
if len(eggSalad.Ingredients) != 3 {
t.Log("dish should be loaded with UnmarshalTOML()")
t.Errorf("expected %d but got %d", 3, len(eggSalad.Ingredients))
}
found := false
for _, i := range eggSalad.Ingredients {
if i.Name == "Rice" {
found = true
break
}
}
if !found {
t.Error("Rice was not loaded in UnmarshalTOML()")
}
// test on a value - must be passed as *
o := menu{}
if _, err := Decode(tomlBlob, &o); err != nil {
log.Fatal(err)
}
}
type menu struct {
Dishes map[string]dish
}
func (m *menu) UnmarshalTOML(p interface{}) error {
m.Dishes = make(map[string]dish)
data, _ := p.(map[string]interface{})
dishes := data["dishes"].(map[string]interface{})
for n, v := range dishes {
if d, ok := v.(map[string]interface{}); ok {
nd := dish{}
nd.UnmarshalTOML(d)
m.Dishes[n] = nd
} else {
return fmt.Errorf("not a dish")
}
}
return nil
}
type dish struct {
Name string
Price float32
Ingredients []ingredient
}
func (d *dish) UnmarshalTOML(p interface{}) error {
data, _ := p.(map[string]interface{})
d.Name, _ = data["name"].(string)
d.Price, _ = data["price"].(float32)
ingredients, _ := data["ingredients"].([]map[string]interface{})
for _, e := range ingredients {
n, _ := interface{}(e).(map[string]interface{})
name, _ := n["name"].(string)
i := ingredient{name}
d.Ingredients = append(d.Ingredients, i)
}
return nil
}
type ingredient struct {
Name string
}
func ExampleMetaData_PrimitiveDecode() {
var md MetaData
var err error
var tomlBlob = `
ranking = ["Springsteen", "J Geils"]
[bands.Springsteen]
started = 1973
albums = ["Greetings", "WIESS", "Born to Run", "Darkness"]
[bands."J Geils"]
started = 1970
albums = ["The J. Geils Band", "Full House", "Blow Your Face Out"]
`
type band struct {
Started int
Albums []string
}
type classics struct {
Ranking []string
Bands map[string]Primitive
}
// Do the initial decode. Reflection is delayed on Primitive values.
var music classics
if md, err = Decode(tomlBlob, &music); err != nil {
log.Fatal(err)
}
// MetaData still includes information on Primitive values.
fmt.Printf("Is `bands.Springsteen` defined? %v\n",
md.IsDefined("bands", "Springsteen"))
// Decode primitive data into Go values.
for _, artist := range music.Ranking {
// A band is a primitive value, so we need to decode it to get a
// real `band` value.
primValue := music.Bands[artist]
var aBand band
if err = md.PrimitiveDecode(primValue, &aBand); err != nil {
log.Fatal(err)
}
fmt.Printf("%s started in %d.\n", artist, aBand.Started)
}
// Check to see if there were any fields left undecoded.
// Note that this won't be empty before decoding the Primitive value!
fmt.Printf("Undecoded: %q\n", md.Undecoded())
// Output:
// Is `bands.Springsteen` defined? true
// Springsteen started in 1973.
// J Geils started in 1970.
// Undecoded: []
}
func ExampleDecode() {
var tomlBlob = `
# Some comments.
[alpha]
ip = "10.0.0.1"
[alpha.config]
Ports = [ 8001, 8002 ]
Location = "Toronto"
Created = 1987-07-05T05:45:00Z
[beta]
ip = "10.0.0.2"
[beta.config]
Ports = [ 9001, 9002 ]
Location = "New Jersey"
Created = 1887-01-05T05:55:00Z
`
type serverConfig struct {
Ports []int
Location string
Created time.Time
}
type server struct {
IP string `toml:"ip"`
Config serverConfig `toml:"config"`
}
type servers map[string]server
var config servers
if _, err := Decode(tomlBlob, &config); err != nil {
log.Fatal(err)
}
for _, name := range []string{"alpha", "beta"} {
s := config[name]
fmt.Printf("Server: %s (ip: %s) in %s created on %s\n",
name, s.IP, s.Config.Location,
s.Config.Created.Format("2006-01-02"))
fmt.Printf("Ports: %v\n", s.Config.Ports)
}
// Output:
// Server: alpha (ip: 10.0.0.1) in Toronto created on 1987-07-05
// Ports: [8001 8002]
// Server: beta (ip: 10.0.0.2) in New Jersey created on 1887-01-05
// Ports: [9001 9002]
}
type duration struct {
time.Duration
}
func (d *duration) UnmarshalText(text []byte) error {
var err error
d.Duration, err = time.ParseDuration(string(text))
return err
}
// Example Unmarshaler shows how to decode TOML strings into your own
// custom data type.
func Example_unmarshaler() {
blob := `
[[song]]
name = "Thunder Road"
duration = "4m49s"
[[song]]
name = "Stairway to Heaven"
duration = "8m03s"
`
type song struct {
Name string
Duration duration
}
type songs struct {
Song []song
}
var favorites songs
if _, err := Decode(blob, &favorites); err != nil {
log.Fatal(err)
}
// Code to implement the TextUnmarshaler interface for `duration`:
//
// type duration struct {
// time.Duration
// }
//
// func (d *duration) UnmarshalText(text []byte) error {
// var err error
// d.Duration, err = time.ParseDuration(string(text))
// return err
// }
for _, s := range favorites.Song {
fmt.Printf("%s (%s)\n", s.Name, s.Duration)
}
// Output:
// Thunder Road (4m49s)
// Stairway to Heaven (8m3s)
}
// Example StrictDecoding shows how to detect whether there are keys in the
// TOML document that weren't decoded into the value given. This is useful
// for returning an error to the user if they've included extraneous fields
// in their configuration.
func Example_strictDecoding() {
var blob = `
key1 = "value1"
key2 = "value2"
key3 = "value3"
`
type config struct {
Key1 string
Key3 string
}
var conf config
md, err := Decode(blob, &conf)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Undecoded keys: %q\n", md.Undecoded())
// Output:
// Undecoded keys: ["key2"]
}
// Example UnmarshalTOML shows how to implement a struct type that knows how to
// unmarshal itself. The struct must take full responsibility for mapping the
// values passed into the struct. The method may be used with interfaces in a
// struct in cases where the actual type is not known until the data is
// examined.
func Example_unmarshalTOML() {
var blob = `
[[parts]]
type = "valve"
id = "valve-1"
size = 1.2
rating = 4
[[parts]]
type = "valve"
id = "valve-2"
size = 2.1
rating = 5
[[parts]]
type = "pipe"
id = "pipe-1"
length = 2.1
diameter = 12
[[parts]]
type = "cable"
id = "cable-1"
length = 12
rating = 3.1
`
o := &order{}
err := Unmarshal([]byte(blob), o)
if err != nil {
log.Fatal(err)
}
fmt.Println(len(o.parts))
for _, part := range o.parts {
fmt.Println(part.Name())
}
// Code to implement UmarshalJSON.
// type order struct {
// // NOTE `order.parts` is a private slice of type `part` which is an
// // interface and may only be loaded from toml using the
// // UnmarshalTOML() method of the Umarshaler interface.
// parts parts
// }
// func (o *order) UnmarshalTOML(data interface{}) error {
// // NOTE the example below contains detailed type casting to show how
// // the 'data' is retrieved. In operational use, a type cast wrapper
// // may be prefered e.g.
// //
// // func AsMap(v interface{}) (map[string]interface{}, error) {
// // return v.(map[string]interface{})
// // }
// //
// // resulting in:
// // d, _ := AsMap(data)
// //
// d, _ := data.(map[string]interface{})
// parts, _ := d["parts"].([]map[string]interface{})
// for _, p := range parts {
// typ, _ := p["type"].(string)
// id, _ := p["id"].(string)
// // detect the type of part and handle each case
// switch p["type"] {
// case "valve":
// size := float32(p["size"].(float64))
// rating := int(p["rating"].(int64))
// valve := &valve{
// Type: typ,
// ID: id,
// Size: size,
// Rating: rating,
// }
// o.parts = append(o.parts, valve)
// case "pipe":
// length := float32(p["length"].(float64))
// diameter := int(p["diameter"].(int64))
// pipe := &pipe{
// Type: typ,
// ID: id,
// Length: length,
// Diameter: diameter,
// }
// o.parts = append(o.parts, pipe)
// case "cable":
// length := int(p["length"].(int64))
// rating := float32(p["rating"].(float64))
// cable := &cable{
// Type: typ,
// ID: id,
// Length: length,
// Rating: rating,
// }
// o.parts = append(o.parts, cable)
// }
// }
// return nil
// }
// type parts []part
// type part interface {
// Name() string
// }
// type valve struct {
// Type string
// ID string
// Size float32
// Rating int
// }
// func (v *valve) Name() string {
// return fmt.Sprintf("VALVE: %s", v.ID)
// }
// type pipe struct {
// Type string
// ID string
// Length float32
// Diameter int
// }
// func (p *pipe) Name() string {
// return fmt.Sprintf("PIPE: %s", p.ID)
// }
// type cable struct {
// Type string
// ID string
// Length int
// Rating float32
// }
// func (c *cable) Name() string {
// return fmt.Sprintf("CABLE: %s", c.ID)
// }
// Output:
// 4
// VALVE: valve-1
// VALVE: valve-2
// PIPE: pipe-1
// CABLE: cable-1
}
type order struct {
// NOTE `order.parts` is a private slice of type `part` which is an
// interface and may only be loaded from toml using the UnmarshalTOML()
// method of the Umarshaler interface.
parts parts
}
func (o *order) UnmarshalTOML(data interface{}) error {
// NOTE the example below contains detailed type casting to show how
// the 'data' is retrieved. In operational use, a type cast wrapper
// may be prefered e.g.
//
// func AsMap(v interface{}) (map[string]interface{}, error) {
// return v.(map[string]interface{})
// }
//
// resulting in:
// d, _ := AsMap(data)
//
d, _ := data.(map[string]interface{})
parts, _ := d["parts"].([]map[string]interface{})
for _, p := range parts {
typ, _ := p["type"].(string)
id, _ := p["id"].(string)
// detect the type of part and handle each case
switch p["type"] {
case "valve":
size := float32(p["size"].(float64))
rating := int(p["rating"].(int64))
valve := &valve{
Type: typ,
ID: id,
Size: size,
Rating: rating,
}
o.parts = append(o.parts, valve)
case "pipe":
length := float32(p["length"].(float64))
diameter := int(p["diameter"].(int64))
pipe := &pipe{
Type: typ,
ID: id,
Length: length,
Diameter: diameter,
}
o.parts = append(o.parts, pipe)
case "cable":
length := int(p["length"].(int64))
rating := float32(p["rating"].(float64))
cable := &cable{
Type: typ,
ID: id,
Length: length,
Rating: rating,
}
o.parts = append(o.parts, cable)
}
}
return nil
}
type parts []part
type part interface {
Name() string
}
type valve struct {
Type string
ID string
Size float32
Rating int
}
func (v *valve) Name() string {
return fmt.Sprintf("VALVE: %s", v.ID)
}
type pipe struct {
Type string
ID string
Length float32
Diameter int
}
func (p *pipe) Name() string {
return fmt.Sprintf("PIPE: %s", p.ID)
}
type cable struct {
Type string
ID string
Length int
Rating float32
}
func (c *cable) Name() string {
return fmt.Sprintf("CABLE: %s", c.ID)
}
+1 -1
View File
@@ -4,7 +4,7 @@ files via reflection. There is also support for delaying decoding with
the Primitive type, and querying the set of keys in a TOML document with the
MetaData type.
The specification implemented: https://github.com/mojombo/toml
The specification implemented: https://github.com/toml-lang/toml
The sub-command github.com/BurntSushi/toml/cmd/tomlv can be used to verify
whether a file is a valid TOML document. It can also be used to print the
+73 -56
View File
@@ -16,17 +16,17 @@ type tomlEncodeError struct{ error }
var (
errArrayMixedElementTypes = errors.New(
"can't encode array with mixed element types")
"toml: cannot encode array with mixed element types")
errArrayNilElement = errors.New(
"can't encode array with nil element")
"toml: cannot encode array with nil element")
errNonString = errors.New(
"can't encode a map with non-string key type")
"toml: cannot encode a map with non-string key type")
errAnonNonStruct = errors.New(
"can't encode an anonymous field that is not a struct")
"toml: cannot encode an anonymous field that is not a struct")
errArrayNoTable = errors.New(
"TOML array element can't contain a table")
"toml: TOML array element cannot contain a table")
errNoKey = errors.New(
"top-level values must be a Go map or struct")
"toml: top-level values must be Go maps or structs")
errAnything = errors.New("") // used in testing
)
@@ -148,7 +148,7 @@ func (enc *Encoder) encode(key Key, rv reflect.Value) {
case reflect.Struct:
enc.eTable(key, rv)
default:
panic(e("Unsupported type for key '%s': %s", key, k))
panic(e("unsupported type for key '%s': %s", key, k))
}
}
@@ -160,7 +160,7 @@ func (enc *Encoder) eElement(rv reflect.Value) {
// Special case time.Time as a primitive. Has to come before
// TextMarshaler below because time.Time implements
// encoding.TextMarshaler, but we need to always use UTC.
enc.wf(v.In(time.FixedZone("UTC", 0)).Format("2006-01-02T15:04:05Z"))
enc.wf(v.UTC().Format("2006-01-02T15:04:05Z"))
return
case TextMarshaler:
// Special case. Use text marshaler if it's available for this value.
@@ -191,7 +191,7 @@ func (enc *Encoder) eElement(rv reflect.Value) {
case reflect.String:
enc.writeQuoted(rv.String())
default:
panic(e("Unexpected primitive type: %s", rv.Kind()))
panic(e("unexpected primitive type: %s", rv.Kind()))
}
}
@@ -241,7 +241,7 @@ func (enc *Encoder) eArrayOfTables(key Key, rv reflect.Value) {
func (enc *Encoder) eTable(key Key, rv reflect.Value) {
panicIfInvalidKey(key)
if len(key) == 1 {
// Output an extra new line between top-level tables.
// Output an extra newline between top-level tables.
// (The newline isn't written if nothing else has been written though.)
enc.newline()
}
@@ -306,19 +306,36 @@ func (enc *Encoder) eStruct(key Key, rv reflect.Value) {
addFields = func(rt reflect.Type, rv reflect.Value, start []int) {
for i := 0; i < rt.NumField(); i++ {
f := rt.Field(i)
// skip unexporded fields
if f.PkgPath != "" {
// skip unexported fields
if f.PkgPath != "" && !f.Anonymous {
continue
}
frv := rv.Field(i)
if f.Anonymous {
frv := eindirect(frv)
t := frv.Type()
if t.Kind() != reflect.Struct {
encPanic(errAnonNonStruct)
t := f.Type
switch t.Kind() {
case reflect.Struct:
// Treat anonymous struct fields with
// tag names as though they are not
// anonymous, like encoding/json does.
if getOptions(f.Tag).name == "" {
addFields(t, frv, f.Index)
continue
}
case reflect.Ptr:
if t.Elem().Kind() == reflect.Struct &&
getOptions(f.Tag).name == "" {
if !frv.IsNil() {
addFields(t.Elem(), frv.Elem(), f.Index)
}
continue
}
// Fall through to the normal field encoding logic below
// for non-struct anonymous fields.
}
addFields(t, frv, f.Index)
} else if typeIsHash(tomlTypeOfGo(frv)) {
}
if typeIsHash(tomlTypeOfGo(frv)) {
fieldsSub = append(fieldsSub, append(start, f.Index...))
} else {
fieldsDirect = append(fieldsDirect, append(start, f.Index...))
@@ -336,18 +353,18 @@ func (enc *Encoder) eStruct(key Key, rv reflect.Value) {
continue
}
keyName := sft.Tag.Get("toml")
if keyName == "-" {
opts := getOptions(sft.Tag)
if opts.skip {
continue
}
if keyName == "" {
keyName = sft.Name
keyName := sft.Name
if opts.name != "" {
keyName = opts.name
}
keyName, opts := getOptions(keyName)
if _, ok := opts["omitempty"]; ok && isEmpty(sf) {
if opts.omitempty && isEmpty(sf) {
continue
} else if _, ok := opts["omitzero"]; ok && isZero(sf) {
}
if opts.omitzero && isZero(sf) {
continue
}
@@ -382,9 +399,8 @@ func tomlTypeOfGo(rv reflect.Value) tomlType {
case reflect.Array, reflect.Slice:
if typeEqual(tomlHash, tomlArrayType(rv)) {
return tomlArrayHash
} else {
return tomlArray
}
return tomlArray
case reflect.Ptr, reflect.Interface:
return tomlTypeOfGo(rv.Elem())
case reflect.String:
@@ -441,50 +457,51 @@ func tomlArrayType(rv reflect.Value) tomlType {
return firstType
}
func getOptions(keyName string) (string, map[string]struct{}) {
opts := make(map[string]struct{})
ss := strings.Split(keyName, ",")
name := ss[0]
if len(ss) > 1 {
for _, opt := range ss {
opts[opt] = struct{}{}
type tagOptions struct {
skip bool // "-"
name string
omitempty bool
omitzero bool
}
func getOptions(tag reflect.StructTag) tagOptions {
t := tag.Get("toml")
if t == "-" {
return tagOptions{skip: true}
}
var opts tagOptions
parts := strings.Split(t, ",")
opts.name = parts[0]
for _, s := range parts[1:] {
switch s {
case "omitempty":
opts.omitempty = true
case "omitzero":
opts.omitzero = true
}
}
return name, opts
return opts
}
func isZero(rv reflect.Value) bool {
switch rv.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
if rv.Int() == 0 {
return true
}
return rv.Int() == 0
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
if rv.Uint() == 0 {
return true
}
return rv.Uint() == 0
case reflect.Float32, reflect.Float64:
if rv.Float() == 0.0 {
return true
}
return rv.Float() == 0.0
}
return false
}
func isEmpty(rv reflect.Value) bool {
switch rv.Kind() {
case reflect.String:
if len(strings.TrimSpace(rv.String())) == 0 {
return true
}
case reflect.Array, reflect.Slice, reflect.Map:
if rv.Len() == 0 {
return true
}
case reflect.Array, reflect.Slice, reflect.Map, reflect.String:
return rv.Len() == 0
case reflect.Bool:
return !rv.Bool()
}
return false
}
-542
View File
@@ -1,542 +0,0 @@
package toml
import (
"bytes"
"fmt"
"log"
"net"
"testing"
"time"
)
func TestEncodeRoundTrip(t *testing.T) {
type Config struct {
Age int
Cats []string
Pi float64
Perfection []int
DOB time.Time
Ipaddress net.IP
}
var inputs = Config{
13,
[]string{"one", "two", "three"},
3.145,
[]int{11, 2, 3, 4},
time.Now(),
net.ParseIP("192.168.59.254"),
}
var firstBuffer bytes.Buffer
e := NewEncoder(&firstBuffer)
err := e.Encode(inputs)
if err != nil {
t.Fatal(err)
}
var outputs Config
if _, err := Decode(firstBuffer.String(), &outputs); err != nil {
log.Printf("Could not decode:\n-----\n%s\n-----\n",
firstBuffer.String())
t.Fatal(err)
}
// could test each value individually, but I'm lazy
var secondBuffer bytes.Buffer
e2 := NewEncoder(&secondBuffer)
err = e2.Encode(outputs)
if err != nil {
t.Fatal(err)
}
if firstBuffer.String() != secondBuffer.String() {
t.Error(
firstBuffer.String(),
"\n\n is not identical to\n\n",
secondBuffer.String())
}
}
// XXX(burntsushi)
// I think these tests probably should be removed. They are good, but they
// ought to be obsolete by toml-test.
func TestEncode(t *testing.T) {
type Embedded struct {
Int int `toml:"_int"`
}
type NonStruct int
date := time.Date(2014, 5, 11, 20, 30, 40, 0, time.FixedZone("IST", 3600))
dateStr := "2014-05-11T19:30:40Z"
tests := map[string]struct {
input interface{}
wantOutput string
wantError error
}{
"bool field": {
input: struct {
BoolTrue bool
BoolFalse bool
}{true, false},
wantOutput: "BoolTrue = true\nBoolFalse = false\n",
},
"int fields": {
input: struct {
Int int
Int8 int8
Int16 int16
Int32 int32
Int64 int64
}{1, 2, 3, 4, 5},
wantOutput: "Int = 1\nInt8 = 2\nInt16 = 3\nInt32 = 4\nInt64 = 5\n",
},
"uint fields": {
input: struct {
Uint uint
Uint8 uint8
Uint16 uint16
Uint32 uint32
Uint64 uint64
}{1, 2, 3, 4, 5},
wantOutput: "Uint = 1\nUint8 = 2\nUint16 = 3\nUint32 = 4" +
"\nUint64 = 5\n",
},
"float fields": {
input: struct {
Float32 float32
Float64 float64
}{1.5, 2.5},
wantOutput: "Float32 = 1.5\nFloat64 = 2.5\n",
},
"string field": {
input: struct{ String string }{"foo"},
wantOutput: "String = \"foo\"\n",
},
"string field and unexported field": {
input: struct {
String string
unexported int
}{"foo", 0},
wantOutput: "String = \"foo\"\n",
},
"datetime field in UTC": {
input: struct{ Date time.Time }{date},
wantOutput: fmt.Sprintf("Date = %s\n", dateStr),
},
"datetime field as primitive": {
// Using a map here to fail if isStructOrMap() returns true for
// time.Time.
input: map[string]interface{}{
"Date": date,
"Int": 1,
},
wantOutput: fmt.Sprintf("Date = %s\nInt = 1\n", dateStr),
},
"array fields": {
input: struct {
IntArray0 [0]int
IntArray3 [3]int
}{[0]int{}, [3]int{1, 2, 3}},
wantOutput: "IntArray0 = []\nIntArray3 = [1, 2, 3]\n",
},
"slice fields": {
input: struct{ IntSliceNil, IntSlice0, IntSlice3 []int }{
nil, []int{}, []int{1, 2, 3},
},
wantOutput: "IntSlice0 = []\nIntSlice3 = [1, 2, 3]\n",
},
"datetime slices": {
input: struct{ DatetimeSlice []time.Time }{
[]time.Time{date, date},
},
wantOutput: fmt.Sprintf("DatetimeSlice = [%s, %s]\n",
dateStr, dateStr),
},
"nested arrays and slices": {
input: struct {
SliceOfArrays [][2]int
ArrayOfSlices [2][]int
SliceOfArraysOfSlices [][2][]int
ArrayOfSlicesOfArrays [2][][2]int
SliceOfMixedArrays [][2]interface{}
ArrayOfMixedSlices [2][]interface{}
}{
[][2]int{{1, 2}, {3, 4}},
[2][]int{{1, 2}, {3, 4}},
[][2][]int{
{
{1, 2}, {3, 4},
},
{
{5, 6}, {7, 8},
},
},
[2][][2]int{
{
{1, 2}, {3, 4},
},
{
{5, 6}, {7, 8},
},
},
[][2]interface{}{
{1, 2}, {"a", "b"},
},
[2][]interface{}{
{1, 2}, {"a", "b"},
},
},
wantOutput: `SliceOfArrays = [[1, 2], [3, 4]]
ArrayOfSlices = [[1, 2], [3, 4]]
SliceOfArraysOfSlices = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]
ArrayOfSlicesOfArrays = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]
SliceOfMixedArrays = [[1, 2], ["a", "b"]]
ArrayOfMixedSlices = [[1, 2], ["a", "b"]]
`,
},
"empty slice": {
input: struct{ Empty []interface{} }{[]interface{}{}},
wantOutput: "Empty = []\n",
},
"(error) slice with element type mismatch (string and integer)": {
input: struct{ Mixed []interface{} }{[]interface{}{1, "a"}},
wantError: errArrayMixedElementTypes,
},
"(error) slice with element type mismatch (integer and float)": {
input: struct{ Mixed []interface{} }{[]interface{}{1, 2.5}},
wantError: errArrayMixedElementTypes,
},
"slice with elems of differing Go types, same TOML types": {
input: struct {
MixedInts []interface{}
MixedFloats []interface{}
}{
[]interface{}{
int(1), int8(2), int16(3), int32(4), int64(5),
uint(1), uint8(2), uint16(3), uint32(4), uint64(5),
},
[]interface{}{float32(1.5), float64(2.5)},
},
wantOutput: "MixedInts = [1, 2, 3, 4, 5, 1, 2, 3, 4, 5]\n" +
"MixedFloats = [1.5, 2.5]\n",
},
"(error) slice w/ element type mismatch (one is nested array)": {
input: struct{ Mixed []interface{} }{
[]interface{}{1, []interface{}{2}},
},
wantError: errArrayMixedElementTypes,
},
"(error) slice with 1 nil element": {
input: struct{ NilElement1 []interface{} }{[]interface{}{nil}},
wantError: errArrayNilElement,
},
"(error) slice with 1 nil element (and other non-nil elements)": {
input: struct{ NilElement []interface{} }{
[]interface{}{1, nil},
},
wantError: errArrayNilElement,
},
"simple map": {
input: map[string]int{"a": 1, "b": 2},
wantOutput: "a = 1\nb = 2\n",
},
"map with interface{} value type": {
input: map[string]interface{}{"a": 1, "b": "c"},
wantOutput: "a = 1\nb = \"c\"\n",
},
"map with interface{} value type, some of which are structs": {
input: map[string]interface{}{
"a": struct{ Int int }{2},
"b": 1,
},
wantOutput: "b = 1\n\n[a]\n Int = 2\n",
},
"nested map": {
input: map[string]map[string]int{
"a": {"b": 1},
"c": {"d": 2},
},
wantOutput: "[a]\n b = 1\n\n[c]\n d = 2\n",
},
"nested struct": {
input: struct{ Struct struct{ Int int } }{
struct{ Int int }{1},
},
wantOutput: "[Struct]\n Int = 1\n",
},
"nested struct and non-struct field": {
input: struct {
Struct struct{ Int int }
Bool bool
}{struct{ Int int }{1}, true},
wantOutput: "Bool = true\n\n[Struct]\n Int = 1\n",
},
"2 nested structs": {
input: struct{ Struct1, Struct2 struct{ Int int } }{
struct{ Int int }{1}, struct{ Int int }{2},
},
wantOutput: "[Struct1]\n Int = 1\n\n[Struct2]\n Int = 2\n",
},
"deeply nested structs": {
input: struct {
Struct1, Struct2 struct{ Struct3 *struct{ Int int } }
}{
struct{ Struct3 *struct{ Int int } }{&struct{ Int int }{1}},
struct{ Struct3 *struct{ Int int } }{nil},
},
wantOutput: "[Struct1]\n [Struct1.Struct3]\n Int = 1" +
"\n\n[Struct2]\n",
},
"nested struct with nil struct elem": {
input: struct {
Struct struct{ Inner *struct{ Int int } }
}{
struct{ Inner *struct{ Int int } }{nil},
},
wantOutput: "[Struct]\n",
},
"nested struct with no fields": {
input: struct {
Struct struct{ Inner struct{} }
}{
struct{ Inner struct{} }{struct{}{}},
},
wantOutput: "[Struct]\n [Struct.Inner]\n",
},
"struct with tags": {
input: struct {
Struct struct {
Int int `toml:"_int"`
} `toml:"_struct"`
Bool bool `toml:"_bool"`
}{
struct {
Int int `toml:"_int"`
}{1}, true,
},
wantOutput: "_bool = true\n\n[_struct]\n _int = 1\n",
},
"embedded struct": {
input: struct{ Embedded }{Embedded{1}},
wantOutput: "_int = 1\n",
},
"embedded *struct": {
input: struct{ *Embedded }{&Embedded{1}},
wantOutput: "_int = 1\n",
},
"nested embedded struct": {
input: struct {
Struct struct{ Embedded } `toml:"_struct"`
}{struct{ Embedded }{Embedded{1}}},
wantOutput: "[_struct]\n _int = 1\n",
},
"nested embedded *struct": {
input: struct {
Struct struct{ *Embedded } `toml:"_struct"`
}{struct{ *Embedded }{&Embedded{1}}},
wantOutput: "[_struct]\n _int = 1\n",
},
"array of tables": {
input: struct {
Structs []*struct{ Int int } `toml:"struct"`
}{
[]*struct{ Int int }{{1}, {3}},
},
wantOutput: "[[struct]]\n Int = 1\n\n[[struct]]\n Int = 3\n",
},
"array of tables order": {
input: map[string]interface{}{
"map": map[string]interface{}{
"zero": 5,
"arr": []map[string]int{
map[string]int{
"friend": 5,
},
},
},
},
wantOutput: "[map]\n zero = 5\n\n [[map.arr]]\n friend = 5\n",
},
"(error) top-level slice": {
input: []struct{ Int int }{{1}, {2}, {3}},
wantError: errNoKey,
},
"(error) slice of slice": {
input: struct {
Slices [][]struct{ Int int }
}{
[][]struct{ Int int }{{{1}}, {{2}}, {{3}}},
},
wantError: errArrayNoTable,
},
"(error) map no string key": {
input: map[int]string{1: ""},
wantError: errNonString,
},
"(error) anonymous non-struct": {
input: struct{ NonStruct }{5},
wantError: errAnonNonStruct,
},
"(error) empty key name": {
input: map[string]int{"": 1},
wantError: errAnything,
},
"(error) empty map name": {
input: map[string]interface{}{
"": map[string]int{"v": 1},
},
wantError: errAnything,
},
}
for label, test := range tests {
encodeExpected(t, label, test.input, test.wantOutput, test.wantError)
}
}
func TestEncodeNestedTableArrays(t *testing.T) {
type song struct {
Name string `toml:"name"`
}
type album struct {
Name string `toml:"name"`
Songs []song `toml:"songs"`
}
type springsteen struct {
Albums []album `toml:"albums"`
}
value := springsteen{
[]album{
{"Born to Run",
[]song{{"Jungleland"}, {"Meeting Across the River"}}},
{"Born in the USA",
[]song{{"Glory Days"}, {"Dancing in the Dark"}}},
},
}
expected := `[[albums]]
name = "Born to Run"
[[albums.songs]]
name = "Jungleland"
[[albums.songs]]
name = "Meeting Across the River"
[[albums]]
name = "Born in the USA"
[[albums.songs]]
name = "Glory Days"
[[albums.songs]]
name = "Dancing in the Dark"
`
encodeExpected(t, "nested table arrays", value, expected, nil)
}
func TestEncodeArrayHashWithNormalHashOrder(t *testing.T) {
type Alpha struct {
V int
}
type Beta struct {
V int
}
type Conf struct {
V int
A Alpha
B []Beta
}
val := Conf{
V: 1,
A: Alpha{2},
B: []Beta{{3}},
}
expected := "V = 1\n\n[A]\n V = 2\n\n[[B]]\n V = 3\n"
encodeExpected(t, "array hash with normal hash order", val, expected, nil)
}
func TestEncodeWithOmitEmpty(t *testing.T) {
type simple struct {
User string `toml:"user"`
Pass string `toml:"password,omitempty"`
}
value := simple{"Testing", ""}
expected := fmt.Sprintf("user = %q\n", value.User)
encodeExpected(t, "simple with omitempty, is empty", value, expected, nil)
value.Pass = "some password"
expected = fmt.Sprintf("user = %q\npassword = %q\n", value.User, value.Pass)
encodeExpected(t, "simple with omitempty, not empty", value, expected, nil)
}
func TestEncodeWithOmitZero(t *testing.T) {
type simple struct {
Number int `toml:"number,omitzero"`
Real float64 `toml:"real,omitzero"`
Unsigned uint `toml:"unsigned,omitzero"`
}
value := simple{0, 0.0, uint(0)}
expected := ""
encodeExpected(t, "simple with omitzero, all zero", value, expected, nil)
value.Number = 10
value.Real = 20
value.Unsigned = 5
expected = `number = 10
real = 20.0
unsigned = 5
`
encodeExpected(t, "simple with omitzero, non-zero", value, expected, nil)
}
func encodeExpected(
t *testing.T, label string, val interface{}, wantStr string, wantErr error,
) {
var buf bytes.Buffer
enc := NewEncoder(&buf)
err := enc.Encode(val)
if err != wantErr {
if wantErr != nil {
if wantErr == errAnything && err != nil {
return
}
t.Errorf("%s: want Encode error %v, got %v", label, wantErr, err)
} else {
t.Errorf("%s: Encode failed: %s", label, err)
}
}
if err != nil {
return
}
if got := buf.String(); wantStr != got {
t.Errorf("%s: want\n-----\n%q\n-----\nbut got\n-----\n%q\n-----\n",
label, wantStr, got)
}
}
func ExampleEncoder_Encode() {
date, _ := time.Parse(time.RFC822, "14 Mar 10 18:00 UTC")
var config = map[string]interface{}{
"date": date,
"counts": []int{1, 1, 2, 3, 5, 8},
"hash": map[string]string{
"key1": "val1",
"key2": "val2",
},
}
buf := new(bytes.Buffer)
if err := NewEncoder(buf).Encode(config); err != nil {
log.Fatal(err)
}
fmt.Println(buf.String())
// Output:
// counts = [1, 1, 2, 3, 5, 8]
// date = 2010-03-14T18:00:00Z
//
// [hash]
// key1 = "val1"
// key2 = "val2"
}
+289 -210
View File
@@ -3,6 +3,7 @@ package toml
import (
"fmt"
"strings"
"unicode"
"unicode/utf8"
)
@@ -29,24 +30,28 @@ const (
itemArrayTableEnd
itemKeyStart
itemCommentStart
itemInlineTableStart
itemInlineTableEnd
)
const (
eof = 0
tableStart = '['
tableEnd = ']'
arrayTableStart = '['
arrayTableEnd = ']'
tableSep = '.'
keySep = '='
arrayStart = '['
arrayEnd = ']'
arrayValTerm = ','
commentStart = '#'
stringStart = '"'
stringEnd = '"'
rawStringStart = '\''
rawStringEnd = '\''
eof = 0
comma = ','
tableStart = '['
tableEnd = ']'
arrayTableStart = '['
arrayTableEnd = ']'
tableSep = '.'
keySep = '='
arrayStart = '['
arrayEnd = ']'
commentStart = '#'
stringStart = '"'
stringEnd = '"'
rawStringStart = '\''
rawStringEnd = '\''
inlineTableStart = '{'
inlineTableEnd = '}'
)
type stateFn func(lx *lexer) stateFn
@@ -55,11 +60,18 @@ type lexer struct {
input string
start int
pos int
width int
line int
state stateFn
items chan item
// Allow for backing up up to three runes.
// This is necessary because TOML contains 3-rune tokens (""" and ''').
prevWidths [3]int
nprev int // how many of prevWidths are in use
// If we emit an eof, we can still back up, but it is not OK to call
// next again.
atEOF bool
// A stack of state functions used to maintain context.
// The idea is to reuse parts of the state machine in various places.
// For example, values can appear at the top level or within arbitrarily
@@ -87,7 +99,7 @@ func (lx *lexer) nextItem() item {
func lex(input string) *lexer {
lx := &lexer{
input: input + "\n",
input: input,
state: lexTop,
line: 1,
items: make(chan item, 10),
@@ -102,7 +114,7 @@ func (lx *lexer) push(state stateFn) {
func (lx *lexer) pop() stateFn {
if len(lx.stack) == 0 {
return lx.errorf("BUG in lexer: no states to pop.")
return lx.errorf("BUG in lexer: no states to pop")
}
last := lx.stack[len(lx.stack)-1]
lx.stack = lx.stack[0 : len(lx.stack)-1]
@@ -124,16 +136,25 @@ func (lx *lexer) emitTrim(typ itemType) {
}
func (lx *lexer) next() (r rune) {
if lx.atEOF {
panic("next called after EOF")
}
if lx.pos >= len(lx.input) {
lx.width = 0
lx.atEOF = true
return eof
}
if lx.input[lx.pos] == '\n' {
lx.line++
}
r, lx.width = utf8.DecodeRuneInString(lx.input[lx.pos:])
lx.pos += lx.width
lx.prevWidths[2] = lx.prevWidths[1]
lx.prevWidths[1] = lx.prevWidths[0]
if lx.nprev < 3 {
lx.nprev++
}
r, w := utf8.DecodeRuneInString(lx.input[lx.pos:])
lx.prevWidths[0] = w
lx.pos += w
return r
}
@@ -142,9 +163,20 @@ func (lx *lexer) ignore() {
lx.start = lx.pos
}
// backup steps back one rune. Can be called only once per call of next.
// backup steps back one rune. Can be called only twice between calls to next.
func (lx *lexer) backup() {
lx.pos -= lx.width
if lx.atEOF {
lx.atEOF = false
return
}
if lx.nprev < 1 {
panic("backed up too far")
}
w := lx.prevWidths[0]
lx.prevWidths[0] = lx.prevWidths[1]
lx.prevWidths[1] = lx.prevWidths[2]
lx.nprev--
lx.pos -= w
if lx.pos < len(lx.input) && lx.input[lx.pos] == '\n' {
lx.line--
}
@@ -166,9 +198,22 @@ func (lx *lexer) peek() rune {
return r
}
// skip ignores all input that matches the given predicate.
func (lx *lexer) skip(pred func(rune) bool) {
for {
r := lx.next()
if pred(r) {
continue
}
lx.backup()
lx.ignore()
return
}
}
// errorf stops all lexing by emitting an error and returning `nil`.
// Note that any value that is a character is escaped if it's a special
// character (new lines, tabs, etc.).
// character (newlines, tabs, etc.).
func (lx *lexer) errorf(format string, values ...interface{}) stateFn {
lx.items <- item{
itemError,
@@ -184,7 +229,6 @@ func lexTop(lx *lexer) stateFn {
if isWhitespace(r) || isNL(r) {
return lexSkip(lx, lexTop)
}
switch r {
case commentStart:
lx.push(lexTop)
@@ -193,7 +237,7 @@ func lexTop(lx *lexer) stateFn {
return lexTableStart
case eof:
if lx.pos > lx.start {
return lx.errorf("Unexpected EOF.")
return lx.errorf("unexpected EOF")
}
lx.emit(itemEOF)
return nil
@@ -208,12 +252,12 @@ func lexTop(lx *lexer) stateFn {
// lexTopEnd is entered whenever a top-level item has been consumed. (A value
// or a table.) It must see only whitespace, and will turn back to lexTop
// upon a new line. If it sees EOF, it will quit the lexer successfully.
// upon a newline. If it sees EOF, it will quit the lexer successfully.
func lexTopEnd(lx *lexer) stateFn {
r := lx.next()
switch {
case r == commentStart:
// a comment will read to a new line for us.
// a comment will read to a newline for us.
lx.push(lexTop)
return lexCommentStart
case isWhitespace(r):
@@ -222,11 +266,11 @@ func lexTopEnd(lx *lexer) stateFn {
lx.ignore()
return lexTop
case r == eof:
lx.ignore()
return lexTop
lx.emit(itemEOF)
return nil
}
return lx.errorf("Expected a top-level item to end with a new line, "+
"comment or EOF, but got %q instead.", r)
return lx.errorf("expected a top-level item to end with a newline, "+
"comment, or EOF, but got %q instead", r)
}
// lexTable lexes the beginning of a table. Namely, it makes sure that
@@ -253,50 +297,47 @@ func lexTableEnd(lx *lexer) stateFn {
func lexArrayTableEnd(lx *lexer) stateFn {
if r := lx.next(); r != arrayTableEnd {
return lx.errorf("Expected end of table array name delimiter %q, "+
"but got %q instead.", arrayTableEnd, r)
return lx.errorf("expected end of table array name delimiter %q, "+
"but got %q instead", arrayTableEnd, r)
}
lx.emit(itemArrayTableEnd)
return lexTopEnd
}
func lexTableNameStart(lx *lexer) stateFn {
lx.skip(isWhitespace)
switch r := lx.peek(); {
case r == tableEnd || r == eof:
return lx.errorf("Unexpected end of table name. (Table names cannot " +
"be empty.)")
return lx.errorf("unexpected end of table name " +
"(table names cannot be empty)")
case r == tableSep:
return lx.errorf("Unexpected table separator. (Table names cannot " +
"be empty.)")
return lx.errorf("unexpected table separator " +
"(table names cannot be empty)")
case r == stringStart || r == rawStringStart:
lx.ignore()
lx.push(lexTableNameEnd)
return lexValue // reuse string lexing
case isWhitespace(r):
return lexTableNameStart
default:
return lexBareTableName
}
}
// lexTableName lexes the name of a table. It assumes that at least one
// lexBareTableName lexes the name of a table. It assumes that at least one
// valid character for the table has already been read.
func lexBareTableName(lx *lexer) stateFn {
switch r := lx.next(); {
case isBareKeyChar(r):
r := lx.next()
if isBareKeyChar(r) {
return lexBareTableName
case r == tableSep || r == tableEnd:
lx.backup()
lx.emitTrim(itemText)
return lexTableNameEnd
default:
return lx.errorf("Bare keys cannot contain %q.", r)
}
lx.backup()
lx.emit(itemText)
return lexTableNameEnd
}
// lexTableNameEnd reads the end of a piece of a table name, optionally
// consuming whitespace.
func lexTableNameEnd(lx *lexer) stateFn {
lx.skip(isWhitespace)
switch r := lx.next(); {
case isWhitespace(r):
return lexTableNameEnd
@@ -306,8 +347,8 @@ func lexTableNameEnd(lx *lexer) stateFn {
case r == tableEnd:
return lx.pop()
default:
return lx.errorf("Expected '.' or ']' to end table name, but got %q "+
"instead.", r)
return lx.errorf("expected '.' or ']' to end table name, "+
"but got %q instead", r)
}
}
@@ -317,7 +358,7 @@ func lexKeyStart(lx *lexer) stateFn {
r := lx.peek()
switch {
case r == keySep:
return lx.errorf("Unexpected key separator %q.", keySep)
return lx.errorf("unexpected key separator %q", keySep)
case isWhitespace(r) || isNL(r):
lx.next()
return lexSkip(lx, lexKeyStart)
@@ -340,14 +381,15 @@ func lexBareKey(lx *lexer) stateFn {
case isBareKeyChar(r):
return lexBareKey
case isWhitespace(r):
lx.emitTrim(itemText)
lx.backup()
lx.emit(itemText)
return lexKeyEnd
case r == keySep:
lx.backup()
lx.emitTrim(itemText)
lx.emit(itemText)
return lexKeyEnd
default:
return lx.errorf("Bare keys cannot contain %q.", r)
return lx.errorf("bare keys cannot contain %q", r)
}
}
@@ -360,7 +402,7 @@ func lexKeyEnd(lx *lexer) stateFn {
case isWhitespace(r):
return lexSkip(lx, lexKeyEnd)
default:
return lx.errorf("Expected key separator %q, but got %q instead.",
return lx.errorf("expected key separator %q, but got %q instead",
keySep, r)
}
}
@@ -369,20 +411,26 @@ func lexKeyEnd(lx *lexer) stateFn {
// lexValue will ignore whitespace.
// After a value is lexed, the last state on the next is popped and returned.
func lexValue(lx *lexer) stateFn {
// We allow whitespace to precede a value, but NOT new lines.
// In array syntax, the array states are responsible for ignoring new
// lines.
// We allow whitespace to precede a value, but NOT newlines.
// In array syntax, the array states are responsible for ignoring newlines.
r := lx.next()
if isWhitespace(r) {
return lexSkip(lx, lexValue)
}
switch {
case r == arrayStart:
case isWhitespace(r):
return lexSkip(lx, lexValue)
case isDigit(r):
lx.backup() // avoid an extra state and use the same as above
return lexNumberOrDateStart
}
switch r {
case arrayStart:
lx.ignore()
lx.emit(itemArray)
return lexArrayValue
case r == stringStart:
case inlineTableStart:
lx.ignore()
lx.emit(itemInlineTableStart)
return lexInlineTableValue
case stringStart:
if lx.accept(stringStart) {
if lx.accept(stringStart) {
lx.ignore() // Ignore """
@@ -392,7 +440,7 @@ func lexValue(lx *lexer) stateFn {
}
lx.ignore() // ignore the '"'
return lexString
case r == rawStringStart:
case rawStringStart:
if lx.accept(rawStringStart) {
if lx.accept(rawStringStart) {
lx.ignore() // Ignore """
@@ -402,23 +450,24 @@ func lexValue(lx *lexer) stateFn {
}
lx.ignore() // ignore the "'"
return lexRawString
case r == 't':
return lexTrue
case r == 'f':
return lexFalse
case r == '-':
case '+', '-':
return lexNumberStart
case isDigit(r):
lx.backup() // avoid an extra state and use the same as above
return lexNumberOrDateStart
case r == '.': // special error case, be kind to users
return lx.errorf("Floats must start with a digit, not '.'.")
case '.': // special error case, be kind to users
return lx.errorf("floats must start with a digit, not '.'")
}
return lx.errorf("Expected value but found %q instead.", r)
if unicode.IsLetter(r) {
// Be permissive here; lexBool will give a nice error if the
// user wrote something like
// x = foo
// (i.e. not 'true' or 'false' but is something else word-like.)
lx.backup()
return lexBool
}
return lx.errorf("expected value but found %q instead", r)
}
// lexArrayValue consumes one value in an array. It assumes that '[' or ','
// have already been consumed. All whitespace and new lines are ignored.
// have already been consumed. All whitespace and newlines are ignored.
func lexArrayValue(lx *lexer) stateFn {
r := lx.next()
switch {
@@ -427,10 +476,11 @@ func lexArrayValue(lx *lexer) stateFn {
case r == commentStart:
lx.push(lexArrayValue)
return lexCommentStart
case r == arrayValTerm:
return lx.errorf("Unexpected array value terminator %q.",
arrayValTerm)
case r == comma:
return lx.errorf("unexpected comma")
case r == arrayEnd:
// NOTE(caleb): The spec isn't clear about whether you can have
// a trailing comma or not, so we'll allow it.
return lexArrayEnd
}
@@ -439,8 +489,9 @@ func lexArrayValue(lx *lexer) stateFn {
return lexValue
}
// lexArrayValueEnd consumes the cruft between values of an array. Namely,
// it ignores whitespace and expects either a ',' or a ']'.
// lexArrayValueEnd consumes everything between the end of an array value and
// the next value (or the end of the array): it ignores whitespace and newlines
// and expects either a ',' or a ']'.
func lexArrayValueEnd(lx *lexer) stateFn {
r := lx.next()
switch {
@@ -449,31 +500,88 @@ func lexArrayValueEnd(lx *lexer) stateFn {
case r == commentStart:
lx.push(lexArrayValueEnd)
return lexCommentStart
case r == arrayValTerm:
case r == comma:
lx.ignore()
return lexArrayValue // move on to the next value
case r == arrayEnd:
return lexArrayEnd
}
return lx.errorf("Expected an array value terminator %q or an array "+
"terminator %q, but got %q instead.", arrayValTerm, arrayEnd, r)
return lx.errorf(
"expected a comma or array terminator %q, but got %q instead",
arrayEnd, r,
)
}
// lexArrayEnd finishes the lexing of an array. It assumes that a ']' has
// just been consumed.
// lexArrayEnd finishes the lexing of an array.
// It assumes that a ']' has just been consumed.
func lexArrayEnd(lx *lexer) stateFn {
lx.ignore()
lx.emit(itemArrayEnd)
return lx.pop()
}
// lexInlineTableValue consumes one key/value pair in an inline table.
// It assumes that '{' or ',' have already been consumed. Whitespace is ignored.
func lexInlineTableValue(lx *lexer) stateFn {
r := lx.next()
switch {
case isWhitespace(r):
return lexSkip(lx, lexInlineTableValue)
case isNL(r):
return lx.errorf("newlines not allowed within inline tables")
case r == commentStart:
lx.push(lexInlineTableValue)
return lexCommentStart
case r == comma:
return lx.errorf("unexpected comma")
case r == inlineTableEnd:
return lexInlineTableEnd
}
lx.backup()
lx.push(lexInlineTableValueEnd)
return lexKeyStart
}
// lexInlineTableValueEnd consumes everything between the end of an inline table
// key/value pair and the next pair (or the end of the table):
// it ignores whitespace and expects either a ',' or a '}'.
func lexInlineTableValueEnd(lx *lexer) stateFn {
r := lx.next()
switch {
case isWhitespace(r):
return lexSkip(lx, lexInlineTableValueEnd)
case isNL(r):
return lx.errorf("newlines not allowed within inline tables")
case r == commentStart:
lx.push(lexInlineTableValueEnd)
return lexCommentStart
case r == comma:
lx.ignore()
return lexInlineTableValue
case r == inlineTableEnd:
return lexInlineTableEnd
}
return lx.errorf("expected a comma or an inline table terminator %q, "+
"but got %q instead", inlineTableEnd, r)
}
// lexInlineTableEnd finishes the lexing of an inline table.
// It assumes that a '}' has just been consumed.
func lexInlineTableEnd(lx *lexer) stateFn {
lx.ignore()
lx.emit(itemInlineTableEnd)
return lx.pop()
}
// lexString consumes the inner contents of a string. It assumes that the
// beginning '"' has already been consumed and ignored.
func lexString(lx *lexer) stateFn {
r := lx.next()
switch {
case r == eof:
return lx.errorf("unexpected EOF")
case isNL(r):
return lx.errorf("Strings cannot contain new lines.")
return lx.errorf("strings cannot contain newlines")
case r == '\\':
lx.push(lexString)
return lexStringEscape
@@ -490,11 +598,12 @@ func lexString(lx *lexer) stateFn {
// lexMultilineString consumes the inner contents of a string. It assumes that
// the beginning '"""' has already been consumed and ignored.
func lexMultilineString(lx *lexer) stateFn {
r := lx.next()
switch {
case r == '\\':
switch lx.next() {
case eof:
return lx.errorf("unexpected EOF")
case '\\':
return lexMultilineStringEscape
case r == stringEnd:
case stringEnd:
if lx.accept(stringEnd) {
if lx.accept(stringEnd) {
lx.backup()
@@ -518,8 +627,10 @@ func lexMultilineString(lx *lexer) stateFn {
func lexRawString(lx *lexer) stateFn {
r := lx.next()
switch {
case r == eof:
return lx.errorf("unexpected EOF")
case isNL(r):
return lx.errorf("Strings cannot contain new lines.")
return lx.errorf("strings cannot contain newlines")
case r == rawStringEnd:
lx.backup()
lx.emit(itemRawString)
@@ -531,12 +642,13 @@ func lexRawString(lx *lexer) stateFn {
}
// lexMultilineRawString consumes a raw string. Nothing can be escaped in such
// a string. It assumes that the beginning "'" has already been consumed and
// a string. It assumes that the beginning "'''" has already been consumed and
// ignored.
func lexMultilineRawString(lx *lexer) stateFn {
r := lx.next()
switch {
case r == rawStringEnd:
switch lx.next() {
case eof:
return lx.errorf("unexpected EOF")
case rawStringEnd:
if lx.accept(rawStringEnd) {
if lx.accept(rawStringEnd) {
lx.backup()
@@ -560,13 +672,11 @@ func lexMultilineRawString(lx *lexer) stateFn {
func lexMultilineStringEscape(lx *lexer) stateFn {
// Handle the special case first:
if isNL(lx.next()) {
lx.next()
return lexMultilineString
} else {
lx.backup()
lx.push(lexMultilineString)
return lexStringEscape(lx)
}
lx.backup()
lx.push(lexMultilineString)
return lexStringEscape(lx)
}
func lexStringEscape(lx *lexer) stateFn {
@@ -591,10 +701,9 @@ func lexStringEscape(lx *lexer) stateFn {
case 'U':
return lexLongUnicodeEscape
}
return lx.errorf("Invalid escape character %q. Only the following "+
return lx.errorf("invalid escape character %q; only the following "+
"escape characters are allowed: "+
"\\b, \\t, \\n, \\f, \\r, \\\", \\/, \\\\, "+
"\\uXXXX and \\UXXXXXXXX.", r)
`\b, \t, \n, \f, \r, \", \\, \uXXXX, and \UXXXXXXXX`, r)
}
func lexShortUnicodeEscape(lx *lexer) stateFn {
@@ -602,8 +711,8 @@ func lexShortUnicodeEscape(lx *lexer) stateFn {
for i := 0; i < 4; i++ {
r = lx.next()
if !isHexadecimal(r) {
return lx.errorf("Expected four hexadecimal digits after '\\u', "+
"but got '%s' instead.", lx.current())
return lx.errorf(`expected four hexadecimal digits after '\u', `+
"but got %q instead", lx.current())
}
}
return lx.pop()
@@ -614,40 +723,43 @@ func lexLongUnicodeEscape(lx *lexer) stateFn {
for i := 0; i < 8; i++ {
r = lx.next()
if !isHexadecimal(r) {
return lx.errorf("Expected eight hexadecimal digits after '\\U', "+
"but got '%s' instead.", lx.current())
return lx.errorf(`expected eight hexadecimal digits after '\U', `+
"but got %q instead", lx.current())
}
}
return lx.pop()
}
// lexNumberOrDateStart consumes either a (positive) integer, float or
// datetime. It assumes that NO negative sign has been consumed.
// lexNumberOrDateStart consumes either an integer, a float, or datetime.
func lexNumberOrDateStart(lx *lexer) stateFn {
r := lx.next()
if !isDigit(r) {
if r == '.' {
return lx.errorf("Floats must start with a digit, not '.'.")
} else {
return lx.errorf("Expected a digit but got %q.", r)
}
if isDigit(r) {
return lexNumberOrDate
}
return lexNumberOrDate
switch r {
case '_':
return lexNumber
case 'e', 'E':
return lexFloat
case '.':
return lx.errorf("floats must start with a digit, not '.'")
}
return lx.errorf("expected a digit but got %q", r)
}
// lexNumberOrDate consumes either a (positive) integer, float or datetime.
// lexNumberOrDate consumes either an integer, float or datetime.
func lexNumberOrDate(lx *lexer) stateFn {
r := lx.next()
switch {
case r == '-':
if lx.pos-lx.start != 5 {
return lx.errorf("All ISO8601 dates must be in full Zulu form.")
}
return lexDateAfterYear
case isDigit(r):
if isDigit(r) {
return lexNumberOrDate
case r == '.':
return lexFloatStart
}
switch r {
case '-':
return lexDatetime
case '_':
return lexNumber
case '.', 'e', 'E':
return lexFloat
}
lx.backup()
@@ -655,46 +767,34 @@ func lexNumberOrDate(lx *lexer) stateFn {
return lx.pop()
}
// lexDateAfterYear consumes a full Zulu Datetime in ISO8601 format.
// It assumes that "YYYY-" has already been consumed.
func lexDateAfterYear(lx *lexer) stateFn {
formats := []rune{
// digits are '0'.
// everything else is direct equality.
'0', '0', '-', '0', '0',
'T',
'0', '0', ':', '0', '0', ':', '0', '0',
'Z',
// lexDatetime consumes a Datetime, to a first approximation.
// The parser validates that it matches one of the accepted formats.
func lexDatetime(lx *lexer) stateFn {
r := lx.next()
if isDigit(r) {
return lexDatetime
}
for _, f := range formats {
r := lx.next()
if f == '0' {
if !isDigit(r) {
return lx.errorf("Expected digit in ISO8601 datetime, "+
"but found %q instead.", r)
}
} else if f != r {
return lx.errorf("Expected %q in ISO8601 datetime, "+
"but found %q instead.", f, r)
}
switch r {
case '-', 'T', ':', '.', 'Z':
return lexDatetime
}
lx.backup()
lx.emit(itemDatetime)
return lx.pop()
}
// lexNumberStart consumes either an integer or a float. It assumes that
// a negative sign has already been read, but that *no* digits have been
// consumed. lexNumberStart will move to the appropriate integer or float
// states.
// lexNumberStart consumes either an integer or a float. It assumes that a sign
// has already been read, but that *no* digits have been consumed.
// lexNumberStart will move to the appropriate integer or float states.
func lexNumberStart(lx *lexer) stateFn {
// we MUST see a digit. Even floats have to start with a digit.
// We MUST see a digit. Even floats have to start with a digit.
r := lx.next()
if !isDigit(r) {
if r == '.' {
return lx.errorf("Floats must start with a digit, not '.'.")
} else {
return lx.errorf("Expected a digit but got %q.", r)
return lx.errorf("floats must start with a digit, not '.'")
}
return lx.errorf("expected a digit but got %q", r)
}
return lexNumber
}
@@ -702,11 +802,14 @@ func lexNumberStart(lx *lexer) stateFn {
// lexNumber consumes an integer or a float after seeing the first digit.
func lexNumber(lx *lexer) stateFn {
r := lx.next()
switch {
case isDigit(r):
if isDigit(r) {
return lexNumber
case r == '.':
return lexFloatStart
}
switch r {
case '_':
return lexNumber
case '.', 'e', 'E':
return lexFloat
}
lx.backup()
@@ -714,60 +817,42 @@ func lexNumber(lx *lexer) stateFn {
return lx.pop()
}
// lexFloatStart starts the consumption of digits of a float after a '.'.
// Namely, at least one digit is required.
func lexFloatStart(lx *lexer) stateFn {
r := lx.next()
if !isDigit(r) {
return lx.errorf("Floats must have a digit after the '.', but got "+
"%q instead.", r)
}
return lexFloat
}
// lexFloat consumes the digits of a float after a '.'.
// Assumes that one digit has been consumed after a '.' already.
// lexFloat consumes the elements of a float. It allows any sequence of
// float-like characters, so floats emitted by the lexer are only a first
// approximation and must be validated by the parser.
func lexFloat(lx *lexer) stateFn {
r := lx.next()
if isDigit(r) {
return lexFloat
}
switch r {
case '_', '.', '-', '+', 'e', 'E':
return lexFloat
}
lx.backup()
lx.emit(itemFloat)
return lx.pop()
}
// lexConst consumes the s[1:] in s. It assumes that s[0] has already been
// consumed.
func lexConst(lx *lexer, s string) stateFn {
for i := range s[1:] {
if r := lx.next(); r != rune(s[i+1]) {
return lx.errorf("Expected %q, but found %q instead.", s[:i+1],
s[:i]+string(r))
// lexBool consumes a bool string: 'true' or 'false.
func lexBool(lx *lexer) stateFn {
var rs []rune
for {
r := lx.next()
if !unicode.IsLetter(r) {
lx.backup()
break
}
rs = append(rs, r)
}
return nil
}
// lexTrue consumes the "rue" in "true". It assumes that 't' has already
// been consumed.
func lexTrue(lx *lexer) stateFn {
if fn := lexConst(lx, "true"); fn != nil {
return fn
s := string(rs)
switch s {
case "true", "false":
lx.emit(itemBool)
return lx.pop()
}
lx.emit(itemBool)
return lx.pop()
}
// lexFalse consumes the "alse" in "false". It assumes that 'f' has already
// been consumed.
func lexFalse(lx *lexer) stateFn {
if fn := lexConst(lx, "false"); fn != nil {
return fn
}
lx.emit(itemBool)
return lx.pop()
return lx.errorf("expected value but found %q instead", s)
}
// lexCommentStart begins the lexing of a comment. It will emit
@@ -779,7 +864,7 @@ func lexCommentStart(lx *lexer) stateFn {
}
// lexComment lexes an entire comment. It assumes that '#' has been consumed.
// It will consume *up to* the first new line character, and pass control
// It will consume *up to* the first newline character, and pass control
// back to the last state on the stack.
func lexComment(lx *lexer) stateFn {
r := lx.peek()
@@ -837,13 +922,7 @@ func (itype itemType) String() string {
return "EOF"
case itemText:
return "Text"
case itemString:
return "String"
case itemRawString:
return "String"
case itemMultilineString:
return "String"
case itemRawMultilineString:
case itemString, itemRawString, itemMultilineString, itemRawMultilineString:
return "String"
case itemBool:
return "Bool"
+118 -24
View File
@@ -2,7 +2,6 @@ package toml
import (
"fmt"
"log"
"strconv"
"strings"
"time"
@@ -81,7 +80,7 @@ func (p *parser) next() item {
}
func (p *parser) bug(format string, v ...interface{}) {
log.Fatalf("BUG: %s\n\n", fmt.Sprintf(format, v...))
panic(fmt.Sprintf("BUG: "+format+"\n\n", v...))
}
func (p *parser) expect(typ itemType) item {
@@ -179,10 +178,18 @@ func (p *parser) value(it item) (interface{}, tomlType) {
}
p.bug("Expected boolean value, but got '%s'.", it.val)
case itemInteger:
num, err := strconv.ParseInt(it.val, 10, 64)
if !numUnderscoresOK(it.val) {
p.panicf("Invalid integer %q: underscores must be surrounded by digits",
it.val)
}
val := strings.Replace(it.val, "_", "", -1)
num, err := strconv.ParseInt(val, 10, 64)
if err != nil {
// See comment below for floats describing why we make a
// distinction between a bug and a user error.
// Distinguish integer values. Normally, it'd be a bug if the lexer
// provides an invalid integer, but it's possible that the number is
// out of range of valid values (which the lexer cannot determine).
// So mark the former as a bug but the latter as a legitimate user
// error.
if e, ok := err.(*strconv.NumError); ok &&
e.Err == strconv.ErrRange {
@@ -194,29 +201,57 @@ func (p *parser) value(it item) (interface{}, tomlType) {
}
return num, p.typeOfPrimitive(it)
case itemFloat:
num, err := strconv.ParseFloat(it.val, 64)
parts := strings.FieldsFunc(it.val, func(r rune) bool {
switch r {
case '.', 'e', 'E':
return true
}
return false
})
for _, part := range parts {
if !numUnderscoresOK(part) {
p.panicf("Invalid float %q: underscores must be "+
"surrounded by digits", it.val)
}
}
if !numPeriodsOK(it.val) {
// As a special case, numbers like '123.' or '1.e2',
// which are valid as far as Go/strconv are concerned,
// must be rejected because TOML says that a fractional
// part consists of '.' followed by 1+ digits.
p.panicf("Invalid float %q: '.' must be followed "+
"by one or more digits", it.val)
}
val := strings.Replace(it.val, "_", "", -1)
num, err := strconv.ParseFloat(val, 64)
if err != nil {
// Distinguish float values. Normally, it'd be a bug if the lexer
// provides an invalid float, but it's possible that the float is
// out of range of valid values (which the lexer cannot determine).
// So mark the former as a bug but the latter as a legitimate user
// error.
//
// This is also true for integers.
if e, ok := err.(*strconv.NumError); ok &&
e.Err == strconv.ErrRange {
p.panicf("Float '%s' is out of the range of 64-bit "+
"IEEE-754 floating-point numbers.", it.val)
} else {
p.bug("Expected float value, but got '%s'.", it.val)
p.panicf("Invalid float value: %q", it.val)
}
}
return num, p.typeOfPrimitive(it)
case itemDatetime:
t, err := time.Parse("2006-01-02T15:04:05Z", it.val)
if err != nil {
p.bug("Expected Zulu formatted DateTime, but got '%s'.", it.val)
var t time.Time
var ok bool
var err error
for _, format := range []string{
"2006-01-02T15:04:05Z07:00",
"2006-01-02T15:04:05",
"2006-01-02",
} {
t, err = time.ParseInLocation(format, it.val, time.Local)
if err == nil {
ok = true
break
}
}
if !ok {
p.panicf("Invalid TOML Datetime: %q.", it.val)
}
return t, p.typeOfPrimitive(it)
case itemArray:
@@ -234,11 +269,75 @@ func (p *parser) value(it item) (interface{}, tomlType) {
types = append(types, typ)
}
return array, p.typeOfArray(types)
case itemInlineTableStart:
var (
hash = make(map[string]interface{})
outerContext = p.context
outerKey = p.currentKey
)
p.context = append(p.context, p.currentKey)
p.currentKey = ""
for it := p.next(); it.typ != itemInlineTableEnd; it = p.next() {
if it.typ != itemKeyStart {
p.bug("Expected key start but instead found %q, around line %d",
it.val, p.approxLine)
}
if it.typ == itemCommentStart {
p.expect(itemText)
continue
}
// retrieve key
k := p.next()
p.approxLine = k.line
kname := p.keyString(k)
// retrieve value
p.currentKey = kname
val, typ := p.value(p.next())
// make sure we keep metadata up to date
p.setType(kname, typ)
p.ordered = append(p.ordered, p.context.add(p.currentKey))
hash[kname] = val
}
p.context = outerContext
p.currentKey = outerKey
return hash, tomlHash
}
p.bug("Unexpected value type: %s", it.typ)
panic("unreachable")
}
// numUnderscoresOK checks whether each underscore in s is surrounded by
// characters that are not underscores.
func numUnderscoresOK(s string) bool {
accept := false
for _, r := range s {
if r == '_' {
if !accept {
return false
}
accept = false
continue
}
accept = true
}
return accept
}
// numPeriodsOK checks whether every period in s is followed by a digit.
func numPeriodsOK(s string) bool {
period := false
for _, r := range s {
if period && !isDigit(r) {
return false
}
period = r == '.'
}
return !period
}
// establishContext sets the current context of the parser,
// where the context is either a hash or an array of hashes. Which one is
// set depends on the value of the `array` parameter.
@@ -401,7 +500,7 @@ func stripFirstNewline(s string) string {
if len(s) == 0 || s[0] != '\n' {
return s
}
return s[1:len(s)]
return s[1:]
}
func stripEscapedWhitespace(s string) string {
@@ -481,12 +580,7 @@ func (p *parser) asciiEscapeToUnicode(bs []byte) rune {
p.bug("Could not parse '%s' as a hexadecimal number, but the "+
"lexer claims it's OK: %s", s, err)
}
// BUG(burntsushi)
// I honestly don't understand how this works. I can't seem
// to find a way to make this fail. I figured this would fail on invalid
// UTF-8 characters like U+DCFF, but it doesn't.
if !utf8.ValidString(string(rune(hex))) {
if !utf8.ValidRune(rune(hex)) {
p.panicf("Escaped character '\\u%s' is not valid UTF-8.", s)
}
return rune(hex)
-1
View File
@@ -1 +0,0 @@
au BufWritePost *.go silent!make tags > /dev/null 2>&1
+6 -5
View File
@@ -92,11 +92,11 @@ func typeFields(t reflect.Type) []field {
// Scan f.typ for fields to include.
for i := 0; i < f.typ.NumField(); i++ {
sf := f.typ.Field(i)
if sf.PkgPath != "" { // unexported
if sf.PkgPath != "" && !sf.Anonymous { // unexported
continue
}
name := sf.Tag.Get("toml")
if name == "-" {
opts := getOptions(sf.Tag)
if opts.skip {
continue
}
index := make([]int, len(f.index)+1)
@@ -110,8 +110,9 @@ func typeFields(t reflect.Type) []field {
}
// Record found field and index sequence.
if name != "" || !sf.Anonymous || ft.Kind() != reflect.Struct {
tagged := name != ""
if opts.name != "" || !sf.Anonymous || ft.Kind() != reflect.Struct {
tagged := opts.name != ""
name := opts.name
if name == "" {
name = sf.Name
}
-20
View File
@@ -1,20 +0,0 @@
Common Functions
================
[![Build Status](https://travis-ci.org/Unknwon/com.svg)](https://travis-ci.org/Unknwon/com) [![Go Walker](http://gowalker.org/api/v1/badge)](http://gowalker.org/github.com/Unknwon/com)
This is an open source project for commonly used functions for the Go programming language.
This package need >= **go 1.2**
Code Convention: based on [Go Code Convention](https://github.com/Unknwon/go-code-convention).
## Contribute
Your contribute is welcome, but you have to check following steps after you added some functions and commit them:
1. Make sure you wrote user-friendly comments for **all functions** .
2. Make sure you wrote test cases with any possible condition for **all functions** in file `*_test.go`.
3. Make sure you wrote benchmarks for **all functions** in file `*_test.go`.
4. Make sure you wrote useful examples for **all functions** in file `example_test.go`.
5. Make sure you ran `go test` and got **PASS** .
+10
View File
@@ -41,6 +41,11 @@ func (f StrTo) Int64() (int64, error) {
return int64(v), err
}
func (f StrTo) Float64() (float64, error) {
v, err := strconv.ParseFloat(f.String(), 64)
return float64(v), err
}
func (f StrTo) MustUint8() uint8 {
v, _ := f.Uint8()
return v
@@ -56,6 +61,11 @@ func (f StrTo) MustInt64() int64 {
return v
}
func (f StrTo) MustFloat64() float64 {
v, _ := f.Float64()
return v
}
func (f StrTo) String() string {
if f.Exist() {
return string(f)
-1
View File
@@ -1 +0,0 @@
TestSaveFile
-1
View File
@@ -1 +0,0 @@
TestSaveFileS
View File
-1
View File
@@ -1 +0,0 @@
TestSaveFile
-1
View File
@@ -1 +0,0 @@
TestSaveFileS
View File
@@ -1 +0,0 @@
TestSaveFile
@@ -1 +0,0 @@
TestSaveFileS
+16
View File
@@ -0,0 +1,16 @@
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
+129
View File
@@ -0,0 +1,129 @@
This package was debianized by Thrift Developer's <dev@thrift.apache.org>.
This package and the Debian packaging is licensed under the Apache License,
see `/usr/share/common-licenses/Apache-2.0'.
The following information was copied from Apache Thrift LICENSE file.
--------------------------------------------------
SOFTWARE DISTRIBUTED WITH THRIFT:
The Apache Thrift software includes a number of subcomponents with
separate copyright notices and license terms. Your use of the source
code for the these subcomponents is subject to the terms and
conditions of the following licenses.
--------------------------------------------------
Portions of the following files are licensed under the MIT License:
lib/erl/src/Makefile.am
Please see doc/otp-base-license.txt for the full terms of this license.
--------------------------------------------------
The following files contain some portions of code contributed under
the Thrift Software License (see doc/old-thrift-license.txt), and relicensed
under the Apache 2.0 License:
compiler/cpp/Makefile.am
compiler/cpp/src/generate/t_cocoa_generator.cc
compiler/cpp/src/generate/t_cpp_generator.cc
compiler/cpp/src/generate/t_csharp_generator.cc
compiler/cpp/src/generate/t_erl_generator.cc
compiler/cpp/src/generate/t_hs_generator.cc
compiler/cpp/src/generate/t_java_generator.cc
compiler/cpp/src/generate/t_ocaml_generator.cc
compiler/cpp/src/generate/t_perl_generator.cc
compiler/cpp/src/generate/t_php_generator.cc
compiler/cpp/src/generate/t_py_generator.cc
compiler/cpp/src/generate/t_rb_generator.cc
compiler/cpp/src/generate/t_st_generator.cc
compiler/cpp/src/generate/t_xsd_generator.cc
compiler/cpp/src/main.cc
compiler/cpp/src/parse/t_field.h
compiler/cpp/src/parse/t_program.h
compiler/cpp/src/platform.h
compiler/cpp/src/thriftl.ll
compiler/cpp/src/thrifty.yy
lib/csharp/src/Protocol/TBinaryProtocol.cs
lib/csharp/src/Protocol/TField.cs
lib/csharp/src/Protocol/TList.cs
lib/csharp/src/Protocol/TMap.cs
lib/csharp/src/Protocol/TMessage.cs
lib/csharp/src/Protocol/TMessageType.cs
lib/csharp/src/Protocol/TProtocol.cs
lib/csharp/src/Protocol/TProtocolException.cs
lib/csharp/src/Protocol/TProtocolFactory.cs
lib/csharp/src/Protocol/TProtocolUtil.cs
lib/csharp/src/Protocol/TSet.cs
lib/csharp/src/Protocol/TStruct.cs
lib/csharp/src/Protocol/TType.cs
lib/csharp/src/Server/TServer.cs
lib/csharp/src/Server/TSimpleServer.cs
lib/csharp/src/Server/TThreadPoolServer.cs
lib/csharp/src/TApplicationException.cs
lib/csharp/src/Thrift.csproj
lib/csharp/src/Thrift.sln
lib/csharp/src/TProcessor.cs
lib/csharp/src/Transport/TServerSocket.cs
lib/csharp/src/Transport/TServerTransport.cs
lib/csharp/src/Transport/TSocket.cs
lib/csharp/src/Transport/TStreamTransport.cs
lib/csharp/src/Transport/TTransport.cs
lib/csharp/src/Transport/TTransportException.cs
lib/csharp/src/Transport/TTransportFactory.cs
lib/csharp/ThriftMSBuildTask/Properties/AssemblyInfo.cs
lib/csharp/ThriftMSBuildTask/ThriftBuild.cs
lib/csharp/ThriftMSBuildTask/ThriftMSBuildTask.csproj
lib/rb/lib/thrift.rb
lib/st/README
lib/st/thrift.st
test/OptionalRequiredTest.cpp
test/OptionalRequiredTest.thrift
test/ThriftTest.thrift
--------------------------------------------------
For the aclocal/ax_boost_base.m4 and contrib/fb303/aclocal/ax_boost_base.m4 components:
# Copyright (c) 2007 Thomas Porschberg <thomas@randspringer.de>
#
# Copying and distribution of this file, with or without
# modification, are permitted in any medium without royalty provided
# the copyright notice and this notice are preserved.
--------------------------------------------------
For the compiler/cpp/src/md5.[ch] components:
/*
Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved.
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
L. Peter Deutsch
ghost@aladdin.com
*/
---------------------------------------------------
For the lib/rb/setup.rb: Copyright (c) 2000-2005 Minero Aoki,
lib/ocaml/OCamlMakefile and lib/ocaml/README-OCamlMakefile components:
Copyright (C) 1999 - 2007 Markus Mottl
Licensed under the terms of the GNU Lesser General Public License 2.1
(see doc/lgpl-2.1.txt for the full terms of this license)
+16
View File
@@ -0,0 +1,16 @@
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
+202
View File
@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
+1
View File
@@ -0,0 +1 @@
server.sh
-1536
View File
File diff suppressed because it is too large Load Diff
-5
View File
@@ -1,5 +0,0 @@
### SDK Features
### SDK Enhancements
### SDK Bugs
-127
View File
@@ -1,127 +0,0 @@
Contributing to the AWS SDK for Go
We work hard to provide a high-quality and useful SDK, and we greatly value
feedback and contributions from our community. Whether it's a bug report,
new feature, correction, or additional documentation, we welcome your issues
and pull requests. Please read through this document before submitting any
issues or pull requests to ensure we have all the necessary information to
effectively respond to your bug report or contribution.
## Filing Bug Reports
You can file bug reports against the SDK on the [GitHub issues][issues] page.
If you are filing a report for a bug or regression in the SDK, it's extremely
helpful to provide as much information as possible when opening the original
issue. This helps us reproduce and investigate the possible bug without having
to wait for this extra information to be provided. Please read the following
guidelines prior to filing a bug report.
1. Search through existing [issues][] to ensure that your specific issue has
not yet been reported. If it is a common issue, it is likely there is
already a bug report for your problem.
2. Ensure that you have tested the latest version of the SDK. Although you
may have an issue against an older version of the SDK, we cannot provide
bug fixes for old versions. It's also possible that the bug may have been
fixed in the latest release.
3. Provide as much information about your environment, SDK version, and
relevant dependencies as possible. For example, let us know what version
of Go you are using, which and version of the operating system, and the
the environment your code is running in. e.g Container.
4. Provide a minimal test case that reproduces your issue or any error
information you related to your problem. We can provide feedback much
more quickly if we know what operations you are calling in the SDK. If
you cannot provide a full test case, provide as much code as you can
to help us diagnose the problem. Any relevant information should be provided
as well, like whether this is a persistent issue, or if it only occurs
some of the time.
## Submitting Pull Requests
We are always happy to receive code and documentation contributions to the SDK.
Please be aware of the following notes prior to opening a pull request:
1. The SDK is released under the [Apache license][license]. Any code you submit
will be released under that license. For substantial contributions, we may
ask you to sign a [Contributor License Agreement (CLA)][cla].
2. If you would like to implement support for a significant feature that is not
yet available in the SDK, please talk to us beforehand to avoid any
duplication of effort.
3. Wherever possible, pull requests should contain tests as appropriate.
Bugfixes should contain tests that exercise the corrected behavior (i.e., the
test should fail without the bugfix and pass with it), and new features
should be accompanied by tests exercising the feature.
4. Pull requests that contain failing tests will not be merged until the test
failures are addressed. Pull requests that cause a significant drop in the
SDK's test coverage percentage are unlikely to be merged until tests have
been added.
5. The JSON files under the SDK's `models` folder are sourced from outside the SDK.
Such as `models/apis/ec2/2016-11-15/api.json`. We will not accept pull requests
directly on these models. If you discover an issue with the models please
create a Github [issue](issues) describing the issue.
### Testing
To run the tests locally, running the `make unit` command will `go get` the
SDK's testing dependencies, and run vet, link and unit tests for the SDK.
```
make unit
```
Standard go testing functionality is supported as well. To test SDK code that
is tagged with `codegen` you'll need to set the build tag in the go test
command. The `make unit` command will do this automatically.
```
go test -tags codegen ./private/...
```
See the `Makefile` for additional testing tags that can be used in testing.
To test on multiple platform the SDK includes several DockerFiles under the
`awstesting/sandbox` folder, and associated make recipes to to execute
unit testing within environments configured for specific Go versions.
```
make sandbox-test-go18
```
To run all sandbox environments use the following make recipe
```
# Optionally update the Go tip that will be used during the batch testing
make update-aws-golang-tip
# Run all SDK tests for supported Go versions in sandboxes
make sandbox-test
```
In addition the sandbox environment include make recipes for interactive modes
so you can run command within the Docker container and context of the SDK.
```
make sandbox-go18
```
### Changelog
You can see all release changes in the `CHANGELOG.md` file at the root of the
repository. The release notes added to this file will contain service client
updates, and major SDK changes.
[issues]: https://github.com/aws/aws-sdk-go/issues
[pr]: https://github.com/aws/aws-sdk-go/pulls
[license]: http://aws.amazon.com/apache2.0/
[cla]: http://en.wikipedia.org/wiki/Contributor_License_Agreement
[releasenotes]: https://github.com/aws/aws-sdk-go/releases
-180
View File
@@ -1,180 +0,0 @@
LINTIGNOREDOT='awstesting/integration.+should not use dot imports'
LINTIGNOREDOC='service/[^/]+/(api|service|waiters)\.go:.+(comment on exported|should have comment or be unexported)'
LINTIGNORECONST='service/[^/]+/(api|service|waiters)\.go:.+(type|struct field|const|func) ([^ ]+) should be ([^ ]+)'
LINTIGNORESTUTTER='service/[^/]+/(api|service)\.go:.+(and that stutters)'
LINTIGNOREINFLECT='service/[^/]+/(api|errors|service)\.go:.+(method|const) .+ should be '
LINTIGNOREINFLECTS3UPLOAD='service/s3/s3manager/upload\.go:.+struct field SSEKMSKeyId should be '
LINTIGNOREDEPS='vendor/.+\.go'
LINTIGNOREPKGCOMMENT='service/[^/]+/doc_custom.go:.+package comment should be of the form'
UNIT_TEST_TAGS="example codegen awsinclude"
SDK_WITH_VENDOR_PKGS=$(shell go list -tags ${UNIT_TEST_TAGS} ./... | grep -v "/vendor/src")
SDK_ONLY_PKGS=$(shell go list ./... | grep -v "/vendor/")
SDK_UNIT_TEST_ONLY_PKGS=$(shell go list -tags ${UNIT_TEST_TAGS} ./... | grep -v "/vendor/")
SDK_GO_1_4=$(shell go version | grep "go1.4")
SDK_GO_1_5=$(shell go version | grep "go1.5")
SDK_GO_VERSION=$(shell go version | awk '''{print $$3}''' | tr -d '''\n''')
all: get-deps generate unit
help:
@echo "Please use \`make <target>' where <target> is one of"
@echo " api_info to print a list of services and versions"
@echo " docs to build SDK documentation"
@echo " build to go build the SDK"
@echo " unit to run unit tests"
@echo " integration to run integration tests"
@echo " performance to run performance tests"
@echo " verify to verify tests"
@echo " lint to lint the SDK"
@echo " vet to vet the SDK"
@echo " generate to go generate and make services"
@echo " gen-test to generate protocol tests"
@echo " gen-services to generate services"
@echo " get-deps to go get the SDK dependencies"
@echo " get-deps-tests to get the SDK's test dependencies"
@echo " get-deps-verify to get the SDK's verification dependencies"
generate: gen-test gen-endpoints gen-services
gen-test: gen-protocol-test
gen-services:
go generate ./service
gen-protocol-test:
go generate ./private/protocol/...
gen-endpoints:
go generate ./models/endpoints/
build:
@echo "go build SDK and vendor packages"
@go build ${SDK_ONLY_PKGS}
unit: get-deps-tests build verify
@echo "go test SDK and vendor packages"
@go test -tags ${UNIT_TEST_TAGS} $(SDK_UNIT_TEST_ONLY_PKGS)
unit-with-race-cover: get-deps-tests build verify
@echo "go test SDK and vendor packages"
@go test -tags ${UNIT_TEST_TAGS} -race -cpu=1,2,4 $(SDK_UNIT_TEST_ONLY_PKGS)
integration: get-deps-tests integ-custom smoke-tests performance
integ-custom:
go test -tags "integration" ./awstesting/integration/customizations/...
cleanup-integ:
go run -tags "integration" ./awstesting/cmd/bucket_cleanup/main.go "aws-sdk-go-integration"
smoke-tests: get-deps-tests
gucumber -go-tags "integration" ./awstesting/integration/smoke
performance: get-deps-tests
AWS_TESTING_LOG_RESULTS=${log-detailed} AWS_TESTING_REGION=$(region) AWS_TESTING_DB_TABLE=$(table) gucumber -go-tags "integration" ./awstesting/performance
sandbox-tests: sandbox-test-go15 sandbox-test-go15-novendorexp sandbox-test-go16 sandbox-test-go17 sandbox-test-go18 sandbox-test-gotip
sandbox-build-go15:
docker build -f ./awstesting/sandbox/Dockerfile.test.go1.5 -t "aws-sdk-go-1.5" .
sandbox-go15: sandbox-build-go15
docker run -i -t aws-sdk-go-1.5 bash
sandbox-test-go15: sandbox-build-go15
docker run -t aws-sdk-go-1.5
sandbox-build-go15-novendorexp:
docker build -f ./awstesting/sandbox/Dockerfile.test.go1.5-novendorexp -t "aws-sdk-go-1.5-novendorexp" .
sandbox-go15-novendorexp: sandbox-build-go15-novendorexp
docker run -i -t aws-sdk-go-1.5-novendorexp bash
sandbox-test-go15-novendorexp: sandbox-build-go15-novendorexp
docker run -t aws-sdk-go-1.5-novendorexp
sandbox-build-go16:
docker build -f ./awstesting/sandbox/Dockerfile.test.go1.6 -t "aws-sdk-go-1.6" .
sandbox-go16: sandbox-build-go16
docker run -i -t aws-sdk-go-1.6 bash
sandbox-test-go16: sandbox-build-go16
docker run -t aws-sdk-go-1.6
sandbox-build-go17:
docker build -f ./awstesting/sandbox/Dockerfile.test.go1.7 -t "aws-sdk-go-1.7" .
sandbox-go17: sandbox-build-go17
docker run -i -t aws-sdk-go-1.7 bash
sandbox-test-go17: sandbox-build-go17
docker run -t aws-sdk-go-1.7
sandbox-build-go18:
docker build -f ./awstesting/sandbox/Dockerfile.test.go1.8 -t "aws-sdk-go-1.8" .
sandbox-go18: sandbox-build-go18
docker run -i -t aws-sdk-go-1.8 bash
sandbox-test-go18: sandbox-build-go18
docker run -t aws-sdk-go-1.8
sandbox-build-gotip:
@echo "Run make update-aws-golang-tip, if this test fails because missing aws-golang:tip container"
docker build -f ./awstesting/sandbox/Dockerfile.test.gotip -t "aws-sdk-go-tip" .
sandbox-gotip: sandbox-build-gotip
docker run -i -t aws-sdk-go-tip bash
sandbox-test-gotip: sandbox-build-gotip
docker run -t aws-sdk-go-tip
update-aws-golang-tip:
docker build --no-cache=true -f ./awstesting/sandbox/Dockerfile.golang-tip -t "aws-golang:tip" .
verify: get-deps-verify lint vet
lint:
@echo "go lint SDK and vendor packages"
@lint=`if [ \( -z "${SDK_GO_1_4}" \) -a \( -z "${SDK_GO_1_5}" \) ]; then golint ./...; else echo "skipping golint"; fi`; \
lint=`echo "$$lint" | grep -E -v -e ${LINTIGNOREDOT} -e ${LINTIGNOREDOC} -e ${LINTIGNORECONST} -e ${LINTIGNORESTUTTER} -e ${LINTIGNOREINFLECT} -e ${LINTIGNOREDEPS} -e ${LINTIGNOREINFLECTS3UPLOAD} -e ${LINTIGNOREPKGCOMMENT}`; \
echo "$$lint"; \
if [ "$$lint" != "" ] && [ "$$lint" != "skipping golint" ]; then exit 1; fi
SDK_BASE_FOLDERS=$(shell ls -d */ | grep -v vendor | grep -v awsmigrate)
ifneq (,$(findstring go1.4, ${SDK_GO_VERSION}))
GO_VET_CMD=echo skipping go vet, ${SDK_GO_VERSION}
else ifneq (,$(findstring go1.6, ${SDK_GO_VERSION}))
GO_VET_CMD=go tool vet --all -shadow -example=false
else
GO_VET_CMD=go tool vet --all -shadow
endif
vet:
${GO_VET_CMD} ${SDK_BASE_FOLDERS}
get-deps: get-deps-tests get-deps-verify
@echo "go get SDK dependencies"
@go get -v $(SDK_ONLY_PKGS)
get-deps-tests:
@echo "go get SDK testing dependencies"
go get github.com/gucumber/gucumber/cmd/gucumber
go get github.com/stretchr/testify
go get github.com/smartystreets/goconvey
go get golang.org/x/net/html
go get golang.org/x/net/http2
get-deps-verify:
@echo "go get SDK verification utilities"
@if [ \( -z "${SDK_GO_1_4}" \) -a \( -z "${SDK_GO_1_5}" \) ]; then go get github.com/golang/lint/golint; else echo "skipped getting golint"; fi
bench:
@echo "go bench SDK packages"
@go test -run NONE -bench . -benchmem -tags 'bench' $(SDK_ONLY_PKGS)
bench-protocol:
@echo "go bench SDK protocol marshallers"
@go test -run NONE -bench . -benchmem -tags 'bench' ./private/protocol/...
docs:
@echo "generate SDK docs"
@# This env variable, DOCS, is for internal use
@if [ -z ${AWS_DOC_GEN_TOOL} ]; then\
rm -rf doc && bundle install && bundle exec yard;\
else\
$(AWS_DOC_GEN_TOOL) `pwd`;\
fi
api_info:
@go run private/model/cli/api-info/api-info.go
-449
View File
@@ -1,449 +0,0 @@
[![API Reference](http://img.shields.io/badge/api-reference-blue.svg)](http://docs.aws.amazon.com/sdk-for-go/api) [![Join the chat at https://gitter.im/aws/aws-sdk-go](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/aws/aws-sdk-go?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Build Status](https://img.shields.io/travis/aws/aws-sdk-go.svg)](https://travis-ci.org/aws/aws-sdk-go) [![Apache V2 License](http://img.shields.io/badge/license-Apache%20V2-blue.svg)](https://github.com/aws/aws-sdk-go/blob/master/LICENSE.txt)
# AWS SDK for Go
aws-sdk-go is the official AWS SDK for the Go programming language.
Checkout our [release notes](https://github.com/aws/aws-sdk-go/releases) for information about the latest bug fixes, updates, and features added to the SDK.
## Installing
If you are using Go 1.5 with the `GO15VENDOREXPERIMENT=1` vendoring flag, or 1.6 and higher you can use the following command to retrieve the SDK. The SDK's non-testing dependencies will be included and are vendored in the `vendor` folder.
go get -u github.com/aws/aws-sdk-go
Otherwise if your Go environment does not have vendoring support enabled, or you do not want to include the vendored SDK's dependencies you can use the following command to retrieve the SDK and its non-testing dependencies using `go get`.
go get -u github.com/aws/aws-sdk-go/aws/...
go get -u github.com/aws/aws-sdk-go/service/...
If you're looking to retrieve just the SDK without any dependencies use the following command.
go get -d github.com/aws/aws-sdk-go/
These two processes will still include the `vendor` folder and it should be deleted if its not going to be used by your environment.
rm -rf $GOPATH/src/github.com/aws/aws-sdk-go/vendor
## Getting Help
Please use these community resources for getting help. We use the GitHub issues for tracking bugs and feature requests.
* Ask a question on [StackOverflow](http://stackoverflow.com/) and tag it with the [`aws-sdk-go`](http://stackoverflow.com/questions/tagged/aws-sdk-go) tag.
* Come join the AWS SDK for Go community chat on [gitter](https://gitter.im/aws/aws-sdk-go).
* Open a support ticket with [AWS Support](http://docs.aws.amazon.com/awssupport/latest/user/getting-started.html).
* If you think you may have found a bug, please open an [issue](https://github.com/aws/aws-sdk-go/issues/new).
## Opening Issues
If you encounter a bug with the AWS SDK for Go we would like to hear about it. Search the [existing issues](https://github.com/aws/aws-sdk-go/issues) and see if others are also experiencing the issue before opening a new issue. Please include the version of AWS SDK for Go, Go language, and OS you’re using. Please also include repro case when appropriate.
The GitHub issues are intended for bug reports and feature requests. For help and questions with using AWS SDK for GO please make use of the resources listed in the [Getting Help](https://github.com/aws/aws-sdk-go#getting-help) section. Keeping the list of open issues lean will help us respond in a timely manner.
## Reference Documentation
[`Getting Started Guide`](https://aws.amazon.com/sdk-for-go/) - This document is a general introduction how to configure and make requests with the SDK. If this is your first time using the SDK, this documentation and the API documentation will help you get started. This document focuses on the syntax and behavior of the SDK. The [Service Developer Guide](https://aws.amazon.com/documentation/) will help you get started using specific AWS services.
[`SDK API Reference Documentation`](https://docs.aws.amazon.com/sdk-for-go/api/) - Use this document to look up all API operation input and output parameters for AWS services supported by the SDK. The API reference also includes documentation of the SDK, and examples how to using the SDK, service client API operations, and API operation require parameters.
[`Service Developer Guide`](https://aws.amazon.com/documentation/) - Use this documentation to learn how to interface with an AWS service. These are great guides both, if you're getting started with a service, or looking for more information on a service. You should not need this document for coding, though in some cases, services may supply helpful samples that you might want to look out for.
[`SDK Examples`](https://github.com/aws/aws-sdk-go/tree/master/example) - Included in the SDK's repo are a several hand crafted examples using the SDK features and AWS services.
## Overview of SDK's Packages
The SDK is composed of two main components, SDK core, and service clients.
The SDK core packages are all available under the aws package at the root of
the SDK. Each client for a supported AWS service is available within its own
package under the service folder at the root of the SDK.
* aws - SDK core, provides common shared types such as Config, Logger,
and utilities to make working with API parameters easier.
* awserr - Provides the error interface that the SDK will use for all
errors that occur in the SDK's processing. This includes service API
response errors as well. The Error type is made up of a code and message.
Cast the SDK's returned error type to awserr.Error and call the Code
method to compare returned error to specific error codes. See the package's
documentation for additional values that can be extracted such as RequestID.
* credentials - Provides the types and built in credentials providers
the SDK will use to retrieve AWS credentials to make API requests with.
Nested under this folder are also additional credentials providers such as
stscreds for assuming IAM roles, and ec2rolecreds for EC2 Instance roles.
* endpoints - Provides the AWS Regions and Endpoints metadata for the SDK.
Use this to lookup AWS service endpoint information such as which services
are in a region, and what regions a service is in. Constants are also provided
for all region identifiers, e.g UsWest2RegionID for "us-west-2".
* session - Provides initial default configuration, and load
configuration from external sources such as environment and shared
credentials file.
* request - Provides the API request sending, and retry logic for the SDK.
This package also includes utilities for defining your own request
retryer, and configuring how the SDK processes the request.
* service - Clients for AWS services. All services supported by the SDK are
available under this folder.
## How to Use the SDK's AWS Service Clients
The SDK includes the Go types and utilities you can use to make requests to
AWS service APIs. Within the service folder at the root of the SDK you'll find
a package for each AWS service the SDK supports. All service clients follows
a common pattern of creation and usage.
When creating a client for an AWS service you'll first need to have a Session
value constructed. The Session provides shared configuration that can be shared
between your service clients. When service clients are created you can pass
in additional configuration via the aws.Config type to override configuration
provided by in the Session to create service client instances with custom
configuration.
Once the service's client is created you can use it to make API requests the
AWS service. These clients are safe to use concurrently.
## Configuring the SDK
In the AWS SDK for Go, you can configure settings for service clients, such
as the log level and maximum number of retries. Most settings are optional;
however, for each service client, you must specify a region and your credentials.
The SDK uses these values to send requests to the correct AWS region and sign
requests with the correct credentials. You can specify these values as part
of a session or as environment variables.
See the SDK's [configuration guide][config_guide] for more information.
See the [session][session_pkg] package documentation for more information on how to use Session
with the SDK.
See the [Config][config_typ] type in the [aws][aws_pkg] package for more information on configuration
options.
[config_guide]: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html
[session_pkg]: https://docs.aws.amazon.com/sdk-for-go/api/aws/session/
[config_typ]: https://docs.aws.amazon.com/sdk-for-go/api/aws/#Config
[aws_pkg]: https://docs.aws.amazon.com/sdk-for-go/api/aws/
### Configuring Credentials
When using the SDK you'll generally need your AWS credentials to authenticate
with AWS services. The SDK supports multiple methods of supporting these
credentials. By default the SDK will source credentials automatically from
its default credential chain. See the session package for more information
on this chain, and how to configure it. The common items in the credential
chain are the following:
* Environment Credentials - Set of environment variables that are useful
when sub processes are created for specific roles.
* Shared Credentials file (~/.aws/credentials) - This file stores your
credentials based on a profile name and is useful for local development.
* EC2 Instance Role Credentials - Use EC2 Instance Role to assign credentials
to application running on an EC2 instance. This removes the need to manage
credential files in production.
Credentials can be configured in code as well by setting the Config's Credentials
value to a custom provider or using one of the providers included with the
SDK to bypass the default credential chain and use a custom one. This is
helpful when you want to instruct the SDK to only use a specific set of
credentials or providers.
This example creates a credential provider for assuming an IAM role, "myRoleARN"
and configures the S3 service client to use that role for API requests.
```go
// Initial credentials loaded from SDK's default credential chain. Such as
// the environment, shared credentials (~/.aws/credentials), or EC2 Instance
// Role. These credentials will be used to to make the STS Assume Role API.
sess := session.Must(session.NewSession())
// Create the credentials from AssumeRoleProvider to assume the role
// referenced by the "myRoleARN" ARN.
creds := stscreds.NewCredentials(sess, "myRoleArn")
// Create service client value configured for credentials
// from assumed role.
svc := s3.New(sess, &aws.Config{Credentials: creds})/
```
See the [credentials][credentials_pkg] package documentation for more information on credential
providers included with the SDK, and how to customize the SDK's usage of
credentials.
The SDK has support for the shared configuration file (~/.aws/config). This
support can be enabled by setting the environment variable, "AWS_SDK_LOAD_CONFIG=1",
or enabling the feature in code when creating a Session via the
Option's SharedConfigState parameter.
```go
sess := session.Must(session.NewSessionWithOptions(session.Options{
SharedConfigState: session.SharedConfigEnable,
}))
```
[credentials_pkg]: ttps://docs.aws.amazon.com/sdk-for-go/api/aws/credentials
### Configuring AWS Region
In addition to the credentials you'll need to specify the region the SDK
will use to make AWS API requests to. In the SDK you can specify the region
either with an environment variable, or directly in code when a Session or
service client is created. The last value specified in code wins if the region
is specified multiple ways.
To set the region via the environment variable set the "AWS_REGION" to the
region you want to the SDK to use. Using this method to set the region will
allow you to run your application in multiple regions without needing additional
code in the application to select the region.
AWS_REGION=us-west-2
The endpoints package includes constants for all regions the SDK knows. The
values are all suffixed with RegionID. These values are helpful, because they
reduce the need to type the region string manually.
To set the region on a Session use the aws package's Config struct parameter
Region to the AWS region you want the service clients created from the session to
use. This is helpful when you want to create multiple service clients, and
all of the clients make API requests to the same region.
```go
sess := session.Must(session.NewSession(&aws.Config{
Region: aws.String(endpoints.UsWest2RegionID),
}))
```
See the [endpoints][endpoints_pkg] package for the AWS Regions and Endpoints metadata.
In addition to setting the region when creating a Session you can also set
the region on a per service client bases. This overrides the region of a
Session. This is helpful when you want to create service clients in specific
regions different from the Session's region.
```go
svc := s3.New(sess, &aws.Config{
Region: aws.String(endpoints.UsWest2RegionID),
})
```
See the [Config][config_typ] type in the [aws][aws_pkg] package for more information and additional
options such as setting the Endpoint, and other service client configuration options.
[endpoints_pkg]: https://docs.aws.amazon.com/sdk-for-go/api/aws/endpoints/
## Making API Requests
Once the client is created you can make an API request to the service.
Each API method takes a input parameter, and returns the service response
and an error. The SDK provides methods for making the API call in multiple ways.
In this list we'll use the S3 ListObjects API as an example for the different
ways of making API requests.
* ListObjects - Base API operation that will make the API request to the service.
* ListObjectsRequest - API methods suffixed with Request will construct the
API request, but not send it. This is also helpful when you want to get a
presigned URL for a request, and share the presigned URL instead of your
application making the request directly.
* ListObjectsPages - Same as the base API operation, but uses a callback to
automatically handle pagination of the API's response.
* ListObjectsWithContext - Same as base API operation, but adds support for
the Context pattern. This is helpful for controlling the canceling of in
flight requests. See the Go standard library context package for more
information. This method also takes request package's Option functional
options as the variadic argument for modifying how the request will be
made, or extracting information from the raw HTTP response.
* ListObjectsPagesWithContext - same as ListObjectsPages, but adds support for
the Context pattern. Similar to ListObjectsWithContext this method also
takes the request package's Option function option types as the variadic
argument.
In addition to the API operations the SDK also includes several higher level
methods that abstract checking for and waiting for an AWS resource to be in
a desired state. In this list we'll use WaitUntilBucketExists to demonstrate
the different forms of waiters.
* WaitUntilBucketExists. - Method to make API request to query an AWS service for
a resource's state. Will return successfully when that state is accomplished.
* WaitUntilBucketExistsWithContext - Same as WaitUntilBucketExists, but adds
support for the Context pattern. In addition these methods take request
package's WaiterOptions to configure the waiter, and how underlying request
will be made by the SDK.
The API method will document which error codes the service might return for
the operation. These errors will also be available as const strings prefixed
with "ErrCode" in the service client's package. If there are no errors listed
in the API's SDK documentation you'll need to consult the AWS service's API
documentation for the errors that could be returned.
```go
ctx := context.Background()
result, err := svc.GetObjectWithContext(ctx, &s3.GetObjectInput{
Bucket: aws.String("my-bucket"),
Key: aws.String("my-key"),
})
if err != nil {
// Cast err to awserr.Error to handle specific error codes.
aerr, ok := err.(awserr.Error)
if ok && aerr.Code() == s3.ErrCodeNoSuchKey {
// Specific error code handling
}
return err
}
// Make sure to close the body when done with it for S3 GetObject APIs or
// will leak connections.
defer result.Body.Close()
fmt.Println("Object Size:", aws.StringValue(result.ContentLength))
```
### API Request Pagination and Resource Waiters
Pagination helper methods are suffixed with "Pages", and provide the
functionality needed to round trip API page requests. Pagination methods
take a callback function that will be called for each page of the API's response.
```go
objects := []string{}
err := svc.ListObjectsPagesWithContext(ctx, &s3.ListObjectsInput{
Bucket: aws.String(myBucket),
}, func(p *s3.ListObjectsOutput, lastPage bool) bool {
for _, o := range p.Contents {
objects = append(objects, aws.StringValue(o.Key))
}
return true // continue paging
})
if err != nil {
panic(fmt.Sprintf("failed to list objects for bucket, %s, %v", myBucket, err))
}
fmt.Println("Objects in bucket:", objects)
```
Waiter helper methods provide the functionality to wait for an AWS resource
state. These methods abstract the logic needed to to check the state of an
AWS resource, and wait until that resource is in a desired state. The waiter
will block until the resource is in the state that is desired, an error occurs,
or the waiter times out. If a resource times out the error code returned will
be request.WaiterResourceNotReadyErrorCode.
```go
err := svc.WaitUntilBucketExistsWithContext(ctx, &s3.HeadBucketInput{
Bucket: aws.String(myBucket),
})
if err != nil {
aerr, ok := err.(awserr.Error)
if ok && aerr.Code() == request.WaiterResourceNotReadyErrorCode {
fmt.Fprintf(os.Stderr, "timed out while waiting for bucket to exist")
}
panic(fmt.Errorf("failed to wait for bucket to exist, %v", err))
}
fmt.Println("Bucket", myBucket, "exists")
```
## Complete SDK Example
This example shows a complete working Go file which will upload a file to S3
and use the Context pattern to implement timeout logic that will cancel the
request if it takes too long. This example highlights how to use sessions,
create a service client, make a request, handle the error, and process the
response.
```go
package main
import (
"context"
"flag"
"fmt"
"os"
"time"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/request"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/s3"
)
// Uploads a file to S3 given a bucket and object key. Also takes a duration
// value to terminate the update if it doesn't complete within that time.
//
// The AWS Region needs to be provided in the AWS shared config or on the
// environment variable as `AWS_REGION`. Credentials also must be provided
// Will default to shared config file, but can load from environment if provided.
//
// Usage:
// # Upload myfile.txt to myBucket/myKey. Must complete within 10 minutes or will fail
// go run withContext.go -b mybucket -k myKey -d 10m < myfile.txt
func main() {
var bucket, key string
var timeout time.Duration
flag.StringVar(&bucket, "b", "", "Bucket name.")
flag.StringVar(&key, "k", "", "Object key name.")
flag.DurationVar(&timeout, "d", 0, "Upload timeout.")
flag.Parse()
// All clients require a Session. The Session provides the client with
// shared configuration such as region, endpoint, and credentials. A
// Session should be shared where possible to take advantage of
// configuration and credential caching. See the session package for
// more information.
sess := session.Must(session.NewSession())
// Create a new instance of the service's client with a Session.
// Optional aws.Config values can also be provided as variadic arguments
// to the New function. This option allows you to provide service
// specific configuration.
svc := s3.New(sess)
// Create a context with a timeout that will abort the upload if it takes
// more than the passed in timeout.
ctx := context.Background()
var cancelFn func()
if timeout > 0 {
ctx, cancelFn = context.WithTimeout(ctx, timeout)
}
// Ensure the context is canceled to prevent leaking.
// See context package for more information, https://golang.org/pkg/context/
defer cancelFn()
// Uploads the object to S3. The Context will interrupt the request if the
// timeout expires.
_, err := svc.PutObjectWithContext(ctx, &s3.PutObjectInput{
Bucket: aws.String(bucket),
Key: aws.String(key),
Body: os.Stdin,
})
if err != nil {
if aerr, ok := err.(awserr.Error); ok && aerr.Code() == request.CanceledErrorCode {
// If the SDK can determine the request or retry delay was canceled
// by a context the CanceledErrorCode error code will be returned.
fmt.Fprintf(os.Stderr, "upload canceled due to timeout, %v\n", err)
} else {
fmt.Fprintf(os.Stderr, "failed to upload object, %v\n", err)
}
os.Exit(1)
}
fmt.Printf("successfully uploaded file to %s/%s\n", bucket, key)
}
```
## License
This SDK is distributed under the
[Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0),
see LICENSE.txt and NOTICE.txt for more information.
+50 -8
View File
@@ -2,6 +2,7 @@ package client
import (
"math/rand"
"strconv"
"sync"
"time"
@@ -38,14 +39,18 @@ func (d DefaultRetryer) RetryRules(r *request.Request) time.Duration {
minTime := 30
throttle := d.shouldThrottle(r)
if throttle {
if delay, ok := getRetryDelay(r); ok {
return delay
}
minTime = 500
}
retryCount := r.RetryCount
if retryCount > 13 {
retryCount = 13
} else if throttle && retryCount > 8 {
if throttle && retryCount > 8 {
retryCount = 8
} else if retryCount > 13 {
retryCount = 13
}
delay := (1 << uint(retryCount)) * (seededRand.Intn(minTime) + minTime)
@@ -68,12 +73,49 @@ func (d DefaultRetryer) ShouldRetry(r *request.Request) bool {
// ShouldThrottle returns true if the request should be throttled.
func (d DefaultRetryer) shouldThrottle(r *request.Request) bool {
if r.HTTPResponse.StatusCode == 502 ||
r.HTTPResponse.StatusCode == 503 ||
r.HTTPResponse.StatusCode == 504 {
return true
switch r.HTTPResponse.StatusCode {
case 429:
case 502:
case 503:
case 504:
default:
return r.IsErrorThrottle()
}
return r.IsErrorThrottle()
return true
}
// This will look in the Retry-After header, RFC 7231, for how long
// it will wait before attempting another request
func getRetryDelay(r *request.Request) (time.Duration, bool) {
if !canUseRetryAfterHeader(r) {
return 0, false
}
delayStr := r.HTTPResponse.Header.Get("Retry-After")
if len(delayStr) == 0 {
return 0, false
}
delay, err := strconv.Atoi(delayStr)
if err != nil {
return 0, false
}
return time.Duration(delay) * time.Second, true
}
// Will look at the status code to see if the retry header pertains to
// the status code.
func canUseRetryAfterHeader(r *request.Request) bool {
switch r.HTTPResponse.StatusCode {
case 429:
case 503:
default:
return false
}
return true
}
// lockedSource is a thread-safe implementation of rand.Source
+1 -1
View File
@@ -168,7 +168,7 @@ type Config struct {
//
EC2MetadataDisableTimeoutOverride *bool
// Instructs the endpiont to be generated for a service client to
// Instructs the endpoint to be generated for a service client to
// be the dual stack endpoint. The dual stack endpoint will support
// both IPv4 and IPv6 addressing.
//
+3 -3
View File
@@ -4,9 +4,9 @@ package aws
import "time"
// An emptyCtx is a copy of the the Go 1.7 context.emptyCtx type. This
// is copied to provide a 1.6 and 1.5 safe version of context that is compatible
// with Go 1.7's Context.
// An emptyCtx is a copy of the Go 1.7 context.emptyCtx type. This is copied to
// provide a 1.6 and 1.5 safe version of context that is compatible with Go
// 1.7's Context.
//
// An emptyCtx is never canceled, has no values, and has no deadline. It is not
// struct{}, since vars of this type must have distinct addresses.
+18
View File
@@ -311,6 +311,24 @@ func TimeValue(v *time.Time) time.Time {
return time.Time{}
}
// SecondsTimeValue converts an int64 pointer to a time.Time value
// representing seconds since Epoch or time.Time{} if the pointer is nil.
func SecondsTimeValue(v *int64) time.Time {
if v != nil {
return time.Unix((*v / 1000), 0)
}
return time.Time{}
}
// MillisecondsTimeValue converts an int64 pointer to a time.Time value
// representing milliseconds sinch Epoch or time.Time{} if the pointer is nil.
func MillisecondsTimeValue(v *int64) time.Time {
if v != nil {
return time.Unix(0, (*v * 1000000))
}
return time.Time{}
}
// TimeUnixMilli returns a Unix timestamp in milliseconds from "January 1, 1970 UTC".
// The result is undefined if the Unix time cannot be represented by an int64.
// Which includes calling TimeUnixMilli on a zero Time is undefined.
-12
View File
@@ -1,12 +0,0 @@
[default]
aws_access_key_id = accessKey
aws_secret_access_key = secret
aws_session_token = token
[no_token]
aws_access_key_id = accessKey
aws_secret_access_key = secret
[with_colon]
aws_access_key_id: accessKey
aws_secret_access_key: secret
+32 -2
View File
@@ -9,6 +9,7 @@ package defaults
import (
"fmt"
"net"
"net/http"
"net/url"
"os"
@@ -118,14 +119,43 @@ func RemoteCredProvider(cfg aws.Config, handlers request.Handlers) credentials.P
return ec2RoleProvider(cfg, handlers)
}
var lookupHostFn = net.LookupHost
func isLoopbackHost(host string) (bool, error) {
ip := net.ParseIP(host)
if ip != nil {
return ip.IsLoopback(), nil
}
// Host is not an ip, perform lookup
addrs, err := lookupHostFn(host)
if err != nil {
return false, err
}
for _, addr := range addrs {
if !net.ParseIP(addr).IsLoopback() {
return false, nil
}
}
return true, nil
}
func localHTTPCredProvider(cfg aws.Config, handlers request.Handlers, u string) credentials.Provider {
var errMsg string
parsed, err := url.Parse(u)
if err != nil {
errMsg = fmt.Sprintf("invalid URL, %v", err)
} else if host := aws.URLHostname(parsed); !(host == "localhost" || host == "127.0.0.1") {
errMsg = fmt.Sprintf("invalid host address, %q, only localhost and 127.0.0.1 are valid.", host)
} else {
host := aws.URLHostname(parsed)
if len(host) == 0 {
errMsg = "unable to parse host from local HTTP cred provider URL"
} else if isLoopback, loopbackErr := isLoopbackHost(host); loopbackErr != nil {
errMsg = fmt.Sprintf("failed to resolve host %q, %v", host, loopbackErr)
} else if !isLoopback {
errMsg = fmt.Sprintf("invalid endpoint host, %q, only loopback hosts are allowed.", host)
}
}
if len(errMsg) > 0 {
File diff suppressed because it is too large Load Diff
+126 -22
View File
@@ -24,10 +24,14 @@ const (
// ErrCodeRead is an error that is returned during HTTP reads.
ErrCodeRead = "ReadError"
// ErrCodeResponseTimeout is the connection timeout error that is recieved
// ErrCodeResponseTimeout is the connection timeout error that is received
// during body reads.
ErrCodeResponseTimeout = "ResponseTimeout"
// ErrCodeInvalidPresignExpire is returned when the expire time provided to
// presign is invalid
ErrCodeInvalidPresignExpire = "InvalidPresignExpireError"
// CanceledErrorCode is the error code that will be returned by an
// API request that was canceled. Requests given a aws.Context may
// return this error when canceled.
@@ -42,7 +46,6 @@ type Request struct {
Retryer
Time time.Time
ExpireTime time.Duration
Operation *Operation
HTTPRequest *http.Request
HTTPResponse *http.Response
@@ -60,6 +63,11 @@ type Request struct {
LastSignedAt time.Time
DisableFollowRedirects bool
// A value greater than 0 instructs the request to be signed as Presigned URL
// You should not set this field directly. Instead use Request's
// Presign or PresignRequest methods.
ExpireTime time.Duration
context aws.Context
built bool
@@ -104,6 +112,8 @@ func New(cfg aws.Config, clientInfo metadata.ClientInfo, handlers Handlers,
err = awserr.New("InvalidEndpointURL", "invalid endpoint uri", err)
}
SanitizeHostForHeader(httpReq)
r := &Request{
Config: cfg,
ClientInfo: clientInfo,
@@ -250,34 +260,59 @@ func (r *Request) SetReaderBody(reader io.ReadSeeker) {
// Presign returns the request's signed URL. Error will be returned
// if the signing fails.
func (r *Request) Presign(expireTime time.Duration) (string, error) {
r.ExpireTime = expireTime
//
// It is invalid to create a presigned URL with a expire duration 0 or less. An
// error is returned if expire duration is 0 or less.
func (r *Request) Presign(expire time.Duration) (string, error) {
r = r.copy()
// Presign requires all headers be hoisted. There is no way to retrieve
// the signed headers not hoisted without this. Making the presigned URL
// useless.
r.NotHoist = false
u, _, err := getPresignedURL(r, expire)
return u, err
}
// PresignRequest behaves just like presign, with the addition of returning a
// set of headers that were signed.
//
// It is invalid to create a presigned URL with a expire duration 0 or less. An
// error is returned if expire duration is 0 or less.
//
// Returns the URL string for the API operation with signature in the query string,
// and the HTTP headers that were included in the signature. These headers must
// be included in any HTTP request made with the presigned URL.
//
// To prevent hoisting any headers to the query string set NotHoist to true on
// this Request value prior to calling PresignRequest.
func (r *Request) PresignRequest(expire time.Duration) (string, http.Header, error) {
r = r.copy()
return getPresignedURL(r, expire)
}
func getPresignedURL(r *Request, expire time.Duration) (string, http.Header, error) {
if expire <= 0 {
return "", nil, awserr.New(
ErrCodeInvalidPresignExpire,
"presigned URL requires an expire duration greater than 0",
nil,
)
}
r.ExpireTime = expire
if r.Operation.BeforePresignFn != nil {
r = r.copy()
err := r.Operation.BeforePresignFn(r)
if err != nil {
return "", err
if err := r.Operation.BeforePresignFn(r); err != nil {
return "", nil, err
}
}
r.Sign()
if r.Error != nil {
return "", r.Error
if err := r.Sign(); err != nil {
return "", nil, err
}
return r.HTTPRequest.URL.String(), nil
}
// PresignRequest behaves just like presign, but hoists all headers and signs them.
// Also returns the signed hash back to the user
func (r *Request) PresignRequest(expireTime time.Duration) (string, http.Header, error) {
r.ExpireTime = expireTime
r.NotHoist = true
r.Sign()
if r.Error != nil {
return "", nil, r.Error
}
return r.HTTPRequest.URL.String(), r.SignedHeaderVals, nil
}
@@ -573,3 +608,72 @@ func shouldRetryCancel(r *Request) bool {
errStr != "net/http: request canceled while waiting for connection")
}
// SanitizeHostForHeader removes default port from host and updates request.Host
func SanitizeHostForHeader(r *http.Request) {
host := getHost(r)
port := portOnly(host)
if port != "" && isDefaultPort(r.URL.Scheme, port) {
r.Host = stripPort(host)
}
}
// Returns host from request
func getHost(r *http.Request) string {
if r.Host != "" {
return r.Host
}
return r.URL.Host
}
// Hostname returns u.Host, without any port number.
//
// If Host is an IPv6 literal with a port number, Hostname returns the
// IPv6 literal without the square brackets. IPv6 literals may include
// a zone identifier.
//
// Copied from the Go 1.8 standard library (net/url)
func stripPort(hostport string) string {
colon := strings.IndexByte(hostport, ':')
if colon == -1 {
return hostport
}
if i := strings.IndexByte(hostport, ']'); i != -1 {
return strings.TrimPrefix(hostport[:i], "[")
}
return hostport[:colon]
}
// Port returns the port part of u.Host, without the leading colon.
// If u.Host doesn't contain a port, Port returns an empty string.
//
// Copied from the Go 1.8 standard library (net/url)
func portOnly(hostport string) string {
colon := strings.IndexByte(hostport, ':')
if colon == -1 {
return ""
}
if i := strings.Index(hostport, "]:"); i != -1 {
return hostport[i+len("]:"):]
}
if strings.Contains(hostport, "]") {
return ""
}
return hostport[colon+len(":"):]
}
// Returns true if the specified URI is using the standard port
// (i.e. port 80 for HTTP URIs or 443 for HTTPS URIs)
func isDefaultPort(scheme, port string) bool {
if port == "" {
return true
}
lowerCaseScheme := strings.ToLower(scheme)
if (lowerCaseScheme == "http" && port == "80") || (lowerCaseScheme == "https" && port == "443") {
return true
}
return false
}
+2 -2
View File
@@ -70,8 +70,8 @@ func isCodeExpiredCreds(code string) bool {
}
var validParentCodes = map[string]struct{}{
ErrCodeSerialization: struct{}{},
ErrCodeRead: struct{}{},
ErrCodeSerialization: {},
ErrCodeRead: {},
}
type temporaryError interface {
+5 -2
View File
@@ -7,6 +7,9 @@ import (
"github.com/aws/aws-sdk-go/aws/credentials"
)
// EnvProviderName provides a name of the provider when config is loaded from environment.
const EnvProviderName = "EnvConfigCredentials"
// envConfig is a collection of environment values the SDK will read
// setup config from. All environment values are optional. But some values
// such as credentials require multiple values to be complete or the values
@@ -76,7 +79,7 @@ type envConfig struct {
SharedConfigFile string
// Sets the path to a custom Credentials Authroity (CA) Bundle PEM file
// that the SDK will use instead of the the system's root CA bundle.
// that the SDK will use instead of the system's root CA bundle.
// Only use this if you want to configure the SDK to use a custom set
// of CAs.
//
@@ -157,7 +160,7 @@ func envConfigLoad(enableSharedConfig bool) envConfig {
if len(cfg.Creds.AccessKeyID) == 0 || len(cfg.Creds.SecretAccessKey) == 0 {
cfg.Creds = credentials.Value{}
} else {
cfg.Creds.ProviderName = "EnvConfigCredentials"
cfg.Creds.ProviderName = EnvProviderName
}
regionKeys := regionEnvKeys
-60
View File
@@ -1,60 +0,0 @@
[default]
s3 =
unsupported_key=123
other_unsupported=abc
region = default_region
[profile alt_profile_name]
region = alt_profile_name_region
[short_profile_name_first]
region = short_profile_name_first_short
[profile short_profile_name_first]
region = short_profile_name_first_alt
[partial_creds]
aws_access_key_id = partial_creds_akid
[complete_creds]
aws_access_key_id = complete_creds_akid
aws_secret_access_key = complete_creds_secret
[complete_creds_with_token]
aws_access_key_id = complete_creds_with_token_akid
aws_secret_access_key = complete_creds_with_token_secret
aws_session_token = complete_creds_with_token_token
[full_profile]
aws_access_key_id = full_profile_akid
aws_secret_access_key = full_profile_secret
region = full_profile_region
[config_file_load_order]
region = shared_config_region
aws_access_key_id = shared_config_akid
aws_secret_access_key = shared_config_secret
[partial_assume_role]
role_arn = partial_assume_role_role_arn
[assume_role]
role_arn = assume_role_role_arn
source_profile = complete_creds
[assume_role_invalid_source_profile]
role_arn = assume_role_invalid_source_profile_role_arn
source_profile = profile_not_exists
[assume_role_w_creds]
role_arn = assume_role_w_creds_role_arn
source_profile = assume_role_w_creds
external_id = 1234
role_session_name = assume_role_w_creds_session_name
aws_access_key_id = assume_role_w_creds_akid
aws_secret_access_key = assume_role_w_creds_secret
[assume_role_wo_creds]
role_arn = assume_role_wo_creds_role_arn
source_profile = assume_role_wo_creds
@@ -1 +0,0 @@
[profile_nam
@@ -1,17 +0,0 @@
[default]
region = default_region
[partial_creds]
aws_access_key_id = AKID
[profile alt_profile_name]
region = alt_profile_name_region
[creds_from_credentials]
aws_access_key_id = creds_from_config_akid
aws_secret_access_key = creds_from_config_secret
[config_file_load_order]
region = shared_config_other_region
aws_access_key_id = shared_config_other_akid
aws_secret_access_key = shared_config_other_secret
+12 -6
View File
@@ -268,7 +268,7 @@ type signingCtx struct {
// "X-Amz-Content-Sha256" header with a precomputed value. The signer will
// only compute the hash if the request header value is empty.
func (v4 Signer) Sign(r *http.Request, body io.ReadSeeker, service, region string, signTime time.Time) (http.Header, error) {
return v4.signWithBody(r, body, service, region, 0, signTime)
return v4.signWithBody(r, body, service, region, 0, false, signTime)
}
// Presign signs AWS v4 requests with the provided body, service name, region
@@ -302,10 +302,10 @@ func (v4 Signer) Sign(r *http.Request, body io.ReadSeeker, service, region strin
// presigned request's signature you can set the "X-Amz-Content-Sha256"
// HTTP header and that will be included in the request's signature.
func (v4 Signer) Presign(r *http.Request, body io.ReadSeeker, service, region string, exp time.Duration, signTime time.Time) (http.Header, error) {
return v4.signWithBody(r, body, service, region, exp, signTime)
return v4.signWithBody(r, body, service, region, exp, true, signTime)
}
func (v4 Signer) signWithBody(r *http.Request, body io.ReadSeeker, service, region string, exp time.Duration, signTime time.Time) (http.Header, error) {
func (v4 Signer) signWithBody(r *http.Request, body io.ReadSeeker, service, region string, exp time.Duration, isPresign bool, signTime time.Time) (http.Header, error) {
currentTimeFn := v4.currentTimeFn
if currentTimeFn == nil {
currentTimeFn = time.Now
@@ -317,7 +317,7 @@ func (v4 Signer) signWithBody(r *http.Request, body io.ReadSeeker, service, regi
Query: r.URL.Query(),
Time: signTime,
ExpireTime: exp,
isPresign: exp != 0,
isPresign: isPresign,
ServiceName: service,
Region: region,
DisableURIPathEscaping: v4.DisableURIPathEscaping,
@@ -339,6 +339,7 @@ func (v4 Signer) signWithBody(r *http.Request, body io.ReadSeeker, service, regi
return http.Header{}, err
}
ctx.sanitizeHostForHeader()
ctx.assignAmzQueryValues()
ctx.build(v4.DisableHeaderHoisting)
@@ -363,6 +364,10 @@ func (v4 Signer) signWithBody(r *http.Request, body io.ReadSeeker, service, regi
return ctx.SignedHeaderVals, nil
}
func (ctx *signingCtx) sanitizeHostForHeader() {
request.SanitizeHostForHeader(ctx.Request)
}
func (ctx *signingCtx) handlePresignRemoval() {
if !ctx.isPresign {
return
@@ -467,7 +472,7 @@ func signSDKRequestWithCurrTime(req *request.Request, curTimeFn func() time.Time
}
signedHeaders, err := v4.signWithBody(req.HTTPRequest, req.GetBody(),
name, region, req.ExpireTime, signingTime,
name, region, req.ExpireTime, req.ExpireTime > 0, signingTime,
)
if err != nil {
req.Error = err
@@ -502,6 +507,8 @@ func (ctx *signingCtx) build(disableHeaderHoisting bool) {
ctx.buildTime() // no depends
ctx.buildCredentialString() // no depends
ctx.buildBodyDigest()
unsignedHeaders := ctx.Request.Header
if ctx.isPresign {
if !disableHeaderHoisting {
@@ -513,7 +520,6 @@ func (ctx *signingCtx) build(disableHeaderHoisting bool) {
}
}
ctx.buildBodyDigest()
ctx.buildCanonicalHeaders(ignoredHeaders, unsignedHeaders)
ctx.buildCanonicalString() // depends on canon headers / signed headers
ctx.buildStringToSign() // depends on canon string
+1 -1
View File
@@ -5,4 +5,4 @@ package aws
const SDKName = "aws-sdk-go"
// SDKVersion is the version of this SDK
const SDKVersion = "1.10.18"
const SDKVersion = "1.12.67"
-405
View File
@@ -1,405 +0,0 @@
// Package sdk is the official AWS SDK for the Go programming language.
//
// The AWS SDK for Go provides APIs and utilities that developers can use to
// build Go applications that use AWS services, such as Amazon Elastic Compute
// Cloud (Amazon EC2) and Amazon Simple Storage Service (Amazon S3).
//
// The SDK removes the complexity of coding directly against a web service
// interface. It hides a lot of the lower-level plumbing, such as authentication,
// request retries, and error handling.
//
// The SDK also includes helpful utilities on top of the AWS APIs that add additional
// capabilities and functionality. For example, the Amazon S3 Download and Upload
// Manager will automatically split up large objects into multiple parts and
// transfer them concurrently.
//
// See the s3manager package documentation for more information.
// https://docs.aws.amazon.com/sdk-for-go/api/service/s3/s3manager/
//
// Getting More Information
//
// Checkout the Getting Started Guide and API Reference Docs detailed the SDK's
// components and details on each AWS client the SDK supports.
//
// The Getting Started Guide provides examples and detailed description of how
// to get setup with the SDK.
// https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/welcome.html
//
// The API Reference Docs include a detailed breakdown of the SDK's components
// such as utilities and AWS clients. Use this as a reference of the Go types
// included with the SDK, such as AWS clients, API operations, and API parameters.
// https://docs.aws.amazon.com/sdk-for-go/api/
//
// Overview of SDK's Packages
//
// The SDK is composed of two main components, SDK core, and service clients.
// The SDK core packages are all available under the aws package at the root of
// the SDK. Each client for a supported AWS service is available within its own
// package under the service folder at the root of the SDK.
//
// * aws - SDK core, provides common shared types such as Config, Logger,
// and utilities to make working with API parameters easier.
//
// * awserr - Provides the error interface that the SDK will use for all
// errors that occur in the SDK's processing. This includes service API
// response errors as well. The Error type is made up of a code and message.
// Cast the SDK's returned error type to awserr.Error and call the Code
// method to compare returned error to specific error codes. See the package's
// documentation for additional values that can be extracted such as RequestId.
//
// * credentials - Provides the types and built in credentials providers
// the SDK will use to retrieve AWS credentials to make API requests with.
// Nested under this folder are also additional credentials providers such as
// stscreds for assuming IAM roles, and ec2rolecreds for EC2 Instance roles.
//
// * endpoints - Provides the AWS Regions and Endpoints metadata for the SDK.
// Use this to lookup AWS service endpoint information such as which services
// are in a region, and what regions a service is in. Constants are also provided
// for all region identifiers, e.g UsWest2RegionID for "us-west-2".
//
// * session - Provides initial default configuration, and load
// configuration from external sources such as environment and shared
// credentials file.
//
// * request - Provides the API request sending, and retry logic for the SDK.
// This package also includes utilities for defining your own request
// retryer, and configuring how the SDK processes the request.
//
// * service - Clients for AWS services. All services supported by the SDK are
// available under this folder.
//
// How to Use the SDK's AWS Service Clients
//
// The SDK includes the Go types and utilities you can use to make requests to
// AWS service APIs. Within the service folder at the root of the SDK you'll find
// a package for each AWS service the SDK supports. All service clients follows
// a common pattern of creation and usage.
//
// When creating a client for an AWS service you'll first need to have a Session
// value constructed. The Session provides shared configuration that can be shared
// between your service clients. When service clients are created you can pass
// in additional configuration via the aws.Config type to override configuration
// provided by in the Session to create service client instances with custom
// configuration.
//
// Once the service's client is created you can use it to make API requests the
// AWS service. These clients are safe to use concurrently.
//
// Configuring the SDK
//
// In the AWS SDK for Go, you can configure settings for service clients, such
// as the log level and maximum number of retries. Most settings are optional;
// however, for each service client, you must specify a region and your credentials.
// The SDK uses these values to send requests to the correct AWS region and sign
// requests with the correct credentials. You can specify these values as part
// of a session or as environment variables.
//
// See the SDK's configuration guide for more information.
// https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html
//
// See the session package documentation for more information on how to use Session
// with the SDK.
// https://docs.aws.amazon.com/sdk-for-go/api/aws/session/
//
// See the Config type in the aws package for more information on configuration
// options.
// https://docs.aws.amazon.com/sdk-for-go/api/aws/#Config
//
// Configuring Credentials
//
// When using the SDK you'll generally need your AWS credentials to authenticate
// with AWS services. The SDK supports multiple methods of supporting these
// credentials. By default the SDK will source credentials automatically from
// its default credential chain. See the session package for more information
// on this chain, and how to configure it. The common items in the credential
// chain are the following:
//
// * Environment Credentials - Set of environment variables that are useful
// when sub processes are created for specific roles.
//
// * Shared Credentials file (~/.aws/credentials) - This file stores your
// credentials based on a profile name and is useful for local development.
//
// * EC2 Instance Role Credentials - Use EC2 Instance Role to assign credentials
// to application running on an EC2 instance. This removes the need to manage
// credential files in production.
//
// Credentials can be configured in code as well by setting the Config's Credentials
// value to a custom provider or using one of the providers included with the
// SDK to bypass the default credential chain and use a custom one. This is
// helpful when you want to instruct the SDK to only use a specific set of
// credentials or providers.
//
// This example creates a credential provider for assuming an IAM role, "myRoleARN"
// and configures the S3 service client to use that role for API requests.
//
// // Initial credentials loaded from SDK's default credential chain. Such as
// // the environment, shared credentials (~/.aws/credentials), or EC2 Instance
// // Role. These credentials will be used to to make the STS Assume Role API.
// sess := session.Must(session.NewSession())
//
// // Create the credentials from AssumeRoleProvider to assume the role
// // referenced by the "myRoleARN" ARN.
// creds := stscreds.NewCredentials(sess, "myRoleArn")
//
// // Create service client value configured for credentials
// // from assumed role.
// svc := s3.New(sess, &aws.Config{Credentials: creds})/
//
// See the credentials package documentation for more information on credential
// providers included with the SDK, and how to customize the SDK's usage of
// credentials.
// https://docs.aws.amazon.com/sdk-for-go/api/aws/credentials
//
// The SDK has support for the shared configuration file (~/.aws/config). This
// support can be enabled by setting the environment variable, "AWS_SDK_LOAD_CONFIG=1",
// or enabling the feature in code when creating a Session via the
// Option's SharedConfigState parameter.
//
// sess := session.Must(session.NewSessionWithOptions(session.Options{
// SharedConfigState: session.SharedConfigEnable,
// }))
//
// Configuring AWS Region
//
// In addition to the credentials you'll need to specify the region the SDK
// will use to make AWS API requests to. In the SDK you can specify the region
// either with an environment variable, or directly in code when a Session or
// service client is created. The last value specified in code wins if the region
// is specified multiple ways.
//
// To set the region via the environment variable set the "AWS_REGION" to the
// region you want to the SDK to use. Using this method to set the region will
// allow you to run your application in multiple regions without needing additional
// code in the application to select the region.
//
// AWS_REGION=us-west-2
//
// The endpoints package includes constants for all regions the SDK knows. The
// values are all suffixed with RegionID. These values are helpful, because they
// reduce the need to type the region string manually.
//
// To set the region on a Session use the aws package's Config struct parameter
// Region to the AWS region you want the service clients created from the session to
// use. This is helpful when you want to create multiple service clients, and
// all of the clients make API requests to the same region.
//
// sess := session.Must(session.NewSession(&aws.Config{
// Region: aws.String(endpoints.UsWest2RegionID),
// }))
//
// See the endpoints package for the AWS Regions and Endpoints metadata.
// https://docs.aws.amazon.com/sdk-for-go/api/aws/endpoints/
//
// In addition to setting the region when creating a Session you can also set
// the region on a per service client bases. This overrides the region of a
// Session. This is helpful when you want to create service clients in specific
// regions different from the Session's region.
//
// svc := s3.New(sess, &aws.Config{
// Region: aws.String(ednpoints.UsWest2RegionID),
// })
//
// See the Config type in the aws package for more information and additional
// options such as setting the Endpoint, and other service client configuration options.
// https://docs.aws.amazon.com/sdk-for-go/api/aws/#Config
//
// Making API Requests
//
// Once the client is created you can make an API request to the service.
// Each API method takes a input parameter, and returns the service response
// and an error. The SDK provides methods for making the API call in multiple ways.
//
// In this list we'll use the S3 ListObjects API as an example for the different
// ways of making API requests.
//
// * ListObjects - Base API operation that will make the API request to the service.
//
// * ListObjectsRequest - API methods suffixed with Request will construct the
// API request, but not send it. This is also helpful when you want to get a
// presigned URL for a request, and share the presigned URL instead of your
// application making the request directly.
//
// * ListObjectsPages - Same as the base API operation, but uses a callback to
// automatically handle pagination of the API's response.
//
// * ListObjectsWithContext - Same as base API operation, but adds support for
// the Context pattern. This is helpful for controlling the canceling of in
// flight requests. See the Go standard library context package for more
// information. This method also takes request package's Option functional
// options as the variadic argument for modifying how the request will be
// made, or extracting information from the raw HTTP response.
//
// * ListObjectsPagesWithContext - same as ListObjectsPages, but adds support for
// the Context pattern. Similar to ListObjectsWithContext this method also
// takes the request package's Option function option types as the variadic
// argument.
//
// In addition to the API operations the SDK also includes several higher level
// methods that abstract checking for and waiting for an AWS resource to be in
// a desired state. In this list we'll use WaitUntilBucketExists to demonstrate
// the different forms of waiters.
//
// * WaitUntilBucketExists. - Method to make API request to query an AWS service for
// a resource's state. Will return successfully when that state is accomplished.
//
// * WaitUntilBucketExistsWithContext - Same as WaitUntilBucketExists, but adds
// support for the Context pattern. In addition these methods take request
// package's WaiterOptions to configure the waiter, and how underlying request
// will be made by the SDK.
//
// The API method will document which error codes the service might return for
// the operation. These errors will also be available as const strings prefixed
// with "ErrCode" in the service client's package. If there are no errors listed
// in the API's SDK documentation you'll need to consult the AWS service's API
// documentation for the errors that could be returned.
//
// ctx := context.Background()
//
// result, err := svc.GetObjectWithContext(ctx, &s3.GetObjectInput{
// Bucket: aws.String("my-bucket"),
// Key: aws.String("my-key"),
// })
// if err != nil {
// // Cast err to awserr.Error to handle specific error codes.
// aerr, ok := err.(awserr.Error)
// if ok && aerr.Code() == s3.ErrCodeNoSuchKey {
// // Specific error code handling
// }
// return err
// }
//
// // Make sure to close the body when done with it for S3 GetObject APIs or
// // will leak connections.
// defer result.Body.Close()
//
// fmt.Println("Object Size:", aws.StringValue(result.ContentLength))
//
// API Request Pagination and Resource Waiters
//
// Pagination helper methods are suffixed with "Pages", and provide the
// functionality needed to round trip API page requests. Pagination methods
// take a callback function that will be called for each page of the API's response.
//
// objects := []string{}
// err := svc.ListObjectsPagesWithContext(ctx, &s3.ListObjectsInput{
// Bucket: aws.String(myBucket),
// }, func(p *s3.ListObjectsOutput, lastPage bool) bool {
// for _, o := range p.Contents {
// objects = append(objects, aws.StringValue(o.Key))
// }
// return true // continue paging
// })
// if err != nil {
// panic(fmt.Sprintf("failed to list objects for bucket, %s, %v", myBucket, err))
// }
//
// fmt.Println("Objects in bucket:", objects)
//
// Waiter helper methods provide the functionality to wait for an AWS resource
// state. These methods abstract the logic needed to to check the state of an
// AWS resource, and wait until that resource is in a desired state. The waiter
// will block until the resource is in the state that is desired, an error occurs,
// or the waiter times out. If a resource times out the error code returned will
// be request.WaiterResourceNotReadyErrorCode.
//
// err := svc.WaitUntilBucketExistsWithContext(ctx, &s3.HeadBucketInput{
// Bucket: aws.String(myBucket),
// })
// if err != nil {
// aerr, ok := err.(awserr.Error)
// if ok && aerr.Code() == request.WaiterResourceNotReadyErrorCode {
// fmt.Fprintf(os.Stderr, "timed out while waiting for bucket to exist")
// }
// panic(fmt.Errorf("failed to wait for bucket to exist, %v", err))
// }
// fmt.Println("Bucket", myBucket, "exists")
//
// Complete SDK Example
//
// This example shows a complete working Go file which will upload a file to S3
// and use the Context pattern to implement timeout logic that will cancel the
// request if it takes too long. This example highlights how to use sessions,
// create a service client, make a request, handle the error, and process the
// response.
//
// package main
//
// import (
// "context"
// "flag"
// "fmt"
// "os"
// "time"
//
// "github.com/aws/aws-sdk-go/aws"
// "github.com/aws/aws-sdk-go/aws/awserr"
// "github.com/aws/aws-sdk-go/aws/request"
// "github.com/aws/aws-sdk-go/aws/session"
// "github.com/aws/aws-sdk-go/service/s3"
// )
//
// // Uploads a file to S3 given a bucket and object key. Also takes a duration
// // value to terminate the update if it doesn't complete within that time.
// //
// // The AWS Region needs to be provided in the AWS shared config or on the
// // environment variable as `AWS_REGION`. Credentials also must be provided
// // Will default to shared config file, but can load from environment if provided.
// //
// // Usage:
// // # Upload myfile.txt to myBucket/myKey. Must complete within 10 minutes or will fail
// // go run withContext.go -b mybucket -k myKey -d 10m < myfile.txt
// func main() {
// var bucket, key string
// var timeout time.Duration
//
// flag.StringVar(&bucket, "b", "", "Bucket name.")
// flag.StringVar(&key, "k", "", "Object key name.")
// flag.DurationVar(&timeout, "d", 0, "Upload timeout.")
// flag.Parse()
//
// // All clients require a Session. The Session provides the client with
// // shared configuration such as region, endpoint, and credentials. A
// // Session should be shared where possible to take advantage of
// // configuration and credential caching. See the session package for
// // more information.
// sess := session.Must(session.NewSession())
//
// // Create a new instance of the service's client with a Session.
// // Optional aws.Config values can also be provided as variadic arguments
// // to the New function. This option allows you to provide service
// // specific configuration.
// svc := s3.New(sess)
//
// // Create a context with a timeout that will abort the upload if it takes
// // more than the passed in timeout.
// ctx := context.Background()
// var cancelFn func()
// if timeout > 0 {
// ctx, cancelFn = context.WithTimeout(ctx, timeout)
// }
// // Ensure the context is canceled to prevent leaking.
// // See context package for more information, https://golang.org/pkg/context/
// defer cancelFn()
//
// // Uploads the object to S3. The Context will interrupt the request if the
// // timeout expires.
// _, err := svc.PutObjectWithContext(ctx, &s3.PutObjectInput{
// Bucket: aws.String(bucket),
// Key: aws.String(key),
// Body: os.Stdin,
// })
// if err != nil {
// if aerr, ok := err.(awserr.Error); ok && aerr.Code() == request.CanceledErrorCode {
// // If the SDK can determine the request or retry delay was canceled
// // by a context the CanceledErrorCode error code will be returned.
// fmt.Fprintf(os.Stderr, "upload canceled due to timeout, %v\n", err)
// } else {
// fmt.Fprintf(os.Stderr, "failed to upload object, %v\n", err)
// }
// os.Exit(1)
// }
//
// fmt.Printf("successfully uploaded file to %s/%s\n", bucket, key)
// }
package sdk
-4
View File
@@ -1,4 +0,0 @@
## AWS SDK for Go Private packages ##
`private` is a collection of packages used internally by the SDK, and is subject to have breaking changes. This package is not `internal` so that if you really need to use its functionality, and understand breaking changes will be made, you are able to.
These packages will be refactored in the future so that the API generator and model parsers are exposed cleanly on their own. Making it easier for you to generate your own code based on the API models.
-800
View File
@@ -1,800 +0,0 @@
// +build codegen
// Package api represents API abstractions for rendering service generated files.
package api
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"path"
"path/filepath"
"regexp"
"sort"
"strings"
"text/template"
)
// An API defines a service API's definition. and logic to serialize the definition.
type API struct {
Metadata Metadata
Operations map[string]*Operation
Shapes map[string]*Shape
Waiters []Waiter
Documentation string
Examples Examples
// Set to true to avoid removing unused shapes
NoRemoveUnusedShapes bool
// Set to true to avoid renaming to 'Input/Output' postfixed shapes
NoRenameToplevelShapes bool
// Set to true to ignore service/request init methods (for testing)
NoInitMethods bool
// Set to true to ignore String() and GoString methods (for generated tests)
NoStringerMethods bool
// Set to true to not generate API service name constants
NoConstServiceNames bool
// Set to true to not generate validation shapes
NoValidataShapeMethods bool
// Set to true to not generate struct field accessors
NoGenStructFieldAccessors bool
SvcClientImportPath string
initialized bool
imports map[string]bool
name string
path string
BaseCrosslinkURL string
}
// A Metadata is the metadata about an API's definition.
type Metadata struct {
APIVersion string
EndpointPrefix string
SigningName string
ServiceAbbreviation string
ServiceFullName string
SignatureVersion string
JSONVersion string
TargetPrefix string
Protocol string
UID string
EndpointsID string
NoResolveEndpoint bool
}
var serviceAliases map[string]string
func Bootstrap() error {
b, err := ioutil.ReadFile(filepath.Join("..", "models", "customizations", "service-aliases.json"))
if err != nil {
return err
}
return json.Unmarshal(b, &serviceAliases)
}
// PackageName name of the API package
func (a *API) PackageName() string {
return strings.ToLower(a.StructName())
}
// InterfacePackageName returns the package name for the interface.
func (a *API) InterfacePackageName() string {
return a.PackageName() + "iface"
}
var nameRegex = regexp.MustCompile(`^Amazon|AWS\s*|\(.*|\s+|\W+`)
// StructName returns the struct name for a given API.
func (a *API) StructName() string {
if a.name == "" {
name := a.Metadata.ServiceAbbreviation
if name == "" {
name = a.Metadata.ServiceFullName
}
name = nameRegex.ReplaceAllString(name, "")
a.name = name
if name, ok := serviceAliases[strings.ToLower(name)]; ok {
a.name = name
}
}
return a.name
}
// UseInitMethods returns if the service's init method should be rendered.
func (a *API) UseInitMethods() bool {
return !a.NoInitMethods
}
// NiceName returns the human friendly API name.
func (a *API) NiceName() string {
if a.Metadata.ServiceAbbreviation != "" {
return a.Metadata.ServiceAbbreviation
}
return a.Metadata.ServiceFullName
}
// ProtocolPackage returns the package name of the protocol this API uses.
func (a *API) ProtocolPackage() string {
switch a.Metadata.Protocol {
case "json":
return "jsonrpc"
case "ec2":
return "ec2query"
default:
return strings.Replace(a.Metadata.Protocol, "-", "", -1)
}
}
// OperationNames returns a slice of API operations supported.
func (a *API) OperationNames() []string {
i, names := 0, make([]string, len(a.Operations))
for n := range a.Operations {
names[i] = n
i++
}
sort.Strings(names)
return names
}
// OperationList returns a slice of API operation pointers
func (a *API) OperationList() []*Operation {
list := make([]*Operation, len(a.Operations))
for i, n := range a.OperationNames() {
list[i] = a.Operations[n]
}
return list
}
// OperationHasOutputPlaceholder returns if any of the API operation input
// or output shapes are place holders.
func (a *API) OperationHasOutputPlaceholder() bool {
for _, op := range a.Operations {
if op.OutputRef.Shape.Placeholder {
return true
}
}
return false
}
// ShapeNames returns a slice of names for each shape used by the API.
func (a *API) ShapeNames() []string {
i, names := 0, make([]string, len(a.Shapes))
for n := range a.Shapes {
names[i] = n
i++
}
sort.Strings(names)
return names
}
// ShapeList returns a slice of shape pointers used by the API.
//
// Will exclude error shapes from the list of shapes returned.
func (a *API) ShapeList() []*Shape {
list := make([]*Shape, 0, len(a.Shapes))
for _, n := range a.ShapeNames() {
// Ignore error shapes in list
if s := a.Shapes[n]; !s.IsError {
list = append(list, s)
}
}
return list
}
// ShapeListErrors returns a list of the errors defined by the API model
func (a *API) ShapeListErrors() []*Shape {
list := []*Shape{}
for _, n := range a.ShapeNames() {
// Ignore error shapes in list
if s := a.Shapes[n]; s.IsError {
list = append(list, s)
}
}
return list
}
// resetImports resets the import map to default values.
func (a *API) resetImports() {
a.imports = map[string]bool{
"github.com/aws/aws-sdk-go/aws": true,
}
}
// importsGoCode returns the generated Go import code.
func (a *API) importsGoCode() string {
if len(a.imports) == 0 {
return ""
}
corePkgs, extPkgs := []string{}, []string{}
for i := range a.imports {
if strings.Contains(i, ".") {
extPkgs = append(extPkgs, i)
} else {
corePkgs = append(corePkgs, i)
}
}
sort.Strings(corePkgs)
sort.Strings(extPkgs)
code := "import (\n"
for _, i := range corePkgs {
code += fmt.Sprintf("\t%q\n", i)
}
if len(corePkgs) > 0 {
code += "\n"
}
for _, i := range extPkgs {
code += fmt.Sprintf("\t%q\n", i)
}
code += ")\n\n"
return code
}
// A tplAPI is the top level template for the API
var tplAPI = template.Must(template.New("api").Parse(`
{{ range $_, $o := .OperationList }}
{{ $o.GoCode }}
{{ end }}
{{ range $_, $s := .ShapeList }}
{{ if and $s.IsInternal (eq $s.Type "structure") }}{{ $s.GoCode }}{{ end }}
{{ end }}
{{ range $_, $s := .ShapeList }}
{{ if $s.IsEnum }}{{ $s.GoCode }}{{ end }}
{{ end }}
`))
// APIGoCode renders the API in Go code. Returning it as a string
func (a *API) APIGoCode() string {
a.resetImports()
a.imports["github.com/aws/aws-sdk-go/aws/awsutil"] = true
a.imports["github.com/aws/aws-sdk-go/aws/request"] = true
if a.OperationHasOutputPlaceholder() {
a.imports["github.com/aws/aws-sdk-go/private/protocol/"+a.ProtocolPackage()] = true
a.imports["github.com/aws/aws-sdk-go/private/protocol"] = true
}
for _, op := range a.Operations {
if op.AuthType == "none" {
a.imports["github.com/aws/aws-sdk-go/aws/credentials"] = true
break
}
}
var buf bytes.Buffer
err := tplAPI.Execute(&buf, a)
if err != nil {
panic(err)
}
code := a.importsGoCode() + strings.TrimSpace(buf.String())
return code
}
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{}{},
}
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...), "/")
}
return ""
}
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 $.APIName $.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 use the client for {{ .Metadata.ServiceFullName }} you will first need
// to create a new instance of it.
//
// When creating a client for an AWS service you'll first need to have a Session
// already created. The Session provides configuration that can be shared
// between multiple service clients. Additional configuration can be applied to
// the Session and service's client when they are constructed. The aws package's
// Config type contains several fields such as Region for the AWS Region the
// client should make API requests too. The optional Config value can be provided
// as the variadic argument for Sessions and client creation.
//
// Once the service's client is created you can use it to make API requests the
// AWS service. These clients are safe to use concurrently.
//
// // Create a session to share configuration, and load external configuration.
// sess := session.Must(session.NewSession())
//
// // Create the service's client with the session.
// svc := {{ .PackageName }}.New(sess)
//
// See the SDK's documentation for more information on how to use service clients.
// https://docs.aws.amazon.com/sdk-for-go/api/
//
// See aws package's Config type for more information on configuration options.
// https://docs.aws.amazon.com/sdk-for-go/api/aws/#Config
//
// See the {{ .Metadata.ServiceFullName }} client {{ .StructName }} for more
// information on creating the service's client.
// https://docs.aws.amazon.com/sdk-for-go/api/service/{{ .PackageName }}/#New
//
{{ $opts := .OperationNames -}}
{{ $optName := index $opts 0 -}}
{{ $opt := index .Operations $optName -}}
{{ $optInputName := $opt.InputRef.GoTypeWithPkgName -}}
// Once the client is created you can make an API request to the service.
// Each API method takes a input parameter, and returns the service response
// and an error.
//
// The API method will document which error codes the service can be returned
// by the operation if the service models the API operation's errors. These
// errors will also be available as const strings prefixed with "ErrCode".
//
// result, err := svc.{{ $opt.ExportedName }}(params)
// if err != nil {
// // Cast err to awserr.Error to handle specific error codes.
// aerr, ok := err.(awserr.Error)
// if ok && aerr.Code() == <error code to check for> {
// // Specific error code handling
// }
// return err
// }
//
// fmt.Println("{{ $optName }} result:")
// fmt.Println(result)
//
// Using the Client with Context
//
// The service's client also provides methods to make API requests with a Context
// value. This allows you to control the timeout, and cancellation of pending
// requests. These methods also take request Option as variadic parameter to apply
// additional configuration to the API request.
//
// ctx := context.Background()
//
// result, err := svc.{{ $opt.ExportedName }}WithContext(ctx, params)
//
// See the request package documentation for more information on using Context pattern
// with the SDK.
// https://docs.aws.amazon.com/sdk-for-go/api/aws/request/
`))
// 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 {
if a.NoConstServiceNames {
return fmt.Sprintf("%q", a.Metadata.EndpointPrefix)
}
return "ServiceName"
},
"EndpointsIDConstValue": func(a *API) string {
if a.NoConstServiceNames {
return fmt.Sprintf("%q", a.Metadata.EndpointPrefix)
}
if a.Metadata.EndpointPrefix == a.Metadata.EndpointsID {
return "ServiceName"
}
return fmt.Sprintf("%q", a.Metadata.EndpointsID)
},
"EndpointsIDValue": func(a *API) string {
if a.NoConstServiceNames {
return fmt.Sprintf("%q", a.Metadata.EndpointPrefix)
}
return "EndpointsID"
},
}).Parse(`
// {{ .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
}
{{ if .UseInitMethods }}// Used for custom client initialization logic
var initClient func(*client.Client)
// Used for custom request initialization logic
var initRequest func(*request.Request)
{{ end }}
{{ if not .NoConstServiceNames -}}
// Service information constants
const (
ServiceName = "{{ .Metadata.EndpointPrefix }}" // Service endpoint prefix API calls made to.
EndpointsID = {{ EndpointsIDConstValue . }} // Service ID for Regions and Endpoints metadata.
)
{{- end }}
// New creates a new instance of the {{ .StructName }} client with a session.
// If additional configuration is needed for the client instance use the optional
// aws.Config parameter to add your extra config.
//
// Example:
// // Create a {{ .StructName }} client from just a session.
// svc := {{ .PackageName }}.New(mySession)
//
// // Create a {{ .StructName }} client with additional configuration
// svc := {{ .PackageName }}.New(mySession, aws.NewConfig().WithRegion("us-west-2"))
func New(p client.ConfigProvider, cfgs ...*aws.Config) *{{ .StructName }} {
{{ if .Metadata.NoResolveEndpoint -}}
var c client.Config
if v, ok := p.(client.ConfigNoResolveEndpointProvider); ok {
c = v.ClientConfigNoResolveEndpoint(cfgs...)
} else {
c = p.ClientConfig({{ EndpointsIDValue . }}, cfgs...)
}
{{- else -}}
c := p.ClientConfig({{ EndpointsIDValue . }}, cfgs...)
{{- end }}
return newClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName)
}
// newClient creates, initializes and returns a new service client instance.
func newClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion, signingName string) *{{ .StructName }} {
{{- if .Metadata.SigningName }}
if len(signingName) == 0 {
signingName = "{{ .Metadata.SigningName }}"
}
{{- end }}
svc := &{{ .StructName }}{
Client: client.New(
cfg,
metadata.ClientInfo{
ServiceName: {{ ServiceNameValue . }},
SigningName: signingName,
SigningRegion: signingRegion,
Endpoint: endpoint,
APIVersion: "{{ .Metadata.APIVersion }}",
{{ if .Metadata.JSONVersion -}}
JSONVersion: "{{ .Metadata.JSONVersion }}",
{{- end }}
{{ if .Metadata.TargetPrefix -}}
TargetPrefix: "{{ .Metadata.TargetPrefix }}",
{{- end }}
},
handlers,
),
}
// Handlers
svc.Handlers.Sign.PushBackNamed({{if eq .Metadata.SignatureVersion "v2"}}v2{{else}}v4{{end}}.SignRequestHandler)
{{- if eq .Metadata.SignatureVersion "v2" }}
svc.Handlers.Sign.PushBackNamed(corehandlers.BuildContentLengthHandler)
{{- end }}
svc.Handlers.Build.PushBackNamed({{ .ProtocolPackage }}.BuildHandler)
svc.Handlers.Unmarshal.PushBackNamed({{ .ProtocolPackage }}.UnmarshalHandler)
svc.Handlers.UnmarshalMeta.PushBackNamed({{ .ProtocolPackage }}.UnmarshalMetaHandler)
svc.Handlers.UnmarshalError.PushBackNamed({{ .ProtocolPackage }}.UnmarshalErrorHandler)
{{ if .UseInitMethods }}// Run custom client initialization if present
if initClient != nil {
initClient(svc.Client)
}
{{ end }}
return svc
}
// newRequest creates a new request for a {{ .StructName }} operation and runs any
// custom request initialization.
func (c *{{ .StructName }}) newRequest(op *request.Operation, params, data interface{}) *request.Request {
req := c.NewRequest(op, params, data)
{{ if .UseInitMethods }}// Run custom request initialization if present
if initRequest != nil {
initRequest(req)
}
{{ end }}
return req
}
`))
// 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()
a.imports["github.com/aws/aws-sdk-go/aws/client"] = true
a.imports["github.com/aws/aws-sdk-go/aws/client/metadata"] = true
a.imports["github.com/aws/aws-sdk-go/aws/request"] = true
if a.Metadata.SignatureVersion == "v2" {
a.imports["github.com/aws/aws-sdk-go/private/signer/v2"] = true
a.imports["github.com/aws/aws-sdk-go/aws/corehandlers"] = true
} else {
a.imports["github.com/aws/aws-sdk-go/aws/signer/v4"] = true
}
a.imports["github.com/aws/aws-sdk-go/private/protocol/"+a.ProtocolPackage()] = true
var buf bytes.Buffer
err := tplService.Execute(&buf, a)
if err != nil {
panic(err)
}
code := a.importsGoCode() + buf.String()
return code
}
// ExampleGoCode renders service example code. Returning it as a string.
func (a *API) ExampleGoCode() string {
exs := []string{}
imports := map[string]bool{}
for _, o := range a.OperationList() {
o.imports = map[string]bool{}
exs = append(exs, o.Example())
for k, v := range o.imports {
imports[k] = v
}
}
code := fmt.Sprintf("import (\n%q\n%q\n%q\n\n%q\n%q\n%q\n",
"bytes",
"fmt",
"time",
"github.com/aws/aws-sdk-go/aws",
"github.com/aws/aws-sdk-go/aws/session",
path.Join(a.SvcClientImportPath, a.PackageName()),
)
for k, _ := range imports {
code += fmt.Sprintf("%q\n", k)
}
code += ")\n\n"
code += "var _ time.Duration\nvar _ bytes.Buffer\n\n"
code += strings.Join(exs, "\n\n")
return code
}
// A tplInterface defines the template for the service interface type.
var tplInterface = template.Must(template.New("interface").Parse(`
// {{ .StructName }}API provides an interface to enable mocking the
// {{ .PackageName }}.{{ .StructName }} service client's API operation,
// paginators, and waiters. This make unit testing your code that calls out
// to the SDK's service client's calls easier.
//
// 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.
//
// // myFunc uses an SDK service client to make a request to
// // {{.Metadata.ServiceFullName}}. {{ $opts := .OperationList }}{{ $opt := index $opts 0 }}
// func myFunc(svc {{ .InterfacePackageName }}.{{ .StructName }}API) bool {
// // Make svc.{{ $opt.ExportedName }} request
// }
//
// func main() {
// sess := session.New()
// svc := {{ .PackageName }}.New(sess)
//
// myFunc(svc)
// }
//
// In your _test.go file:
//
// // Define a mock struct to be used in your unit tests of myFunc.
// type mock{{ .StructName }}Client struct {
// {{ .InterfacePackageName }}.{{ .StructName }}API
// }
// func (m *mock{{ .StructName }}Client) {{ $opt.ExportedName }}(input {{ $opt.InputRef.GoTypeWithPkgName }}) ({{ $opt.OutputRef.GoTypeWithPkgName }}, error) {
// // mock response/functionality
// }
//
// func TestMyFunc(t *testing.T) {
// // Setup Test
// mockSvc := &mock{{ .StructName }}Client{}
//
// myfunc(mockSvc)
//
// // Verify myFunc's functionality
// }
//
// It is important to note that this interface will have breaking changes
// when the service model is updated and adds new API operations, paginators,
// and waiters. Its suggested to use the pattern above for testing, or using
// tooling to generate mocks to satisfy the interfaces.
type {{ .StructName }}API interface {
{{ range $_, $o := .OperationList }}
{{ $o.InterfaceSignature }}
{{ end }}
{{ range $_, $w := .Waiters }}
{{ $w.InterfaceSignature }}
{{ end }}
}
var _ {{ .StructName }}API = (*{{ .PackageName }}.{{ .StructName }})(nil)
`))
// InterfaceGoCode returns the go code for the service's API operations as an
// interface{}. Assumes that the interface is being created in a different
// package than the service API's package.
func (a *API) InterfaceGoCode() string {
a.resetImports()
a.imports = map[string]bool{
"github.com/aws/aws-sdk-go/aws": true,
"github.com/aws/aws-sdk-go/aws/request": true,
path.Join(a.SvcClientImportPath, a.PackageName()): true,
}
var buf bytes.Buffer
err := tplInterface.Execute(&buf, a)
if err != nil {
panic(err)
}
code := a.importsGoCode() + strings.TrimSpace(buf.String())
return code
}
// NewAPIGoCodeWithPkgName returns a string of instantiating the API prefixed
// with its package name. Takes a string depicting the Config.
func (a *API) NewAPIGoCodeWithPkgName(cfg string) string {
return fmt.Sprintf("%s.New(%s)", a.PackageName(), cfg)
}
// computes the validation chain for all input shapes
func (a *API) addShapeValidations() {
for _, o := range a.Operations {
resolveShapeValidations(o.InputRef.Shape)
}
}
// Updates the source shape and all nested shapes with the validations that
// could possibly be needed.
func resolveShapeValidations(s *Shape, ancestry ...*Shape) {
for _, a := range ancestry {
if a == s {
return
}
}
children := []string{}
for _, name := range s.MemberNames() {
ref := s.MemberRefs[name]
if s.IsRequired(name) && !s.Validations.Has(ref, ShapeValidationRequired) {
s.Validations = append(s.Validations, ShapeValidation{
Name: name, Ref: ref, Type: ShapeValidationRequired,
})
}
if ref.Shape.Min != 0 && !s.Validations.Has(ref, ShapeValidationMinVal) {
s.Validations = append(s.Validations, ShapeValidation{
Name: name, Ref: ref, Type: ShapeValidationMinVal,
})
}
switch ref.Shape.Type {
case "map", "list", "structure":
children = append(children, name)
}
}
ancestry = append(ancestry, s)
for _, name := range children {
ref := s.MemberRefs[name]
// Since this is a grab bag we will just continue since
// we can't validate because we don't know the valued shape.
if ref.JSONValue {
continue
}
nestedShape := ref.Shape.NestedShape()
var v *ShapeValidation
if len(nestedShape.Validations) > 0 {
v = &ShapeValidation{
Name: name, Ref: ref, Type: ShapeValidationNested,
}
} else {
resolveShapeValidations(nestedShape, ancestry...)
if len(nestedShape.Validations) > 0 {
v = &ShapeValidation{
Name: name, Ref: ref, Type: ShapeValidationNested,
}
}
}
if v != nil && !s.Validations.Has(v.Ref, v.Type) {
s.Validations = append(s.Validations, *v)
}
}
ancestry = ancestry[:len(ancestry)-1]
}
// A tplAPIErrors is the top level template for the API
var tplAPIErrors = template.Must(template.New("api").Parse(`
const (
{{ range $_, $s := $.ShapeListErrors }}
// {{ $s.ErrorCodeName }} for service response error code
// {{ printf "%q" $s.ErrorName }}.
{{ if $s.Docstring -}}
//
{{ $s.Docstring }}
{{ end -}}
{{ $s.ErrorCodeName }} = {{ printf "%q" $s.ErrorName }}
{{ end }}
)
`))
func (a *API) APIErrorsGoCode() string {
var buf bytes.Buffer
err := tplAPIErrors.Execute(&buf, a)
if err != nil {
panic(err)
}
return strings.TrimSpace(buf.String())
}
@@ -1,172 +0,0 @@
// +build codegen
package api
import (
"io/ioutil"
"path/filepath"
"strings"
)
type service struct {
srcName string
dstName string
serviceVersion string
}
var mergeServices = map[string]service{
"dynamodbstreams": service{
dstName: "dynamodb",
srcName: "streams.dynamodb",
},
"wafregional": service{
dstName: "waf",
srcName: "waf-regional",
serviceVersion: "2015-08-24",
},
}
// customizationPasses Executes customization logic for the API by package name.
func (a *API) customizationPasses() {
var svcCustomizations = map[string]func(*API){
"s3": s3Customizations,
"cloudfront": cloudfrontCustomizations,
"rds": rdsCustomizations,
// Disable endpoint resolving for services that require customer
// to provide endpoint them selves.
"cloudsearchdomain": disableEndpointResolving,
"iotdataplane": disableEndpointResolving,
}
for k, _ := range mergeServices {
svcCustomizations[k] = mergeServicesCustomizations
}
if fn := svcCustomizations[a.PackageName()]; fn != nil {
fn(a)
}
}
// s3Customizations customizes the API generation to replace values specific to S3.
func s3Customizations(a *API) {
var strExpires *Shape
for name, s := range a.Shapes {
// Remove ContentMD5 members
if _, ok := s.MemberRefs["ContentMD5"]; ok {
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") {
if ref, ok := s.MemberRefs["Expires"]; ok {
if strExpires == nil {
newShape := *ref.Shape
strExpires = &newShape
strExpires.Type = "string"
strExpires.refs = []*ShapeRef{}
}
ref.Shape.removeRef(ref)
ref.Shape = strExpires
ref.Shape.refs = append(ref.Shape.refs, &s.MemberRef)
}
}
}
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
// specific to CloudFront.
func cloudfrontCustomizations(a *API) {
// MaxItems members should always be integers
for _, s := range a.Shapes {
if ref, ok := s.MemberRefs["MaxItems"]; ok {
ref.ShapeName = "Integer"
ref.Shape = a.Shapes["Integer"]
}
}
}
// mergeServicesCustomizations references any duplicate shapes from DynamoDB
func mergeServicesCustomizations(a *API) {
info := mergeServices[a.PackageName()]
p := strings.Replace(a.path, info.srcName, info.dstName, -1)
if info.serviceVersion != "" {
index := strings.LastIndex(p, "/")
files, _ := ioutil.ReadDir(p[:index])
if len(files) > 1 {
panic("New version was introduced")
}
p = p[:index] + "/" + info.serviceVersion
}
file := filepath.Join(p, "api-2.json")
serviceAPI := API{}
serviceAPI.Attach(file)
serviceAPI.Setup()
for n := range a.Shapes {
if _, ok := serviceAPI.Shapes[n]; ok {
a.Shapes[n].resolvePkg = "github.com/aws/aws-sdk-go/service/" + info.dstName
}
}
}
// rdsCustomizations are customization for the service/rds. This adds non-modeled fields used for presigning.
func rdsCustomizations(a *API) {
inputs := []string{
"CopyDBSnapshotInput",
"CreateDBInstanceReadReplicaInput",
"CopyDBClusterSnapshotInput",
"CreateDBClusterInput",
}
for _, input := range inputs {
if ref, ok := a.Shapes[input]; ok {
ref.MemberRefs["SourceRegion"] = &ShapeRef{
Documentation: docstring(`SourceRegion is the source region where the resource exists. This is not sent over the wire and is only used for presigning. This value should always have the same region as the source ARN.`),
ShapeName: "String",
Shape: a.Shapes["String"],
Ignore: true,
}
ref.MemberRefs["DestinationRegion"] = &ShapeRef{
Documentation: docstring(`DestinationRegion is used for presigning the request to a given region.`),
ShapeName: "String",
Shape: a.Shapes["String"],
}
}
}
}
func disableEndpointResolving(a *API) {
a.Metadata.NoResolveEndpoint = true
}
-411
View File
@@ -1,411 +0,0 @@
// +build codegen
package api
import (
"bytes"
"encoding/json"
"fmt"
"html"
"os"
"regexp"
"strings"
xhtml "golang.org/x/net/html"
)
type apiDocumentation struct {
*API
Operations map[string]string
Service string
Shapes map[string]shapeDocumentation
}
type shapeDocumentation struct {
Base string
Refs map[string]string
}
// AttachDocs attaches documentation from a JSON filename.
func (a *API) AttachDocs(filename string) {
d := apiDocumentation{API: a}
f, err := os.Open(filename)
defer f.Close()
if err != nil {
panic(err)
}
err = json.NewDecoder(f).Decode(&d)
if err != nil {
panic(err)
}
d.setup()
}
func (d *apiDocumentation) setup() {
d.API.Documentation = docstring(d.Service)
for op, doc := range d.Operations {
d.API.Operations[op].Documentation = docstring(doc)
}
for shape, info := range d.Shapes {
if sh := d.API.Shapes[shape]; sh != nil {
sh.Documentation = docstring(info.Base)
}
for ref, doc := range info.Refs {
if doc == "" {
continue
}
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)
}
}
}
}
}
var reNewline = regexp.MustCompile(`\r?\n`)
var reMultiSpace = regexp.MustCompile(`\s+`)
var reComments = regexp.MustCompile(`<!--.*?-->`)
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, "")
doc = html.UnescapeString(doc)
// Replace doc with full name if doc is empty.
doc = strings.TrimSpace(doc)
if len(doc) == 0 {
doc = fullname
}
return commentify(doc)
}
const (
indent = " "
)
// style is what we want to prefix a string with.
// For instance, <li>Foo</li><li>Bar</li>, will generate
// * Foo
// * Bar
var style = map[string]string{
"ul": indent + "* ",
"li": indent + "* ",
"code": indent,
"pre": indent,
}
// commentify converts a string to a Go comment
func commentify(doc string) string {
if len(doc) == 0 {
return ""
}
lines := strings.Split(doc, "\n")
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)
}
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
// at approximately length characters. Line breaks will only be
// inserted into whitespace.
func wrap(text string, length int, isIndented bool) string {
var buf bytes.Buffer
var last rune
var lastNL bool
var col int
for _, c := range text {
switch c {
case '\r': // ignore this
continue // and also don't track `last`
case '\n': // ignore this too, but reset col
if col >= length || last == '\n' {
buf.WriteString("\n")
}
buf.WriteString("\n")
col = 0
case ' ', '\t': // opportunity to split
if col >= length {
buf.WriteByte('\n')
col = 0
if isIndented {
buf.WriteString(indent)
col += 3
}
} else {
// We only want to write a leading space if the col is greater than zero.
// This will provide the proper spacing for documentation.
buf.WriteRune(c)
col++ // count column
}
default:
buf.WriteRune(c)
col++
}
lastNL = c == '\n'
_ = lastNL
last = c
}
return buf.String()
}
type tagInfo struct {
tag string
key string
val string
txt string
raw string
closingTag bool
}
// generateDoc will generate the proper doc string for html encoded or plain text doc entries.
func generateDoc(htmlSrc string) string {
tokenizer := xhtml.NewTokenizer(strings.NewReader(htmlSrc))
tokens := buildTokenArray(tokenizer)
scopes := findScopes(tokens)
return walk(scopes)
}
func buildTokenArray(tokenizer *xhtml.Tokenizer) []tagInfo {
tokens := []tagInfo{}
for tt := tokenizer.Next(); tt != xhtml.ErrorToken; tt = tokenizer.Next() {
switch tt {
case xhtml.TextToken:
txt := string(tokenizer.Text())
if len(tokens) == 0 {
info := tagInfo{
raw: txt,
}
tokens = append(tokens, info)
}
tn, _ := tokenizer.TagName()
key, val, _ := tokenizer.TagAttr()
info := tagInfo{
tag: string(tn),
key: string(key),
val: string(val),
txt: txt,
}
tokens = append(tokens, info)
case xhtml.StartTagToken:
tn, _ := tokenizer.TagName()
key, val, _ := tokenizer.TagAttr()
info := tagInfo{
tag: string(tn),
key: string(key),
val: string(val),
}
tokens = append(tokens, info)
case xhtml.SelfClosingTagToken, xhtml.EndTagToken:
tn, _ := tokenizer.TagName()
key, val, _ := tokenizer.TagAttr()
info := tagInfo{
tag: string(tn),
key: string(key),
val: string(val),
closingTag: true,
}
tokens = append(tokens, info)
}
}
return tokens
}
// walk is used to traverse each scoped block. These scoped
// blocks will act as blocked text where we do most of our
// text manipulation.
func walk(scopes [][]tagInfo) string {
doc := ""
// Documentation will be chunked by scopes.
// Meaning, for each scope will be divided by one or more newlines.
for _, scope := range scopes {
indentStr, isIndented := priorityIndentation(scope)
block := ""
href := ""
after := false
level := 0
lastTag := ""
for _, token := range scope {
if token.closingTag {
endl := closeTag(token, level)
block += endl
level--
lastTag = ""
} else if token.txt == "" {
if token.val != "" {
href, after = formatText(token, "")
}
if level == 1 && isIndented {
block += indentStr
}
level++
lastTag = token.tag
} else {
if token.txt != " " {
str, _ := formatText(token, lastTag)
block += str
if after {
block += href
after = false
}
} else {
fmt.Println(token.tag)
str, _ := formatText(tagInfo{}, lastTag)
block += str
}
}
}
if !isIndented {
block = strings.TrimPrefix(block, " ")
}
block = wrap(block, 72, isIndented)
doc += block
}
return doc
}
// closeTag will divide up the blocks of documentation to be formated properly.
func closeTag(token tagInfo, level int) string {
switch token.tag {
case "pre", "li", "div":
return "\n"
case "p", "h1", "h2", "h3", "h4", "h5", "h6":
return "\n\n"
case "code":
// indented code is only at the 0th level.
if level == 0 {
return "\n"
}
}
return ""
}
// formatText will format any sort of text based off of a tag. It will also return
// a boolean to add the string after the text token.
func formatText(token tagInfo, lastTag string) (string, bool) {
switch token.tag {
case "a":
if token.val != "" {
return fmt.Sprintf(" (%s)", token.val), true
}
}
// We don't care about a single space nor no text.
if len(token.txt) == 0 || token.txt == " " {
return "", false
}
// Here we want to indent code blocks that are newlines
if lastTag == "code" {
// Greater than one, because we don't care about newlines in the beginning
block := ""
if lines := strings.Split(token.txt, "\n"); len(lines) > 1 {
for _, line := range lines {
block += indent + line
}
block += "\n"
return block, false
}
}
return token.txt, false
}
// This is a parser to check what type of indention is needed.
func priorityIndentation(blocks []tagInfo) (string, bool) {
if len(blocks) == 0 {
return "", false
}
v, ok := style[blocks[0].tag]
return v, ok
}
// Divides into scopes based off levels.
// For instance,
// <p>Testing<code>123</code></p><ul><li>Foo</li></ul>
// This has 2 scopes, the <p> and <ul>
func findScopes(tokens []tagInfo) [][]tagInfo {
level := 0
scope := []tagInfo{}
scopes := [][]tagInfo{}
for _, token := range tokens {
// we will clear empty tagged tokens from the array
txt := strings.TrimSpace(token.txt)
tag := strings.TrimSpace(token.tag)
if len(txt) == 0 && len(tag) == 0 {
continue
}
scope = append(scope, token)
// If it is a closing tag then we check what level
// we are on. If it is 0, then that means we have found a
// scoped block.
if token.closingTag {
level--
if level == 0 {
scopes = append(scopes, scope)
scope = []tagInfo{}
}
// Check opening tags and increment the level
} else if token.txt == "" {
level++
}
}
// In this case, we did not run into a closing tag. This would mean
// we have plaintext for documentation.
if len(scopes) == 0 {
scopes = append(scopes, scope)
}
return scopes
}
-318
View File
@@ -1,318 +0,0 @@
// +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)
}
-256
View File
@@ -1,256 +0,0 @@
// +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()
}
@@ -1,28 +0,0 @@
// +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()
}
-14
View File
@@ -1,14 +0,0 @@
// +build codegen
package api
import "strings"
// ExportableName a name which is exportable as a value or name in Go code
func (a *API) ExportableName(name string) string {
if name == "" {
return name
}
return strings.ToUpper(name[0:1]) + name[1:]
}
-495
View File
@@ -1,495 +0,0 @@
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,
},
},
}
-74
View File
@@ -1,74 +0,0 @@
// +build codegen
package api
import (
"encoding/json"
"fmt"
"os"
"path/filepath"
)
// Load takes a set of files for each filetype and returns an API pointer.
// The API will be initialized once all files have been loaded and parsed.
//
// Will panic if any failure opening the definition JSON files, or there
// are unrecognized exported names.
func Load(api, docs, paginators, waiters string) *API {
a := API{}
a.Attach(api)
a.Attach(docs)
a.Attach(paginators)
a.Attach(waiters)
a.Setup()
return &a
}
// Attach opens a file by name, and unmarshal its JSON data.
// Will proceed to setup the API if not already done so.
func (a *API) Attach(filename string) {
a.path = filepath.Dir(filename)
f, err := os.Open(filename)
defer f.Close()
if err != nil {
panic(err)
}
if err := json.NewDecoder(f).Decode(a); err != nil {
panic(fmt.Errorf("failed to decode %s, err: %v", filename, err))
}
}
// AttachString will unmarshal a raw JSON string, and setup the
// API if not already done so.
func (a *API) AttachString(str string) {
json.Unmarshal([]byte(str), a)
if !a.initialized {
a.Setup()
}
}
// Setup initializes the API.
func (a *API) Setup() {
a.setMetadataEndpointsKey()
a.writeShapeNames()
a.resolveReferences()
a.fixStutterNames()
a.renameExportable()
if !a.NoRenameToplevelShapes {
a.renameToplevelShapes()
}
a.updateTopLevelShapeReferences()
a.createInputOutputShapes()
a.customizationPasses()
if !a.NoRemoveUnusedShapes {
a.removeUnusedShapes()
}
if !a.NoValidataShapeMethods {
a.addShapeValidations()
}
a.initialized = true
}
-493
View File
@@ -1,493 +0,0 @@
// +build codegen
package api
import (
"bytes"
"fmt"
"regexp"
"sort"
"strings"
"text/template"
)
// An Operation defines a specific API Operation.
type Operation struct {
API *API `json:"-"`
ExportedName string
Name string
Documentation string
HTTP HTTPInfo
InputRef ShapeRef `json:"input"`
OutputRef ShapeRef `json:"output"`
ErrorRefs []ShapeRef `json:"errors"`
Paginator *Paginator
Deprecated bool `json:"deprecated"`
AuthType string `json:"authtype"`
imports map[string]bool
}
// A HTTPInfo defines the method of HTTP request for the Operation.
type HTTPInfo struct {
Method string
RequestURI string
ResponseCode uint
}
// HasInput returns if the Operation accepts an input paramater
func (o *Operation) HasInput() bool {
return o.InputRef.ShapeName != ""
}
// HasOutput returns if the Operation accepts an output parameter
func (o *Operation) HasOutput() bool {
return o.OutputRef.ShapeName != ""
}
func (o *Operation) GetSigner() string {
if o.AuthType == "v4-unsigned-body" {
o.API.imports["github.com/aws/aws-sdk-go/aws/signer/v4"] = true
}
buf := bytes.NewBuffer(nil)
switch o.AuthType {
case "none":
buf.WriteString("req.Config.Credentials = credentials.AnonymousCredentials")
case "v4-unsigned-body":
buf.WriteString("req.Handlers.Sign.Remove(v4.SignRequestHandler)\n")
buf.WriteString("handler := v4.BuildNamedHandler(\"v4.CustomSignerHandler\", v4.WithUnsignedPayload)\n")
buf.WriteString("req.Handlers.Sign.PushFrontNamed(handler)")
}
buf.WriteString("\n")
return buf.String()
}
// tplOperation defines a template for rendering an API Operation
var tplOperation = template.Must(template.New("operation").Funcs(template.FuncMap{
"GetCrosslinkURL": GetCrosslinkURL,
}).Parse(`
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.
//
// See {{ .ExportedName }} for usage and error information.
//
// 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.
//
// 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)
//
// err := req.Send()
// if err == nil { // resp is now filled
// fmt.Println(resp)
// }
{{ $crosslinkURL := GetCrosslinkURL $.API.BaseCrosslinkURL $.API.APIName $.API.Metadata.UID $.ExportedName -}}
{{ if ne $crosslinkURL "" -}}
//
// Please also see {{ $crosslinkURL }}
{{ end -}}
func (c *{{ .API.StructName }}) {{ .ExportedName }}Request(` +
`input {{ .InputRef.GoType }}) (req *request.Request, output {{ .OutputRef.GoType }}) {
{{ if (or .Deprecated (or .InputRef.Deprecated .OutputRef.Deprecated)) }}if c.Client.Config.Logger != nil {
c.Client.Config.Logger.Log("This operation, {{ .ExportedName }}, has been deprecated")
}
op := &request.Operation{ {{ else }} op := &request.Operation{ {{ end }}
Name: op{{ .ExportedName }},
{{ if ne .HTTP.Method "" }}HTTPMethod: "{{ .HTTP.Method }}",
{{ end }}HTTPPath: {{ if ne .HTTP.RequestURI "" }}"{{ .HTTP.RequestURI }}"{{ else }}"/"{{ end }},
{{ if .Paginator }}Paginator: &request.Paginator{
InputTokens: {{ .Paginator.InputTokensString }},
OutputTokens: {{ .Paginator.OutputTokensString }},
LimitToken: "{{ .Paginator.LimitKey }}",
TruncationToken: "{{ .Paginator.MoreResults }}",
},
{{ end }}
}
if input == nil {
input = &{{ .InputRef.GoTypeElem }}{}
}
output = &{{ .OutputRef.GoTypeElem }}{}
req = c.newRequest(op, input, output){{ if eq .OutputRef.Shape.Placeholder true }}
req.Handlers.Unmarshal.Remove({{ .API.ProtocolPackage }}.UnmarshalHandler)
req.Handlers.Unmarshal.PushBackNamed(protocol.UnmarshalDiscardBodyHandler){{ end }}
{{ if ne .AuthType "" }}{{ .GetSigner }}{{ end -}}
return
}
// {{ .ExportedName }} API operation for {{ .API.Metadata.ServiceFullName }}.
{{ if .Documentation -}}
//
{{ .Documentation }}
{{ end -}}
//
// Returns awserr.Error for service API and SDK errors. Use runtime type assertions
// with awserr.Error's Code and Message methods to get detailed information about
// the error.
//
// See the AWS API reference guide for {{ .API.Metadata.ServiceFullName }}'s
// API operation {{ .ExportedName }} for usage and error information.
{{ if .ErrorRefs -}}
//
// Returned Error Codes:
{{ range $_, $err := .ErrorRefs -}}
// * {{ $err.Shape.ErrorCodeName }} "{{ $err.Shape.ErrorName}}"
{{ if $err.Docstring -}}
{{ $err.IndentedDocstring }}
{{ end -}}
//
{{ end -}}
{{ end -}}
{{ $crosslinkURL := GetCrosslinkURL $.API.BaseCrosslinkURL $.API.APIName $.API.Metadata.UID $.ExportedName -}}
{{ if ne $crosslinkURL "" -}}
// Please also see {{ $crosslinkURL }}
{{ end -}}
func (c *{{ .API.StructName }}) {{ .ExportedName }}(` +
`input {{ .InputRef.GoType }}) ({{ .OutputRef.GoType }}, error) {
req, out := c.{{ .ExportedName }}Request(input)
return out, req.Send()
}
// {{ .ExportedName }}WithContext is the same as {{ .ExportedName }} with the addition of
// the ability to pass a context and additional request options.
//
// See {{ .ExportedName }} for details on how to use this API operation.
//
// The context must be non-nil and will be used for request cancellation. If
// the context is nil a panic will occur. In the future the SDK may create
// sub-contexts for http.Requests. See https://golang.org/pkg/context/
// for more information on using Contexts.
func (c *{{ .API.StructName }}) {{ .ExportedName }}WithContext(` +
`ctx aws.Context, input {{ .InputRef.GoType }}, opts ...request.Option) ` +
`({{ .OutputRef.GoType }}, error) {
req, out := c.{{ .ExportedName }}Request(input)
req.SetContext(ctx)
req.ApplyOptions(opts...)
return out, req.Send()
}
{{ if .Paginator }}
// {{ .ExportedName }}Pages iterates over the pages of a {{ .ExportedName }} operation,
// calling the "fn" function with the response data for each page. To stop
// iterating, return false from the fn function.
//
// See {{ .ExportedName }} method for more information on how to use this operation.
//
// Note: This operation can generate multiple requests to a service.
//
// // Example iterating over at most 3 pages of a {{ .ExportedName }} operation.
// pageNum := 0
// err := client.{{ .ExportedName }}Pages(params,
// func(page {{ .OutputRef.GoType }}, lastPage bool) bool {
// pageNum++
// fmt.Println(page)
// return pageNum <= 3
// })
//
func (c *{{ .API.StructName }}) {{ .ExportedName }}Pages(` +
`input {{ .InputRef.GoType }}, fn func({{ .OutputRef.GoType }}, bool) bool) error {
return c.{{ .ExportedName }}PagesWithContext(aws.BackgroundContext(), input, fn)
}
// {{ .ExportedName }}PagesWithContext same as {{ .ExportedName }}Pages except
// it takes a Context and allows setting request options on the pages.
//
// The context must be non-nil and will be used for request cancellation. If
// the context is nil a panic will occur. In the future the SDK may create
// sub-contexts for http.Requests. See https://golang.org/pkg/context/
// for more information on using Contexts.
func (c *{{ .API.StructName }}) {{ .ExportedName }}PagesWithContext(` +
`ctx aws.Context, ` +
`input {{ .InputRef.GoType }}, ` +
`fn func({{ .OutputRef.GoType }}, bool) bool, ` +
`opts ...request.Option) error {
p := request.Pagination {
NewRequest: func() (*request.Request, error) {
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
},
}
cont := true
for p.Next() && cont {
cont = fn(p.Page().({{ .OutputRef.GoType }}), !p.HasNextPage())
}
return p.Err()
}
{{ end }}
`))
// GoCode returns a string of rendered GoCode for this Operation
func (o *Operation) GoCode() string {
var buf bytes.Buffer
err := tplOperation.Execute(&buf, o)
if err != nil {
panic(err)
}
return strings.TrimSpace(buf.String())
}
// tplInfSig defines the template for rendering an Operation's signature within an Interface definition.
var tplInfSig = template.Must(template.New("opsig").Parse(`
{{ .ExportedName }}({{ .InputRef.GoTypeWithPkgName }}) ({{ .OutputRef.GoTypeWithPkgName }}, error)
{{ .ExportedName }}WithContext(aws.Context, {{ .InputRef.GoTypeWithPkgName }}, ...request.Option) ({{ .OutputRef.GoTypeWithPkgName }}, error)
{{ .ExportedName }}Request({{ .InputRef.GoTypeWithPkgName }}) (*request.Request, {{ .OutputRef.GoTypeWithPkgName }})
{{ if .Paginator -}}
{{ .ExportedName }}Pages({{ .InputRef.GoTypeWithPkgName }}, func({{ .OutputRef.GoTypeWithPkgName }}, bool) bool) error
{{ .ExportedName }}PagesWithContext(aws.Context, {{ .InputRef.GoTypeWithPkgName }}, func({{ .OutputRef.GoTypeWithPkgName }}, bool) bool, ...request.Option) error
{{- end }}
`))
// InterfaceSignature returns a string representing the Operation's interface{}
// functional signature.
func (o *Operation) InterfaceSignature() string {
var buf bytes.Buffer
err := tplInfSig.Execute(&buf, o)
if err != nil {
panic(err)
}
return strings.TrimSpace(buf.String())
}
// tplExample defines the template for rendering an Operation example
var tplExample = template.Must(template.New("operationExample").Parse(`
func Example{{ .API.StructName }}_{{ .ExportedName }}() {
sess := session.Must(session.NewSession())
svc := {{ .API.PackageName }}.New(sess)
{{ .ExampleInput }}
resp, err := svc.{{ .ExportedName }}(params)
if err != nil {
// Print the error, cast err to awserr.Error to get the Code and
// Message from an error.
fmt.Println(err.Error())
return
}
// Pretty-print the response data.
fmt.Println(resp)
}
`))
// Example returns a string of the rendered Go code for the Operation
func (o *Operation) Example() string {
var buf bytes.Buffer
err := tplExample.Execute(&buf, o)
if err != nil {
panic(err)
}
return strings.TrimSpace(buf.String())
}
// ExampleInput return a string of the rendered Go code for an example's input parameters
func (o *Operation) ExampleInput() string {
if len(o.InputRef.Shape.MemberRefs) == 0 {
if strings.Contains(o.InputRef.GoTypeElem(), ".") {
o.imports["github.com/aws/aws-sdk-go/service/"+strings.Split(o.InputRef.GoTypeElem(), ".")[0]] = true
return fmt.Sprintf("var params *%s", o.InputRef.GoTypeElem())
}
return fmt.Sprintf("var params *%s.%s",
o.API.PackageName(), o.InputRef.GoTypeElem())
}
e := example{o, map[string]int{}}
return "params := " + e.traverseAny(o.InputRef.Shape, false, false)
}
// A example provides
type example struct {
*Operation
visited map[string]int
}
// traverseAny returns rendered Go code for the shape.
func (e *example) traverseAny(s *Shape, required, payload bool) string {
str := ""
e.visited[s.ShapeName]++
switch s.Type {
case "structure":
str = e.traverseStruct(s, required, payload)
case "list":
str = e.traverseList(s, required, payload)
case "map":
str = e.traverseMap(s, required, payload)
case "jsonvalue":
str = "aws.JSONValue{\"key\": \"value\"}"
if required {
str += " // Required"
}
default:
str = e.traverseScalar(s, required, payload)
}
e.visited[s.ShapeName]--
return str
}
var reType = regexp.MustCompile(`\b([A-Z])`)
// traverseStruct returns rendered Go code for a structure type shape.
func (e *example) traverseStruct(s *Shape, required, payload bool) string {
var buf bytes.Buffer
if s.resolvePkg != "" {
e.imports[s.resolvePkg] = true
buf.WriteString("&" + s.GoTypeElem() + "{")
} else {
buf.WriteString("&" + s.API.PackageName() + "." + s.GoTypeElem() + "{")
}
if required {
buf.WriteString(" // Required")
}
buf.WriteString("\n")
req := make([]string, len(s.Required))
copy(req, s.Required)
sort.Strings(req)
if e.visited[s.ShapeName] < 2 {
for _, n := range req {
m := s.MemberRefs[n].Shape
p := n == s.Payload && (s.MemberRefs[n].Streaming || m.Streaming)
buf.WriteString(n + ": " + e.traverseAny(m, true, p) + ",")
if m.Type != "list" && m.Type != "structure" && m.Type != "map" {
buf.WriteString(" // Required")
}
buf.WriteString("\n")
}
for _, n := range s.MemberNames() {
if s.IsRequired(n) {
continue
}
m := s.MemberRefs[n].Shape
p := n == s.Payload && (s.MemberRefs[n].Streaming || m.Streaming)
buf.WriteString(n + ": " + e.traverseAny(m, false, p) + ",\n")
}
} else {
buf.WriteString("// Recursive values...\n")
}
buf.WriteString("}")
return buf.String()
}
// traverseMap returns rendered Go code for a map type shape.
func (e *example) traverseMap(s *Shape, required, payload bool) string {
var buf bytes.Buffer
t := ""
if s.resolvePkg != "" {
e.imports[s.resolvePkg] = true
t = s.GoTypeElem()
} else {
t = reType.ReplaceAllString(s.GoTypeElem(), s.API.PackageName()+".$1")
}
buf.WriteString(t + "{")
if required {
buf.WriteString(" // Required")
}
buf.WriteString("\n")
if e.visited[s.ShapeName] < 2 {
m := s.ValueRef.Shape
buf.WriteString("\"Key\": " + e.traverseAny(m, true, false) + ",")
if m.Type != "list" && m.Type != "structure" && m.Type != "map" {
buf.WriteString(" // Required")
}
buf.WriteString("\n// More values...\n")
} else {
buf.WriteString("// Recursive values...\n")
}
buf.WriteString("}")
return buf.String()
}
// traverseList returns rendered Go code for a list type shape.
func (e *example) traverseList(s *Shape, required, payload bool) string {
var buf bytes.Buffer
t := ""
if s.resolvePkg != "" {
e.imports[s.resolvePkg] = true
t = s.GoTypeElem()
} else {
t = reType.ReplaceAllString(s.GoTypeElem(), s.API.PackageName()+".$1")
}
buf.WriteString(t + "{")
if required {
buf.WriteString(" // Required")
}
buf.WriteString("\n")
if e.visited[s.ShapeName] < 2 {
m := s.MemberRef.Shape
buf.WriteString(e.traverseAny(m, true, false) + ",")
if m.Type != "list" && m.Type != "structure" && m.Type != "map" {
buf.WriteString(" // Required")
}
buf.WriteString("\n// More values...\n")
} else {
buf.WriteString("// Recursive values...\n")
}
buf.WriteString("}")
return buf.String()
}
// traverseScalar returns an AWS Type string representation initialized to a value.
// Will panic if s is an unsupported shape type.
func (e *example) traverseScalar(s *Shape, required, payload bool) string {
str := ""
switch s.Type {
case "integer", "long":
str = `aws.Int64(1)`
case "float", "double":
str = `aws.Float64(1.0)`
case "string", "character":
str = `aws.String("` + s.ShapeName + `")`
case "blob":
if payload {
str = `bytes.NewReader([]byte("PAYLOAD"))`
} else {
str = `[]byte("PAYLOAD")`
}
case "boolean":
str = `aws.Bool(true)`
case "timestamp":
str = `aws.Time(time.Now())`
default:
panic("unsupported shape " + s.Type)
}
return str
}
-91
View File
@@ -1,91 +0,0 @@
// +build codegen
package api
import (
"encoding/json"
"fmt"
"os"
)
// Paginator keeps track of pagination configuration for an API operation.
type Paginator struct {
InputTokens interface{} `json:"input_token"`
OutputTokens interface{} `json:"output_token"`
LimitKey string `json:"limit_key"`
MoreResults string `json:"more_results"`
}
// InputTokensString returns output tokens formatted as a list
func (p *Paginator) InputTokensString() string {
str := p.InputTokens.([]string)
return fmt.Sprintf("%#v", str)
}
// OutputTokensString returns output tokens formatted as a list
func (p *Paginator) OutputTokensString() string {
str := p.OutputTokens.([]string)
return fmt.Sprintf("%#v", str)
}
// used for unmarshaling from the paginators JSON file
type paginationDefinitions struct {
*API
Pagination map[string]Paginator
}
// AttachPaginators attaches pagination configuration from filename to the API.
func (a *API) AttachPaginators(filename string) {
p := paginationDefinitions{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()
}
// setup runs post-processing on the paginator configuration.
func (p *paginationDefinitions) setup() {
for n, e := range p.Pagination {
if e.InputTokens == nil || e.OutputTokens == nil {
continue
}
paginator := e
switch t := paginator.InputTokens.(type) {
case string:
paginator.InputTokens = []string{t}
case []interface{}:
toks := []string{}
for _, e := range t {
s := e.(string)
toks = append(toks, s)
}
paginator.InputTokens = toks
}
switch t := paginator.OutputTokens.(type) {
case string:
paginator.OutputTokens = []string{t}
case []interface{}:
toks := []string{}
for _, e := range t {
s := e.(string)
toks = append(toks, s)
}
paginator.OutputTokens = toks
}
if o, ok := p.Operations[n]; ok {
o.Paginator = &paginator
} else {
panic("unknown operation for paginator " + n)
}
}
}
-133
View File
@@ -1,133 +0,0 @@
// +build codegen
package api
import (
"fmt"
"reflect"
"strings"
"github.com/aws/aws-sdk-go/private/util"
)
// A paramFiller provides string formatting for a shape and its types.
type paramFiller struct {
prefixPackageName bool
}
// typeName returns the type name of a shape.
func (f paramFiller) typeName(shape *Shape) string {
if f.prefixPackageName && shape.Type == "structure" {
return "*" + shape.API.PackageName() + "." + shape.GoTypeElem()
}
return shape.GoType()
}
// ParamsStructFromJSON returns a JSON string representation of a structure.
func ParamsStructFromJSON(value interface{}, shape *Shape, prefixPackageName bool) string {
f := paramFiller{prefixPackageName: prefixPackageName}
return util.GoFmt(f.paramsStructAny(value, shape))
}
// paramsStructAny returns the string representation of any value.
func (f paramFiller) paramsStructAny(value interface{}, shape *Shape) string {
if value == nil {
return ""
}
switch shape.Type {
case "structure":
if value != nil {
vmap := value.(map[string]interface{})
return f.paramsStructStruct(vmap, shape)
}
case "list":
vlist := value.([]interface{})
return f.paramsStructList(vlist, shape)
case "map":
vmap := value.(map[string]interface{})
return f.paramsStructMap(vmap, shape)
case "string", "character":
v := reflect.Indirect(reflect.ValueOf(value))
if v.IsValid() {
return fmt.Sprintf("aws.String(%#v)", v.Interface())
}
case "blob":
v := reflect.Indirect(reflect.ValueOf(value))
if v.IsValid() && shape.Streaming {
return fmt.Sprintf("bytes.NewReader([]byte(%#v))", v.Interface())
} else if v.IsValid() {
return fmt.Sprintf("[]byte(%#v)", v.Interface())
}
case "boolean":
v := reflect.Indirect(reflect.ValueOf(value))
if v.IsValid() {
return fmt.Sprintf("aws.Bool(%#v)", v.Interface())
}
case "integer", "long":
v := reflect.Indirect(reflect.ValueOf(value))
if v.IsValid() {
return fmt.Sprintf("aws.Int64(%v)", v.Interface())
}
case "float", "double":
v := reflect.Indirect(reflect.ValueOf(value))
if v.IsValid() {
return fmt.Sprintf("aws.Float64(%v)", v.Interface())
}
case "timestamp":
v := reflect.Indirect(reflect.ValueOf(value))
if v.IsValid() {
return fmt.Sprintf("aws.Time(time.Unix(%d, 0))", int(v.Float()))
}
default:
panic("Unhandled type " + shape.Type)
}
return ""
}
// paramsStructStruct returns the string representation of a structure
func (f paramFiller) paramsStructStruct(value map[string]interface{}, shape *Shape) string {
out := "&" + f.typeName(shape)[1:] + "{\n"
for _, n := range shape.MemberNames() {
ref := shape.MemberRefs[n]
name := findParamMember(value, n)
if val := f.paramsStructAny(value[name], ref.Shape); val != "" {
out += fmt.Sprintf("%s: %s,\n", n, val)
}
}
out += "}"
return out
}
// paramsStructMap returns the string representation of a map of values
func (f paramFiller) paramsStructMap(value map[string]interface{}, shape *Shape) string {
out := f.typeName(shape) + "{\n"
keys := util.SortedKeys(value)
for _, k := range keys {
v := value[k]
out += fmt.Sprintf("%q: %s,\n", k, f.paramsStructAny(v, shape.ValueRef.Shape))
}
out += "}"
return out
}
// paramsStructList returns the string representation of slice of values
func (f paramFiller) paramsStructList(value []interface{}, shape *Shape) string {
out := f.typeName(shape) + "{\n"
for _, v := range value {
out += fmt.Sprintf("%s,\n", f.paramsStructAny(v, shape.MemberRef.Shape))
}
out += "}"
return out
}
// findParamMember searches a map for a key ignoring case. Returns the map key if found.
func findParamMember(value map[string]interface{}, key string) string {
for actualKey := range value {
if strings.ToLower(key) == strings.ToLower(actualKey) {
return actualKey
}
}
return ""
}
-306
View File
@@ -1,306 +0,0 @@
// +build codegen
package api
import (
"fmt"
"regexp"
"strings"
)
// updateTopLevelShapeReferences moves resultWrapper, locationName, and
// xmlNamespace traits from toplevel shape references to the toplevel
// shapes for easier code generation
func (a *API) updateTopLevelShapeReferences() {
for _, o := range a.Operations {
// these are for REST-XML services
if o.InputRef.LocationName != "" {
o.InputRef.Shape.LocationName = o.InputRef.LocationName
}
if o.InputRef.Location != "" {
o.InputRef.Shape.Location = o.InputRef.Location
}
if o.InputRef.Payload != "" {
o.InputRef.Shape.Payload = o.InputRef.Payload
}
if o.InputRef.XMLNamespace.Prefix != "" {
o.InputRef.Shape.XMLNamespace.Prefix = o.InputRef.XMLNamespace.Prefix
}
if o.InputRef.XMLNamespace.URI != "" {
o.InputRef.Shape.XMLNamespace.URI = o.InputRef.XMLNamespace.URI
}
}
}
// writeShapeNames sets each shape's API and shape name values. Binding the
// shape to its parent API.
func (a *API) writeShapeNames() {
for n, s := range a.Shapes {
s.API = a
s.ShapeName = n
}
}
func (a *API) resolveReferences() {
resolver := referenceResolver{API: a, visited: map[*ShapeRef]bool{}}
for _, s := range a.Shapes {
resolver.resolveShape(s)
}
for _, o := range a.Operations {
o.API = a // resolve parent reference
resolver.resolveReference(&o.InputRef)
resolver.resolveReference(&o.OutputRef)
// Resolve references for errors also
for i := range o.ErrorRefs {
resolver.resolveReference(&o.ErrorRefs[i])
o.ErrorRefs[i].Shape.IsError = true
}
}
}
// A referenceResolver provides a way to resolve shape references to
// shape definitions.
type referenceResolver struct {
*API
visited map[*ShapeRef]bool
}
var jsonvalueShape = &Shape{
ShapeName: "JSONValue",
Type: "jsonvalue",
ValueRef: ShapeRef{
JSONValue: true,
},
}
// resolveReference updates a shape reference to reference the API and
// its shape definition. All other nested references are also resolved.
func (r *referenceResolver) resolveReference(ref *ShapeRef) {
if ref.ShapeName == "" {
return
}
if shape, ok := r.API.Shapes[ref.ShapeName]; ok {
if ref.JSONValue {
ref.ShapeName = "JSONValue"
r.API.Shapes[ref.ShapeName] = jsonvalueShape
}
ref.API = r.API // resolve reference back to API
ref.Shape = shape // resolve shape reference
if r.visited[ref] {
return
}
r.visited[ref] = true
shape.refs = append(shape.refs, ref) // register the ref
// resolve shape's references, if it has any
r.resolveShape(shape)
}
}
// resolveShape resolves a shape's Member Key Value, and nested member
// shape references.
func (r *referenceResolver) resolveShape(shape *Shape) {
r.resolveReference(&shape.MemberRef)
r.resolveReference(&shape.KeyRef)
r.resolveReference(&shape.ValueRef)
for _, m := range shape.MemberRefs {
r.resolveReference(m)
}
}
// renameToplevelShapes renames all top level shapes of an API to their
// exportable variant. The shapes are also updated to include notations
// if they are Input or Outputs.
func (a *API) renameToplevelShapes() {
for _, v := range a.OperationList() {
if v.HasInput() {
name := v.ExportedName + "Input"
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 {
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)
}
}
v.InputRef.Payload = a.ExportableName(v.InputRef.Payload)
v.OutputRef.Payload = a.ExportableName(v.OutputRef.Payload)
}
}
// fixStutterNames fixes all name struttering based on Go naming conventions.
// "Stuttering" is when the prefix of a structure or function matches the
// package name (case insensitive).
func (a *API) fixStutterNames() {
str, end := a.StructName(), ""
if len(str) > 1 {
l := len(str) - 1
str, end = str[0:l], str[l:]
}
re := regexp.MustCompile(fmt.Sprintf(`\A(?i:%s)%s`, str, end))
for name, op := range a.Operations {
newName := re.ReplaceAllString(name, "")
if newName != name {
delete(a.Operations, name)
a.Operations[newName] = op
}
op.ExportedName = newName
}
for k, s := range a.Shapes {
newName := re.ReplaceAllString(k, "")
if newName != s.ShapeName {
s.Rename(newName)
}
}
}
// renameExportable renames all operation names to be exportable names.
// All nested Shape names are also updated to the exportable variant.
func (a *API) renameExportable() {
for name, op := range a.Operations {
newName := a.ExportableName(name)
if newName != name {
delete(a.Operations, name)
a.Operations[newName] = op
}
op.ExportedName = newName
}
for k, s := range a.Shapes {
// FIXME SNS has lower and uppercased shape names with the same name,
// except the lowercased variant is used exclusively for string and
// other primitive types. Renaming both would cause a collision.
// We work around this by only renaming the structure shapes.
if s.Type == "string" {
continue
}
for mName, member := range s.MemberRefs {
newName := a.ExportableName(mName)
if newName != mName {
delete(s.MemberRefs, mName)
s.MemberRefs[newName] = member
// also apply locationName trait so we keep the old one
// but only if there's no locationName trait on ref or shape
if member.LocationName == "" && member.Shape.LocationName == "" {
member.LocationName = mName
}
}
if newName == "_" {
panic("Shape " + s.ShapeName + " uses reserved member name '_'")
}
}
newName := a.ExportableName(k)
if newName != s.ShapeName {
s.Rename(newName)
}
s.Payload = a.ExportableName(s.Payload)
// fix required trait names
for i, n := range s.Required {
s.Required[i] = a.ExportableName(n)
}
}
for _, s := range a.Shapes {
// fix enum names
if s.IsEnum() {
s.EnumConsts = make([]string, len(s.Enum))
for i := range s.Enum {
shape := s.ShapeName
shape = strings.ToUpper(shape[0:1]) + shape[1:]
s.EnumConsts[i] = shape + s.EnumName(i)
}
}
}
}
// createInputOutputShapes creates toplevel input/output shapes if they
// have not been defined in the API. This normalizes all APIs to always
// have an input and output structure in the signature.
func (a *API) createInputOutputShapes() {
for _, op := range a.Operations {
if !op.HasInput() {
setAsPlacholderShape(&op.InputRef, op.ExportedName+"Input", a)
}
if !op.HasOutput() {
setAsPlacholderShape(&op.OutputRef, op.ExportedName+"Output", a)
}
}
}
func setAsPlacholderShape(tgtShapeRef *ShapeRef, name string, a *API) {
shape := a.makeIOShape(name)
shape.Placeholder = true
*tgtShapeRef = ShapeRef{API: a, ShapeName: shape.ShapeName, Shape: shape}
shape.refs = append(shape.refs, tgtShapeRef)
}
// makeIOShape returns a pointer to a new Shape initialized by the name provided.
func (a *API) makeIOShape(name string) *Shape {
shape := &Shape{
API: a, ShapeName: name, Type: "structure",
MemberRefs: map[string]*ShapeRef{},
}
a.Shapes[name] = shape
return shape
}
// removeUnusedShapes removes shapes from the API which are not referenced by any
// other shape in the API.
func (a *API) removeUnusedShapes() {
for n, s := range a.Shapes {
if len(s.refs) == 0 {
delete(a.Shapes, n)
}
}
}
// Represents the service package name to EndpointsID mapping
var custEndpointsKey = map[string]string{
"applicationautoscaling": "application-autoscaling",
}
// Sents the EndpointsID field of Metadata with the value of the
// EndpointPrefix if EndpointsID is not set. Also adds
// customizations for services if EndpointPrefix is not a valid key.
func (a *API) setMetadataEndpointsKey() {
if len(a.Metadata.EndpointsID) != 0 {
return
}
if v, ok := custEndpointsKey[a.PackageName()]; ok {
a.Metadata.EndpointsID = v
} else {
a.Metadata.EndpointsID = a.Metadata.EndpointPrefix
}
}
-684
View File
@@ -1,684 +0,0 @@
// +build codegen
package api
import (
"bytes"
"fmt"
"path"
"regexp"
"sort"
"strings"
"text/template"
)
// A ShapeRef defines the usage of a shape within the API.
type ShapeRef struct {
API *API `json:"-"`
Shape *Shape `json:"-"`
Documentation string
ShapeName string `json:"shape"`
Location string
LocationName string
QueryName string
Flattened bool
Streaming bool
XMLAttribute bool
// Ignore, if set, will not be sent over the wire
Ignore bool
XMLNamespace XMLInfo
Payload string
IdempotencyToken bool `json:"idempotencyToken"`
JSONValue bool `json:"jsonvalue"`
Deprecated bool `json:"deprecated"`
OrigShapeName string `json:"-"`
GenerateGetter bool
}
// ErrorInfo represents the error block of a shape's structure
type ErrorInfo struct {
Code string
HTTPStatusCode int
}
// A XMLInfo defines URL and prefix for Shapes when rendered as XML
type XMLInfo struct {
Prefix string
URI string
}
// A Shape defines the definition of a shape type
type Shape struct {
API *API `json:"-"`
ShapeName string
Documentation string
MemberRefs map[string]*ShapeRef `json:"members"`
MemberRef ShapeRef `json:"member"`
KeyRef ShapeRef `json:"key"`
ValueRef ShapeRef `json:"value"`
Required []string
Payload string
Type string
Exception bool
Enum []string
EnumConsts []string
Flattened bool
Streaming bool
Location string
LocationName string
IdempotencyToken bool `json:"idempotencyToken"`
XMLNamespace XMLInfo
Min float64 // optional Minimum length (string, list) or value (number)
Max float64 // optional Maximum length (string, list) or value (number)
refs []*ShapeRef // References to this shape
resolvePkg string // use this package in the goType() if present
OrigShapeName string `json:"-"`
// Defines if the shape is a placeholder and should not be used directly
Placeholder bool
Deprecated bool `json:"deprecated"`
Validations ShapeValidations
// Error information that is set if the shape is an error shape.
IsError bool
ErrorInfo ErrorInfo `json:"error"`
}
// ErrorCodeName will return the error shape's name formated for
// error code const.
func (s *Shape) ErrorCodeName() string {
return "ErrCode" + s.ShapeName
}
// ErrorName will return the shape's name or error code if available based
// on the API's protocol. This is the error code string returned by the service.
func (s *Shape) ErrorName() string {
name := s.ShapeName
switch s.API.Metadata.Protocol {
case "query", "ec2query", "rest-xml":
if len(s.ErrorInfo.Code) > 0 {
name = s.ErrorInfo.Code
}
}
return name
}
// GoTags returns the struct tags for a shape.
func (s *Shape) GoTags(root, required bool) string {
ref := &ShapeRef{ShapeName: s.ShapeName, API: s.API, Shape: s}
return ref.GoTags(root, required)
}
// Rename changes the name of the Shape to newName. Also updates
// the associated API's reference to use newName.
func (s *Shape) Rename(newName string) {
for _, r := range s.refs {
r.OrigShapeName = r.ShapeName
r.ShapeName = newName
}
delete(s.API.Shapes, s.ShapeName)
s.OrigShapeName = s.ShapeName
s.API.Shapes[newName] = s
s.ShapeName = newName
}
// MemberNames returns a slice of struct member names.
func (s *Shape) MemberNames() []string {
i, names := 0, make([]string, len(s.MemberRefs))
for n := range s.MemberRefs {
names[i] = n
i++
}
sort.Strings(names)
return names
}
// GoTypeWithPkgName returns a shape's type as a string with the package name in
// <packageName>.<type> format. Package naming only applies to structures.
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 {
case "map", "list", "blob", "structure", "jsonvalue":
return false
}
if s.Streaming || s.Shape.Streaming {
return false
}
if s.JSONValue {
return false
}
return true
}
// GoStructValueType returns the Shape's Go type value instead of a pointer
// for the type.
func (s *Shape) GoStructValueType(name string, ref *ShapeRef) string {
v := s.GoStructType(name, ref)
if ref.UseIndirection() && v[0] == '*' {
return v[1:]
}
return v
}
// GoStructType returns the type of a struct field based on the API
// model definition.
func (s *Shape) GoStructType(name string, ref *ShapeRef) string {
if (ref.Streaming || ref.Shape.Streaming) && s.Payload == name {
rtype := "io.ReadSeeker"
if strings.HasSuffix(s.ShapeName, "Output") {
rtype = "io.ReadCloser"
}
s.API.imports["io"] = true
return rtype
}
if ref.JSONValue {
s.API.imports["github.com/aws/aws-sdk-go/aws"] = true
return "aws.JSONValue"
}
for _, v := range s.Validations {
// TODO move this to shape validation resolution
if (v.Ref.Shape.Type == "map" || v.Ref.Shape.Type == "list") && v.Type == ShapeValidationNested {
s.API.imports["fmt"] = true
}
}
return ref.GoType()
}
// GoType returns a shape's Go type
func (s *Shape) GoType() string {
return goType(s, false)
}
// GoType returns a shape ref's Go type.
func (ref *ShapeRef) GoType() string {
if ref.Shape == nil {
panic(fmt.Errorf("missing shape definition on reference for %#v", ref))
}
return ref.Shape.GoType()
}
// GoTypeWithPkgName returns a shape's type as a string with the package name in
// <packageName>.<type> format. Package naming only applies to structures.
func (ref *ShapeRef) GoTypeWithPkgName() string {
if ref.Shape == nil {
panic(fmt.Errorf("missing shape definition on reference for %#v", ref))
}
return ref.Shape.GoTypeWithPkgName()
}
// Returns a string version of the Shape's type.
// If withPkgName is true, the package name will be added as a prefix
func goType(s *Shape, withPkgName bool) string {
switch s.Type {
case "structure":
if withPkgName || s.resolvePkg != "" {
pkg := s.resolvePkg
if pkg != "" {
s.API.imports[pkg] = true
pkg = path.Base(pkg)
} else {
pkg = s.API.PackageName()
}
return fmt.Sprintf("*%s.%s", pkg, s.ShapeName)
}
return "*" + s.ShapeName
case "map":
return "map[string]" + goType(s.ValueRef.Shape, withPkgName)
case "jsonvalue":
return "aws.JSONValue"
case "list":
return "[]" + goType(s.MemberRef.Shape, withPkgName)
case "boolean":
return "*bool"
case "string", "character":
return "*string"
case "blob":
return "[]byte"
case "integer", "long":
return "*int64"
case "float", "double":
return "*float64"
case "timestamp":
s.API.imports["time"] = true
return "*time.Time"
default:
panic("Unsupported shape type: " + s.Type)
}
}
// GoTypeElem returns the Go type for the Shape. If the shape type is a pointer just
// the type will be returned minus the pointer *.
func (s *Shape) GoTypeElem() string {
t := s.GoType()
if strings.HasPrefix(t, "*") {
return t[1:]
}
return t
}
// GoTypeElem returns the Go type for the Shape. If the shape type is a pointer just
// the type will be returned minus the pointer *.
func (ref *ShapeRef) GoTypeElem() string {
if ref.Shape == nil {
panic(fmt.Errorf("missing shape definition on reference for %#v", ref))
}
return ref.Shape.GoTypeElem()
}
// ShapeTag is a struct tag that will be applied to a shape's generated code
type ShapeTag struct {
Key, Val string
}
// String returns the string representation of the shape tag
func (s ShapeTag) String() string {
return fmt.Sprintf(`%s:"%s"`, s.Key, s.Val)
}
// ShapeTags is a collection of shape tags and provides serialization of the
// tags in an ordered list.
type ShapeTags []ShapeTag
// Join returns an ordered serialization of the shape tags with the provided
// separator.
func (s ShapeTags) Join(sep string) string {
o := &bytes.Buffer{}
for i, t := range s {
o.WriteString(t.String())
if i < len(s)-1 {
o.WriteString(sep)
}
}
return o.String()
}
// String is an alias for Join with the empty space separator.
func (s ShapeTags) String() string {
return s.Join(" ")
}
// GoTags returns the rendered tags string for the ShapeRef
func (ref *ShapeRef) GoTags(toplevel bool, isRequired bool) string {
tags := ShapeTags{}
if ref.Location != "" {
tags = append(tags, ShapeTag{"location", ref.Location})
} else if ref.Shape.Location != "" {
tags = append(tags, ShapeTag{"location", ref.Shape.Location})
}
if ref.LocationName != "" {
tags = append(tags, ShapeTag{"locationName", ref.LocationName})
} else if ref.Shape.LocationName != "" {
tags = append(tags, ShapeTag{"locationName", ref.Shape.LocationName})
}
if ref.QueryName != "" {
tags = append(tags, ShapeTag{"queryName", ref.QueryName})
}
if ref.Shape.MemberRef.LocationName != "" {
tags = append(tags, ShapeTag{"locationNameList", ref.Shape.MemberRef.LocationName})
}
if ref.Shape.KeyRef.LocationName != "" {
tags = append(tags, ShapeTag{"locationNameKey", ref.Shape.KeyRef.LocationName})
}
if ref.Shape.ValueRef.LocationName != "" {
tags = append(tags, ShapeTag{"locationNameValue", ref.Shape.ValueRef.LocationName})
}
if ref.Shape.Min > 0 {
tags = append(tags, ShapeTag{"min", fmt.Sprintf("%v", ref.Shape.Min)})
}
if ref.Deprecated || ref.Shape.Deprecated {
tags = append(tags, ShapeTag{"deprecated", "true"})
}
// All shapes have a type
tags = append(tags, ShapeTag{"type", ref.Shape.Type})
// embed the timestamp type for easier lookups
if ref.Shape.Type == "timestamp" {
t := ShapeTag{Key: "timestampFormat"}
if ref.Location == "header" {
t.Val = "rfc822"
} else {
switch ref.API.Metadata.Protocol {
case "json", "rest-json":
t.Val = "unix"
case "rest-xml", "ec2", "query":
t.Val = "iso8601"
}
}
tags = append(tags, t)
}
if ref.Shape.Flattened || ref.Flattened {
tags = append(tags, ShapeTag{"flattened", "true"})
}
if ref.XMLAttribute {
tags = append(tags, ShapeTag{"xmlAttribute", "true"})
}
if isRequired {
tags = append(tags, ShapeTag{"required", "true"})
}
if ref.Shape.IsEnum() {
tags = append(tags, ShapeTag{"enum", ref.ShapeName})
}
if toplevel {
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.IdempotencyToken || ref.Shape.IdempotencyToken {
tags = append(tags, ShapeTag{"idempotencyToken", "true"})
}
if ref.Ignore {
tags = append(tags, ShapeTag{"ignore", "true"})
}
return fmt.Sprintf("`%s`", tags)
}
// Docstring returns the godocs formated documentation
func (ref *ShapeRef) Docstring() string {
if ref.Documentation != "" {
return strings.Trim(ref.Documentation, "\n ")
}
return ref.Shape.Docstring()
}
// Docstring returns the godocs formated documentation
func (s *Shape) Docstring() string {
return strings.Trim(s.Documentation, "\n ")
}
// IndentedDocstring is the indented form of the doc string.
func (ref *ShapeRef) IndentedDocstring() string {
doc := ref.Docstring()
return strings.Replace(doc, "// ", "// ", -1)
}
var goCodeStringerTmpl = template.Must(template.New("goCodeStringerTmpl").Parse(`
// String returns the string representation
func (s {{ .ShapeName }}) String() string {
return awsutil.Prettify(s)
}
// GoString returns the string representation
func (s {{ .ShapeName }}) GoString() string {
return s.String()
}
`))
// GoCodeStringers renders the Stringers for API input/output shapes
func (s *Shape) GoCodeStringers() string {
w := bytes.Buffer{}
if err := goCodeStringerTmpl.Execute(&w, s); err != nil {
panic(fmt.Sprintln("Unexpected error executing GoCodeStringers template", err))
}
return w.String()
}
var enumStrip = regexp.MustCompile(`[^a-zA-Z0-9_:\./-]`)
var enumDelims = regexp.MustCompile(`[-_:\./]+`)
var enumCamelCase = regexp.MustCompile(`([a-z])([A-Z])`)
// EnumName returns the Nth enum in the shapes Enum list
func (s *Shape) EnumName(n int) string {
enum := s.Enum[n]
enum = enumStrip.ReplaceAllLiteralString(enum, "")
enum = enumCamelCase.ReplaceAllString(enum, "$1-$2")
parts := enumDelims.Split(enum, -1)
for i, v := range parts {
v = strings.ToLower(v)
parts[i] = ""
if len(v) > 0 {
parts[i] = strings.ToUpper(v[0:1])
}
if len(v) > 1 {
parts[i] += v[1:]
}
}
enum = strings.Join(parts, "")
enum = strings.ToUpper(enum[0:1]) + enum[1:]
return enum
}
// NestedShape returns the shape pointer value for the shape which is nested
// under the current shape. If the shape is not nested nil will be returned.
//
// strucutures, the current shape is returned
// map: the value shape of the map is returned
// list: the element shape of the list is returned
func (s *Shape) NestedShape() *Shape {
var nestedShape *Shape
switch s.Type {
case "structure":
nestedShape = s
case "map":
nestedShape = s.ValueRef.Shape
case "list":
nestedShape = s.MemberRef.Shape
}
return nestedShape
}
var structShapeTmpl = template.Must(template.New("StructShape").Funcs(template.FuncMap{
"GetCrosslinkURL": GetCrosslinkURL,
}).Parse(`
{{ .Docstring }}
{{ if ne $.OrigShapeName "" -}}
{{ $crosslinkURL := GetCrosslinkURL $.API.BaseCrosslinkURL $.API.APIName $.API.Metadata.UID $.OrigShapeName -}}
{{ if ne $crosslinkURL "" -}}
// Please also see {{ $crosslinkURL }}
{{ end -}}
{{ else -}}
{{ $crosslinkURL := GetCrosslinkURL $.API.BaseCrosslinkURL $.API.APIName $.API.Metadata.UID $.ShapeName -}}
{{ if ne $crosslinkURL "" -}}
// Please also see {{ $crosslinkURL }}
{{ end -}}
{{ end -}}
{{ $context := . -}}
type {{ .ShapeName }} struct {
_ struct{} {{ .GoTags true false }}
{{ range $_, $name := $context.MemberNames -}}
{{ $elem := index $context.MemberRefs $name -}}
{{ $isBlob := $context.WillRefBeBase64Encoded $name -}}
{{ $isRequired := $context.IsRequired $name -}}
{{ $doc := $elem.Docstring -}}
{{ 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 }}
{{ end }}
}
{{ if not .API.NoStringerMethods }}
{{ .GoCodeStringers }}
{{ end }}
{{ if not .API.NoValidataShapeMethods }}
{{ if .Validations -}}
{{ .Validations.GoCode . }}
{{ end }}
{{ end }}
{{ if not .API.NoGenStructFieldAccessors }}
{{ $builderShapeName := print .ShapeName -}}
{{ range $_, $name := $context.MemberNames -}}
{{ $elem := index $context.MemberRefs $name -}}
// Set{{ $name }} sets the {{ $name }} field's value.
func (s *{{ $builderShapeName }}) Set{{ $name }}(v {{ $context.GoStructValueType $name $elem }}) *{{ $builderShapeName }} {
{{ if $elem.UseIndirection -}}
s.{{ $name }} = &v
{{ else -}}
s.{{ $name }} = v
{{ end -}}
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 }}
`))
var enumShapeTmpl = template.Must(template.New("EnumShape").Parse(`
{{ .Docstring }}
const (
{{ $context := . -}}
{{ range $index, $elem := .Enum -}}
{{ $name := index $context.EnumConsts $index -}}
// {{ $name }} is a {{ $context.ShapeName }} enum value
{{ $name }} = "{{ $elem }}"
{{ end }}
)
`))
// GoCode returns the rendered Go code for the Shape.
func (s *Shape) GoCode() string {
b := &bytes.Buffer{}
switch {
case s.Type == "structure":
if err := structShapeTmpl.Execute(b, s); err != nil {
panic(fmt.Sprintf("Failed to generate struct shape %s, %v\n", s.ShapeName, err))
}
case s.IsEnum():
if err := enumShapeTmpl.Execute(b, s); err != nil {
panic(fmt.Sprintf("Failed to generate enum shape %s, %v\n", s.ShapeName, err))
}
default:
panic(fmt.Sprintln("Cannot generate toplevel shape for", s.Type))
}
return b.String()
}
// IsEnum returns whether this shape is an enum list
func (s *Shape) IsEnum() bool {
return s.Type == "string" && len(s.Enum) > 0
}
// IsRequired returns if member is a required field.
func (s *Shape) IsRequired(member string) bool {
for _, n := range s.Required {
if n == member {
return true
}
}
return false
}
// IsInternal returns whether the shape was defined in this package
func (s *Shape) IsInternal() bool {
return s.resolvePkg == ""
}
// removeRef removes a shape reference from the list of references this
// shape is used in.
func (s *Shape) removeRef(ref *ShapeRef) {
r := s.refs
for i := 0; i < len(r); i++ {
if r[i] == ref {
j := i + 1
copy(r[i:], r[j:])
for k, n := len(r)-j+i, len(r); k < n; k++ {
r[k] = nil // free up the end of the list
} // for k
s.refs = r[:len(r)-j+i]
break
}
}
}
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"
}
-155
View File
@@ -1,155 +0,0 @@
// +build codegen
package api
import (
"bytes"
"fmt"
"text/template"
)
// A ShapeValidationType is the type of validation that a shape needs
type ShapeValidationType int
const (
// ShapeValidationRequired states the shape must be set
ShapeValidationRequired = iota
// ShapeValidationMinVal states the shape must have at least a number of
// elements, or for numbers a minimum value
ShapeValidationMinVal
// ShapeValidationNested states the shape has nested values that need
// to be validated
ShapeValidationNested
)
// A ShapeValidation contains information about a shape and the type of validation
// that is needed
type ShapeValidation struct {
// Name of the shape to be validated
Name string
// Reference to the shape within the context the shape is referenced
Ref *ShapeRef
// Type of validation needed
Type ShapeValidationType
}
var validationGoCodeTmpls = template.Must(template.New("validationGoCodeTmpls").Parse(`
{{ define "requiredValue" -}}
if s.{{ .Name }} == nil {
invalidParams.Add(request.NewErrParamRequired("{{ .Name }}"))
}
{{- end }}
{{ define "minLen" -}}
if s.{{ .Name }} != nil && len(s.{{ .Name }}) < {{ .Ref.Shape.Min }} {
invalidParams.Add(request.NewErrParamMinLen("{{ .Name }}", {{ .Ref.Shape.Min }}))
}
{{- end }}
{{ define "minLenString" -}}
if s.{{ .Name }} != nil && len(*s.{{ .Name }}) < {{ .Ref.Shape.Min }} {
invalidParams.Add(request.NewErrParamMinLen("{{ .Name }}", {{ .Ref.Shape.Min }}))
}
{{- end }}
{{ define "minVal" -}}
if s.{{ .Name }} != nil && *s.{{ .Name }} < {{ .Ref.Shape.Min }} {
invalidParams.Add(request.NewErrParamMinValue("{{ .Name }}", {{ .Ref.Shape.Min }}))
}
{{- end }}
{{ define "nestedMapList" -}}
if s.{{ .Name }} != nil {
for i, v := range s.{{ .Name }} {
if v == nil { continue }
if err := v.Validate(); err != nil {
invalidParams.AddNested(fmt.Sprintf("%s[%v]", "{{ .Name }}", i), err.(request.ErrInvalidParams))
}
}
}
{{- end }}
{{ define "nestedStruct" -}}
if s.{{ .Name }} != nil {
if err := s.{{ .Name }}.Validate(); err != nil {
invalidParams.AddNested("{{ .Name }}", err.(request.ErrInvalidParams))
}
}
{{- end }}
`))
// GoCode returns the generated Go code for the Shape with its validation type.
func (sv ShapeValidation) GoCode() string {
var err error
w := &bytes.Buffer{}
switch sv.Type {
case ShapeValidationRequired:
err = validationGoCodeTmpls.ExecuteTemplate(w, "requiredValue", sv)
case ShapeValidationMinVal:
switch sv.Ref.Shape.Type {
case "list", "map", "blob":
err = validationGoCodeTmpls.ExecuteTemplate(w, "minLen", sv)
case "string":
err = validationGoCodeTmpls.ExecuteTemplate(w, "minLenString", sv)
case "integer", "long", "float", "double":
err = validationGoCodeTmpls.ExecuteTemplate(w, "minVal", sv)
default:
panic(fmt.Sprintf("ShapeValidation.GoCode, %s's type %s, no min value handling",
sv.Name, sv.Ref.Shape.Type))
}
case ShapeValidationNested:
switch sv.Ref.Shape.Type {
case "map", "list":
err = validationGoCodeTmpls.ExecuteTemplate(w, "nestedMapList", sv)
default:
err = validationGoCodeTmpls.ExecuteTemplate(w, "nestedStruct", sv)
}
default:
panic(fmt.Sprintf("ShapeValidation.GoCode, %s's type %d, unknown validation type",
sv.Name, sv.Type))
}
if err != nil {
panic(fmt.Sprintf("ShapeValidation.GoCode failed, err: %v", err))
}
return w.String()
}
// A ShapeValidations is a collection of shape validations needed nested within
// a parent shape
type ShapeValidations []ShapeValidation
var validateShapeTmpl = template.Must(template.New("ValidateShape").Parse(`
// Validate inspects the fields of the type to determine if they are valid.
func (s *{{ .Shape.ShapeName }}) Validate() error {
invalidParams := request.ErrInvalidParams{Context: "{{ .Shape.ShapeName }}"}
{{ range $_, $v := .Validations -}}
{{ $v.GoCode }}
{{ end }}
if invalidParams.Len() > 0 {
return invalidParams
}
return nil
}
`))
// GoCode generates the Go code needed to perform validations for the
// shape and its nested fields.
func (vs ShapeValidations) GoCode(shape *Shape) string {
buf := &bytes.Buffer{}
validateShapeTmpl.Execute(buf, map[string]interface{}{
"Shape": shape,
"Validations": vs,
})
return buf.String()
}
// Has returns true or false if the ShapeValidations already contains the
// the reference and validation type.
func (vs ShapeValidations) Has(ref *ShapeRef, typ ShapeValidationType) bool {
for _, v := range vs {
if v.Ref == ref && v.Type == typ {
return true
}
}
return false
}
-189
View File
@@ -1,189 +0,0 @@
// +build codegen
package api
import (
"bytes"
"encoding/json"
"fmt"
"os"
"sort"
"strings"
"text/template"
)
// WaiterAcceptor is the acceptors defined in the model the SDK will use
// to wait on resource states with.
type WaiterAcceptor struct {
State string
Matcher string
Argument string
Expected interface{}
}
// ExpectedString returns the string that was expected by the WaiterAcceptor
func (a *WaiterAcceptor) ExpectedString() string {
switch a.Expected.(type) {
case string:
return fmt.Sprintf("%q", a.Expected)
default:
return fmt.Sprintf("%v", a.Expected)
}
}
// A Waiter is an individual waiter definition.
type Waiter struct {
Name string
Delay int
MaxAttempts int
OperationName string `json:"operation"`
Operation *Operation
Acceptors []WaiterAcceptor
}
// WaitersGoCode generates and returns Go code for each of the waiters of
// this API.
func (a *API) WaitersGoCode() string {
var buf bytes.Buffer
fmt.Fprintf(&buf, "import (\n%q\n\n%q\n%q\n)",
"time",
"github.com/aws/aws-sdk-go/aws",
"github.com/aws/aws-sdk-go/aws/request",
)
for _, w := range a.Waiters {
buf.WriteString(w.GoCode())
}
return buf.String()
}
// used for unmarshaling from the waiter JSON file
type waiterDefinitions struct {
*API
Waiters map[string]Waiter
}
// AttachWaiters reads a file of waiter definitions, and adds those to the API.
// Will panic if an error occurs.
func (a *API) AttachWaiters(filename string) {
p := waiterDefinitions{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()
}
func (p *waiterDefinitions) setup() {
p.API.Waiters = []Waiter{}
i, keys := 0, make([]string, len(p.Waiters))
for k := range p.Waiters {
keys[i] = k
i++
}
sort.Strings(keys)
for _, n := range keys {
e := p.Waiters[n]
n = p.ExportableName(n)
e.Name = n
e.OperationName = p.ExportableName(e.OperationName)
e.Operation = p.API.Operations[e.OperationName]
if e.Operation == nil {
panic("unknown operation " + e.OperationName + " for waiter " + n)
}
p.API.Waiters = append(p.API.Waiters, e)
}
}
var waiterTmpls = template.Must(template.New("waiterTmpls").Funcs(
template.FuncMap{
"titleCase": func(v string) string {
return strings.Title(v)
},
},
).Parse(`
{{ 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
// be returned.
func (c *{{ .Operation.API.StructName }}) WaitUntil{{ .Name }}(input {{ .Operation.InputRef.GoType }}) error {
return c.WaitUntil{{ .Name }}WithContext(aws.BackgroundContext(), input)
}
// WaitUntil{{ .Name }}WithContext is an extended version of WaitUntil{{ .Name }}.
// With the support for passing in a context and options to configure the
// Waiter and the underlying request options.
//
// The context must be non-nil and will be used for request cancellation. If
// the context is nil a panic will occur. In the future the SDK may create
// sub-contexts for http.Requests. See https://golang.org/pkg/context/
// for more information on using Contexts.
func (c *{{ .Operation.API.StructName }}) WaitUntil{{ .Name }}WithContext(` +
`ctx aws.Context, input {{ .Operation.InputRef.GoType }}, opts ...request.WaiterOption) error {
w := request.Waiter{
Name: "WaitUntil{{ .Name }}",
MaxAttempts: {{ .MaxAttempts }},
Delay: request.ConstantWaiterDelay({{ .Delay }} * time.Second),
Acceptors: []request.WaiterAcceptor{
{{ range $_, $a := .Acceptors }}{
State: request.{{ titleCase .State }}WaiterState,
Matcher: request.{{ titleCase .Matcher }}WaiterMatch,
{{- if .Argument }}Argument: "{{ .Argument }}",{{ end }}
Expected: {{ .ExpectedString }},
},
{{ end }}
},
Logger: c.Config.Logger,
NewRequest: func(opts []request.Option) (*request.Request, error) {
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
},
}
w.ApplyOptions(opts...)
return w.WaitWithContext(ctx)
}
{{- end }}
{{ define "waiter interface" }}
WaitUntil{{ .Name }}({{ .Operation.InputRef.GoTypeWithPkgName }}) error
WaitUntil{{ .Name }}WithContext(aws.Context, {{ .Operation.InputRef.GoTypeWithPkgName }}, ...request.WaiterOption) error
{{- end }}
`))
// InterfaceSignature returns a string representing the Waiter's interface
// function signature.
func (w *Waiter) InterfaceSignature() string {
var buf bytes.Buffer
if err := waiterTmpls.ExecuteTemplate(&buf, "waiter interface", w); err != nil {
panic(err)
}
return strings.TrimSpace(buf.String())
}
// GoCode returns the generated Go code for an individual waiter.
func (w *Waiter) GoCode() string {
var buf bytes.Buffer
if err := waiterTmpls.ExecuteTemplate(&buf, "waiter", w); err != nil {
panic(err)
}
return buf.String()
}
@@ -1,29 +0,0 @@
// +build codegen
package main
import (
"fmt"
"os"
"path/filepath"
"sort"
"github.com/aws/aws-sdk-go/private/model/api"
)
func main() {
dir, _ := os.Open(filepath.Join("models", "apis"))
names, _ := dir.Readdirnames(0)
for _, name := range names {
m, _ := filepath.Glob(filepath.Join("models", "apis", name, "*", "api-2.json"))
if len(m) == 0 {
continue
}
sort.Strings(m)
f := m[len(m)-1]
a := api.API{}
a.Attach(f)
fmt.Printf("%s\t%s\n", a.Metadata.ServiceFullName, a.Metadata.APIVersion)
}
}
-303
View File
@@ -1,303 +0,0 @@
// +build codegen
// Command aws-gen-gocli parses a JSON description of an AWS API and generates a
// Go file containing a client for the API.
//
// aws-gen-gocli apis/s3/2006-03-03/api-2.json
package main
import (
"flag"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"runtime/debug"
"sort"
"strings"
"sync"
"github.com/aws/aws-sdk-go/private/model/api"
"github.com/aws/aws-sdk-go/private/util"
)
type generateInfo struct {
*api.API
PackageDir string
}
var excludeServices = map[string]struct{}{
"importexport": {},
}
// newGenerateInfo initializes the service API's folder structure for a specific service.
// If the SERVICES environment variable is set, and this service is not apart of the list
// this service will be skipped.
func newGenerateInfo(modelFile, svcPath, svcImportPath string) *generateInfo {
g := &generateInfo{API: &api.API{SvcClientImportPath: svcImportPath, BaseCrosslinkURL: "https://docs.aws.amazon.com"}}
g.API.Attach(modelFile)
if _, ok := excludeServices[g.API.PackageName()]; ok {
return nil
}
paginatorsFile := strings.Replace(modelFile, "api-2.json", "paginators-1.json", -1)
if _, err := os.Stat(paginatorsFile); err == nil {
g.API.AttachPaginators(paginatorsFile)
} else if !os.IsNotExist(err) {
fmt.Println("api-2.json error:", err)
}
docsFile := strings.Replace(modelFile, "api-2.json", "docs-2.json", -1)
if _, err := os.Stat(docsFile); err == nil {
g.API.AttachDocs(docsFile)
} else {
fmt.Println("docs-2.json error:", err)
}
waitersFile := strings.Replace(modelFile, "api-2.json", "waiters-2.json", -1)
if _, err := os.Stat(waitersFile); err == nil {
g.API.AttachWaiters(waitersFile)
} else if !os.IsNotExist(err) {
fmt.Println("waiters-2.json error:", err)
}
examplesFile := strings.Replace(modelFile, "api-2.json", "examples-1.json", -1)
if _, err := os.Stat(examplesFile); err == nil {
g.API.AttachExamples(examplesFile)
} else if !os.IsNotExist(err) {
fmt.Println("examples-1.json error:", err)
}
// pkgDocAddonsFile := strings.Replace(modelFile, "api-2.json", "go-pkg-doc.gotmpl", -1)
// if _, err := os.Stat(pkgDocAddonsFile); err == nil {
// g.API.AttachPackageDocAddons(pkgDocAddonsFile)
// } else if !os.IsNotExist(err) {
// fmt.Println("go-pkg-doc.gotmpl error:", err)
// }
g.API.Setup()
if svc := os.Getenv("SERVICES"); svc != "" {
svcs := strings.Split(svc, ",")
included := false
for _, s := range svcs {
if s == g.API.PackageName() {
included = true
break
}
}
if !included {
// skip this non-included service
return nil
}
}
// ensure the directory exists
pkgDir := filepath.Join(svcPath, g.API.PackageName())
os.MkdirAll(pkgDir, 0775)
os.MkdirAll(filepath.Join(pkgDir, g.API.InterfacePackageName()), 0775)
g.PackageDir = pkgDir
return g
}
// Generates service api, examples, and interface from api json definition files.
//
// Flags:
// -path alternative service path to write generated files to for each service.
//
// Env:
// SERVICES comma separated list of services to generate.
func main() {
var svcPath, sessionPath, svcImportPath string
flag.StringVar(&svcPath, "path", "service", "directory to generate service clients in")
flag.StringVar(&sessionPath, "sessionPath", filepath.Join("aws", "session"), "generate session service client factories")
flag.StringVar(&svcImportPath, "svc-import-path", "github.com/aws/aws-sdk-go/service", "namespace to generate service client Go code import path under")
flag.Parse()
api.Bootstrap()
files := []string{}
for i := 0; i < flag.NArg(); i++ {
file := flag.Arg(i)
if strings.Contains(file, "*") {
paths, _ := filepath.Glob(file)
files = append(files, paths...)
} else {
files = append(files, file)
}
}
for svcName := range excludeServices {
if strings.Contains(os.Getenv("SERVICES"), svcName) {
fmt.Printf("Service %s is not supported\n", svcName)
os.Exit(1)
}
}
sort.Strings(files)
// Remove old API versions from list
m := map[string]bool{}
for i := range files {
idx := len(files) - 1 - i
parts := strings.Split(files[idx], string(filepath.Separator))
svc := parts[len(parts)-3] // service name is 2nd-to-last component
if m[svc] {
files[idx] = "" // wipe this one out if we already saw the service
}
m[svc] = true
}
wg := sync.WaitGroup{}
for i := range files {
filename := files[i]
if filename == "" { // empty file
continue
}
genInfo := newGenerateInfo(filename, svcPath, svcImportPath)
if genInfo == nil {
continue
}
if _, ok := excludeServices[genInfo.API.PackageName()]; ok {
// Skip services not yet supported.
continue
}
wg.Add(1)
go func(g *generateInfo, filename string) {
defer wg.Done()
writeServiceFiles(g, filename)
}(genInfo, filename)
}
wg.Wait()
}
func writeServiceFiles(g *generateInfo, filename string) {
defer func() {
if r := recover(); r != nil {
fmt.Fprintf(os.Stderr, "Error generating %s\n%s\n%s\n",
filename, r, debug.Stack())
}
}()
fmt.Printf("Generating %s (%s)...\n",
g.API.PackageName(), g.API.Metadata.APIVersion)
// write files for service client and API
Must(writeServiceDocFile(g))
Must(writeAPIFile(g))
Must(writeServiceFile(g))
Must(writeInterfaceFile(g))
Must(writeWaitersFile(g))
Must(writeAPIErrorsFile(g))
Must(writeExamplesFile(g))
}
// Must will panic if the error passed in is not nil.
func Must(err error) {
if err != nil {
panic(err)
}
}
const codeLayout = `// Code generated by private/model/cli/gen-api/main.go. DO NOT EDIT.
%s
package %s
%s
`
func writeGoFile(file string, layout string, args ...interface{}) error {
return ioutil.WriteFile(file, []byte(util.GoFmt(fmt.Sprintf(layout, args...))), 0664)
}
// writeServiceDocFile generates the documentation for service package.
func writeServiceDocFile(g *generateInfo) error {
return writeGoFile(filepath.Join(g.PackageDir, "doc.go"),
codeLayout,
strings.TrimSpace(g.API.ServicePackageDoc()),
g.API.PackageName(),
"",
)
}
// writeExamplesFile writes out the service example file.
func writeExamplesFile(g *generateInfo) error {
code := g.API.ExamplesGoCode()
if len(code) > 0 {
return writeGoFile(filepath.Join(g.PackageDir, "examples_test.go"),
codeLayout,
"",
g.API.PackageName()+"_test",
code,
)
}
return nil
}
// writeServiceFile writes out the service initialization file.
func writeServiceFile(g *generateInfo) error {
return writeGoFile(filepath.Join(g.PackageDir, "service.go"),
codeLayout,
"",
g.API.PackageName(),
g.API.ServiceGoCode(),
)
}
// writeInterfaceFile writes out the service interface file.
func writeInterfaceFile(g *generateInfo) error {
const pkgDoc = `
// Package %s provides an interface to enable mocking the %s service client
// for testing your code.
//
// It is important to note that this interface will have breaking changes
// when the service model is updated and adds new API operations, paginators,
// and waiters.`
return writeGoFile(filepath.Join(g.PackageDir, g.API.InterfacePackageName(), "interface.go"),
codeLayout,
fmt.Sprintf(pkgDoc, g.API.InterfacePackageName(), g.API.Metadata.ServiceFullName),
g.API.InterfacePackageName(),
g.API.InterfaceGoCode(),
)
}
func writeWaitersFile(g *generateInfo) error {
if len(g.API.Waiters) == 0 {
return nil
}
return writeGoFile(filepath.Join(g.PackageDir, "waiters.go"),
codeLayout,
"",
g.API.PackageName(),
g.API.WaitersGoCode(),
)
}
// writeAPIFile writes out the service API file.
func writeAPIFile(g *generateInfo) error {
return writeGoFile(filepath.Join(g.PackageDir, "api.go"),
codeLayout,
"",
g.API.PackageName(),
g.API.APIGoCode(),
)
}
// writeAPIErrorsFile writes out the service API errors file.
func writeAPIErrorsFile(g *generateInfo) error {
return writeGoFile(filepath.Join(g.PackageDir, "errors.go"),
codeLayout,
"",
g.API.PackageName(),
g.API.APIErrorsGoCode(),
)
}
@@ -1,56 +0,0 @@
// +build codegen
// Command gen-endpoints parses a JSON description of the AWS endpoint
// discovery logic and generates a Go file which returns an endpoint.
//
// aws-gen-goendpoints apis/_endpoints.json aws/endpoints_map.go
package main
import (
"flag"
"fmt"
"os"
"github.com/aws/aws-sdk-go/aws/endpoints"
)
// Generates the endpoints from json description
//
// Args:
// -model The definition file to use
// -out The output file to generate
func main() {
var modelName, outName string
flag.StringVar(&modelName, "model", "", "Endpoints definition model")
flag.StringVar(&outName, "out", "", "File to write generated endpoints to.")
flag.Parse()
if len(modelName) == 0 || len(outName) == 0 {
exitErrorf("model and out both required.")
}
modelFile, err := os.Open(modelName)
if err != nil {
exitErrorf("failed to open model definition, %v.", err)
}
defer modelFile.Close()
outFile, err := os.Create(outName)
if err != nil {
exitErrorf("failed to open out file, %v.", err)
}
defer func() {
if err := outFile.Close(); err != nil {
exitErrorf("failed to successfully write %q file, %v", outName, err)
}
}()
if err := endpoints.CodeGenModel(modelFile, outFile); err != nil {
exitErrorf("failed to codegen model, %v", err)
}
}
func exitErrorf(msg string, args ...interface{}) {
fmt.Fprintf(os.Stderr, msg+"\n", args...)
os.Exit(1)
}
@@ -1,279 +0,0 @@
// Package jsonutil provides JSON serialization of AWS requests and responses.
package jsonutil
import (
"bytes"
"encoding/base64"
"encoding/json"
"fmt"
"math"
"reflect"
"sort"
"strconv"
"time"
"github.com/aws/aws-sdk-go/private/protocol"
)
var timeType = reflect.ValueOf(time.Time{}).Type()
var byteSliceType = reflect.ValueOf([]byte{}).Type()
// BuildJSON builds a JSON string for a given object v.
func BuildJSON(v interface{}) ([]byte, error) {
var buf bytes.Buffer
err := buildAny(reflect.ValueOf(v), &buf, "")
return buf.Bytes(), err
}
func buildAny(value reflect.Value, buf *bytes.Buffer, tag reflect.StructTag) error {
origVal := value
value = reflect.Indirect(value)
if !value.IsValid() {
return nil
}
vtype := value.Type()
t := tag.Get("type")
if t == "" {
switch vtype.Kind() {
case reflect.Struct:
// also it can't be a time object
if value.Type() != timeType {
t = "structure"
}
case reflect.Slice:
// also it can't be a byte slice
if _, ok := value.Interface().([]byte); !ok {
t = "list"
}
case reflect.Map:
t = "map"
}
}
switch t {
case "structure":
if field, ok := vtype.FieldByName("_"); ok {
tag = field.Tag
}
return buildStruct(value, buf, tag)
case "list":
return buildList(value, buf, tag)
case "map":
return buildMap(value, buf, tag)
default:
return buildScalar(origVal, buf, tag)
}
}
func buildStruct(value reflect.Value, buf *bytes.Buffer, tag reflect.StructTag) error {
if !value.IsValid() {
return nil
}
// unwrap payloads
if payload := tag.Get("payload"); payload != "" {
field, _ := value.Type().FieldByName(payload)
tag = field.Tag
value = elemOf(value.FieldByName(payload))
if !value.IsValid() {
return nil
}
}
buf.WriteByte('{')
t := value.Type()
first := true
for i := 0; i < t.NumField(); i++ {
member := value.Field(i)
// This allocates the most memory.
// Additionally, we cannot skip nil fields due to
// idempotency auto filling.
field := t.Field(i)
if field.PkgPath != "" {
continue // ignore unexported fields
}
if field.Tag.Get("json") == "-" {
continue
}
if field.Tag.Get("location") != "" {
continue // ignore non-body elements
}
if field.Tag.Get("ignore") != "" {
continue
}
if protocol.CanSetIdempotencyToken(member, field) {
token := protocol.GetIdempotencyToken()
member = reflect.ValueOf(&token)
}
if (member.Kind() == reflect.Ptr || member.Kind() == reflect.Slice || member.Kind() == reflect.Map) && member.IsNil() {
continue // ignore unset fields
}
if first {
first = false
} else {
buf.WriteByte(',')
}
// figure out what this field is called
name := field.Name
if locName := field.Tag.Get("locationName"); locName != "" {
name = locName
}
writeString(name, buf)
buf.WriteString(`:`)
err := buildAny(member, buf, field.Tag)
if err != nil {
return err
}
}
buf.WriteString("}")
return nil
}
func buildList(value reflect.Value, buf *bytes.Buffer, tag reflect.StructTag) error {
buf.WriteString("[")
for i := 0; i < value.Len(); i++ {
buildAny(value.Index(i), buf, "")
if i < value.Len()-1 {
buf.WriteString(",")
}
}
buf.WriteString("]")
return nil
}
type sortedValues []reflect.Value
func (sv sortedValues) Len() int { return len(sv) }
func (sv sortedValues) Swap(i, j int) { sv[i], sv[j] = sv[j], sv[i] }
func (sv sortedValues) Less(i, j int) bool { return sv[i].String() < sv[j].String() }
func buildMap(value reflect.Value, buf *bytes.Buffer, tag reflect.StructTag) error {
buf.WriteString("{")
sv := sortedValues(value.MapKeys())
sort.Sort(sv)
for i, k := range sv {
if i > 0 {
buf.WriteByte(',')
}
writeString(k.String(), buf)
buf.WriteString(`:`)
buildAny(value.MapIndex(k), buf, "")
}
buf.WriteString("}")
return nil
}
func buildScalar(v reflect.Value, buf *bytes.Buffer, tag reflect.StructTag) error {
// prevents allocation on the heap.
scratch := [64]byte{}
switch value := reflect.Indirect(v); value.Kind() {
case reflect.String:
writeString(value.String(), buf)
case reflect.Bool:
if value.Bool() {
buf.WriteString("true")
} else {
buf.WriteString("false")
}
case reflect.Int64:
buf.Write(strconv.AppendInt(scratch[:0], value.Int(), 10))
case reflect.Float64:
f := value.Float()
if math.IsInf(f, 0) || math.IsNaN(f) {
return &json.UnsupportedValueError{Value: v, Str: strconv.FormatFloat(f, 'f', -1, 64)}
}
buf.Write(strconv.AppendFloat(scratch[:0], f, 'f', -1, 64))
default:
switch value.Type() {
case timeType:
converted := v.Interface().(*time.Time)
buf.Write(strconv.AppendInt(scratch[:0], converted.UTC().Unix(), 10))
case byteSliceType:
if !value.IsNil() {
converted := value.Interface().([]byte)
buf.WriteByte('"')
if len(converted) < 1024 {
// for small buffers, using Encode directly is much faster.
dst := make([]byte, base64.StdEncoding.EncodedLen(len(converted)))
base64.StdEncoding.Encode(dst, converted)
buf.Write(dst)
} else {
// for large buffers, avoid unnecessary extra temporary
// buffer space.
enc := base64.NewEncoder(base64.StdEncoding, buf)
enc.Write(converted)
enc.Close()
}
buf.WriteByte('"')
}
default:
return fmt.Errorf("unsupported JSON value %v (%s)", value.Interface(), value.Type())
}
}
return nil
}
var hex = "0123456789abcdef"
func writeString(s string, buf *bytes.Buffer) {
buf.WriteByte('"')
for i := 0; i < len(s); i++ {
if s[i] == '"' {
buf.WriteString(`\"`)
} else if s[i] == '\\' {
buf.WriteString(`\\`)
} else if s[i] == '\b' {
buf.WriteString(`\b`)
} else if s[i] == '\f' {
buf.WriteString(`\f`)
} else if s[i] == '\r' {
buf.WriteString(`\r`)
} else if s[i] == '\t' {
buf.WriteString(`\t`)
} else if s[i] == '\n' {
buf.WriteString(`\n`)
} else if s[i] < 32 {
buf.WriteString("\\u00")
buf.WriteByte(hex[s[i]>>4])
buf.WriteByte(hex[s[i]&0xF])
} else {
buf.WriteByte(s[i])
}
}
buf.WriteByte('"')
}
// Returns the reflection element of a value, if it is a pointer.
func elemOf(value reflect.Value) reflect.Value {
for value.Kind() == reflect.Ptr {
value = value.Elem()
}
return value
}
@@ -1,213 +0,0 @@
package jsonutil
import (
"encoding/base64"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"reflect"
"time"
)
// UnmarshalJSON reads a stream and unmarshals the results in object v.
func UnmarshalJSON(v interface{}, stream io.Reader) error {
var out interface{}
b, err := ioutil.ReadAll(stream)
if err != nil {
return err
}
if len(b) == 0 {
return nil
}
if err := json.Unmarshal(b, &out); err != nil {
return err
}
return unmarshalAny(reflect.ValueOf(v), out, "")
}
func unmarshalAny(value reflect.Value, data interface{}, tag reflect.StructTag) error {
vtype := value.Type()
if vtype.Kind() == reflect.Ptr {
vtype = vtype.Elem() // check kind of actual element type
}
t := tag.Get("type")
if t == "" {
switch vtype.Kind() {
case reflect.Struct:
// also it can't be a time object
if _, ok := value.Interface().(*time.Time); !ok {
t = "structure"
}
case reflect.Slice:
// also it can't be a byte slice
if _, ok := value.Interface().([]byte); !ok {
t = "list"
}
case reflect.Map:
t = "map"
}
}
switch t {
case "structure":
if field, ok := vtype.FieldByName("_"); ok {
tag = field.Tag
}
return unmarshalStruct(value, data, tag)
case "list":
return unmarshalList(value, data, tag)
case "map":
return unmarshalMap(value, data, tag)
default:
return unmarshalScalar(value, data, tag)
}
}
func unmarshalStruct(value reflect.Value, data interface{}, tag reflect.StructTag) error {
if data == nil {
return nil
}
mapData, ok := data.(map[string]interface{})
if !ok {
return fmt.Errorf("JSON value is not a structure (%#v)", data)
}
t := value.Type()
if value.Kind() == reflect.Ptr {
if value.IsNil() { // create the structure if it's nil
s := reflect.New(value.Type().Elem())
value.Set(s)
value = s
}
value = value.Elem()
t = t.Elem()
}
// unwrap any payloads
if payload := tag.Get("payload"); payload != "" {
field, _ := t.FieldByName(payload)
return unmarshalAny(value.FieldByName(payload), data, field.Tag)
}
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
if field.PkgPath != "" {
continue // ignore unexported fields
}
// figure out what this field is called
name := field.Name
if locName := field.Tag.Get("locationName"); locName != "" {
name = locName
}
member := value.FieldByIndex(field.Index)
err := unmarshalAny(member, mapData[name], field.Tag)
if err != nil {
return err
}
}
return nil
}
func unmarshalList(value reflect.Value, data interface{}, tag reflect.StructTag) error {
if data == nil {
return nil
}
listData, ok := data.([]interface{})
if !ok {
return fmt.Errorf("JSON value is not a list (%#v)", data)
}
if value.IsNil() {
l := len(listData)
value.Set(reflect.MakeSlice(value.Type(), l, l))
}
for i, c := range listData {
err := unmarshalAny(value.Index(i), c, "")
if err != nil {
return err
}
}
return nil
}
func unmarshalMap(value reflect.Value, data interface{}, tag reflect.StructTag) error {
if data == nil {
return nil
}
mapData, ok := data.(map[string]interface{})
if !ok {
return fmt.Errorf("JSON value is not a map (%#v)", data)
}
if value.IsNil() {
value.Set(reflect.MakeMap(value.Type()))
}
for k, v := range mapData {
kvalue := reflect.ValueOf(k)
vvalue := reflect.New(value.Type().Elem()).Elem()
unmarshalAny(vvalue, v, "")
value.SetMapIndex(kvalue, vvalue)
}
return nil
}
func unmarshalScalar(value reflect.Value, data interface{}, tag reflect.StructTag) error {
errf := func() error {
return fmt.Errorf("unsupported value: %v (%s)", value.Interface(), value.Type())
}
switch d := data.(type) {
case nil:
return nil // nothing to do here
case string:
switch value.Interface().(type) {
case *string:
value.Set(reflect.ValueOf(&d))
case []byte:
b, err := base64.StdEncoding.DecodeString(d)
if err != nil {
return err
}
value.Set(reflect.ValueOf(b))
default:
return errf()
}
case float64:
switch value.Interface().(type) {
case *int64:
di := int64(d)
value.Set(reflect.ValueOf(&di))
case *float64:
value.Set(reflect.ValueOf(&d))
case *time.Time:
t := time.Unix(int64(d), 0).UTC()
value.Set(reflect.ValueOf(&t))
default:
return errf()
}
case bool:
switch value.Interface().(type) {
case *bool:
value.Set(reflect.ValueOf(&d))
default:
return errf()
}
default:
return fmt.Errorf("unsupported JSON value (%v)", data)
}
return nil
}
-111
View File
@@ -1,111 +0,0 @@
// Package jsonrpc provides JSON RPC utilities for serialization of AWS
// requests and responses.
package jsonrpc
//go:generate go run -tags codegen ../../../models/protocol_tests/generate.go ../../../models/protocol_tests/input/json.json build_test.go
//go:generate go run -tags codegen ../../../models/protocol_tests/generate.go ../../../models/protocol_tests/output/json.json unmarshal_test.go
import (
"encoding/json"
"io/ioutil"
"strings"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/request"
"github.com/aws/aws-sdk-go/private/protocol/json/jsonutil"
"github.com/aws/aws-sdk-go/private/protocol/rest"
)
var emptyJSON = []byte("{}")
// BuildHandler is a named request handler for building jsonrpc protocol requests
var BuildHandler = request.NamedHandler{Name: "awssdk.jsonrpc.Build", Fn: Build}
// UnmarshalHandler is a named request handler for unmarshaling jsonrpc protocol requests
var UnmarshalHandler = request.NamedHandler{Name: "awssdk.jsonrpc.Unmarshal", Fn: Unmarshal}
// UnmarshalMetaHandler is a named request handler for unmarshaling jsonrpc protocol request metadata
var UnmarshalMetaHandler = request.NamedHandler{Name: "awssdk.jsonrpc.UnmarshalMeta", Fn: UnmarshalMeta}
// UnmarshalErrorHandler is a named request handler for unmarshaling jsonrpc protocol request errors
var UnmarshalErrorHandler = request.NamedHandler{Name: "awssdk.jsonrpc.UnmarshalError", Fn: UnmarshalError}
// Build builds a JSON payload for a JSON RPC request.
func Build(req *request.Request) {
var buf []byte
var err error
if req.ParamsFilled() {
buf, err = jsonutil.BuildJSON(req.Params)
if err != nil {
req.Error = awserr.New("SerializationError", "failed encoding JSON RPC request", err)
return
}
} else {
buf = emptyJSON
}
if req.ClientInfo.TargetPrefix != "" || string(buf) != "{}" {
req.SetBufferBody(buf)
}
if req.ClientInfo.TargetPrefix != "" {
target := req.ClientInfo.TargetPrefix + "." + req.Operation.Name
req.HTTPRequest.Header.Add("X-Amz-Target", target)
}
if req.ClientInfo.JSONVersion != "" {
jsonVersion := req.ClientInfo.JSONVersion
req.HTTPRequest.Header.Add("Content-Type", "application/x-amz-json-"+jsonVersion)
}
}
// Unmarshal unmarshals a response for a JSON RPC service.
func Unmarshal(req *request.Request) {
defer req.HTTPResponse.Body.Close()
if req.DataFilled() {
err := jsonutil.UnmarshalJSON(req.Data, req.HTTPResponse.Body)
if err != nil {
req.Error = awserr.New("SerializationError", "failed decoding JSON RPC response", err)
}
}
return
}
// UnmarshalMeta unmarshals headers from a response for a JSON RPC service.
func UnmarshalMeta(req *request.Request) {
rest.UnmarshalMeta(req)
}
// UnmarshalError unmarshals an error response for a JSON RPC service.
func UnmarshalError(req *request.Request) {
defer req.HTTPResponse.Body.Close()
bodyBytes, err := ioutil.ReadAll(req.HTTPResponse.Body)
if err != nil {
req.Error = awserr.New("SerializationError", "failed reading JSON RPC error response", err)
return
}
if len(bodyBytes) == 0 {
req.Error = awserr.NewRequestFailure(
awserr.New("SerializationError", req.HTTPResponse.Status, nil),
req.HTTPResponse.StatusCode,
"",
)
return
}
var jsonErr jsonErrorResponse
if err := json.Unmarshal(bodyBytes, &jsonErr); err != nil {
req.Error = awserr.New("SerializationError", "failed decoding JSON RPC error response", err)
return
}
codes := strings.SplitN(jsonErr.Code, "#", 2)
req.Error = awserr.NewRequestFailure(
awserr.New(codes[len(codes)-1], jsonErr.Message, nil),
req.HTTPResponse.StatusCode,
req.RequestID,
)
}
type jsonErrorResponse struct {
Code string `json:"__type"`
Message string `json:"message"`
}
+76
View File
@@ -0,0 +1,76 @@
package protocol
import (
"encoding/base64"
"encoding/json"
"fmt"
"strconv"
"github.com/aws/aws-sdk-go/aws"
)
// EscapeMode is the mode that should be use for escaping a value
type EscapeMode uint
// The modes for escaping a value before it is marshaled, and unmarshaled.
const (
NoEscape EscapeMode = iota
Base64Escape
QuotedEscape
)
// EncodeJSONValue marshals the value into a JSON string, and optionally base64
// encodes the string before returning it.
//
// Will panic if the escape mode is unknown.
func EncodeJSONValue(v aws.JSONValue, escape EscapeMode) (string, error) {
b, err := json.Marshal(v)
if err != nil {
return "", err
}
switch escape {
case NoEscape:
return string(b), nil
case Base64Escape:
return base64.StdEncoding.EncodeToString(b), nil
case QuotedEscape:
return strconv.Quote(string(b)), nil
}
panic(fmt.Sprintf("EncodeJSONValue called with unknown EscapeMode, %v", escape))
}
// DecodeJSONValue will attempt to decode the string input as a JSONValue.
// Optionally decoding base64 the value first before JSON unmarshaling.
//
// Will panic if the escape mode is unknown.
func DecodeJSONValue(v string, escape EscapeMode) (aws.JSONValue, error) {
var b []byte
var err error
switch escape {
case NoEscape:
b = []byte(v)
case Base64Escape:
b, err = base64.StdEncoding.DecodeString(v)
case QuotedEscape:
var u string
u, err = strconv.Unquote(v)
b = []byte(u)
default:
panic(fmt.Sprintf("DecodeJSONValue called with unknown EscapeMode, %v", escape))
}
if err != nil {
return nil, err
}
m := aws.JSONValue{}
err = json.Unmarshal(b, &m)
if err != nil {
return nil, err
}
return m, nil
}
@@ -121,6 +121,10 @@ func (q *queryParser) parseList(v url.Values, value reflect.Value, prefix string
return nil
}
if _, ok := value.Interface().([]byte); ok {
return q.parseScalar(v, value, prefix, tag)
}
// check for unflattened list member
if !q.isEC2 && tag.Get("flattened") == "" {
if listName := tag.Get("locationNameList"); listName == "" {
+11 -10
View File
@@ -4,7 +4,6 @@ package rest
import (
"bytes"
"encoding/base64"
"encoding/json"
"fmt"
"io"
"net/http"
@@ -18,6 +17,7 @@ import (
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/request"
"github.com/aws/aws-sdk-go/private/protocol"
)
// RFC822 returns an RFC822 formatted timestamp for AWS protocols
@@ -252,13 +252,12 @@ func EscapePath(path string, encodeSep bool) string {
return buf.String()
}
func convertType(v reflect.Value, tag reflect.StructTag) (string, error) {
func convertType(v reflect.Value, tag reflect.StructTag) (str string, err error) {
v = reflect.Indirect(v)
if !v.IsValid() {
return "", errValueNotSet
}
var str string
switch value := v.Interface().(type) {
case string:
str = value
@@ -273,17 +272,19 @@ func convertType(v reflect.Value, tag reflect.StructTag) (string, error) {
case time.Time:
str = value.UTC().Format(RFC822)
case aws.JSONValue:
b, err := json.Marshal(value)
if err != nil {
return "", err
if len(value) == 0 {
return "", errValueNotSet
}
escaping := protocol.NoEscape
if tag.Get("location") == "header" {
str = base64.StdEncoding.EncodeToString(b)
} else {
str = string(b)
escaping = protocol.Base64Escape
}
str, err = protocol.EncodeJSONValue(value, escaping)
if err != nil {
return "", fmt.Errorf("unable to encode JSONValue, %v", err)
}
default:
err := fmt.Errorf("Unsupported value for param %v (%s)", v.Interface(), v.Type())
err := fmt.Errorf("unsupported value for param %v (%s)", v.Interface(), v.Type())
return "", err
}
return str, nil
+4 -10
View File
@@ -3,7 +3,6 @@ package rest
import (
"bytes"
"encoding/base64"
"encoding/json"
"fmt"
"io"
"io/ioutil"
@@ -16,6 +15,7 @@ import (
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/request"
"github.com/aws/aws-sdk-go/private/protocol"
)
// UnmarshalHandler is a named request handler for unmarshaling rest protocol requests
@@ -204,17 +204,11 @@ func unmarshalHeader(v reflect.Value, header string, tag reflect.StructTag) erro
}
v.Set(reflect.ValueOf(&t))
case aws.JSONValue:
b := []byte(header)
var err error
escaping := protocol.NoEscape
if tag.Get("location") == "header" {
b, err = base64.StdEncoding.DecodeString(header)
if err != nil {
return err
}
escaping = protocol.Base64Escape
}
m := aws.JSONValue{}
err = json.Unmarshal(b, &m)
m, err := protocol.DecodeJSONValue(header, escaping)
if err != nil {
return err
}
-92
View File
@@ -1,92 +0,0 @@
// Package restjson provides RESTful JSON serialization of AWS
// requests and responses.
package restjson
//go:generate go run -tags codegen ../../../models/protocol_tests/generate.go ../../../models/protocol_tests/input/rest-json.json build_test.go
//go:generate go run -tags codegen ../../../models/protocol_tests/generate.go ../../../models/protocol_tests/output/rest-json.json unmarshal_test.go
import (
"encoding/json"
"io/ioutil"
"strings"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/request"
"github.com/aws/aws-sdk-go/private/protocol/jsonrpc"
"github.com/aws/aws-sdk-go/private/protocol/rest"
)
// BuildHandler is a named request handler for building restjson protocol requests
var BuildHandler = request.NamedHandler{Name: "awssdk.restjson.Build", Fn: Build}
// UnmarshalHandler is a named request handler for unmarshaling restjson protocol requests
var UnmarshalHandler = request.NamedHandler{Name: "awssdk.restjson.Unmarshal", Fn: Unmarshal}
// UnmarshalMetaHandler is a named request handler for unmarshaling restjson protocol request metadata
var UnmarshalMetaHandler = request.NamedHandler{Name: "awssdk.restjson.UnmarshalMeta", Fn: UnmarshalMeta}
// UnmarshalErrorHandler is a named request handler for unmarshaling restjson protocol request errors
var UnmarshalErrorHandler = request.NamedHandler{Name: "awssdk.restjson.UnmarshalError", Fn: UnmarshalError}
// Build builds a request for the REST JSON protocol.
func Build(r *request.Request) {
rest.Build(r)
if t := rest.PayloadType(r.Params); t == "structure" || t == "" {
jsonrpc.Build(r)
}
}
// Unmarshal unmarshals a response body for the REST JSON protocol.
func Unmarshal(r *request.Request) {
if t := rest.PayloadType(r.Data); t == "structure" || t == "" {
jsonrpc.Unmarshal(r)
} else {
rest.Unmarshal(r)
}
}
// UnmarshalMeta unmarshals response headers for the REST JSON protocol.
func UnmarshalMeta(r *request.Request) {
rest.UnmarshalMeta(r)
}
// UnmarshalError unmarshals a response error for the REST JSON protocol.
func UnmarshalError(r *request.Request) {
defer r.HTTPResponse.Body.Close()
code := r.HTTPResponse.Header.Get("X-Amzn-Errortype")
bodyBytes, err := ioutil.ReadAll(r.HTTPResponse.Body)
if err != nil {
r.Error = awserr.New("SerializationError", "failed reading REST JSON error response", err)
return
}
if len(bodyBytes) == 0 {
r.Error = awserr.NewRequestFailure(
awserr.New("SerializationError", r.HTTPResponse.Status, nil),
r.HTTPResponse.StatusCode,
"",
)
return
}
var jsonErr jsonErrorResponse
if err := json.Unmarshal(bodyBytes, &jsonErr); err != nil {
r.Error = awserr.New("SerializationError", "failed decoding REST JSON error response", err)
return
}
if code == "" {
code = jsonErr.Code
}
code = strings.SplitN(code, ":", 2)[0]
r.Error = awserr.NewRequestFailure(
awserr.New(code, jsonErr.Message, nil),
r.HTTPResponse.StatusCode,
r.RequestID,
)
}
type jsonErrorResponse struct {
Code string `json:"code"`
Message string `json:"message"`
}
-180
View File
@@ -1,180 +0,0 @@
package v2
import (
"crypto/hmac"
"crypto/sha256"
"encoding/base64"
"errors"
"fmt"
"net/http"
"net/url"
"sort"
"strings"
"time"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/request"
)
var (
errInvalidMethod = errors.New("v2 signer only handles HTTP POST")
)
const (
signatureVersion = "2"
signatureMethod = "HmacSHA256"
timeFormat = "2006-01-02T15:04:05Z"
)
type signer struct {
// Values that must be populated from the request
Request *http.Request
Time time.Time
Credentials *credentials.Credentials
Debug aws.LogLevelType
Logger aws.Logger
Query url.Values
stringToSign string
signature string
}
// SignRequestHandler is a named request handler the SDK will use to sign
// service client request with using the V4 signature.
var SignRequestHandler = request.NamedHandler{
Name: "v2.SignRequestHandler", Fn: SignSDKRequest,
}
// SignSDKRequest requests with signature version 2.
//
// Will sign the requests with the service config's Credentials object
// Signing is skipped if the credentials is the credentials.AnonymousCredentials
// object.
func SignSDKRequest(req *request.Request) {
// If the request does not need to be signed ignore the signing of the
// request if the AnonymousCredentials object is used.
if req.Config.Credentials == credentials.AnonymousCredentials {
return
}
if req.HTTPRequest.Method != "POST" && req.HTTPRequest.Method != "GET" {
// The V2 signer only supports GET and POST
req.Error = errInvalidMethod
return
}
v2 := signer{
Request: req.HTTPRequest,
Time: req.Time,
Credentials: req.Config.Credentials,
Debug: req.Config.LogLevel.Value(),
Logger: req.Config.Logger,
}
req.Error = v2.Sign()
if req.Error != nil {
return
}
if req.HTTPRequest.Method == "POST" {
// Set the body of the request based on the modified query parameters
req.SetStringBody(v2.Query.Encode())
// Now that the body has changed, remove any Content-Length header,
// because it will be incorrect
req.HTTPRequest.ContentLength = 0
req.HTTPRequest.Header.Del("Content-Length")
} else {
req.HTTPRequest.URL.RawQuery = v2.Query.Encode()
}
}
func (v2 *signer) Sign() error {
credValue, err := v2.Credentials.Get()
if err != nil {
return err
}
if v2.Request.Method == "POST" {
// Parse the HTTP request to obtain the query parameters that will
// be used to build the string to sign. Note that because the HTTP
// request will need to be modified, the PostForm and Form properties
// are reset to nil after parsing.
v2.Request.ParseForm()
v2.Query = v2.Request.PostForm
v2.Request.PostForm = nil
v2.Request.Form = nil
} else {
v2.Query = v2.Request.URL.Query()
}
// Set new query parameters
v2.Query.Set("AWSAccessKeyId", credValue.AccessKeyID)
v2.Query.Set("SignatureVersion", signatureVersion)
v2.Query.Set("SignatureMethod", signatureMethod)
v2.Query.Set("Timestamp", v2.Time.UTC().Format(timeFormat))
if credValue.SessionToken != "" {
v2.Query.Set("SecurityToken", credValue.SessionToken)
}
// in case this is a retry, ensure no signature present
v2.Query.Del("Signature")
method := v2.Request.Method
host := v2.Request.URL.Host
path := v2.Request.URL.Path
if path == "" {
path = "/"
}
// obtain all of the query keys and sort them
queryKeys := make([]string, 0, len(v2.Query))
for key := range v2.Query {
queryKeys = append(queryKeys, key)
}
sort.Strings(queryKeys)
// build URL-encoded query keys and values
queryKeysAndValues := make([]string, len(queryKeys))
for i, key := range queryKeys {
k := strings.Replace(url.QueryEscape(key), "+", "%20", -1)
v := strings.Replace(url.QueryEscape(v2.Query.Get(key)), "+", "%20", -1)
queryKeysAndValues[i] = k + "=" + v
}
// join into one query string
query := strings.Join(queryKeysAndValues, "&")
// build the canonical string for the V2 signature
v2.stringToSign = strings.Join([]string{
method,
host,
path,
query,
}, "\n")
hash := hmac.New(sha256.New, []byte(credValue.SecretAccessKey))
hash.Write([]byte(v2.stringToSign))
v2.signature = base64.StdEncoding.EncodeToString(hash.Sum(nil))
v2.Query.Set("Signature", v2.signature)
if v2.Debug.Matches(aws.LogDebugWithSigning) {
v2.logSigningInfo()
}
return nil
}
const logSignInfoMsg = `DEBUG: Request Signature:
---[ STRING TO SIGN ]--------------------------------
%s
---[ SIGNATURE ]-------------------------------------
%s
-----------------------------------------------------`
func (v2 *signer) logSigningInfo() {
msg := fmt.Sprintf(logSignInfoMsg, v2.stringToSign, v2.Query.Get("Signature"))
v2.Logger.Log(msg)
}
-14
View File
@@ -1,14 +0,0 @@
package util
import "sort"
// SortedKeys returns a sorted slice of keys of a map.
func SortedKeys(m map[string]interface{}) []string {
i, sorted := 0, make([]string, len(m))
for k := range m {
sorted[i] = k
i++
}
sort.Strings(sorted)
return sorted
}
-109
View File
@@ -1,109 +0,0 @@
package util
import (
"bytes"
"encoding/xml"
"fmt"
"go/format"
"io"
"reflect"
"regexp"
"strings"
"github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil"
)
// GoFmt returns the Go formated string of the input.
//
// Panics if the format fails.
func GoFmt(buf string) string {
formatted, err := format.Source([]byte(buf))
if err != nil {
panic(fmt.Errorf("%s\nOriginal code:\n%s", err.Error(), buf))
}
return string(formatted)
}
var reTrim = regexp.MustCompile(`\s{2,}`)
// Trim removes all leading and trailing white space.
//
// All consecutive spaces will be reduced to a single space.
func Trim(s string) string {
return strings.TrimSpace(reTrim.ReplaceAllString(s, " "))
}
// Capitalize capitalizes the first character of the string.
func Capitalize(s string) string {
if len(s) == 1 {
return strings.ToUpper(s)
}
return strings.ToUpper(s[0:1]) + s[1:]
}
// SortXML sorts the reader's XML elements
func SortXML(r io.Reader) string {
var buf bytes.Buffer
d := xml.NewDecoder(r)
root, _ := xmlutil.XMLToStruct(d, nil)
e := xml.NewEncoder(&buf)
xmlutil.StructToXML(e, root, true)
return buf.String()
}
// PrettyPrint generates a human readable representation of the value v.
// All values of v are recursively found and pretty printed also.
func PrettyPrint(v interface{}) string {
value := reflect.ValueOf(v)
switch value.Kind() {
case reflect.Struct:
str := fullName(value.Type()) + "{\n"
for i := 0; i < value.NumField(); i++ {
l := string(value.Type().Field(i).Name[0])
if strings.ToUpper(l) == l {
str += value.Type().Field(i).Name + ": "
str += PrettyPrint(value.Field(i).Interface())
str += ",\n"
}
}
str += "}"
return str
case reflect.Map:
str := "map[" + fullName(value.Type().Key()) + "]" + fullName(value.Type().Elem()) + "{\n"
for _, k := range value.MapKeys() {
str += "\"" + k.String() + "\": "
str += PrettyPrint(value.MapIndex(k).Interface())
str += ",\n"
}
str += "}"
return str
case reflect.Ptr:
if e := value.Elem(); e.IsValid() {
return "&" + PrettyPrint(e.Interface())
}
return "nil"
case reflect.Slice:
str := "[]" + fullName(value.Type().Elem()) + "{\n"
for i := 0; i < value.Len(); i++ {
str += PrettyPrint(value.Index(i).Interface())
str += ",\n"
}
str += "}"
return str
default:
return fmt.Sprintf("%#v", v)
}
}
func pkgName(t reflect.Type) string {
pkg := t.PkgPath()
c := strings.Split(pkg, "/")
return c[len(c)-1]
}
func fullName(t reflect.Type) string {
if pkg := pkgName(t); pkg != "" {
return pkg + "." + t.Name()
}
return t.Name()
}
File diff suppressed because it is too large Load Diff
@@ -1,136 +0,0 @@
// Code generated by private/model/cli/gen-api/main.go. DO NOT EDIT.
// Package cloudwatchiface provides an interface to enable mocking the Amazon CloudWatch service client
// for testing your code.
//
// It is important to note that this interface will have breaking changes
// when the service model is updated and adds new API operations, paginators,
// and waiters.
package cloudwatchiface
import (
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/request"
"github.com/aws/aws-sdk-go/service/cloudwatch"
)
// CloudWatchAPI provides an interface to enable mocking the
// cloudwatch.CloudWatch service client's API operation,
// paginators, and waiters. This make unit testing your code that calls out
// to the SDK's service client's calls easier.
//
// 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.
//
// // myFunc uses an SDK service client to make a request to
// // Amazon CloudWatch.
// func myFunc(svc cloudwatchiface.CloudWatchAPI) bool {
// // Make svc.DeleteAlarms request
// }
//
// func main() {
// sess := session.New()
// svc := cloudwatch.New(sess)
//
// myFunc(svc)
// }
//
// In your _test.go file:
//
// // Define a mock struct to be used in your unit tests of myFunc.
// type mockCloudWatchClient struct {
// cloudwatchiface.CloudWatchAPI
// }
// func (m *mockCloudWatchClient) DeleteAlarms(input *cloudwatch.DeleteAlarmsInput) (*cloudwatch.DeleteAlarmsOutput, error) {
// // mock response/functionality
// }
//
// func TestMyFunc(t *testing.T) {
// // Setup Test
// mockSvc := &mockCloudWatchClient{}
//
// myfunc(mockSvc)
//
// // Verify myFunc's functionality
// }
//
// It is important to note that this interface will have breaking changes
// when the service model is updated and adds new API operations, paginators,
// and waiters. Its suggested to use the pattern above for testing, or using
// tooling to generate mocks to satisfy the interfaces.
type CloudWatchAPI interface {
DeleteAlarms(*cloudwatch.DeleteAlarmsInput) (*cloudwatch.DeleteAlarmsOutput, error)
DeleteAlarmsWithContext(aws.Context, *cloudwatch.DeleteAlarmsInput, ...request.Option) (*cloudwatch.DeleteAlarmsOutput, error)
DeleteAlarmsRequest(*cloudwatch.DeleteAlarmsInput) (*request.Request, *cloudwatch.DeleteAlarmsOutput)
DeleteDashboards(*cloudwatch.DeleteDashboardsInput) (*cloudwatch.DeleteDashboardsOutput, error)
DeleteDashboardsWithContext(aws.Context, *cloudwatch.DeleteDashboardsInput, ...request.Option) (*cloudwatch.DeleteDashboardsOutput, error)
DeleteDashboardsRequest(*cloudwatch.DeleteDashboardsInput) (*request.Request, *cloudwatch.DeleteDashboardsOutput)
DescribeAlarmHistory(*cloudwatch.DescribeAlarmHistoryInput) (*cloudwatch.DescribeAlarmHistoryOutput, error)
DescribeAlarmHistoryWithContext(aws.Context, *cloudwatch.DescribeAlarmHistoryInput, ...request.Option) (*cloudwatch.DescribeAlarmHistoryOutput, error)
DescribeAlarmHistoryRequest(*cloudwatch.DescribeAlarmHistoryInput) (*request.Request, *cloudwatch.DescribeAlarmHistoryOutput)
DescribeAlarmHistoryPages(*cloudwatch.DescribeAlarmHistoryInput, func(*cloudwatch.DescribeAlarmHistoryOutput, bool) bool) error
DescribeAlarmHistoryPagesWithContext(aws.Context, *cloudwatch.DescribeAlarmHistoryInput, func(*cloudwatch.DescribeAlarmHistoryOutput, bool) bool, ...request.Option) error
DescribeAlarms(*cloudwatch.DescribeAlarmsInput) (*cloudwatch.DescribeAlarmsOutput, error)
DescribeAlarmsWithContext(aws.Context, *cloudwatch.DescribeAlarmsInput, ...request.Option) (*cloudwatch.DescribeAlarmsOutput, error)
DescribeAlarmsRequest(*cloudwatch.DescribeAlarmsInput) (*request.Request, *cloudwatch.DescribeAlarmsOutput)
DescribeAlarmsPages(*cloudwatch.DescribeAlarmsInput, func(*cloudwatch.DescribeAlarmsOutput, bool) bool) error
DescribeAlarmsPagesWithContext(aws.Context, *cloudwatch.DescribeAlarmsInput, func(*cloudwatch.DescribeAlarmsOutput, bool) bool, ...request.Option) error
DescribeAlarmsForMetric(*cloudwatch.DescribeAlarmsForMetricInput) (*cloudwatch.DescribeAlarmsForMetricOutput, error)
DescribeAlarmsForMetricWithContext(aws.Context, *cloudwatch.DescribeAlarmsForMetricInput, ...request.Option) (*cloudwatch.DescribeAlarmsForMetricOutput, error)
DescribeAlarmsForMetricRequest(*cloudwatch.DescribeAlarmsForMetricInput) (*request.Request, *cloudwatch.DescribeAlarmsForMetricOutput)
DisableAlarmActions(*cloudwatch.DisableAlarmActionsInput) (*cloudwatch.DisableAlarmActionsOutput, error)
DisableAlarmActionsWithContext(aws.Context, *cloudwatch.DisableAlarmActionsInput, ...request.Option) (*cloudwatch.DisableAlarmActionsOutput, error)
DisableAlarmActionsRequest(*cloudwatch.DisableAlarmActionsInput) (*request.Request, *cloudwatch.DisableAlarmActionsOutput)
EnableAlarmActions(*cloudwatch.EnableAlarmActionsInput) (*cloudwatch.EnableAlarmActionsOutput, error)
EnableAlarmActionsWithContext(aws.Context, *cloudwatch.EnableAlarmActionsInput, ...request.Option) (*cloudwatch.EnableAlarmActionsOutput, error)
EnableAlarmActionsRequest(*cloudwatch.EnableAlarmActionsInput) (*request.Request, *cloudwatch.EnableAlarmActionsOutput)
GetDashboard(*cloudwatch.GetDashboardInput) (*cloudwatch.GetDashboardOutput, error)
GetDashboardWithContext(aws.Context, *cloudwatch.GetDashboardInput, ...request.Option) (*cloudwatch.GetDashboardOutput, error)
GetDashboardRequest(*cloudwatch.GetDashboardInput) (*request.Request, *cloudwatch.GetDashboardOutput)
GetMetricStatistics(*cloudwatch.GetMetricStatisticsInput) (*cloudwatch.GetMetricStatisticsOutput, error)
GetMetricStatisticsWithContext(aws.Context, *cloudwatch.GetMetricStatisticsInput, ...request.Option) (*cloudwatch.GetMetricStatisticsOutput, error)
GetMetricStatisticsRequest(*cloudwatch.GetMetricStatisticsInput) (*request.Request, *cloudwatch.GetMetricStatisticsOutput)
ListDashboards(*cloudwatch.ListDashboardsInput) (*cloudwatch.ListDashboardsOutput, error)
ListDashboardsWithContext(aws.Context, *cloudwatch.ListDashboardsInput, ...request.Option) (*cloudwatch.ListDashboardsOutput, error)
ListDashboardsRequest(*cloudwatch.ListDashboardsInput) (*request.Request, *cloudwatch.ListDashboardsOutput)
ListMetrics(*cloudwatch.ListMetricsInput) (*cloudwatch.ListMetricsOutput, error)
ListMetricsWithContext(aws.Context, *cloudwatch.ListMetricsInput, ...request.Option) (*cloudwatch.ListMetricsOutput, error)
ListMetricsRequest(*cloudwatch.ListMetricsInput) (*request.Request, *cloudwatch.ListMetricsOutput)
ListMetricsPages(*cloudwatch.ListMetricsInput, func(*cloudwatch.ListMetricsOutput, bool) bool) error
ListMetricsPagesWithContext(aws.Context, *cloudwatch.ListMetricsInput, func(*cloudwatch.ListMetricsOutput, bool) bool, ...request.Option) error
PutDashboard(*cloudwatch.PutDashboardInput) (*cloudwatch.PutDashboardOutput, error)
PutDashboardWithContext(aws.Context, *cloudwatch.PutDashboardInput, ...request.Option) (*cloudwatch.PutDashboardOutput, error)
PutDashboardRequest(*cloudwatch.PutDashboardInput) (*request.Request, *cloudwatch.PutDashboardOutput)
PutMetricAlarm(*cloudwatch.PutMetricAlarmInput) (*cloudwatch.PutMetricAlarmOutput, error)
PutMetricAlarmWithContext(aws.Context, *cloudwatch.PutMetricAlarmInput, ...request.Option) (*cloudwatch.PutMetricAlarmOutput, error)
PutMetricAlarmRequest(*cloudwatch.PutMetricAlarmInput) (*request.Request, *cloudwatch.PutMetricAlarmOutput)
PutMetricData(*cloudwatch.PutMetricDataInput) (*cloudwatch.PutMetricDataOutput, error)
PutMetricDataWithContext(aws.Context, *cloudwatch.PutMetricDataInput, ...request.Option) (*cloudwatch.PutMetricDataOutput, error)
PutMetricDataRequest(*cloudwatch.PutMetricDataInput) (*request.Request, *cloudwatch.PutMetricDataOutput)
SetAlarmState(*cloudwatch.SetAlarmStateInput) (*cloudwatch.SetAlarmStateOutput, error)
SetAlarmStateWithContext(aws.Context, *cloudwatch.SetAlarmStateInput, ...request.Option) (*cloudwatch.SetAlarmStateOutput, error)
SetAlarmStateRequest(*cloudwatch.SetAlarmStateInput) (*request.Request, *cloudwatch.SetAlarmStateOutput)
WaitUntilAlarmExists(*cloudwatch.DescribeAlarmsInput) error
WaitUntilAlarmExistsWithContext(aws.Context, *cloudwatch.DescribeAlarmsInput, ...request.WaiterOption) error
}
var _ CloudWatchAPI = (*cloudwatch.CloudWatch)(nil)
+6 -58
View File
@@ -26,69 +26,17 @@
//
// Using the Client
//
// To use the client for Amazon CloudWatch you will first need
// to create a new instance of it.
// To contact Amazon CloudWatch 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.
//
// When creating a client for an AWS service you'll first need to have a Session
// already created. The Session provides configuration that can be shared
// between multiple service clients. Additional configuration can be applied to
// the Session and service's client when they are constructed. The aws package's
// Config type contains several fields such as Region for the AWS Region the
// client should make API requests too. The optional Config value can be provided
// as the variadic argument for Sessions and client creation.
//
// Once the service's client is created you can use it to make API requests the
// AWS service. These clients are safe to use concurrently.
//
// // Create a session to share configuration, and load external configuration.
// sess := session.Must(session.NewSession())
//
// // Create the service's client with the session.
// svc := cloudwatch.New(sess)
//
// See the SDK's documentation for more information on how to use service clients.
// 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 package's Config type for more information on configuration options.
// See aws.Config documentation for more information on configuring SDK clients.
// https://docs.aws.amazon.com/sdk-for-go/api/aws/#Config
//
// See the Amazon CloudWatch client CloudWatch for more
// information on creating the service's client.
// information on creating client for this service.
// https://docs.aws.amazon.com/sdk-for-go/api/service/cloudwatch/#New
//
// Once the client is created you can make an API request to the service.
// Each API method takes a input parameter, and returns the service response
// and an error.
//
// The API method will document which error codes the service can be returned
// by the operation if the service models the API operation's errors. These
// errors will also be available as const strings prefixed with "ErrCode".
//
// result, err := svc.DeleteAlarms(params)
// if err != nil {
// // Cast err to awserr.Error to handle specific error codes.
// aerr, ok := err.(awserr.Error)
// if ok && aerr.Code() == <error code to check for> {
// // Specific error code handling
// }
// return err
// }
//
// fmt.Println("DeleteAlarms result:")
// fmt.Println(result)
//
// Using the Client with Context
//
// The service's client also provides methods to make API requests with a Context
// value. This allows you to control the timeout, and cancellation of pending
// requests. These methods also take request Option as variadic parameter to apply
// additional configuration to the API request.
//
// ctx := context.Background()
//
// result, err := svc.DeleteAlarmsWithContext(ctx, params)
//
// See the request package documentation for more information on using Context pattern
// with the SDK.
// https://docs.aws.amazon.com/sdk-for-go/api/aws/request/
package cloudwatch
+1 -1
View File
@@ -11,7 +11,7 @@ import (
// WaitUntilAlarmExists uses the CloudWatch API operation
// DescribeAlarms 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 *CloudWatch) WaitUntilAlarmExists(input *DescribeAlarmsInput) error {
return c.WaitUntilAlarmExistsWithContext(aws.BackgroundContext(), input)
+13998 -4141
View File
File diff suppressed because it is too large Load Diff
+8 -61
View File
@@ -4,9 +4,8 @@
// requests to Amazon Elastic Compute Cloud.
//
// Amazon Elastic Compute Cloud (Amazon EC2) provides resizable computing capacity
// in the Amazon Web Services (AWS) cloud. Using Amazon EC2 eliminates your
// need to invest in hardware up front, so you can develop and deploy applications
// faster.
// in the AWS Cloud. Using Amazon EC2 eliminates your need to invest in hardware
// up front, so you can develop and deploy applications faster.
//
// See https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15 for more information on this service.
//
@@ -15,69 +14,17 @@
//
// Using the Client
//
// To use the client for Amazon Elastic Compute Cloud you will first need
// to create a new instance of it.
// To contact Amazon Elastic Compute Cloud 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.
//
// When creating a client for an AWS service you'll first need to have a Session
// already created. The Session provides configuration that can be shared
// between multiple service clients. Additional configuration can be applied to
// the Session and service's client when they are constructed. The aws package's
// Config type contains several fields such as Region for the AWS Region the
// client should make API requests too. The optional Config value can be provided
// as the variadic argument for Sessions and client creation.
//
// Once the service's client is created you can use it to make API requests the
// AWS service. These clients are safe to use concurrently.
//
// // Create a session to share configuration, and load external configuration.
// sess := session.Must(session.NewSession())
//
// // Create the service's client with the session.
// svc := ec2.New(sess)
//
// See the SDK's documentation for more information on how to use service clients.
// 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 package's Config type for more information on configuration options.
// See aws.Config documentation for more information on configuring SDK clients.
// https://docs.aws.amazon.com/sdk-for-go/api/aws/#Config
//
// See the Amazon Elastic Compute Cloud client EC2 for more
// information on creating the service's client.
// information on creating client for this service.
// https://docs.aws.amazon.com/sdk-for-go/api/service/ec2/#New
//
// Once the client is created you can make an API request to the service.
// Each API method takes a input parameter, and returns the service response
// and an error.
//
// The API method will document which error codes the service can be returned
// by the operation if the service models the API operation's errors. These
// errors will also be available as const strings prefixed with "ErrCode".
//
// result, err := svc.AcceptReservedInstancesExchangeQuote(params)
// if err != nil {
// // Cast err to awserr.Error to handle specific error codes.
// aerr, ok := err.(awserr.Error)
// if ok && aerr.Code() == <error code to check for> {
// // Specific error code handling
// }
// return err
// }
//
// fmt.Println("AcceptReservedInstancesExchangeQuote result:")
// fmt.Println(result)
//
// Using the Client with Context
//
// The service's client also provides methods to make API requests with a Context
// value. This allows you to control the timeout, and cancellation of pending
// requests. These methods also take request Option as variadic parameter to apply
// additional configuration to the API request.
//
// ctx := context.Background()
//
// result, err := svc.AcceptReservedInstancesExchangeQuoteWithContext(ctx, params)
//
// See the request package documentation for more information on using Context pattern
// with the SDK.
// https://docs.aws.amazon.com/sdk-for-go/api/aws/request/
package ec2
+129 -1
View File
@@ -21,7 +21,7 @@ import (
//
// 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
// // Amazon Elastic Compute Cloud.
@@ -64,6 +64,10 @@ type EC2API interface {
AcceptReservedInstancesExchangeQuoteWithContext(aws.Context, *ec2.AcceptReservedInstancesExchangeQuoteInput, ...request.Option) (*ec2.AcceptReservedInstancesExchangeQuoteOutput, error)
AcceptReservedInstancesExchangeQuoteRequest(*ec2.AcceptReservedInstancesExchangeQuoteInput) (*request.Request, *ec2.AcceptReservedInstancesExchangeQuoteOutput)
AcceptVpcEndpointConnections(*ec2.AcceptVpcEndpointConnectionsInput) (*ec2.AcceptVpcEndpointConnectionsOutput, error)
AcceptVpcEndpointConnectionsWithContext(aws.Context, *ec2.AcceptVpcEndpointConnectionsInput, ...request.Option) (*ec2.AcceptVpcEndpointConnectionsOutput, error)
AcceptVpcEndpointConnectionsRequest(*ec2.AcceptVpcEndpointConnectionsInput) (*request.Request, *ec2.AcceptVpcEndpointConnectionsOutput)
AcceptVpcPeeringConnection(*ec2.AcceptVpcPeeringConnectionInput) (*ec2.AcceptVpcPeeringConnectionOutput, error)
AcceptVpcPeeringConnectionWithContext(aws.Context, *ec2.AcceptVpcPeeringConnectionInput, ...request.Option) (*ec2.AcceptVpcPeeringConnectionOutput, error)
AcceptVpcPeeringConnectionRequest(*ec2.AcceptVpcPeeringConnectionInput) (*request.Request, *ec2.AcceptVpcPeeringConnectionOutput)
@@ -172,6 +176,10 @@ type EC2API interface {
ConfirmProductInstanceWithContext(aws.Context, *ec2.ConfirmProductInstanceInput, ...request.Option) (*ec2.ConfirmProductInstanceOutput, error)
ConfirmProductInstanceRequest(*ec2.ConfirmProductInstanceInput) (*request.Request, *ec2.ConfirmProductInstanceOutput)
CopyFpgaImage(*ec2.CopyFpgaImageInput) (*ec2.CopyFpgaImageOutput, error)
CopyFpgaImageWithContext(aws.Context, *ec2.CopyFpgaImageInput, ...request.Option) (*ec2.CopyFpgaImageOutput, error)
CopyFpgaImageRequest(*ec2.CopyFpgaImageInput) (*request.Request, *ec2.CopyFpgaImageOutput)
CopyImage(*ec2.CopyImageInput) (*ec2.CopyImageOutput, error)
CopyImageWithContext(aws.Context, *ec2.CopyImageInput, ...request.Option) (*ec2.CopyImageOutput, error)
CopyImageRequest(*ec2.CopyImageInput) (*request.Request, *ec2.CopyImageOutput)
@@ -184,6 +192,10 @@ type EC2API interface {
CreateCustomerGatewayWithContext(aws.Context, *ec2.CreateCustomerGatewayInput, ...request.Option) (*ec2.CreateCustomerGatewayOutput, error)
CreateCustomerGatewayRequest(*ec2.CreateCustomerGatewayInput) (*request.Request, *ec2.CreateCustomerGatewayOutput)
CreateDefaultSubnet(*ec2.CreateDefaultSubnetInput) (*ec2.CreateDefaultSubnetOutput, error)
CreateDefaultSubnetWithContext(aws.Context, *ec2.CreateDefaultSubnetInput, ...request.Option) (*ec2.CreateDefaultSubnetOutput, error)
CreateDefaultSubnetRequest(*ec2.CreateDefaultSubnetInput) (*request.Request, *ec2.CreateDefaultSubnetOutput)
CreateDefaultVpc(*ec2.CreateDefaultVpcInput) (*ec2.CreateDefaultVpcOutput, error)
CreateDefaultVpcWithContext(aws.Context, *ec2.CreateDefaultVpcInput, ...request.Option) (*ec2.CreateDefaultVpcOutput, error)
CreateDefaultVpcRequest(*ec2.CreateDefaultVpcInput) (*request.Request, *ec2.CreateDefaultVpcOutput)
@@ -220,6 +232,14 @@ type EC2API interface {
CreateKeyPairWithContext(aws.Context, *ec2.CreateKeyPairInput, ...request.Option) (*ec2.CreateKeyPairOutput, error)
CreateKeyPairRequest(*ec2.CreateKeyPairInput) (*request.Request, *ec2.CreateKeyPairOutput)
CreateLaunchTemplate(*ec2.CreateLaunchTemplateInput) (*ec2.CreateLaunchTemplateOutput, error)
CreateLaunchTemplateWithContext(aws.Context, *ec2.CreateLaunchTemplateInput, ...request.Option) (*ec2.CreateLaunchTemplateOutput, error)
CreateLaunchTemplateRequest(*ec2.CreateLaunchTemplateInput) (*request.Request, *ec2.CreateLaunchTemplateOutput)
CreateLaunchTemplateVersion(*ec2.CreateLaunchTemplateVersionInput) (*ec2.CreateLaunchTemplateVersionOutput, error)
CreateLaunchTemplateVersionWithContext(aws.Context, *ec2.CreateLaunchTemplateVersionInput, ...request.Option) (*ec2.CreateLaunchTemplateVersionOutput, error)
CreateLaunchTemplateVersionRequest(*ec2.CreateLaunchTemplateVersionInput) (*request.Request, *ec2.CreateLaunchTemplateVersionOutput)
CreateNatGateway(*ec2.CreateNatGatewayInput) (*ec2.CreateNatGatewayOutput, error)
CreateNatGatewayWithContext(aws.Context, *ec2.CreateNatGatewayInput, ...request.Option) (*ec2.CreateNatGatewayOutput, error)
CreateNatGatewayRequest(*ec2.CreateNatGatewayInput) (*request.Request, *ec2.CreateNatGatewayOutput)
@@ -288,6 +308,14 @@ type EC2API interface {
CreateVpcEndpointWithContext(aws.Context, *ec2.CreateVpcEndpointInput, ...request.Option) (*ec2.CreateVpcEndpointOutput, error)
CreateVpcEndpointRequest(*ec2.CreateVpcEndpointInput) (*request.Request, *ec2.CreateVpcEndpointOutput)
CreateVpcEndpointConnectionNotification(*ec2.CreateVpcEndpointConnectionNotificationInput) (*ec2.CreateVpcEndpointConnectionNotificationOutput, error)
CreateVpcEndpointConnectionNotificationWithContext(aws.Context, *ec2.CreateVpcEndpointConnectionNotificationInput, ...request.Option) (*ec2.CreateVpcEndpointConnectionNotificationOutput, error)
CreateVpcEndpointConnectionNotificationRequest(*ec2.CreateVpcEndpointConnectionNotificationInput) (*request.Request, *ec2.CreateVpcEndpointConnectionNotificationOutput)
CreateVpcEndpointServiceConfiguration(*ec2.CreateVpcEndpointServiceConfigurationInput) (*ec2.CreateVpcEndpointServiceConfigurationOutput, error)
CreateVpcEndpointServiceConfigurationWithContext(aws.Context, *ec2.CreateVpcEndpointServiceConfigurationInput, ...request.Option) (*ec2.CreateVpcEndpointServiceConfigurationOutput, error)
CreateVpcEndpointServiceConfigurationRequest(*ec2.CreateVpcEndpointServiceConfigurationInput) (*request.Request, *ec2.CreateVpcEndpointServiceConfigurationOutput)
CreateVpcPeeringConnection(*ec2.CreateVpcPeeringConnectionInput) (*ec2.CreateVpcPeeringConnectionOutput, error)
CreateVpcPeeringConnectionWithContext(aws.Context, *ec2.CreateVpcPeeringConnectionInput, ...request.Option) (*ec2.CreateVpcPeeringConnectionOutput, error)
CreateVpcPeeringConnectionRequest(*ec2.CreateVpcPeeringConnectionInput) (*request.Request, *ec2.CreateVpcPeeringConnectionOutput)
@@ -320,6 +348,10 @@ type EC2API interface {
DeleteFlowLogsWithContext(aws.Context, *ec2.DeleteFlowLogsInput, ...request.Option) (*ec2.DeleteFlowLogsOutput, error)
DeleteFlowLogsRequest(*ec2.DeleteFlowLogsInput) (*request.Request, *ec2.DeleteFlowLogsOutput)
DeleteFpgaImage(*ec2.DeleteFpgaImageInput) (*ec2.DeleteFpgaImageOutput, error)
DeleteFpgaImageWithContext(aws.Context, *ec2.DeleteFpgaImageInput, ...request.Option) (*ec2.DeleteFpgaImageOutput, error)
DeleteFpgaImageRequest(*ec2.DeleteFpgaImageInput) (*request.Request, *ec2.DeleteFpgaImageOutput)
DeleteInternetGateway(*ec2.DeleteInternetGatewayInput) (*ec2.DeleteInternetGatewayOutput, error)
DeleteInternetGatewayWithContext(aws.Context, *ec2.DeleteInternetGatewayInput, ...request.Option) (*ec2.DeleteInternetGatewayOutput, error)
DeleteInternetGatewayRequest(*ec2.DeleteInternetGatewayInput) (*request.Request, *ec2.DeleteInternetGatewayOutput)
@@ -328,6 +360,14 @@ type EC2API interface {
DeleteKeyPairWithContext(aws.Context, *ec2.DeleteKeyPairInput, ...request.Option) (*ec2.DeleteKeyPairOutput, error)
DeleteKeyPairRequest(*ec2.DeleteKeyPairInput) (*request.Request, *ec2.DeleteKeyPairOutput)
DeleteLaunchTemplate(*ec2.DeleteLaunchTemplateInput) (*ec2.DeleteLaunchTemplateOutput, error)
DeleteLaunchTemplateWithContext(aws.Context, *ec2.DeleteLaunchTemplateInput, ...request.Option) (*ec2.DeleteLaunchTemplateOutput, error)
DeleteLaunchTemplateRequest(*ec2.DeleteLaunchTemplateInput) (*request.Request, *ec2.DeleteLaunchTemplateOutput)
DeleteLaunchTemplateVersions(*ec2.DeleteLaunchTemplateVersionsInput) (*ec2.DeleteLaunchTemplateVersionsOutput, error)
DeleteLaunchTemplateVersionsWithContext(aws.Context, *ec2.DeleteLaunchTemplateVersionsInput, ...request.Option) (*ec2.DeleteLaunchTemplateVersionsOutput, error)
DeleteLaunchTemplateVersionsRequest(*ec2.DeleteLaunchTemplateVersionsInput) (*request.Request, *ec2.DeleteLaunchTemplateVersionsOutput)
DeleteNatGateway(*ec2.DeleteNatGatewayInput) (*ec2.DeleteNatGatewayOutput, error)
DeleteNatGatewayWithContext(aws.Context, *ec2.DeleteNatGatewayInput, ...request.Option) (*ec2.DeleteNatGatewayOutput, error)
DeleteNatGatewayRequest(*ec2.DeleteNatGatewayInput) (*request.Request, *ec2.DeleteNatGatewayOutput)
@@ -388,6 +428,14 @@ type EC2API interface {
DeleteVpcWithContext(aws.Context, *ec2.DeleteVpcInput, ...request.Option) (*ec2.DeleteVpcOutput, error)
DeleteVpcRequest(*ec2.DeleteVpcInput) (*request.Request, *ec2.DeleteVpcOutput)
DeleteVpcEndpointConnectionNotifications(*ec2.DeleteVpcEndpointConnectionNotificationsInput) (*ec2.DeleteVpcEndpointConnectionNotificationsOutput, error)
DeleteVpcEndpointConnectionNotificationsWithContext(aws.Context, *ec2.DeleteVpcEndpointConnectionNotificationsInput, ...request.Option) (*ec2.DeleteVpcEndpointConnectionNotificationsOutput, error)
DeleteVpcEndpointConnectionNotificationsRequest(*ec2.DeleteVpcEndpointConnectionNotificationsInput) (*request.Request, *ec2.DeleteVpcEndpointConnectionNotificationsOutput)
DeleteVpcEndpointServiceConfigurations(*ec2.DeleteVpcEndpointServiceConfigurationsInput) (*ec2.DeleteVpcEndpointServiceConfigurationsOutput, error)
DeleteVpcEndpointServiceConfigurationsWithContext(aws.Context, *ec2.DeleteVpcEndpointServiceConfigurationsInput, ...request.Option) (*ec2.DeleteVpcEndpointServiceConfigurationsOutput, error)
DeleteVpcEndpointServiceConfigurationsRequest(*ec2.DeleteVpcEndpointServiceConfigurationsInput) (*request.Request, *ec2.DeleteVpcEndpointServiceConfigurationsOutput)
DeleteVpcEndpoints(*ec2.DeleteVpcEndpointsInput) (*ec2.DeleteVpcEndpointsOutput, error)
DeleteVpcEndpointsWithContext(aws.Context, *ec2.DeleteVpcEndpointsInput, ...request.Option) (*ec2.DeleteVpcEndpointsOutput, error)
DeleteVpcEndpointsRequest(*ec2.DeleteVpcEndpointsInput) (*request.Request, *ec2.DeleteVpcEndpointsOutput)
@@ -460,6 +508,10 @@ type EC2API interface {
DescribeFlowLogsWithContext(aws.Context, *ec2.DescribeFlowLogsInput, ...request.Option) (*ec2.DescribeFlowLogsOutput, error)
DescribeFlowLogsRequest(*ec2.DescribeFlowLogsInput) (*request.Request, *ec2.DescribeFlowLogsOutput)
DescribeFpgaImageAttribute(*ec2.DescribeFpgaImageAttributeInput) (*ec2.DescribeFpgaImageAttributeOutput, error)
DescribeFpgaImageAttributeWithContext(aws.Context, *ec2.DescribeFpgaImageAttributeInput, ...request.Option) (*ec2.DescribeFpgaImageAttributeOutput, error)
DescribeFpgaImageAttributeRequest(*ec2.DescribeFpgaImageAttributeInput) (*request.Request, *ec2.DescribeFpgaImageAttributeOutput)
DescribeFpgaImages(*ec2.DescribeFpgaImagesInput) (*ec2.DescribeFpgaImagesOutput, error)
DescribeFpgaImagesWithContext(aws.Context, *ec2.DescribeFpgaImagesInput, ...request.Option) (*ec2.DescribeFpgaImagesOutput, error)
DescribeFpgaImagesRequest(*ec2.DescribeFpgaImagesInput) (*request.Request, *ec2.DescribeFpgaImagesOutput)
@@ -508,6 +560,10 @@ type EC2API interface {
DescribeInstanceAttributeWithContext(aws.Context, *ec2.DescribeInstanceAttributeInput, ...request.Option) (*ec2.DescribeInstanceAttributeOutput, error)
DescribeInstanceAttributeRequest(*ec2.DescribeInstanceAttributeInput) (*request.Request, *ec2.DescribeInstanceAttributeOutput)
DescribeInstanceCreditSpecifications(*ec2.DescribeInstanceCreditSpecificationsInput) (*ec2.DescribeInstanceCreditSpecificationsOutput, error)
DescribeInstanceCreditSpecificationsWithContext(aws.Context, *ec2.DescribeInstanceCreditSpecificationsInput, ...request.Option) (*ec2.DescribeInstanceCreditSpecificationsOutput, error)
DescribeInstanceCreditSpecificationsRequest(*ec2.DescribeInstanceCreditSpecificationsInput) (*request.Request, *ec2.DescribeInstanceCreditSpecificationsOutput)
DescribeInstanceStatus(*ec2.DescribeInstanceStatusInput) (*ec2.DescribeInstanceStatusOutput, error)
DescribeInstanceStatusWithContext(aws.Context, *ec2.DescribeInstanceStatusInput, ...request.Option) (*ec2.DescribeInstanceStatusOutput, error)
DescribeInstanceStatusRequest(*ec2.DescribeInstanceStatusInput) (*request.Request, *ec2.DescribeInstanceStatusOutput)
@@ -530,6 +586,14 @@ type EC2API interface {
DescribeKeyPairsWithContext(aws.Context, *ec2.DescribeKeyPairsInput, ...request.Option) (*ec2.DescribeKeyPairsOutput, error)
DescribeKeyPairsRequest(*ec2.DescribeKeyPairsInput) (*request.Request, *ec2.DescribeKeyPairsOutput)
DescribeLaunchTemplateVersions(*ec2.DescribeLaunchTemplateVersionsInput) (*ec2.DescribeLaunchTemplateVersionsOutput, error)
DescribeLaunchTemplateVersionsWithContext(aws.Context, *ec2.DescribeLaunchTemplateVersionsInput, ...request.Option) (*ec2.DescribeLaunchTemplateVersionsOutput, error)
DescribeLaunchTemplateVersionsRequest(*ec2.DescribeLaunchTemplateVersionsInput) (*request.Request, *ec2.DescribeLaunchTemplateVersionsOutput)
DescribeLaunchTemplates(*ec2.DescribeLaunchTemplatesInput) (*ec2.DescribeLaunchTemplatesOutput, error)
DescribeLaunchTemplatesWithContext(aws.Context, *ec2.DescribeLaunchTemplatesInput, ...request.Option) (*ec2.DescribeLaunchTemplatesOutput, error)
DescribeLaunchTemplatesRequest(*ec2.DescribeLaunchTemplatesInput) (*request.Request, *ec2.DescribeLaunchTemplatesOutput)
DescribeMovingAddresses(*ec2.DescribeMovingAddressesInput) (*ec2.DescribeMovingAddressesOutput, error)
DescribeMovingAddressesWithContext(aws.Context, *ec2.DescribeMovingAddressesInput, ...request.Option) (*ec2.DescribeMovingAddressesOutput, error)
DescribeMovingAddressesRequest(*ec2.DescribeMovingAddressesInput) (*request.Request, *ec2.DescribeMovingAddressesOutput)
@@ -701,6 +765,22 @@ type EC2API interface {
DescribeVpcClassicLinkDnsSupportWithContext(aws.Context, *ec2.DescribeVpcClassicLinkDnsSupportInput, ...request.Option) (*ec2.DescribeVpcClassicLinkDnsSupportOutput, error)
DescribeVpcClassicLinkDnsSupportRequest(*ec2.DescribeVpcClassicLinkDnsSupportInput) (*request.Request, *ec2.DescribeVpcClassicLinkDnsSupportOutput)
DescribeVpcEndpointConnectionNotifications(*ec2.DescribeVpcEndpointConnectionNotificationsInput) (*ec2.DescribeVpcEndpointConnectionNotificationsOutput, error)
DescribeVpcEndpointConnectionNotificationsWithContext(aws.Context, *ec2.DescribeVpcEndpointConnectionNotificationsInput, ...request.Option) (*ec2.DescribeVpcEndpointConnectionNotificationsOutput, error)
DescribeVpcEndpointConnectionNotificationsRequest(*ec2.DescribeVpcEndpointConnectionNotificationsInput) (*request.Request, *ec2.DescribeVpcEndpointConnectionNotificationsOutput)
DescribeVpcEndpointConnections(*ec2.DescribeVpcEndpointConnectionsInput) (*ec2.DescribeVpcEndpointConnectionsOutput, error)
DescribeVpcEndpointConnectionsWithContext(aws.Context, *ec2.DescribeVpcEndpointConnectionsInput, ...request.Option) (*ec2.DescribeVpcEndpointConnectionsOutput, error)
DescribeVpcEndpointConnectionsRequest(*ec2.DescribeVpcEndpointConnectionsInput) (*request.Request, *ec2.DescribeVpcEndpointConnectionsOutput)
DescribeVpcEndpointServiceConfigurations(*ec2.DescribeVpcEndpointServiceConfigurationsInput) (*ec2.DescribeVpcEndpointServiceConfigurationsOutput, error)
DescribeVpcEndpointServiceConfigurationsWithContext(aws.Context, *ec2.DescribeVpcEndpointServiceConfigurationsInput, ...request.Option) (*ec2.DescribeVpcEndpointServiceConfigurationsOutput, error)
DescribeVpcEndpointServiceConfigurationsRequest(*ec2.DescribeVpcEndpointServiceConfigurationsInput) (*request.Request, *ec2.DescribeVpcEndpointServiceConfigurationsOutput)
DescribeVpcEndpointServicePermissions(*ec2.DescribeVpcEndpointServicePermissionsInput) (*ec2.DescribeVpcEndpointServicePermissionsOutput, error)
DescribeVpcEndpointServicePermissionsWithContext(aws.Context, *ec2.DescribeVpcEndpointServicePermissionsInput, ...request.Option) (*ec2.DescribeVpcEndpointServicePermissionsOutput, error)
DescribeVpcEndpointServicePermissionsRequest(*ec2.DescribeVpcEndpointServicePermissionsInput) (*request.Request, *ec2.DescribeVpcEndpointServicePermissionsOutput)
DescribeVpcEndpointServices(*ec2.DescribeVpcEndpointServicesInput) (*ec2.DescribeVpcEndpointServicesOutput, error)
DescribeVpcEndpointServicesWithContext(aws.Context, *ec2.DescribeVpcEndpointServicesInput, ...request.Option) (*ec2.DescribeVpcEndpointServicesOutput, error)
DescribeVpcEndpointServicesRequest(*ec2.DescribeVpcEndpointServicesInput) (*request.Request, *ec2.DescribeVpcEndpointServicesOutput)
@@ -805,6 +885,10 @@ type EC2API interface {
GetHostReservationPurchasePreviewWithContext(aws.Context, *ec2.GetHostReservationPurchasePreviewInput, ...request.Option) (*ec2.GetHostReservationPurchasePreviewOutput, error)
GetHostReservationPurchasePreviewRequest(*ec2.GetHostReservationPurchasePreviewInput) (*request.Request, *ec2.GetHostReservationPurchasePreviewOutput)
GetLaunchTemplateData(*ec2.GetLaunchTemplateDataInput) (*ec2.GetLaunchTemplateDataOutput, error)
GetLaunchTemplateDataWithContext(aws.Context, *ec2.GetLaunchTemplateDataInput, ...request.Option) (*ec2.GetLaunchTemplateDataOutput, error)
GetLaunchTemplateDataRequest(*ec2.GetLaunchTemplateDataInput) (*request.Request, *ec2.GetLaunchTemplateDataOutput)
GetPasswordData(*ec2.GetPasswordDataInput) (*ec2.GetPasswordDataOutput, error)
GetPasswordDataWithContext(aws.Context, *ec2.GetPasswordDataInput, ...request.Option) (*ec2.GetPasswordDataOutput, error)
GetPasswordDataRequest(*ec2.GetPasswordDataInput) (*request.Request, *ec2.GetPasswordDataOutput)
@@ -833,6 +917,10 @@ type EC2API interface {
ImportVolumeWithContext(aws.Context, *ec2.ImportVolumeInput, ...request.Option) (*ec2.ImportVolumeOutput, error)
ImportVolumeRequest(*ec2.ImportVolumeInput) (*request.Request, *ec2.ImportVolumeOutput)
ModifyFpgaImageAttribute(*ec2.ModifyFpgaImageAttributeInput) (*ec2.ModifyFpgaImageAttributeOutput, error)
ModifyFpgaImageAttributeWithContext(aws.Context, *ec2.ModifyFpgaImageAttributeInput, ...request.Option) (*ec2.ModifyFpgaImageAttributeOutput, error)
ModifyFpgaImageAttributeRequest(*ec2.ModifyFpgaImageAttributeInput) (*request.Request, *ec2.ModifyFpgaImageAttributeOutput)
ModifyHosts(*ec2.ModifyHostsInput) (*ec2.ModifyHostsOutput, error)
ModifyHostsWithContext(aws.Context, *ec2.ModifyHostsInput, ...request.Option) (*ec2.ModifyHostsOutput, error)
ModifyHostsRequest(*ec2.ModifyHostsInput) (*request.Request, *ec2.ModifyHostsOutput)
@@ -853,10 +941,18 @@ type EC2API interface {
ModifyInstanceAttributeWithContext(aws.Context, *ec2.ModifyInstanceAttributeInput, ...request.Option) (*ec2.ModifyInstanceAttributeOutput, error)
ModifyInstanceAttributeRequest(*ec2.ModifyInstanceAttributeInput) (*request.Request, *ec2.ModifyInstanceAttributeOutput)
ModifyInstanceCreditSpecification(*ec2.ModifyInstanceCreditSpecificationInput) (*ec2.ModifyInstanceCreditSpecificationOutput, error)
ModifyInstanceCreditSpecificationWithContext(aws.Context, *ec2.ModifyInstanceCreditSpecificationInput, ...request.Option) (*ec2.ModifyInstanceCreditSpecificationOutput, error)
ModifyInstanceCreditSpecificationRequest(*ec2.ModifyInstanceCreditSpecificationInput) (*request.Request, *ec2.ModifyInstanceCreditSpecificationOutput)
ModifyInstancePlacement(*ec2.ModifyInstancePlacementInput) (*ec2.ModifyInstancePlacementOutput, error)
ModifyInstancePlacementWithContext(aws.Context, *ec2.ModifyInstancePlacementInput, ...request.Option) (*ec2.ModifyInstancePlacementOutput, error)
ModifyInstancePlacementRequest(*ec2.ModifyInstancePlacementInput) (*request.Request, *ec2.ModifyInstancePlacementOutput)
ModifyLaunchTemplate(*ec2.ModifyLaunchTemplateInput) (*ec2.ModifyLaunchTemplateOutput, error)
ModifyLaunchTemplateWithContext(aws.Context, *ec2.ModifyLaunchTemplateInput, ...request.Option) (*ec2.ModifyLaunchTemplateOutput, error)
ModifyLaunchTemplateRequest(*ec2.ModifyLaunchTemplateInput) (*request.Request, *ec2.ModifyLaunchTemplateOutput)
ModifyNetworkInterfaceAttribute(*ec2.ModifyNetworkInterfaceAttributeInput) (*ec2.ModifyNetworkInterfaceAttributeOutput, error)
ModifyNetworkInterfaceAttributeWithContext(aws.Context, *ec2.ModifyNetworkInterfaceAttributeInput, ...request.Option) (*ec2.ModifyNetworkInterfaceAttributeOutput, error)
ModifyNetworkInterfaceAttributeRequest(*ec2.ModifyNetworkInterfaceAttributeInput) (*request.Request, *ec2.ModifyNetworkInterfaceAttributeOutput)
@@ -893,10 +989,26 @@ type EC2API interface {
ModifyVpcEndpointWithContext(aws.Context, *ec2.ModifyVpcEndpointInput, ...request.Option) (*ec2.ModifyVpcEndpointOutput, error)
ModifyVpcEndpointRequest(*ec2.ModifyVpcEndpointInput) (*request.Request, *ec2.ModifyVpcEndpointOutput)
ModifyVpcEndpointConnectionNotification(*ec2.ModifyVpcEndpointConnectionNotificationInput) (*ec2.ModifyVpcEndpointConnectionNotificationOutput, error)
ModifyVpcEndpointConnectionNotificationWithContext(aws.Context, *ec2.ModifyVpcEndpointConnectionNotificationInput, ...request.Option) (*ec2.ModifyVpcEndpointConnectionNotificationOutput, error)
ModifyVpcEndpointConnectionNotificationRequest(*ec2.ModifyVpcEndpointConnectionNotificationInput) (*request.Request, *ec2.ModifyVpcEndpointConnectionNotificationOutput)
ModifyVpcEndpointServiceConfiguration(*ec2.ModifyVpcEndpointServiceConfigurationInput) (*ec2.ModifyVpcEndpointServiceConfigurationOutput, error)
ModifyVpcEndpointServiceConfigurationWithContext(aws.Context, *ec2.ModifyVpcEndpointServiceConfigurationInput, ...request.Option) (*ec2.ModifyVpcEndpointServiceConfigurationOutput, error)
ModifyVpcEndpointServiceConfigurationRequest(*ec2.ModifyVpcEndpointServiceConfigurationInput) (*request.Request, *ec2.ModifyVpcEndpointServiceConfigurationOutput)
ModifyVpcEndpointServicePermissions(*ec2.ModifyVpcEndpointServicePermissionsInput) (*ec2.ModifyVpcEndpointServicePermissionsOutput, error)
ModifyVpcEndpointServicePermissionsWithContext(aws.Context, *ec2.ModifyVpcEndpointServicePermissionsInput, ...request.Option) (*ec2.ModifyVpcEndpointServicePermissionsOutput, error)
ModifyVpcEndpointServicePermissionsRequest(*ec2.ModifyVpcEndpointServicePermissionsInput) (*request.Request, *ec2.ModifyVpcEndpointServicePermissionsOutput)
ModifyVpcPeeringConnectionOptions(*ec2.ModifyVpcPeeringConnectionOptionsInput) (*ec2.ModifyVpcPeeringConnectionOptionsOutput, error)
ModifyVpcPeeringConnectionOptionsWithContext(aws.Context, *ec2.ModifyVpcPeeringConnectionOptionsInput, ...request.Option) (*ec2.ModifyVpcPeeringConnectionOptionsOutput, error)
ModifyVpcPeeringConnectionOptionsRequest(*ec2.ModifyVpcPeeringConnectionOptionsInput) (*request.Request, *ec2.ModifyVpcPeeringConnectionOptionsOutput)
ModifyVpcTenancy(*ec2.ModifyVpcTenancyInput) (*ec2.ModifyVpcTenancyOutput, error)
ModifyVpcTenancyWithContext(aws.Context, *ec2.ModifyVpcTenancyInput, ...request.Option) (*ec2.ModifyVpcTenancyOutput, error)
ModifyVpcTenancyRequest(*ec2.ModifyVpcTenancyInput) (*request.Request, *ec2.ModifyVpcTenancyOutput)
MonitorInstances(*ec2.MonitorInstancesInput) (*ec2.MonitorInstancesOutput, error)
MonitorInstancesWithContext(aws.Context, *ec2.MonitorInstancesInput, ...request.Option) (*ec2.MonitorInstancesOutput, error)
MonitorInstancesRequest(*ec2.MonitorInstancesInput) (*request.Request, *ec2.MonitorInstancesOutput)
@@ -925,6 +1037,10 @@ type EC2API interface {
RegisterImageWithContext(aws.Context, *ec2.RegisterImageInput, ...request.Option) (*ec2.RegisterImageOutput, error)
RegisterImageRequest(*ec2.RegisterImageInput) (*request.Request, *ec2.RegisterImageOutput)
RejectVpcEndpointConnections(*ec2.RejectVpcEndpointConnectionsInput) (*ec2.RejectVpcEndpointConnectionsOutput, error)
RejectVpcEndpointConnectionsWithContext(aws.Context, *ec2.RejectVpcEndpointConnectionsInput, ...request.Option) (*ec2.RejectVpcEndpointConnectionsOutput, error)
RejectVpcEndpointConnectionsRequest(*ec2.RejectVpcEndpointConnectionsInput) (*request.Request, *ec2.RejectVpcEndpointConnectionsOutput)
RejectVpcPeeringConnection(*ec2.RejectVpcPeeringConnectionInput) (*ec2.RejectVpcPeeringConnectionOutput, error)
RejectVpcPeeringConnectionWithContext(aws.Context, *ec2.RejectVpcPeeringConnectionInput, ...request.Option) (*ec2.RejectVpcPeeringConnectionOutput, error)
RejectVpcPeeringConnectionRequest(*ec2.RejectVpcPeeringConnectionInput) (*request.Request, *ec2.RejectVpcPeeringConnectionOutput)
@@ -969,6 +1085,10 @@ type EC2API interface {
RequestSpotInstancesWithContext(aws.Context, *ec2.RequestSpotInstancesInput, ...request.Option) (*ec2.RequestSpotInstancesOutput, error)
RequestSpotInstancesRequest(*ec2.RequestSpotInstancesInput) (*request.Request, *ec2.RequestSpotInstancesOutput)
ResetFpgaImageAttribute(*ec2.ResetFpgaImageAttributeInput) (*ec2.ResetFpgaImageAttributeOutput, error)
ResetFpgaImageAttributeWithContext(aws.Context, *ec2.ResetFpgaImageAttributeInput, ...request.Option) (*ec2.ResetFpgaImageAttributeOutput, error)
ResetFpgaImageAttributeRequest(*ec2.ResetFpgaImageAttributeInput) (*request.Request, *ec2.ResetFpgaImageAttributeOutput)
ResetImageAttribute(*ec2.ResetImageAttributeInput) (*ec2.ResetImageAttributeOutput, error)
ResetImageAttributeWithContext(aws.Context, *ec2.ResetImageAttributeInput, ...request.Option) (*ec2.ResetImageAttributeOutput, error)
ResetImageAttributeRequest(*ec2.ResetImageAttributeInput) (*request.Request, *ec2.ResetImageAttributeOutput)
@@ -1029,6 +1149,14 @@ type EC2API interface {
UnmonitorInstancesWithContext(aws.Context, *ec2.UnmonitorInstancesInput, ...request.Option) (*ec2.UnmonitorInstancesOutput, error)
UnmonitorInstancesRequest(*ec2.UnmonitorInstancesInput) (*request.Request, *ec2.UnmonitorInstancesOutput)
UpdateSecurityGroupRuleDescriptionsEgress(*ec2.UpdateSecurityGroupRuleDescriptionsEgressInput) (*ec2.UpdateSecurityGroupRuleDescriptionsEgressOutput, error)
UpdateSecurityGroupRuleDescriptionsEgressWithContext(aws.Context, *ec2.UpdateSecurityGroupRuleDescriptionsEgressInput, ...request.Option) (*ec2.UpdateSecurityGroupRuleDescriptionsEgressOutput, error)
UpdateSecurityGroupRuleDescriptionsEgressRequest(*ec2.UpdateSecurityGroupRuleDescriptionsEgressInput) (*request.Request, *ec2.UpdateSecurityGroupRuleDescriptionsEgressOutput)
UpdateSecurityGroupRuleDescriptionsIngress(*ec2.UpdateSecurityGroupRuleDescriptionsIngressInput) (*ec2.UpdateSecurityGroupRuleDescriptionsIngressOutput, error)
UpdateSecurityGroupRuleDescriptionsIngressWithContext(aws.Context, *ec2.UpdateSecurityGroupRuleDescriptionsIngressInput, ...request.Option) (*ec2.UpdateSecurityGroupRuleDescriptionsIngressOutput, error)
UpdateSecurityGroupRuleDescriptionsIngressRequest(*ec2.UpdateSecurityGroupRuleDescriptionsIngressInput) (*request.Request, *ec2.UpdateSecurityGroupRuleDescriptionsIngressOutput)
WaitUntilBundleTaskComplete(*ec2.DescribeBundleTasksInput) error
WaitUntilBundleTaskCompleteWithContext(aws.Context, *ec2.DescribeBundleTasksInput, ...request.WaiterOption) error
+41 -31
View File
@@ -11,7 +11,7 @@ import (
// WaitUntilBundleTaskComplete uses the Amazon EC2 API operation
// DescribeBundleTasks 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 *EC2) WaitUntilBundleTaskComplete(input *DescribeBundleTasksInput) error {
return c.WaitUntilBundleTaskCompleteWithContext(aws.BackgroundContext(), input)
@@ -62,7 +62,7 @@ func (c *EC2) WaitUntilBundleTaskCompleteWithContext(ctx aws.Context, input *Des
// WaitUntilConversionTaskCancelled uses the Amazon EC2 API operation
// DescribeConversionTasks 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 *EC2) WaitUntilConversionTaskCancelled(input *DescribeConversionTasksInput) error {
return c.WaitUntilConversionTaskCancelledWithContext(aws.BackgroundContext(), input)
@@ -108,7 +108,7 @@ func (c *EC2) WaitUntilConversionTaskCancelledWithContext(ctx aws.Context, input
// WaitUntilConversionTaskCompleted uses the Amazon EC2 API operation
// DescribeConversionTasks 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 *EC2) WaitUntilConversionTaskCompleted(input *DescribeConversionTasksInput) error {
return c.WaitUntilConversionTaskCompletedWithContext(aws.BackgroundContext(), input)
@@ -164,7 +164,7 @@ func (c *EC2) WaitUntilConversionTaskCompletedWithContext(ctx aws.Context, input
// WaitUntilConversionTaskDeleted uses the Amazon EC2 API operation
// DescribeConversionTasks 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 *EC2) WaitUntilConversionTaskDeleted(input *DescribeConversionTasksInput) error {
return c.WaitUntilConversionTaskDeletedWithContext(aws.BackgroundContext(), input)
@@ -210,7 +210,7 @@ func (c *EC2) WaitUntilConversionTaskDeletedWithContext(ctx aws.Context, input *
// WaitUntilCustomerGatewayAvailable uses the Amazon EC2 API operation
// DescribeCustomerGateways 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 *EC2) WaitUntilCustomerGatewayAvailable(input *DescribeCustomerGatewaysInput) error {
return c.WaitUntilCustomerGatewayAvailableWithContext(aws.BackgroundContext(), input)
@@ -266,7 +266,7 @@ func (c *EC2) WaitUntilCustomerGatewayAvailableWithContext(ctx aws.Context, inpu
// WaitUntilExportTaskCancelled uses the Amazon EC2 API operation
// DescribeExportTasks 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 *EC2) WaitUntilExportTaskCancelled(input *DescribeExportTasksInput) error {
return c.WaitUntilExportTaskCancelledWithContext(aws.BackgroundContext(), input)
@@ -312,7 +312,7 @@ func (c *EC2) WaitUntilExportTaskCancelledWithContext(ctx aws.Context, input *De
// WaitUntilExportTaskCompleted uses the Amazon EC2 API operation
// DescribeExportTasks 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 *EC2) WaitUntilExportTaskCompleted(input *DescribeExportTasksInput) error {
return c.WaitUntilExportTaskCompletedWithContext(aws.BackgroundContext(), input)
@@ -358,7 +358,7 @@ func (c *EC2) WaitUntilExportTaskCompletedWithContext(ctx aws.Context, input *De
// WaitUntilImageAvailable uses the Amazon EC2 API operation
// DescribeImages 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 *EC2) WaitUntilImageAvailable(input *DescribeImagesInput) error {
return c.WaitUntilImageAvailableWithContext(aws.BackgroundContext(), input)
@@ -409,7 +409,7 @@ func (c *EC2) WaitUntilImageAvailableWithContext(ctx aws.Context, input *Describ
// WaitUntilImageExists uses the Amazon EC2 API operation
// DescribeImages 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 *EC2) WaitUntilImageExists(input *DescribeImagesInput) error {
return c.WaitUntilImageExistsWithContext(aws.BackgroundContext(), input)
@@ -460,7 +460,7 @@ func (c *EC2) WaitUntilImageExistsWithContext(ctx aws.Context, input *DescribeIm
// WaitUntilInstanceExists uses the Amazon EC2 API operation
// DescribeInstances 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 *EC2) WaitUntilInstanceExists(input *DescribeInstancesInput) error {
return c.WaitUntilInstanceExistsWithContext(aws.BackgroundContext(), input)
@@ -511,7 +511,7 @@ func (c *EC2) WaitUntilInstanceExistsWithContext(ctx aws.Context, input *Describ
// WaitUntilInstanceRunning uses the Amazon EC2 API operation
// DescribeInstances 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 *EC2) WaitUntilInstanceRunning(input *DescribeInstancesInput) error {
return c.WaitUntilInstanceRunningWithContext(aws.BackgroundContext(), input)
@@ -577,7 +577,7 @@ func (c *EC2) WaitUntilInstanceRunningWithContext(ctx aws.Context, input *Descri
// WaitUntilInstanceStatusOk uses the Amazon EC2 API operation
// DescribeInstanceStatus 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 *EC2) WaitUntilInstanceStatusOk(input *DescribeInstanceStatusInput) error {
return c.WaitUntilInstanceStatusOkWithContext(aws.BackgroundContext(), input)
@@ -628,7 +628,7 @@ func (c *EC2) WaitUntilInstanceStatusOkWithContext(ctx aws.Context, input *Descr
// WaitUntilInstanceStopped uses the Amazon EC2 API operation
// DescribeInstances 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 *EC2) WaitUntilInstanceStopped(input *DescribeInstancesInput) error {
return c.WaitUntilInstanceStoppedWithContext(aws.BackgroundContext(), input)
@@ -684,7 +684,7 @@ func (c *EC2) WaitUntilInstanceStoppedWithContext(ctx aws.Context, input *Descri
// WaitUntilInstanceTerminated uses the Amazon EC2 API operation
// DescribeInstances 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 *EC2) WaitUntilInstanceTerminated(input *DescribeInstancesInput) error {
return c.WaitUntilInstanceTerminatedWithContext(aws.BackgroundContext(), input)
@@ -740,7 +740,7 @@ func (c *EC2) WaitUntilInstanceTerminatedWithContext(ctx aws.Context, input *Des
// WaitUntilKeyPairExists uses the Amazon EC2 API operation
// DescribeKeyPairs 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 *EC2) WaitUntilKeyPairExists(input *DescribeKeyPairsInput) error {
return c.WaitUntilKeyPairExistsWithContext(aws.BackgroundContext(), input)
@@ -791,7 +791,7 @@ func (c *EC2) WaitUntilKeyPairExistsWithContext(ctx aws.Context, input *Describe
// WaitUntilNatGatewayAvailable uses the Amazon EC2 API operation
// DescribeNatGateways 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 *EC2) WaitUntilNatGatewayAvailable(input *DescribeNatGatewaysInput) error {
return c.WaitUntilNatGatewayAvailableWithContext(aws.BackgroundContext(), input)
@@ -857,7 +857,7 @@ func (c *EC2) WaitUntilNatGatewayAvailableWithContext(ctx aws.Context, input *De
// WaitUntilNetworkInterfaceAvailable uses the Amazon EC2 API operation
// DescribeNetworkInterfaces 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 *EC2) WaitUntilNetworkInterfaceAvailable(input *DescribeNetworkInterfacesInput) error {
return c.WaitUntilNetworkInterfaceAvailableWithContext(aws.BackgroundContext(), input)
@@ -908,7 +908,7 @@ func (c *EC2) WaitUntilNetworkInterfaceAvailableWithContext(ctx aws.Context, inp
// WaitUntilPasswordDataAvailable uses the Amazon EC2 API operation
// GetPasswordData 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 *EC2) WaitUntilPasswordDataAvailable(input *GetPasswordDataInput) error {
return c.WaitUntilPasswordDataAvailableWithContext(aws.BackgroundContext(), input)
@@ -954,7 +954,7 @@ func (c *EC2) WaitUntilPasswordDataAvailableWithContext(ctx aws.Context, input *
// WaitUntilSnapshotCompleted uses the Amazon EC2 API operation
// DescribeSnapshots 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 *EC2) WaitUntilSnapshotCompleted(input *DescribeSnapshotsInput) error {
return c.WaitUntilSnapshotCompletedWithContext(aws.BackgroundContext(), input)
@@ -1000,7 +1000,7 @@ func (c *EC2) WaitUntilSnapshotCompletedWithContext(ctx aws.Context, input *Desc
// WaitUntilSpotInstanceRequestFulfilled uses the Amazon EC2 API operation
// DescribeSpotInstanceRequests 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 *EC2) WaitUntilSpotInstanceRequestFulfilled(input *DescribeSpotInstanceRequestsInput) error {
return c.WaitUntilSpotInstanceRequestFulfilledWithContext(aws.BackgroundContext(), input)
@@ -1025,6 +1025,11 @@ func (c *EC2) WaitUntilSpotInstanceRequestFulfilledWithContext(ctx aws.Context,
Matcher: request.PathAllWaiterMatch, Argument: "SpotInstanceRequests[].Status.Code",
Expected: "fulfilled",
},
{
State: request.SuccessWaiterState,
Matcher: request.PathAllWaiterMatch, Argument: "SpotInstanceRequests[].Status.Code",
Expected: "request-canceled-and-instance-running",
},
{
State: request.FailureWaiterState,
Matcher: request.PathAnyWaiterMatch, Argument: "SpotInstanceRequests[].Status.Code",
@@ -1045,6 +1050,11 @@ func (c *EC2) WaitUntilSpotInstanceRequestFulfilledWithContext(ctx aws.Context,
Matcher: request.PathAnyWaiterMatch, Argument: "SpotInstanceRequests[].Status.Code",
Expected: "system-error",
},
{
State: request.RetryWaiterState,
Matcher: request.ErrorWaiterMatch,
Expected: "InvalidSpotInstanceRequestID.NotFound",
},
},
Logger: c.Config.Logger,
NewRequest: func(opts []request.Option) (*request.Request, error) {
@@ -1066,7 +1076,7 @@ func (c *EC2) WaitUntilSpotInstanceRequestFulfilledWithContext(ctx aws.Context,
// WaitUntilSubnetAvailable uses the Amazon EC2 API operation
// DescribeSubnets 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 *EC2) WaitUntilSubnetAvailable(input *DescribeSubnetsInput) error {
return c.WaitUntilSubnetAvailableWithContext(aws.BackgroundContext(), input)
@@ -1112,7 +1122,7 @@ func (c *EC2) WaitUntilSubnetAvailableWithContext(ctx aws.Context, input *Descri
// WaitUntilSystemStatusOk uses the Amazon EC2 API operation
// DescribeInstanceStatus 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 *EC2) WaitUntilSystemStatusOk(input *DescribeInstanceStatusInput) error {
return c.WaitUntilSystemStatusOkWithContext(aws.BackgroundContext(), input)
@@ -1158,7 +1168,7 @@ func (c *EC2) WaitUntilSystemStatusOkWithContext(ctx aws.Context, input *Describ
// WaitUntilVolumeAvailable uses the Amazon EC2 API operation
// DescribeVolumes 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 *EC2) WaitUntilVolumeAvailable(input *DescribeVolumesInput) error {
return c.WaitUntilVolumeAvailableWithContext(aws.BackgroundContext(), input)
@@ -1209,7 +1219,7 @@ func (c *EC2) WaitUntilVolumeAvailableWithContext(ctx aws.Context, input *Descri
// WaitUntilVolumeDeleted uses the Amazon EC2 API operation
// DescribeVolumes 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 *EC2) WaitUntilVolumeDeleted(input *DescribeVolumesInput) error {
return c.WaitUntilVolumeDeletedWithContext(aws.BackgroundContext(), input)
@@ -1260,7 +1270,7 @@ func (c *EC2) WaitUntilVolumeDeletedWithContext(ctx aws.Context, input *Describe
// WaitUntilVolumeInUse uses the Amazon EC2 API operation
// DescribeVolumes 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 *EC2) WaitUntilVolumeInUse(input *DescribeVolumesInput) error {
return c.WaitUntilVolumeInUseWithContext(aws.BackgroundContext(), input)
@@ -1311,7 +1321,7 @@ func (c *EC2) WaitUntilVolumeInUseWithContext(ctx aws.Context, input *DescribeVo
// WaitUntilVpcAvailable uses the Amazon EC2 API operation
// DescribeVpcs 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 *EC2) WaitUntilVpcAvailable(input *DescribeVpcsInput) error {
return c.WaitUntilVpcAvailableWithContext(aws.BackgroundContext(), input)
@@ -1357,7 +1367,7 @@ func (c *EC2) WaitUntilVpcAvailableWithContext(ctx aws.Context, input *DescribeV
// WaitUntilVpcExists uses the Amazon EC2 API operation
// DescribeVpcs 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 *EC2) WaitUntilVpcExists(input *DescribeVpcsInput) error {
return c.WaitUntilVpcExistsWithContext(aws.BackgroundContext(), input)
@@ -1408,7 +1418,7 @@ func (c *EC2) WaitUntilVpcExistsWithContext(ctx aws.Context, input *DescribeVpcs
// WaitUntilVpcPeeringConnectionDeleted uses the Amazon EC2 API operation
// DescribeVpcPeeringConnections 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 *EC2) WaitUntilVpcPeeringConnectionDeleted(input *DescribeVpcPeeringConnectionsInput) error {
return c.WaitUntilVpcPeeringConnectionDeletedWithContext(aws.BackgroundContext(), input)
@@ -1459,7 +1469,7 @@ func (c *EC2) WaitUntilVpcPeeringConnectionDeletedWithContext(ctx aws.Context, i
// WaitUntilVpcPeeringConnectionExists uses the Amazon EC2 API operation
// DescribeVpcPeeringConnections 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 *EC2) WaitUntilVpcPeeringConnectionExists(input *DescribeVpcPeeringConnectionsInput) error {
return c.WaitUntilVpcPeeringConnectionExistsWithContext(aws.BackgroundContext(), input)
@@ -1510,7 +1520,7 @@ func (c *EC2) WaitUntilVpcPeeringConnectionExistsWithContext(ctx aws.Context, in
// WaitUntilVpnConnectionAvailable uses the Amazon EC2 API operation
// DescribeVpnConnections 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 *EC2) WaitUntilVpnConnectionAvailable(input *DescribeVpnConnectionsInput) error {
return c.WaitUntilVpnConnectionAvailableWithContext(aws.BackgroundContext(), input)
@@ -1566,7 +1576,7 @@ func (c *EC2) WaitUntilVpnConnectionAvailableWithContext(ctx aws.Context, input
// WaitUntilVpnConnectionDeleted uses the Amazon EC2 API operation
// DescribeVpnConnections 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 *EC2) WaitUntilVpnConnectionDeleted(input *DescribeVpnConnectionsInput) error {
return c.WaitUntilVpnConnectionDeletedWithContext(aws.BackgroundContext(), input)
+2625 -1121
View File
File diff suppressed because it is too large Load Diff
+6 -58
View File
@@ -10,69 +10,17 @@
//
// Using the Client
//
// To use the client for Amazon Simple Storage Service you will first need
// to create a new instance of it.
// To contact Amazon Simple Storage Service 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.
//
// When creating a client for an AWS service you'll first need to have a Session
// already created. The Session provides configuration that can be shared
// between multiple service clients. Additional configuration can be applied to
// the Session and service's client when they are constructed. The aws package's
// Config type contains several fields such as Region for the AWS Region the
// client should make API requests too. The optional Config value can be provided
// as the variadic argument for Sessions and client creation.
//
// Once the service's client is created you can use it to make API requests the
// AWS service. These clients are safe to use concurrently.
//
// // Create a session to share configuration, and load external configuration.
// sess := session.Must(session.NewSession())
//
// // Create the service's client with the session.
// svc := s3.New(sess)
//
// See the SDK's documentation for more information on how to use service clients.
// 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 package's Config type for more information on configuration options.
// See aws.Config documentation for more information on configuring SDK clients.
// https://docs.aws.amazon.com/sdk-for-go/api/aws/#Config
//
// See the Amazon Simple Storage Service client S3 for more
// information on creating the service's client.
// information on creating client for this service.
// https://docs.aws.amazon.com/sdk-for-go/api/service/s3/#New
//
// Once the client is created you can make an API request to the service.
// Each API method takes a input parameter, and returns the service response
// and an error.
//
// The API method will document which error codes the service can be returned
// by the operation if the service models the API operation's errors. These
// errors will also be available as const strings prefixed with "ErrCode".
//
// result, err := svc.AbortMultipartUpload(params)
// if err != nil {
// // Cast err to awserr.Error to handle specific error codes.
// aerr, ok := err.(awserr.Error)
// if ok && aerr.Code() == <error code to check for> {
// // Specific error code handling
// }
// return err
// }
//
// fmt.Println("AbortMultipartUpload result:")
// fmt.Println(result)
//
// Using the Client with Context
//
// The service's client also provides methods to make API requests with a Context
// value. This allows you to control the timeout, and cancellation of pending
// requests. These methods also take request Option as variadic parameter to apply
// additional configuration to the API request.
//
// ctx := context.Background()
//
// result, err := svc.AbortMultipartUploadWithContext(ctx, params)
//
// See the request package documentation for more information on using Context pattern
// with the SDK.
// https://docs.aws.amazon.com/sdk-for-go/api/aws/request/
package s3
+2 -2
View File
@@ -35,7 +35,7 @@
//
// The s3manager package's Downloader provides concurrently downloading of Objects
// from S3. The Downloader will write S3 Object content with an io.WriterAt.
// Once the Downloader instance is created you can call Upload concurrently from
// Once the Downloader instance is created you can call Download concurrently from
// multiple goroutines safely.
//
// // The session the S3 Downloader will use
@@ -56,7 +56,7 @@
// Key: aws.String(myString),
// })
// if err != nil {
// return fmt.Errorf("failed to upload file, %v", err)
// return fmt.Errorf("failed to download file, %v", err)
// }
// fmt.Printf("file downloaded, %d bytes\n", n)
//

Some files were not shown because too many files have changed in this diff Show More