provider/fastly: Update go-fastly SDK (#7747)
* provider/fastly: Update go-fastly dependency * update test to check regression
This commit is contained in:
parent
4969e64132
commit
9d88ad1d08
|
@ -1566,7 +1566,7 @@ func buildHeader(headerMap interface{}) (*gofastly.CreateHeaderInput, error) {
|
|||
df := headerMap.(map[string]interface{})
|
||||
opts := gofastly.CreateHeaderInput{
|
||||
Name: df["name"].(string),
|
||||
IgnoreIfSet: df["ignore_if_set"].(bool),
|
||||
IgnoreIfSet: gofastly.Compatibool(df["ignore_if_set"].(bool)),
|
||||
Destination: df["destination"].(string),
|
||||
Priority: uint(df["priority"].(int)),
|
||||
Source: df["source"].(string),
|
||||
|
|
|
@ -181,10 +181,11 @@ resource "fastly_service_v1" "foo" {
|
|||
}
|
||||
|
||||
header {
|
||||
destination = "http.Server"
|
||||
type = "cache"
|
||||
action = "delete"
|
||||
name = "remove s3 server"
|
||||
destination = "http.Server"
|
||||
type = "cache"
|
||||
action = "delete"
|
||||
name = "remove s3 server"
|
||||
ignore_if_set = "true"
|
||||
}
|
||||
|
||||
force_destroy = true
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
## Copyright 2014 Alvaro J. Genial. All rights reserved.
|
||||
## Use of this source code is governed by a BSD-style
|
||||
## license that can be found in the LICENSE file.
|
||||
|
||||
language: go
|
||||
|
||||
go:
|
||||
- tip
|
||||
- 1.3
|
||||
# - 1.2
|
||||
# Note: 1.2 is disabled because it seems to require that cover
|
||||
# be installed from code.google.com/p/go.tools/cmd/cover
|
||||
|
||||
before_install:
|
||||
- go get -v golang.org/x/tools/cmd/cover
|
||||
- go get -v golang.org/x/tools/cmd/vet
|
||||
- go get -v github.com/golang/lint/golint
|
||||
- export PATH=$PATH:/home/travis/gopath/bin
|
||||
|
||||
script:
|
||||
- go build -v ./...
|
||||
- go test -v -cover ./...
|
||||
- go vet ./...
|
||||
- golint .
|
|
@ -171,10 +171,47 @@ Now any value with type `Binary` will automatically be encoded using the [URL](h
|
|||
Keys
|
||||
----
|
||||
|
||||
In theory any value can be a key as long as it has a string representation. However, periods have special meaning to `form`, and thus, under the hood (i.e. in encoded form) they are transparently escaped using a preceding backslash (`\`). Backslashes within keys, themselves, are also escaped in this manner (e.g. as `\\`) in order to permit representing `\.` itself (as `\\\.`).
|
||||
In theory any value can be a key as long as it has a string representation. However, by default, periods have special meaning to `form`, and thus, under the hood (i.e. in encoded form) they are transparently escaped using a preceding backslash (`\`). Backslashes within keys, themselves, are also escaped in this manner (e.g. as `\\`) in order to permit representing `\.` itself (as `\\\.`).
|
||||
|
||||
(Note: it is normally unnecessary to deal with this issue unless keys are being constructed manually—e.g. literally embedded in HTML or in a URI.)
|
||||
|
||||
The default delimiter and escape characters used for encoding and decoding composite keys can be changed using the `DelimitWith` and `EscapeWith` setter methods of `Encoder` and `Decoder`, respectively. For example...
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/ajg/form"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type B struct {
|
||||
Qux string `form:"qux"`
|
||||
}
|
||||
type A struct {
|
||||
FooBar B `form:"foo.bar"`
|
||||
}
|
||||
a := A{FooBar: B{"XYZ"}}
|
||||
os.Stdout.WriteString("Default: ")
|
||||
form.NewEncoder(os.Stdout).Encode(a)
|
||||
os.Stdout.WriteString("\nCustom: ")
|
||||
form.NewEncoder(os.Stdout).DelimitWith('/').Encode(a)
|
||||
os.Stdout.WriteString("\n")
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
...will produce...
|
||||
|
||||
```
|
||||
Default: foo%5C.bar.qux=XYZ
|
||||
Custom: foo.bar%2Fqux=XYZ
|
||||
```
|
||||
|
||||
(`%5C` and `%2F` represent `\` and `/`, respectively.)
|
||||
|
||||
Limitations
|
||||
-----------
|
||||
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
TODO
|
||||
====
|
||||
|
||||
- Document IgnoreCase and IgnoreUnknownKeys in README.
|
||||
- Fix want/have newlines in tests.
|
|
@ -16,12 +16,28 @@ import (
|
|||
|
||||
// NewDecoder returns a new form decoder.
|
||||
func NewDecoder(r io.Reader) *decoder {
|
||||
return &decoder{r}
|
||||
return &decoder{r, defaultDelimiter, defaultEscape, false, false}
|
||||
}
|
||||
|
||||
// decoder decodes data from a form (application/x-www-form-urlencoded).
|
||||
type decoder struct {
|
||||
r io.Reader
|
||||
r io.Reader
|
||||
d rune
|
||||
e rune
|
||||
ignoreUnknown bool
|
||||
ignoreCase bool
|
||||
}
|
||||
|
||||
// DelimitWith sets r as the delimiter used for composite keys by decoder d and returns the latter; it is '.' by default.
|
||||
func (d *decoder) DelimitWith(r rune) *decoder {
|
||||
d.d = r
|
||||
return d
|
||||
}
|
||||
|
||||
// EscapeWith sets r as the escape used for delimiters (and to escape itself) by decoder d and returns the latter; it is '\\' by default.
|
||||
func (d *decoder) EscapeWith(r rune) *decoder {
|
||||
d.e = r
|
||||
return d
|
||||
}
|
||||
|
||||
// Decode reads in and decodes form-encoded data into dst.
|
||||
|
@ -35,26 +51,48 @@ func (d decoder) Decode(dst interface{}) error {
|
|||
return err
|
||||
}
|
||||
v := reflect.ValueOf(dst)
|
||||
return decodeNode(v, parseValues(vs, canIndexOrdinally(v)))
|
||||
return d.decodeNode(v, parseValues(d.d, d.e, vs, canIndexOrdinally(v)))
|
||||
}
|
||||
|
||||
// IgnoreUnknownKeys if set to true it will make the decoder ignore values
|
||||
// that are not found in the destination object instead of returning an error.
|
||||
func (d *decoder) IgnoreUnknownKeys(ignoreUnknown bool) {
|
||||
d.ignoreUnknown = ignoreUnknown
|
||||
}
|
||||
|
||||
// IgnoreCase if set to true it will make the decoder try to set values in the
|
||||
// destination object even if the case does not match.
|
||||
func (d *decoder) IgnoreCase(ignoreCase bool) {
|
||||
d.ignoreCase = ignoreCase
|
||||
}
|
||||
|
||||
// DecodeString decodes src into dst.
|
||||
func DecodeString(dst interface{}, src string) error {
|
||||
func (d decoder) DecodeString(dst interface{}, src string) error {
|
||||
vs, err := url.ParseQuery(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
v := reflect.ValueOf(dst)
|
||||
return decodeNode(v, parseValues(vs, canIndexOrdinally(v)))
|
||||
return d.decodeNode(v, parseValues(d.d, d.e, vs, canIndexOrdinally(v)))
|
||||
}
|
||||
|
||||
// DecodeValues decodes vs into dst.
|
||||
func (d decoder) DecodeValues(dst interface{}, vs url.Values) error {
|
||||
v := reflect.ValueOf(dst)
|
||||
return d.decodeNode(v, parseValues(d.d, d.e, vs, canIndexOrdinally(v)))
|
||||
}
|
||||
|
||||
// DecodeString decodes src into dst.
|
||||
func DecodeString(dst interface{}, src string) error {
|
||||
return NewDecoder(nil).DecodeString(dst, src)
|
||||
}
|
||||
|
||||
// DecodeValues decodes vs into dst.
|
||||
func DecodeValues(dst interface{}, vs url.Values) error {
|
||||
v := reflect.ValueOf(dst)
|
||||
return decodeNode(v, parseValues(vs, canIndexOrdinally(v)))
|
||||
return NewDecoder(nil).DecodeValues(dst, vs)
|
||||
}
|
||||
|
||||
func decodeNode(v reflect.Value, n node) (err error) {
|
||||
func (d decoder) decodeNode(v reflect.Value, n node) (err error) {
|
||||
defer func() {
|
||||
if e := recover(); e != nil {
|
||||
err = fmt.Errorf("%v", e)
|
||||
|
@ -64,11 +102,11 @@ func decodeNode(v reflect.Value, n node) (err error) {
|
|||
if v.Kind() == reflect.Slice {
|
||||
return fmt.Errorf("could not decode directly into slice; use pointer to slice")
|
||||
}
|
||||
decodeValue(v, n)
|
||||
d.decodeValue(v, n)
|
||||
return nil
|
||||
}
|
||||
|
||||
func decodeValue(v reflect.Value, x interface{}) {
|
||||
func (d decoder) decodeValue(v reflect.Value, x interface{}) {
|
||||
t := v.Type()
|
||||
k := v.Kind()
|
||||
|
||||
|
@ -84,11 +122,11 @@ func decodeValue(v reflect.Value, x interface{}) {
|
|||
|
||||
switch k {
|
||||
case reflect.Ptr:
|
||||
decodeValue(v.Elem(), x)
|
||||
d.decodeValue(v.Elem(), x)
|
||||
return
|
||||
case reflect.Interface:
|
||||
if !v.IsNil() {
|
||||
decodeValue(v.Elem(), x)
|
||||
d.decodeValue(v.Elem(), x)
|
||||
return
|
||||
|
||||
} else if empty {
|
||||
|
@ -106,48 +144,50 @@ func decodeValue(v reflect.Value, x interface{}) {
|
|||
switch k {
|
||||
case reflect.Struct:
|
||||
if t.ConvertibleTo(timeType) {
|
||||
decodeTime(v, x)
|
||||
d.decodeTime(v, x)
|
||||
} else if t.ConvertibleTo(urlType) {
|
||||
decodeURL(v, x)
|
||||
d.decodeURL(v, x)
|
||||
} else {
|
||||
decodeStruct(v, x)
|
||||
d.decodeStruct(v, x)
|
||||
}
|
||||
case reflect.Slice:
|
||||
decodeSlice(v, x)
|
||||
d.decodeSlice(v, x)
|
||||
case reflect.Array:
|
||||
decodeArray(v, x)
|
||||
d.decodeArray(v, x)
|
||||
case reflect.Map:
|
||||
decodeMap(v, x)
|
||||
d.decodeMap(v, x)
|
||||
case reflect.Invalid, reflect.Uintptr, reflect.UnsafePointer, reflect.Chan, reflect.Func:
|
||||
panic(t.String() + " has unsupported kind " + k.String())
|
||||
default:
|
||||
decodeBasic(v, x)
|
||||
d.decodeBasic(v, x)
|
||||
}
|
||||
}
|
||||
|
||||
func decodeStruct(v reflect.Value, x interface{}) {
|
||||
func (d decoder) decodeStruct(v reflect.Value, x interface{}) {
|
||||
t := v.Type()
|
||||
for k, c := range getNode(x) {
|
||||
if f, ok := findField(v, k); !ok && k == "" {
|
||||
if f, ok := findField(v, k, d.ignoreCase); !ok && k == "" {
|
||||
panic(getString(x) + " cannot be decoded as " + t.String())
|
||||
} else if !ok {
|
||||
panic(k + " doesn't exist in " + t.String())
|
||||
if !d.ignoreUnknown {
|
||||
panic(k + " doesn't exist in " + t.String())
|
||||
}
|
||||
} else if !f.CanSet() {
|
||||
panic(k + " cannot be set in " + t.String())
|
||||
} else {
|
||||
decodeValue(f, c)
|
||||
d.decodeValue(f, c)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func decodeMap(v reflect.Value, x interface{}) {
|
||||
func (d decoder) decodeMap(v reflect.Value, x interface{}) {
|
||||
t := v.Type()
|
||||
if v.IsNil() {
|
||||
v.Set(reflect.MakeMap(t))
|
||||
}
|
||||
for k, c := range getNode(x) {
|
||||
i := reflect.New(t.Key()).Elem()
|
||||
decodeValue(i, k)
|
||||
d.decodeValue(i, k)
|
||||
|
||||
w := v.MapIndex(i)
|
||||
if w.IsValid() { // We have an actual element value to decode into.
|
||||
|
@ -171,12 +211,12 @@ func decodeMap(v reflect.Value, x interface{}) {
|
|||
}
|
||||
}
|
||||
|
||||
decodeValue(w, c)
|
||||
d.decodeValue(w, c)
|
||||
v.SetMapIndex(i, w)
|
||||
}
|
||||
}
|
||||
|
||||
func decodeArray(v reflect.Value, x interface{}) {
|
||||
func (d decoder) decodeArray(v reflect.Value, x interface{}) {
|
||||
t := v.Type()
|
||||
for k, c := range getNode(x) {
|
||||
i, err := strconv.Atoi(k)
|
||||
|
@ -186,11 +226,11 @@ func decodeArray(v reflect.Value, x interface{}) {
|
|||
if l := v.Len(); i >= l {
|
||||
panic("index is above array size")
|
||||
}
|
||||
decodeValue(v.Index(i), c)
|
||||
d.decodeValue(v.Index(i), c)
|
||||
}
|
||||
}
|
||||
|
||||
func decodeSlice(v reflect.Value, x interface{}) {
|
||||
func (d decoder) decodeSlice(v reflect.Value, x interface{}) {
|
||||
t := v.Type()
|
||||
if t.Elem().Kind() == reflect.Uint8 {
|
||||
// Allow, but don't require, byte slices to be encoded as a single string.
|
||||
|
@ -221,11 +261,11 @@ func decodeSlice(v reflect.Value, x interface{}) {
|
|||
delta := i - l + 1
|
||||
v.Set(reflect.AppendSlice(v, reflect.MakeSlice(t, delta, delta)))
|
||||
}
|
||||
decodeValue(v.Index(i), c)
|
||||
d.decodeValue(v.Index(i), c)
|
||||
}
|
||||
}
|
||||
|
||||
func decodeBasic(v reflect.Value, x interface{}) {
|
||||
func (d decoder) decodeBasic(v reflect.Value, x interface{}) {
|
||||
t := v.Type()
|
||||
switch k, s := t.Kind(), getString(x); k {
|
||||
case reflect.Bool:
|
||||
|
@ -276,7 +316,7 @@ func decodeBasic(v reflect.Value, x interface{}) {
|
|||
}
|
||||
}
|
||||
|
||||
func decodeTime(v reflect.Value, x interface{}) {
|
||||
func (d decoder) decodeTime(v reflect.Value, x interface{}) {
|
||||
t := v.Type()
|
||||
s := getString(x)
|
||||
// TODO: Find a more efficient way to do this.
|
||||
|
@ -289,7 +329,7 @@ func decodeTime(v reflect.Value, x interface{}) {
|
|||
panic("cannot decode string `" + s + "` as " + t.String())
|
||||
}
|
||||
|
||||
func decodeURL(v reflect.Value, x interface{}) {
|
||||
func (d decoder) decodeURL(v reflect.Value, x interface{}) {
|
||||
t := v.Type()
|
||||
s := getString(x)
|
||||
if u, err := url.Parse(s); err == nil {
|
||||
|
|
|
@ -18,12 +18,26 @@ import (
|
|||
|
||||
// NewEncoder returns a new form encoder.
|
||||
func NewEncoder(w io.Writer) *encoder {
|
||||
return &encoder{w}
|
||||
return &encoder{w, defaultDelimiter, defaultEscape}
|
||||
}
|
||||
|
||||
// encoder provides a way to encode to a Writer.
|
||||
type encoder struct {
|
||||
w io.Writer
|
||||
d rune
|
||||
e rune
|
||||
}
|
||||
|
||||
// DelimitWith sets r as the delimiter used for composite keys by encoder e and returns the latter; it is '.' by default.
|
||||
func (e *encoder) DelimitWith(r rune) *encoder {
|
||||
e.d = r
|
||||
return e
|
||||
}
|
||||
|
||||
// EscapeWith sets r as the escape used for delimiters (and to escape itself) by encoder e and returns the latter; it is '\\' by default.
|
||||
func (e *encoder) EscapeWith(r rune) *encoder {
|
||||
e.e = r
|
||||
return e
|
||||
}
|
||||
|
||||
// Encode encodes dst as form and writes it out using the encoder's Writer.
|
||||
|
@ -33,7 +47,7 @@ func (e encoder) Encode(dst interface{}) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s := n.Values().Encode()
|
||||
s := n.values(e.d, e.e).Encode()
|
||||
l, err := io.WriteString(e.w, s)
|
||||
switch {
|
||||
case err != nil:
|
||||
|
@ -51,7 +65,8 @@ func EncodeToString(dst interface{}) (string, error) {
|
|||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return n.Values().Encode(), nil
|
||||
vs := n.values(defaultDelimiter, defaultEscape)
|
||||
return vs.Encode(), nil
|
||||
}
|
||||
|
||||
// EncodeToValues encodes dst as a form and returns it as Values.
|
||||
|
@ -61,7 +76,8 @@ func EncodeToValues(dst interface{}) (url.Values, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return n.Values(), nil
|
||||
vs := n.values(defaultDelimiter, defaultEscape)
|
||||
return vs, nil
|
||||
}
|
||||
|
||||
func encodeToNode(v reflect.Value) (n node, err error) {
|
||||
|
@ -258,9 +274,16 @@ func fieldInfo(f reflect.StructField) (k string, oe bool) {
|
|||
return k, oe
|
||||
}
|
||||
|
||||
func findField(v reflect.Value, n string) (reflect.Value, bool) {
|
||||
func findField(v reflect.Value, n string, ignoreCase bool) (reflect.Value, bool) {
|
||||
t := v.Type()
|
||||
l := v.NumField()
|
||||
|
||||
var lowerN string
|
||||
caseInsensitiveMatch := -1
|
||||
if ignoreCase {
|
||||
lowerN = strings.ToLower(n)
|
||||
}
|
||||
|
||||
// First try named fields.
|
||||
for i := 0; i < l; i++ {
|
||||
f := t.Field(i)
|
||||
|
@ -269,9 +292,16 @@ func findField(v reflect.Value, n string) (reflect.Value, bool) {
|
|||
continue
|
||||
} else if n == k {
|
||||
return v.Field(i), true
|
||||
} else if ignoreCase && lowerN == strings.ToLower(k) {
|
||||
caseInsensitiveMatch = i
|
||||
}
|
||||
}
|
||||
|
||||
// If no exact match was found try case insensitive match.
|
||||
if caseInsensitiveMatch != -1 {
|
||||
return v.Field(caseInsensitiveMatch), true
|
||||
}
|
||||
|
||||
// Then try anonymous (embedded) fields.
|
||||
for i := 0; i < l; i++ {
|
||||
f := t.Field(i)
|
||||
|
@ -289,7 +319,7 @@ func findField(v reflect.Value, n string) (reflect.Value, bool) {
|
|||
if fk != reflect.Struct {
|
||||
continue
|
||||
}
|
||||
if ev, ok := findField(fv, n); ok {
|
||||
if ev, ok := findField(fv, n, ignoreCase); ok {
|
||||
return ev, true
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,4 +8,7 @@ package form
|
|||
const (
|
||||
implicitKey = "_"
|
||||
omittedKey = "-"
|
||||
|
||||
defaultDelimiter = '.'
|
||||
defaultEscape = '\\'
|
||||
)
|
||||
|
|
|
@ -12,19 +12,19 @@ import (
|
|||
|
||||
type node map[string]interface{}
|
||||
|
||||
func (n node) Values() url.Values {
|
||||
func (n node) values(d, e rune) url.Values {
|
||||
vs := url.Values{}
|
||||
n.merge("", &vs)
|
||||
n.merge(d, e, "", &vs)
|
||||
return vs
|
||||
}
|
||||
|
||||
func (n node) merge(p string, vs *url.Values) {
|
||||
func (n node) merge(d, e rune, p string, vs *url.Values) {
|
||||
for k, x := range n {
|
||||
switch y := x.(type) {
|
||||
case string:
|
||||
vs.Add(p+escape(k), y)
|
||||
vs.Add(p+escape(d, e, k), y)
|
||||
case node:
|
||||
y.merge(p+escape(k)+".", vs)
|
||||
y.merge(d, e, p+escape(d, e, k)+string(d), vs)
|
||||
default:
|
||||
panic("value is neither string nor node")
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ func (n node) merge(p string, vs *url.Values) {
|
|||
}
|
||||
|
||||
// TODO: Add tests for implicit indexing.
|
||||
func parseValues(vs url.Values, canIndexFirstLevelOrdinally bool) node {
|
||||
func parseValues(d, e rune, vs url.Values, canIndexFirstLevelOrdinally bool) node {
|
||||
// NOTE: Because of the flattening of potentially multiple strings to one key, implicit indexing works:
|
||||
// i. At the first level; e.g. Foo.Bar=A&Foo.Bar=B becomes 0.Foo.Bar=A&1.Foo.Bar=B
|
||||
// ii. At the last level; e.g. Foo.Bar._=A&Foo.Bar._=B becomes Foo.Bar.0=A&Foo.Bar.1=B
|
||||
|
@ -41,11 +41,11 @@ func parseValues(vs url.Values, canIndexFirstLevelOrdinally bool) node {
|
|||
|
||||
m := map[string]string{}
|
||||
for k, ss := range vs {
|
||||
indexLastLevelOrdinally := strings.HasSuffix(k, "."+implicitKey)
|
||||
indexLastLevelOrdinally := strings.HasSuffix(k, string(d)+implicitKey)
|
||||
|
||||
for i, s := range ss {
|
||||
if canIndexFirstLevelOrdinally {
|
||||
k = strconv.Itoa(i) + "." + k
|
||||
k = strconv.Itoa(i) + string(d) + k
|
||||
} else if indexLastLevelOrdinally {
|
||||
k = strings.TrimSuffix(k, implicitKey) + strconv.Itoa(i)
|
||||
}
|
||||
|
@ -56,28 +56,28 @@ func parseValues(vs url.Values, canIndexFirstLevelOrdinally bool) node {
|
|||
|
||||
n := node{}
|
||||
for k, s := range m {
|
||||
n = n.split(k, s)
|
||||
n = n.split(d, e, k, s)
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func splitPath(path string) (k, rest string) {
|
||||
func splitPath(d, e rune, path string) (k, rest string) {
|
||||
esc := false
|
||||
for i, r := range path {
|
||||
switch {
|
||||
case !esc && r == '\\':
|
||||
case !esc && r == e:
|
||||
esc = true
|
||||
case !esc && r == '.':
|
||||
return unescape(path[:i]), path[i+1:]
|
||||
case !esc && r == d:
|
||||
return unescape(d, e, path[:i]), path[i+1:]
|
||||
default:
|
||||
esc = false
|
||||
}
|
||||
}
|
||||
return unescape(path), ""
|
||||
return unescape(d, e, path), ""
|
||||
}
|
||||
|
||||
func (n node) split(path, s string) node {
|
||||
k, rest := splitPath(path)
|
||||
func (n node) split(d, e rune, path, s string) node {
|
||||
k, rest := splitPath(d, e, path)
|
||||
if rest == "" {
|
||||
return add(n, k, s)
|
||||
}
|
||||
|
@ -86,7 +86,7 @@ func (n node) split(path, s string) node {
|
|||
}
|
||||
|
||||
c := getNode(n[k])
|
||||
n[k] = c.split(rest, s)
|
||||
n[k] = c.split(d, e, rest, s)
|
||||
return n
|
||||
}
|
||||
|
||||
|
@ -139,10 +139,14 @@ func getString(x interface{}) string {
|
|||
panic("value is neither string nor node")
|
||||
}
|
||||
|
||||
func escape(s string) string {
|
||||
return strings.Replace(strings.Replace(s, `\`, `\\`, -1), `.`, `\.`, -1)
|
||||
func escape(d, e rune, s string) string {
|
||||
s = strings.Replace(s, string(e), string(e)+string(e), -1) // Escape the escape (\ => \\)
|
||||
s = strings.Replace(s, string(d), string(e)+string(d), -1) // Escape the delimiter (. => \.)
|
||||
return s
|
||||
}
|
||||
|
||||
func unescape(s string) string {
|
||||
return strings.Replace(strings.Replace(s, `\.`, `.`, -1), `\\`, `\`, -1)
|
||||
func unescape(d, e rune, s string) string {
|
||||
s = strings.Replace(s, string(e)+string(d), string(d), -1) // Unescape the delimiter (\. => .)
|
||||
s = strings.Replace(s, string(e)+string(e), string(e), -1) // Unescape the escape (\\ => \)
|
||||
return s
|
||||
}
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
### Go ###
|
||||
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
|
||||
# Folders
|
||||
_obj
|
||||
_test
|
||||
|
||||
# Architecture specific extensions/prefixes
|
||||
*.[568vq]
|
||||
[568vq].out
|
||||
|
||||
*.cgo1.go
|
||||
*.cgo2.c
|
||||
_cgo_defun.c
|
||||
_cgo_gotypes.go
|
||||
_cgo_export.*
|
||||
|
||||
_testmain.go
|
||||
|
||||
*.exe
|
||||
*.test
|
||||
*.prof
|
||||
|
||||
bin/
|
||||
pkg/
|
|
@ -1,19 +0,0 @@
|
|||
sudo: false
|
||||
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.4.2
|
||||
- 1.5.2
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
|
||||
script:
|
||||
- make updatedeps
|
||||
- make test
|
||||
|
||||
env:
|
||||
# FASTLY_API_KEY
|
||||
- secure: "eiYcogJFF+lK/6coFXaOOm0bDHxaK1qqZ0GinMmPXmQ6nonf56omMVxNyOsV+6jz/fdJCA7gfGv600raTAOVNxD23E/p2j6yxPSI5O6itxp0jxJm7p6MOHwkmsXFZGfLxaqVN2CHs+W3sSc4cwzCkCqlik4XLXihHvzYpjBk1AZK6QUMWqdTcDYDWMfk5CW1O6wUpmYiFwlnENwDopGQlSs1+PyEiDEbEMYu1yVUq+f83IJ176arM4XL8NS2GN1QMBKyALA+6jpT/OrFtW5tkheE+WOQ6+/ZnDCtY0i1RA8BBuyACYuf+WEAkmWfJGGk7+Ou6q2JFzIBsd6ZS3EsM4bs4P1FyhPBwK5zyFty2w7+PwVm6wrZ0NfUh6BKsfCF9MweypsKq+F+4GOcpjdCYPKZKGRjQ4iKOZVVzaVGLRanz1EHiXUcLT+DDr0kFbvrLCLqCPvujBfqeUDqVZMpsUqir9HWqVKutczAnYzFaoeeSVap14J/sd6kcgZo2bNMSRQvMoPCOvicdW8RLIV8Hyx2l0Cv596ZfinWBk2Dcmn6APLkbrBpvhv6/SUtBKHMijjFc5VvoxO3ZP6vUCueDaZVNWkX1xk+VA5PD0T/IcilLy3+nBedz+3lmiW7dnQPuWnlPBFPWvYZvW2KaDOazv5rZK+pKIq32BIyhP/n/AU="
|
|
@ -1,21 +1,42 @@
|
|||
TEST?=./...
|
||||
NAME?=$(shell basename "${CURDIR}")
|
||||
EXTERNAL_TOOLS=\
|
||||
github.com/mitchellh/gox
|
||||
|
||||
default: test
|
||||
|
||||
# test runs the test suite and vets the code
|
||||
# test runs the test suite and vets the code.
|
||||
test: generate
|
||||
go list $(TEST) | xargs -n1 go test -timeout=30s -parallel=12 $(TESTARGS)
|
||||
@echo "==> Running tests..."
|
||||
@go list $(TEST) \
|
||||
| grep -v "github.com/sethvargo/${NAME}/vendor" \
|
||||
| xargs -n1 go test -timeout=60s -parallel=10 ${TESTARGS}
|
||||
|
||||
# updatedeps installs all the dependencies the library needs to run and build
|
||||
# testrace runs the race checker
|
||||
testrace: generate
|
||||
@echo "==> Running tests (race)..."
|
||||
@go list $(TEST) \
|
||||
| grep -v "github.com/sethvargo/${NAME}/vendor" \
|
||||
| xargs -n1 go test -timeout=60s -race ${TESTARGS}
|
||||
|
||||
# updatedeps installs all the dependencies needed to run and build.
|
||||
updatedeps:
|
||||
go list ./... \
|
||||
| xargs go list -f '{{ join .Deps "\n" }}{{ printf "\n" }}{{ join .TestImports "\n" }}' \
|
||||
| grep -v github.com/sethvargo/go-fastly \
|
||||
| xargs go get -f -u -v
|
||||
@sh -c "'${CURDIR}/scripts/deps.sh' '${NAME}'"
|
||||
|
||||
# generate runs `go generate` to build the dynamically generated source files
|
||||
# generate runs `go generate` to build the dynamically generated source files.
|
||||
generate:
|
||||
find . -type f -name '.DS_Store' -delete
|
||||
go generate ./...
|
||||
@echo "==> Generating..."
|
||||
@find . -type f -name '.DS_Store' -delete
|
||||
@go list ./... \
|
||||
| grep -v "github.com/hashicorp/${NAME}/vendor" \
|
||||
| xargs -n1 go generate
|
||||
|
||||
.PHONY: default bin dev dist test testrace updatedeps generate
|
||||
# bootstrap installs the necessary go tools for development/build.
|
||||
bootstrap:
|
||||
@echo "==> Bootstrapping..."
|
||||
@for t in ${EXTERNAL_TOOLS}; do \
|
||||
echo "--> Installing "$$t"..." ; \
|
||||
go get -u "$$t"; \
|
||||
done
|
||||
|
||||
.PHONY: default test testrace updatedeps generate bootstrap
|
||||
|
|
|
@ -164,7 +164,7 @@ type UpdateCacheSettingInput struct {
|
|||
NewName string `form:"name,omitempty"`
|
||||
Action CacheSettingAction `form:"action,omitempty"`
|
||||
TTL uint `form:"ttl,omitempty"`
|
||||
StateTTL uint `form:"stale_ttl,omitempty"`
|
||||
StaleTTL uint `form:"stale_ttl,omitempty"`
|
||||
CacheCondition string `form:"cache_condition,omitempty"`
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package fastly
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
|
@ -144,11 +145,6 @@ func (c *Client) Request(verb, p string, ro *RequestOptions) (*http.Response, er
|
|||
// RequestForm makes an HTTP request with the given interface being encoded as
|
||||
// form data.
|
||||
func (c *Client) RequestForm(verb, p string, i interface{}, ro *RequestOptions) (*http.Response, error) {
|
||||
values, err := form.EncodeToValues(i)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if ro == nil {
|
||||
ro = new(RequestOptions)
|
||||
}
|
||||
|
@ -158,10 +154,11 @@ func (c *Client) RequestForm(verb, p string, i interface{}, ro *RequestOptions)
|
|||
}
|
||||
ro.Headers["Content-Type"] = "application/x-www-form-urlencoded"
|
||||
|
||||
// There is a super-jank implementation in the form library where fields with
|
||||
// a "dot" are replaced with "/.". That is then URL encoded and Fastly just
|
||||
// dies. We fix that here.
|
||||
body := strings.Replace(values.Encode(), "%5C.", ".", -1)
|
||||
buf := new(bytes.Buffer)
|
||||
if err := form.NewEncoder(buf).DelimitWith('|').Encode(i); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
body := buf.String()
|
||||
|
||||
ro.Body = strings.NewReader(body)
|
||||
ro.BodyLength = int64(len(body))
|
||||
|
|
|
@ -79,12 +79,12 @@ type HTTPError struct {
|
|||
|
||||
// NewHTTPError creates a new HTTP error from the given code.
|
||||
func NewHTTPError(resp *http.Response) *HTTPError {
|
||||
var e *HTTPError
|
||||
var e HTTPError
|
||||
if resp.Body != nil {
|
||||
decodeJSON(&e, resp.Body)
|
||||
}
|
||||
e.StatusCode = resp.StatusCode
|
||||
return e
|
||||
return &e
|
||||
}
|
||||
|
||||
// Error implements the error interface and returns the string representing the
|
||||
|
|
|
@ -33,9 +33,9 @@ func (b Compatibool) MarshalText() ([]byte, error) {
|
|||
}
|
||||
|
||||
// UnmarshalText implements the encoding.TextUnmarshaler interface.
|
||||
func (b Compatibool) UnmarshalText(t []byte) error {
|
||||
func (b *Compatibool) UnmarshalText(t []byte) error {
|
||||
if bytes.Equal(t, []byte("1")) {
|
||||
b = Compatibool(true)
|
||||
*b = Compatibool(true)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -119,7 +119,7 @@ type CreateHeaderInput struct {
|
|||
|
||||
Name string `form:"name,omitempty"`
|
||||
Action HeaderAction `form:"action,omitempty"`
|
||||
IgnoreIfSet bool `form:"ignore_if_set,omitempty"`
|
||||
IgnoreIfSet Compatibool `form:"ignore_if_set,omitempty"`
|
||||
Type HeaderType `form:"type,omitempty"`
|
||||
Destination string `form:"dst,omitempty"`
|
||||
Source string `form:"src,omitempty"`
|
||||
|
@ -204,7 +204,7 @@ type UpdateHeaderInput struct {
|
|||
|
||||
NewName string `form:"name,omitempty"`
|
||||
Action HeaderAction `form:"action,omitempty"`
|
||||
IgnoreIfSet bool `form:"ignore_if_set,omitempty"`
|
||||
IgnoreIfSet Compatibool `form:"ignore_if_set,omitempty"`
|
||||
Type HeaderType `form:"type,omitempty"`
|
||||
Destination string `form:"dst,omitempty"`
|
||||
Source string `form:"src,omitempty"`
|
||||
|
|
|
@ -6,25 +6,33 @@ import (
|
|||
"time"
|
||||
)
|
||||
|
||||
type S3Redundancy string
|
||||
|
||||
const (
|
||||
S3RedundancyStandard S3Redundancy = "standard"
|
||||
S3RedundancyReduced S3Redundancy = "reduced_redundancy"
|
||||
)
|
||||
|
||||
// S3 represents a S3 response from the Fastly API.
|
||||
type S3 struct {
|
||||
ServiceID string `mapstructure:"service_id"`
|
||||
Version string `mapstructure:"version"`
|
||||
|
||||
Name string `mapstructure:"name"`
|
||||
BucketName string `mapstructure:"bucket_name"`
|
||||
Domain string `mapstructure:"domain"`
|
||||
AccessKey string `mapstructure:"access_key"`
|
||||
SecretKey string `mapstructure:"secret_key"`
|
||||
Path string `mapstructure:"path"`
|
||||
Period uint `mapstructure:"period"`
|
||||
GzipLevel uint `mapstructure:"gzip_level"`
|
||||
Format string `mapstructure:"format"`
|
||||
ResponseCondition string `mapstructure:"response_condition"`
|
||||
TimestampFormat string `mapstructure:"timestamp_format"`
|
||||
CreatedAt *time.Time `mapstructure:"created_at"`
|
||||
UpdatedAt *time.Time `mapstructure:"updated_at"`
|
||||
DeletedAt *time.Time `mapstructure:"deleted_at"`
|
||||
Name string `mapstructure:"name"`
|
||||
BucketName string `mapstructure:"bucket_name"`
|
||||
Domain string `mapstructure:"domain"`
|
||||
AccessKey string `mapstructure:"access_key"`
|
||||
SecretKey string `mapstructure:"secret_key"`
|
||||
Path string `mapstructure:"path"`
|
||||
Period uint `mapstructure:"period"`
|
||||
GzipLevel uint `mapstructure:"gzip_level"`
|
||||
Format string `mapstructure:"format"`
|
||||
ResponseCondition string `mapstructure:"response_condition"`
|
||||
TimestampFormat string `mapstructure:"timestamp_format"`
|
||||
Redundancy S3Redundancy `mapstructure:"redundancy"`
|
||||
CreatedAt *time.Time `mapstructure:"created_at"`
|
||||
UpdatedAt *time.Time `mapstructure:"updated_at"`
|
||||
DeletedAt *time.Time `mapstructure:"deleted_at"`
|
||||
}
|
||||
|
||||
// s3sByName is a sortable list of S3s.
|
||||
|
@ -77,17 +85,18 @@ type CreateS3Input struct {
|
|||
Service string
|
||||
Version string
|
||||
|
||||
Name string `form:"name,omitempty"`
|
||||
BucketName string `form:"bucket_name,omitempty"`
|
||||
Domain string `form:"domain,omitempty"`
|
||||
AccessKey string `form:"access_key,omitempty"`
|
||||
SecretKey string `form:"secret_key,omitempty"`
|
||||
Path string `form:"path,omitempty"`
|
||||
Period uint `form:"period,omitempty"`
|
||||
GzipLevel uint `form:"gzip_level,omitempty"`
|
||||
Format string `form:"format,omitempty"`
|
||||
ResponseCondition string `form:"response_condition,omitempty"`
|
||||
TimestampFormat string `form:"timestamp_format,omitempty"`
|
||||
Name string `form:"name,omitempty"`
|
||||
BucketName string `form:"bucket_name,omitempty"`
|
||||
Domain string `form:"domain,omitempty"`
|
||||
AccessKey string `form:"access_key,omitempty"`
|
||||
SecretKey string `form:"secret_key,omitempty"`
|
||||
Path string `form:"path,omitempty"`
|
||||
Period uint `form:"period,omitempty"`
|
||||
GzipLevel uint `form:"gzip_level,omitempty"`
|
||||
Format string `form:"format,omitempty"`
|
||||
ResponseCondition string `form:"response_condition,omitempty"`
|
||||
TimestampFormat string `form:"timestamp_format,omitempty"`
|
||||
Redundancy S3Redundancy `form:"redundancy,omitempty"`
|
||||
}
|
||||
|
||||
// CreateS3 creates a new Fastly S3.
|
||||
|
@ -161,17 +170,18 @@ type UpdateS3Input struct {
|
|||
// Name is the name of the S3 to update.
|
||||
Name string
|
||||
|
||||
NewName string `form:"name,omitempty"`
|
||||
BucketName string `form:"bucket_name,omitempty"`
|
||||
Domain string `form:"domain,omitempty"`
|
||||
AccessKey string `form:"access_key,omitempty"`
|
||||
SecretKey string `form:"secret_key,omitempty"`
|
||||
Path string `form:"path,omitempty"`
|
||||
Period uint `form:"period,omitempty"`
|
||||
GzipLevel uint `form:"gzip_level,omitempty"`
|
||||
Format string `form:"format,omitempty"`
|
||||
ResponseCondition string `form:"response_condition,omitempty"`
|
||||
TimestampFormat string `form:"timestamp_format,omitempty"`
|
||||
NewName string `form:"name,omitempty"`
|
||||
BucketName string `form:"bucket_name,omitempty"`
|
||||
Domain string `form:"domain,omitempty"`
|
||||
AccessKey string `form:"access_key,omitempty"`
|
||||
SecretKey string `form:"secret_key,omitempty"`
|
||||
Path string `form:"path,omitempty"`
|
||||
Period uint `form:"period,omitempty"`
|
||||
GzipLevel uint `form:"gzip_level,omitempty"`
|
||||
Format string `form:"format,omitempty"`
|
||||
ResponseCondition string `form:"response_condition,omitempty"`
|
||||
TimestampFormat string `form:"timestamp_format,omitempty"`
|
||||
Redundancy S3Redundancy `form:"redundancy,omitempty"`
|
||||
}
|
||||
|
||||
// UpdateS3 updates a specific S3.
|
||||
|
|
|
@ -7,14 +7,14 @@ import (
|
|||
|
||||
// Version represents a distinct configuration version.
|
||||
type Version struct {
|
||||
Number string `mapstructure:"number"`
|
||||
Comment string `mapstructure:"comment"`
|
||||
ServiceID string `mapstructure:"service_id"`
|
||||
Active bool `mapstructure:"active"`
|
||||
Locked bool `mapstructure:"locked"`
|
||||
Deployed bool `mapstructure:"deployed"`
|
||||
Staging bool `mapstructure:"staging"`
|
||||
Testing bool `mapstructure:"testing"`
|
||||
Number string `mapstructure:"number"`
|
||||
Comment string `mapstructure:"comment"`
|
||||
ServiceID string `mapstructure:"service_id"`
|
||||
Active bool `mapstructure:"active"`
|
||||
Locked bool `mapstructure:"locked"`
|
||||
Deployed bool `mapstructure:"deployed"`
|
||||
Staging bool `mapstructure:"staging"`
|
||||
Testing bool `mapstructure:"testing"`
|
||||
}
|
||||
|
||||
// versionsByNumber is a sortable list of versions. This is used by the version
|
||||
|
|
|
@ -250,8 +250,10 @@
|
|||
"revision": "9b82b0372a4edf52f66fbc8feaa6aafe0123001d"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "csR8njyJfkweB0RCtfnLwgXNeqQ=",
|
||||
"path": "github.com/ajg/form",
|
||||
"revision": "c9e1c3ae1f869d211cdaa085d23c6af2f5f83866"
|
||||
"revision": "7ff89c75808766205bfa4411abb436c98c33eb5e",
|
||||
"revisionTime": "2016-06-29T21:43:12Z"
|
||||
},
|
||||
{
|
||||
"path": "github.com/apparentlymart/go-cidr/cidr",
|
||||
|
@ -1611,8 +1613,10 @@
|
|||
"revision": "d41af8bb6a7704f00bc3b7cba9355ae6a5a80048"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "DWJoWDXcRi4HUCyxU6dLVVjR4pI=",
|
||||
"path": "github.com/sethvargo/go-fastly",
|
||||
"revision": "6566b161e807516f4a45bc3054eac291a120e217"
|
||||
"revision": "b0a18d43769d55365d4fbd9ba36493e5c0dcd8f5",
|
||||
"revisionTime": "2016-07-08T18:18:56Z"
|
||||
},
|
||||
{
|
||||
"comment": "v1.1-2-g5578a8c",
|
||||
|
|
Loading…
Reference in New Issue