diff --git a/glide.lock b/glide.lock index 53f2edee9c41..3295cc6b6b3b 100644 --- a/glide.lock +++ b/glide.lock @@ -1,5 +1,5 @@ -hash: 54c022d2a987c13cb158b9cdfd458877ddbdadeee4d26f066118f9cb2da08db4 -updated: 2019-07-31T08:00:42.67906301-04:00 +hash: 7622b75aea01706933f2e1470797c5cd1ceb7d1c97869ce895928386abb09a93 +updated: 2019-08-09T14:43:52.240397386-05:00 imports: - name: bitbucket.org/ww/goautoneg version: 2ae31c8b6b30d2f4c8100c20d527b571e9c433bb @@ -16,7 +16,7 @@ imports: - name: github.com/apcera/gssapi version: 5fb4217df13b8e6878046fe1e5c10e560e1b86dc - name: github.com/apparentlymart/go-cidr - version: b1115bf8e14a60131a196f908223e4506b0ddc35 + version: 1755c023625ec3a84979b90841a1ab067ed6c071 subpackages: - cidr - name: github.com/armon/circbuf @@ -419,7 +419,7 @@ imports: - ipamutils - ipvs - name: github.com/docker/libtrust - version: 9cbd2a1374f46905c68a4eb3694a130610adc62a + version: aabc10ec26b754e797f9028f4589c5b7bd90dc20 - name: github.com/docker/spdystream version: 449fdfce4d962303d702fec724ef0ad181c92528 subpackages: @@ -576,7 +576,8 @@ imports: - name: github.com/google/btree version: 20236160a414454a9c64b6c8829381c6f4bddcaa - name: github.com/google/cadvisor - version: 8949c822ea91fa6b4996614a5ad6ade840be24ee + version: 5fa6b13d2628c5c85c8508082cc1bdfa3373e8a9 + repo: https://github.com/openshift/google-cadvisor.git subpackages: - accelerators - cache/memory @@ -675,7 +676,7 @@ imports: - openstack/utils - pagination - name: github.com/gorilla/mux - version: 08e7f807d38d6a870193019bb439056118661505 + version: e67b3c02c7195c052acff13261f0c9fd1ba53011 - name: github.com/gorilla/websocket version: 4201258b820c74ac8e6922fc9e6b52f71fe46f8d - name: github.com/gregjones/httpcache @@ -735,16 +736,24 @@ imports: version: 2de2192f9e35ce981c152a873ed943b93b79ced4 - name: github.com/kr/fs version: 2788f0dbd16903de03cb8186e5c7d97b69ad387b +- name: github.com/lestrrat-go/jspointer + version: 82fadba7561c3a8d78133c2b957263c0963bb79d +- name: github.com/lestrrat-go/jsref + version: 1b590508f37d3af76c77c8328e16978d2889b486 + subpackages: + - provider +- name: github.com/lestrrat-go/pdebug + version: 39f9a71bcabe9432cbdfe4d3d33f41988acd2ce6 +- name: github.com/lestrrat-go/structinfo + version: acd51874663bf3297433cb1f1015075c3cbe6130 - name: github.com/lestrrat/go-jspointer - version: f4881e611bdbe9fb413a7780721ef8400a1f2341 + version: 82fadba7561c3a8d78133c2b957263c0963bb79d repo: https://github.com/lestrrat/go-jspointer.git - name: github.com/lestrrat/go-jsref version: 50df7b2d07d799426a9ac43fa24bdb4785f72a54 repo: https://github.com/lestrrat/go-jsref.git - subpackages: - - provider - name: github.com/lestrrat/go-jsschema - version: a6a42341b50d8d7e2a733db922eefaa756321021 + version: 5c81c58ffcc359c4390d440b45f5462edb0107cb - name: github.com/lestrrat/go-pdebug version: 569c97477ae8837e053e5a50bc739e15172b8ebe repo: https://github.com/lestrrat/go-pdebug.git @@ -774,7 +783,7 @@ imports: - jlexer - jwriter - name: github.com/MakeNowJust/heredoc - version: bb23615498cded5e105af4ce27de75b089cbe851 + version: e9091a26100e9cfb2b6a8f470085bfa541931a91 - name: github.com/marstr/guid version: 8bdf7d1a087ccc975cf37dd6507da50698fd19ca - name: github.com/mattn/go-shellwords @@ -933,7 +942,7 @@ imports: - go-selinux - go-selinux/label - name: github.com/openshift/api - version: 0922aa5a655be314e20a3e0e94f4f2b105100154 + version: 8f800d2391d0b451818fd5bfc348b16d7cc1e588 subpackages: - annotations - apps @@ -983,11 +992,27 @@ imports: - webconsole - webconsole/v1 - name: github.com/openshift/apiserver-library-go - version: 9ba756241be5498149388d39031e6161e8ebf90c - subpackages: + version: 4d81e8c49306fab396f2ad574beb87e10203d578 + subpackages: + - pkg/admission/imagepolicy + - pkg/admission/imagepolicy/apis/imagepolicy/v1 + - pkg/admission/imagepolicy/apis/imagepolicy/validation + - pkg/admission/imagepolicy/imagereferencemutators + - pkg/admission/imagepolicy/rules + - pkg/admission/quota/clusterresourcequota - pkg/authorization/scope + - pkg/configflags + - pkg/securitycontextconstraints/capabilities + - pkg/securitycontextconstraints/group + - pkg/securitycontextconstraints/sccadmission + - pkg/securitycontextconstraints/sccmatching + - pkg/securitycontextconstraints/seccomp + - pkg/securitycontextconstraints/selinux + - pkg/securitycontextconstraints/user + - pkg/securitycontextconstraints/util + - pkg/securitycontextconstraints/util/sort - name: github.com/openshift/client-go - version: a85ea6a6b3a5d2dbe41582ee35695dd4683e1f02 + version: e9678e3b850da36470c5554609c6cd110aace47e subpackages: - apps/clientset/versioned - apps/clientset/versioned/scheme @@ -1088,7 +1113,7 @@ imports: - user/informers/externalversions/user/v1 - user/listers/user/v1 - name: github.com/openshift/library-go - version: 9fac0f4cee906d25073d044cb600b00e6bfca8b1 + version: 211d32684d6cd8b9a50db92e213d4b6ea827bb63 subpackages: - pkg/apiserver/admission/admissionrestconfig - pkg/apiserver/admission/admissiontimeout @@ -1138,7 +1163,7 @@ imports: - pkg/template/templateprocessingclient - pkg/unidling/unidlingclient - name: github.com/openshift/oc - version: 96787327f0e8f1780104bd935aa4229a5be4f959 + version: 8fdb79e549651c0f3c91d54349715309b5d149d3 subpackages: - pkg/cli - pkg/cli/admin @@ -1399,7 +1424,7 @@ imports: - name: github.com/spf13/cast version: e31f36ffc91a2ba9ddb72a4b6a607ff9b3d3cb63 - name: github.com/spf13/cobra - version: c439c4fa093711d42e1b01acb1235b52004753c1 + version: b80588d523ec50c7fee20218426cf2ff70920f06 - name: github.com/spf13/jwalterweatherman version: 33c24e77fb80341fe7130ee7c594256ff08ccc46 - name: github.com/spf13/pflag @@ -1757,9 +1782,10 @@ imports: - storage/v1alpha1 - storage/v1beta1 - name: k8s.io/apiextensions-apiserver - version: ee330a2a5c6d54e58af0defc868f1258a5c47422 + version: ef1fb026cb0ebf50e765bba38c951dc095f7fddf repo: https://github.com/openshift/kubernetes-apiextensions-apiserver.git subpackages: + - pkg/apihelpers - pkg/apis/apiextensions - pkg/apis/apiextensions/install - pkg/apis/apiextensions/v1beta1 @@ -1785,6 +1811,7 @@ imports: - pkg/client/listers/apiextensions/v1beta1 - pkg/cmd/server/options - pkg/cmd/server/testing + - pkg/controller/apiapproval - pkg/controller/establish - pkg/controller/finalizer - pkg/controller/openapi @@ -2322,12 +2349,12 @@ imports: subpackages: - config/v1alpha1 - name: k8s.io/kubelet - version: f6da02f583256d1a15cc44a101c80bfa2080a46f + version: 60e43eba885b922ab5b385950859964a534af90a repo: https://github.com/openshift/kubernetes-kubelet.git subpackages: - config/v1beta1 - name: k8s.io/kubernetes - version: 9166b5c864d9bd8fe3136c5a28d3c87e645749d9 + version: faf0538d61897caa1a1b8aea789d8def9d585e74 repo: https://github.com/openshift/kubernetes.git subpackages: - cmd/cloud-controller-manager/app @@ -2380,11 +2407,6 @@ imports: - openshift-kube-apiserver/admission/customresourcevalidation/scheduler - openshift-kube-apiserver/admission/customresourcevalidation/securitycontextconstraints - openshift-kube-apiserver/admission/customresourcevalidation/securitycontextconstraints/validation - - openshift-kube-apiserver/admission/imagepolicy - - openshift-kube-apiserver/admission/imagepolicy/apis/imagepolicy/v1 - - openshift-kube-apiserver/admission/imagepolicy/apis/imagepolicy/validation - - openshift-kube-apiserver/admission/imagepolicy/imagereferencemutators - - openshift-kube-apiserver/admission/imagepolicy/rules - openshift-kube-apiserver/admission/namespaceconditions - openshift-kube-apiserver/admission/network/apis/externalipranger - openshift-kube-apiserver/admission/network/apis/externalipranger/v1 @@ -2392,7 +2414,6 @@ imports: - openshift-kube-apiserver/admission/network/apis/restrictedendpoints/v1 - openshift-kube-apiserver/admission/network/externalipranger - openshift-kube-apiserver/admission/network/restrictedendpoints - - openshift-kube-apiserver/admission/quota/clusterresourcequota - openshift-kube-apiserver/admission/route - openshift-kube-apiserver/admission/route/apis/ingressadmission - openshift-kube-apiserver/admission/route/apis/ingressadmission/v1 @@ -2401,22 +2422,11 @@ imports: - openshift-kube-apiserver/admission/scheduler/nodeenv - openshift-kube-apiserver/admission/scheduler/nodeenv/labelselector - openshift-kube-apiserver/admission/scheduler/podnodeconstraints - - openshift-kube-apiserver/admission/security/sccadmission - - openshift-kube-apiserver/admission/security/securitycontextconstraints/capabilities - - openshift-kube-apiserver/admission/security/securitycontextconstraints/group - - openshift-kube-apiserver/admission/security/securitycontextconstraints/sccmatching - - openshift-kube-apiserver/admission/security/securitycontextconstraints/seccomp - - openshift-kube-apiserver/admission/security/securitycontextconstraints/selinux - - openshift-kube-apiserver/admission/security/securitycontextconstraints/user - - openshift-kube-apiserver/admission/security/securitycontextconstraints/util - - openshift-kube-apiserver/admission/security/securitycontextconstraints/util/sort - openshift-kube-apiserver/authentication/oauth - openshift-kube-apiserver/authentication/oauth/rankedset - openshift-kube-apiserver/authorization/browsersafe - - openshift-kube-apiserver/authorization/scope - openshift-kube-apiserver/authorization/scopeauthorizer - openshift-kube-apiserver/configdefault - - openshift-kube-apiserver/configflags - openshift-kube-apiserver/enablement - openshift-kube-apiserver/kubeadmission - openshift-kube-apiserver/openshiftkubeapiserver diff --git a/glide.yaml b/glide.yaml index bd07605c4344..2392e8fbc4be 100644 --- a/glide.yaml +++ b/glide.yaml @@ -107,6 +107,11 @@ import: - package: github.com/opencontainers/runc repo: https://github.com/openshift/opencontainers-runc.git version: 7c7775178c25e952571573f44a8df281824cf8e1 +# pod - sjenning +# openshift-4.1-cadvisor-v0.32.0 +- package: github.com/google/cadvisor + repo: https://github.com/openshift/google-cadvisor.git + version: 5fa6b13d2628c5c85c8508082cc1bdfa3373e8a9 # these need to match the kubelet - package: github.com/docker/distribution repo: https://github.com/openshift/docker-distribution.git diff --git a/vendor/github.com/MakeNowJust/heredoc/heredoc.go b/vendor/github.com/MakeNowJust/heredoc/heredoc.go index fea12e622f12..63ce72adc413 100644 --- a/vendor/github.com/MakeNowJust/heredoc/heredoc.go +++ b/vendor/github.com/MakeNowJust/heredoc/heredoc.go @@ -33,7 +33,7 @@ const maxInt = int(^uint(0) >> 1) // Doc returns un-indented string as here-document. func Doc(raw string) string { skipFirstLine := false - if raw[0] == '\n' { + if len(raw) > 0 && raw[0] == '\n' { raw = raw[1:] } else { skipFirstLine = true diff --git a/vendor/github.com/MakeNowJust/heredoc/heredoc_test.go b/vendor/github.com/MakeNowJust/heredoc/heredoc_test.go index 3b8d5eee9149..290805b1447d 100644 --- a/vendor/github.com/MakeNowJust/heredoc/heredoc_test.go +++ b/vendor/github.com/MakeNowJust/heredoc/heredoc_test.go @@ -13,6 +13,7 @@ type testCase struct { } var tests = []testCase{ + {"", ""}, {` Foo Bar diff --git a/vendor/github.com/apparentlymart/go-cidr/cidr/cidr.go b/vendor/github.com/apparentlymart/go-cidr/cidr/cidr.go index c292db0ce07e..0c9c3d392d4d 100644 --- a/vendor/github.com/apparentlymart/go-cidr/cidr/cidr.go +++ b/vendor/github.com/apparentlymart/go-cidr/cidr/cidr.go @@ -129,7 +129,11 @@ func VerifyNoOverlap(subnets []*net.IPNet, CIDRBlock *net.IPNet) error { if !CIDRBlock.Contains(firstLastIP[i][0]) || !CIDRBlock.Contains(firstLastIP[i][1]) { return fmt.Errorf("%s does not fully contain %s", CIDRBlock.String(), s.String()) } - for j := i + 1; j < len(subnets); j++ { + for j := 0; j < len(subnets); j++ { + if i == j { + continue + } + first := firstLastIP[j][0] last := firstLastIP[j][1] if s.Contains(first) || s.Contains(last) { diff --git a/vendor/github.com/apparentlymart/go-cidr/cidr/cidr_test.go b/vendor/github.com/apparentlymart/go-cidr/cidr/cidr_test.go index 64fdce8e1d13..07de6f154019 100644 --- a/vendor/github.com/apparentlymart/go-cidr/cidr/cidr_test.go +++ b/vendor/github.com/apparentlymart/go-cidr/cidr/cidr_test.go @@ -397,6 +397,15 @@ func TestVerifyNetowrk(t *testing.T) { "192.168.12.128/26", }, }, + &testVerifyNetwork{ + CIDRBlock: "10.42.0.0/24", + CIDRList: []string{ + + "10.42.0.16/28", + "10.42.0.32/28", + "10.42.0.0/24", + }, + }, } for _, tc := range testCases { diff --git a/vendor/github.com/docker/libtrust/README.md b/vendor/github.com/docker/libtrust/README.md index 8e7db38186e6..dcffb31ae4a7 100644 --- a/vendor/github.com/docker/libtrust/README.md +++ b/vendor/github.com/docker/libtrust/README.md @@ -1,5 +1,9 @@ # libtrust +> **WARNING** this library is no longer actively developed, and will be integrated +> in the [docker/distribution][https://www.github.com/docker/distribution] +> repository in future. + Libtrust is library for managing authentication and authorization using public key cryptography. Authentication is handled using the identity attached to the public key. diff --git a/vendor/github.com/docker/libtrust/util.go b/vendor/github.com/docker/libtrust/util.go index d88176cc3d59..a5a101d3f117 100644 --- a/vendor/github.com/docker/libtrust/util.go +++ b/vendor/github.com/docker/libtrust/util.go @@ -152,7 +152,7 @@ func NewIdentityAuthTLSClientConfig(dockerUrl string, trustUnknownHosts bool, ro } // joseBase64UrlEncode encodes the given data using the standard base64 url -// encoding format but with all trailing '=' characters ommitted in accordance +// encoding format but with all trailing '=' characters omitted in accordance // with the jose specification. // http://tools.ietf.org/html/draft-ietf-jose-json-web-signature-31#section-2 func joseBase64UrlEncode(b []byte) string { diff --git a/vendor/github.com/google/cadvisor/container/crio/handler.go b/vendor/github.com/google/cadvisor/container/crio/handler.go index d17ba6d932f3..92c9c36b5fd2 100644 --- a/vendor/github.com/google/cadvisor/container/crio/handler.go +++ b/vendor/github.com/google/cadvisor/container/crio/handler.go @@ -33,6 +33,9 @@ import ( ) type crioContainerHandler struct { + client crioClient + name string + machineInfoFactory info.MachineInfoFactory // Absolute path to the cgroup hierarchies of this container. @@ -68,6 +71,9 @@ type crioContainerHandler struct { reference info.ContainerReference libcontainerHandler *containerlibcontainer.Handler + cgroupManager *cgroupfs.Manager + rootFs string + pidKnown bool } var _ container.ContainerHandler = &crioContainerHandler{} @@ -106,11 +112,20 @@ func newCrioContainerHandler( } id := ContainerNameToCrioId(name) + pidKnown := true cInfo, err := client.ContainerInfo(id) if err != nil { return nil, err } + if cInfo.Pid == 0 { + // If pid is not known yet, network related stats can not be retrieved by the + // libcontainer handler GetStats(). In this case, the crio handler GetStats() + // will reattempt to get the pid and, if now known, will construct the libcontainer + // handler. This libcontainer handler is then cached and reused without additional + // calls to crio. + pidKnown = false + } // passed to fs handler below ... // XXX: this is using the full container logpath, as constructed by the CRI @@ -145,6 +160,8 @@ func newCrioContainerHandler( // TODO: extract object mother method handler := &crioContainerHandler{ + client: client, + name: name, machineInfoFactory: machineInfoFactory, cgroupPaths: cgroupPaths, storageDriver: storageDriver, @@ -155,6 +172,9 @@ func newCrioContainerHandler( includedMetrics: includedMetrics, reference: containerReference, libcontainerHandler: libcontainerHandler, + cgroupManager: cgroupManager, + rootFs: rootFs, + pidKnown: pidKnown, } handler.image = cInfo.Image @@ -266,8 +286,27 @@ func (self *crioContainerHandler) getFsStats(stats *info.ContainerStats) error { return nil } +func (self *crioContainerHandler) getLibcontainerHandler() *containerlibcontainer.Handler { + if self.pidKnown { + return self.libcontainerHandler + } + + id := ContainerNameToCrioId(self.name) + + cInfo, err := self.client.ContainerInfo(id) + if err != nil || cInfo.Pid == 0 { + return self.libcontainerHandler + } + + self.pidKnown = true + self.libcontainerHandler = containerlibcontainer.NewHandler(self.cgroupManager, self.rootFs, cInfo.Pid, self.includedMetrics) + + return self.libcontainerHandler +} + func (self *crioContainerHandler) GetStats() (*info.ContainerStats, error) { - stats, err := self.libcontainerHandler.GetStats() + libcontainerHandler := self.getLibcontainerHandler() + stats, err := libcontainerHandler.GetStats() if err != nil { return stats, err } diff --git a/vendor/github.com/gorilla/mux/.circleci/config.yml b/vendor/github.com/gorilla/mux/.circleci/config.yml new file mode 100644 index 000000000000..536bc119f682 --- /dev/null +++ b/vendor/github.com/gorilla/mux/.circleci/config.yml @@ -0,0 +1,87 @@ +version: 2.0 + +jobs: + # Base test configuration for Go library tests Each distinct version should + # inherit this base, and override (at least) the container image used. + "test": &test + docker: + - image: circleci/golang:latest + working_directory: /go/src/github.com/gorilla/mux + steps: &steps + # Our build steps: we checkout the repo, fetch our deps, lint, and finally + # run "go test" on the package. + - checkout + # Logs the version in our build logs, for posterity + - run: go version + - run: + name: "Fetch dependencies" + command: > + go get -t -v ./... + # Only run gofmt, vet & lint against the latest Go version + - run: + name: "Run golint" + command: > + if [ "${LATEST}" = true ] && [ -z "${SKIP_GOLINT}" ]; then + go get -u golang.org/x/lint/golint + golint ./... + fi + - run: + name: "Run gofmt" + command: > + if [[ "${LATEST}" = true ]]; then + diff -u <(echo -n) <(gofmt -d -e .) + fi + - run: + name: "Run go vet" + command: > + if [[ "${LATEST}" = true ]]; then + go vet -v ./... + fi + - run: go test -v -race ./... + + "latest": + <<: *test + environment: + LATEST: true + + "1.12": + <<: *test + docker: + - image: circleci/golang:1.12 + + "1.11": + <<: *test + docker: + - image: circleci/golang:1.11 + + "1.10": + <<: *test + docker: + - image: circleci/golang:1.10 + + "1.9": + <<: *test + docker: + - image: circleci/golang:1.9 + + "1.8": + <<: *test + docker: + - image: circleci/golang:1.8 + + "1.7": + <<: *test + docker: + - image: circleci/golang:1.7 + +workflows: + version: 2 + build: + jobs: + - "latest" + - "1.12" + - "1.11" + - "1.10" + - "1.9" + - "1.8" + - "1.7" diff --git a/vendor/github.com/gorilla/mux/.github/stale.yml b/vendor/github.com/gorilla/mux/.github/stale.yml index de8a67804bf3..f4b12d30baf3 100644 --- a/vendor/github.com/gorilla/mux/.github/stale.yml +++ b/vendor/github.com/gorilla/mux/.github/stale.yml @@ -1,10 +1,10 @@ -daysUntilStale: 60 -daysUntilClose: 7 +daysUntilStale: 75 +daysUntilClose: 14 # Issues with these labels will never be considered stale exemptLabels: - - v2 - - needs-review - - work-required + - proposal + - needs review + - build system staleLabel: stale markComment: > This issue has been automatically marked as stale because it hasn't seen diff --git a/vendor/github.com/gorilla/mux/.travis.yml b/vendor/github.com/gorilla/mux/.travis.yml deleted file mode 100644 index 0e58a7297f03..000000000000 --- a/vendor/github.com/gorilla/mux/.travis.yml +++ /dev/null @@ -1,24 +0,0 @@ -language: go -sudo: false - -matrix: - include: - - go: 1.7.x - - go: 1.8.x - - go: 1.9.x - - go: 1.10.x - - go: 1.11.x - - go: 1.x - env: LATEST=true - - go: tip - allow_failures: - - go: tip - -install: - - # Skip - -script: - - go get -t -v ./... - - diff -u <(echo -n) <(gofmt -d .) - - if [[ "$LATEST" = true ]]; then go tool vet .; fi - - go test -v -race ./... diff --git a/vendor/github.com/gorilla/mux/ISSUE_TEMPLATE.md b/vendor/github.com/gorilla/mux/ISSUE_TEMPLATE.md deleted file mode 100644 index 232be82e47a6..000000000000 --- a/vendor/github.com/gorilla/mux/ISSUE_TEMPLATE.md +++ /dev/null @@ -1,11 +0,0 @@ -**What version of Go are you running?** (Paste the output of `go version`) - - -**What version of gorilla/mux are you at?** (Paste the output of `git rev-parse HEAD` inside `$GOPATH/src/github.com/gorilla/mux`) - - -**Describe your problem** (and what you have tried so far) - - -**Paste a minimal, runnable, reproduction of your issue below** (use backticks to format it) - diff --git a/vendor/github.com/gorilla/mux/README.md b/vendor/github.com/gorilla/mux/README.md index 9e99a2703c89..28df9a9f2ed5 100644 --- a/vendor/github.com/gorilla/mux/README.md +++ b/vendor/github.com/gorilla/mux/README.md @@ -1,7 +1,7 @@ # gorilla/mux [![GoDoc](https://godoc.org/github.com/gorilla/mux?status.svg)](https://godoc.org/github.com/gorilla/mux) -[![Build Status](https://travis-ci.org/gorilla/mux.svg?branch=master)](https://travis-ci.org/gorilla/mux) +[![CircleCI](https://circleci.com/gh/gorilla/mux.svg?style=svg)](https://circleci.com/gh/gorilla/mux) [![Sourcegraph](https://sourcegraph.com/github.com/gorilla/mux/-/badge.svg)](https://sourcegraph.com/github.com/gorilla/mux?badge) ![Gorilla Logo](http://www.gorillatoolkit.org/static/images/gorilla-icon-64.png) @@ -25,10 +25,12 @@ The name mux stands for "HTTP request multiplexer". Like the standard `http.Serv * [Examples](#examples) * [Matching Routes](#matching-routes) * [Static Files](#static-files) +* [Serving Single Page Applications](#serving-single-page-applications) (e.g. React, Vue, Ember.js, etc.) * [Registered URLs](#registered-urls) * [Walking Routes](#walking-routes) * [Graceful Shutdown](#graceful-shutdown) * [Middleware](#middleware) +* [Handling CORS Requests](#handling-cors-requests) * [Testing Handlers](#testing-handlers) * [Full Example](#full-example) @@ -210,6 +212,93 @@ func main() { } ``` +### Serving Single Page Applications + +Most of the time it makes sense to serve your SPA on a separate web server from your API, +but sometimes it's desirable to serve them both from one place. It's possible to write a simple +handler for serving your SPA (for use with React Router's [BrowserRouter](https://reacttraining.com/react-router/web/api/BrowserRouter) for example), and leverage +mux's powerful routing for your API endpoints. + +```go +package main + +import ( + "encoding/json" + "log" + "net/http" + "os" + "path/filepath" + "time" + + "github.com/gorilla/mux" +) + +// spaHandler implements the http.Handler interface, so we can use it +// to respond to HTTP requests. The path to the static directory and +// path to the index file within that static directory are used to +// serve the SPA in the given static directory. +type spaHandler struct { + staticPath string + indexPath string +} + +// ServeHTTP inspects the URL path to locate a file within the static dir +// on the SPA handler. If a file is found, it will be served. If not, the +// file located at the index path on the SPA handler will be served. This +// is suitable behavior for serving an SPA (single page application). +func (h spaHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + // get the absolute path to prevent directory traversal + path, err := filepath.Abs(r.URL.Path) + if err != nil { + // if we failed to get the absolute path respond with a 400 bad request + // and stop + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + // prepend the path with the path to the static directory + path = filepath.Join(h.staticPath, path) + + // check whether a file exists at the given path + _, err = os.Stat(path) + if os.IsNotExist(err) { + // file does not exist, serve index.html + http.ServeFile(w, r, filepath.Join(h.staticPath, h.indexPath)) + return + } else if err != nil { + // if we got an error (that wasn't that the file doesn't exist) stating the + // file, return a 500 internal server error and stop + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + // otherwise, use http.FileServer to serve the static dir + http.FileServer(http.Dir(h.staticPath)).ServeHTTP(w, r) +} + +func main() { + router := mux.NewRouter() + + router.HandleFunc("/api/health", func(w http.ResponseWriter, r *http.Request) { + // an example API handler + json.NewEncoder(w).Encode(map[string]bool{"ok": true}) + }) + + spa := spaHandler{staticPath: "build", indexPath: "index.html"} + router.PathPrefix("/").Handler(spa) + + srv := &http.Server{ + Handler: router, + Addr: "127.0.0.1:8000", + // Good practice: enforce timeouts for servers you create! + WriteTimeout: 15 * time.Second, + ReadTimeout: 15 * time.Second, + } + + log.Fatal(srv.ListenAndServe()) +} +``` + ### Registered URLs Now let's see how to build registered URLs. @@ -491,6 +580,73 @@ r.Use(amw.Middleware) Note: The handler chain will be stopped if your middleware doesn't call `next.ServeHTTP()` with the corresponding parameters. This can be used to abort a request if the middleware writer wants to. Middlewares _should_ write to `ResponseWriter` if they _are_ going to terminate the request, and they _should not_ write to `ResponseWriter` if they _are not_ going to terminate it. +### Handling CORS Requests + +[CORSMethodMiddleware](https://godoc.org/github.com/gorilla/mux#CORSMethodMiddleware) intends to make it easier to strictly set the `Access-Control-Allow-Methods` response header. + +* You will still need to use your own CORS handler to set the other CORS headers such as `Access-Control-Allow-Origin` +* The middleware will set the `Access-Control-Allow-Methods` header to all the method matchers (e.g. `r.Methods(http.MethodGet, http.MethodPut, http.MethodOptions)` -> `Access-Control-Allow-Methods: GET,PUT,OPTIONS`) on a route +* If you do not specify any methods, then: +> _Important_: there must be an `OPTIONS` method matcher for the middleware to set the headers. + +Here is an example of using `CORSMethodMiddleware` along with a custom `OPTIONS` handler to set all the required CORS headers: + +```go +package main + +import ( + "net/http" + "github.com/gorilla/mux" +) + +func main() { + r := mux.NewRouter() + + // IMPORTANT: you must specify an OPTIONS method matcher for the middleware to set CORS headers + r.HandleFunc("/foo", fooHandler).Methods(http.MethodGet, http.MethodPut, http.MethodPatch, http.MethodOptions) + r.Use(mux.CORSMethodMiddleware(r)) + + http.ListenAndServe(":8080", r) +} + +func fooHandler(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Access-Control-Allow-Origin", "*") + if r.Method == http.MethodOptions { + return + } + + w.Write([]byte("foo")) +} +``` + +And an request to `/foo` using something like: + +```bash +curl localhost:8080/foo -v +``` + +Would look like: + +```bash +* Trying ::1... +* TCP_NODELAY set +* Connected to localhost (::1) port 8080 (#0) +> GET /foo HTTP/1.1 +> Host: localhost:8080 +> User-Agent: curl/7.59.0 +> Accept: */* +> +< HTTP/1.1 200 OK +< Access-Control-Allow-Methods: GET,PUT,PATCH,OPTIONS +< Access-Control-Allow-Origin: * +< Date: Fri, 28 Jun 2019 20:13:30 GMT +< Content-Length: 3 +< Content-Type: text/plain; charset=utf-8 +< +* Connection #0 to host localhost left intact +foo +``` + ### Testing Handlers Testing handlers in a Go web application is straightforward, and _mux_ doesn't complicate this any further. Given two files: `endpoints.go` and `endpoints_test.go`, here's how we'd test an application using _mux_. @@ -503,8 +659,8 @@ package main func HealthCheckHandler(w http.ResponseWriter, r *http.Request) { // A very simple health check. - w.WriteHeader(http.StatusOK) w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) // In the future we could report back on the status of our DB, or our cache // (e.g. Redis) by performing a simple PING, and include them in the response. diff --git a/vendor/github.com/gorilla/mux/doc.go b/vendor/github.com/gorilla/mux/doc.go index 38957deead3d..bd5a38b55d82 100644 --- a/vendor/github.com/gorilla/mux/doc.go +++ b/vendor/github.com/gorilla/mux/doc.go @@ -295,7 +295,7 @@ A more complex authentication middleware, which maps session token to users, cou r := mux.NewRouter() r.HandleFunc("/", handler) - amw := authenticationMiddleware{} + amw := authenticationMiddleware{tokenUsers: make(map[string]string)} amw.Populate() r.Use(amw.Middleware) diff --git a/vendor/github.com/gorilla/mux/example_cors_method_middleware_test.go b/vendor/github.com/gorilla/mux/example_cors_method_middleware_test.go new file mode 100644 index 000000000000..00929fcee5ba --- /dev/null +++ b/vendor/github.com/gorilla/mux/example_cors_method_middleware_test.go @@ -0,0 +1,37 @@ +package mux_test + +import ( + "fmt" + "net/http" + "net/http/httptest" + + "github.com/gorilla/mux" +) + +func ExampleCORSMethodMiddleware() { + r := mux.NewRouter() + + r.HandleFunc("/foo", func(w http.ResponseWriter, r *http.Request) { + // Handle the request + }).Methods(http.MethodGet, http.MethodPut, http.MethodPatch) + r.HandleFunc("/foo", func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Access-Control-Allow-Origin", "http://example.com") + w.Header().Set("Access-Control-Max-Age", "86400") + }).Methods(http.MethodOptions) + + r.Use(mux.CORSMethodMiddleware(r)) + + rw := httptest.NewRecorder() + req, _ := http.NewRequest("OPTIONS", "/foo", nil) // needs to be OPTIONS + req.Header.Set("Access-Control-Request-Method", "POST") // needs to be non-empty + req.Header.Set("Access-Control-Request-Headers", "Authorization") // needs to be non-empty + req.Header.Set("Origin", "http://example.com") // needs to be non-empty + + r.ServeHTTP(rw, req) + + fmt.Println(rw.Header().Get("Access-Control-Allow-Methods")) + fmt.Println(rw.Header().Get("Access-Control-Allow-Origin")) + // Output: + // GET,PUT,PATCH,OPTIONS + // http://example.com +} diff --git a/vendor/github.com/gorilla/mux/go.mod b/vendor/github.com/gorilla/mux/go.mod index cfc8ede5818b..df170a399403 100644 --- a/vendor/github.com/gorilla/mux/go.mod +++ b/vendor/github.com/gorilla/mux/go.mod @@ -1 +1,3 @@ module github.com/gorilla/mux + +go 1.12 diff --git a/vendor/github.com/gorilla/mux/middleware.go b/vendor/github.com/gorilla/mux/middleware.go index ceb812cee284..cf2b26dc037a 100644 --- a/vendor/github.com/gorilla/mux/middleware.go +++ b/vendor/github.com/gorilla/mux/middleware.go @@ -32,37 +32,19 @@ func (r *Router) useInterface(mw middleware) { r.middlewares = append(r.middlewares, mw) } -// CORSMethodMiddleware sets the Access-Control-Allow-Methods response header -// on a request, by matching routes based only on paths. It also handles -// OPTIONS requests, by settings Access-Control-Allow-Methods, and then -// returning without calling the next http handler. +// CORSMethodMiddleware automatically sets the Access-Control-Allow-Methods response header +// on requests for routes that have an OPTIONS method matcher to all the method matchers on +// the route. Routes that do not explicitly handle OPTIONS requests will not be processed +// by the middleware. See examples for usage. func CORSMethodMiddleware(r *Router) MiddlewareFunc { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { - var allMethods []string - - err := r.Walk(func(route *Route, _ *Router, _ []*Route) error { - for _, m := range route.matchers { - if _, ok := m.(*routeRegexp); ok { - if m.Match(req, &RouteMatch{}) { - methods, err := route.GetMethods() - if err != nil { - return err - } - - allMethods = append(allMethods, methods...) - } - break - } - } - return nil - }) - + allMethods, err := getAllMethodsForRoute(r, req) if err == nil { - w.Header().Set("Access-Control-Allow-Methods", strings.Join(append(allMethods, "OPTIONS"), ",")) - - if req.Method == "OPTIONS" { - return + for _, v := range allMethods { + if v == http.MethodOptions { + w.Header().Set("Access-Control-Allow-Methods", strings.Join(allMethods, ",")) + } } } @@ -70,3 +52,28 @@ func CORSMethodMiddleware(r *Router) MiddlewareFunc { }) } } + +// getAllMethodsForRoute returns all the methods from method matchers matching a given +// request. +func getAllMethodsForRoute(r *Router, req *http.Request) ([]string, error) { + var allMethods []string + + err := r.Walk(func(route *Route, _ *Router, _ []*Route) error { + for _, m := range route.matchers { + if _, ok := m.(*routeRegexp); ok { + if m.Match(req, &RouteMatch{}) { + methods, err := route.GetMethods() + if err != nil { + return err + } + + allMethods = append(allMethods, methods...) + } + break + } + } + return nil + }) + + return allMethods, err +} diff --git a/vendor/github.com/gorilla/mux/middleware_test.go b/vendor/github.com/gorilla/mux/middleware_test.go index b708be0991ac..27647afe4305 100644 --- a/vendor/github.com/gorilla/mux/middleware_test.go +++ b/vendor/github.com/gorilla/mux/middleware_test.go @@ -3,7 +3,6 @@ package mux import ( "bytes" "net/http" - "net/http/httptest" "testing" ) @@ -28,12 +27,12 @@ func TestMiddlewareAdd(t *testing.T) { router.useInterface(mw) if len(router.middlewares) != 1 || router.middlewares[0] != mw { - t.Fatal("Middleware was not added correctly") + t.Fatal("Middleware interface was not added correctly") } router.Use(mw.Middleware) if len(router.middlewares) != 2 { - t.Fatal("MiddlewareFunc method was not added correctly") + t.Fatal("Middleware method was not added correctly") } banalMw := func(handler http.Handler) http.Handler { @@ -41,7 +40,7 @@ func TestMiddlewareAdd(t *testing.T) { } router.Use(banalMw) if len(router.middlewares) != 3 { - t.Fatal("MiddlewareFunc method was not added correctly") + t.Fatal("Middleware function was not added correctly") } } @@ -55,34 +54,37 @@ func TestMiddleware(t *testing.T) { rw := NewRecorder() req := newRequest("GET", "/") - // Test regular middleware call - router.ServeHTTP(rw, req) - if mw.timesCalled != 1 { - t.Fatalf("Expected %d calls, but got only %d", 1, mw.timesCalled) - } - - // Middleware should not be called for 404 - req = newRequest("GET", "/not/found") - router.ServeHTTP(rw, req) - if mw.timesCalled != 1 { - t.Fatalf("Expected %d calls, but got only %d", 1, mw.timesCalled) - } + t.Run("regular middleware call", func(t *testing.T) { + router.ServeHTTP(rw, req) + if mw.timesCalled != 1 { + t.Fatalf("Expected %d calls, but got only %d", 1, mw.timesCalled) + } + }) - // Middleware should not be called if there is a method mismatch - req = newRequest("POST", "/") - router.ServeHTTP(rw, req) - if mw.timesCalled != 1 { - t.Fatalf("Expected %d calls, but got only %d", 1, mw.timesCalled) - } + t.Run("not called for 404", func(t *testing.T) { + req = newRequest("GET", "/not/found") + router.ServeHTTP(rw, req) + if mw.timesCalled != 1 { + t.Fatalf("Expected %d calls, but got only %d", 1, mw.timesCalled) + } + }) - // Add the middleware again as function - router.Use(mw.Middleware) - req = newRequest("GET", "/") - router.ServeHTTP(rw, req) - if mw.timesCalled != 3 { - t.Fatalf("Expected %d calls, but got only %d", 3, mw.timesCalled) - } + t.Run("not called for method mismatch", func(t *testing.T) { + req = newRequest("POST", "/") + router.ServeHTTP(rw, req) + if mw.timesCalled != 1 { + t.Fatalf("Expected %d calls, but got only %d", 1, mw.timesCalled) + } + }) + t.Run("regular call using function middleware", func(t *testing.T) { + router.Use(mw.Middleware) + req = newRequest("GET", "/") + router.ServeHTTP(rw, req) + if mw.timesCalled != 3 { + t.Fatalf("Expected %d calls, but got only %d", 3, mw.timesCalled) + } + }) } func TestMiddlewareSubrouter(t *testing.T) { @@ -98,42 +100,56 @@ func TestMiddlewareSubrouter(t *testing.T) { rw := NewRecorder() req := newRequest("GET", "/") - router.ServeHTTP(rw, req) - if mw.timesCalled != 0 { - t.Fatalf("Expected %d calls, but got only %d", 0, mw.timesCalled) - } + t.Run("not called for route outside subrouter", func(t *testing.T) { + router.ServeHTTP(rw, req) + if mw.timesCalled != 0 { + t.Fatalf("Expected %d calls, but got only %d", 0, mw.timesCalled) + } + }) - req = newRequest("GET", "/sub/") - router.ServeHTTP(rw, req) - if mw.timesCalled != 0 { - t.Fatalf("Expected %d calls, but got only %d", 0, mw.timesCalled) - } + t.Run("not called for subrouter root 404", func(t *testing.T) { + req = newRequest("GET", "/sub/") + router.ServeHTTP(rw, req) + if mw.timesCalled != 0 { + t.Fatalf("Expected %d calls, but got only %d", 0, mw.timesCalled) + } + }) - req = newRequest("GET", "/sub/x") - router.ServeHTTP(rw, req) - if mw.timesCalled != 1 { - t.Fatalf("Expected %d calls, but got only %d", 1, mw.timesCalled) - } + t.Run("called once for route inside subrouter", func(t *testing.T) { + req = newRequest("GET", "/sub/x") + router.ServeHTTP(rw, req) + if mw.timesCalled != 1 { + t.Fatalf("Expected %d calls, but got only %d", 1, mw.timesCalled) + } + }) - req = newRequest("GET", "/sub/not/found") - router.ServeHTTP(rw, req) - if mw.timesCalled != 1 { - t.Fatalf("Expected %d calls, but got only %d", 1, mw.timesCalled) - } + t.Run("not called for 404 inside subrouter", func(t *testing.T) { + req = newRequest("GET", "/sub/not/found") + router.ServeHTTP(rw, req) + if mw.timesCalled != 1 { + t.Fatalf("Expected %d calls, but got only %d", 1, mw.timesCalled) + } + }) - router.useInterface(mw) + t.Run("middleware added to router", func(t *testing.T) { + router.useInterface(mw) - req = newRequest("GET", "/") - router.ServeHTTP(rw, req) - if mw.timesCalled != 2 { - t.Fatalf("Expected %d calls, but got only %d", 2, mw.timesCalled) - } + t.Run("called once for route outside subrouter", func(t *testing.T) { + req = newRequest("GET", "/") + router.ServeHTTP(rw, req) + if mw.timesCalled != 2 { + t.Fatalf("Expected %d calls, but got only %d", 2, mw.timesCalled) + } + }) - req = newRequest("GET", "/sub/x") - router.ServeHTTP(rw, req) - if mw.timesCalled != 4 { - t.Fatalf("Expected %d calls, but got only %d", 4, mw.timesCalled) - } + t.Run("called twice for route inside subrouter", func(t *testing.T) { + req = newRequest("GET", "/sub/x") + router.ServeHTTP(rw, req) + if mw.timesCalled != 4 { + t.Fatalf("Expected %d calls, but got only %d", 4, mw.timesCalled) + } + }) + }) } func TestMiddlewareExecution(t *testing.T) { @@ -145,30 +161,33 @@ func TestMiddlewareExecution(t *testing.T) { w.Write(handlerStr) }) - rw := NewRecorder() - req := newRequest("GET", "/") + t.Run("responds normally without middleware", func(t *testing.T) { + rw := NewRecorder() + req := newRequest("GET", "/") - // Test handler-only call - router.ServeHTTP(rw, req) + router.ServeHTTP(rw, req) - if bytes.Compare(rw.Body.Bytes(), handlerStr) != 0 { - t.Fatal("Handler response is not what it should be") - } + if !bytes.Equal(rw.Body.Bytes(), handlerStr) { + t.Fatal("Handler response is not what it should be") + } + }) - // Test middleware call - rw = NewRecorder() + t.Run("responds with handler and middleware response", func(t *testing.T) { + rw := NewRecorder() + req := newRequest("GET", "/") - router.Use(func(h http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.Write(mwStr) - h.ServeHTTP(w, r) + router.Use(func(h http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Write(mwStr) + h.ServeHTTP(w, r) + }) }) - }) - router.ServeHTTP(rw, req) - if bytes.Compare(rw.Body.Bytes(), append(mwStr, handlerStr...)) != 0 { - t.Fatal("Middleware + handler response is not what it should be") - } + router.ServeHTTP(rw, req) + if !bytes.Equal(rw.Body.Bytes(), append(mwStr, handlerStr...)) { + t.Fatal("Middleware + handler response is not what it should be") + } + }) } func TestMiddlewareNotFound(t *testing.T) { @@ -187,26 +206,29 @@ func TestMiddlewareNotFound(t *testing.T) { }) // Test not found call with default handler - rw := NewRecorder() - req := newRequest("GET", "/notfound") + t.Run("not called", func(t *testing.T) { + rw := NewRecorder() + req := newRequest("GET", "/notfound") - router.ServeHTTP(rw, req) - if bytes.Contains(rw.Body.Bytes(), mwStr) { - t.Fatal("Middleware was called for a 404") - } + router.ServeHTTP(rw, req) + if bytes.Contains(rw.Body.Bytes(), mwStr) { + t.Fatal("Middleware was called for a 404") + } + }) - // Test not found call with custom handler - rw = NewRecorder() - req = newRequest("GET", "/notfound") + t.Run("not called with custom not found handler", func(t *testing.T) { + rw := NewRecorder() + req := newRequest("GET", "/notfound") - router.NotFoundHandler = http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { - rw.Write([]byte("Custom 404 handler")) - }) - router.ServeHTTP(rw, req) + router.NotFoundHandler = http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { + rw.Write([]byte("Custom 404 handler")) + }) + router.ServeHTTP(rw, req) - if bytes.Contains(rw.Body.Bytes(), mwStr) { - t.Fatal("Middleware was called for a custom 404") - } + if bytes.Contains(rw.Body.Bytes(), mwStr) { + t.Fatal("Middleware was called for a custom 404") + } + }) } func TestMiddlewareMethodMismatch(t *testing.T) { @@ -225,27 +247,29 @@ func TestMiddlewareMethodMismatch(t *testing.T) { }) }) - // Test method mismatch - rw := NewRecorder() - req := newRequest("POST", "/") + t.Run("not called", func(t *testing.T) { + rw := NewRecorder() + req := newRequest("POST", "/") - router.ServeHTTP(rw, req) - if bytes.Contains(rw.Body.Bytes(), mwStr) { - t.Fatal("Middleware was called for a method mismatch") - } + router.ServeHTTP(rw, req) + if bytes.Contains(rw.Body.Bytes(), mwStr) { + t.Fatal("Middleware was called for a method mismatch") + } + }) - // Test not found call - rw = NewRecorder() - req = newRequest("POST", "/") + t.Run("not called with custom method not allowed handler", func(t *testing.T) { + rw := NewRecorder() + req := newRequest("POST", "/") - router.MethodNotAllowedHandler = http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { - rw.Write([]byte("Method not allowed")) - }) - router.ServeHTTP(rw, req) + router.MethodNotAllowedHandler = http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { + rw.Write([]byte("Method not allowed")) + }) + router.ServeHTTP(rw, req) - if bytes.Contains(rw.Body.Bytes(), mwStr) { - t.Fatal("Middleware was called for a method mismatch") - } + if bytes.Contains(rw.Body.Bytes(), mwStr) { + t.Fatal("Middleware was called for a method mismatch") + } + }) } func TestMiddlewareNotFoundSubrouter(t *testing.T) { @@ -269,27 +293,29 @@ func TestMiddlewareNotFoundSubrouter(t *testing.T) { }) }) - // Test not found call for default handler - rw := NewRecorder() - req := newRequest("GET", "/sub/notfound") + t.Run("not called", func(t *testing.T) { + rw := NewRecorder() + req := newRequest("GET", "/sub/notfound") - router.ServeHTTP(rw, req) - if bytes.Contains(rw.Body.Bytes(), mwStr) { - t.Fatal("Middleware was called for a 404") - } + router.ServeHTTP(rw, req) + if bytes.Contains(rw.Body.Bytes(), mwStr) { + t.Fatal("Middleware was called for a 404") + } + }) - // Test not found call with custom handler - rw = NewRecorder() - req = newRequest("GET", "/sub/notfound") + t.Run("not called with custom not found handler", func(t *testing.T) { + rw := NewRecorder() + req := newRequest("GET", "/sub/notfound") - subrouter.NotFoundHandler = http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { - rw.Write([]byte("Custom 404 handler")) - }) - router.ServeHTTP(rw, req) + subrouter.NotFoundHandler = http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { + rw.Write([]byte("Custom 404 handler")) + }) + router.ServeHTTP(rw, req) - if bytes.Contains(rw.Body.Bytes(), mwStr) { - t.Fatal("Middleware was called for a custom 404") - } + if bytes.Contains(rw.Body.Bytes(), mwStr) { + t.Fatal("Middleware was called for a custom 404") + } + }) } func TestMiddlewareMethodMismatchSubrouter(t *testing.T) { @@ -313,66 +339,142 @@ func TestMiddlewareMethodMismatchSubrouter(t *testing.T) { }) }) - // Test method mismatch without custom handler - rw := NewRecorder() - req := newRequest("POST", "/sub/") + t.Run("not called", func(t *testing.T) { + rw := NewRecorder() + req := newRequest("POST", "/sub/") - router.ServeHTTP(rw, req) - if bytes.Contains(rw.Body.Bytes(), mwStr) { - t.Fatal("Middleware was called for a method mismatch") - } + router.ServeHTTP(rw, req) + if bytes.Contains(rw.Body.Bytes(), mwStr) { + t.Fatal("Middleware was called for a method mismatch") + } + }) - // Test method mismatch with custom handler - rw = NewRecorder() - req = newRequest("POST", "/sub/") + t.Run("not called with custom method not allowed handler", func(t *testing.T) { + rw := NewRecorder() + req := newRequest("POST", "/sub/") - router.MethodNotAllowedHandler = http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { - rw.Write([]byte("Method not allowed")) - }) - router.ServeHTTP(rw, req) + router.MethodNotAllowedHandler = http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { + rw.Write([]byte("Method not allowed")) + }) + router.ServeHTTP(rw, req) - if bytes.Contains(rw.Body.Bytes(), mwStr) { - t.Fatal("Middleware was called for a method mismatch") - } + if bytes.Contains(rw.Body.Bytes(), mwStr) { + t.Fatal("Middleware was called for a method mismatch") + } + }) } func TestCORSMethodMiddleware(t *testing.T) { - router := NewRouter() - - cases := []struct { - path string - response string - method string - testURL string - expectedAllowedMethods string + testCases := []struct { + name string + registerRoutes func(r *Router) + requestHeader http.Header + requestMethod string + requestPath string + expectedAccessControlAllowMethodsHeader string + expectedResponse string }{ - {"/g/{o}", "a", "POST", "/g/asdf", "POST,PUT,GET,OPTIONS"}, - {"/g/{o}", "b", "PUT", "/g/bla", "POST,PUT,GET,OPTIONS"}, - {"/g/{o}", "c", "GET", "/g/orilla", "POST,PUT,GET,OPTIONS"}, - {"/g", "d", "POST", "/g", "POST,OPTIONS"}, + { + name: "does not set without OPTIONS matcher", + registerRoutes: func(r *Router) { + r.HandleFunc("/foo", stringHandler("a")).Methods(http.MethodGet, http.MethodPut, http.MethodPatch) + }, + requestMethod: "GET", + requestPath: "/foo", + expectedAccessControlAllowMethodsHeader: "", + expectedResponse: "a", + }, + { + name: "sets on non OPTIONS", + registerRoutes: func(r *Router) { + r.HandleFunc("/foo", stringHandler("a")).Methods(http.MethodGet, http.MethodPut, http.MethodPatch) + r.HandleFunc("/foo", stringHandler("b")).Methods(http.MethodOptions) + }, + requestMethod: "GET", + requestPath: "/foo", + expectedAccessControlAllowMethodsHeader: "GET,PUT,PATCH,OPTIONS", + expectedResponse: "a", + }, + { + name: "sets without preflight headers", + registerRoutes: func(r *Router) { + r.HandleFunc("/foo", stringHandler("a")).Methods(http.MethodGet, http.MethodPut, http.MethodPatch) + r.HandleFunc("/foo", stringHandler("b")).Methods(http.MethodOptions) + }, + requestMethod: "OPTIONS", + requestPath: "/foo", + expectedAccessControlAllowMethodsHeader: "GET,PUT,PATCH,OPTIONS", + expectedResponse: "b", + }, + { + name: "does not set on error", + registerRoutes: func(r *Router) { + r.HandleFunc("/foo", stringHandler("a")) + }, + requestMethod: "OPTIONS", + requestPath: "/foo", + expectedAccessControlAllowMethodsHeader: "", + expectedResponse: "a", + }, + { + name: "sets header on valid preflight", + registerRoutes: func(r *Router) { + r.HandleFunc("/foo", stringHandler("a")).Methods(http.MethodGet, http.MethodPut, http.MethodPatch) + r.HandleFunc("/foo", stringHandler("b")).Methods(http.MethodOptions) + }, + requestMethod: "OPTIONS", + requestPath: "/foo", + requestHeader: http.Header{ + "Access-Control-Request-Method": []string{"GET"}, + "Access-Control-Request-Headers": []string{"Authorization"}, + "Origin": []string{"http://example.com"}, + }, + expectedAccessControlAllowMethodsHeader: "GET,PUT,PATCH,OPTIONS", + expectedResponse: "b", + }, + { + name: "does not set methods from unmatching routes", + registerRoutes: func(r *Router) { + r.HandleFunc("/foo", stringHandler("c")).Methods(http.MethodDelete) + r.HandleFunc("/foo/bar", stringHandler("a")).Methods(http.MethodGet, http.MethodPut, http.MethodPatch) + r.HandleFunc("/foo/bar", stringHandler("b")).Methods(http.MethodOptions) + }, + requestMethod: "OPTIONS", + requestPath: "/foo/bar", + requestHeader: http.Header{ + "Access-Control-Request-Method": []string{"GET"}, + "Access-Control-Request-Headers": []string{"Authorization"}, + "Origin": []string{"http://example.com"}, + }, + expectedAccessControlAllowMethodsHeader: "GET,PUT,PATCH,OPTIONS", + expectedResponse: "b", + }, } - for _, tt := range cases { - router.HandleFunc(tt.path, stringHandler(tt.response)).Methods(tt.method) - } + for _, tt := range testCases { + t.Run(tt.name, func(t *testing.T) { + router := NewRouter() - router.Use(CORSMethodMiddleware(router)) + tt.registerRoutes(router) - for _, tt := range cases { - rr := httptest.NewRecorder() - req := newRequest(tt.method, tt.testURL) + router.Use(CORSMethodMiddleware(router)) - router.ServeHTTP(rr, req) + rw := NewRecorder() + req := newRequest(tt.requestMethod, tt.requestPath) + req.Header = tt.requestHeader - if rr.Body.String() != tt.response { - t.Errorf("Expected body '%s', found '%s'", tt.response, rr.Body.String()) - } + router.ServeHTTP(rw, req) - allowedMethods := rr.HeaderMap.Get("Access-Control-Allow-Methods") + actualMethodsHeader := rw.Header().Get("Access-Control-Allow-Methods") + if actualMethodsHeader != tt.expectedAccessControlAllowMethodsHeader { + t.Fatalf("Expected Access-Control-Allow-Methods to equal %s but got %s", tt.expectedAccessControlAllowMethodsHeader, actualMethodsHeader) + } - if allowedMethods != tt.expectedAllowedMethods { - t.Errorf("Expected Access-Control-Allow-Methods '%s', found '%s'", tt.expectedAllowedMethods, allowedMethods) - } + actualResponse := rw.Body.String() + if actualResponse != tt.expectedResponse { + t.Fatalf("Expected response to equal %s but got %s", tt.expectedResponse, actualResponse) + } + }) } } @@ -411,27 +513,33 @@ func TestMiddlewareOnMultiSubrouter(t *testing.T) { }) }) - rw := NewRecorder() - req := newRequest("GET", "/first") + t.Run("/first uses first middleware", func(t *testing.T) { + rw := NewRecorder() + req := newRequest("GET", "/first") - router.ServeHTTP(rw, req) - if rw.Body.String() != first { - t.Fatalf("Middleware did not run: expected %s middleware to write a response (got %s)", first, rw.Body.String()) - } + router.ServeHTTP(rw, req) + if rw.Body.String() != first { + t.Fatalf("Middleware did not run: expected %s middleware to write a response (got %s)", first, rw.Body.String()) + } + }) - rw = NewRecorder() - req = newRequest("GET", "/second") + t.Run("/second uses second middleware", func(t *testing.T) { + rw := NewRecorder() + req := newRequest("GET", "/second") - router.ServeHTTP(rw, req) - if rw.Body.String() != second { - t.Fatalf("Middleware did not run: expected %s middleware to write a response (got %s)", second, rw.Body.String()) - } + router.ServeHTTP(rw, req) + if rw.Body.String() != second { + t.Fatalf("Middleware did not run: expected %s middleware to write a response (got %s)", second, rw.Body.String()) + } + }) - rw = NewRecorder() - req = newRequest("GET", "/second/not-exist") + t.Run("uses not found handler", func(t *testing.T) { + rw := NewRecorder() + req := newRequest("GET", "/second/not-exist") - router.ServeHTTP(rw, req) - if rw.Body.String() != notFound { - t.Fatalf("Notfound handler did not run: expected %s for not-exist, (got %s)", notFound, rw.Body.String()) - } + router.ServeHTTP(rw, req) + if rw.Body.String() != notFound { + t.Fatalf("Notfound handler did not run: expected %s for not-exist, (got %s)", notFound, rw.Body.String()) + } + }) } diff --git a/vendor/github.com/gorilla/mux/mux.go b/vendor/github.com/gorilla/mux/mux.go index 8aca972d2f61..26f9582ac844 100644 --- a/vendor/github.com/gorilla/mux/mux.go +++ b/vendor/github.com/gorilla/mux/mux.go @@ -111,10 +111,8 @@ func copyRouteConf(r routeConf) routeConf { c.regexp.queries = append(c.regexp.queries, copyRouteRegexp(q)) } - c.matchers = make([]matcher, 0, len(r.matchers)) - for _, m := range r.matchers { - c.matchers = append(c.matchers, m) - } + c.matchers = make([]matcher, len(r.matchers)) + copy(c.matchers, r.matchers) return c } @@ -283,6 +281,12 @@ func (r *Router) NewRoute() *Route { return route } +// Name registers a new route with a name. +// See Route.Name(). +func (r *Router) Name(name string) *Route { + return r.NewRoute().Name(name) +} + // Handle registers a new route with a matcher for the URL path. // See Route.Path() and Route.Handler(). func (r *Router) Handle(path string, handler http.Handler) *Route { diff --git a/vendor/github.com/gorilla/mux/mux_test.go b/vendor/github.com/gorilla/mux/mux_test.go index 5198024d01c3..34c00dd25ad4 100644 --- a/vendor/github.com/gorilla/mux/mux_test.go +++ b/vendor/github.com/gorilla/mux/mux_test.go @@ -1123,10 +1123,7 @@ func TestSchemes(t *testing.T) { func TestMatcherFunc(t *testing.T) { m := func(r *http.Request, m *RouteMatch) bool { - if r.URL.Host == "aaa.bbb.ccc" { - return true - } - return false + return r.URL.Host == "aaa.bbb.ccc" } tests := []routeTest{ @@ -1444,10 +1441,11 @@ func TestNamedRoutes(t *testing.T) { r3.NewRoute().Name("g") r3.NewRoute().Name("h") r3.NewRoute().Name("i") + r3.Name("j") - if r1.namedRoutes == nil || len(r1.namedRoutes) != 9 { - t.Errorf("Expected 9 named routes, got %v", r1.namedRoutes) - } else if r1.Get("i") == nil { + if r1.namedRoutes == nil || len(r1.namedRoutes) != 10 { + t.Errorf("Expected 10 named routes, got %v", r1.namedRoutes) + } else if r1.Get("j") == nil { t.Errorf("Subroute name not registered") } } @@ -1945,7 +1943,7 @@ type TestA301ResponseWriter struct { } func (ho *TestA301ResponseWriter) Header() http.Header { - return http.Header(ho.hh) + return ho.hh } func (ho *TestA301ResponseWriter) Write(b []byte) (int, error) { diff --git a/vendor/github.com/gorilla/mux/regexp.go b/vendor/github.com/gorilla/mux/regexp.go index f25288675633..ac1abcd473e3 100644 --- a/vendor/github.com/gorilla/mux/regexp.go +++ b/vendor/github.com/gorilla/mux/regexp.go @@ -113,6 +113,13 @@ func newRouteRegexp(tpl string, typ regexpType, options routeRegexpOptions) (*ro if typ != regexpTypePrefix { pattern.WriteByte('$') } + + var wildcardHostPort bool + if typ == regexpTypeHost { + if !strings.Contains(pattern.String(), ":") { + wildcardHostPort = true + } + } reverse.WriteString(raw) if endSlash { reverse.WriteByte('/') @@ -131,13 +138,14 @@ func newRouteRegexp(tpl string, typ regexpType, options routeRegexpOptions) (*ro // Done! return &routeRegexp{ - template: template, - regexpType: typ, - options: options, - regexp: reg, - reverse: reverse.String(), - varsN: varsN, - varsR: varsR, + template: template, + regexpType: typ, + options: options, + regexp: reg, + reverse: reverse.String(), + varsN: varsN, + varsR: varsR, + wildcardHostPort: wildcardHostPort, }, nil } @@ -158,11 +166,22 @@ type routeRegexp struct { varsN []string // Variable regexps (validators). varsR []*regexp.Regexp + // Wildcard host-port (no strict port match in hostname) + wildcardHostPort bool } // Match matches the regexp against the URL host or path. func (r *routeRegexp) Match(req *http.Request, match *RouteMatch) bool { - if r.regexpType != regexpTypeHost { + if r.regexpType == regexpTypeHost { + host := getHost(req) + if r.wildcardHostPort { + // Don't be strict on the port match + if i := strings.Index(host, ":"); i != -1 { + host = host[:i] + } + } + return r.regexp.MatchString(host) + } else { if r.regexpType == regexpTypeQuery { return r.matchQueryString(req) } @@ -172,8 +191,6 @@ func (r *routeRegexp) Match(req *http.Request, match *RouteMatch) bool { } return r.regexp.MatchString(path) } - - return r.regexp.MatchString(getHost(req)) } // url builds a URL part using the given values. diff --git a/vendor/github.com/gorilla/mux/route.go b/vendor/github.com/gorilla/mux/route.go index 16a7cdf4eadc..8479c68c1df7 100644 --- a/vendor/github.com/gorilla/mux/route.go +++ b/vendor/github.com/gorilla/mux/route.go @@ -383,7 +383,7 @@ func (r *Route) PathPrefix(tpl string) *Route { // The above route will only match if the URL contains the defined queries // values, e.g.: ?foo=bar&id=42. // -// It the value is an empty string, it will match any value if the key is set. +// If the value is an empty string, it will match any value if the key is set. // // Variables can define an optional regexp pattern to be matched: // diff --git a/vendor/github.com/lestrrat-go/jspointer/.gitignore b/vendor/github.com/lestrrat-go/jspointer/.gitignore new file mode 100644 index 000000000000..daf913b1b347 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jspointer/.gitignore @@ -0,0 +1,24 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test +*.prof diff --git a/vendor/github.com/lestrrat-go/jspointer/.travis.yml b/vendor/github.com/lestrrat-go/jspointer/.travis.yml new file mode 100644 index 000000000000..21e0a8e8d7c0 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jspointer/.travis.yml @@ -0,0 +1,5 @@ +language: go +sudo: false +go: + - 1.11 + - tip diff --git a/vendor/github.com/lestrrat-go/jspointer/LICENSE b/vendor/github.com/lestrrat-go/jspointer/LICENSE new file mode 100644 index 000000000000..20054b15434d --- /dev/null +++ b/vendor/github.com/lestrrat-go/jspointer/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 lestrrat + +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/lestrrat-go/jspointer/README.md b/vendor/github.com/lestrrat-go/jspointer/README.md new file mode 100644 index 000000000000..e1a4fbcd01b0 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jspointer/README.md @@ -0,0 +1,34 @@ +# go-jspointer + +[![Build Status](https://travis-ci.org/lestrrat-go/jspointer.svg?branch=master)](https://travis-ci.org/lestrrat-go/jspointer) + +[![GoDoc](https://godoc.org/github.com/lestrrat-go/jspointer?status.svg)](https://godoc.org/github.com/lestrrat-go/jspointer) + +JSON pointer for Go + +# Features + +* Compile and match against Maps, Slices, Structs (or pointers to those) +* Set values in each of those + +# Usage + +```go +p, _ := jspointer.New(`/foo/bar/baz`) +result, _ := p.Get(someStruct) +``` + +# Credits + +This is almost a fork of https://github.com/xeipuuv/gojsonpointer. + +# References + +| Name | Notes | +|:--------------------------------------------------------:|:---------------------------------| +| [go-jsval](https://github.com/lestrrat-go/jsval) | Validator generator | +| [go-jsschema](https://github.com/lestrrat-go/jsschema) | JSON Schema implementation | +| [go-jshschema](https://github.com/lestrrat-go/jshschema) | JSON Hyper Schema implementation | +| [go-jsref](https://github.com/lestrrat-go/jsref) | JSON Reference implementation | + + diff --git a/vendor/github.com/lestrrat-go/jspointer/bench/bench_test.go b/vendor/github.com/lestrrat-go/jspointer/bench/bench_test.go new file mode 100644 index 000000000000..3ffe29fb4ded --- /dev/null +++ b/vendor/github.com/lestrrat-go/jspointer/bench/bench_test.go @@ -0,0 +1,40 @@ +// +build bench + +package bench_test + +import ( + "encoding/json" + "testing" + + "github.com/lestrrat-go/jspointer" + "github.com/xeipuuv/gojsonpointer" +) + +const jsontxt = `{"a":[{"b": 1, "c": 2}], "d": 3}` + +var m map[string]interface{} + +func init() { + if err := json.Unmarshal([]byte(jsontxt), &m); err != nil { + panic(err) + } +} + +func BenchmarkGojsonpointer(b *testing.B) { + p, _ := gojsonpointer.NewJsonPointer(`/a/0/c`) + for i := 0; i < b.N; i++ { + res, kind, err := p.Get(m) + _ = res + _ = kind + _ = err + } +} + +func BenchmarkJspointer(b *testing.B) { + p, _ := jspointer.New(`/a/0/c`) + for i := 0; i < b.N; i++ { + res, err := p.Get(m) + _ = res + _ = err + } +} \ No newline at end of file diff --git a/vendor/github.com/lestrrat-go/jspointer/interface.go b/vendor/github.com/lestrrat-go/jspointer/interface.go new file mode 100644 index 000000000000..7fe800233bb2 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jspointer/interface.go @@ -0,0 +1,27 @@ +package jspointer + +import "errors" + +// Errors used in jspointer package +var ( + ErrInvalidPointer = errors.New("invalid pointer") + ErrCanNotSet = errors.New("field cannot be set to") + ErrSliceIndexOutOfBounds = errors.New("slice index out of bounds") +) + +// Consntants used in jspointer package. Mostly for internal usage only +const ( + EncodedTilde = "~0" + EncodedSlash = "~1" + Separator = '/' +) + +type ErrNotFound struct { + Ptr string +} + +// JSPointer represents a JSON pointer +type JSPointer struct { + raw string + tokens tokens +} diff --git a/vendor/github.com/lestrrat-go/jspointer/jspointer.go b/vendor/github.com/lestrrat-go/jspointer/jspointer.go new file mode 100644 index 000000000000..c42b9613f9a3 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jspointer/jspointer.go @@ -0,0 +1,262 @@ +package jspointer + +import ( + "bytes" + "encoding/json" + "errors" + "reflect" + "strconv" + + "github.com/lestrrat-go/structinfo" +) + +type tokens struct { + s string + positions [][2]int +} + +func (t *tokens) size() int { + return len(t.positions) +} + +func (t *tokens) get(i int) string { + p := t.positions[i] + return t.s[p[0]:p[1]] +} + +// New creates a new JSON pointer for given path spec. If the path fails +// to be parsed, an error is returned +func New(path string) (*JSPointer, error) { + var p JSPointer + + if err := p.parse(path); err != nil { + return nil, err + } + p.raw = path + return &p, nil +} + +func (p *JSPointer) parse(s string) error { + if s == "" { + return nil + } + + if s[0] != Separator { + return ErrInvalidPointer + } + + if len(s) < 2 { + return ErrInvalidPointer + } + + ntokens := 0 + for i := 0; i < len(s); i++ { + if s[i] == '/' { + ntokens++ + } + } + + positions := make([][2]int, 0, ntokens) + start := 1 + var buf bytes.Buffer + buf.WriteByte(s[0]) + for i := 1; i < len(s); i++ { + switch s[i] { + case Separator: + buf.WriteByte(s[i]) + positions = append(positions, [2]int{start, buf.Len() - 1}) + start = i + 1 + case '~': + if len(s) == 1 { + buf.WriteByte(s[i]) + } else { + switch s[1] { + case '0': + buf.WriteByte('~') + case '1': + buf.WriteByte('/') + default: + buf.WriteByte(s[i]) + } + } + default: + buf.WriteByte(s[i]) + } + } + + if start < buf.Len() { + positions = append(positions, [2]int{start, buf.Len()}) + } + + p.tokens.s = buf.String() + p.tokens.positions = positions + return nil +} + +// String returns the stringified version of this JSON pointer +func (p JSPointer) String() string { + return p.raw +} + +// Get applies the JSON pointer to the given item, and returns +// the result. +func (p JSPointer) Get(item interface{}) (interface{}, error) { + var ctx matchCtx + + ctx.raw = p.raw + ctx.tokens = &p.tokens + ctx.apply(item) + return ctx.result, ctx.err +} + +// Set applies the JSON pointer to the given item, and sets the +// value accordingly. +func (p JSPointer) Set(item interface{}, value interface{}) error { + var ctx matchCtx + + ctx.set = true + ctx.raw = p.raw + ctx.tokens = &p.tokens + ctx.setvalue = value + ctx.apply(item) + return ctx.err +} + +type matchCtx struct { + err error + raw string + result interface{} + set bool + setvalue interface{} + tokens *tokens +} + +func (e ErrNotFound) Error() string { + return "match to JSON pointer not found: " + e.Ptr +} + +type JSONGetter interface { + JSONGet(tok string) (interface{}, error) +} + +var strType = reflect.TypeOf("") +var zeroval reflect.Value + +func (c *matchCtx) apply(item interface{}) { + if c.tokens.size() == 0 { + c.result = item + return + } + + node := item + lastidx := c.tokens.size() - 1 + for i := 0; i < c.tokens.size(); i++ { + token := c.tokens.get(i) + + if getter, ok := node.(JSONGetter); ok { + x, err := getter.JSONGet(token) + if err != nil { + c.err = ErrNotFound{Ptr: c.raw} + return + } + if i == lastidx { + c.result = x + return + } + node = x + continue + } + v := reflect.ValueOf(node) + + // Does this thing implement a JSONGet? + + if v.Kind() == reflect.Ptr { + v = v.Elem() + } + + switch v.Kind() { + case reflect.Struct: + fn := structinfo.StructFieldFromJSONName(v, token) + if fn == "" { + c.err = ErrNotFound{Ptr: c.raw} + return + } + f := v.FieldByName(fn) + if i == lastidx { + if c.set { + if !f.CanSet() { + c.err = ErrCanNotSet + return + } + f.Set(reflect.ValueOf(c.setvalue)) + return + } + c.result = f.Interface() + return + } + node = f.Interface() + case reflect.Map: + var vt reflect.Value + // We shall try to inflate the token to its Go native + // type if it's not a string. In other words, try not to + // outdo yourselves. + if t := v.Type().Key(); t != strType { + vt = reflect.New(t).Elem() + if err := json.Unmarshal([]byte(token), vt.Addr().Interface()); err != nil { + name := t.PkgPath() + "." + t.Name() + if name == "" { + name = "(anonymous type)" + } + c.err = errors.New("unsupported conversion of string to " + name) + return + } + } else { + vt = reflect.ValueOf(token) + } + n := v.MapIndex(vt) + if zeroval == n { + c.err = ErrNotFound{Ptr: c.raw} + return + } + + if i == lastidx { + if c.set { + v.SetMapIndex(vt, reflect.ValueOf(c.setvalue)) + } else { + c.result = n.Interface() + } + return + } + + node = n.Interface() + case reflect.Slice: + m := node.([]interface{}) + wantidx, err := strconv.Atoi(token) + if err != nil { + c.err = err + return + } + + if wantidx < 0 || len(m) <= wantidx { + c.err = ErrSliceIndexOutOfBounds + return + } + + if i == lastidx { + if c.set { + m[wantidx] = c.setvalue + } else { + c.result = m[wantidx] + } + return + } + node = m[wantidx] + default: + c.err = ErrNotFound{Ptr: c.raw} + return + } + } + + // If you fell through here, there was a big problem + c.err = ErrNotFound{Ptr: c.raw} +} diff --git a/vendor/github.com/lestrrat-go/jspointer/jspointer_test.go b/vendor/github.com/lestrrat-go/jspointer/jspointer_test.go new file mode 100644 index 000000000000..50ba8e610d29 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jspointer/jspointer_test.go @@ -0,0 +1,168 @@ +package jspointer_test + +import ( + "encoding/json" + "testing" + + "github.com/lestrrat-go/jspointer" + "github.com/stretchr/testify/assert" +) + +var src = `{ +"foo": ["bar", "baz"], +"obj": { "a":1, "b":2, "c":[3,4], "d":[ {"e":9}, {"f":[50,51]} ] }, +"": 0, +"a/b": 1, +"c%d": 2, +"e^f": 3, +"g|h": 4, +"i\\j": 5, +"k\"l": 6, +" ": 7, +"m~n": 8 +}` +var target map[string]interface{} + +func init() { + if err := json.Unmarshal([]byte(src), &target); err != nil { + panic(err) + } +} + +func TestEscaping(t *testing.T) { + data := []string{ + `/a~1b`, + `/m~0n`, + `/a~1b/m~0n`, + } + for _, pat := range data { + p, err := jspointer.New(pat) + if !assert.NoError(t, err, "jspointer.New should succeed for '%s'", pat) { + return + } + + if !assert.Equal(t, pat, p.String(), "input pattern and generated expression should match") { + return + } + } +} + +func runmatch(t *testing.T, pat string, m interface{}) (interface{}, error) { + p, err := jspointer.New(pat) + if !assert.NoError(t, err, "jspointer.New should succeed for '%s'", pat) { + return nil, err + } + + return p.Get(m) +} + +func TestFullDocument(t *testing.T) { + res, err := runmatch(t, ``, target) + if !assert.NoError(t, err, "jsonpointer.Get should succeed") { + return + } + if !assert.Equal(t, res, target, "res should be equal to target") { + return + } +} + +func TestGetObject(t *testing.T) { + pats := map[string]interface{}{ + `/obj/a`: float64(1), + `/obj/b`: float64(2), + `/obj/c/0`: float64(3), + `/obj/c/1`: float64(4), + `/obj/d/1/f/0`: float64(50), + } + for pat, expected := range pats { + res, err := runmatch(t, pat, target) + if !assert.NoError(t, err, "jsonpointer.Get should succeed") { + return + } + + if !assert.Equal(t, res, expected, "res should be equal to expected") { + return + } + } +} + +func TestGetArray(t *testing.T) { + foo := target["foo"].([]interface{}) + pats := map[string]interface{}{ + `/foo/0`: foo[0], + `/foo/1`: foo[1], + } + for pat, expected := range pats { + res, err := runmatch(t, pat, target) + if !assert.NoError(t, err, "jsonpointer.Get should succeed") { + return + } + + if !assert.Equal(t, res, expected, "res should be equal to expected") { + return + } + } +} + +func TestSet(t *testing.T) { + var m interface{} + json.Unmarshal([]byte(`{ +"a": [{"b": 1, "c": 2}], "d": 3 +}`), &m) + + p, err := jspointer.New(`/a/0/c`) + if !assert.NoError(t, err, "jspointer.New should succeed") { + return + } + + if !assert.NoError(t, p.Set(m, 999), "jspointer.Set should succeed") { + return + } + + res, err := runmatch(t, `/a/0/c`, m) + if !assert.NoError(t, err, "jsonpointer.Get should succeed") { + return + } + + if !assert.Equal(t, res, 999, "res should be equal to expected") { + return + } +} + +func TestStruct(t *testing.T) { + var s struct { + Foo string `json:"foo"` + Bar map[string]interface{} `json:"bar"` + Baz map[int]int `json:"baz"` + quux int + } + + s.Foo = "foooooo" + s.Bar = map[string]interface{}{ + "a": 0, + "b": 1, + } + s.Baz = map[int]int{ + 2: 3, + } + + res, err := runmatch(t, `/bar/b`, s) + if !assert.NoError(t, err, "jsonpointer.Get should succeed") { + return + } + + if !assert.Equal(t, res, 1, "res should be equal to expected value") { + return + } + + res, err = runmatch(t, `/baz/2`, s) + if !assert.NoError(t, err, "jsonpointer.Get should succeed") { + return + } + + if !assert.Equal(t, res, 3, "res should be equal to expected value") { + return + } +} + + diff --git a/vendor/github.com/lestrrat-go/jsref/.gitignore b/vendor/github.com/lestrrat-go/jsref/.gitignore new file mode 100644 index 000000000000..daf913b1b347 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jsref/.gitignore @@ -0,0 +1,24 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test +*.prof diff --git a/vendor/github.com/lestrrat-go/jsref/.travis.yml b/vendor/github.com/lestrrat-go/jsref/.travis.yml new file mode 100644 index 000000000000..2fbcb829a8e6 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jsref/.travis.yml @@ -0,0 +1,5 @@ +language: go +sudo: false +go: + - 1.11.x + - tip diff --git a/vendor/github.com/lestrrat-go/jsref/LICENSE b/vendor/github.com/lestrrat-go/jsref/LICENSE new file mode 100644 index 000000000000..20054b15434d --- /dev/null +++ b/vendor/github.com/lestrrat-go/jsref/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 lestrrat + +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/lestrrat-go/jsref/README.md b/vendor/github.com/lestrrat-go/jsref/README.md new file mode 100644 index 000000000000..16a88c1aafa8 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jsref/README.md @@ -0,0 +1,107 @@ +# go-jsref + +[![Build Status](https://travis-ci.org/lestrrat-go/jsref.svg?branch=master)](https://travis-ci.org/lestrrat-go/jsref) + +[![GoDoc](https://godoc.org/github.com/lestrrat-go/jsref?status.svg)](https://godoc.org/github.com/lestrrat-go/jsref) + +JSON Reference Implementation for Go + +# SYNOPSIS + +```go +package jsref_test + +import ( + "encoding/json" + "fmt" + "log" + + jsref "github.com/lestrrat-go/jsref" + "github.com/lestrrat-go/jsref/provider" +) + +func Example() { + var v interface{} + src := []byte(` +{ + "foo": ["bar", {"$ref": "#/sub"}, {"$ref": "obj2#/sub"}], + "sub": "baz" +}`) + if err := json.Unmarshal(src, &v); err != nil { + log.Printf("%s", err) + return + } + + // External reference + mp := provider.NewMap() + mp.Set("obj2", map[string]string{"sub": "quux"}) + + res := jsref.New() + res.AddProvider(mp) // Register the provider + + data := []struct { + Ptr string + Options []jsref.Option + }{ + { + Ptr: "#/foo/0", // "bar" + }, + { + Ptr: "#/foo/1", // "baz" + }, + { + Ptr: "#/foo/2", // "quux" (resolves via `mp`) + }, + { + Ptr: "#/foo", // ["bar",{"$ref":"#/sub"},{"$ref":"obj2#/sub"}] + }, + { + Ptr: "#/foo", // ["bar","baz","quux"] + // experimental option to resolve all resulting values + Options: []jsref.Option{ jsref.WithRecursiveResolution(true) }, + }, + } + for _, set := range data { + result, err := res.Resolve(v, set.Ptr, set.Options...) + if err != nil { // failed to resolve + fmt.Printf("err: %s\n", err) + continue + } + b, _ := json.Marshal(result) + fmt.Printf("%s -> %s\n", set.Ptr, string(b)) + } + + // OUTPUT: + // #/foo/0 -> "bar" + // #/foo/1 -> "baz" + // #/foo/2 -> "quux" + // #/foo -> ["bar",{"$ref":"#/sub"},{"$ref":"obj2#/sub"}] + // #/foo -> ["bar","baz","quux"] +} +``` + +# Providers + +The Resolver object by default does not know how to resolve *any* reference: +You must provide it one or more `Provider`s to look for and resolve external references. + +Currently available `Provider`s are: + +| Name | Description | +|:--------------|:------------| +| provider.FS | Resolve from local file system. References must start with a `file:///` prefix | +| provider.Map | Resolve from in memory map. | +| provider.HTTP | Resolve by making HTTP requests. References must start with a `http(s?)://` prefix | + +# References + +| Name | Notes | +|:--------------------------------------------------------:|:---------------------------------| +| [go-jsval](https://github.com/lestrrat-go/jsval) | Validator generator | +| [go-jshschema](https://github.com/lestrrat-go/jshschema) | JSON Hyper Schema implementation | +| [go-jsschema](https://github.com/lestrrat-go/jsschema) | JSON Schema implementation | +| [go-jspointer](https://github.com/lestrrat-go/jspointer) | JSON Pointer implementations | + +# Acknowledgements + +* Boris Burtin diff --git a/vendor/github.com/lestrrat-go/jsref/interface.go b/vendor/github.com/lestrrat-go/jsref/interface.go new file mode 100644 index 000000000000..905a8c313e45 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jsref/interface.go @@ -0,0 +1,23 @@ +package jsref + +import ( + "errors" + "net/url" + "reflect" +) + +var zeroval = reflect.Value{} + +var ErrMaxRecursion = errors.New("reached max number of recursions") + +// Resolver is responsible for interpreting the provided JSON +// reference. +type Resolver struct { + providers []Provider + MaxRecursions int +} + +// Provider resolves a URL into a ... thing. +type Provider interface { + Get(*url.URL) (interface{}, error) +} diff --git a/vendor/github.com/lestrrat-go/jsref/jsref.go b/vendor/github.com/lestrrat-go/jsref/jsref.go new file mode 100644 index 000000000000..107473062bf2 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jsref/jsref.go @@ -0,0 +1,396 @@ +package jsref + +import ( + "net/url" + "reflect" + + "github.com/lestrrat-go/jspointer" + "github.com/lestrrat-go/pdebug" + "github.com/lestrrat-go/structinfo" + "github.com/pkg/errors" +) + +const ref = "$ref" +var refrv = reflect.ValueOf(ref) + +type Option interface { + Name() string + Value() interface{} +} + +type option struct { + name string + value interface{} +} + +func (o option) Name() string { return o.name } +func (o option) Value() interface{} { return o.value } + +// WithRecursiveResolution allows ou to enable recursive resolution +// on the *result* data structure. This means that after resolving +// the JSON reference in the structure at hand, it does another +// pass at resolving the entire data structure. Depending on your +// structure and size, this may incur significant cost. +// +// Please note that recursive resolution of the result is still +// experimental. If you find problems, please submit a pull request +// with a failing test case. +func WithRecursiveResolution(b bool) Option { + return &option{ + name: "recursiveResolution", + value: b, + } +} + +var DefaultMaxRecursions = 10 + +// New creates a new Resolver +func New() *Resolver { + return &Resolver{MaxRecursions: DefaultMaxRecursions} +} + +// AddProvider adds a new Provider to be searched for in case +// a JSON pointer with more than just the URI fragment is given. +func (r *Resolver) AddProvider(p Provider) error { + r.providers = append(r.providers, p) + return nil +} + +type resolveCtx struct { + rlevel int // recurse level + maxrlevel int // max recurse level + object interface{} // the main object that was passed to `Resolve()` +} + +// Resolve takes a target `v`, and a JSON pointer `spec`. +// spec is expected to be in the form of +// +// [scheme://[userinfo@]host/path[?query]]#fragment +// [scheme:opaque[?query]]#fragment +// +// where everything except for `#fragment` is optional. +// If the fragment is empty, an error is returned. +// +// If `spec` is the empty string, `v` is returned +// This method handles recursive JSON references. +// +// If `WithRecursiveResolution` option is given and its value is true, +// an attempt to resolve all references within the resulting object +// is made by traversing the structure recursively. Default is false +func (r *Resolver) Resolve(v interface{}, ptr string, options ...Option) (ret interface{}, err error) { + if pdebug.Enabled { + g := pdebug.Marker("Resolver.Resolve(%s)", ptr).BindError(&err) + defer g.End() + } + var recursiveResolution bool + for _, opt := range options { + switch opt.Name() { + case "recursiveResolution": + recursiveResolution = opt.Value().(bool) + } + } + + ctx := resolveCtx{ + rlevel: 0, + maxrlevel: r.MaxRecursions, + object: v, + } + + // First, expand the target as much as we can + v, err = expandRefRecursive(&ctx, r, v) + if err != nil { + return nil, errors.Wrap(err, "recursive search failed") + } + + result, err := evalptr(&ctx, r, v, ptr) + if err != nil { + return nil, err + } + + if recursiveResolution { + rv, err := traverseExpandRefRecursive(&ctx, r, reflect.ValueOf(result)) + if err != nil { + return nil, errors.Wrap(err, `failed to resolve result`) + } + result = rv.Interface() + } + + return result, nil +} + +func setPtrOrInterface(container, value reflect.Value) bool { + switch container.Kind() { + case reflect.Ptr: + if !value.CanAddr() { + return false + } + container.Set(value.Addr()) + case reflect.Interface: + container.Set(value) + default: + return false + } + return true +} + +func traverseExpandRefRecursive(ctx *resolveCtx, r *Resolver, rv reflect.Value) (reflect.Value, error) { + if pdebug.Enabled { + g := pdebug.Marker("traverseExpandRefRecursive") + defer g.End() + } + + switch rv.Kind() { + case reflect.Ptr, reflect.Interface: + rv = rv.Elem() + } + + switch rv.Kind() { + case reflect.Array, reflect.Slice: + for i := 0; i < rv.Len(); i++ { + elem := rv.Index(i) + var elemcontainer reflect.Value + switch elem.Kind() { + case reflect.Ptr, reflect.Interface: + elemcontainer = elem + elem = elem.Elem() + } + + // Need to check for elem being Valid, otherwise the + // subsequent call to Interface() will fail + if !elem.IsValid() { + continue + } + + if elemcontainer.IsValid() { + if !elemcontainer.CanSet() { + continue + } + } + newv, err := expandRefRecursive(ctx, r, elem.Interface()) + if err != nil { + return zeroval, errors.Wrap(err, `failed to expand array/slice element`) + } + newrv, err := traverseExpandRefRecursive(ctx, r, reflect.ValueOf(newv)) + if err != nil { + return zeroval, errors.Wrap(err, `failed to recurse into array/slice element`) + } + + if elemcontainer.IsValid() { + setPtrOrInterface(elemcontainer, newrv) + } else { + elem.Set(newrv) + } + } + case reflect.Map: + // No refs found in the map keys, but there could be more + // in the values + if _, err := findRef(rv.Interface()); err != nil { + for _, key := range rv.MapKeys() { + value, err := traverseExpandRefRecursive(ctx, r, rv.MapIndex(key)) + if err != nil { + return zeroval, errors.Wrap(err, `failed to traverse map value`) + } + rv.SetMapIndex(key, value) + } + return rv, nil + } + newv, err := expandRefRecursive(ctx, r, rv.Interface()) + if err != nil { + return zeroval, errors.Wrap(err, `failed to expand map element`) + } + return traverseExpandRefRecursive(ctx, r, reflect.ValueOf(newv)) + case reflect.Struct: + // No refs found in the map keys, but there could be more + // in the values + if _, err := findRef(rv.Interface()); err != nil { + for i := 0; i < rv.NumField(); i++ { + field := rv.Field(i) + value, err := traverseExpandRefRecursive(ctx, r, field) + if err != nil { + return zeroval, errors.Wrap(err, `failed to traverse struct field value`) + } + field.Set(value) + } + return rv, nil + } + newv, err := expandRefRecursive(ctx, r, rv.Interface()) + if err != nil { + return zeroval, errors.Wrap(err, `failed to expand struct element`) + } + return traverseExpandRefRecursive(ctx, r, reflect.ValueOf(newv)) + } + return rv, nil +} + +// expands $ref with in v, until all $refs are expanded. +// note: DOES NOT recurse down into structures +func expandRefRecursive(ctx *resolveCtx, r *Resolver, v interface{}) (ret interface{}, err error) { + if pdebug.Enabled { + g := pdebug.Marker("expandRefRecursive") + defer g.End() + } + for { + ref, err := findRef(v) + if err != nil { + if pdebug.Enabled { + pdebug.Printf("No refs found. bailing out of loop") + } + break + } + + if pdebug.Enabled { + pdebug.Printf("Found ref '%s'", ref) + } + + newv, err := expandRef(ctx, r, v, ref) + if err != nil { + if pdebug.Enabled { + pdebug.Printf("Failed to expand ref '%s': %s", ref, err) + } + return nil, errors.Wrap(err, "failed to expand ref") + } + + v = newv + } + + return v, nil +} + +func expandRef(ctx *resolveCtx, r *Resolver, v interface{}, ref string) (ret interface{}, err error) { + ctx.rlevel++ + if ctx.rlevel > ctx.maxrlevel { + return nil, ErrMaxRecursion + } + + defer func() { ctx.rlevel-- }() + + u, err := url.Parse(ref) + if err != nil { + return nil, errors.Wrap(err, "failed to parse ref as URL") + } + + ptr := "#" + u.Fragment + if u.Host == "" && u.Path == "" { + if pdebug.Enabled { + pdebug.Printf("ptr doesn't contain any host/path part, apply json pointer directly to object") + } + return evalptr(ctx, r, ctx.object, ptr) + } + + u.Fragment = "" + for _, p := range r.providers { + pv, err := p.Get(u) + if err == nil { + if pdebug.Enabled { + pdebug.Printf("Found object matching %s", u) + } + + return evalptr(ctx, r, pv, ptr) + } + } + + return nil, errors.New("element pointed by $ref '" + ref + "' not found") +} + +func findRef(v interface{}) (ref string, err error) { + if pdebug.Enabled { + g := pdebug.Marker("findRef").BindError(&err) + defer g.End() + } + + rv := reflect.ValueOf(v) + switch rv.Kind() { + case reflect.Interface, reflect.Ptr: + rv = rv.Elem() + } + + if pdebug.Enabled { + pdebug.Printf("object is a '%s'", rv.Kind()) + } + + // Find if we have a "$ref" element + var refv reflect.Value + switch rv.Kind() { + case reflect.Map: + refv = rv.MapIndex(refrv) + case reflect.Struct: + if fn := structinfo.StructFieldFromJSONName(rv, ref); fn != "" { + refv = rv.FieldByName(fn) + } + default: + return "", errors.New("element is not a map-like container") + } + + if !refv.IsValid() { + return "", errors.New("$ref element not found") + } + + switch refv.Kind() { + case reflect.Interface, reflect.Ptr: + refv = refv.Elem() + } + + switch refv.Kind() { + case reflect.String: + // Empty string isn't a valid pointer + if refv.Len() <= 0 { + return "", errors.New("$ref element not found (empty)") + } + if pdebug.Enabled { + pdebug.Printf("Found ref '%s'", refv) + } + return refv.String(), nil + case reflect.Invalid: + return "", errors.New("$ref element not found") + default: + if pdebug.Enabled { + pdebug.Printf("'$ref' was found, but its kind is %s", refv.Kind()) + } + } + + return "", errors.New("$ref element must be a string") +} + +func evalptr(ctx *resolveCtx, r *Resolver, v interface{}, ptrspec string) (ret interface{}, err error) { + if pdebug.Enabled { + g := pdebug.Marker("evalptr(%s)", ptrspec).BindError(&err) + defer g.End() + } + + // If the reference is empty, return v + if ptrspec == "" || ptrspec == "#" { + if pdebug.Enabled { + pdebug.Printf("Empty pointer, return v itself") + } + return v, nil + } + + // Parse the spec. + u, err := url.Parse(ptrspec) + if err != nil { + return nil, errors.Wrap(err, "failed to parse reference spec") + } + + ptr := u.Fragment + + // We are evaluating the pointer part. That means if the + // Fragment portion is not set, there's no point in evaluating + if ptr == "" { + return nil, errors.Wrap(err, "empty json pointer") + } + + p, err := jspointer.New(ptr) + if err != nil { + return nil, errors.Wrap(err, "failed create a new JSON pointer") + } + x, err := p.Get(v) + if err != nil { + return nil, errors.Wrap(err, "failed to fetch value") + } + + if pdebug.Enabled { + pdebug.Printf("Evaulated JSON pointer, now checking if we can expand further") + } + // If this result contains more refs, expand that + return expandRefRecursive(ctx, r, x) +} diff --git a/vendor/github.com/lestrrat-go/jsref/jsref_example_test.go b/vendor/github.com/lestrrat-go/jsref/jsref_example_test.go new file mode 100644 index 000000000000..eeacd46da33d --- /dev/null +++ b/vendor/github.com/lestrrat-go/jsref/jsref_example_test.go @@ -0,0 +1,69 @@ +package jsref_test + +import ( + "encoding/json" + "fmt" + "log" + + jsref "github.com/lestrrat-go/jsref" + "github.com/lestrrat-go/jsref/provider" +) + +func Example() { + var v interface{} + src := []byte(` +{ + "foo": ["bar", {"$ref": "#/sub"}, {"$ref": "obj2#/sub"}], + "sub": "baz" +}`) + if err := json.Unmarshal(src, &v); err != nil { + log.Printf("%s", err) + return + } + + // External reference + mp := provider.NewMap() + mp.Set("obj2", map[string]string{"sub": "quux"}) + + res := jsref.New() + res.AddProvider(mp) // Register the provider + + data := []struct { + Ptr string + Options []jsref.Option + }{ + { + Ptr: "#/foo/0", // "bar" + }, + { + Ptr: "#/foo/1", // "baz" + }, + { + Ptr: "#/foo/2", // "quux" (resolves via `mp`) + }, + { + Ptr: "#/foo", // ["bar",{"$ref":"#/sub"},{"$ref":"obj2#/sub"}] + }, + { + Ptr: "#/foo", // ["bar","baz","quux"] + // experimental option to resolve all resulting values + Options: []jsref.Option{ jsref.WithRecursiveResolution(true) }, + }, + } + for _, set := range data { + result, err := res.Resolve(v, set.Ptr, set.Options...) + if err != nil { // failed to resolve + fmt.Printf("err: %s\n", err) + continue + } + b, _ := json.Marshal(result) + fmt.Printf("%s -> %s\n", set.Ptr, string(b)) + } + + // OUTPUT: + // #/foo/0 -> "bar" + // #/foo/1 -> "baz" + // #/foo/2 -> "quux" + // #/foo -> ["bar",{"$ref":"#/sub"},{"$ref":"obj2#/sub"}] + // #/foo -> ["bar","baz","quux"] +} diff --git a/vendor/github.com/lestrrat-go/jsref/jsref_test.go b/vendor/github.com/lestrrat-go/jsref/jsref_test.go new file mode 100644 index 000000000000..7c47688baff9 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jsref/jsref_test.go @@ -0,0 +1,295 @@ +package jsref_test + +import ( + "encoding/json" + "io/ioutil" + "log" + "net" + "net/http" + "os" + "path/filepath" + "sort" + "strconv" + "strings" + "testing" + "time" + + "github.com/lestrrat-go/jsref" + "github.com/lestrrat-go/jsref/provider" + "github.com/stretchr/testify/assert" +) + +func TestResolveMemory(t *testing.T) { + m := map[string]interface{}{ + "foo": []interface{}{ + "bar", + map[string]interface{}{ + "$ref": "#/sub", + }, + map[string]interface{}{ + "$ref": "obj2#/sub", + }, + }, + "sub": "baz", + } + + data := map[string]string{ + "#/foo/0": "bar", + "#/foo/1": "baz", + "#/foo/2": "quux", + } + + res := jsref.New() + mp := provider.NewMap() + mp.Set("obj2", map[string]string{"sub": "quux"}) + res.AddProvider(mp) + + ptrlist := make([]string, 0, len(data)) + for ptr := range data { + ptrlist = append(ptrlist, ptr) + } + sort.Strings(ptrlist) + + for _, ptr := range ptrlist { + expected := data[ptr] + v, err := res.Resolve(m, ptr) + if !assert.NoError(t, err, "Resolve(%s) should succeed", ptr) { + return + } + if !assert.Equal(t, v, expected, "Resolve(%s) resolves to '%s'", ptr, expected) { + return + } + } + + // In this test we test if we can optionally recursively + // resolve references + v, err := res.Resolve(m, "#/foo", jsref.WithRecursiveResolution(true)) + if !assert.NoError(t, err, "Resolve(%s) should succeed", "#/foo") { + return + } + + if !assert.Equal(t, []interface{}{"bar", "baz", "quux"}, v) { + return + } +} + +func TestResolveFS(t *testing.T) { + dir, err := ioutil.TempDir("", "jsref-test-") + if !assert.NoError(t, err, "creating temporary directory should succeed") { + return + } + defer os.RemoveAll(dir) + + path := filepath.Join(dir, "obj2") + f, err := os.Create(path) + if !assert.NoError(t, err, "creating %s file should succeed", path) { + return + } + f.Write([]byte(`{"sub":"quux"}`)) + f.Close() + + m := map[string]interface{}{ + "foo": []interface{}{ + "bar", + map[string]interface{}{ + "$ref": "#/sub", + }, + map[string]interface{}{ + "$ref": "file:///obj2#/sub", + }, + }, + "sub": "baz", + } + + data := map[string]string{ + "#/foo/0": "bar", + "#/foo/1": "baz", + "#/foo/2": "quux", + } + + res := jsref.New() + res.AddProvider(provider.NewFS(dir)) + + ptrlist := make([]string, 0, len(data)) + for ptr := range data { + ptrlist = append(ptrlist, ptr) + } + sort.Strings(ptrlist) + + for _, ptr := range ptrlist { + expected := data[ptr] + v, err := res.Resolve(m, ptr) + if !assert.NoError(t, err, "Resolve(%s) should succeed", ptr) { + return + } + if !assert.Equal(t, v, expected, "Resolve(%s) resolves to '%s'", ptr, expected) { + return + } + } +} + +func TestResolveHTTP(t *testing.T) { + if b, _ := strconv.ParseBool(os.Getenv("JSREF_LIVE_TESTS")); !b { + t.Skip("JSREF_LIVE_TESTS is not available, skipping test") + } + + cl := http.Client{ + Transport: &http.Transport{ + Dial: func(n, a string) (net.Conn, error) { + return net.DialTimeout(n, a, 2*time.Second) + }, + }, + } + + const schemaURL = `http://json-schema.org/draft-04/schema#` + if _, err := cl.Get(schemaURL); err != nil { + t.Skip("JSON schema '" + schemaURL + "' unavailable, skipping test") + } + + res := jsref.New() + hp := provider.NewHTTP() + res.AddProvider(hp) + + m := map[string]interface{}{ + "fetch": map[string]string{ + "$ref": schemaURL, + }, + } + + ptr := "#/fetch" + v, err := res.Resolve(m, ptr) + if !assert.NoError(t, err, "Resolve(%s) should succeed", ptr) { + return + } + + switch v.(type) { + case map[string]interface{}: + mv := v.(map[string]interface{}) + if !assert.Equal(t, mv["id"], schemaURL, "Resolve("+schemaURL+") resolved to JSON schema") { + return + } + default: + t.Errorf("Expected map[string]interface{}") + } +} + +func TestResolveRecursive(t *testing.T) { + var v interface{} + src := []byte(` +{ + "foo": { + "type": "array", + "items": [{ "$ref": "#" }] + } +}`) + if err := json.Unmarshal(src, &v); err != nil { + log.Printf("%s", err) + return + } + + res := jsref.New() + _, err := res.Resolve(v, "#/foo") // "bar" + if !assert.NoError(t, err, "res.Resolve should succeed") { + return + } +} + +func TestGHPR12(t *testing.T) { + // https://github.com/lestrrat-go/jsref/pull/2 gave me an example + // using "foo" as the JS pointer (could've been a typo) + // but it gave me weird results, so this is where I'm testing it + var v interface{} + src := []byte(` +{ + "foo": "bar" +}`) + if err := json.Unmarshal(src, &v); err != nil { + log.Printf("%s", err) + return + } + + res := jsref.New() + _, err := res.Resolve(v, "foo") + if !assert.NoError(t, err, "res.Resolve should fail") { + return + } +} + +func TestHyperSchemaRecursive(t *testing.T) { + src := []byte(` +{ + "definitions": { + "virtual_machine": { + "type": "object" + } + }, + "links": [ + { + "schema": { + "type": "object" + }, + "targetSchema": { + "$ref": "#/definitions/virtual_machine" + } + }, + { + "targetSchema": { + "type": "array", + "items": { + "$ref": "#/definitions/virtual_machine" + } + } + } + ] +}`) + var v interface{} + err := json.Unmarshal(src, &v) + assert.Nil(t, err) + res := jsref.New() + + ptrs := []string{ + "#/links/0/schema", + "#/links/0/targetSchema", + "#/links/1/targetSchema", + } + for _, ptr := range ptrs { + result, err := res.Resolve(v, ptr, jsref.WithRecursiveResolution(true)) + assert.Nil(t, err) + b, err := json.Marshal(result) + if !assert.NoError(t, err, "json.Marshal should succeed") { + return + } + if !assert.False(t, strings.Contains(string(b), "$ref"), "%s did not recursively resolve", ptr) { + t.Logf("resolved to '%s'", b) + return + } + } +} + +func TestGHIssue7(t *testing.T) { + src := []byte(`{ + "status": { + "type": ["string", "null"], + "enum": [ + "sent", + "duplicate", + "error", + "invalid", + "rejected", + "unqueued", + "unsubscribed", + null + ] + } +}`) + + var v interface{} + if !assert.NoError(t, json.Unmarshal(src, &v), `Unmarshal should succeed`) { + return + } + + res := jsref.New() + result, err := res.Resolve(v, "", jsref.WithRecursiveResolution(true)) + t.Logf("%s", result) + t.Logf("%s", err) +} diff --git a/vendor/github.com/lestrrat-go/jsref/provider/fs.go b/vendor/github.com/lestrrat-go/jsref/provider/fs.go new file mode 100644 index 000000000000..21eab966d109 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jsref/provider/fs.go @@ -0,0 +1,75 @@ +package provider + +import ( + "encoding/json" + "net/url" + "os" + "path/filepath" + "strings" + + "github.com/lestrrat-go/pdebug" + "github.com/pkg/errors" +) + +// NewFS creates a new Provider that looks for JSON documents +// from the local file system. Documents are only searched +// within `root` +func NewFS(root string) *FS { + return &FS{ + mp: NewMap(), + Root: root, + } +} + +// Get fetches the document specified by the `key` argument. +// Everything other than `.Path` is ignored. +// Note that once a document is read, it WILL be cached for the +// duration of this object, unless you call `Reset` +func (fp *FS) Get(key *url.URL) (out interface{}, err error) { + if pdebug.Enabled { + g := pdebug.Marker("provider.FS.Get(%s)", key.String()).BindError(&err) + defer g.End() + } + + if strings.ToLower(key.Scheme) != "file" { + return nil, errors.New("unsupported scheme '" + key.Scheme + "'") + } + + // Everything other than "Path" is ignored + path := filepath.Clean(filepath.Join(fp.Root, key.Path)) + + mpkey := &url.URL{Path: path} + if x, err := fp.mp.Get(mpkey); err == nil { + return x, nil + } + + fi, err := os.Stat(path) + if err != nil { + return nil, errors.Wrap(err, "failed to stat local resource") + } + + if fi.IsDir() { + return nil, errors.New("target is not a file") + } + + f, err := os.Open(path) + if err != nil { + return nil, errors.Wrap(err, "failed to open local resource") + } + defer f.Close() + + var x interface{} + dec := json.NewDecoder(f) + if err := dec.Decode(&x); err != nil { + return nil, errors.Wrap(err, "failed to parse JSON local resource") + } + + fp.mp.Set(path, x) + + return x, nil +} + +// Reset resets the in memory cache of JSON documents +func (fp *FS) Reset() error { + return fp.mp.Reset() +} diff --git a/vendor/github.com/lestrrat-go/jsref/provider/http.go b/vendor/github.com/lestrrat-go/jsref/provider/http.go new file mode 100644 index 000000000000..acb407b8850f --- /dev/null +++ b/vendor/github.com/lestrrat-go/jsref/provider/http.go @@ -0,0 +1,65 @@ +package provider + +import ( + "encoding/json" + "net/http" + "net/url" + "strings" + "time" + + "github.com/lestrrat-go/pdebug" + "github.com/pkg/errors" +) + +// NewFS creates a new Provider that looks for JSON documents +// from the internet over HTTP(s) +func NewHTTP() *HTTP { + return &HTTP{ + mp: NewMap(), + Client: &http.Client{ + Timeout: 5 * time.Second, + }, + } +} + +// Get fetches the document specified by the `key` argument, making +// a HTTP request if necessary. +// Note that once a document is read, it WILL be cached for the +// duration of this object, unless you call `Reset` +func (hp *HTTP) Get(key *url.URL) (interface{}, error) { + if pdebug.Enabled { + g := pdebug.Marker("HTTP.Get(%s)", key) + defer g.End() + } + + switch strings.ToLower(key.Scheme) { + case "http", "https": + default: + return nil, errors.New("key is not http/https URL") + } + + v, err := hp.mp.Get(key) + if err == nil { // Found! + return v, nil + } + + res, err := hp.Client.Get(key.String()) + if err != nil { + return nil, errors.Wrap(err, "failed to fetch HTTP resource") + } + defer res.Body.Close() + + dec := json.NewDecoder(res.Body) + + var x interface{} + if err := dec.Decode(&x); err != nil { + return nil, errors.Wrap(err, "failed to parse JSON from HTTP resource") + } + + return x, nil +} + +// Reset resets the in memory cache of JSON documents +func (hp *HTTP) Reset() error { + return hp.mp.Reset() +} diff --git a/vendor/github.com/lestrrat-go/jsref/provider/interface.go b/vendor/github.com/lestrrat-go/jsref/provider/interface.go new file mode 100644 index 000000000000..4eaf7190a28f --- /dev/null +++ b/vendor/github.com/lestrrat-go/jsref/provider/interface.go @@ -0,0 +1,21 @@ +package provider + +import ( + "net/http" + "sync" +) + +type FS struct { + mp *Map + Root string +} + +type HTTP struct { + mp *Map + Client *http.Client +} + +type Map struct { + lock sync.Mutex + mapping map[string]interface{} +} diff --git a/vendor/github.com/lestrrat-go/jsref/provider/map.go b/vendor/github.com/lestrrat-go/jsref/provider/map.go new file mode 100644 index 000000000000..48d65a6a4c48 --- /dev/null +++ b/vendor/github.com/lestrrat-go/jsref/provider/map.go @@ -0,0 +1,47 @@ +package provider + +import ( + "net/url" + + "github.com/lestrrat-go/pdebug" + "github.com/pkg/errors" +) + +func NewMap() *Map { + return &Map{ + mapping: make(map[string]interface{}), + } +} + +func (mp *Map) Set(key string, v interface{}) error { + mp.lock.Lock() + defer mp.lock.Unlock() + + mp.mapping[key] = v + return nil +} + +func (mp *Map) Get(key *url.URL) (res interface{}, err error) { + if pdebug.Enabled { + g := pdebug.Marker("Map.Get(%s)", key).BindError(&err) + defer g.End() + } + + mp.lock.Lock() + defer mp.lock.Unlock() + + v, ok := mp.mapping[key.String()] + if !ok { + return nil, errors.New("not found") + } + + return v, nil +} + +func (mp *Map) Reset() error { + mp.lock.Lock() + defer mp.lock.Unlock() + + mp.mapping = make(map[string]interface{}) + return nil +} diff --git a/vendor/github.com/lestrrat-go/pdebug/.gitignore b/vendor/github.com/lestrrat-go/pdebug/.gitignore new file mode 100644 index 000000000000..daf913b1b347 --- /dev/null +++ b/vendor/github.com/lestrrat-go/pdebug/.gitignore @@ -0,0 +1,24 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test +*.prof diff --git a/vendor/github.com/lestrrat-go/pdebug/.travis.yml b/vendor/github.com/lestrrat-go/pdebug/.travis.yml new file mode 100644 index 000000000000..baecfce60a99 --- /dev/null +++ b/vendor/github.com/lestrrat-go/pdebug/.travis.yml @@ -0,0 +1,14 @@ +language: go +sudo: false +go: + - 1.6 + - 1.7 + - tip +install: + - go get -t -v ./... + - go get -t -tags debug0 -v ./... +script: + - go test -v ./... + - go test -tags debug ./... + - PDEBUG_TRACE=1 go test -tags debug ./... + - go test -tags debug0 ./... diff --git a/vendor/github.com/lestrrat-go/pdebug/LICENSE b/vendor/github.com/lestrrat-go/pdebug/LICENSE new file mode 100644 index 000000000000..20054b15434d --- /dev/null +++ b/vendor/github.com/lestrrat-go/pdebug/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 lestrrat + +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/lestrrat-go/pdebug/README.md b/vendor/github.com/lestrrat-go/pdebug/README.md new file mode 100644 index 000000000000..4f6d88959f8a --- /dev/null +++ b/vendor/github.com/lestrrat-go/pdebug/README.md @@ -0,0 +1,95 @@ +# go-pdebug + +[![Build Status](https://travis-ci.org/lestrrat-go/pdebug.svg?branch=master)](https://travis-ci.org/lestrrat-go/pdebug) + +[![GoDoc](https://godoc.org/github.com/lestrrat-go/pdebug?status.svg)](https://godoc.org/github.com/lestrrat-go/pdebug) + +Utilities for my print debugging fun. YMMV + +# Synopsis + +![optimized](https://pbs.twimg.com/media/CbiqhzLUUAIN_7o.png) + +# Description + +Building with `pdebug` declares a constant, `pdebug.Enabled` which you +can use to easily compile in/out depending on the presence of a build tag. + +```go +func Foo() { + // will only be available if you compile with `-tags debug` + if pdebug.Enabled { + pdebug.Printf("Starting Foo()! + } +} +``` + +Note that using `github.com/lestrrat-go/pdebug` and `-tags debug` only +compiles in the code. In order to actually show the debug trace, you need +to specify an environment variable: + +```shell +# For example, to show debug code during testing: +PDEBUG_TRACE=1 go test -tags debug +``` + +If you want to forcefully show the trace (which is handy when you're +debugging/testing), you can use the `debug0` tag instead: + +```shell +go test -tags debug0 +``` + +# Markers + +When you want to print debug a chain of function calls, you can use the +`Marker` functions: + +```go +func Foo() { + if pdebug.Enabled { + g := pdebug.Marker("Foo") + defer g.End() + } + + pdebug.Printf("Inside Foo()!") +} +``` + +This will cause all of the `Printf` calls to automatically indent +the output so it's visually easier to see where a certain trace log +is being generated. + +By default it will print something like: + +``` +|DEBUG| START Foo +|DEBUG| Inside Foo()! +|DEBUG| END Foo (1.23μs) +``` + +If you want to automatically show the error value you are returning +(but only if there is an error), you can use the `BindError` method: + +```go +func Foo() (err error) { + if pdebug.Enabled { + g := pdebug.Marker("Foo").BindError(&err) + defer g.End() + } + + pdebug.Printf("Inside Foo()!") + + return errors.New("boo") +} +``` + +This will print something like: + + +``` +|DEBUG| START Foo +|DEBUG| Inside Foo()! +|DEBUG| END Foo (1.23μs): ERROR boo +``` + diff --git a/vendor/github.com/lestrrat-go/pdebug/autoflag_off.go b/vendor/github.com/lestrrat-go/pdebug/autoflag_off.go new file mode 100644 index 000000000000..3ca774591fd0 --- /dev/null +++ b/vendor/github.com/lestrrat-go/pdebug/autoflag_off.go @@ -0,0 +1,15 @@ +// +build debug + +package pdebug + +import ( + "os" + "strconv" +) + +var Trace = false +func init() { + if b, err := strconv.ParseBool(os.Getenv("PDEBUG_TRACE")); err == nil && b { + Trace = true + } +} \ No newline at end of file diff --git a/vendor/github.com/lestrrat-go/pdebug/autoflag_on.go b/vendor/github.com/lestrrat-go/pdebug/autoflag_on.go new file mode 100644 index 000000000000..f5f674db5d05 --- /dev/null +++ b/vendor/github.com/lestrrat-go/pdebug/autoflag_on.go @@ -0,0 +1,6 @@ +// +build debug0 + +package pdebug + +var Trace = true + diff --git a/vendor/github.com/lestrrat-go/pdebug/common.go b/vendor/github.com/lestrrat-go/pdebug/common.go new file mode 100644 index 000000000000..95f11a007695 --- /dev/null +++ b/vendor/github.com/lestrrat-go/pdebug/common.go @@ -0,0 +1,43 @@ +package pdebug + +import ( + "io" + "os" + "sync" + "time" +) + +type pdctx struct { + mutex sync.Mutex + indentL int + LogTime bool + Prefix string + Writer io.Writer +} + +var emptyMarkerGuard = &markerg{} + +type markerg struct { + indentg guard + ctx *pdctx + f string + args []interface{} + start time.Time + errptr *error +} + +var DefaultCtx = &pdctx{ + LogTime: true, + Prefix: "|DEBUG| ", + Writer: os.Stdout, +} + +type guard struct { + cb func() +} + +func (g *guard) End() { + if cb := g.cb; cb != nil { + cb() + } +} diff --git a/vendor/github.com/lestrrat-go/pdebug/common_test.go b/vendor/github.com/lestrrat-go/pdebug/common_test.go new file mode 100644 index 000000000000..2589727304ce --- /dev/null +++ b/vendor/github.com/lestrrat-go/pdebug/common_test.go @@ -0,0 +1,112 @@ +package pdebug + +import ( + "bytes" + "errors" + "io" + "regexp" + "testing" + + "github.com/stretchr/testify/assert" +) + +func setw(ctx *pdctx, w io.Writer) func() { + oldw := ctx.Writer + ctx.Writer = w + return func() { ctx.Writer = oldw } +} + +func TestPrintf(t *testing.T) { + buf := &bytes.Buffer{} + wg := setw(DefaultCtx, buf) + defer wg() + + Printf("Hello, World!") + + if Enabled && Trace { + re := regexp.MustCompile(`\|DEBUG\| \d+\.\d+ Hello, World!\n`) + if !assert.True(t, re.MatchString(buf.String()), "Simple Printf works") { + return + } + } else { + if !assert.Equal(t, "", buf.String(), "Simple Printf should be suppressed") { + return + } + } +} + +func TestMarker(t *testing.T) { + buf := &bytes.Buffer{} + wg := setw(DefaultCtx, buf) + defer wg() + + f2 := func() (err error) { + g := Marker("f2").BindError(&err) + defer g.End() + Printf("Hello, World!") + return errors.New("dummy error") + } + + f1 := func() { + g := Marker("f1") + defer g.End() + f2() + } + + f1() + + if Enabled && Trace { + re := regexp.MustCompile(`\|DEBUG\| \d+\.\d+ START f1\n\|DEBUG\| \d+\.\d+ START f2\n\|DEBUG\| \d+\.\d+ Hello, World!\n\|DEBUG\| \d+\.\d+ END f2 \(`) + if !assert.True(t, re.MatchString(buf.String()), "Markers should work") { + t.Logf("Expected '%v'", re) + t.Logf("Actual '%v'", buf.String()) + return + } + } else { + if !assert.Equal(t, "", buf.String(), "Markers should work") { + return + } + } +} + +func TestLegacyMarker(t *testing.T) { + buf := &bytes.Buffer{} + wg := setw(DefaultCtx, buf) + defer wg() + + f2 := func() (err error) { + g := IPrintf("START f2") + defer func() { + if err == nil { + g.IRelease("END f2") + } else { + g.IRelease("END f2: %s", err) + } + }() + Printf("Hello, World!") + return errors.New("dummy error") + } + + f1 := func() { + g := IPrintf("START f1") + defer g.IRelease("END f1") + f2() + } + + f1() + + if Enabled && Trace { + re := regexp.MustCompile(`\|DEBUG\| \d+\.\d+ START f1\n\|DEBUG\| \d+\.\d+ START f2\n\|DEBUG\| \d+\.\d+ Hello, World!\n\|DEBUG\| \d+\.\d+ END f2`) + if !assert.True(t, re.MatchString(buf.String()), "Markers should work") { + t.Logf("Expected '%v'", re) + t.Logf("Actual '%v'", buf.String()) + return + } + + // TODO: check for error and timestamp + } else { + if !assert.Equal(t, "", buf.String(), "Markers should work") { + return + } + } +} diff --git a/vendor/github.com/lestrrat-go/pdebug/debug0_test.go b/vendor/github.com/lestrrat-go/pdebug/debug0_test.go new file mode 100644 index 000000000000..052fcca96231 --- /dev/null +++ b/vendor/github.com/lestrrat-go/pdebug/debug0_test.go @@ -0,0 +1,13 @@ +//+build debug0,!debug + +package pdebug + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestDebug0Enabled(t *testing.T) { + assert.True(t, Enabled, "Enable is true") +} diff --git a/vendor/github.com/lestrrat-go/pdebug/debug_off.go b/vendor/github.com/lestrrat-go/pdebug/debug_off.go new file mode 100644 index 000000000000..9f794b29747b --- /dev/null +++ b/vendor/github.com/lestrrat-go/pdebug/debug_off.go @@ -0,0 +1,39 @@ +//+build !debug,!debug0 + +package pdebug + +// Enabled is true if `-tags debug` or `-tags debug0` is used +// during compilation. Use this to "ifdef-out" debug blocks. +const Enabled = false + +// Trace is true if `-tags debug` is used AND the environment +// variable `PDEBUG_TRACE` is set to a `true` value (i.e., +// 1, true, etc), or `-tags debug0` is used. This allows you to +// compile-in the trace logs, but only show them when you +// set the environment variable +const Trace = false + +// IRelease is deprecated. Use Marker()/End() instead +func (g guard) IRelease(f string, args ...interface{}) {} + +// IPrintf is deprecated. Use Marker()/End() instead +func IPrintf(f string, args ...interface{}) guard { return guard{} } + +// Printf prints to standard out, just like a normal fmt.Printf, +// but respects the indentation level set by IPrintf/IRelease. +// Printf is no op unless you compile with the `debug` tag. +func Printf(f string, args ...interface{}) {} + +// Dump dumps the objects using go-spew. +// Dump is a no op unless you compile with the `debug` tag. +func Dump(v ...interface{}) {} + +// Marker marks the beginning of an indented block. The message +// you specify in the arguments is prefixed witha "START", and +// subsequent calls to Printf will be indented one level more. +// +// To reset this, you must call End() on the guard object that +// gets returned by Marker(). +func Marker(f string, args ...interface{}) *markerg { return emptyMarkerGuard } +func (g *markerg) BindError(_ *error) *markerg { return g } +func (g *markerg) End() {} diff --git a/vendor/github.com/lestrrat-go/pdebug/debug_on.go b/vendor/github.com/lestrrat-go/pdebug/debug_on.go new file mode 100644 index 000000000000..064f3420ca8b --- /dev/null +++ b/vendor/github.com/lestrrat-go/pdebug/debug_on.go @@ -0,0 +1,170 @@ +// +build debug OR debug0 + +package pdebug + +import ( + "bytes" + "fmt" + "strings" + "time" + + "github.com/davecgh/go-spew/spew" +) + +const Enabled = true + +type Guard interface { + End() +} + +var emptyGuard = &guard{} + +func (ctx *pdctx) Unindent() { + ctx.mutex.Lock() + defer ctx.mutex.Unlock() + ctx.indentL-- +} + +func (ctx *pdctx) Indent() guard { + ctx.mutex.Lock() + ctx.indentL++ + ctx.mutex.Unlock() + + return guard{cb: ctx.Unindent} +} + +func (ctx *pdctx) preamble(buf *bytes.Buffer) { + if p := ctx.Prefix; len(p) > 0 { + buf.WriteString(p) + } + if ctx.LogTime { + fmt.Fprintf(buf, "%0.5f ", float64(time.Now().UnixNano()) / 1000000.0) + } + + for i := 0; i < ctx.indentL; i++ { + buf.WriteString(" ") + } +} + +func (ctx *pdctx) Printf(f string, args ...interface{}) { + if !strings.HasSuffix(f, "\n") { + f = f + "\n" + } + buf := bytes.Buffer{} + ctx.preamble(&buf) + fmt.Fprintf(&buf, f, args...) + buf.WriteTo(ctx.Writer) +} + +func Marker(f string, args ...interface{}) *markerg { + return DefaultCtx.Marker(f, args...) +} + +func (ctx *pdctx) Marker(f string, args ...interface{}) *markerg { + if !Trace { + return emptyMarkerGuard + } + + buf := &bytes.Buffer{} + ctx.preamble(buf) + buf.WriteString("START ") + fmt.Fprintf(buf, f, args...) + if buf.Len() > 0 { + if b := buf.Bytes(); b[buf.Len()-1] != '\n' { + buf.WriteRune('\n') + } + } + + buf.WriteTo(ctx.Writer) + + g := ctx.Indent() + return &markerg{ + indentg: g, + ctx: ctx, + f: f, + args: args, + start: time.Now(), + errptr: nil, + } +} + +func (g *markerg) BindError(errptr *error) *markerg { + if g.ctx == nil { + return g + } + g.ctx.mutex.Lock() + defer g.ctx.mutex.Unlock() + + g.errptr = errptr + return g +} + +func (g *markerg) End() { + if g.ctx == nil { + return + } + + g.indentg.End() // unindent + buf := &bytes.Buffer{} + g.ctx.preamble(buf) + fmt.Fprint(buf, "END ") + fmt.Fprintf(buf, g.f, g.args...) + fmt.Fprintf(buf, " (%s)", time.Since(g.start)) + if errptr := g.errptr; errptr != nil && *errptr != nil { + fmt.Fprintf(buf, ": ERROR: %s", *errptr) + } + + if buf.Len() > 0 { + if b := buf.Bytes(); b[buf.Len()-1] != '\n' { + buf.WriteRune('\n') + } + } + + buf.WriteTo(g.ctx.Writer) +} + +type legacyg struct { + guard + start time.Time +} + +var emptylegacyg = legacyg{} + +func (g legacyg) IRelease(f string, args ...interface{}) { + if !Trace { + return + } + g.End() + dur := time.Since(g.start) + Printf("%s (%s)", fmt.Sprintf(f, args...), dur) +} + +// IPrintf indents and then prints debug messages. Execute the callback +// to undo the indent +func IPrintf(f string, args ...interface{}) legacyg { + if !Trace { + return emptylegacyg + } + + DefaultCtx.Printf(f, args...) + g := legacyg{ + guard: DefaultCtx.Indent(), + start: time.Now(), + } + return g +} + +// Printf prints debug messages. Only available if compiled with "debug" tag +func Printf(f string, args ...interface{}) { + if !Trace { + return + } + DefaultCtx.Printf(f, args...) +} + +func Dump(v ...interface{}) { + if !Trace { + return + } + spew.Dump(v...) +} diff --git a/vendor/github.com/lestrrat-go/pdebug/debug_test.go b/vendor/github.com/lestrrat-go/pdebug/debug_test.go new file mode 100644 index 000000000000..7e1077ee7596 --- /dev/null +++ b/vendor/github.com/lestrrat-go/pdebug/debug_test.go @@ -0,0 +1,30 @@ +//+build debug,!debug0 + +package pdebug + +import ( + "os" + "strconv" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestDebugEnabled(t *testing.T) { + if !assert.True(t, Enabled, "Enable is true") { + return + } + + b, err := strconv.ParseBool(os.Getenv("PDEBUG_TRACE")) + if err == nil && b { + if !assert.True(t, Trace, "Trace is true") { + return + } + t.Logf("Trace is enabled") + } else { + if !assert.False(t, Trace, "Trace is false") { + return + } + t.Logf("Trace is disabled") + } +} \ No newline at end of file diff --git a/vendor/github.com/lestrrat-go/pdebug/doc.go b/vendor/github.com/lestrrat-go/pdebug/doc.go new file mode 100644 index 000000000000..d0566de384ab --- /dev/null +++ b/vendor/github.com/lestrrat-go/pdebug/doc.go @@ -0,0 +1,15 @@ +// Package pdebug provides tools to produce debug logs the way the author +// (Daisuke Maki a.k.a. lestrrat) likes. All of the functions are no-ops +// unless you compile with the `-tags debug` option. +// +// When you compile your program with `-tags debug`, no trace is displayed, +// but the code enclosed within `if pdebug.Enabled { ... }` is compiled in. +// To show the debug trace, set the PDEBUG_TRACE environment variable to +// true (or 1, or whatever `strconv.ParseBool` parses to true) +// +// If you want to show the debug trace regardless of an environment variable, +// for example, perhaps while you are debugging or running tests, use the +// `-tags debug0` build tag instead. This will enable the debug trace +// forcefully +package pdebug + diff --git a/vendor/github.com/lestrrat-go/pdebug/nodebug_test.go b/vendor/github.com/lestrrat-go/pdebug/nodebug_test.go new file mode 100644 index 000000000000..ae09c76fa85c --- /dev/null +++ b/vendor/github.com/lestrrat-go/pdebug/nodebug_test.go @@ -0,0 +1,14 @@ +//+build !debug,!debug0 + +package pdebug + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestDisabled(t *testing.T) { + assert.False(t, Enabled, "Enable is false") + assert.False(t, Trace, "Trace is false") +} \ No newline at end of file diff --git a/vendor/github.com/lestrrat-go/structinfo/.gitignore b/vendor/github.com/lestrrat-go/structinfo/.gitignore new file mode 100644 index 000000000000..daf913b1b347 --- /dev/null +++ b/vendor/github.com/lestrrat-go/structinfo/.gitignore @@ -0,0 +1,24 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test +*.prof diff --git a/vendor/github.com/lestrrat-go/structinfo/.travis.yml b/vendor/github.com/lestrrat-go/structinfo/.travis.yml new file mode 100644 index 000000000000..5b800297f00e --- /dev/null +++ b/vendor/github.com/lestrrat-go/structinfo/.travis.yml @@ -0,0 +1,5 @@ +language: go +sudo: false +go: + - 1.5 + - tip diff --git a/vendor/github.com/lestrrat-go/structinfo/LICENSE b/vendor/github.com/lestrrat-go/structinfo/LICENSE new file mode 100644 index 000000000000..20054b15434d --- /dev/null +++ b/vendor/github.com/lestrrat-go/structinfo/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 lestrrat + +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/lestrrat-go/structinfo/README.md b/vendor/github.com/lestrrat-go/structinfo/README.md new file mode 100644 index 000000000000..fbf6c877d683 --- /dev/null +++ b/vendor/github.com/lestrrat-go/structinfo/README.md @@ -0,0 +1,7 @@ +# structinfo + +[![Build Status](https://travis-ci.org/lestrrat-go/structinfo.svg?branch=master)](https://travis-ci.org/lestrrat-go/structinfo) + +[![GoDoc](https://godoc.org/github.com/lestrrat-go/structinfo?status.svg)](https://godoc.org/github.com/lestrrat-go/structinfo) + +Tools to inspect Go structs diff --git a/vendor/github.com/lestrrat-go/structinfo/structinfo.go b/vendor/github.com/lestrrat-go/structinfo/structinfo.go new file mode 100644 index 000000000000..0a283ca88897 --- /dev/null +++ b/vendor/github.com/lestrrat-go/structinfo/structinfo.go @@ -0,0 +1,118 @@ +// Package structinfo contains tools to inspect structs. + +package structinfo + +import ( + "reflect" + "sync" +) + +type jsonFieldMap struct { + lock sync.Mutex + fields map[string]string +} + +var type2jfm = map[reflect.Type]jsonFieldMap{} +var type2jfmMutex = sync.Mutex{} + +// JSONFieldsFromStruct returns the names of JSON fields associated +// with the given struct. Returns nil if v is not a struct +func JSONFieldsFromStruct(v reflect.Value) []string { + if v.Kind() != reflect.Struct { + return nil + } + + m := getType2jfm(v.Type()) + m.lock.Lock() + defer m.lock.Unlock() + + l := make([]string, 0, len(m.fields)) + for k := range m.fields { + l = append(l, k) + } + return l +} + +// StructFieldFromJSONName returns the struct field name on the +// given struct value. Empty value means the field is either not +// public, or does not exist. +// +// This can be used to map JSON field names to actual struct fields. +func StructFieldFromJSONName(v reflect.Value, name string) string { + if v.Kind() != reflect.Struct { + return "" + } + + m := getType2jfm(v.Type()) + m.lock.Lock() + defer m.lock.Unlock() + + s, ok := m.fields[name] + if !ok { + return "" + } + return s +} + +func getType2jfm(t reflect.Type) jsonFieldMap { + type2jfmMutex.Lock() + defer type2jfmMutex.Unlock() + + return getType2jfm_nolock(t) +} + +func getType2jfm_nolock(t reflect.Type) jsonFieldMap { + fm, ok := type2jfm[t] + if ok { + return fm + } + + fm = constructJfm(t) + type2jfm[t] = fm + return fm +} + +func constructJfm(t reflect.Type) jsonFieldMap { + if t.Kind() == reflect.Ptr { + t = t.Elem() + } + + fm := jsonFieldMap{ + fields: make(map[string]string), + } + for i := 0; i < t.NumField(); i++ { + sf := t.Field(i) + if sf.Anonymous { // embedded! got to recurse + fm2 := getType2jfm_nolock(sf.Type) + for k, v := range fm2.fields { + fm.fields[k] = v + } + continue + } + + if sf.PkgPath != "" { // unexported + continue + } + + tag := sf.Tag.Get("json") + if tag == "-" { + continue + } + + if tag == "" || tag[0] == ',' { + fm.fields[sf.Name] = sf.Name + continue + } + + flen := 0 + for j := 0; j < len(tag); j++ { + if tag[j] == ',' { + break + } + flen = j + } + fm.fields[tag[:flen+1]] = sf.Name + } + + return fm +} \ No newline at end of file diff --git a/vendor/github.com/lestrrat-go/structinfo/structinfo_test.go b/vendor/github.com/lestrrat-go/structinfo/structinfo_test.go new file mode 100644 index 000000000000..980c2654b7c3 --- /dev/null +++ b/vendor/github.com/lestrrat-go/structinfo/structinfo_test.go @@ -0,0 +1,63 @@ +package structinfo_test + +import ( + "reflect" + "testing" + + "github.com/lestrrat-go/structinfo" + "github.com/stretchr/testify/assert" +) + +type Quux struct { + Baz string `json:"baz"` +} + +type X struct { + private int + Quux + Foo string `json:"foo"` + Bar string `json:"bar,omitempty"` +} + +func TestStructFields(t *testing.T) { + fields := make(map[string]struct{}) + for _, name := range structinfo.JSONFieldsFromStruct(reflect.ValueOf(X{})) { + fields[name] = struct{}{} + } + + expected := map[string]struct{}{ + "foo": {}, + "bar": {}, + "baz": {}, + } + + if !assert.Equal(t, expected, fields, "expected fields match") { + return + } +} + +func TestLookupSructFieldFromJSONName(t *testing.T) { + rv := reflect.ValueOf(X{}) + + data := map[string]string{ + "foo": "Foo", + "bar": "Bar", + "baz": "Baz", + } + + for jsname, fname := range data { + fn := structinfo.StructFieldFromJSONName(rv, jsname) + if !assert.NotEqual(t, fn, "", "should find '%s'", jsname) { + return + } + + sf, ok := rv.Type().FieldByName(fn) + if !assert.True(t, ok, "should be able resolve '%s' (%s)", jsname, fn) { + return + } + + if !assert.Equal(t, sf.Name, fname, "'%s' should map to '%s'", jsname, fname) { + return + } + } +} diff --git a/vendor/github.com/lestrrat/go-jspointer/.travis.yml b/vendor/github.com/lestrrat/go-jspointer/.travis.yml index 5b800297f00e..21e0a8e8d7c0 100644 --- a/vendor/github.com/lestrrat/go-jspointer/.travis.yml +++ b/vendor/github.com/lestrrat/go-jspointer/.travis.yml @@ -1,5 +1,5 @@ language: go sudo: false go: - - 1.5 + - 1.11 - tip diff --git a/vendor/github.com/lestrrat/go-jspointer/README.md b/vendor/github.com/lestrrat/go-jspointer/README.md index 8bce21bcaff3..e1a4fbcd01b0 100644 --- a/vendor/github.com/lestrrat/go-jspointer/README.md +++ b/vendor/github.com/lestrrat/go-jspointer/README.md @@ -1,8 +1,8 @@ # go-jspointer -[![Build Status](https://travis-ci.org/lestrrat/go-jspointer.svg?branch=master)](https://travis-ci.org/lestrrat/go-jspointer) +[![Build Status](https://travis-ci.org/lestrrat-go/jspointer.svg?branch=master)](https://travis-ci.org/lestrrat-go/jspointer) -[![GoDoc](https://godoc.org/github.com/lestrrat/go-jspointer?status.svg)](https://godoc.org/github.com/lestrrat/go-jspointer) +[![GoDoc](https://godoc.org/github.com/lestrrat-go/jspointer?status.svg)](https://godoc.org/github.com/lestrrat-go/jspointer) JSON pointer for Go @@ -26,9 +26,9 @@ This is almost a fork of https://github.com/xeipuuv/gojsonpointer. | Name | Notes | |:--------------------------------------------------------:|:---------------------------------| -| [go-jsval](https://github.com/lestrrat/go-jsval) | Validator generator | -| [go-jsschema](https://github.com/lestrrat/go-jsschema) | JSON Schema implementation | -| [go-jshschema](https://github.com/lestrrat/go-jshschema) | JSON Hyper Schema implementation | -| [go-jsref](https://github.com/lestrrat/go-jsref) | JSON Reference implementation | +| [go-jsval](https://github.com/lestrrat-go/jsval) | Validator generator | +| [go-jsschema](https://github.com/lestrrat-go/jsschema) | JSON Schema implementation | +| [go-jshschema](https://github.com/lestrrat-go/jshschema) | JSON Hyper Schema implementation | +| [go-jsref](https://github.com/lestrrat-go/jsref) | JSON Reference implementation | diff --git a/vendor/github.com/lestrrat/go-jspointer/bench/bench_test.go b/vendor/github.com/lestrrat/go-jspointer/bench/bench_test.go index c0350b280b93..3ffe29fb4ded 100644 --- a/vendor/github.com/lestrrat/go-jspointer/bench/bench_test.go +++ b/vendor/github.com/lestrrat/go-jspointer/bench/bench_test.go @@ -6,7 +6,7 @@ import ( "encoding/json" "testing" - "github.com/lestrrat/go-jspointer" + "github.com/lestrrat-go/jspointer" "github.com/xeipuuv/gojsonpointer" ) diff --git a/vendor/github.com/lestrrat/go-jspointer/interface.go b/vendor/github.com/lestrrat/go-jspointer/interface.go index 1e83d599556e..7fe800233bb2 100644 --- a/vendor/github.com/lestrrat/go-jspointer/interface.go +++ b/vendor/github.com/lestrrat/go-jspointer/interface.go @@ -23,5 +23,5 @@ type ErrNotFound struct { // JSPointer represents a JSON pointer type JSPointer struct { raw string - tokens []string + tokens tokens } diff --git a/vendor/github.com/lestrrat/go-jspointer/jspointer.go b/vendor/github.com/lestrrat/go-jspointer/jspointer.go index 1c1f88fd2a53..c42b9613f9a3 100644 --- a/vendor/github.com/lestrrat/go-jspointer/jspointer.go +++ b/vendor/github.com/lestrrat/go-jspointer/jspointer.go @@ -1,79 +1,96 @@ package jspointer import ( + "bytes" "encoding/json" "errors" "reflect" "strconv" - "strings" - "sync" - "github.com/lestrrat/go-structinfo" + "github.com/lestrrat-go/structinfo" ) -var ctxPool = sync.Pool{ - New: moreCtx, +type tokens struct { + s string + positions [][2]int } -func moreCtx() interface{} { - return &matchCtx{} +func (t *tokens) size() int { + return len(t.positions) } -func getCtx() *matchCtx { - return ctxPool.Get().(*matchCtx) -} - -func releaseCtx(ctx *matchCtx) { - ctx.err = nil - ctx.set = false - ctx.tokens = nil - ctx.result = nil - ctxPool.Put(ctx) +func (t *tokens) get(i int) string { + p := t.positions[i] + return t.s[p[0]:p[1]] } // New creates a new JSON pointer for given path spec. If the path fails // to be parsed, an error is returned func New(path string) (*JSPointer, error) { var p JSPointer - dtokens, err := parse(path) - if err != nil { + + if err := p.parse(path); err != nil { return nil, err } p.raw = path - p.tokens = dtokens return &p, nil } -func parse(s string) ([]string, error) { +func (p *JSPointer) parse(s string) error { if s == "" { - return nil, nil + return nil } if s[0] != Separator { - return nil, ErrInvalidPointer + return ErrInvalidPointer } - prev := 0 - tokens := []string{} + if len(s) < 2 { + return ErrInvalidPointer + } + + ntokens := 0 + for i := 0; i < len(s); i++ { + if s[i] == '/' { + ntokens++ + } + } + + positions := make([][2]int, 0, ntokens) + start := 1 + var buf bytes.Buffer + buf.WriteByte(s[0]) for i := 1; i < len(s); i++ { switch s[i] { case Separator: - tokens = append(tokens, s[prev+1:i]) - prev = i + buf.WriteByte(s[i]) + positions = append(positions, [2]int{start, buf.Len() - 1}) + start = i + 1 + case '~': + if len(s) == 1 { + buf.WriteByte(s[i]) + } else { + switch s[1] { + case '0': + buf.WriteByte('~') + case '1': + buf.WriteByte('/') + default: + buf.WriteByte(s[i]) + } + } + default: + buf.WriteByte(s[i]) } } - if prev != len(s) { - tokens = append(tokens, s[prev+1:]) - } - - dtokens := make([]string, 0, len(tokens)) - for _, t := range tokens { - t = strings.Replace(strings.Replace(t, EncodedSlash, "/", -1), EncodedTilde, "~", -1) - dtokens = append(dtokens, t) + if start < buf.Len() { + positions = append(positions, [2]int{start, buf.Len()}) } - return dtokens, nil + p.tokens.s = buf.String() + p.tokens.positions = positions + return nil } // String returns the stringified version of this JSON pointer @@ -84,11 +101,10 @@ func (p JSPointer) String() string { // Get applies the JSON pointer to the given item, and returns // the result. func (p JSPointer) Get(item interface{}) (interface{}, error) { - ctx := getCtx() - defer releaseCtx(ctx) + var ctx matchCtx ctx.raw = p.raw - ctx.tokens = p.tokens + ctx.tokens = &p.tokens ctx.apply(item) return ctx.result, ctx.err } @@ -96,12 +112,11 @@ func (p JSPointer) Get(item interface{}) (interface{}, error) { // Set applies the JSON pointer to the given item, and sets the // value accordingly. func (p JSPointer) Set(item interface{}, value interface{}) error { - ctx := getCtx() - defer releaseCtx(ctx) + var ctx matchCtx ctx.set = true ctx.raw = p.raw - ctx.tokens = p.tokens + ctx.tokens = &p.tokens ctx.setvalue = value ctx.apply(item) return ctx.err @@ -113,25 +128,48 @@ type matchCtx struct { result interface{} set bool setvalue interface{} - tokens []string + tokens *tokens } func (e ErrNotFound) Error() string { return "match to JSON pointer not found: " + e.Ptr } +type JSONGetter interface { + JSONGet(tok string) (interface{}, error) +} + var strType = reflect.TypeOf("") +var zeroval reflect.Value func (c *matchCtx) apply(item interface{}) { - if len(c.tokens) == 0 { + if c.tokens.size() == 0 { c.result = item return } - lastidx := len(c.tokens) - 1 node := item - for tidx, token := range c.tokens { + lastidx := c.tokens.size() - 1 + for i := 0; i < c.tokens.size(); i++ { + token := c.tokens.get(i) + + if getter, ok := node.(JSONGetter); ok { + x, err := getter.JSONGet(token) + if err != nil { + c.err = ErrNotFound{Ptr: c.raw} + return + } + if i == lastidx { + c.result = x + return + } + node = x + continue + } v := reflect.ValueOf(node) + + // Does this thing implement a JSONGet? + if v.Kind() == reflect.Ptr { v = v.Elem() } @@ -144,7 +182,7 @@ func (c *matchCtx) apply(item interface{}) { return } f := v.FieldByName(fn) - if tidx == lastidx { + if i == lastidx { if c.set { if !f.CanSet() { c.err = ErrCanNotSet @@ -176,12 +214,12 @@ func (c *matchCtx) apply(item interface{}) { vt = reflect.ValueOf(token) } n := v.MapIndex(vt) - if (reflect.Value{}) == n { + if zeroval == n { c.err = ErrNotFound{Ptr: c.raw} return } - if tidx == lastidx { + if i == lastidx { if c.set { v.SetMapIndex(vt, reflect.ValueOf(c.setvalue)) } else { @@ -204,7 +242,7 @@ func (c *matchCtx) apply(item interface{}) { return } - if tidx == lastidx { + if i == lastidx { if c.set { m[wantidx] = c.setvalue } else { diff --git a/vendor/github.com/lestrrat/go-jspointer/jspointer_test.go b/vendor/github.com/lestrrat/go-jspointer/jspointer_test.go index 388c76261ee6..50ba8e610d29 100644 --- a/vendor/github.com/lestrrat/go-jspointer/jspointer_test.go +++ b/vendor/github.com/lestrrat/go-jspointer/jspointer_test.go @@ -4,7 +4,7 @@ import ( "encoding/json" "testing" - "github.com/lestrrat/go-jspointer" + "github.com/lestrrat-go/jspointer" "github.com/stretchr/testify/assert" ) diff --git a/vendor/github.com/lestrrat/go-jsschema/.travis.yml b/vendor/github.com/lestrrat/go-jsschema/.travis.yml index ad9a6993d127..a20c62692f00 100644 --- a/vendor/github.com/lestrrat/go-jsschema/.travis.yml +++ b/vendor/github.com/lestrrat/go-jsschema/.travis.yml @@ -1,7 +1,7 @@ language: go sudo: false go: - - 1.7 + - 1.11.x - tip script: - go test -v ./... diff --git a/vendor/github.com/lestrrat/go-jsschema/README.md b/vendor/github.com/lestrrat/go-jsschema/README.md index c3f78a31e776..79031957e1dd 100644 --- a/vendor/github.com/lestrrat/go-jsschema/README.md +++ b/vendor/github.com/lestrrat/go-jsschema/README.md @@ -1,8 +1,8 @@ # go-jsschema -[![Build Status](https://travis-ci.org/lestrrat/go-jsschema.svg?branch=master)](https://travis-ci.org/lestrrat/go-jsschema) +[![Build Status](https://travis-ci.org/lestrrat-go/jsschema.svg?branch=master)](https://travis-ci.org/lestrrat-go/jsschema) -[![GoDoc](https://godoc.org/github.com/lestrrat/go-jsschema?status.svg)](https://godoc.org/github.com/lestrrat/go-jsschema) +[![GoDoc](https://godoc.org/github.com/lestrrat-go/jsschema?status.svg)](https://godoc.org/github.com/lestrrat-go/jsschema) JSON Schema for Go @@ -14,8 +14,8 @@ package schema_test import ( "log" - "github.com/lestrrat/go-jsschema" - "github.com/lestrrat/go-jsschema/validator" + "github.com/lestrrat-go/jsschema" + "github.com/lestrrat-go/jsschema/validator" ) func Example() { @@ -47,13 +47,13 @@ This packages parses a JSON Schema file, and allows you to inspect, modify the schema, but does nothing more. If you want to validate using the JSON Schema that you read using this package, -look at [go-jsval](https://github.com/lestrrat/go-jsval), which allows you to +look at [go-jsval](https://github.com/lestrrat-go/jsval), which allows you to generate validators, so that you don't have to dynamically read in the JSON schema for each instance of your program. In the same lines, this package does not really care about loading external schemas from various locations (it's just easier to just gather all the schemas -in your local system). It *is* possible to do this via [go-jsref](https://github.com/lestrrat/go-jsref) +in your local system). It *is* possible to do this via [go-jsref](https://github.com/lestrrat-go/jsref) if you really want to do it. # BENCHMARKS @@ -86,7 +86,7 @@ PASS | Name | Notes | |:--------------------------------------------------------:|:---------------------------------| -| [go-jsval](https://github.com/lestrrat/go-jsval) | Validator generator | -| [go-jshschema](https://github.com/lestrrat/go-jshschema) | JSON Hyper Schema implementation | -| [go-jsref](https://github.com/lestrrat/go-jsref) | JSON Reference implementation | -| [go-jspointer](https://github.com/lestrrat/go-jspointer) | JSON Pointer implementations | +| [go-jsval](https://github.com/lestrrat-go/jsval) | Validator generator | +| [go-jshschema](https://github.com/lestrrat-go/jshschema) | JSON Hyper Schema implementation | +| [go-jsref](https://github.com/lestrrat-go/jsref) | JSON Reference implementation | +| [go-jspointer](https://github.com/lestrrat-go/jspointer) | JSON Pointer implementations | diff --git a/vendor/github.com/lestrrat/go-jsschema/benchmark_test.go b/vendor/github.com/lestrrat/go-jsschema/benchmark_test.go index a774668f870a..df973b226d86 100644 --- a/vendor/github.com/lestrrat/go-jsschema/benchmark_test.go +++ b/vendor/github.com/lestrrat/go-jsschema/benchmark_test.go @@ -6,8 +6,8 @@ import ( "strings" "testing" - schema "github.com/lestrrat/go-jsschema" - "github.com/lestrrat/go-jsschema/validator" + schema "github.com/lestrrat-go/jsschema" + "github.com/lestrrat-go/jsschema/validator" "github.com/xeipuuv/gojsonschema" ) diff --git a/vendor/github.com/lestrrat/go-jsschema/cmd/jsschema/jsschema.go b/vendor/github.com/lestrrat/go-jsschema/cmd/jsschema/jsschema.go index e31a94aa335c..d1e39f97388f 100644 --- a/vendor/github.com/lestrrat/go-jsschema/cmd/jsschema/jsschema.go +++ b/vendor/github.com/lestrrat/go-jsschema/cmd/jsschema/jsschema.go @@ -7,8 +7,8 @@ import ( "log" "os" - "github.com/lestrrat/go-jsschema" - "github.com/lestrrat/go-jsschema/validator" + "github.com/lestrrat-go/jsschema" + "github.com/lestrrat-go/jsschema/validator" ) func main() { diff --git a/vendor/github.com/lestrrat/go-jsschema/interface.go b/vendor/github.com/lestrrat/go-jsschema/interface.go index 416cfa7a7b09..d47412b31531 100644 --- a/vendor/github.com/lestrrat/go-jsschema/interface.go +++ b/vendor/github.com/lestrrat/go-jsschema/interface.go @@ -5,7 +5,7 @@ import ( "regexp" "sync" - "github.com/lestrrat/go-jsref" + "github.com/lestrrat-go/jsref" ) const ( diff --git a/vendor/github.com/lestrrat/go-jsschema/marshal.go b/vendor/github.com/lestrrat/go-jsschema/marshal.go index b08bc1c7d618..7a409cfb58e1 100644 --- a/vendor/github.com/lestrrat/go-jsschema/marshal.go +++ b/vendor/github.com/lestrrat/go-jsschema/marshal.go @@ -5,7 +5,7 @@ import ( "regexp" "strconv" - "github.com/lestrrat/go-pdebug" + "github.com/lestrrat-go/pdebug" "github.com/pkg/errors" ) diff --git a/vendor/github.com/lestrrat/go-jsschema/marshal_test.go b/vendor/github.com/lestrrat/go-jsschema/marshal_test.go index fc811d131711..584928bfed30 100644 --- a/vendor/github.com/lestrrat/go-jsschema/marshal_test.go +++ b/vendor/github.com/lestrrat/go-jsschema/marshal_test.go @@ -5,8 +5,8 @@ import ( "strings" "testing" - "github.com/lestrrat/go-jsschema" - "github.com/lestrrat/go-jsschema/validator" + "github.com/lestrrat-go/jsschema" + "github.com/lestrrat-go/jsschema/validator" "github.com/stretchr/testify/assert" ) diff --git a/vendor/github.com/lestrrat/go-jsschema/schema.go b/vendor/github.com/lestrrat/go-jsschema/schema.go index 8d2b2f9f7f37..706ed7091292 100644 --- a/vendor/github.com/lestrrat/go-jsschema/schema.go +++ b/vendor/github.com/lestrrat/go-jsschema/schema.go @@ -8,9 +8,9 @@ import ( "reflect" "strconv" - "github.com/lestrrat/go-jsref" - "github.com/lestrrat/go-jsref/provider" - "github.com/lestrrat/go-pdebug" + "github.com/lestrrat-go/jsref" + "github.com/lestrrat-go/jsref/provider" + "github.com/lestrrat-go/pdebug" "github.com/pkg/errors" ) diff --git a/vendor/github.com/lestrrat/go-jsschema/schema_example_test.go b/vendor/github.com/lestrrat/go-jsschema/schema_example_test.go index 9f69f228035a..cd1dab975a18 100644 --- a/vendor/github.com/lestrrat/go-jsschema/schema_example_test.go +++ b/vendor/github.com/lestrrat/go-jsschema/schema_example_test.go @@ -3,8 +3,8 @@ package schema_test import ( "log" - "github.com/lestrrat/go-jsschema" - "github.com/lestrrat/go-jsschema/validator" + "github.com/lestrrat-go/jsschema" + "github.com/lestrrat-go/jsschema/validator" ) func Example() { diff --git a/vendor/github.com/lestrrat/go-jsschema/schema_test.go b/vendor/github.com/lestrrat/go-jsschema/schema_test.go index 8c55f728f739..499e8d11b26d 100644 --- a/vendor/github.com/lestrrat/go-jsschema/schema_test.go +++ b/vendor/github.com/lestrrat/go-jsschema/schema_test.go @@ -8,8 +8,8 @@ import ( "strings" "testing" - "github.com/lestrrat/go-jsschema" - "github.com/lestrrat/go-jsschema/validator" + "github.com/lestrrat-go/jsschema" + "github.com/lestrrat-go/jsschema/validator" "github.com/stretchr/testify/assert" ) diff --git a/vendor/github.com/lestrrat/go-jsschema/validator/validator.go b/vendor/github.com/lestrrat/go-jsschema/validator/validator.go index b1930617733d..365f01427593 100644 --- a/vendor/github.com/lestrrat/go-jsschema/validator/validator.go +++ b/vendor/github.com/lestrrat/go-jsschema/validator/validator.go @@ -3,9 +3,9 @@ package validator import ( "sync" - "github.com/lestrrat/go-jsschema" - "github.com/lestrrat/go-jsval" - "github.com/lestrrat/go-jsval/builder" + "github.com/lestrrat-go/jsschema" + "github.com/lestrrat-go/jsval" + "github.com/lestrrat-go/jsval/builder" "github.com/pkg/errors" ) diff --git a/vendor/github.com/openshift/api/config/v1/register.go b/vendor/github.com/openshift/api/config/v1/register.go index 66c342569aa2..35eace3701c2 100644 --- a/vendor/github.com/openshift/api/config/v1/register.go +++ b/vendor/github.com/openshift/api/config/v1/register.go @@ -56,6 +56,8 @@ func addKnownTypes(scheme *runtime.Scheme) error { &NetworkList{}, &OAuth{}, &OAuthList{}, + &OperatorHub{}, + &OperatorHubList{}, &Project{}, &ProjectList{}, &Proxy{}, diff --git a/vendor/github.com/openshift/api/config/v1/types_operatorhub.go b/vendor/github.com/openshift/api/config/v1/types_operatorhub.go new file mode 100644 index 000000000000..cf821f9e376a --- /dev/null +++ b/vendor/github.com/openshift/api/config/v1/types_operatorhub.go @@ -0,0 +1,69 @@ +package v1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// OperatorHubSpec defines the desired state of OperatorHub +type OperatorHubSpec struct { + // sources is the list of default hub sources and their configuration. + // If the list is empty, it indicates that the default hub sources are + // enabled on the cluster. The list of default hub sources and their + // current state will always be reflected in the status block. + // +optional + Sources []HubSource `json:"sources,omitempty"` +} + +// OperatorHubStatus defines the observed state of OperatorHub. The current +// state of the default hub sources will always be reflected here. +type OperatorHubStatus struct { + // sources encapsulates the result of applying the configuration for each + // hub source + Sources []HubSourceStatus `json:"sources,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// OperatorHub is the Schema for the operatorhubs API. It can be used to change +// the state of the default hub sources for OperatorHub on the cluster from +// enabled to disabled and vice versa. +// +kubebuilder:subresource:status +// +genclient:nonNamespaced +type OperatorHub struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata"` + + Spec OperatorHubSpec `json:"spec"` + Status OperatorHubStatus `json:"status"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// OperatorHubList contains a list of OperatorHub +type OperatorHubList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata"` + Items []OperatorHub `json:"items"` +} + +// HubSource is used to specify the hub source and its configuration +type HubSource struct { + // name is the name of one of the default hub sources + // +kubebuilder:validation:MaxLength=253 + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:Required + Name string `json:"name"` + // disabled is used to disable a default hub source on cluster + // +kubebuilder:Required + Disabled bool `json:"disabled"` +} + +// HubSourceStatus is used to reflect the current state of applying the +// configuration to a default source +type HubSourceStatus struct { + HubSource + // status indicates success or failure in applying the configuration + Status string `json:"status"` + // message provides more information regarding failures + Message string `json:"message,omitempty"` +} diff --git a/vendor/github.com/openshift/api/config/v1/types_proxy.go b/vendor/github.com/openshift/api/config/v1/types_proxy.go index 821ae89750ef..398470148292 100644 --- a/vendor/github.com/openshift/api/config/v1/types_proxy.go +++ b/vendor/github.com/openshift/api/config/v1/types_proxy.go @@ -46,14 +46,14 @@ type ProxySpec struct { // only be consumed by a proxy validator. The validator is responsible for reading // ConfigMapNameReference, validating the certificate and copying "ca-bundle.crt" // from data to a ConfigMap in the namespace of an operator configured for proxy. - // The namespace for this ConfigMap is "openshift-config-managed". Here is an example + // The namespace for this ConfigMap is "openshift-config". Here is an example // ConfigMap (in yaml): // // apiVersion: v1 // kind: ConfigMap // metadata: - // name: proxy-ca - // namespace: openshift-config-managed + // name: trusted-ca-bundle + // namespace: openshift-config // data: // ca-bundle.crt: | // -----BEGIN CERTIFICATE----- diff --git a/vendor/github.com/openshift/api/config/v1/types_scheduling.go b/vendor/github.com/openshift/api/config/v1/types_scheduling.go index 4a6bfba6fcbb..9b8fa3a52ac4 100644 --- a/vendor/github.com/openshift/api/config/v1/types_scheduling.go +++ b/vendor/github.com/openshift/api/config/v1/types_scheduling.go @@ -6,7 +6,8 @@ import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" // +genclient:nonNamespaced // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object -// Scheduler holds cluster-wide information about Scheduler. The canonical name is `cluster` +// Scheduler holds cluster-wide config information to run the Kubernetes Scheduler +// and influence its placement decisions. The canonical name for this config is `cluster`. type Scheduler struct { metav1.TypeMeta `json:",inline"` // Standard object's metadata. diff --git a/vendor/github.com/openshift/api/config/v1/zz_generated.deepcopy.go b/vendor/github.com/openshift/api/config/v1/zz_generated.deepcopy.go index 4fa507b16a01..3d44627f9c7f 100644 --- a/vendor/github.com/openshift/api/config/v1/zz_generated.deepcopy.go +++ b/vendor/github.com/openshift/api/config/v1/zz_generated.deepcopy.go @@ -1571,6 +1571,39 @@ func (in *HTTPServingInfo) DeepCopy() *HTTPServingInfo { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HubSource) DeepCopyInto(out *HubSource) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HubSource. +func (in *HubSource) DeepCopy() *HubSource { + if in == nil { + return nil + } + out := new(HubSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HubSourceStatus) DeepCopyInto(out *HubSourceStatus) { + *out = *in + out.HubSource = in.HubSource + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HubSourceStatus. +func (in *HubSourceStatus) DeepCopy() *HubSourceStatus { + if in == nil { + return nil + } + out := new(HubSourceStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *IdentityProvider) DeepCopyInto(out *IdentityProvider) { *out = *in @@ -2465,6 +2498,109 @@ func (in *OperandVersion) DeepCopy() *OperandVersion { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *OperatorHub) DeepCopyInto(out *OperatorHub) { + *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 OperatorHub. +func (in *OperatorHub) DeepCopy() *OperatorHub { + if in == nil { + return nil + } + out := new(OperatorHub) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *OperatorHub) 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 *OperatorHubList) DeepCopyInto(out *OperatorHubList) { + *out = *in + out.TypeMeta = in.TypeMeta + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]OperatorHub, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OperatorHubList. +func (in *OperatorHubList) DeepCopy() *OperatorHubList { + if in == nil { + return nil + } + out := new(OperatorHubList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *OperatorHubList) 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 *OperatorHubSpec) DeepCopyInto(out *OperatorHubSpec) { + *out = *in + if in.Sources != nil { + in, out := &in.Sources, &out.Sources + *out = make([]HubSource, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OperatorHubSpec. +func (in *OperatorHubSpec) DeepCopy() *OperatorHubSpec { + if in == nil { + return nil + } + out := new(OperatorHubSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *OperatorHubStatus) DeepCopyInto(out *OperatorHubStatus) { + *out = *in + if in.Sources != nil { + in, out := &in.Sources, &out.Sources + *out = make([]HubSourceStatus, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OperatorHubStatus. +func (in *OperatorHubStatus) DeepCopy() *OperatorHubStatus { + if in == nil { + return nil + } + out := new(OperatorHubStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *PlatformStatus) DeepCopyInto(out *PlatformStatus) { *out = *in diff --git a/vendor/github.com/openshift/api/config/v1/zz_generated.swagger_doc_generated.go b/vendor/github.com/openshift/api/config/v1/zz_generated.swagger_doc_generated.go index 3a5c9df37677..537fb82005e3 100644 --- a/vendor/github.com/openshift/api/config/v1/zz_generated.swagger_doc_generated.go +++ b/vendor/github.com/openshift/api/config/v1/zz_generated.swagger_doc_generated.go @@ -1146,6 +1146,60 @@ func (TokenConfig) SwaggerDoc() map[string]string { return map_TokenConfig } +var map_HubSource = map[string]string{ + "": "HubSource is used to specify the hub source and its configuration", + "name": "name is the name of one of the default hub sources", + "disabled": "disabled is used to disable a default hub source on cluster", +} + +func (HubSource) SwaggerDoc() map[string]string { + return map_HubSource +} + +var map_HubSourceStatus = map[string]string{ + "": "HubSourceStatus is used to reflect the current state of applying the configuration to a default source", + "status": "status indicates success or failure in applying the configuration", + "message": "message provides more information regarding failures", +} + +func (HubSourceStatus) SwaggerDoc() map[string]string { + return map_HubSourceStatus +} + +var map_OperatorHub = map[string]string{ + "": "OperatorHub is the Schema for the operatorhubs API. It can be used to change the state of the default hub sources for OperatorHub on the cluster from enabled to disabled and vice versa.", +} + +func (OperatorHub) SwaggerDoc() map[string]string { + return map_OperatorHub +} + +var map_OperatorHubList = map[string]string{ + "": "OperatorHubList contains a list of OperatorHub", +} + +func (OperatorHubList) SwaggerDoc() map[string]string { + return map_OperatorHubList +} + +var map_OperatorHubSpec = map[string]string{ + "": "OperatorHubSpec defines the desired state of OperatorHub", + "sources": "sources is the list of default hub sources and their configuration. If the list is empty, it indicates that the default hub sources are enabled on the cluster. The list of default hub sources and their current state will always be reflected in the status block.", +} + +func (OperatorHubSpec) SwaggerDoc() map[string]string { + return map_OperatorHubSpec +} + +var map_OperatorHubStatus = map[string]string{ + "": "OperatorHubStatus defines the observed state of OperatorHub. The current state of the default hub sources will always be reflected here.", + "sources": "sources encapsulates the result of applying the configuration for each hub source", +} + +func (OperatorHubStatus) SwaggerDoc() map[string]string { + return map_OperatorHubStatus +} + var map_Project = map[string]string{ "": "Project holds cluster-wide information about Project. The canonical name is `cluster`", "metadata": "Standard object's metadata.", @@ -1208,7 +1262,7 @@ var map_ProxySpec = map[string]string{ "httpsProxy": "httpsProxy is the URL of the proxy for HTTPS requests. Empty means unset and will not result in an env var.", "noProxy": "noProxy is a comma-separated list of hostnames and/or CIDRs for which the proxy should not be used. Empty means unset and will not result in an env var.", "readinessEndpoints": "readinessEndpoints is a list of endpoints used to verify readiness of the proxy.", - "trustedCA": "trustedCA is a reference to a ConfigMap containing a CA certificate bundle used for client egress HTTPS connections. The certificate bundle must be from the CA that signed the proxy's certificate and be signed for everything. trustedCA should only be consumed by a proxy validator. The validator is responsible for reading ConfigMapNameReference, validating the certificate and copying \"ca-bundle.crt\" from data to a ConfigMap in the namespace of an operator configured for proxy. The namespace for this ConfigMap is \"openshift-config-managed\". Here is an example ConfigMap (in yaml):\n\napiVersion: v1 kind: ConfigMap metadata:\n name: proxy-ca\n namespace: openshift-config-managed\n data:\n ca-bundle.crt: |", + "trustedCA": "trustedCA is a reference to a ConfigMap containing a CA certificate bundle used for client egress HTTPS connections. The certificate bundle must be from the CA that signed the proxy's certificate and be signed for everything. trustedCA should only be consumed by a proxy validator. The validator is responsible for reading ConfigMapNameReference, validating the certificate and copying \"ca-bundle.crt\" from data to a ConfigMap in the namespace of an operator configured for proxy. The namespace for this ConfigMap is \"openshift-config\". Here is an example ConfigMap (in yaml):\n\napiVersion: v1 kind: ConfigMap metadata:\n name: trusted-ca-bundle\n namespace: openshift-config\n data:\n ca-bundle.crt: |", } func (ProxySpec) SwaggerDoc() map[string]string { @@ -1227,7 +1281,7 @@ func (ProxyStatus) SwaggerDoc() map[string]string { } var map_Scheduler = map[string]string{ - "": "Scheduler holds cluster-wide information about Scheduler. The canonical name is `cluster`", + "": "Scheduler holds cluster-wide config information to run the Kubernetes Scheduler and influence its placement decisions. The canonical name for this config is `cluster`.", "metadata": "Standard object's metadata.", "spec": "spec holds user settable values for configuration", "status": "status holds observed values from the cluster. They may not be overridden.", diff --git a/vendor/github.com/openshift/apiserver-library-go/Makefile b/vendor/github.com/openshift/apiserver-library-go/Makefile index 541d2017f626..e6dd92cf4eec 100644 --- a/vendor/github.com/openshift/apiserver-library-go/Makefile +++ b/vendor/github.com/openshift/apiserver-library-go/Makefile @@ -12,3 +12,17 @@ clean: GO_TEST_PACKAGES :=./pkg/... + +update: update-generated-deep-copies +.PHONY: update + +verify: verify-generated-deep-copies +.PHONY: verify + +update-generated-deep-copies: + hack/update-generated-deep-copies.sh +.PHONY: update-generated-deep-copies + +verify-generated-deep-copies: + hack/verify-generated-deep-copies.sh +.PHONY: verify-generated-deep-copies diff --git a/vendor/github.com/openshift/apiserver-library-go/OWNERS b/vendor/github.com/openshift/apiserver-library-go/OWNERS new file mode 100644 index 000000000000..9897c9fb0b0e --- /dev/null +++ b/vendor/github.com/openshift/apiserver-library-go/OWNERS @@ -0,0 +1,10 @@ +reviewers: + - deads2k + - sttts + - mfojtik + - soltysh + - tnozicka +approvers: + - deads2k + - sttts + - mfojtik diff --git a/vendor/github.com/openshift/apiserver-library-go/glide.lock b/vendor/github.com/openshift/apiserver-library-go/glide.lock index b9a552d74a6b..f268f0034d3f 100644 --- a/vendor/github.com/openshift/apiserver-library-go/glide.lock +++ b/vendor/github.com/openshift/apiserver-library-go/glide.lock @@ -1,5 +1,5 @@ -hash: 28528b597c719cef00c25ae3ffcd8d1e3b51a6a91bafa0e1453ecff6151de036 -updated: 2019-07-30T08:42:49.496985972-04:00 +hash: c44fe7d003c2234edfa3750e8fc1d8d2d5e983bc2a9ec44d518b0cb9c7282de3 +updated: 2019-07-31T09:05:49.223875358-04:00 imports: - name: github.com/beorn7/perks version: 3ac7bf7a47d159a033b107610db8a1b6575507a4 @@ -165,7 +165,7 @@ imports: - name: github.com/opencontainers/go-digest version: a6d0ee40d4207ea02364bd3b9e8e77b9159ba1eb - name: github.com/openshift/api - version: a33d022e090746dfe27a1dc417c6b84cc640800f + version: 0922aa5a655be314e20a3e0e94f4f2b105100154 subpackages: - config/v1 - image @@ -199,7 +199,7 @@ imports: - security/informers/externalversions/security/v1 - security/listers/security/v1 - name: github.com/openshift/library-go - version: 06fca5b7f9cc44922a00a9850755a79e3060213e + version: 9fac0f4cee906d25073d044cb600b00e6bfca8b1 subpackages: - pkg/apiserver/admission/admissionrestconfig - pkg/authorization/scopemetadata @@ -292,6 +292,10 @@ imports: version: f51c12702a4d776e4c1fa9b0fabab841babae631 subpackages: - rate +- name: golang.org/x/tools + version: 2382e3994d48b1d22acc2c86bcad0a2aff028e32 + subpackages: + - imports - name: google.golang.org/appengine version: 12d5545dc1cfa6047a286d5e853841b6471f4c19 subpackages: @@ -718,12 +722,16 @@ imports: version: c892ea32361a3655e7bd8c06f2d02dd8ce73dd78 subpackages: - features +- name: k8s.io/code-generator + version: 50b561225d70b3eb79a1faafd3dfe7b1a62cbe73 - name: k8s.io/component-base version: 4a91899592f42b2f5859587cc5a676a5b94d2ee3 subpackages: - logs +- name: k8s.io/gengo + version: 51747d6e00da1fc578d5a333a93bb2abcbce7a95 - name: k8s.io/klog - version: 8e90cee79f823779174776412c13478955131846 + version: 8139d8cb77af419532b33dfa7dd09fbc5f1d344f - name: k8s.io/kube-openapi version: b3a7cee44a305be0a69e1b9ac03018307287e1b0 subpackages: diff --git a/vendor/github.com/openshift/apiserver-library-go/glide.yaml b/vendor/github.com/openshift/apiserver-library-go/glide.yaml index fc60317d6d71..87f3ad77182d 100644 --- a/vendor/github.com/openshift/apiserver-library-go/glide.yaml +++ b/vendor/github.com/openshift/apiserver-library-go/glide.yaml @@ -14,6 +14,17 @@ import: - package: k8s.io/kubernetes version: v1.14.0 +# code generator +- package: k8s.io/code-generator + version: kubernetes-1.14.0 +- package: k8s.io/gengo + version: 51747d6e00da1fc578d5a333a93bb2abcbce7a95 +# for gengo +- package: golang.org/x/tools/imports + version: 2382e3994d48b1d22acc2c86bcad0a2aff028e32 + + + # openshift second - package: github.com/openshift/api version: master diff --git a/vendor/github.com/openshift/apiserver-library-go/hack/boilerplate.txt b/vendor/github.com/openshift/apiserver-library-go/hack/boilerplate.txt new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/vendor/github.com/openshift/apiserver-library-go/hack/lib/init.sh b/vendor/github.com/openshift/apiserver-library-go/hack/lib/init.sh new file mode 100644 index 000000000000..d56db7958e3f --- /dev/null +++ b/vendor/github.com/openshift/apiserver-library-go/hack/lib/init.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +# This script is meant to be the entrypoint for OpenShift Bash scripts to import all of the support +# libraries at once in order to make Bash script preambles as minimal as possible. This script recur- +# sively `source`s *.sh files in this directory tree. As such, no files should be `source`ed outside +# of this script to ensure that we do not attempt to overwrite read-only variables. + +set -o errexit +set -o nounset +set -o pipefail diff --git a/vendor/github.com/openshift/apiserver-library-go/hack/update-generated-deep-copies.sh b/vendor/github.com/openshift/apiserver-library-go/hack/update-generated-deep-copies.sh new file mode 100755 index 000000000000..8d677cf35f6c --- /dev/null +++ b/vendor/github.com/openshift/apiserver-library-go/hack/update-generated-deep-copies.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +source "$(dirname "${BASH_SOURCE}")/lib/init.sh" + +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)} + +verify="${VERIFY:-}" + +go install ./${CODEGEN_PKG}/cmd/deepcopy-gen + +function codegen::join() { local IFS="$1"; shift; echo "$*"; } + +# enumerate group versions +ALL_FQ_APIS=( + github.com/openshift/apiserver-library-go/pkg/admission/imagepolicy/apis/imagepolicy/v1 +) + +echo "Generating deepcopy funcs" +${GOPATH}/bin/deepcopy-gen --input-dirs $(codegen::join , "${ALL_FQ_APIS[@]}") -O zz_generated.deepcopy --bounding-dirs $(codegen::join , "${ALL_FQ_APIS[@]}") --go-header-file ${SCRIPT_ROOT}/hack/boilerplate.txt ${verify} "$@" diff --git a/vendor/github.com/openshift/apiserver-library-go/hack/verify-generated-deep-copies.sh b/vendor/github.com/openshift/apiserver-library-go/hack/verify-generated-deep-copies.sh new file mode 100755 index 000000000000..7468ad78460a --- /dev/null +++ b/vendor/github.com/openshift/apiserver-library-go/hack/verify-generated-deep-copies.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +source "$(dirname "${BASH_SOURCE}")/lib/init.sh" + +SCRIPT_ROOT=$(dirname ${BASH_SOURCE})/.. +VERIFY=--verify-only ${SCRIPT_ROOT}/hack/update-generated-deep-copies.sh diff --git a/vendor/github.com/openshift/client-go/glide.lock b/vendor/github.com/openshift/client-go/glide.lock index b3739d131138..f5c8c1538d6e 100644 --- a/vendor/github.com/openshift/client-go/glide.lock +++ b/vendor/github.com/openshift/client-go/glide.lock @@ -1,5 +1,5 @@ hash: 595563cffda70c75833adcf07415011d115db7218cbbddc4c14f1684ad39638a -updated: 2019-07-20T21:53:33.024857-04:00 +updated: 2019-08-06T10:39:29.760053178-04:00 imports: - name: github.com/davecgh/go-spew version: 782f4967f2dc4564575ca782fe2d04090b5faca8 @@ -41,7 +41,7 @@ imports: - name: github.com/modern-go/reflect2 version: 94122c33edd36123c84d5368cfb2b69df93a0ec8 - name: github.com/openshift/api - version: 9525304a0adb725ab4a4a54539a1a6bf6cc343d3 + version: 9ef0612c775d8571388e16d1bc68c4b3df83e7fb subpackages: - apps/v1 - authorization/v1 @@ -105,7 +105,7 @@ imports: subpackages: - imports - name: google.golang.org/appengine - version: b2f4a3cf3c67576a2ee09e1fe62656a5086ce880 + version: fb139bde60fa77cede04f226b4d5a3cf68dcce27 subpackages: - internal - internal/base diff --git a/vendor/github.com/openshift/library-go/alpha-build-machinery/Makefile b/vendor/github.com/openshift/library-go/alpha-build-machinery/Makefile index a875a626a987..c9456fe64443 100644 --- a/vendor/github.com/openshift/library-go/alpha-build-machinery/Makefile +++ b/vendor/github.com/openshift/library-go/alpha-build-machinery/Makefile @@ -10,10 +10,12 @@ examples :=$(wildcard ./make/examples/*/Makefile.test) # $3 - output folder # We need to change dir to the final makefile directory or relative paths won't match. # Dynamic values are replaced with "" so we can do diff against checkout versions. +# Avoid comparing local paths by stripping the prefix. define update-makefile-log mkdir -p "$(3)" set -o pipefail; $(MAKE) -j 1 -C "$(dir $(1))" -f "$(notdir $(1))" --no-print-directory --warn-undefined-variables $(2) 2>&1 | \ sed 's/\.\(buildDate\|versionFromGit\|commitFromGit\|gitTreeState\)="[^"]*" /.\1="" /g' | \ + sed -E 's~/.*/(github.com/openshift/library-go/alpha-build-machinery/.*)~/\1~g' | \ tee "$(3)"/"$(notdir $(1))"$(subst ..,.,.$(2).log) endef diff --git a/vendor/github.com/openshift/library-go/alpha-build-machinery/make/default.example.mk b/vendor/github.com/openshift/library-go/alpha-build-machinery/make/default.example.mk index b8a8112c025e..fffc5b3a3c93 100644 --- a/vendor/github.com/openshift/library-go/alpha-build-machinery/make/default.example.mk +++ b/vendor/github.com/openshift/library-go/alpha-build-machinery/make/default.example.mk @@ -20,12 +20,12 @@ CODEGEN_GROUPS_VERSION :=openshiftapiserver:v1alpha1 # $ make -n --print-data-base | grep ^CODEGEN # This will call a macro called "build-image" which will generate image specific targets based on the parameters: -# $0 - macro name -# $1 - target suffix -# $2 - Dockerfile path -# $3 - context directory for image build +# $1 - target name +# $2 - image ref +# $3 - Dockerfile path +# $4 - context # It will generate target "image-$(1)" for builing the image an binding it as a prerequisite to target "images". -$(call build-image,origin-cluster-openshift-apiserver-operator,./Dockerfile,.) +$(call build-image,ocp-cli,registry.svc.ci.openshift.org/ocp/4.2:cli,./images/cli/Dockerfile.rhel,.) # This will call a macro called "add-bindata" which will generate bindata specific targets based on the parameters: # $0 - macro name diff --git a/vendor/github.com/openshift/library-go/alpha-build-machinery/make/default.example.mk.help.log b/vendor/github.com/openshift/library-go/alpha-build-machinery/make/default.example.mk.help.log index 3645ce965c2c..92aa6acdbb8f 100644 --- a/vendor/github.com/openshift/library-go/alpha-build-machinery/make/default.example.mk.help.log +++ b/vendor/github.com/openshift/library-go/alpha-build-machinery/make/default.example.mk.help.log @@ -4,7 +4,7 @@ build clean clean-binaries help -image-origin-cluster-openshift-apiserver-operator +image-ocp-cli images test test-unit diff --git a/vendor/github.com/openshift/library-go/alpha-build-machinery/make/default.mk b/vendor/github.com/openshift/library-go/alpha-build-machinery/make/default.mk index 6e6c0343732e..564fc1229709 100644 --- a/vendor/github.com/openshift/library-go/alpha-build-machinery/make/default.mk +++ b/vendor/github.com/openshift/library-go/alpha-build-machinery/make/default.mk @@ -15,6 +15,9 @@ update: update-bindata # or self_dir could be modified for the next include by the included file. # Also doing this at the end of the file allows us to user self_dir before it could be modified. include $(addprefix $(self_dir), \ - targets/openshift/*.mk \ + targets/openshift/deps.mk \ + targets/openshift/images.mk \ + targets/openshift/bindata.mk \ + targets/openshift/codegen.mk \ golang.mk \ ) diff --git a/vendor/github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/Makefile b/vendor/github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/Makefile index 615e8afb93db..cf44849eef57 100644 --- a/vendor/github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/Makefile +++ b/vendor/github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/Makefile @@ -1,8 +1,14 @@ include $(addprefix ../../, \ golang.mk \ + targets/openshift/rpm.mk \ ) -CROSS_BUILD_BINDIR :=_output/bin +# rpm wants build-id set +GO_LD_EXTRAFLAGS +=-B 0x$$(head -c20 /dev/urandom|od -An -tx1|tr -d ' \n') + +OUTPUT_DIR :=_output +CROSS_BUILD_BINDIR :=$(OUTPUT_DIR)/bin +RPM_EXTRAFLAGS :=--quiet --define 'version 2.42.0' --define 'dist .el7' --define 'release 6' cross-build-darwin-amd64: +@GOOS=darwin GOARCH=amd64 $(MAKE) --no-print-directory build GO_BUILD_BINDIR:=$(CROSS_BUILD_BINDIR)/darwin_amd64 @@ -17,6 +23,7 @@ cross-build: cross-build-darwin-amd64 cross-build-windows-amd64 clean-cross-build: $(RM) -r '$(CROSS_BUILD_BINDIR)' + if [ -d '$(OUTPUT_DIR)' ]; then rmdir --ignore-fail-on-non-empty '$(OUTPUT_DIR)'; fi .PHONY: clean-cross-build clean: clean-cross-build diff --git a/vendor/github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/Makefile.test b/vendor/github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/Makefile.test index 3d3c0e43607a..f933ce024433 100644 --- a/vendor/github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/Makefile.test +++ b/vendor/github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/Makefile.test @@ -1,6 +1,6 @@ SHELL :=/bin/bash -euo pipefail -test: test-build test-cross-build +test: | test-build test-cross-build test-rpm .PHONY: test test-build: @@ -22,10 +22,11 @@ test-build: $(MAKE) clean [[ ! -f ./openshift ]] [[ ! -f ./oc ]] + $(MAKE) clean .PHONY: test-build test-cross-build: - [[ ! -f ./_output/bin ]] + [[ ! -d ./_output/ ]] $(MAKE) cross-build [[ ! -f ./openshift ]] [[ ! -f ./oc ]] @@ -35,9 +36,18 @@ test-cross-build: [[ -f ./_output/bin/windows_amd64/oc.exe ]] $(MAKE) clean - [[ ! -f ./_output/bin/darwin_amd64/openshift ]] - [[ ! -f ./_output/bin/darwin_amd64/oc ]] - [[ ! -f ./_output/bin/windows_amd64/openshift.exe ]] - [[ ! -f ./_output/bin/windows_amd64/oc.exe ]] - [[ ! -f ./_output/bin ]] + [[ ! -d ./_output/ ]] + $(MAKE) clean .PHONY: test-cross-build + +test-rpm: + [[ ! -d ./_output/ ]] + + $(MAKE) rpm-build + [[ -f ./_output/rpms/x86_64/openshift-2.42.0-6.el7.x86_64.rpm ]] + [[ -f ./_output/srpms/openshift-2.42.0-6.el7.src.rpm ]] + + $(MAKE) clean + [[ ! -d ./_output/ ]] + $(MAKE) clean +.PHONY: test-rpm diff --git a/vendor/github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/Makefile.test.log b/vendor/github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/Makefile.test.log index 58087171db0b..e5acf191f45d 100644 --- a/vendor/github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/Makefile.test.log +++ b/vendor/github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/Makefile.test.log @@ -1,8 +1,8 @@ make build fatal: No names found, cannot describe anything. fatal: No names found, cannot describe anything. -go build -ldflags "-s -w -X github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/pkg/version.versionFromGit="" -X github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/pkg/version.commitFromGit="" -X github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/pkg/version.gitTreeState="" -X github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/pkg/version.buildDate="" " github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/cmd/oc -go build -ldflags "-s -w -X github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/pkg/version.versionFromGit="" -X github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/pkg/version.commitFromGit="" -X github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/pkg/version.gitTreeState="" -X github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/pkg/version.buildDate="" " github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/cmd/openshift +go build -ldflags "-s -w -X github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/pkg/version.versionFromGit="" -X github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/pkg/version.commitFromGit="" -X github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/pkg/version.gitTreeState="" -X github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/pkg/version.buildDate="" -B 0x$(head -c20 /dev/urandom|od -An -tx1|tr -d ' \n')" github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/cmd/oc +go build -ldflags "-s -w -X github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/pkg/version.versionFromGit="" -X github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/pkg/version.commitFromGit="" -X github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/pkg/version.gitTreeState="" -X github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/pkg/version.buildDate="" -B 0x$(head -c20 /dev/urandom|od -An -tx1|tr -d ' \n')" github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/cmd/openshift [[ -f ./openshift ]] [[ -f ./oc ]] # test version is set correctly when linking @@ -18,23 +18,32 @@ diff <( ./oc | grep -v -e 'clean' -e 'dirty' | sed '$d' ) <( \ fatal: No names found, cannot describe anything. make clean rm -f oc openshift +rm -f -r '/github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/_output/srpms' +if [ -d '_output' ]; then rmdir --ignore-fail-on-non-empty '_output'; fi rm -f -r '_output/bin' +if [ -d '_output' ]; then rmdir --ignore-fail-on-non-empty '_output'; fi [[ ! -f ./openshift ]] [[ ! -f ./oc ]] -[[ ! -f ./_output/bin ]] +make clean +rm -f oc openshift +rm -f -r '/github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/_output/srpms' +if [ -d '_output' ]; then rmdir --ignore-fail-on-non-empty '_output'; fi +rm -f -r '_output/bin' +if [ -d '_output' ]; then rmdir --ignore-fail-on-non-empty '_output'; fi +[[ ! -d ./_output/ ]] make cross-build fatal: No names found, cannot describe anything. fatal: No names found, cannot describe anything. mkdir -p '_output/bin/darwin_amd64' -go build -ldflags "-s -w -X github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/pkg/version.versionFromGit="" -X github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/pkg/version.commitFromGit="" -X github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/pkg/version.gitTreeState="" -X github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/pkg/version.buildDate="" " -o '_output/bin/darwin_amd64/oc' github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/cmd/oc +go build -ldflags "-s -w -X github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/pkg/version.versionFromGit="" -X github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/pkg/version.commitFromGit="" -X github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/pkg/version.gitTreeState="" -X github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/pkg/version.buildDate="" -B 0x$(head -c20 /dev/urandom|od -An -tx1|tr -d ' \n')" -o '_output/bin/darwin_amd64/oc' github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/cmd/oc mkdir -p '_output/bin/darwin_amd64' -go build -ldflags "-s -w -X github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/pkg/version.versionFromGit="" -X github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/pkg/version.commitFromGit="" -X github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/pkg/version.gitTreeState="" -X github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/pkg/version.buildDate="" " -o '_output/bin/darwin_amd64/openshift' github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/cmd/openshift +go build -ldflags "-s -w -X github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/pkg/version.versionFromGit="" -X github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/pkg/version.commitFromGit="" -X github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/pkg/version.gitTreeState="" -X github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/pkg/version.buildDate="" -B 0x$(head -c20 /dev/urandom|od -An -tx1|tr -d ' \n')" -o '_output/bin/darwin_amd64/openshift' github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/cmd/openshift fatal: No names found, cannot describe anything. fatal: No names found, cannot describe anything. mkdir -p '_output/bin/windows_amd64' -go build -ldflags "-s -w -X github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/pkg/version.versionFromGit="" -X github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/pkg/version.commitFromGit="" -X github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/pkg/version.gitTreeState="" -X github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/pkg/version.buildDate="" " -o '_output/bin/windows_amd64/oc.exe' github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/cmd/oc +go build -ldflags "-s -w -X github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/pkg/version.versionFromGit="" -X github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/pkg/version.commitFromGit="" -X github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/pkg/version.gitTreeState="" -X github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/pkg/version.buildDate="" -B 0x$(head -c20 /dev/urandom|od -An -tx1|tr -d ' \n')" -o '_output/bin/windows_amd64/oc.exe' github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/cmd/oc mkdir -p '_output/bin/windows_amd64' -go build -ldflags "-s -w -X github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/pkg/version.versionFromGit="" -X github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/pkg/version.commitFromGit="" -X github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/pkg/version.gitTreeState="" -X github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/pkg/version.buildDate="" " -o '_output/bin/windows_amd64/openshift.exe' github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/cmd/openshift +go build -ldflags "-s -w -X github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/pkg/version.versionFromGit="" -X github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/pkg/version.commitFromGit="" -X github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/pkg/version.gitTreeState="" -X github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/pkg/version.buildDate="" -B 0x$(head -c20 /dev/urandom|od -An -tx1|tr -d ' \n')" -o '_output/bin/windows_amd64/openshift.exe' github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/cmd/openshift [[ ! -f ./openshift ]] [[ ! -f ./oc ]] [[ -f ./_output/bin/darwin_amd64/openshift ]] @@ -43,9 +52,34 @@ go build -ldflags "-s -w -X github.com/openshift/library-go/alpha-build-machiner [[ -f ./_output/bin/windows_amd64/oc.exe ]] make clean rm -f oc openshift +rm -f -r '/github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/_output/srpms' +if [ -d '_output' ]; then rmdir --ignore-fail-on-non-empty '_output'; fi +rm -f -r '_output/bin' +if [ -d '_output' ]; then rmdir --ignore-fail-on-non-empty '_output'; fi +[[ ! -d ./_output/ ]] +make clean +rm -f oc openshift +rm -f -r '/github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/_output/srpms' +if [ -d '_output' ]; then rmdir --ignore-fail-on-non-empty '_output'; fi +rm -f -r '_output/bin' +if [ -d '_output' ]; then rmdir --ignore-fail-on-non-empty '_output'; fi +[[ ! -d ./_output/ ]] +make rpm-build +rpmbuild -ba --define "_topdir /github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries" --define "go_package github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries" --quiet --define 'version 2.42.0' --define 'dist .el7' --define 'release 6' ocp.spec +fatal: No names found, cannot describe anything. +fatal: No names found, cannot describe anything. +[[ -f ./_output/rpms/x86_64/openshift-2.42.0-6.el7.x86_64.rpm ]] +[[ -f ./_output/srpms/openshift-2.42.0-6.el7.src.rpm ]] +make clean +rm -f oc openshift +rm -f -r '/github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/_output/srpms' +if [ -d '_output' ]; then rmdir --ignore-fail-on-non-empty '_output'; fi +rm -f -r '_output/bin' +if [ -d '_output' ]; then rmdir --ignore-fail-on-non-empty '_output'; fi +[[ ! -d ./_output/ ]] +make clean +rm -f oc openshift +rm -f -r '/github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/_output/srpms' +if [ -d '_output' ]; then rmdir --ignore-fail-on-non-empty '_output'; fi rm -f -r '_output/bin' -[[ ! -f ./_output/bin/darwin_amd64/openshift ]] -[[ ! -f ./_output/bin/darwin_amd64/oc ]] -[[ ! -f ./_output/bin/windows_amd64/openshift.exe ]] -[[ ! -f ./_output/bin/windows_amd64/oc.exe ]] -[[ ! -f ./_output/bin ]] +if [ -d '_output' ]; then rmdir --ignore-fail-on-non-empty '_output'; fi diff --git a/vendor/github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/ocp.spec b/vendor/github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/ocp.spec new file mode 100644 index 000000000000..fc4117e0b68c --- /dev/null +++ b/vendor/github.com/openshift/library-go/alpha-build-machinery/make/examples/multiple-binaries/ocp.spec @@ -0,0 +1,47 @@ +#debuginfo not supported with Go +%global debug_package %{nil} +# modifying the Go binaries breaks the DWARF debugging +%global __os_install_post %{_rpmconfigdir}/brp-compress + +%global golang_version 1.12 +%global product_name OpenShift + +%{!?version: %global version 0.0.1} +%{!?release: %global release 1} + +Name: openshift +Version: %{version} +Release: %{release}%{dist} +Summary: OpenShift client binaries +License: ASL 2.0 +URL: https://%{go_package} + +# If go_arches not defined fall through to implicit golang archs +%if 0%{?go_arches:1} +ExclusiveArch: %{go_arches} +%else +ExclusiveArch: x86_64 aarch64 ppc64le s390x +%endif + +#BuildRequires: bsdtar +BuildRequires: golang >= %{golang_version} + +%description +%{summary} + +%prep + +%build +make build + +%install +install -d %{buildroot}%{_bindir} + +install -p -m 755 oc %{buildroot}%{_bindir}/oc +install -p -m 755 openshift %{buildroot}%{_bindir}/openshift + +%files +%{_bindir}/oc +%{_bindir}/openshift + +%changelog diff --git a/vendor/github.com/openshift/library-go/alpha-build-machinery/make/operator.example.mk b/vendor/github.com/openshift/library-go/alpha-build-machinery/make/operator.example.mk index 2f0326a9cb14..7e6ff98d56a6 100644 --- a/vendor/github.com/openshift/library-go/alpha-build-machinery/make/operator.example.mk +++ b/vendor/github.com/openshift/library-go/alpha-build-machinery/make/operator.example.mk @@ -22,12 +22,12 @@ CODEGEN_GROUPS_VERSION :=openshiftapiserver:v1alpha1 # $ make -n --print-data-base | grep ^CODEGEN # This will call a macro called "build-image" which will generate image specific targets based on the parameters: -# $0 - macro name -# $1 - target suffix -# $2 - Dockerfile path -# $3 - context directory for image build +# $1 - target name +# $2 - image ref +# $3 - Dockerfile path +# $4 - context # It will generate target "image-$(1)" for builing the image an binding it as a prerequisite to target "images". -$(call build-image,origin-cluster-openshift-apiserver-operator,./Dockerfile,.) +$(call build-image,ocp-openshift-apiserver-operator,registry.svc.ci.openshift.org/ocp/4.2:openshift-apiserver-operator,./Dockerfile.rhel,.) # This will call a macro called "add-bindata" which will generate bindata specific targets based on the parameters: # $0 - macro name diff --git a/vendor/github.com/openshift/library-go/alpha-build-machinery/make/operator.example.mk.help.log b/vendor/github.com/openshift/library-go/alpha-build-machinery/make/operator.example.mk.help.log index 3645ce965c2c..a1489d212baa 100644 --- a/vendor/github.com/openshift/library-go/alpha-build-machinery/make/operator.example.mk.help.log +++ b/vendor/github.com/openshift/library-go/alpha-build-machinery/make/operator.example.mk.help.log @@ -4,7 +4,7 @@ build clean clean-binaries help -image-origin-cluster-openshift-apiserver-operator +image-ocp-openshift-apiserver-operator images test test-unit diff --git a/vendor/github.com/openshift/library-go/alpha-build-machinery/make/targets/openshift/images.mk b/vendor/github.com/openshift/library-go/alpha-build-machinery/make/targets/openshift/images.mk index b48741a739af..00e76ac2613b 100644 --- a/vendor/github.com/openshift/library-go/alpha-build-machinery/make/targets/openshift/images.mk +++ b/vendor/github.com/openshift/library-go/alpha-build-machinery/make/targets/openshift/images.mk @@ -1,19 +1,23 @@ -IMAGE_REGISTRY ?= -IMAGE_ORG ?=openshift -IMAGE_TAG ?=latest - - # IMAGE_BUILD_EXTRA_FLAGS lets you add extra flags for imagebuilder # e.g. to mount secrets and repo information into base image like: # make images IMAGE_BUILD_EXTRA_FLAGS='-mount ~/projects/origin-repos/4.2/:/etc/yum.repos.d/' +IMAGE_BUILD_DEFAULT_FLAGS ?=--allow-pull IMAGE_BUILD_EXTRA_FLAGS ?= -# $1 - image name -# $2 - Dockerfile path -# $3 - context +# $1 - target name +# $2 - image ref +# $3 - Dockerfile path +# $4 - context define build-image-internal image-$(1): - $(strip imagebuilder --allow-pull $(IMAGE_BUILD_EXTRA_FLAGS) -f $(2) -t $(addsuffix /,$(IMAGE_REGISTRY))$(addsuffix /,$(IMAGE_ORG))$(1)$(addprefix :,$(IMAGE_TAG)) $(3)) + $(strip \ + imagebuilder \ + $(IMAGE_BUILD_DEFAULT_FLAGS) \ + -t $(2) + -f $(3) \ + $(IMAGE_BUILD_EXTRA_FLAGS) \ + $(4) \ + ) .PHONY: image-$(1) images: image-$(1) @@ -21,5 +25,5 @@ images: image-$(1) endef define build-image -$(eval $(call build-image-internal,$(1),$(2),$(3))) +$(eval $(call build-image-internal,$(1),$(2),$(3),$(4))) endef diff --git a/vendor/github.com/openshift/library-go/alpha-build-machinery/make/targets/openshift/rpm.mk b/vendor/github.com/openshift/library-go/alpha-build-machinery/make/targets/openshift/rpm.mk new file mode 100644 index 000000000000..b235197c74bf --- /dev/null +++ b/vendor/github.com/openshift/library-go/alpha-build-machinery/make/targets/openshift/rpm.mk @@ -0,0 +1,41 @@ +RPM_OUTPUT_DIR ?=_output +RPM_TOPDIR ?=$(abspath ./) +RPM_BUILDDIR ?=$(RPM_TOPDIR) +RPM_BUILDROOT ?=$(RPM_TOPDIR) +RPM_SOURCEDIR ?=$(RPM_TOPDIR) +RPM_SPECDIR ?=$(RPM_TOPDIR) +RPM_RPMDIR ?=$(RPM_TOPDIR)/$(RPM_OUTPUT_DIR)/rpms +RPM_SRCRPMDIR ?=$(RPM_TOPDIR)/$(RPM_OUTPUT_DIR)/srpms + +RPM_SPECFILES ?=$(wildcard *.spec) +RPM_BUILDFLAGS ?=-ba +RPM_EXTRAFLAGS ?= + +rpm-build: + $(strip \ + rpmbuild $(RPM_BUILDFLAGS) \ + --define "_topdir $(RPM_TOPDIR)" \ + --define "_builddir $(RPM_BUILDDIR)" \ + --define "_buildrootdir $(RPM_BUILDROOT)" \ + --define "_rpmdir $(RPM_RPMDIR)" \ + --define "_srcrpmdir $(RPM_SRCRPMDIR)" \ + --define "_specdir $(RPM_SPECDIR)" \ + --define "_sourcedir $(RPM_SOURCEDIR)" \ + --define "go_package $(GO_PACKAGE)" \ + $(RPM_EXTRAFLAGS) \ + $(RPM_SPECFILES) \ + ) + +clean-rpms: + $(RM) -r '$(RPM_RPMDIR)' '$(RPM_SRCRPMDIR)' + if [ -d '$(RPM_OUTPUT_DIR)' ]; then rmdir --ignore-fail-on-non-empty '$(RPM_OUTPUT_DIR)'; fi +.PHONY: clean-rpms + +clean: clean-rpms + +# We need to be careful to expand all the paths before any include is done +# or self_dir could be modified for the next include by the included file. +# Also doing this at the end of the file allows us to user self_dir before it could be modified. +include $(addprefix $(self_dir), \ + ../../lib/golang.mk \ +) diff --git a/vendor/github.com/openshift/library-go/pkg/operator/configobserver/cloudprovider/observe_cloudprovider.go b/vendor/github.com/openshift/library-go/pkg/operator/configobserver/cloudprovider/observe_cloudprovider.go index 2bccc91ff6a0..f0e5c252f369 100644 --- a/vendor/github.com/openshift/library-go/pkg/operator/configobserver/cloudprovider/observe_cloudprovider.go +++ b/vendor/github.com/openshift/library-go/pkg/operator/configobserver/cloudprovider/observe_cloudprovider.go @@ -96,7 +96,7 @@ func (c *cloudProviderObserver) ObserveCloudProviderNames(genericListers configo } // we set cloudprovider configmap values only for some cloud providers. - validCloudProviders := sets.NewString("azure", "gce", "vsphere") + validCloudProviders := sets.NewString("azure", "gce", "openstack", "vsphere") if !validCloudProviders.Has(cloudProvider) { sourceCloudConfigMap = "" } @@ -152,8 +152,7 @@ func getPlatformName(platformType configv1.PlatformType, recorder events.Recorde cloudProvider = "gce" case configv1.LibvirtPlatformType: case configv1.OpenStackPlatformType: - // TODO(flaper87): Enable this once we've figured out a way to write the cloud provider config in the master nodes - //cloudProvider = "openstack" + cloudProvider = "openstack" case configv1.NonePlatformType: default: // the new doc on the infrastructure fields requires that we treat an unrecognized thing the same bare metal. diff --git a/vendor/github.com/openshift/library-go/pkg/operator/configobserver/cloudprovider/observe_cloudprovider_test.go b/vendor/github.com/openshift/library-go/pkg/operator/configobserver/cloudprovider/observe_cloudprovider_test.go index 21be95596634..1260ae3a68ec 100644 --- a/vendor/github.com/openshift/library-go/pkg/operator/configobserver/cloudprovider/observe_cloudprovider_test.go +++ b/vendor/github.com/openshift/library-go/pkg/operator/configobserver/cloudprovider/observe_cloudprovider_test.go @@ -63,7 +63,8 @@ func TestObserveCloudProviderNames(t *testing.T) { cloudProviderCount: 0, }, { platform: configv1.OpenStackPlatformType, - cloudProviderCount: 0, + expected: "openstack", + cloudProviderCount: 1, }, { platform: configv1.GCPPlatformType, expected: "gce", diff --git a/vendor/github.com/openshift/library-go/pkg/operator/configobserver/proxy/observe_proxy.go b/vendor/github.com/openshift/library-go/pkg/operator/configobserver/proxy/observe_proxy.go index 53988d6b8d03..4231de358385 100644 --- a/vendor/github.com/openshift/library-go/pkg/operator/configobserver/proxy/observe_proxy.go +++ b/vendor/github.com/openshift/library-go/pkg/operator/configobserver/proxy/observe_proxy.go @@ -56,7 +56,7 @@ func (f *observeProxyFlags) ObserveProxyConfig(genericListers configobserver.Lis } newProxyMap := proxyToMap(proxyConfig) - if len(newProxyMap) > 0 { + if newProxyMap != nil { if err := unstructured.SetNestedStringMap(observedConfig, newProxyMap, f.configPath...); err != nil { errs = append(errs, err) } @@ -72,17 +72,21 @@ func (f *observeProxyFlags) ObserveProxyConfig(genericListers configobserver.Lis func proxyToMap(proxy *configv1.Proxy) map[string]string { proxyMap := map[string]string{} - if noProxy := proxy.Spec.NoProxy; len(noProxy) > 0 { + if noProxy := proxy.Status.NoProxy; len(noProxy) > 0 { proxyMap["NO_PROXY"] = noProxy } - if httpProxy := proxy.Spec.HTTPProxy; len(httpProxy) > 0 { + if httpProxy := proxy.Status.HTTPProxy; len(httpProxy) > 0 { proxyMap["HTTP_PROXY"] = httpProxy } - if httpsProxy := proxy.Spec.HTTPSProxy; len(httpsProxy) > 0 { + if httpsProxy := proxy.Status.HTTPSProxy; len(httpsProxy) > 0 { proxyMap["HTTPS_PROXY"] = httpsProxy } + if len(proxyMap) == 0 { + return nil + } + return proxyMap } diff --git a/vendor/github.com/openshift/library-go/pkg/operator/configobserver/proxy/observe_proxy_test.go b/vendor/github.com/openshift/library-go/pkg/operator/configobserver/proxy/observe_proxy_test.go index 4909ea8fc2e9..ef5a7e302173 100644 --- a/vendor/github.com/openshift/library-go/pkg/operator/configobserver/proxy/observe_proxy_test.go +++ b/vendor/github.com/openshift/library-go/pkg/operator/configobserver/proxy/observe_proxy_test.go @@ -33,14 +33,18 @@ func TestObserveProxyConfig(t *testing.T) { configPath := []string{"openshift", "proxy"} tests := []struct { - name string - proxySpec configv1.ProxySpec - expected map[string]interface{} - expectedError []error + name string + proxySpec configv1.ProxySpec + proxyStatus configv1.ProxyStatus + previous map[string]string + expected map[string]interface{} + expectedError []error + eventsExpected int }{ { name: "all unset", proxySpec: configv1.ProxySpec{}, + proxyStatus: configv1.ProxyStatus{}, expected: map[string]interface{}{}, expectedError: []error{}, }, @@ -51,16 +55,22 @@ func TestObserveProxyConfig(t *testing.T) { HTTPSProxy: "https://someplace.it", NoProxy: "127.0.0.1", }, + proxyStatus: configv1.ProxyStatus{ + HTTPProxy: "http://someplace.it", + HTTPSProxy: "https://someplace.it", + NoProxy: "127.0.0.1,incluster.address.it", + }, expected: map[string]interface{}{ "openshift": map[string]interface{}{ "proxy": map[string]interface{}{ "HTTP_PROXY": "http://someplace.it", "HTTPS_PROXY": "https://someplace.it", - "NO_PROXY": "127.0.0.1", + "NO_PROXY": "127.0.0.1,incluster.address.it", }, }, }, - expectedError: []error{}, + expectedError: []error{}, + eventsExpected: 1, }, } for _, tt := range tests { @@ -69,6 +79,7 @@ func TestObserveProxyConfig(t *testing.T) { indexer.Add(&configv1.Proxy{ ObjectMeta: metav1.ObjectMeta{Name: "cluster"}, Spec: tt.proxySpec, + Status: tt.proxyStatus, }) listers := testLister{ lister: configlistersv1.NewProxyLister(indexer), @@ -86,6 +97,9 @@ func TestObserveProxyConfig(t *testing.T) { if !reflect.DeepEqual(errorsGot, tt.expectedError) { t.Errorf("observeProxyFlags.ObserveProxyConfig() errorsGot = %v, want %v", errorsGot, tt.expectedError) } + if events := eventRecorder.Events(); len(events) != tt.eventsExpected { + t.Errorf("expected %d events, but got %d: %v", tt.eventsExpected, len(events), events) + } }) } } diff --git a/vendor/github.com/openshift/library-go/pkg/operator/resource/resourceapply/core.go b/vendor/github.com/openshift/library-go/pkg/operator/resource/resourceapply/core.go index 870b7ceb6422..36777d6eb474 100644 --- a/vendor/github.com/openshift/library-go/pkg/operator/resource/resourceapply/core.go +++ b/vendor/github.com/openshift/library-go/pkg/operator/resource/resourceapply/core.go @@ -196,6 +196,10 @@ func ApplyConfigMap(client coreclientv1.ConfigMapsGetter, recorder events.Record // ApplySecret merges objectmeta, requires data func ApplySecret(client coreclientv1.SecretsGetter, recorder events.Recorder, required *corev1.Secret) (*corev1.Secret, bool, error) { + if len(required.StringData) > 0 { + return nil, false, fmt.Errorf("Secret.stringData is not supported") + } + existing, err := client.Secrets(required.Namespace).Get(required.Name, metav1.GetOptions{}) if apierrors.IsNotFound(err) { actual, err := client.Secrets(required.Namespace).Create(required) @@ -210,6 +214,7 @@ func ApplySecret(client coreclientv1.SecretsGetter, recorder events.Recorder, re existingCopy := existing.DeepCopy() resourcemerge.EnsureObjectMeta(modified, &existingCopy.ObjectMeta, required.ObjectMeta) + dataSame := equality.Semantic.DeepEqual(existingCopy.Data, required.Data) if dataSame && !*modified { return existingCopy, false, nil @@ -217,7 +222,23 @@ func ApplySecret(client coreclientv1.SecretsGetter, recorder events.Recorder, re existingCopy.Data = required.Data if klog.V(4) { - klog.Infof("Secret %q changes: %v", required.Namespace+"/"+required.Name, JSONPatch(existing, required)) + safeRequired := required.DeepCopy() + safeExisting := existing.DeepCopy() + + for s := range safeExisting.Data { + safeExisting.Data[s] = []byte("OLD") + } + for s := range safeRequired.Data { + if _, preexisting := existing.Data[s]; !preexisting { + safeRequired.Data[s] = []byte("NEW") + } else if !equality.Semantic.DeepEqual(existing.Data[s], safeRequired.Data[s]) { + safeRequired.Data[s] = []byte("MODIFIED") + } else { + safeRequired.Data[s] = []byte("OLD") + } + } + + klog.Infof("Secret %q changes: %v", required.Namespace+"/"+required.Name, JSONPatch(safeExisting, safeRequired)) } actual, err := client.Secrets(required.Namespace).Update(existingCopy) diff --git a/vendor/github.com/openshift/library-go/pkg/operator/staticpod/controller/installer/installer_controller.go b/vendor/github.com/openshift/library-go/pkg/operator/staticpod/controller/installer/installer_controller.go index c8821a00ef6f..fd1314e6dac5 100644 --- a/vendor/github.com/openshift/library-go/pkg/operator/staticpod/controller/installer/installer_controller.go +++ b/vendor/github.com/openshift/library-go/pkg/operator/staticpod/controller/installer/installer_controller.go @@ -600,7 +600,7 @@ func (c *InstallerController) newNodeStateForInstallInProgress(currNodeState *op ret.LastFailedRevision = currNodeState.TargetRevision ret.TargetRevision = 0 if len(errors) == 0 { - errors = append(errors, "no detailed termination message, see `oc get -n %q pods/%q -oyaml`", installerPod.Namespace, installerPod.Name) + errors = append(errors, fmt.Sprintf("no detailed termination message, see `oc get -n %q pods/%q -oyaml`", installerPod.Namespace, installerPod.Name)) } ret.LastFailedRevisionErrors = errors return ret, false, "installer pod failed", nil diff --git a/vendor/github.com/openshift/library-go/pkg/operator/staticpod/prune/cmd.go b/vendor/github.com/openshift/library-go/pkg/operator/staticpod/prune/cmd.go index 2db8cda746b1..18ba33178b1c 100644 --- a/vendor/github.com/openshift/library-go/pkg/operator/staticpod/prune/cmd.go +++ b/vendor/github.com/openshift/library-go/pkg/operator/staticpod/prune/cmd.go @@ -64,7 +64,7 @@ func (o *PruneOptions) Validate() error { return fmt.Errorf("--resource-dir is required") } if o.MaxEligibleRevision == 0 { - return fmt.Errorf("--max-eligible-id is required") + return fmt.Errorf("--max-eligible-revision is required") } if len(o.StaticPodName) == 0 { return fmt.Errorf("--static-pod-name is required") diff --git a/vendor/github.com/openshift/oc/LICENSE b/vendor/github.com/openshift/oc/LICENSE new file mode 100644 index 000000000000..c4ea8b6f9d88 --- /dev/null +++ b/vendor/github.com/openshift/oc/LICENSE @@ -0,0 +1,191 @@ + + 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 + + Copyright 2014 Red Hat, Inc. + + 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/github.com/openshift/oc/Makefile b/vendor/github.com/openshift/oc/Makefile index 6883496470a0..84e1743f9351 100644 --- a/vendor/github.com/openshift/oc/Makefile +++ b/vendor/github.com/openshift/oc/Makefile @@ -1,40 +1,55 @@ all: build .PHONY: all -GO_LD_EXTRAFLAGS :=-X github.com/openshift/oc/vendor/k8s.io/kubernetes/pkg/version.gitMajor="1" \ - -X github.com/openshift/oc/vendor/k8s.io/kubernetes/pkg/version.gitMinor="14" \ - -X github.com/openshift/oc/vendor/k8s.io/kubernetes/pkg/version.gitVersion="v1.14.0+724e12f93f" \ - -X github.com/openshift/oc/vendor/k8s.io/kubernetes/pkg/version.gitCommit="$(SOURCE_GIT_COMMIT)" \ - -X github.com/openshift/oc/vendor/k8s.io/kubernetes/pkg/version.buildDate="$(shell date -u +'%Y-%m-%dT%H:%M:%SZ')" \ - -X github.com/openshift/oc/vendor/k8s.io/kubernetes/pkg/version.gitTreeState="clean" - - # Include the library makefile include $(addprefix ./vendor/github.com/openshift/library-go/alpha-build-machinery/make/, \ golang.mk \ targets/openshift/deps.mk \ targets/openshift/images.mk \ + targets/openshift/rpm.mk \ ) +GO_LD_EXTRAFLAGS :=-X github.com/openshift/oc/vendor/k8s.io/kubernetes/pkg/version.gitMajor="1" \ + -X github.com/openshift/oc/vendor/k8s.io/kubernetes/pkg/version.gitMinor="14" \ + -X github.com/openshift/oc/vendor/k8s.io/kubernetes/pkg/version.gitVersion="v1.14.0+724e12f93f" \ + -X github.com/openshift/oc/vendor/k8s.io/kubernetes/pkg/version.gitCommit="$(SOURCE_GIT_COMMIT)" \ + -X github.com/openshift/oc/vendor/k8s.io/kubernetes/pkg/version.buildDate="$(shell date -u +'%Y-%m-%dT%H:%M:%SZ')" \ + -X github.com/openshift/oc/vendor/k8s.io/kubernetes/pkg/version.gitTreeState="clean" + GO_BUILD_PACKAGES :=$(strip \ ./cmd/... \ - ./tools/... \ + $(wildcard ./tools/*) \ ) # These tags make sure we can statically link and avoid shared dependencies GO_BUILD_FLAGS :=-tags 'include_gcs include_oss containers_image_openpgp gssapi' +GO_BUILD_FLAGS_DARWIN :=-tags 'include_gcs include_oss containers_image_openpgp' +GO_BUILD_FLAGS_WINDOWS :=-tags 'include_gcs include_oss containers_image_openpgp' + +OUTPUT_DIR :=_output +CROSS_BUILD_BINDIR :=$(OUTPUT_DIR)/bin +RPM_VERSION :=$(shell set -o pipefail && echo '$(SOURCE_GIT_TAG)' | sed -E 's/v([0-9]+\.[0-9]+\.[0-9]+)-.*/\1/') +RPM_EXTRAFLAGS := \ + --define 'version $(RPM_VERSION)' \ + --define 'dist .el7' \ + --define 'release 1' + +IMAGE_REGISTRY :=registry.svc.ci.openshift.org # This will call a macro called "build-image" which will generate image specific targets based on the parameters: -# $0 - macro name -# $1 - target suffix -# $2 - Dockerfile path -# $3 - context directory for image build -$(call build-image,ose-cli,./images/cli/Dockerfile.rhel,.) +# $1 - target name +# $2 - image ref +# $3 - Dockerfile path +# $4 - context +$(call build-image,ocp-cli,$(IMAGE_REGISTRY)/ocp/4.2:cli,./images/cli/Dockerfile.rhel,.) + +$(call build-image,ocp-cli-artifacts,$(IMAGE_REGISTRY)/ocp/4.2:cli-artifacts,./images/cli-artifacts/Dockerfile.rhel,.) +image-ocp-cli-artifacts: image-ocp-cli -$(call build-image,ose-deployer,./images/deployer/Dockerfile.rhel,.) -image-ose-deployer: image-ose-cli +$(call build-image,ocp-deployer,$(IMAGE_REGISTRY)/ocp/4.2:deployer,./images/deployer/Dockerfile.rhel,.) +image-ocp-deployer: image-ocp-cli -$(call build-image,ose-recycler,./images/recycler/Dockerfile.rhel,.) -image-ose-recycler: image-ose-cli +$(call build-image,ocp-recycler,$(IMAGE_REGISTRY)/ocp/4.2:recycler,./images/recycler/Dockerfile.rhel,.) +image-ocp-recycler: image-ocp-cli update: update-generated-completions .PHONY: update @@ -53,3 +68,22 @@ update-generated-completions: build verify-generated-completions: build hack/verify-generated-completions.sh .PHONY: verify-generated-completions + + +cross-build-darwin-amd64: + +@GOOS=darwin GOARCH=amd64 $(MAKE) --no-print-directory build GO_BUILD_PACKAGES:=./cmd/oc GO_BUILD_FLAGS:="$(GO_BUILD_FLAGS_DARWIN)" GO_BUILD_BINDIR:=$(CROSS_BUILD_BINDIR)/darwin_amd64 +.PHONY: cross-build-darwin-amd64 + +cross-build-windows-amd64: + +@GOOS=windows GOARCH=amd64 $(MAKE) --no-print-directory build GO_BUILD_PACKAGES:=./cmd/oc GO_BUILD_FLAGS:="$(GO_BUILD_FLAGS_WINDOWS)" GO_BUILD_BINDIR:=$(CROSS_BUILD_BINDIR)/windows_amd64 +.PHONY: cross-build-windows-amd64 + +cross-build: cross-build-darwin-amd64 cross-build-windows-amd64 +.PHONY: cross-build + +clean-cross-build: + $(RM) -r '$(CROSS_BUILD_BINDIR)' + if [ -d '$(OUTPUT_DIR)' ]; then rmdir --ignore-fail-on-non-empty '$(OUTPUT_DIR)'; fi +.PHONY: clean-cross-build + +clean: clean-cross-build diff --git a/vendor/github.com/openshift/oc/cmd/oc/oc.go b/vendor/github.com/openshift/oc/cmd/oc/oc.go index 518b5f564b33..bc0905b30e23 100644 --- a/vendor/github.com/openshift/oc/cmd/oc/oc.go +++ b/vendor/github.com/openshift/oc/cmd/oc/oc.go @@ -10,6 +10,9 @@ import ( "github.com/spf13/pflag" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + apimachineryruntime "k8s.io/apimachinery/pkg/runtime" utilruntime "k8s.io/apimachinery/pkg/util/runtime" utilflag "k8s.io/component-base/cli/flag" "k8s.io/component-base/logs" @@ -26,10 +29,11 @@ import ( "github.com/openshift/api/project" "github.com/openshift/api/quota" "github.com/openshift/api/route" - "github.com/openshift/api/security" + securityv1 "github.com/openshift/api/security/v1" "github.com/openshift/api/template" "github.com/openshift/api/user" "github.com/openshift/library-go/pkg/serviceability" + "github.com/openshift/oc/pkg/cli" "github.com/openshift/oc/pkg/helpers/legacy" "github.com/openshift/oc/pkg/version" @@ -73,7 +77,7 @@ func main() { utilruntime.Must(project.Install(scheme.Scheme)) utilruntime.Must(quota.Install(scheme.Scheme)) utilruntime.Must(route.Install(scheme.Scheme)) - utilruntime.Must(security.Install(scheme.Scheme)) + utilruntime.Must(installNonCRDSecurity(scheme.Scheme)) utilruntime.Must(template.Install(scheme.Scheme)) utilruntime.Must(user.Install(scheme.Scheme)) legacy.InstallExternalLegacyAll(scheme.Scheme) @@ -89,7 +93,7 @@ func main() { utilruntime.Must(project.Install(legacyscheme.Scheme)) utilruntime.Must(quota.Install(legacyscheme.Scheme)) utilruntime.Must(route.Install(legacyscheme.Scheme)) - utilruntime.Must(security.Install(legacyscheme.Scheme)) + utilruntime.Must(installNonCRDSecurity(legacyscheme.Scheme)) utilruntime.Must(template.Install(legacyscheme.Scheme)) utilruntime.Must(user.Install(legacyscheme.Scheme)) legacy.InstallExternalLegacyAll(legacyscheme.Scheme) @@ -100,3 +104,18 @@ func main() { os.Exit(1) } } + +func installNonCRDSecurity(scheme *apimachineryruntime.Scheme) error { + scheme.AddKnownTypes(securityv1.GroupVersion, + &securityv1.PodSecurityPolicySubjectReview{}, + &securityv1.PodSecurityPolicySelfSubjectReview{}, + &securityv1.PodSecurityPolicyReview{}, + &securityv1.RangeAllocation{}, + &securityv1.RangeAllocationList{}, + ) + if err := corev1.AddToScheme(scheme); err != nil { + return err + } + metav1.AddToGroupVersion(scheme, securityv1.GroupVersion) + return nil +} diff --git a/vendor/github.com/openshift/oc/cmd/oc/oc_test.go b/vendor/github.com/openshift/oc/cmd/oc/oc_test.go new file mode 100644 index 000000000000..a56716ad73eb --- /dev/null +++ b/vendor/github.com/openshift/oc/cmd/oc/oc_test.go @@ -0,0 +1,37 @@ +package main + +import ( + "reflect" + "testing" + + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + "k8s.io/apimachinery/pkg/util/sets" + + "github.com/openshift/api/security" +) + +func TestInstallNonCRDSecurity(t *testing.T) { + withoutCRDs := runtime.NewScheme() + utilruntime.Must(installNonCRDSecurity(withoutCRDs)) + nonCRDTypes := gvks(withoutCRDs.AllKnownTypes()) + + complete := runtime.NewScheme() + utilruntime.Must(security.Install(complete)) + expected := gvks(complete.AllKnownTypes()) + expected.Delete("security.openshift.io/v1, Kind=SecurityContextConstraints") + expected.Delete("security.openshift.io/v1, Kind=SecurityContextConstraintsList") + + if !reflect.DeepEqual(expected, nonCRDTypes) { + t.Errorf("unexpected security/v1 scheme without CRD types\nunexpected: %v\nmissing: %v", nonCRDTypes.Difference(expected).List(), expected.Difference(nonCRDTypes).List()) + } +} + +func gvks(types map[schema.GroupVersionKind]reflect.Type) sets.String { + ret := sets.NewString() + for k := range types { + ret.Insert(k.String()) + } + return ret +} diff --git a/vendor/github.com/openshift/oc/glide.lock b/vendor/github.com/openshift/oc/glide.lock index 41f4aaf73fe9..9fafadd2c893 100644 --- a/vendor/github.com/openshift/oc/glide.lock +++ b/vendor/github.com/openshift/oc/glide.lock @@ -1,5 +1,5 @@ hash: 133600678bfced8f947d0b7797aa19e87a4b7cb279eab1c96799fd17aac36ec3 -updated: 2019-07-24T07:36:55.22422713-04:00 +updated: 2019-08-01T17:39:30.516109233+02:00 imports: - name: bitbucket.org/ww/goautoneg version: 2ae31c8b6b30d2f4c8100c20d527b571e9c433bb @@ -93,7 +93,7 @@ imports: - types - version - name: github.com/containers/storage - version: 2bbc3ae6cb3749c625baa080621115b68139d860 + version: 1b2a0dcaf4e74170644c851ff75b8637dbd2af68 subpackages: - pkg/fileutils - pkg/homedir @@ -392,7 +392,7 @@ imports: - libcontainer/user - libcontainer/utils - name: github.com/openshift/api - version: d75a161a0f4ded1815ec24321fc1f8609c255cdb + version: 0922aa5a655be314e20a3e0e94f4f2b105100154 subpackages: - annotations - apps @@ -504,7 +504,7 @@ imports: - user/clientset/versioned/typed/user/v1 - user/clientset/versioned/typed/user/v1/fake - name: github.com/openshift/library-go - version: 2ccf23323324d7fd30f5c684e8aeed4ddb323107 + version: 1810ce5f54ff4a1a4fea05e06024896a4885eb05 subpackages: - pkg/apps/appsserialization - pkg/apps/appsutil @@ -682,7 +682,7 @@ imports: - unicode/norm - width - name: golang.org/x/time - version: 9d24e82272b4f38b78bc8cff74fa936d31ccd8ef + version: f51c12702a4d776e4c1fa9b0fabab841babae631 subpackages: - rate - name: golang.org/x/tools @@ -1068,6 +1068,7 @@ imports: version: 473b2830919bc04a8044a290df4be2c83b525b93 repo: https://github.com/openshift/kubernetes.git subpackages: + - cmd/genutils - pkg/api/legacyscheme - pkg/api/service - pkg/api/v1/pod @@ -1290,7 +1291,7 @@ imports: - pkg/transformers/config/defaultconfig - pkg/types - name: sigs.k8s.io/yaml - version: 4cd0c284b15f1735b8cc247df097d262b8903f9f + version: fd68e9863619f6ec2fdd8625fe1f02e7c877e480 - name: vbom.ml/util version: db5cfe13f5cc80a4990d98e2e1b0707a4d1a5394 subpackages: diff --git a/vendor/github.com/openshift/oc/images/cli-artifacts/Dockerfile.rhel b/vendor/github.com/openshift/oc/images/cli-artifacts/Dockerfile.rhel new file mode 100644 index 000000000000..6df27a12e788 --- /dev/null +++ b/vendor/github.com/openshift/oc/images/cli-artifacts/Dockerfile.rhel @@ -0,0 +1,14 @@ +# This Dockerfile builds an image containing the Mac and Windows version of oc +# layered on top of the Linux cli image. +FROM registry.svc.ci.openshift.org/ocp/builder:golang-1.12 AS builder +WORKDIR /go/src/github.com/openshift/oc +COPY . . +RUN yum install -y --setopt=skip_missing_names_on_install=False gpgme-devel libassuan-devel +RUN make cross-build-darwin-amd64 cross-build-windows-amd64 --warn-undefined-variables + +FROM registry.svc.ci.openshift.org/ocp/4.2:cli +COPY --from=builder /go/src/github.com/openshift/oc/_output/bin/darwin_amd64/oc /usr/share/openshift/mac/oc +COPY --from=builder /go/src/github.com/openshift/oc/_output/bin/windows_amd64/oc.exe /usr/share/openshift/windows/oc.exe +LABEL io.k8s.display-name="OpenShift Clients" \ + io.k8s.description="OpenShift is a platform for developing, building, and deploying containerized applications." \ + io.openshift.tags="openshift,cli" diff --git a/vendor/github.com/openshift/oc/oc.spec b/vendor/github.com/openshift/oc/oc.spec new file mode 100644 index 000000000000..a84087694a2c --- /dev/null +++ b/vendor/github.com/openshift/oc/oc.spec @@ -0,0 +1,126 @@ +#debuginfo not supported with Go +%global debug_package %{nil} +# modifying the Go binaries breaks the DWARF debugging +%global __os_install_post %{_rpmconfigdir}/brp-compress + +%global gopath %{_datadir}/gocode +%global import_path github.com/openshift/oc + +%global golang_version 1.12 +%global product_name OpenShift + +%{!?version: %global version 0.0.1} +%{!?release: %global release 1} + +Name: openshift-clients +Version: %{version} +Release: %{release}%{dist} +Summary: OpenShift client binaries +License: ASL 2.0 +URL: https://%{import_path} + +# If go_arches not defined fall through to implicit golang archs +%if 0%{?go_arches:1} +ExclusiveArch: %{go_arches} +%else +ExclusiveArch: x86_64 aarch64 ppc64le s390x +%endif + +#BuildRequires: bsdtar +BuildRequires: golang >= %{golang_version} +BuildRequires: krb5-devel +BuildRequires: rsync + +Provides: atomic-openshift-clients +Obsoletes: atomic-openshift-clients +Requires: bash-completion + +%description +%{summary} + +%package redistributable +Summary: OpenShift Client binaries for Linux, Mac OSX, and Windows +Provides: atomic-openshift-clients-redistributable +Obsoletes: atomic-openshift-clients-redistributable + +%description redistributable +%{summary} + +%prep + +%build +%ifarch x86_64 + # Create Binaries for all supported arches + make build cross-build +%else + %ifarch %{ix86} + GOOS=linux + GOARCH=386 + %endif + %ifarch ppc64le + GOOS=linux + GOARCH=ppc64le + %endif + %ifarch %{arm} aarch64 + GOOS=linux + GOARCH=arm64 + %endif + %ifarch s390x + GOOS=linux + GOARCH=s390x + %endif + %{source_git_vars} make build +%endif + +%install +install -d %{buildroot}%{_bindir} + + # Install for the local platform +install -p -m 755 oc %{buildroot}%{_bindir}/oc + +%ifarch x86_64 +# Install client executable for windows and mac +install -d %{buildroot}%{_datadir}/%{name}/{linux,macosx,windows} +install -p -m 755 ./oc %{buildroot}%{_datadir}/%{name}/linux/oc +install -p -m 755 ./_output/bin/darwin_amd64/oc %{buildroot}/%{_datadir}/%{name}/macosx/oc +install -p -m 755 ./_output/bin/windows_amd64/oc.exe %{buildroot}/%{_datadir}/%{name}/windows/oc.exe +%endif + +ln -s ./oc %{buildroot}%{_bindir}/kubectl + +# Install man1 man pages +install -d -m 0755 %{buildroot}%{_mandir}/man1 +./genman %{buildroot}%{_mandir}/man1 oc + + # Install bash completions +install -d -m 755 %{buildroot}%{_sysconfdir}/bash_completion.d/ +for bin in oc #kubectl +do + echo "+++ INSTALLING BASH COMPLETIONS FOR ${bin} " + %{buildroot}%{_bindir}/${bin} completion bash > %{buildroot}%{_sysconfdir}/bash_completion.d/${bin} + chmod 644 %{buildroot}%{_sysconfdir}/bash_completion.d/${bin} +done + +%files +%license LICENSE +%{_bindir}/oc +%{_bindir}/kubectl +%{_sysconfdir}/bash_completion.d/oc +#%{_sysconfdir}/bash_completion.d/kubectl +%{_mandir}/man1/oc* + +%ifarch x86_64 +%files redistributable +%license LICENSE +%dir %{_datadir}/%{name}/linux/ +%dir %{_datadir}/%{name}/macosx/ +%dir %{_datadir}/%{name}/windows/ +%{_datadir}/%{name}/linux/oc +#%{_datadir}/%{name}/linux/kubectl +%{_datadir}/%{name}/macosx/oc +#%{_datadir}/%{name}/macosx/kubectl +%{_datadir}/%{name}/windows/oc.exe +#%{_datadir}/%{name}/windows/kubectl.exe +%endif + +%changelog diff --git a/vendor/github.com/openshift/oc/pkg/cli/admin/policy/modify_roles.go b/vendor/github.com/openshift/oc/pkg/cli/admin/policy/modify_roles.go index b9bdaf62da09..b6b2862d4994 100644 --- a/vendor/github.com/openshift/oc/pkg/cli/admin/policy/modify_roles.go +++ b/vendor/github.com/openshift/oc/pkg/cli/admin/policy/modify_roles.go @@ -644,9 +644,13 @@ func (o *RoleModificationOptions) RemoveRole() error { if err != nil { return err } - } - if len(roleBindings) == 0 { - return fmt.Errorf("unable to locate RoleBinding %s for %s %q", o.RoleBindingName, o.RoleKind, o.RoleName) + if len(roleBindings) == 0 { + bindingType := "ClusterRoleBinding" + if len(o.RoleBindingNamespace) > 0 { + bindingType = "RoleBinding" + } + return fmt.Errorf("unable to locate any %s for %s %q", bindingType, o.RoleKind, o.RoleName) + } } subjectsToRemove := authorizationutil.BuildRBACSubjects(o.Users, o.Groups) diff --git a/vendor/github.com/openshift/oc/pkg/cli/admin/release/mirror.go b/vendor/github.com/openshift/oc/pkg/cli/admin/release/mirror.go index 51fe6f5af495..db45400846c0 100644 --- a/vendor/github.com/openshift/oc/pkg/cli/admin/release/mirror.go +++ b/vendor/github.com/openshift/oc/pkg/cli/admin/release/mirror.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/json" "fmt" + "io" "os" "sort" "strings" @@ -12,17 +13,20 @@ import ( digest "github.com/opencontainers/go-digest" "github.com/spf13/cobra" - "k8s.io/klog" - corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" "k8s.io/cli-runtime/pkg/genericclioptions" "k8s.io/client-go/util/retry" + "k8s.io/klog" kcmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" "k8s.io/kubernetes/pkg/kubectl/util/templates" + "sigs.k8s.io/yaml" imagev1 "github.com/openshift/api/image/v1" + operatorv1alpha1 "github.com/openshift/api/operator/v1alpha1" imageclient "github.com/openshift/client-go/image/clientset/versioned" "github.com/openshift/library-go/pkg/image/dockerv1client" imagereference "github.com/openshift/library-go/pkg/image/reference" @@ -269,6 +273,8 @@ func (o *MirrorOptions) Run() error { } } + repositories := make(map[string]struct{}) + // build the mapping list for mirroring and rewrite if necessary for i := range is.Spec.Tags { tag := &is.Spec.Tags[i] @@ -283,6 +289,10 @@ func (o *MirrorOptions) Run() error { return fmt.Errorf("image-references should only contain pointers to images by digest: %s", tag.From.Name) } + // Create a unique map of repos as keys + currentRepo := from.AsRepository().String() + repositories[currentRepo] = struct{}{} + dstMirrorRef := targetFn(tag.Name) mappings = append(mappings, mirror.Mapping{ Source: from, @@ -442,18 +452,82 @@ func (o *MirrorOptions) Run() error { } else { fmt.Fprintf(o.Out, "\nSuccess\nUpdate image: %s\nMirrored to: %s\n", to, o.To) } + + if err := printImageContentInstructions(o.Out, o.From, o.To, repositories); err != nil { + return fmt.Errorf("Error creating mirror usage instructions: %v", err) + } return nil } -func sourceImageRef(is *imagev1.ImageStream, name string) (string, bool) { - for _, tag := range is.Spec.Tags { - if tag.Name != name { - continue - } - if tag.From == nil || tag.From.Kind != "DockerImage" { - return "", false - } - return tag.From.Name, true +// printImageContentInstructions provides exapmles to the user for using the new repository mirror +// https://github.com/openshift/installer/blob/master/docs/dev/alternative_release_image_sources.md +func printImageContentInstructions(out io.Writer, from, to string, repositories map[string]struct{}) error { + type installConfigSubsection struct { + ImageContentSources []operatorv1alpha1.RepositoryDigestMirrors `json:"imageContentSources"` } - return "", false + + var sources []operatorv1alpha1.RepositoryDigestMirrors + + mirrorRef, err := imagereference.Parse(to) + if err != nil { + return fmt.Errorf("Unable to parse image reference '%s': %v", to, err) + } + mirrorRepo := mirrorRef.AsRepository().String() + + sourceRef, err := imagereference.Parse(from) + if err != nil { + return fmt.Errorf("Unable to parse image reference '%s': %v", from, err) + } + sourceRepo := sourceRef.AsRepository().String() + repositories[sourceRepo] = struct{}{} + + for repository := range repositories { + sources = append(sources, operatorv1alpha1.RepositoryDigestMirrors{ + Source: repository, + Mirrors: []string{mirrorRepo}, + }) + } + sort.Slice(sources, func(i, j int) bool { + return sources[i].Source < sources[j].Source + }) + + // Create and display install-config.yaml example + imageContentSources := installConfigSubsection{ + ImageContentSources: sources} + installConfigExample, err := yaml.Marshal(imageContentSources) + if err != nil { + return fmt.Errorf("Unable to marshal install-config.yaml example yaml: %v", err) + } + fmt.Fprintf(out, "\nTo use the new mirrored repository to install, add the following section to the install-config.yaml:\n\n") + fmt.Fprintf(out, string(installConfigExample)) + + // Create and display ImageContentSourcePolicy example + icsp := operatorv1alpha1.ImageContentSourcePolicy{ + TypeMeta: metav1.TypeMeta{ + APIVersion: operatorv1alpha1.GroupVersion.String(), + Kind: "ImageContentSourcePolicy"}, + ObjectMeta: metav1.ObjectMeta{ + Name: "example", + }, + Spec: operatorv1alpha1.ImageContentSourcePolicySpec{ + RepositoryDigestMirrors: sources, + }, + } + + // Create an unstructured object for removing creationTimestamp + unstructuredObj := unstructured.Unstructured{} + unstructuredObj.Object, err = runtime.DefaultUnstructuredConverter.ToUnstructured(&icsp) + if err != nil { + return fmt.Errorf("ToUnstructured error: %v", err) + } + delete(unstructuredObj.Object["metadata"].(map[string]interface{}), "creationTimestamp") + + icspExample, err := yaml.Marshal(unstructuredObj.Object) + if err != nil { + return fmt.Errorf("Unable to marshal ImageContentSourcePolicy example yaml: %v", err) + } + fmt.Fprintf(out, "\n\nTo use the new mirrored repository for upgrades, use the following to create an ImageContentSourcePolicy:\n\n") + fmt.Fprintf(out, string(icspExample)) + + return nil } diff --git a/vendor/github.com/spf13/cobra/.circleci/config.yml b/vendor/github.com/spf13/cobra/.circleci/config.yml index 136e17f0ee92..819446439a2d 100644 --- a/vendor/github.com/spf13/cobra/.circleci/config.yml +++ b/vendor/github.com/spf13/cobra/.circleci/config.yml @@ -1,38 +1,53 @@ -workflows: - version: 2 - main: - jobs: - - go-current - - go-previous - - go-latest -base: &base - working_directory: /go/src/github.com/spf13/cobra - steps: - - checkout - - run: - name: "All Commands" - command: | - mkdir -p bin - curl -Lso bin/shellcheck https://github.com/caarlos0/shellcheck-docker/releases/download/v0.4.3/shellcheck - chmod +x bin/shellcheck - go get -t -v ./... - PATH=$PATH:$PWD/bin go test -v ./... - go build - diff -u <(echo -n) <(gofmt -d -s .) - if [ -z $NOVET ]; then - diff -u <(echo -n) <(go tool vet . 2>&1 | grep -vE 'ExampleCommand|bash_completions.*Fprint'); - fi version: 2 + +references: + workspace: &workspace + /go/src/github.com/spf13/cobra + + run_tests: &run_tests + run: + name: "All Commands" + command: | + mkdir -p bin + curl -Lso bin/shellcheck https://github.com/caarlos0/shellcheck-docker/releases/download/v0.4.6/shellcheck + chmod +x bin/shellcheck + go get -t -v ./... + PATH=$PATH:$PWD/bin go test -v ./... + go build + if [ -z $NOVET ]; then + diff -u <(echo -n) <(go vet . 2>&1 | grep -vE 'ExampleCommand|bash_completions.*Fprint'); + fi + jobs: go-current: docker: - - image: circleci/golang:1.8.3 - <<: *base + - image: circleci/golang:1.12 + working_directory: *workspace + steps: + - checkout + - *run_tests + - run: + name: "Check formatting" + command: diff -u <(echo -n) <(gofmt -d -s .) go-previous: docker: - - image: circleci/golang:1.7.6 - <<: *base + - image: circleci/golang:1.11 + working_directory: *workspace + steps: + - checkout + - *run_tests go-latest: docker: - image: circleci/golang:latest - <<: *base + working_directory: *workspace + steps: + - checkout + - *run_tests + +workflows: + version: 2 + main: + jobs: + - go-current + - go-previous + - go-latest diff --git a/vendor/github.com/spf13/cobra/.gitignore b/vendor/github.com/spf13/cobra/.gitignore index 1b8c7c261167..b2b848e77c19 100644 --- a/vendor/github.com/spf13/cobra/.gitignore +++ b/vendor/github.com/spf13/cobra/.gitignore @@ -32,5 +32,8 @@ Session.vim tags *.exe - +cobra cobra.test + +.idea/ +*.iml diff --git a/vendor/github.com/spf13/cobra/.travis.yml b/vendor/github.com/spf13/cobra/.travis.yml index 68efa136331d..38b85f499ca8 100644 --- a/vendor/github.com/spf13/cobra/.travis.yml +++ b/vendor/github.com/spf13/cobra/.travis.yml @@ -1,21 +1,31 @@ language: go +stages: + - diff + - test + +go: + - 1.10.x + - 1.11.x + - 1.12.x + - tip + matrix: - include: - - go: 1.7.6 - - go: 1.8.3 - - go: tip allow_failures: - go: tip + include: + - stage: diff + go: 1.12.x + script: diff -u <(echo -n) <(gofmt -d -s .) before_install: - mkdir -p bin - - curl -Lso bin/shellcheck https://github.com/caarlos0/shellcheck-docker/releases/download/v0.4.3/shellcheck + - curl -Lso bin/shellcheck https://github.com/caarlos0/shellcheck-docker/releases/download/v0.6.0/shellcheck - chmod +x bin/shellcheck + - go get -u github.com/kyoh86/richgo script: - - PATH=$PATH:$PWD/bin go test -v ./... + - PATH=$PATH:$PWD/bin richgo test -v ./... - go build - - diff -u <(echo -n) <(gofmt -d -s .) - if [ -z $NOVET ]; then - diff -u <(echo -n) <(go tool vet . 2>&1 | grep -vE 'ExampleCommand|bash_completions.*Fprint'); + diff -u <(echo -n) <(go vet . 2>&1 | grep -vE 'ExampleCommand|bash_completions.*Fprint'); fi diff --git a/vendor/github.com/spf13/cobra/README.md b/vendor/github.com/spf13/cobra/README.md index 851fcc087cae..649e2e2f751c 100644 --- a/vendor/github.com/spf13/cobra/README.md +++ b/vendor/github.com/spf13/cobra/README.md @@ -2,25 +2,30 @@ Cobra is both a library for creating powerful modern CLI applications as well as a program to generate applications and command files. -Many of the most widely used Go projects are built using Cobra including: - -* [Kubernetes](http://kubernetes.io/) -* [Hugo](http://gohugo.io) -* [rkt](https://github.com/coreos/rkt) -* [etcd](https://github.com/coreos/etcd) -* [Moby (former Docker)](https://github.com/moby/moby) -* [Docker (distribution)](https://github.com/docker/distribution) -* [OpenShift](https://www.openshift.com/) -* [Delve](https://github.com/derekparker/delve) -* [GopherJS](http://www.gopherjs.org/) -* [CockroachDB](http://www.cockroachlabs.com/) -* [Bleve](http://www.blevesearch.com/) -* [ProjectAtomic (enterprise)](http://www.projectatomic.io/) -* [GiantSwarm's swarm](https://github.com/giantswarm/cli) -* [Nanobox](https://github.com/nanobox-io/nanobox)/[Nanopack](https://github.com/nanopack) -* [rclone](http://rclone.org/) -* [nehm](https://github.com/bogem/nehm) -* [Pouch](https://github.com/alibaba/pouch) +Many of the most widely used Go projects are built using Cobra, such as: +[Kubernetes](http://kubernetes.io/), +[Hugo](http://gohugo.io), +[rkt](https://github.com/coreos/rkt), +[etcd](https://github.com/coreos/etcd), +[Moby (former Docker)](https://github.com/moby/moby), +[Docker (distribution)](https://github.com/docker/distribution), +[OpenShift](https://www.openshift.com/), +[Delve](https://github.com/derekparker/delve), +[GopherJS](http://www.gopherjs.org/), +[CockroachDB](http://www.cockroachlabs.com/), +[Bleve](http://www.blevesearch.com/), +[ProjectAtomic (enterprise)](http://www.projectatomic.io/), +[Giant Swarm's gsctl](https://github.com/giantswarm/gsctl), +[Nanobox](https://github.com/nanobox-io/nanobox)/[Nanopack](https://github.com/nanopack), +[rclone](http://rclone.org/), +[nehm](https://github.com/bogem/nehm), +[Pouch](https://github.com/alibaba/pouch), +[Istio](https://istio.io), +[Prototool](https://github.com/uber/prototool), +[mattermost-server](https://github.com/mattermost/mattermost-server), +[Gardener](https://github.com/gardener/gardenctl), +[Linkerd](https://linkerd.io/), +etc. [![Build Status](https://travis-ci.org/spf13/cobra.svg "Travis CI status")](https://travis-ci.org/spf13/cobra) [![CircleCI status](https://circleci.com/gh/spf13/cobra.png?circle-token=:circle-token "CircleCI status")](https://circleci.com/gh/spf13/cobra) @@ -45,6 +50,7 @@ Many of the most widely used Go projects are built using Cobra including: * [Suggestions when "unknown command" happens](#suggestions-when-unknown-command-happens) * [Generating documentation for your command](#generating-documentation-for-your-command) * [Generating bash completions](#generating-bash-completions) + * [Generating zsh completions](#generating-zsh-completions) - [Contributing](#contributing) - [License](#license) @@ -152,9 +158,6 @@ In a Cobra app, typically the main.go file is very bare. It serves one purpose: package main import ( - "fmt" - "os" - "{pathToYourApp}/cmd" ) @@ -215,6 +218,8 @@ import ( "github.com/spf13/viper" ) +var cfgFile string + func init() { cobra.OnInitialize(initConfig) rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.cobra.yaml)") @@ -265,9 +270,6 @@ In a Cobra app, typically the main.go file is very bare. It serves, one purpose, package main import ( - "fmt" - "os" - "{pathToYourApp}/cmd" ) @@ -339,7 +341,7 @@ rootCmd.PersistentFlags().BoolVarP(&Verbose, "verbose", "v", false, "verbose out A flag can also be assigned locally which will only apply to that specific command. ```go -rootCmd.Flags().StringVarP(&Source, "source", "s", "", "Source directory to read from") +localCmd.Flags().StringVarP(&Source, "source", "s", "", "Source directory to read from") ``` ### Local Flag on Parent Commands @@ -395,6 +397,7 @@ The following validators are built in: - `MinimumNArgs(int)` - the command will report an error if there are not at least N positional args. - `MaximumNArgs(int)` - the command will report an error if there are more than N positional args. - `ExactArgs(int)` - the command will report an error if there are not exactly N positional args. +- `ExactValidArgs(int)` - the command will report an error if there are not exactly N positional args OR if there are any positional args that are not in the `ValidArgs` field of `Command` - `RangeArgs(min, max)` - the command will report an error if the number of args is not between the minimum and maximum number of expected args. An example of setting the custom validator: @@ -404,7 +407,7 @@ var cmd = &cobra.Command{ Short: "hello", Args: func(cmd *cobra.Command, args []string) error { if len(args) < 1 { - return errors.New("requires at least one arg") + return errors.New("requires a color argument") } if myapp.IsValidColor(args[0]) { return nil @@ -464,7 +467,7 @@ Echo works a lot like print, except it has a child command.`, } var cmdTimes = &cobra.Command{ - Use: "times [# times] [string to echo]", + Use: "times [string to echo]", Short: "Echo anything to the screen more times", Long: `echo things multiple times back to the user by providing a count and a string.`, @@ -721,6 +724,11 @@ Cobra can generate documentation based on subcommands, flags, etc. in the follow Cobra can generate a bash-completion file. If you add more information to your command, these completions can be amazingly powerful and flexible. Read more about it in [Bash Completions](bash_completions.md). +## Generating zsh completions + +Cobra can generate zsh-completion file. Read more about it in +[Zsh Completions](zsh_completions.md). + # Contributing 1. Fork it diff --git a/vendor/github.com/spf13/cobra/args.go b/vendor/github.com/spf13/cobra/args.go index a5d8a9273eab..c4d820b85313 100644 --- a/vendor/github.com/spf13/cobra/args.go +++ b/vendor/github.com/spf13/cobra/args.go @@ -78,6 +78,18 @@ func ExactArgs(n int) PositionalArgs { } } +// ExactValidArgs returns an error if +// there are not exactly N positional args OR +// there are any positional args that are not in the `ValidArgs` field of `Command` +func ExactValidArgs(n int) PositionalArgs { + return func(cmd *Command, args []string) error { + if err := ExactArgs(n)(cmd, args); err != nil { + return err + } + return OnlyValidArgs(cmd, args) + } +} + // RangeArgs returns an error if the number of args is not within the expected range. func RangeArgs(min int, max int) PositionalArgs { return func(cmd *Command, args []string) error { diff --git a/vendor/github.com/spf13/cobra/args_test.go b/vendor/github.com/spf13/cobra/args_test.go index d797b6f5876e..c81b212eceba 100644 --- a/vendor/github.com/spf13/cobra/args_test.go +++ b/vendor/github.com/spf13/cobra/args_test.go @@ -158,6 +158,52 @@ func TestExactArgsWithInvalidCount(t *testing.T) { } } +func TestExactValidArgs(t *testing.T) { + c := &Command{Use: "c", Args: ExactValidArgs(3), ValidArgs: []string{"a", "b", "c"}, Run: emptyRun} + output, err := executeCommand(c, "a", "b", "c") + if output != "" { + t.Errorf("Unexpected output: %v", output) + } + if err != nil { + t.Errorf("Unexpected error: %v", err) + } +} + +func TestExactValidArgsWithInvalidCount(t *testing.T) { + c := &Command{Use: "c", Args: ExactValidArgs(2), Run: emptyRun} + _, err := executeCommand(c, "a", "b", "c") + + if err == nil { + t.Fatal("Expected an error") + } + + got := err.Error() + expected := "accepts 2 arg(s), received 3" + if got != expected { + t.Fatalf("Expected %q, got %q", expected, got) + } +} + +func TestExactValidArgsWithInvalidArgs(t *testing.T) { + c := &Command{ + Use: "c", + Args: ExactValidArgs(1), + ValidArgs: []string{"one", "two"}, + Run: emptyRun, + } + + _, err := executeCommand(c, "three") + if err == nil { + t.Fatal("Expected an error") + } + + got := err.Error() + expected := `invalid argument "three" for "c"` + if got != expected { + t.Errorf("Expected: %q, got: %q", expected, got) + } +} + func TestRangeArgs(t *testing.T) { c := &Command{Use: "c", Args: RangeArgs(2, 4), Run: emptyRun} output, err := executeCommand(c, "a", "b", "c") diff --git a/vendor/github.com/spf13/cobra/bash_completions.go b/vendor/github.com/spf13/cobra/bash_completions.go index 291eae7d8e5b..03ddda27a3a2 100644 --- a/vendor/github.com/spf13/cobra/bash_completions.go +++ b/vendor/github.com/spf13/cobra/bash_completions.go @@ -72,7 +72,9 @@ __%[1]s_handle_reply() else allflags=("${flags[*]} ${two_word_flags[*]}") fi - COMPREPLY=( $(compgen -W "${allflags[*]}" -- "$cur") ) + while IFS='' read -r c; do + COMPREPLY+=("$c") + done < <(compgen -W "${allflags[*]}" -- "$cur") if [[ $(type -t compopt) = "builtin" ]]; then [[ "${COMPREPLY[0]}" == *= ]] || compopt +o nospace fi @@ -122,14 +124,24 @@ __%[1]s_handle_reply() if [[ ${#must_have_one_flag[@]} -ne 0 ]]; then completions+=("${must_have_one_flag[@]}") fi - COMPREPLY=( $(compgen -W "${completions[*]}" -- "$cur") ) + while IFS='' read -r c; do + COMPREPLY+=("$c") + done < <(compgen -W "${completions[*]}" -- "$cur") if [[ ${#COMPREPLY[@]} -eq 0 && ${#noun_aliases[@]} -gt 0 && ${#must_have_one_noun[@]} -ne 0 ]]; then - COMPREPLY=( $(compgen -W "${noun_aliases[*]}" -- "$cur") ) + while IFS='' read -r c; do + COMPREPLY+=("$c") + done < <(compgen -W "${noun_aliases[*]}" -- "$cur") fi if [[ ${#COMPREPLY[@]} -eq 0 ]]; then - declare -F __custom_func >/dev/null && __custom_func + if declare -F __%[1]s_custom_func >/dev/null; then + # try command name qualified custom func + __%[1]s_custom_func + else + # otherwise fall back to unqualified for compatibility + declare -F __custom_func >/dev/null && __custom_func + fi fi # available in bash-completion >= 2, not always present on macOS @@ -154,7 +166,7 @@ __%[1]s_handle_filename_extension_flag() __%[1]s_handle_subdirs_in_dir_flag() { local dir="$1" - pushd "${dir}" >/dev/null 2>&1 && _filedir -d && popd >/dev/null 2>&1 + pushd "${dir}" >/dev/null 2>&1 && _filedir -d && popd >/dev/null 2>&1 || return } __%[1]s_handle_flag() @@ -193,7 +205,8 @@ __%[1]s_handle_flag() fi # skip the argument to a two word flag - if __%[1]s_contains_word "${words[c]}" "${two_word_flags[@]}"; then + if [[ ${words[c]} != *"="* ]] && __%[1]s_contains_word "${words[c]}" "${two_word_flags[@]}"; then + __%[1]s_debug "${FUNCNAME[0]}: found a flag ${words[c]}, skip the next argument" c=$((c+1)) # if we are looking for a flags value, don't show commands if [[ $c -eq $cword ]]; then @@ -251,6 +264,14 @@ __%[1]s_handle_word() __%[1]s_handle_command elif [[ $c -eq 0 ]]; then __%[1]s_handle_command + elif __%[1]s_contains_word "${words[c]}" "${command_aliases[@]}"; then + # aliashash variable is an associative array which is only supported in bash > 3. + if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + words[c]=${aliashash[${words[c]}]} + __%[1]s_handle_command + else + __%[1]s_handle_noun + fi else __%[1]s_handle_noun fi @@ -266,6 +287,7 @@ func writePostscript(buf *bytes.Buffer, name string) { buf.WriteString(fmt.Sprintf(`{ local cur prev words cword declare -A flaghash 2>/dev/null || : + declare -A aliashash 2>/dev/null || : if declare -F _init_completion >/dev/null 2>&1; then _init_completion -s || return else @@ -305,6 +327,7 @@ func writeCommands(buf *bytes.Buffer, cmd *Command) { continue } buf.WriteString(fmt.Sprintf(" commands+=(%q)\n", c.Name())) + writeCmdAliases(buf, c) } buf.WriteString("\n") } @@ -363,6 +386,10 @@ func writeFlag(buf *bytes.Buffer, flag *pflag.Flag, cmd *Command) { } format += "\")\n" buf.WriteString(fmt.Sprintf(format, name)) + if len(flag.NoOptDefVal) == 0 { + format = " two_word_flags+=(\"--%s\")\n" + buf.WriteString(fmt.Sprintf(format, name)) + } writeFlagHandler(buf, "--"+name, flag.Annotations, cmd) } @@ -443,6 +470,21 @@ func writeRequiredNouns(buf *bytes.Buffer, cmd *Command) { } } +func writeCmdAliases(buf *bytes.Buffer, cmd *Command) { + if len(cmd.Aliases) == 0 { + return + } + + sort.Sort(sort.StringSlice(cmd.Aliases)) + + buf.WriteString(fmt.Sprint(` if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then`, "\n")) + for _, value := range cmd.Aliases { + buf.WriteString(fmt.Sprintf(" command_aliases+=(%q)\n", value)) + buf.WriteString(fmt.Sprintf(" aliashash[%q]=%q\n", value, cmd.Name())) + } + buf.WriteString(` fi`) + buf.WriteString("\n") +} func writeArgAliases(buf *bytes.Buffer, cmd *Command) { buf.WriteString(" noun_aliases=()\n") sort.Sort(sort.StringSlice(cmd.ArgAliases)) @@ -469,6 +511,10 @@ func gen(buf *bytes.Buffer, cmd *Command) { } buf.WriteString(fmt.Sprintf(" last_command=%q\n", commandName)) + buf.WriteString("\n") + buf.WriteString(" command_aliases=()\n") + buf.WriteString("\n") + writeCommands(buf, cmd) writeFlags(buf, cmd) writeRequiredFlag(buf, cmd) @@ -505,51 +551,3 @@ func (c *Command) GenBashCompletionFile(filename string) error { return c.GenBashCompletion(outFile) } - -// MarkFlagRequired adds the BashCompOneRequiredFlag annotation to the named flag if it exists, -// and causes your command to report an error if invoked without the flag. -func (c *Command) MarkFlagRequired(name string) error { - return MarkFlagRequired(c.Flags(), name) -} - -// MarkPersistentFlagRequired adds the BashCompOneRequiredFlag annotation to the named persistent flag if it exists, -// and causes your command to report an error if invoked without the flag. -func (c *Command) MarkPersistentFlagRequired(name string) error { - return MarkFlagRequired(c.PersistentFlags(), name) -} - -// MarkFlagRequired adds the BashCompOneRequiredFlag annotation to the named flag if it exists, -// and causes your command to report an error if invoked without the flag. -func MarkFlagRequired(flags *pflag.FlagSet, name string) error { - return flags.SetAnnotation(name, BashCompOneRequiredFlag, []string{"true"}) -} - -// MarkFlagFilename adds the BashCompFilenameExt annotation to the named flag, if it exists. -// Generated bash autocompletion will select filenames for the flag, limiting to named extensions if provided. -func (c *Command) MarkFlagFilename(name string, extensions ...string) error { - return MarkFlagFilename(c.Flags(), name, extensions...) -} - -// MarkFlagCustom adds the BashCompCustom annotation to the named flag, if it exists. -// Generated bash autocompletion will call the bash function f for the flag. -func (c *Command) MarkFlagCustom(name string, f string) error { - return MarkFlagCustom(c.Flags(), name, f) -} - -// MarkPersistentFlagFilename adds the BashCompFilenameExt annotation to the named persistent flag, if it exists. -// Generated bash autocompletion will select filenames for the flag, limiting to named extensions if provided. -func (c *Command) MarkPersistentFlagFilename(name string, extensions ...string) error { - return MarkFlagFilename(c.PersistentFlags(), name, extensions...) -} - -// MarkFlagFilename adds the BashCompFilenameExt annotation to the named flag in the flag set, if it exists. -// Generated bash autocompletion will select filenames for the flag, limiting to named extensions if provided. -func MarkFlagFilename(flags *pflag.FlagSet, name string, extensions ...string) error { - return flags.SetAnnotation(name, BashCompFilenameExt, extensions) -} - -// MarkFlagCustom adds the BashCompCustom annotation to the named flag in the flag set, if it exists. -// Generated bash autocompletion will call the bash function f for the flag. -func MarkFlagCustom(flags *pflag.FlagSet, name string, f string) error { - return flags.SetAnnotation(name, BashCompCustom, []string{f}) -} diff --git a/vendor/github.com/spf13/cobra/bash_completions.md b/vendor/github.com/spf13/cobra/bash_completions.md index 8d01f456f8a1..4ac61ee132a4 100644 --- a/vendor/github.com/spf13/cobra/bash_completions.md +++ b/vendor/github.com/spf13/cobra/bash_completions.md @@ -1,5 +1,40 @@ # Generating Bash Completions For Your Own cobra.Command +If you are using the generator you can create a completion command by running + +```bash +cobra add completion +``` + +Update the help text show how to install the bash_completion Linux show here [Kubectl docs show mac options](https://kubernetes.io/docs/tasks/tools/install-kubectl/#enabling-shell-autocompletion) + +Writing the shell script to stdout allows the most flexible use. + +```go +// completionCmd represents the completion command +var completionCmd = &cobra.Command{ + Use: "completion", + Short: "Generates bash completion scripts", + Long: `To load completion run + +. <(bitbucket completion) + +To configure your bash shell to load completions for each session add to your bashrc + +# ~/.bashrc or ~/.profile +. <(bitbucket completion) +`, + Run: func(cmd *cobra.Command, args []string) { + rootCmd.GenBashCompletion(os.Stdout); + }, +} +``` + +**Note:** The cobra generator may include messages printed to stdout for example if the config file is loaded, this will break the auto complete script + + +## Example from kubectl + Generating bash completions from a cobra command is incredibly easy. An actual program which does so for the kubernetes kubectl binary is as follows: ```go @@ -47,7 +82,7 @@ __kubectl_get_resource() fi } -__custom_func() { +__kubectl_custom_func() { case ${last_command} in kubectl_get | kubectl_describe | kubectl_delete | kubectl_stop) __kubectl_get_resource @@ -74,7 +109,7 @@ Find more information at https://github.com/GoogleCloudPlatform/kubernetes.`, } ``` -The `BashCompletionFunction` option is really only valid/useful on the root command. Doing the above will cause `__custom_func()` to be called when the built in processor was unable to find a solution. In the case of kubernetes a valid command might look something like `kubectl get pod [mypod]`. If you type `kubectl get pod [tab][tab]` the `__customc_func()` will run because the cobra.Command only understood "kubectl" and "get." `__custom_func()` will see that the cobra.Command is "kubectl_get" and will thus call another helper `__kubectl_get_resource()`. `__kubectl_get_resource` will look at the 'nouns' collected. In our example the only noun will be `pod`. So it will call `__kubectl_parse_get pod`. `__kubectl_parse_get` will actually call out to kubernetes and get any pods. It will then set `COMPREPLY` to valid pods! +The `BashCompletionFunction` option is really only valid/useful on the root command. Doing the above will cause `__kubectl_custom_func()` (`___custom_func()`) to be called when the built in processor was unable to find a solution. In the case of kubernetes a valid command might look something like `kubectl get pod [mypod]`. If you type `kubectl get pod [tab][tab]` the `__kubectl_customc_func()` will run because the cobra.Command only understood "kubectl" and "get." `__kubectl_custom_func()` will see that the cobra.Command is "kubectl_get" and will thus call another helper `__kubectl_get_resource()`. `__kubectl_get_resource` will look at the 'nouns' collected. In our example the only noun will be `pod`. So it will call `__kubectl_parse_get pod`. `__kubectl_parse_get` will actually call out to kubernetes and get any pods. It will then set `COMPREPLY` to valid pods! ## Have the completions code complete your 'nouns' @@ -181,7 +216,7 @@ a custom flag completion function with cobra.BashCompCustom: ```go annotation := make(map[string][]string) - annotation[cobra.BashCompFilenameExt] = []string{"__kubectl_get_namespaces"} + annotation[cobra.BashCompCustom] = []string{"__kubectl_get_namespaces"} flag := &pflag.Flag{ Name: "namespace", diff --git a/vendor/github.com/spf13/cobra/bash_completions_test.go b/vendor/github.com/spf13/cobra/bash_completions_test.go index 02a4f15baaa9..eefa3de0772e 100644 --- a/vendor/github.com/spf13/cobra/bash_completions_test.go +++ b/vendor/github.com/spf13/cobra/bash_completions_test.go @@ -22,6 +22,13 @@ func check(t *testing.T, found, expected string) { } } +func checkNumOccurrences(t *testing.T, found, expected string, expectedOccurrences int) { + numOccurrences := strings.Count(found, expected) + if numOccurrences != expectedOccurrences { + t.Errorf("Expecting to contain %d occurrences of: \n %q\nGot %d:\n %q\n", expectedOccurrences, expected, numOccurrences, found) + } +} + func checkRegex(t *testing.T, found, pattern string) { matched, err := regexp.MatchString(pattern, found) if err != nil { @@ -53,7 +60,7 @@ func runShellCheck(s string) error { } // World worst custom function, just keep telling you to enter hello! -const bashCompletionFunc = `__custom_func() { +const bashCompletionFunc = `__root_custom_func() { COMPREPLY=( "hello" ) } ` @@ -64,7 +71,7 @@ func TestBashCompletions(t *testing.T) { ArgAliases: []string{"pods", "nodes", "services", "replicationcontrollers", "po", "no", "svc", "rc"}, ValidArgs: []string{"pod", "node", "service", "replicationcontroller"}, BashCompletionFunction: bashCompletionFunc, - Run: emptyRun, + Run: emptyRun, } rootCmd.Flags().IntP("introot", "i", -1, "help message for flag introot") rootCmd.MarkFlagRequired("introot") @@ -88,6 +95,10 @@ func TestBashCompletions(t *testing.T) { rootCmd.Flags().String("theme", "", "theme to use (located in /themes/THEMENAME/)") rootCmd.Flags().SetAnnotation("theme", BashCompSubdirsInDir, []string{"themes"}) + // For two word flags check + rootCmd.Flags().StringP("two", "t", "", "this is two word flags") + rootCmd.Flags().BoolP("two-w-default", "T", false, "this is not two word flags") + echoCmd := &Command{ Use: "echo [string to echo]", Aliases: []string{"say"}, @@ -150,7 +161,10 @@ func TestBashCompletions(t *testing.T) { // check for required flags check(t, output, `must_have_one_flag+=("--introot=")`) check(t, output, `must_have_one_flag+=("--persistent-filename=")`) - // check for custom completion function + // check for custom completion function with both qualified and unqualified name + checkNumOccurrences(t, output, `__custom_func`, 2) // 1. check existence, 2. invoke + checkNumOccurrences(t, output, `__root_custom_func`, 3) // 1. check existence, 2. invoke, 3. actual definition + // check for custom completion function body check(t, output, `COMPREPLY=( "hello" )`) // check for required nouns check(t, output, `must_have_one_noun+=("pod")`) @@ -173,6 +187,12 @@ func TestBashCompletions(t *testing.T) { // check for subdirs_in_dir flags in a subcommand checkRegex(t, output, fmt.Sprintf(`_root_echo\(\)\n{[^}]*flags_completion\+=\("__%s_handle_subdirs_in_dir_flag config"\)`, rootCmd.Name())) + // check two word flags + check(t, output, `two_word_flags+=("--two")`) + check(t, output, `two_word_flags+=("-t")`) + checkOmit(t, output, `two_word_flags+=("--two-w-default")`) + checkOmit(t, output, `two_word_flags+=("-T")`) + checkOmit(t, output, deprecatedCmd.Name()) // If available, run shellcheck against the script. diff --git a/vendor/github.com/spf13/cobra/cobra.go b/vendor/github.com/spf13/cobra/cobra.go index 7010fd15b723..d01becc8fa6c 100644 --- a/vendor/github.com/spf13/cobra/cobra.go +++ b/vendor/github.com/spf13/cobra/cobra.go @@ -23,6 +23,7 @@ import ( "strconv" "strings" "text/template" + "time" "unicode" ) @@ -51,11 +52,17 @@ var EnableCommandSorting = true // if the CLI is started from explorer.exe. // To disable the mousetrap, just set this variable to blank string (""). // Works only on Microsoft Windows. -var MousetrapHelpText string = `This is a command line tool. +var MousetrapHelpText = `This is a command line tool. You need to open cmd.exe and run it from there. ` +// MousetrapDisplayDuration controls how long the MousetrapHelpText message is displayed on Windows +// if the CLI is started from explorer.exe. Set to 0 to wait for the return key to be pressed. +// To disable the mousetrap, just set MousetrapHelpText to blank string (""). +// Works only on Microsoft Windows. +var MousetrapDisplayDuration = 5 * time.Second + // AddTemplateFunc adds a template function that's available to Usage and Help // template generation. func AddTemplateFunc(name string, tmplFunc interface{}) { diff --git a/vendor/github.com/spf13/cobra/cobra/README.md b/vendor/github.com/spf13/cobra/cobra/README.md index 6054f95c52ff..c360fdaca34b 100644 --- a/vendor/github.com/spf13/cobra/cobra/README.md +++ b/vendor/github.com/spf13/cobra/cobra/README.md @@ -16,11 +16,23 @@ for you. It is a very powerful application that will populate your program with the right structure so you can immediately enjoy all the benefits of Cobra. It will also automatically apply the license you specify to your application. -Cobra init is pretty smart. You can provide it a full path, or simply a path -similar to what is expected in the import. +Cobra init is pretty smart. You can either run it in your current application directory +or you can specify a relative path to an existing project. If the directory does not exist, it will be created for you. + +Updates to the Cobra generator have now decoupled it from the GOPATH. +As such `--pkg-name` is required. + +**Note:** init will no longer fail on non-empty directories. + +``` +mkdir -p newApp && cd newApp +cobra init --pkg-name github.com/spf13/newApp +``` + +or ``` -cobra init github.com/spf13/newApp +cobra init --pkg-name github.com/spf13/newApp path/to/newApp ``` ### cobra add diff --git a/vendor/github.com/spf13/cobra/cobra/cmd/add.go b/vendor/github.com/spf13/cobra/cobra/cmd/add.go index fb22096a39a5..6645a755f09c 100644 --- a/vendor/github.com/spf13/cobra/cobra/cmd/add.go +++ b/vendor/github.com/spf13/cobra/cobra/cmd/add.go @@ -16,24 +16,20 @@ package cmd import ( "fmt" "os" - "path/filepath" "unicode" "github.com/spf13/cobra" ) -func init() { - addCmd.Flags().StringVarP(&packageName, "package", "t", "", "target package name (e.g. github.com/spf13/hugo)") - addCmd.Flags().StringVarP(&parentName, "parent", "p", "rootCmd", "variable name of parent command for this command") -} - -var packageName, parentName string +var ( + packageName string + parentName string -var addCmd = &cobra.Command{ - Use: "add [command name]", - Aliases: []string{"command"}, - Short: "Add a command to a Cobra Application", - Long: `Add (cobra add) will create a new command, with a license and + addCmd = &cobra.Command{ + Use: "add [command name]", + Aliases: []string{"command"}, + Short: "Add a command to a Cobra Application", + Long: `Add (cobra add) will create a new command, with a license and the appropriate structure for a Cobra-based CLI application, and register it to its parent (default rootCmd). @@ -42,28 +38,41 @@ with an initial uppercase letter. Example: cobra add server -> resulting in a new cmd/server.go`, - Run: func(cmd *cobra.Command, args []string) { - if len(args) < 1 { - er("add needs a name for the command") - } + Run: func(cmd *cobra.Command, args []string) { + if len(args) < 1 { + er("add needs a name for the command") + } - var project *Project - if packageName != "" { - project = NewProject(packageName) - } else { wd, err := os.Getwd() if err != nil { er(err) } - project = NewProjectFromPath(wd) - } - cmdName := validateCmdName(args[0]) - cmdPath := filepath.Join(project.CmdPath(), cmdName+".go") - createCmdFile(project.License(), cmdPath, cmdName) + commandName := validateCmdName(args[0]) + command := &Command{ + CmdName: commandName, + CmdParent: parentName, + Project: &Project{ + AbsolutePath: wd, + Legal: getLicense(), + Copyright: copyrightLine(), + }, + } - fmt.Fprintln(cmd.OutOrStdout(), cmdName, "created at", cmdPath) - }, + err = command.Create() + if err != nil { + er(err) + } + + fmt.Printf("%s created at %s\n", command.CmdName, command.AbsolutePath) + }, + } +) + +func init() { + addCmd.Flags().StringVarP(&packageName, "package", "t", "", "target package name (e.g. github.com/spf13/hugo)") + addCmd.Flags().StringVarP(&parentName, "parent", "p", "rootCmd", "variable name of parent command for this command") + addCmd.Flags().MarkDeprecated("package", "this operation has been removed.") } // validateCmdName returns source without any dashes and underscore. @@ -118,62 +127,3 @@ func validateCmdName(source string) string { } return output } - -func createCmdFile(license License, path, cmdName string) { - template := `{{comment .copyright}} -{{if .license}}{{comment .license}}{{end}} - -package {{.cmdPackage}} - -import ( - "fmt" - - "github.com/spf13/cobra" -) - -// {{.cmdName}}Cmd represents the {{.cmdName}} command -var {{.cmdName}}Cmd = &cobra.Command{ - Use: "{{.cmdName}}", - Short: "A brief description of your command", - Long: ` + "`" + `A longer description that spans multiple lines and likely contains examples -and usage of using your command. For example: - -Cobra is a CLI library for Go that empowers applications. -This application is a tool to generate the needed files -to quickly create a Cobra application.` + "`" + `, - Run: func(cmd *cobra.Command, args []string) { - fmt.Println("{{.cmdName}} called") - }, -} - -func init() { - {{.parentName}}.AddCommand({{.cmdName}}Cmd) - - // Here you will define your flags and configuration settings. - - // Cobra supports Persistent Flags which will work for this command - // and all subcommands, e.g.: - // {{.cmdName}}Cmd.PersistentFlags().String("foo", "", "A help for foo") - - // Cobra supports local flags which will only run when this command - // is called directly, e.g.: - // {{.cmdName}}Cmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") -} -` - - data := make(map[string]interface{}) - data["copyright"] = copyrightLine() - data["license"] = license.Header - data["cmdPackage"] = filepath.Base(filepath.Dir(path)) // last dir of path - data["parentName"] = parentName - data["cmdName"] = cmdName - - cmdScript, err := executeTemplate(template, data) - if err != nil { - er(err) - } - err = writeStringToFile(path, cmdScript) - if err != nil { - er(err) - } -} diff --git a/vendor/github.com/spf13/cobra/cobra/cmd/add_test.go b/vendor/github.com/spf13/cobra/cobra/cmd/add_test.go index b920e2b9dff4..0de1d221fe31 100644 --- a/vendor/github.com/spf13/cobra/cobra/cmd/add_test.go +++ b/vendor/github.com/spf13/cobra/cobra/cmd/add_test.go @@ -1,85 +1,45 @@ package cmd import ( - "errors" - "io/ioutil" + "fmt" "os" - "path/filepath" "testing" - - "github.com/spf13/viper" ) -// TestGoldenAddCmd initializes the project "github.com/spf13/testproject" -// in GOPATH, adds "test" command -// and compares the content of all files in cmd directory of testproject -// with appropriate golden files. -// Use -update to update existing golden files. func TestGoldenAddCmd(t *testing.T) { - projectName := "github.com/spf13/testproject" - project := NewProject(projectName) - defer os.RemoveAll(project.AbsPath()) - - viper.Set("author", "NAME HERE ") - viper.Set("license", "apache") - viper.Set("year", 2017) - defer viper.Set("author", nil) - defer viper.Set("license", nil) - defer viper.Set("year", nil) - - // Initialize the project first. - initializeProject(project) - // Then add the "test" command. - cmdName := "test" - cmdPath := filepath.Join(project.CmdPath(), cmdName+".go") - createCmdFile(project.License(), cmdPath, cmdName) + wd, _ := os.Getwd() + command := &Command{ + CmdName: "test", + CmdParent: parentName, + Project: &Project{ + AbsolutePath: fmt.Sprintf("%s/testproject", wd), + Legal: getLicense(), + Copyright: copyrightLine(), - expectedFiles := []string{".", "root.go", "test.go"} - gotFiles := []string{} - - // Check project file hierarchy and compare the content of every single file - // with appropriate golden file. - err := filepath.Walk(project.CmdPath(), func(path string, info os.FileInfo, err error) error { - if err != nil { - return err - } + // required to init + AppName: "testproject", + PkgName: "github.com/spf13/testproject", + Viper: true, + }, + } - // Make path relative to project.CmdPath(). - // E.g. path = "/home/user/go/src/github.com/spf13/testproject/cmd/root.go" - // then it returns just "root.go". - relPath, err := filepath.Rel(project.CmdPath(), path) - if err != nil { - return err + // init project first + command.Project.Create() + defer func() { + if _, err := os.Stat(command.AbsolutePath); err == nil { + os.RemoveAll(command.AbsolutePath) } - relPath = filepath.ToSlash(relPath) - gotFiles = append(gotFiles, relPath) - goldenPath := filepath.Join("testdata", filepath.Base(path)+".golden") + }() - switch relPath { - // Known directories. - case ".": - return nil - // Known files. - case "root.go", "test.go": - if *update { - got, err := ioutil.ReadFile(path) - if err != nil { - return err - } - ioutil.WriteFile(goldenPath, got, 0644) - } - return compareFiles(path, goldenPath) - } - // Unknown file. - return errors.New("unknown file: " + path) - }) - if err != nil { + if err := command.Create(); err != nil { t.Fatal(err) } - // Check if some files lack. - if err := checkLackFiles(expectedFiles, gotFiles); err != nil { + generatedFile := fmt.Sprintf("%s/cmd/%s.go", command.AbsolutePath, command.CmdName) + goldenFile := fmt.Sprintf("testdata/%s.go.golden", command.CmdName) + err := compareFiles(generatedFile, goldenFile) + if err != nil { t.Fatal(err) } } diff --git a/vendor/github.com/spf13/cobra/cobra/cmd/golden_test.go b/vendor/github.com/spf13/cobra/cobra/cmd/golden_test.go index 59a5a1c9f96a..9010caa13a6a 100644 --- a/vendor/github.com/spf13/cobra/cobra/cmd/golden_test.go +++ b/vendor/github.com/spf13/cobra/cobra/cmd/golden_test.go @@ -17,6 +17,11 @@ func init() { initCmd.SetOutput(new(bytes.Buffer)) } +// ensureLF converts any \r\n to \n +func ensureLF(content []byte) []byte { + return bytes.Replace(content, []byte("\r\n"), []byte("\n"), -1) +} + // compareFiles compares the content of files with pathA and pathB. // If contents are equal, it returns nil. // If not, it returns which files are not equal @@ -30,7 +35,7 @@ func compareFiles(pathA, pathB string) error { if err != nil { return err } - if !bytes.Equal(contentA, contentB) { + if !bytes.Equal(ensureLF(contentA), ensureLF(contentB)) { output := new(bytes.Buffer) output.WriteString(fmt.Sprintf("%q and %q are not equal!\n\n", pathA, pathB)) diff --git a/vendor/github.com/spf13/cobra/cobra/cmd/init.go b/vendor/github.com/spf13/cobra/cobra/cmd/init.go index 24413701527f..dcf5ada4fbdf 100644 --- a/vendor/github.com/spf13/cobra/cobra/cmd/init.go +++ b/vendor/github.com/spf13/cobra/cobra/cmd/init.go @@ -17,17 +17,19 @@ import ( "fmt" "os" "path" - "path/filepath" "github.com/spf13/cobra" "github.com/spf13/viper" ) -var initCmd = &cobra.Command{ - Use: "init [name]", - Aliases: []string{"initialize", "initialise", "create"}, - Short: "Initialize a Cobra Application", - Long: `Initialize (cobra init) will create a new application, with a license +var ( + pkgName string + + initCmd = &cobra.Command{ + Use: "init [name]", + Aliases: []string{"initialize", "initialise", "create"}, + Short: "Initialize a Cobra Application", + Long: `Initialize (cobra init) will create a new application, with a license and the appropriate structure for a Cobra-based CLI application. * If a name is provided, it will be created in the current directory; @@ -39,196 +41,38 @@ and the appropriate structure for a Cobra-based CLI application. Init will not use an existing directory with contents.`, - Run: func(cmd *cobra.Command, args []string) { - wd, err := os.Getwd() - if err != nil { - er(err) - } + Run: func(cmd *cobra.Command, args []string) { - var project *Project - if len(args) == 0 { - project = NewProjectFromPath(wd) - } else if len(args) == 1 { - arg := args[0] - if arg[0] == '.' { - arg = filepath.Join(wd, arg) - } - if filepath.IsAbs(arg) { - project = NewProjectFromPath(arg) - } else { - project = NewProject(arg) + wd, err := os.Getwd() + if err != nil { + er(err) } - } else { - er("please provide only one argument") - } - - initializeProject(project) - - fmt.Fprintln(cmd.OutOrStdout(), `Your Cobra application is ready at -`+project.AbsPath()+`. - -Give it a try by going there and running `+"`go run main.go`."+` -Add commands to it by running `+"`cobra add [cmdname]`.") - }, -} - -func initializeProject(project *Project) { - if !exists(project.AbsPath()) { // If path doesn't yet exist, create it - err := os.MkdirAll(project.AbsPath(), os.ModePerm) - if err != nil { - er(err) - } - } else if !isEmpty(project.AbsPath()) { // If path exists and is not empty don't use it - er("Cobra will not create a new project in a non empty directory: " + project.AbsPath()) - } - - // We have a directory and it's empty. Time to initialize it. - createLicenseFile(project.License(), project.AbsPath()) - createMainFile(project) - createRootCmdFile(project) -} - -func createLicenseFile(license License, path string) { - data := make(map[string]interface{}) - data["copyright"] = copyrightLine() - - // Generate license template from text and data. - text, err := executeTemplate(license.Text, data) - if err != nil { - er(err) - } - - // Write license text to LICENSE file. - err = writeStringToFile(filepath.Join(path, "LICENSE"), text) - if err != nil { - er(err) - } -} - -func createMainFile(project *Project) { - mainTemplate := `{{ comment .copyright }} -{{if .license}}{{ comment .license }}{{end}} - -package main - -import "{{ .importpath }}" - -func main() { - cmd.Execute() -} -` - data := make(map[string]interface{}) - data["copyright"] = copyrightLine() - data["license"] = project.License().Header - data["importpath"] = path.Join(project.Name(), filepath.Base(project.CmdPath())) - - mainScript, err := executeTemplate(mainTemplate, data) - if err != nil { - er(err) - } - - err = writeStringToFile(filepath.Join(project.AbsPath(), "main.go"), mainScript) - if err != nil { - er(err) - } -} -func createRootCmdFile(project *Project) { - template := `{{comment .copyright}} -{{if .license}}{{comment .license}}{{end}} - -package cmd - -import ( - "fmt" - "os" -{{if .viper}} - homedir "github.com/mitchellh/go-homedir"{{end}} - "github.com/spf13/cobra"{{if .viper}} - "github.com/spf13/viper"{{end}} -){{if .viper}} - -var cfgFile string{{end}} - -// rootCmd represents the base command when called without any subcommands -var rootCmd = &cobra.Command{ - Use: "{{.appName}}", - Short: "A brief description of your application", - Long: ` + "`" + `A longer description that spans multiple lines and likely contains -examples and usage of using your application. For example: - -Cobra is a CLI library for Go that empowers applications. -This application is a tool to generate the needed files -to quickly create a Cobra application.` + "`" + `, - // Uncomment the following line if your bare application - // has an action associated with it: - // Run: func(cmd *cobra.Command, args []string) { }, -} - -// Execute adds all child commands to the root command and sets flags appropriately. -// This is called by main.main(). It only needs to happen once to the rootCmd. -func Execute() { - if err := rootCmd.Execute(); err != nil { - fmt.Println(err) - os.Exit(1) - } -} - -func init() { {{- if .viper}} - cobra.OnInitialize(initConfig) -{{end}} - // Here you will define your flags and configuration settings. - // Cobra supports persistent flags, which, if defined here, - // will be global for your application.{{ if .viper }} - rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.{{ .appName }}.yaml)"){{ else }} - // rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.{{ .appName }}.yaml)"){{ end }} - - // Cobra also supports local flags, which will only run - // when this action is called directly. - rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") -}{{ if .viper }} - -// initConfig reads in config file and ENV variables if set. -func initConfig() { - if cfgFile != "" { - // Use config file from the flag. - viper.SetConfigFile(cfgFile) - } else { - // Find home directory. - home, err := homedir.Dir() - if err != nil { - fmt.Println(err) - os.Exit(1) - } - - // Search config in home directory with name ".{{ .appName }}" (without extension). - viper.AddConfigPath(home) - viper.SetConfigName(".{{ .appName }}") - } - - viper.AutomaticEnv() // read in environment variables that match - - // If a config file is found, read it in. - if err := viper.ReadInConfig(); err == nil { - fmt.Println("Using config file:", viper.ConfigFileUsed()) - } -}{{ end }} -` + if len(args) > 0 { + if args[0] != "." { + wd = fmt.Sprintf("%s/%s", wd, args[0]) + } + } - data := make(map[string]interface{}) - data["copyright"] = copyrightLine() - data["viper"] = viper.GetBool("useViper") - data["license"] = project.License().Header - data["appName"] = path.Base(project.Name()) + project := &Project{ + AbsolutePath: wd, + PkgName: pkgName, + Legal: getLicense(), + Copyright: copyrightLine(), + Viper: viper.GetBool("useViper"), + AppName: path.Base(pkgName), + } - rootCmdScript, err := executeTemplate(template, data) - if err != nil { - er(err) - } + if err := project.Create(); err != nil { + er(err) + } - err = writeStringToFile(filepath.Join(project.CmdPath(), "root.go"), rootCmdScript) - if err != nil { - er(err) + fmt.Printf("Your Cobra applicaton is ready at\n%s\n", project.AbsolutePath) + }, } +) +func init() { + initCmd.Flags().StringVar(&pkgName, "pkg-name", "", "fully qualified pkg name") + initCmd.MarkFlagRequired("pkg-name") } diff --git a/vendor/github.com/spf13/cobra/cobra/cmd/init_test.go b/vendor/github.com/spf13/cobra/cobra/cmd/init_test.go index 40eb4038e4ef..9540b2d307d1 100644 --- a/vendor/github.com/spf13/cobra/cobra/cmd/init_test.go +++ b/vendor/github.com/spf13/cobra/cobra/cmd/init_test.go @@ -1,83 +1,42 @@ package cmd import ( - "errors" - "io/ioutil" + "fmt" "os" "path/filepath" "testing" - - "github.com/spf13/viper" ) -// TestGoldenInitCmd initializes the project "github.com/spf13/testproject" -// in GOPATH and compares the content of files in initialized project with -// appropriate golden files ("testdata/*.golden"). -// Use -update to update existing golden files. func TestGoldenInitCmd(t *testing.T) { - projectName := "github.com/spf13/testproject" - project := NewProject(projectName) - defer os.RemoveAll(project.AbsPath()) - - viper.Set("author", "NAME HERE ") - viper.Set("license", "apache") - viper.Set("year", 2017) - defer viper.Set("author", nil) - defer viper.Set("license", nil) - defer viper.Set("year", nil) - os.Args = []string{"cobra", "init", projectName} - if err := rootCmd.Execute(); err != nil { - t.Fatal("Error by execution:", err) + wd, _ := os.Getwd() + project := &Project{ + AbsolutePath: fmt.Sprintf("%s/testproject", wd), + PkgName: "github.com/spf13/testproject", + Legal: getLicense(), + Copyright: copyrightLine(), + Viper: true, + AppName: "testproject", } - expectedFiles := []string{".", "cmd", "LICENSE", "main.go", "cmd/root.go"} - gotFiles := []string{} + err := project.Create() + if err != nil { + t.Fatal(err) + } - // Check project file hierarchy and compare the content of every single file - // with appropriate golden file. - err := filepath.Walk(project.AbsPath(), func(path string, info os.FileInfo, err error) error { - if err != nil { - return err + defer func() { + if _, err := os.Stat(project.AbsolutePath); err == nil { + os.RemoveAll(project.AbsolutePath) } + }() - // Make path relative to project.AbsPath(). - // E.g. path = "/home/user/go/src/github.com/spf13/testproject/cmd/root.go" - // then it returns just "cmd/root.go". - relPath, err := filepath.Rel(project.AbsPath(), path) + expectedFiles := []string{"LICENSE", "main.go", "cmd/root.go"} + for _, f := range expectedFiles { + generatedFile := fmt.Sprintf("%s/%s", project.AbsolutePath, f) + goldenFile := fmt.Sprintf("testdata/%s.golden", filepath.Base(f)) + err := compareFiles(generatedFile, goldenFile) if err != nil { - return err + t.Fatal(err) } - relPath = filepath.ToSlash(relPath) - gotFiles = append(gotFiles, relPath) - goldenPath := filepath.Join("testdata", filepath.Base(path)+".golden") - - switch relPath { - // Known directories. - case ".", "cmd": - return nil - // Known files. - case "LICENSE", "main.go", "cmd/root.go": - if *update { - got, err := ioutil.ReadFile(path) - if err != nil { - return err - } - if err := ioutil.WriteFile(goldenPath, got, 0644); err != nil { - t.Fatal("Error while updating file:", err) - } - } - return compareFiles(path, goldenPath) - } - // Unknown file. - return errors.New("unknown file: " + path) - }) - if err != nil { - t.Fatal(err) - } - - // Check if some files lack. - if err := checkLackFiles(expectedFiles, gotFiles); err != nil { - t.Fatal(err) } } diff --git a/vendor/github.com/spf13/cobra/cobra/cmd/project.go b/vendor/github.com/spf13/cobra/cobra/cmd/project.go index 7ddb8258571d..a53893ccd717 100644 --- a/vendor/github.com/spf13/cobra/cobra/cmd/project.go +++ b/vendor/github.com/spf13/cobra/cobra/cmd/project.go @@ -1,200 +1,96 @@ package cmd import ( + "fmt" "os" - "path/filepath" - "runtime" - "strings" + "text/template" + + "github.com/spf13/cobra/cobra/tpl" ) // Project contains name, license and paths to projects. type Project struct { - absPath string - cmdPath string - srcPath string - license License - name string + // v2 + PkgName string + Copyright string + AbsolutePath string + Legal License + Viper bool + AppName string } -// NewProject returns Project with specified project name. -func NewProject(projectName string) *Project { - if projectName == "" { - er("can't create project with blank name") - } - - p := new(Project) - p.name = projectName - - // 1. Find already created protect. - p.absPath = findPackage(projectName) - - // 2. If there are no created project with this path, and user is in GOPATH, - // then use GOPATH/src/projectName. - if p.absPath == "" { - wd, err := os.Getwd() - if err != nil { - er(err) - } - for _, srcPath := range srcPaths { - goPath := filepath.Dir(srcPath) - if filepathHasPrefix(wd, goPath) { - p.absPath = filepath.Join(srcPath, projectName) - break - } - } - } - - // 3. If user is not in GOPATH, then use (first GOPATH)/src/projectName. - if p.absPath == "" { - p.absPath = filepath.Join(srcPaths[0], projectName) - } - - return p +type Command struct { + CmdName string + CmdParent string + *Project } -// findPackage returns full path to existing go package in GOPATHs. -func findPackage(packageName string) string { - if packageName == "" { - return "" - } - - for _, srcPath := range srcPaths { - packagePath := filepath.Join(srcPath, packageName) - if exists(packagePath) { - return packagePath +func (p *Project) Create() error { + // check if AbsolutePath exists + if _, err := os.Stat(p.AbsolutePath); os.IsNotExist(err) { + // create directory + if err := os.Mkdir(p.AbsolutePath, 0754); err != nil { + return err } } - return "" -} - -// NewProjectFromPath returns Project with specified absolute path to -// package. -func NewProjectFromPath(absPath string) *Project { - if absPath == "" { - er("can't create project: absPath can't be blank") - } - if !filepath.IsAbs(absPath) { - er("can't create project: absPath is not absolute") - } - - // If absPath is symlink, use its destination. - fi, err := os.Lstat(absPath) + // create main.go + mainFile, err := os.Create(fmt.Sprintf("%s/main.go", p.AbsolutePath)) if err != nil { - er("can't read path info: " + err.Error()) - } - if fi.Mode()&os.ModeSymlink != 0 { - path, err := os.Readlink(absPath) - if err != nil { - er("can't read the destination of symlink: " + err.Error()) - } - absPath = path + return err } + defer mainFile.Close() - p := new(Project) - p.absPath = strings.TrimSuffix(absPath, findCmdDir(absPath)) - p.name = filepath.ToSlash(trimSrcPath(p.absPath, p.SrcPath())) - return p -} - -// trimSrcPath trims at the beginning of absPath the srcPath. -func trimSrcPath(absPath, srcPath string) string { - relPath, err := filepath.Rel(srcPath, absPath) + mainTemplate := template.Must(template.New("main").Parse(string(tpl.MainTemplate()))) + err = mainTemplate.Execute(mainFile, p) if err != nil { - er(err) - } - return relPath -} - -// License returns the License object of project. -func (p *Project) License() License { - if p.license.Text == "" && p.license.Name != "None" { - p.license = getLicense() + return err } - return p.license -} - -// Name returns the name of project, e.g. "github.com/spf13/cobra" -func (p Project) Name() string { - return p.name -} - -// CmdPath returns absolute path to directory, where all commands are located. -func (p *Project) CmdPath() string { - if p.absPath == "" { - return "" - } - if p.cmdPath == "" { - p.cmdPath = filepath.Join(p.absPath, findCmdDir(p.absPath)) - } - return p.cmdPath -} -// findCmdDir checks if base of absPath is cmd dir and returns it or -// looks for existing cmd dir in absPath. -func findCmdDir(absPath string) string { - if !exists(absPath) || isEmpty(absPath) { - return "cmd" + // create cmd/root.go + if _, err = os.Stat(fmt.Sprintf("%s/cmd", p.AbsolutePath)); os.IsNotExist(err) { + os.Mkdir(fmt.Sprintf("%s/cmd", p.AbsolutePath), 0751) } - - if isCmdDir(absPath) { - return filepath.Base(absPath) - } - - files, _ := filepath.Glob(filepath.Join(absPath, "c*")) - for _, file := range files { - if isCmdDir(file) { - return filepath.Base(file) - } + rootFile, err := os.Create(fmt.Sprintf("%s/cmd/root.go", p.AbsolutePath)) + if err != nil { + return err } + defer rootFile.Close() - return "cmd" -} - -// isCmdDir checks if base of name is one of cmdDir. -func isCmdDir(name string) bool { - name = filepath.Base(name) - for _, cmdDir := range []string{"cmd", "cmds", "command", "commands"} { - if name == cmdDir { - return true - } + rootTemplate := template.Must(template.New("root").Parse(string(tpl.RootTemplate()))) + err = rootTemplate.Execute(rootFile, p) + if err != nil { + return err } - return false -} -// AbsPath returns absolute path of project. -func (p Project) AbsPath() string { - return p.absPath + // create license + return p.createLicenseFile() } -// SrcPath returns absolute path to $GOPATH/src where project is located. -func (p *Project) SrcPath() string { - if p.srcPath != "" { - return p.srcPath - } - if p.absPath == "" { - p.srcPath = srcPaths[0] - return p.srcPath +func (p *Project) createLicenseFile() error { + data := map[string]interface{}{ + "copyright": copyrightLine(), } - - for _, srcPath := range srcPaths { - if filepathHasPrefix(p.absPath, srcPath) { - p.srcPath = srcPath - break - } + licenseFile, err := os.Create(fmt.Sprintf("%s/LICENSE", p.AbsolutePath)) + if err != nil { + return err } - return p.srcPath + licenseTemplate := template.Must(template.New("license").Parse(p.Legal.Text)) + return licenseTemplate.Execute(licenseFile, data) } -func filepathHasPrefix(path string, prefix string) bool { - if len(path) <= len(prefix) { - return false - } - if runtime.GOOS == "windows" { - // Paths in windows are case-insensitive. - return strings.EqualFold(path[0:len(prefix)], prefix) +func (c *Command) Create() error { + cmdFile, err := os.Create(fmt.Sprintf("%s/cmd/%s.go", c.AbsolutePath, c.CmdName)) + if err != nil { + return err } - return path[0:len(prefix)] == prefix + defer cmdFile.Close() + commandTemplate := template.Must(template.New("sub").Parse(string(tpl.AddCommandTemplate()))) + err = commandTemplate.Execute(cmdFile, c) + if err != nil { + return err + } + return nil } diff --git a/vendor/github.com/spf13/cobra/cobra/cmd/project_test.go b/vendor/github.com/spf13/cobra/cobra/cmd/project_test.go index 037f7c554e50..ed5b054a291b 100644 --- a/vendor/github.com/spf13/cobra/cobra/cmd/project_test.go +++ b/vendor/github.com/spf13/cobra/cobra/cmd/project_test.go @@ -1,24 +1,3 @@ package cmd -import ( - "testing" -) - -func TestFindExistingPackage(t *testing.T) { - path := findPackage("github.com/spf13/cobra") - if path == "" { - t.Fatal("findPackage didn't find the existing package") - } - if !hasGoPathPrefix(path) { - t.Fatalf("%q is not in GOPATH, but must be", path) - } -} - -func hasGoPathPrefix(path string) bool { - for _, srcPath := range srcPaths { - if filepathHasPrefix(path, srcPath) { - return true - } - } - return false -} +/* todo: write tests */ diff --git a/vendor/github.com/spf13/cobra/cobra/cmd/root.go b/vendor/github.com/spf13/cobra/cobra/cmd/root.go index 19568f98024d..97f404bbb655 100644 --- a/vendor/github.com/spf13/cobra/cobra/cmd/root.go +++ b/vendor/github.com/spf13/cobra/cobra/cmd/root.go @@ -23,7 +23,8 @@ import ( var ( // Used for flags. - cfgFile, userLicense string + cfgFile string + userLicense string rootCmd = &cobra.Command{ Use: "cobra", @@ -35,8 +36,8 @@ to quickly create a Cobra application.`, ) // Execute executes the root command. -func Execute() { - rootCmd.Execute() +func Execute() error { + return rootCmd.Execute() } func init() { diff --git a/vendor/github.com/spf13/cobra/cobra/cmd/testdata/main.go.golden b/vendor/github.com/spf13/cobra/cobra/cmd/testdata/main.go.golden index cdbe38d70b0d..4ad570c5438c 100644 --- a/vendor/github.com/spf13/cobra/cobra/cmd/testdata/main.go.golden +++ b/vendor/github.com/spf13/cobra/cobra/cmd/testdata/main.go.golden @@ -1,21 +1,22 @@ -// Copyright © 2017 NAME HERE -// -// 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. +/* +Copyright © 2019 NAME HERE +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 "github.com/spf13/testproject/cmd" func main() { - cmd.Execute() + cmd.Execute() } diff --git a/vendor/github.com/spf13/cobra/cobra/cmd/testdata/root.go.golden b/vendor/github.com/spf13/cobra/cobra/cmd/testdata/root.go.golden index d74f4cd45070..d3b889baa670 100644 --- a/vendor/github.com/spf13/cobra/cobra/cmd/testdata/root.go.golden +++ b/vendor/github.com/spf13/cobra/cobra/cmd/testdata/root.go.golden @@ -1,89 +1,97 @@ -// Copyright © 2017 NAME HERE -// -// 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. +/* +Copyright © 2019 NAME HERE +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 cmd import ( - "fmt" - "os" + "fmt" + "os" + "github.com/spf13/cobra" + + homedir "github.com/mitchellh/go-homedir" + "github.com/spf13/viper" - homedir "github.com/mitchellh/go-homedir" - "github.com/spf13/cobra" - "github.com/spf13/viper" ) + var cfgFile string + // rootCmd represents the base command when called without any subcommands var rootCmd = &cobra.Command{ - Use: "testproject", - Short: "A brief description of your application", - Long: `A longer description that spans multiple lines and likely contains + Use: "testproject", + Short: "A brief description of your application", + Long: `A longer description that spans multiple lines and likely contains examples and usage of using your application. For example: Cobra is a CLI library for Go that empowers applications. This application is a tool to generate the needed files to quickly create a Cobra application.`, - // Uncomment the following line if your bare application - // has an action associated with it: - // Run: func(cmd *cobra.Command, args []string) { }, + // Uncomment the following line if your bare application + // has an action associated with it: + // Run: func(cmd *cobra.Command, args []string) { }, } // Execute adds all child commands to the root command and sets flags appropriately. // This is called by main.main(). It only needs to happen once to the rootCmd. func Execute() { - if err := rootCmd.Execute(); err != nil { - fmt.Println(err) - os.Exit(1) - } + if err := rootCmd.Execute(); err != nil { + fmt.Println(err) + os.Exit(1) + } } func init() { - cobra.OnInitialize(initConfig) + cobra.OnInitialize(initConfig) + + // Here you will define your flags and configuration settings. + // Cobra supports persistent flags, which, if defined here, + // will be global for your application. - // Here you will define your flags and configuration settings. - // Cobra supports persistent flags, which, if defined here, - // will be global for your application. - rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.testproject.yaml)") + rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.testproject.yaml)") - // Cobra also supports local flags, which will only run - // when this action is called directly. - rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") + + // Cobra also supports local flags, which will only run + // when this action is called directly. + rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") } + // initConfig reads in config file and ENV variables if set. func initConfig() { - if cfgFile != "" { - // Use config file from the flag. - viper.SetConfigFile(cfgFile) - } else { - // Find home directory. - home, err := homedir.Dir() - if err != nil { - fmt.Println(err) - os.Exit(1) - } - - // Search config in home directory with name ".testproject" (without extension). - viper.AddConfigPath(home) - viper.SetConfigName(".testproject") - } - - viper.AutomaticEnv() // read in environment variables that match - - // If a config file is found, read it in. - if err := viper.ReadInConfig(); err == nil { - fmt.Println("Using config file:", viper.ConfigFileUsed()) - } + if cfgFile != "" { + // Use config file from the flag. + viper.SetConfigFile(cfgFile) + } else { + // Find home directory. + home, err := homedir.Dir() + if err != nil { + fmt.Println(err) + os.Exit(1) + } + + // Search config in home directory with name ".testproject" (without extension). + viper.AddConfigPath(home) + viper.SetConfigName(".testproject") + } + + viper.AutomaticEnv() // read in environment variables that match + + // If a config file is found, read it in. + if err := viper.ReadInConfig(); err == nil { + fmt.Println("Using config file:", viper.ConfigFileUsed()) + } } + diff --git a/vendor/github.com/spf13/cobra/cobra/cmd/testdata/test.go.golden b/vendor/github.com/spf13/cobra/cobra/cmd/testdata/test.go.golden index ed644275546f..fb8e0fa90d0b 100644 --- a/vendor/github.com/spf13/cobra/cobra/cmd/testdata/test.go.golden +++ b/vendor/github.com/spf13/cobra/cobra/cmd/testdata/test.go.golden @@ -1,17 +1,18 @@ -// Copyright © 2017 NAME HERE -// -// 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. +/* +Copyright © 2019 NAME HERE +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 cmd import ( diff --git a/vendor/github.com/spf13/cobra/cobra/main.go b/vendor/github.com/spf13/cobra/cobra/main.go index c3a9d9cb04c2..eeaf9824ef9c 100644 --- a/vendor/github.com/spf13/cobra/cobra/main.go +++ b/vendor/github.com/spf13/cobra/cobra/main.go @@ -13,8 +13,14 @@ package main -import "github.com/spf13/cobra/cobra/cmd" +import ( + "os" + + "github.com/spf13/cobra/cobra/cmd" +) func main() { - cmd.Execute() + if err := cmd.Execute(); err != nil { + os.Exit(1) + } } diff --git a/vendor/github.com/spf13/cobra/command.go b/vendor/github.com/spf13/cobra/command.go index 15b8112795cb..42e500de586a 100644 --- a/vendor/github.com/spf13/cobra/command.go +++ b/vendor/github.com/spf13/cobra/command.go @@ -17,6 +17,7 @@ package cobra import ( "bytes" + "errors" "fmt" "io" "os" @@ -27,6 +28,11 @@ import ( flag "github.com/spf13/pflag" ) +var ErrSubCommandRequired = errors.New("subcommand is required") + +// FParseErrWhitelist configures Flag parse errors to be ignored +type FParseErrWhitelist flag.ParseErrorsWhitelist + // Command is just that, a command for your application. // E.g. 'go run ...' - 'run' is the command. Cobra requires // you to define the usage and description as part of your command @@ -137,6 +143,9 @@ type Command struct { // TraverseChildren parses flags on all parents before executing child command. TraverseChildren bool + //FParseErrWhitelist flag parse errors to be ignored + FParseErrWhitelist FParseErrWhitelist + // commands is the list of commands supported by this program. commands []*Command // parent is a parent command for this command. @@ -171,8 +180,6 @@ type Command struct { // that we can use on every pflag set and children commands globNormFunc func(f *flag.FlagSet, name string) flag.NormalizedName - // output is an output writer defined by user. - output io.Writer // usageFunc is usage func defined by user. usageFunc func(*Command) error // usageTemplate is usage template defined by user. @@ -189,6 +196,13 @@ type Command struct { helpCommand *Command // versionTemplate is the version template defined by user. versionTemplate string + + // inReader is a reader defined by the user that replaces stdin + inReader io.Reader + // outWriter is a writer defined by the user that replaces stdout + outWriter io.Writer + // errWriter is a writer defined by the user that replaces stderr + errWriter io.Writer } // SetArgs sets arguments for the command. It is set to os.Args[1:] by default, if desired, can be overridden @@ -199,8 +213,28 @@ func (c *Command) SetArgs(a []string) { // SetOutput sets the destination for usage and error messages. // If output is nil, os.Stderr is used. +// Deprecated: Use SetOut and/or SetErr instead func (c *Command) SetOutput(output io.Writer) { - c.output = output + c.outWriter = output + c.errWriter = output +} + +// SetOut sets the destination for usage messages. +// If newOut is nil, os.Stdout is used. +func (c *Command) SetOut(newOut io.Writer) { + c.outWriter = newOut +} + +// SetErr sets the destination for error messages. +// If newErr is nil, os.Stderr is used. +func (c *Command) SetErr(newErr io.Writer) { + c.errWriter = newErr +} + +// SetIn sets the source for input data +// If newIn is nil, os.Stdin is used. +func (c *Command) SetIn(newIn io.Reader) { + c.inReader = newIn } // SetUsageFunc sets usage function. Usage can be defined by application. @@ -261,9 +295,19 @@ func (c *Command) OutOrStderr() io.Writer { return c.getOut(os.Stderr) } +// ErrOrStderr returns output to stderr +func (c *Command) ErrOrStderr() io.Writer { + return c.getErr(os.Stderr) +} + +// InOrStdin returns output to stderr +func (c *Command) InOrStdin() io.Reader { + return c.getIn(os.Stdin) +} + func (c *Command) getOut(def io.Writer) io.Writer { - if c.output != nil { - return c.output + if c.outWriter != nil { + return c.outWriter } if c.HasParent() { return c.parent.getOut(def) @@ -271,6 +315,26 @@ func (c *Command) getOut(def io.Writer) io.Writer { return def } +func (c *Command) getErr(def io.Writer) io.Writer { + if c.errWriter != nil { + return c.errWriter + } + if c.HasParent() { + return c.parent.getErr(def) + } + return def +} + +func (c *Command) getIn(def io.Reader) io.Reader { + if c.inReader != nil { + return c.inReader + } + if c.HasParent() { + return c.parent.getIn(def) + } + return def +} + // UsageFunc returns either the function set by SetUsageFunc for this command // or a parent, or it returns a default usage function. func (c *Command) UsageFunc() (f func(*Command) error) { @@ -308,7 +372,7 @@ func (c *Command) HelpFunc() func(*Command, []string) { } return func(c *Command, a []string) { c.mergePersistentFlags() - err := tmpl(c.OutOrStdout(), c.HelpTemplate(), c) + err := tmpl(c.OutOrStderr(), c.HelpTemplate(), c) if err != nil { c.Println(err) } @@ -323,13 +387,22 @@ func (c *Command) Help() error { return nil } -// UsageString return usage string. +// UsageString returns usage string. func (c *Command) UsageString() string { - tmpOutput := c.output + // Storing normal writers + tmpOutput := c.outWriter + tmpErr := c.errWriter + bb := new(bytes.Buffer) - c.SetOutput(bb) + c.outWriter = bb + c.errWriter = bb + c.Usage() - c.output = tmpOutput + + // Setting things back to normal + c.outWriter = tmpOutput + c.errWriter = tmpErr + return bb.String() } @@ -716,7 +789,7 @@ func (c *Command) execute(a []string) (err error) { } if !c.Runnable() { - return flag.ErrHelp + return ErrSubCommandRequired } c.preRun() @@ -811,13 +884,11 @@ func (c *Command) ExecuteC() (cmd *Command, err error) { // overriding c.InitDefaultHelpCmd() - var args []string + args := c.args // Workaround FAIL with "go test -v" or "cobra.test -test.v", see #155 if c.args == nil && filepath.Base(os.Args[0]) != "cobra.test" { args = os.Args[1:] - } else { - args = c.args } var flags []string @@ -852,6 +923,14 @@ func (c *Command) ExecuteC() (cmd *Command, err error) { return cmd, nil } + // If command wasn't runnable, show full help, but do return the error. + // This will result in apps by default returning a non-success exit code, but also gives them the option to + // handle specially. + if err == ErrSubCommandRequired { + cmd.HelpFunc()(cmd, args) + return cmd, err + } + // If root command has SilentErrors flagged, // all subcommands should respect it if !cmd.SilenceErrors && !c.SilenceErrors { @@ -1064,6 +1143,21 @@ func (c *Command) Printf(format string, i ...interface{}) { c.Print(fmt.Sprintf(format, i...)) } +// PrintErr is a convenience method to Print to the defined Err output, fallback to Stderr if not set. +func (c *Command) PrintErr(i ...interface{}) { + fmt.Fprint(c.ErrOrStderr(), i...) +} + +// PrintErrln is a convenience method to Println to the defined Err output, fallback to Stderr if not set. +func (c *Command) PrintErrln(i ...interface{}) { + c.Print(fmt.Sprintln(i...)) +} + +// PrintErrf is a convenience method to Printf to the defined Err output, fallback to Stderr if not set. +func (c *Command) PrintErrf(format string, i ...interface{}) { + c.Print(fmt.Sprintf(format, i...)) +} + // CommandPath returns the full path to this command. func (c *Command) CommandPath() string { if c.HasParent() { @@ -1329,7 +1423,7 @@ func (c *Command) LocalFlags() *flag.FlagSet { return c.lflags } -// InheritedFlags returns all flags which were inherited from parents commands. +// InheritedFlags returns all flags which were inherited from parent commands. func (c *Command) InheritedFlags() *flag.FlagSet { c.mergePersistentFlags() @@ -1463,6 +1557,10 @@ func (c *Command) ParseFlags(args []string) error { } beforeErrorBufLen := c.flagErrorBuf.Len() c.mergePersistentFlags() + + //do it here after merging all flags and just before parse + c.Flags().ParseErrorsWhitelist = flag.ParseErrorsWhitelist(c.FParseErrWhitelist) + err := c.Flags().Parse(args) // Print warnings if they occurred (e.g. deprecated flag messages). if c.flagErrorBuf.Len()-beforeErrorBufLen > 0 && err == nil { diff --git a/vendor/github.com/spf13/cobra/command_test.go b/vendor/github.com/spf13/cobra/command_test.go index d874a9a515f4..b26bd4abebab 100644 --- a/vendor/github.com/spf13/cobra/command_test.go +++ b/vendor/github.com/spf13/cobra/command_test.go @@ -836,8 +836,8 @@ func TestHelpExecutedOnNonRunnableChild(t *testing.T) { rootCmd.AddCommand(childCmd) output, err := executeCommand(rootCmd, "child") - if err != nil { - t.Errorf("Unexpected error: %v", err) + if err != ErrSubCommandRequired { + t.Errorf("Expected error") } checkStringContains(t, output, childCmd.Long) @@ -1164,12 +1164,13 @@ func TestPersistentHooks(t *testing.T) { t.Errorf("Unexpected error: %v", err) } - // TODO: This test fails, but should not. - // Related to https://github.com/spf13/cobra/issues/252. - // - // if parentPersPreArgs != "one two" { - // t.Errorf("Expected parentPersPreArgs %q, got %q", "one two", parentPersPreArgs) - // } + // TODO: currently PersistenPreRun* defined in parent does not + // run if the matchin child subcommand has PersistenPreRun. + // If the behavior changes (https://github.com/spf13/cobra/issues/252) + // this test must be fixed. + if parentPersPreArgs != "" { + t.Errorf("Expected blank parentPersPreArgs, got %q", parentPersPreArgs) + } if parentPreArgs != "" { t.Errorf("Expected blank parentPreArgs, got %q", parentPreArgs) } @@ -1179,12 +1180,13 @@ func TestPersistentHooks(t *testing.T) { if parentPostArgs != "" { t.Errorf("Expected blank parentPostArgs, got %q", parentPostArgs) } - // TODO: This test fails, but should not. - // Related to https://github.com/spf13/cobra/issues/252. - // - // if parentPersPostArgs != "one two" { - // t.Errorf("Expected parentPersPostArgs %q, got %q", "one two", parentPersPostArgs) - // } + // TODO: currently PersistenPostRun* defined in parent does not + // run if the matchin child subcommand has PersistenPostRun. + // If the behavior changes (https://github.com/spf13/cobra/issues/252) + // this test must be fixed. + if parentPersPostArgs != "" { + t.Errorf("Expected blank parentPersPostArgs, got %q", parentPersPostArgs) + } if childPersPreArgs != "one two" { t.Errorf("Expected childPersPreArgs %q, got %q", "one two", childPersPreArgs) @@ -1379,6 +1381,46 @@ func TestSetOutput(t *testing.T) { } } +func TestSetOut(t *testing.T) { + c := &Command{} + c.SetOut(nil) + if out := c.OutOrStdout(); out != os.Stdout { + t.Errorf("Expected setting output to nil to revert back to stdout") + } +} + +func TestSetErr(t *testing.T) { + c := &Command{} + c.SetErr(nil) + if out := c.ErrOrStderr(); out != os.Stderr { + t.Errorf("Expected setting error to nil to revert back to stderr") + } +} + +func TestSetIn(t *testing.T) { + c := &Command{} + c.SetIn(nil) + if out := c.InOrStdin(); out != os.Stdin { + t.Errorf("Expected setting input to nil to revert back to stdin") + } +} + +func TestUsageStringRedirected(t *testing.T) { + c := &Command{} + + c.usageFunc = func(cmd *Command) error { + cmd.Print("[stdout1]") + cmd.PrintErr("[stderr2]") + cmd.Print("[stdout3]") + return nil + } + + expected := "[stdout1][stderr2][stdout3]" + if got := c.UsageString(); got != expected { + t.Errorf("Expected usage string to consider both stdout and stderr") + } +} + func TestFlagErrorFunc(t *testing.T) { c := &Command{Use: "c", Run: emptyRun} @@ -1626,3 +1668,108 @@ func TestCalledAs(t *testing.T) { t.Run(name, tc.test) } } + +func TestFParseErrWhitelistBackwardCompatibility(t *testing.T) { + c := &Command{Use: "c", Run: emptyRun} + c.Flags().BoolP("boola", "a", false, "a boolean flag") + + output, err := executeCommand(c, "c", "-a", "--unknown", "flag") + if err == nil { + t.Error("expected unknown flag error") + } + checkStringContains(t, output, "unknown flag: --unknown") +} + +func TestFParseErrWhitelistSameCommand(t *testing.T) { + c := &Command{ + Use: "c", + Run: emptyRun, + FParseErrWhitelist: FParseErrWhitelist{ + UnknownFlags: true, + }, + } + c.Flags().BoolP("boola", "a", false, "a boolean flag") + + _, err := executeCommand(c, "c", "-a", "--unknown", "flag") + if err != nil { + t.Error("unexpected error: ", err) + } +} + +func TestFParseErrWhitelistParentCommand(t *testing.T) { + root := &Command{ + Use: "root", + Run: emptyRun, + FParseErrWhitelist: FParseErrWhitelist{ + UnknownFlags: true, + }, + } + + c := &Command{ + Use: "child", + Run: emptyRun, + } + c.Flags().BoolP("boola", "a", false, "a boolean flag") + + root.AddCommand(c) + + output, err := executeCommand(root, "child", "-a", "--unknown", "flag") + if err == nil { + t.Error("expected unknown flag error") + } + checkStringContains(t, output, "unknown flag: --unknown") +} + +func TestFParseErrWhitelistChildCommand(t *testing.T) { + root := &Command{ + Use: "root", + Run: emptyRun, + } + + c := &Command{ + Use: "child", + Run: emptyRun, + FParseErrWhitelist: FParseErrWhitelist{ + UnknownFlags: true, + }, + } + c.Flags().BoolP("boola", "a", false, "a boolean flag") + + root.AddCommand(c) + + _, err := executeCommand(root, "child", "-a", "--unknown", "flag") + if err != nil { + t.Error("unexpected error: ", err.Error()) + } +} + +func TestFParseErrWhitelistSiblingCommand(t *testing.T) { + root := &Command{ + Use: "root", + Run: emptyRun, + } + + c := &Command{ + Use: "child", + Run: emptyRun, + FParseErrWhitelist: FParseErrWhitelist{ + UnknownFlags: true, + }, + } + c.Flags().BoolP("boola", "a", false, "a boolean flag") + + s := &Command{ + Use: "sibling", + Run: emptyRun, + } + s.Flags().BoolP("boolb", "b", false, "a boolean flag") + + root.AddCommand(c) + root.AddCommand(s) + + output, err := executeCommand(root, "sibling", "-b", "--unknown", "flag") + if err == nil { + t.Error("expected unknown flag error") + } + checkStringContains(t, output, "unknown flag: --unknown") +} diff --git a/vendor/github.com/spf13/cobra/command_win.go b/vendor/github.com/spf13/cobra/command_win.go index edec728e4f5a..8768b1736dca 100644 --- a/vendor/github.com/spf13/cobra/command_win.go +++ b/vendor/github.com/spf13/cobra/command_win.go @@ -3,6 +3,7 @@ package cobra import ( + "fmt" "os" "time" @@ -14,7 +15,12 @@ var preExecHookFn = preExecHook func preExecHook(c *Command) { if MousetrapHelpText != "" && mousetrap.StartedByExplorer() { c.Print(MousetrapHelpText) - time.Sleep(5 * time.Second) + if MousetrapDisplayDuration > 0 { + time.Sleep(MousetrapDisplayDuration) + } else { + c.Println("Press return to continue...") + fmt.Scanln() + } os.Exit(1) } } diff --git a/vendor/github.com/spf13/cobra/doc/man_docs.go b/vendor/github.com/spf13/cobra/doc/man_docs.go index ce92332dd178..4a0623393f56 100644 --- a/vendor/github.com/spf13/cobra/doc/man_docs.go +++ b/vendor/github.com/spf13/cobra/doc/man_docs.go @@ -20,6 +20,7 @@ import ( "os" "path/filepath" "sort" + "strconv" "strings" "time" @@ -87,7 +88,7 @@ type GenManTreeOptions struct { // GenManHeader is a lot like the .TH header at the start of man pages. These // include the title, section, date, source, and manual. We will use the -// current time if Date if unset and will use "Auto generated by spf13/cobra" +// current time if Date is unset and will use "Auto generated by spf13/cobra" // if the Source is unset. type GenManHeader struct { Title string @@ -104,14 +105,16 @@ func GenMan(cmd *cobra.Command, header *GenManHeader, w io.Writer) error { if header == nil { header = &GenManHeader{} } - fillHeader(header, cmd.CommandPath()) + if err := fillHeader(header, cmd.CommandPath()); err != nil { + return err + } b := genMan(cmd, header) _, err := w.Write(md2man.Render(b)) return err } -func fillHeader(header *GenManHeader, name string) { +func fillHeader(header *GenManHeader, name string) error { if header.Title == "" { header.Title = strings.ToUpper(strings.Replace(name, " ", "\\-", -1)) } @@ -120,12 +123,20 @@ func fillHeader(header *GenManHeader, name string) { } if header.Date == nil { now := time.Now() + if epoch := os.Getenv("SOURCE_DATE_EPOCH"); epoch != "" { + unixEpoch, err := strconv.ParseInt(epoch, 10, 64) + if err != nil { + return fmt.Errorf("invalid SOURCE_DATE_EPOCH: %v", err) + } + now = time.Unix(unixEpoch, 0) + } header.Date = &now } header.date = (*header.Date).Format("Jan 2006") if header.Source == "" { header.Source = "Auto generated by spf13/cobra" } + return nil } func manPreamble(buf *bytes.Buffer, header *GenManHeader, cmd *cobra.Command, dashedName string) { @@ -176,13 +187,13 @@ func manPrintFlags(buf *bytes.Buffer, flags *pflag.FlagSet) { func manPrintOptions(buf *bytes.Buffer, command *cobra.Command) { flags := command.NonInheritedFlags() - if flags.HasFlags() { + if flags.HasAvailableFlags() { buf.WriteString("# OPTIONS\n") manPrintFlags(buf, flags) buf.WriteString("\n") } flags = command.InheritedFlags() - if flags.HasFlags() { + if flags.HasAvailableFlags() { buf.WriteString("# OPTIONS INHERITED FROM PARENT COMMANDS\n") manPrintFlags(buf, flags) buf.WriteString("\n") diff --git a/vendor/github.com/spf13/cobra/doc/man_docs_test.go b/vendor/github.com/spf13/cobra/doc/man_docs_test.go index 62f85e47f468..2c400f5df7e9 100644 --- a/vendor/github.com/spf13/cobra/doc/man_docs_test.go +++ b/vendor/github.com/spf13/cobra/doc/man_docs_test.go @@ -47,6 +47,42 @@ func TestGenManDoc(t *testing.T) { checkStringContains(t, output, translate("Auto generated")) } +func TestGenManNoHiddenParents(t *testing.T) { + header := &GenManHeader{ + Title: "Project", + Section: "2", + } + + // We generate on a subcommand so we have both subcommands and parents + for _, name := range []string{"rootflag", "strtwo"} { + f := rootCmd.PersistentFlags().Lookup(name) + f.Hidden = true + defer func() { f.Hidden = false }() + } + buf := new(bytes.Buffer) + if err := GenMan(echoCmd, header, buf); err != nil { + t.Fatal(err) + } + output := buf.String() + + // Make sure parent has - in CommandPath() in SEE ALSO: + parentPath := echoCmd.Parent().CommandPath() + dashParentPath := strings.Replace(parentPath, " ", "-", -1) + expected := translate(dashParentPath) + expected = expected + "(" + header.Section + ")" + checkStringContains(t, output, expected) + + checkStringContains(t, output, translate(echoCmd.Name())) + checkStringContains(t, output, translate(echoCmd.Name())) + checkStringContains(t, output, "boolone") + checkStringOmits(t, output, "rootflag") + checkStringContains(t, output, translate(rootCmd.Name())) + checkStringContains(t, output, translate(echoSubCmd.Name())) + checkStringOmits(t, output, translate(deprecatedCmd.Name())) + checkStringContains(t, output, translate("Auto generated")) + checkStringOmits(t, output, "OPTIONS INHERITED FROM PARENT COMMANDS") +} + func TestGenManNoGenTag(t *testing.T) { echoCmd.DisableAutoGenTag = true defer func() { echoCmd.DisableAutoGenTag = false }() diff --git a/vendor/github.com/spf13/cobra/doc/md_docs.go b/vendor/github.com/spf13/cobra/doc/md_docs.go index d7a2c2b62991..d76f6d5ecb45 100644 --- a/vendor/github.com/spf13/cobra/doc/md_docs.go +++ b/vendor/github.com/spf13/cobra/doc/md_docs.go @@ -29,7 +29,7 @@ import ( func printOptions(buf *bytes.Buffer, cmd *cobra.Command, name string) error { flags := cmd.NonInheritedFlags() flags.SetOutput(buf) - if flags.HasFlags() { + if flags.HasAvailableFlags() { buf.WriteString("### Options\n\n```\n") flags.PrintDefaults() buf.WriteString("```\n\n") @@ -37,7 +37,7 @@ func printOptions(buf *bytes.Buffer, cmd *cobra.Command, name string) error { parentFlags := cmd.InheritedFlags() parentFlags.SetOutput(buf) - if parentFlags.HasFlags() { + if parentFlags.HasAvailableFlags() { buf.WriteString("### Options inherited from parent commands\n\n```\n") parentFlags.PrintDefaults() buf.WriteString("```\n\n") diff --git a/vendor/github.com/spf13/cobra/doc/md_docs_test.go b/vendor/github.com/spf13/cobra/doc/md_docs_test.go index b0fa68c0b906..c060f32f7884 100644 --- a/vendor/github.com/spf13/cobra/doc/md_docs_test.go +++ b/vendor/github.com/spf13/cobra/doc/md_docs_test.go @@ -25,6 +25,30 @@ func TestGenMdDoc(t *testing.T) { checkStringContains(t, output, rootCmd.Short) checkStringContains(t, output, echoSubCmd.Short) checkStringOmits(t, output, deprecatedCmd.Short) + checkStringContains(t, output, "Options inherited from parent commands") +} + +func TestGenMdNoHiddenParents(t *testing.T) { + // We generate on subcommand so we have both subcommands and parents. + for _, name := range []string{"rootflag", "strtwo"} { + f := rootCmd.PersistentFlags().Lookup(name) + f.Hidden = true + defer func() { f.Hidden = false }() + } + buf := new(bytes.Buffer) + if err := GenMarkdown(echoCmd, buf); err != nil { + t.Fatal(err) + } + output := buf.String() + + checkStringContains(t, output, echoCmd.Long) + checkStringContains(t, output, echoCmd.Example) + checkStringContains(t, output, "boolone") + checkStringOmits(t, output, "rootflag") + checkStringContains(t, output, rootCmd.Short) + checkStringContains(t, output, echoSubCmd.Short) + checkStringOmits(t, output, deprecatedCmd.Short) + checkStringOmits(t, output, "Options inherited from parent commands") } func TestGenMdNoTag(t *testing.T) { diff --git a/vendor/github.com/spf13/cobra/doc/rest_docs.go b/vendor/github.com/spf13/cobra/doc/rest_docs.go index 4913e3ee2ea2..051d8dc832a4 100644 --- a/vendor/github.com/spf13/cobra/doc/rest_docs.go +++ b/vendor/github.com/spf13/cobra/doc/rest_docs.go @@ -29,7 +29,7 @@ import ( func printOptionsReST(buf *bytes.Buffer, cmd *cobra.Command, name string) error { flags := cmd.NonInheritedFlags() flags.SetOutput(buf) - if flags.HasFlags() { + if flags.HasAvailableFlags() { buf.WriteString("Options\n") buf.WriteString("~~~~~~~\n\n::\n\n") flags.PrintDefaults() @@ -38,7 +38,7 @@ func printOptionsReST(buf *bytes.Buffer, cmd *cobra.Command, name string) error parentFlags := cmd.InheritedFlags() parentFlags.SetOutput(buf) - if parentFlags.HasFlags() { + if parentFlags.HasAvailableFlags() { buf.WriteString("Options inherited from parent commands\n") buf.WriteString("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n::\n\n") parentFlags.PrintDefaults() diff --git a/vendor/github.com/spf13/cobra/doc/rest_docs_test.go b/vendor/github.com/spf13/cobra/doc/rest_docs_test.go index aa3186e8f94a..330a2e5e70e0 100644 --- a/vendor/github.com/spf13/cobra/doc/rest_docs_test.go +++ b/vendor/github.com/spf13/cobra/doc/rest_docs_test.go @@ -27,6 +27,29 @@ func TestGenRSTDoc(t *testing.T) { checkStringOmits(t, output, deprecatedCmd.Short) } +func TestGenRSTNoHiddenParents(t *testing.T) { + // We generate on a subcommand so we have both subcommands and parents + for _, name := range []string{"rootflag", "strtwo"} { + f := rootCmd.PersistentFlags().Lookup(name) + f.Hidden = true + defer func() { f.Hidden = false }() + } + buf := new(bytes.Buffer) + if err := GenReST(echoCmd, buf); err != nil { + t.Fatal(err) + } + output := buf.String() + + checkStringContains(t, output, echoCmd.Long) + checkStringContains(t, output, echoCmd.Example) + checkStringContains(t, output, "boolone") + checkStringOmits(t, output, "rootflag") + checkStringContains(t, output, rootCmd.Short) + checkStringContains(t, output, echoSubCmd.Short) + checkStringOmits(t, output, deprecatedCmd.Short) + checkStringOmits(t, output, "Options inherited from parent commands") +} + func TestGenRSTNoTag(t *testing.T) { rootCmd.DisableAutoGenTag = true defer func() { rootCmd.DisableAutoGenTag = false }() diff --git a/vendor/github.com/spf13/cobra/go.mod b/vendor/github.com/spf13/cobra/go.mod new file mode 100644 index 000000000000..9a9eb65a3703 --- /dev/null +++ b/vendor/github.com/spf13/cobra/go.mod @@ -0,0 +1,13 @@ +module github.com/spf13/cobra + +go 1.12 + +require ( + github.com/BurntSushi/toml v0.3.1 // indirect + github.com/cpuguy83/go-md2man v1.0.10 + github.com/inconshreveable/mousetrap v1.0.0 + github.com/mitchellh/go-homedir v1.1.0 + github.com/spf13/pflag v1.0.3 + github.com/spf13/viper v1.3.2 + gopkg.in/yaml.v2 v2.2.2 +) diff --git a/vendor/github.com/spf13/cobra/go.sum b/vendor/github.com/spf13/cobra/go.sum new file mode 100644 index 000000000000..9761f4d03fe7 --- /dev/null +++ b/vendor/github.com/spf13/cobra/go.sum @@ -0,0 +1,51 @@ +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/viper v1.3.2 h1:VUFqw5KcqRf7i70GOzW7N+Q7+gxVBkSSqiXB12+JQ4M= +github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a h1:1n5lsVfiQW3yfsRGu98756EH1YthsFqr/5mxHduZW2A= +golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/vendor/github.com/spf13/cobra/powershell_completions.go b/vendor/github.com/spf13/cobra/powershell_completions.go new file mode 100644 index 000000000000..756c61b9dcb3 --- /dev/null +++ b/vendor/github.com/spf13/cobra/powershell_completions.go @@ -0,0 +1,100 @@ +// PowerShell completions are based on the amazing work from clap: +// https://github.com/clap-rs/clap/blob/3294d18efe5f264d12c9035f404c7d189d4824e1/src/completions/powershell.rs +// +// The generated scripts require PowerShell v5.0+ (which comes Windows 10, but +// can be downloaded separately for windows 7 or 8.1). + +package cobra + +import ( + "bytes" + "fmt" + "io" + "os" + "strings" + + "github.com/spf13/pflag" +) + +var powerShellCompletionTemplate = `using namespace System.Management.Automation +using namespace System.Management.Automation.Language +Register-ArgumentCompleter -Native -CommandName '%s' -ScriptBlock { + param($wordToComplete, $commandAst, $cursorPosition) + $commandElements = $commandAst.CommandElements + $command = @( + '%s' + for ($i = 1; $i -lt $commandElements.Count; $i++) { + $element = $commandElements[$i] + if ($element -isnot [StringConstantExpressionAst] -or + $element.StringConstantType -ne [StringConstantType]::BareWord -or + $element.Value.StartsWith('-')) { + break + } + $element.Value + } + ) -join ';' + $completions = @(switch ($command) {%s + }) + $completions.Where{ $_.CompletionText -like "$wordToComplete*" } | + Sort-Object -Property ListItemText +}` + +func generatePowerShellSubcommandCases(out io.Writer, cmd *Command, previousCommandName string) { + var cmdName string + if previousCommandName == "" { + cmdName = cmd.Name() + } else { + cmdName = fmt.Sprintf("%s;%s", previousCommandName, cmd.Name()) + } + + fmt.Fprintf(out, "\n '%s' {", cmdName) + + cmd.Flags().VisitAll(func(flag *pflag.Flag) { + if nonCompletableFlag(flag) { + return + } + usage := escapeStringForPowerShell(flag.Usage) + if len(flag.Shorthand) > 0 { + fmt.Fprintf(out, "\n [CompletionResult]::new('-%s', '%s', [CompletionResultType]::ParameterName, '%s')", flag.Shorthand, flag.Shorthand, usage) + } + fmt.Fprintf(out, "\n [CompletionResult]::new('--%s', '%s', [CompletionResultType]::ParameterName, '%s')", flag.Name, flag.Name, usage) + }) + + for _, subCmd := range cmd.Commands() { + usage := escapeStringForPowerShell(subCmd.Short) + fmt.Fprintf(out, "\n [CompletionResult]::new('%s', '%s', [CompletionResultType]::ParameterValue, '%s')", subCmd.Name(), subCmd.Name(), usage) + } + + fmt.Fprint(out, "\n break\n }") + + for _, subCmd := range cmd.Commands() { + generatePowerShellSubcommandCases(out, subCmd, cmdName) + } +} + +func escapeStringForPowerShell(s string) string { + return strings.Replace(s, "'", "''", -1) +} + +// GenPowerShellCompletion generates PowerShell completion file and writes to the passed writer. +func (c *Command) GenPowerShellCompletion(w io.Writer) error { + buf := new(bytes.Buffer) + + var subCommandCases bytes.Buffer + generatePowerShellSubcommandCases(&subCommandCases, c, "") + fmt.Fprintf(buf, powerShellCompletionTemplate, c.Name(), c.Name(), subCommandCases.String()) + + _, err := buf.WriteTo(w) + return err +} + +// GenPowerShellCompletionFile generates PowerShell completion file. +func (c *Command) GenPowerShellCompletionFile(filename string) error { + outFile, err := os.Create(filename) + if err != nil { + return err + } + defer outFile.Close() + + return c.GenPowerShellCompletion(outFile) +} diff --git a/vendor/github.com/spf13/cobra/powershell_completions.md b/vendor/github.com/spf13/cobra/powershell_completions.md new file mode 100644 index 000000000000..afed80240877 --- /dev/null +++ b/vendor/github.com/spf13/cobra/powershell_completions.md @@ -0,0 +1,14 @@ +# Generating PowerShell Completions For Your Own cobra.Command + +Cobra can generate PowerShell completion scripts. Users need PowerShell version 5.0 or above, which comes with Windows 10 and can be downloaded separately for Windows 7 or 8.1. They can then write the completions to a file and source this file from their PowerShell profile, which is referenced by the `$Profile` environment variable. See `Get-Help about_Profiles` for more info about PowerShell profiles. + +# What's supported + +- Completion for subcommands using their `.Short` description +- Completion for non-hidden flags using their `.Name` and `.Shorthand` + +# What's not yet supported + +- Command aliases +- Required, filename or custom flags (they will work like normal flags) +- Custom completion scripts diff --git a/vendor/github.com/spf13/cobra/powershell_completions_test.go b/vendor/github.com/spf13/cobra/powershell_completions_test.go new file mode 100644 index 000000000000..29b609de0540 --- /dev/null +++ b/vendor/github.com/spf13/cobra/powershell_completions_test.go @@ -0,0 +1,122 @@ +package cobra + +import ( + "bytes" + "strings" + "testing" +) + +func TestPowerShellCompletion(t *testing.T) { + tcs := []struct { + name string + root *Command + expectedExpressions []string + }{ + { + name: "trivial", + root: &Command{Use: "trivialapp"}, + expectedExpressions: []string{ + "Register-ArgumentCompleter -Native -CommandName 'trivialapp' -ScriptBlock", + "$command = @(\n 'trivialapp'\n", + }, + }, + { + name: "tree", + root: func() *Command { + r := &Command{Use: "tree"} + + sub1 := &Command{Use: "sub1"} + r.AddCommand(sub1) + + sub11 := &Command{Use: "sub11"} + sub12 := &Command{Use: "sub12"} + + sub1.AddCommand(sub11) + sub1.AddCommand(sub12) + + sub2 := &Command{Use: "sub2"} + r.AddCommand(sub2) + + sub21 := &Command{Use: "sub21"} + sub22 := &Command{Use: "sub22"} + + sub2.AddCommand(sub21) + sub2.AddCommand(sub22) + + return r + }(), + expectedExpressions: []string{ + "'tree'", + "[CompletionResult]::new('sub1', 'sub1', [CompletionResultType]::ParameterValue, '')", + "[CompletionResult]::new('sub2', 'sub2', [CompletionResultType]::ParameterValue, '')", + "'tree;sub1'", + "[CompletionResult]::new('sub11', 'sub11', [CompletionResultType]::ParameterValue, '')", + "[CompletionResult]::new('sub12', 'sub12', [CompletionResultType]::ParameterValue, '')", + "'tree;sub1;sub11'", + "'tree;sub1;sub12'", + "'tree;sub2'", + "[CompletionResult]::new('sub21', 'sub21', [CompletionResultType]::ParameterValue, '')", + "[CompletionResult]::new('sub22', 'sub22', [CompletionResultType]::ParameterValue, '')", + "'tree;sub2;sub21'", + "'tree;sub2;sub22'", + }, + }, + { + name: "flags", + root: func() *Command { + r := &Command{Use: "flags"} + r.Flags().StringP("flag1", "a", "", "") + r.Flags().String("flag2", "", "") + + sub1 := &Command{Use: "sub1"} + sub1.Flags().StringP("flag3", "c", "", "") + r.AddCommand(sub1) + + return r + }(), + expectedExpressions: []string{ + "'flags'", + "[CompletionResult]::new('-a', 'a', [CompletionResultType]::ParameterName, '')", + "[CompletionResult]::new('--flag1', 'flag1', [CompletionResultType]::ParameterName, '')", + "[CompletionResult]::new('--flag2', 'flag2', [CompletionResultType]::ParameterName, '')", + "[CompletionResult]::new('sub1', 'sub1', [CompletionResultType]::ParameterValue, '')", + "'flags;sub1'", + "[CompletionResult]::new('-c', 'c', [CompletionResultType]::ParameterName, '')", + "[CompletionResult]::new('--flag3', 'flag3', [CompletionResultType]::ParameterName, '')", + }, + }, + { + name: "usage", + root: func() *Command { + r := &Command{Use: "usage"} + r.Flags().String("flag", "", "this describes the usage of the 'flag' flag") + + sub1 := &Command{ + Use: "sub1", + Short: "short describes 'sub1'", + } + r.AddCommand(sub1) + + return r + }(), + expectedExpressions: []string{ + "[CompletionResult]::new('--flag', 'flag', [CompletionResultType]::ParameterName, 'this describes the usage of the ''flag'' flag')", + "[CompletionResult]::new('sub1', 'sub1', [CompletionResultType]::ParameterValue, 'short describes ''sub1''')", + }, + }, + } + + for _, tc := range tcs { + t.Run(tc.name, func(t *testing.T) { + buf := new(bytes.Buffer) + tc.root.GenPowerShellCompletion(buf) + output := buf.String() + + for _, expectedExpression := range tc.expectedExpressions { + if !strings.Contains(output, expectedExpression) { + t.Errorf("Expected completion to contain %q somewhere; got %q", expectedExpression, output) + } + } + }) + } +} diff --git a/vendor/github.com/spf13/cobra/shell_completions.go b/vendor/github.com/spf13/cobra/shell_completions.go new file mode 100644 index 000000000000..ba0af9cb553a --- /dev/null +++ b/vendor/github.com/spf13/cobra/shell_completions.go @@ -0,0 +1,85 @@ +package cobra + +import ( + "github.com/spf13/pflag" +) + +// MarkFlagRequired adds the BashCompOneRequiredFlag annotation to the named flag if it exists, +// and causes your command to report an error if invoked without the flag. +func (c *Command) MarkFlagRequired(name string) error { + return MarkFlagRequired(c.Flags(), name) +} + +// MarkPersistentFlagRequired adds the BashCompOneRequiredFlag annotation to the named persistent flag if it exists, +// and causes your command to report an error if invoked without the flag. +func (c *Command) MarkPersistentFlagRequired(name string) error { + return MarkFlagRequired(c.PersistentFlags(), name) +} + +// MarkFlagRequired adds the BashCompOneRequiredFlag annotation to the named flag if it exists, +// and causes your command to report an error if invoked without the flag. +func MarkFlagRequired(flags *pflag.FlagSet, name string) error { + return flags.SetAnnotation(name, BashCompOneRequiredFlag, []string{"true"}) +} + +// MarkFlagFilename adds the BashCompFilenameExt annotation to the named flag, if it exists. +// Generated bash autocompletion will select filenames for the flag, limiting to named extensions if provided. +func (c *Command) MarkFlagFilename(name string, extensions ...string) error { + return MarkFlagFilename(c.Flags(), name, extensions...) +} + +// MarkFlagCustom adds the BashCompCustom annotation to the named flag, if it exists. +// Generated bash autocompletion will call the bash function f for the flag. +func (c *Command) MarkFlagCustom(name string, f string) error { + return MarkFlagCustom(c.Flags(), name, f) +} + +// MarkPersistentFlagFilename instructs the various shell completion +// implementations to limit completions for this persistent flag to the +// specified extensions (patterns). +// +// Shell Completion compatibility matrix: bash, zsh +func (c *Command) MarkPersistentFlagFilename(name string, extensions ...string) error { + return MarkFlagFilename(c.PersistentFlags(), name, extensions...) +} + +// MarkFlagFilename instructs the various shell completion implementations to +// limit completions for this flag to the specified extensions (patterns). +// +// Shell Completion compatibility matrix: bash, zsh +func MarkFlagFilename(flags *pflag.FlagSet, name string, extensions ...string) error { + return flags.SetAnnotation(name, BashCompFilenameExt, extensions) +} + +// MarkFlagCustom instructs the various shell completion implementations to +// limit completions for this flag to the specified extensions (patterns). +// +// Shell Completion compatibility matrix: bash, zsh +func MarkFlagCustom(flags *pflag.FlagSet, name string, f string) error { + return flags.SetAnnotation(name, BashCompCustom, []string{f}) +} + +// MarkFlagDirname instructs the various shell completion implementations to +// complete only directories with this named flag. +// +// Shell Completion compatibility matrix: zsh +func (c *Command) MarkFlagDirname(name string) error { + return MarkFlagDirname(c.Flags(), name) +} + +// MarkPersistentFlagDirname instructs the various shell completion +// implementations to complete only directories with this persistent named flag. +// +// Shell Completion compatibility matrix: zsh +func (c *Command) MarkPersistentFlagDirname(name string) error { + return MarkFlagDirname(c.PersistentFlags(), name) +} + +// MarkFlagDirname instructs the various shell completion implementations to +// complete only directories with this specified flag. +// +// Shell Completion compatibility matrix: zsh +func MarkFlagDirname(flags *pflag.FlagSet, name string) error { + zshPattern := "-(/)" + return flags.SetAnnotation(name, zshCompDirname, []string{zshPattern}) +} diff --git a/vendor/github.com/spf13/cobra/zsh_completions.go b/vendor/github.com/spf13/cobra/zsh_completions.go index 889c22e273c4..12755482f0ce 100644 --- a/vendor/github.com/spf13/cobra/zsh_completions.go +++ b/vendor/github.com/spf13/cobra/zsh_completions.go @@ -1,13 +1,102 @@ package cobra import ( - "bytes" + "encoding/json" "fmt" "io" "os" + "sort" "strings" + "text/template" + + "github.com/spf13/pflag" +) + +const ( + zshCompArgumentAnnotation = "cobra_annotations_zsh_completion_argument_annotation" + zshCompArgumentFilenameComp = "cobra_annotations_zsh_completion_argument_file_completion" + zshCompArgumentWordComp = "cobra_annotations_zsh_completion_argument_word_completion" + zshCompDirname = "cobra_annotations_zsh_dirname" +) + +var ( + zshCompFuncMap = template.FuncMap{ + "genZshFuncName": zshCompGenFuncName, + "extractFlags": zshCompExtractFlag, + "genFlagEntryForZshArguments": zshCompGenFlagEntryForArguments, + "extractArgsCompletions": zshCompExtractArgumentCompletionHintsForRendering, + } + zshCompletionText = ` +{{/* should accept Command (that contains subcommands) as parameter */}} +{{define "argumentsC" -}} +{{ $cmdPath := genZshFuncName .}} +function {{$cmdPath}} { + local -a commands + + _arguments -C \{{- range extractFlags .}} + {{genFlagEntryForZshArguments .}} \{{- end}} + "1: :->cmnds" \ + "*::arg:->args" + + case $state in + cmnds) + commands=({{range .Commands}}{{if not .Hidden}} + "{{.Name}}:{{.Short}}"{{end}}{{end}} + ) + _describe "command" commands + ;; + esac + + case "$words[1]" in {{- range .Commands}}{{if not .Hidden}} + {{.Name}}) + {{$cmdPath}}_{{.Name}} + ;;{{end}}{{end}} + esac +} +{{range .Commands}}{{if not .Hidden}} +{{template "selectCmdTemplate" .}} +{{- end}}{{end}} +{{- end}} + +{{/* should accept Command without subcommands as parameter */}} +{{define "arguments" -}} +function {{genZshFuncName .}} { +{{" _arguments"}}{{range extractFlags .}} \ + {{genFlagEntryForZshArguments . -}} +{{end}}{{range extractArgsCompletions .}} \ + {{.}}{{end}} +} +{{end}} + +{{/* dispatcher for commands with or without subcommands */}} +{{define "selectCmdTemplate" -}} +{{if .Hidden}}{{/* ignore hidden*/}}{{else -}} +{{if .Commands}}{{template "argumentsC" .}}{{else}}{{template "arguments" .}}{{end}} +{{- end}} +{{- end}} + +{{/* template entry point */}} +{{define "Main" -}} +#compdef _{{.Name}} {{.Name}} + +{{template "selectCmdTemplate" .}} +{{end}} +` ) +// zshCompArgsAnnotation is used to encode/decode zsh completion for +// arguments to/from Command.Annotations. +type zshCompArgsAnnotation map[int]zshCompArgHint + +type zshCompArgHint struct { + // Indicates the type of the completion to use. One of: + // zshCompArgumentFilenameComp or zshCompArgumentWordComp + Tipe string `json:"type"` + + // A value for the type above (globs for file completion or words) + Options []string `json:"options"` +} + // GenZshCompletionFile generates zsh completion file. func (c *Command) GenZshCompletionFile(filename string) error { outFile, err := os.Create(filename) @@ -19,108 +108,229 @@ func (c *Command) GenZshCompletionFile(filename string) error { return c.GenZshCompletion(outFile) } -// GenZshCompletion generates a zsh completion file and writes to the passed writer. +// GenZshCompletion generates a zsh completion file and writes to the passed +// writer. The completion always run on the root command regardless of the +// command it was called from. func (c *Command) GenZshCompletion(w io.Writer) error { - buf := new(bytes.Buffer) - - writeHeader(buf, c) - maxDepth := maxDepth(c) - writeLevelMapping(buf, maxDepth) - writeLevelCases(buf, maxDepth, c) + tmpl, err := template.New("Main").Funcs(zshCompFuncMap).Parse(zshCompletionText) + if err != nil { + return fmt.Errorf("error creating zsh completion template: %v", err) + } + return tmpl.Execute(w, c.Root()) +} - _, err := buf.WriteTo(w) - return err +// MarkZshCompPositionalArgumentFile marks the specified argument (first +// argument is 1) as completed by file selection. patterns (e.g. "*.txt") are +// optional - if not provided the completion will search for all files. +func (c *Command) MarkZshCompPositionalArgumentFile(argPosition int, patterns ...string) error { + if argPosition < 1 { + return fmt.Errorf("Invalid argument position (%d)", argPosition) + } + annotation, err := c.zshCompGetArgsAnnotations() + if err != nil { + return err + } + if c.zshcompArgsAnnotationnIsDuplicatePosition(annotation, argPosition) { + return fmt.Errorf("Duplicate annotation for positional argument at index %d", argPosition) + } + annotation[argPosition] = zshCompArgHint{ + Tipe: zshCompArgumentFilenameComp, + Options: patterns, + } + return c.zshCompSetArgsAnnotations(annotation) } -func writeHeader(w io.Writer, cmd *Command) { - fmt.Fprintf(w, "#compdef %s\n\n", cmd.Name()) +// MarkZshCompPositionalArgumentWords marks the specified positional argument +// (first argument is 1) as completed by the provided words. At east one word +// must be provided, spaces within words will be offered completion with +// "word\ word". +func (c *Command) MarkZshCompPositionalArgumentWords(argPosition int, words ...string) error { + if argPosition < 1 { + return fmt.Errorf("Invalid argument position (%d)", argPosition) + } + if len(words) == 0 { + return fmt.Errorf("Trying to set empty word list for positional argument %d", argPosition) + } + annotation, err := c.zshCompGetArgsAnnotations() + if err != nil { + return err + } + if c.zshcompArgsAnnotationnIsDuplicatePosition(annotation, argPosition) { + return fmt.Errorf("Duplicate annotation for positional argument at index %d", argPosition) + } + annotation[argPosition] = zshCompArgHint{ + Tipe: zshCompArgumentWordComp, + Options: words, + } + return c.zshCompSetArgsAnnotations(annotation) } -func maxDepth(c *Command) int { - if len(c.Commands()) == 0 { - return 0 +func zshCompExtractArgumentCompletionHintsForRendering(c *Command) ([]string, error) { + var result []string + annotation, err := c.zshCompGetArgsAnnotations() + if err != nil { + return nil, err } - maxDepthSub := 0 - for _, s := range c.Commands() { - subDepth := maxDepth(s) - if subDepth > maxDepthSub { - maxDepthSub = subDepth + for k, v := range annotation { + s, err := zshCompRenderZshCompArgHint(k, v) + if err != nil { + return nil, err } + result = append(result, s) } - return 1 + maxDepthSub + if len(c.ValidArgs) > 0 { + if _, positionOneExists := annotation[1]; !positionOneExists { + s, err := zshCompRenderZshCompArgHint(1, zshCompArgHint{ + Tipe: zshCompArgumentWordComp, + Options: c.ValidArgs, + }) + if err != nil { + return nil, err + } + result = append(result, s) + } + } + sort.Strings(result) + return result, nil } -func writeLevelMapping(w io.Writer, numLevels int) { - fmt.Fprintln(w, `_arguments \`) - for i := 1; i <= numLevels; i++ { - fmt.Fprintf(w, ` '%d: :->level%d' \`, i, i) - fmt.Fprintln(w) +func zshCompRenderZshCompArgHint(i int, z zshCompArgHint) (string, error) { + switch t := z.Tipe; t { + case zshCompArgumentFilenameComp: + var globs []string + for _, g := range z.Options { + globs = append(globs, fmt.Sprintf(`-g "%s"`, g)) + } + return fmt.Sprintf(`'%d: :_files %s'`, i, strings.Join(globs, " ")), nil + case zshCompArgumentWordComp: + var words []string + for _, w := range z.Options { + words = append(words, fmt.Sprintf("%q", w)) + } + return fmt.Sprintf(`'%d: :(%s)'`, i, strings.Join(words, " ")), nil + default: + return "", fmt.Errorf("Invalid zsh argument completion annotation: %s", t) } - fmt.Fprintf(w, ` '%d: :%s'`, numLevels+1, "_files") - fmt.Fprintln(w) } -func writeLevelCases(w io.Writer, maxDepth int, root *Command) { - fmt.Fprintln(w, "case $state in") - defer fmt.Fprintln(w, "esac") +func (c *Command) zshcompArgsAnnotationnIsDuplicatePosition(annotation zshCompArgsAnnotation, position int) bool { + _, dup := annotation[position] + return dup +} - for i := 1; i <= maxDepth; i++ { - fmt.Fprintf(w, " level%d)\n", i) - writeLevel(w, root, i) - fmt.Fprintln(w, " ;;") +func (c *Command) zshCompGetArgsAnnotations() (zshCompArgsAnnotation, error) { + annotation := make(zshCompArgsAnnotation) + annotationString, ok := c.Annotations[zshCompArgumentAnnotation] + if !ok { + return annotation, nil + } + err := json.Unmarshal([]byte(annotationString), &annotation) + if err != nil { + return annotation, fmt.Errorf("Error unmarshaling zsh argument annotation: %v", err) } - fmt.Fprintln(w, " *)") - fmt.Fprintln(w, " _arguments '*: :_files'") - fmt.Fprintln(w, " ;;") + return annotation, nil } -func writeLevel(w io.Writer, root *Command, i int) { - fmt.Fprintf(w, " case $words[%d] in\n", i) - defer fmt.Fprintln(w, " esac") - - commands := filterByLevel(root, i) - byParent := groupByParent(commands) +func (c *Command) zshCompSetArgsAnnotations(annotation zshCompArgsAnnotation) error { + jsn, err := json.Marshal(annotation) + if err != nil { + return fmt.Errorf("Error marshaling zsh argument annotation: %v", err) + } + if c.Annotations == nil { + c.Annotations = make(map[string]string) + } + c.Annotations[zshCompArgumentAnnotation] = string(jsn) + return nil +} - for p, c := range byParent { - names := names(c) - fmt.Fprintf(w, " %s)\n", p) - fmt.Fprintf(w, " _arguments '%d: :(%s)'\n", i, strings.Join(names, " ")) - fmt.Fprintln(w, " ;;") +func zshCompGenFuncName(c *Command) string { + if c.HasParent() { + return zshCompGenFuncName(c.Parent()) + "_" + c.Name() } - fmt.Fprintln(w, " *)") - fmt.Fprintln(w, " _arguments '*: :_files'") - fmt.Fprintln(w, " ;;") + return "_" + c.Name() +} +func zshCompExtractFlag(c *Command) []*pflag.Flag { + var flags []*pflag.Flag + c.LocalFlags().VisitAll(func(f *pflag.Flag) { + if !f.Hidden { + flags = append(flags, f) + } + }) + c.InheritedFlags().VisitAll(func(f *pflag.Flag) { + if !f.Hidden { + flags = append(flags, f) + } + }) + return flags } -func filterByLevel(c *Command, l int) []*Command { - cs := make([]*Command, 0) - if l == 0 { - cs = append(cs, c) - return cs +// zshCompGenFlagEntryForArguments returns an entry that matches _arguments +// zsh-completion parameters. It's too complicated to generate in a template. +func zshCompGenFlagEntryForArguments(f *pflag.Flag) string { + if f.Name == "" || f.Shorthand == "" { + return zshCompGenFlagEntryForSingleOptionFlag(f) } - for _, s := range c.Commands() { - cs = append(cs, filterByLevel(s, l-1)...) + return zshCompGenFlagEntryForMultiOptionFlag(f) +} + +func zshCompGenFlagEntryForSingleOptionFlag(f *pflag.Flag) string { + var option, multiMark, extras string + + if zshCompFlagCouldBeSpecifiedMoreThenOnce(f) { + multiMark = "*" } - return cs + + option = "--" + f.Name + if option == "--" { + option = "-" + f.Shorthand + } + extras = zshCompGenFlagEntryExtras(f) + + return fmt.Sprintf(`'%s%s[%s]%s'`, multiMark, option, zshCompQuoteFlagDescription(f.Usage), extras) } -func groupByParent(commands []*Command) map[string][]*Command { - m := make(map[string][]*Command) - for _, c := range commands { - parent := c.Parent() - if parent == nil { - continue - } - m[parent.Name()] = append(m[parent.Name()], c) +func zshCompGenFlagEntryForMultiOptionFlag(f *pflag.Flag) string { + var options, parenMultiMark, curlyMultiMark, extras string + + if zshCompFlagCouldBeSpecifiedMoreThenOnce(f) { + parenMultiMark = "*" + curlyMultiMark = "\\*" } - return m + + options = fmt.Sprintf(`'(%s-%s %s--%s)'{%s-%s,%s--%s}`, + parenMultiMark, f.Shorthand, parenMultiMark, f.Name, curlyMultiMark, f.Shorthand, curlyMultiMark, f.Name) + extras = zshCompGenFlagEntryExtras(f) + + return fmt.Sprintf(`%s'[%s]%s'`, options, zshCompQuoteFlagDescription(f.Usage), extras) } -func names(commands []*Command) []string { - ns := make([]string, len(commands)) - for i, c := range commands { - ns[i] = c.Name() +func zshCompGenFlagEntryExtras(f *pflag.Flag) string { + if f.NoOptDefVal != "" { + return "" } - return ns + + extras := ":" // allow options for flag (even without assistance) + for key, values := range f.Annotations { + switch key { + case zshCompDirname: + extras = fmt.Sprintf(":filename:_files -g %q", values[0]) + case BashCompFilenameExt: + extras = ":filename:_files" + for _, pattern := range values { + extras = extras + fmt.Sprintf(` -g "%s"`, pattern) + } + } + } + + return extras +} + +func zshCompFlagCouldBeSpecifiedMoreThenOnce(f *pflag.Flag) bool { + return strings.Contains(f.Value.Type(), "Slice") || + strings.Contains(f.Value.Type(), "Array") +} + +func zshCompQuoteFlagDescription(s string) string { + return strings.Replace(s, "'", `'\''`, -1) } diff --git a/vendor/github.com/spf13/cobra/zsh_completions.md b/vendor/github.com/spf13/cobra/zsh_completions.md new file mode 100644 index 000000000000..df9c2eac93c6 --- /dev/null +++ b/vendor/github.com/spf13/cobra/zsh_completions.md @@ -0,0 +1,39 @@ +## Generating Zsh Completion for your cobra.Command + +Cobra supports native Zsh completion generated from the root `cobra.Command`. +The generated completion script should be put somewhere in your `$fpath` named +`_`. + +### What's Supported + +* Completion for all non-hidden subcommands using their `.Short` description. +* Completion for all non-hidden flags using the following rules: + * Filename completion works by marking the flag with `cmd.MarkFlagFilename...` + family of commands. + * The requirement for argument to the flag is decided by the `.NoOptDefVal` + flag value - if it's empty then completion will expect an argument. + * Flags of one of the various `*Array` and `*Slice` types supports multiple + specifications (with or without argument depending on the specific type). +* Completion of positional arguments using the following rules: + * Argument position for all options below starts at `1`. If argument position + `0` is requested it will raise an error. + * Use `command.MarkZshCompPositionalArgumentFile` to complete filenames. Glob + patterns (e.g. `"*.log"`) are optional - if not specified it will offer to + complete all file types. + * Use `command.MarkZshCompPositionalArgumentWords` to offer specific words for + completion. At least one word is required. + * It's possible to specify completion for some arguments and leave some + unspecified (e.g. offer words for second argument but nothing for first + argument). This will cause no completion for first argument but words + completion for second argument. + * If no argument completion was specified for 1st argument (but optionally was + specified for 2nd) and the command has `ValidArgs` it will be used as + completion options for 1st argument. + * Argument completions only offered for commands with no subcommands. + +### What's not yet Supported + +* Custom completion scripts are not supported yet (We should probably create zsh + specific one, doesn't make sense to re-use the bash one as the functions will + be different). +* Whatever other feature you're looking for and doesn't exist :) diff --git a/vendor/github.com/spf13/cobra/zsh_completions_test.go b/vendor/github.com/spf13/cobra/zsh_completions_test.go index 34e69496f20a..e53fa886e507 100644 --- a/vendor/github.com/spf13/cobra/zsh_completions_test.go +++ b/vendor/github.com/spf13/cobra/zsh_completions_test.go @@ -2,88 +2,474 @@ package cobra import ( "bytes" + "regexp" "strings" "testing" ) -func TestZshCompletion(t *testing.T) { +func TestGenZshCompletion(t *testing.T) { + var debug bool + var option string + tcs := []struct { name string root *Command expectedExpressions []string + invocationArgs []string + skip string }{ { - name: "trivial", - root: &Command{Use: "trivialapp"}, - expectedExpressions: []string{"#compdef trivial"}, + name: "simple command", + root: func() *Command { + r := &Command{ + Use: "mycommand", + Long: "My Command long description", + Run: emptyRun, + } + r.Flags().BoolVar(&debug, "debug", debug, "description") + return r + }(), + expectedExpressions: []string{ + `(?s)function _mycommand {\s+_arguments \\\s+'--debug\[description\]'.*--help.*}`, + "#compdef _mycommand mycommand", + }, }, { - name: "linear", + name: "flags with both long and short flags", root: func() *Command { - r := &Command{Use: "linear"} - - sub1 := &Command{Use: "sub1"} - r.AddCommand(sub1) - - sub2 := &Command{Use: "sub2"} - sub1.AddCommand(sub2) - - sub3 := &Command{Use: "sub3"} - sub2.AddCommand(sub3) + r := &Command{ + Use: "testcmd", + Long: "long description", + Run: emptyRun, + } + r.Flags().BoolVarP(&debug, "debug", "d", debug, "debug description") return r }(), - expectedExpressions: []string{"sub1", "sub2", "sub3"}, + expectedExpressions: []string{ + `'\(-d --debug\)'{-d,--debug}'\[debug description\]'`, + }, }, { - name: "flat", + name: "command with subcommands and flags with values", root: func() *Command { - r := &Command{Use: "flat"} - r.AddCommand(&Command{Use: "c1"}) - r.AddCommand(&Command{Use: "c2"}) + r := &Command{ + Use: "rootcmd", + Long: "Long rootcmd description", + } + d := &Command{ + Use: "subcmd1", + Short: "Subcmd1 short description", + Run: emptyRun, + } + e := &Command{ + Use: "subcmd2", + Long: "Subcmd2 short description", + Run: emptyRun, + } + r.PersistentFlags().BoolVar(&debug, "debug", debug, "description") + d.Flags().StringVarP(&option, "option", "o", option, "option description") + r.AddCommand(d, e) return r }(), - expectedExpressions: []string{"(c1 c2)"}, + expectedExpressions: []string{ + `commands=\(\n\s+"help:.*\n\s+"subcmd1:.*\n\s+"subcmd2:.*\n\s+\)`, + `_arguments \\\n.*'--debug\[description]'`, + `_arguments -C \\\n.*'--debug\[description]'`, + `function _rootcmd_subcmd1 {`, + `function _rootcmd_subcmd1 {`, + `_arguments \\\n.*'\(-o --option\)'{-o,--option}'\[option description]:' \\\n`, + }, }, { - name: "tree", + name: "filename completion with and without globs", root: func() *Command { - r := &Command{Use: "tree"} - - sub1 := &Command{Use: "sub1"} - r.AddCommand(sub1) - - sub11 := &Command{Use: "sub11"} - sub12 := &Command{Use: "sub12"} - - sub1.AddCommand(sub11) - sub1.AddCommand(sub12) + var file string + r := &Command{ + Use: "mycmd", + Short: "my command short description", + Run: emptyRun, + } + r.Flags().StringVarP(&file, "config", "c", file, "config file") + r.MarkFlagFilename("config") + r.Flags().String("output", "", "output file") + r.MarkFlagFilename("output", "*.log", "*.txt") + return r + }(), + expectedExpressions: []string{ + `\n +'\(-c --config\)'{-c,--config}'\[config file]:filename:_files'`, + `:_files -g "\*.log" -g "\*.txt"`, + }, + }, + { + name: "repeated variables both with and without value", + root: func() *Command { + r := genTestCommand("mycmd", true) + _ = r.Flags().BoolSliceP("debug", "d", []bool{}, "debug usage") + _ = r.Flags().StringArray("option", []string{}, "options") + return r + }(), + expectedExpressions: []string{ + `'\*--option\[options]`, + `'\(\*-d \*--debug\)'{\\\*-d,\\\*--debug}`, + }, + }, + { + name: "generated flags --help and --version should be created even when not executing root cmd", + root: func() *Command { + r := &Command{ + Use: "mycmd", + Short: "mycmd short description", + Version: "myversion", + } + s := genTestCommand("sub1", true) + r.AddCommand(s) + return s + }(), + expectedExpressions: []string{ + "--version", + "--help", + }, + invocationArgs: []string{ + "sub1", + }, + skip: "--version and --help are currently not generated when not running on root command", + }, + { + name: "zsh generation should run on root command", + root: func() *Command { + r := genTestCommand("root", false) + s := genTestCommand("sub1", true) + r.AddCommand(s) + return s + }(), + expectedExpressions: []string{ + "function _root {", + }, + }, + { + name: "flag description with single quote (') shouldn't break quotes in completion file", + root: func() *Command { + r := genTestCommand("root", true) + r.Flags().Bool("private", false, "Don't show public info") + return r + }(), + expectedExpressions: []string{ + `--private\[Don'\\''t show public info]`, + }, + }, + { + name: "argument completion for file with and without patterns", + root: func() *Command { + r := genTestCommand("root", true) + r.MarkZshCompPositionalArgumentFile(1, "*.log") + r.MarkZshCompPositionalArgumentFile(2) + return r + }(), + expectedExpressions: []string{ + `'1: :_files -g "\*.log"' \\\n\s+'2: :_files`, + }, + }, + { + name: "argument zsh completion for words", + root: func() *Command { + r := genTestCommand("root", true) + r.MarkZshCompPositionalArgumentWords(1, "word1", "word2") + return r + }(), + expectedExpressions: []string{ + `'1: :\("word1" "word2"\)`, + }, + }, + { + name: "argument completion for words with spaces", + root: func() *Command { + r := genTestCommand("root", true) + r.MarkZshCompPositionalArgumentWords(1, "single", "multiple words") + return r + }(), + expectedExpressions: []string{ + `'1: :\("single" "multiple words"\)'`, + }, + }, + { + name: "argument completion when command has ValidArgs and no annotation for argument completion", + root: func() *Command { + r := genTestCommand("root", true) + r.ValidArgs = []string{"word1", "word2"} + return r + }(), + expectedExpressions: []string{ + `'1: :\("word1" "word2"\)'`, + }, + }, + { + name: "argument completion when command has ValidArgs and no annotation for argument at argPosition 1", + root: func() *Command { + r := genTestCommand("root", true) + r.ValidArgs = []string{"word1", "word2"} + r.MarkZshCompPositionalArgumentFile(2) + return r + }(), + expectedExpressions: []string{ + `'1: :\("word1" "word2"\)' \\`, + }, + }, + { + name: "directory completion for flag", + root: func() *Command { + r := genTestCommand("root", true) + r.Flags().String("test", "", "test") + r.PersistentFlags().String("ptest", "", "ptest") + r.MarkFlagDirname("test") + r.MarkPersistentFlagDirname("ptest") + return r + }(), + expectedExpressions: []string{ + `--test\[test]:filename:_files -g "-\(/\)"`, + `--ptest\[ptest]:filename:_files -g "-\(/\)"`, + }, + }, + } - sub2 := &Command{Use: "sub2"} - r.AddCommand(sub2) + for _, tc := range tcs { + t.Run(tc.name, func(t *testing.T) { + if tc.skip != "" { + t.Skip(tc.skip) + } + tc.root.Root().SetArgs(tc.invocationArgs) + tc.root.Execute() + buf := new(bytes.Buffer) + if err := tc.root.GenZshCompletion(buf); err != nil { + t.Error(err) + } + output := buf.Bytes() - sub21 := &Command{Use: "sub21"} - sub22 := &Command{Use: "sub22"} + for _, expr := range tc.expectedExpressions { + rgx, err := regexp.Compile(expr) + if err != nil { + t.Errorf("error compiling expression (%s): %v", expr, err) + } + if !rgx.Match(output) { + t.Errorf("expected completion (%s) to match '%s'", buf.String(), expr) + } + } + }) + } +} - sub2.AddCommand(sub21) - sub2.AddCommand(sub22) +func TestGenZshCompletionHidden(t *testing.T) { + tcs := []struct { + name string + root *Command + expectedExpressions []string + }{ + { + name: "hidden commands", + root: func() *Command { + r := &Command{ + Use: "main", + Short: "main short description", + } + s1 := &Command{ + Use: "sub1", + Hidden: true, + Run: emptyRun, + } + s2 := &Command{ + Use: "sub2", + Short: "short sub2 description", + Run: emptyRun, + } + r.AddCommand(s1, s2) return r }(), - expectedExpressions: []string{"(sub11 sub12)", "(sub21 sub22)"}, + expectedExpressions: []string{ + "sub1", + }, + }, + { + name: "hidden flags", + root: func() *Command { + var hidden string + r := &Command{ + Use: "root", + Short: "root short description", + Run: emptyRun, + } + r.Flags().StringVarP(&hidden, "hidden", "H", hidden, "hidden usage") + if err := r.Flags().MarkHidden("hidden"); err != nil { + t.Errorf("Error setting flag hidden: %v\n", err) + } + return r + }(), + expectedExpressions: []string{ + "--hidden", + }, }, } for _, tc := range tcs { t.Run(tc.name, func(t *testing.T) { + tc.root.Execute() buf := new(bytes.Buffer) - tc.root.GenZshCompletion(buf) + if err := tc.root.GenZshCompletion(buf); err != nil { + t.Error(err) + } output := buf.String() - for _, expectedExpression := range tc.expectedExpressions { - if !strings.Contains(output, expectedExpression) { - t.Errorf("Expected completion to contain %q somewhere; got %q", expectedExpression, output) + for _, expr := range tc.expectedExpressions { + if strings.Contains(output, expr) { + t.Errorf("Expected completion (%s) not to contain '%s' but it does", output, expr) } } }) } } + +func TestMarkZshCompPositionalArgumentFile(t *testing.T) { + t.Run("Doesn't allow overwriting existing positional argument", func(t *testing.T) { + c := &Command{} + if err := c.MarkZshCompPositionalArgumentFile(1, "*.log"); err != nil { + t.Errorf("Received error when we shouldn't have: %v\n", err) + } + if err := c.MarkZshCompPositionalArgumentFile(1); err == nil { + t.Error("Didn't receive an error when trying to overwrite argument position") + } + }) + + t.Run("Refuses to accept argPosition less then 1", func(t *testing.T) { + c := &Command{} + err := c.MarkZshCompPositionalArgumentFile(0, "*") + if err == nil { + t.Fatal("Error was not thrown when indicating argument position 0") + } + if !strings.Contains(err.Error(), "position") { + t.Errorf("expected error message '%s' to contain 'position'", err.Error()) + } + }) +} + +func TestMarkZshCompPositionalArgumentWords(t *testing.T) { + t.Run("Doesn't allow overwriting existing positional argument", func(t *testing.T) { + c := &Command{} + if err := c.MarkZshCompPositionalArgumentFile(1, "*.log"); err != nil { + t.Errorf("Received error when we shouldn't have: %v\n", err) + } + if err := c.MarkZshCompPositionalArgumentWords(1, "hello"); err == nil { + t.Error("Didn't receive an error when trying to overwrite argument position") + } + }) + + t.Run("Doesn't allow calling without words", func(t *testing.T) { + c := &Command{} + if err := c.MarkZshCompPositionalArgumentWords(0); err == nil { + t.Error("Should not allow saving empty word list for annotation") + } + }) + + t.Run("Refuses to accept argPosition less then 1", func(t *testing.T) { + c := &Command{} + err := c.MarkZshCompPositionalArgumentWords(0, "word") + if err == nil { + t.Fatal("Should not allow setting argument position less then 1") + } + if !strings.Contains(err.Error(), "position") { + t.Errorf("Expected error '%s' to contain 'position' but didn't", err.Error()) + } + }) +} + +func BenchmarkMediumSizeConstruct(b *testing.B) { + root := constructLargeCommandHierarchy() + // if err := root.GenZshCompletionFile("_mycmd"); err != nil { + // b.Error(err) + // } + + for i := 0; i < b.N; i++ { + buf := new(bytes.Buffer) + err := root.GenZshCompletion(buf) + if err != nil { + b.Error(err) + } + } +} + +func TestExtractFlags(t *testing.T) { + var debug, cmdc, cmdd bool + c := &Command{ + Use: "cmdC", + Long: "Command C", + } + c.PersistentFlags().BoolVarP(&debug, "debug", "d", debug, "debug mode") + c.Flags().BoolVar(&cmdc, "cmd-c", cmdc, "Command C") + d := &Command{ + Use: "CmdD", + Long: "Command D", + } + d.Flags().BoolVar(&cmdd, "cmd-d", cmdd, "Command D") + c.AddCommand(d) + + resC := zshCompExtractFlag(c) + resD := zshCompExtractFlag(d) + + if len(resC) != 2 { + t.Errorf("expected Command C to return 2 flags, got %d", len(resC)) + } + if len(resD) != 2 { + t.Errorf("expected Command D to return 2 flags, got %d", len(resD)) + } +} + +func constructLargeCommandHierarchy() *Command { + var config, st1, st2 string + var long, debug bool + var in1, in2 int + var verbose []bool + + r := genTestCommand("mycmd", false) + r.PersistentFlags().StringVarP(&config, "config", "c", config, "config usage") + if err := r.MarkPersistentFlagFilename("config", "*"); err != nil { + panic(err) + } + s1 := genTestCommand("sub1", true) + s1.Flags().BoolVar(&long, "long", long, "long description") + s1.Flags().BoolSliceVar(&verbose, "verbose", verbose, "verbose description") + s1.Flags().StringArray("option", []string{}, "various options") + s2 := genTestCommand("sub2", true) + s2.PersistentFlags().BoolVar(&debug, "debug", debug, "debug description") + s3 := genTestCommand("sub3", true) + s3.Hidden = true + s1_1 := genTestCommand("sub1sub1", true) + s1_1.Flags().StringVar(&st1, "st1", st1, "st1 description") + s1_1.Flags().StringVar(&st2, "st2", st2, "st2 description") + s1_2 := genTestCommand("sub1sub2", true) + s1_3 := genTestCommand("sub1sub3", true) + s1_3.Flags().IntVar(&in1, "int1", in1, "int1 description") + s1_3.Flags().IntVar(&in2, "int2", in2, "int2 description") + s1_3.Flags().StringArrayP("option", "O", []string{}, "more options") + s2_1 := genTestCommand("sub2sub1", true) + s2_2 := genTestCommand("sub2sub2", true) + s2_3 := genTestCommand("sub2sub3", true) + s2_4 := genTestCommand("sub2sub4", true) + s2_5 := genTestCommand("sub2sub5", true) + + s1.AddCommand(s1_1, s1_2, s1_3) + s2.AddCommand(s2_1, s2_2, s2_3, s2_4, s2_5) + r.AddCommand(s1, s2, s3) + r.Execute() + return r +} + +func genTestCommand(name string, withRun bool) *Command { + r := &Command{ + Use: name, + Short: name + " short description", + Long: "Long description for " + name, + } + if withRun { + r.Run = emptyRun + } + + return r +} diff --git a/vendor/github.com/vmware/photon-controller-go-sdk/photon/client.go b/vendor/github.com/vmware/photon-controller-go-sdk/photon/client.go index fb48c59820b9..5e0faac7bd6c 100644 --- a/vendor/github.com/vmware/photon-controller-go-sdk/photon/client.go +++ b/vendor/github.com/vmware/photon-controller-go-sdk/photon/client.go @@ -142,8 +142,8 @@ func NewClient(endpoint string, options *ClientOptions, logger *log.Logger) (c * } restClient := &restClient{ - httpClient: &http.Client{Transport: tr}, - logger: logger, + httpClient: &http.Client{Transport: tr}, + logger: logger, UpdateAccessTokenCallback: tokenCallback, } diff --git a/vendor/github.com/vmware/photon-controller-go-sdk/photon/deployments_test.go b/vendor/github.com/vmware/photon-controller-go-sdk/photon/deployments_test.go index cbbd5f681089..dbfc8f85da86 100644 --- a/vendor/github.com/vmware/photon-controller-go-sdk/photon/deployments_test.go +++ b/vendor/github.com/vmware/photon-controller-go-sdk/photon/deployments_test.go @@ -32,7 +32,7 @@ var _ = Describe("Deployment", func() { deploymentSpec = &DeploymentCreateSpec{ ImageDatastores: []string{randomString(10, "go-sdk-deployment-")}, UseImageDatastoreForVms: true, - Auth: &AuthInfo{}, + Auth: &AuthInfo{}, } }) @@ -59,8 +59,8 @@ var _ = Describe("Deployment", func() { mockDeployment := Deployment{ ImageDatastores: deploymentSpec.ImageDatastores, UseImageDatastoreForVms: deploymentSpec.UseImageDatastoreForVms, - Auth: &AuthInfo{}, - NetworkConfiguration: &NetworkConfiguration{Enabled: false}, + Auth: &AuthInfo{}, + NetworkConfiguration: &NetworkConfiguration{Enabled: false}, } server.SetResponseJson(200, mockDeployment) deployment, err := client.Deployments.Get(task.Entity.ID) diff --git a/vendor/github.com/vmware/photon-controller-go-sdk/photon/lightwave/oidcclient_test.go b/vendor/github.com/vmware/photon-controller-go-sdk/photon/lightwave/oidcclient_test.go index 68bc89ad608f..976f6c7afb03 100644 --- a/vendor/github.com/vmware/photon-controller-go-sdk/photon/lightwave/oidcclient_test.go +++ b/vendor/github.com/vmware/photon-controller-go-sdk/photon/lightwave/oidcclient_test.go @@ -66,7 +66,7 @@ var _ = Describe("OIDCClient", func() { Context("when server responds with valid certificate", func() { BeforeEach(func() { template := &x509.Certificate{ - IsCA: true, + IsCA: true, BasicConstraintsValid: true, SubjectKeyId: []byte{1, 2, 3}, SerialNumber: big.NewInt(1234),