diff --git a/.bazelrc b/.bazelrc
new file mode 100644
index 00000000000..37beb544be0
--- /dev/null
+++ b/.bazelrc
@@ -0,0 +1,3 @@
+build --workspace_status_command=./print-workspace-status.sh
+run --workspace_status_command=./print-workspace-status.sh
+test -c dbg --test_output=errors
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index a1338d68517..ac51a054d2d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,14 +1 @@
-# Binaries for programs and plugins
-*.exe
-*.dll
-*.so
-*.dylib
-
-# Test binary, build with `go test -c`
-*.test
-
-# Output of the go coverage tool, specifically when used with LiteIDE
-*.out
-
-# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736
-.glide/
+bazel-*
diff --git a/BUILD b/BUILD
new file mode 100644
index 00000000000..ef3ba31818f
--- /dev/null
+++ b/BUILD
@@ -0,0 +1,70 @@
+load("@io_bazel_rules_go//go:def.bzl", "gazelle", "go_prefix")
+
+go_prefix("github.com/elafros/binding")
+
+gazelle(
+ name = "gazelle",
+ external = "vendored",
+)
+
+load("@k8s_object//:defaults.bzl", "k8s_object")
+
+k8s_object(
+ name = "controller",
+ images = {
+ "bind-controller:latest": "//cmd/controller:image",
+ },
+ template = "controller.yaml",
+)
+
+k8s_object(
+ name = "namespace",
+ template = "namespace.yaml",
+)
+
+k8s_object(
+ name = "serviceaccount",
+ template = "serviceaccount.yaml",
+)
+
+k8s_object(
+ name = "clusterrolebinding",
+ template = "clusterrolebinding.yaml",
+)
+
+k8s_object(
+ name = "bind",
+ template = "bind.yaml",
+)
+
+k8s_object(
+ name = "eventtype",
+ template = "eventtype.yaml",
+)
+
+k8s_object(
+ name = "eventsource",
+ template = "eventsource.yaml",
+)
+
+load("@io_bazel_rules_k8s//k8s:objects.bzl", "k8s_objects")
+
+k8s_objects(
+ name = "authz",
+ objects = [
+ ":serviceaccount",
+ ":clusterrolebinding",
+ ],
+)
+
+k8s_objects(
+ name = "everything",
+ objects = [
+ ":namespace",
+ ":authz",
+ ":bind",
+ ":eventtype",
+ ":eventsource",
+ ":controller",
+ ],
+)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 00000000000..0786fdf4346
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,24 @@
+# How to contribute
+
+We'd love to accept your patches and contributions to this project. There are
+just a few small guidelines you need to follow.
+
+## Contributor License Agreement
+
+Contributions to this project must be accompanied by a Contributor License
+Agreement. You (or your employer) retain the copyright to your contribution,
+this simply gives us permission to use and redistribute your contributions as
+part of the project. Head over to to see
+your current agreements on file or to sign a new one.
+
+You generally only need to submit a CLA once, so if you've already submitted one
+(even if it was for a different project), you probably don't need to do it
+again.
+
+## Code reviews
+
+All submissions, including submissions by project members, require review. We
+use GitHub pull requests for this purpose. Consult [GitHub Help] for more
+information on using pull requests.
+
+[GitHub Help]: https://help.github.com/articles/about-pull-requests/
diff --git a/Gopkg.lock b/Gopkg.lock
new file mode 100644
index 00000000000..b8b3d57baeb
--- /dev/null
+++ b/Gopkg.lock
@@ -0,0 +1,669 @@
+# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
+
+
+[[projects]]
+ name = "cloud.google.com/go"
+ packages = ["compute/metadata"]
+ revision = "20d4028b8a750c2aca76bf9fefa8ed2d0109b573"
+ version = "v0.19.0"
+
+[[projects]]
+ name = "github.com/PuerkitoBio/purell"
+ packages = ["."]
+ revision = "0bcb03f4b4d0a9428594752bd2a3b9aa0a9d4bd4"
+ version = "v1.1.0"
+
+[[projects]]
+ branch = "master"
+ name = "github.com/PuerkitoBio/urlesc"
+ packages = ["."]
+ revision = "de5bf2ad457846296e2031421a34e2568e304e35"
+
+[[projects]]
+ branch = "master"
+ name = "github.com/beorn7/perks"
+ packages = ["quantile"]
+ revision = "4c0e84591b9aa9e6dcfdf3e020114cd81f89d5f9"
+
+[[projects]]
+ name = "github.com/davecgh/go-spew"
+ packages = ["spew"]
+ revision = "346938d642f2ec3594ed81d874461961cd0faa76"
+ version = "v1.1.0"
+
+[[projects]]
+ branch = "master"
+ name = "github.com/elafros/elafros"
+ packages = [
+ "pkg/apis/cloudbuild",
+ "pkg/apis/cloudbuild/v1alpha1",
+ "pkg/apis/ela",
+ "pkg/apis/ela/v1alpha1",
+ "pkg/apis/istio",
+ "pkg/apis/istio/v1alpha2",
+ "pkg/client/clientset/versioned",
+ "pkg/client/clientset/versioned/scheme",
+ "pkg/client/clientset/versioned/typed/cloudbuild/v1alpha1",
+ "pkg/client/clientset/versioned/typed/ela/v1alpha1",
+ "pkg/client/clientset/versioned/typed/istio/v1alpha2",
+ "pkg/client/informers/externalversions",
+ "pkg/client/informers/externalversions/cloudbuild",
+ "pkg/client/informers/externalversions/cloudbuild/v1alpha1",
+ "pkg/client/informers/externalversions/ela",
+ "pkg/client/informers/externalversions/ela/v1alpha1",
+ "pkg/client/informers/externalversions/internalinterfaces",
+ "pkg/client/informers/externalversions/istio",
+ "pkg/client/informers/externalversions/istio/v1alpha2",
+ "pkg/client/listers/cloudbuild/v1alpha1",
+ "pkg/client/listers/ela/v1alpha1",
+ "pkg/client/listers/istio/v1alpha2"
+ ]
+ revision = "2e915f9e8b7ba9d8c87e32b4406fec13b22be2c8"
+
+[[projects]]
+ name = "github.com/emicklei/go-restful"
+ packages = [
+ ".",
+ "log"
+ ]
+ revision = "26b41036311f2da8242db402557a0dbd09dc83da"
+ version = "v2.6.0"
+
+[[projects]]
+ name = "github.com/ghodss/yaml"
+ packages = ["."]
+ revision = "0ca9ea5df5451ffdf184b4428c902747c2c11cd7"
+ version = "v1.0.0"
+
+[[projects]]
+ branch = "master"
+ name = "github.com/go-openapi/jsonpointer"
+ packages = ["."]
+ revision = "779f45308c19820f1a69e9a4cd965f496e0da10f"
+
+[[projects]]
+ branch = "master"
+ name = "github.com/go-openapi/jsonreference"
+ packages = ["."]
+ revision = "36d33bfe519efae5632669801b180bf1a245da3b"
+
+[[projects]]
+ branch = "master"
+ name = "github.com/go-openapi/spec"
+ packages = ["."]
+ revision = "1de3e0542de65ad8d75452a595886fdd0befb363"
+
+[[projects]]
+ branch = "master"
+ name = "github.com/go-openapi/swag"
+ packages = ["."]
+ revision = "0d03ad0b6405ada874d59d97c416b5cf4234e154"
+
+[[projects]]
+ name = "github.com/gogo/protobuf"
+ packages = [
+ "proto",
+ "sortkeys"
+ ]
+ revision = "1adfc126b41513cc696b209667c8656ea7aac67c"
+ version = "v1.0.0"
+
+[[projects]]
+ branch = "master"
+ name = "github.com/golang/glog"
+ packages = ["."]
+ revision = "23def4e6c14b4da8ac2ed8007337bc5eb5007998"
+
+[[projects]]
+ branch = "master"
+ name = "github.com/golang/groupcache"
+ packages = ["lru"]
+ revision = "66deaeb636dff1ac7d938ce666d090556056a4b0"
+
+[[projects]]
+ name = "github.com/golang/protobuf"
+ packages = [
+ "proto",
+ "ptypes",
+ "ptypes/any",
+ "ptypes/duration",
+ "ptypes/timestamp"
+ ]
+ revision = "925541529c1fa6821df4e44ce2723319eb2be768"
+ version = "v1.0.0"
+
+[[projects]]
+ branch = "master"
+ name = "github.com/google/btree"
+ packages = ["."]
+ revision = "e89373fe6b4a7413d7acd6da1725b83ef713e6e4"
+
+[[projects]]
+ name = "github.com/google/go-github"
+ packages = ["github"]
+ revision = "e48060a28fac52d0f1cb758bc8b87c07bac4a87d"
+ version = "v15.0.0"
+
+[[projects]]
+ branch = "master"
+ name = "github.com/google/go-querystring"
+ packages = ["query"]
+ revision = "53e6ce116135b80d037921a7fdd5138cf32d7a8a"
+
+[[projects]]
+ branch = "master"
+ name = "github.com/google/gofuzz"
+ packages = ["."]
+ revision = "24818f796faf91cd76ec7bddd72458fbced7a6c1"
+
+[[projects]]
+ name = "github.com/googleapis/gnostic"
+ packages = [
+ "OpenAPIv2",
+ "compiler",
+ "extensions"
+ ]
+ revision = "ee43cbb60db7bd22502942cccbc39059117352ab"
+ version = "v0.1.0"
+
+[[projects]]
+ branch = "master"
+ name = "github.com/gregjones/httpcache"
+ packages = [
+ ".",
+ "diskcache"
+ ]
+ revision = "2bcd89a1743fd4b373f7370ce8ddc14dfbd18229"
+
+[[projects]]
+ branch = "master"
+ name = "github.com/hashicorp/golang-lru"
+ packages = [
+ ".",
+ "simplelru"
+ ]
+ revision = "0fb14efe8c47ae851c0034ed7a448854d3d34cf3"
+
+[[projects]]
+ branch = "master"
+ name = "github.com/howeyc/gopass"
+ packages = ["."]
+ revision = "bf9dde6d0d2c004a008c27aaee91170c786f6db8"
+
+[[projects]]
+ name = "github.com/imdario/mergo"
+ packages = ["."]
+ revision = "163f41321a19dd09362d4c63cc2489db2015f1f4"
+ version = "0.3.2"
+
+[[projects]]
+ name = "github.com/json-iterator/go"
+ packages = ["."]
+ revision = "3353055b2a1a5ae1b6a8dfde887a524e7088f3a2"
+ version = "1.1.2"
+
+[[projects]]
+ name = "github.com/juju/ratelimit"
+ packages = ["."]
+ revision = "59fac5042749a5afb9af70e813da1dd5474f0167"
+ version = "1.0.1"
+
+[[projects]]
+ branch = "master"
+ name = "github.com/mailru/easyjson"
+ packages = [
+ "buffer",
+ "jlexer",
+ "jwriter"
+ ]
+ revision = "32fa128f234d041f196a9f3e0fea5ac9772c08e1"
+
+[[projects]]
+ name = "github.com/matttproud/golang_protobuf_extensions"
+ packages = ["pbutil"]
+ revision = "3247c84500bff8d9fb6d579d800f20b3e091582c"
+ version = "v1.0.0"
+
+[[projects]]
+ name = "github.com/modern-go/concurrent"
+ packages = ["."]
+ revision = "e0a39a4cb4216ea8db28e22a69f4ec25610d513a"
+ version = "1.0.0"
+
+[[projects]]
+ name = "github.com/modern-go/reflect2"
+ packages = ["."]
+ revision = "1df9eeb2bb81f327b96228865c5687bc2194af3f"
+ version = "1.0.0"
+
+[[projects]]
+ branch = "master"
+ name = "github.com/petar/GoLLRB"
+ packages = ["llrb"]
+ revision = "53be0d36a84c2a886ca057d34b6aa4468df9ccb4"
+
+[[projects]]
+ name = "github.com/peterbourgon/diskv"
+ packages = ["."]
+ revision = "5f041e8faa004a95c88a202771f4cc3e991971e6"
+ version = "v2.0.1"
+
+[[projects]]
+ name = "github.com/prometheus/client_golang"
+ packages = [
+ "prometheus",
+ "prometheus/promhttp"
+ ]
+ revision = "c5b7fccd204277076155f10851dad72b76a49317"
+ version = "v0.8.0"
+
+[[projects]]
+ branch = "master"
+ name = "github.com/prometheus/client_model"
+ packages = ["go"]
+ revision = "99fa1f4be8e564e8a6b613da7fa6f46c9edafc6c"
+
+[[projects]]
+ branch = "master"
+ name = "github.com/prometheus/common"
+ packages = [
+ "expfmt",
+ "internal/bitbucket.org/ww/goautoneg",
+ "model"
+ ]
+ revision = "6fb6fce6f8b75884b92e1889c150403fc0872c5e"
+
+[[projects]]
+ branch = "master"
+ name = "github.com/prometheus/procfs"
+ packages = [
+ ".",
+ "internal/util",
+ "nfs",
+ "xfs"
+ ]
+ revision = "d274e363d5759d1c916232217be421f1cc89c5fe"
+
+[[projects]]
+ name = "github.com/spf13/pflag"
+ packages = ["."]
+ revision = "e57e3eeb33f795204c1ca35f56c44f83227c6e66"
+ version = "v1.0.0"
+
+[[projects]]
+ branch = "master"
+ name = "golang.org/x/crypto"
+ packages = ["ssh/terminal"]
+ revision = "91a49db82a88618983a78a06c1cbd4e00ab749ab"
+
+[[projects]]
+ branch = "master"
+ name = "golang.org/x/net"
+ packages = [
+ "context",
+ "context/ctxhttp",
+ "http2",
+ "http2/hpack",
+ "idna",
+ "lex/httplex"
+ ]
+ revision = "cbe0f9307d0156177f9dd5dc85da1a31abc5f2fb"
+
+[[projects]]
+ branch = "master"
+ name = "golang.org/x/oauth2"
+ packages = [
+ ".",
+ "google",
+ "internal",
+ "jws",
+ "jwt"
+ ]
+ revision = "2f32c3ac0fa4fb807a0fcefb0b6f2468a0d99bd0"
+
+[[projects]]
+ branch = "master"
+ name = "golang.org/x/sys"
+ packages = [
+ "unix",
+ "windows"
+ ]
+ revision = "f6cff0780e542efa0c8e864dc8fa522808f6a598"
+
+[[projects]]
+ name = "golang.org/x/text"
+ packages = [
+ "collate",
+ "collate/build",
+ "internal/colltab",
+ "internal/gen",
+ "internal/tag",
+ "internal/triegen",
+ "internal/ucd",
+ "language",
+ "secure/bidirule",
+ "transform",
+ "unicode/bidi",
+ "unicode/cldr",
+ "unicode/norm",
+ "unicode/rangetable",
+ "width"
+ ]
+ revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0"
+ version = "v0.3.0"
+
+[[projects]]
+ branch = "master"
+ name = "golang.org/x/tools"
+ packages = [
+ "go/ast/astutil",
+ "imports"
+ ]
+ revision = "73e16cff9e0d4a802937444bebb562458548241d"
+
+[[projects]]
+ name = "google.golang.org/appengine"
+ packages = [
+ ".",
+ "internal",
+ "internal/app_identity",
+ "internal/base",
+ "internal/datastore",
+ "internal/log",
+ "internal/modules",
+ "internal/remote_api",
+ "internal/urlfetch",
+ "urlfetch"
+ ]
+ revision = "150dc57a1b433e64154302bdc40b6bb8aefa313a"
+ version = "v1.0.0"
+
+[[projects]]
+ name = "gopkg.in/go-playground/webhooks.v3"
+ packages = [
+ ".",
+ "github"
+ ]
+ revision = "c271ec3e322dab2e93990e8c5287fe5d5d1209ba"
+ version = "v3.8.0"
+
+[[projects]]
+ name = "gopkg.in/inf.v0"
+ packages = ["."]
+ revision = "3887ee99ecf07df5b447e9b00d9c0b2adaa9f3e4"
+ version = "v0.9.0"
+
+[[projects]]
+ name = "gopkg.in/yaml.v2"
+ packages = ["."]
+ revision = "7f97868eec74b32b0982dd158a51a446d1da7eb5"
+ version = "v2.1.1"
+
+[[projects]]
+ branch = "release-1.9"
+ name = "k8s.io/api"
+ packages = [
+ "admissionregistration/v1alpha1",
+ "admissionregistration/v1beta1",
+ "apps/v1",
+ "apps/v1beta1",
+ "apps/v1beta2",
+ "authentication/v1",
+ "authentication/v1beta1",
+ "authorization/v1",
+ "authorization/v1beta1",
+ "autoscaling/v1",
+ "autoscaling/v2beta1",
+ "batch/v1",
+ "batch/v1beta1",
+ "batch/v2alpha1",
+ "certificates/v1beta1",
+ "core/v1",
+ "events/v1beta1",
+ "extensions/v1beta1",
+ "networking/v1",
+ "policy/v1beta1",
+ "rbac/v1",
+ "rbac/v1alpha1",
+ "rbac/v1beta1",
+ "scheduling/v1alpha1",
+ "settings/v1alpha1",
+ "storage/v1",
+ "storage/v1alpha1",
+ "storage/v1beta1"
+ ]
+ revision = "acf347b865f29325eb61f4cd2df11e86e073a5ee"
+
+[[projects]]
+ branch = "release-1.9"
+ name = "k8s.io/apimachinery"
+ packages = [
+ "pkg/api/errors",
+ "pkg/api/meta",
+ "pkg/api/resource",
+ "pkg/apimachinery",
+ "pkg/apimachinery/registered",
+ "pkg/apis/meta/internalversion",
+ "pkg/apis/meta/v1",
+ "pkg/apis/meta/v1/unstructured",
+ "pkg/apis/meta/v1alpha1",
+ "pkg/conversion",
+ "pkg/conversion/queryparams",
+ "pkg/fields",
+ "pkg/labels",
+ "pkg/runtime",
+ "pkg/runtime/schema",
+ "pkg/runtime/serializer",
+ "pkg/runtime/serializer/json",
+ "pkg/runtime/serializer/protobuf",
+ "pkg/runtime/serializer/recognizer",
+ "pkg/runtime/serializer/streaming",
+ "pkg/runtime/serializer/versioning",
+ "pkg/selection",
+ "pkg/types",
+ "pkg/util/cache",
+ "pkg/util/clock",
+ "pkg/util/diff",
+ "pkg/util/errors",
+ "pkg/util/framer",
+ "pkg/util/intstr",
+ "pkg/util/json",
+ "pkg/util/mergepatch",
+ "pkg/util/net",
+ "pkg/util/runtime",
+ "pkg/util/sets",
+ "pkg/util/sets/types",
+ "pkg/util/strategicpatch",
+ "pkg/util/validation",
+ "pkg/util/validation/field",
+ "pkg/util/wait",
+ "pkg/util/yaml",
+ "pkg/version",
+ "pkg/watch",
+ "third_party/forked/golang/json",
+ "third_party/forked/golang/reflect"
+ ]
+ revision = "19e3f5aa3adca672c153d324e6b7d82ff8935f03"
+
+[[projects]]
+ branch = "release-6.0"
+ name = "k8s.io/client-go"
+ packages = [
+ "discovery",
+ "discovery/fake",
+ "informers",
+ "informers/admissionregistration",
+ "informers/admissionregistration/v1alpha1",
+ "informers/admissionregistration/v1beta1",
+ "informers/apps",
+ "informers/apps/v1",
+ "informers/apps/v1beta1",
+ "informers/apps/v1beta2",
+ "informers/autoscaling",
+ "informers/autoscaling/v1",
+ "informers/autoscaling/v2beta1",
+ "informers/batch",
+ "informers/batch/v1",
+ "informers/batch/v1beta1",
+ "informers/batch/v2alpha1",
+ "informers/certificates",
+ "informers/certificates/v1beta1",
+ "informers/core",
+ "informers/core/v1",
+ "informers/events",
+ "informers/events/v1beta1",
+ "informers/extensions",
+ "informers/extensions/v1beta1",
+ "informers/internalinterfaces",
+ "informers/networking",
+ "informers/networking/v1",
+ "informers/policy",
+ "informers/policy/v1beta1",
+ "informers/rbac",
+ "informers/rbac/v1",
+ "informers/rbac/v1alpha1",
+ "informers/rbac/v1beta1",
+ "informers/scheduling",
+ "informers/scheduling/v1alpha1",
+ "informers/settings",
+ "informers/settings/v1alpha1",
+ "informers/storage",
+ "informers/storage/v1",
+ "informers/storage/v1alpha1",
+ "informers/storage/v1beta1",
+ "kubernetes",
+ "kubernetes/scheme",
+ "kubernetes/typed/admissionregistration/v1alpha1",
+ "kubernetes/typed/admissionregistration/v1beta1",
+ "kubernetes/typed/apps/v1",
+ "kubernetes/typed/apps/v1beta1",
+ "kubernetes/typed/apps/v1beta2",
+ "kubernetes/typed/authentication/v1",
+ "kubernetes/typed/authentication/v1beta1",
+ "kubernetes/typed/authorization/v1",
+ "kubernetes/typed/authorization/v1beta1",
+ "kubernetes/typed/autoscaling/v1",
+ "kubernetes/typed/autoscaling/v2beta1",
+ "kubernetes/typed/batch/v1",
+ "kubernetes/typed/batch/v1beta1",
+ "kubernetes/typed/batch/v2alpha1",
+ "kubernetes/typed/certificates/v1beta1",
+ "kubernetes/typed/core/v1",
+ "kubernetes/typed/events/v1beta1",
+ "kubernetes/typed/extensions/v1beta1",
+ "kubernetes/typed/networking/v1",
+ "kubernetes/typed/policy/v1beta1",
+ "kubernetes/typed/rbac/v1",
+ "kubernetes/typed/rbac/v1alpha1",
+ "kubernetes/typed/rbac/v1beta1",
+ "kubernetes/typed/scheduling/v1alpha1",
+ "kubernetes/typed/settings/v1alpha1",
+ "kubernetes/typed/storage/v1",
+ "kubernetes/typed/storage/v1alpha1",
+ "kubernetes/typed/storage/v1beta1",
+ "listers/admissionregistration/v1alpha1",
+ "listers/admissionregistration/v1beta1",
+ "listers/apps/v1",
+ "listers/apps/v1beta1",
+ "listers/apps/v1beta2",
+ "listers/autoscaling/v1",
+ "listers/autoscaling/v2beta1",
+ "listers/batch/v1",
+ "listers/batch/v1beta1",
+ "listers/batch/v2alpha1",
+ "listers/certificates/v1beta1",
+ "listers/core/v1",
+ "listers/events/v1beta1",
+ "listers/extensions/v1beta1",
+ "listers/networking/v1",
+ "listers/policy/v1beta1",
+ "listers/rbac/v1",
+ "listers/rbac/v1alpha1",
+ "listers/rbac/v1beta1",
+ "listers/scheduling/v1alpha1",
+ "listers/settings/v1alpha1",
+ "listers/storage/v1",
+ "listers/storage/v1alpha1",
+ "listers/storage/v1beta1",
+ "pkg/version",
+ "plugin/pkg/client/auth/gcp",
+ "rest",
+ "rest/watch",
+ "testing",
+ "third_party/forked/golang/template",
+ "tools/auth",
+ "tools/cache",
+ "tools/clientcmd",
+ "tools/clientcmd/api",
+ "tools/clientcmd/api/latest",
+ "tools/clientcmd/api/v1",
+ "tools/metrics",
+ "tools/pager",
+ "tools/record",
+ "tools/reference",
+ "transport",
+ "util/buffer",
+ "util/cert",
+ "util/flowcontrol",
+ "util/homedir",
+ "util/integer",
+ "util/jsonpath",
+ "util/workqueue"
+ ]
+ revision = "9389c055a838d4f208b699b3c7c51b70f2368861"
+
+[[projects]]
+ name = "k8s.io/code-generator"
+ packages = [
+ "cmd/client-gen",
+ "cmd/client-gen/args",
+ "cmd/client-gen/generators",
+ "cmd/client-gen/generators/fake",
+ "cmd/client-gen/generators/scheme",
+ "cmd/client-gen/generators/util",
+ "cmd/client-gen/path",
+ "cmd/client-gen/types",
+ "cmd/deepcopy-gen",
+ "cmd/deepcopy-gen/args",
+ "cmd/defaulter-gen",
+ "cmd/defaulter-gen/args",
+ "cmd/informer-gen",
+ "cmd/informer-gen/args",
+ "cmd/informer-gen/generators",
+ "cmd/lister-gen",
+ "cmd/lister-gen/args",
+ "cmd/lister-gen/generators",
+ "pkg/util"
+ ]
+ revision = "3c1fe2637f4efce271f1e6f50e039b2a0467c60c"
+
+[[projects]]
+ branch = "master"
+ name = "k8s.io/gengo"
+ packages = [
+ "args",
+ "examples/deepcopy-gen/generators",
+ "examples/defaulter-gen/generators",
+ "examples/set-gen/sets",
+ "generator",
+ "namer",
+ "parser",
+ "types"
+ ]
+ revision = "01a732e01d00cb9a81bb0ca050d3e6d2b947927b"
+
+[[projects]]
+ branch = "master"
+ name = "k8s.io/kube-openapi"
+ packages = [
+ "pkg/common",
+ "pkg/util/proto"
+ ]
+ revision = "50ae88d24ede7b8bad68e23c805b5d3da5c8abaf"
+
+[solve-meta]
+ analyzer-name = "dep"
+ analyzer-version = 1
+ inputs-digest = "a2cb78ebdbc32a2762885a0ed102e68484c413950e6563fe78967e46f9cae1f0"
+ solver-name = "gps-cdcl"
+ solver-version = 1
diff --git a/Gopkg.toml b/Gopkg.toml
new file mode 100644
index 00000000000..c654049c519
--- /dev/null
+++ b/Gopkg.toml
@@ -0,0 +1,49 @@
+# Gopkg.toml example
+#
+# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
+# for detailed Gopkg.toml documentation.
+#
+# required = ["github.com/user/thing/cmd/thing"]
+# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
+#
+# [[constraint]]
+# name = "github.com/user/project"
+# version = "1.0.0"
+#
+# [[constraint]]
+# name = "github.com/user/project2"
+# branch = "dev"
+# source = "github.com/myfork/project2"
+#
+# [[override]]
+# name = "github.com/x/y"
+# version = "2.4.0"
+
+# Required for Bazel
+
+required = [
+ "k8s.io/apimachinery/pkg/util/sets/types",
+ "k8s.io/apimachinery/pkg/apimachinery/registered",
+ "k8s.io/code-generator/cmd/deepcopy-gen",
+ "k8s.io/code-generator/cmd/defaulter-gen",
+ "k8s.io/code-generator/cmd/client-gen",
+ "k8s.io/code-generator/cmd/lister-gen",
+ "k8s.io/code-generator/cmd/informer-gen"
+]
+
+[[constraint]]
+ name = "k8s.io/api"
+ branch = "release-1.9"
+
+[[constraint]]
+ name = "k8s.io/apimachinery"
+ branch = "release-1.9"
+
+[[constraint]]
+ # Must match WORKSPACE!
+ name = "k8s.io/code-generator"
+ revision = "3c1fe2637f4efce271f1e6f50e039b2a0467c60c"
+
+[[constraint]]
+ name = "k8s.io/client-go"
+ branch = "release-6.0" # Matches 1.9
diff --git a/README.md b/README.md
index a78b3785deb..ccbe20e1b8f 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,10 @@
-# binding
-Open source specification and implementation for Elafros binding
+# Bind CRD prototype
+
+This is the repository for prototyping extensible event bindings on Elafros
+
+## Team members
+vaikas@
+
+## Quick start
+
+
diff --git a/WORKSPACE b/WORKSPACE
new file mode 100644
index 00000000000..4bbf899c0df
--- /dev/null
+++ b/WORKSPACE
@@ -0,0 +1,87 @@
+workspace(name = "bindcrd")
+
+http_archive(
+ name = "io_kubernetes_build",
+ sha256 = "cf138e48871629345548b4aaf23101314b5621c1bdbe45c4e75edb45b08891f0",
+ strip_prefix = "repo-infra-1fb0a3ff0cc5308a6d8e2f3f9c57d1f2f940354e",
+ urls = ["https://github.com/kubernetes/repo-infra/archive/1fb0a3ff0cc5308a6d8e2f3f9c57d1f2f940354e.tar.gz"],
+)
+
+# Pull in rules_go
+git_repository(
+ name = "io_bazel_rules_go",
+ commit = "737df20c53499fd84b67f04c6ca9ccdee2e77089",
+ remote = "https://github.com/bazelbuild/rules_go.git",
+)
+
+load("@io_bazel_rules_go//go:def.bzl", "go_rules_dependencies", "go_register_toolchains", "go_repository")
+
+go_rules_dependencies()
+
+go_register_toolchains()
+
+# Pull in rules_docker
+git_repository(
+ name = "io_bazel_rules_docker",
+ # HEAD as of 2018-02-03
+ commit = "bf925ec58ad96f2ead21cd8379caedbe3c26efc9",
+ remote = "https://github.com/bazelbuild/rules_docker.git",
+)
+
+load(
+ "@io_bazel_rules_docker//docker:docker.bzl",
+ "docker_repositories",
+)
+
+docker_repositories()
+
+# Pull in the go_image stuff.
+load(
+ "@io_bazel_rules_docker//go:image.bzl",
+ _go_image_repos = "repositories",
+)
+
+_go_image_repos()
+
+# Pull in rules_k8s
+git_repository(
+ name = "io_bazel_rules_k8s",
+ # HEAD as of 2018-02-03
+ commit = "959c5adc2d7863c0ff445c6fd789cfd04bc1815c",
+ remote = "https://github.com/bazelbuild/rules_k8s",
+)
+
+load("@io_bazel_rules_k8s//k8s:k8s.bzl", "k8s_repositories", "k8s_defaults")
+
+k8s_repositories()
+
+_CLUSTER = "{STABLE_K8S_CLUSTER}"
+_REPOSITORY = "{STABLE_DOCKER_REPO}"
+
+k8s_defaults(
+ name = "k8s_object",
+ cluster = _CLUSTER,
+ image_chroot = _REPOSITORY,
+)
+
+go_repository(
+ name = "io_k8s_code_generator",
+ commit = "3c1fe2637f4efce271f1e6f50e039b2a0467c60c",
+ importpath = "k8s.io/code-generator",
+)
+
+go_repository(
+ name = "io_k8s_gengo",
+ commit = "1ef560bbde5195c01629039ad3b337ce63e7b321",
+ importpath = "k8s.io/gengo",
+)
+
+go_repository(
+ name = "com_github_spf13_pflag",
+ commit = "4c012f6dcd9546820e378d0bdda4d8fc772cdfea",
+ importpath = "github.com/spf13/pflag",
+)
+
+# Pull in the go_image stuff.
+load("@io_bazel_rules_docker//container:container.bzl", "container_pull")
+
diff --git a/bind.yaml b/bind.yaml
new file mode 100644
index 00000000000..ebd2807be5b
--- /dev/null
+++ b/bind.yaml
@@ -0,0 +1,24 @@
+# Copyright 2018 Google, 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.
+apiVersion: apiextensions.k8s.io/v1beta1
+kind: CustomResourceDefinition
+metadata:
+ name: binds.elafros.dev
+spec:
+ group: elafros.dev
+ version: v1alpha1
+ names:
+ kind: Bind
+ plural: binds
+ scope: Namespaced
diff --git a/clusterrolebinding.yaml b/clusterrolebinding.yaml
new file mode 100644
index 00000000000..e6d2a4eeded
--- /dev/null
+++ b/clusterrolebinding.yaml
@@ -0,0 +1,25 @@
+# Copyright 2018 Google, 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.
+apiVersion: rbac.authorization.k8s.io/v1beta1
+kind: ClusterRoleBinding
+metadata:
+ name: bind-controller-admin
+subjects:
+ - kind: ServiceAccount
+ name: bind-controller
+ namespace: bind-system
+roleRef:
+ kind: ClusterRole
+ name: cluster-admin
+ apiGroup: rbac.authorization.k8s.io
diff --git a/cmd/controller/BUILD b/cmd/controller/BUILD
new file mode 100644
index 00000000000..9b2be2cafce
--- /dev/null
+++ b/cmd/controller/BUILD
@@ -0,0 +1,40 @@
+package(default_visibility = ["//visibility:public"])
+
+load("@io_bazel_rules_go//go:def.bzl", "gazelle", "go_binary", "go_library")
+
+go_library(
+ name = "go_default_library",
+ srcs = ["main.go"],
+ importpath = "github.com/elafros/binding/cmd/controller",
+ visibility = ["//visibility:private"],
+ deps = [
+ "//pkg/client/clientset/versioned:go_default_library",
+ "//pkg/client/informers/externalversions:go_default_library",
+ "//pkg/controller:go_default_library",
+ "//pkg/controller/bind:go_default_library",
+ "//pkg/signals:go_default_library",
+ "//vendor/github.com/elafros/elafros/pkg/client/clientset/versioned:go_default_library",
+ "//vendor/github.com/elafros/elafros/pkg/client/informers/externalversions:go_default_library",
+ "//vendor/github.com/golang/glog:go_default_library",
+ "//vendor/github.com/prometheus/client_golang/prometheus/promhttp:go_default_library",
+ "//vendor/k8s.io/client-go/informers:go_default_library",
+ "//vendor/k8s.io/client-go/kubernetes:go_default_library",
+ "//vendor/k8s.io/client-go/plugin/pkg/client/auth/gcp:go_default_library",
+ "//vendor/k8s.io/client-go/tools/clientcmd:go_default_library",
+ ],
+)
+
+go_binary(
+ name = "controller",
+ embed = [":go_default_library"],
+ importpath = "github.com/elafros/binding/cmd/controller",
+ pure = "on",
+ visibility = ["//visibility:public"],
+)
+
+load("@io_bazel_rules_docker//go:image.bzl", "go_image")
+
+go_image(
+ name = "image",
+ binary = ":controller",
+)
diff --git a/cmd/controller/main.go b/cmd/controller/main.go
new file mode 100644
index 00000000000..39391580297
--- /dev/null
+++ b/cmd/controller/main.go
@@ -0,0 +1,135 @@
+/*
+Copyright 2017 The Kubernetes Authors.
+
+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 main
+
+import (
+ "context"
+ "flag"
+ "net/http"
+ "time"
+
+ "github.com/golang/glog"
+ kubeinformers "k8s.io/client-go/informers"
+ "k8s.io/client-go/kubernetes"
+ "k8s.io/client-go/tools/clientcmd"
+ // Uncomment the following line to load the gcp plugin (only required to authenticate against GKE clusters).
+ _ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
+
+ elaclientset "github.com/elafros/elafros/pkg/client/clientset/versioned"
+ elainformers "github.com/elafros/elafros/pkg/client/informers/externalversions"
+
+ clientset "github.com/elafros/binding/pkg/client/clientset/versioned"
+ informers "github.com/elafros/binding/pkg/client/informers/externalversions"
+ "github.com/elafros/binding/pkg/controller"
+ "github.com/elafros/binding/pkg/controller/bind"
+ "github.com/elafros/binding/pkg/signals"
+
+ "github.com/prometheus/client_golang/prometheus/promhttp"
+)
+
+const (
+ threadsPerController = 2
+ metricsScrapeAddr = ":9090"
+ metricsScrapePath = "/metrics"
+)
+
+var (
+ masterURL string
+ kubeconfig string
+)
+
+func main() {
+ flag.Parse()
+
+ // set up signals so we handle the first shutdown signal gracefully
+ stopCh := signals.SetupSignalHandler()
+
+ cfg, err := clientcmd.BuildConfigFromFlags(masterURL, kubeconfig)
+ if err != nil {
+ glog.Fatalf("Error building kubeconfig: %s", err.Error())
+ }
+
+ kubeClient, err := kubernetes.NewForConfig(cfg)
+ if err != nil {
+ glog.Fatalf("Error building kubernetes clientset: %s", err.Error())
+ }
+
+ client, err := clientset.NewForConfig(cfg)
+ if err != nil {
+ glog.Fatalf("Error building clientset: %s", err.Error())
+ }
+
+ elaClient, err := elaclientset.NewForConfig(cfg)
+ if err != nil {
+ glog.Fatalf("Error building ela clientset: %s", err.Error())
+ }
+
+ kubeInformerFactory := kubeinformers.NewSharedInformerFactory(kubeClient, time.Second*30)
+ informerFactory := informers.NewSharedInformerFactory(client, time.Second*30)
+ elaInformerFactory := elainformers.NewSharedInformerFactory(elaClient, time.Second*30)
+
+ // Add new controllers here.
+ ctors := []controller.Constructor{
+ bind.NewController,
+ }
+
+ // Build all of our controllers, with the clients constructed above.
+ controllers := make([]controller.Interface, 0, len(ctors))
+ for _, ctor := range ctors {
+ controllers = append(controllers,
+ ctor(kubeClient, client, kubeInformerFactory, informerFactory, elaInformerFactory))
+ }
+
+ go kubeInformerFactory.Start(stopCh)
+ go informerFactory.Start(stopCh)
+ go elaInformerFactory.Start(stopCh)
+
+ // Start all of the controllers.
+ for _, ctrlr := range controllers {
+ go func(ctrlr controller.Interface) {
+ // We don't expect this to return until stop is called,
+ // but if it does, propagate it back.
+ if err := ctrlr.Run(threadsPerController, stopCh); err != nil {
+ glog.Fatalf("Error running controller: %s", err.Error())
+ }
+ }(ctrlr)
+ }
+
+ // Start the endpoint that Prometheus scraper talks to
+ srv := &http.Server{Addr: metricsScrapeAddr}
+ http.Handle(metricsScrapePath, promhttp.Handler())
+ go func() {
+ glog.Info("Starting metrics listener at %s", metricsScrapeAddr)
+ if err := srv.ListenAndServe(); err != nil {
+ glog.Infof("Httpserver: ListenAndServe() finished with error: %s", err)
+ }
+ }()
+
+ <-stopCh
+
+ // Close the http server gracefully
+ ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
+ defer cancel()
+ srv.Shutdown(ctx)
+
+ glog.Flush()
+}
+
+func init() {
+ flag.StringVar(&kubeconfig, "kubeconfig", "", "Path to a kubeconfig. Only required if out-of-cluster.")
+ flag.StringVar(&masterURL, "master", "", "The address of the Kubernetes API server. Overrides any value in kubeconfig. Only required if out-of-cluster.")
+}
diff --git a/controller.yaml b/controller.yaml
new file mode 100644
index 00000000000..82020a8b654
--- /dev/null
+++ b/controller.yaml
@@ -0,0 +1,33 @@
+# Copyright 2018 Google, 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.
+apiVersion: apps/v1beta1
+kind: Deployment
+metadata:
+ name: bind-controller
+ namespace: bind-system
+spec:
+ replicas: 1
+ template:
+ metadata:
+ labels:
+ app: bind-controller
+ spec:
+ serviceAccountName: bind-controller
+ containers:
+ - name: bind-controller
+ image: bind-controller:latest
+ args: [
+ "-logtostderr",
+ "-stderrthreshold", "INFO",
+ ]
diff --git a/eventsource.yaml b/eventsource.yaml
new file mode 100644
index 00000000000..349e6bd3e7b
--- /dev/null
+++ b/eventsource.yaml
@@ -0,0 +1,24 @@
+# Copyright 2018 Google, 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.
+apiVersion: apiextensions.k8s.io/v1beta1
+kind: CustomResourceDefinition
+metadata:
+ name: eventsources.elafros.dev
+spec:
+ group: elafros.dev
+ version: v1alpha1
+ names:
+ kind: EventSource
+ plural: eventsources
+ scope: Namespaced
diff --git a/eventtype.yaml b/eventtype.yaml
new file mode 100644
index 00000000000..68020501404
--- /dev/null
+++ b/eventtype.yaml
@@ -0,0 +1,24 @@
+# Copyright 2018 Google, 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.
+apiVersion: apiextensions.k8s.io/v1beta1
+kind: CustomResourceDefinition
+metadata:
+ name: eventtypes.elafros.dev
+spec:
+ group: elafros.dev
+ version: v1alpha1
+ names:
+ kind: EventType
+ plural: eventtypes
+ scope: Namespaced
diff --git a/hack/boilerplate/BUILD b/hack/boilerplate/BUILD
new file mode 100644
index 00000000000..01ba17bf120
--- /dev/null
+++ b/hack/boilerplate/BUILD
@@ -0,0 +1 @@
+exports_files(["boilerplate.go.txt"])
diff --git a/hack/boilerplate/boilerplate.go.txt b/hack/boilerplate/boilerplate.go.txt
new file mode 100644
index 00000000000..9e490c9ef3d
--- /dev/null
+++ b/hack/boilerplate/boilerplate.go.txt
@@ -0,0 +1,15 @@
+/*
+Copyright 2018 Google, 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.
+*/
diff --git a/hack/update-codegen.sh b/hack/update-codegen.sh
new file mode 100755
index 00000000000..d2cec2cf54e
--- /dev/null
+++ b/hack/update-codegen.sh
@@ -0,0 +1,34 @@
+#!/bin/bash
+
+# Copyright 2018 Google, 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.
+
+set -o errexit
+set -o nounset
+set -o pipefail
+
+SCRIPT_ROOT=$(dirname ${BASH_SOURCE})/..
+CODEGEN_PKG=${CODEGEN_PKG:-$(cd ${SCRIPT_ROOT}; ls -d -1 ./vendor/k8s.io/code-generator 2>/dev/null || echo ../../../k8s.io/code-generator)}
+
+# generate the code with:
+# --output-base because this script should also be able to run inside the vendor dir of
+# k8s.io/kubernetes. The output-base is needed for the generators to output into the vendor dir
+# instead of the $GOPATH directly. For normal projects this can be dropped.
+${CODEGEN_PKG}/generate-groups.sh "deepcopy,client,informer,lister" \
+ github.com/elafros/binding/pkg/client github.com/elafros/binding/pkg/apis \
+ bind:v1alpha1 \
+ --go-header-file ${SCRIPT_ROOT}/hack/boilerplate/boilerplate.go.txt
+
+# Make sure our dependencies are up-to-date
+${SCRIPT_ROOT}/hack/update-deps.sh
diff --git a/hack/update-deps.sh b/hack/update-deps.sh
new file mode 100755
index 00000000000..1a944d672b1
--- /dev/null
+++ b/hack/update-deps.sh
@@ -0,0 +1,40 @@
+#!/bin/bash
+
+# Copyright 2018 Google, 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.
+
+set -o errexit
+set -o nounset
+set -o pipefail
+
+SCRIPT_ROOT=$(dirname ${BASH_SOURCE})/..
+
+pushd ${SCRIPT_ROOT}
+trap popd EXIT
+
+# Ensure we have everything we need under vendor/
+dep ensure
+dep prune
+
+# Make sure that BUILD files are up to date (the above removes them).
+bazel run //:gazelle -- -proto=disable
+
+# Rewrite the code-generator imports, which we pull in through WORKSPACE,
+# since it's hard to vendor.
+sed -i 's|//vendor/k8s.io/code-generator/|@io_k8s_code_generator//|g' \
+ $(find ${SCRIPT_ROOT}/vendor -type f -name '*' | xargs grep k8s.io/code-generator |& grep code-gen | cut -d':' -f 1 | uniq)
+
+# Fix up a case in k8s' client-go where non-testdata relies on files
+# in testdata (and so breaks after pruning).
+sed -i 's|.*".*dontUseThisKey.pem",||g' vendor/k8s.io/client-go/util/cert/BUILD
diff --git a/hack/verify-codegen.sh b/hack/verify-codegen.sh
new file mode 100755
index 00000000000..b5341f7f9b7
--- /dev/null
+++ b/hack/verify-codegen.sh
@@ -0,0 +1,48 @@
+#!/bin/bash
+
+# Copyright 2018 Google, 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.
+
+set -o errexit
+set -o nounset
+set -o pipefail
+
+SCRIPT_ROOT=$(dirname "${BASH_SOURCE}")/..
+
+DIFFROOT="${SCRIPT_ROOT}/pkg"
+TMP_DIFFROOT="${SCRIPT_ROOT}/_tmp/pkg"
+_tmp="${SCRIPT_ROOT}/_tmp"
+
+cleanup() {
+ rm -rf "${_tmp}"
+}
+trap "cleanup" EXIT SIGINT
+
+cleanup
+
+mkdir -p "${TMP_DIFFROOT}"
+cp -a "${DIFFROOT}"/* "${TMP_DIFFROOT}"
+
+"${SCRIPT_ROOT}/hack/update-codegen.sh"
+echo "diffing ${DIFFROOT} against freshly generated codegen"
+ret=0
+diff -Naupr "${DIFFROOT}" "${TMP_DIFFROOT}" || ret=$?
+cp -a "${TMP_DIFFROOT}"/* "${DIFFROOT}"
+if [[ $ret -eq 0 ]]
+then
+ echo "${DIFFROOT} up to date."
+else
+ echo "${DIFFROOT} is out of date. Please run hack/update-codegen.sh"
+ exit 1
+fi
diff --git a/namespace.yaml b/namespace.yaml
new file mode 100644
index 00000000000..0151193e368
--- /dev/null
+++ b/namespace.yaml
@@ -0,0 +1,17 @@
+# Copyright 2018 Google, 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.
+apiVersion: v1
+kind: Namespace
+metadata:
+ name: bind-system
diff --git a/pkg/apis/bind/BUILD b/pkg/apis/bind/BUILD
new file mode 100644
index 00000000000..128f1654f7c
--- /dev/null
+++ b/pkg/apis/bind/BUILD
@@ -0,0 +1,8 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_library")
+
+go_library(
+ name = "go_default_library",
+ srcs = ["register.go"],
+ importpath = "github.com/elafros/binding/pkg/apis/bind",
+ visibility = ["//visibility:public"],
+)
diff --git a/pkg/apis/bind/register.go b/pkg/apis/bind/register.go
new file mode 100644
index 00000000000..e2ec56c581c
--- /dev/null
+++ b/pkg/apis/bind/register.go
@@ -0,0 +1,21 @@
+/*
+Copyright 2018 Google, 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 bind
+
+const (
+ GroupName = "elafros.dev"
+)
diff --git a/pkg/apis/bind/v1alpha1/BUILD b/pkg/apis/bind/v1alpha1/BUILD
new file mode 100644
index 00000000000..9a0cb903f0d
--- /dev/null
+++ b/pkg/apis/bind/v1alpha1/BUILD
@@ -0,0 +1,22 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_library")
+
+go_library(
+ name = "go_default_library",
+ srcs = [
+ "bind_types.go",
+ "doc.go",
+ "event_source_types.go",
+ "event_type_types.go",
+ "register.go",
+ "zz_generated.deepcopy.go",
+ ],
+ importpath = "github.com/elafros/binding/pkg/apis/bind/v1alpha1",
+ visibility = ["//visibility:public"],
+ deps = [
+ "//pkg/apis/bind:go_default_library",
+ "//vendor/k8s.io/api/core/v1:go_default_library",
+ "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
+ "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
+ "//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
+ ],
+)
diff --git a/pkg/apis/bind/v1alpha1/bind_types.go b/pkg/apis/bind/v1alpha1/bind_types.go
new file mode 100644
index 00000000000..6f5835d6715
--- /dev/null
+++ b/pkg/apis/bind/v1alpha1/bind_types.go
@@ -0,0 +1,149 @@
+/*
+Copyright 2018 Google, 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 v1alpha1
+
+import (
+ corev1 "k8s.io/api/core/v1"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+
+ "k8s.io/apimachinery/pkg/runtime"
+)
+
+// +genclient
+// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
+
+// Bind is a specification for a Bind resource
+type Bind struct {
+ metav1.TypeMeta `json:",inline"`
+ metav1.ObjectMeta `json:"metadata,omitempty"`
+
+ Spec BindSpec `json:"spec"`
+ Status BindStatus `json:"status"`
+}
+
+type BindAction struct {
+ // RouteName specifies Elafros route as a target.
+ RouteName string `json:"routeName,omitempty"`
+}
+
+type BindSource struct {
+ // EventSource specifies the event source to consume
+ EventSource string `json:"eventSource"`
+
+ // EventType specifies the event type to consume
+ EventType string `json:"eventType"`
+}
+
+// BindSpec is the spec for a Bind resource
+type BindSpec struct {
+ // Action specifies the target handler for the events
+ Action BindAction `json:"action"`
+
+ // Source specifies the trigger we're binding to
+ Source BindSource `json:"source"`
+
+ // Parameters is what's necessary to create the subscription.
+ // This is specific to each Source. Opaque to platform, only consumed
+ // by the actual trigger actuator.
+ Parameters *runtime.RawExtension `json:"parameters,omitempty"`
+
+ // ParametersFrom are pointers to secrets that contain sensitive
+ // parameters. Opaque to platform, merged in with Parameters and consumed
+ // by the actual trigger actuator.
+ ParametersFrom []ParametersFromSource `json:"parametersFrom,omitempty"`
+}
+
+// ParametersFromSource represents the source of a set of Parameters
+// TODO: consider making this into a new secret type.
+type ParametersFromSource struct {
+ // The Secret key to select from.
+ // The value must be a JSON object.
+ //+optional
+ SecretKeyRef *SecretKeyReference `json:"secretKeyRef,omitempty"`
+}
+
+// SecretKeyReference references a key of a Secret.
+type SecretKeyReference struct {
+ // The name of the secret in the pod's namespace to select from.
+ Name string `json:"name"`
+ // The key of the secret to select from. Must be a valid secret key.
+ Key string `json:"key"`
+}
+
+// BindStatus is the status for a Bind resource
+type BindStatus struct {
+ Conditions []BindCondition `json:"conditions,omitempty"`
+}
+
+type BindConditionType string
+
+const (
+ // BindComplete specifies that the bind has completed successfully.
+ BindComplete BindConditionType = "Complete"
+ // BindFailed specifies that the bind has failed.
+ BindFailed BindConditionType = "Failed"
+ // BindInvalid specifies that the given bind specification is invalid.
+ BindInvalid BindConditionType = "Invalid"
+)
+
+// BindCondition defines a readiness condition for a Bind.
+// See: https://github.com/kubernetes/community/blob/master/contributors/devel/api-conventions.md#typical-status-properties
+type BindCondition struct {
+ Type BindConditionType `json:"state"`
+
+ Status corev1.ConditionStatus `json:"status" description:"status of the condition, one of True, False, Unknown"`
+ // +optional
+ Reason string `json:"reason,omitempty" description:"one-word CamelCase reason for the condition's last transition"`
+ // +optional
+ Message string `json:"message,omitempty" description:"human-readable message indicating details about last transition"`
+}
+
+// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
+
+// BindList is a list of Bind resources
+type BindList struct {
+ metav1.TypeMeta `json:",inline"`
+ metav1.ListMeta `json:"metadata"`
+
+ Items []Bind `json:"items"`
+}
+
+func (bs *BindStatus) SetCondition(new *BindCondition) {
+ if new == nil {
+ return
+ }
+
+ t := new.Type
+ var conditions []BindCondition
+ for _, cond := range bs.Conditions {
+ if cond.Type != t {
+ conditions = append(conditions, cond)
+ }
+ }
+ conditions = append(conditions, *new)
+ bs.Conditions = conditions
+}
+
+func (bs *BindStatus) RemoveCondition(t BindConditionType) {
+ var conditions []BindCondition
+ for _, cond := range bs.Conditions {
+ if cond.Type != t {
+ conditions = append(conditions, cond)
+ }
+ }
+ bs.Conditions = conditions
+}
diff --git a/pkg/apis/bind/v1alpha1/doc.go b/pkg/apis/bind/v1alpha1/doc.go
new file mode 100644
index 00000000000..914cffade4a
--- /dev/null
+++ b/pkg/apis/bind/v1alpha1/doc.go
@@ -0,0 +1,16 @@
+/*
+Copyright 2018 Google, 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.
+*/
+// +k8s:deepcopy-gen=package
+// Package v1alpha1 is the v1alpha1 version of the API.
+// +groupName=elafros.dev
+package v1alpha1
diff --git a/pkg/apis/bind/v1alpha1/event_source_types.go b/pkg/apis/bind/v1alpha1/event_source_types.go
new file mode 100644
index 00000000000..53628438005
--- /dev/null
+++ b/pkg/apis/bind/v1alpha1/event_source_types.go
@@ -0,0 +1,108 @@
+/*
+Copyright 2018 Google, 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 v1alpha1
+
+import (
+ corev1 "k8s.io/api/core/v1"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+// +genclient
+// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
+
+// EventSource is a specification for a EventSource resource
+// It would define necessary information to talk to the source of the event.
+// Some examples would be github.com, or GCP, etc.
+type EventSource struct {
+ metav1.TypeMeta `json:",inline"`
+ metav1.ObjectMeta `json:"metadata,omitempty"`
+
+ Spec EventSourceSpec `json:"spec"`
+ Status EventSourceStatus `json:"status"`
+}
+
+// EventSourceSpec is the spec for a EventSource resource
+// TODO: Define this to actually be useful. Placeholder for now
+type EventSourceSpec struct {
+ Type string `json:"type,omitempty"`
+ Source string `json:"source,omitempty"`
+}
+
+// EventSourceStatus is the status for a EventSource resource
+type EventSourceStatus struct {
+ Conditions []EventSourceCondition `json:"conditions,omitempty"`
+}
+
+type EventSourceConditionType string
+
+const (
+ // EventSourceComplete specifies that the bind has completed successfully.
+ EventSourceComplete EventSourceConditionType = "Complete"
+ // EventSourceFailed specifies that the bind has failed.
+ EventSourceFailed EventSourceConditionType = "Failed"
+ // EventSourceInvalid specifies that the given bind specification is invalid.
+ EventSourceInvalid EventSourceConditionType = "Invalid"
+)
+
+// EventSourceCondition defines a readiness condition for a EventSource.
+// See: https://github.com/kubernetes/community/blob/master/contributors/devel/api-conventions.md#typical-status-properties
+type EventSourceCondition struct {
+ Type EventSourceConditionType `json:"state"`
+
+ Status corev1.ConditionStatus `json:"status" description:"status of the condition, one of True, False, Unknown"`
+
+ // +optional
+ Reason string `json:"reason,omitempty" description:"one-word CamelCase reason for the condition's last transition"`
+ // +optional
+ Message string `json:"message,omitempty" description:"human-readable message indicating details about last transition"`
+}
+
+// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
+
+// EventSourceList is a list of EventSource resources
+type EventSourceList struct {
+ metav1.TypeMeta `json:",inline"`
+ metav1.ListMeta `json:"metadata"`
+
+ Items []EventSource `json:"items"`
+}
+
+func (ess *EventSourceStatus) SetCondition(new *EventSourceCondition) {
+ if new == nil {
+ return
+ }
+
+ t := new.Type
+ var conditions []EventSourceCondition
+ for _, cond := range ess.Conditions {
+ if cond.Type != t {
+ conditions = append(conditions, cond)
+ }
+ }
+ conditions = append(conditions, *new)
+ ess.Conditions = conditions
+}
+
+func (ess *EventSourceStatus) RemoveCondition(t EventSourceConditionType) {
+ var conditions []EventSourceCondition
+ for _, cond := range ess.Conditions {
+ if cond.Type != t {
+ conditions = append(conditions, cond)
+ }
+ }
+ ess.Conditions = conditions
+}
diff --git a/pkg/apis/bind/v1alpha1/event_type_types.go b/pkg/apis/bind/v1alpha1/event_type_types.go
new file mode 100644
index 00000000000..4509dc70044
--- /dev/null
+++ b/pkg/apis/bind/v1alpha1/event_type_types.go
@@ -0,0 +1,115 @@
+/*
+Copyright 2018 Google, 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 v1alpha1
+
+import (
+ corev1 "k8s.io/api/core/v1"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/runtime"
+)
+
+// +genclient
+// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
+
+// EventType is a specification for a EventType resource
+// EventSource can expose multiple event types. For example, github
+// has PullRequest events as well as Issues and Comments, etc.
+type EventType struct {
+ metav1.TypeMeta `json:",inline"`
+ metav1.ObjectMeta `json:"metadata,omitempty"`
+
+ Spec EventTypeSpec `json:"spec"`
+ Status EventTypeStatus `json:"status"`
+}
+
+// EventTypeSpec is the spec for a EventType resource
+// TODO: Define this to be more useful
+type EventTypeSpec struct {
+ EventSource string `json:"eventSource"`
+ Description string `json:"description,omitempty"`
+ // SubscribeSchema describing how to subscribe to this. This basically
+ // defines what is required in the Bind.Parameters so that the developer
+ // can see the required parameters.
+ SubscribeSchema *runtime.RawExtension `json:"subscribeSchema,omitempty"`
+ // Describe the schema for the events emitted by this EventType.
+ EventSchema *runtime.RawExtension `json:"eventSchema,omitempty"`
+}
+
+// EventTypeStatus is the status for a EventType resource
+type EventTypeStatus struct {
+ Conditions []EventTypeCondition `json:"conditions,omitempty"`
+}
+
+type EventTypeConditionType string
+
+const (
+ // EventTypeComplete specifies that the bind has completed successfully.
+ EventTypeComplete EventTypeConditionType = "Complete"
+ // EventTypeFailed specifies that the bind has failed.
+ EventTypeFailed EventTypeConditionType = "Failed"
+ // EventTypeInvalid specifies that the given bind specification is invalid.
+ EventTypeInvalid EventTypeConditionType = "Invalid"
+)
+
+// EventTypeCondition defines a readiness condition for a EventType.
+// See: https://github.com/kubernetes/community/blob/master/contributors/devel/api-conventions.md#typical-status-properties
+type EventTypeCondition struct {
+ Type EventTypeConditionType `json:"state"`
+
+ Status corev1.ConditionStatus `json:"status" description:"status of the condition, one of True, False, Unknown"`
+
+ // +optional
+ Reason string `json:"reason,omitempty" description:"one-word CamelCase reason for the condition's last transition"`
+ // +optional
+ Message string `json:"message,omitempty" description:"human-readable message indicating details about last transition"`
+}
+
+// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
+
+// EventTypeList is a list of EventType resources
+type EventTypeList struct {
+ metav1.TypeMeta `json:",inline"`
+ metav1.ListMeta `json:"metadata"`
+
+ Items []EventType `json:"items"`
+}
+
+func (ets *EventTypeStatus) SetCondition(new *EventTypeCondition) {
+ if new == nil {
+ return
+ }
+
+ t := new.Type
+ var conditions []EventTypeCondition
+ for _, cond := range ets.Conditions {
+ if cond.Type != t {
+ conditions = append(conditions, cond)
+ }
+ }
+ conditions = append(conditions, *new)
+ ets.Conditions = conditions
+}
+
+func (ets *EventTypeStatus) RemoveCondition(t EventTypeConditionType) {
+ var conditions []EventTypeCondition
+ for _, cond := range ets.Conditions {
+ if cond.Type != t {
+ conditions = append(conditions, cond)
+ }
+ }
+ ets.Conditions = conditions
+}
diff --git a/pkg/apis/bind/v1alpha1/register.go b/pkg/apis/bind/v1alpha1/register.go
new file mode 100644
index 00000000000..e0dbb140bd4
--- /dev/null
+++ b/pkg/apis/bind/v1alpha1/register.go
@@ -0,0 +1,57 @@
+/*
+Copyright 2018 Google, 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 v1alpha1
+
+import (
+ "github.com/elafros/binding/pkg/apis/bind"
+
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+)
+
+// SchemeGroupVersion is group version used to register these objects
+var SchemeGroupVersion = schema.GroupVersion{Group: bind.GroupName, Version: "v1alpha1"}
+
+// Kind takes an unqualified kind and returns back a Group qualified GroupKind
+func Kind(kind string) schema.GroupKind {
+ return SchemeGroupVersion.WithKind(kind).GroupKind()
+}
+
+// Resource takes an unqualified resource and returns a Group qualified GroupResource
+func Resource(resource string) schema.GroupResource {
+ return SchemeGroupVersion.WithResource(resource).GroupResource()
+}
+
+var (
+ SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
+ AddToScheme = SchemeBuilder.AddToScheme
+)
+
+// Adds the list of known types to Scheme.
+func addKnownTypes(scheme *runtime.Scheme) error {
+ scheme.AddKnownTypes(SchemeGroupVersion,
+ &Bind{},
+ &BindList{},
+ &EventSource{},
+ &EventSourceList{},
+ &EventType{},
+ &EventTypeList{},
+ )
+ metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
+ return nil
+}
diff --git a/pkg/apis/bind/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/bind/v1alpha1/zz_generated.deepcopy.go
new file mode 100644
index 00000000000..fbf74af6f76
--- /dev/null
+++ b/pkg/apis/bind/v1alpha1/zz_generated.deepcopy.go
@@ -0,0 +1,476 @@
+// +build !ignore_autogenerated
+
+/*
+Copyright 2018 Google, 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.
+*/
+
+// Code generated by deepcopy-gen. DO NOT EDIT.
+
+package v1alpha1
+
+import (
+ runtime "k8s.io/apimachinery/pkg/runtime"
+)
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *Bind) DeepCopyInto(out *Bind) {
+ *out = *in
+ out.TypeMeta = in.TypeMeta
+ in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
+ in.Spec.DeepCopyInto(&out.Spec)
+ in.Status.DeepCopyInto(&out.Status)
+ return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Bind.
+func (in *Bind) DeepCopy() *Bind {
+ if in == nil {
+ return nil
+ }
+ out := new(Bind)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *Bind) DeepCopyObject() runtime.Object {
+ if c := in.DeepCopy(); c != nil {
+ return c
+ }
+ return nil
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *BindAction) DeepCopyInto(out *BindAction) {
+ *out = *in
+ return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BindAction.
+func (in *BindAction) DeepCopy() *BindAction {
+ if in == nil {
+ return nil
+ }
+ out := new(BindAction)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *BindCondition) DeepCopyInto(out *BindCondition) {
+ *out = *in
+ return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BindCondition.
+func (in *BindCondition) DeepCopy() *BindCondition {
+ if in == nil {
+ return nil
+ }
+ out := new(BindCondition)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *BindList) DeepCopyInto(out *BindList) {
+ *out = *in
+ out.TypeMeta = in.TypeMeta
+ out.ListMeta = in.ListMeta
+ if in.Items != nil {
+ in, out := &in.Items, &out.Items
+ *out = make([]Bind, len(*in))
+ for i := range *in {
+ (*in)[i].DeepCopyInto(&(*out)[i])
+ }
+ }
+ return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BindList.
+func (in *BindList) DeepCopy() *BindList {
+ if in == nil {
+ return nil
+ }
+ out := new(BindList)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *BindList) DeepCopyObject() runtime.Object {
+ if c := in.DeepCopy(); c != nil {
+ return c
+ }
+ return nil
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *BindSource) DeepCopyInto(out *BindSource) {
+ *out = *in
+ return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BindSource.
+func (in *BindSource) DeepCopy() *BindSource {
+ if in == nil {
+ return nil
+ }
+ out := new(BindSource)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *BindSpec) DeepCopyInto(out *BindSpec) {
+ *out = *in
+ out.Action = in.Action
+ out.Source = in.Source
+ if in.Parameters != nil {
+ in, out := &in.Parameters, &out.Parameters
+ if *in == nil {
+ *out = nil
+ } else {
+ *out = new(runtime.RawExtension)
+ (*in).DeepCopyInto(*out)
+ }
+ }
+ if in.ParametersFrom != nil {
+ in, out := &in.ParametersFrom, &out.ParametersFrom
+ *out = make([]ParametersFromSource, len(*in))
+ for i := range *in {
+ (*in)[i].DeepCopyInto(&(*out)[i])
+ }
+ }
+ return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BindSpec.
+func (in *BindSpec) DeepCopy() *BindSpec {
+ if in == nil {
+ return nil
+ }
+ out := new(BindSpec)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *BindStatus) DeepCopyInto(out *BindStatus) {
+ *out = *in
+ if in.Conditions != nil {
+ in, out := &in.Conditions, &out.Conditions
+ *out = make([]BindCondition, len(*in))
+ copy(*out, *in)
+ }
+ return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BindStatus.
+func (in *BindStatus) DeepCopy() *BindStatus {
+ if in == nil {
+ return nil
+ }
+ out := new(BindStatus)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *EventSource) DeepCopyInto(out *EventSource) {
+ *out = *in
+ out.TypeMeta = in.TypeMeta
+ in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
+ out.Spec = in.Spec
+ in.Status.DeepCopyInto(&out.Status)
+ return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EventSource.
+func (in *EventSource) DeepCopy() *EventSource {
+ if in == nil {
+ return nil
+ }
+ out := new(EventSource)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *EventSource) DeepCopyObject() runtime.Object {
+ if c := in.DeepCopy(); c != nil {
+ return c
+ }
+ return nil
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *EventSourceCondition) DeepCopyInto(out *EventSourceCondition) {
+ *out = *in
+ return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EventSourceCondition.
+func (in *EventSourceCondition) DeepCopy() *EventSourceCondition {
+ if in == nil {
+ return nil
+ }
+ out := new(EventSourceCondition)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *EventSourceList) DeepCopyInto(out *EventSourceList) {
+ *out = *in
+ out.TypeMeta = in.TypeMeta
+ out.ListMeta = in.ListMeta
+ if in.Items != nil {
+ in, out := &in.Items, &out.Items
+ *out = make([]EventSource, len(*in))
+ for i := range *in {
+ (*in)[i].DeepCopyInto(&(*out)[i])
+ }
+ }
+ return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EventSourceList.
+func (in *EventSourceList) DeepCopy() *EventSourceList {
+ if in == nil {
+ return nil
+ }
+ out := new(EventSourceList)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *EventSourceList) DeepCopyObject() runtime.Object {
+ if c := in.DeepCopy(); c != nil {
+ return c
+ }
+ return nil
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *EventSourceSpec) DeepCopyInto(out *EventSourceSpec) {
+ *out = *in
+ return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EventSourceSpec.
+func (in *EventSourceSpec) DeepCopy() *EventSourceSpec {
+ if in == nil {
+ return nil
+ }
+ out := new(EventSourceSpec)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *EventSourceStatus) DeepCopyInto(out *EventSourceStatus) {
+ *out = *in
+ if in.Conditions != nil {
+ in, out := &in.Conditions, &out.Conditions
+ *out = make([]EventSourceCondition, len(*in))
+ copy(*out, *in)
+ }
+ return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EventSourceStatus.
+func (in *EventSourceStatus) DeepCopy() *EventSourceStatus {
+ if in == nil {
+ return nil
+ }
+ out := new(EventSourceStatus)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *EventType) DeepCopyInto(out *EventType) {
+ *out = *in
+ out.TypeMeta = in.TypeMeta
+ in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
+ in.Spec.DeepCopyInto(&out.Spec)
+ in.Status.DeepCopyInto(&out.Status)
+ return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EventType.
+func (in *EventType) DeepCopy() *EventType {
+ if in == nil {
+ return nil
+ }
+ out := new(EventType)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *EventType) DeepCopyObject() runtime.Object {
+ if c := in.DeepCopy(); c != nil {
+ return c
+ }
+ return nil
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *EventTypeCondition) DeepCopyInto(out *EventTypeCondition) {
+ *out = *in
+ return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EventTypeCondition.
+func (in *EventTypeCondition) DeepCopy() *EventTypeCondition {
+ if in == nil {
+ return nil
+ }
+ out := new(EventTypeCondition)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *EventTypeList) DeepCopyInto(out *EventTypeList) {
+ *out = *in
+ out.TypeMeta = in.TypeMeta
+ out.ListMeta = in.ListMeta
+ if in.Items != nil {
+ in, out := &in.Items, &out.Items
+ *out = make([]EventType, len(*in))
+ for i := range *in {
+ (*in)[i].DeepCopyInto(&(*out)[i])
+ }
+ }
+ return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EventTypeList.
+func (in *EventTypeList) DeepCopy() *EventTypeList {
+ if in == nil {
+ return nil
+ }
+ out := new(EventTypeList)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *EventTypeList) DeepCopyObject() runtime.Object {
+ if c := in.DeepCopy(); c != nil {
+ return c
+ }
+ return nil
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *EventTypeSpec) DeepCopyInto(out *EventTypeSpec) {
+ *out = *in
+ if in.SubscribeSchema != nil {
+ in, out := &in.SubscribeSchema, &out.SubscribeSchema
+ if *in == nil {
+ *out = nil
+ } else {
+ *out = new(runtime.RawExtension)
+ (*in).DeepCopyInto(*out)
+ }
+ }
+ if in.EventSchema != nil {
+ in, out := &in.EventSchema, &out.EventSchema
+ if *in == nil {
+ *out = nil
+ } else {
+ *out = new(runtime.RawExtension)
+ (*in).DeepCopyInto(*out)
+ }
+ }
+ return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EventTypeSpec.
+func (in *EventTypeSpec) DeepCopy() *EventTypeSpec {
+ if in == nil {
+ return nil
+ }
+ out := new(EventTypeSpec)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *EventTypeStatus) DeepCopyInto(out *EventTypeStatus) {
+ *out = *in
+ if in.Conditions != nil {
+ in, out := &in.Conditions, &out.Conditions
+ *out = make([]EventTypeCondition, len(*in))
+ copy(*out, *in)
+ }
+ return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EventTypeStatus.
+func (in *EventTypeStatus) DeepCopy() *EventTypeStatus {
+ if in == nil {
+ return nil
+ }
+ out := new(EventTypeStatus)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ParametersFromSource) DeepCopyInto(out *ParametersFromSource) {
+ *out = *in
+ if in.SecretKeyRef != nil {
+ in, out := &in.SecretKeyRef, &out.SecretKeyRef
+ if *in == nil {
+ *out = nil
+ } else {
+ *out = new(SecretKeyReference)
+ **out = **in
+ }
+ }
+ return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ParametersFromSource.
+func (in *ParametersFromSource) DeepCopy() *ParametersFromSource {
+ if in == nil {
+ return nil
+ }
+ out := new(ParametersFromSource)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *SecretKeyReference) DeepCopyInto(out *SecretKeyReference) {
+ *out = *in
+ return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretKeyReference.
+func (in *SecretKeyReference) DeepCopy() *SecretKeyReference {
+ if in == nil {
+ return nil
+ }
+ out := new(SecretKeyReference)
+ in.DeepCopyInto(out)
+ return out
+}
diff --git a/pkg/client/clientset/versioned/BUILD.bazel b/pkg/client/clientset/versioned/BUILD.bazel
new file mode 100644
index 00000000000..603bf9a91a1
--- /dev/null
+++ b/pkg/client/clientset/versioned/BUILD.bazel
@@ -0,0 +1,18 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_library")
+
+go_library(
+ name = "go_default_library",
+ srcs = [
+ "clientset.go",
+ "doc.go",
+ ],
+ importpath = "github.com/elafros/binding/pkg/client/clientset/versioned",
+ visibility = ["//visibility:public"],
+ deps = [
+ "//pkg/client/clientset/versioned/typed/bind/v1alpha1:go_default_library",
+ "//vendor/github.com/golang/glog:go_default_library",
+ "//vendor/k8s.io/client-go/discovery:go_default_library",
+ "//vendor/k8s.io/client-go/rest:go_default_library",
+ "//vendor/k8s.io/client-go/util/flowcontrol:go_default_library",
+ ],
+)
diff --git a/pkg/client/clientset/versioned/clientset.go b/pkg/client/clientset/versioned/clientset.go
new file mode 100644
index 00000000000..ac04432ce95
--- /dev/null
+++ b/pkg/client/clientset/versioned/clientset.go
@@ -0,0 +1,100 @@
+/*
+Copyright 2018 Google, 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.
+*/
+
+// Code generated by client-gen. DO NOT EDIT.
+
+package versioned
+
+import (
+ elafrosv1alpha1 "github.com/elafros/binding/pkg/client/clientset/versioned/typed/bind/v1alpha1"
+ glog "github.com/golang/glog"
+ discovery "k8s.io/client-go/discovery"
+ rest "k8s.io/client-go/rest"
+ flowcontrol "k8s.io/client-go/util/flowcontrol"
+)
+
+type Interface interface {
+ Discovery() discovery.DiscoveryInterface
+ ElafrosV1alpha1() elafrosv1alpha1.ElafrosV1alpha1Interface
+ // Deprecated: please explicitly pick a version if possible.
+ Elafros() elafrosv1alpha1.ElafrosV1alpha1Interface
+}
+
+// Clientset contains the clients for groups. Each group has exactly one
+// version included in a Clientset.
+type Clientset struct {
+ *discovery.DiscoveryClient
+ elafrosV1alpha1 *elafrosv1alpha1.ElafrosV1alpha1Client
+}
+
+// ElafrosV1alpha1 retrieves the ElafrosV1alpha1Client
+func (c *Clientset) ElafrosV1alpha1() elafrosv1alpha1.ElafrosV1alpha1Interface {
+ return c.elafrosV1alpha1
+}
+
+// Deprecated: Elafros retrieves the default version of ElafrosClient.
+// Please explicitly pick a version.
+func (c *Clientset) Elafros() elafrosv1alpha1.ElafrosV1alpha1Interface {
+ return c.elafrosV1alpha1
+}
+
+// Discovery retrieves the DiscoveryClient
+func (c *Clientset) Discovery() discovery.DiscoveryInterface {
+ if c == nil {
+ return nil
+ }
+ return c.DiscoveryClient
+}
+
+// NewForConfig creates a new Clientset for the given config.
+func NewForConfig(c *rest.Config) (*Clientset, error) {
+ configShallowCopy := *c
+ if configShallowCopy.RateLimiter == nil && configShallowCopy.QPS > 0 {
+ configShallowCopy.RateLimiter = flowcontrol.NewTokenBucketRateLimiter(configShallowCopy.QPS, configShallowCopy.Burst)
+ }
+ var cs Clientset
+ var err error
+ cs.elafrosV1alpha1, err = elafrosv1alpha1.NewForConfig(&configShallowCopy)
+ if err != nil {
+ return nil, err
+ }
+
+ cs.DiscoveryClient, err = discovery.NewDiscoveryClientForConfig(&configShallowCopy)
+ if err != nil {
+ glog.Errorf("failed to create the DiscoveryClient: %v", err)
+ return nil, err
+ }
+ return &cs, nil
+}
+
+// NewForConfigOrDie creates a new Clientset for the given config and
+// panics if there is an error in the config.
+func NewForConfigOrDie(c *rest.Config) *Clientset {
+ var cs Clientset
+ cs.elafrosV1alpha1 = elafrosv1alpha1.NewForConfigOrDie(c)
+
+ cs.DiscoveryClient = discovery.NewDiscoveryClientForConfigOrDie(c)
+ return &cs
+}
+
+// New creates a new Clientset for the given RESTClient.
+func New(c rest.Interface) *Clientset {
+ var cs Clientset
+ cs.elafrosV1alpha1 = elafrosv1alpha1.New(c)
+
+ cs.DiscoveryClient = discovery.NewDiscoveryClient(c)
+ return &cs
+}
diff --git a/pkg/client/clientset/versioned/doc.go b/pkg/client/clientset/versioned/doc.go
new file mode 100644
index 00000000000..77edf19e4e0
--- /dev/null
+++ b/pkg/client/clientset/versioned/doc.go
@@ -0,0 +1,20 @@
+/*
+Copyright 2018 Google, 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.
+*/
+
+// Code generated by client-gen. DO NOT EDIT.
+
+// This package has the automatically generated clientset.
+package versioned
diff --git a/pkg/client/clientset/versioned/fake/BUILD.bazel b/pkg/client/clientset/versioned/fake/BUILD.bazel
new file mode 100644
index 00000000000..92d112e79b1
--- /dev/null
+++ b/pkg/client/clientset/versioned/fake/BUILD.bazel
@@ -0,0 +1,26 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_library")
+
+go_library(
+ name = "go_default_library",
+ srcs = [
+ "clientset_generated.go",
+ "doc.go",
+ "register.go",
+ ],
+ importpath = "github.com/elafros/binding/pkg/client/clientset/versioned/fake",
+ visibility = ["//visibility:public"],
+ deps = [
+ "//pkg/apis/bind/v1alpha1:go_default_library",
+ "//pkg/client/clientset/versioned:go_default_library",
+ "//pkg/client/clientset/versioned/typed/bind/v1alpha1:go_default_library",
+ "//pkg/client/clientset/versioned/typed/bind/v1alpha1/fake:go_default_library",
+ "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
+ "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
+ "//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
+ "//vendor/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library",
+ "//vendor/k8s.io/apimachinery/pkg/watch:go_default_library",
+ "//vendor/k8s.io/client-go/discovery:go_default_library",
+ "//vendor/k8s.io/client-go/discovery/fake:go_default_library",
+ "//vendor/k8s.io/client-go/testing:go_default_library",
+ ],
+)
diff --git a/pkg/client/clientset/versioned/fake/clientset_generated.go b/pkg/client/clientset/versioned/fake/clientset_generated.go
new file mode 100644
index 00000000000..4287859907b
--- /dev/null
+++ b/pkg/client/clientset/versioned/fake/clientset_generated.go
@@ -0,0 +1,73 @@
+/*
+Copyright 2018 Google, 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.
+*/
+
+// Code generated by client-gen. DO NOT EDIT.
+
+package fake
+
+import (
+ clientset "github.com/elafros/binding/pkg/client/clientset/versioned"
+ elafrosv1alpha1 "github.com/elafros/binding/pkg/client/clientset/versioned/typed/bind/v1alpha1"
+ fakeelafrosv1alpha1 "github.com/elafros/binding/pkg/client/clientset/versioned/typed/bind/v1alpha1/fake"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/watch"
+ "k8s.io/client-go/discovery"
+ fakediscovery "k8s.io/client-go/discovery/fake"
+ "k8s.io/client-go/testing"
+)
+
+// NewSimpleClientset returns a clientset that will respond with the provided objects.
+// It's backed by a very simple object tracker that processes creates, updates and deletions as-is,
+// without applying any validations and/or defaults. It shouldn't be considered a replacement
+// for a real clientset and is mostly useful in simple unit tests.
+func NewSimpleClientset(objects ...runtime.Object) *Clientset {
+ o := testing.NewObjectTracker(scheme, codecs.UniversalDecoder())
+ for _, obj := range objects {
+ if err := o.Add(obj); err != nil {
+ panic(err)
+ }
+ }
+
+ fakePtr := testing.Fake{}
+ fakePtr.AddReactor("*", "*", testing.ObjectReaction(o))
+ fakePtr.AddWatchReactor("*", testing.DefaultWatchReactor(watch.NewFake(), nil))
+
+ return &Clientset{fakePtr, &fakediscovery.FakeDiscovery{Fake: &fakePtr}}
+}
+
+// Clientset implements clientset.Interface. Meant to be embedded into a
+// struct to get a default implementation. This makes faking out just the method
+// you want to test easier.
+type Clientset struct {
+ testing.Fake
+ discovery *fakediscovery.FakeDiscovery
+}
+
+func (c *Clientset) Discovery() discovery.DiscoveryInterface {
+ return c.discovery
+}
+
+var _ clientset.Interface = &Clientset{}
+
+// ElafrosV1alpha1 retrieves the ElafrosV1alpha1Client
+func (c *Clientset) ElafrosV1alpha1() elafrosv1alpha1.ElafrosV1alpha1Interface {
+ return &fakeelafrosv1alpha1.FakeElafrosV1alpha1{Fake: &c.Fake}
+}
+
+// Elafros retrieves the ElafrosV1alpha1Client
+func (c *Clientset) Elafros() elafrosv1alpha1.ElafrosV1alpha1Interface {
+ return &fakeelafrosv1alpha1.FakeElafrosV1alpha1{Fake: &c.Fake}
+}
diff --git a/pkg/client/clientset/versioned/fake/doc.go b/pkg/client/clientset/versioned/fake/doc.go
new file mode 100644
index 00000000000..7625f531fcf
--- /dev/null
+++ b/pkg/client/clientset/versioned/fake/doc.go
@@ -0,0 +1,20 @@
+/*
+Copyright 2018 Google, 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.
+*/
+
+// Code generated by client-gen. DO NOT EDIT.
+
+// This package has the automatically generated fake clientset.
+package fake
diff --git a/pkg/client/clientset/versioned/fake/register.go b/pkg/client/clientset/versioned/fake/register.go
new file mode 100644
index 00000000000..076051d517e
--- /dev/null
+++ b/pkg/client/clientset/versioned/fake/register.go
@@ -0,0 +1,55 @@
+/*
+Copyright 2018 Google, 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.
+*/
+
+// Code generated by client-gen. DO NOT EDIT.
+
+package fake
+
+import (
+ elafrosv1alpha1 "github.com/elafros/binding/pkg/apis/bind/v1alpha1"
+ v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ runtime "k8s.io/apimachinery/pkg/runtime"
+ schema "k8s.io/apimachinery/pkg/runtime/schema"
+ serializer "k8s.io/apimachinery/pkg/runtime/serializer"
+)
+
+var scheme = runtime.NewScheme()
+var codecs = serializer.NewCodecFactory(scheme)
+var parameterCodec = runtime.NewParameterCodec(scheme)
+
+func init() {
+ v1.AddToGroupVersion(scheme, schema.GroupVersion{Version: "v1"})
+ AddToScheme(scheme)
+}
+
+// AddToScheme adds all types of this clientset into the given scheme. This allows composition
+// of clientsets, like in:
+//
+// import (
+// "k8s.io/client-go/kubernetes"
+// clientsetscheme "k8s.io/client-go/kuberentes/scheme"
+// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme"
+// )
+//
+// kclientset, _ := kubernetes.NewForConfig(c)
+// aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme)
+//
+// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types
+// correctly.
+func AddToScheme(scheme *runtime.Scheme) {
+ elafrosv1alpha1.AddToScheme(scheme)
+
+}
diff --git a/pkg/client/clientset/versioned/scheme/BUILD.bazel b/pkg/client/clientset/versioned/scheme/BUILD.bazel
new file mode 100644
index 00000000000..24707e6ff99
--- /dev/null
+++ b/pkg/client/clientset/versioned/scheme/BUILD.bazel
@@ -0,0 +1,18 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_library")
+
+go_library(
+ name = "go_default_library",
+ srcs = [
+ "doc.go",
+ "register.go",
+ ],
+ importpath = "github.com/elafros/binding/pkg/client/clientset/versioned/scheme",
+ visibility = ["//visibility:public"],
+ deps = [
+ "//pkg/apis/bind/v1alpha1:go_default_library",
+ "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
+ "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
+ "//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
+ "//vendor/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library",
+ ],
+)
diff --git a/pkg/client/clientset/versioned/scheme/doc.go b/pkg/client/clientset/versioned/scheme/doc.go
new file mode 100644
index 00000000000..3dabeaea201
--- /dev/null
+++ b/pkg/client/clientset/versioned/scheme/doc.go
@@ -0,0 +1,20 @@
+/*
+Copyright 2018 Google, 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.
+*/
+
+// Code generated by client-gen. DO NOT EDIT.
+
+// This package contains the scheme of the automatically generated clientset.
+package scheme
diff --git a/pkg/client/clientset/versioned/scheme/register.go b/pkg/client/clientset/versioned/scheme/register.go
new file mode 100644
index 00000000000..7ba92ff47c9
--- /dev/null
+++ b/pkg/client/clientset/versioned/scheme/register.go
@@ -0,0 +1,55 @@
+/*
+Copyright 2018 Google, 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.
+*/
+
+// Code generated by client-gen. DO NOT EDIT.
+
+package scheme
+
+import (
+ elafrosv1alpha1 "github.com/elafros/binding/pkg/apis/bind/v1alpha1"
+ v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ runtime "k8s.io/apimachinery/pkg/runtime"
+ schema "k8s.io/apimachinery/pkg/runtime/schema"
+ serializer "k8s.io/apimachinery/pkg/runtime/serializer"
+)
+
+var Scheme = runtime.NewScheme()
+var Codecs = serializer.NewCodecFactory(Scheme)
+var ParameterCodec = runtime.NewParameterCodec(Scheme)
+
+func init() {
+ v1.AddToGroupVersion(Scheme, schema.GroupVersion{Version: "v1"})
+ AddToScheme(Scheme)
+}
+
+// AddToScheme adds all types of this clientset into the given scheme. This allows composition
+// of clientsets, like in:
+//
+// import (
+// "k8s.io/client-go/kubernetes"
+// clientsetscheme "k8s.io/client-go/kuberentes/scheme"
+// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme"
+// )
+//
+// kclientset, _ := kubernetes.NewForConfig(c)
+// aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme)
+//
+// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types
+// correctly.
+func AddToScheme(scheme *runtime.Scheme) {
+ elafrosv1alpha1.AddToScheme(scheme)
+
+}
diff --git a/pkg/client/clientset/versioned/typed/bind/v1alpha1/BUILD.bazel b/pkg/client/clientset/versioned/typed/bind/v1alpha1/BUILD.bazel
new file mode 100644
index 00000000000..c649ed2e8d4
--- /dev/null
+++ b/pkg/client/clientset/versioned/typed/bind/v1alpha1/BUILD.bazel
@@ -0,0 +1,24 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_library")
+
+go_library(
+ name = "go_default_library",
+ srcs = [
+ "bind.go",
+ "bind_client.go",
+ "doc.go",
+ "eventsource.go",
+ "eventtype.go",
+ "generated_expansion.go",
+ ],
+ importpath = "github.com/elafros/binding/pkg/client/clientset/versioned/typed/bind/v1alpha1",
+ visibility = ["//visibility:public"],
+ deps = [
+ "//pkg/apis/bind/v1alpha1:go_default_library",
+ "//pkg/client/clientset/versioned/scheme:go_default_library",
+ "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
+ "//vendor/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library",
+ "//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
+ "//vendor/k8s.io/apimachinery/pkg/watch:go_default_library",
+ "//vendor/k8s.io/client-go/rest:go_default_library",
+ ],
+)
diff --git a/pkg/client/clientset/versioned/typed/bind/v1alpha1/bind.go b/pkg/client/clientset/versioned/typed/bind/v1alpha1/bind.go
new file mode 100644
index 00000000000..774710990cb
--- /dev/null
+++ b/pkg/client/clientset/versioned/typed/bind/v1alpha1/bind.go
@@ -0,0 +1,174 @@
+/*
+Copyright 2018 Google, 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.
+*/
+
+// Code generated by client-gen. DO NOT EDIT.
+
+package v1alpha1
+
+import (
+ v1alpha1 "github.com/elafros/binding/pkg/apis/bind/v1alpha1"
+ scheme "github.com/elafros/binding/pkg/client/clientset/versioned/scheme"
+ v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ types "k8s.io/apimachinery/pkg/types"
+ watch "k8s.io/apimachinery/pkg/watch"
+ rest "k8s.io/client-go/rest"
+)
+
+// BindsGetter has a method to return a BindInterface.
+// A group's client should implement this interface.
+type BindsGetter interface {
+ Binds(namespace string) BindInterface
+}
+
+// BindInterface has methods to work with Bind resources.
+type BindInterface interface {
+ Create(*v1alpha1.Bind) (*v1alpha1.Bind, error)
+ Update(*v1alpha1.Bind) (*v1alpha1.Bind, error)
+ UpdateStatus(*v1alpha1.Bind) (*v1alpha1.Bind, error)
+ Delete(name string, options *v1.DeleteOptions) error
+ DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error
+ Get(name string, options v1.GetOptions) (*v1alpha1.Bind, error)
+ List(opts v1.ListOptions) (*v1alpha1.BindList, error)
+ Watch(opts v1.ListOptions) (watch.Interface, error)
+ Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.Bind, err error)
+ BindExpansion
+}
+
+// binds implements BindInterface
+type binds struct {
+ client rest.Interface
+ ns string
+}
+
+// newBinds returns a Binds
+func newBinds(c *ElafrosV1alpha1Client, namespace string) *binds {
+ return &binds{
+ client: c.RESTClient(),
+ ns: namespace,
+ }
+}
+
+// Get takes name of the bind, and returns the corresponding bind object, and an error if there is any.
+func (c *binds) Get(name string, options v1.GetOptions) (result *v1alpha1.Bind, err error) {
+ result = &v1alpha1.Bind{}
+ err = c.client.Get().
+ Namespace(c.ns).
+ Resource("binds").
+ Name(name).
+ VersionedParams(&options, scheme.ParameterCodec).
+ Do().
+ Into(result)
+ return
+}
+
+// List takes label and field selectors, and returns the list of Binds that match those selectors.
+func (c *binds) List(opts v1.ListOptions) (result *v1alpha1.BindList, err error) {
+ result = &v1alpha1.BindList{}
+ err = c.client.Get().
+ Namespace(c.ns).
+ Resource("binds").
+ VersionedParams(&opts, scheme.ParameterCodec).
+ Do().
+ Into(result)
+ return
+}
+
+// Watch returns a watch.Interface that watches the requested binds.
+func (c *binds) Watch(opts v1.ListOptions) (watch.Interface, error) {
+ opts.Watch = true
+ return c.client.Get().
+ Namespace(c.ns).
+ Resource("binds").
+ VersionedParams(&opts, scheme.ParameterCodec).
+ Watch()
+}
+
+// Create takes the representation of a bind and creates it. Returns the server's representation of the bind, and an error, if there is any.
+func (c *binds) Create(bind *v1alpha1.Bind) (result *v1alpha1.Bind, err error) {
+ result = &v1alpha1.Bind{}
+ err = c.client.Post().
+ Namespace(c.ns).
+ Resource("binds").
+ Body(bind).
+ Do().
+ Into(result)
+ return
+}
+
+// Update takes the representation of a bind and updates it. Returns the server's representation of the bind, and an error, if there is any.
+func (c *binds) Update(bind *v1alpha1.Bind) (result *v1alpha1.Bind, err error) {
+ result = &v1alpha1.Bind{}
+ err = c.client.Put().
+ Namespace(c.ns).
+ Resource("binds").
+ Name(bind.Name).
+ Body(bind).
+ Do().
+ Into(result)
+ return
+}
+
+// UpdateStatus was generated because the type contains a Status member.
+// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
+
+func (c *binds) UpdateStatus(bind *v1alpha1.Bind) (result *v1alpha1.Bind, err error) {
+ result = &v1alpha1.Bind{}
+ err = c.client.Put().
+ Namespace(c.ns).
+ Resource("binds").
+ Name(bind.Name).
+ SubResource("status").
+ Body(bind).
+ Do().
+ Into(result)
+ return
+}
+
+// Delete takes name of the bind and deletes it. Returns an error if one occurs.
+func (c *binds) Delete(name string, options *v1.DeleteOptions) error {
+ return c.client.Delete().
+ Namespace(c.ns).
+ Resource("binds").
+ Name(name).
+ Body(options).
+ Do().
+ Error()
+}
+
+// DeleteCollection deletes a collection of objects.
+func (c *binds) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error {
+ return c.client.Delete().
+ Namespace(c.ns).
+ Resource("binds").
+ VersionedParams(&listOptions, scheme.ParameterCodec).
+ Body(options).
+ Do().
+ Error()
+}
+
+// Patch applies the patch and returns the patched bind.
+func (c *binds) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.Bind, err error) {
+ result = &v1alpha1.Bind{}
+ err = c.client.Patch(pt).
+ Namespace(c.ns).
+ Resource("binds").
+ SubResource(subresources...).
+ Name(name).
+ Body(data).
+ Do().
+ Into(result)
+ return
+}
diff --git a/pkg/client/clientset/versioned/typed/bind/v1alpha1/bind_client.go b/pkg/client/clientset/versioned/typed/bind/v1alpha1/bind_client.go
new file mode 100644
index 00000000000..b0947f2f64a
--- /dev/null
+++ b/pkg/client/clientset/versioned/typed/bind/v1alpha1/bind_client.go
@@ -0,0 +1,100 @@
+/*
+Copyright 2018 Google, 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.
+*/
+
+// Code generated by client-gen. DO NOT EDIT.
+
+package v1alpha1
+
+import (
+ v1alpha1 "github.com/elafros/binding/pkg/apis/bind/v1alpha1"
+ "github.com/elafros/binding/pkg/client/clientset/versioned/scheme"
+ serializer "k8s.io/apimachinery/pkg/runtime/serializer"
+ rest "k8s.io/client-go/rest"
+)
+
+type ElafrosV1alpha1Interface interface {
+ RESTClient() rest.Interface
+ BindsGetter
+ EventSourcesGetter
+ EventTypesGetter
+}
+
+// ElafrosV1alpha1Client is used to interact with features provided by the elafros.dev group.
+type ElafrosV1alpha1Client struct {
+ restClient rest.Interface
+}
+
+func (c *ElafrosV1alpha1Client) Binds(namespace string) BindInterface {
+ return newBinds(c, namespace)
+}
+
+func (c *ElafrosV1alpha1Client) EventSources(namespace string) EventSourceInterface {
+ return newEventSources(c, namespace)
+}
+
+func (c *ElafrosV1alpha1Client) EventTypes(namespace string) EventTypeInterface {
+ return newEventTypes(c, namespace)
+}
+
+// NewForConfig creates a new ElafrosV1alpha1Client for the given config.
+func NewForConfig(c *rest.Config) (*ElafrosV1alpha1Client, error) {
+ config := *c
+ if err := setConfigDefaults(&config); err != nil {
+ return nil, err
+ }
+ client, err := rest.RESTClientFor(&config)
+ if err != nil {
+ return nil, err
+ }
+ return &ElafrosV1alpha1Client{client}, nil
+}
+
+// NewForConfigOrDie creates a new ElafrosV1alpha1Client for the given config and
+// panics if there is an error in the config.
+func NewForConfigOrDie(c *rest.Config) *ElafrosV1alpha1Client {
+ client, err := NewForConfig(c)
+ if err != nil {
+ panic(err)
+ }
+ return client
+}
+
+// New creates a new ElafrosV1alpha1Client for the given RESTClient.
+func New(c rest.Interface) *ElafrosV1alpha1Client {
+ return &ElafrosV1alpha1Client{c}
+}
+
+func setConfigDefaults(config *rest.Config) error {
+ gv := v1alpha1.SchemeGroupVersion
+ config.GroupVersion = &gv
+ config.APIPath = "/apis"
+ config.NegotiatedSerializer = serializer.DirectCodecFactory{CodecFactory: scheme.Codecs}
+
+ if config.UserAgent == "" {
+ config.UserAgent = rest.DefaultKubernetesUserAgent()
+ }
+
+ return nil
+}
+
+// RESTClient returns a RESTClient that is used to communicate
+// with API server by this client implementation.
+func (c *ElafrosV1alpha1Client) RESTClient() rest.Interface {
+ if c == nil {
+ return nil
+ }
+ return c.restClient
+}
diff --git a/pkg/client/clientset/versioned/typed/bind/v1alpha1/doc.go b/pkg/client/clientset/versioned/typed/bind/v1alpha1/doc.go
new file mode 100644
index 00000000000..1d8f2a89974
--- /dev/null
+++ b/pkg/client/clientset/versioned/typed/bind/v1alpha1/doc.go
@@ -0,0 +1,20 @@
+/*
+Copyright 2018 Google, 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.
+*/
+
+// Code generated by client-gen. DO NOT EDIT.
+
+// This package has the automatically generated typed clients.
+package v1alpha1
diff --git a/pkg/client/clientset/versioned/typed/bind/v1alpha1/eventsource.go b/pkg/client/clientset/versioned/typed/bind/v1alpha1/eventsource.go
new file mode 100644
index 00000000000..530c8d2f0e7
--- /dev/null
+++ b/pkg/client/clientset/versioned/typed/bind/v1alpha1/eventsource.go
@@ -0,0 +1,174 @@
+/*
+Copyright 2018 Google, 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.
+*/
+
+// Code generated by client-gen. DO NOT EDIT.
+
+package v1alpha1
+
+import (
+ v1alpha1 "github.com/elafros/binding/pkg/apis/bind/v1alpha1"
+ scheme "github.com/elafros/binding/pkg/client/clientset/versioned/scheme"
+ v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ types "k8s.io/apimachinery/pkg/types"
+ watch "k8s.io/apimachinery/pkg/watch"
+ rest "k8s.io/client-go/rest"
+)
+
+// EventSourcesGetter has a method to return a EventSourceInterface.
+// A group's client should implement this interface.
+type EventSourcesGetter interface {
+ EventSources(namespace string) EventSourceInterface
+}
+
+// EventSourceInterface has methods to work with EventSource resources.
+type EventSourceInterface interface {
+ Create(*v1alpha1.EventSource) (*v1alpha1.EventSource, error)
+ Update(*v1alpha1.EventSource) (*v1alpha1.EventSource, error)
+ UpdateStatus(*v1alpha1.EventSource) (*v1alpha1.EventSource, error)
+ Delete(name string, options *v1.DeleteOptions) error
+ DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error
+ Get(name string, options v1.GetOptions) (*v1alpha1.EventSource, error)
+ List(opts v1.ListOptions) (*v1alpha1.EventSourceList, error)
+ Watch(opts v1.ListOptions) (watch.Interface, error)
+ Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.EventSource, err error)
+ EventSourceExpansion
+}
+
+// eventSources implements EventSourceInterface
+type eventSources struct {
+ client rest.Interface
+ ns string
+}
+
+// newEventSources returns a EventSources
+func newEventSources(c *ElafrosV1alpha1Client, namespace string) *eventSources {
+ return &eventSources{
+ client: c.RESTClient(),
+ ns: namespace,
+ }
+}
+
+// Get takes name of the eventSource, and returns the corresponding eventSource object, and an error if there is any.
+func (c *eventSources) Get(name string, options v1.GetOptions) (result *v1alpha1.EventSource, err error) {
+ result = &v1alpha1.EventSource{}
+ err = c.client.Get().
+ Namespace(c.ns).
+ Resource("eventsources").
+ Name(name).
+ VersionedParams(&options, scheme.ParameterCodec).
+ Do().
+ Into(result)
+ return
+}
+
+// List takes label and field selectors, and returns the list of EventSources that match those selectors.
+func (c *eventSources) List(opts v1.ListOptions) (result *v1alpha1.EventSourceList, err error) {
+ result = &v1alpha1.EventSourceList{}
+ err = c.client.Get().
+ Namespace(c.ns).
+ Resource("eventsources").
+ VersionedParams(&opts, scheme.ParameterCodec).
+ Do().
+ Into(result)
+ return
+}
+
+// Watch returns a watch.Interface that watches the requested eventSources.
+func (c *eventSources) Watch(opts v1.ListOptions) (watch.Interface, error) {
+ opts.Watch = true
+ return c.client.Get().
+ Namespace(c.ns).
+ Resource("eventsources").
+ VersionedParams(&opts, scheme.ParameterCodec).
+ Watch()
+}
+
+// Create takes the representation of a eventSource and creates it. Returns the server's representation of the eventSource, and an error, if there is any.
+func (c *eventSources) Create(eventSource *v1alpha1.EventSource) (result *v1alpha1.EventSource, err error) {
+ result = &v1alpha1.EventSource{}
+ err = c.client.Post().
+ Namespace(c.ns).
+ Resource("eventsources").
+ Body(eventSource).
+ Do().
+ Into(result)
+ return
+}
+
+// Update takes the representation of a eventSource and updates it. Returns the server's representation of the eventSource, and an error, if there is any.
+func (c *eventSources) Update(eventSource *v1alpha1.EventSource) (result *v1alpha1.EventSource, err error) {
+ result = &v1alpha1.EventSource{}
+ err = c.client.Put().
+ Namespace(c.ns).
+ Resource("eventsources").
+ Name(eventSource.Name).
+ Body(eventSource).
+ Do().
+ Into(result)
+ return
+}
+
+// UpdateStatus was generated because the type contains a Status member.
+// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
+
+func (c *eventSources) UpdateStatus(eventSource *v1alpha1.EventSource) (result *v1alpha1.EventSource, err error) {
+ result = &v1alpha1.EventSource{}
+ err = c.client.Put().
+ Namespace(c.ns).
+ Resource("eventsources").
+ Name(eventSource.Name).
+ SubResource("status").
+ Body(eventSource).
+ Do().
+ Into(result)
+ return
+}
+
+// Delete takes name of the eventSource and deletes it. Returns an error if one occurs.
+func (c *eventSources) Delete(name string, options *v1.DeleteOptions) error {
+ return c.client.Delete().
+ Namespace(c.ns).
+ Resource("eventsources").
+ Name(name).
+ Body(options).
+ Do().
+ Error()
+}
+
+// DeleteCollection deletes a collection of objects.
+func (c *eventSources) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error {
+ return c.client.Delete().
+ Namespace(c.ns).
+ Resource("eventsources").
+ VersionedParams(&listOptions, scheme.ParameterCodec).
+ Body(options).
+ Do().
+ Error()
+}
+
+// Patch applies the patch and returns the patched eventSource.
+func (c *eventSources) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.EventSource, err error) {
+ result = &v1alpha1.EventSource{}
+ err = c.client.Patch(pt).
+ Namespace(c.ns).
+ Resource("eventsources").
+ SubResource(subresources...).
+ Name(name).
+ Body(data).
+ Do().
+ Into(result)
+ return
+}
diff --git a/pkg/client/clientset/versioned/typed/bind/v1alpha1/eventtype.go b/pkg/client/clientset/versioned/typed/bind/v1alpha1/eventtype.go
new file mode 100644
index 00000000000..680eb5e8e63
--- /dev/null
+++ b/pkg/client/clientset/versioned/typed/bind/v1alpha1/eventtype.go
@@ -0,0 +1,174 @@
+/*
+Copyright 2018 Google, 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.
+*/
+
+// Code generated by client-gen. DO NOT EDIT.
+
+package v1alpha1
+
+import (
+ v1alpha1 "github.com/elafros/binding/pkg/apis/bind/v1alpha1"
+ scheme "github.com/elafros/binding/pkg/client/clientset/versioned/scheme"
+ v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ types "k8s.io/apimachinery/pkg/types"
+ watch "k8s.io/apimachinery/pkg/watch"
+ rest "k8s.io/client-go/rest"
+)
+
+// EventTypesGetter has a method to return a EventTypeInterface.
+// A group's client should implement this interface.
+type EventTypesGetter interface {
+ EventTypes(namespace string) EventTypeInterface
+}
+
+// EventTypeInterface has methods to work with EventType resources.
+type EventTypeInterface interface {
+ Create(*v1alpha1.EventType) (*v1alpha1.EventType, error)
+ Update(*v1alpha1.EventType) (*v1alpha1.EventType, error)
+ UpdateStatus(*v1alpha1.EventType) (*v1alpha1.EventType, error)
+ Delete(name string, options *v1.DeleteOptions) error
+ DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error
+ Get(name string, options v1.GetOptions) (*v1alpha1.EventType, error)
+ List(opts v1.ListOptions) (*v1alpha1.EventTypeList, error)
+ Watch(opts v1.ListOptions) (watch.Interface, error)
+ Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.EventType, err error)
+ EventTypeExpansion
+}
+
+// eventTypes implements EventTypeInterface
+type eventTypes struct {
+ client rest.Interface
+ ns string
+}
+
+// newEventTypes returns a EventTypes
+func newEventTypes(c *ElafrosV1alpha1Client, namespace string) *eventTypes {
+ return &eventTypes{
+ client: c.RESTClient(),
+ ns: namespace,
+ }
+}
+
+// Get takes name of the eventType, and returns the corresponding eventType object, and an error if there is any.
+func (c *eventTypes) Get(name string, options v1.GetOptions) (result *v1alpha1.EventType, err error) {
+ result = &v1alpha1.EventType{}
+ err = c.client.Get().
+ Namespace(c.ns).
+ Resource("eventtypes").
+ Name(name).
+ VersionedParams(&options, scheme.ParameterCodec).
+ Do().
+ Into(result)
+ return
+}
+
+// List takes label and field selectors, and returns the list of EventTypes that match those selectors.
+func (c *eventTypes) List(opts v1.ListOptions) (result *v1alpha1.EventTypeList, err error) {
+ result = &v1alpha1.EventTypeList{}
+ err = c.client.Get().
+ Namespace(c.ns).
+ Resource("eventtypes").
+ VersionedParams(&opts, scheme.ParameterCodec).
+ Do().
+ Into(result)
+ return
+}
+
+// Watch returns a watch.Interface that watches the requested eventTypes.
+func (c *eventTypes) Watch(opts v1.ListOptions) (watch.Interface, error) {
+ opts.Watch = true
+ return c.client.Get().
+ Namespace(c.ns).
+ Resource("eventtypes").
+ VersionedParams(&opts, scheme.ParameterCodec).
+ Watch()
+}
+
+// Create takes the representation of a eventType and creates it. Returns the server's representation of the eventType, and an error, if there is any.
+func (c *eventTypes) Create(eventType *v1alpha1.EventType) (result *v1alpha1.EventType, err error) {
+ result = &v1alpha1.EventType{}
+ err = c.client.Post().
+ Namespace(c.ns).
+ Resource("eventtypes").
+ Body(eventType).
+ Do().
+ Into(result)
+ return
+}
+
+// Update takes the representation of a eventType and updates it. Returns the server's representation of the eventType, and an error, if there is any.
+func (c *eventTypes) Update(eventType *v1alpha1.EventType) (result *v1alpha1.EventType, err error) {
+ result = &v1alpha1.EventType{}
+ err = c.client.Put().
+ Namespace(c.ns).
+ Resource("eventtypes").
+ Name(eventType.Name).
+ Body(eventType).
+ Do().
+ Into(result)
+ return
+}
+
+// UpdateStatus was generated because the type contains a Status member.
+// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
+
+func (c *eventTypes) UpdateStatus(eventType *v1alpha1.EventType) (result *v1alpha1.EventType, err error) {
+ result = &v1alpha1.EventType{}
+ err = c.client.Put().
+ Namespace(c.ns).
+ Resource("eventtypes").
+ Name(eventType.Name).
+ SubResource("status").
+ Body(eventType).
+ Do().
+ Into(result)
+ return
+}
+
+// Delete takes name of the eventType and deletes it. Returns an error if one occurs.
+func (c *eventTypes) Delete(name string, options *v1.DeleteOptions) error {
+ return c.client.Delete().
+ Namespace(c.ns).
+ Resource("eventtypes").
+ Name(name).
+ Body(options).
+ Do().
+ Error()
+}
+
+// DeleteCollection deletes a collection of objects.
+func (c *eventTypes) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error {
+ return c.client.Delete().
+ Namespace(c.ns).
+ Resource("eventtypes").
+ VersionedParams(&listOptions, scheme.ParameterCodec).
+ Body(options).
+ Do().
+ Error()
+}
+
+// Patch applies the patch and returns the patched eventType.
+func (c *eventTypes) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.EventType, err error) {
+ result = &v1alpha1.EventType{}
+ err = c.client.Patch(pt).
+ Namespace(c.ns).
+ Resource("eventtypes").
+ SubResource(subresources...).
+ Name(name).
+ Body(data).
+ Do().
+ Into(result)
+ return
+}
diff --git a/pkg/client/clientset/versioned/typed/bind/v1alpha1/fake/BUILD.bazel b/pkg/client/clientset/versioned/typed/bind/v1alpha1/fake/BUILD.bazel
new file mode 100644
index 00000000000..dc4e6913b4b
--- /dev/null
+++ b/pkg/client/clientset/versioned/typed/bind/v1alpha1/fake/BUILD.bazel
@@ -0,0 +1,25 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_library")
+
+go_library(
+ name = "go_default_library",
+ srcs = [
+ "doc.go",
+ "fake_bind.go",
+ "fake_bind_client.go",
+ "fake_eventsource.go",
+ "fake_eventtype.go",
+ ],
+ importpath = "github.com/elafros/binding/pkg/client/clientset/versioned/typed/bind/v1alpha1/fake",
+ visibility = ["//visibility:public"],
+ deps = [
+ "//pkg/apis/bind/v1alpha1:go_default_library",
+ "//pkg/client/clientset/versioned/typed/bind/v1alpha1:go_default_library",
+ "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
+ "//vendor/k8s.io/apimachinery/pkg/labels:go_default_library",
+ "//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
+ "//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
+ "//vendor/k8s.io/apimachinery/pkg/watch:go_default_library",
+ "//vendor/k8s.io/client-go/rest:go_default_library",
+ "//vendor/k8s.io/client-go/testing:go_default_library",
+ ],
+)
diff --git a/pkg/client/clientset/versioned/typed/bind/v1alpha1/fake/doc.go b/pkg/client/clientset/versioned/typed/bind/v1alpha1/fake/doc.go
new file mode 100644
index 00000000000..2195046d473
--- /dev/null
+++ b/pkg/client/clientset/versioned/typed/bind/v1alpha1/fake/doc.go
@@ -0,0 +1,20 @@
+/*
+Copyright 2018 Google, 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.
+*/
+
+// Code generated by client-gen. DO NOT EDIT.
+
+// Package fake has the automatically generated clients.
+package fake
diff --git a/pkg/client/clientset/versioned/typed/bind/v1alpha1/fake/fake_bind.go b/pkg/client/clientset/versioned/typed/bind/v1alpha1/fake/fake_bind.go
new file mode 100644
index 00000000000..7a335876e6e
--- /dev/null
+++ b/pkg/client/clientset/versioned/typed/bind/v1alpha1/fake/fake_bind.go
@@ -0,0 +1,140 @@
+/*
+Copyright 2018 Google, 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.
+*/
+
+// Code generated by client-gen. DO NOT EDIT.
+
+package fake
+
+import (
+ v1alpha1 "github.com/elafros/binding/pkg/apis/bind/v1alpha1"
+ v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ labels "k8s.io/apimachinery/pkg/labels"
+ schema "k8s.io/apimachinery/pkg/runtime/schema"
+ types "k8s.io/apimachinery/pkg/types"
+ watch "k8s.io/apimachinery/pkg/watch"
+ testing "k8s.io/client-go/testing"
+)
+
+// FakeBinds implements BindInterface
+type FakeBinds struct {
+ Fake *FakeElafrosV1alpha1
+ ns string
+}
+
+var bindsResource = schema.GroupVersionResource{Group: "elafros.dev", Version: "v1alpha1", Resource: "binds"}
+
+var bindsKind = schema.GroupVersionKind{Group: "elafros.dev", Version: "v1alpha1", Kind: "Bind"}
+
+// Get takes name of the bind, and returns the corresponding bind object, and an error if there is any.
+func (c *FakeBinds) Get(name string, options v1.GetOptions) (result *v1alpha1.Bind, err error) {
+ obj, err := c.Fake.
+ Invokes(testing.NewGetAction(bindsResource, c.ns, name), &v1alpha1.Bind{})
+
+ if obj == nil {
+ return nil, err
+ }
+ return obj.(*v1alpha1.Bind), err
+}
+
+// List takes label and field selectors, and returns the list of Binds that match those selectors.
+func (c *FakeBinds) List(opts v1.ListOptions) (result *v1alpha1.BindList, err error) {
+ obj, err := c.Fake.
+ Invokes(testing.NewListAction(bindsResource, bindsKind, c.ns, opts), &v1alpha1.BindList{})
+
+ if obj == nil {
+ return nil, err
+ }
+
+ label, _, _ := testing.ExtractFromListOptions(opts)
+ if label == nil {
+ label = labels.Everything()
+ }
+ list := &v1alpha1.BindList{}
+ for _, item := range obj.(*v1alpha1.BindList).Items {
+ if label.Matches(labels.Set(item.Labels)) {
+ list.Items = append(list.Items, item)
+ }
+ }
+ return list, err
+}
+
+// Watch returns a watch.Interface that watches the requested binds.
+func (c *FakeBinds) Watch(opts v1.ListOptions) (watch.Interface, error) {
+ return c.Fake.
+ InvokesWatch(testing.NewWatchAction(bindsResource, c.ns, opts))
+
+}
+
+// Create takes the representation of a bind and creates it. Returns the server's representation of the bind, and an error, if there is any.
+func (c *FakeBinds) Create(bind *v1alpha1.Bind) (result *v1alpha1.Bind, err error) {
+ obj, err := c.Fake.
+ Invokes(testing.NewCreateAction(bindsResource, c.ns, bind), &v1alpha1.Bind{})
+
+ if obj == nil {
+ return nil, err
+ }
+ return obj.(*v1alpha1.Bind), err
+}
+
+// Update takes the representation of a bind and updates it. Returns the server's representation of the bind, and an error, if there is any.
+func (c *FakeBinds) Update(bind *v1alpha1.Bind) (result *v1alpha1.Bind, err error) {
+ obj, err := c.Fake.
+ Invokes(testing.NewUpdateAction(bindsResource, c.ns, bind), &v1alpha1.Bind{})
+
+ if obj == nil {
+ return nil, err
+ }
+ return obj.(*v1alpha1.Bind), err
+}
+
+// UpdateStatus was generated because the type contains a Status member.
+// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
+func (c *FakeBinds) UpdateStatus(bind *v1alpha1.Bind) (*v1alpha1.Bind, error) {
+ obj, err := c.Fake.
+ Invokes(testing.NewUpdateSubresourceAction(bindsResource, "status", c.ns, bind), &v1alpha1.Bind{})
+
+ if obj == nil {
+ return nil, err
+ }
+ return obj.(*v1alpha1.Bind), err
+}
+
+// Delete takes name of the bind and deletes it. Returns an error if one occurs.
+func (c *FakeBinds) Delete(name string, options *v1.DeleteOptions) error {
+ _, err := c.Fake.
+ Invokes(testing.NewDeleteAction(bindsResource, c.ns, name), &v1alpha1.Bind{})
+
+ return err
+}
+
+// DeleteCollection deletes a collection of objects.
+func (c *FakeBinds) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error {
+ action := testing.NewDeleteCollectionAction(bindsResource, c.ns, listOptions)
+
+ _, err := c.Fake.Invokes(action, &v1alpha1.BindList{})
+ return err
+}
+
+// Patch applies the patch and returns the patched bind.
+func (c *FakeBinds) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.Bind, err error) {
+ obj, err := c.Fake.
+ Invokes(testing.NewPatchSubresourceAction(bindsResource, c.ns, name, data, subresources...), &v1alpha1.Bind{})
+
+ if obj == nil {
+ return nil, err
+ }
+ return obj.(*v1alpha1.Bind), err
+}
diff --git a/pkg/client/clientset/versioned/typed/bind/v1alpha1/fake/fake_bind_client.go b/pkg/client/clientset/versioned/typed/bind/v1alpha1/fake/fake_bind_client.go
new file mode 100644
index 00000000000..da9c3844e4a
--- /dev/null
+++ b/pkg/client/clientset/versioned/typed/bind/v1alpha1/fake/fake_bind_client.go
@@ -0,0 +1,48 @@
+/*
+Copyright 2018 Google, 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.
+*/
+
+// Code generated by client-gen. DO NOT EDIT.
+
+package fake
+
+import (
+ v1alpha1 "github.com/elafros/binding/pkg/client/clientset/versioned/typed/bind/v1alpha1"
+ rest "k8s.io/client-go/rest"
+ testing "k8s.io/client-go/testing"
+)
+
+type FakeElafrosV1alpha1 struct {
+ *testing.Fake
+}
+
+func (c *FakeElafrosV1alpha1) Binds(namespace string) v1alpha1.BindInterface {
+ return &FakeBinds{c, namespace}
+}
+
+func (c *FakeElafrosV1alpha1) EventSources(namespace string) v1alpha1.EventSourceInterface {
+ return &FakeEventSources{c, namespace}
+}
+
+func (c *FakeElafrosV1alpha1) EventTypes(namespace string) v1alpha1.EventTypeInterface {
+ return &FakeEventTypes{c, namespace}
+}
+
+// RESTClient returns a RESTClient that is used to communicate
+// with API server by this client implementation.
+func (c *FakeElafrosV1alpha1) RESTClient() rest.Interface {
+ var ret *rest.RESTClient
+ return ret
+}
diff --git a/pkg/client/clientset/versioned/typed/bind/v1alpha1/fake/fake_eventsource.go b/pkg/client/clientset/versioned/typed/bind/v1alpha1/fake/fake_eventsource.go
new file mode 100644
index 00000000000..395e0005e38
--- /dev/null
+++ b/pkg/client/clientset/versioned/typed/bind/v1alpha1/fake/fake_eventsource.go
@@ -0,0 +1,140 @@
+/*
+Copyright 2018 Google, 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.
+*/
+
+// Code generated by client-gen. DO NOT EDIT.
+
+package fake
+
+import (
+ v1alpha1 "github.com/elafros/binding/pkg/apis/bind/v1alpha1"
+ v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ labels "k8s.io/apimachinery/pkg/labels"
+ schema "k8s.io/apimachinery/pkg/runtime/schema"
+ types "k8s.io/apimachinery/pkg/types"
+ watch "k8s.io/apimachinery/pkg/watch"
+ testing "k8s.io/client-go/testing"
+)
+
+// FakeEventSources implements EventSourceInterface
+type FakeEventSources struct {
+ Fake *FakeElafrosV1alpha1
+ ns string
+}
+
+var eventsourcesResource = schema.GroupVersionResource{Group: "elafros.dev", Version: "v1alpha1", Resource: "eventsources"}
+
+var eventsourcesKind = schema.GroupVersionKind{Group: "elafros.dev", Version: "v1alpha1", Kind: "EventSource"}
+
+// Get takes name of the eventSource, and returns the corresponding eventSource object, and an error if there is any.
+func (c *FakeEventSources) Get(name string, options v1.GetOptions) (result *v1alpha1.EventSource, err error) {
+ obj, err := c.Fake.
+ Invokes(testing.NewGetAction(eventsourcesResource, c.ns, name), &v1alpha1.EventSource{})
+
+ if obj == nil {
+ return nil, err
+ }
+ return obj.(*v1alpha1.EventSource), err
+}
+
+// List takes label and field selectors, and returns the list of EventSources that match those selectors.
+func (c *FakeEventSources) List(opts v1.ListOptions) (result *v1alpha1.EventSourceList, err error) {
+ obj, err := c.Fake.
+ Invokes(testing.NewListAction(eventsourcesResource, eventsourcesKind, c.ns, opts), &v1alpha1.EventSourceList{})
+
+ if obj == nil {
+ return nil, err
+ }
+
+ label, _, _ := testing.ExtractFromListOptions(opts)
+ if label == nil {
+ label = labels.Everything()
+ }
+ list := &v1alpha1.EventSourceList{}
+ for _, item := range obj.(*v1alpha1.EventSourceList).Items {
+ if label.Matches(labels.Set(item.Labels)) {
+ list.Items = append(list.Items, item)
+ }
+ }
+ return list, err
+}
+
+// Watch returns a watch.Interface that watches the requested eventSources.
+func (c *FakeEventSources) Watch(opts v1.ListOptions) (watch.Interface, error) {
+ return c.Fake.
+ InvokesWatch(testing.NewWatchAction(eventsourcesResource, c.ns, opts))
+
+}
+
+// Create takes the representation of a eventSource and creates it. Returns the server's representation of the eventSource, and an error, if there is any.
+func (c *FakeEventSources) Create(eventSource *v1alpha1.EventSource) (result *v1alpha1.EventSource, err error) {
+ obj, err := c.Fake.
+ Invokes(testing.NewCreateAction(eventsourcesResource, c.ns, eventSource), &v1alpha1.EventSource{})
+
+ if obj == nil {
+ return nil, err
+ }
+ return obj.(*v1alpha1.EventSource), err
+}
+
+// Update takes the representation of a eventSource and updates it. Returns the server's representation of the eventSource, and an error, if there is any.
+func (c *FakeEventSources) Update(eventSource *v1alpha1.EventSource) (result *v1alpha1.EventSource, err error) {
+ obj, err := c.Fake.
+ Invokes(testing.NewUpdateAction(eventsourcesResource, c.ns, eventSource), &v1alpha1.EventSource{})
+
+ if obj == nil {
+ return nil, err
+ }
+ return obj.(*v1alpha1.EventSource), err
+}
+
+// UpdateStatus was generated because the type contains a Status member.
+// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
+func (c *FakeEventSources) UpdateStatus(eventSource *v1alpha1.EventSource) (*v1alpha1.EventSource, error) {
+ obj, err := c.Fake.
+ Invokes(testing.NewUpdateSubresourceAction(eventsourcesResource, "status", c.ns, eventSource), &v1alpha1.EventSource{})
+
+ if obj == nil {
+ return nil, err
+ }
+ return obj.(*v1alpha1.EventSource), err
+}
+
+// Delete takes name of the eventSource and deletes it. Returns an error if one occurs.
+func (c *FakeEventSources) Delete(name string, options *v1.DeleteOptions) error {
+ _, err := c.Fake.
+ Invokes(testing.NewDeleteAction(eventsourcesResource, c.ns, name), &v1alpha1.EventSource{})
+
+ return err
+}
+
+// DeleteCollection deletes a collection of objects.
+func (c *FakeEventSources) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error {
+ action := testing.NewDeleteCollectionAction(eventsourcesResource, c.ns, listOptions)
+
+ _, err := c.Fake.Invokes(action, &v1alpha1.EventSourceList{})
+ return err
+}
+
+// Patch applies the patch and returns the patched eventSource.
+func (c *FakeEventSources) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.EventSource, err error) {
+ obj, err := c.Fake.
+ Invokes(testing.NewPatchSubresourceAction(eventsourcesResource, c.ns, name, data, subresources...), &v1alpha1.EventSource{})
+
+ if obj == nil {
+ return nil, err
+ }
+ return obj.(*v1alpha1.EventSource), err
+}
diff --git a/pkg/client/clientset/versioned/typed/bind/v1alpha1/fake/fake_eventtype.go b/pkg/client/clientset/versioned/typed/bind/v1alpha1/fake/fake_eventtype.go
new file mode 100644
index 00000000000..717a25d1039
--- /dev/null
+++ b/pkg/client/clientset/versioned/typed/bind/v1alpha1/fake/fake_eventtype.go
@@ -0,0 +1,140 @@
+/*
+Copyright 2018 Google, 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.
+*/
+
+// Code generated by client-gen. DO NOT EDIT.
+
+package fake
+
+import (
+ v1alpha1 "github.com/elafros/binding/pkg/apis/bind/v1alpha1"
+ v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ labels "k8s.io/apimachinery/pkg/labels"
+ schema "k8s.io/apimachinery/pkg/runtime/schema"
+ types "k8s.io/apimachinery/pkg/types"
+ watch "k8s.io/apimachinery/pkg/watch"
+ testing "k8s.io/client-go/testing"
+)
+
+// FakeEventTypes implements EventTypeInterface
+type FakeEventTypes struct {
+ Fake *FakeElafrosV1alpha1
+ ns string
+}
+
+var eventtypesResource = schema.GroupVersionResource{Group: "elafros.dev", Version: "v1alpha1", Resource: "eventtypes"}
+
+var eventtypesKind = schema.GroupVersionKind{Group: "elafros.dev", Version: "v1alpha1", Kind: "EventType"}
+
+// Get takes name of the eventType, and returns the corresponding eventType object, and an error if there is any.
+func (c *FakeEventTypes) Get(name string, options v1.GetOptions) (result *v1alpha1.EventType, err error) {
+ obj, err := c.Fake.
+ Invokes(testing.NewGetAction(eventtypesResource, c.ns, name), &v1alpha1.EventType{})
+
+ if obj == nil {
+ return nil, err
+ }
+ return obj.(*v1alpha1.EventType), err
+}
+
+// List takes label and field selectors, and returns the list of EventTypes that match those selectors.
+func (c *FakeEventTypes) List(opts v1.ListOptions) (result *v1alpha1.EventTypeList, err error) {
+ obj, err := c.Fake.
+ Invokes(testing.NewListAction(eventtypesResource, eventtypesKind, c.ns, opts), &v1alpha1.EventTypeList{})
+
+ if obj == nil {
+ return nil, err
+ }
+
+ label, _, _ := testing.ExtractFromListOptions(opts)
+ if label == nil {
+ label = labels.Everything()
+ }
+ list := &v1alpha1.EventTypeList{}
+ for _, item := range obj.(*v1alpha1.EventTypeList).Items {
+ if label.Matches(labels.Set(item.Labels)) {
+ list.Items = append(list.Items, item)
+ }
+ }
+ return list, err
+}
+
+// Watch returns a watch.Interface that watches the requested eventTypes.
+func (c *FakeEventTypes) Watch(opts v1.ListOptions) (watch.Interface, error) {
+ return c.Fake.
+ InvokesWatch(testing.NewWatchAction(eventtypesResource, c.ns, opts))
+
+}
+
+// Create takes the representation of a eventType and creates it. Returns the server's representation of the eventType, and an error, if there is any.
+func (c *FakeEventTypes) Create(eventType *v1alpha1.EventType) (result *v1alpha1.EventType, err error) {
+ obj, err := c.Fake.
+ Invokes(testing.NewCreateAction(eventtypesResource, c.ns, eventType), &v1alpha1.EventType{})
+
+ if obj == nil {
+ return nil, err
+ }
+ return obj.(*v1alpha1.EventType), err
+}
+
+// Update takes the representation of a eventType and updates it. Returns the server's representation of the eventType, and an error, if there is any.
+func (c *FakeEventTypes) Update(eventType *v1alpha1.EventType) (result *v1alpha1.EventType, err error) {
+ obj, err := c.Fake.
+ Invokes(testing.NewUpdateAction(eventtypesResource, c.ns, eventType), &v1alpha1.EventType{})
+
+ if obj == nil {
+ return nil, err
+ }
+ return obj.(*v1alpha1.EventType), err
+}
+
+// UpdateStatus was generated because the type contains a Status member.
+// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
+func (c *FakeEventTypes) UpdateStatus(eventType *v1alpha1.EventType) (*v1alpha1.EventType, error) {
+ obj, err := c.Fake.
+ Invokes(testing.NewUpdateSubresourceAction(eventtypesResource, "status", c.ns, eventType), &v1alpha1.EventType{})
+
+ if obj == nil {
+ return nil, err
+ }
+ return obj.(*v1alpha1.EventType), err
+}
+
+// Delete takes name of the eventType and deletes it. Returns an error if one occurs.
+func (c *FakeEventTypes) Delete(name string, options *v1.DeleteOptions) error {
+ _, err := c.Fake.
+ Invokes(testing.NewDeleteAction(eventtypesResource, c.ns, name), &v1alpha1.EventType{})
+
+ return err
+}
+
+// DeleteCollection deletes a collection of objects.
+func (c *FakeEventTypes) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error {
+ action := testing.NewDeleteCollectionAction(eventtypesResource, c.ns, listOptions)
+
+ _, err := c.Fake.Invokes(action, &v1alpha1.EventTypeList{})
+ return err
+}
+
+// Patch applies the patch and returns the patched eventType.
+func (c *FakeEventTypes) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.EventType, err error) {
+ obj, err := c.Fake.
+ Invokes(testing.NewPatchSubresourceAction(eventtypesResource, c.ns, name, data, subresources...), &v1alpha1.EventType{})
+
+ if obj == nil {
+ return nil, err
+ }
+ return obj.(*v1alpha1.EventType), err
+}
diff --git a/pkg/client/clientset/versioned/typed/bind/v1alpha1/generated_expansion.go b/pkg/client/clientset/versioned/typed/bind/v1alpha1/generated_expansion.go
new file mode 100644
index 00000000000..3e46993d080
--- /dev/null
+++ b/pkg/client/clientset/versioned/typed/bind/v1alpha1/generated_expansion.go
@@ -0,0 +1,25 @@
+/*
+Copyright 2018 Google, 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.
+*/
+
+// Code generated by client-gen. DO NOT EDIT.
+
+package v1alpha1
+
+type BindExpansion interface{}
+
+type EventSourceExpansion interface{}
+
+type EventTypeExpansion interface{}
diff --git a/pkg/client/informers/externalversions/BUILD.bazel b/pkg/client/informers/externalversions/BUILD.bazel
new file mode 100644
index 00000000000..38da07a77b4
--- /dev/null
+++ b/pkg/client/informers/externalversions/BUILD.bazel
@@ -0,0 +1,21 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_library")
+
+go_library(
+ name = "go_default_library",
+ srcs = [
+ "factory.go",
+ "generic.go",
+ ],
+ importpath = "github.com/elafros/binding/pkg/client/informers/externalversions",
+ visibility = ["//visibility:public"],
+ deps = [
+ "//pkg/apis/bind/v1alpha1:go_default_library",
+ "//pkg/client/clientset/versioned:go_default_library",
+ "//pkg/client/informers/externalversions/bind:go_default_library",
+ "//pkg/client/informers/externalversions/internalinterfaces:go_default_library",
+ "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
+ "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
+ "//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
+ "//vendor/k8s.io/client-go/tools/cache:go_default_library",
+ ],
+)
diff --git a/pkg/client/informers/externalversions/bind/BUILD.bazel b/pkg/client/informers/externalversions/bind/BUILD.bazel
new file mode 100644
index 00000000000..4332c2368af
--- /dev/null
+++ b/pkg/client/informers/externalversions/bind/BUILD.bazel
@@ -0,0 +1,12 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_library")
+
+go_library(
+ name = "go_default_library",
+ srcs = ["interface.go"],
+ importpath = "github.com/elafros/binding/pkg/client/informers/externalversions/bind",
+ visibility = ["//visibility:public"],
+ deps = [
+ "//pkg/client/informers/externalversions/bind/v1alpha1:go_default_library",
+ "//pkg/client/informers/externalversions/internalinterfaces:go_default_library",
+ ],
+)
diff --git a/pkg/client/informers/externalversions/bind/interface.go b/pkg/client/informers/externalversions/bind/interface.go
new file mode 100644
index 00000000000..06a5af076d7
--- /dev/null
+++ b/pkg/client/informers/externalversions/bind/interface.go
@@ -0,0 +1,48 @@
+/*
+Copyright 2018 Google, 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.
+*/
+
+// Code generated by informer-gen. DO NOT EDIT.
+
+// This file was automatically generated by informer-gen
+
+package elafros
+
+import (
+ v1alpha1 "github.com/elafros/binding/pkg/client/informers/externalversions/bind/v1alpha1"
+ internalinterfaces "github.com/elafros/binding/pkg/client/informers/externalversions/internalinterfaces"
+)
+
+// Interface provides access to each of this group's versions.
+type Interface interface {
+ // V1alpha1 provides access to shared informers for resources in V1alpha1.
+ V1alpha1() v1alpha1.Interface
+}
+
+type group struct {
+ factory internalinterfaces.SharedInformerFactory
+ namespace string
+ tweakListOptions internalinterfaces.TweakListOptionsFunc
+}
+
+// New returns a new Interface.
+func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface {
+ return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions}
+}
+
+// V1alpha1 returns a new v1alpha1.Interface.
+func (g *group) V1alpha1() v1alpha1.Interface {
+ return v1alpha1.New(g.factory, g.namespace, g.tweakListOptions)
+}
diff --git a/pkg/client/informers/externalversions/bind/v1alpha1/BUILD.bazel b/pkg/client/informers/externalversions/bind/v1alpha1/BUILD.bazel
new file mode 100644
index 00000000000..dbec6795c9d
--- /dev/null
+++ b/pkg/client/informers/externalversions/bind/v1alpha1/BUILD.bazel
@@ -0,0 +1,23 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_library")
+
+go_library(
+ name = "go_default_library",
+ srcs = [
+ "bind.go",
+ "eventsource.go",
+ "eventtype.go",
+ "interface.go",
+ ],
+ importpath = "github.com/elafros/binding/pkg/client/informers/externalversions/bind/v1alpha1",
+ visibility = ["//visibility:public"],
+ deps = [
+ "//pkg/apis/bind/v1alpha1:go_default_library",
+ "//pkg/client/clientset/versioned:go_default_library",
+ "//pkg/client/informers/externalversions/internalinterfaces:go_default_library",
+ "//pkg/client/listers/bind/v1alpha1:go_default_library",
+ "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
+ "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
+ "//vendor/k8s.io/apimachinery/pkg/watch:go_default_library",
+ "//vendor/k8s.io/client-go/tools/cache:go_default_library",
+ ],
+)
diff --git a/pkg/client/informers/externalversions/bind/v1alpha1/bind.go b/pkg/client/informers/externalversions/bind/v1alpha1/bind.go
new file mode 100644
index 00000000000..18b6b89c31b
--- /dev/null
+++ b/pkg/client/informers/externalversions/bind/v1alpha1/bind.go
@@ -0,0 +1,91 @@
+/*
+Copyright 2018 Google, 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.
+*/
+
+// Code generated by informer-gen. DO NOT EDIT.
+
+// This file was automatically generated by informer-gen
+
+package v1alpha1
+
+import (
+ time "time"
+
+ bind_v1alpha1 "github.com/elafros/binding/pkg/apis/bind/v1alpha1"
+ versioned "github.com/elafros/binding/pkg/client/clientset/versioned"
+ internalinterfaces "github.com/elafros/binding/pkg/client/informers/externalversions/internalinterfaces"
+ v1alpha1 "github.com/elafros/binding/pkg/client/listers/bind/v1alpha1"
+ v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ runtime "k8s.io/apimachinery/pkg/runtime"
+ watch "k8s.io/apimachinery/pkg/watch"
+ cache "k8s.io/client-go/tools/cache"
+)
+
+// BindInformer provides access to a shared informer and lister for
+// Binds.
+type BindInformer interface {
+ Informer() cache.SharedIndexInformer
+ Lister() v1alpha1.BindLister
+}
+
+type bindInformer struct {
+ factory internalinterfaces.SharedInformerFactory
+ tweakListOptions internalinterfaces.TweakListOptionsFunc
+ namespace string
+}
+
+// NewBindInformer constructs a new informer for Bind type.
+// Always prefer using an informer factory to get a shared informer instead of getting an independent
+// one. This reduces memory footprint and number of connections to the server.
+func NewBindInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
+ return NewFilteredBindInformer(client, namespace, resyncPeriod, indexers, nil)
+}
+
+// NewFilteredBindInformer constructs a new informer for Bind type.
+// Always prefer using an informer factory to get a shared informer instead of getting an independent
+// one. This reduces memory footprint and number of connections to the server.
+func NewFilteredBindInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
+ return cache.NewSharedIndexInformer(
+ &cache.ListWatch{
+ ListFunc: func(options v1.ListOptions) (runtime.Object, error) {
+ if tweakListOptions != nil {
+ tweakListOptions(&options)
+ }
+ return client.ElafrosV1alpha1().Binds(namespace).List(options)
+ },
+ WatchFunc: func(options v1.ListOptions) (watch.Interface, error) {
+ if tweakListOptions != nil {
+ tweakListOptions(&options)
+ }
+ return client.ElafrosV1alpha1().Binds(namespace).Watch(options)
+ },
+ },
+ &bind_v1alpha1.Bind{},
+ resyncPeriod,
+ indexers,
+ )
+}
+
+func (f *bindInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
+ return NewFilteredBindInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
+}
+
+func (f *bindInformer) Informer() cache.SharedIndexInformer {
+ return f.factory.InformerFor(&bind_v1alpha1.Bind{}, f.defaultInformer)
+}
+
+func (f *bindInformer) Lister() v1alpha1.BindLister {
+ return v1alpha1.NewBindLister(f.Informer().GetIndexer())
+}
diff --git a/pkg/client/informers/externalversions/bind/v1alpha1/eventsource.go b/pkg/client/informers/externalversions/bind/v1alpha1/eventsource.go
new file mode 100644
index 00000000000..aa647c797ad
--- /dev/null
+++ b/pkg/client/informers/externalversions/bind/v1alpha1/eventsource.go
@@ -0,0 +1,91 @@
+/*
+Copyright 2018 Google, 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.
+*/
+
+// Code generated by informer-gen. DO NOT EDIT.
+
+// This file was automatically generated by informer-gen
+
+package v1alpha1
+
+import (
+ time "time"
+
+ bind_v1alpha1 "github.com/elafros/binding/pkg/apis/bind/v1alpha1"
+ versioned "github.com/elafros/binding/pkg/client/clientset/versioned"
+ internalinterfaces "github.com/elafros/binding/pkg/client/informers/externalversions/internalinterfaces"
+ v1alpha1 "github.com/elafros/binding/pkg/client/listers/bind/v1alpha1"
+ v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ runtime "k8s.io/apimachinery/pkg/runtime"
+ watch "k8s.io/apimachinery/pkg/watch"
+ cache "k8s.io/client-go/tools/cache"
+)
+
+// EventSourceInformer provides access to a shared informer and lister for
+// EventSources.
+type EventSourceInformer interface {
+ Informer() cache.SharedIndexInformer
+ Lister() v1alpha1.EventSourceLister
+}
+
+type eventSourceInformer struct {
+ factory internalinterfaces.SharedInformerFactory
+ tweakListOptions internalinterfaces.TweakListOptionsFunc
+ namespace string
+}
+
+// NewEventSourceInformer constructs a new informer for EventSource type.
+// Always prefer using an informer factory to get a shared informer instead of getting an independent
+// one. This reduces memory footprint and number of connections to the server.
+func NewEventSourceInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
+ return NewFilteredEventSourceInformer(client, namespace, resyncPeriod, indexers, nil)
+}
+
+// NewFilteredEventSourceInformer constructs a new informer for EventSource type.
+// Always prefer using an informer factory to get a shared informer instead of getting an independent
+// one. This reduces memory footprint and number of connections to the server.
+func NewFilteredEventSourceInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
+ return cache.NewSharedIndexInformer(
+ &cache.ListWatch{
+ ListFunc: func(options v1.ListOptions) (runtime.Object, error) {
+ if tweakListOptions != nil {
+ tweakListOptions(&options)
+ }
+ return client.ElafrosV1alpha1().EventSources(namespace).List(options)
+ },
+ WatchFunc: func(options v1.ListOptions) (watch.Interface, error) {
+ if tweakListOptions != nil {
+ tweakListOptions(&options)
+ }
+ return client.ElafrosV1alpha1().EventSources(namespace).Watch(options)
+ },
+ },
+ &bind_v1alpha1.EventSource{},
+ resyncPeriod,
+ indexers,
+ )
+}
+
+func (f *eventSourceInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
+ return NewFilteredEventSourceInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
+}
+
+func (f *eventSourceInformer) Informer() cache.SharedIndexInformer {
+ return f.factory.InformerFor(&bind_v1alpha1.EventSource{}, f.defaultInformer)
+}
+
+func (f *eventSourceInformer) Lister() v1alpha1.EventSourceLister {
+ return v1alpha1.NewEventSourceLister(f.Informer().GetIndexer())
+}
diff --git a/pkg/client/informers/externalversions/bind/v1alpha1/eventtype.go b/pkg/client/informers/externalversions/bind/v1alpha1/eventtype.go
new file mode 100644
index 00000000000..f9f8fa91b3e
--- /dev/null
+++ b/pkg/client/informers/externalversions/bind/v1alpha1/eventtype.go
@@ -0,0 +1,91 @@
+/*
+Copyright 2018 Google, 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.
+*/
+
+// Code generated by informer-gen. DO NOT EDIT.
+
+// This file was automatically generated by informer-gen
+
+package v1alpha1
+
+import (
+ time "time"
+
+ bind_v1alpha1 "github.com/elafros/binding/pkg/apis/bind/v1alpha1"
+ versioned "github.com/elafros/binding/pkg/client/clientset/versioned"
+ internalinterfaces "github.com/elafros/binding/pkg/client/informers/externalversions/internalinterfaces"
+ v1alpha1 "github.com/elafros/binding/pkg/client/listers/bind/v1alpha1"
+ v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ runtime "k8s.io/apimachinery/pkg/runtime"
+ watch "k8s.io/apimachinery/pkg/watch"
+ cache "k8s.io/client-go/tools/cache"
+)
+
+// EventTypeInformer provides access to a shared informer and lister for
+// EventTypes.
+type EventTypeInformer interface {
+ Informer() cache.SharedIndexInformer
+ Lister() v1alpha1.EventTypeLister
+}
+
+type eventTypeInformer struct {
+ factory internalinterfaces.SharedInformerFactory
+ tweakListOptions internalinterfaces.TweakListOptionsFunc
+ namespace string
+}
+
+// NewEventTypeInformer constructs a new informer for EventType type.
+// Always prefer using an informer factory to get a shared informer instead of getting an independent
+// one. This reduces memory footprint and number of connections to the server.
+func NewEventTypeInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
+ return NewFilteredEventTypeInformer(client, namespace, resyncPeriod, indexers, nil)
+}
+
+// NewFilteredEventTypeInformer constructs a new informer for EventType type.
+// Always prefer using an informer factory to get a shared informer instead of getting an independent
+// one. This reduces memory footprint and number of connections to the server.
+func NewFilteredEventTypeInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
+ return cache.NewSharedIndexInformer(
+ &cache.ListWatch{
+ ListFunc: func(options v1.ListOptions) (runtime.Object, error) {
+ if tweakListOptions != nil {
+ tweakListOptions(&options)
+ }
+ return client.ElafrosV1alpha1().EventTypes(namespace).List(options)
+ },
+ WatchFunc: func(options v1.ListOptions) (watch.Interface, error) {
+ if tweakListOptions != nil {
+ tweakListOptions(&options)
+ }
+ return client.ElafrosV1alpha1().EventTypes(namespace).Watch(options)
+ },
+ },
+ &bind_v1alpha1.EventType{},
+ resyncPeriod,
+ indexers,
+ )
+}
+
+func (f *eventTypeInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
+ return NewFilteredEventTypeInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
+}
+
+func (f *eventTypeInformer) Informer() cache.SharedIndexInformer {
+ return f.factory.InformerFor(&bind_v1alpha1.EventType{}, f.defaultInformer)
+}
+
+func (f *eventTypeInformer) Lister() v1alpha1.EventTypeLister {
+ return v1alpha1.NewEventTypeLister(f.Informer().GetIndexer())
+}
diff --git a/pkg/client/informers/externalversions/bind/v1alpha1/interface.go b/pkg/client/informers/externalversions/bind/v1alpha1/interface.go
new file mode 100644
index 00000000000..e47286b3887
--- /dev/null
+++ b/pkg/client/informers/externalversions/bind/v1alpha1/interface.go
@@ -0,0 +1,61 @@
+/*
+Copyright 2018 Google, 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.
+*/
+
+// Code generated by informer-gen. DO NOT EDIT.
+
+// This file was automatically generated by informer-gen
+
+package v1alpha1
+
+import (
+ internalinterfaces "github.com/elafros/binding/pkg/client/informers/externalversions/internalinterfaces"
+)
+
+// Interface provides access to all the informers in this group version.
+type Interface interface {
+ // Binds returns a BindInformer.
+ Binds() BindInformer
+ // EventSources returns a EventSourceInformer.
+ EventSources() EventSourceInformer
+ // EventTypes returns a EventTypeInformer.
+ EventTypes() EventTypeInformer
+}
+
+type version struct {
+ factory internalinterfaces.SharedInformerFactory
+ namespace string
+ tweakListOptions internalinterfaces.TweakListOptionsFunc
+}
+
+// New returns a new Interface.
+func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface {
+ return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions}
+}
+
+// Binds returns a BindInformer.
+func (v *version) Binds() BindInformer {
+ return &bindInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
+}
+
+// EventSources returns a EventSourceInformer.
+func (v *version) EventSources() EventSourceInformer {
+ return &eventSourceInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
+}
+
+// EventTypes returns a EventTypeInformer.
+func (v *version) EventTypes() EventTypeInformer {
+ return &eventTypeInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
+}
diff --git a/pkg/client/informers/externalversions/factory.go b/pkg/client/informers/externalversions/factory.go
new file mode 100644
index 00000000000..c97e7de1542
--- /dev/null
+++ b/pkg/client/informers/externalversions/factory.go
@@ -0,0 +1,133 @@
+/*
+Copyright 2018 Google, 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.
+*/
+
+// Code generated by informer-gen. DO NOT EDIT.
+
+// This file was automatically generated by informer-gen
+
+package externalversions
+
+import (
+ reflect "reflect"
+ sync "sync"
+ time "time"
+
+ versioned "github.com/elafros/binding/pkg/client/clientset/versioned"
+ bind "github.com/elafros/binding/pkg/client/informers/externalversions/bind"
+ internalinterfaces "github.com/elafros/binding/pkg/client/informers/externalversions/internalinterfaces"
+ v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ runtime "k8s.io/apimachinery/pkg/runtime"
+ schema "k8s.io/apimachinery/pkg/runtime/schema"
+ cache "k8s.io/client-go/tools/cache"
+)
+
+type sharedInformerFactory struct {
+ client versioned.Interface
+ namespace string
+ tweakListOptions internalinterfaces.TweakListOptionsFunc
+ lock sync.Mutex
+ defaultResync time.Duration
+
+ informers map[reflect.Type]cache.SharedIndexInformer
+ // startedInformers is used for tracking which informers have been started.
+ // This allows Start() to be called multiple times safely.
+ startedInformers map[reflect.Type]bool
+}
+
+// NewSharedInformerFactory constructs a new instance of sharedInformerFactory
+func NewSharedInformerFactory(client versioned.Interface, defaultResync time.Duration) SharedInformerFactory {
+ return NewFilteredSharedInformerFactory(client, defaultResync, v1.NamespaceAll, nil)
+}
+
+// NewFilteredSharedInformerFactory constructs a new instance of sharedInformerFactory.
+// Listers obtained via this SharedInformerFactory will be subject to the same filters
+// as specified here.
+func NewFilteredSharedInformerFactory(client versioned.Interface, defaultResync time.Duration, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerFactory {
+ return &sharedInformerFactory{
+ client: client,
+ namespace: namespace,
+ tweakListOptions: tweakListOptions,
+ defaultResync: defaultResync,
+ informers: make(map[reflect.Type]cache.SharedIndexInformer),
+ startedInformers: make(map[reflect.Type]bool),
+ }
+}
+
+// Start initializes all requested informers.
+func (f *sharedInformerFactory) Start(stopCh <-chan struct{}) {
+ f.lock.Lock()
+ defer f.lock.Unlock()
+
+ for informerType, informer := range f.informers {
+ if !f.startedInformers[informerType] {
+ go informer.Run(stopCh)
+ f.startedInformers[informerType] = true
+ }
+ }
+}
+
+// WaitForCacheSync waits for all started informers' cache were synced.
+func (f *sharedInformerFactory) WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool {
+ informers := func() map[reflect.Type]cache.SharedIndexInformer {
+ f.lock.Lock()
+ defer f.lock.Unlock()
+
+ informers := map[reflect.Type]cache.SharedIndexInformer{}
+ for informerType, informer := range f.informers {
+ if f.startedInformers[informerType] {
+ informers[informerType] = informer
+ }
+ }
+ return informers
+ }()
+
+ res := map[reflect.Type]bool{}
+ for informType, informer := range informers {
+ res[informType] = cache.WaitForCacheSync(stopCh, informer.HasSynced)
+ }
+ return res
+}
+
+// InternalInformerFor returns the SharedIndexInformer for obj using an internal
+// client.
+func (f *sharedInformerFactory) InformerFor(obj runtime.Object, newFunc internalinterfaces.NewInformerFunc) cache.SharedIndexInformer {
+ f.lock.Lock()
+ defer f.lock.Unlock()
+
+ informerType := reflect.TypeOf(obj)
+ informer, exists := f.informers[informerType]
+ if exists {
+ return informer
+ }
+ informer = newFunc(f.client, f.defaultResync)
+ f.informers[informerType] = informer
+
+ return informer
+}
+
+// SharedInformerFactory provides shared informers for resources in all known
+// API group versions.
+type SharedInformerFactory interface {
+ internalinterfaces.SharedInformerFactory
+ ForResource(resource schema.GroupVersionResource) (GenericInformer, error)
+ WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool
+
+ Elafros() bind.Interface
+}
+
+func (f *sharedInformerFactory) Elafros() bind.Interface {
+ return bind.New(f, f.namespace, f.tweakListOptions)
+}
diff --git a/pkg/client/informers/externalversions/generic.go b/pkg/client/informers/externalversions/generic.go
new file mode 100644
index 00000000000..57d4ea001ef
--- /dev/null
+++ b/pkg/client/informers/externalversions/generic.go
@@ -0,0 +1,68 @@
+/*
+Copyright 2018 Google, 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.
+*/
+
+// Code generated by informer-gen. DO NOT EDIT.
+
+// This file was automatically generated by informer-gen
+
+package externalversions
+
+import (
+ "fmt"
+
+ v1alpha1 "github.com/elafros/binding/pkg/apis/bind/v1alpha1"
+ schema "k8s.io/apimachinery/pkg/runtime/schema"
+ cache "k8s.io/client-go/tools/cache"
+)
+
+// GenericInformer is type of SharedIndexInformer which will locate and delegate to other
+// sharedInformers based on type
+type GenericInformer interface {
+ Informer() cache.SharedIndexInformer
+ Lister() cache.GenericLister
+}
+
+type genericInformer struct {
+ informer cache.SharedIndexInformer
+ resource schema.GroupResource
+}
+
+// Informer returns the SharedIndexInformer.
+func (f *genericInformer) Informer() cache.SharedIndexInformer {
+ return f.informer
+}
+
+// Lister returns the GenericLister.
+func (f *genericInformer) Lister() cache.GenericLister {
+ return cache.NewGenericLister(f.Informer().GetIndexer(), f.resource)
+}
+
+// ForResource gives generic access to a shared informer of the matching type
+// TODO extend this to unknown resources with a client pool
+func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource) (GenericInformer, error) {
+ switch resource {
+ // Group=elafros.dev, Version=v1alpha1
+ case v1alpha1.SchemeGroupVersion.WithResource("binds"):
+ return &genericInformer{resource: resource.GroupResource(), informer: f.Elafros().V1alpha1().Binds().Informer()}, nil
+ case v1alpha1.SchemeGroupVersion.WithResource("eventsources"):
+ return &genericInformer{resource: resource.GroupResource(), informer: f.Elafros().V1alpha1().EventSources().Informer()}, nil
+ case v1alpha1.SchemeGroupVersion.WithResource("eventtypes"):
+ return &genericInformer{resource: resource.GroupResource(), informer: f.Elafros().V1alpha1().EventTypes().Informer()}, nil
+
+ }
+
+ return nil, fmt.Errorf("no informer found for %v", resource)
+}
diff --git a/pkg/client/informers/externalversions/internalinterfaces/BUILD.bazel b/pkg/client/informers/externalversions/internalinterfaces/BUILD.bazel
new file mode 100644
index 00000000000..ec4fe9178c1
--- /dev/null
+++ b/pkg/client/informers/externalversions/internalinterfaces/BUILD.bazel
@@ -0,0 +1,14 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_library")
+
+go_library(
+ name = "go_default_library",
+ srcs = ["factory_interfaces.go"],
+ importpath = "github.com/elafros/binding/pkg/client/informers/externalversions/internalinterfaces",
+ visibility = ["//visibility:public"],
+ deps = [
+ "//pkg/client/clientset/versioned:go_default_library",
+ "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
+ "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
+ "//vendor/k8s.io/client-go/tools/cache:go_default_library",
+ ],
+)
diff --git a/pkg/client/informers/externalversions/internalinterfaces/factory_interfaces.go b/pkg/client/informers/externalversions/internalinterfaces/factory_interfaces.go
new file mode 100644
index 00000000000..213546a2681
--- /dev/null
+++ b/pkg/client/informers/externalversions/internalinterfaces/factory_interfaces.go
@@ -0,0 +1,40 @@
+/*
+Copyright 2018 Google, 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.
+*/
+
+// Code generated by informer-gen. DO NOT EDIT.
+
+// This file was automatically generated by informer-gen
+
+package internalinterfaces
+
+import (
+ time "time"
+
+ versioned "github.com/elafros/binding/pkg/client/clientset/versioned"
+ v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ runtime "k8s.io/apimachinery/pkg/runtime"
+ cache "k8s.io/client-go/tools/cache"
+)
+
+type NewInformerFunc func(versioned.Interface, time.Duration) cache.SharedIndexInformer
+
+// SharedInformerFactory a small interface to allow for adding an informer without an import cycle
+type SharedInformerFactory interface {
+ Start(stopCh <-chan struct{})
+ InformerFor(obj runtime.Object, newFunc NewInformerFunc) cache.SharedIndexInformer
+}
+
+type TweakListOptionsFunc func(*v1.ListOptions)
diff --git a/pkg/client/listers/bind/v1alpha1/BUILD.bazel b/pkg/client/listers/bind/v1alpha1/BUILD.bazel
new file mode 100644
index 00000000000..4cec70cf39f
--- /dev/null
+++ b/pkg/client/listers/bind/v1alpha1/BUILD.bazel
@@ -0,0 +1,19 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_library")
+
+go_library(
+ name = "go_default_library",
+ srcs = [
+ "bind.go",
+ "eventsource.go",
+ "eventtype.go",
+ "expansion_generated.go",
+ ],
+ importpath = "github.com/elafros/binding/pkg/client/listers/bind/v1alpha1",
+ visibility = ["//visibility:public"],
+ deps = [
+ "//pkg/apis/bind/v1alpha1:go_default_library",
+ "//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
+ "//vendor/k8s.io/apimachinery/pkg/labels:go_default_library",
+ "//vendor/k8s.io/client-go/tools/cache:go_default_library",
+ ],
+)
diff --git a/pkg/client/listers/bind/v1alpha1/bind.go b/pkg/client/listers/bind/v1alpha1/bind.go
new file mode 100644
index 00000000000..c01b9057fca
--- /dev/null
+++ b/pkg/client/listers/bind/v1alpha1/bind.go
@@ -0,0 +1,96 @@
+/*
+Copyright 2018 Google, 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.
+*/
+
+// Code generated by lister-gen. DO NOT EDIT.
+
+// This file was automatically generated by lister-gen
+
+package v1alpha1
+
+import (
+ v1alpha1 "github.com/elafros/binding/pkg/apis/bind/v1alpha1"
+ "k8s.io/apimachinery/pkg/api/errors"
+ "k8s.io/apimachinery/pkg/labels"
+ "k8s.io/client-go/tools/cache"
+)
+
+// BindLister helps list Binds.
+type BindLister interface {
+ // List lists all Binds in the indexer.
+ List(selector labels.Selector) (ret []*v1alpha1.Bind, err error)
+ // Binds returns an object that can list and get Binds.
+ Binds(namespace string) BindNamespaceLister
+ BindListerExpansion
+}
+
+// bindLister implements the BindLister interface.
+type bindLister struct {
+ indexer cache.Indexer
+}
+
+// NewBindLister returns a new BindLister.
+func NewBindLister(indexer cache.Indexer) BindLister {
+ return &bindLister{indexer: indexer}
+}
+
+// List lists all Binds in the indexer.
+func (s *bindLister) List(selector labels.Selector) (ret []*v1alpha1.Bind, err error) {
+ err = cache.ListAll(s.indexer, selector, func(m interface{}) {
+ ret = append(ret, m.(*v1alpha1.Bind))
+ })
+ return ret, err
+}
+
+// Binds returns an object that can list and get Binds.
+func (s *bindLister) Binds(namespace string) BindNamespaceLister {
+ return bindNamespaceLister{indexer: s.indexer, namespace: namespace}
+}
+
+// BindNamespaceLister helps list and get Binds.
+type BindNamespaceLister interface {
+ // List lists all Binds in the indexer for a given namespace.
+ List(selector labels.Selector) (ret []*v1alpha1.Bind, err error)
+ // Get retrieves the Bind from the indexer for a given namespace and name.
+ Get(name string) (*v1alpha1.Bind, error)
+ BindNamespaceListerExpansion
+}
+
+// bindNamespaceLister implements the BindNamespaceLister
+// interface.
+type bindNamespaceLister struct {
+ indexer cache.Indexer
+ namespace string
+}
+
+// List lists all Binds in the indexer for a given namespace.
+func (s bindNamespaceLister) List(selector labels.Selector) (ret []*v1alpha1.Bind, err error) {
+ err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) {
+ ret = append(ret, m.(*v1alpha1.Bind))
+ })
+ return ret, err
+}
+
+// Get retrieves the Bind from the indexer for a given namespace and name.
+func (s bindNamespaceLister) Get(name string) (*v1alpha1.Bind, error) {
+ obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name)
+ if err != nil {
+ return nil, err
+ }
+ if !exists {
+ return nil, errors.NewNotFound(v1alpha1.Resource("bind"), name)
+ }
+ return obj.(*v1alpha1.Bind), nil
+}
diff --git a/pkg/client/listers/bind/v1alpha1/eventsource.go b/pkg/client/listers/bind/v1alpha1/eventsource.go
new file mode 100644
index 00000000000..fc3e008c2f0
--- /dev/null
+++ b/pkg/client/listers/bind/v1alpha1/eventsource.go
@@ -0,0 +1,96 @@
+/*
+Copyright 2018 Google, 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.
+*/
+
+// Code generated by lister-gen. DO NOT EDIT.
+
+// This file was automatically generated by lister-gen
+
+package v1alpha1
+
+import (
+ v1alpha1 "github.com/elafros/binding/pkg/apis/bind/v1alpha1"
+ "k8s.io/apimachinery/pkg/api/errors"
+ "k8s.io/apimachinery/pkg/labels"
+ "k8s.io/client-go/tools/cache"
+)
+
+// EventSourceLister helps list EventSources.
+type EventSourceLister interface {
+ // List lists all EventSources in the indexer.
+ List(selector labels.Selector) (ret []*v1alpha1.EventSource, err error)
+ // EventSources returns an object that can list and get EventSources.
+ EventSources(namespace string) EventSourceNamespaceLister
+ EventSourceListerExpansion
+}
+
+// eventSourceLister implements the EventSourceLister interface.
+type eventSourceLister struct {
+ indexer cache.Indexer
+}
+
+// NewEventSourceLister returns a new EventSourceLister.
+func NewEventSourceLister(indexer cache.Indexer) EventSourceLister {
+ return &eventSourceLister{indexer: indexer}
+}
+
+// List lists all EventSources in the indexer.
+func (s *eventSourceLister) List(selector labels.Selector) (ret []*v1alpha1.EventSource, err error) {
+ err = cache.ListAll(s.indexer, selector, func(m interface{}) {
+ ret = append(ret, m.(*v1alpha1.EventSource))
+ })
+ return ret, err
+}
+
+// EventSources returns an object that can list and get EventSources.
+func (s *eventSourceLister) EventSources(namespace string) EventSourceNamespaceLister {
+ return eventSourceNamespaceLister{indexer: s.indexer, namespace: namespace}
+}
+
+// EventSourceNamespaceLister helps list and get EventSources.
+type EventSourceNamespaceLister interface {
+ // List lists all EventSources in the indexer for a given namespace.
+ List(selector labels.Selector) (ret []*v1alpha1.EventSource, err error)
+ // Get retrieves the EventSource from the indexer for a given namespace and name.
+ Get(name string) (*v1alpha1.EventSource, error)
+ EventSourceNamespaceListerExpansion
+}
+
+// eventSourceNamespaceLister implements the EventSourceNamespaceLister
+// interface.
+type eventSourceNamespaceLister struct {
+ indexer cache.Indexer
+ namespace string
+}
+
+// List lists all EventSources in the indexer for a given namespace.
+func (s eventSourceNamespaceLister) List(selector labels.Selector) (ret []*v1alpha1.EventSource, err error) {
+ err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) {
+ ret = append(ret, m.(*v1alpha1.EventSource))
+ })
+ return ret, err
+}
+
+// Get retrieves the EventSource from the indexer for a given namespace and name.
+func (s eventSourceNamespaceLister) Get(name string) (*v1alpha1.EventSource, error) {
+ obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name)
+ if err != nil {
+ return nil, err
+ }
+ if !exists {
+ return nil, errors.NewNotFound(v1alpha1.Resource("eventsource"), name)
+ }
+ return obj.(*v1alpha1.EventSource), nil
+}
diff --git a/pkg/client/listers/bind/v1alpha1/eventtype.go b/pkg/client/listers/bind/v1alpha1/eventtype.go
new file mode 100644
index 00000000000..b9c489208ca
--- /dev/null
+++ b/pkg/client/listers/bind/v1alpha1/eventtype.go
@@ -0,0 +1,96 @@
+/*
+Copyright 2018 Google, 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.
+*/
+
+// Code generated by lister-gen. DO NOT EDIT.
+
+// This file was automatically generated by lister-gen
+
+package v1alpha1
+
+import (
+ v1alpha1 "github.com/elafros/binding/pkg/apis/bind/v1alpha1"
+ "k8s.io/apimachinery/pkg/api/errors"
+ "k8s.io/apimachinery/pkg/labels"
+ "k8s.io/client-go/tools/cache"
+)
+
+// EventTypeLister helps list EventTypes.
+type EventTypeLister interface {
+ // List lists all EventTypes in the indexer.
+ List(selector labels.Selector) (ret []*v1alpha1.EventType, err error)
+ // EventTypes returns an object that can list and get EventTypes.
+ EventTypes(namespace string) EventTypeNamespaceLister
+ EventTypeListerExpansion
+}
+
+// eventTypeLister implements the EventTypeLister interface.
+type eventTypeLister struct {
+ indexer cache.Indexer
+}
+
+// NewEventTypeLister returns a new EventTypeLister.
+func NewEventTypeLister(indexer cache.Indexer) EventTypeLister {
+ return &eventTypeLister{indexer: indexer}
+}
+
+// List lists all EventTypes in the indexer.
+func (s *eventTypeLister) List(selector labels.Selector) (ret []*v1alpha1.EventType, err error) {
+ err = cache.ListAll(s.indexer, selector, func(m interface{}) {
+ ret = append(ret, m.(*v1alpha1.EventType))
+ })
+ return ret, err
+}
+
+// EventTypes returns an object that can list and get EventTypes.
+func (s *eventTypeLister) EventTypes(namespace string) EventTypeNamespaceLister {
+ return eventTypeNamespaceLister{indexer: s.indexer, namespace: namespace}
+}
+
+// EventTypeNamespaceLister helps list and get EventTypes.
+type EventTypeNamespaceLister interface {
+ // List lists all EventTypes in the indexer for a given namespace.
+ List(selector labels.Selector) (ret []*v1alpha1.EventType, err error)
+ // Get retrieves the EventType from the indexer for a given namespace and name.
+ Get(name string) (*v1alpha1.EventType, error)
+ EventTypeNamespaceListerExpansion
+}
+
+// eventTypeNamespaceLister implements the EventTypeNamespaceLister
+// interface.
+type eventTypeNamespaceLister struct {
+ indexer cache.Indexer
+ namespace string
+}
+
+// List lists all EventTypes in the indexer for a given namespace.
+func (s eventTypeNamespaceLister) List(selector labels.Selector) (ret []*v1alpha1.EventType, err error) {
+ err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) {
+ ret = append(ret, m.(*v1alpha1.EventType))
+ })
+ return ret, err
+}
+
+// Get retrieves the EventType from the indexer for a given namespace and name.
+func (s eventTypeNamespaceLister) Get(name string) (*v1alpha1.EventType, error) {
+ obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name)
+ if err != nil {
+ return nil, err
+ }
+ if !exists {
+ return nil, errors.NewNotFound(v1alpha1.Resource("eventtype"), name)
+ }
+ return obj.(*v1alpha1.EventType), nil
+}
diff --git a/pkg/client/listers/bind/v1alpha1/expansion_generated.go b/pkg/client/listers/bind/v1alpha1/expansion_generated.go
new file mode 100644
index 00000000000..8b64243af76
--- /dev/null
+++ b/pkg/client/listers/bind/v1alpha1/expansion_generated.go
@@ -0,0 +1,45 @@
+/*
+Copyright 2018 Google, 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.
+*/
+
+// Code generated by lister-gen. DO NOT EDIT.
+
+// This file was automatically generated by lister-gen
+
+package v1alpha1
+
+// BindListerExpansion allows custom methods to be added to
+// BindLister.
+type BindListerExpansion interface{}
+
+// BindNamespaceListerExpansion allows custom methods to be added to
+// BindNamespaceLister.
+type BindNamespaceListerExpansion interface{}
+
+// EventSourceListerExpansion allows custom methods to be added to
+// EventSourceLister.
+type EventSourceListerExpansion interface{}
+
+// EventSourceNamespaceListerExpansion allows custom methods to be added to
+// EventSourceNamespaceLister.
+type EventSourceNamespaceListerExpansion interface{}
+
+// EventTypeListerExpansion allows custom methods to be added to
+// EventTypeLister.
+type EventTypeListerExpansion interface{}
+
+// EventTypeNamespaceListerExpansion allows custom methods to be added to
+// EventTypeNamespaceLister.
+type EventTypeNamespaceListerExpansion interface{}
diff --git a/pkg/controller/BUILD b/pkg/controller/BUILD
new file mode 100644
index 00000000000..a17c06c175e
--- /dev/null
+++ b/pkg/controller/BUILD
@@ -0,0 +1,15 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_library")
+
+go_library(
+ name = "go_default_library",
+ srcs = ["controller.go"],
+ importpath = "github.com/elafros/binding/pkg/controller",
+ visibility = ["//visibility:public"],
+ deps = [
+ "//pkg/client/clientset/versioned:go_default_library",
+ "//pkg/client/informers/externalversions:go_default_library",
+ "//vendor/github.com/elafros/elafros/pkg/client/informers/externalversions:go_default_library",
+ "//vendor/k8s.io/client-go/informers:go_default_library",
+ "//vendor/k8s.io/client-go/kubernetes:go_default_library",
+ ],
+)
diff --git a/pkg/controller/bind/BUILD b/pkg/controller/bind/BUILD
new file mode 100644
index 00000000000..9e219679b75
--- /dev/null
+++ b/pkg/controller/bind/BUILD
@@ -0,0 +1,33 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_library")
+
+go_library(
+ name = "go_default_library",
+ srcs = ["controller.go"],
+ importpath = "github.com/elafros/binding/pkg/controller/bind",
+ visibility = ["//visibility:public"],
+ deps = [
+ "//pkg/apis/bind/v1alpha1:go_default_library",
+ "//pkg/client/clientset/versioned:go_default_library",
+ "//pkg/client/clientset/versioned/scheme:go_default_library",
+ "//pkg/client/informers/externalversions:go_default_library",
+ "//pkg/client/listers/bind/v1alpha1:go_default_library",
+ "//pkg/controller:go_default_library",
+ "//pkg/triggers:go_default_library",
+ "//vendor/github.com/elafros/elafros/pkg/client/informers/externalversions:go_default_library",
+ "//vendor/github.com/elafros/elafros/pkg/client/listers/ela/v1alpha1:go_default_library",
+ "//vendor/github.com/ghodss/yaml:go_default_library",
+ "//vendor/github.com/golang/glog:go_default_library",
+ "//vendor/k8s.io/api/core/v1:go_default_library",
+ "//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
+ "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
+ "//vendor/k8s.io/apimachinery/pkg/util/runtime:go_default_library",
+ "//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library",
+ "//vendor/k8s.io/client-go/informers:go_default_library",
+ "//vendor/k8s.io/client-go/kubernetes:go_default_library",
+ "//vendor/k8s.io/client-go/kubernetes/scheme:go_default_library",
+ "//vendor/k8s.io/client-go/kubernetes/typed/core/v1:go_default_library",
+ "//vendor/k8s.io/client-go/tools/cache:go_default_library",
+ "//vendor/k8s.io/client-go/tools/record:go_default_library",
+ "//vendor/k8s.io/client-go/util/workqueue:go_default_library",
+ ],
+)
diff --git a/pkg/controller/bind/controller.go b/pkg/controller/bind/controller.go
new file mode 100644
index 00000000000..cadbca13144
--- /dev/null
+++ b/pkg/controller/bind/controller.go
@@ -0,0 +1,434 @@
+/*
+Copyright 2018 Google, 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 bind
+
+import (
+ "encoding/json"
+ "fmt"
+ "time"
+
+ "github.com/ghodss/yaml"
+ "github.com/golang/glog"
+ corev1 "k8s.io/api/core/v1"
+ "k8s.io/apimachinery/pkg/api/errors"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/util/runtime"
+ "k8s.io/apimachinery/pkg/util/wait"
+ kubeinformers "k8s.io/client-go/informers"
+ "k8s.io/client-go/kubernetes"
+ "k8s.io/client-go/kubernetes/scheme"
+ typedcorev1 "k8s.io/client-go/kubernetes/typed/core/v1"
+ "k8s.io/client-go/tools/cache"
+ "k8s.io/client-go/tools/record"
+ "k8s.io/client-go/util/workqueue"
+
+ elainformers "github.com/elafros/elafros/pkg/client/informers/externalversions"
+ elalisters "github.com/elafros/elafros/pkg/client/listers/ela/v1alpha1"
+
+ "github.com/elafros/binding/pkg/controller"
+ "github.com/elafros/binding/pkg/triggers"
+
+ v1alpha1 "github.com/elafros/binding/pkg/apis/bind/v1alpha1"
+
+ clientset "github.com/elafros/binding/pkg/client/clientset/versioned"
+ bindscheme "github.com/elafros/binding/pkg/client/clientset/versioned/scheme"
+ informers "github.com/elafros/binding/pkg/client/informers/externalversions"
+ listers "github.com/elafros/binding/pkg/client/listers/bind/v1alpha1"
+)
+
+const controllerAgentName = "bind-controller"
+
+const (
+ // SuccessSynced is used as part of the Event 'reason' when a Bind is synced
+ SuccessSynced = "Synced"
+
+ // MessageResourceSynced is the message used for an Event fired when a Bind
+ // is synced successfully
+ MessageResourceSynced = "Bind synced successfully"
+)
+
+// Controller is the controller implementation for Bind resources
+type Controller struct {
+ // kubeclientset is a standard kubernetes clientset
+ kubeclientset kubernetes.Interface
+ // bindclientset is a clientset for our own API group
+ bindclientset clientset.Interface
+
+ bindsLister listers.BindLister
+ bindsSynced cache.InformerSynced
+
+ eventTypesLister listers.EventTypeLister
+ eventTypesSynced cache.InformerSynced
+
+ eventSourcesLister listers.EventSourceLister
+ eventSourcesSynced cache.InformerSynced
+
+ routesLister elalisters.RouteLister
+ routesSynced cache.InformerSynced
+
+ // workqueue is a rate limited work queue. This is used to queue work to be
+ // processed instead of performing it as soon as a change happens. This
+ // means we can ensure we only process a fixed amount of resources at a
+ // time, and makes it easy to ensure we are never processing the same item
+ // simultaneously in two different workers.
+ workqueue workqueue.RateLimitingInterface
+ // recorder is an event recorder for recording Event resources to the
+ // Kubernetes API.
+ recorder record.EventRecorder
+
+ triggers map[string]triggers.Trigger
+}
+
+// NewController returns a new bind controller
+func NewController(
+ kubeclientset kubernetes.Interface,
+ bindclientset clientset.Interface,
+ kubeInformerFactory kubeinformers.SharedInformerFactory,
+ bindInformerFactory informers.SharedInformerFactory,
+ routeInformerFactory elainformers.SharedInformerFactory) controller.Interface {
+
+ // obtain a reference to a shared index informer for the Bind types.
+ // bindInformer := bindInformerFactory.Elafros().V1alpha1().Binds()
+ bindInformer := bindInformerFactory.Elafros().V1alpha1()
+
+ // obtain a reference to a shared index informer for the Route type.
+ routeInformer := routeInformerFactory.Elafros().V1alpha1().Routes()
+
+ // Create event broadcaster
+ // Add bind-controller types to the default Kubernetes Scheme so Events can be
+ // logged for bind-controller types.
+ bindscheme.AddToScheme(scheme.Scheme)
+ glog.V(4).Info("Creating event broadcaster")
+ eventBroadcaster := record.NewBroadcaster()
+ eventBroadcaster.StartLogging(glog.Infof)
+ eventBroadcaster.StartRecordingToSink(&typedcorev1.EventSinkImpl{Interface: kubeclientset.CoreV1().Events("")})
+ recorder := eventBroadcaster.NewRecorder(scheme.Scheme, corev1.EventSource{Component: controllerAgentName})
+
+ controller := &Controller{
+ kubeclientset: kubeclientset,
+ bindclientset: bindclientset,
+ bindsLister: bindInformer.Binds().Lister(),
+ bindsSynced: bindInformer.Binds().Informer().HasSynced,
+ routesLister: routeInformer.Lister(),
+ routesSynced: routeInformer.Informer().HasSynced,
+ eventSourcesLister: bindInformer.EventSources().Lister(),
+ eventSourcesSynced: bindInformer.EventSources().Informer().HasSynced,
+ eventTypesLister: bindInformer.EventTypes().Lister(),
+ eventTypesSynced: bindInformer.EventTypes().Informer().HasSynced,
+ workqueue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "Binds"),
+ recorder: recorder,
+ }
+
+ controller.triggers = make(map[string]triggers.Trigger)
+ controller.triggers["github"] = triggers.NewGithubTrigger()
+ glog.Info("Setting up event handlers")
+ // Set up an event handler for when Bind resources change
+ bindInformer.Binds().Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
+ AddFunc: controller.enqueueBind,
+ UpdateFunc: func(old, new interface{}) {
+ controller.enqueueBind(new)
+ },
+ })
+
+ return controller
+}
+
+// Run will set up the event handlers for types we are interested in, as well
+// as syncing informer caches and starting workers. It will block until stopCh
+// is closed, at which point it will shutdown the workqueue and wait for
+// workers to finish processing their current work items.
+func (c *Controller) Run(threadiness int, stopCh <-chan struct{}) error {
+ defer runtime.HandleCrash()
+ defer c.workqueue.ShutDown()
+
+ // Start the informer factories to begin populating the informer caches
+ glog.Info("Starting Bind controller")
+
+ // Wait for the caches to be synced before starting workers
+ glog.Info("Waiting for Bind informer caches to sync")
+ if ok := cache.WaitForCacheSync(stopCh, c.bindsSynced); !ok {
+ return fmt.Errorf("failed to wait for Bind caches to sync")
+ }
+
+ glog.Info("Waiting for EventSources informer caches to sync")
+ if ok := cache.WaitForCacheSync(stopCh, c.eventSourcesSynced); !ok {
+ return fmt.Errorf("failed to wait for EventSources caches to sync")
+ }
+
+ glog.Info("Waiting for EventTypes informer caches to sync")
+ if ok := cache.WaitForCacheSync(stopCh, c.eventTypesSynced); !ok {
+ return fmt.Errorf("failed to wait for EventTypes caches to sync")
+ }
+
+ glog.Info("Waiting for route informer caches to sync")
+ if ok := cache.WaitForCacheSync(stopCh, c.routesSynced); !ok {
+ return fmt.Errorf("failed to wait for Route caches to sync")
+ }
+
+ glog.Info("Starting workers")
+ // Launch two workers to process Bind resources
+ for i := 0; i < threadiness; i++ {
+ go wait.Until(c.runWorker, time.Second, stopCh)
+ }
+
+ glog.Info("Started workers")
+ <-stopCh
+ glog.Info("Shutting down workers")
+
+ return nil
+}
+
+// runWorker is a long-running function that will continually call the
+// processNextWorkItem function in order to read and process a message on the
+// workqueue.
+func (c *Controller) runWorker() {
+ for c.processNextWorkItem() {
+ }
+}
+
+// processNextWorkItem will read a single work item off the workqueue and
+// attempt to process it, by calling the syncHandler.
+func (c *Controller) processNextWorkItem() bool {
+ obj, shutdown := c.workqueue.Get()
+
+ if shutdown {
+ return false
+ }
+
+ // We wrap this block in a func so we can defer c.workqueue.Done.
+ if err := func(obj interface{}) error {
+ // We call Done here so the workqueue knows we have finished
+ // processing this item. We also must remember to call Forget if we
+ // do not want this work item being re-queued. For example, we do
+ // not call Forget if a transient error occurs, instead the item is
+ // put back on the workqueue and attempted again after a back-off
+ // period.
+ defer c.workqueue.Done(obj)
+ // We expect strings to come off the workqueue. These are of the
+ // form namespace/name. We do this as the delayed nature of the
+ // workqueue means the items in the informer cache may actually be
+ // more up to date that when the item was initially put onto the
+ // workqueue.
+ key, ok := obj.(string)
+ if !ok {
+ // As the item in the workqueue is actually invalid, we call
+ // Forget here else we'd go into a loop of attempting to
+ // process a work item that is invalid.
+ c.workqueue.Forget(obj)
+ runtime.HandleError(fmt.Errorf("expected string in workqueue but got %#v", obj))
+ return nil
+ }
+ // Run the syncHandler, passing it the namespace/name string of the
+ // Bind resource to be synced.
+ if err := c.syncHandler(key); err != nil {
+ return fmt.Errorf("error syncing '%s': %s", key, err.Error())
+ }
+ // Finally, if no error occurs we Forget this item so it does not
+ // get queued again until another change happens.
+ c.workqueue.Forget(obj)
+ glog.Infof("Successfully synced '%s'", key)
+ return nil
+ }(obj); err != nil {
+ runtime.HandleError(err)
+ }
+
+ return true
+}
+
+// enqueueBind takes a Bind resource and converts it into a namespace/name
+// string which is then put onto the work queue. This method should *not* be
+// passed resources of any type other than Bind.
+func (c *Controller) enqueueBind(obj interface{}) {
+ var key string
+ var err error
+ if key, err = cache.MetaNamespaceKeyFunc(obj); err != nil {
+ runtime.HandleError(err)
+ return
+ }
+ c.workqueue.AddRateLimited(key)
+}
+
+// syncHandler compares the actual state with the desired, and attempts to
+// converge the two. It then updates the Status block of the Bind resource
+// with the current status of the resource.
+func (c *Controller) syncHandler(key string) error {
+ // Convert the namespace/name string into a distinct namespace and name
+ namespace, name, err := cache.SplitMetaNamespaceKey(key)
+ if err != nil {
+ runtime.HandleError(fmt.Errorf("invalid resource key: %s", key))
+ return nil
+ }
+
+ // Get the Bind resource with this namespace/name
+ bind, err := c.bindsLister.Binds(namespace).Get(name)
+ if err != nil {
+ // The Bind resource may no longer exist, in which case we stop
+ // processing.
+ if errors.IsNotFound(err) {
+ runtime.HandleError(fmt.Errorf("bind '%s' in work queue no longer exists", key))
+ return nil
+ }
+
+ return err
+ }
+ // Don't mutate the informer's copy of our object.
+ bind = bind.DeepCopy()
+
+ // Find the Route that they want.
+ routeName := bind.Spec.Action.RouteName
+ route, err := c.routesLister.Routes(namespace).Get(routeName)
+ if err != nil {
+ if errors.IsNotFound(err) {
+ runtime.HandleError(fmt.Errorf("Route %q in namespace %q does not exist", routeName, namespace))
+ }
+ return err
+ }
+ glog.Infof("Found route url as '%q'", route.Spec.DomainSuffix)
+
+ es, err := c.eventSourcesLister.EventSources(namespace).Get(bind.Spec.Source.EventSource)
+ if err != nil {
+ if errors.IsNotFound(err) {
+ runtime.HandleError(fmt.Errorf("EventSource %q in namespace %q does not exist", bind.Spec.Source.EventSource, namespace))
+ }
+ return err
+ }
+
+ et, err := c.eventTypesLister.EventTypes(namespace).Get(bind.Spec.Source.EventType)
+ if err != nil {
+ if errors.IsNotFound(err) {
+ runtime.HandleError(fmt.Errorf("EventType %q in namespace %q does not exist", bind.Spec.Source.EventSource, namespace))
+ }
+ return err
+ }
+
+ params, err := getParameters(c.kubeclientset, namespace, bind.Spec.Parameters.Raw, bind.Spec.ParametersFrom)
+ if err != nil {
+ glog.Warningf("Failed to process parameters: %s", err)
+ return err
+ }
+
+ if bind.Status.Conditions != nil {
+ glog.Infof("Already has status, skipping")
+ return nil
+ }
+
+ glog.Infof("Creating a subscription to %q : %q with Parameters %+v", es.Name, et.Name, params)
+ if val, ok := c.triggers[es.Name]; ok {
+ r, err := val.Bind(params, route.Spec.DomainSuffix)
+ if err != nil {
+ glog.Warningf("BIND failed: %s", err)
+ msg := fmt.Sprintf("Bind failed with : %s", r)
+ bind.Status.SetCondition(&v1alpha1.BindCondition{
+ Type: v1alpha1.BindFailed,
+ Status: corev1.ConditionTrue,
+ Reason: "BindFailed",
+ Message: msg,
+ })
+ } else {
+ bind.Status.SetCondition(&v1alpha1.BindCondition{
+ Type: v1alpha1.BindComplete,
+ Status: corev1.ConditionTrue,
+ Reason: fmt.Sprintf("BindSuccess: Hook: %s", r["ID"].(string)),
+ Message: "Bind successful",
+ })
+ }
+ }
+ _, err = c.updateStatus(bind)
+ if err != nil {
+ glog.Warningf("Failed to update status: %s", err)
+ return err
+ }
+
+ c.recorder.Event(bind, corev1.EventTypeNormal, SuccessSynced, MessageResourceSynced)
+ return nil
+}
+
+func (c *Controller) updateStatus(u *v1alpha1.Bind) (*v1alpha1.Bind, error) {
+ bindClient := c.bindclientset.ElafrosV1alpha1().Binds(u.Namespace)
+ newu, err := bindClient.Get(u.Name, metav1.GetOptions{})
+ if err != nil {
+ return nil, err
+ }
+ newu.Status = u.Status
+
+ // Until #38113 is merged, we must use Update instead of UpdateStatus to
+ // update the Status block of the Bind resource. UpdateStatus will not
+ // allow changes to the Spec of the resource, which is ideal for ensuring
+ // nothing other than resource status has been updated.
+ return bindClient.Update(newu)
+}
+
+func getParameters(kubeClient kubernetes.Interface, namespace string, parameters []byte, parametersFrom []v1alpha1.ParametersFromSource) (map[string]interface{}, error) {
+ r := make(map[string]interface{})
+ if parameters != nil && len(parameters) > 0 {
+ p := make(map[string]interface{})
+ if err := yaml.Unmarshal(parameters, &p); err != nil {
+ return nil, err
+ }
+ for k, v := range p {
+ r[k] = v
+ }
+ }
+ if parametersFrom != nil {
+ glog.Infof("Fetching from source %+v", parametersFrom)
+ for _, p := range parametersFrom {
+ pfs, err := fetchParametersFromSource(kubeClient, namespace, &p)
+ if err != nil {
+ return nil, err
+ }
+ for k, v := range pfs {
+ r[k] = v
+ }
+ }
+ }
+ return r, nil
+}
+
+func fetchParametersFromSource(kubeClient kubernetes.Interface, namespace string, parametersFrom *v1alpha1.ParametersFromSource) (map[string]interface{}, error) {
+ var params map[string]interface{}
+ if parametersFrom.SecretKeyRef != nil {
+ glog.Infof("Fetching secret %+v", parametersFrom.SecretKeyRef)
+ data, err := fetchSecretKeyValue(kubeClient, namespace, parametersFrom.SecretKeyRef)
+ if err != nil {
+ return nil, err
+ }
+
+ p, err := unmarshalJSON(data)
+ if err != nil {
+ return nil, err
+ }
+ params = p
+
+ }
+ return params, nil
+}
+
+func fetchSecretKeyValue(kubeClient kubernetes.Interface, namespace string, secretKeyRef *v1alpha1.SecretKeyReference) ([]byte, error) {
+ secret, err := kubeClient.CoreV1().Secrets(namespace).Get(secretKeyRef.Name, metav1.GetOptions{})
+ if err != nil {
+ return nil, err
+ }
+ return secret.Data[secretKeyRef.Key], nil
+}
+
+func unmarshalJSON(in []byte) (map[string]interface{}, error) {
+ parameters := make(map[string]interface{})
+ if err := json.Unmarshal(in, ¶meters); err != nil {
+ return nil, fmt.Errorf("failed to unmarshal parameters as JSON object: %v", err)
+ }
+ return parameters, nil
+}
diff --git a/pkg/controller/controller.go b/pkg/controller/controller.go
new file mode 100644
index 00000000000..b50bfdb6177
--- /dev/null
+++ b/pkg/controller/controller.go
@@ -0,0 +1,33 @@
+/*
+Copyright 2018 Google, 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 controller
+
+import (
+ kubeinformers "k8s.io/client-go/informers"
+ "k8s.io/client-go/kubernetes"
+
+ elainformers "github.com/elafros/elafros/pkg/client/informers/externalversions"
+
+ clientset "github.com/elafros/binding/pkg/client/clientset/versioned"
+ informers "github.com/elafros/binding/pkg/client/informers/externalversions"
+)
+
+type Interface interface {
+ Run(threadiness int, stopCh <-chan struct{}) error
+}
+
+type Constructor func(kubernetes.Interface, clientset.Interface, kubeinformers.SharedInformerFactory, informers.SharedInformerFactory, elainformers.SharedInformerFactory) Interface
diff --git a/pkg/signals/BUILD b/pkg/signals/BUILD
new file mode 100644
index 00000000000..b0b97b4e170
--- /dev/null
+++ b/pkg/signals/BUILD
@@ -0,0 +1,45 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_library")
+
+go_library(
+ name = "go_default_library",
+ srcs = [
+ "signal.go",
+ ] + select({
+ "@io_bazel_rules_go//go/platform:android": [
+ "signal_posix.go",
+ ],
+ "@io_bazel_rules_go//go/platform:darwin": [
+ "signal_posix.go",
+ ],
+ "@io_bazel_rules_go//go/platform:dragonfly": [
+ "signal_posix.go",
+ ],
+ "@io_bazel_rules_go//go/platform:freebsd": [
+ "signal_posix.go",
+ ],
+ "@io_bazel_rules_go//go/platform:linux": [
+ "signal_posix.go",
+ ],
+ "@io_bazel_rules_go//go/platform:nacl": [
+ "signal_posix.go",
+ ],
+ "@io_bazel_rules_go//go/platform:netbsd": [
+ "signal_posix.go",
+ ],
+ "@io_bazel_rules_go//go/platform:openbsd": [
+ "signal_posix.go",
+ ],
+ "@io_bazel_rules_go//go/platform:plan9": [
+ "signal_posix.go",
+ ],
+ "@io_bazel_rules_go//go/platform:solaris": [
+ "signal_posix.go",
+ ],
+ "@io_bazel_rules_go//go/platform:windows": [
+ "signal_windows.go",
+ ],
+ "//conditions:default": [],
+ }),
+ importpath = "github.com/elafros/binding/pkg/signals",
+ visibility = ["//visibility:public"],
+)
diff --git a/pkg/signals/signal.go b/pkg/signals/signal.go
new file mode 100644
index 00000000000..a139a8263d4
--- /dev/null
+++ b/pkg/signals/signal.go
@@ -0,0 +1,43 @@
+/*
+Copyright 2018 Google, 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 signals
+
+import (
+ "os"
+ "os/signal"
+)
+
+var onlyOneSignalHandler = make(chan struct{})
+
+// SetupSignalHandler registered for SIGTERM and SIGINT. A stop channel is returned
+// which is closed on one of these signals. If a second signal is caught, the program
+// is terminated with exit code 1.
+func SetupSignalHandler() (stopCh <-chan struct{}) {
+ close(onlyOneSignalHandler) // panics when called twice
+
+ stop := make(chan struct{})
+ c := make(chan os.Signal, 2)
+ signal.Notify(c, shutdownSignals...)
+ go func() {
+ <-c
+ close(stop)
+ <-c
+ os.Exit(1) // second signal. Exit directly.
+ }()
+
+ return stop
+}
diff --git a/pkg/signals/signal_posix.go b/pkg/signals/signal_posix.go
new file mode 100644
index 00000000000..d53362353dd
--- /dev/null
+++ b/pkg/signals/signal_posix.go
@@ -0,0 +1,26 @@
+// +build !windows
+
+/*
+Copyright 2018 Google, 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 signals
+
+import (
+ "os"
+ "syscall"
+)
+
+var shutdownSignals = []os.Signal{os.Interrupt, syscall.SIGTERM}
diff --git a/pkg/signals/signal_windows.go b/pkg/signals/signal_windows.go
new file mode 100644
index 00000000000..e89e71adca4
--- /dev/null
+++ b/pkg/signals/signal_windows.go
@@ -0,0 +1,23 @@
+/*
+Copyright 2018 Google, 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 signals
+
+import (
+ "os"
+)
+
+var shutdownSignals = []os.Signal{os.Interrupt}
diff --git a/pkg/triggers/BUILD b/pkg/triggers/BUILD
new file mode 100644
index 00000000000..207f60f66ee
--- /dev/null
+++ b/pkg/triggers/BUILD
@@ -0,0 +1,16 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_library")
+
+go_library(
+ name = "go_default_library",
+ srcs = [
+ "github.go",
+ "trigger.go",
+ ],
+ importpath = "github.com/elafros/binding/pkg/triggers",
+ visibility = ["//visibility:public"],
+ deps = [
+ "//vendor/github.com/golang/glog:go_default_library",
+ "//vendor/github.com/google/go-github/github:go_default_library",
+ "//vendor/golang.org/x/oauth2:go_default_library",
+ ],
+)
diff --git a/pkg/triggers/github.go b/pkg/triggers/github.go
new file mode 100644
index 00000000000..c0b66ac689e
--- /dev/null
+++ b/pkg/triggers/github.go
@@ -0,0 +1,81 @@
+/*
+Copyright 2018 Google, 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 triggers
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/golang/glog"
+
+ "golang.org/x/oauth2"
+
+ ghclient "github.com/google/go-github/github"
+)
+
+const (
+ // SuccessSynced is used as part of the Event 'reason' when a Bind is synced
+ SuccessSynced = "Synced"
+
+ // MessageResourceSynced is the message used for an Event fired when a Bind
+ // is synced successfully
+ MessageResourceSynced = "Bind synced successfully"
+)
+
+type GithubTrigger struct {
+}
+
+func NewGithubTrigger() Trigger {
+ return &GithubTrigger{}
+}
+
+func (t *GithubTrigger) Bind(parameters map[string]interface{}, route string) (map[string]interface{}, error) {
+ glog.Infof("CREATING GITHUB WEBHOOK")
+
+ ctx := context.Background()
+ ts := oauth2.StaticTokenSource(
+ &oauth2.Token{AccessToken: parameters["accessToken"].(string)},
+ )
+ tc := oauth2.NewClient(ctx, ts)
+ glog.Infof("CREATING GITHUB WEBHOOK with access token: %s", parameters["accessToken"].(string))
+
+ client := ghclient.NewClient(tc)
+ active := true
+ name := "web"
+ config := make(map[string]interface{})
+ config["url"] = fmt.Sprintf("http://%s", route)
+ config["content_type"] = "json"
+ config["secret"] = parameters["secretToken"].(string)
+ hook := ghclient.Hook{
+ Name: &name,
+ URL: &route,
+ Events: []string{"pull_request"},
+ Active: &active,
+ Config: config,
+ }
+
+ h, r, err := client.Repositories.CreateHook(ctx, parameters["owner"].(string), parameters["repo"].(string), &hook)
+ if err != nil {
+ glog.Warningf("Failed to create the webhook: %s", err)
+ glog.Warningf("Response:\n%+v", r)
+ return nil, err
+ }
+ glog.Infof("Created hook: %+v", h)
+ ret := make(map[string]interface{})
+ ret["ID"] = fmt.Sprintf("%d", h.ID)
+ return ret, nil
+}
diff --git a/pkg/triggers/trigger.go b/pkg/triggers/trigger.go
new file mode 100644
index 00000000000..b8efe4e6b8f
--- /dev/null
+++ b/pkg/triggers/trigger.go
@@ -0,0 +1,21 @@
+/*
+Copyright 2018 Google, 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 triggers
+
+type Trigger interface {
+ Bind(parameters map[string]interface{}, route string) (map[string]interface{}, error)
+}
diff --git a/print-workspace-status.sh b/print-workspace-status.sh
new file mode 100755
index 00000000000..5fdf6b932c8
--- /dev/null
+++ b/print-workspace-status.sh
@@ -0,0 +1,23 @@
+#!/bin/bash
+# Copyright 2018 Google, 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.
+
+set -o errexit
+set -o nounset
+set -o pipefail
+
+cat <
+ {
+ "accessToken": "asdfasfdsaf",
+ "secretToken": "password"
+ }
+```
+
+## Running
+
+You can deploy this to Elafros from the root directory via:
+```shell
+bazel run sample/github:everything.create
+```
+
+Once deployed, you can inspect the created resources with `kubectl` commands:
+
+```shell
+# This will show the Route that we created:
+kubectl get route -o yaml
+
+# This will show the Configuration that we created:
+kubectl get configurations -o yaml
+
+# This will show the Revision that was created by our configuration:
+kubectl get revisions -o yaml
+
+# This will show the available EventSources that you can bind to:
+kubectl get eventsources -oyaml
+
+# This will show the available EventTypes that you can bind to:
+kubectl get eventtypes -oyaml
+
+```
+
+To make this service accessible to github, we first need to determine its ingress address
+(might have to wait a little while until 'ADDRESS' gets assigned):
+```shell
+$ watch kubectl get ingress
+NAME HOSTS ADDRESS PORTS AGE
+git-webhook-ela-ingress demostuff.aikas.org 35.202.30.59 80 14s
+```
+
+Once the `ADDRESS` gets assigned to the cluster, you need to assign a DNS name for that IP address.
+[Using GCP DNS](https://support.google.com/domains/answer/3290350)
+
+So, you'd need to create an A record for demostuff.aikas.org pointing to 35.202.30.59.
+
+To now bind the github webhook for pull requests with the function we created above, you need to
+ create a Bind object. Modify sample/github/pullrequest.yaml to point to owner of the repo as well
+ as the particular repo you want to subscribe to. So, change spec.parameters.[owner,repo] with the values
+ you want.
+
+ For example, if I wanted to receive notifications to:
+ github.com/vaikas/misc repo, my Bind object would look like so:
+
+```yaml
+apiVersion: elafros.dev/v1alpha1
+kind: Bind
+metadata:
+ name: bind-example
+ namespace: default
+spec:
+ action:
+ routeName: git-webhook
+ source:
+ eventSource: github
+ eventType: pullrequest
+ parameters:
+ owner: vaikas
+ repo: misc
+ parametersFrom:
+ - secretKeyRef:
+ name: githubsecret
+ key: githubCredentials
+
+```
+
+Then create the binding so that you can see changes
+
+```shell
+ kubectl create -f sample/github/pullrequest.yaml
+```
+
+
+Then create a PR for the repo you configured the webhook for, and you'll see that the Title
+will be modified with the suffix '(looks pretty legit to me)'
+
+## Cleaning up
+
+To clean up the sample service:
+
+```shell
+bazel run sample/github:everything.delete
+```
diff --git a/sample/github/configuration.yaml b/sample/github/configuration.yaml
new file mode 100644
index 00000000000..612d4539fd5
--- /dev/null
+++ b/sample/github/configuration.yaml
@@ -0,0 +1,31 @@
+# Copyright 2018 Google LLC
+#
+# 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
+#
+# https://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.
+
+apiVersion: elafros.dev/v1alpha1
+kind: Configuration
+metadata:
+ name: git-webhook
+ namespace: default
+spec:
+ template:
+ spec:
+ serviceType: container
+ containerSpec:
+ image: git-webhook:latest
+ env:
+ - name: GITHUB_SECRET
+ valueFrom:
+ secretKeyRef:
+ name: githubsecret
+ key: githubCredentials
diff --git a/sample/github/eventsource.yaml b/sample/github/eventsource.yaml
new file mode 100644
index 00000000000..a743dff763c
--- /dev/null
+++ b/sample/github/eventsource.yaml
@@ -0,0 +1,22 @@
+# Copyright 2018 Google LLC
+#
+# 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
+#
+# https://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.
+
+apiVersion: elafros.dev/v1alpha1
+kind: EventSource
+metadata:
+ name: github
+ namespace: default
+spec:
+ type: github
+ source: github.com
diff --git a/sample/github/eventtype.yaml b/sample/github/eventtype.yaml
new file mode 100644
index 00000000000..6223af12baa
--- /dev/null
+++ b/sample/github/eventtype.yaml
@@ -0,0 +1,22 @@
+# Copyright 2018 Google LLC
+#
+# 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
+#
+# https://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.
+
+apiVersion: elafros.dev/v1alpha1
+kind: EventType
+metadata:
+ name: pullrequest
+ namespace: default
+spec:
+ eventSource: github
+ description: "notifications on pullrequests"
diff --git a/sample/github/githubsecret.yaml b/sample/github/githubsecret.yaml
new file mode 100644
index 00000000000..0f5245a3571
--- /dev/null
+++ b/sample/github/githubsecret.yaml
@@ -0,0 +1,25 @@
+# Copyright 2018 Google LLC
+#
+# 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
+#
+# https://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.
+
+apiVersion: v1
+kind: Secret
+metadata:
+ name: githubsecret
+type: Opaque
+stringData:
+ githubCredentials: >
+ {
+ "accessToken": "",
+ "secretToken": ""
+ }
diff --git a/sample/github/gitwebhook.go b/sample/github/gitwebhook.go
new file mode 100644
index 00000000000..076531fa012
--- /dev/null
+++ b/sample/github/gitwebhook.go
@@ -0,0 +1,121 @@
+/*
+Copyright 2018 Google LLC
+
+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
+
+ https://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 main
+
+import (
+ "context"
+ "encoding/json"
+ "flag"
+ "fmt"
+ "os"
+ "strings"
+
+ "github.com/golang/glog"
+ "golang.org/x/oauth2"
+ webhooks "gopkg.in/go-playground/webhooks.v3"
+ "gopkg.in/go-playground/webhooks.v3/github"
+
+ ghclient "github.com/google/go-github/github"
+)
+
+const (
+ // Environment variable containing json credentials
+ envSecret = "GITHUB_SECRET"
+ // this is what we tack onto each PR title if not there already
+ titleSuffix = "looks pretty legit to me"
+)
+
+// GithubHandler holds necessary objects for communicating with the Github.
+type GithubHandler struct {
+ client *ghclient.Client
+ ctx context.Context
+}
+
+type GithubSecrets struct {
+ AccessToken string `json:"accessToken"`
+ SecretToken string `json:"secretToken"`
+}
+
+// HandlePullRequest is invoked whenever a PullRequest is modified (created, updated, etc.)
+func (handler *GithubHandler) HandlePullRequest(payload interface{}, header webhooks.Header) {
+ glog.Info("Handling Pull Request")
+
+ pl := payload.(github.PullRequestPayload)
+
+ // Do whatever you want from here...
+ title := pl.PullRequest.Title
+ glog.Infof("GOT PR with Title: %q", title)
+
+ // Check the title and if it contains 'looks pretty legit' leave it alone
+ if strings.Contains(title, titleSuffix) {
+ // already modified, leave it alone.
+ return
+ }
+
+ newTitle := fmt.Sprintf("%s (%s)", title, titleSuffix)
+ updatedPR := ghclient.PullRequest{
+ Title: &newTitle,
+ }
+ newPR, response, err := handler.client.PullRequests.Edit(handler.ctx, pl.Repository.Owner.Login, pl.Repository.Name, int(pl.Number), &updatedPR)
+ if err != nil {
+ glog.Warningf("Failed to update PR: %s\n%s", err, response)
+ return
+ }
+ if newPR.Title != nil {
+ glog.Infof("New PR Title: %q", *newPR.Title)
+ } else {
+ glog.Infof("New PR title is nil")
+ }
+}
+
+func main() {
+ flag.Parse()
+ // set the logs to stderr so kube will see them.
+ flag.Lookup("logtostderr").Value.Set("true")
+ githubSecrets := os.Getenv(envSecret)
+
+ var credentials GithubSecrets
+ err := json.Unmarshal([]byte(githubSecrets), &credentials)
+ if err != nil {
+ glog.Fatalf("Failed to unmarshal credentials: %s", err)
+ return
+ }
+
+ // Set up the auth for being able to talk to Github. It's
+ // odd that you have to also pass context around for the
+ // calls even after giving it to client. But, whatever.
+ ctx := context.Background()
+ ts := oauth2.StaticTokenSource(
+ &oauth2.Token{AccessToken: credentials.AccessToken},
+ )
+ tc := oauth2.NewClient(ctx, ts)
+
+ client := ghclient.NewClient(tc)
+
+ h := &GithubHandler{
+ client: client,
+ ctx: ctx,
+ }
+
+ hook := github.New(&github.Config{Secret: credentials.SecretToken})
+ hook.RegisterEvents(h.HandlePullRequest, github.PullRequestEvent)
+
+ err = webhooks.Run(hook, ":8080", "/")
+ if err != nil {
+ glog.Fatalf("Failed to run the webhook")
+ }
+}
diff --git a/sample/github/pullrequest.yaml b/sample/github/pullrequest.yaml
new file mode 100644
index 00000000000..d7f41605efd
--- /dev/null
+++ b/sample/github/pullrequest.yaml
@@ -0,0 +1,33 @@
+# Copyright 2018 Google LLC
+#
+# 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
+#
+# https://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.
+
+apiVersion: elafros.dev/v1alpha1
+kind: Bind
+metadata:
+ name: bind-example
+ namespace: default
+spec:
+ action:
+ routeName: git-webhook
+ source:
+ eventSource: github
+ eventType: pullrequest
+ parameters:
+ owner: vaikas
+ repo: misc
+ foo: bar
+ parametersFrom:
+ - secretKeyRef:
+ name: githubsecret
+ key: githubCredentials
diff --git a/sample/github/route.yaml b/sample/github/route.yaml
new file mode 100644
index 00000000000..481c7e0f533
--- /dev/null
+++ b/sample/github/route.yaml
@@ -0,0 +1,24 @@
+# Copyright 2018 Google LLC
+#
+# 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
+#
+# https://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.
+
+apiVersion: elafros.dev/v1alpha1
+kind: Route
+metadata:
+ name: git-webhook
+ namespace: default
+spec:
+ domainSuffix: demostuff.aikas.org
+ traffic:
+ - configuration: git-webhook
+ percent: 100
diff --git a/serviceaccount.yaml b/serviceaccount.yaml
new file mode 100644
index 00000000000..c7c5480781b
--- /dev/null
+++ b/serviceaccount.yaml
@@ -0,0 +1,18 @@
+# Copyright 2018 Google, 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.
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ name: bind-controller
+ namespace: bind-system
diff --git a/vendor/cloud.google.com/go/.travis.yml b/vendor/cloud.google.com/go/.travis.yml
new file mode 100644
index 00000000000..59594d41ce5
--- /dev/null
+++ b/vendor/cloud.google.com/go/.travis.yml
@@ -0,0 +1,21 @@
+sudo: false
+language: go
+go:
+- 1.6.x
+- 1.7.x
+- 1.8.x
+- 1.9.x
+install:
+- go get -v cloud.google.com/go/...
+script:
+- openssl aes-256-cbc -K $encrypted_a8b3f4fc85f4_key -iv $encrypted_a8b3f4fc85f4_iv -in keys.tar.enc -out keys.tar -d
+- tar xvf keys.tar
+- GCLOUD_TESTS_GOLANG_PROJECT_ID="dulcet-port-762"
+ GCLOUD_TESTS_GOLANG_KEY="$(pwd)/dulcet-port-762-key.json"
+ GCLOUD_TESTS_GOLANG_FIRESTORE_PROJECT_ID="gcloud-golang-firestore-tests"
+ GCLOUD_TESTS_GOLANG_FIRESTORE_KEY="$(pwd)/gcloud-golang-firestore-tests-key.json"
+ ./run-tests.sh $TRAVIS_COMMIT
+env:
+ matrix:
+ # The GCLOUD_TESTS_API_KEY environment variable.
+ secure: VdldogUOoubQ60LhuHJ+g/aJoBiujkSkWEWl79Zb8cvQorcQbxISS+JsOOp4QkUOU4WwaHAm8/3pIH1QMWOR6O78DaLmDKi5Q4RpkVdCpUXy+OAfQaZIcBsispMrjxLXnqFjo9ELnrArfjoeCTzaX0QTCfwQwVmigC8rR30JBKI=
diff --git a/vendor/cloud.google.com/go/AUTHORS b/vendor/cloud.google.com/go/AUTHORS
new file mode 100644
index 00000000000..c364af1da09
--- /dev/null
+++ b/vendor/cloud.google.com/go/AUTHORS
@@ -0,0 +1,15 @@
+# This is the official list of cloud authors for copyright purposes.
+# This file is distinct from the CONTRIBUTORS files.
+# See the latter for an explanation.
+
+# Names should be added to this file as:
+# Name or Organization
+# The email address is not required for organizations.
+
+Filippo Valsorda
+Google Inc.
+Ingo Oeser
+Palm Stone Games, Inc.
+Paweł Knap
+Péter Szilágyi
+Tyler Treat
diff --git a/vendor/cloud.google.com/go/BUILD.bazel b/vendor/cloud.google.com/go/BUILD.bazel
new file mode 100644
index 00000000000..643265be88f
--- /dev/null
+++ b/vendor/cloud.google.com/go/BUILD.bazel
@@ -0,0 +1,29 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
+
+go_library(
+ name = "go_default_library",
+ srcs = ["cloud.go"],
+ importpath = "cloud.google.com/go",
+ visibility = ["//visibility:public"],
+)
+
+go_test(
+ name = "go_default_test",
+ srcs = [
+ "import_test.go",
+ "license_test.go",
+ ],
+ embed = [":go_default_library"],
+ importpath = "cloud.google.com/go",
+)
+
+go_test(
+ name = "go_default_xtest",
+ srcs = ["authexample_test.go"],
+ importpath = "cloud.google.com/go_test",
+ deps = [
+ "//vendor/cloud.google.com/go/datastore:go_default_library",
+ "//vendor/golang.org/x/net/context:go_default_library",
+ "//vendor/google.golang.org/api/option:go_default_library",
+ ],
+)
diff --git a/vendor/cloud.google.com/go/CONTRIBUTING.md b/vendor/cloud.google.com/go/CONTRIBUTING.md
new file mode 100644
index 00000000000..95c94a48b42
--- /dev/null
+++ b/vendor/cloud.google.com/go/CONTRIBUTING.md
@@ -0,0 +1,152 @@
+# Contributing
+
+1. Sign one of the contributor license agreements below.
+1. `go get golang.org/x/review/git-codereview` to install the code reviewing tool.
+ 1. You will need to ensure that your `GOBIN` directory (by default
+ `$GOPATH/bin`) is in your `PATH` so that git can find the command.
+ 1. If you would like, you may want to set up aliases for git-codereview,
+ such that `git codereview change` becomes `git change`. See the
+ [godoc](https://godoc.org/golang.org/x/review/git-codereview) for details.
+ 1. Should you run into issues with the git-codereview tool, please note
+ that all error messages will assume that you have set up these
+ aliases.
+1. Get the cloud package by running `go get -d cloud.google.com/go`.
+ 1. If you have already checked out the source, make sure that the remote git
+ origin is https://code.googlesource.com/gocloud:
+
+ git remote set-url origin https://code.googlesource.com/gocloud
+1. Make sure your auth is configured correctly by visiting
+ https://code.googlesource.com, clicking "Generate Password", and following
+ the directions.
+1. Make changes and create a change by running `git codereview change `,
+provide a commit message, and use `git codereview mail` to create a Gerrit CL.
+1. Keep amending to the change with `git codereview change` and mail as your receive
+feedback. Each new mailed amendment will create a new patch set for your change in Gerrit.
+
+## Integration Tests
+
+In addition to the unit tests, you may run the integration test suite.
+
+To run the integrations tests, creating and configuration of a project in the
+Google Developers Console is required.
+
+After creating a project, you must [create a service account](https://developers.google.com/identity/protocols/OAuth2ServiceAccount#creatinganaccount).
+Ensure the project-level **Owner**
+[IAM role](console.cloud.google.com/iam-admin/iam/project) role is added to the
+service account. Alternatively, the account can be granted all of the following roles:
+- **Editor**
+- **Logs Configuration Writer**
+- **PubSub Admin**
+
+Once you create a project, set the following environment variables to be able to
+run the against the actual APIs.
+
+- **GCLOUD_TESTS_GOLANG_PROJECT_ID**: Developers Console project's ID (e.g. bamboo-shift-455)
+- **GCLOUD_TESTS_GOLANG_KEY**: The path to the JSON key file.
+- **GCLOUD_TESTS_API_KEY**: Your API key.
+
+Firestore requires a different project and key:
+
+- **GCLOUD_TESTS_GOLANG_FIRESTORE_PROJECT_ID**: Developers Console project's ID
+ supporting Firestore
+- **GCLOUD_TESTS_GOLANG_FIRESTORE_KEY**: The path to the JSON key file.
+
+Install the [gcloud command-line tool][gcloudcli] to your machine and use it
+to create some resources used in integration tests.
+
+From the project's root directory:
+
+``` sh
+# Set the default project in your env.
+$ gcloud config set project $GCLOUD_TESTS_GOLANG_PROJECT_ID
+
+# Authenticate the gcloud tool with your account.
+$ gcloud auth login
+
+# Create the indexes used in the datastore integration tests.
+$ gcloud preview datastore create-indexes datastore/testdata/index.yaml
+
+# Create a Google Cloud storage bucket with the same name as your test project,
+# and with the Stackdriver Logging service account as owner, for the sink
+# integration tests in logging.
+$ gsutil mb gs://$GCLOUD_TESTS_GOLANG_PROJECT_ID
+$ gsutil acl ch -g cloud-logs@google.com:O gs://$GCLOUD_TESTS_GOLANG_PROJECT_ID
+
+# Create a PubSub topic for integration tests of storage notifications.
+$ gcloud beta pubsub topics create go-storage-notification-test
+
+# Create a Spanner instance for the spanner integration tests.
+$ gcloud beta spanner instances create go-integration-test --config regional-us-central1 --nodes 1 --description 'Instance for go client test'
+# NOTE: Spanner instances are priced by the node-hour, so you may want to delete
+# the instance after testing with 'gcloud beta spanner instances delete'.
+
+
+```
+
+Once you've set the environment variables, you can run the integration tests by
+running:
+
+``` sh
+$ go test -v cloud.google.com/go/...
+```
+
+## Contributor License Agreements
+
+Before we can accept your pull requests you'll need to sign a Contributor
+License Agreement (CLA):
+
+- **If you are an individual writing original source code** and **you own the
+intellectual property**, then you'll need to sign an [individual CLA][indvcla].
+- **If you work for a company that wants to allow you to contribute your
+work**, then you'll need to sign a [corporate CLA][corpcla].
+
+You can sign these electronically (just scroll to the bottom). After that,
+we'll be able to accept your pull requests.
+
+## Contributor Code of Conduct
+
+As contributors and maintainers of this project,
+and in the interest of fostering an open and welcoming community,
+we pledge to respect all people who contribute through reporting issues,
+posting feature requests, updating documentation,
+submitting pull requests or patches, and other activities.
+
+We are committed to making participation in this project
+a harassment-free experience for everyone,
+regardless of level of experience, gender, gender identity and expression,
+sexual orientation, disability, personal appearance,
+body size, race, ethnicity, age, religion, or nationality.
+
+Examples of unacceptable behavior by participants include:
+
+* The use of sexualized language or imagery
+* Personal attacks
+* Trolling or insulting/derogatory comments
+* Public or private harassment
+* Publishing other's private information,
+such as physical or electronic
+addresses, without explicit permission
+* Other unethical or unprofessional conduct.
+
+Project maintainers have the right and responsibility to remove, edit, or reject
+comments, commits, code, wiki edits, issues, and other contributions
+that are not aligned to this Code of Conduct.
+By adopting this Code of Conduct,
+project maintainers commit themselves to fairly and consistently
+applying these principles to every aspect of managing this project.
+Project maintainers who do not follow or enforce the Code of Conduct
+may be permanently removed from the project team.
+
+This code of conduct applies both within project spaces and in public spaces
+when an individual is representing the project or its community.
+
+Instances of abusive, harassing, or otherwise unacceptable behavior
+may be reported by opening an issue
+or contacting one or more of the project maintainers.
+
+This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.2.0,
+available at [http://contributor-covenant.org/version/1/2/0/](http://contributor-covenant.org/version/1/2/0/)
+
+[gcloudcli]: https://developers.google.com/cloud/sdk/gcloud/
+[indvcla]: https://developers.google.com/open-source/cla/individual
+[corpcla]: https://developers.google.com/open-source/cla/corporate
diff --git a/vendor/cloud.google.com/go/CONTRIBUTORS b/vendor/cloud.google.com/go/CONTRIBUTORS
new file mode 100644
index 00000000000..eb55275bf0d
--- /dev/null
+++ b/vendor/cloud.google.com/go/CONTRIBUTORS
@@ -0,0 +1,39 @@
+# People who have agreed to one of the CLAs and can contribute patches.
+# The AUTHORS file lists the copyright holders; this file
+# lists people. For example, Google employees are listed here
+# but not in AUTHORS, because Google holds the copyright.
+#
+# https://developers.google.com/open-source/cla/individual
+# https://developers.google.com/open-source/cla/corporate
+#
+# Names should be added to this file as:
+# Name
+
+# Keep the list alphabetically sorted.
+
+Alexis Hunt
+Andreas Litt
+Andrew Gerrand
+Brad Fitzpatrick
+Burcu Dogan
+Dave Day
+David Sansome
+David Symonds
+Filippo Valsorda
+Glenn Lewis
+Ingo Oeser
+Johan Euphrosine
+Jonathan Amsterdam
+Kunpei Sakai
+Luna Duclos
+Magnus Hiie
+Mario Castro
+Michael McGreevy
+Omar Jarjur
+Paweł Knap
+Péter Szilágyi
+Sarah Adams
+Thanatat Tamtan
+Toby Burress
+Tuo Shan
+Tyler Treat
diff --git a/vendor/cloud.google.com/go/LICENSE b/vendor/cloud.google.com/go/LICENSE
new file mode 100644
index 00000000000..d6456956733
--- /dev/null
+++ b/vendor/cloud.google.com/go/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/vendor/cloud.google.com/go/MIGRATION.md b/vendor/cloud.google.com/go/MIGRATION.md
new file mode 100644
index 00000000000..791210de197
--- /dev/null
+++ b/vendor/cloud.google.com/go/MIGRATION.md
@@ -0,0 +1,54 @@
+# Code Changes
+
+## v0.10.0
+
+- pubsub: Replace
+
+ ```
+ sub.ModifyPushConfig(ctx, pubsub.PushConfig{Endpoint: "https://example.com/push"})
+ ```
+
+ with
+
+ ```
+ sub.Update(ctx, pubsub.SubscriptionConfigToUpdate{
+ PushConfig: &pubsub.PushConfig{Endpoint: "https://example.com/push"},
+ })
+ ```
+
+- trace: traceGRPCServerInterceptor will be provided from *trace.Client.
+Given an initialized `*trace.Client` named `tc`, instead of
+
+ ```
+ s := grpc.NewServer(grpc.UnaryInterceptor(trace.GRPCServerInterceptor(tc)))
+ ```
+
+ write
+
+ ```
+ s := grpc.NewServer(grpc.UnaryInterceptor(tc.GRPCServerInterceptor()))
+ ```
+
+- trace trace.GRPCClientInterceptor will also provided from *trace.Client.
+Instead of
+
+ ```
+ conn, err := grpc.Dial(srv.Addr, grpc.WithUnaryInterceptor(trace.GRPCClientInterceptor()))
+ ```
+
+ write
+
+ ```
+ conn, err := grpc.Dial(srv.Addr, grpc.WithUnaryInterceptor(tc.GRPCClientInterceptor()))
+ ```
+
+- trace: We removed the deprecated `trace.EnableGRPCTracing`. Use the gRPC
+interceptor as a dial option as shown below when initializing Cloud package
+clients:
+
+ ```
+ c, err := pubsub.NewClient(ctx, "project-id", option.WithGRPCDialOption(grpc.WithUnaryInterceptor(tc.GRPCClientInterceptor())))
+ if err != nil {
+ ...
+ }
+ ```
diff --git a/vendor/cloud.google.com/go/README.md b/vendor/cloud.google.com/go/README.md
new file mode 100644
index 00000000000..80a605fc35f
--- /dev/null
+++ b/vendor/cloud.google.com/go/README.md
@@ -0,0 +1,545 @@
+# Google Cloud Client Libraries for Go
+
+[](https://godoc.org/cloud.google.com/go)
+
+Go packages for [Google Cloud Platform](https://cloud.google.com) services.
+
+``` go
+import "cloud.google.com/go"
+```
+
+To install the packages on your system,
+
+```
+$ go get -u cloud.google.com/go/...
+```
+
+**NOTE:** Some of these packages are under development, and may occasionally
+make backwards-incompatible changes.
+
+**NOTE:** Github repo is a mirror of [https://code.googlesource.com/gocloud](https://code.googlesource.com/gocloud).
+
+ * [News](#news)
+ * [Supported APIs](#supported-apis)
+ * [Go Versions Supported](#go-versions-supported)
+ * [Authorization](#authorization)
+ * [Cloud Datastore](#cloud-datastore-)
+ * [Cloud Storage](#cloud-storage-)
+ * [Cloud Pub/Sub](#cloud-pub-sub-)
+ * [Cloud BigQuery](#cloud-bigquery-)
+ * [Stackdriver Logging](#stackdriver-logging-)
+ * [Cloud Spanner](#cloud-spanner-)
+
+
+## News
+
+_February 26, 2018_
+
+*v0.19.0*
+
+- bigquery:
+ - Support customer-managed encryption keys.
+
+- bigtable:
+ - Improved emulator support.
+ - Support GetCluster.
+
+- datastore:
+ - Add general mutations.
+ - Support pointer struct fields.
+ - Support transaction options.
+
+- firestore:
+ - Add Transaction.GetAll.
+ - Support document cursors.
+
+- logging:
+ - Support concurrent RPCs to the service.
+ - Support per-entry resources.
+
+- profiler:
+ - Add config options to disable heap and thread profiling.
+ - Read the project ID from $GOOGLE_CLOUD_PROJECT when it's set.
+
+- pubsub:
+ - BEHAVIOR CHANGE: Release flow control after ack/nack (instead of after the
+ callback returns).
+ - Add SubscriptionInProject.
+ - Add OpenCensus instrumentation for streaming pull.
+
+- storage:
+ - Support CORS.
+
+
+_January 18, 2018_
+
+*v0.18.0*
+
+- bigquery:
+ - Marked stable.
+ - Schema inference of nullable fields supported.
+ - Added TimePartitioning to QueryConfig.
+
+- firestore: Data provided to DocumentRef.Set with a Merge option can contain
+ Delete sentinels.
+
+- logging: Clients can accept parent resources other than projects.
+
+- pubsub:
+ - pubsub/pstest: A lighweight fake for pubsub. Experimental; feedback welcome.
+ - Support updating more subscription metadata: AckDeadline,
+ RetainAckedMessages and RetentionDuration.
+
+- oslogin/apiv1beta: New client for the Cloud OS Login API.
+
+- rpcreplay: A package for recording and replaying gRPC traffic.
+
+- spanner:
+ - Add a ReadWithOptions that supports a row limit, as well as an index.
+ - Support query plan and execution statistics.
+ - Added [OpenCensus](http://opencensus.io) support.
+
+- storage: Clarify checksum validation for gzipped files (it is not validated
+ when the file is served uncompressed).
+
+
+_December 11, 2017_
+
+*v0.17.0*
+
+- firestore BREAKING CHANGES:
+ - Remove UpdateMap and UpdateStruct; rename UpdatePaths to Update.
+ Change
+ `docref.UpdateMap(ctx, map[string]interface{}{"a.b", 1})`
+ to
+ `docref.Update(ctx, []firestore.Update{{Path: "a.b", Value: 1}})`
+
+ Change
+ `docref.UpdateStruct(ctx, []string{"Field"}, aStruct)`
+ to
+ `docref.Update(ctx, []firestore.Update{{Path: "Field", Value: aStruct.Field}})`
+ - Rename MergePaths to Merge; require args to be FieldPaths
+ - A value stored as an integer can be read into a floating-point field, and vice versa.
+- bigtable/cmd/cbt:
+ - Support deleting a column.
+ - Add regex option for row read.
+- spanner: Mark stable.
+- storage:
+ - Add Reader.ContentEncoding method.
+ - Fix handling of SignedURL headers.
+- bigquery:
+ - If Uploader.Put is called with no rows, it returns nil without making a
+ call.
+ - Schema inference supports the "nullable" option in struct tags for
+ non-required fields.
+ - TimePartitioning supports "Field".
+
+
+[Older news](https://github.com/GoogleCloudPlatform/google-cloud-go/blob/master/old-news.md)
+
+## Supported APIs
+
+Google API | Status | Package
+---------------------------------|--------------|-----------------------------------------------------------
+[BigQuery][cloud-bigquery] | stable | [`cloud.google.com/go/bigquery`][cloud-bigquery-ref]
+[Bigtable][cloud-bigtable] | stable | [`cloud.google.com/go/bigtable`][cloud-bigtable-ref]
+[Container][cloud-container] | alpha | [`cloud.google.com/go/container/apiv1`][cloud-container-ref]
+[Data Loss Prevention][cloud-dlp]| alpha | [`cloud.google.com/go/dlp/apiv2beta1`][cloud-dlp-ref]
+[Datastore][cloud-datastore] | stable | [`cloud.google.com/go/datastore`][cloud-datastore-ref]
+[Debugger][cloud-debugger] | alpha | [`cloud.google.com/go/debugger/apiv2`][cloud-debugger-ref]
+[ErrorReporting][cloud-errors] | alpha | [`cloud.google.com/go/errorreporting`][cloud-errors-ref]
+[Firestore][cloud-firestore] | beta | [`cloud.google.com/go/firestore`][cloud-firestore-ref]
+[Language][cloud-language] | stable | [`cloud.google.com/go/language/apiv1`][cloud-language-ref]
+[Logging][cloud-logging] | stable | [`cloud.google.com/go/logging`][cloud-logging-ref]
+[Monitoring][cloud-monitoring] | beta | [`cloud.google.com/go/monitoring/apiv3`][cloud-monitoring-ref]
+[OS Login][cloud-oslogin] | alpha | [`cloud.google.com/compute/docs/oslogin/rest`][cloud-oslogin-ref]
+[Pub/Sub][cloud-pubsub] | beta | [`cloud.google.com/go/pubsub`][cloud-pubsub-ref]
+[Spanner][cloud-spanner] | stable | [`cloud.google.com/go/spanner`][cloud-spanner-ref]
+[Speech][cloud-speech] | stable | [`cloud.google.com/go/speech/apiv1`][cloud-speech-ref]
+[Storage][cloud-storage] | stable | [`cloud.google.com/go/storage`][cloud-storage-ref]
+[Translation][cloud-translation] | stable | [`cloud.google.com/go/translate`][cloud-translation-ref]
+[Video Intelligence][cloud-video]| beta | [`cloud.google.com/go/videointelligence/apiv1beta1`][cloud-video-ref]
+[Vision][cloud-vision] | stable | [`cloud.google.com/go/vision/apiv1`][cloud-vision-ref]
+
+
+> **Alpha status**: the API is still being actively developed. As a
+> result, it might change in backward-incompatible ways and is not recommended
+> for production use.
+>
+> **Beta status**: the API is largely complete, but still has outstanding
+> features and bugs to be addressed. There may be minor backwards-incompatible
+> changes where necessary.
+>
+> **Stable status**: the API is mature and ready for production use. We will
+> continue addressing bugs and feature requests.
+
+Documentation and examples are available at
+https://godoc.org/cloud.google.com/go
+
+Visit or join the
+[google-api-go-announce group](https://groups.google.com/forum/#!forum/google-api-go-announce)
+for updates on these packages.
+
+## Go Versions Supported
+
+We support the two most recent major versions of Go. If Google App Engine uses
+an older version, we support that as well. You can see which versions are
+currently supported by looking at the lines following `go:` in
+[`.travis.yml`](.travis.yml).
+
+## Authorization
+
+By default, each API will use [Google Application Default Credentials][default-creds]
+for authorization credentials used in calling the API endpoints. This will allow your
+application to run in many environments without requiring explicit configuration.
+
+[snip]:# (auth)
+```go
+client, err := storage.NewClient(ctx)
+```
+
+To authorize using a
+[JSON key file](https://cloud.google.com/iam/docs/managing-service-account-keys),
+pass
+[`option.WithServiceAccountFile`](https://godoc.org/google.golang.org/api/option#WithServiceAccountFile)
+to the `NewClient` function of the desired package. For example:
+
+[snip]:# (auth-JSON)
+```go
+client, err := storage.NewClient(ctx, option.WithServiceAccountFile("path/to/keyfile.json"))
+```
+
+You can exert more control over authorization by using the
+[`golang.org/x/oauth2`](https://godoc.org/golang.org/x/oauth2) package to
+create an `oauth2.TokenSource`. Then pass
+[`option.WithTokenSource`](https://godoc.org/google.golang.org/api/option#WithTokenSource)
+to the `NewClient` function:
+[snip]:# (auth-ts)
+```go
+tokenSource := ...
+client, err := storage.NewClient(ctx, option.WithTokenSource(tokenSource))
+```
+
+## Cloud Datastore [](https://godoc.org/cloud.google.com/go/datastore)
+
+- [About Cloud Datastore][cloud-datastore]
+- [Activating the API for your project][cloud-datastore-activation]
+- [API documentation][cloud-datastore-docs]
+- [Go client documentation](https://godoc.org/cloud.google.com/go/datastore)
+- [Complete sample program](https://github.com/GoogleCloudPlatform/golang-samples/tree/master/datastore/tasks)
+
+### Example Usage
+
+First create a `datastore.Client` to use throughout your application:
+
+[snip]:# (datastore-1)
+```go
+client, err := datastore.NewClient(ctx, "my-project-id")
+if err != nil {
+ log.Fatal(err)
+}
+```
+
+Then use that client to interact with the API:
+
+[snip]:# (datastore-2)
+```go
+type Post struct {
+ Title string
+ Body string `datastore:",noindex"`
+ PublishedAt time.Time
+}
+keys := []*datastore.Key{
+ datastore.NameKey("Post", "post1", nil),
+ datastore.NameKey("Post", "post2", nil),
+}
+posts := []*Post{
+ {Title: "Post 1", Body: "...", PublishedAt: time.Now()},
+ {Title: "Post 2", Body: "...", PublishedAt: time.Now()},
+}
+if _, err := client.PutMulti(ctx, keys, posts); err != nil {
+ log.Fatal(err)
+}
+```
+
+## Cloud Storage [](https://godoc.org/cloud.google.com/go/storage)
+
+- [About Cloud Storage][cloud-storage]
+- [API documentation][cloud-storage-docs]
+- [Go client documentation](https://godoc.org/cloud.google.com/go/storage)
+- [Complete sample programs](https://github.com/GoogleCloudPlatform/golang-samples/tree/master/storage)
+
+### Example Usage
+
+First create a `storage.Client` to use throughout your application:
+
+[snip]:# (storage-1)
+```go
+client, err := storage.NewClient(ctx)
+if err != nil {
+ log.Fatal(err)
+}
+```
+
+[snip]:# (storage-2)
+```go
+// Read the object1 from bucket.
+rc, err := client.Bucket("bucket").Object("object1").NewReader(ctx)
+if err != nil {
+ log.Fatal(err)
+}
+defer rc.Close()
+body, err := ioutil.ReadAll(rc)
+if err != nil {
+ log.Fatal(err)
+}
+```
+
+## Cloud Pub/Sub [](https://godoc.org/cloud.google.com/go/pubsub)
+
+- [About Cloud Pubsub][cloud-pubsub]
+- [API documentation][cloud-pubsub-docs]
+- [Go client documentation](https://godoc.org/cloud.google.com/go/pubsub)
+- [Complete sample programs](https://github.com/GoogleCloudPlatform/golang-samples/tree/master/pubsub)
+
+### Example Usage
+
+First create a `pubsub.Client` to use throughout your application:
+
+[snip]:# (pubsub-1)
+```go
+client, err := pubsub.NewClient(ctx, "project-id")
+if err != nil {
+ log.Fatal(err)
+}
+```
+
+Then use the client to publish and subscribe:
+
+[snip]:# (pubsub-2)
+```go
+// Publish "hello world" on topic1.
+topic := client.Topic("topic1")
+res := topic.Publish(ctx, &pubsub.Message{
+ Data: []byte("hello world"),
+})
+// The publish happens asynchronously.
+// Later, you can get the result from res:
+...
+msgID, err := res.Get(ctx)
+if err != nil {
+ log.Fatal(err)
+}
+
+// Use a callback to receive messages via subscription1.
+sub := client.Subscription("subscription1")
+err = sub.Receive(ctx, func(ctx context.Context, m *pubsub.Message) {
+ fmt.Println(m.Data)
+ m.Ack() // Acknowledge that we've consumed the message.
+})
+if err != nil {
+ log.Println(err)
+}
+```
+
+## Cloud BigQuery [](https://godoc.org/cloud.google.com/go/bigquery)
+
+- [About Cloud BigQuery][cloud-bigquery]
+- [API documentation][cloud-bigquery-docs]
+- [Go client documentation][cloud-bigquery-ref]
+- [Complete sample programs](https://github.com/GoogleCloudPlatform/golang-samples/tree/master/bigquery)
+
+### Example Usage
+
+First create a `bigquery.Client` to use throughout your application:
+[snip]:# (bq-1)
+```go
+c, err := bigquery.NewClient(ctx, "my-project-ID")
+if err != nil {
+ // TODO: Handle error.
+}
+```
+
+Then use that client to interact with the API:
+[snip]:# (bq-2)
+```go
+// Construct a query.
+q := c.Query(`
+ SELECT year, SUM(number)
+ FROM [bigquery-public-data:usa_names.usa_1910_2013]
+ WHERE name = "William"
+ GROUP BY year
+ ORDER BY year
+`)
+// Execute the query.
+it, err := q.Read(ctx)
+if err != nil {
+ // TODO: Handle error.
+}
+// Iterate through the results.
+for {
+ var values []bigquery.Value
+ err := it.Next(&values)
+ if err == iterator.Done {
+ break
+ }
+ if err != nil {
+ // TODO: Handle error.
+ }
+ fmt.Println(values)
+}
+```
+
+
+## Stackdriver Logging [](https://godoc.org/cloud.google.com/go/logging)
+
+- [About Stackdriver Logging][cloud-logging]
+- [API documentation][cloud-logging-docs]
+- [Go client documentation][cloud-logging-ref]
+- [Complete sample programs](https://github.com/GoogleCloudPlatform/golang-samples/tree/master/logging)
+
+### Example Usage
+
+First create a `logging.Client` to use throughout your application:
+[snip]:# (logging-1)
+```go
+ctx := context.Background()
+client, err := logging.NewClient(ctx, "my-project")
+if err != nil {
+ // TODO: Handle error.
+}
+```
+
+Usually, you'll want to add log entries to a buffer to be periodically flushed
+(automatically and asynchronously) to the Stackdriver Logging service.
+[snip]:# (logging-2)
+```go
+logger := client.Logger("my-log")
+logger.Log(logging.Entry{Payload: "something happened!"})
+```
+
+Close your client before your program exits, to flush any buffered log entries.
+[snip]:# (logging-3)
+```go
+err = client.Close()
+if err != nil {
+ // TODO: Handle error.
+}
+```
+
+## Cloud Spanner [](https://godoc.org/cloud.google.com/go/spanner)
+
+- [About Cloud Spanner][cloud-spanner]
+- [API documentation][cloud-spanner-docs]
+- [Go client documentation](https://godoc.org/cloud.google.com/go/spanner)
+
+### Example Usage
+
+First create a `spanner.Client` to use throughout your application:
+
+[snip]:# (spanner-1)
+```go
+client, err := spanner.NewClient(ctx, "projects/P/instances/I/databases/D")
+if err != nil {
+ log.Fatal(err)
+}
+```
+
+[snip]:# (spanner-2)
+```go
+// Simple Reads And Writes
+_, err = client.Apply(ctx, []*spanner.Mutation{
+ spanner.Insert("Users",
+ []string{"name", "email"},
+ []interface{}{"alice", "a@example.com"})})
+if err != nil {
+ log.Fatal(err)
+}
+row, err := client.Single().ReadRow(ctx, "Users",
+ spanner.Key{"alice"}, []string{"email"})
+if err != nil {
+ log.Fatal(err)
+}
+```
+
+
+## Contributing
+
+Contributions are welcome. Please, see the
+[CONTRIBUTING](https://github.com/GoogleCloudPlatform/google-cloud-go/blob/master/CONTRIBUTING.md)
+document for details. We're using Gerrit for our code reviews. Please don't open pull
+requests against this repo, new pull requests will be automatically closed.
+
+Please note that this project is released with a Contributor Code of Conduct.
+By participating in this project you agree to abide by its terms.
+See [Contributor Code of Conduct](https://github.com/GoogleCloudPlatform/google-cloud-go/blob/master/CONTRIBUTING.md#contributor-code-of-conduct)
+for more information.
+
+[cloud-datastore]: https://cloud.google.com/datastore/
+[cloud-datastore-ref]: https://godoc.org/cloud.google.com/go/datastore
+[cloud-datastore-docs]: https://cloud.google.com/datastore/docs
+[cloud-datastore-activation]: https://cloud.google.com/datastore/docs/activate
+
+[cloud-firestore]: https://cloud.google.com/firestore/
+[cloud-firestore-ref]: https://godoc.org/cloud.google.com/go/firestore
+[cloud-firestore-docs]: https://cloud.google.com/firestore/docs
+[cloud-firestore-activation]: https://cloud.google.com/firestore/docs/activate
+
+[cloud-pubsub]: https://cloud.google.com/pubsub/
+[cloud-pubsub-ref]: https://godoc.org/cloud.google.com/go/pubsub
+[cloud-pubsub-docs]: https://cloud.google.com/pubsub/docs
+
+[cloud-storage]: https://cloud.google.com/storage/
+[cloud-storage-ref]: https://godoc.org/cloud.google.com/go/storage
+[cloud-storage-docs]: https://cloud.google.com/storage/docs
+[cloud-storage-create-bucket]: https://cloud.google.com/storage/docs/cloud-console#_creatingbuckets
+
+[cloud-bigtable]: https://cloud.google.com/bigtable/
+[cloud-bigtable-ref]: https://godoc.org/cloud.google.com/go/bigtable
+
+[cloud-bigquery]: https://cloud.google.com/bigquery/
+[cloud-bigquery-docs]: https://cloud.google.com/bigquery/docs
+[cloud-bigquery-ref]: https://godoc.org/cloud.google.com/go/bigquery
+
+[cloud-logging]: https://cloud.google.com/logging/
+[cloud-logging-docs]: https://cloud.google.com/logging/docs
+[cloud-logging-ref]: https://godoc.org/cloud.google.com/go/logging
+
+[cloud-monitoring]: https://cloud.google.com/monitoring/
+[cloud-monitoring-ref]: https://godoc.org/cloud.google.com/go/monitoring/apiv3
+
+[cloud-vision]: https://cloud.google.com/vision
+[cloud-vision-ref]: https://godoc.org/cloud.google.com/go/vision/apiv1
+
+[cloud-language]: https://cloud.google.com/natural-language
+[cloud-language-ref]: https://godoc.org/cloud.google.com/go/language/apiv1
+
+[cloud-oslogin]: https://cloud.google.com/compute/docs/oslogin/rest
+[cloud-oslogin-ref]: https://cloud.google.com/compute/docs/oslogin/rest
+
+[cloud-speech]: https://cloud.google.com/speech
+[cloud-speech-ref]: https://godoc.org/cloud.google.com/go/speech/apiv1
+
+[cloud-spanner]: https://cloud.google.com/spanner/
+[cloud-spanner-ref]: https://godoc.org/cloud.google.com/go/spanner
+[cloud-spanner-docs]: https://cloud.google.com/spanner/docs
+
+[cloud-translation]: https://cloud.google.com/translation
+[cloud-translation-ref]: https://godoc.org/cloud.google.com/go/translation
+
+[cloud-video]: https://cloud.google.com/video-intelligence/
+[cloud-video-ref]: https://godoc.org/cloud.google.com/go/videointelligence/apiv1beta1
+
+[cloud-errors]: https://cloud.google.com/error-reporting/
+[cloud-errors-ref]: https://godoc.org/cloud.google.com/go/errorreporting
+
+[cloud-container]: https://cloud.google.com/containers/
+[cloud-container-ref]: https://godoc.org/cloud.google.com/go/container/apiv1
+
+[cloud-debugger]: https://cloud.google.com/debugger/
+[cloud-debugger-ref]: https://godoc.org/cloud.google.com/go/debugger/apiv2
+
+[cloud-dlp]: https://cloud.google.com/dlp/
+[cloud-dlp-ref]: https://godoc.org/cloud.google.com/go/dlp/apiv2beta1
+
+[default-creds]: https://developers.google.com/identity/protocols/application-default-credentials
diff --git a/vendor/cloud.google.com/go/appveyor.yml b/vendor/cloud.google.com/go/appveyor.yml
new file mode 100644
index 00000000000..e66cd00af4f
--- /dev/null
+++ b/vendor/cloud.google.com/go/appveyor.yml
@@ -0,0 +1,32 @@
+# This file configures AppVeyor (http://www.appveyor.com),
+# a Windows-based CI service similar to Travis.
+
+# Identifier for this run
+version: "{build}"
+
+# Clone the repo into this path, which conforms to the standard
+# Go workspace structure.
+clone_folder: c:\gopath\src\cloud.google.com\go
+
+environment:
+ GOPATH: c:\gopath
+ GCLOUD_TESTS_GOLANG_PROJECT_ID: dulcet-port-762
+ GCLOUD_TESTS_GOLANG_KEY: c:\gopath\src\cloud.google.com\go\key.json
+ KEYFILE_CONTENTS:
+ secure: IvRbDAhM2PIQqzVkjzJ4FjizUvoQ+c3vG/qhJQG+HlZ/L5KEkqLu+x6WjLrExrNMyGku4znB2jmbTrUW3Ob4sGG+R5vvqeQ3YMHCVIkw5CxY+/bUDkW5RZWsVbuCnNa/vKsWmCP+/sZW6ICe29yKJ2ZOb6QaauI4s9R6j+cqBbU9pumMGYFRb0Rw3uUU7DKmVFCy+NjTENZIlDP9rmjANgAzigowJJEb2Tg9sLlQKmQeKiBSRN8lKc5Nq60a+fIzHGKvql4eIitDDDpOpyHv15/Xr1BzFw2yDoiR4X1lng0u7q0X9RgX4VIYa6gT16NXBEmQgbuX8gh7SfPMp9RhiZD9sVUaV+yogEabYpyPnmUURo0hXwkctKaBkQlEmKvjHwF5dvbg8+yqGhwtjAgFNimXG3INrwQsfQsZskkQWanutbJf9xy50GyWWFZZdi0uT4oXP/b5P7aklPXKXsvrJKBh7RjEaqBrhi86IJwOjBspvoR4l2WmcQyxb2xzQS1pjbBJFQfYJJ8+JgsstTL8PBO9d4ybJC0li1Om1qnWxkaewvPxxuoHJ9LpRKof19yRYWBmhTXb2tTASKG/zslvl4fgG4DmQBS93WC7dsiGOhAraGw2eCTgd0lYZOhk1FjWl9TS80aktXxzH/7nTvem5ohm+eDl6O0wnTL4KXjQVNSQ1PyLn4lGRJ5MNGzBTRFWIr2API2rca4Fysyfh/UdmazPGlNbY9JPGqb9+F04QzLfqm+Zz/cHy59E7lOSMBlUI4KD6d6ZNNKNRH+/g9i+fSiyiXKugTfda8KBnWGyPwprxuWGYaiQUGUYOwJY5R6x5c4mjImAB310V+Wo33UbWFJiwxEDsiCNqW1meVkBzt2er26vh4qbgCUIQ3iM3gFPfHgy+QxkmIhic7Q1HYacQElt8AAP41M7cCKWCuZidegP37MBB//mjjiNt047ZSQEvB4tqsX/OvfbByVef+cbtVw9T0yjHvmCdPW1XrhyrCCgclu6oYYdbmc5D7BBDRbjjMWGv6YvceAbfGf6ukdB5PuV+TGEN/FoQ1QTRA6Aqf+3fLMg4mS4oyTfw5xyYNbv3qoyLPrp+BnxI53WB9p0hfMg4n9FD6NntBxjDq+Q3Lk/bjC/Y4MaRWdzbMzF9a0lgGfcw9DURlK5p7uGJC9vg34feNoQprxVEZRQ01cHLeob6eGkYm4HxSRx8JY39Mh+9wzJo+k/aIvFleNC3e35NOrkXr6wb5e42n2DwBdPqdNolTLtLFRglAL1LTpp27UjvjieWJAKfoDTR5CKl01sZqt0wPdLLcvsMj6CiPFmccUIOYeZMe86kLBD61Qa5F1EwkgO3Om2qSjW96FzL4skRc+BmU5RrHlAFSldR1wpUgtkUMv9vH5Cy+UJdcvpZ8KbmhZ2PsjF7ddJ1ve9RAw3cP325AyIMwZ77Ef1mgTM0NJze6eSW1qKlEsgt1FADPyeUu1NQTA2H2dueMPGlArWTSUgyWR9AdfpqouT7eg0JWI5w+yUZZC+/rPglYbt84oLmYpwuli0z8FyEQRPIc3EtkfWIv/yYgDr2TZ0N2KvGfpi/MAUWgxI1gleC2uKgEOEtuJthd3XZjF2NoE7IBqjQOINybcJOjyeB5vRLDY1FLuxYzdg1y1etkV4XQig/vje
+
+install:
+ # Info for debugging.
+ - echo %PATH%
+ - go version
+ - go env
+ - go get -v -d -t ./...
+
+
+# Provide a build script, or AppVeyor will call msbuild.
+build_script:
+ - go install -v ./...
+ - echo %KEYFILE_CONTENTS% > %GCLOUD_TESTS_GOLANG_KEY%
+
+test_script:
+ - go test -v ./...
diff --git a/vendor/cloud.google.com/go/authexample_test.go b/vendor/cloud.google.com/go/authexample_test.go
new file mode 100644
index 00000000000..fe75467f94c
--- /dev/null
+++ b/vendor/cloud.google.com/go/authexample_test.go
@@ -0,0 +1,49 @@
+// Copyright 2016 Google 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 cloud_test
+
+import (
+ "cloud.google.com/go/datastore"
+ "golang.org/x/net/context"
+ "google.golang.org/api/option"
+)
+
+func Example_applicationDefaultCredentials() {
+ // Google Application Default Credentials is the recommended way to authorize
+ // and authenticate clients.
+ //
+ // See the following link on how to create and obtain Application Default Credentials:
+ // https://developers.google.com/identity/protocols/application-default-credentials.
+ client, err := datastore.NewClient(context.Background(), "project-id")
+ if err != nil {
+ // TODO: handle error.
+ }
+ _ = client // Use the client.
+}
+
+func Example_serviceAccountFile() {
+ // Use a JSON key file associated with a Google service account to
+ // authenticate and authorize. Service Account keys can be created and
+ // downloaded from https://console.developers.google.com/permissions/serviceaccounts.
+ //
+ // Note: This example uses the datastore client, but the same steps apply to
+ // the other client libraries underneath this package.
+ client, err := datastore.NewClient(context.Background(),
+ "project-id", option.WithServiceAccountFile("/path/to/service-account-key.json"))
+ if err != nil {
+ // TODO: handle error.
+ }
+ _ = client // Use the client.
+}
diff --git a/vendor/cloud.google.com/go/cloud.go b/vendor/cloud.google.com/go/cloud.go
new file mode 100644
index 00000000000..0be0df33f98
--- /dev/null
+++ b/vendor/cloud.google.com/go/cloud.go
@@ -0,0 +1,40 @@
+// Copyright 2014 Google 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 cloud is the root of the packages used to access Google Cloud
+Services. See https://godoc.org/cloud.google.com/go for a full list
+of sub-packages.
+
+Examples in this package show ways to authorize and authenticate the
+sub packages.
+
+Connection Pooling
+
+Connection pooling differs in clients based on their transport. Cloud
+clients either rely on HTTP or gRPC transports to communicate
+with Google Cloud.
+
+Cloud clients that use HTTP (bigquery, compute, storage, and translate) rely on the
+underlying HTTP transport to cache connections for later re-use. These are cached to
+the default http.MaxIdleConns and http.MaxIdleConnsPerHost settings in
+http.DefaultTransport.
+
+For gPRC clients (all others in this repo), connection pooling is configurable. Users
+of cloud client libraries may specify option.WithGRPCConnectionPool(n) as a client
+option to NewClient calls. This configures the underlying gRPC connections to be
+pooled and addressed in a round robin fashion.
+
+*/
+package cloud // import "cloud.google.com/go"
diff --git a/vendor/cloud.google.com/go/compute/metadata/BUILD.bazel b/vendor/cloud.google.com/go/compute/metadata/BUILD.bazel
new file mode 100644
index 00000000000..43a697677bb
--- /dev/null
+++ b/vendor/cloud.google.com/go/compute/metadata/BUILD.bazel
@@ -0,0 +1,19 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
+
+go_library(
+ name = "go_default_library",
+ srcs = ["metadata.go"],
+ importpath = "cloud.google.com/go/compute/metadata",
+ visibility = ["//visibility:public"],
+ deps = [
+ "//vendor/golang.org/x/net/context:go_default_library",
+ "//vendor/golang.org/x/net/context/ctxhttp:go_default_library",
+ ],
+)
+
+go_test(
+ name = "go_default_test",
+ srcs = ["metadata_test.go"],
+ embed = [":go_default_library"],
+ importpath = "cloud.google.com/go/compute/metadata",
+)
diff --git a/vendor/cloud.google.com/go/compute/metadata/metadata.go b/vendor/cloud.google.com/go/compute/metadata/metadata.go
new file mode 100644
index 00000000000..e708c031b95
--- /dev/null
+++ b/vendor/cloud.google.com/go/compute/metadata/metadata.go
@@ -0,0 +1,437 @@
+// Copyright 2014 Google 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 metadata provides access to Google Compute Engine (GCE)
+// metadata and API service accounts.
+//
+// This package is a wrapper around the GCE metadata service,
+// as documented at https://developers.google.com/compute/docs/metadata.
+package metadata // import "cloud.google.com/go/compute/metadata"
+
+import (
+ "encoding/json"
+ "fmt"
+ "io/ioutil"
+ "net"
+ "net/http"
+ "net/url"
+ "os"
+ "runtime"
+ "strings"
+ "sync"
+ "time"
+
+ "golang.org/x/net/context"
+ "golang.org/x/net/context/ctxhttp"
+)
+
+const (
+ // metadataIP is the documented metadata server IP address.
+ metadataIP = "169.254.169.254"
+
+ // metadataHostEnv is the environment variable specifying the
+ // GCE metadata hostname. If empty, the default value of
+ // metadataIP ("169.254.169.254") is used instead.
+ // This is variable name is not defined by any spec, as far as
+ // I know; it was made up for the Go package.
+ metadataHostEnv = "GCE_METADATA_HOST"
+
+ userAgent = "gcloud-golang/0.1"
+)
+
+type cachedValue struct {
+ k string
+ trim bool
+ mu sync.Mutex
+ v string
+}
+
+var (
+ projID = &cachedValue{k: "project/project-id", trim: true}
+ projNum = &cachedValue{k: "project/numeric-project-id", trim: true}
+ instID = &cachedValue{k: "instance/id", trim: true}
+)
+
+var (
+ metaClient = &http.Client{
+ Transport: &http.Transport{
+ Dial: (&net.Dialer{
+ Timeout: 2 * time.Second,
+ KeepAlive: 30 * time.Second,
+ }).Dial,
+ ResponseHeaderTimeout: 2 * time.Second,
+ },
+ }
+ subscribeClient = &http.Client{
+ Transport: &http.Transport{
+ Dial: (&net.Dialer{
+ Timeout: 2 * time.Second,
+ KeepAlive: 30 * time.Second,
+ }).Dial,
+ },
+ }
+)
+
+// NotDefinedError is returned when requested metadata is not defined.
+//
+// The underlying string is the suffix after "/computeMetadata/v1/".
+//
+// This error is not returned if the value is defined to be the empty
+// string.
+type NotDefinedError string
+
+func (suffix NotDefinedError) Error() string {
+ return fmt.Sprintf("metadata: GCE metadata %q not defined", string(suffix))
+}
+
+// Get returns a value from the metadata service.
+// The suffix is appended to "http://${GCE_METADATA_HOST}/computeMetadata/v1/".
+//
+// If the GCE_METADATA_HOST environment variable is not defined, a default of
+// 169.254.169.254 will be used instead.
+//
+// If the requested metadata is not defined, the returned error will
+// be of type NotDefinedError.
+func Get(suffix string) (string, error) {
+ val, _, err := getETag(metaClient, suffix)
+ return val, err
+}
+
+// getETag returns a value from the metadata service as well as the associated
+// ETag using the provided client. This func is otherwise equivalent to Get.
+func getETag(client *http.Client, suffix string) (value, etag string, err error) {
+ // Using a fixed IP makes it very difficult to spoof the metadata service in
+ // a container, which is an important use-case for local testing of cloud
+ // deployments. To enable spoofing of the metadata service, the environment
+ // variable GCE_METADATA_HOST is first inspected to decide where metadata
+ // requests shall go.
+ host := os.Getenv(metadataHostEnv)
+ if host == "" {
+ // Using 169.254.169.254 instead of "metadata" here because Go
+ // binaries built with the "netgo" tag and without cgo won't
+ // know the search suffix for "metadata" is
+ // ".google.internal", and this IP address is documented as
+ // being stable anyway.
+ host = metadataIP
+ }
+ url := "http://" + host + "/computeMetadata/v1/" + suffix
+ req, _ := http.NewRequest("GET", url, nil)
+ req.Header.Set("Metadata-Flavor", "Google")
+ req.Header.Set("User-Agent", userAgent)
+ res, err := client.Do(req)
+ if err != nil {
+ return "", "", err
+ }
+ defer res.Body.Close()
+ if res.StatusCode == http.StatusNotFound {
+ return "", "", NotDefinedError(suffix)
+ }
+ if res.StatusCode != 200 {
+ return "", "", fmt.Errorf("status code %d trying to fetch %s", res.StatusCode, url)
+ }
+ all, err := ioutil.ReadAll(res.Body)
+ if err != nil {
+ return "", "", err
+ }
+ return string(all), res.Header.Get("Etag"), nil
+}
+
+func getTrimmed(suffix string) (s string, err error) {
+ s, err = Get(suffix)
+ s = strings.TrimSpace(s)
+ return
+}
+
+func (c *cachedValue) get() (v string, err error) {
+ defer c.mu.Unlock()
+ c.mu.Lock()
+ if c.v != "" {
+ return c.v, nil
+ }
+ if c.trim {
+ v, err = getTrimmed(c.k)
+ } else {
+ v, err = Get(c.k)
+ }
+ if err == nil {
+ c.v = v
+ }
+ return
+}
+
+var (
+ onGCEOnce sync.Once
+ onGCE bool
+)
+
+// OnGCE reports whether this process is running on Google Compute Engine.
+func OnGCE() bool {
+ onGCEOnce.Do(initOnGCE)
+ return onGCE
+}
+
+func initOnGCE() {
+ onGCE = testOnGCE()
+}
+
+func testOnGCE() bool {
+ // The user explicitly said they're on GCE, so trust them.
+ if os.Getenv(metadataHostEnv) != "" {
+ return true
+ }
+
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+
+ resc := make(chan bool, 2)
+
+ // Try two strategies in parallel.
+ // See https://github.com/GoogleCloudPlatform/google-cloud-go/issues/194
+ go func() {
+ req, _ := http.NewRequest("GET", "http://"+metadataIP, nil)
+ req.Header.Set("User-Agent", userAgent)
+ res, err := ctxhttp.Do(ctx, metaClient, req)
+ if err != nil {
+ resc <- false
+ return
+ }
+ defer res.Body.Close()
+ resc <- res.Header.Get("Metadata-Flavor") == "Google"
+ }()
+
+ go func() {
+ addrs, err := net.LookupHost("metadata.google.internal")
+ if err != nil || len(addrs) == 0 {
+ resc <- false
+ return
+ }
+ resc <- strsContains(addrs, metadataIP)
+ }()
+
+ tryHarder := systemInfoSuggestsGCE()
+ if tryHarder {
+ res := <-resc
+ if res {
+ // The first strategy succeeded, so let's use it.
+ return true
+ }
+ // Wait for either the DNS or metadata server probe to
+ // contradict the other one and say we are running on
+ // GCE. Give it a lot of time to do so, since the system
+ // info already suggests we're running on a GCE BIOS.
+ timer := time.NewTimer(5 * time.Second)
+ defer timer.Stop()
+ select {
+ case res = <-resc:
+ return res
+ case <-timer.C:
+ // Too slow. Who knows what this system is.
+ return false
+ }
+ }
+
+ // There's no hint from the system info that we're running on
+ // GCE, so use the first probe's result as truth, whether it's
+ // true or false. The goal here is to optimize for speed for
+ // users who are NOT running on GCE. We can't assume that
+ // either a DNS lookup or an HTTP request to a blackholed IP
+ // address is fast. Worst case this should return when the
+ // metaClient's Transport.ResponseHeaderTimeout or
+ // Transport.Dial.Timeout fires (in two seconds).
+ return <-resc
+}
+
+// systemInfoSuggestsGCE reports whether the local system (without
+// doing network requests) suggests that we're running on GCE. If this
+// returns true, testOnGCE tries a bit harder to reach its metadata
+// server.
+func systemInfoSuggestsGCE() bool {
+ if runtime.GOOS != "linux" {
+ // We don't have any non-Linux clues available, at least yet.
+ return false
+ }
+ slurp, _ := ioutil.ReadFile("/sys/class/dmi/id/product_name")
+ name := strings.TrimSpace(string(slurp))
+ return name == "Google" || name == "Google Compute Engine"
+}
+
+// Subscribe subscribes to a value from the metadata service.
+// The suffix is appended to "http://${GCE_METADATA_HOST}/computeMetadata/v1/".
+// The suffix may contain query parameters.
+//
+// Subscribe calls fn with the latest metadata value indicated by the provided
+// suffix. If the metadata value is deleted, fn is called with the empty string
+// and ok false. Subscribe blocks until fn returns a non-nil error or the value
+// is deleted. Subscribe returns the error value returned from the last call to
+// fn, which may be nil when ok == false.
+func Subscribe(suffix string, fn func(v string, ok bool) error) error {
+ const failedSubscribeSleep = time.Second * 5
+
+ // First check to see if the metadata value exists at all.
+ val, lastETag, err := getETag(subscribeClient, suffix)
+ if err != nil {
+ return err
+ }
+
+ if err := fn(val, true); err != nil {
+ return err
+ }
+
+ ok := true
+ if strings.ContainsRune(suffix, '?') {
+ suffix += "&wait_for_change=true&last_etag="
+ } else {
+ suffix += "?wait_for_change=true&last_etag="
+ }
+ for {
+ val, etag, err := getETag(subscribeClient, suffix+url.QueryEscape(lastETag))
+ if err != nil {
+ if _, deleted := err.(NotDefinedError); !deleted {
+ time.Sleep(failedSubscribeSleep)
+ continue // Retry on other errors.
+ }
+ ok = false
+ }
+ lastETag = etag
+
+ if err := fn(val, ok); err != nil || !ok {
+ return err
+ }
+ }
+}
+
+// ProjectID returns the current instance's project ID string.
+func ProjectID() (string, error) { return projID.get() }
+
+// NumericProjectID returns the current instance's numeric project ID.
+func NumericProjectID() (string, error) { return projNum.get() }
+
+// InternalIP returns the instance's primary internal IP address.
+func InternalIP() (string, error) {
+ return getTrimmed("instance/network-interfaces/0/ip")
+}
+
+// ExternalIP returns the instance's primary external (public) IP address.
+func ExternalIP() (string, error) {
+ return getTrimmed("instance/network-interfaces/0/access-configs/0/external-ip")
+}
+
+// Hostname returns the instance's hostname. This will be of the form
+// ".c..internal".
+func Hostname() (string, error) {
+ return getTrimmed("instance/hostname")
+}
+
+// InstanceTags returns the list of user-defined instance tags,
+// assigned when initially creating a GCE instance.
+func InstanceTags() ([]string, error) {
+ var s []string
+ j, err := Get("instance/tags")
+ if err != nil {
+ return nil, err
+ }
+ if err := json.NewDecoder(strings.NewReader(j)).Decode(&s); err != nil {
+ return nil, err
+ }
+ return s, nil
+}
+
+// InstanceID returns the current VM's numeric instance ID.
+func InstanceID() (string, error) {
+ return instID.get()
+}
+
+// InstanceName returns the current VM's instance ID string.
+func InstanceName() (string, error) {
+ host, err := Hostname()
+ if err != nil {
+ return "", err
+ }
+ return strings.Split(host, ".")[0], nil
+}
+
+// Zone returns the current VM's zone, such as "us-central1-b".
+func Zone() (string, error) {
+ zone, err := getTrimmed("instance/zone")
+ // zone is of the form "projects//zones/".
+ if err != nil {
+ return "", err
+ }
+ return zone[strings.LastIndex(zone, "/")+1:], nil
+}
+
+// InstanceAttributes returns the list of user-defined attributes,
+// assigned when initially creating a GCE VM instance. The value of an
+// attribute can be obtained with InstanceAttributeValue.
+func InstanceAttributes() ([]string, error) { return lines("instance/attributes/") }
+
+// ProjectAttributes returns the list of user-defined attributes
+// applying to the project as a whole, not just this VM. The value of
+// an attribute can be obtained with ProjectAttributeValue.
+func ProjectAttributes() ([]string, error) { return lines("project/attributes/") }
+
+func lines(suffix string) ([]string, error) {
+ j, err := Get(suffix)
+ if err != nil {
+ return nil, err
+ }
+ s := strings.Split(strings.TrimSpace(j), "\n")
+ for i := range s {
+ s[i] = strings.TrimSpace(s[i])
+ }
+ return s, nil
+}
+
+// InstanceAttributeValue returns the value of the provided VM
+// instance attribute.
+//
+// If the requested attribute is not defined, the returned error will
+// be of type NotDefinedError.
+//
+// InstanceAttributeValue may return ("", nil) if the attribute was
+// defined to be the empty string.
+func InstanceAttributeValue(attr string) (string, error) {
+ return Get("instance/attributes/" + attr)
+}
+
+// ProjectAttributeValue returns the value of the provided
+// project attribute.
+//
+// If the requested attribute is not defined, the returned error will
+// be of type NotDefinedError.
+//
+// ProjectAttributeValue may return ("", nil) if the attribute was
+// defined to be the empty string.
+func ProjectAttributeValue(attr string) (string, error) {
+ return Get("project/attributes/" + attr)
+}
+
+// Scopes returns the service account scopes for the given account.
+// The account may be empty or the string "default" to use the instance's
+// main account.
+func Scopes(serviceAccount string) ([]string, error) {
+ if serviceAccount == "" {
+ serviceAccount = "default"
+ }
+ return lines("instance/service-accounts/" + serviceAccount + "/scopes")
+}
+
+func strsContains(ss []string, s string) bool {
+ for _, v := range ss {
+ if v == s {
+ return true
+ }
+ }
+ return false
+}
diff --git a/vendor/cloud.google.com/go/compute/metadata/metadata_test.go b/vendor/cloud.google.com/go/compute/metadata/metadata_test.go
new file mode 100644
index 00000000000..9ac59269181
--- /dev/null
+++ b/vendor/cloud.google.com/go/compute/metadata/metadata_test.go
@@ -0,0 +1,48 @@
+// Copyright 2016 Google 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 metadata
+
+import (
+ "os"
+ "sync"
+ "testing"
+)
+
+func TestOnGCE_Stress(t *testing.T) {
+ if testing.Short() {
+ t.Skip("skipping in -short mode")
+ }
+ var last bool
+ for i := 0; i < 100; i++ {
+ onGCEOnce = sync.Once{}
+
+ now := OnGCE()
+ if i > 0 && now != last {
+ t.Errorf("%d. changed from %v to %v", i, last, now)
+ }
+ last = now
+ }
+ t.Logf("OnGCE() = %v", last)
+}
+
+func TestOnGCE_Force(t *testing.T) {
+ onGCEOnce = sync.Once{}
+ old := os.Getenv(metadataHostEnv)
+ defer os.Setenv(metadataHostEnv, old)
+ os.Setenv(metadataHostEnv, "127.0.0.1")
+ if !OnGCE() {
+ t.Error("OnGCE() = false; want true")
+ }
+}
diff --git a/vendor/cloud.google.com/go/import_test.go b/vendor/cloud.google.com/go/import_test.go
new file mode 100644
index 00000000000..839fae45fac
--- /dev/null
+++ b/vendor/cloud.google.com/go/import_test.go
@@ -0,0 +1,61 @@
+// Copyright 2017 Google 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 cloud
+
+import (
+ "go/parser"
+ "go/token"
+ "os"
+ "path/filepath"
+ "strconv"
+ "testing"
+)
+
+func TestContextImport(t *testing.T) {
+ t.Parallel()
+
+ whiteList := map[string]bool{
+ "storage/go17.go": true,
+ }
+
+ err := filepath.Walk(".", func(path string, fi os.FileInfo, err error) error {
+ if err != nil {
+ return err
+ }
+ if filepath.Ext(path) != ".go" || whiteList[path] {
+ return nil
+ }
+
+ fset := token.NewFileSet()
+ file, err := parser.ParseFile(fset, path, nil, parser.ImportsOnly)
+ if err != nil {
+ return err
+ }
+
+ for _, imp := range file.Imports {
+ impPath, err := strconv.Unquote(imp.Path.Value)
+ if err != nil {
+ return err
+ }
+ if impPath == "context" {
+ t.Errorf(`file %q import "context", want "golang.org/x/net/context"`, path)
+ }
+ }
+ return nil
+ })
+ if err != nil {
+ t.Fatal(err)
+ }
+}
diff --git a/vendor/cloud.google.com/go/keys.tar.enc b/vendor/cloud.google.com/go/keys.tar.enc
new file mode 100644
index 00000000000..c54408c93a2
Binary files /dev/null and b/vendor/cloud.google.com/go/keys.tar.enc differ
diff --git a/vendor/cloud.google.com/go/license_test.go b/vendor/cloud.google.com/go/license_test.go
new file mode 100644
index 00000000000..f93e9e00564
--- /dev/null
+++ b/vendor/cloud.google.com/go/license_test.go
@@ -0,0 +1,71 @@
+// Copyright 2016 Google 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 cloud
+
+import (
+ "bytes"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "strings"
+ "testing"
+)
+
+var sentinels = []string{
+ "Copyright",
+ "Google",
+ `Licensed under the Apache License, Version 2.0 (the "License");`,
+}
+
+func TestLicense(t *testing.T) {
+ t.Parallel()
+ err := filepath.Walk(".", func(path string, fi os.FileInfo, err error) error {
+ if err != nil {
+ return err
+ }
+
+ if ext := filepath.Ext(path); ext != ".go" && ext != ".proto" {
+ return nil
+ }
+ if strings.HasSuffix(path, ".pb.go") {
+ // .pb.go files are generated from the proto files.
+ // .proto files must have license headers.
+ return nil
+ }
+ if path == "bigtable/cmd/cbt/cbtdoc.go" {
+ // Automatically generated.
+ return nil
+ }
+
+ src, err := ioutil.ReadFile(path)
+ if err != nil {
+ return nil
+ }
+ src = src[:140] // Ensure all of the sentinel values are at the top of the file.
+
+ // Find license
+ for _, sentinel := range sentinels {
+ if !bytes.Contains(src, []byte(sentinel)) {
+ t.Errorf("%v: license header not present. want %q", path, sentinel)
+ return nil
+ }
+ }
+
+ return nil
+ })
+ if err != nil {
+ t.Fatal(err)
+ }
+}
diff --git a/vendor/cloud.google.com/go/old-news.md b/vendor/cloud.google.com/go/old-news.md
new file mode 100644
index 00000000000..a0bd83be933
--- /dev/null
+++ b/vendor/cloud.google.com/go/old-news.md
@@ -0,0 +1,596 @@
+_October 30, 2017_
+
+*v0.16.0*
+
+- Other bigquery changes:
+ - `JobIterator.Next` returns `*Job`; removed `JobInfo` (BREAKING CHANGE).
+ - UseStandardSQL is deprecated; set UseLegacySQL to true if you need
+ Legacy SQL.
+ - Uploader.Put will generate a random insert ID if you do not provide one.
+ - Support time partitioning for load jobs.
+ - Support dry-run queries.
+ - A `Job` remembers its last retrieved status.
+ - Support retrieving job configuration.
+ - Support labels for jobs and tables.
+ - Support dataset access lists.
+ - Improve support for external data sources, including data from Bigtable and
+ Google Sheets, and tables with external data.
+ - Support updating a table's view configuration.
+ - Fix uploading civil times with nanoseconds.
+
+- storage:
+ - Support PubSub notifications.
+ - Support Requester Pays buckets.
+
+- profiler: Support goroutine and mutex profile types.
+
+
+_October 3, 2017_
+
+*v0.15.0*
+
+- firestore: beta release. See the
+ [announcement](https://firebase.googleblog.com/2017/10/introducing-cloud-firestore.html).
+
+- errorreporting: The existing package has been redesigned.
+
+- errors: This package has been removed. Use errorreporting.
+
+
+_September 28, 2017_
+
+*v0.14.0*
+
+- bigquery BREAKING CHANGES:
+ - Standard SQL is the default for queries and views.
+ - `Table.Create` takes `TableMetadata` as a second argument, instead of
+ options.
+ - `Dataset.Create` takes `DatasetMetadata` as a second argument.
+ - `DatasetMetadata` field `ID` renamed to `FullID`
+ - `TableMetadata` field `ID` renamed to `FullID`
+
+- Other bigquery changes:
+ - The client will append a random suffix to a provided job ID if you set
+ `AddJobIDSuffix` to true in a job config.
+ - Listing jobs is supported.
+ - Better retry logic.
+
+- vision, language, speech: clients are now stable
+
+- monitoring: client is now beta
+
+- profiler:
+ - Rename InstanceName to Instance, ZoneName to Zone
+ - Auto-detect service name and version on AppEngine.
+
+_September 8, 2017_
+
+*v0.13.0*
+
+- bigquery: UseLegacySQL options for CreateTable and QueryConfig. Use these
+ options to continue using Legacy SQL after the client switches its default
+ to Standard SQL.
+
+- bigquery: Support for updating dataset labels.
+
+- bigquery: Set DatasetIterator.ProjectID to list datasets in a project other
+ than the client's. DatasetsInProject is no longer needed and is deprecated.
+
+- bigtable: Fail ListInstances when any zones fail.
+
+- spanner: support decoding of slices of basic types (e.g. []string, []int64,
+ etc.)
+
+- logging/logadmin: UpdateSink no longer creates a sink if it is missing
+ (actually a change to the underlying service, not the client)
+
+- profiler: Service and ServiceVersion replace Target in Config.
+
+_August 22, 2017_
+
+*v0.12.0*
+
+- pubsub: Subscription.Receive now uses streaming pull.
+
+- pubsub: add Client.TopicInProject to access topics in a different project
+ than the client.
+
+- errors: renamed errorreporting. The errors package will be removed shortly.
+
+- datastore: improved retry behavior.
+
+- bigquery: support updates to dataset metadata, with etags.
+
+- bigquery: add etag support to Table.Update (BREAKING: etag argument added).
+
+- bigquery: generate all job IDs on the client.
+
+- storage: support bucket lifecycle configurations.
+
+
+_July 31, 2017_
+
+*v0.11.0*
+
+- Clients for spanner, pubsub and video are now in beta.
+
+- New client for DLP.
+
+- spanner: performance and testing improvements.
+
+- storage: requester-pays buckets are supported.
+
+- storage, profiler, bigtable, bigquery: bug fixes and other minor improvements.
+
+- pubsub: bug fixes and other minor improvements
+
+_June 17, 2017_
+
+
+*v0.10.0*
+
+- pubsub: Subscription.ModifyPushConfig replaced with Subscription.Update.
+
+- pubsub: Subscription.Receive now runs concurrently for higher throughput.
+
+- vision: cloud.google.com/go/vision is deprecated. Use
+cloud.google.com/go/vision/apiv1 instead.
+
+- translation: now stable.
+
+- trace: several changes to the surface. See the link below.
+
+[Code changes required from v0.9.0.](https://github.com/GoogleCloudPlatform/google-cloud-go/blob/master/MIGRATION.md)
+
+
+_March 17, 2017_
+
+Breaking Pubsub changes.
+* Publish is now asynchronous
+([announcement](https://groups.google.com/d/topic/google-api-go-announce/aaqRDIQ3rvU/discussion)).
+* Subscription.Pull replaced by Subscription.Receive, which takes a callback ([announcement](https://groups.google.com/d/topic/google-api-go-announce/8pt6oetAdKc/discussion)).
+* Message.Done replaced with Message.Ack and Message.Nack.
+
+_February 14, 2017_
+
+Release of a client library for Spanner. See
+the
+[blog post](https://cloudplatform.googleblog.com/2017/02/introducing-Cloud-Spanner-a-global-database-service-for-mission-critical-applications.html).
+
+Note that although the Spanner service is beta, the Go client library is alpha.
+
+_December 12, 2016_
+
+Beta release of BigQuery, DataStore, Logging and Storage. See the
+[blog post](https://cloudplatform.googleblog.com/2016/12/announcing-new-google-cloud-client.html).
+
+Also, BigQuery now supports structs. Read a row directly into a struct with
+`RowIterator.Next`, and upload a row directly from a struct with `Uploader.Put`.
+You can also use field tags. See the [package documentation][cloud-bigquery-ref]
+for details.
+
+_December 5, 2016_
+
+More changes to BigQuery:
+
+* The `ValueList` type was removed. It is no longer necessary. Instead of
+ ```go
+ var v ValueList
+ ... it.Next(&v) ..
+ ```
+ use
+
+ ```go
+ var v []Value
+ ... it.Next(&v) ...
+ ```
+
+* Previously, repeatedly calling `RowIterator.Next` on the same `[]Value` or
+ `ValueList` would append to the slice. Now each call resets the size to zero first.
+
+* Schema inference will infer the SQL type BYTES for a struct field of
+ type []byte. Previously it inferred STRING.
+
+* The types `uint`, `uint64` and `uintptr` are no longer supported in schema
+ inference. BigQuery's integer type is INT64, and those types may hold values
+ that are not correctly represented in a 64-bit signed integer.
+
+* The SQL types DATE, TIME and DATETIME are now supported. They correspond to
+ the `Date`, `Time` and `DateTime` types in the new `cloud.google.com/go/civil`
+ package.
+
+_November 17, 2016_
+
+Change to BigQuery: values from INTEGER columns will now be returned as int64,
+not int. This will avoid errors arising from large values on 32-bit systems.
+
+_November 8, 2016_
+
+New datastore feature: datastore now encodes your nested Go structs as Entity values,
+instead of a flattened list of the embedded struct's fields.
+This means that you may now have twice-nested slices, eg.
+```go
+type State struct {
+ Cities []struct{
+ Populations []int
+ }
+}
+```
+
+See [the announcement](https://groups.google.com/forum/#!topic/google-api-go-announce/79jtrdeuJAg) for
+more details.
+
+_November 8, 2016_
+
+Breaking changes to datastore: contexts no longer hold namespaces; instead you
+must set a key's namespace explicitly. Also, key functions have been changed
+and renamed.
+
+* The WithNamespace function has been removed. To specify a namespace in a Query, use the Query.Namespace method:
+ ```go
+ q := datastore.NewQuery("Kind").Namespace("ns")
+ ```
+
+* All the fields of Key are exported. That means you can construct any Key with a struct literal:
+ ```go
+ k := &Key{Kind: "Kind", ID: 37, Namespace: "ns"}
+ ```
+
+* As a result of the above, the Key methods Kind, ID, d.Name, Parent, SetParent and Namespace have been removed.
+
+* `NewIncompleteKey` has been removed, replaced by `IncompleteKey`. Replace
+ ```go
+ NewIncompleteKey(ctx, kind, parent)
+ ```
+ with
+ ```go
+ IncompleteKey(kind, parent)
+ ```
+ and if you do use namespaces, make sure you set the namespace on the returned key.
+
+* `NewKey` has been removed, replaced by `NameKey` and `IDKey`. Replace
+ ```go
+ NewKey(ctx, kind, name, 0, parent)
+ NewKey(ctx, kind, "", id, parent)
+ ```
+ with
+ ```go
+ NameKey(kind, name, parent)
+ IDKey(kind, id, parent)
+ ```
+ and if you do use namespaces, make sure you set the namespace on the returned key.
+
+* The `Done` variable has been removed. Replace `datastore.Done` with `iterator.Done`, from the package `google.golang.org/api/iterator`.
+
+* The `Client.Close` method will have a return type of error. It will return the result of closing the underlying gRPC connection.
+
+See [the announcement](https://groups.google.com/forum/#!topic/google-api-go-announce/hqXtM_4Ix-0) for
+more details.
+
+_October 27, 2016_
+
+Breaking change to bigquery: `NewGCSReference` is now a function,
+not a method on `Client`.
+
+New bigquery feature: `Table.LoaderFrom` now accepts a `ReaderSource`, enabling
+loading data into a table from a file or any `io.Reader`.
+
+_October 21, 2016_
+
+Breaking change to pubsub: removed `pubsub.Done`.
+
+Use `iterator.Done` instead, where `iterator` is the package
+`google.golang.org/api/iterator`.
+
+_October 19, 2016_
+
+Breaking changes to cloud.google.com/go/bigquery:
+
+* Client.Table and Client.OpenTable have been removed.
+ Replace
+ ```go
+ client.OpenTable("project", "dataset", "table")
+ ```
+ with
+ ```go
+ client.DatasetInProject("project", "dataset").Table("table")
+ ```
+
+* Client.CreateTable has been removed.
+ Replace
+ ```go
+ client.CreateTable(ctx, "project", "dataset", "table")
+ ```
+ with
+ ```go
+ client.DatasetInProject("project", "dataset").Table("table").Create(ctx)
+ ```
+
+* Dataset.ListTables have been replaced with Dataset.Tables.
+ Replace
+ ```go
+ tables, err := ds.ListTables(ctx)
+ ```
+ with
+ ```go
+ it := ds.Tables(ctx)
+ for {
+ table, err := it.Next()
+ if err == iterator.Done {
+ break
+ }
+ if err != nil {
+ // TODO: Handle error.
+ }
+ // TODO: use table.
+ }
+ ```
+
+* Client.Read has been replaced with Job.Read, Table.Read and Query.Read.
+ Replace
+ ```go
+ it, err := client.Read(ctx, job)
+ ```
+ with
+ ```go
+ it, err := job.Read(ctx)
+ ```
+ and similarly for reading from tables or queries.
+
+* The iterator returned from the Read methods is now named RowIterator. Its
+ behavior is closer to the other iterators in these libraries. It no longer
+ supports the Schema method; see the next item.
+ Replace
+ ```go
+ for it.Next(ctx) {
+ var vals ValueList
+ if err := it.Get(&vals); err != nil {
+ // TODO: Handle error.
+ }
+ // TODO: use vals.
+ }
+ if err := it.Err(); err != nil {
+ // TODO: Handle error.
+ }
+ ```
+ with
+ ```
+ for {
+ var vals ValueList
+ err := it.Next(&vals)
+ if err == iterator.Done {
+ break
+ }
+ if err != nil {
+ // TODO: Handle error.
+ }
+ // TODO: use vals.
+ }
+ ```
+ Instead of the `RecordsPerRequest(n)` option, write
+ ```go
+ it.PageInfo().MaxSize = n
+ ```
+ Instead of the `StartIndex(i)` option, write
+ ```go
+ it.StartIndex = i
+ ```
+
+* ValueLoader.Load now takes a Schema in addition to a slice of Values.
+ Replace
+ ```go
+ func (vl *myValueLoader) Load(v []bigquery.Value)
+ ```
+ with
+ ```go
+ func (vl *myValueLoader) Load(v []bigquery.Value, s bigquery.Schema)
+ ```
+
+
+* Table.Patch is replace by Table.Update.
+ Replace
+ ```go
+ p := table.Patch()
+ p.Description("new description")
+ metadata, err := p.Apply(ctx)
+ ```
+ with
+ ```go
+ metadata, err := table.Update(ctx, bigquery.TableMetadataToUpdate{
+ Description: "new description",
+ })
+ ```
+
+* Client.Copy is replaced by separate methods for each of its four functions.
+ All options have been replaced by struct fields.
+
+ * To load data from Google Cloud Storage into a table, use Table.LoaderFrom.
+
+ Replace
+ ```go
+ client.Copy(ctx, table, gcsRef)
+ ```
+ with
+ ```go
+ table.LoaderFrom(gcsRef).Run(ctx)
+ ```
+ Instead of passing options to Copy, set fields on the Loader:
+ ```go
+ loader := table.LoaderFrom(gcsRef)
+ loader.WriteDisposition = bigquery.WriteTruncate
+ ```
+
+ * To extract data from a table into Google Cloud Storage, use
+ Table.ExtractorTo. Set fields on the returned Extractor instead of
+ passing options.
+
+ Replace
+ ```go
+ client.Copy(ctx, gcsRef, table)
+ ```
+ with
+ ```go
+ table.ExtractorTo(gcsRef).Run(ctx)
+ ```
+
+ * To copy data into a table from one or more other tables, use
+ Table.CopierFrom. Set fields on the returned Copier instead of passing options.
+
+ Replace
+ ```go
+ client.Copy(ctx, dstTable, srcTable)
+ ```
+ with
+ ```go
+ dst.Table.CopierFrom(srcTable).Run(ctx)
+ ```
+
+ * To start a query job, create a Query and call its Run method. Set fields
+ on the query instead of passing options.
+
+ Replace
+ ```go
+ client.Copy(ctx, table, query)
+ ```
+ with
+ ```go
+ query.Run(ctx)
+ ```
+
+* Table.NewUploader has been renamed to Table.Uploader. Instead of options,
+ configure an Uploader by setting its fields.
+ Replace
+ ```go
+ u := table.NewUploader(bigquery.UploadIgnoreUnknownValues())
+ ```
+ with
+ ```go
+ u := table.NewUploader(bigquery.UploadIgnoreUnknownValues())
+ u.IgnoreUnknownValues = true
+ ```
+
+_October 10, 2016_
+
+Breaking changes to cloud.google.com/go/storage:
+
+* AdminClient replaced by methods on Client.
+ Replace
+ ```go
+ adminClient.CreateBucket(ctx, bucketName, attrs)
+ ```
+ with
+ ```go
+ client.Bucket(bucketName).Create(ctx, projectID, attrs)
+ ```
+
+* BucketHandle.List replaced by BucketHandle.Objects.
+ Replace
+ ```go
+ for query != nil {
+ objs, err := bucket.List(d.ctx, query)
+ if err != nil { ... }
+ query = objs.Next
+ for _, obj := range objs.Results {
+ fmt.Println(obj)
+ }
+ }
+ ```
+ with
+ ```go
+ iter := bucket.Objects(d.ctx, query)
+ for {
+ obj, err := iter.Next()
+ if err == iterator.Done {
+ break
+ }
+ if err != nil { ... }
+ fmt.Println(obj)
+ }
+ ```
+ (The `iterator` package is at `google.golang.org/api/iterator`.)
+
+ Replace `Query.Cursor` with `ObjectIterator.PageInfo().Token`.
+
+ Replace `Query.MaxResults` with `ObjectIterator.PageInfo().MaxSize`.
+
+
+* ObjectHandle.CopyTo replaced by ObjectHandle.CopierFrom.
+ Replace
+ ```go
+ attrs, err := src.CopyTo(ctx, dst, nil)
+ ```
+ with
+ ```go
+ attrs, err := dst.CopierFrom(src).Run(ctx)
+ ```
+
+ Replace
+ ```go
+ attrs, err := src.CopyTo(ctx, dst, &storage.ObjectAttrs{ContextType: "text/html"})
+ ```
+ with
+ ```go
+ c := dst.CopierFrom(src)
+ c.ContextType = "text/html"
+ attrs, err := c.Run(ctx)
+ ```
+
+* ObjectHandle.ComposeFrom replaced by ObjectHandle.ComposerFrom.
+ Replace
+ ```go
+ attrs, err := dst.ComposeFrom(ctx, []*storage.ObjectHandle{src1, src2}, nil)
+ ```
+ with
+ ```go
+ attrs, err := dst.ComposerFrom(src1, src2).Run(ctx)
+ ```
+
+* ObjectHandle.Update's ObjectAttrs argument replaced by ObjectAttrsToUpdate.
+ Replace
+ ```go
+ attrs, err := obj.Update(ctx, &storage.ObjectAttrs{ContextType: "text/html"})
+ ```
+ with
+ ```go
+ attrs, err := obj.Update(ctx, storage.ObjectAttrsToUpdate{ContextType: "text/html"})
+ ```
+
+* ObjectHandle.WithConditions replaced by ObjectHandle.If.
+ Replace
+ ```go
+ obj.WithConditions(storage.Generation(gen), storage.IfMetaGenerationMatch(mgen))
+ ```
+ with
+ ```go
+ obj.Generation(gen).If(storage.Conditions{MetagenerationMatch: mgen})
+ ```
+
+ Replace
+ ```go
+ obj.WithConditions(storage.IfGenerationMatch(0))
+ ```
+ with
+ ```go
+ obj.If(storage.Conditions{DoesNotExist: true})
+ ```
+
+* `storage.Done` replaced by `iterator.Done` (from package `google.golang.org/api/iterator`).
+
+_October 6, 2016_
+
+Package preview/logging deleted. Use logging instead.
+
+_September 27, 2016_
+
+Logging client replaced with preview version (see below).
+
+_September 8, 2016_
+
+* New clients for some of Google's Machine Learning APIs: Vision, Speech, and
+Natural Language.
+
+* Preview version of a new [Stackdriver Logging][cloud-logging] client in
+[`cloud.google.com/go/preview/logging`](https://godoc.org/cloud.google.com/go/preview/logging).
+This client uses gRPC as its transport layer, and supports log reading, sinks
+and metrics. It will replace the current client at `cloud.google.com/go/logging` shortly.
+
diff --git a/vendor/cloud.google.com/go/regen-gapic.sh b/vendor/cloud.google.com/go/regen-gapic.sh
new file mode 100755
index 00000000000..7b96a43cd8c
--- /dev/null
+++ b/vendor/cloud.google.com/go/regen-gapic.sh
@@ -0,0 +1,64 @@
+#!/bin/bash
+
+# This script generates all GAPIC clients in this repo.
+# One-time setup:
+# cd path/to/googleapis # https://github.com/googleapis/googleapis
+# virtualenv env
+# . env/bin/activate
+# pip install googleapis-artman
+# deactivate
+#
+# Regenerate:
+# cd path/to/googleapis
+# . env/bin/activate
+# $GOPATH/src/cloud.google.com/go/regen-gapic.sh
+# deactivate
+#
+# Being in googleapis directory is important;
+# that's where we find YAML files and where artman puts the "artman-genfiles" directory.
+#
+# NOTE: This script does not generate the "raw" gRPC client found in google.golang.org/genproto.
+# To do that, use the regen.sh script in the genproto repo instead.
+
+set -ex
+
+APIS=(
+google/cloud/bigquery/datatransfer/artman_bigquerydatatransfer.yaml
+google/cloud/dataproc/artman_dataproc_v1.yaml
+google/cloud/language/artman_language_v1.yaml
+google/cloud/language/artman_language_v1beta2.yaml
+google/cloud/oslogin/artman_oslogin_v1beta.yaml
+google/cloud/speech/artman_speech_v1.yaml
+google/cloud/speech/artman_speech_v1beta1.yaml
+google/cloud/videointelligence/artman_videointelligence_v1beta1.yaml
+google/cloud/videointelligence/artman_videointelligence_v1beta2.yaml
+google/cloud/vision/artman_vision_v1.yaml
+google/cloud/vision/artman_vision_v1p1beta1.yaml
+google/container/artman_container.yaml
+google/devtools/artman_clouddebugger.yaml
+google/devtools/clouderrorreporting/artman_errorreporting.yaml
+google/devtools/cloudtrace/artman_cloudtrace_v1.yaml
+google/devtools/cloudtrace/artman_cloudtrace_v2.yaml
+google/firestore/artman_firestore.yaml
+google/logging/artman_logging.yaml
+google/longrunning/artman_longrunning.yaml
+google/monitoring/artman_monitoring.yaml
+google/privacy/dlp/artman_dlp.yaml
+google/privacy/dlp/artman_dlp_v2beta2.yaml
+google/pubsub/artman_pubsub.yaml
+google/spanner/admin/database/artman_spanner_admin_database.yaml
+google/spanner/admin/instance/artman_spanner_admin_instance.yaml
+google/spanner/artman_spanner.yaml
+)
+
+for api in "${APIS[@]}"; do
+ rm -rf artman-genfiles/*
+ artman --config "$api" generate go_gapic
+ cp -r artman-genfiles/gapi-*/cloud.google.com/go/* $GOPATH/src/cloud.google.com/go/
+done
+
+go list cloud.google.com/go/... | grep apiv | xargs go test
+
+go test -short cloud.google.com/go/...
+
+echo "googleapis version: $(git rev-parse HEAD)"
diff --git a/vendor/cloud.google.com/go/run-tests.sh b/vendor/cloud.google.com/go/run-tests.sh
new file mode 100755
index 00000000000..f47ff50a5e9
--- /dev/null
+++ b/vendor/cloud.google.com/go/run-tests.sh
@@ -0,0 +1,88 @@
+#!/bin/bash
+
+# Selectively run tests for this repo, based on what has changed
+# in a commit. Runs short tests for the whole repo, and full tests
+# for changed directories.
+
+set -e
+
+prefix=cloud.google.com/go
+
+dryrun=false
+if [[ $1 == "-n" ]]; then
+ dryrun=true
+ shift
+fi
+
+if [[ $1 == "" ]]; then
+ echo >&2 "usage: $0 [-n] COMMIT"
+ exit 1
+fi
+
+# Files or directories that cause all tests to run if modified.
+declare -A run_all
+run_all=([.travis.yml]=1 [run-tests.sh]=1)
+
+function run {
+ if $dryrun; then
+ echo $*
+ else
+ (set -x; $*)
+ fi
+}
+
+
+# Find all the packages that have changed in this commit.
+declare -A changed_packages
+
+for f in $(git diff-tree --no-commit-id --name-only -r $1); do
+ if [[ ${run_all[$f]} == 1 ]]; then
+ # This change requires a full test. Do it and exit.
+ run go test -race -v $prefix/...
+ exit
+ fi
+ # Map, e.g., "spanner/client.go" to "$prefix/spanner".
+ d=$(dirname $f)
+ if [[ $d == "." ]]; then
+ pkg=$prefix
+ else
+ pkg=$prefix/$d
+ fi
+ changed_packages[$pkg]=1
+done
+
+echo "changed packages: ${!changed_packages[*]}"
+
+
+# Reports whether its argument, a package name, depends (recursively)
+# on a changed package.
+function depends_on_changed_package {
+ # According to go list, a package does not depend on itself, so
+ # we test that separately.
+ if [[ ${changed_packages[$1]} == 1 ]]; then
+ return 0
+ fi
+ for dep in $(go list -f '{{range .Deps}}{{.}} {{end}}' $1); do
+ if [[ ${changed_packages[$dep]} == 1 ]]; then
+ return 0
+ fi
+ done
+ return 1
+}
+
+# Collect the packages into two separate lists. (It is faster go test a list of
+# packages than to individually go test each one.)
+
+shorts=
+fulls=
+for pkg in $(go list $prefix/...); do # for each package in the repo
+ if depends_on_changed_package $pkg; then # if it depends on a changed package
+ fulls="$fulls $pkg" # run the full test
+ else # otherwise
+ shorts="$shorts $pkg" # run the short test
+ fi
+done
+run go test -race -v -short $shorts
+if [[ $fulls != "" ]]; then
+ run go test -race -v $fulls
+fi
diff --git a/vendor/github.com/PuerkitoBio/purell/.gitignore b/vendor/github.com/PuerkitoBio/purell/.gitignore
new file mode 100644
index 00000000000..748e4c8073c
--- /dev/null
+++ b/vendor/github.com/PuerkitoBio/purell/.gitignore
@@ -0,0 +1,5 @@
+*.sublime-*
+.DS_Store
+*.swp
+*.swo
+tags
diff --git a/vendor/github.com/PuerkitoBio/purell/.travis.yml b/vendor/github.com/PuerkitoBio/purell/.travis.yml
new file mode 100644
index 00000000000..facfc91c65a
--- /dev/null
+++ b/vendor/github.com/PuerkitoBio/purell/.travis.yml
@@ -0,0 +1,7 @@
+language: go
+
+go:
+ - 1.4
+ - 1.5
+ - 1.6
+ - tip
diff --git a/vendor/github.com/PuerkitoBio/purell/BUILD.bazel b/vendor/github.com/PuerkitoBio/purell/BUILD.bazel
new file mode 100644
index 00000000000..2a2365aa3be
--- /dev/null
+++ b/vendor/github.com/PuerkitoBio/purell/BUILD.bazel
@@ -0,0 +1,26 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
+
+go_library(
+ name = "go_default_library",
+ srcs = ["purell.go"],
+ importpath = "github.com/PuerkitoBio/purell",
+ visibility = ["//visibility:public"],
+ deps = [
+ "//vendor/github.com/PuerkitoBio/urlesc:go_default_library",
+ "//vendor/golang.org/x/net/idna:go_default_library",
+ "//vendor/golang.org/x/text/unicode/norm:go_default_library",
+ "//vendor/golang.org/x/text/width:go_default_library",
+ ],
+)
+
+go_test(
+ name = "go_default_test",
+ srcs = [
+ "bench_test.go",
+ "example_test.go",
+ "purell_test.go",
+ "urlnorm_test.go",
+ ],
+ embed = [":go_default_library"],
+ importpath = "github.com/PuerkitoBio/purell",
+)
diff --git a/vendor/github.com/PuerkitoBio/purell/LICENSE b/vendor/github.com/PuerkitoBio/purell/LICENSE
new file mode 100644
index 00000000000..4b9986dea71
--- /dev/null
+++ b/vendor/github.com/PuerkitoBio/purell/LICENSE
@@ -0,0 +1,12 @@
+Copyright (c) 2012, Martin Angers
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+* Neither the name of the author nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/github.com/PuerkitoBio/purell/README.md b/vendor/github.com/PuerkitoBio/purell/README.md
new file mode 100644
index 00000000000..09e8a32cbe9
--- /dev/null
+++ b/vendor/github.com/PuerkitoBio/purell/README.md
@@ -0,0 +1,187 @@
+# Purell
+
+Purell is a tiny Go library to normalize URLs. It returns a pure URL. Pure-ell. Sanitizer and all. Yeah, I know...
+
+Based on the [wikipedia paper][wiki] and the [RFC 3986 document][rfc].
+
+[](http://travis-ci.org/PuerkitoBio/purell)
+
+## Install
+
+`go get github.com/PuerkitoBio/purell`
+
+## Changelog
+
+* **2016-11-14 (v1.1.0)** : IDN: Conform to RFC 5895: Fold character width (thanks to @beeker1121).
+* **2016-07-27 (v1.0.0)** : Normalize IDN to ASCII (thanks to @zenovich).
+* **2015-02-08** : Add fix for relative paths issue ([PR #5][pr5]) and add fix for unnecessary encoding of reserved characters ([see issue #7][iss7]).
+* **v0.2.0** : Add benchmarks, Attempt IDN support.
+* **v0.1.0** : Initial release.
+
+## Examples
+
+From `example_test.go` (note that in your code, you would import "github.com/PuerkitoBio/purell", and would prefix references to its methods and constants with "purell."):
+
+```go
+package purell
+
+import (
+ "fmt"
+ "net/url"
+)
+
+func ExampleNormalizeURLString() {
+ if normalized, err := NormalizeURLString("hTTp://someWEBsite.com:80/Amazing%3f/url/",
+ FlagLowercaseScheme|FlagLowercaseHost|FlagUppercaseEscapes); err != nil {
+ panic(err)
+ } else {
+ fmt.Print(normalized)
+ }
+ // Output: http://somewebsite.com:80/Amazing%3F/url/
+}
+
+func ExampleMustNormalizeURLString() {
+ normalized := MustNormalizeURLString("hTTpS://someWEBsite.com:443/Amazing%fa/url/",
+ FlagsUnsafeGreedy)
+ fmt.Print(normalized)
+
+ // Output: http://somewebsite.com/Amazing%FA/url
+}
+
+func ExampleNormalizeURL() {
+ if u, err := url.Parse("Http://SomeUrl.com:8080/a/b/.././c///g?c=3&a=1&b=9&c=0#target"); err != nil {
+ panic(err)
+ } else {
+ normalized := NormalizeURL(u, FlagsUsuallySafeGreedy|FlagRemoveDuplicateSlashes|FlagRemoveFragment)
+ fmt.Print(normalized)
+ }
+
+ // Output: http://someurl.com:8080/a/c/g?c=3&a=1&b=9&c=0
+}
+```
+
+## API
+
+As seen in the examples above, purell offers three methods, `NormalizeURLString(string, NormalizationFlags) (string, error)`, `MustNormalizeURLString(string, NormalizationFlags) (string)` and `NormalizeURL(*url.URL, NormalizationFlags) (string)`. They all normalize the provided URL based on the specified flags. Here are the available flags:
+
+```go
+const (
+ // Safe normalizations
+ FlagLowercaseScheme NormalizationFlags = 1 << iota // HTTP://host -> http://host, applied by default in Go1.1
+ FlagLowercaseHost // http://HOST -> http://host
+ FlagUppercaseEscapes // http://host/t%ef -> http://host/t%EF
+ FlagDecodeUnnecessaryEscapes // http://host/t%41 -> http://host/tA
+ FlagEncodeNecessaryEscapes // http://host/!"#$ -> http://host/%21%22#$
+ FlagRemoveDefaultPort // http://host:80 -> http://host
+ FlagRemoveEmptyQuerySeparator // http://host/path? -> http://host/path
+
+ // Usually safe normalizations
+ FlagRemoveTrailingSlash // http://host/path/ -> http://host/path
+ FlagAddTrailingSlash // http://host/path -> http://host/path/ (should choose only one of these add/remove trailing slash flags)
+ FlagRemoveDotSegments // http://host/path/./a/b/../c -> http://host/path/a/c
+
+ // Unsafe normalizations
+ FlagRemoveDirectoryIndex // http://host/path/index.html -> http://host/path/
+ FlagRemoveFragment // http://host/path#fragment -> http://host/path
+ FlagForceHTTP // https://host -> http://host
+ FlagRemoveDuplicateSlashes // http://host/path//a///b -> http://host/path/a/b
+ FlagRemoveWWW // http://www.host/ -> http://host/
+ FlagAddWWW // http://host/ -> http://www.host/ (should choose only one of these add/remove WWW flags)
+ FlagSortQuery // http://host/path?c=3&b=2&a=1&b=1 -> http://host/path?a=1&b=1&b=2&c=3
+
+ // Normalizations not in the wikipedia article, required to cover tests cases
+ // submitted by jehiah
+ FlagDecodeDWORDHost // http://1113982867 -> http://66.102.7.147
+ FlagDecodeOctalHost // http://0102.0146.07.0223 -> http://66.102.7.147
+ FlagDecodeHexHost // http://0x42660793 -> http://66.102.7.147
+ FlagRemoveUnnecessaryHostDots // http://.host../path -> http://host/path
+ FlagRemoveEmptyPortSeparator // http://host:/path -> http://host/path
+
+ // Convenience set of safe normalizations
+ FlagsSafe NormalizationFlags = FlagLowercaseHost | FlagLowercaseScheme | FlagUppercaseEscapes | FlagDecodeUnnecessaryEscapes | FlagEncodeNecessaryEscapes | FlagRemoveDefaultPort | FlagRemoveEmptyQuerySeparator
+
+ // For convenience sets, "greedy" uses the "remove trailing slash" and "remove www. prefix" flags,
+ // while "non-greedy" uses the "add (or keep) the trailing slash" and "add www. prefix".
+
+ // Convenience set of usually safe normalizations (includes FlagsSafe)
+ FlagsUsuallySafeGreedy NormalizationFlags = FlagsSafe | FlagRemoveTrailingSlash | FlagRemoveDotSegments
+ FlagsUsuallySafeNonGreedy NormalizationFlags = FlagsSafe | FlagAddTrailingSlash | FlagRemoveDotSegments
+
+ // Convenience set of unsafe normalizations (includes FlagsUsuallySafe)
+ FlagsUnsafeGreedy NormalizationFlags = FlagsUsuallySafeGreedy | FlagRemoveDirectoryIndex | FlagRemoveFragment | FlagForceHTTP | FlagRemoveDuplicateSlashes | FlagRemoveWWW | FlagSortQuery
+ FlagsUnsafeNonGreedy NormalizationFlags = FlagsUsuallySafeNonGreedy | FlagRemoveDirectoryIndex | FlagRemoveFragment | FlagForceHTTP | FlagRemoveDuplicateSlashes | FlagAddWWW | FlagSortQuery
+
+ // Convenience set of all available flags
+ FlagsAllGreedy = FlagsUnsafeGreedy | FlagDecodeDWORDHost | FlagDecodeOctalHost | FlagDecodeHexHost | FlagRemoveUnnecessaryHostDots | FlagRemoveEmptyPortSeparator
+ FlagsAllNonGreedy = FlagsUnsafeNonGreedy | FlagDecodeDWORDHost | FlagDecodeOctalHost | FlagDecodeHexHost | FlagRemoveUnnecessaryHostDots | FlagRemoveEmptyPortSeparator
+)
+```
+
+For convenience, the set of flags `FlagsSafe`, `FlagsUsuallySafe[Greedy|NonGreedy]`, `FlagsUnsafe[Greedy|NonGreedy]` and `FlagsAll[Greedy|NonGreedy]` are provided for the similarly grouped normalizations on [wikipedia's URL normalization page][wiki]. You can add (using the bitwise OR `|` operator) or remove (using the bitwise AND NOT `&^` operator) individual flags from the sets if required, to build your own custom set.
+
+The [full godoc reference is available on gopkgdoc][godoc].
+
+Some things to note:
+
+* `FlagDecodeUnnecessaryEscapes`, `FlagEncodeNecessaryEscapes`, `FlagUppercaseEscapes` and `FlagRemoveEmptyQuerySeparator` are always implicitly set, because internally, the URL string is parsed as an URL object, which automatically decodes unnecessary escapes, uppercases and encodes necessary ones, and removes empty query separators (an unnecessary `?` at the end of the url). So this operation cannot **not** be done. For this reason, `FlagRemoveEmptyQuerySeparator` (as well as the other three) has been included in the `FlagsSafe` convenience set, instead of `FlagsUnsafe`, where Wikipedia puts it.
+
+* The `FlagDecodeUnnecessaryEscapes` decodes the following escapes (*from -> to*):
+ - %24 -> $
+ - %26 -> &
+ - %2B-%3B -> +,-./0123456789:;
+ - %3D -> =
+ - %40-%5A -> @ABCDEFGHIJKLMNOPQRSTUVWXYZ
+ - %5F -> _
+ - %61-%7A -> abcdefghijklmnopqrstuvwxyz
+ - %7E -> ~
+
+
+* When the `NormalizeURL` function is used (passing an URL object), this source URL object is modified (that is, after the call, the URL object will be modified to reflect the normalization).
+
+* The *replace IP with domain name* normalization (`http://208.77.188.166/ → http://www.example.com/`) is obviously not possible for a library without making some network requests. This is not implemented in purell.
+
+* The *remove unused query string parameters* and *remove default query parameters* are also not implemented, since this is a very case-specific normalization, and it is quite trivial to do with an URL object.
+
+### Safe vs Usually Safe vs Unsafe
+
+Purell allows you to control the level of risk you take while normalizing an URL. You can aggressively normalize, play it totally safe, or anything in between.
+
+Consider the following URL:
+
+`HTTPS://www.RooT.com/toto/t%45%1f///a/./b/../c/?z=3&w=2&a=4&w=1#invalid`
+
+Normalizing with the `FlagsSafe` gives:
+
+`https://www.root.com/toto/tE%1F///a/./b/../c/?z=3&w=2&a=4&w=1#invalid`
+
+With the `FlagsUsuallySafeGreedy`:
+
+`https://www.root.com/toto/tE%1F///a/c?z=3&w=2&a=4&w=1#invalid`
+
+And with `FlagsUnsafeGreedy`:
+
+`http://root.com/toto/tE%1F/a/c?a=4&w=1&w=2&z=3`
+
+## TODOs
+
+* Add a class/default instance to allow specifying custom directory index names? At the moment, removing directory index removes `(^|/)((?:default|index)\.\w{1,4})$`.
+
+## Thanks / Contributions
+
+@rogpeppe
+@jehiah
+@opennota
+@pchristopher1275
+@zenovich
+@beeker1121
+
+## License
+
+The [BSD 3-Clause license][bsd].
+
+[bsd]: http://opensource.org/licenses/BSD-3-Clause
+[wiki]: http://en.wikipedia.org/wiki/URL_normalization
+[rfc]: http://tools.ietf.org/html/rfc3986#section-6
+[godoc]: http://go.pkgdoc.org/github.com/PuerkitoBio/purell
+[pr5]: https://github.com/PuerkitoBio/purell/pull/5
+[iss7]: https://github.com/PuerkitoBio/purell/issues/7
diff --git a/vendor/github.com/PuerkitoBio/purell/bench_test.go b/vendor/github.com/PuerkitoBio/purell/bench_test.go
new file mode 100644
index 00000000000..7549731fc40
--- /dev/null
+++ b/vendor/github.com/PuerkitoBio/purell/bench_test.go
@@ -0,0 +1,57 @@
+package purell
+
+import (
+ "testing"
+)
+
+var (
+ safeUrl = "HttPS://..iaMHost..Test:443/paTh^A%ef//./%41PaTH/..//?"
+ usuallySafeUrl = "HttPS://..iaMHost..Test:443/paTh^A%ef//./%41PaTH/../final/"
+ unsafeUrl = "HttPS://..www.iaMHost..Test:443/paTh^A%ef//./%41PaTH/../final/index.html?t=val1&a=val4&z=val5&a=val1#fragment"
+ allDWORDUrl = "HttPS://1113982867:/paTh^A%ef//./%41PaTH/../final/index.html?t=val1&a=val4&z=val5&a=val1#fragment"
+ allOctalUrl = "HttPS://0102.0146.07.0223:/paTh^A%ef//./%41PaTH/../final/index.html?t=val1&a=val4&z=val5&a=val1#fragment"
+ allHexUrl = "HttPS://0x42660793:/paTh^A%ef//./%41PaTH/../final/index.html?t=val1&a=val4&z=val5&a=val1#fragment"
+ allCombinedUrl = "HttPS://..0x42660793.:/paTh^A%ef//./%41PaTH/../final/index.html?t=val1&a=val4&z=val5&a=val1#fragment"
+)
+
+func BenchmarkSafe(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ NormalizeURLString(safeUrl, FlagsSafe)
+ }
+}
+
+func BenchmarkUsuallySafe(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ NormalizeURLString(usuallySafeUrl, FlagsUsuallySafeGreedy)
+ }
+}
+
+func BenchmarkUnsafe(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ NormalizeURLString(unsafeUrl, FlagsUnsafeGreedy)
+ }
+}
+
+func BenchmarkAllDWORD(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ NormalizeURLString(allDWORDUrl, FlagsAllGreedy)
+ }
+}
+
+func BenchmarkAllOctal(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ NormalizeURLString(allOctalUrl, FlagsAllGreedy)
+ }
+}
+
+func BenchmarkAllHex(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ NormalizeURLString(allHexUrl, FlagsAllGreedy)
+ }
+}
+
+func BenchmarkAllCombined(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ NormalizeURLString(allCombinedUrl, FlagsAllGreedy)
+ }
+}
diff --git a/vendor/github.com/PuerkitoBio/purell/example_test.go b/vendor/github.com/PuerkitoBio/purell/example_test.go
new file mode 100644
index 00000000000..997b95369cb
--- /dev/null
+++ b/vendor/github.com/PuerkitoBio/purell/example_test.go
@@ -0,0 +1,35 @@
+package purell
+
+import (
+ "fmt"
+ "net/url"
+)
+
+func ExampleNormalizeURLString() {
+ if normalized, err := NormalizeURLString("hTTp://someWEBsite.com:80/Amazing%3f/url/",
+ FlagLowercaseScheme|FlagLowercaseHost|FlagUppercaseEscapes); err != nil {
+ panic(err)
+ } else {
+ fmt.Print(normalized)
+ }
+ // Output: http://somewebsite.com:80/Amazing%3F/url/
+}
+
+func ExampleMustNormalizeURLString() {
+ normalized := MustNormalizeURLString("hTTpS://someWEBsite.com:443/Amazing%fa/url/",
+ FlagsUnsafeGreedy)
+ fmt.Print(normalized)
+
+ // Output: http://somewebsite.com/Amazing%FA/url
+}
+
+func ExampleNormalizeURL() {
+ if u, err := url.Parse("Http://SomeUrl.com:8080/a/b/.././c///g?c=3&a=1&b=9&c=0#target"); err != nil {
+ panic(err)
+ } else {
+ normalized := NormalizeURL(u, FlagsUsuallySafeGreedy|FlagRemoveDuplicateSlashes|FlagRemoveFragment)
+ fmt.Print(normalized)
+ }
+
+ // Output: http://someurl.com:8080/a/c/g?c=3&a=1&b=9&c=0
+}
diff --git a/vendor/github.com/PuerkitoBio/purell/purell.go b/vendor/github.com/PuerkitoBio/purell/purell.go
new file mode 100644
index 00000000000..645e1b76f79
--- /dev/null
+++ b/vendor/github.com/PuerkitoBio/purell/purell.go
@@ -0,0 +1,379 @@
+/*
+Package purell offers URL normalization as described on the wikipedia page:
+http://en.wikipedia.org/wiki/URL_normalization
+*/
+package purell
+
+import (
+ "bytes"
+ "fmt"
+ "net/url"
+ "regexp"
+ "sort"
+ "strconv"
+ "strings"
+
+ "github.com/PuerkitoBio/urlesc"
+ "golang.org/x/net/idna"
+ "golang.org/x/text/unicode/norm"
+ "golang.org/x/text/width"
+)
+
+// A set of normalization flags determines how a URL will
+// be normalized.
+type NormalizationFlags uint
+
+const (
+ // Safe normalizations
+ FlagLowercaseScheme NormalizationFlags = 1 << iota // HTTP://host -> http://host, applied by default in Go1.1
+ FlagLowercaseHost // http://HOST -> http://host
+ FlagUppercaseEscapes // http://host/t%ef -> http://host/t%EF
+ FlagDecodeUnnecessaryEscapes // http://host/t%41 -> http://host/tA
+ FlagEncodeNecessaryEscapes // http://host/!"#$ -> http://host/%21%22#$
+ FlagRemoveDefaultPort // http://host:80 -> http://host
+ FlagRemoveEmptyQuerySeparator // http://host/path? -> http://host/path
+
+ // Usually safe normalizations
+ FlagRemoveTrailingSlash // http://host/path/ -> http://host/path
+ FlagAddTrailingSlash // http://host/path -> http://host/path/ (should choose only one of these add/remove trailing slash flags)
+ FlagRemoveDotSegments // http://host/path/./a/b/../c -> http://host/path/a/c
+
+ // Unsafe normalizations
+ FlagRemoveDirectoryIndex // http://host/path/index.html -> http://host/path/
+ FlagRemoveFragment // http://host/path#fragment -> http://host/path
+ FlagForceHTTP // https://host -> http://host
+ FlagRemoveDuplicateSlashes // http://host/path//a///b -> http://host/path/a/b
+ FlagRemoveWWW // http://www.host/ -> http://host/
+ FlagAddWWW // http://host/ -> http://www.host/ (should choose only one of these add/remove WWW flags)
+ FlagSortQuery // http://host/path?c=3&b=2&a=1&b=1 -> http://host/path?a=1&b=1&b=2&c=3
+
+ // Normalizations not in the wikipedia article, required to cover tests cases
+ // submitted by jehiah
+ FlagDecodeDWORDHost // http://1113982867 -> http://66.102.7.147
+ FlagDecodeOctalHost // http://0102.0146.07.0223 -> http://66.102.7.147
+ FlagDecodeHexHost // http://0x42660793 -> http://66.102.7.147
+ FlagRemoveUnnecessaryHostDots // http://.host../path -> http://host/path
+ FlagRemoveEmptyPortSeparator // http://host:/path -> http://host/path
+
+ // Convenience set of safe normalizations
+ FlagsSafe NormalizationFlags = FlagLowercaseHost | FlagLowercaseScheme | FlagUppercaseEscapes | FlagDecodeUnnecessaryEscapes | FlagEncodeNecessaryEscapes | FlagRemoveDefaultPort | FlagRemoveEmptyQuerySeparator
+
+ // For convenience sets, "greedy" uses the "remove trailing slash" and "remove www. prefix" flags,
+ // while "non-greedy" uses the "add (or keep) the trailing slash" and "add www. prefix".
+
+ // Convenience set of usually safe normalizations (includes FlagsSafe)
+ FlagsUsuallySafeGreedy NormalizationFlags = FlagsSafe | FlagRemoveTrailingSlash | FlagRemoveDotSegments
+ FlagsUsuallySafeNonGreedy NormalizationFlags = FlagsSafe | FlagAddTrailingSlash | FlagRemoveDotSegments
+
+ // Convenience set of unsafe normalizations (includes FlagsUsuallySafe)
+ FlagsUnsafeGreedy NormalizationFlags = FlagsUsuallySafeGreedy | FlagRemoveDirectoryIndex | FlagRemoveFragment | FlagForceHTTP | FlagRemoveDuplicateSlashes | FlagRemoveWWW | FlagSortQuery
+ FlagsUnsafeNonGreedy NormalizationFlags = FlagsUsuallySafeNonGreedy | FlagRemoveDirectoryIndex | FlagRemoveFragment | FlagForceHTTP | FlagRemoveDuplicateSlashes | FlagAddWWW | FlagSortQuery
+
+ // Convenience set of all available flags
+ FlagsAllGreedy = FlagsUnsafeGreedy | FlagDecodeDWORDHost | FlagDecodeOctalHost | FlagDecodeHexHost | FlagRemoveUnnecessaryHostDots | FlagRemoveEmptyPortSeparator
+ FlagsAllNonGreedy = FlagsUnsafeNonGreedy | FlagDecodeDWORDHost | FlagDecodeOctalHost | FlagDecodeHexHost | FlagRemoveUnnecessaryHostDots | FlagRemoveEmptyPortSeparator
+)
+
+const (
+ defaultHttpPort = ":80"
+ defaultHttpsPort = ":443"
+)
+
+// Regular expressions used by the normalizations
+var rxPort = regexp.MustCompile(`(:\d+)/?$`)
+var rxDirIndex = regexp.MustCompile(`(^|/)((?:default|index)\.\w{1,4})$`)
+var rxDupSlashes = regexp.MustCompile(`/{2,}`)
+var rxDWORDHost = regexp.MustCompile(`^(\d+)((?:\.+)?(?:\:\d*)?)$`)
+var rxOctalHost = regexp.MustCompile(`^(0\d*)\.(0\d*)\.(0\d*)\.(0\d*)((?:\.+)?(?:\:\d*)?)$`)
+var rxHexHost = regexp.MustCompile(`^0x([0-9A-Fa-f]+)((?:\.+)?(?:\:\d*)?)$`)
+var rxHostDots = regexp.MustCompile(`^(.+?)(:\d+)?$`)
+var rxEmptyPort = regexp.MustCompile(`:+$`)
+
+// Map of flags to implementation function.
+// FlagDecodeUnnecessaryEscapes has no action, since it is done automatically
+// by parsing the string as an URL. Same for FlagUppercaseEscapes and FlagRemoveEmptyQuerySeparator.
+
+// Since maps have undefined traversing order, make a slice of ordered keys
+var flagsOrder = []NormalizationFlags{
+ FlagLowercaseScheme,
+ FlagLowercaseHost,
+ FlagRemoveDefaultPort,
+ FlagRemoveDirectoryIndex,
+ FlagRemoveDotSegments,
+ FlagRemoveFragment,
+ FlagForceHTTP, // Must be after remove default port (because https=443/http=80)
+ FlagRemoveDuplicateSlashes,
+ FlagRemoveWWW,
+ FlagAddWWW,
+ FlagSortQuery,
+ FlagDecodeDWORDHost,
+ FlagDecodeOctalHost,
+ FlagDecodeHexHost,
+ FlagRemoveUnnecessaryHostDots,
+ FlagRemoveEmptyPortSeparator,
+ FlagRemoveTrailingSlash, // These two (add/remove trailing slash) must be last
+ FlagAddTrailingSlash,
+}
+
+// ... and then the map, where order is unimportant
+var flags = map[NormalizationFlags]func(*url.URL){
+ FlagLowercaseScheme: lowercaseScheme,
+ FlagLowercaseHost: lowercaseHost,
+ FlagRemoveDefaultPort: removeDefaultPort,
+ FlagRemoveDirectoryIndex: removeDirectoryIndex,
+ FlagRemoveDotSegments: removeDotSegments,
+ FlagRemoveFragment: removeFragment,
+ FlagForceHTTP: forceHTTP,
+ FlagRemoveDuplicateSlashes: removeDuplicateSlashes,
+ FlagRemoveWWW: removeWWW,
+ FlagAddWWW: addWWW,
+ FlagSortQuery: sortQuery,
+ FlagDecodeDWORDHost: decodeDWORDHost,
+ FlagDecodeOctalHost: decodeOctalHost,
+ FlagDecodeHexHost: decodeHexHost,
+ FlagRemoveUnnecessaryHostDots: removeUnncessaryHostDots,
+ FlagRemoveEmptyPortSeparator: removeEmptyPortSeparator,
+ FlagRemoveTrailingSlash: removeTrailingSlash,
+ FlagAddTrailingSlash: addTrailingSlash,
+}
+
+// MustNormalizeURLString returns the normalized string, and panics if an error occurs.
+// It takes an URL string as input, as well as the normalization flags.
+func MustNormalizeURLString(u string, f NormalizationFlags) string {
+ result, e := NormalizeURLString(u, f)
+ if e != nil {
+ panic(e)
+ }
+ return result
+}
+
+// NormalizeURLString returns the normalized string, or an error if it can't be parsed into an URL object.
+// It takes an URL string as input, as well as the normalization flags.
+func NormalizeURLString(u string, f NormalizationFlags) (string, error) {
+ parsed, err := url.Parse(u)
+ if err != nil {
+ return "", err
+ }
+
+ if f&FlagLowercaseHost == FlagLowercaseHost {
+ parsed.Host = strings.ToLower(parsed.Host)
+ }
+
+ // The idna package doesn't fully conform to RFC 5895
+ // (https://tools.ietf.org/html/rfc5895), so we do it here.
+ // Taken from Go 1.8 cycle source, courtesy of bradfitz.
+ // TODO: Remove when (if?) idna package conforms to RFC 5895.
+ parsed.Host = width.Fold.String(parsed.Host)
+ parsed.Host = norm.NFC.String(parsed.Host)
+ if parsed.Host, err = idna.ToASCII(parsed.Host); err != nil {
+ return "", err
+ }
+
+ return NormalizeURL(parsed, f), nil
+}
+
+// NormalizeURL returns the normalized string.
+// It takes a parsed URL object as input, as well as the normalization flags.
+func NormalizeURL(u *url.URL, f NormalizationFlags) string {
+ for _, k := range flagsOrder {
+ if f&k == k {
+ flags[k](u)
+ }
+ }
+ return urlesc.Escape(u)
+}
+
+func lowercaseScheme(u *url.URL) {
+ if len(u.Scheme) > 0 {
+ u.Scheme = strings.ToLower(u.Scheme)
+ }
+}
+
+func lowercaseHost(u *url.URL) {
+ if len(u.Host) > 0 {
+ u.Host = strings.ToLower(u.Host)
+ }
+}
+
+func removeDefaultPort(u *url.URL) {
+ if len(u.Host) > 0 {
+ scheme := strings.ToLower(u.Scheme)
+ u.Host = rxPort.ReplaceAllStringFunc(u.Host, func(val string) string {
+ if (scheme == "http" && val == defaultHttpPort) || (scheme == "https" && val == defaultHttpsPort) {
+ return ""
+ }
+ return val
+ })
+ }
+}
+
+func removeTrailingSlash(u *url.URL) {
+ if l := len(u.Path); l > 0 {
+ if strings.HasSuffix(u.Path, "/") {
+ u.Path = u.Path[:l-1]
+ }
+ } else if l = len(u.Host); l > 0 {
+ if strings.HasSuffix(u.Host, "/") {
+ u.Host = u.Host[:l-1]
+ }
+ }
+}
+
+func addTrailingSlash(u *url.URL) {
+ if l := len(u.Path); l > 0 {
+ if !strings.HasSuffix(u.Path, "/") {
+ u.Path += "/"
+ }
+ } else if l = len(u.Host); l > 0 {
+ if !strings.HasSuffix(u.Host, "/") {
+ u.Host += "/"
+ }
+ }
+}
+
+func removeDotSegments(u *url.URL) {
+ if len(u.Path) > 0 {
+ var dotFree []string
+ var lastIsDot bool
+
+ sections := strings.Split(u.Path, "/")
+ for _, s := range sections {
+ if s == ".." {
+ if len(dotFree) > 0 {
+ dotFree = dotFree[:len(dotFree)-1]
+ }
+ } else if s != "." {
+ dotFree = append(dotFree, s)
+ }
+ lastIsDot = (s == "." || s == "..")
+ }
+ // Special case if host does not end with / and new path does not begin with /
+ u.Path = strings.Join(dotFree, "/")
+ if u.Host != "" && !strings.HasSuffix(u.Host, "/") && !strings.HasPrefix(u.Path, "/") {
+ u.Path = "/" + u.Path
+ }
+ // Special case if the last segment was a dot, make sure the path ends with a slash
+ if lastIsDot && !strings.HasSuffix(u.Path, "/") {
+ u.Path += "/"
+ }
+ }
+}
+
+func removeDirectoryIndex(u *url.URL) {
+ if len(u.Path) > 0 {
+ u.Path = rxDirIndex.ReplaceAllString(u.Path, "$1")
+ }
+}
+
+func removeFragment(u *url.URL) {
+ u.Fragment = ""
+}
+
+func forceHTTP(u *url.URL) {
+ if strings.ToLower(u.Scheme) == "https" {
+ u.Scheme = "http"
+ }
+}
+
+func removeDuplicateSlashes(u *url.URL) {
+ if len(u.Path) > 0 {
+ u.Path = rxDupSlashes.ReplaceAllString(u.Path, "/")
+ }
+}
+
+func removeWWW(u *url.URL) {
+ if len(u.Host) > 0 && strings.HasPrefix(strings.ToLower(u.Host), "www.") {
+ u.Host = u.Host[4:]
+ }
+}
+
+func addWWW(u *url.URL) {
+ if len(u.Host) > 0 && !strings.HasPrefix(strings.ToLower(u.Host), "www.") {
+ u.Host = "www." + u.Host
+ }
+}
+
+func sortQuery(u *url.URL) {
+ q := u.Query()
+
+ if len(q) > 0 {
+ arKeys := make([]string, len(q))
+ i := 0
+ for k, _ := range q {
+ arKeys[i] = k
+ i++
+ }
+ sort.Strings(arKeys)
+ buf := new(bytes.Buffer)
+ for _, k := range arKeys {
+ sort.Strings(q[k])
+ for _, v := range q[k] {
+ if buf.Len() > 0 {
+ buf.WriteRune('&')
+ }
+ buf.WriteString(fmt.Sprintf("%s=%s", k, urlesc.QueryEscape(v)))
+ }
+ }
+
+ // Rebuild the raw query string
+ u.RawQuery = buf.String()
+ }
+}
+
+func decodeDWORDHost(u *url.URL) {
+ if len(u.Host) > 0 {
+ if matches := rxDWORDHost.FindStringSubmatch(u.Host); len(matches) > 2 {
+ var parts [4]int64
+
+ dword, _ := strconv.ParseInt(matches[1], 10, 0)
+ for i, shift := range []uint{24, 16, 8, 0} {
+ parts[i] = dword >> shift & 0xFF
+ }
+ u.Host = fmt.Sprintf("%d.%d.%d.%d%s", parts[0], parts[1], parts[2], parts[3], matches[2])
+ }
+ }
+}
+
+func decodeOctalHost(u *url.URL) {
+ if len(u.Host) > 0 {
+ if matches := rxOctalHost.FindStringSubmatch(u.Host); len(matches) > 5 {
+ var parts [4]int64
+
+ for i := 1; i <= 4; i++ {
+ parts[i-1], _ = strconv.ParseInt(matches[i], 8, 0)
+ }
+ u.Host = fmt.Sprintf("%d.%d.%d.%d%s", parts[0], parts[1], parts[2], parts[3], matches[5])
+ }
+ }
+}
+
+func decodeHexHost(u *url.URL) {
+ if len(u.Host) > 0 {
+ if matches := rxHexHost.FindStringSubmatch(u.Host); len(matches) > 2 {
+ // Conversion is safe because of regex validation
+ parsed, _ := strconv.ParseInt(matches[1], 16, 0)
+ // Set host as DWORD (base 10) encoded host
+ u.Host = fmt.Sprintf("%d%s", parsed, matches[2])
+ // The rest is the same as decoding a DWORD host
+ decodeDWORDHost(u)
+ }
+ }
+}
+
+func removeUnncessaryHostDots(u *url.URL) {
+ if len(u.Host) > 0 {
+ if matches := rxHostDots.FindStringSubmatch(u.Host); len(matches) > 1 {
+ // Trim the leading and trailing dots
+ u.Host = strings.Trim(matches[1], ".")
+ if len(matches) > 2 {
+ u.Host += matches[2]
+ }
+ }
+ }
+}
+
+func removeEmptyPortSeparator(u *url.URL) {
+ if len(u.Host) > 0 {
+ u.Host = rxEmptyPort.ReplaceAllString(u.Host, "")
+ }
+}
diff --git a/vendor/github.com/PuerkitoBio/purell/purell_test.go b/vendor/github.com/PuerkitoBio/purell/purell_test.go
new file mode 100644
index 00000000000..a3732e5a3d1
--- /dev/null
+++ b/vendor/github.com/PuerkitoBio/purell/purell_test.go
@@ -0,0 +1,768 @@
+package purell
+
+import (
+ "fmt"
+ "net/url"
+ "testing"
+)
+
+type testCase struct {
+ nm string
+ src string
+ flgs NormalizationFlags
+ res string
+ parsed bool
+}
+
+var (
+ cases = [...]*testCase{
+ &testCase{
+ "LowerScheme",
+ "HTTP://www.SRC.ca",
+ FlagLowercaseScheme,
+ "http://www.SRC.ca",
+ false,
+ },
+ &testCase{
+ "LowerScheme2",
+ "http://www.SRC.ca",
+ FlagLowercaseScheme,
+ "http://www.SRC.ca",
+ false,
+ },
+ &testCase{
+ "LowerHost",
+ "HTTP://www.SRC.ca/",
+ FlagLowercaseHost,
+ "http://www.src.ca/", // Since Go1.1, scheme is automatically lowercased
+ false,
+ },
+ &testCase{
+ "UpperEscapes",
+ `http://www.whatever.com/Some%aa%20Special%8Ecases/`,
+ FlagUppercaseEscapes,
+ "http://www.whatever.com/Some%AA%20Special%8Ecases/",
+ false,
+ },
+ &testCase{
+ "UnnecessaryEscapes",
+ `http://www.toto.com/%41%42%2E%44/%32%33%52%2D/%5f%7E`,
+ FlagDecodeUnnecessaryEscapes,
+ "http://www.toto.com/AB.D/23R-/_~",
+ false,
+ },
+ &testCase{
+ "RemoveDefaultPort",
+ "HTTP://www.SRC.ca:80/",
+ FlagRemoveDefaultPort,
+ "http://www.SRC.ca/", // Since Go1.1, scheme is automatically lowercased
+ false,
+ },
+ &testCase{
+ "RemoveDefaultPort2",
+ "HTTP://www.SRC.ca:80",
+ FlagRemoveDefaultPort,
+ "http://www.SRC.ca", // Since Go1.1, scheme is automatically lowercased
+ false,
+ },
+ &testCase{
+ "RemoveDefaultPort3",
+ "HTTP://www.SRC.ca:8080",
+ FlagRemoveDefaultPort,
+ "http://www.SRC.ca:8080", // Since Go1.1, scheme is automatically lowercased
+ false,
+ },
+ &testCase{
+ "Safe",
+ "HTTP://www.SRC.ca:80/to%1ato%8b%ee/OKnow%41%42%43%7e",
+ FlagsSafe,
+ "http://www.src.ca/to%1Ato%8B%EE/OKnowABC~",
+ false,
+ },
+ &testCase{
+ "BothLower",
+ "HTTP://www.SRC.ca:80/to%1ato%8b%ee/OKnow%41%42%43%7e",
+ FlagLowercaseHost | FlagLowercaseScheme,
+ "http://www.src.ca:80/to%1Ato%8B%EE/OKnowABC~",
+ false,
+ },
+ &testCase{
+ "RemoveTrailingSlash",
+ "HTTP://www.SRC.ca:80/",
+ FlagRemoveTrailingSlash,
+ "http://www.SRC.ca:80", // Since Go1.1, scheme is automatically lowercased
+ false,
+ },
+ &testCase{
+ "RemoveTrailingSlash2",
+ "HTTP://www.SRC.ca:80/toto/titi/",
+ FlagRemoveTrailingSlash,
+ "http://www.SRC.ca:80/toto/titi", // Since Go1.1, scheme is automatically lowercased
+ false,
+ },
+ &testCase{
+ "RemoveTrailingSlash3",
+ "HTTP://www.SRC.ca:80/toto/titi/fin/?a=1",
+ FlagRemoveTrailingSlash,
+ "http://www.SRC.ca:80/toto/titi/fin?a=1", // Since Go1.1, scheme is automatically lowercased
+ false,
+ },
+ &testCase{
+ "AddTrailingSlash",
+ "HTTP://www.SRC.ca:80",
+ FlagAddTrailingSlash,
+ "http://www.SRC.ca:80/", // Since Go1.1, scheme is automatically lowercased
+ false,
+ },
+ &testCase{
+ "AddTrailingSlash2",
+ "HTTP://www.SRC.ca:80/toto/titi.html",
+ FlagAddTrailingSlash,
+ "http://www.SRC.ca:80/toto/titi.html/", // Since Go1.1, scheme is automatically lowercased
+ false,
+ },
+ &testCase{
+ "AddTrailingSlash3",
+ "HTTP://www.SRC.ca:80/toto/titi/fin?a=1",
+ FlagAddTrailingSlash,
+ "http://www.SRC.ca:80/toto/titi/fin/?a=1", // Since Go1.1, scheme is automatically lowercased
+ false,
+ },
+ &testCase{
+ "RemoveDotSegments",
+ "HTTP://root/a/b/./../../c/",
+ FlagRemoveDotSegments,
+ "http://root/c/", // Since Go1.1, scheme is automatically lowercased
+ false,
+ },
+ &testCase{
+ "RemoveDotSegments2",
+ "HTTP://root/../a/b/./../c/../d",
+ FlagRemoveDotSegments,
+ "http://root/a/d", // Since Go1.1, scheme is automatically lowercased
+ false,
+ },
+ &testCase{
+ "UsuallySafe",
+ "HTTP://www.SRC.ca:80/to%1ato%8b%ee/./c/d/../OKnow%41%42%43%7e/?a=b#test",
+ FlagsUsuallySafeGreedy,
+ "http://www.src.ca/to%1Ato%8B%EE/c/OKnowABC~?a=b#test",
+ false,
+ },
+ &testCase{
+ "RemoveDirectoryIndex",
+ "HTTP://root/a/b/c/default.aspx",
+ FlagRemoveDirectoryIndex,
+ "http://root/a/b/c/", // Since Go1.1, scheme is automatically lowercased
+ false,
+ },
+ &testCase{
+ "RemoveDirectoryIndex2",
+ "HTTP://root/a/b/c/default#a=b",
+ FlagRemoveDirectoryIndex,
+ "http://root/a/b/c/default#a=b", // Since Go1.1, scheme is automatically lowercased
+ false,
+ },
+ &testCase{
+ "RemoveFragment",
+ "HTTP://root/a/b/c/default#toto=tata",
+ FlagRemoveFragment,
+ "http://root/a/b/c/default", // Since Go1.1, scheme is automatically lowercased
+ false,
+ },
+ &testCase{
+ "ForceHTTP",
+ "https://root/a/b/c/default#toto=tata",
+ FlagForceHTTP,
+ "http://root/a/b/c/default#toto=tata",
+ false,
+ },
+ &testCase{
+ "RemoveDuplicateSlashes",
+ "https://root/a//b///c////default#toto=tata",
+ FlagRemoveDuplicateSlashes,
+ "https://root/a/b/c/default#toto=tata",
+ false,
+ },
+ &testCase{
+ "RemoveDuplicateSlashes2",
+ "https://root//a//b///c////default#toto=tata",
+ FlagRemoveDuplicateSlashes,
+ "https://root/a/b/c/default#toto=tata",
+ false,
+ },
+ &testCase{
+ "RemoveWWW",
+ "https://www.root/a/b/c/",
+ FlagRemoveWWW,
+ "https://root/a/b/c/",
+ false,
+ },
+ &testCase{
+ "RemoveWWW2",
+ "https://WwW.Root/a/b/c/",
+ FlagRemoveWWW,
+ "https://Root/a/b/c/",
+ false,
+ },
+ &testCase{
+ "AddWWW",
+ "https://Root/a/b/c/",
+ FlagAddWWW,
+ "https://www.Root/a/b/c/",
+ false,
+ },
+ &testCase{
+ "SortQuery",
+ "http://root/toto/?b=4&a=1&c=3&b=2&a=5",
+ FlagSortQuery,
+ "http://root/toto/?a=1&a=5&b=2&b=4&c=3",
+ false,
+ },
+ &testCase{
+ "RemoveEmptyQuerySeparator",
+ "http://root/toto/?",
+ FlagRemoveEmptyQuerySeparator,
+ "http://root/toto/",
+ false,
+ },
+ &testCase{
+ "Unsafe",
+ "HTTPS://www.RooT.com/toto/t%45%1f///a/./b/../c/?z=3&w=2&a=4&w=1#invalid",
+ FlagsUnsafeGreedy,
+ "http://root.com/toto/tE%1F/a/c?a=4&w=1&w=2&z=3",
+ false,
+ },
+ &testCase{
+ "Safe2",
+ "HTTPS://www.RooT.com/toto/t%45%1f///a/./b/../c/?z=3&w=2&a=4&w=1#invalid",
+ FlagsSafe,
+ "https://www.root.com/toto/tE%1F///a/./b/../c/?z=3&w=2&a=4&w=1#invalid",
+ false,
+ },
+ &testCase{
+ "UsuallySafe2",
+ "HTTPS://www.RooT.com/toto/t%45%1f///a/./b/../c/?z=3&w=2&a=4&w=1#invalid",
+ FlagsUsuallySafeGreedy,
+ "https://www.root.com/toto/tE%1F///a/c?z=3&w=2&a=4&w=1#invalid",
+ false,
+ },
+ &testCase{
+ "AddTrailingSlashBug",
+ "http://src.ca/",
+ FlagsAllNonGreedy,
+ "http://www.src.ca/",
+ false,
+ },
+ &testCase{
+ "SourceModified",
+ "HTTPS://www.RooT.com/toto/t%45%1f///a/./b/../c/?z=3&w=2&a=4&w=1#invalid",
+ FlagsUnsafeGreedy,
+ "http://root.com/toto/tE%1F/a/c?a=4&w=1&w=2&z=3",
+ true,
+ },
+ &testCase{
+ "IPv6-1",
+ "http://[2001:db8:1f70::999:de8:7648:6e8]/test",
+ FlagsSafe | FlagRemoveDotSegments,
+ "http://[2001:db8:1f70::999:de8:7648:6e8]/test",
+ false,
+ },
+ &testCase{
+ "IPv6-2",
+ "http://[::ffff:192.168.1.1]/test",
+ FlagsSafe | FlagRemoveDotSegments,
+ "http://[::ffff:192.168.1.1]/test",
+ false,
+ },
+ &testCase{
+ "IPv6-3",
+ "http://[::ffff:192.168.1.1]:80/test",
+ FlagsSafe | FlagRemoveDotSegments,
+ "http://[::ffff:192.168.1.1]/test",
+ false,
+ },
+ &testCase{
+ "IPv6-4",
+ "htTps://[::fFff:192.168.1.1]:443/test",
+ FlagsSafe | FlagRemoveDotSegments,
+ "https://[::ffff:192.168.1.1]/test",
+ false,
+ },
+ &testCase{
+ "FTP",
+ "ftp://user:pass@ftp.foo.net/foo/bar",
+ FlagsSafe | FlagRemoveDotSegments,
+ "ftp://user:pass@ftp.foo.net/foo/bar",
+ false,
+ },
+ &testCase{
+ "Standard-1",
+ "http://www.foo.com:80/foo",
+ FlagsSafe | FlagRemoveDotSegments,
+ "http://www.foo.com/foo",
+ false,
+ },
+ &testCase{
+ "Standard-2",
+ "http://www.foo.com:8000/foo",
+ FlagsSafe | FlagRemoveDotSegments,
+ "http://www.foo.com:8000/foo",
+ false,
+ },
+ &testCase{
+ "Standard-3",
+ "http://www.foo.com/%7ebar",
+ FlagsSafe | FlagRemoveDotSegments,
+ "http://www.foo.com/~bar",
+ false,
+ },
+ &testCase{
+ "Standard-4",
+ "http://www.foo.com/%7Ebar",
+ FlagsSafe | FlagRemoveDotSegments,
+ "http://www.foo.com/~bar",
+ false,
+ },
+ &testCase{
+ "Standard-5",
+ "http://USER:pass@www.Example.COM/foo/bar",
+ FlagsSafe | FlagRemoveDotSegments,
+ "http://USER:pass@www.example.com/foo/bar",
+ false,
+ },
+ &testCase{
+ "Standard-6",
+ "http://test.example/?a=%26&b=1",
+ FlagsSafe | FlagRemoveDotSegments,
+ "http://test.example/?a=%26&b=1",
+ false,
+ },
+ &testCase{
+ "Standard-7",
+ "http://test.example/%25/?p=%20val%20%25",
+ FlagsSafe | FlagRemoveDotSegments,
+ "http://test.example/%25/?p=%20val%20%25",
+ false,
+ },
+ &testCase{
+ "Standard-8",
+ "http://test.example/path/with a%20space+/",
+ FlagsSafe | FlagRemoveDotSegments,
+ "http://test.example/path/with%20a%20space+/",
+ false,
+ },
+ &testCase{
+ "Standard-9",
+ "http://test.example/?",
+ FlagsSafe | FlagRemoveDotSegments,
+ "http://test.example/",
+ false,
+ },
+ &testCase{
+ "Standard-10",
+ "http://a.COM/path/?b&a",
+ FlagsSafe | FlagRemoveDotSegments,
+ "http://a.com/path/?b&a",
+ false,
+ },
+ &testCase{
+ "StandardCasesAddTrailingSlash",
+ "http://test.example?",
+ FlagsSafe | FlagAddTrailingSlash,
+ "http://test.example/",
+ false,
+ },
+ &testCase{
+ "OctalIP-1",
+ "http://0123.011.0.4/",
+ FlagsSafe | FlagDecodeOctalHost,
+ "http://0123.011.0.4/",
+ false,
+ },
+ &testCase{
+ "OctalIP-2",
+ "http://0102.0146.07.0223/",
+ FlagsSafe | FlagDecodeOctalHost,
+ "http://66.102.7.147/",
+ false,
+ },
+ &testCase{
+ "OctalIP-3",
+ "http://0102.0146.07.0223.:23/",
+ FlagsSafe | FlagDecodeOctalHost,
+ "http://66.102.7.147.:23/",
+ false,
+ },
+ &testCase{
+ "OctalIP-4",
+ "http://USER:pass@0102.0146.07.0223../",
+ FlagsSafe | FlagDecodeOctalHost,
+ "http://USER:pass@66.102.7.147../",
+ false,
+ },
+ &testCase{
+ "DWORDIP-1",
+ "http://123.1113982867/",
+ FlagsSafe | FlagDecodeDWORDHost,
+ "http://123.1113982867/",
+ false,
+ },
+ &testCase{
+ "DWORDIP-2",
+ "http://1113982867/",
+ FlagsSafe | FlagDecodeDWORDHost,
+ "http://66.102.7.147/",
+ false,
+ },
+ &testCase{
+ "DWORDIP-3",
+ "http://1113982867.:23/",
+ FlagsSafe | FlagDecodeDWORDHost,
+ "http://66.102.7.147.:23/",
+ false,
+ },
+ &testCase{
+ "DWORDIP-4",
+ "http://USER:pass@1113982867../",
+ FlagsSafe | FlagDecodeDWORDHost,
+ "http://USER:pass@66.102.7.147../",
+ false,
+ },
+ &testCase{
+ "HexIP-1",
+ "http://0x123.1113982867/",
+ FlagsSafe | FlagDecodeHexHost,
+ "http://0x123.1113982867/",
+ false,
+ },
+ &testCase{
+ "HexIP-2",
+ "http://0x42660793/",
+ FlagsSafe | FlagDecodeHexHost,
+ "http://66.102.7.147/",
+ false,
+ },
+ &testCase{
+ "HexIP-3",
+ "http://0x42660793.:23/",
+ FlagsSafe | FlagDecodeHexHost,
+ "http://66.102.7.147.:23/",
+ false,
+ },
+ &testCase{
+ "HexIP-4",
+ "http://USER:pass@0x42660793../",
+ FlagsSafe | FlagDecodeHexHost,
+ "http://USER:pass@66.102.7.147../",
+ false,
+ },
+ &testCase{
+ "UnnecessaryHostDots-1",
+ "http://.www.foo.com../foo/bar.html",
+ FlagsSafe | FlagRemoveUnnecessaryHostDots,
+ "http://www.foo.com/foo/bar.html",
+ false,
+ },
+ &testCase{
+ "UnnecessaryHostDots-2",
+ "http://www.foo.com./foo/bar.html",
+ FlagsSafe | FlagRemoveUnnecessaryHostDots,
+ "http://www.foo.com/foo/bar.html",
+ false,
+ },
+ &testCase{
+ "UnnecessaryHostDots-3",
+ "http://www.foo.com.:81/foo",
+ FlagsSafe | FlagRemoveUnnecessaryHostDots,
+ "http://www.foo.com:81/foo",
+ false,
+ },
+ &testCase{
+ "UnnecessaryHostDots-4",
+ "http://www.example.com./",
+ FlagsSafe | FlagRemoveUnnecessaryHostDots,
+ "http://www.example.com/",
+ false,
+ },
+ &testCase{
+ "EmptyPort-1",
+ "http://www.thedraymin.co.uk:/main/?p=308",
+ FlagsSafe | FlagRemoveEmptyPortSeparator,
+ "http://www.thedraymin.co.uk/main/?p=308",
+ false,
+ },
+ &testCase{
+ "EmptyPort-2",
+ "http://www.src.ca:",
+ FlagsSafe | FlagRemoveEmptyPortSeparator,
+ "http://www.src.ca",
+ false,
+ },
+ &testCase{
+ "Slashes-1",
+ "http://test.example/foo/bar/.",
+ FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
+ "http://test.example/foo/bar/",
+ false,
+ },
+ &testCase{
+ "Slashes-2",
+ "http://test.example/foo/bar/./",
+ FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
+ "http://test.example/foo/bar/",
+ false,
+ },
+ &testCase{
+ "Slashes-3",
+ "http://test.example/foo/bar/..",
+ FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
+ "http://test.example/foo/",
+ false,
+ },
+ &testCase{
+ "Slashes-4",
+ "http://test.example/foo/bar/../",
+ FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
+ "http://test.example/foo/",
+ false,
+ },
+ &testCase{
+ "Slashes-5",
+ "http://test.example/foo/bar/../baz",
+ FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
+ "http://test.example/foo/baz",
+ false,
+ },
+ &testCase{
+ "Slashes-6",
+ "http://test.example/foo/bar/../..",
+ FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
+ "http://test.example/",
+ false,
+ },
+ &testCase{
+ "Slashes-7",
+ "http://test.example/foo/bar/../../",
+ FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
+ "http://test.example/",
+ false,
+ },
+ &testCase{
+ "Slashes-8",
+ "http://test.example/foo/bar/../../baz",
+ FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
+ "http://test.example/baz",
+ false,
+ },
+ &testCase{
+ "Slashes-9",
+ "http://test.example/foo/bar/../../../baz",
+ FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
+ "http://test.example/baz",
+ false,
+ },
+ &testCase{
+ "Slashes-10",
+ "http://test.example/foo/bar/../../../../baz",
+ FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
+ "http://test.example/baz",
+ false,
+ },
+ &testCase{
+ "Slashes-11",
+ "http://test.example/./foo",
+ FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
+ "http://test.example/foo",
+ false,
+ },
+ &testCase{
+ "Slashes-12",
+ "http://test.example/../foo",
+ FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
+ "http://test.example/foo",
+ false,
+ },
+ &testCase{
+ "Slashes-13",
+ "http://test.example/foo.",
+ FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
+ "http://test.example/foo.",
+ false,
+ },
+ &testCase{
+ "Slashes-14",
+ "http://test.example/.foo",
+ FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
+ "http://test.example/.foo",
+ false,
+ },
+ &testCase{
+ "Slashes-15",
+ "http://test.example/foo..",
+ FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
+ "http://test.example/foo..",
+ false,
+ },
+ &testCase{
+ "Slashes-16",
+ "http://test.example/..foo",
+ FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
+ "http://test.example/..foo",
+ false,
+ },
+ &testCase{
+ "Slashes-17",
+ "http://test.example/./../foo",
+ FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
+ "http://test.example/foo",
+ false,
+ },
+ &testCase{
+ "Slashes-18",
+ "http://test.example/./foo/.",
+ FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
+ "http://test.example/foo/",
+ false,
+ },
+ &testCase{
+ "Slashes-19",
+ "http://test.example/foo/./bar",
+ FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
+ "http://test.example/foo/bar",
+ false,
+ },
+ &testCase{
+ "Slashes-20",
+ "http://test.example/foo/../bar",
+ FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
+ "http://test.example/bar",
+ false,
+ },
+ &testCase{
+ "Slashes-21",
+ "http://test.example/foo//",
+ FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
+ "http://test.example/foo/",
+ false,
+ },
+ &testCase{
+ "Slashes-22",
+ "http://test.example/foo///bar//",
+ FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
+ "http://test.example/foo/bar/",
+ false,
+ },
+ &testCase{
+ "Relative",
+ "foo/bar",
+ FlagsAllGreedy,
+ "foo/bar",
+ false,
+ },
+ &testCase{
+ "Relative-1",
+ "./../foo",
+ FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
+ "foo",
+ false,
+ },
+ &testCase{
+ "Relative-2",
+ "./foo/bar/../baz/../bang/..",
+ FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
+ "foo/",
+ false,
+ },
+ &testCase{
+ "Relative-3",
+ "foo///bar//",
+ FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes,
+ "foo/bar/",
+ false,
+ },
+ &testCase{
+ "Relative-4",
+ "www.youtube.com",
+ FlagsUsuallySafeGreedy,
+ "www.youtube.com",
+ false,
+ },
+ /*&testCase{
+ "UrlNorm-5",
+ "http://ja.wikipedia.org/wiki/%E3%82%AD%E3%83%A3%E3%82%BF%E3%83%94%E3%83%A9%E3%83%BC%E3%82%B8%E3%83%A3%E3%83%91%E3%83%B3",
+ FlagsSafe | FlagRemoveDotSegments,
+ "http://ja.wikipedia.org/wiki/\xe3\x82\xad\xe3\x83\xa3\xe3\x82\xbf\xe3\x83\x94\xe3\x83\xa9\xe3\x83\xbc\xe3\x82\xb8\xe3\x83\xa3\xe3\x83\x91\xe3\x83\xb3",
+ false,
+ },
+ &testCase{
+ "UrlNorm-1",
+ "http://test.example/?a=%e3%82%82%26",
+ FlagsAllGreedy,
+ "http://test.example/?a=\xe3\x82\x82%26",
+ false,
+ },*/
+ }
+)
+
+func TestRunner(t *testing.T) {
+ for _, tc := range cases {
+ runCase(tc, t)
+ }
+}
+
+func runCase(tc *testCase, t *testing.T) {
+ t.Logf("running %s...", tc.nm)
+ if tc.parsed {
+ u, e := url.Parse(tc.src)
+ if e != nil {
+ t.Errorf("%s - FAIL : %s", tc.nm, e)
+ return
+ } else {
+ NormalizeURL(u, tc.flgs)
+ if s := u.String(); s != tc.res {
+ t.Errorf("%s - FAIL expected '%s', got '%s'", tc.nm, tc.res, s)
+ }
+ }
+ } else {
+ if s, e := NormalizeURLString(tc.src, tc.flgs); e != nil {
+ t.Errorf("%s - FAIL : %s", tc.nm, e)
+ } else if s != tc.res {
+ t.Errorf("%s - FAIL expected '%s', got '%s'", tc.nm, tc.res, s)
+ }
+ }
+}
+
+func TestDecodeUnnecessaryEscapesAll(t *testing.T) {
+ var url = "http://host/"
+
+ for i := 0; i < 256; i++ {
+ url += fmt.Sprintf("%%%02x", i)
+ }
+ if s, e := NormalizeURLString(url, FlagDecodeUnnecessaryEscapes); e != nil {
+ t.Fatalf("Got error %s", e.Error())
+ } else {
+ const want = "http://host/%00%01%02%03%04%05%06%07%08%09%0A%0B%0C%0D%0E%0F%10%11%12%13%14%15%16%17%18%19%1A%1B%1C%1D%1E%1F%20!%22%23$%25&'()*+,-./0123456789:;%3C=%3E%3F@ABCDEFGHIJKLMNOPQRSTUVWXYZ[%5C]%5E_%60abcdefghijklmnopqrstuvwxyz%7B%7C%7D~%7F%80%81%82%83%84%85%86%87%88%89%8A%8B%8C%8D%8E%8F%90%91%92%93%94%95%96%97%98%99%9A%9B%9C%9D%9E%9F%A0%A1%A2%A3%A4%A5%A6%A7%A8%A9%AA%AB%AC%AD%AE%AF%B0%B1%B2%B3%B4%B5%B6%B7%B8%B9%BA%BB%BC%BD%BE%BF%C0%C1%C2%C3%C4%C5%C6%C7%C8%C9%CA%CB%CC%CD%CE%CF%D0%D1%D2%D3%D4%D5%D6%D7%D8%D9%DA%DB%DC%DD%DE%DF%E0%E1%E2%E3%E4%E5%E6%E7%E8%E9%EA%EB%EC%ED%EE%EF%F0%F1%F2%F3%F4%F5%F6%F7%F8%F9%FA%FB%FC%FD%FE%FF"
+ if s != want {
+ t.Errorf("DecodeUnnecessaryEscapesAll:\nwant\n%s\ngot\n%s", want, s)
+ }
+ }
+}
+
+func TestEncodeNecessaryEscapesAll(t *testing.T) {
+ var url = "http://host/"
+
+ for i := 0; i < 256; i++ {
+ if i != 0x25 {
+ url += string(i)
+ }
+ }
+ if s, e := NormalizeURLString(url, FlagEncodeNecessaryEscapes); e != nil {
+ t.Fatalf("Got error %s", e.Error())
+ } else {
+ const want = "http://host/%00%01%02%03%04%05%06%07%08%09%0A%0B%0C%0D%0E%0F%10%11%12%13%14%15%16%17%18%19%1A%1B%1C%1D%1E%1F%20!%22#$&'()*+,-./0123456789:;%3C=%3E?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[%5C]%5E_%60abcdefghijklmnopqrstuvwxyz%7B%7C%7D~%7F%C2%80%C2%81%C2%82%C2%83%C2%84%C2%85%C2%86%C2%87%C2%88%C2%89%C2%8A%C2%8B%C2%8C%C2%8D%C2%8E%C2%8F%C2%90%C2%91%C2%92%C2%93%C2%94%C2%95%C2%96%C2%97%C2%98%C2%99%C2%9A%C2%9B%C2%9C%C2%9D%C2%9E%C2%9F%C2%A0%C2%A1%C2%A2%C2%A3%C2%A4%C2%A5%C2%A6%C2%A7%C2%A8%C2%A9%C2%AA%C2%AB%C2%AC%C2%AD%C2%AE%C2%AF%C2%B0%C2%B1%C2%B2%C2%B3%C2%B4%C2%B5%C2%B6%C2%B7%C2%B8%C2%B9%C2%BA%C2%BB%C2%BC%C2%BD%C2%BE%C2%BF%C3%80%C3%81%C3%82%C3%83%C3%84%C3%85%C3%86%C3%87%C3%88%C3%89%C3%8A%C3%8B%C3%8C%C3%8D%C3%8E%C3%8F%C3%90%C3%91%C3%92%C3%93%C3%94%C3%95%C3%96%C3%97%C3%98%C3%99%C3%9A%C3%9B%C3%9C%C3%9D%C3%9E%C3%9F%C3%A0%C3%A1%C3%A2%C3%A3%C3%A4%C3%A5%C3%A6%C3%A7%C3%A8%C3%A9%C3%AA%C3%AB%C3%AC%C3%AD%C3%AE%C3%AF%C3%B0%C3%B1%C3%B2%C3%B3%C3%B4%C3%B5%C3%B6%C3%B7%C3%B8%C3%B9%C3%BA%C3%BB%C3%BC%C3%BD%C3%BE%C3%BF"
+ if s != want {
+ t.Errorf("EncodeNecessaryEscapesAll:\nwant\n%s\ngot\n%s", want, s)
+ }
+ }
+}
diff --git a/vendor/github.com/PuerkitoBio/purell/urlnorm_test.go b/vendor/github.com/PuerkitoBio/purell/urlnorm_test.go
new file mode 100644
index 00000000000..d1b2ca6c0e9
--- /dev/null
+++ b/vendor/github.com/PuerkitoBio/purell/urlnorm_test.go
@@ -0,0 +1,53 @@
+package purell
+
+import (
+ "testing"
+)
+
+// Test cases merged from PR #1
+// Originally from https://github.com/jehiah/urlnorm/blob/master/test_urlnorm.py
+
+func assertMap(t *testing.T, cases map[string]string, f NormalizationFlags) {
+ for bad, good := range cases {
+ s, e := NormalizeURLString(bad, f)
+ if e != nil {
+ t.Errorf("%s normalizing %v to %v", e.Error(), bad, good)
+ } else {
+ if s != good {
+ t.Errorf("source: %v expected: %v got: %v", bad, good, s)
+ }
+ }
+ }
+}
+
+// This tests normalization to a unicode representation
+// precent escapes for unreserved values are unescaped to their unicode value
+// tests normalization to idna domains
+// test ip word handling, ipv6 address handling, and trailing domain periods
+// in general, this matches google chromes unescaping for things in the address bar.
+// spaces are converted to '+' (perhaphs controversial)
+// http://code.google.com/p/google-url/ probably is another good reference for this approach
+func TestUrlnorm(t *testing.T) {
+ testcases := map[string]string{
+ "http://test.example/?a=%e3%82%82%26": "http://test.example/?a=%e3%82%82%26",
+ //"http://test.example/?a=%e3%82%82%26": "http://test.example/?a=\xe3\x82\x82%26", //should return a unicode character
+ "http://s.xn--q-bga.DE/": "http://s.xn--q-bga.de/", //should be in idna format
+ "http://XBLA\u306eXbox.com": "http://xn--xblaxbox-jf4g.com", //test utf8 and unicode
+ "http://президент.рф": "http://xn--d1abbgf6aiiy.xn--p1ai",
+ "http://ПРЕЗИДЕНТ.РФ": "http://xn--d1abbgf6aiiy.xn--p1ai",
+ "http://ab¥ヲ₩○.com": "http://xn--ab-ida8983azmfnvs.com", //test width folding
+ "http://\u00e9.com": "http://xn--9ca.com",
+ "http://e\u0301.com": "http://xn--9ca.com",
+ "http://ja.wikipedia.org/wiki/%E3%82%AD%E3%83%A3%E3%82%BF%E3%83%94%E3%83%A9%E3%83%BC%E3%82%B8%E3%83%A3%E3%83%91%E3%83%B3": "http://ja.wikipedia.org/wiki/%E3%82%AD%E3%83%A3%E3%82%BF%E3%83%94%E3%83%A9%E3%83%BC%E3%82%B8%E3%83%A3%E3%83%91%E3%83%B3",
+ //"http://ja.wikipedia.org/wiki/%E3%82%AD%E3%83%A3%E3%82%BF%E3%83%94%E3%83%A9%E3%83%BC%E3%82%B8%E3%83%A3%E3%83%91%E3%83%B3": "http://ja.wikipedia.org/wiki/\xe3\x82\xad\xe3\x83\xa3\xe3\x82\xbf\xe3\x83\x94\xe3\x83\xa9\xe3\x83\xbc\xe3\x82\xb8\xe3\x83\xa3\xe3\x83\x91\xe3\x83\xb3",
+
+ "http://test.example/\xe3\x82\xad": "http://test.example/%E3%82%AD",
+ //"http://test.example/\xe3\x82\xad": "http://test.example/\xe3\x82\xad",
+ "http://test.example/?p=%23val#test-%23-val%25": "http://test.example/?p=%23val#test-%23-val%25", //check that %23 (#) is not escaped where it shouldn't be
+
+ "http://test.domain/I%C3%B1t%C3%ABrn%C3%A2ti%C3%B4n%EF%BF%BDliz%C3%A6ti%C3%B8n": "http://test.domain/I%C3%B1t%C3%ABrn%C3%A2ti%C3%B4n%EF%BF%BDliz%C3%A6ti%C3%B8n",
+ //"http://test.domain/I%C3%B1t%C3%ABrn%C3%A2ti%C3%B4n%EF%BF%BDliz%C3%A6ti%C3%B8n": "http://test.domain/I\xc3\xb1t\xc3\xabrn\xc3\xa2ti\xc3\xb4n\xef\xbf\xbdliz\xc3\xa6ti\xc3\xb8n",
+ }
+
+ assertMap(t, testcases, FlagsSafe|FlagRemoveDotSegments)
+}
diff --git a/vendor/github.com/PuerkitoBio/urlesc/.travis.yml b/vendor/github.com/PuerkitoBio/urlesc/.travis.yml
new file mode 100644
index 00000000000..ba6b225f91e
--- /dev/null
+++ b/vendor/github.com/PuerkitoBio/urlesc/.travis.yml
@@ -0,0 +1,15 @@
+language: go
+
+go:
+ - 1.4.x
+ - 1.5.x
+ - 1.6.x
+ - 1.7.x
+ - 1.8.x
+ - tip
+
+install:
+ - go build .
+
+script:
+ - go test -v
diff --git a/vendor/github.com/PuerkitoBio/urlesc/BUILD.bazel b/vendor/github.com/PuerkitoBio/urlesc/BUILD.bazel
new file mode 100644
index 00000000000..f6bcd59c080
--- /dev/null
+++ b/vendor/github.com/PuerkitoBio/urlesc/BUILD.bazel
@@ -0,0 +1,15 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
+
+go_library(
+ name = "go_default_library",
+ srcs = ["urlesc.go"],
+ importpath = "github.com/PuerkitoBio/urlesc",
+ visibility = ["//visibility:public"],
+)
+
+go_test(
+ name = "go_default_test",
+ srcs = ["urlesc_test.go"],
+ embed = [":go_default_library"],
+ importpath = "github.com/PuerkitoBio/urlesc",
+)
diff --git a/vendor/github.com/PuerkitoBio/urlesc/LICENSE b/vendor/github.com/PuerkitoBio/urlesc/LICENSE
new file mode 100644
index 00000000000..74487567632
--- /dev/null
+++ b/vendor/github.com/PuerkitoBio/urlesc/LICENSE
@@ -0,0 +1,27 @@
+Copyright (c) 2012 The Go Authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+ * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/github.com/PuerkitoBio/urlesc/README.md b/vendor/github.com/PuerkitoBio/urlesc/README.md
new file mode 100644
index 00000000000..57aff0a5396
--- /dev/null
+++ b/vendor/github.com/PuerkitoBio/urlesc/README.md
@@ -0,0 +1,16 @@
+urlesc [](https://travis-ci.org/PuerkitoBio/urlesc) [](http://godoc.org/github.com/PuerkitoBio/urlesc)
+======
+
+Package urlesc implements query escaping as per RFC 3986.
+
+It contains some parts of the net/url package, modified so as to allow
+some reserved characters incorrectly escaped by net/url (see [issue 5684](https://github.com/golang/go/issues/5684)).
+
+## Install
+
+ go get github.com/PuerkitoBio/urlesc
+
+## License
+
+Go license (BSD-3-Clause)
+
diff --git a/vendor/github.com/PuerkitoBio/urlesc/urlesc.go b/vendor/github.com/PuerkitoBio/urlesc/urlesc.go
new file mode 100644
index 00000000000..1b84624594d
--- /dev/null
+++ b/vendor/github.com/PuerkitoBio/urlesc/urlesc.go
@@ -0,0 +1,180 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package urlesc implements query escaping as per RFC 3986.
+// It contains some parts of the net/url package, modified so as to allow
+// some reserved characters incorrectly escaped by net/url.
+// See https://github.com/golang/go/issues/5684
+package urlesc
+
+import (
+ "bytes"
+ "net/url"
+ "strings"
+)
+
+type encoding int
+
+const (
+ encodePath encoding = 1 + iota
+ encodeUserPassword
+ encodeQueryComponent
+ encodeFragment
+)
+
+// Return true if the specified character should be escaped when
+// appearing in a URL string, according to RFC 3986.
+func shouldEscape(c byte, mode encoding) bool {
+ // §2.3 Unreserved characters (alphanum)
+ if 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9' {
+ return false
+ }
+
+ switch c {
+ case '-', '.', '_', '~': // §2.3 Unreserved characters (mark)
+ return false
+
+ // §2.2 Reserved characters (reserved)
+ case ':', '/', '?', '#', '[', ']', '@', // gen-delims
+ '!', '$', '&', '\'', '(', ')', '*', '+', ',', ';', '=': // sub-delims
+ // Different sections of the URL allow a few of
+ // the reserved characters to appear unescaped.
+ switch mode {
+ case encodePath: // §3.3
+ // The RFC allows sub-delims and : @.
+ // '/', '[' and ']' can be used to assign meaning to individual path
+ // segments. This package only manipulates the path as a whole,
+ // so we allow those as well. That leaves only ? and # to escape.
+ return c == '?' || c == '#'
+
+ case encodeUserPassword: // §3.2.1
+ // The RFC allows : and sub-delims in
+ // userinfo. The parsing of userinfo treats ':' as special so we must escape
+ // all the gen-delims.
+ return c == ':' || c == '/' || c == '?' || c == '#' || c == '[' || c == ']' || c == '@'
+
+ case encodeQueryComponent: // §3.4
+ // The RFC allows / and ?.
+ return c != '/' && c != '?'
+
+ case encodeFragment: // §4.1
+ // The RFC text is silent but the grammar allows
+ // everything, so escape nothing but #
+ return c == '#'
+ }
+ }
+
+ // Everything else must be escaped.
+ return true
+}
+
+// QueryEscape escapes the string so it can be safely placed
+// inside a URL query.
+func QueryEscape(s string) string {
+ return escape(s, encodeQueryComponent)
+}
+
+func escape(s string, mode encoding) string {
+ spaceCount, hexCount := 0, 0
+ for i := 0; i < len(s); i++ {
+ c := s[i]
+ if shouldEscape(c, mode) {
+ if c == ' ' && mode == encodeQueryComponent {
+ spaceCount++
+ } else {
+ hexCount++
+ }
+ }
+ }
+
+ if spaceCount == 0 && hexCount == 0 {
+ return s
+ }
+
+ t := make([]byte, len(s)+2*hexCount)
+ j := 0
+ for i := 0; i < len(s); i++ {
+ switch c := s[i]; {
+ case c == ' ' && mode == encodeQueryComponent:
+ t[j] = '+'
+ j++
+ case shouldEscape(c, mode):
+ t[j] = '%'
+ t[j+1] = "0123456789ABCDEF"[c>>4]
+ t[j+2] = "0123456789ABCDEF"[c&15]
+ j += 3
+ default:
+ t[j] = s[i]
+ j++
+ }
+ }
+ return string(t)
+}
+
+var uiReplacer = strings.NewReplacer(
+ "%21", "!",
+ "%27", "'",
+ "%28", "(",
+ "%29", ")",
+ "%2A", "*",
+)
+
+// unescapeUserinfo unescapes some characters that need not to be escaped as per RFC3986.
+func unescapeUserinfo(s string) string {
+ return uiReplacer.Replace(s)
+}
+
+// Escape reassembles the URL into a valid URL string.
+// The general form of the result is one of:
+//
+// scheme:opaque
+// scheme://userinfo@host/path?query#fragment
+//
+// If u.Opaque is non-empty, String uses the first form;
+// otherwise it uses the second form.
+//
+// In the second form, the following rules apply:
+// - if u.Scheme is empty, scheme: is omitted.
+// - if u.User is nil, userinfo@ is omitted.
+// - if u.Host is empty, host/ is omitted.
+// - if u.Scheme and u.Host are empty and u.User is nil,
+// the entire scheme://userinfo@host/ is omitted.
+// - if u.Host is non-empty and u.Path begins with a /,
+// the form host/path does not add its own /.
+// - if u.RawQuery is empty, ?query is omitted.
+// - if u.Fragment is empty, #fragment is omitted.
+func Escape(u *url.URL) string {
+ var buf bytes.Buffer
+ if u.Scheme != "" {
+ buf.WriteString(u.Scheme)
+ buf.WriteByte(':')
+ }
+ if u.Opaque != "" {
+ buf.WriteString(u.Opaque)
+ } else {
+ if u.Scheme != "" || u.Host != "" || u.User != nil {
+ buf.WriteString("//")
+ if ui := u.User; ui != nil {
+ buf.WriteString(unescapeUserinfo(ui.String()))
+ buf.WriteByte('@')
+ }
+ if h := u.Host; h != "" {
+ buf.WriteString(h)
+ }
+ }
+ if u.Path != "" && u.Path[0] != '/' && u.Host != "" {
+ buf.WriteByte('/')
+ }
+ buf.WriteString(escape(u.Path, encodePath))
+ }
+ if u.RawQuery != "" {
+ buf.WriteByte('?')
+ buf.WriteString(u.RawQuery)
+ }
+ if u.Fragment != "" {
+ buf.WriteByte('#')
+ buf.WriteString(escape(u.Fragment, encodeFragment))
+ }
+ return buf.String()
+}
diff --git a/vendor/github.com/PuerkitoBio/urlesc/urlesc_test.go b/vendor/github.com/PuerkitoBio/urlesc/urlesc_test.go
new file mode 100644
index 00000000000..45202e1dd89
--- /dev/null
+++ b/vendor/github.com/PuerkitoBio/urlesc/urlesc_test.go
@@ -0,0 +1,641 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package urlesc
+
+import (
+ "net/url"
+ "testing"
+)
+
+type URLTest struct {
+ in string
+ out *url.URL
+ roundtrip string // expected result of reserializing the URL; empty means same as "in".
+}
+
+var urltests = []URLTest{
+ // no path
+ {
+ "http://www.google.com",
+ &url.URL{
+ Scheme: "http",
+ Host: "www.google.com",
+ },
+ "",
+ },
+ // path
+ {
+ "http://www.google.com/",
+ &url.URL{
+ Scheme: "http",
+ Host: "www.google.com",
+ Path: "/",
+ },
+ "",
+ },
+ // path with hex escaping
+ {
+ "http://www.google.com/file%20one%26two",
+ &url.URL{
+ Scheme: "http",
+ Host: "www.google.com",
+ Path: "/file one&two",
+ },
+ "http://www.google.com/file%20one&two",
+ },
+ // user
+ {
+ "ftp://webmaster@www.google.com/",
+ &url.URL{
+ Scheme: "ftp",
+ User: url.User("webmaster"),
+ Host: "www.google.com",
+ Path: "/",
+ },
+ "",
+ },
+ // escape sequence in username
+ {
+ "ftp://john%20doe@www.google.com/",
+ &url.URL{
+ Scheme: "ftp",
+ User: url.User("john doe"),
+ Host: "www.google.com",
+ Path: "/",
+ },
+ "ftp://john%20doe@www.google.com/",
+ },
+ // query
+ {
+ "http://www.google.com/?q=go+language",
+ &url.URL{
+ Scheme: "http",
+ Host: "www.google.com",
+ Path: "/",
+ RawQuery: "q=go+language",
+ },
+ "",
+ },
+ // query with hex escaping: NOT parsed
+ {
+ "http://www.google.com/?q=go%20language",
+ &url.URL{
+ Scheme: "http",
+ Host: "www.google.com",
+ Path: "/",
+ RawQuery: "q=go%20language",
+ },
+ "",
+ },
+ // %20 outside query
+ {
+ "http://www.google.com/a%20b?q=c+d",
+ &url.URL{
+ Scheme: "http",
+ Host: "www.google.com",
+ Path: "/a b",
+ RawQuery: "q=c+d",
+ },
+ "",
+ },
+ // path without leading /, so no parsing
+ {
+ "http:www.google.com/?q=go+language",
+ &url.URL{
+ Scheme: "http",
+ Opaque: "www.google.com/",
+ RawQuery: "q=go+language",
+ },
+ "http:www.google.com/?q=go+language",
+ },
+ // path without leading /, so no parsing
+ {
+ "http:%2f%2fwww.google.com/?q=go+language",
+ &url.URL{
+ Scheme: "http",
+ Opaque: "%2f%2fwww.google.com/",
+ RawQuery: "q=go+language",
+ },
+ "http:%2f%2fwww.google.com/?q=go+language",
+ },
+ // non-authority with path
+ {
+ "mailto:/webmaster@golang.org",
+ &url.URL{
+ Scheme: "mailto",
+ Path: "/webmaster@golang.org",
+ },
+ "mailto:///webmaster@golang.org", // unfortunate compromise
+ },
+ // non-authority
+ {
+ "mailto:webmaster@golang.org",
+ &url.URL{
+ Scheme: "mailto",
+ Opaque: "webmaster@golang.org",
+ },
+ "",
+ },
+ // unescaped :// in query should not create a scheme
+ {
+ "/foo?query=http://bad",
+ &url.URL{
+ Path: "/foo",
+ RawQuery: "query=http://bad",
+ },
+ "",
+ },
+ // leading // without scheme should create an authority
+ {
+ "//foo",
+ &url.URL{
+ Host: "foo",
+ },
+ "",
+ },
+ // leading // without scheme, with userinfo, path, and query
+ {
+ "//user@foo/path?a=b",
+ &url.URL{
+ User: url.User("user"),
+ Host: "foo",
+ Path: "/path",
+ RawQuery: "a=b",
+ },
+ "",
+ },
+ // Three leading slashes isn't an authority, but doesn't return an error.
+ // (We can't return an error, as this code is also used via
+ // ServeHTTP -> ReadRequest -> Parse, which is arguably a
+ // different URL parsing context, but currently shares the
+ // same codepath)
+ {
+ "///threeslashes",
+ &url.URL{
+ Path: "///threeslashes",
+ },
+ "",
+ },
+ {
+ "http://user:password@google.com",
+ &url.URL{
+ Scheme: "http",
+ User: url.UserPassword("user", "password"),
+ Host: "google.com",
+ },
+ "http://user:password@google.com",
+ },
+ // unescaped @ in username should not confuse host
+ {
+ "http://j@ne:password@google.com",
+ &url.URL{
+ Scheme: "http",
+ User: url.UserPassword("j@ne", "password"),
+ Host: "google.com",
+ },
+ "http://j%40ne:password@google.com",
+ },
+ // unescaped @ in password should not confuse host
+ {
+ "http://jane:p@ssword@google.com",
+ &url.URL{
+ Scheme: "http",
+ User: url.UserPassword("jane", "p@ssword"),
+ Host: "google.com",
+ },
+ "http://jane:p%40ssword@google.com",
+ },
+ {
+ "http://j@ne:password@google.com/p@th?q=@go",
+ &url.URL{
+ Scheme: "http",
+ User: url.UserPassword("j@ne", "password"),
+ Host: "google.com",
+ Path: "/p@th",
+ RawQuery: "q=@go",
+ },
+ "http://j%40ne:password@google.com/p@th?q=@go",
+ },
+ {
+ "http://www.google.com/?q=go+language#foo",
+ &url.URL{
+ Scheme: "http",
+ Host: "www.google.com",
+ Path: "/",
+ RawQuery: "q=go+language",
+ Fragment: "foo",
+ },
+ "",
+ },
+ {
+ "http://www.google.com/?q=go+language#foo%26bar",
+ &url.URL{
+ Scheme: "http",
+ Host: "www.google.com",
+ Path: "/",
+ RawQuery: "q=go+language",
+ Fragment: "foo&bar",
+ },
+ "http://www.google.com/?q=go+language#foo&bar",
+ },
+ {
+ "file:///home/adg/rabbits",
+ &url.URL{
+ Scheme: "file",
+ Host: "",
+ Path: "/home/adg/rabbits",
+ },
+ "file:///home/adg/rabbits",
+ },
+ // "Windows" paths are no exception to the rule.
+ // See golang.org/issue/6027, especially comment #9.
+ {
+ "file:///C:/FooBar/Baz.txt",
+ &url.URL{
+ Scheme: "file",
+ Host: "",
+ Path: "/C:/FooBar/Baz.txt",
+ },
+ "file:///C:/FooBar/Baz.txt",
+ },
+ // case-insensitive scheme
+ {
+ "MaIlTo:webmaster@golang.org",
+ &url.URL{
+ Scheme: "mailto",
+ Opaque: "webmaster@golang.org",
+ },
+ "mailto:webmaster@golang.org",
+ },
+ // Relative path
+ {
+ "a/b/c",
+ &url.URL{
+ Path: "a/b/c",
+ },
+ "a/b/c",
+ },
+ // escaped '?' in username and password
+ {
+ "http://%3Fam:pa%3Fsword@google.com",
+ &url.URL{
+ Scheme: "http",
+ User: url.UserPassword("?am", "pa?sword"),
+ Host: "google.com",
+ },
+ "",
+ },
+ // escaped '?' and '#' in path
+ {
+ "http://example.com/%3F%23",
+ &url.URL{
+ Scheme: "http",
+ Host: "example.com",
+ Path: "?#",
+ },
+ "",
+ },
+ // unescaped [ ] ! ' ( ) * in path
+ {
+ "http://example.com/[]!'()*",
+ &url.URL{
+ Scheme: "http",
+ Host: "example.com",
+ Path: "[]!'()*",
+ },
+ "http://example.com/[]!'()*",
+ },
+ // escaped : / ? # [ ] @ in username and password
+ {
+ "http://%3A%2F%3F:%23%5B%5D%40@example.com",
+ &url.URL{
+ Scheme: "http",
+ User: url.UserPassword(":/?", "#[]@"),
+ Host: "example.com",
+ },
+ "",
+ },
+ // unescaped ! $ & ' ( ) * + , ; = in username and password
+ {
+ "http://!$&'():*+,;=@example.com",
+ &url.URL{
+ Scheme: "http",
+ User: url.UserPassword("!$&'()", "*+,;="),
+ Host: "example.com",
+ },
+ "",
+ },
+ // unescaped = : / . ? = in query component
+ {
+ "http://example.com/?q=http://google.com/?q=",
+ &url.URL{
+ Scheme: "http",
+ Host: "example.com",
+ Path: "/",
+ RawQuery: "q=http://google.com/?q=",
+ },
+ "",
+ },
+ // unescaped : / ? [ ] @ ! $ & ' ( ) * + , ; = in fragment
+ {
+ "http://example.com/#:/?%23[]@!$&'()*+,;=",
+ &url.URL{
+ Scheme: "http",
+ Host: "example.com",
+ Path: "/",
+ Fragment: ":/?#[]@!$&'()*+,;=",
+ },
+ "",
+ },
+}
+
+func DoTestString(t *testing.T, parse func(string) (*url.URL, error), name string, tests []URLTest) {
+ for _, tt := range tests {
+ u, err := parse(tt.in)
+ if err != nil {
+ t.Errorf("%s(%q) returned error %s", name, tt.in, err)
+ continue
+ }
+ expected := tt.in
+ if len(tt.roundtrip) > 0 {
+ expected = tt.roundtrip
+ }
+ s := Escape(u)
+ if s != expected {
+ t.Errorf("Escape(%s(%q)) == %q (expected %q)", name, tt.in, s, expected)
+ }
+ }
+}
+
+func TestURLString(t *testing.T) {
+ DoTestString(t, url.Parse, "Parse", urltests)
+
+ // no leading slash on path should prepend
+ // slash on String() call
+ noslash := URLTest{
+ "http://www.google.com/search",
+ &url.URL{
+ Scheme: "http",
+ Host: "www.google.com",
+ Path: "search",
+ },
+ "",
+ }
+ s := Escape(noslash.out)
+ if s != noslash.in {
+ t.Errorf("Expected %s; go %s", noslash.in, s)
+ }
+}
+
+type EscapeTest struct {
+ in string
+ out string
+ err error
+}
+
+var escapeTests = []EscapeTest{
+ {
+ "",
+ "",
+ nil,
+ },
+ {
+ "abc",
+ "abc",
+ nil,
+ },
+ {
+ "one two",
+ "one+two",
+ nil,
+ },
+ {
+ "10%",
+ "10%25",
+ nil,
+ },
+ {
+ " ?&=#+%!<>#\"{}|\\^[]`☺\t:/@$'()*,;",
+ "+?%26%3D%23%2B%25%21%3C%3E%23%22%7B%7D%7C%5C%5E%5B%5D%60%E2%98%BA%09%3A/%40%24%27%28%29%2A%2C%3B",
+ nil,
+ },
+}
+
+func TestEscape(t *testing.T) {
+ for _, tt := range escapeTests {
+ actual := QueryEscape(tt.in)
+ if tt.out != actual {
+ t.Errorf("QueryEscape(%q) = %q, want %q", tt.in, actual, tt.out)
+ }
+
+ // for bonus points, verify that escape:unescape is an identity.
+ roundtrip, err := url.QueryUnescape(actual)
+ if roundtrip != tt.in || err != nil {
+ t.Errorf("QueryUnescape(%q) = %q, %s; want %q, %s", actual, roundtrip, err, tt.in, "[no error]")
+ }
+ }
+}
+
+var resolveReferenceTests = []struct {
+ base, rel, expected string
+}{
+ // Absolute URL references
+ {"http://foo.com?a=b", "https://bar.com/", "https://bar.com/"},
+ {"http://foo.com/", "https://bar.com/?a=b", "https://bar.com/?a=b"},
+ {"http://foo.com/bar", "mailto:foo@example.com", "mailto:foo@example.com"},
+
+ // Path-absolute references
+ {"http://foo.com/bar", "/baz", "http://foo.com/baz"},
+ {"http://foo.com/bar?a=b#f", "/baz", "http://foo.com/baz"},
+ {"http://foo.com/bar?a=b", "/baz?c=d", "http://foo.com/baz?c=d"},
+
+ // Scheme-relative
+ {"https://foo.com/bar?a=b", "//bar.com/quux", "https://bar.com/quux"},
+
+ // Path-relative references:
+
+ // ... current directory
+ {"http://foo.com", ".", "http://foo.com/"},
+ {"http://foo.com/bar", ".", "http://foo.com/"},
+ {"http://foo.com/bar/", ".", "http://foo.com/bar/"},
+
+ // ... going down
+ {"http://foo.com", "bar", "http://foo.com/bar"},
+ {"http://foo.com/", "bar", "http://foo.com/bar"},
+ {"http://foo.com/bar/baz", "quux", "http://foo.com/bar/quux"},
+
+ // ... going up
+ {"http://foo.com/bar/baz", "../quux", "http://foo.com/quux"},
+ {"http://foo.com/bar/baz", "../../../../../quux", "http://foo.com/quux"},
+ {"http://foo.com/bar", "..", "http://foo.com/"},
+ {"http://foo.com/bar/baz", "./..", "http://foo.com/"},
+ // ".." in the middle (issue 3560)
+ {"http://foo.com/bar/baz", "quux/dotdot/../tail", "http://foo.com/bar/quux/tail"},
+ {"http://foo.com/bar/baz", "quux/./dotdot/../tail", "http://foo.com/bar/quux/tail"},
+ {"http://foo.com/bar/baz", "quux/./dotdot/.././tail", "http://foo.com/bar/quux/tail"},
+ {"http://foo.com/bar/baz", "quux/./dotdot/./../tail", "http://foo.com/bar/quux/tail"},
+ {"http://foo.com/bar/baz", "quux/./dotdot/dotdot/././../../tail", "http://foo.com/bar/quux/tail"},
+ {"http://foo.com/bar/baz", "quux/./dotdot/dotdot/./.././../tail", "http://foo.com/bar/quux/tail"},
+ {"http://foo.com/bar/baz", "quux/./dotdot/dotdot/dotdot/./../../.././././tail", "http://foo.com/bar/quux/tail"},
+ {"http://foo.com/bar/baz", "quux/./dotdot/../dotdot/../dot/./tail/..", "http://foo.com/bar/quux/dot/"},
+
+ // Remove any dot-segments prior to forming the target URI.
+ // http://tools.ietf.org/html/rfc3986#section-5.2.4
+ {"http://foo.com/dot/./dotdot/../foo/bar", "../baz", "http://foo.com/dot/baz"},
+
+ // Triple dot isn't special
+ {"http://foo.com/bar", "...", "http://foo.com/..."},
+
+ // Fragment
+ {"http://foo.com/bar", ".#frag", "http://foo.com/#frag"},
+
+ // RFC 3986: Normal Examples
+ // http://tools.ietf.org/html/rfc3986#section-5.4.1
+ {"http://a/b/c/d;p?q", "g:h", "g:h"},
+ {"http://a/b/c/d;p?q", "g", "http://a/b/c/g"},
+ {"http://a/b/c/d;p?q", "./g", "http://a/b/c/g"},
+ {"http://a/b/c/d;p?q", "g/", "http://a/b/c/g/"},
+ {"http://a/b/c/d;p?q", "/g", "http://a/g"},
+ {"http://a/b/c/d;p?q", "//g", "http://g"},
+ {"http://a/b/c/d;p?q", "?y", "http://a/b/c/d;p?y"},
+ {"http://a/b/c/d;p?q", "g?y", "http://a/b/c/g?y"},
+ {"http://a/b/c/d;p?q", "#s", "http://a/b/c/d;p?q#s"},
+ {"http://a/b/c/d;p?q", "g#s", "http://a/b/c/g#s"},
+ {"http://a/b/c/d;p?q", "g?y#s", "http://a/b/c/g?y#s"},
+ {"http://a/b/c/d;p?q", ";x", "http://a/b/c/;x"},
+ {"http://a/b/c/d;p?q", "g;x", "http://a/b/c/g;x"},
+ {"http://a/b/c/d;p?q", "g;x?y#s", "http://a/b/c/g;x?y#s"},
+ {"http://a/b/c/d;p?q", "", "http://a/b/c/d;p?q"},
+ {"http://a/b/c/d;p?q", ".", "http://a/b/c/"},
+ {"http://a/b/c/d;p?q", "./", "http://a/b/c/"},
+ {"http://a/b/c/d;p?q", "..", "http://a/b/"},
+ {"http://a/b/c/d;p?q", "../", "http://a/b/"},
+ {"http://a/b/c/d;p?q", "../g", "http://a/b/g"},
+ {"http://a/b/c/d;p?q", "../..", "http://a/"},
+ {"http://a/b/c/d;p?q", "../../", "http://a/"},
+ {"http://a/b/c/d;p?q", "../../g", "http://a/g"},
+
+ // RFC 3986: Abnormal Examples
+ // http://tools.ietf.org/html/rfc3986#section-5.4.2
+ {"http://a/b/c/d;p?q", "../../../g", "http://a/g"},
+ {"http://a/b/c/d;p?q", "../../../../g", "http://a/g"},
+ {"http://a/b/c/d;p?q", "/./g", "http://a/g"},
+ {"http://a/b/c/d;p?q", "/../g", "http://a/g"},
+ {"http://a/b/c/d;p?q", "g.", "http://a/b/c/g."},
+ {"http://a/b/c/d;p?q", ".g", "http://a/b/c/.g"},
+ {"http://a/b/c/d;p?q", "g..", "http://a/b/c/g.."},
+ {"http://a/b/c/d;p?q", "..g", "http://a/b/c/..g"},
+ {"http://a/b/c/d;p?q", "./../g", "http://a/b/g"},
+ {"http://a/b/c/d;p?q", "./g/.", "http://a/b/c/g/"},
+ {"http://a/b/c/d;p?q", "g/./h", "http://a/b/c/g/h"},
+ {"http://a/b/c/d;p?q", "g/../h", "http://a/b/c/h"},
+ {"http://a/b/c/d;p?q", "g;x=1/./y", "http://a/b/c/g;x=1/y"},
+ {"http://a/b/c/d;p?q", "g;x=1/../y", "http://a/b/c/y"},
+ {"http://a/b/c/d;p?q", "g?y/./x", "http://a/b/c/g?y/./x"},
+ {"http://a/b/c/d;p?q", "g?y/../x", "http://a/b/c/g?y/../x"},
+ {"http://a/b/c/d;p?q", "g#s/./x", "http://a/b/c/g#s/./x"},
+ {"http://a/b/c/d;p?q", "g#s/../x", "http://a/b/c/g#s/../x"},
+
+ // Extras.
+ {"https://a/b/c/d;p?q", "//g?q", "https://g?q"},
+ {"https://a/b/c/d;p?q", "//g#s", "https://g#s"},
+ {"https://a/b/c/d;p?q", "//g/d/e/f?y#s", "https://g/d/e/f?y#s"},
+ {"https://a/b/c/d;p#s", "?y", "https://a/b/c/d;p?y"},
+ {"https://a/b/c/d;p?q#s", "?y", "https://a/b/c/d;p?y"},
+}
+
+func TestResolveReference(t *testing.T) {
+ mustParse := func(url_ string) *url.URL {
+ u, err := url.Parse(url_)
+ if err != nil {
+ t.Fatalf("Expected URL to parse: %q, got error: %v", url_, err)
+ }
+ return u
+ }
+ opaque := &url.URL{Scheme: "scheme", Opaque: "opaque"}
+ for _, test := range resolveReferenceTests {
+ base := mustParse(test.base)
+ rel := mustParse(test.rel)
+ url := base.ResolveReference(rel)
+ if Escape(url) != test.expected {
+ t.Errorf("URL(%q).ResolveReference(%q) == %q, got %q", test.base, test.rel, test.expected, Escape(url))
+ }
+ // Ensure that new instances are returned.
+ if base == url {
+ t.Errorf("Expected URL.ResolveReference to return new URL instance.")
+ }
+ // Test the convenience wrapper too.
+ url, err := base.Parse(test.rel)
+ if err != nil {
+ t.Errorf("URL(%q).Parse(%q) failed: %v", test.base, test.rel, err)
+ } else if Escape(url) != test.expected {
+ t.Errorf("URL(%q).Parse(%q) == %q, got %q", test.base, test.rel, test.expected, Escape(url))
+ } else if base == url {
+ // Ensure that new instances are returned for the wrapper too.
+ t.Errorf("Expected URL.Parse to return new URL instance.")
+ }
+ // Ensure Opaque resets the URL.
+ url = base.ResolveReference(opaque)
+ if *url != *opaque {
+ t.Errorf("ResolveReference failed to resolve opaque URL: want %#v, got %#v", url, opaque)
+ }
+ // Test the convenience wrapper with an opaque URL too.
+ url, err = base.Parse("scheme:opaque")
+ if err != nil {
+ t.Errorf(`URL(%q).Parse("scheme:opaque") failed: %v`, test.base, err)
+ } else if *url != *opaque {
+ t.Errorf("Parse failed to resolve opaque URL: want %#v, got %#v", url, opaque)
+ } else if base == url {
+ // Ensure that new instances are returned, again.
+ t.Errorf("Expected URL.Parse to return new URL instance.")
+ }
+ }
+}
+
+type shouldEscapeTest struct {
+ in byte
+ mode encoding
+ escape bool
+}
+
+var shouldEscapeTests = []shouldEscapeTest{
+ // Unreserved characters (§2.3)
+ {'a', encodePath, false},
+ {'a', encodeUserPassword, false},
+ {'a', encodeQueryComponent, false},
+ {'a', encodeFragment, false},
+ {'z', encodePath, false},
+ {'A', encodePath, false},
+ {'Z', encodePath, false},
+ {'0', encodePath, false},
+ {'9', encodePath, false},
+ {'-', encodePath, false},
+ {'-', encodeUserPassword, false},
+ {'-', encodeQueryComponent, false},
+ {'-', encodeFragment, false},
+ {'.', encodePath, false},
+ {'_', encodePath, false},
+ {'~', encodePath, false},
+
+ // User information (§3.2.1)
+ {':', encodeUserPassword, true},
+ {'/', encodeUserPassword, true},
+ {'?', encodeUserPassword, true},
+ {'@', encodeUserPassword, true},
+ {'$', encodeUserPassword, false},
+ {'&', encodeUserPassword, false},
+ {'+', encodeUserPassword, false},
+ {',', encodeUserPassword, false},
+ {';', encodeUserPassword, false},
+ {'=', encodeUserPassword, false},
+}
+
+func TestShouldEscape(t *testing.T) {
+ for _, tt := range shouldEscapeTests {
+ if shouldEscape(tt.in, tt.mode) != tt.escape {
+ t.Errorf("shouldEscape(%q, %v) returned %v; expected %v", tt.in, tt.mode, !tt.escape, tt.escape)
+ }
+ }
+}
diff --git a/vendor/github.com/beorn7/perks/.gitignore b/vendor/github.com/beorn7/perks/.gitignore
new file mode 100644
index 00000000000..1bd9209aa19
--- /dev/null
+++ b/vendor/github.com/beorn7/perks/.gitignore
@@ -0,0 +1,2 @@
+*.test
+*.prof
diff --git a/vendor/github.com/beorn7/perks/LICENSE b/vendor/github.com/beorn7/perks/LICENSE
new file mode 100644
index 00000000000..339177be663
--- /dev/null
+++ b/vendor/github.com/beorn7/perks/LICENSE
@@ -0,0 +1,20 @@
+Copyright (C) 2013 Blake Mizerany
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/vendor/github.com/beorn7/perks/README.md b/vendor/github.com/beorn7/perks/README.md
new file mode 100644
index 00000000000..fc05777701a
--- /dev/null
+++ b/vendor/github.com/beorn7/perks/README.md
@@ -0,0 +1,31 @@
+# Perks for Go (golang.org)
+
+Perks contains the Go package quantile that computes approximate quantiles over
+an unbounded data stream within low memory and CPU bounds.
+
+For more information and examples, see:
+http://godoc.org/github.com/bmizerany/perks
+
+A very special thank you and shout out to Graham Cormode (Rutgers University),
+Flip Korn (AT&T Labs–Research), S. Muthukrishnan (Rutgers University), and
+Divesh Srivastava (AT&T Labs–Research) for their research and publication of
+[Effective Computation of Biased Quantiles over Data Streams](http://www.cs.rutgers.edu/~muthu/bquant.pdf)
+
+Thank you, also:
+* Armon Dadgar (@armon)
+* Andrew Gerrand (@nf)
+* Brad Fitzpatrick (@bradfitz)
+* Keith Rarick (@kr)
+
+FAQ:
+
+Q: Why not move the quantile package into the project root?
+A: I want to add more packages to perks later.
+
+Copyright (C) 2013 Blake Mizerany
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/vendor/github.com/beorn7/perks/quantile/BUILD.bazel b/vendor/github.com/beorn7/perks/quantile/BUILD.bazel
new file mode 100644
index 00000000000..24d9185c238
--- /dev/null
+++ b/vendor/github.com/beorn7/perks/quantile/BUILD.bazel
@@ -0,0 +1,25 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
+
+go_library(
+ name = "go_default_library",
+ srcs = ["stream.go"],
+ importpath = "github.com/beorn7/perks/quantile",
+ visibility = ["//visibility:public"],
+)
+
+go_test(
+ name = "go_default_test",
+ srcs = [
+ "bench_test.go",
+ "stream_test.go",
+ ],
+ embed = [":go_default_library"],
+ importpath = "github.com/beorn7/perks/quantile",
+)
+
+go_test(
+ name = "go_default_xtest",
+ srcs = ["example_test.go"],
+ importpath = "github.com/beorn7/perks/quantile_test",
+ deps = [":go_default_library"],
+)
diff --git a/vendor/github.com/beorn7/perks/quantile/bench_test.go b/vendor/github.com/beorn7/perks/quantile/bench_test.go
new file mode 100644
index 00000000000..0bd0e4e7752
--- /dev/null
+++ b/vendor/github.com/beorn7/perks/quantile/bench_test.go
@@ -0,0 +1,63 @@
+package quantile
+
+import (
+ "testing"
+)
+
+func BenchmarkInsertTargeted(b *testing.B) {
+ b.ReportAllocs()
+
+ s := NewTargeted(Targets)
+ b.ResetTimer()
+ for i := float64(0); i < float64(b.N); i++ {
+ s.Insert(i)
+ }
+}
+
+func BenchmarkInsertTargetedSmallEpsilon(b *testing.B) {
+ s := NewTargeted(TargetsSmallEpsilon)
+ b.ResetTimer()
+ for i := float64(0); i < float64(b.N); i++ {
+ s.Insert(i)
+ }
+}
+
+func BenchmarkInsertBiased(b *testing.B) {
+ s := NewLowBiased(0.01)
+ b.ResetTimer()
+ for i := float64(0); i < float64(b.N); i++ {
+ s.Insert(i)
+ }
+}
+
+func BenchmarkInsertBiasedSmallEpsilon(b *testing.B) {
+ s := NewLowBiased(0.0001)
+ b.ResetTimer()
+ for i := float64(0); i < float64(b.N); i++ {
+ s.Insert(i)
+ }
+}
+
+func BenchmarkQuery(b *testing.B) {
+ s := NewTargeted(Targets)
+ for i := float64(0); i < 1e6; i++ {
+ s.Insert(i)
+ }
+ b.ResetTimer()
+ n := float64(b.N)
+ for i := float64(0); i < n; i++ {
+ s.Query(i / n)
+ }
+}
+
+func BenchmarkQuerySmallEpsilon(b *testing.B) {
+ s := NewTargeted(TargetsSmallEpsilon)
+ for i := float64(0); i < 1e6; i++ {
+ s.Insert(i)
+ }
+ b.ResetTimer()
+ n := float64(b.N)
+ for i := float64(0); i < n; i++ {
+ s.Query(i / n)
+ }
+}
diff --git a/vendor/github.com/beorn7/perks/quantile/example_test.go b/vendor/github.com/beorn7/perks/quantile/example_test.go
new file mode 100644
index 00000000000..ab3293aaf2a
--- /dev/null
+++ b/vendor/github.com/beorn7/perks/quantile/example_test.go
@@ -0,0 +1,121 @@
+// +build go1.1
+
+package quantile_test
+
+import (
+ "bufio"
+ "fmt"
+ "log"
+ "os"
+ "strconv"
+ "time"
+
+ "github.com/beorn7/perks/quantile"
+)
+
+func Example_simple() {
+ ch := make(chan float64)
+ go sendFloats(ch)
+
+ // Compute the 50th, 90th, and 99th percentile.
+ q := quantile.NewTargeted(map[float64]float64{
+ 0.50: 0.005,
+ 0.90: 0.001,
+ 0.99: 0.0001,
+ })
+ for v := range ch {
+ q.Insert(v)
+ }
+
+ fmt.Println("perc50:", q.Query(0.50))
+ fmt.Println("perc90:", q.Query(0.90))
+ fmt.Println("perc99:", q.Query(0.99))
+ fmt.Println("count:", q.Count())
+ // Output:
+ // perc50: 5
+ // perc90: 16
+ // perc99: 223
+ // count: 2388
+}
+
+func Example_mergeMultipleStreams() {
+ // Scenario:
+ // We have multiple database shards. On each shard, there is a process
+ // collecting query response times from the database logs and inserting
+ // them into a Stream (created via NewTargeted(0.90)), much like the
+ // Simple example. These processes expose a network interface for us to
+ // ask them to serialize and send us the results of their
+ // Stream.Samples so we may Merge and Query them.
+ //
+ // NOTES:
+ // * These sample sets are small, allowing us to get them
+ // across the network much faster than sending the entire list of data
+ // points.
+ //
+ // * For this to work correctly, we must supply the same quantiles
+ // a priori the process collecting the samples supplied to NewTargeted,
+ // even if we do not plan to query them all here.
+ ch := make(chan quantile.Samples)
+ getDBQuerySamples(ch)
+ q := quantile.NewTargeted(map[float64]float64{0.90: 0.001})
+ for samples := range ch {
+ q.Merge(samples)
+ }
+ fmt.Println("perc90:", q.Query(0.90))
+}
+
+func Example_window() {
+ // Scenario: We want the 90th, 95th, and 99th percentiles for each
+ // minute.
+
+ ch := make(chan float64)
+ go sendStreamValues(ch)
+
+ tick := time.NewTicker(1 * time.Minute)
+ q := quantile.NewTargeted(map[float64]float64{
+ 0.90: 0.001,
+ 0.95: 0.0005,
+ 0.99: 0.0001,
+ })
+ for {
+ select {
+ case t := <-tick.C:
+ flushToDB(t, q.Samples())
+ q.Reset()
+ case v := <-ch:
+ q.Insert(v)
+ }
+ }
+}
+
+func sendStreamValues(ch chan float64) {
+ // Use your imagination
+}
+
+func flushToDB(t time.Time, samples quantile.Samples) {
+ // Use your imagination
+}
+
+// This is a stub for the above example. In reality this would hit the remote
+// servers via http or something like it.
+func getDBQuerySamples(ch chan quantile.Samples) {}
+
+func sendFloats(ch chan<- float64) {
+ f, err := os.Open("exampledata.txt")
+ if err != nil {
+ log.Fatal(err)
+ }
+ sc := bufio.NewScanner(f)
+ for sc.Scan() {
+ b := sc.Bytes()
+ v, err := strconv.ParseFloat(string(b), 64)
+ if err != nil {
+ log.Fatal(err)
+ }
+ ch <- v
+ }
+ if sc.Err() != nil {
+ log.Fatal(sc.Err())
+ }
+ close(ch)
+}
diff --git a/vendor/github.com/beorn7/perks/quantile/exampledata.txt b/vendor/github.com/beorn7/perks/quantile/exampledata.txt
new file mode 100644
index 00000000000..1602287d7ce
--- /dev/null
+++ b/vendor/github.com/beorn7/perks/quantile/exampledata.txt
@@ -0,0 +1,2388 @@
+8
+5
+26
+12
+5
+235
+13
+6
+28
+30
+3
+3
+3
+3
+5
+2
+33
+7
+2
+4
+7
+12
+14
+5
+8
+3
+10
+4
+5
+3
+6
+6
+209
+20
+3
+10
+14
+3
+4
+6
+8
+5
+11
+7
+3
+2
+3
+3
+212
+5
+222
+4
+10
+10
+5
+6
+3
+8
+3
+10
+254
+220
+2
+3
+5
+24
+5
+4
+222
+7
+3
+3
+223
+8
+15
+12
+14
+14
+3
+2
+2
+3
+13
+3
+11
+4
+4
+6
+5
+7
+13
+5
+3
+5
+2
+5
+3
+5
+2
+7
+15
+17
+14
+3
+6
+6
+3
+17
+5
+4
+7
+6
+4
+4
+8
+6
+8
+3
+9
+3
+6
+3
+4
+5
+3
+3
+660
+4
+6
+10
+3
+6
+3
+2
+5
+13
+2
+4
+4
+10
+4
+8
+4
+3
+7
+9
+9
+3
+10
+37
+3
+13
+4
+12
+3
+6
+10
+8
+5
+21
+2
+3
+8
+3
+2
+3
+3
+4
+12
+2
+4
+8
+8
+4
+3
+2
+20
+1
+6
+32
+2
+11
+6
+18
+3
+8
+11
+3
+212
+3
+4
+2
+6
+7
+12
+11
+3
+2
+16
+10
+6
+4
+6
+3
+2
+7
+3
+2
+2
+2
+2
+5
+6
+4
+3
+10
+3
+4
+6
+5
+3
+4
+4
+5
+6
+4
+3
+4
+4
+5
+7
+5
+5
+3
+2
+7
+2
+4
+12
+4
+5
+6
+2
+4
+4
+8
+4
+15
+13
+7
+16
+5
+3
+23
+5
+5
+7
+3
+2
+9
+8
+7
+5
+8
+11
+4
+10
+76
+4
+47
+4
+3
+2
+7
+4
+2
+3
+37
+10
+4
+2
+20
+5
+4
+4
+10
+10
+4
+3
+7
+23
+240
+7
+13
+5
+5
+3
+3
+2
+5
+4
+2
+8
+7
+19
+2
+23
+8
+7
+2
+5
+3
+8
+3
+8
+13
+5
+5
+5
+2
+3
+23
+4
+9
+8
+4
+3
+3
+5
+220
+2
+3
+4
+6
+14
+3
+53
+6
+2
+5
+18
+6
+3
+219
+6
+5
+2
+5
+3
+6
+5
+15
+4
+3
+17
+3
+2
+4
+7
+2
+3
+3
+4
+4
+3
+2
+664
+6
+3
+23
+5
+5
+16
+5
+8
+2
+4
+2
+24
+12
+3
+2
+3
+5
+8
+3
+5
+4
+3
+14
+3
+5
+8
+2
+3
+7
+9
+4
+2
+3
+6
+8
+4
+3
+4
+6
+5
+3
+3
+6
+3
+19
+4
+4
+6
+3
+6
+3
+5
+22
+5
+4
+4
+3
+8
+11
+4
+9
+7
+6
+13
+4
+4
+4
+6
+17
+9
+3
+3
+3
+4
+3
+221
+5
+11
+3
+4
+2
+12
+6
+3
+5
+7
+5
+7
+4
+9
+7
+14
+37
+19
+217
+16
+3
+5
+2
+2
+7
+19
+7
+6
+7
+4
+24
+5
+11
+4
+7
+7
+9
+13
+3
+4
+3
+6
+28
+4
+4
+5
+5
+2
+5
+6
+4
+4
+6
+10
+5
+4
+3
+2
+3
+3
+6
+5
+5
+4
+3
+2
+3
+7
+4
+6
+18
+16
+8
+16
+4
+5
+8
+6
+9
+13
+1545
+6
+215
+6
+5
+6
+3
+45
+31
+5
+2
+2
+4
+3
+3
+2
+5
+4
+3
+5
+7
+7
+4
+5
+8
+5
+4
+749
+2
+31
+9
+11
+2
+11
+5
+4
+4
+7
+9
+11
+4
+5
+4
+7
+3
+4
+6
+2
+15
+3
+4
+3
+4
+3
+5
+2
+13
+5
+5
+3
+3
+23
+4
+4
+5
+7
+4
+13
+2
+4
+3
+4
+2
+6
+2
+7
+3
+5
+5
+3
+29
+5
+4
+4
+3
+10
+2
+3
+79
+16
+6
+6
+7
+7
+3
+5
+5
+7
+4
+3
+7
+9
+5
+6
+5
+9
+6
+3
+6
+4
+17
+2
+10
+9
+3
+6
+2
+3
+21
+22
+5
+11
+4
+2
+17
+2
+224
+2
+14
+3
+4
+4
+2
+4
+4
+4
+4
+5
+3
+4
+4
+10
+2
+6
+3
+3
+5
+7
+2
+7
+5
+6
+3
+218
+2
+2
+5
+2
+6
+3
+5
+222
+14
+6
+33
+3
+2
+5
+3
+3
+3
+9
+5
+3
+3
+2
+7
+4
+3
+4
+3
+5
+6
+5
+26
+4
+13
+9
+7
+3
+221
+3
+3
+4
+4
+4
+4
+2
+18
+5
+3
+7
+9
+6
+8
+3
+10
+3
+11
+9
+5
+4
+17
+5
+5
+6
+6
+3
+2
+4
+12
+17
+6
+7
+218
+4
+2
+4
+10
+3
+5
+15
+3
+9
+4
+3
+3
+6
+29
+3
+3
+4
+5
+5
+3
+8
+5
+6
+6
+7
+5
+3
+5
+3
+29
+2
+31
+5
+15
+24
+16
+5
+207
+4
+3
+3
+2
+15
+4
+4
+13
+5
+5
+4
+6
+10
+2
+7
+8
+4
+6
+20
+5
+3
+4
+3
+12
+12
+5
+17
+7
+3
+3
+3
+6
+10
+3
+5
+25
+80
+4
+9
+3
+2
+11
+3
+3
+2
+3
+8
+7
+5
+5
+19
+5
+3
+3
+12
+11
+2
+6
+5
+5
+5
+3
+3
+3
+4
+209
+14
+3
+2
+5
+19
+4
+4
+3
+4
+14
+5
+6
+4
+13
+9
+7
+4
+7
+10
+2
+9
+5
+7
+2
+8
+4
+6
+5
+5
+222
+8
+7
+12
+5
+216
+3
+4
+4
+6
+3
+14
+8
+7
+13
+4
+3
+3
+3
+3
+17
+5
+4
+3
+33
+6
+6
+33
+7
+5
+3
+8
+7
+5
+2
+9
+4
+2
+233
+24
+7
+4
+8
+10
+3
+4
+15
+2
+16
+3
+3
+13
+12
+7
+5
+4
+207
+4
+2
+4
+27
+15
+2
+5
+2
+25
+6
+5
+5
+6
+13
+6
+18
+6
+4
+12
+225
+10
+7
+5
+2
+2
+11
+4
+14
+21
+8
+10
+3
+5
+4
+232
+2
+5
+5
+3
+7
+17
+11
+6
+6
+23
+4
+6
+3
+5
+4
+2
+17
+3
+6
+5
+8
+3
+2
+2
+14
+9
+4
+4
+2
+5
+5
+3
+7
+6
+12
+6
+10
+3
+6
+2
+2
+19
+5
+4
+4
+9
+2
+4
+13
+3
+5
+6
+3
+6
+5
+4
+9
+6
+3
+5
+7
+3
+6
+6
+4
+3
+10
+6
+3
+221
+3
+5
+3
+6
+4
+8
+5
+3
+6
+4
+4
+2
+54
+5
+6
+11
+3
+3
+4
+4
+4
+3
+7
+3
+11
+11
+7
+10
+6
+13
+223
+213
+15
+231
+7
+3
+7
+228
+2
+3
+4
+4
+5
+6
+7
+4
+13
+3
+4
+5
+3
+6
+4
+6
+7
+2
+4
+3
+4
+3
+3
+6
+3
+7
+3
+5
+18
+5
+6
+8
+10
+3
+3
+3
+2
+4
+2
+4
+4
+5
+6
+6
+4
+10
+13
+3
+12
+5
+12
+16
+8
+4
+19
+11
+2
+4
+5
+6
+8
+5
+6
+4
+18
+10
+4
+2
+216
+6
+6
+6
+2
+4
+12
+8
+3
+11
+5
+6
+14
+5
+3
+13
+4
+5
+4
+5
+3
+28
+6
+3
+7
+219
+3
+9
+7
+3
+10
+6
+3
+4
+19
+5
+7
+11
+6
+15
+19
+4
+13
+11
+3
+7
+5
+10
+2
+8
+11
+2
+6
+4
+6
+24
+6
+3
+3
+3
+3
+6
+18
+4
+11
+4
+2
+5
+10
+8
+3
+9
+5
+3
+4
+5
+6
+2
+5
+7
+4
+4
+14
+6
+4
+4
+5
+5
+7
+2
+4
+3
+7
+3
+3
+6
+4
+5
+4
+4
+4
+3
+3
+3
+3
+8
+14
+2
+3
+5
+3
+2
+4
+5
+3
+7
+3
+3
+18
+3
+4
+4
+5
+7
+3
+3
+3
+13
+5
+4
+8
+211
+5
+5
+3
+5
+2
+5
+4
+2
+655
+6
+3
+5
+11
+2
+5
+3
+12
+9
+15
+11
+5
+12
+217
+2
+6
+17
+3
+3
+207
+5
+5
+4
+5
+9
+3
+2
+8
+5
+4
+3
+2
+5
+12
+4
+14
+5
+4
+2
+13
+5
+8
+4
+225
+4
+3
+4
+5
+4
+3
+3
+6
+23
+9
+2
+6
+7
+233
+4
+4
+6
+18
+3
+4
+6
+3
+4
+4
+2
+3
+7
+4
+13
+227
+4
+3
+5
+4
+2
+12
+9
+17
+3
+7
+14
+6
+4
+5
+21
+4
+8
+9
+2
+9
+25
+16
+3
+6
+4
+7
+8
+5
+2
+3
+5
+4
+3
+3
+5
+3
+3
+3
+2
+3
+19
+2
+4
+3
+4
+2
+3
+4
+4
+2
+4
+3
+3
+3
+2
+6
+3
+17
+5
+6
+4
+3
+13
+5
+3
+3
+3
+4
+9
+4
+2
+14
+12
+4
+5
+24
+4
+3
+37
+12
+11
+21
+3
+4
+3
+13
+4
+2
+3
+15
+4
+11
+4
+4
+3
+8
+3
+4
+4
+12
+8
+5
+3
+3
+4
+2
+220
+3
+5
+223
+3
+3
+3
+10
+3
+15
+4
+241
+9
+7
+3
+6
+6
+23
+4
+13
+7
+3
+4
+7
+4
+9
+3
+3
+4
+10
+5
+5
+1
+5
+24
+2
+4
+5
+5
+6
+14
+3
+8
+2
+3
+5
+13
+13
+3
+5
+2
+3
+15
+3
+4
+2
+10
+4
+4
+4
+5
+5
+3
+5
+3
+4
+7
+4
+27
+3
+6
+4
+15
+3
+5
+6
+6
+5
+4
+8
+3
+9
+2
+6
+3
+4
+3
+7
+4
+18
+3
+11
+3
+3
+8
+9
+7
+24
+3
+219
+7
+10
+4
+5
+9
+12
+2
+5
+4
+4
+4
+3
+3
+19
+5
+8
+16
+8
+6
+22
+3
+23
+3
+242
+9
+4
+3
+3
+5
+7
+3
+3
+5
+8
+3
+7
+5
+14
+8
+10
+3
+4
+3
+7
+4
+6
+7
+4
+10
+4
+3
+11
+3
+7
+10
+3
+13
+6
+8
+12
+10
+5
+7
+9
+3
+4
+7
+7
+10
+8
+30
+9
+19
+4
+3
+19
+15
+4
+13
+3
+215
+223
+4
+7
+4
+8
+17
+16
+3
+7
+6
+5
+5
+4
+12
+3
+7
+4
+4
+13
+4
+5
+2
+5
+6
+5
+6
+6
+7
+10
+18
+23
+9
+3
+3
+6
+5
+2
+4
+2
+7
+3
+3
+2
+5
+5
+14
+10
+224
+6
+3
+4
+3
+7
+5
+9
+3
+6
+4
+2
+5
+11
+4
+3
+3
+2
+8
+4
+7
+4
+10
+7
+3
+3
+18
+18
+17
+3
+3
+3
+4
+5
+3
+3
+4
+12
+7
+3
+11
+13
+5
+4
+7
+13
+5
+4
+11
+3
+12
+3
+6
+4
+4
+21
+4
+6
+9
+5
+3
+10
+8
+4
+6
+4
+4
+6
+5
+4
+8
+6
+4
+6
+4
+4
+5
+9
+6
+3
+4
+2
+9
+3
+18
+2
+4
+3
+13
+3
+6
+6
+8
+7
+9
+3
+2
+16
+3
+4
+6
+3
+2
+33
+22
+14
+4
+9
+12
+4
+5
+6
+3
+23
+9
+4
+3
+5
+5
+3
+4
+5
+3
+5
+3
+10
+4
+5
+5
+8
+4
+4
+6
+8
+5
+4
+3
+4
+6
+3
+3
+3
+5
+9
+12
+6
+5
+9
+3
+5
+3
+2
+2
+2
+18
+3
+2
+21
+2
+5
+4
+6
+4
+5
+10
+3
+9
+3
+2
+10
+7
+3
+6
+6
+4
+4
+8
+12
+7
+3
+7
+3
+3
+9
+3
+4
+5
+4
+4
+5
+5
+10
+15
+4
+4
+14
+6
+227
+3
+14
+5
+216
+22
+5
+4
+2
+2
+6
+3
+4
+2
+9
+9
+4
+3
+28
+13
+11
+4
+5
+3
+3
+2
+3
+3
+5
+3
+4
+3
+5
+23
+26
+3
+4
+5
+6
+4
+6
+3
+5
+5
+3
+4
+3
+2
+2
+2
+7
+14
+3
+6
+7
+17
+2
+2
+15
+14
+16
+4
+6
+7
+13
+6
+4
+5
+6
+16
+3
+3
+28
+3
+6
+15
+3
+9
+2
+4
+6
+3
+3
+22
+4
+12
+6
+7
+2
+5
+4
+10
+3
+16
+6
+9
+2
+5
+12
+7
+5
+5
+5
+5
+2
+11
+9
+17
+4
+3
+11
+7
+3
+5
+15
+4
+3
+4
+211
+8
+7
+5
+4
+7
+6
+7
+6
+3
+6
+5
+6
+5
+3
+4
+4
+26
+4
+6
+10
+4
+4
+3
+2
+3
+3
+4
+5
+9
+3
+9
+4
+4
+5
+5
+8
+2
+4
+2
+3
+8
+4
+11
+19
+5
+8
+6
+3
+5
+6
+12
+3
+2
+4
+16
+12
+3
+4
+4
+8
+6
+5
+6
+6
+219
+8
+222
+6
+16
+3
+13
+19
+5
+4
+3
+11
+6
+10
+4
+7
+7
+12
+5
+3
+3
+5
+6
+10
+3
+8
+2
+5
+4
+7
+2
+4
+4
+2
+12
+9
+6
+4
+2
+40
+2
+4
+10
+4
+223
+4
+2
+20
+6
+7
+24
+5
+4
+5
+2
+20
+16
+6
+5
+13
+2
+3
+3
+19
+3
+2
+4
+5
+6
+7
+11
+12
+5
+6
+7
+7
+3
+5
+3
+5
+3
+14
+3
+4
+4
+2
+11
+1
+7
+3
+9
+6
+11
+12
+5
+8
+6
+221
+4
+2
+12
+4
+3
+15
+4
+5
+226
+7
+218
+7
+5
+4
+5
+18
+4
+5
+9
+4
+4
+2
+9
+18
+18
+9
+5
+6
+6
+3
+3
+7
+3
+5
+4
+4
+4
+12
+3
+6
+31
+5
+4
+7
+3
+6
+5
+6
+5
+11
+2
+2
+11
+11
+6
+7
+5
+8
+7
+10
+5
+23
+7
+4
+3
+5
+34
+2
+5
+23
+7
+3
+6
+8
+4
+4
+4
+2
+5
+3
+8
+5
+4
+8
+25
+2
+3
+17
+8
+3
+4
+8
+7
+3
+15
+6
+5
+7
+21
+9
+5
+6
+6
+5
+3
+2
+3
+10
+3
+6
+3
+14
+7
+4
+4
+8
+7
+8
+2
+6
+12
+4
+213
+6
+5
+21
+8
+2
+5
+23
+3
+11
+2
+3
+6
+25
+2
+3
+6
+7
+6
+6
+4
+4
+6
+3
+17
+9
+7
+6
+4
+3
+10
+7
+2
+3
+3
+3
+11
+8
+3
+7
+6
+4
+14
+36
+3
+4
+3
+3
+22
+13
+21
+4
+2
+7
+4
+4
+17
+15
+3
+7
+11
+2
+4
+7
+6
+209
+6
+3
+2
+2
+24
+4
+9
+4
+3
+3
+3
+29
+2
+2
+4
+3
+3
+5
+4
+6
+3
+3
+2
+4
diff --git a/vendor/github.com/beorn7/perks/quantile/stream.go b/vendor/github.com/beorn7/perks/quantile/stream.go
new file mode 100644
index 00000000000..f4cabd66956
--- /dev/null
+++ b/vendor/github.com/beorn7/perks/quantile/stream.go
@@ -0,0 +1,292 @@
+// Package quantile computes approximate quantiles over an unbounded data
+// stream within low memory and CPU bounds.
+//
+// A small amount of accuracy is traded to achieve the above properties.
+//
+// Multiple streams can be merged before calling Query to generate a single set
+// of results. This is meaningful when the streams represent the same type of
+// data. See Merge and Samples.
+//
+// For more detailed information about the algorithm used, see:
+//
+// Effective Computation of Biased Quantiles over Data Streams
+//
+// http://www.cs.rutgers.edu/~muthu/bquant.pdf
+package quantile
+
+import (
+ "math"
+ "sort"
+)
+
+// Sample holds an observed value and meta information for compression. JSON
+// tags have been added for convenience.
+type Sample struct {
+ Value float64 `json:",string"`
+ Width float64 `json:",string"`
+ Delta float64 `json:",string"`
+}
+
+// Samples represents a slice of samples. It implements sort.Interface.
+type Samples []Sample
+
+func (a Samples) Len() int { return len(a) }
+func (a Samples) Less(i, j int) bool { return a[i].Value < a[j].Value }
+func (a Samples) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
+
+type invariant func(s *stream, r float64) float64
+
+// NewLowBiased returns an initialized Stream for low-biased quantiles
+// (e.g. 0.01, 0.1, 0.5) where the needed quantiles are not known a priori, but
+// error guarantees can still be given even for the lower ranks of the data
+// distribution.
+//
+// The provided epsilon is a relative error, i.e. the true quantile of a value
+// returned by a query is guaranteed to be within (1±Epsilon)*Quantile.
+//
+// See http://www.cs.rutgers.edu/~muthu/bquant.pdf for time, space, and error
+// properties.
+func NewLowBiased(epsilon float64) *Stream {
+ ƒ := func(s *stream, r float64) float64 {
+ return 2 * epsilon * r
+ }
+ return newStream(ƒ)
+}
+
+// NewHighBiased returns an initialized Stream for high-biased quantiles
+// (e.g. 0.01, 0.1, 0.5) where the needed quantiles are not known a priori, but
+// error guarantees can still be given even for the higher ranks of the data
+// distribution.
+//
+// The provided epsilon is a relative error, i.e. the true quantile of a value
+// returned by a query is guaranteed to be within 1-(1±Epsilon)*(1-Quantile).
+//
+// See http://www.cs.rutgers.edu/~muthu/bquant.pdf for time, space, and error
+// properties.
+func NewHighBiased(epsilon float64) *Stream {
+ ƒ := func(s *stream, r float64) float64 {
+ return 2 * epsilon * (s.n - r)
+ }
+ return newStream(ƒ)
+}
+
+// NewTargeted returns an initialized Stream concerned with a particular set of
+// quantile values that are supplied a priori. Knowing these a priori reduces
+// space and computation time. The targets map maps the desired quantiles to
+// their absolute errors, i.e. the true quantile of a value returned by a query
+// is guaranteed to be within (Quantile±Epsilon).
+//
+// See http://www.cs.rutgers.edu/~muthu/bquant.pdf for time, space, and error properties.
+func NewTargeted(targets map[float64]float64) *Stream {
+ ƒ := func(s *stream, r float64) float64 {
+ var m = math.MaxFloat64
+ var f float64
+ for quantile, epsilon := range targets {
+ if quantile*s.n <= r {
+ f = (2 * epsilon * r) / quantile
+ } else {
+ f = (2 * epsilon * (s.n - r)) / (1 - quantile)
+ }
+ if f < m {
+ m = f
+ }
+ }
+ return m
+ }
+ return newStream(ƒ)
+}
+
+// Stream computes quantiles for a stream of float64s. It is not thread-safe by
+// design. Take care when using across multiple goroutines.
+type Stream struct {
+ *stream
+ b Samples
+ sorted bool
+}
+
+func newStream(ƒ invariant) *Stream {
+ x := &stream{ƒ: ƒ}
+ return &Stream{x, make(Samples, 0, 500), true}
+}
+
+// Insert inserts v into the stream.
+func (s *Stream) Insert(v float64) {
+ s.insert(Sample{Value: v, Width: 1})
+}
+
+func (s *Stream) insert(sample Sample) {
+ s.b = append(s.b, sample)
+ s.sorted = false
+ if len(s.b) == cap(s.b) {
+ s.flush()
+ }
+}
+
+// Query returns the computed qth percentiles value. If s was created with
+// NewTargeted, and q is not in the set of quantiles provided a priori, Query
+// will return an unspecified result.
+func (s *Stream) Query(q float64) float64 {
+ if !s.flushed() {
+ // Fast path when there hasn't been enough data for a flush;
+ // this also yields better accuracy for small sets of data.
+ l := len(s.b)
+ if l == 0 {
+ return 0
+ }
+ i := int(math.Ceil(float64(l) * q))
+ if i > 0 {
+ i -= 1
+ }
+ s.maybeSort()
+ return s.b[i].Value
+ }
+ s.flush()
+ return s.stream.query(q)
+}
+
+// Merge merges samples into the underlying streams samples. This is handy when
+// merging multiple streams from separate threads, database shards, etc.
+//
+// ATTENTION: This method is broken and does not yield correct results. The
+// underlying algorithm is not capable of merging streams correctly.
+func (s *Stream) Merge(samples Samples) {
+ sort.Sort(samples)
+ s.stream.merge(samples)
+}
+
+// Reset reinitializes and clears the list reusing the samples buffer memory.
+func (s *Stream) Reset() {
+ s.stream.reset()
+ s.b = s.b[:0]
+}
+
+// Samples returns stream samples held by s.
+func (s *Stream) Samples() Samples {
+ if !s.flushed() {
+ return s.b
+ }
+ s.flush()
+ return s.stream.samples()
+}
+
+// Count returns the total number of samples observed in the stream
+// since initialization.
+func (s *Stream) Count() int {
+ return len(s.b) + s.stream.count()
+}
+
+func (s *Stream) flush() {
+ s.maybeSort()
+ s.stream.merge(s.b)
+ s.b = s.b[:0]
+}
+
+func (s *Stream) maybeSort() {
+ if !s.sorted {
+ s.sorted = true
+ sort.Sort(s.b)
+ }
+}
+
+func (s *Stream) flushed() bool {
+ return len(s.stream.l) > 0
+}
+
+type stream struct {
+ n float64
+ l []Sample
+ ƒ invariant
+}
+
+func (s *stream) reset() {
+ s.l = s.l[:0]
+ s.n = 0
+}
+
+func (s *stream) insert(v float64) {
+ s.merge(Samples{{v, 1, 0}})
+}
+
+func (s *stream) merge(samples Samples) {
+ // TODO(beorn7): This tries to merge not only individual samples, but
+ // whole summaries. The paper doesn't mention merging summaries at
+ // all. Unittests show that the merging is inaccurate. Find out how to
+ // do merges properly.
+ var r float64
+ i := 0
+ for _, sample := range samples {
+ for ; i < len(s.l); i++ {
+ c := s.l[i]
+ if c.Value > sample.Value {
+ // Insert at position i.
+ s.l = append(s.l, Sample{})
+ copy(s.l[i+1:], s.l[i:])
+ s.l[i] = Sample{
+ sample.Value,
+ sample.Width,
+ math.Max(sample.Delta, math.Floor(s.ƒ(s, r))-1),
+ // TODO(beorn7): How to calculate delta correctly?
+ }
+ i++
+ goto inserted
+ }
+ r += c.Width
+ }
+ s.l = append(s.l, Sample{sample.Value, sample.Width, 0})
+ i++
+ inserted:
+ s.n += sample.Width
+ r += sample.Width
+ }
+ s.compress()
+}
+
+func (s *stream) count() int {
+ return int(s.n)
+}
+
+func (s *stream) query(q float64) float64 {
+ t := math.Ceil(q * s.n)
+ t += math.Ceil(s.ƒ(s, t) / 2)
+ p := s.l[0]
+ var r float64
+ for _, c := range s.l[1:] {
+ r += p.Width
+ if r+c.Width+c.Delta > t {
+ return p.Value
+ }
+ p = c
+ }
+ return p.Value
+}
+
+func (s *stream) compress() {
+ if len(s.l) < 2 {
+ return
+ }
+ x := s.l[len(s.l)-1]
+ xi := len(s.l) - 1
+ r := s.n - 1 - x.Width
+
+ for i := len(s.l) - 2; i >= 0; i-- {
+ c := s.l[i]
+ if c.Width+x.Width+x.Delta <= s.ƒ(s, r) {
+ x.Width += c.Width
+ s.l[xi] = x
+ // Remove element at i.
+ copy(s.l[i:], s.l[i+1:])
+ s.l = s.l[:len(s.l)-1]
+ xi -= 1
+ } else {
+ x = c
+ xi = i
+ }
+ r -= c.Width
+ }
+}
+
+func (s *stream) samples() Samples {
+ samples := make(Samples, len(s.l))
+ copy(samples, s.l)
+ return samples
+}
diff --git a/vendor/github.com/beorn7/perks/quantile/stream_test.go b/vendor/github.com/beorn7/perks/quantile/stream_test.go
new file mode 100644
index 00000000000..855195097e1
--- /dev/null
+++ b/vendor/github.com/beorn7/perks/quantile/stream_test.go
@@ -0,0 +1,215 @@
+package quantile
+
+import (
+ "math"
+ "math/rand"
+ "sort"
+ "testing"
+)
+
+var (
+ Targets = map[float64]float64{
+ 0.01: 0.001,
+ 0.10: 0.01,
+ 0.50: 0.05,
+ 0.90: 0.01,
+ 0.99: 0.001,
+ }
+ TargetsSmallEpsilon = map[float64]float64{
+ 0.01: 0.0001,
+ 0.10: 0.001,
+ 0.50: 0.005,
+ 0.90: 0.001,
+ 0.99: 0.0001,
+ }
+ LowQuantiles = []float64{0.01, 0.1, 0.5}
+ HighQuantiles = []float64{0.99, 0.9, 0.5}
+)
+
+const RelativeEpsilon = 0.01
+
+func verifyPercsWithAbsoluteEpsilon(t *testing.T, a []float64, s *Stream) {
+ sort.Float64s(a)
+ for quantile, epsilon := range Targets {
+ n := float64(len(a))
+ k := int(quantile * n)
+ if k < 1 {
+ k = 1
+ }
+ lower := int((quantile - epsilon) * n)
+ if lower < 1 {
+ lower = 1
+ }
+ upper := int(math.Ceil((quantile + epsilon) * n))
+ if upper > len(a) {
+ upper = len(a)
+ }
+ w, min, max := a[k-1], a[lower-1], a[upper-1]
+ if g := s.Query(quantile); g < min || g > max {
+ t.Errorf("q=%f: want %v [%f,%f], got %v", quantile, w, min, max, g)
+ }
+ }
+}
+
+func verifyLowPercsWithRelativeEpsilon(t *testing.T, a []float64, s *Stream) {
+ sort.Float64s(a)
+ for _, qu := range LowQuantiles {
+ n := float64(len(a))
+ k := int(qu * n)
+
+ lowerRank := int((1 - RelativeEpsilon) * qu * n)
+ upperRank := int(math.Ceil((1 + RelativeEpsilon) * qu * n))
+ w, min, max := a[k-1], a[lowerRank-1], a[upperRank-1]
+ if g := s.Query(qu); g < min || g > max {
+ t.Errorf("q=%f: want %v [%f,%f], got %v", qu, w, min, max, g)
+ }
+ }
+}
+
+func verifyHighPercsWithRelativeEpsilon(t *testing.T, a []float64, s *Stream) {
+ sort.Float64s(a)
+ for _, qu := range HighQuantiles {
+ n := float64(len(a))
+ k := int(qu * n)
+
+ lowerRank := int((1 - (1+RelativeEpsilon)*(1-qu)) * n)
+ upperRank := int(math.Ceil((1 - (1-RelativeEpsilon)*(1-qu)) * n))
+ w, min, max := a[k-1], a[lowerRank-1], a[upperRank-1]
+ if g := s.Query(qu); g < min || g > max {
+ t.Errorf("q=%f: want %v [%f,%f], got %v", qu, w, min, max, g)
+ }
+ }
+}
+
+func populateStream(s *Stream) []float64 {
+ a := make([]float64, 0, 1e5+100)
+ for i := 0; i < cap(a); i++ {
+ v := rand.NormFloat64()
+ // Add 5% asymmetric outliers.
+ if i%20 == 0 {
+ v = v*v + 1
+ }
+ s.Insert(v)
+ a = append(a, v)
+ }
+ return a
+}
+
+func TestTargetedQuery(t *testing.T) {
+ rand.Seed(42)
+ s := NewTargeted(Targets)
+ a := populateStream(s)
+ verifyPercsWithAbsoluteEpsilon(t, a, s)
+}
+
+func TestTargetedQuerySmallSampleSize(t *testing.T) {
+ rand.Seed(42)
+ s := NewTargeted(TargetsSmallEpsilon)
+ a := []float64{1, 2, 3, 4, 5}
+ for _, v := range a {
+ s.Insert(v)
+ }
+ verifyPercsWithAbsoluteEpsilon(t, a, s)
+ // If not yet flushed, results should be precise:
+ if !s.flushed() {
+ for φ, want := range map[float64]float64{
+ 0.01: 1,
+ 0.10: 1,
+ 0.50: 3,
+ 0.90: 5,
+ 0.99: 5,
+ } {
+ if got := s.Query(φ); got != want {
+ t.Errorf("want %f for φ=%f, got %f", want, φ, got)
+ }
+ }
+ }
+}
+
+func TestLowBiasedQuery(t *testing.T) {
+ rand.Seed(42)
+ s := NewLowBiased(RelativeEpsilon)
+ a := populateStream(s)
+ verifyLowPercsWithRelativeEpsilon(t, a, s)
+}
+
+func TestHighBiasedQuery(t *testing.T) {
+ rand.Seed(42)
+ s := NewHighBiased(RelativeEpsilon)
+ a := populateStream(s)
+ verifyHighPercsWithRelativeEpsilon(t, a, s)
+}
+
+// BrokenTestTargetedMerge is broken, see Merge doc comment.
+func BrokenTestTargetedMerge(t *testing.T) {
+ rand.Seed(42)
+ s1 := NewTargeted(Targets)
+ s2 := NewTargeted(Targets)
+ a := populateStream(s1)
+ a = append(a, populateStream(s2)...)
+ s1.Merge(s2.Samples())
+ verifyPercsWithAbsoluteEpsilon(t, a, s1)
+}
+
+// BrokenTestLowBiasedMerge is broken, see Merge doc comment.
+func BrokenTestLowBiasedMerge(t *testing.T) {
+ rand.Seed(42)
+ s1 := NewLowBiased(RelativeEpsilon)
+ s2 := NewLowBiased(RelativeEpsilon)
+ a := populateStream(s1)
+ a = append(a, populateStream(s2)...)
+ s1.Merge(s2.Samples())
+ verifyLowPercsWithRelativeEpsilon(t, a, s2)
+}
+
+// BrokenTestHighBiasedMerge is broken, see Merge doc comment.
+func BrokenTestHighBiasedMerge(t *testing.T) {
+ rand.Seed(42)
+ s1 := NewHighBiased(RelativeEpsilon)
+ s2 := NewHighBiased(RelativeEpsilon)
+ a := populateStream(s1)
+ a = append(a, populateStream(s2)...)
+ s1.Merge(s2.Samples())
+ verifyHighPercsWithRelativeEpsilon(t, a, s2)
+}
+
+func TestUncompressed(t *testing.T) {
+ q := NewTargeted(Targets)
+ for i := 100; i > 0; i-- {
+ q.Insert(float64(i))
+ }
+ if g := q.Count(); g != 100 {
+ t.Errorf("want count 100, got %d", g)
+ }
+ // Before compression, Query should have 100% accuracy.
+ for quantile := range Targets {
+ w := quantile * 100
+ if g := q.Query(quantile); g != w {
+ t.Errorf("want %f, got %f", w, g)
+ }
+ }
+}
+
+func TestUncompressedSamples(t *testing.T) {
+ q := NewTargeted(map[float64]float64{0.99: 0.001})
+ for i := 1; i <= 100; i++ {
+ q.Insert(float64(i))
+ }
+ if g := q.Samples().Len(); g != 100 {
+ t.Errorf("want count 100, got %d", g)
+ }
+}
+
+func TestUncompressedOne(t *testing.T) {
+ q := NewTargeted(map[float64]float64{0.99: 0.01})
+ q.Insert(3.14)
+ if g := q.Query(0.90); g != 3.14 {
+ t.Error("want PI, got", g)
+ }
+}
+
+func TestDefaults(t *testing.T) {
+ if g := NewTargeted(map[float64]float64{0.99: 0.001}).Query(0.99); g != 0 {
+ t.Errorf("want 0, got %f", g)
+ }
+}
diff --git a/vendor/github.com/davecgh/go-spew/.gitignore b/vendor/github.com/davecgh/go-spew/.gitignore
new file mode 100644
index 00000000000..00268614f04
--- /dev/null
+++ b/vendor/github.com/davecgh/go-spew/.gitignore
@@ -0,0 +1,22 @@
+# Compiled Object files, Static and Dynamic libs (Shared Objects)
+*.o
+*.a
+*.so
+
+# Folders
+_obj
+_test
+
+# Architecture specific extensions/prefixes
+*.[568vq]
+[568vq].out
+
+*.cgo1.go
+*.cgo2.c
+_cgo_defun.c
+_cgo_gotypes.go
+_cgo_export.*
+
+_testmain.go
+
+*.exe
diff --git a/vendor/github.com/davecgh/go-spew/.travis.yml b/vendor/github.com/davecgh/go-spew/.travis.yml
new file mode 100644
index 00000000000..984e0736e7d
--- /dev/null
+++ b/vendor/github.com/davecgh/go-spew/.travis.yml
@@ -0,0 +1,14 @@
+language: go
+go:
+ - 1.5.4
+ - 1.6.3
+ - 1.7
+install:
+ - go get -v golang.org/x/tools/cmd/cover
+script:
+ - go test -v -tags=safe ./spew
+ - go test -v -tags=testcgo ./spew -covermode=count -coverprofile=profile.cov
+after_success:
+ - go get -v github.com/mattn/goveralls
+ - export PATH=$PATH:$HOME/gopath/bin
+ - goveralls -coverprofile=profile.cov -service=travis-ci
diff --git a/vendor/github.com/davecgh/go-spew/LICENSE b/vendor/github.com/davecgh/go-spew/LICENSE
new file mode 100644
index 00000000000..c836416192d
--- /dev/null
+++ b/vendor/github.com/davecgh/go-spew/LICENSE
@@ -0,0 +1,15 @@
+ISC License
+
+Copyright (c) 2012-2016 Dave Collins
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/vendor/github.com/davecgh/go-spew/README.md b/vendor/github.com/davecgh/go-spew/README.md
new file mode 100644
index 00000000000..262430449b2
--- /dev/null
+++ b/vendor/github.com/davecgh/go-spew/README.md
@@ -0,0 +1,205 @@
+go-spew
+=======
+
+[]
+(https://travis-ci.org/davecgh/go-spew) [![ISC License]
+(http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org) [![Coverage Status]
+(https://img.shields.io/coveralls/davecgh/go-spew.svg)]
+(https://coveralls.io/r/davecgh/go-spew?branch=master)
+
+
+Go-spew implements a deep pretty printer for Go data structures to aid in
+debugging. A comprehensive suite of tests with 100% test coverage is provided
+to ensure proper functionality. See `test_coverage.txt` for the gocov coverage
+report. Go-spew is licensed under the liberal ISC license, so it may be used in
+open source or commercial projects.
+
+If you're interested in reading about how this package came to life and some
+of the challenges involved in providing a deep pretty printer, there is a blog
+post about it
+[here](https://web.archive.org/web/20160304013555/https://blog.cyphertite.com/go-spew-a-journey-into-dumping-go-data-structures/).
+
+## Documentation
+
+[]
+(http://godoc.org/github.com/davecgh/go-spew/spew)
+
+Full `go doc` style documentation for the project can be viewed online without
+installing this package by using the excellent GoDoc site here:
+http://godoc.org/github.com/davecgh/go-spew/spew
+
+You can also view the documentation locally once the package is installed with
+the `godoc` tool by running `godoc -http=":6060"` and pointing your browser to
+http://localhost:6060/pkg/github.com/davecgh/go-spew/spew
+
+## Installation
+
+```bash
+$ go get -u github.com/davecgh/go-spew/spew
+```
+
+## Quick Start
+
+Add this import line to the file you're working in:
+
+```Go
+import "github.com/davecgh/go-spew/spew"
+```
+
+To dump a variable with full newlines, indentation, type, and pointer
+information use Dump, Fdump, or Sdump:
+
+```Go
+spew.Dump(myVar1, myVar2, ...)
+spew.Fdump(someWriter, myVar1, myVar2, ...)
+str := spew.Sdump(myVar1, myVar2, ...)
+```
+
+Alternatively, if you would prefer to use format strings with a compacted inline
+printing style, use the convenience wrappers Printf, Fprintf, etc with %v (most
+compact), %+v (adds pointer addresses), %#v (adds types), or %#+v (adds types
+and pointer addresses):
+
+```Go
+spew.Printf("myVar1: %v -- myVar2: %+v", myVar1, myVar2)
+spew.Printf("myVar3: %#v -- myVar4: %#+v", myVar3, myVar4)
+spew.Fprintf(someWriter, "myVar1: %v -- myVar2: %+v", myVar1, myVar2)
+spew.Fprintf(someWriter, "myVar3: %#v -- myVar4: %#+v", myVar3, myVar4)
+```
+
+## Debugging a Web Application Example
+
+Here is an example of how you can use `spew.Sdump()` to help debug a web application. Please be sure to wrap your output using the `html.EscapeString()` function for safety reasons. You should also only use this debugging technique in a development environment, never in production.
+
+```Go
+package main
+
+import (
+ "fmt"
+ "html"
+ "net/http"
+
+ "github.com/davecgh/go-spew/spew"
+)
+
+func handler(w http.ResponseWriter, r *http.Request) {
+ w.Header().Set("Content-Type", "text/html")
+ fmt.Fprintf(w, "Hi there, %s!", r.URL.Path[1:])
+ fmt.Fprintf(w, "")
+}
+
+func main() {
+ http.HandleFunc("/", handler)
+ http.ListenAndServe(":8080", nil)
+}
+```
+
+## Sample Dump Output
+
+```
+(main.Foo) {
+ unexportedField: (*main.Bar)(0xf84002e210)({
+ flag: (main.Flag) flagTwo,
+ data: (uintptr)
+ }),
+ ExportedField: (map[interface {}]interface {}) {
+ (string) "one": (bool) true
+ }
+}
+([]uint8) {
+ 00000000 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 |............... |
+ 00000010 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 |!"#$%&'()*+,-./0|
+ 00000020 31 32 |12|
+}
+```
+
+## Sample Formatter Output
+
+Double pointer to a uint8:
+```
+ %v: <**>5
+ %+v: <**>(0xf8400420d0->0xf8400420c8)5
+ %#v: (**uint8)5
+ %#+v: (**uint8)(0xf8400420d0->0xf8400420c8)5
+```
+
+Pointer to circular struct with a uint8 field and a pointer to itself:
+```
+ %v: <*>{1 <*>}
+ %+v: <*>(0xf84003e260){ui8:1 c:<*>(0xf84003e260)}
+ %#v: (*main.circular){ui8:(uint8)1 c:(*main.circular)}
+ %#+v: (*main.circular)(0xf84003e260){ui8:(uint8)1 c:(*main.circular)(0xf84003e260)}
+```
+
+## Configuration Options
+
+Configuration of spew is handled by fields in the ConfigState type. For
+convenience, all of the top-level functions use a global state available via the
+spew.Config global.
+
+It is also possible to create a ConfigState instance that provides methods
+equivalent to the top-level functions. This allows concurrent configuration
+options. See the ConfigState documentation for more details.
+
+```
+* Indent
+ String to use for each indentation level for Dump functions.
+ It is a single space by default. A popular alternative is "\t".
+
+* MaxDepth
+ Maximum number of levels to descend into nested data structures.
+ There is no limit by default.
+
+* DisableMethods
+ Disables invocation of error and Stringer interface methods.
+ Method invocation is enabled by default.
+
+* DisablePointerMethods
+ Disables invocation of error and Stringer interface methods on types
+ which only accept pointer receivers from non-pointer variables. This option
+ relies on access to the unsafe package, so it will not have any effect when
+ running in environments without access to the unsafe package such as Google
+ App Engine or with the "safe" build tag specified.
+ Pointer method invocation is enabled by default.
+
+* DisablePointerAddresses
+ DisablePointerAddresses specifies whether to disable the printing of
+ pointer addresses. This is useful when diffing data structures in tests.
+
+* DisableCapacities
+ DisableCapacities specifies whether to disable the printing of capacities
+ for arrays, slices, maps and channels. This is useful when diffing data
+ structures in tests.
+
+* ContinueOnMethod
+ Enables recursion into types after invoking error and Stringer interface
+ methods. Recursion after method invocation is disabled by default.
+
+* SortKeys
+ Specifies map keys should be sorted before being printed. Use
+ this to have a more deterministic, diffable output. Note that
+ only native types (bool, int, uint, floats, uintptr and string)
+ and types which implement error or Stringer interfaces are supported,
+ with other types sorted according to the reflect.Value.String() output
+ which guarantees display stability. Natural map order is used by
+ default.
+
+* SpewKeys
+ SpewKeys specifies that, as a last resort attempt, map keys should be
+ spewed to strings and sorted by those strings. This is only considered
+ if SortKeys is true.
+
+```
+
+## Unsafe Package Dependency
+
+This package relies on the unsafe package to perform some of the more advanced
+features, however it also supports a "limited" mode which allows it to work in
+environments where the unsafe package is not available. By default, it will
+operate in this mode on Google App Engine and when compiled with GopherJS. The
+"safe" build tag may also be specified to force the package to build without
+using the unsafe package.
+
+## License
+
+Go-spew is licensed under the [copyfree](http://copyfree.org) ISC License.
diff --git a/vendor/github.com/davecgh/go-spew/cov_report.sh b/vendor/github.com/davecgh/go-spew/cov_report.sh
new file mode 100644
index 00000000000..9579497e411
--- /dev/null
+++ b/vendor/github.com/davecgh/go-spew/cov_report.sh
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+# This script uses gocov to generate a test coverage report.
+# The gocov tool my be obtained with the following command:
+# go get github.com/axw/gocov/gocov
+#
+# It will be installed to $GOPATH/bin, so ensure that location is in your $PATH.
+
+# Check for gocov.
+if ! type gocov >/dev/null 2>&1; then
+ echo >&2 "This script requires the gocov tool."
+ echo >&2 "You may obtain it with the following command:"
+ echo >&2 "go get github.com/axw/gocov/gocov"
+ exit 1
+fi
+
+# Only run the cgo tests if gcc is installed.
+if type gcc >/dev/null 2>&1; then
+ (cd spew && gocov test -tags testcgo | gocov report)
+else
+ (cd spew && gocov test | gocov report)
+fi
diff --git a/vendor/github.com/davecgh/go-spew/spew/BUILD.bazel b/vendor/github.com/davecgh/go-spew/spew/BUILD.bazel
new file mode 100644
index 00000000000..3ea2ebea5fe
--- /dev/null
+++ b/vendor/github.com/davecgh/go-spew/spew/BUILD.bazel
@@ -0,0 +1,40 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
+
+go_library(
+ name = "go_default_library",
+ srcs = [
+ "bypass.go",
+ "common.go",
+ "config.go",
+ "doc.go",
+ "dump.go",
+ "format.go",
+ "spew.go",
+ ],
+ importpath = "github.com/davecgh/go-spew/spew",
+ visibility = ["//visibility:public"],
+)
+
+go_test(
+ name = "go_default_test",
+ srcs = [
+ "internal_test.go",
+ "internalunsafe_test.go",
+ ],
+ embed = [":go_default_library"],
+ importpath = "github.com/davecgh/go-spew/spew",
+)
+
+go_test(
+ name = "go_default_xtest",
+ srcs = [
+ "common_test.go",
+ "dump_test.go",
+ "dumpnocgo_test.go",
+ "example_test.go",
+ "format_test.go",
+ "spew_test.go",
+ ],
+ importpath = "github.com/davecgh/go-spew/spew_test",
+ deps = [":go_default_library"],
+)
diff --git a/vendor/github.com/davecgh/go-spew/spew/bypass.go b/vendor/github.com/davecgh/go-spew/spew/bypass.go
new file mode 100644
index 00000000000..8a4a6589a2d
--- /dev/null
+++ b/vendor/github.com/davecgh/go-spew/spew/bypass.go
@@ -0,0 +1,152 @@
+// Copyright (c) 2015-2016 Dave Collins
+//
+// Permission to use, copy, modify, and distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+// NOTE: Due to the following build constraints, this file will only be compiled
+// when the code is not running on Google App Engine, compiled by GopherJS, and
+// "-tags safe" is not added to the go build command line. The "disableunsafe"
+// tag is deprecated and thus should not be used.
+// +build !js,!appengine,!safe,!disableunsafe
+
+package spew
+
+import (
+ "reflect"
+ "unsafe"
+)
+
+const (
+ // UnsafeDisabled is a build-time constant which specifies whether or
+ // not access to the unsafe package is available.
+ UnsafeDisabled = false
+
+ // ptrSize is the size of a pointer on the current arch.
+ ptrSize = unsafe.Sizeof((*byte)(nil))
+)
+
+var (
+ // offsetPtr, offsetScalar, and offsetFlag are the offsets for the
+ // internal reflect.Value fields. These values are valid before golang
+ // commit ecccf07e7f9d which changed the format. The are also valid
+ // after commit 82f48826c6c7 which changed the format again to mirror
+ // the original format. Code in the init function updates these offsets
+ // as necessary.
+ offsetPtr = uintptr(ptrSize)
+ offsetScalar = uintptr(0)
+ offsetFlag = uintptr(ptrSize * 2)
+
+ // flagKindWidth and flagKindShift indicate various bits that the
+ // reflect package uses internally to track kind information.
+ //
+ // flagRO indicates whether or not the value field of a reflect.Value is
+ // read-only.
+ //
+ // flagIndir indicates whether the value field of a reflect.Value is
+ // the actual data or a pointer to the data.
+ //
+ // These values are valid before golang commit 90a7c3c86944 which
+ // changed their positions. Code in the init function updates these
+ // flags as necessary.
+ flagKindWidth = uintptr(5)
+ flagKindShift = uintptr(flagKindWidth - 1)
+ flagRO = uintptr(1 << 0)
+ flagIndir = uintptr(1 << 1)
+)
+
+func init() {
+ // Older versions of reflect.Value stored small integers directly in the
+ // ptr field (which is named val in the older versions). Versions
+ // between commits ecccf07e7f9d and 82f48826c6c7 added a new field named
+ // scalar for this purpose which unfortunately came before the flag
+ // field, so the offset of the flag field is different for those
+ // versions.
+ //
+ // This code constructs a new reflect.Value from a known small integer
+ // and checks if the size of the reflect.Value struct indicates it has
+ // the scalar field. When it does, the offsets are updated accordingly.
+ vv := reflect.ValueOf(0xf00)
+ if unsafe.Sizeof(vv) == (ptrSize * 4) {
+ offsetScalar = ptrSize * 2
+ offsetFlag = ptrSize * 3
+ }
+
+ // Commit 90a7c3c86944 changed the flag positions such that the low
+ // order bits are the kind. This code extracts the kind from the flags
+ // field and ensures it's the correct type. When it's not, the flag
+ // order has been changed to the newer format, so the flags are updated
+ // accordingly.
+ upf := unsafe.Pointer(uintptr(unsafe.Pointer(&vv)) + offsetFlag)
+ upfv := *(*uintptr)(upf)
+ flagKindMask := uintptr((1<>flagKindShift != uintptr(reflect.Int) {
+ flagKindShift = 0
+ flagRO = 1 << 5
+ flagIndir = 1 << 6
+
+ // Commit adf9b30e5594 modified the flags to separate the
+ // flagRO flag into two bits which specifies whether or not the
+ // field is embedded. This causes flagIndir to move over a bit
+ // and means that flagRO is the combination of either of the
+ // original flagRO bit and the new bit.
+ //
+ // This code detects the change by extracting what used to be
+ // the indirect bit to ensure it's set. When it's not, the flag
+ // order has been changed to the newer format, so the flags are
+ // updated accordingly.
+ if upfv&flagIndir == 0 {
+ flagRO = 3 << 5
+ flagIndir = 1 << 7
+ }
+ }
+}
+
+// unsafeReflectValue converts the passed reflect.Value into a one that bypasses
+// the typical safety restrictions preventing access to unaddressable and
+// unexported data. It works by digging the raw pointer to the underlying
+// value out of the protected value and generating a new unprotected (unsafe)
+// reflect.Value to it.
+//
+// This allows us to check for implementations of the Stringer and error
+// interfaces to be used for pretty printing ordinarily unaddressable and
+// inaccessible values such as unexported struct fields.
+func unsafeReflectValue(v reflect.Value) (rv reflect.Value) {
+ indirects := 1
+ vt := v.Type()
+ upv := unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetPtr)
+ rvf := *(*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetFlag))
+ if rvf&flagIndir != 0 {
+ vt = reflect.PtrTo(v.Type())
+ indirects++
+ } else if offsetScalar != 0 {
+ // The value is in the scalar field when it's not one of the
+ // reference types.
+ switch vt.Kind() {
+ case reflect.Uintptr:
+ case reflect.Chan:
+ case reflect.Func:
+ case reflect.Map:
+ case reflect.Ptr:
+ case reflect.UnsafePointer:
+ default:
+ upv = unsafe.Pointer(uintptr(unsafe.Pointer(&v)) +
+ offsetScalar)
+ }
+ }
+
+ pv := reflect.NewAt(vt, upv)
+ rv = pv
+ for i := 0; i < indirects; i++ {
+ rv = rv.Elem()
+ }
+ return rv
+}
diff --git a/vendor/github.com/davecgh/go-spew/spew/bypasssafe.go b/vendor/github.com/davecgh/go-spew/spew/bypasssafe.go
new file mode 100644
index 00000000000..1fe3cf3d5d1
--- /dev/null
+++ b/vendor/github.com/davecgh/go-spew/spew/bypasssafe.go
@@ -0,0 +1,38 @@
+// Copyright (c) 2015-2016 Dave Collins
+//
+// Permission to use, copy, modify, and distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+// NOTE: Due to the following build constraints, this file will only be compiled
+// when the code is running on Google App Engine, compiled by GopherJS, or
+// "-tags safe" is added to the go build command line. The "disableunsafe"
+// tag is deprecated and thus should not be used.
+// +build js appengine safe disableunsafe
+
+package spew
+
+import "reflect"
+
+const (
+ // UnsafeDisabled is a build-time constant which specifies whether or
+ // not access to the unsafe package is available.
+ UnsafeDisabled = true
+)
+
+// unsafeReflectValue typically converts the passed reflect.Value into a one
+// that bypasses the typical safety restrictions preventing access to
+// unaddressable and unexported data. However, doing this relies on access to
+// the unsafe package. This is a stub version which simply returns the passed
+// reflect.Value when the unsafe package is not available.
+func unsafeReflectValue(v reflect.Value) reflect.Value {
+ return v
+}
diff --git a/vendor/github.com/davecgh/go-spew/spew/common.go b/vendor/github.com/davecgh/go-spew/spew/common.go
new file mode 100644
index 00000000000..7c519ff47ac
--- /dev/null
+++ b/vendor/github.com/davecgh/go-spew/spew/common.go
@@ -0,0 +1,341 @@
+/*
+ * Copyright (c) 2013-2016 Dave Collins
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+package spew
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "reflect"
+ "sort"
+ "strconv"
+)
+
+// Some constants in the form of bytes to avoid string overhead. This mirrors
+// the technique used in the fmt package.
+var (
+ panicBytes = []byte("(PANIC=")
+ plusBytes = []byte("+")
+ iBytes = []byte("i")
+ trueBytes = []byte("true")
+ falseBytes = []byte("false")
+ interfaceBytes = []byte("(interface {})")
+ commaNewlineBytes = []byte(",\n")
+ newlineBytes = []byte("\n")
+ openBraceBytes = []byte("{")
+ openBraceNewlineBytes = []byte("{\n")
+ closeBraceBytes = []byte("}")
+ asteriskBytes = []byte("*")
+ colonBytes = []byte(":")
+ colonSpaceBytes = []byte(": ")
+ openParenBytes = []byte("(")
+ closeParenBytes = []byte(")")
+ spaceBytes = []byte(" ")
+ pointerChainBytes = []byte("->")
+ nilAngleBytes = []byte("")
+ maxNewlineBytes = []byte("\n")
+ maxShortBytes = []byte("")
+ circularBytes = []byte("")
+ circularShortBytes = []byte("")
+ invalidAngleBytes = []byte("")
+ openBracketBytes = []byte("[")
+ closeBracketBytes = []byte("]")
+ percentBytes = []byte("%")
+ precisionBytes = []byte(".")
+ openAngleBytes = []byte("<")
+ closeAngleBytes = []byte(">")
+ openMapBytes = []byte("map[")
+ closeMapBytes = []byte("]")
+ lenEqualsBytes = []byte("len=")
+ capEqualsBytes = []byte("cap=")
+)
+
+// hexDigits is used to map a decimal value to a hex digit.
+var hexDigits = "0123456789abcdef"
+
+// catchPanic handles any panics that might occur during the handleMethods
+// calls.
+func catchPanic(w io.Writer, v reflect.Value) {
+ if err := recover(); err != nil {
+ w.Write(panicBytes)
+ fmt.Fprintf(w, "%v", err)
+ w.Write(closeParenBytes)
+ }
+}
+
+// handleMethods attempts to call the Error and String methods on the underlying
+// type the passed reflect.Value represents and outputes the result to Writer w.
+//
+// It handles panics in any called methods by catching and displaying the error
+// as the formatted value.
+func handleMethods(cs *ConfigState, w io.Writer, v reflect.Value) (handled bool) {
+ // We need an interface to check if the type implements the error or
+ // Stringer interface. However, the reflect package won't give us an
+ // interface on certain things like unexported struct fields in order
+ // to enforce visibility rules. We use unsafe, when it's available,
+ // to bypass these restrictions since this package does not mutate the
+ // values.
+ if !v.CanInterface() {
+ if UnsafeDisabled {
+ return false
+ }
+
+ v = unsafeReflectValue(v)
+ }
+
+ // Choose whether or not to do error and Stringer interface lookups against
+ // the base type or a pointer to the base type depending on settings.
+ // Technically calling one of these methods with a pointer receiver can
+ // mutate the value, however, types which choose to satisify an error or
+ // Stringer interface with a pointer receiver should not be mutating their
+ // state inside these interface methods.
+ if !cs.DisablePointerMethods && !UnsafeDisabled && !v.CanAddr() {
+ v = unsafeReflectValue(v)
+ }
+ if v.CanAddr() {
+ v = v.Addr()
+ }
+
+ // Is it an error or Stringer?
+ switch iface := v.Interface().(type) {
+ case error:
+ defer catchPanic(w, v)
+ if cs.ContinueOnMethod {
+ w.Write(openParenBytes)
+ w.Write([]byte(iface.Error()))
+ w.Write(closeParenBytes)
+ w.Write(spaceBytes)
+ return false
+ }
+
+ w.Write([]byte(iface.Error()))
+ return true
+
+ case fmt.Stringer:
+ defer catchPanic(w, v)
+ if cs.ContinueOnMethod {
+ w.Write(openParenBytes)
+ w.Write([]byte(iface.String()))
+ w.Write(closeParenBytes)
+ w.Write(spaceBytes)
+ return false
+ }
+ w.Write([]byte(iface.String()))
+ return true
+ }
+ return false
+}
+
+// printBool outputs a boolean value as true or false to Writer w.
+func printBool(w io.Writer, val bool) {
+ if val {
+ w.Write(trueBytes)
+ } else {
+ w.Write(falseBytes)
+ }
+}
+
+// printInt outputs a signed integer value to Writer w.
+func printInt(w io.Writer, val int64, base int) {
+ w.Write([]byte(strconv.FormatInt(val, base)))
+}
+
+// printUint outputs an unsigned integer value to Writer w.
+func printUint(w io.Writer, val uint64, base int) {
+ w.Write([]byte(strconv.FormatUint(val, base)))
+}
+
+// printFloat outputs a floating point value using the specified precision,
+// which is expected to be 32 or 64bit, to Writer w.
+func printFloat(w io.Writer, val float64, precision int) {
+ w.Write([]byte(strconv.FormatFloat(val, 'g', -1, precision)))
+}
+
+// printComplex outputs a complex value using the specified float precision
+// for the real and imaginary parts to Writer w.
+func printComplex(w io.Writer, c complex128, floatPrecision int) {
+ r := real(c)
+ w.Write(openParenBytes)
+ w.Write([]byte(strconv.FormatFloat(r, 'g', -1, floatPrecision)))
+ i := imag(c)
+ if i >= 0 {
+ w.Write(plusBytes)
+ }
+ w.Write([]byte(strconv.FormatFloat(i, 'g', -1, floatPrecision)))
+ w.Write(iBytes)
+ w.Write(closeParenBytes)
+}
+
+// printHexPtr outputs a uintptr formatted as hexidecimal with a leading '0x'
+// prefix to Writer w.
+func printHexPtr(w io.Writer, p uintptr) {
+ // Null pointer.
+ num := uint64(p)
+ if num == 0 {
+ w.Write(nilAngleBytes)
+ return
+ }
+
+ // Max uint64 is 16 bytes in hex + 2 bytes for '0x' prefix
+ buf := make([]byte, 18)
+
+ // It's simpler to construct the hex string right to left.
+ base := uint64(16)
+ i := len(buf) - 1
+ for num >= base {
+ buf[i] = hexDigits[num%base]
+ num /= base
+ i--
+ }
+ buf[i] = hexDigits[num]
+
+ // Add '0x' prefix.
+ i--
+ buf[i] = 'x'
+ i--
+ buf[i] = '0'
+
+ // Strip unused leading bytes.
+ buf = buf[i:]
+ w.Write(buf)
+}
+
+// valuesSorter implements sort.Interface to allow a slice of reflect.Value
+// elements to be sorted.
+type valuesSorter struct {
+ values []reflect.Value
+ strings []string // either nil or same len and values
+ cs *ConfigState
+}
+
+// newValuesSorter initializes a valuesSorter instance, which holds a set of
+// surrogate keys on which the data should be sorted. It uses flags in
+// ConfigState to decide if and how to populate those surrogate keys.
+func newValuesSorter(values []reflect.Value, cs *ConfigState) sort.Interface {
+ vs := &valuesSorter{values: values, cs: cs}
+ if canSortSimply(vs.values[0].Kind()) {
+ return vs
+ }
+ if !cs.DisableMethods {
+ vs.strings = make([]string, len(values))
+ for i := range vs.values {
+ b := bytes.Buffer{}
+ if !handleMethods(cs, &b, vs.values[i]) {
+ vs.strings = nil
+ break
+ }
+ vs.strings[i] = b.String()
+ }
+ }
+ if vs.strings == nil && cs.SpewKeys {
+ vs.strings = make([]string, len(values))
+ for i := range vs.values {
+ vs.strings[i] = Sprintf("%#v", vs.values[i].Interface())
+ }
+ }
+ return vs
+}
+
+// canSortSimply tests whether a reflect.Kind is a primitive that can be sorted
+// directly, or whether it should be considered for sorting by surrogate keys
+// (if the ConfigState allows it).
+func canSortSimply(kind reflect.Kind) bool {
+ // This switch parallels valueSortLess, except for the default case.
+ switch kind {
+ case reflect.Bool:
+ return true
+ case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
+ return true
+ case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
+ return true
+ case reflect.Float32, reflect.Float64:
+ return true
+ case reflect.String:
+ return true
+ case reflect.Uintptr:
+ return true
+ case reflect.Array:
+ return true
+ }
+ return false
+}
+
+// Len returns the number of values in the slice. It is part of the
+// sort.Interface implementation.
+func (s *valuesSorter) Len() int {
+ return len(s.values)
+}
+
+// Swap swaps the values at the passed indices. It is part of the
+// sort.Interface implementation.
+func (s *valuesSorter) Swap(i, j int) {
+ s.values[i], s.values[j] = s.values[j], s.values[i]
+ if s.strings != nil {
+ s.strings[i], s.strings[j] = s.strings[j], s.strings[i]
+ }
+}
+
+// valueSortLess returns whether the first value should sort before the second
+// value. It is used by valueSorter.Less as part of the sort.Interface
+// implementation.
+func valueSortLess(a, b reflect.Value) bool {
+ switch a.Kind() {
+ case reflect.Bool:
+ return !a.Bool() && b.Bool()
+ case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
+ return a.Int() < b.Int()
+ case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
+ return a.Uint() < b.Uint()
+ case reflect.Float32, reflect.Float64:
+ return a.Float() < b.Float()
+ case reflect.String:
+ return a.String() < b.String()
+ case reflect.Uintptr:
+ return a.Uint() < b.Uint()
+ case reflect.Array:
+ // Compare the contents of both arrays.
+ l := a.Len()
+ for i := 0; i < l; i++ {
+ av := a.Index(i)
+ bv := b.Index(i)
+ if av.Interface() == bv.Interface() {
+ continue
+ }
+ return valueSortLess(av, bv)
+ }
+ }
+ return a.String() < b.String()
+}
+
+// Less returns whether the value at index i should sort before the
+// value at index j. It is part of the sort.Interface implementation.
+func (s *valuesSorter) Less(i, j int) bool {
+ if s.strings == nil {
+ return valueSortLess(s.values[i], s.values[j])
+ }
+ return s.strings[i] < s.strings[j]
+}
+
+// sortValues is a sort function that handles both native types and any type that
+// can be converted to error or Stringer. Other inputs are sorted according to
+// their Value.String() value to ensure display stability.
+func sortValues(values []reflect.Value, cs *ConfigState) {
+ if len(values) == 0 {
+ return
+ }
+ sort.Sort(newValuesSorter(values, cs))
+}
diff --git a/vendor/github.com/davecgh/go-spew/spew/common_test.go b/vendor/github.com/davecgh/go-spew/spew/common_test.go
new file mode 100644
index 00000000000..0f5ce47dcaf
--- /dev/null
+++ b/vendor/github.com/davecgh/go-spew/spew/common_test.go
@@ -0,0 +1,298 @@
+/*
+ * Copyright (c) 2013-2016 Dave Collins
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+package spew_test
+
+import (
+ "fmt"
+ "reflect"
+ "testing"
+
+ "github.com/davecgh/go-spew/spew"
+)
+
+// custom type to test Stinger interface on non-pointer receiver.
+type stringer string
+
+// String implements the Stringer interface for testing invocation of custom
+// stringers on types with non-pointer receivers.
+func (s stringer) String() string {
+ return "stringer " + string(s)
+}
+
+// custom type to test Stinger interface on pointer receiver.
+type pstringer string
+
+// String implements the Stringer interface for testing invocation of custom
+// stringers on types with only pointer receivers.
+func (s *pstringer) String() string {
+ return "stringer " + string(*s)
+}
+
+// xref1 and xref2 are cross referencing structs for testing circular reference
+// detection.
+type xref1 struct {
+ ps2 *xref2
+}
+type xref2 struct {
+ ps1 *xref1
+}
+
+// indirCir1, indirCir2, and indirCir3 are used to generate an indirect circular
+// reference for testing detection.
+type indirCir1 struct {
+ ps2 *indirCir2
+}
+type indirCir2 struct {
+ ps3 *indirCir3
+}
+type indirCir3 struct {
+ ps1 *indirCir1
+}
+
+// embed is used to test embedded structures.
+type embed struct {
+ a string
+}
+
+// embedwrap is used to test embedded structures.
+type embedwrap struct {
+ *embed
+ e *embed
+}
+
+// panicer is used to intentionally cause a panic for testing spew properly
+// handles them
+type panicer int
+
+func (p panicer) String() string {
+ panic("test panic")
+}
+
+// customError is used to test custom error interface invocation.
+type customError int
+
+func (e customError) Error() string {
+ return fmt.Sprintf("error: %d", int(e))
+}
+
+// stringizeWants converts a slice of wanted test output into a format suitable
+// for a test error message.
+func stringizeWants(wants []string) string {
+ s := ""
+ for i, want := range wants {
+ if i > 0 {
+ s += fmt.Sprintf("want%d: %s", i+1, want)
+ } else {
+ s += "want: " + want
+ }
+ }
+ return s
+}
+
+// testFailed returns whether or not a test failed by checking if the result
+// of the test is in the slice of wanted strings.
+func testFailed(result string, wants []string) bool {
+ for _, want := range wants {
+ if result == want {
+ return false
+ }
+ }
+ return true
+}
+
+type sortableStruct struct {
+ x int
+}
+
+func (ss sortableStruct) String() string {
+ return fmt.Sprintf("ss.%d", ss.x)
+}
+
+type unsortableStruct struct {
+ x int
+}
+
+type sortTestCase struct {
+ input []reflect.Value
+ expected []reflect.Value
+}
+
+func helpTestSortValues(tests []sortTestCase, cs *spew.ConfigState, t *testing.T) {
+ getInterfaces := func(values []reflect.Value) []interface{} {
+ interfaces := []interface{}{}
+ for _, v := range values {
+ interfaces = append(interfaces, v.Interface())
+ }
+ return interfaces
+ }
+
+ for _, test := range tests {
+ spew.SortValues(test.input, cs)
+ // reflect.DeepEqual cannot really make sense of reflect.Value,
+ // probably because of all the pointer tricks. For instance,
+ // v(2.0) != v(2.0) on a 32-bits system. Turn them into interface{}
+ // instead.
+ input := getInterfaces(test.input)
+ expected := getInterfaces(test.expected)
+ if !reflect.DeepEqual(input, expected) {
+ t.Errorf("Sort mismatch:\n %v != %v", input, expected)
+ }
+ }
+}
+
+// TestSortValues ensures the sort functionality for relect.Value based sorting
+// works as intended.
+func TestSortValues(t *testing.T) {
+ v := reflect.ValueOf
+
+ a := v("a")
+ b := v("b")
+ c := v("c")
+ embedA := v(embed{"a"})
+ embedB := v(embed{"b"})
+ embedC := v(embed{"c"})
+ tests := []sortTestCase{
+ // No values.
+ {
+ []reflect.Value{},
+ []reflect.Value{},
+ },
+ // Bools.
+ {
+ []reflect.Value{v(false), v(true), v(false)},
+ []reflect.Value{v(false), v(false), v(true)},
+ },
+ // Ints.
+ {
+ []reflect.Value{v(2), v(1), v(3)},
+ []reflect.Value{v(1), v(2), v(3)},
+ },
+ // Uints.
+ {
+ []reflect.Value{v(uint8(2)), v(uint8(1)), v(uint8(3))},
+ []reflect.Value{v(uint8(1)), v(uint8(2)), v(uint8(3))},
+ },
+ // Floats.
+ {
+ []reflect.Value{v(2.0), v(1.0), v(3.0)},
+ []reflect.Value{v(1.0), v(2.0), v(3.0)},
+ },
+ // Strings.
+ {
+ []reflect.Value{b, a, c},
+ []reflect.Value{a, b, c},
+ },
+ // Array
+ {
+ []reflect.Value{v([3]int{3, 2, 1}), v([3]int{1, 3, 2}), v([3]int{1, 2, 3})},
+ []reflect.Value{v([3]int{1, 2, 3}), v([3]int{1, 3, 2}), v([3]int{3, 2, 1})},
+ },
+ // Uintptrs.
+ {
+ []reflect.Value{v(uintptr(2)), v(uintptr(1)), v(uintptr(3))},
+ []reflect.Value{v(uintptr(1)), v(uintptr(2)), v(uintptr(3))},
+ },
+ // SortableStructs.
+ {
+ // Note: not sorted - DisableMethods is set.
+ []reflect.Value{v(sortableStruct{2}), v(sortableStruct{1}), v(sortableStruct{3})},
+ []reflect.Value{v(sortableStruct{2}), v(sortableStruct{1}), v(sortableStruct{3})},
+ },
+ // UnsortableStructs.
+ {
+ // Note: not sorted - SpewKeys is false.
+ []reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})},
+ []reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})},
+ },
+ // Invalid.
+ {
+ []reflect.Value{embedB, embedA, embedC},
+ []reflect.Value{embedB, embedA, embedC},
+ },
+ }
+ cs := spew.ConfigState{DisableMethods: true, SpewKeys: false}
+ helpTestSortValues(tests, &cs, t)
+}
+
+// TestSortValuesWithMethods ensures the sort functionality for relect.Value
+// based sorting works as intended when using string methods.
+func TestSortValuesWithMethods(t *testing.T) {
+ v := reflect.ValueOf
+
+ a := v("a")
+ b := v("b")
+ c := v("c")
+ tests := []sortTestCase{
+ // Ints.
+ {
+ []reflect.Value{v(2), v(1), v(3)},
+ []reflect.Value{v(1), v(2), v(3)},
+ },
+ // Strings.
+ {
+ []reflect.Value{b, a, c},
+ []reflect.Value{a, b, c},
+ },
+ // SortableStructs.
+ {
+ []reflect.Value{v(sortableStruct{2}), v(sortableStruct{1}), v(sortableStruct{3})},
+ []reflect.Value{v(sortableStruct{1}), v(sortableStruct{2}), v(sortableStruct{3})},
+ },
+ // UnsortableStructs.
+ {
+ // Note: not sorted - SpewKeys is false.
+ []reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})},
+ []reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})},
+ },
+ }
+ cs := spew.ConfigState{DisableMethods: false, SpewKeys: false}
+ helpTestSortValues(tests, &cs, t)
+}
+
+// TestSortValuesWithSpew ensures the sort functionality for relect.Value
+// based sorting works as intended when using spew to stringify keys.
+func TestSortValuesWithSpew(t *testing.T) {
+ v := reflect.ValueOf
+
+ a := v("a")
+ b := v("b")
+ c := v("c")
+ tests := []sortTestCase{
+ // Ints.
+ {
+ []reflect.Value{v(2), v(1), v(3)},
+ []reflect.Value{v(1), v(2), v(3)},
+ },
+ // Strings.
+ {
+ []reflect.Value{b, a, c},
+ []reflect.Value{a, b, c},
+ },
+ // SortableStructs.
+ {
+ []reflect.Value{v(sortableStruct{2}), v(sortableStruct{1}), v(sortableStruct{3})},
+ []reflect.Value{v(sortableStruct{1}), v(sortableStruct{2}), v(sortableStruct{3})},
+ },
+ // UnsortableStructs.
+ {
+ []reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})},
+ []reflect.Value{v(unsortableStruct{1}), v(unsortableStruct{2}), v(unsortableStruct{3})},
+ },
+ }
+ cs := spew.ConfigState{DisableMethods: true, SpewKeys: true}
+ helpTestSortValues(tests, &cs, t)
+}
diff --git a/vendor/github.com/davecgh/go-spew/spew/config.go b/vendor/github.com/davecgh/go-spew/spew/config.go
new file mode 100644
index 00000000000..2e3d22f3120
--- /dev/null
+++ b/vendor/github.com/davecgh/go-spew/spew/config.go
@@ -0,0 +1,306 @@
+/*
+ * Copyright (c) 2013-2016 Dave Collins
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+package spew
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "os"
+)
+
+// ConfigState houses the configuration options used by spew to format and
+// display values. There is a global instance, Config, that is used to control
+// all top-level Formatter and Dump functionality. Each ConfigState instance
+// provides methods equivalent to the top-level functions.
+//
+// The zero value for ConfigState provides no indentation. You would typically
+// want to set it to a space or a tab.
+//
+// Alternatively, you can use NewDefaultConfig to get a ConfigState instance
+// with default settings. See the documentation of NewDefaultConfig for default
+// values.
+type ConfigState struct {
+ // Indent specifies the string to use for each indentation level. The
+ // global config instance that all top-level functions use set this to a
+ // single space by default. If you would like more indentation, you might
+ // set this to a tab with "\t" or perhaps two spaces with " ".
+ Indent string
+
+ // MaxDepth controls the maximum number of levels to descend into nested
+ // data structures. The default, 0, means there is no limit.
+ //
+ // NOTE: Circular data structures are properly detected, so it is not
+ // necessary to set this value unless you specifically want to limit deeply
+ // nested data structures.
+ MaxDepth int
+
+ // DisableMethods specifies whether or not error and Stringer interfaces are
+ // invoked for types that implement them.
+ DisableMethods bool
+
+ // DisablePointerMethods specifies whether or not to check for and invoke
+ // error and Stringer interfaces on types which only accept a pointer
+ // receiver when the current type is not a pointer.
+ //
+ // NOTE: This might be an unsafe action since calling one of these methods
+ // with a pointer receiver could technically mutate the value, however,
+ // in practice, types which choose to satisify an error or Stringer
+ // interface with a pointer receiver should not be mutating their state
+ // inside these interface methods. As a result, this option relies on
+ // access to the unsafe package, so it will not have any effect when
+ // running in environments without access to the unsafe package such as
+ // Google App Engine or with the "safe" build tag specified.
+ DisablePointerMethods bool
+
+ // DisablePointerAddresses specifies whether to disable the printing of
+ // pointer addresses. This is useful when diffing data structures in tests.
+ DisablePointerAddresses bool
+
+ // DisableCapacities specifies whether to disable the printing of capacities
+ // for arrays, slices, maps and channels. This is useful when diffing
+ // data structures in tests.
+ DisableCapacities bool
+
+ // ContinueOnMethod specifies whether or not recursion should continue once
+ // a custom error or Stringer interface is invoked. The default, false,
+ // means it will print the results of invoking the custom error or Stringer
+ // interface and return immediately instead of continuing to recurse into
+ // the internals of the data type.
+ //
+ // NOTE: This flag does not have any effect if method invocation is disabled
+ // via the DisableMethods or DisablePointerMethods options.
+ ContinueOnMethod bool
+
+ // SortKeys specifies map keys should be sorted before being printed. Use
+ // this to have a more deterministic, diffable output. Note that only
+ // native types (bool, int, uint, floats, uintptr and string) and types
+ // that support the error or Stringer interfaces (if methods are
+ // enabled) are supported, with other types sorted according to the
+ // reflect.Value.String() output which guarantees display stability.
+ SortKeys bool
+
+ // SpewKeys specifies that, as a last resort attempt, map keys should
+ // be spewed to strings and sorted by those strings. This is only
+ // considered if SortKeys is true.
+ SpewKeys bool
+}
+
+// Config is the active configuration of the top-level functions.
+// The configuration can be changed by modifying the contents of spew.Config.
+var Config = ConfigState{Indent: " "}
+
+// Errorf is a wrapper for fmt.Errorf that treats each argument as if it were
+// passed with a Formatter interface returned by c.NewFormatter. It returns
+// the formatted string as a value that satisfies error. See NewFormatter
+// for formatting details.
+//
+// This function is shorthand for the following syntax:
+//
+// fmt.Errorf(format, c.NewFormatter(a), c.NewFormatter(b))
+func (c *ConfigState) Errorf(format string, a ...interface{}) (err error) {
+ return fmt.Errorf(format, c.convertArgs(a)...)
+}
+
+// Fprint is a wrapper for fmt.Fprint that treats each argument as if it were
+// passed with a Formatter interface returned by c.NewFormatter. It returns
+// the number of bytes written and any write error encountered. See
+// NewFormatter for formatting details.
+//
+// This function is shorthand for the following syntax:
+//
+// fmt.Fprint(w, c.NewFormatter(a), c.NewFormatter(b))
+func (c *ConfigState) Fprint(w io.Writer, a ...interface{}) (n int, err error) {
+ return fmt.Fprint(w, c.convertArgs(a)...)
+}
+
+// Fprintf is a wrapper for fmt.Fprintf that treats each argument as if it were
+// passed with a Formatter interface returned by c.NewFormatter. It returns
+// the number of bytes written and any write error encountered. See
+// NewFormatter for formatting details.
+//
+// This function is shorthand for the following syntax:
+//
+// fmt.Fprintf(w, format, c.NewFormatter(a), c.NewFormatter(b))
+func (c *ConfigState) Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) {
+ return fmt.Fprintf(w, format, c.convertArgs(a)...)
+}
+
+// Fprintln is a wrapper for fmt.Fprintln that treats each argument as if it
+// passed with a Formatter interface returned by c.NewFormatter. See
+// NewFormatter for formatting details.
+//
+// This function is shorthand for the following syntax:
+//
+// fmt.Fprintln(w, c.NewFormatter(a), c.NewFormatter(b))
+func (c *ConfigState) Fprintln(w io.Writer, a ...interface{}) (n int, err error) {
+ return fmt.Fprintln(w, c.convertArgs(a)...)
+}
+
+// Print is a wrapper for fmt.Print that treats each argument as if it were
+// passed with a Formatter interface returned by c.NewFormatter. It returns
+// the number of bytes written and any write error encountered. See
+// NewFormatter for formatting details.
+//
+// This function is shorthand for the following syntax:
+//
+// fmt.Print(c.NewFormatter(a), c.NewFormatter(b))
+func (c *ConfigState) Print(a ...interface{}) (n int, err error) {
+ return fmt.Print(c.convertArgs(a)...)
+}
+
+// Printf is a wrapper for fmt.Printf that treats each argument as if it were
+// passed with a Formatter interface returned by c.NewFormatter. It returns
+// the number of bytes written and any write error encountered. See
+// NewFormatter for formatting details.
+//
+// This function is shorthand for the following syntax:
+//
+// fmt.Printf(format, c.NewFormatter(a), c.NewFormatter(b))
+func (c *ConfigState) Printf(format string, a ...interface{}) (n int, err error) {
+ return fmt.Printf(format, c.convertArgs(a)...)
+}
+
+// Println is a wrapper for fmt.Println that treats each argument as if it were
+// passed with a Formatter interface returned by c.NewFormatter. It returns
+// the number of bytes written and any write error encountered. See
+// NewFormatter for formatting details.
+//
+// This function is shorthand for the following syntax:
+//
+// fmt.Println(c.NewFormatter(a), c.NewFormatter(b))
+func (c *ConfigState) Println(a ...interface{}) (n int, err error) {
+ return fmt.Println(c.convertArgs(a)...)
+}
+
+// Sprint is a wrapper for fmt.Sprint that treats each argument as if it were
+// passed with a Formatter interface returned by c.NewFormatter. It returns
+// the resulting string. See NewFormatter for formatting details.
+//
+// This function is shorthand for the following syntax:
+//
+// fmt.Sprint(c.NewFormatter(a), c.NewFormatter(b))
+func (c *ConfigState) Sprint(a ...interface{}) string {
+ return fmt.Sprint(c.convertArgs(a)...)
+}
+
+// Sprintf is a wrapper for fmt.Sprintf that treats each argument as if it were
+// passed with a Formatter interface returned by c.NewFormatter. It returns
+// the resulting string. See NewFormatter for formatting details.
+//
+// This function is shorthand for the following syntax:
+//
+// fmt.Sprintf(format, c.NewFormatter(a), c.NewFormatter(b))
+func (c *ConfigState) Sprintf(format string, a ...interface{}) string {
+ return fmt.Sprintf(format, c.convertArgs(a)...)
+}
+
+// Sprintln is a wrapper for fmt.Sprintln that treats each argument as if it
+// were passed with a Formatter interface returned by c.NewFormatter. It
+// returns the resulting string. See NewFormatter for formatting details.
+//
+// This function is shorthand for the following syntax:
+//
+// fmt.Sprintln(c.NewFormatter(a), c.NewFormatter(b))
+func (c *ConfigState) Sprintln(a ...interface{}) string {
+ return fmt.Sprintln(c.convertArgs(a)...)
+}
+
+/*
+NewFormatter returns a custom formatter that satisfies the fmt.Formatter
+interface. As a result, it integrates cleanly with standard fmt package
+printing functions. The formatter is useful for inline printing of smaller data
+types similar to the standard %v format specifier.
+
+The custom formatter only responds to the %v (most compact), %+v (adds pointer
+addresses), %#v (adds types), and %#+v (adds types and pointer addresses) verb
+combinations. Any other verbs such as %x and %q will be sent to the the
+standard fmt package for formatting. In addition, the custom formatter ignores
+the width and precision arguments (however they will still work on the format
+specifiers not handled by the custom formatter).
+
+Typically this function shouldn't be called directly. It is much easier to make
+use of the custom formatter by calling one of the convenience functions such as
+c.Printf, c.Println, or c.Printf.
+*/
+func (c *ConfigState) NewFormatter(v interface{}) fmt.Formatter {
+ return newFormatter(c, v)
+}
+
+// Fdump formats and displays the passed arguments to io.Writer w. It formats
+// exactly the same as Dump.
+func (c *ConfigState) Fdump(w io.Writer, a ...interface{}) {
+ fdump(c, w, a...)
+}
+
+/*
+Dump displays the passed parameters to standard out with newlines, customizable
+indentation, and additional debug information such as complete types and all
+pointer addresses used to indirect to the final value. It provides the
+following features over the built-in printing facilities provided by the fmt
+package:
+
+ * Pointers are dereferenced and followed
+ * Circular data structures are detected and handled properly
+ * Custom Stringer/error interfaces are optionally invoked, including
+ on unexported types
+ * Custom types which only implement the Stringer/error interfaces via
+ a pointer receiver are optionally invoked when passing non-pointer
+ variables
+ * Byte arrays and slices are dumped like the hexdump -C command which
+ includes offsets, byte values in hex, and ASCII output
+
+The configuration options are controlled by modifying the public members
+of c. See ConfigState for options documentation.
+
+See Fdump if you would prefer dumping to an arbitrary io.Writer or Sdump to
+get the formatted result as a string.
+*/
+func (c *ConfigState) Dump(a ...interface{}) {
+ fdump(c, os.Stdout, a...)
+}
+
+// Sdump returns a string with the passed arguments formatted exactly the same
+// as Dump.
+func (c *ConfigState) Sdump(a ...interface{}) string {
+ var buf bytes.Buffer
+ fdump(c, &buf, a...)
+ return buf.String()
+}
+
+// convertArgs accepts a slice of arguments and returns a slice of the same
+// length with each argument converted to a spew Formatter interface using
+// the ConfigState associated with s.
+func (c *ConfigState) convertArgs(args []interface{}) (formatters []interface{}) {
+ formatters = make([]interface{}, len(args))
+ for index, arg := range args {
+ formatters[index] = newFormatter(c, arg)
+ }
+ return formatters
+}
+
+// NewDefaultConfig returns a ConfigState with the following default settings.
+//
+// Indent: " "
+// MaxDepth: 0
+// DisableMethods: false
+// DisablePointerMethods: false
+// ContinueOnMethod: false
+// SortKeys: false
+func NewDefaultConfig() *ConfigState {
+ return &ConfigState{Indent: " "}
+}
diff --git a/vendor/github.com/davecgh/go-spew/spew/doc.go b/vendor/github.com/davecgh/go-spew/spew/doc.go
new file mode 100644
index 00000000000..aacaac6f1e1
--- /dev/null
+++ b/vendor/github.com/davecgh/go-spew/spew/doc.go
@@ -0,0 +1,211 @@
+/*
+ * Copyright (c) 2013-2016 Dave Collins
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+Package spew implements a deep pretty printer for Go data structures to aid in
+debugging.
+
+A quick overview of the additional features spew provides over the built-in
+printing facilities for Go data types are as follows:
+
+ * Pointers are dereferenced and followed
+ * Circular data structures are detected and handled properly
+ * Custom Stringer/error interfaces are optionally invoked, including
+ on unexported types
+ * Custom types which only implement the Stringer/error interfaces via
+ a pointer receiver are optionally invoked when passing non-pointer
+ variables
+ * Byte arrays and slices are dumped like the hexdump -C command which
+ includes offsets, byte values in hex, and ASCII output (only when using
+ Dump style)
+
+There are two different approaches spew allows for dumping Go data structures:
+
+ * Dump style which prints with newlines, customizable indentation,
+ and additional debug information such as types and all pointer addresses
+ used to indirect to the final value
+ * A custom Formatter interface that integrates cleanly with the standard fmt
+ package and replaces %v, %+v, %#v, and %#+v to provide inline printing
+ similar to the default %v while providing the additional functionality
+ outlined above and passing unsupported format verbs such as %x and %q
+ along to fmt
+
+Quick Start
+
+This section demonstrates how to quickly get started with spew. See the
+sections below for further details on formatting and configuration options.
+
+To dump a variable with full newlines, indentation, type, and pointer
+information use Dump, Fdump, or Sdump:
+ spew.Dump(myVar1, myVar2, ...)
+ spew.Fdump(someWriter, myVar1, myVar2, ...)
+ str := spew.Sdump(myVar1, myVar2, ...)
+
+Alternatively, if you would prefer to use format strings with a compacted inline
+printing style, use the convenience wrappers Printf, Fprintf, etc with
+%v (most compact), %+v (adds pointer addresses), %#v (adds types), or
+%#+v (adds types and pointer addresses):
+ spew.Printf("myVar1: %v -- myVar2: %+v", myVar1, myVar2)
+ spew.Printf("myVar3: %#v -- myVar4: %#+v", myVar3, myVar4)
+ spew.Fprintf(someWriter, "myVar1: %v -- myVar2: %+v", myVar1, myVar2)
+ spew.Fprintf(someWriter, "myVar3: %#v -- myVar4: %#+v", myVar3, myVar4)
+
+Configuration Options
+
+Configuration of spew is handled by fields in the ConfigState type. For
+convenience, all of the top-level functions use a global state available
+via the spew.Config global.
+
+It is also possible to create a ConfigState instance that provides methods
+equivalent to the top-level functions. This allows concurrent configuration
+options. See the ConfigState documentation for more details.
+
+The following configuration options are available:
+ * Indent
+ String to use for each indentation level for Dump functions.
+ It is a single space by default. A popular alternative is "\t".
+
+ * MaxDepth
+ Maximum number of levels to descend into nested data structures.
+ There is no limit by default.
+
+ * DisableMethods
+ Disables invocation of error and Stringer interface methods.
+ Method invocation is enabled by default.
+
+ * DisablePointerMethods
+ Disables invocation of error and Stringer interface methods on types
+ which only accept pointer receivers from non-pointer variables.
+ Pointer method invocation is enabled by default.
+
+ * DisablePointerAddresses
+ DisablePointerAddresses specifies whether to disable the printing of
+ pointer addresses. This is useful when diffing data structures in tests.
+
+ * DisableCapacities
+ DisableCapacities specifies whether to disable the printing of
+ capacities for arrays, slices, maps and channels. This is useful when
+ diffing data structures in tests.
+
+ * ContinueOnMethod
+ Enables recursion into types after invoking error and Stringer interface
+ methods. Recursion after method invocation is disabled by default.
+
+ * SortKeys
+ Specifies map keys should be sorted before being printed. Use
+ this to have a more deterministic, diffable output. Note that
+ only native types (bool, int, uint, floats, uintptr and string)
+ and types which implement error or Stringer interfaces are
+ supported with other types sorted according to the
+ reflect.Value.String() output which guarantees display
+ stability. Natural map order is used by default.
+
+ * SpewKeys
+ Specifies that, as a last resort attempt, map keys should be
+ spewed to strings and sorted by those strings. This is only
+ considered if SortKeys is true.
+
+Dump Usage
+
+Simply call spew.Dump with a list of variables you want to dump:
+
+ spew.Dump(myVar1, myVar2, ...)
+
+You may also call spew.Fdump if you would prefer to output to an arbitrary
+io.Writer. For example, to dump to standard error:
+
+ spew.Fdump(os.Stderr, myVar1, myVar2, ...)
+
+A third option is to call spew.Sdump to get the formatted output as a string:
+
+ str := spew.Sdump(myVar1, myVar2, ...)
+
+Sample Dump Output
+
+See the Dump example for details on the setup of the types and variables being
+shown here.
+
+ (main.Foo) {
+ unexportedField: (*main.Bar)(0xf84002e210)({
+ flag: (main.Flag) flagTwo,
+ data: (uintptr)
+ }),
+ ExportedField: (map[interface {}]interface {}) (len=1) {
+ (string) (len=3) "one": (bool) true
+ }
+ }
+
+Byte (and uint8) arrays and slices are displayed uniquely like the hexdump -C
+command as shown.
+ ([]uint8) (len=32 cap=32) {
+ 00000000 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 |............... |
+ 00000010 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 |!"#$%&'()*+,-./0|
+ 00000020 31 32 |12|
+ }
+
+Custom Formatter
+
+Spew provides a custom formatter that implements the fmt.Formatter interface
+so that it integrates cleanly with standard fmt package printing functions. The
+formatter is useful for inline printing of smaller data types similar to the
+standard %v format specifier.
+
+The custom formatter only responds to the %v (most compact), %+v (adds pointer
+addresses), %#v (adds types), or %#+v (adds types and pointer addresses) verb
+combinations. Any other verbs such as %x and %q will be sent to the the
+standard fmt package for formatting. In addition, the custom formatter ignores
+the width and precision arguments (however they will still work on the format
+specifiers not handled by the custom formatter).
+
+Custom Formatter Usage
+
+The simplest way to make use of the spew custom formatter is to call one of the
+convenience functions such as spew.Printf, spew.Println, or spew.Printf. The
+functions have syntax you are most likely already familiar with:
+
+ spew.Printf("myVar1: %v -- myVar2: %+v", myVar1, myVar2)
+ spew.Printf("myVar3: %#v -- myVar4: %#+v", myVar3, myVar4)
+ spew.Println(myVar, myVar2)
+ spew.Fprintf(os.Stderr, "myVar1: %v -- myVar2: %+v", myVar1, myVar2)
+ spew.Fprintf(os.Stderr, "myVar3: %#v -- myVar4: %#+v", myVar3, myVar4)
+
+See the Index for the full list convenience functions.
+
+Sample Formatter Output
+
+Double pointer to a uint8:
+ %v: <**>5
+ %+v: <**>(0xf8400420d0->0xf8400420c8)5
+ %#v: (**uint8)5
+ %#+v: (**uint8)(0xf8400420d0->0xf8400420c8)5
+
+Pointer to circular struct with a uint8 field and a pointer to itself:
+ %v: <*>{1 <*>}
+ %+v: <*>(0xf84003e260){ui8:1 c:<*>(0xf84003e260)}
+ %#v: (*main.circular){ui8:(uint8)1 c:(*main.circular)}
+ %#+v: (*main.circular)(0xf84003e260){ui8:(uint8)1 c:(*main.circular)(0xf84003e260)}
+
+See the Printf example for details on the setup of variables being shown
+here.
+
+Errors
+
+Since it is possible for custom Stringer/error interfaces to panic, spew
+detects them and handles them internally by printing the panic information
+inline with the output. Since spew is intended to provide deep pretty printing
+capabilities on structures, it intentionally does not return any errors.
+*/
+package spew
diff --git a/vendor/github.com/davecgh/go-spew/spew/dump.go b/vendor/github.com/davecgh/go-spew/spew/dump.go
new file mode 100644
index 00000000000..df1d582a728
--- /dev/null
+++ b/vendor/github.com/davecgh/go-spew/spew/dump.go
@@ -0,0 +1,509 @@
+/*
+ * Copyright (c) 2013-2016 Dave Collins
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+package spew
+
+import (
+ "bytes"
+ "encoding/hex"
+ "fmt"
+ "io"
+ "os"
+ "reflect"
+ "regexp"
+ "strconv"
+ "strings"
+)
+
+var (
+ // uint8Type is a reflect.Type representing a uint8. It is used to
+ // convert cgo types to uint8 slices for hexdumping.
+ uint8Type = reflect.TypeOf(uint8(0))
+
+ // cCharRE is a regular expression that matches a cgo char.
+ // It is used to detect character arrays to hexdump them.
+ cCharRE = regexp.MustCompile("^.*\\._Ctype_char$")
+
+ // cUnsignedCharRE is a regular expression that matches a cgo unsigned
+ // char. It is used to detect unsigned character arrays to hexdump
+ // them.
+ cUnsignedCharRE = regexp.MustCompile("^.*\\._Ctype_unsignedchar$")
+
+ // cUint8tCharRE is a regular expression that matches a cgo uint8_t.
+ // It is used to detect uint8_t arrays to hexdump them.
+ cUint8tCharRE = regexp.MustCompile("^.*\\._Ctype_uint8_t$")
+)
+
+// dumpState contains information about the state of a dump operation.
+type dumpState struct {
+ w io.Writer
+ depth int
+ pointers map[uintptr]int
+ ignoreNextType bool
+ ignoreNextIndent bool
+ cs *ConfigState
+}
+
+// indent performs indentation according to the depth level and cs.Indent
+// option.
+func (d *dumpState) indent() {
+ if d.ignoreNextIndent {
+ d.ignoreNextIndent = false
+ return
+ }
+ d.w.Write(bytes.Repeat([]byte(d.cs.Indent), d.depth))
+}
+
+// unpackValue returns values inside of non-nil interfaces when possible.
+// This is useful for data types like structs, arrays, slices, and maps which
+// can contain varying types packed inside an interface.
+func (d *dumpState) unpackValue(v reflect.Value) reflect.Value {
+ if v.Kind() == reflect.Interface && !v.IsNil() {
+ v = v.Elem()
+ }
+ return v
+}
+
+// dumpPtr handles formatting of pointers by indirecting them as necessary.
+func (d *dumpState) dumpPtr(v reflect.Value) {
+ // Remove pointers at or below the current depth from map used to detect
+ // circular refs.
+ for k, depth := range d.pointers {
+ if depth >= d.depth {
+ delete(d.pointers, k)
+ }
+ }
+
+ // Keep list of all dereferenced pointers to show later.
+ pointerChain := make([]uintptr, 0)
+
+ // Figure out how many levels of indirection there are by dereferencing
+ // pointers and unpacking interfaces down the chain while detecting circular
+ // references.
+ nilFound := false
+ cycleFound := false
+ indirects := 0
+ ve := v
+ for ve.Kind() == reflect.Ptr {
+ if ve.IsNil() {
+ nilFound = true
+ break
+ }
+ indirects++
+ addr := ve.Pointer()
+ pointerChain = append(pointerChain, addr)
+ if pd, ok := d.pointers[addr]; ok && pd < d.depth {
+ cycleFound = true
+ indirects--
+ break
+ }
+ d.pointers[addr] = d.depth
+
+ ve = ve.Elem()
+ if ve.Kind() == reflect.Interface {
+ if ve.IsNil() {
+ nilFound = true
+ break
+ }
+ ve = ve.Elem()
+ }
+ }
+
+ // Display type information.
+ d.w.Write(openParenBytes)
+ d.w.Write(bytes.Repeat(asteriskBytes, indirects))
+ d.w.Write([]byte(ve.Type().String()))
+ d.w.Write(closeParenBytes)
+
+ // Display pointer information.
+ if !d.cs.DisablePointerAddresses && len(pointerChain) > 0 {
+ d.w.Write(openParenBytes)
+ for i, addr := range pointerChain {
+ if i > 0 {
+ d.w.Write(pointerChainBytes)
+ }
+ printHexPtr(d.w, addr)
+ }
+ d.w.Write(closeParenBytes)
+ }
+
+ // Display dereferenced value.
+ d.w.Write(openParenBytes)
+ switch {
+ case nilFound == true:
+ d.w.Write(nilAngleBytes)
+
+ case cycleFound == true:
+ d.w.Write(circularBytes)
+
+ default:
+ d.ignoreNextType = true
+ d.dump(ve)
+ }
+ d.w.Write(closeParenBytes)
+}
+
+// dumpSlice handles formatting of arrays and slices. Byte (uint8 under
+// reflection) arrays and slices are dumped in hexdump -C fashion.
+func (d *dumpState) dumpSlice(v reflect.Value) {
+ // Determine whether this type should be hex dumped or not. Also,
+ // for types which should be hexdumped, try to use the underlying data
+ // first, then fall back to trying to convert them to a uint8 slice.
+ var buf []uint8
+ doConvert := false
+ doHexDump := false
+ numEntries := v.Len()
+ if numEntries > 0 {
+ vt := v.Index(0).Type()
+ vts := vt.String()
+ switch {
+ // C types that need to be converted.
+ case cCharRE.MatchString(vts):
+ fallthrough
+ case cUnsignedCharRE.MatchString(vts):
+ fallthrough
+ case cUint8tCharRE.MatchString(vts):
+ doConvert = true
+
+ // Try to use existing uint8 slices and fall back to converting
+ // and copying if that fails.
+ case vt.Kind() == reflect.Uint8:
+ // We need an addressable interface to convert the type
+ // to a byte slice. However, the reflect package won't
+ // give us an interface on certain things like
+ // unexported struct fields in order to enforce
+ // visibility rules. We use unsafe, when available, to
+ // bypass these restrictions since this package does not
+ // mutate the values.
+ vs := v
+ if !vs.CanInterface() || !vs.CanAddr() {
+ vs = unsafeReflectValue(vs)
+ }
+ if !UnsafeDisabled {
+ vs = vs.Slice(0, numEntries)
+
+ // Use the existing uint8 slice if it can be
+ // type asserted.
+ iface := vs.Interface()
+ if slice, ok := iface.([]uint8); ok {
+ buf = slice
+ doHexDump = true
+ break
+ }
+ }
+
+ // The underlying data needs to be converted if it can't
+ // be type asserted to a uint8 slice.
+ doConvert = true
+ }
+
+ // Copy and convert the underlying type if needed.
+ if doConvert && vt.ConvertibleTo(uint8Type) {
+ // Convert and copy each element into a uint8 byte
+ // slice.
+ buf = make([]uint8, numEntries)
+ for i := 0; i < numEntries; i++ {
+ vv := v.Index(i)
+ buf[i] = uint8(vv.Convert(uint8Type).Uint())
+ }
+ doHexDump = true
+ }
+ }
+
+ // Hexdump the entire slice as needed.
+ if doHexDump {
+ indent := strings.Repeat(d.cs.Indent, d.depth)
+ str := indent + hex.Dump(buf)
+ str = strings.Replace(str, "\n", "\n"+indent, -1)
+ str = strings.TrimRight(str, d.cs.Indent)
+ d.w.Write([]byte(str))
+ return
+ }
+
+ // Recursively call dump for each item.
+ for i := 0; i < numEntries; i++ {
+ d.dump(d.unpackValue(v.Index(i)))
+ if i < (numEntries - 1) {
+ d.w.Write(commaNewlineBytes)
+ } else {
+ d.w.Write(newlineBytes)
+ }
+ }
+}
+
+// dump is the main workhorse for dumping a value. It uses the passed reflect
+// value to figure out what kind of object we are dealing with and formats it
+// appropriately. It is a recursive function, however circular data structures
+// are detected and handled properly.
+func (d *dumpState) dump(v reflect.Value) {
+ // Handle invalid reflect values immediately.
+ kind := v.Kind()
+ if kind == reflect.Invalid {
+ d.w.Write(invalidAngleBytes)
+ return
+ }
+
+ // Handle pointers specially.
+ if kind == reflect.Ptr {
+ d.indent()
+ d.dumpPtr(v)
+ return
+ }
+
+ // Print type information unless already handled elsewhere.
+ if !d.ignoreNextType {
+ d.indent()
+ d.w.Write(openParenBytes)
+ d.w.Write([]byte(v.Type().String()))
+ d.w.Write(closeParenBytes)
+ d.w.Write(spaceBytes)
+ }
+ d.ignoreNextType = false
+
+ // Display length and capacity if the built-in len and cap functions
+ // work with the value's kind and the len/cap itself is non-zero.
+ valueLen, valueCap := 0, 0
+ switch v.Kind() {
+ case reflect.Array, reflect.Slice, reflect.Chan:
+ valueLen, valueCap = v.Len(), v.Cap()
+ case reflect.Map, reflect.String:
+ valueLen = v.Len()
+ }
+ if valueLen != 0 || !d.cs.DisableCapacities && valueCap != 0 {
+ d.w.Write(openParenBytes)
+ if valueLen != 0 {
+ d.w.Write(lenEqualsBytes)
+ printInt(d.w, int64(valueLen), 10)
+ }
+ if !d.cs.DisableCapacities && valueCap != 0 {
+ if valueLen != 0 {
+ d.w.Write(spaceBytes)
+ }
+ d.w.Write(capEqualsBytes)
+ printInt(d.w, int64(valueCap), 10)
+ }
+ d.w.Write(closeParenBytes)
+ d.w.Write(spaceBytes)
+ }
+
+ // Call Stringer/error interfaces if they exist and the handle methods flag
+ // is enabled
+ if !d.cs.DisableMethods {
+ if (kind != reflect.Invalid) && (kind != reflect.Interface) {
+ if handled := handleMethods(d.cs, d.w, v); handled {
+ return
+ }
+ }
+ }
+
+ switch kind {
+ case reflect.Invalid:
+ // Do nothing. We should never get here since invalid has already
+ // been handled above.
+
+ case reflect.Bool:
+ printBool(d.w, v.Bool())
+
+ case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
+ printInt(d.w, v.Int(), 10)
+
+ case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
+ printUint(d.w, v.Uint(), 10)
+
+ case reflect.Float32:
+ printFloat(d.w, v.Float(), 32)
+
+ case reflect.Float64:
+ printFloat(d.w, v.Float(), 64)
+
+ case reflect.Complex64:
+ printComplex(d.w, v.Complex(), 32)
+
+ case reflect.Complex128:
+ printComplex(d.w, v.Complex(), 64)
+
+ case reflect.Slice:
+ if v.IsNil() {
+ d.w.Write(nilAngleBytes)
+ break
+ }
+ fallthrough
+
+ case reflect.Array:
+ d.w.Write(openBraceNewlineBytes)
+ d.depth++
+ if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) {
+ d.indent()
+ d.w.Write(maxNewlineBytes)
+ } else {
+ d.dumpSlice(v)
+ }
+ d.depth--
+ d.indent()
+ d.w.Write(closeBraceBytes)
+
+ case reflect.String:
+ d.w.Write([]byte(strconv.Quote(v.String())))
+
+ case reflect.Interface:
+ // The only time we should get here is for nil interfaces due to
+ // unpackValue calls.
+ if v.IsNil() {
+ d.w.Write(nilAngleBytes)
+ }
+
+ case reflect.Ptr:
+ // Do nothing. We should never get here since pointers have already
+ // been handled above.
+
+ case reflect.Map:
+ // nil maps should be indicated as different than empty maps
+ if v.IsNil() {
+ d.w.Write(nilAngleBytes)
+ break
+ }
+
+ d.w.Write(openBraceNewlineBytes)
+ d.depth++
+ if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) {
+ d.indent()
+ d.w.Write(maxNewlineBytes)
+ } else {
+ numEntries := v.Len()
+ keys := v.MapKeys()
+ if d.cs.SortKeys {
+ sortValues(keys, d.cs)
+ }
+ for i, key := range keys {
+ d.dump(d.unpackValue(key))
+ d.w.Write(colonSpaceBytes)
+ d.ignoreNextIndent = true
+ d.dump(d.unpackValue(v.MapIndex(key)))
+ if i < (numEntries - 1) {
+ d.w.Write(commaNewlineBytes)
+ } else {
+ d.w.Write(newlineBytes)
+ }
+ }
+ }
+ d.depth--
+ d.indent()
+ d.w.Write(closeBraceBytes)
+
+ case reflect.Struct:
+ d.w.Write(openBraceNewlineBytes)
+ d.depth++
+ if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) {
+ d.indent()
+ d.w.Write(maxNewlineBytes)
+ } else {
+ vt := v.Type()
+ numFields := v.NumField()
+ for i := 0; i < numFields; i++ {
+ d.indent()
+ vtf := vt.Field(i)
+ d.w.Write([]byte(vtf.Name))
+ d.w.Write(colonSpaceBytes)
+ d.ignoreNextIndent = true
+ d.dump(d.unpackValue(v.Field(i)))
+ if i < (numFields - 1) {
+ d.w.Write(commaNewlineBytes)
+ } else {
+ d.w.Write(newlineBytes)
+ }
+ }
+ }
+ d.depth--
+ d.indent()
+ d.w.Write(closeBraceBytes)
+
+ case reflect.Uintptr:
+ printHexPtr(d.w, uintptr(v.Uint()))
+
+ case reflect.UnsafePointer, reflect.Chan, reflect.Func:
+ printHexPtr(d.w, v.Pointer())
+
+ // There were not any other types at the time this code was written, but
+ // fall back to letting the default fmt package handle it in case any new
+ // types are added.
+ default:
+ if v.CanInterface() {
+ fmt.Fprintf(d.w, "%v", v.Interface())
+ } else {
+ fmt.Fprintf(d.w, "%v", v.String())
+ }
+ }
+}
+
+// fdump is a helper function to consolidate the logic from the various public
+// methods which take varying writers and config states.
+func fdump(cs *ConfigState, w io.Writer, a ...interface{}) {
+ for _, arg := range a {
+ if arg == nil {
+ w.Write(interfaceBytes)
+ w.Write(spaceBytes)
+ w.Write(nilAngleBytes)
+ w.Write(newlineBytes)
+ continue
+ }
+
+ d := dumpState{w: w, cs: cs}
+ d.pointers = make(map[uintptr]int)
+ d.dump(reflect.ValueOf(arg))
+ d.w.Write(newlineBytes)
+ }
+}
+
+// Fdump formats and displays the passed arguments to io.Writer w. It formats
+// exactly the same as Dump.
+func Fdump(w io.Writer, a ...interface{}) {
+ fdump(&Config, w, a...)
+}
+
+// Sdump returns a string with the passed arguments formatted exactly the same
+// as Dump.
+func Sdump(a ...interface{}) string {
+ var buf bytes.Buffer
+ fdump(&Config, &buf, a...)
+ return buf.String()
+}
+
+/*
+Dump displays the passed parameters to standard out with newlines, customizable
+indentation, and additional debug information such as complete types and all
+pointer addresses used to indirect to the final value. It provides the
+following features over the built-in printing facilities provided by the fmt
+package:
+
+ * Pointers are dereferenced and followed
+ * Circular data structures are detected and handled properly
+ * Custom Stringer/error interfaces are optionally invoked, including
+ on unexported types
+ * Custom types which only implement the Stringer/error interfaces via
+ a pointer receiver are optionally invoked when passing non-pointer
+ variables
+ * Byte arrays and slices are dumped like the hexdump -C command which
+ includes offsets, byte values in hex, and ASCII output
+
+The configuration options are controlled by an exported package global,
+spew.Config. See ConfigState for options documentation.
+
+See Fdump if you would prefer dumping to an arbitrary io.Writer or Sdump to
+get the formatted result as a string.
+*/
+func Dump(a ...interface{}) {
+ fdump(&Config, os.Stdout, a...)
+}
diff --git a/vendor/github.com/davecgh/go-spew/spew/dump_test.go b/vendor/github.com/davecgh/go-spew/spew/dump_test.go
new file mode 100644
index 00000000000..5aad9c7af0b
--- /dev/null
+++ b/vendor/github.com/davecgh/go-spew/spew/dump_test.go
@@ -0,0 +1,1042 @@
+/*
+ * Copyright (c) 2013-2016 Dave Collins
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+Test Summary:
+NOTE: For each test, a nil pointer, a single pointer and double pointer to the
+base test element are also tested to ensure proper indirection across all types.
+
+- Max int8, int16, int32, int64, int
+- Max uint8, uint16, uint32, uint64, uint
+- Boolean true and false
+- Standard complex64 and complex128
+- Array containing standard ints
+- Array containing type with custom formatter on pointer receiver only
+- Array containing interfaces
+- Array containing bytes
+- Slice containing standard float32 values
+- Slice containing type with custom formatter on pointer receiver only
+- Slice containing interfaces
+- Slice containing bytes
+- Nil slice
+- Standard string
+- Nil interface
+- Sub-interface
+- Map with string keys and int vals
+- Map with custom formatter type on pointer receiver only keys and vals
+- Map with interface keys and values
+- Map with nil interface value
+- Struct with primitives
+- Struct that contains another struct
+- Struct that contains custom type with Stringer pointer interface via both
+ exported and unexported fields
+- Struct that contains embedded struct and field to same struct
+- Uintptr to 0 (null pointer)
+- Uintptr address of real variable
+- Unsafe.Pointer to 0 (null pointer)
+- Unsafe.Pointer to address of real variable
+- Nil channel
+- Standard int channel
+- Function with no params and no returns
+- Function with param and no returns
+- Function with multiple params and multiple returns
+- Struct that is circular through self referencing
+- Structs that are circular through cross referencing
+- Structs that are indirectly circular
+- Type that panics in its Stringer interface
+*/
+
+package spew_test
+
+import (
+ "bytes"
+ "fmt"
+ "testing"
+ "unsafe"
+
+ "github.com/davecgh/go-spew/spew"
+)
+
+// dumpTest is used to describe a test to be performed against the Dump method.
+type dumpTest struct {
+ in interface{}
+ wants []string
+}
+
+// dumpTests houses all of the tests to be performed against the Dump method.
+var dumpTests = make([]dumpTest, 0)
+
+// addDumpTest is a helper method to append the passed input and desired result
+// to dumpTests
+func addDumpTest(in interface{}, wants ...string) {
+ test := dumpTest{in, wants}
+ dumpTests = append(dumpTests, test)
+}
+
+func addIntDumpTests() {
+ // Max int8.
+ v := int8(127)
+ nv := (*int8)(nil)
+ pv := &v
+ vAddr := fmt.Sprintf("%p", pv)
+ pvAddr := fmt.Sprintf("%p", &pv)
+ vt := "int8"
+ vs := "127"
+ addDumpTest(v, "("+vt+") "+vs+"\n")
+ addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
+ addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
+ addDumpTest(nv, "(*"+vt+")()\n")
+
+ // Max int16.
+ v2 := int16(32767)
+ nv2 := (*int16)(nil)
+ pv2 := &v2
+ v2Addr := fmt.Sprintf("%p", pv2)
+ pv2Addr := fmt.Sprintf("%p", &pv2)
+ v2t := "int16"
+ v2s := "32767"
+ addDumpTest(v2, "("+v2t+") "+v2s+"\n")
+ addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n")
+ addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
+ addDumpTest(nv2, "(*"+v2t+")()\n")
+
+ // Max int32.
+ v3 := int32(2147483647)
+ nv3 := (*int32)(nil)
+ pv3 := &v3
+ v3Addr := fmt.Sprintf("%p", pv3)
+ pv3Addr := fmt.Sprintf("%p", &pv3)
+ v3t := "int32"
+ v3s := "2147483647"
+ addDumpTest(v3, "("+v3t+") "+v3s+"\n")
+ addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s+")\n")
+ addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s+")\n")
+ addDumpTest(nv3, "(*"+v3t+")()\n")
+
+ // Max int64.
+ v4 := int64(9223372036854775807)
+ nv4 := (*int64)(nil)
+ pv4 := &v4
+ v4Addr := fmt.Sprintf("%p", pv4)
+ pv4Addr := fmt.Sprintf("%p", &pv4)
+ v4t := "int64"
+ v4s := "9223372036854775807"
+ addDumpTest(v4, "("+v4t+") "+v4s+"\n")
+ addDumpTest(pv4, "(*"+v4t+")("+v4Addr+")("+v4s+")\n")
+ addDumpTest(&pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")("+v4s+")\n")
+ addDumpTest(nv4, "(*"+v4t+")()\n")
+
+ // Max int.
+ v5 := int(2147483647)
+ nv5 := (*int)(nil)
+ pv5 := &v5
+ v5Addr := fmt.Sprintf("%p", pv5)
+ pv5Addr := fmt.Sprintf("%p", &pv5)
+ v5t := "int"
+ v5s := "2147483647"
+ addDumpTest(v5, "("+v5t+") "+v5s+"\n")
+ addDumpTest(pv5, "(*"+v5t+")("+v5Addr+")("+v5s+")\n")
+ addDumpTest(&pv5, "(**"+v5t+")("+pv5Addr+"->"+v5Addr+")("+v5s+")\n")
+ addDumpTest(nv5, "(*"+v5t+")()\n")
+}
+
+func addUintDumpTests() {
+ // Max uint8.
+ v := uint8(255)
+ nv := (*uint8)(nil)
+ pv := &v
+ vAddr := fmt.Sprintf("%p", pv)
+ pvAddr := fmt.Sprintf("%p", &pv)
+ vt := "uint8"
+ vs := "255"
+ addDumpTest(v, "("+vt+") "+vs+"\n")
+ addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
+ addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
+ addDumpTest(nv, "(*"+vt+")()\n")
+
+ // Max uint16.
+ v2 := uint16(65535)
+ nv2 := (*uint16)(nil)
+ pv2 := &v2
+ v2Addr := fmt.Sprintf("%p", pv2)
+ pv2Addr := fmt.Sprintf("%p", &pv2)
+ v2t := "uint16"
+ v2s := "65535"
+ addDumpTest(v2, "("+v2t+") "+v2s+"\n")
+ addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n")
+ addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
+ addDumpTest(nv2, "(*"+v2t+")()\n")
+
+ // Max uint32.
+ v3 := uint32(4294967295)
+ nv3 := (*uint32)(nil)
+ pv3 := &v3
+ v3Addr := fmt.Sprintf("%p", pv3)
+ pv3Addr := fmt.Sprintf("%p", &pv3)
+ v3t := "uint32"
+ v3s := "4294967295"
+ addDumpTest(v3, "("+v3t+") "+v3s+"\n")
+ addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s+")\n")
+ addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s+")\n")
+ addDumpTest(nv3, "(*"+v3t+")()\n")
+
+ // Max uint64.
+ v4 := uint64(18446744073709551615)
+ nv4 := (*uint64)(nil)
+ pv4 := &v4
+ v4Addr := fmt.Sprintf("%p", pv4)
+ pv4Addr := fmt.Sprintf("%p", &pv4)
+ v4t := "uint64"
+ v4s := "18446744073709551615"
+ addDumpTest(v4, "("+v4t+") "+v4s+"\n")
+ addDumpTest(pv4, "(*"+v4t+")("+v4Addr+")("+v4s+")\n")
+ addDumpTest(&pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")("+v4s+")\n")
+ addDumpTest(nv4, "(*"+v4t+")()\n")
+
+ // Max uint.
+ v5 := uint(4294967295)
+ nv5 := (*uint)(nil)
+ pv5 := &v5
+ v5Addr := fmt.Sprintf("%p", pv5)
+ pv5Addr := fmt.Sprintf("%p", &pv5)
+ v5t := "uint"
+ v5s := "4294967295"
+ addDumpTest(v5, "("+v5t+") "+v5s+"\n")
+ addDumpTest(pv5, "(*"+v5t+")("+v5Addr+")("+v5s+")\n")
+ addDumpTest(&pv5, "(**"+v5t+")("+pv5Addr+"->"+v5Addr+")("+v5s+")\n")
+ addDumpTest(nv5, "(*"+v5t+")()\n")
+}
+
+func addBoolDumpTests() {
+ // Boolean true.
+ v := bool(true)
+ nv := (*bool)(nil)
+ pv := &v
+ vAddr := fmt.Sprintf("%p", pv)
+ pvAddr := fmt.Sprintf("%p", &pv)
+ vt := "bool"
+ vs := "true"
+ addDumpTest(v, "("+vt+") "+vs+"\n")
+ addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
+ addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
+ addDumpTest(nv, "(*"+vt+")()\n")
+
+ // Boolean false.
+ v2 := bool(false)
+ pv2 := &v2
+ v2Addr := fmt.Sprintf("%p", pv2)
+ pv2Addr := fmt.Sprintf("%p", &pv2)
+ v2t := "bool"
+ v2s := "false"
+ addDumpTest(v2, "("+v2t+") "+v2s+"\n")
+ addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n")
+ addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
+}
+
+func addFloatDumpTests() {
+ // Standard float32.
+ v := float32(3.1415)
+ nv := (*float32)(nil)
+ pv := &v
+ vAddr := fmt.Sprintf("%p", pv)
+ pvAddr := fmt.Sprintf("%p", &pv)
+ vt := "float32"
+ vs := "3.1415"
+ addDumpTest(v, "("+vt+") "+vs+"\n")
+ addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
+ addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
+ addDumpTest(nv, "(*"+vt+")()\n")
+
+ // Standard float64.
+ v2 := float64(3.1415926)
+ nv2 := (*float64)(nil)
+ pv2 := &v2
+ v2Addr := fmt.Sprintf("%p", pv2)
+ pv2Addr := fmt.Sprintf("%p", &pv2)
+ v2t := "float64"
+ v2s := "3.1415926"
+ addDumpTest(v2, "("+v2t+") "+v2s+"\n")
+ addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n")
+ addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
+ addDumpTest(nv2, "(*"+v2t+")()\n")
+}
+
+func addComplexDumpTests() {
+ // Standard complex64.
+ v := complex(float32(6), -2)
+ nv := (*complex64)(nil)
+ pv := &v
+ vAddr := fmt.Sprintf("%p", pv)
+ pvAddr := fmt.Sprintf("%p", &pv)
+ vt := "complex64"
+ vs := "(6-2i)"
+ addDumpTest(v, "("+vt+") "+vs+"\n")
+ addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
+ addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
+ addDumpTest(nv, "(*"+vt+")()\n")
+
+ // Standard complex128.
+ v2 := complex(float64(-6), 2)
+ nv2 := (*complex128)(nil)
+ pv2 := &v2
+ v2Addr := fmt.Sprintf("%p", pv2)
+ pv2Addr := fmt.Sprintf("%p", &pv2)
+ v2t := "complex128"
+ v2s := "(-6+2i)"
+ addDumpTest(v2, "("+v2t+") "+v2s+"\n")
+ addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n")
+ addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
+ addDumpTest(nv2, "(*"+v2t+")()\n")
+}
+
+func addArrayDumpTests() {
+ // Array containing standard ints.
+ v := [3]int{1, 2, 3}
+ vLen := fmt.Sprintf("%d", len(v))
+ vCap := fmt.Sprintf("%d", cap(v))
+ nv := (*[3]int)(nil)
+ pv := &v
+ vAddr := fmt.Sprintf("%p", pv)
+ pvAddr := fmt.Sprintf("%p", &pv)
+ vt := "int"
+ vs := "(len=" + vLen + " cap=" + vCap + ") {\n (" + vt + ") 1,\n (" +
+ vt + ") 2,\n (" + vt + ") 3\n}"
+ addDumpTest(v, "([3]"+vt+") "+vs+"\n")
+ addDumpTest(pv, "(*[3]"+vt+")("+vAddr+")("+vs+")\n")
+ addDumpTest(&pv, "(**[3]"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
+ addDumpTest(nv, "(*[3]"+vt+")()\n")
+
+ // Array containing type with custom formatter on pointer receiver only.
+ v2i0 := pstringer("1")
+ v2i1 := pstringer("2")
+ v2i2 := pstringer("3")
+ v2 := [3]pstringer{v2i0, v2i1, v2i2}
+ v2i0Len := fmt.Sprintf("%d", len(v2i0))
+ v2i1Len := fmt.Sprintf("%d", len(v2i1))
+ v2i2Len := fmt.Sprintf("%d", len(v2i2))
+ v2Len := fmt.Sprintf("%d", len(v2))
+ v2Cap := fmt.Sprintf("%d", cap(v2))
+ nv2 := (*[3]pstringer)(nil)
+ pv2 := &v2
+ v2Addr := fmt.Sprintf("%p", pv2)
+ pv2Addr := fmt.Sprintf("%p", &pv2)
+ v2t := "spew_test.pstringer"
+ v2sp := "(len=" + v2Len + " cap=" + v2Cap + ") {\n (" + v2t +
+ ") (len=" + v2i0Len + ") stringer 1,\n (" + v2t +
+ ") (len=" + v2i1Len + ") stringer 2,\n (" + v2t +
+ ") (len=" + v2i2Len + ") " + "stringer 3\n}"
+ v2s := v2sp
+ if spew.UnsafeDisabled {
+ v2s = "(len=" + v2Len + " cap=" + v2Cap + ") {\n (" + v2t +
+ ") (len=" + v2i0Len + ") \"1\",\n (" + v2t + ") (len=" +
+ v2i1Len + ") \"2\",\n (" + v2t + ") (len=" + v2i2Len +
+ ") " + "\"3\"\n}"
+ }
+ addDumpTest(v2, "([3]"+v2t+") "+v2s+"\n")
+ addDumpTest(pv2, "(*[3]"+v2t+")("+v2Addr+")("+v2sp+")\n")
+ addDumpTest(&pv2, "(**[3]"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2sp+")\n")
+ addDumpTest(nv2, "(*[3]"+v2t+")()\n")
+
+ // Array containing interfaces.
+ v3i0 := "one"
+ v3 := [3]interface{}{v3i0, int(2), uint(3)}
+ v3i0Len := fmt.Sprintf("%d", len(v3i0))
+ v3Len := fmt.Sprintf("%d", len(v3))
+ v3Cap := fmt.Sprintf("%d", cap(v3))
+ nv3 := (*[3]interface{})(nil)
+ pv3 := &v3
+ v3Addr := fmt.Sprintf("%p", pv3)
+ pv3Addr := fmt.Sprintf("%p", &pv3)
+ v3t := "[3]interface {}"
+ v3t2 := "string"
+ v3t3 := "int"
+ v3t4 := "uint"
+ v3s := "(len=" + v3Len + " cap=" + v3Cap + ") {\n (" + v3t2 + ") " +
+ "(len=" + v3i0Len + ") \"one\",\n (" + v3t3 + ") 2,\n (" +
+ v3t4 + ") 3\n}"
+ addDumpTest(v3, "("+v3t+") "+v3s+"\n")
+ addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s+")\n")
+ addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s+")\n")
+ addDumpTest(nv3, "(*"+v3t+")()\n")
+
+ // Array containing bytes.
+ v4 := [34]byte{
+ 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+ 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
+ 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
+ 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
+ 0x31, 0x32,
+ }
+ v4Len := fmt.Sprintf("%d", len(v4))
+ v4Cap := fmt.Sprintf("%d", cap(v4))
+ nv4 := (*[34]byte)(nil)
+ pv4 := &v4
+ v4Addr := fmt.Sprintf("%p", pv4)
+ pv4Addr := fmt.Sprintf("%p", &pv4)
+ v4t := "[34]uint8"
+ v4s := "(len=" + v4Len + " cap=" + v4Cap + ") " +
+ "{\n 00000000 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20" +
+ " |............... |\n" +
+ " 00000010 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30" +
+ " |!\"#$%&'()*+,-./0|\n" +
+ " 00000020 31 32 " +
+ " |12|\n}"
+ addDumpTest(v4, "("+v4t+") "+v4s+"\n")
+ addDumpTest(pv4, "(*"+v4t+")("+v4Addr+")("+v4s+")\n")
+ addDumpTest(&pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")("+v4s+")\n")
+ addDumpTest(nv4, "(*"+v4t+")()\n")
+}
+
+func addSliceDumpTests() {
+ // Slice containing standard float32 values.
+ v := []float32{3.14, 6.28, 12.56}
+ vLen := fmt.Sprintf("%d", len(v))
+ vCap := fmt.Sprintf("%d", cap(v))
+ nv := (*[]float32)(nil)
+ pv := &v
+ vAddr := fmt.Sprintf("%p", pv)
+ pvAddr := fmt.Sprintf("%p", &pv)
+ vt := "float32"
+ vs := "(len=" + vLen + " cap=" + vCap + ") {\n (" + vt + ") 3.14,\n (" +
+ vt + ") 6.28,\n (" + vt + ") 12.56\n}"
+ addDumpTest(v, "([]"+vt+") "+vs+"\n")
+ addDumpTest(pv, "(*[]"+vt+")("+vAddr+")("+vs+")\n")
+ addDumpTest(&pv, "(**[]"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
+ addDumpTest(nv, "(*[]"+vt+")()\n")
+
+ // Slice containing type with custom formatter on pointer receiver only.
+ v2i0 := pstringer("1")
+ v2i1 := pstringer("2")
+ v2i2 := pstringer("3")
+ v2 := []pstringer{v2i0, v2i1, v2i2}
+ v2i0Len := fmt.Sprintf("%d", len(v2i0))
+ v2i1Len := fmt.Sprintf("%d", len(v2i1))
+ v2i2Len := fmt.Sprintf("%d", len(v2i2))
+ v2Len := fmt.Sprintf("%d", len(v2))
+ v2Cap := fmt.Sprintf("%d", cap(v2))
+ nv2 := (*[]pstringer)(nil)
+ pv2 := &v2
+ v2Addr := fmt.Sprintf("%p", pv2)
+ pv2Addr := fmt.Sprintf("%p", &pv2)
+ v2t := "spew_test.pstringer"
+ v2s := "(len=" + v2Len + " cap=" + v2Cap + ") {\n (" + v2t + ") (len=" +
+ v2i0Len + ") stringer 1,\n (" + v2t + ") (len=" + v2i1Len +
+ ") stringer 2,\n (" + v2t + ") (len=" + v2i2Len + ") " +
+ "stringer 3\n}"
+ addDumpTest(v2, "([]"+v2t+") "+v2s+"\n")
+ addDumpTest(pv2, "(*[]"+v2t+")("+v2Addr+")("+v2s+")\n")
+ addDumpTest(&pv2, "(**[]"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
+ addDumpTest(nv2, "(*[]"+v2t+")()\n")
+
+ // Slice containing interfaces.
+ v3i0 := "one"
+ v3 := []interface{}{v3i0, int(2), uint(3), nil}
+ v3i0Len := fmt.Sprintf("%d", len(v3i0))
+ v3Len := fmt.Sprintf("%d", len(v3))
+ v3Cap := fmt.Sprintf("%d", cap(v3))
+ nv3 := (*[]interface{})(nil)
+ pv3 := &v3
+ v3Addr := fmt.Sprintf("%p", pv3)
+ pv3Addr := fmt.Sprintf("%p", &pv3)
+ v3t := "[]interface {}"
+ v3t2 := "string"
+ v3t3 := "int"
+ v3t4 := "uint"
+ v3t5 := "interface {}"
+ v3s := "(len=" + v3Len + " cap=" + v3Cap + ") {\n (" + v3t2 + ") " +
+ "(len=" + v3i0Len + ") \"one\",\n (" + v3t3 + ") 2,\n (" +
+ v3t4 + ") 3,\n (" + v3t5 + ") \n}"
+ addDumpTest(v3, "("+v3t+") "+v3s+"\n")
+ addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s+")\n")
+ addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s+")\n")
+ addDumpTest(nv3, "(*"+v3t+")()\n")
+
+ // Slice containing bytes.
+ v4 := []byte{
+ 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+ 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
+ 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
+ 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
+ 0x31, 0x32,
+ }
+ v4Len := fmt.Sprintf("%d", len(v4))
+ v4Cap := fmt.Sprintf("%d", cap(v4))
+ nv4 := (*[]byte)(nil)
+ pv4 := &v4
+ v4Addr := fmt.Sprintf("%p", pv4)
+ pv4Addr := fmt.Sprintf("%p", &pv4)
+ v4t := "[]uint8"
+ v4s := "(len=" + v4Len + " cap=" + v4Cap + ") " +
+ "{\n 00000000 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20" +
+ " |............... |\n" +
+ " 00000010 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30" +
+ " |!\"#$%&'()*+,-./0|\n" +
+ " 00000020 31 32 " +
+ " |12|\n}"
+ addDumpTest(v4, "("+v4t+") "+v4s+"\n")
+ addDumpTest(pv4, "(*"+v4t+")("+v4Addr+")("+v4s+")\n")
+ addDumpTest(&pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")("+v4s+")\n")
+ addDumpTest(nv4, "(*"+v4t+")()\n")
+
+ // Nil slice.
+ v5 := []int(nil)
+ nv5 := (*[]int)(nil)
+ pv5 := &v5
+ v5Addr := fmt.Sprintf("%p", pv5)
+ pv5Addr := fmt.Sprintf("%p", &pv5)
+ v5t := "[]int"
+ v5s := ""
+ addDumpTest(v5, "("+v5t+") "+v5s+"\n")
+ addDumpTest(pv5, "(*"+v5t+")("+v5Addr+")("+v5s+")\n")
+ addDumpTest(&pv5, "(**"+v5t+")("+pv5Addr+"->"+v5Addr+")("+v5s+")\n")
+ addDumpTest(nv5, "(*"+v5t+")()\n")
+}
+
+func addStringDumpTests() {
+ // Standard string.
+ v := "test"
+ vLen := fmt.Sprintf("%d", len(v))
+ nv := (*string)(nil)
+ pv := &v
+ vAddr := fmt.Sprintf("%p", pv)
+ pvAddr := fmt.Sprintf("%p", &pv)
+ vt := "string"
+ vs := "(len=" + vLen + ") \"test\""
+ addDumpTest(v, "("+vt+") "+vs+"\n")
+ addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
+ addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
+ addDumpTest(nv, "(*"+vt+")()\n")
+}
+
+func addInterfaceDumpTests() {
+ // Nil interface.
+ var v interface{}
+ nv := (*interface{})(nil)
+ pv := &v
+ vAddr := fmt.Sprintf("%p", pv)
+ pvAddr := fmt.Sprintf("%p", &pv)
+ vt := "interface {}"
+ vs := ""
+ addDumpTest(v, "("+vt+") "+vs+"\n")
+ addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
+ addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
+ addDumpTest(nv, "(*"+vt+")()\n")
+
+ // Sub-interface.
+ v2 := interface{}(uint16(65535))
+ pv2 := &v2
+ v2Addr := fmt.Sprintf("%p", pv2)
+ pv2Addr := fmt.Sprintf("%p", &pv2)
+ v2t := "uint16"
+ v2s := "65535"
+ addDumpTest(v2, "("+v2t+") "+v2s+"\n")
+ addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n")
+ addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
+}
+
+func addMapDumpTests() {
+ // Map with string keys and int vals.
+ k := "one"
+ kk := "two"
+ m := map[string]int{k: 1, kk: 2}
+ klen := fmt.Sprintf("%d", len(k)) // not kLen to shut golint up
+ kkLen := fmt.Sprintf("%d", len(kk))
+ mLen := fmt.Sprintf("%d", len(m))
+ nilMap := map[string]int(nil)
+ nm := (*map[string]int)(nil)
+ pm := &m
+ mAddr := fmt.Sprintf("%p", pm)
+ pmAddr := fmt.Sprintf("%p", &pm)
+ mt := "map[string]int"
+ mt1 := "string"
+ mt2 := "int"
+ ms := "(len=" + mLen + ") {\n (" + mt1 + ") (len=" + klen + ") " +
+ "\"one\": (" + mt2 + ") 1,\n (" + mt1 + ") (len=" + kkLen +
+ ") \"two\": (" + mt2 + ") 2\n}"
+ ms2 := "(len=" + mLen + ") {\n (" + mt1 + ") (len=" + kkLen + ") " +
+ "\"two\": (" + mt2 + ") 2,\n (" + mt1 + ") (len=" + klen +
+ ") \"one\": (" + mt2 + ") 1\n}"
+ addDumpTest(m, "("+mt+") "+ms+"\n", "("+mt+") "+ms2+"\n")
+ addDumpTest(pm, "(*"+mt+")("+mAddr+")("+ms+")\n",
+ "(*"+mt+")("+mAddr+")("+ms2+")\n")
+ addDumpTest(&pm, "(**"+mt+")("+pmAddr+"->"+mAddr+")("+ms+")\n",
+ "(**"+mt+")("+pmAddr+"->"+mAddr+")("+ms2+")\n")
+ addDumpTest(nm, "(*"+mt+")()\n")
+ addDumpTest(nilMap, "("+mt+") \n")
+
+ // Map with custom formatter type on pointer receiver only keys and vals.
+ k2 := pstringer("one")
+ v2 := pstringer("1")
+ m2 := map[pstringer]pstringer{k2: v2}
+ k2Len := fmt.Sprintf("%d", len(k2))
+ v2Len := fmt.Sprintf("%d", len(v2))
+ m2Len := fmt.Sprintf("%d", len(m2))
+ nilMap2 := map[pstringer]pstringer(nil)
+ nm2 := (*map[pstringer]pstringer)(nil)
+ pm2 := &m2
+ m2Addr := fmt.Sprintf("%p", pm2)
+ pm2Addr := fmt.Sprintf("%p", &pm2)
+ m2t := "map[spew_test.pstringer]spew_test.pstringer"
+ m2t1 := "spew_test.pstringer"
+ m2t2 := "spew_test.pstringer"
+ m2s := "(len=" + m2Len + ") {\n (" + m2t1 + ") (len=" + k2Len + ") " +
+ "stringer one: (" + m2t2 + ") (len=" + v2Len + ") stringer 1\n}"
+ if spew.UnsafeDisabled {
+ m2s = "(len=" + m2Len + ") {\n (" + m2t1 + ") (len=" + k2Len +
+ ") " + "\"one\": (" + m2t2 + ") (len=" + v2Len +
+ ") \"1\"\n}"
+ }
+ addDumpTest(m2, "("+m2t+") "+m2s+"\n")
+ addDumpTest(pm2, "(*"+m2t+")("+m2Addr+")("+m2s+")\n")
+ addDumpTest(&pm2, "(**"+m2t+")("+pm2Addr+"->"+m2Addr+")("+m2s+")\n")
+ addDumpTest(nm2, "(*"+m2t+")()\n")
+ addDumpTest(nilMap2, "("+m2t+") \n")
+
+ // Map with interface keys and values.
+ k3 := "one"
+ k3Len := fmt.Sprintf("%d", len(k3))
+ m3 := map[interface{}]interface{}{k3: 1}
+ m3Len := fmt.Sprintf("%d", len(m3))
+ nilMap3 := map[interface{}]interface{}(nil)
+ nm3 := (*map[interface{}]interface{})(nil)
+ pm3 := &m3
+ m3Addr := fmt.Sprintf("%p", pm3)
+ pm3Addr := fmt.Sprintf("%p", &pm3)
+ m3t := "map[interface {}]interface {}"
+ m3t1 := "string"
+ m3t2 := "int"
+ m3s := "(len=" + m3Len + ") {\n (" + m3t1 + ") (len=" + k3Len + ") " +
+ "\"one\": (" + m3t2 + ") 1\n}"
+ addDumpTest(m3, "("+m3t+") "+m3s+"\n")
+ addDumpTest(pm3, "(*"+m3t+")("+m3Addr+")("+m3s+")\n")
+ addDumpTest(&pm3, "(**"+m3t+")("+pm3Addr+"->"+m3Addr+")("+m3s+")\n")
+ addDumpTest(nm3, "(*"+m3t+")()\n")
+ addDumpTest(nilMap3, "("+m3t+") \n")
+
+ // Map with nil interface value.
+ k4 := "nil"
+ k4Len := fmt.Sprintf("%d", len(k4))
+ m4 := map[string]interface{}{k4: nil}
+ m4Len := fmt.Sprintf("%d", len(m4))
+ nilMap4 := map[string]interface{}(nil)
+ nm4 := (*map[string]interface{})(nil)
+ pm4 := &m4
+ m4Addr := fmt.Sprintf("%p", pm4)
+ pm4Addr := fmt.Sprintf("%p", &pm4)
+ m4t := "map[string]interface {}"
+ m4t1 := "string"
+ m4t2 := "interface {}"
+ m4s := "(len=" + m4Len + ") {\n (" + m4t1 + ") (len=" + k4Len + ")" +
+ " \"nil\": (" + m4t2 + ") \n}"
+ addDumpTest(m4, "("+m4t+") "+m4s+"\n")
+ addDumpTest(pm4, "(*"+m4t+")("+m4Addr+")("+m4s+")\n")
+ addDumpTest(&pm4, "(**"+m4t+")("+pm4Addr+"->"+m4Addr+")("+m4s+")\n")
+ addDumpTest(nm4, "(*"+m4t+")()\n")
+ addDumpTest(nilMap4, "("+m4t+") \n")
+}
+
+func addStructDumpTests() {
+ // Struct with primitives.
+ type s1 struct {
+ a int8
+ b uint8
+ }
+ v := s1{127, 255}
+ nv := (*s1)(nil)
+ pv := &v
+ vAddr := fmt.Sprintf("%p", pv)
+ pvAddr := fmt.Sprintf("%p", &pv)
+ vt := "spew_test.s1"
+ vt2 := "int8"
+ vt3 := "uint8"
+ vs := "{\n a: (" + vt2 + ") 127,\n b: (" + vt3 + ") 255\n}"
+ addDumpTest(v, "("+vt+") "+vs+"\n")
+ addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
+ addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
+ addDumpTest(nv, "(*"+vt+")()\n")
+
+ // Struct that contains another struct.
+ type s2 struct {
+ s1 s1
+ b bool
+ }
+ v2 := s2{s1{127, 255}, true}
+ nv2 := (*s2)(nil)
+ pv2 := &v2
+ v2Addr := fmt.Sprintf("%p", pv2)
+ pv2Addr := fmt.Sprintf("%p", &pv2)
+ v2t := "spew_test.s2"
+ v2t2 := "spew_test.s1"
+ v2t3 := "int8"
+ v2t4 := "uint8"
+ v2t5 := "bool"
+ v2s := "{\n s1: (" + v2t2 + ") {\n a: (" + v2t3 + ") 127,\n b: (" +
+ v2t4 + ") 255\n },\n b: (" + v2t5 + ") true\n}"
+ addDumpTest(v2, "("+v2t+") "+v2s+"\n")
+ addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n")
+ addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
+ addDumpTest(nv2, "(*"+v2t+")()\n")
+
+ // Struct that contains custom type with Stringer pointer interface via both
+ // exported and unexported fields.
+ type s3 struct {
+ s pstringer
+ S pstringer
+ }
+ v3 := s3{"test", "test2"}
+ nv3 := (*s3)(nil)
+ pv3 := &v3
+ v3Addr := fmt.Sprintf("%p", pv3)
+ pv3Addr := fmt.Sprintf("%p", &pv3)
+ v3t := "spew_test.s3"
+ v3t2 := "spew_test.pstringer"
+ v3s := "{\n s: (" + v3t2 + ") (len=4) stringer test,\n S: (" + v3t2 +
+ ") (len=5) stringer test2\n}"
+ v3sp := v3s
+ if spew.UnsafeDisabled {
+ v3s = "{\n s: (" + v3t2 + ") (len=4) \"test\",\n S: (" +
+ v3t2 + ") (len=5) \"test2\"\n}"
+ v3sp = "{\n s: (" + v3t2 + ") (len=4) \"test\",\n S: (" +
+ v3t2 + ") (len=5) stringer test2\n}"
+ }
+ addDumpTest(v3, "("+v3t+") "+v3s+"\n")
+ addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3sp+")\n")
+ addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3sp+")\n")
+ addDumpTest(nv3, "(*"+v3t+")()\n")
+
+ // Struct that contains embedded struct and field to same struct.
+ e := embed{"embedstr"}
+ eLen := fmt.Sprintf("%d", len("embedstr"))
+ v4 := embedwrap{embed: &e, e: &e}
+ nv4 := (*embedwrap)(nil)
+ pv4 := &v4
+ eAddr := fmt.Sprintf("%p", &e)
+ v4Addr := fmt.Sprintf("%p", pv4)
+ pv4Addr := fmt.Sprintf("%p", &pv4)
+ v4t := "spew_test.embedwrap"
+ v4t2 := "spew_test.embed"
+ v4t3 := "string"
+ v4s := "{\n embed: (*" + v4t2 + ")(" + eAddr + ")({\n a: (" + v4t3 +
+ ") (len=" + eLen + ") \"embedstr\"\n }),\n e: (*" + v4t2 +
+ ")(" + eAddr + ")({\n a: (" + v4t3 + ") (len=" + eLen + ")" +
+ " \"embedstr\"\n })\n}"
+ addDumpTest(v4, "("+v4t+") "+v4s+"\n")
+ addDumpTest(pv4, "(*"+v4t+")("+v4Addr+")("+v4s+")\n")
+ addDumpTest(&pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")("+v4s+")\n")
+ addDumpTest(nv4, "(*"+v4t+")()\n")
+}
+
+func addUintptrDumpTests() {
+ // Null pointer.
+ v := uintptr(0)
+ pv := &v
+ vAddr := fmt.Sprintf("%p", pv)
+ pvAddr := fmt.Sprintf("%p", &pv)
+ vt := "uintptr"
+ vs := ""
+ addDumpTest(v, "("+vt+") "+vs+"\n")
+ addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
+ addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
+
+ // Address of real variable.
+ i := 1
+ v2 := uintptr(unsafe.Pointer(&i))
+ nv2 := (*uintptr)(nil)
+ pv2 := &v2
+ v2Addr := fmt.Sprintf("%p", pv2)
+ pv2Addr := fmt.Sprintf("%p", &pv2)
+ v2t := "uintptr"
+ v2s := fmt.Sprintf("%p", &i)
+ addDumpTest(v2, "("+v2t+") "+v2s+"\n")
+ addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n")
+ addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
+ addDumpTest(nv2, "(*"+v2t+")()\n")
+}
+
+func addUnsafePointerDumpTests() {
+ // Null pointer.
+ v := unsafe.Pointer(uintptr(0))
+ nv := (*unsafe.Pointer)(nil)
+ pv := &v
+ vAddr := fmt.Sprintf("%p", pv)
+ pvAddr := fmt.Sprintf("%p", &pv)
+ vt := "unsafe.Pointer"
+ vs := ""
+ addDumpTest(v, "("+vt+") "+vs+"\n")
+ addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
+ addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
+ addDumpTest(nv, "(*"+vt+")()\n")
+
+ // Address of real variable.
+ i := 1
+ v2 := unsafe.Pointer(&i)
+ pv2 := &v2
+ v2Addr := fmt.Sprintf("%p", pv2)
+ pv2Addr := fmt.Sprintf("%p", &pv2)
+ v2t := "unsafe.Pointer"
+ v2s := fmt.Sprintf("%p", &i)
+ addDumpTest(v2, "("+v2t+") "+v2s+"\n")
+ addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n")
+ addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
+ addDumpTest(nv, "(*"+vt+")()\n")
+}
+
+func addChanDumpTests() {
+ // Nil channel.
+ var v chan int
+ pv := &v
+ nv := (*chan int)(nil)
+ vAddr := fmt.Sprintf("%p", pv)
+ pvAddr := fmt.Sprintf("%p", &pv)
+ vt := "chan int"
+ vs := ""
+ addDumpTest(v, "("+vt+") "+vs+"\n")
+ addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
+ addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
+ addDumpTest(nv, "(*"+vt+")()\n")
+
+ // Real channel.
+ v2 := make(chan int)
+ pv2 := &v2
+ v2Addr := fmt.Sprintf("%p", pv2)
+ pv2Addr := fmt.Sprintf("%p", &pv2)
+ v2t := "chan int"
+ v2s := fmt.Sprintf("%p", v2)
+ addDumpTest(v2, "("+v2t+") "+v2s+"\n")
+ addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n")
+ addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
+}
+
+func addFuncDumpTests() {
+ // Function with no params and no returns.
+ v := addIntDumpTests
+ nv := (*func())(nil)
+ pv := &v
+ vAddr := fmt.Sprintf("%p", pv)
+ pvAddr := fmt.Sprintf("%p", &pv)
+ vt := "func()"
+ vs := fmt.Sprintf("%p", v)
+ addDumpTest(v, "("+vt+") "+vs+"\n")
+ addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
+ addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
+ addDumpTest(nv, "(*"+vt+")()\n")
+
+ // Function with param and no returns.
+ v2 := TestDump
+ nv2 := (*func(*testing.T))(nil)
+ pv2 := &v2
+ v2Addr := fmt.Sprintf("%p", pv2)
+ pv2Addr := fmt.Sprintf("%p", &pv2)
+ v2t := "func(*testing.T)"
+ v2s := fmt.Sprintf("%p", v2)
+ addDumpTest(v2, "("+v2t+") "+v2s+"\n")
+ addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n")
+ addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
+ addDumpTest(nv2, "(*"+v2t+")()\n")
+
+ // Function with multiple params and multiple returns.
+ var v3 = func(i int, s string) (b bool, err error) {
+ return true, nil
+ }
+ nv3 := (*func(int, string) (bool, error))(nil)
+ pv3 := &v3
+ v3Addr := fmt.Sprintf("%p", pv3)
+ pv3Addr := fmt.Sprintf("%p", &pv3)
+ v3t := "func(int, string) (bool, error)"
+ v3s := fmt.Sprintf("%p", v3)
+ addDumpTest(v3, "("+v3t+") "+v3s+"\n")
+ addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s+")\n")
+ addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s+")\n")
+ addDumpTest(nv3, "(*"+v3t+")()\n")
+}
+
+func addCircularDumpTests() {
+ // Struct that is circular through self referencing.
+ type circular struct {
+ c *circular
+ }
+ v := circular{nil}
+ v.c = &v
+ pv := &v
+ vAddr := fmt.Sprintf("%p", pv)
+ pvAddr := fmt.Sprintf("%p", &pv)
+ vt := "spew_test.circular"
+ vs := "{\n c: (*" + vt + ")(" + vAddr + ")({\n c: (*" + vt + ")(" +
+ vAddr + ")()\n })\n}"
+ vs2 := "{\n c: (*" + vt + ")(" + vAddr + ")()\n}"
+ addDumpTest(v, "("+vt+") "+vs+"\n")
+ addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs2+")\n")
+ addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs2+")\n")
+
+ // Structs that are circular through cross referencing.
+ v2 := xref1{nil}
+ ts2 := xref2{&v2}
+ v2.ps2 = &ts2
+ pv2 := &v2
+ ts2Addr := fmt.Sprintf("%p", &ts2)
+ v2Addr := fmt.Sprintf("%p", pv2)
+ pv2Addr := fmt.Sprintf("%p", &pv2)
+ v2t := "spew_test.xref1"
+ v2t2 := "spew_test.xref2"
+ v2s := "{\n ps2: (*" + v2t2 + ")(" + ts2Addr + ")({\n ps1: (*" + v2t +
+ ")(" + v2Addr + ")({\n ps2: (*" + v2t2 + ")(" + ts2Addr +
+ ")()\n })\n })\n}"
+ v2s2 := "{\n ps2: (*" + v2t2 + ")(" + ts2Addr + ")({\n ps1: (*" + v2t +
+ ")(" + v2Addr + ")()\n })\n}"
+ addDumpTest(v2, "("+v2t+") "+v2s+"\n")
+ addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s2+")\n")
+ addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s2+")\n")
+
+ // Structs that are indirectly circular.
+ v3 := indirCir1{nil}
+ tic2 := indirCir2{nil}
+ tic3 := indirCir3{&v3}
+ tic2.ps3 = &tic3
+ v3.ps2 = &tic2
+ pv3 := &v3
+ tic2Addr := fmt.Sprintf("%p", &tic2)
+ tic3Addr := fmt.Sprintf("%p", &tic3)
+ v3Addr := fmt.Sprintf("%p", pv3)
+ pv3Addr := fmt.Sprintf("%p", &pv3)
+ v3t := "spew_test.indirCir1"
+ v3t2 := "spew_test.indirCir2"
+ v3t3 := "spew_test.indirCir3"
+ v3s := "{\n ps2: (*" + v3t2 + ")(" + tic2Addr + ")({\n ps3: (*" + v3t3 +
+ ")(" + tic3Addr + ")({\n ps1: (*" + v3t + ")(" + v3Addr +
+ ")({\n ps2: (*" + v3t2 + ")(" + tic2Addr +
+ ")()\n })\n })\n })\n}"
+ v3s2 := "{\n ps2: (*" + v3t2 + ")(" + tic2Addr + ")({\n ps3: (*" + v3t3 +
+ ")(" + tic3Addr + ")({\n ps1: (*" + v3t + ")(" + v3Addr +
+ ")()\n })\n })\n}"
+ addDumpTest(v3, "("+v3t+") "+v3s+"\n")
+ addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s2+")\n")
+ addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s2+")\n")
+}
+
+func addPanicDumpTests() {
+ // Type that panics in its Stringer interface.
+ v := panicer(127)
+ nv := (*panicer)(nil)
+ pv := &v
+ vAddr := fmt.Sprintf("%p", pv)
+ pvAddr := fmt.Sprintf("%p", &pv)
+ vt := "spew_test.panicer"
+ vs := "(PANIC=test panic)127"
+ addDumpTest(v, "("+vt+") "+vs+"\n")
+ addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
+ addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
+ addDumpTest(nv, "(*"+vt+")()\n")
+}
+
+func addErrorDumpTests() {
+ // Type that has a custom Error interface.
+ v := customError(127)
+ nv := (*customError)(nil)
+ pv := &v
+ vAddr := fmt.Sprintf("%p", pv)
+ pvAddr := fmt.Sprintf("%p", &pv)
+ vt := "spew_test.customError"
+ vs := "error: 127"
+ addDumpTest(v, "("+vt+") "+vs+"\n")
+ addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
+ addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
+ addDumpTest(nv, "(*"+vt+")()\n")
+}
+
+// TestDump executes all of the tests described by dumpTests.
+func TestDump(t *testing.T) {
+ // Setup tests.
+ addIntDumpTests()
+ addUintDumpTests()
+ addBoolDumpTests()
+ addFloatDumpTests()
+ addComplexDumpTests()
+ addArrayDumpTests()
+ addSliceDumpTests()
+ addStringDumpTests()
+ addInterfaceDumpTests()
+ addMapDumpTests()
+ addStructDumpTests()
+ addUintptrDumpTests()
+ addUnsafePointerDumpTests()
+ addChanDumpTests()
+ addFuncDumpTests()
+ addCircularDumpTests()
+ addPanicDumpTests()
+ addErrorDumpTests()
+ addCgoDumpTests()
+
+ t.Logf("Running %d tests", len(dumpTests))
+ for i, test := range dumpTests {
+ buf := new(bytes.Buffer)
+ spew.Fdump(buf, test.in)
+ s := buf.String()
+ if testFailed(s, test.wants) {
+ t.Errorf("Dump #%d\n got: %s %s", i, s, stringizeWants(test.wants))
+ continue
+ }
+ }
+}
+
+func TestDumpSortedKeys(t *testing.T) {
+ cfg := spew.ConfigState{SortKeys: true}
+ s := cfg.Sdump(map[int]string{1: "1", 3: "3", 2: "2"})
+ expected := "(map[int]string) (len=3) {\n(int) 1: (string) (len=1) " +
+ "\"1\",\n(int) 2: (string) (len=1) \"2\",\n(int) 3: (string) " +
+ "(len=1) \"3\"\n" +
+ "}\n"
+ if s != expected {
+ t.Errorf("Sorted keys mismatch:\n %v %v", s, expected)
+ }
+
+ s = cfg.Sdump(map[stringer]int{"1": 1, "3": 3, "2": 2})
+ expected = "(map[spew_test.stringer]int) (len=3) {\n" +
+ "(spew_test.stringer) (len=1) stringer 1: (int) 1,\n" +
+ "(spew_test.stringer) (len=1) stringer 2: (int) 2,\n" +
+ "(spew_test.stringer) (len=1) stringer 3: (int) 3\n" +
+ "}\n"
+ if s != expected {
+ t.Errorf("Sorted keys mismatch:\n %v %v", s, expected)
+ }
+
+ s = cfg.Sdump(map[pstringer]int{pstringer("1"): 1, pstringer("3"): 3, pstringer("2"): 2})
+ expected = "(map[spew_test.pstringer]int) (len=3) {\n" +
+ "(spew_test.pstringer) (len=1) stringer 1: (int) 1,\n" +
+ "(spew_test.pstringer) (len=1) stringer 2: (int) 2,\n" +
+ "(spew_test.pstringer) (len=1) stringer 3: (int) 3\n" +
+ "}\n"
+ if spew.UnsafeDisabled {
+ expected = "(map[spew_test.pstringer]int) (len=3) {\n" +
+ "(spew_test.pstringer) (len=1) \"1\": (int) 1,\n" +
+ "(spew_test.pstringer) (len=1) \"2\": (int) 2,\n" +
+ "(spew_test.pstringer) (len=1) \"3\": (int) 3\n" +
+ "}\n"
+ }
+ if s != expected {
+ t.Errorf("Sorted keys mismatch:\n %v %v", s, expected)
+ }
+
+ s = cfg.Sdump(map[customError]int{customError(1): 1, customError(3): 3, customError(2): 2})
+ expected = "(map[spew_test.customError]int) (len=3) {\n" +
+ "(spew_test.customError) error: 1: (int) 1,\n" +
+ "(spew_test.customError) error: 2: (int) 2,\n" +
+ "(spew_test.customError) error: 3: (int) 3\n" +
+ "}\n"
+ if s != expected {
+ t.Errorf("Sorted keys mismatch:\n %v %v", s, expected)
+ }
+
+}
diff --git a/vendor/github.com/davecgh/go-spew/spew/dumpcgo_test.go b/vendor/github.com/davecgh/go-spew/spew/dumpcgo_test.go
new file mode 100644
index 00000000000..6ab180809a6
--- /dev/null
+++ b/vendor/github.com/davecgh/go-spew/spew/dumpcgo_test.go
@@ -0,0 +1,99 @@
+// Copyright (c) 2013-2016 Dave Collins
+//
+// Permission to use, copy, modify, and distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+// NOTE: Due to the following build constraints, this file will only be compiled
+// when both cgo is supported and "-tags testcgo" is added to the go test
+// command line. This means the cgo tests are only added (and hence run) when
+// specifially requested. This configuration is used because spew itself
+// does not require cgo to run even though it does handle certain cgo types
+// specially. Rather than forcing all clients to require cgo and an external
+// C compiler just to run the tests, this scheme makes them optional.
+// +build cgo,testcgo
+
+package spew_test
+
+import (
+ "fmt"
+
+ "github.com/davecgh/go-spew/spew/testdata"
+)
+
+func addCgoDumpTests() {
+ // C char pointer.
+ v := testdata.GetCgoCharPointer()
+ nv := testdata.GetCgoNullCharPointer()
+ pv := &v
+ vcAddr := fmt.Sprintf("%p", v)
+ vAddr := fmt.Sprintf("%p", pv)
+ pvAddr := fmt.Sprintf("%p", &pv)
+ vt := "*testdata._Ctype_char"
+ vs := "116"
+ addDumpTest(v, "("+vt+")("+vcAddr+")("+vs+")\n")
+ addDumpTest(pv, "(*"+vt+")("+vAddr+"->"+vcAddr+")("+vs+")\n")
+ addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+"->"+vcAddr+")("+vs+")\n")
+ addDumpTest(nv, "("+vt+")()\n")
+
+ // C char array.
+ v2, v2l, v2c := testdata.GetCgoCharArray()
+ v2Len := fmt.Sprintf("%d", v2l)
+ v2Cap := fmt.Sprintf("%d", v2c)
+ v2t := "[6]testdata._Ctype_char"
+ v2s := "(len=" + v2Len + " cap=" + v2Cap + ") " +
+ "{\n 00000000 74 65 73 74 32 00 " +
+ " |test2.|\n}"
+ addDumpTest(v2, "("+v2t+") "+v2s+"\n")
+
+ // C unsigned char array.
+ v3, v3l, v3c := testdata.GetCgoUnsignedCharArray()
+ v3Len := fmt.Sprintf("%d", v3l)
+ v3Cap := fmt.Sprintf("%d", v3c)
+ v3t := "[6]testdata._Ctype_unsignedchar"
+ v3t2 := "[6]testdata._Ctype_uchar"
+ v3s := "(len=" + v3Len + " cap=" + v3Cap + ") " +
+ "{\n 00000000 74 65 73 74 33 00 " +
+ " |test3.|\n}"
+ addDumpTest(v3, "("+v3t+") "+v3s+"\n", "("+v3t2+") "+v3s+"\n")
+
+ // C signed char array.
+ v4, v4l, v4c := testdata.GetCgoSignedCharArray()
+ v4Len := fmt.Sprintf("%d", v4l)
+ v4Cap := fmt.Sprintf("%d", v4c)
+ v4t := "[6]testdata._Ctype_schar"
+ v4t2 := "testdata._Ctype_schar"
+ v4s := "(len=" + v4Len + " cap=" + v4Cap + ") " +
+ "{\n (" + v4t2 + ") 116,\n (" + v4t2 + ") 101,\n (" + v4t2 +
+ ") 115,\n (" + v4t2 + ") 116,\n (" + v4t2 + ") 52,\n (" + v4t2 +
+ ") 0\n}"
+ addDumpTest(v4, "("+v4t+") "+v4s+"\n")
+
+ // C uint8_t array.
+ v5, v5l, v5c := testdata.GetCgoUint8tArray()
+ v5Len := fmt.Sprintf("%d", v5l)
+ v5Cap := fmt.Sprintf("%d", v5c)
+ v5t := "[6]testdata._Ctype_uint8_t"
+ v5s := "(len=" + v5Len + " cap=" + v5Cap + ") " +
+ "{\n 00000000 74 65 73 74 35 00 " +
+ " |test5.|\n}"
+ addDumpTest(v5, "("+v5t+") "+v5s+"\n")
+
+ // C typedefed unsigned char array.
+ v6, v6l, v6c := testdata.GetCgoTypdefedUnsignedCharArray()
+ v6Len := fmt.Sprintf("%d", v6l)
+ v6Cap := fmt.Sprintf("%d", v6c)
+ v6t := "[6]testdata._Ctype_custom_uchar_t"
+ v6s := "(len=" + v6Len + " cap=" + v6Cap + ") " +
+ "{\n 00000000 74 65 73 74 36 00 " +
+ " |test6.|\n}"
+ addDumpTest(v6, "("+v6t+") "+v6s+"\n")
+}
diff --git a/vendor/github.com/davecgh/go-spew/spew/dumpnocgo_test.go b/vendor/github.com/davecgh/go-spew/spew/dumpnocgo_test.go
new file mode 100644
index 00000000000..52a0971fb3f
--- /dev/null
+++ b/vendor/github.com/davecgh/go-spew/spew/dumpnocgo_test.go
@@ -0,0 +1,26 @@
+// Copyright (c) 2013 Dave Collins
+//
+// Permission to use, copy, modify, and distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+// NOTE: Due to the following build constraints, this file will only be compiled
+// when either cgo is not supported or "-tags testcgo" is not added to the go
+// test command line. This file intentionally does not setup any cgo tests in
+// this scenario.
+// +build !cgo !testcgo
+
+package spew_test
+
+func addCgoDumpTests() {
+ // Don't add any tests for cgo since this file is only compiled when
+ // there should not be any cgo tests.
+}
diff --git a/vendor/github.com/davecgh/go-spew/spew/example_test.go b/vendor/github.com/davecgh/go-spew/spew/example_test.go
new file mode 100644
index 00000000000..c6ec8c6d59e
--- /dev/null
+++ b/vendor/github.com/davecgh/go-spew/spew/example_test.go
@@ -0,0 +1,226 @@
+/*
+ * Copyright (c) 2013-2016 Dave Collins
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+package spew_test
+
+import (
+ "fmt"
+
+ "github.com/davecgh/go-spew/spew"
+)
+
+type Flag int
+
+const (
+ flagOne Flag = iota
+ flagTwo
+)
+
+var flagStrings = map[Flag]string{
+ flagOne: "flagOne",
+ flagTwo: "flagTwo",
+}
+
+func (f Flag) String() string {
+ if s, ok := flagStrings[f]; ok {
+ return s
+ }
+ return fmt.Sprintf("Unknown flag (%d)", int(f))
+}
+
+type Bar struct {
+ data uintptr
+}
+
+type Foo struct {
+ unexportedField Bar
+ ExportedField map[interface{}]interface{}
+}
+
+// This example demonstrates how to use Dump to dump variables to stdout.
+func ExampleDump() {
+ // The following package level declarations are assumed for this example:
+ /*
+ type Flag int
+
+ const (
+ flagOne Flag = iota
+ flagTwo
+ )
+
+ var flagStrings = map[Flag]string{
+ flagOne: "flagOne",
+ flagTwo: "flagTwo",
+ }
+
+ func (f Flag) String() string {
+ if s, ok := flagStrings[f]; ok {
+ return s
+ }
+ return fmt.Sprintf("Unknown flag (%d)", int(f))
+ }
+
+ type Bar struct {
+ data uintptr
+ }
+
+ type Foo struct {
+ unexportedField Bar
+ ExportedField map[interface{}]interface{}
+ }
+ */
+
+ // Setup some sample data structures for the example.
+ bar := Bar{uintptr(0)}
+ s1 := Foo{bar, map[interface{}]interface{}{"one": true}}
+ f := Flag(5)
+ b := []byte{
+ 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+ 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
+ 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
+ 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
+ 0x31, 0x32,
+ }
+
+ // Dump!
+ spew.Dump(s1, f, b)
+
+ // Output:
+ // (spew_test.Foo) {
+ // unexportedField: (spew_test.Bar) {
+ // data: (uintptr)
+ // },
+ // ExportedField: (map[interface {}]interface {}) (len=1) {
+ // (string) (len=3) "one": (bool) true
+ // }
+ // }
+ // (spew_test.Flag) Unknown flag (5)
+ // ([]uint8) (len=34 cap=34) {
+ // 00000000 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 |............... |
+ // 00000010 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 |!"#$%&'()*+,-./0|
+ // 00000020 31 32 |12|
+ // }
+ //
+}
+
+// This example demonstrates how to use Printf to display a variable with a
+// format string and inline formatting.
+func ExamplePrintf() {
+ // Create a double pointer to a uint 8.
+ ui8 := uint8(5)
+ pui8 := &ui8
+ ppui8 := &pui8
+
+ // Create a circular data type.
+ type circular struct {
+ ui8 uint8
+ c *circular
+ }
+ c := circular{ui8: 1}
+ c.c = &c
+
+ // Print!
+ spew.Printf("ppui8: %v\n", ppui8)
+ spew.Printf("circular: %v\n", c)
+
+ // Output:
+ // ppui8: <**>5
+ // circular: {1 <*>{1 <*>}}
+}
+
+// This example demonstrates how to use a ConfigState.
+func ExampleConfigState() {
+ // Modify the indent level of the ConfigState only. The global
+ // configuration is not modified.
+ scs := spew.ConfigState{Indent: "\t"}
+
+ // Output using the ConfigState instance.
+ v := map[string]int{"one": 1}
+ scs.Printf("v: %v\n", v)
+ scs.Dump(v)
+
+ // Output:
+ // v: map[one:1]
+ // (map[string]int) (len=1) {
+ // (string) (len=3) "one": (int) 1
+ // }
+}
+
+// This example demonstrates how to use ConfigState.Dump to dump variables to
+// stdout
+func ExampleConfigState_Dump() {
+ // See the top-level Dump example for details on the types used in this
+ // example.
+
+ // Create two ConfigState instances with different indentation.
+ scs := spew.ConfigState{Indent: "\t"}
+ scs2 := spew.ConfigState{Indent: " "}
+
+ // Setup some sample data structures for the example.
+ bar := Bar{uintptr(0)}
+ s1 := Foo{bar, map[interface{}]interface{}{"one": true}}
+
+ // Dump using the ConfigState instances.
+ scs.Dump(s1)
+ scs2.Dump(s1)
+
+ // Output:
+ // (spew_test.Foo) {
+ // unexportedField: (spew_test.Bar) {
+ // data: (uintptr)
+ // },
+ // ExportedField: (map[interface {}]interface {}) (len=1) {
+ // (string) (len=3) "one": (bool) true
+ // }
+ // }
+ // (spew_test.Foo) {
+ // unexportedField: (spew_test.Bar) {
+ // data: (uintptr)
+ // },
+ // ExportedField: (map[interface {}]interface {}) (len=1) {
+ // (string) (len=3) "one": (bool) true
+ // }
+ // }
+ //
+}
+
+// This example demonstrates how to use ConfigState.Printf to display a variable
+// with a format string and inline formatting.
+func ExampleConfigState_Printf() {
+ // See the top-level Dump example for details on the types used in this
+ // example.
+
+ // Create two ConfigState instances and modify the method handling of the
+ // first ConfigState only.
+ scs := spew.NewDefaultConfig()
+ scs2 := spew.NewDefaultConfig()
+ scs.DisableMethods = true
+
+ // Alternatively
+ // scs := spew.ConfigState{Indent: " ", DisableMethods: true}
+ // scs2 := spew.ConfigState{Indent: " "}
+
+ // This is of type Flag which implements a Stringer and has raw value 1.
+ f := flagTwo
+
+ // Dump using the ConfigState instances.
+ scs.Printf("f: %v\n", f)
+ scs2.Printf("f: %v\n", f)
+
+ // Output:
+ // f: 1
+ // f: flagTwo
+}
diff --git a/vendor/github.com/davecgh/go-spew/spew/format.go b/vendor/github.com/davecgh/go-spew/spew/format.go
new file mode 100644
index 00000000000..c49875bacbb
--- /dev/null
+++ b/vendor/github.com/davecgh/go-spew/spew/format.go
@@ -0,0 +1,419 @@
+/*
+ * Copyright (c) 2013-2016 Dave Collins
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+package spew
+
+import (
+ "bytes"
+ "fmt"
+ "reflect"
+ "strconv"
+ "strings"
+)
+
+// supportedFlags is a list of all the character flags supported by fmt package.
+const supportedFlags = "0-+# "
+
+// formatState implements the fmt.Formatter interface and contains information
+// about the state of a formatting operation. The NewFormatter function can
+// be used to get a new Formatter which can be used directly as arguments
+// in standard fmt package printing calls.
+type formatState struct {
+ value interface{}
+ fs fmt.State
+ depth int
+ pointers map[uintptr]int
+ ignoreNextType bool
+ cs *ConfigState
+}
+
+// buildDefaultFormat recreates the original format string without precision
+// and width information to pass in to fmt.Sprintf in the case of an
+// unrecognized type. Unless new types are added to the language, this
+// function won't ever be called.
+func (f *formatState) buildDefaultFormat() (format string) {
+ buf := bytes.NewBuffer(percentBytes)
+
+ for _, flag := range supportedFlags {
+ if f.fs.Flag(int(flag)) {
+ buf.WriteRune(flag)
+ }
+ }
+
+ buf.WriteRune('v')
+
+ format = buf.String()
+ return format
+}
+
+// constructOrigFormat recreates the original format string including precision
+// and width information to pass along to the standard fmt package. This allows
+// automatic deferral of all format strings this package doesn't support.
+func (f *formatState) constructOrigFormat(verb rune) (format string) {
+ buf := bytes.NewBuffer(percentBytes)
+
+ for _, flag := range supportedFlags {
+ if f.fs.Flag(int(flag)) {
+ buf.WriteRune(flag)
+ }
+ }
+
+ if width, ok := f.fs.Width(); ok {
+ buf.WriteString(strconv.Itoa(width))
+ }
+
+ if precision, ok := f.fs.Precision(); ok {
+ buf.Write(precisionBytes)
+ buf.WriteString(strconv.Itoa(precision))
+ }
+
+ buf.WriteRune(verb)
+
+ format = buf.String()
+ return format
+}
+
+// unpackValue returns values inside of non-nil interfaces when possible and
+// ensures that types for values which have been unpacked from an interface
+// are displayed when the show types flag is also set.
+// This is useful for data types like structs, arrays, slices, and maps which
+// can contain varying types packed inside an interface.
+func (f *formatState) unpackValue(v reflect.Value) reflect.Value {
+ if v.Kind() == reflect.Interface {
+ f.ignoreNextType = false
+ if !v.IsNil() {
+ v = v.Elem()
+ }
+ }
+ return v
+}
+
+// formatPtr handles formatting of pointers by indirecting them as necessary.
+func (f *formatState) formatPtr(v reflect.Value) {
+ // Display nil if top level pointer is nil.
+ showTypes := f.fs.Flag('#')
+ if v.IsNil() && (!showTypes || f.ignoreNextType) {
+ f.fs.Write(nilAngleBytes)
+ return
+ }
+
+ // Remove pointers at or below the current depth from map used to detect
+ // circular refs.
+ for k, depth := range f.pointers {
+ if depth >= f.depth {
+ delete(f.pointers, k)
+ }
+ }
+
+ // Keep list of all dereferenced pointers to possibly show later.
+ pointerChain := make([]uintptr, 0)
+
+ // Figure out how many levels of indirection there are by derferencing
+ // pointers and unpacking interfaces down the chain while detecting circular
+ // references.
+ nilFound := false
+ cycleFound := false
+ indirects := 0
+ ve := v
+ for ve.Kind() == reflect.Ptr {
+ if ve.IsNil() {
+ nilFound = true
+ break
+ }
+ indirects++
+ addr := ve.Pointer()
+ pointerChain = append(pointerChain, addr)
+ if pd, ok := f.pointers[addr]; ok && pd < f.depth {
+ cycleFound = true
+ indirects--
+ break
+ }
+ f.pointers[addr] = f.depth
+
+ ve = ve.Elem()
+ if ve.Kind() == reflect.Interface {
+ if ve.IsNil() {
+ nilFound = true
+ break
+ }
+ ve = ve.Elem()
+ }
+ }
+
+ // Display type or indirection level depending on flags.
+ if showTypes && !f.ignoreNextType {
+ f.fs.Write(openParenBytes)
+ f.fs.Write(bytes.Repeat(asteriskBytes, indirects))
+ f.fs.Write([]byte(ve.Type().String()))
+ f.fs.Write(closeParenBytes)
+ } else {
+ if nilFound || cycleFound {
+ indirects += strings.Count(ve.Type().String(), "*")
+ }
+ f.fs.Write(openAngleBytes)
+ f.fs.Write([]byte(strings.Repeat("*", indirects)))
+ f.fs.Write(closeAngleBytes)
+ }
+
+ // Display pointer information depending on flags.
+ if f.fs.Flag('+') && (len(pointerChain) > 0) {
+ f.fs.Write(openParenBytes)
+ for i, addr := range pointerChain {
+ if i > 0 {
+ f.fs.Write(pointerChainBytes)
+ }
+ printHexPtr(f.fs, addr)
+ }
+ f.fs.Write(closeParenBytes)
+ }
+
+ // Display dereferenced value.
+ switch {
+ case nilFound == true:
+ f.fs.Write(nilAngleBytes)
+
+ case cycleFound == true:
+ f.fs.Write(circularShortBytes)
+
+ default:
+ f.ignoreNextType = true
+ f.format(ve)
+ }
+}
+
+// format is the main workhorse for providing the Formatter interface. It
+// uses the passed reflect value to figure out what kind of object we are
+// dealing with and formats it appropriately. It is a recursive function,
+// however circular data structures are detected and handled properly.
+func (f *formatState) format(v reflect.Value) {
+ // Handle invalid reflect values immediately.
+ kind := v.Kind()
+ if kind == reflect.Invalid {
+ f.fs.Write(invalidAngleBytes)
+ return
+ }
+
+ // Handle pointers specially.
+ if kind == reflect.Ptr {
+ f.formatPtr(v)
+ return
+ }
+
+ // Print type information unless already handled elsewhere.
+ if !f.ignoreNextType && f.fs.Flag('#') {
+ f.fs.Write(openParenBytes)
+ f.fs.Write([]byte(v.Type().String()))
+ f.fs.Write(closeParenBytes)
+ }
+ f.ignoreNextType = false
+
+ // Call Stringer/error interfaces if they exist and the handle methods
+ // flag is enabled.
+ if !f.cs.DisableMethods {
+ if (kind != reflect.Invalid) && (kind != reflect.Interface) {
+ if handled := handleMethods(f.cs, f.fs, v); handled {
+ return
+ }
+ }
+ }
+
+ switch kind {
+ case reflect.Invalid:
+ // Do nothing. We should never get here since invalid has already
+ // been handled above.
+
+ case reflect.Bool:
+ printBool(f.fs, v.Bool())
+
+ case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
+ printInt(f.fs, v.Int(), 10)
+
+ case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
+ printUint(f.fs, v.Uint(), 10)
+
+ case reflect.Float32:
+ printFloat(f.fs, v.Float(), 32)
+
+ case reflect.Float64:
+ printFloat(f.fs, v.Float(), 64)
+
+ case reflect.Complex64:
+ printComplex(f.fs, v.Complex(), 32)
+
+ case reflect.Complex128:
+ printComplex(f.fs, v.Complex(), 64)
+
+ case reflect.Slice:
+ if v.IsNil() {
+ f.fs.Write(nilAngleBytes)
+ break
+ }
+ fallthrough
+
+ case reflect.Array:
+ f.fs.Write(openBracketBytes)
+ f.depth++
+ if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) {
+ f.fs.Write(maxShortBytes)
+ } else {
+ numEntries := v.Len()
+ for i := 0; i < numEntries; i++ {
+ if i > 0 {
+ f.fs.Write(spaceBytes)
+ }
+ f.ignoreNextType = true
+ f.format(f.unpackValue(v.Index(i)))
+ }
+ }
+ f.depth--
+ f.fs.Write(closeBracketBytes)
+
+ case reflect.String:
+ f.fs.Write([]byte(v.String()))
+
+ case reflect.Interface:
+ // The only time we should get here is for nil interfaces due to
+ // unpackValue calls.
+ if v.IsNil() {
+ f.fs.Write(nilAngleBytes)
+ }
+
+ case reflect.Ptr:
+ // Do nothing. We should never get here since pointers have already
+ // been handled above.
+
+ case reflect.Map:
+ // nil maps should be indicated as different than empty maps
+ if v.IsNil() {
+ f.fs.Write(nilAngleBytes)
+ break
+ }
+
+ f.fs.Write(openMapBytes)
+ f.depth++
+ if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) {
+ f.fs.Write(maxShortBytes)
+ } else {
+ keys := v.MapKeys()
+ if f.cs.SortKeys {
+ sortValues(keys, f.cs)
+ }
+ for i, key := range keys {
+ if i > 0 {
+ f.fs.Write(spaceBytes)
+ }
+ f.ignoreNextType = true
+ f.format(f.unpackValue(key))
+ f.fs.Write(colonBytes)
+ f.ignoreNextType = true
+ f.format(f.unpackValue(v.MapIndex(key)))
+ }
+ }
+ f.depth--
+ f.fs.Write(closeMapBytes)
+
+ case reflect.Struct:
+ numFields := v.NumField()
+ f.fs.Write(openBraceBytes)
+ f.depth++
+ if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) {
+ f.fs.Write(maxShortBytes)
+ } else {
+ vt := v.Type()
+ for i := 0; i < numFields; i++ {
+ if i > 0 {
+ f.fs.Write(spaceBytes)
+ }
+ vtf := vt.Field(i)
+ if f.fs.Flag('+') || f.fs.Flag('#') {
+ f.fs.Write([]byte(vtf.Name))
+ f.fs.Write(colonBytes)
+ }
+ f.format(f.unpackValue(v.Field(i)))
+ }
+ }
+ f.depth--
+ f.fs.Write(closeBraceBytes)
+
+ case reflect.Uintptr:
+ printHexPtr(f.fs, uintptr(v.Uint()))
+
+ case reflect.UnsafePointer, reflect.Chan, reflect.Func:
+ printHexPtr(f.fs, v.Pointer())
+
+ // There were not any other types at the time this code was written, but
+ // fall back to letting the default fmt package handle it if any get added.
+ default:
+ format := f.buildDefaultFormat()
+ if v.CanInterface() {
+ fmt.Fprintf(f.fs, format, v.Interface())
+ } else {
+ fmt.Fprintf(f.fs, format, v.String())
+ }
+ }
+}
+
+// Format satisfies the fmt.Formatter interface. See NewFormatter for usage
+// details.
+func (f *formatState) Format(fs fmt.State, verb rune) {
+ f.fs = fs
+
+ // Use standard formatting for verbs that are not v.
+ if verb != 'v' {
+ format := f.constructOrigFormat(verb)
+ fmt.Fprintf(fs, format, f.value)
+ return
+ }
+
+ if f.value == nil {
+ if fs.Flag('#') {
+ fs.Write(interfaceBytes)
+ }
+ fs.Write(nilAngleBytes)
+ return
+ }
+
+ f.format(reflect.ValueOf(f.value))
+}
+
+// newFormatter is a helper function to consolidate the logic from the various
+// public methods which take varying config states.
+func newFormatter(cs *ConfigState, v interface{}) fmt.Formatter {
+ fs := &formatState{value: v, cs: cs}
+ fs.pointers = make(map[uintptr]int)
+ return fs
+}
+
+/*
+NewFormatter returns a custom formatter that satisfies the fmt.Formatter
+interface. As a result, it integrates cleanly with standard fmt package
+printing functions. The formatter is useful for inline printing of smaller data
+types similar to the standard %v format specifier.
+
+The custom formatter only responds to the %v (most compact), %+v (adds pointer
+addresses), %#v (adds types), or %#+v (adds types and pointer addresses) verb
+combinations. Any other verbs such as %x and %q will be sent to the the
+standard fmt package for formatting. In addition, the custom formatter ignores
+the width and precision arguments (however they will still work on the format
+specifiers not handled by the custom formatter).
+
+Typically this function shouldn't be called directly. It is much easier to make
+use of the custom formatter by calling one of the convenience functions such as
+Printf, Println, or Fprintf.
+*/
+func NewFormatter(v interface{}) fmt.Formatter {
+ return newFormatter(&Config, v)
+}
diff --git a/vendor/github.com/davecgh/go-spew/spew/format_test.go b/vendor/github.com/davecgh/go-spew/spew/format_test.go
new file mode 100644
index 00000000000..f9b93abe86b
--- /dev/null
+++ b/vendor/github.com/davecgh/go-spew/spew/format_test.go
@@ -0,0 +1,1558 @@
+/*
+ * Copyright (c) 2013-2016 Dave Collins
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+Test Summary:
+NOTE: For each test, a nil pointer, a single pointer and double pointer to the
+base test element are also tested to ensure proper indirection across all types.
+
+- Max int8, int16, int32, int64, int
+- Max uint8, uint16, uint32, uint64, uint
+- Boolean true and false
+- Standard complex64 and complex128
+- Array containing standard ints
+- Array containing type with custom formatter on pointer receiver only
+- Array containing interfaces
+- Slice containing standard float32 values
+- Slice containing type with custom formatter on pointer receiver only
+- Slice containing interfaces
+- Nil slice
+- Standard string
+- Nil interface
+- Sub-interface
+- Map with string keys and int vals
+- Map with custom formatter type on pointer receiver only keys and vals
+- Map with interface keys and values
+- Map with nil interface value
+- Struct with primitives
+- Struct that contains another struct
+- Struct that contains custom type with Stringer pointer interface via both
+ exported and unexported fields
+- Struct that contains embedded struct and field to same struct
+- Uintptr to 0 (null pointer)
+- Uintptr address of real variable
+- Unsafe.Pointer to 0 (null pointer)
+- Unsafe.Pointer to address of real variable
+- Nil channel
+- Standard int channel
+- Function with no params and no returns
+- Function with param and no returns
+- Function with multiple params and multiple returns
+- Struct that is circular through self referencing
+- Structs that are circular through cross referencing
+- Structs that are indirectly circular
+- Type that panics in its Stringer interface
+- Type that has a custom Error interface
+- %x passthrough with uint
+- %#x passthrough with uint
+- %f passthrough with precision
+- %f passthrough with width and precision
+- %d passthrough with width
+- %q passthrough with string
+*/
+
+package spew_test
+
+import (
+ "bytes"
+ "fmt"
+ "testing"
+ "unsafe"
+
+ "github.com/davecgh/go-spew/spew"
+)
+
+// formatterTest is used to describe a test to be performed against NewFormatter.
+type formatterTest struct {
+ format string
+ in interface{}
+ wants []string
+}
+
+// formatterTests houses all of the tests to be performed against NewFormatter.
+var formatterTests = make([]formatterTest, 0)
+
+// addFormatterTest is a helper method to append the passed input and desired
+// result to formatterTests.
+func addFormatterTest(format string, in interface{}, wants ...string) {
+ test := formatterTest{format, in, wants}
+ formatterTests = append(formatterTests, test)
+}
+
+func addIntFormatterTests() {
+ // Max int8.
+ v := int8(127)
+ nv := (*int8)(nil)
+ pv := &v
+ vAddr := fmt.Sprintf("%p", pv)
+ pvAddr := fmt.Sprintf("%p", &pv)
+ vt := "int8"
+ vs := "127"
+ addFormatterTest("%v", v, vs)
+ addFormatterTest("%v", pv, "<*>"+vs)
+ addFormatterTest("%v", &pv, "<**>"+vs)
+ addFormatterTest("%v", nv, "")
+ addFormatterTest("%+v", v, vs)
+ addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+ addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+ addFormatterTest("%+v", nv, "")
+ addFormatterTest("%#v", v, "("+vt+")"+vs)
+ addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
+ addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
+ addFormatterTest("%#v", nv, "(*"+vt+")"+"")
+ addFormatterTest("%#+v", v, "("+vt+")"+vs)
+ addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
+ addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
+ addFormatterTest("%#+v", nv, "(*"+vt+")"+"")
+
+ // Max int16.
+ v2 := int16(32767)
+ nv2 := (*int16)(nil)
+ pv2 := &v2
+ v2Addr := fmt.Sprintf("%p", pv2)
+ pv2Addr := fmt.Sprintf("%p", &pv2)
+ v2t := "int16"
+ v2s := "32767"
+ addFormatterTest("%v", v2, v2s)
+ addFormatterTest("%v", pv2, "<*>"+v2s)
+ addFormatterTest("%v", &pv2, "<**>"+v2s)
+ addFormatterTest("%v", nv2, "")
+ addFormatterTest("%+v", v2, v2s)
+ addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
+ addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
+ addFormatterTest("%+v", nv2, "")
+ addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
+ addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
+ addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
+ addFormatterTest("%#v", nv2, "(*"+v2t+")"+"")
+ addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
+ addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
+ addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
+ addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"")
+
+ // Max int32.
+ v3 := int32(2147483647)
+ nv3 := (*int32)(nil)
+ pv3 := &v3
+ v3Addr := fmt.Sprintf("%p", pv3)
+ pv3Addr := fmt.Sprintf("%p", &pv3)
+ v3t := "int32"
+ v3s := "2147483647"
+ addFormatterTest("%v", v3, v3s)
+ addFormatterTest("%v", pv3, "<*>"+v3s)
+ addFormatterTest("%v", &pv3, "<**>"+v3s)
+ addFormatterTest("%v", nv3, "")
+ addFormatterTest("%+v", v3, v3s)
+ addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s)
+ addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s)
+ addFormatterTest("%+v", nv3, "")
+ addFormatterTest("%#v", v3, "("+v3t+")"+v3s)
+ addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s)
+ addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s)
+ addFormatterTest("%#v", nv3, "(*"+v3t+")"+"")
+ addFormatterTest("%#+v", v3, "("+v3t+")"+v3s)
+ addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s)
+ addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s)
+ addFormatterTest("%#v", nv3, "(*"+v3t+")"+"")
+
+ // Max int64.
+ v4 := int64(9223372036854775807)
+ nv4 := (*int64)(nil)
+ pv4 := &v4
+ v4Addr := fmt.Sprintf("%p", pv4)
+ pv4Addr := fmt.Sprintf("%p", &pv4)
+ v4t := "int64"
+ v4s := "9223372036854775807"
+ addFormatterTest("%v", v4, v4s)
+ addFormatterTest("%v", pv4, "<*>"+v4s)
+ addFormatterTest("%v", &pv4, "<**>"+v4s)
+ addFormatterTest("%v", nv4, "")
+ addFormatterTest("%+v", v4, v4s)
+ addFormatterTest("%+v", pv4, "<*>("+v4Addr+")"+v4s)
+ addFormatterTest("%+v", &pv4, "<**>("+pv4Addr+"->"+v4Addr+")"+v4s)
+ addFormatterTest("%+v", nv4, "")
+ addFormatterTest("%#v", v4, "("+v4t+")"+v4s)
+ addFormatterTest("%#v", pv4, "(*"+v4t+")"+v4s)
+ addFormatterTest("%#v", &pv4, "(**"+v4t+")"+v4s)
+ addFormatterTest("%#v", nv4, "(*"+v4t+")"+"")
+ addFormatterTest("%#+v", v4, "("+v4t+")"+v4s)
+ addFormatterTest("%#+v", pv4, "(*"+v4t+")("+v4Addr+")"+v4s)
+ addFormatterTest("%#+v", &pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")"+v4s)
+ addFormatterTest("%#+v", nv4, "(*"+v4t+")"+"")
+
+ // Max int.
+ v5 := int(2147483647)
+ nv5 := (*int)(nil)
+ pv5 := &v5
+ v5Addr := fmt.Sprintf("%p", pv5)
+ pv5Addr := fmt.Sprintf("%p", &pv5)
+ v5t := "int"
+ v5s := "2147483647"
+ addFormatterTest("%v", v5, v5s)
+ addFormatterTest("%v", pv5, "<*>"+v5s)
+ addFormatterTest("%v", &pv5, "<**>"+v5s)
+ addFormatterTest("%v", nv5, "")
+ addFormatterTest("%+v", v5, v5s)
+ addFormatterTest("%+v", pv5, "<*>("+v5Addr+")"+v5s)
+ addFormatterTest("%+v", &pv5, "<**>("+pv5Addr+"->"+v5Addr+")"+v5s)
+ addFormatterTest("%+v", nv5, "")
+ addFormatterTest("%#v", v5, "("+v5t+")"+v5s)
+ addFormatterTest("%#v", pv5, "(*"+v5t+")"+v5s)
+ addFormatterTest("%#v", &pv5, "(**"+v5t+")"+v5s)
+ addFormatterTest("%#v", nv5, "(*"+v5t+")"+"")
+ addFormatterTest("%#+v", v5, "("+v5t+")"+v5s)
+ addFormatterTest("%#+v", pv5, "(*"+v5t+")("+v5Addr+")"+v5s)
+ addFormatterTest("%#+v", &pv5, "(**"+v5t+")("+pv5Addr+"->"+v5Addr+")"+v5s)
+ addFormatterTest("%#+v", nv5, "(*"+v5t+")"+"")
+}
+
+func addUintFormatterTests() {
+ // Max uint8.
+ v := uint8(255)
+ nv := (*uint8)(nil)
+ pv := &v
+ vAddr := fmt.Sprintf("%p", pv)
+ pvAddr := fmt.Sprintf("%p", &pv)
+ vt := "uint8"
+ vs := "255"
+ addFormatterTest("%v", v, vs)
+ addFormatterTest("%v", pv, "<*>"+vs)
+ addFormatterTest("%v", &pv, "<**>"+vs)
+ addFormatterTest("%v", nv, "")
+ addFormatterTest("%+v", v, vs)
+ addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+ addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+ addFormatterTest("%+v", nv, "")
+ addFormatterTest("%#v", v, "("+vt+")"+vs)
+ addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
+ addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
+ addFormatterTest("%#v", nv, "(*"+vt+")"+"")
+ addFormatterTest("%#+v", v, "("+vt+")"+vs)
+ addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
+ addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
+ addFormatterTest("%#+v", nv, "(*"+vt+")"+"")
+
+ // Max uint16.
+ v2 := uint16(65535)
+ nv2 := (*uint16)(nil)
+ pv2 := &v2
+ v2Addr := fmt.Sprintf("%p", pv2)
+ pv2Addr := fmt.Sprintf("%p", &pv2)
+ v2t := "uint16"
+ v2s := "65535"
+ addFormatterTest("%v", v2, v2s)
+ addFormatterTest("%v", pv2, "<*>"+v2s)
+ addFormatterTest("%v", &pv2, "<**>"+v2s)
+ addFormatterTest("%v", nv2, "")
+ addFormatterTest("%+v", v2, v2s)
+ addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
+ addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
+ addFormatterTest("%+v", nv2, "")
+ addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
+ addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
+ addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
+ addFormatterTest("%#v", nv2, "(*"+v2t+")"+"")
+ addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
+ addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
+ addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
+ addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"")
+
+ // Max uint32.
+ v3 := uint32(4294967295)
+ nv3 := (*uint32)(nil)
+ pv3 := &v3
+ v3Addr := fmt.Sprintf("%p", pv3)
+ pv3Addr := fmt.Sprintf("%p", &pv3)
+ v3t := "uint32"
+ v3s := "4294967295"
+ addFormatterTest("%v", v3, v3s)
+ addFormatterTest("%v", pv3, "<*>"+v3s)
+ addFormatterTest("%v", &pv3, "<**>"+v3s)
+ addFormatterTest("%v", nv3, "")
+ addFormatterTest("%+v", v3, v3s)
+ addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s)
+ addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s)
+ addFormatterTest("%+v", nv3, "")
+ addFormatterTest("%#v", v3, "("+v3t+")"+v3s)
+ addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s)
+ addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s)
+ addFormatterTest("%#v", nv3, "(*"+v3t+")"+"")
+ addFormatterTest("%#+v", v3, "("+v3t+")"+v3s)
+ addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s)
+ addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s)
+ addFormatterTest("%#v", nv3, "(*"+v3t+")"+"")
+
+ // Max uint64.
+ v4 := uint64(18446744073709551615)
+ nv4 := (*uint64)(nil)
+ pv4 := &v4
+ v4Addr := fmt.Sprintf("%p", pv4)
+ pv4Addr := fmt.Sprintf("%p", &pv4)
+ v4t := "uint64"
+ v4s := "18446744073709551615"
+ addFormatterTest("%v", v4, v4s)
+ addFormatterTest("%v", pv4, "<*>"+v4s)
+ addFormatterTest("%v", &pv4, "<**>"+v4s)
+ addFormatterTest("%v", nv4, "")
+ addFormatterTest("%+v", v4, v4s)
+ addFormatterTest("%+v", pv4, "<*>("+v4Addr+")"+v4s)
+ addFormatterTest("%+v", &pv4, "<**>("+pv4Addr+"->"+v4Addr+")"+v4s)
+ addFormatterTest("%+v", nv4, "")
+ addFormatterTest("%#v", v4, "("+v4t+")"+v4s)
+ addFormatterTest("%#v", pv4, "(*"+v4t+")"+v4s)
+ addFormatterTest("%#v", &pv4, "(**"+v4t+")"+v4s)
+ addFormatterTest("%#v", nv4, "(*"+v4t+")"+"")
+ addFormatterTest("%#+v", v4, "("+v4t+")"+v4s)
+ addFormatterTest("%#+v", pv4, "(*"+v4t+")("+v4Addr+")"+v4s)
+ addFormatterTest("%#+v", &pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")"+v4s)
+ addFormatterTest("%#+v", nv4, "(*"+v4t+")"+"")
+
+ // Max uint.
+ v5 := uint(4294967295)
+ nv5 := (*uint)(nil)
+ pv5 := &v5
+ v5Addr := fmt.Sprintf("%p", pv5)
+ pv5Addr := fmt.Sprintf("%p", &pv5)
+ v5t := "uint"
+ v5s := "4294967295"
+ addFormatterTest("%v", v5, v5s)
+ addFormatterTest("%v", pv5, "<*>"+v5s)
+ addFormatterTest("%v", &pv5, "<**>"+v5s)
+ addFormatterTest("%v", nv5, "")
+ addFormatterTest("%+v", v5, v5s)
+ addFormatterTest("%+v", pv5, "<*>("+v5Addr+")"+v5s)
+ addFormatterTest("%+v", &pv5, "<**>("+pv5Addr+"->"+v5Addr+")"+v5s)
+ addFormatterTest("%+v", nv5, "")
+ addFormatterTest("%#v", v5, "("+v5t+")"+v5s)
+ addFormatterTest("%#v", pv5, "(*"+v5t+")"+v5s)
+ addFormatterTest("%#v", &pv5, "(**"+v5t+")"+v5s)
+ addFormatterTest("%#v", nv5, "(*"+v5t+")"+"")
+ addFormatterTest("%#+v", v5, "("+v5t+")"+v5s)
+ addFormatterTest("%#+v", pv5, "(*"+v5t+")("+v5Addr+")"+v5s)
+ addFormatterTest("%#+v", &pv5, "(**"+v5t+")("+pv5Addr+"->"+v5Addr+")"+v5s)
+ addFormatterTest("%#v", nv5, "(*"+v5t+")"+"")
+}
+
+func addBoolFormatterTests() {
+ // Boolean true.
+ v := bool(true)
+ nv := (*bool)(nil)
+ pv := &v
+ vAddr := fmt.Sprintf("%p", pv)
+ pvAddr := fmt.Sprintf("%p", &pv)
+ vt := "bool"
+ vs := "true"
+ addFormatterTest("%v", v, vs)
+ addFormatterTest("%v", pv, "<*>"+vs)
+ addFormatterTest("%v", &pv, "<**>"+vs)
+ addFormatterTest("%v", nv, "")
+ addFormatterTest("%+v", v, vs)
+ addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+ addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+ addFormatterTest("%+v", nv, "")
+ addFormatterTest("%#v", v, "("+vt+")"+vs)
+ addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
+ addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
+ addFormatterTest("%#v", nv, "(*"+vt+")"+"")
+ addFormatterTest("%#+v", v, "("+vt+")"+vs)
+ addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
+ addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
+ addFormatterTest("%#+v", nv, "(*"+vt+")"+"")
+
+ // Boolean false.
+ v2 := bool(false)
+ pv2 := &v2
+ v2Addr := fmt.Sprintf("%p", pv2)
+ pv2Addr := fmt.Sprintf("%p", &pv2)
+ v2t := "bool"
+ v2s := "false"
+ addFormatterTest("%v", v2, v2s)
+ addFormatterTest("%v", pv2, "<*>"+v2s)
+ addFormatterTest("%v", &pv2, "<**>"+v2s)
+ addFormatterTest("%+v", v2, v2s)
+ addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
+ addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
+ addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
+ addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
+ addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
+ addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
+ addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
+ addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
+}
+
+func addFloatFormatterTests() {
+ // Standard float32.
+ v := float32(3.1415)
+ nv := (*float32)(nil)
+ pv := &v
+ vAddr := fmt.Sprintf("%p", pv)
+ pvAddr := fmt.Sprintf("%p", &pv)
+ vt := "float32"
+ vs := "3.1415"
+ addFormatterTest("%v", v, vs)
+ addFormatterTest("%v", pv, "<*>"+vs)
+ addFormatterTest("%v", &pv, "<**>"+vs)
+ addFormatterTest("%v", nv, "")
+ addFormatterTest("%+v", v, vs)
+ addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+ addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+ addFormatterTest("%+v", nv, "")
+ addFormatterTest("%#v", v, "("+vt+")"+vs)
+ addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
+ addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
+ addFormatterTest("%#v", nv, "(*"+vt+")"+"")
+ addFormatterTest("%#+v", v, "("+vt+")"+vs)
+ addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
+ addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
+ addFormatterTest("%#+v", nv, "(*"+vt+")"+"")
+
+ // Standard float64.
+ v2 := float64(3.1415926)
+ nv2 := (*float64)(nil)
+ pv2 := &v2
+ v2Addr := fmt.Sprintf("%p", pv2)
+ pv2Addr := fmt.Sprintf("%p", &pv2)
+ v2t := "float64"
+ v2s := "3.1415926"
+ addFormatterTest("%v", v2, v2s)
+ addFormatterTest("%v", pv2, "<*>"+v2s)
+ addFormatterTest("%v", &pv2, "<**>"+v2s)
+ addFormatterTest("%+v", nv2, "")
+ addFormatterTest("%+v", v2, v2s)
+ addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
+ addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
+ addFormatterTest("%+v", nv2, "")
+ addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
+ addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
+ addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
+ addFormatterTest("%#v", nv2, "(*"+v2t+")"+"")
+ addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
+ addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
+ addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
+ addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"")
+}
+
+func addComplexFormatterTests() {
+ // Standard complex64.
+ v := complex(float32(6), -2)
+ nv := (*complex64)(nil)
+ pv := &v
+ vAddr := fmt.Sprintf("%p", pv)
+ pvAddr := fmt.Sprintf("%p", &pv)
+ vt := "complex64"
+ vs := "(6-2i)"
+ addFormatterTest("%v", v, vs)
+ addFormatterTest("%v", pv, "<*>"+vs)
+ addFormatterTest("%v", &pv, "<**>"+vs)
+ addFormatterTest("%+v", nv, "")
+ addFormatterTest("%+v", v, vs)
+ addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+ addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+ addFormatterTest("%+v", nv, "")
+ addFormatterTest("%#v", v, "("+vt+")"+vs)
+ addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
+ addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
+ addFormatterTest("%#v", nv, "(*"+vt+")"+"")
+ addFormatterTest("%#+v", v, "("+vt+")"+vs)
+ addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
+ addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
+ addFormatterTest("%#+v", nv, "(*"+vt+")"+"")
+
+ // Standard complex128.
+ v2 := complex(float64(-6), 2)
+ nv2 := (*complex128)(nil)
+ pv2 := &v2
+ v2Addr := fmt.Sprintf("%p", pv2)
+ pv2Addr := fmt.Sprintf("%p", &pv2)
+ v2t := "complex128"
+ v2s := "(-6+2i)"
+ addFormatterTest("%v", v2, v2s)
+ addFormatterTest("%v", pv2, "<*>"+v2s)
+ addFormatterTest("%v", &pv2, "<**>"+v2s)
+ addFormatterTest("%+v", nv2, "")
+ addFormatterTest("%+v", v2, v2s)
+ addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
+ addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
+ addFormatterTest("%+v", nv2, "")
+ addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
+ addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
+ addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
+ addFormatterTest("%#v", nv2, "(*"+v2t+")"+"")
+ addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
+ addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
+ addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
+ addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"")
+}
+
+func addArrayFormatterTests() {
+ // Array containing standard ints.
+ v := [3]int{1, 2, 3}
+ nv := (*[3]int)(nil)
+ pv := &v
+ vAddr := fmt.Sprintf("%p", pv)
+ pvAddr := fmt.Sprintf("%p", &pv)
+ vt := "[3]int"
+ vs := "[1 2 3]"
+ addFormatterTest("%v", v, vs)
+ addFormatterTest("%v", pv, "<*>"+vs)
+ addFormatterTest("%v", &pv, "<**>"+vs)
+ addFormatterTest("%+v", nv, "")
+ addFormatterTest("%+v", v, vs)
+ addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+ addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+ addFormatterTest("%+v", nv, "")
+ addFormatterTest("%#v", v, "("+vt+")"+vs)
+ addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
+ addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
+ addFormatterTest("%#v", nv, "(*"+vt+")"+"")
+ addFormatterTest("%#+v", v, "("+vt+")"+vs)
+ addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
+ addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
+ addFormatterTest("%#+v", nv, "(*"+vt+")"+"")
+
+ // Array containing type with custom formatter on pointer receiver only.
+ v2 := [3]pstringer{"1", "2", "3"}
+ nv2 := (*[3]pstringer)(nil)
+ pv2 := &v2
+ v2Addr := fmt.Sprintf("%p", pv2)
+ pv2Addr := fmt.Sprintf("%p", &pv2)
+ v2t := "[3]spew_test.pstringer"
+ v2sp := "[stringer 1 stringer 2 stringer 3]"
+ v2s := v2sp
+ if spew.UnsafeDisabled {
+ v2s = "[1 2 3]"
+ }
+ addFormatterTest("%v", v2, v2s)
+ addFormatterTest("%v", pv2, "<*>"+v2sp)
+ addFormatterTest("%v", &pv2, "<**>"+v2sp)
+ addFormatterTest("%+v", nv2, "")
+ addFormatterTest("%+v", v2, v2s)
+ addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2sp)
+ addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2sp)
+ addFormatterTest("%+v", nv2, "")
+ addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
+ addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2sp)
+ addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2sp)
+ addFormatterTest("%#v", nv2, "(*"+v2t+")"+"")
+ addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
+ addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2sp)
+ addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2sp)
+ addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"")
+
+ // Array containing interfaces.
+ v3 := [3]interface{}{"one", int(2), uint(3)}
+ nv3 := (*[3]interface{})(nil)
+ pv3 := &v3
+ v3Addr := fmt.Sprintf("%p", pv3)
+ pv3Addr := fmt.Sprintf("%p", &pv3)
+ v3t := "[3]interface {}"
+ v3t2 := "string"
+ v3t3 := "int"
+ v3t4 := "uint"
+ v3s := "[one 2 3]"
+ v3s2 := "[(" + v3t2 + ")one (" + v3t3 + ")2 (" + v3t4 + ")3]"
+ addFormatterTest("%v", v3, v3s)
+ addFormatterTest("%v", pv3, "<*>"+v3s)
+ addFormatterTest("%v", &pv3, "<**>"+v3s)
+ addFormatterTest("%+v", nv3, "")
+ addFormatterTest("%+v", v3, v3s)
+ addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s)
+ addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s)
+ addFormatterTest("%+v", nv3, "")
+ addFormatterTest("%#v", v3, "("+v3t+")"+v3s2)
+ addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s2)
+ addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s2)
+ addFormatterTest("%#v", nv3, "(*"+v3t+")"+"")
+ addFormatterTest("%#+v", v3, "("+v3t+")"+v3s2)
+ addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s2)
+ addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s2)
+ addFormatterTest("%#+v", nv3, "(*"+v3t+")"+"")
+}
+
+func addSliceFormatterTests() {
+ // Slice containing standard float32 values.
+ v := []float32{3.14, 6.28, 12.56}
+ nv := (*[]float32)(nil)
+ pv := &v
+ vAddr := fmt.Sprintf("%p", pv)
+ pvAddr := fmt.Sprintf("%p", &pv)
+ vt := "[]float32"
+ vs := "[3.14 6.28 12.56]"
+ addFormatterTest("%v", v, vs)
+ addFormatterTest("%v", pv, "<*>"+vs)
+ addFormatterTest("%v", &pv, "<**>"+vs)
+ addFormatterTest("%+v", nv, "")
+ addFormatterTest("%+v", v, vs)
+ addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+ addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+ addFormatterTest("%+v", nv, "")
+ addFormatterTest("%#v", v, "("+vt+")"+vs)
+ addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
+ addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
+ addFormatterTest("%#v", nv, "(*"+vt+")"+"")
+ addFormatterTest("%#+v", v, "("+vt+")"+vs)
+ addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
+ addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
+ addFormatterTest("%#+v", nv, "(*"+vt+")"+"")
+
+ // Slice containing type with custom formatter on pointer receiver only.
+ v2 := []pstringer{"1", "2", "3"}
+ nv2 := (*[]pstringer)(nil)
+ pv2 := &v2
+ v2Addr := fmt.Sprintf("%p", pv2)
+ pv2Addr := fmt.Sprintf("%p", &pv2)
+ v2t := "[]spew_test.pstringer"
+ v2s := "[stringer 1 stringer 2 stringer 3]"
+ addFormatterTest("%v", v2, v2s)
+ addFormatterTest("%v", pv2, "<*>"+v2s)
+ addFormatterTest("%v", &pv2, "<**>"+v2s)
+ addFormatterTest("%+v", nv2, "")
+ addFormatterTest("%+v", v2, v2s)
+ addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
+ addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
+ addFormatterTest("%+v", nv2, "")
+ addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
+ addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
+ addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
+ addFormatterTest("%#v", nv2, "(*"+v2t+")"+"")
+ addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
+ addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
+ addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
+ addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"")
+
+ // Slice containing interfaces.
+ v3 := []interface{}{"one", int(2), uint(3), nil}
+ nv3 := (*[]interface{})(nil)
+ pv3 := &v3
+ v3Addr := fmt.Sprintf("%p", pv3)
+ pv3Addr := fmt.Sprintf("%p", &pv3)
+ v3t := "[]interface {}"
+ v3t2 := "string"
+ v3t3 := "int"
+ v3t4 := "uint"
+ v3t5 := "interface {}"
+ v3s := "[one 2 3 ]"
+ v3s2 := "[(" + v3t2 + ")one (" + v3t3 + ")2 (" + v3t4 + ")3 (" + v3t5 +
+ ")]"
+ addFormatterTest("%v", v3, v3s)
+ addFormatterTest("%v", pv3, "<*>"+v3s)
+ addFormatterTest("%v", &pv3, "<**>"+v3s)
+ addFormatterTest("%+v", nv3, "")
+ addFormatterTest("%+v", v3, v3s)
+ addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s)
+ addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s)
+ addFormatterTest("%+v", nv3, "")
+ addFormatterTest("%#v", v3, "("+v3t+")"+v3s2)
+ addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s2)
+ addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s2)
+ addFormatterTest("%#v", nv3, "(*"+v3t+")"+"")
+ addFormatterTest("%#+v", v3, "("+v3t+")"+v3s2)
+ addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s2)
+ addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s2)
+ addFormatterTest("%#+v", nv3, "(*"+v3t+")"+"")
+
+ // Nil slice.
+ var v4 []int
+ nv4 := (*[]int)(nil)
+ pv4 := &v4
+ v4Addr := fmt.Sprintf("%p", pv4)
+ pv4Addr := fmt.Sprintf("%p", &pv4)
+ v4t := "[]int"
+ v4s := ""
+ addFormatterTest("%v", v4, v4s)
+ addFormatterTest("%v", pv4, "<*>"+v4s)
+ addFormatterTest("%v", &pv4, "<**>"+v4s)
+ addFormatterTest("%+v", nv4, "")
+ addFormatterTest("%+v", v4, v4s)
+ addFormatterTest("%+v", pv4, "<*>("+v4Addr+")"+v4s)
+ addFormatterTest("%+v", &pv4, "<**>("+pv4Addr+"->"+v4Addr+")"+v4s)
+ addFormatterTest("%+v", nv4, "")
+ addFormatterTest("%#v", v4, "("+v4t+")"+v4s)
+ addFormatterTest("%#v", pv4, "(*"+v4t+")"+v4s)
+ addFormatterTest("%#v", &pv4, "(**"+v4t+")"+v4s)
+ addFormatterTest("%#v", nv4, "(*"+v4t+")"+"")
+ addFormatterTest("%#+v", v4, "("+v4t+")"+v4s)
+ addFormatterTest("%#+v", pv4, "(*"+v4t+")("+v4Addr+")"+v4s)
+ addFormatterTest("%#+v", &pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")"+v4s)
+ addFormatterTest("%#+v", nv4, "(*"+v4t+")"+"")
+}
+
+func addStringFormatterTests() {
+ // Standard string.
+ v := "test"
+ nv := (*string)(nil)
+ pv := &v
+ vAddr := fmt.Sprintf("%p", pv)
+ pvAddr := fmt.Sprintf("%p", &pv)
+ vt := "string"
+ vs := "test"
+ addFormatterTest("%v", v, vs)
+ addFormatterTest("%v", pv, "<*>"+vs)
+ addFormatterTest("%v", &pv, "<**>"+vs)
+ addFormatterTest("%+v", nv, "")
+ addFormatterTest("%+v", v, vs)
+ addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+ addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+ addFormatterTest("%+v", nv, "")
+ addFormatterTest("%#v", v, "("+vt+")"+vs)
+ addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
+ addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
+ addFormatterTest("%#v", nv, "(*"+vt+")"+"")
+ addFormatterTest("%#+v", v, "("+vt+")"+vs)
+ addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
+ addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
+ addFormatterTest("%#+v", nv, "(*"+vt+")"+"")
+}
+
+func addInterfaceFormatterTests() {
+ // Nil interface.
+ var v interface{}
+ nv := (*interface{})(nil)
+ pv := &v
+ vAddr := fmt.Sprintf("%p", pv)
+ pvAddr := fmt.Sprintf("%p", &pv)
+ vt := "interface {}"
+ vs := ""
+ addFormatterTest("%v", v, vs)
+ addFormatterTest("%v", pv, "<*>"+vs)
+ addFormatterTest("%v", &pv, "<**>"+vs)
+ addFormatterTest("%+v", nv, "")
+ addFormatterTest("%+v", v, vs)
+ addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
+ addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
+ addFormatterTest("%+v", nv, "")
+ addFormatterTest("%#v", v, "("+vt+")"+vs)
+ addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
+ addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
+ addFormatterTest("%#v", nv, "(*"+vt+")"+"")
+ addFormatterTest("%#+v", v, "("+vt+")"+vs)
+ addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
+ addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
+ addFormatterTest("%#+v", nv, "(*"+vt+")"+"")
+
+ // Sub-interface.
+ v2 := interface{}(uint16(65535))
+ pv2 := &v2
+ v2Addr := fmt.Sprintf("%p", pv2)
+ pv2Addr := fmt.Sprintf("%p", &pv2)
+ v2t := "uint16"
+ v2s := "65535"
+ addFormatterTest("%v", v2, v2s)
+ addFormatterTest("%v", pv2, "<*>"+v2s)
+ addFormatterTest("%v", &pv2, "<**>"+v2s)
+ addFormatterTest("%+v", v2, v2s)
+ addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
+ addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
+ addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
+ addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
+ addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
+ addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
+ addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
+ addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
+}
+
+func addMapFormatterTests() {
+ // Map with string keys and int vals.
+ v := map[string]int{"one": 1, "two": 2}
+ nilMap := map[string]int(nil)
+ nv := (*map[string]int)(nil)
+ pv := &v
+ vAddr := fmt.Sprintf("%p", pv)
+ pvAddr := fmt.Sprintf("%p", &pv)
+ vt := "map[string]int"
+ vs := "map[one:1 two:2]"
+ vs2 := "map[two:2 one:1]"
+ addFormatterTest("%v", v, vs, vs2)
+ addFormatterTest("%v", pv, "<*>"+vs, "<*>"+vs2)
+ addFormatterTest("%v", &pv, "<**>"+vs, "<**>"+vs2)
+ addFormatterTest("%+v", nilMap, "")
+ addFormatterTest("%+v", nv, "")
+ addFormatterTest("%+v", v, vs, vs2)
+ addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs, "<*>("+vAddr+")"+vs2)
+ addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs,
+ "<**>("+pvAddr+"->"+vAddr+")"+vs2)
+ addFormatterTest("%+v", nilMap, "")
+ addFormatterTest("%+v", nv, "")
+ addFormatterTest("%#v", v, "("+vt+")"+vs, "("+vt+")"+vs2)
+ addFormatterTest("%#v", pv, "(*"+vt+")"+vs, "(*"+vt+")"+vs2)
+ addFormatterTest("%#v", &pv, "(**"+vt+")"+vs, "(**"+vt+")"+vs2)
+ addFormatterTest("%#v", nilMap, "("+vt+")"+"")
+ addFormatterTest("%#v", nv, "(*"+vt+")"+"")
+ addFormatterTest("%#+v", v, "("+vt+")"+vs, "("+vt+")"+vs2)
+ addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs,
+ "(*"+vt+")("+vAddr+")"+vs2)
+ addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs,
+ "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs2)
+ addFormatterTest("%#+v", nilMap, "("+vt+")"+"")
+ addFormatterTest("%#+v", nv, "(*"+vt+")"+"")
+
+ // Map with custom formatter type on pointer receiver only keys and vals.
+ v2 := map[pstringer]pstringer{"one": "1"}
+ nv2 := (*map[pstringer]pstringer)(nil)
+ pv2 := &v2
+ v2Addr := fmt.Sprintf("%p", pv2)
+ pv2Addr := fmt.Sprintf("%p", &pv2)
+ v2t := "map[spew_test.pstringer]spew_test.pstringer"
+ v2s := "map[stringer one:stringer 1]"
+ if spew.UnsafeDisabled {
+ v2s = "map[one:1]"
+ }
+ addFormatterTest("%v", v2, v2s)
+ addFormatterTest("%v", pv2, "<*>"+v2s)
+ addFormatterTest("%v", &pv2, "<**>"+v2s)
+ addFormatterTest("%+v", nv2, "")
+ addFormatterTest("%+v", v2, v2s)
+ addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
+ addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
+ addFormatterTest("%+v", nv2, "")
+ addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
+ addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
+ addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
+ addFormatterTest("%#v", nv2, "(*"+v2t+")"+"")
+ addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
+ addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
+ addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
+ addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"")
+
+ // Map with interface keys and values.
+ v3 := map[interface{}]interface{}{"one": 1}
+ nv3 := (*map[interface{}]interface{})(nil)
+ pv3 := &v3
+ v3Addr := fmt.Sprintf("%p", pv3)
+ pv3Addr := fmt.Sprintf("%p", &pv3)
+ v3t := "map[interface {}]interface {}"
+ v3t1 := "string"
+ v3t2 := "int"
+ v3s := "map[one:1]"
+ v3s2 := "map[(" + v3t1 + ")one:(" + v3t2 + ")1]"
+ addFormatterTest("%v", v3, v3s)
+ addFormatterTest("%v", pv3, "<*>"+v3s)
+ addFormatterTest("%v", &pv3, "<**>"+v3s)
+ addFormatterTest("%+v", nv3, "")
+ addFormatterTest("%+v", v3, v3s)
+ addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s)
+ addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s)
+ addFormatterTest("%+v", nv3, "")
+ addFormatterTest("%#v", v3, "("+v3t+")"+v3s2)
+ addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s2)
+ addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s2)
+ addFormatterTest("%#v", nv3, "(*"+v3t+")"+"")
+ addFormatterTest("%#+v", v3, "("+v3t+")"+v3s2)
+ addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s2)
+ addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s2)
+ addFormatterTest("%#+v", nv3, "(*"+v3t+")"+"")
+
+ // Map with nil interface value
+ v4 := map[string]interface{}{"nil": nil}
+ nv4 := (*map[string]interface{})(nil)
+ pv4 := &v4
+ v4Addr := fmt.Sprintf("%p", pv4)
+ pv4Addr := fmt.Sprintf("%p", &pv4)
+ v4t := "map[string]interface {}"
+ v4t1 := "interface {}"
+ v4s := "map[nil:]"
+ v4s2 := "map[nil:(" + v4t1 + ")