summaryrefslogtreecommitdiffstats
path: root/vendor/github.com
diff options
context:
space:
mode:
authorChristopher Speller <crspeller@gmail.com>2017-11-13 09:09:58 -0800
committerGitHub <noreply@github.com>2017-11-13 09:09:58 -0800
commit1329aa51b605cb54ba9aae3a82a0a87b881fb7b3 (patch)
tree93cbf354ab894a560fc2cef8ef685d681b4ff889 /vendor/github.com
parent7304a61ef597970be3031b14e652fb3a4df44304 (diff)
downloadchat-1329aa51b605cb54ba9aae3a82a0a87b881fb7b3.tar.gz
chat-1329aa51b605cb54ba9aae3a82a0a87b881fb7b3.tar.bz2
chat-1329aa51b605cb54ba9aae3a82a0a87b881fb7b3.zip
Updating server dependancies. (#7816)
Diffstat (limited to 'vendor/github.com')
-rw-r--r--vendor/github.com/NYTimes/gziphandler/gzip.go12
-rw-r--r--vendor/github.com/NYTimes/gziphandler/gzip_test.go33
-rw-r--r--vendor/github.com/armon/go-metrics/inmem.go4
-rw-r--r--vendor/github.com/armon/go-metrics/inmem_endpoint_test.go8
-rw-r--r--vendor/github.com/armon/go-metrics/inmem_test.go2
-rw-r--r--vendor/github.com/disintegration/imaging/clone.go312
-rw-r--r--vendor/github.com/disintegration/imaging/clone_test.go247
-rw-r--r--vendor/github.com/disintegration/imaging/helpers.go266
-rw-r--r--vendor/github.com/disintegration/imaging/helpers_test.go240
-rw-r--r--vendor/github.com/disintegration/imaging/histogram.go2
-rw-r--r--vendor/github.com/disintegration/imaging/resize.go10
-rw-r--r--vendor/github.com/disintegration/imaging/transform.go4
-rw-r--r--vendor/github.com/go-ini/ini/.github/ISSUE_TEMPLATE.md5
-rw-r--r--vendor/github.com/go-ini/ini/.github/PULL_REQUEST_TEMPLATE.md3
-rw-r--r--vendor/github.com/go-ini/ini/.gitignore1
-rw-r--r--vendor/github.com/go-ini/ini/.travis.yml4
-rw-r--r--vendor/github.com/go-ini/ini/LICENSE2
-rw-r--r--vendor/github.com/go-ini/ini/Makefile5
-rw-r--r--vendor/github.com/go-ini/ini/README.md29
-rw-r--r--vendor/github.com/go-ini/ini/README_ZH.md29
-rw-r--r--vendor/github.com/go-ini/ini/bench_test.go118
-rw-r--r--vendor/github.com/go-ini/ini/file.go392
-rw-r--r--vendor/github.com/go-ini/ini/file_test.go355
-rw-r--r--vendor/github.com/go-ini/ini/ini.go376
-rw-r--r--vendor/github.com/go-ini/ini/ini_internal_test.go35
-rw-r--r--vendor/github.com/go-ini/ini/ini_test.go672
-rw-r--r--vendor/github.com/go-ini/ini/key.go40
-rw-r--r--vendor/github.com/go-ini/ini/key_test.go391
-rw-r--r--vendor/github.com/go-ini/ini/parser.go25
-rw-r--r--vendor/github.com/go-ini/ini/parser_test.go49
-rw-r--r--vendor/github.com/go-ini/ini/section.go9
-rw-r--r--vendor/github.com/go-ini/ini/section_test.go306
-rw-r--r--vendor/github.com/go-ini/ini/struct.go16
-rw-r--r--vendor/github.com/go-ini/ini/struct_test.go99
-rw-r--r--vendor/github.com/go-ini/ini/testdata/aicc.ini11
-rw-r--r--vendor/github.com/go-ini/ini/testdata/full.ini83
-rw-r--r--vendor/github.com/go-ini/ini/testdata/minimal.ini (renamed from vendor/github.com/go-ini/ini/testdata/conf.ini)0
-rw-r--r--vendor/github.com/go-redis/redis/commands.go5
-rw-r--r--vendor/github.com/go-redis/redis/internal/pool/pool.go19
-rw-r--r--vendor/github.com/go-redis/redis/internal/proto/scan.go3
-rw-r--r--vendor/github.com/go-redis/redis/internal/util.go37
-rw-r--r--vendor/github.com/go-redis/redis/pubsub.go36
-rw-r--r--vendor/github.com/go-redis/redis/pubsub_test.go16
-rw-r--r--vendor/github.com/go-redis/redis/race_test.go9
-rw-r--r--vendor/github.com/golang/protobuf/README.md1
-rw-r--r--vendor/github.com/gorilla/handlers/.travis.yml2
-rw-r--r--vendor/github.com/gorilla/handlers/cors.go12
-rw-r--r--vendor/github.com/gorilla/handlers/cors_test.go37
-rw-r--r--vendor/github.com/gorilla/mux/.travis.yml6
-rw-r--r--vendor/github.com/gorilla/mux/README.md36
-rw-r--r--vendor/github.com/gorilla/mux/mux.go51
-rw-r--r--vendor/github.com/gorilla/mux/mux_test.go723
-rw-r--r--vendor/github.com/gorilla/mux/regexp.go6
-rw-r--r--vendor/github.com/gorilla/mux/route.go44
-rw-r--r--vendor/github.com/hashicorp/go-sockaddr/ifaddr_test.go117
-rw-r--r--vendor/github.com/hashicorp/go-sockaddr/ifaddrs.go75
-rw-r--r--vendor/github.com/hashicorp/go-sockaddr/template/doc.go8
-rw-r--r--vendor/github.com/hashicorp/hcl/.travis.yml3
-rw-r--r--vendor/github.com/hashicorp/hcl/decoder.go31
-rw-r--r--vendor/github.com/hashicorp/hcl/hcl/scanner/scanner.go2
-rw-r--r--vendor/github.com/hashicorp/hcl/json/scanner/scanner.go2
-rw-r--r--vendor/github.com/hashicorp/memberlist/memberlist.go12
-rw-r--r--vendor/github.com/hashicorp/memberlist/memberlist_test.go2
-rw-r--r--vendor/github.com/hashicorp/memberlist/suspicion.go2
-rw-r--r--vendor/github.com/hashicorp/memberlist/util.go42
-rw-r--r--vendor/github.com/hashicorp/memberlist/util_test.go41
-rwxr-xr-xvendor/github.com/lib/pq/.travis.sh25
-rw-r--r--vendor/github.com/lib/pq/.travis.yml14
-rw-r--r--vendor/github.com/lib/pq/README.md1
-rw-r--r--vendor/github.com/lib/pq/array_test.go12
-rw-r--r--vendor/github.com/lib/pq/conn.go32
-rw-r--r--vendor/github.com/lib/pq/conn_test.go74
-rw-r--r--vendor/github.com/lib/pq/copy_test.go8
-rw-r--r--vendor/github.com/lib/pq/doc.go32
-rw-r--r--vendor/github.com/lib/pq/encode_test.go10
-rw-r--r--vendor/github.com/lib/pq/example/listen/doc.go (renamed from vendor/github.com/lib/pq/listen_example/doc.go)8
-rw-r--r--vendor/github.com/lib/pq/hstore/hstore.go2
-rw-r--r--vendor/github.com/lib/pq/notify.go56
-rw-r--r--vendor/github.com/lib/pq/notify_test.go6
-rw-r--r--vendor/github.com/magiconair/properties/CHANGELOG.md45
-rw-r--r--vendor/github.com/magiconair/properties/README.md2
-rw-r--r--vendor/github.com/magiconair/properties/lex.go3
-rw-r--r--vendor/github.com/magiconair/properties/properties_test.go2
-rw-r--r--vendor/github.com/miekg/dns/.travis.yml12
-rw-r--r--vendor/github.com/miekg/dns/README.md27
-rw-r--r--vendor/github.com/miekg/dns/client.go4
-rw-r--r--vendor/github.com/miekg/dns/client_test.go122
-rw-r--r--vendor/github.com/miekg/dns/clientconfig.go8
-rw-r--r--vendor/github.com/miekg/dns/clientconfig_test.go26
-rw-r--r--vendor/github.com/miekg/dns/compress_generate.go25
-rw-r--r--vendor/github.com/miekg/dns/dns.go9
-rw-r--r--vendor/github.com/miekg/dns/dns_bench_test.go37
-rw-r--r--vendor/github.com/miekg/dns/dns_test.go72
-rw-r--r--vendor/github.com/miekg/dns/dnssec_test.go113
-rw-r--r--vendor/github.com/miekg/dns/dnsutil/util.go18
-rw-r--r--vendor/github.com/miekg/dns/dnsutil/util_test.go22
-rw-r--r--vendor/github.com/miekg/dns/doc.go5
-rw-r--r--vendor/github.com/miekg/dns/edns.go36
-rw-r--r--vendor/github.com/miekg/dns/edns_test.go2
-rw-r--r--vendor/github.com/miekg/dns/issue_test.go10
-rw-r--r--vendor/github.com/miekg/dns/labels.go46
-rw-r--r--vendor/github.com/miekg/dns/labels_test.go40
-rw-r--r--vendor/github.com/miekg/dns/msg.go93
-rw-r--r--vendor/github.com/miekg/dns/nsecx_test.go6
-rw-r--r--vendor/github.com/miekg/dns/parse_test.go98
-rw-r--r--vendor/github.com/miekg/dns/privaterr_test.go5
-rw-r--r--vendor/github.com/miekg/dns/rr_test.go7
-rw-r--r--vendor/github.com/miekg/dns/sanitize_test.go51
-rw-r--r--vendor/github.com/miekg/dns/scan.go44
-rw-r--r--vendor/github.com/miekg/dns/scan_rr.go2
-rw-r--r--vendor/github.com/miekg/dns/server.go29
-rw-r--r--vendor/github.com/miekg/dns/server_test.go148
-rw-r--r--vendor/github.com/miekg/dns/types.go89
-rw-r--r--vendor/github.com/miekg/dns/types_generate.go3
-rw-r--r--vendor/github.com/miekg/dns/types_test.go2
-rw-r--r--vendor/github.com/miekg/dns/update_test.go28
-rw-r--r--vendor/github.com/miekg/dns/xfr.go59
-rw-r--r--vendor/github.com/miekg/dns/xfr_test.go4
-rw-r--r--vendor/github.com/miekg/dns/zcompress.go112
-rw-r--r--vendor/github.com/miekg/dns/ztypes.go3
-rw-r--r--vendor/github.com/mitchellh/mapstructure/mapstructure.go22
-rw-r--r--vendor/github.com/nicksnyder/go-i18n/i18n/language/language.go6
-rw-r--r--vendor/github.com/nicksnyder/go-i18n/i18n/language/pluralspec.go4
-rw-r--r--vendor/github.com/nicksnyder/go-i18n/i18n/language/pluralspec_test.go2
-rw-r--r--vendor/github.com/pelletier/go-toml/.gitignore1
-rw-r--r--vendor/github.com/pelletier/go-toml/.travis.yml5
-rw-r--r--vendor/github.com/pelletier/go-toml/README.md18
-rw-r--r--vendor/github.com/pelletier/go-toml/doc.go2
-rw-r--r--vendor/github.com/pelletier/go-toml/doc_test.go9
-rw-r--r--vendor/github.com/pelletier/go-toml/fuzz.go31
-rwxr-xr-xvendor/github.com/pelletier/go-toml/fuzz.sh15
-rw-r--r--vendor/github.com/pelletier/go-toml/keysparsing.go107
-rw-r--r--vendor/github.com/pelletier/go-toml/keysparsing_test.go16
-rw-r--r--vendor/github.com/pelletier/go-toml/marshal.go230
-rw-r--r--vendor/github.com/pelletier/go-toml/marshal_test.go134
-rw-r--r--vendor/github.com/pelletier/go-toml/parser.go6
-rw-r--r--vendor/github.com/pelletier/go-toml/parser_test.go2
-rw-r--r--vendor/github.com/pelletier/go-toml/query/doc.go2
-rw-r--r--vendor/github.com/pelletier/go-toml/toml.go26
-rw-r--r--vendor/github.com/pelletier/go-toml/tomltree_create.go6
-rw-r--r--vendor/github.com/pelletier/go-toml/tomltree_write.go43
-rw-r--r--vendor/github.com/pelletier/go-toml/tomltree_write_test.go16
-rw-r--r--vendor/github.com/pkg/errors/format_test.go2
-rw-r--r--vendor/github.com/prometheus/common/log/log.go9
-rw-r--r--vendor/github.com/prometheus/procfs/fixtures/26231/limits2
-rw-r--r--vendor/github.com/prometheus/procfs/proc_limits.go38
-rw-r--r--vendor/github.com/prometheus/procfs/proc_limits_test.go6
-rw-r--r--vendor/github.com/segmentio/backo-go/vendor/github.com/bmizerany/assert/.gitignore7
-rw-r--r--vendor/github.com/segmentio/backo-go/vendor/github.com/bmizerany/assert/README.md45
-rw-r--r--vendor/github.com/segmentio/backo-go/vendor/github.com/bmizerany/assert/assert.go76
-rw-r--r--vendor/github.com/segmentio/backo-go/vendor/github.com/bmizerany/assert/assert_test.go15
-rw-r--r--vendor/github.com/segmentio/backo-go/vendor/github.com/bmizerany/assert/example/point.go5
-rw-r--r--vendor/github.com/segmentio/backo-go/vendor/github.com/bmizerany/assert/example/point_test.go13
-rw-r--r--vendor/github.com/spf13/afero/.travis.yml3
-rw-r--r--vendor/github.com/spf13/afero/README.md13
-rw-r--r--vendor/github.com/spf13/afero/appveyor.yml2
-rw-r--r--vendor/github.com/spf13/afero/cacheOnReadFs.go9
-rw-r--r--vendor/github.com/spf13/afero/composite_test.go36
-rw-r--r--vendor/github.com/spf13/afero/mem/file.go40
-rw-r--r--vendor/github.com/spf13/afero/mem/file_test.go154
-rw-r--r--vendor/github.com/spf13/afero/memmap.go5
-rw-r--r--vendor/github.com/spf13/afero/memmap_test.go47
-rw-r--r--vendor/github.com/spf13/afero/memradix.go14
-rw-r--r--vendor/github.com/spf13/afero/util.go2
-rw-r--r--vendor/github.com/spf13/cobra/README.md435
-rw-r--r--vendor/github.com/spf13/cobra/args.go25
-rw-r--r--vendor/github.com/spf13/cobra/args_test.go241
-rw-r--r--vendor/github.com/spf13/cobra/bash_completions.go2
-rw-r--r--vendor/github.com/spf13/cobra/bash_completions_test.go236
-rw-r--r--vendor/github.com/spf13/cobra/cobra.go9
-rw-r--r--vendor/github.com/spf13/cobra/cobra/README.md94
-rw-r--r--vendor/github.com/spf13/cobra/cobra/cmd/helpers.go23
-rw-r--r--vendor/github.com/spf13/cobra/cobra/cmd/licenses.go2
-rw-r--r--vendor/github.com/spf13/cobra/cobra_test.go1228
-rw-r--r--vendor/github.com/spf13/cobra/command.go187
-rw-r--r--vendor/github.com/spf13/cobra/command_test.go1473
-rw-r--r--vendor/github.com/spf13/cobra/doc/cmd_test.go157
-rw-r--r--vendor/github.com/spf13/cobra/doc/man_docs_test.go147
-rw-r--r--vendor/github.com/spf13/cobra/doc/md_docs_test.go96
-rw-r--r--vendor/github.com/spf13/cobra/doc/rest_docs.go185
-rw-r--r--vendor/github.com/spf13/cobra/doc/rest_docs.md114
-rw-r--r--vendor/github.com/spf13/cobra/doc/rest_docs_test.go76
-rw-r--r--vendor/github.com/spf13/cobra/doc/yaml_docs_test.go89
-rw-r--r--vendor/github.com/spf13/cobra/zsh_completions_test.go7
-rw-r--r--vendor/github.com/spf13/viper/README.md4
-rw-r--r--vendor/github.com/spf13/viper/util.go5
-rw-r--r--vendor/github.com/spf13/viper/viper.go9
-rw-r--r--vendor/github.com/spf13/viper/viper_test.go2
-rw-r--r--vendor/github.com/xenolf/lego/.travis.yml2
-rw-r--r--vendor/github.com/xenolf/lego/acme/dns_challenge.go13
-rw-r--r--vendor/github.com/xenolf/lego/acme/dns_challenge_test.go9
-rw-r--r--vendor/github.com/xenolf/lego/cli_handlers.go11
-rw-r--r--vendor/github.com/xenolf/lego/providers/dns/dns_providers.go3
-rw-r--r--vendor/github.com/xenolf/lego/providers/dns/godaddy/godaddy.go155
-rw-r--r--vendor/github.com/xenolf/lego/providers/dns/godaddy/godaddy_test.go60
195 files changed, 8185 insertions, 5484 deletions
diff --git a/vendor/github.com/NYTimes/gziphandler/gzip.go b/vendor/github.com/NYTimes/gziphandler/gzip.go
index b6af9115a..13ee34a42 100644
--- a/vendor/github.com/NYTimes/gziphandler/gzip.go
+++ b/vendor/github.com/NYTimes/gziphandler/gzip.go
@@ -82,6 +82,7 @@ type GzipResponseWriter struct {
buf []byte // Holds the first part of the write before reaching the minSize or the end of the write.
contentTypes []string // Only compress if the response is one of these content-types. All are accepted if empty.
+ flushed bool // Indicate if the stream was already flushed
}
// Write appends data to the gzip writer.
@@ -150,7 +151,9 @@ func (w *GzipResponseWriter) startGzip() error {
// WriteHeader just saves the response code until close or GZIP effective writes.
func (w *GzipResponseWriter) WriteHeader(code int) {
- w.code = code
+ if w.code == 0 {
+ w.code = code
+ }
}
// init graps a new gzip writer from the gzipWriterPool and writes the correct
@@ -167,7 +170,8 @@ func (w *GzipResponseWriter) init() {
func (w *GzipResponseWriter) Close() error {
if w.gw == nil {
// Gzip not trigged yet, write out regular response.
- if w.code != 0 {
+ // WriteHeader only if it wasn't already wrote by a Flush
+ if !w.flushed && w.code != 0 {
w.ResponseWriter.WriteHeader(w.code)
}
if w.buf != nil {
@@ -195,7 +199,11 @@ func (w *GzipResponseWriter) Flush() {
}
if fw, ok := w.ResponseWriter.(http.Flusher); ok {
+ if !w.flushed && w.code != 0 {
+ w.ResponseWriter.WriteHeader(w.code)
+ }
fw.Flush()
+ w.flushed = true
}
}
diff --git a/vendor/github.com/NYTimes/gziphandler/gzip_test.go b/vendor/github.com/NYTimes/gziphandler/gzip_test.go
index 655a19373..7decfd17b 100644
--- a/vendor/github.com/NYTimes/gziphandler/gzip_test.go
+++ b/vendor/github.com/NYTimes/gziphandler/gzip_test.go
@@ -306,6 +306,39 @@ func TestStatusCodes(t *testing.T) {
}
}
+func TestStatusCodesFlushed(t *testing.T) {
+ handler := GzipHandler(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
+ rw.WriteHeader(http.StatusNotFound)
+ rw.(http.Flusher).Flush()
+ rw.Write([]byte("Not found"))
+ }))
+ r := httptest.NewRequest(http.MethodGet, "/", nil)
+ r.Header.Set(acceptEncoding, "gzip")
+ w := httptest.NewRecorder()
+ handler.ServeHTTP(w, r)
+
+ result := w.Result()
+ if result.StatusCode != http.StatusNotFound {
+ t.Errorf("StatusCode should have been 404 but was %d", result.StatusCode)
+ }
+}
+
+func TestIgnoreSubsequentWriteHeader(t *testing.T) {
+ handler := GzipHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(500)
+ w.WriteHeader(404)
+ }))
+ r := httptest.NewRequest("GET", "/", nil)
+ r.Header.Set("Accept-Encoding", "gzip")
+ w := httptest.NewRecorder()
+ handler.ServeHTTP(w, r)
+
+ result := w.Result()
+ if result.StatusCode != 500 {
+ t.Errorf("StatusCode should have been 500 but was %d", result.StatusCode)
+ }
+}
+
func TestDontWriteWhenNotWrittenTo(t *testing.T) {
// When using gzip as middleware without ANY writes in the handler,
// ensure the gzip middleware doesn't touch the actual ResponseWriter
diff --git a/vendor/github.com/armon/go-metrics/inmem.go b/vendor/github.com/armon/go-metrics/inmem.go
index cd1773042..8fe1de802 100644
--- a/vendor/github.com/armon/go-metrics/inmem.go
+++ b/vendor/github.com/armon/go-metrics/inmem.go
@@ -70,7 +70,7 @@ func NewIntervalMetrics(intv time.Time) *IntervalMetrics {
// about a sample
type AggregateSample struct {
Count int // The count of emitted pairs
- Rate float64 `json:"-"` // The count of emitted pairs per time unit (usually 1 second)
+ Rate float64 // The values rate per time unit (usually 1 second)
Sum float64 // The sum of values
SumSq float64 `json:"-"` // The sum of squared values
Min float64 // Minimum value
@@ -107,7 +107,7 @@ func (a *AggregateSample) Ingest(v float64, rateDenom float64) {
if v > a.Max || a.Count == 1 {
a.Max = v
}
- a.Rate = float64(a.Count) / rateDenom
+ a.Rate = float64(a.Sum) / rateDenom
a.LastUpdated = time.Now()
}
diff --git a/vendor/github.com/armon/go-metrics/inmem_endpoint_test.go b/vendor/github.com/armon/go-metrics/inmem_endpoint_test.go
index 326d56ada..f9c6793b6 100644
--- a/vendor/github.com/armon/go-metrics/inmem_endpoint_test.go
+++ b/vendor/github.com/armon/go-metrics/inmem_endpoint_test.go
@@ -61,7 +61,7 @@ func TestDisplayMetrics(t *testing.T) {
Max: 22,
Sum: 42,
SumSq: 884,
- Rate: 200,
+ Rate: 4200,
},
Mean: 21,
Stddev: 1.4142135623730951,
@@ -75,7 +75,7 @@ func TestDisplayMetrics(t *testing.T) {
Max: 40,
Sum: 60,
SumSq: 2000,
- Rate: 200,
+ Rate: 6000,
},
Mean: 30,
Stddev: 14.142135623730951,
@@ -92,7 +92,7 @@ func TestDisplayMetrics(t *testing.T) {
Max: 24,
Sum: 44,
SumSq: 976,
- Rate: 200,
+ Rate: 4400,
},
Mean: 22,
Stddev: 2.8284271247461903,
@@ -106,7 +106,7 @@ func TestDisplayMetrics(t *testing.T) {
Max: 33,
Sum: 56,
SumSq: 1618,
- Rate: 200,
+ Rate: 5600,
},
Mean: 28,
Stddev: 7.0710678118654755,
diff --git a/vendor/github.com/armon/go-metrics/inmem_test.go b/vendor/github.com/armon/go-metrics/inmem_test.go
index 8d30e7c30..3b037c70d 100644
--- a/vendor/github.com/armon/go-metrics/inmem_test.go
+++ b/vendor/github.com/armon/go-metrics/inmem_test.go
@@ -53,7 +53,7 @@ func TestInmemSink(t *testing.T) {
if agg.Count != 2 {
t.Fatalf("bad val: %v", agg)
}
- if agg.Rate != 200 {
+ if agg.Rate != 4200 {
t.Fatalf("bad val: %v", agg.Rate)
}
if agg.Sum != 42 {
diff --git a/vendor/github.com/disintegration/imaging/clone.go b/vendor/github.com/disintegration/imaging/clone.go
new file mode 100644
index 000000000..a22e01913
--- /dev/null
+++ b/vendor/github.com/disintegration/imaging/clone.go
@@ -0,0 +1,312 @@
+package imaging
+
+import (
+ "image"
+ "image/color"
+)
+
+// Clone returns a copy of the given image.
+func Clone(img image.Image) *image.NRGBA {
+ dstBounds := img.Bounds().Sub(img.Bounds().Min)
+ dst := image.NewNRGBA(dstBounds)
+
+ switch src := img.(type) {
+ case *image.NRGBA:
+ copyNRGBA(dst, src)
+ case *image.NRGBA64:
+ copyNRGBA64(dst, src)
+ case *image.RGBA:
+ copyRGBA(dst, src)
+ case *image.RGBA64:
+ copyRGBA64(dst, src)
+ case *image.Gray:
+ copyGray(dst, src)
+ case *image.Gray16:
+ copyGray16(dst, src)
+ case *image.YCbCr:
+ copyYCbCr(dst, src)
+ case *image.Paletted:
+ copyPaletted(dst, src)
+ default:
+ copyImage(dst, src)
+ }
+
+ return dst
+}
+
+func copyNRGBA(dst *image.NRGBA, src *image.NRGBA) {
+ srcMinX := src.Rect.Min.X
+ srcMinY := src.Rect.Min.Y
+ dstW := dst.Rect.Dx()
+ dstH := dst.Rect.Dy()
+ rowSize := dstW * 4
+ parallel(dstH, func(partStart, partEnd int) {
+ for dstY := partStart; dstY < partEnd; dstY++ {
+ di := dst.PixOffset(0, dstY)
+ si := src.PixOffset(srcMinX, srcMinY+dstY)
+ copy(dst.Pix[di:di+rowSize], src.Pix[si:si+rowSize])
+ }
+ })
+}
+
+func copyNRGBA64(dst *image.NRGBA, src *image.NRGBA64) {
+ srcMinX := src.Rect.Min.X
+ srcMinY := src.Rect.Min.Y
+ dstW := dst.Rect.Dx()
+ dstH := dst.Rect.Dy()
+ parallel(dstH, func(partStart, partEnd int) {
+ for dstY := partStart; dstY < partEnd; dstY++ {
+ di := dst.PixOffset(0, dstY)
+ si := src.PixOffset(srcMinX, srcMinY+dstY)
+ for dstX := 0; dstX < dstW; dstX++ {
+ dst.Pix[di+0] = src.Pix[si+0]
+ dst.Pix[di+1] = src.Pix[si+2]
+ dst.Pix[di+2] = src.Pix[si+4]
+ dst.Pix[di+3] = src.Pix[si+6]
+ di += 4
+ si += 8
+ }
+ }
+ })
+}
+
+func copyRGBA(dst *image.NRGBA, src *image.RGBA) {
+ srcMinX := src.Rect.Min.X
+ srcMinY := src.Rect.Min.Y
+ dstW := dst.Rect.Dx()
+ dstH := dst.Rect.Dy()
+ parallel(dstH, func(partStart, partEnd int) {
+ for dstY := partStart; dstY < partEnd; dstY++ {
+ di := dst.PixOffset(0, dstY)
+ si := src.PixOffset(srcMinX, srcMinY+dstY)
+ for dstX := 0; dstX < dstW; dstX++ {
+ a := src.Pix[si+3]
+ dst.Pix[di+3] = a
+
+ switch a {
+ case 0:
+ dst.Pix[di+0] = 0
+ dst.Pix[di+1] = 0
+ dst.Pix[di+2] = 0
+ case 0xff:
+ dst.Pix[di+0] = src.Pix[si+0]
+ dst.Pix[di+1] = src.Pix[si+1]
+ dst.Pix[di+2] = src.Pix[si+2]
+ default:
+ var tmp uint16
+ tmp = uint16(src.Pix[si+0]) * 0xff / uint16(a)
+ dst.Pix[di+0] = uint8(tmp)
+ tmp = uint16(src.Pix[si+1]) * 0xff / uint16(a)
+ dst.Pix[di+1] = uint8(tmp)
+ tmp = uint16(src.Pix[si+2]) * 0xff / uint16(a)
+ dst.Pix[di+2] = uint8(tmp)
+ }
+
+ di += 4
+ si += 4
+ }
+ }
+ })
+}
+
+func copyRGBA64(dst *image.NRGBA, src *image.RGBA64) {
+ srcMinX := src.Rect.Min.X
+ srcMinY := src.Rect.Min.Y
+ dstW := dst.Rect.Dx()
+ dstH := dst.Rect.Dy()
+ parallel(dstH, func(partStart, partEnd int) {
+ for dstY := partStart; dstY < partEnd; dstY++ {
+ di := dst.PixOffset(0, dstY)
+ si := src.PixOffset(srcMinX, srcMinY+dstY)
+ for dstX := 0; dstX < dstW; dstX++ {
+ a := src.Pix[si+6]
+ dst.Pix[di+3] = a
+
+ switch a {
+ case 0:
+ dst.Pix[di+0] = 0
+ dst.Pix[di+1] = 0
+ dst.Pix[di+2] = 0
+ case 0xff:
+ dst.Pix[di+0] = src.Pix[si+0]
+ dst.Pix[di+1] = src.Pix[si+2]
+ dst.Pix[di+2] = src.Pix[si+4]
+ default:
+ var tmp uint16
+ tmp = uint16(src.Pix[si+0]) * 0xff / uint16(a)
+ dst.Pix[di+0] = uint8(tmp)
+ tmp = uint16(src.Pix[si+2]) * 0xff / uint16(a)
+ dst.Pix[di+1] = uint8(tmp)
+ tmp = uint16(src.Pix[si+4]) * 0xff / uint16(a)
+ dst.Pix[di+2] = uint8(tmp)
+ }
+
+ di += 4
+ si += 8
+ }
+ }
+ })
+}
+
+func copyGray(dst *image.NRGBA, src *image.Gray) {
+ srcMinX := src.Rect.Min.X
+ srcMinY := src.Rect.Min.Y
+ dstW := dst.Rect.Dx()
+ dstH := dst.Rect.Dy()
+ parallel(dstH, func(partStart, partEnd int) {
+ for dstY := partStart; dstY < partEnd; dstY++ {
+ di := dst.PixOffset(0, dstY)
+ si := src.PixOffset(srcMinX, srcMinY+dstY)
+ for dstX := 0; dstX < dstW; dstX++ {
+ c := src.Pix[si]
+ dst.Pix[di+0] = c
+ dst.Pix[di+1] = c
+ dst.Pix[di+2] = c
+ dst.Pix[di+3] = 0xff
+ di += 4
+ si++
+ }
+ }
+ })
+}
+
+func copyGray16(dst *image.NRGBA, src *image.Gray16) {
+ srcMinX := src.Rect.Min.X
+ srcMinY := src.Rect.Min.Y
+ dstW := dst.Rect.Dx()
+ dstH := dst.Rect.Dy()
+ parallel(dstH, func(partStart, partEnd int) {
+ for dstY := partStart; dstY < partEnd; dstY++ {
+ di := dst.PixOffset(0, dstY)
+ si := src.PixOffset(srcMinX, srcMinY+dstY)
+ for dstX := 0; dstX < dstW; dstX++ {
+ c := src.Pix[si]
+ dst.Pix[di+0] = c
+ dst.Pix[di+1] = c
+ dst.Pix[di+2] = c
+ dst.Pix[di+3] = 0xff
+ di += 4
+ si += 2
+ }
+ }
+ })
+}
+
+func copyYCbCr(dst *image.NRGBA, src *image.YCbCr) {
+ srcMinX := src.Rect.Min.X
+ srcMinY := src.Rect.Min.Y
+ dstW := dst.Rect.Dx()
+ dstH := dst.Rect.Dy()
+ parallel(dstH, func(partStart, partEnd int) {
+ for dstY := partStart; dstY < partEnd; dstY++ {
+ srcY := srcMinY + dstY
+ di := dst.PixOffset(0, dstY)
+ for dstX := 0; dstX < dstW; dstX++ {
+ srcX := srcMinX + dstX
+
+ siy := (srcY-srcMinY)*src.YStride + (srcX - srcMinX)
+
+ var sic int
+ switch src.SubsampleRatio {
+ case image.YCbCrSubsampleRatio444:
+ sic = (srcY-srcMinY)*src.CStride + (srcX - srcMinX)
+ case image.YCbCrSubsampleRatio422:
+ sic = (srcY-srcMinY)*src.CStride + (srcX/2 - srcMinX/2)
+ case image.YCbCrSubsampleRatio420:
+ sic = (srcY/2-srcMinY/2)*src.CStride + (srcX/2 - srcMinX/2)
+ case image.YCbCrSubsampleRatio440:
+ sic = (srcY/2-srcMinY/2)*src.CStride + (srcX - srcMinX)
+ default:
+ sic = src.COffset(srcX, srcY)
+ }
+
+ y := int32(src.Y[siy])
+ cb := int32(src.Cb[sic]) - 128
+ cr := int32(src.Cr[sic]) - 128
+
+ r := (y<<16 + 91881*cr + 1<<15) >> 16
+ if r > 255 {
+ r = 255
+ } else if r < 0 {
+ r = 0
+ }
+
+ g := (y<<16 - 22554*cb - 46802*cr + 1<<15) >> 16
+ if g > 255 {
+ g = 255
+ } else if g < 0 {
+ g = 0
+ }
+
+ b := (y<<16 + 116130*cb + 1<<15) >> 16
+ if b > 255 {
+ b = 255
+ } else if b < 0 {
+ b = 0
+ }
+
+ dst.Pix[di+0] = uint8(r)
+ dst.Pix[di+1] = uint8(g)
+ dst.Pix[di+2] = uint8(b)
+ dst.Pix[di+3] = 255
+
+ di += 4
+ }
+ }
+ })
+}
+
+func copyPaletted(dst *image.NRGBA, src *image.Paletted) {
+ srcMinX := src.Rect.Min.X
+ srcMinY := src.Rect.Min.Y
+ dstW := dst.Rect.Dx()
+ dstH := dst.Rect.Dy()
+ plen := len(src.Palette)
+ pnew := make([]color.NRGBA, plen)
+ for i := 0; i < plen; i++ {
+ pnew[i] = color.NRGBAModel.Convert(src.Palette[i]).(color.NRGBA)
+ }
+ parallel(dstH, func(partStart, partEnd int) {
+ for dstY := partStart; dstY < partEnd; dstY++ {
+ di := dst.PixOffset(0, dstY)
+ si := src.PixOffset(srcMinX, srcMinY+dstY)
+ for dstX := 0; dstX < dstW; dstX++ {
+ c := pnew[src.Pix[si]]
+ dst.Pix[di+0] = c.R
+ dst.Pix[di+1] = c.G
+ dst.Pix[di+2] = c.B
+ dst.Pix[di+3] = c.A
+ di += 4
+ si++
+ }
+ }
+ })
+}
+
+func copyImage(dst *image.NRGBA, src image.Image) {
+ srcMinX := src.Bounds().Min.X
+ srcMinY := src.Bounds().Min.Y
+ dstW := dst.Bounds().Dx()
+ dstH := dst.Bounds().Dy()
+ parallel(dstH, func(partStart, partEnd int) {
+ for dstY := partStart; dstY < partEnd; dstY++ {
+ di := dst.PixOffset(0, dstY)
+ for dstX := 0; dstX < dstW; dstX++ {
+ c := color.NRGBAModel.Convert(src.At(srcMinX+dstX, srcMinY+dstY)).(color.NRGBA)
+ dst.Pix[di+0] = c.R
+ dst.Pix[di+1] = c.G
+ dst.Pix[di+2] = c.B
+ dst.Pix[di+3] = c.A
+ di += 4
+ }
+ }
+ })
+}
+
+// toNRGBA converts any image type to *image.NRGBA with min-point at (0, 0).
+func toNRGBA(img image.Image) *image.NRGBA {
+ if img, ok := img.(*image.NRGBA); ok && img.Bounds().Min.Eq(image.ZP) {
+ return img
+ }
+ return Clone(img)
+}
diff --git a/vendor/github.com/disintegration/imaging/clone_test.go b/vendor/github.com/disintegration/imaging/clone_test.go
new file mode 100644
index 000000000..36e309f0a
--- /dev/null
+++ b/vendor/github.com/disintegration/imaging/clone_test.go
@@ -0,0 +1,247 @@
+package imaging
+
+import (
+ "image"
+ "image/color"
+ "testing"
+)
+
+func TestClone(t *testing.T) {
+ td := []struct {
+ desc string
+ src image.Image
+ want *image.NRGBA
+ }{
+ {
+ "Clone NRGBA",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 0, 1),
+ Stride: 1 * 4,
+ Pix: []uint8{0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff},
+ },
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 1, 2),
+ Stride: 1 * 4,
+ Pix: []uint8{0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff},
+ },
+ },
+ {
+ "Clone NRGBA64",
+ &image.NRGBA64{
+ Rect: image.Rect(-1, -1, 0, 1),
+ Stride: 1 * 8,
+ Pix: []uint8{
+ 0x00, 0x00, 0x11, 0x11, 0x22, 0x22, 0x33, 0x33,
+ 0xcc, 0xcc, 0xdd, 0xdd, 0xee, 0xee, 0xff, 0xff,
+ },
+ },
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 1, 2),
+ Stride: 1 * 4,
+ Pix: []uint8{0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff},
+ },
+ },
+ {
+ "Clone RGBA",
+ &image.RGBA{
+ Rect: image.Rect(-1, -1, 0, 2),
+ Stride: 1 * 4,
+ Pix: []uint8{0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff},
+ },
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 1, 3),
+ Stride: 1 * 4,
+ Pix: []uint8{0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xaa, 0x33, 0xcc, 0xdd, 0xee, 0xff},
+ },
+ },
+ {
+ "Clone RGBA64",
+ &image.RGBA64{
+ Rect: image.Rect(-1, -1, 0, 2),
+ Stride: 1 * 8,
+ Pix: []uint8{
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x11, 0x11, 0x22, 0x22, 0x33, 0x33,
+ 0xcc, 0xcc, 0xdd, 0xdd, 0xee, 0xee, 0xff, 0xff,
+ },
+ },
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 1, 3),
+ Stride: 1 * 4,
+ Pix: []uint8{0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xaa, 0x33, 0xcc, 0xdd, 0xee, 0xff},
+ },
+ },
+ {
+ "Clone Gray",
+ &image.Gray{
+ Rect: image.Rect(-1, -1, 0, 1),
+ Stride: 1 * 1,
+ Pix: []uint8{0x11, 0xee},
+ },
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 1, 2),
+ Stride: 1 * 4,
+ Pix: []uint8{0x11, 0x11, 0x11, 0xff, 0xee, 0xee, 0xee, 0xff},
+ },
+ },
+ {
+ "Clone Gray16",
+ &image.Gray16{
+ Rect: image.Rect(-1, -1, 0, 1),
+ Stride: 1 * 2,
+ Pix: []uint8{0x11, 0x11, 0xee, 0xee},
+ },
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 1, 2),
+ Stride: 1 * 4,
+ Pix: []uint8{0x11, 0x11, 0x11, 0xff, 0xee, 0xee, 0xee, 0xff},
+ },
+ },
+ {
+ "Clone Alpha",
+ &image.Alpha{
+ Rect: image.Rect(-1, -1, 0, 1),
+ Stride: 1 * 1,
+ Pix: []uint8{0x11, 0xee},
+ },
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 1, 2),
+ Stride: 1 * 4,
+ Pix: []uint8{0xff, 0xff, 0xff, 0x11, 0xff, 0xff, 0xff, 0xee},
+ },
+ },
+ {
+ "Clone YCbCr",
+ &image.YCbCr{
+ Rect: image.Rect(-1, -1, 5, 0),
+ SubsampleRatio: image.YCbCrSubsampleRatio444,
+ YStride: 6,
+ CStride: 6,
+ Y: []uint8{0x00, 0xff, 0x7f, 0x26, 0x4b, 0x0e},
+ Cb: []uint8{0x80, 0x80, 0x80, 0x6b, 0x56, 0xc0},
+ Cr: []uint8{0x80, 0x80, 0x80, 0xc0, 0x4b, 0x76},
+ },
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 6, 1),
+ Stride: 6 * 4,
+ Pix: []uint8{
+ 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0x7f, 0x7f, 0x7f, 0xff,
+ 0x7f, 0x00, 0x00, 0xff,
+ 0x00, 0x7f, 0x00, 0xff,
+ 0x00, 0x00, 0x7f, 0xff,
+ },
+ },
+ },
+ {
+ "Clone YCbCr 444",
+ &image.YCbCr{
+ Y: []uint8{0x4c, 0x69, 0x1d, 0xb1, 0x96, 0xe2, 0x26, 0x34, 0xe, 0x59, 0x4b, 0x71, 0x0, 0x4c, 0x99, 0xff},
+ Cb: []uint8{0x55, 0xd4, 0xff, 0x8e, 0x2c, 0x01, 0x6b, 0xaa, 0xc0, 0x95, 0x56, 0x40, 0x80, 0x80, 0x80, 0x80},
+ Cr: []uint8{0xff, 0xeb, 0x6b, 0x36, 0x15, 0x95, 0xc0, 0xb5, 0x76, 0x41, 0x4b, 0x8c, 0x80, 0x80, 0x80, 0x80},
+ YStride: 4,
+ CStride: 4,
+ SubsampleRatio: image.YCbCrSubsampleRatio444,
+ Rect: image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
+ },
+ &image.NRGBA{
+ Pix: []uint8{0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x49, 0xe1, 0xca, 0xff, 0x0, 0xff, 0x0, 0xff, 0xff, 0xff, 0x0, 0xff, 0x7f, 0x0, 0x0, 0xff, 0x7f, 0x0, 0x7f, 0xff, 0x0, 0x0, 0x7f, 0xff, 0x0, 0x7f, 0x7f, 0xff, 0x0, 0x7f, 0x0, 0xff, 0x82, 0x7f, 0x0, 0xff, 0x0, 0x0, 0x0, 0xff, 0x4c, 0x4c, 0x4c, 0xff, 0x99, 0x99, 0x99, 0xff, 0xff, 0xff, 0xff, 0xff},
+ Stride: 16,
+ Rect: image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
+ },
+ },
+ {
+ "Clone YCbCr 440",
+ &image.YCbCr{
+ Y: []uint8{0x4c, 0x69, 0x1d, 0xb1, 0x96, 0xe2, 0x26, 0x34, 0xe, 0x59, 0x4b, 0x71, 0x0, 0x4c, 0x99, 0xff},
+ Cb: []uint8{0x2c, 0x01, 0x6b, 0xaa, 0x80, 0x80, 0x80, 0x80},
+ Cr: []uint8{0x15, 0x95, 0xc0, 0xb5, 0x80, 0x80, 0x80, 0x80},
+ YStride: 4,
+ CStride: 4,
+ SubsampleRatio: image.YCbCrSubsampleRatio440,
+ Rect: image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
+ },
+ &image.NRGBA{
+ Pix: []uint8{0x0, 0xb5, 0x0, 0xff, 0x86, 0x86, 0x0, 0xff, 0x77, 0x0, 0x0, 0xff, 0xfb, 0x7d, 0xfb, 0xff, 0x0, 0xff, 0x1, 0xff, 0xff, 0xff, 0x1, 0xff, 0x80, 0x0, 0x1, 0xff, 0x7e, 0x0, 0x7e, 0xff, 0xe, 0xe, 0xe, 0xff, 0x59, 0x59, 0x59, 0xff, 0x4b, 0x4b, 0x4b, 0xff, 0x71, 0x71, 0x71, 0xff, 0x0, 0x0, 0x0, 0xff, 0x4c, 0x4c, 0x4c, 0xff, 0x99, 0x99, 0x99, 0xff, 0xff, 0xff, 0xff, 0xff},
+ Stride: 16,
+ Rect: image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
+ },
+ },
+ {
+ "Clone YCbCr 422",
+ &image.YCbCr{
+ Y: []uint8{0x4c, 0x69, 0x1d, 0xb1, 0x96, 0xe2, 0x26, 0x34, 0xe, 0x59, 0x4b, 0x71, 0x0, 0x4c, 0x99, 0xff},
+ Cb: []uint8{0xd4, 0x8e, 0x01, 0xaa, 0x95, 0x40, 0x80, 0x80},
+ Cr: []uint8{0xeb, 0x36, 0x95, 0xb5, 0x41, 0x8c, 0x80, 0x80},
+ YStride: 4,
+ CStride: 2,
+ SubsampleRatio: image.YCbCrSubsampleRatio422,
+ Rect: image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
+ },
+ &image.NRGBA{
+ Pix: []uint8{0xe2, 0x0, 0xe1, 0xff, 0xff, 0x0, 0xfe, 0xff, 0x0, 0x4d, 0x36, 0xff, 0x49, 0xe1, 0xca, 0xff, 0xb3, 0xb3, 0x0, 0xff, 0xff, 0xff, 0x1, 0xff, 0x70, 0x0, 0x70, 0xff, 0x7e, 0x0, 0x7e, 0xff, 0x0, 0x34, 0x33, 0xff, 0x1, 0x7f, 0x7e, 0xff, 0x5c, 0x58, 0x0, 0xff, 0x82, 0x7e, 0x0, 0xff, 0x0, 0x0, 0x0, 0xff, 0x4c, 0x4c, 0x4c, 0xff, 0x99, 0x99, 0x99, 0xff, 0xff, 0xff, 0xff, 0xff},
+ Stride: 16,
+ Rect: image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
+ },
+ },
+ {
+ "Clone YCbCr 420",
+ &image.YCbCr{
+ Y: []uint8{0x4c, 0x69, 0x1d, 0xb1, 0x96, 0xe2, 0x26, 0x34, 0xe, 0x59, 0x4b, 0x71, 0x0, 0x4c, 0x99, 0xff},
+ Cb: []uint8{0x01, 0xaa, 0x80, 0x80},
+ Cr: []uint8{0x95, 0xb5, 0x80, 0x80},
+ YStride: 4, CStride: 2,
+ SubsampleRatio: image.YCbCrSubsampleRatio420,
+ Rect: image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
+ },
+ &image.NRGBA{
+ Pix: []uint8{0x69, 0x69, 0x0, 0xff, 0x86, 0x86, 0x0, 0xff, 0x67, 0x0, 0x67, 0xff, 0xfb, 0x7d, 0xfb, 0xff, 0xb3, 0xb3, 0x0, 0xff, 0xff, 0xff, 0x1, 0xff, 0x70, 0x0, 0x70, 0xff, 0x7e, 0x0, 0x7e, 0xff, 0xe, 0xe, 0xe, 0xff, 0x59, 0x59, 0x59, 0xff, 0x4b, 0x4b, 0x4b, 0xff, 0x71, 0x71, 0x71, 0xff, 0x0, 0x0, 0x0, 0xff, 0x4c, 0x4c, 0x4c, 0xff, 0x99, 0x99, 0x99, 0xff, 0xff, 0xff, 0xff, 0xff},
+ Stride: 16,
+ Rect: image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
+ },
+ },
+ {
+ "Clone Paletted",
+ &image.Paletted{
+ Rect: image.Rect(-1, -1, 5, 0),
+ Stride: 6 * 1,
+ Palette: color.Palette{
+ color.NRGBA{R: 0x00, G: 0x00, B: 0x00, A: 0xff},
+ color.NRGBA{R: 0xff, G: 0xff, B: 0xff, A: 0xff},
+ color.NRGBA{R: 0x7f, G: 0x7f, B: 0x7f, A: 0xff},
+ color.NRGBA{R: 0x7f, G: 0x00, B: 0x00, A: 0xff},
+ color.NRGBA{R: 0x00, G: 0x7f, B: 0x00, A: 0xff},
+ color.NRGBA{R: 0x00, G: 0x00, B: 0x7f, A: 0xff},
+ },
+ Pix: []uint8{0x0, 0x1, 0x2, 0x3, 0x4, 0x5},
+ },
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 6, 1),
+ Stride: 6 * 4,
+ Pix: []uint8{
+ 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0x7f, 0x7f, 0x7f, 0xff,
+ 0x7f, 0x00, 0x00, 0xff,
+ 0x00, 0x7f, 0x00, 0xff,
+ 0x00, 0x00, 0x7f, 0xff,
+ },
+ },
+ },
+ }
+
+ for _, d := range td {
+ got := Clone(d.src)
+ want := d.want
+
+ delta := 0
+ if _, ok := d.src.(*image.YCbCr); ok {
+ delta = 1
+ }
+
+ if !compareNRGBA(got, want, delta) {
+ t.Errorf("test [%s] failed: %#v", d.desc, got)
+ }
+ }
+}
diff --git a/vendor/github.com/disintegration/imaging/helpers.go b/vendor/github.com/disintegration/imaging/helpers.go
index 9184ccde6..5fb2b5aac 100644
--- a/vendor/github.com/disintegration/imaging/helpers.go
+++ b/vendor/github.com/disintegration/imaging/helpers.go
@@ -165,269 +165,3 @@ func New(width, height int, fillColor color.Color) *image.NRGBA {
return dst
}
-
-// Clone returns a copy of the given image.
-func Clone(img image.Image) *image.NRGBA {
- dstBounds := img.Bounds().Sub(img.Bounds().Min)
- dst := image.NewNRGBA(dstBounds)
-
- switch src := img.(type) {
- case *image.NRGBA:
- copyNRGBA(dst, src)
- case *image.NRGBA64:
- copyNRGBA64(dst, src)
- case *image.RGBA:
- copyRGBA(dst, src)
- case *image.RGBA64:
- copyRGBA64(dst, src)
- case *image.Gray:
- copyGray(dst, src)
- case *image.Gray16:
- copyGray16(dst, src)
- case *image.YCbCr:
- copyYCbCr(dst, src)
- case *image.Paletted:
- copyPaletted(dst, src)
- default:
- copyImage(dst, src)
- }
-
- return dst
-}
-
-func copyNRGBA(dst *image.NRGBA, src *image.NRGBA) {
- srcMinX := src.Rect.Min.X
- srcMinY := src.Rect.Min.Y
- dstW := dst.Rect.Dx()
- dstH := dst.Rect.Dy()
- rowSize := dstW * 4
- parallel(dstH, func(partStart, partEnd int) {
- for dstY := partStart; dstY < partEnd; dstY++ {
- di := dst.PixOffset(0, dstY)
- si := src.PixOffset(srcMinX, srcMinY+dstY)
- copy(dst.Pix[di:di+rowSize], src.Pix[si:si+rowSize])
- }
- })
-}
-
-func copyNRGBA64(dst *image.NRGBA, src *image.NRGBA64) {
- srcMinX := src.Rect.Min.X
- srcMinY := src.Rect.Min.Y
- dstW := dst.Rect.Dx()
- dstH := dst.Rect.Dy()
- parallel(dstH, func(partStart, partEnd int) {
- for dstY := partStart; dstY < partEnd; dstY++ {
- di := dst.PixOffset(0, dstY)
- si := src.PixOffset(srcMinX, srcMinY+dstY)
- for dstX := 0; dstX < dstW; dstX++ {
- dst.Pix[di+0] = src.Pix[si+0]
- dst.Pix[di+1] = src.Pix[si+2]
- dst.Pix[di+2] = src.Pix[si+4]
- dst.Pix[di+3] = src.Pix[si+6]
- di += 4
- si += 8
- }
- }
- })
-}
-
-func copyRGBA(dst *image.NRGBA, src *image.RGBA) {
- srcMinX := src.Rect.Min.X
- srcMinY := src.Rect.Min.Y
- dstW := dst.Rect.Dx()
- dstH := dst.Rect.Dy()
- parallel(dstH, func(partStart, partEnd int) {
- for dstY := partStart; dstY < partEnd; dstY++ {
- di := dst.PixOffset(0, dstY)
- si := src.PixOffset(srcMinX, srcMinY+dstY)
- for dstX := 0; dstX < dstW; dstX++ {
- a := src.Pix[si+3]
- dst.Pix[di+3] = a
-
- switch a {
- case 0:
- dst.Pix[di+0] = 0
- dst.Pix[di+1] = 0
- dst.Pix[di+2] = 0
- case 0xff:
- dst.Pix[di+0] = src.Pix[si+0]
- dst.Pix[di+1] = src.Pix[si+1]
- dst.Pix[di+2] = src.Pix[si+2]
- default:
- var tmp uint16
- tmp = uint16(src.Pix[si+0]) * 0xff / uint16(a)
- dst.Pix[di+0] = uint8(tmp)
- tmp = uint16(src.Pix[si+1]) * 0xff / uint16(a)
- dst.Pix[di+1] = uint8(tmp)
- tmp = uint16(src.Pix[si+2]) * 0xff / uint16(a)
- dst.Pix[di+2] = uint8(tmp)
- }
-
- di += 4
- si += 4
- }
- }
- })
-}
-
-func copyRGBA64(dst *image.NRGBA, src *image.RGBA64) {
- srcMinX := src.Rect.Min.X
- srcMinY := src.Rect.Min.Y
- dstW := dst.Rect.Dx()
- dstH := dst.Rect.Dy()
- parallel(dstH, func(partStart, partEnd int) {
- for dstY := partStart; dstY < partEnd; dstY++ {
- di := dst.PixOffset(0, dstY)
- si := src.PixOffset(srcMinX, srcMinY+dstY)
- for dstX := 0; dstX < dstW; dstX++ {
- a := src.Pix[si+6]
- dst.Pix[di+3] = a
-
- switch a {
- case 0:
- dst.Pix[di+0] = 0
- dst.Pix[di+1] = 0
- dst.Pix[di+2] = 0
- case 0xff:
- dst.Pix[di+0] = src.Pix[si+0]
- dst.Pix[di+1] = src.Pix[si+2]
- dst.Pix[di+2] = src.Pix[si+4]
- default:
- var tmp uint16
- tmp = uint16(src.Pix[si+0]) * 0xff / uint16(a)
- dst.Pix[di+0] = uint8(tmp)
- tmp = uint16(src.Pix[si+2]) * 0xff / uint16(a)
- dst.Pix[di+1] = uint8(tmp)
- tmp = uint16(src.Pix[si+4]) * 0xff / uint16(a)
- dst.Pix[di+2] = uint8(tmp)
- }
-
- di += 4
- si += 8
- }
- }
- })
-}
-
-func copyGray(dst *image.NRGBA, src *image.Gray) {
- srcMinX := src.Rect.Min.X
- srcMinY := src.Rect.Min.Y
- dstW := dst.Rect.Dx()
- dstH := dst.Rect.Dy()
- parallel(dstH, func(partStart, partEnd int) {
- for dstY := partStart; dstY < partEnd; dstY++ {
- di := dst.PixOffset(0, dstY)
- si := src.PixOffset(srcMinX, srcMinY+dstY)
- for dstX := 0; dstX < dstW; dstX++ {
- c := src.Pix[si]
- dst.Pix[di+0] = c
- dst.Pix[di+1] = c
- dst.Pix[di+2] = c
- dst.Pix[di+3] = 0xff
- di += 4
- si++
- }
- }
- })
-}
-
-func copyGray16(dst *image.NRGBA, src *image.Gray16) {
- srcMinX := src.Rect.Min.X
- srcMinY := src.Rect.Min.Y
- dstW := dst.Rect.Dx()
- dstH := dst.Rect.Dy()
- parallel(dstH, func(partStart, partEnd int) {
- for dstY := partStart; dstY < partEnd; dstY++ {
- di := dst.PixOffset(0, dstY)
- si := src.PixOffset(srcMinX, srcMinY+dstY)
- for dstX := 0; dstX < dstW; dstX++ {
- c := src.Pix[si]
- dst.Pix[di+0] = c
- dst.Pix[di+1] = c
- dst.Pix[di+2] = c
- dst.Pix[di+3] = 0xff
- di += 4
- si += 2
- }
- }
- })
-}
-
-func copyYCbCr(dst *image.NRGBA, src *image.YCbCr) {
- srcMinX := src.Rect.Min.X
- srcMinY := src.Rect.Min.Y
- dstW := dst.Rect.Dx()
- dstH := dst.Rect.Dy()
- parallel(dstH, func(partStart, partEnd int) {
- for dstY := partStart; dstY < partEnd; dstY++ {
- di := dst.PixOffset(0, dstY)
- for dstX := 0; dstX < dstW; dstX++ {
- srcX := srcMinX + dstX
- srcY := srcMinY + dstY
- siy := src.YOffset(srcX, srcY)
- sic := src.COffset(srcX, srcY)
- r, g, b := color.YCbCrToRGB(src.Y[siy], src.Cb[sic], src.Cr[sic])
- dst.Pix[di+0] = r
- dst.Pix[di+1] = g
- dst.Pix[di+2] = b
- dst.Pix[di+3] = 0xff
- di += 4
- }
- }
- })
-}
-
-func copyPaletted(dst *image.NRGBA, src *image.Paletted) {
- srcMinX := src.Rect.Min.X
- srcMinY := src.Rect.Min.Y
- dstW := dst.Rect.Dx()
- dstH := dst.Rect.Dy()
- plen := len(src.Palette)
- pnew := make([]color.NRGBA, plen)
- for i := 0; i < plen; i++ {
- pnew[i] = color.NRGBAModel.Convert(src.Palette[i]).(color.NRGBA)
- }
- parallel(dstH, func(partStart, partEnd int) {
- for dstY := partStart; dstY < partEnd; dstY++ {
- di := dst.PixOffset(0, dstY)
- si := src.PixOffset(srcMinX, srcMinY+dstY)
- for dstX := 0; dstX < dstW; dstX++ {
- c := pnew[src.Pix[si]]
- dst.Pix[di+0] = c.R
- dst.Pix[di+1] = c.G
- dst.Pix[di+2] = c.B
- dst.Pix[di+3] = c.A
- di += 4
- si++
- }
- }
- })
-}
-
-func copyImage(dst *image.NRGBA, src image.Image) {
- srcMinX := src.Bounds().Min.X
- srcMinY := src.Bounds().Min.Y
- dstW := dst.Bounds().Dx()
- dstH := dst.Bounds().Dy()
- parallel(dstH, func(partStart, partEnd int) {
- for dstY := partStart; dstY < partEnd; dstY++ {
- di := dst.PixOffset(0, dstY)
- for dstX := 0; dstX < dstW; dstX++ {
- c := color.NRGBAModel.Convert(src.At(srcMinX+dstX, srcMinY+dstY)).(color.NRGBA)
- dst.Pix[di+0] = c.R
- dst.Pix[di+1] = c.G
- dst.Pix[di+2] = c.B
- dst.Pix[di+3] = c.A
- di += 4
- }
- }
- })
-}
-
-// toNRGBA converts any image type to *image.NRGBA with min-point at (0, 0).
-func toNRGBA(img image.Image) *image.NRGBA {
- if img, ok := img.(*image.NRGBA); ok && img.Bounds().Min.Eq(image.ZP) {
- return img
- }
- return Clone(img)
-}
diff --git a/vendor/github.com/disintegration/imaging/helpers_test.go b/vendor/github.com/disintegration/imaging/helpers_test.go
index 1287ec588..c3b87f23c 100644
--- a/vendor/github.com/disintegration/imaging/helpers_test.go
+++ b/vendor/github.com/disintegration/imaging/helpers_test.go
@@ -140,246 +140,6 @@ func TestNew(t *testing.T) {
}
}
-func TestClone(t *testing.T) {
- td := []struct {
- desc string
- src image.Image
- want *image.NRGBA
- }{
- {
- "Clone NRGBA",
- &image.NRGBA{
- Rect: image.Rect(-1, -1, 0, 1),
- Stride: 1 * 4,
- Pix: []uint8{0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff},
- },
- &image.NRGBA{
- Rect: image.Rect(0, 0, 1, 2),
- Stride: 1 * 4,
- Pix: []uint8{0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff},
- },
- },
- {
- "Clone NRGBA64",
- &image.NRGBA64{
- Rect: image.Rect(-1, -1, 0, 1),
- Stride: 1 * 8,
- Pix: []uint8{
- 0x00, 0x00, 0x11, 0x11, 0x22, 0x22, 0x33, 0x33,
- 0xcc, 0xcc, 0xdd, 0xdd, 0xee, 0xee, 0xff, 0xff,
- },
- },
- &image.NRGBA{
- Rect: image.Rect(0, 0, 1, 2),
- Stride: 1 * 4,
- Pix: []uint8{0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff},
- },
- },
- {
- "Clone RGBA",
- &image.RGBA{
- Rect: image.Rect(-1, -1, 0, 2),
- Stride: 1 * 4,
- Pix: []uint8{0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff},
- },
- &image.NRGBA{
- Rect: image.Rect(0, 0, 1, 3),
- Stride: 1 * 4,
- Pix: []uint8{0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xaa, 0x33, 0xcc, 0xdd, 0xee, 0xff},
- },
- },
- {
- "Clone RGBA64",
- &image.RGBA64{
- Rect: image.Rect(-1, -1, 0, 2),
- Stride: 1 * 8,
- Pix: []uint8{
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x11, 0x11, 0x22, 0x22, 0x33, 0x33,
- 0xcc, 0xcc, 0xdd, 0xdd, 0xee, 0xee, 0xff, 0xff,
- },
- },
- &image.NRGBA{
- Rect: image.Rect(0, 0, 1, 3),
- Stride: 1 * 4,
- Pix: []uint8{0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xaa, 0x33, 0xcc, 0xdd, 0xee, 0xff},
- },
- },
- {
- "Clone Gray",
- &image.Gray{
- Rect: image.Rect(-1, -1, 0, 1),
- Stride: 1 * 1,
- Pix: []uint8{0x11, 0xee},
- },
- &image.NRGBA{
- Rect: image.Rect(0, 0, 1, 2),
- Stride: 1 * 4,
- Pix: []uint8{0x11, 0x11, 0x11, 0xff, 0xee, 0xee, 0xee, 0xff},
- },
- },
- {
- "Clone Gray16",
- &image.Gray16{
- Rect: image.Rect(-1, -1, 0, 1),
- Stride: 1 * 2,
- Pix: []uint8{0x11, 0x11, 0xee, 0xee},
- },
- &image.NRGBA{
- Rect: image.Rect(0, 0, 1, 2),
- Stride: 1 * 4,
- Pix: []uint8{0x11, 0x11, 0x11, 0xff, 0xee, 0xee, 0xee, 0xff},
- },
- },
- {
- "Clone Alpha",
- &image.Alpha{
- Rect: image.Rect(-1, -1, 0, 1),
- Stride: 1 * 1,
- Pix: []uint8{0x11, 0xee},
- },
- &image.NRGBA{
- Rect: image.Rect(0, 0, 1, 2),
- Stride: 1 * 4,
- Pix: []uint8{0xff, 0xff, 0xff, 0x11, 0xff, 0xff, 0xff, 0xee},
- },
- },
- {
- "Clone YCbCr",
- &image.YCbCr{
- Rect: image.Rect(-1, -1, 5, 0),
- SubsampleRatio: image.YCbCrSubsampleRatio444,
- YStride: 6,
- CStride: 6,
- Y: []uint8{0x00, 0xff, 0x7f, 0x26, 0x4b, 0x0e},
- Cb: []uint8{0x80, 0x80, 0x80, 0x6b, 0x56, 0xc0},
- Cr: []uint8{0x80, 0x80, 0x80, 0xc0, 0x4b, 0x76},
- },
- &image.NRGBA{
- Rect: image.Rect(0, 0, 6, 1),
- Stride: 6 * 4,
- Pix: []uint8{
- 0x00, 0x00, 0x00, 0xff,
- 0xff, 0xff, 0xff, 0xff,
- 0x7f, 0x7f, 0x7f, 0xff,
- 0x7f, 0x00, 0x00, 0xff,
- 0x00, 0x7f, 0x00, 0xff,
- 0x00, 0x00, 0x7f, 0xff,
- },
- },
- },
- {
- "Clone YCbCr 444",
- &image.YCbCr{
- Y: []uint8{0x4c, 0x69, 0x1d, 0xb1, 0x96, 0xe2, 0x26, 0x34, 0xe, 0x59, 0x4b, 0x71, 0x0, 0x4c, 0x99, 0xff},
- Cb: []uint8{0x55, 0xd4, 0xff, 0x8e, 0x2c, 0x01, 0x6b, 0xaa, 0xc0, 0x95, 0x56, 0x40, 0x80, 0x80, 0x80, 0x80},
- Cr: []uint8{0xff, 0xeb, 0x6b, 0x36, 0x15, 0x95, 0xc0, 0xb5, 0x76, 0x41, 0x4b, 0x8c, 0x80, 0x80, 0x80, 0x80},
- YStride: 4,
- CStride: 4,
- SubsampleRatio: image.YCbCrSubsampleRatio444,
- Rect: image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
- },
- &image.NRGBA{
- Pix: []uint8{0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x49, 0xe1, 0xca, 0xff, 0x0, 0xff, 0x0, 0xff, 0xff, 0xff, 0x0, 0xff, 0x7f, 0x0, 0x0, 0xff, 0x7f, 0x0, 0x7f, 0xff, 0x0, 0x0, 0x7f, 0xff, 0x0, 0x7f, 0x7f, 0xff, 0x0, 0x7f, 0x0, 0xff, 0x82, 0x7f, 0x0, 0xff, 0x0, 0x0, 0x0, 0xff, 0x4c, 0x4c, 0x4c, 0xff, 0x99, 0x99, 0x99, 0xff, 0xff, 0xff, 0xff, 0xff},
- Stride: 16,
- Rect: image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
- },
- },
- {
- "Clone YCbCr 440",
- &image.YCbCr{
- Y: []uint8{0x4c, 0x69, 0x1d, 0xb1, 0x96, 0xe2, 0x26, 0x34, 0xe, 0x59, 0x4b, 0x71, 0x0, 0x4c, 0x99, 0xff},
- Cb: []uint8{0x2c, 0x01, 0x6b, 0xaa, 0x80, 0x80, 0x80, 0x80},
- Cr: []uint8{0x15, 0x95, 0xc0, 0xb5, 0x80, 0x80, 0x80, 0x80},
- YStride: 4,
- CStride: 4,
- SubsampleRatio: image.YCbCrSubsampleRatio440,
- Rect: image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
- },
- &image.NRGBA{
- Pix: []uint8{0x0, 0xb5, 0x0, 0xff, 0x86, 0x86, 0x0, 0xff, 0x77, 0x0, 0x0, 0xff, 0xfb, 0x7d, 0xfb, 0xff, 0x0, 0xff, 0x1, 0xff, 0xff, 0xff, 0x1, 0xff, 0x80, 0x0, 0x1, 0xff, 0x7e, 0x0, 0x7e, 0xff, 0xe, 0xe, 0xe, 0xff, 0x59, 0x59, 0x59, 0xff, 0x4b, 0x4b, 0x4b, 0xff, 0x71, 0x71, 0x71, 0xff, 0x0, 0x0, 0x0, 0xff, 0x4c, 0x4c, 0x4c, 0xff, 0x99, 0x99, 0x99, 0xff, 0xff, 0xff, 0xff, 0xff},
- Stride: 16,
- Rect: image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
- },
- },
- {
- "Clone YCbCr 422",
- &image.YCbCr{
- Y: []uint8{0x4c, 0x69, 0x1d, 0xb1, 0x96, 0xe2, 0x26, 0x34, 0xe, 0x59, 0x4b, 0x71, 0x0, 0x4c, 0x99, 0xff},
- Cb: []uint8{0xd4, 0x8e, 0x01, 0xaa, 0x95, 0x40, 0x80, 0x80},
- Cr: []uint8{0xeb, 0x36, 0x95, 0xb5, 0x41, 0x8c, 0x80, 0x80},
- YStride: 4,
- CStride: 2,
- SubsampleRatio: image.YCbCrSubsampleRatio422,
- Rect: image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
- },
- &image.NRGBA{
- Pix: []uint8{0xe2, 0x0, 0xe1, 0xff, 0xff, 0x0, 0xfe, 0xff, 0x0, 0x4d, 0x36, 0xff, 0x49, 0xe1, 0xca, 0xff, 0xb3, 0xb3, 0x0, 0xff, 0xff, 0xff, 0x1, 0xff, 0x70, 0x0, 0x70, 0xff, 0x7e, 0x0, 0x7e, 0xff, 0x0, 0x34, 0x33, 0xff, 0x1, 0x7f, 0x7e, 0xff, 0x5c, 0x58, 0x0, 0xff, 0x82, 0x7e, 0x0, 0xff, 0x0, 0x0, 0x0, 0xff, 0x4c, 0x4c, 0x4c, 0xff, 0x99, 0x99, 0x99, 0xff, 0xff, 0xff, 0xff, 0xff},
- Stride: 16,
- Rect: image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
- },
- },
- {
- "Clone YCbCr 420",
- &image.YCbCr{
- Y: []uint8{0x4c, 0x69, 0x1d, 0xb1, 0x96, 0xe2, 0x26, 0x34, 0xe, 0x59, 0x4b, 0x71, 0x0, 0x4c, 0x99, 0xff},
- Cb: []uint8{0x01, 0xaa, 0x80, 0x80},
- Cr: []uint8{0x95, 0xb5, 0x80, 0x80},
- YStride: 4, CStride: 2,
- SubsampleRatio: image.YCbCrSubsampleRatio420,
- Rect: image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
- },
- &image.NRGBA{
- Pix: []uint8{0x69, 0x69, 0x0, 0xff, 0x86, 0x86, 0x0, 0xff, 0x67, 0x0, 0x67, 0xff, 0xfb, 0x7d, 0xfb, 0xff, 0xb3, 0xb3, 0x0, 0xff, 0xff, 0xff, 0x1, 0xff, 0x70, 0x0, 0x70, 0xff, 0x7e, 0x0, 0x7e, 0xff, 0xe, 0xe, 0xe, 0xff, 0x59, 0x59, 0x59, 0xff, 0x4b, 0x4b, 0x4b, 0xff, 0x71, 0x71, 0x71, 0xff, 0x0, 0x0, 0x0, 0xff, 0x4c, 0x4c, 0x4c, 0xff, 0x99, 0x99, 0x99, 0xff, 0xff, 0xff, 0xff, 0xff},
- Stride: 16,
- Rect: image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
- },
- },
- {
- "Clone Paletted",
- &image.Paletted{
- Rect: image.Rect(-1, -1, 5, 0),
- Stride: 6 * 1,
- Palette: color.Palette{
- color.NRGBA{R: 0x00, G: 0x00, B: 0x00, A: 0xff},
- color.NRGBA{R: 0xff, G: 0xff, B: 0xff, A: 0xff},
- color.NRGBA{R: 0x7f, G: 0x7f, B: 0x7f, A: 0xff},
- color.NRGBA{R: 0x7f, G: 0x00, B: 0x00, A: 0xff},
- color.NRGBA{R: 0x00, G: 0x7f, B: 0x00, A: 0xff},
- color.NRGBA{R: 0x00, G: 0x00, B: 0x7f, A: 0xff},
- },
- Pix: []uint8{0x0, 0x1, 0x2, 0x3, 0x4, 0x5},
- },
- &image.NRGBA{
- Rect: image.Rect(0, 0, 6, 1),
- Stride: 6 * 4,
- Pix: []uint8{
- 0x00, 0x00, 0x00, 0xff,
- 0xff, 0xff, 0xff, 0xff,
- 0x7f, 0x7f, 0x7f, 0xff,
- 0x7f, 0x00, 0x00, 0xff,
- 0x00, 0x7f, 0x00, 0xff,
- 0x00, 0x00, 0x7f, 0xff,
- },
- },
- },
- }
-
- for _, d := range td {
- got := Clone(d.src)
- want := d.want
-
- delta := 0
- if _, ok := d.src.(*image.YCbCr); ok {
- delta = 1
- }
-
- if !compareNRGBA(got, want, delta) {
- t.Errorf("test [%s] failed: %#v", d.desc, got)
- }
- }
-}
-
func TestFormats(t *testing.T) {
formatNames := map[Format]string{
JPEG: "JPEG",
diff --git a/vendor/github.com/disintegration/imaging/histogram.go b/vendor/github.com/disintegration/imaging/histogram.go
index 3afcb7ae2..967ee6a25 100644
--- a/vendor/github.com/disintegration/imaging/histogram.go
+++ b/vendor/github.com/disintegration/imaging/histogram.go
@@ -28,7 +28,7 @@ func Histogram(img image.Image) [256]float64 {
g := src.Pix[i+1]
b := src.Pix[i+2]
- var y float32 = 0.299*float32(r) + 0.587*float32(g) + 0.114*float32(b)
+ y := 0.299*float32(r) + 0.587*float32(g) + 0.114*float32(b)
histogram[int(y+0.5)]++
total++
diff --git a/vendor/github.com/disintegration/imaging/resize.go b/vendor/github.com/disintegration/imaging/resize.go
index 1659bbce8..cd5bfb5d8 100644
--- a/vendor/github.com/disintegration/imaging/resize.go
+++ b/vendor/github.com/disintegration/imaging/resize.go
@@ -19,6 +19,7 @@ func precomputeWeights(dstSize, srcSize int, filter ResampleFilter) [][]indexWei
ru := math.Ceil(scale * filter.Support)
out := make([][]indexWeight, dstSize)
+ tmp := make([]indexWeight, 0, dstSize*int(ru+2)*2)
for v := 0; v < dstSize; v++ {
fu := (float64(v)+0.5)*du - 0.5
@@ -37,14 +38,17 @@ func precomputeWeights(dstSize, srcSize int, filter ResampleFilter) [][]indexWei
w := filter.Kernel((float64(u) - fu) / scale)
if w != 0 {
sum += w
- out[v] = append(out[v], indexWeight{index: u, weight: w})
+ tmp = append(tmp, indexWeight{index: u, weight: w})
}
}
if sum != 0 {
- for i := range out[v] {
- out[v][i].weight /= sum
+ for i := range tmp {
+ tmp[i].weight /= sum
}
}
+
+ out[v] = tmp
+ tmp = tmp[len(tmp):]
}
return out
diff --git a/vendor/github.com/disintegration/imaging/transform.go b/vendor/github.com/disintegration/imaging/transform.go
index 43668dfd7..94d72d556 100644
--- a/vendor/github.com/disintegration/imaging/transform.go
+++ b/vendor/github.com/disintegration/imaging/transform.go
@@ -235,7 +235,7 @@ func Rotate(img image.Image, angle float64, bgColor color.Color) *image.NRGBA {
dstYOff := float64(dstH)/2 - 0.5
bgColorNRGBA := color.NRGBAModel.Convert(bgColor).(color.NRGBA)
- sin, cos := math.Sincos(math.Pi * float64(angle) / 180)
+ sin, cos := math.Sincos(math.Pi * angle / 180)
parallel(dstH, func(partStart, partEnd int) {
for dstY := partStart; dstY < partEnd; dstY++ {
@@ -259,7 +259,7 @@ func rotatedSize(w, h int, angle float64) (int, int) {
return 0, 0
}
- sin, cos := math.Sincos(math.Pi * float64(angle) / 180)
+ sin, cos := math.Sincos(math.Pi * angle / 180)
x1, y1 := rotatePoint(float64(w-1), 0, sin, cos)
x2, y2 := rotatePoint(float64(w-1), float64(h-1), sin, cos)
x3, y3 := rotatePoint(0, float64(h-1), sin, cos)
diff --git a/vendor/github.com/go-ini/ini/.github/ISSUE_TEMPLATE.md b/vendor/github.com/go-ini/ini/.github/ISSUE_TEMPLATE.md
new file mode 100644
index 000000000..849f69f4b
--- /dev/null
+++ b/vendor/github.com/go-ini/ini/.github/ISSUE_TEMPLATE.md
@@ -0,0 +1,5 @@
+### Please give general description of the problem
+
+### Please provide code snippets to reproduce the problem described above
+
+### Do you have any suggestion to fix the problem? \ No newline at end of file
diff --git a/vendor/github.com/go-ini/ini/.github/PULL_REQUEST_TEMPLATE.md b/vendor/github.com/go-ini/ini/.github/PULL_REQUEST_TEMPLATE.md
new file mode 100644
index 000000000..b4565aeb5
--- /dev/null
+++ b/vendor/github.com/go-ini/ini/.github/PULL_REQUEST_TEMPLATE.md
@@ -0,0 +1,3 @@
+### What problem should be fixed?
+
+### Have you added test cases to catch the problem?
diff --git a/vendor/github.com/go-ini/ini/.gitignore b/vendor/github.com/go-ini/ini/.gitignore
index c5203bf6e..12411127b 100644
--- a/vendor/github.com/go-ini/ini/.gitignore
+++ b/vendor/github.com/go-ini/ini/.gitignore
@@ -3,3 +3,4 @@ ini.sublime-project
ini.sublime-workspace
testdata/conf_reflect.ini
.idea
+/.vscode
diff --git a/vendor/github.com/go-ini/ini/.travis.yml b/vendor/github.com/go-ini/ini/.travis.yml
index d9d1b8ffa..b097527e1 100644
--- a/vendor/github.com/go-ini/ini/.travis.yml
+++ b/vendor/github.com/go-ini/ini/.travis.yml
@@ -5,9 +5,11 @@ go:
- 1.6.x
- 1.7.x
- 1.8.x
- - master
+ - 1.9.x
script:
- go get golang.org/x/tools/cmd/cover
- go get github.com/smartystreets/goconvey
+ - mkdir -p $HOME/gopath/src/gopkg.in
+ - ln -s $HOME/gopath/src/github.com/go-ini/ini $HOME/gopath/src/gopkg.in/ini.v1
- go test -v -cover -race
diff --git a/vendor/github.com/go-ini/ini/LICENSE b/vendor/github.com/go-ini/ini/LICENSE
index 37ec93a14..d361bbcdf 100644
--- a/vendor/github.com/go-ini/ini/LICENSE
+++ b/vendor/github.com/go-ini/ini/LICENSE
@@ -176,7 +176,7 @@ recommend that a file or class name and description of purpose be included on
the same "printed page" as the copyright notice for easier identification within
third-party archives.
- Copyright [yyyy] [name of copyright owner]
+ Copyright 2014 Unknwon
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
diff --git a/vendor/github.com/go-ini/ini/Makefile b/vendor/github.com/go-ini/ini/Makefile
index ac034e525..1316911d2 100644
--- a/vendor/github.com/go-ini/ini/Makefile
+++ b/vendor/github.com/go-ini/ini/Makefile
@@ -1,4 +1,4 @@
-.PHONY: build test bench vet
+.PHONY: build test bench vet coverage
build: vet bench
@@ -10,3 +10,6 @@ bench:
vet:
go vet
+
+coverage:
+ go test -coverprofile=c.out && go tool cover -html=c.out && rm c.out \ No newline at end of file
diff --git a/vendor/github.com/go-ini/ini/README.md b/vendor/github.com/go-ini/ini/README.md
index e67d51f32..f4ff27cd3 100644
--- a/vendor/github.com/go-ini/ini/README.md
+++ b/vendor/github.com/go-ini/ini/README.md
@@ -101,7 +101,7 @@ skip-name-resolve
By default, this is considered as missing value. But if you know you're going to deal with those cases, you can assign advanced load options:
```go
-cfg, err := LoadSources(LoadOptions{AllowBooleanKeys: true}, "my.cnf"))
+cfg, err := ini.LoadSources(ini.LoadOptions{AllowBooleanKeys: true}, "my.cnf"))
```
The value of those keys are always `true`, and when you save to a file, it will keep in the same foramt as you read.
@@ -125,7 +125,7 @@ If you want to save a value with `#` or `;`, please quote them with ``` ` ``` or
Alternatively, you can use following `LoadOptions` to completely ignore inline comments:
```go
-cfg, err := LoadSources(LoadOptions{IgnoreInlineComment: true}, "app.ini"))
+cfg, err := ini.LoadSources(ini.LoadOptions{IgnoreInlineComment: true}, "app.ini"))
```
### Working with sections
@@ -329,6 +329,20 @@ foo = "some value" // foo: some value
bar = 'some value' // bar: some value
```
+Sometimes you downloaded file from [Crowdin](https://crowdin.com/) has values like the following (value is surrounded by double quotes and quotes in the value are escaped):
+
+```ini
+create_repo="created repository <a href=\"%s\">%s</a>"
+```
+
+How do you transform this to regular format automatically?
+
+```go
+cfg, err := ini.LoadSources(ini.LoadOptions{UnescapeValueDoubleQuotes: true}, "en-US.ini"))
+cfg.Section("<name of your section>").Key("create_repo").String()
+// You got: created repository <a href="%s">%s</a>
+```
+
That's all? Hmm, no.
#### Helper methods of working with values
@@ -480,7 +494,7 @@ cfg.Section("package.sub").ParentKeys() // ["CLONE_URL"]
Sometimes, you have sections that do not contain key-value pairs but raw content, to handle such case, you can use `LoadOptions.UnparsableSections`:
```go
-cfg, err := LoadSources(LoadOptions{UnparseableSections: []string{"COMMENTS"}}, `[COMMENTS]
+cfg, err := ini.LoadSources(ini.LoadOptions{UnparseableSections: []string{"COMMENTS"}}, `[COMMENTS]
<1><L.Slide#2> This slide has the fuel listed in the wrong units <e.1>`))
body := cfg.Section("COMMENTS").Body()
@@ -573,7 +587,7 @@ Why not?
```go
type Embeded struct {
- Dates []time.Time `delim:"|"`
+ Dates []time.Time `delim:"|" comment:"Time data"`
Places []string `ini:"places,omitempty"`
None []int `ini:",omitempty"`
}
@@ -581,10 +595,10 @@ type Embeded struct {
type Author struct {
Name string `ini:"NAME"`
Male bool
- Age int
+ Age int `comment:"Author's age"`
GPA float64
NeverMind string `ini:"-"`
- *Embeded
+ *Embeded `comment:"Embeded section"`
}
func main() {
@@ -605,10 +619,13 @@ So, what do I get?
```ini
NAME = Unknwon
Male = true
+; Author's age
Age = 21
GPA = 2.8
+; Embeded section
[Embeded]
+; Time data
Dates = 2015-08-07T22:14:22+08:00|2015-08-07T22:14:22+08:00
places = HangZhou,Boston
```
diff --git a/vendor/github.com/go-ini/ini/README_ZH.md b/vendor/github.com/go-ini/ini/README_ZH.md
index 0cf419449..69aefef12 100644
--- a/vendor/github.com/go-ini/ini/README_ZH.md
+++ b/vendor/github.com/go-ini/ini/README_ZH.md
@@ -94,7 +94,7 @@ skip-name-resolve
默认情况下这被认为是缺失值而无法完成解析,但可以通过高级的加载选项对它们进行处理:
```go
-cfg, err := LoadSources(LoadOptions{AllowBooleanKeys: true}, "my.cnf"))
+cfg, err := ini.LoadSources(ini.LoadOptions{AllowBooleanKeys: true}, "my.cnf"))
```
这些键的值永远为 `true`,且在保存到文件时也只会输出键名。
@@ -118,7 +118,7 @@ key, err := sec.NewBooleanKey("skip-host-cache")
除此之外,您还可以通过 `LoadOptions` 完全忽略行内注释:
```go
-cfg, err := LoadSources(LoadOptions{IgnoreInlineComment: true}, "app.ini"))
+cfg, err := ini.LoadSources(ini.LoadOptions{IgnoreInlineComment: true}, "app.ini"))
```
### 操作分区(Section)
@@ -322,6 +322,20 @@ foo = "some value" // foo: some value
bar = 'some value' // bar: some value
```
+有时您会获得像从 [Crowdin](https://crowdin.com/) 网站下载的文件那样具有特殊格式的值(值使用双引号括起来,内部的双引号被转义):
+
+```ini
+create_repo="创建了仓库 <a href=\"%s\">%s</a>"
+```
+
+那么,怎么自动地将这类值进行处理呢?
+
+```go
+cfg, err := ini.LoadSources(ini.LoadOptions{UnescapeValueDoubleQuotes: true}, "en-US.ini"))
+cfg.Section("<name of your section>").Key("create_repo").String()
+// You got: 创建了仓库 <a href="%s">%s</a>
+```
+
这就是全部了?哈哈,当然不是。
#### 操作键值的辅助方法
@@ -473,7 +487,7 @@ cfg.Section("package.sub").ParentKeys() // ["CLONE_URL"]
如果遇到一些比较特殊的分区,它们不包含常见的键值对,而是没有固定格式的纯文本,则可以使用 `LoadOptions.UnparsableSections` 进行处理:
```go
-cfg, err := LoadSources(LoadOptions{UnparseableSections: []string{"COMMENTS"}}, `[COMMENTS]
+cfg, err := LoadSources(ini.LoadOptions{UnparseableSections: []string{"COMMENTS"}}, `[COMMENTS]
<1><L.Slide#2> This slide has the fuel listed in the wrong units <e.1>`))
body := cfg.Section("COMMENTS").Body()
@@ -564,7 +578,7 @@ p := &Person{
```go
type Embeded struct {
- Dates []time.Time `delim:"|"`
+ Dates []time.Time `delim:"|" comment:"Time data"`
Places []string `ini:"places,omitempty"`
None []int `ini:",omitempty"`
}
@@ -572,10 +586,10 @@ type Embeded struct {
type Author struct {
Name string `ini:"NAME"`
Male bool
- Age int
+ Age int `comment:"Author's age"`
GPA float64
NeverMind string `ini:"-"`
- *Embeded
+ *Embeded `comment:"Embeded section"`
}
func main() {
@@ -596,10 +610,13 @@ func main() {
```ini
NAME = Unknwon
Male = true
+; Author's age
Age = 21
GPA = 2.8
+; Embeded section
[Embeded]
+; Time data
Dates = 2015-08-07T22:14:22+08:00|2015-08-07T22:14:22+08:00
places = HangZhou,Boston
```
diff --git a/vendor/github.com/go-ini/ini/bench_test.go b/vendor/github.com/go-ini/ini/bench_test.go
new file mode 100644
index 000000000..fc1802469
--- /dev/null
+++ b/vendor/github.com/go-ini/ini/bench_test.go
@@ -0,0 +1,118 @@
+// Copyright 2017 Unknwon
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+package ini_test
+
+import (
+ "testing"
+
+ "gopkg.in/ini.v1"
+)
+
+func newTestFile(block bool) *ini.File {
+ c, _ := ini.Load([]byte(_CONF_DATA))
+ c.BlockMode = block
+ return c
+}
+
+func Benchmark_Key_Value(b *testing.B) {
+ c := newTestFile(true)
+ for i := 0; i < b.N; i++ {
+ c.Section("").Key("NAME").Value()
+ }
+}
+
+func Benchmark_Key_Value_NonBlock(b *testing.B) {
+ c := newTestFile(false)
+ for i := 0; i < b.N; i++ {
+ c.Section("").Key("NAME").Value()
+ }
+}
+
+func Benchmark_Key_Value_ViaSection(b *testing.B) {
+ c := newTestFile(true)
+ sec := c.Section("")
+ for i := 0; i < b.N; i++ {
+ sec.Key("NAME").Value()
+ }
+}
+
+func Benchmark_Key_Value_ViaSection_NonBlock(b *testing.B) {
+ c := newTestFile(false)
+ sec := c.Section("")
+ for i := 0; i < b.N; i++ {
+ sec.Key("NAME").Value()
+ }
+}
+
+func Benchmark_Key_Value_Direct(b *testing.B) {
+ c := newTestFile(true)
+ key := c.Section("").Key("NAME")
+ for i := 0; i < b.N; i++ {
+ key.Value()
+ }
+}
+
+func Benchmark_Key_Value_Direct_NonBlock(b *testing.B) {
+ c := newTestFile(false)
+ key := c.Section("").Key("NAME")
+ for i := 0; i < b.N; i++ {
+ key.Value()
+ }
+}
+
+func Benchmark_Key_String(b *testing.B) {
+ c := newTestFile(true)
+ for i := 0; i < b.N; i++ {
+ _ = c.Section("").Key("NAME").String()
+ }
+}
+
+func Benchmark_Key_String_NonBlock(b *testing.B) {
+ c := newTestFile(false)
+ for i := 0; i < b.N; i++ {
+ _ = c.Section("").Key("NAME").String()
+ }
+}
+
+func Benchmark_Key_String_ViaSection(b *testing.B) {
+ c := newTestFile(true)
+ sec := c.Section("")
+ for i := 0; i < b.N; i++ {
+ _ = sec.Key("NAME").String()
+ }
+}
+
+func Benchmark_Key_String_ViaSection_NonBlock(b *testing.B) {
+ c := newTestFile(false)
+ sec := c.Section("")
+ for i := 0; i < b.N; i++ {
+ _ = sec.Key("NAME").String()
+ }
+}
+
+func Benchmark_Key_SetValue(b *testing.B) {
+ c := newTestFile(true)
+ for i := 0; i < b.N; i++ {
+ c.Section("").Key("NAME").SetValue("10")
+ }
+}
+
+func Benchmark_Key_SetValue_VisSection(b *testing.B) {
+ c := newTestFile(true)
+ sec := c.Section("")
+ for i := 0; i < b.N; i++ {
+ sec.Key("NAME").SetValue("10")
+ }
+}
diff --git a/vendor/github.com/go-ini/ini/file.go b/vendor/github.com/go-ini/ini/file.go
new file mode 100644
index 000000000..93ac50836
--- /dev/null
+++ b/vendor/github.com/go-ini/ini/file.go
@@ -0,0 +1,392 @@
+// Copyright 2017 Unknwon
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+package ini
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "strings"
+ "sync"
+)
+
+// File represents a combination of a or more INI file(s) in memory.
+type File struct {
+ options LoadOptions
+ dataSources []dataSource
+
+ // Should make things safe, but sometimes doesn't matter.
+ BlockMode bool
+ lock sync.RWMutex
+
+ // To keep data in order.
+ sectionList []string
+ // Actual data is stored here.
+ sections map[string]*Section
+
+ NameMapper
+ ValueMapper
+}
+
+// newFile initializes File object with given data sources.
+func newFile(dataSources []dataSource, opts LoadOptions) *File {
+ return &File{
+ BlockMode: true,
+ dataSources: dataSources,
+ sections: make(map[string]*Section),
+ sectionList: make([]string, 0, 10),
+ options: opts,
+ }
+}
+
+// Empty returns an empty file object.
+func Empty() *File {
+ // Ignore error here, we sure our data is good.
+ f, _ := Load([]byte(""))
+ return f
+}
+
+// NewSection creates a new section.
+func (f *File) NewSection(name string) (*Section, error) {
+ if len(name) == 0 {
+ return nil, errors.New("error creating new section: empty section name")
+ } else if f.options.Insensitive && name != DEFAULT_SECTION {
+ name = strings.ToLower(name)
+ }
+
+ if f.BlockMode {
+ f.lock.Lock()
+ defer f.lock.Unlock()
+ }
+
+ if inSlice(name, f.sectionList) {
+ return f.sections[name], nil
+ }
+
+ f.sectionList = append(f.sectionList, name)
+ f.sections[name] = newSection(f, name)
+ return f.sections[name], nil
+}
+
+// NewRawSection creates a new section with an unparseable body.
+func (f *File) NewRawSection(name, body string) (*Section, error) {
+ section, err := f.NewSection(name)
+ if err != nil {
+ return nil, err
+ }
+
+ section.isRawSection = true
+ section.rawBody = body
+ return section, nil
+}
+
+// NewSections creates a list of sections.
+func (f *File) NewSections(names ...string) (err error) {
+ for _, name := range names {
+ if _, err = f.NewSection(name); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// GetSection returns section by given name.
+func (f *File) GetSection(name string) (*Section, error) {
+ if len(name) == 0 {
+ name = DEFAULT_SECTION
+ }
+ if f.options.Insensitive {
+ name = strings.ToLower(name)
+ }
+
+ if f.BlockMode {
+ f.lock.RLock()
+ defer f.lock.RUnlock()
+ }
+
+ sec := f.sections[name]
+ if sec == nil {
+ return nil, fmt.Errorf("section '%s' does not exist", name)
+ }
+ return sec, nil
+}
+
+// Section assumes named section exists and returns a zero-value when not.
+func (f *File) Section(name string) *Section {
+ sec, err := f.GetSection(name)
+ if err != nil {
+ // Note: It's OK here because the only possible error is empty section name,
+ // but if it's empty, this piece of code won't be executed.
+ sec, _ = f.NewSection(name)
+ return sec
+ }
+ return sec
+}
+
+// Section returns list of Section.
+func (f *File) Sections() []*Section {
+ sections := make([]*Section, len(f.sectionList))
+ for i := range f.sectionList {
+ sections[i] = f.Section(f.sectionList[i])
+ }
+ return sections
+}
+
+// ChildSections returns a list of child sections of given section name.
+func (f *File) ChildSections(name string) []*Section {
+ return f.Section(name).ChildSections()
+}
+
+// SectionStrings returns list of section names.
+func (f *File) SectionStrings() []string {
+ list := make([]string, len(f.sectionList))
+ copy(list, f.sectionList)
+ return list
+}
+
+// DeleteSection deletes a section.
+func (f *File) DeleteSection(name string) {
+ if f.BlockMode {
+ f.lock.Lock()
+ defer f.lock.Unlock()
+ }
+
+ if len(name) == 0 {
+ name = DEFAULT_SECTION
+ }
+
+ for i, s := range f.sectionList {
+ if s == name {
+ f.sectionList = append(f.sectionList[:i], f.sectionList[i+1:]...)
+ delete(f.sections, name)
+ return
+ }
+ }
+}
+
+func (f *File) reload(s dataSource) error {
+ r, err := s.ReadCloser()
+ if err != nil {
+ return err
+ }
+ defer r.Close()
+
+ return f.parse(r)
+}
+
+// Reload reloads and parses all data sources.
+func (f *File) Reload() (err error) {
+ for _, s := range f.dataSources {
+ if err = f.reload(s); err != nil {
+ // In loose mode, we create an empty default section for nonexistent files.
+ if os.IsNotExist(err) && f.options.Loose {
+ f.parse(bytes.NewBuffer(nil))
+ continue
+ }
+ return err
+ }
+ }
+ return nil
+}
+
+// Append appends one or more data sources and reloads automatically.
+func (f *File) Append(source interface{}, others ...interface{}) error {
+ ds, err := parseDataSource(source)
+ if err != nil {
+ return err
+ }
+ f.dataSources = append(f.dataSources, ds)
+ for _, s := range others {
+ ds, err = parseDataSource(s)
+ if err != nil {
+ return err
+ }
+ f.dataSources = append(f.dataSources, ds)
+ }
+ return f.Reload()
+}
+
+func (f *File) writeToBuffer(indent string) (*bytes.Buffer, error) {
+ equalSign := "="
+ if PrettyFormat {
+ equalSign = " = "
+ }
+
+ // Use buffer to make sure target is safe until finish encoding.
+ buf := bytes.NewBuffer(nil)
+ for i, sname := range f.sectionList {
+ sec := f.Section(sname)
+ if len(sec.Comment) > 0 {
+ if sec.Comment[0] != '#' && sec.Comment[0] != ';' {
+ sec.Comment = "; " + sec.Comment
+ } else {
+ sec.Comment = sec.Comment[:1] + " " + strings.TrimSpace(sec.Comment[1:])
+ }
+ if _, err := buf.WriteString(sec.Comment + LineBreak); err != nil {
+ return nil, err
+ }
+ }
+
+ if i > 0 || DefaultHeader {
+ if _, err := buf.WriteString("[" + sname + "]" + LineBreak); err != nil {
+ return nil, err
+ }
+ } else {
+ // Write nothing if default section is empty
+ if len(sec.keyList) == 0 {
+ continue
+ }
+ }
+
+ if sec.isRawSection {
+ if _, err := buf.WriteString(sec.rawBody); err != nil {
+ return nil, err
+ }
+
+ if PrettySection {
+ // Put a line between sections
+ if _, err := buf.WriteString(LineBreak); err != nil {
+ return nil, err
+ }
+ }
+ continue
+ }
+
+ // Count and generate alignment length and buffer spaces using the
+ // longest key. Keys may be modifed if they contain certain characters so
+ // we need to take that into account in our calculation.
+ alignLength := 0
+ if PrettyFormat {
+ for _, kname := range sec.keyList {
+ keyLength := len(kname)
+ // First case will surround key by ` and second by """
+ if strings.ContainsAny(kname, "\"=:") {
+ keyLength += 2
+ } else if strings.Contains(kname, "`") {
+ keyLength += 6
+ }
+
+ if keyLength > alignLength {
+ alignLength = keyLength
+ }
+ }
+ }
+ alignSpaces := bytes.Repeat([]byte(" "), alignLength)
+
+ KEY_LIST:
+ for _, kname := range sec.keyList {
+ key := sec.Key(kname)
+ if len(key.Comment) > 0 {
+ if len(indent) > 0 && sname != DEFAULT_SECTION {
+ buf.WriteString(indent)
+ }
+ if key.Comment[0] != '#' && key.Comment[0] != ';' {
+ key.Comment = "; " + key.Comment
+ } else {
+ key.Comment = key.Comment[:1] + " " + strings.TrimSpace(key.Comment[1:])
+ }
+ if _, err := buf.WriteString(key.Comment + LineBreak); err != nil {
+ return nil, err
+ }
+ }
+
+ if len(indent) > 0 && sname != DEFAULT_SECTION {
+ buf.WriteString(indent)
+ }
+
+ switch {
+ case key.isAutoIncrement:
+ kname = "-"
+ case strings.ContainsAny(kname, "\"=:"):
+ kname = "`" + kname + "`"
+ case strings.Contains(kname, "`"):
+ kname = `"""` + kname + `"""`
+ }
+
+ for _, val := range key.ValueWithShadows() {
+ if _, err := buf.WriteString(kname); err != nil {
+ return nil, err
+ }
+
+ if key.isBooleanType {
+ if kname != sec.keyList[len(sec.keyList)-1] {
+ buf.WriteString(LineBreak)
+ }
+ continue KEY_LIST
+ }
+
+ // Write out alignment spaces before "=" sign
+ if PrettyFormat {
+ buf.Write(alignSpaces[:alignLength-len(kname)])
+ }
+
+ // In case key value contains "\n", "`", "\"", "#" or ";"
+ if strings.ContainsAny(val, "\n`") {
+ val = `"""` + val + `"""`
+ } else if !f.options.IgnoreInlineComment && strings.ContainsAny(val, "#;") {
+ val = "`" + val + "`"
+ }
+ if _, err := buf.WriteString(equalSign + val + LineBreak); err != nil {
+ return nil, err
+ }
+ }
+ }
+
+ if PrettySection {
+ // Put a line between sections
+ if _, err := buf.WriteString(LineBreak); err != nil {
+ return nil, err
+ }
+ }
+ }
+
+ return buf, nil
+}
+
+// WriteToIndent writes content into io.Writer with given indention.
+// If PrettyFormat has been set to be true,
+// it will align "=" sign with spaces under each section.
+func (f *File) WriteToIndent(w io.Writer, indent string) (int64, error) {
+ buf, err := f.writeToBuffer(indent)
+ if err != nil {
+ return 0, err
+ }
+ return buf.WriteTo(w)
+}
+
+// WriteTo writes file content into io.Writer.
+func (f *File) WriteTo(w io.Writer) (int64, error) {
+ return f.WriteToIndent(w, "")
+}
+
+// SaveToIndent writes content to file system with given value indention.
+func (f *File) SaveToIndent(filename, indent string) error {
+ // Note: Because we are truncating with os.Create,
+ // so it's safer to save to a temporary file location and rename afte done.
+ buf, err := f.writeToBuffer(indent)
+ if err != nil {
+ return err
+ }
+
+ return ioutil.WriteFile(filename, buf.Bytes(), 0666)
+}
+
+// SaveTo writes content to file system.
+func (f *File) SaveTo(filename string) error {
+ return f.SaveToIndent(filename, "")
+}
diff --git a/vendor/github.com/go-ini/ini/file_test.go b/vendor/github.com/go-ini/ini/file_test.go
new file mode 100644
index 000000000..11612eb9a
--- /dev/null
+++ b/vendor/github.com/go-ini/ini/file_test.go
@@ -0,0 +1,355 @@
+// Copyright 2017 Unknwon
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+package ini_test
+
+import (
+ "bytes"
+ "testing"
+
+ . "github.com/smartystreets/goconvey/convey"
+ "gopkg.in/ini.v1"
+)
+
+func TestEmpty(t *testing.T) {
+ Convey("Create an empty object", t, func() {
+ f := ini.Empty()
+ So(f, ShouldNotBeNil)
+
+ // Should only have the default section
+ So(len(f.Sections()), ShouldEqual, 1)
+
+ // Default section should not contain any key
+ So(len(f.Section("").Keys()), ShouldBeZeroValue)
+ })
+}
+
+func TestFile_NewSection(t *testing.T) {
+ Convey("Create a new section", t, func() {
+ f := ini.Empty()
+ So(f, ShouldNotBeNil)
+
+ sec, err := f.NewSection("author")
+ So(err, ShouldBeNil)
+ So(sec, ShouldNotBeNil)
+ So(sec.Name(), ShouldEqual, "author")
+
+ So(f.SectionStrings(), ShouldResemble, []string{ini.DEFAULT_SECTION, "author"})
+
+ Convey("With duplicated name", func() {
+ sec, err := f.NewSection("author")
+ So(err, ShouldBeNil)
+ So(sec, ShouldNotBeNil)
+
+ // Does nothing if section already exists
+ So(f.SectionStrings(), ShouldResemble, []string{ini.DEFAULT_SECTION, "author"})
+ })
+
+ Convey("With empty string", func() {
+ _, err := f.NewSection("")
+ So(err, ShouldNotBeNil)
+ })
+ })
+}
+
+func TestFile_NewRawSection(t *testing.T) {
+ Convey("Create a new raw section", t, func() {
+ f := ini.Empty()
+ So(f, ShouldNotBeNil)
+
+ sec, err := f.NewRawSection("comments", `1111111111111111111000000000000000001110000
+111111111111111111100000000000111000000000`)
+ So(err, ShouldBeNil)
+ So(sec, ShouldNotBeNil)
+ So(sec.Name(), ShouldEqual, "comments")
+
+ So(f.SectionStrings(), ShouldResemble, []string{ini.DEFAULT_SECTION, "comments"})
+ So(f.Section("comments").Body(), ShouldEqual, `1111111111111111111000000000000000001110000
+111111111111111111100000000000111000000000`)
+
+ Convey("With duplicated name", func() {
+ sec, err := f.NewRawSection("comments", `1111111111111111111000000000000000001110000`)
+ So(err, ShouldBeNil)
+ So(sec, ShouldNotBeNil)
+ So(f.SectionStrings(), ShouldResemble, []string{ini.DEFAULT_SECTION, "comments"})
+
+ // Overwrite previous existed section
+ So(f.Section("comments").Body(), ShouldEqual, `1111111111111111111000000000000000001110000`)
+ })
+
+ Convey("With empty string", func() {
+ _, err := f.NewRawSection("", "")
+ So(err, ShouldNotBeNil)
+ })
+ })
+}
+
+func TestFile_NewSections(t *testing.T) {
+ Convey("Create new sections", t, func() {
+ f := ini.Empty()
+ So(f, ShouldNotBeNil)
+
+ So(f.NewSections("package", "author"), ShouldBeNil)
+ So(f.SectionStrings(), ShouldResemble, []string{ini.DEFAULT_SECTION, "package", "author"})
+
+ Convey("With duplicated name", func() {
+ So(f.NewSections("author", "features"), ShouldBeNil)
+
+ // Ignore section already exists
+ So(f.SectionStrings(), ShouldResemble, []string{ini.DEFAULT_SECTION, "package", "author", "features"})
+ })
+
+ Convey("With empty string", func() {
+ So(f.NewSections("", ""), ShouldNotBeNil)
+ })
+ })
+}
+
+func TestFile_GetSection(t *testing.T) {
+ Convey("Get a section", t, func() {
+ f, err := ini.Load(_FULL_CONF)
+ So(err, ShouldBeNil)
+ So(f, ShouldNotBeNil)
+
+ sec, err := f.GetSection("author")
+ So(err, ShouldBeNil)
+ So(sec, ShouldNotBeNil)
+ So(sec.Name(), ShouldEqual, "author")
+
+ Convey("Section not exists", func() {
+ _, err := f.GetSection("404")
+ So(err, ShouldNotBeNil)
+ })
+ })
+}
+
+func TestFile_Section(t *testing.T) {
+ Convey("Get a section", t, func() {
+ f, err := ini.Load(_FULL_CONF)
+ So(err, ShouldBeNil)
+ So(f, ShouldNotBeNil)
+
+ sec := f.Section("author")
+ So(sec, ShouldNotBeNil)
+ So(sec.Name(), ShouldEqual, "author")
+
+ Convey("Section not exists", func() {
+ sec := f.Section("404")
+ So(sec, ShouldNotBeNil)
+ So(sec.Name(), ShouldEqual, "404")
+ })
+ })
+
+ Convey("Get default section in lower case with insensitive load", t, func() {
+ f, err := ini.InsensitiveLoad([]byte(`
+[default]
+NAME = ini
+VERSION = v1`))
+ So(err, ShouldBeNil)
+ So(f, ShouldNotBeNil)
+
+ So(f.Section("").Key("name").String(), ShouldEqual, "ini")
+ So(f.Section("").Key("version").String(), ShouldEqual, "v1")
+ })
+}
+
+func TestFile_Sections(t *testing.T) {
+ Convey("Get all sections", t, func() {
+ f, err := ini.Load(_FULL_CONF)
+ So(err, ShouldBeNil)
+ So(f, ShouldNotBeNil)
+
+ secs := f.Sections()
+ names := []string{ini.DEFAULT_SECTION, "author", "package", "package.sub", "features", "types", "array", "note", "comments", "string escapes", "advance"}
+ So(len(secs), ShouldEqual, len(names))
+ for i, name := range names {
+ So(secs[i].Name(), ShouldEqual, name)
+ }
+ })
+}
+
+func TestFile_ChildSections(t *testing.T) {
+ Convey("Get child sections by parent name", t, func() {
+ f, err := ini.Load([]byte(`
+[node]
+[node.biz1]
+[node.biz2]
+[node.biz3]
+[node.bizN]
+`))
+ So(err, ShouldBeNil)
+ So(f, ShouldNotBeNil)
+
+ children := f.ChildSections("node")
+ names := []string{"node.biz1", "node.biz2", "node.biz3", "node.bizN"}
+ So(len(children), ShouldEqual, len(names))
+ for i, name := range names {
+ So(children[i].Name(), ShouldEqual, name)
+ }
+ })
+}
+
+func TestFile_SectionStrings(t *testing.T) {
+ Convey("Get all section names", t, func() {
+ f, err := ini.Load(_FULL_CONF)
+ So(err, ShouldBeNil)
+ So(f, ShouldNotBeNil)
+
+ So(f.SectionStrings(), ShouldResemble, []string{ini.DEFAULT_SECTION, "author", "package", "package.sub", "features", "types", "array", "note", "comments", "string escapes", "advance"})
+ })
+}
+
+func TestFile_DeleteSection(t *testing.T) {
+ Convey("Delete a section", t, func() {
+ f := ini.Empty()
+ So(f, ShouldNotBeNil)
+
+ f.NewSections("author", "package", "features")
+ f.DeleteSection("features")
+ f.DeleteSection("")
+ So(f.SectionStrings(), ShouldResemble, []string{"author", "package"})
+ })
+}
+
+func TestFile_Append(t *testing.T) {
+ Convey("Append a data source", t, func() {
+ f := ini.Empty()
+ So(f, ShouldNotBeNil)
+
+ So(f.Append(_MINIMAL_CONF, []byte(`
+[author]
+NAME = Unknwon`)), ShouldBeNil)
+
+ Convey("With bad input", func() {
+ So(f.Append(123), ShouldNotBeNil)
+ So(f.Append(_MINIMAL_CONF, 123), ShouldNotBeNil)
+ })
+ })
+}
+
+func TestFile_WriteTo(t *testing.T) {
+ Convey("Write content to somewhere", t, func() {
+ f, err := ini.Load(_FULL_CONF)
+ So(err, ShouldBeNil)
+ So(f, ShouldNotBeNil)
+
+ f.Section("author").Comment = `Information about package author
+# Bio can be written in multiple lines.`
+ f.Section("author").Key("NAME").Comment = "This is author name"
+ f.Section("note").NewBooleanKey("boolean_key")
+ f.Section("note").NewKey("more", "notes")
+
+ var buf bytes.Buffer
+ _, err = f.WriteTo(&buf)
+ So(err, ShouldBeNil)
+ So(buf.String(), ShouldEqual, `; Package name
+NAME = ini
+; Package version
+VERSION = v1
+; Package import path
+IMPORT_PATH = gopkg.in/%(NAME)s.%(VERSION)s
+
+; Information about package author
+# Bio can be written in multiple lines.
+[author]
+; This is author name
+NAME = Unknwon
+E-MAIL = u@gogs.io
+GITHUB = https://github.com/%(NAME)s
+# Succeeding comment
+BIO = """Gopher.
+Coding addict.
+Good man.
+"""
+
+[package]
+CLONE_URL = https://%(IMPORT_PATH)s
+
+[package.sub]
+UNUSED_KEY = should be deleted
+
+[features]
+- = Support read/write comments of keys and sections
+- = Support auto-increment of key names
+- = Support load multiple files to overwrite key values
+
+[types]
+STRING = str
+BOOL = true
+BOOL_FALSE = false
+FLOAT64 = 1.25
+INT = 10
+TIME = 2015-01-01T20:17:05Z
+DURATION = 2h45m
+UINT = 3
+
+[array]
+STRINGS = en, zh, de
+FLOAT64S = 1.1, 2.2, 3.3
+INTS = 1, 2, 3
+UINTS = 1, 2, 3
+TIMES = 2015-01-01T20:17:05Z,2015-01-01T20:17:05Z,2015-01-01T20:17:05Z
+
+[note]
+empty_lines = next line is empty
+boolean_key
+more = notes
+
+; Comment before the section
+; This is a comment for the section too
+[comments]
+; Comment before key
+key = value
+; This is a comment for key2
+key2 = value2
+key3 = "one", "two", "three"
+
+[string escapes]
+key1 = value1, value2, value3
+key2 = value1\, value2
+key3 = val\ue1, value2
+key4 = value1\\, value\\\\2
+key5 = value1\,, value2
+key6 = aaa bbb\ and\ space ccc
+
+[advance]
+value with quotes = some value
+value quote2 again = some value
+includes comment sign = `+"`"+"my#password"+"`"+`
+includes comment sign2 = `+"`"+"my;password"+"`"+`
+true = 2+3=5
+`+"`"+`1+1=2`+"`"+` = true
+`+"`"+`6+1=7`+"`"+` = true
+"""`+"`"+`5+5`+"`"+`""" = 10
+`+"`"+`"6+6"`+"`"+` = 12
+`+"`"+`7-2=4`+"`"+` = false
+ADDRESS = """404 road,
+NotFound, State, 50000"""
+two_lines = how about continuation lines?
+lots_of_lines = 1 2 3 4
+
+`)
+ })
+}
+
+func TestFile_SaveTo(t *testing.T) {
+ Convey("Write content to somewhere", t, func() {
+ f, err := ini.Load(_FULL_CONF)
+ So(err, ShouldBeNil)
+ So(f, ShouldNotBeNil)
+
+ So(f.SaveTo("testdata/conf_out.ini"), ShouldBeNil)
+ So(f.SaveToIndent("testdata/conf_out.ini", "\t"), ShouldBeNil)
+ })
+}
diff --git a/vendor/github.com/go-ini/ini/ini.go b/vendor/github.com/go-ini/ini/ini.go
index 7f3c4d1ed..508d60c19 100644
--- a/vendor/github.com/go-ini/ini/ini.go
+++ b/vendor/github.com/go-ini/ini/ini.go
@@ -17,15 +17,12 @@ package ini
import (
"bytes"
- "errors"
"fmt"
"io"
"io/ioutil"
"os"
"regexp"
"runtime"
- "strings"
- "sync"
)
const (
@@ -35,7 +32,7 @@ const (
// Maximum allowed depth when recursively substituing variable names.
_DEPTH_VALUES = 99
- _VERSION = "1.28.2"
+ _VERSION = "1.30.3"
)
// Version returns current package version literal.
@@ -92,18 +89,6 @@ func (s sourceFile) ReadCloser() (_ io.ReadCloser, err error) {
return os.Open(s.name)
}
-type bytesReadCloser struct {
- reader io.Reader
-}
-
-func (rc *bytesReadCloser) Read(p []byte) (n int, err error) {
- return rc.reader.Read(p)
-}
-
-func (rc *bytesReadCloser) Close() error {
- return nil
-}
-
// sourceData represents an object that contains content in memory.
type sourceData struct {
data []byte
@@ -122,38 +107,6 @@ func (s *sourceReadCloser) ReadCloser() (io.ReadCloser, error) {
return s.reader, nil
}
-// File represents a combination of a or more INI file(s) in memory.
-type File struct {
- // Should make things safe, but sometimes doesn't matter.
- BlockMode bool
- // Make sure data is safe in multiple goroutines.
- lock sync.RWMutex
-
- // Allow combination of multiple data sources.
- dataSources []dataSource
- // Actual data is stored here.
- sections map[string]*Section
-
- // To keep data in order.
- sectionList []string
-
- options LoadOptions
-
- NameMapper
- ValueMapper
-}
-
-// newFile initializes File object with given data sources.
-func newFile(dataSources []dataSource, opts LoadOptions) *File {
- return &File{
- BlockMode: true,
- dataSources: dataSources,
- sections: make(map[string]*Section),
- sectionList: make([]string, 0, 10),
- options: opts,
- }
-}
-
func parseDataSource(source interface{}) (dataSource, error) {
switch s := source.(type) {
case string:
@@ -181,6 +134,8 @@ type LoadOptions struct {
AllowBooleanKeys bool
// AllowShadows indicates whether to keep track of keys with same name under same section.
AllowShadows bool
+ // UnescapeValueDoubleQuotes indicates whether to unescape double quotes inside value to regular format when value is surrounded by double quotes, e.g. key="a \"value\"" => key=a "value"
+ UnescapeValueDoubleQuotes bool
// Some INI formats allow group blocks that store a block of raw content that doesn't otherwise
// conform to key/value pairs. Specify the names of those blocks here.
UnparseableSections []string
@@ -229,328 +184,3 @@ func InsensitiveLoad(source interface{}, others ...interface{}) (*File, error) {
func ShadowLoad(source interface{}, others ...interface{}) (*File, error) {
return LoadSources(LoadOptions{AllowShadows: true}, source, others...)
}
-
-// Empty returns an empty file object.
-func Empty() *File {
- // Ignore error here, we sure our data is good.
- f, _ := Load([]byte(""))
- return f
-}
-
-// NewSection creates a new section.
-func (f *File) NewSection(name string) (*Section, error) {
- if len(name) == 0 {
- return nil, errors.New("error creating new section: empty section name")
- } else if f.options.Insensitive && name != DEFAULT_SECTION {
- name = strings.ToLower(name)
- }
-
- if f.BlockMode {
- f.lock.Lock()
- defer f.lock.Unlock()
- }
-
- if inSlice(name, f.sectionList) {
- return f.sections[name], nil
- }
-
- f.sectionList = append(f.sectionList, name)
- f.sections[name] = newSection(f, name)
- return f.sections[name], nil
-}
-
-// NewRawSection creates a new section with an unparseable body.
-func (f *File) NewRawSection(name, body string) (*Section, error) {
- section, err := f.NewSection(name)
- if err != nil {
- return nil, err
- }
-
- section.isRawSection = true
- section.rawBody = body
- return section, nil
-}
-
-// NewSections creates a list of sections.
-func (f *File) NewSections(names ...string) (err error) {
- for _, name := range names {
- if _, err = f.NewSection(name); err != nil {
- return err
- }
- }
- return nil
-}
-
-// GetSection returns section by given name.
-func (f *File) GetSection(name string) (*Section, error) {
- if len(name) == 0 {
- name = DEFAULT_SECTION
- } else if f.options.Insensitive {
- name = strings.ToLower(name)
- }
-
- if f.BlockMode {
- f.lock.RLock()
- defer f.lock.RUnlock()
- }
-
- sec := f.sections[name]
- if sec == nil {
- return nil, fmt.Errorf("section '%s' does not exist", name)
- }
- return sec, nil
-}
-
-// Section assumes named section exists and returns a zero-value when not.
-func (f *File) Section(name string) *Section {
- sec, err := f.GetSection(name)
- if err != nil {
- // Note: It's OK here because the only possible error is empty section name,
- // but if it's empty, this piece of code won't be executed.
- sec, _ = f.NewSection(name)
- return sec
- }
- return sec
-}
-
-// Section returns list of Section.
-func (f *File) Sections() []*Section {
- sections := make([]*Section, len(f.sectionList))
- for i := range f.sectionList {
- sections[i] = f.Section(f.sectionList[i])
- }
- return sections
-}
-
-// ChildSections returns a list of child sections of given section name.
-func (f *File) ChildSections(name string) []*Section {
- return f.Section(name).ChildSections()
-}
-
-// SectionStrings returns list of section names.
-func (f *File) SectionStrings() []string {
- list := make([]string, len(f.sectionList))
- copy(list, f.sectionList)
- return list
-}
-
-// DeleteSection deletes a section.
-func (f *File) DeleteSection(name string) {
- if f.BlockMode {
- f.lock.Lock()
- defer f.lock.Unlock()
- }
-
- if len(name) == 0 {
- name = DEFAULT_SECTION
- }
-
- for i, s := range f.sectionList {
- if s == name {
- f.sectionList = append(f.sectionList[:i], f.sectionList[i+1:]...)
- delete(f.sections, name)
- return
- }
- }
-}
-
-func (f *File) reload(s dataSource) error {
- r, err := s.ReadCloser()
- if err != nil {
- return err
- }
- defer r.Close()
-
- return f.parse(r)
-}
-
-// Reload reloads and parses all data sources.
-func (f *File) Reload() (err error) {
- for _, s := range f.dataSources {
- if err = f.reload(s); err != nil {
- // In loose mode, we create an empty default section for nonexistent files.
- if os.IsNotExist(err) && f.options.Loose {
- f.parse(bytes.NewBuffer(nil))
- continue
- }
- return err
- }
- }
- return nil
-}
-
-// Append appends one or more data sources and reloads automatically.
-func (f *File) Append(source interface{}, others ...interface{}) error {
- ds, err := parseDataSource(source)
- if err != nil {
- return err
- }
- f.dataSources = append(f.dataSources, ds)
- for _, s := range others {
- ds, err = parseDataSource(s)
- if err != nil {
- return err
- }
- f.dataSources = append(f.dataSources, ds)
- }
- return f.Reload()
-}
-
-func (f *File) writeToBuffer(indent string) (*bytes.Buffer, error) {
- equalSign := "="
- if PrettyFormat {
- equalSign = " = "
- }
-
- // Use buffer to make sure target is safe until finish encoding.
- buf := bytes.NewBuffer(nil)
- for i, sname := range f.sectionList {
- sec := f.Section(sname)
- if len(sec.Comment) > 0 {
- if sec.Comment[0] != '#' && sec.Comment[0] != ';' {
- sec.Comment = "; " + sec.Comment
- }
- if _, err := buf.WriteString(sec.Comment + LineBreak); err != nil {
- return nil, err
- }
- }
-
- if i > 0 || DefaultHeader {
- if _, err := buf.WriteString("[" + sname + "]" + LineBreak); err != nil {
- return nil, err
- }
- } else {
- // Write nothing if default section is empty
- if len(sec.keyList) == 0 {
- continue
- }
- }
-
- if sec.isRawSection {
- if _, err := buf.WriteString(sec.rawBody); err != nil {
- return nil, err
- }
- continue
- }
-
- // Count and generate alignment length and buffer spaces using the
- // longest key. Keys may be modifed if they contain certain characters so
- // we need to take that into account in our calculation.
- alignLength := 0
- if PrettyFormat {
- for _, kname := range sec.keyList {
- keyLength := len(kname)
- // First case will surround key by ` and second by """
- if strings.ContainsAny(kname, "\"=:") {
- keyLength += 2
- } else if strings.Contains(kname, "`") {
- keyLength += 6
- }
-
- if keyLength > alignLength {
- alignLength = keyLength
- }
- }
- }
- alignSpaces := bytes.Repeat([]byte(" "), alignLength)
-
- KEY_LIST:
- for _, kname := range sec.keyList {
- key := sec.Key(kname)
- if len(key.Comment) > 0 {
- if len(indent) > 0 && sname != DEFAULT_SECTION {
- buf.WriteString(indent)
- }
- if key.Comment[0] != '#' && key.Comment[0] != ';' {
- key.Comment = "; " + key.Comment
- }
- if _, err := buf.WriteString(key.Comment + LineBreak); err != nil {
- return nil, err
- }
- }
-
- if len(indent) > 0 && sname != DEFAULT_SECTION {
- buf.WriteString(indent)
- }
-
- switch {
- case key.isAutoIncrement:
- kname = "-"
- case strings.ContainsAny(kname, "\"=:"):
- kname = "`" + kname + "`"
- case strings.Contains(kname, "`"):
- kname = `"""` + kname + `"""`
- }
-
- for _, val := range key.ValueWithShadows() {
- if _, err := buf.WriteString(kname); err != nil {
- return nil, err
- }
-
- if key.isBooleanType {
- if kname != sec.keyList[len(sec.keyList)-1] {
- buf.WriteString(LineBreak)
- }
- continue KEY_LIST
- }
-
- // Write out alignment spaces before "=" sign
- if PrettyFormat {
- buf.Write(alignSpaces[:alignLength-len(kname)])
- }
-
- // In case key value contains "\n", "`", "\"", "#" or ";"
- if strings.ContainsAny(val, "\n`") {
- val = `"""` + val + `"""`
- } else if !f.options.IgnoreInlineComment && strings.ContainsAny(val, "#;") {
- val = "`" + val + "`"
- }
- if _, err := buf.WriteString(equalSign + val + LineBreak); err != nil {
- return nil, err
- }
- }
- }
-
- if PrettySection {
- // Put a line between sections
- if _, err := buf.WriteString(LineBreak); err != nil {
- return nil, err
- }
- }
- }
-
- return buf, nil
-}
-
-// WriteToIndent writes content into io.Writer with given indention.
-// If PrettyFormat has been set to be true,
-// it will align "=" sign with spaces under each section.
-func (f *File) WriteToIndent(w io.Writer, indent string) (int64, error) {
- buf, err := f.writeToBuffer(indent)
- if err != nil {
- return 0, err
- }
- return buf.WriteTo(w)
-}
-
-// WriteTo writes file content into io.Writer.
-func (f *File) WriteTo(w io.Writer) (int64, error) {
- return f.WriteToIndent(w, "")
-}
-
-// SaveToIndent writes content to file system with given value indention.
-func (f *File) SaveToIndent(filename, indent string) error {
- // Note: Because we are truncating with os.Create,
- // so it's safer to save to a temporary file location and rename afte done.
- buf, err := f.writeToBuffer(indent)
- if err != nil {
- return err
- }
-
- return ioutil.WriteFile(filename, buf.Bytes(), 0666)
-}
-
-// SaveTo writes content to file system.
-func (f *File) SaveTo(filename string) error {
- return f.SaveToIndent(filename, "")
-}
diff --git a/vendor/github.com/go-ini/ini/ini_internal_test.go b/vendor/github.com/go-ini/ini/ini_internal_test.go
new file mode 100644
index 000000000..257ef1ebb
--- /dev/null
+++ b/vendor/github.com/go-ini/ini/ini_internal_test.go
@@ -0,0 +1,35 @@
+// Copyright 2017 Unknwon
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+package ini
+
+import (
+ "testing"
+
+ . "github.com/smartystreets/goconvey/convey"
+)
+
+func Test_Version(t *testing.T) {
+ Convey("Get version", t, func() {
+ So(Version(), ShouldEqual, _VERSION)
+ })
+}
+
+func Test_isSlice(t *testing.T) {
+ Convey("Check if a string is in the slice", t, func() {
+ ss := []string{"a", "b", "c"}
+ So(inSlice("a", ss), ShouldBeTrue)
+ So(inSlice("d", ss), ShouldBeFalse)
+ })
+}
diff --git a/vendor/github.com/go-ini/ini/ini_test.go b/vendor/github.com/go-ini/ini/ini_test.go
index b3dd217c6..7a1efe4ec 100644
--- a/vendor/github.com/go-ini/ini/ini_test.go
+++ b/vendor/github.com/go-ini/ini/ini_test.go
@@ -12,480 +12,312 @@
// License for the specific language governing permissions and limitations
// under the License.
-package ini
+package ini_test
import (
"bytes"
"io/ioutil"
- "strings"
"testing"
- "time"
. "github.com/smartystreets/goconvey/convey"
+ "gopkg.in/ini.v1"
)
-func Test_Version(t *testing.T) {
- Convey("Get version", t, func() {
- So(Version(), ShouldEqual, _VERSION)
- })
-}
-
-const _CONF_DATA = `
-; Package name
-NAME = ini
-; Package version
-VERSION = v1
-; Package import path
-IMPORT_PATH = gopkg.in/%(NAME)s.%(VERSION)s
+const (
+ _CONF_DATA = `
+ ; Package name
+ NAME = ini
+ ; Package version
+ VERSION = v1
+ ; Package import path
+ IMPORT_PATH = gopkg.in/%(NAME)s.%(VERSION)s
+
+ # Information about package author
+ # Bio can be written in multiple lines.
+ [author]
+ NAME = Unknwon ; Succeeding comment
+ E-MAIL = fake@localhost
+ GITHUB = https://github.com/%(NAME)s
+ BIO = """Gopher.
+ Coding addict.
+ Good man.
+ """ # Succeeding comment`
+ _MINIMAL_CONF = "testdata/minimal.ini"
+ _FULL_CONF = "testdata/full.ini"
+ _NOT_FOUND_CONF = "testdata/404.ini"
+)
-# Information about package author
-# Bio can be written in multiple lines.
+func TestLoad(t *testing.T) {
+ Convey("Load from good data sources", t, func() {
+ f, err := ini.Load([]byte(`
+NAME = ini
+VERSION = v1
+IMPORT_PATH = gopkg.in/%(NAME)s.%(VERSION)s`),
+ "testdata/minimal.ini",
+ ioutil.NopCloser(bytes.NewReader([]byte(`
[author]
-NAME = Unknwon ; Succeeding comment
-E-MAIL = fake@localhost
-GITHUB = https://github.com/%(NAME)s
-BIO = """Gopher.
-Coding addict.
-Good man.
-""" # Succeeding comment
-
-[package]
-CLONE_URL = https://%(IMPORT_PATH)s
-
-[package.sub]
-UNUSED_KEY = should be deleted
-
-[features]
--: Support read/write comments of keys and sections
--: Support auto-increment of key names
--: Support load multiple files to overwrite key values
-
-[types]
-STRING = str
-BOOL = true
-BOOL_FALSE = false
-FLOAT64 = 1.25
-INT = 10
-TIME = 2015-01-01T20:17:05Z
-DURATION = 2h45m
-UINT = 3
-
-[array]
-STRINGS = en, zh, de
-FLOAT64S = 1.1, 2.2, 3.3
-INTS = 1, 2, 3
-UINTS = 1, 2, 3
-TIMES = 2015-01-01T20:17:05Z,2015-01-01T20:17:05Z,2015-01-01T20:17:05Z
-
-[note]
-empty_lines = next line is empty\
-
-; Comment before the section
-[comments] ; This is a comment for the section too
-; Comment before key
-key = "value"
-key2 = "value2" ; This is a comment for key2
-key3 = "one", "two", "three"
-
-[advance]
-value with quotes = "some value"
-value quote2 again = 'some value'
-includes comment sign = ` + "`" + "my#password" + "`" + `
-includes comment sign2 = ` + "`" + "my;password" + "`" + `
-true = 2+3=5
-"1+1=2" = true
-"""6+1=7""" = true
-"""` + "`" + `5+5` + "`" + `""" = 10
-` + "`" + `"6+6"` + "`" + ` = 12
-` + "`" + `7-2=4` + "`" + ` = false
-ADDRESS = ` + "`" + `404 road,
-NotFound, State, 50000` + "`" + `
-
-two_lines = how about \
- continuation lines?
-lots_of_lines = 1 \
- 2 \
- 3 \
- 4 \
-`
-
-func Test_Load(t *testing.T) {
- Convey("Load from data sources", t, func() {
-
- Convey("Load with empty data", func() {
- So(Empty(), ShouldNotBeNil)
- })
-
- Convey("Load with multiple data sources", func() {
- cfg, err := Load([]byte(_CONF_DATA), "testdata/conf.ini", ioutil.NopCloser(bytes.NewReader([]byte(_CONF_DATA))))
- So(err, ShouldBeNil)
- So(cfg, ShouldNotBeNil)
-
- f, err := Load([]byte(_CONF_DATA), "testdata/404.ini")
- So(err, ShouldNotBeNil)
- So(f, ShouldBeNil)
- })
+NAME = Unknwon
+`))),
+ )
+ So(err, ShouldBeNil)
+ So(f, ShouldNotBeNil)
- Convey("Load with io.ReadCloser", func() {
- cfg, err := Load(ioutil.NopCloser(bytes.NewReader([]byte(_CONF_DATA))))
- So(err, ShouldBeNil)
- So(cfg, ShouldNotBeNil)
+ // Vaildate values make sure all sources are loaded correctly
+ sec := f.Section("")
+ So(sec.Key("NAME").String(), ShouldEqual, "ini")
+ So(sec.Key("VERSION").String(), ShouldEqual, "v1")
+ So(sec.Key("IMPORT_PATH").String(), ShouldEqual, "gopkg.in/ini.v1")
- So(cfg.Section("").Key("NAME").String(), ShouldEqual, "ini")
- })
+ sec = f.Section("author")
+ So(sec.Key("NAME").String(), ShouldEqual, "Unknwon")
+ So(sec.Key("E-MAIL").String(), ShouldEqual, "u@gogs.io")
})
- Convey("Bad load process", t, func() {
-
- Convey("Load from invalid data sources", func() {
- _, err := Load(_CONF_DATA)
- So(err, ShouldNotBeNil)
-
- f, err := Load("testdata/404.ini")
- So(err, ShouldNotBeNil)
- So(f, ShouldBeNil)
-
- _, err = Load(1)
+ Convey("Load from bad data sources", t, func() {
+ Convey("Invalid input", func() {
+ _, err := ini.Load(_NOT_FOUND_CONF)
So(err, ShouldNotBeNil)
+ })
- _, err = Load([]byte(""), 1)
+ Convey("Unsupported type", func() {
+ _, err := ini.Load(123)
So(err, ShouldNotBeNil)
})
+ })
+}
- Convey("Load with bad section name", func() {
- _, err := Load([]byte("[]"))
- So(err, ShouldNotBeNil)
+func TestLoadSources(t *testing.T) {
+ Convey("Load from data sources with options", t, func() {
+ Convey("Ignore nonexistent files", func() {
+ f, err := ini.LooseLoad(_NOT_FOUND_CONF, _MINIMAL_CONF)
+ So(err, ShouldBeNil)
+ So(f, ShouldNotBeNil)
- _, err = Load([]byte("["))
- So(err, ShouldNotBeNil)
+ Convey("Inverse case", func() {
+ _, err = ini.Load(_NOT_FOUND_CONF)
+ So(err, ShouldNotBeNil)
+ })
})
- Convey("Load with bad keys", func() {
- _, err := Load([]byte(`"""name`))
- So(err, ShouldNotBeNil)
+ Convey("Insensitive to section and key names", func() {
+ f, err := ini.InsensitiveLoad(_MINIMAL_CONF)
+ So(err, ShouldBeNil)
+ So(f, ShouldNotBeNil)
- _, err = Load([]byte(`"""name"""`))
- So(err, ShouldNotBeNil)
+ So(f.Section("Author").Key("e-mail").String(), ShouldEqual, "u@gogs.io")
- _, err = Load([]byte(`""=1`))
- So(err, ShouldNotBeNil)
+ Convey("Write out", func() {
+ var buf bytes.Buffer
+ _, err := f.WriteTo(&buf)
+ So(err, ShouldBeNil)
+ So(buf.String(), ShouldEqual, `[author]
+e-mail = u@gogs.io
- _, err = Load([]byte(`=`))
- So(err, ShouldNotBeNil)
+`)
+ })
- _, err = Load([]byte(`name`))
- So(err, ShouldNotBeNil)
- })
+ Convey("Inverse case", func() {
+ f, err := ini.Load(_MINIMAL_CONF)
+ So(err, ShouldBeNil)
+ So(f, ShouldNotBeNil)
- Convey("Load with bad values", func() {
- _, err := Load([]byte(`name="""Unknwon`))
- So(err, ShouldNotBeNil)
+ So(f.Section("Author").Key("e-mail").String(), ShouldBeEmpty)
+ })
})
- })
- Convey("Get section and key insensitively", t, func() {
- cfg, err := InsensitiveLoad([]byte(_CONF_DATA), "testdata/conf.ini")
- So(err, ShouldBeNil)
- So(cfg, ShouldNotBeNil)
+ Convey("Ignore continuation lines", func() {
+ f, err := ini.LoadSources(ini.LoadOptions{
+ IgnoreContinuation: true,
+ }, []byte(`
+key1=a\b\
+key2=c\d\
+key3=value`))
+ So(err, ShouldBeNil)
+ So(f, ShouldNotBeNil)
- sec, err := cfg.GetSection("Author")
- So(err, ShouldBeNil)
- So(sec, ShouldNotBeNil)
+ So(f.Section("").Key("key1").String(), ShouldEqual, `a\b\`)
+ So(f.Section("").Key("key2").String(), ShouldEqual, `c\d\`)
+ So(f.Section("").Key("key3").String(), ShouldEqual, "value")
- key, err := sec.GetKey("E-mail")
- So(err, ShouldBeNil)
- So(key, ShouldNotBeNil)
- })
-
- Convey("Load with ignoring continuation lines", t, func() {
- cfg, err := LoadSources(LoadOptions{IgnoreContinuation: true}, []byte(`key1=a\b\
+ Convey("Inverse case", func() {
+ f, err := ini.Load([]byte(`
+key1=a\b\
key2=c\d\`))
- So(err, ShouldBeNil)
- So(cfg, ShouldNotBeNil)
+ So(err, ShouldBeNil)
+ So(f, ShouldNotBeNil)
- So(cfg.Section("").Key("key1").String(), ShouldEqual, `a\b\`)
- So(cfg.Section("").Key("key2").String(), ShouldEqual, `c\d\`)
- })
-
- Convey("Load with ignoring inline comments", t, func() {
- cfg, err := LoadSources(LoadOptions{IgnoreInlineComment: true}, []byte(`key1=value ;comment
-key2=value #comment2`))
- So(err, ShouldBeNil)
- So(cfg, ShouldNotBeNil)
-
- So(cfg.Section("").Key("key1").String(), ShouldEqual, `value ;comment`)
- So(cfg.Section("").Key("key2").String(), ShouldEqual, `value #comment2`)
-
- var buf bytes.Buffer
- cfg.WriteTo(&buf)
- So(buf.String(), ShouldEqual, `key1 = value ;comment
-key2 = value #comment2
+ So(f.Section("").Key("key1").String(), ShouldEqual, `a\bkey2=c\d`)
+ })
+ })
-`)
- })
+ Convey("Ignore inline comments", func() {
+ f, err := ini.LoadSources(ini.LoadOptions{
+ IgnoreInlineComment: true,
+ }, []byte(`
+key1=value ;comment
+key2=value2 #comment2`))
+ So(err, ShouldBeNil)
+ So(f, ShouldNotBeNil)
+
+ So(f.Section("").Key("key1").String(), ShouldEqual, `value ;comment`)
+ So(f.Section("").Key("key2").String(), ShouldEqual, `value2 #comment2`)
+
+ Convey("Inverse case", func() {
+ f, err := ini.Load([]byte(`
+key1=value ;comment
+key2=value2 #comment2`))
+ So(err, ShouldBeNil)
+ So(f, ShouldNotBeNil)
+
+ So(f.Section("").Key("key1").String(), ShouldEqual, `value`)
+ So(f.Section("").Key("key1").Comment, ShouldEqual, `;comment`)
+ So(f.Section("").Key("key2").String(), ShouldEqual, `value2`)
+ So(f.Section("").Key("key2").Comment, ShouldEqual, `#comment2`)
+ })
+ })
- Convey("Load with boolean type keys", t, func() {
- cfg, err := LoadSources(LoadOptions{AllowBooleanKeys: true}, []byte(`key1=hello
-key2
-#key3
-key4
-key5`))
- So(err, ShouldBeNil)
- So(cfg, ShouldNotBeNil)
-
- So(strings.Join(cfg.Section("").KeyStrings(), ","), ShouldEqual, "key1,key2,key4,key5")
- So(cfg.Section("").Key("key2").MustBool(false), ShouldBeTrue)
-
- var buf bytes.Buffer
- cfg.WriteTo(&buf)
- // there is always a trailing \n at the end of the section
- So(buf.String(), ShouldEqual, `key1 = hello
-key2
-#key3
-key4
-key5
+ Convey("Allow boolean type keys", func() {
+ f, err := ini.LoadSources(ini.LoadOptions{
+ AllowBooleanKeys: true,
+ }, []byte(`
+key1=hello
+#key2
+key3`))
+ So(err, ShouldBeNil)
+ So(f, ShouldNotBeNil)
+
+ So(f.Section("").KeyStrings(), ShouldResemble, []string{"key1", "key3"})
+ So(f.Section("").Key("key3").MustBool(false), ShouldBeTrue)
+
+ Convey("Write out", func() {
+ var buf bytes.Buffer
+ _, err := f.WriteTo(&buf)
+ So(err, ShouldBeNil)
+ So(buf.String(), ShouldEqual, `key1 = hello
+# key2
+key3
`)
- })
-}
-
-func Test_File_ChildSections(t *testing.T) {
- Convey("Find child sections by parent name", t, func() {
- cfg, err := Load([]byte(`
-[node]
-
-[node.biz1]
-
-[node.biz2]
-
-[node.biz3]
-
-[node.bizN]
-`))
- So(err, ShouldBeNil)
- So(cfg, ShouldNotBeNil)
-
- children := cfg.ChildSections("node")
- names := make([]string, len(children))
- for i := range children {
- names[i] = children[i].name
- }
- So(strings.Join(names, ","), ShouldEqual, "node.biz1,node.biz2,node.biz3,node.bizN")
- })
-}
+ })
+
+ Convey("Inverse case", func() {
+ _, err := ini.Load([]byte(`
+key1=hello
+#key2
+key3`))
+ So(err, ShouldNotBeNil)
+ })
+ })
-func Test_LooseLoad(t *testing.T) {
- Convey("Loose load from data sources", t, func() {
- Convey("Loose load mixed with nonexistent file", func() {
- cfg, err := LooseLoad("testdata/404.ini")
+ Convey("Allow shadow keys", func() {
+ f, err := ini.ShadowLoad([]byte(`
+[remote "origin"]
+url = https://github.com/Antergone/test1.git
+url = https://github.com/Antergone/test2.git
+fetch = +refs/heads/*:refs/remotes/origin/*`))
So(err, ShouldBeNil)
- So(cfg, ShouldNotBeNil)
- var fake struct {
- Name string `ini:"name"`
- }
- So(cfg.MapTo(&fake), ShouldBeNil)
+ So(f, ShouldNotBeNil)
+
+ So(f.Section(`remote "origin"`).Key("url").String(), ShouldEqual, "https://github.com/Antergone/test1.git")
+ So(f.Section(`remote "origin"`).Key("url").ValueWithShadows(), ShouldResemble, []string{
+ "https://github.com/Antergone/test1.git",
+ "https://github.com/Antergone/test2.git",
+ })
+ So(f.Section(`remote "origin"`).Key("fetch").String(), ShouldEqual, "+refs/heads/*:refs/remotes/origin/*")
+
+ Convey("Write out", func() {
+ var buf bytes.Buffer
+ _, err := f.WriteTo(&buf)
+ So(err, ShouldBeNil)
+ So(buf.String(), ShouldEqual, `[remote "origin"]
+url = https://github.com/Antergone/test1.git
+url = https://github.com/Antergone/test2.git
+fetch = +refs/heads/*:refs/remotes/origin/*
- cfg, err = LooseLoad([]byte("name=Unknwon"), "testdata/404.ini")
- So(err, ShouldBeNil)
- So(cfg.Section("").Key("name").String(), ShouldEqual, "Unknwon")
- So(cfg.MapTo(&fake), ShouldBeNil)
- So(fake.Name, ShouldEqual, "Unknwon")
+`)
+ })
+
+ Convey("Inverse case", func() {
+ f, err := ini.Load([]byte(`
+[remote "origin"]
+url = https://github.com/Antergone/test1.git
+url = https://github.com/Antergone/test2.git`))
+ So(err, ShouldBeNil)
+ So(f, ShouldNotBeNil)
+
+ So(f.Section(`remote "origin"`).Key("url").String(), ShouldEqual, "https://github.com/Antergone/test2.git")
+ })
})
- })
-}
+ Convey("Unescape double quotes inside value", func() {
+ f, err := ini.LoadSources(ini.LoadOptions{
+ UnescapeValueDoubleQuotes: true,
+ }, []byte(`
+create_repo="创建了仓库 <a href=\"%s\">%s</a>"`))
+ So(err, ShouldBeNil)
+ So(f, ShouldNotBeNil)
-func Test_File_Append(t *testing.T) {
- Convey("Append data sources", t, func() {
- cfg, err := Load([]byte(""))
- So(err, ShouldBeNil)
- So(cfg, ShouldNotBeNil)
+ So(f.Section("").Key("create_repo").String(), ShouldEqual, `创建了仓库 <a href="%s">%s</a>`)
- So(cfg.Append([]byte(""), []byte("")), ShouldBeNil)
+ Convey("Inverse case", func() {
+ f, err := ini.Load([]byte(`
+create_repo="创建了仓库 <a href=\"%s\">%s</a>"`))
+ So(err, ShouldBeNil)
+ So(f, ShouldNotBeNil)
- Convey("Append bad data sources", func() {
- So(cfg.Append(1), ShouldNotBeNil)
- So(cfg.Append([]byte(""), 1), ShouldNotBeNil)
+ So(f.Section("").Key("create_repo").String(), ShouldEqual, `"创建了仓库 <a href=\"%s\">%s</a>"`)
+ })
})
- })
-}
-
-func Test_File_WriteTo(t *testing.T) {
- Convey("Write to somewhere", t, func() {
- var buf bytes.Buffer
- cfg := Empty()
- cfg.WriteTo(&buf)
- })
-}
-
-func Test_File_SaveTo_WriteTo(t *testing.T) {
- Convey("Save file", t, func() {
- cfg, err := Load([]byte(_CONF_DATA), "testdata/conf.ini")
- So(err, ShouldBeNil)
- So(cfg, ShouldNotBeNil)
- cfg.Section("").Key("NAME").Comment = "Package name"
- cfg.Section("author").Comment = `Information about package author
-# Bio can be written in multiple lines.`
- cfg.Section("advanced").Key("val w/ pound").SetValue("my#password")
- cfg.Section("advanced").Key("longest key has a colon : yes/no").SetValue("yes")
- So(cfg.SaveTo("testdata/conf_out.ini"), ShouldBeNil)
+ Convey("Allow unparseable sections", func() {
+ f, err := ini.LoadSources(ini.LoadOptions{
+ Insensitive: true,
+ UnparseableSections: []string{"core_lesson", "comments"},
+ }, []byte(`
+Lesson_Location = 87
+Lesson_Status = C
+Score = 3
+Time = 00:02:30
- cfg.Section("author").Key("NAME").Comment = "This is author name"
+[CORE_LESSON]
+my lesson state data – 1111111111111111111000000000000000001110000
+111111111111111111100000000000111000000000 – end my lesson state data
- So(cfg.SaveToIndent("testdata/conf_out.ini", "\t"), ShouldBeNil)
+[COMMENTS]
+<1><L.Slide#2> This slide has the fuel listed in the wrong units <e.1>`))
+ So(err, ShouldBeNil)
+ So(f, ShouldNotBeNil)
+
+ So(f.Section("").Key("score").String(), ShouldEqual, "3")
+ So(f.Section("").Body(), ShouldBeEmpty)
+ So(f.Section("core_lesson").Body(), ShouldEqual, `my lesson state data – 1111111111111111111000000000000000001110000
+111111111111111111100000000000111000000000 – end my lesson state data`)
+ So(f.Section("comments").Body(), ShouldEqual, `<1><L.Slide#2> This slide has the fuel listed in the wrong units <e.1>`)
+
+ Convey("Write out", func() {
+ var buf bytes.Buffer
+ _, err := f.WriteTo(&buf)
+ So(err, ShouldBeNil)
+ So(buf.String(), ShouldEqual, `lesson_location = 87
+lesson_status = C
+score = 3
+time = 00:02:30
+
+[core_lesson]
+my lesson state data – 1111111111111111111000000000000000001110000
+111111111111111111100000000000111000000000 – end my lesson state data
- var buf bytes.Buffer
- _, err = cfg.WriteToIndent(&buf, "\t")
- So(err, ShouldBeNil)
- So(buf.String(), ShouldEqual, `; Package name
-NAME = ini
-; Package version
-VERSION = v1
-; Package import path
-IMPORT_PATH = gopkg.in/%(NAME)s.%(VERSION)s
-
-; Information about package author
-# Bio can be written in multiple lines.
-[author]
- ; This is author name
- NAME = Unknwon
- E-MAIL = u@gogs.io
- GITHUB = https://github.com/%(NAME)s
- # Succeeding comment
- BIO = """Gopher.
-Coding addict.
-Good man.
-"""
-
-[package]
- CLONE_URL = https://%(IMPORT_PATH)s
-
-[package.sub]
- UNUSED_KEY = should be deleted
-
-[features]
- - = Support read/write comments of keys and sections
- - = Support auto-increment of key names
- - = Support load multiple files to overwrite key values
-
-[types]
- STRING = str
- BOOL = true
- BOOL_FALSE = false
- FLOAT64 = 1.25
- INT = 10
- TIME = 2015-01-01T20:17:05Z
- DURATION = 2h45m
- UINT = 3
-
-[array]
- STRINGS = en, zh, de
- FLOAT64S = 1.1, 2.2, 3.3
- INTS = 1, 2, 3
- UINTS = 1, 2, 3
- TIMES = 2015-01-01T20:17:05Z,2015-01-01T20:17:05Z,2015-01-01T20:17:05Z
-
-[note]
- empty_lines = next line is empty
-
-; Comment before the section
-; This is a comment for the section too
[comments]
- ; Comment before key
- key = value
- ; This is a comment for key2
- key2 = value2
- key3 = "one", "two", "three"
-
-[advance]
- value with quotes = some value
- value quote2 again = some value
- includes comment sign = `+"`"+"my#password"+"`"+`
- includes comment sign2 = `+"`"+"my;password"+"`"+`
- true = 2+3=5
- `+"`"+`1+1=2`+"`"+` = true
- `+"`"+`6+1=7`+"`"+` = true
- """`+"`"+`5+5`+"`"+`""" = 10
- `+"`"+`"6+6"`+"`"+` = 12
- `+"`"+`7-2=4`+"`"+` = false
- ADDRESS = """404 road,
-NotFound, State, 50000"""
- two_lines = how about continuation lines?
- lots_of_lines = 1 2 3 4
-
-[advanced]
- val w/ pound = `+"`"+`my#password`+"`"+`
- `+"`"+`longest key has a colon : yes/no`+"`"+` = yes
-
+<1><L.Slide#2> This slide has the fuel listed in the wrong units <e.1>
`)
- })
-}
-
-func Test_File_WriteTo_SectionRaw(t *testing.T) {
- Convey("Write a INI with a raw section", t, func() {
- var buf bytes.Buffer
- cfg, err := LoadSources(
- LoadOptions{
- UnparseableSections: []string{"CORE_LESSON", "COMMENTS"},
- },
- "testdata/aicc.ini")
- So(err, ShouldBeNil)
- So(cfg, ShouldNotBeNil)
- cfg.WriteToIndent(&buf, "\t")
- So(buf.String(), ShouldEqual, `[Core]
- Lesson_Location = 87
- Lesson_Status = C
- Score = 3
- Time = 00:02:30
+ })
+ Convey("Inverse case", func() {
+ _, err := ini.Load([]byte(`
[CORE_LESSON]
my lesson state data – 1111111111111111111000000000000000001110000
-111111111111111111100000000000111000000000 – end my lesson state data
-[COMMENTS]
-<1><L.Slide#2> This slide has the fuel listed in the wrong units <e.1>
-`)
+111111111111111111100000000000111000000000 – end my lesson state data`))
+ So(err, ShouldNotBeNil)
+ })
+ })
})
}
-
-// Helpers for slice tests.
-func float64sEqual(values []float64, expected ...float64) {
- So(values, ShouldHaveLength, len(expected))
- for i, v := range expected {
- So(values[i], ShouldEqual, v)
- }
-}
-
-func intsEqual(values []int, expected ...int) {
- So(values, ShouldHaveLength, len(expected))
- for i, v := range expected {
- So(values[i], ShouldEqual, v)
- }
-}
-
-func int64sEqual(values []int64, expected ...int64) {
- So(values, ShouldHaveLength, len(expected))
- for i, v := range expected {
- So(values[i], ShouldEqual, v)
- }
-}
-
-func uintsEqual(values []uint, expected ...uint) {
- So(values, ShouldHaveLength, len(expected))
- for i, v := range expected {
- So(values[i], ShouldEqual, v)
- }
-}
-
-func uint64sEqual(values []uint64, expected ...uint64) {
- So(values, ShouldHaveLength, len(expected))
- for i, v := range expected {
- So(values[i], ShouldEqual, v)
- }
-}
-
-func timesEqual(values []time.Time, expected ...time.Time) {
- So(values, ShouldHaveLength, len(expected))
- for i, v := range expected {
- So(values[i].String(), ShouldEqual, v.String())
- }
-}
diff --git a/vendor/github.com/go-ini/ini/key.go b/vendor/github.com/go-ini/ini/key.go
index 838356af0..ab566c2c1 100644
--- a/vendor/github.com/go-ini/ini/key.go
+++ b/vendor/github.com/go-ini/ini/key.go
@@ -15,6 +15,7 @@
package ini
import (
+ "bytes"
"errors"
"fmt"
"strconv"
@@ -25,6 +26,7 @@ import (
// Key represents a key under a section.
type Key struct {
s *Section
+ Comment string
name string
value string
isAutoIncrement bool
@@ -32,8 +34,6 @@ type Key struct {
isShadow bool
shadows []*Key
-
- Comment string
}
// newKey simply return a key object with given values.
@@ -444,11 +444,39 @@ func (k *Key) Strings(delim string) []string {
return []string{}
}
- vals := strings.Split(str, delim)
- for i := range vals {
- // vals[i] = k.transformValue(strings.TrimSpace(vals[i]))
- vals[i] = strings.TrimSpace(vals[i])
+ runes := []rune(str)
+ vals := make([]string, 0, 2)
+ var buf bytes.Buffer
+ escape := false
+ idx := 0
+ for {
+ if escape {
+ escape = false
+ if runes[idx] != '\\' && !strings.HasPrefix(string(runes[idx:]), delim) {
+ buf.WriteRune('\\')
+ }
+ buf.WriteRune(runes[idx])
+ } else {
+ if runes[idx] == '\\' {
+ escape = true
+ } else if strings.HasPrefix(string(runes[idx:]), delim) {
+ idx += len(delim) - 1
+ vals = append(vals, strings.TrimSpace(buf.String()))
+ buf.Reset()
+ } else {
+ buf.WriteRune(runes[idx])
+ }
+ }
+ idx += 1
+ if idx == len(runes) {
+ break
+ }
+ }
+
+ if buf.Len() > 0 {
+ vals = append(vals, strings.TrimSpace(buf.String()))
}
+
return vals
}
diff --git a/vendor/github.com/go-ini/ini/key_test.go b/vendor/github.com/go-ini/ini/key_test.go
index 1281d5bf0..588efd429 100644
--- a/vendor/github.com/go-ini/ini/key_test.go
+++ b/vendor/github.com/go-ini/ini/key_test.go
@@ -12,26 +12,108 @@
// License for the specific language governing permissions and limitations
// under the License.
-package ini
+package ini_test
import (
- "bytes"
"fmt"
"strings"
"testing"
"time"
. "github.com/smartystreets/goconvey/convey"
+ "gopkg.in/ini.v1"
)
-func Test_Key(t *testing.T) {
- Convey("Test getting and setting values", t, func() {
- cfg, err := Load([]byte(_CONF_DATA), "testdata/conf.ini")
+func TestKey_AddShadow(t *testing.T) {
+ Convey("Add shadow to a key", t, func() {
+ f, err := ini.ShadowLoad([]byte(`
+[notes]
+-: note1`))
So(err, ShouldBeNil)
- So(cfg, ShouldNotBeNil)
+ So(f, ShouldNotBeNil)
- Convey("Get values in default section", func() {
- sec := cfg.Section("")
+ k, err := f.Section("").NewKey("NAME", "ini")
+ So(err, ShouldBeNil)
+ So(k, ShouldNotBeNil)
+
+ So(k.AddShadow("ini.v1"), ShouldBeNil)
+ So(k.ValueWithShadows(), ShouldResemble, []string{"ini", "ini.v1"})
+
+ Convey("Add shadow to boolean key", func() {
+ k, err := f.Section("").NewBooleanKey("published")
+ So(err, ShouldBeNil)
+ So(k, ShouldNotBeNil)
+ So(k.AddShadow("beta"), ShouldNotBeNil)
+ })
+
+ Convey("Add shadow to auto-increment key", func() {
+ So(f.Section("notes").Key("#1").AddShadow("beta"), ShouldNotBeNil)
+ })
+ })
+
+ Convey("Shadow is not allowed", t, func() {
+ f := ini.Empty()
+ So(f, ShouldNotBeNil)
+
+ k, err := f.Section("").NewKey("NAME", "ini")
+ So(err, ShouldBeNil)
+ So(k, ShouldNotBeNil)
+
+ So(k.AddShadow("ini.v1"), ShouldNotBeNil)
+ })
+}
+
+// Helpers for slice tests.
+func float64sEqual(values []float64, expected ...float64) {
+ So(values, ShouldHaveLength, len(expected))
+ for i, v := range expected {
+ So(values[i], ShouldEqual, v)
+ }
+}
+
+func intsEqual(values []int, expected ...int) {
+ So(values, ShouldHaveLength, len(expected))
+ for i, v := range expected {
+ So(values[i], ShouldEqual, v)
+ }
+}
+
+func int64sEqual(values []int64, expected ...int64) {
+ So(values, ShouldHaveLength, len(expected))
+ for i, v := range expected {
+ So(values[i], ShouldEqual, v)
+ }
+}
+
+func uintsEqual(values []uint, expected ...uint) {
+ So(values, ShouldHaveLength, len(expected))
+ for i, v := range expected {
+ So(values[i], ShouldEqual, v)
+ }
+}
+
+func uint64sEqual(values []uint64, expected ...uint64) {
+ So(values, ShouldHaveLength, len(expected))
+ for i, v := range expected {
+ So(values[i], ShouldEqual, v)
+ }
+}
+
+func timesEqual(values []time.Time, expected ...time.Time) {
+ So(values, ShouldHaveLength, len(expected))
+ for i, v := range expected {
+ So(values[i].String(), ShouldEqual, v.String())
+ }
+}
+
+func TestKey_Helpers(t *testing.T) {
+ Convey("Getting and setting values", t, func() {
+ f, err := ini.Load(_FULL_CONF)
+ So(err, ShouldBeNil)
+ So(f, ShouldNotBeNil)
+
+ Convey("Get string representation", func() {
+ sec := f.Section("")
So(sec, ShouldNotBeNil)
So(sec.Key("NAME").Value(), ShouldEqual, "ini")
So(sec.Key("NAME").String(), ShouldEqual, "ini")
@@ -40,55 +122,65 @@ func Test_Key(t *testing.T) {
}), ShouldEqual, "ini")
So(sec.Key("NAME").Comment, ShouldEqual, "; Package name")
So(sec.Key("IMPORT_PATH").String(), ShouldEqual, "gopkg.in/ini.v1")
+
+ Convey("With ValueMapper", func() {
+ f.ValueMapper = func(in string) string {
+ if in == "gopkg.in/%(NAME)s.%(VERSION)s" {
+ return "github.com/go-ini/ini"
+ }
+ return in
+ }
+ So(sec.Key("IMPORT_PATH").String(), ShouldEqual, "github.com/go-ini/ini")
+ })
})
Convey("Get values in non-default section", func() {
- sec := cfg.Section("author")
+ sec := f.Section("author")
So(sec, ShouldNotBeNil)
So(sec.Key("NAME").String(), ShouldEqual, "Unknwon")
So(sec.Key("GITHUB").String(), ShouldEqual, "https://github.com/Unknwon")
- sec = cfg.Section("package")
+ sec = f.Section("package")
So(sec, ShouldNotBeNil)
So(sec.Key("CLONE_URL").String(), ShouldEqual, "https://gopkg.in/ini.v1")
})
Convey("Get auto-increment key names", func() {
- keys := cfg.Section("features").Keys()
+ keys := f.Section("features").Keys()
for i, k := range keys {
So(k.Name(), ShouldEqual, fmt.Sprintf("#%d", i+1))
}
})
Convey("Get parent-keys that are available to the child section", func() {
- parentKeys := cfg.Section("package.sub").ParentKeys()
+ parentKeys := f.Section("package.sub").ParentKeys()
for _, k := range parentKeys {
So(k.Name(), ShouldEqual, "CLONE_URL")
}
})
Convey("Get overwrite value", func() {
- So(cfg.Section("author").Key("E-MAIL").String(), ShouldEqual, "u@gogs.io")
+ So(f.Section("author").Key("E-MAIL").String(), ShouldEqual, "u@gogs.io")
})
Convey("Get sections", func() {
- sections := cfg.Sections()
- for i, name := range []string{DEFAULT_SECTION, "author", "package", "package.sub", "features", "types", "array", "note", "comments", "advance"} {
+ sections := f.Sections()
+ for i, name := range []string{ini.DEFAULT_SECTION, "author", "package", "package.sub", "features", "types", "array", "note", "comments", "string escapes", "advance"} {
So(sections[i].Name(), ShouldEqual, name)
}
})
Convey("Get parent section value", func() {
- So(cfg.Section("package.sub").Key("CLONE_URL").String(), ShouldEqual, "https://gopkg.in/ini.v1")
- So(cfg.Section("package.fake.sub").Key("CLONE_URL").String(), ShouldEqual, "https://gopkg.in/ini.v1")
+ So(f.Section("package.sub").Key("CLONE_URL").String(), ShouldEqual, "https://gopkg.in/ini.v1")
+ So(f.Section("package.fake.sub").Key("CLONE_URL").String(), ShouldEqual, "https://gopkg.in/ini.v1")
})
Convey("Get multiple line value", func() {
- So(cfg.Section("author").Key("BIO").String(), ShouldEqual, "Gopher.\nCoding addict.\nGood man.\n")
+ So(f.Section("author").Key("BIO").String(), ShouldEqual, "Gopher.\nCoding addict.\nGood man.\n")
})
Convey("Get values with type", func() {
- sec := cfg.Section("types")
+ sec := f.Section("types")
v1, err := sec.Key("BOOL").Bool()
So(err, ShouldBeNil)
So(v1, ShouldBeTrue)
@@ -168,7 +260,7 @@ func Test_Key(t *testing.T) {
})
Convey("Get value with candidates", func() {
- sec := cfg.Section("types")
+ sec := f.Section("types")
So(sec.Key("STRING").In("", []string{"str", "arr", "types"}), ShouldEqual, "str")
So(sec.Key("FLOAT64").InFloat64(0, []float64{1.25, 2.5, 3.75}), ShouldEqual, 1.25)
So(sec.Key("INT").InInt(0, []int{10, 20, 30}), ShouldEqual, 10)
@@ -194,7 +286,7 @@ func Test_Key(t *testing.T) {
})
Convey("Get values in range", func() {
- sec := cfg.Section("types")
+ sec := f.Section("types")
So(sec.Key("FLOAT64").RangeFloat64(0, 1, 2), ShouldEqual, 1.25)
So(sec.Key("INT").RangeInt(0, 10, 20), ShouldEqual, 10)
So(sec.Key("INT").RangeInt64(0, 10, 20), ShouldEqual, 10)
@@ -218,7 +310,7 @@ func Test_Key(t *testing.T) {
})
Convey("Get values into slice", func() {
- sec := cfg.Section("array")
+ sec := f.Section("array")
So(strings.Join(sec.Key("STRINGS").Strings(","), ","), ShouldEqual, "en,zh,de")
So(len(sec.Key("STRINGS_404").Strings(",")), ShouldEqual, 0)
@@ -243,8 +335,18 @@ func Test_Key(t *testing.T) {
timesEqual(vals6, t, t, t)
})
+ Convey("Test string slice escapes", func() {
+ sec := f.Section("string escapes")
+ So(sec.Key("key1").Strings(","), ShouldResemble, []string{"value1", "value2", "value3"})
+ So(sec.Key("key2").Strings(","), ShouldResemble, []string{"value1, value2"})
+ So(sec.Key("key3").Strings(","), ShouldResemble, []string{`val\ue1`, "value2"})
+ So(sec.Key("key4").Strings(","), ShouldResemble, []string{`value1\`, `value\\2`})
+ So(sec.Key("key5").Strings(",,"), ShouldResemble, []string{"value1,, value2"})
+ So(sec.Key("key6").Strings(" "), ShouldResemble, []string{"aaa", "bbb and space", "ccc"})
+ })
+
Convey("Get valid values into slice", func() {
- sec := cfg.Section("array")
+ sec := f.Section("array")
vals1 := sec.Key("FLOAT64S").ValidFloat64s(",")
float64sEqual(vals1, 1.1, 2.2, 3.3)
@@ -267,7 +369,7 @@ func Test_Key(t *testing.T) {
})
Convey("Get values one type into slice of another type", func() {
- sec := cfg.Section("array")
+ sec := f.Section("array")
vals1 := sec.Key("STRINGS").ValidFloat64s(",")
So(vals1, ShouldBeEmpty)
@@ -288,7 +390,7 @@ func Test_Key(t *testing.T) {
})
Convey("Get valid values into slice without errors", func() {
- sec := cfg.Section("array")
+ sec := f.Section("array")
vals1, err := sec.Key("FLOAT64S").StrictFloat64s(",")
So(err, ShouldBeNil)
float64sEqual(vals1, 1.1, 2.2, 3.3)
@@ -317,7 +419,7 @@ func Test_Key(t *testing.T) {
})
Convey("Get invalid values into slice", func() {
- sec := cfg.Section("array")
+ sec := f.Section("array")
vals1, err := sec.Key("STRINGS").StrictFloat64s(",")
So(vals1, ShouldBeEmpty)
So(err, ShouldNotBeNil)
@@ -342,232 +444,37 @@ func Test_Key(t *testing.T) {
So(vals6, ShouldBeEmpty)
So(err, ShouldNotBeNil)
})
-
- Convey("Get key hash", func() {
- cfg.Section("").KeysHash()
- })
-
- Convey("Set key value", func() {
- k := cfg.Section("author").Key("NAME")
- k.SetValue("无闻")
- So(k.String(), ShouldEqual, "无闻")
- })
-
- Convey("Get key strings", func() {
- So(strings.Join(cfg.Section("types").KeyStrings(), ","), ShouldEqual, "STRING,BOOL,BOOL_FALSE,FLOAT64,INT,TIME,DURATION,UINT")
- })
-
- Convey("Delete a key", func() {
- cfg.Section("package.sub").DeleteKey("UNUSED_KEY")
- _, err := cfg.Section("package.sub").GetKey("UNUSED_KEY")
- So(err, ShouldNotBeNil)
- })
-
- Convey("Has Key (backwards compatible)", func() {
- sec := cfg.Section("package.sub")
- haskey1 := sec.Haskey("UNUSED_KEY")
- haskey2 := sec.Haskey("CLONE_URL")
- haskey3 := sec.Haskey("CLONE_URL_NO")
- So(haskey1, ShouldBeTrue)
- So(haskey2, ShouldBeTrue)
- So(haskey3, ShouldBeFalse)
- })
-
- Convey("Has Key", func() {
- sec := cfg.Section("package.sub")
- haskey1 := sec.HasKey("UNUSED_KEY")
- haskey2 := sec.HasKey("CLONE_URL")
- haskey3 := sec.HasKey("CLONE_URL_NO")
- So(haskey1, ShouldBeTrue)
- So(haskey2, ShouldBeTrue)
- So(haskey3, ShouldBeFalse)
- })
-
- Convey("Has Value", func() {
- sec := cfg.Section("author")
- hasvalue1 := sec.HasValue("Unknwon")
- hasvalue2 := sec.HasValue("doc")
- So(hasvalue1, ShouldBeTrue)
- So(hasvalue2, ShouldBeFalse)
- })
})
+}
- Convey("Test getting and setting bad values", t, func() {
- cfg, err := Load([]byte(_CONF_DATA), "testdata/conf.ini")
+func TestKey_StringsWithShadows(t *testing.T) {
+ Convey("Get strings of shadows of a key", t, func() {
+ f, err := ini.ShadowLoad([]byte(""))
So(err, ShouldBeNil)
- So(cfg, ShouldNotBeNil)
-
- Convey("Create new key with empty name", func() {
- k, err := cfg.Section("").NewKey("", "")
- So(err, ShouldNotBeNil)
- So(k, ShouldBeNil)
- })
-
- Convey("Create new section with empty name", func() {
- s, err := cfg.NewSection("")
- So(err, ShouldNotBeNil)
- So(s, ShouldBeNil)
- })
-
- Convey("Create new sections with empty name", func() {
- So(cfg.NewSections(""), ShouldNotBeNil)
- })
+ So(f, ShouldNotBeNil)
- Convey("Get section that not exists", func() {
- s, err := cfg.GetSection("404")
- So(err, ShouldNotBeNil)
- So(s, ShouldBeNil)
-
- s = cfg.Section("404")
- So(s, ShouldNotBeNil)
- })
- })
-
- Convey("Test key hash clone", t, func() {
- cfg, err := Load([]byte(strings.Replace("network=tcp,addr=127.0.0.1:6379,db=4,pool_size=100,idle_timeout=180", ",", "\n", -1)))
+ k, err := f.Section("").NewKey("NUMS", "1,2")
So(err, ShouldBeNil)
- for _, v := range cfg.Section("").KeysHash() {
- So(len(v), ShouldBeGreaterThan, 0)
- }
- })
-
- Convey("Key has empty value", t, func() {
- _conf := `key1=
-key2= ; comment`
- cfg, err := Load([]byte(_conf))
+ So(k, ShouldNotBeNil)
+ k, err = f.Section("").NewKey("NUMS", "4,5,6")
So(err, ShouldBeNil)
- So(cfg.Section("").Key("key1").Value(), ShouldBeEmpty)
- })
-}
-
-const _CONF_GIT_CONFIG = `
-[remote "origin"]
- url = https://github.com/Antergone/test1.git
- url = https://github.com/Antergone/test2.git
-`
-
-func Test_Key_Shadows(t *testing.T) {
- Convey("Shadows keys", t, func() {
- Convey("Disable shadows", func() {
- cfg, err := Load([]byte(_CONF_GIT_CONFIG))
- So(err, ShouldBeNil)
- So(cfg.Section(`remote "origin"`).Key("url").String(), ShouldEqual, "https://github.com/Antergone/test2.git")
- })
-
- Convey("Enable shadows", func() {
- cfg, err := ShadowLoad([]byte(_CONF_GIT_CONFIG))
- So(err, ShouldBeNil)
- So(cfg.Section(`remote "origin"`).Key("url").String(), ShouldEqual, "https://github.com/Antergone/test1.git")
- So(strings.Join(cfg.Section(`remote "origin"`).Key("url").ValueWithShadows(), " "), ShouldEqual,
- "https://github.com/Antergone/test1.git https://github.com/Antergone/test2.git")
+ So(k, ShouldNotBeNil)
- Convey("Save with shadows", func() {
- var buf bytes.Buffer
- _, err := cfg.WriteTo(&buf)
- So(err, ShouldBeNil)
- So(buf.String(), ShouldEqual, `[remote "origin"]
-url = https://github.com/Antergone/test1.git
-url = https://github.com/Antergone/test2.git
-
-`)
- })
- })
+ So(k.StringsWithShadows(","), ShouldResemble, []string{"1", "2", "4", "5", "6"})
})
}
-func newTestFile(block bool) *File {
- c, _ := Load([]byte(_CONF_DATA))
- c.BlockMode = block
- return c
-}
-
-func Benchmark_Key_Value(b *testing.B) {
- c := newTestFile(true)
- for i := 0; i < b.N; i++ {
- c.Section("").Key("NAME").Value()
- }
-}
-
-func Benchmark_Key_Value_NonBlock(b *testing.B) {
- c := newTestFile(false)
- for i := 0; i < b.N; i++ {
- c.Section("").Key("NAME").Value()
- }
-}
+func TestKey_SetValue(t *testing.T) {
+ Convey("Set value of key", t, func() {
+ f := ini.Empty()
+ So(f, ShouldNotBeNil)
-func Benchmark_Key_Value_ViaSection(b *testing.B) {
- c := newTestFile(true)
- sec := c.Section("")
- for i := 0; i < b.N; i++ {
- sec.Key("NAME").Value()
- }
-}
-
-func Benchmark_Key_Value_ViaSection_NonBlock(b *testing.B) {
- c := newTestFile(false)
- sec := c.Section("")
- for i := 0; i < b.N; i++ {
- sec.Key("NAME").Value()
- }
-}
-
-func Benchmark_Key_Value_Direct(b *testing.B) {
- c := newTestFile(true)
- key := c.Section("").Key("NAME")
- for i := 0; i < b.N; i++ {
- key.Value()
- }
-}
-
-func Benchmark_Key_Value_Direct_NonBlock(b *testing.B) {
- c := newTestFile(false)
- key := c.Section("").Key("NAME")
- for i := 0; i < b.N; i++ {
- key.Value()
- }
-}
-
-func Benchmark_Key_String(b *testing.B) {
- c := newTestFile(true)
- for i := 0; i < b.N; i++ {
- _ = c.Section("").Key("NAME").String()
- }
-}
-
-func Benchmark_Key_String_NonBlock(b *testing.B) {
- c := newTestFile(false)
- for i := 0; i < b.N; i++ {
- _ = c.Section("").Key("NAME").String()
- }
-}
-
-func Benchmark_Key_String_ViaSection(b *testing.B) {
- c := newTestFile(true)
- sec := c.Section("")
- for i := 0; i < b.N; i++ {
- _ = sec.Key("NAME").String()
- }
-}
-
-func Benchmark_Key_String_ViaSection_NonBlock(b *testing.B) {
- c := newTestFile(false)
- sec := c.Section("")
- for i := 0; i < b.N; i++ {
- _ = sec.Key("NAME").String()
- }
-}
-
-func Benchmark_Key_SetValue(b *testing.B) {
- c := newTestFile(true)
- for i := 0; i < b.N; i++ {
- c.Section("").Key("NAME").SetValue("10")
- }
-}
+ k, err := f.Section("").NewKey("NAME", "ini")
+ So(err, ShouldBeNil)
+ So(k, ShouldNotBeNil)
+ So(k.Value(), ShouldEqual, "ini")
-func Benchmark_Key_SetValue_VisSection(b *testing.B) {
- c := newTestFile(true)
- sec := c.Section("")
- for i := 0; i < b.N; i++ {
- sec.Key("NAME").SetValue("10")
- }
+ k.SetValue("ini.v1")
+ So(k.Value(), ShouldEqual, "ini.v1")
+ })
}
diff --git a/vendor/github.com/go-ini/ini/parser.go b/vendor/github.com/go-ini/ini/parser.go
index 69d547627..f8ac8026a 100644
--- a/vendor/github.com/go-ini/ini/parser.go
+++ b/vendor/github.com/go-ini/ini/parser.go
@@ -193,7 +193,7 @@ func hasSurroundedQuote(in string, quote byte) bool {
strings.IndexByte(in[1:], quote) == len(in)-2
}
-func (p *parser) readValue(in []byte, ignoreContinuation, ignoreInlineComment bool) (string, error) {
+func (p *parser) readValue(in []byte, ignoreContinuation, ignoreInlineComment, unescapeValueDoubleQuotes bool) (string, error) {
line := strings.TrimLeftFunc(string(in), unicode.IsSpace)
if len(line) == 0 {
return "", nil
@@ -204,6 +204,8 @@ func (p *parser) readValue(in []byte, ignoreContinuation, ignoreInlineComment bo
valQuote = `"""`
} else if line[0] == '`' {
valQuote = "`"
+ } else if unescapeValueDoubleQuotes && line[0] == '"' {
+ valQuote = `"`
}
if len(valQuote) > 0 {
@@ -214,6 +216,9 @@ func (p *parser) readValue(in []byte, ignoreContinuation, ignoreInlineComment bo
return p.readMultilines(line, line[startIdx:], valQuote)
}
+ if unescapeValueDoubleQuotes && valQuote == `"` {
+ return strings.Replace(line[startIdx:pos+startIdx], `\"`, `"`, -1), nil
+ }
return line[startIdx : pos+startIdx], nil
}
@@ -234,7 +239,7 @@ func (p *parser) readValue(in []byte, ignoreContinuation, ignoreInlineComment bo
}
}
- // Trim single quotes
+ // Trim single and double quotes
if hasSurroundedQuote(line, '\'') ||
hasSurroundedQuote(line, '"') {
line = line[1 : len(line)-1]
@@ -250,7 +255,11 @@ func (f *File) parse(reader io.Reader) (err error) {
}
// Ignore error because default section name is never empty string.
- section, _ := f.NewSection(DEFAULT_SECTION)
+ name := DEFAULT_SECTION
+ if f.options.Insensitive {
+ name = strings.ToLower(DEFAULT_SECTION)
+ }
+ section, _ := f.NewSection(name)
var line []byte
var inUnparseableSection bool
@@ -321,7 +330,10 @@ func (f *File) parse(reader io.Reader) (err error) {
if err != nil {
// Treat as boolean key when desired, and whole line is key name.
if IsErrDelimiterNotFound(err) && f.options.AllowBooleanKeys {
- kname, err := p.readValue(line, f.options.IgnoreContinuation, f.options.IgnoreInlineComment)
+ kname, err := p.readValue(line,
+ f.options.IgnoreContinuation,
+ f.options.IgnoreInlineComment,
+ f.options.UnescapeValueDoubleQuotes)
if err != nil {
return err
}
@@ -344,7 +356,10 @@ func (f *File) parse(reader io.Reader) (err error) {
p.count++
}
- value, err := p.readValue(line[offset:], f.options.IgnoreContinuation, f.options.IgnoreInlineComment)
+ value, err := p.readValue(line[offset:],
+ f.options.IgnoreContinuation,
+ f.options.IgnoreInlineComment,
+ f.options.UnescapeValueDoubleQuotes)
if err != nil {
return err
}
diff --git a/vendor/github.com/go-ini/ini/parser_test.go b/vendor/github.com/go-ini/ini/parser_test.go
index 05258195b..bb0f2665e 100644
--- a/vendor/github.com/go-ini/ini/parser_test.go
+++ b/vendor/github.com/go-ini/ini/parser_test.go
@@ -12,31 +12,66 @@
// License for the specific language governing permissions and limitations
// under the License.
-package ini
+package ini_test
import (
"testing"
. "github.com/smartystreets/goconvey/convey"
+ "gopkg.in/ini.v1"
)
-func Test_BOM(t *testing.T) {
+func TestBOM(t *testing.T) {
Convey("Test handling BOM", t, func() {
Convey("UTF-8-BOM", func() {
- cfg, err := Load("testdata/UTF-8-BOM.ini")
+ f, err := ini.Load("testdata/UTF-8-BOM.ini")
So(err, ShouldBeNil)
- So(cfg, ShouldNotBeNil)
+ So(f, ShouldNotBeNil)
- So(cfg.Section("author").Key("E-MAIL").String(), ShouldEqual, "u@gogs.io")
+ So(f.Section("author").Key("E-MAIL").String(), ShouldEqual, "u@gogs.io")
})
Convey("UTF-16-LE-BOM", func() {
- cfg, err := Load("testdata/UTF-16-LE-BOM.ini")
+ f, err := ini.Load("testdata/UTF-16-LE-BOM.ini")
So(err, ShouldBeNil)
- So(cfg, ShouldNotBeNil)
+ So(f, ShouldNotBeNil)
})
Convey("UTF-16-BE-BOM", func() {
})
})
}
+
+func TestBadLoad(t *testing.T) {
+ Convey("Load with bad data", t, func() {
+ Convey("Bad section name", func() {
+ _, err := ini.Load([]byte("[]"))
+ So(err, ShouldNotBeNil)
+
+ _, err = ini.Load([]byte("["))
+ So(err, ShouldNotBeNil)
+ })
+
+ Convey("Bad keys", func() {
+ _, err := ini.Load([]byte(`"""name`))
+ So(err, ShouldNotBeNil)
+
+ _, err = ini.Load([]byte(`"""name"""`))
+ So(err, ShouldNotBeNil)
+
+ _, err = ini.Load([]byte(`""=1`))
+ So(err, ShouldNotBeNil)
+
+ _, err = ini.Load([]byte(`=`))
+ So(err, ShouldNotBeNil)
+
+ _, err = ini.Load([]byte(`name`))
+ So(err, ShouldNotBeNil)
+ })
+
+ Convey("Bad values", func() {
+ _, err := ini.Load([]byte(`name="""Unknwon`))
+ So(err, ShouldNotBeNil)
+ })
+ })
+}
diff --git a/vendor/github.com/go-ini/ini/section.go b/vendor/github.com/go-ini/ini/section.go
index 94f7375ed..d8a402619 100644
--- a/vendor/github.com/go-ini/ini/section.go
+++ b/vendor/github.com/go-ini/ini/section.go
@@ -54,6 +54,14 @@ func (s *Section) Body() string {
return strings.TrimSpace(s.rawBody)
}
+// SetBody updates body content only if section is raw.
+func (s *Section) SetBody(body string) {
+ if !s.isRawSection {
+ return
+ }
+ s.rawBody = body
+}
+
// NewKey creates a new key to given section.
func (s *Section) NewKey(name, val string) (*Key, error) {
if len(name) == 0 {
@@ -136,6 +144,7 @@ func (s *Section) HasKey(name string) bool {
}
// Haskey is a backwards-compatible name for HasKey.
+// TODO: delete me in v2
func (s *Section) Haskey(name string) bool {
return s.HasKey(name)
}
diff --git a/vendor/github.com/go-ini/ini/section_test.go b/vendor/github.com/go-ini/ini/section_test.go
index 80282c197..e9c347881 100644
--- a/vendor/github.com/go-ini/ini/section_test.go
+++ b/vendor/github.com/go-ini/ini/section_test.go
@@ -12,64 +12,302 @@
// License for the specific language governing permissions and limitations
// under the License.
-package ini
+package ini_test
import (
- "strings"
"testing"
. "github.com/smartystreets/goconvey/convey"
+ "gopkg.in/ini.v1"
)
-func Test_Section(t *testing.T) {
- Convey("Test CRD sections", t, func() {
- cfg, err := Load([]byte(_CONF_DATA), "testdata/conf.ini")
+func TestSection_SetBody(t *testing.T) {
+ Convey("Set body of raw section", t, func() {
+ f := ini.Empty()
+ So(f, ShouldNotBeNil)
+
+ sec, err := f.NewRawSection("comments", `1111111111111111111000000000000000001110000
+111111111111111111100000000000111000000000`)
+ So(err, ShouldBeNil)
+ So(sec, ShouldNotBeNil)
+ So(sec.Body(), ShouldEqual, `1111111111111111111000000000000000001110000
+111111111111111111100000000000111000000000`)
+
+ sec.SetBody("1111111111111111111000000000000000001110000")
+ So(sec.Body(), ShouldEqual, `1111111111111111111000000000000000001110000`)
+
+ Convey("Set for non-raw section", func() {
+ sec, err := f.NewSection("author")
+ So(err, ShouldBeNil)
+ So(sec, ShouldNotBeNil)
+ So(sec.Body(), ShouldBeEmpty)
+
+ sec.SetBody("1111111111111111111000000000000000001110000")
+ So(sec.Body(), ShouldBeEmpty)
+ })
+ })
+}
+
+func TestSection_NewKey(t *testing.T) {
+ Convey("Create a new key", t, func() {
+ f := ini.Empty()
+ So(f, ShouldNotBeNil)
+
+ k, err := f.Section("").NewKey("NAME", "ini")
+ So(err, ShouldBeNil)
+ So(k, ShouldNotBeNil)
+ So(k.Name(), ShouldEqual, "NAME")
+ So(k.Value(), ShouldEqual, "ini")
+
+ Convey("With duplicated name", func() {
+ k, err := f.Section("").NewKey("NAME", "ini.v1")
+ So(err, ShouldBeNil)
+ So(k, ShouldNotBeNil)
+
+ // Overwrite previous existed key
+ So(k.Value(), ShouldEqual, "ini.v1")
+ })
+
+ Convey("With empty string", func() {
+ _, err := f.Section("").NewKey("", "")
+ So(err, ShouldNotBeNil)
+ })
+ })
+
+ Convey("Create keys with same name and allow shadow", t, func() {
+ f, err := ini.ShadowLoad([]byte(""))
+ So(err, ShouldBeNil)
+ So(f, ShouldNotBeNil)
+
+ k, err := f.Section("").NewKey("NAME", "ini")
+ So(err, ShouldBeNil)
+ So(k, ShouldNotBeNil)
+ k, err = f.Section("").NewKey("NAME", "ini.v1")
So(err, ShouldBeNil)
- So(cfg, ShouldNotBeNil)
+ So(k, ShouldNotBeNil)
- Convey("Get section strings", func() {
- So(strings.Join(cfg.SectionStrings(), ","), ShouldEqual, "DEFAULT,author,package,package.sub,features,types,array,note,comments,advance")
+ So(k.ValueWithShadows(), ShouldResemble, []string{"ini", "ini.v1"})
+ })
+}
+
+func TestSection_NewBooleanKey(t *testing.T) {
+ Convey("Create a new boolean key", t, func() {
+ f := ini.Empty()
+ So(f, ShouldNotBeNil)
+
+ k, err := f.Section("").NewBooleanKey("start-ssh-server")
+ So(err, ShouldBeNil)
+ So(k, ShouldNotBeNil)
+ So(k.Name(), ShouldEqual, "start-ssh-server")
+ So(k.Value(), ShouldEqual, "true")
+
+ Convey("With empty string", func() {
+ _, err := f.Section("").NewBooleanKey("")
+ So(err, ShouldNotBeNil)
})
+ })
+}
+
+func TestSection_GetKey(t *testing.T) {
+ Convey("Get a key", t, func() {
+ f := ini.Empty()
+ So(f, ShouldNotBeNil)
- Convey("Delete a section", func() {
- cfg.DeleteSection("")
- So(cfg.SectionStrings()[0], ShouldNotEqual, DEFAULT_SECTION)
+ k, err := f.Section("").NewKey("NAME", "ini")
+ So(err, ShouldBeNil)
+ So(k, ShouldNotBeNil)
+
+ k, err = f.Section("").GetKey("NAME")
+ So(err, ShouldBeNil)
+ So(k, ShouldNotBeNil)
+ So(k.Name(), ShouldEqual, "NAME")
+ So(k.Value(), ShouldEqual, "ini")
+
+ Convey("Key not exists", func() {
+ _, err := f.Section("").GetKey("404")
+ So(err, ShouldNotBeNil)
})
- Convey("Create new sections", func() {
- cfg.NewSections("test", "test2")
- _, err := cfg.GetSection("test")
+ Convey("Key exists in parent section", func() {
+ k, err := f.Section("parent").NewKey("AGE", "18")
So(err, ShouldBeNil)
- _, err = cfg.GetSection("test2")
+ So(k, ShouldNotBeNil)
+
+ k, err = f.Section("parent.child.son").GetKey("AGE")
So(err, ShouldBeNil)
+ So(k, ShouldNotBeNil)
+ So(k.Value(), ShouldEqual, "18")
})
})
}
-func Test_SectionRaw(t *testing.T) {
- Convey("Test section raw string", t, func() {
- cfg, err := LoadSources(
- LoadOptions{
- Insensitive: true,
- UnparseableSections: []string{"core_lesson", "comments"},
- },
- "testdata/aicc.ini")
+func TestSection_HasKey(t *testing.T) {
+ Convey("Check if a key exists", t, func() {
+ f := ini.Empty()
+ So(f, ShouldNotBeNil)
+
+ k, err := f.Section("").NewKey("NAME", "ini")
So(err, ShouldBeNil)
- So(cfg, ShouldNotBeNil)
+ So(k, ShouldNotBeNil)
+
+ So(f.Section("").HasKey("NAME"), ShouldBeTrue)
+ So(f.Section("").Haskey("NAME"), ShouldBeTrue)
+ So(f.Section("").HasKey("404"), ShouldBeFalse)
+ So(f.Section("").Haskey("404"), ShouldBeFalse)
+ })
+}
- Convey("Get section strings", func() {
- So(strings.Join(cfg.SectionStrings(), ","), ShouldEqual, "DEFAULT,core,core_lesson,comments")
+func TestSection_HasValue(t *testing.T) {
+ Convey("Check if contains a value in any key", t, func() {
+ f := ini.Empty()
+ So(f, ShouldNotBeNil)
+
+ k, err := f.Section("").NewKey("NAME", "ini")
+ So(err, ShouldBeNil)
+ So(k, ShouldNotBeNil)
+
+ So(f.Section("").HasValue("ini"), ShouldBeTrue)
+ So(f.Section("").HasValue("404"), ShouldBeFalse)
+ })
+}
+
+func TestSection_Key(t *testing.T) {
+ Convey("Get a key", t, func() {
+ f := ini.Empty()
+ So(f, ShouldNotBeNil)
+
+ k, err := f.Section("").NewKey("NAME", "ini")
+ So(err, ShouldBeNil)
+ So(k, ShouldNotBeNil)
+
+ k = f.Section("").Key("NAME")
+ So(k, ShouldNotBeNil)
+ So(k.Name(), ShouldEqual, "NAME")
+ So(k.Value(), ShouldEqual, "ini")
+
+ Convey("Key not exists", func() {
+ k := f.Section("").Key("404")
+ So(k, ShouldNotBeNil)
+ So(k.Name(), ShouldEqual, "404")
})
- Convey("Validate non-raw section", func() {
- val, err := cfg.Section("core").GetKey("lesson_status")
+ Convey("Key exists in parent section", func() {
+ k, err := f.Section("parent").NewKey("AGE", "18")
So(err, ShouldBeNil)
- So(val.String(), ShouldEqual, "C")
- })
+ So(k, ShouldNotBeNil)
- Convey("Validate raw section", func() {
- So(cfg.Section("core_lesson").Body(), ShouldEqual, `my lesson state data – 1111111111111111111000000000000000001110000
-111111111111111111100000000000111000000000 – end my lesson state data`)
+ k = f.Section("parent.child.son").Key("AGE")
+ So(k, ShouldNotBeNil)
+ So(k.Value(), ShouldEqual, "18")
})
})
-} \ No newline at end of file
+}
+
+func TestSection_Keys(t *testing.T) {
+ Convey("Get all keys in a section", t, func() {
+ f := ini.Empty()
+ So(f, ShouldNotBeNil)
+
+ k, err := f.Section("").NewKey("NAME", "ini")
+ So(err, ShouldBeNil)
+ So(k, ShouldNotBeNil)
+ k, err = f.Section("").NewKey("VERSION", "v1")
+ So(err, ShouldBeNil)
+ So(k, ShouldNotBeNil)
+ k, err = f.Section("").NewKey("IMPORT_PATH", "gopkg.in/ini.v1")
+ So(err, ShouldBeNil)
+ So(k, ShouldNotBeNil)
+
+ keys := f.Section("").Keys()
+ names := []string{"NAME", "VERSION", "IMPORT_PATH"}
+ So(len(keys), ShouldEqual, len(names))
+ for i, name := range names {
+ So(keys[i].Name(), ShouldEqual, name)
+ }
+ })
+}
+
+func TestSection_ParentKeys(t *testing.T) {
+ Convey("Get all keys of parent sections", t, func() {
+ f := ini.Empty()
+ So(f, ShouldNotBeNil)
+
+ k, err := f.Section("package").NewKey("NAME", "ini")
+ So(err, ShouldBeNil)
+ So(k, ShouldNotBeNil)
+ k, err = f.Section("package").NewKey("VERSION", "v1")
+ So(err, ShouldBeNil)
+ So(k, ShouldNotBeNil)
+ k, err = f.Section("package").NewKey("IMPORT_PATH", "gopkg.in/ini.v1")
+ So(err, ShouldBeNil)
+ So(k, ShouldNotBeNil)
+
+ keys := f.Section("package.sub.sub2").ParentKeys()
+ names := []string{"NAME", "VERSION", "IMPORT_PATH"}
+ So(len(keys), ShouldEqual, len(names))
+ for i, name := range names {
+ So(keys[i].Name(), ShouldEqual, name)
+ }
+ })
+}
+
+func TestSection_KeyStrings(t *testing.T) {
+ Convey("Get all key names in a section", t, func() {
+ f := ini.Empty()
+ So(f, ShouldNotBeNil)
+
+ k, err := f.Section("").NewKey("NAME", "ini")
+ So(err, ShouldBeNil)
+ So(k, ShouldNotBeNil)
+ k, err = f.Section("").NewKey("VERSION", "v1")
+ So(err, ShouldBeNil)
+ So(k, ShouldNotBeNil)
+ k, err = f.Section("").NewKey("IMPORT_PATH", "gopkg.in/ini.v1")
+ So(err, ShouldBeNil)
+ So(k, ShouldNotBeNil)
+
+ So(f.Section("").KeyStrings(), ShouldResemble, []string{"NAME", "VERSION", "IMPORT_PATH"})
+ })
+}
+
+func TestSection_KeyHash(t *testing.T) {
+ Convey("Get clone of key hash", t, func() {
+ f := ini.Empty()
+ So(f, ShouldNotBeNil)
+
+ k, err := f.Section("").NewKey("NAME", "ini")
+ So(err, ShouldBeNil)
+ So(k, ShouldNotBeNil)
+ k, err = f.Section("").NewKey("VERSION", "v1")
+ So(err, ShouldBeNil)
+ So(k, ShouldNotBeNil)
+ k, err = f.Section("").NewKey("IMPORT_PATH", "gopkg.in/ini.v1")
+ So(err, ShouldBeNil)
+ So(k, ShouldNotBeNil)
+
+ hash := f.Section("").KeysHash()
+ relation := map[string]string{
+ "NAME": "ini",
+ "VERSION": "v1",
+ "IMPORT_PATH": "gopkg.in/ini.v1",
+ }
+ for k, v := range hash {
+ So(v, ShouldEqual, relation[k])
+ }
+ })
+}
+
+func TestSection_DeleteKey(t *testing.T) {
+ Convey("Delete a key", t, func() {
+ f := ini.Empty()
+ So(f, ShouldNotBeNil)
+
+ k, err := f.Section("").NewKey("NAME", "ini")
+ So(err, ShouldBeNil)
+ So(k, ShouldNotBeNil)
+
+ So(f.Section("").HasKey("NAME"), ShouldBeTrue)
+ f.Section("").DeleteKey("NAME")
+ So(f.Section("").HasKey("NAME"), ShouldBeFalse)
+ })
+}
diff --git a/vendor/github.com/go-ini/ini/struct.go b/vendor/github.com/go-ini/ini/struct.go
index eeb8dabaa..9719dc698 100644
--- a/vendor/github.com/go-ini/ini/struct.go
+++ b/vendor/github.com/go-ini/ini/struct.go
@@ -113,7 +113,7 @@ func setSliceWithProperType(key *Key, field reflect.Value, delim string, allowSh
default:
return fmt.Errorf("unsupported type '[]%s'", sliceOf)
}
- if isStrict {
+ if err != nil && isStrict {
return err
}
@@ -166,7 +166,7 @@ func setWithProperType(t reflect.Type, key *Key, field reflect.Value, delim stri
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
durationVal, err := key.Duration()
// Skip zero value
- if err == nil && int(durationVal) > 0 {
+ if err == nil && int64(durationVal) > 0 {
field.Set(reflect.ValueOf(durationVal))
return nil
}
@@ -450,6 +450,12 @@ func (s *Section) reflectFrom(val reflect.Value) error {
// Note: fieldName can never be empty here, ignore error.
sec, _ = s.f.NewSection(fieldName)
}
+
+ // Add comment from comment tag
+ if len(sec.Comment) == 0 {
+ sec.Comment = tpField.Tag.Get("comment")
+ }
+
if err = sec.reflectFrom(field); err != nil {
return fmt.Errorf("error reflecting field (%s): %v", fieldName, err)
}
@@ -461,6 +467,12 @@ func (s *Section) reflectFrom(val reflect.Value) error {
if err != nil {
key, _ = s.NewKey(fieldName, "")
}
+
+ // Add comment from comment tag
+ if len(key.Comment) == 0 {
+ key.Comment = tpField.Tag.Get("comment")
+ }
+
if err = reflectWithProperType(tpField.Type, key, field, parseDelim(tpField.Tag.Get("delim"))); err != nil {
return fmt.Errorf("error reflecting field (%s): %v", fieldName, err)
}
diff --git a/vendor/github.com/go-ini/ini/struct_test.go b/vendor/github.com/go-ini/ini/struct_test.go
index b8ba25293..75987ea99 100644
--- a/vendor/github.com/go-ini/ini/struct_test.go
+++ b/vendor/github.com/go-ini/ini/struct_test.go
@@ -12,7 +12,7 @@
// License for the specific language governing permissions and limitations
// under the License.
-package ini
+package ini_test
import (
"bytes"
@@ -22,6 +22,7 @@ import (
"time"
. "github.com/smartystreets/goconvey/convey"
+ "gopkg.in/ini.v1"
)
type testNested struct {
@@ -126,11 +127,11 @@ Born = nil
Cities =
`
-func Test_Struct(t *testing.T) {
+func Test_MapToStruct(t *testing.T) {
Convey("Map to struct", t, func() {
Convey("Map file to struct", func() {
ts := new(testStruct)
- So(MapTo(ts, []byte(_CONF_DATA_STRUCT)), ShouldBeNil)
+ So(ini.MapTo(ts, []byte(_CONF_DATA_STRUCT)), ShouldBeNil)
So(ts.Name, ShouldEqual, "Unknwon")
So(ts.Age, ShouldEqual, 21)
@@ -159,7 +160,7 @@ func Test_Struct(t *testing.T) {
Convey("Map section to struct", func() {
foobar := new(fooBar)
- f, err := Load([]byte(_CONF_DATA_STRUCT))
+ f, err := ini.Load([]byte(_CONF_DATA_STRUCT))
So(err, ShouldBeNil)
So(f.Section("foo.bar").MapTo(foobar), ShouldBeNil)
@@ -168,58 +169,58 @@ func Test_Struct(t *testing.T) {
})
Convey("Map to non-pointer struct", func() {
- cfg, err := Load([]byte(_CONF_DATA_STRUCT))
+ f, err := ini.Load([]byte(_CONF_DATA_STRUCT))
So(err, ShouldBeNil)
- So(cfg, ShouldNotBeNil)
+ So(f, ShouldNotBeNil)
- So(cfg.MapTo(testStruct{}), ShouldNotBeNil)
+ So(f.MapTo(testStruct{}), ShouldNotBeNil)
})
Convey("Map to unsupported type", func() {
- cfg, err := Load([]byte(_CONF_DATA_STRUCT))
+ f, err := ini.Load([]byte(_CONF_DATA_STRUCT))
So(err, ShouldBeNil)
- So(cfg, ShouldNotBeNil)
+ So(f, ShouldNotBeNil)
- cfg.NameMapper = func(raw string) string {
+ f.NameMapper = func(raw string) string {
if raw == "Byte" {
return "NAME"
}
return raw
}
- So(cfg.MapTo(&unsupport{}), ShouldNotBeNil)
- So(cfg.MapTo(&unsupport2{}), ShouldNotBeNil)
- So(cfg.MapTo(&unsupport4{}), ShouldNotBeNil)
+ So(f.MapTo(&unsupport{}), ShouldNotBeNil)
+ So(f.MapTo(&unsupport2{}), ShouldNotBeNil)
+ So(f.MapTo(&unsupport4{}), ShouldNotBeNil)
})
Convey("Map to omitempty field", func() {
ts := new(testStruct)
- So(MapTo(ts, []byte(_CONF_DATA_STRUCT)), ShouldBeNil)
+ So(ini.MapTo(ts, []byte(_CONF_DATA_STRUCT)), ShouldBeNil)
So(ts.Omitted, ShouldEqual, true)
})
Convey("Map with shadows", func() {
- cfg, err := LoadSources(LoadOptions{AllowShadows: true}, []byte(_CONF_DATA_STRUCT))
+ f, err := ini.LoadSources(ini.LoadOptions{AllowShadows: true}, []byte(_CONF_DATA_STRUCT))
So(err, ShouldBeNil)
ts := new(testStruct)
- So(cfg.MapTo(ts), ShouldBeNil)
+ So(f.MapTo(ts), ShouldBeNil)
So(strings.Join(ts.Shadows, " "), ShouldEqual, "1 2 3 4")
So(fmt.Sprintf("%v", ts.ShadowInts), ShouldEqual, "[1 2 3 4]")
})
Convey("Map from invalid data source", func() {
- So(MapTo(&testStruct{}, "hi"), ShouldNotBeNil)
+ So(ini.MapTo(&testStruct{}, "hi"), ShouldNotBeNil)
})
Convey("Map to wrong types and gain default values", func() {
- cfg, err := Load([]byte(_INVALID_DATA_CONF_STRUCT))
+ f, err := ini.Load([]byte(_INVALID_DATA_CONF_STRUCT))
So(err, ShouldBeNil)
t, err := time.Parse(time.RFC3339, "1993-10-07T20:17:05Z")
So(err, ShouldBeNil)
dv := &defaultValue{"Joe", 10, true, 1.25, t, []string{"HangZhou", "Boston"}}
- So(cfg.MapTo(dv), ShouldBeNil)
+ So(f.MapTo(dv), ShouldBeNil)
So(dv.Name, ShouldEqual, "Joe")
So(dv.Age, ShouldEqual, 10)
So(dv.Male, ShouldBeTrue)
@@ -230,7 +231,7 @@ func Test_Struct(t *testing.T) {
})
Convey("Map to struct in strict mode", t, func() {
- cfg, err := Load([]byte(`
+ f, err := ini.Load([]byte(`
name=bruce
age=a30`))
So(err, ShouldBeNil)
@@ -241,12 +242,28 @@ age=a30`))
}
s := new(Strict)
- So(cfg.Section("").StrictMapTo(s), ShouldNotBeNil)
+ So(f.Section("").StrictMapTo(s), ShouldNotBeNil)
})
+ Convey("Map slice in strict mode", t, func() {
+ f, err := ini.Load([]byte(`
+names=alice, bruce`))
+ So(err, ShouldBeNil)
+
+ type Strict struct {
+ Names []string `ini:"names"`
+ }
+ s := new(Strict)
+
+ So(f.Section("").StrictMapTo(s), ShouldBeNil)
+ So(fmt.Sprint(s.Names), ShouldEqual, "[alice bruce]")
+ })
+}
+
+func Test_ReflectFromStruct(t *testing.T) {
Convey("Reflect from struct", t, func() {
type Embeded struct {
- Dates []time.Time `delim:"|"`
+ Dates []time.Time `delim:"|" comment:"Time data"`
Places []string
Years []int
Numbers []int64
@@ -258,12 +275,12 @@ age=a30`))
type Author struct {
Name string `ini:"NAME"`
Male bool
- Age int
+ Age int `comment:"Author's age"`
Height uint
GPA float64
Date time.Time
NeverMind string `ini:"-"`
- *Embeded `ini:"infos"`
+ *Embeded `ini:"infos" comment:"Embeded section"`
}
t, err := time.Parse(time.RFC3339, "1993-10-07T20:17:05Z")
@@ -279,20 +296,23 @@ age=a30`))
[]float64{192.168, 10.11},
[]int{},
}}
- cfg := Empty()
- So(ReflectFrom(cfg, a), ShouldBeNil)
+ cfg := ini.Empty()
+ So(ini.ReflectFrom(cfg, a), ShouldBeNil)
var buf bytes.Buffer
_, err = cfg.WriteTo(&buf)
So(err, ShouldBeNil)
So(buf.String(), ShouldEqual, `NAME = Unknwon
Male = true
+; Author's age
Age = 21
Height = 100
GPA = 2.8
Date = 1993-10-07T20:17:05Z
+; Embeded section
[infos]
+; Time data
Dates = 1993-10-07T20:17:05Z|1993-10-07T20:17:05Z
Places = HangZhou,Boston
Years = 1993,1994
@@ -305,11 +325,11 @@ None =
`)
Convey("Reflect from non-point struct", func() {
- So(ReflectFrom(cfg, Author{}), ShouldNotBeNil)
+ So(ini.ReflectFrom(cfg, Author{}), ShouldNotBeNil)
})
Convey("Reflect from struct with omitempty", func() {
- cfg := Empty()
+ cfg := ini.Empty()
type SpecialStruct struct {
FirstName string `ini:"first_name"`
LastName string `ini:"last_name"`
@@ -319,7 +339,7 @@ None =
NotEmpty int `ini:"omitempty"`
}
- So(ReflectFrom(cfg, &SpecialStruct{FirstName: "John", LastName: "Doe", NotEmpty: 9}), ShouldBeNil)
+ So(ini.ReflectFrom(cfg, &SpecialStruct{FirstName: "John", LastName: "Doe", NotEmpty: 9}), ShouldBeNil)
var buf bytes.Buffer
_, err = cfg.WriteTo(&buf)
@@ -338,15 +358,30 @@ type testMapper struct {
func Test_NameGetter(t *testing.T) {
Convey("Test name mappers", t, func() {
- So(MapToWithMapper(&testMapper{}, TitleUnderscore, []byte("packag_name=ini")), ShouldBeNil)
+ So(ini.MapToWithMapper(&testMapper{}, ini.TitleUnderscore, []byte("packag_name=ini")), ShouldBeNil)
- cfg, err := Load([]byte("PACKAGE_NAME=ini"))
+ cfg, err := ini.Load([]byte("PACKAGE_NAME=ini"))
So(err, ShouldBeNil)
So(cfg, ShouldNotBeNil)
- cfg.NameMapper = AllCapsUnderscore
+ cfg.NameMapper = ini.AllCapsUnderscore
tg := new(testMapper)
So(cfg.MapTo(tg), ShouldBeNil)
So(tg.PackageName, ShouldEqual, "ini")
})
}
+
+type testDurationStruct struct {
+ Duration time.Duration `ini:"Duration"`
+}
+
+func Test_Duration(t *testing.T) {
+ Convey("Duration less than 16m50s", t, func() {
+ ds := new(testDurationStruct)
+ So(ini.MapTo(ds, []byte("Duration=16m49s")), ShouldBeNil)
+
+ dur, err := time.ParseDuration("16m49s")
+ So(err, ShouldBeNil)
+ So(ds.Duration.Seconds(), ShouldEqual, dur.Seconds())
+ })
+}
diff --git a/vendor/github.com/go-ini/ini/testdata/aicc.ini b/vendor/github.com/go-ini/ini/testdata/aicc.ini
deleted file mode 100644
index 59a61970d..000000000
--- a/vendor/github.com/go-ini/ini/testdata/aicc.ini
+++ /dev/null
@@ -1,11 +0,0 @@
-[Core]
- Lesson_Location = 87
-Lesson_Status = C
- Score = 3
-Time = 00:02:30
-
-[CORE_LESSON]
-my lesson state data – 1111111111111111111000000000000000001110000
-111111111111111111100000000000111000000000 – end my lesson state data
-[COMMENTS]
-<1><L.Slide#2> This slide has the fuel listed in the wrong units <e.1>
diff --git a/vendor/github.com/go-ini/ini/testdata/full.ini b/vendor/github.com/go-ini/ini/testdata/full.ini
new file mode 100644
index 000000000..469b1f13e
--- /dev/null
+++ b/vendor/github.com/go-ini/ini/testdata/full.ini
@@ -0,0 +1,83 @@
+; Package name
+NAME = ini
+; Package version
+VERSION = v1
+; Package import path
+IMPORT_PATH = gopkg.in/%(NAME)s.%(VERSION)s
+
+# Information about package author
+# Bio can be written in multiple lines.
+[author]
+NAME = Unknwon
+E-MAIL = u@gogs.io
+GITHUB = https://github.com/%(NAME)s
+BIO = """Gopher.
+Coding addict.
+Good man.
+""" # Succeeding comment
+
+[package]
+CLONE_URL = https://%(IMPORT_PATH)s
+
+[package.sub]
+UNUSED_KEY = should be deleted
+
+[features]
+-: Support read/write comments of keys and sections
+-: Support auto-increment of key names
+-: Support load multiple files to overwrite key values
+
+[types]
+STRING = str
+BOOL = true
+BOOL_FALSE = false
+FLOAT64 = 1.25
+INT = 10
+TIME = 2015-01-01T20:17:05Z
+DURATION = 2h45m
+UINT = 3
+
+[array]
+STRINGS = en, zh, de
+FLOAT64S = 1.1, 2.2, 3.3
+INTS = 1, 2, 3
+UINTS = 1, 2, 3
+TIMES = 2015-01-01T20:17:05Z,2015-01-01T20:17:05Z,2015-01-01T20:17:05Z
+
+[note]
+empty_lines = next line is empty\
+
+; Comment before the section
+[comments] ; This is a comment for the section too
+; Comment before key
+key = "value"
+key2 = "value2" ; This is a comment for key2
+key3 = "one", "two", "three"
+
+[string escapes]
+key1 = value1, value2, value3
+key2 = value1\, value2
+key3 = val\ue1, value2
+key4 = value1\\, value\\\\2
+key5 = value1\,, value2
+key6 = aaa bbb\ and\ space ccc
+
+[advance]
+value with quotes = "some value"
+value quote2 again = 'some value'
+includes comment sign = `my#password`
+includes comment sign2 = `my;password`
+true = 2+3=5
+"1+1=2" = true
+"""6+1=7""" = true
+"""`5+5`""" = 10
+`"6+6"` = 12
+`7-2=4` = false
+ADDRESS = `404 road,
+NotFound, State, 50000`
+two_lines = how about \
+ continuation lines?
+lots_of_lines = 1 \
+ 2 \
+ 3 \
+ 4 \
diff --git a/vendor/github.com/go-ini/ini/testdata/conf.ini b/vendor/github.com/go-ini/ini/testdata/minimal.ini
index f8e7ec89f..f8e7ec89f 100644
--- a/vendor/github.com/go-ini/ini/testdata/conf.ini
+++ b/vendor/github.com/go-ini/ini/testdata/minimal.ini
diff --git a/vendor/github.com/go-redis/redis/commands.go b/vendor/github.com/go-redis/redis/commands.go
index a3b90f12d..c04b3c49b 100644
--- a/vendor/github.com/go-redis/redis/commands.go
+++ b/vendor/github.com/go-redis/redis/commands.go
@@ -214,6 +214,7 @@ type Cmdable interface {
ScriptKill() *StatusCmd
ScriptLoad(script string) *StringCmd
DebugObject(key string) *StringCmd
+ Publish(channel string, message interface{}) *IntCmd
PubSubChannels(pattern string) *StringSliceCmd
PubSubNumSub(channels ...string) *StringIntMapCmd
PubSubNumPat() *IntCmd
@@ -1880,8 +1881,8 @@ func (c *cmdable) DebugObject(key string) *StringCmd {
//------------------------------------------------------------------------------
// Publish posts the message to the channel.
-func (c *cmdable) Publish(channel, message string) *IntCmd {
- cmd := NewIntCmd("PUBLISH", channel, message)
+func (c *cmdable) Publish(channel string, message interface{}) *IntCmd {
+ cmd := NewIntCmd("publish", channel, message)
c.process(cmd)
return cmd
}
diff --git a/vendor/github.com/go-redis/redis/internal/pool/pool.go b/vendor/github.com/go-redis/redis/internal/pool/pool.go
index 836ec1045..ae81905ea 100644
--- a/vendor/github.com/go-redis/redis/internal/pool/pool.go
+++ b/vendor/github.com/go-redis/redis/internal/pool/pool.go
@@ -60,8 +60,10 @@ type Options struct {
type ConnPool struct {
opt *Options
- dialErrorsNum uint32 // atomic
- _lastDialError atomic.Value
+ dialErrorsNum uint32 // atomic
+
+ lastDialError error
+ lastDialErrorMu sync.RWMutex
queue chan struct{}
@@ -98,7 +100,7 @@ func (p *ConnPool) NewConn() (*Conn, error) {
}
if atomic.LoadUint32(&p.dialErrorsNum) >= uint32(p.opt.PoolSize) {
- return nil, p.lastDialError()
+ return nil, p.getLastDialError()
}
netConn, err := p.opt.Dialer()
@@ -138,11 +140,16 @@ func (p *ConnPool) tryDial() {
}
func (p *ConnPool) setLastDialError(err error) {
- p._lastDialError.Store(err)
+ p.lastDialErrorMu.Lock()
+ p.lastDialError = err
+ p.lastDialErrorMu.Unlock()
}
-func (p *ConnPool) lastDialError() error {
- return p._lastDialError.Load().(error)
+func (p *ConnPool) getLastDialError() error {
+ p.lastDialErrorMu.RLock()
+ err := p.lastDialError
+ p.lastDialErrorMu.RUnlock()
+ return err
}
// Get returns existed connection from the pool or creates a new one.
diff --git a/vendor/github.com/go-redis/redis/internal/proto/scan.go b/vendor/github.com/go-redis/redis/internal/proto/scan.go
index 0431a877d..03c8b59aa 100644
--- a/vendor/github.com/go-redis/redis/internal/proto/scan.go
+++ b/vendor/github.com/go-redis/redis/internal/proto/scan.go
@@ -120,8 +120,9 @@ func ScanSlice(data []string, slice interface{}) error {
return fmt.Errorf("redis: ScanSlice(non-slice %T)", slice)
}
+ next := internal.MakeSliceNextElemFunc(v)
for i, s := range data {
- elem := internal.SliceNextElem(v)
+ elem := next()
if err := Scan(internal.StringToBytes(s), elem.Addr().Interface()); err != nil {
return fmt.Errorf("redis: ScanSlice(index=%d value=%q) failed: %s", i, s, err)
}
diff --git a/vendor/github.com/go-redis/redis/internal/util.go b/vendor/github.com/go-redis/redis/internal/util.go
index 520596fd9..1ba9805fe 100644
--- a/vendor/github.com/go-redis/redis/internal/util.go
+++ b/vendor/github.com/go-redis/redis/internal/util.go
@@ -28,20 +28,35 @@ func isLower(s string) bool {
return true
}
-func SliceNextElem(v reflect.Value) reflect.Value {
- if v.Len() < v.Cap() {
- v.Set(v.Slice(0, v.Len()+1))
- return v.Index(v.Len() - 1)
- }
-
+func MakeSliceNextElemFunc(v reflect.Value) func() reflect.Value {
elemType := v.Type().Elem()
if elemType.Kind() == reflect.Ptr {
- elem := reflect.New(elemType.Elem())
- v.Set(reflect.Append(v, elem))
- return elem.Elem()
+ elemType = elemType.Elem()
+ return func() reflect.Value {
+ if v.Len() < v.Cap() {
+ v.Set(v.Slice(0, v.Len()+1))
+ elem := v.Index(v.Len() - 1)
+ if elem.IsNil() {
+ elem.Set(reflect.New(elemType))
+ }
+ return elem.Elem()
+ }
+
+ elem := reflect.New(elemType)
+ v.Set(reflect.Append(v, elem))
+ return elem.Elem()
+ }
}
- v.Set(reflect.Append(v, reflect.Zero(elemType)))
- return v.Index(v.Len() - 1)
+ zero := reflect.Zero(elemType)
+ return func() reflect.Value {
+ if v.Len() < v.Cap() {
+ v.Set(v.Slice(0, v.Len()+1))
+ return v.Index(v.Len() - 1)
+ }
+
+ v.Set(reflect.Append(v, zero))
+ return v.Index(v.Len() - 1)
+ }
}
diff --git a/vendor/github.com/go-redis/redis/pubsub.go b/vendor/github.com/go-redis/redis/pubsub.go
index e754a16f2..01f8a61aa 100644
--- a/vendor/github.com/go-redis/redis/pubsub.go
+++ b/vendor/github.com/go-redis/redis/pubsub.go
@@ -29,6 +29,9 @@ type PubSub struct {
closed bool
cmd *Cmd
+
+ chOnce sync.Once
+ ch chan *Message
}
func (c *PubSub) conn() (*pool.Conn, error) {
@@ -346,24 +349,27 @@ func (c *PubSub) receiveMessage(timeout time.Duration) (*Message, error) {
}
}
-// Channel returns a channel for concurrently receiving messages.
-// The channel is closed with PubSub.
+// Channel returns a Go channel for concurrently receiving messages.
+// The channel is closed with PubSub. Receive or ReceiveMessage APIs
+// can not be used after channel is created.
func (c *PubSub) Channel() <-chan *Message {
- ch := make(chan *Message, 100)
- go func() {
- for {
- msg, err := c.ReceiveMessage()
- if err != nil {
- if err == pool.ErrClosed {
- break
+ c.chOnce.Do(func() {
+ c.ch = make(chan *Message, 100)
+ go func() {
+ for {
+ msg, err := c.ReceiveMessage()
+ if err != nil {
+ if err == pool.ErrClosed {
+ break
+ }
+ continue
}
- continue
+ c.ch <- msg
}
- ch <- msg
- }
- close(ch)
- }()
- return ch
+ close(c.ch)
+ }()
+ })
+ return c.ch
}
func appendIfNotExists(ss []string, es ...string) []string {
diff --git a/vendor/github.com/go-redis/redis/pubsub_test.go b/vendor/github.com/go-redis/redis/pubsub_test.go
index 6fc04a198..6a85bd038 100644
--- a/vendor/github.com/go-redis/redis/pubsub_test.go
+++ b/vendor/github.com/go-redis/redis/pubsub_test.go
@@ -424,4 +424,20 @@ var _ = Describe("PubSub", func() {
wg.Wait()
})
+
+ It("handles big message payload", func() {
+ pubsub := client.Subscribe("mychannel")
+ defer pubsub.Close()
+
+ ch := pubsub.Channel()
+
+ bigVal := bigVal()
+ err := client.Publish("mychannel", bigVal).Err()
+ Expect(err).NotTo(HaveOccurred())
+
+ var msg *redis.Message
+ Eventually(ch).Should(Receive(&msg))
+ Expect(msg.Channel).To(Equal("mychannel"))
+ Expect(msg.Payload).To(Equal(string(bigVal)))
+ })
})
diff --git a/vendor/github.com/go-redis/redis/race_test.go b/vendor/github.com/go-redis/redis/race_test.go
index 5bcb0768e..14264086c 100644
--- a/vendor/github.com/go-redis/redis/race_test.go
+++ b/vendor/github.com/go-redis/redis/race_test.go
@@ -105,7 +105,7 @@ var _ = Describe("races", func() {
It("should handle big vals in Get", func() {
C, N = 4, 100
- bigVal := bytes.Repeat([]byte{'*'}, 1<<17) // 128kb
+ bigVal := bigVal()
err := client.Set("key", bigVal, 0).Err()
Expect(err).NotTo(HaveOccurred())
@@ -126,8 +126,7 @@ var _ = Describe("races", func() {
It("should handle big vals in Set", func() {
C, N = 4, 100
- bigVal := bytes.Repeat([]byte{'*'}, 1<<17) // 128kb
-
+ bigVal := bigVal()
perform(C, func(id int) {
for i := 0; i < N; i++ {
err := client.Set("key", bigVal, 0).Err()
@@ -245,3 +244,7 @@ var _ = Describe("races", func() {
Expect(n).To(Equal(int64(N)))
})
})
+
+func bigVal() []byte {
+ return bytes.Repeat([]byte{'*'}, 1<<17) // 128kb
+}
diff --git a/vendor/github.com/golang/protobuf/README.md b/vendor/github.com/golang/protobuf/README.md
index 207eb6b48..9c4c815c0 100644
--- a/vendor/github.com/golang/protobuf/README.md
+++ b/vendor/github.com/golang/protobuf/README.md
@@ -1,6 +1,7 @@
# Go support for Protocol Buffers
[![Build Status](https://travis-ci.org/golang/protobuf.svg?branch=master)](https://travis-ci.org/golang/protobuf)
+[![GoDoc](https://godoc.org/github.com/golang/protobuf?status.svg)](https://godoc.org/github.com/golang/protobuf)
Google's data interchange format.
Copyright 2010 The Go Authors.
diff --git a/vendor/github.com/gorilla/handlers/.travis.yml b/vendor/github.com/gorilla/handlers/.travis.yml
index 4ea1e7a1f..1ba74af10 100644
--- a/vendor/github.com/gorilla/handlers/.travis.yml
+++ b/vendor/github.com/gorilla/handlers/.travis.yml
@@ -7,6 +7,7 @@ matrix:
- go: 1.5
- go: 1.6
- go: 1.7
+ - go: 1.8
- go: tip
allow_failures:
- go: tip
@@ -16,3 +17,4 @@ script:
- diff -u <(echo -n) <(gofmt -d .)
- go vet $(go list ./... | grep -v /vendor/)
- go test -v -race ./...
+
diff --git a/vendor/github.com/gorilla/handlers/cors.go b/vendor/github.com/gorilla/handlers/cors.go
index 1f92d1ad4..1cf7581ce 100644
--- a/vendor/github.com/gorilla/handlers/cors.go
+++ b/vendor/github.com/gorilla/handlers/cors.go
@@ -110,7 +110,17 @@ func (ch *cors) ServeHTTP(w http.ResponseWriter, r *http.Request) {
w.Header().Set(corsVaryHeader, corsOriginHeader)
}
- w.Header().Set(corsAllowOriginHeader, origin)
+ returnOrigin := origin
+ for _, o := range ch.allowedOrigins {
+ // A configuration of * is different than explicitly setting an allowed
+ // origin. Returning arbitrary origin headers an an access control allow
+ // origin header is unsafe and is not required by any use case.
+ if o == corsOriginMatchAll {
+ returnOrigin = "*"
+ break
+ }
+ }
+ w.Header().Set(corsAllowOriginHeader, returnOrigin)
if r.Method == corsOptionMethod {
return
diff --git a/vendor/github.com/gorilla/handlers/cors_test.go b/vendor/github.com/gorilla/handlers/cors_test.go
index c63913eee..61eb18f77 100644
--- a/vendor/github.com/gorilla/handlers/cors_test.go
+++ b/vendor/github.com/gorilla/handlers/cors_test.go
@@ -327,10 +327,45 @@ func TestCORSHandlerWithCustomValidator(t *testing.T) {
return false
}
- CORS(AllowedOriginValidator(originValidator))(testHandler).ServeHTTP(rr, r)
+ // Specially craft a CORS object.
+ handleFunc := func(h http.Handler) http.Handler {
+ c := &cors{
+ allowedMethods: defaultCorsMethods,
+ allowedHeaders: defaultCorsHeaders,
+ allowedOrigins: []string{"http://a.example.com"},
+ h: h,
+ }
+ AllowedOriginValidator(originValidator)(c)
+ return c
+ }
+
+ handleFunc(testHandler).ServeHTTP(rr, r)
header := rr.HeaderMap.Get(corsAllowOriginHeader)
if header != r.URL.String() {
t.Fatalf("bad header: expected %s to be %s, got %s.", corsAllowOriginHeader, r.URL.String(), header)
}
}
+
+func TestCORSAllowStar(t *testing.T) {
+ r := newRequest("GET", "http://a.example.com")
+ r.Header.Set("Origin", r.URL.String())
+ rr := httptest.NewRecorder()
+
+ testHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
+ originValidator := func(origin string) bool {
+ if strings.HasSuffix(origin, ".example.com") {
+ return true
+ }
+ return false
+ }
+
+ CORS(AllowedOriginValidator(originValidator))(testHandler).ServeHTTP(rr, r)
+ header := rr.HeaderMap.Get(corsAllowOriginHeader)
+ // Because * is the default CORS policy (which is safe), we should be
+ // expect a * returned here as the Access Control Allow Origin header
+ if header != "*" {
+ t.Fatalf("bad header: expected %s to be %s, got %s.", corsAllowOriginHeader, r.URL.String(), header)
+ }
+
+}
diff --git a/vendor/github.com/gorilla/mux/.travis.yml b/vendor/github.com/gorilla/mux/.travis.yml
index ca377e61c..3302233f3 100644
--- a/vendor/github.com/gorilla/mux/.travis.yml
+++ b/vendor/github.com/gorilla/mux/.travis.yml
@@ -3,13 +3,13 @@ sudo: false
matrix:
include:
- - go: 1.2
- - go: 1.3
- - go: 1.4
- go: 1.5
- go: 1.6
- go: 1.7
- go: 1.8
+ - go: 1.9
+ - go: tip
+ allow_failures:
- go: tip
install:
diff --git a/vendor/github.com/gorilla/mux/README.md b/vendor/github.com/gorilla/mux/README.md
index 8dcd71887..67a79e00a 100644
--- a/vendor/github.com/gorilla/mux/README.md
+++ b/vendor/github.com/gorilla/mux/README.md
@@ -135,6 +135,14 @@ r.HandleFunc("/products", ProductsHandler).
Schemes("http")
```
+Routes are tested in the order they were added to the router. If two routes match, the first one wins:
+
+```go
+r := mux.NewRouter()
+r.HandleFunc("/specific", specificHandler)
+r.PathPrefix("/").Handler(catchAllHandler)
+```
+
Setting the same matching conditions again and again can be boring, so we have a way to group several routes that share the same requirements. We call it "subrouting".
For example, let's say we have several URLs that should only match when the host is `www.example.com`. Create a route for that host and get a "subrouter" from it:
@@ -193,22 +201,34 @@ func main() {
r.HandleFunc("/products", handler).Methods("POST")
r.HandleFunc("/articles", handler).Methods("GET")
r.HandleFunc("/articles/{id}", handler).Methods("GET", "PUT")
+ r.HandleFunc("/authors", handler).Queries("surname", "{surname}")
r.Walk(func(route *mux.Route, router *mux.Router, ancestors []*mux.Route) error {
t, err := route.GetPathTemplate()
if err != nil {
return err
}
+ qt, err := route.GetQueriesTemplates()
+ if err != nil {
+ return err
+ }
// p will contain regular expression is compatible with regular expression in Perl, Python, and other languages.
// for instance the regular expression for path '/articles/{id}' will be '^/articles/(?P<v0>[^/]+)$'
p, err := route.GetPathRegexp()
if err != nil {
return err
}
+ // qr will contain a list of regular expressions with the same semantics as GetPathRegexp,
+ // just applied to the Queries pairs instead, e.g., 'Queries("surname", "{surname}") will return
+ // {"^surname=(?P<v0>.*)$}. Where each combined query pair will have an entry in the list.
+ qr, err := route.GetQueriesRegexp()
+ if err != nil {
+ return err
+ }
m, err := route.GetMethods()
if err != nil {
return err
}
- fmt.Println(strings.Join(m, ","), t, p)
+ fmt.Println(strings.Join(m, ","), strings.Join(qt, ","), strings.Join(qr, ","), t, p)
return nil
})
http.Handle("/", r)
@@ -331,22 +351,34 @@ r.HandleFunc("/", handler)
r.HandleFunc("/products", handler).Methods("POST")
r.HandleFunc("/articles", handler).Methods("GET")
r.HandleFunc("/articles/{id}", handler).Methods("GET", "PUT")
+r.HandleFunc("/authors", handler).Queries("surname", "{surname}")
r.Walk(func(route *mux.Route, router *mux.Router, ancestors []*mux.Route) error {
t, err := route.GetPathTemplate()
if err != nil {
return err
}
+ qt, err := route.GetQueriesTemplates()
+ if err != nil {
+ return err
+ }
// p will contain a regular expression that is compatible with regular expressions in Perl, Python, and other languages.
// For example, the regular expression for path '/articles/{id}' will be '^/articles/(?P<v0>[^/]+)$'.
p, err := route.GetPathRegexp()
if err != nil {
return err
}
+ // qr will contain a list of regular expressions with the same semantics as GetPathRegexp,
+ // just applied to the Queries pairs instead, e.g., 'Queries("surname", "{surname}") will return
+ // {"^surname=(?P<v0>.*)$}. Where each combined query pair will have an entry in the list.
+ qr, err := route.GetQueriesRegexp()
+ if err != nil {
+ return err
+ }
m, err := route.GetMethods()
if err != nil {
return err
}
- fmt.Println(strings.Join(m, ","), t, p)
+ fmt.Println(strings.Join(m, ","), strings.Join(qt, ","), strings.Join(qr, ","), t, p)
return nil
})
```
diff --git a/vendor/github.com/gorilla/mux/mux.go b/vendor/github.com/gorilla/mux/mux.go
index fb69196db..49de78923 100644
--- a/vendor/github.com/gorilla/mux/mux.go
+++ b/vendor/github.com/gorilla/mux/mux.go
@@ -10,11 +10,11 @@ import (
"net/http"
"path"
"regexp"
- "strings"
)
var (
ErrMethodMismatch = errors.New("method is not allowed")
+ ErrNotFound = errors.New("no matching route was found")
)
// NewRouter returns a new router instance.
@@ -65,7 +65,17 @@ type Router struct {
useEncodedPath bool
}
-// Match matches registered routes against the request.
+// Match attempts to match the given request against the router's registered routes.
+//
+// If the request matches a route of this router or one of its subrouters the Route,
+// Handler, and Vars fields of the the match argument are filled and this function
+// returns true.
+//
+// If the request does not match any of this router's or its subrouters' routes
+// then this function returns false. If available, a reason for the match failure
+// will be filled in the match argument's MatchErr field. If the match failure type
+// (eg: not found) has a registered handler, the handler is assigned to the Handler
+// field of the match argument.
func (r *Router) Match(req *http.Request, match *RouteMatch) bool {
for _, route := range r.routes {
if route.Match(req, match) {
@@ -73,16 +83,23 @@ func (r *Router) Match(req *http.Request, match *RouteMatch) bool {
}
}
- if match.MatchErr == ErrMethodMismatch && r.MethodNotAllowedHandler != nil {
- match.Handler = r.MethodNotAllowedHandler
- return true
+ if match.MatchErr == ErrMethodMismatch {
+ if r.MethodNotAllowedHandler != nil {
+ match.Handler = r.MethodNotAllowedHandler
+ return true
+ } else {
+ return false
+ }
}
// Closest match for a router (includes sub-routers)
if r.NotFoundHandler != nil {
match.Handler = r.NotFoundHandler
+ match.MatchErr = ErrNotFound
return true
}
+
+ match.MatchErr = ErrNotFound
return false
}
@@ -94,7 +111,7 @@ func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
if !r.skipClean {
path := req.URL.Path
if r.useEncodedPath {
- path = getPath(req)
+ path = req.URL.EscapedPath()
}
// Clean path to canonical form and redirect.
if p := cleanPath(path); p != path {
@@ -409,28 +426,6 @@ func setCurrentRoute(r *http.Request, val interface{}) *http.Request {
// Helpers
// ----------------------------------------------------------------------------
-// getPath returns the escaped path if possible; doing what URL.EscapedPath()
-// which was added in go1.5 does
-func getPath(req *http.Request) string {
- if req.RequestURI != "" {
- // Extract the path from RequestURI (which is escaped unlike URL.Path)
- // as detailed here as detailed in https://golang.org/pkg/net/url/#URL
- // for < 1.5 server side workaround
- // http://localhost/path/here?v=1 -> /path/here
- path := req.RequestURI
- path = strings.TrimPrefix(path, req.URL.Scheme+`://`)
- path = strings.TrimPrefix(path, req.URL.Host)
- if i := strings.LastIndex(path, "?"); i > -1 {
- path = path[:i]
- }
- if i := strings.LastIndex(path, "#"); i > -1 {
- path = path[:i]
- }
- return path
- }
- return req.URL.Path
-}
-
// cleanPath returns the canonical path for p, eliminating . and .. elements.
// Borrowed from the net/http package.
func cleanPath(p string) string {
diff --git a/vendor/github.com/gorilla/mux/mux_test.go b/vendor/github.com/gorilla/mux/mux_test.go
index 484fab431..6c7e30d19 100644
--- a/vendor/github.com/gorilla/mux/mux_test.go
+++ b/vendor/github.com/gorilla/mux/mux_test.go
@@ -29,20 +29,22 @@ func (r *routeRegexp) GoString() string {
}
type routeTest struct {
- title string // title of the test
- route *Route // the route being tested
- request *http.Request // a request to test the route
- vars map[string]string // the expected vars of the match
- scheme string // the expected scheme of the built URL
- host string // the expected host of the built URL
- path string // the expected path of the built URL
- query string // the expected query string of the built URL
- pathTemplate string // the expected path template of the route
- hostTemplate string // the expected host template of the route
- methods []string // the expected route methods
- pathRegexp string // the expected path regexp
- shouldMatch bool // whether the request is expected to match the route at all
- shouldRedirect bool // whether the request should result in a redirect
+ title string // title of the test
+ route *Route // the route being tested
+ request *http.Request // a request to test the route
+ vars map[string]string // the expected vars of the match
+ scheme string // the expected scheme of the built URL
+ host string // the expected host of the built URL
+ path string // the expected path of the built URL
+ query string // the expected query string of the built URL
+ pathTemplate string // the expected path template of the route
+ hostTemplate string // the expected host template of the route
+ queriesTemplate string // the expected query template of the route
+ methods []string // the expected route methods
+ pathRegexp string // the expected path regexp
+ queriesRegexp string // the expected query regexp
+ shouldMatch bool // whether the request is expected to match the route at all
+ shouldRedirect bool // whether the request should result in a redirect
}
func TestHost(t *testing.T) {
@@ -739,257 +741,309 @@ func TestMethods(t *testing.T) {
func TestQueries(t *testing.T) {
tests := []routeTest{
{
- title: "Queries route, match",
- route: new(Route).Queries("foo", "bar", "baz", "ding"),
- request: newRequest("GET", "http://localhost?foo=bar&baz=ding"),
- vars: map[string]string{},
- host: "",
- path: "",
- query: "foo=bar&baz=ding",
- shouldMatch: true,
- },
- {
- title: "Queries route, match with a query string",
- route: new(Route).Host("www.example.com").Path("/api").Queries("foo", "bar", "baz", "ding"),
- request: newRequest("GET", "http://www.example.com/api?foo=bar&baz=ding"),
- vars: map[string]string{},
- host: "",
- path: "",
- query: "foo=bar&baz=ding",
- pathTemplate: `/api`,
- hostTemplate: `www.example.com`,
- shouldMatch: true,
- },
- {
- title: "Queries route, match with a query string out of order",
- route: new(Route).Host("www.example.com").Path("/api").Queries("foo", "bar", "baz", "ding"),
- request: newRequest("GET", "http://www.example.com/api?baz=ding&foo=bar"),
- vars: map[string]string{},
- host: "",
- path: "",
- query: "foo=bar&baz=ding",
- pathTemplate: `/api`,
- hostTemplate: `www.example.com`,
- shouldMatch: true,
- },
- {
- title: "Queries route, bad query",
- route: new(Route).Queries("foo", "bar", "baz", "ding"),
- request: newRequest("GET", "http://localhost?foo=bar&baz=dong"),
- vars: map[string]string{},
- host: "",
- path: "",
- shouldMatch: false,
- },
- {
- title: "Queries route with pattern, match",
- route: new(Route).Queries("foo", "{v1}"),
- request: newRequest("GET", "http://localhost?foo=bar"),
- vars: map[string]string{"v1": "bar"},
- host: "",
- path: "",
- query: "foo=bar",
- shouldMatch: true,
- },
- {
- title: "Queries route with multiple patterns, match",
- route: new(Route).Queries("foo", "{v1}", "baz", "{v2}"),
- request: newRequest("GET", "http://localhost?foo=bar&baz=ding"),
- vars: map[string]string{"v1": "bar", "v2": "ding"},
- host: "",
- path: "",
- query: "foo=bar&baz=ding",
- shouldMatch: true,
- },
- {
- title: "Queries route with regexp pattern, match",
- route: new(Route).Queries("foo", "{v1:[0-9]+}"),
- request: newRequest("GET", "http://localhost?foo=10"),
- vars: map[string]string{"v1": "10"},
- host: "",
- path: "",
- query: "foo=10",
- shouldMatch: true,
- },
- {
- title: "Queries route with regexp pattern, regexp does not match",
- route: new(Route).Queries("foo", "{v1:[0-9]+}"),
- request: newRequest("GET", "http://localhost?foo=a"),
- vars: map[string]string{},
- host: "",
- path: "",
- shouldMatch: false,
- },
- {
- title: "Queries route with regexp pattern with quantifier, match",
- route: new(Route).Queries("foo", "{v1:[0-9]{1}}"),
- request: newRequest("GET", "http://localhost?foo=1"),
- vars: map[string]string{"v1": "1"},
- host: "",
- path: "",
- query: "foo=1",
- shouldMatch: true,
- },
- {
- title: "Queries route with regexp pattern with quantifier, additional variable in query string, match",
- route: new(Route).Queries("foo", "{v1:[0-9]{1}}"),
- request: newRequest("GET", "http://localhost?bar=2&foo=1"),
- vars: map[string]string{"v1": "1"},
- host: "",
- path: "",
- query: "foo=1",
- shouldMatch: true,
- },
- {
- title: "Queries route with regexp pattern with quantifier, regexp does not match",
- route: new(Route).Queries("foo", "{v1:[0-9]{1}}"),
- request: newRequest("GET", "http://localhost?foo=12"),
- vars: map[string]string{},
- host: "",
- path: "",
- shouldMatch: false,
- },
- {
- title: "Queries route with regexp pattern with quantifier, additional capturing group",
- route: new(Route).Queries("foo", "{v1:[0-9]{1}(?:a|b)}"),
- request: newRequest("GET", "http://localhost?foo=1a"),
- vars: map[string]string{"v1": "1a"},
- host: "",
- path: "",
- query: "foo=1a",
- shouldMatch: true,
- },
- {
- title: "Queries route with regexp pattern with quantifier, additional variable in query string, regexp does not match",
- route: new(Route).Queries("foo", "{v1:[0-9]{1}}"),
- request: newRequest("GET", "http://localhost?foo=12"),
- vars: map[string]string{},
- host: "",
- path: "",
- shouldMatch: false,
- },
- {
- title: "Queries route with hyphenated name, match",
- route: new(Route).Queries("foo", "{v-1}"),
- request: newRequest("GET", "http://localhost?foo=bar"),
- vars: map[string]string{"v-1": "bar"},
- host: "",
- path: "",
- query: "foo=bar",
- shouldMatch: true,
- },
- {
- title: "Queries route with multiple hyphenated names, match",
- route: new(Route).Queries("foo", "{v-1}", "baz", "{v-2}"),
- request: newRequest("GET", "http://localhost?foo=bar&baz=ding"),
- vars: map[string]string{"v-1": "bar", "v-2": "ding"},
- host: "",
- path: "",
- query: "foo=bar&baz=ding",
- shouldMatch: true,
- },
- {
- title: "Queries route with hyphenate name and pattern, match",
- route: new(Route).Queries("foo", "{v-1:[0-9]+}"),
- request: newRequest("GET", "http://localhost?foo=10"),
- vars: map[string]string{"v-1": "10"},
- host: "",
- path: "",
- query: "foo=10",
- shouldMatch: true,
- },
- {
- title: "Queries route with hyphenated name and pattern with quantifier, additional capturing group",
- route: new(Route).Queries("foo", "{v-1:[0-9]{1}(?:a|b)}"),
- request: newRequest("GET", "http://localhost?foo=1a"),
- vars: map[string]string{"v-1": "1a"},
- host: "",
- path: "",
- query: "foo=1a",
- shouldMatch: true,
- },
- {
- title: "Queries route with empty value, should match",
- route: new(Route).Queries("foo", ""),
- request: newRequest("GET", "http://localhost?foo=bar"),
- vars: map[string]string{},
- host: "",
- path: "",
- query: "foo=",
- shouldMatch: true,
- },
- {
- title: "Queries route with empty value and no parameter in request, should not match",
- route: new(Route).Queries("foo", ""),
- request: newRequest("GET", "http://localhost"),
- vars: map[string]string{},
- host: "",
- path: "",
- shouldMatch: false,
- },
- {
- title: "Queries route with empty value and empty parameter in request, should match",
- route: new(Route).Queries("foo", ""),
- request: newRequest("GET", "http://localhost?foo="),
- vars: map[string]string{},
- host: "",
- path: "",
- query: "foo=",
- shouldMatch: true,
- },
- {
- title: "Queries route with overlapping value, should not match",
- route: new(Route).Queries("foo", "bar"),
- request: newRequest("GET", "http://localhost?foo=barfoo"),
- vars: map[string]string{},
- host: "",
- path: "",
- shouldMatch: false,
- },
- {
- title: "Queries route with no parameter in request, should not match",
- route: new(Route).Queries("foo", "{bar}"),
- request: newRequest("GET", "http://localhost"),
- vars: map[string]string{},
- host: "",
- path: "",
- shouldMatch: false,
- },
- {
- title: "Queries route with empty parameter in request, should match",
- route: new(Route).Queries("foo", "{bar}"),
- request: newRequest("GET", "http://localhost?foo="),
- vars: map[string]string{"foo": ""},
- host: "",
- path: "",
- query: "foo=",
- shouldMatch: true,
- },
- {
- title: "Queries route, bad submatch",
- route: new(Route).Queries("foo", "bar", "baz", "ding"),
- request: newRequest("GET", "http://localhost?fffoo=bar&baz=dingggg"),
- vars: map[string]string{},
- host: "",
- path: "",
- shouldMatch: false,
- },
- {
- title: "Queries route with pattern, match, escaped value",
- route: new(Route).Queries("foo", "{v1}"),
- request: newRequest("GET", "http://localhost?foo=%25bar%26%20%2F%3D%3F"),
- vars: map[string]string{"v1": "%bar& /=?"},
- host: "",
- path: "",
- query: "foo=%25bar%26+%2F%3D%3F",
- shouldMatch: true,
+ title: "Queries route, match",
+ route: new(Route).Queries("foo", "bar", "baz", "ding"),
+ request: newRequest("GET", "http://localhost?foo=bar&baz=ding"),
+ vars: map[string]string{},
+ host: "",
+ path: "",
+ query: "foo=bar&baz=ding",
+ queriesTemplate: "foo=bar,baz=ding",
+ queriesRegexp: "^foo=bar$,^baz=ding$",
+ shouldMatch: true,
+ },
+ {
+ title: "Queries route, match with a query string",
+ route: new(Route).Host("www.example.com").Path("/api").Queries("foo", "bar", "baz", "ding"),
+ request: newRequest("GET", "http://www.example.com/api?foo=bar&baz=ding"),
+ vars: map[string]string{},
+ host: "",
+ path: "",
+ query: "foo=bar&baz=ding",
+ pathTemplate: `/api`,
+ hostTemplate: `www.example.com`,
+ queriesTemplate: "foo=bar,baz=ding",
+ queriesRegexp: "^foo=bar$,^baz=ding$",
+ shouldMatch: true,
+ },
+ {
+ title: "Queries route, match with a query string out of order",
+ route: new(Route).Host("www.example.com").Path("/api").Queries("foo", "bar", "baz", "ding"),
+ request: newRequest("GET", "http://www.example.com/api?baz=ding&foo=bar"),
+ vars: map[string]string{},
+ host: "",
+ path: "",
+ query: "foo=bar&baz=ding",
+ pathTemplate: `/api`,
+ hostTemplate: `www.example.com`,
+ queriesTemplate: "foo=bar,baz=ding",
+ queriesRegexp: "^foo=bar$,^baz=ding$",
+ shouldMatch: true,
+ },
+ {
+ title: "Queries route, bad query",
+ route: new(Route).Queries("foo", "bar", "baz", "ding"),
+ request: newRequest("GET", "http://localhost?foo=bar&baz=dong"),
+ vars: map[string]string{},
+ host: "",
+ path: "",
+ queriesTemplate: "foo=bar,baz=ding",
+ queriesRegexp: "^foo=bar$,^baz=ding$",
+ shouldMatch: false,
+ },
+ {
+ title: "Queries route with pattern, match",
+ route: new(Route).Queries("foo", "{v1}"),
+ request: newRequest("GET", "http://localhost?foo=bar"),
+ vars: map[string]string{"v1": "bar"},
+ host: "",
+ path: "",
+ query: "foo=bar",
+ queriesTemplate: "foo={v1}",
+ queriesRegexp: "^foo=(?P<v0>.*)$",
+ shouldMatch: true,
+ },
+ {
+ title: "Queries route with multiple patterns, match",
+ route: new(Route).Queries("foo", "{v1}", "baz", "{v2}"),
+ request: newRequest("GET", "http://localhost?foo=bar&baz=ding"),
+ vars: map[string]string{"v1": "bar", "v2": "ding"},
+ host: "",
+ path: "",
+ query: "foo=bar&baz=ding",
+ queriesTemplate: "foo={v1},baz={v2}",
+ queriesRegexp: "^foo=(?P<v0>.*)$,^baz=(?P<v0>.*)$",
+ shouldMatch: true,
+ },
+ {
+ title: "Queries route with regexp pattern, match",
+ route: new(Route).Queries("foo", "{v1:[0-9]+}"),
+ request: newRequest("GET", "http://localhost?foo=10"),
+ vars: map[string]string{"v1": "10"},
+ host: "",
+ path: "",
+ query: "foo=10",
+ queriesTemplate: "foo={v1:[0-9]+}",
+ queriesRegexp: "^foo=(?P<v0>[0-9]+)$",
+ shouldMatch: true,
+ },
+ {
+ title: "Queries route with regexp pattern, regexp does not match",
+ route: new(Route).Queries("foo", "{v1:[0-9]+}"),
+ request: newRequest("GET", "http://localhost?foo=a"),
+ vars: map[string]string{},
+ host: "",
+ path: "",
+ queriesTemplate: "foo={v1:[0-9]+}",
+ queriesRegexp: "^foo=(?P<v0>[0-9]+)$",
+ shouldMatch: false,
+ },
+ {
+ title: "Queries route with regexp pattern with quantifier, match",
+ route: new(Route).Queries("foo", "{v1:[0-9]{1}}"),
+ request: newRequest("GET", "http://localhost?foo=1"),
+ vars: map[string]string{"v1": "1"},
+ host: "",
+ path: "",
+ query: "foo=1",
+ queriesTemplate: "foo={v1:[0-9]{1}}",
+ queriesRegexp: "^foo=(?P<v0>[0-9]{1})$",
+ shouldMatch: true,
+ },
+ {
+ title: "Queries route with regexp pattern with quantifier, additional variable in query string, match",
+ route: new(Route).Queries("foo", "{v1:[0-9]{1}}"),
+ request: newRequest("GET", "http://localhost?bar=2&foo=1"),
+ vars: map[string]string{"v1": "1"},
+ host: "",
+ path: "",
+ query: "foo=1",
+ queriesTemplate: "foo={v1:[0-9]{1}}",
+ queriesRegexp: "^foo=(?P<v0>[0-9]{1})$",
+ shouldMatch: true,
+ },
+ {
+ title: "Queries route with regexp pattern with quantifier, regexp does not match",
+ route: new(Route).Queries("foo", "{v1:[0-9]{1}}"),
+ request: newRequest("GET", "http://localhost?foo=12"),
+ vars: map[string]string{},
+ host: "",
+ path: "",
+ queriesTemplate: "foo={v1:[0-9]{1}}",
+ queriesRegexp: "^foo=(?P<v0>[0-9]{1})$",
+ shouldMatch: false,
+ },
+ {
+ title: "Queries route with regexp pattern with quantifier, additional capturing group",
+ route: new(Route).Queries("foo", "{v1:[0-9]{1}(?:a|b)}"),
+ request: newRequest("GET", "http://localhost?foo=1a"),
+ vars: map[string]string{"v1": "1a"},
+ host: "",
+ path: "",
+ query: "foo=1a",
+ queriesTemplate: "foo={v1:[0-9]{1}(?:a|b)}",
+ queriesRegexp: "^foo=(?P<v0>[0-9]{1}(?:a|b))$",
+ shouldMatch: true,
+ },
+ {
+ title: "Queries route with regexp pattern with quantifier, additional variable in query string, regexp does not match",
+ route: new(Route).Queries("foo", "{v1:[0-9]{1}}"),
+ request: newRequest("GET", "http://localhost?foo=12"),
+ vars: map[string]string{},
+ host: "",
+ path: "",
+ queriesTemplate: "foo={v1:[0-9]{1}}",
+ queriesRegexp: "^foo=(?P<v0>[0-9]{1})$",
+ shouldMatch: false,
+ },
+ {
+ title: "Queries route with hyphenated name, match",
+ route: new(Route).Queries("foo", "{v-1}"),
+ request: newRequest("GET", "http://localhost?foo=bar"),
+ vars: map[string]string{"v-1": "bar"},
+ host: "",
+ path: "",
+ query: "foo=bar",
+ queriesTemplate: "foo={v-1}",
+ queriesRegexp: "^foo=(?P<v0>.*)$",
+ shouldMatch: true,
+ },
+ {
+ title: "Queries route with multiple hyphenated names, match",
+ route: new(Route).Queries("foo", "{v-1}", "baz", "{v-2}"),
+ request: newRequest("GET", "http://localhost?foo=bar&baz=ding"),
+ vars: map[string]string{"v-1": "bar", "v-2": "ding"},
+ host: "",
+ path: "",
+ query: "foo=bar&baz=ding",
+ queriesTemplate: "foo={v-1},baz={v-2}",
+ queriesRegexp: "^foo=(?P<v0>.*)$,^baz=(?P<v0>.*)$",
+ shouldMatch: true,
+ },
+ {
+ title: "Queries route with hyphenate name and pattern, match",
+ route: new(Route).Queries("foo", "{v-1:[0-9]+}"),
+ request: newRequest("GET", "http://localhost?foo=10"),
+ vars: map[string]string{"v-1": "10"},
+ host: "",
+ path: "",
+ query: "foo=10",
+ queriesTemplate: "foo={v-1:[0-9]+}",
+ queriesRegexp: "^foo=(?P<v0>[0-9]+)$",
+ shouldMatch: true,
+ },
+ {
+ title: "Queries route with hyphenated name and pattern with quantifier, additional capturing group",
+ route: new(Route).Queries("foo", "{v-1:[0-9]{1}(?:a|b)}"),
+ request: newRequest("GET", "http://localhost?foo=1a"),
+ vars: map[string]string{"v-1": "1a"},
+ host: "",
+ path: "",
+ query: "foo=1a",
+ queriesTemplate: "foo={v-1:[0-9]{1}(?:a|b)}",
+ queriesRegexp: "^foo=(?P<v0>[0-9]{1}(?:a|b))$",
+ shouldMatch: true,
+ },
+ {
+ title: "Queries route with empty value, should match",
+ route: new(Route).Queries("foo", ""),
+ request: newRequest("GET", "http://localhost?foo=bar"),
+ vars: map[string]string{},
+ host: "",
+ path: "",
+ query: "foo=",
+ queriesTemplate: "foo=",
+ queriesRegexp: "^foo=.*$",
+ shouldMatch: true,
+ },
+ {
+ title: "Queries route with empty value and no parameter in request, should not match",
+ route: new(Route).Queries("foo", ""),
+ request: newRequest("GET", "http://localhost"),
+ vars: map[string]string{},
+ host: "",
+ path: "",
+ queriesTemplate: "foo=",
+ queriesRegexp: "^foo=.*$",
+ shouldMatch: false,
+ },
+ {
+ title: "Queries route with empty value and empty parameter in request, should match",
+ route: new(Route).Queries("foo", ""),
+ request: newRequest("GET", "http://localhost?foo="),
+ vars: map[string]string{},
+ host: "",
+ path: "",
+ query: "foo=",
+ queriesTemplate: "foo=",
+ queriesRegexp: "^foo=.*$",
+ shouldMatch: true,
+ },
+ {
+ title: "Queries route with overlapping value, should not match",
+ route: new(Route).Queries("foo", "bar"),
+ request: newRequest("GET", "http://localhost?foo=barfoo"),
+ vars: map[string]string{},
+ host: "",
+ path: "",
+ queriesTemplate: "foo=bar",
+ queriesRegexp: "^foo=bar$",
+ shouldMatch: false,
+ },
+ {
+ title: "Queries route with no parameter in request, should not match",
+ route: new(Route).Queries("foo", "{bar}"),
+ request: newRequest("GET", "http://localhost"),
+ vars: map[string]string{},
+ host: "",
+ path: "",
+ queriesTemplate: "foo={bar}",
+ queriesRegexp: "^foo=(?P<v0>.*)$",
+ shouldMatch: false,
+ },
+ {
+ title: "Queries route with empty parameter in request, should match",
+ route: new(Route).Queries("foo", "{bar}"),
+ request: newRequest("GET", "http://localhost?foo="),
+ vars: map[string]string{"foo": ""},
+ host: "",
+ path: "",
+ query: "foo=",
+ queriesTemplate: "foo={bar}",
+ queriesRegexp: "^foo=(?P<v0>.*)$",
+ shouldMatch: true,
+ },
+ {
+ title: "Queries route, bad submatch",
+ route: new(Route).Queries("foo", "bar", "baz", "ding"),
+ request: newRequest("GET", "http://localhost?fffoo=bar&baz=dingggg"),
+ vars: map[string]string{},
+ host: "",
+ path: "",
+ queriesTemplate: "foo=bar,baz=ding",
+ queriesRegexp: "^foo=bar$,^baz=ding$",
+ shouldMatch: false,
+ },
+ {
+ title: "Queries route with pattern, match, escaped value",
+ route: new(Route).Queries("foo", "{v1}"),
+ request: newRequest("GET", "http://localhost?foo=%25bar%26%20%2F%3D%3F"),
+ vars: map[string]string{"v1": "%bar& /=?"},
+ host: "",
+ path: "",
+ query: "foo=%25bar%26+%2F%3D%3F",
+ queriesTemplate: "foo={v1}",
+ queriesRegexp: "^foo=(?P<v0>.*)$",
+ shouldMatch: true,
},
}
for _, test := range tests {
testRoute(t, test)
testTemplate(t, test)
+ testQueriesTemplates(t, test)
testUseEscapedRoute(t, test)
+ testQueriesRegexp(t, test)
}
}
@@ -1717,20 +1771,38 @@ func testRegexp(t *testing.T, test routeTest) {
}
}
+func testQueriesRegexp(t *testing.T, test routeTest) {
+ route := test.route
+ queries, queriesErr := route.GetQueriesRegexp()
+ gotQueries := strings.Join(queries, ",")
+ if test.queriesRegexp != "" && queriesErr == nil && gotQueries != test.queriesRegexp {
+ t.Errorf("(%v) GetQueriesRegexp not equal: expected %v, got %v", test.title, test.queriesRegexp, gotQueries)
+ }
+}
+
+func testQueriesTemplates(t *testing.T, test routeTest) {
+ route := test.route
+ queries, queriesErr := route.GetQueriesTemplates()
+ gotQueries := strings.Join(queries, ",")
+ if test.queriesTemplate != "" && queriesErr == nil && gotQueries != test.queriesTemplate {
+ t.Errorf("(%v) GetQueriesTemplates not equal: expected %v, got %v", test.title, test.queriesTemplate, gotQueries)
+ }
+}
+
type TestA301ResponseWriter struct {
hh http.Header
status int
}
-func (ho TestA301ResponseWriter) Header() http.Header {
+func (ho *TestA301ResponseWriter) Header() http.Header {
return http.Header(ho.hh)
}
-func (ho TestA301ResponseWriter) Write(b []byte) (int, error) {
+func (ho *TestA301ResponseWriter) Write(b []byte) (int, error) {
return 0, nil
}
-func (ho TestA301ResponseWriter) WriteHeader(code int) {
+func (ho *TestA301ResponseWriter) WriteHeader(code int) {
ho.status = code
}
@@ -1805,6 +1877,96 @@ func TestSubrouterHeader(t *testing.T) {
}
}
+func TestNoMatchMethodErrorHandler(t *testing.T) {
+ func1 := func(w http.ResponseWriter, r *http.Request) {}
+
+ r := NewRouter()
+ r.HandleFunc("/", func1).Methods("GET", "POST")
+
+ req, _ := http.NewRequest("PUT", "http://localhost/", nil)
+ match := new(RouteMatch)
+ matched := r.Match(req, match)
+
+ if matched {
+ t.Error("Should not have matched route for methods")
+ }
+
+ if match.MatchErr != ErrMethodMismatch {
+ t.Error("Should get ErrMethodMismatch error")
+ }
+
+ resp := NewRecorder()
+ r.ServeHTTP(resp, req)
+ if resp.Code != 405 {
+ t.Errorf("Expecting code %v", 405)
+ }
+
+ // Add matching route
+ r.HandleFunc("/", func1).Methods("PUT")
+
+ match = new(RouteMatch)
+ matched = r.Match(req, match)
+
+ if !matched {
+ t.Error("Should have matched route for methods")
+ }
+
+ if match.MatchErr != nil {
+ t.Error("Should not have any matching error. Found:", match.MatchErr)
+ }
+}
+
+func TestErrMatchNotFound(t *testing.T) {
+ emptyHandler := func(w http.ResponseWriter, r *http.Request) {}
+
+ r := NewRouter()
+ r.HandleFunc("/", emptyHandler)
+ s := r.PathPrefix("/sub/").Subrouter()
+ s.HandleFunc("/", emptyHandler)
+
+ // Regular 404 not found
+ req, _ := http.NewRequest("GET", "/sub/whatever", nil)
+ match := new(RouteMatch)
+ matched := r.Match(req, match)
+
+ if matched {
+ t.Errorf("Subrouter should not have matched that, got %v", match.Route)
+ }
+ // Even without a custom handler, MatchErr is set to ErrNotFound
+ if match.MatchErr != ErrNotFound {
+ t.Errorf("Expected ErrNotFound MatchErr, but was %v", match.MatchErr)
+ }
+
+ // Now lets add a 404 handler to subrouter
+ s.NotFoundHandler = http.NotFoundHandler()
+ req, _ = http.NewRequest("GET", "/sub/whatever", nil)
+
+ // Test the subrouter first
+ match = new(RouteMatch)
+ matched = s.Match(req, match)
+ // Now we should get a match
+ if !matched {
+ t.Errorf("Subrouter should have matched %s", req.RequestURI)
+ }
+ // But MatchErr should be set to ErrNotFound anyway
+ if match.MatchErr != ErrNotFound {
+ t.Errorf("Expected ErrNotFound MatchErr, but was %v", match.MatchErr)
+ }
+
+ // Now test the parent (MatchErr should propagate)
+ match = new(RouteMatch)
+ matched = r.Match(req, match)
+
+ // Now we should get a match
+ if !matched {
+ t.Errorf("Router should have matched %s via subrouter", req.RequestURI)
+ }
+ // But MatchErr should be set to ErrNotFound anyway
+ if match.MatchErr != ErrNotFound {
+ t.Errorf("Expected ErrNotFound MatchErr, but was %v", match.MatchErr)
+ }
+}
+
// mapToPairs converts a string map to a slice of string pairs
func mapToPairs(m map[string]string) []string {
var i int
@@ -1871,42 +2033,3 @@ func newRequest(method, url string) *http.Request {
}
return req
}
-
-func TestNoMatchMethodErrorHandler(t *testing.T) {
- func1 := func(w http.ResponseWriter, r *http.Request) {}
-
- r := NewRouter()
- r.HandleFunc("/", func1).Methods("GET", "POST")
-
- req, _ := http.NewRequest("PUT", "http://localhost/", nil)
- match := new(RouteMatch)
- matched := r.Match(req, match)
-
- if matched {
- t.Error("Should not have matched route for methods")
- }
-
- if match.MatchErr != ErrMethodMismatch {
- t.Error("Should get ErrMethodMismatch error")
- }
-
- resp := NewRecorder()
- r.ServeHTTP(resp, req)
- if resp.Code != 405 {
- t.Errorf("Expecting code %v", 405)
- }
-
- // Add matching route
- r.HandleFunc("/", func1).Methods("PUT")
-
- match = new(RouteMatch)
- matched = r.Match(req, match)
-
- if !matched {
- t.Error("Should have matched route for methods")
- }
-
- if match.MatchErr != nil {
- t.Error("Should not have any matching error. Found:", match.MatchErr)
- }
-}
diff --git a/vendor/github.com/gorilla/mux/regexp.go b/vendor/github.com/gorilla/mux/regexp.go
index 80d1f7858..e83213b7d 100644
--- a/vendor/github.com/gorilla/mux/regexp.go
+++ b/vendor/github.com/gorilla/mux/regexp.go
@@ -141,7 +141,7 @@ type routeRegexp struct {
matchQuery bool
// The strictSlash value defined on the route, but disabled if PathPrefix was used.
strictSlash bool
- // Determines whether to use encoded path from getPath function or unencoded
+ // Determines whether to use encoded req.URL.EnscapedPath() or unencoded
// req.URL.Path for path matching
useEncodedPath bool
// Expanded regexp.
@@ -162,7 +162,7 @@ func (r *routeRegexp) Match(req *http.Request, match *RouteMatch) bool {
}
path := req.URL.Path
if r.useEncodedPath {
- path = getPath(req)
+ path = req.URL.EscapedPath()
}
return r.regexp.MatchString(path)
}
@@ -272,7 +272,7 @@ func (v *routeRegexpGroup) setMatch(req *http.Request, m *RouteMatch, r *Route)
}
path := req.URL.Path
if r.useEncodedPath {
- path = getPath(req)
+ path = req.URL.EscapedPath()
}
// Store path variables.
if v.path != nil {
diff --git a/vendor/github.com/gorilla/mux/route.go b/vendor/github.com/gorilla/mux/route.go
index 6863adba5..69aeae791 100644
--- a/vendor/github.com/gorilla/mux/route.go
+++ b/vendor/github.com/gorilla/mux/route.go
@@ -72,7 +72,11 @@ func (r *Route) Match(req *http.Request, match *RouteMatch) bool {
return false
}
- match.MatchErr = nil
+ if match.MatchErr == ErrMethodMismatch {
+ // We found a route which matches request method, clear MatchErr
+ match.MatchErr = nil
+ }
+
// Yay, we have a match. Let's collect some info about it.
if match.Route == nil {
match.Route = r
@@ -608,6 +612,44 @@ func (r *Route) GetPathRegexp() (string, error) {
return r.regexp.path.regexp.String(), nil
}
+// GetQueriesRegexp returns the expanded regular expressions used to match the
+// route queries.
+// This is useful for building simple REST API documentation and for instrumentation
+// against third-party services.
+// An empty list will be returned if the route does not have queries.
+func (r *Route) GetQueriesRegexp() ([]string, error) {
+ if r.err != nil {
+ return nil, r.err
+ }
+ if r.regexp == nil || r.regexp.queries == nil {
+ return nil, errors.New("mux: route doesn't have queries")
+ }
+ var queries []string
+ for _, query := range r.regexp.queries {
+ queries = append(queries, query.regexp.String())
+ }
+ return queries, nil
+}
+
+// GetQueriesTemplates returns the templates used to build the
+// query matching.
+// This is useful for building simple REST API documentation and for instrumentation
+// against third-party services.
+// An empty list will be returned if the route does not define queries.
+func (r *Route) GetQueriesTemplates() ([]string, error) {
+ if r.err != nil {
+ return nil, r.err
+ }
+ if r.regexp == nil || r.regexp.queries == nil {
+ return nil, errors.New("mux: route doesn't have queries")
+ }
+ var queries []string
+ for _, query := range r.regexp.queries {
+ queries = append(queries, query.template)
+ }
+ return queries, nil
+}
+
// GetMethods returns the methods the route matches against
// This is useful for building simple REST API documentation and for instrumentation
// against third-party services.
diff --git a/vendor/github.com/hashicorp/go-sockaddr/ifaddr_test.go b/vendor/github.com/hashicorp/go-sockaddr/ifaddr_test.go
index 859c3e421..45a0cc788 100644
--- a/vendor/github.com/hashicorp/go-sockaddr/ifaddr_test.go
+++ b/vendor/github.com/hashicorp/go-sockaddr/ifaddr_test.go
@@ -411,6 +411,114 @@ func TestIfAddrMath(t *testing.T) {
wantFail: true,
},
{
+ name: "ipv4 mask operand equals input ipv4 subnet mask",
+ ifAddr: sockaddr.IfAddr{
+ SockAddr: sockaddr.MustIPv4Addr("10.20.30.40/8"),
+ },
+ operation: "mask",
+ value: "8",
+ expected: "10.0.0.0/8",
+ },
+ {
+ name: "ipv4 mask operand larger than input ipv4 subnet mask",
+ ifAddr: sockaddr.IfAddr{
+ SockAddr: sockaddr.MustIPv4Addr("192.168.10.20/24"),
+ },
+ operation: "mask",
+ value: "16",
+ expected: "192.168.0.0/16",
+ },
+ {
+ name: "ipv4 host upper bound mask operand larger than input ipv4 subnet mask",
+ ifAddr: sockaddr.IfAddr{
+ SockAddr: sockaddr.MustIPv4Addr("192.168.255.255/24"),
+ },
+ operation: "mask",
+ value: "16",
+ expected: "192.168.0.0/16",
+ },
+ {
+ name: "ipv4 mask operand smaller than ipv4 subnet mask",
+ ifAddr: sockaddr.IfAddr{
+ SockAddr: sockaddr.MustIPv4Addr("10.20.30.40/8"),
+ },
+ operation: "mask",
+ value: "16",
+ expected: "10.20.0.0/8",
+ },
+ {
+ name: "ipv4 host upper bound mask operand smaller than input ipv4 subnet mask",
+ ifAddr: sockaddr.IfAddr{
+ SockAddr: sockaddr.MustIPv4Addr("10.20.255.255/8"),
+ },
+ operation: "mask",
+ value: "16",
+ expected: "10.20.0.0/8",
+ },
+ {
+ name: "ipv4 mask bad value upper bound",
+ ifAddr: sockaddr.IfAddr{
+ SockAddr: sockaddr.MustIPv4Addr("127.0.0.1/8"),
+ },
+ operation: "mask",
+ value: "33",
+ wantFail: true,
+ },
+ {
+ name: "ipv4 mask bad value lower bound",
+ ifAddr: sockaddr.IfAddr{
+ SockAddr: sockaddr.MustIPv4Addr("127.0.0.1/8"),
+ },
+ operation: "mask",
+ value: "-1",
+ wantFail: true,
+ },
+ {
+ name: "ipv6 mask operand equals input ipv6 subnet mask",
+ ifAddr: sockaddr.IfAddr{
+ SockAddr: sockaddr.MustIPv6Addr("2001:0db8:85a3::8a2e:0370:7334/64"),
+ },
+ operation: "mask",
+ value: "64",
+ expected: "2001:db8:85a3::/64",
+ },
+ {
+ name: "ipv6 mask operand larger than input ipv6 subnet mask",
+ ifAddr: sockaddr.IfAddr{
+ SockAddr: sockaddr.MustIPv6Addr("2001:0db8:85a3::8a2e:0370:7334/64"),
+ },
+ operation: "mask",
+ value: "32",
+ expected: "2001:db8::/32",
+ },
+ {
+ name: "ipv6 mask operand smaller than input ipv6 subnet mask",
+ ifAddr: sockaddr.IfAddr{
+ SockAddr: sockaddr.MustIPv6Addr("2001:0db8:85a3::8a2e:0370:7334/64"),
+ },
+ operation: "mask",
+ value: "96",
+ expected: "2001:db8:85a3::8a2e:0:0/64",
+ },
+ {
+ name: "ipv6 mask bad value upper bound",
+ ifAddr: sockaddr.IfAddr{
+ SockAddr: sockaddr.MustIPv6Addr("::1/128"),
+ },
+ operation: "mask",
+ value: "129",
+ wantFail: true,
+ },
+ {
+ name: "ipv6 mask bad value lower bound",
+ ifAddr: sockaddr.IfAddr{
+ SockAddr: sockaddr.MustIPv6Addr("::1/128"),
+ },
+ operation: "mask",
+ value: "-1",
+ wantFail: true,
+ },
+ {
name: "unix unsupported operation",
ifAddr: sockaddr.IfAddr{
SockAddr: sockaddr.MustUnixSock("/tmp/bar"),
@@ -428,6 +536,15 @@ func TestIfAddrMath(t *testing.T) {
value: "+123",
wantFail: true,
},
+ {
+ name: "unix unsupported operation",
+ ifAddr: sockaddr.IfAddr{
+ SockAddr: sockaddr.MustUnixSock("/tmp/foo"),
+ },
+ operation: "mask",
+ value: "8",
+ wantFail: true,
+ },
}
for i, test := range tests {
diff --git a/vendor/github.com/hashicorp/go-sockaddr/ifaddrs.go b/vendor/github.com/hashicorp/go-sockaddr/ifaddrs.go
index b87589a22..4b4e63808 100644
--- a/vendor/github.com/hashicorp/go-sockaddr/ifaddrs.go
+++ b/vendor/github.com/hashicorp/go-sockaddr/ifaddrs.go
@@ -1,6 +1,7 @@
package sockaddr
import (
+ "encoding/binary"
"errors"
"fmt"
"math/big"
@@ -866,6 +867,80 @@ func IfAddrMath(operation, value string, inputIfAddr IfAddr) (IfAddr, error) {
default:
return IfAddr{}, fmt.Errorf("unsupported type for operation %q: %T", operation, sockType)
}
+ case "mask":
+ // "mask" operates on the IP address and returns the IP address on
+ // which the given integer mask has been applied. If the applied mask
+ // corresponds to a larger network than the mask of the IP address,
+ // the latter will be replaced by the former.
+ switch sockType := inputIfAddr.SockAddr.Type(); sockType {
+ case TypeIPv4:
+ i, err := strconv.ParseUint(value, 10, 32)
+ if err != nil {
+ return IfAddr{}, fmt.Errorf("unable to convert %q to int for operation %q: %v", value, operation, err)
+ }
+
+ if i > 32 {
+ return IfAddr{}, fmt.Errorf("parameter for operation %q on ipv4 addresses must be between 0 and 32", operation)
+ }
+
+ ipv4 := *ToIPv4Addr(inputIfAddr.SockAddr)
+
+ ipv4Mask := net.CIDRMask(int(i), 32)
+ ipv4MaskUint32 := binary.BigEndian.Uint32(ipv4Mask)
+
+ maskedIpv4 := ipv4.NetIP().Mask(ipv4Mask)
+ maskedIpv4Uint32 := binary.BigEndian.Uint32(maskedIpv4)
+
+ maskedIpv4MaskUint32 := uint32(ipv4.Mask)
+
+ if ipv4MaskUint32 < maskedIpv4MaskUint32 {
+ maskedIpv4MaskUint32 = ipv4MaskUint32
+ }
+
+ return IfAddr{
+ SockAddr: IPv4Addr{
+ Address: IPv4Address(maskedIpv4Uint32),
+ Mask: IPv4Mask(maskedIpv4MaskUint32),
+ },
+ Interface: inputIfAddr.Interface,
+ }, nil
+ case TypeIPv6:
+ i, err := strconv.ParseUint(value, 10, 32)
+ if err != nil {
+ return IfAddr{}, fmt.Errorf("unable to convert %q to int for operation %q: %v", value, operation, err)
+ }
+
+ if i > 128 {
+ return IfAddr{}, fmt.Errorf("parameter for operation %q on ipv6 addresses must be between 0 and 64", operation)
+ }
+
+ ipv6 := *ToIPv6Addr(inputIfAddr.SockAddr)
+
+ ipv6Mask := net.CIDRMask(int(i), 128)
+ ipv6MaskBigInt := new(big.Int)
+ ipv6MaskBigInt.SetBytes(ipv6Mask)
+
+ maskedIpv6 := ipv6.NetIP().Mask(ipv6Mask)
+ maskedIpv6BigInt := new(big.Int)
+ maskedIpv6BigInt.SetBytes(maskedIpv6)
+
+ maskedIpv6MaskBigInt := new(big.Int)
+ maskedIpv6MaskBigInt.Set(ipv6.Mask)
+
+ if ipv6MaskBigInt.Cmp(maskedIpv6MaskBigInt) == -1 {
+ maskedIpv6MaskBigInt = ipv6MaskBigInt
+ }
+
+ return IfAddr{
+ SockAddr: IPv6Addr{
+ Address: IPv6Address(maskedIpv6BigInt),
+ Mask: IPv6Mask(maskedIpv6MaskBigInt),
+ },
+ Interface: inputIfAddr.Interface,
+ }, nil
+ default:
+ return IfAddr{}, fmt.Errorf("unsupported type for operation %q: %T", operation, sockType)
+ }
default:
return IfAddr{}, fmt.Errorf("unsupported math operation: %q", operation)
}
diff --git a/vendor/github.com/hashicorp/go-sockaddr/template/doc.go b/vendor/github.com/hashicorp/go-sockaddr/template/doc.go
index 90c8784a3..8cc6730a4 100644
--- a/vendor/github.com/hashicorp/go-sockaddr/template/doc.go
+++ b/vendor/github.com/hashicorp/go-sockaddr/template/doc.go
@@ -212,6 +212,13 @@ Supported operations include:
from the network's broadcast address (e.g. 127.0.0.1 `"network" "-1"` will
return "127.255.255.255"). Values that overflow the network size will
safely wrap.
+ - `mask`: Applies the given network mask to the address. The network mask is
+ expressed as a decimal value (e.g. network mask "24" corresponds to
+ `255.255.255.0`). After applying the network mask, the network mask of the
+ resulting address will be either the applied network mask or the network mask
+ of the input address depending on which network is larger
+ (e.g. 192.168.10.20/24 `"mask" "16"` will return "192.168.0.0/16" but
+ 192.168.10.20/24 `"mask" "28"` will return "192.168.10.16/24").
Example:
@@ -219,6 +226,7 @@ Example:
{{ GetPrivateInterfaces | include "type" "IP" | math "address" "-256" | attr "address" }}
{{ GetPrivateInterfaces | include "type" "IP" | math "network" "+2" | attr "address" }}
{{ GetPrivateInterfaces | include "type" "IP" | math "network" "-2" | attr "address" }}
+ {{ GetPrivateInterfaces | include "type" "IP" | math "mask" "24" | attr "address" }}
{{ GetPrivateInterfaces | include "flags" "forwardable|up" | include "type" "IPv4" | math "network" "+2" | attr "address" }}
diff --git a/vendor/github.com/hashicorp/hcl/.travis.yml b/vendor/github.com/hashicorp/hcl/.travis.yml
index 3f83d9023..cb63a3216 100644
--- a/vendor/github.com/hashicorp/hcl/.travis.yml
+++ b/vendor/github.com/hashicorp/hcl/.travis.yml
@@ -3,7 +3,8 @@ sudo: false
language: go
go:
- - 1.8
+ - 1.x
+ - tip
branches:
only:
diff --git a/vendor/github.com/hashicorp/hcl/decoder.go b/vendor/github.com/hashicorp/hcl/decoder.go
index b88f322a8..bed9ebbe1 100644
--- a/vendor/github.com/hashicorp/hcl/decoder.go
+++ b/vendor/github.com/hashicorp/hcl/decoder.go
@@ -573,7 +573,11 @@ func (d *decoder) decodeStruct(name string, node ast.Node, result reflect.Value)
// Compile the list of all the fields that we're going to be decoding
// from all the structs.
- fields := make(map[*reflect.StructField]reflect.Value)
+ type field struct {
+ field reflect.StructField
+ val reflect.Value
+ }
+ fields := []field{}
for len(structs) > 0 {
structVal := structs[0]
structs = structs[1:]
@@ -616,7 +620,7 @@ func (d *decoder) decodeStruct(name string, node ast.Node, result reflect.Value)
}
// Normal struct field, store it away
- fields[&fieldType] = structVal.Field(i)
+ fields = append(fields, field{fieldType, structVal.Field(i)})
}
}
@@ -624,26 +628,27 @@ func (d *decoder) decodeStruct(name string, node ast.Node, result reflect.Value)
decodedFields := make([]string, 0, len(fields))
decodedFieldsVal := make([]reflect.Value, 0)
unusedKeysVal := make([]reflect.Value, 0)
- for fieldType, field := range fields {
- if !field.IsValid() {
+ for _, f := range fields {
+ field, fieldValue := f.field, f.val
+ if !fieldValue.IsValid() {
// This should never happen
panic("field is not valid")
}
// If we can't set the field, then it is unexported or something,
// and we just continue onwards.
- if !field.CanSet() {
+ if !fieldValue.CanSet() {
continue
}
- fieldName := fieldType.Name
+ fieldName := field.Name
- tagValue := fieldType.Tag.Get(tagName)
+ tagValue := field.Tag.Get(tagName)
tagParts := strings.SplitN(tagValue, ",", 2)
if len(tagParts) >= 2 {
switch tagParts[1] {
case "decodedFields":
- decodedFieldsVal = append(decodedFieldsVal, field)
+ decodedFieldsVal = append(decodedFieldsVal, fieldValue)
continue
case "key":
if item == nil {
@@ -654,10 +659,10 @@ func (d *decoder) decodeStruct(name string, node ast.Node, result reflect.Value)
}
}
- field.SetString(item.Keys[0].Token.Value().(string))
+ fieldValue.SetString(item.Keys[0].Token.Value().(string))
continue
case "unusedKeys":
- unusedKeysVal = append(unusedKeysVal, field)
+ unusedKeysVal = append(unusedKeysVal, fieldValue)
continue
}
}
@@ -684,7 +689,7 @@ func (d *decoder) decodeStruct(name string, node ast.Node, result reflect.Value)
// because we actually want the value.
fieldName = fmt.Sprintf("%s.%s", name, fieldName)
if len(prefixMatches.Items) > 0 {
- if err := d.decode(fieldName, prefixMatches, field); err != nil {
+ if err := d.decode(fieldName, prefixMatches, fieldValue); err != nil {
return err
}
}
@@ -694,12 +699,12 @@ func (d *decoder) decodeStruct(name string, node ast.Node, result reflect.Value)
decodeNode = &ast.ObjectList{Items: ot.List.Items}
}
- if err := d.decode(fieldName, decodeNode, field); err != nil {
+ if err := d.decode(fieldName, decodeNode, fieldValue); err != nil {
return err
}
}
- decodedFields = append(decodedFields, fieldType.Name)
+ decodedFields = append(decodedFields, field.Name)
}
if len(decodedFieldsVal) > 0 {
diff --git a/vendor/github.com/hashicorp/hcl/hcl/scanner/scanner.go b/vendor/github.com/hashicorp/hcl/hcl/scanner/scanner.go
index 69662367f..6601ef76e 100644
--- a/vendor/github.com/hashicorp/hcl/hcl/scanner/scanner.go
+++ b/vendor/github.com/hashicorp/hcl/hcl/scanner/scanner.go
@@ -351,7 +351,7 @@ func (s *Scanner) scanNumber(ch rune) token.Type {
return token.NUMBER
}
-// scanMantissa scans the mantissa begining from the rune. It returns the next
+// scanMantissa scans the mantissa beginning from the rune. It returns the next
// non decimal rune. It's used to determine wheter it's a fraction or exponent.
func (s *Scanner) scanMantissa(ch rune) rune {
scanned := false
diff --git a/vendor/github.com/hashicorp/hcl/json/scanner/scanner.go b/vendor/github.com/hashicorp/hcl/json/scanner/scanner.go
index dd5c72bb3..fe3f0f095 100644
--- a/vendor/github.com/hashicorp/hcl/json/scanner/scanner.go
+++ b/vendor/github.com/hashicorp/hcl/json/scanner/scanner.go
@@ -246,7 +246,7 @@ func (s *Scanner) scanNumber(ch rune) token.Type {
return token.NUMBER
}
-// scanMantissa scans the mantissa begining from the rune. It returns the next
+// scanMantissa scans the mantissa beginning from the rune. It returns the next
// non decimal rune. It's used to determine wheter it's a fraction or exponent.
func (s *Scanner) scanMantissa(ch rune) rune {
scanned := false
diff --git a/vendor/github.com/hashicorp/memberlist/memberlist.go b/vendor/github.com/hashicorp/memberlist/memberlist.go
index e1e38fc94..bdf333b43 100644
--- a/vendor/github.com/hashicorp/memberlist/memberlist.go
+++ b/vendor/github.com/hashicorp/memberlist/memberlist.go
@@ -308,23 +308,17 @@ func (m *Memberlist) tcpLookupIP(host string, defaultPort uint16) ([]ipPort, err
// resolveAddr is used to resolve the address into an address,
// port, and error. If no port is given, use the default
func (m *Memberlist) resolveAddr(hostStr string) ([]ipPort, error) {
- // Normalize the incoming string to host:port so we can apply Go's
- // parser to it.
- port := uint16(0)
- if !hasPort(hostStr) {
- hostStr += ":" + strconv.Itoa(m.config.BindPort)
- }
+ // This captures the supplied port, or the default one.
+ hostStr = ensurePort(hostStr, m.config.BindPort)
host, sport, err := net.SplitHostPort(hostStr)
if err != nil {
return nil, err
}
-
- // This will capture the supplied port, or the default one added above.
lport, err := strconv.ParseUint(sport, 10, 16)
if err != nil {
return nil, err
}
- port = uint16(lport)
+ port := uint16(lport)
// If it looks like an IP address we are done. The SplitHostPort() above
// will make sure the host part is in good shape for parsing, even for
diff --git a/vendor/github.com/hashicorp/memberlist/memberlist_test.go b/vendor/github.com/hashicorp/memberlist/memberlist_test.go
index ecda7fb55..ee2fc5d52 100644
--- a/vendor/github.com/hashicorp/memberlist/memberlist_test.go
+++ b/vendor/github.com/hashicorp/memberlist/memberlist_test.go
@@ -424,7 +424,7 @@ func TestMemberList_ResolveAddr_TCP_First(t *testing.T) {
}
port := uint16(m.config.BindPort)
expected := []ipPort{
- ipPort{net.ParseIP("127.0.0.1").To4(), port},
+ ipPort{net.ParseIP("127.0.0.1"), port},
ipPort{net.ParseIP("2001:db8:a0b:12f0::1"), port},
}
if !reflect.DeepEqual(ips, expected) {
diff --git a/vendor/github.com/hashicorp/memberlist/suspicion.go b/vendor/github.com/hashicorp/memberlist/suspicion.go
index 5f573e1fc..f8aa9e20a 100644
--- a/vendor/github.com/hashicorp/memberlist/suspicion.go
+++ b/vendor/github.com/hashicorp/memberlist/suspicion.go
@@ -117,7 +117,7 @@ func (s *suspicion) Confirm(from string) bool {
// stop the timer then we will call the timeout function directly from
// here.
n := atomic.AddInt32(&s.n, 1)
- elapsed := time.Now().Sub(s.start)
+ elapsed := time.Since(s.start)
remaining := remainingSuspicionTime(n, s.k, elapsed, s.min, s.max)
if s.timer.Stop() {
if remaining > 0 {
diff --git a/vendor/github.com/hashicorp/memberlist/util.go b/vendor/github.com/hashicorp/memberlist/util.go
index a4f926e3a..e2381a698 100644
--- a/vendor/github.com/hashicorp/memberlist/util.go
+++ b/vendor/github.com/hashicorp/memberlist/util.go
@@ -217,20 +217,6 @@ func decodeCompoundMessage(buf []byte) (trunc int, parts [][]byte, err error) {
return
}
-// Given a string of the form "host", "host:port",
-// "ipv6::addr" or "[ipv6::address]:port",
-// return true if the string includes a port.
-func hasPort(s string) bool {
- last := strings.LastIndex(s, ":")
- if last == -1 {
- return false
- }
- if s[0] == '[' {
- return s[last-1] == ']'
- }
- return strings.Index(s, ":") == last
-}
-
// compressPayload takes an opaque input buffer, compresses it
// and wraps it in a compress{} message that is encoded.
func compressPayload(inp []byte) (*bytes.Buffer, error) {
@@ -294,3 +280,31 @@ func decompressBuffer(c *compress) ([]byte, error) {
func joinHostPort(host string, port uint16) string {
return net.JoinHostPort(host, strconv.Itoa(int(port)))
}
+
+// hasPort is given a string of the form "host", "host:port", "ipv6::address",
+// or "[ipv6::address]:port", and returns true if the string includes a port.
+func hasPort(s string) bool {
+ // IPv6 address in brackets.
+ if strings.LastIndex(s, "[") == 0 {
+ return strings.LastIndex(s, ":") > strings.LastIndex(s, "]")
+ }
+
+ // Otherwise the presence of a single colon determines if there's a port
+ // since IPv6 addresses outside of brackets (count > 1) can't have a
+ // port.
+ return strings.Count(s, ":") == 1
+}
+
+// ensurePort makes sure the given string has a port number on it, otherwise it
+// appends the given port as a default.
+func ensurePort(s string, port int) string {
+ if hasPort(s) {
+ return s
+ }
+
+ // If this is an IPv6 address, the join call will add another set of
+ // brackets, so we have to trim before we add the default port.
+ s = strings.Trim(s, "[]")
+ s = net.JoinHostPort(s, strconv.Itoa(port))
+ return s
+}
diff --git a/vendor/github.com/hashicorp/memberlist/util_test.go b/vendor/github.com/hashicorp/memberlist/util_test.go
index e1d8eba01..b7f2b4199 100644
--- a/vendor/github.com/hashicorp/memberlist/util_test.go
+++ b/vendor/github.com/hashicorp/memberlist/util_test.go
@@ -7,24 +7,31 @@ import (
"time"
)
-func Test_hasPort(t *testing.T) {
- cases := []struct {
- s string
- expected bool
+func TestUtil_PortFunctions(t *testing.T) {
+ tests := []struct {
+ addr string
+ hasPort bool
+ ensurePort string
}{
- {"", false},
- {":80", true},
- {"127.0.0.1", false},
- {"127.0.0.1:80", true},
- {"::1", false},
- {"2001:db8:a0b:12f0::1", false},
- {"[2001:db8:a0b:12f0::1]", false},
- {"[2001:db8:a0b:12f0::1]:80", true},
- }
- for _, c := range cases {
- if hasPort(c.s) != c.expected {
- t.Fatalf("bad: '%s' hasPort was not %v", c.s, c.expected)
- }
+ {"1.2.3.4", false, "1.2.3.4:8301"},
+ {"1.2.3.4:1234", true, "1.2.3.4:1234"},
+ {"2600:1f14:e22:1501:f9a:2e0c:a167:67e8", false, "[2600:1f14:e22:1501:f9a:2e0c:a167:67e8]:8301"},
+ {"[2600:1f14:e22:1501:f9a:2e0c:a167:67e8]", false, "[2600:1f14:e22:1501:f9a:2e0c:a167:67e8]:8301"},
+ {"[2600:1f14:e22:1501:f9a:2e0c:a167:67e8]:1234", true, "[2600:1f14:e22:1501:f9a:2e0c:a167:67e8]:1234"},
+ {"localhost", false, "localhost:8301"},
+ {"localhost:1234", true, "localhost:1234"},
+ {"hashicorp.com", false, "hashicorp.com:8301"},
+ {"hashicorp.com:1234", true, "hashicorp.com:1234"},
+ }
+ for _, tt := range tests {
+ t.Run(tt.addr, func(t *testing.T) {
+ if got, want := hasPort(tt.addr), tt.hasPort; got != want {
+ t.Fatalf("got %v want %v", got, want)
+ }
+ if got, want := ensurePort(tt.addr, 8301), tt.ensurePort; got != want {
+ t.Fatalf("got %v want %v", got, want)
+ }
+ })
}
}
diff --git a/vendor/github.com/lib/pq/.travis.sh b/vendor/github.com/lib/pq/.travis.sh
index ebf447030..ead01df73 100755
--- a/vendor/github.com/lib/pq/.travis.sh
+++ b/vendor/github.com/lib/pq/.travis.sh
@@ -70,4 +70,29 @@ postgresql_uninstall() {
sudo rm -rf /var/lib/postgresql
}
+megacheck_install() {
+ # Megacheck is Go 1.6+, so skip if Go 1.5.
+ if [[ "$(go version)" =~ "go1.5" ]]
+ then
+ echo "megacheck not supported, skipping installation"
+ return 0
+ fi
+ # Lock megacheck version at $MEGACHECK_VERSION to prevent spontaneous
+ # new error messages in old code.
+ go get -d honnef.co/go/tools/...
+ git -C $GOPATH/src/honnef.co/go/tools/ checkout $MEGACHECK_VERSION
+ go install honnef.co/go/tools/cmd/megacheck
+ megacheck --version
+}
+
+golint_install() {
+ # Golint is Go 1.6+, so skip if Go 1.5.
+ if [[ "$(go version)" =~ "go1.5" ]]
+ then
+ echo "golint not supported, skipping installation"
+ return 0
+ fi
+ go get github.com/golang/lint/golint
+}
+
$1
diff --git a/vendor/github.com/lib/pq/.travis.yml b/vendor/github.com/lib/pq/.travis.yml
index 452515c66..01468f05c 100644
--- a/vendor/github.com/lib/pq/.travis.yml
+++ b/vendor/github.com/lib/pq/.travis.yml
@@ -16,7 +16,9 @@ env:
- PQGOSSLTESTS=1
- PQSSLCERTTEST_PATH=$PWD/certs
- PGHOST=127.0.0.1
+ - MEGACHECK_VERSION=2017.1
matrix:
+ - PGVERSION=10
- PGVERSION=9.6
- PGVERSION=9.5
- PGVERSION=9.4
@@ -31,6 +33,8 @@ before_install:
- ./.travis.sh postgresql_install
- ./.travis.sh postgresql_configure
- ./.travis.sh client_configure
+ - ./.travis.sh megacheck_install
+ - ./.travis.sh golint_install
- go get golang.org/x/tools/cmd/goimports
before_script:
@@ -42,5 +46,15 @@ script:
- >
goimports -d -e $(find -name '*.go') | awk '{ print } END { exit NR == 0 ? 0 : 1 }'
- go vet ./...
+ # For compatibility with Go 1.5, launch only if megacheck is present,
+ # ignore SA1019 (deprecation warnings) in conn_test.go (we have to use the
+ # deprecated driver.Execer and driver.Queryer interfaces) and S1024
+ # (time.Until) everywhere.
+ - >
+ which megacheck > /dev/null
+ && megacheck -ignore 'github.com/lib/pq/conn_test.go:SA1019 github.com/lib/pq/*.go:S1024' ./...
+ || echo 'megacheck is not supported, skipping check'
+ # For compatibility with Go 1.5, launch only if golint is present.
+ - which golint > /dev/null && golint ./... || echo 'golint is not supported, skipping check'
- PQTEST_BINARY_PARAMETERS=no go test -race -v ./...
- PQTEST_BINARY_PARAMETERS=yes go test -race -v ./...
diff --git a/vendor/github.com/lib/pq/README.md b/vendor/github.com/lib/pq/README.md
index 7670fc87a..781c89eea 100644
--- a/vendor/github.com/lib/pq/README.md
+++ b/vendor/github.com/lib/pq/README.md
@@ -1,5 +1,6 @@
# pq - A pure Go postgres driver for Go's database/sql package
+[![GoDoc](https://godoc.org/github.com/lib/pq?status.svg)](https://godoc.org/github.com/lib/pq)
[![Build Status](https://travis-ci.org/lib/pq.svg?branch=master)](https://travis-ci.org/lib/pq)
## Install
diff --git a/vendor/github.com/lib/pq/array_test.go b/vendor/github.com/lib/pq/array_test.go
index 10b843184..f724bcd88 100644
--- a/vendor/github.com/lib/pq/array_test.go
+++ b/vendor/github.com/lib/pq/array_test.go
@@ -89,9 +89,7 @@ func TestParseArrayError(t *testing.T) {
}
func TestArrayScanner(t *testing.T) {
- var s sql.Scanner
-
- s = Array(&[]bool{})
+ var s sql.Scanner = Array(&[]bool{})
if _, ok := s.(*BoolArray); !ok {
t.Errorf("Expected *BoolArray, got %T", s)
}
@@ -126,9 +124,7 @@ func TestArrayScanner(t *testing.T) {
}
func TestArrayValuer(t *testing.T) {
- var v driver.Valuer
-
- v = Array([]bool{})
+ var v driver.Valuer = Array([]bool{})
if _, ok := v.(*BoolArray); !ok {
t.Errorf("Expected *BoolArray, got %T", v)
}
@@ -1193,9 +1189,7 @@ func TestGenericArrayValue(t *testing.T) {
}
func TestGenericArrayValueErrors(t *testing.T) {
- var v []interface{}
-
- v = []interface{}{func() {}}
+ v := []interface{}{func() {}}
if _, err := (GenericArray{v}).Value(); err == nil {
t.Errorf("Expected error for %q, got nil", v)
}
diff --git a/vendor/github.com/lib/pq/conn.go b/vendor/github.com/lib/pq/conn.go
index 338a0bc18..fadb88e5e 100644
--- a/vendor/github.com/lib/pq/conn.go
+++ b/vendor/github.com/lib/pq/conn.go
@@ -35,8 +35,12 @@ var (
errNoLastInsertID = errors.New("no LastInsertId available after the empty statement")
)
+// Driver is the Postgres database driver.
type Driver struct{}
+// Open opens a new connection to the database. name is a connection string.
+// Most users should only use it through database/sql package from the standard
+// library.
func (d *Driver) Open(name string) (driver.Conn, error) {
return Open(name)
}
@@ -78,6 +82,8 @@ func (s transactionStatus) String() string {
panic("not reached")
}
+// Dialer is the dialer interface. It can be used to obtain more control over
+// how pq creates network connections.
type Dialer interface {
Dial(network, address string) (net.Conn, error)
DialTimeout(network, address string, timeout time.Duration) (net.Conn, error)
@@ -149,11 +155,7 @@ func (cn *conn) handleDriverSettings(o values) (err error) {
if err != nil {
return err
}
- err = boolSetting("binary_parameters", &cn.binaryParameters)
- if err != nil {
- return err
- }
- return nil
+ return boolSetting("binary_parameters", &cn.binaryParameters)
}
func (cn *conn) handlePgpass(o values) {
@@ -165,11 +167,16 @@ func (cn *conn) handlePgpass(o values) {
if filename == "" {
// XXX this code doesn't work on Windows where the default filename is
// XXX %APPDATA%\postgresql\pgpass.conf
- user, err := user.Current()
- if err != nil {
- return
+ // Prefer $HOME over user.Current due to glibc bug: golang.org/issue/13470
+ userHome := os.Getenv("HOME")
+ if userHome == "" {
+ user, err := user.Current()
+ if err != nil {
+ return
+ }
+ userHome = user.HomeDir
}
- filename = filepath.Join(user.HomeDir, ".pgpass")
+ filename = filepath.Join(userHome, ".pgpass")
}
fileinfo, err := os.Stat(filename)
if err != nil {
@@ -237,10 +244,14 @@ func (cn *conn) writeBuf(b byte) *writeBuf {
}
}
+// Open opens a new connection to the database. name is a connection string.
+// Most users should only use it through database/sql package from the standard
+// library.
func Open(name string) (_ driver.Conn, err error) {
return DialOpen(defaultDialer{}, name)
}
+// DialOpen opens a new connection to the database using a dialer.
func DialOpen(d Dialer, name string) (_ driver.Conn, err error) {
// Handle any panics during connection initialization. Note that we
// specifically do *not* want to use errRecover(), as that would turn any
@@ -1431,7 +1442,8 @@ func (rs *rows) NextResultSet() error {
//
// tblname := "my_table"
// data := "my_data"
-// err = db.Exec(fmt.Sprintf("INSERT INTO %s VALUES ($1)", pq.QuoteIdentifier(tblname)), data)
+// quoted := pq.QuoteIdentifier(tblname)
+// err := db.Exec(fmt.Sprintf("INSERT INTO %s VALUES ($1)", quoted), data)
//
// Any double quotes in name will be escaped. The quoted identifier will be
// case sensitive when used in a query. If the input string contains a zero
diff --git a/vendor/github.com/lib/pq/conn_test.go b/vendor/github.com/lib/pq/conn_test.go
index d3c01f343..030a798c9 100644
--- a/vendor/github.com/lib/pq/conn_test.go
+++ b/vendor/github.com/lib/pq/conn_test.go
@@ -935,12 +935,14 @@ func TestParseErrorInExtendedQuery(t *testing.T) {
db := openTestConn(t)
defer db.Close()
- rows, err := db.Query("PARSE_ERROR $1", 1)
- if err == nil {
- t.Fatal("expected error")
+ _, err := db.Query("PARSE_ERROR $1", 1)
+ pqErr, _ := err.(*Error)
+ // Expecting a syntax error.
+ if err == nil || pqErr == nil || pqErr.Code != "42601" {
+ t.Fatalf("expected syntax error, got %s", err)
}
- rows, err = db.Query("SELECT 1")
+ rows, err := db.Query("SELECT 1")
if err != nil {
t.Fatal(err)
}
@@ -1205,16 +1207,11 @@ func TestParseComplete(t *testing.T) {
tpc("SELECT foo", "", 0, true) // invalid row count
}
-func TestExecerInterface(t *testing.T) {
- // Gin up a straw man private struct just for the type check
- cn := &conn{c: nil}
- var cni interface{} = cn
-
- _, ok := cni.(driver.Execer)
- if !ok {
- t.Fatal("Driver doesn't implement Execer")
- }
-}
+// Test interface conformance.
+var (
+ _ driver.Execer = (*conn)(nil)
+ _ driver.Queryer = (*conn)(nil)
+)
func TestNullAfterNonNull(t *testing.T) {
db := openTestConn(t)
@@ -1392,36 +1389,29 @@ func TestParseOpts(t *testing.T) {
}
func TestRuntimeParameters(t *testing.T) {
- type RuntimeTestResult int
- const (
- ResultUnknown RuntimeTestResult = iota
- ResultSuccess
- ResultError // other error
- )
-
tests := []struct {
- conninfo string
- param string
- expected string
- expectedOutcome RuntimeTestResult
+ conninfo string
+ param string
+ expected string
+ success bool
}{
// invalid parameter
- {"DOESNOTEXIST=foo", "", "", ResultError},
+ {"DOESNOTEXIST=foo", "", "", false},
// we can only work with a specific value for these two
- {"client_encoding=SQL_ASCII", "", "", ResultError},
- {"datestyle='ISO, YDM'", "", "", ResultError},
+ {"client_encoding=SQL_ASCII", "", "", false},
+ {"datestyle='ISO, YDM'", "", "", false},
// "options" should work exactly as it does in libpq
- {"options='-c search_path=pqgotest'", "search_path", "pqgotest", ResultSuccess},
+ {"options='-c search_path=pqgotest'", "search_path", "pqgotest", true},
// pq should override client_encoding in this case
- {"options='-c client_encoding=SQL_ASCII'", "client_encoding", "UTF8", ResultSuccess},
+ {"options='-c client_encoding=SQL_ASCII'", "client_encoding", "UTF8", true},
// allow client_encoding to be set explicitly
- {"client_encoding=UTF8", "client_encoding", "UTF8", ResultSuccess},
+ {"client_encoding=UTF8", "client_encoding", "UTF8", true},
// test a runtime parameter not supported by libpq
- {"work_mem='139kB'", "work_mem", "139kB", ResultSuccess},
+ {"work_mem='139kB'", "work_mem", "139kB", true},
// test fallback_application_name
- {"application_name=foo fallback_application_name=bar", "application_name", "foo", ResultSuccess},
- {"application_name='' fallback_application_name=bar", "application_name", "", ResultSuccess},
- {"fallback_application_name=bar", "application_name", "bar", ResultSuccess},
+ {"application_name=foo fallback_application_name=bar", "application_name", "foo", true},
+ {"application_name='' fallback_application_name=bar", "application_name", "", true},
+ {"fallback_application_name=bar", "application_name", "bar", true},
}
for _, test := range tests {
@@ -1436,23 +1426,23 @@ func TestRuntimeParameters(t *testing.T) {
continue
}
- tryGetParameterValue := func() (value string, outcome RuntimeTestResult) {
+ tryGetParameterValue := func() (value string, success bool) {
defer db.Close()
row := db.QueryRow("SELECT current_setting($1)", test.param)
err = row.Scan(&value)
if err != nil {
- return "", ResultError
+ return "", false
}
- return value, ResultSuccess
+ return value, true
}
- value, outcome := tryGetParameterValue()
- if outcome != test.expectedOutcome && outcome == ResultError {
+ value, success := tryGetParameterValue()
+ if success != test.success && !test.success {
t.Fatalf("%v: unexpected error: %v", test.conninfo, err)
}
- if outcome != test.expectedOutcome {
+ if success != test.success {
t.Fatalf("unexpected outcome %v (was expecting %v) for conninfo \"%s\"",
- outcome, test.expectedOutcome, test.conninfo)
+ success, test.success, test.conninfo)
}
if value != test.expected {
t.Fatalf("bad value for %s: got %s, want %s with conninfo \"%s\"",
diff --git a/vendor/github.com/lib/pq/copy_test.go b/vendor/github.com/lib/pq/copy_test.go
index 86745b38f..c1a3cd7fa 100644
--- a/vendor/github.com/lib/pq/copy_test.go
+++ b/vendor/github.com/lib/pq/copy_test.go
@@ -9,8 +9,7 @@ import (
)
func TestCopyInStmt(t *testing.T) {
- var stmt string
- stmt = CopyIn("table name")
+ stmt := CopyIn("table name")
if stmt != `COPY "table name" () FROM STDIN` {
t.Fatal(stmt)
}
@@ -27,8 +26,7 @@ func TestCopyInStmt(t *testing.T) {
}
func TestCopyInSchemaStmt(t *testing.T) {
- var stmt string
- stmt = CopyInSchema("schema name", "table name")
+ stmt := CopyInSchema("schema name", "table name")
if stmt != `COPY "schema name"."table name" () FROM STDIN` {
t.Fatal(stmt)
}
@@ -226,7 +224,7 @@ func TestCopyInTypes(t *testing.T) {
if text != "Héllö\n ☃!\r\t\\" {
t.Fatal("unexpected result", text)
}
- if bytes.Compare(blob, []byte{0, 255, 9, 10, 13}) != 0 {
+ if !bytes.Equal(blob, []byte{0, 255, 9, 10, 13}) {
t.Fatal("unexpected result", blob)
}
if nothing.Valid {
diff --git a/vendor/github.com/lib/pq/doc.go b/vendor/github.com/lib/pq/doc.go
index 6d252ecee..b2c3582c8 100644
--- a/vendor/github.com/lib/pq/doc.go
+++ b/vendor/github.com/lib/pq/doc.go
@@ -11,7 +11,8 @@ using this package directly. For example:
)
func main() {
- db, err := sql.Open("postgres", "user=pqgotest dbname=pqgotest sslmode=verify-full")
+ connStr := "user=pqgotest dbname=pqgotest sslmode=verify-full"
+ db, err := sql.Open("postgres", connStr)
if err != nil {
log.Fatal(err)
}
@@ -23,7 +24,8 @@ using this package directly. For example:
You can also connect to a database using a URL. For example:
- db, err := sql.Open("postgres", "postgres://pqgotest:password@localhost/pqgotest?sslmode=verify-full")
+ connStr := "postgres://pqgotest:password@localhost/pqgotest?sslmode=verify-full"
+ db, err := sql.Open("postgres", connStr)
Connection String Parameters
@@ -43,21 +45,28 @@ supported:
* dbname - The name of the database to connect to
* user - The user to sign in as
* password - The user's password
- * host - The host to connect to. Values that start with / are for unix domain sockets. (default is localhost)
+ * host - The host to connect to. Values that start with / are for unix
+ domain sockets. (default is localhost)
* port - The port to bind to. (default is 5432)
- * sslmode - Whether or not to use SSL (default is require, this is not the default for libpq)
+ * sslmode - Whether or not to use SSL (default is require, this is not
+ the default for libpq)
* fallback_application_name - An application_name to fall back to if one isn't provided.
- * connect_timeout - Maximum wait for connection, in seconds. Zero or not specified means wait indefinitely.
+ * connect_timeout - Maximum wait for connection, in seconds. Zero or
+ not specified means wait indefinitely.
* sslcert - Cert file location. The file must contain PEM encoded data.
* sslkey - Key file location. The file must contain PEM encoded data.
- * sslrootcert - The location of the root certificate file. The file must contain PEM encoded data.
+ * sslrootcert - The location of the root certificate file. The file
+ must contain PEM encoded data.
Valid values for sslmode are:
* disable - No SSL
* require - Always SSL (skip verification)
- * verify-ca - Always SSL (verify that the certificate presented by the server was signed by a trusted CA)
- * verify-full - Always SSL (verify that the certification presented by the server was signed by a trusted CA and the server host name matches the one in the certificate)
+ * verify-ca - Always SSL (verify that the certificate presented by the
+ server was signed by a trusted CA)
+ * verify-full - Always SSL (verify that the certification presented by
+ the server was signed by a trusted CA and the server host name
+ matches the one in the certificate)
See http://www.postgresql.org/docs/current/static/libpq-connect.html#LIBPQ-CONNSTRING
for more information about connection string parameters.
@@ -68,7 +77,7 @@ Use single quotes for values that contain whitespace:
A backslash will escape the next character in values:
- "user=space\ man password='it\'s valid'
+ "user=space\ man password='it\'s valid'"
Note that the connection parameter client_encoding (which sets the
text encoding for the connection) may be set but must be "UTF8",
@@ -129,7 +138,8 @@ This package returns the following types for values from the PostgreSQL backend:
- integer types smallint, integer, and bigint are returned as int64
- floating-point types real and double precision are returned as float64
- character types char, varchar, and text are returned as string
- - temporal types date, time, timetz, timestamp, and timestamptz are returned as time.Time
+ - temporal types date, time, timetz, timestamp, and timestamptz are
+ returned as time.Time
- the boolean type is returned as bool
- the bytea type is returned as []byte
@@ -229,7 +239,7 @@ for more information). Note that the channel name will be truncated to 63
bytes by the PostgreSQL server.
You can find a complete, working example of Listener usage at
-http://godoc.org/github.com/lib/pq/listen_example.
+http://godoc.org/github.com/lib/pq/examples/listen.
*/
package pq
diff --git a/vendor/github.com/lib/pq/encode_test.go b/vendor/github.com/lib/pq/encode_test.go
index 837d45bec..634a05c66 100644
--- a/vendor/github.com/lib/pq/encode_test.go
+++ b/vendor/github.com/lib/pq/encode_test.go
@@ -267,9 +267,7 @@ func TestTimestampWithOutTimezone(t *testing.T) {
t.Fatalf("Could not run query: %v", err)
}
- n := r.Next()
-
- if n != true {
+ if !r.Next() {
t.Fatal("Expected at least one row")
}
@@ -289,8 +287,7 @@ func TestTimestampWithOutTimezone(t *testing.T) {
expected, result)
}
- n = r.Next()
- if n != false {
+ if r.Next() {
t.Fatal("Expected only one row")
}
}
@@ -731,8 +728,7 @@ func TestAppendEscapedText(t *testing.T) {
}
func TestAppendEscapedTextExistingBuffer(t *testing.T) {
- var buf []byte
- buf = []byte("123\t")
+ buf := []byte("123\t")
if esc := appendEscapedText(buf, "hallo\tescape"); string(esc) != "123\thallo\\tescape" {
t.Fatal(string(esc))
}
diff --git a/vendor/github.com/lib/pq/listen_example/doc.go b/vendor/github.com/lib/pq/example/listen/doc.go
index 80f0a9b97..91e2ddbad 100644
--- a/vendor/github.com/lib/pq/listen_example/doc.go
+++ b/vendor/github.com/lib/pq/example/listen/doc.go
@@ -1,6 +1,6 @@
/*
-Below you will find a self-contained Go program which uses the LISTEN / NOTIFY
+Package listen is a self-contained Go program which uses the LISTEN / NOTIFY
mechanism to avoid polling the database while waiting for more work to arrive.
//
@@ -77,7 +77,9 @@ mechanism to avoid polling the database while waiting for more work to arrive.
}
}
- listener := pq.NewListener(conninfo, 10 * time.Second, time.Minute, reportProblem)
+ minReconn := 10 * time.Second
+ maxReconn := time.Minute
+ listener := pq.NewListener(conninfo, minReconn, maxReconn, reportProblem)
err = listener.Listen("getwork")
if err != nil {
panic(err)
@@ -93,4 +95,4 @@ mechanism to avoid polling the database while waiting for more work to arrive.
*/
-package listen_example
+package listen
diff --git a/vendor/github.com/lib/pq/hstore/hstore.go b/vendor/github.com/lib/pq/hstore/hstore.go
index 72d5abf51..f1470db14 100644
--- a/vendor/github.com/lib/pq/hstore/hstore.go
+++ b/vendor/github.com/lib/pq/hstore/hstore.go
@@ -6,7 +6,7 @@ import (
"strings"
)
-// A wrapper for transferring Hstore values back and forth easily.
+// Hstore is a wrapper for transferring Hstore values back and forth easily.
type Hstore struct {
Map map[string]sql.NullString
}
diff --git a/vendor/github.com/lib/pq/notify.go b/vendor/github.com/lib/pq/notify.go
index 09f94244b..412c6ac1e 100644
--- a/vendor/github.com/lib/pq/notify.go
+++ b/vendor/github.com/lib/pq/notify.go
@@ -60,7 +60,7 @@ type ListenerConn struct {
replyChan chan message
}
-// Creates a new ListenerConn. Use NewListener instead.
+// NewListenerConn creates a new ListenerConn. Use NewListener instead.
func NewListenerConn(name string, notificationChan chan<- *Notification) (*ListenerConn, error) {
return newDialListenerConn(defaultDialer{}, name, notificationChan)
}
@@ -214,17 +214,17 @@ func (l *ListenerConn) listenerConnMain() {
// this ListenerConn is done
}
-// Send a LISTEN query to the server. See ExecSimpleQuery.
+// Listen sends a LISTEN query to the server. See ExecSimpleQuery.
func (l *ListenerConn) Listen(channel string) (bool, error) {
return l.ExecSimpleQuery("LISTEN " + QuoteIdentifier(channel))
}
-// Send an UNLISTEN query to the server. See ExecSimpleQuery.
+// Unlisten sends an UNLISTEN query to the server. See ExecSimpleQuery.
func (l *ListenerConn) Unlisten(channel string) (bool, error) {
return l.ExecSimpleQuery("UNLISTEN " + QuoteIdentifier(channel))
}
-// Send `UNLISTEN *` to the server. See ExecSimpleQuery.
+// UnlistenAll sends an `UNLISTEN *` query to the server. See ExecSimpleQuery.
func (l *ListenerConn) UnlistenAll() (bool, error) {
return l.ExecSimpleQuery("UNLISTEN *")
}
@@ -267,8 +267,8 @@ func (l *ListenerConn) sendSimpleQuery(q string) (err error) {
return nil
}
-// Execute a "simple query" (i.e. one with no bindable parameters) on the
-// connection. The possible return values are:
+// ExecSimpleQuery executes a "simple query" (i.e. one with no bindable
+// parameters) on the connection. The possible return values are:
// 1) "executed" is true; the query was executed to completion on the
// database server. If the query failed, err will be set to the error
// returned by the database, otherwise err will be nil.
@@ -333,6 +333,7 @@ func (l *ListenerConn) ExecSimpleQuery(q string) (executed bool, err error) {
}
}
+// Close closes the connection.
func (l *ListenerConn) Close() error {
l.connectionLock.Lock()
if l.err != nil {
@@ -346,7 +347,7 @@ func (l *ListenerConn) Close() error {
return l.cn.c.Close()
}
-// Err() returns the reason the connection was closed. It is not safe to call
+// Err returns the reason the connection was closed. It is not safe to call
// this function until l.Notify has been closed.
func (l *ListenerConn) Err() error {
return l.err
@@ -354,32 +355,43 @@ func (l *ListenerConn) Err() error {
var errListenerClosed = errors.New("pq: Listener has been closed")
+// ErrChannelAlreadyOpen is returned from Listen when a channel is already
+// open.
var ErrChannelAlreadyOpen = errors.New("pq: channel is already open")
+
+// ErrChannelNotOpen is returned from Unlisten when a channel is not open.
var ErrChannelNotOpen = errors.New("pq: channel is not open")
+// ListenerEventType is an enumeration of listener event types.
type ListenerEventType int
const (
- // Emitted only when the database connection has been initially
- // initialized. err will always be nil.
+ // ListenerEventConnected is emitted only when the database connection
+ // has been initially initialized. The err argument of the callback
+ // will always be nil.
ListenerEventConnected ListenerEventType = iota
- // Emitted after a database connection has been lost, either because of an
- // error or because Close has been called. err will be set to the reason
- // the database connection was lost.
+ // ListenerEventDisconnected is emitted after a database connection has
+ // been lost, either because of an error or because Close has been
+ // called. The err argument will be set to the reason the database
+ // connection was lost.
ListenerEventDisconnected
- // Emitted after a database connection has been re-established after
- // connection loss. err will always be nil. After this event has been
- // emitted, a nil pq.Notification is sent on the Listener.Notify channel.
+ // ListenerEventReconnected is emitted after a database connection has
+ // been re-established after connection loss. The err argument of the
+ // callback will always be nil. After this event has been emitted, a
+ // nil pq.Notification is sent on the Listener.Notify channel.
ListenerEventReconnected
- // Emitted after a connection to the database was attempted, but failed.
- // err will be set to an error describing why the connection attempt did
- // not succeed.
+ // ListenerEventConnectionAttemptFailed is emitted after a connection
+ // to the database was attempted, but failed. The err argument will be
+ // set to an error describing why the connection attempt did not
+ // succeed.
ListenerEventConnectionAttemptFailed
)
+// EventCallbackType is the event callback type. See also ListenerEventType
+// constants' documentation.
type EventCallbackType func(event ListenerEventType, err error)
// Listener provides an interface for listening to notifications from a
@@ -454,9 +466,9 @@ func NewDialListener(d Dialer,
return l
}
-// Returns the notification channel for this listener. This is the same
-// channel as Notify, and will not be recreated during the life time of the
-// Listener.
+// NotificationChannel returns the notification channel for this listener.
+// This is the same channel as Notify, and will not be recreated during the
+// life time of the Listener.
func (l *Listener) NotificationChannel() <-chan *Notification {
return l.Notify
}
@@ -639,7 +651,7 @@ func (l *Listener) resync(cn *ListenerConn, notificationChan <-chan *Notificatio
// close and then return the error message from the connection, as
// per ListenerConn's interface.
if err != nil {
- for _ = range notificationChan {
+ for range notificationChan {
}
doneChan <- cn.Err()
return
diff --git a/vendor/github.com/lib/pq/notify_test.go b/vendor/github.com/lib/pq/notify_test.go
index 82a77e1eb..075666ddb 100644
--- a/vendor/github.com/lib/pq/notify_test.go
+++ b/vendor/github.com/lib/pq/notify_test.go
@@ -123,6 +123,9 @@ func TestConnUnlisten(t *testing.T) {
}
_, err = db.Exec("NOTIFY notify_test")
+ if err != nil {
+ t.Fatal(err)
+ }
err = expectNotification(t, channel, "notify_test", "")
if err != nil {
@@ -159,6 +162,9 @@ func TestConnUnlistenAll(t *testing.T) {
}
_, err = db.Exec("NOTIFY notify_test")
+ if err != nil {
+ t.Fatal(err)
+ }
err = expectNotification(t, channel, "notify_test", "")
if err != nil {
diff --git a/vendor/github.com/magiconair/properties/CHANGELOG.md b/vendor/github.com/magiconair/properties/CHANGELOG.md
index ebd1bcd32..b0d98d81d 100644
--- a/vendor/github.com/magiconair/properties/CHANGELOG.md
+++ b/vendor/github.com/magiconair/properties/CHANGELOG.md
@@ -1,62 +1,65 @@
## Changelog
-### Unreleased
+### [1.7.4](https://github.com/magiconair/properties/tree/v1.7.4) - 31 Oct 2017
+ * [Issue #23](https://github.com/magiconair/properties/issues/23): Ignore blank lines with whitespaces
* [PR #24](https://github.com/magiconair/properties/pull/24): Update keys when DisableExpansion is enabled
Thanks to @mgurov for the fix.
-### [1.7.3](https://github.com/magiconair/properties/tags/v1.7.3) - 10 Jul 2017
+### [1.7.3](https://github.com/magiconair/properties/tree/v1.7.3) - 10 Jul 2017
* [Issue #17](https://github.com/magiconair/properties/issues/17): Add [SetValue()](http://godoc.org/github.com/magiconair/properties#Properties.SetValue) method to set values generically
* [Issue #22](https://github.com/magiconair/properties/issues/22): Add [LoadMap()](http://godoc.org/github.com/magiconair/properties#LoadMap) function to load properties from a string map
-### [1.7.2](https://github.com/magiconair/properties/tags/v1.7.2) - 20 Mar 2017
+### [1.7.2](https://github.com/magiconair/properties/tree/v1.7.2) - 20 Mar 2017
* [Issue #15](https://github.com/magiconair/properties/issues/15): Drop gocheck dependency
* [PR #21](https://github.com/magiconair/properties/pull/21): Add [Map()](http://godoc.org/github.com/magiconair/properties#Properties.Map) and [FilterFunc()](http://godoc.org/github.com/magiconair/properties#Properties.FilterFunc)
-### [1.7.1](https://github.com/magiconair/properties/tags/v1.7.1) - 13 Jan 2017
+### [1.7.1](https://github.com/magiconair/properties/tree/v1.7.1) - 13 Jan 2017
+ * [Issue #14](https://github.com/magiconair/properties/issues/14): Decouple TestLoadExpandedFile from `$USER`
+ * [PR #12](https://github.com/magiconair/properties/pull/12): Load from files and URLs
* [PR #16](https://github.com/magiconair/properties/pull/16): Keep gofmt happy
* [PR #18](https://github.com/magiconair/properties/pull/18): Fix Delete() function
-### [1.7.0](https://github.com/magiconair/properties/tags/v1.7.0) - 20 Mar 2016
+### [1.7.0](https://github.com/magiconair/properties/tree/v1.7.0) - 20 Mar 2016
* [Issue #10](https://github.com/magiconair/properties/issues/10): Add [LoadURL,LoadURLs,MustLoadURL,MustLoadURLs](http://godoc.org/github.com/magiconair/properties#LoadURL) method to load properties from a URL.
* [Issue #11](https://github.com/magiconair/properties/issues/11): Add [LoadString,MustLoadString](http://godoc.org/github.com/magiconair/properties#LoadString) method to load properties from an UTF8 string.
* [PR #8](https://github.com/magiconair/properties/pull/8): Add [MustFlag](http://godoc.org/github.com/magiconair/properties#Properties.MustFlag) method to provide overrides via command line flags. (@pascaldekloe)
-### [1.6.0](https://github.com/magiconair/properties/tags/v1.6.0) - 11 Dec 2015
+### [1.6.0](https://github.com/magiconair/properties/tree/v1.6.0) - 11 Dec 2015
* Add [Decode](http://godoc.org/github.com/magiconair/properties#Properties.Decode) method to populate struct from properties via tags.
-### [1.5.6](https://github.com/magiconair/properties/tags/v1.5.6) - 18 Oct 2015
+### [1.5.6](https://github.com/magiconair/properties/tree/v1.5.6) - 18 Oct 2015
* Vendored in gopkg.in/check.v1
-### [1.5.5](https://github.com/magiconair/properties/tags/v1.5.5) - 31 Jul 2015
+### [1.5.5](https://github.com/magiconair/properties/tree/v1.5.5) - 31 Jul 2015
* [PR #6](https://github.com/magiconair/properties/pull/6): Add [Delete](http://godoc.org/github.com/magiconair/properties#Properties.Delete) method to remove keys including comments. (@gerbenjacobs)
-### [1.5.4](https://github.com/magiconair/properties/tags/v1.5.4) - 23 Jun 2015
+### [1.5.4](https://github.com/magiconair/properties/tree/v1.5.4) - 23 Jun 2015
* [Issue #5](https://github.com/magiconair/properties/issues/5): Allow disabling of property expansion [DisableExpansion](http://godoc.org/github.com/magiconair/properties#Properties.DisableExpansion). When property expansion is disabled Properties become a simple key/value store and don't check for circular references.
-### [1.5.3](https://github.com/magiconair/properties/tags/v1.5.3) - 02 Jun 2015
+### [1.5.3](https://github.com/magiconair/properties/tree/v1.5.3) - 02 Jun 2015
* [Issue #4](https://github.com/magiconair/properties/issues/4): Maintain key order in [Filter()](http://godoc.org/github.com/magiconair/properties#Properties.Filter), [FilterPrefix()](http://godoc.org/github.com/magiconair/properties#Properties.FilterPrefix) and [FilterRegexp()](http://godoc.org/github.com/magiconair/properties#Properties.FilterRegexp)
-### [1.5.2](https://github.com/magiconair/properties/tags/v1.5.2) - 10 Apr 2015
+### [1.5.2](https://github.com/magiconair/properties/tree/v1.5.2) - 10 Apr 2015
* [Issue #3](https://github.com/magiconair/properties/issues/3): Don't print comments in [WriteComment()](http://godoc.org/github.com/magiconair/properties#Properties.WriteComment) if they are all empty
* Add clickable links to README
-### [1.5.1](https://github.com/magiconair/properties/tags/v1.5.1) - 08 Dec 2014
+### [1.5.1](https://github.com/magiconair/properties/tree/v1.5.1) - 08 Dec 2014
* Added [GetParsedDuration()](http://godoc.org/github.com/magiconair/properties#Properties.GetParsedDuration) and [MustGetParsedDuration()](http://godoc.org/github.com/magiconair/properties#Properties.MustGetParsedDuration) for values specified compatible with
[time.ParseDuration()](http://golang.org/pkg/time/#ParseDuration).
-### [1.5.0](https://github.com/magiconair/properties/tags/v1.5.0) - 18 Nov 2014
+### [1.5.0](https://github.com/magiconair/properties/tree/v1.5.0) - 18 Nov 2014
* Added support for single and multi-line comments (reading, writing and updating)
* The order of keys is now preserved
@@ -64,31 +67,31 @@
* Added a [MustSet()](http://godoc.org/github.com/magiconair/properties#Properties.MustSet) method
* Migrated test library from launchpad.net/gocheck to [gopkg.in/check.v1](http://gopkg.in/check.v1)
-### [1.4.2](https://github.com/magiconair/properties/tags/v1.4.2) - 15 Nov 2014
+### [1.4.2](https://github.com/magiconair/properties/tree/v1.4.2) - 15 Nov 2014
* [Issue #2](https://github.com/magiconair/properties/issues/2): Fixed goroutine leak in parser which created two lexers but cleaned up only one
-### [1.4.1](https://github.com/magiconair/properties/tags/v1.4.1) - 13 Nov 2014
+### [1.4.1](https://github.com/magiconair/properties/tree/v1.4.1) - 13 Nov 2014
* [Issue #1](https://github.com/magiconair/properties/issues/1): Fixed bug in Keys() method which returned an empty string
-### [1.4.0](https://github.com/magiconair/properties/tags/v1.4.0) - 23 Sep 2014
+### [1.4.0](https://github.com/magiconair/properties/tree/v1.4.0) - 23 Sep 2014
* Added [Keys()](http://godoc.org/github.com/magiconair/properties#Properties.Keys) to get the keys
* Added [Filter()](http://godoc.org/github.com/magiconair/properties#Properties.Filter), [FilterRegexp()](http://godoc.org/github.com/magiconair/properties#Properties.FilterRegexp) and [FilterPrefix()](http://godoc.org/github.com/magiconair/properties#Properties.FilterPrefix) to get a subset of the properties
-### [1.3.0](https://github.com/magiconair/properties/tags/v1.3.0) - 18 Mar 2014
+### [1.3.0](https://github.com/magiconair/properties/tree/v1.3.0) - 18 Mar 2014
* Added support for time.Duration
-* Made MustXXX() failure beha[ior configurable (log.Fatal, panic](https://github.com/magiconair/properties/tags/vior configurable (log.Fatal, panic) - custom)
+* Made MustXXX() failure beha[ior configurable (log.Fatal, panic](https://github.com/magiconair/properties/tree/vior configurable (log.Fatal, panic) - custom)
* Changed default of MustXXX() failure from panic to log.Fatal
-### [1.2.0](https://github.com/magiconair/properties/tags/v1.2.0) - 05 Mar 2014
+### [1.2.0](https://github.com/magiconair/properties/tree/v1.2.0) - 05 Mar 2014
* Added MustGet... functions
* Added support for int and uint with range checks on 32 bit platforms
-### [1.1.0](https://github.com/magiconair/properties/tags/v1.1.0) - 20 Jan 2014
+### [1.1.0](https://github.com/magiconair/properties/tree/v1.1.0) - 20 Jan 2014
* Renamed from goproperties to properties
* Added support for expansion of environment vars in
@@ -96,6 +99,6 @@
* Fixed bug where value expressions were not at the
start of the string
-### [1.0.0](https://github.com/magiconair/properties/tags/v1.0.0) - 7 Jan 2014
+### [1.0.0](https://github.com/magiconair/properties/tree/v1.0.0) - 7 Jan 2014
* Initial release
diff --git a/vendor/github.com/magiconair/properties/README.md b/vendor/github.com/magiconair/properties/README.md
index eb3b8c435..258fbb2b5 100644
--- a/vendor/github.com/magiconair/properties/README.md
+++ b/vendor/github.com/magiconair/properties/README.md
@@ -1,7 +1,7 @@
Overview [![Build Status](https://travis-ci.org/magiconair/properties.svg?branch=master)](https://travis-ci.org/magiconair/properties)
========
-#### Current version: 1.7.3
+#### Current version: 1.7.4
properties is a Go library for reading and writing properties files.
diff --git a/vendor/github.com/magiconair/properties/lex.go b/vendor/github.com/magiconair/properties/lex.go
index a3cba0319..c63fcc60d 100644
--- a/vendor/github.com/magiconair/properties/lex.go
+++ b/vendor/github.com/magiconair/properties/lex.go
@@ -196,9 +196,8 @@ func lexBeforeKey(l *lexer) stateFn {
return lexComment
case isWhitespace(r):
- l.acceptRun(whitespace)
l.ignore()
- return lexKey
+ return lexBeforeKey
default:
l.backup()
diff --git a/vendor/github.com/magiconair/properties/properties_test.go b/vendor/github.com/magiconair/properties/properties_test.go
index 7e92618e0..a22f48df2 100644
--- a/vendor/github.com/magiconair/properties/properties_test.go
+++ b/vendor/github.com/magiconair/properties/properties_test.go
@@ -44,6 +44,8 @@ var complexTests = [][]string{
{"\nkey=value\n", "key", "value"},
{"\rkey=value\r", "key", "value"},
{"\r\nkey=value\r\n", "key", "value"},
+ {"\nkey=value\n \nkey2=value2", "key", "value", "key2", "value2"},
+ {"\nkey=value\n\t\nkey2=value2", "key", "value", "key2", "value2"},
// escaped chars in key
{"k\\ ey = value", "k ey", "value"},
diff --git a/vendor/github.com/miekg/dns/.travis.yml b/vendor/github.com/miekg/dns/.travis.yml
index bb8b8d40b..542dd68c0 100644
--- a/vendor/github.com/miekg/dns/.travis.yml
+++ b/vendor/github.com/miekg/dns/.travis.yml
@@ -1,14 +1,20 @@
language: go
sudo: false
go:
- - 1.7.x
- - 1.8.x
+ - 1.9.x
- tip
+env:
+ - TESTS="-race -v -bench=. -coverprofile=coverage.txt -covermode=atomic"
+ - TESTS="-race -v ./..."
+
before_install:
# don't use the miekg/dns when testing forks
- mkdir -p $GOPATH/src/github.com/miekg
- ln -s $TRAVIS_BUILD_DIR $GOPATH/src/github.com/miekg/ || true
script:
- - go test -race -v -bench=.
+ - go test $TESTS
+
+after_success:
+ - bash <(curl -s https://codecov.io/bash)
diff --git a/vendor/github.com/miekg/dns/README.md b/vendor/github.com/miekg/dns/README.md
index 32a49cbf5..94b54fe25 100644
--- a/vendor/github.com/miekg/dns/README.md
+++ b/vendor/github.com/miekg/dns/README.md
@@ -1,19 +1,19 @@
[![Build Status](https://travis-ci.org/miekg/dns.svg?branch=master)](https://travis-ci.org/miekg/dns)
+[![Code Coverage](https://img.shields.io/codecov/c/github/miekg/dns/master.svg)](https://codecov.io/github/miekg/dns?branch=master)
+[![Go Report Card](https://goreportcard.com/badge/github.com/miekg/dns)](https://goreportcard.com/report/miekg/dns)
[![](https://godoc.org/github.com/miekg/dns?status.svg)](https://godoc.org/github.com/miekg/dns)
# Alternative (more granular) approach to a DNS library
> Less is more.
-Complete and usable DNS library. All widely used Resource Records are
-supported, including the DNSSEC types. It follows a lean and mean philosophy.
-If there is stuff you should know as a DNS programmer there isn't a convenience
-function for it. Server side and client side programming is supported, i.e. you
-can build servers and resolvers with it.
+Complete and usable DNS library. All widely used Resource Records are supported, including the
+DNSSEC types. It follows a lean and mean philosophy. If there is stuff you should know as a DNS
+programmer there isn't a convenience function for it. Server side and client side programming is
+supported, i.e. you can build servers and resolvers with it.
-We try to keep the "master" branch as sane as possible and at the bleeding edge
-of standards, avoiding breaking changes wherever reasonable. We support the last
-two versions of Go, currently: 1.7 and 1.8.
+We try to keep the "master" branch as sane as possible and at the bleeding edge of standards,
+avoiding breaking changes wherever reasonable. We support the last two versions of Go.
# Goals
@@ -55,11 +55,13 @@ A not-so-up-to-date-list-that-may-be-actually-current:
* https://github.com/mehrdadrad/mylg
* https://github.com/bamarni/dockness
* https://github.com/fffaraz/microdns
-* http://quilt.io
+* http://kelda.io
* https://github.com/ipdcode/hades (JD.COM)
* https://github.com/StackExchange/dnscontrol/
* https://www.dnsperf.com/
* https://dnssectest.net/
+* https://dns.apebits.com
+* https://github.com/oif/apex
Send pull request if you want to be listed here.
@@ -86,8 +88,8 @@ Miek Gieben - 2010-2012 - <miek@miek.nl>
# Building
-Building is done with the `go` tool. If you have setup your GOPATH
-correctly, the following should work:
+Building is done with the `go` tool. If you have setup your GOPATH correctly, the following should
+work:
go get github.com/miekg/dns
go build github.com/miekg/dns
@@ -150,9 +152,8 @@ Example programs can be found in the `github.com/miekg/exdns` repository.
* 7314 - DNS (EDNS) EXPIRE Option
* 7828 - edns-tcp-keepalive EDNS0 Option
* 7553 - URI record
-* 7858 - DNS over TLS: Initiation and Performance Considerations (draft)
+* 7858 - DNS over TLS: Initiation and Performance Considerations
* 7873 - Domain Name System (DNS) Cookies (draft-ietf-dnsop-cookies)
-* xxxx - EDNS0 DNS Update Lease (draft)
## Loosely based upon
diff --git a/vendor/github.com/miekg/dns/client.go b/vendor/github.com/miekg/dns/client.go
index 359a0ab8f..0914482ab 100644
--- a/vendor/github.com/miekg/dns/client.go
+++ b/vendor/github.com/miekg/dns/client.go
@@ -78,6 +78,7 @@ func (c *Client) writeTimeout() time.Duration {
return dnsTimeout
}
+// Dial connects to the address on the named network.
func (c *Client) Dial(address string) (conn *Conn, err error) {
// create a new dialer with the appropriate timeout
var d net.Dialer
@@ -454,8 +455,7 @@ func ExchangeConn(c net.Conn, m *Msg) (r *Msg, err error) {
// DialTimeout acts like Dial but takes a timeout.
func DialTimeout(network, address string, timeout time.Duration) (conn *Conn, err error) {
-
- client := Client{Net: "udp", Dialer: &net.Dialer{Timeout: timeout}}
+ client := Client{Net: network, Dialer: &net.Dialer{Timeout: timeout}}
conn, err = client.Dial(address)
if err != nil {
return nil, err
diff --git a/vendor/github.com/miekg/dns/client_test.go b/vendor/github.com/miekg/dns/client_test.go
index 3ff619cfa..ef977aefc 100644
--- a/vendor/github.com/miekg/dns/client_test.go
+++ b/vendor/github.com/miekg/dns/client_test.go
@@ -6,6 +6,7 @@ import (
"fmt"
"net"
"strconv"
+ "strings"
"sync"
"testing"
"time"
@@ -15,7 +16,7 @@ func TestDialUDP(t *testing.T) {
HandleFunc("miek.nl.", HelloServer)
defer HandleRemove("miek.nl.")
- s, addrstr, err := RunLocalUDPServer("[::1]:0")
+ s, addrstr, err := RunLocalUDPServer(":0")
if err != nil {
t.Fatalf("unable to run test server: %v", err)
}
@@ -38,7 +39,7 @@ func TestClientSync(t *testing.T) {
HandleFunc("miek.nl.", HelloServer)
defer HandleRemove("miek.nl.")
- s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
+ s, addrstr, err := RunLocalUDPServer(":0")
if err != nil {
t.Fatalf("unable to run test server: %v", err)
}
@@ -72,7 +73,7 @@ func TestClientLocalAddress(t *testing.T) {
HandleFunc("miek.nl.", HelloServerEchoAddrPort)
defer HandleRemove("miek.nl.")
- s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
+ s, addrstr, err := RunLocalUDPServer(":0")
if err != nil {
t.Fatalf("unable to run test server: %v", err)
}
@@ -82,11 +83,11 @@ func TestClientLocalAddress(t *testing.T) {
m.SetQuestion("miek.nl.", TypeSOA)
c := new(Client)
- laddr := net.UDPAddr{IP: net.ParseIP("127.0.0.1"), Port: 12345, Zone: ""}
+ laddr := net.UDPAddr{IP: net.ParseIP("0.0.0.0"), Port: 12345, Zone: ""}
c.Dialer = &net.Dialer{LocalAddr: &laddr}
r, _, err := c.Exchange(m, addrstr)
if err != nil {
- t.Errorf("failed to exchange: %v", err)
+ t.Fatalf("failed to exchange: %v", err)
}
if r != nil && r.Rcode != RcodeSuccess {
t.Errorf("failed to get an valid answer\n%v", r)
@@ -98,7 +99,7 @@ func TestClientLocalAddress(t *testing.T) {
if txt == nil {
t.Errorf("invalid TXT response\n%v", txt)
}
- if len(txt.Txt) != 1 || txt.Txt[0] != "127.0.0.1:12345" {
+ if len(txt.Txt) != 1 || !strings.Contains(txt.Txt[0], ":12345") {
t.Errorf("invalid TXT response\n%v", txt.Txt)
}
}
@@ -116,7 +117,7 @@ func TestClientTLSSyncV4(t *testing.T) {
Certificates: []tls.Certificate{cert},
}
- s, addrstr, err := RunLocalTLSServer("127.0.0.1:0", &config)
+ s, addrstr, err := RunLocalTLSServer(":0", &config)
if err != nil {
t.Fatalf("unable to run test server: %v", err)
}
@@ -162,70 +163,11 @@ func TestClientTLSSyncV4(t *testing.T) {
}
}
-func TestClientTLSSyncV6(t *testing.T) {
- HandleFunc("miek.nl.", HelloServer)
- defer HandleRemove("miek.nl.")
-
- cert, err := tls.X509KeyPair(CertPEMBlock, KeyPEMBlock)
- if err != nil {
- t.Fatalf("unable to build certificate: %v", err)
- }
-
- config := tls.Config{
- Certificates: []tls.Certificate{cert},
- }
-
- s, addrstr, err := RunLocalTLSServer("[::1]:0", &config)
- if err != nil {
- t.Fatalf("unable to run test server: %v", err)
- }
- defer s.Shutdown()
-
- m := new(Msg)
- m.SetQuestion("miek.nl.", TypeSOA)
-
- c := new(Client)
-
- // test tcp-tls
- c.Net = "tcp-tls"
- c.TLSConfig = &tls.Config{
- InsecureSkipVerify: true,
- }
-
- r, _, err := c.Exchange(m, addrstr)
- if err != nil {
- t.Fatalf("failed to exchange: %v", err)
- }
- if r == nil {
- t.Fatal("response is nil")
- }
- if r.Rcode != RcodeSuccess {
- t.Errorf("failed to get an valid answer\n%v", r)
- }
-
- // test tcp6-tls
- c.Net = "tcp6-tls"
- c.TLSConfig = &tls.Config{
- InsecureSkipVerify: true,
- }
-
- r, _, err = c.Exchange(m, addrstr)
- if err != nil {
- t.Fatalf("failed to exchange: %v", err)
- }
- if r == nil {
- t.Fatal("response is nil")
- }
- if r.Rcode != RcodeSuccess {
- t.Errorf("failed to get an valid answer\n%v", r)
- }
-}
-
func TestClientSyncBadID(t *testing.T) {
HandleFunc("miek.nl.", HelloServerBadID)
defer HandleRemove("miek.nl.")
- s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
+ s, addrstr, err := RunLocalUDPServer(":0")
if err != nil {
t.Fatalf("unable to run test server: %v", err)
}
@@ -248,7 +190,7 @@ func TestClientEDNS0(t *testing.T) {
HandleFunc("miek.nl.", HelloServer)
defer HandleRemove("miek.nl.")
- s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
+ s, addrstr, err := RunLocalUDPServer(":0")
if err != nil {
t.Fatalf("unable to run test server: %v", err)
}
@@ -295,7 +237,7 @@ func TestClientEDNS0Local(t *testing.T) {
HandleFunc("miek.nl.", handler)
defer HandleRemove("miek.nl.")
- s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
+ s, addrstr, err := RunLocalUDPServer(":0")
if err != nil {
t.Fatalf("unable to run test server: %s", err)
}
@@ -321,7 +263,6 @@ func TestClientEDNS0Local(t *testing.T) {
}
if r.Rcode != RcodeSuccess {
t.Fatal("failed to get a valid answer")
- t.Logf("%v\n", r)
}
txt := r.Extra[0].(*TXT).Txt[0]
@@ -333,41 +274,11 @@ func TestClientEDNS0Local(t *testing.T) {
got := r.Extra[1].(*OPT).Option[0].(*EDNS0_LOCAL).String()
if got != optStr1 {
t.Errorf("failed to get local edns0 answer; got %s, expected %s", got, optStr1)
- t.Logf("%v\n", r)
}
got = r.Extra[1].(*OPT).Option[1].(*EDNS0_LOCAL).String()
if got != optStr2 {
t.Errorf("failed to get local edns0 answer; got %s, expected %s", got, optStr2)
- t.Logf("%v\n", r)
- }
-}
-
-// ExampleTsigSecret_updateLeaseTSIG shows how to update a lease signed with TSIG
-func ExampleTsigSecret_updateLeaseTSIG() {
- m := new(Msg)
- m.SetUpdate("t.local.ip6.io.")
- rr, _ := NewRR("t.local.ip6.io. 30 A 127.0.0.1")
- rrs := make([]RR, 1)
- rrs[0] = rr
- m.Insert(rrs)
-
- leaseRr := new(OPT)
- leaseRr.Hdr.Name = "."
- leaseRr.Hdr.Rrtype = TypeOPT
- e := new(EDNS0_UL)
- e.Code = EDNS0UL
- e.Lease = 120
- leaseRr.Option = append(leaseRr.Option, e)
- m.Extra = append(m.Extra, leaseRr)
-
- c := new(Client)
- m.SetTsig("polvi.", HmacMD5, 300, time.Now().Unix())
- c.TsigSecret = map[string]string{"polvi.": "pRZgBrBvI4NAHZYhxmhs/Q=="}
-
- _, _, err := c.Exchange(m, "127.0.0.1:53")
- if err != nil {
- panic(err)
}
}
@@ -376,7 +287,7 @@ func TestClientConn(t *testing.T) {
defer HandleRemove("miek.nl.")
// This uses TCP just to make it slightly different than TestClientSync
- s, addrstr, err := RunLocalTCPServer("127.0.0.1:0")
+ s, addrstr, err := RunLocalTCPServer(":0")
if err != nil {
t.Fatalf("unable to run test server: %v", err)
}
@@ -558,7 +469,7 @@ func TestTruncatedMsg(t *testing.T) {
func TestTimeout(t *testing.T) {
// Set up a dummy UDP server that won't respond
- addr, err := net.ResolveUDPAddr("udp", "127.0.0.1:0")
+ addr, err := net.ResolveUDPAddr("udp", ":0")
if err != nil {
t.Fatalf("unable to resolve local udp address: %v", err)
}
@@ -614,7 +525,7 @@ func TestTimeout(t *testing.T) {
length := time.Since(start)
if length > allowable {
- t.Errorf("exchange took longer (%v) than specified Timeout (%v)", length, timeout)
+ t.Errorf("exchange took longer %v than specified Timeout %v", length, allowable)
}
}
@@ -640,7 +551,7 @@ func TestConcurrentExchanges(t *testing.T) {
HandleFunc("miek.nl.", handler)
defer HandleRemove("miek.nl.")
- s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
+ s, addrstr, err := RunLocalUDPServer(":0")
if err != nil {
t.Fatalf("unable to run test server: %s", err)
}
@@ -673,8 +584,7 @@ func TestConcurrentExchanges(t *testing.T) {
wg.Wait()
if r[0] == r[1] {
- t.Log("Got same response object, expected non-shared responses")
- t.Fail()
+ t.Errorf("got same response, expected non-shared responses")
}
}
}
diff --git a/vendor/github.com/miekg/dns/clientconfig.go b/vendor/github.com/miekg/dns/clientconfig.go
index 0a1f5a92c..6479fef93 100644
--- a/vendor/github.com/miekg/dns/clientconfig.go
+++ b/vendor/github.com/miekg/dns/clientconfig.go
@@ -2,6 +2,7 @@ package dns
import (
"bufio"
+ "io"
"os"
"strconv"
"strings"
@@ -25,8 +26,13 @@ func ClientConfigFromFile(resolvconf string) (*ClientConfig, error) {
return nil, err
}
defer file.Close()
+ return ClientConfigFromReader(file)
+}
+
+// ClientConfigFromReader works like ClientConfigFromFile but takes an io.Reader as argument
+func ClientConfigFromReader(resolvconf io.Reader) (*ClientConfig, error) {
c := new(ClientConfig)
- scanner := bufio.NewScanner(file)
+ scanner := bufio.NewScanner(resolvconf)
c.Servers = make([]string, 0)
c.Search = make([]string, 0)
c.Port = "53"
diff --git a/vendor/github.com/miekg/dns/clientconfig_test.go b/vendor/github.com/miekg/dns/clientconfig_test.go
index 7755a8a6f..4c5d1fb60 100644
--- a/vendor/github.com/miekg/dns/clientconfig_test.go
+++ b/vendor/github.com/miekg/dns/clientconfig_test.go
@@ -4,6 +4,7 @@ import (
"io/ioutil"
"os"
"path/filepath"
+ "strings"
"testing"
)
@@ -20,6 +21,26 @@ nameserver 10.28.10.2
nameserver 11.28.10.1` // <- NOTE: NO newline.
func testConfig(t *testing.T, data string) {
+ cc, err := ClientConfigFromReader(strings.NewReader(data))
+ if err != nil {
+ t.Errorf("error parsing resolv.conf: %v", err)
+ }
+ if l := len(cc.Servers); l != 2 {
+ t.Errorf("incorrect number of nameservers detected: %d", l)
+ }
+ if l := len(cc.Search); l != 1 {
+ t.Errorf("domain directive not parsed correctly: %v", cc.Search)
+ } else {
+ if cc.Search[0] != "somedomain.com" {
+ t.Errorf("domain is unexpected: %v", cc.Search[0])
+ }
+ }
+}
+
+func TestNameserver(t *testing.T) { testConfig(t, normal) }
+func TestMissingFinalNewLine(t *testing.T) { testConfig(t, missingNewline) }
+
+func TestReadFromFile(t *testing.T) {
tempDir, err := ioutil.TempDir("", "")
if err != nil {
t.Fatalf("tempDir: %v", err)
@@ -27,7 +48,7 @@ func testConfig(t *testing.T, data string) {
defer os.RemoveAll(tempDir)
path := filepath.Join(tempDir, "resolv.conf")
- if err := ioutil.WriteFile(path, []byte(data), 0644); err != nil {
+ if err := ioutil.WriteFile(path, []byte(normal), 0644); err != nil {
t.Fatalf("writeFile: %v", err)
}
cc, err := ClientConfigFromFile(path)
@@ -46,9 +67,6 @@ func testConfig(t *testing.T, data string) {
}
}
-func TestNameserver(t *testing.T) { testConfig(t, normal) }
-func TestMissingFinalNewLine(t *testing.T) { testConfig(t, missingNewline) }
-
func TestNameList(t *testing.T) {
cfg := ClientConfig{
Ndots: 1,
diff --git a/vendor/github.com/miekg/dns/compress_generate.go b/vendor/github.com/miekg/dns/compress_generate.go
index 1a301e9f3..d2e5db26e 100644
--- a/vendor/github.com/miekg/dns/compress_generate.go
+++ b/vendor/github.com/miekg/dns/compress_generate.go
@@ -51,8 +51,9 @@ func main() {
fatalIfErr(err)
scope := pkg.Scope()
- domainTypes := map[string]bool{} // Types that have a domain name in them (either comressible or not).
- cdomainTypes := map[string]bool{} // Types that have a compressible domain name in them (subset of domainType)
+ var domainTypes []string // Types that have a domain name in them (either compressible or not).
+ var cdomainTypes []string // Types that have a compressible domain name in them (subset of domainType)
+Names:
for _, name := range scope.Names() {
o := scope.Lookup(name)
if o == nil || !o.Exported() {
@@ -73,21 +74,25 @@ func main() {
for i := 1; i < st.NumFields(); i++ {
if _, ok := st.Field(i).Type().(*types.Slice); ok {
if st.Tag(i) == `dns:"domain-name"` {
- domainTypes[o.Name()] = true
+ domainTypes = append(domainTypes, o.Name())
+ continue Names
}
if st.Tag(i) == `dns:"cdomain-name"` {
- cdomainTypes[o.Name()] = true
- domainTypes[o.Name()] = true
+ cdomainTypes = append(cdomainTypes, o.Name())
+ domainTypes = append(domainTypes, o.Name())
+ continue Names
}
continue
}
switch {
case st.Tag(i) == `dns:"domain-name"`:
- domainTypes[o.Name()] = true
+ domainTypes = append(domainTypes, o.Name())
+ continue Names
case st.Tag(i) == `dns:"cdomain-name"`:
- cdomainTypes[o.Name()] = true
- domainTypes[o.Name()] = true
+ cdomainTypes = append(cdomainTypes, o.Name())
+ domainTypes = append(domainTypes, o.Name())
+ continue Names
}
}
}
@@ -99,7 +104,7 @@ func main() {
fmt.Fprint(b, "func compressionLenHelperType(c map[string]int, r RR) {\n")
fmt.Fprint(b, "switch x := r.(type) {\n")
- for name, _ := range domainTypes {
+ for _, name := range domainTypes {
o := scope.Lookup(name)
st, _ := getTypeStruct(o.Type(), scope)
@@ -135,7 +140,7 @@ func main() {
fmt.Fprint(b, "func compressionLenSearchType(c map[string]int, r RR) (int, bool) {\n")
fmt.Fprint(b, "switch x := r.(type) {\n")
- for name, _ := range cdomainTypes {
+ for _, name := range cdomainTypes {
o := scope.Lookup(name)
st, _ := getTypeStruct(o.Type(), scope)
diff --git a/vendor/github.com/miekg/dns/dns.go b/vendor/github.com/miekg/dns/dns.go
index b3292287c..5133eac72 100644
--- a/vendor/github.com/miekg/dns/dns.go
+++ b/vendor/github.com/miekg/dns/dns.go
@@ -6,9 +6,12 @@ const (
year68 = 1 << 31 // For RFC1982 (Serial Arithmetic) calculations in 32 bits.
defaultTtl = 3600 // Default internal TTL.
- DefaultMsgSize = 4096 // DefaultMsgSize is the standard default for messages larger than 512 bytes.
- MinMsgSize = 512 // MinMsgSize is the minimal size of a DNS packet.
- MaxMsgSize = 65535 // MaxMsgSize is the largest possible DNS packet.
+ // DefaultMsgSize is the standard default for messages larger than 512 bytes.
+ DefaultMsgSize = 4096
+ // MinMsgSize is the minimal size of a DNS packet.
+ MinMsgSize = 512
+ // MaxMsgSize is the largest possible DNS packet.
+ MaxMsgSize = 65535
)
// Error represents a DNS error.
diff --git a/vendor/github.com/miekg/dns/dns_bench_test.go b/vendor/github.com/miekg/dns/dns_bench_test.go
index bccc3d540..7bf8bd211 100644
--- a/vendor/github.com/miekg/dns/dns_bench_test.go
+++ b/vendor/github.com/miekg/dns/dns_bench_test.go
@@ -17,7 +17,26 @@ func BenchmarkMsgLength(b *testing.B) {
return msg
}
name1 := "12345678901234567890123456789012345.12345678.123."
- rrMx, _ := NewRR(name1 + " 3600 IN MX 10 " + name1)
+ rrMx := testRR(name1 + " 3600 IN MX 10 " + name1)
+ msg := makeMsg(name1, []RR{rrMx, rrMx}, nil, nil)
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ msg.Len()
+ }
+}
+
+func BenchmarkMsgLengthNoCompression(b *testing.B) {
+ b.StopTimer()
+ makeMsg := func(question string, ans, ns, e []RR) *Msg {
+ msg := new(Msg)
+ msg.SetQuestion(Fqdn(question), TypeANY)
+ msg.Answer = append(msg.Answer, ans...)
+ msg.Ns = append(msg.Ns, ns...)
+ msg.Extra = append(msg.Extra, e...)
+ return msg
+ }
+ name1 := "12345678901234567890123456789012345.12345678.123."
+ rrMx := testRR(name1 + " 3600 IN MX 10 " + name1)
msg := makeMsg(name1, []RR{rrMx, rrMx}, nil, nil)
b.StartTimer()
for i := 0; i < b.N; i++ {
@@ -36,7 +55,7 @@ func BenchmarkMsgLengthPack(b *testing.B) {
return msg
}
name1 := "12345678901234567890123456789012345.12345678.123."
- rrMx, _ := NewRR(name1 + " 3600 IN MX 10 " + name1)
+ rrMx := testRR(name1 + " 3600 IN MX 10 " + name1)
msg := makeMsg(name1, []RR{rrMx, rrMx}, nil, nil)
b.ResetTimer()
for i := 0; i < b.N; i++ {
@@ -77,11 +96,11 @@ func BenchmarkCopy(b *testing.B) {
b.ReportAllocs()
m := new(Msg)
m.SetQuestion("miek.nl.", TypeA)
- rr, _ := NewRR("miek.nl. 2311 IN A 127.0.0.1")
+ rr := testRR("miek.nl. 2311 IN A 127.0.0.1")
m.Answer = []RR{rr}
- rr, _ = NewRR("miek.nl. 2311 IN NS 127.0.0.1")
+ rr = testRR("miek.nl. 2311 IN NS 127.0.0.1")
m.Ns = []RR{rr}
- rr, _ = NewRR("miek.nl. 2311 IN A 127.0.0.1")
+ rr = testRR("miek.nl. 2311 IN A 127.0.0.1")
m.Extra = []RR{rr}
b.ResetTimer()
@@ -139,7 +158,7 @@ func BenchmarkUnpackMX(b *testing.B) {
}
func BenchmarkPackAAAAA(b *testing.B) {
- aaaa, _ := NewRR(". IN A ::1")
+ aaaa := testRR(". IN A ::1")
buf := make([]byte, aaaa.len())
b.ReportAllocs()
@@ -150,7 +169,7 @@ func BenchmarkPackAAAAA(b *testing.B) {
}
func BenchmarkUnpackAAAA(b *testing.B) {
- aaaa, _ := NewRR(". IN A ::1")
+ aaaa := testRR(". IN A ::1")
buf := make([]byte, aaaa.len())
PackRR(aaaa, buf, 0, nil, false)
@@ -173,7 +192,7 @@ func BenchmarkPackMsg(b *testing.B) {
return msg
}
name1 := "12345678901234567890123456789012345.12345678.123."
- rrMx, _ := NewRR(name1 + " 3600 IN MX 10 " + name1)
+ rrMx := testRR(name1 + " 3600 IN MX 10 " + name1)
msg := makeMsg(name1, []RR{rrMx, rrMx}, nil, nil)
buf := make([]byte, 512)
b.ReportAllocs()
@@ -194,7 +213,7 @@ func BenchmarkUnpackMsg(b *testing.B) {
return msg
}
name1 := "12345678901234567890123456789012345.12345678.123."
- rrMx, _ := NewRR(name1 + " 3600 IN MX 10 " + name1)
+ rrMx := testRR(name1 + " 3600 IN MX 10 " + name1)
msg := makeMsg(name1, []RR{rrMx, rrMx}, nil, nil)
msgBuf, _ := msg.Pack()
b.ReportAllocs()
diff --git a/vendor/github.com/miekg/dns/dns_test.go b/vendor/github.com/miekg/dns/dns_test.go
index 5568c316c..5835c13d5 100644
--- a/vendor/github.com/miekg/dns/dns_test.go
+++ b/vendor/github.com/miekg/dns/dns_test.go
@@ -126,60 +126,17 @@ func TestBailiwick(t *testing.T) {
}
}
-func TestPack(t *testing.T) {
- rr := []string{"US. 86400 IN NSEC 0-.us. NS SOA RRSIG NSEC DNSKEY TYPE65534"}
- m := new(Msg)
- var err error
- m.Answer = make([]RR, 1)
- for _, r := range rr {
- m.Answer[0], err = NewRR(r)
- if err != nil {
- t.Errorf("failed to create RR: %v", err)
- continue
- }
- if _, err := m.Pack(); err != nil {
- t.Errorf("packing failed: %v", err)
- }
- }
- x := new(Msg)
- ns, _ := NewRR("pool.ntp.org. 390 IN NS a.ntpns.org")
- ns.(*NS).Ns = "a.ntpns.org"
- x.Ns = append(m.Ns, ns)
- x.Ns = append(m.Ns, ns)
- x.Ns = append(m.Ns, ns)
- // This crashes due to the fact the a.ntpns.org isn't a FQDN
- // How to recover() from a remove panic()?
- if _, err := x.Pack(); err == nil {
- t.Error("packing should fail")
- }
- x.Answer = make([]RR, 1)
- x.Answer[0], err = NewRR(rr[0])
- if err != nil {
- t.Fatal(err)
- }
- if _, err := x.Pack(); err == nil {
- t.Error("packing should fail")
- }
- x.Question = make([]Question, 1)
- x.Question[0] = Question{";sd#edddds鍛↙赏‘℅∥↙xzztsestxssweewwsssstx@s@Z嵌e@cn.pool.ntp.org.", TypeA, ClassINET}
- if _, err := x.Pack(); err == nil {
- t.Error("packing should fail")
- }
-}
-
func TestPackNAPTR(t *testing.T) {
for _, n := range []string{
`apple.com. IN NAPTR 100 50 "se" "SIP+D2U" "" _sip._udp.apple.com.`,
`apple.com. IN NAPTR 90 50 "se" "SIP+D2T" "" _sip._tcp.apple.com.`,
`apple.com. IN NAPTR 50 50 "se" "SIPS+D2T" "" _sips._tcp.apple.com.`,
} {
- rr, _ := NewRR(n)
+ rr := testRR(n)
msg := make([]byte, rr.len())
if off, err := PackRR(rr, msg, 0, nil, false); err != nil {
t.Errorf("packing failed: %v", err)
t.Errorf("length %d, need more than %d", rr.len(), off)
- } else {
- t.Logf("buf size needed: %d", off)
}
}
}
@@ -207,8 +164,8 @@ func TestMsgCompressLength(t *testing.T) {
}
name1 := "12345678901234567890123456789012345.12345678.123."
- rrA, _ := NewRR(name1 + " 3600 IN A 192.0.2.1")
- rrMx, _ := NewRR(name1 + " 3600 IN MX 10 " + name1)
+ rrA := testRR(name1 + " 3600 IN A 192.0.2.1")
+ rrMx := testRR(name1 + " 3600 IN MX 10 " + name1)
tests := []*Msg{
makeMsg(name1, []RR{rrA}, nil, nil),
makeMsg(name1, []RR{rrMx, rrMx}, nil, nil)}
@@ -237,8 +194,8 @@ func TestMsgLength(t *testing.T) {
}
name1 := "12345678901234567890123456789012345.12345678.123."
- rrA, _ := NewRR(name1 + " 3600 IN A 192.0.2.1")
- rrMx, _ := NewRR(name1 + " 3600 IN MX 10 " + name1)
+ rrA := testRR(name1 + " 3600 IN A 192.0.2.1")
+ rrMx := testRR(name1 + " 3600 IN MX 10 " + name1)
tests := []*Msg{
makeMsg(name1, []RR{rrA}, nil, nil),
makeMsg(name1, []RR{rrMx, rrMx}, nil, nil)}
@@ -331,14 +288,14 @@ func TestMsgCompressLength2(t *testing.T) {
}
func TestToRFC3597(t *testing.T) {
- a, _ := NewRR("miek.nl. IN A 10.0.1.1")
+ a := testRR("miek.nl. IN A 10.0.1.1")
x := new(RFC3597)
x.ToRFC3597(a)
if x.String() != `miek.nl. 3600 CLASS1 TYPE1 \# 4 0a000101` {
t.Errorf("string mismatch, got: %s", x)
}
- b, _ := NewRR("miek.nl. IN MX 10 mx.miek.nl.")
+ b := testRR("miek.nl. IN MX 10 mx.miek.nl.")
x.ToRFC3597(b)
if x.String() != `miek.nl. 3600 CLASS1 TYPE15 \# 14 000a026d78046d69656b026e6c00` {
t.Errorf("string mismatch, got: %s", x)
@@ -372,11 +329,9 @@ func TestNoRdataUnpack(t *testing.T) {
t.Errorf("failed to pack RR: %v", err)
continue
}
- rr, _, err := UnpackRR(data[:off], 0)
- if err != nil {
+ if _, _, err := UnpackRR(data[:off], 0); err != nil {
t.Errorf("failed to unpack RR with zero rdata: %s: %v", TypeToString[typ], err)
}
- t.Log(rr)
}
}
@@ -397,7 +352,7 @@ func TestRdataOverflow(t *testing.T) {
}
func TestCopy(t *testing.T) {
- rr, _ := NewRR("miek.nl. 2311 IN A 127.0.0.1") // Weird TTL to avoid catching TTL
+ rr := testRR("miek.nl. 2311 IN A 127.0.0.1") // Weird TTL to avoid catching TTL
rr1 := Copy(rr)
if rr.String() != rr1.String() {
t.Fatalf("Copy() failed %s != %s", rr.String(), rr1.String())
@@ -407,9 +362,9 @@ func TestCopy(t *testing.T) {
func TestMsgCopy(t *testing.T) {
m := new(Msg)
m.SetQuestion("miek.nl.", TypeA)
- rr, _ := NewRR("miek.nl. 2311 IN A 127.0.0.1")
+ rr := testRR("miek.nl. 2311 IN A 127.0.0.1")
m.Answer = []RR{rr}
- rr, _ = NewRR("miek.nl. 2311 IN NS 127.0.0.1")
+ rr = testRR("miek.nl. 2311 IN NS 127.0.0.1")
m.Ns = []RR{rr}
m1 := m.Copy()
@@ -417,12 +372,12 @@ func TestMsgCopy(t *testing.T) {
t.Fatalf("Msg.Copy() failed %s != %s", m.String(), m1.String())
}
- m1.Answer[0], _ = NewRR("somethingelse.nl. 2311 IN A 127.0.0.1")
+ m1.Answer[0] = testRR("somethingelse.nl. 2311 IN A 127.0.0.1")
if m.String() == m1.String() {
t.Fatalf("Msg.Copy() failed; change to copy changed template %s", m.String())
}
- rr, _ = NewRR("miek.nl. 2311 IN A 127.0.0.2")
+ rr = testRR("miek.nl. 2311 IN A 127.0.0.2")
m1.Answer = append(m1.Answer, rr)
if m1.Ns[0].String() == m1.Answer[1].String() {
t.Fatalf("Msg.Copy() failed; append changed underlying array %s", m1.Ns[0].String())
@@ -448,6 +403,5 @@ func TestMsgPackBuffer(t *testing.T) {
t.Errorf("packet %d failed to unpack", i)
continue
}
- t.Logf("packet %d %s", i, m.String())
}
}
diff --git a/vendor/github.com/miekg/dns/dnssec_test.go b/vendor/github.com/miekg/dns/dnssec_test.go
index ca085ed3b..d5de439ba 100644
--- a/vendor/github.com/miekg/dns/dnssec_test.go
+++ b/vendor/github.com/miekg/dns/dnssec_test.go
@@ -35,57 +35,6 @@ func getSoa() *SOA {
return soa
}
-func TestGenerateEC(t *testing.T) {
- if testing.Short() {
- t.Skip("skipping test in short mode.")
- }
- key := new(DNSKEY)
- key.Hdr.Rrtype = TypeDNSKEY
- key.Hdr.Name = "miek.nl."
- key.Hdr.Class = ClassINET
- key.Hdr.Ttl = 14400
- key.Flags = 256
- key.Protocol = 3
- key.Algorithm = ECDSAP256SHA256
- privkey, _ := key.Generate(256)
- t.Log(key.String())
- t.Log(key.PrivateKeyString(privkey))
-}
-
-func TestGenerateDSA(t *testing.T) {
- if testing.Short() {
- t.Skip("skipping test in short mode.")
- }
- key := new(DNSKEY)
- key.Hdr.Rrtype = TypeDNSKEY
- key.Hdr.Name = "miek.nl."
- key.Hdr.Class = ClassINET
- key.Hdr.Ttl = 14400
- key.Flags = 256
- key.Protocol = 3
- key.Algorithm = DSA
- privkey, _ := key.Generate(1024)
- t.Log(key.String())
- t.Log(key.PrivateKeyString(privkey))
-}
-
-func TestGenerateRSA(t *testing.T) {
- if testing.Short() {
- t.Skip("skipping test in short mode.")
- }
- key := new(DNSKEY)
- key.Hdr.Rrtype = TypeDNSKEY
- key.Hdr.Name = "miek.nl."
- key.Hdr.Class = ClassINET
- key.Hdr.Ttl = 14400
- key.Flags = 256
- key.Protocol = 3
- key.Algorithm = RSASHA256
- privkey, _ := key.Generate(1024)
- t.Log(key.String())
- t.Log(key.PrivateKeyString(privkey))
-}
-
func TestSecure(t *testing.T) {
soa := getSoa()
@@ -211,10 +160,9 @@ func TestSignVerify(t *testing.T) {
continue
}
if err := sig.Verify(key, []RR{r}); err != nil {
- t.Error("failure to validate")
+ t.Errorf("failure to validate: %s", r.Header().Name)
continue
}
- t.Logf("validated: %s", r.Header().Name)
}
}
@@ -248,9 +196,7 @@ func Test65534(t *testing.T) {
}
if err := sig.Verify(key, []RR{t6}); err != nil {
t.Error(err)
- t.Error("failure to validate")
- } else {
- t.Logf("validated: %s", t6.Header().Name)
+ t.Errorf("failure to validate %s", t6.Header().Name)
}
}
@@ -381,7 +327,7 @@ Created: 20110302104537
Publish: 20110302104537
Activate: 20110302104537`
- xk, _ := NewRR(pub)
+ xk := testRR(pub)
k := xk.(*DNSKEY)
p, err := k.NewPrivateKey(priv)
if err != nil {
@@ -432,10 +378,7 @@ func TestSignVerifyECDSA(t *testing.T) {
Algorithm: 14 (ECDSAP384SHA384)
PrivateKey: WURgWHCcYIYUPWgeLmiPY2DJJk02vgrmTfitxgqcL4vwW7BOrbawVmVe0d9V94SR`
- eckey, err := NewRR(pub)
- if err != nil {
- t.Fatal(err)
- }
+ eckey := testRR(pub)
privkey, err := eckey.(*DNSKEY).NewPrivateKey(priv)
if err != nil {
t.Fatal(err)
@@ -448,7 +391,7 @@ PrivateKey: WURgWHCcYIYUPWgeLmiPY2DJJk02vgrmTfitxgqcL4vwW7BOrbawVmVe0d9V94SR`
if ds.Digest != "72d7b62976ce06438e9c0bf319013cf801f09ecc84b8d7e9495f27e305c6a9b0563a9b5f4d288405c3008a946df983d6" {
t.Fatal("wrong DS Digest")
}
- a, _ := NewRR("www.example.net. 3600 IN A 192.0.2.1")
+ a := testRR("www.example.net. 3600 IN A 192.0.2.1")
sig := new(RRSIG)
sig.Hdr = RR_Header{"example.net.", TypeRRSIG, ClassINET, 14400, 0}
sig.Expiration, _ = StringToTime("20100909102025")
@@ -473,10 +416,7 @@ PrivateKey: WURgWHCcYIYUPWgeLmiPY2DJJk02vgrmTfitxgqcL4vwW7BOrbawVmVe0d9V94SR`
}
func TestSignVerifyECDSA2(t *testing.T) {
- srv1, err := NewRR("srv.miek.nl. IN SRV 1000 800 0 web1.miek.nl.")
- if err != nil {
- t.Fatal(err)
- }
+ srv1 := testRR("srv.miek.nl. IN SRV 1000 800 0 web1.miek.nl.")
srv := srv1.(*SRV)
// With this key
@@ -511,7 +451,7 @@ func TestSignVerifyECDSA2(t *testing.T) {
err = sig.Verify(key, []RR{srv})
if err != nil {
- t.Logf("failure to validate:\n%s\n%s\n%s\n\n%s\n\n%v",
+ t.Errorf("failure to validate:\n%s\n%s\n%s\n\n%s\n\n%v",
key.String(),
srv.String(),
sig.String(),
@@ -530,10 +470,7 @@ func TestRFC6605P256(t *testing.T) {
exPriv := `Private-key-format: v1.2
Algorithm: 13 (ECDSAP256SHA256)
PrivateKey: GU6SnQ/Ou+xC5RumuIUIuJZteXT2z0O/ok1s38Et6mQ=`
- rrDNSKEY, err := NewRR(exDNSKEY)
- if err != nil {
- t.Fatal(err)
- }
+ rrDNSKEY := testRR(exDNSKEY)
priv, err := rrDNSKEY.(*DNSKEY).NewPrivateKey(exPriv)
if err != nil {
t.Fatal(err)
@@ -542,10 +479,7 @@ PrivateKey: GU6SnQ/Ou+xC5RumuIUIuJZteXT2z0O/ok1s38Et6mQ=`
exDS := `example.net. 3600 IN DS 55648 13 2 (
b4c8c1fe2e7477127b27115656ad6256f424625bf5c1
e2770ce6d6e37df61d17 )`
- rrDS, err := NewRR(exDS)
- if err != nil {
- t.Fatal(err)
- }
+ rrDS := testRR(exDS)
ourDS := rrDNSKEY.(*DNSKEY).ToDS(SHA256)
if !reflect.DeepEqual(ourDS, rrDS.(*DS)) {
t.Errorf("DS record differs:\n%v\n%v", ourDS, rrDS.(*DS))
@@ -556,15 +490,9 @@ PrivateKey: GU6SnQ/Ou+xC5RumuIUIuJZteXT2z0O/ok1s38Et6mQ=`
20100909100439 20100812100439 55648 example.net.
qx6wLYqmh+l9oCKTN6qIc+bw6ya+KJ8oMz0YP107epXA
yGmt+3SNruPFKG7tZoLBLlUzGGus7ZwmwWep666VCw== )`
- rrA, err := NewRR(exA)
- if err != nil {
- t.Fatal(err)
- }
- rrRRSIG, err := NewRR(exRRSIG)
- if err != nil {
- t.Fatal(err)
- }
- if err = rrRRSIG.(*RRSIG).Verify(rrDNSKEY.(*DNSKEY), []RR{rrA}); err != nil {
+ rrA := testRR(exA)
+ rrRRSIG := testRR(exRRSIG)
+ if err := rrRRSIG.(*RRSIG).Verify(rrDNSKEY.(*DNSKEY), []RR{rrA}); err != nil {
t.Errorf("failure to validate the spec RRSIG: %v", err)
}
@@ -604,10 +532,7 @@ func TestRFC6605P384(t *testing.T) {
exPriv := `Private-key-format: v1.2
Algorithm: 14 (ECDSAP384SHA384)
PrivateKey: WURgWHCcYIYUPWgeLmiPY2DJJk02vgrmTfitxgqcL4vwW7BOrbawVmVe0d9V94SR`
- rrDNSKEY, err := NewRR(exDNSKEY)
- if err != nil {
- t.Fatal(err)
- }
+ rrDNSKEY := testRR(exDNSKEY)
priv, err := rrDNSKEY.(*DNSKEY).NewPrivateKey(exPriv)
if err != nil {
t.Fatal(err)
@@ -617,10 +542,7 @@ PrivateKey: WURgWHCcYIYUPWgeLmiPY2DJJk02vgrmTfitxgqcL4vwW7BOrbawVmVe0d9V94SR`
72d7b62976ce06438e9c0bf319013cf801f09ecc84b8
d7e9495f27e305c6a9b0563a9b5f4d288405c3008a94
6df983d6 )`
- rrDS, err := NewRR(exDS)
- if err != nil {
- t.Fatal(err)
- }
+ rrDS := testRR(exDS)
ourDS := rrDNSKEY.(*DNSKEY).ToDS(SHA384)
if !reflect.DeepEqual(ourDS, rrDS.(*DS)) {
t.Fatalf("DS record differs:\n%v\n%v", ourDS, rrDS.(*DS))
@@ -632,11 +554,8 @@ PrivateKey: WURgWHCcYIYUPWgeLmiPY2DJJk02vgrmTfitxgqcL4vwW7BOrbawVmVe0d9V94SR`
/L5hDKIvGDyI1fcARX3z65qrmPsVz73QD1Mr5CEqOiLP
95hxQouuroGCeZOvzFaxsT8Glr74hbavRKayJNuydCuz
WTSSPdz7wnqXL5bdcJzusdnI0RSMROxxwGipWcJm )`
- rrA, err := NewRR(exA)
- if err != nil {
- t.Fatal(err)
- }
- rrRRSIG, err := NewRR(exRRSIG)
+ rrA := testRR(exA)
+ rrRRSIG := testRR(exRRSIG)
if err != nil {
t.Fatal(err)
}
diff --git a/vendor/github.com/miekg/dns/dnsutil/util.go b/vendor/github.com/miekg/dns/dnsutil/util.go
index c8c6af7b3..76ac4de66 100644
--- a/vendor/github.com/miekg/dns/dnsutil/util.go
+++ b/vendor/github.com/miekg/dns/dnsutil/util.go
@@ -20,7 +20,9 @@ import (
func AddOrigin(s, origin string) string {
// ("foo.", "origin.") -> "foo." (already a FQDN)
// ("foo", "origin.") -> "foo.origin."
- // ("foo"), "origin" -> "foo.origin"
+ // ("foo", "origin") -> "foo.origin"
+ // ("foo", ".") -> "foo." (Same as dns.Fqdn())
+ // ("foo.", ".") -> "foo." (Same as dns.Fqdn())
// ("@", "origin.") -> "origin." (@ represents the apex (bare) domain)
// ("", "origin.") -> "origin." (not obvious)
// ("foo", "") -> "foo" (not obvious)
@@ -34,32 +36,34 @@ func AddOrigin(s, origin string) string {
if s == "@" || len(s) == 0 {
return origin // Expand apex.
}
-
if origin == "." {
- return s + origin // AddOrigin(s, ".") is an expensive way to add a ".".
+ return dns.Fqdn(s)
}
return s + "." + origin // The simple case.
}
// TrimDomainName trims origin from s if s is a subdomain.
-// This function will never return "", but returns "@" instead (@ represents the apex (bare) domain).
+// This function will never return "", but returns "@" instead (@ represents the apex domain).
func TrimDomainName(s, origin string) string {
// An apex (bare) domain is always returned as "@".
// If the return value ends in a ".", the domain was not the suffix.
// origin can end in "." or not. Either way the results should be the same.
if len(s) == 0 {
- return "@" // Return the apex (@) rather than "".
+ return "@"
}
// Someone is using TrimDomainName(s, ".") to remove a dot if it exists.
if origin == "." {
return strings.TrimSuffix(s, origin)
}
- // Dude, you aren't even if the right subdomain!
+ original := s
+ s = dns.Fqdn(s)
+ origin = dns.Fqdn(origin)
+
if !dns.IsSubDomain(origin, s) {
- return s
+ return original
}
slabels := dns.Split(s)
diff --git a/vendor/github.com/miekg/dns/dnsutil/util_test.go b/vendor/github.com/miekg/dns/dnsutil/util_test.go
index 0f1ecec8e..6754789bc 100644
--- a/vendor/github.com/miekg/dns/dnsutil/util_test.go
+++ b/vendor/github.com/miekg/dns/dnsutil/util_test.go
@@ -10,6 +10,8 @@ func TestAddOrigin(t *testing.T) {
{"@", "example.com.", "example.com."},
{"foo", "example.com.", "foo.example.com."},
{"foo.", "example.com.", "foo."},
+ {"example.com", ".", "example.com."},
+ {"example.com.", ".", "example.com."},
// Oddball tests:
// In general origin should not be "" or "." but at least
// these tests verify we don't crash and will keep results
@@ -26,16 +28,15 @@ func TestAddOrigin(t *testing.T) {
for _, test := range tests {
actual := AddOrigin(test.e1, test.e2)
if test.expected != actual {
- t.Errorf("AddOrigin(%#v, %#v) expected %#v, go %#v\n", test.e1, test.e2, test.expected, actual)
+ t.Errorf("AddOrigin(%#v, %#v) expected %#v, got %#v\n", test.e1, test.e2, test.expected, actual)
}
}
}
func TestTrimDomainName(t *testing.T) {
-
// Basic tests.
// Try trimming "example.com" and "example.com." from typical use cases.
- var tests_examplecom = []struct{ experiment, expected string }{
+ testsEx := []struct{ experiment, expected string }{
{"foo.example.com", "foo"},
{"foo.example.com.", "foo"},
{".foo.example.com", ".foo"},
@@ -51,10 +52,10 @@ func TestTrimDomainName(t *testing.T) {
{".foo.ronco.com.", ".foo.ronco.com."},
}
for _, dom := range []string{"example.com", "example.com."} {
- for i, test := range tests_examplecom {
+ for i, test := range testsEx {
actual := TrimDomainName(test.experiment, dom)
if test.expected != actual {
- t.Errorf("%d TrimDomainName(%#v, %#v): expected (%v) got (%v)\n", i, test.experiment, dom, test.expected, actual)
+ t.Errorf("%d TrimDomainName(%#v, %#v): expected %v, got %v\n", i, test.experiment, dom, test.expected, actual)
}
}
}
@@ -63,7 +64,7 @@ func TestTrimDomainName(t *testing.T) {
// These test shouldn't be needed but I was weary of off-by-one errors.
// In theory, these can't happen because there are no single-letter TLDs,
// but it is good to exercize the code this way.
- var tests = []struct{ experiment, expected string }{
+ tests := []struct{ experiment, expected string }{
{"", "@"},
{".", "."},
{"a.b.c.d.e.f.", "a.b.c.d.e"},
@@ -105,7 +106,7 @@ func TestTrimDomainName(t *testing.T) {
for i, test := range tests {
actual := TrimDomainName(test.experiment, dom)
if test.expected != actual {
- t.Errorf("%d TrimDomainName(%#v, %#v): expected (%v) got (%v)\n", i, test.experiment, dom, test.expected, actual)
+ t.Errorf("%d TrimDomainName(%#v, %#v): expected %v, got %v\n", i, test.experiment, dom, test.expected, actual)
}
}
}
@@ -114,17 +115,16 @@ func TestTrimDomainName(t *testing.T) {
// These test cases provide both origin, s, and the expected result.
// If you find a bug in the while, this is probably the easiest place
// to add it as a test case.
- var tests_wild = []struct{ e1, e2, expected string }{
+ var testsWild = []struct{ e1, e2, expected string }{
{"mathoverflow.net.", ".", "mathoverflow.net"},
{"mathoverflow.net", ".", "mathoverflow.net"},
{"", ".", "@"},
{"@", ".", "@"},
}
- for i, test := range tests_wild {
+ for i, test := range testsWild {
actual := TrimDomainName(test.e1, test.e2)
if test.expected != actual {
- t.Errorf("%d TrimDomainName(%#v, %#v): expected (%v) got (%v)\n", i, test.e1, test.e2, test.expected, actual)
+ t.Errorf("%d TrimDomainName(%#v, %#v): expected %v, got %v\n", i, test.e1, test.e2, test.expected, actual)
}
}
-
}
diff --git a/vendor/github.com/miekg/dns/doc.go b/vendor/github.com/miekg/dns/doc.go
index ceabd24c1..26e288dfe 100644
--- a/vendor/github.com/miekg/dns/doc.go
+++ b/vendor/github.com/miekg/dns/doc.go
@@ -168,6 +168,11 @@ Basic use pattern when querying with a TSIG name "axfr." (note that these key na
must be fully qualified - as they are domain names) and the base64 secret
"so6ZGir4GPAqINNh9U5c3A==":
+If an incoming message contains a TSIG record it MUST be the last record in
+the additional section (RFC2845 3.2). This means that you should make the
+call to SetTsig last, right before executing the query. If you make any
+changes to the RRset after calling SetTsig() the signature will be incorrect.
+
c := new(dns.Client)
c.TsigSecret = map[string]string{"axfr.": "so6ZGir4GPAqINNh9U5c3A=="}
m := new(dns.Msg)
diff --git a/vendor/github.com/miekg/dns/edns.go b/vendor/github.com/miekg/dns/edns.go
index 718842f28..a6a36bdf2 100644
--- a/vendor/github.com/miekg/dns/edns.go
+++ b/vendor/github.com/miekg/dns/edns.go
@@ -106,15 +106,12 @@ func (rr *OPT) SetVersion(v uint8) {
// ExtendedRcode returns the EDNS extended RCODE field (the upper 8 bits of the TTL).
func (rr *OPT) ExtendedRcode() int {
- return int((rr.Hdr.Ttl&0xFF000000)>>24) + 15
+ return int((rr.Hdr.Ttl & 0xFF000000) >> 24)
}
// SetExtendedRcode sets the EDNS extended RCODE field.
func (rr *OPT) SetExtendedRcode(v uint8) {
- if v < RcodeBadVers { // Smaller than 16.. Use the 4 bits you have!
- return
- }
- rr.Hdr.Ttl = rr.Hdr.Ttl&0x00FFFFFF | (uint32(v-15) << 24)
+ rr.Hdr.Ttl = rr.Hdr.Ttl&0x00FFFFFF | (uint32(v) << 24)
}
// UDPSize returns the UDP buffer size.
@@ -185,7 +182,8 @@ func (e *EDNS0_NSID) pack() ([]byte, error) {
return h, nil
}
-func (e *EDNS0_NSID) Option() uint16 { return EDNS0NSID }
+// Option implements the EDNS0 interface.
+func (e *EDNS0_NSID) Option() uint16 { return EDNS0NSID } // Option returns the option code.
func (e *EDNS0_NSID) unpack(b []byte) error { e.Nsid = hex.EncodeToString(b); return nil }
func (e *EDNS0_NSID) String() string { return string(e.Nsid) }
@@ -219,6 +217,7 @@ type EDNS0_SUBNET struct {
DraftOption bool // Set to true if using the old (0x50fa) option code
}
+// Option implements the EDNS0 interface.
func (e *EDNS0_SUBNET) Option() uint16 {
if e.DraftOption {
return EDNS0SUBNETDRAFT
@@ -232,6 +231,12 @@ func (e *EDNS0_SUBNET) pack() ([]byte, error) {
b[2] = e.SourceNetmask
b[3] = e.SourceScope
switch e.Family {
+ case 0:
+ // "dig" sets AddressFamily to 0 if SourceNetmask is also 0
+ // We might don't need to complain either
+ if e.SourceNetmask != 0 {
+ return nil, errors.New("dns: bad address family")
+ }
case 1:
if e.SourceNetmask > net.IPv4len*8 {
return nil, errors.New("dns: bad netmask")
@@ -266,6 +271,13 @@ func (e *EDNS0_SUBNET) unpack(b []byte) error {
e.SourceNetmask = b[2]
e.SourceScope = b[3]
switch e.Family {
+ case 0:
+ // "dig" sets AddressFamily to 0 if SourceNetmask is also 0
+ // It's okay to accept such a packet
+ if e.SourceNetmask != 0 {
+ return errors.New("dns: bad address family")
+ }
+ e.Address = net.IPv4(0, 0, 0, 0)
case 1:
if e.SourceNetmask > net.IPv4len*8 || e.SourceScope > net.IPv4len*8 {
return errors.New("dns: bad netmask")
@@ -335,6 +347,7 @@ func (e *EDNS0_COOKIE) pack() ([]byte, error) {
return h, nil
}
+// Option implements the EDNS0 interface.
func (e *EDNS0_COOKIE) Option() uint16 { return EDNS0COOKIE }
func (e *EDNS0_COOKIE) unpack(b []byte) error { e.Cookie = hex.EncodeToString(b); return nil }
func (e *EDNS0_COOKIE) String() string { return e.Cookie }
@@ -356,6 +369,7 @@ type EDNS0_UL struct {
Lease uint32
}
+// Option implements the EDNS0 interface.
func (e *EDNS0_UL) Option() uint16 { return EDNS0UL }
func (e *EDNS0_UL) String() string { return strconv.FormatUint(uint64(e.Lease), 10) }
@@ -385,6 +399,7 @@ type EDNS0_LLQ struct {
LeaseLife uint32
}
+// Option implements the EDNS0 interface.
func (e *EDNS0_LLQ) Option() uint16 { return EDNS0LLQ }
func (e *EDNS0_LLQ) pack() ([]byte, error) {
@@ -421,6 +436,7 @@ type EDNS0_DAU struct {
AlgCode []uint8
}
+// Option implements the EDNS0 interface.
func (e *EDNS0_DAU) Option() uint16 { return EDNS0DAU }
func (e *EDNS0_DAU) pack() ([]byte, error) { return e.AlgCode, nil }
func (e *EDNS0_DAU) unpack(b []byte) error { e.AlgCode = b; return nil }
@@ -442,6 +458,7 @@ type EDNS0_DHU struct {
AlgCode []uint8
}
+// Option implements the EDNS0 interface.
func (e *EDNS0_DHU) Option() uint16 { return EDNS0DHU }
func (e *EDNS0_DHU) pack() ([]byte, error) { return e.AlgCode, nil }
func (e *EDNS0_DHU) unpack(b []byte) error { e.AlgCode = b; return nil }
@@ -463,6 +480,7 @@ type EDNS0_N3U struct {
AlgCode []uint8
}
+// Option implements the EDNS0 interface.
func (e *EDNS0_N3U) Option() uint16 { return EDNS0N3U }
func (e *EDNS0_N3U) pack() ([]byte, error) { return e.AlgCode, nil }
func (e *EDNS0_N3U) unpack(b []byte) error { e.AlgCode = b; return nil }
@@ -485,6 +503,7 @@ type EDNS0_EXPIRE struct {
Expire uint32
}
+// Option implements the EDNS0 interface.
func (e *EDNS0_EXPIRE) Option() uint16 { return EDNS0EXPIRE }
func (e *EDNS0_EXPIRE) String() string { return strconv.FormatUint(uint64(e.Expire), 10) }
@@ -523,6 +542,7 @@ type EDNS0_LOCAL struct {
Data []byte
}
+// Option implements the EDNS0 interface.
func (e *EDNS0_LOCAL) Option() uint16 { return e.Code }
func (e *EDNS0_LOCAL) String() string {
return strconv.FormatInt(int64(e.Code), 10) + ":0x" + hex.EncodeToString(e.Data)
@@ -554,6 +574,7 @@ type EDNS0_TCP_KEEPALIVE struct {
Timeout uint16 // an idle timeout value for the TCP connection, specified in units of 100 milliseconds, encoded in network byte order.
}
+// Option implements the EDNS0 interface.
func (e *EDNS0_TCP_KEEPALIVE) Option() uint16 { return EDNS0TCPKEEPALIVE }
func (e *EDNS0_TCP_KEEPALIVE) pack() ([]byte, error) {
@@ -606,7 +627,8 @@ type EDNS0_PADDING struct {
Padding []byte
}
-func (e *EDNS0_PADDING) pack() ([]byte, error) { return e.Padding, nil }
+// Option implements the EDNS0 interface.
func (e *EDNS0_PADDING) Option() uint16 { return EDNS0PADDING }
+func (e *EDNS0_PADDING) pack() ([]byte, error) { return e.Padding, nil }
func (e *EDNS0_PADDING) unpack(b []byte) error { e.Padding = b; return nil }
func (e *EDNS0_PADDING) String() string { return fmt.Sprintf("%0X", e.Padding) }
diff --git a/vendor/github.com/miekg/dns/edns_test.go b/vendor/github.com/miekg/dns/edns_test.go
index c290b0c8a..f7cf15754 100644
--- a/vendor/github.com/miekg/dns/edns_test.go
+++ b/vendor/github.com/miekg/dns/edns_test.go
@@ -63,6 +63,6 @@ func TestOPTTtl(t *testing.T) {
e.SetExtendedRcode(42)
if e.ExtendedRcode() != 42 {
- t.Errorf("set 42, expected %d, got %d", 42-15, e.ExtendedRcode())
+ t.Errorf("set 42, expected %d, got %d", 42, e.ExtendedRcode())
}
}
diff --git a/vendor/github.com/miekg/dns/issue_test.go b/vendor/github.com/miekg/dns/issue_test.go
index 265ad56c0..7299d3143 100644
--- a/vendor/github.com/miekg/dns/issue_test.go
+++ b/vendor/github.com/miekg/dns/issue_test.go
@@ -26,10 +26,7 @@ func TestTCPRtt(t *testing.T) {
}
func TestNSEC3MissingSalt(t *testing.T) {
- rr, err := NewRR("ji6neoaepv8b5o6k4ev33abha8ht9fgc.example. NSEC3 1 1 12 aabbccdd K8UDEMVP1J2F7EG6JEBPS17VP3N8I58H")
- if err != nil {
- t.Fatalf("failed to parse example rr: %s", err)
- }
+ rr := testRR("ji6neoaepv8b5o6k4ev33abha8ht9fgc.example. NSEC3 1 1 12 aabbccdd K8UDEMVP1J2F7EG6JEBPS17VP3N8I58H")
m := new(Msg)
m.Answer = []RR{rr}
mb, err := m.Pack()
@@ -47,10 +44,7 @@ func TestNSEC3MissingSalt(t *testing.T) {
}
func TestNSEC3MixedNextDomain(t *testing.T) {
- rr, err := NewRR("ji6neoaepv8b5o6k4ev33abha8ht9fgc.example. NSEC3 1 1 12 - k8udemvp1j2f7eg6jebps17vp3n8i58h")
- if err != nil {
- t.Fatalf("failed to parse example rr: %s", err)
- }
+ rr := testRR("ji6neoaepv8b5o6k4ev33abha8ht9fgc.example. NSEC3 1 1 12 - k8udemvp1j2f7eg6jebps17vp3n8i58h")
m := new(Msg)
m.Answer = []RR{rr}
mb, err := m.Pack()
diff --git a/vendor/github.com/miekg/dns/labels.go b/vendor/github.com/miekg/dns/labels.go
index 9538d9c3a..760b89e71 100644
--- a/vendor/github.com/miekg/dns/labels.go
+++ b/vendor/github.com/miekg/dns/labels.go
@@ -1,7 +1,5 @@
package dns
-import "strings"
-
// Holds a bunch of helper functions for dealing with labels.
// SplitDomainName splits a name string into it's labels.
@@ -44,7 +42,7 @@ func SplitDomainName(s string) (labels []string) {
// CompareDomainName compares the names s1 and s2 and
// returns how many labels they have in common starting from the *right*.
-// The comparison stops at the first inequality. The names are not downcased
+// The comparison stops at the first inequality. The names are downcased
// before the comparison.
//
// www.miek.nl. and miek.nl. have two labels in common: miek and nl
@@ -52,24 +50,21 @@ func SplitDomainName(s string) (labels []string) {
//
// s1 and s2 must be syntactically valid domain names.
func CompareDomainName(s1, s2 string) (n int) {
- s1, s2 = strings.ToLower(s1), strings.ToLower(s2)
- s1 = Fqdn(s1)
- s2 = Fqdn(s2)
- l1 := Split(s1)
- l2 := Split(s2)
-
// the first check: root label
- if l1 == nil || l2 == nil {
- return
+ if s1 == "." || s2 == "." {
+ return 0
}
+ l1 := Split(s1)
+ l2 := Split(s2)
+
j1 := len(l1) - 1 // end
i1 := len(l1) - 2 // start
j2 := len(l2) - 1
i2 := len(l2) - 2
// the second check can be done here: last/only label
// before we fall through into the for-loop below
- if s1[l1[j1]:] == s2[l2[j2]:] {
+ if equal(s1[l1[j1]:], s2[l2[j2]:]) {
n++
} else {
return
@@ -78,7 +73,7 @@ func CompareDomainName(s1, s2 string) (n int) {
if i1 < 0 || i2 < 0 {
break
}
- if s1[l1[i1]:l1[j1]] == s2[l2[i2]:l2[j2]] {
+ if equal(s1[l1[i1]:l1[j1]], s2[l2[i2]:l2[j2]]) {
n++
} else {
break
@@ -169,3 +164,28 @@ func PrevLabel(s string, n int) (i int, start bool) {
}
return lab[len(lab)-n], false
}
+
+// equal compares a and b while ignoring case. It returns true when equal otherwise false.
+func equal(a, b string) bool {
+ // might be lifted into API function.
+ la := len(a)
+ lb := len(b)
+ if la != lb {
+ return false
+ }
+
+ for i := la - 1; i >= 0; i-- {
+ ai := a[i]
+ bi := b[i]
+ if ai >= 'A' && ai <= 'Z' {
+ ai |= ('a' - 'A')
+ }
+ if bi >= 'A' && bi <= 'Z' {
+ bi |= ('a' - 'A')
+ }
+ if ai != bi {
+ return false
+ }
+ }
+ return true
+}
diff --git a/vendor/github.com/miekg/dns/labels_test.go b/vendor/github.com/miekg/dns/labels_test.go
index 9875d6cd9..d9bb556df 100644
--- a/vendor/github.com/miekg/dns/labels_test.go
+++ b/vendor/github.com/miekg/dns/labels_test.go
@@ -7,8 +7,8 @@ func TestCompareDomainName(t *testing.T) {
s2 := "miek.nl."
s3 := "www.bla.nl."
s4 := "nl.www.bla."
- s5 := "nl"
- s6 := "miek.nl"
+ s5 := "nl."
+ s6 := "miek.nl."
if CompareDomainName(s1, s2) != 2 {
t.Errorf("%s with %s should be %d", s1, s2, 2)
@@ -54,8 +54,6 @@ func TestSplit(t *testing.T) {
for s, i := range splitter {
if x := len(Split(s)); x != i {
t.Errorf("labels should be %d, got %d: %s %v", i, x, s, Split(s))
- } else {
- t.Logf("%s %v", s, Split(s))
}
}
}
@@ -87,19 +85,19 @@ func TestPrevLabel(t *testing.T) {
int
}
prever := map[prev]int{
- prev{"www.miek.nl.", 0}: 12,
- prev{"www.miek.nl.", 1}: 9,
- prev{"www.miek.nl.", 2}: 4,
+ {"www.miek.nl.", 0}: 12,
+ {"www.miek.nl.", 1}: 9,
+ {"www.miek.nl.", 2}: 4,
- prev{"www.miek.nl", 0}: 11,
- prev{"www.miek.nl", 1}: 9,
- prev{"www.miek.nl", 2}: 4,
+ {"www.miek.nl", 0}: 11,
+ {"www.miek.nl", 1}: 9,
+ {"www.miek.nl", 2}: 4,
- prev{"www.miek.nl.", 5}: 0,
- prev{"www.miek.nl", 5}: 0,
+ {"www.miek.nl.", 5}: 0,
+ {"www.miek.nl", 5}: 0,
- prev{"www.miek.nl.", 3}: 0,
- prev{"www.miek.nl", 3}: 0,
+ {"www.miek.nl.", 3}: 0,
+ {"www.miek.nl", 3}: 0,
}
for s, i := range prever {
x, ok := PrevLabel(s.string, s.int)
@@ -176,28 +174,28 @@ func TestIsDomainName(t *testing.T) {
func BenchmarkSplitLabels(b *testing.B) {
for i := 0; i < b.N; i++ {
- Split("www.example.com")
+ Split("www.example.com.")
}
}
func BenchmarkLenLabels(b *testing.B) {
for i := 0; i < b.N; i++ {
- CountLabel("www.example.com")
+ CountLabel("www.example.com.")
}
}
-func BenchmarkCompareLabels(b *testing.B) {
+func BenchmarkCompareDomainName(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
- CompareDomainName("www.example.com", "aa.example.com")
+ CompareDomainName("www.example.com.", "aa.example.com.")
}
}
func BenchmarkIsSubDomain(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
- IsSubDomain("www.example.com", "aa.example.com")
- IsSubDomain("example.com", "aa.example.com")
- IsSubDomain("miek.nl", "aa.example.com")
+ IsSubDomain("www.example.com.", "aa.example.com.")
+ IsSubDomain("example.com.", "aa.example.com.")
+ IsSubDomain("miek.nl.", "aa.example.com.")
}
}
diff --git a/vendor/github.com/miekg/dns/msg.go b/vendor/github.com/miekg/dns/msg.go
index 605fe6c5c..afce17635 100644
--- a/vendor/github.com/miekg/dns/msg.go
+++ b/vendor/github.com/miekg/dns/msg.go
@@ -26,6 +26,7 @@ const (
maxDomainNameWireOctets = 255 // See RFC 1035 section 2.3.4
)
+// Errors defined in this package.
var (
ErrAlg error = &Error{err: "bad algorithm"} // ErrAlg indicates an error with the (DNSSEC) algorithm.
ErrAuth error = &Error{err: "bad authentication"} // ErrAuth indicates an error in the TSIG authentication.
@@ -57,7 +58,7 @@ var (
// For instance, to make it return a static value:
//
// dns.Id = func() uint16 { return 3 }
-var Id func() uint16 = id
+var Id = id
var (
idLock sync.Mutex
@@ -360,7 +361,7 @@ Loop:
case '"', '\\':
s = append(s, '\\', b)
// presentation-format \X escapes add an extra byte
- maxLen += 1
+ maxLen++
default:
if b < 32 || b >= 127 { // unprintable, use \DDD
var buf [3]byte
@@ -913,67 +914,55 @@ func (dns *Msg) Len() int { return compressedLen(dns, dns.Compress) }
func compressedLen(dns *Msg, compress bool) int {
// We always return one more than needed.
l := 12 // Message header is always 12 bytes
- compression := map[string]int{}
-
- for i := 0; i < len(dns.Question); i++ {
- l += dns.Question[i].len()
- if compress {
- compressionLenHelper(compression, dns.Question[i].Name)
+ if compress {
+ compression := map[string]int{}
+ for _, r := range dns.Question {
+ l += r.len()
+ compressionLenHelper(compression, r.Name)
}
- }
- for i := 0; i < len(dns.Answer); i++ {
- if dns.Answer[i] == nil {
- continue
+ l += compressionLenSlice(compression, dns.Answer)
+ l += compressionLenSlice(compression, dns.Ns)
+ l += compressionLenSlice(compression, dns.Extra)
+ } else {
+ for _, r := range dns.Question {
+ l += r.len()
}
- l += dns.Answer[i].len()
- if compress {
- k, ok := compressionLenSearch(compression, dns.Answer[i].Header().Name)
- if ok {
- l += 1 - k
+ for _, r := range dns.Answer {
+ if r != nil {
+ l += r.len()
}
- compressionLenHelper(compression, dns.Answer[i].Header().Name)
- k, ok = compressionLenSearchType(compression, dns.Answer[i])
- if ok {
- l += 1 - k
- }
- compressionLenHelperType(compression, dns.Answer[i])
- }
- }
- for i := 0; i < len(dns.Ns); i++ {
- if dns.Ns[i] == nil {
- continue
}
- l += dns.Ns[i].len()
- if compress {
- k, ok := compressionLenSearch(compression, dns.Ns[i].Header().Name)
- if ok {
- l += 1 - k
+ for _, r := range dns.Ns {
+ if r != nil {
+ l += r.len()
}
- compressionLenHelper(compression, dns.Ns[i].Header().Name)
- k, ok = compressionLenSearchType(compression, dns.Ns[i])
- if ok {
- l += 1 - k
+ }
+ for _, r := range dns.Extra {
+ if r != nil {
+ l += r.len()
}
- compressionLenHelperType(compression, dns.Ns[i])
}
}
- for i := 0; i < len(dns.Extra); i++ {
- if dns.Extra[i] == nil {
+ return l
+}
+
+func compressionLenSlice(c map[string]int, rs []RR) int {
+ var l int
+ for _, r := range rs {
+ if r == nil {
continue
}
- l += dns.Extra[i].len()
- if compress {
- k, ok := compressionLenSearch(compression, dns.Extra[i].Header().Name)
- if ok {
- l += 1 - k
- }
- compressionLenHelper(compression, dns.Extra[i].Header().Name)
- k, ok = compressionLenSearchType(compression, dns.Extra[i])
- if ok {
- l += 1 - k
- }
- compressionLenHelperType(compression, dns.Extra[i])
+ l += r.len()
+ k, ok := compressionLenSearch(c, r.Header().Name)
+ if ok {
+ l += 1 - k
+ }
+ compressionLenHelper(c, r.Header().Name)
+ k, ok = compressionLenSearchType(c, r)
+ if ok {
+ l += 1 - k
}
+ compressionLenHelperType(c, r)
}
return l
}
diff --git a/vendor/github.com/miekg/dns/nsecx_test.go b/vendor/github.com/miekg/dns/nsecx_test.go
index 8d5f71797..f8edd6db1 100644
--- a/vendor/github.com/miekg/dns/nsecx_test.go
+++ b/vendor/github.com/miekg/dns/nsecx_test.go
@@ -15,7 +15,7 @@ func TestPackNsec3(t *testing.T) {
}
func TestNsec3(t *testing.T) {
- nsec3, _ := NewRR("sk4e8fj94u78smusb40o1n0oltbblu2r.nl. IN NSEC3 1 1 5 F10E9F7EA83FC8F3 SK4F38CQ0ATIEI8MH3RGD0P5I4II6QAN NS SOA TXT RRSIG DNSKEY NSEC3PARAM")
+ nsec3 := testRR("sk4e8fj94u78smusb40o1n0oltbblu2r.nl. IN NSEC3 1 1 5 F10E9F7EA83FC8F3 SK4F38CQ0ATIEI8MH3RGD0P5I4II6QAN NS SOA TXT RRSIG DNSKEY NSEC3PARAM")
if !nsec3.(*NSEC3).Match("nl.") { // name hash = sk4e8fj94u78smusb40o1n0oltbblu2r
t.Fatal("sk4e8fj94u78smusb40o1n0oltbblu2r.nl. should match sk4e8fj94u78smusb40o1n0oltbblu2r.nl.")
}
@@ -28,7 +28,7 @@ func TestNsec3(t *testing.T) {
if nsec3.(*NSEC3).Match("test.nl.") { // name hash = gd0ptr5bnfpimpu2d3v6gd4n0bai7s0q
t.Fatal("gd0ptr5bnfpimpu2d3v6gd4n0bai7s0q.nl. should not match sk4e8fj94u78smusb40o1n0oltbblu2r.nl.")
}
- nsec3, _ = NewRR("nl. IN NSEC3 1 1 5 F10E9F7EA83FC8F3 SK4F38CQ0ATIEI8MH3RGD0P5I4II6QAN NS SOA TXT RRSIG DNSKEY NSEC3PARAM")
+ nsec3 = testRR("nl. IN NSEC3 1 1 5 F10E9F7EA83FC8F3 SK4F38CQ0ATIEI8MH3RGD0P5I4II6QAN NS SOA TXT RRSIG DNSKEY NSEC3PARAM")
if nsec3.(*NSEC3).Match("nl.") {
t.Fatal("sk4e8fj94u78smusb40o1n0oltbblu2r.nl. should not match a record without a owner hash")
}
@@ -127,7 +127,7 @@ func TestNsec3(t *testing.T) {
} {
covers := tc.rr.Cover(tc.name)
if tc.covers != covers {
- t.Fatalf("Cover failed for %s: expected %t, got %t [record: %s]", tc.name, tc.covers, covers, tc.rr)
+ t.Fatalf("cover failed for %s: expected %t, got %t [record: %s]", tc.name, tc.covers, covers, tc.rr)
}
}
}
diff --git a/vendor/github.com/miekg/dns/parse_test.go b/vendor/github.com/miekg/dns/parse_test.go
index c7ecb499d..e7ffd4084 100644
--- a/vendor/github.com/miekg/dns/parse_test.go
+++ b/vendor/github.com/miekg/dns/parse_test.go
@@ -13,7 +13,6 @@ import (
"strings"
"testing"
"testing/quick"
- "time"
)
func TestDotInName(t *testing.T) {
@@ -53,14 +52,10 @@ func TestTooLongDomainName(t *testing.T) {
_, err := NewRR(dom + " IN A 127.0.0.1")
if err == nil {
t.Error("should be too long")
- } else {
- t.Logf("error is %v", err)
}
_, err = NewRR("..com. IN A 127.0.0.1")
if err == nil {
t.Error("should fail")
- } else {
- t.Logf("error is %v", err)
}
}
@@ -103,23 +98,14 @@ func TestDomainNameAndTXTEscapes(t *testing.T) {
s := rr1.String()
rr2, err := NewRR(s)
if err != nil {
- t.Errorf("Error parsing unpacked RR's string: %v", err)
- t.Errorf(" Bytes: %v", rrbytes)
- t.Errorf("String: %v", s)
+ t.Errorf("error parsing unpacked RR's string: %v", err)
}
repacked := make([]byte, len(rrbytes))
if _, err := PackRR(rr2, repacked, 0, nil, false); err != nil {
t.Errorf("error packing parsed RR: %v", err)
- t.Errorf(" original Bytes: %v", rrbytes)
- t.Errorf("unpacked Struct: %v", rr1)
- t.Errorf(" parsed Struct: %v", rr2)
}
if !bytes.Equal(repacked, rrbytes) {
t.Error("packed bytes don't match original bytes")
- t.Errorf(" original bytes: %v", rrbytes)
- t.Errorf(" packed bytes: %v", repacked)
- t.Errorf("unpacked struct: %v", rr1)
- t.Errorf(" parsed struct: %v", rr2)
}
}
}
@@ -349,8 +335,6 @@ func TestParseDirectiveMisc(t *testing.T) {
}
if rr.String() != o {
t.Errorf("`%s' should be equal to\n`%s', but is `%s'", i, o, rr.String())
- } else {
- t.Logf("RR is OK: `%s'", rr.String())
}
}
}
@@ -372,8 +356,6 @@ func TestNSEC(t *testing.T) {
}
if rr.String() != o {
t.Errorf("`%s' should be equal to\n`%s', but is `%s'", i, o, rr.String())
- } else {
- t.Logf("RR is OK: `%s'", rr.String())
}
}
}
@@ -391,8 +373,6 @@ func TestParseLOC(t *testing.T) {
}
if rr.String() != o {
t.Errorf("`%s' should be equal to\n`%s', but is `%s'", i, o, rr.String())
- } else {
- t.Logf("RR is OK: `%s'", rr.String())
}
}
}
@@ -409,8 +389,6 @@ func TestParseDS(t *testing.T) {
}
if rr.String() != o {
t.Errorf("`%s' should be equal to\n`%s', but is `%s'", i, o, rr.String())
- } else {
- t.Logf("RR is OK: `%s'", rr.String())
}
}
}
@@ -443,8 +421,6 @@ func TestQuotes(t *testing.T) {
}
if rr.String() != o {
t.Errorf("`%s' should be equal to\n`%s', but is\n`%s'", i, o, rr.String())
- } else {
- t.Logf("RR is OK: `%s'", rr.String())
}
}
}
@@ -466,8 +442,6 @@ func TestParseClass(t *testing.T) {
}
if rr.String() != o {
t.Errorf("`%s' should be equal to\n`%s', but is\n`%s'", i, o, rr.String())
- } else {
- t.Logf("RR is OK: `%s'", rr.String())
}
}
}
@@ -517,8 +491,6 @@ func TestBrace(t *testing.T) {
}
if rr.String() != o {
t.Errorf("`%s' should be equal to\n`%s', but is `%s'", i, o, rr.String())
- } else {
- t.Logf("RR is OK: `%s'", rr.String())
}
}
}
@@ -544,34 +516,6 @@ func TestParseFailure(t *testing.T) {
}
}
-func TestZoneParsing(t *testing.T) {
- // parse_test.db
- db := `
-a.example.com. IN A 127.0.0.1
-8db7._openpgpkey.example.com. IN OPENPGPKEY mQCNAzIG
-$ORIGIN a.example.com.
-test IN A 127.0.0.1
- IN SSHFP 1 2 (
- BC6533CDC95A79078A39A56EA7635984ED655318ADA9
- B6159E30723665DA95BB )
-$ORIGIN b.example.com.
-test IN CNAME test.a.example.com.
-`
- start := time.Now().UnixNano()
- to := ParseZone(strings.NewReader(db), "", "parse_test.db")
- var i int
- for x := range to {
- i++
- if x.Error != nil {
- t.Error(x.Error)
- continue
- }
- t.Log(x.RR)
- }
- delta := time.Now().UnixNano() - start
- t.Logf("%d RRs parsed in %.2f s (%.2f RR/s)", i, float32(delta)/1e9, float32(i)/(float32(delta)/1e9))
-}
-
func TestOmittedTTL(t *testing.T) {
zone := `
$ORIGIN example.com.
@@ -667,7 +611,6 @@ b1slImA8YVJyuIDsj7kwzG7jnERNqnWxZ48AWkskmdHaVDP4BcelrTI3rMXdXF5D
if err != nil {
t.Fatalf("failed to parse RR: %v", err)
}
- t.Logf("RR: %s", rr)
msg := new(Msg)
msg.Answer = []RR{rr, rr}
bytes, err := msg.Pack()
@@ -682,7 +625,6 @@ b1slImA8YVJyuIDsj7kwzG7jnERNqnWxZ48AWkskmdHaVDP4BcelrTI3rMXdXF5D
}
for i, rr := range msg.Answer {
rr := rr.(*HIP)
- t.Logf("RR: %s", rr)
if l := len(rr.RendezvousServers); l != 2 {
t.Fatalf("2 servers expected, only %d in record %d:\n%v", l, i, msg)
}
@@ -827,20 +769,14 @@ func TestSRVPacking(t *testing.T) {
}
func TestParseBackslash(t *testing.T) {
- if r, err := NewRR("nul\\000gap.test.globnix.net. 600 IN A 192.0.2.10"); err != nil {
+ if _, err := NewRR("nul\\000gap.test.globnix.net. 600 IN A 192.0.2.10"); err != nil {
t.Errorf("could not create RR with \\000 in it")
- } else {
- t.Logf("parsed %s", r.String())
}
- if r, err := NewRR(`nul\000gap.test.globnix.net. 600 IN TXT "Hello\123"`); err != nil {
+ if _, err := NewRR(`nul\000gap.test.globnix.net. 600 IN TXT "Hello\123"`); err != nil {
t.Errorf("could not create RR with \\000 in it")
- } else {
- t.Logf("parsed %s", r.String())
}
- if r, err := NewRR(`m\ @\ iek.nl. IN 3600 A 127.0.0.1`); err != nil {
+ if _, err := NewRR(`m\ @\ iek.nl. IN 3600 A 127.0.0.1`); err != nil {
t.Errorf("could not create RR with \\ and \\@ in it")
- } else {
- t.Logf("parsed %s", r.String())
}
}
@@ -887,8 +823,6 @@ func TestGposEidNimloc(t *testing.T) {
}
if rr.String() != o {
t.Errorf("`%s' should be equal to\n`%s', but is `%s'", i, o, rr.String())
- } else {
- t.Logf("RR is OK: `%s'", rr.String())
}
}
}
@@ -906,8 +840,6 @@ func TestPX(t *testing.T) {
}
if rr.String() != o {
t.Errorf("`%s' should be equal to\n`%s', but is `%s'", i, o, rr.String())
- } else {
- t.Logf("RR is OK: `%s'", rr.String())
}
}
}
@@ -1053,7 +985,6 @@ func TestTXT(t *testing.T) {
if rr.(*TXT).Txt[1] != "b" {
t.Errorf("Txt should have two chunk, last one my be 'b', but is %s", rr.(*TXT).Txt[1])
}
- t.Log(rr.String())
}
func TestTypeXXXX(t *testing.T) {
@@ -1095,7 +1026,6 @@ func TestDigit(t *testing.T) {
t.Fatalf("failed to parse %v", err)
}
PackRR(r, buf, 0, nil, false)
- t.Log(buf)
if buf[5] != i {
t.Fatalf("5 pos must be %d, is %d", i, buf[5])
}
@@ -1128,7 +1058,6 @@ func TestTxtEqual(t *testing.T) {
// This is not an error, but keep this test.
t.Errorf("these two TXT records should match:\n%s\n%s", rr1.String(), rr2.String())
}
- t.Logf("%s\n%s", rr1.String(), rr2.String())
}
func TestTxtLong(t *testing.T) {
@@ -1155,12 +1084,8 @@ func TestMalformedPackets(t *testing.T) {
// com = 63 6f 6d
for _, packet := range packets {
data, _ := hex.DecodeString(packet)
- // for _, v := range data {
- // t.Log(v)
- // }
var msg Msg
msg.Unpack(data)
- // println(msg.String())
}
}
@@ -1317,7 +1242,6 @@ func TestParseTokenOverflow(t *testing.T) {
if err == nil {
t.Fatalf("token overflow should return an error")
}
- t.Logf("err: %s\n", err)
}
func TestParseTLSA(t *testing.T) {
@@ -1334,8 +1258,6 @@ func TestParseTLSA(t *testing.T) {
}
if rr.String() != o {
t.Errorf("`%s' should be equal to\n`%s', but is `%s'", o, o, rr.String())
- } else {
- t.Logf("RR is OK: `%s'", rr.String())
}
}
}
@@ -1355,8 +1277,6 @@ func TestParseSMIMEA(t *testing.T) {
}
if rr.String() != o {
t.Errorf("`%s' should be equal to\n`%s', but is `%s'", o, o, rr.String())
- } else {
- t.Logf("RR is OK: `%s'", rr.String())
}
}
}
@@ -1377,8 +1297,6 @@ func TestParseSSHFP(t *testing.T) {
}
if rr.String() != result {
t.Errorf("`%s' should be equal to\n\n`%s', but is \n`%s'", o, result, rr.String())
- } else {
- t.Logf("RR is OK: `%s'", rr.String())
}
}
}
@@ -1402,8 +1320,6 @@ func TestParseHINFO(t *testing.T) {
}
if rr.String() != o {
t.Errorf("`%s' should be equal to\n`%s', but is `%s'", i, o, rr.String())
- } else {
- t.Logf("RR is OK: `%s'", rr.String())
}
}
}
@@ -1424,8 +1340,6 @@ func TestParseCAA(t *testing.T) {
}
if rr.String() != o {
t.Errorf("`%s' should be equal to\n`%s', but is `%s'", i, o, rr.String())
- } else {
- t.Logf("RR is OK: `%s'", rr.String())
}
}
}
@@ -1472,8 +1386,6 @@ func TestParseURI(t *testing.T) {
}
if rr.String() != o {
t.Errorf("`%s' should be equal to\n`%s', but is `%s'", i, o, rr.String())
- } else {
- t.Logf("RR is OK: `%s'", rr.String())
}
}
}
@@ -1490,8 +1402,6 @@ func TestParseAVC(t *testing.T) {
}
if rr.String() != o {
t.Errorf("`%s' should be equal to\n`%s', but is `%s'", avc, o, rr.String())
- } else {
- t.Logf("RR is OK: `%s'", rr.String())
}
}
}
diff --git a/vendor/github.com/miekg/dns/privaterr_test.go b/vendor/github.com/miekg/dns/privaterr_test.go
index f50d0f48c..fa5ff48fa 100644
--- a/vendor/github.com/miekg/dns/privaterr_test.go
+++ b/vendor/github.com/miekg/dns/privaterr_test.go
@@ -59,8 +59,6 @@ func TestPrivateText(t *testing.T) {
}
if rr.String() != testrecord {
t.Errorf("record string representation did not match original %#v != %#v", rr.String(), testrecord)
- } else {
- t.Log(rr.String())
}
}
@@ -96,8 +94,6 @@ func TestPrivateByteSlice(t *testing.T) {
if rr1.String() != testrecord {
t.Errorf("record string representation did not match original %#v != %#v", rr1.String(), testrecord)
- } else {
- t.Log(rr1.String())
}
}
@@ -166,6 +162,5 @@ func TestPrivateZoneParser(t *testing.T) {
if err := x.Error; err != nil {
t.Fatal(err)
}
- t.Log(x.RR)
}
}
diff --git a/vendor/github.com/miekg/dns/rr_test.go b/vendor/github.com/miekg/dns/rr_test.go
new file mode 100644
index 000000000..77a153b1e
--- /dev/null
+++ b/vendor/github.com/miekg/dns/rr_test.go
@@ -0,0 +1,7 @@
+package dns
+
+// testRR returns the RR from string s. The error is thrown away.
+func testRR(s string) RR {
+ r, _ := NewRR(s)
+ return r
+}
diff --git a/vendor/github.com/miekg/dns/sanitize_test.go b/vendor/github.com/miekg/dns/sanitize_test.go
index 2ba3fe9a3..b2c0e2081 100644
--- a/vendor/github.com/miekg/dns/sanitize_test.go
+++ b/vendor/github.com/miekg/dns/sanitize_test.go
@@ -3,37 +3,36 @@ package dns
import "testing"
func TestDedup(t *testing.T) {
- // make it []string
testcases := map[[3]RR][]string{
[...]RR{
- newRR(t, "mIek.nl. IN A 127.0.0.1"),
- newRR(t, "mieK.nl. IN A 127.0.0.1"),
- newRR(t, "miek.Nl. IN A 127.0.0.1"),
+ testRR("mIek.nl. IN A 127.0.0.1"),
+ testRR("mieK.nl. IN A 127.0.0.1"),
+ testRR("miek.Nl. IN A 127.0.0.1"),
}: {"mIek.nl.\t3600\tIN\tA\t127.0.0.1"},
[...]RR{
- newRR(t, "miEk.nl. 2000 IN A 127.0.0.1"),
- newRR(t, "mieK.Nl. 1000 IN A 127.0.0.1"),
- newRR(t, "Miek.nL. 500 IN A 127.0.0.1"),
+ testRR("miEk.nl. 2000 IN A 127.0.0.1"),
+ testRR("mieK.Nl. 1000 IN A 127.0.0.1"),
+ testRR("Miek.nL. 500 IN A 127.0.0.1"),
}: {"miEk.nl.\t500\tIN\tA\t127.0.0.1"},
[...]RR{
- newRR(t, "miek.nl. IN A 127.0.0.1"),
- newRR(t, "miek.nl. CH A 127.0.0.1"),
- newRR(t, "miek.nl. IN A 127.0.0.1"),
+ testRR("miek.nl. IN A 127.0.0.1"),
+ testRR("miek.nl. CH A 127.0.0.1"),
+ testRR("miek.nl. IN A 127.0.0.1"),
}: {"miek.nl.\t3600\tIN\tA\t127.0.0.1",
"miek.nl.\t3600\tCH\tA\t127.0.0.1",
},
[...]RR{
- newRR(t, "miek.nl. CH A 127.0.0.1"),
- newRR(t, "miek.nl. IN A 127.0.0.1"),
- newRR(t, "miek.de. IN A 127.0.0.1"),
+ testRR("miek.nl. CH A 127.0.0.1"),
+ testRR("miek.nl. IN A 127.0.0.1"),
+ testRR("miek.de. IN A 127.0.0.1"),
}: {"miek.nl.\t3600\tCH\tA\t127.0.0.1",
"miek.nl.\t3600\tIN\tA\t127.0.0.1",
"miek.de.\t3600\tIN\tA\t127.0.0.1",
},
[...]RR{
- newRR(t, "miek.de. IN A 127.0.0.1"),
- newRR(t, "miek.nl. 200 IN A 127.0.0.1"),
- newRR(t, "miek.nl. 300 IN A 127.0.0.1"),
+ testRR("miek.de. IN A 127.0.0.1"),
+ testRR("miek.nl. 200 IN A 127.0.0.1"),
+ testRR("miek.nl. 300 IN A 127.0.0.1"),
}: {"miek.de.\t3600\tIN\tA\t127.0.0.1",
"miek.nl.\t200\tIN\tA\t127.0.0.1",
},
@@ -51,9 +50,9 @@ func TestDedup(t *testing.T) {
func BenchmarkDedup(b *testing.B) {
rrs := []RR{
- newRR(nil, "miEk.nl. 2000 IN A 127.0.0.1"),
- newRR(nil, "mieK.Nl. 1000 IN A 127.0.0.1"),
- newRR(nil, "Miek.nL. 500 IN A 127.0.0.1"),
+ testRR("miEk.nl. 2000 IN A 127.0.0.1"),
+ testRR("mieK.Nl. 1000 IN A 127.0.0.1"),
+ testRR("Miek.nL. 500 IN A 127.0.0.1"),
}
m := make(map[string]RR)
for i := 0; i < b.N; i++ {
@@ -63,9 +62,9 @@ func BenchmarkDedup(b *testing.B) {
func TestNormalizedString(t *testing.T) {
tests := map[RR]string{
- newRR(t, "mIEk.Nl. 3600 IN A 127.0.0.1"): "miek.nl.\tIN\tA\t127.0.0.1",
- newRR(t, "m\\ iek.nL. 3600 IN A 127.0.0.1"): "m\\ iek.nl.\tIN\tA\t127.0.0.1",
- newRR(t, "m\\\tIeK.nl. 3600 in A 127.0.0.1"): "m\\009iek.nl.\tIN\tA\t127.0.0.1",
+ testRR("mIEk.Nl. 3600 IN A 127.0.0.1"): "miek.nl.\tIN\tA\t127.0.0.1",
+ testRR("m\\ iek.nL. 3600 IN A 127.0.0.1"): "m\\ iek.nl.\tIN\tA\t127.0.0.1",
+ testRR("m\\\tIeK.nl. 3600 in A 127.0.0.1"): "m\\009iek.nl.\tIN\tA\t127.0.0.1",
}
for tc, expected := range tests {
n := normalizedString(tc)
@@ -74,11 +73,3 @@ func TestNormalizedString(t *testing.T) {
}
}
}
-
-func newRR(t *testing.T, s string) RR {
- r, err := NewRR(s)
- if err != nil {
- t.Logf("newRR: %v", err)
- }
- return r
-}
diff --git a/vendor/github.com/miekg/dns/scan.go b/vendor/github.com/miekg/dns/scan.go
index c7b1eb19a..243b9cf18 100644
--- a/vendor/github.com/miekg/dns/scan.go
+++ b/vendor/github.com/miekg/dns/scan.go
@@ -38,7 +38,7 @@ const (
zOwner
zClass
zDirOrigin // $ORIGIN
- zDirTtl // $TTL
+ zDirTTL // $TTL
zDirInclude // $INCLUDE
zDirGenerate // $GENERATE
@@ -51,13 +51,13 @@ const (
zExpectAny // Expect rrtype, ttl or class
zExpectAnyNoClass // Expect rrtype or ttl
zExpectAnyNoClassBl // The whitespace after _EXPECT_ANY_NOCLASS
- zExpectAnyNoTtl // Expect rrtype or class
- zExpectAnyNoTtlBl // Whitespace after _EXPECT_ANY_NOTTL
+ zExpectAnyNoTTL // Expect rrtype or class
+ zExpectAnyNoTTLBl // Whitespace after _EXPECT_ANY_NOTTL
zExpectRrtype // Expect rrtype
zExpectRrtypeBl // Whitespace BEFORE rrtype
zExpectRdata // The first element of the rdata
- zExpectDirTtlBl // Space after directive $TTL
- zExpectDirTtl // Directive $TTL
+ zExpectDirTTLBl // Space after directive $TTL
+ zExpectDirTTL // Directive $TTL
zExpectDirOriginBl // Space after directive $ORIGIN
zExpectDirOrigin // Directive $ORIGIN
zExpectDirIncludeBl // Space after directive $INCLUDE
@@ -231,8 +231,8 @@ func parseZone(r io.Reader, origin string, defttl *ttlState, f string, t chan *T
h.Name = name
prevName = h.Name
st = zExpectOwnerBl
- case zDirTtl:
- st = zExpectDirTtlBl
+ case zDirTTL:
+ st = zExpectDirTTLBl
case zDirOrigin:
st = zExpectDirOriginBl
case zDirInclude:
@@ -251,7 +251,7 @@ func parseZone(r io.Reader, origin string, defttl *ttlState, f string, t chan *T
// Discard, can happen when there is nothing on the
// line except the RR type
case zString:
- ttl, ok := stringToTtl(l.token)
+ ttl, ok := stringToTTL(l.token)
if !ok {
t <- &Token{Error: &ParseError{f, "not a TTL", l}}
return
@@ -260,7 +260,7 @@ func parseZone(r io.Reader, origin string, defttl *ttlState, f string, t chan *T
if defttl == nil || !defttl.isByDirective {
defttl = &ttlState{ttl, false}
}
- st = zExpectAnyNoTtlBl
+ st = zExpectAnyNoTTLBl
default:
t <- &Token{Error: &ParseError{f, "syntax error at beginning", l}}
@@ -307,13 +307,13 @@ func parseZone(r io.Reader, origin string, defttl *ttlState, f string, t chan *T
}
parseZone(r1, neworigin, defttl, l.token, t, include+1)
st = zExpectOwnerDir
- case zExpectDirTtlBl:
+ case zExpectDirTTLBl:
if l.value != zBlank {
t <- &Token{Error: &ParseError{f, "no blank after $TTL-directive", l}}
return
}
- st = zExpectDirTtl
- case zExpectDirTtl:
+ st = zExpectDirTTL
+ case zExpectDirTTL:
if l.value != zString {
t <- &Token{Error: &ParseError{f, "expecting $TTL value, not this...", l}}
return
@@ -322,7 +322,7 @@ func parseZone(r io.Reader, origin string, defttl *ttlState, f string, t chan *T
t <- &Token{Error: e}
return
}
- ttl, ok := stringToTtl(l.token)
+ ttl, ok := stringToTTL(l.token)
if !ok {
t <- &Token{Error: &ParseError{f, "expecting $TTL value, not this...", l}}
return
@@ -385,7 +385,7 @@ func parseZone(r io.Reader, origin string, defttl *ttlState, f string, t chan *T
h.Class = l.torc
st = zExpectAnyNoClassBl
case zString:
- ttl, ok := stringToTtl(l.token)
+ ttl, ok := stringToTTL(l.token)
if !ok {
t <- &Token{Error: &ParseError{f, "not a TTL", l}}
return
@@ -394,7 +394,7 @@ func parseZone(r io.Reader, origin string, defttl *ttlState, f string, t chan *T
if defttl == nil || !defttl.isByDirective {
defttl = &ttlState{ttl, false}
}
- st = zExpectAnyNoTtlBl
+ st = zExpectAnyNoTTLBl
default:
t <- &Token{Error: &ParseError{f, "expecting RR type, TTL or class, not this...", l}}
return
@@ -405,13 +405,13 @@ func parseZone(r io.Reader, origin string, defttl *ttlState, f string, t chan *T
return
}
st = zExpectAnyNoClass
- case zExpectAnyNoTtlBl:
+ case zExpectAnyNoTTLBl:
if l.value != zBlank {
t <- &Token{Error: &ParseError{f, "no blank before TTL", l}}
return
}
- st = zExpectAnyNoTtl
- case zExpectAnyNoTtl:
+ st = zExpectAnyNoTTL
+ case zExpectAnyNoTTL:
switch l.value {
case zClass:
h.Class = l.torc
@@ -426,7 +426,7 @@ func parseZone(r io.Reader, origin string, defttl *ttlState, f string, t chan *T
case zExpectAnyNoClass:
switch l.value {
case zString:
- ttl, ok := stringToTtl(l.token)
+ ttl, ok := stringToTTL(l.token)
if !ok {
t <- &Token{Error: &ParseError{f, "not a TTL", l}}
return
@@ -539,7 +539,7 @@ func zlexer(s *scan, c chan lex) {
// escape $... start with a \ not a $, so this will work
switch l.tokenUpper {
case "$TTL":
- l.value = zDirTtl
+ l.value = zDirTTL
case "$ORIGIN":
l.value = zDirOrigin
case "$INCLUDE":
@@ -837,8 +837,8 @@ func typeToInt(token string) (uint16, bool) {
return uint16(typ), true
}
-// Parse things like 2w, 2m, etc, Return the time in seconds.
-func stringToTtl(token string) (uint32, bool) {
+// stringToTTL parses things like 2w, 2m, etc, and returns the time in seconds.
+func stringToTTL(token string) (uint32, bool) {
s := uint32(0)
i := uint32(0)
for _, c := range token {
diff --git a/vendor/github.com/miekg/dns/scan_rr.go b/vendor/github.com/miekg/dns/scan_rr.go
index 824b9c949..c53ba1d5b 100644
--- a/vendor/github.com/miekg/dns/scan_rr.go
+++ b/vendor/github.com/miekg/dns/scan_rr.go
@@ -590,7 +590,7 @@ func setSOA(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
return nil, &ParseError{f, "bad SOA zone parameter", l}, ""
}
// We allow other fields to be unitful duration strings
- if v, ok = stringToTtl(l.token); !ok {
+ if v, ok = stringToTTL(l.token); !ok {
return nil, &ParseError{f, "bad SOA zone parameter", l}, ""
}
diff --git a/vendor/github.com/miekg/dns/server.go b/vendor/github.com/miekg/dns/server.go
index 0ca6e008c..ee7e256fb 100644
--- a/vendor/github.com/miekg/dns/server.go
+++ b/vendor/github.com/miekg/dns/server.go
@@ -297,10 +297,7 @@ type Server struct {
// DecorateWriter is optional, allows customization of the process that writes raw DNS messages.
DecorateWriter DecorateWriter
- // Graceful shutdown handling
-
- inFlight sync.WaitGroup
-
+ // Shutdown handling
lock sync.RWMutex
started bool
}
@@ -412,10 +409,8 @@ func (srv *Server) ActivateAndServe() error {
return &Error{err: "bad listeners"}
}
-// Shutdown gracefully shuts down a server. After a call to Shutdown, ListenAndServe and
-// ActivateAndServe will return. All in progress queries are completed before the server
-// is taken down. If the Shutdown is taking longer than the reading timeout an error
-// is returned.
+// Shutdown shuts down a server. After a call to Shutdown, ListenAndServe and
+// ActivateAndServe will return.
func (srv *Server) Shutdown() error {
srv.lock.Lock()
if !srv.started {
@@ -431,19 +426,7 @@ func (srv *Server) Shutdown() error {
if srv.Listener != nil {
srv.Listener.Close()
}
-
- fin := make(chan bool)
- go func() {
- srv.inFlight.Wait()
- fin <- true
- }()
-
- select {
- case <-time.After(srv.getReadTimeout()):
- return &Error{err: "server shutdown is pending"}
- case <-fin:
- return nil
- }
+ return nil
}
// getReadTimeout is a helper func to use system timeout if server did not intend to change it.
@@ -493,7 +476,6 @@ func (srv *Server) serveTCP(l net.Listener) error {
if err != nil {
continue
}
- srv.inFlight.Add(1)
go srv.serve(rw.RemoteAddr(), handler, m, nil, nil, rw)
}
}
@@ -529,15 +511,12 @@ func (srv *Server) serveUDP(l *net.UDPConn) error {
if err != nil {
continue
}
- srv.inFlight.Add(1)
go srv.serve(s.RemoteAddr(), handler, m, l, s, nil)
}
}
// Serve a new connection.
func (srv *Server) serve(a net.Addr, h Handler, m []byte, u *net.UDPConn, s *SessionUDP, t net.Conn) {
- defer srv.inFlight.Done()
-
w := &response{tsigSecret: srv.TsigSecret, udp: u, tcp: t, remoteAddr: a, udpSession: s}
if srv.DecorateWriter != nil {
w.writer = srv.DecorateWriter(w)
diff --git a/vendor/github.com/miekg/dns/server_test.go b/vendor/github.com/miekg/dns/server_test.go
index b74f2f1a8..1a4b7ca0c 100644
--- a/vendor/github.com/miekg/dns/server_test.go
+++ b/vendor/github.com/miekg/dns/server_test.go
@@ -147,7 +147,7 @@ func TestServing(t *testing.T) {
defer HandleRemove("miek.nl.")
defer HandleRemove("example.com.")
- s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
+ s, addrstr, err := RunLocalUDPServer(":0")
if err != nil {
t.Fatalf("unable to run test server: %v", err)
}
@@ -202,7 +202,7 @@ func TestServingTLS(t *testing.T) {
Certificates: []tls.Certificate{cert},
}
- s, addrstr, err := RunLocalTLSServer("127.0.0.1:0", &config)
+ s, addrstr, err := RunLocalTLSServer(":0", &config)
if err != nil {
t.Fatalf("unable to run test server: %v", err)
}
@@ -247,13 +247,77 @@ func TestServingTLS(t *testing.T) {
}
}
+func TestServingListenAndServe(t *testing.T) {
+ HandleFunc("example.com.", AnotherHelloServer)
+ defer HandleRemove("example.com.")
+
+ waitLock := sync.Mutex{}
+ server := &Server{Addr: ":0", Net: "udp", ReadTimeout: time.Hour, WriteTimeout: time.Hour, NotifyStartedFunc: waitLock.Unlock}
+ waitLock.Lock()
+
+ go func() {
+ server.ListenAndServe()
+ }()
+ waitLock.Lock()
+
+ c, m := new(Client), new(Msg)
+ m.SetQuestion("example.com.", TypeTXT)
+ addr := server.PacketConn.LocalAddr().String() // Get address via the PacketConn that gets set.
+ r, _, err := c.Exchange(m, addr)
+ if err != nil {
+ t.Fatal("failed to exchange example.com", err)
+ }
+ txt := r.Extra[0].(*TXT).Txt[0]
+ if txt != "Hello example" {
+ t.Error("unexpected result for example.com", txt, "!= Hello example")
+ }
+ server.Shutdown()
+}
+
+func TestServingListenAndServeTLS(t *testing.T) {
+ HandleFunc("example.com.", AnotherHelloServer)
+ defer HandleRemove("example.com.")
+
+ cert, err := tls.X509KeyPair(CertPEMBlock, KeyPEMBlock)
+ if err != nil {
+ t.Fatalf("unable to build certificate: %v", err)
+ }
+
+ config := &tls.Config{
+ Certificates: []tls.Certificate{cert},
+ }
+
+ waitLock := sync.Mutex{}
+ server := &Server{Addr: ":0", Net: "tcp", TLSConfig: config, ReadTimeout: time.Hour, WriteTimeout: time.Hour, NotifyStartedFunc: waitLock.Unlock}
+ waitLock.Lock()
+
+ go func() {
+ server.ListenAndServe()
+ }()
+ waitLock.Lock()
+
+ c, m := new(Client), new(Msg)
+ c.Net = "tcp"
+ m.SetQuestion("example.com.", TypeTXT)
+ addr := server.Listener.Addr().String() // Get address via the Listener that gets set.
+ r, _, err := c.Exchange(m, addr)
+ if err != nil {
+ t.Fatal(err)
+ }
+ txt := r.Extra[0].(*TXT).Txt[0]
+ if txt != "Hello example" {
+ t.Error("unexpected result for example.com", txt, "!= Hello example")
+ }
+ server.Shutdown()
+}
+
func BenchmarkServe(b *testing.B) {
b.StopTimer()
HandleFunc("miek.nl.", HelloServer)
defer HandleRemove("miek.nl.")
a := runtime.GOMAXPROCS(4)
- s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
+ s, addrstr, err := RunLocalUDPServer(":0")
if err != nil {
b.Fatalf("unable to run test server: %v", err)
}
@@ -306,7 +370,7 @@ func BenchmarkServeCompress(b *testing.B) {
HandleFunc("miek.nl.", HelloServerCompress)
defer HandleRemove("miek.nl.")
a := runtime.GOMAXPROCS(4)
- s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
+ s, addrstr, err := RunLocalUDPServer(":0")
if err != nil {
b.Fatalf("unable to run test server: %v", err)
}
@@ -407,7 +471,7 @@ func TestServingLargeResponses(t *testing.T) {
HandleFunc("example.", HelloServerLargeResponse)
defer HandleRemove("example.")
- s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
+ s, addrstr, err := RunLocalUDPServer(":0")
if err != nil {
t.Fatalf("unable to run test server: %v", err)
}
@@ -447,7 +511,7 @@ func TestServingResponse(t *testing.T) {
t.Skip("skipping test in short mode.")
}
HandleFunc("miek.nl.", HelloServer)
- s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
+ s, addrstr, err := RunLocalUDPServer(":0")
if err != nil {
t.Fatalf("unable to run test server: %v", err)
}
@@ -467,7 +531,7 @@ func TestServingResponse(t *testing.T) {
}
s.Shutdown()
- s, addrstr, err = RunLocalUDPServerUnsafe("127.0.0.1:0")
+ s, addrstr, err = RunLocalUDPServerUnsafe(":0")
if err != nil {
t.Fatalf("unable to run test server: %v", err)
}
@@ -481,7 +545,7 @@ func TestServingResponse(t *testing.T) {
}
func TestShutdownTCP(t *testing.T) {
- s, _, err := RunLocalTCPServer("127.0.0.1:0")
+ s, _, err := RunLocalTCPServer(":0")
if err != nil {
t.Fatalf("unable to run test server: %v", err)
}
@@ -501,7 +565,7 @@ func TestShutdownTLS(t *testing.T) {
Certificates: []tls.Certificate{cert},
}
- s, _, err := RunLocalTLSServer("127.0.0.1:0", &config)
+ s, _, err := RunLocalTLSServer(":0", &config)
if err != nil {
t.Fatalf("unable to run test server: %v", err)
}
@@ -529,7 +593,7 @@ func (t *trigger) Get() bool {
func TestHandlerCloseTCP(t *testing.T) {
- ln, err := net.Listen("tcp", "127.0.0.1:0")
+ ln, err := net.Listen("tcp", ":0")
if err != nil {
panic(err)
}
@@ -553,7 +617,7 @@ func TestHandlerCloseTCP(t *testing.T) {
exchange:
_, _, err := c.Exchange(m, addr)
if err != nil && err != io.EOF {
- t.Logf("exchange failed: %s\n", err)
+ t.Errorf("exchange failed: %s\n", err)
if tries == 3 {
return
}
@@ -569,7 +633,7 @@ func TestHandlerCloseTCP(t *testing.T) {
}
func TestShutdownUDP(t *testing.T) {
- s, _, fin, err := RunLocalUDPServerWithFinChan("127.0.0.1:0")
+ s, _, fin, err := RunLocalUDPServerWithFinChan(":0")
if err != nil {
t.Fatalf("unable to run test server: %v", err)
}
@@ -580,7 +644,23 @@ func TestShutdownUDP(t *testing.T) {
select {
case <-fin:
case <-time.After(2 * time.Second):
- t.Error("Could not shutdown test UDP server. Gave up waiting")
+ t.Error("could not shutdown test UDP server. Gave up waiting")
+ }
+}
+
+func TestServerStartStopRace(t *testing.T) {
+ for i := 0; i < 10; i++ {
+ var err error
+ s := &Server{}
+ s, _, _, err = RunLocalUDPServerWithFinChan(":0")
+ if err != nil {
+ t.Fatalf("Could not start server: %s", err)
+ }
+ go func() {
+ if err := s.Shutdown(); err != nil {
+ t.Fatalf("Could not stop server: %s", err)
+ }
+ }()
}
}
@@ -600,7 +680,7 @@ func ExampleDecorateWriter() {
})
// simple UDP server
- pc, err := net.ListenPacket("udp", "127.0.0.1:0")
+ pc, err := net.ListenPacket("udp", ":0")
if err != nil {
fmt.Println(err.Error())
return
@@ -687,43 +767,3 @@ zDCJkckCgYEAndqM5KXGk5xYo+MAA1paZcbTUXwaWwjLU+XSRSSoyBEi5xMtfvUb
kFsxKCqxAnBVGEWAvVZAiiTOxleQFjz5RnL0BQp9Lg2cQe+dvuUmIAA=
-----END RSA PRIVATE KEY-----`)
)
-
-func testShutdownBindPort(t *testing.T, protocol string, port string) {
- handler := NewServeMux()
- handler.HandleFunc(".", func(w ResponseWriter, r *Msg) {})
- startedCh := make(chan struct{})
- s := &Server{
- Addr: net.JoinHostPort("127.0.0.1", port),
- Net: protocol,
- Handler: handler,
- NotifyStartedFunc: func() {
- startedCh <- struct{}{}
- },
- }
- go func() {
- if err := s.ListenAndServe(); err != nil {
- t.Log(err)
- }
- }()
- <-startedCh
- t.Logf("DNS server is started on: %s", s.Addr)
- if err := s.Shutdown(); err != nil {
- t.Fatal(err)
- }
- time.Sleep(100 * time.Millisecond)
- go func() {
- if err := s.ListenAndServe(); err != nil {
- t.Fatal(err)
- }
- }()
- <-startedCh
- t.Logf("DNS server is started on: %s", s.Addr)
-}
-
-func TestShutdownBindPortUDP(t *testing.T) {
- testShutdownBindPort(t, "udp", "1153")
-}
-
-func TestShutdownBindPortTCP(t *testing.T) {
- testShutdownBindPort(t, "tcp", "1154")
-}
diff --git a/vendor/github.com/miekg/dns/types.go b/vendor/github.com/miekg/dns/types.go
index 57f065bc8..deddb301b 100644
--- a/vendor/github.com/miekg/dns/types.go
+++ b/vendor/github.com/miekg/dns/types.go
@@ -164,14 +164,15 @@ const (
_Z = 1 << 6 // Z
_AD = 1 << 5 // authticated data
_CD = 1 << 4 // checking disabled
+)
+// Various constants used in the LOC RR, See RFC 1887.
+const (
LOC_EQUATOR = 1 << 31 // RFC 1876, Section 2.
LOC_PRIMEMERIDIAN = 1 << 31 // RFC 1876, Section 2.
-
- LOC_HOURS = 60 * 1000
- LOC_DEGREES = 60 * LOC_HOURS
-
- LOC_ALTITUDEBASE = 100000
+ LOC_HOURS = 60 * 1000
+ LOC_DEGREES = 60 * LOC_HOURS
+ LOC_ALTITUDEBASE = 100000
)
// Different Certificate Types, see RFC 4398, Section 2.1
@@ -237,6 +238,7 @@ type ANY struct {
func (rr *ANY) String() string { return rr.Hdr.String() }
+// CNAME RR. See RFC 1034.
type CNAME struct {
Hdr RR_Header
Target string `dns:"cdomain-name"`
@@ -244,6 +246,7 @@ type CNAME struct {
func (rr *CNAME) String() string { return rr.Hdr.String() + sprintName(rr.Target) }
+// HINFO RR. See RFC 1034.
type HINFO struct {
Hdr RR_Header
Cpu string
@@ -254,6 +257,7 @@ func (rr *HINFO) String() string {
return rr.Hdr.String() + sprintTxt([]string{rr.Cpu, rr.Os})
}
+// MB RR. See RFC 1035.
type MB struct {
Hdr RR_Header
Mb string `dns:"cdomain-name"`
@@ -261,6 +265,7 @@ type MB struct {
func (rr *MB) String() string { return rr.Hdr.String() + sprintName(rr.Mb) }
+// MG RR. See RFC 1035.
type MG struct {
Hdr RR_Header
Mg string `dns:"cdomain-name"`
@@ -268,6 +273,7 @@ type MG struct {
func (rr *MG) String() string { return rr.Hdr.String() + sprintName(rr.Mg) }
+// MINFO RR. See RFC 1035.
type MINFO struct {
Hdr RR_Header
Rmail string `dns:"cdomain-name"`
@@ -278,6 +284,7 @@ func (rr *MINFO) String() string {
return rr.Hdr.String() + sprintName(rr.Rmail) + " " + sprintName(rr.Email)
}
+// MR RR. See RFC 1035.
type MR struct {
Hdr RR_Header
Mr string `dns:"cdomain-name"`
@@ -287,6 +294,7 @@ func (rr *MR) String() string {
return rr.Hdr.String() + sprintName(rr.Mr)
}
+// MF RR. See RFC 1035.
type MF struct {
Hdr RR_Header
Mf string `dns:"cdomain-name"`
@@ -296,6 +304,7 @@ func (rr *MF) String() string {
return rr.Hdr.String() + sprintName(rr.Mf)
}
+// MD RR. See RFC 1035.
type MD struct {
Hdr RR_Header
Md string `dns:"cdomain-name"`
@@ -305,6 +314,7 @@ func (rr *MD) String() string {
return rr.Hdr.String() + sprintName(rr.Md)
}
+// MX RR. See RFC 1035.
type MX struct {
Hdr RR_Header
Preference uint16
@@ -315,6 +325,7 @@ func (rr *MX) String() string {
return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) + " " + sprintName(rr.Mx)
}
+// AFSDB RR. See RFC 1183.
type AFSDB struct {
Hdr RR_Header
Subtype uint16
@@ -325,6 +336,7 @@ func (rr *AFSDB) String() string {
return rr.Hdr.String() + strconv.Itoa(int(rr.Subtype)) + " " + sprintName(rr.Hostname)
}
+// X25 RR. See RFC 1183, Section 3.1.
type X25 struct {
Hdr RR_Header
PSDNAddress string
@@ -334,6 +346,7 @@ func (rr *X25) String() string {
return rr.Hdr.String() + rr.PSDNAddress
}
+// RT RR. See RFC 1183, Section 3.3.
type RT struct {
Hdr RR_Header
Preference uint16
@@ -344,6 +357,7 @@ func (rr *RT) String() string {
return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) + " " + sprintName(rr.Host)
}
+// NS RR. See RFC 1035.
type NS struct {
Hdr RR_Header
Ns string `dns:"cdomain-name"`
@@ -353,6 +367,7 @@ func (rr *NS) String() string {
return rr.Hdr.String() + sprintName(rr.Ns)
}
+// PTR RR. See RFC 1035.
type PTR struct {
Hdr RR_Header
Ptr string `dns:"cdomain-name"`
@@ -362,6 +377,7 @@ func (rr *PTR) String() string {
return rr.Hdr.String() + sprintName(rr.Ptr)
}
+// RP RR. See RFC 1138, Section 2.2.
type RP struct {
Hdr RR_Header
Mbox string `dns:"domain-name"`
@@ -372,6 +388,7 @@ func (rr *RP) String() string {
return rr.Hdr.String() + rr.Mbox + " " + sprintTxt([]string{rr.Txt})
}
+// SOA RR. See RFC 1035.
type SOA struct {
Hdr RR_Header
Ns string `dns:"cdomain-name"`
@@ -392,6 +409,7 @@ func (rr *SOA) String() string {
" " + strconv.FormatInt(int64(rr.Minttl), 10)
}
+// TXT RR. See RFC 1035.
type TXT struct {
Hdr RR_Header
Txt []string `dns:"txt"`
@@ -524,6 +542,7 @@ func nextByte(b []byte, offset int) (byte, int) {
return b[offset+1], 2
}
+// SPF RR. See RFC 4408, Section 3.1.1.
type SPF struct {
Hdr RR_Header
Txt []string `dns:"txt"`
@@ -531,6 +550,7 @@ type SPF struct {
func (rr *SPF) String() string { return rr.Hdr.String() + sprintTxt(rr.Txt) }
+// AVC RR. See https://www.iana.org/assignments/dns-parameters/AVC/avc-completed-template.
type AVC struct {
Hdr RR_Header
Txt []string `dns:"txt"`
@@ -538,6 +558,7 @@ type AVC struct {
func (rr *AVC) String() string { return rr.Hdr.String() + sprintTxt(rr.Txt) }
+// SRV RR. See RFC 2782.
type SRV struct {
Hdr RR_Header
Priority uint16
@@ -553,6 +574,7 @@ func (rr *SRV) String() string {
strconv.Itoa(int(rr.Port)) + " " + sprintName(rr.Target)
}
+// NAPTR RR. See RFC 2915.
type NAPTR struct {
Hdr RR_Header
Order uint16
@@ -573,7 +595,7 @@ func (rr *NAPTR) String() string {
rr.Replacement
}
-// The CERT resource record, see RFC 4398.
+// CERT RR. See RFC 4398.
type CERT struct {
Hdr RR_Header
Type uint16
@@ -599,7 +621,7 @@ func (rr *CERT) String() string {
" " + rr.Certificate
}
-// The DNAME resource record, see RFC 2672.
+// DNAME RR. See RFC 2672.
type DNAME struct {
Hdr RR_Header
Target string `dns:"domain-name"`
@@ -609,6 +631,7 @@ func (rr *DNAME) String() string {
return rr.Hdr.String() + sprintName(rr.Target)
}
+// A RR. See RFC 1035.
type A struct {
Hdr RR_Header
A net.IP `dns:"a"`
@@ -621,6 +644,7 @@ func (rr *A) String() string {
return rr.Hdr.String() + rr.A.String()
}
+// AAAA RR. See RFC 3596.
type AAAA struct {
Hdr RR_Header
AAAA net.IP `dns:"aaaa"`
@@ -633,6 +657,7 @@ func (rr *AAAA) String() string {
return rr.Hdr.String() + rr.AAAA.String()
}
+// PX RR. See RFC 2163.
type PX struct {
Hdr RR_Header
Preference uint16
@@ -644,6 +669,7 @@ func (rr *PX) String() string {
return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) + " " + sprintName(rr.Map822) + " " + sprintName(rr.Mapx400)
}
+// GPOS RR. See RFC 1712.
type GPOS struct {
Hdr RR_Header
Longitude string
@@ -655,6 +681,7 @@ func (rr *GPOS) String() string {
return rr.Hdr.String() + rr.Longitude + " " + rr.Latitude + " " + rr.Altitude
}
+// LOC RR. See RFC RFC 1876.
type LOC struct {
Hdr RR_Header
Version uint8
@@ -731,11 +758,12 @@ func (rr *LOC) String() string {
return s
}
-// SIG is identical to RRSIG and nowadays only used for SIG(0), RFC2931.
+// SIG RR. See RFC 2535. The SIG RR is identical to RRSIG and nowadays only used for SIG(0), See RFC 2931.
type SIG struct {
RRSIG
}
+// RRSIG RR. See RFC 4034 and RFC 3755.
type RRSIG struct {
Hdr RR_Header
TypeCovered uint16
@@ -763,6 +791,7 @@ func (rr *RRSIG) String() string {
return s
}
+// NSEC RR. See RFC 4034 and RFC 3755.
type NSEC struct {
Hdr RR_Header
NextDomain string `dns:"domain-name"`
@@ -790,14 +819,13 @@ func (rr *NSEC) len() int {
return l
}
-type DLV struct {
- DS
-}
+// DLV RR. See RFC 4431.
+type DLV struct{ DS }
-type CDS struct {
- DS
-}
+// CDS RR. See RFC 7344.
+type CDS struct{ DS }
+// DS RR. See RFC 4034 and RFC 3658.
type DS struct {
Hdr RR_Header
KeyTag uint16
@@ -813,6 +841,7 @@ func (rr *DS) String() string {
" " + strings.ToUpper(rr.Digest)
}
+// KX RR. See RFC 2230.
type KX struct {
Hdr RR_Header
Preference uint16
@@ -824,6 +853,7 @@ func (rr *KX) String() string {
" " + sprintName(rr.Exchanger)
}
+// TA RR. See http://www.watson.org/~weiler/INI1999-19.pdf.
type TA struct {
Hdr RR_Header
KeyTag uint16
@@ -839,6 +869,7 @@ func (rr *TA) String() string {
" " + strings.ToUpper(rr.Digest)
}
+// TALINK RR. See https://www.iana.org/assignments/dns-parameters/TALINK/talink-completed-template.
type TALINK struct {
Hdr RR_Header
PreviousName string `dns:"domain-name"`
@@ -850,6 +881,7 @@ func (rr *TALINK) String() string {
sprintName(rr.PreviousName) + " " + sprintName(rr.NextName)
}
+// SSHFP RR. See RFC RFC 4255.
type SSHFP struct {
Hdr RR_Header
Algorithm uint8
@@ -863,14 +895,17 @@ func (rr *SSHFP) String() string {
" " + strings.ToUpper(rr.FingerPrint)
}
+// KEY RR. See RFC RFC 2535.
type KEY struct {
DNSKEY
}
+// CDNSKEY RR. See RFC 7344.
type CDNSKEY struct {
DNSKEY
}
+// DNSKEY RR. See RFC 4034 and RFC 3755.
type DNSKEY struct {
Hdr RR_Header
Flags uint16
@@ -886,6 +921,7 @@ func (rr *DNSKEY) String() string {
" " + rr.PublicKey
}
+// RKEY RR. See https://www.iana.org/assignments/dns-parameters/RKEY/rkey-completed-template.
type RKEY struct {
Hdr RR_Header
Flags uint16
@@ -901,6 +937,7 @@ func (rr *RKEY) String() string {
" " + rr.PublicKey
}
+// NSAPPTR RR. See RFC 1348.
type NSAPPTR struct {
Hdr RR_Header
Ptr string `dns:"domain-name"`
@@ -908,6 +945,7 @@ type NSAPPTR struct {
func (rr *NSAPPTR) String() string { return rr.Hdr.String() + sprintName(rr.Ptr) }
+// NSEC3 RR. See RFC 5155.
type NSEC3 struct {
Hdr RR_Header
Hash uint8
@@ -946,6 +984,7 @@ func (rr *NSEC3) len() int {
return l
}
+// NSEC3PARAM RR. See RFC 5155.
type NSEC3PARAM struct {
Hdr RR_Header
Hash uint8
@@ -964,6 +1003,7 @@ func (rr *NSEC3PARAM) String() string {
return s
}
+// TKEY RR. See RFC 2930.
type TKEY struct {
Hdr RR_Header
Algorithm string `dns:"domain-name"`
@@ -982,7 +1022,7 @@ func (rr *TKEY) String() string {
return ""
}
-// RFC3597 represents an unknown/generic RR.
+// RFC3597 represents an unknown/generic RR. See RFC 3597.
type RFC3597 struct {
Hdr RR_Header
Rdata string `dns:"hex"`
@@ -1006,6 +1046,7 @@ func rfc3597Header(h RR_Header) string {
return s
}
+// URI RR. See RFC 7553.
type URI struct {
Hdr RR_Header
Priority uint16
@@ -1018,6 +1059,7 @@ func (rr *URI) String() string {
" " + strconv.Itoa(int(rr.Weight)) + " " + sprintTxtOctet(rr.Target)
}
+// DHCID RR. See RFC 4701.
type DHCID struct {
Hdr RR_Header
Digest string `dns:"base64"`
@@ -1025,6 +1067,7 @@ type DHCID struct {
func (rr *DHCID) String() string { return rr.Hdr.String() + rr.Digest }
+// TLSA RR. See RFC 6698.
type TLSA struct {
Hdr RR_Header
Usage uint8
@@ -1041,6 +1084,7 @@ func (rr *TLSA) String() string {
" " + rr.Certificate
}
+// SMIMEA RR. See RFC 8162.
type SMIMEA struct {
Hdr RR_Header
Usage uint8
@@ -1063,6 +1107,7 @@ func (rr *SMIMEA) String() string {
return s
}
+// HIP RR. See RFC 8005.
type HIP struct {
Hdr RR_Header
HitLength uint8
@@ -1084,6 +1129,7 @@ func (rr *HIP) String() string {
return s
}
+// NINFO RR. See https://www.iana.org/assignments/dns-parameters/NINFO/ninfo-completed-template.
type NINFO struct {
Hdr RR_Header
ZSData []string `dns:"txt"`
@@ -1091,6 +1137,7 @@ type NINFO struct {
func (rr *NINFO) String() string { return rr.Hdr.String() + sprintTxt(rr.ZSData) }
+// NID RR. See RFC RFC 6742.
type NID struct {
Hdr RR_Header
Preference uint16
@@ -1104,6 +1151,7 @@ func (rr *NID) String() string {
return s
}
+// L32 RR, See RFC 6742.
type L32 struct {
Hdr RR_Header
Preference uint16
@@ -1118,6 +1166,7 @@ func (rr *L32) String() string {
" " + rr.Locator32.String()
}
+// L64 RR, See RFC 6742.
type L64 struct {
Hdr RR_Header
Preference uint16
@@ -1131,6 +1180,7 @@ func (rr *L64) String() string {
return s
}
+// LP RR. See RFC 6742.
type LP struct {
Hdr RR_Header
Preference uint16
@@ -1141,6 +1191,7 @@ func (rr *LP) String() string {
return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) + " " + sprintName(rr.Fqdn)
}
+// EUI48 RR. See RFC 7043.
type EUI48 struct {
Hdr RR_Header
Address uint64 `dns:"uint48"`
@@ -1148,6 +1199,7 @@ type EUI48 struct {
func (rr *EUI48) String() string { return rr.Hdr.String() + euiToString(rr.Address, 48) }
+// EUI64 RR. See RFC 7043.
type EUI64 struct {
Hdr RR_Header
Address uint64
@@ -1155,6 +1207,7 @@ type EUI64 struct {
func (rr *EUI64) String() string { return rr.Hdr.String() + euiToString(rr.Address, 64) }
+// CAA RR. See RFC 6844.
type CAA struct {
Hdr RR_Header
Flag uint8
@@ -1166,6 +1219,7 @@ func (rr *CAA) String() string {
return rr.Hdr.String() + strconv.Itoa(int(rr.Flag)) + " " + rr.Tag + " " + sprintTxtOctet(rr.Value)
}
+// UID RR. Deprecated, IANA-Reserved.
type UID struct {
Hdr RR_Header
Uid uint32
@@ -1173,6 +1227,7 @@ type UID struct {
func (rr *UID) String() string { return rr.Hdr.String() + strconv.FormatInt(int64(rr.Uid), 10) }
+// GID RR. Deprecated, IANA-Reserved.
type GID struct {
Hdr RR_Header
Gid uint32
@@ -1180,6 +1235,7 @@ type GID struct {
func (rr *GID) String() string { return rr.Hdr.String() + strconv.FormatInt(int64(rr.Gid), 10) }
+// UINFO RR. Deprecated, IANA-Reserved.
type UINFO struct {
Hdr RR_Header
Uinfo string
@@ -1187,6 +1243,7 @@ type UINFO struct {
func (rr *UINFO) String() string { return rr.Hdr.String() + sprintTxt([]string{rr.Uinfo}) }
+// EID RR. See http://ana-3.lcs.mit.edu/~jnc/nimrod/dns.txt.
type EID struct {
Hdr RR_Header
Endpoint string `dns:"hex"`
@@ -1194,6 +1251,7 @@ type EID struct {
func (rr *EID) String() string { return rr.Hdr.String() + strings.ToUpper(rr.Endpoint) }
+// NIMLOC RR. See http://ana-3.lcs.mit.edu/~jnc/nimrod/dns.txt.
type NIMLOC struct {
Hdr RR_Header
Locator string `dns:"hex"`
@@ -1201,6 +1259,7 @@ type NIMLOC struct {
func (rr *NIMLOC) String() string { return rr.Hdr.String() + strings.ToUpper(rr.Locator) }
+// OPENPGPKEY RR. See RFC 7929.
type OPENPGPKEY struct {
Hdr RR_Header
PublicKey string `dns:"base64"`
diff --git a/vendor/github.com/miekg/dns/types_generate.go b/vendor/github.com/miekg/dns/types_generate.go
index dd1310942..3de021ca7 100644
--- a/vendor/github.com/miekg/dns/types_generate.go
+++ b/vendor/github.com/miekg/dns/types_generate.go
@@ -27,7 +27,7 @@ var skipLen = map[string]struct{}{
var packageHdr = `
// *** DO NOT MODIFY ***
-// AUTOGENERATED BY go generate from type_generate.go
+// AUTOGENERATED BY go generate from types_generate.go
package dns
@@ -56,7 +56,6 @@ var TypeToString = map[uint16]string{
`))
var headerFunc = template.Must(template.New("headerFunc").Parse(`
-// Header() functions
{{range .}} func (rr *{{.}}) Header() *RR_Header { return &rr.Hdr }
{{end}}
diff --git a/vendor/github.com/miekg/dns/types_test.go b/vendor/github.com/miekg/dns/types_test.go
index c117cfbc7..3dbddee1e 100644
--- a/vendor/github.com/miekg/dns/types_test.go
+++ b/vendor/github.com/miekg/dns/types_test.go
@@ -44,7 +44,7 @@ func TestCmToM(t *testing.T) {
func TestSplitN(t *testing.T) {
xs := splitN("abc", 5)
if len(xs) != 1 && xs[0] != "abc" {
- t.Errorf("Failure to split abc")
+ t.Errorf("failure to split abc")
}
s := ""
diff --git a/vendor/github.com/miekg/dns/update_test.go b/vendor/github.com/miekg/dns/update_test.go
index 12760a1ee..6813baa10 100644
--- a/vendor/github.com/miekg/dns/update_test.go
+++ b/vendor/github.com/miekg/dns/update_test.go
@@ -13,11 +13,8 @@ func TestDynamicUpdateParsing(t *testing.T) {
typ == "Reserved" || typ == "None" || typ == "NXT" || typ == "MAILB" || typ == "MAILA" {
continue
}
- r, err := NewRR(prefix + typ)
- if err != nil {
+ if _, err := NewRR(prefix + typ); err != nil {
t.Errorf("failure to parse: %s %s: %v", prefix, typ, err)
- } else {
- t.Logf("parsed: %s", r.String())
}
}
}
@@ -56,10 +53,7 @@ func TestDynamicUpdateZeroRdataUnpack(t *testing.T) {
func TestRemoveRRset(t *testing.T) {
// Should add a zero data RR in Class ANY with a TTL of 0
// for each set mentioned in the RRs provided to it.
- rr, err := NewRR(". 100 IN A 127.0.0.1")
- if err != nil {
- t.Fatalf("error constructing RR: %v", err)
- }
+ rr := testRR(". 100 IN A 127.0.0.1")
m := new(Msg)
m.Ns = []RR{&RR_Header{Name: ".", Rrtype: TypeA, Class: ClassANY, Ttl: 0, Rdlength: 0}}
expectstr := m.String()
@@ -92,15 +86,15 @@ func TestPreReqAndRemovals(t *testing.T) {
m.Id = 1234
// Use a full set of RRs each time, so we are sure the rdata is stripped.
- rrName1, _ := NewRR("name_used. 3600 IN A 127.0.0.1")
- rrName2, _ := NewRR("name_not_used. 3600 IN A 127.0.0.1")
- rrRemove1, _ := NewRR("remove1. 3600 IN A 127.0.0.1")
- rrRemove2, _ := NewRR("remove2. 3600 IN A 127.0.0.1")
- rrRemove3, _ := NewRR("remove3. 3600 IN A 127.0.0.1")
- rrInsert, _ := NewRR("insert. 3600 IN A 127.0.0.1")
- rrRrset1, _ := NewRR("rrset_used1. 3600 IN A 127.0.0.1")
- rrRrset2, _ := NewRR("rrset_used2. 3600 IN A 127.0.0.1")
- rrRrset3, _ := NewRR("rrset_not_used. 3600 IN A 127.0.0.1")
+ rrName1 := testRR("name_used. 3600 IN A 127.0.0.1")
+ rrName2 := testRR("name_not_used. 3600 IN A 127.0.0.1")
+ rrRemove1 := testRR("remove1. 3600 IN A 127.0.0.1")
+ rrRemove2 := testRR("remove2. 3600 IN A 127.0.0.1")
+ rrRemove3 := testRR("remove3. 3600 IN A 127.0.0.1")
+ rrInsert := testRR("insert. 3600 IN A 127.0.0.1")
+ rrRrset1 := testRR("rrset_used1. 3600 IN A 127.0.0.1")
+ rrRrset2 := testRR("rrset_used2. 3600 IN A 127.0.0.1")
+ rrRrset3 := testRR("rrset_not_used. 3600 IN A 127.0.0.1")
// Handle the prereqs.
m.NameUsed([]RR{rrName1})
diff --git a/vendor/github.com/miekg/dns/xfr.go b/vendor/github.com/miekg/dns/xfr.go
index 576c5590a..2e892ea38 100644
--- a/vendor/github.com/miekg/dns/xfr.go
+++ b/vendor/github.com/miekg/dns/xfr.go
@@ -51,18 +51,18 @@ func (t *Transfer) In(q *Msg, a string) (env chan *Envelope, err error) {
env = make(chan *Envelope)
go func() {
if q.Question[0].Qtype == TypeAXFR {
- go t.inAxfr(q.Id, env)
+ go t.inAxfr(q, env)
return
}
if q.Question[0].Qtype == TypeIXFR {
- go t.inIxfr(q.Id, env)
+ go t.inIxfr(q, env)
return
}
}()
return env, nil
}
-func (t *Transfer) inAxfr(id uint16, c chan *Envelope) {
+func (t *Transfer) inAxfr(q *Msg, c chan *Envelope) {
first := true
defer t.Close()
defer close(c)
@@ -77,7 +77,7 @@ func (t *Transfer) inAxfr(id uint16, c chan *Envelope) {
c <- &Envelope{nil, err}
return
}
- if id != in.Id {
+ if q.Id != in.Id {
c <- &Envelope{in.Answer, ErrId}
return
}
@@ -110,9 +110,11 @@ func (t *Transfer) inAxfr(id uint16, c chan *Envelope) {
}
}
-func (t *Transfer) inIxfr(id uint16, c chan *Envelope) {
+func (t *Transfer) inIxfr(q *Msg, c chan *Envelope) {
serial := uint32(0) // The first serial seen is the current server serial
- first := true
+ axfr := true
+ n := 0
+ qser := q.Ns[0].(*SOA).Serial
defer t.Close()
defer close(c)
timeout := dnsTimeout
@@ -126,21 +128,15 @@ func (t *Transfer) inIxfr(id uint16, c chan *Envelope) {
c <- &Envelope{nil, err}
return
}
- if id != in.Id {
+ if q.Id != in.Id {
c <- &Envelope{in.Answer, ErrId}
return
}
- if first {
- if in.Rcode != RcodeSuccess {
- c <- &Envelope{in.Answer, &Error{err: fmt.Sprintf(errXFR, in.Rcode)}}
- return
- }
- // A single SOA RR signals "no changes"
- if len(in.Answer) == 1 && isSOAFirst(in) {
- c <- &Envelope{in.Answer, nil}
- return
- }
-
+ if in.Rcode != RcodeSuccess {
+ c <- &Envelope{in.Answer, &Error{err: fmt.Sprintf(errXFR, in.Rcode)}}
+ return
+ }
+ if n == 0 {
// Check if the returned answer is ok
if !isSOAFirst(in) {
c <- &Envelope{in.Answer, ErrSoa}
@@ -148,21 +144,30 @@ func (t *Transfer) inIxfr(id uint16, c chan *Envelope) {
}
// This serial is important
serial = in.Answer[0].(*SOA).Serial
- first = !first
+ // Check if there are no changes in zone
+ if qser >= serial {
+ c <- &Envelope{in.Answer, nil}
+ return
+ }
}
-
// Now we need to check each message for SOA records, to see what we need to do
- if !first {
- t.tsigTimersOnly = true
- // If the last record in the IXFR contains the servers' SOA, we should quit
- if v, ok := in.Answer[len(in.Answer)-1].(*SOA); ok {
+ t.tsigTimersOnly = true
+ for _, rr := range in.Answer {
+ if v, ok := rr.(*SOA); ok {
if v.Serial == serial {
- c <- &Envelope{in.Answer, nil}
- return
+ n++
+ // quit if it's a full axfr or the the servers' SOA is repeated the third time
+ if axfr && n == 2 || n == 3 {
+ c <- &Envelope{in.Answer, nil}
+ return
+ }
+ } else if axfr {
+ // it's an ixfr
+ axfr = false
}
}
- c <- &Envelope{in.Answer, nil}
}
+ c <- &Envelope{in.Answer, nil}
}
}
diff --git a/vendor/github.com/miekg/dns/xfr_test.go b/vendor/github.com/miekg/dns/xfr_test.go
index a478963a3..e7cc6b2fa 100644
--- a/vendor/github.com/miekg/dns/xfr_test.go
+++ b/vendor/github.com/miekg/dns/xfr_test.go
@@ -39,7 +39,7 @@ func TestAXFR_Miek(t *testing.T) {
break
}
for _, rr := range ex.RR {
- t.Log(rr.String())
+ // Nothing
}
}
}
@@ -90,7 +90,7 @@ func TestAXFR_Miek_Tsig(t *testing.T) {
break
}
for _, rr := range ex.RR {
- t.Log(rr.String())
+ // Nothing
}
}
}
diff --git a/vendor/github.com/miekg/dns/zcompress.go b/vendor/github.com/miekg/dns/zcompress.go
index b277978b9..ee9841ed5 100644
--- a/vendor/github.com/miekg/dns/zcompress.go
+++ b/vendor/github.com/miekg/dns/zcompress.go
@@ -5,83 +5,80 @@ package dns
func compressionLenHelperType(c map[string]int, r RR) {
switch x := r.(type) {
- case *PTR:
- compressionLenHelper(c, x.Ptr)
- case *SOA:
- compressionLenHelper(c, x.Ns)
- compressionLenHelper(c, x.Mbox)
case *AFSDB:
compressionLenHelper(c, x.Hostname)
+ case *CNAME:
+ compressionLenHelper(c, x.Target)
+ case *DNAME:
+ compressionLenHelper(c, x.Target)
case *HIP:
for i := range x.RendezvousServers {
compressionLenHelper(c, x.RendezvousServers[i])
}
+ case *KX:
+ compressionLenHelper(c, x.Exchanger)
case *LP:
compressionLenHelper(c, x.Fqdn)
- case *CNAME:
- compressionLenHelper(c, x.Target)
case *MB:
compressionLenHelper(c, x.Mb)
- case *RP:
- compressionLenHelper(c, x.Mbox)
- compressionLenHelper(c, x.Txt)
- case *RRSIG:
- compressionLenHelper(c, x.SignerName)
+ case *MD:
+ compressionLenHelper(c, x.Md)
case *MF:
compressionLenHelper(c, x.Mf)
+ case *MG:
+ compressionLenHelper(c, x.Mg)
case *MINFO:
compressionLenHelper(c, x.Rmail)
compressionLenHelper(c, x.Email)
- case *SIG:
- compressionLenHelper(c, x.SignerName)
- case *SRV:
- compressionLenHelper(c, x.Target)
- case *TSIG:
- compressionLenHelper(c, x.Algorithm)
- case *KX:
- compressionLenHelper(c, x.Exchanger)
- case *MG:
- compressionLenHelper(c, x.Mg)
- case *NSAPPTR:
- compressionLenHelper(c, x.Ptr)
- case *PX:
- compressionLenHelper(c, x.Map822)
- compressionLenHelper(c, x.Mapx400)
- case *DNAME:
- compressionLenHelper(c, x.Target)
case *MR:
compressionLenHelper(c, x.Mr)
case *MX:
compressionLenHelper(c, x.Mx)
- case *TKEY:
- compressionLenHelper(c, x.Algorithm)
- case *NSEC:
- compressionLenHelper(c, x.NextDomain)
- case *TALINK:
- compressionLenHelper(c, x.PreviousName)
- compressionLenHelper(c, x.NextName)
- case *MD:
- compressionLenHelper(c, x.Md)
case *NAPTR:
compressionLenHelper(c, x.Replacement)
case *NS:
compressionLenHelper(c, x.Ns)
+ case *NSAPPTR:
+ compressionLenHelper(c, x.Ptr)
+ case *NSEC:
+ compressionLenHelper(c, x.NextDomain)
+ case *PTR:
+ compressionLenHelper(c, x.Ptr)
+ case *PX:
+ compressionLenHelper(c, x.Map822)
+ compressionLenHelper(c, x.Mapx400)
+ case *RP:
+ compressionLenHelper(c, x.Mbox)
+ compressionLenHelper(c, x.Txt)
+ case *RRSIG:
+ compressionLenHelper(c, x.SignerName)
case *RT:
compressionLenHelper(c, x.Host)
+ case *SIG:
+ compressionLenHelper(c, x.SignerName)
+ case *SOA:
+ compressionLenHelper(c, x.Ns)
+ compressionLenHelper(c, x.Mbox)
+ case *SRV:
+ compressionLenHelper(c, x.Target)
+ case *TALINK:
+ compressionLenHelper(c, x.PreviousName)
+ compressionLenHelper(c, x.NextName)
+ case *TKEY:
+ compressionLenHelper(c, x.Algorithm)
+ case *TSIG:
+ compressionLenHelper(c, x.Algorithm)
}
}
func compressionLenSearchType(c map[string]int, r RR) (int, bool) {
switch x := r.(type) {
- case *MG:
- k1, ok1 := compressionLenSearch(c, x.Mg)
- return k1, ok1
- case *PTR:
- k1, ok1 := compressionLenSearch(c, x.Ptr)
- return k1, ok1
case *AFSDB:
k1, ok1 := compressionLenSearch(c, x.Hostname)
return k1, ok1
+ case *CNAME:
+ k1, ok1 := compressionLenSearch(c, x.Target)
+ return k1, ok1
case *MB:
k1, ok1 := compressionLenSearch(c, x.Mb)
return k1, ok1
@@ -91,18 +88,8 @@ func compressionLenSearchType(c map[string]int, r RR) (int, bool) {
case *MF:
k1, ok1 := compressionLenSearch(c, x.Mf)
return k1, ok1
- case *NS:
- k1, ok1 := compressionLenSearch(c, x.Ns)
- return k1, ok1
- case *RT:
- k1, ok1 := compressionLenSearch(c, x.Host)
- return k1, ok1
- case *SOA:
- k1, ok1 := compressionLenSearch(c, x.Ns)
- k2, ok2 := compressionLenSearch(c, x.Mbox)
- return k1 + k2, ok1 && ok2
- case *CNAME:
- k1, ok1 := compressionLenSearch(c, x.Target)
+ case *MG:
+ k1, ok1 := compressionLenSearch(c, x.Mg)
return k1, ok1
case *MINFO:
k1, ok1 := compressionLenSearch(c, x.Rmail)
@@ -114,6 +101,19 @@ func compressionLenSearchType(c map[string]int, r RR) (int, bool) {
case *MX:
k1, ok1 := compressionLenSearch(c, x.Mx)
return k1, ok1
+ case *NS:
+ k1, ok1 := compressionLenSearch(c, x.Ns)
+ return k1, ok1
+ case *PTR:
+ k1, ok1 := compressionLenSearch(c, x.Ptr)
+ return k1, ok1
+ case *RT:
+ k1, ok1 := compressionLenSearch(c, x.Host)
+ return k1, ok1
+ case *SOA:
+ k1, ok1 := compressionLenSearch(c, x.Ns)
+ k2, ok2 := compressionLenSearch(c, x.Mbox)
+ return k1 + k2, ok1 && ok2
}
return 0, false
}
diff --git a/vendor/github.com/miekg/dns/ztypes.go b/vendor/github.com/miekg/dns/ztypes.go
index 3e534f12e..0613ba09d 100644
--- a/vendor/github.com/miekg/dns/ztypes.go
+++ b/vendor/github.com/miekg/dns/ztypes.go
@@ -1,5 +1,5 @@
// *** DO NOT MODIFY ***
-// AUTOGENERATED BY go generate from type_generate.go
+// AUTOGENERATED BY go generate from types_generate.go
package dns
@@ -163,7 +163,6 @@ var TypeToString = map[uint16]string{
TypeNSAPPTR: "NSAP-PTR",
}
-// Header() functions
func (rr *A) Header() *RR_Header { return &rr.Hdr }
func (rr *AAAA) Header() *RR_Header { return &rr.Hdr }
func (rr *AFSDB) Header() *RR_Header { return &rr.Hdr }
diff --git a/vendor/github.com/mitchellh/mapstructure/mapstructure.go b/vendor/github.com/mitchellh/mapstructure/mapstructure.go
index 6ec5c3335..30a9957c6 100644
--- a/vendor/github.com/mitchellh/mapstructure/mapstructure.go
+++ b/vendor/github.com/mitchellh/mapstructure/mapstructure.go
@@ -686,7 +686,11 @@ func (d *Decoder) decodeStruct(name string, data interface{}, val reflect.Value)
// Compile the list of all the fields that we're going to be decoding
// from all the structs.
- fields := make(map[*reflect.StructField]reflect.Value)
+ type field struct {
+ field reflect.StructField
+ val reflect.Value
+ }
+ fields := []field{}
for len(structs) > 0 {
structVal := structs[0]
structs = structs[1:]
@@ -718,14 +722,16 @@ func (d *Decoder) decodeStruct(name string, data interface{}, val reflect.Value)
}
// Normal struct field, store it away
- fields[&fieldType] = structVal.Field(i)
+ fields = append(fields, field{fieldType, structVal.Field(i)})
}
}
- for fieldType, field := range fields {
- fieldName := fieldType.Name
+ // for fieldType, field := range fields {
+ for _, f := range fields {
+ field, fieldValue := f.field, f.val
+ fieldName := field.Name
- tagValue := fieldType.Tag.Get(d.config.TagName)
+ tagValue := field.Tag.Get(d.config.TagName)
tagValue = strings.SplitN(tagValue, ",", 2)[0]
if tagValue != "" {
fieldName = tagValue
@@ -760,14 +766,14 @@ func (d *Decoder) decodeStruct(name string, data interface{}, val reflect.Value)
// Delete the key we're using from the unused map so we stop tracking
delete(dataValKeysUnused, rawMapKey.Interface())
- if !field.IsValid() {
+ if !fieldValue.IsValid() {
// This should never happen
panic("field is not valid")
}
// If we can't set the field, then it is unexported or something,
// and we just continue onwards.
- if !field.CanSet() {
+ if !fieldValue.CanSet() {
continue
}
@@ -777,7 +783,7 @@ func (d *Decoder) decodeStruct(name string, data interface{}, val reflect.Value)
fieldName = fmt.Sprintf("%s.%s", name, fieldName)
}
- if err := d.decode(fieldName, rawMapVal.Interface(), field); err != nil {
+ if err := d.decode(fieldName, rawMapVal.Interface(), fieldValue); err != nil {
errors = appendErrors(errors, err)
}
}
diff --git a/vendor/github.com/nicksnyder/go-i18n/i18n/language/language.go b/vendor/github.com/nicksnyder/go-i18n/i18n/language/language.go
index 9a155efc5..b045a2751 100644
--- a/vendor/github.com/nicksnyder/go-i18n/i18n/language/language.go
+++ b/vendor/github.com/nicksnyder/go-i18n/i18n/language/language.go
@@ -45,7 +45,7 @@ func Parse(src string) []*Language {
switch chr {
case ',', ';', '.':
tag := strings.TrimSpace(src[start:end])
- if spec := getPluralSpec(tag); spec != nil {
+ if spec := GetPluralSpec(tag); spec != nil {
langs = append(langs, &Language{NormalizeTag(tag), spec})
}
start = end + 1
@@ -53,12 +53,12 @@ func Parse(src string) []*Language {
}
if start > 0 {
tag := strings.TrimSpace(src[start:])
- if spec := getPluralSpec(tag); spec != nil {
+ if spec := GetPluralSpec(tag); spec != nil {
langs = append(langs, &Language{NormalizeTag(tag), spec})
}
return dedupe(langs)
}
- if spec := getPluralSpec(src); spec != nil {
+ if spec := GetPluralSpec(src); spec != nil {
langs = append(langs, &Language{NormalizeTag(src), spec})
}
return langs
diff --git a/vendor/github.com/nicksnyder/go-i18n/i18n/language/pluralspec.go b/vendor/github.com/nicksnyder/go-i18n/i18n/language/pluralspec.go
index 85b2a1b37..fc31e8807 100644
--- a/vendor/github.com/nicksnyder/go-i18n/i18n/language/pluralspec.go
+++ b/vendor/github.com/nicksnyder/go-i18n/i18n/language/pluralspec.go
@@ -36,9 +36,9 @@ func (ps *PluralSpec) Plural(number interface{}) (Plural, error) {
return ps.PluralFunc(ops), nil
}
-// getPluralSpec returns the PluralSpec that matches the longest prefix of tag.
+// GetPluralSpec returns the PluralSpec that matches the longest prefix of tag.
// It returns nil if no PluralSpec matches tag.
-func getPluralSpec(tag string) *PluralSpec {
+func GetPluralSpec(tag string) *PluralSpec {
tag = NormalizeTag(tag)
subtag := tag
for {
diff --git a/vendor/github.com/nicksnyder/go-i18n/i18n/language/pluralspec_test.go b/vendor/github.com/nicksnyder/go-i18n/i18n/language/pluralspec_test.go
index 919b489bd..51c1685ad 100644
--- a/vendor/github.com/nicksnyder/go-i18n/i18n/language/pluralspec_test.go
+++ b/vendor/github.com/nicksnyder/go-i18n/i18n/language/pluralspec_test.go
@@ -68,7 +68,7 @@ func TestGetPluralSpec(t *testing.T) {
{"xx", nil},
}
for _, test := range tests {
- spec := getPluralSpec(test.src)
+ spec := GetPluralSpec(test.src)
if spec != test.spec {
t.Errorf("getPluralSpec(%q) = %q expected %q", test.src, spec, test.spec)
}
diff --git a/vendor/github.com/pelletier/go-toml/.gitignore b/vendor/github.com/pelletier/go-toml/.gitignore
index f1b619018..99e38bbc5 100644
--- a/vendor/github.com/pelletier/go-toml/.gitignore
+++ b/vendor/github.com/pelletier/go-toml/.gitignore
@@ -1 +1,2 @@
test_program/test_program_bin
+fuzz/
diff --git a/vendor/github.com/pelletier/go-toml/.travis.yml b/vendor/github.com/pelletier/go-toml/.travis.yml
index 496691166..6e644fdfd 100644
--- a/vendor/github.com/pelletier/go-toml/.travis.yml
+++ b/vendor/github.com/pelletier/go-toml/.travis.yml
@@ -1,9 +1,8 @@
sudo: false
language: go
go:
- - 1.7.6
- - 1.8.3
- - 1.9
+ - 1.8.4
+ - 1.9.1
- tip
matrix:
allow_failures:
diff --git a/vendor/github.com/pelletier/go-toml/README.md b/vendor/github.com/pelletier/go-toml/README.md
index 2681690d5..0d357acf3 100644
--- a/vendor/github.com/pelletier/go-toml/README.md
+++ b/vendor/github.com/pelletier/go-toml/README.md
@@ -57,9 +57,9 @@ type Config struct {
}
doc := []byte(`
-[postgres]
-user = "pelletier"
-password = "mypassword"`)
+[Postgres]
+User = "pelletier"
+Password = "mypassword"`)
config := Config{}
toml.Unmarshal(doc, &config)
@@ -114,6 +114,18 @@ You have to make sure two kind of tests run:
You can run both of them using `./test.sh`.
+### Fuzzing
+
+The script `./fuzz.sh` is available to
+run [go-fuzz](https://github.com/dvyukov/go-fuzz) on go-toml.
+
+## Versioning
+
+Go-toml follows [Semantic Versioning](http://semver.org/). The supported version
+of [TOML](https://github.com/toml-lang/toml) is indicated at the beginning of
+this document. The last two major versions of Go are supported
+(see [Go Release Policy](https://golang.org/doc/devel/release.html#policy)).
+
## License
The MIT License (MIT). Read [LICENSE](LICENSE).
diff --git a/vendor/github.com/pelletier/go-toml/doc.go b/vendor/github.com/pelletier/go-toml/doc.go
index 3c89619e8..d5fd98c02 100644
--- a/vendor/github.com/pelletier/go-toml/doc.go
+++ b/vendor/github.com/pelletier/go-toml/doc.go
@@ -17,7 +17,7 @@
// JSONPath-like queries
//
// The package github.com/pelletier/go-toml/query implements a system
-// similar to JSONPath to quickly retrive elements of a TOML document using a
+// similar to JSONPath to quickly retrieve elements of a TOML document using a
// single expression. See the package documentation for more information.
//
package toml
diff --git a/vendor/github.com/pelletier/go-toml/doc_test.go b/vendor/github.com/pelletier/go-toml/doc_test.go
index a48c04b01..3b8171b22 100644
--- a/vendor/github.com/pelletier/go-toml/doc_test.go
+++ b/vendor/github.com/pelletier/go-toml/doc_test.go
@@ -61,19 +61,24 @@ func ExampleMarshal() {
type Postgres struct {
User string `toml:"user"`
Password string `toml:"password"`
+ Database string `toml:"db" commented:"true" comment:"not used anymore"`
}
type Config struct {
- Postgres Postgres `toml:"postgres"`
+ Postgres Postgres `toml:"postgres" comment:"Postgres configuration"`
}
- config := Config{Postgres{User: "pelletier", Password: "mypassword"}}
+ config := Config{Postgres{User: "pelletier", Password: "mypassword", Database: "old_database"}}
b, err := toml.Marshal(config)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(b))
// Output:
+ // # Postgres configuration
// [postgres]
+ //
+ // # not used anymore
+ // # db = "old_database"
// password = "mypassword"
// user = "pelletier"
}
diff --git a/vendor/github.com/pelletier/go-toml/fuzz.go b/vendor/github.com/pelletier/go-toml/fuzz.go
new file mode 100644
index 000000000..14570c8d3
--- /dev/null
+++ b/vendor/github.com/pelletier/go-toml/fuzz.go
@@ -0,0 +1,31 @@
+// +build gofuzz
+
+package toml
+
+func Fuzz(data []byte) int {
+ tree, err := LoadBytes(data)
+ if err != nil {
+ if tree != nil {
+ panic("tree must be nil if there is an error")
+ }
+ return 0
+ }
+
+ str, err := tree.ToTomlString()
+ if err != nil {
+ if str != "" {
+ panic(`str must be "" if there is an error`)
+ }
+ panic(err)
+ }
+
+ tree, err = Load(str)
+ if err != nil {
+ if tree != nil {
+ panic("tree must be nil if there is an error")
+ }
+ return 0
+ }
+
+ return 1
+}
diff --git a/vendor/github.com/pelletier/go-toml/fuzz.sh b/vendor/github.com/pelletier/go-toml/fuzz.sh
new file mode 100755
index 000000000..3204b4c44
--- /dev/null
+++ b/vendor/github.com/pelletier/go-toml/fuzz.sh
@@ -0,0 +1,15 @@
+#! /bin/sh
+set -eu
+
+go get github.com/dvyukov/go-fuzz/go-fuzz
+go get github.com/dvyukov/go-fuzz/go-fuzz-build
+
+if [ ! -e toml-fuzz.zip ]; then
+ go-fuzz-build github.com/pelletier/go-toml
+fi
+
+rm -fr fuzz
+mkdir -p fuzz/corpus
+cp *.toml fuzz/corpus
+
+go-fuzz -bin=toml-fuzz.zip -workdir=fuzz
diff --git a/vendor/github.com/pelletier/go-toml/keysparsing.go b/vendor/github.com/pelletier/go-toml/keysparsing.go
index d62ca5fd1..9707c6884 100644
--- a/vendor/github.com/pelletier/go-toml/keysparsing.go
+++ b/vendor/github.com/pelletier/go-toml/keysparsing.go
@@ -6,15 +6,37 @@ import (
"bytes"
"errors"
"fmt"
+ "strconv"
"unicode"
)
+var escapeSequenceMap = map[rune]rune{
+ 'b': '\b',
+ 't': '\t',
+ 'n': '\n',
+ 'f': '\f',
+ 'r': '\r',
+ '"': '"',
+ '\\': '\\',
+}
+
+type parseKeyState int
+
+const (
+ BARE parseKeyState = iota
+ BASIC
+ LITERAL
+ ESC
+ UNICODE_4
+ UNICODE_8
+)
+
func parseKey(key string) ([]string, error) {
groups := []string{}
var buffer bytes.Buffer
- inQuotes := false
+ var hex bytes.Buffer
+ state := BARE
wasInQuotes := false
- escapeNext := false
ignoreSpace := true
expectDot := false
@@ -25,25 +47,67 @@ func parseKey(key string) ([]string, error) {
}
ignoreSpace = false
}
- if escapeNext {
- buffer.WriteRune(char)
- escapeNext = false
+
+ if state == ESC {
+ if char == 'u' {
+ state = UNICODE_4
+ hex.Reset()
+ } else if char == 'U' {
+ state = UNICODE_8
+ hex.Reset()
+ } else if newChar, ok := escapeSequenceMap[char]; ok {
+ buffer.WriteRune(newChar)
+ state = BASIC
+ } else {
+ return nil, fmt.Errorf(`invalid escape sequence \%c`, char)
+ }
+ continue
+ }
+
+ if state == UNICODE_4 || state == UNICODE_8 {
+ if isHexDigit(char) {
+ hex.WriteRune(char)
+ }
+ if (state == UNICODE_4 && hex.Len() == 4) || (state == UNICODE_8 && hex.Len() == 8) {
+ if value, err := strconv.ParseInt(hex.String(), 16, 32); err == nil {
+ buffer.WriteRune(rune(value))
+ } else {
+ return nil, err
+ }
+ state = BASIC
+ }
continue
}
+
switch char {
case '\\':
- escapeNext = true
- continue
+ if state == BASIC {
+ state = ESC
+ } else if state == LITERAL {
+ buffer.WriteRune(char)
+ }
+ case '\'':
+ if state == BARE {
+ state = LITERAL
+ } else if state == LITERAL {
+ groups = append(groups, buffer.String())
+ buffer.Reset()
+ wasInQuotes = true
+ state = BARE
+ }
+ expectDot = false
case '"':
- if inQuotes {
+ if state == BARE {
+ state = BASIC
+ } else if state == BASIC {
groups = append(groups, buffer.String())
buffer.Reset()
+ state = BARE
wasInQuotes = true
}
- inQuotes = !inQuotes
expectDot = false
case '.':
- if inQuotes {
+ if state != BARE {
buffer.WriteRune(char)
} else {
if !wasInQuotes {
@@ -58,28 +122,31 @@ func parseKey(key string) ([]string, error) {
wasInQuotes = false
}
case ' ':
- if inQuotes {
+ if state == BASIC {
buffer.WriteRune(char)
} else {
expectDot = true
}
default:
- if !inQuotes && !isValidBareChar(char) {
- return nil, fmt.Errorf("invalid bare character: %c", char)
- }
- if !inQuotes && expectDot {
- return nil, errors.New("what?")
+ if state == BARE {
+ if !isValidBareChar(char) {
+ return nil, fmt.Errorf("invalid bare character: %c", char)
+ } else if expectDot {
+ return nil, errors.New("what?")
+ }
}
buffer.WriteRune(char)
expectDot = false
}
}
- if inQuotes {
- return nil, errors.New("mismatched quotes")
- }
- if escapeNext {
+
+ // state must be BARE at the end
+ if state == ESC {
return nil, errors.New("unfinished escape sequence")
+ } else if state != BARE {
+ return nil, errors.New("mismatched quotes")
}
+
if buffer.Len() > 0 {
groups = append(groups, buffer.String())
}
diff --git a/vendor/github.com/pelletier/go-toml/keysparsing_test.go b/vendor/github.com/pelletier/go-toml/keysparsing_test.go
index 1a9ecccaa..7aa4cd64a 100644
--- a/vendor/github.com/pelletier/go-toml/keysparsing_test.go
+++ b/vendor/github.com/pelletier/go-toml/keysparsing_test.go
@@ -22,7 +22,10 @@ func testResult(t *testing.T, key string, expected []string) {
}
func testError(t *testing.T, key string, expectedError string) {
- _, err := parseKey(key)
+ res, err := parseKey(key)
+ if err == nil {
+ t.Fatalf("Expected error, but succesfully parsed key %s", res)
+ }
if fmt.Sprintf("%s", err) != expectedError {
t.Fatalf("Expected error \"%s\", but got \"%s\".", expectedError, err)
}
@@ -47,6 +50,17 @@ func TestBaseKeyPound(t *testing.T) {
func TestQuotedKeys(t *testing.T) {
testResult(t, `hello."foo".bar`, []string{"hello", "foo", "bar"})
testResult(t, `"hello!"`, []string{"hello!"})
+ testResult(t, `"hello\tworld"`, []string{"hello\tworld"})
+ testResult(t, `"\U0001F914"`, []string{"\U0001F914"})
+ testResult(t, `"\u2764"`, []string{"\u2764"})
+
+ testResult(t, `hello.'foo'.bar`, []string{"hello", "foo", "bar"})
+ testResult(t, `'hello!'`, []string{"hello!"})
+ testResult(t, `'hello\tworld'`, []string{`hello\tworld`})
+
+ testError(t, `"\w"`, `invalid escape sequence \w`)
+ testError(t, `"\`, `unfinished escape sequence`)
+ testError(t, `"\t`, `mismatched quotes`)
}
func TestEmptyKey(t *testing.T) {
diff --git a/vendor/github.com/pelletier/go-toml/marshal.go b/vendor/github.com/pelletier/go-toml/marshal.go
index 1a3176f97..1bbdfa1d8 100644
--- a/vendor/github.com/pelletier/go-toml/marshal.go
+++ b/vendor/github.com/pelletier/go-toml/marshal.go
@@ -4,17 +4,29 @@ import (
"bytes"
"errors"
"fmt"
+ "io"
"reflect"
+ "strconv"
"strings"
"time"
)
type tomlOpts struct {
name string
+ comment string
+ commented bool
include bool
omitempty bool
}
+type encOpts struct {
+ quoteMapKeys bool
+}
+
+var encOptsDefaults = encOpts{
+ quoteMapKeys: false,
+}
+
var timeType = reflect.TypeOf(time.Time{})
var marshalerType = reflect.TypeOf(new(Marshaler)).Elem()
@@ -94,8 +106,15 @@ encoder, except that there is no concept of a Marshaler interface or MarshalTOML
function for sub-structs, and currently only definite types can be marshaled
(i.e. no `interface{}`).
+The following struct annotations are supported:
+
+ toml:"Field" Overrides the field's name to output.
+ omitempty When set, empty values and groups are not emitted.
+ comment:"comment" Emits a # comment on the same line. This supports new lines.
+ commented:"true" Emits the value as commented.
+
Note that pointers are automatically assigned the "omitempty" option, as TOML
-explicity does not handle null values (saying instead the label should be
+explicitly does not handle null values (saying instead the label should be
dropped).
Tree structural types and corresponding marshal types:
@@ -115,6 +134,47 @@ Tree primitive types and corresponding marshal types:
time.Time time.Time{}, pointers to same
*/
func Marshal(v interface{}) ([]byte, error) {
+ return NewEncoder(nil).marshal(v)
+}
+
+// Encoder writes TOML values to an output stream.
+type Encoder struct {
+ w io.Writer
+ encOpts
+}
+
+// NewEncoder returns a new encoder that writes to w.
+func NewEncoder(w io.Writer) *Encoder {
+ return &Encoder{
+ w: w,
+ encOpts: encOptsDefaults,
+ }
+}
+
+// Encode writes the TOML encoding of v to the stream.
+//
+// See the documentation for Marshal for details.
+func (e *Encoder) Encode(v interface{}) error {
+ b, err := e.marshal(v)
+ if err != nil {
+ return err
+ }
+ if _, err := e.w.Write(b); err != nil {
+ return err
+ }
+ return nil
+}
+
+// QuoteMapKeys sets up the encoder to encode
+// maps with string type keys with quoted TOML keys.
+//
+// This relieves the character limitations on map keys.
+func (e *Encoder) QuoteMapKeys(v bool) *Encoder {
+ e.quoteMapKeys = v
+ return e
+}
+
+func (e *Encoder) marshal(v interface{}) ([]byte, error) {
mtype := reflect.TypeOf(v)
if mtype.Kind() != reflect.Struct {
return []byte{}, errors.New("Only a struct can be marshaled to TOML")
@@ -123,7 +183,7 @@ func Marshal(v interface{}) ([]byte, error) {
if isCustomMarshaler(mtype) {
return callCustomMarshaler(sval)
}
- t, err := valueToTree(mtype, sval)
+ t, err := e.valueToTree(mtype, sval)
if err != nil {
return []byte{}, err
}
@@ -132,9 +192,9 @@ func Marshal(v interface{}) ([]byte, error) {
}
// Convert given marshal struct or map value to toml tree
-func valueToTree(mtype reflect.Type, mval reflect.Value) (*Tree, error) {
+func (e *Encoder) valueToTree(mtype reflect.Type, mval reflect.Value) (*Tree, error) {
if mtype.Kind() == reflect.Ptr {
- return valueToTree(mtype.Elem(), mval.Elem())
+ return e.valueToTree(mtype.Elem(), mval.Elem())
}
tval := newTree()
switch mtype.Kind() {
@@ -143,31 +203,39 @@ func valueToTree(mtype reflect.Type, mval reflect.Value) (*Tree, error) {
mtypef, mvalf := mtype.Field(i), mval.Field(i)
opts := tomlOptions(mtypef)
if opts.include && (!opts.omitempty || !isZero(mvalf)) {
- val, err := valueToToml(mtypef.Type, mvalf)
+ val, err := e.valueToToml(mtypef.Type, mvalf)
if err != nil {
return nil, err
}
- tval.Set(opts.name, val)
+ tval.Set(opts.name, opts.comment, opts.commented, val)
}
}
case reflect.Map:
for _, key := range mval.MapKeys() {
mvalf := mval.MapIndex(key)
- val, err := valueToToml(mtype.Elem(), mvalf)
+ val, err := e.valueToToml(mtype.Elem(), mvalf)
if err != nil {
return nil, err
}
- tval.Set(key.String(), val)
+ if e.quoteMapKeys {
+ keyStr, err := tomlValueStringRepresentation(key.String())
+ if err != nil {
+ return nil, err
+ }
+ tval.SetPath([]string{keyStr}, "", false, val)
+ } else {
+ tval.Set(key.String(), "", false, val)
+ }
}
}
return tval, nil
}
// Convert given marshal slice to slice of Toml trees
-func valueToTreeSlice(mtype reflect.Type, mval reflect.Value) ([]*Tree, error) {
+func (e *Encoder) valueToTreeSlice(mtype reflect.Type, mval reflect.Value) ([]*Tree, error) {
tval := make([]*Tree, mval.Len(), mval.Len())
for i := 0; i < mval.Len(); i++ {
- val, err := valueToTree(mtype.Elem(), mval.Index(i))
+ val, err := e.valueToTree(mtype.Elem(), mval.Index(i))
if err != nil {
return nil, err
}
@@ -177,10 +245,10 @@ func valueToTreeSlice(mtype reflect.Type, mval reflect.Value) ([]*Tree, error) {
}
// Convert given marshal slice to slice of toml values
-func valueToOtherSlice(mtype reflect.Type, mval reflect.Value) (interface{}, error) {
+func (e *Encoder) valueToOtherSlice(mtype reflect.Type, mval reflect.Value) (interface{}, error) {
tval := make([]interface{}, mval.Len(), mval.Len())
for i := 0; i < mval.Len(); i++ {
- val, err := valueToToml(mtype.Elem(), mval.Index(i))
+ val, err := e.valueToToml(mtype.Elem(), mval.Index(i))
if err != nil {
return nil, err
}
@@ -190,19 +258,19 @@ func valueToOtherSlice(mtype reflect.Type, mval reflect.Value) (interface{}, err
}
// Convert given marshal value to toml value
-func valueToToml(mtype reflect.Type, mval reflect.Value) (interface{}, error) {
+func (e *Encoder) valueToToml(mtype reflect.Type, mval reflect.Value) (interface{}, error) {
if mtype.Kind() == reflect.Ptr {
- return valueToToml(mtype.Elem(), mval.Elem())
+ return e.valueToToml(mtype.Elem(), mval.Elem())
}
switch {
case isCustomMarshaler(mtype):
return callCustomMarshaler(mval)
case isTree(mtype):
- return valueToTree(mtype, mval)
+ return e.valueToTree(mtype, mval)
case isTreeSlice(mtype):
- return valueToTreeSlice(mtype, mval)
+ return e.valueToTreeSlice(mtype, mval)
case isOtherSlice(mtype):
- return valueToOtherSlice(mtype, mval)
+ return e.valueToOtherSlice(mtype, mval)
default:
switch mtype.Kind() {
case reflect.Bool:
@@ -227,17 +295,16 @@ func valueToToml(mtype reflect.Type, mval reflect.Value) (interface{}, error) {
// Neither Unmarshaler interfaces nor UnmarshalTOML functions are supported for
// sub-structs, and only definite types can be unmarshaled.
func (t *Tree) Unmarshal(v interface{}) error {
- mtype := reflect.TypeOf(v)
- if mtype.Kind() != reflect.Ptr || mtype.Elem().Kind() != reflect.Struct {
- return errors.New("Only a pointer to struct can be unmarshaled from TOML")
- }
+ d := Decoder{tval: t}
+ return d.unmarshal(v)
+}
- sval, err := valueFromTree(mtype.Elem(), t)
- if err != nil {
- return err
- }
- reflect.ValueOf(v).Elem().Set(sval)
- return nil
+// Marshal returns the TOML encoding of Tree.
+// See Marshal() documentation for types mapping table.
+func (t *Tree) Marshal() ([]byte, error) {
+ var buf bytes.Buffer
+ err := NewEncoder(&buf).Encode(t)
+ return buf.Bytes(), err
}
// Unmarshal parses the TOML-encoded data and stores the result in the value
@@ -246,6 +313,10 @@ func (t *Tree) Unmarshal(v interface{}) error {
// sub-structs, and currently only definite types can be unmarshaled to (i.e. no
// `interface{}`).
//
+// The following struct annotations are supported:
+//
+// toml:"Field" Overrides the field's name to map to.
+//
// See Marshal() documentation for types mapping table.
func Unmarshal(data []byte, v interface{}) error {
t, err := LoadReader(bytes.NewReader(data))
@@ -255,10 +326,52 @@ func Unmarshal(data []byte, v interface{}) error {
return t.Unmarshal(v)
}
+// Decoder reads and decodes TOML values from an input stream.
+type Decoder struct {
+ r io.Reader
+ tval *Tree
+ encOpts
+}
+
+// NewDecoder returns a new decoder that reads from r.
+func NewDecoder(r io.Reader) *Decoder {
+ return &Decoder{
+ r: r,
+ encOpts: encOptsDefaults,
+ }
+}
+
+// Decode reads a TOML-encoded value from it's input
+// and unmarshals it in the value pointed at by v.
+//
+// See the documentation for Marshal for details.
+func (d *Decoder) Decode(v interface{}) error {
+ var err error
+ d.tval, err = LoadReader(d.r)
+ if err != nil {
+ return err
+ }
+ return d.unmarshal(v)
+}
+
+func (d *Decoder) unmarshal(v interface{}) error {
+ mtype := reflect.TypeOf(v)
+ if mtype.Kind() != reflect.Ptr || mtype.Elem().Kind() != reflect.Struct {
+ return errors.New("Only a pointer to struct can be unmarshaled from TOML")
+ }
+
+ sval, err := d.valueFromTree(mtype.Elem(), d.tval)
+ if err != nil {
+ return err
+ }
+ reflect.ValueOf(v).Elem().Set(sval)
+ return nil
+}
+
// Convert toml tree to marshal struct or map, using marshal type
-func valueFromTree(mtype reflect.Type, tval *Tree) (reflect.Value, error) {
+func (d *Decoder) valueFromTree(mtype reflect.Type, tval *Tree) (reflect.Value, error) {
if mtype.Kind() == reflect.Ptr {
- return unwrapPointer(mtype, tval)
+ return d.unwrapPointer(mtype, tval)
}
var mval reflect.Value
switch mtype.Kind() {
@@ -276,7 +389,7 @@ func valueFromTree(mtype reflect.Type, tval *Tree) (reflect.Value, error) {
continue
}
val := tval.Get(key)
- mvalf, err := valueFromToml(mtypef.Type, val)
+ mvalf, err := d.valueFromToml(mtypef.Type, val)
if err != nil {
return mval, formatError(err, tval.GetPosition(key))
}
@@ -288,8 +401,9 @@ func valueFromTree(mtype reflect.Type, tval *Tree) (reflect.Value, error) {
case reflect.Map:
mval = reflect.MakeMap(mtype)
for _, key := range tval.Keys() {
- val := tval.Get(key)
- mvalf, err := valueFromToml(mtype.Elem(), val)
+ // TODO: path splits key
+ val := tval.GetPath([]string{key})
+ mvalf, err := d.valueFromToml(mtype.Elem(), val)
if err != nil {
return mval, formatError(err, tval.GetPosition(key))
}
@@ -300,10 +414,10 @@ func valueFromTree(mtype reflect.Type, tval *Tree) (reflect.Value, error) {
}
// Convert toml value to marshal struct/map slice, using marshal type
-func valueFromTreeSlice(mtype reflect.Type, tval []*Tree) (reflect.Value, error) {
+func (d *Decoder) valueFromTreeSlice(mtype reflect.Type, tval []*Tree) (reflect.Value, error) {
mval := reflect.MakeSlice(mtype, len(tval), len(tval))
for i := 0; i < len(tval); i++ {
- val, err := valueFromTree(mtype.Elem(), tval[i])
+ val, err := d.valueFromTree(mtype.Elem(), tval[i])
if err != nil {
return mval, err
}
@@ -313,10 +427,10 @@ func valueFromTreeSlice(mtype reflect.Type, tval []*Tree) (reflect.Value, error)
}
// Convert toml value to marshal primitive slice, using marshal type
-func valueFromOtherSlice(mtype reflect.Type, tval []interface{}) (reflect.Value, error) {
+func (d *Decoder) valueFromOtherSlice(mtype reflect.Type, tval []interface{}) (reflect.Value, error) {
mval := reflect.MakeSlice(mtype, len(tval), len(tval))
for i := 0; i < len(tval); i++ {
- val, err := valueFromToml(mtype.Elem(), tval[i])
+ val, err := d.valueFromToml(mtype.Elem(), tval[i])
if err != nil {
return mval, err
}
@@ -326,17 +440,30 @@ func valueFromOtherSlice(mtype reflect.Type, tval []interface{}) (reflect.Value,
}
// Convert toml value to marshal value, using marshal type
-func valueFromToml(mtype reflect.Type, tval interface{}) (reflect.Value, error) {
+func (d *Decoder) valueFromToml(mtype reflect.Type, tval interface{}) (reflect.Value, error) {
if mtype.Kind() == reflect.Ptr {
- return unwrapPointer(mtype, tval)
+ return d.unwrapPointer(mtype, tval)
}
- switch {
- case isTree(mtype):
- return valueFromTree(mtype, tval.(*Tree))
- case isTreeSlice(mtype):
- return valueFromTreeSlice(mtype, tval.([]*Tree))
- case isOtherSlice(mtype):
- return valueFromOtherSlice(mtype, tval.([]interface{}))
+
+ switch tval.(type) {
+ case *Tree:
+ if isTree(mtype) {
+ return d.valueFromTree(mtype, tval.(*Tree))
+ } else {
+ return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to a tree", tval, tval)
+ }
+ case []*Tree:
+ if isTreeSlice(mtype) {
+ return d.valueFromTreeSlice(mtype, tval.([]*Tree))
+ } else {
+ return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to trees", tval, tval)
+ }
+ case []interface{}:
+ if isOtherSlice(mtype) {
+ return d.valueFromOtherSlice(mtype, tval.([]interface{}))
+ } else {
+ return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to a slice", tval, tval)
+ }
default:
switch mtype.Kind() {
case reflect.Bool:
@@ -430,13 +557,13 @@ func valueFromToml(mtype reflect.Type, tval interface{}) (reflect.Value, error)
}
return reflect.ValueOf(val), nil
default:
- return reflect.ValueOf(nil), fmt.Errorf("Unmarshal can't handle %v(%v)", mtype, mtype.Kind())
+ return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to %v(%v)", tval, tval, mtype, mtype.Kind())
}
}
}
-func unwrapPointer(mtype reflect.Type, tval interface{}) (reflect.Value, error) {
- val, err := valueFromToml(mtype.Elem(), tval)
+func (d *Decoder) unwrapPointer(mtype reflect.Type, tval interface{}) (reflect.Value, error) {
+ val, err := d.valueFromToml(mtype.Elem(), tval)
if err != nil {
return reflect.ValueOf(nil), err
}
@@ -448,7 +575,12 @@ func unwrapPointer(mtype reflect.Type, tval interface{}) (reflect.Value, error)
func tomlOptions(vf reflect.StructField) tomlOpts {
tag := vf.Tag.Get("toml")
parse := strings.Split(tag, ",")
- result := tomlOpts{vf.Name, true, false}
+ var comment string
+ if c := vf.Tag.Get("comment"); c != "" {
+ comment = c
+ }
+ commented, _ := strconv.ParseBool(vf.Tag.Get("commented"))
+ result := tomlOpts{name: vf.Name, comment: comment, commented: commented, include: true, omitempty: false}
if parse[0] != "" {
if parse[0] == "-" && len(parse) == 1 {
result.include = false
diff --git a/vendor/github.com/pelletier/go-toml/marshal_test.go b/vendor/github.com/pelletier/go-toml/marshal_test.go
index dbfc7c1d1..e7d1d6e4d 100644
--- a/vendor/github.com/pelletier/go-toml/marshal_test.go
+++ b/vendor/github.com/pelletier/go-toml/marshal_test.go
@@ -6,6 +6,7 @@ import (
"fmt"
"io/ioutil"
"reflect"
+ "strings"
"testing"
"time"
)
@@ -508,6 +509,14 @@ func TestPointerUnmarshal(t *testing.T) {
}
}
+func TestUnmarshalTypeMismatch(t *testing.T) {
+ result := pointerMarshalTestStruct{}
+ err := Unmarshal([]byte("List = 123"), &result)
+ if !strings.HasPrefix(err.Error(), "(1, 1): Can't convert 123(int64) to []string(slice)") {
+ t.Errorf("Type mismatch must be reported: got %v", err.Error())
+ }
+}
+
type nestedMarshalTestStruct struct {
String [][]string
//Struct [][]basicMarshalTestSubStruct
@@ -598,3 +607,128 @@ func TestNestedCustomMarshaler(t *testing.T) {
t.Errorf("Bad nested custom marshaler: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result)
}
}
+
+var commentTestToml = []byte(`
+# it's a comment on type
+[postgres]
+ # isCommented = "dvalue"
+ noComment = "cvalue"
+
+ # A comment on AttrB with a
+ # break line
+ password = "bvalue"
+
+ # A comment on AttrA
+ user = "avalue"
+
+ [[postgres.My]]
+
+ # a comment on my on typeC
+ My = "Foo"
+
+ [[postgres.My]]
+
+ # a comment on my on typeC
+ My = "Baar"
+`)
+
+func TestMarshalComment(t *testing.T) {
+ type TypeC struct {
+ My string `comment:"a comment on my on typeC"`
+ }
+ type TypeB struct {
+ AttrA string `toml:"user" comment:"A comment on AttrA"`
+ AttrB string `toml:"password" comment:"A comment on AttrB with a\n break line"`
+ AttrC string `toml:"noComment"`
+ AttrD string `toml:"isCommented" commented:"true"`
+ My []TypeC
+ }
+ type TypeA struct {
+ TypeB TypeB `toml:"postgres" comment:"it's a comment on type"`
+ }
+
+ ta := []TypeC{{My: "Foo"}, {My: "Baar"}}
+ config := TypeA{TypeB{AttrA: "avalue", AttrB: "bvalue", AttrC: "cvalue", AttrD: "dvalue", My: ta}}
+ result, err := Marshal(config)
+ if err != nil {
+ t.Fatal(err)
+ }
+ expected := commentTestToml
+ if !bytes.Equal(result, expected) {
+ t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result)
+ }
+}
+
+type mapsTestStruct struct {
+ Simple map[string]string
+ Paths map[string]string
+ Other map[string]float64
+ X struct {
+ Y struct {
+ Z map[string]bool
+ }
+ }
+}
+
+var mapsTestData = mapsTestStruct{
+ Simple: map[string]string{
+ "one plus one": "two",
+ "next": "three",
+ },
+ Paths: map[string]string{
+ "/this/is/a/path": "/this/is/also/a/path",
+ "/heloo.txt": "/tmp/lololo.txt",
+ },
+ Other: map[string]float64{
+ "testing": 3.9999,
+ },
+ X: struct{ Y struct{ Z map[string]bool } }{
+ Y: struct{ Z map[string]bool }{
+ Z: map[string]bool{
+ "is.Nested": true,
+ },
+ },
+ },
+}
+var mapsTestToml = []byte(`
+[Other]
+ "testing" = 3.9999
+
+[Paths]
+ "/heloo.txt" = "/tmp/lololo.txt"
+ "/this/is/a/path" = "/this/is/also/a/path"
+
+[Simple]
+ "next" = "three"
+ "one plus one" = "two"
+
+[X]
+
+ [X.Y]
+
+ [X.Y.Z]
+ "is.Nested" = true
+`)
+
+func TestEncodeQuotedMapKeys(t *testing.T) {
+ var buf bytes.Buffer
+ if err := NewEncoder(&buf).QuoteMapKeys(true).Encode(mapsTestData); err != nil {
+ t.Fatal(err)
+ }
+ result := buf.Bytes()
+ expected := mapsTestToml
+ if !bytes.Equal(result, expected) {
+ t.Errorf("Bad maps marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result)
+ }
+}
+func TestDecodeQuotedMapKeys(t *testing.T) {
+ result := mapsTestStruct{}
+ err := NewDecoder(bytes.NewBuffer(mapsTestToml)).Decode(&result)
+ expected := mapsTestData
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !reflect.DeepEqual(result, expected) {
+ t.Errorf("Bad maps unmarshal: expected %v, got %v", expected, result)
+ }
+}
diff --git a/vendor/github.com/pelletier/go-toml/parser.go b/vendor/github.com/pelletier/go-toml/parser.go
index 8ee49cb56..d492a1e6f 100644
--- a/vendor/github.com/pelletier/go-toml/parser.go
+++ b/vendor/github.com/pelletier/go-toml/parser.go
@@ -110,7 +110,7 @@ func (p *tomlParser) parseGroupArray() tomlParserStateFn {
newTree := newTree()
newTree.position = startToken.Position
array = append(array, newTree)
- p.tree.SetPath(p.currentTable, array)
+ p.tree.SetPath(p.currentTable, "", false, array)
// remove all keys that were children of this table array
prefix := key.val + "."
@@ -205,7 +205,7 @@ func (p *tomlParser) parseAssign() tomlParserStateFn {
case *Tree, []*Tree:
toInsert = value
default:
- toInsert = &tomlValue{value, key.Position}
+ toInsert = &tomlValue{value: value, position: key.Position}
}
targetNode.values[keyVal] = toInsert
return p.parseStart
@@ -299,7 +299,7 @@ Loop:
key := p.getToken()
p.assume(tokenEqual)
value := p.parseRvalue()
- tree.Set(key.val, value)
+ tree.Set(key.val, "", false, value)
case tokenComma:
if previous == nil {
p.raiseError(follow, "inline table cannot start with a comma")
diff --git a/vendor/github.com/pelletier/go-toml/parser_test.go b/vendor/github.com/pelletier/go-toml/parser_test.go
index 508cb65f0..029bc52c3 100644
--- a/vendor/github.com/pelletier/go-toml/parser_test.go
+++ b/vendor/github.com/pelletier/go-toml/parser_test.go
@@ -46,7 +46,7 @@ func assertTree(t *testing.T, tree *Tree, err error, ref map[string]interface{})
func TestCreateSubTree(t *testing.T) {
tree := newTree()
tree.createSubTree([]string{"a", "b", "c"}, Position{})
- tree.Set("a.b.c", 42)
+ tree.Set("a.b.c", "", false, 42)
if tree.Get("a.b.c") != 42 {
t.Fail()
}
diff --git a/vendor/github.com/pelletier/go-toml/query/doc.go b/vendor/github.com/pelletier/go-toml/query/doc.go
index f999fc965..ed63c1109 100644
--- a/vendor/github.com/pelletier/go-toml/query/doc.go
+++ b/vendor/github.com/pelletier/go-toml/query/doc.go
@@ -139,7 +139,7 @@
// Compiled Queries
//
// Queries may be executed directly on a Tree object, or compiled ahead
-// of time and executed discretely. The former is more convienent, but has the
+// of time and executed discretely. The former is more convenient, but has the
// penalty of having to recompile the query expression each time.
//
// // basic query
diff --git a/vendor/github.com/pelletier/go-toml/toml.go b/vendor/github.com/pelletier/go-toml/toml.go
index 64f19ed30..c3e324374 100644
--- a/vendor/github.com/pelletier/go-toml/toml.go
+++ b/vendor/github.com/pelletier/go-toml/toml.go
@@ -11,14 +11,18 @@ import (
)
type tomlValue struct {
- value interface{} // string, int64, uint64, float64, bool, time.Time, [] of any of this list
- position Position
+ value interface{} // string, int64, uint64, float64, bool, time.Time, [] of any of this list
+ comment string
+ commented bool
+ position Position
}
// Tree is the result of the parsing of a TOML file.
type Tree struct {
- values map[string]interface{} // string -> *tomlValue, *Tree, []*Tree
- position Position
+ values map[string]interface{} // string -> *tomlValue, *Tree, []*Tree
+ comment string
+ commented bool
+ position Position
}
func newTree() *Tree {
@@ -177,14 +181,14 @@ func (t *Tree) GetDefault(key string, def interface{}) interface{} {
// Set an element in the tree.
// Key is a dot-separated path (e.g. a.b.c).
// Creates all necessary intermediate trees, if needed.
-func (t *Tree) Set(key string, value interface{}) {
- t.SetPath(strings.Split(key, "."), value)
+func (t *Tree) Set(key string, comment string, commented bool, value interface{}) {
+ t.SetPath(strings.Split(key, "."), comment, commented, value)
}
// SetPath sets an element in the tree.
// Keys is an array of path elements (e.g. {"a","b","c"}).
// Creates all necessary intermediate trees, if needed.
-func (t *Tree) SetPath(keys []string, value interface{}) {
+func (t *Tree) SetPath(keys []string, comment string, commented bool, value interface{}) {
subtree := t
for _, intermediateKey := range keys[:len(keys)-1] {
nextTree, exists := subtree.values[intermediateKey]
@@ -209,13 +213,17 @@ func (t *Tree) SetPath(keys []string, value interface{}) {
switch value.(type) {
case *Tree:
+ tt := value.(*Tree)
+ tt.comment = comment
toInsert = value
case []*Tree:
toInsert = value
case *tomlValue:
- toInsert = value
+ tt := value.(*tomlValue)
+ tt.comment = comment
+ toInsert = tt
default:
- toInsert = &tomlValue{value: value}
+ toInsert = &tomlValue{value: value, comment: comment, commented: commented}
}
subtree.values[keys[len(keys)-1]] = toInsert
diff --git a/vendor/github.com/pelletier/go-toml/tomltree_create.go b/vendor/github.com/pelletier/go-toml/tomltree_create.go
index 19d1c0dc6..79610e9b3 100644
--- a/vendor/github.com/pelletier/go-toml/tomltree_create.go
+++ b/vendor/github.com/pelletier/go-toml/tomltree_create.go
@@ -104,7 +104,7 @@ func sliceToTree(object interface{}) (interface{}, error) {
}
arrayValue = reflect.Append(arrayValue, reflect.ValueOf(simpleValue))
}
- return &tomlValue{arrayValue.Interface(), Position{}}, nil
+ return &tomlValue{value: arrayValue.Interface(), position: Position{}}, nil
}
func toTree(object interface{}) (interface{}, error) {
@@ -127,7 +127,7 @@ func toTree(object interface{}) (interface{}, error) {
}
values[key.String()] = newValue
}
- return &Tree{values, Position{}}, nil
+ return &Tree{values: values, position: Position{}}, nil
}
if value.Kind() == reflect.Array || value.Kind() == reflect.Slice {
@@ -138,5 +138,5 @@ func toTree(object interface{}) (interface{}, error) {
if err != nil {
return nil, err
}
- return &tomlValue{simpleValue, Position{}}, nil
+ return &tomlValue{value: simpleValue, position: Position{}}, nil
}
diff --git a/vendor/github.com/pelletier/go-toml/tomltree_write.go b/vendor/github.com/pelletier/go-toml/tomltree_write.go
index ca763ed58..449f35a44 100644
--- a/vendor/github.com/pelletier/go-toml/tomltree_write.go
+++ b/vendor/github.com/pelletier/go-toml/tomltree_write.go
@@ -118,7 +118,24 @@ func (t *Tree) writeTo(w io.Writer, indent, keyspace string, bytesCount int64) (
return bytesCount, err
}
- writtenBytesCount, err := writeStrings(w, indent, k, " = ", repr, "\n")
+ if v.comment != "" {
+ comment := strings.Replace(v.comment, "\n", "\n"+indent+"#", -1)
+ start := "# "
+ if strings.HasPrefix(comment, "#") {
+ start = ""
+ }
+ writtenBytesCountComment, errc := writeStrings(w, "\n", indent, start, comment, "\n")
+ bytesCount += int64(writtenBytesCountComment)
+ if errc != nil {
+ return bytesCount, errc
+ }
+ }
+
+ var commented string
+ if v.commented {
+ commented = "# "
+ }
+ writtenBytesCount, err := writeStrings(w, indent, commented, k, " = ", repr, "\n")
bytesCount += int64(writtenBytesCount)
if err != nil {
return bytesCount, err
@@ -132,11 +149,31 @@ func (t *Tree) writeTo(w io.Writer, indent, keyspace string, bytesCount int64) (
if keyspace != "" {
combinedKey = keyspace + "." + combinedKey
}
+ var commented string
+ if t.commented {
+ commented = "# "
+ }
switch node := v.(type) {
// node has to be of those two types given how keys are sorted above
case *Tree:
- writtenBytesCount, err := writeStrings(w, "\n", indent, "[", combinedKey, "]\n")
+ tv, ok := t.values[k].(*Tree)
+ if !ok {
+ return bytesCount, fmt.Errorf("invalid value type at %s: %T", k, t.values[k])
+ }
+ if tv.comment != "" {
+ comment := strings.Replace(tv.comment, "\n", "\n"+indent+"#", -1)
+ start := "# "
+ if strings.HasPrefix(comment, "#") {
+ start = ""
+ }
+ writtenBytesCountComment, errc := writeStrings(w, "\n", indent, start, comment)
+ bytesCount += int64(writtenBytesCountComment)
+ if errc != nil {
+ return bytesCount, errc
+ }
+ }
+ writtenBytesCount, err := writeStrings(w, "\n", indent, commented, "[", combinedKey, "]\n")
bytesCount += int64(writtenBytesCount)
if err != nil {
return bytesCount, err
@@ -147,7 +184,7 @@ func (t *Tree) writeTo(w io.Writer, indent, keyspace string, bytesCount int64) (
}
case []*Tree:
for _, subTree := range node {
- writtenBytesCount, err := writeStrings(w, "\n", indent, "[[", combinedKey, "]]\n")
+ writtenBytesCount, err := writeStrings(w, "\n", indent, commented, "[[", combinedKey, "]]\n")
bytesCount += int64(writtenBytesCount)
if err != nil {
return bytesCount, err
diff --git a/vendor/github.com/pelletier/go-toml/tomltree_write_test.go b/vendor/github.com/pelletier/go-toml/tomltree_write_test.go
index c2a1ce3b7..5ea59bc1a 100644
--- a/vendor/github.com/pelletier/go-toml/tomltree_write_test.go
+++ b/vendor/github.com/pelletier/go-toml/tomltree_write_test.go
@@ -30,7 +30,7 @@ func (f *failingWriter) Write(p []byte) (n int, err error) {
f.buffer.Write(p[:toWrite])
f.written = f.failAt
- return toWrite, fmt.Errorf("failingWriter failed after writting %d bytes", f.written)
+ return toWrite, fmt.Errorf("failingWriter failed after writing %d bytes", f.written)
}
func assertErrorString(t *testing.T, expected string, err error) {
@@ -161,13 +161,13 @@ func TestTreeWriteToInvalidTreeSimpleValue(t *testing.T) {
}
func TestTreeWriteToInvalidTreeTomlValue(t *testing.T) {
- tree := Tree{values: map[string]interface{}{"foo": &tomlValue{int8(1), Position{}}}}
+ tree := Tree{values: map[string]interface{}{"foo": &tomlValue{value: int8(1), comment: "", position: Position{}}}}
_, err := tree.ToTomlString()
assertErrorString(t, "unsupported value type int8: 1", err)
}
func TestTreeWriteToInvalidTreeTomlValueArray(t *testing.T) {
- tree := Tree{values: map[string]interface{}{"foo": &tomlValue{[]interface{}{int8(1)}, Position{}}}}
+ tree := Tree{values: map[string]interface{}{"foo": &tomlValue{value: int8(1), comment: "", position: Position{}}}}
_, err := tree.ToTomlString()
assertErrorString(t, "unsupported value type int8: 1", err)
}
@@ -176,7 +176,7 @@ func TestTreeWriteToFailingWriterInSimpleValue(t *testing.T) {
toml, _ := Load(`a = 2`)
writer := failingWriter{failAt: 0, written: 0}
_, err := toml.WriteTo(&writer)
- assertErrorString(t, "failingWriter failed after writting 0 bytes", err)
+ assertErrorString(t, "failingWriter failed after writing 0 bytes", err)
}
func TestTreeWriteToFailingWriterInTable(t *testing.T) {
@@ -185,11 +185,11 @@ func TestTreeWriteToFailingWriterInTable(t *testing.T) {
a = 2`)
writer := failingWriter{failAt: 2, written: 0}
_, err := toml.WriteTo(&writer)
- assertErrorString(t, "failingWriter failed after writting 2 bytes", err)
+ assertErrorString(t, "failingWriter failed after writing 2 bytes", err)
writer = failingWriter{failAt: 13, written: 0}
_, err = toml.WriteTo(&writer)
- assertErrorString(t, "failingWriter failed after writting 13 bytes", err)
+ assertErrorString(t, "failingWriter failed after writing 13 bytes", err)
}
func TestTreeWriteToFailingWriterInArray(t *testing.T) {
@@ -198,11 +198,11 @@ func TestTreeWriteToFailingWriterInArray(t *testing.T) {
a = 2`)
writer := failingWriter{failAt: 2, written: 0}
_, err := toml.WriteTo(&writer)
- assertErrorString(t, "failingWriter failed after writting 2 bytes", err)
+ assertErrorString(t, "failingWriter failed after writing 2 bytes", err)
writer = failingWriter{failAt: 15, written: 0}
_, err = toml.WriteTo(&writer)
- assertErrorString(t, "failingWriter failed after writting 15 bytes", err)
+ assertErrorString(t, "failingWriter failed after writing 15 bytes", err)
}
func TestTreeWriteToMapExampleFile(t *testing.T) {
diff --git a/vendor/github.com/pkg/errors/format_test.go b/vendor/github.com/pkg/errors/format_test.go
index 15fd7d89d..c2eef5f04 100644
--- a/vendor/github.com/pkg/errors/format_test.go
+++ b/vendor/github.com/pkg/errors/format_test.go
@@ -491,7 +491,7 @@ type wrapper struct {
want []string
}
-func prettyBlocks(blocks []string, prefix ...string) string {
+func prettyBlocks(blocks []string) string {
var out []string
for _, b := range blocks {
diff --git a/vendor/github.com/prometheus/common/log/log.go b/vendor/github.com/prometheus/common/log/log.go
index 04e906c07..108830255 100644
--- a/vendor/github.com/prometheus/common/log/log.go
+++ b/vendor/github.com/prometheus/common/log/log.go
@@ -56,11 +56,11 @@ func (s *loggerSettings) apply(ctx *kingpin.ParseContext) error {
// To use the default Kingpin application, call AddFlags(kingpin.CommandLine)
func AddFlags(a *kingpin.Application) {
s := loggerSettings{}
- kingpin.Flag("log.level", "Only log messages with the given severity or above. Valid levels: [debug, info, warn, error, fatal]").
+ a.Flag("log.level", "Only log messages with the given severity or above. Valid levels: [debug, info, warn, error, fatal]").
Default(origLogger.Level.String()).
StringVar(&s.level)
defaultFormat := url.URL{Scheme: "logger", Opaque: "stderr"}
- kingpin.Flag("log.format", `Set the log target and format. Example: "logger:syslog?appname=bob&local=7" or "logger:stdout?json=true"`).
+ a.Flag("log.format", `Set the log target and format. Example: "logger:syslog?appname=bob&local=7" or "logger:stdout?json=true"`).
Default(defaultFormat.String()).
StringVar(&s.format)
a.Action(s.apply)
@@ -345,6 +345,11 @@ func Fatalf(format string, args ...interface{}) {
baseLogger.sourced().Fatalf(format, args...)
}
+// AddHook adds hook to Prometheus' original logger.
+func AddHook(hook logrus.Hook) {
+ origLogger.Hooks.Add(hook)
+}
+
type errorLogWriter struct{}
func (errorLogWriter) Write(b []byte) (int, error) {
diff --git a/vendor/github.com/prometheus/procfs/fixtures/26231/limits b/vendor/github.com/prometheus/procfs/fixtures/26231/limits
index 23c6b6898..8b40108aa 100644
--- a/vendor/github.com/prometheus/procfs/fixtures/26231/limits
+++ b/vendor/github.com/prometheus/procfs/fixtures/26231/limits
@@ -8,7 +8,7 @@ Max resident set unlimited unlimited bytes
Max processes 62898 62898 processes
Max open files 2048 4096 files
Max locked memory 65536 65536 bytes
-Max address space unlimited unlimited bytes
+Max address space 8589934592 unlimited bytes
Max file locks unlimited unlimited locks
Max pending signals 62898 62898 signals
Max msgqueue size 819200 819200 bytes
diff --git a/vendor/github.com/prometheus/procfs/proc_limits.go b/vendor/github.com/prometheus/procfs/proc_limits.go
index 2df997ce1..b684a5b55 100644
--- a/vendor/github.com/prometheus/procfs/proc_limits.go
+++ b/vendor/github.com/prometheus/procfs/proc_limits.go
@@ -13,46 +13,46 @@ import (
// http://man7.org/linux/man-pages/man2/getrlimit.2.html.
type ProcLimits struct {
// CPU time limit in seconds.
- CPUTime int
+ CPUTime int64
// Maximum size of files that the process may create.
- FileSize int
+ FileSize int64
// Maximum size of the process's data segment (initialized data,
// uninitialized data, and heap).
- DataSize int
+ DataSize int64
// Maximum size of the process stack in bytes.
- StackSize int
+ StackSize int64
// Maximum size of a core file.
- CoreFileSize int
+ CoreFileSize int64
// Limit of the process's resident set in pages.
- ResidentSet int
+ ResidentSet int64
// Maximum number of processes that can be created for the real user ID of
// the calling process.
- Processes int
+ Processes int64
// Value one greater than the maximum file descriptor number that can be
// opened by this process.
- OpenFiles int
+ OpenFiles int64
// Maximum number of bytes of memory that may be locked into RAM.
- LockedMemory int
+ LockedMemory int64
// Maximum size of the process's virtual memory address space in bytes.
- AddressSpace int
+ AddressSpace int64
// Limit on the combined number of flock(2) locks and fcntl(2) leases that
// this process may establish.
- FileLocks int
+ FileLocks int64
// Limit of signals that may be queued for the real user ID of the calling
// process.
- PendingSignals int
+ PendingSignals int64
// Limit on the number of bytes that can be allocated for POSIX message
// queues for the real user ID of the calling process.
- MsqqueueSize int
+ MsqqueueSize int64
// Limit of the nice priority set using setpriority(2) or nice(2).
- NicePriority int
+ NicePriority int64
// Limit of the real-time priority set using sched_setscheduler(2) or
// sched_setparam(2).
- RealtimePriority int
+ RealtimePriority int64
// Limit (in microseconds) on the amount of CPU time that a process
// scheduled under a real-time scheduling policy may consume without making
// a blocking system call.
- RealtimeTimeout int
+ RealtimeTimeout int64
}
const (
@@ -125,13 +125,13 @@ func (p Proc) NewLimits() (ProcLimits, error) {
return l, s.Err()
}
-func parseInt(s string) (int, error) {
+func parseInt(s string) (int64, error) {
if s == limitsUnlimited {
return -1, nil
}
- i, err := strconv.ParseInt(s, 10, 32)
+ i, err := strconv.ParseInt(s, 10, 64)
if err != nil {
return 0, fmt.Errorf("couldn't parse value %s: %s", s, err)
}
- return int(i), nil
+ return i, nil
}
diff --git a/vendor/github.com/prometheus/procfs/proc_limits_test.go b/vendor/github.com/prometheus/procfs/proc_limits_test.go
index 70bf04ec2..ac62a3bb6 100644
--- a/vendor/github.com/prometheus/procfs/proc_limits_test.go
+++ b/vendor/github.com/prometheus/procfs/proc_limits_test.go
@@ -15,14 +15,14 @@ func TestNewLimits(t *testing.T) {
for _, test := range []struct {
name string
- want int
- have int
+ want int64
+ have int64
}{
{name: "cpu time", want: -1, have: l.CPUTime},
{name: "open files", want: 2048, have: l.OpenFiles},
{name: "msgqueue size", want: 819200, have: l.MsqqueueSize},
{name: "nice priority", want: 0, have: l.NicePriority},
- {name: "address space", want: -1, have: l.AddressSpace},
+ {name: "address space", want: 8589934592, have: l.AddressSpace},
} {
if test.want != test.have {
t.Errorf("want %s %d, have %d", test.name, test.want, test.have)
diff --git a/vendor/github.com/segmentio/backo-go/vendor/github.com/bmizerany/assert/.gitignore b/vendor/github.com/segmentio/backo-go/vendor/github.com/bmizerany/assert/.gitignore
new file mode 100644
index 000000000..b6fadf4eb
--- /dev/null
+++ b/vendor/github.com/segmentio/backo-go/vendor/github.com/bmizerany/assert/.gitignore
@@ -0,0 +1,7 @@
+_go_.*
+_gotest_.*
+_obj
+_test
+_testmain.go
+*.out
+*.[568]
diff --git a/vendor/github.com/segmentio/backo-go/vendor/github.com/bmizerany/assert/README.md b/vendor/github.com/segmentio/backo-go/vendor/github.com/bmizerany/assert/README.md
new file mode 100644
index 000000000..8b6b6fc4f
--- /dev/null
+++ b/vendor/github.com/segmentio/backo-go/vendor/github.com/bmizerany/assert/README.md
@@ -0,0 +1,45 @@
+# Assert (c) Blake Mizerany and Keith Rarick -- MIT LICENCE
+
+## Assertions for Go tests
+
+## Install
+
+ $ go get github.com/bmizerany/assert
+
+## Use
+
+**point.go**
+
+ package point
+
+ type Point struct {
+ x, y int
+ }
+
+**point_test.go**
+
+
+ package point
+
+ import (
+ "testing"
+ "github.com/bmizerany/assert"
+ )
+
+ func TestAsserts(t *testing.T) {
+ p1 := Point{1, 1}
+ p2 := Point{2, 1}
+
+ assert.Equal(t, p1, p2)
+ }
+
+**output**
+ $ go test
+ --- FAIL: TestAsserts (0.00 seconds)
+ assert.go:15: /Users/flavio.barbosa/dev/stewie/src/point_test.go:12
+ assert.go:24: ! X: 1 != 2
+ FAIL
+
+## Docs
+
+ http://github.com/bmizerany/assert
diff --git a/vendor/github.com/segmentio/backo-go/vendor/github.com/bmizerany/assert/assert.go b/vendor/github.com/segmentio/backo-go/vendor/github.com/bmizerany/assert/assert.go
new file mode 100644
index 000000000..7409f985e
--- /dev/null
+++ b/vendor/github.com/segmentio/backo-go/vendor/github.com/bmizerany/assert/assert.go
@@ -0,0 +1,76 @@
+package assert
+// Testing helpers for doozer.
+
+import (
+ "github.com/kr/pretty"
+ "reflect"
+ "testing"
+ "runtime"
+ "fmt"
+)
+
+func assert(t *testing.T, result bool, f func(), cd int) {
+ if !result {
+ _, file, line, _ := runtime.Caller(cd + 1)
+ t.Errorf("%s:%d", file, line)
+ f()
+ t.FailNow()
+ }
+}
+
+func equal(t *testing.T, exp, got interface{}, cd int, args ...interface{}) {
+ fn := func() {
+ for _, desc := range pretty.Diff(exp, got) {
+ t.Error("!", desc)
+ }
+ if len(args) > 0 {
+ t.Error("!", " -", fmt.Sprint(args...))
+ }
+ }
+ result := reflect.DeepEqual(exp, got)
+ assert(t, result, fn, cd+1)
+}
+
+func tt(t *testing.T, result bool, cd int, args ...interface{}) {
+ fn := func() {
+ t.Errorf("! Failure")
+ if len(args) > 0 {
+ t.Error("!", " -", fmt.Sprint(args...))
+ }
+ }
+ assert(t, result, fn, cd+1)
+}
+
+func T(t *testing.T, result bool, args ...interface{}) {
+ tt(t, result, 1, args...)
+}
+
+func Tf(t *testing.T, result bool, format string, args ...interface{}) {
+ tt(t, result, 1, fmt.Sprintf(format, args...))
+}
+
+func Equal(t *testing.T, exp, got interface{}, args ...interface{}) {
+ equal(t, exp, got, 1, args...)
+}
+
+func Equalf(t *testing.T, exp, got interface{}, format string, args ...interface{}) {
+ equal(t, exp, got, 1, fmt.Sprintf(format, args...))
+}
+
+func NotEqual(t *testing.T, exp, got interface{}, args ...interface{}) {
+ fn := func() {
+ t.Errorf("! Unexpected: <%#v>", exp)
+ if len(args) > 0 {
+ t.Error("!", " -", fmt.Sprint(args...))
+ }
+ }
+ result := !reflect.DeepEqual(exp, got)
+ assert(t, result, fn, 1)
+}
+
+func Panic(t *testing.T, err interface{}, fn func()) {
+ defer func() {
+ equal(t, err, recover(), 3)
+ }()
+ fn()
+}
diff --git a/vendor/github.com/segmentio/backo-go/vendor/github.com/bmizerany/assert/assert_test.go b/vendor/github.com/segmentio/backo-go/vendor/github.com/bmizerany/assert/assert_test.go
new file mode 100644
index 000000000..162a590c6
--- /dev/null
+++ b/vendor/github.com/segmentio/backo-go/vendor/github.com/bmizerany/assert/assert_test.go
@@ -0,0 +1,15 @@
+package assert
+
+import (
+ "testing"
+)
+
+func TestLineNumbers(t *testing.T) {
+ Equal(t, "foo", "foo", "msg!")
+ //Equal(t, "foo", "bar", "this should blow up")
+}
+
+func TestNotEqual(t *testing.T) {
+ NotEqual(t, "foo", "bar", "msg!")
+ //NotEqual(t, "foo", "foo", "this should blow up")
+}
diff --git a/vendor/github.com/segmentio/backo-go/vendor/github.com/bmizerany/assert/example/point.go b/vendor/github.com/segmentio/backo-go/vendor/github.com/bmizerany/assert/example/point.go
new file mode 100644
index 000000000..15789fe10
--- /dev/null
+++ b/vendor/github.com/segmentio/backo-go/vendor/github.com/bmizerany/assert/example/point.go
@@ -0,0 +1,5 @@
+package point
+
+type Point struct {
+ X, Y int
+}
diff --git a/vendor/github.com/segmentio/backo-go/vendor/github.com/bmizerany/assert/example/point_test.go b/vendor/github.com/segmentio/backo-go/vendor/github.com/bmizerany/assert/example/point_test.go
new file mode 100644
index 000000000..34e791a43
--- /dev/null
+++ b/vendor/github.com/segmentio/backo-go/vendor/github.com/bmizerany/assert/example/point_test.go
@@ -0,0 +1,13 @@
+package point
+
+import (
+ "testing"
+ "assert"
+)
+
+func TestAsserts(t *testing.T) {
+ p1 := Point{1, 1}
+ p2 := Point{2, 1}
+
+ assert.Equal(t, p1, p2)
+}
diff --git a/vendor/github.com/spf13/afero/.travis.yml b/vendor/github.com/spf13/afero/.travis.yml
index 6c296d293..618159a4e 100644
--- a/vendor/github.com/spf13/afero/.travis.yml
+++ b/vendor/github.com/spf13/afero/.travis.yml
@@ -16,5 +16,6 @@ matrix:
fast_finish: true
script:
- - go test -v ./...
- go build
+ - go test -race -v ./...
+
diff --git a/vendor/github.com/spf13/afero/README.md b/vendor/github.com/spf13/afero/README.md
index d9e332730..0c9b04b53 100644
--- a/vendor/github.com/spf13/afero/README.md
+++ b/vendor/github.com/spf13/afero/README.md
@@ -61,11 +61,11 @@ import "github.com/spf13/afero"
First define a package variable and set it to a pointer to a filesystem.
```go
-var AppFs afero.Fs = afero.NewMemMapFs()
+var AppFs = afero.NewMemMapFs()
or
-var AppFs afero.Fs = afero.NewOsFs()
+var AppFs = afero.NewOsFs()
```
It is important to note that if you repeat the composite literal you
will be using a completely new and isolated filesystem. In the case of
@@ -81,7 +81,10 @@ So if my application before had:
```go
os.Open('/tmp/foo')
```
-We would replace it with a call to `AppFs.Open('/tmp/foo')`.
+We would replace it with:
+```go
+AppFs.Open('/tmp/foo')
+```
`AppFs` being the variable we defined above.
@@ -166,8 +169,8 @@ f, err := afero.TempFile(fs,"", "ioutil-test")
### Calling via Afero
```go
-fs := afero.NewMemMapFs
-afs := &Afero{Fs: fs}
+fs := afero.NewMemMapFs()
+afs := &afero.Afero{Fs: fs}
f, err := afs.TempFile("", "ioutil-test")
```
diff --git a/vendor/github.com/spf13/afero/appveyor.yml b/vendor/github.com/spf13/afero/appveyor.yml
index 006f31534..a633ad500 100644
--- a/vendor/github.com/spf13/afero/appveyor.yml
+++ b/vendor/github.com/spf13/afero/appveyor.yml
@@ -12,4 +12,4 @@ build_script:
go build github.com/spf13/afero
test_script:
-- cmd: go test -v github.com/spf13/afero
+- cmd: go test -race -v github.com/spf13/afero/...
diff --git a/vendor/github.com/spf13/afero/cacheOnReadFs.go b/vendor/github.com/spf13/afero/cacheOnReadFs.go
index e54a4f8b4..b026e0de8 100644
--- a/vendor/github.com/spf13/afero/cacheOnReadFs.go
+++ b/vendor/github.com/spf13/afero/cacheOnReadFs.go
@@ -64,15 +64,10 @@ func (u *CacheOnReadFs) cacheStatus(name string) (state cacheState, fi os.FileIn
return cacheHit, lfi, nil
}
- if err == syscall.ENOENT {
+ if err == syscall.ENOENT || os.IsNotExist(err) {
return cacheMiss, nil, nil
}
- var ok bool
- if err, ok = err.(*os.PathError); ok {
- if err == os.ErrNotExist {
- return cacheMiss, nil, nil
- }
- }
+
return cacheMiss, nil, err
}
diff --git a/vendor/github.com/spf13/afero/composite_test.go b/vendor/github.com/spf13/afero/composite_test.go
index e8ac1a818..8e44611dc 100644
--- a/vendor/github.com/spf13/afero/composite_test.go
+++ b/vendor/github.com/spf13/afero/composite_test.go
@@ -1,6 +1,7 @@
package afero
import (
+ "bytes"
"fmt"
"io/ioutil"
"os"
@@ -366,3 +367,38 @@ func TestUnionCacheExpire(t *testing.T) {
t.Errorf("cache time failed: <%s>", data)
}
}
+
+func TestCacheOnReadFsNotInLayer(t *testing.T) {
+ base := NewMemMapFs()
+ layer := NewMemMapFs()
+ fs := NewCacheOnReadFs(base, layer, 0)
+
+ fh, err := base.Create("/file.txt")
+ if err != nil {
+ t.Fatal("unable to create file: ", err)
+ }
+
+ txt := []byte("This is a test")
+ fh.Write(txt)
+ fh.Close()
+
+ fh, err = fs.Open("/file.txt")
+ if err != nil {
+ t.Fatal("could not open file: ", err)
+ }
+
+ b, err := ReadAll(fh)
+ fh.Close()
+
+ if err != nil {
+ t.Fatal("could not read file: ", err)
+ } else if !bytes.Equal(txt, b) {
+ t.Fatalf("wanted file text %q, got %q", txt, b)
+ }
+
+ fh, err = layer.Open("/file.txt")
+ if err != nil {
+ t.Fatal("could not open file from layer: ", err)
+ }
+ fh.Close()
+}
diff --git a/vendor/github.com/spf13/afero/mem/file.go b/vendor/github.com/spf13/afero/mem/file.go
index e41e0123d..5401a3b7c 100644
--- a/vendor/github.com/spf13/afero/mem/file.go
+++ b/vendor/github.com/spf13/afero/mem/file.go
@@ -74,14 +74,24 @@ func CreateDir(name string) *FileData {
}
func ChangeFileName(f *FileData, newname string) {
+ f.Lock()
f.name = newname
+ f.Unlock()
}
func SetMode(f *FileData, mode os.FileMode) {
+ f.Lock()
f.mode = mode
+ f.Unlock()
}
func SetModTime(f *FileData, mtime time.Time) {
+ f.Lock()
+ setModTime(f, mtime)
+ f.Unlock()
+}
+
+func setModTime(f *FileData, mtime time.Time) {
f.modtime = mtime
}
@@ -102,7 +112,7 @@ func (f *File) Close() error {
f.fileData.Lock()
f.closed = true
if !f.readOnly {
- SetModTime(f.fileData, time.Now())
+ setModTime(f.fileData, time.Now())
}
f.fileData.Unlock()
return nil
@@ -197,7 +207,7 @@ func (f *File) Truncate(size int64) error {
} else {
f.fileData.data = f.fileData.data[0:size]
}
- SetModTime(f.fileData, time.Now())
+ setModTime(f.fileData, time.Now())
return nil
}
@@ -236,7 +246,7 @@ func (f *File) Write(b []byte) (n int, err error) {
f.fileData.data = append(f.fileData.data[:cur], b...)
f.fileData.data = append(f.fileData.data, tail...)
}
- SetModTime(f.fileData, time.Now())
+ setModTime(f.fileData, time.Now())
atomic.StoreInt64(&f.at, int64(len(f.fileData.data)))
return
@@ -261,17 +271,33 @@ type FileInfo struct {
// Implements os.FileInfo
func (s *FileInfo) Name() string {
+ s.Lock()
_, name := filepath.Split(s.name)
+ s.Unlock()
return name
}
-func (s *FileInfo) Mode() os.FileMode { return s.mode }
-func (s *FileInfo) ModTime() time.Time { return s.modtime }
-func (s *FileInfo) IsDir() bool { return s.dir }
-func (s *FileInfo) Sys() interface{} { return nil }
+func (s *FileInfo) Mode() os.FileMode {
+ s.Lock()
+ defer s.Unlock()
+ return s.mode
+}
+func (s *FileInfo) ModTime() time.Time {
+ s.Lock()
+ defer s.Unlock()
+ return s.modtime
+}
+func (s *FileInfo) IsDir() bool {
+ s.Lock()
+ defer s.Unlock()
+ return s.dir
+}
+func (s *FileInfo) Sys() interface{} { return nil }
func (s *FileInfo) Size() int64 {
if s.IsDir() {
return int64(42)
}
+ s.Lock()
+ defer s.Unlock()
return int64(len(s.data))
}
diff --git a/vendor/github.com/spf13/afero/mem/file_test.go b/vendor/github.com/spf13/afero/mem/file_test.go
new file mode 100644
index 000000000..5769067a7
--- /dev/null
+++ b/vendor/github.com/spf13/afero/mem/file_test.go
@@ -0,0 +1,154 @@
+package mem
+
+import (
+ "testing"
+ "time"
+)
+
+func TestFileDataNameRace(t *testing.T) {
+ t.Parallel()
+ const someName = "someName"
+ const someOtherName = "someOtherName"
+ d := FileData{
+ name: someName,
+ }
+
+ if d.Name() != someName {
+ t.Errorf("Failed to read correct Name, was %v", d.Name())
+ }
+
+ ChangeFileName(&d, someOtherName)
+ if d.Name() != someOtherName {
+ t.Errorf("Failed to set Name, was %v", d.Name())
+ }
+
+ go func() {
+ ChangeFileName(&d, someName)
+ }()
+
+ if d.Name() != someName && d.Name() != someOtherName {
+ t.Errorf("Failed to read either Name, was %v", d.Name())
+ }
+}
+
+func TestFileDataModTimeRace(t *testing.T) {
+ t.Parallel()
+ someTime := time.Now()
+ someOtherTime := someTime.Add(1 * time.Minute)
+
+ d := FileData{
+ modtime: someTime,
+ }
+
+ s := FileInfo{
+ FileData: &d,
+ }
+
+ if s.ModTime() != someTime {
+ t.Errorf("Failed to read correct value, was %v", s.ModTime())
+ }
+
+ SetModTime(&d, someOtherTime)
+ if s.ModTime() != someOtherTime {
+ t.Errorf("Failed to set ModTime, was %v", s.ModTime())
+ }
+
+ go func() {
+ SetModTime(&d, someTime)
+ }()
+
+ if s.ModTime() != someTime && s.ModTime() != someOtherTime {
+ t.Errorf("Failed to read either modtime, was %v", s.ModTime())
+ }
+}
+
+func TestFileDataModeRace(t *testing.T) {
+ t.Parallel()
+ const someMode = 0777
+ const someOtherMode = 0660
+
+ d := FileData{
+ mode: someMode,
+ }
+
+ s := FileInfo{
+ FileData: &d,
+ }
+
+ if s.Mode() != someMode {
+ t.Errorf("Failed to read correct value, was %v", s.Mode())
+ }
+
+ SetMode(&d, someOtherMode)
+ if s.Mode() != someOtherMode {
+ t.Errorf("Failed to set Mode, was %v", s.Mode())
+ }
+
+ go func() {
+ SetMode(&d, someMode)
+ }()
+
+ if s.Mode() != someMode && s.Mode() != someOtherMode {
+ t.Errorf("Failed to read either mode, was %v", s.Mode())
+ }
+}
+
+func TestFileDataIsDirRace(t *testing.T) {
+ t.Parallel()
+
+ d := FileData{
+ dir: true,
+ }
+
+ s := FileInfo{
+ FileData: &d,
+ }
+
+ if s.IsDir() != true {
+ t.Errorf("Failed to read correct value, was %v", s.IsDir())
+ }
+
+ go func() {
+ s.Lock()
+ d.dir = false
+ s.Unlock()
+ }()
+
+ //just logging the value to trigger a read:
+ t.Logf("Value is %v", s.IsDir())
+}
+
+func TestFileDataSizeRace(t *testing.T) {
+ t.Parallel()
+
+ const someData = "Hello"
+ const someOtherDataSize = "Hello World"
+
+ d := FileData{
+ data: []byte(someData),
+ dir: false,
+ }
+
+ s := FileInfo{
+ FileData: &d,
+ }
+
+ if s.Size() != int64(len(someData)) {
+ t.Errorf("Failed to read correct value, was %v", s.Size())
+ }
+
+ go func() {
+ s.Lock()
+ d.data = []byte(someOtherDataSize)
+ s.Unlock()
+ }()
+
+ //just logging the value to trigger a read:
+ t.Logf("Value is %v", s.Size())
+
+ //Testing the Dir size case
+ d.dir = true
+ if s.Size() != int64(42) {
+ t.Errorf("Failed to read correct value for dir, was %v", s.Size())
+ }
+}
diff --git a/vendor/github.com/spf13/afero/memmap.go b/vendor/github.com/spf13/afero/memmap.go
index 14cd438fb..09498e70f 100644
--- a/vendor/github.com/spf13/afero/memmap.go
+++ b/vendor/github.com/spf13/afero/memmap.go
@@ -141,7 +141,7 @@ func (m *MemMapFs) Mkdir(name string, perm os.FileMode) error {
m.registerWithParent(item)
m.mu.Unlock()
- m.Chmod(name, perm)
+ m.Chmod(name, perm|os.ModeDir)
return nil
}
@@ -151,9 +151,8 @@ func (m *MemMapFs) MkdirAll(path string, perm os.FileMode) error {
if err != nil {
if err.(*os.PathError).Err == ErrFileExists {
return nil
- } else {
- return err
}
+ return err
}
return nil
}
diff --git a/vendor/github.com/spf13/afero/memmap_test.go b/vendor/github.com/spf13/afero/memmap_test.go
index d28e91220..09d8680f6 100644
--- a/vendor/github.com/spf13/afero/memmap_test.go
+++ b/vendor/github.com/spf13/afero/memmap_test.go
@@ -110,6 +110,8 @@ func TestPermSet(t *testing.T) {
const dirPathAll = "/my/path/to/dir"
const fileMode = os.FileMode(0765)
+ // directories will also have the directory bit set
+ const dirMode = fileMode | os.ModeDir
fs := NewMemMapFs()
@@ -132,7 +134,7 @@ func TestPermSet(t *testing.T) {
}
// Test Mkdir
- err = fs.Mkdir(dirPath, fileMode)
+ err = fs.Mkdir(dirPath, dirMode)
if err != nil {
t.Errorf("MkDir Create failed: %s", err)
return
@@ -142,13 +144,14 @@ func TestPermSet(t *testing.T) {
t.Errorf("Stat failed: %s", err)
return
}
- if s.Mode().String() != fileMode.String() {
- t.Errorf("Permissions Incorrect: %s != %s", s.Mode().String(), fileMode.String())
+ // sets File
+ if s.Mode().String() != dirMode.String() {
+ t.Errorf("Permissions Incorrect: %s != %s", s.Mode().String(), dirMode.String())
return
}
// Test MkdirAll
- err = fs.MkdirAll(dirPathAll, fileMode)
+ err = fs.MkdirAll(dirPathAll, dirMode)
if err != nil {
t.Errorf("MkDir Create failed: %s", err)
return
@@ -158,8 +161,8 @@ func TestPermSet(t *testing.T) {
t.Errorf("Stat failed: %s", err)
return
}
- if s.Mode().String() != fileMode.String() {
- t.Errorf("Permissions Incorrect: %s != %s", s.Mode().String(), fileMode.String())
+ if s.Mode().String() != dirMode.String() {
+ t.Errorf("Permissions Incorrect: %s != %s", s.Mode().String(), dirMode.String())
return
}
}
@@ -384,3 +387,35 @@ loop:
}
}
}
+
+func TestMemFsDirMode(t *testing.T) {
+ fs := NewMemMapFs()
+ err := fs.Mkdir("/testDir1", 0644)
+ if err != nil {
+ t.Error(err)
+ }
+ err = fs.MkdirAll("/sub/testDir2", 0644)
+ if err != nil {
+ t.Error(err)
+ }
+ info, err := fs.Stat("/testDir1")
+ if err != nil {
+ t.Error(err)
+ }
+ if !info.IsDir() {
+ t.Error("should be a directory")
+ }
+ if !info.Mode().IsDir() {
+ t.Error("FileMode is not directory")
+ }
+ info, err = fs.Stat("/sub/testDir2")
+ if err != nil {
+ t.Error(err)
+ }
+ if !info.IsDir() {
+ t.Error("should be a directory")
+ }
+ if !info.Mode().IsDir() {
+ t.Error("FileMode is not directory")
+ }
+}
diff --git a/vendor/github.com/spf13/afero/memradix.go b/vendor/github.com/spf13/afero/memradix.go
deleted file mode 100644
index 87527f35a..000000000
--- a/vendor/github.com/spf13/afero/memradix.go
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright © 2014 Steve Francia <spf@spf13.com>.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package afero
diff --git a/vendor/github.com/spf13/afero/util.go b/vendor/github.com/spf13/afero/util.go
index 2f44e6a10..7463887fd 100644
--- a/vendor/github.com/spf13/afero/util.go
+++ b/vendor/github.com/spf13/afero/util.go
@@ -157,7 +157,7 @@ func UnicodeSanitize(s string) string {
return string(target)
}
-// Transform characters with accents into plan forms
+// Transform characters with accents into plain forms.
func NeuterAccents(s string) string {
t := transform.Chain(norm.NFD, transform.RemoveFunc(isMn), norm.NFC)
result, _, _ := transform.String(t, string(s))
diff --git a/vendor/github.com/spf13/cobra/README.md b/vendor/github.com/spf13/cobra/README.md
index da9aa881e..d8b5c96c8 100644
--- a/vendor/github.com/spf13/cobra/README.md
+++ b/vendor/github.com/spf13/cobra/README.md
@@ -19,13 +19,33 @@ Many of the most widely used Go projects are built using Cobra including:
* [GiantSwarm's swarm](https://github.com/giantswarm/cli)
* [Nanobox](https://github.com/nanobox-io/nanobox)/[Nanopack](https://github.com/nanopack)
* [rclone](http://rclone.org/)
-
+* [nehm](https://github.com/bogem/nehm)
[![Build Status](https://travis-ci.org/spf13/cobra.svg "Travis CI status")](https://travis-ci.org/spf13/cobra)
[![CircleCI status](https://circleci.com/gh/spf13/cobra.png?circle-token=:circle-token "CircleCI status")](https://circleci.com/gh/spf13/cobra)
[![GoDoc](https://godoc.org/github.com/spf13/cobra?status.svg)](https://godoc.org/github.com/spf13/cobra)
-![cobra](https://cloud.githubusercontent.com/assets/173412/10911369/84832a8e-8212-11e5-9f82-cc96660a4794.gif)
+# Table of Contents
+
+- [Overview](#overview)
+- [Concepts](#concepts)
+ * [Commands](#commands)
+ * [Flags](#flags)
+- [Installing](#installing)
+- [Getting Started](#getting-started)
+ * [Using the Cobra Generator](#using-the-cobra-generator)
+ * [Using the Cobra Library](#using-the-cobra-library)
+ * [Working with Flags](#working-with-flags)
+ * [Positional and Custom Arguments](#positional-and-custom-arguments)
+ * [Example](#example)
+ * [Help Command](#help-command)
+ * [Usage Message](#usage-message)
+ * [PreRun and PostRun Hooks](#prerun-and-postrun-hooks)
+ * [Suggestions when "unknown command" happens](#suggestions-when-unknown-command-happens)
+ * [Generating documentation for your command](#generating-documentation-for-your-command)
+ * [Generating bash completions](#generating-bash-completions)
+- [Contributing](#contributing)
+- [License](#license)
# Overview
@@ -43,7 +63,6 @@ Cobra provides:
* Easy generation of applications & commands with `cobra init appname` & `cobra add cmdname`
* Intelligent suggestions (`app srver`... did you mean `app server`?)
* Automatic help generation for commands and flags
-* Automatic detailed help for `app help [command]`
* Automatic help flag recognition of `-h`, `--help`, etc.
* Automatically generated bash autocomplete for your application
* Automatically generated man pages for your application
@@ -51,16 +70,6 @@ Cobra provides:
* The flexibility to define your own help, usage, etc.
* Optional tight integration with [viper](http://github.com/spf13/viper) for 12-factor apps
-Cobra has an exceptionally clean interface and simple design without needless
-constructors or initialization methods.
-
-Applications built with Cobra commands are designed to be as user-friendly as
-possible. Flags can be placed before or after the command (as long as a
-confusing space isn’t provided). Both short and long flags can be used. A
-command need not even be fully typed. Help is automatically generated and
-available for the application or for a specific command using either the help
-command or the `--help` flag.
-
# Concepts
Cobra is built on a structure of commands, arguments & flags.
@@ -93,20 +102,11 @@ have children commands and optionally run an action.
In the example above, 'server' is the command.
-A Command has the following structure:
-
-```go
-type Command struct {
- Use string // The one-line usage message.
- Short string // The short description shown in the 'help' output.
- Long string // The long message shown in the 'help <this-command>' output.
- Run func(cmd *Command, args []string) // Run runs the command.
-}
-```
+[More about cobra.Command](https://godoc.org/github.com/spf13/cobra#Command)
## Flags
-A Flag is a way to modify the behavior of a command. Cobra supports
+A flag is a way to modify the behavior of a command. Cobra supports
fully POSIX-compliant flags as well as the Go [flag package](https://golang.org/pkg/flag/).
A Cobra command can define flags that persist through to children commands
and flags that are only available to that command.
@@ -170,106 +170,14 @@ func main() {
Cobra provides its own program that will create your application and add any
commands you want. It's the easiest way to incorporate Cobra into your application.
-In order to use the cobra command, compile it using the following command:
+[Here](https://github.com/spf13/cobra/blob/master/cobra/README.md) you can find more information about it.
- go get github.com/spf13/cobra/cobra
-
-This will create the cobra executable under your `$GOPATH/bin` directory.
-
-### cobra init
-
-The `cobra init [yourApp]` command will create your initial application code
-for you. It is a very powerful application that will populate your program with
-the right structure so you can immediately enjoy all the benefits of Cobra. It
-will also automatically apply the license you specify to your application.
-
-Cobra init is pretty smart. You can provide it a full path, or simply a path
-similar to what is expected in the import.
-
-```
-cobra init github.com/spf13/newAppName
-```
-
-### cobra add
-
-Once an application is initialized Cobra can create additional commands for you.
-Let's say you created an app and you wanted the following commands for it:
-
-* app serve
-* app config
-* app config create
-
-In your project directory (where your main.go file is) you would run the following:
-
-```
-cobra add serve
-cobra add config
-cobra add create -p 'configCmd'
-```
-
-*Note: Use camelCase (not snake_case/snake-case) for command names.
-Otherwise, you will encounter errors.
-For example, `cobra add add-user` is incorrect, but `cobra add addUser` is valid.*
-
-Once you have run these three commands you would have an app structure similar to
-the following:
-
-```
- ▾ app/
- ▾ cmd/
- serve.go
- config.go
- create.go
- main.go
-```
-
-At this point you can run `go run main.go` and it would run your app. `go run
-main.go serve`, `go run main.go config`, `go run main.go config create` along
-with `go run main.go help serve`, etc. would all work.
-
-Obviously you haven't added your own code to these yet. The commands are ready
-for you to give them their tasks. Have fun!
-
-### Configuring the cobra generator
-
-The Cobra generator will be easier to use if you provide a simple configuration
-file which will help you eliminate providing a bunch of repeated information in
-flags over and over.
-
-An example ~/.cobra.yaml file:
-
-```yaml
-author: Steve Francia <spf@spf13.com>
-license: MIT
-```
-
-You can specify no license by setting `license` to `none` or you can specify
-a custom license:
-
-```yaml
-license:
- header: This file is part of {{ .appName }}.
- text: |
- {{ .copyright }}
-
- This is my license. There are many like it, but this one is mine.
- My license is my best friend. It is my life. I must master it as I must
- master my life.
-```
-
-You can also use built-in licenses. For example, **GPLv2**, **GPLv3**, **LGPL**,
-**AGPL**, **MIT**, **2-Clause BSD** or **3-Clause BSD**.
-
-## Manually implementing Cobra
+## Using the Cobra Library
To manually implement Cobra you need to create a bare main.go file and a RootCmd file.
You will optionally provide additional commands as you see fit.
-### Create the root command
-
-The root command represents your binary itself.
-
-#### Manually create rootCmd
+### Create rootCmd
Cobra doesn't require any special constructors. Simply create your commands.
@@ -316,10 +224,6 @@ func init() {
viper.SetDefault("license", "apache")
}
-func Execute() {
- RootCmd.Execute()
-}
-
func initConfig() {
// Don't forget to read config either from cfgFile or from home directory!
if cfgFile != "" {
@@ -400,17 +304,6 @@ var versionCmd = &cobra.Command{
}
```
-### Attach command to its parent
-
-
-If you notice in the above example we attach the command to its parent. In
-this case the parent is the rootCmd. In this example we are attaching it to the
-root, but commands can be attached at any level.
-
-```go
-RootCmd.AddCommand(versionCmd)
-```
-
## Working with Flags
Flags provide modifiers to control how the action command operates.
@@ -446,6 +339,19 @@ A flag can also be assigned locally which will only apply to that specific comma
RootCmd.Flags().StringVarP(&Source, "source", "s", "", "Source directory to read from")
```
+### Local Flag on Parent Commands
+
+By default Cobra only parses local flags on the target command, any local flags on
+parent commands are ignored. By enabling `Command.TraverseChildren` Cobra will
+parse local flags on each command before executing the target command.
+
+```go
+command := cobra.Command{
+ Use: "print [OPTIONS] [COMMANDS]",
+ TraverseChildren: true,
+}
+```
+
### Bind Flags with Config
You can also bind your flags with [viper](https://github.com/spf13/viper):
@@ -569,7 +475,7 @@ a count and a string.`,
For a more complete example of a larger application, please checkout [Hugo](http://gohugo.io/).
-## The Help Command
+## Help Command
Cobra automatically adds a help command to your application when you have subcommands.
This will be called when a user runs 'app help'. Additionally, help will also
@@ -582,60 +488,28 @@ create' is called. Every command will automatically have the '--help' flag adde
The following output is automatically generated by Cobra. Nothing beyond the
command and flag definitions are needed.
- > hugo help
+ $ cobra help
- hugo is the main command, used to build your Hugo site.
-
- Hugo is a Fast and Flexible Static Site Generator
- built with love by spf13 and friends in Go.
-
- Complete documentation is available at http://gohugo.io/.
+ Cobra is a CLI library for Go that empowers applications.
+ This application is a tool to generate the needed files
+ to quickly create a Cobra application.
Usage:
- hugo [flags]
- hugo [command]
+ cobra [command]
Available Commands:
- server Hugo runs its own webserver to render the files
- version Print the version number of Hugo
- config Print the site configuration
- check Check content in the source directory
- benchmark Benchmark hugo by building a site a number of times.
- convert Convert your content to different formats
- new Create new content for your site
- list Listing out various types of content
- undraft Undraft changes the content's draft status from 'True' to 'False'
- genautocomplete Generate shell autocompletion script for Hugo
- gendoc Generate Markdown documentation for the Hugo CLI.
- genman Generate man page for Hugo
- import Import your site from others.
+ add Add a command to a Cobra Application
+ help Help about any command
+ init Initialize a Cobra Application
Flags:
- -b, --baseURL="": hostname (and path) to the root, e.g. http://spf13.com/
- -D, --buildDrafts[=false]: include content marked as draft
- -F, --buildFuture[=false]: include content with publishdate in the future
- --cacheDir="": filesystem path to cache directory. Defaults: $TMPDIR/hugo_cache/
- --canonifyURLs[=false]: if true, all relative URLs will be canonicalized using baseURL
- --config="": config file (default is path/config.yaml|json|toml)
- -d, --destination="": filesystem path to write files to
- --disableRSS[=false]: Do not build RSS files
- --disableSitemap[=false]: Do not build Sitemap file
- --editor="": edit new content with this editor, if provided
- --ignoreCache[=false]: Ignores the cache directory for reading but still writes to it
- --log[=false]: Enable Logging
- --logFile="": Log File path (if set, logging enabled automatically)
- --noTimes[=false]: Don't sync modification time of files
- --pluralizeListTitles[=true]: Pluralize titles in lists using inflect
- --preserveTaxonomyNames[=false]: Preserve taxonomy names as written ("Gérard Depardieu" vs "gerard-depardieu")
- -s, --source="": filesystem path to read files relative from
- --stepAnalysis[=false]: display memory and timing of different steps of the program
- -t, --theme="": theme to use (located in /themes/THEMENAME/)
- --uglyURLs[=false]: if true, use /filename.html instead of /filename/
- -v, --verbose[=false]: verbose output
- --verboseLog[=false]: verbose logging
- -w, --watch[=false]: watch filesystem for changes and recreate as needed
-
- Use "hugo [command] --help" for more information about a command.
+ -a, --author string author name for copyright attribution (default "YOUR NAME")
+ --config string config file (default is $HOME/.cobra.yaml)
+ -h, --help help for cobra
+ -l, --license string name of license for the project
+ --viper use Viper for configuration (default true)
+
+ Use "cobra [command] --help" for more information about a command.
Help is just a command like any other. There is no special logic or behavior
@@ -643,36 +517,18 @@ around it. In fact, you can provide your own if you want.
### Defining your own help
-You can provide your own Help command or your own template for the default command to use.
-
-The default help command is
+You can provide your own Help command or your own template for the default command to use
+with followind functions:
```go
-func (c *Command) initHelp() {
- if c.helpCommand == nil {
- c.helpCommand = &Command{
- Use: "help [command]",
- Short: "Help about any command",
- Long: `Help provides help for any command in the application.
- Simply type ` + c.Name() + ` help [path to command] for full details.`,
- Run: c.HelpFunc(),
- }
- }
- c.AddCommand(c.helpCommand)
-}
-```
-
-You can provide your own command, function or template through the following methods:
-
-```go
-command.SetHelpCommand(cmd *Command)
-command.SetHelpFunc(f func(*Command, []string))
-command.SetHelpTemplate(s string)
+cmd.SetHelpCommand(cmd *Command)
+cmd.SetHelpFunc(f func(*Command, []string))
+cmd.SetHelpTemplate(s string)
```
The latter two will also apply to any children commands.
-## Usage
+## Usage Message
When the user provides an invalid flag or invalid command, Cobra responds by
showing the user the 'usage'.
@@ -681,71 +537,35 @@ showing the user the 'usage'.
You may recognize this from the help above. That's because the default help
embeds the usage as part of its output.
+ $ cobra --invalid
+ Error: unknown flag: --invalid
Usage:
- hugo [flags]
- hugo [command]
+ cobra [command]
Available Commands:
- server Hugo runs its own webserver to render the files
- version Print the version number of Hugo
- config Print the site configuration
- check Check content in the source directory
- benchmark Benchmark hugo by building a site a number of times.
- convert Convert your content to different formats
- new Create new content for your site
- list Listing out various types of content
- undraft Undraft changes the content's draft status from 'True' to 'False'
- genautocomplete Generate shell autocompletion script for Hugo
- gendoc Generate Markdown documentation for the Hugo CLI.
- genman Generate man page for Hugo
- import Import your site from others.
+ add Add a command to a Cobra Application
+ help Help about any command
+ init Initialize a Cobra Application
Flags:
- -b, --baseURL="": hostname (and path) to the root, e.g. http://spf13.com/
- -D, --buildDrafts[=false]: include content marked as draft
- -F, --buildFuture[=false]: include content with publishdate in the future
- --cacheDir="": filesystem path to cache directory. Defaults: $TMPDIR/hugo_cache/
- --canonifyURLs[=false]: if true, all relative URLs will be canonicalized using baseURL
- --config="": config file (default is path/config.yaml|json|toml)
- -d, --destination="": filesystem path to write files to
- --disableRSS[=false]: Do not build RSS files
- --disableSitemap[=false]: Do not build Sitemap file
- --editor="": edit new content with this editor, if provided
- --ignoreCache[=false]: Ignores the cache directory for reading but still writes to it
- --log[=false]: Enable Logging
- --logFile="": Log File path (if set, logging enabled automatically)
- --noTimes[=false]: Don't sync modification time of files
- --pluralizeListTitles[=true]: Pluralize titles in lists using inflect
- --preserveTaxonomyNames[=false]: Preserve taxonomy names as written ("Gérard Depardieu" vs "gerard-depardieu")
- -s, --source="": filesystem path to read files relative from
- --stepAnalysis[=false]: display memory and timing of different steps of the program
- -t, --theme="": theme to use (located in /themes/THEMENAME/)
- --uglyURLs[=false]: if true, use /filename.html instead of /filename/
- -v, --verbose[=false]: verbose output
- --verboseLog[=false]: verbose logging
- -w, --watch[=false]: watch filesystem for changes and recreate as needed
+ -a, --author string author name for copyright attribution (default "YOUR NAME")
+ --config string config file (default is $HOME/.cobra.yaml)
+ -h, --help help for cobra
+ -l, --license string name of license for the project
+ --viper use Viper for configuration (default true)
+
+ Use "cobra [command] --help" for more information about a command.
### Defining your own usage
You can provide your own usage function or template for Cobra to use.
-
-The default usage function is:
-
-```go
-return func(c *Command) error {
- err := tmpl(c.Out(), c.UsageTemplate(), c)
- return err
-}
-```
-
Like help, the function and template are overridable through public methods:
```go
-command.SetUsageFunc(f func(*Command) error)
-
-command.SetUsageTemplate(s string)
+cmd.SetUsageFunc(f func(*Command) error)
+cmd.SetUsageTemplate(s string)
```
-## PreRun or PostRun Hooks
+## PreRun and PostRun Hooks
It is possible to run functions before or after the main `Run` function of your command. The `PersistentPreRun` and `PreRun` functions will be executed before `Run`. `PersistentPostRun` and `PostRun` will be executed after `Run`. The `Persistent*Run` functions will be inherited by children if they do not declare their own. These functions are run in the following order:
@@ -815,51 +635,19 @@ func main() {
}
```
+Output:
+```
+Inside rootCmd PersistentPreRun with args: []
+Inside rootCmd PreRun with args: []
+Inside rootCmd Run with args: []
+Inside rootCmd PostRun with args: []
+Inside rootCmd PersistentPostRun with args: []
-## Alternative Error Handling
-
-Cobra also has functions where the return signature is an error. This allows for errors to bubble up to the top,
-providing a way to handle the errors in one location. The current list of functions that return an error is:
-
-* PersistentPreRunE
-* PreRunE
-* RunE
-* PostRunE
-* PersistentPostRunE
-
-If you would like to silence the default `error` and `usage` output in favor of your own, you can set `SilenceUsage`
-and `SilenceErrors` to `true` on the command. A child command respects these flags if they are set on the parent
-command.
-
-**Example Usage using RunE:**
-
-```go
-package main
-
-import (
- "errors"
- "log"
-
- "github.com/spf13/cobra"
-)
-
-func main() {
- var rootCmd = &cobra.Command{
- Use: "hugo",
- Short: "Hugo is a very fast static site generator",
- Long: `A Fast and Flexible Static Site Generator built with
-love by spf13 and friends in Go.
-Complete documentation is available at http://hugo.spf13.com`,
- RunE: func(cmd *cobra.Command, args []string) error {
- // Do Stuff Here
- return errors.New("some random error")
- },
- }
-
- if err := rootCmd.Execute(); err != nil {
- log.Fatal(err)
- }
-}
+Inside rootCmd PersistentPreRun with args: [arg1 arg2]
+Inside subCmd PreRun with args: [arg1 arg2]
+Inside subCmd Run with args: [arg1 arg2]
+Inside subCmd PostRun with args: [arg1 arg2]
+Inside subCmd PersistentPostRun with args: [arg1 arg2]
```
## Suggestions when "unknown command" happens
@@ -902,41 +690,28 @@ Did you mean this?
Run 'kubectl help' for usage.
```
-## Generating Markdown-formatted documentation for your command
+## Generating documentation for your command
-Cobra can generate a Markdown-formatted document based on the subcommands, flags, etc. A simple example of how to do this for your command can be found in [Markdown Docs](doc/md_docs.md).
+Cobra can generate documentation based on subcommands, flags, etc. in the following formats:
-## Generating man pages for your command
+- [Markdown](doc/md_docs.md)
+- [ReStructured Text](doc/rest_docs.md)
+- [Man Page](doc/man_docs.md)
-Cobra can generate a man page based on the subcommands, flags, etc. A simple example of how to do this for your command can be found in [Man Docs](doc/man_docs.md).
-
-## Generating bash completions for your command
+## Generating bash completions
Cobra can generate a bash-completion file. If you add more information to your command, these completions can be amazingly powerful and flexible. Read more about it in [Bash Completions](bash_completions.md).
-
-## Extensions
-
-Libraries for extending Cobra:
-
-* [cmdns](https://github.com/gosuri/cmdns): Enables name spacing a command's immediate children. It provides an alternative way to structure subcommands, similar to `heroku apps:create` and `ovrclk clusters:launch`.
-
-## Contributing
+# Contributing
1. Fork it
-2. Create your feature branch (`git checkout -b my-new-feature`)
-3. Commit your changes (`git commit -am 'Add some feature'`)
-4. Push to the branch (`git push origin my-new-feature`)
-5. Create new Pull Request
-
-## Contributors
-
-Names in no particular order:
-
-* [spf13](https://github.com/spf13),
-[eparis](https://github.com/eparis),
-[bep](https://github.com/bep), and many more!
-
-## License
+2. Download your fork to your PC (`git clone https://github.com/your_username/cobra && cd cobra`)
+3. Create your feature branch (`git checkout -b my-new-feature`)
+4. Make changes and add them (`git add .`)
+5. Commit your changes (`git commit -m 'Add some feature'`)
+6. Push to the branch (`git push origin my-new-feature`)
+7. Create new pull request
+
+# License
Cobra is released under the Apache 2.0 license. See [LICENSE.txt](https://github.com/spf13/cobra/blob/master/LICENSE.txt)
diff --git a/vendor/github.com/spf13/cobra/args.go b/vendor/github.com/spf13/cobra/args.go
index 94a6ca273..a5d8a9273 100644
--- a/vendor/github.com/spf13/cobra/args.go
+++ b/vendor/github.com/spf13/cobra/args.go
@@ -16,14 +16,14 @@ func legacyArgs(cmd *Command, args []string) error {
return nil
}
- // root command with subcommands, do subcommand checking
+ // root command with subcommands, do subcommand checking.
if !cmd.HasParent() && len(args) > 0 {
return fmt.Errorf("unknown command %q for %q%s", args[0], cmd.CommandPath(), cmd.findSuggestions(args[0]))
}
return nil
}
-// NoArgs returns an error if any args are included
+// NoArgs returns an error if any args are included.
func NoArgs(cmd *Command, args []string) error {
if len(args) > 0 {
return fmt.Errorf("unknown command %q for %q", args[0], cmd.CommandPath())
@@ -31,7 +31,7 @@ func NoArgs(cmd *Command, args []string) error {
return nil
}
-// OnlyValidArgs returns an error if any args are not in the list of ValidArgs
+// OnlyValidArgs returns an error if any args are not in the list of ValidArgs.
func OnlyValidArgs(cmd *Command, args []string) error {
if len(cmd.ValidArgs) > 0 {
for _, v := range args {
@@ -43,21 +43,12 @@ func OnlyValidArgs(cmd *Command, args []string) error {
return nil
}
-func stringInSlice(a string, list []string) bool {
- for _, b := range list {
- if b == a {
- return true
- }
- }
- return false
-}
-
-// ArbitraryArgs never returns an error
+// ArbitraryArgs never returns an error.
func ArbitraryArgs(cmd *Command, args []string) error {
return nil
}
-// MinimumNArgs returns an error if there is not at least N args
+// MinimumNArgs returns an error if there is not at least N args.
func MinimumNArgs(n int) PositionalArgs {
return func(cmd *Command, args []string) error {
if len(args) < n {
@@ -67,7 +58,7 @@ func MinimumNArgs(n int) PositionalArgs {
}
}
-// MaximumNArgs returns an error if there are more than N args
+// MaximumNArgs returns an error if there are more than N args.
func MaximumNArgs(n int) PositionalArgs {
return func(cmd *Command, args []string) error {
if len(args) > n {
@@ -77,7 +68,7 @@ func MaximumNArgs(n int) PositionalArgs {
}
}
-// ExactArgs returns an error if there are not exactly n args
+// ExactArgs returns an error if there are not exactly n args.
func ExactArgs(n int) PositionalArgs {
return func(cmd *Command, args []string) error {
if len(args) != n {
@@ -87,7 +78,7 @@ func ExactArgs(n int) PositionalArgs {
}
}
-// RangeArgs returns an error if the number of args is not within the expected range
+// RangeArgs returns an error if the number of args is not within the expected range.
func RangeArgs(min int, max int) PositionalArgs {
return func(cmd *Command, args []string) error {
if len(args) < min || len(args) > max {
diff --git a/vendor/github.com/spf13/cobra/args_test.go b/vendor/github.com/spf13/cobra/args_test.go
new file mode 100644
index 000000000..d797b6f58
--- /dev/null
+++ b/vendor/github.com/spf13/cobra/args_test.go
@@ -0,0 +1,241 @@
+package cobra
+
+import (
+ "strings"
+ "testing"
+)
+
+func TestNoArgs(t *testing.T) {
+ c := &Command{Use: "c", Args: NoArgs, Run: emptyRun}
+
+ output, err := executeCommand(c)
+ if output != "" {
+ t.Errorf("Unexpected string: %v", output)
+ }
+ if err != nil {
+ t.Fatalf("Unexpected error: %v", err)
+ }
+}
+
+func TestNoArgsWithArgs(t *testing.T) {
+ c := &Command{Use: "c", Args: NoArgs, Run: emptyRun}
+
+ _, err := executeCommand(c, "illegal")
+ if err == nil {
+ t.Fatal("Expected an error")
+ }
+
+ got := err.Error()
+ expected := `unknown command "illegal" for "c"`
+ if got != expected {
+ t.Errorf("Expected: %q, got: %q", expected, got)
+ }
+}
+
+func TestOnlyValidArgs(t *testing.T) {
+ c := &Command{
+ Use: "c",
+ Args: OnlyValidArgs,
+ ValidArgs: []string{"one", "two"},
+ Run: emptyRun,
+ }
+
+ output, err := executeCommand(c, "one", "two")
+ if output != "" {
+ t.Errorf("Unexpected output: %v", output)
+ }
+ if err != nil {
+ t.Fatalf("Unexpected error: %v", err)
+ }
+}
+
+func TestOnlyValidArgsWithInvalidArgs(t *testing.T) {
+ c := &Command{
+ Use: "c",
+ Args: OnlyValidArgs,
+ ValidArgs: []string{"one", "two"},
+ Run: emptyRun,
+ }
+
+ _, err := executeCommand(c, "three")
+ if err == nil {
+ t.Fatal("Expected an error")
+ }
+
+ got := err.Error()
+ expected := `invalid argument "three" for "c"`
+ if got != expected {
+ t.Errorf("Expected: %q, got: %q", expected, got)
+ }
+}
+
+func TestArbitraryArgs(t *testing.T) {
+ c := &Command{Use: "c", Args: ArbitraryArgs, Run: emptyRun}
+ output, err := executeCommand(c, "a", "b")
+ if output != "" {
+ t.Errorf("Unexpected output: %v", output)
+ }
+ if err != nil {
+ t.Errorf("Unexpected error: %v", err)
+ }
+}
+
+func TestMinimumNArgs(t *testing.T) {
+ c := &Command{Use: "c", Args: MinimumNArgs(2), Run: emptyRun}
+ output, err := executeCommand(c, "a", "b", "c")
+ if output != "" {
+ t.Errorf("Unexpected output: %v", output)
+ }
+ if err != nil {
+ t.Errorf("Unexpected error: %v", err)
+ }
+}
+
+func TestMinimumNArgsWithLessArgs(t *testing.T) {
+ c := &Command{Use: "c", Args: MinimumNArgs(2), Run: emptyRun}
+ _, err := executeCommand(c, "a")
+
+ if err == nil {
+ t.Fatal("Expected an error")
+ }
+
+ got := err.Error()
+ expected := "requires at least 2 arg(s), only received 1"
+ if got != expected {
+ t.Fatalf("Expected %q, got %q", expected, got)
+ }
+}
+
+func TestMaximumNArgs(t *testing.T) {
+ c := &Command{Use: "c", Args: MaximumNArgs(3), Run: emptyRun}
+ output, err := executeCommand(c, "a", "b")
+ if output != "" {
+ t.Errorf("Unexpected output: %v", output)
+ }
+ if err != nil {
+ t.Errorf("Unexpected error: %v", err)
+ }
+}
+
+func TestMaximumNArgsWithMoreArgs(t *testing.T) {
+ c := &Command{Use: "c", Args: MaximumNArgs(2), Run: emptyRun}
+ _, err := executeCommand(c, "a", "b", "c")
+
+ if err == nil {
+ t.Fatal("Expected an error")
+ }
+
+ got := err.Error()
+ expected := "accepts at most 2 arg(s), received 3"
+ if got != expected {
+ t.Fatalf("Expected %q, got %q", expected, got)
+ }
+}
+
+func TestExactArgs(t *testing.T) {
+ c := &Command{Use: "c", Args: ExactArgs(3), Run: emptyRun}
+ output, err := executeCommand(c, "a", "b", "c")
+ if output != "" {
+ t.Errorf("Unexpected output: %v", output)
+ }
+ if err != nil {
+ t.Errorf("Unexpected error: %v", err)
+ }
+}
+
+func TestExactArgsWithInvalidCount(t *testing.T) {
+ c := &Command{Use: "c", Args: ExactArgs(2), Run: emptyRun}
+ _, err := executeCommand(c, "a", "b", "c")
+
+ if err == nil {
+ t.Fatal("Expected an error")
+ }
+
+ got := err.Error()
+ expected := "accepts 2 arg(s), received 3"
+ if got != expected {
+ t.Fatalf("Expected %q, got %q", expected, got)
+ }
+}
+
+func TestRangeArgs(t *testing.T) {
+ c := &Command{Use: "c", Args: RangeArgs(2, 4), Run: emptyRun}
+ output, err := executeCommand(c, "a", "b", "c")
+ if output != "" {
+ t.Errorf("Unexpected output: %v", output)
+ }
+ if err != nil {
+ t.Errorf("Unexpected error: %v", err)
+ }
+}
+
+func TestRangeArgsWithInvalidCount(t *testing.T) {
+ c := &Command{Use: "c", Args: RangeArgs(2, 4), Run: emptyRun}
+ _, err := executeCommand(c, "a")
+
+ if err == nil {
+ t.Fatal("Expected an error")
+ }
+
+ got := err.Error()
+ expected := "accepts between 2 and 4 arg(s), received 1"
+ if got != expected {
+ t.Fatalf("Expected %q, got %q", expected, got)
+ }
+}
+
+func TestRootTakesNoArgs(t *testing.T) {
+ rootCmd := &Command{Use: "root", Run: emptyRun}
+ childCmd := &Command{Use: "child", Run: emptyRun}
+ rootCmd.AddCommand(childCmd)
+
+ _, err := executeCommand(rootCmd, "illegal", "args")
+ if err == nil {
+ t.Fatal("Expected an error")
+ }
+
+ got := err.Error()
+ expected := `unknown command "illegal" for "root"`
+ if !strings.Contains(got, expected) {
+ t.Errorf("expected %q, got %q", expected, got)
+ }
+}
+
+func TestRootTakesArgs(t *testing.T) {
+ rootCmd := &Command{Use: "root", Args: ArbitraryArgs, Run: emptyRun}
+ childCmd := &Command{Use: "child", Run: emptyRun}
+ rootCmd.AddCommand(childCmd)
+
+ _, err := executeCommand(rootCmd, "legal", "args")
+ if err != nil {
+ t.Errorf("Unexpected error: %v", err)
+ }
+}
+
+func TestChildTakesNoArgs(t *testing.T) {
+ rootCmd := &Command{Use: "root", Run: emptyRun}
+ childCmd := &Command{Use: "child", Args: NoArgs, Run: emptyRun}
+ rootCmd.AddCommand(childCmd)
+
+ _, err := executeCommand(rootCmd, "child", "illegal", "args")
+ if err == nil {
+ t.Fatal("Expected an error")
+ }
+
+ got := err.Error()
+ expected := `unknown command "illegal" for "root child"`
+ if !strings.Contains(got, expected) {
+ t.Errorf("expected %q, got %q", expected, got)
+ }
+}
+
+func TestChildTakesArgs(t *testing.T) {
+ rootCmd := &Command{Use: "root", Run: emptyRun}
+ childCmd := &Command{Use: "child", Args: ArbitraryArgs, Run: emptyRun}
+ rootCmd.AddCommand(childCmd)
+
+ _, err := executeCommand(rootCmd, "child", "legal", "args")
+ if err != nil {
+ t.Fatalf("Unexpected error: %v", err)
+ }
+}
diff --git a/vendor/github.com/spf13/cobra/bash_completions.go b/vendor/github.com/spf13/cobra/bash_completions.go
index e402065dd..c19fe7a06 100644
--- a/vendor/github.com/spf13/cobra/bash_completions.go
+++ b/vendor/github.com/spf13/cobra/bash_completions.go
@@ -92,7 +92,7 @@ __handle_reply()
cur="${cur#*=}"
${flags_completion[${index}]}
if [ -n "${ZSH_VERSION}" ]; then
- # zfs completion needs --flag= prefix
+ # zsh completion needs --flag= prefix
eval "COMPREPLY=( \"\${COMPREPLY[@]/#/${flag}=}\" )"
fi
fi
diff --git a/vendor/github.com/spf13/cobra/bash_completions_test.go b/vendor/github.com/spf13/cobra/bash_completions_test.go
index a3b13a32a..a0da87148 100644
--- a/vendor/github.com/spf13/cobra/bash_completions_test.go
+++ b/vendor/github.com/spf13/cobra/bash_completions_test.go
@@ -10,13 +10,13 @@ import (
func checkOmit(t *testing.T, found, unexpected string) {
if strings.Contains(found, unexpected) {
- t.Errorf("Unexpected response.\nGot: %q\nBut should not have!\n", unexpected)
+ t.Errorf("Got: %q\nBut should not have!\n", unexpected)
}
}
func check(t *testing.T, found, expected string) {
if !strings.Contains(found, expected) {
- t.Errorf("Unexpected response.\nExpecting to contain: \n %q\nGot:\n %q\n", expected, found)
+ t.Errorf("Expecting to contain: \n %q\nGot:\n %q\n", expected, found)
}
}
@@ -33,162 +33,164 @@ func runShellCheck(s string) error {
return err
}
go func() {
- defer stdin.Close()
stdin.Write([]byte(s))
+ stdin.Close()
}()
return cmd.Run()
}
// World worst custom function, just keep telling you to enter hello!
-const (
- bashCompletionFunc = `__custom_func() {
-COMPREPLY=( "hello" )
+const bashCompletionFunc = `__custom_func() {
+ COMPREPLY=( "hello" )
}
`
-)
func TestBashCompletions(t *testing.T) {
- c := initializeWithRootCmd()
- cmdEcho.AddCommand(cmdTimes)
- c.AddCommand(cmdEcho, cmdPrint, cmdDeprecated, cmdColon)
-
- // custom completion function
- c.BashCompletionFunction = bashCompletionFunc
-
- // required flag
- c.MarkFlagRequired("introot")
-
- // valid nouns
- validArgs := []string{"pod", "node", "service", "replicationcontroller"}
- c.ValidArgs = validArgs
-
- // noun aliases
- argAliases := []string{"pods", "nodes", "services", "replicationcontrollers", "po", "no", "svc", "rc"}
- c.ArgAliases = argAliases
-
- // filename
- var flagval string
- c.Flags().StringVar(&flagval, "filename", "", "Enter a filename")
- c.MarkFlagFilename("filename", "json", "yaml", "yml")
-
- // persistent filename
- var flagvalPersistent string
- c.PersistentFlags().StringVar(&flagvalPersistent, "persistent-filename", "", "Enter a filename")
- c.MarkPersistentFlagFilename("persistent-filename")
- c.MarkPersistentFlagRequired("persistent-filename")
-
- // filename extensions
- var flagvalExt string
- c.Flags().StringVar(&flagvalExt, "filename-ext", "", "Enter a filename (extension limited)")
- c.MarkFlagFilename("filename-ext")
-
- // filename extensions
- var flagvalCustom string
- c.Flags().StringVar(&flagvalCustom, "custom", "", "Enter a filename (extension limited)")
- c.MarkFlagCustom("custom", "__complete_custom")
-
- // subdirectories in a given directory
- var flagvalTheme string
- c.Flags().StringVar(&flagvalTheme, "theme", "", "theme to use (located in /themes/THEMENAME/)")
- c.Flags().SetAnnotation("theme", BashCompSubdirsInDir, []string{"themes"})
-
- out := new(bytes.Buffer)
- c.GenBashCompletion(out)
- str := out.String()
-
- check(t, str, "_cobra-test")
- check(t, str, "_cobra-test_echo")
- check(t, str, "_cobra-test_echo_times")
- check(t, str, "_cobra-test_print")
- check(t, str, "_cobra-test_cmd__colon")
+ rootCmd := &Command{
+ Use: "root",
+ ArgAliases: []string{"pods", "nodes", "services", "replicationcontrollers", "po", "no", "svc", "rc"},
+ ValidArgs: []string{"pod", "node", "service", "replicationcontroller"},
+ BashCompletionFunction: bashCompletionFunc,
+ Run: emptyRun,
+ }
+ rootCmd.Flags().IntP("introot", "i", -1, "help message for flag introot")
+ rootCmd.MarkFlagRequired("introot")
+
+ // Filename.
+ rootCmd.Flags().String("filename", "", "Enter a filename")
+ rootCmd.MarkFlagFilename("filename", "json", "yaml", "yml")
+
+ // Persistent filename.
+ rootCmd.PersistentFlags().String("persistent-filename", "", "Enter a filename")
+ rootCmd.MarkPersistentFlagFilename("persistent-filename")
+ rootCmd.MarkPersistentFlagRequired("persistent-filename")
+
+ // Filename extensions.
+ rootCmd.Flags().String("filename-ext", "", "Enter a filename (extension limited)")
+ rootCmd.MarkFlagFilename("filename-ext")
+ rootCmd.Flags().String("custom", "", "Enter a filename (extension limited)")
+ rootCmd.MarkFlagCustom("custom", "__complete_custom")
+
+ // Subdirectories in a given directory.
+ rootCmd.Flags().String("theme", "", "theme to use (located in /themes/THEMENAME/)")
+ rootCmd.Flags().SetAnnotation("theme", BashCompSubdirsInDir, []string{"themes"})
+
+ echoCmd := &Command{
+ Use: "echo [string to echo]",
+ Aliases: []string{"say"},
+ Short: "Echo anything to the screen",
+ Long: "an utterly useless command for testing.",
+ Example: "Just run cobra-test echo",
+ Run: emptyRun,
+ }
+
+ printCmd := &Command{
+ Use: "print [string to print]",
+ Args: MinimumNArgs(1),
+ Short: "Print anything to the screen",
+ Long: "an absolutely utterly useless command for testing.",
+ Run: emptyRun,
+ }
+
+ deprecatedCmd := &Command{
+ Use: "deprecated [can't do anything here]",
+ Args: NoArgs,
+ Short: "A command which is deprecated",
+ Long: "an absolutely utterly useless command for testing deprecation!.",
+ Deprecated: "Please use echo instead",
+ Run: emptyRun,
+ }
+
+ colonCmd := &Command{
+ Use: "cmd:colon",
+ Run: emptyRun,
+ }
+
+ timesCmd := &Command{
+ Use: "times [# times] [string to echo]",
+ SuggestFor: []string{"counts"},
+ Args: OnlyValidArgs,
+ ValidArgs: []string{"one", "two", "three", "four"},
+ Short: "Echo anything to the screen more times",
+ Long: "a slightly useless command for testing.",
+ Run: emptyRun,
+ }
+
+ echoCmd.AddCommand(timesCmd)
+ rootCmd.AddCommand(echoCmd, printCmd, deprecatedCmd, colonCmd)
+
+ buf := new(bytes.Buffer)
+ rootCmd.GenBashCompletion(buf)
+ output := buf.String()
+
+ check(t, output, "_root")
+ check(t, output, "_root_echo")
+ check(t, output, "_root_echo_times")
+ check(t, output, "_root_print")
+ check(t, output, "_root_cmd__colon")
// check for required flags
- check(t, str, `must_have_one_flag+=("--introot=")`)
- check(t, str, `must_have_one_flag+=("--persistent-filename=")`)
+ check(t, output, `must_have_one_flag+=("--introot=")`)
+ check(t, output, `must_have_one_flag+=("--persistent-filename=")`)
// check for custom completion function
- check(t, str, `COMPREPLY=( "hello" )`)
+ check(t, output, `COMPREPLY=( "hello" )`)
// check for required nouns
- check(t, str, `must_have_one_noun+=("pod")`)
+ check(t, output, `must_have_one_noun+=("pod")`)
// check for noun aliases
- check(t, str, `noun_aliases+=("pods")`)
- check(t, str, `noun_aliases+=("rc")`)
- checkOmit(t, str, `must_have_one_noun+=("pods")`)
+ check(t, output, `noun_aliases+=("pods")`)
+ check(t, output, `noun_aliases+=("rc")`)
+ checkOmit(t, output, `must_have_one_noun+=("pods")`)
// check for filename extension flags
- check(t, str, `flags_completion+=("_filedir")`)
+ check(t, output, `flags_completion+=("_filedir")`)
// check for filename extension flags
- check(t, str, `must_have_one_noun+=("three")`)
+ check(t, output, `must_have_one_noun+=("three")`)
// check for filename extension flags
- check(t, str, `flags_completion+=("__handle_filename_extension_flag json|yaml|yml")`)
+ check(t, output, `flags_completion+=("__handle_filename_extension_flag json|yaml|yml")`)
// check for custom flags
- check(t, str, `flags_completion+=("__complete_custom")`)
+ check(t, output, `flags_completion+=("__complete_custom")`)
// check for subdirs_in_dir flags
- check(t, str, `flags_completion+=("__handle_subdirs_in_dir_flag themes")`)
+ check(t, output, `flags_completion+=("__handle_subdirs_in_dir_flag themes")`)
- checkOmit(t, str, cmdDeprecated.Name())
+ checkOmit(t, output, deprecatedCmd.Name())
- // if available, run shellcheck against the script
+ // If available, run shellcheck against the script.
if err := exec.Command("which", "shellcheck").Run(); err != nil {
return
}
- err := runShellCheck(str)
- if err != nil {
+ if err := runShellCheck(output); err != nil {
t.Fatalf("shellcheck failed: %v", err)
}
}
func TestBashCompletionHiddenFlag(t *testing.T) {
- var cmdTrue = &Command{
- Use: "does nothing",
- Run: func(cmd *Command, args []string) {},
- }
+ c := &Command{Use: "c", Run: emptyRun}
- const flagName = "hidden-foo-bar-baz"
+ const flagName = "hiddenFlag"
+ c.Flags().Bool(flagName, false, "")
+ c.Flags().MarkHidden(flagName)
- var flagValue bool
- cmdTrue.Flags().BoolVar(&flagValue, flagName, false, "hidden flag")
- cmdTrue.Flags().MarkHidden(flagName)
+ buf := new(bytes.Buffer)
+ c.GenBashCompletion(buf)
+ output := buf.String()
- out := new(bytes.Buffer)
- cmdTrue.GenBashCompletion(out)
- bashCompletion := out.String()
- if strings.Contains(bashCompletion, flagName) {
- t.Errorf("expected completion to not include %q flag: Got %v", flagName, bashCompletion)
+ if strings.Contains(output, flagName) {
+ t.Errorf("Expected completion to not include %q flag: Got %v", flagName, output)
}
}
func TestBashCompletionDeprecatedFlag(t *testing.T) {
- var cmdTrue = &Command{
- Use: "does nothing",
- Run: func(cmd *Command, args []string) {},
- }
-
- const flagName = "deprecated-foo-bar-baz"
-
- var flagValue bool
- cmdTrue.Flags().BoolVar(&flagValue, flagName, false, "hidden flag")
- cmdTrue.Flags().MarkDeprecated(flagName, "use --does-not-exist instead")
-
- out := new(bytes.Buffer)
- cmdTrue.GenBashCompletion(out)
- bashCompletion := out.String()
- if strings.Contains(bashCompletion, flagName) {
- t.Errorf("expected completion to not include %q flag: Got %v", flagName, bashCompletion)
- }
-}
+ c := &Command{Use: "c", Run: emptyRun}
-func BenchmarkBashCompletion(b *testing.B) {
- c := initializeWithRootCmd()
- cmdEcho.AddCommand(cmdTimes)
- c.AddCommand(cmdEcho, cmdPrint, cmdDeprecated, cmdColon)
+ const flagName = "deprecated-flag"
+ c.Flags().Bool(flagName, false, "")
+ c.Flags().MarkDeprecated(flagName, "use --not-deprecated instead")
buf := new(bytes.Buffer)
+ c.GenBashCompletion(buf)
+ output := buf.String()
- b.ResetTimer()
- for i := 0; i < b.N; i++ {
- buf.Reset()
- if err := c.GenBashCompletion(buf); err != nil {
- b.Fatal(err)
- }
+ if strings.Contains(output, flagName) {
+ t.Errorf("expected completion to not include %q flag: Got %v", flagName, output)
}
}
diff --git a/vendor/github.com/spf13/cobra/cobra.go b/vendor/github.com/spf13/cobra/cobra.go
index 8928cefc2..e4b910c5d 100644
--- a/vendor/github.com/spf13/cobra/cobra.go
+++ b/vendor/github.com/spf13/cobra/cobra.go
@@ -188,3 +188,12 @@ func ld(s, t string, ignoreCase bool) int {
}
return d[len(s)][len(t)]
}
+
+func stringInSlice(a string, list []string) bool {
+ for _, b := range list {
+ if b == a {
+ return true
+ }
+ }
+ return false
+}
diff --git a/vendor/github.com/spf13/cobra/cobra/README.md b/vendor/github.com/spf13/cobra/cobra/README.md
new file mode 100644
index 000000000..6054f95c5
--- /dev/null
+++ b/vendor/github.com/spf13/cobra/cobra/README.md
@@ -0,0 +1,94 @@
+# Cobra Generator
+
+Cobra provides its own program that will create your application and add any
+commands you want. It's the easiest way to incorporate Cobra into your application.
+
+In order to use the cobra command, compile it using the following command:
+
+ go get github.com/spf13/cobra/cobra
+
+This will create the cobra executable under your `$GOPATH/bin` directory.
+
+### cobra init
+
+The `cobra init [app]` command will create your initial application code
+for you. It is a very powerful application that will populate your program with
+the right structure so you can immediately enjoy all the benefits of Cobra. It
+will also automatically apply the license you specify to your application.
+
+Cobra init is pretty smart. You can provide it a full path, or simply a path
+similar to what is expected in the import.
+
+```
+cobra init github.com/spf13/newApp
+```
+
+### cobra add
+
+Once an application is initialized, Cobra can create additional commands for you.
+Let's say you created an app and you wanted the following commands for it:
+
+* app serve
+* app config
+* app config create
+
+In your project directory (where your main.go file is) you would run the following:
+
+```
+cobra add serve
+cobra add config
+cobra add create -p 'configCmd'
+```
+
+*Note: Use camelCase (not snake_case/snake-case) for command names.
+Otherwise, you will encounter errors.
+For example, `cobra add add-user` is incorrect, but `cobra add addUser` is valid.*
+
+Once you have run these three commands you would have an app structure similar to
+the following:
+
+```
+ ▾ app/
+ ▾ cmd/
+ serve.go
+ config.go
+ create.go
+ main.go
+```
+
+At this point you can run `go run main.go` and it would run your app. `go run
+main.go serve`, `go run main.go config`, `go run main.go config create` along
+with `go run main.go help serve`, etc. would all work.
+
+Obviously you haven't added your own code to these yet. The commands are ready
+for you to give them their tasks. Have fun!
+
+### Configuring the cobra generator
+
+The Cobra generator will be easier to use if you provide a simple configuration
+file which will help you eliminate providing a bunch of repeated information in
+flags over and over.
+
+An example ~/.cobra.yaml file:
+
+```yaml
+author: Steve Francia <spf@spf13.com>
+license: MIT
+```
+
+You can specify no license by setting `license` to `none` or you can specify
+a custom license:
+
+```yaml
+license:
+ header: This file is part of {{ .appName }}.
+ text: |
+ {{ .copyright }}
+
+ This is my license. There are many like it, but this one is mine.
+ My license is my best friend. It is my life. I must master it as I must
+ master my life.
+```
+
+You can also use built-in licenses. For example, **GPLv2**, **GPLv3**, **LGPL**,
+**AGPL**, **MIT**, **2-Clause BSD** or **3-Clause BSD**.
diff --git a/vendor/github.com/spf13/cobra/cobra/cmd/helpers.go b/vendor/github.com/spf13/cobra/cobra/cmd/helpers.go
index c5e261ce3..e5b37ec72 100644
--- a/vendor/github.com/spf13/cobra/cobra/cmd/helpers.go
+++ b/vendor/github.com/spf13/cobra/cobra/cmd/helpers.go
@@ -18,6 +18,7 @@ import (
"fmt"
"io"
"os"
+ "os/exec"
"path/filepath"
"strings"
"text/template"
@@ -31,7 +32,27 @@ func init() {
envGoPath := os.Getenv("GOPATH")
goPaths := filepath.SplitList(envGoPath)
if len(goPaths) == 0 {
- er("$GOPATH is not set")
+ // Adapted from https://github.com/Masterminds/glide/pull/798/files.
+ // As of Go 1.8 the GOPATH is no longer required to be set. Instead there
+ // is a default value. If there is no GOPATH check for the default value.
+ // Note, checking the GOPATH first to avoid invoking the go toolchain if
+ // possible.
+
+ goExecutable := os.Getenv("COBRA_GO_EXECUTABLE")
+ if len(goExecutable) <= 0 {
+ goExecutable = "go"
+ }
+
+ out, err := exec.Command(goExecutable, "env", "GOPATH").Output()
+ if err != nil {
+ er(err)
+ }
+
+ toolchainGoPath := strings.TrimSpace(string(out))
+ goPaths = filepath.SplitList(toolchainGoPath)
+ if len(goPaths) == 0 {
+ er("$GOPATH is not set")
+ }
}
srcPaths = make([]string, 0, len(goPaths))
for _, goPath := range goPaths {
diff --git a/vendor/github.com/spf13/cobra/cobra/cmd/licenses.go b/vendor/github.com/spf13/cobra/cobra/cmd/licenses.go
index cf2a6b7af..a070134dd 100644
--- a/vendor/github.com/spf13/cobra/cobra/cmd/licenses.go
+++ b/vendor/github.com/spf13/cobra/cobra/cmd/licenses.go
@@ -63,7 +63,7 @@ func getLicense() License {
// If user wants to have custom license, use that.
if viper.IsSet("license.header") || viper.IsSet("license.text") {
return License{Header: viper.GetString("license.header"),
- Text: "license.text"}
+ Text: viper.GetString("license.text")}
}
// If user wants to have built-in license, use that.
diff --git a/vendor/github.com/spf13/cobra/cobra_test.go b/vendor/github.com/spf13/cobra/cobra_test.go
index d5df951e6..0d1755bdb 100644
--- a/vendor/github.com/spf13/cobra/cobra_test.go
+++ b/vendor/github.com/spf13/cobra/cobra_test.go
@@ -1,1200 +1,10 @@
package cobra
import (
- "bytes"
- "fmt"
- "os"
- "reflect"
- "runtime"
- "strings"
"testing"
"text/template"
-
- "github.com/spf13/pflag"
)
-var tp, te, tt, tr []string
-var rootPersPre, echoPre, echoPersPre, timesPersPre []string
-var flagb1, flagb2, flagb3, flagbr, flagbp bool
-var flags1, flags2a, flags2b, flags3, outs string
-var flagi1, flagi2, flagi3, flagi4, flagir int
-var rootcalled bool
-var versionUsed int
-
-const strtwoParentHelp = "help message for parent flag strtwo"
-const strtwoChildHelp = "help message for child flag strtwo"
-
-var cmdHidden = &Command{
- Use: "hide [secret string to print]",
- Short: "Print anything to screen (if command is known)",
- Long: `an absolutely utterly useless command for testing.`,
- Run: func(cmd *Command, args []string) {
- outs = "hidden"
- },
- Hidden: true,
-}
-
-var cmdPrint = &Command{
- Use: "print [string to print]",
- Args: MinimumNArgs(1),
- Short: "Print anything to the screen",
- Long: `an absolutely utterly useless command for testing.`,
- Run: func(cmd *Command, args []string) {
- tp = args
- },
-}
-
-var cmdEcho = &Command{
- Use: "echo [string to echo]",
- Aliases: []string{"say"},
- Short: "Echo anything to the screen",
- Long: `an utterly useless command for testing.`,
- Example: "Just run cobra-test echo",
- PersistentPreRun: func(cmd *Command, args []string) {
- echoPersPre = args
- },
- PreRun: func(cmd *Command, args []string) {
- echoPre = args
- },
- Run: func(cmd *Command, args []string) {
- te = args
- },
-}
-
-var cmdEchoSub = &Command{
- Use: "echosub [string to print]",
- Short: "second sub command for echo",
- Long: `an absolutely utterly useless command for testing gendocs!.`,
- Run: func(cmd *Command, args []string) {
- },
-}
-
-var cmdDeprecated = &Command{
- Use: "deprecated [can't do anything here]",
- Short: "A command which is deprecated",
- Long: `an absolutely utterly useless command for testing deprecation!.`,
- Deprecated: "Please use echo instead",
- Run: func(cmd *Command, args []string) {
- },
- Args: NoArgs,
-}
-
-var cmdTimes = &Command{
- Use: "times [# times] [string to echo]",
- SuggestFor: []string{"counts"},
- Short: "Echo anything to the screen more times",
- Long: `a slightly useless command for testing.`,
- PersistentPreRun: func(cmd *Command, args []string) {
- timesPersPre = args
- },
- Run: func(cmd *Command, args []string) {
- tt = args
- },
- Args: OnlyValidArgs,
- ValidArgs: []string{"one", "two", "three", "four"},
-}
-
-var cmdRootNoRun = &Command{
- Use: "cobra-test",
- Short: "The root can run its own function",
- Long: "The root description for help",
- PersistentPreRun: func(cmd *Command, args []string) {
- rootPersPre = args
- },
-}
-
-var cmdRootSameName = &Command{
- Use: "print",
- Short: "Root with the same name as a subcommand",
- Long: "The root description for help",
-}
-
-var cmdRootTakesArgs = &Command{
- Use: "root-with-args [random args]",
- Short: "The root can run it's own function and takes args!",
- Long: "The root description for help, and some args",
- Run: func(cmd *Command, args []string) {
- tr = args
- },
- Args: ArbitraryArgs,
-}
-
-var cmdRootWithRun = &Command{
- Use: "cobra-test",
- Short: "The root can run its own function",
- Long: "The root description for help",
- Run: func(cmd *Command, args []string) {
- tr = args
- rootcalled = true
- },
-}
-
-var cmdSubNoRun = &Command{
- Use: "subnorun",
- Short: "A subcommand without a Run function",
- Long: "A long output about a subcommand without a Run function",
-}
-
-var cmdCustomFlags = &Command{
- Use: "customflags [flags] -- REMOTE_COMMAND",
- Short: "A command that expects flags in a custom location",
- Long: "A long output about a command that expects flags in a custom location",
- Run: func(cmd *Command, args []string) {
- },
-}
-
-var cmdVersion1 = &Command{
- Use: "version",
- Short: "Print the version number",
- Long: `First version of the version command`,
- Run: func(cmd *Command, args []string) {
- versionUsed = 1
- },
-}
-
-var cmdVersion2 = &Command{
- Use: "version",
- Short: "Print the version number",
- Long: `Second version of the version command`,
- Run: func(cmd *Command, args []string) {
- versionUsed = 2
- },
-}
-
-var cmdColon = &Command{
- Use: "cmd:colon",
- Run: func(cmd *Command, args []string) {
- },
-}
-
-func flagInit() {
- cmdEcho.ResetFlags()
- cmdPrint.ResetFlags()
- cmdTimes.ResetFlags()
- cmdRootNoRun.ResetFlags()
- cmdRootSameName.ResetFlags()
- cmdRootWithRun.ResetFlags()
- cmdSubNoRun.ResetFlags()
- cmdCustomFlags.ResetFlags()
- cmdVersion1.ResetFlags()
- cmdVersion2.ResetFlags()
-
- cmdRootNoRun.PersistentFlags().StringVarP(&flags2a, "strtwo", "t", "two", strtwoParentHelp)
- cmdCustomFlags.Flags().IntVar(&flagi4, "intfour", 456, "help message for flag intfour")
- cmdEcho.Flags().BoolVarP(&flagb1, "boolone", "b", true, "help message for flag boolone")
- cmdEcho.Flags().IntVarP(&flagi1, "intone", "i", 123, "help message for flag intone")
- cmdEcho.PersistentFlags().BoolVarP(&flagbp, "persistentbool", "p", false, "help message for flag persistentbool")
- cmdEcho.PersistentFlags().StringVarP(&flags1, "strone", "s", "one", "help message for flag strone")
- cmdPrint.Flags().IntVarP(&flagi3, "intthree", "i", 345, "help message for flag intthree")
- cmdTimes.Flags().BoolVarP(&flagb2, "booltwo", "c", false, "help message for flag booltwo")
- cmdTimes.Flags().IntVarP(&flagi2, "inttwo", "j", 234, "help message for flag inttwo")
- cmdTimes.Flags().StringVarP(&flags2b, "strtwo", "t", "2", strtwoChildHelp)
- cmdTimes.PersistentFlags().StringVarP(&flags2b, "strtwo", "t", "2", strtwoChildHelp)
- cmdPrint.Flags().BoolVarP(&flagb3, "boolthree", "b", true, "help message for flag boolthree")
- cmdPrint.PersistentFlags().StringVarP(&flags3, "strthree", "s", "three", "help message for flag strthree")
-}
-
-func commandInit() {
- cmdEcho.ResetCommands()
- cmdPrint.ResetCommands()
- cmdTimes.ResetCommands()
- cmdRootNoRun.ResetCommands()
- cmdRootSameName.ResetCommands()
- cmdRootWithRun.ResetCommands()
- cmdSubNoRun.ResetCommands()
- cmdCustomFlags.ResetCommands()
-}
-
-func initialize() *Command {
- tt, tp, te = nil, nil, nil
- rootPersPre, echoPre, echoPersPre, timesPersPre = nil, nil, nil, nil
-
- var c = cmdRootNoRun
- flagInit()
- commandInit()
- return c
-}
-
-func initializeWithSameName() *Command {
- tt, tp, te = nil, nil, nil
- rootPersPre, echoPre, echoPersPre, timesPersPre = nil, nil, nil, nil
- var c = cmdRootSameName
- flagInit()
- commandInit()
- return c
-}
-
-func initializeWithRootCmd() *Command {
- cmdRootWithRun.ResetCommands()
- tt, tp, te, tr, rootcalled = nil, nil, nil, nil, false
- flagInit()
- cmdRootWithRun.Flags().BoolVarP(&flagbr, "boolroot", "b", false, "help message for flag boolroot")
- cmdRootWithRun.Flags().IntVarP(&flagir, "introot", "i", 321, "help message for flag introot")
- commandInit()
- return cmdRootWithRun
-}
-
-type resulter struct {
- Error error
- Output string
- Command *Command
-}
-
-func fullSetupTest(args ...string) resulter {
- c := initializeWithRootCmd()
-
- return fullTester(c, args...)
-}
-
-func noRRSetupTestSilenced(args ...string) resulter {
- c := initialize()
- c.SilenceErrors = true
- c.SilenceUsage = true
- return fullTester(c, args...)
-}
-
-func noRRSetupTest(args ...string) resulter {
- c := initialize()
-
- return fullTester(c, args...)
-}
-
-func rootOnlySetupTest(args ...string) resulter {
- c := initializeWithRootCmd()
-
- return simpleTester(c, args...)
-}
-
-func simpleTester(c *Command, args ...string) resulter {
- buf := new(bytes.Buffer)
- // Testing flag with invalid input
- c.SetOutput(buf)
- c.SetArgs(args)
-
- err := c.Execute()
- output := buf.String()
-
- return resulter{err, output, c}
-}
-
-func simpleTesterC(c *Command, args ...string) resulter {
- buf := new(bytes.Buffer)
- // Testing flag with invalid input
- c.SetOutput(buf)
- c.SetArgs(args)
-
- cmd, err := c.ExecuteC()
- output := buf.String()
-
- return resulter{err, output, cmd}
-}
-
-func fullTester(c *Command, args ...string) resulter {
- buf := new(bytes.Buffer)
- // Testing flag with invalid input
- c.SetOutput(buf)
- cmdEcho.AddCommand(cmdTimes)
- c.AddCommand(cmdPrint, cmdEcho, cmdSubNoRun, cmdCustomFlags, cmdDeprecated)
- c.SetArgs(args)
-
- err := c.Execute()
- output := buf.String()
-
- return resulter{err, output, c}
-}
-
-func logErr(t *testing.T, found, expected string) {
- out := new(bytes.Buffer)
-
- _, _, line, ok := runtime.Caller(2)
- if ok {
- fmt.Fprintf(out, "Line: %d ", line)
- }
- fmt.Fprintf(out, "Unexpected response.\nExpecting to contain: \n %q\nGot:\n %q\n", expected, found)
- t.Errorf(out.String())
-}
-
-func checkStringContains(t *testing.T, found, expected string) {
- if !strings.Contains(found, expected) {
- logErr(t, found, expected)
- }
-}
-
-func checkResultContains(t *testing.T, x resulter, check string) {
- checkStringContains(t, x.Output, check)
-}
-
-func checkStringOmits(t *testing.T, found, expected string) {
- if strings.Contains(found, expected) {
- logErr(t, found, expected)
- }
-}
-
-func checkResultOmits(t *testing.T, x resulter, check string) {
- checkStringOmits(t, x.Output, check)
-}
-
-func checkOutputContains(t *testing.T, c *Command, check string) {
- buf := new(bytes.Buffer)
- c.SetOutput(buf)
- c.Execute()
-
- if !strings.Contains(buf.String(), check) {
- logErr(t, buf.String(), check)
- }
-}
-
-func TestSingleCommand(t *testing.T) {
- noRRSetupTest("print", "one", "two")
-
- if te != nil || tt != nil {
- t.Error("Wrong command called")
- }
- if tp == nil {
- t.Error("Wrong command called")
- }
- if strings.Join(tp, " ") != "one two" {
- t.Error("Command didn't parse correctly")
- }
-}
-
-func TestChildCommand(t *testing.T) {
- noRRSetupTest("echo", "times", "one", "two")
-
- if te != nil || tp != nil {
- t.Error("Wrong command called")
- }
- if tt == nil {
- t.Error("Wrong command called")
- }
- if strings.Join(tt, " ") != "one two" {
- t.Error("Command didn't parse correctly")
- }
-}
-
-func TestCommandAlias(t *testing.T) {
- noRRSetupTest("say", "times", "one", "two")
-
- if te != nil || tp != nil {
- t.Error("Wrong command called")
- }
- if tt == nil {
- t.Error("Wrong command called")
- }
- if strings.Join(tt, " ") != "one two" {
- t.Error("Command didn't parse correctly")
- }
-}
-
-func TestPrefixMatching(t *testing.T) {
- EnablePrefixMatching = true
- noRRSetupTest("ech", "times", "one", "two")
-
- if te != nil || tp != nil {
- t.Error("Wrong command called")
- }
- if tt == nil {
- t.Error("Wrong command called")
- }
- if strings.Join(tt, " ") != "one two" {
- t.Error("Command didn't parse correctly")
- }
-
- EnablePrefixMatching = false
-}
-
-func TestNoPrefixMatching(t *testing.T) {
- EnablePrefixMatching = false
-
- noRRSetupTest("ech", "times", "one", "two")
-
- if !(tt == nil && te == nil && tp == nil) {
- t.Error("Wrong command called")
- }
-}
-
-func TestAliasPrefixMatching(t *testing.T) {
- EnablePrefixMatching = true
- noRRSetupTest("sa", "times", "one", "two")
-
- if te != nil || tp != nil {
- t.Error("Wrong command called")
- }
- if tt == nil {
- t.Error("Wrong command called")
- }
- if strings.Join(tt, " ") != "one two" {
- t.Error("Command didn't parse correctly")
- }
- EnablePrefixMatching = false
-}
-
-func TestChildSameName(t *testing.T) {
- c := initializeWithSameName()
- c.AddCommand(cmdPrint, cmdEcho)
- c.SetArgs([]string{"print", "one", "two"})
- c.Execute()
-
- if te != nil || tt != nil {
- t.Error("Wrong command called")
- }
- if tp == nil {
- t.Error("Wrong command called")
- }
- if strings.Join(tp, " ") != "one two" {
- t.Error("Command didn't parse correctly")
- }
-}
-
-func TestGrandChildSameName(t *testing.T) {
- c := initializeWithSameName()
- cmdTimes.AddCommand(cmdPrint)
- c.AddCommand(cmdTimes)
- c.SetArgs([]string{"times", "print", "one", "two"})
- c.Execute()
-
- if te != nil || tt != nil {
- t.Error("Wrong command called")
- }
- if tp == nil {
- t.Error("Wrong command called")
- }
- if strings.Join(tp, " ") != "one two" {
- t.Error("Command didn't parse correctly")
- }
-}
-
-func TestUsage(t *testing.T) {
- x := fullSetupTest("help")
- checkResultContains(t, x, cmdRootWithRun.Use+" [flags]")
- x = fullSetupTest("help", "customflags")
- checkResultContains(t, x, cmdCustomFlags.Use)
- checkResultOmits(t, x, cmdCustomFlags.Use+" [flags]")
-}
-
-func TestRootTakesNoArgs(t *testing.T) {
- c := initializeWithSameName()
- c.AddCommand(cmdPrint, cmdEcho)
- result := simpleTester(c, "illegal")
-
- if result.Error == nil {
- t.Fatal("Expected an error")
- }
-
- expectedError := `unknown command "illegal" for "print"`
- if !strings.Contains(result.Error.Error(), expectedError) {
- t.Errorf("exptected %v, got %v", expectedError, result.Error.Error())
- }
-}
-
-func TestRootTakesArgs(t *testing.T) {
- c := cmdRootTakesArgs
- result := simpleTester(c, "legal")
-
- if result.Error != nil {
- t.Errorf("expected no error, but got %v", result.Error)
- }
-}
-
-func TestSubCmdTakesNoArgs(t *testing.T) {
- result := fullSetupTest("deprecated", "illegal")
-
- if result.Error == nil {
- t.Fatal("Expected an error")
- }
-
- expectedError := `unknown command "illegal" for "cobra-test deprecated"`
- if !strings.Contains(result.Error.Error(), expectedError) {
- t.Errorf("expected %v, got %v", expectedError, result.Error.Error())
- }
-}
-
-func TestSubCmdTakesArgs(t *testing.T) {
- noRRSetupTest("echo", "times", "one", "two")
- if strings.Join(tt, " ") != "one two" {
- t.Error("Command didn't parse correctly")
- }
-}
-
-func TestCmdOnlyValidArgs(t *testing.T) {
- result := noRRSetupTest("echo", "times", "one", "two", "five")
-
- if result.Error == nil {
- t.Fatal("Expected an error")
- }
-
- expectedError := `invalid argument "five"`
- if !strings.Contains(result.Error.Error(), expectedError) {
- t.Errorf("expected %v, got %v", expectedError, result.Error.Error())
- }
-}
-
-func TestFlagLong(t *testing.T) {
- noRRSetupTest("echo", "--intone=13", "something", "--", "here")
-
- if cmdEcho.ArgsLenAtDash() != 1 {
- t.Errorf("expected argsLenAtDash: %d but got %d", 1, cmdRootNoRun.ArgsLenAtDash())
- }
- if strings.Join(te, " ") != "something here" {
- t.Errorf("flags didn't leave proper args remaining..%s given", te)
- }
- if flagi1 != 13 {
- t.Errorf("int flag didn't get correct value, had %d", flagi1)
- }
- if flagi2 != 234 {
- t.Errorf("default flag value changed, 234 expected, %d given", flagi2)
- }
-}
-
-func TestFlagShort(t *testing.T) {
- noRRSetupTest("echo", "-i13", "--", "something", "here")
-
- if cmdEcho.ArgsLenAtDash() != 0 {
- t.Errorf("expected argsLenAtDash: %d but got %d", 0, cmdRootNoRun.ArgsLenAtDash())
- }
- if strings.Join(te, " ") != "something here" {
- t.Errorf("flags didn't leave proper args remaining..%s given", te)
- }
- if flagi1 != 13 {
- t.Errorf("int flag didn't get correct value, had %d", flagi1)
- }
- if flagi2 != 234 {
- t.Errorf("default flag value changed, 234 expected, %d given", flagi2)
- }
-
- noRRSetupTest("echo", "-i", "13", "something", "here")
-
- if strings.Join(te, " ") != "something here" {
- t.Errorf("flags didn't leave proper args remaining..%s given", te)
- }
- if flagi1 != 13 {
- t.Errorf("int flag didn't get correct value, had %d", flagi1)
- }
- if flagi2 != 234 {
- t.Errorf("default flag value changed, 234 expected, %d given", flagi2)
- }
-
- noRRSetupTest("print", "-i99", "one", "two")
-
- if strings.Join(tp, " ") != "one two" {
- t.Errorf("flags didn't leave proper args remaining..%s given", tp)
- }
- if flagi3 != 99 {
- t.Errorf("int flag didn't get correct value, had %d", flagi3)
- }
- if flagi1 != 123 {
- t.Errorf("default flag value changed on different command with same shortname, 234 expected, %d given", flagi2)
- }
-}
-
-func TestChildCommandFlags(t *testing.T) {
- noRRSetupTest("echo", "times", "-j", "99", "one", "two")
-
- if strings.Join(tt, " ") != "one two" {
- t.Errorf("flags didn't leave proper args remaining..%s given", tt)
- }
-
- // Testing with flag that shouldn't be persistent
- r := noRRSetupTest("echo", "times", "-j", "99", "-i77", "one", "two")
-
- if r.Error == nil {
- t.Errorf("invalid flag should generate error")
- }
-
- if !strings.Contains(r.Error.Error(), "unknown shorthand") {
- t.Errorf("Wrong error message displayed, \n %s", r.Error)
- }
-
- if flagi2 != 99 {
- t.Errorf("flag value should be 99, %d given", flagi2)
- }
-
- if flagi1 != 123 {
- t.Errorf("unset flag should have default value, expecting 123, given %d", flagi1)
- }
-
- // Testing with flag only existing on child
- r = noRRSetupTest("echo", "-j", "99", "-i77", "one", "two")
-
- if r.Error == nil {
- t.Errorf("invalid flag should generate error")
- }
- if !strings.Contains(r.Error.Error(), "unknown shorthand flag") {
- t.Errorf("Wrong error message displayed, \n %s", r.Error)
- }
-
- // Testing with persistent flag overwritten by child
- noRRSetupTest("echo", "times", "--strtwo=child", "one", "two")
-
- if flags2b != "child" {
- t.Errorf("flag value should be child, %s given", flags2b)
- }
-
- if flags2a != "two" {
- t.Errorf("unset flag should have default value, expecting two, given %s", flags2a)
- }
-
- // Testing flag with invalid input
- r = noRRSetupTest("echo", "-i10E")
-
- if r.Error == nil {
- t.Errorf("invalid input should generate error")
- }
- if !strings.Contains(r.Error.Error(), "invalid syntax") {
- t.Errorf("Wrong error message displayed, \n %s", r.Error)
- }
-}
-
-func TestTrailingCommandFlags(t *testing.T) {
- x := fullSetupTest("echo", "two", "-x")
-
- if x.Error == nil {
- t.Errorf("invalid flag should generate error")
- }
-}
-
-func TestInvalidSubcommandFlags(t *testing.T) {
- cmd := initializeWithRootCmd()
- cmd.AddCommand(cmdTimes)
-
- result := simpleTester(cmd, "times", "--inttwo=2", "--badflag=bar")
- // given that we are not checking here result.Error we check for
- // stock usage message
- checkResultContains(t, result, "cobra-test times [# times]")
- if strings.Contains(result.Error.Error(), "unknown flag: --inttwo") {
- t.Errorf("invalid --badflag flag shouldn't fail on 'unknown' --inttwo flag")
- }
-
-}
-
-func TestSubcommandExecuteC(t *testing.T) {
- cmd := initializeWithRootCmd()
- double := &Command{
- Use: "double message",
- Run: func(c *Command, args []string) {
- msg := strings.Join(args, " ")
- c.Println(msg, msg)
- },
- }
-
- echo := &Command{
- Use: "echo message",
- Run: func(c *Command, args []string) {
- msg := strings.Join(args, " ")
- c.Println(msg)
- },
- }
-
- cmd.AddCommand(double, echo)
-
- result := simpleTesterC(cmd, "double", "hello", "world")
- checkResultContains(t, result, "hello world hello world")
-
- if result.Command.Name() != "double" {
- t.Errorf("invalid cmd returned from ExecuteC: should be 'double' but got %s", result.Command.Name())
- }
-
- result = simpleTesterC(cmd, "echo", "msg", "to", "be", "echoed")
- checkResultContains(t, result, "msg to be echoed")
-
- if result.Command.Name() != "echo" {
- t.Errorf("invalid cmd returned from ExecuteC: should be 'echo' but got %s", result.Command.Name())
- }
-}
-
-func TestSubcommandArgEvaluation(t *testing.T) {
- cmd := initializeWithRootCmd()
-
- first := &Command{
- Use: "first",
- Run: func(cmd *Command, args []string) {
- },
- }
- cmd.AddCommand(first)
-
- second := &Command{
- Use: "second",
- Run: func(cmd *Command, args []string) {
- fmt.Fprintf(cmd.OutOrStdout(), "%v", args)
- },
- }
- first.AddCommand(second)
-
- result := simpleTester(cmd, "first", "second", "first", "third")
-
- expectedOutput := fmt.Sprint([]string{"first third"})
- if result.Output != expectedOutput {
- t.Errorf("exptected %v, got %v", expectedOutput, result.Output)
- }
-}
-
-func TestPersistentFlags(t *testing.T) {
- fullSetupTest("echo", "-s", "something", "-p", "more", "here")
-
- // persistentFlag should act like normal flag on its own command
- if strings.Join(te, " ") != "more here" {
- t.Errorf("flags didn't leave proper args remaining..%s given", te)
- }
- if flags1 != "something" {
- t.Errorf("string flag didn't get correct value, had %v", flags1)
- }
- if !flagbp {
- t.Errorf("persistent bool flag not parsed correctly. Expected true, had %v", flagbp)
- }
-
- // persistentFlag should act like normal flag on its own command
- fullSetupTest("echo", "times", "-s", "again", "-c", "-p", "one", "two")
-
- if strings.Join(tt, " ") != "one two" {
- t.Errorf("flags didn't leave proper args remaining. %s given", tt)
- }
-
- if flags1 != "again" {
- t.Errorf("string flag didn't get correct value, had %v", flags1)
- }
-
- if !flagb2 {
- t.Errorf("local flag not parsed correctly. Expected true, had %v", flagb2)
- }
- if !flagbp {
- t.Errorf("persistent bool flag not parsed correctly. Expected true, had %v", flagbp)
- }
-}
-
-func TestHelpCommand(t *testing.T) {
- x := fullSetupTest("help")
- checkResultContains(t, x, cmdRootWithRun.Long)
-
- x = fullSetupTest("help", "echo")
- checkResultContains(t, x, cmdEcho.Long)
-
- x = fullSetupTest("help", "echo", "times")
- checkResultContains(t, x, cmdTimes.Long)
-}
-
-func TestChildCommandHelp(t *testing.T) {
- c := noRRSetupTest("print", "--help")
- checkResultContains(t, c, strtwoParentHelp)
- r := noRRSetupTest("echo", "times", "--help")
- checkResultContains(t, r, strtwoChildHelp)
-}
-
-func TestNonRunChildHelp(t *testing.T) {
- x := noRRSetupTest("subnorun")
- checkResultContains(t, x, cmdSubNoRun.Long)
-}
-
-func TestRunnableRootCommand(t *testing.T) {
- x := fullSetupTest("")
-
- if !rootcalled {
- t.Errorf("Root Function was not called\n out:%v", x.Error)
- }
-}
-
-func TestVisitParents(t *testing.T) {
- c := &Command{Use: "app"}
- sub := &Command{Use: "sub"}
- dsub := &Command{Use: "dsub"}
- sub.AddCommand(dsub)
- c.AddCommand(sub)
- total := 0
- add := func(x *Command) {
- total++
- }
- sub.VisitParents(add)
- if total != 1 {
- t.Errorf("Should have visited 1 parent but visited %d", total)
- }
-
- total = 0
- dsub.VisitParents(add)
- if total != 2 {
- t.Errorf("Should have visited 2 parent but visited %d", total)
- }
-
- total = 0
- c.VisitParents(add)
- if total != 0 {
- t.Errorf("Should have not visited any parent but visited %d", total)
- }
-}
-
-func TestRunnableRootCommandNilInput(t *testing.T) {
- c := initializeWithRootCmd()
-
- buf := new(bytes.Buffer)
- // Testing flag with invalid input
- c.SetOutput(buf)
- cmdEcho.AddCommand(cmdTimes)
- c.AddCommand(cmdPrint, cmdEcho)
- c.SetArgs([]string{})
-
- err := c.Execute()
- if err != nil {
- t.Errorf("Execute() failed with %v", err)
- }
-
- if !rootcalled {
- t.Errorf("Root Function was not called")
- }
-}
-
-func TestRunnableRootCommandEmptyInput(t *testing.T) {
- args := []string{"", "--introot=12", ""}
- c := initializeWithRootCmd()
-
- buf := new(bytes.Buffer)
- // Testing flag with invalid input
- c.SetOutput(buf)
- cmdEcho.AddCommand(cmdTimes)
- c.AddCommand(cmdPrint, cmdEcho)
- c.SetArgs(args)
-
- c.Execute()
-
- if !rootcalled {
- t.Errorf("Root Function was not called.\nOutput was:\n%s\n", buf)
- }
-}
-
-func TestInvalidSubcommandWhenArgsAllowed(t *testing.T) {
- fullSetupTest("echo", "invalid-sub")
-
- if te[0] != "invalid-sub" {
- t.Errorf("Subcommand didn't work...")
- }
-}
-
-func TestRootFlags(t *testing.T) {
- fullSetupTest("-i", "17", "-b")
-
- if !flagbr {
- t.Errorf("flag value should be true, %v given", flagbr)
- }
-
- if flagir != 17 {
- t.Errorf("flag value should be 17, %d given", flagir)
- }
-}
-
-func TestRootHelp(t *testing.T) {
- x := fullSetupTest("--help")
-
- checkResultContains(t, x, "Available Commands:")
- checkResultContains(t, x, "for more information about a command")
-
- if strings.Contains(x.Output, "unknown flag: --help") {
- t.Errorf("--help shouldn't trigger an error, Got: \n %s", x.Output)
- }
-
- if strings.Contains(x.Output, cmdEcho.Use) {
- t.Errorf("--help shouldn't display subcommand's usage, Got: \n %s", x.Output)
- }
-
- x = fullSetupTest("echo", "--help")
-
- if strings.Contains(x.Output, cmdTimes.Use) {
- t.Errorf("--help shouldn't display subsubcommand's usage, Got: \n %s", x.Output)
- }
-
- checkResultContains(t, x, "Available Commands:")
- checkResultContains(t, x, "for more information about a command")
-
- if strings.Contains(x.Output, "unknown flag: --help") {
- t.Errorf("--help shouldn't trigger an error, Got: \n %s", x.Output)
- }
-
-}
-
-func TestFlagAccess(t *testing.T) {
- initialize()
-
- local := cmdTimes.LocalFlags()
- inherited := cmdTimes.InheritedFlags()
-
- for _, f := range []string{"inttwo", "strtwo", "booltwo"} {
- if local.Lookup(f) == nil {
- t.Errorf("LocalFlags expected to contain %s, Got: nil", f)
- }
- }
- if inherited.Lookup("strone") == nil {
- t.Errorf("InheritedFlags expected to contain strone, Got: nil")
- }
- if inherited.Lookup("strtwo") != nil {
- t.Errorf("InheritedFlags shouldn not contain overwritten flag strtwo")
- }
-}
-
-func TestNoNRunnableRootCommandNilInput(t *testing.T) {
- c := initialize()
-
- buf := new(bytes.Buffer)
- // Testing flag with invalid input
- c.SetOutput(buf)
- cmdEcho.AddCommand(cmdTimes)
- c.AddCommand(cmdPrint, cmdEcho)
- c.SetArgs([]string{})
-
- c.Execute()
-
- if !strings.Contains(buf.String(), cmdRootNoRun.Long) {
- t.Errorf("Expected to get help output, Got: \n %s", buf)
- }
-}
-
-func TestRootNoCommandHelp(t *testing.T) {
- x := rootOnlySetupTest("--help")
-
- checkResultOmits(t, x, "Available Commands:")
- checkResultOmits(t, x, "for more information about a command")
-
- if strings.Contains(x.Output, "unknown flag: --help") {
- t.Errorf("--help shouldn't trigger an error, Got: \n %s", x.Output)
- }
-
- x = rootOnlySetupTest("echo", "--help")
-
- checkResultOmits(t, x, "Available Commands:")
- checkResultOmits(t, x, "for more information about a command")
-
- if strings.Contains(x.Output, "unknown flag: --help") {
- t.Errorf("--help shouldn't trigger an error, Got: \n %s", x.Output)
- }
-}
-
-func TestRootUnknownCommand(t *testing.T) {
- r := noRRSetupTest("bogus")
- s := "Error: unknown command \"bogus\" for \"cobra-test\"\nRun 'cobra-test --help' for usage.\n"
-
- if r.Output != s {
- t.Errorf("Unexpected response.\nExpecting to be:\n %q\nGot:\n %q\n", s, r.Output)
- }
-
- r = noRRSetupTest("--strtwo=a", "bogus")
- if r.Output != s {
- t.Errorf("Unexpected response.\nExpecting to be:\n %q\nGot:\n %q\n", s, r.Output)
- }
-}
-
-func TestRootUnknownCommandSilenced(t *testing.T) {
- r := noRRSetupTestSilenced("bogus")
-
- if r.Output != "" {
- t.Errorf("Unexpected response.\nExpecting to be: \n\"\"\n Got:\n %q\n", r.Output)
- }
-
- r = noRRSetupTestSilenced("--strtwo=a", "bogus")
- if r.Output != "" {
- t.Errorf("Unexpected response.\nExpecting to be:\n\"\"\nGot:\n %q\n", r.Output)
- }
-}
-
-func TestRootSuggestions(t *testing.T) {
- outputWithSuggestions := "Error: unknown command \"%s\" for \"cobra-test\"\n\nDid you mean this?\n\t%s\n\nRun 'cobra-test --help' for usage.\n"
- outputWithoutSuggestions := "Error: unknown command \"%s\" for \"cobra-test\"\nRun 'cobra-test --help' for usage.\n"
-
- cmd := initializeWithRootCmd()
- cmd.AddCommand(cmdTimes)
-
- tests := map[string]string{
- "time": "times",
- "tiems": "times",
- "tims": "times",
- "timeS": "times",
- "rimes": "times",
- "ti": "times",
- "t": "times",
- "timely": "times",
- "ri": "",
- "timezone": "",
- "foo": "",
- "counts": "times",
- }
-
- for typo, suggestion := range tests {
- for _, suggestionsDisabled := range []bool{false, true} {
- cmd.DisableSuggestions = suggestionsDisabled
- result := simpleTester(cmd, typo)
- expected := ""
- if len(suggestion) == 0 || suggestionsDisabled {
- expected = fmt.Sprintf(outputWithoutSuggestions, typo)
- } else {
- expected = fmt.Sprintf(outputWithSuggestions, typo, suggestion)
- }
- if result.Output != expected {
- t.Errorf("Unexpected response.\nExpecting to be:\n %q\nGot:\n %q\n", expected, result.Output)
- }
- }
- }
-}
-
-func TestFlagsBeforeCommand(t *testing.T) {
- // short without space
- x := fullSetupTest("-i10", "echo")
- if x.Error != nil {
- t.Errorf("Valid Input shouldn't have errors, got:\n %q", x.Error)
- }
-
- x = noRRSetupTest("echo", "-i=10")
- if x.Error != nil {
- t.Errorf("Valid Input shouldn't have errors, got:\n %s", x.Error)
- }
-
- // long with equals
- x = noRRSetupTest("--intone=123", "echo", "one", "two")
- if x.Error != nil {
- t.Errorf("Valid Input shouldn't have errors, got:\n %s", x.Error)
- }
-
- // With parsing error properly reported
- x = fullSetupTest("-i10E", "echo")
- if !strings.Contains(x.Error.Error(), "invalid syntax") {
- t.Errorf("Wrong error message displayed, \n %s", x.Error)
- }
-}
-
-func TestRemoveCommand(t *testing.T) {
- versionUsed = 0
- c := initializeWithRootCmd()
- c.AddCommand(cmdVersion1)
- c.RemoveCommand(cmdVersion1)
- x := fullTester(c, "version")
- if x.Error == nil {
- t.Errorf("Removed command should not have been called\n")
- return
- }
-}
-
-func TestCommandWithoutSubcommands(t *testing.T) {
- c := initializeWithRootCmd()
-
- x := simpleTester(c, "")
- if x.Error != nil {
- t.Errorf("Calling command without subcommands should not have error: %v", x.Error)
- return
- }
-}
-
-func TestCommandWithoutSubcommandsWithArg(t *testing.T) {
- c := initializeWithRootCmd()
- expectedArgs := []string{"arg"}
-
- x := simpleTester(c, "arg")
- if x.Error != nil {
- t.Errorf("Calling command without subcommands but with arg should not have error: %v", x.Error)
- return
- }
- if !reflect.DeepEqual(expectedArgs, tr) {
- t.Errorf("Calling command without subcommands but with arg has wrong args: expected: %v, actual: %v", expectedArgs, tr)
- return
- }
-}
-
-func TestReplaceCommandWithRemove(t *testing.T) {
- versionUsed = 0
- c := initializeWithRootCmd()
- c.AddCommand(cmdVersion1)
- c.RemoveCommand(cmdVersion1)
- c.AddCommand(cmdVersion2)
- x := fullTester(c, "version")
- if x.Error != nil {
- t.Errorf("Valid Input shouldn't have errors, got:\n %q", x.Error)
- return
- }
- if versionUsed == 1 {
- t.Errorf("Removed command shouldn't be called\n")
- }
- if versionUsed != 2 {
- t.Errorf("Replacing command should have been called but didn't\n")
- }
-}
-
-func TestDeprecatedSub(t *testing.T) {
- c := fullSetupTest("deprecated")
-
- checkResultContains(t, c, cmdDeprecated.Deprecated)
-}
-
-func TestPreRun(t *testing.T) {
- noRRSetupTest("echo", "one", "two")
- if echoPre == nil || echoPersPre == nil {
- t.Error("PreRun or PersistentPreRun not called")
- }
- if rootPersPre != nil || timesPersPre != nil {
- t.Error("Wrong *Pre functions called!")
- }
-
- noRRSetupTest("echo", "times", "one", "two")
- if timesPersPre == nil {
- t.Error("PreRun or PersistentPreRun not called")
- }
- if echoPre != nil || echoPersPre != nil || rootPersPre != nil {
- t.Error("Wrong *Pre functions called!")
- }
-
- noRRSetupTest("print", "one", "two")
- if rootPersPre == nil {
- t.Error("Parent PersistentPreRun not called but should not have been")
- }
- if echoPre != nil || echoPersPre != nil || timesPersPre != nil {
- t.Error("Wrong *Pre functions called!")
- }
-}
-
-// Check if cmdEchoSub gets PersistentPreRun from rootCmd even if is added last
-func TestPeristentPreRunPropagation(t *testing.T) {
- rootCmd := initialize()
-
- // First add the cmdEchoSub to cmdPrint
- cmdPrint.AddCommand(cmdEchoSub)
- // Now add cmdPrint to rootCmd
- rootCmd.AddCommand(cmdPrint)
-
- rootCmd.SetArgs([]string{"print", "echosub", "lala"})
- rootCmd.Execute()
-
- if len(rootPersPre) == 0 || rootPersPre[0] != "lala" {
- t.Error("RootCmd PersistentPreRun not called but should have been")
- }
-}
-
-func TestGlobalNormFuncPropagation(t *testing.T) {
- normFunc := func(f *pflag.FlagSet, name string) pflag.NormalizedName {
- return pflag.NormalizedName(name)
- }
-
- rootCmd := initialize()
- rootCmd.SetGlobalNormalizationFunc(normFunc)
- if reflect.ValueOf(normFunc).Pointer() != reflect.ValueOf(rootCmd.GlobalNormalizationFunc()).Pointer() {
- t.Error("rootCmd seems to have a wrong normalization function")
- }
-
- // First add the cmdEchoSub to cmdPrint
- cmdPrint.AddCommand(cmdEchoSub)
- if cmdPrint.GlobalNormalizationFunc() != nil && cmdEchoSub.GlobalNormalizationFunc() != nil {
- t.Error("cmdPrint and cmdEchoSub should had no normalization functions")
- }
-
- // Now add cmdPrint to rootCmd
- rootCmd.AddCommand(cmdPrint)
- if reflect.ValueOf(cmdPrint.GlobalNormalizationFunc()).Pointer() != reflect.ValueOf(rootCmd.GlobalNormalizationFunc()).Pointer() ||
- reflect.ValueOf(cmdEchoSub.GlobalNormalizationFunc()).Pointer() != reflect.ValueOf(rootCmd.GlobalNormalizationFunc()).Pointer() {
- t.Error("cmdPrint and cmdEchoSub should had the normalization function of rootCmd")
- }
-}
-
-func TestFlagOnPflagCommandLine(t *testing.T) {
- flagName := "flagOnCommandLine"
- pflag.String(flagName, "", "about my flag")
- r := fullSetupTest("--help")
-
- checkResultContains(t, r, flagName)
-
- // Reset pflag.CommandLine flagset.
- pflag.CommandLine = pflag.NewFlagSet(os.Args[0], pflag.ExitOnError)
-}
-
func TestAddTemplateFunctions(t *testing.T) {
AddTemplateFunc("t", func() bool { return true })
AddTemplateFuncs(template.FuncMap{
@@ -1202,43 +12,11 @@ func TestAddTemplateFunctions(t *testing.T) {
"h": func() string { return "Hello," },
"w": func() string { return "world." }})
- const usage = "Hello, world."
-
c := &Command{}
c.SetUsageTemplate(`{{if t}}{{h}}{{end}}{{if f}}{{h}}{{end}} {{w}}`)
- if us := c.UsageString(); us != usage {
- t.Errorf("c.UsageString() != \"%s\", is \"%s\"", usage, us)
- }
-}
-
-func TestUsageIsNotPrintedTwice(t *testing.T) {
- var cmd = &Command{Use: "root"}
- var sub = &Command{Use: "sub"}
- cmd.AddCommand(sub)
-
- r := simpleTester(cmd, "")
- if strings.Count(r.Output, "Usage:") != 1 {
- t.Error("Usage output is not printed exactly once")
- }
-}
-
-func BenchmarkInheritedFlags(b *testing.B) {
- initialize()
- cmdEcho.AddCommand(cmdTimes)
- b.ResetTimer()
-
- for i := 0; i < b.N; i++ {
- cmdTimes.InheritedFlags()
- }
-}
-
-func BenchmarkLocalFlags(b *testing.B) {
- initialize()
- cmdEcho.AddCommand(cmdTimes)
- b.ResetTimer()
-
- for i := 0; i < b.N; i++ {
- cmdTimes.LocalFlags()
+ const expected = "Hello, world."
+ if got := c.UsageString(); got != expected {
+ t.Errorf("Expected UsageString: %v\nGot: %v", expected, got)
}
}
diff --git a/vendor/github.com/spf13/cobra/command.go b/vendor/github.com/spf13/cobra/command.go
index 185e45263..6cb642647 100644
--- a/vendor/github.com/spf13/cobra/command.go
+++ b/vendor/github.com/spf13/cobra/command.go
@@ -125,8 +125,9 @@ type Command struct {
// Must be > 0.
SuggestionsMinimumDistance int
- // name is the command name, usually the executable's name.
- name string
+ // TraverseChildren parses flags on all parents before executing child command.
+ TraverseChildren bool
+
// commands is the list of commands supported by this program.
commands []*Command
// parent is a parent command for this command.
@@ -475,13 +476,14 @@ func argsMinusFirstX(args []string, x string) []string {
return args
}
+func isFlagArg(arg string) bool {
+ return ((len(arg) >= 3 && arg[1] == '-') ||
+ (len(arg) >= 2 && arg[0] == '-' && arg[1] != '-'))
+}
+
// Find the target command given the args and command tree
// Meant to be run on the highest node. Only searches down.
func (c *Command) Find(args []string) (*Command, []string, error) {
- if c == nil {
- return nil, nil, fmt.Errorf("Called find() on a nil Command")
- }
-
var innerfind func(*Command, []string) (*Command, []string)
innerfind = func(c *Command, innerArgs []string) (*Command, []string) {
@@ -490,28 +492,11 @@ func (c *Command) Find(args []string) (*Command, []string, error) {
return c, innerArgs
}
nextSubCmd := argsWOflags[0]
- matches := make([]*Command, 0)
- for _, cmd := range c.commands {
- if cmd.Name() == nextSubCmd || cmd.HasAlias(nextSubCmd) { // exact name or alias match
- return innerfind(cmd, argsMinusFirstX(innerArgs, nextSubCmd))
- }
- if EnablePrefixMatching {
- if strings.HasPrefix(cmd.Name(), nextSubCmd) { // prefix match
- matches = append(matches, cmd)
- }
- for _, x := range cmd.Aliases {
- if strings.HasPrefix(x, nextSubCmd) {
- matches = append(matches, cmd)
- }
- }
- }
- }
- // only accept a single prefix match - multiple matches would be ambiguous
- if len(matches) == 1 {
- return innerfind(matches[0], argsMinusFirstX(innerArgs, argsWOflags[0]))
+ cmd := c.findNext(nextSubCmd)
+ if cmd != nil {
+ return innerfind(cmd, argsMinusFirstX(innerArgs, nextSubCmd))
}
-
return c, innerArgs
}
@@ -539,6 +524,66 @@ func (c *Command) findSuggestions(arg string) string {
return suggestionsString
}
+func (c *Command) findNext(next string) *Command {
+ matches := make([]*Command, 0)
+ for _, cmd := range c.commands {
+ if cmd.Name() == next || cmd.HasAlias(next) {
+ return cmd
+ }
+ if EnablePrefixMatching && cmd.hasNameOrAliasPrefix(next) {
+ matches = append(matches, cmd)
+ }
+ }
+
+ if len(matches) == 1 {
+ return matches[0]
+ }
+ return nil
+}
+
+// Traverse the command tree to find the command, and parse args for
+// each parent.
+func (c *Command) Traverse(args []string) (*Command, []string, error) {
+ flags := []string{}
+ inFlag := false
+
+ for i, arg := range args {
+ switch {
+ // A long flag with a space separated value
+ case strings.HasPrefix(arg, "--") && !strings.Contains(arg, "="):
+ // TODO: this isn't quite right, we should really check ahead for 'true' or 'false'
+ inFlag = !hasNoOptDefVal(arg[2:], c.Flags())
+ flags = append(flags, arg)
+ continue
+ // A short flag with a space separated value
+ case strings.HasPrefix(arg, "-") && !strings.Contains(arg, "=") && len(arg) == 2 && !shortHasNoOptDefVal(arg[1:], c.Flags()):
+ inFlag = true
+ flags = append(flags, arg)
+ continue
+ // The value for a flag
+ case inFlag:
+ inFlag = false
+ flags = append(flags, arg)
+ continue
+ // A flag without a value, or with an `=` separated value
+ case isFlagArg(arg):
+ flags = append(flags, arg)
+ continue
+ }
+
+ cmd := c.findNext(arg)
+ if cmd == nil {
+ return c, args, nil
+ }
+
+ if err := c.ParseFlags(flags); err != nil {
+ return nil, args, err
+ }
+ return cmd.Traverse(args[i+1:])
+ }
+ return c, args, nil
+}
+
// SuggestionsFor provides suggestions for the typedName.
func (c *Command) SuggestionsFor(typedName string) []string {
suggestions := []string{}
@@ -576,10 +621,8 @@ func (c *Command) Root() *Command {
return c
}
-// ArgsLenAtDash will return the length of f.Args at the moment when a -- was
-// found during arg parsing. This allows your program to know which args were
-// before the -- and which came after. (Description from
-// https://godoc.org/github.com/spf13/pflag#FlagSet.ArgsLenAtDash).
+// ArgsLenAtDash will return the length of c.Flags().Args at the moment
+// when a -- was found during args parsing.
func (c *Command) ArgsLenAtDash() int {
return c.Flags().ArgsLenAtDash()
}
@@ -646,6 +689,9 @@ func (c *Command) execute(a []string) (err error) {
c.PreRun(c, argWoFlags)
}
+ if err := c.validateRequiredFlags(); err != nil {
+ return err
+ }
if c.RunE != nil {
if err := c.RunE(c, argWoFlags); err != nil {
return err
@@ -714,7 +760,12 @@ func (c *Command) ExecuteC() (cmd *Command, err error) {
args = c.args
}
- cmd, flags, err := c.Find(args)
+ var flags []string
+ if c.TraverseChildren {
+ cmd, flags, err = c.Traverse(args)
+ } else {
+ cmd, flags, err = c.Find(args)
+ }
if err != nil {
// If found parse to a subcommand and then failed, talk about the subcommand
if cmd != nil {
@@ -726,6 +777,7 @@ func (c *Command) ExecuteC() (cmd *Command, err error) {
}
return c, err
}
+
err = cmd.execute(flags)
if err != nil {
// Always show help if requested, even if SilenceErrors is in
@@ -757,6 +809,25 @@ func (c *Command) ValidateArgs(args []string) error {
return c.Args(c, args)
}
+func (c *Command) validateRequiredFlags() error {
+ flags := c.Flags()
+ missingFlagNames := []string{}
+ flags.VisitAll(func(pflag *flag.Flag) {
+ requiredAnnotation, found := pflag.Annotations[BashCompOneRequiredFlag]
+ if !found {
+ return
+ }
+ if (requiredAnnotation[0] == "true") && !pflag.Changed {
+ missingFlagNames = append(missingFlagNames, pflag.Name)
+ }
+ })
+
+ if len(missingFlagNames) > 0 {
+ return fmt.Errorf(`Required flag(s) "%s" have/has not been set`, strings.Join(missingFlagNames, `", "`))
+ }
+ return nil
+}
+
// InitDefaultHelpFlag adds default help flag to c.
// It is called automatically by executing the c or by calling help and usage.
// If c already has help flag, it will do nothing.
@@ -804,8 +875,9 @@ Simply type ` + c.Name() + ` help [path to command] for full details.`,
c.AddCommand(c.helpCommand)
}
-// ResetCommands used for testing.
+// ResetCommands delete parent, subcommand and help command from c.
func (c *Command) ResetCommands() {
+ c.parent = nil
c.commands = nil
c.helpCommand = nil
c.parentsPflags = nil
@@ -971,15 +1043,12 @@ func (c *Command) DebugFlags() {
// Name returns the command's name: the first word in the use line.
func (c *Command) Name() string {
- if c.name == "" {
- name := c.Use
- i := strings.Index(name, " ")
- if i >= 0 {
- name = name[:i]
- }
- c.name = name
+ name := c.Use
+ i := strings.Index(name, " ")
+ if i >= 0 {
+ name = name[:i]
}
- return c.name
+ return name
}
// HasAlias determines if a given string is an alias of the command.
@@ -992,7 +1061,21 @@ func (c *Command) HasAlias(s string) bool {
return false
}
-// NameAndAliases returns string containing name and all aliases
+// hasNameOrAliasPrefix returns true if the Name or any of aliases start
+// with prefix
+func (c *Command) hasNameOrAliasPrefix(prefix string) bool {
+ if strings.HasPrefix(c.Name(), prefix) {
+ return true
+ }
+ for _, alias := range c.Aliases {
+ if strings.HasPrefix(alias, prefix) {
+ return true
+ }
+ }
+ return false
+}
+
+// NameAndAliases returns a list of the command name and all aliases
func (c *Command) NameAndAliases() string {
return strings.Join(append([]string{c.Name()}, c.Aliases...), ", ")
}
@@ -1078,7 +1161,7 @@ func (c *Command) HasAvailableSubCommands() bool {
}
}
- // the command either has no sub comamnds, or no available (non deprecated/help/hidden)
+ // the command either has no sub commands, or no available (non deprecated/help/hidden)
// sub commands
return false
}
@@ -1132,6 +1215,9 @@ func (c *Command) LocalFlags() *flag.FlagSet {
c.lflags.SetOutput(c.flagErrorBuf)
}
c.lflags.SortFlags = c.Flags().SortFlags
+ if c.globNormFunc != nil {
+ c.lflags.SetNormalizeFunc(c.globNormFunc)
+ }
addToLocal := func(f *flag.Flag) {
if c.lflags.Lookup(f.Name) == nil && c.parentsPflags.Lookup(f.Name) == nil {
@@ -1156,6 +1242,10 @@ func (c *Command) InheritedFlags() *flag.FlagSet {
}
local := c.LocalFlags()
+ if c.globNormFunc != nil {
+ c.iflags.SetNormalizeFunc(c.globNormFunc)
+ }
+
c.parentsPflags.VisitAll(func(f *flag.Flag) {
if c.iflags.Lookup(f.Name) == nil && local.Lookup(f.Name) == nil {
c.iflags.AddFlag(f)
@@ -1181,7 +1271,7 @@ func (c *Command) PersistentFlags() *flag.FlagSet {
return c.pflags
}
-// ResetFlags is used in testing.
+// ResetFlags deletes all flags from command.
func (c *Command) ResetFlags() {
c.flagErrorBuf = new(bytes.Buffer)
c.flagErrorBuf.Reset()
@@ -1189,6 +1279,10 @@ func (c *Command) ResetFlags() {
c.flags.SetOutput(c.flagErrorBuf)
c.pflags = flag.NewFlagSet(c.Name(), flag.ContinueOnError)
c.pflags.SetOutput(c.flagErrorBuf)
+
+ c.lflags = nil
+ c.iflags = nil
+ c.parentsPflags = nil
}
// HasFlags checks if the command contains any flags (local plus persistent from the entire structure).
@@ -1264,6 +1358,9 @@ func (c *Command) ParseFlags(args []string) error {
return nil
}
+ if c.flagErrorBuf == nil {
+ c.flagErrorBuf = new(bytes.Buffer)
+ }
beforeErrorBufLen := c.flagErrorBuf.Len()
c.mergePersistentFlags()
err := c.Flags().Parse(args)
@@ -1298,6 +1395,10 @@ func (c *Command) updateParentsPflags() {
c.parentsPflags.SortFlags = false
}
+ if c.globNormFunc != nil {
+ c.parentsPflags.SetNormalizeFunc(c.globNormFunc)
+ }
+
c.Root().PersistentFlags().AddFlagSet(flag.CommandLine)
c.VisitParents(func(parent *Command) {
diff --git a/vendor/github.com/spf13/cobra/command_test.go b/vendor/github.com/spf13/cobra/command_test.go
index aa6658f85..edffc1501 100644
--- a/vendor/github.com/spf13/cobra/command_test.go
+++ b/vendor/github.com/spf13/cobra/command_test.go
@@ -11,27 +11,450 @@ import (
"github.com/spf13/pflag"
)
-// test to ensure hidden commands run as intended
-func TestHiddenCommandExecutes(t *testing.T) {
+func emptyRun(*Command, []string) {}
+
+func executeCommand(root *Command, args ...string) (output string, err error) {
+ _, output, err = executeCommandC(root, args...)
+ return output, err
+}
+
+func executeCommandC(root *Command, args ...string) (c *Command, output string, err error) {
+ buf := new(bytes.Buffer)
+ root.SetOutput(buf)
+ root.SetArgs(args)
+
+ c, err = root.ExecuteC()
+
+ return c, buf.String(), err
+}
+
+func resetCommandLineFlagSet() {
+ pflag.CommandLine = pflag.NewFlagSet(os.Args[0], pflag.ExitOnError)
+}
+
+func checkStringContains(t *testing.T, got, expected string) {
+ if !strings.Contains(got, expected) {
+ t.Errorf("Expected to contain: \n %v\nGot:\n %v\n", expected, got)
+ }
+}
+
+func checkStringOmits(t *testing.T, got, expected string) {
+ if strings.Contains(got, expected) {
+ t.Errorf("Expected to not contain: \n %v\nGot: %v", expected, got)
+ }
+}
- // ensure that outs does not already equal what the command will be setting it
- // to, if it did this test would not actually be testing anything...
- if outs == "hidden" {
- t.Errorf("outs should NOT EQUAL hidden")
+func TestSingleCommand(t *testing.T) {
+ var rootCmdArgs []string
+ rootCmd := &Command{
+ Use: "root",
+ Args: ExactArgs(2),
+ Run: func(_ *Command, args []string) { rootCmdArgs = args },
}
+ aCmd := &Command{Use: "a", Args: NoArgs, Run: emptyRun}
+ bCmd := &Command{Use: "b", Args: NoArgs, Run: emptyRun}
+ rootCmd.AddCommand(aCmd, bCmd)
- cmdHidden.Execute()
+ output, err := executeCommand(rootCmd, "one", "two")
+ if output != "" {
+ t.Errorf("Unexpected output: %v", output)
+ }
+ if err != nil {
+ t.Errorf("Unexpected error: %v", err)
+ }
- // upon running the command, the value of outs should now be 'hidden'
- if outs != "hidden" {
- t.Errorf("Hidden command failed to run!")
+ got := strings.Join(rootCmdArgs, " ")
+ expected := "one two"
+ if got != expected {
+ t.Errorf("rootCmdArgs expected: %q, got: %q", expected, got)
}
}
-// test to ensure hidden commands do not show up in usage/help text
-func TestHiddenCommandIsHidden(t *testing.T) {
- if cmdHidden.IsAvailableCommand() {
- t.Errorf("Hidden command found!")
+func TestChildCommand(t *testing.T) {
+ var child1CmdArgs []string
+ rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun}
+ child1Cmd := &Command{
+ Use: "child1",
+ Args: ExactArgs(2),
+ Run: func(_ *Command, args []string) { child1CmdArgs = args },
+ }
+ child2Cmd := &Command{Use: "child2", Args: NoArgs, Run: emptyRun}
+ rootCmd.AddCommand(child1Cmd, child2Cmd)
+
+ output, err := executeCommand(rootCmd, "child1", "one", "two")
+ if output != "" {
+ t.Errorf("Unexpected output: %v", output)
+ }
+ if err != nil {
+ t.Errorf("Unexpected error: %v", err)
+ }
+
+ got := strings.Join(child1CmdArgs, " ")
+ expected := "one two"
+ if got != expected {
+ t.Errorf("child1CmdArgs expected: %q, got: %q", expected, got)
+ }
+}
+
+func TestCallCommandWithoutSubcommands(t *testing.T) {
+ rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun}
+ _, err := executeCommand(rootCmd)
+ if err != nil {
+ t.Errorf("Calling command without subcommands should not have error: %v", err)
+ }
+}
+
+func TestRootExecuteUnknownCommand(t *testing.T) {
+ rootCmd := &Command{Use: "root", Run: emptyRun}
+ rootCmd.AddCommand(&Command{Use: "child", Run: emptyRun})
+
+ output, _ := executeCommand(rootCmd, "unknown")
+
+ expected := "Error: unknown command \"unknown\" for \"root\"\nRun 'root --help' for usage.\n"
+
+ if output != expected {
+ t.Errorf("Expected:\n %q\nGot:\n %q\n", expected, output)
+ }
+}
+
+func TestSubcommandExecuteC(t *testing.T) {
+ rootCmd := &Command{Use: "root", Run: emptyRun}
+ childCmd := &Command{Use: "child", Run: emptyRun}
+ rootCmd.AddCommand(childCmd)
+
+ c, output, err := executeCommandC(rootCmd, "child")
+ if output != "" {
+ t.Errorf("Unexpected output: %v", output)
+ }
+ if err != nil {
+ t.Errorf("Unexpected error: %v", err)
+ }
+
+ if c.Name() != "child" {
+ t.Errorf(`invalid command returned from ExecuteC: expected "child"', got %q`, c.Name())
+ }
+}
+
+func TestRootUnknownCommandSilenced(t *testing.T) {
+ rootCmd := &Command{Use: "root", Run: emptyRun}
+ rootCmd.SilenceErrors = true
+ rootCmd.SilenceUsage = true
+ rootCmd.AddCommand(&Command{Use: "child", Run: emptyRun})
+
+ output, _ := executeCommand(rootCmd, "unknown")
+ if output != "" {
+ t.Errorf("Expected blank output, because of silenced usage.\nGot:\n %q\n", output)
+ }
+}
+
+func TestCommandAlias(t *testing.T) {
+ var timesCmdArgs []string
+ rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun}
+ echoCmd := &Command{
+ Use: "echo",
+ Aliases: []string{"say", "tell"},
+ Args: NoArgs,
+ Run: emptyRun,
+ }
+ timesCmd := &Command{
+ Use: "times",
+ Args: ExactArgs(2),
+ Run: func(_ *Command, args []string) { timesCmdArgs = args },
+ }
+ echoCmd.AddCommand(timesCmd)
+ rootCmd.AddCommand(echoCmd)
+
+ output, err := executeCommand(rootCmd, "tell", "times", "one", "two")
+ if output != "" {
+ t.Errorf("Unexpected output: %v", output)
+ }
+ if err != nil {
+ t.Errorf("Unexpected error: %v", err)
+ }
+
+ got := strings.Join(timesCmdArgs, " ")
+ expected := "one two"
+ if got != expected {
+ t.Errorf("timesCmdArgs expected: %v, got: %v", expected, got)
+ }
+}
+
+func TestEnablePrefixMatching(t *testing.T) {
+ EnablePrefixMatching = true
+
+ var aCmdArgs []string
+ rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun}
+ aCmd := &Command{
+ Use: "aCmd",
+ Args: ExactArgs(2),
+ Run: func(_ *Command, args []string) { aCmdArgs = args },
+ }
+ bCmd := &Command{Use: "bCmd", Args: NoArgs, Run: emptyRun}
+ rootCmd.AddCommand(aCmd, bCmd)
+
+ output, err := executeCommand(rootCmd, "a", "one", "two")
+ if output != "" {
+ t.Errorf("Unexpected output: %v", output)
+ }
+ if err != nil {
+ t.Errorf("Unexpected error: %v", err)
+ }
+
+ got := strings.Join(aCmdArgs, " ")
+ expected := "one two"
+ if got != expected {
+ t.Errorf("aCmdArgs expected: %q, got: %q", expected, got)
+ }
+
+ EnablePrefixMatching = false
+}
+
+func TestAliasPrefixMatching(t *testing.T) {
+ EnablePrefixMatching = true
+
+ var timesCmdArgs []string
+ rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun}
+ echoCmd := &Command{
+ Use: "echo",
+ Aliases: []string{"say", "tell"},
+ Args: NoArgs,
+ Run: emptyRun,
+ }
+ timesCmd := &Command{
+ Use: "times",
+ Args: ExactArgs(2),
+ Run: func(_ *Command, args []string) { timesCmdArgs = args },
+ }
+ echoCmd.AddCommand(timesCmd)
+ rootCmd.AddCommand(echoCmd)
+
+ output, err := executeCommand(rootCmd, "sa", "times", "one", "two")
+ if output != "" {
+ t.Errorf("Unexpected output: %v", output)
+ }
+ if err != nil {
+ t.Errorf("Unexpected error: %v", err)
+ }
+
+ got := strings.Join(timesCmdArgs, " ")
+ expected := "one two"
+ if got != expected {
+ t.Errorf("timesCmdArgs expected: %v, got: %v", expected, got)
+ }
+
+ EnablePrefixMatching = false
+}
+
+// TestChildSameName checks the correct behaviour of cobra in cases,
+// when an application with name "foo" and with subcommand "foo"
+// is executed with args "foo foo".
+func TestChildSameName(t *testing.T) {
+ var fooCmdArgs []string
+ rootCmd := &Command{Use: "foo", Args: NoArgs, Run: emptyRun}
+ fooCmd := &Command{
+ Use: "foo",
+ Args: ExactArgs(2),
+ Run: func(_ *Command, args []string) { fooCmdArgs = args },
+ }
+ barCmd := &Command{Use: "bar", Args: NoArgs, Run: emptyRun}
+ rootCmd.AddCommand(fooCmd, barCmd)
+
+ output, err := executeCommand(rootCmd, "foo", "one", "two")
+ if output != "" {
+ t.Errorf("Unexpected output: %v", output)
+ }
+ if err != nil {
+ t.Errorf("Unexpected error: %v", err)
+ }
+
+ got := strings.Join(fooCmdArgs, " ")
+ expected := "one two"
+ if got != expected {
+ t.Errorf("fooCmdArgs expected: %v, got: %v", expected, got)
+ }
+}
+
+// TestGrandChildSameName checks the correct behaviour of cobra in cases,
+// when user has a root command and a grand child
+// with the same name.
+func TestGrandChildSameName(t *testing.T) {
+ var fooCmdArgs []string
+ rootCmd := &Command{Use: "foo", Args: NoArgs, Run: emptyRun}
+ barCmd := &Command{Use: "bar", Args: NoArgs, Run: emptyRun}
+ fooCmd := &Command{
+ Use: "foo",
+ Args: ExactArgs(2),
+ Run: func(_ *Command, args []string) { fooCmdArgs = args },
+ }
+ barCmd.AddCommand(fooCmd)
+ rootCmd.AddCommand(barCmd)
+
+ output, err := executeCommand(rootCmd, "bar", "foo", "one", "two")
+ if output != "" {
+ t.Errorf("Unexpected output: %v", output)
+ }
+ if err != nil {
+ t.Errorf("Unexpected error: %v", err)
+ }
+
+ got := strings.Join(fooCmdArgs, " ")
+ expected := "one two"
+ if got != expected {
+ t.Errorf("fooCmdArgs expected: %v, got: %v", expected, got)
+ }
+}
+
+func TestFlagLong(t *testing.T) {
+ var cArgs []string
+ c := &Command{
+ Use: "c",
+ Args: ArbitraryArgs,
+ Run: func(_ *Command, args []string) { cArgs = args },
+ }
+
+ var intFlagValue int
+ var stringFlagValue string
+ c.Flags().IntVar(&intFlagValue, "intf", -1, "")
+ c.Flags().StringVar(&stringFlagValue, "sf", "", "")
+
+ output, err := executeCommand(c, "--intf=7", "--sf=abc", "one", "--", "two")
+ if output != "" {
+ t.Errorf("Unexpected output: %v", err)
+ }
+ if err != nil {
+ t.Errorf("Unexpected error: %v", err)
+ }
+
+ if c.ArgsLenAtDash() != 1 {
+ t.Errorf("Expected ArgsLenAtDash: %v but got %v", 1, c.ArgsLenAtDash())
+ }
+ if intFlagValue != 7 {
+ t.Errorf("Expected intFlagValue: %v, got %v", 7, intFlagValue)
+ }
+ if stringFlagValue != "abc" {
+ t.Errorf("Expected stringFlagValue: %q, got %q", "abc", stringFlagValue)
+ }
+
+ got := strings.Join(cArgs, " ")
+ expected := "one two"
+ if got != expected {
+ t.Errorf("Expected arguments: %q, got %q", expected, got)
+ }
+}
+
+func TestFlagShort(t *testing.T) {
+ var cArgs []string
+ c := &Command{
+ Use: "c",
+ Args: ArbitraryArgs,
+ Run: func(_ *Command, args []string) { cArgs = args },
+ }
+
+ var intFlagValue int
+ var stringFlagValue string
+ c.Flags().IntVarP(&intFlagValue, "intf", "i", -1, "")
+ c.Flags().StringVarP(&stringFlagValue, "sf", "s", "", "")
+
+ output, err := executeCommand(c, "-i", "7", "-sabc", "one", "two")
+ if output != "" {
+ t.Errorf("Unexpected output: %v", err)
+ }
+ if err != nil {
+ t.Errorf("Unexpected error: %v", err)
+ }
+
+ if intFlagValue != 7 {
+ t.Errorf("Expected flag value: %v, got %v", 7, intFlagValue)
+ }
+ if stringFlagValue != "abc" {
+ t.Errorf("Expected stringFlagValue: %q, got %q", "abc", stringFlagValue)
+ }
+
+ got := strings.Join(cArgs, " ")
+ expected := "one two"
+ if got != expected {
+ t.Errorf("Expected arguments: %q, got %q", expected, got)
+ }
+}
+
+func TestChildFlag(t *testing.T) {
+ rootCmd := &Command{Use: "root", Run: emptyRun}
+ childCmd := &Command{Use: "child", Run: emptyRun}
+ rootCmd.AddCommand(childCmd)
+
+ var intFlagValue int
+ childCmd.Flags().IntVarP(&intFlagValue, "intf", "i", -1, "")
+
+ output, err := executeCommand(rootCmd, "child", "-i7")
+ if output != "" {
+ t.Errorf("Unexpected output: %v", err)
+ }
+ if err != nil {
+ t.Errorf("Unexpected error: %v", err)
+ }
+
+ if intFlagValue != 7 {
+ t.Errorf("Expected flag value: %v, got %v", 7, intFlagValue)
+ }
+}
+
+func TestChildFlagWithParentLocalFlag(t *testing.T) {
+ rootCmd := &Command{Use: "root", Run: emptyRun}
+ childCmd := &Command{Use: "child", Run: emptyRun}
+ rootCmd.AddCommand(childCmd)
+
+ var intFlagValue int
+ rootCmd.Flags().StringP("sf", "s", "", "")
+ childCmd.Flags().IntVarP(&intFlagValue, "intf", "i", -1, "")
+
+ _, err := executeCommand(rootCmd, "child", "-i7", "-sabc")
+ if err == nil {
+ t.Errorf("Invalid flag should generate error")
+ }
+
+ checkStringContains(t, err.Error(), "unknown shorthand")
+
+ if intFlagValue != 7 {
+ t.Errorf("Expected flag value: %v, got %v", 7, intFlagValue)
+ }
+}
+
+func TestFlagInvalidInput(t *testing.T) {
+ rootCmd := &Command{Use: "root", Run: emptyRun}
+ rootCmd.Flags().IntP("intf", "i", -1, "")
+
+ _, err := executeCommand(rootCmd, "-iabc")
+ if err == nil {
+ t.Errorf("Invalid flag value should generate error")
+ }
+
+ checkStringContains(t, err.Error(), "invalid syntax")
+}
+
+func TestFlagBeforeCommand(t *testing.T) {
+ rootCmd := &Command{Use: "root", Run: emptyRun}
+ childCmd := &Command{Use: "child", Run: emptyRun}
+ rootCmd.AddCommand(childCmd)
+
+ var flagValue int
+ childCmd.Flags().IntVarP(&flagValue, "intf", "i", -1, "")
+
+ // With short flag.
+ _, err := executeCommand(rootCmd, "-i7", "child")
+ if err != nil {
+ t.Errorf("Unexpected error: %v", err)
+ }
+ if flagValue != 7 {
+ t.Errorf("Expected flag value: %v, got %v", 7, flagValue)
+ }
+
+ // With long flag.
+ _, err = executeCommand(rootCmd, "--intf=8", "child")
+ if err != nil {
+ t.Errorf("Unexpected error: %v", err)
+ }
+ if flagValue != 8 {
+ t.Errorf("Expected flag value: %v, got %v", 9, flagValue)
}
}
@@ -45,11 +468,11 @@ func TestStripFlags(t *testing.T) {
[]string{"foo", "bar"},
},
{
- []string{"foo", "--bar", "-b"},
+ []string{"foo", "--str", "-s"},
[]string{"foo"},
},
{
- []string{"-b", "foo", "--bar", "bar"},
+ []string{"-s", "foo", "--str", "bar"},
[]string{},
},
{
@@ -65,7 +488,7 @@ func TestStripFlags(t *testing.T) {
[]string{"echo"},
},
{
- []string{"-ib", "echo", "-bfoo", "baz"},
+ []string{"-ib", "echo", "-sfoo", "baz"},
[]string{"echo", "baz"},
},
{
@@ -73,15 +496,15 @@ func TestStripFlags(t *testing.T) {
[]string{"bar", "blah"},
},
{
- []string{"--int=baz", "-bbar", "-i", "foo", "blah"},
+ []string{"--int=baz", "-sbar", "-i", "foo", "blah"},
[]string{"blah"},
},
{
- []string{"--cat", "bar", "-i", "foo", "blah"},
+ []string{"--bool", "bar", "-i", "foo", "blah"},
[]string{"bar", "blah"},
},
{
- []string{"-c", "bar", "-i", "foo", "blah"},
+ []string{"-b", "bar", "-i", "foo", "blah"},
[]string{"bar", "blah"},
},
{
@@ -94,61 +517,757 @@ func TestStripFlags(t *testing.T) {
},
}
- cmdPrint := &Command{
- Use: "print [string to print]",
- Short: "Print anything to the screen",
- Long: `an utterly useless command for testing.`,
- Run: func(cmd *Command, args []string) {
- tp = args
- },
- }
-
- var flagi int
- var flagstr string
- var flagbool bool
- cmdPrint.PersistentFlags().BoolVarP(&flagbool, "persist", "p", false, "help for persistent one")
- cmdPrint.Flags().IntVarP(&flagi, "int", "i", 345, "help message for flag int")
- cmdPrint.Flags().StringVarP(&flagstr, "bar", "b", "bar", "help message for flag string")
- cmdPrint.Flags().BoolVarP(&flagbool, "cat", "c", false, "help message for flag bool")
+ c := &Command{Use: "c", Run: emptyRun}
+ c.PersistentFlags().BoolP("persist", "p", false, "")
+ c.Flags().IntP("int", "i", -1, "")
+ c.Flags().StringP("str", "s", "", "")
+ c.Flags().BoolP("bool", "b", false, "")
- for _, test := range tests {
- output := stripFlags(test.input, cmdPrint)
- if !reflect.DeepEqual(test.output, output) {
- t.Errorf("expected: %v, got: %v", test.output, output)
+ for i, test := range tests {
+ got := stripFlags(test.input, c)
+ if !reflect.DeepEqual(test.output, got) {
+ t.Errorf("(%v) Expected: %v, got: %v", i, test.output, got)
}
}
}
func TestDisableFlagParsing(t *testing.T) {
- targs := []string{}
- cmdPrint := &Command{
+ var cArgs []string
+ c := &Command{
+ Use: "c",
DisableFlagParsing: true,
- Run: func(cmd *Command, args []string) {
- targs = args
+ Run: func(_ *Command, args []string) {
+ cArgs = args
},
}
+
args := []string{"cmd", "-v", "-race", "-file", "foo.go"}
- cmdPrint.SetArgs(args)
- err := cmdPrint.Execute()
+ output, err := executeCommand(c, args...)
+ if output != "" {
+ t.Errorf("Unexpected output: %v", output)
+ }
+ if err != nil {
+ t.Errorf("Unexpected error: %v", err)
+ }
+
+ if !reflect.DeepEqual(args, cArgs) {
+ t.Errorf("Expected: %v, got: %v", args, cArgs)
+ }
+}
+
+func TestPersistentFlagsOnSameCommand(t *testing.T) {
+ var rootCmdArgs []string
+ rootCmd := &Command{
+ Use: "root",
+ Args: ArbitraryArgs,
+ Run: func(_ *Command, args []string) { rootCmdArgs = args },
+ }
+
+ var flagValue int
+ rootCmd.PersistentFlags().IntVarP(&flagValue, "intf", "i", -1, "")
+
+ output, err := executeCommand(rootCmd, "-i7", "one", "two")
+ if output != "" {
+ t.Errorf("Unexpected output: %v", output)
+ }
if err != nil {
- t.Error(err)
+ t.Errorf("Unexpected error: %v", err)
}
- if !reflect.DeepEqual(args, targs) {
- t.Errorf("expected: %v, got: %v", args, targs)
+
+ got := strings.Join(rootCmdArgs, " ")
+ expected := "one two"
+ if got != expected {
+ t.Errorf("rootCmdArgs expected: %q, got %q", expected, got)
+ }
+ if flagValue != 7 {
+ t.Errorf("flagValue expected: %v, got %v", 7, flagValue)
+ }
+}
+
+// TestEmptyInputs checks,
+// if flags correctly parsed with blank strings in args.
+func TestEmptyInputs(t *testing.T) {
+ c := &Command{Use: "c", Run: emptyRun}
+
+ var flagValue int
+ c.Flags().IntVarP(&flagValue, "intf", "i", -1, "")
+
+ output, err := executeCommand(c, "", "-i7", "")
+ if output != "" {
+ t.Errorf("Unexpected output: %v", output)
+ }
+ if err != nil {
+ t.Errorf("Unexpected error: %v", err)
+ }
+
+ if flagValue != 7 {
+ t.Errorf("flagValue expected: %v, got %v", 7, flagValue)
+ }
+}
+
+func TestOverwrittenFlag(t *testing.T) {
+ // TODO: This test fails, but should work.
+ t.Skip()
+
+ parent := &Command{Use: "parent", Run: emptyRun}
+ child := &Command{Use: "child", Run: emptyRun}
+
+ parent.PersistentFlags().Bool("boolf", false, "")
+ parent.PersistentFlags().Int("intf", -1, "")
+ child.Flags().String("strf", "", "")
+ child.Flags().Int("intf", -1, "")
+
+ parent.AddCommand(child)
+
+ childInherited := child.InheritedFlags()
+ childLocal := child.LocalFlags()
+
+ if childLocal.Lookup("strf") == nil {
+ t.Error(`LocalFlags expected to contain "strf", got "nil"`)
+ }
+ if childInherited.Lookup("boolf") == nil {
+ t.Error(`InheritedFlags expected to contain "boolf", got "nil"`)
+ }
+
+ if childInherited.Lookup("intf") != nil {
+ t.Errorf(`InheritedFlags should not contain overwritten flag "intf"`)
+ }
+ if childLocal.Lookup("intf") == nil {
+ t.Error(`LocalFlags expected to contain "intf", got "nil"`)
+ }
+}
+
+func TestPersistentFlagsOnChild(t *testing.T) {
+ var childCmdArgs []string
+ rootCmd := &Command{Use: "root", Run: emptyRun}
+ childCmd := &Command{
+ Use: "child",
+ Args: ArbitraryArgs,
+ Run: func(_ *Command, args []string) { childCmdArgs = args },
+ }
+ rootCmd.AddCommand(childCmd)
+
+ var parentFlagValue int
+ var childFlagValue int
+ rootCmd.PersistentFlags().IntVarP(&parentFlagValue, "parentf", "p", -1, "")
+ childCmd.Flags().IntVarP(&childFlagValue, "childf", "c", -1, "")
+
+ output, err := executeCommand(rootCmd, "child", "-c7", "-p8", "one", "two")
+ if output != "" {
+ t.Errorf("Unexpected output: %v", output)
+ }
+ if err != nil {
+ t.Errorf("Unexpected error: %v", err)
+ }
+
+ got := strings.Join(childCmdArgs, " ")
+ expected := "one two"
+ if got != expected {
+ t.Errorf("childCmdArgs expected: %q, got %q", expected, got)
+ }
+ if parentFlagValue != 8 {
+ t.Errorf("parentFlagValue expected: %v, got %v", 8, parentFlagValue)
+ }
+ if childFlagValue != 7 {
+ t.Errorf("childFlagValue expected: %v, got %v", 7, childFlagValue)
+ }
+}
+
+func TestRequiredFlags(t *testing.T) {
+ c := &Command{Use: "c", Run: emptyRun}
+ c.Flags().String("foo1", "", "")
+ c.MarkFlagRequired("foo1")
+ c.Flags().String("foo2", "", "")
+ c.MarkFlagRequired("foo2")
+ c.Flags().String("bar", "", "")
+
+ expected := fmt.Sprintf("Required flag(s) %q, %q have/has not been set", "foo1", "foo2")
+
+ _, err := executeCommand(c)
+ got := err.Error()
+
+ if got != expected {
+ t.Errorf("Expected error: %q, got: %q", expected, got)
+ }
+}
+
+func TestPersistentRequiredFlags(t *testing.T) {
+ parent := &Command{Use: "parent", Run: emptyRun}
+ parent.PersistentFlags().String("foo1", "", "")
+ parent.MarkPersistentFlagRequired("foo1")
+ parent.PersistentFlags().String("foo2", "", "")
+ parent.MarkPersistentFlagRequired("foo2")
+ parent.Flags().String("foo3", "", "")
+
+ child := &Command{Use: "child", Run: emptyRun}
+ child.Flags().String("bar1", "", "")
+ child.MarkFlagRequired("bar1")
+ child.Flags().String("bar2", "", "")
+ child.MarkFlagRequired("bar2")
+ child.Flags().String("bar3", "", "")
+
+ parent.AddCommand(child)
+
+ expected := fmt.Sprintf("Required flag(s) %q, %q, %q, %q have/has not been set", "bar1", "bar2", "foo1", "foo2")
+
+ _, err := executeCommand(parent, "child")
+ if err.Error() != expected {
+ t.Errorf("Expected %q, got %q", expected, err.Error())
}
}
func TestInitHelpFlagMergesFlags(t *testing.T) {
usage := "custom flag"
- baseCmd := Command{Use: "testcmd"}
- baseCmd.PersistentFlags().Bool("help", false, usage)
- cmd := Command{Use: "do"}
- baseCmd.AddCommand(&cmd)
+ rootCmd := &Command{Use: "root"}
+ rootCmd.PersistentFlags().Bool("help", false, "custom flag")
+ childCmd := &Command{Use: "child"}
+ rootCmd.AddCommand(childCmd)
+
+ childCmd.InitDefaultHelpFlag()
+ got := childCmd.Flags().Lookup("help").Usage
+ if got != usage {
+ t.Errorf("Expected the help flag from the root command with usage: %v\nGot the default with usage: %v", usage, got)
+ }
+}
+
+func TestHelpCommandExecuted(t *testing.T) {
+ rootCmd := &Command{Use: "root", Long: "Long description", Run: emptyRun}
+ rootCmd.AddCommand(&Command{Use: "child", Run: emptyRun})
+
+ output, err := executeCommand(rootCmd, "help")
+ if err != nil {
+ t.Errorf("Unexpected error: %v", err)
+ }
+
+ checkStringContains(t, output, rootCmd.Long)
+}
- cmd.InitDefaultHelpFlag()
- actual := cmd.Flags().Lookup("help").Usage
- if actual != usage {
- t.Fatalf("Expected the help flag from the base command with usage '%s', but got the default with usage '%s'", usage, actual)
+func TestHelpCommandExecutedOnChild(t *testing.T) {
+ rootCmd := &Command{Use: "root", Run: emptyRun}
+ childCmd := &Command{Use: "child", Long: "Long description", Run: emptyRun}
+ rootCmd.AddCommand(childCmd)
+
+ output, err := executeCommand(rootCmd, "help", "child")
+ if err != nil {
+ t.Errorf("Unexpected error: %v", err)
+ }
+
+ checkStringContains(t, output, childCmd.Long)
+}
+
+func TestSetHelpCommand(t *testing.T) {
+ c := &Command{Use: "c", Run: emptyRun}
+ c.AddCommand(&Command{Use: "empty", Run: emptyRun})
+
+ expected := "WORKS"
+ c.SetHelpCommand(&Command{
+ Use: "help [command]",
+ Short: "Help about any command",
+ Long: `Help provides help for any command in the application.
+ Simply type ` + c.Name() + ` help [path to command] for full details.`,
+ Run: func(c *Command, _ []string) { c.Print(expected) },
+ })
+
+ got, err := executeCommand(c, "help")
+ if err != nil {
+ t.Errorf("Unexpected error: %v", err)
+ }
+
+ if got != expected {
+ t.Errorf("Expected to contain %q, got %q", expected, got)
+ }
+}
+
+func TestHelpFlagExecuted(t *testing.T) {
+ rootCmd := &Command{Use: "root", Long: "Long description", Run: emptyRun}
+
+ output, err := executeCommand(rootCmd, "--help")
+ if err != nil {
+ t.Errorf("Unexpected error: %v", err)
+ }
+
+ checkStringContains(t, output, rootCmd.Long)
+}
+
+func TestHelpFlagExecutedOnChild(t *testing.T) {
+ rootCmd := &Command{Use: "root", Run: emptyRun}
+ childCmd := &Command{Use: "child", Long: "Long description", Run: emptyRun}
+ rootCmd.AddCommand(childCmd)
+
+ output, err := executeCommand(rootCmd, "child", "--help")
+ if err != nil {
+ t.Errorf("Unexpected error: %v", err)
+ }
+
+ checkStringContains(t, output, childCmd.Long)
+}
+
+// TestHelpFlagInHelp checks,
+// if '--help' flag is shown in help for child (executing `parent help child`),
+// that has no other flags.
+// Related to https://github.com/spf13/cobra/issues/302.
+func TestHelpFlagInHelp(t *testing.T) {
+ parentCmd := &Command{Use: "parent", Run: func(*Command, []string) {}}
+
+ childCmd := &Command{Use: "child", Run: func(*Command, []string) {}}
+ parentCmd.AddCommand(childCmd)
+
+ output, err := executeCommand(parentCmd, "help", "child")
+ if err != nil {
+ t.Errorf("Unexpected error: %v", err)
+ }
+
+ checkStringContains(t, output, "[flags]")
+}
+
+func TestFlagsInUsage(t *testing.T) {
+ rootCmd := &Command{Use: "root", Args: NoArgs, Run: func(*Command, []string) {}}
+ output, err := executeCommand(rootCmd, "--help")
+ if err != nil {
+ t.Errorf("Unexpected error: %v", err)
+ }
+
+ checkStringContains(t, output, "[flags]")
+}
+
+func TestHelpExecutedOnNonRunnableChild(t *testing.T) {
+ rootCmd := &Command{Use: "root", Run: emptyRun}
+ childCmd := &Command{Use: "child", Long: "Long description"}
+ rootCmd.AddCommand(childCmd)
+
+ output, err := executeCommand(rootCmd, "child")
+ if err != nil {
+ t.Errorf("Unexpected error: %v", err)
+ }
+
+ checkStringContains(t, output, childCmd.Long)
+}
+
+func TestUsageIsNotPrintedTwice(t *testing.T) {
+ var cmd = &Command{Use: "root"}
+ var sub = &Command{Use: "sub"}
+ cmd.AddCommand(sub)
+
+ output, _ := executeCommand(cmd, "")
+ if strings.Count(output, "Usage:") != 1 {
+ t.Error("Usage output is not printed exactly once")
+ }
+}
+
+func TestVisitParents(t *testing.T) {
+ c := &Command{Use: "app"}
+ sub := &Command{Use: "sub"}
+ dsub := &Command{Use: "dsub"}
+ sub.AddCommand(dsub)
+ c.AddCommand(sub)
+
+ total := 0
+ add := func(x *Command) {
+ total++
+ }
+ sub.VisitParents(add)
+ if total != 1 {
+ t.Errorf("Should have visited 1 parent but visited %d", total)
+ }
+
+ total = 0
+ dsub.VisitParents(add)
+ if total != 2 {
+ t.Errorf("Should have visited 2 parents but visited %d", total)
+ }
+
+ total = 0
+ c.VisitParents(add)
+ if total != 0 {
+ t.Errorf("Should have visited no parents but visited %d", total)
+ }
+}
+
+func TestSuggestions(t *testing.T) {
+ rootCmd := &Command{Use: "root", Run: emptyRun}
+ timesCmd := &Command{
+ Use: "times",
+ SuggestFor: []string{"counts"},
+ Run: emptyRun,
+ }
+ rootCmd.AddCommand(timesCmd)
+
+ templateWithSuggestions := "Error: unknown command \"%s\" for \"root\"\n\nDid you mean this?\n\t%s\n\nRun 'root --help' for usage.\n"
+ templateWithoutSuggestions := "Error: unknown command \"%s\" for \"root\"\nRun 'root --help' for usage.\n"
+
+ tests := map[string]string{
+ "time": "times",
+ "tiems": "times",
+ "tims": "times",
+ "timeS": "times",
+ "rimes": "times",
+ "ti": "times",
+ "t": "times",
+ "timely": "times",
+ "ri": "",
+ "timezone": "",
+ "foo": "",
+ "counts": "times",
+ }
+
+ for typo, suggestion := range tests {
+ for _, suggestionsDisabled := range []bool{true, false} {
+ rootCmd.DisableSuggestions = suggestionsDisabled
+
+ var expected string
+ output, _ := executeCommand(rootCmd, typo)
+
+ if suggestion == "" || suggestionsDisabled {
+ expected = fmt.Sprintf(templateWithoutSuggestions, typo)
+ } else {
+ expected = fmt.Sprintf(templateWithSuggestions, typo, suggestion)
+ }
+
+ if output != expected {
+ t.Errorf("Unexpected response.\nExpected:\n %q\nGot:\n %q\n", expected, output)
+ }
+ }
+ }
+}
+
+func TestRemoveCommand(t *testing.T) {
+ rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun}
+ childCmd := &Command{Use: "child", Run: emptyRun}
+ rootCmd.AddCommand(childCmd)
+ rootCmd.RemoveCommand(childCmd)
+
+ _, err := executeCommand(rootCmd, "child")
+ if err == nil {
+ t.Error("Expected error on calling removed command. Got nil.")
+ }
+}
+
+func TestReplaceCommandWithRemove(t *testing.T) {
+ childUsed := 0
+ rootCmd := &Command{Use: "root", Run: emptyRun}
+ child1Cmd := &Command{
+ Use: "child",
+ Run: func(*Command, []string) { childUsed = 1 },
+ }
+ child2Cmd := &Command{
+ Use: "child",
+ Run: func(*Command, []string) { childUsed = 2 },
+ }
+ rootCmd.AddCommand(child1Cmd)
+ rootCmd.RemoveCommand(child1Cmd)
+ rootCmd.AddCommand(child2Cmd)
+
+ output, err := executeCommand(rootCmd, "child")
+ if output != "" {
+ t.Errorf("Unexpected output: %v", output)
+ }
+ if err != nil {
+ t.Errorf("Unexpected error: %v", err)
+ }
+
+ if childUsed == 1 {
+ t.Error("Removed command shouldn't be called")
+ }
+ if childUsed != 2 {
+ t.Error("Replacing command should have been called but didn't")
+ }
+}
+
+func TestDeprecatedCommand(t *testing.T) {
+ rootCmd := &Command{Use: "root", Run: emptyRun}
+ deprecatedCmd := &Command{
+ Use: "deprecated",
+ Deprecated: "This command is deprecated",
+ Run: emptyRun,
+ }
+ rootCmd.AddCommand(deprecatedCmd)
+
+ output, err := executeCommand(rootCmd, "deprecated")
+ if err != nil {
+ t.Errorf("Unexpected error: %v", err)
+ }
+
+ checkStringContains(t, output, deprecatedCmd.Deprecated)
+}
+
+func TestHooks(t *testing.T) {
+ var (
+ persPreArgs string
+ preArgs string
+ runArgs string
+ postArgs string
+ persPostArgs string
+ )
+
+ c := &Command{
+ Use: "c",
+ PersistentPreRun: func(_ *Command, args []string) {
+ persPreArgs = strings.Join(args, " ")
+ },
+ PreRun: func(_ *Command, args []string) {
+ preArgs = strings.Join(args, " ")
+ },
+ Run: func(_ *Command, args []string) {
+ runArgs = strings.Join(args, " ")
+ },
+ PostRun: func(_ *Command, args []string) {
+ postArgs = strings.Join(args, " ")
+ },
+ PersistentPostRun: func(_ *Command, args []string) {
+ persPostArgs = strings.Join(args, " ")
+ },
+ }
+
+ output, err := executeCommand(c, "one", "two")
+ if output != "" {
+ t.Errorf("Unexpected output: %v", output)
+ }
+ if err != nil {
+ t.Errorf("Unexpected error: %v", err)
+ }
+
+ if persPreArgs != "one two" {
+ t.Errorf("Expected persPreArgs %q, got %q", "one two", persPreArgs)
+ }
+ if preArgs != "one two" {
+ t.Errorf("Expected preArgs %q, got %q", "one two", preArgs)
+ }
+ if runArgs != "one two" {
+ t.Errorf("Expected runArgs %q, got %q", "one two", runArgs)
+ }
+ if postArgs != "one two" {
+ t.Errorf("Expected postArgs %q, got %q", "one two", postArgs)
+ }
+ if persPostArgs != "one two" {
+ t.Errorf("Expected persPostArgs %q, got %q", "one two", persPostArgs)
+ }
+}
+
+func TestPersistentHooks(t *testing.T) {
+ var (
+ parentPersPreArgs string
+ parentPreArgs string
+ parentRunArgs string
+ parentPostArgs string
+ parentPersPostArgs string
+ )
+
+ var (
+ childPersPreArgs string
+ childPreArgs string
+ childRunArgs string
+ childPostArgs string
+ childPersPostArgs string
+ )
+
+ parentCmd := &Command{
+ Use: "parent",
+ PersistentPreRun: func(_ *Command, args []string) {
+ parentPersPreArgs = strings.Join(args, " ")
+ },
+ PreRun: func(_ *Command, args []string) {
+ parentPreArgs = strings.Join(args, " ")
+ },
+ Run: func(_ *Command, args []string) {
+ parentRunArgs = strings.Join(args, " ")
+ },
+ PostRun: func(_ *Command, args []string) {
+ parentPostArgs = strings.Join(args, " ")
+ },
+ PersistentPostRun: func(_ *Command, args []string) {
+ parentPersPostArgs = strings.Join(args, " ")
+ },
+ }
+
+ childCmd := &Command{
+ Use: "child",
+ PersistentPreRun: func(_ *Command, args []string) {
+ childPersPreArgs = strings.Join(args, " ")
+ },
+ PreRun: func(_ *Command, args []string) {
+ childPreArgs = strings.Join(args, " ")
+ },
+ Run: func(_ *Command, args []string) {
+ childRunArgs = strings.Join(args, " ")
+ },
+ PostRun: func(_ *Command, args []string) {
+ childPostArgs = strings.Join(args, " ")
+ },
+ PersistentPostRun: func(_ *Command, args []string) {
+ childPersPostArgs = strings.Join(args, " ")
+ },
+ }
+ parentCmd.AddCommand(childCmd)
+
+ output, err := executeCommand(parentCmd, "child", "one", "two")
+ if output != "" {
+ t.Errorf("Unexpected output: %v", output)
+ }
+ if err != nil {
+ t.Errorf("Unexpected error: %v", err)
+ }
+
+ // TODO: This test fails, but should not.
+ // Related to https://github.com/spf13/cobra/issues/252.
+ //
+ // if parentPersPreArgs != "one two" {
+ // t.Errorf("Expected parentPersPreArgs %q, got %q", "one two", parentPersPreArgs)
+ // }
+ if parentPreArgs != "" {
+ t.Errorf("Expected blank parentPreArgs, got %q", parentPreArgs)
+ }
+ if parentRunArgs != "" {
+ t.Errorf("Expected blank parentRunArgs, got %q", parentRunArgs)
+ }
+ if parentPostArgs != "" {
+ t.Errorf("Expected blank parentPostArgs, got %q", parentPostArgs)
+ }
+ // TODO: This test fails, but should not.
+ // Related to https://github.com/spf13/cobra/issues/252.
+ //
+ // if parentPersPostArgs != "one two" {
+ // t.Errorf("Expected parentPersPostArgs %q, got %q", "one two", parentPersPostArgs)
+ // }
+
+ if childPersPreArgs != "one two" {
+ t.Errorf("Expected childPersPreArgs %q, got %q", "one two", childPersPreArgs)
+ }
+ if childPreArgs != "one two" {
+ t.Errorf("Expected childPreArgs %q, got %q", "one two", childPreArgs)
+ }
+ if childRunArgs != "one two" {
+ t.Errorf("Expected childRunArgs %q, got %q", "one two", childRunArgs)
+ }
+ if childPostArgs != "one two" {
+ t.Errorf("Expected childPostArgs %q, got %q", "one two", childPostArgs)
+ }
+ if childPersPostArgs != "one two" {
+ t.Errorf("Expected childPersPostArgs %q, got %q", "one two", childPersPostArgs)
+ }
+}
+
+// Related to https://github.com/spf13/cobra/issues/521.
+func TestGlobalNormFuncPropagation(t *testing.T) {
+ normFunc := func(f *pflag.FlagSet, name string) pflag.NormalizedName {
+ return pflag.NormalizedName(name)
+ }
+
+ rootCmd := &Command{Use: "root", Run: emptyRun}
+ childCmd := &Command{Use: "child", Run: emptyRun}
+ rootCmd.AddCommand(childCmd)
+
+ rootCmd.SetGlobalNormalizationFunc(normFunc)
+ if reflect.ValueOf(normFunc).Pointer() != reflect.ValueOf(rootCmd.GlobalNormalizationFunc()).Pointer() {
+ t.Error("rootCmd seems to have a wrong normalization function")
+ }
+
+ if reflect.ValueOf(normFunc).Pointer() != reflect.ValueOf(childCmd.GlobalNormalizationFunc()).Pointer() {
+ t.Error("childCmd should have had the normalization function of rootCmd")
+ }
+}
+
+// Related to https://github.com/spf13/cobra/issues/521.
+func TestNormPassedOnLocal(t *testing.T) {
+ toUpper := func(f *pflag.FlagSet, name string) pflag.NormalizedName {
+ return pflag.NormalizedName(strings.ToUpper(name))
+ }
+
+ c := &Command{}
+ c.Flags().Bool("flagname", true, "this is a dummy flag")
+ c.SetGlobalNormalizationFunc(toUpper)
+ if c.LocalFlags().Lookup("flagname") != c.LocalFlags().Lookup("FLAGNAME") {
+ t.Error("Normalization function should be passed on to Local flag set")
+ }
+}
+
+// Related to https://github.com/spf13/cobra/issues/521.
+func TestNormPassedOnInherited(t *testing.T) {
+ toUpper := func(f *pflag.FlagSet, name string) pflag.NormalizedName {
+ return pflag.NormalizedName(strings.ToUpper(name))
+ }
+
+ c := &Command{}
+ c.SetGlobalNormalizationFunc(toUpper)
+
+ child1 := &Command{}
+ c.AddCommand(child1)
+
+ c.PersistentFlags().Bool("flagname", true, "")
+
+ child2 := &Command{}
+ c.AddCommand(child2)
+
+ inherited := child1.InheritedFlags()
+ if inherited.Lookup("flagname") == nil || inherited.Lookup("flagname") != inherited.Lookup("FLAGNAME") {
+ t.Error("Normalization function should be passed on to inherited flag set in command added before flag")
+ }
+
+ inherited = child2.InheritedFlags()
+ if inherited.Lookup("flagname") == nil || inherited.Lookup("flagname") != inherited.Lookup("FLAGNAME") {
+ t.Error("Normalization function should be passed on to inherited flag set in command added after flag")
+ }
+}
+
+// Related to https://github.com/spf13/cobra/issues/521.
+func TestConsistentNormalizedName(t *testing.T) {
+ toUpper := func(f *pflag.FlagSet, name string) pflag.NormalizedName {
+ return pflag.NormalizedName(strings.ToUpper(name))
+ }
+ n := func(f *pflag.FlagSet, name string) pflag.NormalizedName {
+ return pflag.NormalizedName(name)
+ }
+
+ c := &Command{}
+ c.Flags().Bool("flagname", true, "")
+ c.SetGlobalNormalizationFunc(toUpper)
+ c.SetGlobalNormalizationFunc(n)
+
+ if c.LocalFlags().Lookup("flagname") == c.LocalFlags().Lookup("FLAGNAME") {
+ t.Error("Normalizing flag names should not result in duplicate flags")
+ }
+}
+
+func TestFlagOnPflagCommandLine(t *testing.T) {
+ flagName := "flagOnCommandLine"
+ pflag.String(flagName, "", "about my flag")
+
+ c := &Command{Use: "c", Run: emptyRun}
+ c.AddCommand(&Command{Use: "child", Run: emptyRun})
+
+ output, _ := executeCommand(c, "--help")
+ checkStringContains(t, output, flagName)
+
+ resetCommandLineFlagSet()
+}
+
+// TestHiddenCommandExecutes checks,
+// if hidden commands run as intended.
+func TestHiddenCommandExecutes(t *testing.T) {
+ executed := false
+ c := &Command{
+ Use: "c",
+ Hidden: true,
+ Run: func(*Command, []string) { executed = true },
+ }
+
+ output, err := executeCommand(c)
+ if output != "" {
+ t.Errorf("Unexpected output: %v", output)
+ }
+ if err != nil {
+ t.Errorf("Unexpected error: %v", err)
+ }
+
+ if !executed {
+ t.Error("Hidden command should have been executed")
+ }
+}
+
+// test to ensure hidden commands do not show up in usage/help text
+func TestHiddenCommandIsHidden(t *testing.T) {
+ c := &Command{Use: "c", Hidden: true, Run: emptyRun}
+ if c.IsAvailableCommand() {
+ t.Errorf("Hidden command should be unavailable")
}
}
@@ -158,15 +1277,16 @@ func TestCommandsAreSorted(t *testing.T) {
originalNames := []string{"middle", "zlast", "afirst"}
expectedNames := []string{"afirst", "middle", "zlast"}
- var tmpCommand = &Command{Use: "tmp"}
+ var rootCmd = &Command{Use: "root"}
for _, name := range originalNames {
- tmpCommand.AddCommand(&Command{Use: name})
+ rootCmd.AddCommand(&Command{Use: name})
}
- for i, c := range tmpCommand.Commands() {
- if expectedNames[i] != c.Name() {
- t.Errorf("expected: %s, got: %s", expectedNames[i], c.Name())
+ for i, c := range rootCmd.Commands() {
+ got := c.Name()
+ if expectedNames[i] != got {
+ t.Errorf("Expected: %s, got: %s", expectedNames[i], got)
}
}
@@ -178,15 +1298,16 @@ func TestEnableCommandSortingIsDisabled(t *testing.T) {
originalNames := []string{"middle", "zlast", "afirst"}
- var tmpCommand = &Command{Use: "tmp"}
+ var rootCmd = &Command{Use: "root"}
for _, name := range originalNames {
- tmpCommand.AddCommand(&Command{Use: name})
+ rootCmd.AddCommand(&Command{Use: name})
}
- for i, c := range tmpCommand.Commands() {
- if originalNames[i] != c.Name() {
- t.Errorf("expected: %s, got: %s", originalNames[i], c.Name())
+ for i, c := range rootCmd.Commands() {
+ got := c.Name()
+ if originalNames[i] != got {
+ t.Errorf("expected: %s, got: %s", originalNames[i], got)
}
}
@@ -194,33 +1315,27 @@ func TestEnableCommandSortingIsDisabled(t *testing.T) {
}
func TestSetOutput(t *testing.T) {
- cmd := &Command{}
- cmd.SetOutput(nil)
- if out := cmd.OutOrStdout(); out != os.Stdout {
- t.Fatalf("expected setting output to nil to revert back to stdout, got %v", out)
+ c := &Command{}
+ c.SetOutput(nil)
+ if out := c.OutOrStdout(); out != os.Stdout {
+ t.Errorf("Expected setting output to nil to revert back to stdout")
}
}
func TestFlagErrorFunc(t *testing.T) {
- cmd := &Command{
- Use: "print",
- RunE: func(cmd *Command, args []string) error {
- return nil
- },
- }
- expectedFmt := "This is expected: %s"
+ c := &Command{Use: "c", Run: emptyRun}
- cmd.SetFlagErrorFunc(func(c *Command, err error) error {
+ expectedFmt := "This is expected: %v"
+ c.SetFlagErrorFunc(func(_ *Command, err error) error {
return fmt.Errorf(expectedFmt, err)
})
- cmd.SetArgs([]string{"--bogus-flag"})
- cmd.SetOutput(new(bytes.Buffer))
- err := cmd.Execute()
+ _, err := executeCommand(c, "--unknown-flag")
- expected := fmt.Sprintf(expectedFmt, "unknown flag: --bogus-flag")
- if err.Error() != expected {
- t.Errorf("expected %v, got %v", expected, err.Error())
+ got := err.Error()
+ expected := fmt.Sprintf(expectedFmt, "unknown flag: --unknown-flag")
+ if got != expected {
+ t.Errorf("Expected %v, got %v", expected, got)
}
}
@@ -228,19 +1343,19 @@ func TestFlagErrorFunc(t *testing.T) {
// if cmd.LocalFlags() is unsorted when cmd.Flags().SortFlags set to false.
// Related to https://github.com/spf13/cobra/issues/404.
func TestSortedFlags(t *testing.T) {
- cmd := &Command{}
- cmd.Flags().SortFlags = false
+ c := &Command{}
+ c.Flags().SortFlags = false
names := []string{"C", "B", "A", "D"}
for _, name := range names {
- cmd.Flags().Bool(name, false, "")
+ c.Flags().Bool(name, false, "")
}
i := 0
- cmd.LocalFlags().VisitAll(func(f *pflag.Flag) {
+ c.LocalFlags().VisitAll(func(f *pflag.Flag) {
if i == len(names) {
return
}
- if isStringInStringSlice(f.Name, names) {
+ if stringInSlice(f.Name, names) {
if names[i] != f.Name {
t.Errorf("Incorrect order. Expected %v, got %v", names[i], f.Name)
}
@@ -249,101 +1364,145 @@ func TestSortedFlags(t *testing.T) {
})
}
-// contains checks, if s is in ss.
-func isStringInStringSlice(s string, ss []string) bool {
- for _, v := range ss {
- if v == s {
- return true
- }
- }
- return false
-}
-
-// TestHelpFlagInHelp checks,
-// if '--help' flag is shown in help for child (executing `parent help child`),
-// that has no other flags.
-// Related to https://github.com/spf13/cobra/issues/302.
-func TestHelpFlagInHelp(t *testing.T) {
- output := new(bytes.Buffer)
- parent := &Command{Use: "parent", Run: func(*Command, []string) {}}
- parent.SetOutput(output)
-
- child := &Command{Use: "child", Run: func(*Command, []string) {}}
- parent.AddCommand(child)
-
- parent.SetArgs([]string{"help", "child"})
- err := parent.Execute()
- if err != nil {
- t.Fatal(err)
- }
-
- if !strings.Contains(output.String(), "[flags]") {
- t.Errorf("\nExpecting to contain: %v\nGot: %v", "[flags]", output.String())
- }
-}
-
// TestMergeCommandLineToFlags checks,
// if pflag.CommandLine is correctly merged to c.Flags() after first call
// of c.mergePersistentFlags.
// Related to https://github.com/spf13/cobra/issues/443.
func TestMergeCommandLineToFlags(t *testing.T) {
pflag.Bool("boolflag", false, "")
- c := &Command{Use: "c", Run: func(*Command, []string) {}}
+ c := &Command{Use: "c", Run: emptyRun}
c.mergePersistentFlags()
if c.Flags().Lookup("boolflag") == nil {
t.Fatal("Expecting to have flag from CommandLine in c.Flags()")
}
- // Reset pflag.CommandLine flagset.
- pflag.CommandLine = pflag.NewFlagSet(os.Args[0], pflag.ExitOnError)
+ resetCommandLineFlagSet()
}
// TestUseDeprecatedFlags checks,
// if cobra.Execute() prints a message, if a deprecated flag is used.
// Related to https://github.com/spf13/cobra/issues/463.
func TestUseDeprecatedFlags(t *testing.T) {
- c := &Command{Use: "c", Run: func(*Command, []string) {}}
- output := new(bytes.Buffer)
- c.SetOutput(output)
+ c := &Command{Use: "c", Run: emptyRun}
c.Flags().BoolP("deprecated", "d", false, "deprecated flag")
c.Flags().MarkDeprecated("deprecated", "This flag is deprecated")
- c.SetArgs([]string{"c", "-d"})
- if err := c.Execute(); err != nil {
+ output, err := executeCommand(c, "c", "-d")
+ if err != nil {
t.Error("Unexpected error:", err)
}
- if !strings.Contains(output.String(), "This flag is deprecated") {
- t.Errorf("Expected to contain deprecated message, but got %q", output.String())
+ checkStringContains(t, output, "This flag is deprecated")
+}
+
+func TestTraverseWithParentFlags(t *testing.T) {
+ rootCmd := &Command{Use: "root", TraverseChildren: true}
+ rootCmd.Flags().String("str", "", "")
+ rootCmd.Flags().BoolP("bool", "b", false, "")
+
+ childCmd := &Command{Use: "child"}
+ childCmd.Flags().Int("int", -1, "")
+
+ rootCmd.AddCommand(childCmd)
+
+ c, args, err := rootCmd.Traverse([]string{"-b", "--str", "ok", "child", "--int"})
+ if err != nil {
+ t.Errorf("Unexpected error: %v", err)
+ }
+ if len(args) != 1 && args[0] != "--add" {
+ t.Errorf("Wrong args: %v", args)
+ }
+ if c.Name() != childCmd.Name() {
+ t.Errorf("Expected command: %q, got: %q", childCmd.Name(), c.Name())
}
}
-// TestSetHelpCommand checks, if SetHelpCommand works correctly.
-func TestSetHelpCommand(t *testing.T) {
- c := &Command{Use: "c", Run: func(*Command, []string) {}}
- output := new(bytes.Buffer)
- c.SetOutput(output)
- c.SetArgs([]string{"help"})
-
- // Help will not be shown, if c has no subcommands.
- c.AddCommand(&Command{
- Use: "empty",
- Run: func(cmd *Command, args []string) {},
- })
+func TestTraverseNoParentFlags(t *testing.T) {
+ rootCmd := &Command{Use: "root", TraverseChildren: true}
+ rootCmd.Flags().String("foo", "", "foo things")
- correctMessage := "WORKS"
- c.SetHelpCommand(&Command{
- Use: "help [command]",
- Short: "Help about any command",
- Long: `Help provides help for any command in the application.
- Simply type ` + c.Name() + ` help [path to command] for full details.`,
- Run: func(c *Command, args []string) { c.Print(correctMessage) },
- })
+ childCmd := &Command{Use: "child"}
+ childCmd.Flags().String("str", "", "")
+ rootCmd.AddCommand(childCmd)
- if err := c.Execute(); err != nil {
- t.Error("Unexpected error:", err)
+ c, args, err := rootCmd.Traverse([]string{"child"})
+ if err != nil {
+ t.Errorf("Unexpected error: %v", err)
+ }
+ if len(args) != 0 {
+ t.Errorf("Wrong args %v", args)
+ }
+ if c.Name() != childCmd.Name() {
+ t.Errorf("Expected command: %q, got: %q", childCmd.Name(), c.Name())
+ }
+}
+
+func TestTraverseWithBadParentFlags(t *testing.T) {
+ rootCmd := &Command{Use: "root", TraverseChildren: true}
+
+ childCmd := &Command{Use: "child"}
+ childCmd.Flags().String("str", "", "")
+ rootCmd.AddCommand(childCmd)
+
+ expected := "unknown flag: --str"
+
+ c, _, err := rootCmd.Traverse([]string{"--str", "ok", "child"})
+ if err == nil || !strings.Contains(err.Error(), expected) {
+ t.Errorf("Expected error, %q, got %q", expected, err)
+ }
+ if c != nil {
+ t.Errorf("Expected nil command")
}
+}
+
+func TestTraverseWithBadChildFlag(t *testing.T) {
+ rootCmd := &Command{Use: "root", TraverseChildren: true}
+ rootCmd.Flags().String("str", "", "")
+
+ childCmd := &Command{Use: "child"}
+ rootCmd.AddCommand(childCmd)
+
+ // Expect no error because the last commands args shouldn't be parsed in
+ // Traverse.
+ c, args, err := rootCmd.Traverse([]string{"child", "--str"})
+ if err != nil {
+ t.Errorf("Unexpected error: %v", err)
+ }
+ if len(args) != 1 && args[0] != "--str" {
+ t.Errorf("Wrong args: %v", args)
+ }
+ if c.Name() != childCmd.Name() {
+ t.Errorf("Expected command %q, got: %q", childCmd.Name(), c.Name())
+ }
+}
+
+func TestTraverseWithTwoSubcommands(t *testing.T) {
+ rootCmd := &Command{Use: "root", TraverseChildren: true}
+
+ subCmd := &Command{Use: "sub", TraverseChildren: true}
+ rootCmd.AddCommand(subCmd)
+
+ subsubCmd := &Command{
+ Use: "subsub",
+ }
+ subCmd.AddCommand(subsubCmd)
+
+ c, _, err := rootCmd.Traverse([]string{"sub", "subsub"})
+ if err != nil {
+ t.Fatalf("Unexpected error: %v", err)
+ }
+ if c.Name() != subsubCmd.Name() {
+ t.Fatalf("Expected command: %q, got %q", subsubCmd.Name(), c.Name())
+ }
+}
+
+// TestUpdateName checks if c.Name() updates on changed c.Use.
+// Related to https://github.com/spf13/cobra/pull/422#discussion_r143918343.
+func TestUpdateName(t *testing.T) {
+ c := &Command{Use: "name xyz"}
+ originalName := c.Name()
- if output.String() != correctMessage {
- t.Errorf("Expected to contain %q message, but got %q", correctMessage, output.String())
+ c.Use = "changedName abc"
+ if originalName == c.Name() || c.Name() != "changedName" {
+ t.Error("c.Name() should be updated on changed c.Use")
}
}
diff --git a/vendor/github.com/spf13/cobra/doc/cmd_test.go b/vendor/github.com/spf13/cobra/doc/cmd_test.go
index a4b5568fa..d29c577df 100644
--- a/vendor/github.com/spf13/cobra/doc/cmd_test.go
+++ b/vendor/github.com/spf13/cobra/doc/cmd_test.go
@@ -1,145 +1,86 @@
package doc
import (
- "bytes"
- "fmt"
- "runtime"
"strings"
"testing"
"github.com/spf13/cobra"
)
-var flagb1, flagb2, flagb3, flagbr, flagbp bool
-var flags1, flags2a, flags2b, flags3 string
-var flagi1, flagi2, flagi3, flagir int
+func emptyRun(*cobra.Command, []string) {}
-const strtwoParentHelp = "help message for parent flag strtwo"
-const strtwoChildHelp = "help message for child flag strtwo"
+func init() {
+ rootCmd.PersistentFlags().StringP("rootflag", "r", "two", "")
+ rootCmd.PersistentFlags().StringP("strtwo", "t", "two", "help message for parent flag strtwo")
-var cmdEcho = &cobra.Command{
+ echoCmd.PersistentFlags().StringP("strone", "s", "one", "help message for flag strone")
+ echoCmd.PersistentFlags().BoolP("persistentbool", "p", false, "help message for flag persistentbool")
+ echoCmd.Flags().IntP("intone", "i", 123, "help message for flag intone")
+ echoCmd.Flags().BoolP("boolone", "b", true, "help message for flag boolone")
+
+ timesCmd.PersistentFlags().StringP("strtwo", "t", "2", "help message for child flag strtwo")
+ timesCmd.Flags().IntP("inttwo", "j", 234, "help message for flag inttwo")
+ timesCmd.Flags().BoolP("booltwo", "c", false, "help message for flag booltwo")
+
+ printCmd.PersistentFlags().StringP("strthree", "s", "three", "help message for flag strthree")
+ printCmd.Flags().IntP("intthree", "i", 345, "help message for flag intthree")
+ printCmd.Flags().BoolP("boolthree", "b", true, "help message for flag boolthree")
+
+ echoCmd.AddCommand(timesCmd, echoSubCmd, deprecatedCmd)
+ rootCmd.AddCommand(printCmd, echoCmd)
+}
+
+var rootCmd = &cobra.Command{
+ Use: "root",
+ Short: "Root short description",
+ Long: "Root long description",
+ Run: emptyRun,
+}
+
+var echoCmd = &cobra.Command{
Use: "echo [string to echo]",
Aliases: []string{"say"},
Short: "Echo anything to the screen",
- Long: `an utterly useless command for testing.`,
+ Long: "an utterly useless command for testing",
Example: "Just run cobra-test echo",
}
-var cmdEchoSub = &cobra.Command{
+var echoSubCmd = &cobra.Command{
Use: "echosub [string to print]",
Short: "second sub command for echo",
- Long: `an absolutely utterly useless command for testing gendocs!.`,
- Run: func(cmd *cobra.Command, args []string) {},
+ Long: "an absolutely utterly useless command for testing gendocs!.",
+ Run: emptyRun,
+}
+
+var timesCmd = &cobra.Command{
+ Use: "times [# times] [string to echo]",
+ SuggestFor: []string{"counts"},
+ Short: "Echo anything to the screen more times",
+ Long: `a slightly useless command for testing.`,
+ Run: emptyRun,
}
-var cmdDeprecated = &cobra.Command{
+var deprecatedCmd = &cobra.Command{
Use: "deprecated [can't do anything here]",
Short: "A command which is deprecated",
Long: `an absolutely utterly useless command for testing deprecation!.`,
Deprecated: "Please use echo instead",
}
-var cmdTimes = &cobra.Command{
- Use: "times [# times] [string to echo]",
- SuggestFor: []string{"counts"},
- Short: "Echo anything to the screen more times",
- Long: `a slightly useless command for testing.`,
- PersistentPreRun: func(cmd *cobra.Command, args []string) {},
- Run: func(cmd *cobra.Command, args []string) {},
-}
-
-var cmdPrint = &cobra.Command{
+var printCmd = &cobra.Command{
Use: "print [string to print]",
Short: "Print anything to the screen",
Long: `an absolutely utterly useless command for testing.`,
}
-var cmdRootNoRun = &cobra.Command{
- Use: "cobra-test",
- Short: "The root can run its own function",
- Long: "The root description for help",
-}
-
-var cmdRootSameName = &cobra.Command{
- Use: "print",
- Short: "Root with the same name as a subcommand",
- Long: "The root description for help",
-}
-
-var cmdRootWithRun = &cobra.Command{
- Use: "cobra-test",
- Short: "The root can run its own function",
- Long: "The root description for help",
-}
-
-var cmdSubNoRun = &cobra.Command{
- Use: "subnorun",
- Short: "A subcommand without a Run function",
- Long: "A long output about a subcommand without a Run function",
-}
-
-var cmdVersion1 = &cobra.Command{
- Use: "version",
- Short: "Print the version number",
- Long: `First version of the version command`,
-}
-
-var cmdVersion2 = &cobra.Command{
- Use: "version",
- Short: "Print the version number",
- Long: `Second version of the version command`,
-}
-
-func flagInit() {
- cmdEcho.ResetFlags()
- cmdPrint.ResetFlags()
- cmdTimes.ResetFlags()
- cmdRootNoRun.ResetFlags()
- cmdRootSameName.ResetFlags()
- cmdRootWithRun.ResetFlags()
- cmdSubNoRun.ResetFlags()
- cmdRootNoRun.PersistentFlags().StringVarP(&flags2a, "strtwo", "t", "two", strtwoParentHelp)
- cmdEcho.Flags().IntVarP(&flagi1, "intone", "i", 123, "help message for flag intone")
- cmdTimes.Flags().IntVarP(&flagi2, "inttwo", "j", 234, "help message for flag inttwo")
- cmdPrint.Flags().IntVarP(&flagi3, "intthree", "i", 345, "help message for flag intthree")
- cmdEcho.PersistentFlags().StringVarP(&flags1, "strone", "s", "one", "help message for flag strone")
- cmdEcho.PersistentFlags().BoolVarP(&flagbp, "persistentbool", "p", false, "help message for flag persistentbool")
- cmdTimes.PersistentFlags().StringVarP(&flags2b, "strtwo", "t", "2", strtwoChildHelp)
- cmdPrint.PersistentFlags().StringVarP(&flags3, "strthree", "s", "three", "help message for flag strthree")
- cmdEcho.Flags().BoolVarP(&flagb1, "boolone", "b", true, "help message for flag boolone")
- cmdTimes.Flags().BoolVarP(&flagb2, "booltwo", "c", false, "help message for flag booltwo")
- cmdPrint.Flags().BoolVarP(&flagb3, "boolthree", "b", true, "help message for flag boolthree")
- cmdVersion1.ResetFlags()
- cmdVersion2.ResetFlags()
-}
-
-func initializeWithRootCmd() *cobra.Command {
- cmdRootWithRun.ResetCommands()
- flagInit()
- cmdRootWithRun.Flags().BoolVarP(&flagbr, "boolroot", "b", false, "help message for flag boolroot")
- cmdRootWithRun.Flags().IntVarP(&flagir, "introot", "i", 321, "help message for flag introot")
- return cmdRootWithRun
-}
-
-func checkStringContains(t *testing.T, found, expected string) {
- if !strings.Contains(found, expected) {
- logErr(t, found, expected)
+func checkStringContains(t *testing.T, got, expected string) {
+ if !strings.Contains(got, expected) {
+ t.Errorf("Expected to contain: \n %v\nGot:\n %v\n", expected, got)
}
}
-func checkStringOmits(t *testing.T, found, expected string) {
- if strings.Contains(found, expected) {
- logErr(t, found, expected)
- }
-}
-
-func logErr(t *testing.T, found, expected string) {
- out := new(bytes.Buffer)
-
- _, _, line, ok := runtime.Caller(2)
- if ok {
- fmt.Fprintf(out, "Line: %d ", line)
+func checkStringOmits(t *testing.T, got, expected string) {
+ if strings.Contains(got, expected) {
+ t.Errorf("Expected to not contain: \n %v\nGot: %v", expected, got)
}
- fmt.Fprintf(out, "Unexpected response.\nExpecting to contain: \n %q\nGot:\n %q\n", expected, found)
- t.Errorf(out.String())
}
diff --git a/vendor/github.com/spf13/cobra/doc/man_docs_test.go b/vendor/github.com/spf13/cobra/doc/man_docs_test.go
index 87991063e..62f85e47f 100644
--- a/vendor/github.com/spf13/cobra/doc/man_docs_test.go
+++ b/vendor/github.com/spf13/cobra/doc/man_docs_test.go
@@ -18,135 +18,97 @@ func translate(in string) string {
}
func TestGenManDoc(t *testing.T) {
- c := initializeWithRootCmd()
- // Need two commands to run the command alphabetical sort
- cmdEcho.AddCommand(cmdTimes, cmdEchoSub, cmdDeprecated)
- c.AddCommand(cmdPrint, cmdEcho)
- cmdRootWithRun.PersistentFlags().StringVarP(&flags2a, "rootflag", "r", "two", strtwoParentHelp)
-
- out := new(bytes.Buffer)
-
header := &GenManHeader{
Title: "Project",
Section: "2",
}
+
// We generate on a subcommand so we have both subcommands and parents
- if err := GenMan(cmdEcho, header, out); err != nil {
+ buf := new(bytes.Buffer)
+ if err := GenMan(echoCmd, header, buf); err != nil {
t.Fatal(err)
}
- found := out.String()
+ output := buf.String()
// Make sure parent has - in CommandPath() in SEE ALSO:
- parentPath := cmdEcho.Parent().CommandPath()
+ parentPath := echoCmd.Parent().CommandPath()
dashParentPath := strings.Replace(parentPath, " ", "-", -1)
expected := translate(dashParentPath)
expected = expected + "(" + header.Section + ")"
- checkStringContains(t, found, expected)
-
- // Our description
- expected = translate(cmdEcho.Name())
- checkStringContains(t, found, expected)
-
- // Better have our example
- expected = translate(cmdEcho.Name())
- checkStringContains(t, found, expected)
-
- // A local flag
- expected = "boolone"
- checkStringContains(t, found, expected)
-
- // persistent flag on parent
- expected = "rootflag"
- checkStringContains(t, found, expected)
-
- // We better output info about our parent
- expected = translate(cmdRootWithRun.Name())
- checkStringContains(t, found, expected)
-
- // And about subcommands
- expected = translate(cmdEchoSub.Name())
- checkStringContains(t, found, expected)
-
- unexpected := translate(cmdDeprecated.Name())
- checkStringOmits(t, found, unexpected)
-
- // auto generated
- expected = translate("Auto generated")
- checkStringContains(t, found, expected)
+ checkStringContains(t, output, expected)
+
+ checkStringContains(t, output, translate(echoCmd.Name()))
+ checkStringContains(t, output, translate(echoCmd.Name()))
+ checkStringContains(t, output, "boolone")
+ checkStringContains(t, output, "rootflag")
+ checkStringContains(t, output, translate(rootCmd.Name()))
+ checkStringContains(t, output, translate(echoSubCmd.Name()))
+ checkStringOmits(t, output, translate(deprecatedCmd.Name()))
+ checkStringContains(t, output, translate("Auto generated"))
}
func TestGenManNoGenTag(t *testing.T) {
- c := initializeWithRootCmd()
- // Need two commands to run the command alphabetical sort
- cmdEcho.AddCommand(cmdTimes, cmdEchoSub, cmdDeprecated)
- c.AddCommand(cmdPrint, cmdEcho)
- cmdRootWithRun.PersistentFlags().StringVarP(&flags2a, "rootflag", "r", "two", strtwoParentHelp)
- cmdEcho.DisableAutoGenTag = true
- out := new(bytes.Buffer)
+ echoCmd.DisableAutoGenTag = true
+ defer func() { echoCmd.DisableAutoGenTag = false }()
header := &GenManHeader{
Title: "Project",
Section: "2",
}
+
// We generate on a subcommand so we have both subcommands and parents
- if err := GenMan(cmdEcho, header, out); err != nil {
+ buf := new(bytes.Buffer)
+ if err := GenMan(echoCmd, header, buf); err != nil {
t.Fatal(err)
}
- found := out.String()
+ output := buf.String()
unexpected := translate("#HISTORY")
- checkStringOmits(t, found, unexpected)
+ checkStringOmits(t, output, unexpected)
}
func TestGenManSeeAlso(t *testing.T) {
- noop := func(cmd *cobra.Command, args []string) {}
-
- top := &cobra.Command{Use: "top", Run: noop}
- aaa := &cobra.Command{Use: "aaa", Run: noop, Hidden: true} // #229
- bbb := &cobra.Command{Use: "bbb", Run: noop}
- ccc := &cobra.Command{Use: "ccc", Run: noop}
- top.AddCommand(aaa, bbb, ccc)
+ rootCmd := &cobra.Command{Use: "root", Run: emptyRun}
+ aCmd := &cobra.Command{Use: "aaa", Run: emptyRun, Hidden: true} // #229
+ bCmd := &cobra.Command{Use: "bbb", Run: emptyRun}
+ cCmd := &cobra.Command{Use: "ccc", Run: emptyRun}
+ rootCmd.AddCommand(aCmd, bCmd, cCmd)
- out := new(bytes.Buffer)
+ buf := new(bytes.Buffer)
header := &GenManHeader{}
- if err := GenMan(top, header, out); err != nil {
+ if err := GenMan(rootCmd, header, buf); err != nil {
t.Fatal(err)
}
+ scanner := bufio.NewScanner(buf)
- scanner := bufio.NewScanner(out)
-
- if err := AssertLineFound(scanner, ".SH SEE ALSO"); err != nil {
- t.Fatal(fmt.Errorf("Couldn't find SEE ALSO section header: %s", err.Error()))
+ if err := assertLineFound(scanner, ".SH SEE ALSO"); err != nil {
+ t.Fatalf("Couldn't find SEE ALSO section header: %v", err)
}
-
- if err := AssertNextLineEquals(scanner, ".PP"); err != nil {
- t.Fatal(fmt.Errorf("First line after SEE ALSO wasn't break-indent: %s", err.Error()))
+ if err := assertNextLineEquals(scanner, ".PP"); err != nil {
+ t.Fatalf("First line after SEE ALSO wasn't break-indent: %v", err)
}
-
- if err := AssertNextLineEquals(scanner, `\fBtop\-bbb(1)\fP, \fBtop\-ccc(1)\fP`); err != nil {
- t.Fatal(fmt.Errorf("Second line after SEE ALSO wasn't correct: %s", err.Error()))
+ if err := assertNextLineEquals(scanner, `\fBroot\-bbb(1)\fP, \fBroot\-ccc(1)\fP`); err != nil {
+ t.Fatalf("Second line after SEE ALSO wasn't correct: %v", err)
}
}
func TestManPrintFlagsHidesShortDeperecated(t *testing.T) {
- cmd := &cobra.Command{}
- flags := cmd.Flags()
- flags.StringP("foo", "f", "default", "Foo flag")
- flags.MarkShorthandDeprecated("foo", "don't use it no more")
+ c := &cobra.Command{}
+ c.Flags().StringP("foo", "f", "default", "Foo flag")
+ c.Flags().MarkShorthandDeprecated("foo", "don't use it no more")
- out := new(bytes.Buffer)
- manPrintFlags(out, flags)
+ buf := new(bytes.Buffer)
+ manPrintFlags(buf, c.Flags())
+ got := buf.String()
expected := "**--foo**=\"default\"\n\tFoo flag\n\n"
- if out.String() != expected {
- t.Fatalf("Expected %s, but got %s", expected, out.String())
+ if got != expected {
+ t.Errorf("Expected %v, got %v", expected, got)
}
}
func TestGenManTree(t *testing.T) {
- cmd := &cobra.Command{
- Use: "do [OPTIONS] arg1 arg2",
- }
+ c := &cobra.Command{Use: "do [OPTIONS] arg1 arg2"}
header := &GenManHeader{Section: "2"}
tmpdir, err := ioutil.TempDir("", "test-gen-man-tree")
if err != nil {
@@ -154,7 +116,7 @@ func TestGenManTree(t *testing.T) {
}
defer os.RemoveAll(tmpdir)
- if err := GenManTree(cmd, header, tmpdir); err != nil {
+ if err := GenManTree(c, header, tmpdir); err != nil {
t.Fatalf("GenManTree failed: %s", err.Error())
}
@@ -167,7 +129,7 @@ func TestGenManTree(t *testing.T) {
}
}
-func AssertLineFound(scanner *bufio.Scanner, expectedLine string) error {
+func assertLineFound(scanner *bufio.Scanner, expectedLine string) error {
for scanner.Scan() {
line := scanner.Text()
if line == expectedLine {
@@ -176,30 +138,29 @@ func AssertLineFound(scanner *bufio.Scanner, expectedLine string) error {
}
if err := scanner.Err(); err != nil {
- return fmt.Errorf("AssertLineFound: scan failed: %s", err.Error())
+ return fmt.Errorf("scan failed: %s", err)
}
- return fmt.Errorf("AssertLineFound: hit EOF before finding %#v", expectedLine)
+ return fmt.Errorf("hit EOF before finding %v", expectedLine)
}
-func AssertNextLineEquals(scanner *bufio.Scanner, expectedLine string) error {
+func assertNextLineEquals(scanner *bufio.Scanner, expectedLine string) error {
if scanner.Scan() {
line := scanner.Text()
if line == expectedLine {
return nil
}
- return fmt.Errorf("AssertNextLineEquals: got %#v, not %#v", line, expectedLine)
+ return fmt.Errorf("got %v, not %v", line, expectedLine)
}
if err := scanner.Err(); err != nil {
- return fmt.Errorf("AssertNextLineEquals: scan failed: %s", err.Error())
+ return fmt.Errorf("scan failed: %v", err)
}
- return fmt.Errorf("AssertNextLineEquals: hit EOF before finding %#v", expectedLine)
+ return fmt.Errorf("hit EOF before finding %v", expectedLine)
}
func BenchmarkGenManToFile(b *testing.B) {
- c := initializeWithRootCmd()
file, err := ioutil.TempFile("", "")
if err != nil {
b.Fatal(err)
@@ -209,7 +170,7 @@ func BenchmarkGenManToFile(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
- if err := GenMan(c, nil, file); err != nil {
+ if err := GenMan(rootCmd, nil, file); err != nil {
b.Fatal(err)
}
}
diff --git a/vendor/github.com/spf13/cobra/doc/md_docs_test.go b/vendor/github.com/spf13/cobra/doc/md_docs_test.go
index ba6b9a46e..b0fa68c0b 100644
--- a/vendor/github.com/spf13/cobra/doc/md_docs_test.go
+++ b/vendor/github.com/spf13/cobra/doc/md_docs_test.go
@@ -5,100 +5,51 @@ import (
"io/ioutil"
"os"
"path/filepath"
- "strings"
"testing"
"github.com/spf13/cobra"
)
func TestGenMdDoc(t *testing.T) {
- c := initializeWithRootCmd()
- // Need two commands to run the command alphabetical sort
- cmdEcho.AddCommand(cmdTimes, cmdEchoSub, cmdDeprecated)
- c.AddCommand(cmdPrint, cmdEcho)
- cmdRootWithRun.PersistentFlags().StringVarP(&flags2a, "rootflag", "r", "two", strtwoParentHelp)
-
- out := new(bytes.Buffer)
-
- // We generate on s subcommand so we have both subcommands and parents
- if err := GenMarkdown(cmdEcho, out); err != nil {
+ // We generate on subcommand so we have both subcommands and parents.
+ buf := new(bytes.Buffer)
+ if err := GenMarkdown(echoCmd, buf); err != nil {
t.Fatal(err)
}
- found := out.String()
-
- // Our description
- expected := cmdEcho.Long
- if !strings.Contains(found, expected) {
- t.Errorf("Unexpected response.\nExpecting to contain: \n %q\nGot:\n %q\n", expected, found)
- }
-
- // Better have our example
- expected = cmdEcho.Example
- if !strings.Contains(found, expected) {
- t.Errorf("Unexpected response.\nExpecting to contain: \n %q\nGot:\n %q\n", expected, found)
- }
-
- // A local flag
- expected = "boolone"
- if !strings.Contains(found, expected) {
- t.Errorf("Unexpected response.\nExpecting to contain: \n %q\nGot:\n %q\n", expected, found)
- }
-
- // persistent flag on parent
- expected = "rootflag"
- if !strings.Contains(found, expected) {
- t.Errorf("Unexpected response.\nExpecting to contain: \n %q\nGot:\n %q\n", expected, found)
- }
-
- // We better output info about our parent
- expected = cmdRootWithRun.Short
- if !strings.Contains(found, expected) {
- t.Errorf("Unexpected response.\nExpecting to contain: \n %q\nGot:\n %q\n", expected, found)
- }
-
- // And about subcommands
- expected = cmdEchoSub.Short
- if !strings.Contains(found, expected) {
- t.Errorf("Unexpected response.\nExpecting to contain: \n %q\nGot:\n %q\n", expected, found)
- }
-
- unexpected := cmdDeprecated.Short
- if strings.Contains(found, unexpected) {
- t.Errorf("Unexpected response.\nFound: %v\nBut should not have!!\n", unexpected)
- }
+ output := buf.String()
+
+ checkStringContains(t, output, echoCmd.Long)
+ checkStringContains(t, output, echoCmd.Example)
+ checkStringContains(t, output, "boolone")
+ checkStringContains(t, output, "rootflag")
+ checkStringContains(t, output, rootCmd.Short)
+ checkStringContains(t, output, echoSubCmd.Short)
+ checkStringOmits(t, output, deprecatedCmd.Short)
}
func TestGenMdNoTag(t *testing.T) {
- c := initializeWithRootCmd()
- // Need two commands to run the command alphabetical sort
- cmdEcho.AddCommand(cmdTimes, cmdEchoSub, cmdDeprecated)
- c.AddCommand(cmdPrint, cmdEcho)
- c.DisableAutoGenTag = true
- cmdRootWithRun.PersistentFlags().StringVarP(&flags2a, "rootflag", "r", "two", strtwoParentHelp)
- out := new(bytes.Buffer)
+ rootCmd.DisableAutoGenTag = true
+ defer func() { rootCmd.DisableAutoGenTag = false }()
- if err := GenMarkdown(c, out); err != nil {
+ buf := new(bytes.Buffer)
+ if err := GenMarkdown(rootCmd, buf); err != nil {
t.Fatal(err)
}
- found := out.String()
-
- unexpected := "Auto generated"
- checkStringOmits(t, found, unexpected)
+ output := buf.String()
+ checkStringOmits(t, output, "Auto generated")
}
func TestGenMdTree(t *testing.T) {
- cmd := &cobra.Command{
- Use: "do [OPTIONS] arg1 arg2",
- }
+ c := &cobra.Command{Use: "do [OPTIONS] arg1 arg2"}
tmpdir, err := ioutil.TempDir("", "test-gen-md-tree")
if err != nil {
- t.Fatalf("Failed to create tmpdir: %s", err.Error())
+ t.Fatalf("Failed to create tmpdir: %v", err)
}
defer os.RemoveAll(tmpdir)
- if err := GenMarkdownTree(cmd, tmpdir); err != nil {
- t.Fatalf("GenMarkdownTree failed: %s", err.Error())
+ if err := GenMarkdownTree(c, tmpdir); err != nil {
+ t.Fatalf("GenMarkdownTree failed: %v", err)
}
if _, err := os.Stat(filepath.Join(tmpdir, "do.md")); err != nil {
@@ -107,7 +58,6 @@ func TestGenMdTree(t *testing.T) {
}
func BenchmarkGenMarkdownToFile(b *testing.B) {
- c := initializeWithRootCmd()
file, err := ioutil.TempFile("", "")
if err != nil {
b.Fatal(err)
@@ -117,7 +67,7 @@ func BenchmarkGenMarkdownToFile(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
- if err := GenMarkdown(c, file); err != nil {
+ if err := GenMarkdown(rootCmd, file); err != nil {
b.Fatal(err)
}
}
diff --git a/vendor/github.com/spf13/cobra/doc/rest_docs.go b/vendor/github.com/spf13/cobra/doc/rest_docs.go
new file mode 100644
index 000000000..4913e3ee2
--- /dev/null
+++ b/vendor/github.com/spf13/cobra/doc/rest_docs.go
@@ -0,0 +1,185 @@
+//Copyright 2015 Red Hat Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package doc
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "os"
+ "path/filepath"
+ "sort"
+ "strings"
+ "time"
+
+ "github.com/spf13/cobra"
+)
+
+func printOptionsReST(buf *bytes.Buffer, cmd *cobra.Command, name string) error {
+ flags := cmd.NonInheritedFlags()
+ flags.SetOutput(buf)
+ if flags.HasFlags() {
+ buf.WriteString("Options\n")
+ buf.WriteString("~~~~~~~\n\n::\n\n")
+ flags.PrintDefaults()
+ buf.WriteString("\n")
+ }
+
+ parentFlags := cmd.InheritedFlags()
+ parentFlags.SetOutput(buf)
+ if parentFlags.HasFlags() {
+ buf.WriteString("Options inherited from parent commands\n")
+ buf.WriteString("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n::\n\n")
+ parentFlags.PrintDefaults()
+ buf.WriteString("\n")
+ }
+ return nil
+}
+
+// linkHandler for default ReST hyperlink markup
+func defaultLinkHandler(name, ref string) string {
+ return fmt.Sprintf("`%s <%s.rst>`_", name, ref)
+}
+
+// GenReST creates reStructured Text output.
+func GenReST(cmd *cobra.Command, w io.Writer) error {
+ return GenReSTCustom(cmd, w, defaultLinkHandler)
+}
+
+// GenReSTCustom creates custom reStructured Text output.
+func GenReSTCustom(cmd *cobra.Command, w io.Writer, linkHandler func(string, string) string) error {
+ cmd.InitDefaultHelpCmd()
+ cmd.InitDefaultHelpFlag()
+
+ buf := new(bytes.Buffer)
+ name := cmd.CommandPath()
+
+ short := cmd.Short
+ long := cmd.Long
+ if len(long) == 0 {
+ long = short
+ }
+ ref := strings.Replace(name, " ", "_", -1)
+
+ buf.WriteString(".. _" + ref + ":\n\n")
+ buf.WriteString(name + "\n")
+ buf.WriteString(strings.Repeat("-", len(name)) + "\n\n")
+ buf.WriteString(short + "\n\n")
+ buf.WriteString("Synopsis\n")
+ buf.WriteString("~~~~~~~~\n\n")
+ buf.WriteString("\n" + long + "\n\n")
+
+ if cmd.Runnable() {
+ buf.WriteString(fmt.Sprintf("::\n\n %s\n\n", cmd.UseLine()))
+ }
+
+ if len(cmd.Example) > 0 {
+ buf.WriteString("Examples\n")
+ buf.WriteString("~~~~~~~~\n\n")
+ buf.WriteString(fmt.Sprintf("::\n\n%s\n\n", indentString(cmd.Example, " ")))
+ }
+
+ if err := printOptionsReST(buf, cmd, name); err != nil {
+ return err
+ }
+ if hasSeeAlso(cmd) {
+ buf.WriteString("SEE ALSO\n")
+ buf.WriteString("~~~~~~~~\n\n")
+ if cmd.HasParent() {
+ parent := cmd.Parent()
+ pname := parent.CommandPath()
+ ref = strings.Replace(pname, " ", "_", -1)
+ buf.WriteString(fmt.Sprintf("* %s \t - %s\n", linkHandler(pname, ref), parent.Short))
+ cmd.VisitParents(func(c *cobra.Command) {
+ if c.DisableAutoGenTag {
+ cmd.DisableAutoGenTag = c.DisableAutoGenTag
+ }
+ })
+ }
+
+ children := cmd.Commands()
+ sort.Sort(byName(children))
+
+ for _, child := range children {
+ if !child.IsAvailableCommand() || child.IsAdditionalHelpTopicCommand() {
+ continue
+ }
+ cname := name + " " + child.Name()
+ ref = strings.Replace(cname, " ", "_", -1)
+ buf.WriteString(fmt.Sprintf("* %s \t - %s\n", linkHandler(cname, ref), child.Short))
+ }
+ buf.WriteString("\n")
+ }
+ if !cmd.DisableAutoGenTag {
+ buf.WriteString("*Auto generated by spf13/cobra on " + time.Now().Format("2-Jan-2006") + "*\n")
+ }
+ _, err := buf.WriteTo(w)
+ return err
+}
+
+// GenReSTTree will generate a ReST page for this command and all
+// descendants in the directory given.
+// This function may not work correctly if your command names have `-` in them.
+// If you have `cmd` with two subcmds, `sub` and `sub-third`,
+// and `sub` has a subcommand called `third`, it is undefined which
+// help output will be in the file `cmd-sub-third.1`.
+func GenReSTTree(cmd *cobra.Command, dir string) error {
+ emptyStr := func(s string) string { return "" }
+ return GenReSTTreeCustom(cmd, dir, emptyStr, defaultLinkHandler)
+}
+
+// GenReSTTreeCustom is the the same as GenReSTTree, but
+// with custom filePrepender and linkHandler.
+func GenReSTTreeCustom(cmd *cobra.Command, dir string, filePrepender func(string) string, linkHandler func(string, string) string) error {
+ for _, c := range cmd.Commands() {
+ if !c.IsAvailableCommand() || c.IsAdditionalHelpTopicCommand() {
+ continue
+ }
+ if err := GenReSTTreeCustom(c, dir, filePrepender, linkHandler); err != nil {
+ return err
+ }
+ }
+
+ basename := strings.Replace(cmd.CommandPath(), " ", "_", -1) + ".rst"
+ filename := filepath.Join(dir, basename)
+ f, err := os.Create(filename)
+ if err != nil {
+ return err
+ }
+ defer f.Close()
+
+ if _, err := io.WriteString(f, filePrepender(filename)); err != nil {
+ return err
+ }
+ if err := GenReSTCustom(cmd, f, linkHandler); err != nil {
+ return err
+ }
+ return nil
+}
+
+// adapted from: https://github.com/kr/text/blob/main/indent.go
+func indentString(s, p string) string {
+ var res []byte
+ b := []byte(s)
+ prefix := []byte(p)
+ bol := true
+ for _, c := range b {
+ if bol && c != '\n' {
+ res = append(res, prefix...)
+ }
+ res = append(res, c)
+ bol = c == '\n'
+ }
+ return string(res)
+}
diff --git a/vendor/github.com/spf13/cobra/doc/rest_docs.md b/vendor/github.com/spf13/cobra/doc/rest_docs.md
new file mode 100644
index 000000000..6098430ef
--- /dev/null
+++ b/vendor/github.com/spf13/cobra/doc/rest_docs.md
@@ -0,0 +1,114 @@
+# Generating ReStructured Text Docs For Your Own cobra.Command
+
+Generating ReST pages from a cobra command is incredibly easy. An example is as follows:
+
+```go
+package main
+
+import (
+ "log"
+
+ "github.com/spf13/cobra"
+ "github.com/spf13/cobra/doc"
+)
+
+func main() {
+ cmd := &cobra.Command{
+ Use: "test",
+ Short: "my test program",
+ }
+ err := doc.GenReSTTree(cmd, "/tmp")
+ if err != nil {
+ log.Fatal(err)
+ }
+}
+```
+
+That will get you a ReST document `/tmp/test.rst`
+
+## Generate ReST docs for the entire command tree
+
+This program can actually generate docs for the kubectl command in the kubernetes project
+
+```go
+package main
+
+import (
+ "log"
+ "io/ioutil"
+ "os"
+
+ "k8s.io/kubernetes/pkg/kubectl/cmd"
+ cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
+
+ "github.com/spf13/cobra/doc"
+)
+
+func main() {
+ kubectl := cmd.NewKubectlCommand(cmdutil.NewFactory(nil), os.Stdin, ioutil.Discard, ioutil.Discard)
+ err := doc.GenReSTTree(kubectl, "./")
+ if err != nil {
+ log.Fatal(err)
+ }
+}
+```
+
+This will generate a whole series of files, one for each command in the tree, in the directory specified (in this case "./")
+
+## Generate ReST docs for a single command
+
+You may wish to have more control over the output, or only generate for a single command, instead of the entire command tree. If this is the case you may prefer to `GenReST` instead of `GenReSTTree`
+
+```go
+ out := new(bytes.Buffer)
+ err := doc.GenReST(cmd, out)
+ if err != nil {
+ log.Fatal(err)
+ }
+```
+
+This will write the ReST doc for ONLY "cmd" into the out, buffer.
+
+## Customize the output
+
+Both `GenReST` and `GenReSTTree` have alternate versions with callbacks to get some control of the output:
+
+```go
+func GenReSTTreeCustom(cmd *Command, dir string, filePrepender func(string) string, linkHandler func(string, string) string) error {
+ //...
+}
+```
+
+```go
+func GenReSTCustom(cmd *Command, out *bytes.Buffer, linkHandler func(string, string) string) error {
+ //...
+}
+```
+
+The `filePrepender` will prepend the return value given the full filepath to the rendered ReST file. A common use case is to add front matter to use the generated documentation with [Hugo](http://gohugo.io/):
+
+```go
+const fmTemplate = `---
+date: %s
+title: "%s"
+slug: %s
+url: %s
+---
+`
+filePrepender := func(filename string) string {
+ now := time.Now().Format(time.RFC3339)
+ name := filepath.Base(filename)
+ base := strings.TrimSuffix(name, path.Ext(name))
+ url := "/commands/" + strings.ToLower(base) + "/"
+ return fmt.Sprintf(fmTemplate, now, strings.Replace(base, "_", " ", -1), base, url)
+}
+```
+
+The `linkHandler` can be used to customize the rendered links to the commands, given a command name and reference. This is useful while converting rst to html or while generating documentation with tools like Sphinx where `:ref:` is used:
+
+```go
+// Sphinx cross-referencing format
+linkHandler := func(name, ref string) string {
+ return fmt.Sprintf(":ref:`%s <%s>`", name, ref)
+}
+```
diff --git a/vendor/github.com/spf13/cobra/doc/rest_docs_test.go b/vendor/github.com/spf13/cobra/doc/rest_docs_test.go
new file mode 100644
index 000000000..aa3186e8f
--- /dev/null
+++ b/vendor/github.com/spf13/cobra/doc/rest_docs_test.go
@@ -0,0 +1,76 @@
+package doc
+
+import (
+ "bytes"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "testing"
+
+ "github.com/spf13/cobra"
+)
+
+func TestGenRSTDoc(t *testing.T) {
+ // We generate on a subcommand so we have both subcommands and parents
+ buf := new(bytes.Buffer)
+ if err := GenReST(echoCmd, buf); err != nil {
+ t.Fatal(err)
+ }
+ output := buf.String()
+
+ checkStringContains(t, output, echoCmd.Long)
+ checkStringContains(t, output, echoCmd.Example)
+ checkStringContains(t, output, "boolone")
+ checkStringContains(t, output, "rootflag")
+ checkStringContains(t, output, rootCmd.Short)
+ checkStringContains(t, output, echoSubCmd.Short)
+ checkStringOmits(t, output, deprecatedCmd.Short)
+}
+
+func TestGenRSTNoTag(t *testing.T) {
+ rootCmd.DisableAutoGenTag = true
+ defer func() { rootCmd.DisableAutoGenTag = false }()
+
+ buf := new(bytes.Buffer)
+ if err := GenReST(rootCmd, buf); err != nil {
+ t.Fatal(err)
+ }
+ output := buf.String()
+
+ unexpected := "Auto generated"
+ checkStringOmits(t, output, unexpected)
+}
+
+func TestGenRSTTree(t *testing.T) {
+ c := &cobra.Command{Use: "do [OPTIONS] arg1 arg2"}
+
+ tmpdir, err := ioutil.TempDir("", "test-gen-rst-tree")
+ if err != nil {
+ t.Fatalf("Failed to create tmpdir: %s", err.Error())
+ }
+ defer os.RemoveAll(tmpdir)
+
+ if err := GenReSTTree(c, tmpdir); err != nil {
+ t.Fatalf("GenReSTTree failed: %s", err.Error())
+ }
+
+ if _, err := os.Stat(filepath.Join(tmpdir, "do.rst")); err != nil {
+ t.Fatalf("Expected file 'do.rst' to exist")
+ }
+}
+
+func BenchmarkGenReSTToFile(b *testing.B) {
+ file, err := ioutil.TempFile("", "")
+ if err != nil {
+ b.Fatal(err)
+ }
+ defer os.Remove(file.Name())
+ defer file.Close()
+
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ if err := GenReST(rootCmd, file); err != nil {
+ b.Fatal(err)
+ }
+ }
+}
diff --git a/vendor/github.com/spf13/cobra/doc/yaml_docs_test.go b/vendor/github.com/spf13/cobra/doc/yaml_docs_test.go
index 29e985e40..c5a63594f 100644
--- a/vendor/github.com/spf13/cobra/doc/yaml_docs_test.go
+++ b/vendor/github.com/spf13/cobra/doc/yaml_docs_test.go
@@ -5,92 +5,42 @@ import (
"io/ioutil"
"os"
"path/filepath"
- "strings"
"testing"
"github.com/spf13/cobra"
)
func TestGenYamlDoc(t *testing.T) {
- c := initializeWithRootCmd()
- // Need two commands to run the command alphabetical sort
- cmdEcho.AddCommand(cmdTimes, cmdEchoSub, cmdDeprecated)
- c.AddCommand(cmdPrint, cmdEcho)
- cmdRootWithRun.PersistentFlags().StringVarP(&flags2a, "rootflag", "r", "two", strtwoParentHelp)
-
- out := new(bytes.Buffer)
-
// We generate on s subcommand so we have both subcommands and parents
- if err := GenYaml(cmdEcho, out); err != nil {
+ buf := new(bytes.Buffer)
+ if err := GenYaml(echoCmd, buf); err != nil {
t.Fatal(err)
}
- found := out.String()
-
- // Our description
- expected := cmdEcho.Long
- if !strings.Contains(found, expected) {
- t.Errorf("Unexpected response.\nExpecting to contain: \n %q\nGot:\n %q\n", expected, found)
- }
-
- // Better have our example
- expected = cmdEcho.Example
- if !strings.Contains(found, expected) {
- t.Errorf("Unexpected response.\nExpecting to contain: \n %q\nGot:\n %q\n", expected, found)
- }
-
- // A local flag
- expected = "boolone"
- if !strings.Contains(found, expected) {
- t.Errorf("Unexpected response.\nExpecting to contain: \n %q\nGot:\n %q\n", expected, found)
- }
-
- // persistent flag on parent
- expected = "rootflag"
- if !strings.Contains(found, expected) {
- t.Errorf("Unexpected response.\nExpecting to contain: \n %q\nGot:\n %q\n", expected, found)
- }
-
- // We better output info about our parent
- expected = cmdRootWithRun.Short
- if !strings.Contains(found, expected) {
- t.Errorf("Unexpected response.\nExpecting to contain: \n %q\nGot:\n %q\n", expected, found)
- }
-
- // And about subcommands
- expected = cmdEchoSub.Short
- if !strings.Contains(found, expected) {
- t.Errorf("Unexpected response.\nExpecting to contain: \n %q\nGot:\n %q\n", expected, found)
- }
-
- unexpected := cmdDeprecated.Short
- if strings.Contains(found, unexpected) {
- t.Errorf("Unexpected response.\nFound: %v\nBut should not have!!\n", unexpected)
- }
+ output := buf.String()
+
+ checkStringContains(t, output, echoCmd.Long)
+ checkStringContains(t, output, echoCmd.Example)
+ checkStringContains(t, output, "boolone")
+ checkStringContains(t, output, "rootflag")
+ checkStringContains(t, output, rootCmd.Short)
+ checkStringContains(t, output, echoSubCmd.Short)
}
func TestGenYamlNoTag(t *testing.T) {
- c := initializeWithRootCmd()
- // Need two commands to run the command alphabetical sort
- cmdEcho.AddCommand(cmdTimes, cmdEchoSub, cmdDeprecated)
- c.AddCommand(cmdPrint, cmdEcho)
- c.DisableAutoGenTag = true
- cmdRootWithRun.PersistentFlags().StringVarP(&flags2a, "rootflag", "r", "two", strtwoParentHelp)
- out := new(bytes.Buffer)
+ rootCmd.DisableAutoGenTag = true
+ defer func() { rootCmd.DisableAutoGenTag = false }()
- if err := GenYaml(c, out); err != nil {
+ buf := new(bytes.Buffer)
+ if err := GenYaml(rootCmd, buf); err != nil {
t.Fatal(err)
}
- found := out.String()
-
- unexpected := "Auto generated"
- checkStringOmits(t, found, unexpected)
+ output := buf.String()
+ checkStringOmits(t, output, "Auto generated")
}
func TestGenYamlTree(t *testing.T) {
- cmd := &cobra.Command{
- Use: "do [OPTIONS] arg1 arg2",
- }
+ c := &cobra.Command{Use: "do [OPTIONS] arg1 arg2"}
tmpdir, err := ioutil.TempDir("", "test-gen-yaml-tree")
if err != nil {
@@ -98,7 +48,7 @@ func TestGenYamlTree(t *testing.T) {
}
defer os.RemoveAll(tmpdir)
- if err := GenYamlTree(cmd, tmpdir); err != nil {
+ if err := GenYamlTree(c, tmpdir); err != nil {
t.Fatalf("GenYamlTree failed: %s", err.Error())
}
@@ -108,7 +58,6 @@ func TestGenYamlTree(t *testing.T) {
}
func BenchmarkGenYamlToFile(b *testing.B) {
- c := initializeWithRootCmd()
file, err := ioutil.TempFile("", "")
if err != nil {
b.Fatal(err)
@@ -118,7 +67,7 @@ func BenchmarkGenYamlToFile(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
- if err := GenYaml(c, file); err != nil {
+ if err := GenYaml(rootCmd, file); err != nil {
b.Fatal(err)
}
}
diff --git a/vendor/github.com/spf13/cobra/zsh_completions_test.go b/vendor/github.com/spf13/cobra/zsh_completions_test.go
index 08b851591..34e69496f 100644
--- a/vendor/github.com/spf13/cobra/zsh_completions_test.go
+++ b/vendor/github.com/spf13/cobra/zsh_completions_test.go
@@ -77,10 +77,11 @@ func TestZshCompletion(t *testing.T) {
t.Run(tc.name, func(t *testing.T) {
buf := new(bytes.Buffer)
tc.root.GenZshCompletion(buf)
- completion := buf.String()
+ output := buf.String()
+
for _, expectedExpression := range tc.expectedExpressions {
- if !strings.Contains(completion, expectedExpression) {
- t.Errorf("expected completion to contain '%v' somewhere; got '%v'", expectedExpression, completion)
+ if !strings.Contains(output, expectedExpression) {
+ t.Errorf("Expected completion to contain %q somewhere; got %q", expectedExpression, output)
}
}
})
diff --git a/vendor/github.com/spf13/viper/README.md b/vendor/github.com/spf13/viper/README.md
index 848d92d6b..64bf47435 100644
--- a/vendor/github.com/spf13/viper/README.md
+++ b/vendor/github.com/spf13/viper/README.md
@@ -185,7 +185,7 @@ with ENV:
* `AutomaticEnv()`
* `BindEnv(string...) : error`
* `SetEnvPrefix(string)`
- * `SetEnvReplacer(string...) *strings.Replacer`
+ * `SetEnvKeyReplacer(string...) *strings.Replacer`
_When working with ENV variables, it’s important to recognize that Viper
treats ENV variables as case sensitive._
@@ -212,7 +212,7 @@ time a `viper.Get` request is made. It will apply the following rules. It will
check for a environment variable with a name matching the key uppercased and
prefixed with the `EnvPrefix` if set.
-`SetEnvReplacer` allows you to use a `strings.Replacer` object to rewrite Env
+`SetEnvKeyReplacer` allows you to use a `strings.Replacer` object to rewrite Env
keys to an extent. This is useful if you want to use `-` or something in your
`Get()` calls, but want your environmental variables to use `_` delimiters. An
example of using it can be found in `viper_test.go`.
diff --git a/vendor/github.com/spf13/viper/util.go b/vendor/github.com/spf13/viper/util.go
index 3ebada91a..c784dad40 100644
--- a/vendor/github.com/spf13/viper/util.go
+++ b/vendor/github.com/spf13/viper/util.go
@@ -24,6 +24,7 @@ import (
"github.com/hashicorp/hcl"
"github.com/magiconair/properties"
toml "github.com/pelletier/go-toml"
+ "github.com/spf13/afero"
"github.com/spf13/cast"
jww "github.com/spf13/jwalterweatherman"
"gopkg.in/yaml.v2"
@@ -121,8 +122,8 @@ func absPathify(inPath string) string {
}
// Check if File / Directory Exists
-func exists(path string) (bool, error) {
- _, err := v.fs.Stat(path)
+func exists(fs afero.Fs, path string) (bool, error) {
+ _, err := fs.Stat(path)
if err == nil {
return true, nil
}
diff --git a/vendor/github.com/spf13/viper/viper.go b/vendor/github.com/spf13/viper/viper.go
index 2a221e53c..64f006a39 100644
--- a/vendor/github.com/spf13/viper/viper.go
+++ b/vendor/github.com/spf13/viper/viper.go
@@ -747,13 +747,16 @@ func (v *Viper) Unmarshal(rawVal interface{}) error {
}
// defaultDecoderConfig returns default mapsstructure.DecoderConfig with suppot
-// of time.Duration values
+// of time.Duration values & string slices
func defaultDecoderConfig(output interface{}) *mapstructure.DecoderConfig {
return &mapstructure.DecoderConfig{
Metadata: nil,
Result: output,
WeaklyTypedInput: true,
- DecodeHook: mapstructure.StringToTimeDurationHookFunc(),
+ DecodeHook: mapstructure.ComposeDecodeHookFunc(
+ mapstructure.StringToTimeDurationHookFunc(),
+ mapstructure.StringToSliceHookFunc(","),
+ ),
}
}
@@ -1534,7 +1537,7 @@ func (v *Viper) searchInPath(in string) (filename string) {
jww.DEBUG.Println("Searching for config in ", in)
for _, ext := range SupportedExts {
jww.DEBUG.Println("Checking for", filepath.Join(in, v.configName+"."+ext))
- if b, _ := exists(filepath.Join(in, v.configName+"."+ext)); b {
+ if b, _ := exists(v.fs, filepath.Join(in, v.configName+"."+ext)); b {
jww.DEBUG.Println("Found: ", filepath.Join(in, v.configName+"."+ext))
return filepath.Join(in, v.configName+"."+ext)
}
diff --git a/vendor/github.com/spf13/viper/viper_test.go b/vendor/github.com/spf13/viper/viper_test.go
index 774ca1168..7050d5abd 100644
--- a/vendor/github.com/spf13/viper/viper_test.go
+++ b/vendor/github.com/spf13/viper/viper_test.go
@@ -417,7 +417,7 @@ func TestAutoEnvWithPrefix(t *testing.T) {
assert.Equal(t, "13", Get("bar"))
}
-func TestSetEnvReplacer(t *testing.T) {
+func TestSetEnvKeyReplacer(t *testing.T) {
Reset()
AutomaticEnv()
diff --git a/vendor/github.com/xenolf/lego/.travis.yml b/vendor/github.com/xenolf/lego/.travis.yml
index ff9ae963a..8cf9aed1b 100644
--- a/vendor/github.com/xenolf/lego/.travis.yml
+++ b/vendor/github.com/xenolf/lego/.travis.yml
@@ -1,7 +1,7 @@
language: go
go:
-- 1.7
- 1.8
+- 1.9
- tip
services:
- memcached
diff --git a/vendor/github.com/xenolf/lego/acme/dns_challenge.go b/vendor/github.com/xenolf/lego/acme/dns_challenge.go
index 7c4cb80de..133739748 100644
--- a/vendor/github.com/xenolf/lego/acme/dns_challenge.go
+++ b/vendor/github.com/xenolf/lego/acme/dns_challenge.go
@@ -11,7 +11,6 @@ import (
"time"
"github.com/miekg/dns"
- "golang.org/x/net/publicsuffix"
)
type preCheckDNSFunc func(fqdn, value string) (bool, error)
@@ -242,10 +241,6 @@ func FindZoneByFqdn(fqdn string, nameservers []string) (string, error) {
labelIndexes := dns.Split(fqdn)
for _, index := range labelIndexes {
domain := fqdn[index:]
- // Give up if we have reached the TLD
- if isTLD(domain) {
- break
- }
in, err := dnsQuery(domain, dns.TypeSOA, nameservers, true)
if err != nil {
@@ -273,14 +268,6 @@ func FindZoneByFqdn(fqdn string, nameservers []string) (string, error) {
return "", fmt.Errorf("Could not find the start of authority")
}
-func isTLD(domain string) bool {
- publicsuffix, _ := publicsuffix.PublicSuffix(UnFqdn(domain))
- if publicsuffix == UnFqdn(domain) {
- return true
- }
- return false
-}
-
// ClearFqdnCache clears the cache of fqdn to zone mappings. Primarily used in testing.
func ClearFqdnCache() {
fqdnToZone = map[string]string{}
diff --git a/vendor/github.com/xenolf/lego/acme/dns_challenge_test.go b/vendor/github.com/xenolf/lego/acme/dns_challenge_test.go
index 597aaac17..4a2a7feac 100644
--- a/vendor/github.com/xenolf/lego/acme/dns_challenge_test.go
+++ b/vendor/github.com/xenolf/lego/acme/dns_challenge_test.go
@@ -37,14 +37,6 @@ var lookupNameserversTestsErr = []struct {
{"_null.n0n0.",
"Could not determine the zone",
},
- // invalid domain
- {"_null.com.",
- "Could not determine the zone",
- },
- // invalid domain
- {"in-valid.co.uk.",
- "Could not determine the zone",
- },
}
var findZoneByFqdnTests = []struct {
@@ -53,6 +45,7 @@ var findZoneByFqdnTests = []struct {
}{
{"mail.google.com.", "google.com."}, // domain is a CNAME
{"foo.google.com.", "google.com."}, // domain is a non-existent subdomain
+ {"example.com.ac.", "ac."}, // domain is a eTLD
}
var checkAuthoritativeNssTests = []struct {
diff --git a/vendor/github.com/xenolf/lego/cli_handlers.go b/vendor/github.com/xenolf/lego/cli_handlers.go
index 79bbb37e5..b8790c4b2 100644
--- a/vendor/github.com/xenolf/lego/cli_handlers.go
+++ b/vendor/github.com/xenolf/lego/cli_handlers.go
@@ -329,8 +329,10 @@ func run(c *cli.Context) error {
}
func revoke(c *cli.Context) error {
-
- conf, _, client := setup(c)
+ conf, acc, client := setup(c)
+ if acc.Registration == nil {
+ logger().Fatalf("Account %s is not registered. Use 'run' to register a new account.\n", acc.Email)
+ }
err := checkFolder(conf.CertPath())
if err != nil {
@@ -355,7 +357,10 @@ func revoke(c *cli.Context) error {
}
func renew(c *cli.Context) error {
- conf, _, client := setup(c)
+ conf, acc, client := setup(c)
+ if acc.Registration == nil {
+ logger().Fatalf("Account %s is not registered. Use 'run' to register a new account.\n", acc.Email)
+ }
if len(c.GlobalStringSlice("domains")) <= 0 {
logger().Fatal("Please specify at least one domain.")
diff --git a/vendor/github.com/xenolf/lego/providers/dns/dns_providers.go b/vendor/github.com/xenolf/lego/providers/dns/dns_providers.go
index 94c8879b2..d7530f788 100644
--- a/vendor/github.com/xenolf/lego/providers/dns/dns_providers.go
+++ b/vendor/github.com/xenolf/lego/providers/dns/dns_providers.go
@@ -15,6 +15,7 @@ import (
"github.com/xenolf/lego/providers/dns/dyn"
"github.com/xenolf/lego/providers/dns/exoscale"
"github.com/xenolf/lego/providers/dns/gandi"
+ "github.com/xenolf/lego/providers/dns/godaddy"
"github.com/xenolf/lego/providers/dns/googlecloud"
"github.com/xenolf/lego/providers/dns/linode"
"github.com/xenolf/lego/providers/dns/namecheap"
@@ -54,6 +55,8 @@ func NewDNSChallengeProviderByName(name string) (acme.ChallengeProvider, error)
provider, err = gandi.NewDNSProvider()
case "gcloud":
provider, err = googlecloud.NewDNSProvider()
+ case "godaddy":
+ provider, err = godaddy.NewDNSProvider()
case "linode":
provider, err = linode.NewDNSProvider()
case "manual":
diff --git a/vendor/github.com/xenolf/lego/providers/dns/godaddy/godaddy.go b/vendor/github.com/xenolf/lego/providers/dns/godaddy/godaddy.go
new file mode 100644
index 000000000..4112f6628
--- /dev/null
+++ b/vendor/github.com/xenolf/lego/providers/dns/godaddy/godaddy.go
@@ -0,0 +1,155 @@
+// Package godaddy implements a DNS provider for solving the DNS-01 challenge using godaddy DNS.
+package godaddy
+
+import (
+ "fmt"
+ "io"
+ "net/http"
+ "os"
+ "time"
+
+ "bytes"
+ "encoding/json"
+ "github.com/xenolf/lego/acme"
+ "io/ioutil"
+ "strings"
+)
+
+// GoDaddyAPIURL represents the API endpoint to call.
+const apiURL = "https://api.godaddy.com"
+
+// DNSProvider is an implementation of the acme.ChallengeProvider interface
+type DNSProvider struct {
+ apiKey string
+ apiSecret string
+}
+
+// NewDNSProvider returns a DNSProvider instance configured for godaddy.
+// Credentials must be passed in the environment variables: GODADDY_API_KEY
+// and GODADDY_API_SECRET.
+func NewDNSProvider() (*DNSProvider, error) {
+ apikey := os.Getenv("GODADDY_API_KEY")
+ secret := os.Getenv("GODADDY_API_SECRET")
+ return NewDNSProviderCredentials(apikey, secret)
+}
+
+// NewDNSProviderCredentials uses the supplied credentials to return a
+// DNSProvider instance configured for godaddy.
+func NewDNSProviderCredentials(apiKey, apiSecret string) (*DNSProvider, error) {
+ if apiKey == "" || apiSecret == "" {
+ return nil, fmt.Errorf("GoDaddy credentials missing")
+ }
+
+ return &DNSProvider{apiKey, apiSecret}, nil
+}
+
+// Timeout returns the timeout and interval to use when checking for DNS
+// propagation. Adjusting here to cope with spikes in propagation times.
+func (c *DNSProvider) Timeout() (timeout, interval time.Duration) {
+ return 120 * time.Second, 2 * time.Second
+}
+
+func (c *DNSProvider) extractRecordName(fqdn, domain string) string {
+ name := acme.UnFqdn(fqdn)
+ if idx := strings.Index(name, "."+domain); idx != -1 {
+ return name[:idx]
+ }
+ return name
+}
+
+// Present creates a TXT record to fulfil the dns-01 challenge
+func (c *DNSProvider) Present(domain, token, keyAuth string) error {
+ fqdn, value, ttl := acme.DNS01Record(domain, keyAuth)
+ domainZone, err := c.getZone(fqdn)
+ if err != nil {
+ return err
+ }
+
+ if ttl < 600 {
+ ttl = 600
+ }
+
+ recordName := c.extractRecordName(fqdn, domainZone)
+ rec := []DNSRecord{
+ {
+ Type: "TXT",
+ Name: recordName,
+ Data: value,
+ Ttl: ttl,
+ },
+ }
+
+ return c.updateRecords(rec, domainZone, recordName)
+}
+
+func (c *DNSProvider) updateRecords(records []DNSRecord, domainZone string, recordName string) error {
+ body, err := json.Marshal(records)
+ if err != nil {
+ return err
+ }
+
+ var resp *http.Response
+ resp, err = c.makeRequest("PUT", fmt.Sprintf("/v1/domains/%s/records/TXT/%s", domainZone, recordName), bytes.NewReader(body))
+ if err != nil {
+ return err
+ }
+
+ defer resp.Body.Close()
+
+ if resp.StatusCode != http.StatusOK {
+ bodyBytes, _ := ioutil.ReadAll(resp.Body)
+ return fmt.Errorf("Could not create record %v; Status: %v; Body: %s\n", string(body), resp.StatusCode, string(bodyBytes))
+ }
+ return nil
+}
+
+// CleanUp sets null value in the TXT DNS record as GoDaddy has no proper DELETE record method
+func (c *DNSProvider) CleanUp(domain, token, keyAuth string) error {
+ fqdn, _, _ := acme.DNS01Record(domain, keyAuth)
+ domainZone, err := c.getZone(fqdn)
+ if err != nil {
+ return err
+ }
+
+ recordName := c.extractRecordName(fqdn, domainZone)
+ rec := []DNSRecord{
+ {
+ Type: "TXT",
+ Name: recordName,
+ Data: "null",
+ },
+ }
+
+ return c.updateRecords(rec, domainZone, recordName)
+}
+
+func (c *DNSProvider) getZone(fqdn string) (string, error) {
+ authZone, err := acme.FindZoneByFqdn(fqdn, acme.RecursiveNameservers)
+ if err != nil {
+ return "", err
+ }
+
+ return acme.UnFqdn(authZone), nil
+}
+
+func (c *DNSProvider) makeRequest(method, uri string, body io.Reader) (*http.Response, error) {
+ req, err := http.NewRequest(method, fmt.Sprintf("%s%s", apiURL, uri), body)
+ if err != nil {
+ return nil, err
+ }
+
+ req.Header.Set("Accept", "application/json")
+ req.Header.Set("Content-Type", "application/json")
+ req.Header.Set("Authorization", fmt.Sprintf("sso-key %s:%s", c.apiKey, c.apiSecret))
+
+ client := http.Client{Timeout: 30 * time.Second}
+ return client.Do(req)
+}
+
+type DNSRecord struct {
+ Type string `json:"type"`
+ Name string `json:"name"`
+ Data string `json:"data"`
+ Priority int `json:"priority,omitempty"`
+ Ttl int `json:"ttl,omitempty"`
+}
diff --git a/vendor/github.com/xenolf/lego/providers/dns/godaddy/godaddy_test.go b/vendor/github.com/xenolf/lego/providers/dns/godaddy/godaddy_test.go
new file mode 100644
index 000000000..de84d827e
--- /dev/null
+++ b/vendor/github.com/xenolf/lego/providers/dns/godaddy/godaddy_test.go
@@ -0,0 +1,60 @@
+package godaddy
+
+import (
+ "os"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+var (
+ godaddyAPIKey string
+ godaddyAPISecret string
+ godaddyDomain string
+ godaddyLiveTest bool
+)
+
+func init() {
+ godaddyAPIKey = os.Getenv("GODADDY_API_KEY")
+ godaddyAPISecret = os.Getenv("GODADDY_API_SECRET")
+ godaddyDomain = os.Getenv("GODADDY_DOMAIN")
+
+ if len(godaddyAPIKey) > 0 && len(godaddyAPISecret) > 0 && len(godaddyDomain) > 0 {
+ godaddyLiveTest = true
+ }
+}
+
+func TestNewDNSProvider(t *testing.T) {
+ provider, err := NewDNSProvider()
+
+ if !godaddyLiveTest {
+ assert.Error(t, err)
+ } else {
+ assert.NotNil(t, provider)
+ assert.NoError(t, err)
+ }
+}
+
+func TestDNSProvider_Present(t *testing.T) {
+ if !godaddyLiveTest {
+ t.Skip("skipping live test")
+ }
+
+ provider, err := NewDNSProvider()
+ assert.NoError(t, err)
+
+ err = provider.Present(godaddyDomain, "", "123d==")
+ assert.NoError(t, err)
+}
+
+func TestDNSProvider_CleanUp(t *testing.T) {
+ if !godaddyLiveTest {
+ t.Skip("skipping live test")
+ }
+
+ provider, err := NewDNSProvider()
+ assert.NoError(t, err)
+
+ err = provider.CleanUp(godaddyDomain, "", "123d==")
+ assert.NoError(t, err)
+}