diff --git a/config/config/crds.yml b/config/config/crds.yml index 38e4f04245..f4527e4b78 100644 --- a/config/config/crds.yml +++ b/config/config/crds.yml @@ -1434,6 +1434,9 @@ spec: required: - spec type: object + x-kubernetes-validations: + - message: Expected service account or cluster. + rule: has(self.spec.serviceAccountName) || has(self.spec.cluster) served: true storage: true subresources: @@ -1594,6 +1597,9 @@ spec: required: - spec type: object + x-kubernetes-validations: + - message: Expected service account or cluster. + rule: has(self.spec.serviceAccountName) || has(self.spec.cluster) served: true storage: true subresources: diff --git a/go.mod b/go.mod index 677508826c..7513d666c7 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/vmware-tanzu/carvel-kapp-controller go 1.21 require ( - github.com/fatih/color v1.13.0 // indirect + github.com/fatih/color v1.15.0 // indirect github.com/gogo/protobuf v1.3.2 github.com/google/go-cmp v0.5.9 // indirect github.com/prometheus/client_golang v1.15.1 @@ -21,7 +21,7 @@ require ( k8s.io/kube-aggregator v0.22.17 k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f sigs.k8s.io/controller-runtime v0.15.3 - sigs.k8s.io/controller-tools v0.7.0 + sigs.k8s.io/controller-tools v0.12.1 sigs.k8s.io/yaml v1.3.0 ) @@ -30,7 +30,7 @@ require ( github.com/cppforlife/go-cli-ui v0.0.0-20220425131040-94f26b16bc14 github.com/go-logr/logr v1.2.4 github.com/k14s/semver/v4 v4.0.1-0.20210701191048-266d47ac6115 - github.com/spf13/cobra v1.6.1 + github.com/spf13/cobra v1.7.0 golang.org/x/sync v0.2.0 gopkg.in/yaml.v2 v2.4.0 k8s.io/component-base v0.27.7 @@ -62,7 +62,7 @@ require ( github.com/go-openapi/jsonpointer v0.19.6 // indirect github.com/go-openapi/jsonreference v0.20.1 // indirect github.com/go-openapi/swag v0.22.3 // indirect - github.com/gobuffalo/flect v0.2.3 // indirect + github.com/gobuffalo/flect v1.0.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/google/cel-go v0.12.7 // indirect @@ -73,11 +73,11 @@ require ( github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 // indirect github.com/hashicorp/go-version v1.2.1 // indirect github.com/imdario/mergo v0.3.12 // indirect - github.com/inconshreveable/mousetrap v1.0.1 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/mailru/easyjson v0.7.7 // indirect - github.com/mattn/go-colorable v0.1.12 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.17 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/mitchellh/mapstructure v1.4.1 // indirect diff --git a/go.sum b/go.sum index 391610c231..2c9b3ff237 100644 --- a/go.sum +++ b/go.sum @@ -54,7 +54,6 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= -github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM= github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ= github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= @@ -131,9 +130,8 @@ github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQL github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= -github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= -github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= +github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= @@ -178,11 +176,10 @@ github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/ github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= -github.com/gobuffalo/flect v0.2.3 h1:f/ZukRnSNA/DUpSNDadko7Qc0PhGvsew35p/2tu+CRY= -github.com/gobuffalo/flect v0.2.3/go.mod h1:vmkQwuZYhN5Pc4ljYQZzP+1sq+NEkK+lh20jmEmX3jc= +github.com/gobuffalo/flect v1.0.2 h1:eqjPGSo2WmjgY2XlpGwo2NXgL3RucAKo4k4qQMNA5sA= +github.com/gobuffalo/flect v1.0.2/go.mod h1:A5msMlrHtLqh9umBSnvabjsMrCcCpAyzglnDvkbYKHs= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= @@ -233,7 +230,6 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= @@ -296,8 +292,8 @@ github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJ github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc= -github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ= @@ -322,7 +318,6 @@ github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= @@ -336,7 +331,6 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= @@ -344,15 +338,12 @@ github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0 github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= -github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= -github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= @@ -395,26 +386,23 @@ github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.13.0/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1lskyM0= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= -github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= -github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/ginkgo/v2 v2.9.5 h1:+6Hr4uxzP4XIUyAkg61dWBw8lb/gc4/X5luuxN/EC+Q= github.com/onsi/ginkgo/v2 v2.9.5/go.mod h1:tvAoo1QUJwNEU2ITftXTpR7R1RbCzoZUOs3RonqW57k= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.14.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0= github.com/onsi/gomega v1.27.7 h1:fVih9JD6ogIiHUN6ePK7HJidyEDpWGVB5mzM7cWNXoU= github.com/onsi/gomega v1.27.7/go.mod h1:1p8OOlwo2iUUDsHnOrjE5UKYJ+e3W8eQ3qSlRahPmr4= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= 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/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= @@ -473,21 +461,16 @@ github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= -github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= -github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk= -github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA= -github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= +github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= +github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= -github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns= github.com/stoewer/go-strcase v1.2.0 h1:Z2iHWqGXH00XYgqDmNgQbIBxf3wrNq0F3feEy0ainaU= github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -547,7 +530,6 @@ go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opentelemetry.io/contrib v0.20.0/go.mod h1:G/EtFaa6qaN7+LxqfIAT3GiZa7Wv5DTBUzl5H4LY0Kc= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.20.0/go.mod h1:oVGt1LRbBOBq1A5BQLlUg9UaU/54aiHw8cgjV3aWZ/E= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.35.0 h1:xFSRQBbXF6VvYRf2lqMJXxoB72XI1K/azav8TekHHSw= @@ -599,7 +581,6 @@ golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -622,7 +603,6 @@ golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= @@ -663,12 +643,8 @@ golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= -golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= @@ -677,7 +653,6 @@ golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4Iltr golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.5.0 h1:HuArIo48skDwlrvM3sEdHXElYslAMsf3KwRkkW4MC4s= golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I= @@ -715,7 +690,6 @@ golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -732,11 +706,7 @@ golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -744,8 +714,6 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= @@ -803,9 +771,7 @@ golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200626171337-aa94e735be7f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo= @@ -827,7 +793,6 @@ google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/ google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -858,7 +823,6 @@ google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfG google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200626011028-ee7919e894b5/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f h1:BWUVssLB0HVOSY78gIdvk1dTVYtT1y8SBWtPYuTJ/6w= @@ -874,9 +838,7 @@ google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8 google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= -google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= @@ -910,7 +872,6 @@ gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMy gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= @@ -938,30 +899,23 @@ honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -k8s.io/api v0.22.2/go.mod h1:y3ydYpLJAaDI+BbSe2xmGcqxiWHmWjkEeIbiwHvnPR8= k8s.io/api v0.22.17/go.mod h1:6qVojJ3y+qIq7JSMwTH0BcPHl3dch4HefIC+4nguZhs= k8s.io/api v0.27.7 h1:7yG4D3t/q4utJe2ptlRw9aPuxcSmroTsYxsofkQNl/A= k8s.io/api v0.27.7/go.mod h1:ZNExI/Lhrs9YrLgVWx6jjHZdoWCTXfBXuFjt1X6olro= -k8s.io/apiextensions-apiserver v0.22.2/go.mod h1:2E0Ve/isxNl7tWLSUDgi6+cmwHi5fQRdwGVCxbC+KFA= k8s.io/apiextensions-apiserver v0.27.7 h1:YqIOwZAUokzxJIjunmUd4zS1v3JhK34EPXn+pP0/bsU= k8s.io/apiextensions-apiserver v0.27.7/go.mod h1:x0p+b5a955lfPz9gaDeBy43obM12s+N9dNHK6+dUL+g= -k8s.io/apimachinery v0.22.2/go.mod h1:O3oNtNadZdeOMxHFVxOreoznohCpy0z6mocxbZr7oJ0= k8s.io/apimachinery v0.22.17/go.mod h1:ZvVLP5iLhwVFg2Yx9Gh5W0um0DUauExbRhe+2Z8I1EU= k8s.io/apimachinery v0.27.7 h1:Gxgtb7Y/Rsu8ymgmUEaiErkxa6RY4oTd8kNUI6SUR58= k8s.io/apimachinery v0.27.7/go.mod h1:jBGQgTjkw99ef6q5hv1YurDd3BqKDk9YRxmX0Ozo0i8= -k8s.io/apiserver v0.22.2/go.mod h1:vrpMmbyjWrgdyOvZTSpsusQq5iigKNWv9o9KlDAbBHI= k8s.io/apiserver v0.22.17/go.mod h1:zNXYCtXZ91AkmIUZgQ8lT9vdlDqgSkokJpds/F6DdGU= k8s.io/apiserver v0.27.7 h1:E8sDHwfUug82YC1++qvE73QxihaXDqT4tr8XYBOEtc4= k8s.io/apiserver v0.27.7/go.mod h1:OrLG9RwCOerutAlo8QJW5EHzUG9Dad7k6rgcDUNSO/w= -k8s.io/client-go v0.22.2/go.mod h1:sAlhrkVDf50ZHx6z4K0S40wISNTarf1r800F+RlCF6U= k8s.io/client-go v0.22.17/go.mod h1:SQPVpN+E/5Q/aSV7fYDT8VKVdaljhxI/t/84ADVJoC4= k8s.io/client-go v0.27.7 h1:+Xgh9OOKv6A3qdD4Dnl/0VOI5EvAv+0s/OseDxVVTwQ= k8s.io/client-go v0.27.7/go.mod h1:dZ2kqcalYp5YZ2EV12XIMc77G6PxHWOJp/kclZr4+5Q= -k8s.io/code-generator v0.22.2/go.mod h1:eV77Y09IopzeXOJzndrDyCI88UBok2h6WxAlBwpxa+o= k8s.io/code-generator v0.22.17/go.mod h1:iOZwYADSgFPNGWfqHFfg1V0TNJnl1t0WyZluQp4baqU= k8s.io/code-generator v0.27.7 h1:cbMN3+QxMHrQG1rYQOiNEqoLTRnqBW50pjPHgFCFe94= k8s.io/code-generator v0.27.7/go.mod h1:w1YF/xQcTg+d9Ag+04xuRqER+q8rDnJ70ynLql8/RLA= -k8s.io/component-base v0.22.2/go.mod h1:5Br2QhI9OTe79p+TzPe9JKNQYvEKbq9rTJDWllunGug= k8s.io/component-base v0.22.17/go.mod h1:Mrcvmxs+Ctx/xCYGWoFAvfZO9DC4gDgLtUbPJ4PjjUE= k8s.io/component-base v0.27.7 h1:kngM58HR9W9Nqpv7e4rpdRyWnKl/ABpUhLAZ+HoliMs= k8s.io/component-base v0.27.7/go.mod h1:YGjlCVL1oeKvG3HSciyPHFh+LCjIEqsxz4BDR3cfHRs= @@ -978,28 +932,24 @@ k8s.io/kms v0.27.7 h1:3iB92lQIH4uEz0V+wQAXvAsgIDhmXg/8lCu01FCjtqI= k8s.io/kms v0.27.7/go.mod h1:JspOc8g6+cDlZfgW5GqnHS+OV6tAVyg4iXytCrqfNPw= k8s.io/kube-aggregator v0.22.17 h1:E8T1McXbB31Z7L71nR8/lMtWS01bhOE7AF8TF/sqDHw= k8s.io/kube-aggregator v0.22.17/go.mod h1:J557nueFVurHA1JiDrxT1HlgygNQ+2exsTVUXiz2T7k= -k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw= k8s.io/kube-openapi v0.0.0-20211109043538-20434351676c/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw= k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f h1:2kWPakN3i/k81b0gvD5C5FJ2kxm1WrQFanWchyKuqGg= k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f/go.mod h1:byini6yhqGC14c3ebc/QwanvYwhuMWF6yz2F8uwW8eg= -k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20211116205334-6203023598ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20230209194617-a36077c30491 h1:r0BAOLElQnnFhE/ApUsg3iHdVYYPBjNSSOMowRZxxsY= k8s.io/utils v0.0.0-20230209194617-a36077c30491/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.22/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.30/go.mod h1:fEO7lRTdivWO2qYVCVG7dEADOMo/MLDCVr8So2g88Uw= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.1.2 h1:trsWhjU5jZrx6UvFu4WzQDrN7Pga4a7Qg+zcfcj64PA= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.1.2/go.mod h1:+qG7ISXqCDVVcyO8hLn12AKVYYUjM7ftlqsqmrhMZE0= sigs.k8s.io/controller-runtime v0.15.3 h1:L+t5heIaI3zeejoIyyvLQs5vTVu/67IU2FfisVzFlBc= sigs.k8s.io/controller-runtime v0.15.3/go.mod h1:kp4jckA4vTx281S/0Yk2LFEEQe67mjg+ev/yknv47Ds= -sigs.k8s.io/controller-tools v0.7.0 h1:iZIz1vEcavyEfxjcTLs1WH/MPf4vhPCtTKhoHqV8/G0= -sigs.k8s.io/controller-tools v0.7.0/go.mod h1:bpBAo0VcSDDLuWt47evLhMLPxRPxMDInTEH/YbdeMK0= +sigs.k8s.io/controller-tools v0.12.1 h1:GyQqxzH5wksa4n3YDIJdJJOopztR5VDM+7qsyg5yE4U= +sigs.k8s.io/controller-tools v0.12.1/go.mod h1:rXlpTfFHZMpZA8aGq9ejArgZiieHd+fkk/fTatY8A2M= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= -sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= sigs.k8s.io/structured-merge-diff/v4 v4.2.1/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE= sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= diff --git a/pkg/apis/kappctrl/v1alpha1/types.go b/pkg/apis/kappctrl/v1alpha1/types.go index dc89189e4a..4bd6456f61 100644 --- a/pkg/apis/kappctrl/v1alpha1/types.go +++ b/pkg/apis/kappctrl/v1alpha1/types.go @@ -14,6 +14,7 @@ import ( // +kubebuilder:printcolumn:name=Description,JSONPath=.status.friendlyDescription,description=Friendly description,type=string // +kubebuilder:printcolumn:name=Since-Deploy,JSONPath=.status.deploy.startedAt,description=Last time app started being deployed. Does not mean anything was changed.,type=date // +kubebuilder:printcolumn:name=Age,JSONPath=.metadata.creationTimestamp,description=Time since creation,type=date +// +kubebuilder:validation:XValidation:rule="has(self.spec.serviceAccountName) || has(self.spec.cluster)", message="Expected service account or cluster." // +protobuf=false // An App is a set of Kubernetes resources. These resources could span any number of namespaces or could be cluster-wide (e.g. CRDs). An App is represented in kapp-controller using a App CR. // The App CR comprises of three main sections: diff --git a/pkg/apis/packaging/v1alpha1/package_install.go b/pkg/apis/packaging/v1alpha1/package_install.go index 0195b08409..d2aa890a7d 100644 --- a/pkg/apis/packaging/v1alpha1/package_install.go +++ b/pkg/apis/packaging/v1alpha1/package_install.go @@ -17,6 +17,7 @@ import ( // +kubebuilder:printcolumn:name=Package version,JSONPath=.status.version,description=PackageMetadata version,type=string // +kubebuilder:printcolumn:name=Description,JSONPath=.status.friendlyDescription,description=Friendly description,type=string // +kubebuilder:printcolumn:name=Age,JSONPath=.metadata.creationTimestamp,description=Time since creation,type=date +// +kubebuilder:validation:XValidation:rule="has(self.spec.serviceAccountName) || has(self.spec.cluster)", message="Expected service account or cluster." // A Package Install is an actual installation of a package and its underlying resources on a Kubernetes cluster. // It is represented in kapp-controller by a PackageInstall CR. // A PackageInstall CR must reference a Package CR. diff --git a/test/e2e/kappcontroller/cel_validation.go b/test/e2e/kappcontroller/cel_validation.go new file mode 100644 index 0000000000..7556e38578 --- /dev/null +++ b/test/e2e/kappcontroller/cel_validation.go @@ -0,0 +1,75 @@ +// Copyright 2021 VMware, Inc. +// SPDX-License-Identifier: Apache-2.0 + +package kappcontroller + +import ( + "fmt" + "strings" + "testing" + + "github.com/stretchr/testify/require" + "github.com/vmware-tanzu/carvel-kapp-controller/test/e2e" +) + +// TestSAandClusterCELValidation tests packageInstall and App CR +// to ensure that either SA or cluster is validated at admission. +func TestSAandClusterCELValidation(t *testing.T) { + env := e2e.BuildEnv(t) + logger := e2e.Logger{} + kapp := e2e.Kapp{t, env.Namespace, logger} + kubectl := e2e.Kubectl{t, env.Namespace, logger} + + name := "incorrect-spec-without-sa-cluster" + + appYAML := fmt.Sprintf(` +--- +apiVersion: kappctrl.k14s.io/v1alpha1 +kind: App +metadata: + name: %s + annotations: + kapp.k14s.io/change-group: kappctrl-e2e.k14s.io/apps +spec: + fetch: + - inline: + paths: + file.yml: | + apiVersion: v1 + kind: ConfigMap + metadata: + name: configmap + template: + - ytt: {} + deploy: + - kapp: {} +`, name) + + pkginstallYAML := fmt.Sprintf(` +--- +apiVersion: packaging.carvel.dev/v1alpha1 +kind: PackageInstall +metadata: + name: %[2]s + namespace: %[1]s + annotations: + kapp.k14s.io/change-group: kappctrl-e2e.k14s.io/packageinstalls +spec: + packageRef: + refName: pkg.incorrect.carvel.dev + versionSelection: + constraints: 1.0.0 +`, env.Namespace, name) + + logger.Section("Create App CR with kubectl", func() { + _, err := kubectl.RunWithOpts([]string{"apply", "-f", "-"}, e2e.RunOpts{StdinReader: strings.NewReader(appYAML), AllowError: true}) + require.Error(t, err) + require.ErrorContains(t, err, "Expected service account or cluster.") + }) + + logger.Section("Create PackageInstall with kapp", func() { + _, err := kapp.RunWithOpts([]string{"deploy", "-a", name, "-f", "-"}, e2e.RunOpts{StdinReader: strings.NewReader(pkginstallYAML), AllowError: true}) + require.Error(t, err) + require.ErrorContains(t, err, "Expected service account or cluster.") + }) +} \ No newline at end of file diff --git a/vendor/github.com/fatih/color/README.md b/vendor/github.com/fatih/color/README.md index 5152bf59bf..be82827cac 100644 --- a/vendor/github.com/fatih/color/README.md +++ b/vendor/github.com/fatih/color/README.md @@ -7,7 +7,6 @@ suits you. ![Color](https://user-images.githubusercontent.com/438920/96832689-03b3e000-13f4-11eb-9803-46f4c4de3406.jpg) - ## Install ```bash @@ -124,17 +123,17 @@ fmt.Println("All text will now be bold magenta.") ``` ### Disable/Enable color - + There might be a case where you want to explicitly disable/enable color output. the `go-isatty` package will automatically disable color output for non-tty output streams (for example if the output were piped directly to `less`). The `color` package also disables color output if the [`NO_COLOR`](https://no-color.org) environment -variable is set (regardless of its value). +variable is set to a non-empty string. -`Color` has support to disable/enable colors programatically both globally and +`Color` has support to disable/enable colors programmatically both globally and for single color definitions. For example suppose you have a CLI app and a -`--no-color` bool flag. You can easily disable the color output with: +`-no-color` bool flag. You can easily disable the color output with: ```go var flagNoColor = flag.Bool("no-color", false, "Disable color output") @@ -167,11 +166,10 @@ To output color in GitHub Actions (or other CI systems that support ANSI colors) * Save/Return previous values * Evaluate fmt.Formatter interface - ## Credits - * [Fatih Arslan](https://github.com/fatih) - * Windows support via @mattn: [colorable](https://github.com/mattn/go-colorable) +* [Fatih Arslan](https://github.com/fatih) +* Windows support via @mattn: [colorable](https://github.com/mattn/go-colorable) ## License diff --git a/vendor/github.com/fatih/color/color.go b/vendor/github.com/fatih/color/color.go index 98a60f3c88..889f9e77bd 100644 --- a/vendor/github.com/fatih/color/color.go +++ b/vendor/github.com/fatih/color/color.go @@ -19,10 +19,10 @@ var ( // set (regardless of its value). This is a global option and affects all // colors. For more control over each color block use the methods // DisableColor() individually. - NoColor = noColorExists() || os.Getenv("TERM") == "dumb" || + NoColor = noColorIsSet() || os.Getenv("TERM") == "dumb" || (!isatty.IsTerminal(os.Stdout.Fd()) && !isatty.IsCygwinTerminal(os.Stdout.Fd())) - // Output defines the standard output of the print functions. By default + // Output defines the standard output of the print functions. By default, // os.Stdout is used. Output = colorable.NewColorableStdout() @@ -35,10 +35,9 @@ var ( colorsCacheMu sync.Mutex // protects colorsCache ) -// noColorExists returns true if the environment variable NO_COLOR exists. -func noColorExists() bool { - _, exists := os.LookupEnv("NO_COLOR") - return exists +// noColorIsSet returns true if the environment variable NO_COLOR is set to a non-empty string. +func noColorIsSet() bool { + return os.Getenv("NO_COLOR") != "" } // Color defines a custom color object which is defined by SGR parameters. @@ -120,7 +119,7 @@ func New(value ...Attribute) *Color { params: make([]Attribute, 0), } - if noColorExists() { + if noColorIsSet() { c.noColor = boolPtr(true) } @@ -152,7 +151,7 @@ func (c *Color) Set() *Color { return c } - fmt.Fprintf(Output, c.format()) + fmt.Fprint(Output, c.format()) return c } @@ -164,16 +163,21 @@ func (c *Color) unset() { Unset() } -func (c *Color) setWriter(w io.Writer) *Color { +// SetWriter is used to set the SGR sequence with the given io.Writer. This is +// a low-level function, and users should use the higher-level functions, such +// as color.Fprint, color.Print, etc. +func (c *Color) SetWriter(w io.Writer) *Color { if c.isNoColorSet() { return c } - fmt.Fprintf(w, c.format()) + fmt.Fprint(w, c.format()) return c } -func (c *Color) unsetWriter(w io.Writer) { +// UnsetWriter resets all escape attributes and clears the output with the give +// io.Writer. Usually should be called after SetWriter(). +func (c *Color) UnsetWriter(w io.Writer) { if c.isNoColorSet() { return } @@ -192,20 +196,14 @@ func (c *Color) Add(value ...Attribute) *Color { return c } -func (c *Color) prepend(value Attribute) { - c.params = append(c.params, 0) - copy(c.params[1:], c.params[0:]) - c.params[0] = value -} - // Fprint formats using the default formats for its operands and writes to w. // Spaces are added between operands when neither is a string. // It returns the number of bytes written and any write error encountered. // On Windows, users should wrap w with colorable.NewColorable() if w is of // type *os.File. func (c *Color) Fprint(w io.Writer, a ...interface{}) (n int, err error) { - c.setWriter(w) - defer c.unsetWriter(w) + c.SetWriter(w) + defer c.UnsetWriter(w) return fmt.Fprint(w, a...) } @@ -227,8 +225,8 @@ func (c *Color) Print(a ...interface{}) (n int, err error) { // On Windows, users should wrap w with colorable.NewColorable() if w is of // type *os.File. func (c *Color) Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) { - c.setWriter(w) - defer c.unsetWriter(w) + c.SetWriter(w) + defer c.UnsetWriter(w) return fmt.Fprintf(w, format, a...) } @@ -248,8 +246,8 @@ func (c *Color) Printf(format string, a ...interface{}) (n int, err error) { // On Windows, users should wrap w with colorable.NewColorable() if w is of // type *os.File. func (c *Color) Fprintln(w io.Writer, a ...interface{}) (n int, err error) { - c.setWriter(w) - defer c.unsetWriter(w) + c.SetWriter(w) + defer c.UnsetWriter(w) return fmt.Fprintln(w, a...) } @@ -396,7 +394,7 @@ func (c *Color) DisableColor() { } // EnableColor enables the color output. Use it in conjunction with -// DisableColor(). Otherwise this method has no side effects. +// DisableColor(). Otherwise, this method has no side effects. func (c *Color) EnableColor() { c.noColor = boolPtr(false) } diff --git a/vendor/github.com/fatih/color/color_windows.go b/vendor/github.com/fatih/color/color_windows.go new file mode 100644 index 0000000000..be01c558e5 --- /dev/null +++ b/vendor/github.com/fatih/color/color_windows.go @@ -0,0 +1,19 @@ +package color + +import ( + "os" + + "golang.org/x/sys/windows" +) + +func init() { + // Opt-in for ansi color support for current process. + // https://learn.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences#output-sequences + var outMode uint32 + out := windows.Handle(os.Stdout.Fd()) + if err := windows.GetConsoleMode(out, &outMode); err != nil { + return + } + outMode |= windows.ENABLE_PROCESSED_OUTPUT | windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING + _ = windows.SetConsoleMode(out, outMode) +} diff --git a/vendor/github.com/fatih/color/doc.go b/vendor/github.com/fatih/color/doc.go index 04541de786..9491ad5413 100644 --- a/vendor/github.com/fatih/color/doc.go +++ b/vendor/github.com/fatih/color/doc.go @@ -5,106 +5,105 @@ that suits you. Use simple and default helper functions with predefined foreground colors: - color.Cyan("Prints text in cyan.") + color.Cyan("Prints text in cyan.") - // a newline will be appended automatically - color.Blue("Prints %s in blue.", "text") + // a newline will be appended automatically + color.Blue("Prints %s in blue.", "text") - // More default foreground colors.. - color.Red("We have red") - color.Yellow("Yellow color too!") - color.Magenta("And many others ..") + // More default foreground colors.. + color.Red("We have red") + color.Yellow("Yellow color too!") + color.Magenta("And many others ..") - // Hi-intensity colors - color.HiGreen("Bright green color.") - color.HiBlack("Bright black means gray..") - color.HiWhite("Shiny white color!") + // Hi-intensity colors + color.HiGreen("Bright green color.") + color.HiBlack("Bright black means gray..") + color.HiWhite("Shiny white color!") -However there are times where custom color mixes are required. Below are some +However, there are times when custom color mixes are required. Below are some examples to create custom color objects and use the print functions of each separate color object. - // Create a new color object - c := color.New(color.FgCyan).Add(color.Underline) - c.Println("Prints cyan text with an underline.") + // Create a new color object + c := color.New(color.FgCyan).Add(color.Underline) + c.Println("Prints cyan text with an underline.") - // Or just add them to New() - d := color.New(color.FgCyan, color.Bold) - d.Printf("This prints bold cyan %s\n", "too!.") + // Or just add them to New() + d := color.New(color.FgCyan, color.Bold) + d.Printf("This prints bold cyan %s\n", "too!.") - // Mix up foreground and background colors, create new mixes! - red := color.New(color.FgRed) + // Mix up foreground and background colors, create new mixes! + red := color.New(color.FgRed) - boldRed := red.Add(color.Bold) - boldRed.Println("This will print text in bold red.") + boldRed := red.Add(color.Bold) + boldRed.Println("This will print text in bold red.") - whiteBackground := red.Add(color.BgWhite) - whiteBackground.Println("Red text with White background.") + whiteBackground := red.Add(color.BgWhite) + whiteBackground.Println("Red text with White background.") - // Use your own io.Writer output - color.New(color.FgBlue).Fprintln(myWriter, "blue color!") + // Use your own io.Writer output + color.New(color.FgBlue).Fprintln(myWriter, "blue color!") - blue := color.New(color.FgBlue) - blue.Fprint(myWriter, "This will print text in blue.") + blue := color.New(color.FgBlue) + blue.Fprint(myWriter, "This will print text in blue.") You can create PrintXxx functions to simplify even more: - // Create a custom print function for convenient - red := color.New(color.FgRed).PrintfFunc() - red("warning") - red("error: %s", err) + // Create a custom print function for convenient + red := color.New(color.FgRed).PrintfFunc() + red("warning") + red("error: %s", err) - // Mix up multiple attributes - notice := color.New(color.Bold, color.FgGreen).PrintlnFunc() - notice("don't forget this...") + // Mix up multiple attributes + notice := color.New(color.Bold, color.FgGreen).PrintlnFunc() + notice("don't forget this...") You can also FprintXxx functions to pass your own io.Writer: - blue := color.New(FgBlue).FprintfFunc() - blue(myWriter, "important notice: %s", stars) - - // Mix up with multiple attributes - success := color.New(color.Bold, color.FgGreen).FprintlnFunc() - success(myWriter, don't forget this...") + blue := color.New(FgBlue).FprintfFunc() + blue(myWriter, "important notice: %s", stars) + // Mix up with multiple attributes + success := color.New(color.Bold, color.FgGreen).FprintlnFunc() + success(myWriter, don't forget this...") Or create SprintXxx functions to mix strings with other non-colorized strings: - yellow := New(FgYellow).SprintFunc() - red := New(FgRed).SprintFunc() + yellow := New(FgYellow).SprintFunc() + red := New(FgRed).SprintFunc() - fmt.Printf("this is a %s and this is %s.\n", yellow("warning"), red("error")) + fmt.Printf("this is a %s and this is %s.\n", yellow("warning"), red("error")) - info := New(FgWhite, BgGreen).SprintFunc() - fmt.Printf("this %s rocks!\n", info("package")) + info := New(FgWhite, BgGreen).SprintFunc() + fmt.Printf("this %s rocks!\n", info("package")) Windows support is enabled by default. All Print functions work as intended. -However only for color.SprintXXX functions, user should use fmt.FprintXXX and +However, only for color.SprintXXX functions, user should use fmt.FprintXXX and set the output to color.Output: - fmt.Fprintf(color.Output, "Windows support: %s", color.GreenString("PASS")) + fmt.Fprintf(color.Output, "Windows support: %s", color.GreenString("PASS")) - info := New(FgWhite, BgGreen).SprintFunc() - fmt.Fprintf(color.Output, "this %s rocks!\n", info("package")) + info := New(FgWhite, BgGreen).SprintFunc() + fmt.Fprintf(color.Output, "this %s rocks!\n", info("package")) Using with existing code is possible. Just use the Set() method to set the standard output to the given parameters. That way a rewrite of an existing code is not required. - // Use handy standard colors. - color.Set(color.FgYellow) + // Use handy standard colors. + color.Set(color.FgYellow) - fmt.Println("Existing text will be now in Yellow") - fmt.Printf("This one %s\n", "too") + fmt.Println("Existing text will be now in Yellow") + fmt.Printf("This one %s\n", "too") - color.Unset() // don't forget to unset + color.Unset() // don't forget to unset - // You can mix up parameters - color.Set(color.FgMagenta, color.Bold) - defer color.Unset() // use it in your function + // You can mix up parameters + color.Set(color.FgMagenta, color.Bold) + defer color.Unset() // use it in your function - fmt.Println("All text will be now bold magenta.") + fmt.Println("All text will be now bold magenta.") There might be a case where you want to disable color output (for example to pipe the standard output of your app to somewhere else). `Color` has support to @@ -112,24 +111,24 @@ disable colors both globally and for single color definition. For example suppose you have a CLI app and a `--no-color` bool flag. You can easily disable the color output with: - var flagNoColor = flag.Bool("no-color", false, "Disable color output") + var flagNoColor = flag.Bool("no-color", false, "Disable color output") - if *flagNoColor { - color.NoColor = true // disables colorized output - } + if *flagNoColor { + color.NoColor = true // disables colorized output + } You can also disable the color by setting the NO_COLOR environment variable to any value. It also has support for single color definitions (local). You can disable/enable color output on the fly: - c := color.New(color.FgCyan) - c.Println("Prints cyan text") + c := color.New(color.FgCyan) + c.Println("Prints cyan text") - c.DisableColor() - c.Println("This is printed without any color") + c.DisableColor() + c.Println("This is printed without any color") - c.EnableColor() - c.Println("This prints again cyan...") + c.EnableColor() + c.Println("This prints again cyan...") */ package color diff --git a/vendor/github.com/gobuffalo/flect/README.md b/vendor/github.com/gobuffalo/flect/README.md index 2d9a1bd3b6..14547e2277 100644 --- a/vendor/github.com/gobuffalo/flect/README.md +++ b/vendor/github.com/gobuffalo/flect/README.md @@ -1,25 +1,53 @@ # Flect -

-GoDoc -CI -Go Report Card -

+[![Go Reference](https://pkg.go.dev/badge/github.com/gobuffalo/flect.svg)](https://pkg.go.dev/github.com/gobuffalo/flect) +[![Standard Test](https://github.com/gobuffalo/flect/actions/workflows/standard-go-test.yml/badge.svg)](https://github.com/gobuffalo/flect/actions/workflows/standard-go-test.yml) +[![Go Report Card](https://goreportcard.com/badge/github.com/gobuffalo/flect)](https://goreportcard.com/report/github.com/gobuffalo/flect) This is a new inflection engine to replace [https://github.com/markbates/inflect](https://github.com/markbates/inflect) designed to be more modular, more readable, and easier to fix issues on than the original. +Flect provides word inflection features such as `Singularize` and `Pluralize` +for English nouns and text utility features such as `Camelize`, `Capitalize`, +`Humanize`, and more. + +Due to the flexibly-complex nature of English noun inflection, it is almost +impossible to cover all exceptions (such as identical/irregular plural). +With this reason along with the main purpose of Flect, which is to make it +easy to develop web application in Go, Flect has limitations with its own +rules. + +* It covers regular rule (adding -s or -es and of the word) +* It covers well-known irregular rules (such as -is to -es, -f to -ves, etc) + * https://en.wiktionary.org/wiki/Appendix:English_irregular_nouns#Rules +* It covers well-known irregular words (such as children, men, etc) +* If a word can be countable and uncountable like milk or time, it will be + treated as countable. +* If a word has more than one plural forms, which means it has at least one + irregular plural, we tried to find most popular one. (The selected plural + could be odd to you, please feel free to open an issue with back data) + * For example, we selected "stadiums" over "stadia", "dwarfs" over "dwarves" + * One or combination of en.wiktionary.org, britannica.com, and + trends.google.com are used to check the recent usage trends. +* However, we cannot cover all cases and some of our cases could not fit with + your situation. You can override the default with functions such as + `InsertPlural()`, `InsertSingular()`, or `LoadInfrections()`. +* If you have a json file named `inflections.json` in your application root, + the file will be automatically loaded as your custom inflection dictionary. + ## Installation -```bash -$ go get -u -v github.com/gobuffalo/flect +```console +$ go get github.com/gobuffalo/flect ``` -## `github.com/gobuffalo/flect` -GoDoc + +## Packages + +### `github.com/gobuffalo/flect` The `github.com/gobuffalo/flect` package contains "basic" inflection tools, like pluralization, singularization, etc... -### The `Ident` Type +#### The `Ident` Type In addition to helpful methods that take in a `string` and return a `string`, there is an `Ident` type that can be used to create new, custom, inflection rules. @@ -30,7 +58,6 @@ The `Ident` type contains two fields. Examples of creating new inflection rules using `Ident` can be found in the `github.com/gobuffalo/flect/name` package. -## `github.com/gobuffalo/flect/name` -GoDoc +### `github.com/gobuffalo/flect/name` The `github.com/gobuffalo/flect/name` package contains more "business" inflection rules like creating proper names, table names, etc... diff --git a/vendor/github.com/gobuffalo/flect/SHOULDERS.md b/vendor/github.com/gobuffalo/flect/SHOULDERS.md index 8c359f157e..75222c6bc7 100644 --- a/vendor/github.com/gobuffalo/flect/SHOULDERS.md +++ b/vendor/github.com/gobuffalo/flect/SHOULDERS.md @@ -1,10 +1,12 @@ -# github.com/gobuffalo/flect Stands on the Shoulders of Giants +# Flect Stands on the Shoulders of Giants -github.com/gobuffalo/flect does not try to reinvent the wheel! Instead, it uses the already great wheels developed by the Go community and puts them all together in the best way possible. Without these giants, this project would not be possible. Please make sure to check them out and thank them for all of their hard work. +Flect does not try to reinvent the wheel! Instead, it uses the already great wheels developed by the Go community and puts them all together in the best way possible. Without these giants, this project would not be possible. Please make sure to check them out and thank them for all of their hard work. Thank you to the following **GIANTS**: - * [github.com/davecgh/go-spew](https://godoc.org/github.com/davecgh/go-spew) - +* [github.com/pmezard/go-difflib](https://godoc.org/github.com/pmezard/go-difflib) +* [github.com/stretchr/objx](https://godoc.org/github.com/stretchr/objx) * [github.com/stretchr/testify](https://godoc.org/github.com/stretchr/testify) +* [gopkg.in/check.v1](https://godoc.org/gopkg.in/check.v1) +* [gopkg.in/yaml.v3](https://godoc.org/gopkg.in/yaml.v3) diff --git a/vendor/github.com/gobuffalo/flect/camelize.go b/vendor/github.com/gobuffalo/flect/camelize.go index 8a9928e8be..d8851c8f5e 100644 --- a/vendor/github.com/gobuffalo/flect/camelize.go +++ b/vendor/github.com/gobuffalo/flect/camelize.go @@ -22,10 +22,6 @@ func (i Ident) Camelize() Ident { for i, part := range i.Parts { var x string var capped bool - if strings.ToLower(part) == "id" { - out = append(out, "ID") - continue - } for _, c := range part { if unicode.IsLetter(c) || unicode.IsDigit(c) { if i == 0 { diff --git a/vendor/github.com/gobuffalo/flect/custom_data.go b/vendor/github.com/gobuffalo/flect/custom_data.go index 9a2dfc74ad..efb445f671 100644 --- a/vendor/github.com/gobuffalo/flect/custom_data.go +++ b/vendor/github.com/gobuffalo/flect/custom_data.go @@ -8,6 +8,7 @@ import ( "io/ioutil" "os" "path/filepath" + "strings" ) func init() { @@ -75,6 +76,10 @@ func LoadInflections(r io.Reader) error { defer singularMoot.Unlock() for s, p := range m { + if strings.Contains(s, " ") || strings.Contains(p, " ") { + // flect works with parts, so multi-words should not be allowed + return fmt.Errorf("inflection elements should be a single word") + } singleToPlural[s] = p pluralToSingle[p] = s } diff --git a/vendor/github.com/gobuffalo/flect/humanize.go b/vendor/github.com/gobuffalo/flect/humanize.go index 6a0b75af7b..311c8beed4 100644 --- a/vendor/github.com/gobuffalo/flect/humanize.go +++ b/vendor/github.com/gobuffalo/flect/humanize.go @@ -22,13 +22,9 @@ func (i Ident) Humanize() Ident { return New("") } - var parts []string - for index, part := range i.Parts { - if index == 0 { - part = strings.Title(i.Parts[0]) - } - - parts = xappend(parts, part) + parts := xappend([]string{}, Titleize(i.Parts[0])) + if len(i.Parts) > 1 { + parts = xappend(parts, i.Parts[1:]...) } return New(strings.Join(parts, " ")) diff --git a/vendor/github.com/gobuffalo/flect/pascalize.go b/vendor/github.com/gobuffalo/flect/pascalize.go index 76f0c6a706..6396d0d4e7 100644 --- a/vendor/github.com/gobuffalo/flect/pascalize.go +++ b/vendor/github.com/gobuffalo/flect/pascalize.go @@ -1,7 +1,7 @@ package flect import ( - "unicode" + "strings" ) // Pascalize returns a string with each segment capitalized @@ -21,5 +21,12 @@ func (i Ident) Pascalize() Ident { if len(c.String()) == 0 { return c } - return New(string(unicode.ToUpper(rune(c.Original[0]))) + c.Original[1:]) + if len(i.Parts) == 0 { + return i + } + capLen := 1 + if _, ok := baseAcronyms[strings.ToUpper(i.Parts[0])]; ok { + capLen = len(i.Parts[0]) + } + return New(string(strings.ToUpper(c.Original[0:capLen])) + c.Original[capLen:]) } diff --git a/vendor/github.com/gobuffalo/flect/plural_rules.go b/vendor/github.com/gobuffalo/flect/plural_rules.go index ff67928438..3904e79744 100644 --- a/vendor/github.com/gobuffalo/flect/plural_rules.go +++ b/vendor/github.com/gobuffalo/flect/plural_rules.go @@ -1,153 +1,255 @@ package flect +import "fmt" + var pluralRules = []rule{} // AddPlural adds a rule that will replace the given suffix with the replacement suffix. +// The name is confusing. This function will be deprecated in the next release. func AddPlural(suffix string, repl string) { + InsertPluralRule(suffix, repl) +} + +// InsertPluralRule inserts a rule that will replace the given suffix with +// the repl(acement) at the begining of the list of the pluralize rules. +func InsertPluralRule(suffix, repl string) { pluralMoot.Lock() defer pluralMoot.Unlock() - pluralRules = append(pluralRules, rule{ + + pluralRules = append([]rule{{ suffix: suffix, - fn: func(s string) string { - s = s[:len(s)-len(suffix)] - return s + repl - }, - }) + fn: simpleRuleFunc(suffix, repl), + }}, pluralRules...) - pluralRules = append(pluralRules, rule{ + pluralRules = append([]rule{{ suffix: repl, fn: noop, - }) + }}, pluralRules...) } -var singleToPlural = map[string]string{ - "aircraft": "aircraft", - "alias": "aliases", - "alumna": "alumnae", - "alumnus": "alumni", - "analysis": "analyses", - "antenna": "antennas", - "antithesis": "antitheses", - "apex": "apexes", - "appendix": "appendices", - "axis": "axes", - "bacillus": "bacilli", - "bacterium": "bacteria", - "basis": "bases", - "beau": "beaus", - "bison": "bison", - "bureau": "bureaus", - "bus": "buses", - "campus": "campuses", - "caucus": "caucuses", - "child": "children", - "château": "châteaux", - "circus": "circuses", - "codex": "codices", - "concerto": "concertos", - "corpus": "corpora", - "crisis": "crises", - "curriculum": "curriculums", - "datum": "data", - "deer": "deer", - "diagnosis": "diagnoses", - "die": "dice", - "dwarf": "dwarves", - "ellipsis": "ellipses", - "equipment": "equipment", - "erratum": "errata", - "faux pas": "faux pas", - "fez": "fezzes", - "fish": "fish", - "focus": "foci", - "foo": "foos", - "foot": "feet", - "formula": "formulas", - "fungus": "fungi", - "genus": "genera", - "goose": "geese", - "graffito": "graffiti", - "grouse": "grouse", - "half": "halves", - "halo": "halos", - "hoof": "hooves", - "human": "humans", - "hypothesis": "hypotheses", - "index": "indices", - "information": "information", - "jeans": "jeans", - "larva": "larvae", - "libretto": "librettos", - "loaf": "loaves", - "locus": "loci", - "louse": "lice", - "matrix": "matrices", - "minutia": "minutiae", - "money": "money", - "moose": "moose", - "mouse": "mice", - "nebula": "nebulae", - "news": "news", - "nucleus": "nuclei", - "oasis": "oases", - "octopus": "octopi", - "offspring": "offspring", - "opus": "opera", - "ovum": "ova", - "ox": "oxen", - "parenthesis": "parentheses", - "phenomenon": "phenomena", - "photo": "photos", - "phylum": "phyla", - "piano": "pianos", - "plus": "pluses", - "police": "police", - "prognosis": "prognoses", - "prometheus": "prometheuses", - "quiz": "quizzes", - "quota": "quotas", - "radius": "radiuses", - "referendum": "referendums", - "ress": "resses", - "rice": "rice", - "salmon": "salmon", - "sex": "sexes", - "series": "series", - "sheep": "sheep", - "shoe": "shoes", - "shrimp": "shrimp", - "species": "species", - "stimulus": "stimuli", - "stratum": "strata", - "swine": "swine", - "syllabus": "syllabi", - "symposium": "symposiums", - "synapse": "synapses", - "synopsis": "synopses", - "tableau": "tableaus", - "testis": "testes", - "thesis": "theses", - "thief": "thieves", - "tooth": "teeth", - "trout": "trout", - "tuna": "tuna", - "vedalia": "vedalias", - "vertebra": "vertebrae", - "vertix": "vertices", - "vita": "vitae", - "vortex": "vortices", - "wharf": "wharves", - "wife": "wives", - "woman": "women", - "wolf": "wolves", - "you": "you", +type word struct { + singular string + plural string + alternative string + unidirectional bool // plural to singular is not possible (or bad) + uncountable bool + exact bool +} + +// dictionary is the main table for singularize and pluralize. +// All words in the dictionary will be added to singleToPlural, pluralToSingle +// and singlePluralAssertions by init() functions. +var dictionary = []word{ + // identicals https://en.wikipedia.org/wiki/English_plurals#Nouns_with_identical_singular_and_plural + {singular: "aircraft", plural: "aircraft"}, + {singular: "beef", plural: "beef", alternative: "beefs"}, + {singular: "bison", plural: "bison"}, + {singular: "blues", plural: "blues", unidirectional: true}, + {singular: "chassis", plural: "chassis"}, + {singular: "deer", plural: "deer"}, + {singular: "fish", plural: "fish", alternative: "fishes"}, + {singular: "moose", plural: "moose"}, + {singular: "police", plural: "police"}, + {singular: "salmon", plural: "salmon", alternative: "salmons"}, + {singular: "series", plural: "series"}, + {singular: "sheep", plural: "sheep"}, + {singular: "shrimp", plural: "shrimp", alternative: "shrimps"}, + {singular: "species", plural: "species"}, + {singular: "swine", plural: "swine", alternative: "swines"}, + {singular: "trout", plural: "trout", alternative: "trouts"}, + {singular: "tuna", plural: "tuna", alternative: "tunas"}, + {singular: "you", plural: "you"}, + // -en https://en.wikipedia.org/wiki/English_plurals#Plurals_in_-(e)n + {singular: "child", plural: "children"}, + {singular: "ox", plural: "oxen", exact: true}, + // apophonic https://en.wikipedia.org/wiki/English_plurals#Apophonic_plurals + {singular: "foot", plural: "feet"}, + {singular: "goose", plural: "geese"}, + {singular: "man", plural: "men"}, + {singular: "human", plural: "humans"}, // not humen + {singular: "louse", plural: "lice", exact: true}, + {singular: "mouse", plural: "mice"}, + {singular: "tooth", plural: "teeth"}, + {singular: "woman", plural: "women"}, + // misc https://en.wikipedia.org/wiki/English_plurals#Miscellaneous_irregular_plurals + {singular: "die", plural: "dice", exact: true}, + {singular: "person", plural: "people"}, + + // Words from French that end in -u add an x; in addition to eau to eaux rule + {singular: "adieu", plural: "adieux", alternative: "adieus"}, + {singular: "fabliau", plural: "fabliaux"}, + {singular: "bureau", plural: "bureaus", alternative: "bureaux"}, // popular + + // Words from Greek that end in -on change -on to -a; in addition to hedron rule + {singular: "criterion", plural: "criteria"}, + {singular: "ganglion", plural: "ganglia", alternative: "ganglions"}, + {singular: "lexicon", plural: "lexica", alternative: "lexicons"}, + {singular: "mitochondrion", plural: "mitochondria", alternative: "mitochondrions"}, + {singular: "noumenon", plural: "noumena"}, + {singular: "phenomenon", plural: "phenomena"}, + {singular: "taxon", plural: "taxa"}, + + // Words from Latin that end in -um change -um to -a; in addition to some rules + {singular: "media", plural: "media"}, // popular case: media -> media + {singular: "medium", plural: "media", alternative: "mediums", unidirectional: true}, + {singular: "stadium", plural: "stadiums", alternative: "stadia"}, + {singular: "aquarium", plural: "aquaria", alternative: "aquariums"}, + {singular: "auditorium", plural: "auditoria", alternative: "auditoriums"}, + {singular: "symposium", plural: "symposia", alternative: "symposiums"}, + {singular: "curriculum", plural: "curriculums", alternative: "curricula"}, // ulum + {singular: "quota", plural: "quotas"}, + + // Words from Latin that end in -us change -us to -i or -era + {singular: "alumnus", plural: "alumni", alternative: "alumnuses"}, // -i + {singular: "bacillus", plural: "bacilli"}, + {singular: "cactus", plural: "cacti", alternative: "cactuses"}, + {singular: "coccus", plural: "cocci"}, + {singular: "focus", plural: "foci", alternative: "focuses"}, + {singular: "locus", plural: "loci", alternative: "locuses"}, + {singular: "nucleus", plural: "nuclei", alternative: "nucleuses"}, + {singular: "octopus", plural: "octupuses", alternative: "octopi"}, + {singular: "radius", plural: "radii", alternative: "radiuses"}, + {singular: "syllabus", plural: "syllabi"}, + {singular: "corpus", plural: "corpora", alternative: "corpuses"}, // -ra + {singular: "genus", plural: "genera"}, + + // Words from Latin that end in -a change -a to -ae + {singular: "alumna", plural: "alumnae"}, + {singular: "vertebra", plural: "vertebrae"}, + {singular: "differentia", plural: "differentiae"}, // -tia + {singular: "minutia", plural: "minutiae"}, + {singular: "vita", plural: "vitae"}, // -ita + {singular: "larva", plural: "larvae"}, // -va + {singular: "postcava", plural: "postcavae"}, + {singular: "praecava", plural: "praecavae"}, + {singular: "uva", plural: "uvae"}, + + // Words from Latin that end in -ex change -ex to -ices + {singular: "apex", plural: "apices", alternative: "apexes"}, + {singular: "codex", plural: "codices", alternative: "codexes"}, + {singular: "index", plural: "indices", alternative: "indexes"}, + {singular: "latex", plural: "latices", alternative: "latexes"}, + {singular: "vertex", plural: "vertices", alternative: "vertexes"}, + {singular: "vortex", plural: "vortices", alternative: "vortexes"}, + + // Words from Latin that end in -ix change -ix to -ices (eg, matrix becomes matrices) + {singular: "appendix", plural: "appendices", alternative: "appendixes"}, + {singular: "radix", plural: "radices", alternative: "radixes"}, + {singular: "helix", plural: "helices", alternative: "helixes"}, + + // Words from Latin that end in -is change -is to -es + {singular: "axis", plural: "axes", exact: true}, + {singular: "crisis", plural: "crises"}, + {singular: "ellipsis", plural: "ellipses", unidirectional: true}, // ellipse + {singular: "genesis", plural: "geneses"}, + {singular: "oasis", plural: "oases"}, + {singular: "thesis", plural: "theses"}, + {singular: "testis", plural: "testes"}, + {singular: "base", plural: "bases"}, // popular case + {singular: "basis", plural: "bases", unidirectional: true}, + + {singular: "alias", plural: "aliases", exact: true}, // no alia, no aliasis + {singular: "vedalia", plural: "vedalias"}, // no vedalium, no vedaliases + + // Words that end in -ch, -o, -s, -sh, -x, -z (can be conflict with the others) + {singular: "use", plural: "uses", exact: true}, // us vs use + {singular: "abuse", plural: "abuses"}, + {singular: "cause", plural: "causes"}, + {singular: "clause", plural: "clauses"}, + {singular: "cruse", plural: "cruses"}, + {singular: "excuse", plural: "excuses"}, + {singular: "fuse", plural: "fuses"}, + {singular: "house", plural: "houses"}, + {singular: "misuse", plural: "misuses"}, + {singular: "muse", plural: "muses"}, + {singular: "pause", plural: "pauses"}, + {singular: "ache", plural: "aches"}, + {singular: "topaz", plural: "topazes"}, + {singular: "buffalo", plural: "buffaloes", alternative: "buffalos"}, + {singular: "potato", plural: "potatoes"}, + {singular: "tomato", plural: "tomatoes"}, + + // uncountables + {singular: "equipment", uncountable: true}, + {singular: "information", uncountable: true}, + {singular: "jeans", uncountable: true}, + {singular: "money", uncountable: true}, + {singular: "news", uncountable: true}, + {singular: "rice", uncountable: true}, + + // exceptions: -f to -ves, not -fe + {singular: "dwarf", plural: "dwarfs", alternative: "dwarves"}, + {singular: "hoof", plural: "hoofs", alternative: "hooves"}, + {singular: "thief", plural: "thieves"}, + // exceptions: instead of -f(e) to -ves + {singular: "chive", plural: "chives"}, + {singular: "hive", plural: "hives"}, + {singular: "move", plural: "moves"}, + + // exceptions: instead of -y to -ies + {singular: "movie", plural: "movies"}, + {singular: "cookie", plural: "cookies"}, + + // exceptions: instead of -um to -a + {singular: "pretorium", plural: "pretoriums"}, + {singular: "agenda", plural: "agendas"}, // instead of plural of agendum + // exceptions: instead of -um to -a (chemical element names) + + // Words from Latin that end in -a change -a to -ae + {singular: "formula", plural: "formulas", alternative: "formulae"}, // also -um/-a + + // exceptions: instead of -o to -oes + {singular: "shoe", plural: "shoes"}, + {singular: "toe", plural: "toes", exact: true}, + {singular: "graffiti", plural: "graffiti"}, + + // abbreviations + {singular: "ID", plural: "IDs", exact: true}, } +// singleToPlural is the highest priority map for Pluralize(). +// singularToPluralSuffixList is used to build pluralRules for suffixes and +// compound words. +var singleToPlural = map[string]string{} + +// pluralToSingle is the highest priority map for Singularize(). +// singularToPluralSuffixList is used to build singularRules for suffixes and +// compound words. var pluralToSingle = map[string]string{} +// NOTE: This map should not be built as reverse map of singleToPlural since +// there are words that has the same plurals. + +// build singleToPlural and pluralToSingle with dictionary func init() { - for k, v := range singleToPlural { - pluralToSingle[v] = k + for _, wd := range dictionary { + if singleToPlural[wd.singular] != "" { + panic(fmt.Errorf("map singleToPlural already has an entry for %s", wd.singular)) + } + + if wd.uncountable && wd.plural == "" { + wd.plural = wd.singular + } + + if wd.plural == "" { + panic(fmt.Errorf("plural for %s is not provided", wd.singular)) + } + + singleToPlural[wd.singular] = wd.plural + + if !wd.unidirectional { + if pluralToSingle[wd.plural] != "" { + panic(fmt.Errorf("map pluralToSingle already has an entry for %s", wd.plural)) + } + pluralToSingle[wd.plural] = wd.singular + + if wd.alternative != "" { + if pluralToSingle[wd.alternative] != "" { + panic(fmt.Errorf("map pluralToSingle already has an entry for %s", wd.alternative)) + } + pluralToSingle[wd.alternative] = wd.singular + } + } } } @@ -156,133 +258,160 @@ type singularToPluralSuffix struct { plural string } +// singularToPluralSuffixList is a list of "bidirectional" suffix rules for +// the irregular plurals follow such rules. +// +// NOTE: IMPORTANT! The order of items in this list is the rule priority, not +// alphabet order. The first match will be used to inflect. var singularToPluralSuffixList = []singularToPluralSuffix{ - {"iterion", "iteria"}, - {"campus", "campuses"}, - {"genera", "genus"}, - {"person", "people"}, - {"phylum", "phyla"}, - {"randum", "randa"}, - {"actus", "acti"}, - {"adium", "adia"}, - {"basis", "basis"}, - {"child", "children"}, - {"chive", "chives"}, - {"focus", "foci"}, - {"hello", "hellos"}, - {"jeans", "jeans"}, - {"louse", "lice"}, - {"media", "media"}, - {"mouse", "mice"}, - {"movie", "movies"}, - {"oasis", "oasis"}, - {"atum", "ata"}, - {"atus", "atuses"}, - {"base", "bases"}, - {"cess", "cesses"}, - {"dium", "diums"}, - {"eses", "esis"}, - {"half", "halves"}, - {"hive", "hives"}, - {"iano", "ianos"}, - {"irus", "iri"}, - {"isis", "ises"}, - {"leus", "li"}, - {"mnus", "mni"}, - {"move", "moves"}, - {"news", "news"}, - {"odex", "odice"}, - {"oose", "eese"}, - {"ouse", "ouses"}, - {"ovum", "ova"}, - {"rion", "ria"}, - {"shoe", "shoes"}, - {"stis", "stes"}, - {"tive", "tives"}, - {"vice", "vices"}, - {"wife", "wives"}, - {"afe", "aves"}, - {"bfe", "bves"}, - {"box", "boxes"}, - {"cfe", "cves"}, - {"dfe", "dves"}, - {"dge", "dges"}, - {"efe", "eves"}, - {"gfe", "gves"}, - {"hfe", "hves"}, - {"ife", "ives"}, - {"itz", "itzes"}, - {"ium", "ia"}, - {"ize", "izes"}, - {"jfe", "jves"}, - {"kfe", "kves"}, - {"man", "men"}, - {"mfe", "mves"}, - {"nfe", "nves"}, - {"nna", "nnas"}, + // https://en.wiktionary.org/wiki/Appendix:English_irregular_nouns#Rules + // Words that end in -f or -fe change -f or -fe to -ves + {"tive", "tives"}, // exception + {"eaf", "eaves"}, {"oaf", "oaves"}, - {"oci", "ocus"}, - {"ode", "odes"}, - {"ofe", "oves"}, - {"oot", "eet"}, - {"pfe", "pves"}, - {"pse", "psis"}, - {"qfe", "qves"}, - {"quy", "quies"}, + {"afe", "aves"}, + {"arf", "arves"}, {"rfe", "rves"}, - {"sfe", "sves"}, - {"tfe", "tves"}, - {"tum", "ta"}, - {"tus", "tuses"}, - {"ufe", "uves"}, - {"ula", "ulae"}, - {"ula", "ulas"}, - {"uli", "ulus"}, - {"use", "uses"}, - {"uss", "usses"}, - {"vfe", "vves"}, - {"wfe", "wves"}, - {"xfe", "xves"}, - {"yfe", "yves"}, - {"you", "you"}, - {"zfe", "zves"}, - {"by", "bies"}, + {"rf", "rves"}, + {"lf", "lves"}, + {"fe", "ves"}, // previously '[a-eg-km-z]fe' TODO: regex support + + // Words that end in -y preceded by a consonant change -y to -ies + {"ay", "ays"}, + {"ey", "eys"}, + {"oy", "oys"}, + {"quy", "quies"}, + {"uy", "uys"}, + {"y", "ies"}, // '[^aeiou]y' + + // Words from French that end in -u add an x (eg, château becomes châteaux) + {"eau", "eaux"}, // it seems like 'eau' is the most popular form of this rule + + // Words from Latin that end in -a change -a to -ae; before -on to -a and -um to -a + {"bula", "bulae"}, + {"dula", "bulae"}, + {"lula", "bulae"}, + {"nula", "bulae"}, + {"vula", "bulae"}, + + // Words from Greek that end in -on change -on to -a (eg, polyhedron becomes polyhedra) + // https://en.wiktionary.org/wiki/Category:English_irregular_plurals_ending_in_"-a" + {"hedron", "hedra"}, + + // Words from Latin that end in -um change -um to -a (eg, minimum becomes minima) + // https://en.wiktionary.org/wiki/Category:English_irregular_plurals_ending_in_"-a" + {"ium", "ia"}, // some exceptions especially chemical element names + {"seum", "seums"}, + {"eum", "ea"}, + {"oum", "oa"}, + {"stracum", "straca"}, + {"dum", "da"}, + {"elum", "ela"}, + {"ilum", "ila"}, + {"olum", "ola"}, + {"ulum", "ula"}, + {"llum", "lla"}, + {"ylum", "yla"}, + {"imum", "ima"}, + {"ernum", "erna"}, + {"gnum", "gna"}, + {"brum", "bra"}, + {"crum", "cra"}, + {"terum", "tera"}, + {"serum", "sera"}, + {"trum", "tra"}, + {"antum", "anta"}, + {"atum", "ata"}, + {"entum", "enta"}, + {"etum", "eta"}, + {"itum", "ita"}, + {"otum", "ota"}, + {"utum", "uta"}, + {"ctum", "cta"}, + {"ovum", "ova"}, + + // Words from Latin that end in -us change -us to -i or -era + // not easy to make a simple rule. just add them all to the dictionary + + // Words from Latin that end in -ex change -ex to -ices (eg, vortex becomes vortices) + // Words from Latin that end in -ix change -ix to -ices (eg, matrix becomes matrices) + // for example, -dix, -dex, and -dice will have the same plural form so + // making a simple rule is not possible for them + {"trix", "trices"}, // ignore a few words end in trice + + // Words from Latin that end in -is change -is to -es (eg, thesis becomes theses) + // -sis and -se has the same plural -ses so making a rule is not easy too. + {"iasis", "iases"}, + {"mesis", "meses"}, + {"kinesis", "kineses"}, + {"resis", "reses"}, + {"gnosis", "gnoses"}, // e.g. diagnosis + {"opsis", "opses"}, // e.g. synopsis + {"ysis", "yses"}, // e.g. analysis + + // Words that end in -ch, -o, -s, -sh, -x, -z + {"ouse", "ouses"}, + {"lause", "lauses"}, + {"us", "uses"}, // use/uses is in the dictionary + {"ch", "ches"}, - {"cy", "cies"}, - {"dy", "dies"}, - {"ex", "ices"}, - {"fy", "fies"}, - {"gy", "gies"}, - {"hy", "hies"}, {"io", "ios"}, - {"jy", "jies"}, - {"ky", "kies"}, - {"lf", "lves"}, - {"ly", "lies"}, - {"my", "mies"}, - {"ny", "nies"}, - {"py", "pies"}, - {"qy", "qies"}, - {"rf", "rves"}, - {"ry", "ries"}, {"sh", "shes"}, {"ss", "sses"}, - {"sy", "sies"}, - {"ty", "ties"}, + {"ez", "ezzes"}, + {"iz", "izzes"}, {"tz", "tzes"}, - {"va", "vae"}, - {"vy", "vies"}, - {"wy", "wies"}, - {"xy", "xies"}, - {"zy", "zies"}, {"zz", "zzes"}, + {"ano", "anos"}, + {"lo", "los"}, + {"to", "tos"}, + {"oo", "oos"}, {"o", "oes"}, {"x", "xes"}, + + // for abbreviations + {"S", "Ses"}, + + // excluded rules: seems rare + // Words from Hebrew that add -im or -ot (eg, cherub becomes cherubim) + // - cherub (cherubs or cherubim), seraph (seraphs or seraphim) + // Words from Greek that end in -ma change -ma to -mata + // - The most of words end in -ma are in this category but it looks like + // just adding -s is more popular. + // Words from Latin that end in -nx change -nx to -nges + // - The most of words end in -nx are in this category but it looks like + // just adding -es is more popular. (sphinxes) + + // excluded rules: don't care at least for now: + // Words that end in -ful that add an s after the -ful + // Words that end in -s or -ese denoting a national of a particular country + // Symbols or letters, which often add -'s } func init() { - for _, suffix := range singularToPluralSuffixList { - AddPlural(suffix.singular, suffix.plural) - AddSingular(suffix.plural, suffix.singular) + for i := len(singularToPluralSuffixList) - 1; i >= 0; i-- { + InsertPluralRule(singularToPluralSuffixList[i].singular, singularToPluralSuffixList[i].plural) + InsertSingularRule(singularToPluralSuffixList[i].plural, singularToPluralSuffixList[i].singular) + } + + // build pluralRule and singularRule with dictionary for compound words + for _, wd := range dictionary { + if wd.exact { + continue + } + + if wd.uncountable && wd.plural == "" { + wd.plural = wd.singular + } + + InsertPluralRule(wd.singular, wd.plural) + + if !wd.unidirectional { + InsertSingularRule(wd.plural, wd.singular) + + if wd.alternative != "" { + InsertSingularRule(wd.alternative, wd.singular) + } + } } } diff --git a/vendor/github.com/gobuffalo/flect/pluralize.go b/vendor/github.com/gobuffalo/flect/pluralize.go index e265f84e91..d0ac77d3fc 100644 --- a/vendor/github.com/gobuffalo/flect/pluralize.go +++ b/vendor/github.com/gobuffalo/flect/pluralize.go @@ -38,15 +38,28 @@ func (i Ident) Pluralize() Ident { pluralMoot.RLock() defer pluralMoot.RUnlock() + // check if the Original has an explicit entry in the map + if p, ok := singleToPlural[i.Original]; ok { + return i.ReplaceSuffix(i.Original, p) + } + if _, ok := pluralToSingle[i.Original]; ok { + return i + } + ls := strings.ToLower(s) if _, ok := pluralToSingle[ls]; ok { return i } + if p, ok := singleToPlural[ls]; ok { + if s == Capitalize(s) { + p = Capitalize(p) + } return i.ReplaceSuffix(s, p) } + for _, r := range pluralRules { - if strings.HasSuffix(ls, r.suffix) { + if strings.HasSuffix(s, r.suffix) { return i.ReplaceSuffix(s, r.fn(s)) } } diff --git a/vendor/github.com/gobuffalo/flect/rule.go b/vendor/github.com/gobuffalo/flect/rule.go index dc616b337d..5428e6ed01 100644 --- a/vendor/github.com/gobuffalo/flect/rule.go +++ b/vendor/github.com/gobuffalo/flect/rule.go @@ -7,4 +7,11 @@ type rule struct { fn ruleFn } +func simpleRuleFunc(suffix, repl string) func(string) string { + return func(s string) string { + s = s[:len(s)-len(suffix)] + return s + repl + } +} + func noop(s string) string { return s } diff --git a/vendor/github.com/gobuffalo/flect/singular_rules.go b/vendor/github.com/gobuffalo/flect/singular_rules.go index b20371b355..d59307b73c 100644 --- a/vendor/github.com/gobuffalo/flect/singular_rules.go +++ b/vendor/github.com/gobuffalo/flect/singular_rules.go @@ -3,21 +3,24 @@ package flect var singularRules = []rule{} // AddSingular adds a rule that will replace the given suffix with the replacement suffix. +// The name is confusing. This function will be deprecated in the next release. func AddSingular(ext string, repl string) { + InsertSingularRule(ext, repl) +} + +// InsertSingularRule inserts a rule that will replace the given suffix with +// the repl(acement) at the beginning of the list of the singularize rules. +func InsertSingularRule(suffix, repl string) { singularMoot.Lock() defer singularMoot.Unlock() - singularRules = append(singularRules, rule{ - suffix: ext, - fn: func(s string) string { - s = s[:len(s)-len(ext)] - return s + repl - }, - }) - singularRules = append(singularRules, rule{ + singularRules = append([]rule{{ + suffix: suffix, + fn: simpleRuleFunc(suffix, repl), + }}, singularRules...) + + singularRules = append([]rule{{ suffix: repl, - fn: func(s string) string { - return s - }, - }) + fn: noop, + }}, singularRules...) } diff --git a/vendor/github.com/gobuffalo/flect/singularize.go b/vendor/github.com/gobuffalo/flect/singularize.go index 1ed4995053..d00cf4f1e4 100644 --- a/vendor/github.com/gobuffalo/flect/singularize.go +++ b/vendor/github.com/gobuffalo/flect/singularize.go @@ -19,10 +19,7 @@ func Singularize(s string) string { // SingularizeWithSize("user", 1) = user // SingularizeWithSize("user", 2) = users func SingularizeWithSize(s string, i int) string { - if i == 1 || i == -1 { - return New(s).Singularize().String() - } - return New(s).Pluralize().String() + return PluralizeWithSize(s, i) } // Singularize returns a singular version of the string @@ -30,28 +27,43 @@ func SingularizeWithSize(s string, i int) string { // data = datum // people = person func (i Ident) Singularize() Ident { - s := i.Original + s := i.LastPart() if len(s) == 0 { return i } singularMoot.RLock() defer singularMoot.RUnlock() + + // check if the Original has an explicit entry in the map + if p, ok := pluralToSingle[i.Original]; ok { + return i.ReplaceSuffix(i.Original, p) + } + if _, ok := singleToPlural[i.Original]; ok { + return i + } + ls := strings.ToLower(s) if p, ok := pluralToSingle[ls]; ok { - return New(p) + if s == Capitalize(s) { + p = Capitalize(p) + } + return i.ReplaceSuffix(s, p) } + if _, ok := singleToPlural[ls]; ok { return i } + for _, r := range singularRules { - if strings.HasSuffix(ls, r.suffix) { - return New(r.fn(s)) + if strings.HasSuffix(s, r.suffix) { + return i.ReplaceSuffix(s, r.fn(s)) } } if strings.HasSuffix(s, "s") { - return New(s[:len(s)-1]) + return i.ReplaceSuffix("s", "") } + return i } diff --git a/vendor/github.com/gobuffalo/flect/titleize.go b/vendor/github.com/gobuffalo/flect/titleize.go index cbbf08a5aa..0878ada8de 100644 --- a/vendor/github.com/gobuffalo/flect/titleize.go +++ b/vendor/github.com/gobuffalo/flect/titleize.go @@ -19,12 +19,20 @@ func Titleize(s string) string { // "This is `code` ok" = "This Is `code` OK" func (i Ident) Titleize() Ident { var parts []string + + // TODO: we need to reconsider the design. + // this approach preserves inline code block as is but it also + // preserves the other words start with a special character. + // I would prefer: "*wonderful* world" to be "*Wonderful* World" for _, part := range i.Parts { - x := string(unicode.ToTitle(rune(part[0]))) - if len(part) > 1 { - x += part[1:] + // CAUTION: in unicode, []rune(str)[0] is not rune(str[0]) + runes := []rune(part) + x := string(unicode.ToTitle(runes[0])) + if len(runes) > 1 { + x += string(runes[1:]) } parts = append(parts, x) } + return New(strings.Join(parts, " ")) } diff --git a/vendor/github.com/gobuffalo/flect/underscore.go b/vendor/github.com/gobuffalo/flect/underscore.go index e1466d99b9..d42859a59a 100644 --- a/vendor/github.com/gobuffalo/flect/underscore.go +++ b/vendor/github.com/gobuffalo/flect/underscore.go @@ -6,17 +6,17 @@ import ( ) // Underscore a string -// bob dylan = bob_dylan -// Nice to see you! = nice_to_see_you -// widgetID = widget_id +// bob dylan --> bob_dylan +// Nice to see you! --> nice_to_see_you +// widgetID --> widget_id func Underscore(s string) string { return New(s).Underscore().String() } // Underscore a string -// bob dylan = bob_dylan -// Nice to see you! = nice_to_see_you -// widgetID = widget_id +// bob dylan --> bob_dylan +// Nice to see you! --> nice_to_see_you +// widgetID --> widget_id func (i Ident) Underscore() Ident { out := make([]string, 0, len(i.Parts)) for _, part := range i.Parts { diff --git a/vendor/github.com/gobuffalo/flect/version.go b/vendor/github.com/gobuffalo/flect/version.go index 9624d5df2d..79486ed2c2 100644 --- a/vendor/github.com/gobuffalo/flect/version.go +++ b/vendor/github.com/gobuffalo/flect/version.go @@ -1,4 +1,4 @@ package flect //Version holds Flect version number -const Version = "v0.1.6" +const Version = "v1.0.0" diff --git a/vendor/github.com/inconshreveable/mousetrap/trap_others.go b/vendor/github.com/inconshreveable/mousetrap/trap_others.go index 9d2d8a4bab..06a91f0868 100644 --- a/vendor/github.com/inconshreveable/mousetrap/trap_others.go +++ b/vendor/github.com/inconshreveable/mousetrap/trap_others.go @@ -1,3 +1,4 @@ +//go:build !windows // +build !windows package mousetrap diff --git a/vendor/github.com/inconshreveable/mousetrap/trap_windows.go b/vendor/github.com/inconshreveable/mousetrap/trap_windows.go index 336142a5e3..0c56880216 100644 --- a/vendor/github.com/inconshreveable/mousetrap/trap_windows.go +++ b/vendor/github.com/inconshreveable/mousetrap/trap_windows.go @@ -1,81 +1,32 @@ -// +build windows -// +build !go1.4 - package mousetrap import ( - "fmt" - "os" "syscall" "unsafe" ) -const ( - // defined by the Win32 API - th32cs_snapprocess uintptr = 0x2 -) - -var ( - kernel = syscall.MustLoadDLL("kernel32.dll") - CreateToolhelp32Snapshot = kernel.MustFindProc("CreateToolhelp32Snapshot") - Process32First = kernel.MustFindProc("Process32FirstW") - Process32Next = kernel.MustFindProc("Process32NextW") -) - -// ProcessEntry32 structure defined by the Win32 API -type processEntry32 struct { - dwSize uint32 - cntUsage uint32 - th32ProcessID uint32 - th32DefaultHeapID int - th32ModuleID uint32 - cntThreads uint32 - th32ParentProcessID uint32 - pcPriClassBase int32 - dwFlags uint32 - szExeFile [syscall.MAX_PATH]uint16 -} - -func getProcessEntry(pid int) (pe *processEntry32, err error) { - snapshot, _, e1 := CreateToolhelp32Snapshot.Call(th32cs_snapprocess, uintptr(0)) - if snapshot == uintptr(syscall.InvalidHandle) { - err = fmt.Errorf("CreateToolhelp32Snapshot: %v", e1) - return +func getProcessEntry(pid int) (*syscall.ProcessEntry32, error) { + snapshot, err := syscall.CreateToolhelp32Snapshot(syscall.TH32CS_SNAPPROCESS, 0) + if err != nil { + return nil, err } - defer syscall.CloseHandle(syscall.Handle(snapshot)) - - var processEntry processEntry32 - processEntry.dwSize = uint32(unsafe.Sizeof(processEntry)) - ok, _, e1 := Process32First.Call(snapshot, uintptr(unsafe.Pointer(&processEntry))) - if ok == 0 { - err = fmt.Errorf("Process32First: %v", e1) - return + defer syscall.CloseHandle(snapshot) + var procEntry syscall.ProcessEntry32 + procEntry.Size = uint32(unsafe.Sizeof(procEntry)) + if err = syscall.Process32First(snapshot, &procEntry); err != nil { + return nil, err } - for { - if processEntry.th32ProcessID == uint32(pid) { - pe = &processEntry - return + if procEntry.ProcessID == uint32(pid) { + return &procEntry, nil } - - ok, _, e1 = Process32Next.Call(snapshot, uintptr(unsafe.Pointer(&processEntry))) - if ok == 0 { - err = fmt.Errorf("Process32Next: %v", e1) - return + err = syscall.Process32Next(snapshot, &procEntry) + if err != nil { + return nil, err } } } -func getppid() (pid int, err error) { - pe, err := getProcessEntry(os.Getpid()) - if err != nil { - return - } - - pid = int(pe.th32ParentProcessID) - return -} - // StartedByExplorer returns true if the program was invoked by the user double-clicking // on the executable from explorer.exe // @@ -83,16 +34,9 @@ func getppid() (pid int, err error) { // It does not guarantee that the program was run from a terminal. It only can tell you // whether it was launched from explorer.exe func StartedByExplorer() bool { - ppid, err := getppid() + pe, err := getProcessEntry(syscall.Getppid()) if err != nil { return false } - - pe, err := getProcessEntry(ppid) - if err != nil { - return false - } - - name := syscall.UTF16ToString(pe.szExeFile[:]) - return name == "explorer.exe" + return "explorer.exe" == syscall.UTF16ToString(pe.ExeFile[:]) } diff --git a/vendor/github.com/inconshreveable/mousetrap/trap_windows_1.4.go b/vendor/github.com/inconshreveable/mousetrap/trap_windows_1.4.go deleted file mode 100644 index 9a28e57c3c..0000000000 --- a/vendor/github.com/inconshreveable/mousetrap/trap_windows_1.4.go +++ /dev/null @@ -1,46 +0,0 @@ -// +build windows -// +build go1.4 - -package mousetrap - -import ( - "os" - "syscall" - "unsafe" -) - -func getProcessEntry(pid int) (*syscall.ProcessEntry32, error) { - snapshot, err := syscall.CreateToolhelp32Snapshot(syscall.TH32CS_SNAPPROCESS, 0) - if err != nil { - return nil, err - } - defer syscall.CloseHandle(snapshot) - var procEntry syscall.ProcessEntry32 - procEntry.Size = uint32(unsafe.Sizeof(procEntry)) - if err = syscall.Process32First(snapshot, &procEntry); err != nil { - return nil, err - } - for { - if procEntry.ProcessID == uint32(pid) { - return &procEntry, nil - } - err = syscall.Process32Next(snapshot, &procEntry) - if err != nil { - return nil, err - } - } -} - -// StartedByExplorer returns true if the program was invoked by the user double-clicking -// on the executable from explorer.exe -// -// It is conservative and returns false if any of the internal calls fail. -// It does not guarantee that the program was run from a terminal. It only can tell you -// whether it was launched from explorer.exe -func StartedByExplorer() bool { - pe, err := getProcessEntry(os.Getppid()) - if err != nil { - return false - } - return "explorer.exe" == syscall.UTF16ToString(pe.ExeFile[:]) -} diff --git a/vendor/github.com/spf13/cobra/.golangci.yml b/vendor/github.com/spf13/cobra/.golangci.yml index 439d3e1de4..2578d94b5e 100644 --- a/vendor/github.com/spf13/cobra/.golangci.yml +++ b/vendor/github.com/spf13/cobra/.golangci.yml @@ -1,4 +1,4 @@ -# Copyright 2013-2022 The Cobra Authors +# Copyright 2013-2023 The Cobra Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/vendor/github.com/spf13/cobra/Makefile b/vendor/github.com/spf13/cobra/Makefile index c433a01bce..0da8d7aa08 100644 --- a/vendor/github.com/spf13/cobra/Makefile +++ b/vendor/github.com/spf13/cobra/Makefile @@ -5,10 +5,6 @@ ifeq (, $(shell which golangci-lint)) $(warning "could not find golangci-lint in $(PATH), run: curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh") endif -ifeq (, $(shell which richgo)) -$(warning "could not find richgo in $(PATH), run: go install github.com/kyoh86/richgo@latest") -endif - .PHONY: fmt lint test install_deps clean default: all @@ -25,6 +21,10 @@ lint: test: install_deps $(info ******************** running tests ********************) + go test -v ./... + +richtest: install_deps + $(info ******************** running tests with kyoh86/richgo ********************) richgo test -v ./... install_deps: diff --git a/vendor/github.com/spf13/cobra/README.md b/vendor/github.com/spf13/cobra/README.md index 7cc726beb4..592c0b8ab0 100644 --- a/vendor/github.com/spf13/cobra/README.md +++ b/vendor/github.com/spf13/cobra/README.md @@ -1,4 +1,4 @@ -![cobra logo](https://cloud.githubusercontent.com/assets/173412/10886352/ad566232-814f-11e5-9cd0-aa101788c117.png) +![cobra logo](assets/CobraMain.png) Cobra is a library for creating powerful modern CLI applications. @@ -6,7 +6,7 @@ Cobra is used in many Go projects such as [Kubernetes](https://kubernetes.io/), [Hugo](https://gohugo.io), and [GitHub CLI](https://github.com/cli/cli) to name a few. [This list](./projects_using_cobra.md) contains a more extensive list of projects using Cobra. -[![](https://img.shields.io/github/workflow/status/spf13/cobra/Test?longCache=tru&label=Test&logo=github%20actions&logoColor=fff)](https://github.com/spf13/cobra/actions?query=workflow%3ATest) +[![](https://img.shields.io/github/actions/workflow/status/spf13/cobra/test.yml?branch=main&longCache=true&label=Test&logo=github%20actions&logoColor=fff)](https://github.com/spf13/cobra/actions?query=workflow%3ATest) [![Go Reference](https://pkg.go.dev/badge/github.com/spf13/cobra.svg)](https://pkg.go.dev/github.com/spf13/cobra) [![Go Report Card](https://goreportcard.com/badge/github.com/spf13/cobra)](https://goreportcard.com/report/github.com/spf13/cobra) [![Slack](https://img.shields.io/badge/Slack-cobra-brightgreen)](https://gophers.slack.com/archives/CD3LP1199) diff --git a/vendor/github.com/spf13/cobra/active_help.go b/vendor/github.com/spf13/cobra/active_help.go index 95e03aecb6..2d0239437a 100644 --- a/vendor/github.com/spf13/cobra/active_help.go +++ b/vendor/github.com/spf13/cobra/active_help.go @@ -1,4 +1,4 @@ -// Copyright 2013-2022 The Cobra Authors +// Copyright 2013-2023 The Cobra Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/vendor/github.com/spf13/cobra/args.go b/vendor/github.com/spf13/cobra/args.go index 2c1f99e787..e79ec33a81 100644 --- a/vendor/github.com/spf13/cobra/args.go +++ b/vendor/github.com/spf13/cobra/args.go @@ -1,4 +1,4 @@ -// Copyright 2013-2022 The Cobra Authors +// Copyright 2013-2023 The Cobra Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -21,7 +21,7 @@ import ( type PositionalArgs func(cmd *Command, args []string) error -// Legacy arg validation has the following behaviour: +// legacyArgs validation has the following behaviour: // - root commands with no subcommands can take arbitrary arguments // - root commands with subcommands will do subcommand validity checking // - subcommands will always accept arbitrary arguments diff --git a/vendor/github.com/spf13/cobra/bash_completions.go b/vendor/github.com/spf13/cobra/bash_completions.go index 3acdb27974..10c78847de 100644 --- a/vendor/github.com/spf13/cobra/bash_completions.go +++ b/vendor/github.com/spf13/cobra/bash_completions.go @@ -1,4 +1,4 @@ -// Copyright 2013-2022 The Cobra Authors +// Copyright 2013-2023 The Cobra Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -532,7 +532,7 @@ func writeLocalNonPersistentFlag(buf io.StringWriter, flag *pflag.Flag) { } } -// Setup annotations for go completions for registered flags +// prepareCustomAnnotationsForFlags setup annotations for go completions for registered flags func prepareCustomAnnotationsForFlags(cmd *Command) { flagCompletionMutex.RLock() defer flagCompletionMutex.RUnlock() diff --git a/vendor/github.com/spf13/cobra/bash_completionsV2.go b/vendor/github.com/spf13/cobra/bash_completionsV2.go index bb4b71892c..19b09560c1 100644 --- a/vendor/github.com/spf13/cobra/bash_completionsV2.go +++ b/vendor/github.com/spf13/cobra/bash_completionsV2.go @@ -1,4 +1,4 @@ -// Copyright 2013-2022 The Cobra Authors +// Copyright 2013-2023 The Cobra Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -38,7 +38,7 @@ func genBashComp(buf io.StringWriter, name string, includeDesc bool) { __%[1]s_debug() { - if [[ -n ${BASH_COMP_DEBUG_FILE:-} ]]; then + if [[ -n ${BASH_COMP_DEBUG_FILE-} ]]; then echo "$*" >> "${BASH_COMP_DEBUG_FILE}" fi } @@ -65,7 +65,7 @@ __%[1]s_get_completion_results() { lastChar=${lastParam:$((${#lastParam}-1)):1} __%[1]s_debug "lastParam ${lastParam}, lastChar ${lastChar}" - if [ -z "${cur}" ] && [ "${lastChar}" != "=" ]; then + if [[ -z ${cur} && ${lastChar} != = ]]; then # If the last parameter is complete (there is a space following it) # We add an extra empty parameter so we can indicate this to the go method. __%[1]s_debug "Adding extra empty parameter" @@ -75,7 +75,7 @@ __%[1]s_get_completion_results() { # When completing a flag with an = (e.g., %[1]s -n=) # bash focuses on the part after the =, so we need to remove # the flag part from $cur - if [[ "${cur}" == -*=* ]]; then + if [[ ${cur} == -*=* ]]; then cur="${cur#*=}" fi @@ -87,7 +87,7 @@ __%[1]s_get_completion_results() { directive=${out##*:} # Remove the directive out=${out%%:*} - if [ "${directive}" = "${out}" ]; then + if [[ ${directive} == "${out}" ]]; then # There is not directive specified directive=0 fi @@ -101,22 +101,36 @@ __%[1]s_process_completion_results() { local shellCompDirectiveNoFileComp=%[5]d local shellCompDirectiveFilterFileExt=%[6]d local shellCompDirectiveFilterDirs=%[7]d + local shellCompDirectiveKeepOrder=%[8]d - if [ $((directive & shellCompDirectiveError)) -ne 0 ]; then + if (((directive & shellCompDirectiveError) != 0)); then # Error code. No completion. __%[1]s_debug "Received error from custom completion go code" return else - if [ $((directive & shellCompDirectiveNoSpace)) -ne 0 ]; then - if [[ $(type -t compopt) = "builtin" ]]; then + if (((directive & shellCompDirectiveNoSpace) != 0)); then + if [[ $(type -t compopt) == builtin ]]; then __%[1]s_debug "Activating no space" compopt -o nospace else __%[1]s_debug "No space directive not supported in this version of bash" fi fi - if [ $((directive & shellCompDirectiveNoFileComp)) -ne 0 ]; then - if [[ $(type -t compopt) = "builtin" ]]; then + if (((directive & shellCompDirectiveKeepOrder) != 0)); then + if [[ $(type -t compopt) == builtin ]]; then + # no sort isn't supported for bash less than < 4.4 + if [[ ${BASH_VERSINFO[0]} -lt 4 || ( ${BASH_VERSINFO[0]} -eq 4 && ${BASH_VERSINFO[1]} -lt 4 ) ]]; then + __%[1]s_debug "No sort directive not supported in this version of bash" + else + __%[1]s_debug "Activating keep order" + compopt -o nosort + fi + else + __%[1]s_debug "No sort directive not supported in this version of bash" + fi + fi + if (((directive & shellCompDirectiveNoFileComp) != 0)); then + if [[ $(type -t compopt) == builtin ]]; then __%[1]s_debug "Activating no file completion" compopt +o default else @@ -130,7 +144,7 @@ __%[1]s_process_completion_results() { local activeHelp=() __%[1]s_extract_activeHelp - if [ $((directive & shellCompDirectiveFilterFileExt)) -ne 0 ]; then + if (((directive & shellCompDirectiveFilterFileExt) != 0)); then # File extension filtering local fullFilter filter filteringCmd @@ -143,13 +157,12 @@ __%[1]s_process_completion_results() { filteringCmd="_filedir $fullFilter" __%[1]s_debug "File filtering command: $filteringCmd" $filteringCmd - elif [ $((directive & shellCompDirectiveFilterDirs)) -ne 0 ]; then + elif (((directive & shellCompDirectiveFilterDirs) != 0)); then # File completion for directories only - # Use printf to strip any trailing newline local subdir - subdir=$(printf "%%s" "${completions[0]}") - if [ -n "$subdir" ]; then + subdir=${completions[0]} + if [[ -n $subdir ]]; then __%[1]s_debug "Listing directories in $subdir" pushd "$subdir" >/dev/null 2>&1 && _filedir -d && popd >/dev/null 2>&1 || return else @@ -164,7 +177,7 @@ __%[1]s_process_completion_results() { __%[1]s_handle_special_char "$cur" = # Print the activeHelp statements before we finish - if [ ${#activeHelp[*]} -ne 0 ]; then + if ((${#activeHelp[*]} != 0)); then printf "\n"; printf "%%s\n" "${activeHelp[@]}" printf "\n" @@ -184,21 +197,21 @@ __%[1]s_process_completion_results() { # Separate activeHelp lines from real completions. # Fills the $activeHelp and $completions arrays. __%[1]s_extract_activeHelp() { - local activeHelpMarker="%[8]s" + local activeHelpMarker="%[9]s" local endIndex=${#activeHelpMarker} while IFS='' read -r comp; do - if [ "${comp:0:endIndex}" = "$activeHelpMarker" ]; then + if [[ ${comp:0:endIndex} == $activeHelpMarker ]]; then comp=${comp:endIndex} __%[1]s_debug "ActiveHelp found: $comp" - if [ -n "$comp" ]; then + if [[ -n $comp ]]; then activeHelp+=("$comp") fi else # Not an activeHelp line but a normal completion completions+=("$comp") fi - done < <(printf "%%s\n" "${out}") + done <<<"${out}" } __%[1]s_handle_completion_types() { @@ -254,7 +267,7 @@ __%[1]s_handle_standard_completion_case() { done < <(printf "%%s\n" "${completions[@]}") # If there is a single completion left, remove the description text - if [ ${#COMPREPLY[*]} -eq 1 ]; then + if ((${#COMPREPLY[*]} == 1)); then __%[1]s_debug "COMPREPLY[0]: ${COMPREPLY[0]}" comp="${COMPREPLY[0]%%%%$tab*}" __%[1]s_debug "Removed description from single completion, which is now: ${comp}" @@ -271,8 +284,8 @@ __%[1]s_handle_special_char() if [[ "$comp" == *${char}* && "$COMP_WORDBREAKS" == *${char}* ]]; then local word=${comp%%"${comp##*${char}}"} local idx=${#COMPREPLY[*]} - while [[ $((--idx)) -ge 0 ]]; do - COMPREPLY[$idx]=${COMPREPLY[$idx]#"$word"} + while ((--idx >= 0)); do + COMPREPLY[idx]=${COMPREPLY[idx]#"$word"} done fi } @@ -298,7 +311,7 @@ __%[1]s_format_comp_descriptions() # Make sure we can fit a description of at least 8 characters # if we are to align the descriptions. - if [[ $maxdesclength -gt 8 ]]; then + if ((maxdesclength > 8)); then # Add the proper number of spaces to align the descriptions for ((i = ${#comp} ; i < longest ; i++)); do comp+=" " @@ -310,8 +323,8 @@ __%[1]s_format_comp_descriptions() # If there is enough space for any description text, # truncate the descriptions that are too long for the shell width - if [ $maxdesclength -gt 0 ]; then - if [ ${#desc} -gt $maxdesclength ]; then + if ((maxdesclength > 0)); then + if ((${#desc} > maxdesclength)); then desc=${desc:0:$(( maxdesclength - 1 ))} desc+="…" fi @@ -332,9 +345,9 @@ __start_%[1]s() # Call _init_completion from the bash-completion package # to prepare the arguments properly if declare -F _init_completion >/dev/null 2>&1; then - _init_completion -n "=:" || return + _init_completion -n =: || return else - __%[1]s_init_completion -n "=:" || return + __%[1]s_init_completion -n =: || return fi __%[1]s_debug @@ -361,7 +374,7 @@ fi # ex: ts=4 sw=4 et filetype=sh `, name, compCmd, ShellCompDirectiveError, ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp, - ShellCompDirectiveFilterFileExt, ShellCompDirectiveFilterDirs, + ShellCompDirectiveFilterFileExt, ShellCompDirectiveFilterDirs, ShellCompDirectiveKeepOrder, activeHelpMarker)) } diff --git a/vendor/github.com/spf13/cobra/cobra.go b/vendor/github.com/spf13/cobra/cobra.go index fe44bc8a07..b07b44a0ce 100644 --- a/vendor/github.com/spf13/cobra/cobra.go +++ b/vendor/github.com/spf13/cobra/cobra.go @@ -1,4 +1,4 @@ -// Copyright 2013-2022 The Cobra Authors +// Copyright 2013-2023 The Cobra Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -167,8 +167,8 @@ func appendIfNotPresent(s, stringToAppend string) string { // rpad adds padding to the right of a string. func rpad(s string, padding int) string { - template := fmt.Sprintf("%%-%ds", padding) - return fmt.Sprintf(template, s) + formattedString := fmt.Sprintf("%%-%ds", padding) + return fmt.Sprintf(formattedString, s) } // tmpl executes the given template text on data, writing the result to w. diff --git a/vendor/github.com/spf13/cobra/command.go b/vendor/github.com/spf13/cobra/command.go index 6ff47dd5c3..01f7c6f1c5 100644 --- a/vendor/github.com/spf13/cobra/command.go +++ b/vendor/github.com/spf13/cobra/command.go @@ -1,4 +1,4 @@ -// Copyright 2013-2022 The Cobra Authors +// Copyright 2013-2023 The Cobra Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -35,7 +35,7 @@ const FlagSetByCobraAnnotation = "cobra_annotation_flag_set_by_cobra" // FParseErrWhitelist configures Flag parse errors to be ignored type FParseErrWhitelist flag.ParseErrorsWhitelist -// Structure to manage groups for commands +// Group Structure to manage groups for commands type Group struct { ID string Title string @@ -47,7 +47,7 @@ type Group struct { // definition to ensure usability. type Command struct { // Use is the one-line usage message. - // Recommended syntax is as follow: + // Recommended syntax is as follows: // [ ] identifies an optional argument. Arguments that are not enclosed in brackets are required. // ... indicates that you can specify multiple values for the previous argument. // | indicates mutually exclusive information. You can use the argument to the left of the separator or the @@ -321,7 +321,7 @@ func (c *Command) SetHelpCommand(cmd *Command) { c.helpCommand = cmd } -// SetHelpCommandGroup sets the group id of the help command. +// SetHelpCommandGroupID sets the group id of the help command. func (c *Command) SetHelpCommandGroupID(groupID string) { if c.helpCommand != nil { c.helpCommand.GroupID = groupID @@ -330,7 +330,7 @@ func (c *Command) SetHelpCommandGroupID(groupID string) { c.helpCommandGroupID = groupID } -// SetCompletionCommandGroup sets the group id of the completion command. +// SetCompletionCommandGroupID sets the group id of the completion command. func (c *Command) SetCompletionCommandGroupID(groupID string) { // completionCommandGroupID is used if no completion command is defined by the user c.Root().completionCommandGroupID = groupID @@ -655,20 +655,44 @@ Loop: // argsMinusFirstX removes only the first x from args. Otherwise, commands that look like // openshift admin policy add-role-to-user admin my-user, lose the admin argument (arg[4]). -func argsMinusFirstX(args []string, x string) []string { - for i, y := range args { - if x == y { - ret := []string{} - ret = append(ret, args[:i]...) - ret = append(ret, args[i+1:]...) - return ret +// Special care needs to be taken not to remove a flag value. +func (c *Command) argsMinusFirstX(args []string, x string) []string { + if len(args) == 0 { + return args + } + c.mergePersistentFlags() + flags := c.Flags() + +Loop: + for pos := 0; pos < len(args); pos++ { + s := args[pos] + switch { + case s == "--": + // -- means we have reached the end of the parseable args. Break out of the loop now. + break Loop + case strings.HasPrefix(s, "--") && !strings.Contains(s, "=") && !hasNoOptDefVal(s[2:], flags): + fallthrough + case strings.HasPrefix(s, "-") && !strings.Contains(s, "=") && len(s) == 2 && !shortHasNoOptDefVal(s[1:], flags): + // This is a flag without a default value, and an equal sign is not used. Increment pos in order to skip + // over the next arg, because that is the value of this flag. + pos++ + continue + case !strings.HasPrefix(s, "-"): + // This is not a flag or a flag value. Check to see if it matches what we're looking for, and if so, + // return the args, excluding the one at this position. + if s == x { + ret := []string{} + ret = append(ret, args[:pos]...) + ret = append(ret, args[pos+1:]...) + return ret + } } } return args } func isFlagArg(arg string) bool { - return ((len(arg) >= 3 && arg[1] == '-') || + return ((len(arg) >= 3 && arg[0:2] == "--") || (len(arg) >= 2 && arg[0] == '-' && arg[1] != '-')) } @@ -686,7 +710,7 @@ func (c *Command) Find(args []string) (*Command, []string, error) { cmd := c.findNext(nextSubCmd) if cmd != nil { - return innerfind(cmd, argsMinusFirstX(innerArgs, nextSubCmd)) + return innerfind(cmd, c.argsMinusFirstX(innerArgs, nextSubCmd)) } return c, innerArgs } @@ -1272,7 +1296,7 @@ func (c *Command) AllChildCommandsHaveGroup() bool { return true } -// ContainGroups return if groupID exists in the list of command groups. +// ContainsGroup return if groupID exists in the list of command groups. func (c *Command) ContainsGroup(groupID string) bool { for _, x := range c.commandgroups { if x.ID == groupID { diff --git a/vendor/github.com/spf13/cobra/command_notwin.go b/vendor/github.com/spf13/cobra/command_notwin.go index 2b77f8f019..307f0c127f 100644 --- a/vendor/github.com/spf13/cobra/command_notwin.go +++ b/vendor/github.com/spf13/cobra/command_notwin.go @@ -1,4 +1,4 @@ -// Copyright 2013-2022 The Cobra Authors +// Copyright 2013-2023 The Cobra Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/vendor/github.com/spf13/cobra/command_win.go b/vendor/github.com/spf13/cobra/command_win.go index 520f23abf0..adbef395c2 100644 --- a/vendor/github.com/spf13/cobra/command_win.go +++ b/vendor/github.com/spf13/cobra/command_win.go @@ -1,4 +1,4 @@ -// Copyright 2013-2022 The Cobra Authors +// Copyright 2013-2023 The Cobra Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/vendor/github.com/spf13/cobra/completions.go b/vendor/github.com/spf13/cobra/completions.go index e8a0206db1..ee38c4d0b8 100644 --- a/vendor/github.com/spf13/cobra/completions.go +++ b/vendor/github.com/spf13/cobra/completions.go @@ -1,4 +1,4 @@ -// Copyright 2013-2022 The Cobra Authors +// Copyright 2013-2023 The Cobra Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -77,6 +77,10 @@ const ( // obtain the same behavior but only for flags. ShellCompDirectiveFilterDirs + // ShellCompDirectiveKeepOrder indicates that the shell should preserve the order + // in which the completions are provided + ShellCompDirectiveKeepOrder + // =========================================================================== // All directives using iota should be above this one. @@ -159,6 +163,9 @@ func (d ShellCompDirective) string() string { if d&ShellCompDirectiveFilterDirs != 0 { directives = append(directives, "ShellCompDirectiveFilterDirs") } + if d&ShellCompDirectiveKeepOrder != 0 { + directives = append(directives, "ShellCompDirectiveKeepOrder") + } if len(directives) == 0 { directives = append(directives, "ShellCompDirectiveDefault") } @@ -169,7 +176,7 @@ func (d ShellCompDirective) string() string { return strings.Join(directives, ", ") } -// Adds a special hidden command that can be used to request custom completions. +// initCompleteCmd adds a special hidden command that can be used to request custom completions. func (c *Command) initCompleteCmd(args []string) { completeCmd := &Command{ Use: fmt.Sprintf("%s [command-line]", ShellCompRequestCmd), @@ -727,7 +734,7 @@ to enable it. You can execute the following once: To load completions in your current shell session: - source <(%[1]s completion zsh); compdef _%[1]s %[1]s + source <(%[1]s completion zsh) To load completions for every new session, execute once: diff --git a/vendor/github.com/spf13/cobra/fish_completions.go b/vendor/github.com/spf13/cobra/fish_completions.go index 97112a17b2..12ca0d2b11 100644 --- a/vendor/github.com/spf13/cobra/fish_completions.go +++ b/vendor/github.com/spf13/cobra/fish_completions.go @@ -1,4 +1,4 @@ -// Copyright 2013-2022 The Cobra Authors +// Copyright 2013-2023 The Cobra Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -53,7 +53,7 @@ function __%[1]s_perform_completion __%[1]s_debug "last arg: $lastArg" # Disable ActiveHelp which is not supported for fish shell - set -l requestComp "%[9]s=0 $args[1] %[3]s $args[2..-1] $lastArg" + set -l requestComp "%[10]s=0 $args[1] %[3]s $args[2..-1] $lastArg" __%[1]s_debug "Calling $requestComp" set -l results (eval $requestComp 2> /dev/null) @@ -89,6 +89,60 @@ function __%[1]s_perform_completion printf "%%s\n" "$directiveLine" end +# this function limits calls to __%[1]s_perform_completion, by caching the result behind $__%[1]s_perform_completion_once_result +function __%[1]s_perform_completion_once + __%[1]s_debug "Starting __%[1]s_perform_completion_once" + + if test -n "$__%[1]s_perform_completion_once_result" + __%[1]s_debug "Seems like a valid result already exists, skipping __%[1]s_perform_completion" + return 0 + end + + set --global __%[1]s_perform_completion_once_result (__%[1]s_perform_completion) + if test -z "$__%[1]s_perform_completion_once_result" + __%[1]s_debug "No completions, probably due to a failure" + return 1 + end + + __%[1]s_debug "Performed completions and set __%[1]s_perform_completion_once_result" + return 0 +end + +# this function is used to clear the $__%[1]s_perform_completion_once_result variable after completions are run +function __%[1]s_clear_perform_completion_once_result + __%[1]s_debug "" + __%[1]s_debug "========= clearing previously set __%[1]s_perform_completion_once_result variable ==========" + set --erase __%[1]s_perform_completion_once_result + __%[1]s_debug "Succesfully erased the variable __%[1]s_perform_completion_once_result" +end + +function __%[1]s_requires_order_preservation + __%[1]s_debug "" + __%[1]s_debug "========= checking if order preservation is required ==========" + + __%[1]s_perform_completion_once + if test -z "$__%[1]s_perform_completion_once_result" + __%[1]s_debug "Error determining if order preservation is required" + return 1 + end + + set -l directive (string sub --start 2 $__%[1]s_perform_completion_once_result[-1]) + __%[1]s_debug "Directive is: $directive" + + set -l shellCompDirectiveKeepOrder %[9]d + set -l keeporder (math (math --scale 0 $directive / $shellCompDirectiveKeepOrder) %% 2) + __%[1]s_debug "Keeporder is: $keeporder" + + if test $keeporder -ne 0 + __%[1]s_debug "This does require order preservation" + return 0 + end + + __%[1]s_debug "This doesn't require order preservation" + return 1 +end + + # This function does two things: # - Obtain the completions and store them in the global __%[1]s_comp_results # - Return false if file completion should be performed @@ -99,17 +153,17 @@ function __%[1]s_prepare_completions # Start fresh set --erase __%[1]s_comp_results - set -l results (__%[1]s_perform_completion) - __%[1]s_debug "Completion results: $results" + __%[1]s_perform_completion_once + __%[1]s_debug "Completion results: $__%[1]s_perform_completion_once_result" - if test -z "$results" + if test -z "$__%[1]s_perform_completion_once_result" __%[1]s_debug "No completion, probably due to a failure" # Might as well do file completion, in case it helps return 1 end - set -l directive (string sub --start 2 $results[-1]) - set --global __%[1]s_comp_results $results[1..-2] + set -l directive (string sub --start 2 $__%[1]s_perform_completion_once_result[-1]) + set --global __%[1]s_comp_results $__%[1]s_perform_completion_once_result[1..-2] __%[1]s_debug "Completions are: $__%[1]s_comp_results" __%[1]s_debug "Directive is: $directive" @@ -205,13 +259,17 @@ end # Remove any pre-existing completions for the program since we will be handling all of them. complete -c %[2]s -e +# this will get called after the two calls below and clear the $__%[1]s_perform_completion_once_result global +complete -c %[2]s -n '__%[1]s_clear_perform_completion_once_result' # The call to __%[1]s_prepare_completions will setup __%[1]s_comp_results # which provides the program's completion choices. -complete -c %[2]s -n '__%[1]s_prepare_completions' -f -a '$__%[1]s_comp_results' - +# If this doesn't require order preservation, we don't use the -k flag +complete -c %[2]s -n 'not __%[1]s_requires_order_preservation && __%[1]s_prepare_completions' -f -a '$__%[1]s_comp_results' +# otherwise we use the -k flag +complete -k -c %[2]s -n '__%[1]s_requires_order_preservation && __%[1]s_prepare_completions' -f -a '$__%[1]s_comp_results' `, nameForVar, name, compCmd, ShellCompDirectiveError, ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp, - ShellCompDirectiveFilterFileExt, ShellCompDirectiveFilterDirs, activeHelpEnvVar(name))) + ShellCompDirectiveFilterFileExt, ShellCompDirectiveFilterDirs, ShellCompDirectiveKeepOrder, activeHelpEnvVar(name))) } // GenFishCompletion generates fish completion file and writes to the passed writer. diff --git a/vendor/github.com/spf13/cobra/flag_groups.go b/vendor/github.com/spf13/cobra/flag_groups.go index 9c377aaf9c..b35fde1554 100644 --- a/vendor/github.com/spf13/cobra/flag_groups.go +++ b/vendor/github.com/spf13/cobra/flag_groups.go @@ -1,4 +1,4 @@ -// Copyright 2013-2022 The Cobra Authors +// Copyright 2013-2023 The Cobra Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/vendor/github.com/spf13/cobra/powershell_completions.go b/vendor/github.com/spf13/cobra/powershell_completions.go index 004de42e41..177d2755f2 100644 --- a/vendor/github.com/spf13/cobra/powershell_completions.go +++ b/vendor/github.com/spf13/cobra/powershell_completions.go @@ -1,4 +1,4 @@ -// Copyright 2013-2022 The Cobra Authors +// Copyright 2013-2023 The Cobra Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -77,6 +77,7 @@ filter __%[1]s_escapeStringWithSpecialChars { $ShellCompDirectiveNoFileComp=%[6]d $ShellCompDirectiveFilterFileExt=%[7]d $ShellCompDirectiveFilterDirs=%[8]d + $ShellCompDirectiveKeepOrder=%[9]d # Prepare the command to request completions for the program. # Split the command at the first space to separate the program and arguments. @@ -106,13 +107,22 @@ filter __%[1]s_escapeStringWithSpecialChars { # If the last parameter is complete (there is a space following it) # We add an extra empty parameter so we can indicate this to the go method. __%[1]s_debug "Adding extra empty parameter" -`+" # We need to use `\"`\" to pass an empty argument a \"\" or '' does not work!!!"+` -`+" $RequestComp=\"$RequestComp\" + ' `\"`\"'"+` + # PowerShell 7.2+ changed the way how the arguments are passed to executables, + # so for pre-7.2 or when Legacy argument passing is enabled we need to use +`+" # `\"`\" to pass an empty argument, a \"\" or '' does not work!!!"+` + if ($PSVersionTable.PsVersion -lt [version]'7.2.0' -or + ($PSVersionTable.PsVersion -lt [version]'7.3.0' -and -not [ExperimentalFeature]::IsEnabled("PSNativeCommandArgumentPassing")) -or + (($PSVersionTable.PsVersion -ge [version]'7.3.0' -or [ExperimentalFeature]::IsEnabled("PSNativeCommandArgumentPassing")) -and + $PSNativeCommandArgumentPassing -eq 'Legacy')) { +`+" $RequestComp=\"$RequestComp\" + ' `\"`\"'"+` + } else { + $RequestComp="$RequestComp" + ' ""' + } } __%[1]s_debug "Calling $RequestComp" # First disable ActiveHelp which is not supported for Powershell - $env:%[9]s=0 + $env:%[10]s=0 #call the command store the output in $out and redirect stderr and stdout to null # $Out is an array contains each line per element @@ -137,7 +147,7 @@ filter __%[1]s_escapeStringWithSpecialChars { } $Longest = 0 - $Values = $Out | ForEach-Object { + [Array]$Values = $Out | ForEach-Object { #Split the output in name and description `+" $Name, $Description = $_.Split(\"`t\",2)"+` __%[1]s_debug "Name: $Name Description: $Description" @@ -182,6 +192,11 @@ filter __%[1]s_escapeStringWithSpecialChars { } } + # we sort the values in ascending order by name if keep order isn't passed + if (($Directive -band $ShellCompDirectiveKeepOrder) -eq 0 ) { + $Values = $Values | Sort-Object -Property Name + } + if (($Directive -band $ShellCompDirectiveNoFileComp) -ne 0 ) { __%[1]s_debug "ShellCompDirectiveNoFileComp is called" @@ -267,7 +282,7 @@ filter __%[1]s_escapeStringWithSpecialChars { Register-ArgumentCompleter -CommandName '%[1]s' -ScriptBlock $__%[2]sCompleterBlock `, name, nameForVar, compCmd, ShellCompDirectiveError, ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp, - ShellCompDirectiveFilterFileExt, ShellCompDirectiveFilterDirs, activeHelpEnvVar(name))) + ShellCompDirectiveFilterFileExt, ShellCompDirectiveFilterDirs, ShellCompDirectiveKeepOrder, activeHelpEnvVar(name))) } func (c *Command) genPowerShellCompletion(w io.Writer, includeDesc bool) error { diff --git a/vendor/github.com/spf13/cobra/projects_using_cobra.md b/vendor/github.com/spf13/cobra/projects_using_cobra.md index 6865f88e79..8a291eb20e 100644 --- a/vendor/github.com/spf13/cobra/projects_using_cobra.md +++ b/vendor/github.com/spf13/cobra/projects_using_cobra.md @@ -1,11 +1,13 @@ ## Projects using Cobra - [Allero](https://github.com/allero-io/allero) +- [Arewefastyet](https://benchmark.vitess.io) - [Arduino CLI](https://github.com/arduino/arduino-cli) - [Bleve](https://blevesearch.com/) - [Cilium](https://cilium.io/) - [CloudQuery](https://github.com/cloudquery/cloudquery) - [CockroachDB](https://www.cockroachlabs.com/) +- [Constellation](https://github.com/edgelesssys/constellation) - [Cosmos SDK](https://github.com/cosmos/cosmos-sdk) - [Datree](https://github.com/datreeio/datree) - [Delve](https://github.com/derekparker/delve) @@ -25,7 +27,7 @@ - [Istio](https://istio.io) - [Kool](https://github.com/kool-dev/kool) - [Kubernetes](https://kubernetes.io/) -- [Kubescape](https://github.com/armosec/kubescape) +- [Kubescape](https://github.com/kubescape/kubescape) - [KubeVirt](https://github.com/kubevirt/kubevirt) - [Linkerd](https://linkerd.io/) - [Mattermost-server](https://github.com/mattermost/mattermost-server) @@ -51,10 +53,12 @@ - [Random](https://github.com/erdaltsksn/random) - [Rclone](https://rclone.org/) - [Scaleway CLI](https://github.com/scaleway/scaleway-cli) +- [Sia](https://github.com/SiaFoundation/siad) - [Skaffold](https://skaffold.dev/) - [Tendermint](https://github.com/tendermint/tendermint) - [Twitch CLI](https://github.com/twitchdev/twitch-cli) - [UpCloud CLI (`upctl`)](https://github.com/UpCloudLtd/upcloud-cli) +- [Vitess](https://vitess.io) - VMware's [Tanzu Community Edition](https://github.com/vmware-tanzu/community-edition) & [Tanzu Framework](https://github.com/vmware-tanzu/tanzu-framework) - [Werf](https://werf.io/) - [ZITADEL](https://github.com/zitadel/zitadel) diff --git a/vendor/github.com/spf13/cobra/shell_completions.go b/vendor/github.com/spf13/cobra/shell_completions.go index 126e83c307..b035742d39 100644 --- a/vendor/github.com/spf13/cobra/shell_completions.go +++ b/vendor/github.com/spf13/cobra/shell_completions.go @@ -1,4 +1,4 @@ -// Copyright 2013-2022 The Cobra Authors +// Copyright 2013-2023 The Cobra Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/vendor/github.com/spf13/cobra/shell_completions.md b/vendor/github.com/spf13/cobra/shell_completions.md index 553ee5df8a..065c0621d4 100644 --- a/vendor/github.com/spf13/cobra/shell_completions.md +++ b/vendor/github.com/spf13/cobra/shell_completions.md @@ -71,7 +71,7 @@ PowerShell: `,cmd.Root().Name()), DisableFlagsInUseLine: true, ValidArgs: []string{"bash", "zsh", "fish", "powershell"}, - Args: cobra.ExactValidArgs(1), + Args: cobra.MatchAll(cobra.ExactArgs(1), cobra.OnlyValidArgs), Run: func(cmd *cobra.Command, args []string) { switch args[0] { case "bash": @@ -162,16 +162,7 @@ cmd := &cobra.Command{ } ``` -The aliases are not shown to the user on tab completion, but they are accepted as valid nouns by -the completion algorithm if entered manually, e.g. in: - -```bash -$ kubectl get rc [tab][tab] -backend frontend database -``` - -Note that without declaring `rc` as an alias, the completion algorithm would not know to show the list of -replication controllers following `rc`. +The aliases are shown to the user on tab completion only if no completions were found within sub-commands or `ValidArgs`. ### Dynamic completion of nouns @@ -237,6 +228,10 @@ ShellCompDirectiveFilterFileExt // return []string{"themes"}, ShellCompDirectiveFilterDirs // ShellCompDirectiveFilterDirs + +// ShellCompDirectiveKeepOrder indicates that the shell should preserve the order +// in which the completions are provided +ShellCompDirectiveKeepOrder ``` ***Note***: When using the `ValidArgsFunction`, Cobra will call your registered function after having parsed all flags and arguments provided in the command-line. You therefore don't need to do this parsing yourself. For example, when a user calls `helm status --namespace my-rook-ns [tab][tab]`, Cobra will call your registered `ValidArgsFunction` after having parsed the `--namespace` flag, as it would have done when calling the `RunE` function. @@ -385,6 +380,19 @@ or ```go ValidArgs: []string{"bash\tCompletions for bash", "zsh\tCompletions for zsh"} ``` + +If you don't want to show descriptions in the completions, you can add `--no-descriptions` to the default `completion` command to disable them, like: + +```bash +$ source <(helm completion bash) +$ helm completion [tab][tab] +bash (generate autocompletion script for bash) powershell (generate autocompletion script for powershell) +fish (generate autocompletion script for fish) zsh (generate autocompletion script for zsh) + +$ source <(helm completion bash --no-descriptions) +$ helm completion [tab][tab] +bash fish powershell zsh +``` ## Bash completions ### Dependencies diff --git a/vendor/github.com/spf13/cobra/user_guide.md b/vendor/github.com/spf13/cobra/user_guide.md index e55367e853..85201d840c 100644 --- a/vendor/github.com/spf13/cobra/user_guide.md +++ b/vendor/github.com/spf13/cobra/user_guide.md @@ -188,6 +188,37 @@ var versionCmd = &cobra.Command{ } ``` +### Organizing subcommands + +A command may have subcommands which in turn may have other subcommands. This is achieved by using +`AddCommand`. In some cases, especially in larger applications, each subcommand may be defined in +its own go package. + +The suggested approach is for the parent command to use `AddCommand` to add its most immediate +subcommands. For example, consider the following directory structure: + +```text +├── cmd +│   ├── root.go +│   └── sub1 +│   ├── sub1.go +│   └── sub2 +│   ├── leafA.go +│   ├── leafB.go +│   └── sub2.go +└── main.go +``` + +In this case: + +* The `init` function of `root.go` adds the command defined in `sub1.go` to the root command. +* The `init` function of `sub1.go` adds the command defined in `sub2.go` to the sub1 command. +* The `init` function of `sub2.go` adds the commands defined in `leafA.go` and `leafB.go` to the + sub2 command. + +This approach ensures the subcommands are always included at compile time while avoiding cyclic +references. + ### Returning and handling errors If you wish to return an error to the caller of a command, `RunE` can be used. @@ -313,8 +344,8 @@ rootCmd.MarkFlagsRequiredTogether("username", "password") You can also prevent different flags from being provided together if they represent mutually exclusive options such as specifying an output format as either `--json` or `--yaml` but never both: ```go -rootCmd.Flags().BoolVar(&u, "json", false, "Output in JSON") -rootCmd.Flags().BoolVar(&pw, "yaml", false, "Output in YAML") +rootCmd.Flags().BoolVar(&ofJson, "json", false, "Output in JSON") +rootCmd.Flags().BoolVar(&ofYaml, "yaml", false, "Output in YAML") rootCmd.MarkFlagsMutuallyExclusive("json", "yaml") ``` @@ -349,7 +380,7 @@ shown below: ```go var cmd = &cobra.Command{ Short: "hello", - Args: MatchAll(ExactArgs(2), OnlyValidArgs), + Args: cobra.MatchAll(cobra.ExactArgs(2), cobra.OnlyValidArgs), Run: func(cmd *cobra.Command, args []string) { fmt.Println("Hello, World!") }, diff --git a/vendor/github.com/spf13/cobra/zsh_completions.go b/vendor/github.com/spf13/cobra/zsh_completions.go index 84cec76fde..1856e4c7f6 100644 --- a/vendor/github.com/spf13/cobra/zsh_completions.go +++ b/vendor/github.com/spf13/cobra/zsh_completions.go @@ -1,4 +1,4 @@ -// Copyright 2013-2022 The Cobra Authors +// Copyright 2013-2023 The Cobra Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -90,6 +90,7 @@ func genZshComp(buf io.StringWriter, name string, includeDesc bool) { compCmd = ShellCompNoDescRequestCmd } WriteStringAndCheck(buf, fmt.Sprintf(`#compdef %[1]s +compdef _%[1]s %[1]s # zsh completion for %-36[1]s -*- shell-script -*- @@ -108,8 +109,9 @@ _%[1]s() local shellCompDirectiveNoFileComp=%[5]d local shellCompDirectiveFilterFileExt=%[6]d local shellCompDirectiveFilterDirs=%[7]d + local shellCompDirectiveKeepOrder=%[8]d - local lastParam lastChar flagPrefix requestComp out directive comp lastComp noSpace + local lastParam lastChar flagPrefix requestComp out directive comp lastComp noSpace keepOrder local -a completions __%[1]s_debug "\n========= starting completion logic ==========" @@ -177,7 +179,7 @@ _%[1]s() return fi - local activeHelpMarker="%[8]s" + local activeHelpMarker="%[9]s" local endIndex=${#activeHelpMarker} local startIndex=$((${#activeHelpMarker}+1)) local hasActiveHelp=0 @@ -227,6 +229,11 @@ _%[1]s() noSpace="-S ''" fi + if [ $((directive & shellCompDirectiveKeepOrder)) -ne 0 ]; then + __%[1]s_debug "Activating keep order." + keepOrder="-V" + fi + if [ $((directive & shellCompDirectiveFilterFileExt)) -ne 0 ]; then # File extension filtering local filteringCmd @@ -262,7 +269,7 @@ _%[1]s() return $result else __%[1]s_debug "Calling _describe" - if eval _describe "completions" completions $flagPrefix $noSpace; then + if eval _describe $keepOrder "completions" completions $flagPrefix $noSpace; then __%[1]s_debug "_describe found some completions" # Return the success of having called _describe @@ -296,6 +303,6 @@ if [ "$funcstack[1]" = "_%[1]s" ]; then fi `, name, compCmd, ShellCompDirectiveError, ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp, - ShellCompDirectiveFilterFileExt, ShellCompDirectiveFilterDirs, + ShellCompDirectiveFilterFileExt, ShellCompDirectiveFilterDirs, ShellCompDirectiveKeepOrder, activeHelpMarker)) } diff --git a/vendor/modules.txt b/vendor/modules.txt index 83e447f09b..e23d109515 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -55,8 +55,8 @@ github.com/evanphx/json-patch # github.com/evanphx/json-patch/v5 v5.6.0 ## explicit; go 1.12 github.com/evanphx/json-patch/v5 -# github.com/fatih/color v1.13.0 -## explicit; go 1.13 +# github.com/fatih/color v1.15.0 +## explicit; go 1.17 github.com/fatih/color # github.com/felixge/httpsnoop v1.0.3 ## explicit; go 1.13 @@ -85,8 +85,8 @@ github.com/go-openapi/jsonreference/internal # github.com/go-openapi/swag v0.22.3 ## explicit; go 1.18 github.com/go-openapi/swag -# github.com/gobuffalo/flect v0.2.3 -## explicit; go 1.13 +# github.com/gobuffalo/flect v1.0.2 +## explicit; go 1.16 github.com/gobuffalo/flect # github.com/gogo/protobuf v1.3.2 ## explicit; go 1.15 @@ -183,7 +183,7 @@ github.com/hashicorp/go-version # github.com/imdario/mergo v0.3.12 ## explicit; go 1.13 github.com/imdario/mergo -# github.com/inconshreveable/mousetrap v1.0.1 +# github.com/inconshreveable/mousetrap v1.1.0 ## explicit; go 1.18 github.com/inconshreveable/mousetrap # github.com/josharian/intern v1.0.0 @@ -200,8 +200,8 @@ github.com/k14s/semver/v4 github.com/mailru/easyjson/buffer github.com/mailru/easyjson/jlexer github.com/mailru/easyjson/jwriter -# github.com/mattn/go-colorable v0.1.12 -## explicit; go 1.13 +# github.com/mattn/go-colorable v0.1.13 +## explicit; go 1.15 github.com/mattn/go-colorable # github.com/mattn/go-isatty v0.0.17 ## explicit; go 1.15 @@ -248,7 +248,7 @@ github.com/prometheus/common/model github.com/prometheus/procfs github.com/prometheus/procfs/internal/fs github.com/prometheus/procfs/internal/util -# github.com/spf13/cobra v1.6.1 +# github.com/spf13/cobra v1.7.0 ## explicit; go 1.15 github.com/spf13/cobra # github.com/spf13/pflag v1.0.5 @@ -1324,8 +1324,8 @@ sigs.k8s.io/controller-runtime/pkg/source sigs.k8s.io/controller-runtime/pkg/webhook sigs.k8s.io/controller-runtime/pkg/webhook/admission sigs.k8s.io/controller-runtime/pkg/webhook/internal/metrics -# sigs.k8s.io/controller-tools v0.7.0 -## explicit; go 1.16 +# sigs.k8s.io/controller-tools v0.12.1 +## explicit; go 1.20 sigs.k8s.io/controller-tools/cmd/controller-gen sigs.k8s.io/controller-tools/pkg/crd sigs.k8s.io/controller-tools/pkg/crd/markers diff --git a/vendor/sigs.k8s.io/controller-tools/cmd/controller-gen/main.go b/vendor/sigs.k8s.io/controller-tools/cmd/controller-gen/main.go index 692b26c8da..c27bcda42c 100644 --- a/vendor/sigs.k8s.io/controller-tools/cmd/controller-gen/main.go +++ b/vendor/sigs.k8s.io/controller-tools/cmd/controller-gen/main.go @@ -5,7 +5,7 @@ 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 + 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, diff --git a/vendor/sigs.k8s.io/controller-tools/pkg/crd/doc.go b/vendor/sigs.k8s.io/controller-tools/pkg/crd/doc.go index fd48e44aec..914af94d91 100644 --- a/vendor/sigs.k8s.io/controller-tools/pkg/crd/doc.go +++ b/vendor/sigs.k8s.io/controller-tools/pkg/crd/doc.go @@ -17,14 +17,14 @@ limitations under the License. // Package crd contains utilities for generating CustomResourceDefinitions and // their corresponding OpenAPI validation schemata. // -// Markers +// # Markers // // Markers live under the markers subpackage. Two types of markers exist: // those that modify schema generation (for validation), and those that modify // the rest of the CRD. See the subpackage for more information and all // supported markers. // -// Collecting Types and Generating CRDs +// # Collecting Types and Generating CRDs // // The Parser is the entrypoint for collecting the information required to // generate CRDs. Like loader and collector, its methods are idemptotent, not @@ -40,13 +40,13 @@ limitations under the License. // Errors are generally attached directly to the relevant Package with // AddError. // -// Known Packages +// # Known Packages // // There are a few types from Kubernetes that have special meaning, but don't // have validation markers attached. Those specific types have overrides // listed in KnownPackages that can be added as overrides to any parser. // -// Flattening +// # Flattening // // Once schemata are generated, they can be used directly by external tooling // (like JSONSchema validators), but must first be "flattened" to not contain diff --git a/vendor/sigs.k8s.io/controller-tools/pkg/crd/flatten.go b/vendor/sigs.k8s.io/controller-tools/pkg/crd/flatten.go index 00f4dc4c7d..9224c26b27 100644 --- a/vendor/sigs.k8s.io/controller-tools/pkg/crd/flatten.go +++ b/vendor/sigs.k8s.io/controller-tools/pkg/crd/flatten.go @@ -143,6 +143,10 @@ func flattenAllOfInto(dst *apiext.JSONSchemaProps, src apiext.JSONSchemaProps, e dstProps.Schema = &apiext.JSONSchemaProps{} } flattenAllOfInto(dstProps.Schema, *srcProps.Schema, errRec) + case "XPreserveUnknownFields": + dstField.Set(srcField) + case "XMapType": + dstField.Set(srcField) // NB(directxman12): no need to explicitly handle nullable -- false is considered to be the zero value // TODO(directxman12): src isn't necessarily the field value -- it's just the most recent allOf entry default: diff --git a/vendor/sigs.k8s.io/controller-tools/pkg/crd/gen.go b/vendor/sigs.k8s.io/controller-tools/pkg/crd/gen.go index 9959874624..546ba9a6d7 100644 --- a/vendor/sigs.k8s.io/controller-tools/pkg/crd/gen.go +++ b/vendor/sigs.k8s.io/controller-tools/pkg/crd/gen.go @@ -20,6 +20,8 @@ import ( "fmt" "go/ast" "go/types" + "sort" + "strings" apiext "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" "k8s.io/apimachinery/pkg/runtime/schema" @@ -41,6 +43,11 @@ const defaultVersion = v1 // Generator generates CustomResourceDefinition objects. type Generator struct { + // IgnoreUnexportedFields indicates that we should skip unexported fields. + // + // Left unspecified, the default is false. + IgnoreUnexportedFields *bool `marker:",optional"` + // AllowDangerousTypes allows types which are usually omitted from CRD generation // because they are not recommended. // @@ -72,6 +79,12 @@ type Generator struct { // GenerateEmbeddedObjectMeta specifies if any embedded ObjectMeta in the CRD should be generated GenerateEmbeddedObjectMeta *bool `marker:",optional"` + + // HeaderFile specifies the header text (e.g. license) to prepend to generated files. + HeaderFile string `marker:",optional"` + + // Year specifies the year to substitute for " YEAR" in the header file. + Year string `marker:",optional"` } func (Generator) CheckFilter() loader.NodeFilter { @@ -80,12 +93,20 @@ func (Generator) CheckFilter() loader.NodeFilter { func (Generator) RegisterMarkers(into *markers.Registry) error { return crdmarkers.Register(into) } + +// transformRemoveCRDStatus ensures we do not write the CRD status field. +func transformRemoveCRDStatus(obj map[string]interface{}) error { + delete(obj, "status") + return nil +} + func (g Generator) Generate(ctx *genall.GenerationContext) error { parser := &Parser{ Collector: ctx.Collector, Checker: ctx.Checker, // Perform defaulting here to avoid ambiguity later - AllowDangerousTypes: g.AllowDangerousTypes != nil && *g.AllowDangerousTypes == true, + IgnoreUnexportedFields: g.IgnoreUnexportedFields != nil && *g.IgnoreUnexportedFields == true, + AllowDangerousTypes: g.AllowDangerousTypes != nil && *g.AllowDangerousTypes == true, // Indicates the parser on whether to register the ObjectMeta type or not GenerateEmbeddedObjectMeta: g.GenerateEmbeddedObjectMeta != nil && *g.GenerateEmbeddedObjectMeta == true, } @@ -114,7 +135,18 @@ func (g Generator) Generate(ctx *genall.GenerationContext) error { crdVersions = []string{defaultVersion} } - for groupKind := range kubeKinds { + var headerText string + + if g.HeaderFile != "" { + headerBytes, err := ctx.ReadFile(g.HeaderFile) + if err != nil { + return err + } + headerText = string(headerBytes) + } + headerText = strings.ReplaceAll(headerText, " YEAR", " "+g.Year) + + for _, groupKind := range kubeKinds { parser.NeedCRDFor(groupKind, g.MaxDescLen) crdRaw := parser.CustomResourceDefinitions[groupKind] addAttribution(&crdRaw) @@ -139,7 +171,7 @@ func (g Generator) Generate(ctx *genall.GenerationContext) error { } else { fileName = fmt.Sprintf("%s_%s.%s.yaml", crdRaw.Spec.Group, crdRaw.Spec.Names.Plural, crdVersions[i]) } - if err := ctx.WriteYAML(fileName, crd); err != nil { + if err := ctx.WriteYAML(fileName, headerText, []interface{}{crd}, genall.WithTransform(transformRemoveCRDStatus), genall.WithTransform(genall.TransformRemoveCreationTimestamp)); err != nil { return err } } @@ -203,7 +235,7 @@ func FindMetav1(roots []*loader.Package) *loader.Package { // FindKubeKinds locates all types that contain TypeMeta and ObjectMeta // (and thus may be a Kubernetes object), and returns the corresponding // group-kinds. -func FindKubeKinds(parser *Parser, metav1Pkg *loader.Package) map[schema.GroupKind]struct{} { +func FindKubeKinds(parser *Parser, metav1Pkg *loader.Package) []schema.GroupKind { // TODO(directxman12): technically, we should be finding metav1 per-package kubeKinds := map[schema.GroupKind]struct{}{} for typeIdent, info := range parser.Types { @@ -234,7 +266,12 @@ func FindKubeKinds(parser *Parser, metav1Pkg *loader.Package) map[schema.GroupKi } fieldPkgPath := loader.NonVendorPath(namedField.Obj().Pkg().Path()) fieldPkg := pkg.Imports()[fieldPkgPath] - if fieldPkg != metav1Pkg { + + // Compare the metav1 package by ID and not by the actual instance + // of the object. The objects in memory could be different due to + // loading from different root paths, even when they both refer to + // the same metav1 package. + if fieldPkg == nil || fieldPkg.ID != metav1Pkg.ID { continue } @@ -257,7 +294,15 @@ func FindKubeKinds(parser *Parser, metav1Pkg *loader.Package) map[schema.GroupKi kubeKinds[groupKind] = struct{}{} } - return kubeKinds + groupKindList := make([]schema.GroupKind, 0, len(kubeKinds)) + for groupKind := range kubeKinds { + groupKindList = append(groupKindList, groupKind) + } + sort.Slice(groupKindList, func(i, j int) bool { + return groupKindList[i].String() < groupKindList[j].String() + }) + + return groupKindList } // filterTypesForCRDs filters out all nodes that aren't used in CRD generation, diff --git a/vendor/sigs.k8s.io/controller-tools/pkg/crd/known_types.go b/vendor/sigs.k8s.io/controller-tools/pkg/crd/known_types.go index 7e862cfb17..9e8decb286 100644 --- a/vendor/sigs.k8s.io/controller-tools/pkg/crd/known_types.go +++ b/vendor/sigs.k8s.io/controller-tools/pkg/crd/known_types.go @@ -5,7 +5,7 @@ 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 + 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, @@ -74,7 +74,8 @@ var KnownPackages = map[string]PackageOverride{ "k8s.io/apimachinery/pkg/runtime": func(p *Parser, pkg *loader.Package) { p.Schemata[TypeIdent{Name: "RawExtension", Package: pkg}] = apiext.JSONSchemaProps{ // TODO(directxman12): regexp validation for this (or get kube to support it as a format value) - Type: "object", + Type: "object", + XPreserveUnknownFields: boolPtr(true), } p.AddPackage(pkg) // get the rest of the types }, diff --git a/vendor/sigs.k8s.io/controller-tools/pkg/crd/markers/crd.go b/vendor/sigs.k8s.io/controller-tools/pkg/crd/markers/crd.go index 5e99256c12..1b1cf5ede1 100644 --- a/vendor/sigs.k8s.io/controller-tools/pkg/crd/markers/crd.go +++ b/vendor/sigs.k8s.io/controller-tools/pkg/crd/markers/crd.go @@ -18,6 +18,7 @@ package markers import ( "fmt" + "strings" apiext "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" @@ -51,6 +52,9 @@ var CRDMarkers = []*definitionWithHelp{ must(markers.MakeDefinition("kubebuilder:deprecatedversion", markers.DescribesType, DeprecatedVersion{})). WithHelp(DeprecatedVersion{}.Help()), + + must(markers.MakeDefinition("kubebuilder:metadata", markers.DescribesType, Metadata{})). + WithHelp(Metadata{}.Help()), } // TODO: categories and singular used to be annotations types @@ -279,7 +283,7 @@ type Resource struct { Scope string `marker:",optional"` } -func (s Resource) ApplyToCRD(crd *apiext.CustomResourceDefinitionSpec, version string) error { +func (s Resource) ApplyToCRD(crd *apiext.CustomResourceDefinitionSpec, _ string) error { if s.Path != "" { crd.Names.Plural = s.Path } @@ -345,3 +349,42 @@ func (s DeprecatedVersion) ApplyToCRD(crd *apiext.CustomResourceDefinitionSpec, } return nil } + +// +controllertools:marker:generateHelp:category=CRD + +// Metadata configures the additional annotations or labels for this CRD. +// For example adding annotation "api-approved.kubernetes.io" for a CRD with Kubernetes groups, +// or annotation "cert-manager.io/inject-ca-from-secret" for a CRD that needs CA injection. +type Metadata struct { + // Annotations will be added into the annotations of this CRD. + Annotations []string `marker:",optional"` + // Labels will be added into the labels of this CRD. + Labels []string `marker:",optional"` +} + +func (s Metadata) ApplyToCRD(crd *apiext.CustomResourceDefinition, _ string) error { + if len(s.Annotations) > 0 { + if crd.Annotations == nil { + crd.Annotations = map[string]string{} + } + for _, str := range s.Annotations { + kv := strings.SplitN(str, "=", 2) + if len(kv) < 2 { + return fmt.Errorf("annotation %s is not in 'xxx=xxx' format", str) + } + crd.Annotations[kv[0]] = kv[1] + } + } + + if len(s.Labels) > 0 { + if crd.Labels == nil { + crd.Labels = map[string]string{} + } + for _, str := range s.Labels { + kv := strings.SplitN(str, "=", 2) + crd.Labels[kv[0]] = kv[1] + } + } + + return nil +} diff --git a/vendor/sigs.k8s.io/controller-tools/pkg/crd/markers/doc.go b/vendor/sigs.k8s.io/controller-tools/pkg/crd/markers/doc.go index 48736401cf..995af44b37 100644 --- a/vendor/sigs.k8s.io/controller-tools/pkg/crd/markers/doc.go +++ b/vendor/sigs.k8s.io/controller-tools/pkg/crd/markers/doc.go @@ -19,7 +19,7 @@ limitations under the License. // // All markers related to CRD generation live in AllDefinitions. // -// Validation Markers +// # Validation Markers // // Validation markers have values that implement ApplyToSchema // (crd.SchemaMarker). Any marker implementing this will automatically @@ -31,7 +31,7 @@ limitations under the License. // All validation markers start with "+kubebuilder:validation", and // have the same name as their type name. // -// CRD Markers +// # CRD Markers // // Markers that modify anything in the CRD itself *except* for the schema // implement ApplyToCRD (crd.CRDMarker). They are expected to detect whether @@ -39,7 +39,7 @@ limitations under the License. // them), or to the root-level CRD for legacy cases. They are applied *after* // the rest of the CRD is computed. // -// Misc +// # Misc // // This package also defines the "+groupName" and "+versionName" package-level // markers, for defining package<->group-version mappings. diff --git a/vendor/sigs.k8s.io/controller-tools/pkg/crd/markers/topology.go b/vendor/sigs.k8s.io/controller-tools/pkg/crd/markers/topology.go index 0f4a94b180..a92995c802 100644 --- a/vendor/sigs.k8s.io/controller-tools/pkg/crd/markers/topology.go +++ b/vendor/sigs.k8s.io/controller-tools/pkg/crd/markers/topology.go @@ -28,12 +28,20 @@ import ( var TopologyMarkers = []*definitionWithHelp{ must(markers.MakeDefinition("listMapKey", markers.DescribesField, ListMapKey(""))). WithHelp(ListMapKey("").Help()), + must(markers.MakeDefinition("listMapKey", markers.DescribesType, ListMapKey(""))). + WithHelp(ListMapKey("").Help()), must(markers.MakeDefinition("listType", markers.DescribesField, ListType(""))). WithHelp(ListType("").Help()), + must(markers.MakeDefinition("listType", markers.DescribesType, ListType(""))). + WithHelp(ListType("").Help()), must(markers.MakeDefinition("mapType", markers.DescribesField, MapType(""))). WithHelp(MapType("").Help()), + must(markers.MakeDefinition("mapType", markers.DescribesType, MapType(""))). + WithHelp(MapType("").Help()), must(markers.MakeDefinition("structType", markers.DescribesField, StructType(""))). WithHelp(StructType("").Help()), + must(markers.MakeDefinition("structType", markers.DescribesType, StructType(""))). + WithHelp(StructType("").Help()), } func init() { @@ -47,15 +55,15 @@ func init() { // // Possible data-structure types of a list are: // -// - "map": it needs to have a key field, which will be used to build an -// associative list. A typical example is a the pod container list, -// which is indexed by the container name. +// - "map": it needs to have a key field, which will be used to build an +// associative list. A typical example is a the pod container list, +// which is indexed by the container name. // -// - "set": Fields need to be "scalar", and there can be only one -// occurrence of each. +// - "set": Fields need to be "scalar", and there can be only one +// occurrence of each. // -// - "atomic": All the fields in the list are treated as a single value, -// are typically manipulated together by the same actor. +// - "atomic": All the fields in the list are treated as a single value, +// are typically manipulated together by the same actor. type ListType string // +controllertools:marker:generateHelp:category="CRD processing" @@ -75,12 +83,12 @@ type ListMapKey string // // Possible values: // -// - "granular": items in the map are independent of each other, -// and can be manipulated by different actors. -// This is the default behavior. +// - "granular": items in the map are independent of each other, +// and can be manipulated by different actors. +// This is the default behavior. // -// - "atomic": all fields are treated as one unit. -// Any changes have to replace the entire map. +// - "atomic": all fields are treated as one unit. +// Any changes have to replace the entire map. type MapType string // +controllertools:marker:generateHelp:category="CRD processing" @@ -91,12 +99,12 @@ type MapType string // // Possible values: // -// - "granular": fields in the struct are independent of each other, -// and can be manipulated by different actors. -// This is the default behavior. +// - "granular": fields in the struct are independent of each other, +// and can be manipulated by different actors. +// This is the default behavior. // -// - "atomic": all fields are treated as one unit. -// Any changes have to replace the entire struct. +// - "atomic": all fields are treated as one unit. +// Any changes have to replace the entire struct. type StructType string func (l ListType) ApplyToSchema(schema *apiext.JSONSchemaProps) error { diff --git a/vendor/sigs.k8s.io/controller-tools/pkg/crd/markers/validation.go b/vendor/sigs.k8s.io/controller-tools/pkg/crd/markers/validation.go index b20ff1623d..80344dd3a9 100644 --- a/vendor/sigs.k8s.io/controller-tools/pkg/crd/markers/validation.go +++ b/vendor/sigs.k8s.io/controller-tools/pkg/crd/markers/validation.go @@ -17,9 +17,9 @@ limitations under the License. package markers import ( - "fmt" - "encoding/json" + "fmt" + "math" apiext "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" @@ -37,7 +37,7 @@ const ( // reusable and writing complex validations on slice items. var ValidationMarkers = mustMakeAllWithPrefix("kubebuilder:validation", markers.DescribesField, - // integer markers + // numeric markers Maximum(0), Minimum(0), @@ -67,6 +67,7 @@ var ValidationMarkers = mustMakeAllWithPrefix("kubebuilder:validation", markers. XPreserveUnknownFields{}, XEmbeddedResource{}, XIntOrString{}, + XValidation{}, ) // FieldOnlyMarkers list field-specific validation markers (i.e. those markers that don't make @@ -85,6 +86,9 @@ var FieldOnlyMarkers = []*definitionWithHelp{ must(markers.MakeAnyTypeDefinition("kubebuilder:default", markers.DescribesField, Default{})). WithHelp(Default{}.Help()), + must(markers.MakeAnyTypeDefinition("kubebuilder:example", markers.DescribesField, Example{})). + WithHelp(Example{}.Help()), + must(markers.MakeDefinition("kubebuilder:validation:EmbeddedResource", markers.DescribesField, XEmbeddedResource{})). WithHelp(XEmbeddedResource{}.Help()), @@ -122,11 +126,19 @@ func init() { // +controllertools:marker:generateHelp:category="CRD validation" // Maximum specifies the maximum numeric value that this field can have. -type Maximum int +type Maximum float64 + +func (m Maximum) Value() float64 { + return float64(m) +} // +controllertools:marker:generateHelp:category="CRD validation" -// Minimum specifies the minimum numeric value that this field can have. Negative integers are supported. -type Minimum int +// Minimum specifies the minimum numeric value that this field can have. Negative numbers are supported. +type Minimum float64 + +func (m Minimum) Value() float64 { + return float64(m) +} // +controllertools:marker:generateHelp:category="CRD validation" // ExclusiveMinimum indicates that the minimum is "up to" but not including that value. @@ -138,7 +150,11 @@ type ExclusiveMaximum bool // +controllertools:marker:generateHelp:category="CRD validation" // MultipleOf specifies that this field must have a numeric value that's a multiple of this one. -type MultipleOf int +type MultipleOf float64 + +func (m MultipleOf) Value() float64 { + return float64(m) +} // +controllertools:marker:generateHelp:category="CRD validation" // MaxLength specifies the maximum length for this string. @@ -157,7 +173,7 @@ type Pattern string type MaxItems int // +controllertools:marker:generateHelp:category="CRD validation" -// MinItems specifies the minimun length for this list. +// MinItems specifies the minimum length for this list. type MinItems int // +controllertools:marker:generateHelp:category="CRD validation" @@ -209,6 +225,19 @@ type Default struct { Value interface{} } +// +controllertools:marker:generateHelp:category="CRD validation" +// Example sets the example value for this field. +// +// An example value will be accepted as any value valid for the +// field. Formatting for common types include: boolean: `true`, string: +// `Cluster`, numerical: `1.24`, array: `{1,2}`, object: `{policy: +// "delete"}`). Examples should be defined in pruned form, and only best-effort +// validation will be performed. Full validation of an example requires +// submission of the containing CRD to an apiserver. +type Example struct { + Value interface{} +} + // +controllertools:marker:generateHelp:category="CRD processing" // PreserveUnknownFields stops the apiserver from pruning fields which are not specified. // @@ -251,41 +280,80 @@ type XIntOrString struct{} // to be used only as a last resort. type Schemaless struct{} +func hasNumericType(schema *apiext.JSONSchemaProps) bool { + return schema.Type == "integer" || schema.Type == "number" +} + +func isIntegral(value float64) bool { + return value == math.Trunc(value) && !math.IsNaN(value) && !math.IsInf(value, 0) +} + +// +controllertools:marker:generateHelp:category="CRD validation" +// XValidation marks a field as requiring a value for which a given +// expression evaluates to true. +// +// This marker may be repeated to specify multiple expressions, all of +// which must evaluate to true. +type XValidation struct { + Rule string + Message string `marker:",optional"` +} + func (m Maximum) ApplyToSchema(schema *apiext.JSONSchemaProps) error { - if schema.Type != "integer" { - return fmt.Errorf("must apply maximum to an integer") + if !hasNumericType(schema) { + return fmt.Errorf("must apply maximum to a numeric value, found %s", schema.Type) + } + + if schema.Type == "integer" && !isIntegral(m.Value()) { + return fmt.Errorf("cannot apply non-integral maximum validation (%v) to integer value", m.Value()) } - val := float64(m) + + val := m.Value() schema.Maximum = &val return nil } + func (m Minimum) ApplyToSchema(schema *apiext.JSONSchemaProps) error { - if schema.Type != "integer" { - return fmt.Errorf("must apply minimum to an integer") + if !hasNumericType(schema) { + return fmt.Errorf("must apply minimum to a numeric value, found %s", schema.Type) } - val := float64(m) + + if schema.Type == "integer" && !isIntegral(m.Value()) { + return fmt.Errorf("cannot apply non-integral minimum validation (%v) to integer value", m.Value()) + } + + val := m.Value() schema.Minimum = &val return nil } + func (m ExclusiveMaximum) ApplyToSchema(schema *apiext.JSONSchemaProps) error { - if schema.Type != "integer" { - return fmt.Errorf("must apply exclusivemaximum to an integer") + if !hasNumericType(schema) { + return fmt.Errorf("must apply exclusivemaximum to a numeric value, found %s", schema.Type) } schema.ExclusiveMaximum = bool(m) return nil } + func (m ExclusiveMinimum) ApplyToSchema(schema *apiext.JSONSchemaProps) error { - if schema.Type != "integer" { - return fmt.Errorf("must apply exclusiveminimum to an integer") + if !hasNumericType(schema) { + return fmt.Errorf("must apply exclusiveminimum to a numeric value, found %s", schema.Type) } + schema.ExclusiveMinimum = bool(m) return nil } + func (m MultipleOf) ApplyToSchema(schema *apiext.JSONSchemaProps) error { - if schema.Type != "integer" { - return fmt.Errorf("must apply multipleof to an integer") + if !hasNumericType(schema) { + return fmt.Errorf("must apply multipleof to a numeric value, found %s", schema.Type) } - val := float64(m) + + if schema.Type == "integer" && !isIntegral(m.Value()) { + return fmt.Errorf("cannot apply non-integral multipleof validation (%v) to integer value", m.Value()) + } + + val := m.Value() schema.MultipleOf = &val return nil } @@ -298,6 +366,7 @@ func (m MaxLength) ApplyToSchema(schema *apiext.JSONSchemaProps) error { schema.MaxLength = &val return nil } + func (m MinLength) ApplyToSchema(schema *apiext.JSONSchemaProps) error { if schema.Type != "string" { return fmt.Errorf("must apply minlength to a string") @@ -306,6 +375,7 @@ func (m MinLength) ApplyToSchema(schema *apiext.JSONSchemaProps) error { schema.MinLength = &val return nil } + func (m Pattern) ApplyToSchema(schema *apiext.JSONSchemaProps) error { // Allow string types or IntOrStrings. An IntOrString will still // apply the pattern validation when a string is detected, the pattern @@ -325,6 +395,7 @@ func (m MaxItems) ApplyToSchema(schema *apiext.JSONSchemaProps) error { schema.MaxItems = &val return nil } + func (m MinItems) ApplyToSchema(schema *apiext.JSONSchemaProps) error { if schema.Type != "array" { return fmt.Errorf("must apply minitems to an array") @@ -333,6 +404,7 @@ func (m MinItems) ApplyToSchema(schema *apiext.JSONSchemaProps) error { schema.MinItems = &val return nil } + func (m UniqueItems) ApplyToSchema(schema *apiext.JSONSchemaProps) error { if schema.Type != "array" { return fmt.Errorf("must apply uniqueitems to an array") @@ -376,6 +448,7 @@ func (m Enum) ApplyToSchema(schema *apiext.JSONSchemaProps) error { schema.Enum = vals return nil } + func (m Format) ApplyToSchema(schema *apiext.JSONSchemaProps) error { schema.Format = string(m) return nil @@ -408,6 +481,15 @@ func (m Default) ApplyToSchema(schema *apiext.JSONSchemaProps) error { return nil } +func (m Example) ApplyToSchema(schema *apiext.JSONSchemaProps) error { + marshalledExample, err := json.Marshal(m.Value) + if err != nil { + return err + } + schema.Example = &apiext.JSON{Raw: marshalledExample} + return nil +} + func (m XPreserveUnknownFields) ApplyToSchema(schema *apiext.JSONSchemaProps) error { defTrue := true schema.XPreserveUnknownFields = &defTrue @@ -428,3 +510,11 @@ func (m XIntOrString) ApplyToSchema(schema *apiext.JSONSchemaProps) error { } func (m XIntOrString) ApplyFirst() {} + +func (m XValidation) ApplyToSchema(schema *apiext.JSONSchemaProps) error { + schema.XValidations = append(schema.XValidations, apiext.ValidationRule{ + Rule: m.Rule, + Message: m.Message, + }) + return nil +} diff --git a/vendor/sigs.k8s.io/controller-tools/pkg/crd/markers/zz_generated.markerhelp.go b/vendor/sigs.k8s.io/controller-tools/pkg/crd/markers/zz_generated.markerhelp.go index 03e3e44bf0..fbd681aa67 100644 --- a/vendor/sigs.k8s.io/controller-tools/pkg/crd/markers/zz_generated.markerhelp.go +++ b/vendor/sigs.k8s.io/controller-tools/pkg/crd/markers/zz_generated.markerhelp.go @@ -1,3 +1,4 @@ +//go:build !ignore_autogenerated // +build !ignore_autogenerated /* @@ -67,6 +68,22 @@ func (Enum) Help() *markers.DefinitionHelp { } } +func (Example) Help() *markers.DefinitionHelp { + return &markers.DefinitionHelp{ + Category: "CRD validation", + DetailedHelp: markers.DetailedHelp{ + Summary: "sets the example value for this field. ", + Details: "An example value will be accepted as any value valid for the field. Formatting for common types include: boolean: `true`, string: `Cluster`, numerical: `1.24`, array: `{1,2}`, object: `{policy: \"delete\"}`). Examples should be defined in pruned form, and only best-effort validation will be performed. Full validation of an example requires submission of the containing CRD to an apiserver.", + }, + FieldHelp: map[string]markers.DetailedHelp{ + "Value": { + Summary: "", + Details: "", + }, + }, + } +} + func (ExclusiveMaximum) Help() *markers.DefinitionHelp { return &markers.DefinitionHelp{ Category: "CRD validation", @@ -116,7 +133,7 @@ func (ListType) Help() *markers.DefinitionHelp { Category: "CRD processing", DetailedHelp: markers.DetailedHelp{ Summary: "specifies the type of data-structure that the list represents (map, set, atomic). ", - Details: "Possible data-structure types of a list are: \n - \"map\": it needs to have a key field, which will be used to build an associative list. A typical example is a the pod container list, which is indexed by the container name. \n - \"set\": Fields need to be \"scalar\", and there can be only one occurrence of each. \n - \"atomic\": All the fields in the list are treated as a single value, are typically manipulated together by the same actor.", + Details: "Possible data-structure types of a list are: \n - \"map\": it needs to have a key field, which will be used to build an associative list. A typical example is a the pod container list, which is indexed by the container name. \n - \"set\": Fields need to be \"scalar\", and there can be only one occurrence of each. \n - \"atomic\": All the fields in the list are treated as a single value, are typically manipulated together by the same actor.", }, FieldHelp: map[string]markers.DetailedHelp{}, } @@ -127,7 +144,7 @@ func (MapType) Help() *markers.DefinitionHelp { Category: "CRD processing", DetailedHelp: markers.DetailedHelp{ Summary: "specifies the level of atomicity of the map; i.e. whether each item in the map is independent of the others, or all fields are treated as a single unit. ", - Details: "Possible values: \n - \"granular\": items in the map are independent of each other, and can be manipulated by different actors. This is the default behavior. \n - \"atomic\": all fields are treated as one unit. Any changes have to replace the entire map.", + Details: "Possible values: \n - \"granular\": items in the map are independent of each other, and can be manipulated by different actors. This is the default behavior. \n - \"atomic\": all fields are treated as one unit. Any changes have to replace the entire map.", }, FieldHelp: map[string]markers.DetailedHelp{}, } @@ -177,11 +194,31 @@ func (Maximum) Help() *markers.DefinitionHelp { } } +func (Metadata) Help() *markers.DefinitionHelp { + return &markers.DefinitionHelp{ + Category: "CRD", + DetailedHelp: markers.DetailedHelp{ + Summary: "configures the additional annotations or labels for this CRD. For example adding annotation \"api-approved.kubernetes.io\" for a CRD with Kubernetes groups, or annotation \"cert-manager.io/inject-ca-from-secret\" for a CRD that needs CA injection.", + Details: "", + }, + FieldHelp: map[string]markers.DetailedHelp{ + "Annotations": { + Summary: "will be added into the annotations of this CRD.", + Details: "", + }, + "Labels": { + Summary: "will be added into the labels of this CRD.", + Details: "", + }, + }, + } +} + func (MinItems) Help() *markers.DefinitionHelp { return &markers.DefinitionHelp{ Category: "CRD validation", DetailedHelp: markers.DetailedHelp{ - Summary: "specifies the minimun length for this list.", + Summary: "specifies the minimum length for this list.", Details: "", }, FieldHelp: map[string]markers.DetailedHelp{}, @@ -214,7 +251,7 @@ func (Minimum) Help() *markers.DefinitionHelp { return &markers.DefinitionHelp{ Category: "CRD validation", DetailedHelp: markers.DetailedHelp{ - Summary: "specifies the minimum numeric value that this field can have. Negative integers are supported.", + Summary: "specifies the minimum numeric value that this field can have. Negative numbers are supported.", Details: "", }, FieldHelp: map[string]markers.DetailedHelp{}, @@ -360,7 +397,7 @@ func (StructType) Help() *markers.DefinitionHelp { Category: "CRD processing", DetailedHelp: markers.DetailedHelp{ Summary: "specifies the level of atomicity of the struct; i.e. whether each field in the struct is independent of the others, or all fields are treated as a single unit. ", - Details: "Possible values: \n - \"granular\": fields in the struct are independent of each other, and can be manipulated by different actors. This is the default behavior. \n - \"atomic\": all fields are treated as one unit. Any changes have to replace the entire struct.", + Details: "Possible values: \n - \"granular\": fields in the struct are independent of each other, and can be manipulated by different actors. This is the default behavior. \n - \"atomic\": all fields are treated as one unit. Any changes have to replace the entire struct.", }, FieldHelp: map[string]markers.DetailedHelp{}, } @@ -466,3 +503,23 @@ func (XPreserveUnknownFields) Help() *markers.DefinitionHelp { FieldHelp: map[string]markers.DetailedHelp{}, } } + +func (XValidation) Help() *markers.DefinitionHelp { + return &markers.DefinitionHelp{ + Category: "CRD validation", + DetailedHelp: markers.DetailedHelp{ + Summary: "marks a field as requiring a value for which a given expression evaluates to true. ", + Details: "This marker may be repeated to specify multiple expressions, all of which must evaluate to true.", + }, + FieldHelp: map[string]markers.DetailedHelp{ + "Rule": { + Summary: "", + Details: "", + }, + "Message": { + Summary: "", + Details: "", + }, + }, + } +} diff --git a/vendor/sigs.k8s.io/controller-tools/pkg/crd/parser.go b/vendor/sigs.k8s.io/controller-tools/pkg/crd/parser.go index 164e4756d3..4c15de9072 100644 --- a/vendor/sigs.k8s.io/controller-tools/pkg/crd/parser.go +++ b/vendor/sigs.k8s.io/controller-tools/pkg/crd/parser.go @@ -87,6 +87,9 @@ type Parser struct { // TODO: Should we have a more formal mechanism for putting "type patterns" in each of the above categories? AllowDangerousTypes bool + // IgnoreUnexportedFields specifies if unexported fields on the struct should be skipped + IgnoreUnexportedFields bool + // GenerateEmbeddedObjectMeta specifies if any embedded ObjectMeta should be generated GenerateEmbeddedObjectMeta bool } @@ -178,7 +181,7 @@ func (p *Parser) NeedSchemaFor(typ TypeIdent) { // avoid tripping recursive schemata, like ManagedFields, by adding an empty WIP schema p.Schemata[typ] = apiext.JSONSchemaProps{} - schemaCtx := newSchemaContext(typ.Package, p, p.AllowDangerousTypes) + schemaCtx := newSchemaContext(typ.Package, p, p.AllowDangerousTypes, p.IgnoreUnexportedFields) ctxForInfo := schemaCtx.ForInfo(info) pkgMarkers, err := markers.PackageMarkers(p.Collector, typ.Package) diff --git a/vendor/sigs.k8s.io/controller-tools/pkg/crd/schema.go b/vendor/sigs.k8s.io/controller-tools/pkg/crd/schema.go index b665817f91..e76d3ea88c 100644 --- a/vendor/sigs.k8s.io/controller-tools/pkg/crd/schema.go +++ b/vendor/sigs.k8s.io/controller-tools/pkg/crd/schema.go @@ -69,17 +69,19 @@ type schemaContext struct { schemaRequester schemaRequester PackageMarkers markers.MarkerValues - allowDangerousTypes bool + allowDangerousTypes bool + ignoreUnexportedFields bool } // newSchemaContext constructs a new schemaContext for the given package and schema requester. // It must have type info added before use via ForInfo. -func newSchemaContext(pkg *loader.Package, req schemaRequester, allowDangerousTypes bool) *schemaContext { +func newSchemaContext(pkg *loader.Package, req schemaRequester, allowDangerousTypes, ignoreUnexportedFields bool) *schemaContext { pkg.NeedTypesInfo() return &schemaContext{ - pkg: pkg, - schemaRequester: req, - allowDangerousTypes: allowDangerousTypes, + pkg: pkg, + schemaRequester: req, + allowDangerousTypes: allowDangerousTypes, + ignoreUnexportedFields: ignoreUnexportedFields, } } @@ -87,10 +89,11 @@ func newSchemaContext(pkg *loader.Package, req schemaRequester, allowDangerousTy // as this one, except with the given type information. func (c *schemaContext) ForInfo(info *markers.TypeInfo) *schemaContext { return &schemaContext{ - pkg: c.pkg, - info: info, - schemaRequester: c.schemaRequester, - allowDangerousTypes: c.allowDangerousTypes, + pkg: c.pkg, + info: info, + schemaRequester: c.schemaRequester, + allowDangerousTypes: c.allowDangerousTypes, + ignoreUnexportedFields: c.ignoreUnexportedFields, } } @@ -339,6 +342,11 @@ func structToSchema(ctx *schemaContext, structType *ast.StructType) *apiext.JSON } for _, field := range ctx.info.Fields { + // Skip if the field is not an inline field, ignoreUnexportedFields is true, and the field is not exported + if field.Name != "" && ctx.ignoreUnexportedFields && !ast.IsExported(field.Name) { + continue + } + jsonTag, hasTag := field.Tag.Lookup("json") if !hasTag { // if the field doesn't have a JSON tag, it doesn't belong in output (and shouldn't exist in a serialized type) diff --git a/vendor/sigs.k8s.io/controller-tools/pkg/crd/spec.go b/vendor/sigs.k8s.io/controller-tools/pkg/crd/spec.go index d48ce25258..5fd246c3fc 100644 --- a/vendor/sigs.k8s.io/controller-tools/pkg/crd/spec.go +++ b/vendor/sigs.k8s.io/controller-tools/pkg/crd/spec.go @@ -5,7 +5,7 @@ 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 + 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, @@ -30,13 +30,21 @@ import ( ) // SpecMarker is a marker that knows how to apply itself to a particular -// version in a CRD. +// version in a CRD Spec. type SpecMarker interface { // ApplyToCRD applies this marker to the given CRD, in the given version // within that CRD. It's called after everything else in the CRD is populated. ApplyToCRD(crd *apiext.CustomResourceDefinitionSpec, version string) error } +// Marker is a marker that knows how to apply itself to a particular +// version in a CRD. +type Marker interface { + // ApplyToCRD applies this marker to the given CRD, in the given version + // within that CRD. It's called after everything else in the CRD is populated. + ApplyToCRD(crd *apiext.CustomResourceDefinition, version string) error +} + // NeedCRDFor requests the full CRD for the given group-kind. It requires // that the packages containing the Go structs for that CRD have already // been loaded with NeedPackage. @@ -109,12 +117,14 @@ func (p *Parser) NeedCRDFor(groupKind schema.GroupKind, maxDescLen *int) { for _, markerVals := range typeInfo.Markers { for _, val := range markerVals { - crdMarker, isCrdMarker := val.(SpecMarker) - if !isCrdMarker { - continue - } - if err := crdMarker.ApplyToCRD(&crd.Spec, ver); err != nil { - pkg.AddError(loader.ErrFromNode(err /* an okay guess */, typeInfo.RawSpec)) + if specMarker, isSpecMarker := val.(SpecMarker); isSpecMarker { + if err := specMarker.ApplyToCRD(&crd.Spec, ver); err != nil { + pkg.AddError(loader.ErrFromNode(err /* an okay guess */, typeInfo.RawSpec)) + } + } else if crdMarker, isCRDMarker := val.(Marker); isCRDMarker { + if err := crdMarker.ApplyToCRD(&crd, ver); err != nil { + pkg.AddError(loader.ErrFromNode(err /* an okay guess */, typeInfo.RawSpec)) + } } } } @@ -164,11 +174,5 @@ func (p *Parser) NeedCRDFor(groupKind schema.GroupKind, maxDescLen *int) { packages[0].AddError(fmt.Errorf("CRD for %s with version(s) %v does not serve any version", groupKind, crd.Spec.Versions)) } - // NB(directxman12): CRD's status doesn't have omitempty markers, which means things - // get serialized as null, which causes the validator to freak out. Manually set - // these to empty till we get a better solution. - crd.Status.Conditions = []apiext.CustomResourceDefinitionCondition{} - crd.Status.StoredVersions = []string{} - p.CustomResourceDefinitions[groupKind] = crd } diff --git a/vendor/sigs.k8s.io/controller-tools/pkg/crd/zz_generated.markerhelp.go b/vendor/sigs.k8s.io/controller-tools/pkg/crd/zz_generated.markerhelp.go index 5e30a191be..15f2a85c37 100644 --- a/vendor/sigs.k8s.io/controller-tools/pkg/crd/zz_generated.markerhelp.go +++ b/vendor/sigs.k8s.io/controller-tools/pkg/crd/zz_generated.markerhelp.go @@ -1,3 +1,4 @@ +//go:build !ignore_autogenerated // +build !ignore_autogenerated /* @@ -32,6 +33,10 @@ func (Generator) Help() *markers.DefinitionHelp { Details: "", }, FieldHelp: map[string]markers.DetailedHelp{ + "IgnoreUnexportedFields": { + Summary: "indicates that we should skip unexported fields. ", + Details: "Left unspecified, the default is false.", + }, "AllowDangerousTypes": { Summary: "allows types which are usually omitted from CRD generation because they are not recommended. ", Details: "Currently the following additional types are allowed when this is true: float32 float64 \n Left unspecified, the default is false", @@ -48,6 +53,14 @@ func (Generator) Help() *markers.DefinitionHelp { Summary: "specifies if any embedded ObjectMeta in the CRD should be generated", Details: "", }, + "HeaderFile": { + Summary: "specifies the header text (e.g. license) to prepend to generated files.", + Details: "", + }, + "Year": { + Summary: "specifies the year to substitute for \" YEAR\" in the header file.", + Details: "", + }, }, } } diff --git a/vendor/sigs.k8s.io/controller-tools/pkg/deepcopy/gen.go b/vendor/sigs.k8s.io/controller-tools/pkg/deepcopy/gen.go index 54a72363b7..7e674a80aa 100644 --- a/vendor/sigs.k8s.io/controller-tools/pkg/deepcopy/gen.go +++ b/vendor/sigs.k8s.io/controller-tools/pkg/deepcopy/gen.go @@ -175,7 +175,8 @@ type ObjectGenCtx struct { // writeHeader writes out the build tag, package declaration, and imports func writeHeader(pkg *loader.Package, out io.Writer, packageName string, imports *importsList, headerText string) { // NB(directxman12): blank line after build tags to distinguish them from comments - _, err := fmt.Fprintf(out, `// +build !ignore_autogenerated + _, err := fmt.Fprintf(out, `//go:build !ignore_autogenerated +// +build !ignore_autogenerated %[3]s diff --git a/vendor/sigs.k8s.io/controller-tools/pkg/deepcopy/traverse.go b/vendor/sigs.k8s.io/controller-tools/pkg/deepcopy/traverse.go index 3a751757d5..9658e10524 100644 --- a/vendor/sigs.k8s.io/controller-tools/pkg/deepcopy/traverse.go +++ b/vendor/sigs.k8s.io/controller-tools/pkg/deepcopy/traverse.go @@ -735,11 +735,14 @@ func hasAnyDeepCopyMethod(pkg *loader.Package, typeInfo types.Type) bool { // eventualUnderlyingType gets the "final" type in a sequence of named aliases. // It's effectively a shortcut for calling Underlying in a loop. func eventualUnderlyingType(typeInfo types.Type) types.Type { - last := typeInfo - for underlying := typeInfo.Underlying(); underlying != last; last, underlying = underlying, underlying.Underlying() { - // get the actual underlying type + for { + underlying := typeInfo.Underlying() + if underlying == typeInfo { + break + } + typeInfo = underlying } - return last + return typeInfo } // fineToShallowCopy checks if a shallow-copying a type is equivalent to deepcopy-ing it. diff --git a/vendor/sigs.k8s.io/controller-tools/pkg/deepcopy/zz_generated.markerhelp.go b/vendor/sigs.k8s.io/controller-tools/pkg/deepcopy/zz_generated.markerhelp.go index 6e001c6e25..913bc1fb7f 100644 --- a/vendor/sigs.k8s.io/controller-tools/pkg/deepcopy/zz_generated.markerhelp.go +++ b/vendor/sigs.k8s.io/controller-tools/pkg/deepcopy/zz_generated.markerhelp.go @@ -1,3 +1,4 @@ +//go:build !ignore_autogenerated // +build !ignore_autogenerated /* diff --git a/vendor/sigs.k8s.io/controller-tools/pkg/genall/doc.go b/vendor/sigs.k8s.io/controller-tools/pkg/genall/doc.go index df8dd71389..af67402e68 100644 --- a/vendor/sigs.k8s.io/controller-tools/pkg/genall/doc.go +++ b/vendor/sigs.k8s.io/controller-tools/pkg/genall/doc.go @@ -17,14 +17,14 @@ limitations under the License. // Package genall defines entrypoints for generation tools to hook into and // share the same set of parsing, typechecking, and marker information. // -// Generators +// # Generators // // Each Generator knows how to register its markers into a central Registry, // and then how to generate output using a Collector and some root packages. // Each generator can be considered to be the output type of a marker, for easy // command line parsing. // -// Output and Input +// # Output and Input // // Generators output artifacts via an OutputRule. OutputRules know how to // write output for different package-associated (code) files, as well as @@ -40,7 +40,7 @@ limitations under the License. // InputRule defines custom input loading, but its shared across all // Generators. There's currently only a filesystem implementation. // -// Runtime and Context +// # Runtime and Context // // Runtime maps together Generators, and constructs "contexts" which provide // the common collector and roots, plus the output rule for that generator, and @@ -50,7 +50,7 @@ limitations under the License. // skipping type-checking errors (since those are commonly caused by the // partial type-checking of loader.TypeChecker). // -// Options +// # Options // // The FromOptions (and associated helpers) function makes it easy to use generators // and output rules as markers that can be parsed from the command line, producing diff --git a/vendor/sigs.k8s.io/controller-tools/pkg/genall/genall.go b/vendor/sigs.k8s.io/controller-tools/pkg/genall/genall.go index 2cf4ec7e72..bed7ec6039 100644 --- a/vendor/sigs.k8s.io/controller-tools/pkg/genall/genall.go +++ b/vendor/sigs.k8s.io/controller-tools/pkg/genall/genall.go @@ -17,13 +17,14 @@ limitations under the License. package genall import ( + "encoding/json" "fmt" "io" "io/ioutil" "os" "golang.org/x/tools/go/packages" - "sigs.k8s.io/yaml" + rawyaml "gopkg.in/yaml.v2" "sigs.k8s.io/controller-tools/pkg/loader" "sigs.k8s.io/controller-tools/pkg/markers" @@ -120,22 +121,46 @@ type GenerationContext struct { InputRule } +// WriteYAMLOptions implements the Options Pattern for WriteYAML. +type WriteYAMLOptions struct { + transform func(obj map[string]interface{}) error +} + +// WithTransform applies a transformation to objects just before writing them. +func WithTransform(transform func(obj map[string]interface{}) error) *WriteYAMLOptions { + return &WriteYAMLOptions{ + transform: transform, + } +} + +// TransformRemoveCreationTimestamp ensures we do not write the metadata.creationTimestamp field. +func TransformRemoveCreationTimestamp(obj map[string]interface{}) error { + metadata := obj["metadata"].(map[interface{}]interface{}) + delete(metadata, "creationTimestamp") + return nil +} + // WriteYAML writes the given objects out, serialized as YAML, using the // context's OutputRule. Objects are written as separate documents, separated // from each other by `---` (as per the YAML spec). -func (g GenerationContext) WriteYAML(itemPath string, objs ...interface{}) error { +func (g GenerationContext) WriteYAML(itemPath, headerText string, objs []interface{}, options ...*WriteYAMLOptions) error { out, err := g.Open(nil, itemPath) if err != nil { return err } defer out.Close() + _, err = out.Write([]byte(headerText)) + if err != nil { + return err + } + for _, obj := range objs { - yamlContent, err := yaml.Marshal(obj) + yamlContent, err := yamlMarshal(obj, options...) if err != nil { return err } - n, err := out.Write(append([]byte("\n---\n"), yamlContent...)) + n, err := out.Write(append([]byte("---\n"), yamlContent...)) if err != nil { return err } @@ -147,6 +172,41 @@ func (g GenerationContext) WriteYAML(itemPath string, objs ...interface{}) error return nil } +// yamlMarshal is based on sigs.k8s.io/yaml.Marshal, but allows for transforming the final data before writing. +func yamlMarshal(o interface{}, options ...*WriteYAMLOptions) ([]byte, error) { + j, err := json.Marshal(o) + if err != nil { + return nil, fmt.Errorf("error marshaling into JSON: %v", err) + } + + return yamlJSONToYAMLWithFilter(j, options...) +} + +// yamlJSONToYAMLWithFilter is based on sigs.k8s.io/yaml.JSONToYAML, but allows for transforming the final data before writing. +func yamlJSONToYAMLWithFilter(j []byte, options ...*WriteYAMLOptions) ([]byte, error) { + // Convert the JSON to an object. + var jsonObj map[string]interface{} + // We are using yaml.Unmarshal here (instead of json.Unmarshal) because the + // Go JSON library doesn't try to pick the right number type (int, float, + // etc.) when unmarshalling to interface{}, it just picks float64 + // universally. go-yaml does go through the effort of picking the right + // number type, so we can preserve number type throughout this process. + if err := rawyaml.Unmarshal(j, &jsonObj); err != nil { + return nil, err + } + + for _, option := range options { + if option.transform != nil { + if err := option.transform(jsonObj); err != nil { + return nil, err + } + } + } + + // Marshal this object into YAML. + return rawyaml.Marshal(jsonObj) +} + // ReadFile reads the given boilerplate artifact using the context's InputRule. func (g GenerationContext) ReadFile(path string) ([]byte, error) { file, err := g.OpenForRead(path) diff --git a/vendor/sigs.k8s.io/controller-tools/pkg/genall/help/pretty/doc.go b/vendor/sigs.k8s.io/controller-tools/pkg/genall/help/pretty/doc.go index 06622db744..bc99e9ba99 100644 --- a/vendor/sigs.k8s.io/controller-tools/pkg/genall/help/pretty/doc.go +++ b/vendor/sigs.k8s.io/controller-tools/pkg/genall/help/pretty/doc.go @@ -17,13 +17,13 @@ limitations under the License. // Package pretty contains utilities for formatting terminal help output, // and a use of those to display marker help. // -// Terminal Output +// # Terminal Output // // The Span interface and Table struct allow you to construct tables with // colored formatting, without causing ANSI formatting characters to mess up width // calculations. // -// Marker Help +// # Marker Help // // The MarkersSummary prints a summary table for marker help, while the MarkersDetails // prints out more detailed information, with explainations of the individual marker fields. diff --git a/vendor/sigs.k8s.io/controller-tools/pkg/genall/options.go b/vendor/sigs.k8s.io/controller-tools/pkg/genall/options.go index 45e3bc41f3..658b96bb35 100644 --- a/vendor/sigs.k8s.io/controller-tools/pkg/genall/options.go +++ b/vendor/sigs.k8s.io/controller-tools/pkg/genall/options.go @@ -30,6 +30,8 @@ var ( // +controllertools:marker:generateHelp:category="" // InputPaths represents paths and go-style path patterns to use as package roots. +// +// Multiple paths can be specified using "{path1, path2, path3}". type InputPaths []string // RegisterOptionsMarkers registers "mandatory" options markers for FromOptions into the given registry. @@ -134,6 +136,9 @@ func protoFromOptions(optionsRegistry *markers.Registry, options []string) (prot switch val := val.(type) { case Generator: gens = append(gens, &val) + if _, alreadyExists := gensByName[defn.Name]; alreadyExists { + return protoRuntime{}, fmt.Errorf("multiple instances of '%s' generator specified", defn.Name) + } gensByName[defn.Name] = &val case OutputRule: _, genName := splitOutputRuleOption(defn.Name) diff --git a/vendor/sigs.k8s.io/controller-tools/pkg/genall/output.go b/vendor/sigs.k8s.io/controller-tools/pkg/genall/output.go index b5a09e1692..4cd29f4960 100644 --- a/vendor/sigs.k8s.io/controller-tools/pkg/genall/output.go +++ b/vendor/sigs.k8s.io/controller-tools/pkg/genall/output.go @@ -103,7 +103,7 @@ type OutputToDirectory string func (o OutputToDirectory) Open(_ *loader.Package, itemPath string) (io.WriteCloser, error) { // ensure the directory exists - if err := os.MkdirAll(string(o), os.ModePerm); err != nil { + if err := os.MkdirAll(filepath.Dir(filepath.Join(string(o), itemPath)), os.ModePerm); err != nil { return nil, err } path := filepath.Join(string(o), itemPath) @@ -122,7 +122,7 @@ var OutputToStdout = outputToStdout{} // Generally useful for single-artifact outputs. type outputToStdout struct{} -func (o outputToStdout) Open(_ *loader.Package, itemPath string) (io.WriteCloser, error) { +func (o outputToStdout) Open(_ *loader.Package, _ string) (io.WriteCloser, error) { return nopCloser{os.Stdout}, nil } diff --git a/vendor/sigs.k8s.io/controller-tools/pkg/genall/zz_generated.markerhelp.go b/vendor/sigs.k8s.io/controller-tools/pkg/genall/zz_generated.markerhelp.go index 1319397e63..6428f0ce28 100644 --- a/vendor/sigs.k8s.io/controller-tools/pkg/genall/zz_generated.markerhelp.go +++ b/vendor/sigs.k8s.io/controller-tools/pkg/genall/zz_generated.markerhelp.go @@ -1,3 +1,4 @@ +//go:build !ignore_autogenerated // +build !ignore_autogenerated /* @@ -28,8 +29,8 @@ func (InputPaths) Help() *markers.DefinitionHelp { return &markers.DefinitionHelp{ Category: "", DetailedHelp: markers.DetailedHelp{ - Summary: "represents paths and go-style path patterns to use as package roots.", - Details: "", + Summary: "represents paths and go-style path patterns to use as package roots. ", + Details: "Multiple paths can be specified using \"{path1, path2, path3}\".", }, FieldHelp: map[string]markers.DetailedHelp{}, } diff --git a/vendor/sigs.k8s.io/controller-tools/pkg/loader/doc.go b/vendor/sigs.k8s.io/controller-tools/pkg/loader/doc.go index a80065ec74..6853c062f4 100644 --- a/vendor/sigs.k8s.io/controller-tools/pkg/loader/doc.go +++ b/vendor/sigs.k8s.io/controller-tools/pkg/loader/doc.go @@ -22,7 +22,7 @@ limitations under the License. // Because it uses go/packages, it's modules-aware, and works in both modules- // and non-modules environments. // -// Loading +// # Loading // // The main entrypoint for loading is LoadRoots, which traverse the package // graph starting at the given patterns (file, package, path, or ...-wildcard, @@ -33,7 +33,7 @@ limitations under the License. // Packages are suitable for comparison, as each unique package only ever has // one *Package object returned. // -// Syntax and TypeChecking +// # Syntax and TypeChecking // // ASTs and type-checking information can be loaded with NeedSyntax and // NeedTypesInfo, respectively. Both are idempotent -- repeated calls will @@ -41,14 +41,14 @@ limitations under the License. // check the current package -- if you want to type-check imports as well, // you'll need to type-check them first. // -// Reference Pruning and Recursive Checking +// # Reference Pruning and Recursive Checking // // In order to type-check using only the packages you care about, you can use a // TypeChecker. TypeChecker will visit each top-level type declaration, // collect (optionally filtered) references, and type-check references // packages. // -// Errors +// # Errors // // Errors can be added to each package. Use ErrFromNode to create an error // from an AST node. Errors can then be printed (complete with file and diff --git a/vendor/sigs.k8s.io/controller-tools/pkg/loader/loader.go b/vendor/sigs.k8s.io/controller-tools/pkg/loader/loader.go index 35c2713357..2efa94c7d9 100644 --- a/vendor/sigs.k8s.io/controller-tools/pkg/loader/loader.go +++ b/vendor/sigs.k8s.io/controller-tools/pkg/loader/loader.go @@ -1,5 +1,5 @@ /* -Copyright 2019 The Kubernetes Authors. +Copyright 2019-2022 The Kubernetes Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -25,9 +25,12 @@ import ( "go/types" "io/ioutil" "os" + "path/filepath" + "regexp" "sync" "golang.org/x/tools/go/packages" + "k8s.io/apimachinery/pkg/util/sets" ) // Much of this is strongly inspired by the contents of go/packages, @@ -329,6 +332,40 @@ func LoadRoots(roots ...string) ([]*Package, error) { // // This is generally only useful for use in testing when you need to modify // loading settings to load from a fake location. +// +// This function will traverse Go module boundaries for roots that are file- +// system paths and end with "...". Please note this feature currently only +// supports roots that are filesystem paths. For more information, please +// refer to the high-level outline of this function's logic: +// +// 1. If no roots are provided then load the working directory and return +// early. +// +// 2. Otherwise sort the provided roots into two, distinct buckets: +// +// a. package/module names +// b. filesystem paths +// +// A filesystem path is distinguished from a Go package/module name by +// the same rules as followed by the "go" command. At a high level, a +// root is a filesystem path IFF it meets ANY of the following criteria: +// +// * is absolute +// * begins with . +// * begins with .. +// +// For more information please refer to the output of the command +// "go help packages". +// +// 3. Load the package/module roots as a single call to packages.Load. If +// there are no filesystem path roots then return early. +// +// 4. For filesystem path roots ending with "...", check to see if its +// descendants include any nested, Go modules. If so, add the directory +// that contains the nested Go module to the filesystem path roots. +// +// 5. Load the filesystem path roots and return the load packages for the +// package/module roots AND the filesystem path roots. func LoadRootsWithConfig(cfg *packages.Config, roots ...string) ([]*Package, error) { l := &loader{ cfg: cfg, @@ -341,18 +378,250 @@ func LoadRootsWithConfig(cfg *packages.Config, roots ...string) ([]*Package, err // put our build flags first so that callers can override them l.cfg.BuildFlags = append([]string{"-tags", "ignore_autogenerated"}, l.cfg.BuildFlags...) - rawPkgs, err := packages.Load(l.cfg, roots...) - if err != nil { - return nil, err + // Visit the import graphs of the loaded, root packages. If an imported + // package refers to another loaded, root package, then replace the + // instance of the imported package with a reference to the loaded, root + // package. This is required to make kubebuilder markers work correctly + // when multiple root paths are loaded and types from one path reference + // types from another root path. + defer func() { + for i := range l.Roots { + visitImports(l.Roots, l.Roots[i], nil) + } + }() + + // uniquePkgIDs is used to keep track of the discovered packages to be nice + // and try and prevent packages from showing up twice when nested module + // support is enabled. there is not harm that comes from this per se, but + // it makes testing easier when a known number of modules can be asserted + uniquePkgIDs := sets.String{} + + // loadPackages returns the Go packages for the provided roots + // + // if validatePkgFn is nil, a package will be returned in the slice, + // otherwise the package is only returned if the result of + // validatePkgFn(pkg.ID) is truthy + loadPackages := func(roots ...string) ([]*Package, error) { + rawPkgs, err := packages.Load(l.cfg, roots...) + if err != nil { + loadRoot := l.cfg.Dir + if l.cfg.Dir == "" { + loadRoot, _ = os.Getwd() + } + return nil, fmt.Errorf("load packages in root %q: %w", loadRoot, err) + } + var pkgs []*Package + for _, rp := range rawPkgs { + p := l.packageFor(rp) + if !uniquePkgIDs.Has(p.ID) { + pkgs = append(pkgs, p) + uniquePkgIDs.Insert(p.ID) + } + } + return pkgs, nil + } + + // if no roots were provided then load the current package and return early + if len(roots) == 0 { + pkgs, err := loadPackages() + if err != nil { + return nil, err + } + l.Roots = append(l.Roots, pkgs...) + return l.Roots, nil + } + + // pkgRoots is a slice of roots that are package/modules and fspRoots + // is a slice of roots that are local filesystem paths. + // + // please refer to this function's godoc comments for more information on + // how these two types of roots are distinguished from one another + var ( + pkgRoots []string + fspRoots []string + fspRootRx = regexp.MustCompile(`^\.{1,2}`) + ) + for _, r := range roots { + if filepath.IsAbs(r) || fspRootRx.MatchString(r) { + fspRoots = append(fspRoots, r) + } else { + pkgRoots = append(pkgRoots, r) + } } - for _, rawPkg := range rawPkgs { - l.Roots = append(l.Roots, l.packageFor(rawPkg)) + // handle the package roots by sending them into the packages.Load function + // all at once. this is more efficient, but cannot be used for the file- + // system path roots due to them needing a custom, calculated value for the + // cfg.Dir field + if len(pkgRoots) > 0 { + pkgs, err := loadPackages(pkgRoots...) + if err != nil { + return nil, err + } + l.Roots = append(l.Roots, pkgs...) + } + + // if there are no filesystem path roots then go ahead and return early + if len(fspRoots) == 0 { + return l.Roots, nil + } + + // + // at this point we are handling filesystem path roots + // + + // ensure the cfg.Dir field is reset to its original value upon + // returning from this function. it should honestly be fine if it is + // not given most callers will not send in the cfg parameter directly, + // as it's largely for testing, but still, let's be good stewards. + defer func(d string) { + cfg.Dir = d + }(cfg.Dir) + + // store the value of cfg.Dir so we can use it later if it is non-empty. + // we need to store it now as the value of cfg.Dir will be updated by + // a loop below + cfgDir := cfg.Dir + + // addNestedGoModulesToRoots is given to filepath.WalkDir and adds the + // directory part of p to the list of filesystem path roots IFF p is the + // path to a file named "go.mod" + addNestedGoModulesToRoots := func( + p string, + d os.DirEntry, + e error) error { + + if e != nil { + return e + } + if !d.IsDir() && filepath.Base(p) == "go.mod" { + fspRoots = append(fspRoots, filepath.Join(filepath.Dir(p), "...")) + } + return nil + } + + // in the first pass over the filesystem path roots we: + // + // 1. make the root into an absolute path + // + // 2. check to see if a root uses the nested path syntax, ex. ... + // + // 3. if so, walk the root's descendants, searching for any nested Go + // modules + // + // 4. if found then the directory containing the Go module is added to + // the list of the filesystem path roots + for i := range fspRoots { + r := fspRoots[i] + + // clean up the root + r = filepath.Clean(r) + + // get the absolute path of the root + if !filepath.IsAbs(r) { + + // if the initial value of cfg.Dir was non-empty then use it when + // building the absolute path to this root. otherwise use the + // filepath.Abs function to get the absolute path of the root based + // on the working directory + if cfgDir != "" { + r = filepath.Join(cfgDir, r) + } else { + ar, err := filepath.Abs(r) + if err != nil { + return nil, err + } + r = ar + } + } + + // update the root to be an absolute path + fspRoots[i] = r + + b, d := filepath.Base(r), filepath.Dir(r) + + // if the base element is "..." then it means nested traversal is + // activated. this can be passed directly to the loader. however, if + // specified we also want to traverse the path manually to determine if + // there are any nested Go modules we want to add to the list of file- + // system path roots to process + if b == "..." { + if err := filepath.WalkDir( + d, + addNestedGoModulesToRoots); err != nil { + + return nil, err + } + } + } + + // in the second pass over the filesystem path roots we: + // + // 1. determine the directory from which to execute the loader + // + // 2. update the loader config's Dir property to be the directory from + // step one + // + // 3. determine whether the root passed to the loader should be "./." + // or "./..." + // + // 4. execute the loader with the value from step three + for _, r := range fspRoots { + b, d := filepath.Base(r), filepath.Dir(r) + + // we want the base part of the path to be either "..." or ".", except + // Go's filepath utilities clean paths during manipulation, removing the + // ".". thus, if not "...", let's update the path components so that: + // + // d = r + // b = "." + if b != "..." { + d = r + b = "." + } + + // update the loader configuration's Dir field to the directory part of + // the root + l.cfg.Dir = d + + // update the root to be "./..." or "./." + // (with OS-specific filepath separator). please note filepath.Join + // would clean up the trailing "." character that we want preserved, + // hence the more manual path concatenation logic + r = fmt.Sprintf(".%s%s", string(filepath.Separator), b) + + // load the packages from the roots + pkgs, err := loadPackages(r) + if err != nil { + return nil, err + } + l.Roots = append(l.Roots, pkgs...) } return l.Roots, nil } +// visitImports walks a dependency graph, replacing imported package +// references with those from the rootPkgs list. This ensures the +// kubebuilder marker generation is handled correctly. For more info, +// please see issue 680. +func visitImports(rootPkgs []*Package, pkg *Package, seen sets.String) { + if seen == nil { + seen = sets.String{} + } + for importedPkgID, importedPkg := range pkg.Imports() { + for i := range rootPkgs { + if importedPkgID == rootPkgs[i].ID { + pkg.imports[importedPkgID] = rootPkgs[i] + } + } + if !seen.Has(importedPkgID) { + seen.Insert(importedPkgID) + visitImports(rootPkgs, importedPkg, seen) + } + } +} + // importFunc is an implementation of the single-method // types.Importer interface based on a function value. type importerFunc func(path string) (*types.Package, error) diff --git a/vendor/sigs.k8s.io/controller-tools/pkg/loader/refs.go b/vendor/sigs.k8s.io/controller-tools/pkg/loader/refs.go index 59ea262bb6..37c3295f14 100644 --- a/vendor/sigs.k8s.io/controller-tools/pkg/loader/refs.go +++ b/vendor/sigs.k8s.io/controller-tools/pkg/loader/refs.go @@ -133,9 +133,14 @@ func (c *referenceCollector) Visit(node ast.Node) ast.Visitor { // local reference or dot-import, ignore return nil case *ast.SelectorExpr: - pkgName := typedNode.X.(*ast.Ident).Name - c.refs.external(pkgName) - return nil + switch x := typedNode.X.(type) { + case *ast.Ident: + pkgName := x.Name + c.refs.external(pkgName) + return nil + default: + return c + } default: return c } diff --git a/vendor/sigs.k8s.io/controller-tools/pkg/markers/collect.go b/vendor/sigs.k8s.io/controller-tools/pkg/markers/collect.go index c5ea2345fd..63aa7344b2 100644 --- a/vendor/sigs.k8s.io/controller-tools/pkg/markers/collect.go +++ b/vendor/sigs.k8s.io/controller-tools/pkg/markers/collect.go @@ -31,7 +31,7 @@ import ( type Collector struct { *Registry - byPackage map[string]map[ast.Node]MarkerValues + byPackage map[*loader.Package]map[ast.Node]MarkerValues mu sync.Mutex } @@ -53,7 +53,7 @@ func (c *Collector) init() { c.Registry = &Registry{} } if c.byPackage == nil { - c.byPackage = make(map[string]map[ast.Node]MarkerValues) + c.byPackage = make(map[*loader.Package]map[ast.Node]MarkerValues) } } @@ -65,17 +65,17 @@ func (c *Collector) init() { // // - it's in the Godoc for that AST node // -// - it's in the closest non-godoc comment group above that node, -// *and* that node is a type or field node, *and* [it's either -// registered as type-level *or* it's not registered as being -// package-level] +// - it's in the closest non-godoc comment group above that node, +// *and* that node is a type or field node, *and* [it's either +// registered as type-level *or* it's not registered as being +// package-level] // -// - it's not in the Godoc of a node, doesn't meet the above criteria, and -// isn't in a struct definition (in which case it's package-level) +// - it's not in the Godoc of a node, doesn't meet the above criteria, and +// isn't in a struct definition (in which case it's package-level) func (c *Collector) MarkersInPackage(pkg *loader.Package) (map[ast.Node]MarkerValues, error) { c.mu.Lock() c.init() - if markers, exist := c.byPackage[pkg.ID]; exist { + if markers, exist := c.byPackage[pkg]; exist { c.mu.Unlock() return markers, nil } @@ -91,8 +91,7 @@ func (c *Collector) MarkersInPackage(pkg *loader.Package) (map[ast.Node]MarkerVa c.mu.Lock() defer c.mu.Unlock() - c.byPackage[pkg.ID] = markers - + c.byPackage[pkg] = markers return markers, nil } diff --git a/vendor/sigs.k8s.io/controller-tools/pkg/markers/doc.go b/vendor/sigs.k8s.io/controller-tools/pkg/markers/doc.go index 707036de8f..ab6947ccaf 100644 --- a/vendor/sigs.k8s.io/controller-tools/pkg/markers/doc.go +++ b/vendor/sigs.k8s.io/controller-tools/pkg/markers/doc.go @@ -19,7 +19,7 @@ limitations under the License. // avoid confusing with struct tags). Parsed result (output) values take the // form of Go values, much like the "encoding/json" package. // -// Definitions and Parsing +// # Definitions and Parsing // // Markers are defined as structured Definitions which can be used to // consistently parse marker comments. A Definition contains an concrete @@ -29,20 +29,20 @@ limitations under the License. // // Markers take the general form // -// +path:to:marker=val +// +path:to:marker=val // -// +path:to:marker:arg1=val,arg2=val2 +// +path:to:marker:arg1=val,arg2=val2 // -// +path:to:marker +// +path:to:marker // // Arguments may be ints, bools, strings, and slices. Ints and bool take their // standard form from Go. Strings may take any of their standard forms, or any // sequence of unquoted characters up until a `,` or `;` is encountered. Lists // take either of the following forms: // -// val;val;val +// val;val;val // -// {val, val, val} +// {val, val, val} // // Note that the first form will not properly parse nested slices, but is // generally convenient and is the form used in many existing markers. @@ -61,7 +61,7 @@ limitations under the License. // non-optional fields aren't mentioned, an error will be raised unless // `Strict` is set to false. // -// Registries and Lookup +// # Registries and Lookup // // Definitions can be added to registries to facilitate lookups. Each // definition is marked as either describing a type, struct field, or package @@ -69,7 +69,7 @@ limitations under the License. // long as each describes a different construct (type, field, or package). // Definitions can then be looked up by passing unparsed markers. // -// Collection and Extraction +// # Collection and Extraction // // Markers can be collected from a loader.Package using a Collector. The // Collector will read from a given Registry, collecting comments that look @@ -85,7 +85,7 @@ limitations under the License. // Like loader.Package, Collector's methods are idempotent and will not // reperform work. // -// Traversal +// # Traversal // // EachType function iterates over each type in a Package, providing // conveniently structured type and field information with marker values @@ -93,14 +93,14 @@ limitations under the License. // // PackageMarkers can be used to fetch just package-level markers. // -// Help +// # Help // // Help can be defined for each marker using the DefinitionHelp struct. It's // mostly intended to be generated off of godocs using cmd/helpgen, which takes // the first line as summary (removing the type/field name), and considers the // rest as details. It looks for the // -// +controllertools:generateHelp[:category=] +// +controllertools:generateHelp[:category=] // // marker to start generation. // diff --git a/vendor/sigs.k8s.io/controller-tools/pkg/markers/parse.go b/vendor/sigs.k8s.io/controller-tools/pkg/markers/parse.go index fcb33925e8..d84b70eb74 100644 --- a/vendor/sigs.k8s.io/controller-tools/pkg/markers/parse.go +++ b/vendor/sigs.k8s.io/controller-tools/pkg/markers/parse.go @@ -84,6 +84,8 @@ const ( InvalidType ArgumentType = iota // IntType is an int IntType + // NumberType is a float64 + NumberType // StringType is a string StringType // BoolType is a bool @@ -127,6 +129,8 @@ func (a Argument) typeString(out *strings.Builder) { out.WriteString("") case IntType: out.WriteString("int") + case NumberType: + out.WriteString("float64") case StringType: out.WriteString("string") case BoolType: @@ -180,6 +184,8 @@ func makeSliceType(itemType Argument) (reflect.Type, error) { switch itemType.Type { case IntType: itemReflectedType = reflect.TypeOf(int(0)) + case NumberType: + itemReflectedType = reflect.TypeOf(float64(0)) case StringType: itemReflectedType = reflect.TypeOf("") case BoolType: @@ -215,6 +221,8 @@ func makeMapType(itemType Argument) (reflect.Type, error) { switch itemType.Type { case IntType: itemReflectedType = reflect.TypeOf(int(0)) + case NumberType: + itemReflectedType = reflect.TypeOf(float64(0)) case StringType: itemReflectedType = reflect.TypeOf("") case BoolType: @@ -260,7 +268,11 @@ func guessType(scanner *sc.Scanner, raw string, allowSlice bool) *Argument { subScanner := parserScanner(subRaw, scanner.Error) var tok rune - for tok = subScanner.Scan(); tok != ',' && tok != sc.EOF && tok != ';'; tok = subScanner.Scan() { + for { + tok = subScanner.Scan() + if tok == ',' || tok == sc.EOF || tok == ';' { + break + } // wait till we get something interesting } @@ -346,9 +358,13 @@ func guessType(scanner *sc.Scanner, raw string, allowSlice bool) *Argument { if nextTok == '-' { nextTok = subScanner.Scan() } + if nextTok == sc.Int { return &Argument{Type: IntType} } + if nextTok == sc.Float { + return &Argument{Type: NumberType} + } } // otherwise assume bare strings @@ -357,6 +373,14 @@ func guessType(scanner *sc.Scanner, raw string, allowSlice bool) *Argument { // parseString parses either of the two accepted string forms (quoted, or bare tokens). func (a *Argument) parseString(scanner *sc.Scanner, raw string, out reflect.Value) { + // we need to temporarily disable the scanner's int/float parsing, since we want to + // prevent number parsing errors. + oldMode := scanner.Mode + scanner.Mode = oldMode &^ sc.ScanInts &^ sc.ScanFloats + defer func() { + scanner.Mode = oldMode + }() + // strings are a bit weird -- the "easy" case is quoted strings (tokenized as strings), // the "hard" case (present for backwards compat) is a bare sequence of tokens that aren't // a comma. @@ -471,7 +495,7 @@ func (a *Argument) parseMap(scanner *sc.Scanner, raw string, out reflect.Value) func (a *Argument) parse(scanner *sc.Scanner, raw string, out reflect.Value, inSlice bool) { // nolint:gocyclo if a.Type == InvalidType { - scanner.Error(scanner, fmt.Sprintf("cannot parse invalid type")) + scanner.Error(scanner, "cannot parse invalid type") return } if a.Pointer { @@ -483,8 +507,39 @@ func (a *Argument) parse(scanner *sc.Scanner, raw string, out reflect.Value, inS // raw consumes everything else castAndSet(out, reflect.ValueOf(raw[scanner.Pos().Offset:])) // consume everything else - for tok := scanner.Scan(); tok != sc.EOF; tok = scanner.Scan() { + var tok rune + for { + tok = scanner.Scan() + if tok == sc.EOF { + break + } + } + case NumberType: + nextChar := scanner.Peek() + isNegative := false + if nextChar == '-' { + isNegative = true + scanner.Scan() // eat the '-' + } + + tok := scanner.Scan() + if tok != sc.Float && tok != sc.Int { + scanner.Error(scanner, fmt.Sprintf("expected integer or float, got %q", scanner.TokenText())) + return } + + text := scanner.TokenText() + if isNegative { + text = "-" + text + } + + val, err := strconv.ParseFloat(text, 64) + if err != nil { + scanner.Error(scanner, fmt.Sprintf("unable to parse number: %v", err)) + return + } + + castAndSet(out, reflect.ValueOf(val)) case IntType: nextChar := scanner.Peek() isNegative := false @@ -597,6 +652,8 @@ func ArgumentFromType(rawType reflect.Type) (Argument, error) { arg.Type = StringType case reflect.Int, reflect.Int32: // NB(directxman12): all ints in kubernetes are int32, so explicitly support that arg.Type = IntType + case reflect.Float64: + arg.Type = NumberType case reflect.Bool: arg.Type = BoolType case reflect.Slice: @@ -755,7 +812,7 @@ func (d *Definition) loadFields() error { func parserScanner(raw string, err func(*sc.Scanner, string)) *sc.Scanner { scanner := &sc.Scanner{} scanner.Init(bytes.NewBufferString(raw)) - scanner.Mode = sc.ScanIdents | sc.ScanInts | sc.ScanStrings | sc.ScanRawStrings | sc.SkipComments + scanner.Mode = sc.ScanIdents | sc.ScanInts | sc.ScanFloats | sc.ScanStrings | sc.ScanRawStrings | sc.SkipComments scanner.Error = err return scanner diff --git a/vendor/sigs.k8s.io/controller-tools/pkg/markers/reg.go b/vendor/sigs.k8s.io/controller-tools/pkg/markers/reg.go index b0124630f8..7dcd458994 100644 --- a/vendor/sigs.k8s.io/controller-tools/pkg/markers/reg.go +++ b/vendor/sigs.k8s.io/controller-tools/pkg/markers/reg.go @@ -52,7 +52,8 @@ func (r *Registry) init() { // Define defines a new marker with the given name, target, and output type. // It's a shortcut around -// r.Register(MakeDefinition(name, target, obj)) +// +// r.Register(MakeDefinition(name, target, obj)) func (r *Registry) Define(name string, target TargetType, obj interface{}) error { def, err := MakeDefinition(name, target, obj) if err != nil { diff --git a/vendor/sigs.k8s.io/controller-tools/pkg/markers/zip.go b/vendor/sigs.k8s.io/controller-tools/pkg/markers/zip.go index a9b4c98af5..b352ededc7 100644 --- a/vendor/sigs.k8s.io/controller-tools/pkg/markers/zip.go +++ b/vendor/sigs.k8s.io/controller-tools/pkg/markers/zip.go @@ -67,12 +67,22 @@ func extractDoc(node ast.Node, decl *ast.GenDecl) string { // chop off the extraneous last part outLines = outLines[:len(outLines)-1] } - // respect double-newline meaning actual newline + for i, line := range outLines { + // Trim any extranous whitespace, + // for handling /*…*/-style comments, + // which have whitespace preserved in go/ast: + line = strings.TrimSpace(line) + + // Respect that double-newline means + // actual newline: if line == "" { outLines[i] = "\n" + } else { + outLines[i] = line } } + return strings.Join(outLines, " ") } @@ -139,11 +149,11 @@ type TypeCallback func(info *TypeInfo) // EachType collects all markers, then calls the given callback for each type declaration in a package. // Each individual spec is considered separate, so // -// type ( -// Foo string -// Bar int -// Baz struct{} -// ) +// type ( +// Foo string +// Bar int +// Baz struct{} +// ) // // yields three calls to the callback. func EachType(col *Collector, pkg *loader.Package, cb TypeCallback) error { diff --git a/vendor/sigs.k8s.io/controller-tools/pkg/rbac/parser.go b/vendor/sigs.k8s.io/controller-tools/pkg/rbac/parser.go index 8adfb36638..c8bbe9d546 100644 --- a/vendor/sigs.k8s.io/controller-tools/pkg/rbac/parser.go +++ b/vendor/sigs.k8s.io/controller-tools/pkg/rbac/parser.go @@ -19,7 +19,7 @@ limitations under the License. // // The markers take the form: // -// +kubebuilder:rbac:groups=,resources=,resourceNames=,verbs=,urls= +// +kubebuilder:rbac:groups=,resources=,resourceNames=,verbs=,urls= package rbac import ( @@ -149,6 +149,12 @@ func (r *Rule) ToRule() rbacv1.PolicyRule { type Generator struct { // RoleName sets the name of the generated ClusterRole. RoleName string + + // HeaderFile specifies the header text (e.g. license) to prepend to generated files. + HeaderFile string `marker:",optional"` + + // Year specifies the year to substitute for " YEAR" in the header file. + Year string `marker:",optional"` } func (Generator) RegisterMarkers(into *markers.Registry) error { @@ -263,5 +269,15 @@ func (g Generator) Generate(ctx *genall.GenerationContext) error { return nil } - return ctx.WriteYAML("role.yaml", objs...) + var headerText string + if g.HeaderFile != "" { + headerBytes, err := ctx.ReadFile(g.HeaderFile) + if err != nil { + return err + } + headerText = string(headerBytes) + } + headerText = strings.ReplaceAll(headerText, " YEAR", " "+g.Year) + + return ctx.WriteYAML("role.yaml", headerText, objs, genall.WithTransform(genall.TransformRemoveCreationTimestamp)) } diff --git a/vendor/sigs.k8s.io/controller-tools/pkg/rbac/zz_generated.markerhelp.go b/vendor/sigs.k8s.io/controller-tools/pkg/rbac/zz_generated.markerhelp.go index 29deffea30..5b6d9c4875 100644 --- a/vendor/sigs.k8s.io/controller-tools/pkg/rbac/zz_generated.markerhelp.go +++ b/vendor/sigs.k8s.io/controller-tools/pkg/rbac/zz_generated.markerhelp.go @@ -1,3 +1,4 @@ +//go:build !ignore_autogenerated // +build !ignore_autogenerated /* @@ -36,6 +37,14 @@ func (Generator) Help() *markers.DefinitionHelp { Summary: "sets the name of the generated ClusterRole.", Details: "", }, + "HeaderFile": { + Summary: "specifies the header text (e.g. license) to prepend to generated files.", + Details: "", + }, + "Year": { + Summary: "specifies the year to substitute for \" YEAR\" in the header file.", + Details: "", + }, }, } } diff --git a/vendor/sigs.k8s.io/controller-tools/pkg/schemapatcher/gen.go b/vendor/sigs.k8s.io/controller-tools/pkg/schemapatcher/gen.go index 6aec36ca6e..e33ec11ff5 100644 --- a/vendor/sigs.k8s.io/controller-tools/pkg/schemapatcher/gen.go +++ b/vendor/sigs.k8s.io/controller-tools/pkg/schemapatcher/gen.go @@ -113,7 +113,7 @@ func (g Generator) Generate(ctx *genall.GenerationContext) (result error) { } // generate schemata for the types we care about, and save them to be written later. - for groupKind := range crdgen.FindKubeKinds(parser, metav1Pkg) { + for _, groupKind := range crdgen.FindKubeKinds(parser, metav1Pkg) { existingSet, wanted := partialCRDSets[groupKind] if !wanted { continue @@ -358,12 +358,16 @@ func crdsFromDirectory(ctx *genall.GenerationContext, dir string) (map[schema.Gr if err := kyaml.Unmarshal(rawContent, &typeMeta); err != nil { continue } + + if typeMeta.APIVersion == "" || typeMeta.Kind != "CustomResourceDefinition" { + // If there's no API version this file probably isn't a CRD. + // Likewise we don't need to care if the Kind isn't CustomResourceDefinition. + continue + } + if !isSupportedAPIExtGroupVer(typeMeta.APIVersion) { return nil, fmt.Errorf("load %q: apiVersion %q not supported", filepath.Join(dir, fileInfo.Name()), typeMeta.APIVersion) } - if typeMeta.Kind != "CustomResourceDefinition" { - continue - } // collect the group-kind and versions from the actual structured form var actualCRD crdIsh diff --git a/vendor/sigs.k8s.io/controller-tools/pkg/schemapatcher/zz_generated.markerhelp.go b/vendor/sigs.k8s.io/controller-tools/pkg/schemapatcher/zz_generated.markerhelp.go index 96950a9d11..db9745d767 100644 --- a/vendor/sigs.k8s.io/controller-tools/pkg/schemapatcher/zz_generated.markerhelp.go +++ b/vendor/sigs.k8s.io/controller-tools/pkg/schemapatcher/zz_generated.markerhelp.go @@ -1,3 +1,4 @@ +//go:build !ignore_autogenerated // +build !ignore_autogenerated /* diff --git a/vendor/sigs.k8s.io/controller-tools/pkg/version/version.go b/vendor/sigs.k8s.io/controller-tools/pkg/version/version.go index 245826f692..09c8efcf40 100644 --- a/vendor/sigs.k8s.io/controller-tools/pkg/version/version.go +++ b/vendor/sigs.k8s.io/controller-tools/pkg/version/version.go @@ -5,7 +5,7 @@ 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 + 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, @@ -23,8 +23,8 @@ import ( // Version returns the version of the main module func Version() string { info, ok := debug.ReadBuildInfo() - if !ok { - // binary has not been built with module support + if !ok || info == nil || info.Main.Version == "" { + // binary has not been built with module support or doesn't contain a version. return "(unknown)" } return info.Main.Version @@ -36,10 +36,10 @@ func Version() string { // // - "Version: v0.2.1" when the program has been compiled with: // -// $ go get github.com/controller-tools/cmd/controller-gen@v0.2.1 +// $ go get github.com/controller-tools/cmd/controller-gen@v0.2.1 // -// Note: go modules requires the usage of semver compatible tags starting with -// 'v' to have nice human-readable versions. +// Note: go modules requires the usage of semver compatible tags starting with +// 'v' to have nice human-readable versions. // // - "Version: (devel)" when the program is compiled from a local git checkout. // diff --git a/vendor/sigs.k8s.io/controller-tools/pkg/webhook/parser.go b/vendor/sigs.k8s.io/controller-tools/pkg/webhook/parser.go index f3434e1ab2..1075f84250 100644 --- a/vendor/sigs.k8s.io/controller-tools/pkg/webhook/parser.go +++ b/vendor/sigs.k8s.io/controller-tools/pkg/webhook/parser.go @@ -19,11 +19,12 @@ limitations under the License. // // The markers take the form: // -// +kubebuilder:webhook:webhookVersions=<[]string>,failurePolicy=,matchPolicy=,groups=<[]string>,resources=<[]string>,verbs=<[]string>,versions=<[]string>,name=,path=,mutating=,sideEffects=,admissionReviewVersions=<[]string> +// +kubebuilder:webhook:webhookVersions=<[]string>,failurePolicy=,matchPolicy=,groups=<[]string>,resources=<[]string>,verbs=<[]string>,versions=<[]string>,name=,path=,mutating=,sideEffects=,admissionReviewVersions=<[]string>,reinvocationPolicy= package webhook import ( "fmt" + "sort" "strings" admissionregv1 "k8s.io/api/admissionregistration/v1" @@ -111,6 +112,14 @@ type Config struct { // AdmissionReviewVersions is an ordered list of preferred `AdmissionReview` // versions the Webhook expects. AdmissionReviewVersions []string `marker:"admissionReviewVersions"` + + // ReinvocationPolicy allows mutating webhooks to request reinvocation after other mutations + // + // To allow mutating admission plugins to observe changes made by other plugins, + // built-in mutating admission plugins are re-run if a mutating webhook modifies + // an object, and mutating webhooks can specify a reinvocationPolicy to control + // whether they are reinvoked as well. + ReinvocationPolicy string `marker:"reinvocationPolicy,optional"` } // verbToAPIVariant converts a marker's verb to the proper value for the API. @@ -151,6 +160,7 @@ func (c Config) ToMutatingWebhook() (admissionregv1.MutatingWebhook, error) { ClientConfig: c.clientConfig(), SideEffects: c.sideEffects(), AdmissionReviewVersions: c.AdmissionReviewVersions, + ReinvocationPolicy: c.reinvocationPolicy(), }, nil } @@ -263,6 +273,20 @@ func (c Config) sideEffects() *admissionregv1.SideEffectClass { return &sideEffects } +// reinvocationPolicy returns the reinvocationPolicy config for a mutating webhook. +func (c Config) reinvocationPolicy() *admissionregv1.ReinvocationPolicyType { + var reinvocationPolicy admissionregv1.ReinvocationPolicyType + switch strings.ToLower(c.ReinvocationPolicy) { + case strings.ToLower(string(admissionregv1.NeverReinvocationPolicy)): + reinvocationPolicy = admissionregv1.NeverReinvocationPolicy + case strings.ToLower(string(admissionregv1.IfNeededReinvocationPolicy)): + reinvocationPolicy = admissionregv1.IfNeededReinvocationPolicy + default: + return nil + } + return &reinvocationPolicy +} + // webhookVersions returns the target API versions of the {Mutating,Validating}WebhookConfiguration objects for a webhook. func (c Config) webhookVersions() ([]string, error) { // If WebhookVersions is not specified, we default it to `v1`. @@ -281,7 +305,13 @@ func (c Config) webhookVersions() ([]string, error) { // +controllertools:marker:generateHelp // Generator generates (partial) {Mutating,Validating}WebhookConfiguration objects. -type Generator struct{} +type Generator struct { + // HeaderFile specifies the header text (e.g. license) to prepend to generated files. + HeaderFile string `marker:",optional"` + + // Year specifies the year to substitute for " YEAR" in the header file. + Year string `marker:",optional"` +} func (Generator) RegisterMarkers(into *markers.Registry) error { if err := into.Register(ConfigDefinition); err != nil { @@ -291,7 +321,7 @@ func (Generator) RegisterMarkers(into *markers.Registry) error { return nil } -func (Generator) Generate(ctx *genall.GenerationContext) error { +func (g Generator) Generate(ctx *genall.GenerationContext) error { supportedWebhookVersions := supportedWebhookVersions() mutatingCfgs := make(map[string][]admissionregv1.MutatingWebhook, len(supportedWebhookVersions)) validatingCfgs := make(map[string][]admissionregv1.ValidatingWebhook, len(supportedWebhookVersions)) @@ -301,7 +331,12 @@ func (Generator) Generate(ctx *genall.GenerationContext) error { root.AddError(err) } - for _, cfg := range markerSet[ConfigDefinition.Name] { + cfgs := markerSet[ConfigDefinition.Name] + sort.SliceStable(cfgs, func(i, j int) bool { + return cfgs[i].(Config).Name < cfgs[j].(Config).Name + }) + + for _, cfg := range cfgs { cfg := cfg.(Config) webhookVersions, err := cfg.webhookVersions() if err != nil { @@ -382,6 +417,16 @@ func (Generator) Generate(ctx *genall.GenerationContext) error { } } + var headerText string + if g.HeaderFile != "" { + headerBytes, err := ctx.ReadFile(g.HeaderFile) + if err != nil { + return err + } + headerText = string(headerBytes) + } + headerText = strings.ReplaceAll(headerText, " YEAR", " "+g.Year) + for k, v := range versionedWebhooks { var fileName string if k == defaultWebhookVersion { @@ -389,7 +434,7 @@ func (Generator) Generate(ctx *genall.GenerationContext) error { } else { fileName = fmt.Sprintf("manifests.%s.yaml", k) } - if err := ctx.WriteYAML(fileName, v...); err != nil { + if err := ctx.WriteYAML(fileName, headerText, v, genall.WithTransform(genall.TransformRemoveCreationTimestamp)); err != nil { return err } } diff --git a/vendor/sigs.k8s.io/controller-tools/pkg/webhook/zz_generated.markerhelp.go b/vendor/sigs.k8s.io/controller-tools/pkg/webhook/zz_generated.markerhelp.go index 5e4e02f863..8e1ef419d9 100644 --- a/vendor/sigs.k8s.io/controller-tools/pkg/webhook/zz_generated.markerhelp.go +++ b/vendor/sigs.k8s.io/controller-tools/pkg/webhook/zz_generated.markerhelp.go @@ -1,3 +1,4 @@ +//go:build !ignore_autogenerated // +build !ignore_autogenerated /* @@ -80,6 +81,10 @@ func (Config) Help() *markers.DefinitionHelp { Summary: "is an ordered list of preferred `AdmissionReview` versions the Webhook expects.", Details: "", }, + "ReinvocationPolicy": { + Summary: "allows mutating webhooks to request reinvocation after other mutations ", + Details: "To allow mutating admission plugins to observe changes made by other plugins, built-in mutating admission plugins are re-run if a mutating webhook modifies an object, and mutating webhooks can specify a reinvocationPolicy to control whether they are reinvoked as well.", + }, }, } } @@ -91,6 +96,15 @@ func (Generator) Help() *markers.DefinitionHelp { Summary: "generates (partial) {Mutating,Validating}WebhookConfiguration objects.", Details: "", }, - FieldHelp: map[string]markers.DetailedHelp{}, + FieldHelp: map[string]markers.DetailedHelp{ + "HeaderFile": { + Summary: "specifies the header text (e.g. license) to prepend to generated files.", + Details: "", + }, + "Year": { + Summary: "specifies the year to substitute for \" YEAR\" in the header file.", + Details: "", + }, + }, } }