Merge branch 'master' into mssql_datasource
This commit is contained in:
-5
@@ -1,5 +0,0 @@
|
||||
TAGS
|
||||
tags
|
||||
.*.swp
|
||||
tomlcheck/tomlcheck
|
||||
toml.test
|
||||
-12
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
```
|
||||
|
||||
[](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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -1 +0,0 @@
|
||||
au BufWritePost *.go silent!make tags > /dev/null 2>&1
|
||||
+6
-5
@@ -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
@@ -1,20 +0,0 @@
|
||||
Common Functions
|
||||
================
|
||||
|
||||
[](https://travis-ci.org/Unknwon/com) [](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
@@ -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
@@ -1 +0,0 @@
|
||||
TestSaveFile
|
||||
-1
@@ -1 +0,0 @@
|
||||
TestSaveFileS
|
||||
-1
@@ -1 +0,0 @@
|
||||
TestSaveFile
|
||||
-1
@@ -1 +0,0 @@
|
||||
TestSaveFileS
|
||||
-1
@@ -1 +0,0 @@
|
||||
TestSaveFile
|
||||
-1
@@ -1 +0,0 @@
|
||||
TestSaveFileS
|
||||
+16
@@ -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
@@ -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
@@ -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
@@ -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
@@ -0,0 +1 @@
|
||||
server.sh
|
||||
-1536
File diff suppressed because it is too large
Load Diff
-5
@@ -1,5 +0,0 @@
|
||||
### SDK Features
|
||||
|
||||
### SDK Enhancements
|
||||
|
||||
### SDK Bugs
|
||||
-127
@@ -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
@@ -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
@@ -1,449 +0,0 @@
|
||||
[](http://docs.aws.amazon.com/sdk-for-go/api) [](https://gitter.im/aws/aws-sdk-go?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [](https://travis-ci.org/aws/aws-sdk-go) [](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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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 {
|
||||
|
||||
+331
-45
File diff suppressed because it is too large
Load Diff
+126
-22
@@ -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
@@ -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
@@ -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
@@ -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
@@ -1 +0,0 @@
|
||||
[profile_nam
|
||||
-17
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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())
|
||||
}
|
||||
-172
@@ -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
@@ -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
@@ -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
@@ -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()
|
||||
}
|
||||
Generated
Vendored
-28
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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()
|
||||
}
|
||||
-29
@@ -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
@@ -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(),
|
||||
)
|
||||
}
|
||||
-56
@@ -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)
|
||||
}
|
||||
-279
@@ -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
|
||||
}
|
||||
-213
@@ -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
@@ -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
@@ -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
|
||||
}
|
||||
+4
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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()
|
||||
}
|
||||
+305
-241
File diff suppressed because it is too large
Load Diff
-136
@@ -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
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
+8
-61
@@ -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
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
+6
-58
@@ -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
@@ -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
Reference in New Issue
Block a user