diff options
author | Nathan Dench <ndenc2@gmail.com> | 2019-05-24 15:16:44 +1000 |
---|---|---|
committer | Nathan Dench <ndenc2@gmail.com> | 2019-05-24 15:16:44 +1000 |
commit | 107c1cdb09c575aa2f61d97f48d8587eb6bada4c (patch) | |
tree | ca7d008643efc555c388baeaf1d986e0b6b3e28c /vendor/github.com/mitchellh | |
parent | 844b5a68d8af4791755b8f0ad293cc99f5959183 (diff) | |
download | terraform-provider-statuscake-107c1cdb09c575aa2f61d97f48d8587eb6bada4c.tar.gz terraform-provider-statuscake-107c1cdb09c575aa2f61d97f48d8587eb6bada4c.tar.zst terraform-provider-statuscake-107c1cdb09c575aa2f61d97f48d8587eb6bada4c.zip |
Upgrade to 0.12
Diffstat (limited to 'vendor/github.com/mitchellh')
28 files changed, 1067 insertions, 202 deletions
diff --git a/vendor/github.com/mitchellh/cli/.travis.yml b/vendor/github.com/mitchellh/cli/.travis.yml index 974234b..b8599b3 100644 --- a/vendor/github.com/mitchellh/cli/.travis.yml +++ b/vendor/github.com/mitchellh/cli/.travis.yml | |||
@@ -3,8 +3,9 @@ sudo: false | |||
3 | language: go | 3 | language: go |
4 | 4 | ||
5 | go: | 5 | go: |
6 | - 1.8 | 6 | - "1.8" |
7 | - 1.9 | 7 | - "1.9" |
8 | - "1.10" | ||
8 | 9 | ||
9 | branches: | 10 | branches: |
10 | only: | 11 | only: |
diff --git a/vendor/github.com/mitchellh/cli/cli.go b/vendor/github.com/mitchellh/cli/cli.go index a25a582..c2dbe55 100644 --- a/vendor/github.com/mitchellh/cli/cli.go +++ b/vendor/github.com/mitchellh/cli/cli.go | |||
@@ -87,7 +87,7 @@ type CLI struct { | |||
87 | // should be set exactly to the binary name that is autocompleted. | 87 | // should be set exactly to the binary name that is autocompleted. |
88 | // | 88 | // |
89 | // Autocompletion is supported via the github.com/posener/complete | 89 | // Autocompletion is supported via the github.com/posener/complete |
90 | // library. This library supports both bash and zsh. To add support | 90 | // library. This library supports bash, zsh and fish. To add support |
91 | // for other shells, please see that library. | 91 | // for other shells, please see that library. |
92 | // | 92 | // |
93 | // AutocompleteInstall and AutocompleteUninstall are the global flag | 93 | // AutocompleteInstall and AutocompleteUninstall are the global flag |
@@ -419,6 +419,11 @@ func (c *CLI) initAutocomplete() { | |||
419 | func (c *CLI) initAutocompleteSub(prefix string) complete.Command { | 419 | func (c *CLI) initAutocompleteSub(prefix string) complete.Command { |
420 | var cmd complete.Command | 420 | var cmd complete.Command |
421 | walkFn := func(k string, raw interface{}) bool { | 421 | walkFn := func(k string, raw interface{}) bool { |
422 | // Ignore the empty key which can be present for default commands. | ||
423 | if k == "" { | ||
424 | return false | ||
425 | } | ||
426 | |||
422 | // Keep track of the full key so that we can nest further if necessary | 427 | // Keep track of the full key so that we can nest further if necessary |
423 | fullKey := k | 428 | fullKey := k |
424 | 429 | ||
diff --git a/vendor/github.com/mitchellh/cli/go.mod b/vendor/github.com/mitchellh/cli/go.mod new file mode 100644 index 0000000..675325f --- /dev/null +++ b/vendor/github.com/mitchellh/cli/go.mod | |||
@@ -0,0 +1,12 @@ | |||
1 | module github.com/mitchellh/cli | ||
2 | |||
3 | require ( | ||
4 | github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310 | ||
5 | github.com/bgentry/speakeasy v0.1.0 | ||
6 | github.com/fatih/color v1.7.0 | ||
7 | github.com/hashicorp/go-multierror v1.0.0 // indirect | ||
8 | github.com/mattn/go-colorable v0.0.9 // indirect | ||
9 | github.com/mattn/go-isatty v0.0.3 | ||
10 | github.com/posener/complete v1.1.1 | ||
11 | golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc // indirect | ||
12 | ) | ||
diff --git a/vendor/github.com/mitchellh/cli/go.sum b/vendor/github.com/mitchellh/cli/go.sum new file mode 100644 index 0000000..0370875 --- /dev/null +++ b/vendor/github.com/mitchellh/cli/go.sum | |||
@@ -0,0 +1,22 @@ | |||
1 | github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310 h1:BUAU3CGlLvorLI26FmByPp2eC2qla6E1Tw+scpcg/to= | ||
2 | github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= | ||
3 | github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY= | ||
4 | github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= | ||
5 | github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= | ||
6 | github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= | ||
7 | github.com/hashicorp/errwrap v0.0.0-20180715044906-d6c0cd880357 h1:Rem2+U35z1QtPQc6r+WolF7yXiefXqDKyk+lN2pE164= | ||
8 | github.com/hashicorp/errwrap v0.0.0-20180715044906-d6c0cd880357/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= | ||
9 | github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= | ||
10 | github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= | ||
11 | github.com/hashicorp/go-multierror v0.0.0-20180717150148-3d5d8f294aa0 h1:j30noezaCfvNLcdMYSvHLv81DxYRSt1grlpseG67vhU= | ||
12 | github.com/hashicorp/go-multierror v0.0.0-20180717150148-3d5d8f294aa0/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I= | ||
13 | github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o= | ||
14 | github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= | ||
15 | github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4= | ||
16 | github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= | ||
17 | github.com/mattn/go-isatty v0.0.3 h1:ns/ykhmWi7G9O+8a448SecJU3nSMBXJfqQkl0upE1jI= | ||
18 | github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= | ||
19 | github.com/posener/complete v1.1.1 h1:ccV59UEOTzVDnDUEFdT95ZzHVZ+5+158q8+SJb2QV5w= | ||
20 | github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= | ||
21 | golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc h1:MeuS1UDyZyFH++6vVy44PuufTeFF0d0nfI6XB87YGSk= | ||
22 | golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||
diff --git a/vendor/github.com/mitchellh/cli/ui_colored.go b/vendor/github.com/mitchellh/cli/ui_colored.go index e3d5131..b0ec448 100644 --- a/vendor/github.com/mitchellh/cli/ui_colored.go +++ b/vendor/github.com/mitchellh/cli/ui_colored.go | |||
@@ -1,7 +1,11 @@ | |||
1 | package cli | 1 | package cli |
2 | 2 | ||
3 | import ( | 3 | import ( |
4 | "fmt" | 4 | "github.com/fatih/color" |
5 | ) | ||
6 | |||
7 | const ( | ||
8 | noColor = -1 | ||
5 | ) | 9 | ) |
6 | 10 | ||
7 | // UiColor is a posix shell color code to use. | 11 | // UiColor is a posix shell color code to use. |
@@ -12,13 +16,13 @@ type UiColor struct { | |||
12 | 16 | ||
13 | // A list of colors that are useful. These are all non-bolded by default. | 17 | // A list of colors that are useful. These are all non-bolded by default. |
14 | var ( | 18 | var ( |
15 | UiColorNone UiColor = UiColor{-1, false} | 19 | UiColorNone UiColor = UiColor{noColor, false} |
16 | UiColorRed = UiColor{31, false} | 20 | UiColorRed = UiColor{int(color.FgHiRed), false} |
17 | UiColorGreen = UiColor{32, false} | 21 | UiColorGreen = UiColor{int(color.FgHiGreen), false} |
18 | UiColorYellow = UiColor{33, false} | 22 | UiColorYellow = UiColor{int(color.FgHiYellow), false} |
19 | UiColorBlue = UiColor{34, false} | 23 | UiColorBlue = UiColor{int(color.FgHiBlue), false} |
20 | UiColorMagenta = UiColor{35, false} | 24 | UiColorMagenta = UiColor{int(color.FgHiMagenta), false} |
21 | UiColorCyan = UiColor{36, false} | 25 | UiColorCyan = UiColor{int(color.FgHiCyan), false} |
22 | ) | 26 | ) |
23 | 27 | ||
24 | // ColoredUi is a Ui implementation that colors its output according | 28 | // ColoredUi is a Ui implementation that colors its output according |
@@ -55,15 +59,15 @@ func (u *ColoredUi) Warn(message string) { | |||
55 | u.Ui.Warn(u.colorize(message, u.WarnColor)) | 59 | u.Ui.Warn(u.colorize(message, u.WarnColor)) |
56 | } | 60 | } |
57 | 61 | ||
58 | func (u *ColoredUi) colorize(message string, color UiColor) string { | 62 | func (u *ColoredUi) colorize(message string, uc UiColor) string { |
59 | if color.Code == -1 { | 63 | if uc.Code == noColor { |
60 | return message | 64 | return message |
61 | } | 65 | } |
62 | 66 | ||
63 | attr := 0 | 67 | attr := []color.Attribute{color.Attribute(uc.Code)} |
64 | if color.Bold { | 68 | if uc.Bold { |
65 | attr = 1 | 69 | attr = append(attr, color.Bold) |
66 | } | 70 | } |
67 | 71 | ||
68 | return fmt.Sprintf("\033[%d;%dm%s\033[0m", attr, color.Code, message) | 72 | return color.New(attr...).SprintFunc()(message) |
69 | } | 73 | } |
diff --git a/vendor/github.com/mitchellh/colorstring/.travis.yml b/vendor/github.com/mitchellh/colorstring/.travis.yml new file mode 100644 index 0000000..74e286a --- /dev/null +++ b/vendor/github.com/mitchellh/colorstring/.travis.yml | |||
@@ -0,0 +1,15 @@ | |||
1 | language: go | ||
2 | |||
3 | go: | ||
4 | - 1.0 | ||
5 | - 1.1 | ||
6 | - 1.2 | ||
7 | - 1.3 | ||
8 | - tip | ||
9 | |||
10 | script: | ||
11 | - go test | ||
12 | |||
13 | matrix: | ||
14 | allow_failures: | ||
15 | - go: tip | ||
diff --git a/vendor/github.com/mitchellh/colorstring/LICENSE b/vendor/github.com/mitchellh/colorstring/LICENSE new file mode 100644 index 0000000..2298515 --- /dev/null +++ b/vendor/github.com/mitchellh/colorstring/LICENSE | |||
@@ -0,0 +1,21 @@ | |||
1 | The MIT License (MIT) | ||
2 | |||
3 | Copyright (c) 2014 Mitchell Hashimoto | ||
4 | |||
5 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
6 | of this software and associated documentation files (the "Software"), to deal | ||
7 | in the Software without restriction, including without limitation the rights | ||
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
9 | copies of the Software, and to permit persons to whom the Software is | ||
10 | furnished to do so, subject to the following conditions: | ||
11 | |||
12 | The above copyright notice and this permission notice shall be included in | ||
13 | all copies or substantial portions of the Software. | ||
14 | |||
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
21 | THE SOFTWARE. | ||
diff --git a/vendor/github.com/mitchellh/colorstring/README.md b/vendor/github.com/mitchellh/colorstring/README.md new file mode 100644 index 0000000..0654d45 --- /dev/null +++ b/vendor/github.com/mitchellh/colorstring/README.md | |||
@@ -0,0 +1,30 @@ | |||
1 | # colorstring [![Build Status](https://travis-ci.org/mitchellh/colorstring.svg)](https://travis-ci.org/mitchellh/colorstring) | ||
2 | |||
3 | colorstring is a [Go](http://www.golang.org) library for outputting colored | ||
4 | strings to a console using a simple inline syntax in your string to specify | ||
5 | the color to print as. | ||
6 | |||
7 | For example, the string `[blue]hello [red]world` would output the text | ||
8 | "hello world" in two colors. The API of colorstring allows for easily disabling | ||
9 | colors, adding aliases, etc. | ||
10 | |||
11 | ## Installation | ||
12 | |||
13 | Standard `go get`: | ||
14 | |||
15 | ``` | ||
16 | $ go get github.com/mitchellh/colorstring | ||
17 | ``` | ||
18 | |||
19 | ## Usage & Example | ||
20 | |||
21 | For usage and examples see the [Godoc](http://godoc.org/github.com/mitchellh/colorstring). | ||
22 | |||
23 | Usage is easy enough: | ||
24 | |||
25 | ```go | ||
26 | colorstring.Println("[blue]Hello [red]World!") | ||
27 | ``` | ||
28 | |||
29 | Additionally, the `Colorize` struct can be used to set options such as | ||
30 | custom colors, color disabling, etc. | ||
diff --git a/vendor/github.com/mitchellh/colorstring/colorstring.go b/vendor/github.com/mitchellh/colorstring/colorstring.go new file mode 100644 index 0000000..3de5b24 --- /dev/null +++ b/vendor/github.com/mitchellh/colorstring/colorstring.go | |||
@@ -0,0 +1,244 @@ | |||
1 | // colorstring provides functions for colorizing strings for terminal | ||
2 | // output. | ||
3 | package colorstring | ||
4 | |||
5 | import ( | ||
6 | "bytes" | ||
7 | "fmt" | ||
8 | "io" | ||
9 | "regexp" | ||
10 | "strings" | ||
11 | ) | ||
12 | |||
13 | // Color colorizes your strings using the default settings. | ||
14 | // | ||
15 | // Strings given to Color should use the syntax `[color]` to specify the | ||
16 | // color for text following. For example: `[blue]Hello` will return "Hello" | ||
17 | // in blue. See DefaultColors for all the supported colors and attributes. | ||
18 | // | ||
19 | // If an unrecognized color is given, it is ignored and assumed to be part | ||
20 | // of the string. For example: `[hi]world` will result in "[hi]world". | ||
21 | // | ||
22 | // A color reset is appended to the end of every string. This will reset | ||
23 | // the color of following strings when you output this text to the same | ||
24 | // terminal session. | ||
25 | // | ||
26 | // If you want to customize any of this behavior, use the Colorize struct. | ||
27 | func Color(v string) string { | ||
28 | return def.Color(v) | ||
29 | } | ||
30 | |||
31 | // ColorPrefix returns the color sequence that prefixes the given text. | ||
32 | // | ||
33 | // This is useful when wrapping text if you want to inherit the color | ||
34 | // of the wrapped text. For example, "[green]foo" will return "[green]". | ||
35 | // If there is no color sequence, then this will return "". | ||
36 | func ColorPrefix(v string) string { | ||
37 | return def.ColorPrefix(v) | ||
38 | } | ||
39 | |||
40 | // Colorize colorizes your strings, giving you the ability to customize | ||
41 | // some of the colorization process. | ||
42 | // | ||
43 | // The options in Colorize can be set to customize colorization. If you're | ||
44 | // only interested in the defaults, just use the top Color function directly, | ||
45 | // which creates a default Colorize. | ||
46 | type Colorize struct { | ||
47 | // Colors maps a color string to the code for that color. The code | ||
48 | // is a string so that you can use more complex colors to set foreground, | ||
49 | // background, attributes, etc. For example, "boldblue" might be | ||
50 | // "1;34" | ||
51 | Colors map[string]string | ||
52 | |||
53 | // If true, color attributes will be ignored. This is useful if you're | ||
54 | // outputting to a location that doesn't support colors and you just | ||
55 | // want the strings returned. | ||
56 | Disable bool | ||
57 | |||
58 | // Reset, if true, will reset the color after each colorization by | ||
59 | // adding a reset code at the end. | ||
60 | Reset bool | ||
61 | } | ||
62 | |||
63 | // Color colorizes a string according to the settings setup in the struct. | ||
64 | // | ||
65 | // For more details on the syntax, see the top-level Color function. | ||
66 | func (c *Colorize) Color(v string) string { | ||
67 | matches := parseRe.FindAllStringIndex(v, -1) | ||
68 | if len(matches) == 0 { | ||
69 | return v | ||
70 | } | ||
71 | |||
72 | result := new(bytes.Buffer) | ||
73 | colored := false | ||
74 | m := []int{0, 0} | ||
75 | for _, nm := range matches { | ||
76 | // Write the text in between this match and the last | ||
77 | result.WriteString(v[m[1]:nm[0]]) | ||
78 | m = nm | ||
79 | |||
80 | var replace string | ||
81 | if code, ok := c.Colors[v[m[0]+1:m[1]-1]]; ok { | ||
82 | colored = true | ||
83 | |||
84 | if !c.Disable { | ||
85 | replace = fmt.Sprintf("\033[%sm", code) | ||
86 | } | ||
87 | } else { | ||
88 | replace = v[m[0]:m[1]] | ||
89 | } | ||
90 | |||
91 | result.WriteString(replace) | ||
92 | } | ||
93 | result.WriteString(v[m[1]:]) | ||
94 | |||
95 | if colored && c.Reset && !c.Disable { | ||
96 | // Write the clear byte at the end | ||
97 | result.WriteString("\033[0m") | ||
98 | } | ||
99 | |||
100 | return result.String() | ||
101 | } | ||
102 | |||
103 | // ColorPrefix returns the first color sequence that exists in this string. | ||
104 | // | ||
105 | // For example: "[green]foo" would return "[green]". If no color sequence | ||
106 | // exists, then "" is returned. This is especially useful when wrapping | ||
107 | // colored texts to inherit the color of the wrapped text. | ||
108 | func (c *Colorize) ColorPrefix(v string) string { | ||
109 | return prefixRe.FindString(strings.TrimSpace(v)) | ||
110 | } | ||
111 | |||
112 | // DefaultColors are the default colors used when colorizing. | ||
113 | // | ||
114 | // If the color is surrounded in underscores, such as "_blue_", then that | ||
115 | // color will be used for the background color. | ||
116 | var DefaultColors map[string]string | ||
117 | |||
118 | func init() { | ||
119 | DefaultColors = map[string]string{ | ||
120 | // Default foreground/background colors | ||
121 | "default": "39", | ||
122 | "_default_": "49", | ||
123 | |||
124 | // Foreground colors | ||
125 | "black": "30", | ||
126 | "red": "31", | ||
127 | "green": "32", | ||
128 | "yellow": "33", | ||
129 | "blue": "34", | ||
130 | "magenta": "35", | ||
131 | "cyan": "36", | ||
132 | "light_gray": "37", | ||
133 | "dark_gray": "90", | ||
134 | "light_red": "91", | ||
135 | "light_green": "92", | ||
136 | "light_yellow": "93", | ||
137 | "light_blue": "94", | ||
138 | "light_magenta": "95", | ||
139 | "light_cyan": "96", | ||
140 | "white": "97", | ||
141 | |||
142 | // Background colors | ||
143 | "_black_": "40", | ||
144 | "_red_": "41", | ||
145 | "_green_": "42", | ||
146 | "_yellow_": "43", | ||
147 | "_blue_": "44", | ||
148 | "_magenta_": "45", | ||
149 | "_cyan_": "46", | ||
150 | "_light_gray_": "47", | ||
151 | "_dark_gray_": "100", | ||
152 | "_light_red_": "101", | ||
153 | "_light_green_": "102", | ||
154 | "_light_yellow_": "103", | ||
155 | "_light_blue_": "104", | ||
156 | "_light_magenta_": "105", | ||
157 | "_light_cyan_": "106", | ||
158 | "_white_": "107", | ||
159 | |||
160 | // Attributes | ||
161 | "bold": "1", | ||
162 | "dim": "2", | ||
163 | "underline": "4", | ||
164 | "blink_slow": "5", | ||
165 | "blink_fast": "6", | ||
166 | "invert": "7", | ||
167 | "hidden": "8", | ||
168 | |||
169 | // Reset to reset everything to their defaults | ||
170 | "reset": "0", | ||
171 | "reset_bold": "21", | ||
172 | } | ||
173 | |||
174 | def = Colorize{ | ||
175 | Colors: DefaultColors, | ||
176 | Reset: true, | ||
177 | } | ||
178 | } | ||
179 | |||
180 | var def Colorize | ||
181 | var parseReRaw = `\[[a-z0-9_-]+\]` | ||
182 | var parseRe = regexp.MustCompile(`(?i)` + parseReRaw) | ||
183 | var prefixRe = regexp.MustCompile(`^(?i)(` + parseReRaw + `)+`) | ||
184 | |||
185 | // Print is a convenience wrapper for fmt.Print with support for color codes. | ||
186 | // | ||
187 | // Print formats using the default formats for its operands and writes to | ||
188 | // standard output with support for color codes. Spaces are added between | ||
189 | // operands when neither is a string. It returns the number of bytes written | ||
190 | // and any write error encountered. | ||
191 | func Print(a string) (n int, err error) { | ||
192 | return fmt.Print(Color(a)) | ||
193 | } | ||
194 | |||
195 | // Println is a convenience wrapper for fmt.Println with support for color | ||
196 | // codes. | ||
197 | // | ||
198 | // Println formats using the default formats for its operands and writes to | ||
199 | // standard output with support for color codes. Spaces are always added | ||
200 | // between operands and a newline is appended. It returns the number of bytes | ||
201 | // written and any write error encountered. | ||
202 | func Println(a string) (n int, err error) { | ||
203 | return fmt.Println(Color(a)) | ||
204 | } | ||
205 | |||
206 | // Printf is a convenience wrapper for fmt.Printf with support for color codes. | ||
207 | // | ||
208 | // Printf formats according to a format specifier and writes to standard output | ||
209 | // with support for color codes. It returns the number of bytes written and any | ||
210 | // write error encountered. | ||
211 | func Printf(format string, a ...interface{}) (n int, err error) { | ||
212 | return fmt.Printf(Color(format), a...) | ||
213 | } | ||
214 | |||
215 | // Fprint is a convenience wrapper for fmt.Fprint with support for color codes. | ||
216 | // | ||
217 | // Fprint formats using the default formats for its operands and writes to w | ||
218 | // with support for color codes. Spaces are added between operands when neither | ||
219 | // is a string. It returns the number of bytes written and any write error | ||
220 | // encountered. | ||
221 | func Fprint(w io.Writer, a string) (n int, err error) { | ||
222 | return fmt.Fprint(w, Color(a)) | ||
223 | } | ||
224 | |||
225 | // Fprintln is a convenience wrapper for fmt.Fprintln with support for color | ||
226 | // codes. | ||
227 | // | ||
228 | // Fprintln formats using the default formats for its operands and writes to w | ||
229 | // with support for color codes. Spaces are always added between operands and a | ||
230 | // newline is appended. It returns the number of bytes written and any write | ||
231 | // error encountered. | ||
232 | func Fprintln(w io.Writer, a string) (n int, err error) { | ||
233 | return fmt.Fprintln(w, Color(a)) | ||
234 | } | ||
235 | |||
236 | // Fprintf is a convenience wrapper for fmt.Fprintf with support for color | ||
237 | // codes. | ||
238 | // | ||
239 | // Fprintf formats according to a format specifier and writes to w with support | ||
240 | // for color codes. It returns the number of bytes written and any write error | ||
241 | // encountered. | ||
242 | func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) { | ||
243 | return fmt.Fprintf(w, Color(format), a...) | ||
244 | } | ||
diff --git a/vendor/github.com/mitchellh/colorstring/go.mod b/vendor/github.com/mitchellh/colorstring/go.mod new file mode 100644 index 0000000..446ff8d --- /dev/null +++ b/vendor/github.com/mitchellh/colorstring/go.mod | |||
@@ -0,0 +1 @@ | |||
module github.com/mitchellh/colorstring | |||
diff --git a/vendor/github.com/mitchellh/copystructure/go.mod b/vendor/github.com/mitchellh/copystructure/go.mod new file mode 100644 index 0000000..d018643 --- /dev/null +++ b/vendor/github.com/mitchellh/copystructure/go.mod | |||
@@ -0,0 +1,3 @@ | |||
1 | module github.com/mitchellh/copystructure | ||
2 | |||
3 | require github.com/mitchellh/reflectwalk v1.0.0 | ||
diff --git a/vendor/github.com/mitchellh/copystructure/go.sum b/vendor/github.com/mitchellh/copystructure/go.sum new file mode 100644 index 0000000..be57245 --- /dev/null +++ b/vendor/github.com/mitchellh/copystructure/go.sum | |||
@@ -0,0 +1,2 @@ | |||
1 | github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY= | ||
2 | github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= | ||
diff --git a/vendor/github.com/mitchellh/go-homedir/go.mod b/vendor/github.com/mitchellh/go-homedir/go.mod new file mode 100644 index 0000000..7efa09a --- /dev/null +++ b/vendor/github.com/mitchellh/go-homedir/go.mod | |||
@@ -0,0 +1 @@ | |||
module github.com/mitchellh/go-homedir | |||
diff --git a/vendor/github.com/mitchellh/go-homedir/homedir.go b/vendor/github.com/mitchellh/go-homedir/homedir.go index 47e1f9e..fb87bef 100644 --- a/vendor/github.com/mitchellh/go-homedir/homedir.go +++ b/vendor/github.com/mitchellh/go-homedir/homedir.go | |||
@@ -77,33 +77,51 @@ func Expand(path string) (string, error) { | |||
77 | } | 77 | } |
78 | 78 | ||
79 | func dirUnix() (string, error) { | 79 | func dirUnix() (string, error) { |
80 | homeEnv := "HOME" | ||
81 | if runtime.GOOS == "plan9" { | ||
82 | // On plan9, env vars are lowercase. | ||
83 | homeEnv = "home" | ||
84 | } | ||
85 | |||
80 | // First prefer the HOME environmental variable | 86 | // First prefer the HOME environmental variable |
81 | if home := os.Getenv("HOME"); home != "" { | 87 | if home := os.Getenv(homeEnv); home != "" { |
82 | return home, nil | 88 | return home, nil |
83 | } | 89 | } |
84 | 90 | ||
85 | // If that fails, try getent | ||
86 | var stdout bytes.Buffer | 91 | var stdout bytes.Buffer |
87 | cmd := exec.Command("getent", "passwd", strconv.Itoa(os.Getuid())) | 92 | |
88 | cmd.Stdout = &stdout | 93 | // If that fails, try OS specific commands |
89 | if err := cmd.Run(); err != nil { | 94 | if runtime.GOOS == "darwin" { |
90 | // If the error is ErrNotFound, we ignore it. Otherwise, return it. | 95 | cmd := exec.Command("sh", "-c", `dscl -q . -read /Users/"$(whoami)" NFSHomeDirectory | sed 's/^[^ ]*: //'`) |
91 | if err != exec.ErrNotFound { | 96 | cmd.Stdout = &stdout |
92 | return "", err | 97 | if err := cmd.Run(); err == nil { |
98 | result := strings.TrimSpace(stdout.String()) | ||
99 | if result != "" { | ||
100 | return result, nil | ||
101 | } | ||
93 | } | 102 | } |
94 | } else { | 103 | } else { |
95 | if passwd := strings.TrimSpace(stdout.String()); passwd != "" { | 104 | cmd := exec.Command("getent", "passwd", strconv.Itoa(os.Getuid())) |
96 | // username:password:uid:gid:gecos:home:shell | 105 | cmd.Stdout = &stdout |
97 | passwdParts := strings.SplitN(passwd, ":", 7) | 106 | if err := cmd.Run(); err != nil { |
98 | if len(passwdParts) > 5 { | 107 | // If the error is ErrNotFound, we ignore it. Otherwise, return it. |
99 | return passwdParts[5], nil | 108 | if err != exec.ErrNotFound { |
109 | return "", err | ||
110 | } | ||
111 | } else { | ||
112 | if passwd := strings.TrimSpace(stdout.String()); passwd != "" { | ||
113 | // username:password:uid:gid:gecos:home:shell | ||
114 | passwdParts := strings.SplitN(passwd, ":", 7) | ||
115 | if len(passwdParts) > 5 { | ||
116 | return passwdParts[5], nil | ||
117 | } | ||
100 | } | 118 | } |
101 | } | 119 | } |
102 | } | 120 | } |
103 | 121 | ||
104 | // If all else fails, try the shell | 122 | // If all else fails, try the shell |
105 | stdout.Reset() | 123 | stdout.Reset() |
106 | cmd = exec.Command("sh", "-c", "cd && pwd") | 124 | cmd := exec.Command("sh", "-c", "cd && pwd") |
107 | cmd.Stdout = &stdout | 125 | cmd.Stdout = &stdout |
108 | if err := cmd.Run(); err != nil { | 126 | if err := cmd.Run(); err != nil { |
109 | return "", err | 127 | return "", err |
@@ -123,14 +141,16 @@ func dirWindows() (string, error) { | |||
123 | return home, nil | 141 | return home, nil |
124 | } | 142 | } |
125 | 143 | ||
144 | // Prefer standard environment variable USERPROFILE | ||
145 | if home := os.Getenv("USERPROFILE"); home != "" { | ||
146 | return home, nil | ||
147 | } | ||
148 | |||
126 | drive := os.Getenv("HOMEDRIVE") | 149 | drive := os.Getenv("HOMEDRIVE") |
127 | path := os.Getenv("HOMEPATH") | 150 | path := os.Getenv("HOMEPATH") |
128 | home := drive + path | 151 | home := drive + path |
129 | if drive == "" || path == "" { | 152 | if drive == "" || path == "" { |
130 | home = os.Getenv("USERPROFILE") | 153 | return "", errors.New("HOMEDRIVE, HOMEPATH, or USERPROFILE are blank") |
131 | } | ||
132 | if home == "" { | ||
133 | return "", errors.New("HOMEDRIVE, HOMEPATH, and USERPROFILE are blank") | ||
134 | } | 154 | } |
135 | 155 | ||
136 | return home, nil | 156 | return home, nil |
diff --git a/vendor/github.com/mitchellh/go-testing-interface/.travis.yml b/vendor/github.com/mitchellh/go-testing-interface/.travis.yml index 4c83109..928d000 100644 --- a/vendor/github.com/mitchellh/go-testing-interface/.travis.yml +++ b/vendor/github.com/mitchellh/go-testing-interface/.travis.yml | |||
@@ -2,6 +2,7 @@ language: go | |||
2 | 2 | ||
3 | go: | 3 | go: |
4 | - 1.8 | 4 | - 1.8 |
5 | - 1.x | ||
5 | - tip | 6 | - tip |
6 | 7 | ||
7 | script: | 8 | script: |
diff --git a/vendor/github.com/mitchellh/go-testing-interface/go.mod b/vendor/github.com/mitchellh/go-testing-interface/go.mod new file mode 100644 index 0000000..062796d --- /dev/null +++ b/vendor/github.com/mitchellh/go-testing-interface/go.mod | |||
@@ -0,0 +1 @@ | |||
module github.com/mitchellh/go-testing-interface | |||
diff --git a/vendor/github.com/mitchellh/go-testing-interface/testing_go19.go b/vendor/github.com/mitchellh/go-testing-interface/testing_go19.go index 07fbcb5..31b42ca 100644 --- a/vendor/github.com/mitchellh/go-testing-interface/testing_go19.go +++ b/vendor/github.com/mitchellh/go-testing-interface/testing_go19.go | |||
@@ -19,14 +19,19 @@ import ( | |||
19 | type T interface { | 19 | type T interface { |
20 | Error(args ...interface{}) | 20 | Error(args ...interface{}) |
21 | Errorf(format string, args ...interface{}) | 21 | Errorf(format string, args ...interface{}) |
22 | Fatal(args ...interface{}) | ||
23 | Fatalf(format string, args ...interface{}) | ||
24 | Fail() | 22 | Fail() |
25 | FailNow() | 23 | FailNow() |
26 | Failed() bool | 24 | Failed() bool |
27 | Helper() | 25 | Fatal(args ...interface{}) |
26 | Fatalf(format string, args ...interface{}) | ||
28 | Log(args ...interface{}) | 27 | Log(args ...interface{}) |
29 | Logf(format string, args ...interface{}) | 28 | Logf(format string, args ...interface{}) |
29 | Name() string | ||
30 | Skip(args ...interface{}) | ||
31 | SkipNow() | ||
32 | Skipf(format string, args ...interface{}) | ||
33 | Skipped() bool | ||
34 | Helper() | ||
30 | } | 35 | } |
31 | 36 | ||
32 | // RuntimeT implements T and can be instantiated and run at runtime to | 37 | // RuntimeT implements T and can be instantiated and run at runtime to |
@@ -34,7 +39,8 @@ type T interface { | |||
34 | // for calls to Fatal. For calls to Error, you'll have to check the errors | 39 | // for calls to Fatal. For calls to Error, you'll have to check the errors |
35 | // list to determine whether to exit yourself. | 40 | // list to determine whether to exit yourself. |
36 | type RuntimeT struct { | 41 | type RuntimeT struct { |
37 | failed bool | 42 | skipped bool |
43 | failed bool | ||
38 | } | 44 | } |
39 | 45 | ||
40 | func (t *RuntimeT) Error(args ...interface{}) { | 46 | func (t *RuntimeT) Error(args ...interface{}) { |
@@ -43,20 +49,10 @@ func (t *RuntimeT) Error(args ...interface{}) { | |||
43 | } | 49 | } |
44 | 50 | ||
45 | func (t *RuntimeT) Errorf(format string, args ...interface{}) { | 51 | func (t *RuntimeT) Errorf(format string, args ...interface{}) { |
46 | log.Println(fmt.Sprintf(format, args...)) | 52 | log.Printf(format, args...) |
47 | t.Fail() | 53 | t.Fail() |
48 | } | 54 | } |
49 | 55 | ||
50 | func (t *RuntimeT) Fatal(args ...interface{}) { | ||
51 | log.Println(fmt.Sprintln(args...)) | ||
52 | t.FailNow() | ||
53 | } | ||
54 | |||
55 | func (t *RuntimeT) Fatalf(format string, args ...interface{}) { | ||
56 | log.Println(fmt.Sprintf(format, args...)) | ||
57 | t.FailNow() | ||
58 | } | ||
59 | |||
60 | func (t *RuntimeT) Fail() { | 56 | func (t *RuntimeT) Fail() { |
61 | t.failed = true | 57 | t.failed = true |
62 | } | 58 | } |
@@ -69,7 +65,15 @@ func (t *RuntimeT) Failed() bool { | |||
69 | return t.failed | 65 | return t.failed |
70 | } | 66 | } |
71 | 67 | ||
72 | func (t *RuntimeT) Helper() {} | 68 | func (t *RuntimeT) Fatal(args ...interface{}) { |
69 | log.Print(args...) | ||
70 | t.FailNow() | ||
71 | } | ||
72 | |||
73 | func (t *RuntimeT) Fatalf(format string, args ...interface{}) { | ||
74 | log.Printf(format, args...) | ||
75 | t.FailNow() | ||
76 | } | ||
73 | 77 | ||
74 | func (t *RuntimeT) Log(args ...interface{}) { | 78 | func (t *RuntimeT) Log(args ...interface{}) { |
75 | log.Println(fmt.Sprintln(args...)) | 79 | log.Println(fmt.Sprintln(args...)) |
@@ -78,3 +82,27 @@ func (t *RuntimeT) Log(args ...interface{}) { | |||
78 | func (t *RuntimeT) Logf(format string, args ...interface{}) { | 82 | func (t *RuntimeT) Logf(format string, args ...interface{}) { |
79 | log.Println(fmt.Sprintf(format, args...)) | 83 | log.Println(fmt.Sprintf(format, args...)) |
80 | } | 84 | } |
85 | |||
86 | func (t *RuntimeT) Name() string { | ||
87 | return "" | ||
88 | } | ||
89 | |||
90 | func (t *RuntimeT) Skip(args ...interface{}) { | ||
91 | log.Print(args...) | ||
92 | t.SkipNow() | ||
93 | } | ||
94 | |||
95 | func (t *RuntimeT) SkipNow() { | ||
96 | t.skipped = true | ||
97 | } | ||
98 | |||
99 | func (t *RuntimeT) Skipf(format string, args ...interface{}) { | ||
100 | log.Printf(format, args...) | ||
101 | t.SkipNow() | ||
102 | } | ||
103 | |||
104 | func (t *RuntimeT) Skipped() bool { | ||
105 | return t.skipped | ||
106 | } | ||
107 | |||
108 | func (t *RuntimeT) Helper() {} | ||
diff --git a/vendor/github.com/mitchellh/go-wordwrap/go.mod b/vendor/github.com/mitchellh/go-wordwrap/go.mod new file mode 100644 index 0000000..2ae411b --- /dev/null +++ b/vendor/github.com/mitchellh/go-wordwrap/go.mod | |||
@@ -0,0 +1 @@ | |||
module github.com/mitchellh/go-wordwrap | |||
diff --git a/vendor/github.com/mitchellh/hashstructure/README.md b/vendor/github.com/mitchellh/hashstructure/README.md index 7d0de5b..28ce45a 100644 --- a/vendor/github.com/mitchellh/hashstructure/README.md +++ b/vendor/github.com/mitchellh/hashstructure/README.md | |||
@@ -1,4 +1,4 @@ | |||
1 | # hashstructure | 1 | # hashstructure [![GoDoc](https://godoc.org/github.com/mitchellh/hashstructure?status.svg)](https://godoc.org/github.com/mitchellh/hashstructure) |
2 | 2 | ||
3 | hashstructure is a Go library for creating a unique hash value | 3 | hashstructure is a Go library for creating a unique hash value |
4 | for arbitrary values in Go. | 4 | for arbitrary values in Go. |
@@ -19,6 +19,9 @@ sending data across the network, caching values locally (de-dup), and so on. | |||
19 | 19 | ||
20 | * Optionally specify a custom hash function to optimize for speed, collision | 20 | * Optionally specify a custom hash function to optimize for speed, collision |
21 | avoidance for your data set, etc. | 21 | avoidance for your data set, etc. |
22 | |||
23 | * Optionally hash the output of `.String()` on structs that implement fmt.Stringer, | ||
24 | allowing effective hashing of time.Time | ||
22 | 25 | ||
23 | ## Installation | 26 | ## Installation |
24 | 27 | ||
@@ -34,28 +37,29 @@ For usage and examples see the [Godoc](http://godoc.org/github.com/mitchellh/has | |||
34 | 37 | ||
35 | A quick code example is shown below: | 38 | A quick code example is shown below: |
36 | 39 | ||
37 | 40 | ```go | |
38 | type ComplexStruct struct { | 41 | type ComplexStruct struct { |
39 | Name string | 42 | Name string |
40 | Age uint | 43 | Age uint |
41 | Metadata map[string]interface{} | 44 | Metadata map[string]interface{} |
42 | } | 45 | } |
43 | 46 | ||
44 | v := ComplexStruct{ | 47 | v := ComplexStruct{ |
45 | Name: "mitchellh", | 48 | Name: "mitchellh", |
46 | Age: 64, | 49 | Age: 64, |
47 | Metadata: map[string]interface{}{ | 50 | Metadata: map[string]interface{}{ |
48 | "car": true, | 51 | "car": true, |
49 | "location": "California", | 52 | "location": "California", |
50 | "siblings": []string{"Bob", "John"}, | 53 | "siblings": []string{"Bob", "John"}, |
51 | }, | 54 | }, |
52 | } | 55 | } |
53 | 56 | ||
54 | hash, err := hashstructure.Hash(v, nil) | 57 | hash, err := hashstructure.Hash(v, nil) |
55 | if err != nil { | 58 | if err != nil { |
56 | panic(err) | 59 | panic(err) |
57 | } | 60 | } |
58 | 61 | ||
59 | fmt.Printf("%d", hash) | 62 | fmt.Printf("%d", hash) |
60 | // Output: | 63 | // Output: |
61 | // 2307517237273902113 | 64 | // 2307517237273902113 |
65 | ``` | ||
diff --git a/vendor/github.com/mitchellh/hashstructure/go.mod b/vendor/github.com/mitchellh/hashstructure/go.mod new file mode 100644 index 0000000..966582a --- /dev/null +++ b/vendor/github.com/mitchellh/hashstructure/go.mod | |||
@@ -0,0 +1 @@ | |||
module github.com/mitchellh/hashstructure | |||
diff --git a/vendor/github.com/mitchellh/hashstructure/hashstructure.go b/vendor/github.com/mitchellh/hashstructure/hashstructure.go index 6f586fa..ea13a15 100644 --- a/vendor/github.com/mitchellh/hashstructure/hashstructure.go +++ b/vendor/github.com/mitchellh/hashstructure/hashstructure.go | |||
@@ -8,6 +8,16 @@ import ( | |||
8 | "reflect" | 8 | "reflect" |
9 | ) | 9 | ) |
10 | 10 | ||
11 | // ErrNotStringer is returned when there's an error with hash:"string" | ||
12 | type ErrNotStringer struct { | ||
13 | Field string | ||
14 | } | ||
15 | |||
16 | // Error implements error for ErrNotStringer | ||
17 | func (ens *ErrNotStringer) Error() string { | ||
18 | return fmt.Sprintf("hashstructure: %s has hash:\"string\" set, but does not implement fmt.Stringer", ens.Field) | ||
19 | } | ||
20 | |||
11 | // HashOptions are options that are available for hashing. | 21 | // HashOptions are options that are available for hashing. |
12 | type HashOptions struct { | 22 | type HashOptions struct { |
13 | // Hasher is the hash function to use. If this isn't set, it will | 23 | // Hasher is the hash function to use. If this isn't set, it will |
@@ -17,12 +27,18 @@ type HashOptions struct { | |||
17 | // TagName is the struct tag to look at when hashing the structure. | 27 | // TagName is the struct tag to look at when hashing the structure. |
18 | // By default this is "hash". | 28 | // By default this is "hash". |
19 | TagName string | 29 | TagName string |
30 | |||
31 | // ZeroNil is flag determining if nil pointer should be treated equal | ||
32 | // to a zero value of pointed type. By default this is false. | ||
33 | ZeroNil bool | ||
20 | } | 34 | } |
21 | 35 | ||
22 | // Hash returns the hash value of an arbitrary value. | 36 | // Hash returns the hash value of an arbitrary value. |
23 | // | 37 | // |
24 | // If opts is nil, then default options will be used. See HashOptions | 38 | // If opts is nil, then default options will be used. See HashOptions |
25 | // for the default values. | 39 | // for the default values. The same *HashOptions value cannot be used |
40 | // concurrently. None of the values within a *HashOptions struct are | ||
41 | // safe to read/write while hashing is being done. | ||
26 | // | 42 | // |
27 | // Notes on the value: | 43 | // Notes on the value: |
28 | // | 44 | // |
@@ -41,11 +57,14 @@ type HashOptions struct { | |||
41 | // | 57 | // |
42 | // The available tag values are: | 58 | // The available tag values are: |
43 | // | 59 | // |
44 | // * "ignore" - The field will be ignored and not affect the hash code. | 60 | // * "ignore" or "-" - The field will be ignored and not affect the hash code. |
45 | // | 61 | // |
46 | // * "set" - The field will be treated as a set, where ordering doesn't | 62 | // * "set" - The field will be treated as a set, where ordering doesn't |
47 | // affect the hash code. This only works for slices. | 63 | // affect the hash code. This only works for slices. |
48 | // | 64 | // |
65 | // * "string" - The field will be hashed as a string, only works when the | ||
66 | // field implements fmt.Stringer | ||
67 | // | ||
49 | func Hash(v interface{}, opts *HashOptions) (uint64, error) { | 68 | func Hash(v interface{}, opts *HashOptions) (uint64, error) { |
50 | // Create default options | 69 | // Create default options |
51 | if opts == nil { | 70 | if opts == nil { |
@@ -63,15 +82,17 @@ func Hash(v interface{}, opts *HashOptions) (uint64, error) { | |||
63 | 82 | ||
64 | // Create our walker and walk the structure | 83 | // Create our walker and walk the structure |
65 | w := &walker{ | 84 | w := &walker{ |
66 | h: opts.Hasher, | 85 | h: opts.Hasher, |
67 | tag: opts.TagName, | 86 | tag: opts.TagName, |
87 | zeronil: opts.ZeroNil, | ||
68 | } | 88 | } |
69 | return w.visit(reflect.ValueOf(v), nil) | 89 | return w.visit(reflect.ValueOf(v), nil) |
70 | } | 90 | } |
71 | 91 | ||
72 | type walker struct { | 92 | type walker struct { |
73 | h hash.Hash64 | 93 | h hash.Hash64 |
74 | tag string | 94 | tag string |
95 | zeronil bool | ||
75 | } | 96 | } |
76 | 97 | ||
77 | type visitOpts struct { | 98 | type visitOpts struct { |
@@ -84,6 +105,8 @@ type visitOpts struct { | |||
84 | } | 105 | } |
85 | 106 | ||
86 | func (w *walker) visit(v reflect.Value, opts *visitOpts) (uint64, error) { | 107 | func (w *walker) visit(v reflect.Value, opts *visitOpts) (uint64, error) { |
108 | t := reflect.TypeOf(0) | ||
109 | |||
87 | // Loop since these can be wrapped in multiple layers of pointers | 110 | // Loop since these can be wrapped in multiple layers of pointers |
88 | // and interfaces. | 111 | // and interfaces. |
89 | for { | 112 | for { |
@@ -96,6 +119,9 @@ func (w *walker) visit(v reflect.Value, opts *visitOpts) (uint64, error) { | |||
96 | } | 119 | } |
97 | 120 | ||
98 | if v.Kind() == reflect.Ptr { | 121 | if v.Kind() == reflect.Ptr { |
122 | if w.zeronil { | ||
123 | t = v.Type().Elem() | ||
124 | } | ||
99 | v = reflect.Indirect(v) | 125 | v = reflect.Indirect(v) |
100 | continue | 126 | continue |
101 | } | 127 | } |
@@ -105,8 +131,7 @@ func (w *walker) visit(v reflect.Value, opts *visitOpts) (uint64, error) { | |||
105 | 131 | ||
106 | // If it is nil, treat it like a zero. | 132 | // If it is nil, treat it like a zero. |
107 | if !v.IsValid() { | 133 | if !v.IsValid() { |
108 | var tmp int8 | 134 | v = reflect.Zero(t) |
109 | v = reflect.ValueOf(tmp) | ||
110 | } | 135 | } |
111 | 136 | ||
112 | // Binary writing can use raw ints, we have to convert to | 137 | // Binary writing can use raw ints, we have to convert to |
@@ -189,8 +214,8 @@ func (w *walker) visit(v reflect.Value, opts *visitOpts) (uint64, error) { | |||
189 | return h, nil | 214 | return h, nil |
190 | 215 | ||
191 | case reflect.Struct: | 216 | case reflect.Struct: |
192 | var include Includable | ||
193 | parent := v.Interface() | 217 | parent := v.Interface() |
218 | var include Includable | ||
194 | if impl, ok := parent.(Includable); ok { | 219 | if impl, ok := parent.(Includable); ok { |
195 | include = impl | 220 | include = impl |
196 | } | 221 | } |
@@ -203,7 +228,7 @@ func (w *walker) visit(v reflect.Value, opts *visitOpts) (uint64, error) { | |||
203 | 228 | ||
204 | l := v.NumField() | 229 | l := v.NumField() |
205 | for i := 0; i < l; i++ { | 230 | for i := 0; i < l; i++ { |
206 | if v := v.Field(i); v.CanSet() || t.Field(i).Name != "_" { | 231 | if innerV := v.Field(i); v.CanSet() || t.Field(i).Name != "_" { |
207 | var f visitFlag | 232 | var f visitFlag |
208 | fieldType := t.Field(i) | 233 | fieldType := t.Field(i) |
209 | if fieldType.PkgPath != "" { | 234 | if fieldType.PkgPath != "" { |
@@ -212,14 +237,25 @@ func (w *walker) visit(v reflect.Value, opts *visitOpts) (uint64, error) { | |||
212 | } | 237 | } |
213 | 238 | ||
214 | tag := fieldType.Tag.Get(w.tag) | 239 | tag := fieldType.Tag.Get(w.tag) |
215 | if tag == "ignore" { | 240 | if tag == "ignore" || tag == "-" { |
216 | // Ignore this field | 241 | // Ignore this field |
217 | continue | 242 | continue |
218 | } | 243 | } |
219 | 244 | ||
245 | // if string is set, use the string value | ||
246 | if tag == "string" { | ||
247 | if impl, ok := innerV.Interface().(fmt.Stringer); ok { | ||
248 | innerV = reflect.ValueOf(impl.String()) | ||
249 | } else { | ||
250 | return 0, &ErrNotStringer{ | ||
251 | Field: v.Type().Field(i).Name, | ||
252 | } | ||
253 | } | ||
254 | } | ||
255 | |||
220 | // Check if we implement includable and check it | 256 | // Check if we implement includable and check it |
221 | if include != nil { | 257 | if include != nil { |
222 | incl, err := include.HashInclude(fieldType.Name, v) | 258 | incl, err := include.HashInclude(fieldType.Name, innerV) |
223 | if err != nil { | 259 | if err != nil { |
224 | return 0, err | 260 | return 0, err |
225 | } | 261 | } |
@@ -238,7 +274,7 @@ func (w *walker) visit(v reflect.Value, opts *visitOpts) (uint64, error) { | |||
238 | return 0, err | 274 | return 0, err |
239 | } | 275 | } |
240 | 276 | ||
241 | vh, err := w.visit(v, &visitOpts{ | 277 | vh, err := w.visit(innerV, &visitOpts{ |
242 | Flags: f, | 278 | Flags: f, |
243 | Struct: parent, | 279 | Struct: parent, |
244 | StructField: fieldType.Name, | 280 | StructField: fieldType.Name, |
@@ -289,7 +325,6 @@ func (w *walker) visit(v reflect.Value, opts *visitOpts) (uint64, error) { | |||
289 | return 0, fmt.Errorf("unknown kind to hash: %s", k) | 325 | return 0, fmt.Errorf("unknown kind to hash: %s", k) |
290 | } | 326 | } |
291 | 327 | ||
292 | return 0, nil | ||
293 | } | 328 | } |
294 | 329 | ||
295 | func hashUpdateOrdered(h hash.Hash64, a, b uint64) uint64 { | 330 | func hashUpdateOrdered(h hash.Hash64, a, b uint64) uint64 { |
diff --git a/vendor/github.com/mitchellh/mapstructure/.travis.yml b/vendor/github.com/mitchellh/mapstructure/.travis.yml index 7f3fe9a..1689c7d 100644 --- a/vendor/github.com/mitchellh/mapstructure/.travis.yml +++ b/vendor/github.com/mitchellh/mapstructure/.travis.yml | |||
@@ -1,7 +1,8 @@ | |||
1 | language: go | 1 | language: go |
2 | |||
3 | go: | ||
4 | - "1.11.x" | ||
5 | - tip | ||
2 | 6 | ||
3 | go: | ||
4 | - 1.4 | ||
5 | |||
6 | script: | 7 | script: |
7 | - go test | 8 | - go test |
diff --git a/vendor/github.com/mitchellh/mapstructure/CHANGELOG.md b/vendor/github.com/mitchellh/mapstructure/CHANGELOG.md new file mode 100644 index 0000000..3b3cb72 --- /dev/null +++ b/vendor/github.com/mitchellh/mapstructure/CHANGELOG.md | |||
@@ -0,0 +1,21 @@ | |||
1 | ## 1.1.2 | ||
2 | |||
3 | * Fix error when decode hook decodes interface implementation into interface | ||
4 | type. [GH-140] | ||
5 | |||
6 | ## 1.1.1 | ||
7 | |||
8 | * Fix panic that can happen in `decodePtr` | ||
9 | |||
10 | ## 1.1.0 | ||
11 | |||
12 | * Added `StringToIPHookFunc` to convert `string` to `net.IP` and `net.IPNet` [GH-133] | ||
13 | * Support struct to struct decoding [GH-137] | ||
14 | * If source map value is nil, then destination map value is nil (instead of empty) | ||
15 | * If source slice value is nil, then destination slice value is nil (instead of empty) | ||
16 | * If source pointer is nil, then destination pointer is set to nil (instead of | ||
17 | allocated zero value of type) | ||
18 | |||
19 | ## 1.0.0 | ||
20 | |||
21 | * Initial tagged stable release. | ||
diff --git a/vendor/github.com/mitchellh/mapstructure/README.md b/vendor/github.com/mitchellh/mapstructure/README.md index 659d688..0018dc7 100644 --- a/vendor/github.com/mitchellh/mapstructure/README.md +++ b/vendor/github.com/mitchellh/mapstructure/README.md | |||
@@ -1,4 +1,4 @@ | |||
1 | # mapstructure | 1 | # mapstructure [![Godoc](https://godoc.org/github.com/mitchellh/mapstructure?status.svg)](https://godoc.org/github.com/mitchellh/mapstructure) |
2 | 2 | ||
3 | mapstructure is a Go library for decoding generic map values to structures | 3 | mapstructure is a Go library for decoding generic map values to structures |
4 | and vice versa, while providing helpful error handling. | 4 | and vice versa, while providing helpful error handling. |
diff --git a/vendor/github.com/mitchellh/mapstructure/decode_hooks.go b/vendor/github.com/mitchellh/mapstructure/decode_hooks.go index 115ae67..1f0abc6 100644 --- a/vendor/github.com/mitchellh/mapstructure/decode_hooks.go +++ b/vendor/github.com/mitchellh/mapstructure/decode_hooks.go | |||
@@ -2,6 +2,8 @@ package mapstructure | |||
2 | 2 | ||
3 | import ( | 3 | import ( |
4 | "errors" | 4 | "errors" |
5 | "fmt" | ||
6 | "net" | ||
5 | "reflect" | 7 | "reflect" |
6 | "strconv" | 8 | "strconv" |
7 | "strings" | 9 | "strings" |
@@ -38,12 +40,6 @@ func DecodeHookExec( | |||
38 | raw DecodeHookFunc, | 40 | raw DecodeHookFunc, |
39 | from reflect.Type, to reflect.Type, | 41 | from reflect.Type, to reflect.Type, |
40 | data interface{}) (interface{}, error) { | 42 | data interface{}) (interface{}, error) { |
41 | // Build our arguments that reflect expects | ||
42 | argVals := make([]reflect.Value, 3) | ||
43 | argVals[0] = reflect.ValueOf(from) | ||
44 | argVals[1] = reflect.ValueOf(to) | ||
45 | argVals[2] = reflect.ValueOf(data) | ||
46 | |||
47 | switch f := typedDecodeHook(raw).(type) { | 43 | switch f := typedDecodeHook(raw).(type) { |
48 | case DecodeHookFuncType: | 44 | case DecodeHookFuncType: |
49 | return f(from, to, data) | 45 | return f(from, to, data) |
@@ -121,6 +117,74 @@ func StringToTimeDurationHookFunc() DecodeHookFunc { | |||
121 | } | 117 | } |
122 | } | 118 | } |
123 | 119 | ||
120 | // StringToIPHookFunc returns a DecodeHookFunc that converts | ||
121 | // strings to net.IP | ||
122 | func StringToIPHookFunc() DecodeHookFunc { | ||
123 | return func( | ||
124 | f reflect.Type, | ||
125 | t reflect.Type, | ||
126 | data interface{}) (interface{}, error) { | ||
127 | if f.Kind() != reflect.String { | ||
128 | return data, nil | ||
129 | } | ||
130 | if t != reflect.TypeOf(net.IP{}) { | ||
131 | return data, nil | ||
132 | } | ||
133 | |||
134 | // Convert it by parsing | ||
135 | ip := net.ParseIP(data.(string)) | ||
136 | if ip == nil { | ||
137 | return net.IP{}, fmt.Errorf("failed parsing ip %v", data) | ||
138 | } | ||
139 | |||
140 | return ip, nil | ||
141 | } | ||
142 | } | ||
143 | |||
144 | // StringToIPNetHookFunc returns a DecodeHookFunc that converts | ||
145 | // strings to net.IPNet | ||
146 | func StringToIPNetHookFunc() DecodeHookFunc { | ||
147 | return func( | ||
148 | f reflect.Type, | ||
149 | t reflect.Type, | ||
150 | data interface{}) (interface{}, error) { | ||
151 | if f.Kind() != reflect.String { | ||
152 | return data, nil | ||
153 | } | ||
154 | if t != reflect.TypeOf(net.IPNet{}) { | ||
155 | return data, nil | ||
156 | } | ||
157 | |||
158 | // Convert it by parsing | ||
159 | _, net, err := net.ParseCIDR(data.(string)) | ||
160 | return net, err | ||
161 | } | ||
162 | } | ||
163 | |||
164 | // StringToTimeHookFunc returns a DecodeHookFunc that converts | ||
165 | // strings to time.Time. | ||
166 | func StringToTimeHookFunc(layout string) DecodeHookFunc { | ||
167 | return func( | ||
168 | f reflect.Type, | ||
169 | t reflect.Type, | ||
170 | data interface{}) (interface{}, error) { | ||
171 | if f.Kind() != reflect.String { | ||
172 | return data, nil | ||
173 | } | ||
174 | if t != reflect.TypeOf(time.Time{}) { | ||
175 | return data, nil | ||
176 | } | ||
177 | |||
178 | // Convert it by parsing | ||
179 | return time.Parse(layout, data.(string)) | ||
180 | } | ||
181 | } | ||
182 | |||
183 | // WeaklyTypedHook is a DecodeHookFunc which adds support for weak typing to | ||
184 | // the decoder. | ||
185 | // | ||
186 | // Note that this is significantly different from the WeaklyTypedInput option | ||
187 | // of the DecoderConfig. | ||
124 | func WeaklyTypedHook( | 188 | func WeaklyTypedHook( |
125 | f reflect.Kind, | 189 | f reflect.Kind, |
126 | t reflect.Kind, | 190 | t reflect.Kind, |
@@ -132,9 +196,8 @@ func WeaklyTypedHook( | |||
132 | case reflect.Bool: | 196 | case reflect.Bool: |
133 | if dataVal.Bool() { | 197 | if dataVal.Bool() { |
134 | return "1", nil | 198 | return "1", nil |
135 | } else { | ||
136 | return "0", nil | ||
137 | } | 199 | } |
200 | return "0", nil | ||
138 | case reflect.Float32: | 201 | case reflect.Float32: |
139 | return strconv.FormatFloat(dataVal.Float(), 'f', -1, 64), nil | 202 | return strconv.FormatFloat(dataVal.Float(), 'f', -1, 64), nil |
140 | case reflect.Int: | 203 | case reflect.Int: |
diff --git a/vendor/github.com/mitchellh/mapstructure/go.mod b/vendor/github.com/mitchellh/mapstructure/go.mod new file mode 100644 index 0000000..d2a7125 --- /dev/null +++ b/vendor/github.com/mitchellh/mapstructure/go.mod | |||
@@ -0,0 +1 @@ | |||
module github.com/mitchellh/mapstructure | |||
diff --git a/vendor/github.com/mitchellh/mapstructure/mapstructure.go b/vendor/github.com/mitchellh/mapstructure/mapstructure.go index 6dee0ef..256ee63 100644 --- a/vendor/github.com/mitchellh/mapstructure/mapstructure.go +++ b/vendor/github.com/mitchellh/mapstructure/mapstructure.go | |||
@@ -1,5 +1,5 @@ | |||
1 | // The mapstructure package exposes functionality to convert an | 1 | // Package mapstructure exposes functionality to convert an arbitrary |
2 | // arbitrary map[string]interface{} into a native Go structure. | 2 | // map[string]interface{} into a native Go structure. |
3 | // | 3 | // |
4 | // The Go structure can be arbitrarily complex, containing slices, | 4 | // The Go structure can be arbitrarily complex, containing slices, |
5 | // other structs, etc. and the decoder will properly decode nested | 5 | // other structs, etc. and the decoder will properly decode nested |
@@ -32,7 +32,12 @@ import ( | |||
32 | // both. | 32 | // both. |
33 | type DecodeHookFunc interface{} | 33 | type DecodeHookFunc interface{} |
34 | 34 | ||
35 | // DecodeHookFuncType is a DecodeHookFunc which has complete information about | ||
36 | // the source and target types. | ||
35 | type DecodeHookFuncType func(reflect.Type, reflect.Type, interface{}) (interface{}, error) | 37 | type DecodeHookFuncType func(reflect.Type, reflect.Type, interface{}) (interface{}, error) |
38 | |||
39 | // DecodeHookFuncKind is a DecodeHookFunc which knows only the Kinds of the | ||
40 | // source and target types. | ||
36 | type DecodeHookFuncKind func(reflect.Kind, reflect.Kind, interface{}) (interface{}, error) | 41 | type DecodeHookFuncKind func(reflect.Kind, reflect.Kind, interface{}) (interface{}, error) |
37 | 42 | ||
38 | // DecoderConfig is the configuration that is used to create a new decoder | 43 | // DecoderConfig is the configuration that is used to create a new decoder |
@@ -109,12 +114,12 @@ type Metadata struct { | |||
109 | Unused []string | 114 | Unused []string |
110 | } | 115 | } |
111 | 116 | ||
112 | // Decode takes a map and uses reflection to convert it into the | 117 | // Decode takes an input structure and uses reflection to translate it to |
113 | // given Go native structure. val must be a pointer to a struct. | 118 | // the output structure. output must be a pointer to a map or struct. |
114 | func Decode(m interface{}, rawVal interface{}) error { | 119 | func Decode(input interface{}, output interface{}) error { |
115 | config := &DecoderConfig{ | 120 | config := &DecoderConfig{ |
116 | Metadata: nil, | 121 | Metadata: nil, |
117 | Result: rawVal, | 122 | Result: output, |
118 | } | 123 | } |
119 | 124 | ||
120 | decoder, err := NewDecoder(config) | 125 | decoder, err := NewDecoder(config) |
@@ -122,7 +127,7 @@ func Decode(m interface{}, rawVal interface{}) error { | |||
122 | return err | 127 | return err |
123 | } | 128 | } |
124 | 129 | ||
125 | return decoder.Decode(m) | 130 | return decoder.Decode(input) |
126 | } | 131 | } |
127 | 132 | ||
128 | // WeakDecode is the same as Decode but is shorthand to enable | 133 | // WeakDecode is the same as Decode but is shorthand to enable |
@@ -142,6 +147,40 @@ func WeakDecode(input, output interface{}) error { | |||
142 | return decoder.Decode(input) | 147 | return decoder.Decode(input) |
143 | } | 148 | } |
144 | 149 | ||
150 | // DecodeMetadata is the same as Decode, but is shorthand to | ||
151 | // enable metadata collection. See DecoderConfig for more info. | ||
152 | func DecodeMetadata(input interface{}, output interface{}, metadata *Metadata) error { | ||
153 | config := &DecoderConfig{ | ||
154 | Metadata: metadata, | ||
155 | Result: output, | ||
156 | } | ||
157 | |||
158 | decoder, err := NewDecoder(config) | ||
159 | if err != nil { | ||
160 | return err | ||
161 | } | ||
162 | |||
163 | return decoder.Decode(input) | ||
164 | } | ||
165 | |||
166 | // WeakDecodeMetadata is the same as Decode, but is shorthand to | ||
167 | // enable both WeaklyTypedInput and metadata collection. See | ||
168 | // DecoderConfig for more info. | ||
169 | func WeakDecodeMetadata(input interface{}, output interface{}, metadata *Metadata) error { | ||
170 | config := &DecoderConfig{ | ||
171 | Metadata: metadata, | ||
172 | Result: output, | ||
173 | WeaklyTypedInput: true, | ||
174 | } | ||
175 | |||
176 | decoder, err := NewDecoder(config) | ||
177 | if err != nil { | ||
178 | return err | ||
179 | } | ||
180 | |||
181 | return decoder.Decode(input) | ||
182 | } | ||
183 | |||
145 | // NewDecoder returns a new decoder for the given configuration. Once | 184 | // NewDecoder returns a new decoder for the given configuration. Once |
146 | // a decoder has been returned, the same configuration must not be used | 185 | // a decoder has been returned, the same configuration must not be used |
147 | // again. | 186 | // again. |
@@ -179,68 +218,91 @@ func NewDecoder(config *DecoderConfig) (*Decoder, error) { | |||
179 | 218 | ||
180 | // Decode decodes the given raw interface to the target pointer specified | 219 | // Decode decodes the given raw interface to the target pointer specified |
181 | // by the configuration. | 220 | // by the configuration. |
182 | func (d *Decoder) Decode(raw interface{}) error { | 221 | func (d *Decoder) Decode(input interface{}) error { |
183 | return d.decode("", raw, reflect.ValueOf(d.config.Result).Elem()) | 222 | return d.decode("", input, reflect.ValueOf(d.config.Result).Elem()) |
184 | } | 223 | } |
185 | 224 | ||
186 | // Decodes an unknown data type into a specific reflection value. | 225 | // Decodes an unknown data type into a specific reflection value. |
187 | func (d *Decoder) decode(name string, data interface{}, val reflect.Value) error { | 226 | func (d *Decoder) decode(name string, input interface{}, outVal reflect.Value) error { |
188 | if data == nil { | 227 | var inputVal reflect.Value |
189 | // If the data is nil, then we don't set anything. | 228 | if input != nil { |
229 | inputVal = reflect.ValueOf(input) | ||
230 | |||
231 | // We need to check here if input is a typed nil. Typed nils won't | ||
232 | // match the "input == nil" below so we check that here. | ||
233 | if inputVal.Kind() == reflect.Ptr && inputVal.IsNil() { | ||
234 | input = nil | ||
235 | } | ||
236 | } | ||
237 | |||
238 | if input == nil { | ||
239 | // If the data is nil, then we don't set anything, unless ZeroFields is set | ||
240 | // to true. | ||
241 | if d.config.ZeroFields { | ||
242 | outVal.Set(reflect.Zero(outVal.Type())) | ||
243 | |||
244 | if d.config.Metadata != nil && name != "" { | ||
245 | d.config.Metadata.Keys = append(d.config.Metadata.Keys, name) | ||
246 | } | ||
247 | } | ||
190 | return nil | 248 | return nil |
191 | } | 249 | } |
192 | 250 | ||
193 | dataVal := reflect.ValueOf(data) | 251 | if !inputVal.IsValid() { |
194 | if !dataVal.IsValid() { | 252 | // If the input value is invalid, then we just set the value |
195 | // If the data value is invalid, then we just set the value | ||
196 | // to be the zero value. | 253 | // to be the zero value. |
197 | val.Set(reflect.Zero(val.Type())) | 254 | outVal.Set(reflect.Zero(outVal.Type())) |
255 | if d.config.Metadata != nil && name != "" { | ||
256 | d.config.Metadata.Keys = append(d.config.Metadata.Keys, name) | ||
257 | } | ||
198 | return nil | 258 | return nil |
199 | } | 259 | } |
200 | 260 | ||
201 | if d.config.DecodeHook != nil { | 261 | if d.config.DecodeHook != nil { |
202 | // We have a DecodeHook, so let's pre-process the data. | 262 | // We have a DecodeHook, so let's pre-process the input. |
203 | var err error | 263 | var err error |
204 | data, err = DecodeHookExec( | 264 | input, err = DecodeHookExec( |
205 | d.config.DecodeHook, | 265 | d.config.DecodeHook, |
206 | dataVal.Type(), val.Type(), data) | 266 | inputVal.Type(), outVal.Type(), input) |
207 | if err != nil { | 267 | if err != nil { |
208 | return fmt.Errorf("error decoding '%s': %s", name, err) | 268 | return fmt.Errorf("error decoding '%s': %s", name, err) |
209 | } | 269 | } |
210 | } | 270 | } |
211 | 271 | ||
212 | var err error | 272 | var err error |
213 | dataKind := getKind(val) | 273 | outputKind := getKind(outVal) |
214 | switch dataKind { | 274 | switch outputKind { |
215 | case reflect.Bool: | 275 | case reflect.Bool: |
216 | err = d.decodeBool(name, data, val) | 276 | err = d.decodeBool(name, input, outVal) |
217 | case reflect.Interface: | 277 | case reflect.Interface: |
218 | err = d.decodeBasic(name, data, val) | 278 | err = d.decodeBasic(name, input, outVal) |
219 | case reflect.String: | 279 | case reflect.String: |
220 | err = d.decodeString(name, data, val) | 280 | err = d.decodeString(name, input, outVal) |
221 | case reflect.Int: | 281 | case reflect.Int: |
222 | err = d.decodeInt(name, data, val) | 282 | err = d.decodeInt(name, input, outVal) |
223 | case reflect.Uint: | 283 | case reflect.Uint: |
224 | err = d.decodeUint(name, data, val) | 284 | err = d.decodeUint(name, input, outVal) |
225 | case reflect.Float32: | 285 | case reflect.Float32: |
226 | err = d.decodeFloat(name, data, val) | 286 | err = d.decodeFloat(name, input, outVal) |
227 | case reflect.Struct: | 287 | case reflect.Struct: |
228 | err = d.decodeStruct(name, data, val) | 288 | err = d.decodeStruct(name, input, outVal) |
229 | case reflect.Map: | 289 | case reflect.Map: |
230 | err = d.decodeMap(name, data, val) | 290 | err = d.decodeMap(name, input, outVal) |
231 | case reflect.Ptr: | 291 | case reflect.Ptr: |
232 | err = d.decodePtr(name, data, val) | 292 | err = d.decodePtr(name, input, outVal) |
233 | case reflect.Slice: | 293 | case reflect.Slice: |
234 | err = d.decodeSlice(name, data, val) | 294 | err = d.decodeSlice(name, input, outVal) |
295 | case reflect.Array: | ||
296 | err = d.decodeArray(name, input, outVal) | ||
235 | case reflect.Func: | 297 | case reflect.Func: |
236 | err = d.decodeFunc(name, data, val) | 298 | err = d.decodeFunc(name, input, outVal) |
237 | default: | 299 | default: |
238 | // If we reached this point then we weren't able to decode it | 300 | // If we reached this point then we weren't able to decode it |
239 | return fmt.Errorf("%s: unsupported type: %s", name, dataKind) | 301 | return fmt.Errorf("%s: unsupported type: %s", name, outputKind) |
240 | } | 302 | } |
241 | 303 | ||
242 | // If we reached here, then we successfully decoded SOMETHING, so | 304 | // If we reached here, then we successfully decoded SOMETHING, so |
243 | // mark the key as used if we're tracking metadata. | 305 | // mark the key as used if we're tracking metainput. |
244 | if d.config.Metadata != nil && name != "" { | 306 | if d.config.Metadata != nil && name != "" { |
245 | d.config.Metadata.Keys = append(d.config.Metadata.Keys, name) | 307 | d.config.Metadata.Keys = append(d.config.Metadata.Keys, name) |
246 | } | 308 | } |
@@ -251,7 +313,19 @@ func (d *Decoder) decode(name string, data interface{}, val reflect.Value) error | |||
251 | // This decodes a basic type (bool, int, string, etc.) and sets the | 313 | // This decodes a basic type (bool, int, string, etc.) and sets the |
252 | // value to "data" of that type. | 314 | // value to "data" of that type. |
253 | func (d *Decoder) decodeBasic(name string, data interface{}, val reflect.Value) error { | 315 | func (d *Decoder) decodeBasic(name string, data interface{}, val reflect.Value) error { |
316 | if val.IsValid() && val.Elem().IsValid() { | ||
317 | return d.decode(name, data, val.Elem()) | ||
318 | } | ||
319 | |||
254 | dataVal := reflect.ValueOf(data) | 320 | dataVal := reflect.ValueOf(data) |
321 | |||
322 | // If the input data is a pointer, and the assigned type is the dereference | ||
323 | // of that exact pointer, then indirect it so that we can assign it. | ||
324 | // Example: *string to string | ||
325 | if dataVal.Kind() == reflect.Ptr && dataVal.Type().Elem() == val.Type() { | ||
326 | dataVal = reflect.Indirect(dataVal) | ||
327 | } | ||
328 | |||
255 | if !dataVal.IsValid() { | 329 | if !dataVal.IsValid() { |
256 | dataVal = reflect.Zero(val.Type()) | 330 | dataVal = reflect.Zero(val.Type()) |
257 | } | 331 | } |
@@ -268,7 +342,7 @@ func (d *Decoder) decodeBasic(name string, data interface{}, val reflect.Value) | |||
268 | } | 342 | } |
269 | 343 | ||
270 | func (d *Decoder) decodeString(name string, data interface{}, val reflect.Value) error { | 344 | func (d *Decoder) decodeString(name string, data interface{}, val reflect.Value) error { |
271 | dataVal := reflect.ValueOf(data) | 345 | dataVal := reflect.Indirect(reflect.ValueOf(data)) |
272 | dataKind := getKind(dataVal) | 346 | dataKind := getKind(dataVal) |
273 | 347 | ||
274 | converted := true | 348 | converted := true |
@@ -287,12 +361,22 @@ func (d *Decoder) decodeString(name string, data interface{}, val reflect.Value) | |||
287 | val.SetString(strconv.FormatUint(dataVal.Uint(), 10)) | 361 | val.SetString(strconv.FormatUint(dataVal.Uint(), 10)) |
288 | case dataKind == reflect.Float32 && d.config.WeaklyTypedInput: | 362 | case dataKind == reflect.Float32 && d.config.WeaklyTypedInput: |
289 | val.SetString(strconv.FormatFloat(dataVal.Float(), 'f', -1, 64)) | 363 | val.SetString(strconv.FormatFloat(dataVal.Float(), 'f', -1, 64)) |
290 | case dataKind == reflect.Slice && d.config.WeaklyTypedInput: | 364 | case dataKind == reflect.Slice && d.config.WeaklyTypedInput, |
365 | dataKind == reflect.Array && d.config.WeaklyTypedInput: | ||
291 | dataType := dataVal.Type() | 366 | dataType := dataVal.Type() |
292 | elemKind := dataType.Elem().Kind() | 367 | elemKind := dataType.Elem().Kind() |
293 | switch { | 368 | switch elemKind { |
294 | case elemKind == reflect.Uint8: | 369 | case reflect.Uint8: |
295 | val.SetString(string(dataVal.Interface().([]uint8))) | 370 | var uints []uint8 |
371 | if dataKind == reflect.Array { | ||
372 | uints = make([]uint8, dataVal.Len(), dataVal.Len()) | ||
373 | for i := range uints { | ||
374 | uints[i] = dataVal.Index(i).Interface().(uint8) | ||
375 | } | ||
376 | } else { | ||
377 | uints = dataVal.Interface().([]uint8) | ||
378 | } | ||
379 | val.SetString(string(uints)) | ||
296 | default: | 380 | default: |
297 | converted = false | 381 | converted = false |
298 | } | 382 | } |
@@ -310,7 +394,7 @@ func (d *Decoder) decodeString(name string, data interface{}, val reflect.Value) | |||
310 | } | 394 | } |
311 | 395 | ||
312 | func (d *Decoder) decodeInt(name string, data interface{}, val reflect.Value) error { | 396 | func (d *Decoder) decodeInt(name string, data interface{}, val reflect.Value) error { |
313 | dataVal := reflect.ValueOf(data) | 397 | dataVal := reflect.Indirect(reflect.ValueOf(data)) |
314 | dataKind := getKind(dataVal) | 398 | dataKind := getKind(dataVal) |
315 | dataType := dataVal.Type() | 399 | dataType := dataVal.Type() |
316 | 400 | ||
@@ -352,7 +436,7 @@ func (d *Decoder) decodeInt(name string, data interface{}, val reflect.Value) er | |||
352 | } | 436 | } |
353 | 437 | ||
354 | func (d *Decoder) decodeUint(name string, data interface{}, val reflect.Value) error { | 438 | func (d *Decoder) decodeUint(name string, data interface{}, val reflect.Value) error { |
355 | dataVal := reflect.ValueOf(data) | 439 | dataVal := reflect.Indirect(reflect.ValueOf(data)) |
356 | dataKind := getKind(dataVal) | 440 | dataKind := getKind(dataVal) |
357 | 441 | ||
358 | switch { | 442 | switch { |
@@ -395,7 +479,7 @@ func (d *Decoder) decodeUint(name string, data interface{}, val reflect.Value) e | |||
395 | } | 479 | } |
396 | 480 | ||
397 | func (d *Decoder) decodeBool(name string, data interface{}, val reflect.Value) error { | 481 | func (d *Decoder) decodeBool(name string, data interface{}, val reflect.Value) error { |
398 | dataVal := reflect.ValueOf(data) | 482 | dataVal := reflect.Indirect(reflect.ValueOf(data)) |
399 | dataKind := getKind(dataVal) | 483 | dataKind := getKind(dataVal) |
400 | 484 | ||
401 | switch { | 485 | switch { |
@@ -426,7 +510,7 @@ func (d *Decoder) decodeBool(name string, data interface{}, val reflect.Value) e | |||
426 | } | 510 | } |
427 | 511 | ||
428 | func (d *Decoder) decodeFloat(name string, data interface{}, val reflect.Value) error { | 512 | func (d *Decoder) decodeFloat(name string, data interface{}, val reflect.Value) error { |
429 | dataVal := reflect.ValueOf(data) | 513 | dataVal := reflect.Indirect(reflect.ValueOf(data)) |
430 | dataKind := getKind(dataVal) | 514 | dataKind := getKind(dataVal) |
431 | dataType := dataVal.Type() | 515 | dataType := dataVal.Type() |
432 | 516 | ||
@@ -436,7 +520,7 @@ func (d *Decoder) decodeFloat(name string, data interface{}, val reflect.Value) | |||
436 | case dataKind == reflect.Uint: | 520 | case dataKind == reflect.Uint: |
437 | val.SetFloat(float64(dataVal.Uint())) | 521 | val.SetFloat(float64(dataVal.Uint())) |
438 | case dataKind == reflect.Float32: | 522 | case dataKind == reflect.Float32: |
439 | val.SetFloat(float64(dataVal.Float())) | 523 | val.SetFloat(dataVal.Float()) |
440 | case dataKind == reflect.Bool && d.config.WeaklyTypedInput: | 524 | case dataKind == reflect.Bool && d.config.WeaklyTypedInput: |
441 | if dataVal.Bool() { | 525 | if dataVal.Bool() { |
442 | val.SetFloat(1) | 526 | val.SetFloat(1) |
@@ -482,38 +566,68 @@ func (d *Decoder) decodeMap(name string, data interface{}, val reflect.Value) er | |||
482 | valMap = reflect.MakeMap(mapType) | 566 | valMap = reflect.MakeMap(mapType) |
483 | } | 567 | } |
484 | 568 | ||
485 | // Check input type | 569 | // Check input type and based on the input type jump to the proper func |
486 | dataVal := reflect.Indirect(reflect.ValueOf(data)) | 570 | dataVal := reflect.Indirect(reflect.ValueOf(data)) |
487 | if dataVal.Kind() != reflect.Map { | 571 | switch dataVal.Kind() { |
488 | // In weak mode, we accept a slice of maps as an input... | 572 | case reflect.Map: |
489 | if d.config.WeaklyTypedInput { | 573 | return d.decodeMapFromMap(name, dataVal, val, valMap) |
490 | switch dataVal.Kind() { | ||
491 | case reflect.Array, reflect.Slice: | ||
492 | // Special case for BC reasons (covered by tests) | ||
493 | if dataVal.Len() == 0 { | ||
494 | val.Set(valMap) | ||
495 | return nil | ||
496 | } | ||
497 | 574 | ||
498 | for i := 0; i < dataVal.Len(); i++ { | 575 | case reflect.Struct: |
499 | err := d.decode( | 576 | return d.decodeMapFromStruct(name, dataVal, val, valMap) |
500 | fmt.Sprintf("%s[%d]", name, i), | ||
501 | dataVal.Index(i).Interface(), val) | ||
502 | if err != nil { | ||
503 | return err | ||
504 | } | ||
505 | } | ||
506 | 577 | ||
507 | return nil | 578 | case reflect.Array, reflect.Slice: |
508 | } | 579 | if d.config.WeaklyTypedInput { |
580 | return d.decodeMapFromSlice(name, dataVal, val, valMap) | ||
509 | } | 581 | } |
510 | 582 | ||
583 | fallthrough | ||
584 | |||
585 | default: | ||
511 | return fmt.Errorf("'%s' expected a map, got '%s'", name, dataVal.Kind()) | 586 | return fmt.Errorf("'%s' expected a map, got '%s'", name, dataVal.Kind()) |
512 | } | 587 | } |
588 | } | ||
589 | |||
590 | func (d *Decoder) decodeMapFromSlice(name string, dataVal reflect.Value, val reflect.Value, valMap reflect.Value) error { | ||
591 | // Special case for BC reasons (covered by tests) | ||
592 | if dataVal.Len() == 0 { | ||
593 | val.Set(valMap) | ||
594 | return nil | ||
595 | } | ||
596 | |||
597 | for i := 0; i < dataVal.Len(); i++ { | ||
598 | err := d.decode( | ||
599 | fmt.Sprintf("%s[%d]", name, i), | ||
600 | dataVal.Index(i).Interface(), val) | ||
601 | if err != nil { | ||
602 | return err | ||
603 | } | ||
604 | } | ||
605 | |||
606 | return nil | ||
607 | } | ||
608 | |||
609 | func (d *Decoder) decodeMapFromMap(name string, dataVal reflect.Value, val reflect.Value, valMap reflect.Value) error { | ||
610 | valType := val.Type() | ||
611 | valKeyType := valType.Key() | ||
612 | valElemType := valType.Elem() | ||
513 | 613 | ||
514 | // Accumulate errors | 614 | // Accumulate errors |
515 | errors := make([]string, 0) | 615 | errors := make([]string, 0) |
516 | 616 | ||
617 | // If the input data is empty, then we just match what the input data is. | ||
618 | if dataVal.Len() == 0 { | ||
619 | if dataVal.IsNil() { | ||
620 | if !val.IsNil() { | ||
621 | val.Set(dataVal) | ||
622 | } | ||
623 | } else { | ||
624 | // Set to empty allocated value | ||
625 | val.Set(valMap) | ||
626 | } | ||
627 | |||
628 | return nil | ||
629 | } | ||
630 | |||
517 | for _, k := range dataVal.MapKeys() { | 631 | for _, k := range dataVal.MapKeys() { |
518 | fieldName := fmt.Sprintf("%s[%s]", name, k) | 632 | fieldName := fmt.Sprintf("%s[%s]", name, k) |
519 | 633 | ||
@@ -546,22 +660,128 @@ func (d *Decoder) decodeMap(name string, data interface{}, val reflect.Value) er | |||
546 | return nil | 660 | return nil |
547 | } | 661 | } |
548 | 662 | ||
663 | func (d *Decoder) decodeMapFromStruct(name string, dataVal reflect.Value, val reflect.Value, valMap reflect.Value) error { | ||
664 | typ := dataVal.Type() | ||
665 | for i := 0; i < typ.NumField(); i++ { | ||
666 | // Get the StructField first since this is a cheap operation. If the | ||
667 | // field is unexported, then ignore it. | ||
668 | f := typ.Field(i) | ||
669 | if f.PkgPath != "" { | ||
670 | continue | ||
671 | } | ||
672 | |||
673 | // Next get the actual value of this field and verify it is assignable | ||
674 | // to the map value. | ||
675 | v := dataVal.Field(i) | ||
676 | if !v.Type().AssignableTo(valMap.Type().Elem()) { | ||
677 | return fmt.Errorf("cannot assign type '%s' to map value field of type '%s'", v.Type(), valMap.Type().Elem()) | ||
678 | } | ||
679 | |||
680 | tagValue := f.Tag.Get(d.config.TagName) | ||
681 | tagParts := strings.Split(tagValue, ",") | ||
682 | |||
683 | // Determine the name of the key in the map | ||
684 | keyName := f.Name | ||
685 | if tagParts[0] != "" { | ||
686 | if tagParts[0] == "-" { | ||
687 | continue | ||
688 | } | ||
689 | keyName = tagParts[0] | ||
690 | } | ||
691 | |||
692 | // If "squash" is specified in the tag, we squash the field down. | ||
693 | squash := false | ||
694 | for _, tag := range tagParts[1:] { | ||
695 | if tag == "squash" { | ||
696 | squash = true | ||
697 | break | ||
698 | } | ||
699 | } | ||
700 | if squash && v.Kind() != reflect.Struct { | ||
701 | return fmt.Errorf("cannot squash non-struct type '%s'", v.Type()) | ||
702 | } | ||
703 | |||
704 | switch v.Kind() { | ||
705 | // this is an embedded struct, so handle it differently | ||
706 | case reflect.Struct: | ||
707 | x := reflect.New(v.Type()) | ||
708 | x.Elem().Set(v) | ||
709 | |||
710 | vType := valMap.Type() | ||
711 | vKeyType := vType.Key() | ||
712 | vElemType := vType.Elem() | ||
713 | mType := reflect.MapOf(vKeyType, vElemType) | ||
714 | vMap := reflect.MakeMap(mType) | ||
715 | |||
716 | err := d.decode(keyName, x.Interface(), vMap) | ||
717 | if err != nil { | ||
718 | return err | ||
719 | } | ||
720 | |||
721 | if squash { | ||
722 | for _, k := range vMap.MapKeys() { | ||
723 | valMap.SetMapIndex(k, vMap.MapIndex(k)) | ||
724 | } | ||
725 | } else { | ||
726 | valMap.SetMapIndex(reflect.ValueOf(keyName), vMap) | ||
727 | } | ||
728 | |||
729 | default: | ||
730 | valMap.SetMapIndex(reflect.ValueOf(keyName), v) | ||
731 | } | ||
732 | } | ||
733 | |||
734 | if val.CanAddr() { | ||
735 | val.Set(valMap) | ||
736 | } | ||
737 | |||
738 | return nil | ||
739 | } | ||
740 | |||
549 | func (d *Decoder) decodePtr(name string, data interface{}, val reflect.Value) error { | 741 | func (d *Decoder) decodePtr(name string, data interface{}, val reflect.Value) error { |
742 | // If the input data is nil, then we want to just set the output | ||
743 | // pointer to be nil as well. | ||
744 | isNil := data == nil | ||
745 | if !isNil { | ||
746 | switch v := reflect.Indirect(reflect.ValueOf(data)); v.Kind() { | ||
747 | case reflect.Chan, | ||
748 | reflect.Func, | ||
749 | reflect.Interface, | ||
750 | reflect.Map, | ||
751 | reflect.Ptr, | ||
752 | reflect.Slice: | ||
753 | isNil = v.IsNil() | ||
754 | } | ||
755 | } | ||
756 | if isNil { | ||
757 | if !val.IsNil() && val.CanSet() { | ||
758 | nilValue := reflect.New(val.Type()).Elem() | ||
759 | val.Set(nilValue) | ||
760 | } | ||
761 | |||
762 | return nil | ||
763 | } | ||
764 | |||
550 | // Create an element of the concrete (non pointer) type and decode | 765 | // Create an element of the concrete (non pointer) type and decode |
551 | // into that. Then set the value of the pointer to this type. | 766 | // into that. Then set the value of the pointer to this type. |
552 | valType := val.Type() | 767 | valType := val.Type() |
553 | valElemType := valType.Elem() | 768 | valElemType := valType.Elem() |
769 | if val.CanSet() { | ||
770 | realVal := val | ||
771 | if realVal.IsNil() || d.config.ZeroFields { | ||
772 | realVal = reflect.New(valElemType) | ||
773 | } | ||
554 | 774 | ||
555 | realVal := val | 775 | if err := d.decode(name, data, reflect.Indirect(realVal)); err != nil { |
556 | if realVal.IsNil() || d.config.ZeroFields { | 776 | return err |
557 | realVal = reflect.New(valElemType) | 777 | } |
558 | } | ||
559 | 778 | ||
560 | if err := d.decode(name, data, reflect.Indirect(realVal)); err != nil { | 779 | val.Set(realVal) |
561 | return err | 780 | } else { |
781 | if err := d.decode(name, data, reflect.Indirect(val)); err != nil { | ||
782 | return err | ||
783 | } | ||
562 | } | 784 | } |
563 | |||
564 | val.Set(realVal) | ||
565 | return nil | 785 | return nil |
566 | } | 786 | } |
567 | 787 | ||
@@ -587,22 +807,101 @@ func (d *Decoder) decodeSlice(name string, data interface{}, val reflect.Value) | |||
587 | 807 | ||
588 | valSlice := val | 808 | valSlice := val |
589 | if valSlice.IsNil() || d.config.ZeroFields { | 809 | if valSlice.IsNil() || d.config.ZeroFields { |
810 | if d.config.WeaklyTypedInput { | ||
811 | switch { | ||
812 | // Slice and array we use the normal logic | ||
813 | case dataValKind == reflect.Slice, dataValKind == reflect.Array: | ||
814 | break | ||
815 | |||
816 | // Empty maps turn into empty slices | ||
817 | case dataValKind == reflect.Map: | ||
818 | if dataVal.Len() == 0 { | ||
819 | val.Set(reflect.MakeSlice(sliceType, 0, 0)) | ||
820 | return nil | ||
821 | } | ||
822 | // Create slice of maps of other sizes | ||
823 | return d.decodeSlice(name, []interface{}{data}, val) | ||
824 | |||
825 | case dataValKind == reflect.String && valElemType.Kind() == reflect.Uint8: | ||
826 | return d.decodeSlice(name, []byte(dataVal.String()), val) | ||
827 | |||
828 | // All other types we try to convert to the slice type | ||
829 | // and "lift" it into it. i.e. a string becomes a string slice. | ||
830 | default: | ||
831 | // Just re-try this function with data as a slice. | ||
832 | return d.decodeSlice(name, []interface{}{data}, val) | ||
833 | } | ||
834 | } | ||
835 | |||
836 | // Check input type | ||
837 | if dataValKind != reflect.Array && dataValKind != reflect.Slice { | ||
838 | return fmt.Errorf( | ||
839 | "'%s': source data must be an array or slice, got %s", name, dataValKind) | ||
840 | |||
841 | } | ||
842 | |||
843 | // If the input value is empty, then don't allocate since non-nil != nil | ||
844 | if dataVal.Len() == 0 { | ||
845 | return nil | ||
846 | } | ||
847 | |||
848 | // Make a new slice to hold our result, same size as the original data. | ||
849 | valSlice = reflect.MakeSlice(sliceType, dataVal.Len(), dataVal.Len()) | ||
850 | } | ||
851 | |||
852 | // Accumulate any errors | ||
853 | errors := make([]string, 0) | ||
854 | |||
855 | for i := 0; i < dataVal.Len(); i++ { | ||
856 | currentData := dataVal.Index(i).Interface() | ||
857 | for valSlice.Len() <= i { | ||
858 | valSlice = reflect.Append(valSlice, reflect.Zero(valElemType)) | ||
859 | } | ||
860 | currentField := valSlice.Index(i) | ||
861 | |||
862 | fieldName := fmt.Sprintf("%s[%d]", name, i) | ||
863 | if err := d.decode(fieldName, currentData, currentField); err != nil { | ||
864 | errors = appendErrors(errors, err) | ||
865 | } | ||
866 | } | ||
867 | |||
868 | // Finally, set the value to the slice we built up | ||
869 | val.Set(valSlice) | ||
870 | |||
871 | // If there were errors, we return those | ||
872 | if len(errors) > 0 { | ||
873 | return &Error{errors} | ||
874 | } | ||
875 | |||
876 | return nil | ||
877 | } | ||
878 | |||
879 | func (d *Decoder) decodeArray(name string, data interface{}, val reflect.Value) error { | ||
880 | dataVal := reflect.Indirect(reflect.ValueOf(data)) | ||
881 | dataValKind := dataVal.Kind() | ||
882 | valType := val.Type() | ||
883 | valElemType := valType.Elem() | ||
884 | arrayType := reflect.ArrayOf(valType.Len(), valElemType) | ||
885 | |||
886 | valArray := val | ||
887 | |||
888 | if valArray.Interface() == reflect.Zero(valArray.Type()).Interface() || d.config.ZeroFields { | ||
590 | // Check input type | 889 | // Check input type |
591 | if dataValKind != reflect.Array && dataValKind != reflect.Slice { | 890 | if dataValKind != reflect.Array && dataValKind != reflect.Slice { |
592 | if d.config.WeaklyTypedInput { | 891 | if d.config.WeaklyTypedInput { |
593 | switch { | 892 | switch { |
594 | // Empty maps turn into empty slices | 893 | // Empty maps turn into empty arrays |
595 | case dataValKind == reflect.Map: | 894 | case dataValKind == reflect.Map: |
596 | if dataVal.Len() == 0 { | 895 | if dataVal.Len() == 0 { |
597 | val.Set(reflect.MakeSlice(sliceType, 0, 0)) | 896 | val.Set(reflect.Zero(arrayType)) |
598 | return nil | 897 | return nil |
599 | } | 898 | } |
600 | 899 | ||
601 | // All other types we try to convert to the slice type | 900 | // All other types we try to convert to the array type |
602 | // and "lift" it into it. i.e. a string becomes a string slice. | 901 | // and "lift" it into it. i.e. a string becomes a string array. |
603 | default: | 902 | default: |
604 | // Just re-try this function with data as a slice. | 903 | // Just re-try this function with data as a slice. |
605 | return d.decodeSlice(name, []interface{}{data}, val) | 904 | return d.decodeArray(name, []interface{}{data}, val) |
606 | } | 905 | } |
607 | } | 906 | } |
608 | 907 | ||
@@ -610,9 +909,14 @@ func (d *Decoder) decodeSlice(name string, data interface{}, val reflect.Value) | |||
610 | "'%s': source data must be an array or slice, got %s", name, dataValKind) | 909 | "'%s': source data must be an array or slice, got %s", name, dataValKind) |
611 | 910 | ||
612 | } | 911 | } |
912 | if dataVal.Len() > arrayType.Len() { | ||
913 | return fmt.Errorf( | ||
914 | "'%s': expected source data to have length less or equal to %d, got %d", name, arrayType.Len(), dataVal.Len()) | ||
613 | 915 | ||
614 | // Make a new slice to hold our result, same size as the original data. | 916 | } |
615 | valSlice = reflect.MakeSlice(sliceType, dataVal.Len(), dataVal.Len()) | 917 | |
918 | // Make a new array to hold our result, same size as the original data. | ||
919 | valArray = reflect.New(arrayType).Elem() | ||
616 | } | 920 | } |
617 | 921 | ||
618 | // Accumulate any errors | 922 | // Accumulate any errors |
@@ -620,10 +924,7 @@ func (d *Decoder) decodeSlice(name string, data interface{}, val reflect.Value) | |||
620 | 924 | ||
621 | for i := 0; i < dataVal.Len(); i++ { | 925 | for i := 0; i < dataVal.Len(); i++ { |
622 | currentData := dataVal.Index(i).Interface() | 926 | currentData := dataVal.Index(i).Interface() |
623 | for valSlice.Len() <= i { | 927 | currentField := valArray.Index(i) |
624 | valSlice = reflect.Append(valSlice, reflect.Zero(valElemType)) | ||
625 | } | ||
626 | currentField := valSlice.Index(i) | ||
627 | 928 | ||
628 | fieldName := fmt.Sprintf("%s[%d]", name, i) | 929 | fieldName := fmt.Sprintf("%s[%d]", name, i) |
629 | if err := d.decode(fieldName, currentData, currentField); err != nil { | 930 | if err := d.decode(fieldName, currentData, currentField); err != nil { |
@@ -631,8 +932,8 @@ func (d *Decoder) decodeSlice(name string, data interface{}, val reflect.Value) | |||
631 | } | 932 | } |
632 | } | 933 | } |
633 | 934 | ||
634 | // Finally, set the value to the slice we built up | 935 | // Finally, set the value to the array we built up |
635 | val.Set(valSlice) | 936 | val.Set(valArray) |
636 | 937 | ||
637 | // If there were errors, we return those | 938 | // If there were errors, we return those |
638 | if len(errors) > 0 { | 939 | if len(errors) > 0 { |
@@ -653,10 +954,29 @@ func (d *Decoder) decodeStruct(name string, data interface{}, val reflect.Value) | |||
653 | } | 954 | } |
654 | 955 | ||
655 | dataValKind := dataVal.Kind() | 956 | dataValKind := dataVal.Kind() |
656 | if dataValKind != reflect.Map { | 957 | switch dataValKind { |
657 | return fmt.Errorf("'%s' expected a map, got '%s'", name, dataValKind) | 958 | case reflect.Map: |
959 | return d.decodeStructFromMap(name, dataVal, val) | ||
960 | |||
961 | case reflect.Struct: | ||
962 | // Not the most efficient way to do this but we can optimize later if | ||
963 | // we want to. To convert from struct to struct we go to map first | ||
964 | // as an intermediary. | ||
965 | m := make(map[string]interface{}) | ||
966 | mval := reflect.Indirect(reflect.ValueOf(&m)) | ||
967 | if err := d.decodeMapFromStruct(name, dataVal, mval, mval); err != nil { | ||
968 | return err | ||
969 | } | ||
970 | |||
971 | result := d.decodeStructFromMap(name, mval, val) | ||
972 | return result | ||
973 | |||
974 | default: | ||
975 | return fmt.Errorf("'%s' expected a map, got '%s'", name, dataVal.Kind()) | ||
658 | } | 976 | } |
977 | } | ||
659 | 978 | ||
979 | func (d *Decoder) decodeStructFromMap(name string, dataVal, val reflect.Value) error { | ||
660 | dataValType := dataVal.Type() | 980 | dataValType := dataVal.Type() |
661 | if kind := dataValType.Key().Kind(); kind != reflect.String && kind != reflect.Interface { | 981 | if kind := dataValType.Key().Kind(); kind != reflect.String && kind != reflect.Interface { |
662 | return fmt.Errorf( | 982 | return fmt.Errorf( |
@@ -681,7 +1001,11 @@ func (d *Decoder) decodeStruct(name string, data interface{}, val reflect.Value) | |||
681 | 1001 | ||
682 | // Compile the list of all the fields that we're going to be decoding | 1002 | // Compile the list of all the fields that we're going to be decoding |
683 | // from all the structs. | 1003 | // from all the structs. |
684 | fields := make(map[*reflect.StructField]reflect.Value) | 1004 | type field struct { |
1005 | field reflect.StructField | ||
1006 | val reflect.Value | ||
1007 | } | ||
1008 | fields := []field{} | ||
685 | for len(structs) > 0 { | 1009 | for len(structs) > 0 { |
686 | structVal := structs[0] | 1010 | structVal := structs[0] |
687 | structs = structs[1:] | 1011 | structs = structs[1:] |
@@ -707,20 +1031,22 @@ func (d *Decoder) decodeStruct(name string, data interface{}, val reflect.Value) | |||
707 | errors = appendErrors(errors, | 1031 | errors = appendErrors(errors, |
708 | fmt.Errorf("%s: unsupported type for squash: %s", fieldType.Name, fieldKind)) | 1032 | fmt.Errorf("%s: unsupported type for squash: %s", fieldType.Name, fieldKind)) |
709 | } else { | 1033 | } else { |
710 | structs = append(structs, val.FieldByName(fieldType.Name)) | 1034 | structs = append(structs, structVal.FieldByName(fieldType.Name)) |
711 | } | 1035 | } |
712 | continue | 1036 | continue |
713 | } | 1037 | } |
714 | 1038 | ||
715 | // Normal struct field, store it away | 1039 | // Normal struct field, store it away |
716 | fields[&fieldType] = structVal.Field(i) | 1040 | fields = append(fields, field{fieldType, structVal.Field(i)}) |
717 | } | 1041 | } |
718 | } | 1042 | } |
719 | 1043 | ||
720 | for fieldType, field := range fields { | 1044 | // for fieldType, field := range fields { |
721 | fieldName := fieldType.Name | 1045 | for _, f := range fields { |
1046 | field, fieldValue := f.field, f.val | ||
1047 | fieldName := field.Name | ||
722 | 1048 | ||
723 | tagValue := fieldType.Tag.Get(d.config.TagName) | 1049 | tagValue := field.Tag.Get(d.config.TagName) |
724 | tagValue = strings.SplitN(tagValue, ",", 2)[0] | 1050 | tagValue = strings.SplitN(tagValue, ",", 2)[0] |
725 | if tagValue != "" { | 1051 | if tagValue != "" { |
726 | fieldName = tagValue | 1052 | fieldName = tagValue |
@@ -755,14 +1081,14 @@ func (d *Decoder) decodeStruct(name string, data interface{}, val reflect.Value) | |||
755 | // Delete the key we're using from the unused map so we stop tracking | 1081 | // Delete the key we're using from the unused map so we stop tracking |
756 | delete(dataValKeysUnused, rawMapKey.Interface()) | 1082 | delete(dataValKeysUnused, rawMapKey.Interface()) |
757 | 1083 | ||
758 | if !field.IsValid() { | 1084 | if !fieldValue.IsValid() { |
759 | // This should never happen | 1085 | // This should never happen |
760 | panic("field is not valid") | 1086 | panic("field is not valid") |
761 | } | 1087 | } |
762 | 1088 | ||
763 | // If we can't set the field, then it is unexported or something, | 1089 | // If we can't set the field, then it is unexported or something, |
764 | // and we just continue onwards. | 1090 | // and we just continue onwards. |
765 | if !field.CanSet() { | 1091 | if !fieldValue.CanSet() { |
766 | continue | 1092 | continue |
767 | } | 1093 | } |
768 | 1094 | ||
@@ -772,7 +1098,7 @@ func (d *Decoder) decodeStruct(name string, data interface{}, val reflect.Value) | |||
772 | fieldName = fmt.Sprintf("%s.%s", name, fieldName) | 1098 | fieldName = fmt.Sprintf("%s.%s", name, fieldName) |
773 | } | 1099 | } |
774 | 1100 | ||
775 | if err := d.decode(fieldName, rawMapVal.Interface(), field); err != nil { | 1101 | if err := d.decode(fieldName, rawMapVal.Interface(), fieldValue); err != nil { |
776 | errors = appendErrors(errors, err) | 1102 | errors = appendErrors(errors, err) |
777 | } | 1103 | } |
778 | } | 1104 | } |
diff --git a/vendor/github.com/mitchellh/reflectwalk/go.mod b/vendor/github.com/mitchellh/reflectwalk/go.mod new file mode 100644 index 0000000..52bb7c4 --- /dev/null +++ b/vendor/github.com/mitchellh/reflectwalk/go.mod | |||
@@ -0,0 +1 @@ | |||
module github.com/mitchellh/reflectwalk | |||