diff --git a/docs/project/olmv1_limitations.md b/docs/project/olmv1_limitations.md index 8f0e921e34..c27200b6dd 100644 --- a/docs/project/olmv1_limitations.md +++ b/docs/project/olmv1_limitations.md @@ -14,6 +14,7 @@ Currently, OLM v1 only supports installing operators packaged in [OLM v0 bundles * `olm.gvk.required` * `olm.package.required` * `olm.constraint` +* **must not** define `APIService`s in the `ClusterServiceVersion` OLM v1 verifies these criteria at install time and will surface violations in the `ClusterExtensions`'s `.status.conditions`. diff --git a/go.mod b/go.mod index 93cd021b13..fd94b6f038 100644 --- a/go.mod +++ b/go.mod @@ -9,37 +9,37 @@ require ( github.com/cert-manager/cert-manager v1.21.1 github.com/containerd/containerd v1.7.34 github.com/cucumber/gherkin/go/v26 v26.2.0 - github.com/cucumber/godog v0.15.1 + github.com/cucumber/godog v0.16.0 github.com/cucumber/messages/go/v21 v21.0.1 github.com/evanphx/json-patch v5.9.11+incompatible github.com/fsnotify/fsnotify v1.10.1 github.com/go-logr/logr v1.4.4 github.com/golang-jwt/jwt/v5 v5.3.1 github.com/google/go-cmp v0.7.0 - github.com/google/go-containerregistry v0.21.7 + github.com/google/go-containerregistry v0.21.9 github.com/google/renameio/v2 v2.0.2 github.com/gorilla/handlers v1.5.2 github.com/graphql-go/graphql v0.8.1 - github.com/klauspost/compress v1.19.1 + github.com/klauspost/compress v1.19.2 github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/image-spec v1.1.1 github.com/operator-framework/api v0.45.0 github.com/operator-framework/helm-operator-plugins v0.9.1 - github.com/operator-framework/operator-registry v1.73.0 + github.com/operator-framework/operator-registry v1.74.0 github.com/prometheus/client_golang v1.24.1 github.com/prometheus/common v0.70.1 github.com/santhosh-tekuri/jsonschema/v6 v6.0.3 github.com/spf13/cobra v1.10.2 github.com/spf13/pflag v1.0.10 - github.com/stretchr/testify v1.11.1 - go.podman.io/image/v5 v5.41.0 + github.com/stretchr/testify v1.12.1 + go.podman.io/image/v5 v5.41.1 go.uber.org/mock v0.6.0 golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f golang.org/x/sync v0.22.0 - golang.org/x/tools v0.48.0 - helm.sh/helm/v3 v3.21.3 + golang.org/x/tools v0.49.0 + helm.sh/helm/v3 v3.21.4 k8s.io/api v0.36.3 - k8s.io/apiextensions-apiserver v0.36.2 + k8s.io/apiextensions-apiserver v0.36.3 k8s.io/apimachinery v0.36.3 k8s.io/apiserver v0.36.3 k8s.io/cli-runtime v0.36.3 @@ -88,11 +88,13 @@ require ( github.com/containerd/typeurl/v2 v2.2.3 // indirect github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01 // indirect github.com/containers/ocicrypt v1.3.2 // indirect + github.com/cucumber/gherkin/go/v42 v42.0.0 // indirect + github.com/cucumber/messages/go/v34 v34.2.0 // indirect github.com/cyberphone/json-canonicalization v0.0.0-20241213102144-19d51d7fe467 // indirect github.com/cyphar/filepath-securejoin v0.7.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/distribution/reference v0.6.0 // indirect - github.com/docker/cli v29.6.2+incompatible // indirect + github.com/docker/cli v29.7.1+incompatible // indirect github.com/docker/distribution v2.8.3+incompatible // indirect github.com/docker/docker-credential-helpers v0.9.8 // indirect github.com/docker/go-connections v0.8.1 // indirect @@ -159,7 +161,7 @@ require ( github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.22 // indirect github.com/mattn/go-runewidth v0.0.27 // indirect - github.com/mattn/go-sqlite3 v1.14.48 // indirect + github.com/mattn/go-sqlite3 v1.14.49 // indirect github.com/miekg/pkcs11 v1.1.2 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/go-wordwrap v1.0.1 // indirect @@ -223,23 +225,23 @@ require ( go.opentelemetry.io/otel/sdk v1.44.0 // indirect go.opentelemetry.io/otel/trace v1.44.0 // indirect go.opentelemetry.io/proto/otlp v1.10.0 // indirect - go.podman.io/common v0.68.1 // indirect + go.podman.io/common v0.69.0 // indirect go.podman.io/storage v1.64.0 // indirect go.yaml.in/yaml/v2 v2.4.4 // indirect go.yaml.in/yaml/v3 v3.0.5 // indirect - golang.org/x/crypto v0.54.0 // indirect - golang.org/x/mod v0.38.0 // indirect - golang.org/x/net v0.57.0 // indirect + golang.org/x/crypto v0.55.0 // indirect + golang.org/x/mod v0.39.0 // indirect + golang.org/x/net v0.58.0 // indirect golang.org/x/oauth2 v0.36.0 // indirect golang.org/x/sys v0.47.0 // indirect golang.org/x/term v0.45.0 // indirect - golang.org/x/text v0.40.0 // indirect + golang.org/x/text v0.41.0 // indirect golang.org/x/time v0.15.0 // indirect gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect google.golang.org/genproto v0.0.0-20260319201613-d00831a3d3e7 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20260610212136-7ab31c22f7ad // indirect - google.golang.org/grpc v1.82.1 // indirect + google.golang.org/grpc v1.83.1 // indirect google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af // indirect gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect diff --git a/go.sum b/go.sum index 37ea1e65d6..8ea7b2c0f0 100644 --- a/go.sum +++ b/go.sum @@ -90,17 +90,19 @@ github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec= github.com/coreos/go-systemd/v22 v22.7.0 h1:LAEzFkke61DFROc7zNLX/WA2i5J8gYqe0rSj9KI28KA= github.com/coreos/go-systemd/v22 v22.7.0/go.mod h1:xNUYtjHu2EDXbsxz1i41wouACIwT7Ybq9o0BQhMwD0w= -github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s= github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE= github.com/cucumber/gherkin/go/v26 v26.2.0 h1:EgIjePLWiPeslwIWmNQ3XHcypPsWAHoMCz/YEBKP4GI= github.com/cucumber/gherkin/go/v26 v26.2.0/go.mod h1:t2GAPnB8maCT4lkHL99BDCVNzCh1d7dBhCLt150Nr/0= -github.com/cucumber/godog v0.15.1 h1:rb/6oHDdvVZKS66hrhpjFQFHjthFSrQBCOI1LwshNTI= -github.com/cucumber/godog v0.15.1/go.mod h1:qju+SQDewOljHuq9NSM66s0xEhogx0q30flfxL4WUk8= +github.com/cucumber/gherkin/go/v42 v42.0.0 h1:Ulh3E2awUUSSja+wonP/IOQ+ycmiZwZbgmzqk5H8JNI= +github.com/cucumber/gherkin/go/v42 v42.0.0/go.mod h1:CsaumaO2dR9XvBc6ZyiGLMhWCKtTRDxgoxqJigSjSSg= +github.com/cucumber/godog v0.16.0 h1:ezQbgItuWqZrjPUQwLJ3muwIlvzXBOfZso5QZfG7efE= +github.com/cucumber/godog v0.16.0/go.mod h1:EDUX9yCqANK+GpbftMDeu61sUDtdLuo1JJgXD2n3bbM= github.com/cucumber/messages/go/v21 v21.0.1 h1:wzA0LxwjlWQYZd32VTlAVDTkW6inOFmSM+RuOwHZiMI= github.com/cucumber/messages/go/v21 v21.0.1/go.mod h1:zheH/2HS9JLVFukdrsPWoPdmUtmYQAQPLk7w5vWsk5s= -github.com/cucumber/messages/go/v22 v22.0.0/go.mod h1:aZipXTKc0JnjCsXrJnuZpWhtay93k7Rn3Dee7iyPJjs= +github.com/cucumber/messages/go/v34 v34.2.0 h1:VCbcNOMz+f8ccjjOOx1NLBNhwvE7/X49Atc8klJa+i8= +github.com/cucumber/messages/go/v34 v34.2.0/go.mod h1:LYUPjqlTS1kS0pdkdf6sS5uirnjwiIzEGyXPezXNhL8= github.com/cyberphone/json-canonicalization v0.0.0-20241213102144-19d51d7fe467 h1:uX1JmpONuD549D73r6cgnxyUu18Zb7yHAy5AYU0Pm4Q= github.com/cyberphone/json-canonicalization v0.0.0-20241213102144-19d51d7fe467/go.mod h1:uzvlm1mxhHkdfqitSA92i7Se+S9ksOn3a3qmv/kyOCw= github.com/cyphar/filepath-securejoin v0.7.0 h1:s0Y3ITPy6sQn5xt54DuYvTF8hu134ooYLUb58DX/HjE= @@ -117,8 +119,8 @@ github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5Qvfr github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI= github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= -github.com/docker/cli v29.6.2+incompatible h1:/bjePvcbbFTnRrMfWJBY7AjfICdsiLVgHn6LwTVOcqw= -github.com/docker/cli v29.6.2+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/cli v29.7.1+incompatible h1:ILZpP6B7fedIr6ANy824QkDp1WMJuouIq0O2SrBkB2w= +github.com/docker/cli v29.7.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk= github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/docker-credential-helpers v0.9.8 h1:bIREROb7So6PRlq6KTtdS9MPEjC29OQRkFNlvK2OX8Q= @@ -218,8 +220,6 @@ github.com/gobuffalo/flect v1.0.3 h1:xeWBM2nui+qnVvNM4S3foBhCAL2XgPU+a7FdpelbTq4 github.com/gobuffalo/flect v1.0.3/go.mod h1:A5msMlrHtLqh9umBSnvabjsMrCcCpAyzglnDvkbYKHs= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= -github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= -github.com/gofrs/uuid v4.3.1+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA= github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= @@ -261,8 +261,8 @@ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= -github.com/google/go-containerregistry v0.21.7 h1:/vPFuVXDjtFREsVArW+0h1CIl5urnOhzei4X2DMW9IU= -github.com/google/go-containerregistry v0.21.7/go.mod h1:kjSbt7/zMsKLWfnHrIvKvhXHUw91jbe9DNjPPJ32gXE= +github.com/google/go-containerregistry v0.21.9 h1:F+D4uZ3iA3DLMJLfhaqMdHJbzeqm/216WGQq2dokuLs= +github.com/google/go-containerregistry v0.21.9/go.mod h1:dP5XNKcL7kMFF/TB3LfvWmVhAcv7iqkHb3oDK8aauTo= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -297,10 +297,8 @@ github.com/h2non/go-is-svg v0.0.0-20160927212452-35e8c4b0612c/go.mod h1:ObS/W+h8 github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/go-immutable-radix v1.3.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-memdb v1.3.4/go.mod h1:uBTr1oQbtuMgd1SSGoR8YV27eT3sBHbYiNm53bMpgSg= github.com/hashicorp/go-memdb v1.3.5 h1:b3taDMxCBCBVgyRrS1AZVHO14ubMYZB++QpNhBg+Nyo= github.com/hashicorp/go-memdb v1.3.5/go.mod h1:8IVKKBkVe+fxFgdFOYxzQQNjz+sWCyHCdIC/+5+Vy1Y= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= @@ -332,15 +330,12 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.19.1 h1:VsB4HPswih7mmZ8WleSFQ75c/Ui1M4trX5oAsJnhSlk= -github.com/klauspost/compress v1.19.1/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ= +github.com/klauspost/compress v1.19.2 h1:hMRETovs/pu/dVWN7zIT1PGG8t509MwT6bO7XSi26R8= +github.com/klauspost/compress v1.19.2/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ= github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU= github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -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/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= @@ -361,8 +356,8 @@ github.com/mattn/go-isatty v0.0.22/go.mod h1:ZXfXG4SQHsB/w3ZeOYbR0PrPwLy+n6xiMrJ github.com/mattn/go-runewidth v0.0.27 h1:Feg/Oou5zI/wnpgDF6omIU0OokC9GxLC/WRknhVlIR0= github.com/mattn/go-runewidth v0.0.27/go.mod h1:3qAiGCV4Koz/yuveO58qUefmUTRm8r0IGEXZ9jeHp/8= github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= -github.com/mattn/go-sqlite3 v1.14.48 h1:7XHIgl0a8HwOaiK4E47ozLkST78rR9+OtNGx27D/TFs= -github.com/mattn/go-sqlite3 v1.14.48/go.mod h1:6JTjA44L93a0QCyJef5YvlPoKXntQPjzWv5gtm9sB6w= +github.com/mattn/go-sqlite3 v1.14.49 h1:B8jBHC3xhxZgxztrgruTuLucebnULQnx4W7cF7SAE9w= +github.com/mattn/go-sqlite3 v1.14.49/go.mod h1:6JTjA44L93a0QCyJef5YvlPoKXntQPjzWv5gtm9sB6w= github.com/miekg/dns v1.1.72 h1:vhmr+TF2A3tuoGNkLDFK9zi36F2LS+hKTRW0Uf8kbzI= github.com/miekg/dns v1.1.72/go.mod h1:+EuEPhdHOsfk6Wk5TT2CzssZdqkmFhf8r+aVyDEToIs= github.com/miekg/pkcs11 v1.1.2 h1:/VxmeAX5qU6Q3EwafypogwWbYryHFmF2RpkJmw3m4MQ= @@ -423,8 +418,8 @@ github.com/operator-framework/helm-operator-plugins v0.9.1 h1:WSGXhcntMdTmc//s8a github.com/operator-framework/helm-operator-plugins v0.9.1/go.mod h1:vKg3/yJAadHAXwRkU//uUruvdJaQm9XAIJq0+D5ABTw= github.com/operator-framework/operator-lib v0.19.0 h1:az6ogYj21rtU0SF9uYctRLyKp2dtlqTsmpfehFy6Ce8= github.com/operator-framework/operator-lib v0.19.0/go.mod h1:KxycAjFnHt0DBtHmH3Jm7yHcY5sdrshPKTqM/HKAQ08= -github.com/operator-framework/operator-registry v1.73.0 h1:ZlgunOFoo0z2aR1teQs54sOkzBdEMmJKF0W6iQXNW90= -github.com/operator-framework/operator-registry v1.73.0/go.mod h1:3nfBxNTdxK1rKTBUSilyhLNHABv1N0HUVDpX08eaM58= +github.com/operator-framework/operator-registry v1.74.0 h1:InCaEwEEydEZB9yHcal9oBlo2SqCgq12dJhqORR8uvU= +github.com/operator-framework/operator-registry v1.74.0/go.mod h1:iKcgSTJr1WJtlDq8scnaWvUeCW/2WWdcyHocWuSGNQk= github.com/otiai10/copy v1.14.1 h1:5/7E6qsUMBaH5AnQ0sSLzzTg1oTECmcCmT6lvF45Na8= github.com/otiai10/copy v1.14.1/go.mod h1:oQwrEDDOci3IM8dJF0d8+jnbfPDllW6vUjNc3DoZm9I= github.com/otiai10/mint v1.6.3 h1:87qsV/aw1F5as1eH1zS/yqHY85ANKVMgkDrf9rcxbQs= @@ -485,11 +480,8 @@ github.com/smallstep/pkcs7 v0.2.1 h1:6Kfzr/QizdIuB6LSv8y1LJdZ3aPSfTNhTLqAx9CTLfA github.com/smallstep/pkcs7 v0.2.1/go.mod h1:RcXHsMfL+BzH8tRhmrF1NkkpebKpq3JEM66cOFxanf0= github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY= github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo= -github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU= github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/pflag v1.0.7/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= @@ -507,9 +499,8 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= -github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/stretchr/testify v1.12.1 h1:EuwCh5fleGS7H32xRwO3wRGT7DxrDhLAT6FF8MpWDWE= +github.com/stretchr/testify v1.12.1/go.mod h1:MDEgiDPPsNp5cuIrHPPCyornHKgEVbtFUmoNlxoYthg= github.com/ulikunitz/xz v0.5.16 h1:ld6NyySjx5lowVKwJvMRLnW5nxKX/xnpSiFYZ/Lxur0= github.com/ulikunitz/xz v0.5.16/go.mod h1:H9Rt/W6/Qj27PGauhQc6nfCDy7vHpzsOThBSaYDoEhw= github.com/vbatts/tar-split v0.12.3 h1:Cd46rkGXI3Td4yrVNwU8ripbxFaQbmesqhjBUUYAJSw= @@ -585,10 +576,10 @@ go.opentelemetry.io/otel/trace v1.44.0 h1:jxF5CsGYCe74MCRx2X4g7WsY/VBKRqqpNvXlX/ go.opentelemetry.io/otel/trace v1.44.0/go.mod h1:oLl1jrMQAVo6v3GAggN+1VH9VIz9iUSvW53sW1Q8PIE= go.opentelemetry.io/proto/otlp v1.10.0 h1:IQRWgT5srOCYfiWnpqUYz9CVmbO8bFmKcwYxpuCSL2g= go.opentelemetry.io/proto/otlp v1.10.0/go.mod h1:/CV4QoCR/S9yaPj8utp3lvQPoqMtxXdzn7ozvvozVqk= -go.podman.io/common v0.68.1 h1:y8NoHLidghpgHtWtwB9+pN7cHhIDe33g1sB4RFCRvKI= -go.podman.io/common v0.68.1/go.mod h1:zVzufHkRpLueF6NW6N+fAs1C2METdzYcfD9zuw+oJKA= -go.podman.io/image/v5 v5.41.0 h1:xOan4jlwbT4R5qhe3ruDAGJLnOC2z0eR61WhZjHbe4E= -go.podman.io/image/v5 v5.41.0/go.mod h1:wfgAlfczPK4ZZw/wn/Av2iJfb3z9Vv+RKWgjHNShzZk= +go.podman.io/common v0.69.0 h1:tAM8gJRCgoPmyfXnYP+6VRfOQ6JySgafpY28OhDZpWc= +go.podman.io/common v0.69.0/go.mod h1:g1iVXP+Xn/8He+96qpJw75pu054FRDQMiDGf2VKKspg= +go.podman.io/image/v5 v5.41.1 h1:iPrhIt7/aNfRBMuzoxbMUVpQmR7Q75ahnrzkIC4JWLQ= +go.podman.io/image/v5 v5.41.1/go.mod h1:wfgAlfczPK4ZZw/wn/Av2iJfb3z9Vv+RKWgjHNShzZk= go.podman.io/storage v1.64.0 h1:ryHCZO+Zl0ZG7OTHF+Qc4C0zLNuoe9W35zgE7mh2pYw= go.podman.io/storage v1.64.0/go.mod h1:ft0DzCRMZs1yn0rszmLYXEEwgd7IIc66JRwSRPUDwwc= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= @@ -612,8 +603,8 @@ golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliY golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M= -golang.org/x/crypto v0.54.0 h1:YLIA59K4fiNzHzjnZt2tUJQjQtUWfWbeHBqKtk3eScw= -golang.org/x/crypto v0.54.0/go.mod h1:KWL8ny2AZdGR2cWmzeHrp2azQPGogOv+HeQaVEXC2dk= +golang.org/x/crypto v0.55.0 h1:+KWHjbgOaAQ66dh/YlkZKHlz9ZUlq61AFirAR9ntP8M= +golang.org/x/crypto v0.55.0/go.mod h1:uq0V9dE/fzQuJtbnL+2EhWOE63vo164FY8xqEnV9xis= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f h1:W3F4c+6OLc6H2lb//N1q4WpJkhzJCK5J6kUi1NTVXfM= golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f/go.mod h1:J1xhfL/vlindoeF/aINzNzt2Bket5bjo9sdOYzOsU80= @@ -627,8 +618,8 @@ golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/mod v0.38.0 h1:MECBjubtXD7yj4HrhIUcywNaGeNVUdfVnxmPajOk4yk= -golang.org/x/mod v0.38.0/go.mod h1:V6Xz0pq8TQ3dGqVQ1FVHuelZpAL0uNhSkk9ogYP3c40= +golang.org/x/mod v0.39.0 h1:UF5zwQdCRRUpHfyPwr7d4UrGiVeldIsogtzWVnczL74= +golang.org/x/mod v0.39.0/go.mod h1:bvIbwjQ0HUFFf5AKukeeYQG4ZBUG9yxQbR9aEweIwYY= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -645,8 +636,8 @@ golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= -golang.org/x/net v0.57.0 h1:K5+3DljvIuDG9/Jv9rvyMywYNFCQ9RSUY6OOTTkT+tE= -golang.org/x/net v0.57.0/go.mod h1:KpXc8iv+r3XplLAG/f7Jsf9RPszJzdR0f58q9vGOuEU= +golang.org/x/net v0.58.0 h1:ynWG7rqYi4ccpTEuPZ2QGWHktVEM9DMCj9yzDE0Q7To= +golang.org/x/net v0.58.0/go.mod h1:YwCddHnFlT7eLQqVprV19OnhLGtc5xOKgE0RyqgfWAU= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs= golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q= @@ -701,8 +692,8 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= -golang.org/x/text v0.40.0 h1:Ub2Z6/xjgF1WrYQz2nuITOEegKFtiIy+rieRJ5lHZKs= -golang.org/x/text v0.40.0/go.mod h1:hpnzDAfGV753zIKo+wk3u1bVKCGPbrnF7+7LBF/UHVY= +golang.org/x/text v0.41.0 h1:vz/seA0lnX87Othu2f/0L24RcgrXD9/YFTSuGjj3rH8= +golang.org/x/text v0.41.0/go.mod h1:jvf1O8ajNzZqhSrQBPbutR/EB83Cc0CFrezNQIwbb5M= golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U= golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -717,8 +708,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= -golang.org/x/tools v0.48.0 h1:3+hClM1aLL5mjMKm5ovokw9epgRXPuu2tILgismM6RE= -golang.org/x/tools v0.48.0/go.mod h1:08xX0orndb/F7jJxGDicx061tyd5pcMto75YMAXr6lk= +golang.org/x/tools v0.49.0 h1:3NI7VXzL9+1WZD52Dx2ttoPwD5DWrFGpl9mFZDlmisI= +golang.org/x/tools v0.49.0/go.mod h1:SJNXV9DBKT0UbdttsQjbfJlAE/q+y36++zo3uL3N0Oo= golang.org/x/tools/go/expect v0.1.1-deprecated h1:jpBZDwmgPhXsKZC6WhL20P4b/wmnpsEAGHaNy0n/rJM= golang.org/x/tools/go/expect v0.1.1-deprecated/go.mod h1:eihoPOH+FgIqa3FpoTwguz/bVUSGBlGQU67vpBeOrBY= golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated h1:1h2MnaIAIXISqTFKdENegdpAgUXz6NrPEsbIeWaBRvM= @@ -747,8 +738,8 @@ google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyac google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.82.1 h1:NnAxzGRA0677vCa4BUkOAnO5+FfQqVl9iUXeD0IqcGE= -google.golang.org/grpc v1.82.1/go.mod h1:yzTZ1TB1Z3SG+LIYaI+WiE8D5+PZ3ArnrSp8zF3+/ZA= +google.golang.org/grpc v1.83.1 h1:HIO0+BEtBP6soyqvqC8sNUjZ7bTs+0hFQuFF+RAy++Y= +google.golang.org/grpc v1.83.1/go.mod h1:kDyl6SKsiHKt0uylY5gtn5cEjkrIOhQOGDgIc4JGwzQ= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -778,14 +769,14 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q= gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA= -helm.sh/helm/v3 v3.21.3 h1:wkamdwI3liEkW6wI1l9aGqQZGxcTKyt8kx0qJLPcmCg= -helm.sh/helm/v3 v3.21.3/go.mod h1:iaJ0iNsPoTZl++7h6vzQFyT0VEVtLYJiyRBDkPOOBTs= +helm.sh/helm/v3 v3.21.4 h1:T/GcIEXU/gNjJnkITlIZ3e9xqkZjhFTmISuStTZ6+Qg= +helm.sh/helm/v3 v3.21.4/go.mod h1:cS2FBb+xfLuaSqvEmbqIeKUVFgHdHVHtVeXb2epof3M= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= k8s.io/api v0.36.3 h1:NxB+05W2UGqXWFXcLO0RB5cnqnUPP5v5sVlaOH0Iz4w= k8s.io/api v0.36.3/go.mod h1:JzLQKqRHC5+I8RVj/lS3lCg0mg6nWI9Fo/Sk3ElxHzg= -k8s.io/apiextensions-apiserver v0.36.2 h1:3O5gqOj/dt2XWWbpMe+TXWpE9yU6pjM/tXxtHHJT/K4= -k8s.io/apiextensions-apiserver v0.36.2/go.mod h1:cL1tBWe8XSaP1H30iWKGo7hf6iAUUUJPEU70dskmAnA= +k8s.io/apiextensions-apiserver v0.36.3 h1:dPmOAPhwTtqb1bTxbFPsy18KHPhktQeO3WUPXunZIB0= +k8s.io/apiextensions-apiserver v0.36.3/go.mod h1:KTXFqgXiuw2pRoL+Wpmttqc+up9Xt/GohadPWeLLOa4= k8s.io/apimachinery v0.36.3 h1:PkzMRBRG8joFD8EhCuQAtNPvJlxb82FwplP26HIzvAM= k8s.io/apimachinery v0.36.3/go.mod h1:cTSjBWgPe/6CQyBKzY/hDIRWCQQQeK0mfLbml0UYFHE= k8s.io/apiserver v0.36.3 h1:MGSg2SkdfuytiDEcRylT5mQFmmSsbx90XFUO67Y4bsQ= diff --git a/openshift/tests-extension/go.mod b/openshift/tests-extension/go.mod index e9d7ada14e..7477317f96 100644 --- a/openshift/tests-extension/go.mod +++ b/openshift/tests-extension/go.mod @@ -13,7 +13,7 @@ require ( github.com/openshift/origin v1.5.0-alpha.3.0.20251010041851-79ff1dbbe815 github.com/operator-framework/api v0.45.0 github.com/operator-framework/operator-controller v1.8.1-0.20260319123036-8ccea5a0cf67 - github.com/operator-framework/operator-registry v1.73.0 + github.com/operator-framework/operator-registry v1.74.0 github.com/pborman/uuid v1.2.1 github.com/pkg/errors v0.9.1 github.com/spf13/cobra v1.10.2 @@ -21,7 +21,7 @@ require ( github.com/tidwall/pretty v1.2.1 gopkg.in/yaml.v3 v3.0.1 k8s.io/api v0.36.3 - k8s.io/apiextensions-apiserver v0.36.2 + k8s.io/apiextensions-apiserver v0.36.3 k8s.io/apimachinery v0.36.3 k8s.io/apiserver v0.36.3 k8s.io/client-go v0.36.3 @@ -96,19 +96,19 @@ require ( go.opentelemetry.io/proto/otlp v1.10.0 // indirect go.yaml.in/yaml/v2 v2.4.4 // indirect go.yaml.in/yaml/v3 v3.0.5 // indirect - golang.org/x/crypto v0.54.0 // indirect + golang.org/x/crypto v0.55.0 // indirect golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f // indirect - golang.org/x/net v0.57.0 // indirect + golang.org/x/net v0.58.0 // indirect golang.org/x/oauth2 v0.36.0 // indirect golang.org/x/sync v0.22.0 // indirect golang.org/x/sys v0.47.0 // indirect golang.org/x/term v0.45.0 // indirect - golang.org/x/text v0.40.0 // indirect + golang.org/x/text v0.41.0 // indirect golang.org/x/time v0.15.0 // indirect - golang.org/x/tools v0.48.0 // indirect + golang.org/x/tools v0.49.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20260610212136-7ab31c22f7ad // indirect - google.golang.org/grpc v1.82.1 // indirect + google.golang.org/grpc v1.83.1 // indirect google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af // indirect gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect diff --git a/openshift/tests-extension/go.sum b/openshift/tests-extension/go.sum index b4c3143f79..7b63c9b0c1 100644 --- a/openshift/tests-extension/go.sum +++ b/openshift/tests-extension/go.sum @@ -98,8 +98,8 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.19.1 h1:VsB4HPswih7mmZ8WleSFQ75c/Ui1M4trX5oAsJnhSlk= -github.com/klauspost/compress v1.19.1/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ= +github.com/klauspost/compress v1.19.2 h1:hMRETovs/pu/dVWN7zIT1PGG8t509MwT6bO7XSi26R8= +github.com/klauspost/compress v1.19.2/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -158,8 +158,8 @@ github.com/openshift/origin v1.5.0-alpha.3.0.20251010041851-79ff1dbbe815 h1:Q8fO github.com/openshift/origin v1.5.0-alpha.3.0.20251010041851-79ff1dbbe815/go.mod h1:thiTAaYNKIS7Lh6Lvzwi1JcE/TrX8oSc8u8PfP/Gaa8= github.com/operator-framework/api v0.45.0 h1:hkROwtsLH3oszp4IW+WsXEFSDgveSahHI7DKStOtrUI= github.com/operator-framework/api v0.45.0/go.mod h1:IQ4uuISTiIhV09oAurJSGD4KabayhY5nV6k1XmA235M= -github.com/operator-framework/operator-registry v1.73.0 h1:ZlgunOFoo0z2aR1teQs54sOkzBdEMmJKF0W6iQXNW90= -github.com/operator-framework/operator-registry v1.73.0/go.mod h1:3nfBxNTdxK1rKTBUSilyhLNHABv1N0HUVDpX08eaM58= +github.com/operator-framework/operator-registry v1.74.0 h1:InCaEwEEydEZB9yHcal9oBlo2SqCgq12dJhqORR8uvU= +github.com/operator-framework/operator-registry v1.74.0/go.mod h1:iKcgSTJr1WJtlDq8scnaWvUeCW/2WWdcyHocWuSGNQk= github.com/pborman/uuid v1.2.1 h1:+ZZIw58t/ozdjRaXh/3awHfmWRbzYxJoAdNJxe/3pvw= github.com/pborman/uuid v1.2.1/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -189,8 +189,8 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= -github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/stretchr/testify v1.12.1 h1:EuwCh5fleGS7H32xRwO3wRGT7DxrDhLAT6FF8MpWDWE= +github.com/stretchr/testify v1.12.1/go.mod h1:MDEgiDPPsNp5cuIrHPPCyornHKgEVbtFUmoNlxoYthg= github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY= github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= @@ -236,8 +236,8 @@ go.yaml.in/yaml/v3 v3.0.5/go.mod h1:HVTZu1O7/Vkt2N+BFy8Zza+lnLsABggaTM2ZpNIGuKg= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 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.54.0 h1:YLIA59K4fiNzHzjnZt2tUJQjQtUWfWbeHBqKtk3eScw= -golang.org/x/crypto v0.54.0/go.mod h1:KWL8ny2AZdGR2cWmzeHrp2azQPGogOv+HeQaVEXC2dk= +golang.org/x/crypto v0.55.0 h1:+KWHjbgOaAQ66dh/YlkZKHlz9ZUlq61AFirAR9ntP8M= +golang.org/x/crypto v0.55.0/go.mod h1:uq0V9dE/fzQuJtbnL+2EhWOE63vo164FY8xqEnV9xis= golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f h1:W3F4c+6OLc6H2lb//N1q4WpJkhzJCK5J6kUi1NTVXfM= golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f/go.mod h1:J1xhfL/vlindoeF/aINzNzt2Bket5bjo9sdOYzOsU80= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -246,8 +246,8 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.57.0 h1:K5+3DljvIuDG9/Jv9rvyMywYNFCQ9RSUY6OOTTkT+tE= -golang.org/x/net v0.57.0/go.mod h1:KpXc8iv+r3XplLAG/f7Jsf9RPszJzdR0f58q9vGOuEU= +golang.org/x/net v0.58.0 h1:ynWG7rqYi4ccpTEuPZ2QGWHktVEM9DMCj9yzDE0Q7To= +golang.org/x/net v0.58.0/go.mod h1:YwCddHnFlT7eLQqVprV19OnhLGtc5xOKgE0RyqgfWAU= golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs= golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -264,16 +264,16 @@ golang.org/x/term v0.45.0 h1:NwWyBmoJCbfTHpxrWoZ9C6/VxOf7ic219I8xZZFdrf0= golang.org/x/term v0.45.0/go.mod h1:9aqxs0blBcrm/n0L9QW0aRVD+ktan8ssZromtqJC43w= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.40.0 h1:Ub2Z6/xjgF1WrYQz2nuITOEegKFtiIy+rieRJ5lHZKs= -golang.org/x/text v0.40.0/go.mod h1:hpnzDAfGV753zIKo+wk3u1bVKCGPbrnF7+7LBF/UHVY= +golang.org/x/text v0.41.0 h1:vz/seA0lnX87Othu2f/0L24RcgrXD9/YFTSuGjj3rH8= +golang.org/x/text v0.41.0/go.mod h1:jvf1O8ajNzZqhSrQBPbutR/EB83Cc0CFrezNQIwbb5M= golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U= golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.48.0 h1:3+hClM1aLL5mjMKm5ovokw9epgRXPuu2tILgismM6RE= -golang.org/x/tools v0.48.0/go.mod h1:08xX0orndb/F7jJxGDicx061tyd5pcMto75YMAXr6lk= +golang.org/x/tools v0.49.0 h1:3NI7VXzL9+1WZD52Dx2ttoPwD5DWrFGpl9mFZDlmisI= +golang.org/x/tools v0.49.0/go.mod h1:SJNXV9DBKT0UbdttsQjbfJlAE/q+y36++zo3uL3N0Oo= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -284,8 +284,8 @@ google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa h1: google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:q4lMZS6kskjT5HvCPrnnypcDPVJqT/f4nfxmkE7gryY= google.golang.org/genproto/googleapis/rpc v0.0.0-20260610212136-7ab31c22f7ad h1:45WmJvIV6C2+O/jjLkPUH+F3aOj/1miDoU2DD0+NWbg= google.golang.org/genproto/googleapis/rpc v0.0.0-20260610212136-7ab31c22f7ad/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= -google.golang.org/grpc v1.82.1 h1:NnAxzGRA0677vCa4BUkOAnO5+FfQqVl9iUXeD0IqcGE= -google.golang.org/grpc v1.82.1/go.mod h1:yzTZ1TB1Z3SG+LIYaI+WiE8D5+PZ3ArnrSp8zF3+/ZA= +google.golang.org/grpc v1.83.1 h1:HIO0+BEtBP6soyqvqC8sNUjZ7bTs+0hFQuFF+RAy++Y= +google.golang.org/grpc v1.83.1/go.mod h1:kDyl6SKsiHKt0uylY5gtn5cEjkrIOhQOGDgIc4JGwzQ= google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af h1:+5/Sw3GsDNlEmu7TfklWKPdQ0Ykja5VEmq2i817+jbI= google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/openshift/tests-extension/vendor/golang.org/x/crypto/internal/poly1305/mac_noasm.go b/openshift/tests-extension/vendor/golang.org/x/crypto/internal/poly1305/mac_noasm.go index 8d99551fee..b1da45687c 100644 --- a/openshift/tests-extension/vendor/golang.org/x/crypto/internal/poly1305/mac_noasm.go +++ b/openshift/tests-extension/vendor/golang.org/x/crypto/internal/poly1305/mac_noasm.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build (!amd64 && !loong64 && !ppc64le && !ppc64 && !s390x) || !gc || purego +//go:build (!amd64 && !loong64 && !ppc64le && !ppc64 && !riscv64 && !s390x) || !gc || purego package poly1305 diff --git a/openshift/tests-extension/vendor/golang.org/x/crypto/internal/poly1305/sum_asm.go b/openshift/tests-extension/vendor/golang.org/x/crypto/internal/poly1305/sum_asm.go index 315b84ac39..55041bf51d 100644 --- a/openshift/tests-extension/vendor/golang.org/x/crypto/internal/poly1305/sum_asm.go +++ b/openshift/tests-extension/vendor/golang.org/x/crypto/internal/poly1305/sum_asm.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build gc && !purego && (amd64 || loong64 || ppc64 || ppc64le) +//go:build gc && !purego && (amd64 || loong64 || ppc64 || ppc64le || riscv64) package poly1305 diff --git a/openshift/tests-extension/vendor/golang.org/x/crypto/internal/poly1305/sum_riscv64.s b/openshift/tests-extension/vendor/golang.org/x/crypto/internal/poly1305/sum_riscv64.s new file mode 100644 index 0000000000..ce5eb3d43d --- /dev/null +++ b/openshift/tests-extension/vendor/golang.org/x/crypto/internal/poly1305/sum_riscv64.s @@ -0,0 +1,158 @@ +// Copyright 2026 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build gc && !purego + +#define LOAD64U(base, offset, t0, t1, t2, t3, dst) \ + MOVBU (offset+0*1)(base), t0; \ + MOVBU (offset+1*1)(base), t1; \ + MOVBU (offset+2*1)(base), t2; \ + MOVBU (offset+3*1)(base), t3; \ + SLL $8, t1; \ + SLL $16, t2; \ + SLL $24, t3; \ + OR t1, t0; \ + OR t3, t2; \ + OR t2, t0, dst; \ + MOVBU (offset+4*1)(base), t0; \ + MOVBU (offset+5*1)(base), t1; \ + MOVBU (offset+6*1)(base), t2; \ + MOVBU (offset+7*1)(base), t3; \ + SLL $32, t0; \ + SLL $40, t1; \ + SLL $48, t2; \ + SLL $56, t3; \ + OR t1, t0; \ + OR t3, t2; \ + OR t2, t0; \ + OR t0, dst + +// func update(state *macState, msg []byte) +TEXT ·update(SB), $0-32 + MOV state+0(FP), X5 + MOV msg_base+8(FP), X6 + MOV msg_len+16(FP), X7 + + MOV $16, X8 + + AND $7, X6, X28 + + MOV (0*8)(X5), X9 // h0 + MOV (1*8)(X5), X10 // h1 + MOV (2*8)(X5), X11 // h2 + MOV (3*8)(X5), X12 // r0 + MOV (4*8)(X5), X13 // r1 + + BLT X7, X8, tail + +loop: + BEQZ X28, aligned_load + + LOAD64U(X6, 0*8, X16, X18, X19, X20, X15) // msg[0:8] + LOAD64U(X6, 1*8, X16, X18, X19, X20, X17) // msg[8:16] + JMP block + +aligned_load: + MOV (0*8)(X6), X15 // msg[0:8] + MOV (1*8)(X6), X17 // msg[8:16] + +block: + ADD X15, X9 // h0 (x1 + y1 = z1', if z1' < x1 then z1' overflow) + SLTU X15, X9, X19 // h0.carry + ADD X17, X10, X22 + SLTU X17, X22, X23 + ADD X22, X19, X10 // h1 + SLTU X22, X10, X19 + OR X23, X19 // h1.carry + ADD $1, X19 + ADD X19, X11 // h2 + + ADD $16, X6 // msg = msg[16:] + +multiply: + MULHU X9, X12, X16 // h0r0.hi + MUL X9, X12, X15 // h0r0.lo + MULHU X10, X12, X17 // h1r0.hi + MUL X10, X12, X14 // h1r0.lo + ADD X14, X16 + SLTU X14, X16, X19 + ADD X19, X17 + MUL X11, X12, X20 + ADD X17, X20 + MULHU X9, X13, X17 // h0r1.hi + MUL X9, X13, X14 // h0r1.lo + ADD X14, X16 + SLTU X14, X16, X19 + ADD X19, X17 + MOV X17, X9 + MUL X11, X13, X21 // h2r1 + MULHU X10, X13, X17 // h1r1.hi + MUL X10, X13, X14 // h1r1.lo + ADD X14, X20 + ADD X17, X21, X22 + SLTU X14, X20, X19 + ADD X22, X19, X21 + ADD X9, X20 + SLTU X9, X20, X19 + ADD X19, X21 + AND $3, X20, X11 + AND $-4, X20, X18 + ADD X18, X15, X9 + ADD X21, X16, X22 + SLTU X18, X9, X19 + SLTU X21, X22, X23 + ADD X22, X19, X10 + SLTU X22, X10, X19 + OR X19, X23, X19 + ADD X19, X11 + SLL $62, X21, X22 + SRL $2, X20, X23 + SRL $2, X21, X21 + OR X22, X23, X20 + ADD X20, X9, X9 + ADD X21, X10, X22 + SLTU X20, X9, X19 + SLTU X21, X22, X23 + ADD X22, X19, X10 + SLTU X22, X10, X19 + OR X19, X23, X19 + ADD X19, X11, X11 + + SUB $16, X7, X7 + BGE X7, X8, loop + +tail: + BEQ X7, X0, done + MOV $1, X15 + MOV $0, X16 + ADD X7, X6, X6 + +flush_buffer: + MOVBU -1(X6), X20 + SRL $56, X15, X19 + SLL $8, X16, X23 + SLL $8, X15, X15 + OR X19, X23, X16 + XOR X20, X15 + SUB $1, X7, X7 + SUB $1, X6, X6 + BNE X7, X0, flush_buffer + + ADD X15, X9 + SLTU X15, X9, X19 + ADD X16, X10, X22 + SLTU X16, X22, X23 + ADD X22, X19, X10 + SLTU X22, X10, X19 + OR X23, X19 + ADD X19, X11 + + MOV $16, X7 + JMP multiply + +done: + MOV X9, (0*8)(X5) // h0 + MOV X10, (1*8)(X5) + MOV X11, (2*8)(X5) + RET diff --git a/openshift/tests-extension/vendor/golang.org/x/crypto/ssh/certs.go b/openshift/tests-extension/vendor/golang.org/x/crypto/ssh/certs.go index 6f75d77ec1..fa848f51a5 100644 --- a/openshift/tests-extension/vendor/golang.org/x/crypto/ssh/certs.go +++ b/openshift/tests-extension/vendor/golang.org/x/crypto/ssh/certs.go @@ -229,15 +229,20 @@ func parseCert(in []byte, privAlgo string) (*Certificate, error) { return nil, err } c.Reserved = g.Reserved + // Reject a certificate whose signature key is itself a certificate before + // parsing it. Certificates signed by certificates are not supported (see + // PROTOCOL.certkeys), and rejecting after ParsePublicKey returns would allow + // a chain of nested certificates to recurse once per level, exhausting the + // goroutine stack. + if sigAlgo, _, ok := parseString(g.SignatureKey); !ok { + return nil, errShortRead + } else if _, ok := certKeyAlgoNames[string(sigAlgo)]; ok { + return nil, fmt.Errorf("ssh: the signature key type %q is invalid for certificates", sigAlgo) + } k, err := ParsePublicKey(g.SignatureKey) if err != nil { return nil, err } - // The Type() function is intended to return only certificate key types, but - // we use certKeyAlgoNames anyway for safety, to match [Certificate.Type]. - if _, ok := certKeyAlgoNames[k.Type()]; ok { - return nil, fmt.Errorf("ssh: the signature key type %q is invalid for certificates", k.Type()) - } c.SignatureKey = k c.Signature, rest, ok = parseSignatureBody(g.Signature) if !ok || len(rest) > 0 { diff --git a/openshift/tests-extension/vendor/golang.org/x/crypto/ssh/channel.go b/openshift/tests-extension/vendor/golang.org/x/crypto/ssh/channel.go index afc9aef185..ba3279e91d 100644 --- a/openshift/tests-extension/vendor/golang.org/x/crypto/ssh/channel.go +++ b/openshift/tests-extension/vendor/golang.org/x/crypto/ssh/channel.go @@ -216,6 +216,10 @@ type channel struct { // packetPool has a buffer for each extended channel ID to // save allocations during writes. packetPool map[uint32][]byte + + // closeOnce guards close so it is idempotent: closing the internal Go + // channels (msg, incomingRequests) more than once would panic. + closeOnce sync.Once } // writePacket sends a packet. If the packet is a channel close, it updates @@ -340,7 +344,18 @@ func (ch *channel) handleData(packet []byte) error { if extended == 1 { ch.extPending.write(data) } else if extended > 0 { - // discard other extended data. + // RFC 4254, Section 5.2 defines no extended data types other + // than stderr (type 1, handled above) and this package provides + // no API to read them, so the data is discarded. Credit its + // window back immediately: it can never be read, so the + // deduction above would otherwise shrink the window permanently. + // adjustWindow returns io.EOF if the local side has already + // sent a channel close; ignore it like ReadExtended does, since + // an error returned here would terminate the mux read loop and + // tear down the whole connection. + if err := ch.adjustWindow(length); err != nil && err != io.EOF { + return err + } } else { ch.pending.write(data) } @@ -393,17 +408,19 @@ func (c *channel) ReadExtended(data []byte, extended uint32) (n int, err error) } func (c *channel) close() { - c.pending.eof() - c.extPending.eof() - close(c.msg) - close(c.incomingRequests) - c.writeMu.Lock() - // This is not necessary for a normal channel teardown, but if - // there was another error, it is. - c.sentClose = true - c.writeMu.Unlock() - // Unblock writers. - c.remoteWin.close() + c.closeOnce.Do(func() { + c.pending.eof() + c.extPending.eof() + close(c.msg) + close(c.incomingRequests) + c.writeMu.Lock() + // This is not necessary for a normal channel teardown, but if + // there was another error, it is. + c.sentClose = true + c.writeMu.Unlock() + // Unblock writers. + c.remoteWin.close() + }) } // responseMessageReceived is called when a success or failure message is @@ -493,19 +510,20 @@ func (ch *channel) handlePacket(packet []byte) error { func (m *mux) newChannel(chanType string, direction channelDirection, extraData []byte) *channel { ch := &channel{ - remoteWin: window{Cond: newCond()}, - myWindow: channelWindowSize, - pending: newBuffer(), - extPending: newBuffer(), - direction: direction, - incomingRequests: make(chan *Request, chanSize), - msg: make(chan interface{}, chanSize), - chanType: chanType, - extraData: extraData, - mux: m, - packetPool: make(map[uint32][]byte), - } - ch.localId = m.chanList.add(ch) + remoteWin: window{Cond: newCond()}, + myWindow: channelWindowSize, + maxIncomingPayload: channelMaxPacket, + pending: newBuffer(), + extPending: newBuffer(), + direction: direction, + incomingRequests: make(chan *Request, chanSize), + msg: make(chan interface{}, chanSize), + chanType: chanType, + extraData: extraData, + mux: m, + packetPool: make(map[uint32][]byte), + } + m.chanList.add(ch) return ch } @@ -529,7 +547,6 @@ func (ch *channel) Accept() (Channel, <-chan *Request, error) { if ch.decided { return nil, nil, errDecidedAlready } - ch.maxIncomingPayload = channelMaxPacket confirm := channelOpenConfirmMsg{ PeersID: ch.remoteId, MyID: ch.localId, diff --git a/openshift/tests-extension/vendor/golang.org/x/crypto/ssh/client_auth.go b/openshift/tests-extension/vendor/golang.org/x/crypto/ssh/client_auth.go index 60af2fc4dd..138cc9003a 100644 --- a/openshift/tests-extension/vendor/golang.org/x/crypto/ssh/client_auth.go +++ b/openshift/tests-extension/vendor/golang.org/x/crypto/ssh/client_auth.go @@ -798,7 +798,7 @@ func (g *gssAPIWithMICCallback) auth(session []byte, user string, c packetConn, return authFailure, nil, fmt.Errorf("GSS-API Error:\n"+ "Major Status: %d\n"+ "Minor Status: %d\n"+ - "Error Message: %s\n", userAuthGSSAPIErrorResp.MajorStatus, userAuthGSSAPIErrorResp.MinorStatus, + "Error Message: %q\n", userAuthGSSAPIErrorResp.MajorStatus, userAuthGSSAPIErrorResp.MinorStatus, userAuthGSSAPIErrorResp.Message) case msgUserAuthGSSAPIToken: userAuthGSSAPITokenReq := &userAuthGSSAPIToken{} diff --git a/openshift/tests-extension/vendor/golang.org/x/crypto/ssh/common.go b/openshift/tests-extension/vendor/golang.org/x/crypto/ssh/common.go index 2e44e9c9ec..aed0fd926a 100644 --- a/openshift/tests-extension/vendor/golang.org/x/crypto/ssh/common.go +++ b/openshift/tests-extension/vendor/golang.org/x/crypto/ssh/common.go @@ -419,7 +419,7 @@ type AlgorithmNegotiationError struct { } func (a *AlgorithmNegotiationError) Error() string { - return fmt.Sprintf("ssh: no common algorithm for %s; we offered: %v, peer offered: %v", + return fmt.Sprintf("ssh: no common algorithm for %s; we offered: %q, peer offered: %q", a.What, a.SupportedAlgorithms, a.RequestedAlgorithms) } @@ -544,7 +544,7 @@ func (c *Config) SetDefaults() { if c.Rand == nil { c.Rand = rand.Reader } - if c.Ciphers == nil { + if len(c.Ciphers) == 0 { c.Ciphers = defaultCiphers } var ciphers []string @@ -556,7 +556,7 @@ func (c *Config) SetDefaults() { } c.Ciphers = ciphers - if c.KeyExchanges == nil { + if len(c.KeyExchanges) == 0 { c.KeyExchanges = defaultKexAlgos } var kexs []string @@ -571,7 +571,7 @@ func (c *Config) SetDefaults() { } c.KeyExchanges = kexs - if c.MACs == nil { + if len(c.MACs) == 0 { c.MACs = defaultMACs } var macs []string diff --git a/openshift/tests-extension/vendor/golang.org/x/crypto/ssh/connection.go b/openshift/tests-extension/vendor/golang.org/x/crypto/ssh/connection.go index 378f6407b5..9e0ed089c4 100644 --- a/openshift/tests-extension/vendor/golang.org/x/crypto/ssh/connection.go +++ b/openshift/tests-extension/vendor/golang.org/x/crypto/ssh/connection.go @@ -17,7 +17,7 @@ type OpenChannelError struct { } func (e *OpenChannelError) Error() string { - return fmt.Sprintf("ssh: rejected: %s (%s)", e.Reason, e.Message) + return fmt.Sprintf("ssh: rejected: %s (%q)", e.Reason, e.Message) } // ConnMetadata holds metadata for the connection. diff --git a/openshift/tests-extension/vendor/golang.org/x/crypto/ssh/handshake.go b/openshift/tests-extension/vendor/golang.org/x/crypto/ssh/handshake.go index 4be3cbb6de..711a7f7c47 100644 --- a/openshift/tests-extension/vendor/golang.org/x/crypto/ssh/handshake.go +++ b/openshift/tests-extension/vendor/golang.org/x/crypto/ssh/handshake.go @@ -162,7 +162,7 @@ func newClientTransport(conn keyingTransport, clientVersion, serverVersion []byt t.remoteAddr = addr t.hostKeyCallback = config.HostKeyCallback t.bannerCallback = config.BannerCallback - if config.HostKeyAlgorithms != nil { + if len(config.HostKeyAlgorithms) > 0 { t.hostKeyAlgorithms = config.HostKeyAlgorithms } else { t.hostKeyAlgorithms = defaultHostKeyAlgos diff --git a/openshift/tests-extension/vendor/golang.org/x/crypto/ssh/keys.go b/openshift/tests-extension/vendor/golang.org/x/crypto/ssh/keys.go index 64377715e1..fbbfb6cf42 100644 --- a/openshift/tests-extension/vendor/golang.org/x/crypto/ssh/keys.go +++ b/openshift/tests-extension/vendor/golang.org/x/crypto/ssh/keys.go @@ -485,10 +485,11 @@ func parseRSA(in []byte) (out PublicKey, rest []byte, err error) { return nil, nil, err } - // 8192 bits is also the maximum RSA key size accepted by crypto/tls for - // signature verification: - // https://github.com/golang/go/blob/69801b25/src/crypto/tls/handshake_client.go#L1096 - if w.N.BitLen() > 8192 { + // 16384 bits is the largest RSA key OpenSSH will generate (ssh-keygen + // caps -b at 16384), so it is the practical upper bound for keys seen on + // the wire. Rejecting anything larger bounds the CPU spent verifying an + // attacker-supplied key and signature, mitigating a denial of service. + if w.N.BitLen() > 16384 { return nil, nil, errors.New("ssh: rsa modulus too large") } if w.E.BitLen() > 24 { @@ -1669,13 +1670,13 @@ func parseOpenSSHPrivateKey(key []byte, decrypt openSSHDecryptFunc) (crypto.Priv } // Mirror the validation done in parseRSA for public keys: cap the - // modulus at the same limit enforced by crypto/tls, reject oversized - // or invalid exponents, and additionally bound the prime factors to + // modulus at the OpenSSH-generated maximum, reject oversized or + // invalid exponents, and additionally bound the prime factors to // avoid the expensive CRT coefficient recomputation in pk.Precompute. - if key.N.BitLen() > 8192 { + if key.N.BitLen() > 16384 { return nil, errors.New("ssh: rsa modulus too large") } - if key.P.BitLen() > 4096 || key.Q.BitLen() > 4096 { + if key.P.BitLen() > 8192 || key.Q.BitLen() > 8192 { return nil, errors.New("ssh: rsa prime too large") } if key.E.BitLen() > 24 { diff --git a/openshift/tests-extension/vendor/golang.org/x/crypto/ssh/messages.go b/openshift/tests-extension/vendor/golang.org/x/crypto/ssh/messages.go index de86f71cf4..1d23dde259 100644 --- a/openshift/tests-extension/vendor/golang.org/x/crypto/ssh/messages.go +++ b/openshift/tests-extension/vendor/golang.org/x/crypto/ssh/messages.go @@ -44,16 +44,7 @@ type disconnectMsg struct { } func (d *disconnectMsg) Error() string { - return fmt.Sprintf("ssh: disconnect, reason %d: %q", d.Reason, sanitizeString(d.Message)) -} - -func sanitizeString(s string) string { - return strings.Map(func(r rune) rune { - if r == '\t' || (r >= ' ' && r < 0x7f) { - return r - } - return -1 - }, s) + return fmt.Sprintf("ssh: disconnect, reason %d: %q", d.Reason, d.Message) } // See RFC 4253, section 7.1. diff --git a/openshift/tests-extension/vendor/golang.org/x/crypto/ssh/mux.go b/openshift/tests-extension/vendor/golang.org/x/crypto/ssh/mux.go index 5775881c6a..955560bdae 100644 --- a/openshift/tests-extension/vendor/golang.org/x/crypto/ssh/mux.go +++ b/openshift/tests-extension/vendor/golang.org/x/crypto/ssh/mux.go @@ -32,18 +32,21 @@ type chanList struct { offset uint32 } -// Assigns a channel ID to the given channel. -func (c *chanList) add(ch *channel) uint32 { +// add stores the given channel and assigns its localId while holding the +// lock, so that getChan can never return a channel whose localId is not yet +// initialized. +func (c *chanList) add(ch *channel) { c.Lock() defer c.Unlock() for i := range c.chans { if c.chans[i] == nil { c.chans[i] = ch - return uint32(i) + c.offset + ch.localId = uint32(i) + c.offset + return } } c.chans = append(c.chans, ch) - return uint32(len(c.chans)-1) + c.offset + ch.localId = uint32(len(c.chans)-1) + c.offset } // getChan returns the channel for the given ID. @@ -343,8 +346,6 @@ func (m *mux) OpenChannel(chanType string, extra []byte) (Channel, <-chan *Reque func (m *mux) openChannel(chanType string, extra []byte) (*channel, error) { ch := m.newChannel(chanType, channelOutbound, extra) - ch.maxIncomingPayload = channelMaxPacket - open := channelOpenMsg{ ChanType: chanType, PeersWindow: ch.myWindow, diff --git a/openshift/tests-extension/vendor/golang.org/x/crypto/ssh/server.go b/openshift/tests-extension/vendor/golang.org/x/crypto/ssh/server.go index 3c0fcc953e..e090262682 100644 --- a/openshift/tests-extension/vendor/golang.org/x/crypto/ssh/server.go +++ b/openshift/tests-extension/vendor/golang.org/x/crypto/ssh/server.go @@ -26,10 +26,16 @@ type Permissions struct { // defines "force-command" (only allow the given command to // execute) and "source-address" (only allow connections from // the given address). The SSH package currently only enforces - // the "source-address" critical option. It is up to server - // implementations to enforce other critical options, such as - // "force-command", by checking them after the SSH handshake - // is successful. In general, SSH servers should reject + // the "source-address" critical option: it is validated against + // the client's remote address whenever it is present in the + // Permissions returned by any authentication callback. Its value + // is a comma-separated list of IP addresses and CIDR blocks; + // consistently with OpenSSH, a connection whose remote address is + // not an IP address, such as a Unix domain socket, never matches + // the list and is rejected when the option is present. It is up + // to server implementations to enforce other critical options, + // such as "force-command", by checking them after the SSH + // handshake is successful. In general, SSH servers should reject // connections that specify critical options that are unknown // or not supported. CriticalOptions map[string]string @@ -223,7 +229,9 @@ type ServerConfig struct { // Permissions object can be the same object, optionally modified, or a // completely new object. If VerifiedPublicKeyCallback is non-nil, // PublicKeyCallback is not allowed to return a PartialSuccessError, which - // can instead be returned by VerifiedPublicKeyCallback. + // can instead be returned by VerifiedPublicKeyCallback. The + // signatureAlgorithm argument is the format of the signature that was + // successfully verified. // // VerifiedPublicKeyCallback does not affect which authentication methods // are included in the list of methods that can be attempted by the client. @@ -442,6 +450,10 @@ func (s *connection) serverHandshake(config *ServerConfig) (*Permissions, error) return perms, err } +// checkSourceAddress matches addr against sourceAddrs, a comma-separated list +// of IP addresses and CIDR blocks. Consistently with OpenSSH, a remote address +// that is not IP-based, such as a Unix domain socket, never matches the list +// and is rejected. func checkSourceAddress(addr net.Addr, sourceAddrs string) error { if addr == nil { return errors.New("ssh: no address known for client, but source-address match required") @@ -449,7 +461,7 @@ func checkSourceAddress(addr net.Addr, sourceAddrs string) error { tcpAddr, ok := addr.(*net.TCPAddr) if !ok { - return fmt.Errorf("ssh: remote address %v is not an TCP address when checking source-address match", addr) + return fmt.Errorf("ssh: remote address %v is not a TCP address when checking source-address match", addr) } for _, sourceAddr := range strings.Split(sourceAddrs, ",") { @@ -472,6 +484,21 @@ func checkSourceAddress(addr net.Addr, sourceAddrs string) error { return fmt.Errorf("ssh: remote address %v is not allowed because of source-address restriction", addr) } +// checkSourceAddressCriticalOption enforces the source-address critical +// option, if present in perms, as documented in Permissions.CriticalOptions. +// A present but empty value matches no address, so it denies authentication, +// consistently with OpenSSH, rather than being treated as absent. +func checkSourceAddressCriticalOption(addr net.Addr, perms *Permissions) error { + if perms == nil { + return nil + } + saco, ok := perms.CriticalOptions[sourceAddressCriticalOption] + if !ok { + return nil + } + return checkSourceAddress(addr, saco) +} + func gssExchangeToken(gssapiConfig *GSSAPIWithMICConfig, token []byte, s *connection, sessionID []byte, userAuthReq userAuthRequestMsg) (authErr error, perms *Permissions, err error) { gssAPIServer := gssapiConfig.Server @@ -685,7 +712,7 @@ userAuthLoop: } if userAuthReq.Service != serviceSSH { - return nil, errors.New("ssh: client attempted to negotiate for unknown service: " + userAuthReq.Service) + return nil, fmt.Errorf("ssh: client attempted to negotiate for unknown service: %q", userAuthReq.Service) } if s.user != userAuthReq.User && partialSuccessReturned { @@ -771,7 +798,8 @@ userAuthLoop: pubKey, err := ParsePublicKey(pubKeyData) if err != nil { - return nil, err + authErr = err + break } candidate, ok := cache.get(s.user, pubKeyData) @@ -784,13 +812,14 @@ userAuthLoop: return nil, errors.New("ssh: invalid library usage: PublicKeyCallback must not return partial success when VerifiedPublicKeyCallback is defined") } - if (candidate.result == nil || isPartialSuccessError) && - candidate.perms != nil && - candidate.perms.CriticalOptions != nil && - candidate.perms.CriticalOptions[sourceAddressCriticalOption] != "" { - if err := checkSourceAddress( - s.RemoteAddr(), - candidate.perms.CriticalOptions[sourceAddressCriticalOption]); err != nil { + // This check is authoritative for the Permissions returned by + // PublicKeyCallback: the check at the end of the auth loop sees + // the final Permissions, which VerifiedPublicKeyCallback may + // have replaced, and is skipped on partial success. It also + // makes public key queries fail before the client signs when + // PublicKeyCallback supplies the restriction. + if candidate.result == nil || isPartialSuccessError { + if err := checkSourceAddressCriticalOption(s.RemoteAddr(), candidate.perms); err != nil { candidate.result = err } } @@ -864,14 +893,7 @@ userAuthLoop: // Only call VerifiedPublicKeyCallback after the key has been accepted // and successfully verified. If authErr is non-nil, the key is not // considered verified and the callback must not run. - perms, authErr = config.VerifiedPublicKeyCallback(s, pubKey, perms, algo) - } - if authErr == nil && perms != nil && perms.CriticalOptions != nil { - if saco := perms.CriticalOptions[sourceAddressCriticalOption]; saco != "" { - if err := checkSourceAddress(s.RemoteAddr(), saco); err != nil { - authErr = err - } - } + perms, authErr = config.VerifiedPublicKeyCallback(s, pubKey, perms, sig.Format) } } case "gssapi-with-mic": @@ -925,6 +947,17 @@ userAuthLoop: authErr = fmt.Errorf("ssh: unknown method %q", userAuthReq.Method) } + // The source-address critical option is enforced on the Permissions + // returned by any authentication callback. Permissions returned + // together with a PartialSuccessError skip this check: that is safe + // because they are required to be nil, as enforced in the partial + // success handling below. + if authErr == nil { + if err := checkSourceAddressCriticalOption(s.RemoteAddr(), perms); err != nil { + authErr = err + } + } + authErrs = append(authErrs, authErr) if config.AuthLogCallback != nil { diff --git a/openshift/tests-extension/vendor/golang.org/x/crypto/ssh/ssh_gss.go b/openshift/tests-extension/vendor/golang.org/x/crypto/ssh/ssh_gss.go index a6249a1227..a7a099754f 100644 --- a/openshift/tests-extension/vendor/golang.org/x/crypto/ssh/ssh_gss.go +++ b/openshift/tests-extension/vendor/golang.org/x/crypto/ssh/ssh_gss.go @@ -118,24 +118,28 @@ func parseGSSAPIPayload(payload []byte) (*userAuthRequestGSSAPI, error) { OIDS: make([]asn1.ObjectIdentifier, n), } for i := 0; i < int(n); i++ { - var ( - desiredMech []byte - err error - ) + var desiredMech []byte desiredMech, rest, ok = parseString(rest) if !ok { return nil, errors.New("parse string failed") } - if rest, err = asn1.Unmarshal(desiredMech, &s.OIDS[i]); err != nil { + trailing, err := asn1.Unmarshal(desiredMech, &s.OIDS[i]) + if err != nil { return nil, err } + if len(trailing) != 0 { + return nil, errors.New("trailing bytes after OID") + } + } + if len(rest) != 0 { + return nil, errors.New("trailing bytes after mechanisms") } return s, nil } // See RFC 4462 section 3.6. func buildMIC(sessionID string, username string, service string, authMethod string) []byte { - out := make([]byte, 0, 0) + out := make([]byte, 0) out = appendString(out, sessionID) out = append(out, msgUserAuthRequest) out = appendString(out, username) diff --git a/openshift/tests-extension/vendor/golang.org/x/crypto/ssh/streamlocal.go b/openshift/tests-extension/vendor/golang.org/x/crypto/ssh/streamlocal.go index 152470fcb7..8e997da3db 100644 --- a/openshift/tests-extension/vendor/golang.org/x/crypto/ssh/streamlocal.go +++ b/openshift/tests-extension/vendor/golang.org/x/crypto/ssh/streamlocal.go @@ -58,6 +58,7 @@ func (c *Client) dialStreamLocal(socketPath string) (Channel, error) { return nil, err } go DiscardRequests(in) + go io.Copy(io.Discard, ch.Stderr()) return ch, err } @@ -79,6 +80,7 @@ func (l *unixListener) Accept() (net.Conn, error) { return nil, err } go DiscardRequests(incoming) + go io.Copy(io.Discard, ch.Stderr()) return &chanConn{ Channel: ch, diff --git a/openshift/tests-extension/vendor/golang.org/x/crypto/ssh/tcpip.go b/openshift/tests-extension/vendor/golang.org/x/crypto/ssh/tcpip.go index 78c41fe5a1..213d8a614a 100644 --- a/openshift/tests-extension/vendor/golang.org/x/crypto/ssh/tcpip.go +++ b/openshift/tests-extension/vendor/golang.org/x/crypto/ssh/tcpip.go @@ -332,6 +332,7 @@ func (l *tcpListener) Accept() (net.Conn, error) { return nil, err } go DiscardRequests(incoming) + go io.Copy(io.Discard, ch.Stderr()) return &chanConn{ Channel: ch, @@ -495,6 +496,7 @@ func (c *Client) dial(laddr string, lport int, raddr string, rport int) (Channel return nil, err } go DiscardRequests(in) + go io.Copy(io.Discard, ch.Stderr()) return ch, nil } diff --git a/openshift/tests-extension/vendor/golang.org/x/net/http2/hpack/encode.go b/openshift/tests-extension/vendor/golang.org/x/net/http2/hpack/encode.go index 46219da2b0..e6d0c265ac 100644 --- a/openshift/tests-extension/vendor/golang.org/x/net/http2/hpack/encode.go +++ b/openshift/tests-extension/vendor/golang.org/x/net/http2/hpack/encode.go @@ -39,7 +39,6 @@ func NewEncoder(w io.Writer) *Encoder { tableSizeUpdate: false, w: w, } - e.dynTab.table.init() e.dynTab.setMaxSize(initialHeaderTableSize) return e } diff --git a/openshift/tests-extension/vendor/golang.org/x/net/http2/hpack/hpack.go b/openshift/tests-extension/vendor/golang.org/x/net/http2/hpack/hpack.go index 7a1d976696..ecd3eeca99 100644 --- a/openshift/tests-extension/vendor/golang.org/x/net/http2/hpack/hpack.go +++ b/openshift/tests-extension/vendor/golang.org/x/net/http2/hpack/hpack.go @@ -105,7 +105,6 @@ func NewDecoder(maxDynamicTableSize uint32, emitFunc func(f HeaderField)) *Decod emitEnabled: true, firstField: true, } - d.dynTab.table.init() d.dynTab.allowedMaxSize = maxDynamicTableSize d.dynTab.setMaxSize(maxDynamicTableSize) return d diff --git a/openshift/tests-extension/vendor/golang.org/x/net/http2/hpack/tables.go b/openshift/tests-extension/vendor/golang.org/x/net/http2/hpack/tables.go index 8cbdf3f019..3bd7eb7533 100644 --- a/openshift/tests-extension/vendor/golang.org/x/net/http2/hpack/tables.go +++ b/openshift/tests-extension/vendor/golang.org/x/net/http2/hpack/tables.go @@ -31,10 +31,18 @@ type headerFieldTable struct { // byName maps a HeaderField name to the unique id of the newest entry with // the same name. See above for a definition of "unique id". + // + // byName and byNameValue are used only by search, which is only called + // for tables used by encoders. For tables used only by decoders, the + // maps are never built, as a memory optimization for servers with many + // mostly-idle connections, each pinning a dynamic table. The maps are + // built lazily by the first search call and are nil until then. The two + // maps are always both nil or both non-nil. byName map[string]uint64 // byNameValue maps a HeaderField name/value pair to the unique id of the newest // entry with the same name and value. See above for a definition of "unique id". + // See byName for when this map is non-nil. byNameValue map[pairNameValue]uint64 } @@ -42,9 +50,17 @@ type pairNameValue struct { name, value string } -func (t *headerFieldTable) init() { - t.byName = make(map[string]uint64) - t.byNameValue = make(map[pairNameValue]uint64) +// buildMaps initializes byName and byNameValue from ents. +func (t *headerFieldTable) buildMaps() { + t.byName = make(map[string]uint64, len(t.ents)) + t.byNameValue = make(map[pairNameValue]uint64, len(t.ents)) + for k, f := range t.ents { + // Map to the newest matching entry: later (newer) entries + // overwrite earlier ones, matching addEntry's behavior. + id := t.evictCount + uint64(k) + 1 + t.byName[f.Name] = id + t.byNameValue[pairNameValue{f.Name, f.Value}] = id + } } // len reports the number of entries in the table. @@ -54,9 +70,11 @@ func (t *headerFieldTable) len() int { // addEntry adds a new entry. func (t *headerFieldTable) addEntry(f HeaderField) { - id := uint64(t.len()) + t.evictCount + 1 - t.byName[f.Name] = id - t.byNameValue[pairNameValue{f.Name, f.Value}] = id + if t.byName != nil { + id := uint64(t.len()) + t.evictCount + 1 + t.byName[f.Name] = id + t.byNameValue[pairNameValue{f.Name, f.Value}] = id + } t.ents = append(t.ents, f) } @@ -65,14 +83,16 @@ func (t *headerFieldTable) evictOldest(n int) { if n > t.len() { panic(fmt.Sprintf("evictOldest(%v) on table with %v entries", n, t.len())) } - for k := 0; k < n; k++ { - f := t.ents[k] - id := t.evictCount + uint64(k) + 1 - if t.byName[f.Name] == id { - delete(t.byName, f.Name) - } - if p := (pairNameValue{f.Name, f.Value}); t.byNameValue[p] == id { - delete(t.byNameValue, p) + if t.byName != nil { + for k := 0; k < n; k++ { + f := t.ents[k] + id := t.evictCount + uint64(k) + 1 + if t.byName[f.Name] == id { + delete(t.byName, f.Name) + } + if p := (pairNameValue{f.Name, f.Value}); t.byNameValue[p] == id { + delete(t.byNameValue, p) + } } } copy(t.ents, t.ents[n:]) @@ -100,6 +120,9 @@ func (t *headerFieldTable) evictOldest(n int) { // // See Section 2.3.3. func (t *headerFieldTable) search(f HeaderField) (i uint64, nameValueMatch bool) { + if t.byName == nil { + t.buildMaps() + } if !f.Sensitive { if id := t.byNameValue[pairNameValue{f.Name, f.Value}]; id != 0 { return t.idToIndex(id), true diff --git a/openshift/tests-extension/vendor/golang.org/x/net/http2/transport_wrap.go b/openshift/tests-extension/vendor/golang.org/x/net/http2/transport_wrap.go index 534e77ab96..741fb97062 100644 --- a/openshift/tests-extension/vendor/golang.org/x/net/http2/transport_wrap.go +++ b/openshift/tests-extension/vendor/golang.org/x/net/http2/transport_wrap.go @@ -237,32 +237,40 @@ type ClientConn struct { } func (cc *ClientConn) roundTrip(req *http.Request) (*http.Response, error) { - err := func() error { + haveReservation, err := func() (bool, error) { cc.mu.Lock() defer cc.mu.Unlock() if cc.doNotReuse { - return errClientConnUnusable - } - cc.roundTrips++ - if cc.reserved > 0 { - // We've already reserved a concurrency slot for this request. - cc.reserved-- - } else if cc.cc.Reserve() != nil { - // We don't seem to have an available concurrency slot, - // so bump the pending count (requests waiting for a slot). - cc.pending++ + return false, errClientConnUnusable } + // ClientConn.Shutdown will not shut down the conn while // cc.starting > 0 or cc.cc.InFlight() > 0. // // The starting state covers the gap between us deciding to // start sending the request, and actually sending it. cc.starting++ - return nil + + cc.roundTrips++ + if cc.reserved == 0 { + // We do not have a concurrency slot reserved for this request. + return false, nil + } + cc.reserved-- + return true, nil }() if err != nil { return nil, err } + // If we have no reservation, try to acquire one. + // (This must be done without cc.mu held, since Reserve may call back to the state hook.) + if !haveReservation && cc.cc.Reserve() != nil { + // We could not acquire a concurrency slot, so bump the pending count + // (requests waiting for a slot). + cc.mu.Lock() + cc.pending++ + cc.mu.Unlock() + } resp, err := cc.cc.RoundTrip(req) cc.mu.Lock() cc.starting-- @@ -293,16 +301,21 @@ func (cc *ClientConn) ping(ctx context.Context) error { } func (cc *ClientConn) reserveNewRequest() bool { + if err := cc.cc.Reserve(); err != nil { + return false + } + reserved := true cc.mu.Lock() - defer cc.mu.Unlock() if cc.doNotReuse { - return false + reserved = false + } else { + cc.reserved++ } - if err := cc.cc.Reserve(); err != nil { - return false + cc.mu.Unlock() + if !reserved { + cc.cc.Release() } - cc.reserved++ - return true + return reserved } func (cc *ClientConn) setDoNotReuse() { diff --git a/openshift/tests-extension/vendor/golang.org/x/tools/go/ast/inspector/cursor.go b/openshift/tests-extension/vendor/golang.org/x/tools/go/ast/inspector/cursor.go index 239b10c4da..1c482252da 100644 --- a/openshift/tests-extension/vendor/golang.org/x/tools/go/ast/inspector/cursor.go +++ b/openshift/tests-extension/vendor/golang.org/x/tools/go/ast/inspector/cursor.go @@ -10,6 +10,7 @@ import ( "go/token" "iter" "reflect" + "strings" "golang.org/x/tools/go/ast/edge" ) @@ -110,6 +111,46 @@ func (c Cursor) String() string { return reflect.TypeOf(c.Node()).String() } +// GoString returns a string describing the cursor's path from the +// root, if any. +func (c Cursor) GoString() string { + if !c.Valid() { + return "(invalid)" + } + if c.index < 0 { + return "(root)" + } + // e.g "File.Decls[1].(*ast.GenDecl).Specs[0].(*ast.TypeSpec)" + // + // In hindsight even the File node should have reported a + // virtual ParentEdge of (Root_Files, i) where i is the index + // among the files passed to NewInspector. Then the path would + // read "(root).Files[i]", etc; but we missed the boat. + var buf strings.Builder + buf.WriteString("File") + var visit func(Cursor) + visit = func(c Cursor) { + ek, idx := c.ParentEdge() + if ek == edge.Invalid { + return // File + } + visit(c.Parent()) + fmt.Fprintf(&buf, ".%s", ek.FieldName()) + if idx >= 0 { + fmt.Fprintf(&buf, "[%d]", idx) + } + ftype := ek.FieldType() + if idx >= 0 { + ftype = ftype.Elem() // []T -> T + } + if ftype.Kind() == reflect.Interface { + fmt.Fprintf(&buf, ".(%T)", c.Node()) + } + } + visit(c) + return buf.String() +} + // indices return the [start, end) half-open interval of event indices. func (c Cursor) indices() (int32, int32) { if c.index < 0 { diff --git a/openshift/tests-extension/vendor/google.golang.org/grpc/clientconn.go b/openshift/tests-extension/vendor/google.golang.org/grpc/clientconn.go index c4bca5203e..b27c7e84a3 100644 --- a/openshift/tests-extension/vendor/google.golang.org/grpc/clientconn.go +++ b/openshift/tests-extension/vendor/google.golang.org/grpc/clientconn.go @@ -24,12 +24,10 @@ import ( "fmt" "math" "net/url" - "os" "slices" "strings" "sync" "sync/atomic" - "syscall" "time" "google.golang.org/grpc/balancer" @@ -1573,26 +1571,13 @@ func (ac *addrConn) createTransport(ctx context.Context, addr resolver.Address, // to the provided transport.GoAwayInfo, as specified by gRFC A94: // https://github.com/grpc/proposal/blob/master/A94-grpc-subchannel-disconnections-metrics.md func disconnectErrorString(info transport.GoAwayInfo) string { - err := info.Err - var sysErr syscall.Errno - switch { - case info.Reason != transport.GoAwayInvalid: + if info.Reason != transport.GoAwayInvalid { return fmt.Sprintf("GOAWAY %s", info.GoAwayCode.String()) - case err == nil: - return "unknown" - case errors.Is(err, context.Canceled): - return "subchannel shutdown" - case errors.Is(err, syscall.ECONNRESET): - return "connection reset" - case errors.Is(err, syscall.ETIMEDOUT), errors.Is(err, context.DeadlineExceeded), errors.Is(err, os.ErrDeadlineExceeded): - return "connection timed out" - case errors.Is(err, syscall.ECONNABORTED): - return "connection aborted" - case errors.As(err, &sysErr): - return "socket error" - default: + } + if info.Err == nil { return "unknown" } + return disconnectErrorLabel(info.Err) } // startHealthCheck starts the health checking stream (RPC) to watch the health diff --git a/openshift/tests-extension/vendor/google.golang.org/grpc/clientconn_disconnect_reason_noplan9.go b/openshift/tests-extension/vendor/google.golang.org/grpc/clientconn_disconnect_reason_noplan9.go new file mode 100644 index 0000000000..f0fcd88423 --- /dev/null +++ b/openshift/tests-extension/vendor/google.golang.org/grpc/clientconn_disconnect_reason_noplan9.go @@ -0,0 +1,48 @@ +//go:build !plan9 + +/* + * + * Copyright 2026 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package grpc + +import ( + "context" + "errors" + "os" + "syscall" +) + +// disconnectErrorLabel returns the grpc.disconnect_error metric label for a +// transport error, as specified by gRFC A94. +func disconnectErrorLabel(err error) string { + var sysErr syscall.Errno + switch { + case errors.Is(err, context.Canceled): + return "subchannel shutdown" + case errors.Is(err, syscall.ECONNRESET): + return "connection reset" + case errors.Is(err, syscall.ETIMEDOUT), errors.Is(err, context.DeadlineExceeded), errors.Is(err, os.ErrDeadlineExceeded): + return "connection timed out" + case errors.Is(err, syscall.ECONNABORTED): + return "connection aborted" + case errors.As(err, &sysErr): + return "socket error" + default: + return "unknown" + } +} diff --git a/openshift/tests-extension/vendor/google.golang.org/grpc/clientconn_disconnect_reason_plan9.go b/openshift/tests-extension/vendor/google.golang.org/grpc/clientconn_disconnect_reason_plan9.go new file mode 100644 index 0000000000..930b12664c --- /dev/null +++ b/openshift/tests-extension/vendor/google.golang.org/grpc/clientconn_disconnect_reason_plan9.go @@ -0,0 +1,39 @@ +/* + * + * Copyright 2026 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package grpc + +import ( + "context" + "errors" + "os" +) + +// disconnectErrorLabel returns the grpc.disconnect_error metric label for a +// transport error, as specified by gRFC A94. syscall.Errno does not exist on +// plan9, so only the portable classifications are available. +func disconnectErrorLabel(err error) string { + switch { + case errors.Is(err, context.Canceled): + return "subchannel shutdown" + case errors.Is(err, context.DeadlineExceeded), errors.Is(err, os.ErrDeadlineExceeded): + return "connection timed out" + default: + return "unknown" + } +} diff --git a/openshift/tests-extension/vendor/google.golang.org/grpc/internal/envconfig/envconfig.go b/openshift/tests-extension/vendor/google.golang.org/grpc/internal/envconfig/envconfig.go index 29d332e7b6..3334481274 100644 --- a/openshift/tests-extension/vendor/google.golang.org/grpc/internal/envconfig/envconfig.go +++ b/openshift/tests-extension/vendor/google.golang.org/grpc/internal/envconfig/envconfig.go @@ -150,8 +150,18 @@ var ( // throttling limit if unforeseen issues arise, and it will be removed in a // future release. // - // TODO: Remove this env var once v1.83.0 is release. + // TODO: Remove this env var once v1.83.0 is released. ControlBufferThrottleLimit = uint64FromEnv("GRPC_GO_EXPERIMENTAL_CONTROL_BUFFER_THROTTLE_LIMIT", 100, 1, 10000) + + // EnableReceiveBufferCompaction enables the compaction of data buffers + // to reduce the number of buffers in the receive buffer. + // + // This environment variable serves as an escape hatch to disable the + // feature if unforeseen issues arise, and it will be removed in a future + // release. + // + // TODO: Remove this env var once v1.85.0 is released. + EnableReceiveBufferCompaction = boolFromEnv("GRPC_GO_EXPERIMENTAL_ENABLE_RECEIVE_BUFFER_COMPACTION", true) ) func boolFromEnv(envVar string, def bool) bool { diff --git a/openshift/tests-extension/vendor/google.golang.org/grpc/internal/envconfig/xds.go b/openshift/tests-extension/vendor/google.golang.org/grpc/internal/envconfig/xds.go index a2312f8eac..e4b6919138 100644 --- a/openshift/tests-extension/vendor/google.golang.org/grpc/internal/envconfig/xds.go +++ b/openshift/tests-extension/vendor/google.golang.org/grpc/internal/envconfig/xds.go @@ -69,9 +69,8 @@ var ( // https://github.com/grpc/proposal/blob/master/A87-mtls-spiffe-support.md XDSSPIFFEEnabled = boolFromEnv("GRPC_EXPERIMENTAL_XDS_MTLS_SPIFFE", false) - // XDSHTTPConnectEnabled is true if gRPC should parse custom Metadata - // configuring use of an HTTP CONNECT proxy via xDS from cluster resources. - // For more details, see: + // XDSHTTPConnectEnabled controls support for dynamic HTTP CONNECT proxying + // configured via the xDS control plane. For more details, see: // https://github.com/grpc/proposal/blob/master/A86-xds-http-connect.md XDSHTTPConnectEnabled = boolFromEnv("GRPC_EXPERIMENTAL_XDS_HTTP_CONNECT", false) @@ -88,7 +87,7 @@ var ( // XDSORCAToLRSPropEnabled controls whether ORCA metrics are explicitly // filtered and prefix-propagated to the LRS server. For more details, see: // https://github.com/grpc/proposal/blob/master/A85-lrs-custom-metrics-changes.md - XDSORCAToLRSPropEnabled = boolFromEnv("GRPC_EXPERIMENTAL_XDS_ORCA_LRS_PROPAGATION", false) + XDSORCAToLRSPropEnabled = boolFromEnv("GRPC_EXPERIMENTAL_XDS_ORCA_LRS_PROPAGATION", true) // XDSClientExtProcEnabled indicates whether ExtProc filter is enabled on // the client side. For more details, see: diff --git a/openshift/tests-extension/vendor/google.golang.org/grpc/internal/grpcsync/callback_serializer.go b/openshift/tests-extension/vendor/google.golang.org/grpc/internal/grpcsync/callback_serializer.go index 9b6d8a1fa3..d4999fcca8 100644 --- a/openshift/tests-extension/vendor/google.golang.org/grpc/internal/grpcsync/callback_serializer.go +++ b/openshift/tests-extension/vendor/google.golang.org/grpc/internal/grpcsync/callback_serializer.go @@ -20,10 +20,15 @@ package grpcsync import ( "context" + "errors" "google.golang.org/grpc/internal/buffer" ) +// ErrSerializerClosed is returned by ScheduleAndWait if the CallbackSerializer +// was closed before the callback could be scheduled. +var ErrSerializerClosed = errors.New("callback serializer is closed") + // CallbackSerializer provides a mechanism to schedule callbacks in a // synchronized manner. It provides a FIFO guarantee on the order of execution // of scheduled callbacks. New callbacks can be scheduled by invoking the @@ -77,6 +82,27 @@ func (cs *CallbackSerializer) ScheduleOr(f func(ctx context.Context), onFailure } } +// ScheduleAndWait schedules the provided callback function f to be executed in +// the order it was added and blocks until f has run. If the context passed to +// NewCallbackSerializer was canceled before this method is called, f is not run +// and ScheduleAndWait returns ErrSerializerClosed. +// +// Callbacks are expected to honor the context when performing any blocking +// operations, and should return early when the context is canceled. +func (cs *CallbackSerializer) ScheduleAndWait(f func(ctx context.Context)) error { + done := make(chan struct{}) + var err error + cs.ScheduleOr(func(ctx context.Context) { + f(ctx) + close(done) + }, func() { + err = ErrSerializerClosed + close(done) + }) + <-done + return err +} + func (cs *CallbackSerializer) run(ctx context.Context) { defer close(cs.done) diff --git a/openshift/tests-extension/vendor/google.golang.org/grpc/internal/mem/buffer_pool.go b/openshift/tests-extension/vendor/google.golang.org/grpc/internal/mem/buffer_pool.go index 2d83b2eced..00aeca419f 100644 --- a/openshift/tests-extension/vendor/google.golang.org/grpc/internal/mem/buffer_pool.go +++ b/openshift/tests-extension/vendor/google.golang.org/grpc/internal/mem/buffer_pool.go @@ -26,12 +26,26 @@ import ( "slices" "sort" "sync" + + "google.golang.org/grpc/internal" ) const ( goPageSize = 4 * 1024 // 4KiB. N.B. this must be a power of 2. ) +var ( + // BufferPoolingThreshold is the minimum size of a buffer that can be pooled. + // This is used to determine whether to pool buffers or allocate them directly. + BufferPoolingThreshold = 1 << 10 +) + +func init() { + internal.SetBufferPoolingThresholdForTesting = func(threshold int) { + BufferPoolingThreshold = threshold + } +} + var uintSize = bits.UintSize // use a variable for mocking during tests. // bufferPool is a copy of the public bufferPool interface used to avoid diff --git a/openshift/tests-extension/vendor/google.golang.org/grpc/internal/resolver/config_selector.go b/openshift/tests-extension/vendor/google.golang.org/grpc/internal/resolver/config_selector.go index 6320e9b576..238950bbbf 100644 --- a/openshift/tests-extension/vendor/google.golang.org/grpc/internal/resolver/config_selector.go +++ b/openshift/tests-extension/vendor/google.golang.org/grpc/internal/resolver/config_selector.go @@ -24,7 +24,6 @@ import ( "sync" "google.golang.org/grpc/internal/serviceconfig" - "google.golang.org/grpc/metadata" "google.golang.org/grpc/resolver" ) @@ -52,82 +51,7 @@ type RPCConfig struct { Context context.Context MethodConfig serviceconfig.MethodConfig // configuration to use for this RPC OnCommitted func() // Called when the RPC has been committed (retries no longer possible) - Interceptor ClientInterceptor -} - -// ClientStream is the same as grpc.ClientStream, but defined here for circular -// dependency reasons. -type ClientStream interface { - // Header returns the header metadata received from the server if there - // is any. It blocks if the metadata is not ready to read. - Header() (metadata.MD, error) - // Trailer returns the trailer metadata from the server, if there is any. - // It must only be called after stream.CloseAndRecv has returned, or - // stream.Recv has returned a non-nil error (including io.EOF). - Trailer() metadata.MD - // CloseSend closes the send direction of the stream. It closes the stream - // when non-nil error is met. It is also not safe to call CloseSend - // concurrently with SendMsg. - CloseSend() error - // Context returns the context for this stream. - // - // It should not be called until after Header or RecvMsg has returned. Once - // called, subsequent client-side retries are disabled. - Context() context.Context - // SendMsg is generally called by generated code. On error, SendMsg aborts - // the stream. If the error was generated by the client, the status is - // returned directly; otherwise, io.EOF is returned and the status of - // the stream may be discovered using RecvMsg. - // - // SendMsg blocks until: - // - There is sufficient flow control to schedule m with the transport, or - // - The stream is done, or - // - The stream breaks. - // - // SendMsg does not wait until the message is received by the server. An - // untimely stream closure may result in lost messages. To ensure delivery, - // users should ensure the RPC completed successfully using RecvMsg. - // - // It is safe to have a goroutine calling SendMsg and another goroutine - // calling RecvMsg on the same stream at the same time, but it is not safe - // to call SendMsg on the same stream in different goroutines. It is also - // not safe to call CloseSend concurrently with SendMsg. - SendMsg(m any) error - // RecvMsg blocks until it receives a message into m or the stream is - // done. It returns io.EOF when the stream completes successfully. On - // any other error, the stream is aborted and the error contains the RPC - // status. - // - // It is safe to have a goroutine calling SendMsg and another goroutine - // calling RecvMsg on the same stream at the same time, but it is not - // safe to call RecvMsg on the same stream in different goroutines. - RecvMsg(m any) error -} - -// ClientInterceptor is an interceptor for gRPC client streams. -type ClientInterceptor interface { - // NewStream creates a ClientStream for an RPC. - // - // Implementations must delegate stream creation to the provided newStream - // function. To intercept or override stream behavior, implementations - // may wrap the ClientStream returned by the delegate. - // - // Note: RPCInfo.Context is currently unused and will be nil. - // - // The done function is invoked when the RPC has finished using its - // underlying connection or if a connection could not be assigned. Because - // interceptors operate at the application layer, RPC operations may - // continue on the ClientStream even after done has been called. The - // caller must ensure done is non-nil. - // - // To ensure RPC completion notifications propagate through the entire - // interceptor chain, implementations must ensure that the done function - // passed to the delegate newStream invokes the done function passed to - // NewStream. - NewStream(ctx context.Context, ri RPCInfo, done func(), newStream func(ctx context.Context, done func()) (ClientStream, error)) (ClientStream, error) - // Close closes the interceptor. Once called, no new calls to NewStream are - // accepted. Ongoing calls to NewStream are allowed to complete. - Close() + Interceptor any } // ServerInterceptor is an interceptor for incoming RPC's on gRPC server side. diff --git a/openshift/tests-extension/vendor/google.golang.org/grpc/internal/transport/client_stream.go b/openshift/tests-extension/vendor/google.golang.org/grpc/internal/transport/client_stream.go index ad382b0fda..046f0a5557 100644 --- a/openshift/tests-extension/vendor/google.golang.org/grpc/internal/transport/client_stream.go +++ b/openshift/tests-extension/vendor/google.golang.org/grpc/internal/transport/client_stream.go @@ -39,9 +39,8 @@ const nonGRPCDataMaxLen = 1024 type ClientStream struct { Stream // Embed for common stream functionality. - ct *http2Client - done chan struct{} // closed at the end of stream to unblock writers. - doneFunc func() // invoked at the end of stream. + ct *http2Client + done chan struct{} // closed at the end of stream to unblock writers. headerChan chan struct{} // closed to indicate the end of header metadata. header metadata.MD // the received header metadata diff --git a/openshift/tests-extension/vendor/google.golang.org/grpc/internal/transport/handler_server.go b/openshift/tests-extension/vendor/google.golang.org/grpc/internal/transport/handler_server.go index a8356c9adb..9cd8d28d33 100644 --- a/openshift/tests-extension/vendor/google.golang.org/grpc/internal/transport/handler_server.go +++ b/openshift/tests-extension/vendor/google.golang.org/grpc/internal/transport/handler_server.go @@ -424,7 +424,7 @@ func (ht *serverHandlerTransport) HandleStreams(ctx context.Context, startStream st: ht, headerWireLength: 0, // won't have access to header wire length until golang/go#18997. } - s.Stream.buf.init() + s.Stream.buf.init(ht.bufferPool) s.readRequester = s s.trReader = transportReader{ reader: recvBufferReader{ctx: s.ctx, ctxDone: s.ctx.Done(), recv: &s.buf}, diff --git a/openshift/tests-extension/vendor/google.golang.org/grpc/internal/transport/http2_client.go b/openshift/tests-extension/vendor/google.golang.org/grpc/internal/transport/http2_client.go index 822c09ba62..10d1977415 100644 --- a/openshift/tests-extension/vendor/google.golang.org/grpc/internal/transport/http2_client.go +++ b/openshift/tests-extension/vendor/google.golang.org/grpc/internal/transport/http2_client.go @@ -498,10 +498,9 @@ func (t *http2Client) newStream(ctx context.Context, callHdr *CallHdr, handler s ct: t, done: make(chan struct{}), headerChan: make(chan struct{}), - doneFunc: callHdr.DoneFunc, statsHandler: handler, } - s.Stream.buf.init() + s.Stream.buf.init(t.bufferPool) s.Stream.wq.init(defaultWriteQuota, s.done) s.readRequester = s // The client side stream context should have exactly the same life cycle with the user provided context. @@ -998,9 +997,6 @@ func (t *http2Client) closeStream(s *ClientStream, err error, rst bool, rstCode t.controlBuf.executeAndPut(addBackStreamQuota, cleanup) // This will unblock write. close(s.done) - if s.doneFunc != nil { - s.doneFunc() - } } // Close kicks off the shutdown process of the transport. This should be called diff --git a/openshift/tests-extension/vendor/google.golang.org/grpc/internal/transport/http2_server.go b/openshift/tests-extension/vendor/google.golang.org/grpc/internal/transport/http2_server.go index be8ae9f9c5..63c6539a3d 100644 --- a/openshift/tests-extension/vendor/google.golang.org/grpc/internal/transport/http2_server.go +++ b/openshift/tests-extension/vendor/google.golang.org/grpc/internal/transport/http2_server.go @@ -407,7 +407,7 @@ func (t *http2Server) operateHeaders(ctx context.Context, frame *http2.MetaHeade st: t, headerWireLength: int(frame.Header().Length), } - s.Stream.buf.init() + s.Stream.buf.init(t.bufferPool) var ( // if false, content-type was missing or invalid isGRPC = false diff --git a/openshift/tests-extension/vendor/google.golang.org/grpc/internal/transport/transport.go b/openshift/tests-extension/vendor/google.golang.org/grpc/internal/transport/transport.go index 6dfae39849..5fc901e5cf 100644 --- a/openshift/tests-extension/vendor/google.golang.org/grpc/internal/transport/transport.go +++ b/openshift/tests-extension/vendor/google.golang.org/grpc/internal/transport/transport.go @@ -30,11 +30,14 @@ import ( "sync" "sync/atomic" "time" + "unsafe" "golang.org/x/net/http2" "google.golang.org/grpc/codes" "google.golang.org/grpc/credentials" "google.golang.org/grpc/internal/channelz" + "google.golang.org/grpc/internal/envconfig" + imem "google.golang.org/grpc/internal/mem" "google.golang.org/grpc/internal/transport/internal" "google.golang.org/grpc/keepalive" "google.golang.org/grpc/mem" @@ -45,7 +48,30 @@ import ( "google.golang.org/grpc/tap" ) -const logLevel = 2 +const ( + logLevel = 2 + // recvMsgSize estimates the memory overhead of a recvMsg in the backlog. + // It accounts for the recvMsg struct itself and the slice header of the + // underlying buffer's data. + recvMsgSize = int(unsafe.Sizeof(recvMsg{}) + unsafe.Sizeof([]byte{})) + + // utilizationFactor controls when we consider memory utilization acceptable. + // When backlogHeapSize / payloadSize <= utilizationFactor (meaning at least + // 50% of the heap memory is actual payload data), compaction is skipped. + utilizationFactor = 2 +) + +var ( + // compactionThreshold is approx 57KB (on 64-bit systems). It allows + // accumulating up to 1024 1-byte payloads before triggering compaction. + // + // Because individual payloads <= 1024 bytes are allocated on the heap + // outside mem.BufferPool, waiting for at least 1024 bytes to accumulate + // ensures that compaction coalesces those small heap allocations into a + // single large buffer from mem.BufferPool, enabling buffer reuse while + // avoiding frequent copying for small bursts of frames. + compactionThreshold = imem.BufferPoolingThreshold * (recvMsgSize + 1) +) func init() { internal.TimeNowFunc = func() int64 { return time.Now().UnixNano() } @@ -71,23 +97,31 @@ type recvBuffer struct { c chan recvMsg mu sync.Mutex backlog []recvMsg - err error + // uncompactedSuffixLen tracks the number of consecutive data messages at + // the tail of backlog that have not been compacted. + uncompactedSuffixLen int + // uncompactedBytes tracks the total payload bytes across the trailing + // uncompactedSuffixLen messages. + uncompactedBytes int + err error + bufPool mem.BufferPool } // init allows a recvBuffer to be initialized in-place, which is useful // for resetting a buffer or for avoiding a heap allocation when the buffer // is embedded in another struct. -func (b *recvBuffer) init() { +func (b *recvBuffer) init(pool mem.BufferPool) { b.c = make(chan recvMsg, 1) + b.bufPool = pool } func (b *recvBuffer) put(r recvMsg) { b.mu.Lock() + defer b.mu.Unlock() if b.err != nil { // drop the buffer on the floor. Since b.err is not nil, any subsequent reads // will always return an error, making this buffer inaccessible. r.buffer.Free() - b.mu.Unlock() // An error had occurred earlier, don't accept more // data or errors. return @@ -96,13 +130,70 @@ func (b *recvBuffer) put(r recvMsg) { if len(b.backlog) == 0 { select { case b.c <- r: - b.mu.Unlock() return default: } } b.backlog = append(b.backlog, r) - b.mu.Unlock() + b.compactBacklogLocked(r) +} + +func (b *recvBuffer) compactBacklogLocked(r recvMsg) { + if !envconfig.EnableReceiveBufferCompaction { + return + } + if r.buffer == nil { + b.uncompactedBytes = 0 + b.uncompactedSuffixLen = 0 + return + } + + b.uncompactedSuffixLen++ + b.uncompactedBytes += r.buffer.Len() + backlogHeapSize := b.uncompactedSuffixLen*recvMsgSize + b.uncompactedBytes + + // If the memory overhead is less than 50% of the heap usage (e.g., because + // a large DATA frame arrived), the average message size in the suffix is + // large enough that memory bloat is not a concern. Reset suffix tracking. + if backlogHeapSize <= utilizationFactor*b.uncompactedBytes { + b.uncompactedBytes = 0 + b.uncompactedSuffixLen = 0 + return + } + // Avoid compacting too frequently for short bursts of small frames. + // Wait until we have accumulated at least ~1024 small messages (~57 KB). + if backlogHeapSize <= compactionThreshold { + // Still can accumulate more payloads. + return + } + + // Since the memory utilization is less than 50%, the average payload size + // of each recvMsg must be less than recvMsgSize (approx 56 bytes). + // In the worst case for bytes copied (where the average payload is just + // below recvMsgSize), compaction will occur once every: + // compactionThreshold / (recvMsgSize + avg_payload) = ~520 messages, + // copying ~29KB of data. + + start := 0 + newBuf := b.bufPool.Get(b.uncompactedBytes) + startIdx := len(b.backlog) - b.uncompactedSuffixLen + + for i := startIdx; i < len(b.backlog); i++ { + m := b.backlog[i] + b.backlog[i] = recvMsg{} + start += copy((*newBuf)[start:], m.buffer.ReadOnlyData()) + m.buffer.Free() + } + b.backlog[startIdx] = recvMsg{ + buffer: mem.NewBuffer(newBuf, b.bufPool), + } + b.backlog = b.backlog[:startIdx+1] + // After compaction, the suffix is replaced with a single message containing + // the combined payload. The new utilization is close to 1.0 (overhead of + // one recvMsg relative to the large compacted payload), which is well + // below the utilization factor of 2. + b.uncompactedBytes = 0 + b.uncompactedSuffixLen = 0 } func (b *recvBuffer) load() { @@ -110,6 +201,13 @@ func (b *recvBuffer) load() { if len(b.backlog) > 0 { select { case b.c <- b.backlog[0]: + // backlog[0] is only part of the tracked uncompacted suffix if the + // entire backlog currently consists of the suffix. If an earlier + // compaction or reset occurred, backlog[0] is already compacted. + if envconfig.EnableReceiveBufferCompaction && b.uncompactedSuffixLen == len(b.backlog) { + b.uncompactedSuffixLen-- + b.uncompactedBytes -= b.backlog[0].buffer.Len() + } b.backlog[0] = recvMsg{} b.backlog = b.backlog[1:] default: @@ -594,8 +692,6 @@ type CallHdr struct { PreviousAttempts int // value of grpc-previous-rpc-attempts header to set - DoneFunc func() // called when the stream is finished - // Authority is used to explicitly override the `:authority` header. // // This value comes from one of two sources: diff --git a/openshift/tests-extension/vendor/google.golang.org/grpc/mem/buffer_pool.go b/openshift/tests-extension/vendor/google.golang.org/grpc/mem/buffer_pool.go index 3b02b90916..aa121379fd 100644 --- a/openshift/tests-extension/vendor/google.golang.org/grpc/mem/buffer_pool.go +++ b/openshift/tests-extension/vendor/google.golang.org/grpc/mem/buffer_pool.go @@ -59,10 +59,6 @@ func init() { internal.SetDefaultBufferPool = func(pool BufferPool) { defaultBufferPool = pool } - - internal.SetBufferPoolingThresholdForTesting = func(threshold int) { - bufferPoolingThreshold = threshold - } } // DefaultBufferPool returns the current default buffer pool. It is a BufferPool diff --git a/openshift/tests-extension/vendor/google.golang.org/grpc/mem/buffers.go b/openshift/tests-extension/vendor/google.golang.org/grpc/mem/buffers.go index 2b410b16eb..9b355d4465 100644 --- a/openshift/tests-extension/vendor/google.golang.org/grpc/mem/buffers.go +++ b/openshift/tests-extension/vendor/google.golang.org/grpc/mem/buffers.go @@ -29,6 +29,8 @@ import ( "fmt" "sync" "sync/atomic" + + "google.golang.org/grpc/internal/mem" ) // A Buffer represents a reference counted piece of data (in bytes) that can be @@ -63,8 +65,6 @@ type Buffer interface { } var ( - bufferPoolingThreshold = 1 << 10 - bufferObjectPool = sync.Pool{New: func() any { return new(buffer) }} ) @@ -72,7 +72,7 @@ var ( // equal to the threshold for buffer pooling. This is used to determine whether // to pool buffers or allocate them directly. func IsBelowBufferPoolingThreshold(size int) bool { - return size <= bufferPoolingThreshold + return size <= mem.BufferPoolingThreshold } type buffer struct { diff --git a/openshift/tests-extension/vendor/google.golang.org/grpc/stream.go b/openshift/tests-extension/vendor/google.golang.org/grpc/stream.go index 4aac644a83..51aff85dfb 100644 --- a/openshift/tests-extension/vendor/google.golang.org/grpc/stream.go +++ b/openshift/tests-extension/vendor/google.golang.org/grpc/stream.go @@ -201,6 +201,15 @@ func endOfClientStream(cc *ClientConn, err error, opts ...CallOption) { } } +// clientInterceptor is structurally identical to the ClientInterceptor defined +// in internal/xds/httpfilter/httpfilter.go. It is defined locally here so that +// we can type-assert the generic Interceptor field in iresolver.RPCConfig +// without introducing a dependency on xDS packages. +type clientInterceptor interface { + NewStream(ctx context.Context, ri iresolver.RPCInfo, newStream func(ctx context.Context, opts ...CallOption) (ClientStream, error), opts ...CallOption) (ClientStream, error) + Close() +} + func newClientStream(ctx context.Context, desc *StreamDesc, cc *ClientConn, method string, opts ...CallOption) (_ ClientStream, err error) { if channelz.IsOn() { cc.incrCallsStarted() @@ -244,8 +253,11 @@ func newClientStream(ctx context.Context, desc *StreamDesc, cc *ClientConn, meth mc := &emptyMethodConfig var onCommit func() - newStream := func(ctx context.Context, done func()) (iresolver.ClientStream, error) { - return newClientStreamWithParams(ctx, desc, cc, method, mc, onCommit, done, nameResolutionDelayed, opts...) + newStream := func(ctx context.Context, filterOpts ...CallOption) (ClientStream, error) { + if filterOpts != nil { + opts = combine(opts, filterOpts) + } + return newClientStreamWithParams(ctx, desc, cc, method, mc, onCommit, nameResolutionDelayed, opts...) } rpcInfo := iresolver.RPCInfo{Context: ctx, Method: method} @@ -270,20 +282,24 @@ func newClientStream(ctx context.Context, desc *StreamDesc, cc *ClientConn, meth if rpcConfig.Interceptor != nil { rpcInfo.Context = nil ns := newStream - newStream = func(ctx context.Context, done func()) (iresolver.ClientStream, error) { - cs, err := rpcConfig.Interceptor.NewStream(ctx, rpcInfo, done, ns) - if err != nil { - return nil, toRPCErr(err) + if interceptor, ok := rpcConfig.Interceptor.(clientInterceptor); ok { + newStream = func(ctx context.Context, filterOpts ...CallOption) (ClientStream, error) { + cs, err := interceptor.NewStream(ctx, rpcInfo, ns, filterOpts...) + if err != nil { + return nil, toRPCErr(err) + } + return cs, nil } - return cs, nil + } else { + return nil, status.Errorf(codes.Internal, "invalid client interceptor type %T", rpcConfig.Interceptor) } } } - return newStream(ctx, func() {}) + return newStream(ctx) } -func newClientStreamWithParams(ctx context.Context, desc *StreamDesc, cc *ClientConn, method string, mc *serviceconfig.MethodConfig, onCommit, doneFunc func(), nameResolutionDelayed bool, opts ...CallOption) (_ iresolver.ClientStream, err error) { +func newClientStreamWithParams(ctx context.Context, desc *StreamDesc, cc *ClientConn, method string, mc *serviceconfig.MethodConfig, onCommit func(), nameResolutionDelayed bool, opts ...CallOption) (_ ClientStream, err error) { callInfo := defaultCallInfo() if mc.WaitForReady != nil { callInfo.failFast = !*mc.WaitForReady @@ -321,7 +337,6 @@ func newClientStreamWithParams(ctx context.Context, desc *StreamDesc, cc *Client Host: cc.authority, Method: method, ContentSubtype: callInfo.contentSubtype, - DoneFunc: doneFunc, Authority: callInfo.authority, } if allowed := callInfo.acceptedResponseCompressors; len(allowed) > 0 { diff --git a/openshift/tests-extension/vendor/google.golang.org/grpc/version.go b/openshift/tests-extension/vendor/google.golang.org/grpc/version.go index 53c737feeb..64ec3b3cfd 100644 --- a/openshift/tests-extension/vendor/google.golang.org/grpc/version.go +++ b/openshift/tests-extension/vendor/google.golang.org/grpc/version.go @@ -19,4 +19,4 @@ package grpc // Version is the current grpc version. -const Version = "1.82.1" +const Version = "1.83.1" diff --git a/openshift/tests-extension/vendor/modules.txt b/openshift/tests-extension/vendor/modules.txt index f58b715aa3..c77a71b00f 100644 --- a/openshift/tests-extension/vendor/modules.txt +++ b/openshift/tests-extension/vendor/modules.txt @@ -290,7 +290,7 @@ github.com/operator-framework/api/pkg/operators/v1alpha1 # github.com/operator-framework/operator-controller v1.8.1-0.20260319123036-8ccea5a0cf67 => ../../ ## explicit; go 1.26.3 github.com/operator-framework/operator-controller/api/v1 -# github.com/operator-framework/operator-registry v1.73.0 +# github.com/operator-framework/operator-registry v1.74.0 ## explicit; go 1.26.3 github.com/operator-framework/operator-registry/alpha/property # github.com/pborman/uuid v1.2.1 @@ -419,7 +419,7 @@ go.yaml.in/yaml/v2 # go.yaml.in/yaml/v3 v3.0.5 ## explicit; go 1.16 go.yaml.in/yaml/v3 -# golang.org/x/crypto v0.54.0 +# golang.org/x/crypto v0.55.0 ## explicit; go 1.25.0 golang.org/x/crypto/blowfish golang.org/x/crypto/chacha20 @@ -433,7 +433,7 @@ golang.org/x/crypto/ssh/internal/bcrypt_pbkdf # golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f ## explicit; go 1.25.0 golang.org/x/exp/slices -# golang.org/x/net v0.57.0 +# golang.org/x/net v0.58.0 ## explicit; go 1.25.0 golang.org/x/net/context golang.org/x/net/html @@ -467,7 +467,7 @@ golang.org/x/sys/windows/registry # golang.org/x/term v0.45.0 ## explicit; go 1.25.0 golang.org/x/term -# golang.org/x/text v0.40.0 +# golang.org/x/text v0.41.0 ## explicit; go 1.25.0 golang.org/x/text/encoding golang.org/x/text/encoding/charmap @@ -500,7 +500,7 @@ golang.org/x/text/unicode/norm # golang.org/x/time v0.15.0 ## explicit; go 1.25.0 golang.org/x/time/rate -# golang.org/x/tools v0.48.0 +# golang.org/x/tools v0.49.0 ## explicit; go 1.25.0 golang.org/x/tools/cover golang.org/x/tools/go/ast/edge @@ -513,7 +513,7 @@ google.golang.org/genproto/googleapis/api/httpbody ## explicit; go 1.25.0 google.golang.org/genproto/googleapis/rpc/errdetails google.golang.org/genproto/googleapis/rpc/status -# google.golang.org/grpc v1.82.1 +# google.golang.org/grpc v1.83.1 ## explicit; go 1.25.0 google.golang.org/grpc google.golang.org/grpc/attributes @@ -699,7 +699,7 @@ k8s.io/api/storage/v1 k8s.io/api/storage/v1alpha1 k8s.io/api/storage/v1beta1 k8s.io/api/storagemigration/v1alpha1 -# k8s.io/apiextensions-apiserver v0.36.2 => github.com/openshift/kubernetes/staging/src/k8s.io/apiextensions-apiserver v0.0.0-20251108023427-891f5bb03061 +# k8s.io/apiextensions-apiserver v0.36.3 => github.com/openshift/kubernetes/staging/src/k8s.io/apiextensions-apiserver v0.0.0-20251108023427-891f5bb03061 ## explicit; go 1.24.0 k8s.io/apiextensions-apiserver/pkg/apis/apiextensions k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1 diff --git a/requirements.txt b/requirements.txt index 493d112da7..0e915eb103 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,26 +1,26 @@ Babel==2.18.0 beautifulsoup4==4.15.0 certifi==2026.7.22 -charset-normalizer==3.4.9 +charset-normalizer==3.5.1 click==8.4.2 colorama==0.4.6 cssselect==1.5.0 ghp-import==2.1.0 -idna==3.18 +idna==3.19 Jinja2==3.1.6 -lxml==6.1.1 -Markdown==3.10.2 +lxml==6.1.2 +Markdown==3.10.3 markdown2==2.5.5 MarkupSafe==3.0.3 mergedeep==1.3.4 mkdocs==1.6.1 mkdocs-material==9.7.7 mkdocs-material-extensions==1.3.1 -packaging==26.2 +packaging==26.3 paginate==0.5.7 pathspec==1.1.1 -platformdirs==4.11.0 -Pygments==2.20.0 +platformdirs==4.11.3 +Pygments==2.21.0 pymdown-extensions==11.0.1 pyquery==2.1.0 python-dateutil==2.9.0.post0 @@ -30,7 +30,7 @@ readtime==3.0.0 regex==2026.7.19 requests==2.34.2 six==1.17.0 -soupsieve==2.9.1 +soupsieve==2.9.2 urllib3==2.7.0 watchdog==6.0.0 mkdocs-asciinema-player==1.2.0 diff --git a/vendor/golang.org/x/crypto/openpgp/clearsign/clearsign.go b/vendor/github.com/ProtonMail/go-crypto/openpgp/clearsign/clearsign.go similarity index 59% rename from vendor/golang.org/x/crypto/openpgp/clearsign/clearsign.go rename to vendor/github.com/ProtonMail/go-crypto/openpgp/clearsign/clearsign.go index cbd2e5df2b..460347afb5 100644 --- a/vendor/golang.org/x/crypto/openpgp/clearsign/clearsign.go +++ b/vendor/github.com/ProtonMail/go-crypto/openpgp/clearsign/clearsign.go @@ -7,14 +7,7 @@ // // Clearsigned messages are cryptographically signed, but the contents of the // message are kept in plaintext so that it can be read without special tools. -// -// Deprecated: this package is unsafe by design, and has numerous known security -// issues. It is not maintained, and should not be used. New applications should -// consider a more focused, modern alternative to OpenPGP for their specific -// task. If you are required to interoperate with OpenPGP systems and need a -// maintained package, consider github.com/ProtonMail/go-crypto/openpgp, which -// is a maintained fork that aims to be a drop-in replacement for this package. -package clearsign +package clearsign // import "github.com/ProtonMail/go-crypto/openpgp/clearsign" import ( "bufio" @@ -24,16 +17,18 @@ import ( "hash" "io" "net/textproto" + "slices" "strconv" "strings" - "golang.org/x/crypto/openpgp/armor" - "golang.org/x/crypto/openpgp/errors" - "golang.org/x/crypto/openpgp/packet" + "github.com/ProtonMail/go-crypto/openpgp" + "github.com/ProtonMail/go-crypto/openpgp/armor" + "github.com/ProtonMail/go-crypto/openpgp/errors" + "github.com/ProtonMail/go-crypto/openpgp/packet" ) // A Block represents a clearsigned message. A signature on a Block can -// be checked by passing Bytes into openpgp.CheckDetachedSignature. +// be checked by calling Block.VerifySignature. type Block struct { Headers textproto.MIMEHeader // Optional unverified Hash headers Plaintext []byte // The original message text @@ -55,9 +50,13 @@ var endText = []byte("-----BEGIN PGP SIGNATURE-----") // end is a marker which denotes the end of the armored signature. var end = []byte("\n-----END PGP SIGNATURE-----") +var allowedHashHeaderValues = []string{"MD5", "SHA1", "RIPEMD160", "SHA224", "SHA256", "SHA384", "SHA512", "SHA3-256", "SHA3-512"} + var crlf = []byte("\r\n") var lf = byte('\n') +const hashHeader string = "Hash" + // getLine returns the first \r\n or \n delineated line from the given byte // array. The line does not include the \r\n or \n. The remainder of the byte // array (also not including the new line bytes) is also returned and this will @@ -115,7 +114,7 @@ func Decode(data []byte) (b *Block, rest []byte) { return nil, data } // An empty line marks the end of the headers. - if line, rest = getLine(rest); len(line) == 0 { + if line, rest = getLine(rest); len(strings.TrimSpace(string(line))) == 0 { break } @@ -133,11 +132,18 @@ func Decode(data []byte) (b *Block, rest []byte) { key, val := string(line[0:i]), string(line[i+1:]) key = strings.TrimSpace(key) - if key != "Hash" { + if key == hashHeader { + for _, val := range strings.Split(val, ",") { + val = strings.ToUpper(strings.TrimSpace(val)) + if !slices.Contains(allowedHashHeaderValues, val) { + return nil, data + } + b.Headers.Add(key, val) + } + } else { + // Only "Hash" headers are allowed. return nil, data } - val = strings.TrimSpace(val) - b.Headers.Add(key, val) } firstLine := true @@ -173,6 +179,7 @@ func Decode(data []byte) (b *Block, rest []byte) { b.Plaintext = append(b.Plaintext, line...) b.Plaintext = append(b.Plaintext, lf) } + b.Plaintext = b.Plaintext[:len(b.Plaintext)-1] // We want to find the extent of the armored data (including any newlines at // the end). @@ -203,10 +210,12 @@ func Decode(data []byte) (b *Block, rest []byte) { // When closed, an armored signature is created and written to complete the // message. type dashEscaper struct { - buffered *bufio.Writer - hashers []hash.Hash // one per key in privateKeys - hashType crypto.Hash - toHash io.Writer // writes to all the hashes in hashers + buffered *bufio.Writer + hashers []hash.Hash // one per key in privateKeys + hashTypes []crypto.Hash + toHash io.Writer // writes to all the hashes in hashers + salts [][]byte // salts for the signatures if v6 + armorHeader map[string]string // Armor headers atBeginningOfLine bool isFirstLine bool @@ -226,7 +235,9 @@ func (d *dashEscaper) Write(data []byte) (n int, err error) { // The final CRLF isn't included in the hash so we have to wait // until this point (the start of the next line) before writing it. if !d.isFirstLine { - d.toHash.Write(crlf) + if _, err = d.toHash.Write(crlf); err != nil { + return + } } d.isFirstLine = false } @@ -247,12 +258,16 @@ func (d *dashEscaper) Write(data []byte) (n int, err error) { if _, err = d.buffered.Write(dashEscape); err != nil { return } - d.toHash.Write(d.byteBuf) + if _, err = d.toHash.Write(d.byteBuf); err != nil { + return + } d.atBeginningOfLine = false } else if b == '\n' { // Nothing to do because we delay writing CRLF to the hash. } else { - d.toHash.Write(d.byteBuf) + if _, err = d.toHash.Write(d.byteBuf); err != nil { + return + } d.atBeginningOfLine = false } if err = d.buffered.WriteByte(b); err != nil { @@ -273,13 +288,17 @@ func (d *dashEscaper) Write(data []byte) (n int, err error) { // Any buffered whitespace wasn't at the end of the line so // we need to write it out. if len(d.whitespace) > 0 { - d.toHash.Write(d.whitespace) + if _, err = d.toHash.Write(d.whitespace); err != nil { + return + } if _, err = d.buffered.Write(d.whitespace); err != nil { return } d.whitespace = d.whitespace[:0] } - d.toHash.Write(d.byteBuf) + if _, err = d.toHash.Write(d.byteBuf); err != nil { + return + } if err = d.buffered.WriteByte(b); err != nil { return } @@ -292,26 +311,42 @@ func (d *dashEscaper) Write(data []byte) (n int, err error) { } func (d *dashEscaper) Close() (err error) { - if !d.atBeginningOfLine { - if err = d.buffered.WriteByte(lf); err != nil { - return + if d.atBeginningOfLine { + if !d.isFirstLine { + if _, err := d.toHash.Write(crlf); err != nil { + return err + } } } + if err = d.buffered.WriteByte(lf); err != nil { + return + } - out, err := armor.Encode(d.buffered, "PGP SIGNATURE", nil) + out, err := armor.EncodeWithChecksumOption(d.buffered, "PGP SIGNATURE", d.armorHeader, false) if err != nil { return } t := d.config.Now() + indexSalt := 0 for i, k := range d.privateKeys { sig := new(packet.Signature) + sig.Version = k.Version sig.SigType = packet.SigTypeText sig.PubKeyAlgo = k.PubKeyAlgo - sig.Hash = d.hashType + sig.Hash = d.hashTypes[i] sig.CreationTime = t sig.IssuerKeyId = &k.KeyId - + sig.IssuerFingerprint = k.Fingerprint + sig.Notations = d.config.Notations() + sigLifetimeSecs := d.config.SigLifetime() + sig.SigLifetimeSecs = &sigLifetimeSecs + if k.Version == 6 { + if err = sig.SetSalt(d.salts[indexSalt]); err != nil { + return + } + indexSalt++ + } if err = sig.Sign(d.hashers[i], k, d.config); err != nil { return } @@ -335,10 +370,25 @@ func Encode(w io.Writer, privateKey *packet.PrivateKey, config *packet.Config) ( return EncodeMulti(w, []*packet.PrivateKey{privateKey}, config) } +// EncodeWithHeader returns a WriteCloser which will clear-sign a message with privateKey +// and write it to w. If config is nil, sensible defaults are used. +// Additionally provides a headers argument for custom headers. +func EncodeWithHeader(w io.Writer, privateKey *packet.PrivateKey, config *packet.Config, headers map[string]string) (plaintext io.WriteCloser, err error) { + return EncodeMultiWithHeader(w, []*packet.PrivateKey{privateKey}, config, headers) +} + // EncodeMulti returns a WriteCloser which will clear-sign a message with all the // private keys indicated and write it to w. If config is nil, sensible defaults // are used. func EncodeMulti(w io.Writer, privateKeys []*packet.PrivateKey, config *packet.Config) (plaintext io.WriteCloser, err error) { + return EncodeMultiWithHeader(w, privateKeys, config, nil) +} + +// EncodeMultiWithHeader returns a WriteCloser which will clear-sign a message with all the +// private keys indicated and write it to w. If config is nil, sensible defaults +// are used. +// Additionally provides a headers argument for custom headers. +func EncodeMultiWithHeader(w io.Writer, privateKeys []*packet.PrivateKey, config *packet.Config, headers map[string]string) (plaintext io.WriteCloser, err error) { for _, k := range privateKeys { if k.Encrypted { return nil, errors.InvalidArgumentError(fmt.Sprintf("signing key %s is encrypted", k.KeyIdString())) @@ -346,19 +396,36 @@ func EncodeMulti(w io.Writer, privateKeys []*packet.PrivateKey, config *packet.C } hashType := config.Hash() - name := nameOfHash(hashType) - if len(name) == 0 { - return nil, errors.UnsupportedError("unknown hash type: " + strconv.Itoa(int(hashType))) - } - if !hashType.Available() { - return nil, errors.UnsupportedError("unsupported hash type: " + strconv.Itoa(int(hashType))) - } var hashers []hash.Hash + var hashTypes []crypto.Hash var ws []io.Writer - for range privateKeys { - h := hashType.New() + var salts [][]byte + for _, sk := range privateKeys { + acceptedHashes := acceptableHashesToWrite(&sk.PublicKey) + // acceptedHashes contains at least one hash + selectedHashType := acceptedHashes[0] + for _, acceptedHash := range acceptedHashes { + if hashType == acceptedHash { + selectedHashType = hashType + break + } + } + h := selectedHashType.New() + if sk.Version == 6 { + // generate salt + var salt []byte + salt, err = packet.SignatureSaltForHash(hashType, config.Random()) + if err != nil { + return + } + if _, err = h.Write(salt); err != nil { + return + } + salts = append(salts, salt) + } hashers = append(hashers, h) + hashTypes = append(hashTypes, selectedHashType) ws = append(ws, h) } toHash := io.MultiWriter(ws...) @@ -371,24 +438,25 @@ func EncodeMulti(w io.Writer, privateKeys []*packet.PrivateKey, config *packet.C if err = buffered.WriteByte(lf); err != nil { return } - if _, err = buffered.WriteString("Hash: "); err != nil { - return - } - if _, err = buffered.WriteString(name); err != nil { - return - } - if err = buffered.WriteByte(lf); err != nil { - return + // write headers + nonV6 := len(salts) < len(hashers) + // Crypto refresh: Headers SHOULD NOT be emitted + if nonV6 { // Emit header if non v6 signatures are present for compatibility + if err := writeHashHeader(buffered, hashTypes); err != nil { + return nil, err + } } if err = buffered.WriteByte(lf); err != nil { return } plaintext = &dashEscaper{ - buffered: buffered, - hashers: hashers, - hashType: hashType, - toHash: toHash, + buffered: buffered, + hashers: hashers, + hashTypes: hashTypes, + toHash: toHash, + salts: salts, + armorHeader: headers, atBeginningOfLine: true, isFirstLine: true, @@ -402,16 +470,51 @@ func EncodeMulti(w io.Writer, privateKeys []*packet.PrivateKey, config *packet.C return } +// VerifySignature checks a clearsigned message signature, and checks that the +// hash algorithm in the header matches the hash algorithm in the signature. +func (b *Block) VerifySignature(keyring openpgp.KeyRing, config *packet.Config) (signer *openpgp.Entity, err error) { + _, signer, err = openpgp.VerifyDetachedSignature(keyring, bytes.NewBuffer(b.Bytes), b.ArmoredSignature.Body, config) + return +} + +// writeHashHeader writes the legacy cleartext hash header to buffered. +func writeHashHeader(buffered *bufio.Writer, hashTypes []crypto.Hash) error { + seen := make(map[string]bool, len(hashTypes)) + if _, err := buffered.WriteString(fmt.Sprintf("%s: ", hashHeader)); err != nil { + return err + } + + for index, sigHashType := range hashTypes { + first := index == 0 + name := nameOfHash(sigHashType) + if len(name) == 0 { + return errors.UnsupportedError("unknown hash type: " + strconv.Itoa(int(sigHashType))) + } + + switch { + case !seen[name] && first: + if _, err := buffered.WriteString(name); err != nil { + return err + } + case !seen[name]: + if _, err := buffered.WriteString(fmt.Sprintf(",%s", name)); err != nil { + return err + } + } + seen[name] = true + } + + if err := buffered.WriteByte(lf); err != nil { + return err + } + + return nil +} + // nameOfHash returns the OpenPGP name for the given hash, or the empty string // if the name isn't known. See RFC 4880, section 9.4. func nameOfHash(h crypto.Hash) string { switch h { - case crypto.MD5: - return "MD5" - case crypto.SHA1: - return "SHA1" - case crypto.RIPEMD160: - return "RIPEMD160" case crypto.SHA224: return "SHA224" case crypto.SHA256: @@ -420,6 +523,45 @@ func nameOfHash(h crypto.Hash) string { return "SHA384" case crypto.SHA512: return "SHA512" + case crypto.SHA3_256: + return "SHA3-256" + case crypto.SHA3_512: + return "SHA3-512" } return "" } + +func acceptableHashesToWrite(singingKey *packet.PublicKey) []crypto.Hash { + switch singingKey.PubKeyAlgo { + case packet.PubKeyAlgoEd448: + return []crypto.Hash{ + crypto.SHA512, + crypto.SHA3_512, + } + case packet.PubKeyAlgoECDSA, packet.PubKeyAlgoEdDSA: + if curve, err := singingKey.Curve(); err == nil { + if curve == packet.Curve448 || + curve == packet.CurveNistP521 || + curve == packet.CurveBrainpoolP512 { + return []crypto.Hash{ + crypto.SHA512, + crypto.SHA3_512, + } + } else if curve == packet.CurveBrainpoolP384 || + curve == packet.CurveNistP384 { + return []crypto.Hash{ + crypto.SHA384, + crypto.SHA512, + crypto.SHA3_512, + } + } + } + } + return []crypto.Hash{ + crypto.SHA256, + crypto.SHA384, + crypto.SHA512, + crypto.SHA3_256, + crypto.SHA3_512, + } +} diff --git a/vendor/github.com/cucumber/gherkin/go/v42/.gitignore b/vendor/github.com/cucumber/gherkin/go/v42/.gitignore new file mode 100644 index 0000000000..7b0ee7aeb6 --- /dev/null +++ b/vendor/github.com/cucumber/gherkin/go/v42/.gitignore @@ -0,0 +1,17 @@ +.built +.compared +.deps +.dist +.dist-compressed +.go-get +.gofmt +.linted +.tested* +acceptance/ +bin/ +dist/ +dist_compressed/ +*.bin +*.iml +# upx dist/cucumber-gherkin-openbsd-386 fails with a core dump +core.*.!usr!bin!upx-ucl diff --git a/vendor/github.com/cucumber/gherkin/go/v42/LICENSE b/vendor/github.com/cucumber/gherkin/go/v42/LICENSE new file mode 100644 index 0000000000..58780c68e1 --- /dev/null +++ b/vendor/github.com/cucumber/gherkin/go/v42/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 Cucumber Ltd, Gaspar Nagy, Björn Rasmusson, Peter Sergeant, and contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/cucumber/gherkin/go/v42/Makefile b/vendor/github.com/cucumber/gherkin/go/v42/Makefile new file mode 100644 index 0000000000..c1e75e42ed --- /dev/null +++ b/vendor/github.com/cucumber/gherkin/go/v42/Makefile @@ -0,0 +1,91 @@ +SHELL := /usr/bin/env bash + +GHERKIN_LANGUAGES_JSON = dialects_builtin.go +GHERKIN_PARSER = parser.go +GHERKIN_RAZOR = parser.go.razor +SOURCE_FILES = $(shell find . -name "*.go" | grep -v $(GHERKIN_PARSER)) + +GHERKIN = bin/gherkin +GHERKIN_GENERATE_TOKENS = bin/gherkin-generate-tokens + +GOOD_FEATURE_FILES = $(shell find ../testdata/good -name "*.feature") +BAD_FEATURE_FILES = $(shell find ../testdata/bad -name "*.feature") + +TOKENS = $(patsubst ../testdata/%,acceptance/testdata/%.tokens,$(GOOD_FEATURE_FILES)) +ASTS = $(patsubst ../testdata/%,acceptance/testdata/%.ast.ndjson,$(GOOD_FEATURE_FILES)) +PICKLES = $(patsubst ../testdata/%,acceptance/testdata/%.pickles.ndjson,$(GOOD_FEATURE_FILES)) +SOURCES = $(patsubst ../testdata/%,acceptance/testdata/%.source.ndjson,$(GOOD_FEATURE_FILES)) +ERRORS = $(patsubst ../testdata/%,acceptance/testdata/%.errors.ndjson,$(BAD_FEATURE_FILES)) + +.DEFAULT_GOAL = help + +help: ## Show this help + @awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \n\nWhere is one of:\n"} /^[$$()% a-zA-Z_-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST) +.PHONY: help + +generate: $(GHERKIN_PARSER) ## Generate gherkin parser files +.PHONY: generate + +clean-generate: ## Remove generated Gherkin parser files ## Generate gherkin parser files + rm -f $(GHERKIN_PARSER) +.PHONY: clean-generate + +copy-gherkin-languages: $(GHERKIN_LANGUAGES_JSON) ## Copy gherkin-languages.json and/or generate derived files +.PHONY: copy-gherkin-languages + +clean-gherkin-languages: ## Remove gherkin-languages.json and any derived files + rm -f $(GHERKIN_LANGUAGES_JSON) +.PHONY: clean-gherkin-languages + +mostlyclean: + rm -rf .built + rm -rf acceptance + rm -rf bin +.PHONY: mostlyclean + +clean: mostlyclean ## Remove all build artifacts and files generated by the acceptance tests +.PHONY: clean + +.DELETE_ON_ERROR: + +acceptance: .built $(TOKENS) $(ASTS) $(PICKLES) $(ERRORS) $(SOURCES) ## Build acceptance test dir and compare results with reference + +.built: bin/gherkin-generate-tokens bin/gherkin + touch $@ + +bin/gherkin-generate-tokens: + go build -o $@ ./gherkin-generate-tokens + +bin/gherkin: + go build -o $@ -a ./main + +dialects_builtin.go: ../gherkin-languages.json dialects_builtin.go.jq + cat $< | jq --sort-keys --from-file dialects_builtin.go.jq --raw-output --compact-output > $@ + +$(GHERKIN_PARSER): $(GHERKIN_RAZOR) ../gherkin.berp + berp -g ../gherkin.berp -t $< -o $@ --noBOM + +acceptance/testdata/%.tokens: ../testdata/% ../testdata/%.tokens + mkdir -p $(@D) + $(GHERKIN_GENERATE_TOKENS) $< > $@ + diff --unified $<.tokens $@ + +acceptance/testdata/%.ast.ndjson: ../testdata/% ../testdata/%.ast.ndjson + mkdir -p $(@D) + $(GHERKIN) --no-source --no-pickles --predictable-ids $< | jq --sort-keys --compact-output "." > $@ + diff --unified <(jq "." $<.ast.ndjson) <(jq "." $@) + +acceptance/testdata/%.pickles.ndjson: ../testdata/% ../testdata/%.pickles.ndjson + mkdir -p $(@D) + $(GHERKIN) --no-source --no-ast --predictable-ids $< | jq --sort-keys --compact-output "." > $@ + diff --unified <(jq "." $<.pickles.ndjson) <(jq "." $@) + +acceptance/testdata/%.source.ndjson: ../testdata/% ../testdata/%.source.ndjson + mkdir -p $(@D) + $(GHERKIN) --no-ast --no-pickles --predictable-ids $< | jq --sort-keys --compact-output "." > $@ + diff --unified <(jq "." $<.source.ndjson) <(jq "." $@) + +acceptance/testdata/%.errors.ndjson: ../testdata/% ../testdata/%.errors.ndjson + mkdir -p $(@D) + $(GHERKIN) --no-source --predictable-ids $< | jq --sort-keys --compact-output "." > $@ + diff --unified <(jq "." $<.errors.ndjson) <(jq "." $@) diff --git a/vendor/github.com/cucumber/gherkin/go/v42/README.md b/vendor/github.com/cucumber/gherkin/go/v42/README.md new file mode 100644 index 0000000000..cdaba03c98 --- /dev/null +++ b/vendor/github.com/cucumber/gherkin/go/v42/README.md @@ -0,0 +1,37 @@ +# Gherkin for Go + +[![GoDoc](https://pkg.go.dev/github.com/cucumber/gherkin/go?status.svg)](http://godoc.org/github.com/cucumber/gherkin/go) + +Gherkin parser/compiler for Go. Please see [Gherkin](https://github.com/cucumber/gherkin) for details. + +## Building + +You need Go installed (obviously). You also need to make sure your `PATH` +points to where Go installs packages: + +```bash +# Add go bin to path +export PATH=$(go env GOPATH)/bin:${PATH} +``` + +Now build it: + +``` +make .dist +``` + +You should have cross-compiled binaries in `./dist/`. + +## Compress binaries + +You need [upx](https://upx.github.io/) installed. + +``` +make .dist +make .dist-compressed +``` + +Your `./dist_compressed/` directory should now have compressed binaries. +Compression fails for some binaries, so you likely won't have a full set. + +The build copies the successfully compressed binaries back to `./dist/`. diff --git a/vendor/github.com/cucumber/gherkin/go/v42/astbuilder.go b/vendor/github.com/cucumber/gherkin/go/v42/astbuilder.go new file mode 100644 index 0000000000..78c8cdba38 --- /dev/null +++ b/vendor/github.com/cucumber/gherkin/go/v42/astbuilder.go @@ -0,0 +1,452 @@ +package gherkin + +import ( + "github.com/cucumber/messages/go/v34" + "strings" +) + +type AstBuilder interface { + Builder + GetGherkinDocument() *messages.GherkinDocument +} + +type astBuilder struct { + stack []*astNode + comments []*messages.Comment + newId func() string +} + +func (t *astBuilder) Reset() { + t.comments = []*messages.Comment{} + t.stack = []*astNode{} + t.push(newAstNode(RuleTypeNone)) +} + +func (t *astBuilder) GetGherkinDocument() *messages.GherkinDocument { + res := t.currentNode().getSingle(RuleTypeGherkinDocument, nil) + if val, ok := res.(*messages.GherkinDocument); ok { + return val + } + return nil +} + +type astNode struct { + ruleType RuleType + subNodes map[RuleType][]interface{} +} + +func (a *astNode) add(rt RuleType, obj interface{}) { + a.subNodes[rt] = append(a.subNodes[rt], obj) +} + +func (a *astNode) getSingle(rt RuleType, defaultValue interface{}) interface{} { + if val, ok := a.subNodes[rt]; ok { + for i := range val { + return val[i] + } + } + return defaultValue +} + +func (a *astNode) getItems(rt RuleType) []interface{} { + var res []interface{} + if val, ok := a.subNodes[rt]; ok { + for i := range val { + res = append(res, val[i]) + } + } + return res +} + +func (a *astNode) getToken(tt TokenType) *Token { + if val, ok := a.getSingle(tt.RuleType(), nil).(*Token); ok { + return val + } + return nil +} + +func (a *astNode) getTokens(tt TokenType) []*Token { + var items = a.getItems(tt.RuleType()) + var tokens []*Token + for i := range items { + if val, ok := items[i].(*Token); ok { + tokens = append(tokens, val) + } + } + return tokens +} + +func (t *astBuilder) currentNode() *astNode { + if len(t.stack) > 0 { + return t.stack[len(t.stack)-1] + } + return nil +} + +func newAstNode(rt RuleType) *astNode { + return &astNode{ + ruleType: rt, + subNodes: make(map[RuleType][]interface{}), + } +} + +func NewAstBuilder(newId func() string) AstBuilder { + builder := new(astBuilder) + builder.newId = newId + builder.comments = []*messages.Comment{} + builder.push(newAstNode(RuleTypeNone)) + return builder +} + +func (t *astBuilder) push(n *astNode) { + t.stack = append(t.stack, n) +} + +func (t *astBuilder) pop() *astNode { + x := t.stack[len(t.stack)-1] + t.stack = t.stack[:len(t.stack)-1] + return x +} + +func (t *astBuilder) Build(tok *Token) (bool, error) { + if tok.Type == TokenTypeComment { + comment := &messages.Comment{ + Location: astLocation(tok), + Text: tok.Text, + } + t.comments = append(t.comments, comment) + } else { + t.currentNode().add(tok.Type.RuleType(), tok) + } + return true, nil +} + +func (t *astBuilder) StartRule(r RuleType) (bool, error) { + t.push(newAstNode(r)) + return true, nil +} + +func (t *astBuilder) EndRule(r RuleType) (bool, error) { + node := t.pop() + transformedNode, err := t.transformNode(node) + t.currentNode().add(node.ruleType, transformedNode) + return true, err +} + +func (t *astBuilder) transformNode(node *astNode) (interface{}, error) { + switch node.ruleType { + + case RuleTypeStep: + stepLine := node.getToken(TokenTypeStepLine) + + step := &messages.Step{ + Location: astLocation(stepLine), + Keyword: stepLine.Keyword, + KeywordType: stepLine.KeywordType, + Text: stepLine.Text, + Id: t.newId(), + } + dataTable := node.getSingle(RuleTypeDataTable, nil) + if dataTable != nil { + step.DataTable = dataTable.(*messages.DataTable) + } + docString := node.getSingle(RuleTypeDocString, nil) + if docString != nil { + step.DocString = docString.(*messages.DocString) + } + + return step, nil + + case RuleTypeDocString: + separatorToken := node.getToken(TokenTypeDocStringSeparator) + lineTokens := node.getTokens(TokenTypeOther) + var text string + for i := range lineTokens { + if i > 0 { + text += "\n" + } + text += lineTokens[i].Text + } + docString := &messages.DocString{ + Location: astLocation(separatorToken), + Content: text, + Delimiter: separatorToken.Keyword, + } + if len(separatorToken.Text) > 0 { + docString.MediaType = separatorToken.Text + } + + return docString, nil + + case RuleTypeDataTable: + rows, err := astTableRows(node, t.newId) + dt := &messages.DataTable{ + Location: rows[0].Location, + Rows: rows, + } + return dt, err + + case RuleTypeBackground: + backgroundLine := node.getToken(TokenTypeBackgroundLine) + bg := &messages.Background{ + Id: t.newId(), + Location: astLocation(backgroundLine), + Keyword: backgroundLine.Keyword, + Name: backgroundLine.Text, + Description: getDescription(node), + Steps: astSteps(node), + } + return bg, nil + + case RuleTypeScenarioDefinition: + scenarioNode := node.getSingle(RuleTypeScenario, nil).(*astNode) + scenarioLine := scenarioNode.getToken(TokenTypeScenarioLine) + tags := astTags(node, t.newId) + sc := &messages.Scenario{ + Id: t.newId(), + Tags: tags, + Location: astLocation(scenarioLine), + Keyword: scenarioLine.Keyword, + Name: scenarioLine.Text, + Description: getDescription(scenarioNode), + Steps: astSteps(scenarioNode), + Examples: astExamples(scenarioNode), + } + + return sc, nil + + case RuleTypeExamplesDefinition: + tags := astTags(node, t.newId) + examplesNode := node.getSingle(RuleTypeExamples, nil).(*astNode) + examplesLine := examplesNode.getToken(TokenTypeExamplesLine) + examplesTable := examplesNode.getSingle(RuleTypeExamplesTable, make([]*messages.TableRow, 0)).([]*messages.TableRow) + + var tableHeader *messages.TableRow + var tableBody []*messages.TableRow + + if len(examplesTable) > 0 { + tableHeader = examplesTable[0] + tableBody = examplesTable[1:] + } else { + tableHeader = nil + tableBody = examplesTable + } + + ex := &messages.Examples{ + Id: t.newId(), + Tags: tags, + Location: astLocation(examplesLine), + Keyword: examplesLine.Keyword, + Name: examplesLine.Text, + Description: getDescription(examplesNode), + TableHeader: tableHeader, + TableBody: tableBody, + } + return ex, nil + + case RuleTypeExamplesTable: + allRows, err := astTableRows(node, t.newId) + return allRows, err + + case RuleTypeDescription: + lineTokens := node.getTokens(TokenTypeOther) + // Trim trailing empty lines + end := len(lineTokens) + for end > 0 && strings.TrimSpace(lineTokens[end-1].Text) == "" { + end-- + } + var desc []string + for i := range lineTokens[0:end] { + desc = append(desc, lineTokens[i].Text) + } + return strings.Join(desc, "\n"), nil + + case RuleTypeFeature: + header := node.getSingle(RuleTypeFeatureHeader, nil).(*astNode) + tags := astTags(header, t.newId) + featureLine := header.getToken(TokenTypeFeatureLine) + if featureLine == nil { + return nil, nil + } + + children := make([]*messages.FeatureChild, 0) + background, _ := node.getSingle(RuleTypeBackground, nil).(*messages.Background) + if background != nil { + children = append(children, &messages.FeatureChild{ + Background: background, + }) + } + scenarios := node.getItems(RuleTypeScenarioDefinition) + for i := range scenarios { + scenario := scenarios[i].(*messages.Scenario) + children = append(children, &messages.FeatureChild{ + Scenario: scenario, + }) + } + rules := node.getItems(RuleTypeRule) + for i := range rules { + rule := rules[i].(*messages.Rule) + children = append(children, &messages.FeatureChild{ + Rule: rule, + }) + } + + feature := &messages.Feature{ + Tags: tags, + Location: astLocation(featureLine), + Language: featureLine.GherkinDialect, + Keyword: featureLine.Keyword, + Name: featureLine.Text, + Description: getDescription(header), + Children: children, + } + return feature, nil + + case RuleTypeRule: + header := node.getSingle(RuleTypeRuleHeader, nil).(*astNode) + ruleLine := header.getToken(TokenTypeRuleLine) + if ruleLine == nil { + return nil, nil + } + + tags := astTags(header, t.newId) + var children []*messages.RuleChild + background, _ := node.getSingle(RuleTypeBackground, nil).(*messages.Background) + + if background != nil { + children = append(children, &messages.RuleChild{ + Background: background, + }) + } + scenarios := node.getItems(RuleTypeScenarioDefinition) + for i := range scenarios { + scenario := scenarios[i].(*messages.Scenario) + children = append(children, &messages.RuleChild{ + Scenario: scenario, + }) + } + + rule := &messages.Rule{ + Id: t.newId(), + Location: astLocation(ruleLine), + Keyword: ruleLine.Keyword, + Name: ruleLine.Text, + Description: getDescription(header), + Children: children, + Tags: tags, + } + return rule, nil + + case RuleTypeGherkinDocument: + feature, _ := node.getSingle(RuleTypeFeature, nil).(*messages.Feature) + + doc := &messages.GherkinDocument{} + if feature != nil { + doc.Feature = feature + } + doc.Comments = t.comments + return doc, nil + } + return node, nil +} + +func getDescription(node *astNode) string { + return node.getSingle(RuleTypeDescription, "").(string) +} + +func astLocation(t *Token) *messages.Location { + return &messages.Location{ + Line: int64(t.Location.Line), + Column: int64(t.Location.Column), + } +} + +func astTableRows(t *astNode, newId func() string) (rows []*messages.TableRow, err error) { + rows = []*messages.TableRow{} + tokens := t.getTokens(TokenTypeTableRow) + for i := range tokens { + row := &messages.TableRow{ + Id: newId(), + Location: astLocation(tokens[i]), + Cells: astTableCells(tokens[i]), + } + rows = append(rows, row) + } + err = ensureCellCount(rows) + return +} + +func ensureCellCount(rows []*messages.TableRow) error { + if len(rows) <= 1 { + return nil + } + cellCount := len(rows[0].Cells) + for i := range rows { + if cellCount != len(rows[i].Cells) { + return &parseError{"inconsistent cell count within the table", &Location{ + Line: int(rows[i].Location.Line), + Column: int(rows[i].Location.Column), + }} + } + } + return nil +} + +func astTableCells(t *Token) (cells []*messages.TableCell) { + cells = []*messages.TableCell{} + for i := range t.Items { + item := t.Items[i] + cell := &messages.TableCell{} + cell.Location = &messages.Location{ + Line: int64(t.Location.Line), + Column: int64(item.Column), + } + cell.Value = item.Text + cells = append(cells, cell) + } + return +} + +func astSteps(t *astNode) (steps []*messages.Step) { + steps = []*messages.Step{} + tokens := t.getItems(RuleTypeStep) + for i := range tokens { + step, _ := tokens[i].(*messages.Step) + steps = append(steps, step) + } + return +} + +func astExamples(t *astNode) (examples []*messages.Examples) { + examples = []*messages.Examples{} + tokens := t.getItems(RuleTypeExamplesDefinition) + for i := range tokens { + example, _ := tokens[i].(*messages.Examples) + examples = append(examples, example) + } + return +} + +func astTags(node *astNode, newId func() string) (tags []*messages.Tag) { + tags = []*messages.Tag{} + tagsNode, ok := node.getSingle(RuleTypeTags, nil).(*astNode) + if !ok { + return + } + tokens := tagsNode.getTokens(TokenTypeTagLine) + for i := range tokens { + token := tokens[i] + for k := range token.Items { + item := token.Items[k] + tag := &messages.Tag{} + tag.Location = &messages.Location{ + Line: int64(token.Location.Line), + Column: int64(item.Column), + } + tag.Name = item.Text + tag.Id = newId() + tags = append(tags, tag) + } + } + return +} diff --git a/vendor/github.com/cucumber/gherkin/go/v42/dialect.go b/vendor/github.com/cucumber/gherkin/go/v42/dialect.go new file mode 100644 index 0000000000..7e51ca09e2 --- /dev/null +++ b/vendor/github.com/cucumber/gherkin/go/v42/dialect.go @@ -0,0 +1,74 @@ +package gherkin + +import ( + "sort" + + messages "github.com/cucumber/messages/go/v34" +) + +func init() { + // only needs to be calcuated one, on startup + for _, d := range builtinDialects { + d.stepKeywords = []string{} + d.stepKeywords = append(d.stepKeywords, d.Keywords[given]...) + d.stepKeywords = append(d.stepKeywords, d.Keywords[when]...) + d.stepKeywords = append(d.stepKeywords, d.Keywords[then]...) + d.stepKeywords = append(d.stepKeywords, d.Keywords[and]...) + d.stepKeywords = append(d.stepKeywords, d.Keywords[but]...) + sort.Slice(d.stepKeywords, func(i, j int) bool { + return d.stepKeywords[i] > d.stepKeywords[j] + }) + } +} + +type Dialect struct { + Language string + Name string + Native string + Keywords map[string][]string + KeywordTypes map[string]messages.StepKeywordType + + stepKeywords []string +} + +func (g *Dialect) FeatureKeywords() []string { + return g.Keywords["feature"] +} + +func (g *Dialect) RuleKeywords() []string { + return g.Keywords["rule"] +} + +func (g *Dialect) ScenarioKeywords() []string { + return g.Keywords["scenario"] +} + +func (g *Dialect) StepKeywords() []string { + return g.stepKeywords +} + +func (g *Dialect) BackgroundKeywords() []string { + return g.Keywords["background"] +} + +func (g *Dialect) ScenarioOutlineKeywords() []string { + return g.Keywords["scenarioOutline"] +} + +func (g *Dialect) ExamplesKeywords() []string { + return g.Keywords["examples"] +} + +func (g *Dialect) StepKeywordType(keyword string) messages.StepKeywordType { + return g.KeywordTypes[keyword] +} + +type DialectProvider interface { + GetDialect(language string) *Dialect +} + +type gherkinDialectMap map[string]*Dialect + +func (g gherkinDialectMap) GetDialect(language string) *Dialect { + return g[language] +} diff --git a/vendor/github.com/cucumber/gherkin/go/v42/dialects_builtin.go b/vendor/github.com/cucumber/gherkin/go/v42/dialects_builtin.go new file mode 100644 index 0000000000..7abb5ae4ab --- /dev/null +++ b/vendor/github.com/cucumber/gherkin/go/v42/dialects_builtin.go @@ -0,0 +1,5758 @@ +// Code generated from dialects_builtin.go.jq (make dialects_builtin.go); DO NOT EDIT. + +package gherkin + +import messages "github.com/cucumber/messages/go/v34" + +// Builtin dialects for af (Afrikaans), am (Armenian), an (Aragonese), ar (Arabic), ast (Asturian), az (Azerbaijani), be (Belarusian), bg (Bulgarian), bm (Malay), bs (Bosnian), ca (Catalan), cs (Czech), cy-GB (Welsh), da (Danish), de (German), el (Greek), em (Emoji), en (English), en-Scouse (Scouse), en-au (Australian), en-lol (LOLCAT), en-old (Old English), en-pirate (Pirate), en-tx (Texas), eo (Esperanto), es (Spanish), et (Estonian), fa (Persian), fi (Finnish), fr (French), ga (Irish), gj (Gujarati), gl (Galician), he (Hebrew), hi (Hindi), hr (Croatian), ht (Creole), hu (Hungarian), id (Indonesian), is (Icelandic), it (Italian), ja (Japanese), jv (Javanese), ka (Georgian), kn (Kannada), ko (Korean), lt (Lithuanian), lu (Luxemburgish), lv (Latvian), mk-Cyrl (Macedonian), mk-Latn (Macedonian (Latin)), mn (Mongolian), ne (Nepali), nl (Dutch), no (Norwegian), pa (Panjabi), pl (Polish), pt (Portuguese), ro (Romanian), ru (Russian), sk (Slovak), sl (Slovenian), sr-Cyrl (Serbian), sr-Latn (Serbian (Latin)), sv (Swedish), ta (Tamil), th (Thai), te (Telugu), tlh (Klingon), tr (Turkish), tt (Tatar), uk (Ukrainian), ur (Urdu), uz (Uzbek), vi (Vietnamese), zh-CN (Chinese simplified), ml (Malayalam), zh-TW (Chinese traditional), mr (Marathi), amh (Amharic) +func DialectsBuiltin() DialectProvider { + return builtinDialects +} + +const ( + feature = "feature" + rule = "rule" + background = "background" + scenario = "scenario" + scenarioOutline = "scenarioOutline" + examples = "examples" + given = "given" + when = "when" + then = "then" + and = "and" + but = "but" +) + +var builtinDialects = gherkinDialectMap{ + "af": &Dialect{ + Language: "af", + Name: "Afrikaans", + Native: "Afrikaans", + Keywords: map[string][]string{ + feature: { + "Funksie", + "Besigheid Behoefte", + "Vermoë", + }, + rule: { + "Reël", + "Reel", + }, + background: { + "Agtergrond", + }, + scenario: { + "Voorbeeld", + "Situasie", + }, + scenarioOutline: { + "Situasie Uiteensetting", + }, + examples: { + "Voorbeelde", + }, + given: { + "* ", + "Gegewe ", + }, + when: { + "* ", + "Wanneer ", + }, + then: { + "* ", + "Dan ", + }, + and: { + "* ", + "En ", + }, + but: { + "* ", + "Maar ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "Gegewe ": messages.StepKeywordType_CONTEXT, + + "Wanneer ": messages.StepKeywordType_ACTION, + + "Dan ": messages.StepKeywordType_OUTCOME, + + "En ": messages.StepKeywordType_CONJUNCTION, + + "Maar ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "am": &Dialect{ + Language: "am", + Name: "Armenian", + Native: "հայերեն", + Keywords: map[string][]string{ + feature: { + "Ֆունկցիոնալություն", + "Հատկություն", + }, + rule: { + "Rule", + }, + background: { + "Կոնտեքստ", + }, + scenario: { + "Օրինակ", + "Սցենար", + }, + scenarioOutline: { + "Սցենարի կառուցվացքը", + }, + examples: { + "Օրինակներ", + }, + given: { + "* ", + "Դիցուք ", + }, + when: { + "* ", + "Եթե ", + "Երբ ", + }, + then: { + "* ", + "Ապա ", + }, + and: { + "* ", + "Եվ ", + }, + but: { + "* ", + "Բայց ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "Դիցուք ": messages.StepKeywordType_CONTEXT, + + "Եթե ": messages.StepKeywordType_ACTION, + + "Երբ ": messages.StepKeywordType_ACTION, + + "Ապա ": messages.StepKeywordType_OUTCOME, + + "Եվ ": messages.StepKeywordType_CONJUNCTION, + + "Բայց ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "an": &Dialect{ + Language: "an", + Name: "Aragonese", + Native: "Aragonés", + Keywords: map[string][]string{ + feature: { + "Caracteristica", + }, + rule: { + "Rule", + }, + background: { + "Antecedents", + }, + scenario: { + "Eixemplo", + "Caso", + }, + scenarioOutline: { + "Esquema del caso", + }, + examples: { + "Eixemplos", + }, + given: { + "* ", + "Dau ", + "Dada ", + "Daus ", + "Dadas ", + }, + when: { + "* ", + "Cuan ", + }, + then: { + "* ", + "Alavez ", + "Allora ", + "Antonces ", + }, + and: { + "* ", + "Y ", + "E ", + }, + but: { + "* ", + "Pero ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "Dau ": messages.StepKeywordType_CONTEXT, + + "Dada ": messages.StepKeywordType_CONTEXT, + + "Daus ": messages.StepKeywordType_CONTEXT, + + "Dadas ": messages.StepKeywordType_CONTEXT, + + "Cuan ": messages.StepKeywordType_ACTION, + + "Alavez ": messages.StepKeywordType_OUTCOME, + + "Allora ": messages.StepKeywordType_OUTCOME, + + "Antonces ": messages.StepKeywordType_OUTCOME, + + "Y ": messages.StepKeywordType_CONJUNCTION, + + "E ": messages.StepKeywordType_CONJUNCTION, + + "Pero ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "ar": &Dialect{ + Language: "ar", + Name: "Arabic", + Native: "العربية", + Keywords: map[string][]string{ + feature: { + "خاصية", + }, + rule: { + "Rule", + }, + background: { + "الخلفية", + }, + scenario: { + "مثال", + "سيناريو", + }, + scenarioOutline: { + "سيناريو مخطط", + }, + examples: { + "امثلة", + }, + given: { + "* ", + "بفرض ", + }, + when: { + "* ", + "متى ", + "عندما ", + }, + then: { + "* ", + "اذاً ", + "ثم ", + }, + and: { + "* ", + "و ", + }, + but: { + "* ", + "لكن ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "بفرض ": messages.StepKeywordType_CONTEXT, + + "متى ": messages.StepKeywordType_ACTION, + + "عندما ": messages.StepKeywordType_ACTION, + + "اذاً ": messages.StepKeywordType_OUTCOME, + + "ثم ": messages.StepKeywordType_OUTCOME, + + "و ": messages.StepKeywordType_CONJUNCTION, + + "لكن ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "ast": &Dialect{ + Language: "ast", + Name: "Asturian", + Native: "asturianu", + Keywords: map[string][]string{ + feature: { + "Carauterística", + }, + rule: { + "Rule", + }, + background: { + "Antecedentes", + }, + scenario: { + "Exemplo", + "Casu", + }, + scenarioOutline: { + "Esbozu del casu", + }, + examples: { + "Exemplos", + }, + given: { + "* ", + "Dáu ", + "Dada ", + "Daos ", + "Daes ", + }, + when: { + "* ", + "Cuando ", + }, + then: { + "* ", + "Entós ", + }, + and: { + "* ", + "Y ", + "Ya ", + }, + but: { + "* ", + "Peru ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "Dáu ": messages.StepKeywordType_CONTEXT, + + "Dada ": messages.StepKeywordType_CONTEXT, + + "Daos ": messages.StepKeywordType_CONTEXT, + + "Daes ": messages.StepKeywordType_CONTEXT, + + "Cuando ": messages.StepKeywordType_ACTION, + + "Entós ": messages.StepKeywordType_OUTCOME, + + "Y ": messages.StepKeywordType_CONJUNCTION, + + "Ya ": messages.StepKeywordType_CONJUNCTION, + + "Peru ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "az": &Dialect{ + Language: "az", + Name: "Azerbaijani", + Native: "Azərbaycanca", + Keywords: map[string][]string{ + feature: { + "Özəllik", + }, + rule: { + "Rule", + }, + background: { + "Keçmiş", + "Kontekst", + }, + scenario: { + "Nümunə", + "Ssenari", + }, + scenarioOutline: { + "Ssenarinin strukturu", + }, + examples: { + "Nümunələr", + }, + given: { + "* ", + "Tutaq ki ", + "Verilir ", + }, + when: { + "* ", + "Əgər ", + "Nə vaxt ki ", + }, + then: { + "* ", + "O halda ", + }, + and: { + "* ", + "Və ", + "Həm ", + }, + but: { + "* ", + "Amma ", + "Ancaq ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "Tutaq ki ": messages.StepKeywordType_CONTEXT, + + "Verilir ": messages.StepKeywordType_CONTEXT, + + "Əgər ": messages.StepKeywordType_ACTION, + + "Nə vaxt ki ": messages.StepKeywordType_ACTION, + + "O halda ": messages.StepKeywordType_OUTCOME, + + "Və ": messages.StepKeywordType_CONJUNCTION, + + "Həm ": messages.StepKeywordType_CONJUNCTION, + + "Amma ": messages.StepKeywordType_CONJUNCTION, + + "Ancaq ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "be": &Dialect{ + Language: "be", + Name: "Belarusian", + Native: "Беларуская", + Keywords: map[string][]string{ + feature: { + "Функцыянальнасць", + "Фіча", + }, + rule: { + "Правілы", + }, + background: { + "Кантэкст", + }, + scenario: { + "Сцэнарый", + "Cцэнар", + }, + scenarioOutline: { + "Шаблон сцэнарыя", + "Узор сцэнара", + }, + examples: { + "Прыклады", + }, + given: { + "* ", + "Няхай ", + "Дадзена ", + }, + when: { + "* ", + "Калі ", + }, + then: { + "* ", + "Тады ", + }, + and: { + "* ", + "I ", + "Ды ", + "Таксама ", + }, + but: { + "* ", + "Але ", + "Інакш ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "Няхай ": messages.StepKeywordType_CONTEXT, + + "Дадзена ": messages.StepKeywordType_CONTEXT, + + "Калі ": messages.StepKeywordType_ACTION, + + "Тады ": messages.StepKeywordType_OUTCOME, + + "I ": messages.StepKeywordType_CONJUNCTION, + + "Ды ": messages.StepKeywordType_CONJUNCTION, + + "Таксама ": messages.StepKeywordType_CONJUNCTION, + + "Але ": messages.StepKeywordType_CONJUNCTION, + + "Інакш ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "bg": &Dialect{ + Language: "bg", + Name: "Bulgarian", + Native: "български", + Keywords: map[string][]string{ + feature: { + "Функционалност", + }, + rule: { + "Правило", + }, + background: { + "Предистория", + }, + scenario: { + "Пример", + "Сценарий", + }, + scenarioOutline: { + "Рамка на сценарий", + }, + examples: { + "Примери", + }, + given: { + "* ", + "Дадено ", + }, + when: { + "* ", + "Когато ", + }, + then: { + "* ", + "То ", + }, + and: { + "* ", + "И ", + }, + but: { + "* ", + "Но ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "Дадено ": messages.StepKeywordType_CONTEXT, + + "Когато ": messages.StepKeywordType_ACTION, + + "То ": messages.StepKeywordType_OUTCOME, + + "И ": messages.StepKeywordType_CONJUNCTION, + + "Но ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "bm": &Dialect{ + Language: "bm", + Name: "Malay", + Native: "Bahasa Melayu", + Keywords: map[string][]string{ + feature: { + "Fungsi", + }, + rule: { + "Rule", + }, + background: { + "Latar Belakang", + }, + scenario: { + "Senario", + "Situasi", + "Keadaan", + }, + scenarioOutline: { + "Kerangka Senario", + "Kerangka Situasi", + "Kerangka Keadaan", + "Garis Panduan Senario", + }, + examples: { + "Contoh", + }, + given: { + "* ", + "Diberi ", + "Bagi ", + }, + when: { + "* ", + "Apabila ", + }, + then: { + "* ", + "Maka ", + "Kemudian ", + }, + and: { + "* ", + "Dan ", + }, + but: { + "* ", + "Tetapi ", + "Tapi ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "Diberi ": messages.StepKeywordType_CONTEXT, + + "Bagi ": messages.StepKeywordType_CONTEXT, + + "Apabila ": messages.StepKeywordType_ACTION, + + "Maka ": messages.StepKeywordType_OUTCOME, + + "Kemudian ": messages.StepKeywordType_OUTCOME, + + "Dan ": messages.StepKeywordType_CONJUNCTION, + + "Tetapi ": messages.StepKeywordType_CONJUNCTION, + + "Tapi ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "bs": &Dialect{ + Language: "bs", + Name: "Bosnian", + Native: "Bosanski", + Keywords: map[string][]string{ + feature: { + "Karakteristika", + }, + rule: { + "Rule", + }, + background: { + "Pozadina", + }, + scenario: { + "Primjer", + "Scenariju", + "Scenario", + }, + scenarioOutline: { + "Scenariju-obris", + "Scenario-outline", + }, + examples: { + "Primjeri", + }, + given: { + "* ", + "Dato ", + }, + when: { + "* ", + "Kada ", + }, + then: { + "* ", + "Zatim ", + }, + and: { + "* ", + "I ", + "A ", + }, + but: { + "* ", + "Ali ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "Dato ": messages.StepKeywordType_CONTEXT, + + "Kada ": messages.StepKeywordType_ACTION, + + "Zatim ": messages.StepKeywordType_OUTCOME, + + "I ": messages.StepKeywordType_CONJUNCTION, + + "A ": messages.StepKeywordType_CONJUNCTION, + + "Ali ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "ca": &Dialect{ + Language: "ca", + Name: "Catalan", + Native: "català", + Keywords: map[string][]string{ + feature: { + "Característica", + "Funcionalitat", + }, + rule: { + "Rule", + }, + background: { + "Rerefons", + "Antecedents", + }, + scenario: { + "Exemple", + "Escenari", + }, + scenarioOutline: { + "Esquema de l'escenari", + }, + examples: { + "Exemples", + }, + given: { + "* ", + "Donat ", + "Donada ", + "Atès ", + "Atesa ", + }, + when: { + "* ", + "Quan ", + }, + then: { + "* ", + "Aleshores ", + "Cal ", + }, + and: { + "* ", + "I ", + }, + but: { + "* ", + "Però ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "Donat ": messages.StepKeywordType_CONTEXT, + + "Donada ": messages.StepKeywordType_CONTEXT, + + "Atès ": messages.StepKeywordType_CONTEXT, + + "Atesa ": messages.StepKeywordType_CONTEXT, + + "Quan ": messages.StepKeywordType_ACTION, + + "Aleshores ": messages.StepKeywordType_OUTCOME, + + "Cal ": messages.StepKeywordType_OUTCOME, + + "I ": messages.StepKeywordType_CONJUNCTION, + + "Però ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "cs": &Dialect{ + Language: "cs", + Name: "Czech", + Native: "Česky", + Keywords: map[string][]string{ + feature: { + "Požadavek", + }, + rule: { + "Pravidlo", + }, + background: { + "Pozadí", + "Kontext", + }, + scenario: { + "Příklad", + "Scénář", + }, + scenarioOutline: { + "Náčrt Scénáře", + "Osnova scénáře", + }, + examples: { + "Příklady", + }, + given: { + "* ", + "Pokud ", + "Za předpokladu ", + }, + when: { + "* ", + "Když ", + }, + then: { + "* ", + "Pak ", + }, + and: { + "* ", + "A také ", + "A ", + }, + but: { + "* ", + "Ale ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "Pokud ": messages.StepKeywordType_CONTEXT, + + "Za předpokladu ": messages.StepKeywordType_CONTEXT, + + "Když ": messages.StepKeywordType_ACTION, + + "Pak ": messages.StepKeywordType_OUTCOME, + + "A také ": messages.StepKeywordType_CONJUNCTION, + + "A ": messages.StepKeywordType_CONJUNCTION, + + "Ale ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "cy-GB": &Dialect{ + Language: "cy-GB", + Name: "Welsh", + Native: "Cymraeg", + Keywords: map[string][]string{ + feature: { + "Arwedd", + }, + rule: { + "Rule", + }, + background: { + "Cefndir", + }, + scenario: { + "Enghraifft", + "Scenario", + }, + scenarioOutline: { + "Scenario Amlinellol", + }, + examples: { + "Enghreifftiau", + }, + given: { + "* ", + "Anrhegedig a ", + }, + when: { + "* ", + "Pryd ", + }, + then: { + "* ", + "Yna ", + }, + and: { + "* ", + "A ", + }, + but: { + "* ", + "Ond ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "Anrhegedig a ": messages.StepKeywordType_CONTEXT, + + "Pryd ": messages.StepKeywordType_ACTION, + + "Yna ": messages.StepKeywordType_OUTCOME, + + "A ": messages.StepKeywordType_CONJUNCTION, + + "Ond ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "da": &Dialect{ + Language: "da", + Name: "Danish", + Native: "dansk", + Keywords: map[string][]string{ + feature: { + "Egenskab", + }, + rule: { + "Regel", + }, + background: { + "Baggrund", + }, + scenario: { + "Eksempel", + "Scenarie", + }, + scenarioOutline: { + "Abstrakt Scenario", + }, + examples: { + "Eksempler", + }, + given: { + "* ", + "Givet ", + }, + when: { + "* ", + "Når ", + }, + then: { + "* ", + "Så ", + }, + and: { + "* ", + "Og ", + }, + but: { + "* ", + "Men ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "Givet ": messages.StepKeywordType_CONTEXT, + + "Når ": messages.StepKeywordType_ACTION, + + "Så ": messages.StepKeywordType_OUTCOME, + + "Og ": messages.StepKeywordType_CONJUNCTION, + + "Men ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "de": &Dialect{ + Language: "de", + Name: "German", + Native: "Deutsch", + Keywords: map[string][]string{ + feature: { + "Funktionalität", + "Funktion", + }, + rule: { + "Rule", + "Regel", + }, + background: { + "Grundlage", + "Hintergrund", + "Voraussetzungen", + "Vorbedingungen", + }, + scenario: { + "Beispiel", + "Szenario", + }, + scenarioOutline: { + "Szenariogrundriss", + "Szenarien", + }, + examples: { + "Beispiele", + }, + given: { + "* ", + "Angenommen ", + "Gegeben sei ", + "Gegeben seien ", + }, + when: { + "* ", + "Wenn ", + }, + then: { + "* ", + "Dann ", + }, + and: { + "* ", + "Und ", + }, + but: { + "* ", + "Aber ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "Angenommen ": messages.StepKeywordType_CONTEXT, + + "Gegeben sei ": messages.StepKeywordType_CONTEXT, + + "Gegeben seien ": messages.StepKeywordType_CONTEXT, + + "Wenn ": messages.StepKeywordType_ACTION, + + "Dann ": messages.StepKeywordType_OUTCOME, + + "Und ": messages.StepKeywordType_CONJUNCTION, + + "Aber ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "el": &Dialect{ + Language: "el", + Name: "Greek", + Native: "Ελληνικά", + Keywords: map[string][]string{ + feature: { + "Δυνατότητα", + "Λειτουργία", + }, + rule: { + "Rule", + }, + background: { + "Υπόβαθρο", + }, + scenario: { + "Παράδειγμα", + "Σενάριο", + }, + scenarioOutline: { + "Περιγραφή Σεναρίου", + "Περίγραμμα Σεναρίου", + }, + examples: { + "Παραδείγματα", + "Σενάρια", + }, + given: { + "* ", + "Δεδομένου ", + }, + when: { + "* ", + "Όταν ", + }, + then: { + "* ", + "Τότε ", + }, + and: { + "* ", + "Και ", + }, + but: { + "* ", + "Αλλά ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "Δεδομένου ": messages.StepKeywordType_CONTEXT, + + "Όταν ": messages.StepKeywordType_ACTION, + + "Τότε ": messages.StepKeywordType_OUTCOME, + + "Και ": messages.StepKeywordType_CONJUNCTION, + + "Αλλά ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "em": &Dialect{ + Language: "em", + Name: "Emoji", + Native: "😀", + Keywords: map[string][]string{ + feature: { + "📚", + }, + rule: { + "Rule", + }, + background: { + "💤", + }, + scenario: { + "🥒", + "📕", + }, + scenarioOutline: { + "📖", + }, + examples: { + "📓", + }, + given: { + "* ", + "😐", + }, + when: { + "* ", + "🎬", + }, + then: { + "* ", + "🙏", + }, + and: { + "* ", + "😂", + }, + but: { + "* ", + "😔", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "😐": messages.StepKeywordType_CONTEXT, + + "🎬": messages.StepKeywordType_ACTION, + + "🙏": messages.StepKeywordType_OUTCOME, + + "😂": messages.StepKeywordType_CONJUNCTION, + + "😔": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "en": &Dialect{ + Language: "en", + Name: "English", + Native: "English", + Keywords: map[string][]string{ + feature: { + "Feature", + "Business Need", + "Ability", + }, + rule: { + "Rule", + }, + background: { + "Background", + }, + scenario: { + "Example", + "Scenario", + }, + scenarioOutline: { + "Scenario Outline", + "Scenario Template", + }, + examples: { + "Examples", + "Scenarios", + }, + given: { + "* ", + "Given ", + }, + when: { + "* ", + "When ", + }, + then: { + "* ", + "Then ", + }, + and: { + "* ", + "And ", + }, + but: { + "* ", + "But ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "Given ": messages.StepKeywordType_CONTEXT, + + "When ": messages.StepKeywordType_ACTION, + + "Then ": messages.StepKeywordType_OUTCOME, + + "And ": messages.StepKeywordType_CONJUNCTION, + + "But ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "en-Scouse": &Dialect{ + Language: "en-Scouse", + Name: "Scouse", + Native: "Scouse", + Keywords: map[string][]string{ + feature: { + "Feature", + }, + rule: { + "Rule", + }, + background: { + "Dis is what went down", + }, + scenario: { + "The thing of it is", + }, + scenarioOutline: { + "Wharrimean is", + }, + examples: { + "Examples", + }, + given: { + "* ", + "Givun ", + "Youse know when youse got ", + }, + when: { + "* ", + "Wun ", + "Youse know like when ", + }, + then: { + "* ", + "Dun ", + "Den youse gotta ", + }, + and: { + "* ", + "An ", + }, + but: { + "* ", + "Buh ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "Givun ": messages.StepKeywordType_CONTEXT, + + "Youse know when youse got ": messages.StepKeywordType_CONTEXT, + + "Wun ": messages.StepKeywordType_ACTION, + + "Youse know like when ": messages.StepKeywordType_ACTION, + + "Dun ": messages.StepKeywordType_OUTCOME, + + "Den youse gotta ": messages.StepKeywordType_OUTCOME, + + "An ": messages.StepKeywordType_CONJUNCTION, + + "Buh ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "en-au": &Dialect{ + Language: "en-au", + Name: "Australian", + Native: "Australian", + Keywords: map[string][]string{ + feature: { + "Pretty much", + }, + rule: { + "Rule", + }, + background: { + "First off", + }, + scenario: { + "Awww, look mate", + }, + scenarioOutline: { + "Reckon it's like", + }, + examples: { + "You'll wanna", + }, + given: { + "* ", + "Y'know ", + }, + when: { + "* ", + "It's just unbelievable ", + }, + then: { + "* ", + "But at the end of the day I reckon ", + }, + and: { + "* ", + "Too right ", + }, + but: { + "* ", + "Yeah nah ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "Y'know ": messages.StepKeywordType_CONTEXT, + + "It's just unbelievable ": messages.StepKeywordType_ACTION, + + "But at the end of the day I reckon ": messages.StepKeywordType_OUTCOME, + + "Too right ": messages.StepKeywordType_CONJUNCTION, + + "Yeah nah ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "en-lol": &Dialect{ + Language: "en-lol", + Name: "LOLCAT", + Native: "LOLCAT", + Keywords: map[string][]string{ + feature: { + "OH HAI", + }, + rule: { + "Rule", + }, + background: { + "B4", + }, + scenario: { + "MISHUN", + }, + scenarioOutline: { + "MISHUN SRSLY", + }, + examples: { + "EXAMPLZ", + }, + given: { + "* ", + "I CAN HAZ ", + }, + when: { + "* ", + "WEN ", + }, + then: { + "* ", + "DEN ", + }, + and: { + "* ", + "AN ", + }, + but: { + "* ", + "BUT ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "I CAN HAZ ": messages.StepKeywordType_CONTEXT, + + "WEN ": messages.StepKeywordType_ACTION, + + "DEN ": messages.StepKeywordType_OUTCOME, + + "AN ": messages.StepKeywordType_CONJUNCTION, + + "BUT ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "en-old": &Dialect{ + Language: "en-old", + Name: "Old English", + Native: "Englisc", + Keywords: map[string][]string{ + feature: { + "Hwaet", + "Hwæt", + }, + rule: { + "Rule", + }, + background: { + "Aer", + "Ær", + }, + scenario: { + "Swa", + }, + scenarioOutline: { + "Swa hwaer swa", + "Swa hwær swa", + }, + examples: { + "Se the", + "Se þe", + "Se ðe", + }, + given: { + "* ", + "Thurh ", + "Þurh ", + "Ðurh ", + }, + when: { + "* ", + "Bæþsealf ", + "Bæþsealfa ", + "Bæþsealfe ", + "Ciricæw ", + "Ciricæwe ", + "Ciricæwa ", + }, + then: { + "* ", + "Tha ", + "Þa ", + "Ða ", + "Tha the ", + "Þa þe ", + "Ða ðe ", + }, + and: { + "* ", + "Ond ", + "7 ", + }, + but: { + "* ", + "Ac ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "Thurh ": messages.StepKeywordType_CONTEXT, + + "Þurh ": messages.StepKeywordType_CONTEXT, + + "Ðurh ": messages.StepKeywordType_CONTEXT, + + "Bæþsealf ": messages.StepKeywordType_ACTION, + + "Bæþsealfa ": messages.StepKeywordType_ACTION, + + "Bæþsealfe ": messages.StepKeywordType_ACTION, + + "Ciricæw ": messages.StepKeywordType_ACTION, + + "Ciricæwe ": messages.StepKeywordType_ACTION, + + "Ciricæwa ": messages.StepKeywordType_ACTION, + + "Tha ": messages.StepKeywordType_OUTCOME, + + "Þa ": messages.StepKeywordType_OUTCOME, + + "Ða ": messages.StepKeywordType_OUTCOME, + + "Tha the ": messages.StepKeywordType_OUTCOME, + + "Þa þe ": messages.StepKeywordType_OUTCOME, + + "Ða ðe ": messages.StepKeywordType_OUTCOME, + + "Ond ": messages.StepKeywordType_CONJUNCTION, + + "7 ": messages.StepKeywordType_CONJUNCTION, + + "Ac ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "en-pirate": &Dialect{ + Language: "en-pirate", + Name: "Pirate", + Native: "Pirate", + Keywords: map[string][]string{ + feature: { + "Ahoy matey!", + }, + rule: { + "Rule", + }, + background: { + "Yo-ho-ho", + }, + scenario: { + "Heave to", + }, + scenarioOutline: { + "Shiver me timbers", + }, + examples: { + "Dead men tell no tales", + }, + given: { + "* ", + "Gangway! ", + }, + when: { + "* ", + "Blimey! ", + }, + then: { + "* ", + "Let go and haul ", + }, + and: { + "* ", + "Aye ", + }, + but: { + "* ", + "Avast! ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "Gangway! ": messages.StepKeywordType_CONTEXT, + + "Blimey! ": messages.StepKeywordType_ACTION, + + "Let go and haul ": messages.StepKeywordType_OUTCOME, + + "Aye ": messages.StepKeywordType_CONJUNCTION, + + "Avast! ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "en-tx": &Dialect{ + Language: "en-tx", + Name: "Texas", + Native: "Texas", + Keywords: map[string][]string{ + feature: { + "This ain’t my first rodeo", + "All gussied up", + }, + rule: { + "Rule ", + }, + background: { + "Lemme tell y'all a story", + }, + scenario: { + "All hat and no cattle", + }, + scenarioOutline: { + "Serious as a snake bite", + "Busy as a hound in flea season", + }, + examples: { + "Now that's a story longer than a cattle drive in July", + }, + given: { + "Fixin' to ", + "All git out ", + }, + when: { + "Quick out of the chute ", + }, + then: { + "There’s no tree but bears some fruit ", + }, + and: { + "Come hell or high water ", + }, + but: { + "Well now hold on, I'll you what ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "Fixin' to ": messages.StepKeywordType_CONTEXT, + + "All git out ": messages.StepKeywordType_CONTEXT, + + "Quick out of the chute ": messages.StepKeywordType_ACTION, + + "There’s no tree but bears some fruit ": messages.StepKeywordType_OUTCOME, + + "Come hell or high water ": messages.StepKeywordType_CONJUNCTION, + + "Well now hold on, I'll you what ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "eo": &Dialect{ + Language: "eo", + Name: "Esperanto", + Native: "Esperanto", + Keywords: map[string][]string{ + feature: { + "Trajto", + }, + rule: { + "Regulo", + }, + background: { + "Fono", + }, + scenario: { + "Ekzemplo", + "Scenaro", + "Kazo", + }, + scenarioOutline: { + "Konturo de la scenaro", + "Skizo", + "Kazo-skizo", + }, + examples: { + "Ekzemploj", + }, + given: { + "* ", + "Donitaĵo ", + "Komence ", + }, + when: { + "* ", + "Se ", + }, + then: { + "* ", + "Do ", + }, + and: { + "* ", + "Kaj ", + }, + but: { + "* ", + "Sed ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "Donitaĵo ": messages.StepKeywordType_CONTEXT, + + "Komence ": messages.StepKeywordType_CONTEXT, + + "Se ": messages.StepKeywordType_ACTION, + + "Do ": messages.StepKeywordType_OUTCOME, + + "Kaj ": messages.StepKeywordType_CONJUNCTION, + + "Sed ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "es": &Dialect{ + Language: "es", + Name: "Spanish", + Native: "español", + Keywords: map[string][]string{ + feature: { + "Característica", + "Necesidad del negocio", + "Requisito", + }, + rule: { + "Regla", + "Regla de negocio", + }, + background: { + "Antecedentes", + }, + scenario: { + "Ejemplo", + "Escenario", + }, + scenarioOutline: { + "Esquema del escenario", + }, + examples: { + "Ejemplos", + }, + given: { + "* ", + "Dado ", + "Dada ", + "Dados ", + "Dadas ", + }, + when: { + "* ", + "Cuando ", + }, + then: { + "* ", + "Entonces ", + }, + and: { + "* ", + "Y ", + "E ", + }, + but: { + "* ", + "Pero ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "Dado ": messages.StepKeywordType_CONTEXT, + + "Dada ": messages.StepKeywordType_CONTEXT, + + "Dados ": messages.StepKeywordType_CONTEXT, + + "Dadas ": messages.StepKeywordType_CONTEXT, + + "Cuando ": messages.StepKeywordType_ACTION, + + "Entonces ": messages.StepKeywordType_OUTCOME, + + "Y ": messages.StepKeywordType_CONJUNCTION, + + "E ": messages.StepKeywordType_CONJUNCTION, + + "Pero ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "et": &Dialect{ + Language: "et", + Name: "Estonian", + Native: "eesti keel", + Keywords: map[string][]string{ + feature: { + "Omadus", + }, + rule: { + "Reegel", + }, + background: { + "Taust", + }, + scenario: { + "Juhtum", + "Stsenaarium", + }, + scenarioOutline: { + "Raamjuhtum", + "Raamstsenaarium", + }, + examples: { + "Juhtumid", + }, + given: { + "* ", + "Eeldades ", + }, + when: { + "* ", + "Kui ", + }, + then: { + "* ", + "Siis ", + }, + and: { + "* ", + "Ja ", + }, + but: { + "* ", + "Kuid ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "Eeldades ": messages.StepKeywordType_CONTEXT, + + "Kui ": messages.StepKeywordType_ACTION, + + "Siis ": messages.StepKeywordType_OUTCOME, + + "Ja ": messages.StepKeywordType_CONJUNCTION, + + "Kuid ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "fa": &Dialect{ + Language: "fa", + Name: "Persian", + Native: "فارسی", + Keywords: map[string][]string{ + feature: { + "ویژگی", + "قابلیت", + }, + rule: { + "قانون", + }, + background: { + "زمینه", + "پیش زمینه", + "مقدمات", + }, + scenario: { + "مثال", + "سناریو", + }, + scenarioOutline: { + "الگوی سناریو", + }, + examples: { + "نمونه ها", + }, + given: { + "* ", + "با فرض ", + "فرض کنید ", + "با در نظر گرفتن ", + }, + when: { + "* ", + "هنگامی ", + "وقتی ", + }, + then: { + "* ", + "آنگاه ", + "سپس ", + "انتظار می رود ", + }, + and: { + "* ", + "و ", + }, + but: { + "* ", + "اما ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "با فرض ": messages.StepKeywordType_CONTEXT, + + "فرض کنید ": messages.StepKeywordType_CONTEXT, + + "با در نظر گرفتن ": messages.StepKeywordType_CONTEXT, + + "هنگامی ": messages.StepKeywordType_ACTION, + + "وقتی ": messages.StepKeywordType_ACTION, + + "آنگاه ": messages.StepKeywordType_OUTCOME, + + "سپس ": messages.StepKeywordType_OUTCOME, + + "انتظار می رود ": messages.StepKeywordType_OUTCOME, + + "و ": messages.StepKeywordType_CONJUNCTION, + + "اما ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "fi": &Dialect{ + Language: "fi", + Name: "Finnish", + Native: "suomi", + Keywords: map[string][]string{ + feature: { + "Ominaisuus", + }, + rule: { + "Rule", + }, + background: { + "Tausta", + }, + scenario: { + "Tapaus", + }, + scenarioOutline: { + "Tapausaihio", + }, + examples: { + "Tapaukset", + }, + given: { + "* ", + "Oletetaan ", + }, + when: { + "* ", + "Kun ", + }, + then: { + "* ", + "Niin ", + }, + and: { + "* ", + "Ja ", + }, + but: { + "* ", + "Mutta ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "Oletetaan ": messages.StepKeywordType_CONTEXT, + + "Kun ": messages.StepKeywordType_ACTION, + + "Niin ": messages.StepKeywordType_OUTCOME, + + "Ja ": messages.StepKeywordType_CONJUNCTION, + + "Mutta ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "fr": &Dialect{ + Language: "fr", + Name: "French", + Native: "français", + Keywords: map[string][]string{ + feature: { + "Fonctionnalité", + }, + rule: { + "Règle", + }, + background: { + "Contexte", + }, + scenario: { + "Exemple", + "Scénario", + }, + scenarioOutline: { + "Plan du scénario", + "Plan du Scénario", + }, + examples: { + "Exemples", + }, + given: { + "* ", + "Soit ", + "Sachant que ", + "Sachant qu'", + "Sachant ", + "Etant donné que ", + "Etant donné qu'", + "Etant donné ", + "Etant donnée ", + "Etant donnés ", + "Etant données ", + "Étant donné que ", + "Étant donné qu'", + "Étant donné ", + "Étant donnée ", + "Étant donnés ", + "Étant données ", + }, + when: { + "* ", + "Quand ", + "Lorsque ", + "Lorsqu'", + }, + then: { + "* ", + "Alors ", + "Donc ", + }, + and: { + "* ", + "Et que ", + "Et qu'", + "Et ", + }, + but: { + "* ", + "Mais que ", + "Mais qu'", + "Mais ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "Soit ": messages.StepKeywordType_CONTEXT, + + "Sachant que ": messages.StepKeywordType_CONTEXT, + + "Sachant qu'": messages.StepKeywordType_CONTEXT, + + "Sachant ": messages.StepKeywordType_CONTEXT, + + "Etant donné que ": messages.StepKeywordType_CONTEXT, + + "Etant donné qu'": messages.StepKeywordType_CONTEXT, + + "Etant donné ": messages.StepKeywordType_CONTEXT, + + "Etant donnée ": messages.StepKeywordType_CONTEXT, + + "Etant donnés ": messages.StepKeywordType_CONTEXT, + + "Etant données ": messages.StepKeywordType_CONTEXT, + + "Étant donné que ": messages.StepKeywordType_CONTEXT, + + "Étant donné qu'": messages.StepKeywordType_CONTEXT, + + "Étant donné ": messages.StepKeywordType_CONTEXT, + + "Étant donnée ": messages.StepKeywordType_CONTEXT, + + "Étant donnés ": messages.StepKeywordType_CONTEXT, + + "Étant données ": messages.StepKeywordType_CONTEXT, + + "Quand ": messages.StepKeywordType_ACTION, + + "Lorsque ": messages.StepKeywordType_ACTION, + + "Lorsqu'": messages.StepKeywordType_ACTION, + + "Alors ": messages.StepKeywordType_OUTCOME, + + "Donc ": messages.StepKeywordType_OUTCOME, + + "Et que ": messages.StepKeywordType_CONJUNCTION, + + "Et qu'": messages.StepKeywordType_CONJUNCTION, + + "Et ": messages.StepKeywordType_CONJUNCTION, + + "Mais que ": messages.StepKeywordType_CONJUNCTION, + + "Mais qu'": messages.StepKeywordType_CONJUNCTION, + + "Mais ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "ga": &Dialect{ + Language: "ga", + Name: "Irish", + Native: "Gaeilge", + Keywords: map[string][]string{ + feature: { + "Gné", + }, + rule: { + "Riail", + }, + background: { + "Cúlra", + }, + scenario: { + "Sampla", + "Cás", + }, + scenarioOutline: { + "Cás Achomair", + }, + examples: { + "Samplaí", + }, + given: { + "* ", + "Cuir i gcás go ", + "Cuir i gcás nach ", + "Cuir i gcás gur ", + "Cuir i gcás nár ", + }, + when: { + "* ", + "Nuair a ", + "Nuair nach ", + "Nuair ba ", + "Nuair nár ", + }, + then: { + "* ", + "Ansin ", + }, + and: { + "* ", + "Agus ", + }, + but: { + "* ", + "Ach ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "Cuir i gcás go ": messages.StepKeywordType_CONTEXT, + + "Cuir i gcás nach ": messages.StepKeywordType_CONTEXT, + + "Cuir i gcás gur ": messages.StepKeywordType_CONTEXT, + + "Cuir i gcás nár ": messages.StepKeywordType_CONTEXT, + + "Nuair a ": messages.StepKeywordType_ACTION, + + "Nuair nach ": messages.StepKeywordType_ACTION, + + "Nuair ba ": messages.StepKeywordType_ACTION, + + "Nuair nár ": messages.StepKeywordType_ACTION, + + "Ansin ": messages.StepKeywordType_OUTCOME, + + "Agus ": messages.StepKeywordType_CONJUNCTION, + + "Ach ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "gj": &Dialect{ + Language: "gj", + Name: "Gujarati", + Native: "ગુજરાતી", + Keywords: map[string][]string{ + feature: { + "લક્ષણ", + "વ્યાપાર જરૂર", + "ક્ષમતા", + }, + rule: { + "નિયમ", + }, + background: { + "બેકગ્રાઉન્ડ", + }, + scenario: { + "ઉદાહરણ", + "સ્થિતિ", + }, + scenarioOutline: { + "પરિદ્દશ્ય રૂપરેખા", + "પરિદ્દશ્ય ઢાંચો", + }, + examples: { + "ઉદાહરણો", + }, + given: { + "* ", + "આપેલ છે ", + }, + when: { + "* ", + "ક્યારે ", + }, + then: { + "* ", + "પછી ", + }, + and: { + "* ", + "અને ", + }, + but: { + "* ", + "પણ ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "આપેલ છે ": messages.StepKeywordType_CONTEXT, + + "ક્યારે ": messages.StepKeywordType_ACTION, + + "પછી ": messages.StepKeywordType_OUTCOME, + + "અને ": messages.StepKeywordType_CONJUNCTION, + + "પણ ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "gl": &Dialect{ + Language: "gl", + Name: "Galician", + Native: "galego", + Keywords: map[string][]string{ + feature: { + "Característica", + }, + rule: { + "Rule", + }, + background: { + "Contexto", + }, + scenario: { + "Exemplo", + "Escenario", + }, + scenarioOutline: { + "Esbozo do escenario", + }, + examples: { + "Exemplos", + }, + given: { + "* ", + "Dado ", + "Dada ", + "Dados ", + "Dadas ", + }, + when: { + "* ", + "Cando ", + }, + then: { + "* ", + "Entón ", + "Logo ", + }, + and: { + "* ", + "E ", + }, + but: { + "* ", + "Mais ", + "Pero ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "Dado ": messages.StepKeywordType_CONTEXT, + + "Dada ": messages.StepKeywordType_CONTEXT, + + "Dados ": messages.StepKeywordType_CONTEXT, + + "Dadas ": messages.StepKeywordType_CONTEXT, + + "Cando ": messages.StepKeywordType_ACTION, + + "Entón ": messages.StepKeywordType_OUTCOME, + + "Logo ": messages.StepKeywordType_OUTCOME, + + "E ": messages.StepKeywordType_CONJUNCTION, + + "Mais ": messages.StepKeywordType_CONJUNCTION, + + "Pero ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "he": &Dialect{ + Language: "he", + Name: "Hebrew", + Native: "עברית", + Keywords: map[string][]string{ + feature: { + "תכונה", + }, + rule: { + "כלל", + }, + background: { + "רקע", + }, + scenario: { + "דוגמא", + "תרחיש", + }, + scenarioOutline: { + "תבנית תרחיש", + }, + examples: { + "דוגמאות", + }, + given: { + "* ", + "בהינתן ", + }, + when: { + "* ", + "כאשר ", + }, + then: { + "* ", + "אז ", + "אזי ", + }, + and: { + "* ", + "וגם ", + }, + but: { + "* ", + "אבל ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "בהינתן ": messages.StepKeywordType_CONTEXT, + + "כאשר ": messages.StepKeywordType_ACTION, + + "אז ": messages.StepKeywordType_OUTCOME, + + "אזי ": messages.StepKeywordType_OUTCOME, + + "וגם ": messages.StepKeywordType_CONJUNCTION, + + "אבל ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "hi": &Dialect{ + Language: "hi", + Name: "Hindi", + Native: "हिंदी", + Keywords: map[string][]string{ + feature: { + "रूप लेख", + }, + rule: { + "नियम", + }, + background: { + "पृष्ठभूमि", + }, + scenario: { + "परिदृश्य", + }, + scenarioOutline: { + "परिदृश्य रूपरेखा", + }, + examples: { + "उदाहरण", + }, + given: { + "* ", + "अगर ", + "यदि ", + "चूंकि ", + }, + when: { + "* ", + "जब ", + "कदा ", + }, + then: { + "* ", + "तब ", + "तदा ", + }, + and: { + "* ", + "और ", + "तथा ", + }, + but: { + "* ", + "पर ", + "परन्तु ", + "किन्तु ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "अगर ": messages.StepKeywordType_CONTEXT, + + "यदि ": messages.StepKeywordType_CONTEXT, + + "चूंकि ": messages.StepKeywordType_CONTEXT, + + "जब ": messages.StepKeywordType_ACTION, + + "कदा ": messages.StepKeywordType_ACTION, + + "तब ": messages.StepKeywordType_OUTCOME, + + "तदा ": messages.StepKeywordType_OUTCOME, + + "और ": messages.StepKeywordType_CONJUNCTION, + + "तथा ": messages.StepKeywordType_CONJUNCTION, + + "पर ": messages.StepKeywordType_CONJUNCTION, + + "परन्तु ": messages.StepKeywordType_CONJUNCTION, + + "किन्तु ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "hr": &Dialect{ + Language: "hr", + Name: "Croatian", + Native: "hrvatski", + Keywords: map[string][]string{ + feature: { + "Osobina", + "Mogućnost", + "Mogucnost", + }, + rule: { + "Rule", + }, + background: { + "Pozadina", + }, + scenario: { + "Primjer", + "Scenarij", + }, + scenarioOutline: { + "Skica", + "Koncept", + }, + examples: { + "Primjeri", + "Scenariji", + }, + given: { + "* ", + "Zadan ", + "Zadani ", + "Zadano ", + "Ukoliko ", + }, + when: { + "* ", + "Kada ", + "Kad ", + }, + then: { + "* ", + "Onda ", + }, + and: { + "* ", + "I ", + }, + but: { + "* ", + "Ali ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "Zadan ": messages.StepKeywordType_CONTEXT, + + "Zadani ": messages.StepKeywordType_CONTEXT, + + "Zadano ": messages.StepKeywordType_CONTEXT, + + "Ukoliko ": messages.StepKeywordType_CONTEXT, + + "Kada ": messages.StepKeywordType_ACTION, + + "Kad ": messages.StepKeywordType_ACTION, + + "Onda ": messages.StepKeywordType_OUTCOME, + + "I ": messages.StepKeywordType_CONJUNCTION, + + "Ali ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "ht": &Dialect{ + Language: "ht", + Name: "Creole", + Native: "kreyòl", + Keywords: map[string][]string{ + feature: { + "Karakteristik", + "Mak", + "Fonksyonalite", + }, + rule: { + "Rule", + }, + background: { + "Kontèks", + "Istorik", + }, + scenario: { + "Senaryo", + }, + scenarioOutline: { + "Plan senaryo", + "Plan Senaryo", + "Senaryo deskripsyon", + "Senaryo Deskripsyon", + "Dyagram senaryo", + "Dyagram Senaryo", + }, + examples: { + "Egzanp", + }, + given: { + "* ", + "Sipoze ", + "Sipoze ke ", + "Sipoze Ke ", + }, + when: { + "* ", + "Lè ", + "Le ", + }, + then: { + "* ", + "Lè sa a ", + "Le sa a ", + }, + and: { + "* ", + "Ak ", + "Epi ", + "E ", + }, + but: { + "* ", + "Men ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "Sipoze ": messages.StepKeywordType_CONTEXT, + + "Sipoze ke ": messages.StepKeywordType_CONTEXT, + + "Sipoze Ke ": messages.StepKeywordType_CONTEXT, + + "Lè ": messages.StepKeywordType_ACTION, + + "Le ": messages.StepKeywordType_ACTION, + + "Lè sa a ": messages.StepKeywordType_OUTCOME, + + "Le sa a ": messages.StepKeywordType_OUTCOME, + + "Ak ": messages.StepKeywordType_CONJUNCTION, + + "Epi ": messages.StepKeywordType_CONJUNCTION, + + "E ": messages.StepKeywordType_CONJUNCTION, + + "Men ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "hu": &Dialect{ + Language: "hu", + Name: "Hungarian", + Native: "magyar", + Keywords: map[string][]string{ + feature: { + "Jellemző", + }, + rule: { + "Szabály", + }, + background: { + "Háttér", + }, + scenario: { + "Példa", + "Forgatókönyv", + }, + scenarioOutline: { + "Forgatókönyv vázlat", + }, + examples: { + "Példák", + }, + given: { + "* ", + "Amennyiben ", + "Adott ", + }, + when: { + "* ", + "Majd ", + "Ha ", + "Amikor ", + }, + then: { + "* ", + "Akkor ", + }, + and: { + "* ", + "És ", + }, + but: { + "* ", + "De ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "Amennyiben ": messages.StepKeywordType_CONTEXT, + + "Adott ": messages.StepKeywordType_CONTEXT, + + "Majd ": messages.StepKeywordType_ACTION, + + "Ha ": messages.StepKeywordType_ACTION, + + "Amikor ": messages.StepKeywordType_ACTION, + + "Akkor ": messages.StepKeywordType_OUTCOME, + + "És ": messages.StepKeywordType_CONJUNCTION, + + "De ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "id": &Dialect{ + Language: "id", + Name: "Indonesian", + Native: "Bahasa Indonesia", + Keywords: map[string][]string{ + feature: { + "Fitur", + }, + rule: { + "Rule", + "Aturan", + }, + background: { + "Dasar", + "Latar Belakang", + }, + scenario: { + "Skenario", + }, + scenarioOutline: { + "Skenario konsep", + "Garis-Besar Skenario", + }, + examples: { + "Contoh", + "Misal", + }, + given: { + "* ", + "Dengan ", + "Diketahui ", + "Diasumsikan ", + "Bila ", + "Jika ", + }, + when: { + "* ", + "Ketika ", + }, + then: { + "* ", + "Maka ", + "Kemudian ", + }, + and: { + "* ", + "Dan ", + }, + but: { + "* ", + "Tapi ", + "Tetapi ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "Dengan ": messages.StepKeywordType_CONTEXT, + + "Diketahui ": messages.StepKeywordType_CONTEXT, + + "Diasumsikan ": messages.StepKeywordType_CONTEXT, + + "Bila ": messages.StepKeywordType_CONTEXT, + + "Jika ": messages.StepKeywordType_CONTEXT, + + "Ketika ": messages.StepKeywordType_ACTION, + + "Maka ": messages.StepKeywordType_OUTCOME, + + "Kemudian ": messages.StepKeywordType_OUTCOME, + + "Dan ": messages.StepKeywordType_CONJUNCTION, + + "Tapi ": messages.StepKeywordType_CONJUNCTION, + + "Tetapi ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "is": &Dialect{ + Language: "is", + Name: "Icelandic", + Native: "Íslenska", + Keywords: map[string][]string{ + feature: { + "Eiginleiki", + }, + rule: { + "Rule", + }, + background: { + "Bakgrunnur", + }, + scenario: { + "Atburðarás", + }, + scenarioOutline: { + "Lýsing Atburðarásar", + "Lýsing Dæma", + }, + examples: { + "Dæmi", + "Atburðarásir", + }, + given: { + "* ", + "Ef ", + }, + when: { + "* ", + "Þegar ", + }, + then: { + "* ", + "Þá ", + }, + and: { + "* ", + "Og ", + }, + but: { + "* ", + "En ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "Ef ": messages.StepKeywordType_CONTEXT, + + "Þegar ": messages.StepKeywordType_ACTION, + + "Þá ": messages.StepKeywordType_OUTCOME, + + "Og ": messages.StepKeywordType_CONJUNCTION, + + "En ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "it": &Dialect{ + Language: "it", + Name: "Italian", + Native: "italiano", + Keywords: map[string][]string{ + feature: { + "Funzionalità", + "Esigenza di Business", + "Abilità", + }, + rule: { + "Regola", + }, + background: { + "Contesto", + }, + scenario: { + "Esempio", + "Scenario", + }, + scenarioOutline: { + "Schema dello scenario", + }, + examples: { + "Esempi", + }, + given: { + "* ", + "Dato ", + "Data ", + "Dati ", + "Date ", + }, + when: { + "* ", + "Quando ", + }, + then: { + "* ", + "Allora ", + }, + and: { + "* ", + "E ", + "Ed ", + }, + but: { + "* ", + "Ma ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "Dato ": messages.StepKeywordType_CONTEXT, + + "Data ": messages.StepKeywordType_CONTEXT, + + "Dati ": messages.StepKeywordType_CONTEXT, + + "Date ": messages.StepKeywordType_CONTEXT, + + "Quando ": messages.StepKeywordType_ACTION, + + "Allora ": messages.StepKeywordType_OUTCOME, + + "E ": messages.StepKeywordType_CONJUNCTION, + + "Ed ": messages.StepKeywordType_CONJUNCTION, + + "Ma ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "ja": &Dialect{ + Language: "ja", + Name: "Japanese", + Native: "日本語", + Keywords: map[string][]string{ + feature: { + "フィーチャ", + "機能", + }, + rule: { + "ルール", + }, + background: { + "背景", + }, + scenario: { + "シナリオ", + }, + scenarioOutline: { + "シナリオアウトライン", + "シナリオテンプレート", + "テンプレ", + "シナリオテンプレ", + }, + examples: { + "例", + "サンプル", + }, + given: { + "* ", + "前提", + }, + when: { + "* ", + "もし", + }, + then: { + "* ", + "ならば", + }, + and: { + "* ", + "且つ", + "かつ", + }, + but: { + "* ", + "然し", + "しかし", + "但し", + "ただし", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "前提": messages.StepKeywordType_CONTEXT, + + "もし": messages.StepKeywordType_ACTION, + + "ならば": messages.StepKeywordType_OUTCOME, + + "且つ": messages.StepKeywordType_CONJUNCTION, + + "かつ": messages.StepKeywordType_CONJUNCTION, + + "然し": messages.StepKeywordType_CONJUNCTION, + + "しかし": messages.StepKeywordType_CONJUNCTION, + + "但し": messages.StepKeywordType_CONJUNCTION, + + "ただし": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "jv": &Dialect{ + Language: "jv", + Name: "Javanese", + Native: "Basa Jawa", + Keywords: map[string][]string{ + feature: { + "Fitur", + }, + rule: { + "Rule", + }, + background: { + "Dasar", + }, + scenario: { + "Skenario", + }, + scenarioOutline: { + "Konsep skenario", + }, + examples: { + "Conto", + "Contone", + }, + given: { + "* ", + "Nalika ", + "Nalikaning ", + }, + when: { + "* ", + "Manawa ", + "Menawa ", + }, + then: { + "* ", + "Njuk ", + "Banjur ", + }, + and: { + "* ", + "Lan ", + }, + but: { + "* ", + "Tapi ", + "Nanging ", + "Ananging ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "Nalika ": messages.StepKeywordType_CONTEXT, + + "Nalikaning ": messages.StepKeywordType_CONTEXT, + + "Manawa ": messages.StepKeywordType_ACTION, + + "Menawa ": messages.StepKeywordType_ACTION, + + "Njuk ": messages.StepKeywordType_OUTCOME, + + "Banjur ": messages.StepKeywordType_OUTCOME, + + "Lan ": messages.StepKeywordType_CONJUNCTION, + + "Tapi ": messages.StepKeywordType_CONJUNCTION, + + "Nanging ": messages.StepKeywordType_CONJUNCTION, + + "Ananging ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "ka": &Dialect{ + Language: "ka", + Name: "Georgian", + Native: "ქართული", + Keywords: map[string][]string{ + feature: { + "თვისება", + "მოთხოვნა", + }, + rule: { + "წესი", + }, + background: { + "კონტექსტი", + }, + scenario: { + "მაგალითად", + "მაგალითი", + "მაგ", + "სცენარი", + }, + scenarioOutline: { + "სცენარის ნიმუში", + "სცენარის შაბლონი", + "ნიმუში", + "შაბლონი", + }, + examples: { + "მაგალითები", + }, + given: { + "* ", + "მოცემული ", + "მოცემულია ", + "ვთქვათ ", + }, + when: { + "* ", + "როდესაც ", + "როცა ", + "როგორც კი ", + "თუ ", + }, + then: { + "* ", + "მაშინ ", + }, + and: { + "* ", + "და ", + "ასევე ", + }, + but: { + "* ", + "მაგრამ ", + "თუმცა ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "მოცემული ": messages.StepKeywordType_CONTEXT, + + "მოცემულია ": messages.StepKeywordType_CONTEXT, + + "ვთქვათ ": messages.StepKeywordType_CONTEXT, + + "როდესაც ": messages.StepKeywordType_ACTION, + + "როცა ": messages.StepKeywordType_ACTION, + + "როგორც კი ": messages.StepKeywordType_ACTION, + + "თუ ": messages.StepKeywordType_ACTION, + + "მაშინ ": messages.StepKeywordType_OUTCOME, + + "და ": messages.StepKeywordType_CONJUNCTION, + + "ასევე ": messages.StepKeywordType_CONJUNCTION, + + "მაგრამ ": messages.StepKeywordType_CONJUNCTION, + + "თუმცა ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "kn": &Dialect{ + Language: "kn", + Name: "Kannada", + Native: "ಕನ್ನಡ", + Keywords: map[string][]string{ + feature: { + "ಹೆಚ್ಚಳ", + }, + rule: { + "Rule", + }, + background: { + "ಹಿನ್ನೆಲೆ", + }, + scenario: { + "ಉದಾಹರಣೆ", + "ಕಥಾಸಾರಾಂಶ", + }, + scenarioOutline: { + "ವಿವರಣೆ", + }, + examples: { + "ಉದಾಹರಣೆಗಳು", + }, + given: { + "* ", + "ನೀಡಿದ ", + }, + when: { + "* ", + "ಸ್ಥಿತಿಯನ್ನು ", + }, + then: { + "* ", + "ನಂತರ ", + }, + and: { + "* ", + "ಮತ್ತು ", + }, + but: { + "* ", + "ಆದರೆ ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "ನೀಡಿದ ": messages.StepKeywordType_CONTEXT, + + "ಸ್ಥಿತಿಯನ್ನು ": messages.StepKeywordType_ACTION, + + "ನಂತರ ": messages.StepKeywordType_OUTCOME, + + "ಮತ್ತು ": messages.StepKeywordType_CONJUNCTION, + + "ಆದರೆ ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "ko": &Dialect{ + Language: "ko", + Name: "Korean", + Native: "한국어", + Keywords: map[string][]string{ + feature: { + "기능", + }, + rule: { + "규칙", + }, + background: { + "배경", + }, + scenario: { + "시나리오", + }, + scenarioOutline: { + "시나리오 개요", + }, + examples: { + "예", + }, + given: { + "* ", + "조건 ", + "먼저 ", + }, + when: { + "* ", + "만일 ", + "만약 ", + }, + then: { + "* ", + "그러면 ", + }, + and: { + "* ", + "그리고 ", + }, + but: { + "* ", + "하지만 ", + "단 ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "조건 ": messages.StepKeywordType_CONTEXT, + + "먼저 ": messages.StepKeywordType_CONTEXT, + + "만일 ": messages.StepKeywordType_ACTION, + + "만약 ": messages.StepKeywordType_ACTION, + + "그러면 ": messages.StepKeywordType_OUTCOME, + + "그리고 ": messages.StepKeywordType_CONJUNCTION, + + "하지만 ": messages.StepKeywordType_CONJUNCTION, + + "단 ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "lt": &Dialect{ + Language: "lt", + Name: "Lithuanian", + Native: "lietuvių kalba", + Keywords: map[string][]string{ + feature: { + "Savybė", + }, + rule: { + "Rule", + }, + background: { + "Kontekstas", + }, + scenario: { + "Pavyzdys", + "Scenarijus", + }, + scenarioOutline: { + "Scenarijaus šablonas", + }, + examples: { + "Pavyzdžiai", + "Scenarijai", + "Variantai", + }, + given: { + "* ", + "Duota ", + }, + when: { + "* ", + "Kai ", + }, + then: { + "* ", + "Tada ", + }, + and: { + "* ", + "Ir ", + }, + but: { + "* ", + "Bet ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "Duota ": messages.StepKeywordType_CONTEXT, + + "Kai ": messages.StepKeywordType_ACTION, + + "Tada ": messages.StepKeywordType_OUTCOME, + + "Ir ": messages.StepKeywordType_CONJUNCTION, + + "Bet ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "lu": &Dialect{ + Language: "lu", + Name: "Luxemburgish", + Native: "Lëtzebuergesch", + Keywords: map[string][]string{ + feature: { + "Funktionalitéit", + }, + rule: { + "Rule", + }, + background: { + "Hannergrond", + }, + scenario: { + "Beispill", + "Szenario", + }, + scenarioOutline: { + "Plang vum Szenario", + }, + examples: { + "Beispiller", + }, + given: { + "* ", + "ugeholl ", + }, + when: { + "* ", + "wann ", + }, + then: { + "* ", + "dann ", + }, + and: { + "* ", + "an ", + "a ", + }, + but: { + "* ", + "awer ", + "mä ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "ugeholl ": messages.StepKeywordType_CONTEXT, + + "wann ": messages.StepKeywordType_ACTION, + + "dann ": messages.StepKeywordType_OUTCOME, + + "an ": messages.StepKeywordType_CONJUNCTION, + + "a ": messages.StepKeywordType_CONJUNCTION, + + "awer ": messages.StepKeywordType_CONJUNCTION, + + "mä ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "lv": &Dialect{ + Language: "lv", + Name: "Latvian", + Native: "latviešu", + Keywords: map[string][]string{ + feature: { + "Funkcionalitāte", + "Fīča", + }, + rule: { + "Rule", + }, + background: { + "Konteksts", + "Situācija", + }, + scenario: { + "Piemērs", + "Scenārijs", + }, + scenarioOutline: { + "Scenārijs pēc parauga", + }, + examples: { + "Piemēri", + "Paraugs", + }, + given: { + "* ", + "Kad ", + }, + when: { + "* ", + "Ja ", + }, + then: { + "* ", + "Tad ", + }, + and: { + "* ", + "Un ", + }, + but: { + "* ", + "Bet ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "Kad ": messages.StepKeywordType_CONTEXT, + + "Ja ": messages.StepKeywordType_ACTION, + + "Tad ": messages.StepKeywordType_OUTCOME, + + "Un ": messages.StepKeywordType_CONJUNCTION, + + "Bet ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "mk-Cyrl": &Dialect{ + Language: "mk-Cyrl", + Name: "Macedonian", + Native: "Македонски", + Keywords: map[string][]string{ + feature: { + "Функционалност", + "Бизнис потреба", + "Можност", + }, + rule: { + "Rule", + }, + background: { + "Контекст", + "Содржина", + }, + scenario: { + "Пример", + "Сценарио", + "На пример", + }, + scenarioOutline: { + "Преглед на сценарија", + "Скица", + "Концепт", + }, + examples: { + "Примери", + "Сценарија", + }, + given: { + "* ", + "Дадено ", + "Дадена ", + }, + when: { + "* ", + "Кога ", + }, + then: { + "* ", + "Тогаш ", + }, + and: { + "* ", + "И ", + }, + but: { + "* ", + "Но ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "Дадено ": messages.StepKeywordType_CONTEXT, + + "Дадена ": messages.StepKeywordType_CONTEXT, + + "Кога ": messages.StepKeywordType_ACTION, + + "Тогаш ": messages.StepKeywordType_OUTCOME, + + "И ": messages.StepKeywordType_CONJUNCTION, + + "Но ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "mk-Latn": &Dialect{ + Language: "mk-Latn", + Name: "Macedonian (Latin)", + Native: "Makedonski (Latinica)", + Keywords: map[string][]string{ + feature: { + "Funkcionalnost", + "Biznis potreba", + "Mozhnost", + }, + rule: { + "Rule", + }, + background: { + "Kontekst", + "Sodrzhina", + }, + scenario: { + "Scenario", + "Na primer", + }, + scenarioOutline: { + "Pregled na scenarija", + "Skica", + "Koncept", + }, + examples: { + "Primeri", + "Scenaria", + }, + given: { + "* ", + "Dadeno ", + "Dadena ", + }, + when: { + "* ", + "Koga ", + }, + then: { + "* ", + "Togash ", + }, + and: { + "* ", + "I ", + }, + but: { + "* ", + "No ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "Dadeno ": messages.StepKeywordType_CONTEXT, + + "Dadena ": messages.StepKeywordType_CONTEXT, + + "Koga ": messages.StepKeywordType_ACTION, + + "Togash ": messages.StepKeywordType_OUTCOME, + + "I ": messages.StepKeywordType_CONJUNCTION, + + "No ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "mn": &Dialect{ + Language: "mn", + Name: "Mongolian", + Native: "монгол", + Keywords: map[string][]string{ + feature: { + "Функц", + "Функционал", + }, + rule: { + "Rule", + }, + background: { + "Агуулга", + }, + scenario: { + "Сценар", + }, + scenarioOutline: { + "Сценарын төлөвлөгөө", + }, + examples: { + "Тухайлбал", + }, + given: { + "* ", + "Өгөгдсөн нь ", + "Анх ", + }, + when: { + "* ", + "Хэрэв ", + }, + then: { + "* ", + "Тэгэхэд ", + "Үүний дараа ", + }, + and: { + "* ", + "Мөн ", + "Тэгээд ", + }, + but: { + "* ", + "Гэхдээ ", + "Харин ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "Өгөгдсөн нь ": messages.StepKeywordType_CONTEXT, + + "Анх ": messages.StepKeywordType_CONTEXT, + + "Хэрэв ": messages.StepKeywordType_ACTION, + + "Тэгэхэд ": messages.StepKeywordType_OUTCOME, + + "Үүний дараа ": messages.StepKeywordType_OUTCOME, + + "Мөн ": messages.StepKeywordType_CONJUNCTION, + + "Тэгээд ": messages.StepKeywordType_CONJUNCTION, + + "Гэхдээ ": messages.StepKeywordType_CONJUNCTION, + + "Харин ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "ne": &Dialect{ + Language: "ne", + Name: "Nepali", + Native: "नेपाली", + Keywords: map[string][]string{ + feature: { + "सुविधा", + "विशेषता", + }, + rule: { + "नियम", + }, + background: { + "पृष्ठभूमी", + }, + scenario: { + "परिदृश्य", + }, + scenarioOutline: { + "परिदृश्य रूपरेखा", + }, + examples: { + "उदाहरण", + "उदाहरणहरु", + }, + given: { + "* ", + "दिइएको ", + "दिएको ", + "यदि ", + }, + when: { + "* ", + "जब ", + }, + then: { + "* ", + "त्यसपछि ", + "अनी ", + }, + and: { + "* ", + "र ", + "अनि ", + }, + but: { + "* ", + "तर ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "दिइएको ": messages.StepKeywordType_CONTEXT, + + "दिएको ": messages.StepKeywordType_CONTEXT, + + "यदि ": messages.StepKeywordType_CONTEXT, + + "जब ": messages.StepKeywordType_ACTION, + + "त्यसपछि ": messages.StepKeywordType_OUTCOME, + + "अनी ": messages.StepKeywordType_OUTCOME, + + "र ": messages.StepKeywordType_CONJUNCTION, + + "अनि ": messages.StepKeywordType_CONJUNCTION, + + "तर ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "nl": &Dialect{ + Language: "nl", + Name: "Dutch", + Native: "Nederlands", + Keywords: map[string][]string{ + feature: { + "Functionaliteit", + }, + rule: { + "Regel", + }, + background: { + "Achtergrond", + }, + scenario: { + "Voorbeeld", + "Scenario", + }, + scenarioOutline: { + "Abstract Scenario", + }, + examples: { + "Voorbeelden", + }, + given: { + "* ", + "Gegeven ", + "Stel ", + }, + when: { + "* ", + "Als ", + "Wanneer ", + }, + then: { + "* ", + "Dan ", + }, + and: { + "* ", + "En ", + }, + but: { + "* ", + "Maar ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "Gegeven ": messages.StepKeywordType_CONTEXT, + + "Stel ": messages.StepKeywordType_CONTEXT, + + "Als ": messages.StepKeywordType_ACTION, + + "Wanneer ": messages.StepKeywordType_ACTION, + + "Dan ": messages.StepKeywordType_OUTCOME, + + "En ": messages.StepKeywordType_CONJUNCTION, + + "Maar ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "no": &Dialect{ + Language: "no", + Name: "Norwegian", + Native: "norsk", + Keywords: map[string][]string{ + feature: { + "Egenskap", + }, + rule: { + "Regel", + }, + background: { + "Bakgrunn", + }, + scenario: { + "Eksempel", + "Scenario", + }, + scenarioOutline: { + "Scenariomal", + "Abstrakt Scenario", + }, + examples: { + "Eksempler", + }, + given: { + "* ", + "Gitt ", + }, + when: { + "* ", + "Når ", + }, + then: { + "* ", + "Så ", + }, + and: { + "* ", + "Og ", + }, + but: { + "* ", + "Men ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "Gitt ": messages.StepKeywordType_CONTEXT, + + "Når ": messages.StepKeywordType_ACTION, + + "Så ": messages.StepKeywordType_OUTCOME, + + "Og ": messages.StepKeywordType_CONJUNCTION, + + "Men ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "pa": &Dialect{ + Language: "pa", + Name: "Panjabi", + Native: "ਪੰਜਾਬੀ", + Keywords: map[string][]string{ + feature: { + "ਖਾਸੀਅਤ", + "ਮੁਹਾਂਦਰਾ", + "ਨਕਸ਼ ਨੁਹਾਰ", + }, + rule: { + "Rule", + }, + background: { + "ਪਿਛੋਕੜ", + }, + scenario: { + "ਉਦਾਹਰਨ", + "ਪਟਕਥਾ", + }, + scenarioOutline: { + "ਪਟਕਥਾ ਢਾਂਚਾ", + "ਪਟਕਥਾ ਰੂਪ ਰੇਖਾ", + }, + examples: { + "ਉਦਾਹਰਨਾਂ", + }, + given: { + "* ", + "ਜੇਕਰ ", + "ਜਿਵੇਂ ਕਿ ", + }, + when: { + "* ", + "ਜਦੋਂ ", + }, + then: { + "* ", + "ਤਦ ", + }, + and: { + "* ", + "ਅਤੇ ", + }, + but: { + "* ", + "ਪਰ ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "ਜੇਕਰ ": messages.StepKeywordType_CONTEXT, + + "ਜਿਵੇਂ ਕਿ ": messages.StepKeywordType_CONTEXT, + + "ਜਦੋਂ ": messages.StepKeywordType_ACTION, + + "ਤਦ ": messages.StepKeywordType_OUTCOME, + + "ਅਤੇ ": messages.StepKeywordType_CONJUNCTION, + + "ਪਰ ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "pl": &Dialect{ + Language: "pl", + Name: "Polish", + Native: "polski", + Keywords: map[string][]string{ + feature: { + "Właściwość", + "Funkcja", + "Aspekt", + "Potrzeba biznesowa", + }, + rule: { + "Zasada", + "Reguła", + }, + background: { + "Założenia", + }, + scenario: { + "Przykład", + "Scenariusz", + }, + scenarioOutline: { + "Szablon scenariusza", + }, + examples: { + "Przykłady", + }, + given: { + "* ", + "Zakładając ", + "Mając ", + "Zakładając, że ", + }, + when: { + "* ", + "Jeżeli ", + "Jeśli ", + "Gdy ", + "Kiedy ", + }, + then: { + "* ", + "Wtedy ", + }, + and: { + "* ", + "Oraz ", + "I ", + }, + but: { + "* ", + "Ale ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "Zakładając ": messages.StepKeywordType_CONTEXT, + + "Mając ": messages.StepKeywordType_CONTEXT, + + "Zakładając, że ": messages.StepKeywordType_CONTEXT, + + "Jeżeli ": messages.StepKeywordType_ACTION, + + "Jeśli ": messages.StepKeywordType_ACTION, + + "Gdy ": messages.StepKeywordType_ACTION, + + "Kiedy ": messages.StepKeywordType_ACTION, + + "Wtedy ": messages.StepKeywordType_OUTCOME, + + "Oraz ": messages.StepKeywordType_CONJUNCTION, + + "I ": messages.StepKeywordType_CONJUNCTION, + + "Ale ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "pt": &Dialect{ + Language: "pt", + Name: "Portuguese", + Native: "português", + Keywords: map[string][]string{ + feature: { + "Funcionalidade", + "Característica", + "Caracteristica", + }, + rule: { + "Regra", + }, + background: { + "Contexto", + "Cenário de Fundo", + "Cenario de Fundo", + "Fundo", + }, + scenario: { + "Exemplo", + "Cenário", + "Cenario", + }, + scenarioOutline: { + "Esquema do Cenário", + "Esquema do Cenario", + "Delineação do Cenário", + "Delineacao do Cenario", + }, + examples: { + "Exemplos", + "Cenários", + "Cenarios", + }, + given: { + "* ", + "Dado ", + "Dada ", + "Dados ", + "Dadas ", + }, + when: { + "* ", + "Quando ", + }, + then: { + "* ", + "Então ", + "Entao ", + }, + and: { + "* ", + "E ", + }, + but: { + "* ", + "Mas ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "Dado ": messages.StepKeywordType_CONTEXT, + + "Dada ": messages.StepKeywordType_CONTEXT, + + "Dados ": messages.StepKeywordType_CONTEXT, + + "Dadas ": messages.StepKeywordType_CONTEXT, + + "Quando ": messages.StepKeywordType_ACTION, + + "Então ": messages.StepKeywordType_OUTCOME, + + "Entao ": messages.StepKeywordType_OUTCOME, + + "E ": messages.StepKeywordType_CONJUNCTION, + + "Mas ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "ro": &Dialect{ + Language: "ro", + Name: "Romanian", + Native: "română", + Keywords: map[string][]string{ + feature: { + "Functionalitate", + "Funcționalitate", + "Funcţionalitate", + }, + rule: { + "Rule", + }, + background: { + "Context", + }, + scenario: { + "Exemplu", + "Scenariu", + }, + scenarioOutline: { + "Structura scenariu", + "Structură scenariu", + }, + examples: { + "Exemple", + }, + given: { + "* ", + "Date fiind ", + "Dat fiind ", + "Dată fiind", + "Dati fiind ", + "Dați fiind ", + "Daţi fiind ", + }, + when: { + "* ", + "Cand ", + "Când ", + }, + then: { + "* ", + "Atunci ", + }, + and: { + "* ", + "Si ", + "Și ", + "Şi ", + }, + but: { + "* ", + "Dar ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "Date fiind ": messages.StepKeywordType_CONTEXT, + + "Dat fiind ": messages.StepKeywordType_CONTEXT, + + "Dată fiind": messages.StepKeywordType_CONTEXT, + + "Dati fiind ": messages.StepKeywordType_CONTEXT, + + "Dați fiind ": messages.StepKeywordType_CONTEXT, + + "Daţi fiind ": messages.StepKeywordType_CONTEXT, + + "Cand ": messages.StepKeywordType_ACTION, + + "Când ": messages.StepKeywordType_ACTION, + + "Atunci ": messages.StepKeywordType_OUTCOME, + + "Si ": messages.StepKeywordType_CONJUNCTION, + + "Și ": messages.StepKeywordType_CONJUNCTION, + + "Şi ": messages.StepKeywordType_CONJUNCTION, + + "Dar ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "ru": &Dialect{ + Language: "ru", + Name: "Russian", + Native: "русский", + Keywords: map[string][]string{ + feature: { + "Функция", + "Функциональность", + "Функционал", + "Свойство", + "Фича", + }, + rule: { + "Правило", + }, + background: { + "Предыстория", + "Контекст", + }, + scenario: { + "Пример", + "Сценарий", + }, + scenarioOutline: { + "Структура сценария", + "Шаблон сценария", + }, + examples: { + "Примеры", + "Значения", + }, + given: { + "* ", + "Допустим ", + "Дано ", + "Пусть ", + }, + when: { + "* ", + "Когда ", + "Если ", + }, + then: { + "* ", + "То ", + "Затем ", + "Тогда ", + }, + and: { + "* ", + "И ", + "К тому же ", + "Также ", + }, + but: { + "* ", + "Но ", + "А ", + "Иначе ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "Допустим ": messages.StepKeywordType_CONTEXT, + + "Дано ": messages.StepKeywordType_CONTEXT, + + "Пусть ": messages.StepKeywordType_CONTEXT, + + "Когда ": messages.StepKeywordType_ACTION, + + "Если ": messages.StepKeywordType_ACTION, + + "То ": messages.StepKeywordType_OUTCOME, + + "Затем ": messages.StepKeywordType_OUTCOME, + + "Тогда ": messages.StepKeywordType_OUTCOME, + + "И ": messages.StepKeywordType_CONJUNCTION, + + "К тому же ": messages.StepKeywordType_CONJUNCTION, + + "Также ": messages.StepKeywordType_CONJUNCTION, + + "Но ": messages.StepKeywordType_CONJUNCTION, + + "А ": messages.StepKeywordType_CONJUNCTION, + + "Иначе ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "sk": &Dialect{ + Language: "sk", + Name: "Slovak", + Native: "Slovensky", + Keywords: map[string][]string{ + feature: { + "Požiadavka", + "Funkcia", + "Vlastnosť", + }, + rule: { + "Rule", + }, + background: { + "Pozadie", + }, + scenario: { + "Príklad", + "Scenár", + }, + scenarioOutline: { + "Náčrt Scenáru", + "Náčrt Scenára", + "Osnova Scenára", + }, + examples: { + "Príklady", + }, + given: { + "* ", + "Pokiaľ ", + "Za predpokladu ", + }, + when: { + "* ", + "Keď ", + "Ak ", + }, + then: { + "* ", + "Tak ", + "Potom ", + }, + and: { + "* ", + "A ", + "A tiež ", + "A taktiež ", + "A zároveň ", + }, + but: { + "* ", + "Ale ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "Pokiaľ ": messages.StepKeywordType_CONTEXT, + + "Za predpokladu ": messages.StepKeywordType_CONTEXT, + + "Keď ": messages.StepKeywordType_ACTION, + + "Ak ": messages.StepKeywordType_ACTION, + + "Tak ": messages.StepKeywordType_OUTCOME, + + "Potom ": messages.StepKeywordType_OUTCOME, + + "A ": messages.StepKeywordType_CONJUNCTION, + + "A tiež ": messages.StepKeywordType_CONJUNCTION, + + "A taktiež ": messages.StepKeywordType_CONJUNCTION, + + "A zároveň ": messages.StepKeywordType_CONJUNCTION, + + "Ale ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "sl": &Dialect{ + Language: "sl", + Name: "Slovenian", + Native: "Slovenski", + Keywords: map[string][]string{ + feature: { + "Funkcionalnost", + "Funkcija", + "Možnosti", + "Moznosti", + "Lastnost", + "Značilnost", + }, + rule: { + "Rule", + }, + background: { + "Kontekst", + "Osnova", + "Ozadje", + }, + scenario: { + "Primer", + "Scenarij", + }, + scenarioOutline: { + "Struktura scenarija", + "Skica", + "Koncept", + "Oris scenarija", + "Osnutek", + }, + examples: { + "Primeri", + "Scenariji", + }, + given: { + "Dano ", + "Podano ", + "Zaradi ", + "Privzeto ", + }, + when: { + "Ko ", + "Ce ", + "Če ", + "Kadar ", + }, + then: { + "Nato ", + "Potem ", + "Takrat ", + }, + and: { + "In ", + "Ter ", + }, + but: { + "Toda ", + "Ampak ", + "Vendar ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "Dano ": messages.StepKeywordType_CONTEXT, + + "Podano ": messages.StepKeywordType_CONTEXT, + + "Zaradi ": messages.StepKeywordType_CONTEXT, + + "Privzeto ": messages.StepKeywordType_CONTEXT, + + "Ko ": messages.StepKeywordType_ACTION, + + "Ce ": messages.StepKeywordType_ACTION, + + "Če ": messages.StepKeywordType_ACTION, + + "Kadar ": messages.StepKeywordType_ACTION, + + "Nato ": messages.StepKeywordType_OUTCOME, + + "Potem ": messages.StepKeywordType_OUTCOME, + + "Takrat ": messages.StepKeywordType_OUTCOME, + + "In ": messages.StepKeywordType_CONJUNCTION, + + "Ter ": messages.StepKeywordType_CONJUNCTION, + + "Toda ": messages.StepKeywordType_CONJUNCTION, + + "Ampak ": messages.StepKeywordType_CONJUNCTION, + + "Vendar ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "sr-Cyrl": &Dialect{ + Language: "sr-Cyrl", + Name: "Serbian", + Native: "Српски", + Keywords: map[string][]string{ + feature: { + "Функционалност", + "Могућност", + "Особина", + }, + rule: { + "Правило", + }, + background: { + "Контекст", + "Основа", + "Позадина", + }, + scenario: { + "Сценарио", + "Пример", + }, + scenarioOutline: { + "Структура сценарија", + "Скица", + "Концепт", + }, + examples: { + "Примери", + "Сценарији", + }, + given: { + "* ", + "За дато ", + "За дате ", + "За дати ", + }, + when: { + "* ", + "Када ", + "Кад ", + }, + then: { + "* ", + "Онда ", + }, + and: { + "* ", + "И ", + }, + but: { + "* ", + "Али ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "За дато ": messages.StepKeywordType_CONTEXT, + + "За дате ": messages.StepKeywordType_CONTEXT, + + "За дати ": messages.StepKeywordType_CONTEXT, + + "Када ": messages.StepKeywordType_ACTION, + + "Кад ": messages.StepKeywordType_ACTION, + + "Онда ": messages.StepKeywordType_OUTCOME, + + "И ": messages.StepKeywordType_CONJUNCTION, + + "Али ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "sr-Latn": &Dialect{ + Language: "sr-Latn", + Name: "Serbian (Latin)", + Native: "Srpski (Latinica)", + Keywords: map[string][]string{ + feature: { + "Funkcionalnost", + "Mogućnost", + "Mogucnost", + "Osobina", + }, + rule: { + "Pravilo", + }, + background: { + "Kontekst", + "Osnova", + "Pozadina", + }, + scenario: { + "Scenario", + "Primer", + }, + scenarioOutline: { + "Struktura scenarija", + "Skica", + "Koncept", + }, + examples: { + "Primeri", + "Scenariji", + }, + given: { + "* ", + "Za dato ", + "Za date ", + "Za dati ", + }, + when: { + "* ", + "Kada ", + "Kad ", + }, + then: { + "* ", + "Onda ", + }, + and: { + "* ", + "I ", + }, + but: { + "* ", + "Ali ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "Za dato ": messages.StepKeywordType_CONTEXT, + + "Za date ": messages.StepKeywordType_CONTEXT, + + "Za dati ": messages.StepKeywordType_CONTEXT, + + "Kada ": messages.StepKeywordType_ACTION, + + "Kad ": messages.StepKeywordType_ACTION, + + "Onda ": messages.StepKeywordType_OUTCOME, + + "I ": messages.StepKeywordType_CONJUNCTION, + + "Ali ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "sv": &Dialect{ + Language: "sv", + Name: "Swedish", + Native: "Svenska", + Keywords: map[string][]string{ + feature: { + "Egenskap", + }, + rule: { + "Regel", + }, + background: { + "Bakgrund", + }, + scenario: { + "Scenario", + }, + scenarioOutline: { + "Abstrakt Scenario", + "Scenariomall", + }, + examples: { + "Exempel", + }, + given: { + "* ", + "Givet ", + }, + when: { + "* ", + "När ", + }, + then: { + "* ", + "Så ", + }, + and: { + "* ", + "Och ", + }, + but: { + "* ", + "Men ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "Givet ": messages.StepKeywordType_CONTEXT, + + "När ": messages.StepKeywordType_ACTION, + + "Så ": messages.StepKeywordType_OUTCOME, + + "Och ": messages.StepKeywordType_CONJUNCTION, + + "Men ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "ta": &Dialect{ + Language: "ta", + Name: "Tamil", + Native: "தமிழ்", + Keywords: map[string][]string{ + feature: { + "அம்சம்", + "வணிக தேவை", + "திறன்", + }, + rule: { + "Rule", + }, + background: { + "பின்னணி", + }, + scenario: { + "உதாரணமாக", + "காட்சி", + }, + scenarioOutline: { + "காட்சி சுருக்கம்", + "காட்சி வார்ப்புரு", + }, + examples: { + "எடுத்துக்காட்டுகள்", + "காட்சிகள்", + "நிலைமைகளில்", + }, + given: { + "* ", + "கொடுக்கப்பட்ட ", + }, + when: { + "* ", + "எப்போது ", + }, + then: { + "* ", + "அப்பொழுது ", + }, + and: { + "* ", + "மேலும் ", + "மற்றும் ", + }, + but: { + "* ", + "ஆனால் ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "கொடுக்கப்பட்ட ": messages.StepKeywordType_CONTEXT, + + "எப்போது ": messages.StepKeywordType_ACTION, + + "அப்பொழுது ": messages.StepKeywordType_OUTCOME, + + "மேலும் ": messages.StepKeywordType_CONJUNCTION, + + "மற்றும் ": messages.StepKeywordType_CONJUNCTION, + + "ஆனால் ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "th": &Dialect{ + Language: "th", + Name: "Thai", + Native: "ไทย", + Keywords: map[string][]string{ + feature: { + "โครงหลัก", + "ความต้องการทางธุรกิจ", + "ความสามารถ", + }, + rule: { + "Rule", + }, + background: { + "แนวคิด", + }, + scenario: { + "เหตุการณ์", + }, + scenarioOutline: { + "สรุปเหตุการณ์", + "โครงสร้างของเหตุการณ์", + }, + examples: { + "ชุดของตัวอย่าง", + "ชุดของเหตุการณ์", + }, + given: { + "* ", + "กำหนดให้ ", + }, + when: { + "* ", + "เมื่อ ", + }, + then: { + "* ", + "ดังนั้น ", + }, + and: { + "* ", + "และ ", + }, + but: { + "* ", + "แต่ ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "กำหนดให้ ": messages.StepKeywordType_CONTEXT, + + "เมื่อ ": messages.StepKeywordType_ACTION, + + "ดังนั้น ": messages.StepKeywordType_OUTCOME, + + "และ ": messages.StepKeywordType_CONJUNCTION, + + "แต่ ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "te": &Dialect{ + Language: "te", + Name: "Telugu", + Native: "తెలుగు", + Keywords: map[string][]string{ + feature: { + "గుణము", + }, + rule: { + "Rule", + }, + background: { + "నేపథ్యం", + }, + scenario: { + "ఉదాహరణ", + "సన్నివేశం", + }, + scenarioOutline: { + "కథనం", + }, + examples: { + "ఉదాహరణలు", + }, + given: { + "* ", + "చెప్పబడినది ", + }, + when: { + "* ", + "ఈ పరిస్థితిలో ", + }, + then: { + "* ", + "అప్పుడు ", + }, + and: { + "* ", + "మరియు ", + }, + but: { + "* ", + "కాని ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "చెప్పబడినది ": messages.StepKeywordType_CONTEXT, + + "ఈ పరిస్థితిలో ": messages.StepKeywordType_ACTION, + + "అప్పుడు ": messages.StepKeywordType_OUTCOME, + + "మరియు ": messages.StepKeywordType_CONJUNCTION, + + "కాని ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "tlh": &Dialect{ + Language: "tlh", + Name: "Klingon", + Native: "tlhIngan", + Keywords: map[string][]string{ + feature: { + "Qap", + "Qu'meH 'ut", + "perbogh", + "poQbogh malja'", + "laH", + }, + rule: { + "Rule", + }, + background: { + "mo'", + }, + scenario: { + "lut", + }, + scenarioOutline: { + "lut chovnatlh", + }, + examples: { + "ghantoH", + "lutmey", + }, + given: { + "* ", + "ghu' noblu' ", + "DaH ghu' bejlu' ", + }, + when: { + "* ", + "qaSDI' ", + }, + then: { + "* ", + "vaj ", + }, + and: { + "* ", + "'ej ", + "latlh ", + }, + but: { + "* ", + "'ach ", + "'a ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "ghu' noblu' ": messages.StepKeywordType_CONTEXT, + + "DaH ghu' bejlu' ": messages.StepKeywordType_CONTEXT, + + "qaSDI' ": messages.StepKeywordType_ACTION, + + "vaj ": messages.StepKeywordType_OUTCOME, + + "'ej ": messages.StepKeywordType_CONJUNCTION, + + "latlh ": messages.StepKeywordType_CONJUNCTION, + + "'ach ": messages.StepKeywordType_CONJUNCTION, + + "'a ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "tr": &Dialect{ + Language: "tr", + Name: "Turkish", + Native: "Türkçe", + Keywords: map[string][]string{ + feature: { + "Özellik", + "İş Gereksinimi", + "Gereksinim", + "İşlev", + "Kullanıcı Hikayesi", + "Yetenek", + "Teknik Gereksinim", + }, + rule: { + "Kural", + "İş Kuralı", + "Kaide", + "Hüküm", + "Madde", + }, + background: { + "Geçmiş", + "Arka Plan", + "Ön Koşul", + "Önkoşul", + "Önceki Durum", + "Giriş", + "Mukaddime", + "Mevcut Durum", + }, + scenario: { + "Örnek", + "Senaryo", + "Durum", + "Vaka", + }, + scenarioOutline: { + "Senaryo taslağı", + "Senaryo şablonu", + }, + examples: { + "Örnekler", + "Değerler", + }, + given: { + "* ", + "Mevcut ", + "Önceden ", + "Geçmişte ", + "Daha önce ", + "Halihazırda ", + "Zaten ", + "Sistemde ", + "Diyelim ki ", + "Varsayalım ki ", + "Farz edelim ki ", + "Kabul edelim ki ", + "Başlangıçta ", + "Varsayılan olarak ", + "Biliniyor ki ", + }, + when: { + "* ", + "Eğer ", + "Eğer ki ", + "Ne zaman ", + "Ne zaman ki ", + "Şayet ", + }, + then: { + "* ", + "Beklenen ", + "O zaman ", + "Sonuç olarak ", + "Böylece ", + "Bunun üzerine ", + "Bu durumda ", + "O takdirde ", + "Şu halde ", + "Netice itibariyle ", + "Buna binaen ", + }, + and: { + "* ", + "Ve ", + "Hem de ", + "Bir de ", + "Ayrıca ", + "İlaveten ", + "Buna ek olarak ", + }, + but: { + "* ", + "Fakat ", + "Ama ", + "Ancak ", + "Yalnız ", + "Lakin ", + "Meğer ki ", + "Buna mukabil ", + "Aksi halde ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "Mevcut ": messages.StepKeywordType_CONTEXT, + + "Önceden ": messages.StepKeywordType_CONTEXT, + + "Geçmişte ": messages.StepKeywordType_CONTEXT, + + "Daha önce ": messages.StepKeywordType_CONTEXT, + + "Halihazırda ": messages.StepKeywordType_CONTEXT, + + "Zaten ": messages.StepKeywordType_CONTEXT, + + "Sistemde ": messages.StepKeywordType_CONTEXT, + + "Diyelim ki ": messages.StepKeywordType_CONTEXT, + + "Varsayalım ki ": messages.StepKeywordType_CONTEXT, + + "Farz edelim ki ": messages.StepKeywordType_CONTEXT, + + "Kabul edelim ki ": messages.StepKeywordType_CONTEXT, + + "Başlangıçta ": messages.StepKeywordType_CONTEXT, + + "Varsayılan olarak ": messages.StepKeywordType_CONTEXT, + + "Biliniyor ki ": messages.StepKeywordType_CONTEXT, + + "Eğer ": messages.StepKeywordType_ACTION, + + "Eğer ki ": messages.StepKeywordType_ACTION, + + "Ne zaman ": messages.StepKeywordType_ACTION, + + "Ne zaman ki ": messages.StepKeywordType_ACTION, + + "Şayet ": messages.StepKeywordType_ACTION, + + "Beklenen ": messages.StepKeywordType_OUTCOME, + + "O zaman ": messages.StepKeywordType_OUTCOME, + + "Sonuç olarak ": messages.StepKeywordType_OUTCOME, + + "Böylece ": messages.StepKeywordType_OUTCOME, + + "Bunun üzerine ": messages.StepKeywordType_OUTCOME, + + "Bu durumda ": messages.StepKeywordType_OUTCOME, + + "O takdirde ": messages.StepKeywordType_OUTCOME, + + "Şu halde ": messages.StepKeywordType_OUTCOME, + + "Netice itibariyle ": messages.StepKeywordType_OUTCOME, + + "Buna binaen ": messages.StepKeywordType_OUTCOME, + + "Ve ": messages.StepKeywordType_CONJUNCTION, + + "Hem de ": messages.StepKeywordType_CONJUNCTION, + + "Bir de ": messages.StepKeywordType_CONJUNCTION, + + "Ayrıca ": messages.StepKeywordType_CONJUNCTION, + + "İlaveten ": messages.StepKeywordType_CONJUNCTION, + + "Buna ek olarak ": messages.StepKeywordType_CONJUNCTION, + + "Fakat ": messages.StepKeywordType_CONJUNCTION, + + "Ama ": messages.StepKeywordType_CONJUNCTION, + + "Ancak ": messages.StepKeywordType_CONJUNCTION, + + "Yalnız ": messages.StepKeywordType_CONJUNCTION, + + "Lakin ": messages.StepKeywordType_CONJUNCTION, + + "Meğer ki ": messages.StepKeywordType_CONJUNCTION, + + "Buna mukabil ": messages.StepKeywordType_CONJUNCTION, + + "Aksi halde ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "tt": &Dialect{ + Language: "tt", + Name: "Tatar", + Native: "Татарча", + Keywords: map[string][]string{ + feature: { + "Мөмкинлек", + "Үзенчәлеклелек", + }, + rule: { + "Rule", + }, + background: { + "Кереш", + }, + scenario: { + "Сценарий", + }, + scenarioOutline: { + "Сценарийның төзелеше", + }, + examples: { + "Үрнәкләр", + "Мисаллар", + }, + given: { + "* ", + "Әйтик ", + }, + when: { + "* ", + "Әгәр ", + }, + then: { + "* ", + "Нәтиҗәдә ", + }, + and: { + "* ", + "Һәм ", + "Вә ", + }, + but: { + "* ", + "Ләкин ", + "Әмма ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "Әйтик ": messages.StepKeywordType_CONTEXT, + + "Әгәр ": messages.StepKeywordType_ACTION, + + "Нәтиҗәдә ": messages.StepKeywordType_OUTCOME, + + "Һәм ": messages.StepKeywordType_CONJUNCTION, + + "Вә ": messages.StepKeywordType_CONJUNCTION, + + "Ләкин ": messages.StepKeywordType_CONJUNCTION, + + "Әмма ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "uk": &Dialect{ + Language: "uk", + Name: "Ukrainian", + Native: "Українська", + Keywords: map[string][]string{ + feature: { + "Функціонал", + }, + rule: { + "Rule", + }, + background: { + "Передумова", + }, + scenario: { + "Приклад", + "Сценарій", + }, + scenarioOutline: { + "Структура сценарію", + }, + examples: { + "Приклади", + }, + given: { + "* ", + "Припустимо ", + "Припустимо, що ", + "Нехай ", + "Дано ", + }, + when: { + "* ", + "Якщо ", + "Коли ", + }, + then: { + "* ", + "То ", + "Тоді ", + }, + and: { + "* ", + "І ", + "А також ", + "Та ", + }, + but: { + "* ", + "Але ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "Припустимо ": messages.StepKeywordType_CONTEXT, + + "Припустимо, що ": messages.StepKeywordType_CONTEXT, + + "Нехай ": messages.StepKeywordType_CONTEXT, + + "Дано ": messages.StepKeywordType_CONTEXT, + + "Якщо ": messages.StepKeywordType_ACTION, + + "Коли ": messages.StepKeywordType_ACTION, + + "То ": messages.StepKeywordType_OUTCOME, + + "Тоді ": messages.StepKeywordType_OUTCOME, + + "І ": messages.StepKeywordType_CONJUNCTION, + + "А також ": messages.StepKeywordType_CONJUNCTION, + + "Та ": messages.StepKeywordType_CONJUNCTION, + + "Але ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "ur": &Dialect{ + Language: "ur", + Name: "Urdu", + Native: "اردو", + Keywords: map[string][]string{ + feature: { + "صلاحیت", + "کاروبار کی ضرورت", + "خصوصیت", + }, + rule: { + "Rule", + }, + background: { + "پس منظر", + }, + scenario: { + "منظرنامہ", + }, + scenarioOutline: { + "منظر نامے کا خاکہ", + }, + examples: { + "مثالیں", + }, + given: { + "* ", + "اگر ", + "بالفرض ", + "فرض کیا ", + }, + when: { + "* ", + "جب ", + }, + then: { + "* ", + "پھر ", + "تب ", + }, + and: { + "* ", + "اور ", + }, + but: { + "* ", + "لیکن ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "اگر ": messages.StepKeywordType_CONTEXT, + + "بالفرض ": messages.StepKeywordType_CONTEXT, + + "فرض کیا ": messages.StepKeywordType_CONTEXT, + + "جب ": messages.StepKeywordType_ACTION, + + "پھر ": messages.StepKeywordType_OUTCOME, + + "تب ": messages.StepKeywordType_OUTCOME, + + "اور ": messages.StepKeywordType_CONJUNCTION, + + "لیکن ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "uz": &Dialect{ + Language: "uz", + Name: "Uzbek", + Native: "Узбекча", + Keywords: map[string][]string{ + feature: { + "Функционал", + }, + rule: { + "Rule", + }, + background: { + "Тарих", + }, + scenario: { + "Сценарий", + }, + scenarioOutline: { + "Сценарий структураси", + }, + examples: { + "Мисоллар", + }, + given: { + "* ", + "Belgilangan ", + }, + when: { + "* ", + "Агар ", + }, + then: { + "* ", + "Унда ", + }, + and: { + "* ", + "Ва ", + }, + but: { + "* ", + "Лекин ", + "Бирок ", + "Аммо ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "Belgilangan ": messages.StepKeywordType_CONTEXT, + + "Агар ": messages.StepKeywordType_ACTION, + + "Унда ": messages.StepKeywordType_OUTCOME, + + "Ва ": messages.StepKeywordType_CONJUNCTION, + + "Лекин ": messages.StepKeywordType_CONJUNCTION, + + "Бирок ": messages.StepKeywordType_CONJUNCTION, + + "Аммо ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "vi": &Dialect{ + Language: "vi", + Name: "Vietnamese", + Native: "Tiếng Việt", + Keywords: map[string][]string{ + feature: { + "Tính năng", + }, + rule: { + "Quy tắc", + }, + background: { + "Bối cảnh", + }, + scenario: { + "Tình huống", + "Kịch bản", + }, + scenarioOutline: { + "Khung tình huống", + "Khung kịch bản", + }, + examples: { + "Dữ liệu", + }, + given: { + "* ", + "Biết ", + "Cho ", + }, + when: { + "* ", + "Khi ", + }, + then: { + "* ", + "Thì ", + }, + and: { + "* ", + "Và ", + }, + but: { + "* ", + "Nhưng ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "Biết ": messages.StepKeywordType_CONTEXT, + + "Cho ": messages.StepKeywordType_CONTEXT, + + "Khi ": messages.StepKeywordType_ACTION, + + "Thì ": messages.StepKeywordType_OUTCOME, + + "Và ": messages.StepKeywordType_CONJUNCTION, + + "Nhưng ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "zh-CN": &Dialect{ + Language: "zh-CN", + Name: "Chinese simplified", + Native: "简体中文", + Keywords: map[string][]string{ + feature: { + "功能", + }, + rule: { + "Rule", + "规则", + }, + background: { + "背景", + }, + scenario: { + "场景", + "剧本", + }, + scenarioOutline: { + "场景大纲", + "剧本大纲", + }, + examples: { + "例子", + }, + given: { + "* ", + "假如", + "假设", + "假定", + }, + when: { + "* ", + "当", + }, + then: { + "* ", + "那么", + }, + and: { + "* ", + "而且", + "并且", + "同时", + }, + but: { + "* ", + "但是", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "假如": messages.StepKeywordType_CONTEXT, + + "假设": messages.StepKeywordType_CONTEXT, + + "假定": messages.StepKeywordType_CONTEXT, + + "当": messages.StepKeywordType_ACTION, + + "那么": messages.StepKeywordType_OUTCOME, + + "而且": messages.StepKeywordType_CONJUNCTION, + + "并且": messages.StepKeywordType_CONJUNCTION, + + "同时": messages.StepKeywordType_CONJUNCTION, + + "但是": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "ml": &Dialect{ + Language: "ml", + Name: "Malayalam", + Native: "മലയാളം", + Keywords: map[string][]string{ + feature: { + "സവിശേഷത", + }, + rule: { + "നിയമം", + }, + background: { + "പശ്ചാത്തലം", + }, + scenario: { + "രംഗം", + }, + scenarioOutline: { + "സാഹചര്യത്തിന്റെ രൂപരേഖ", + }, + examples: { + "ഉദാഹരണങ്ങൾ", + }, + given: { + "* ", + "നൽകിയത്", + }, + when: { + "എപ്പോൾ", + }, + then: { + "* ", + "പിന്നെ", + }, + and: { + "* ", + "ഒപ്പം", + }, + but: { + "* ", + "പക്ഷേ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "നൽകിയത്": messages.StepKeywordType_CONTEXT, + + "എപ്പോൾ": messages.StepKeywordType_ACTION, + + "പിന്നെ": messages.StepKeywordType_OUTCOME, + + "ഒപ്പം": messages.StepKeywordType_CONJUNCTION, + + "പക്ഷേ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "zh-TW": &Dialect{ + Language: "zh-TW", + Name: "Chinese traditional", + Native: "繁體中文", + Keywords: map[string][]string{ + feature: { + "功能", + }, + rule: { + "Rule", + }, + background: { + "背景", + }, + scenario: { + "場景", + "劇本", + }, + scenarioOutline: { + "場景大綱", + "劇本大綱", + }, + examples: { + "例子", + }, + given: { + "* ", + "假如", + "假設", + "假定", + }, + when: { + "* ", + "當", + }, + then: { + "* ", + "那麼", + }, + and: { + "* ", + "而且", + "並且", + "同時", + }, + but: { + "* ", + "但是", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "假如": messages.StepKeywordType_CONTEXT, + + "假設": messages.StepKeywordType_CONTEXT, + + "假定": messages.StepKeywordType_CONTEXT, + + "當": messages.StepKeywordType_ACTION, + + "那麼": messages.StepKeywordType_OUTCOME, + + "而且": messages.StepKeywordType_CONJUNCTION, + + "並且": messages.StepKeywordType_CONJUNCTION, + + "同時": messages.StepKeywordType_CONJUNCTION, + + "但是": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "mr": &Dialect{ + Language: "mr", + Name: "Marathi", + Native: "मराठी", + Keywords: map[string][]string{ + feature: { + "वैशिष्ट्य", + "सुविधा", + }, + rule: { + "नियम", + }, + background: { + "पार्श्वभूमी", + }, + scenario: { + "परिदृश्य", + }, + scenarioOutline: { + "परिदृश्य रूपरेखा", + }, + examples: { + "उदाहरण", + }, + given: { + "* ", + "जर", + "दिलेल्या प्रमाणे ", + }, + when: { + "* ", + "जेव्हा ", + }, + then: { + "* ", + "मग ", + "तेव्हा ", + }, + and: { + "* ", + "आणि ", + "तसेच ", + }, + but: { + "* ", + "पण ", + "परंतु ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "जर": messages.StepKeywordType_CONTEXT, + + "दिलेल्या प्रमाणे ": messages.StepKeywordType_CONTEXT, + + "जेव्हा ": messages.StepKeywordType_ACTION, + + "मग ": messages.StepKeywordType_OUTCOME, + + "तेव्हा ": messages.StepKeywordType_OUTCOME, + + "आणि ": messages.StepKeywordType_CONJUNCTION, + + "तसेच ": messages.StepKeywordType_CONJUNCTION, + + "पण ": messages.StepKeywordType_CONJUNCTION, + + "परंतु ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, + "amh": &Dialect{ + Language: "amh", + Name: "Amharic", + Native: "አማርኛ", + Keywords: map[string][]string{ + feature: { + "ስራ", + "የተፈለገው ስራ", + "የሚፈለገው ድርጊት", + }, + rule: { + "ህግ", + }, + background: { + "ቅድመ ሁኔታ", + "መነሻ", + "መነሻ ሀሳብ", + }, + scenario: { + "ምሳሌ", + "ሁናቴ", + }, + scenarioOutline: { + "ሁናቴ ዝርዝር", + "ሁናቴ አብነት", + }, + examples: { + "ምሳሌዎች", + "ሁናቴዎች", + }, + given: { + "* ", + "የተሰጠ ", + }, + when: { + "* ", + "መቼ ", + }, + then: { + "* ", + "ከዚያ ", + }, + and: { + "* ", + "እና ", + }, + but: { + "* ", + "ግን ", + }, + }, + KeywordTypes: map[string]messages.StepKeywordType{ + "የተሰጠ ": messages.StepKeywordType_CONTEXT, + + "መቼ ": messages.StepKeywordType_ACTION, + + "ከዚያ ": messages.StepKeywordType_OUTCOME, + + "እና ": messages.StepKeywordType_CONJUNCTION, + + "ግን ": messages.StepKeywordType_CONJUNCTION, + + "* ": messages.StepKeywordType_UNKNOWN, + }, + }, +} diff --git a/vendor/github.com/cucumber/gherkin/go/v42/dialects_builtin.go.jq b/vendor/github.com/cucumber/gherkin/go/v42/dialects_builtin.go.jq new file mode 100644 index 0000000000..722844d2e9 --- /dev/null +++ b/vendor/github.com/cucumber/gherkin/go/v42/dialects_builtin.go.jq @@ -0,0 +1,114 @@ +. as $root +| ( + [ to_entries[] + | [ + "\t",(.key|@json),": &Dialect{\n", + "\t\tLanguage: ", (.key|@json), ",\n", + "\t\tName: ", (.value.name|@json),",\n", + "\t\tNative: ",(.value.native|@json),",\n", + "\t\tKeywords: map[string][]string{\n" + ] + ( + [ .value + | {"feature","rule","background","scenario","scenarioOutline","examples","given","when","then","and","but"} + | to_entries[] + | "\t\t\t"+(.key), ": {\n", + ([ .value[] | "\t\t\t\t", @json, ",\n" ]|add), + "\t\t\t},\n" + ] + ) + [ + "\t\t},\n", + "\t\tKeywordTypes: map[string]messages.StepKeywordType{\n" + ] + ( + [ .value.given + | ( + [ .[] | select(. != "* ") | + "\t\t\t", + @json, + ": messages.StepKeywordType_CONTEXT", + ",\n\n" + ] | add + ), + "" + ] + + + [ .value.when + | ( + [ .[] | select(. != "* ") | + "\t\t\t", + @json, + ": messages.StepKeywordType_ACTION", + ",\n\n" + ] | add + ), + "" + ] + + + [ .value.then + | ( + [ .[] | select(. != "* ") | + "\t\t\t", + @json, + ": messages.StepKeywordType_OUTCOME", + ",\n\n" + ] | add + ), + "" + ] + + + [ .value.and + | ( + [ .[] | select(. != "* ") | + "\t\t\t", + @json, + ": messages.StepKeywordType_CONJUNCTION", + ",\n\n" + ] | add + ), + "" + ] + + + [ .value.but + | ( + [ .[] | select(. != "* ") | + "\t\t\t", + @json, + ": messages.StepKeywordType_CONJUNCTION", + ",\n\n" + ] | add + ), + "" + ] + + [ + "\t\t\t\"* \": messages.StepKeywordType_UNKNOWN,\n" + ] + ) + [ + "\t\t},\n", + "\t},\n" + ] + | add + ] + | add + ) +| "// Code generated from dialects_builtin.go.jq (make dialects_builtin.go); DO NOT EDIT.\n\n" # Standard header defined at https://golang.org/s/generatedcode ++ "package gherkin\n\n" ++ "import messages \"github.com/cucumber/messages/go/v34\"\n\n" ++ "// Builtin dialects for " + ([ $root | to_entries[] | .key+" ("+.value.name+")" ] | join(", ")) + "\n" ++ "func DialectsBuiltin() DialectProvider {\n" ++ "\treturn builtinDialects\n" ++ "}\n\n" ++ "const (\n" ++ " feature = \"feature\"\n" ++ " rule = \"rule\"\n" ++ " background = \"background\"\n" ++ " scenario = \"scenario\"\n" ++ " scenarioOutline = \"scenarioOutline\"\n" ++ " examples = \"examples\"\n" ++ " given = \"given\"\n" ++ " when = \"when\"\n" ++ " then = \"then\"\n" ++ " and = \"and\"\n" ++ " but = \"but\"\n" ++ ")\n\n" ++ "var builtinDialects = gherkinDialectMap{\n" ++ . ++ "}" diff --git a/vendor/github.com/cucumber/gherkin/go/v42/gherkin.go b/vendor/github.com/cucumber/gherkin/go/v42/gherkin.go new file mode 100644 index 0000000000..a5fdfc356f --- /dev/null +++ b/vendor/github.com/cucumber/gherkin/go/v42/gherkin.go @@ -0,0 +1,144 @@ +package gherkin + +import ( + "bufio" + "fmt" + "io" + "strings" + + messages "github.com/cucumber/messages/go/v34" +) + +type Parser interface { + StopAtFirstError(b bool) + Parse(s Scanner, m Matcher) (err error) +} + +/* +The Scanner reads a gherkin doc (typically read from a .feature file) and creates a token for +each line. The tokens are passed to the parser, which outputs an AST (Abstract Syntax Tree). + +If the scanner sees a # language header, it will reconfigure itself dynamically to look for +Gherkin keywords for the associated language. The keywords are defined in gherkin-languages.json. +*/ +type Scanner interface { + Scan() (line *Line, atEof bool, err error) +} + +type Builder interface { + Build(*Token) (bool, error) + StartRule(RuleType) (bool, error) + EndRule(RuleType) (bool, error) + Reset() +} + +type Token struct { + Type TokenType + Keyword string + KeywordType messages.StepKeywordType + Text string + Items []*LineSpan + GherkinDialect string + Indent string + Location *Location +} + +func (t *Token) IsEOF() bool { + return t.Type == TokenTypeEOF +} +func (t *Token) String() string { + return fmt.Sprintf("%v: %s/%s", t.Type, t.Keyword, t.Text) +} + +type LineSpan struct { + Column int + Text string +} + +func (l *LineSpan) String() string { + return fmt.Sprintf("%d:%s", l.Column, l.Text) +} + +type parser struct { + builder Builder + stopAtFirstError bool +} + +func NewParser(b Builder) Parser { + return &parser{ + builder: b, + } +} + +func (p *parser) StopAtFirstError(b bool) { + p.stopAtFirstError = b +} + +func NewScanner(r io.Reader) Scanner { + return &scanner{ + s: bufio.NewScanner(r), + line: 0, + } +} + +type scanner struct { + s *bufio.Scanner + line int +} + +func (t *scanner) Scan() (line *Line, atEof bool, err error) { + scanning := t.s.Scan() + if !scanning { + err = t.s.Err() + if err == nil { + atEof = true + } + } + if err == nil { + t.line += 1 + str := t.s.Text() + line = &Line{str, t.line, strings.TrimLeft(str, " \t"), atEof} + } + return +} + +type Line struct { + LineText string + LineNumber int + TrimmedLineText string + AtEof bool +} + +func (g *Line) Indent() int { + return len(g.LineText) - len(g.TrimmedLineText) +} + +func (g *Line) IsEmpty() bool { + return len(g.TrimmedLineText) == 0 +} + +func (g *Line) IsEof() bool { + return g.AtEof +} + +func (g *Line) StartsWith(prefix string) bool { + return strings.HasPrefix(g.TrimmedLineText, prefix) +} + +func ParseGherkinDocument(in io.Reader, newId func() string) (gherkinDocument *messages.GherkinDocument, err error) { + return ParseGherkinDocumentForLanguage(in, DefaultDialect, newId) +} + +func ParseGherkinDocumentForLanguage(in io.Reader, language string, newId func() string) (gherkinDocument *messages.GherkinDocument, err error) { + + builder := NewAstBuilder(newId) + parser := NewParser(builder) + parser.StopAtFirstError(false) + matcher := NewLanguageMatcher(DialectsBuiltin(), language) + + scanner := NewScanner(in) + + err = parser.Parse(scanner, matcher) + + return builder.GetGherkinDocument(), err +} diff --git a/vendor/github.com/cucumber/gherkin/go/v42/matcher.go b/vendor/github.com/cucumber/gherkin/go/v42/matcher.go new file mode 100644 index 0000000000..2c94bcd9a2 --- /dev/null +++ b/vendor/github.com/cucumber/gherkin/go/v42/matcher.go @@ -0,0 +1,305 @@ +package gherkin + +import ( + "regexp" + "strings" + "unicode" + "unicode/utf8" +) + +const ( + DefaultDialect = "en" + CommentPrefix = "#" + TagPrefix = "@" + TitleKeywordSeparator = ":" + TableCellSeparator = '|' + EscapeChar = '\\' + EscapedNewline = 'n' + DocstringSeparator = "\"\"\"" + DocstringAlternativeSeparator = "```" +) + +var ( + defaultLanguagePattern = regexp.MustCompile("^\\s*#\\s*language\\s*:\\s*([a-zA-Z\\-_]+)\\s*$") + commentDelimiterPattern = regexp.MustCompile(`\s+` + CommentPrefix) +) + +type matcher struct { + gdp DialectProvider + defaultLang string + lang string + dialect *Dialect + activeDocStringSeparator string + indentToRemove int + languagePattern *regexp.Regexp +} + +func NewMatcher(gdp DialectProvider) Matcher { + return &matcher{ + gdp: gdp, + defaultLang: DefaultDialect, + lang: DefaultDialect, + dialect: gdp.GetDialect(DefaultDialect), + languagePattern: defaultLanguagePattern, + } +} + +func NewLanguageMatcher(gdp DialectProvider, language string) Matcher { + return &matcher{ + gdp: gdp, + defaultLang: language, + lang: language, + dialect: gdp.GetDialect(language), + languagePattern: defaultLanguagePattern, + } +} + +func (m *matcher) Reset() { + m.indentToRemove = 0 + m.activeDocStringSeparator = "" + if m.lang != "en" { + m.dialect = m.gdp.GetDialect(m.defaultLang) + m.lang = "en" + } +} + +func (m *matcher) newTokenAtLocation(line, index int) (token *Token) { + column := index + 1 + token = new(Token) + token.GherkinDialect = m.lang + token.Location = &Location{line, column} + return +} + +func (m *matcher) MatchEOF(line *Line) (ok bool, token *Token, err error) { + if line.IsEof() { + token, ok = m.newTokenAtLocation(line.LineNumber, line.Indent()), true + token.Type = TokenTypeEOF + } + return +} + +func (m *matcher) MatchEmpty(line *Line) (ok bool, token *Token, err error) { + if line.IsEmpty() { + token, ok = m.newTokenAtLocation(line.LineNumber, 0), true + token.Type = TokenTypeEmpty + } + return +} + +func (m *matcher) MatchComment(line *Line) (ok bool, token *Token, err error) { + if line.StartsWith(CommentPrefix) { + token, ok = m.newTokenAtLocation(line.LineNumber, 0), true + token.Type = TokenTypeComment + token.Text = line.LineText + } + return +} + +func (m *matcher) MatchTagLine(line *Line) (ok bool, token *Token, err error) { + if !line.StartsWith(TagPrefix) { + return + } + uncommentedLine := commentDelimiterPattern.Split(line.TrimmedLineText, 2)[0] + var tags []*LineSpan + var column = line.Indent() + 1 + + splits := strings.Split(uncommentedLine, TagPrefix) + for i := range splits { + txt := strings.TrimRightFunc(splits[i], func(r rune) bool { + return unicode.IsSpace(r) + }) + if len(txt) == 0 { + continue + } + if strings.ContainsAny(txt, "\t\n\f\r ") { + location := &Location{line.LineNumber, column} + msg := "A tag may not contain whitespace" + err = &parseError{msg, location} + break + } + tags = append(tags, &LineSpan{column, TagPrefix + txt}) + column = column + utf8.RuneCountInString(splits[i]) + 1 + } + + token, ok = m.newTokenAtLocation(line.LineNumber, line.Indent()), true + token.Type = TokenTypeTagLine + token.Items = tags + + return +} + +func (m *matcher) matchTitleLine(line *Line, tokenType TokenType, keywords []string) (ok bool, token *Token, err error) { + for i := range keywords { + keyword := keywords[i] + if line.StartsWith(keyword + TitleKeywordSeparator) { + token, ok = m.newTokenAtLocation(line.LineNumber, line.Indent()), true + token.Type = tokenType + token.Keyword = keyword + token.Text = strings.Trim(line.TrimmedLineText[len(keyword)+1:], " \t") + return + } + } + return +} + +func (m *matcher) MatchFeatureLine(line *Line) (ok bool, token *Token, err error) { + return m.matchTitleLine(line, TokenTypeFeatureLine, m.dialect.FeatureKeywords()) +} +func (m *matcher) MatchRuleLine(line *Line) (ok bool, token *Token, err error) { + return m.matchTitleLine(line, TokenTypeRuleLine, m.dialect.RuleKeywords()) +} +func (m *matcher) MatchBackgroundLine(line *Line) (ok bool, token *Token, err error) { + return m.matchTitleLine(line, TokenTypeBackgroundLine, m.dialect.BackgroundKeywords()) +} +func (m *matcher) MatchScenarioLine(line *Line) (ok bool, token *Token, err error) { + ok, token, err = m.matchTitleLine(line, TokenTypeScenarioLine, m.dialect.ScenarioKeywords()) + if ok || (err != nil) { + return ok, token, err + } + ok, token, err = m.matchTitleLine(line, TokenTypeScenarioLine, m.dialect.ScenarioOutlineKeywords()) + return ok, token, err +} +func (m *matcher) MatchExamplesLine(line *Line) (ok bool, token *Token, err error) { + return m.matchTitleLine(line, TokenTypeExamplesLine, m.dialect.ExamplesKeywords()) +} +func (m *matcher) MatchStepLine(line *Line) (ok bool, token *Token, err error) { + keywords := m.dialect.StepKeywords() + for i := range keywords { + keyword := keywords[i] + if line.StartsWith(keyword) { + token, ok = m.newTokenAtLocation(line.LineNumber, line.Indent()), true + token.Type = TokenTypeStepLine + token.Keyword = keyword + token.KeywordType = m.dialect.StepKeywordType(keyword) + token.Text = strings.Trim(line.TrimmedLineText[len(keyword):], " \t") + return + } + } + return +} + +func (m *matcher) MatchDocStringSeparator(line *Line) (ok bool, token *Token, err error) { + if m.activeDocStringSeparator != "" { + if line.StartsWith(m.activeDocStringSeparator) { + // close + token, ok = m.newTokenAtLocation(line.LineNumber, line.Indent()), true + token.Type = TokenTypeDocStringSeparator + token.Keyword = m.activeDocStringSeparator + + m.indentToRemove = 0 + m.activeDocStringSeparator = "" + } + return + } + if line.StartsWith(DocstringSeparator) { + m.activeDocStringSeparator = DocstringSeparator + } else if line.StartsWith(DocstringAlternativeSeparator) { + m.activeDocStringSeparator = DocstringAlternativeSeparator + } + if m.activeDocStringSeparator != "" { + // open + mediaType := line.TrimmedLineText[len(m.activeDocStringSeparator):] + m.indentToRemove = line.Indent() + token, ok = m.newTokenAtLocation(line.LineNumber, line.Indent()), true + token.Type = TokenTypeDocStringSeparator + token.Keyword = m.activeDocStringSeparator + token.Text = mediaType + } + return +} + +func isSpaceAndNotNewLine(r rune) bool { + return unicode.IsSpace(r) && r != '\n' +} + +func (m *matcher) MatchTableRow(line *Line) (ok bool, token *Token, err error) { + var firstChar, firstPos = utf8.DecodeRuneInString(line.TrimmedLineText) + if firstChar == TableCellSeparator { + var cells []*LineSpan + var cell []rune + var startCol = line.Indent() + 2 // column where the current cell started + // start after the first separator, it's not included in the cell + for i, w, col := firstPos, 0, startCol; i < len(line.TrimmedLineText); i += w { + var char rune + char, w = utf8.DecodeRuneInString(line.TrimmedLineText[i:]) + if char == TableCellSeparator { + // append current cell + txt := string(cell) + + txtTrimmedLeadingSpace := strings.TrimLeftFunc(txt, isSpaceAndNotNewLine) + ind := utf8.RuneCountInString(txt) - utf8.RuneCountInString(txtTrimmedLeadingSpace) + txtTrimmed := strings.TrimRightFunc(txtTrimmedLeadingSpace, isSpaceAndNotNewLine) + cells = append(cells, &LineSpan{startCol + ind, txtTrimmed}) + // start building next + cell = make([]rune, 0) + startCol = col + 1 + } else if char == EscapeChar { + // skip this character but count the column + i += w + col++ + char, w = utf8.DecodeRuneInString(line.TrimmedLineText[i:]) + if char == EscapedNewline { + cell = append(cell, '\n') + } else { + if char != TableCellSeparator && char != EscapeChar { + cell = append(cell, EscapeChar) + } + cell = append(cell, char) + } + } else { + cell = append(cell, char) + } + col++ + } + + token, ok = m.newTokenAtLocation(line.LineNumber, line.Indent()), true + token.Type = TokenTypeTableRow + token.Items = cells + } + return +} + +func (m *matcher) MatchLanguage(line *Line) (ok bool, token *Token, err error) { + matches := m.languagePattern.FindStringSubmatch(line.TrimmedLineText) + if len(matches) > 0 { + lang := matches[1] + token, ok = m.newTokenAtLocation(line.LineNumber, line.Indent()), true + token.Type = TokenTypeLanguage + token.Text = lang + + dialect := m.gdp.GetDialect(lang) + if dialect == nil { + err = &parseError{"Language not supported: " + lang, token.Location} + } else { + m.lang = lang + m.dialect = dialect + } + } + return +} + +func (m *matcher) MatchOther(line *Line) (ok bool, token *Token, err error) { + token, ok = m.newTokenAtLocation(line.LineNumber, 0), true + token.Type = TokenTypeOther + + element := line.LineText + txt := strings.TrimLeft(element, " ") + + if len(element)-len(txt) > m.indentToRemove { + token.Text = m.unescapeDocString(element[m.indentToRemove:]) + } else { + token.Text = m.unescapeDocString(txt) + } + return +} + +func (m *matcher) unescapeDocString(text string) string { + if m.activeDocStringSeparator == DocstringSeparator { + return strings.Replace(text, "\\\"\\\"\\\"", DocstringSeparator, -1) + } + if m.activeDocStringSeparator == DocstringAlternativeSeparator { + return strings.Replace(text, "\\`\\`\\`", DocstringAlternativeSeparator, -1) + } + return text +} diff --git a/vendor/github.com/cucumber/gherkin/go/v42/messages.go b/vendor/github.com/cucumber/gherkin/go/v42/messages.go new file mode 100644 index 0000000000..dc60ee82e9 --- /dev/null +++ b/vendor/github.com/cucumber/gherkin/go/v42/messages.go @@ -0,0 +1,120 @@ +package gherkin + +import ( + "encoding/json" + "fmt" + "github.com/cucumber/messages/go/v34" + "io" + "io/ioutil" + "strings" +) + +func Messages( + paths []string, + decoder *json.Decoder, + language string, + includeSource bool, + includeGherkinDocument bool, + includePickles bool, + encoder *json.Encoder, + newId func() string, +) ([]messages.Envelope, error) { + var result []messages.Envelope + var err error + + handleMessage := func(result []messages.Envelope, message *messages.Envelope) ([]messages.Envelope, error) { + if encoder != nil { + err = encoder.Encode(message) + return result, err + } else { + result = append(result, *message) + } + + return result, err + } + + processSource := func(source *messages.Source) error { + if includeSource { + result, err = handleMessage(result, &messages.Envelope{ + Source: source, + }) + } + doc, err := ParseGherkinDocumentForLanguage(strings.NewReader(source.Data), language, newId) + if errs, ok := err.(parseErrors); ok { + // expected parse errors + for _, err := range errs { + if pe, ok := err.(*parseError); ok { + result, err = handleMessage(result, pe.asMessage(source.Uri)) + } else { + return fmt.Errorf("parse feature file: %s, unexpected error: %+v\n", source.Uri, err) + } + } + return nil + } + + if includeGherkinDocument { + doc.Uri = source.Uri + result, err = handleMessage(result, &messages.Envelope{ + GherkinDocument: doc, + }) + } + + if includePickles { + for _, pickle := range Pickles(*doc, source.Uri, newId) { + result, err = handleMessage(result, &messages.Envelope{ + Pickle: pickle, + }) + } + } + return nil + } + + if len(paths) == 0 { + for { + envelope := &messages.Envelope{} + err := decoder.Decode(envelope) + //marshal, err := json.Marshal(envelope) + //fmt.Println(string(marshal)) + if err == io.EOF { + break + } + + if envelope.Source != nil { + err = processSource(envelope.Source) + if err != nil { + return result, err + } + } + } + } else { + for _, path := range paths { + in, err := ioutil.ReadFile(path) + if err != nil { + return result, fmt.Errorf("read feature file: %s - %+v", path, err) + } + source := &messages.Source{ + Uri: path, + Data: string(in), + MediaType: "text/x.cucumber.gherkin+plain", + } + processSource(source) + } + } + + return result, err +} + +func (a *parseError) asMessage(uri string) *messages.Envelope { + return &messages.Envelope{ + ParseError: &messages.ParseError{ + Message: a.Error(), + Source: &messages.SourceReference{ + Uri: uri, + Location: &messages.Location{ + Line: int64(a.loc.Line), + Column: int64(a.loc.Column), + }, + }, + }, + } +} diff --git a/vendor/github.com/cucumber/gherkin/go/v42/parser.go b/vendor/github.com/cucumber/gherkin/go/v42/parser.go new file mode 100644 index 0000000000..86e7f556fe --- /dev/null +++ b/vendor/github.com/cucumber/gherkin/go/v42/parser.go @@ -0,0 +1,4929 @@ +// +// This file is generated. Do not edit! Edit parser.go.razor instead. + +package gherkin + +import ( + "fmt" + "strings" +) + +type TokenType int + +const ( + TokenTypeNone TokenType = iota + TokenTypeEOF + TokenTypeEmpty + TokenTypeComment + TokenTypeTagLine + TokenTypeFeatureLine + TokenTypeRuleLine + TokenTypeBackgroundLine + TokenTypeScenarioLine + TokenTypeExamplesLine + TokenTypeStepLine + TokenTypeDocStringSeparator + TokenTypeTableRow + TokenTypeLanguage + TokenTypeOther +) + +func tokenTypeForRule(rt RuleType) TokenType { + return TokenTypeNone +} + +func (t TokenType) Name() string { + switch t { + case TokenTypeEOF: + return "EOF" + case TokenTypeEmpty: + return "Empty" + case TokenTypeComment: + return "Comment" + case TokenTypeTagLine: + return "TagLine" + case TokenTypeFeatureLine: + return "FeatureLine" + case TokenTypeRuleLine: + return "RuleLine" + case TokenTypeBackgroundLine: + return "BackgroundLine" + case TokenTypeScenarioLine: + return "ScenarioLine" + case TokenTypeExamplesLine: + return "ExamplesLine" + case TokenTypeStepLine: + return "StepLine" + case TokenTypeDocStringSeparator: + return "DocStringSeparator" + case TokenTypeTableRow: + return "TableRow" + case TokenTypeLanguage: + return "Language" + case TokenTypeOther: + return "Other" + } + return "" +} + +func (t TokenType) RuleType() RuleType { + switch t { + case TokenTypeEOF: + return RuleTypeEOF + case TokenTypeEmpty: + return RuleTypeEmpty + case TokenTypeComment: + return RuleTypeComment + case TokenTypeTagLine: + return RuleTypeTagLine + case TokenTypeFeatureLine: + return RuleTypeFeatureLine + case TokenTypeRuleLine: + return RuleTypeRuleLine + case TokenTypeBackgroundLine: + return RuleTypeBackgroundLine + case TokenTypeScenarioLine: + return RuleTypeScenarioLine + case TokenTypeExamplesLine: + return RuleTypeExamplesLine + case TokenTypeStepLine: + return RuleTypeStepLine + case TokenTypeDocStringSeparator: + return RuleTypeDocStringSeparator + case TokenTypeTableRow: + return RuleTypeTableRow + case TokenTypeLanguage: + return RuleTypeLanguage + case TokenTypeOther: + return RuleTypeOther + } + return RuleTypeNone +} + +type RuleType int + +const ( + RuleTypeNone RuleType = iota + RuleTypeEOF + RuleTypeEmpty + RuleTypeComment + RuleTypeTagLine + RuleTypeFeatureLine + RuleTypeRuleLine + RuleTypeBackgroundLine + RuleTypeScenarioLine + RuleTypeExamplesLine + RuleTypeStepLine + RuleTypeDocStringSeparator + RuleTypeTableRow + RuleTypeLanguage + RuleTypeOther + RuleTypeGherkinDocument + RuleTypeFeature + RuleTypeFeatureHeader + RuleTypeRule + RuleTypeRuleHeader + RuleTypeBackground + RuleTypeScenarioDefinition + RuleTypeScenario + RuleTypeExamplesDefinition + RuleTypeExamples + RuleTypeExamplesTable + RuleTypeStep + RuleTypeStepArg + RuleTypeDataTableAndMaybeDocString + RuleTypeDocStringAndMaybeDataTable + RuleTypeDataTable + RuleTypeDocString + RuleTypeTags + RuleTypeDescriptionHelper + RuleTypeDescription +) + +func (t RuleType) IsEOF() bool { + return t == RuleTypeEOF +} +func (t RuleType) Name() string { + switch t { + case RuleTypeEOF: + return "#EOF" + case RuleTypeEmpty: + return "#Empty" + case RuleTypeComment: + return "#Comment" + case RuleTypeTagLine: + return "#TagLine" + case RuleTypeFeatureLine: + return "#FeatureLine" + case RuleTypeRuleLine: + return "#RuleLine" + case RuleTypeBackgroundLine: + return "#BackgroundLine" + case RuleTypeScenarioLine: + return "#ScenarioLine" + case RuleTypeExamplesLine: + return "#ExamplesLine" + case RuleTypeStepLine: + return "#StepLine" + case RuleTypeDocStringSeparator: + return "#DocStringSeparator" + case RuleTypeTableRow: + return "#TableRow" + case RuleTypeLanguage: + return "#Language" + case RuleTypeOther: + return "#Other" + case RuleTypeGherkinDocument: + return "GherkinDocument" + case RuleTypeFeature: + return "Feature" + case RuleTypeFeatureHeader: + return "FeatureHeader" + case RuleTypeRule: + return "Rule" + case RuleTypeRuleHeader: + return "RuleHeader" + case RuleTypeBackground: + return "Background" + case RuleTypeScenarioDefinition: + return "ScenarioDefinition" + case RuleTypeScenario: + return "Scenario" + case RuleTypeExamplesDefinition: + return "ExamplesDefinition" + case RuleTypeExamples: + return "Examples" + case RuleTypeExamplesTable: + return "ExamplesTable" + case RuleTypeStep: + return "Step" + case RuleTypeStepArg: + return "StepArg" + case RuleTypeDataTableAndMaybeDocString: + return "DataTableAndMaybeDocString" + case RuleTypeDocStringAndMaybeDataTable: + return "DocStringAndMaybeDataTable" + case RuleTypeDataTable: + return "DataTable" + case RuleTypeDocString: + return "DocString" + case RuleTypeTags: + return "Tags" + case RuleTypeDescriptionHelper: + return "DescriptionHelper" + case RuleTypeDescription: + return "Description" + } + return "" +} + +type Location struct { + Line int + Column int +} + +type parseError struct { + msg string + loc *Location +} + +func (a *parseError) Error() string { + return fmt.Sprintf("(%d:%d): %s", a.loc.Line, a.loc.Column, a.msg) +} + +type parseErrors []error + +func (pe parseErrors) Error() string { + var ret = []string{"Parser errors:"} + for i := range pe { + ret = append(ret, pe[i].Error()) + } + return strings.Join(ret, "\n") +} + +func (p *parser) Parse(s Scanner, m Matcher) (err error) { + p.builder.Reset() + m.Reset() + ctxt := &parseContext{p, s, p.builder, m, nil, nil} + var state int + ctxt.startRule(RuleTypeGherkinDocument) + for { + gl, eof, err := ctxt.scan() + if err != nil { + ctxt.addError(err) + if p.stopAtFirstError { + break + } + } + state, err = ctxt.match(state, gl) + if err != nil { + ctxt.addError(err) + if p.stopAtFirstError { + break + } + } + if eof { + // done! \o/ + break + } + } + ctxt.endRule(RuleTypeGherkinDocument) + if len(ctxt.errors) > 0 { + return ctxt.errors + } + return +} + +type parseContext struct { + p *parser + s Scanner + b Builder + m Matcher + queue []*scanResult + errors parseErrors +} + +func (ctxt *parseContext) addError(e error) { + ctxt.errors = append(ctxt.errors, e) + // if (p.errors.length > 10) + // throw Errors.CompositeParserException.create(p.errors); +} + +type scanResult struct { + line *Line + atEof bool + err error +} + +func (ctxt *parseContext) scan() (*Line, bool, error) { + l := len(ctxt.queue) + if l > 0 { + x := ctxt.queue[0] + ctxt.queue = ctxt.queue[1:] + return x.line, x.atEof, x.err + } + return ctxt.s.Scan() +} + +func (ctxt *parseContext) startRule(r RuleType) (bool, error) { + ok, err := ctxt.b.StartRule(r) + if err != nil { + ctxt.addError(err) + } + return ok, err +} + +func (ctxt *parseContext) endRule(r RuleType) (bool, error) { + ok, err := ctxt.b.EndRule(r) + if err != nil { + ctxt.addError(err) + } + return ok, err +} + +func (ctxt *parseContext) build(t *Token) (bool, error) { + ok, err := ctxt.b.Build(t) + if err != nil { + ctxt.addError(err) + } + return ok, err +} + +func (ctxt *parseContext) match(state int, line *Line) (newState int, err error) { + switch state { + case 0: + return ctxt.matchAt0(line) + case 1: + return ctxt.matchAt1(line) + case 2: + return ctxt.matchAt2(line) + case 3: + return ctxt.matchAt3(line) + case 4: + return ctxt.matchAt4(line) + case 5: + return ctxt.matchAt5(line) + case 6: + return ctxt.matchAt6(line) + case 7: + return ctxt.matchAt7(line) + case 8: + return ctxt.matchAt8(line) + case 9: + return ctxt.matchAt9(line) + case 10: + return ctxt.matchAt10(line) + case 11: + return ctxt.matchAt11(line) + case 12: + return ctxt.matchAt12(line) + case 13: + return ctxt.matchAt13(line) + case 14: + return ctxt.matchAt14(line) + case 15: + return ctxt.matchAt15(line) + case 16: + return ctxt.matchAt16(line) + case 17: + return ctxt.matchAt17(line) + case 18: + return ctxt.matchAt18(line) + case 19: + return ctxt.matchAt19(line) + case 20: + return ctxt.matchAt20(line) + case 21: + return ctxt.matchAt21(line) + case 22: + return ctxt.matchAt22(line) + case 23: + return ctxt.matchAt23(line) + case 24: + return ctxt.matchAt24(line) + case 25: + return ctxt.matchAt25(line) + case 26: + return ctxt.matchAt26(line) + case 27: + return ctxt.matchAt27(line) + case 28: + return ctxt.matchAt28(line) + case 29: + return ctxt.matchAt29(line) + case 30: + return ctxt.matchAt30(line) + case 31: + return ctxt.matchAt31(line) + case 32: + return ctxt.matchAt32(line) + case 33: + return ctxt.matchAt33(line) + case 34: + return ctxt.matchAt34(line) + case 35: + return ctxt.matchAt35(line) + case 36: + return ctxt.matchAt36(line) + case 37: + return ctxt.matchAt37(line) + case 38: + return ctxt.matchAt38(line) + case 39: + return ctxt.matchAt39(line) + case 40: + return ctxt.matchAt40(line) + case 41: + return ctxt.matchAt41(line) + case 43: + return ctxt.matchAt43(line) + case 44: + return ctxt.matchAt44(line) + case 45: + return ctxt.matchAt45(line) + case 46: + return ctxt.matchAt46(line) + case 47: + return ctxt.matchAt47(line) + case 48: + return ctxt.matchAt48(line) + case 49: + return ctxt.matchAt49(line) + case 50: + return ctxt.matchAt50(line) + case 51: + return ctxt.matchAt51(line) + case 52: + return ctxt.matchAt52(line) + case 53: + return ctxt.matchAt53(line) + case 54: + return ctxt.matchAt54(line) + default: + return state, fmt.Errorf("Unknown state: %+v", state) + } +} + +// Start +func (ctxt *parseContext) matchAt0(line *Line) (newState int, err error) { + if ok, token, err := ctxt.matchEOF(line); ok { + ctxt.build(token) + return 42, err + } + if ok, token, err := ctxt.matchLanguage(line); ok { + ctxt.startRule(RuleTypeFeature) + ctxt.startRule(RuleTypeFeatureHeader) + ctxt.build(token) + return 1, err + } + if ok, token, err := ctxt.matchTagLine(line); ok { + ctxt.startRule(RuleTypeFeature) + ctxt.startRule(RuleTypeFeatureHeader) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 2, err + } + if ok, token, err := ctxt.matchFeatureLine(line); ok { + ctxt.startRule(RuleTypeFeature) + ctxt.startRule(RuleTypeFeatureHeader) + ctxt.build(token) + return 3, err + } + if ok, token, err := ctxt.matchComment(line); ok { + ctxt.build(token) + return 0, err + } + if ok, token, err := ctxt.matchEmpty(line); ok { + ctxt.build(token) + return 0, err + } + + // var stateComment = "State: 0 - Start" + var expectedTokens = []string{"#EOF", "#Language", "#TagLine", "#FeatureLine", "#Comment", "#Empty"} + if line.IsEof() { + err = &parseError{ + msg: fmt.Sprintf("unexpected end of file, expected: %s", strings.Join(expectedTokens, ", ")), + loc: &Location{Line: line.LineNumber, Column: 0}, + } + } else { + err = &parseError{ + msg: fmt.Sprintf("expected: %s, got '%s'", strings.Join(expectedTokens, ", "), line.LineText), + loc: &Location{Line: line.LineNumber, Column: line.Indent() + 1}, + } + } + // if (ctxt.p.stopAtFirstError) throw error; + //ctxt.addError(err) + return 0, err +} + +// GherkinDocument:0>Feature:0>FeatureHeader:0>#Language:0 +func (ctxt *parseContext) matchAt1(line *Line) (newState int, err error) { + if ok, token, err := ctxt.matchTagLine(line); ok { + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 2, err + } + if ok, token, err := ctxt.matchFeatureLine(line); ok { + ctxt.build(token) + return 3, err + } + if ok, token, err := ctxt.matchComment(line); ok { + ctxt.build(token) + return 1, err + } + if ok, token, err := ctxt.matchEmpty(line); ok { + ctxt.build(token) + return 1, err + } + + // var stateComment = "State: 1 - GherkinDocument:0>Feature:0>FeatureHeader:0>#Language:0" + var expectedTokens = []string{"#TagLine", "#FeatureLine", "#Comment", "#Empty"} + if line.IsEof() { + err = &parseError{ + msg: fmt.Sprintf("unexpected end of file, expected: %s", strings.Join(expectedTokens, ", ")), + loc: &Location{Line: line.LineNumber, Column: 0}, + } + } else { + err = &parseError{ + msg: fmt.Sprintf("expected: %s, got '%s'", strings.Join(expectedTokens, ", "), line.LineText), + loc: &Location{Line: line.LineNumber, Column: line.Indent() + 1}, + } + } + // if (ctxt.p.stopAtFirstError) throw error; + //ctxt.addError(err) + return 1, err +} + +// GherkinDocument:0>Feature:0>FeatureHeader:1>Tags:0>#TagLine:0 +func (ctxt *parseContext) matchAt2(line *Line) (newState int, err error) { + if ok, token, err := ctxt.matchTagLine(line); ok { + ctxt.build(token) + return 2, err + } + if ok, token, err := ctxt.matchFeatureLine(line); ok { + ctxt.endRule(RuleTypeTags) + ctxt.build(token) + return 3, err + } + if ok, token, err := ctxt.matchComment(line); ok { + ctxt.build(token) + return 2, err + } + if ok, token, err := ctxt.matchEmpty(line); ok { + ctxt.build(token) + return 2, err + } + + // var stateComment = "State: 2 - GherkinDocument:0>Feature:0>FeatureHeader:1>Tags:0>#TagLine:0" + var expectedTokens = []string{"#TagLine", "#FeatureLine", "#Comment", "#Empty"} + if line.IsEof() { + err = &parseError{ + msg: fmt.Sprintf("unexpected end of file, expected: %s", strings.Join(expectedTokens, ", ")), + loc: &Location{Line: line.LineNumber, Column: 0}, + } + } else { + err = &parseError{ + msg: fmt.Sprintf("expected: %s, got '%s'", strings.Join(expectedTokens, ", "), line.LineText), + loc: &Location{Line: line.LineNumber, Column: line.Indent() + 1}, + } + } + // if (ctxt.p.stopAtFirstError) throw error; + //ctxt.addError(err) + return 2, err +} + +// GherkinDocument:0>Feature:0>FeatureHeader:2>#FeatureLine:0 +func (ctxt *parseContext) matchAt3(line *Line) (newState int, err error) { + if ok, token, err := ctxt.matchEOF(line); ok { + ctxt.endRule(RuleTypeFeatureHeader) + ctxt.endRule(RuleTypeFeature) + ctxt.build(token) + return 42, err + } + if ok, token, err := ctxt.matchEmpty(line); ok { + ctxt.build(token) + return 3, err + } + if ok, token, err := ctxt.matchComment(line); ok { + ctxt.startRule(RuleTypeDescription) + ctxt.build(token) + return 4, err + } + if ok, token, err := ctxt.matchBackgroundLine(line); ok { + ctxt.endRule(RuleTypeFeatureHeader) + ctxt.startRule(RuleTypeBackground) + ctxt.build(token) + return 5, err + } + if ok, token, err := ctxt.matchTagLine(line); ok { + if ctxt.lookahead0(line) { + ctxt.endRule(RuleTypeFeatureHeader) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 11, err + } + } + if ok, token, err := ctxt.matchTagLine(line); ok { + ctxt.endRule(RuleTypeFeatureHeader) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 22, err + } + if ok, token, err := ctxt.matchScenarioLine(line); ok { + ctxt.endRule(RuleTypeFeatureHeader) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenario) + ctxt.build(token) + return 12, err + } + if ok, token, err := ctxt.matchRuleLine(line); ok { + ctxt.endRule(RuleTypeFeatureHeader) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.build(token) + return 23, err + } + if ok, token, err := ctxt.matchOther(line); ok { + ctxt.startRule(RuleTypeDescription) + ctxt.build(token) + return 4, err + } + + // var stateComment = "State: 3 - GherkinDocument:0>Feature:0>FeatureHeader:2>#FeatureLine:0" + var expectedTokens = []string{"#EOF", "#Empty", "#Comment", "#BackgroundLine", "#TagLine", "#ScenarioLine", "#RuleLine", "#Other"} + if line.IsEof() { + err = &parseError{ + msg: fmt.Sprintf("unexpected end of file, expected: %s", strings.Join(expectedTokens, ", ")), + loc: &Location{Line: line.LineNumber, Column: 0}, + } + } else { + err = &parseError{ + msg: fmt.Sprintf("expected: %s, got '%s'", strings.Join(expectedTokens, ", "), line.LineText), + loc: &Location{Line: line.LineNumber, Column: line.Indent() + 1}, + } + } + // if (ctxt.p.stopAtFirstError) throw error; + //ctxt.addError(err) + return 3, err +} + +// GherkinDocument:0>Feature:0>FeatureHeader:3>DescriptionHelper:1>Description:0>__alt1:0>#Other:0 +func (ctxt *parseContext) matchAt4(line *Line) (newState int, err error) { + if ok, token, err := ctxt.matchEOF(line); ok { + ctxt.endRule(RuleTypeDescription) + ctxt.endRule(RuleTypeFeatureHeader) + ctxt.endRule(RuleTypeFeature) + ctxt.build(token) + return 42, err + } + if ok, token, err := ctxt.matchComment(line); ok { + ctxt.build(token) + return 4, err + } + if ok, token, err := ctxt.matchBackgroundLine(line); ok { + ctxt.endRule(RuleTypeDescription) + ctxt.endRule(RuleTypeFeatureHeader) + ctxt.startRule(RuleTypeBackground) + ctxt.build(token) + return 5, err + } + if ok, token, err := ctxt.matchTagLine(line); ok { + if ctxt.lookahead0(line) { + ctxt.endRule(RuleTypeDescription) + ctxt.endRule(RuleTypeFeatureHeader) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 11, err + } + } + if ok, token, err := ctxt.matchTagLine(line); ok { + ctxt.endRule(RuleTypeDescription) + ctxt.endRule(RuleTypeFeatureHeader) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 22, err + } + if ok, token, err := ctxt.matchScenarioLine(line); ok { + ctxt.endRule(RuleTypeDescription) + ctxt.endRule(RuleTypeFeatureHeader) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenario) + ctxt.build(token) + return 12, err + } + if ok, token, err := ctxt.matchRuleLine(line); ok { + ctxt.endRule(RuleTypeDescription) + ctxt.endRule(RuleTypeFeatureHeader) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.build(token) + return 23, err + } + if ok, token, err := ctxt.matchOther(line); ok { + ctxt.build(token) + return 4, err + } + + // var stateComment = "State: 4 - GherkinDocument:0>Feature:0>FeatureHeader:3>DescriptionHelper:1>Description:0>__alt1:0>#Other:0" + var expectedTokens = []string{"#EOF", "#Comment", "#BackgroundLine", "#TagLine", "#ScenarioLine", "#RuleLine", "#Other"} + if line.IsEof() { + err = &parseError{ + msg: fmt.Sprintf("unexpected end of file, expected: %s", strings.Join(expectedTokens, ", ")), + loc: &Location{Line: line.LineNumber, Column: 0}, + } + } else { + err = &parseError{ + msg: fmt.Sprintf("expected: %s, got '%s'", strings.Join(expectedTokens, ", "), line.LineText), + loc: &Location{Line: line.LineNumber, Column: line.Indent() + 1}, + } + } + // if (ctxt.p.stopAtFirstError) throw error; + //ctxt.addError(err) + return 4, err +} + +// GherkinDocument:0>Feature:1>Background:0>#BackgroundLine:0 +func (ctxt *parseContext) matchAt5(line *Line) (newState int, err error) { + if ok, token, err := ctxt.matchEOF(line); ok { + ctxt.endRule(RuleTypeBackground) + ctxt.endRule(RuleTypeFeature) + ctxt.build(token) + return 42, err + } + if ok, token, err := ctxt.matchEmpty(line); ok { + ctxt.build(token) + return 5, err + } + if ok, token, err := ctxt.matchComment(line); ok { + ctxt.startRule(RuleTypeDescription) + ctxt.build(token) + return 6, err + } + if ok, token, err := ctxt.matchStepLine(line); ok { + ctxt.startRule(RuleTypeStep) + ctxt.build(token) + return 7, err + } + if ok, token, err := ctxt.matchTagLine(line); ok { + if ctxt.lookahead0(line) { + ctxt.endRule(RuleTypeBackground) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 11, err + } + } + if ok, token, err := ctxt.matchTagLine(line); ok { + ctxt.endRule(RuleTypeBackground) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 22, err + } + if ok, token, err := ctxt.matchScenarioLine(line); ok { + ctxt.endRule(RuleTypeBackground) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenario) + ctxt.build(token) + return 12, err + } + if ok, token, err := ctxt.matchRuleLine(line); ok { + ctxt.endRule(RuleTypeBackground) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.build(token) + return 23, err + } + if ok, token, err := ctxt.matchOther(line); ok { + ctxt.startRule(RuleTypeDescription) + ctxt.build(token) + return 6, err + } + + // var stateComment = "State: 5 - GherkinDocument:0>Feature:1>Background:0>#BackgroundLine:0" + var expectedTokens = []string{"#EOF", "#Empty", "#Comment", "#StepLine", "#TagLine", "#ScenarioLine", "#RuleLine", "#Other"} + if line.IsEof() { + err = &parseError{ + msg: fmt.Sprintf("unexpected end of file, expected: %s", strings.Join(expectedTokens, ", ")), + loc: &Location{Line: line.LineNumber, Column: 0}, + } + } else { + err = &parseError{ + msg: fmt.Sprintf("expected: %s, got '%s'", strings.Join(expectedTokens, ", "), line.LineText), + loc: &Location{Line: line.LineNumber, Column: line.Indent() + 1}, + } + } + // if (ctxt.p.stopAtFirstError) throw error; + //ctxt.addError(err) + return 5, err +} + +// GherkinDocument:0>Feature:1>Background:1>DescriptionHelper:1>Description:0>__alt1:0>#Other:0 +func (ctxt *parseContext) matchAt6(line *Line) (newState int, err error) { + if ok, token, err := ctxt.matchEOF(line); ok { + ctxt.endRule(RuleTypeDescription) + ctxt.endRule(RuleTypeBackground) + ctxt.endRule(RuleTypeFeature) + ctxt.build(token) + return 42, err + } + if ok, token, err := ctxt.matchComment(line); ok { + ctxt.build(token) + return 6, err + } + if ok, token, err := ctxt.matchStepLine(line); ok { + ctxt.endRule(RuleTypeDescription) + ctxt.startRule(RuleTypeStep) + ctxt.build(token) + return 7, err + } + if ok, token, err := ctxt.matchTagLine(line); ok { + if ctxt.lookahead0(line) { + ctxt.endRule(RuleTypeDescription) + ctxt.endRule(RuleTypeBackground) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 11, err + } + } + if ok, token, err := ctxt.matchTagLine(line); ok { + ctxt.endRule(RuleTypeDescription) + ctxt.endRule(RuleTypeBackground) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 22, err + } + if ok, token, err := ctxt.matchScenarioLine(line); ok { + ctxt.endRule(RuleTypeDescription) + ctxt.endRule(RuleTypeBackground) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenario) + ctxt.build(token) + return 12, err + } + if ok, token, err := ctxt.matchRuleLine(line); ok { + ctxt.endRule(RuleTypeDescription) + ctxt.endRule(RuleTypeBackground) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.build(token) + return 23, err + } + if ok, token, err := ctxt.matchOther(line); ok { + ctxt.build(token) + return 6, err + } + + // var stateComment = "State: 6 - GherkinDocument:0>Feature:1>Background:1>DescriptionHelper:1>Description:0>__alt1:0>#Other:0" + var expectedTokens = []string{"#EOF", "#Comment", "#StepLine", "#TagLine", "#ScenarioLine", "#RuleLine", "#Other"} + if line.IsEof() { + err = &parseError{ + msg: fmt.Sprintf("unexpected end of file, expected: %s", strings.Join(expectedTokens, ", ")), + loc: &Location{Line: line.LineNumber, Column: 0}, + } + } else { + err = &parseError{ + msg: fmt.Sprintf("expected: %s, got '%s'", strings.Join(expectedTokens, ", "), line.LineText), + loc: &Location{Line: line.LineNumber, Column: line.Indent() + 1}, + } + } + // if (ctxt.p.stopAtFirstError) throw error; + //ctxt.addError(err) + return 6, err +} + +// GherkinDocument:0>Feature:1>Background:2>Step:0>#StepLine:0 +func (ctxt *parseContext) matchAt7(line *Line) (newState int, err error) { + if ok, token, err := ctxt.matchEOF(line); ok { + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeBackground) + ctxt.endRule(RuleTypeFeature) + ctxt.build(token) + return 42, err + } + if ok, token, err := ctxt.matchTableRow(line); ok { + ctxt.startRule(RuleTypeDataTable) + ctxt.build(token) + return 8, err + } + if ok, token, err := ctxt.matchDocStringSeparator(line); ok { + ctxt.startRule(RuleTypeDocString) + ctxt.build(token) + return 52, err + } + if ok, token, err := ctxt.matchStepLine(line); ok { + ctxt.endRule(RuleTypeStep) + ctxt.startRule(RuleTypeStep) + ctxt.build(token) + return 7, err + } + if ok, token, err := ctxt.matchTagLine(line); ok { + if ctxt.lookahead0(line) { + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeBackground) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 11, err + } + } + if ok, token, err := ctxt.matchTagLine(line); ok { + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeBackground) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 22, err + } + if ok, token, err := ctxt.matchScenarioLine(line); ok { + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeBackground) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenario) + ctxt.build(token) + return 12, err + } + if ok, token, err := ctxt.matchRuleLine(line); ok { + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeBackground) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.build(token) + return 23, err + } + if ok, token, err := ctxt.matchComment(line); ok { + ctxt.build(token) + return 7, err + } + if ok, token, err := ctxt.matchEmpty(line); ok { + ctxt.build(token) + return 7, err + } + + // var stateComment = "State: 7 - GherkinDocument:0>Feature:1>Background:2>Step:0>#StepLine:0" + var expectedTokens = []string{"#EOF", "#TableRow", "#DocStringSeparator", "#StepLine", "#TagLine", "#ScenarioLine", "#RuleLine", "#Comment", "#Empty"} + if line.IsEof() { + err = &parseError{ + msg: fmt.Sprintf("unexpected end of file, expected: %s", strings.Join(expectedTokens, ", ")), + loc: &Location{Line: line.LineNumber, Column: 0}, + } + } else { + err = &parseError{ + msg: fmt.Sprintf("expected: %s, got '%s'", strings.Join(expectedTokens, ", "), line.LineText), + loc: &Location{Line: line.LineNumber, Column: line.Indent() + 1}, + } + } + // if (ctxt.p.stopAtFirstError) throw error; + //ctxt.addError(err) + return 7, err +} + +// GherkinDocument:0>Feature:1>Background:2>Step:1>StepArg:0>__alt0:0>DataTableAndMaybeDocString:0>DataTable:0>#TableRow:0 +func (ctxt *parseContext) matchAt8(line *Line) (newState int, err error) { + if ok, token, err := ctxt.matchEOF(line); ok { + ctxt.endRule(RuleTypeDataTable) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeBackground) + ctxt.endRule(RuleTypeFeature) + ctxt.build(token) + return 42, err + } + if ok, token, err := ctxt.matchTableRow(line); ok { + ctxt.build(token) + return 8, err + } + if ok, token, err := ctxt.matchDocStringSeparator(line); ok { + ctxt.endRule(RuleTypeDataTable) + ctxt.startRule(RuleTypeDocString) + ctxt.build(token) + return 9, err + } + if ok, token, err := ctxt.matchStepLine(line); ok { + ctxt.endRule(RuleTypeDataTable) + ctxt.endRule(RuleTypeStep) + ctxt.startRule(RuleTypeStep) + ctxt.build(token) + return 7, err + } + if ok, token, err := ctxt.matchTagLine(line); ok { + if ctxt.lookahead0(line) { + ctxt.endRule(RuleTypeDataTable) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeBackground) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 11, err + } + } + if ok, token, err := ctxt.matchTagLine(line); ok { + ctxt.endRule(RuleTypeDataTable) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeBackground) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 22, err + } + if ok, token, err := ctxt.matchScenarioLine(line); ok { + ctxt.endRule(RuleTypeDataTable) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeBackground) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenario) + ctxt.build(token) + return 12, err + } + if ok, token, err := ctxt.matchRuleLine(line); ok { + ctxt.endRule(RuleTypeDataTable) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeBackground) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.build(token) + return 23, err + } + if ok, token, err := ctxt.matchComment(line); ok { + ctxt.build(token) + return 8, err + } + if ok, token, err := ctxt.matchEmpty(line); ok { + ctxt.build(token) + return 8, err + } + + // var stateComment = "State: 8 - GherkinDocument:0>Feature:1>Background:2>Step:1>StepArg:0>__alt0:0>DataTableAndMaybeDocString:0>DataTable:0>#TableRow:0" + var expectedTokens = []string{"#EOF", "#TableRow", "#DocStringSeparator", "#StepLine", "#TagLine", "#ScenarioLine", "#RuleLine", "#Comment", "#Empty"} + if line.IsEof() { + err = &parseError{ + msg: fmt.Sprintf("unexpected end of file, expected: %s", strings.Join(expectedTokens, ", ")), + loc: &Location{Line: line.LineNumber, Column: 0}, + } + } else { + err = &parseError{ + msg: fmt.Sprintf("expected: %s, got '%s'", strings.Join(expectedTokens, ", "), line.LineText), + loc: &Location{Line: line.LineNumber, Column: line.Indent() + 1}, + } + } + // if (ctxt.p.stopAtFirstError) throw error; + //ctxt.addError(err) + return 8, err +} + +// GherkinDocument:0>Feature:1>Background:2>Step:1>StepArg:0>__alt0:0>DataTableAndMaybeDocString:1>DocString:0>#DocStringSeparator:0 +func (ctxt *parseContext) matchAt9(line *Line) (newState int, err error) { + if ok, token, err := ctxt.matchDocStringSeparator(line); ok { + ctxt.build(token) + return 10, err + } + if ok, token, err := ctxt.matchOther(line); ok { + ctxt.build(token) + return 9, err + } + + // var stateComment = "State: 9 - GherkinDocument:0>Feature:1>Background:2>Step:1>StepArg:0>__alt0:0>DataTableAndMaybeDocString:1>DocString:0>#DocStringSeparator:0" + var expectedTokens = []string{"#DocStringSeparator", "#Other"} + if line.IsEof() { + err = &parseError{ + msg: fmt.Sprintf("unexpected end of file, expected: %s", strings.Join(expectedTokens, ", ")), + loc: &Location{Line: line.LineNumber, Column: 0}, + } + } else { + err = &parseError{ + msg: fmt.Sprintf("expected: %s, got '%s'", strings.Join(expectedTokens, ", "), line.LineText), + loc: &Location{Line: line.LineNumber, Column: line.Indent() + 1}, + } + } + // if (ctxt.p.stopAtFirstError) throw error; + //ctxt.addError(err) + return 9, err +} + +// GherkinDocument:0>Feature:1>Background:2>Step:1>StepArg:0>__alt0:0>DataTableAndMaybeDocString:1>DocString:2>#DocStringSeparator:0 +func (ctxt *parseContext) matchAt10(line *Line) (newState int, err error) { + if ok, token, err := ctxt.matchEOF(line); ok { + ctxt.endRule(RuleTypeDocString) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeBackground) + ctxt.endRule(RuleTypeFeature) + ctxt.build(token) + return 42, err + } + if ok, token, err := ctxt.matchStepLine(line); ok { + ctxt.endRule(RuleTypeDocString) + ctxt.endRule(RuleTypeStep) + ctxt.startRule(RuleTypeStep) + ctxt.build(token) + return 7, err + } + if ok, token, err := ctxt.matchTagLine(line); ok { + if ctxt.lookahead0(line) { + ctxt.endRule(RuleTypeDocString) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeBackground) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 11, err + } + } + if ok, token, err := ctxt.matchTagLine(line); ok { + ctxt.endRule(RuleTypeDocString) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeBackground) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 22, err + } + if ok, token, err := ctxt.matchScenarioLine(line); ok { + ctxt.endRule(RuleTypeDocString) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeBackground) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenario) + ctxt.build(token) + return 12, err + } + if ok, token, err := ctxt.matchRuleLine(line); ok { + ctxt.endRule(RuleTypeDocString) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeBackground) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.build(token) + return 23, err + } + if ok, token, err := ctxt.matchComment(line); ok { + ctxt.build(token) + return 10, err + } + if ok, token, err := ctxt.matchEmpty(line); ok { + ctxt.build(token) + return 10, err + } + + // var stateComment = "State: 10 - GherkinDocument:0>Feature:1>Background:2>Step:1>StepArg:0>__alt0:0>DataTableAndMaybeDocString:1>DocString:2>#DocStringSeparator:0" + var expectedTokens = []string{"#EOF", "#StepLine", "#TagLine", "#ScenarioLine", "#RuleLine", "#Comment", "#Empty"} + if line.IsEof() { + err = &parseError{ + msg: fmt.Sprintf("unexpected end of file, expected: %s", strings.Join(expectedTokens, ", ")), + loc: &Location{Line: line.LineNumber, Column: 0}, + } + } else { + err = &parseError{ + msg: fmt.Sprintf("expected: %s, got '%s'", strings.Join(expectedTokens, ", "), line.LineText), + loc: &Location{Line: line.LineNumber, Column: line.Indent() + 1}, + } + } + // if (ctxt.p.stopAtFirstError) throw error; + //ctxt.addError(err) + return 10, err +} + +// GherkinDocument:0>Feature:2>ScenarioDefinition:0>Tags:0>#TagLine:0 +func (ctxt *parseContext) matchAt11(line *Line) (newState int, err error) { + if ok, token, err := ctxt.matchTagLine(line); ok { + ctxt.build(token) + return 11, err + } + if ok, token, err := ctxt.matchScenarioLine(line); ok { + ctxt.endRule(RuleTypeTags) + ctxt.startRule(RuleTypeScenario) + ctxt.build(token) + return 12, err + } + if ok, token, err := ctxt.matchComment(line); ok { + ctxt.build(token) + return 11, err + } + if ok, token, err := ctxt.matchEmpty(line); ok { + ctxt.build(token) + return 11, err + } + + // var stateComment = "State: 11 - GherkinDocument:0>Feature:2>ScenarioDefinition:0>Tags:0>#TagLine:0" + var expectedTokens = []string{"#TagLine", "#ScenarioLine", "#Comment", "#Empty"} + if line.IsEof() { + err = &parseError{ + msg: fmt.Sprintf("unexpected end of file, expected: %s", strings.Join(expectedTokens, ", ")), + loc: &Location{Line: line.LineNumber, Column: 0}, + } + } else { + err = &parseError{ + msg: fmt.Sprintf("expected: %s, got '%s'", strings.Join(expectedTokens, ", "), line.LineText), + loc: &Location{Line: line.LineNumber, Column: line.Indent() + 1}, + } + } + // if (ctxt.p.stopAtFirstError) throw error; + //ctxt.addError(err) + return 11, err +} + +// GherkinDocument:0>Feature:2>ScenarioDefinition:1>Scenario:0>#ScenarioLine:0 +func (ctxt *parseContext) matchAt12(line *Line) (newState int, err error) { + if ok, token, err := ctxt.matchEOF(line); ok { + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.endRule(RuleTypeFeature) + ctxt.build(token) + return 42, err + } + if ok, token, err := ctxt.matchEmpty(line); ok { + ctxt.build(token) + return 12, err + } + if ok, token, err := ctxt.matchComment(line); ok { + ctxt.startRule(RuleTypeDescription) + ctxt.build(token) + return 13, err + } + if ok, token, err := ctxt.matchStepLine(line); ok { + ctxt.startRule(RuleTypeStep) + ctxt.build(token) + return 14, err + } + if ok, token, err := ctxt.matchTagLine(line); ok { + if ctxt.lookahead1(line) { + ctxt.startRule(RuleTypeExamplesDefinition) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 18, err + } + } + if ok, token, err := ctxt.matchTagLine(line); ok { + if ctxt.lookahead0(line) { + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 11, err + } + } + if ok, token, err := ctxt.matchTagLine(line); ok { + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 22, err + } + if ok, token, err := ctxt.matchExamplesLine(line); ok { + ctxt.startRule(RuleTypeExamplesDefinition) + ctxt.startRule(RuleTypeExamples) + ctxt.build(token) + return 19, err + } + if ok, token, err := ctxt.matchScenarioLine(line); ok { + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenario) + ctxt.build(token) + return 12, err + } + if ok, token, err := ctxt.matchRuleLine(line); ok { + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.build(token) + return 23, err + } + if ok, token, err := ctxt.matchOther(line); ok { + ctxt.startRule(RuleTypeDescription) + ctxt.build(token) + return 13, err + } + + // var stateComment = "State: 12 - GherkinDocument:0>Feature:2>ScenarioDefinition:1>Scenario:0>#ScenarioLine:0" + var expectedTokens = []string{"#EOF", "#Empty", "#Comment", "#StepLine", "#TagLine", "#ExamplesLine", "#ScenarioLine", "#RuleLine", "#Other"} + if line.IsEof() { + err = &parseError{ + msg: fmt.Sprintf("unexpected end of file, expected: %s", strings.Join(expectedTokens, ", ")), + loc: &Location{Line: line.LineNumber, Column: 0}, + } + } else { + err = &parseError{ + msg: fmt.Sprintf("expected: %s, got '%s'", strings.Join(expectedTokens, ", "), line.LineText), + loc: &Location{Line: line.LineNumber, Column: line.Indent() + 1}, + } + } + // if (ctxt.p.stopAtFirstError) throw error; + //ctxt.addError(err) + return 12, err +} + +// GherkinDocument:0>Feature:2>ScenarioDefinition:1>Scenario:1>DescriptionHelper:1>Description:0>__alt1:0>#Other:0 +func (ctxt *parseContext) matchAt13(line *Line) (newState int, err error) { + if ok, token, err := ctxt.matchEOF(line); ok { + ctxt.endRule(RuleTypeDescription) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.endRule(RuleTypeFeature) + ctxt.build(token) + return 42, err + } + if ok, token, err := ctxt.matchComment(line); ok { + ctxt.build(token) + return 13, err + } + if ok, token, err := ctxt.matchStepLine(line); ok { + ctxt.endRule(RuleTypeDescription) + ctxt.startRule(RuleTypeStep) + ctxt.build(token) + return 14, err + } + if ok, token, err := ctxt.matchTagLine(line); ok { + if ctxt.lookahead1(line) { + ctxt.endRule(RuleTypeDescription) + ctxt.startRule(RuleTypeExamplesDefinition) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 18, err + } + } + if ok, token, err := ctxt.matchTagLine(line); ok { + if ctxt.lookahead0(line) { + ctxt.endRule(RuleTypeDescription) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 11, err + } + } + if ok, token, err := ctxt.matchTagLine(line); ok { + ctxt.endRule(RuleTypeDescription) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 22, err + } + if ok, token, err := ctxt.matchExamplesLine(line); ok { + ctxt.endRule(RuleTypeDescription) + ctxt.startRule(RuleTypeExamplesDefinition) + ctxt.startRule(RuleTypeExamples) + ctxt.build(token) + return 19, err + } + if ok, token, err := ctxt.matchScenarioLine(line); ok { + ctxt.endRule(RuleTypeDescription) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenario) + ctxt.build(token) + return 12, err + } + if ok, token, err := ctxt.matchRuleLine(line); ok { + ctxt.endRule(RuleTypeDescription) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.build(token) + return 23, err + } + if ok, token, err := ctxt.matchOther(line); ok { + ctxt.build(token) + return 13, err + } + + // var stateComment = "State: 13 - GherkinDocument:0>Feature:2>ScenarioDefinition:1>Scenario:1>DescriptionHelper:1>Description:0>__alt1:0>#Other:0" + var expectedTokens = []string{"#EOF", "#Comment", "#StepLine", "#TagLine", "#ExamplesLine", "#ScenarioLine", "#RuleLine", "#Other"} + if line.IsEof() { + err = &parseError{ + msg: fmt.Sprintf("unexpected end of file, expected: %s", strings.Join(expectedTokens, ", ")), + loc: &Location{Line: line.LineNumber, Column: 0}, + } + } else { + err = &parseError{ + msg: fmt.Sprintf("expected: %s, got '%s'", strings.Join(expectedTokens, ", "), line.LineText), + loc: &Location{Line: line.LineNumber, Column: line.Indent() + 1}, + } + } + // if (ctxt.p.stopAtFirstError) throw error; + //ctxt.addError(err) + return 13, err +} + +// GherkinDocument:0>Feature:2>ScenarioDefinition:1>Scenario:2>Step:0>#StepLine:0 +func (ctxt *parseContext) matchAt14(line *Line) (newState int, err error) { + if ok, token, err := ctxt.matchEOF(line); ok { + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.endRule(RuleTypeFeature) + ctxt.build(token) + return 42, err + } + if ok, token, err := ctxt.matchTableRow(line); ok { + ctxt.startRule(RuleTypeDataTable) + ctxt.build(token) + return 15, err + } + if ok, token, err := ctxt.matchDocStringSeparator(line); ok { + ctxt.startRule(RuleTypeDocString) + ctxt.build(token) + return 49, err + } + if ok, token, err := ctxt.matchStepLine(line); ok { + ctxt.endRule(RuleTypeStep) + ctxt.startRule(RuleTypeStep) + ctxt.build(token) + return 14, err + } + if ok, token, err := ctxt.matchTagLine(line); ok { + if ctxt.lookahead1(line) { + ctxt.endRule(RuleTypeStep) + ctxt.startRule(RuleTypeExamplesDefinition) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 18, err + } + } + if ok, token, err := ctxt.matchTagLine(line); ok { + if ctxt.lookahead0(line) { + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 11, err + } + } + if ok, token, err := ctxt.matchTagLine(line); ok { + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 22, err + } + if ok, token, err := ctxt.matchExamplesLine(line); ok { + ctxt.endRule(RuleTypeStep) + ctxt.startRule(RuleTypeExamplesDefinition) + ctxt.startRule(RuleTypeExamples) + ctxt.build(token) + return 19, err + } + if ok, token, err := ctxt.matchScenarioLine(line); ok { + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenario) + ctxt.build(token) + return 12, err + } + if ok, token, err := ctxt.matchRuleLine(line); ok { + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.build(token) + return 23, err + } + if ok, token, err := ctxt.matchComment(line); ok { + ctxt.build(token) + return 14, err + } + if ok, token, err := ctxt.matchEmpty(line); ok { + ctxt.build(token) + return 14, err + } + + // var stateComment = "State: 14 - GherkinDocument:0>Feature:2>ScenarioDefinition:1>Scenario:2>Step:0>#StepLine:0" + var expectedTokens = []string{"#EOF", "#TableRow", "#DocStringSeparator", "#StepLine", "#TagLine", "#ExamplesLine", "#ScenarioLine", "#RuleLine", "#Comment", "#Empty"} + if line.IsEof() { + err = &parseError{ + msg: fmt.Sprintf("unexpected end of file, expected: %s", strings.Join(expectedTokens, ", ")), + loc: &Location{Line: line.LineNumber, Column: 0}, + } + } else { + err = &parseError{ + msg: fmt.Sprintf("expected: %s, got '%s'", strings.Join(expectedTokens, ", "), line.LineText), + loc: &Location{Line: line.LineNumber, Column: line.Indent() + 1}, + } + } + // if (ctxt.p.stopAtFirstError) throw error; + //ctxt.addError(err) + return 14, err +} + +// GherkinDocument:0>Feature:2>ScenarioDefinition:1>Scenario:2>Step:1>StepArg:0>__alt0:0>DataTableAndMaybeDocString:0>DataTable:0>#TableRow:0 +func (ctxt *parseContext) matchAt15(line *Line) (newState int, err error) { + if ok, token, err := ctxt.matchEOF(line); ok { + ctxt.endRule(RuleTypeDataTable) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.endRule(RuleTypeFeature) + ctxt.build(token) + return 42, err + } + if ok, token, err := ctxt.matchTableRow(line); ok { + ctxt.build(token) + return 15, err + } + if ok, token, err := ctxt.matchDocStringSeparator(line); ok { + ctxt.endRule(RuleTypeDataTable) + ctxt.startRule(RuleTypeDocString) + ctxt.build(token) + return 16, err + } + if ok, token, err := ctxt.matchStepLine(line); ok { + ctxt.endRule(RuleTypeDataTable) + ctxt.endRule(RuleTypeStep) + ctxt.startRule(RuleTypeStep) + ctxt.build(token) + return 14, err + } + if ok, token, err := ctxt.matchTagLine(line); ok { + if ctxt.lookahead1(line) { + ctxt.endRule(RuleTypeDataTable) + ctxt.endRule(RuleTypeStep) + ctxt.startRule(RuleTypeExamplesDefinition) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 18, err + } + } + if ok, token, err := ctxt.matchTagLine(line); ok { + if ctxt.lookahead0(line) { + ctxt.endRule(RuleTypeDataTable) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 11, err + } + } + if ok, token, err := ctxt.matchTagLine(line); ok { + ctxt.endRule(RuleTypeDataTable) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 22, err + } + if ok, token, err := ctxt.matchExamplesLine(line); ok { + ctxt.endRule(RuleTypeDataTable) + ctxt.endRule(RuleTypeStep) + ctxt.startRule(RuleTypeExamplesDefinition) + ctxt.startRule(RuleTypeExamples) + ctxt.build(token) + return 19, err + } + if ok, token, err := ctxt.matchScenarioLine(line); ok { + ctxt.endRule(RuleTypeDataTable) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenario) + ctxt.build(token) + return 12, err + } + if ok, token, err := ctxt.matchRuleLine(line); ok { + ctxt.endRule(RuleTypeDataTable) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.build(token) + return 23, err + } + if ok, token, err := ctxt.matchComment(line); ok { + ctxt.build(token) + return 15, err + } + if ok, token, err := ctxt.matchEmpty(line); ok { + ctxt.build(token) + return 15, err + } + + // var stateComment = "State: 15 - GherkinDocument:0>Feature:2>ScenarioDefinition:1>Scenario:2>Step:1>StepArg:0>__alt0:0>DataTableAndMaybeDocString:0>DataTable:0>#TableRow:0" + var expectedTokens = []string{"#EOF", "#TableRow", "#DocStringSeparator", "#StepLine", "#TagLine", "#ExamplesLine", "#ScenarioLine", "#RuleLine", "#Comment", "#Empty"} + if line.IsEof() { + err = &parseError{ + msg: fmt.Sprintf("unexpected end of file, expected: %s", strings.Join(expectedTokens, ", ")), + loc: &Location{Line: line.LineNumber, Column: 0}, + } + } else { + err = &parseError{ + msg: fmt.Sprintf("expected: %s, got '%s'", strings.Join(expectedTokens, ", "), line.LineText), + loc: &Location{Line: line.LineNumber, Column: line.Indent() + 1}, + } + } + // if (ctxt.p.stopAtFirstError) throw error; + //ctxt.addError(err) + return 15, err +} + +// GherkinDocument:0>Feature:2>ScenarioDefinition:1>Scenario:2>Step:1>StepArg:0>__alt0:0>DataTableAndMaybeDocString:1>DocString:0>#DocStringSeparator:0 +func (ctxt *parseContext) matchAt16(line *Line) (newState int, err error) { + if ok, token, err := ctxt.matchDocStringSeparator(line); ok { + ctxt.build(token) + return 17, err + } + if ok, token, err := ctxt.matchOther(line); ok { + ctxt.build(token) + return 16, err + } + + // var stateComment = "State: 16 - GherkinDocument:0>Feature:2>ScenarioDefinition:1>Scenario:2>Step:1>StepArg:0>__alt0:0>DataTableAndMaybeDocString:1>DocString:0>#DocStringSeparator:0" + var expectedTokens = []string{"#DocStringSeparator", "#Other"} + if line.IsEof() { + err = &parseError{ + msg: fmt.Sprintf("unexpected end of file, expected: %s", strings.Join(expectedTokens, ", ")), + loc: &Location{Line: line.LineNumber, Column: 0}, + } + } else { + err = &parseError{ + msg: fmt.Sprintf("expected: %s, got '%s'", strings.Join(expectedTokens, ", "), line.LineText), + loc: &Location{Line: line.LineNumber, Column: line.Indent() + 1}, + } + } + // if (ctxt.p.stopAtFirstError) throw error; + //ctxt.addError(err) + return 16, err +} + +// GherkinDocument:0>Feature:2>ScenarioDefinition:1>Scenario:2>Step:1>StepArg:0>__alt0:0>DataTableAndMaybeDocString:1>DocString:2>#DocStringSeparator:0 +func (ctxt *parseContext) matchAt17(line *Line) (newState int, err error) { + if ok, token, err := ctxt.matchEOF(line); ok { + ctxt.endRule(RuleTypeDocString) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.endRule(RuleTypeFeature) + ctxt.build(token) + return 42, err + } + if ok, token, err := ctxt.matchStepLine(line); ok { + ctxt.endRule(RuleTypeDocString) + ctxt.endRule(RuleTypeStep) + ctxt.startRule(RuleTypeStep) + ctxt.build(token) + return 14, err + } + if ok, token, err := ctxt.matchTagLine(line); ok { + if ctxt.lookahead1(line) { + ctxt.endRule(RuleTypeDocString) + ctxt.endRule(RuleTypeStep) + ctxt.startRule(RuleTypeExamplesDefinition) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 18, err + } + } + if ok, token, err := ctxt.matchTagLine(line); ok { + if ctxt.lookahead0(line) { + ctxt.endRule(RuleTypeDocString) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 11, err + } + } + if ok, token, err := ctxt.matchTagLine(line); ok { + ctxt.endRule(RuleTypeDocString) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 22, err + } + if ok, token, err := ctxt.matchExamplesLine(line); ok { + ctxt.endRule(RuleTypeDocString) + ctxt.endRule(RuleTypeStep) + ctxt.startRule(RuleTypeExamplesDefinition) + ctxt.startRule(RuleTypeExamples) + ctxt.build(token) + return 19, err + } + if ok, token, err := ctxt.matchScenarioLine(line); ok { + ctxt.endRule(RuleTypeDocString) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenario) + ctxt.build(token) + return 12, err + } + if ok, token, err := ctxt.matchRuleLine(line); ok { + ctxt.endRule(RuleTypeDocString) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.build(token) + return 23, err + } + if ok, token, err := ctxt.matchComment(line); ok { + ctxt.build(token) + return 17, err + } + if ok, token, err := ctxt.matchEmpty(line); ok { + ctxt.build(token) + return 17, err + } + + // var stateComment = "State: 17 - GherkinDocument:0>Feature:2>ScenarioDefinition:1>Scenario:2>Step:1>StepArg:0>__alt0:0>DataTableAndMaybeDocString:1>DocString:2>#DocStringSeparator:0" + var expectedTokens = []string{"#EOF", "#StepLine", "#TagLine", "#ExamplesLine", "#ScenarioLine", "#RuleLine", "#Comment", "#Empty"} + if line.IsEof() { + err = &parseError{ + msg: fmt.Sprintf("unexpected end of file, expected: %s", strings.Join(expectedTokens, ", ")), + loc: &Location{Line: line.LineNumber, Column: 0}, + } + } else { + err = &parseError{ + msg: fmt.Sprintf("expected: %s, got '%s'", strings.Join(expectedTokens, ", "), line.LineText), + loc: &Location{Line: line.LineNumber, Column: line.Indent() + 1}, + } + } + // if (ctxt.p.stopAtFirstError) throw error; + //ctxt.addError(err) + return 17, err +} + +// GherkinDocument:0>Feature:2>ScenarioDefinition:1>Scenario:3>ExamplesDefinition:0>Tags:0>#TagLine:0 +func (ctxt *parseContext) matchAt18(line *Line) (newState int, err error) { + if ok, token, err := ctxt.matchTagLine(line); ok { + ctxt.build(token) + return 18, err + } + if ok, token, err := ctxt.matchExamplesLine(line); ok { + ctxt.endRule(RuleTypeTags) + ctxt.startRule(RuleTypeExamples) + ctxt.build(token) + return 19, err + } + if ok, token, err := ctxt.matchComment(line); ok { + ctxt.build(token) + return 18, err + } + if ok, token, err := ctxt.matchEmpty(line); ok { + ctxt.build(token) + return 18, err + } + + // var stateComment = "State: 18 - GherkinDocument:0>Feature:2>ScenarioDefinition:1>Scenario:3>ExamplesDefinition:0>Tags:0>#TagLine:0" + var expectedTokens = []string{"#TagLine", "#ExamplesLine", "#Comment", "#Empty"} + if line.IsEof() { + err = &parseError{ + msg: fmt.Sprintf("unexpected end of file, expected: %s", strings.Join(expectedTokens, ", ")), + loc: &Location{Line: line.LineNumber, Column: 0}, + } + } else { + err = &parseError{ + msg: fmt.Sprintf("expected: %s, got '%s'", strings.Join(expectedTokens, ", "), line.LineText), + loc: &Location{Line: line.LineNumber, Column: line.Indent() + 1}, + } + } + // if (ctxt.p.stopAtFirstError) throw error; + //ctxt.addError(err) + return 18, err +} + +// GherkinDocument:0>Feature:2>ScenarioDefinition:1>Scenario:3>ExamplesDefinition:1>Examples:0>#ExamplesLine:0 +func (ctxt *parseContext) matchAt19(line *Line) (newState int, err error) { + if ok, token, err := ctxt.matchEOF(line); ok { + ctxt.endRule(RuleTypeExamples) + ctxt.endRule(RuleTypeExamplesDefinition) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.endRule(RuleTypeFeature) + ctxt.build(token) + return 42, err + } + if ok, token, err := ctxt.matchEmpty(line); ok { + ctxt.build(token) + return 19, err + } + if ok, token, err := ctxt.matchComment(line); ok { + ctxt.startRule(RuleTypeDescription) + ctxt.build(token) + return 20, err + } + if ok, token, err := ctxt.matchTableRow(line); ok { + ctxt.startRule(RuleTypeExamplesTable) + ctxt.build(token) + return 21, err + } + if ok, token, err := ctxt.matchTagLine(line); ok { + if ctxt.lookahead1(line) { + ctxt.endRule(RuleTypeExamples) + ctxt.endRule(RuleTypeExamplesDefinition) + ctxt.startRule(RuleTypeExamplesDefinition) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 18, err + } + } + if ok, token, err := ctxt.matchTagLine(line); ok { + if ctxt.lookahead0(line) { + ctxt.endRule(RuleTypeExamples) + ctxt.endRule(RuleTypeExamplesDefinition) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 11, err + } + } + if ok, token, err := ctxt.matchTagLine(line); ok { + ctxt.endRule(RuleTypeExamples) + ctxt.endRule(RuleTypeExamplesDefinition) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 22, err + } + if ok, token, err := ctxt.matchExamplesLine(line); ok { + ctxt.endRule(RuleTypeExamples) + ctxt.endRule(RuleTypeExamplesDefinition) + ctxt.startRule(RuleTypeExamplesDefinition) + ctxt.startRule(RuleTypeExamples) + ctxt.build(token) + return 19, err + } + if ok, token, err := ctxt.matchScenarioLine(line); ok { + ctxt.endRule(RuleTypeExamples) + ctxt.endRule(RuleTypeExamplesDefinition) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenario) + ctxt.build(token) + return 12, err + } + if ok, token, err := ctxt.matchRuleLine(line); ok { + ctxt.endRule(RuleTypeExamples) + ctxt.endRule(RuleTypeExamplesDefinition) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.build(token) + return 23, err + } + if ok, token, err := ctxt.matchOther(line); ok { + ctxt.startRule(RuleTypeDescription) + ctxt.build(token) + return 20, err + } + + // var stateComment = "State: 19 - GherkinDocument:0>Feature:2>ScenarioDefinition:1>Scenario:3>ExamplesDefinition:1>Examples:0>#ExamplesLine:0" + var expectedTokens = []string{"#EOF", "#Empty", "#Comment", "#TableRow", "#TagLine", "#ExamplesLine", "#ScenarioLine", "#RuleLine", "#Other"} + if line.IsEof() { + err = &parseError{ + msg: fmt.Sprintf("unexpected end of file, expected: %s", strings.Join(expectedTokens, ", ")), + loc: &Location{Line: line.LineNumber, Column: 0}, + } + } else { + err = &parseError{ + msg: fmt.Sprintf("expected: %s, got '%s'", strings.Join(expectedTokens, ", "), line.LineText), + loc: &Location{Line: line.LineNumber, Column: line.Indent() + 1}, + } + } + // if (ctxt.p.stopAtFirstError) throw error; + //ctxt.addError(err) + return 19, err +} + +// GherkinDocument:0>Feature:2>ScenarioDefinition:1>Scenario:3>ExamplesDefinition:1>Examples:1>DescriptionHelper:1>Description:0>__alt1:0>#Other:0 +func (ctxt *parseContext) matchAt20(line *Line) (newState int, err error) { + if ok, token, err := ctxt.matchEOF(line); ok { + ctxt.endRule(RuleTypeDescription) + ctxt.endRule(RuleTypeExamples) + ctxt.endRule(RuleTypeExamplesDefinition) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.endRule(RuleTypeFeature) + ctxt.build(token) + return 42, err + } + if ok, token, err := ctxt.matchComment(line); ok { + ctxt.build(token) + return 20, err + } + if ok, token, err := ctxt.matchTableRow(line); ok { + ctxt.endRule(RuleTypeDescription) + ctxt.startRule(RuleTypeExamplesTable) + ctxt.build(token) + return 21, err + } + if ok, token, err := ctxt.matchTagLine(line); ok { + if ctxt.lookahead1(line) { + ctxt.endRule(RuleTypeDescription) + ctxt.endRule(RuleTypeExamples) + ctxt.endRule(RuleTypeExamplesDefinition) + ctxt.startRule(RuleTypeExamplesDefinition) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 18, err + } + } + if ok, token, err := ctxt.matchTagLine(line); ok { + if ctxt.lookahead0(line) { + ctxt.endRule(RuleTypeDescription) + ctxt.endRule(RuleTypeExamples) + ctxt.endRule(RuleTypeExamplesDefinition) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 11, err + } + } + if ok, token, err := ctxt.matchTagLine(line); ok { + ctxt.endRule(RuleTypeDescription) + ctxt.endRule(RuleTypeExamples) + ctxt.endRule(RuleTypeExamplesDefinition) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 22, err + } + if ok, token, err := ctxt.matchExamplesLine(line); ok { + ctxt.endRule(RuleTypeDescription) + ctxt.endRule(RuleTypeExamples) + ctxt.endRule(RuleTypeExamplesDefinition) + ctxt.startRule(RuleTypeExamplesDefinition) + ctxt.startRule(RuleTypeExamples) + ctxt.build(token) + return 19, err + } + if ok, token, err := ctxt.matchScenarioLine(line); ok { + ctxt.endRule(RuleTypeDescription) + ctxt.endRule(RuleTypeExamples) + ctxt.endRule(RuleTypeExamplesDefinition) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenario) + ctxt.build(token) + return 12, err + } + if ok, token, err := ctxt.matchRuleLine(line); ok { + ctxt.endRule(RuleTypeDescription) + ctxt.endRule(RuleTypeExamples) + ctxt.endRule(RuleTypeExamplesDefinition) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.build(token) + return 23, err + } + if ok, token, err := ctxt.matchOther(line); ok { + ctxt.build(token) + return 20, err + } + + // var stateComment = "State: 20 - GherkinDocument:0>Feature:2>ScenarioDefinition:1>Scenario:3>ExamplesDefinition:1>Examples:1>DescriptionHelper:1>Description:0>__alt1:0>#Other:0" + var expectedTokens = []string{"#EOF", "#Comment", "#TableRow", "#TagLine", "#ExamplesLine", "#ScenarioLine", "#RuleLine", "#Other"} + if line.IsEof() { + err = &parseError{ + msg: fmt.Sprintf("unexpected end of file, expected: %s", strings.Join(expectedTokens, ", ")), + loc: &Location{Line: line.LineNumber, Column: 0}, + } + } else { + err = &parseError{ + msg: fmt.Sprintf("expected: %s, got '%s'", strings.Join(expectedTokens, ", "), line.LineText), + loc: &Location{Line: line.LineNumber, Column: line.Indent() + 1}, + } + } + // if (ctxt.p.stopAtFirstError) throw error; + //ctxt.addError(err) + return 20, err +} + +// GherkinDocument:0>Feature:2>ScenarioDefinition:1>Scenario:3>ExamplesDefinition:1>Examples:2>ExamplesTable:0>#TableRow:0 +func (ctxt *parseContext) matchAt21(line *Line) (newState int, err error) { + if ok, token, err := ctxt.matchEOF(line); ok { + ctxt.endRule(RuleTypeExamplesTable) + ctxt.endRule(RuleTypeExamples) + ctxt.endRule(RuleTypeExamplesDefinition) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.endRule(RuleTypeFeature) + ctxt.build(token) + return 42, err + } + if ok, token, err := ctxt.matchTableRow(line); ok { + ctxt.build(token) + return 21, err + } + if ok, token, err := ctxt.matchTagLine(line); ok { + if ctxt.lookahead1(line) { + ctxt.endRule(RuleTypeExamplesTable) + ctxt.endRule(RuleTypeExamples) + ctxt.endRule(RuleTypeExamplesDefinition) + ctxt.startRule(RuleTypeExamplesDefinition) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 18, err + } + } + if ok, token, err := ctxt.matchTagLine(line); ok { + if ctxt.lookahead0(line) { + ctxt.endRule(RuleTypeExamplesTable) + ctxt.endRule(RuleTypeExamples) + ctxt.endRule(RuleTypeExamplesDefinition) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 11, err + } + } + if ok, token, err := ctxt.matchTagLine(line); ok { + ctxt.endRule(RuleTypeExamplesTable) + ctxt.endRule(RuleTypeExamples) + ctxt.endRule(RuleTypeExamplesDefinition) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 22, err + } + if ok, token, err := ctxt.matchExamplesLine(line); ok { + ctxt.endRule(RuleTypeExamplesTable) + ctxt.endRule(RuleTypeExamples) + ctxt.endRule(RuleTypeExamplesDefinition) + ctxt.startRule(RuleTypeExamplesDefinition) + ctxt.startRule(RuleTypeExamples) + ctxt.build(token) + return 19, err + } + if ok, token, err := ctxt.matchScenarioLine(line); ok { + ctxt.endRule(RuleTypeExamplesTable) + ctxt.endRule(RuleTypeExamples) + ctxt.endRule(RuleTypeExamplesDefinition) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenario) + ctxt.build(token) + return 12, err + } + if ok, token, err := ctxt.matchRuleLine(line); ok { + ctxt.endRule(RuleTypeExamplesTable) + ctxt.endRule(RuleTypeExamples) + ctxt.endRule(RuleTypeExamplesDefinition) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.build(token) + return 23, err + } + if ok, token, err := ctxt.matchComment(line); ok { + ctxt.build(token) + return 21, err + } + if ok, token, err := ctxt.matchEmpty(line); ok { + ctxt.build(token) + return 21, err + } + + // var stateComment = "State: 21 - GherkinDocument:0>Feature:2>ScenarioDefinition:1>Scenario:3>ExamplesDefinition:1>Examples:2>ExamplesTable:0>#TableRow:0" + var expectedTokens = []string{"#EOF", "#TableRow", "#TagLine", "#ExamplesLine", "#ScenarioLine", "#RuleLine", "#Comment", "#Empty"} + if line.IsEof() { + err = &parseError{ + msg: fmt.Sprintf("unexpected end of file, expected: %s", strings.Join(expectedTokens, ", ")), + loc: &Location{Line: line.LineNumber, Column: 0}, + } + } else { + err = &parseError{ + msg: fmt.Sprintf("expected: %s, got '%s'", strings.Join(expectedTokens, ", "), line.LineText), + loc: &Location{Line: line.LineNumber, Column: line.Indent() + 1}, + } + } + // if (ctxt.p.stopAtFirstError) throw error; + //ctxt.addError(err) + return 21, err +} + +// GherkinDocument:0>Feature:3>Rule:0>RuleHeader:0>Tags:0>#TagLine:0 +func (ctxt *parseContext) matchAt22(line *Line) (newState int, err error) { + if ok, token, err := ctxt.matchTagLine(line); ok { + ctxt.build(token) + return 22, err + } + if ok, token, err := ctxt.matchRuleLine(line); ok { + ctxt.endRule(RuleTypeTags) + ctxt.build(token) + return 23, err + } + if ok, token, err := ctxt.matchComment(line); ok { + ctxt.build(token) + return 22, err + } + if ok, token, err := ctxt.matchEmpty(line); ok { + ctxt.build(token) + return 22, err + } + + // var stateComment = "State: 22 - GherkinDocument:0>Feature:3>Rule:0>RuleHeader:0>Tags:0>#TagLine:0" + var expectedTokens = []string{"#TagLine", "#RuleLine", "#Comment", "#Empty"} + if line.IsEof() { + err = &parseError{ + msg: fmt.Sprintf("unexpected end of file, expected: %s", strings.Join(expectedTokens, ", ")), + loc: &Location{Line: line.LineNumber, Column: 0}, + } + } else { + err = &parseError{ + msg: fmt.Sprintf("expected: %s, got '%s'", strings.Join(expectedTokens, ", "), line.LineText), + loc: &Location{Line: line.LineNumber, Column: line.Indent() + 1}, + } + } + // if (ctxt.p.stopAtFirstError) throw error; + //ctxt.addError(err) + return 22, err +} + +// GherkinDocument:0>Feature:3>Rule:0>RuleHeader:1>#RuleLine:0 +func (ctxt *parseContext) matchAt23(line *Line) (newState int, err error) { + if ok, token, err := ctxt.matchEOF(line); ok { + ctxt.endRule(RuleTypeRuleHeader) + ctxt.endRule(RuleTypeRule) + ctxt.endRule(RuleTypeFeature) + ctxt.build(token) + return 42, err + } + if ok, token, err := ctxt.matchEmpty(line); ok { + ctxt.build(token) + return 23, err + } + if ok, token, err := ctxt.matchComment(line); ok { + ctxt.startRule(RuleTypeDescription) + ctxt.build(token) + return 24, err + } + if ok, token, err := ctxt.matchBackgroundLine(line); ok { + ctxt.endRule(RuleTypeRuleHeader) + ctxt.startRule(RuleTypeBackground) + ctxt.build(token) + return 25, err + } + if ok, token, err := ctxt.matchTagLine(line); ok { + if ctxt.lookahead0(line) { + ctxt.endRule(RuleTypeRuleHeader) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 31, err + } + } + if ok, token, err := ctxt.matchTagLine(line); ok { + ctxt.endRule(RuleTypeRuleHeader) + ctxt.endRule(RuleTypeRule) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 22, err + } + if ok, token, err := ctxt.matchScenarioLine(line); ok { + ctxt.endRule(RuleTypeRuleHeader) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenario) + ctxt.build(token) + return 32, err + } + if ok, token, err := ctxt.matchRuleLine(line); ok { + ctxt.endRule(RuleTypeRuleHeader) + ctxt.endRule(RuleTypeRule) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.build(token) + return 23, err + } + if ok, token, err := ctxt.matchOther(line); ok { + ctxt.startRule(RuleTypeDescription) + ctxt.build(token) + return 24, err + } + + // var stateComment = "State: 23 - GherkinDocument:0>Feature:3>Rule:0>RuleHeader:1>#RuleLine:0" + var expectedTokens = []string{"#EOF", "#Empty", "#Comment", "#BackgroundLine", "#TagLine", "#ScenarioLine", "#RuleLine", "#Other"} + if line.IsEof() { + err = &parseError{ + msg: fmt.Sprintf("unexpected end of file, expected: %s", strings.Join(expectedTokens, ", ")), + loc: &Location{Line: line.LineNumber, Column: 0}, + } + } else { + err = &parseError{ + msg: fmt.Sprintf("expected: %s, got '%s'", strings.Join(expectedTokens, ", "), line.LineText), + loc: &Location{Line: line.LineNumber, Column: line.Indent() + 1}, + } + } + // if (ctxt.p.stopAtFirstError) throw error; + //ctxt.addError(err) + return 23, err +} + +// GherkinDocument:0>Feature:3>Rule:0>RuleHeader:2>DescriptionHelper:1>Description:0>__alt1:0>#Other:0 +func (ctxt *parseContext) matchAt24(line *Line) (newState int, err error) { + if ok, token, err := ctxt.matchEOF(line); ok { + ctxt.endRule(RuleTypeDescription) + ctxt.endRule(RuleTypeRuleHeader) + ctxt.endRule(RuleTypeRule) + ctxt.endRule(RuleTypeFeature) + ctxt.build(token) + return 42, err + } + if ok, token, err := ctxt.matchComment(line); ok { + ctxt.build(token) + return 24, err + } + if ok, token, err := ctxt.matchBackgroundLine(line); ok { + ctxt.endRule(RuleTypeDescription) + ctxt.endRule(RuleTypeRuleHeader) + ctxt.startRule(RuleTypeBackground) + ctxt.build(token) + return 25, err + } + if ok, token, err := ctxt.matchTagLine(line); ok { + if ctxt.lookahead0(line) { + ctxt.endRule(RuleTypeDescription) + ctxt.endRule(RuleTypeRuleHeader) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 31, err + } + } + if ok, token, err := ctxt.matchTagLine(line); ok { + ctxt.endRule(RuleTypeDescription) + ctxt.endRule(RuleTypeRuleHeader) + ctxt.endRule(RuleTypeRule) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 22, err + } + if ok, token, err := ctxt.matchScenarioLine(line); ok { + ctxt.endRule(RuleTypeDescription) + ctxt.endRule(RuleTypeRuleHeader) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenario) + ctxt.build(token) + return 32, err + } + if ok, token, err := ctxt.matchRuleLine(line); ok { + ctxt.endRule(RuleTypeDescription) + ctxt.endRule(RuleTypeRuleHeader) + ctxt.endRule(RuleTypeRule) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.build(token) + return 23, err + } + if ok, token, err := ctxt.matchOther(line); ok { + ctxt.build(token) + return 24, err + } + + // var stateComment = "State: 24 - GherkinDocument:0>Feature:3>Rule:0>RuleHeader:2>DescriptionHelper:1>Description:0>__alt1:0>#Other:0" + var expectedTokens = []string{"#EOF", "#Comment", "#BackgroundLine", "#TagLine", "#ScenarioLine", "#RuleLine", "#Other"} + if line.IsEof() { + err = &parseError{ + msg: fmt.Sprintf("unexpected end of file, expected: %s", strings.Join(expectedTokens, ", ")), + loc: &Location{Line: line.LineNumber, Column: 0}, + } + } else { + err = &parseError{ + msg: fmt.Sprintf("expected: %s, got '%s'", strings.Join(expectedTokens, ", "), line.LineText), + loc: &Location{Line: line.LineNumber, Column: line.Indent() + 1}, + } + } + // if (ctxt.p.stopAtFirstError) throw error; + //ctxt.addError(err) + return 24, err +} + +// GherkinDocument:0>Feature:3>Rule:1>Background:0>#BackgroundLine:0 +func (ctxt *parseContext) matchAt25(line *Line) (newState int, err error) { + if ok, token, err := ctxt.matchEOF(line); ok { + ctxt.endRule(RuleTypeBackground) + ctxt.endRule(RuleTypeRule) + ctxt.endRule(RuleTypeFeature) + ctxt.build(token) + return 42, err + } + if ok, token, err := ctxt.matchEmpty(line); ok { + ctxt.build(token) + return 25, err + } + if ok, token, err := ctxt.matchComment(line); ok { + ctxt.startRule(RuleTypeDescription) + ctxt.build(token) + return 26, err + } + if ok, token, err := ctxt.matchStepLine(line); ok { + ctxt.startRule(RuleTypeStep) + ctxt.build(token) + return 27, err + } + if ok, token, err := ctxt.matchTagLine(line); ok { + if ctxt.lookahead0(line) { + ctxt.endRule(RuleTypeBackground) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 31, err + } + } + if ok, token, err := ctxt.matchTagLine(line); ok { + ctxt.endRule(RuleTypeBackground) + ctxt.endRule(RuleTypeRule) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 22, err + } + if ok, token, err := ctxt.matchScenarioLine(line); ok { + ctxt.endRule(RuleTypeBackground) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenario) + ctxt.build(token) + return 32, err + } + if ok, token, err := ctxt.matchRuleLine(line); ok { + ctxt.endRule(RuleTypeBackground) + ctxt.endRule(RuleTypeRule) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.build(token) + return 23, err + } + if ok, token, err := ctxt.matchOther(line); ok { + ctxt.startRule(RuleTypeDescription) + ctxt.build(token) + return 26, err + } + + // var stateComment = "State: 25 - GherkinDocument:0>Feature:3>Rule:1>Background:0>#BackgroundLine:0" + var expectedTokens = []string{"#EOF", "#Empty", "#Comment", "#StepLine", "#TagLine", "#ScenarioLine", "#RuleLine", "#Other"} + if line.IsEof() { + err = &parseError{ + msg: fmt.Sprintf("unexpected end of file, expected: %s", strings.Join(expectedTokens, ", ")), + loc: &Location{Line: line.LineNumber, Column: 0}, + } + } else { + err = &parseError{ + msg: fmt.Sprintf("expected: %s, got '%s'", strings.Join(expectedTokens, ", "), line.LineText), + loc: &Location{Line: line.LineNumber, Column: line.Indent() + 1}, + } + } + // if (ctxt.p.stopAtFirstError) throw error; + //ctxt.addError(err) + return 25, err +} + +// GherkinDocument:0>Feature:3>Rule:1>Background:1>DescriptionHelper:1>Description:0>__alt1:0>#Other:0 +func (ctxt *parseContext) matchAt26(line *Line) (newState int, err error) { + if ok, token, err := ctxt.matchEOF(line); ok { + ctxt.endRule(RuleTypeDescription) + ctxt.endRule(RuleTypeBackground) + ctxt.endRule(RuleTypeRule) + ctxt.endRule(RuleTypeFeature) + ctxt.build(token) + return 42, err + } + if ok, token, err := ctxt.matchComment(line); ok { + ctxt.build(token) + return 26, err + } + if ok, token, err := ctxt.matchStepLine(line); ok { + ctxt.endRule(RuleTypeDescription) + ctxt.startRule(RuleTypeStep) + ctxt.build(token) + return 27, err + } + if ok, token, err := ctxt.matchTagLine(line); ok { + if ctxt.lookahead0(line) { + ctxt.endRule(RuleTypeDescription) + ctxt.endRule(RuleTypeBackground) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 31, err + } + } + if ok, token, err := ctxt.matchTagLine(line); ok { + ctxt.endRule(RuleTypeDescription) + ctxt.endRule(RuleTypeBackground) + ctxt.endRule(RuleTypeRule) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 22, err + } + if ok, token, err := ctxt.matchScenarioLine(line); ok { + ctxt.endRule(RuleTypeDescription) + ctxt.endRule(RuleTypeBackground) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenario) + ctxt.build(token) + return 32, err + } + if ok, token, err := ctxt.matchRuleLine(line); ok { + ctxt.endRule(RuleTypeDescription) + ctxt.endRule(RuleTypeBackground) + ctxt.endRule(RuleTypeRule) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.build(token) + return 23, err + } + if ok, token, err := ctxt.matchOther(line); ok { + ctxt.build(token) + return 26, err + } + + // var stateComment = "State: 26 - GherkinDocument:0>Feature:3>Rule:1>Background:1>DescriptionHelper:1>Description:0>__alt1:0>#Other:0" + var expectedTokens = []string{"#EOF", "#Comment", "#StepLine", "#TagLine", "#ScenarioLine", "#RuleLine", "#Other"} + if line.IsEof() { + err = &parseError{ + msg: fmt.Sprintf("unexpected end of file, expected: %s", strings.Join(expectedTokens, ", ")), + loc: &Location{Line: line.LineNumber, Column: 0}, + } + } else { + err = &parseError{ + msg: fmt.Sprintf("expected: %s, got '%s'", strings.Join(expectedTokens, ", "), line.LineText), + loc: &Location{Line: line.LineNumber, Column: line.Indent() + 1}, + } + } + // if (ctxt.p.stopAtFirstError) throw error; + //ctxt.addError(err) + return 26, err +} + +// GherkinDocument:0>Feature:3>Rule:1>Background:2>Step:0>#StepLine:0 +func (ctxt *parseContext) matchAt27(line *Line) (newState int, err error) { + if ok, token, err := ctxt.matchEOF(line); ok { + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeBackground) + ctxt.endRule(RuleTypeRule) + ctxt.endRule(RuleTypeFeature) + ctxt.build(token) + return 42, err + } + if ok, token, err := ctxt.matchTableRow(line); ok { + ctxt.startRule(RuleTypeDataTable) + ctxt.build(token) + return 28, err + } + if ok, token, err := ctxt.matchDocStringSeparator(line); ok { + ctxt.startRule(RuleTypeDocString) + ctxt.build(token) + return 46, err + } + if ok, token, err := ctxt.matchStepLine(line); ok { + ctxt.endRule(RuleTypeStep) + ctxt.startRule(RuleTypeStep) + ctxt.build(token) + return 27, err + } + if ok, token, err := ctxt.matchTagLine(line); ok { + if ctxt.lookahead0(line) { + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeBackground) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 31, err + } + } + if ok, token, err := ctxt.matchTagLine(line); ok { + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeBackground) + ctxt.endRule(RuleTypeRule) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 22, err + } + if ok, token, err := ctxt.matchScenarioLine(line); ok { + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeBackground) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenario) + ctxt.build(token) + return 32, err + } + if ok, token, err := ctxt.matchRuleLine(line); ok { + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeBackground) + ctxt.endRule(RuleTypeRule) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.build(token) + return 23, err + } + if ok, token, err := ctxt.matchComment(line); ok { + ctxt.build(token) + return 27, err + } + if ok, token, err := ctxt.matchEmpty(line); ok { + ctxt.build(token) + return 27, err + } + + // var stateComment = "State: 27 - GherkinDocument:0>Feature:3>Rule:1>Background:2>Step:0>#StepLine:0" + var expectedTokens = []string{"#EOF", "#TableRow", "#DocStringSeparator", "#StepLine", "#TagLine", "#ScenarioLine", "#RuleLine", "#Comment", "#Empty"} + if line.IsEof() { + err = &parseError{ + msg: fmt.Sprintf("unexpected end of file, expected: %s", strings.Join(expectedTokens, ", ")), + loc: &Location{Line: line.LineNumber, Column: 0}, + } + } else { + err = &parseError{ + msg: fmt.Sprintf("expected: %s, got '%s'", strings.Join(expectedTokens, ", "), line.LineText), + loc: &Location{Line: line.LineNumber, Column: line.Indent() + 1}, + } + } + // if (ctxt.p.stopAtFirstError) throw error; + //ctxt.addError(err) + return 27, err +} + +// GherkinDocument:0>Feature:3>Rule:1>Background:2>Step:1>StepArg:0>__alt0:0>DataTableAndMaybeDocString:0>DataTable:0>#TableRow:0 +func (ctxt *parseContext) matchAt28(line *Line) (newState int, err error) { + if ok, token, err := ctxt.matchEOF(line); ok { + ctxt.endRule(RuleTypeDataTable) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeBackground) + ctxt.endRule(RuleTypeRule) + ctxt.endRule(RuleTypeFeature) + ctxt.build(token) + return 42, err + } + if ok, token, err := ctxt.matchTableRow(line); ok { + ctxt.build(token) + return 28, err + } + if ok, token, err := ctxt.matchDocStringSeparator(line); ok { + ctxt.endRule(RuleTypeDataTable) + ctxt.startRule(RuleTypeDocString) + ctxt.build(token) + return 29, err + } + if ok, token, err := ctxt.matchStepLine(line); ok { + ctxt.endRule(RuleTypeDataTable) + ctxt.endRule(RuleTypeStep) + ctxt.startRule(RuleTypeStep) + ctxt.build(token) + return 27, err + } + if ok, token, err := ctxt.matchTagLine(line); ok { + if ctxt.lookahead0(line) { + ctxt.endRule(RuleTypeDataTable) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeBackground) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 31, err + } + } + if ok, token, err := ctxt.matchTagLine(line); ok { + ctxt.endRule(RuleTypeDataTable) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeBackground) + ctxt.endRule(RuleTypeRule) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 22, err + } + if ok, token, err := ctxt.matchScenarioLine(line); ok { + ctxt.endRule(RuleTypeDataTable) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeBackground) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenario) + ctxt.build(token) + return 32, err + } + if ok, token, err := ctxt.matchRuleLine(line); ok { + ctxt.endRule(RuleTypeDataTable) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeBackground) + ctxt.endRule(RuleTypeRule) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.build(token) + return 23, err + } + if ok, token, err := ctxt.matchComment(line); ok { + ctxt.build(token) + return 28, err + } + if ok, token, err := ctxt.matchEmpty(line); ok { + ctxt.build(token) + return 28, err + } + + // var stateComment = "State: 28 - GherkinDocument:0>Feature:3>Rule:1>Background:2>Step:1>StepArg:0>__alt0:0>DataTableAndMaybeDocString:0>DataTable:0>#TableRow:0" + var expectedTokens = []string{"#EOF", "#TableRow", "#DocStringSeparator", "#StepLine", "#TagLine", "#ScenarioLine", "#RuleLine", "#Comment", "#Empty"} + if line.IsEof() { + err = &parseError{ + msg: fmt.Sprintf("unexpected end of file, expected: %s", strings.Join(expectedTokens, ", ")), + loc: &Location{Line: line.LineNumber, Column: 0}, + } + } else { + err = &parseError{ + msg: fmt.Sprintf("expected: %s, got '%s'", strings.Join(expectedTokens, ", "), line.LineText), + loc: &Location{Line: line.LineNumber, Column: line.Indent() + 1}, + } + } + // if (ctxt.p.stopAtFirstError) throw error; + //ctxt.addError(err) + return 28, err +} + +// GherkinDocument:0>Feature:3>Rule:1>Background:2>Step:1>StepArg:0>__alt0:0>DataTableAndMaybeDocString:1>DocString:0>#DocStringSeparator:0 +func (ctxt *parseContext) matchAt29(line *Line) (newState int, err error) { + if ok, token, err := ctxt.matchDocStringSeparator(line); ok { + ctxt.build(token) + return 30, err + } + if ok, token, err := ctxt.matchOther(line); ok { + ctxt.build(token) + return 29, err + } + + // var stateComment = "State: 29 - GherkinDocument:0>Feature:3>Rule:1>Background:2>Step:1>StepArg:0>__alt0:0>DataTableAndMaybeDocString:1>DocString:0>#DocStringSeparator:0" + var expectedTokens = []string{"#DocStringSeparator", "#Other"} + if line.IsEof() { + err = &parseError{ + msg: fmt.Sprintf("unexpected end of file, expected: %s", strings.Join(expectedTokens, ", ")), + loc: &Location{Line: line.LineNumber, Column: 0}, + } + } else { + err = &parseError{ + msg: fmt.Sprintf("expected: %s, got '%s'", strings.Join(expectedTokens, ", "), line.LineText), + loc: &Location{Line: line.LineNumber, Column: line.Indent() + 1}, + } + } + // if (ctxt.p.stopAtFirstError) throw error; + //ctxt.addError(err) + return 29, err +} + +// GherkinDocument:0>Feature:3>Rule:1>Background:2>Step:1>StepArg:0>__alt0:0>DataTableAndMaybeDocString:1>DocString:2>#DocStringSeparator:0 +func (ctxt *parseContext) matchAt30(line *Line) (newState int, err error) { + if ok, token, err := ctxt.matchEOF(line); ok { + ctxt.endRule(RuleTypeDocString) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeBackground) + ctxt.endRule(RuleTypeRule) + ctxt.endRule(RuleTypeFeature) + ctxt.build(token) + return 42, err + } + if ok, token, err := ctxt.matchStepLine(line); ok { + ctxt.endRule(RuleTypeDocString) + ctxt.endRule(RuleTypeStep) + ctxt.startRule(RuleTypeStep) + ctxt.build(token) + return 27, err + } + if ok, token, err := ctxt.matchTagLine(line); ok { + if ctxt.lookahead0(line) { + ctxt.endRule(RuleTypeDocString) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeBackground) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 31, err + } + } + if ok, token, err := ctxt.matchTagLine(line); ok { + ctxt.endRule(RuleTypeDocString) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeBackground) + ctxt.endRule(RuleTypeRule) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 22, err + } + if ok, token, err := ctxt.matchScenarioLine(line); ok { + ctxt.endRule(RuleTypeDocString) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeBackground) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenario) + ctxt.build(token) + return 32, err + } + if ok, token, err := ctxt.matchRuleLine(line); ok { + ctxt.endRule(RuleTypeDocString) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeBackground) + ctxt.endRule(RuleTypeRule) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.build(token) + return 23, err + } + if ok, token, err := ctxt.matchComment(line); ok { + ctxt.build(token) + return 30, err + } + if ok, token, err := ctxt.matchEmpty(line); ok { + ctxt.build(token) + return 30, err + } + + // var stateComment = "State: 30 - GherkinDocument:0>Feature:3>Rule:1>Background:2>Step:1>StepArg:0>__alt0:0>DataTableAndMaybeDocString:1>DocString:2>#DocStringSeparator:0" + var expectedTokens = []string{"#EOF", "#StepLine", "#TagLine", "#ScenarioLine", "#RuleLine", "#Comment", "#Empty"} + if line.IsEof() { + err = &parseError{ + msg: fmt.Sprintf("unexpected end of file, expected: %s", strings.Join(expectedTokens, ", ")), + loc: &Location{Line: line.LineNumber, Column: 0}, + } + } else { + err = &parseError{ + msg: fmt.Sprintf("expected: %s, got '%s'", strings.Join(expectedTokens, ", "), line.LineText), + loc: &Location{Line: line.LineNumber, Column: line.Indent() + 1}, + } + } + // if (ctxt.p.stopAtFirstError) throw error; + //ctxt.addError(err) + return 30, err +} + +// GherkinDocument:0>Feature:3>Rule:2>ScenarioDefinition:0>Tags:0>#TagLine:0 +func (ctxt *parseContext) matchAt31(line *Line) (newState int, err error) { + if ok, token, err := ctxt.matchTagLine(line); ok { + ctxt.build(token) + return 31, err + } + if ok, token, err := ctxt.matchScenarioLine(line); ok { + ctxt.endRule(RuleTypeTags) + ctxt.startRule(RuleTypeScenario) + ctxt.build(token) + return 32, err + } + if ok, token, err := ctxt.matchComment(line); ok { + ctxt.build(token) + return 31, err + } + if ok, token, err := ctxt.matchEmpty(line); ok { + ctxt.build(token) + return 31, err + } + + // var stateComment = "State: 31 - GherkinDocument:0>Feature:3>Rule:2>ScenarioDefinition:0>Tags:0>#TagLine:0" + var expectedTokens = []string{"#TagLine", "#ScenarioLine", "#Comment", "#Empty"} + if line.IsEof() { + err = &parseError{ + msg: fmt.Sprintf("unexpected end of file, expected: %s", strings.Join(expectedTokens, ", ")), + loc: &Location{Line: line.LineNumber, Column: 0}, + } + } else { + err = &parseError{ + msg: fmt.Sprintf("expected: %s, got '%s'", strings.Join(expectedTokens, ", "), line.LineText), + loc: &Location{Line: line.LineNumber, Column: line.Indent() + 1}, + } + } + // if (ctxt.p.stopAtFirstError) throw error; + //ctxt.addError(err) + return 31, err +} + +// GherkinDocument:0>Feature:3>Rule:2>ScenarioDefinition:1>Scenario:0>#ScenarioLine:0 +func (ctxt *parseContext) matchAt32(line *Line) (newState int, err error) { + if ok, token, err := ctxt.matchEOF(line); ok { + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.endRule(RuleTypeRule) + ctxt.endRule(RuleTypeFeature) + ctxt.build(token) + return 42, err + } + if ok, token, err := ctxt.matchEmpty(line); ok { + ctxt.build(token) + return 32, err + } + if ok, token, err := ctxt.matchComment(line); ok { + ctxt.startRule(RuleTypeDescription) + ctxt.build(token) + return 33, err + } + if ok, token, err := ctxt.matchStepLine(line); ok { + ctxt.startRule(RuleTypeStep) + ctxt.build(token) + return 34, err + } + if ok, token, err := ctxt.matchTagLine(line); ok { + if ctxt.lookahead1(line) { + ctxt.startRule(RuleTypeExamplesDefinition) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 38, err + } + } + if ok, token, err := ctxt.matchTagLine(line); ok { + if ctxt.lookahead0(line) { + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 31, err + } + } + if ok, token, err := ctxt.matchTagLine(line); ok { + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.endRule(RuleTypeRule) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 22, err + } + if ok, token, err := ctxt.matchExamplesLine(line); ok { + ctxt.startRule(RuleTypeExamplesDefinition) + ctxt.startRule(RuleTypeExamples) + ctxt.build(token) + return 39, err + } + if ok, token, err := ctxt.matchScenarioLine(line); ok { + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenario) + ctxt.build(token) + return 32, err + } + if ok, token, err := ctxt.matchRuleLine(line); ok { + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.endRule(RuleTypeRule) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.build(token) + return 23, err + } + if ok, token, err := ctxt.matchOther(line); ok { + ctxt.startRule(RuleTypeDescription) + ctxt.build(token) + return 33, err + } + + // var stateComment = "State: 32 - GherkinDocument:0>Feature:3>Rule:2>ScenarioDefinition:1>Scenario:0>#ScenarioLine:0" + var expectedTokens = []string{"#EOF", "#Empty", "#Comment", "#StepLine", "#TagLine", "#ExamplesLine", "#ScenarioLine", "#RuleLine", "#Other"} + if line.IsEof() { + err = &parseError{ + msg: fmt.Sprintf("unexpected end of file, expected: %s", strings.Join(expectedTokens, ", ")), + loc: &Location{Line: line.LineNumber, Column: 0}, + } + } else { + err = &parseError{ + msg: fmt.Sprintf("expected: %s, got '%s'", strings.Join(expectedTokens, ", "), line.LineText), + loc: &Location{Line: line.LineNumber, Column: line.Indent() + 1}, + } + } + // if (ctxt.p.stopAtFirstError) throw error; + //ctxt.addError(err) + return 32, err +} + +// GherkinDocument:0>Feature:3>Rule:2>ScenarioDefinition:1>Scenario:1>DescriptionHelper:1>Description:0>__alt1:0>#Other:0 +func (ctxt *parseContext) matchAt33(line *Line) (newState int, err error) { + if ok, token, err := ctxt.matchEOF(line); ok { + ctxt.endRule(RuleTypeDescription) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.endRule(RuleTypeRule) + ctxt.endRule(RuleTypeFeature) + ctxt.build(token) + return 42, err + } + if ok, token, err := ctxt.matchComment(line); ok { + ctxt.build(token) + return 33, err + } + if ok, token, err := ctxt.matchStepLine(line); ok { + ctxt.endRule(RuleTypeDescription) + ctxt.startRule(RuleTypeStep) + ctxt.build(token) + return 34, err + } + if ok, token, err := ctxt.matchTagLine(line); ok { + if ctxt.lookahead1(line) { + ctxt.endRule(RuleTypeDescription) + ctxt.startRule(RuleTypeExamplesDefinition) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 38, err + } + } + if ok, token, err := ctxt.matchTagLine(line); ok { + if ctxt.lookahead0(line) { + ctxt.endRule(RuleTypeDescription) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 31, err + } + } + if ok, token, err := ctxt.matchTagLine(line); ok { + ctxt.endRule(RuleTypeDescription) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.endRule(RuleTypeRule) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 22, err + } + if ok, token, err := ctxt.matchExamplesLine(line); ok { + ctxt.endRule(RuleTypeDescription) + ctxt.startRule(RuleTypeExamplesDefinition) + ctxt.startRule(RuleTypeExamples) + ctxt.build(token) + return 39, err + } + if ok, token, err := ctxt.matchScenarioLine(line); ok { + ctxt.endRule(RuleTypeDescription) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenario) + ctxt.build(token) + return 32, err + } + if ok, token, err := ctxt.matchRuleLine(line); ok { + ctxt.endRule(RuleTypeDescription) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.endRule(RuleTypeRule) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.build(token) + return 23, err + } + if ok, token, err := ctxt.matchOther(line); ok { + ctxt.build(token) + return 33, err + } + + // var stateComment = "State: 33 - GherkinDocument:0>Feature:3>Rule:2>ScenarioDefinition:1>Scenario:1>DescriptionHelper:1>Description:0>__alt1:0>#Other:0" + var expectedTokens = []string{"#EOF", "#Comment", "#StepLine", "#TagLine", "#ExamplesLine", "#ScenarioLine", "#RuleLine", "#Other"} + if line.IsEof() { + err = &parseError{ + msg: fmt.Sprintf("unexpected end of file, expected: %s", strings.Join(expectedTokens, ", ")), + loc: &Location{Line: line.LineNumber, Column: 0}, + } + } else { + err = &parseError{ + msg: fmt.Sprintf("expected: %s, got '%s'", strings.Join(expectedTokens, ", "), line.LineText), + loc: &Location{Line: line.LineNumber, Column: line.Indent() + 1}, + } + } + // if (ctxt.p.stopAtFirstError) throw error; + //ctxt.addError(err) + return 33, err +} + +// GherkinDocument:0>Feature:3>Rule:2>ScenarioDefinition:1>Scenario:2>Step:0>#StepLine:0 +func (ctxt *parseContext) matchAt34(line *Line) (newState int, err error) { + if ok, token, err := ctxt.matchEOF(line); ok { + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.endRule(RuleTypeRule) + ctxt.endRule(RuleTypeFeature) + ctxt.build(token) + return 42, err + } + if ok, token, err := ctxt.matchTableRow(line); ok { + ctxt.startRule(RuleTypeDataTable) + ctxt.build(token) + return 35, err + } + if ok, token, err := ctxt.matchDocStringSeparator(line); ok { + ctxt.startRule(RuleTypeDocString) + ctxt.build(token) + return 43, err + } + if ok, token, err := ctxt.matchStepLine(line); ok { + ctxt.endRule(RuleTypeStep) + ctxt.startRule(RuleTypeStep) + ctxt.build(token) + return 34, err + } + if ok, token, err := ctxt.matchTagLine(line); ok { + if ctxt.lookahead1(line) { + ctxt.endRule(RuleTypeStep) + ctxt.startRule(RuleTypeExamplesDefinition) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 38, err + } + } + if ok, token, err := ctxt.matchTagLine(line); ok { + if ctxt.lookahead0(line) { + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 31, err + } + } + if ok, token, err := ctxt.matchTagLine(line); ok { + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.endRule(RuleTypeRule) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 22, err + } + if ok, token, err := ctxt.matchExamplesLine(line); ok { + ctxt.endRule(RuleTypeStep) + ctxt.startRule(RuleTypeExamplesDefinition) + ctxt.startRule(RuleTypeExamples) + ctxt.build(token) + return 39, err + } + if ok, token, err := ctxt.matchScenarioLine(line); ok { + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenario) + ctxt.build(token) + return 32, err + } + if ok, token, err := ctxt.matchRuleLine(line); ok { + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.endRule(RuleTypeRule) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.build(token) + return 23, err + } + if ok, token, err := ctxt.matchComment(line); ok { + ctxt.build(token) + return 34, err + } + if ok, token, err := ctxt.matchEmpty(line); ok { + ctxt.build(token) + return 34, err + } + + // var stateComment = "State: 34 - GherkinDocument:0>Feature:3>Rule:2>ScenarioDefinition:1>Scenario:2>Step:0>#StepLine:0" + var expectedTokens = []string{"#EOF", "#TableRow", "#DocStringSeparator", "#StepLine", "#TagLine", "#ExamplesLine", "#ScenarioLine", "#RuleLine", "#Comment", "#Empty"} + if line.IsEof() { + err = &parseError{ + msg: fmt.Sprintf("unexpected end of file, expected: %s", strings.Join(expectedTokens, ", ")), + loc: &Location{Line: line.LineNumber, Column: 0}, + } + } else { + err = &parseError{ + msg: fmt.Sprintf("expected: %s, got '%s'", strings.Join(expectedTokens, ", "), line.LineText), + loc: &Location{Line: line.LineNumber, Column: line.Indent() + 1}, + } + } + // if (ctxt.p.stopAtFirstError) throw error; + //ctxt.addError(err) + return 34, err +} + +// GherkinDocument:0>Feature:3>Rule:2>ScenarioDefinition:1>Scenario:2>Step:1>StepArg:0>__alt0:0>DataTableAndMaybeDocString:0>DataTable:0>#TableRow:0 +func (ctxt *parseContext) matchAt35(line *Line) (newState int, err error) { + if ok, token, err := ctxt.matchEOF(line); ok { + ctxt.endRule(RuleTypeDataTable) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.endRule(RuleTypeRule) + ctxt.endRule(RuleTypeFeature) + ctxt.build(token) + return 42, err + } + if ok, token, err := ctxt.matchTableRow(line); ok { + ctxt.build(token) + return 35, err + } + if ok, token, err := ctxt.matchDocStringSeparator(line); ok { + ctxt.endRule(RuleTypeDataTable) + ctxt.startRule(RuleTypeDocString) + ctxt.build(token) + return 36, err + } + if ok, token, err := ctxt.matchStepLine(line); ok { + ctxt.endRule(RuleTypeDataTable) + ctxt.endRule(RuleTypeStep) + ctxt.startRule(RuleTypeStep) + ctxt.build(token) + return 34, err + } + if ok, token, err := ctxt.matchTagLine(line); ok { + if ctxt.lookahead1(line) { + ctxt.endRule(RuleTypeDataTable) + ctxt.endRule(RuleTypeStep) + ctxt.startRule(RuleTypeExamplesDefinition) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 38, err + } + } + if ok, token, err := ctxt.matchTagLine(line); ok { + if ctxt.lookahead0(line) { + ctxt.endRule(RuleTypeDataTable) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 31, err + } + } + if ok, token, err := ctxt.matchTagLine(line); ok { + ctxt.endRule(RuleTypeDataTable) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.endRule(RuleTypeRule) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 22, err + } + if ok, token, err := ctxt.matchExamplesLine(line); ok { + ctxt.endRule(RuleTypeDataTable) + ctxt.endRule(RuleTypeStep) + ctxt.startRule(RuleTypeExamplesDefinition) + ctxt.startRule(RuleTypeExamples) + ctxt.build(token) + return 39, err + } + if ok, token, err := ctxt.matchScenarioLine(line); ok { + ctxt.endRule(RuleTypeDataTable) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenario) + ctxt.build(token) + return 32, err + } + if ok, token, err := ctxt.matchRuleLine(line); ok { + ctxt.endRule(RuleTypeDataTable) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.endRule(RuleTypeRule) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.build(token) + return 23, err + } + if ok, token, err := ctxt.matchComment(line); ok { + ctxt.build(token) + return 35, err + } + if ok, token, err := ctxt.matchEmpty(line); ok { + ctxt.build(token) + return 35, err + } + + // var stateComment = "State: 35 - GherkinDocument:0>Feature:3>Rule:2>ScenarioDefinition:1>Scenario:2>Step:1>StepArg:0>__alt0:0>DataTableAndMaybeDocString:0>DataTable:0>#TableRow:0" + var expectedTokens = []string{"#EOF", "#TableRow", "#DocStringSeparator", "#StepLine", "#TagLine", "#ExamplesLine", "#ScenarioLine", "#RuleLine", "#Comment", "#Empty"} + if line.IsEof() { + err = &parseError{ + msg: fmt.Sprintf("unexpected end of file, expected: %s", strings.Join(expectedTokens, ", ")), + loc: &Location{Line: line.LineNumber, Column: 0}, + } + } else { + err = &parseError{ + msg: fmt.Sprintf("expected: %s, got '%s'", strings.Join(expectedTokens, ", "), line.LineText), + loc: &Location{Line: line.LineNumber, Column: line.Indent() + 1}, + } + } + // if (ctxt.p.stopAtFirstError) throw error; + //ctxt.addError(err) + return 35, err +} + +// GherkinDocument:0>Feature:3>Rule:2>ScenarioDefinition:1>Scenario:2>Step:1>StepArg:0>__alt0:0>DataTableAndMaybeDocString:1>DocString:0>#DocStringSeparator:0 +func (ctxt *parseContext) matchAt36(line *Line) (newState int, err error) { + if ok, token, err := ctxt.matchDocStringSeparator(line); ok { + ctxt.build(token) + return 37, err + } + if ok, token, err := ctxt.matchOther(line); ok { + ctxt.build(token) + return 36, err + } + + // var stateComment = "State: 36 - GherkinDocument:0>Feature:3>Rule:2>ScenarioDefinition:1>Scenario:2>Step:1>StepArg:0>__alt0:0>DataTableAndMaybeDocString:1>DocString:0>#DocStringSeparator:0" + var expectedTokens = []string{"#DocStringSeparator", "#Other"} + if line.IsEof() { + err = &parseError{ + msg: fmt.Sprintf("unexpected end of file, expected: %s", strings.Join(expectedTokens, ", ")), + loc: &Location{Line: line.LineNumber, Column: 0}, + } + } else { + err = &parseError{ + msg: fmt.Sprintf("expected: %s, got '%s'", strings.Join(expectedTokens, ", "), line.LineText), + loc: &Location{Line: line.LineNumber, Column: line.Indent() + 1}, + } + } + // if (ctxt.p.stopAtFirstError) throw error; + //ctxt.addError(err) + return 36, err +} + +// GherkinDocument:0>Feature:3>Rule:2>ScenarioDefinition:1>Scenario:2>Step:1>StepArg:0>__alt0:0>DataTableAndMaybeDocString:1>DocString:2>#DocStringSeparator:0 +func (ctxt *parseContext) matchAt37(line *Line) (newState int, err error) { + if ok, token, err := ctxt.matchEOF(line); ok { + ctxt.endRule(RuleTypeDocString) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.endRule(RuleTypeRule) + ctxt.endRule(RuleTypeFeature) + ctxt.build(token) + return 42, err + } + if ok, token, err := ctxt.matchStepLine(line); ok { + ctxt.endRule(RuleTypeDocString) + ctxt.endRule(RuleTypeStep) + ctxt.startRule(RuleTypeStep) + ctxt.build(token) + return 34, err + } + if ok, token, err := ctxt.matchTagLine(line); ok { + if ctxt.lookahead1(line) { + ctxt.endRule(RuleTypeDocString) + ctxt.endRule(RuleTypeStep) + ctxt.startRule(RuleTypeExamplesDefinition) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 38, err + } + } + if ok, token, err := ctxt.matchTagLine(line); ok { + if ctxt.lookahead0(line) { + ctxt.endRule(RuleTypeDocString) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 31, err + } + } + if ok, token, err := ctxt.matchTagLine(line); ok { + ctxt.endRule(RuleTypeDocString) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.endRule(RuleTypeRule) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 22, err + } + if ok, token, err := ctxt.matchExamplesLine(line); ok { + ctxt.endRule(RuleTypeDocString) + ctxt.endRule(RuleTypeStep) + ctxt.startRule(RuleTypeExamplesDefinition) + ctxt.startRule(RuleTypeExamples) + ctxt.build(token) + return 39, err + } + if ok, token, err := ctxt.matchScenarioLine(line); ok { + ctxt.endRule(RuleTypeDocString) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenario) + ctxt.build(token) + return 32, err + } + if ok, token, err := ctxt.matchRuleLine(line); ok { + ctxt.endRule(RuleTypeDocString) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.endRule(RuleTypeRule) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.build(token) + return 23, err + } + if ok, token, err := ctxt.matchComment(line); ok { + ctxt.build(token) + return 37, err + } + if ok, token, err := ctxt.matchEmpty(line); ok { + ctxt.build(token) + return 37, err + } + + // var stateComment = "State: 37 - GherkinDocument:0>Feature:3>Rule:2>ScenarioDefinition:1>Scenario:2>Step:1>StepArg:0>__alt0:0>DataTableAndMaybeDocString:1>DocString:2>#DocStringSeparator:0" + var expectedTokens = []string{"#EOF", "#StepLine", "#TagLine", "#ExamplesLine", "#ScenarioLine", "#RuleLine", "#Comment", "#Empty"} + if line.IsEof() { + err = &parseError{ + msg: fmt.Sprintf("unexpected end of file, expected: %s", strings.Join(expectedTokens, ", ")), + loc: &Location{Line: line.LineNumber, Column: 0}, + } + } else { + err = &parseError{ + msg: fmt.Sprintf("expected: %s, got '%s'", strings.Join(expectedTokens, ", "), line.LineText), + loc: &Location{Line: line.LineNumber, Column: line.Indent() + 1}, + } + } + // if (ctxt.p.stopAtFirstError) throw error; + //ctxt.addError(err) + return 37, err +} + +// GherkinDocument:0>Feature:3>Rule:2>ScenarioDefinition:1>Scenario:3>ExamplesDefinition:0>Tags:0>#TagLine:0 +func (ctxt *parseContext) matchAt38(line *Line) (newState int, err error) { + if ok, token, err := ctxt.matchTagLine(line); ok { + ctxt.build(token) + return 38, err + } + if ok, token, err := ctxt.matchExamplesLine(line); ok { + ctxt.endRule(RuleTypeTags) + ctxt.startRule(RuleTypeExamples) + ctxt.build(token) + return 39, err + } + if ok, token, err := ctxt.matchComment(line); ok { + ctxt.build(token) + return 38, err + } + if ok, token, err := ctxt.matchEmpty(line); ok { + ctxt.build(token) + return 38, err + } + + // var stateComment = "State: 38 - GherkinDocument:0>Feature:3>Rule:2>ScenarioDefinition:1>Scenario:3>ExamplesDefinition:0>Tags:0>#TagLine:0" + var expectedTokens = []string{"#TagLine", "#ExamplesLine", "#Comment", "#Empty"} + if line.IsEof() { + err = &parseError{ + msg: fmt.Sprintf("unexpected end of file, expected: %s", strings.Join(expectedTokens, ", ")), + loc: &Location{Line: line.LineNumber, Column: 0}, + } + } else { + err = &parseError{ + msg: fmt.Sprintf("expected: %s, got '%s'", strings.Join(expectedTokens, ", "), line.LineText), + loc: &Location{Line: line.LineNumber, Column: line.Indent() + 1}, + } + } + // if (ctxt.p.stopAtFirstError) throw error; + //ctxt.addError(err) + return 38, err +} + +// GherkinDocument:0>Feature:3>Rule:2>ScenarioDefinition:1>Scenario:3>ExamplesDefinition:1>Examples:0>#ExamplesLine:0 +func (ctxt *parseContext) matchAt39(line *Line) (newState int, err error) { + if ok, token, err := ctxt.matchEOF(line); ok { + ctxt.endRule(RuleTypeExamples) + ctxt.endRule(RuleTypeExamplesDefinition) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.endRule(RuleTypeRule) + ctxt.endRule(RuleTypeFeature) + ctxt.build(token) + return 42, err + } + if ok, token, err := ctxt.matchEmpty(line); ok { + ctxt.build(token) + return 39, err + } + if ok, token, err := ctxt.matchComment(line); ok { + ctxt.startRule(RuleTypeDescription) + ctxt.build(token) + return 40, err + } + if ok, token, err := ctxt.matchTableRow(line); ok { + ctxt.startRule(RuleTypeExamplesTable) + ctxt.build(token) + return 41, err + } + if ok, token, err := ctxt.matchTagLine(line); ok { + if ctxt.lookahead1(line) { + ctxt.endRule(RuleTypeExamples) + ctxt.endRule(RuleTypeExamplesDefinition) + ctxt.startRule(RuleTypeExamplesDefinition) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 38, err + } + } + if ok, token, err := ctxt.matchTagLine(line); ok { + if ctxt.lookahead0(line) { + ctxt.endRule(RuleTypeExamples) + ctxt.endRule(RuleTypeExamplesDefinition) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 31, err + } + } + if ok, token, err := ctxt.matchTagLine(line); ok { + ctxt.endRule(RuleTypeExamples) + ctxt.endRule(RuleTypeExamplesDefinition) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.endRule(RuleTypeRule) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 22, err + } + if ok, token, err := ctxt.matchExamplesLine(line); ok { + ctxt.endRule(RuleTypeExamples) + ctxt.endRule(RuleTypeExamplesDefinition) + ctxt.startRule(RuleTypeExamplesDefinition) + ctxt.startRule(RuleTypeExamples) + ctxt.build(token) + return 39, err + } + if ok, token, err := ctxt.matchScenarioLine(line); ok { + ctxt.endRule(RuleTypeExamples) + ctxt.endRule(RuleTypeExamplesDefinition) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenario) + ctxt.build(token) + return 32, err + } + if ok, token, err := ctxt.matchRuleLine(line); ok { + ctxt.endRule(RuleTypeExamples) + ctxt.endRule(RuleTypeExamplesDefinition) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.endRule(RuleTypeRule) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.build(token) + return 23, err + } + if ok, token, err := ctxt.matchOther(line); ok { + ctxt.startRule(RuleTypeDescription) + ctxt.build(token) + return 40, err + } + + // var stateComment = "State: 39 - GherkinDocument:0>Feature:3>Rule:2>ScenarioDefinition:1>Scenario:3>ExamplesDefinition:1>Examples:0>#ExamplesLine:0" + var expectedTokens = []string{"#EOF", "#Empty", "#Comment", "#TableRow", "#TagLine", "#ExamplesLine", "#ScenarioLine", "#RuleLine", "#Other"} + if line.IsEof() { + err = &parseError{ + msg: fmt.Sprintf("unexpected end of file, expected: %s", strings.Join(expectedTokens, ", ")), + loc: &Location{Line: line.LineNumber, Column: 0}, + } + } else { + err = &parseError{ + msg: fmt.Sprintf("expected: %s, got '%s'", strings.Join(expectedTokens, ", "), line.LineText), + loc: &Location{Line: line.LineNumber, Column: line.Indent() + 1}, + } + } + // if (ctxt.p.stopAtFirstError) throw error; + //ctxt.addError(err) + return 39, err +} + +// GherkinDocument:0>Feature:3>Rule:2>ScenarioDefinition:1>Scenario:3>ExamplesDefinition:1>Examples:1>DescriptionHelper:1>Description:0>__alt1:0>#Other:0 +func (ctxt *parseContext) matchAt40(line *Line) (newState int, err error) { + if ok, token, err := ctxt.matchEOF(line); ok { + ctxt.endRule(RuleTypeDescription) + ctxt.endRule(RuleTypeExamples) + ctxt.endRule(RuleTypeExamplesDefinition) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.endRule(RuleTypeRule) + ctxt.endRule(RuleTypeFeature) + ctxt.build(token) + return 42, err + } + if ok, token, err := ctxt.matchComment(line); ok { + ctxt.build(token) + return 40, err + } + if ok, token, err := ctxt.matchTableRow(line); ok { + ctxt.endRule(RuleTypeDescription) + ctxt.startRule(RuleTypeExamplesTable) + ctxt.build(token) + return 41, err + } + if ok, token, err := ctxt.matchTagLine(line); ok { + if ctxt.lookahead1(line) { + ctxt.endRule(RuleTypeDescription) + ctxt.endRule(RuleTypeExamples) + ctxt.endRule(RuleTypeExamplesDefinition) + ctxt.startRule(RuleTypeExamplesDefinition) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 38, err + } + } + if ok, token, err := ctxt.matchTagLine(line); ok { + if ctxt.lookahead0(line) { + ctxt.endRule(RuleTypeDescription) + ctxt.endRule(RuleTypeExamples) + ctxt.endRule(RuleTypeExamplesDefinition) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 31, err + } + } + if ok, token, err := ctxt.matchTagLine(line); ok { + ctxt.endRule(RuleTypeDescription) + ctxt.endRule(RuleTypeExamples) + ctxt.endRule(RuleTypeExamplesDefinition) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.endRule(RuleTypeRule) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 22, err + } + if ok, token, err := ctxt.matchExamplesLine(line); ok { + ctxt.endRule(RuleTypeDescription) + ctxt.endRule(RuleTypeExamples) + ctxt.endRule(RuleTypeExamplesDefinition) + ctxt.startRule(RuleTypeExamplesDefinition) + ctxt.startRule(RuleTypeExamples) + ctxt.build(token) + return 39, err + } + if ok, token, err := ctxt.matchScenarioLine(line); ok { + ctxt.endRule(RuleTypeDescription) + ctxt.endRule(RuleTypeExamples) + ctxt.endRule(RuleTypeExamplesDefinition) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenario) + ctxt.build(token) + return 32, err + } + if ok, token, err := ctxt.matchRuleLine(line); ok { + ctxt.endRule(RuleTypeDescription) + ctxt.endRule(RuleTypeExamples) + ctxt.endRule(RuleTypeExamplesDefinition) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.endRule(RuleTypeRule) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.build(token) + return 23, err + } + if ok, token, err := ctxt.matchOther(line); ok { + ctxt.build(token) + return 40, err + } + + // var stateComment = "State: 40 - GherkinDocument:0>Feature:3>Rule:2>ScenarioDefinition:1>Scenario:3>ExamplesDefinition:1>Examples:1>DescriptionHelper:1>Description:0>__alt1:0>#Other:0" + var expectedTokens = []string{"#EOF", "#Comment", "#TableRow", "#TagLine", "#ExamplesLine", "#ScenarioLine", "#RuleLine", "#Other"} + if line.IsEof() { + err = &parseError{ + msg: fmt.Sprintf("unexpected end of file, expected: %s", strings.Join(expectedTokens, ", ")), + loc: &Location{Line: line.LineNumber, Column: 0}, + } + } else { + err = &parseError{ + msg: fmt.Sprintf("expected: %s, got '%s'", strings.Join(expectedTokens, ", "), line.LineText), + loc: &Location{Line: line.LineNumber, Column: line.Indent() + 1}, + } + } + // if (ctxt.p.stopAtFirstError) throw error; + //ctxt.addError(err) + return 40, err +} + +// GherkinDocument:0>Feature:3>Rule:2>ScenarioDefinition:1>Scenario:3>ExamplesDefinition:1>Examples:2>ExamplesTable:0>#TableRow:0 +func (ctxt *parseContext) matchAt41(line *Line) (newState int, err error) { + if ok, token, err := ctxt.matchEOF(line); ok { + ctxt.endRule(RuleTypeExamplesTable) + ctxt.endRule(RuleTypeExamples) + ctxt.endRule(RuleTypeExamplesDefinition) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.endRule(RuleTypeRule) + ctxt.endRule(RuleTypeFeature) + ctxt.build(token) + return 42, err + } + if ok, token, err := ctxt.matchTableRow(line); ok { + ctxt.build(token) + return 41, err + } + if ok, token, err := ctxt.matchTagLine(line); ok { + if ctxt.lookahead1(line) { + ctxt.endRule(RuleTypeExamplesTable) + ctxt.endRule(RuleTypeExamples) + ctxt.endRule(RuleTypeExamplesDefinition) + ctxt.startRule(RuleTypeExamplesDefinition) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 38, err + } + } + if ok, token, err := ctxt.matchTagLine(line); ok { + if ctxt.lookahead0(line) { + ctxt.endRule(RuleTypeExamplesTable) + ctxt.endRule(RuleTypeExamples) + ctxt.endRule(RuleTypeExamplesDefinition) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 31, err + } + } + if ok, token, err := ctxt.matchTagLine(line); ok { + ctxt.endRule(RuleTypeExamplesTable) + ctxt.endRule(RuleTypeExamples) + ctxt.endRule(RuleTypeExamplesDefinition) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.endRule(RuleTypeRule) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 22, err + } + if ok, token, err := ctxt.matchExamplesLine(line); ok { + ctxt.endRule(RuleTypeExamplesTable) + ctxt.endRule(RuleTypeExamples) + ctxt.endRule(RuleTypeExamplesDefinition) + ctxt.startRule(RuleTypeExamplesDefinition) + ctxt.startRule(RuleTypeExamples) + ctxt.build(token) + return 39, err + } + if ok, token, err := ctxt.matchScenarioLine(line); ok { + ctxt.endRule(RuleTypeExamplesTable) + ctxt.endRule(RuleTypeExamples) + ctxt.endRule(RuleTypeExamplesDefinition) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenario) + ctxt.build(token) + return 32, err + } + if ok, token, err := ctxt.matchRuleLine(line); ok { + ctxt.endRule(RuleTypeExamplesTable) + ctxt.endRule(RuleTypeExamples) + ctxt.endRule(RuleTypeExamplesDefinition) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.endRule(RuleTypeRule) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.build(token) + return 23, err + } + if ok, token, err := ctxt.matchComment(line); ok { + ctxt.build(token) + return 41, err + } + if ok, token, err := ctxt.matchEmpty(line); ok { + ctxt.build(token) + return 41, err + } + + // var stateComment = "State: 41 - GherkinDocument:0>Feature:3>Rule:2>ScenarioDefinition:1>Scenario:3>ExamplesDefinition:1>Examples:2>ExamplesTable:0>#TableRow:0" + var expectedTokens = []string{"#EOF", "#TableRow", "#TagLine", "#ExamplesLine", "#ScenarioLine", "#RuleLine", "#Comment", "#Empty"} + if line.IsEof() { + err = &parseError{ + msg: fmt.Sprintf("unexpected end of file, expected: %s", strings.Join(expectedTokens, ", ")), + loc: &Location{Line: line.LineNumber, Column: 0}, + } + } else { + err = &parseError{ + msg: fmt.Sprintf("expected: %s, got '%s'", strings.Join(expectedTokens, ", "), line.LineText), + loc: &Location{Line: line.LineNumber, Column: line.Indent() + 1}, + } + } + // if (ctxt.p.stopAtFirstError) throw error; + //ctxt.addError(err) + return 41, err +} + +// GherkinDocument:0>Feature:3>Rule:2>ScenarioDefinition:1>Scenario:2>Step:1>StepArg:0>__alt0:1>DocStringAndMaybeDataTable:0>DocString:0>#DocStringSeparator:0 +func (ctxt *parseContext) matchAt43(line *Line) (newState int, err error) { + if ok, token, err := ctxt.matchDocStringSeparator(line); ok { + ctxt.build(token) + return 44, err + } + if ok, token, err := ctxt.matchOther(line); ok { + ctxt.build(token) + return 43, err + } + + // var stateComment = "State: 43 - GherkinDocument:0>Feature:3>Rule:2>ScenarioDefinition:1>Scenario:2>Step:1>StepArg:0>__alt0:1>DocStringAndMaybeDataTable:0>DocString:0>#DocStringSeparator:0" + var expectedTokens = []string{"#DocStringSeparator", "#Other"} + if line.IsEof() { + err = &parseError{ + msg: fmt.Sprintf("unexpected end of file, expected: %s", strings.Join(expectedTokens, ", ")), + loc: &Location{Line: line.LineNumber, Column: 0}, + } + } else { + err = &parseError{ + msg: fmt.Sprintf("expected: %s, got '%s'", strings.Join(expectedTokens, ", "), line.LineText), + loc: &Location{Line: line.LineNumber, Column: line.Indent() + 1}, + } + } + // if (ctxt.p.stopAtFirstError) throw error; + //ctxt.addError(err) + return 43, err +} + +// GherkinDocument:0>Feature:3>Rule:2>ScenarioDefinition:1>Scenario:2>Step:1>StepArg:0>__alt0:1>DocStringAndMaybeDataTable:0>DocString:2>#DocStringSeparator:0 +func (ctxt *parseContext) matchAt44(line *Line) (newState int, err error) { + if ok, token, err := ctxt.matchEOF(line); ok { + ctxt.endRule(RuleTypeDocString) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.endRule(RuleTypeRule) + ctxt.endRule(RuleTypeFeature) + ctxt.build(token) + return 42, err + } + if ok, token, err := ctxt.matchTableRow(line); ok { + ctxt.endRule(RuleTypeDocString) + ctxt.startRule(RuleTypeDataTable) + ctxt.build(token) + return 45, err + } + if ok, token, err := ctxt.matchStepLine(line); ok { + ctxt.endRule(RuleTypeDocString) + ctxt.endRule(RuleTypeStep) + ctxt.startRule(RuleTypeStep) + ctxt.build(token) + return 34, err + } + if ok, token, err := ctxt.matchTagLine(line); ok { + if ctxt.lookahead1(line) { + ctxt.endRule(RuleTypeDocString) + ctxt.endRule(RuleTypeStep) + ctxt.startRule(RuleTypeExamplesDefinition) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 38, err + } + } + if ok, token, err := ctxt.matchTagLine(line); ok { + if ctxt.lookahead0(line) { + ctxt.endRule(RuleTypeDocString) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 31, err + } + } + if ok, token, err := ctxt.matchTagLine(line); ok { + ctxt.endRule(RuleTypeDocString) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.endRule(RuleTypeRule) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 22, err + } + if ok, token, err := ctxt.matchExamplesLine(line); ok { + ctxt.endRule(RuleTypeDocString) + ctxt.endRule(RuleTypeStep) + ctxt.startRule(RuleTypeExamplesDefinition) + ctxt.startRule(RuleTypeExamples) + ctxt.build(token) + return 39, err + } + if ok, token, err := ctxt.matchScenarioLine(line); ok { + ctxt.endRule(RuleTypeDocString) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenario) + ctxt.build(token) + return 32, err + } + if ok, token, err := ctxt.matchRuleLine(line); ok { + ctxt.endRule(RuleTypeDocString) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.endRule(RuleTypeRule) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.build(token) + return 23, err + } + if ok, token, err := ctxt.matchComment(line); ok { + ctxt.build(token) + return 44, err + } + if ok, token, err := ctxt.matchEmpty(line); ok { + ctxt.build(token) + return 44, err + } + + // var stateComment = "State: 44 - GherkinDocument:0>Feature:3>Rule:2>ScenarioDefinition:1>Scenario:2>Step:1>StepArg:0>__alt0:1>DocStringAndMaybeDataTable:0>DocString:2>#DocStringSeparator:0" + var expectedTokens = []string{"#EOF", "#TableRow", "#StepLine", "#TagLine", "#ExamplesLine", "#ScenarioLine", "#RuleLine", "#Comment", "#Empty"} + if line.IsEof() { + err = &parseError{ + msg: fmt.Sprintf("unexpected end of file, expected: %s", strings.Join(expectedTokens, ", ")), + loc: &Location{Line: line.LineNumber, Column: 0}, + } + } else { + err = &parseError{ + msg: fmt.Sprintf("expected: %s, got '%s'", strings.Join(expectedTokens, ", "), line.LineText), + loc: &Location{Line: line.LineNumber, Column: line.Indent() + 1}, + } + } + // if (ctxt.p.stopAtFirstError) throw error; + //ctxt.addError(err) + return 44, err +} + +// GherkinDocument:0>Feature:3>Rule:2>ScenarioDefinition:1>Scenario:2>Step:1>StepArg:0>__alt0:1>DocStringAndMaybeDataTable:1>DataTable:0>#TableRow:0 +func (ctxt *parseContext) matchAt45(line *Line) (newState int, err error) { + if ok, token, err := ctxt.matchEOF(line); ok { + ctxt.endRule(RuleTypeDataTable) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.endRule(RuleTypeRule) + ctxt.endRule(RuleTypeFeature) + ctxt.build(token) + return 42, err + } + if ok, token, err := ctxt.matchTableRow(line); ok { + ctxt.build(token) + return 45, err + } + if ok, token, err := ctxt.matchStepLine(line); ok { + ctxt.endRule(RuleTypeDataTable) + ctxt.endRule(RuleTypeStep) + ctxt.startRule(RuleTypeStep) + ctxt.build(token) + return 34, err + } + if ok, token, err := ctxt.matchTagLine(line); ok { + if ctxt.lookahead1(line) { + ctxt.endRule(RuleTypeDataTable) + ctxt.endRule(RuleTypeStep) + ctxt.startRule(RuleTypeExamplesDefinition) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 38, err + } + } + if ok, token, err := ctxt.matchTagLine(line); ok { + if ctxt.lookahead0(line) { + ctxt.endRule(RuleTypeDataTable) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 31, err + } + } + if ok, token, err := ctxt.matchTagLine(line); ok { + ctxt.endRule(RuleTypeDataTable) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.endRule(RuleTypeRule) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 22, err + } + if ok, token, err := ctxt.matchExamplesLine(line); ok { + ctxt.endRule(RuleTypeDataTable) + ctxt.endRule(RuleTypeStep) + ctxt.startRule(RuleTypeExamplesDefinition) + ctxt.startRule(RuleTypeExamples) + ctxt.build(token) + return 39, err + } + if ok, token, err := ctxt.matchScenarioLine(line); ok { + ctxt.endRule(RuleTypeDataTable) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenario) + ctxt.build(token) + return 32, err + } + if ok, token, err := ctxt.matchRuleLine(line); ok { + ctxt.endRule(RuleTypeDataTable) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.endRule(RuleTypeRule) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.build(token) + return 23, err + } + if ok, token, err := ctxt.matchComment(line); ok { + ctxt.build(token) + return 45, err + } + if ok, token, err := ctxt.matchEmpty(line); ok { + ctxt.build(token) + return 45, err + } + + // var stateComment = "State: 45 - GherkinDocument:0>Feature:3>Rule:2>ScenarioDefinition:1>Scenario:2>Step:1>StepArg:0>__alt0:1>DocStringAndMaybeDataTable:1>DataTable:0>#TableRow:0" + var expectedTokens = []string{"#EOF", "#TableRow", "#StepLine", "#TagLine", "#ExamplesLine", "#ScenarioLine", "#RuleLine", "#Comment", "#Empty"} + if line.IsEof() { + err = &parseError{ + msg: fmt.Sprintf("unexpected end of file, expected: %s", strings.Join(expectedTokens, ", ")), + loc: &Location{Line: line.LineNumber, Column: 0}, + } + } else { + err = &parseError{ + msg: fmt.Sprintf("expected: %s, got '%s'", strings.Join(expectedTokens, ", "), line.LineText), + loc: &Location{Line: line.LineNumber, Column: line.Indent() + 1}, + } + } + // if (ctxt.p.stopAtFirstError) throw error; + //ctxt.addError(err) + return 45, err +} + +// GherkinDocument:0>Feature:3>Rule:1>Background:2>Step:1>StepArg:0>__alt0:1>DocStringAndMaybeDataTable:0>DocString:0>#DocStringSeparator:0 +func (ctxt *parseContext) matchAt46(line *Line) (newState int, err error) { + if ok, token, err := ctxt.matchDocStringSeparator(line); ok { + ctxt.build(token) + return 47, err + } + if ok, token, err := ctxt.matchOther(line); ok { + ctxt.build(token) + return 46, err + } + + // var stateComment = "State: 46 - GherkinDocument:0>Feature:3>Rule:1>Background:2>Step:1>StepArg:0>__alt0:1>DocStringAndMaybeDataTable:0>DocString:0>#DocStringSeparator:0" + var expectedTokens = []string{"#DocStringSeparator", "#Other"} + if line.IsEof() { + err = &parseError{ + msg: fmt.Sprintf("unexpected end of file, expected: %s", strings.Join(expectedTokens, ", ")), + loc: &Location{Line: line.LineNumber, Column: 0}, + } + } else { + err = &parseError{ + msg: fmt.Sprintf("expected: %s, got '%s'", strings.Join(expectedTokens, ", "), line.LineText), + loc: &Location{Line: line.LineNumber, Column: line.Indent() + 1}, + } + } + // if (ctxt.p.stopAtFirstError) throw error; + //ctxt.addError(err) + return 46, err +} + +// GherkinDocument:0>Feature:3>Rule:1>Background:2>Step:1>StepArg:0>__alt0:1>DocStringAndMaybeDataTable:0>DocString:2>#DocStringSeparator:0 +func (ctxt *parseContext) matchAt47(line *Line) (newState int, err error) { + if ok, token, err := ctxt.matchEOF(line); ok { + ctxt.endRule(RuleTypeDocString) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeBackground) + ctxt.endRule(RuleTypeRule) + ctxt.endRule(RuleTypeFeature) + ctxt.build(token) + return 42, err + } + if ok, token, err := ctxt.matchTableRow(line); ok { + ctxt.endRule(RuleTypeDocString) + ctxt.startRule(RuleTypeDataTable) + ctxt.build(token) + return 48, err + } + if ok, token, err := ctxt.matchStepLine(line); ok { + ctxt.endRule(RuleTypeDocString) + ctxt.endRule(RuleTypeStep) + ctxt.startRule(RuleTypeStep) + ctxt.build(token) + return 27, err + } + if ok, token, err := ctxt.matchTagLine(line); ok { + if ctxt.lookahead0(line) { + ctxt.endRule(RuleTypeDocString) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeBackground) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 31, err + } + } + if ok, token, err := ctxt.matchTagLine(line); ok { + ctxt.endRule(RuleTypeDocString) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeBackground) + ctxt.endRule(RuleTypeRule) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 22, err + } + if ok, token, err := ctxt.matchScenarioLine(line); ok { + ctxt.endRule(RuleTypeDocString) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeBackground) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenario) + ctxt.build(token) + return 32, err + } + if ok, token, err := ctxt.matchRuleLine(line); ok { + ctxt.endRule(RuleTypeDocString) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeBackground) + ctxt.endRule(RuleTypeRule) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.build(token) + return 23, err + } + if ok, token, err := ctxt.matchComment(line); ok { + ctxt.build(token) + return 47, err + } + if ok, token, err := ctxt.matchEmpty(line); ok { + ctxt.build(token) + return 47, err + } + + // var stateComment = "State: 47 - GherkinDocument:0>Feature:3>Rule:1>Background:2>Step:1>StepArg:0>__alt0:1>DocStringAndMaybeDataTable:0>DocString:2>#DocStringSeparator:0" + var expectedTokens = []string{"#EOF", "#TableRow", "#StepLine", "#TagLine", "#ScenarioLine", "#RuleLine", "#Comment", "#Empty"} + if line.IsEof() { + err = &parseError{ + msg: fmt.Sprintf("unexpected end of file, expected: %s", strings.Join(expectedTokens, ", ")), + loc: &Location{Line: line.LineNumber, Column: 0}, + } + } else { + err = &parseError{ + msg: fmt.Sprintf("expected: %s, got '%s'", strings.Join(expectedTokens, ", "), line.LineText), + loc: &Location{Line: line.LineNumber, Column: line.Indent() + 1}, + } + } + // if (ctxt.p.stopAtFirstError) throw error; + //ctxt.addError(err) + return 47, err +} + +// GherkinDocument:0>Feature:3>Rule:1>Background:2>Step:1>StepArg:0>__alt0:1>DocStringAndMaybeDataTable:1>DataTable:0>#TableRow:0 +func (ctxt *parseContext) matchAt48(line *Line) (newState int, err error) { + if ok, token, err := ctxt.matchEOF(line); ok { + ctxt.endRule(RuleTypeDataTable) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeBackground) + ctxt.endRule(RuleTypeRule) + ctxt.endRule(RuleTypeFeature) + ctxt.build(token) + return 42, err + } + if ok, token, err := ctxt.matchTableRow(line); ok { + ctxt.build(token) + return 48, err + } + if ok, token, err := ctxt.matchStepLine(line); ok { + ctxt.endRule(RuleTypeDataTable) + ctxt.endRule(RuleTypeStep) + ctxt.startRule(RuleTypeStep) + ctxt.build(token) + return 27, err + } + if ok, token, err := ctxt.matchTagLine(line); ok { + if ctxt.lookahead0(line) { + ctxt.endRule(RuleTypeDataTable) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeBackground) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 31, err + } + } + if ok, token, err := ctxt.matchTagLine(line); ok { + ctxt.endRule(RuleTypeDataTable) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeBackground) + ctxt.endRule(RuleTypeRule) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 22, err + } + if ok, token, err := ctxt.matchScenarioLine(line); ok { + ctxt.endRule(RuleTypeDataTable) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeBackground) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenario) + ctxt.build(token) + return 32, err + } + if ok, token, err := ctxt.matchRuleLine(line); ok { + ctxt.endRule(RuleTypeDataTable) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeBackground) + ctxt.endRule(RuleTypeRule) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.build(token) + return 23, err + } + if ok, token, err := ctxt.matchComment(line); ok { + ctxt.build(token) + return 48, err + } + if ok, token, err := ctxt.matchEmpty(line); ok { + ctxt.build(token) + return 48, err + } + + // var stateComment = "State: 48 - GherkinDocument:0>Feature:3>Rule:1>Background:2>Step:1>StepArg:0>__alt0:1>DocStringAndMaybeDataTable:1>DataTable:0>#TableRow:0" + var expectedTokens = []string{"#EOF", "#TableRow", "#StepLine", "#TagLine", "#ScenarioLine", "#RuleLine", "#Comment", "#Empty"} + if line.IsEof() { + err = &parseError{ + msg: fmt.Sprintf("unexpected end of file, expected: %s", strings.Join(expectedTokens, ", ")), + loc: &Location{Line: line.LineNumber, Column: 0}, + } + } else { + err = &parseError{ + msg: fmt.Sprintf("expected: %s, got '%s'", strings.Join(expectedTokens, ", "), line.LineText), + loc: &Location{Line: line.LineNumber, Column: line.Indent() + 1}, + } + } + // if (ctxt.p.stopAtFirstError) throw error; + //ctxt.addError(err) + return 48, err +} + +// GherkinDocument:0>Feature:2>ScenarioDefinition:1>Scenario:2>Step:1>StepArg:0>__alt0:1>DocStringAndMaybeDataTable:0>DocString:0>#DocStringSeparator:0 +func (ctxt *parseContext) matchAt49(line *Line) (newState int, err error) { + if ok, token, err := ctxt.matchDocStringSeparator(line); ok { + ctxt.build(token) + return 50, err + } + if ok, token, err := ctxt.matchOther(line); ok { + ctxt.build(token) + return 49, err + } + + // var stateComment = "State: 49 - GherkinDocument:0>Feature:2>ScenarioDefinition:1>Scenario:2>Step:1>StepArg:0>__alt0:1>DocStringAndMaybeDataTable:0>DocString:0>#DocStringSeparator:0" + var expectedTokens = []string{"#DocStringSeparator", "#Other"} + if line.IsEof() { + err = &parseError{ + msg: fmt.Sprintf("unexpected end of file, expected: %s", strings.Join(expectedTokens, ", ")), + loc: &Location{Line: line.LineNumber, Column: 0}, + } + } else { + err = &parseError{ + msg: fmt.Sprintf("expected: %s, got '%s'", strings.Join(expectedTokens, ", "), line.LineText), + loc: &Location{Line: line.LineNumber, Column: line.Indent() + 1}, + } + } + // if (ctxt.p.stopAtFirstError) throw error; + //ctxt.addError(err) + return 49, err +} + +// GherkinDocument:0>Feature:2>ScenarioDefinition:1>Scenario:2>Step:1>StepArg:0>__alt0:1>DocStringAndMaybeDataTable:0>DocString:2>#DocStringSeparator:0 +func (ctxt *parseContext) matchAt50(line *Line) (newState int, err error) { + if ok, token, err := ctxt.matchEOF(line); ok { + ctxt.endRule(RuleTypeDocString) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.endRule(RuleTypeFeature) + ctxt.build(token) + return 42, err + } + if ok, token, err := ctxt.matchTableRow(line); ok { + ctxt.endRule(RuleTypeDocString) + ctxt.startRule(RuleTypeDataTable) + ctxt.build(token) + return 51, err + } + if ok, token, err := ctxt.matchStepLine(line); ok { + ctxt.endRule(RuleTypeDocString) + ctxt.endRule(RuleTypeStep) + ctxt.startRule(RuleTypeStep) + ctxt.build(token) + return 14, err + } + if ok, token, err := ctxt.matchTagLine(line); ok { + if ctxt.lookahead1(line) { + ctxt.endRule(RuleTypeDocString) + ctxt.endRule(RuleTypeStep) + ctxt.startRule(RuleTypeExamplesDefinition) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 18, err + } + } + if ok, token, err := ctxt.matchTagLine(line); ok { + if ctxt.lookahead0(line) { + ctxt.endRule(RuleTypeDocString) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 11, err + } + } + if ok, token, err := ctxt.matchTagLine(line); ok { + ctxt.endRule(RuleTypeDocString) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 22, err + } + if ok, token, err := ctxt.matchExamplesLine(line); ok { + ctxt.endRule(RuleTypeDocString) + ctxt.endRule(RuleTypeStep) + ctxt.startRule(RuleTypeExamplesDefinition) + ctxt.startRule(RuleTypeExamples) + ctxt.build(token) + return 19, err + } + if ok, token, err := ctxt.matchScenarioLine(line); ok { + ctxt.endRule(RuleTypeDocString) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenario) + ctxt.build(token) + return 12, err + } + if ok, token, err := ctxt.matchRuleLine(line); ok { + ctxt.endRule(RuleTypeDocString) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.build(token) + return 23, err + } + if ok, token, err := ctxt.matchComment(line); ok { + ctxt.build(token) + return 50, err + } + if ok, token, err := ctxt.matchEmpty(line); ok { + ctxt.build(token) + return 50, err + } + + // var stateComment = "State: 50 - GherkinDocument:0>Feature:2>ScenarioDefinition:1>Scenario:2>Step:1>StepArg:0>__alt0:1>DocStringAndMaybeDataTable:0>DocString:2>#DocStringSeparator:0" + var expectedTokens = []string{"#EOF", "#TableRow", "#StepLine", "#TagLine", "#ExamplesLine", "#ScenarioLine", "#RuleLine", "#Comment", "#Empty"} + if line.IsEof() { + err = &parseError{ + msg: fmt.Sprintf("unexpected end of file, expected: %s", strings.Join(expectedTokens, ", ")), + loc: &Location{Line: line.LineNumber, Column: 0}, + } + } else { + err = &parseError{ + msg: fmt.Sprintf("expected: %s, got '%s'", strings.Join(expectedTokens, ", "), line.LineText), + loc: &Location{Line: line.LineNumber, Column: line.Indent() + 1}, + } + } + // if (ctxt.p.stopAtFirstError) throw error; + //ctxt.addError(err) + return 50, err +} + +// GherkinDocument:0>Feature:2>ScenarioDefinition:1>Scenario:2>Step:1>StepArg:0>__alt0:1>DocStringAndMaybeDataTable:1>DataTable:0>#TableRow:0 +func (ctxt *parseContext) matchAt51(line *Line) (newState int, err error) { + if ok, token, err := ctxt.matchEOF(line); ok { + ctxt.endRule(RuleTypeDataTable) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.endRule(RuleTypeFeature) + ctxt.build(token) + return 42, err + } + if ok, token, err := ctxt.matchTableRow(line); ok { + ctxt.build(token) + return 51, err + } + if ok, token, err := ctxt.matchStepLine(line); ok { + ctxt.endRule(RuleTypeDataTable) + ctxt.endRule(RuleTypeStep) + ctxt.startRule(RuleTypeStep) + ctxt.build(token) + return 14, err + } + if ok, token, err := ctxt.matchTagLine(line); ok { + if ctxt.lookahead1(line) { + ctxt.endRule(RuleTypeDataTable) + ctxt.endRule(RuleTypeStep) + ctxt.startRule(RuleTypeExamplesDefinition) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 18, err + } + } + if ok, token, err := ctxt.matchTagLine(line); ok { + if ctxt.lookahead0(line) { + ctxt.endRule(RuleTypeDataTable) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 11, err + } + } + if ok, token, err := ctxt.matchTagLine(line); ok { + ctxt.endRule(RuleTypeDataTable) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 22, err + } + if ok, token, err := ctxt.matchExamplesLine(line); ok { + ctxt.endRule(RuleTypeDataTable) + ctxt.endRule(RuleTypeStep) + ctxt.startRule(RuleTypeExamplesDefinition) + ctxt.startRule(RuleTypeExamples) + ctxt.build(token) + return 19, err + } + if ok, token, err := ctxt.matchScenarioLine(line); ok { + ctxt.endRule(RuleTypeDataTable) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenario) + ctxt.build(token) + return 12, err + } + if ok, token, err := ctxt.matchRuleLine(line); ok { + ctxt.endRule(RuleTypeDataTable) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeScenario) + ctxt.endRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.build(token) + return 23, err + } + if ok, token, err := ctxt.matchComment(line); ok { + ctxt.build(token) + return 51, err + } + if ok, token, err := ctxt.matchEmpty(line); ok { + ctxt.build(token) + return 51, err + } + + // var stateComment = "State: 51 - GherkinDocument:0>Feature:2>ScenarioDefinition:1>Scenario:2>Step:1>StepArg:0>__alt0:1>DocStringAndMaybeDataTable:1>DataTable:0>#TableRow:0" + var expectedTokens = []string{"#EOF", "#TableRow", "#StepLine", "#TagLine", "#ExamplesLine", "#ScenarioLine", "#RuleLine", "#Comment", "#Empty"} + if line.IsEof() { + err = &parseError{ + msg: fmt.Sprintf("unexpected end of file, expected: %s", strings.Join(expectedTokens, ", ")), + loc: &Location{Line: line.LineNumber, Column: 0}, + } + } else { + err = &parseError{ + msg: fmt.Sprintf("expected: %s, got '%s'", strings.Join(expectedTokens, ", "), line.LineText), + loc: &Location{Line: line.LineNumber, Column: line.Indent() + 1}, + } + } + // if (ctxt.p.stopAtFirstError) throw error; + //ctxt.addError(err) + return 51, err +} + +// GherkinDocument:0>Feature:1>Background:2>Step:1>StepArg:0>__alt0:1>DocStringAndMaybeDataTable:0>DocString:0>#DocStringSeparator:0 +func (ctxt *parseContext) matchAt52(line *Line) (newState int, err error) { + if ok, token, err := ctxt.matchDocStringSeparator(line); ok { + ctxt.build(token) + return 53, err + } + if ok, token, err := ctxt.matchOther(line); ok { + ctxt.build(token) + return 52, err + } + + // var stateComment = "State: 52 - GherkinDocument:0>Feature:1>Background:2>Step:1>StepArg:0>__alt0:1>DocStringAndMaybeDataTable:0>DocString:0>#DocStringSeparator:0" + var expectedTokens = []string{"#DocStringSeparator", "#Other"} + if line.IsEof() { + err = &parseError{ + msg: fmt.Sprintf("unexpected end of file, expected: %s", strings.Join(expectedTokens, ", ")), + loc: &Location{Line: line.LineNumber, Column: 0}, + } + } else { + err = &parseError{ + msg: fmt.Sprintf("expected: %s, got '%s'", strings.Join(expectedTokens, ", "), line.LineText), + loc: &Location{Line: line.LineNumber, Column: line.Indent() + 1}, + } + } + // if (ctxt.p.stopAtFirstError) throw error; + //ctxt.addError(err) + return 52, err +} + +// GherkinDocument:0>Feature:1>Background:2>Step:1>StepArg:0>__alt0:1>DocStringAndMaybeDataTable:0>DocString:2>#DocStringSeparator:0 +func (ctxt *parseContext) matchAt53(line *Line) (newState int, err error) { + if ok, token, err := ctxt.matchEOF(line); ok { + ctxt.endRule(RuleTypeDocString) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeBackground) + ctxt.endRule(RuleTypeFeature) + ctxt.build(token) + return 42, err + } + if ok, token, err := ctxt.matchTableRow(line); ok { + ctxt.endRule(RuleTypeDocString) + ctxt.startRule(RuleTypeDataTable) + ctxt.build(token) + return 54, err + } + if ok, token, err := ctxt.matchStepLine(line); ok { + ctxt.endRule(RuleTypeDocString) + ctxt.endRule(RuleTypeStep) + ctxt.startRule(RuleTypeStep) + ctxt.build(token) + return 7, err + } + if ok, token, err := ctxt.matchTagLine(line); ok { + if ctxt.lookahead0(line) { + ctxt.endRule(RuleTypeDocString) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeBackground) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 11, err + } + } + if ok, token, err := ctxt.matchTagLine(line); ok { + ctxt.endRule(RuleTypeDocString) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeBackground) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 22, err + } + if ok, token, err := ctxt.matchScenarioLine(line); ok { + ctxt.endRule(RuleTypeDocString) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeBackground) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenario) + ctxt.build(token) + return 12, err + } + if ok, token, err := ctxt.matchRuleLine(line); ok { + ctxt.endRule(RuleTypeDocString) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeBackground) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.build(token) + return 23, err + } + if ok, token, err := ctxt.matchComment(line); ok { + ctxt.build(token) + return 53, err + } + if ok, token, err := ctxt.matchEmpty(line); ok { + ctxt.build(token) + return 53, err + } + + // var stateComment = "State: 53 - GherkinDocument:0>Feature:1>Background:2>Step:1>StepArg:0>__alt0:1>DocStringAndMaybeDataTable:0>DocString:2>#DocStringSeparator:0" + var expectedTokens = []string{"#EOF", "#TableRow", "#StepLine", "#TagLine", "#ScenarioLine", "#RuleLine", "#Comment", "#Empty"} + if line.IsEof() { + err = &parseError{ + msg: fmt.Sprintf("unexpected end of file, expected: %s", strings.Join(expectedTokens, ", ")), + loc: &Location{Line: line.LineNumber, Column: 0}, + } + } else { + err = &parseError{ + msg: fmt.Sprintf("expected: %s, got '%s'", strings.Join(expectedTokens, ", "), line.LineText), + loc: &Location{Line: line.LineNumber, Column: line.Indent() + 1}, + } + } + // if (ctxt.p.stopAtFirstError) throw error; + //ctxt.addError(err) + return 53, err +} + +// GherkinDocument:0>Feature:1>Background:2>Step:1>StepArg:0>__alt0:1>DocStringAndMaybeDataTable:1>DataTable:0>#TableRow:0 +func (ctxt *parseContext) matchAt54(line *Line) (newState int, err error) { + if ok, token, err := ctxt.matchEOF(line); ok { + ctxt.endRule(RuleTypeDataTable) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeBackground) + ctxt.endRule(RuleTypeFeature) + ctxt.build(token) + return 42, err + } + if ok, token, err := ctxt.matchTableRow(line); ok { + ctxt.build(token) + return 54, err + } + if ok, token, err := ctxt.matchStepLine(line); ok { + ctxt.endRule(RuleTypeDataTable) + ctxt.endRule(RuleTypeStep) + ctxt.startRule(RuleTypeStep) + ctxt.build(token) + return 7, err + } + if ok, token, err := ctxt.matchTagLine(line); ok { + if ctxt.lookahead0(line) { + ctxt.endRule(RuleTypeDataTable) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeBackground) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 11, err + } + } + if ok, token, err := ctxt.matchTagLine(line); ok { + ctxt.endRule(RuleTypeDataTable) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeBackground) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.startRule(RuleTypeTags) + ctxt.build(token) + return 22, err + } + if ok, token, err := ctxt.matchScenarioLine(line); ok { + ctxt.endRule(RuleTypeDataTable) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeBackground) + ctxt.startRule(RuleTypeScenarioDefinition) + ctxt.startRule(RuleTypeScenario) + ctxt.build(token) + return 12, err + } + if ok, token, err := ctxt.matchRuleLine(line); ok { + ctxt.endRule(RuleTypeDataTable) + ctxt.endRule(RuleTypeStep) + ctxt.endRule(RuleTypeBackground) + ctxt.startRule(RuleTypeRule) + ctxt.startRule(RuleTypeRuleHeader) + ctxt.build(token) + return 23, err + } + if ok, token, err := ctxt.matchComment(line); ok { + ctxt.build(token) + return 54, err + } + if ok, token, err := ctxt.matchEmpty(line); ok { + ctxt.build(token) + return 54, err + } + + // var stateComment = "State: 54 - GherkinDocument:0>Feature:1>Background:2>Step:1>StepArg:0>__alt0:1>DocStringAndMaybeDataTable:1>DataTable:0>#TableRow:0" + var expectedTokens = []string{"#EOF", "#TableRow", "#StepLine", "#TagLine", "#ScenarioLine", "#RuleLine", "#Comment", "#Empty"} + if line.IsEof() { + err = &parseError{ + msg: fmt.Sprintf("unexpected end of file, expected: %s", strings.Join(expectedTokens, ", ")), + loc: &Location{Line: line.LineNumber, Column: 0}, + } + } else { + err = &parseError{ + msg: fmt.Sprintf("expected: %s, got '%s'", strings.Join(expectedTokens, ", "), line.LineText), + loc: &Location{Line: line.LineNumber, Column: line.Indent() + 1}, + } + } + // if (ctxt.p.stopAtFirstError) throw error; + //ctxt.addError(err) + return 54, err +} + +type Matcher interface { + MatchEOF(line *Line) (bool, *Token, error) + MatchEmpty(line *Line) (bool, *Token, error) + MatchComment(line *Line) (bool, *Token, error) + MatchTagLine(line *Line) (bool, *Token, error) + MatchFeatureLine(line *Line) (bool, *Token, error) + MatchRuleLine(line *Line) (bool, *Token, error) + MatchBackgroundLine(line *Line) (bool, *Token, error) + MatchScenarioLine(line *Line) (bool, *Token, error) + MatchExamplesLine(line *Line) (bool, *Token, error) + MatchStepLine(line *Line) (bool, *Token, error) + MatchDocStringSeparator(line *Line) (bool, *Token, error) + MatchTableRow(line *Line) (bool, *Token, error) + MatchLanguage(line *Line) (bool, *Token, error) + MatchOther(line *Line) (bool, *Token, error) + Reset() +} + +func (ctxt *parseContext) isMatchEOF(line *Line) bool { + ok, _, _ := ctxt.matchEOF(line) + return ok +} +func (ctxt *parseContext) matchEOF(line *Line) (bool, *Token, error) { + return ctxt.m.MatchEOF(line) +} + +func (ctxt *parseContext) isMatchEmpty(line *Line) bool { + ok, _, _ := ctxt.matchEmpty(line) + return ok +} +func (ctxt *parseContext) matchEmpty(line *Line) (bool, *Token, error) { + if line.IsEof() { + return false, nil, nil + } + return ctxt.m.MatchEmpty(line) +} + +func (ctxt *parseContext) isMatchComment(line *Line) bool { + ok, _, _ := ctxt.matchComment(line) + return ok +} +func (ctxt *parseContext) matchComment(line *Line) (bool, *Token, error) { + if line.IsEof() { + return false, nil, nil + } + return ctxt.m.MatchComment(line) +} + +func (ctxt *parseContext) isMatchTagLine(line *Line) bool { + ok, _, _ := ctxt.matchTagLine(line) + return ok +} +func (ctxt *parseContext) matchTagLine(line *Line) (bool, *Token, error) { + if line.IsEof() { + return false, nil, nil + } + return ctxt.m.MatchTagLine(line) +} + +func (ctxt *parseContext) isMatchFeatureLine(line *Line) bool { + ok, _, _ := ctxt.matchFeatureLine(line) + return ok +} +func (ctxt *parseContext) matchFeatureLine(line *Line) (bool, *Token, error) { + if line.IsEof() { + return false, nil, nil + } + return ctxt.m.MatchFeatureLine(line) +} + +func (ctxt *parseContext) isMatchRuleLine(line *Line) bool { + ok, _, _ := ctxt.matchRuleLine(line) + return ok +} +func (ctxt *parseContext) matchRuleLine(line *Line) (bool, *Token, error) { + if line.IsEof() { + return false, nil, nil + } + return ctxt.m.MatchRuleLine(line) +} + +func (ctxt *parseContext) isMatchBackgroundLine(line *Line) bool { + ok, _, _ := ctxt.matchBackgroundLine(line) + return ok +} +func (ctxt *parseContext) matchBackgroundLine(line *Line) (bool, *Token, error) { + if line.IsEof() { + return false, nil, nil + } + return ctxt.m.MatchBackgroundLine(line) +} + +func (ctxt *parseContext) isMatchScenarioLine(line *Line) bool { + ok, _, _ := ctxt.matchScenarioLine(line) + return ok +} +func (ctxt *parseContext) matchScenarioLine(line *Line) (bool, *Token, error) { + if line.IsEof() { + return false, nil, nil + } + return ctxt.m.MatchScenarioLine(line) +} + +func (ctxt *parseContext) isMatchExamplesLine(line *Line) bool { + ok, _, _ := ctxt.matchExamplesLine(line) + return ok +} +func (ctxt *parseContext) matchExamplesLine(line *Line) (bool, *Token, error) { + if line.IsEof() { + return false, nil, nil + } + return ctxt.m.MatchExamplesLine(line) +} + +func (ctxt *parseContext) isMatchStepLine(line *Line) bool { + ok, _, _ := ctxt.matchStepLine(line) + return ok +} +func (ctxt *parseContext) matchStepLine(line *Line) (bool, *Token, error) { + if line.IsEof() { + return false, nil, nil + } + return ctxt.m.MatchStepLine(line) +} + +func (ctxt *parseContext) isMatchDocStringSeparator(line *Line) bool { + ok, _, _ := ctxt.matchDocStringSeparator(line) + return ok +} +func (ctxt *parseContext) matchDocStringSeparator(line *Line) (bool, *Token, error) { + if line.IsEof() { + return false, nil, nil + } + return ctxt.m.MatchDocStringSeparator(line) +} + +func (ctxt *parseContext) isMatchTableRow(line *Line) bool { + ok, _, _ := ctxt.matchTableRow(line) + return ok +} +func (ctxt *parseContext) matchTableRow(line *Line) (bool, *Token, error) { + if line.IsEof() { + return false, nil, nil + } + return ctxt.m.MatchTableRow(line) +} + +func (ctxt *parseContext) isMatchLanguage(line *Line) bool { + ok, _, _ := ctxt.matchLanguage(line) + return ok +} +func (ctxt *parseContext) matchLanguage(line *Line) (bool, *Token, error) { + if line.IsEof() { + return false, nil, nil + } + return ctxt.m.MatchLanguage(line) +} + +func (ctxt *parseContext) isMatchOther(line *Line) bool { + ok, _, _ := ctxt.matchOther(line) + return ok +} +func (ctxt *parseContext) matchOther(line *Line) (bool, *Token, error) { + if line.IsEof() { + return false, nil, nil + } + return ctxt.m.MatchOther(line) +} + +func (ctxt *parseContext) lookahead0(initialLine *Line) bool { + var queue []*scanResult + var match bool + + for { + line, atEof, err := ctxt.scan() + queue = append(queue, &scanResult{line, atEof, err}) + + if false || ctxt.isMatchScenarioLine(line) { + match = true + break + } + if !(false || ctxt.isMatchEmpty(line) || ctxt.isMatchComment(line) || ctxt.isMatchTagLine(line)) { + break + } + if atEof { + break + } + } + + ctxt.queue = append(ctxt.queue, queue...) + + return match +} + +func (ctxt *parseContext) lookahead1(initialLine *Line) bool { + var queue []*scanResult + var match bool + + for { + line, atEof, err := ctxt.scan() + queue = append(queue, &scanResult{line, atEof, err}) + + if false || ctxt.isMatchExamplesLine(line) { + match = true + break + } + if !(false || ctxt.isMatchEmpty(line) || ctxt.isMatchComment(line) || ctxt.isMatchTagLine(line)) { + break + } + if atEof { + break + } + } + + ctxt.queue = append(ctxt.queue, queue...) + + return match +} diff --git a/vendor/github.com/cucumber/gherkin/go/v42/parser.go.razor b/vendor/github.com/cucumber/gherkin/go/v42/parser.go.razor new file mode 100644 index 0000000000..2e772d8a95 --- /dev/null +++ b/vendor/github.com/cucumber/gherkin/go/v42/parser.go.razor @@ -0,0 +1,313 @@ +@using Berp; +@helper CallProduction(ProductionRule production) +{ + switch(production.Type) + { + case ProductionRuleType.Start: + @:ctxt.startRule(@Raw("RuleType" + production.RuleName.Replace("#", ""))) + break; + case ProductionRuleType.End: + @:ctxt.endRule(@Raw("RuleType" + production.RuleName.Replace("#", ""))) + break; + case ProductionRuleType.Process: + @:ctxt.build(token) + break; + } +} +@helper HandleParserError(IEnumerable expectedTokens, State state) +{ + // var stateComment = "State: @state.Id - @Raw(state.Comment)" + var expectedTokens = []string{"@Raw(string.Join("\", \"", expectedTokens))"} + if line.IsEof() { + err = &parseError{ + msg: fmt.Sprintf("unexpected end of file, expected: %s", strings.Join(expectedTokens, ", ")), + loc: &Location{Line: line.LineNumber, Column: 0}, + } + } else { + err = &parseError{ + msg: fmt.Sprintf("expected: %s, got '%s'", strings.Join(expectedTokens, ", "), line.LineText), + loc: &Location{Line: line.LineNumber, Column: line.Indent() + 1}, + } + } + // if (ctxt.p.stopAtFirstError) throw error; + //ctxt.addError(err) + return @state.Id, err +} +@helper MatchToken(TokenType tokenType) +{ctxt.match@(tokenType)(line)} +@helper IsMatchToken(TokenType tokenType) +{ctxt.isMatch@(tokenType)(line)} +@helper TokenConst(Rule rule) +{@Raw("rule" + rule.Name.Replace("#", "Int"))} +// +// This file is generated. Do not edit! Edit parser.go.razor instead. + +package gherkin + +import ( + "fmt" + "strings" +) + +type TokenType int + +const ( + TokenTypeNone TokenType = iota + @foreach(var rule in Model.RuleSet.TokenRules) +{ @Raw("TokenType" + rule.Name.Replace("#", "")) +} +) + +func tokenTypeForRule(rt RuleType) TokenType { + return TokenTypeNone +} + +func (t TokenType) Name() string { + switch t { + @foreach(var rule in Model.RuleSet.TokenRules) +{ case @Raw("TokenType" + rule.Name.Replace("#", "")): + return "@Raw(rule.Name.Replace("#", ""))" +} + } + return "" +} + +func (t TokenType) RuleType() RuleType { + switch t { + @foreach(var rule in Model.RuleSet.TokenRules) +{ case @Raw("TokenType" + rule.Name.Replace("#", "")): + return @Raw("RuleType" + rule.Name.Replace("#", "")) +} + } + return RuleTypeNone +} + +type RuleType int + +const ( + RuleTypeNone RuleType = iota + @foreach(var rule in Model.RuleSet.Where(r => !r.TempRule)) +{ @Raw("RuleType" + rule.Name.Replace("#", "")) +} +) + +func (t RuleType) IsEOF() bool { + return t == RuleTypeEOF +} +func (t RuleType) Name() string { + switch t { + @foreach(var rule in Model.RuleSet.Where(r => !r.TempRule)) +{ case @Raw("RuleType" + rule.Name.Replace("#", "")): + return "@Raw(rule.Name)" +} + } + return "" +} + +type Location struct { + Line int + Column int +} + +type parseError struct { + msg string + loc *Location +} + +func (a *parseError) Error() string { + return fmt.Sprintf("(%d:%d): %s", a.loc.Line, a.loc.Column, a.msg) +} + +type parseErrors []error + +func (pe parseErrors) Error() string { + var ret = []string{"Parser errors:"} + for i := range pe { + ret = append(ret, pe[i].Error()) + } + return strings.Join(ret, "\n") +} + +func (p *parser) Parse(s Scanner, m Matcher) (err error) { + p.builder.Reset() + m.Reset() + ctxt := &parseContext{p, s, p.builder, m, nil, nil} + var state int + ctxt.startRule(@Raw("RuleType" + @Model.RuleSet.StartRule.Name)) + for { + gl, eof, err := ctxt.scan() + if err != nil { + ctxt.addError(err) + if p.stopAtFirstError { + break + } + } + state, err = ctxt.match(state, gl) + if err != nil { + ctxt.addError(err) + if p.stopAtFirstError { + break + } + } + if eof { + // done! \o/ + break + } + } + ctxt.endRule(@Raw("RuleType" + @Model.RuleSet.StartRule.Name)) + if len(ctxt.errors) > 0 { + return ctxt.errors + } + return +} + +type parseContext struct { + p *parser + s Scanner + b Builder + m Matcher + queue []*scanResult + errors parseErrors +} + +func (ctxt *parseContext) addError(e error) { + ctxt.errors = append(ctxt.errors, e) + // if (p.errors.length > 10) + // throw Errors.CompositeParserException.create(p.errors); +} + +type scanResult struct { + line *Line + atEof bool + err error +} + +func (ctxt *parseContext) scan() (*Line, bool, error) { + l := len(ctxt.queue) + if l > 0 { + x := ctxt.queue[0] + ctxt.queue = ctxt.queue[1:] + return x.line, x.atEof, x.err + } + return ctxt.s.Scan() +} + +func (ctxt *parseContext) startRule(r RuleType) (bool, error) { + ok, err := ctxt.b.StartRule(r) + if err != nil { + ctxt.addError(err) + } + return ok, err +} + +func (ctxt *parseContext) endRule(r RuleType) (bool, error) { + ok, err := ctxt.b.EndRule(r) + if err != nil { + ctxt.addError(err) + } + return ok, err +} + +func (ctxt *parseContext) build(t *Token) (bool, error) { + ok, err := ctxt.b.Build(t) + if err != nil { + ctxt.addError(err) + } + return ok, err +} + +func (ctxt *parseContext) match(state int, line *Line) (newState int, err error) { + switch state { + @foreach(var state in Model.States.Values.Where(s => !s.IsEndState)) + { + @:case @state.Id: + @:return ctxt.matchAt@(state.Id)(line) + } + default: + return state, fmt.Errorf("Unknown state: %+v", state) + } +} +@foreach(var state in Model.States.Values.Where(s => !s.IsEndState)) +{ + +// @Raw(state.Comment) +func (ctxt *parseContext) matchAt@(state.Id)(line *Line) (newState int, err error) { + @foreach(var transition in state.Transitions) + { + @:if ok, token, err := @MatchToken(transition.TokenType); ok { + if (transition.LookAheadHint != null) + { + @:if ctxt.lookahead@(transition.LookAheadHint.Id)(line) { + foreach(var production in transition.Productions) + { + @CallProduction(production) + } + @:return @transition.TargetState, err + @:} + } else { + foreach(var production in transition.Productions) + { + @CallProduction(production) + } + @:return @transition.TargetState, err + } + @:} + } + @HandleParserError(state.Transitions.Select(t => "#" + t.TokenType.ToString()).Distinct(), state) +} + +} + +type Matcher interface { + @foreach(var rule in Model.RuleSet.TokenRules) + { Match@(rule.Name.Replace("#", ""))(line *Line) (bool, *Token, error) +} + Reset() +} +@foreach(var rule in Model.RuleSet.TokenRules) +{ + +func (ctxt *parseContext) isMatch@(rule.Name.Replace("#", ""))(line *Line) bool { + ok, _, _ := ctxt.match@(rule.Name.Replace("#", ""))(line) + return ok +} +func (ctxt *parseContext) match@(rule.Name.Replace("#", ""))(line *Line) (bool, *Token, error) { + @if (rule.Name != "#EOF") + { + @:if line.IsEof() { + @: return false, nil, nil + @:} + } + return ctxt.m.Match@(rule.Name.Replace("#", ""))(line) +} + +} +@foreach(var lookAheadHint in Model.RuleSet.LookAheadHints) +{ + +func (ctxt *parseContext) lookahead@(lookAheadHint.Id)(initialLine *Line) bool { + var queue []*scanResult + var match bool + + for { + line, atEof, err := ctxt.scan() + queue = append(queue, &scanResult{line, atEof, err}) + + if @{false}@foreach(var tokenType in lookAheadHint.ExpectedTokens) { || @IsMatchToken(tokenType)} { + match = true + break + } + if !(@{false}@foreach(var tokenType in lookAheadHint.Skip) { || @IsMatchToken(tokenType)}) { + break + } + if atEof { + break + } + } + + ctxt.queue = append(ctxt.queue, queue...) + + return match +} + +} diff --git a/vendor/github.com/cucumber/gherkin/go/v42/pickles.go b/vendor/github.com/cucumber/gherkin/go/v42/pickles.go new file mode 100644 index 0000000000..ed38d0f7b0 --- /dev/null +++ b/vendor/github.com/cucumber/gherkin/go/v42/pickles.go @@ -0,0 +1,291 @@ +package gherkin + +import ( + "strings" + + "github.com/cucumber/messages/go/v34" +) + +func Pickles(gherkinDocument messages.GherkinDocument, uri string, newId func() string) []*messages.Pickle { + pickles := make([]*messages.Pickle, 0) + if gherkinDocument.Feature == nil { + return pickles + } + language := gherkinDocument.Feature.Language + + pickles = compileFeature(pickles, *gherkinDocument.Feature, uri, language, newId) + return pickles +} + +func compileFeature(pickles []*messages.Pickle, feature messages.Feature, uri string, language string, newId func() string) []*messages.Pickle { + featureBackgroundSteps := make([]*messages.Step, 0) + featureTags := feature.Tags + for _, child := range feature.Children { + if child.Background != nil { + featureBackgroundSteps = append(featureBackgroundSteps, child.Background.Steps...) + } + if child.Rule != nil { + pickles = compileRule(pickles, child.Rule, featureTags, featureBackgroundSteps, uri, language, newId) + } + if child.Scenario != nil { + if len(child.Scenario.Examples) == 0 { + pickles = compileScenario(pickles, featureBackgroundSteps, child.Scenario, featureTags, uri, language, newId) + } else { + pickles = compileScenarioOutline(pickles, child.Scenario, featureTags, featureBackgroundSteps, uri, language, newId) + } + } + } + return pickles +} + +func compileRule( + pickles []*messages.Pickle, + rule *messages.Rule, + featureTags []*messages.Tag, + featureBackgroundSteps []*messages.Step, + uri string, + language string, + newId func() string, +) []*messages.Pickle { + ruleBackgroundSteps := make([]*messages.Step, 0) + ruleBackgroundSteps = append(ruleBackgroundSteps, featureBackgroundSteps...) + tags := append(featureTags, rule.Tags...) + + for _, child := range rule.Children { + if child.Background != nil { + ruleBackgroundSteps = append(ruleBackgroundSteps, child.Background.Steps...) + } + if child.Scenario != nil { + if len(child.Scenario.Examples) == 0 { + pickles = compileScenario(pickles, ruleBackgroundSteps, child.Scenario, tags, uri, language, newId) + } else { + pickles = compileScenarioOutline(pickles, child.Scenario, tags, ruleBackgroundSteps, uri, language, newId) + } + } + } + return pickles + +} + +func compileScenarioOutline( + pickles []*messages.Pickle, + scenario *messages.Scenario, + inheritedTags []*messages.Tag, + backgroundSteps []*messages.Step, + uri string, + language string, + newId func() string, +) []*messages.Pickle { + for _, examples := range scenario.Examples { + if examples.TableHeader == nil { + continue + } + variableCells := examples.TableHeader.Cells + for _, valuesRow := range examples.TableBody { + valueCells := valuesRow.Cells + + computedPickleSteps := make([]*messages.PickleStep, 0) + pickleBackgroundSteps := make([]*messages.PickleStep, 0) + + if len(scenario.Steps) > 0 { + pickleBackgroundSteps = pickleSteps(backgroundSteps, newId) + } + + // translate computedPickleSteps based on valuesRow + previous := messages.PickleStepType_UNKNOWN + for _, step := range scenario.Steps { + text := step.Text + for i, variableCell := range variableCells { + text = strings.Replace(text, "<"+variableCell.Value+">", valueCells[i].Value, -1) + } + + pickleStep := pickleStep(step, variableCells, valuesRow, newId, previous) + previous = pickleStep.Type + computedPickleSteps = append(computedPickleSteps, pickleStep) + } + + // translate pickle name + name := scenario.Name + for i, key := range variableCells { + name = strings.Replace(name, "<"+key.Value+">", valueCells[i].Value, -1) + } + + if len(computedPickleSteps) > 0 { + computedPickleSteps = append(pickleBackgroundSteps, computedPickleSteps...) + } + + id := newId() + tags := pickleTags(append(inheritedTags, append(scenario.Tags, examples.Tags...)...)) + + pickles = append(pickles, &messages.Pickle{ + Id: id, + Uri: uri, + Location: valuesRow.Location, + Steps: computedPickleSteps, + Tags: tags, + Name: name, + Language: language, + AstNodeIds: []string{scenario.Id, valuesRow.Id}, + }) + } + } + return pickles +} + +func compileScenario( + pickles []*messages.Pickle, + backgroundSteps []*messages.Step, + scenario *messages.Scenario, + inheritedTags []*messages.Tag, + uri string, + language string, + newId func() string, +) []*messages.Pickle { + steps := make([]*messages.PickleStep, 0) + if len(scenario.Steps) > 0 { + pickleBackgroundSteps := pickleSteps(backgroundSteps, newId) + steps = append(pickleBackgroundSteps, pickleSteps(scenario.Steps, newId)...) + } + tags := pickleTags(append(inheritedTags, scenario.Tags...)) + id := newId() + pickles = append(pickles, &messages.Pickle{ + Id: id, + Uri: uri, + Location: scenario.Location, + Steps: steps, + Tags: tags, + Name: scenario.Name, + Language: language, + AstNodeIds: []string{scenario.Id}, + }) + return pickles +} + +func pickleDataTable(table *messages.DataTable, variableCells []*messages.TableCell, valueCells []*messages.TableCell) *messages.PickleTable { + pickleTableRows := make([]*messages.PickleTableRow, len(table.Rows)) + for i, row := range table.Rows { + pickleTableCells := make([]*messages.PickleTableCell, len(row.Cells)) + for j, cell := range row.Cells { + pickleTableCells[j] = &messages.PickleTableCell{ + Value: interpolate(cell.Value, variableCells, valueCells), + } + } + pickleTableRows[i] = &messages.PickleTableRow{Cells: pickleTableCells} + } + return &messages.PickleTable{ + Rows: pickleTableRows, + } +} + +func pickleDocString(docString *messages.DocString, variableCells []*messages.TableCell, valueCells []*messages.TableCell) *messages.PickleDocString { + return &messages.PickleDocString{ + MediaType: interpolate(docString.MediaType, variableCells, valueCells), + Content: interpolate(docString.Content, variableCells, valueCells), + } +} + +func pickleTags(tags []*messages.Tag) []*messages.PickleTag { + ptags := make([]*messages.PickleTag, len(tags)) + for i, tag := range tags { + ptags[i] = &messages.PickleTag{ + Name: tag.Name, + AstNodeId: tag.Id, + } + } + return ptags +} + +func pickleSteps(steps []*messages.Step, newId func() string) []*messages.PickleStep { + pickleSteps := make([]*messages.PickleStep, len(steps)) + previous := messages.PickleStepType_UNKNOWN + for i, step := range steps { + pickleStep := pickleStep(step, nil, nil, newId, previous) + previous = pickleStep.Type + pickleSteps[i] = pickleStep + } + return pickleSteps +} + +func pickleStep( + step *messages.Step, + variableCells []*messages.TableCell, + valuesRow *messages.TableRow, + newId func() string, + previous messages.PickleStepType, +) *messages.PickleStep { + + var valueCells []*messages.TableCell + if valuesRow != nil { + valueCells = valuesRow.Cells + } + + pickleStep := &messages.PickleStep{ + Id: newId(), + Text: interpolate(step.Text, variableCells, valueCells), + Type: mapType(step.KeywordType, previous), + AstNodeIds: []string{step.Id}, + } + if valuesRow != nil { + pickleStep.AstNodeIds = append(pickleStep.AstNodeIds, valuesRow.Id) + } + pickleStep.Argument = pickleStepArgument(step, variableCells, valueCells) + return pickleStep +} + +func pickleStepArgument(step *messages.Step, variableCells []*messages.TableCell, valueCells []*messages.TableCell) *messages.PickleStepArgument { + dataTable := step.DataTable + docString := step.DocString + + if dataTable != nil && docString != nil { + pickleStepArgument := &messages.PickleStepArgument{ + DocString: pickleDocString(docString, variableCells, valueCells), + DataTable: pickleDataTable(dataTable, variableCells, valueCells), + } + if docString.Location.Line > dataTable.Location.Line { + pickleStepArgument.DataTable.ArgumentIndex = int64(1) + pickleStepArgument.DocString.ArgumentIndex = int64(2) + } else { + pickleStepArgument.DataTable.ArgumentIndex = int64(2) + pickleStepArgument.DocString.ArgumentIndex = int64(1) + } + return pickleStepArgument + } else if dataTable != nil { + return &messages.PickleStepArgument{ + DataTable: pickleDataTable(dataTable, variableCells, valueCells), + } + } else if docString != nil { + return &messages.PickleStepArgument{ + DocString: pickleDocString(docString, variableCells, valueCells), + } + } + return nil +} + +func mapType(keywordType messages.StepKeywordType, previous messages.PickleStepType) messages.PickleStepType { + switch keywordType { + case messages.StepKeywordType_UNKNOWN: + return messages.PickleStepType_UNKNOWN + case messages.StepKeywordType_CONTEXT: + return messages.PickleStepType_CONTEXT + case messages.StepKeywordType_ACTION: + return messages.PickleStepType_ACTION + case messages.StepKeywordType_OUTCOME: + return messages.PickleStepType_OUTCOME + case messages.StepKeywordType_CONJUNCTION: + return previous + default: + panic("Bad enum value for StepKeywordType") + } +} + +func interpolate(s string, variableCells []*messages.TableCell, valueCells []*messages.TableCell) string { + if variableCells == nil || valueCells == nil { + return s + } + + for i, variableCell := range variableCells { + s = strings.Replace(s, "<"+variableCell.Value+">", valueCells[i].Value, -1) + } + + return s +} diff --git a/vendor/github.com/cucumber/gherkin/go/v42/test.feature b/vendor/github.com/cucumber/gherkin/go/v42/test.feature new file mode 100644 index 0000000000..dff77a22b7 --- /dev/null +++ b/vendor/github.com/cucumber/gherkin/go/v42/test.feature @@ -0,0 +1,151 @@ +Feature: + + Scenario: scenario 1 + Given text + + Scenario: scenario 2 + Given text + + Scenario: scenario 3 + Given text + + Scenario: scenario 4 + Given text + + Scenario: scenario 5 + Given text + + Scenario: scenario 6 + Given text + + Scenario: scenario 7 + Given text + + Scenario: scenario 8 + Given text + + Scenario: scenario 9 + Given text + + Scenario: scenario 10 + Given text + + Scenario: scenario 11 + Given text + + Scenario: scenario 12 + Given text + + Scenario: scenario 13 + Given text + + Scenario: scenario 14 + Given text + + Scenario: scenario 15 + Given text + + Scenario: scenario 16 + Given text + + Scenario: scenario 17 + Given text + + Scenario: scenario 18 + Given text + + Scenario: scenario 19 + Given text + + Scenario: scenario 20 + Given text + + Scenario: scenario 21 + Given text + + Scenario: scenario 22 + Given text + + Scenario: scenario 23 + Given text + + Scenario: scenario 24 + Given text + + Scenario: scenario 25 + Given text + + Scenario: scenario 26 + Given text + + Scenario: scenario 27 + Given text + + Scenario: scenario 28 + Given text + + Scenario: scenario 29 + Given text + + Scenario: scenario 30 + Given text + + Scenario: scenario 31 + Given text + + Scenario: scenario 32 + Given text + + Scenario: scenario 33 + Given text + + Scenario: scenario 34 + Given text + + Scenario: scenario 35 + Given text + + Scenario: scenario 36 + Given text + + Scenario: scenario 37 + Given text + + Scenario: scenario 38 + Given text + + Scenario: scenario 39 + Given text + + Scenario: scenario 40 + Given text + + Scenario: scenario 41 + Given text + + Scenario: scenario 42 + Given text + + Scenario: scenario 43 + Given text + + Scenario: scenario 44 + Given text + + Scenario: scenario 45 + Given text + + Scenario: scenario 46 + Given text + + Scenario: scenario 47 + Given text + + Scenario: scenario 48 + Given text + + Scenario: scenario 49 + Given text + + Scenario: scenario 50 + Given text diff --git a/vendor/github.com/cucumber/gherkin/go/v42/test.sh b/vendor/github.com/cucumber/gherkin/go/v42/test.sh new file mode 100644 index 0000000000..97debf6479 --- /dev/null +++ b/vendor/github.com/cucumber/gherkin/go/v42/test.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env sh + +./bin/gherkin --no-ast --no-pickles test.feature | ./bin/gherkin --no-source --no-ast --json diff --git a/vendor/github.com/cucumber/godog/CHANGELOG.md b/vendor/github.com/cucumber/godog/CHANGELOG.md index 21a323e0ab..2cb9b01db6 100644 --- a/vendor/github.com/cucumber/godog/CHANGELOG.md +++ b/vendor/github.com/cucumber/godog/CHANGELOG.md @@ -8,6 +8,15 @@ This document is formatted according to the principles of [Keep A CHANGELOG](htt ## Unreleased +## [v0.16.0] + +### Changed +- Upgrade `cucumber/messages` to v34 and `cucumber/gherkin` to v42 - ([764](https://github.com/cucumber/godog/pull/764) - [vearutop](https://github.com/vearutop)) +- Require Go 1.18, tidy example module - ([741](https://github.com/cucumber/godog/pull/741) - [vearutop](https://github.com/vearutop)) + +### Fixed +- fix(hooks): wrap errors to preserve sentinel values - ([760](https://github.com/cucumber/godog/pull/760) - [victoriacheng15](https://github.com/victoriacheng15)) + ## [v0.15.1] ### Added @@ -27,6 +36,7 @@ This document is formatted according to the principles of [Keep A CHANGELOG](htt - fix: change bang to being in README by @nahomEagleLion in https://github.com/cucumber/godog/pull/687 - Mark junit test cases as skipped if no pickle step results available by @mrsheepuk in https://github.com/cucumber/godog/pull/597 - Print step declaration line instead of handler declaration line by @SpencerC in https://github.com/cucumber/godog/pull/668 +- fix(tags): the , operator was not working as an OR operator in the tags by @kcross-ctoken in https://github.com/cucumber/godog/pull/740 ## [v0.15.0] @@ -261,6 +271,7 @@ This document is formatted according to the principles of [Keep A CHANGELOG](htt ### Changed - Changed code references to DATA-DOG/godog to cucumber/godog to help get things building correctly. ([mxygem](https://github.com/mxygem)) +[v0.16.0]: https://github.com/cucumber/godog/compare/v0.15.1...v0.16.0 [v0.15.1]: https://github.com/cucumber/godog/compare/v0.15.0...v0.15.1 [v0.15.0]: https://github.com/cucumber/godog/compare/v0.14.1...v0.15.0 [v0.14.1]: https://github.com/cucumber/godog/compare/v0.14.0...v0.14.1 diff --git a/vendor/github.com/cucumber/godog/LICENSE b/vendor/github.com/cucumber/godog/LICENSE index 97dcbd65f4..d620a7bec0 100644 --- a/vendor/github.com/cucumber/godog/LICENSE +++ b/vendor/github.com/cucumber/godog/LICENSE @@ -1,4 +1,4 @@ -The MIT License (MIT) +MIT License Copyright (c) SmartBear diff --git a/vendor/github.com/cucumber/godog/README.md b/vendor/github.com/cucumber/godog/README.md index dceacf1673..720fd12dc3 100644 --- a/vendor/github.com/cucumber/godog/README.md +++ b/vendor/github.com/cucumber/godog/README.md @@ -1,9 +1,10 @@ + + [![#StandWithUkraine](https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/badges/StandWithUkraine.svg)](https://vshymanskyy.github.io/StandWithUkraine) [![Build Status](https://github.com/cucumber/godog/workflows/test/badge.svg)](https://github.com/cucumber/godog/actions?query=branch%main+workflow%3Atest) [![PkgGoDev](https://pkg.go.dev/badge/github.com/cucumber/godog)](https://pkg.go.dev/github.com/cucumber/godog) [![codecov](https://codecov.io/gh/cucumber/godog/branch/master/graph/badge.svg)](https://codecov.io/gh/cucumber/godog) -[![pull requests](https://oselvar.com/api/badge?label=pull%20requests&csvUrl=https%3A%2F%2Fraw.githubusercontent.com%2Fcucumber%2Foselvar-github-metrics%2Fmain%2Fdata%2Fcucumber%2Fgodog%2FpullRequests.csv)](https://oselvar.com/github/cucumber/oselvar-github-metrics/main/cucumber/godog) -[![issues](https://oselvar.com/api/badge?label=issues&csvUrl=https%3A%2F%2Fraw.githubusercontent.com%2Fcucumber%2Foselvar-github-metrics%2Fmain%2Fdata%2Fcucumber%2Fgodog%2Fissues.csv)](https://oselvar.com/github/cucumber/oselvar-github-metrics/main/cucumber/godog) +[![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/cucumber/godog/badge)](https://scorecard.dev/viewer/?uri=github.com/cucumber/godog) # Godog diff --git a/vendor/github.com/cucumber/godog/flags.go b/vendor/github.com/cucumber/godog/flags.go index 45efbfec74..e6a99c3d20 100644 --- a/vendor/github.com/cucumber/godog/flags.go +++ b/vendor/github.com/cucumber/godog/flags.go @@ -208,7 +208,7 @@ func usage(set *flag.FlagSet, w io.Writer) func() { // --- GENERAL --- fmt.Fprintln(w, colors.Yellow("Usage:")) - fmt.Fprintf(w, s(2)+"go test [options]\n\n") + fmt.Fprint(w, s(2)+"go test [options]\n\n") // --- OPTIONS --- fmt.Fprintln(w, colors.Yellow("Options:")) diff --git a/vendor/github.com/cucumber/godog/formatters/fmt.go b/vendor/github.com/cucumber/godog/formatters/fmt.go index 973cf11b83..3a7171ad02 100644 --- a/vendor/github.com/cucumber/godog/formatters/fmt.go +++ b/vendor/github.com/cucumber/godog/formatters/fmt.go @@ -4,7 +4,7 @@ import ( "io" "regexp" - messages "github.com/cucumber/messages/go/v21" + messages "github.com/cucumber/messages/go/v34" ) type registeredFormatter struct { diff --git a/vendor/github.com/cucumber/godog/internal/formatters/fmt.go b/vendor/github.com/cucumber/godog/internal/formatters/fmt.go index 5530c0c243..264df4c8fd 100644 --- a/vendor/github.com/cucumber/godog/internal/formatters/fmt.go +++ b/vendor/github.com/cucumber/godog/internal/formatters/fmt.go @@ -9,7 +9,7 @@ import ( "strconv" "strings" - messages "github.com/cucumber/messages/go/v21" + messages "github.com/cucumber/messages/go/v34" "github.com/cucumber/godog/colors" "github.com/cucumber/godog/internal/models" diff --git a/vendor/github.com/cucumber/godog/internal/formatters/fmt_base.go b/vendor/github.com/cucumber/godog/internal/formatters/fmt_base.go index 607a1c0656..77b0ea826f 100644 --- a/vendor/github.com/cucumber/godog/internal/formatters/fmt_base.go +++ b/vendor/github.com/cucumber/godog/internal/formatters/fmt_base.go @@ -11,7 +11,7 @@ import ( "sync" "unicode" - messages "github.com/cucumber/messages/go/v21" + messages "github.com/cucumber/messages/go/v34" "github.com/cucumber/godog/colors" "github.com/cucumber/godog/formatters" @@ -204,6 +204,22 @@ func (f *Base) Summary() { } } +func asciiTitle(s string) string { + var b strings.Builder + b.Grow(len(s)) + + newWord := true + for i := 0; i < len(s); i++ { + c := s[i] + if ('a' <= c && c <= 'z') && newWord { + c -= 'a' - 'A' + } + b.WriteByte(c) + newWord = !('0' <= c && c <= '9' || 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z') + } + return b.String() +} + // Snippets returns code suggestions for undefined steps. func (f *Base) Snippets() string { undefinedStepResults := f.Storage.MustGetPickleStepResultsByStatus(undefined) @@ -236,7 +252,7 @@ func (f *Base) Snippets() string { for i, w := range strings.Split(name, " ") { switch { case i != 0: - w = strings.Title(w) + w = asciiTitle(w) case len(w) > 0: w = string(unicode.ToLower(rune(w[0]))) + w[1:] } diff --git a/vendor/github.com/cucumber/godog/internal/formatters/fmt_cucumber.go b/vendor/github.com/cucumber/godog/internal/formatters/fmt_cucumber.go index 31380c9757..628e4dbfc4 100644 --- a/vendor/github.com/cucumber/godog/internal/formatters/fmt_cucumber.go +++ b/vendor/github.com/cucumber/godog/internal/formatters/fmt_cucumber.go @@ -21,7 +21,7 @@ import ( "github.com/cucumber/godog/formatters" "github.com/cucumber/godog/internal/models" - messages "github.com/cucumber/messages/go/v21" + messages "github.com/cucumber/messages/go/v34" ) func init() { diff --git a/vendor/github.com/cucumber/godog/internal/formatters/fmt_events.go b/vendor/github.com/cucumber/godog/internal/formatters/fmt_events.go index c5ffcb50e1..bfecb4caba 100644 --- a/vendor/github.com/cucumber/godog/internal/formatters/fmt_events.go +++ b/vendor/github.com/cucumber/godog/internal/formatters/fmt_events.go @@ -7,7 +7,7 @@ import ( "github.com/cucumber/godog/formatters" "github.com/cucumber/godog/internal/utils" - messages "github.com/cucumber/messages/go/v21" + messages "github.com/cucumber/messages/go/v34" ) const nanoSec = 1000000 diff --git a/vendor/github.com/cucumber/godog/internal/formatters/fmt_flushwrap.go b/vendor/github.com/cucumber/godog/internal/formatters/fmt_flushwrap.go index 129b062100..93cd63938c 100644 --- a/vendor/github.com/cucumber/godog/internal/formatters/fmt_flushwrap.go +++ b/vendor/github.com/cucumber/godog/internal/formatters/fmt_flushwrap.go @@ -4,7 +4,7 @@ import ( "sync" "github.com/cucumber/godog/formatters" - messages "github.com/cucumber/messages/go/v21" + messages "github.com/cucumber/messages/go/v34" ) // WrapOnFlush wrap a `formatters.Formatter` in a `formatters.FlushFormatter`, which only diff --git a/vendor/github.com/cucumber/godog/internal/formatters/fmt_multi.go b/vendor/github.com/cucumber/godog/internal/formatters/fmt_multi.go index 001c998096..d929fdd519 100644 --- a/vendor/github.com/cucumber/godog/internal/formatters/fmt_multi.go +++ b/vendor/github.com/cucumber/godog/internal/formatters/fmt_multi.go @@ -5,7 +5,7 @@ import ( "github.com/cucumber/godog/formatters" "github.com/cucumber/godog/internal/storage" - messages "github.com/cucumber/messages/go/v21" + messages "github.com/cucumber/messages/go/v34" ) // MultiFormatter passes test progress to multiple formatters. diff --git a/vendor/github.com/cucumber/godog/internal/formatters/fmt_pretty.go b/vendor/github.com/cucumber/godog/internal/formatters/fmt_pretty.go index 76d733793c..f27533c823 100644 --- a/vendor/github.com/cucumber/godog/internal/formatters/fmt_pretty.go +++ b/vendor/github.com/cucumber/godog/internal/formatters/fmt_pretty.go @@ -8,7 +8,7 @@ import ( "strings" "unicode/utf8" - messages "github.com/cucumber/messages/go/v21" + messages "github.com/cucumber/messages/go/v34" "github.com/cucumber/godog/colors" "github.com/cucumber/godog/formatters" diff --git a/vendor/github.com/cucumber/godog/internal/formatters/fmt_progress.go b/vendor/github.com/cucumber/godog/internal/formatters/fmt_progress.go index 9722ef7a5c..c6ec25861d 100644 --- a/vendor/github.com/cucumber/godog/internal/formatters/fmt_progress.go +++ b/vendor/github.com/cucumber/godog/internal/formatters/fmt_progress.go @@ -8,7 +8,7 @@ import ( "strings" "github.com/cucumber/godog/formatters" - messages "github.com/cucumber/messages/go/v21" + messages "github.com/cucumber/messages/go/v34" ) func init() { @@ -42,7 +42,7 @@ func (f *Progress) Summary() { left := math.Mod(float64(*f.Steps), float64(f.StepsPerRow)) if left != 0 { if *f.Steps > f.StepsPerRow { - fmt.Fprintf(f.out, s(f.StepsPerRow-int(left))+fmt.Sprintf(" %d\n", *f.Steps)) + fmt.Fprint(f.out, s(f.StepsPerRow-int(left))+fmt.Sprintf(" %d\n", *f.Steps)) } else { fmt.Fprintf(f.out, " %d\n", *f.Steps) } diff --git a/vendor/github.com/cucumber/godog/internal/formatters/undefined_snippets_gen.go b/vendor/github.com/cucumber/godog/internal/formatters/undefined_snippets_gen.go index ff6cd79ef7..e639abd807 100644 --- a/vendor/github.com/cucumber/godog/internal/formatters/undefined_snippets_gen.go +++ b/vendor/github.com/cucumber/godog/internal/formatters/undefined_snippets_gen.go @@ -7,7 +7,7 @@ import ( "strings" "text/template" - messages "github.com/cucumber/messages/go/v21" + messages "github.com/cucumber/messages/go/v34" ) // some snippet formatting regexps diff --git a/vendor/github.com/cucumber/godog/internal/models/feature.go b/vendor/github.com/cucumber/godog/internal/models/feature.go index 9d9d84da70..bc68d46b5a 100644 --- a/vendor/github.com/cucumber/godog/internal/models/feature.go +++ b/vendor/github.com/cucumber/godog/internal/models/feature.go @@ -1,7 +1,7 @@ package models import ( - messages "github.com/cucumber/messages/go/v21" + messages "github.com/cucumber/messages/go/v34" ) // Feature is an internal object to group together diff --git a/vendor/github.com/cucumber/godog/internal/models/stepdef.go b/vendor/github.com/cucumber/godog/internal/models/stepdef.go index 7c2e973ac4..7e6c83ed9e 100644 --- a/vendor/github.com/cucumber/godog/internal/models/stepdef.go +++ b/vendor/github.com/cucumber/godog/internal/models/stepdef.go @@ -7,7 +7,7 @@ import ( "reflect" "strconv" - messages "github.com/cucumber/messages/go/v21" + messages "github.com/cucumber/messages/go/v34" "github.com/cucumber/godog/formatters" ) diff --git a/vendor/github.com/cucumber/godog/internal/parser/parser.go b/vendor/github.com/cucumber/godog/internal/parser/parser.go index f607000aa2..7f0da672c5 100644 --- a/vendor/github.com/cucumber/godog/internal/parser/parser.go +++ b/vendor/github.com/cucumber/godog/internal/parser/parser.go @@ -10,8 +10,8 @@ import ( "strconv" "strings" - gherkin "github.com/cucumber/gherkin/go/v26" - messages "github.com/cucumber/messages/go/v21" + gherkin "github.com/cucumber/gherkin/go/v42" + messages "github.com/cucumber/messages/go/v34" "github.com/cucumber/godog/internal/flags" "github.com/cucumber/godog/internal/models" diff --git a/vendor/github.com/cucumber/godog/internal/storage/storage.go b/vendor/github.com/cucumber/godog/internal/storage/storage.go index 72b7e86f7f..474cfc880e 100644 --- a/vendor/github.com/cucumber/godog/internal/storage/storage.go +++ b/vendor/github.com/cucumber/godog/internal/storage/storage.go @@ -4,7 +4,7 @@ import ( "fmt" "sync" - messages "github.com/cucumber/messages/go/v21" + messages "github.com/cucumber/messages/go/v34" "github.com/hashicorp/go-memdb" "github.com/cucumber/godog/internal/models" diff --git a/vendor/github.com/cucumber/godog/internal/tags/tag_filter.go b/vendor/github.com/cucumber/godog/internal/tags/tag_filter.go index 72b4512b4f..0672edc2db 100644 --- a/vendor/github.com/cucumber/godog/internal/tags/tag_filter.go +++ b/vendor/github.com/cucumber/godog/internal/tags/tag_filter.go @@ -3,7 +3,7 @@ package tags import ( "strings" - messages "github.com/cucumber/messages/go/v21" + messages "github.com/cucumber/messages/go/v34" ) // ApplyTagFilter will apply a filter string on the @@ -25,28 +25,28 @@ func ApplyTagFilter(filter string, pickles []*messages.Pickle) []*messages.Pickl } // Based on http://behat.readthedocs.org/en/v2.5/guides/6.cli.html#gherkin-filters -func match(filter string, tags []*messages.PickleTag) (ok bool) { - ok = true - - for _, andTags := range strings.Split(filter, "&&") { - var okComma bool - - for _, tag := range strings.Split(andTags, ",") { - tag = strings.TrimSpace(tag) - tag = strings.Replace(tag, "@", "", -1) +func match(filters string, tags []*messages.PickleTag) (ok bool) { + ok = false + for _, filter := range strings.Split(filters, ",") { + ok = matchAnd(filter, tags) || ok + } - okComma = contains(tags, tag) || okComma + return +} - if tag[0] == '~' { - tag = tag[1:] - okComma = !contains(tags, tag) || okComma - } +func matchAnd(filter string, tags []*messages.PickleTag) bool { + and := len(filter) > 0 + for _, tag := range strings.Split(filter, "&&") { + tag = strings.TrimSpace(tag) + tag = strings.Replace(tag, "@", "", -1) + if tag[0] == '~' { + tag = tag[1:] + and = !contains(tags, tag) && and + } else { + and = contains(tags, tag) && and } - - ok = ok && okComma } - - return + return and } func contains(tags []*messages.PickleTag, tag string) bool { diff --git a/vendor/github.com/cucumber/godog/run.go b/vendor/github.com/cucumber/godog/run.go index 1231d02861..6b383492de 100644 --- a/vendor/github.com/cucumber/godog/run.go +++ b/vendor/github.com/cucumber/godog/run.go @@ -16,7 +16,7 @@ import ( "sync" "testing" - messages "github.com/cucumber/messages/go/v21" + messages "github.com/cucumber/messages/go/v34" "github.com/cucumber/godog/colors" "github.com/cucumber/godog/formatters" diff --git a/vendor/github.com/cucumber/godog/suite.go b/vendor/github.com/cucumber/godog/suite.go index 6ca1bf53d5..616419e35c 100644 --- a/vendor/github.com/cucumber/godog/suite.go +++ b/vendor/github.com/cucumber/godog/suite.go @@ -8,7 +8,7 @@ import ( "strings" "testing" - messages "github.com/cucumber/messages/go/v21" + messages "github.com/cucumber/messages/go/v34" "github.com/cucumber/godog/formatters" "github.com/cucumber/godog/internal/models" @@ -304,7 +304,7 @@ func (s *suite) runBeforeStepHooks(ctx context.Context, step *Step, err error) ( if err == nil { err = herr } else { - err = fmt.Errorf("%v, %w", herr, err) + err = mergeErrors(herr, err) } } @@ -329,7 +329,7 @@ func (s *suite) runAfterStepHooks(ctx context.Context, step *Step, status StepRe if err == nil { err = herr } else { - err = fmt.Errorf("%v, %w", herr, err) + err = mergeErrors(herr, err) } } @@ -351,7 +351,7 @@ func (s *suite) runBeforeScenarioHooks(ctx context.Context, pickle *messages.Pic if err == nil { err = herr } else { - err = fmt.Errorf("%v, %w", herr, err) + err = mergeErrors(herr, err) } } @@ -389,7 +389,7 @@ func (s *suite) runAfterScenarioHooks(ctx context.Context, pickle *messages.Pick err = fmt.Errorf("step error: %w", err) isStepErr = false } - err = fmt.Errorf("%v, %w", herr, err) + err = mergeErrors(herr, err) } } @@ -649,3 +649,34 @@ func (s *suite) runPickle(pickle *messages.Pickle) (err error) { return err } + +type joinedError struct { + err1 error + err2 error +} + +func (e *joinedError) Error() string { + return fmt.Sprintf("%v, %v", e.err1, e.err2) +} + +func (e *joinedError) Unwrap() []error { + return []error{e.err1, e.err2} +} + +func (e *joinedError) Is(target error) bool { + return errors.Is(e.err1, target) || errors.Is(e.err2, target) +} + +func (e *joinedError) As(target interface{}) bool { + return errors.As(e.err1, target) || errors.As(e.err2, target) +} + +func mergeErrors(err1, err2 error) error { + if err1 == nil { + return err2 + } + if err2 == nil { + return err1 + } + return &joinedError{err1: err1, err2: err2} +} diff --git a/vendor/github.com/cucumber/godog/test_context.go b/vendor/github.com/cucumber/godog/test_context.go index add9f47b07..9e974fbcd0 100644 --- a/vendor/github.com/cucumber/godog/test_context.go +++ b/vendor/github.com/cucumber/godog/test_context.go @@ -7,7 +7,7 @@ import ( "regexp" "runtime" - messages "github.com/cucumber/messages/go/v21" + messages "github.com/cucumber/messages/go/v34" "github.com/cucumber/godog/formatters" "github.com/cucumber/godog/internal/builder" @@ -237,6 +237,7 @@ func (ctx ScenarioContext) AfterStep(fn func(st *Step, err error)) { // // The stepFunc may accept one or several arguments of type: // - int, int8, int16, int32, int64 +// - uint, uint8, uint16, uint32, uint64 // - float32, float64 // - string // - []byte diff --git a/vendor/github.com/cucumber/godog/testingt.go b/vendor/github.com/cucumber/godog/testingt.go index 25981b89aa..40d81e0072 100644 --- a/vendor/github.com/cucumber/godog/testingt.go +++ b/vendor/github.com/cucumber/godog/testingt.go @@ -2,6 +2,7 @@ package godog import ( "context" + "errors" "fmt" "strings" "testing" @@ -183,9 +184,9 @@ func (dt *testingT) isFailed() error { } switch len(dt.failMessages) { case 0: - return fmt.Errorf("fail called on TestingT") + return errors.New("fail called on TestingT") case 1: - return fmt.Errorf(dt.failMessages[0]) + return errors.New(dt.failMessages[0]) default: return fmt.Errorf("checks failed:\n* %s", strings.Join(dt.failMessages, "\n* ")) } diff --git a/vendor/github.com/cucumber/messages/go/v34/.gitignore b/vendor/github.com/cucumber/messages/go/v34/.gitignore new file mode 100644 index 0000000000..7b0ee7aeb6 --- /dev/null +++ b/vendor/github.com/cucumber/messages/go/v34/.gitignore @@ -0,0 +1,17 @@ +.built +.compared +.deps +.dist +.dist-compressed +.go-get +.gofmt +.linted +.tested* +acceptance/ +bin/ +dist/ +dist_compressed/ +*.bin +*.iml +# upx dist/cucumber-gherkin-openbsd-386 fails with a core dump +core.*.!usr!bin!upx-ucl diff --git a/vendor/github.com/cucumber/messages/go/v34/LICENSE b/vendor/github.com/cucumber/messages/go/v34/LICENSE new file mode 100644 index 0000000000..520b896f74 --- /dev/null +++ b/vendor/github.com/cucumber/messages/go/v34/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 Cucumber Ltd and contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/cucumber/messages/go/v34/Makefile b/vendor/github.com/cucumber/messages/go/v34/Makefile new file mode 100644 index 0000000000..35a777a414 --- /dev/null +++ b/vendor/github.com/cucumber/messages/go/v34/Makefile @@ -0,0 +1,19 @@ +schemas = $(shell find ../jsonschema/src -name "*.schema.json") + +.DEFAULT_GOAL = help + +help: ## Show this help + @awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \n\nWhere is one of:\n"} /^[$$()% a-zA-Z_-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST) + +generate: require messages.go ## Generate go code based on the schemas found in ../jsonschema and using the scripts in ../jsonschema/scripts for the generation + +require: ## Check requirements for the code generation (ruby and go are required) + @ruby --version >/dev/null 2>&1 || (echo "ERROR: ruby is required."; exit 1) + @go version >/dev/null 2>&1 || (echo "ERROR: go is required."; exit 1) + +clean: ## Remove automatically generated files and related artifacts + rm -f messages.go + +messages.go: $(schemas) ../codegen/codegen.rb ../codegen/templates/go.go.erb ../codegen/templates/go.enum.go.erb + ruby ../codegen/codegen.rb Generator::Go go.go.erb > $@ + ruby ../codegen/codegen.rb Generator::Go go.enum.go.erb >> $@ diff --git a/vendor/github.com/cucumber/messages/go/v34/id_generator.go b/vendor/github.com/cucumber/messages/go/v34/id_generator.go new file mode 100644 index 0000000000..e884e7fe68 --- /dev/null +++ b/vendor/github.com/cucumber/messages/go/v34/id_generator.go @@ -0,0 +1,29 @@ +package messages + +import ( + "strconv" + + "github.com/google/uuid" +) + +type IdGenerator interface { + newId() func() string +} + +type Incrementing struct { + next int +} + +func (self *Incrementing) NewId() string { + result := strconv.Itoa(self.next) + self.next++ + return result +} + +type UUID struct { + next int +} + +func (i UUID) NewId() string { + return uuid.New().String() +} diff --git a/vendor/github.com/cucumber/messages/go/v34/messages.go b/vendor/github.com/cucumber/messages/go/v34/messages.go new file mode 100644 index 0000000000..52ab6d4317 --- /dev/null +++ b/vendor/github.com/cucumber/messages/go/v34/messages.go @@ -0,0 +1,590 @@ +package messages + +type Attachment struct { + Body string `json:"body"` + ContentEncoding AttachmentContentEncoding `json:"contentEncoding"` + FileName string `json:"fileName,omitempty"` + MediaType string `json:"mediaType"` + Source *Source `json:"source,omitempty"` + TestCaseStartedId string `json:"testCaseStartedId,omitempty"` + TestStepId string `json:"testStepId,omitempty"` + Url string `json:"url,omitempty"` + TestRunStartedId string `json:"testRunStartedId,omitempty"` + TestRunHookStartedId string `json:"testRunHookStartedId,omitempty"` + Timestamp *Timestamp `json:"timestamp,omitempty"` +} + +type Duration struct { + Seconds int64 `json:"seconds"` + Nanos int64 `json:"nanos"` +} + +type Envelope struct { + Attachment *Attachment `json:"attachment,omitempty"` + ExternalAttachment *ExternalAttachment `json:"externalAttachment,omitempty"` + GherkinDocument *GherkinDocument `json:"gherkinDocument,omitempty"` + Hook *Hook `json:"hook,omitempty"` + Meta *Meta `json:"meta,omitempty"` + ParameterType *ParameterType `json:"parameterType,omitempty"` + ParseError *ParseError `json:"parseError,omitempty"` + Pickle *Pickle `json:"pickle,omitempty"` + Suggestion *Suggestion `json:"suggestion,omitempty"` + Source *Source `json:"source,omitempty"` + StepDefinition *StepDefinition `json:"stepDefinition,omitempty"` + TestCase *TestCase `json:"testCase,omitempty"` + TestCaseFinished *TestCaseFinished `json:"testCaseFinished,omitempty"` + TestCaseStarted *TestCaseStarted `json:"testCaseStarted,omitempty"` + TestRunFinished *TestRunFinished `json:"testRunFinished,omitempty"` + TestRunStarted *TestRunStarted `json:"testRunStarted,omitempty"` + TestStepFinished *TestStepFinished `json:"testStepFinished,omitempty"` + TestStepStarted *TestStepStarted `json:"testStepStarted,omitempty"` + TestRunHookStarted *TestRunHookStarted `json:"testRunHookStarted,omitempty"` + TestRunHookFinished *TestRunHookFinished `json:"testRunHookFinished,omitempty"` + UndefinedParameterType *UndefinedParameterType `json:"undefinedParameterType,omitempty"` +} + +type Exception struct { + Type string `json:"type"` + Message string `json:"message,omitempty"` + StackTrace string `json:"stackTrace,omitempty"` +} + +type ExternalAttachment struct { + Url string `json:"url"` + MediaType string `json:"mediaType"` + TestCaseStartedId string `json:"testCaseStartedId,omitempty"` + TestStepId string `json:"testStepId,omitempty"` + TestRunHookStartedId string `json:"testRunHookStartedId,omitempty"` + Timestamp *Timestamp `json:"timestamp,omitempty"` +} + +type GherkinDocument struct { + Uri string `json:"uri,omitempty"` + Feature *Feature `json:"feature,omitempty"` + Comments []*Comment `json:"comments"` +} + +type Background struct { + Location *Location `json:"location"` + Keyword string `json:"keyword"` + Name string `json:"name"` + Description string `json:"description"` + Steps []*Step `json:"steps"` + Id string `json:"id"` +} + +type Comment struct { + Location *Location `json:"location"` + Text string `json:"text"` +} + +type DataTable struct { + Location *Location `json:"location"` + Rows []*TableRow `json:"rows"` +} + +type DocString struct { + Location *Location `json:"location"` + MediaType string `json:"mediaType,omitempty"` + Content string `json:"content"` + Delimiter string `json:"delimiter"` +} + +type Examples struct { + Location *Location `json:"location"` + Tags []*Tag `json:"tags"` + Keyword string `json:"keyword"` + Name string `json:"name"` + Description string `json:"description"` + TableHeader *TableRow `json:"tableHeader,omitempty"` + TableBody []*TableRow `json:"tableBody"` + Id string `json:"id"` +} + +type Feature struct { + Location *Location `json:"location"` + Tags []*Tag `json:"tags"` + Language string `json:"language"` + Keyword string `json:"keyword"` + Name string `json:"name"` + Description string `json:"description"` + Children []*FeatureChild `json:"children"` +} + +type FeatureChild struct { + Rule *Rule `json:"rule,omitempty"` + Background *Background `json:"background,omitempty"` + Scenario *Scenario `json:"scenario,omitempty"` +} + +type Rule struct { + Location *Location `json:"location"` + Tags []*Tag `json:"tags"` + Keyword string `json:"keyword"` + Name string `json:"name"` + Description string `json:"description"` + Children []*RuleChild `json:"children"` + Id string `json:"id"` +} + +type RuleChild struct { + Background *Background `json:"background,omitempty"` + Scenario *Scenario `json:"scenario,omitempty"` +} + +type Scenario struct { + Location *Location `json:"location"` + Tags []*Tag `json:"tags"` + Keyword string `json:"keyword"` + Name string `json:"name"` + Description string `json:"description"` + Steps []*Step `json:"steps"` + Examples []*Examples `json:"examples"` + Id string `json:"id"` +} + +type Step struct { + Location *Location `json:"location"` + Keyword string `json:"keyword"` + KeywordType StepKeywordType `json:"keywordType,omitempty"` + Text string `json:"text"` + DocString *DocString `json:"docString,omitempty"` + DataTable *DataTable `json:"dataTable,omitempty"` + Id string `json:"id"` +} + +type TableCell struct { + Location *Location `json:"location"` + Value string `json:"value"` +} + +type TableRow struct { + Location *Location `json:"location"` + Cells []*TableCell `json:"cells"` + Id string `json:"id"` +} + +type Tag struct { + Location *Location `json:"location"` + Name string `json:"name"` + Id string `json:"id"` +} + +type Hook struct { + Id string `json:"id"` + Name string `json:"name,omitempty"` + SourceReference *SourceReference `json:"sourceReference"` + TagExpression string `json:"tagExpression,omitempty"` + Type HookType `json:"type,omitempty"` +} + +type Location struct { + Line int64 `json:"line"` + Column int64 `json:"column,omitempty"` +} + +type Meta struct { + ProtocolVersion string `json:"protocolVersion"` + Implementation *Product `json:"implementation"` + Runtime *Product `json:"runtime"` + Os *Product `json:"os"` + Cpu *Product `json:"cpu"` + Ci *Ci `json:"ci,omitempty"` +} + +type Ci struct { + Name string `json:"name"` + Url string `json:"url,omitempty"` + BuildNumber string `json:"buildNumber,omitempty"` + Git *Git `json:"git,omitempty"` +} + +type Git struct { + Remote string `json:"remote"` + Revision string `json:"revision"` + Branch string `json:"branch,omitempty"` + Tag string `json:"tag,omitempty"` +} + +type Product struct { + Name string `json:"name"` + Version string `json:"version,omitempty"` +} + +type ParameterType struct { + Name string `json:"name"` + RegularExpressions []string `json:"regularExpressions"` + PreferForRegularExpressionMatch bool `json:"preferForRegularExpressionMatch"` + UseForSnippets bool `json:"useForSnippets"` + Id string `json:"id"` + SourceReference *SourceReference `json:"sourceReference,omitempty"` +} + +type ParseError struct { + Source *SourceReference `json:"source"` + Message string `json:"message"` +} + +type Pickle struct { + Id string `json:"id"` + Uri string `json:"uri"` + Location *Location `json:"location,omitempty"` + Name string `json:"name"` + Language string `json:"language"` + Steps []*PickleStep `json:"steps"` + Tags []*PickleTag `json:"tags"` + AstNodeIds []string `json:"astNodeIds"` +} + +type PickleDocString struct { + ArgumentIndex int64 `json:"argumentIndex,omitempty"` + MediaType string `json:"mediaType,omitempty"` + Content string `json:"content"` +} + +type PickleStep struct { + Argument *PickleStepArgument `json:"argument,omitempty"` + AstNodeIds []string `json:"astNodeIds"` + Id string `json:"id"` + Type PickleStepType `json:"type,omitempty"` + Text string `json:"text"` +} + +type PickleStepArgument struct { + DocString *PickleDocString `json:"docString,omitempty"` + DataTable *PickleTable `json:"dataTable,omitempty"` +} + +type PickleTable struct { + ArgumentIndex int64 `json:"argumentIndex,omitempty"` + Rows []*PickleTableRow `json:"rows"` +} + +type PickleTableCell struct { + Value string `json:"value"` +} + +type PickleTableRow struct { + Cells []*PickleTableCell `json:"cells"` +} + +type PickleTag struct { + Name string `json:"name"` + AstNodeId string `json:"astNodeId"` +} + +type Source struct { + Uri string `json:"uri"` + Data string `json:"data"` + MediaType SourceMediaType `json:"mediaType"` +} + +type SourceReference struct { + Uri string `json:"uri,omitempty"` + JavaMethod *JavaMethod `json:"javaMethod,omitempty"` + JavaStackTraceElement *JavaStackTraceElement `json:"javaStackTraceElement,omitempty"` + Location *Location `json:"location,omitempty"` +} + +type JavaMethod struct { + ClassName string `json:"className"` + MethodName string `json:"methodName"` + MethodParameterTypes []string `json:"methodParameterTypes"` +} + +type JavaStackTraceElement struct { + ClassName string `json:"className"` + FileName string `json:"fileName"` + MethodName string `json:"methodName"` +} + +type StepDefinition struct { + Id string `json:"id"` + Pattern *StepDefinitionPattern `json:"pattern"` + SourceReference *SourceReference `json:"sourceReference"` +} + +type StepDefinitionPattern struct { + Source string `json:"source"` + Type StepDefinitionPatternType `json:"type"` +} + +type Suggestion struct { + Id string `json:"id"` + PickleStepId string `json:"pickleStepId"` + Snippets []*Snippet `json:"snippets"` +} + +type Snippet struct { + Language string `json:"language"` + Code string `json:"code"` +} + +type TestCase struct { + Id string `json:"id"` + PickleId string `json:"pickleId"` + TestSteps []*TestStep `json:"testSteps"` + TestRunStartedId string `json:"testRunStartedId,omitempty"` +} + +type Group struct { + Children []*Group `json:"children,omitempty"` + Start int64 `json:"start,omitempty"` + Value string `json:"value,omitempty"` +} + +type StepMatchArgument struct { + Group *Group `json:"group"` + ParameterTypeName string `json:"parameterTypeName,omitempty"` +} + +type StepMatchArgumentsList struct { + StepMatchArguments []*StepMatchArgument `json:"stepMatchArguments"` +} + +type TestStep struct { + HookId string `json:"hookId,omitempty"` + Id string `json:"id"` + PickleStepId string `json:"pickleStepId,omitempty"` + StepDefinitionIds []string `json:"stepDefinitionIds,omitempty"` + StepMatchArgumentsLists []*StepMatchArgumentsList `json:"stepMatchArgumentsLists,omitempty"` +} + +type TestCaseFinished struct { + TestCaseStartedId string `json:"testCaseStartedId"` + Timestamp *Timestamp `json:"timestamp"` + WillBeRetried bool `json:"willBeRetried"` +} + +type TestCaseStarted struct { + Attempt int64 `json:"attempt"` + Id string `json:"id"` + TestCaseId string `json:"testCaseId"` + WorkerId string `json:"workerId,omitempty"` + Timestamp *Timestamp `json:"timestamp"` +} + +type TestRunFinished struct { + Message string `json:"message,omitempty"` + Success bool `json:"success"` + Timestamp *Timestamp `json:"timestamp"` + Exception *Exception `json:"exception,omitempty"` + TestRunStartedId string `json:"testRunStartedId,omitempty"` +} + +type TestRunHookFinished struct { + TestRunHookStartedId string `json:"testRunHookStartedId"` + Result *TestStepResult `json:"result"` + Timestamp *Timestamp `json:"timestamp"` +} + +type TestRunHookStarted struct { + Id string `json:"id"` + TestRunStartedId string `json:"testRunStartedId"` + HookId string `json:"hookId"` + WorkerId string `json:"workerId,omitempty"` + Timestamp *Timestamp `json:"timestamp"` +} + +type TestRunStarted struct { + Timestamp *Timestamp `json:"timestamp"` + Id string `json:"id,omitempty"` +} + +type TestStepFinished struct { + TestCaseStartedId string `json:"testCaseStartedId"` + TestStepId string `json:"testStepId"` + TestStepResult *TestStepResult `json:"testStepResult"` + Timestamp *Timestamp `json:"timestamp"` +} + +type TestStepResult struct { + Duration *Duration `json:"duration"` + Message string `json:"message,omitempty"` + Status TestStepResultStatus `json:"status"` + Exception *Exception `json:"exception,omitempty"` +} + +type TestStepStarted struct { + TestCaseStartedId string `json:"testCaseStartedId"` + TestStepId string `json:"testStepId"` + Timestamp *Timestamp `json:"timestamp"` +} + +type Timestamp struct { + Seconds int64 `json:"seconds"` + Nanos int64 `json:"nanos"` +} + +type UndefinedParameterType struct { + Expression string `json:"expression"` + Name string `json:"name"` +} + +type AttachmentContentEncoding string + +const ( + AttachmentContentEncoding_IDENTITY AttachmentContentEncoding = "IDENTITY" + AttachmentContentEncoding_BASE64 AttachmentContentEncoding = "BASE64" +) + +func (e AttachmentContentEncoding) String() string { + switch e { + case AttachmentContentEncoding_IDENTITY: + return "IDENTITY" + case AttachmentContentEncoding_BASE64: + return "BASE64" + default: + panic("Bad enum value for AttachmentContentEncoding") + } +} + +type HookType string + +const ( + HookType_BEFORE_TEST_RUN HookType = "BEFORE_TEST_RUN" + HookType_AFTER_TEST_RUN HookType = "AFTER_TEST_RUN" + HookType_BEFORE_TEST_CASE HookType = "BEFORE_TEST_CASE" + HookType_AFTER_TEST_CASE HookType = "AFTER_TEST_CASE" + HookType_BEFORE_TEST_STEP HookType = "BEFORE_TEST_STEP" + HookType_AFTER_TEST_STEP HookType = "AFTER_TEST_STEP" +) + +func (e HookType) String() string { + switch e { + case HookType_BEFORE_TEST_RUN: + return "BEFORE_TEST_RUN" + case HookType_AFTER_TEST_RUN: + return "AFTER_TEST_RUN" + case HookType_BEFORE_TEST_CASE: + return "BEFORE_TEST_CASE" + case HookType_AFTER_TEST_CASE: + return "AFTER_TEST_CASE" + case HookType_BEFORE_TEST_STEP: + return "BEFORE_TEST_STEP" + case HookType_AFTER_TEST_STEP: + return "AFTER_TEST_STEP" + default: + panic("Bad enum value for HookType") + } +} + +type PickleStepType string + +const ( + PickleStepType_UNKNOWN PickleStepType = "Unknown" + PickleStepType_CONTEXT PickleStepType = "Context" + PickleStepType_ACTION PickleStepType = "Action" + PickleStepType_OUTCOME PickleStepType = "Outcome" +) + +func (e PickleStepType) String() string { + switch e { + case PickleStepType_UNKNOWN: + return "Unknown" + case PickleStepType_CONTEXT: + return "Context" + case PickleStepType_ACTION: + return "Action" + case PickleStepType_OUTCOME: + return "Outcome" + default: + panic("Bad enum value for PickleStepType") + } +} + +type SourceMediaType string + +const ( + SourceMediaType_TEXT_X_CUCUMBER_GHERKIN_PLAIN SourceMediaType = "text/x.cucumber.gherkin+plain" + SourceMediaType_TEXT_X_CUCUMBER_GHERKIN_MARKDOWN SourceMediaType = "text/x.cucumber.gherkin+markdown" +) + +func (e SourceMediaType) String() string { + switch e { + case SourceMediaType_TEXT_X_CUCUMBER_GHERKIN_PLAIN: + return "text/x.cucumber.gherkin+plain" + case SourceMediaType_TEXT_X_CUCUMBER_GHERKIN_MARKDOWN: + return "text/x.cucumber.gherkin+markdown" + default: + panic("Bad enum value for SourceMediaType") + } +} + +type StepDefinitionPatternType string + +const ( + StepDefinitionPatternType_CUCUMBER_EXPRESSION StepDefinitionPatternType = "CUCUMBER_EXPRESSION" + StepDefinitionPatternType_REGULAR_EXPRESSION StepDefinitionPatternType = "REGULAR_EXPRESSION" +) + +func (e StepDefinitionPatternType) String() string { + switch e { + case StepDefinitionPatternType_CUCUMBER_EXPRESSION: + return "CUCUMBER_EXPRESSION" + case StepDefinitionPatternType_REGULAR_EXPRESSION: + return "REGULAR_EXPRESSION" + default: + panic("Bad enum value for StepDefinitionPatternType") + } +} + +type StepKeywordType string + +const ( + StepKeywordType_UNKNOWN StepKeywordType = "Unknown" + StepKeywordType_CONTEXT StepKeywordType = "Context" + StepKeywordType_ACTION StepKeywordType = "Action" + StepKeywordType_OUTCOME StepKeywordType = "Outcome" + StepKeywordType_CONJUNCTION StepKeywordType = "Conjunction" +) + +func (e StepKeywordType) String() string { + switch e { + case StepKeywordType_UNKNOWN: + return "Unknown" + case StepKeywordType_CONTEXT: + return "Context" + case StepKeywordType_ACTION: + return "Action" + case StepKeywordType_OUTCOME: + return "Outcome" + case StepKeywordType_CONJUNCTION: + return "Conjunction" + default: + panic("Bad enum value for StepKeywordType") + } +} + +type TestStepResultStatus string + +const ( + TestStepResultStatus_UNKNOWN TestStepResultStatus = "UNKNOWN" + TestStepResultStatus_PASSED TestStepResultStatus = "PASSED" + TestStepResultStatus_SKIPPED TestStepResultStatus = "SKIPPED" + TestStepResultStatus_PENDING TestStepResultStatus = "PENDING" + TestStepResultStatus_UNDEFINED TestStepResultStatus = "UNDEFINED" + TestStepResultStatus_AMBIGUOUS TestStepResultStatus = "AMBIGUOUS" + TestStepResultStatus_FAILED TestStepResultStatus = "FAILED" +) + +func (e TestStepResultStatus) String() string { + switch e { + case TestStepResultStatus_UNKNOWN: + return "UNKNOWN" + case TestStepResultStatus_PASSED: + return "PASSED" + case TestStepResultStatus_SKIPPED: + return "SKIPPED" + case TestStepResultStatus_PENDING: + return "PENDING" + case TestStepResultStatus_UNDEFINED: + return "UNDEFINED" + case TestStepResultStatus_AMBIGUOUS: + return "AMBIGUOUS" + case TestStepResultStatus_FAILED: + return "FAILED" + default: + panic("Bad enum value for TestStepResultStatus") + } +} diff --git a/vendor/github.com/cucumber/messages/go/v34/time_conversion.go b/vendor/github.com/cucumber/messages/go/v34/time_conversion.go new file mode 100644 index 0000000000..3a387931e7 --- /dev/null +++ b/vendor/github.com/cucumber/messages/go/v34/time_conversion.go @@ -0,0 +1,34 @@ +package messages + +import "time" + +const nanosPerSecond = 1000000000 + +func DurationToGoDuration(duration Duration) time.Duration { + secondNanos := duration.Seconds * nanosPerSecond + return time.Duration(secondNanos + int64(duration.Nanos)) +} + +func GoDurationToDuration(goDuration time.Duration) Duration { + seconds := int64(goDuration / nanosPerSecond) + nanos := int64(goDuration % nanosPerSecond) + return Duration{ + Seconds: seconds, + Nanos: nanos, + } +} + +func TimestampToGoTime(timestamp Timestamp) time.Time { + return time.Unix(timestamp.Seconds, timestamp.Nanos) +} + +func GoTimeToTimestamp(t time.Time) Timestamp { + unixNanos := t.UnixNano() + seconds := unixNanos / nanosPerSecond + nanos := unixNanos % nanosPerSecond + + return Timestamp{ + Seconds: seconds, + Nanos: nanos, + } +} diff --git a/vendor/github.com/docker/cli/cli/config/credentials/file_store.go b/vendor/github.com/docker/cli/cli/config/credentials/file_store.go index e3ef8e25ed..d4037b7a48 100644 --- a/vendor/github.com/docker/cli/cli/config/credentials/file_store.go +++ b/vendor/github.com/docker/cli/cli/config/credentials/file_store.go @@ -104,7 +104,7 @@ func (c *fileStore) Store(authConfig types.AuthConfig) error { // stored as hostname or as hostname including scheme (in legacy configuration // files). // -// It's the equivalent to [registry.ConvertToHostname] in the daemon. +// It's based on [registry.ConvertToHostname] from Moby daemon. // // [registry.ConvertToHostname]: https://pkg.go.dev/github.com/moby/moby/v2@v2.0.0-beta.7/daemon/pkg/registry#ConvertToHostname func ConvertToHostname(maybeURL string) string { @@ -117,7 +117,48 @@ func ConvertToHostname(maybeURL string) string { } return net.JoinHostPort(u.Hostname(), u.Port()) } + + if hostName := hostFromURLFallback(stripped); hostName != "" { + return hostName + } } hostName, _, _ := strings.Cut(stripped, "/") return hostName } + +// hostFromURLFallback extracts a host from scheme URLs that net/url rejects. +// Go rejects unbracketed IPv6 literals in URL hosts since +// https://github.com/golang/go/commit/0c28789bd7dfc55099cac86a3212dda0d6c091f6 +func hostFromURLFallback(maybeURL string) string { + _, rest, ok := strings.Cut(maybeURL, "://") + if !ok { + return "" + } + + hostName, _, _ := strings.Cut(rest, "/") + if hostName == "" { + return "" + } + + if strings.Count(hostName, ":") > 1 && !strings.HasPrefix(hostName, "[") { + portStart := strings.LastIndex(hostName, ":") + addr, port := hostName[:portStart], hostName[portStart+1:] + if addr != "" && isPort(port) { + return net.JoinHostPort(addr, port) + } + } + + return hostName +} + +func isPort(port string) bool { + if port == "" { + return false + } + for _, r := range port { + if r < '0' || r > '9' { + return false + } + } + return true +} diff --git a/vendor/github.com/google/go-containerregistry/pkg/authn/keychain.go b/vendor/github.com/google/go-containerregistry/pkg/authn/keychain.go index ade2c63c90..a9b105e177 100644 --- a/vendor/github.com/google/go-containerregistry/pkg/authn/keychain.go +++ b/vendor/github.com/google/go-containerregistry/pkg/authn/keychain.go @@ -102,11 +102,19 @@ func (dk *defaultKeychain) ResolveContext(_ context.Context, target Resource) (A if !foundDockerConfig && os.Getenv("DOCKER_CONFIG") != "" { foundDockerConfig = fileExists(filepath.Join(os.Getenv("DOCKER_CONFIG"), "config.json")) } + configDir := os.Getenv("XDG_CONFIG_HOME") + if configDir == "" && home != "" { + configDir = filepath.Join(home, ".config") + } + podmanAuth := filepath.Join(os.Getenv("XDG_RUNTIME_DIR"), "containers/auth.json") + if (os.Getenv("XDG_RUNTIME_DIR") == "" || !fileExists(podmanAuth)) && configDir != "" { + podmanAuth = filepath.Join(configDir, "containers/auth.json") + } // If either of those locations are found, load it using Docker's // config.Load, which may fail if the config can't be parsed. // // If neither was found, look for Podman's auth at - // $REGISTRY_AUTH_FILE or $XDG_RUNTIME_DIR/containers/auth.json + // $REGISTRY_AUTH_FILE or containers/auth.json under XDG runtime/config dirs // and attempt to load it as a Docker config. // // If neither are found, fallback to Anonymous. @@ -126,7 +134,7 @@ func (dk *defaultKeychain) ResolveContext(_ context.Context, target Resource) (A if err != nil { return nil, err } - } else if path := filepath.Clean(filepath.Join(os.Getenv("XDG_RUNTIME_DIR"), "containers/auth.json")); fileExists(path) { + } else if path := filepath.Clean(podmanAuth); fileExists(path) { f, err := os.Open(path) if err != nil { return nil, err diff --git a/vendor/github.com/google/go-containerregistry/pkg/name/doc.go b/vendor/github.com/google/go-containerregistry/pkg/name/doc.go index b294794dc1..b67ad0ffcb 100644 --- a/vendor/github.com/google/go-containerregistry/pkg/name/doc.go +++ b/vendor/github.com/google/go-containerregistry/pkg/name/doc.go @@ -17,9 +17,11 @@ // What's in a name? For image references, not nearly enough! // // Image references look a lot like URLs, but they differ in that they don't -// contain the scheme (http or https), they can end with a :tag or a @digest -// (the latter being validated), and they perform defaulting for missing -// components. +// contain the scheme (http or https), they can end with a :tag, an @digest +// (the latter being validated), or both. When a reference includes both a tag +// and a digest, it is treated as a digest reference: the digest is the +// identifier used for verification, while the tag is retained only in the +// original string form. // // Since image references don't contain the scheme, we do our best to infer // if we use http or https from the given hostname. We allow http fallback for diff --git a/vendor/github.com/google/go-containerregistry/pkg/name/ref.go b/vendor/github.com/google/go-containerregistry/pkg/name/ref.go index 0a04867723..539d0ff318 100644 --- a/vendor/github.com/google/go-containerregistry/pkg/name/ref.go +++ b/vendor/github.com/google/go-containerregistry/pkg/name/ref.go @@ -37,6 +37,7 @@ type Reference interface { } // ParseReference parses the string as a reference, either by tag or digest. +// References that include both a tag and digest parse as Digest references. func ParseReference(s string, opts ...Option) (Reference, error) { if t, err := NewTag(s, opts...); err == nil { return t, nil diff --git a/vendor/github.com/google/go-containerregistry/pkg/v1/mutate/mutate.go b/vendor/github.com/google/go-containerregistry/pkg/v1/mutate/mutate.go index 09458e96cb..596c78cb26 100644 --- a/vendor/github.com/google/go-containerregistry/pkg/v1/mutate/mutate.go +++ b/vendor/github.com/google/go-containerregistry/pkg/v1/mutate/mutate.go @@ -22,7 +22,7 @@ import ( "fmt" "io" "maps" - "path/filepath" + "path" "strings" "time" @@ -37,6 +37,11 @@ import ( const whiteoutPrefix = ".wh." +// opaqueWhiteout marks a directory as opaque: all entries from lower layers under +// its parent directory are hidden. It shares the whiteoutPrefix, so it must be +// matched exactly and handled before the generic per-file whiteout logic. +const opaqueWhiteout = ".wh..wh..opq" + // Addendum contains layers and history to be appended // to a base image type Addendum struct { @@ -267,6 +272,9 @@ func extract(img v1.Image, w io.Writer) error { defer tarWriter.Close() fileMap := map[string]bool{} + // opaqueDirs holds directories opaqued by an upper layer; entries under them + // from lower (later-iterated) layers are hidden. + opaqueDirs := map[string]bool{} layers, err := img.Layers() if err != nil { @@ -277,14 +285,18 @@ func extract(img v1.Image, w io.Writer) error { // whiteout layers more efficient, since we can just keep track of the removed // files as we see .wh. layers and ignore those in previous layers. for i := len(layers) - 1; i >= 0; i-- { - if err := extractLayer(tarWriter, fileMap, layers[i]); err != nil { + if err := extractLayer(tarWriter, fileMap, opaqueDirs, layers[i]); err != nil { return err } } return nil } -func extractLayer(tarWriter *tar.Writer, fileMap map[string]bool, layer v1.Layer) error { +func extractLayer(tarWriter *tar.Writer, fileMap, opaqueDirs map[string]bool, layer v1.Layer) error { + // Opaque markers in this layer hide only lower layers, so stage them and + // promote to opaqueDirs after the whole layer is processed. + layerOpaque := map[string]bool{} + layerReader, err := layer.Uncompressed() if err != nil { return fmt.Errorf("reading layer contents: %w", err) @@ -303,7 +315,10 @@ func extractLayer(tarWriter *tar.Writer, fileMap map[string]bool, layer v1.Layer // Some tools prepend everything with "./", so if we don't Clean the // name, we may have duplicate entries, which angers tar-split. - header.Name = filepath.Clean(header.Name) + header.Name = path.Clean(header.Name) + if unsafeArchivePath(header.Name) { + return fmt.Errorf("unsafe tar path %q", header.Name) + } // Reject relative symlinks and hardlinks whose targets escape the // image rootfs. Relative targets are resolved against the symlink's @@ -313,11 +328,8 @@ func extractLayer(tarWriter *tar.Writer, fileMap map[string]bool, layer v1.Layer // Absolute targets are left as-is; see #2238 for ongoing discussion // on whether they should be pruned. if header.Typeflag == tar.TypeSymlink || header.Typeflag == tar.TypeLink { - if !filepath.IsAbs(header.Linkname) { - resolved := filepath.Clean(filepath.Join(filepath.Dir(header.Name), header.Linkname)) //nolint:gosec // G305: path is only used for validation, not file I/O - if strings.HasPrefix(resolved, "..") { - continue - } + if unsafeRelativeLink(header.Name, header.Linkname) { + continue } } @@ -326,8 +338,16 @@ func extractLayer(tarWriter *tar.Writer, fileMap map[string]bool, layer v1.Layer // prefers USTAR over PAX header.Format = tar.FormatPAX - basename := filepath.Base(header.Name) - dirname := filepath.Dir(header.Name) + basename := path.Base(header.Name) + dirname := path.Dir(header.Name) + + // An opaque marker hides all lower-layer entries under dirname. It shares + // the whiteout prefix, so handle it before the generic per-file logic. + if basename == opaqueWhiteout { + layerOpaque[dirname] = true + continue + } + tombstone := strings.HasPrefix(basename, whiteoutPrefix) if tombstone { basename = basename[len(whiteoutPrefix):] @@ -339,7 +359,7 @@ func extractLayer(tarWriter *tar.Writer, fileMap map[string]bool, layer v1.Layer if header.Typeflag == tar.TypeDir { name = header.Name } else { - name = filepath.Join(dirname, basename) + name = path.Join(dirname, basename) } if _, ok := fileMap[name]; ok && !tombstone { @@ -351,6 +371,11 @@ func extractLayer(tarWriter *tar.Writer, fileMap map[string]bool, layer v1.Layer continue } + // check for a parent directory opaqued by an upper layer + if inOpaqueDir(opaqueDirs, name) { + continue + } + // mark file as handled. non-directory implicitly tombstones // any entries with a matching (or child) name fileMap[name] = tombstone || (header.Typeflag != tar.TypeDir) @@ -366,6 +391,11 @@ func extractLayer(tarWriter *tar.Writer, fileMap map[string]bool, layer v1.Layer } } + // Opaque dirs found in this layer now hide entries in lower layers. + for d := range layerOpaque { + opaqueDirs[d] = true + } + // Drain any bytes the tar.Reader did not consume (trailing data after the // end-of-archive marker) so the underlying verifying reader reaches io.EOF // and the layer's digest is verified. Without this, a layer whose contents @@ -377,9 +407,23 @@ func extractLayer(tarWriter *tar.Writer, fileMap map[string]bool, layer v1.Layer return nil } +func inOpaqueDir(opaqueDirs map[string]bool, file string) bool { + for file != "" { + dirname := path.Dir(file) + if file == dirname { + break + } + if opaqueDirs[dirname] { + return true + } + file = dirname + } + return false +} + func inWhiteoutDir(fileMap map[string]bool, file string) bool { for file != "" { - dirname := filepath.Dir(file) + dirname := path.Dir(file) if file == dirname { break } @@ -391,6 +435,39 @@ func inWhiteoutDir(fileMap map[string]bool, file string) bool { return false } +func unsafeArchivePath(name string) bool { + clean := cleanArchivePath(name) + if clean == ".." || strings.HasPrefix(clean, "../") { + return true + } + if strings.HasPrefix(name, "\\") { + return true + } + return hasWindowsDrivePrefix(clean) +} + +func unsafeRelativeLink(name, linkname string) bool { + clean := cleanArchivePath(linkname) + if path.IsAbs(clean) { + return false + } + if hasWindowsDrivePrefix(clean) { + return true + } + resolved := path.Clean(path.Join(path.Dir(name), clean)) //nolint:gosec // G305: path is only used for validation, not file I/O + return strings.HasPrefix(resolved, "..") +} + +func cleanArchivePath(name string) string { + return path.Clean(strings.ReplaceAll(name, "\\", "/")) +} + +func hasWindowsDrivePrefix(name string) bool { + return len(name) >= 2 && + (('A' <= name[0] && name[0] <= 'Z') || ('a' <= name[0] && name[0] <= 'z')) && + name[1] == ':' +} + // Time sets all timestamps in an image to the given timestamp. func Time(img v1.Image, t time.Time) (v1.Image, error) { newImage := empty.Image diff --git a/vendor/github.com/google/go-containerregistry/pkg/v1/mutate/rebase.go b/vendor/github.com/google/go-containerregistry/pkg/v1/mutate/rebase.go index c606e0b76e..a7ac8ff535 100644 --- a/vendor/github.com/google/go-containerregistry/pkg/v1/mutate/rebase.go +++ b/vendor/github.com/google/go-containerregistry/pkg/v1/mutate/rebase.go @@ -97,13 +97,21 @@ func Rebase(orig, oldBase, newBase v1.Image) (v1.Image, error) { return nil, fmt.Errorf("could not get new base layers for new base: %w", err) } // Add new base layers. - rebasedImage, err = Append(rebasedImage, createAddendums(0, 0, newConfig.History, newBaseLayers)...) + newBaseAdds, err := createAddendums(0, 0, newConfig.History, newBaseLayers) + if err != nil { + return nil, fmt.Errorf("failed to process new base image: %w", err) + } + rebasedImage, err = Append(rebasedImage, newBaseAdds...) if err != nil { return nil, fmt.Errorf("failed to append new base image: %w", err) } // Add original layers above the old base. - rebasedImage, err = Append(rebasedImage, createAddendums(len(oldConfig.History), len(oldBaseLayers)+1, origConfig.History, origLayers)...) + origAdds, err := createAddendums(len(oldConfig.History), len(oldBaseLayers)+1, origConfig.History, origLayers) + if err != nil { + return nil, fmt.Errorf("failed to process original image: %w", err) + } + rebasedImage, err = Append(rebasedImage, origAdds...) if err != nil { return nil, fmt.Errorf("failed to append original image: %w", err) } @@ -113,7 +121,7 @@ func Rebase(orig, oldBase, newBase v1.Image) (v1.Image, error) { // createAddendums makes a list of addendums from a history and layers starting from a specific history and layer // indexes. -func createAddendums(startHistory, startLayer int, history []v1.History, layers []v1.Layer) []Addendum { +func createAddendums(startHistory, startLayer int, history []v1.History, layers []v1.Layer) ([]Addendum, error) { var adds []Addendum // History should be a superset of layers; empty layers (e.g. ENV statements) only exist in history. // They cannot be iterated identically but must be walked independently, only advancing the iterator for layers @@ -123,6 +131,9 @@ func createAddendums(startHistory, startLayer int, history []v1.History, layers var layer v1.Layer emptyLayer := history[historyIndex].EmptyLayer if !emptyLayer { + if layerIndex >= len(layers) { + return nil, fmt.Errorf("malformed image: config history references at least %d non-empty layer(s), but only %d layer(s) are present", layerIndex+1, len(layers)) + } layer = layers[layerIndex] layerIndex++ } @@ -136,9 +147,9 @@ func createAddendums(startHistory, startLayer int, history []v1.History, layers // In the event history was malformed or non-existent, append the remaining layers. for i := layerIndex; i < len(layers); i++ { if i >= startLayer { - adds = append(adds, Addendum{Layer: layers[layerIndex]}) + adds = append(adds, Addendum{Layer: layers[i]}) } } - return adds + return adds, nil } diff --git a/vendor/github.com/google/go-containerregistry/pkg/v1/remote/check.go b/vendor/github.com/google/go-containerregistry/pkg/v1/remote/check.go index b4395c2391..ac879a6737 100644 --- a/vendor/github.com/google/go-containerregistry/pkg/v1/remote/check.go +++ b/vendor/github.com/google/go-containerregistry/pkg/v1/remote/check.go @@ -68,5 +68,5 @@ func (w *writer) cancelUpload(loc string) { if err != nil { return } - _, _ = w.client.Do(req) + _, _ = w.getClient().Do(req) } diff --git a/vendor/github.com/google/go-containerregistry/pkg/v1/remote/limiter.go b/vendor/github.com/google/go-containerregistry/pkg/v1/remote/limiter.go index 54ec3b28dc..153d7cf02f 100644 --- a/vendor/github.com/google/go-containerregistry/pkg/v1/remote/limiter.go +++ b/vendor/github.com/google/go-containerregistry/pkg/v1/remote/limiter.go @@ -48,6 +48,14 @@ type limitedReadCloser struct { once sync.Once } +func (l *limitedReadCloser) Read(p []byte) (int, error) { + n, err := l.ReadCloser.Read(p) + if err != nil { + l.once.Do(l.release) + } + return n, err +} + func (l *limitedReadCloser) Close() error { err := l.ReadCloser.Close() l.once.Do(l.release) diff --git a/vendor/github.com/google/go-containerregistry/pkg/v1/remote/options.go b/vendor/github.com/google/go-containerregistry/pkg/v1/remote/options.go index 3d8bb8ddfd..749db0b68a 100644 --- a/vendor/github.com/google/go-containerregistry/pkg/v1/remote/options.go +++ b/vendor/github.com/google/go-containerregistry/pkg/v1/remote/options.go @@ -46,6 +46,7 @@ type options struct { retryPredicate retry.Predicate retryStatusCodes []int limiter *pullLimiter + referrersTagFallback bool // Only these options can overwrite Reuse()d options. platform v1.Platform @@ -108,6 +109,8 @@ const ( // ECR returns an error if n > 1000: // https://github.com/google/go-containerregistry/issues/1091 defaultPageSize = 1000 + + defaultReferrersTagFallback = true ) // DefaultTransport is based on http.DefaultTransport with modifications @@ -129,14 +132,15 @@ var DefaultTransport http.RoundTripper = &http.Transport{ func makeOptions(opts ...Option) (*options, error) { o := &options{ - transport: DefaultTransport, - platform: defaultPlatform, - context: context.Background(), - jobs: defaultJobs, - pageSize: defaultPageSize, - retryPredicate: defaultRetryPredicate, - retryBackoff: defaultRetryBackoff, - retryStatusCodes: defaultRetryStatusCodes, + transport: DefaultTransport, + platform: defaultPlatform, + context: context.Background(), + jobs: defaultJobs, + pageSize: defaultPageSize, + retryPredicate: defaultRetryPredicate, + retryBackoff: defaultRetryBackoff, + retryStatusCodes: defaultRetryStatusCodes, + referrersTagFallback: defaultReferrersTagFallback, } for _, option := range opts { @@ -328,6 +332,24 @@ func WithRetryStatusCodes(codes ...int) Option { } } +// WithReferrersTagFallback toggles the referrers tag fallback scheme, see: +// https://github.com/opencontainers/distribution-spec/blob/main/spec.md#referrers-tag-schema +// +// When enabled, pushing a manifest with a subject to a registry that doesn't +// support the Referrers API maintains an image index of referrers under a +// fallback tag, and listing referrers reads from that tag. When disabled, +// the Referrers API is required: pushing a manifest with a subject and +// listing referrers both fail against a registry that doesn't support it, +// rather than falling back to the tag scheme. +// +// The default is true. +func WithReferrersTagFallback(enabled bool) Option { + return func(o *options) error { + o.referrersTagFallback = enabled + return nil + } +} + // WithFilter sets the filter querystring for HTTP operations. func WithFilter(key string, value string) Option { return func(o *options) error { diff --git a/vendor/github.com/google/go-containerregistry/pkg/v1/remote/puller.go b/vendor/github.com/google/go-containerregistry/pkg/v1/remote/puller.go index 7da8017eec..bcb0d7350f 100644 --- a/vendor/github.com/google/go-containerregistry/pkg/v1/remote/puller.go +++ b/vendor/github.com/google/go-containerregistry/pkg/v1/remote/puller.go @@ -218,5 +218,5 @@ func (p *Puller) referrers(ctx context.Context, d name.Digest, filter map[string if err != nil { return nil, err } - return f.fetchReferrers(ctx, filter, d) + return f.fetchReferrers(ctx, filter, d, p.o.referrersTagFallback) } diff --git a/vendor/github.com/google/go-containerregistry/pkg/v1/remote/pusher.go b/vendor/github.com/google/go-containerregistry/pkg/v1/remote/pusher.go index 5675c97c8f..3a1d16f544 100644 --- a/vendor/github.com/google/go-containerregistry/pkg/v1/remote/pusher.go +++ b/vendor/github.com/google/go-containerregistry/pkg/v1/remote/pusher.go @@ -410,7 +410,7 @@ func (rw *repoWriter) writeChild(ctx context.Context, child partial.Describable, func (rw *repoWriter) manifestExists(ctx context.Context, ref name.Reference, t Taggable) (bool, error) { f := &fetcher{ target: ref.Context(), - client: rw.w.client, + client: rw.w.getClient(), } m, err := taggableToManifest(t) diff --git a/vendor/github.com/google/go-containerregistry/pkg/v1/remote/referrers.go b/vendor/github.com/google/go-containerregistry/pkg/v1/remote/referrers.go index c23e1d83b6..5a111d7fcf 100644 --- a/vendor/github.com/google/go-containerregistry/pkg/v1/remote/referrers.go +++ b/vendor/github.com/google/go-containerregistry/pkg/v1/remote/referrers.go @@ -18,6 +18,7 @@ import ( "bytes" "context" "errors" + "fmt" "net/http" "strings" @@ -46,7 +47,7 @@ func fallbackTag(d name.Digest) name.Tag { return d.Context().Tag(strings.Replace(d.DigestStr(), ":", "-", 1)) } -func (f *fetcher) fetchReferrers(ctx context.Context, filter map[string]string, d name.Digest) (v1.ImageIndex, error) { +func (f *fetcher) fetchReferrers(ctx context.Context, filter map[string]string, d name.Digest, tagFallback bool) (v1.ImageIndex, error) { // Check the Referrers API endpoint first. u := f.url("referrers", d.DigestStr()) req, err := http.NewRequestWithContext(ctx, http.MethodGet, u.String(), nil) @@ -72,6 +73,9 @@ func (f *fetcher) fetchReferrers(ctx context.Context, filter map[string]string, return nil, err } } else { + if !tagFallback { + return nil, fmt.Errorf("registry %s does not support the Referrers API and the referrers tag fallback is disabled", d.Context().RegistryStr()) + } // The registry doesn't support the Referrers API endpoint, so we'll use the fallback tag scheme. b, _, err = f.fetchManifest(ctx, fallbackTag(d), []types.MediaType{types.OCIImageIndex}) var terr *transport.Error diff --git a/vendor/github.com/google/go-containerregistry/pkg/v1/remote/transport/bearer.go b/vendor/github.com/google/go-containerregistry/pkg/v1/remote/transport/bearer.go index cbc2b1d4f9..f576ccd300 100644 --- a/vendor/github.com/google/go-containerregistry/pkg/v1/remote/transport/bearer.go +++ b/vendor/github.com/google/go-containerregistry/pkg/v1/remote/transport/bearer.go @@ -221,6 +221,16 @@ func (bt *bearerTransport) RoundTrip(in *http.Request) (*http.Response, error) { // close out old response, since we will not return it. res.Body.Close() + // For cross-host challenges (the request was redirected to another host), + // never mutate bt's shared state: accumulating this host's scope into + // bt.scopes or refreshing bt's token from bt.realm would pollute future + // same-host requests with a scope/token that belongs to a request we + // only ever intended to send to the redirected host. Instead, attempt a + // fresh per-host token exchange scoped entirely to this one request. + if !matchesHost(bt.registry.RegistryStr(), in, bt.scheme) { + return bt.handleCrossHostChallenge(in, challenges) + } + newScopes := []string{} bt.mx.Lock() got := stringSet(bt.scopes) @@ -247,18 +257,7 @@ func (bt *bearerTransport) RoundTrip(in *http.Request) (*http.Response, error) { if err = bt.refresh(in.Context()); err != nil { return nil, err } - // Re-attach the freshly fetched token, but only when the request is - // still talking to the registry we authenticated against. matchesHost - // guards against forwarding the Authorization header across an - // http.Client-level redirect to a different host: a malicious or - // compromised registry can 302 the request to an attacker-controlled - // host, answer the follow-up with a Bearer challenge, and harvest the - // token if we re-attach it unconditionally. For a cross-host request - // fall back to sendRequest(), which omits the credential, rather than - // leaking it to a host we never logged in to. - if !matchesHost(bt.registry.RegistryStr(), in, bt.scheme) { - return sendRequest() - } + bt.mx.RLock() tok := bt.bearer.RegistryToken bt.mx.RUnlock() @@ -269,6 +268,65 @@ func (bt *bearerTransport) RoundTrip(in *http.Request) (*http.Response, error) { return res, err } +// handleCrossHostChallenge performs a per-host bearer token exchange when +// the request has been redirected to a host different from bt.registry. It +// parses the redirected host's own WWW-Authenticate Bearer challenge, fetches +// a token from that host's realm using anonymous auth (the original registry's +// credentials are never forwarded cross-host), and applies the token only to +// this request. +// +// If no usable Bearer challenge is present, or the token exchange fails, the +// request is retried without an Authorization header. +func (bt *bearerTransport) handleCrossHostChallenge(in *http.Request, challenges []authchallenge.Challenge) (*http.Response, error) { + for _, wac := range challenges { + if strings.ToLower(wac.Scheme) != "bearer" { + continue + } + if _, ok := wac.Parameters["realm"]; !ok { + continue + } + + redirectedReg, err := name.NewRegistry(in.URL.Host, name.WeakValidation) + if err != nil { + logs.Warn.Printf("cross-host redirect: invalid host %q: %v", in.URL.Host, err) + continue + } + + // Build a transport.Challenge from the redirected host's WWW-Authenticate + // parameters. fromChallenge validates the realm URL (SSRF guard). + pr := &Challenge{ + Scheme: wac.Scheme, + Parameters: wac.Parameters, + Insecure: in.URL.Scheme == "http", + } + scope := wac.Parameters["scope"] + // TODO: use a keychain to resolve credentials for the redirected host so + // that token endpoints requiring auth are also supported. For now, anonymous + // auth covers the common case where the redirected host's token endpoint is + // public. See https://github.com/google/go-containerregistry/issues/2359. + tmpBt, err := fromChallenge(redirectedReg, authn.Anonymous, bt.inner, pr, scope) + if err != nil { + logs.Warn.Printf("cross-host bearer challenge setup for %q failed: %v", in.URL.Host, err) + continue + } + + if err := tmpBt.refresh(in.Context()); err != nil { + logs.Warn.Printf("cross-host bearer exchange for %q failed: %v", in.URL.Host, err) + continue + } + + tmpBt.mx.RLock() + tok := tmpBt.bearer.RegistryToken + tmpBt.mx.RUnlock() + + in.Header.Set("Authorization", fmt.Sprintf("Bearer %s", tok)) + return bt.inner.RoundTrip(in) + } + + // No usable bearer challenge; retry without credentials. + return bt.inner.RoundTrip(in) +} + // It's unclear which authentication flow to use based purely on the protocol, // so we rely on heuristics and fallbacks to support as many registries as possible. // The basic token exchange is attempted first, falling back to the oauth flow. diff --git a/vendor/github.com/google/go-containerregistry/pkg/v1/remote/write.go b/vendor/github.com/google/go-containerregistry/pkg/v1/remote/write.go index 4ff30a8cb1..01e9c767bb 100644 --- a/vendor/github.com/google/go-containerregistry/pkg/v1/remote/write.go +++ b/vendor/github.com/google/go-containerregistry/pkg/v1/remote/write.go @@ -61,12 +61,21 @@ type writer struct { backoff Backoff predicate retry.Predicate + referrersTagFallback bool + scopeLock sync.Mutex // Keep track of scopes that we have already requested. scopeSet map[string]struct{} scopes []string } +// getClient returns the HTTP client, blocking on scope updates. +func (w *writer) getClient() *http.Client { + w.scopeLock.Lock() + defer w.scopeLock.Unlock() + return w.client +} + // makeDeleteClient returns an HTTP client whose token includes the "delete" // action so that registries requiring an explicit delete permission grant // access for manifest deletion. @@ -106,15 +115,16 @@ func makeWriter(ctx context.Context, repo name.Repository, ls []v1.Layer, o *opt scopeSet[scope] = struct{}{} } return &writer{ - repo: repo, - client: &http.Client{Transport: tr}, - auth: auth, - transport: o.transport, - progress: o.progress, - backoff: o.retryBackoff, - predicate: o.retryPredicate, - scopes: scopes, - scopeSet: scopeSet, + repo: repo, + client: &http.Client{Transport: tr}, + auth: auth, + transport: o.transport, + progress: o.progress, + backoff: o.retryBackoff, + predicate: o.retryPredicate, + referrersTagFallback: o.referrersTagFallback, + scopes: scopes, + scopeSet: scopeSet, }, nil } @@ -205,7 +215,7 @@ func (w *writer) checkExistingBlob(ctx context.Context, h v1.Hash) (bool, error) return false, err } - resp, err := w.client.Do(req.WithContext(ctx)) + resp, err := w.getClient().Do(req.WithContext(ctx)) if err != nil { return false, err } @@ -243,7 +253,7 @@ func (w *writer) initiateUpload(ctx context.Context, from, mount, origin string) return "", false, err } req.Header.Set("Content-Type", "application/json") - resp, err := w.client.Do(req.WithContext(ctx)) + resp, err := w.getClient().Do(req.WithContext(ctx)) if err != nil { if from != "" { // https://github.com/google/go-containerregistry/issues/1679 @@ -323,7 +333,7 @@ func (w *writer) streamBlob(ctx context.Context, layer v1.Layer, streamLocation } req.Header.Set("Content-Type", "application/octet-stream") - resp, err := w.client.Do(req.WithContext(ctx)) + resp, err := w.getClient().Do(req.WithContext(ctx)) if err != nil { return "", err } @@ -355,7 +365,7 @@ func (w *writer) commitBlob(ctx context.Context, location, digest string) error } req.Header.Set("Content-Type", "application/octet-stream") - resp, err := w.client.Do(req.WithContext(ctx)) + resp, err := w.getClient().Do(req.WithContext(ctx)) if err != nil { return err } @@ -514,7 +524,7 @@ func (w *writer) commitSubjectReferrers(ctx context.Context, sub name.Digest, ad return err } req.Header.Set("Accept", string(types.OCIImageIndex)) - resp, err := w.client.Do(req.WithContext(ctx)) + resp, err := w.getClient().Do(req.WithContext(ctx)) if err != nil { return err } @@ -527,6 +537,9 @@ func (w *writer) commitSubjectReferrers(ctx context.Context, sub name.Digest, ad // The registry supports Referrers API. The registry is responsible for updating the referrers list. return nil } + if !w.referrersTagFallback { + return fmt.Errorf("registry %s does not support the Referrers API and the referrers tag fallback is disabled", w.repo.RegistryStr()) + } // The registry doesn't support Referrers API, we need to update the manifest tagged with the fallback tag. // Make the request to GET the current manifest. @@ -537,7 +550,7 @@ func (w *writer) commitSubjectReferrers(ctx context.Context, sub name.Digest, ad return err } req.Header.Set("Accept", string(types.OCIImageIndex)) - resp, err = w.client.Do(req.WithContext(ctx)) + resp, err = w.getClient().Do(req.WithContext(ctx)) if err != nil { return err } @@ -624,7 +637,7 @@ func (w *writer) commitManifest(ctx context.Context, t Taggable, ref name.Refere } req.Header.Set("Content-Type", string(desc.MediaType)) - resp, err := w.client.Do(req.WithContext(ctx)) + resp, err := w.getClient().Do(req.WithContext(ctx)) if err != nil { return err } diff --git a/vendor/github.com/google/go-containerregistry/pkg/v1/tarball/image.go b/vendor/github.com/google/go-containerregistry/pkg/v1/tarball/image.go index 9b0350b121..76b61c687c 100644 --- a/vendor/github.com/google/go-containerregistry/pkg/v1/tarball/image.go +++ b/vendor/github.com/google/go-containerregistry/pkg/v1/tarball/image.go @@ -304,6 +304,9 @@ func (i *uncompressedImage) LayerByDiffID(h v1.Hash) (partial.UncompressedLayer, } for idx, diffID := range cfg.RootFS.DiffIDs { if diffID == h { + if idx >= len(i.imgDescriptor.Layers) { + return nil, fmt.Errorf("config has %d rootfs.diff_id(s) but tarball manifest only references %d layer(s); the config may not describe a runnable image", len(cfg.RootFS.DiffIDs), len(i.imgDescriptor.Layers)) + } // Technically the media type should be 'application/tar' but given that our // v1.Layer doesn't force consumers to care about whether the layer is compressed // we should be fine returning the DockerLayer media type diff --git a/vendor/github.com/google/go-containerregistry/pkg/v1/tarball/write.go b/vendor/github.com/google/go-containerregistry/pkg/v1/tarball/write.go index 062268a5b9..4b1bfd0a61 100644 --- a/vendor/github.com/google/go-containerregistry/pkg/v1/tarball/write.go +++ b/vendor/github.com/google/go-containerregistry/pkg/v1/tarball/write.go @@ -28,6 +28,7 @@ import ( "github.com/google/go-containerregistry/pkg/name" v1 "github.com/google/go-containerregistry/pkg/v1" "github.com/google/go-containerregistry/pkg/v1/partial" + "github.com/google/go-containerregistry/pkg/v1/types" ) // WriteToFile writes in the compressed format to a tarball, on disk. @@ -184,7 +185,7 @@ func writeImagesToTar(imageToTags map[v1.Image][]string, m []byte, size int64, w // gunzip expects certain file extensions: // https://www.gnu.org/software/gzip/manual/html_node/Overview.html - layerFiles[i] = fmt.Sprintf("%s.tar.gz", hex) + layerFiles[i] = hex + layerExtension(l) if _, ok := seenLayerDigests[hex]; ok { continue @@ -244,7 +245,7 @@ func calculateManifest(imageToTags map[v1.Image][]string) (m Manifest, err error // gunzip expects certain file extensions: // https://www.gnu.org/software/gzip/manual/html_node/Overview.html - layerFiles[i] = fmt.Sprintf("%s.tar.gz", hex) + layerFiles[i] = hex + layerExtension(l) // Add to LayerSources if it's a foreign layer. desc, err := partial.BlobDescriptor(img, d) @@ -463,3 +464,16 @@ func calculateSingleFileInTarSize(in int64) (out int64) { out += 512 return out } + +func layerExtension(l v1.Layer) string { + mt, _ := l.MediaType() + switch mt { + case types.OCILayerZStd: + return ".tar.zst" + case types.OCIUncompressedLayer, types.OCIUncompressedRestrictedLayer, types.DockerUncompressedLayer: + return ".tar" + default: + // historically, only gzip compressed tar was supported, so this is the fallback + return ".tar.gz" + } +} diff --git a/vendor/github.com/klauspost/compress/huff0/decompress_amd64.go b/vendor/github.com/klauspost/compress/huff0/decompress_amd64.go index 2d6ef64be1..7035d656d9 100644 --- a/vendor/github.com/klauspost/compress/huff0/decompress_amd64.go +++ b/vendor/github.com/klauspost/compress/huff0/decompress_amd64.go @@ -1,222 +1,49 @@ //go:build amd64 && !appengine && !noasm && gc -// This file contains the specialisation of Decoder.Decompress4X -// and Decoder.Decompress1X that use an asm implementation of thir main loops. +// amd64 stubs and dispatch for the asm loops used by decompress_asm.go. package huff0 import ( - "errors" - "fmt" - "github.com/klauspost/compress/internal/cpuinfo" ) -// decompress4x_main_loop_x86 is an x86 assembler implementation +// decompress4x_main_loop_amd64 is an x86 assembler implementation // of Decompress4X when tablelog > 8. // //go:noescape func decompress4x_main_loop_amd64(ctx *decompress4xContext) -// decompress4x_8b_loop_x86 is an x86 assembler implementation +// decompress4x_8b_main_loop_amd64 is an x86 assembler implementation // of Decompress4X when tablelog <= 8 which decodes 4 entries // per loop. // //go:noescape func decompress4x_8b_main_loop_amd64(ctx *decompress4xContext) -// fallback8BitSize is the size where using Go version is faster. -const fallback8BitSize = 800 - -type decompress4xContext struct { - pbr *[4]bitReaderShifted - peekBits uint8 - out *byte - dstEvery int - tbl *dEntrySingle - decoded int - limit *byte -} - -// Decompress4X will decompress a 4X encoded stream. -// The length of the supplied input must match the end of a block exactly. -// The *capacity* of the dst slice must match the destination size of -// the uncompressed data exactly. -func (d *Decoder) Decompress4X(dst, src []byte) ([]byte, error) { - if len(d.dt.single) == 0 { - return nil, errors.New("no table loaded") - } - if len(src) < 6+(4*1) { - return nil, errors.New("input too small") - } - - use8BitTables := d.actualTableLog <= 8 - if cap(dst) < fallback8BitSize && use8BitTables { - return d.decompress4X8bit(dst, src) - } - - var br [4]bitReaderShifted - // Decode "jump table" - start := 6 - for i := range 3 { - length := int(src[i*2]) | (int(src[i*2+1]) << 8) - if start+length >= len(src) { - return nil, errors.New("truncated input (or invalid offset)") - } - err := br[i].init(src[start : start+length]) - if err != nil { - return nil, err - } - start += length - } - err := br[3].init(src[start:]) - if err != nil { - return nil, err - } - - // destination, offset to match first output - dstSize := cap(dst) - dst = dst[:dstSize] - out := dst - dstEvery := (dstSize + 3) / 4 - - const tlSize = 1 << tableLogMax - const tlMask = tlSize - 1 - single := d.dt.single[:tlSize] - - var decoded int - - if len(out) > 4*4 && !(br[0].off < 4 || br[1].off < 4 || br[2].off < 4 || br[3].off < 4) { - ctx := decompress4xContext{ - pbr: &br, - peekBits: uint8((64 - d.actualTableLog) & 63), // see: bitReaderShifted.peekBitsFast() - out: &out[0], - dstEvery: dstEvery, - tbl: &single[0], - limit: &out[dstEvery-4], // Always stop decoding when first buffer gets here to avoid writing OOB on last. - } - if use8BitTables { - decompress4x_8b_main_loop_amd64(&ctx) - } else { - decompress4x_main_loop_amd64(&ctx) - } - - decoded = ctx.decoded - out = out[decoded/4:] - } - - // Decode remaining. - remainBytes := dstEvery - (decoded / 4) - for i := range br { - offset := dstEvery * i - endsAt := min(offset+remainBytes, len(out)) - br := &br[i] - bitsLeft := br.remaining() - for bitsLeft > 0 { - br.fill() - if offset >= endsAt { - return nil, errors.New("corruption detected: stream overrun 4") - } - - // Read value and increment offset. - val := br.peekBitsFast(d.actualTableLog) - v := single[val&tlMask].entry - nBits := uint8(v) - br.advance(nBits) - bitsLeft -= uint(nBits) - out[offset] = uint8(v >> 8) - offset++ - } - if offset != endsAt { - return nil, fmt.Errorf("corruption detected: short output block %d, end %d != %d", i, offset, endsAt) - } - decoded += offset - dstEvery*i - err = br.close() - if err != nil { - return nil, err - } - } - if dstSize != decoded { - return nil, errors.New("corruption detected: short output block") - } - return dst, nil -} - -// decompress4x_main_loop_x86 is an x86 assembler implementation +// decompress1x_main_loop_amd64 is an x86 assembler implementation // of Decompress1X when tablelog > 8. // //go:noescape func decompress1x_main_loop_amd64(ctx *decompress1xContext) -// decompress4x_main_loop_x86 is an x86 with BMI2 assembler implementation +// decompress1x_main_loop_bmi2 is an x86 with BMI2 assembler implementation // of Decompress1X when tablelog > 8. // //go:noescape func decompress1x_main_loop_bmi2(ctx *decompress1xContext) -type decompress1xContext struct { - pbr *bitReaderShifted - peekBits uint8 - out *byte - outCap int - tbl *dEntrySingle - decoded int +func decompress4x_main_loop_asm(ctx *decompress4xContext) { + decompress4x_main_loop_amd64(ctx) } -// Error reported by asm implementations -const error_max_decoded_size_exeeded = -1 - -// Decompress1X will decompress a 1X encoded stream. -// The cap of the output buffer will be the maximum decompressed size. -// The length of the supplied input must match the end of a block exactly. -func (d *Decoder) Decompress1X(dst, src []byte) ([]byte, error) { - if len(d.dt.single) == 0 { - return nil, errors.New("no table loaded") - } - var br bitReaderShifted - err := br.init(src) - if err != nil { - return dst, err - } - maxDecodedSize := cap(dst) - dst = dst[:maxDecodedSize] - - const tlSize = 1 << tableLogMax - const tlMask = tlSize - 1 - - if maxDecodedSize >= 4 { - ctx := decompress1xContext{ - pbr: &br, - out: &dst[0], - outCap: maxDecodedSize, - peekBits: uint8((64 - d.actualTableLog) & 63), // see: bitReaderShifted.peekBitsFast() - tbl: &d.dt.single[0], - } - - if cpuinfo.HasBMI2() { - decompress1x_main_loop_bmi2(&ctx) - } else { - decompress1x_main_loop_amd64(&ctx) - } - if ctx.decoded == error_max_decoded_size_exeeded { - return nil, ErrMaxDecodedSizeExceeded - } - - dst = dst[:ctx.decoded] - } +func decompress4x_8b_main_loop_asm(ctx *decompress4xContext) { + decompress4x_8b_main_loop_amd64(ctx) +} - // br < 8, so uint8 is fine - bitsLeft := uint8(br.off)*8 + 64 - br.bitsRead - for bitsLeft > 0 { - br.fill() - if len(dst) >= maxDecodedSize { - br.close() - return nil, ErrMaxDecodedSizeExceeded - } - v := d.dt.single[br.peekBitsFast(d.actualTableLog)&tlMask] - nBits := uint8(v.entry) - br.advance(nBits) - bitsLeft -= nBits - dst = append(dst, uint8(v.entry>>8)) +func decompress1x_main_loop_asm(ctx *decompress1xContext) { + if cpuinfo.HasBMI2() { + decompress1x_main_loop_bmi2(ctx) + } else { + decompress1x_main_loop_amd64(ctx) } - return dst, br.close() } diff --git a/vendor/github.com/klauspost/compress/huff0/decompress_amd64.s b/vendor/github.com/klauspost/compress/huff0/decompress_amd64.s index c4c7ab2d1f..c5d4a710a0 100644 --- a/vendor/github.com/klauspost/compress/huff0/decompress_amd64.s +++ b/vendor/github.com/klauspost/compress/huff0/decompress_amd64.s @@ -1,6 +1,6 @@ -// Code generated by command: go run gen.go -out ../decompress_amd64.s -pkg=huff0. DO NOT EDIT. +// Code generated by command: go run gen.go -out ../decompress.s -arch amd64,arm64 -pkg=huff0. DO NOT EDIT. -//go:build amd64 && !appengine && !noasm && gc +//go:build !appengine && !noasm && gc // func decompress4x_main_loop_amd64(ctx *decompress4xContext) TEXT ·decompress4x_main_loop_amd64(SB), $0-8 diff --git a/vendor/github.com/klauspost/compress/huff0/decompress_arm64.go b/vendor/github.com/klauspost/compress/huff0/decompress_arm64.go new file mode 100644 index 0000000000..8ba3c810e6 --- /dev/null +++ b/vendor/github.com/klauspost/compress/huff0/decompress_arm64.go @@ -0,0 +1,37 @@ +//go:build arm64 && !appengine && !noasm && gc + +// arm64 stubs and dispatch for the asm loops used by decompress_asm.go. +// The asm (decompress_arm64.s) is generated by the avo arm64 lowering +// printer from the same source as the amd64 asm; see _generate/gen.go. +package huff0 + +// decompress4x_main_loop_arm64 is an arm64 assembler implementation +// of Decompress4X when tablelog > 8. +// +//go:noescape +func decompress4x_main_loop_arm64(ctx *decompress4xContext) + +// decompress4x_8b_main_loop_arm64 is an arm64 assembler implementation +// of Decompress4X when tablelog <= 8 which decodes 4 entries +// per loop. +// +//go:noescape +func decompress4x_8b_main_loop_arm64(ctx *decompress4xContext) + +// decompress1x_main_loop_arm64 is an arm64 assembler implementation +// of Decompress1X when tablelog > 8. +// +//go:noescape +func decompress1x_main_loop_arm64(ctx *decompress1xContext) + +func decompress4x_main_loop_asm(ctx *decompress4xContext) { + decompress4x_main_loop_arm64(ctx) +} + +func decompress4x_8b_main_loop_asm(ctx *decompress4xContext) { + decompress4x_8b_main_loop_arm64(ctx) +} + +func decompress1x_main_loop_asm(ctx *decompress1xContext) { + decompress1x_main_loop_arm64(ctx) +} diff --git a/vendor/github.com/klauspost/compress/huff0/decompress_arm64.s b/vendor/github.com/klauspost/compress/huff0/decompress_arm64.s new file mode 100644 index 0000000000..e16012721a --- /dev/null +++ b/vendor/github.com/klauspost/compress/huff0/decompress_arm64.s @@ -0,0 +1,851 @@ +// Code generated by command: go run gen.go -out ../decompress.s -arch amd64,arm64 -pkg=huff0. DO NOT EDIT. +// EXPERIMENTAL arm64 output lowered from an amd64 avo program. + +//go:build arm64 && !appengine && !noasm && gc + +// func decompress4x_main_loop_amd64(ctx *decompress4xContext) +TEXT ·decompress4x_main_loop_arm64(SB), $0-8 + // Preload values + MOVD ctx+0(FP), R0 + MOVBU 8(R0), R6 + MOVD 16(R0), R3 + MOVD 48(R0), R5 + MOVD 24(R0), R7 + MOVD 32(R0), R8 + MOVD (R0), R9 + + // Main loop +main_loop: + MOVD $0, R2 + CMP R5, R3 + CSET GE, R16 + BFI $0, R16, $8, R2 + + // br0.fillFast32() + MOVD 32(R9), R10 + MOVBU 40(R9), R11 + CMP $0x20, R11 + BLS skip_fill0 + MOVD 24(R9), R0 + SUB $0x20, R11, R11 + SUB $0x04, R0, R0 + MOVD (R9), R12 + + // b.value |= uint64(low) << (b.bitsRead & 63) + ADD R12, R0, R15 + MOVWU (R15), R12 + MOVD R11, R1 + LSL R1, R12, R12 + MOVD R0, 24(R9) + ORR R12, R10, R10 + + // exhausted += (br0.off < 4) + CMP $0x04, R0 + CSINC HS, R2, R2, R16 + BFI $0, R16, $8, R2 + +skip_fill0: + // val0 := br0.peekTopBits(peekBits) + MOVD R10, R12 + MOVD R6, R1 + LSR R1, R12, R12 + + // v0 := table[val0&mask] + ADD R12<<1, R8, R15 + MOVHU (R15), R1 + + // br0.advance(uint8(v0.entry) + UBFX $8, R1, $8, R16 + BFI $0, R16, $8, R0 + LSL R1, R10, R10 + ADD R1, R11, R15 + BFI $0, R15, $8, R11 + + // val1 := br0.peekTopBits(peekBits) + MOVD R6, R1 + MOVD R10, R12 + LSR R1, R12, R12 + + // v1 := table[val1&mask] + ADD R12<<1, R8, R15 + MOVHU (R15), R1 + + // br0.advance(uint8(v1.entry)) + UBFX $8, R1, $8, R16 + BFI $8, R16, $8, R0 + LSL R1, R10, R10 + ADD R1, R11, R15 + BFI $0, R15, $8, R11 + + // these two writes get coalesced + // out[id * dstEvery + 0] = uint8(v0.entry >> 8) + // out[id * dstEvery + 1] = uint8(v1.entry >> 8) + MOVH R0, (R3) + + // update the bitreader structure + MOVD R10, 32(R9) + MOVB R11, 40(R9) + + // br1.fillFast32() + MOVD 80(R9), R10 + MOVBU 88(R9), R11 + CMP $0x20, R11 + BLS skip_fill1 + MOVD 72(R9), R0 + SUB $0x20, R11, R11 + SUB $0x04, R0, R0 + MOVD 48(R9), R12 + + // b.value |= uint64(low) << (b.bitsRead & 63) + ADD R12, R0, R15 + MOVWU (R15), R12 + MOVD R11, R1 + LSL R1, R12, R12 + MOVD R0, 72(R9) + ORR R12, R10, R10 + + // exhausted += (br1.off < 4) + CMP $0x04, R0 + CSINC HS, R2, R2, R16 + BFI $0, R16, $8, R2 + +skip_fill1: + // val0 := br1.peekTopBits(peekBits) + MOVD R10, R12 + MOVD R6, R1 + LSR R1, R12, R12 + + // v0 := table[val0&mask] + ADD R12<<1, R8, R15 + MOVHU (R15), R1 + + // br1.advance(uint8(v0.entry) + UBFX $8, R1, $8, R16 + BFI $0, R16, $8, R0 + LSL R1, R10, R10 + ADD R1, R11, R15 + BFI $0, R15, $8, R11 + + // val1 := br1.peekTopBits(peekBits) + MOVD R6, R1 + MOVD R10, R12 + LSR R1, R12, R12 + + // v1 := table[val1&mask] + ADD R12<<1, R8, R15 + MOVHU (R15), R1 + + // br1.advance(uint8(v1.entry)) + UBFX $8, R1, $8, R16 + BFI $8, R16, $8, R0 + LSL R1, R10, R10 + ADD R1, R11, R15 + BFI $0, R15, $8, R11 + + // these two writes get coalesced + // out[id * dstEvery + 0] = uint8(v0.entry >> 8) + // out[id * dstEvery + 1] = uint8(v1.entry >> 8) + ADD R7, R3, R15 + MOVH R0, (R15) + + // update the bitreader structure + MOVD R10, 80(R9) + MOVB R11, 88(R9) + + // br2.fillFast32() + MOVD 128(R9), R10 + MOVBU 136(R9), R11 + CMP $0x20, R11 + BLS skip_fill2 + MOVD 120(R9), R0 + SUB $0x20, R11, R11 + SUB $0x04, R0, R0 + MOVD 96(R9), R12 + + // b.value |= uint64(low) << (b.bitsRead & 63) + ADD R12, R0, R15 + MOVWU (R15), R12 + MOVD R11, R1 + LSL R1, R12, R12 + MOVD R0, 120(R9) + ORR R12, R10, R10 + + // exhausted += (br2.off < 4) + CMP $0x04, R0 + CSINC HS, R2, R2, R16 + BFI $0, R16, $8, R2 + +skip_fill2: + // val0 := br2.peekTopBits(peekBits) + MOVD R10, R12 + MOVD R6, R1 + LSR R1, R12, R12 + + // v0 := table[val0&mask] + ADD R12<<1, R8, R15 + MOVHU (R15), R1 + + // br2.advance(uint8(v0.entry) + UBFX $8, R1, $8, R16 + BFI $0, R16, $8, R0 + LSL R1, R10, R10 + ADD R1, R11, R15 + BFI $0, R15, $8, R11 + + // val1 := br2.peekTopBits(peekBits) + MOVD R6, R1 + MOVD R10, R12 + LSR R1, R12, R12 + + // v1 := table[val1&mask] + ADD R12<<1, R8, R15 + MOVHU (R15), R1 + + // br2.advance(uint8(v1.entry)) + UBFX $8, R1, $8, R16 + BFI $8, R16, $8, R0 + LSL R1, R10, R10 + ADD R1, R11, R15 + BFI $0, R15, $8, R11 + + // these two writes get coalesced + // out[id * dstEvery + 0] = uint8(v0.entry >> 8) + // out[id * dstEvery + 1] = uint8(v1.entry >> 8) + ADD R7<<1, R3, R15 + MOVH R0, (R15) + + // update the bitreader structure + MOVD R10, 128(R9) + MOVB R11, 136(R9) + + // br3.fillFast32() + MOVD 176(R9), R10 + MOVBU 184(R9), R11 + CMP $0x20, R11 + BLS skip_fill3 + MOVD 168(R9), R0 + SUB $0x20, R11, R11 + SUB $0x04, R0, R0 + MOVD 144(R9), R12 + + // b.value |= uint64(low) << (b.bitsRead & 63) + ADD R12, R0, R15 + MOVWU (R15), R12 + MOVD R11, R1 + LSL R1, R12, R12 + MOVD R0, 168(R9) + ORR R12, R10, R10 + + // exhausted += (br3.off < 4) + CMP $0x04, R0 + CSINC HS, R2, R2, R16 + BFI $0, R16, $8, R2 + +skip_fill3: + // val0 := br3.peekTopBits(peekBits) + MOVD R10, R12 + MOVD R6, R1 + LSR R1, R12, R12 + + // v0 := table[val0&mask] + ADD R12<<1, R8, R15 + MOVHU (R15), R1 + + // br3.advance(uint8(v0.entry) + UBFX $8, R1, $8, R16 + BFI $0, R16, $8, R0 + LSL R1, R10, R10 + ADD R1, R11, R15 + BFI $0, R15, $8, R11 + + // val1 := br3.peekTopBits(peekBits) + MOVD R6, R1 + MOVD R10, R12 + LSR R1, R12, R12 + + // v1 := table[val1&mask] + ADD R12<<1, R8, R15 + MOVHU (R15), R1 + + // br3.advance(uint8(v1.entry)) + UBFX $8, R1, $8, R16 + BFI $8, R16, $8, R0 + LSL R1, R10, R10 + ADD R1, R11, R15 + BFI $0, R15, $8, R11 + + // these two writes get coalesced + // out[id * dstEvery + 0] = uint8(v0.entry >> 8) + // out[id * dstEvery + 1] = uint8(v1.entry >> 8) + ADD R7<<1, R7, R1 + ADD R1, R3, R15 + MOVH R0, (R15) + + // update the bitreader structure + MOVD R10, 176(R9) + MOVB R11, 184(R9) + ADD $0x02, R3, R3 + AND $0xff, R2, R15 + AND $0xff, R2, R16 + TST R16, R15 + BEQ main_loop + MOVD ctx+0(FP), R0 + MOVD 16(R0), R16 + SUB R16, R3, R3 + LSL $0x02, R3, R3 + MOVD R3, 40(R0) + RET + +// func decompress4x_8b_main_loop_amd64(ctx *decompress4xContext) +TEXT ·decompress4x_8b_main_loop_arm64(SB), $0-8 + // Preload values + MOVD ctx+0(FP), R1 + MOVBU 8(R1), R6 + MOVD 16(R1), R3 + MOVD 48(R1), R5 + MOVD 24(R1), R7 + MOVD 32(R1), R8 + MOVD (R1), R9 + + // Main loop +main_loop: + MOVD $0, R2 + CMP R5, R3 + CSET GE, R16 + BFI $0, R16, $8, R2 + + // br0.fillFast32() + MOVD 32(R9), R10 + MOVBU 40(R9), R11 + CMP $0x20, R11 + BLS skip_fill0 + MOVD 24(R9), R12 + SUB $0x20, R11, R11 + SUB $0x04, R12, R12 + MOVD (R9), R13 + + // b.value |= uint64(low) << (b.bitsRead & 63) + ADD R13, R12, R15 + MOVWU (R15), R13 + MOVD R11, R1 + LSL R1, R13, R13 + MOVD R12, 24(R9) + ORR R13, R10, R10 + + // exhausted += (br0.off < 4) + CMP $0x04, R12 + CSINC HS, R2, R2, R16 + BFI $0, R16, $8, R2 + +skip_fill0: + // val0 := br0.peekTopBits(peekBits) + MOVD R10, R12 + MOVD R6, R1 + LSR R1, R12, R12 + + // v0 := table[val0&mask] + ADD R12<<1, R8, R15 + MOVHU (R15), R1 + + // br0.advance(uint8(v0.entry) + UBFX $8, R1, $8, R16 + BFI $0, R16, $8, R0 + LSL R1, R10, R10 + ADD R1, R11, R15 + BFI $0, R15, $8, R11 + + // val1 := br0.peekTopBits(peekBits) + MOVD R10, R12 + MOVD R6, R1 + LSR R1, R12, R12 + + // v1 := table[val0&mask] + ADD R12<<1, R8, R15 + MOVHU (R15), R1 + + // br0.advance(uint8(v1.entry) + UBFX $8, R1, $8, R16 + BFI $8, R16, $8, R0 + LSL R1, R10, R10 + ADD R1, R11, R15 + BFI $0, R15, $8, R11 + REVW R0, R0 + + // val2 := br0.peekTopBits(peekBits) + MOVD R10, R12 + MOVD R6, R1 + LSR R1, R12, R12 + + // v2 := table[val0&mask] + ADD R12<<1, R8, R15 + MOVHU (R15), R1 + + // br0.advance(uint8(v2.entry) + UBFX $8, R1, $8, R16 + BFI $8, R16, $8, R0 + LSL R1, R10, R10 + ADD R1, R11, R15 + BFI $0, R15, $8, R11 + + // val3 := br0.peekTopBits(peekBits) + MOVD R10, R12 + MOVD R6, R1 + LSR R1, R12, R12 + + // v3 := table[val0&mask] + ADD R12<<1, R8, R15 + MOVHU (R15), R1 + + // br0.advance(uint8(v3.entry) + UBFX $8, R1, $8, R16 + BFI $0, R16, $8, R0 + LSL R1, R10, R10 + ADD R1, R11, R15 + BFI $0, R15, $8, R11 + REVW R0, R0 + + // these four writes get coalesced + // out[id * dstEvery + 0] = uint8(v0.entry >> 8) + // out[id * dstEvery + 1] = uint8(v1.entry >> 8) + // out[id * dstEvery + 3] = uint8(v2.entry >> 8) + // out[id * dstEvery + 4] = uint8(v3.entry >> 8) + MOVW R0, (R3) + + // update the bitreader structure + MOVD R10, 32(R9) + MOVB R11, 40(R9) + + // br1.fillFast32() + MOVD 80(R9), R10 + MOVBU 88(R9), R11 + CMP $0x20, R11 + BLS skip_fill1 + MOVD 72(R9), R12 + SUB $0x20, R11, R11 + SUB $0x04, R12, R12 + MOVD 48(R9), R13 + + // b.value |= uint64(low) << (b.bitsRead & 63) + ADD R13, R12, R15 + MOVWU (R15), R13 + MOVD R11, R1 + LSL R1, R13, R13 + MOVD R12, 72(R9) + ORR R13, R10, R10 + + // exhausted += (br1.off < 4) + CMP $0x04, R12 + CSINC HS, R2, R2, R16 + BFI $0, R16, $8, R2 + +skip_fill1: + // val0 := br1.peekTopBits(peekBits) + MOVD R10, R12 + MOVD R6, R1 + LSR R1, R12, R12 + + // v0 := table[val0&mask] + ADD R12<<1, R8, R15 + MOVHU (R15), R1 + + // br1.advance(uint8(v0.entry) + UBFX $8, R1, $8, R16 + BFI $0, R16, $8, R0 + LSL R1, R10, R10 + ADD R1, R11, R15 + BFI $0, R15, $8, R11 + + // val1 := br1.peekTopBits(peekBits) + MOVD R10, R12 + MOVD R6, R1 + LSR R1, R12, R12 + + // v1 := table[val0&mask] + ADD R12<<1, R8, R15 + MOVHU (R15), R1 + + // br1.advance(uint8(v1.entry) + UBFX $8, R1, $8, R16 + BFI $8, R16, $8, R0 + LSL R1, R10, R10 + ADD R1, R11, R15 + BFI $0, R15, $8, R11 + REVW R0, R0 + + // val2 := br1.peekTopBits(peekBits) + MOVD R10, R12 + MOVD R6, R1 + LSR R1, R12, R12 + + // v2 := table[val0&mask] + ADD R12<<1, R8, R15 + MOVHU (R15), R1 + + // br1.advance(uint8(v2.entry) + UBFX $8, R1, $8, R16 + BFI $8, R16, $8, R0 + LSL R1, R10, R10 + ADD R1, R11, R15 + BFI $0, R15, $8, R11 + + // val3 := br1.peekTopBits(peekBits) + MOVD R10, R12 + MOVD R6, R1 + LSR R1, R12, R12 + + // v3 := table[val0&mask] + ADD R12<<1, R8, R15 + MOVHU (R15), R1 + + // br1.advance(uint8(v3.entry) + UBFX $8, R1, $8, R16 + BFI $0, R16, $8, R0 + LSL R1, R10, R10 + ADD R1, R11, R15 + BFI $0, R15, $8, R11 + REVW R0, R0 + + // these four writes get coalesced + // out[id * dstEvery + 0] = uint8(v0.entry >> 8) + // out[id * dstEvery + 1] = uint8(v1.entry >> 8) + // out[id * dstEvery + 3] = uint8(v2.entry >> 8) + // out[id * dstEvery + 4] = uint8(v3.entry >> 8) + ADD R7, R3, R15 + MOVW R0, (R15) + + // update the bitreader structure + MOVD R10, 80(R9) + MOVB R11, 88(R9) + + // br2.fillFast32() + MOVD 128(R9), R10 + MOVBU 136(R9), R11 + CMP $0x20, R11 + BLS skip_fill2 + MOVD 120(R9), R12 + SUB $0x20, R11, R11 + SUB $0x04, R12, R12 + MOVD 96(R9), R13 + + // b.value |= uint64(low) << (b.bitsRead & 63) + ADD R13, R12, R15 + MOVWU (R15), R13 + MOVD R11, R1 + LSL R1, R13, R13 + MOVD R12, 120(R9) + ORR R13, R10, R10 + + // exhausted += (br2.off < 4) + CMP $0x04, R12 + CSINC HS, R2, R2, R16 + BFI $0, R16, $8, R2 + +skip_fill2: + // val0 := br2.peekTopBits(peekBits) + MOVD R10, R12 + MOVD R6, R1 + LSR R1, R12, R12 + + // v0 := table[val0&mask] + ADD R12<<1, R8, R15 + MOVHU (R15), R1 + + // br2.advance(uint8(v0.entry) + UBFX $8, R1, $8, R16 + BFI $0, R16, $8, R0 + LSL R1, R10, R10 + ADD R1, R11, R15 + BFI $0, R15, $8, R11 + + // val1 := br2.peekTopBits(peekBits) + MOVD R10, R12 + MOVD R6, R1 + LSR R1, R12, R12 + + // v1 := table[val0&mask] + ADD R12<<1, R8, R15 + MOVHU (R15), R1 + + // br2.advance(uint8(v1.entry) + UBFX $8, R1, $8, R16 + BFI $8, R16, $8, R0 + LSL R1, R10, R10 + ADD R1, R11, R15 + BFI $0, R15, $8, R11 + REVW R0, R0 + + // val2 := br2.peekTopBits(peekBits) + MOVD R10, R12 + MOVD R6, R1 + LSR R1, R12, R12 + + // v2 := table[val0&mask] + ADD R12<<1, R8, R15 + MOVHU (R15), R1 + + // br2.advance(uint8(v2.entry) + UBFX $8, R1, $8, R16 + BFI $8, R16, $8, R0 + LSL R1, R10, R10 + ADD R1, R11, R15 + BFI $0, R15, $8, R11 + + // val3 := br2.peekTopBits(peekBits) + MOVD R10, R12 + MOVD R6, R1 + LSR R1, R12, R12 + + // v3 := table[val0&mask] + ADD R12<<1, R8, R15 + MOVHU (R15), R1 + + // br2.advance(uint8(v3.entry) + UBFX $8, R1, $8, R16 + BFI $0, R16, $8, R0 + LSL R1, R10, R10 + ADD R1, R11, R15 + BFI $0, R15, $8, R11 + REVW R0, R0 + + // these four writes get coalesced + // out[id * dstEvery + 0] = uint8(v0.entry >> 8) + // out[id * dstEvery + 1] = uint8(v1.entry >> 8) + // out[id * dstEvery + 3] = uint8(v2.entry >> 8) + // out[id * dstEvery + 4] = uint8(v3.entry >> 8) + ADD R7<<1, R3, R15 + MOVW R0, (R15) + + // update the bitreader structure + MOVD R10, 128(R9) + MOVB R11, 136(R9) + + // br3.fillFast32() + MOVD 176(R9), R10 + MOVBU 184(R9), R11 + CMP $0x20, R11 + BLS skip_fill3 + MOVD 168(R9), R12 + SUB $0x20, R11, R11 + SUB $0x04, R12, R12 + MOVD 144(R9), R13 + + // b.value |= uint64(low) << (b.bitsRead & 63) + ADD R13, R12, R15 + MOVWU (R15), R13 + MOVD R11, R1 + LSL R1, R13, R13 + MOVD R12, 168(R9) + ORR R13, R10, R10 + + // exhausted += (br3.off < 4) + CMP $0x04, R12 + CSINC HS, R2, R2, R16 + BFI $0, R16, $8, R2 + +skip_fill3: + // val0 := br3.peekTopBits(peekBits) + MOVD R10, R12 + MOVD R6, R1 + LSR R1, R12, R12 + + // v0 := table[val0&mask] + ADD R12<<1, R8, R15 + MOVHU (R15), R1 + + // br3.advance(uint8(v0.entry) + UBFX $8, R1, $8, R16 + BFI $0, R16, $8, R0 + LSL R1, R10, R10 + ADD R1, R11, R15 + BFI $0, R15, $8, R11 + + // val1 := br3.peekTopBits(peekBits) + MOVD R10, R12 + MOVD R6, R1 + LSR R1, R12, R12 + + // v1 := table[val0&mask] + ADD R12<<1, R8, R15 + MOVHU (R15), R1 + + // br3.advance(uint8(v1.entry) + UBFX $8, R1, $8, R16 + BFI $8, R16, $8, R0 + LSL R1, R10, R10 + ADD R1, R11, R15 + BFI $0, R15, $8, R11 + REVW R0, R0 + + // val2 := br3.peekTopBits(peekBits) + MOVD R10, R12 + MOVD R6, R1 + LSR R1, R12, R12 + + // v2 := table[val0&mask] + ADD R12<<1, R8, R15 + MOVHU (R15), R1 + + // br3.advance(uint8(v2.entry) + UBFX $8, R1, $8, R16 + BFI $8, R16, $8, R0 + LSL R1, R10, R10 + ADD R1, R11, R15 + BFI $0, R15, $8, R11 + + // val3 := br3.peekTopBits(peekBits) + MOVD R10, R12 + MOVD R6, R1 + LSR R1, R12, R12 + + // v3 := table[val0&mask] + ADD R12<<1, R8, R15 + MOVHU (R15), R1 + + // br3.advance(uint8(v3.entry) + UBFX $8, R1, $8, R16 + BFI $0, R16, $8, R0 + LSL R1, R10, R10 + ADD R1, R11, R15 + BFI $0, R15, $8, R11 + REVW R0, R0 + + // these four writes get coalesced + // out[id * dstEvery + 0] = uint8(v0.entry >> 8) + // out[id * dstEvery + 1] = uint8(v1.entry >> 8) + // out[id * dstEvery + 3] = uint8(v2.entry >> 8) + // out[id * dstEvery + 4] = uint8(v3.entry >> 8) + ADD R7<<1, R7, R1 + ADD R1, R3, R15 + MOVW R0, (R15) + + // update the bitreader structure + MOVD R10, 176(R9) + MOVB R11, 184(R9) + ADD $0x04, R3, R3 + AND $0xff, R2, R15 + AND $0xff, R2, R16 + TST R16, R15 + BEQ main_loop + MOVD ctx+0(FP), R0 + MOVD 16(R0), R16 + SUB R16, R3, R3 + LSL $0x02, R3, R3 + MOVD R3, 40(R0) + RET + +// func decompress1x_main_loop_amd64(ctx *decompress1xContext) +TEXT ·decompress1x_main_loop_arm64(SB), $0-8 + MOVD ctx+0(FP), R1 + MOVD 16(R1), R2 + MOVD 24(R1), R3 + CMP $0x04, R3 + BLO error_max_decoded_size_exceeded + ADD R3, R2, R3 + MOVD (R1), R5 + MOVD (R5), R7 + MOVD 24(R5), R8 + MOVD 32(R5), R9 + MOVBU 40(R5), R10 + MOVD 32(R1), R5 + MOVBU 8(R1), R6 + JMP loop_condition + +main_loop: + // Check if we have room for 4 bytes in the output buffer + ADD $4, R2, R1 + CMP R3, R1 + BGE error_max_decoded_size_exceeded + + // Decode 4 values + CMP $0x20, R10 + BLT bitReader_fillFast_1_end + SUB $0x20, R10, R10 + SUB $0x04, R8, R8 + ADD R8, R7, R15 + MOVWU (R15), R11 + MOVD R10, R1 + LSL R1, R11, R11 + ORR R11, R9, R9 + +bitReader_fillFast_1_end: + MOVD R6, R1 + MOVD R9, R11 + LSR R1, R11, R11 + ADD R11<<1, R5, R15 + MOVHU (R15), R1 + UBFX $8, R1, $8, R16 + BFI $0, R16, $8, R0 + MOVBU R1, R1 + ADD R1, R10, R10 + LSL R1, R9, R9 + MOVD R6, R1 + MOVD R9, R11 + LSR R1, R11, R11 + ADD R11<<1, R5, R15 + MOVHU (R15), R1 + UBFX $8, R1, $8, R16 + BFI $8, R16, $8, R0 + MOVBU R1, R1 + ADD R1, R10, R10 + LSL R1, R9, R9 + REVW R0, R0 + CMP $0x20, R10 + BLT bitReader_fillFast_2_end + SUB $0x20, R10, R10 + SUB $0x04, R8, R8 + ADD R8, R7, R15 + MOVWU (R15), R11 + MOVD R10, R1 + LSL R1, R11, R11 + ORR R11, R9, R9 + +bitReader_fillFast_2_end: + MOVD R6, R1 + MOVD R9, R11 + LSR R1, R11, R11 + ADD R11<<1, R5, R15 + MOVHU (R15), R1 + UBFX $8, R1, $8, R16 + BFI $8, R16, $8, R0 + MOVBU R1, R1 + ADD R1, R10, R10 + LSL R1, R9, R9 + MOVD R6, R1 + MOVD R9, R11 + LSR R1, R11, R11 + ADD R11<<1, R5, R15 + MOVHU (R15), R1 + UBFX $8, R1, $8, R16 + BFI $0, R16, $8, R0 + MOVBU R1, R1 + ADD R1, R10, R10 + LSL R1, R9, R9 + REVW R0, R0 + + // Store the decoded values + MOVW R0, (R2) + ADD $0x04, R2, R2 + +loop_condition: + CMP $0x08, R8 + BGE main_loop + + // Update ctx structure + MOVD ctx+0(FP), R0 + MOVD 16(R0), R16 + SUB R16, R2, R2 + MOVD R2, 40(R0) + MOVD (R0), R0 + MOVD R8, 24(R0) + MOVD R9, 32(R0) + MOVB R10, 40(R0) + RET + + // Report error +error_max_decoded_size_exceeded: + MOVD ctx+0(FP), R0 + MOVD $-1, R1 + MOVD R1, 40(R0) + RET + +// skipped decompress1x_main_loop_bmi2 (generic twin preferred on arm64) diff --git a/vendor/github.com/klauspost/compress/huff0/decompress_asm.go b/vendor/github.com/klauspost/compress/huff0/decompress_asm.go new file mode 100644 index 0000000000..4854dd4365 --- /dev/null +++ b/vendor/github.com/klauspost/compress/huff0/decompress_asm.go @@ -0,0 +1,193 @@ +//go:build (amd64 || arm64) && !appengine && !noasm && gc + +// This file contains the specialisation of Decoder.Decompress4X +// and Decoder.Decompress1X that use an asm implementation of their main loops. +// The asm function stubs and any per-arch dispatch live in decompress_amd64.go +// and decompress_arm64.go. +package huff0 + +import ( + "errors" + "fmt" +) + +// fallback8BitSize is the size where using Go version is faster. +const fallback8BitSize = 800 + +type decompress4xContext struct { + pbr *[4]bitReaderShifted + peekBits uint8 + out *byte + dstEvery int + tbl *dEntrySingle + decoded int + limit *byte +} + +// Decompress4X will decompress a 4X encoded stream. +// The length of the supplied input must match the end of a block exactly. +// The *capacity* of the dst slice must match the destination size of +// the uncompressed data exactly. +func (d *Decoder) Decompress4X(dst, src []byte) ([]byte, error) { + if len(d.dt.single) == 0 { + return nil, errors.New("no table loaded") + } + if len(src) < 6+(4*1) { + return nil, errors.New("input too small") + } + + use8BitTables := d.actualTableLog <= 8 + if cap(dst) < fallback8BitSize && use8BitTables { + return d.decompress4X8bit(dst, src) + } + + var br [4]bitReaderShifted + // Decode "jump table" + start := 6 + for i := range 3 { + length := int(src[i*2]) | (int(src[i*2+1]) << 8) + if start+length >= len(src) { + return nil, errors.New("truncated input (or invalid offset)") + } + err := br[i].init(src[start : start+length]) + if err != nil { + return nil, err + } + start += length + } + err := br[3].init(src[start:]) + if err != nil { + return nil, err + } + + // destination, offset to match first output + dstSize := cap(dst) + dst = dst[:dstSize] + out := dst + dstEvery := (dstSize + 3) / 4 + + const tlSize = 1 << tableLogMax + const tlMask = tlSize - 1 + single := d.dt.single[:tlSize] + + var decoded int + + if len(out) > 4*4 && !(br[0].off < 4 || br[1].off < 4 || br[2].off < 4 || br[3].off < 4) { + ctx := decompress4xContext{ + pbr: &br, + peekBits: uint8((64 - d.actualTableLog) & 63), // see: bitReaderShifted.peekBitsFast() + out: &out[0], + dstEvery: dstEvery, + tbl: &single[0], + limit: &out[dstEvery-4], // Always stop decoding when first buffer gets here to avoid writing OOB on last. + } + if use8BitTables { + decompress4x_8b_main_loop_asm(&ctx) + } else { + decompress4x_main_loop_asm(&ctx) + } + + decoded = ctx.decoded + out = out[decoded/4:] + } + + // Decode remaining. + remainBytes := dstEvery - (decoded / 4) + for i := range br { + offset := dstEvery * i + endsAt := min(offset+remainBytes, len(out)) + br := &br[i] + bitsLeft := br.remaining() + for bitsLeft > 0 { + br.fill() + if offset >= endsAt { + return nil, errors.New("corruption detected: stream overrun 4") + } + + // Read value and increment offset. + val := br.peekBitsFast(d.actualTableLog) + v := single[val&tlMask].entry + nBits := uint8(v) + br.advance(nBits) + bitsLeft -= uint(nBits) + out[offset] = uint8(v >> 8) + offset++ + } + if offset != endsAt { + return nil, fmt.Errorf("corruption detected: short output block %d, end %d != %d", i, offset, endsAt) + } + decoded += offset - dstEvery*i + err = br.close() + if err != nil { + return nil, err + } + } + if dstSize != decoded { + return nil, errors.New("corruption detected: short output block") + } + return dst, nil +} + +type decompress1xContext struct { + pbr *bitReaderShifted + peekBits uint8 + out *byte + outCap int + tbl *dEntrySingle + decoded int +} + +// Error reported by asm implementations +const error_max_decoded_size_exeeded = -1 + +// Decompress1X will decompress a 1X encoded stream. +// The cap of the output buffer will be the maximum decompressed size. +// The length of the supplied input must match the end of a block exactly. +func (d *Decoder) Decompress1X(dst, src []byte) ([]byte, error) { + if len(d.dt.single) == 0 { + return nil, errors.New("no table loaded") + } + var br bitReaderShifted + err := br.init(src) + if err != nil { + return dst, err + } + maxDecodedSize := cap(dst) + dst = dst[:maxDecodedSize] + + const tlSize = 1 << tableLogMax + const tlMask = tlSize - 1 + + if maxDecodedSize >= 4 { + ctx := decompress1xContext{ + pbr: &br, + out: &dst[0], + outCap: maxDecodedSize, + peekBits: uint8((64 - d.actualTableLog) & 63), // see: bitReaderShifted.peekBitsFast() + tbl: &d.dt.single[0], + } + + decompress1x_main_loop_asm(&ctx) + if ctx.decoded == error_max_decoded_size_exeeded { + return nil, ErrMaxDecodedSizeExceeded + } + + dst = dst[:ctx.decoded] + } + + // br < 8, so uint8 is fine + bitsLeft := uint8(br.off)*8 + 64 - br.bitsRead + for bitsLeft > 0 { + br.fill() + if len(dst) >= maxDecodedSize { + br.close() + return nil, ErrMaxDecodedSizeExceeded + } + v := d.dt.single[br.peekBitsFast(d.actualTableLog)&tlMask] + nBits := uint8(v.entry) + br.advance(nBits) + bitsLeft -= nBits + dst = append(dst, uint8(v.entry>>8)) + } + return dst, br.close() +} diff --git a/vendor/github.com/klauspost/compress/huff0/decompress_generic.go b/vendor/github.com/klauspost/compress/huff0/decompress_generic.go index 6103923222..e1bca5c686 100644 --- a/vendor/github.com/klauspost/compress/huff0/decompress_generic.go +++ b/vendor/github.com/klauspost/compress/huff0/decompress_generic.go @@ -1,4 +1,4 @@ -//go:build !amd64 || appengine || !gc || noasm +//go:build (!amd64 && !arm64) || appengine || !gc || noasm // This file contains a generic implementation of Decoder.Decompress4X. package huff0 diff --git a/vendor/github.com/klauspost/compress/zstd/blockdec.go b/vendor/github.com/klauspost/compress/zstd/blockdec.go index 2329e996f8..51f9da0387 100644 --- a/vendor/github.com/klauspost/compress/zstd/blockdec.go +++ b/vendor/github.com/klauspost/compress/zstd/blockdec.go @@ -400,8 +400,9 @@ func (b *blockDec) decodeLiterals(in []byte, hist *history) (remain []byte, err } } var err error - // Use our out buffer. - huff.MaxDecodedSize = litRegenSize + // Decoder.Decompress* uses cap(dst) for the size limit. Do not write + // MaxDecodedSize on hist.huffTree: with a trained dictionary that + // pointer aliases the shared dict.litEnc and concurrent DecodeAll races. if fourStreams { literals, err = huff.Decoder().Decompress4X(b.literalBuf[:0:litRegenSize], literals) } else { @@ -673,10 +674,6 @@ func (b *blockDec) executeSequences(hist *history) error { hbytes := hist.b if len(hbytes) > hist.windowSize { hbytes = hbytes[len(hbytes)-hist.windowSize:] - // We do not need history anymore. - if hist.dict != nil { - hist.dict.content = nil - } } hist.decoders.windowSize = hist.windowSize hist.decoders.out = b.dst[:0] diff --git a/vendor/github.com/klauspost/compress/zstd/dict.go b/vendor/github.com/klauspost/compress/zstd/dict.go index 4f1c4938cd..67f40e7914 100644 --- a/vendor/github.com/klauspost/compress/zstd/dict.go +++ b/vendor/github.com/klauspost/compress/zstd/dict.go @@ -296,40 +296,81 @@ func BuildDict(o BuildDictOptions) ([]byte, error) { if offset > 3 { newOffsets[offset-3]++ } else { - newOffsets[uint32(o.Offsets[offset-1])]++ + // Repeat codes reference the training Offsets. Skip unset + // (zero) entries so they are not ranked as real offsets. + prev := o.Offsets[offset-1] + if prev > 0 { + newOffsets[uint32(prev)]++ + } } } } // Find most used offsets. var sortedOffsets []uint32 for k := range newOffsets { + if k == 0 { + continue + } sortedOffsets = append(sortedOffsets, k) } sort.Slice(sortedOffsets, func(i, j int) bool { a, b := sortedOffsets[i], sortedOffsets[j] - if a == b { + ca, cb := newOffsets[a], newOffsets[b] + if ca == cb { // Prefer the longer offset - return sortedOffsets[i] > sortedOffsets[j] + return a > b } - return newOffsets[sortedOffsets[i]] > newOffsets[sortedOffsets[j]] + return ca > cb }) - if len(sortedOffsets) > 3 { - if debug { - print("Offsets:") - for i, v := range sortedOffsets { - if i > 20 { - break - } - printf("[%d: %d],", v, newOffsets[v]) + if debug { + print("Offsets:") + for i, v := range sortedOffsets { + if i > 20 { + break } - println("") + printf("[%d: %d],", v, newOffsets[v]) + } + println("") + } + // Dictionary recent-offsets must be three positive values within the + // history. Ranked matches may be fewer (or empty when only unset + // repeat codes were seen), so fill remaining slots with defaults. + used := make(map[int]bool, 3) + var finalOffsets [3]int + nOff := 0 + for _, v := range sortedOffsets { + iv := int(v) + if iv <= 0 || iv > len(hist) || used[iv] { + continue + } + finalOffsets[nOff] = iv + used[iv] = true + nOff++ + if nOff == 3 { + break } - - sortedOffsets = sortedOffsets[:3] } - for i, v := range sortedOffsets { - o.Offsets[i] = int(v) + for _, def := range []int{1, 4, 8} { + if nOff == 3 { + break + } + if def <= len(hist) && !used[def] { + finalOffsets[nOff] = def + used[def] = true + nOff++ + } + } + for def := 1; nOff < 3 && def <= len(hist); def++ { + if !used[def] { + finalOffsets[nOff] = def + used[def] = true + nOff++ + } + } + if nOff < 3 { + return nil, fmt.Errorf("could not determine 3 valid dictionary offsets (history size %d)", len(hist)) } + o.Offsets = finalOffsets if debug { println("New repeat offsets", o.Offsets) } @@ -337,6 +378,9 @@ func BuildDict(o BuildDictOptions) ([]byte, error) { if nUsed == 0 || seqs == 0 { return nil, fmt.Errorf("%d blocks, %d sequences found", nUsed, seqs) } + if litTotal == 0 { + return nil, errors.New("0 literals found") + } if debug { println("Sequences:", seqs, "Blocks:", nUsed, "Literals:", litTotal) } @@ -517,11 +561,10 @@ func BuildDict(o BuildDictOptions) ([]byte, error) { out.Write(binary.LittleEndian.AppendUint32(nil, uint32(o.Offsets[1]))) out.Write(binary.LittleEndian.AppendUint32(nil, uint32(o.Offsets[2]))) out.Write(hist) + if _, err := loadDict(out.Bytes()); err != nil { + return nil, fmt.Errorf("built dictionary failed validation: %w", err) + } if debug { - _, err := loadDict(out.Bytes()) - if err != nil { - panic(err) - } i, err := InspectDictionary(out.Bytes()) if err != nil { panic(err) diff --git a/vendor/github.com/klauspost/compress/zstd/seqdec_amd64.s b/vendor/github.com/klauspost/compress/zstd/seqdec_amd64.s index 3fc381c7a7..4d3188ff49 100644 --- a/vendor/github.com/klauspost/compress/zstd/seqdec_amd64.s +++ b/vendor/github.com/klauspost/compress/zstd/seqdec_amd64.s @@ -2081,7 +2081,7 @@ sequenceDecs_decodeSync_amd64_match_len_ofs_ok: MOVQ 16(SP), R13 // Check if we have enough space in s.out - LEAQ (AX)(R13*1), R14 + LEAQ 16(AX)(R13*1), R14 ADDQ R10, R14 CMPQ R14, 32(SP) JA error_not_enough_space @@ -2601,7 +2601,7 @@ sequenceDecs_decodeSync_bmi2_match_len_ofs_ok: MOVQ 16(SP), R13 // Check if we have enough space in s.out - LEAQ (CX)(R13*1), R14 + LEAQ 16(CX)(R13*1), R14 ADDQ R9, R14 CMPQ R14, 32(SP) JA error_not_enough_space diff --git a/vendor/github.com/klauspost/compress/zstd/seqdec_arm64.s b/vendor/github.com/klauspost/compress/zstd/seqdec_arm64.s index a468e5fc2c..6f54ef21ba 100644 --- a/vendor/github.com/klauspost/compress/zstd/seqdec_arm64.s +++ b/vendor/github.com/klauspost/compress/zstd/seqdec_arm64.s @@ -12,7 +12,7 @@ TEXT ·sequenceDecs_decode_arm64(SB), $8-32 MOVD (R1), R0 MOVD 32(R1), R5 ADD R5, R0, R0 - MOVD R0, (RSP) + MOVD R0, 8(RSP) MOVD ctx+16(FP), R0 MOVD 72(R0), R6 MOVD 80(R0), R7 @@ -24,7 +24,7 @@ TEXT ·sequenceDecs_decode_arm64(SB), $8-32 MOVD 160(R0), R12 sequenceDecs_decode_amd64_main_loop: - MOVD (RSP), R13 + MOVD 8(RSP), R13 // Fill bitreader to have enough for the offset and match length. CMP $0x08, R5 @@ -60,7 +60,8 @@ sequenceDecs_decode_amd64_fill_end: MOVD R3, R1 MOVD R2, R14 LSL R1, R14, R14 - UBFX $8, R0, $8, R1 + UBFX $8, R0, $8, R16 + BFI $0, R16, $8, R1 LSR $0x20, R0, R0 TST R1, R1 BEQ sequenceDecs_decode_amd64_of_update_zero @@ -81,7 +82,8 @@ sequenceDecs_decode_amd64_of_update_zero: MOVD R3, R1 MOVD R2, R14 LSL R1, R14, R14 - UBFX $8, R0, $8, R1 + UBFX $8, R0, $8, R16 + BFI $0, R16, $8, R1 LSR $0x20, R0, R0 TST R1, R1 BEQ sequenceDecs_decode_amd64_ml_update_zero @@ -131,7 +133,8 @@ sequenceDecs_decode_amd64_fill_2_end: MOVD R3, R1 MOVD R2, R14 LSL R1, R14, R14 - UBFX $8, R0, $8, R1 + UBFX $8, R0, $8, R16 + BFI $0, R16, $8, R1 LSR $0x20, R0, R0 TST R1, R1 BEQ sequenceDecs_decode_amd64_ll_update_zero @@ -148,7 +151,7 @@ sequenceDecs_decode_amd64_ll_update_zero: MOVD R0, (R9) // Fill bitreader for state updates - MOVD R13, (RSP) + MOVD R13, 8(RSP) MOVD R8, R0 LSR $0x08, R0, R0 MOVBU R0, R0 @@ -166,7 +169,7 @@ sequenceDecs_decode_amd64_ll_update_zero: NEG R1, R16 ROR R16, R14, R14 MOVD $0x00000001, R4 - MOVB R13, R1 + BFI $0, R13, $8, R1 LSLW R1, R4, R4 SUBW $1, R4, R4 AND R4, R14, R14 @@ -187,7 +190,7 @@ sequenceDecs_decode_amd64_ll_update_zero: NEG R1, R16 ROR R16, R14, R14 MOVD $0x00000001, R4 - MOVB R13, R1 + BFI $0, R13, $8, R1 LSLW R1, R4, R4 SUBW $1, R4, R4 AND R4, R14, R14 @@ -208,7 +211,7 @@ sequenceDecs_decode_amd64_ll_update_zero: NEG R1, R16 ROR R16, R14, R14 MOVD $0x00000001, R4 - MOVB R13, R1 + BFI $0, R13, $8, R1 LSLW R1, R4, R4 SUBW $1, R4, R4 AND R4, R14, R14 @@ -360,7 +363,7 @@ TEXT ·sequenceDecs_decode_56_arm64(SB), $8-32 MOVD (R1), R0 MOVD 32(R1), R5 ADD R5, R0, R0 - MOVD R0, (RSP) + MOVD R0, 8(RSP) MOVD ctx+16(FP), R0 MOVD 72(R0), R6 MOVD 80(R0), R7 @@ -372,7 +375,7 @@ TEXT ·sequenceDecs_decode_56_arm64(SB), $8-32 MOVD 160(R0), R12 sequenceDecs_decode_56_amd64_main_loop: - MOVD (RSP), R13 + MOVD 8(RSP), R13 // Fill bitreader to have enough for the offset and match length. CMP $0x08, R5 @@ -408,7 +411,8 @@ sequenceDecs_decode_56_amd64_fill_end: MOVD R3, R1 MOVD R2, R14 LSL R1, R14, R14 - UBFX $8, R0, $8, R1 + UBFX $8, R0, $8, R16 + BFI $0, R16, $8, R1 LSR $0x20, R0, R0 TST R1, R1 BEQ sequenceDecs_decode_56_amd64_of_update_zero @@ -429,7 +433,8 @@ sequenceDecs_decode_56_amd64_of_update_zero: MOVD R3, R1 MOVD R2, R14 LSL R1, R14, R14 - UBFX $8, R0, $8, R1 + UBFX $8, R0, $8, R16 + BFI $0, R16, $8, R1 LSR $0x20, R0, R0 TST R1, R1 BEQ sequenceDecs_decode_56_amd64_ml_update_zero @@ -450,7 +455,8 @@ sequenceDecs_decode_56_amd64_ml_update_zero: MOVD R3, R1 MOVD R2, R14 LSL R1, R14, R14 - UBFX $8, R0, $8, R1 + UBFX $8, R0, $8, R16 + BFI $0, R16, $8, R1 LSR $0x20, R0, R0 TST R1, R1 BEQ sequenceDecs_decode_56_amd64_ll_update_zero @@ -467,7 +473,7 @@ sequenceDecs_decode_56_amd64_ll_update_zero: MOVD R0, (R9) // Fill bitreader for state updates - MOVD R13, (RSP) + MOVD R13, 8(RSP) MOVD R8, R0 LSR $0x08, R0, R0 MOVBU R0, R0 @@ -485,7 +491,7 @@ sequenceDecs_decode_56_amd64_ll_update_zero: NEG R1, R16 ROR R16, R14, R14 MOVD $0x00000001, R4 - MOVB R13, R1 + BFI $0, R13, $8, R1 LSLW R1, R4, R4 SUBW $1, R4, R4 AND R4, R14, R14 @@ -506,7 +512,7 @@ sequenceDecs_decode_56_amd64_ll_update_zero: NEG R1, R16 ROR R16, R14, R14 MOVD $0x00000001, R4 - MOVB R13, R1 + BFI $0, R13, $8, R1 LSLW R1, R4, R4 SUBW $1, R4, R4 AND R4, R14, R14 @@ -527,7 +533,7 @@ sequenceDecs_decode_56_amd64_ll_update_zero: NEG R1, R16 ROR R16, R14, R14 MOVD $0x00000001, R4 - MOVB R13, R1 + BFI $0, R13, $8, R1 LSLW R1, R4, R4 SUBW $1, R4, R4 AND R4, R14, R14 @@ -766,13 +772,14 @@ copy_4_small: JMP copy_4_move_8through16 copy_4_move_3: - MOVH (R13), R10 - MOVB 2(R13), R11 - MOVH R10, (R3) - MOVB R11, 2(R3) - ADD R12, R13, R13 - ADD R12, R3, R3 - JMP copy_4_end + MOVHU (R13), R10 + MOVBU 2(R13), R16 + BFI $0, R16, $8, R11 + MOVH R10, (R3) + MOVB R11, 2(R3) + ADD R12, R13, R13 + ADD R12, R3, R3 + JMP copy_4_end copy_4_move_4through7: MOVWU (R13), R10 @@ -834,24 +841,27 @@ copy_5_small: JMP copy_5_move_8through16 copy_5_move_1or2: - MOVB (R13), R14 - ADD R10, R13, R15 - MOVB -1(R15), R4 - MOVB R14, (R3) - ADD R10, R3, R15 - MOVB R4, -1(R15) - ADD R10, R13, R13 - ADD R10, R3, R3 - JMP copy_5_end + MOVBU (R13), R16 + BFI $0, R16, $8, R14 + ADD R10, R13, R15 + MOVBU -1(R15), R16 + BFI $0, R16, $8, R4 + MOVB R14, (R3) + ADD R10, R3, R15 + MOVB R4, -1(R15) + ADD R10, R13, R13 + ADD R10, R3, R3 + JMP copy_5_end copy_5_move_3: - MOVH (R13), R14 - MOVB 2(R13), R4 - MOVH R14, (R3) - MOVB R4, 2(R3) - ADD R10, R13, R13 - ADD R10, R3, R3 - JMP copy_5_end + MOVHU (R13), R14 + MOVBU 2(R13), R16 + BFI $0, R16, $8, R4 + MOVH R14, (R3) + MOVB R4, 2(R3) + ADD R10, R13, R13 + ADD R10, R3, R3 + JMP copy_5_end copy_5_move_4through7: MOVWU (R13), R14 @@ -906,12 +916,13 @@ copy_overlapping_match: ADD R12, R6, R6 copy_slow_3: - MOVB (R10), R11 - MOVB R11, (R3) - ADD $1, R10, R10 - ADD $1, R3, R3 - SUBS $1, R12, R12 - BNE copy_slow_3 + MOVBU (R10), R16 + BFI $0, R16, $8, R11 + MOVB R11, (R3) + ADD $1, R10, R10 + ADD $1, R3, R3 + SUBS $1, R12, R12 + BNE copy_slow_3 handle_loop: ADD $0x18, R0, R0 @@ -1016,24 +1027,27 @@ copy_1_small: JMP copy_1_move_8through16 copy_1_move_1or2: - MOVB (R5), R13 - ADD R10, R5, R15 - MOVB -1(R15), R14 - MOVB R13, (R3) - ADD R10, R3, R15 - MOVB R14, -1(R15) - ADD R10, R5, R5 - ADD R10, R3, R3 - JMP copy_1_end + MOVBU (R5), R16 + BFI $0, R16, $8, R13 + ADD R10, R5, R15 + MOVBU -1(R15), R16 + BFI $0, R16, $8, R14 + MOVB R13, (R3) + ADD R10, R3, R15 + MOVB R14, -1(R15) + ADD R10, R5, R5 + ADD R10, R3, R3 + JMP copy_1_end copy_1_move_3: - MOVH (R5), R13 - MOVB 2(R5), R14 - MOVH R13, (R3) - MOVB R14, 2(R3) - ADD R10, R5, R5 - ADD R10, R3, R3 - JMP copy_1_end + MOVHU (R5), R13 + MOVBU 2(R5), R16 + BFI $0, R16, $8, R14 + MOVH R13, (R3) + MOVB R14, 2(R3) + ADD R10, R5, R5 + ADD R10, R3, R3 + JMP copy_1_end copy_1_move_4through7: MOVWU (R5), R13 @@ -1104,13 +1118,14 @@ copy_4_small: JMP copy_4_move_8through16 copy_4_move_3: - MOVH (R13), R10 - MOVB 2(R13), R11 - MOVH R10, (R3) - MOVB R11, 2(R3) - ADD R12, R13, R13 - ADD R12, R3, R3 - JMP copy_4_end + MOVHU (R13), R10 + MOVBU 2(R13), R16 + BFI $0, R16, $8, R11 + MOVH R10, (R3) + MOVB R11, 2(R3) + ADD R12, R13, R13 + ADD R12, R3, R3 + JMP copy_4_end copy_4_move_4through7: MOVWU (R13), R10 @@ -1172,24 +1187,27 @@ copy_5_small: JMP copy_5_move_8through16 copy_5_move_1or2: - MOVB (R13), R14 - ADD R10, R13, R15 - MOVB -1(R15), R4 - MOVB R14, (R3) - ADD R10, R3, R15 - MOVB R4, -1(R15) - ADD R10, R13, R13 - ADD R10, R3, R3 - JMP copy_5_end + MOVBU (R13), R16 + BFI $0, R16, $8, R14 + ADD R10, R13, R15 + MOVBU -1(R15), R16 + BFI $0, R16, $8, R4 + MOVB R14, (R3) + ADD R10, R3, R15 + MOVB R4, -1(R15) + ADD R10, R13, R13 + ADD R10, R3, R3 + JMP copy_5_end copy_5_move_3: - MOVH (R13), R14 - MOVB 2(R13), R4 - MOVH R14, (R3) - MOVB R4, 2(R3) - ADD R10, R13, R13 - ADD R10, R3, R3 - JMP copy_5_end + MOVHU (R13), R14 + MOVBU 2(R13), R16 + BFI $0, R16, $8, R4 + MOVH R14, (R3) + MOVB R4, 2(R3) + ADD R10, R13, R13 + ADD R10, R3, R3 + JMP copy_5_end copy_5_move_4through7: MOVWU (R13), R14 @@ -1257,24 +1275,27 @@ copy_2_small: JMP copy_2_move_8through16 copy_2_move_1or2: - MOVB (R10), R11 - ADD R12, R10, R15 - MOVB -1(R15), R13 - MOVB R11, (R3) - ADD R12, R3, R15 - MOVB R13, -1(R15) - ADD R12, R10, R10 - ADD R12, R3, R3 - JMP copy_2_end + MOVBU (R10), R16 + BFI $0, R16, $8, R11 + ADD R12, R10, R15 + MOVBU -1(R15), R16 + BFI $0, R16, $8, R13 + MOVB R11, (R3) + ADD R12, R3, R15 + MOVB R13, -1(R15) + ADD R12, R10, R10 + ADD R12, R3, R3 + JMP copy_2_end copy_2_move_3: - MOVH (R10), R11 - MOVB 2(R10), R13 - MOVH R11, (R3) - MOVB R13, 2(R3) - ADD R12, R10, R10 - ADD R12, R3, R3 - JMP copy_2_end + MOVHU (R10), R11 + MOVBU 2(R10), R16 + BFI $0, R16, $8, R13 + MOVH R11, (R3) + MOVB R13, 2(R3) + ADD R12, R10, R10 + ADD R12, R3, R3 + JMP copy_2_end copy_2_move_4through7: MOVWU (R10), R11 @@ -1305,12 +1326,13 @@ copy_overlapping_match: ADD R12, R6, R6 copy_slow_3: - MOVB (R10), R11 - MOVB R11, (R3) - ADD $1, R10, R10 - ADD $1, R3, R3 - SUBS $1, R12, R12 - BNE copy_slow_3 + MOVBU (R10), R16 + BFI $0, R16, $8, R11 + MOVB R11, (R3) + ADD $1, R10, R10 + ADD $1, R3, R3 + SUBS $1, R12, R12 + BNE copy_slow_3 handle_loop: ADD $0x18, R0, R0 @@ -1361,41 +1383,41 @@ TEXT ·sequenceDecs_decodeSync_arm64(SB), $64-32 MOVD (R1), R0 MOVD 32(R1), R5 ADD R5, R0, R0 - MOVD R0, (RSP) + MOVD R0, 8(RSP) MOVD ctx+16(FP), R0 MOVD 72(R0), R6 MOVD 80(R0), R7 MOVD 88(R0), R8 MOVD $0, R1 - MOVD R1, 8(RSP) MOVD R1, 16(RSP) MOVD R1, 24(RSP) + MOVD R1, 32(RSP) MOVD 112(R0), R9 MOVD 128(R0), R1 - MOVD R1, 32(RSP) + MOVD R1, 40(RSP) MOVD 144(R0), R10 MOVD 136(R0), R11 MOVD 200(R0), R1 - MOVD R1, 56(RSP) + MOVD R1, 64(RSP) MOVD 176(R0), R1 - MOVD R1, 48(RSP) + MOVD R1, 56(RSP) MOVD 184(R0), R0 - MOVD R0, 40(RSP) - MOVD 40(RSP), R0 - MOVD 48(RSP), R16 + MOVD R0, 48(RSP) + MOVD 48(RSP), R0 + MOVD 56(RSP), R16 ADD R0, R16, R16 - MOVD R16, 48(RSP) + MOVD R16, 56(RSP) // Calculate pointer to s.out[cap(s.out)] (a past-end pointer) - MOVD 32(RSP), R16 + MOVD 40(RSP), R16 ADD R9, R16, R16 - MOVD R16, 32(RSP) + MOVD R16, 40(RSP) // outBase += outPosition ADD R11, R9, R9 sequenceDecs_decodeSync_amd64_main_loop: - MOVD (RSP), R12 + MOVD 8(RSP), R12 // Fill bitreader to have enough for the offset and match length. CMP $0x08, R5 @@ -1431,7 +1453,8 @@ sequenceDecs_decodeSync_amd64_fill_end: MOVD R3, R1 MOVD R2, R13 LSL R1, R13, R13 - UBFX $8, R0, $8, R1 + UBFX $8, R0, $8, R16 + BFI $0, R16, $8, R1 LSR $0x20, R0, R0 TST R1, R1 BEQ sequenceDecs_decodeSync_amd64_of_update_zero @@ -1445,14 +1468,15 @@ sequenceDecs_decodeSync_amd64_fill_end: ADD R13, R0, R0 sequenceDecs_decodeSync_amd64_of_update_zero: - MOVD R0, 8(RSP) + MOVD R0, 16(RSP) // Update match length MOVD R7, R0 MOVD R3, R1 MOVD R2, R13 LSL R1, R13, R13 - UBFX $8, R0, $8, R1 + UBFX $8, R0, $8, R16 + BFI $0, R16, $8, R1 LSR $0x20, R0, R0 TST R1, R1 BEQ sequenceDecs_decodeSync_amd64_ml_update_zero @@ -1466,7 +1490,7 @@ sequenceDecs_decodeSync_amd64_of_update_zero: ADD R13, R0, R0 sequenceDecs_decodeSync_amd64_ml_update_zero: - MOVD R0, 16(RSP) + MOVD R0, 24(RSP) // Fill bitreader to have enough for the remaining CMP $0x08, R5 @@ -1502,7 +1526,8 @@ sequenceDecs_decodeSync_amd64_fill_2_end: MOVD R3, R1 MOVD R2, R13 LSL R1, R13, R13 - UBFX $8, R0, $8, R1 + UBFX $8, R0, $8, R16 + BFI $0, R16, $8, R1 LSR $0x20, R0, R0 TST R1, R1 BEQ sequenceDecs_decodeSync_amd64_ll_update_zero @@ -1516,10 +1541,10 @@ sequenceDecs_decodeSync_amd64_fill_2_end: ADD R13, R0, R0 sequenceDecs_decodeSync_amd64_ll_update_zero: - MOVD R0, 24(RSP) + MOVD R0, 32(RSP) // Fill bitreader for state updates - MOVD R12, (RSP) + MOVD R12, 8(RSP) MOVD R8, R0 LSR $0x08, R0, R0 MOVBU R0, R0 @@ -1537,7 +1562,7 @@ sequenceDecs_decodeSync_amd64_ll_update_zero: NEG R1, R16 ROR R16, R13, R13 MOVD $0x00000001, R14 - MOVB R12, R1 + BFI $0, R12, $8, R1 LSLW R1, R14, R14 SUBW $1, R14, R14 AND R14, R13, R13 @@ -1558,7 +1583,7 @@ sequenceDecs_decodeSync_amd64_ll_update_zero: NEG R1, R16 ROR R16, R13, R13 MOVD $0x00000001, R14 - MOVB R12, R1 + BFI $0, R12, $8, R1 LSLW R1, R14, R14 SUBW $1, R14, R14 AND R14, R13, R13 @@ -1579,7 +1604,7 @@ sequenceDecs_decodeSync_amd64_ll_update_zero: NEG R1, R16 ROR R16, R13, R13 MOVD $0x00000001, R14 - MOVB R12, R1 + BFI $0, R12, $8, R1 LSLW R1, R14, R14 SUBW $1, R14, R14 AND R14, R13, R13 @@ -1594,7 +1619,7 @@ sequenceDecs_decodeSync_amd64_ll_update_zero: sequenceDecs_decodeSync_amd64_skip_update: // Adjust offset MOVD s+0(FP), R1 - MOVD 8(RSP), R12 + MOVD 16(RSP), R12 CMP $0x01, R0 BLS sequenceDecs_decodeSync_amd64_adjust_offsetB_1_or_0 ADD $144, R1, R15 @@ -1605,7 +1630,7 @@ sequenceDecs_decodeSync_amd64_skip_update: JMP sequenceDecs_decodeSync_amd64_after_adjust sequenceDecs_decodeSync_amd64_adjust_offsetB_1_or_0: - MOVD 24(RSP), R16 + MOVD 32(RSP), R16 CMP $0x00000000, R16 BNE sequenceDecs_decodeSync_amd64_adjust_offset_maybezero ADD $1, R12, R12 @@ -1643,11 +1668,11 @@ sequenceDecs_decodeSync_amd64_adjust_skip: MOVD R13, R12 sequenceDecs_decodeSync_amd64_after_adjust: - MOVD R12, 8(RSP) + MOVD R12, 16(RSP) // Check values - MOVD 16(RSP), R0 - MOVD 24(RSP), R1 + MOVD 24(RSP), R0 + MOVD 32(RSP), R1 ADD R1, R0, R13 MOVD s+0(FP), R14 MOVD 256(R14), R16 @@ -1666,14 +1691,15 @@ sequenceDecs_decodeSync_amd64_after_adjust: BNE sequenceDecs_decodeSync_amd64_error_match_len_ofs_mismatch sequenceDecs_decodeSync_amd64_match_len_ofs_ok: - MOVD 24(RSP), R0 - MOVD 8(RSP), R1 - MOVD 16(RSP), R12 + MOVD 32(RSP), R0 + MOVD 16(RSP), R1 + MOVD 24(RSP), R12 // Check if we have enough space in s.out ADD R12, R0, R13 + ADD $16, R13, R13 ADD R9, R13, R13 - MOVD 32(RSP), R16 + MOVD 40(RSP), R16 CMP R16, R13 BHI error_not_enough_space @@ -1697,11 +1723,11 @@ copy_1: // Malformed input if seq.mo > t+len(hist) || seq.mo > s.windowSize) check_offset: MOVD R11, R0 - MOVD 40(RSP), R16 + MOVD 48(RSP), R16 ADD R16, R0, R0 CMP R0, R1 BGT error_match_off_too_big - MOVD 56(RSP), R16 + MOVD 64(RSP), R16 CMP R16, R1 BGT error_match_off_too_big @@ -1709,7 +1735,7 @@ check_offset: MOVD R1, R0 SUBS R11, R0, R0 BLS copy_match - MOVD 48(RSP), R13 + MOVD 56(RSP), R13 SUB R0, R13, R13 CMP R0, R12 BGT copy_all_from_history @@ -1742,13 +1768,14 @@ copy_4_small: JMP copy_4_move_8through16 copy_4_move_3: - MOVH (R13), R0 - MOVB 2(R13), R1 - MOVH R0, (R9) - MOVB R1, 2(R9) - ADD R12, R13, R13 - ADD R12, R9, R9 - JMP copy_4_end + MOVHU (R13), R0 + MOVBU 2(R13), R16 + BFI $0, R16, $8, R1 + MOVH R0, (R9) + MOVB R1, 2(R9) + ADD R12, R13, R13 + ADD R12, R9, R9 + JMP copy_4_end copy_4_move_4through7: MOVWU (R13), R0 @@ -1807,24 +1834,27 @@ copy_5_small: JMP copy_5_move_8through16 copy_5_move_1or2: - MOVB (R13), R14 - ADD R0, R13, R15 - MOVB -1(R15), R4 - MOVB R14, (R9) - ADD R0, R9, R15 - MOVB R4, -1(R15) - ADD R0, R13, R13 - ADD R0, R9, R9 - JMP copy_5_end + MOVBU (R13), R16 + BFI $0, R16, $8, R14 + ADD R0, R13, R15 + MOVBU -1(R15), R16 + BFI $0, R16, $8, R4 + MOVB R14, (R9) + ADD R0, R9, R15 + MOVB R4, -1(R15) + ADD R0, R13, R13 + ADD R0, R9, R9 + JMP copy_5_end copy_5_move_3: - MOVH (R13), R14 - MOVB 2(R13), R4 - MOVH R14, (R9) - MOVB R4, 2(R9) - ADD R0, R13, R13 - ADD R0, R9, R9 - JMP copy_5_end + MOVHU (R13), R14 + MOVBU 2(R13), R16 + BFI $0, R16, $8, R4 + MOVH R14, (R9) + MOVB R4, 2(R9) + ADD R0, R13, R13 + ADD R0, R9, R9 + JMP copy_5_end copy_5_move_4through7: MOVWU (R13), R14 @@ -1879,12 +1909,13 @@ copy_overlapping_match: ADD R12, R11, R11 copy_slow_3: - MOVB (R0), R1 - MOVB R1, (R9) - ADD $1, R0, R0 - ADD $1, R9, R9 - SUBS $1, R12, R12 - BNE copy_slow_3 + MOVBU (R0), R16 + BFI $0, R16, $8, R1 + MOVB R1, (R9) + ADD $1, R0, R0 + ADD $1, R9, R9 + SUBS $1, R12, R12 + BNE copy_slow_3 handle_loop: MOVD ctx+16(FP), R0 @@ -1913,7 +1944,7 @@ loop_finished: // Return with match length error sequenceDecs_decodeSync_amd64_error_match_len_ofs_mismatch: - MOVD 16(RSP), R0 + MOVD 24(RSP), R0 MOVD ctx+16(FP), R1 MOVD R0, 216(R1) MOVD $0x00000001, R16 @@ -1923,7 +1954,7 @@ sequenceDecs_decodeSync_amd64_error_match_len_ofs_mismatch: // Return with match too long error sequenceDecs_decodeSync_amd64_error_match_len_too_big: MOVD ctx+16(FP), R0 - MOVD 16(RSP), R1 + MOVD 24(RSP), R1 MOVD R1, 216(R0) MOVD $0x00000002, R16 MOVD R16, ret+24(FP) @@ -1932,7 +1963,7 @@ sequenceDecs_decodeSync_amd64_error_match_len_too_big: // Return with match offset too long error error_match_off_too_big: MOVD ctx+16(FP), R0 - MOVD 8(RSP), R1 + MOVD 16(RSP), R1 MOVD R1, 224(R0) MOVD R11, 136(R0) MOVD $0x00000003, R16 @@ -1942,7 +1973,7 @@ error_match_off_too_big: // Return with not enough literals error error_not_enough_literals: MOVD ctx+16(FP), R0 - MOVD 24(RSP), R1 + MOVD 32(RSP), R1 MOVD R1, 208(R0) MOVD $0x00000004, R16 MOVD R16, ret+24(FP) @@ -1957,9 +1988,9 @@ error_overread: // Return with not enough output space error error_not_enough_space: MOVD ctx+16(FP), R0 - MOVD 24(RSP), R1 + MOVD 32(RSP), R1 MOVD R1, 208(R0) - MOVD 16(RSP), R1 + MOVD 24(RSP), R1 MOVD R1, 216(R0) MOVD R11, 136(R0) MOVD $0x00000005, R16 @@ -1977,41 +2008,41 @@ TEXT ·sequenceDecs_decodeSync_safe_arm64(SB), $64-32 MOVD (R1), R0 MOVD 32(R1), R5 ADD R5, R0, R0 - MOVD R0, (RSP) + MOVD R0, 8(RSP) MOVD ctx+16(FP), R0 MOVD 72(R0), R6 MOVD 80(R0), R7 MOVD 88(R0), R8 MOVD $0, R1 - MOVD R1, 8(RSP) MOVD R1, 16(RSP) MOVD R1, 24(RSP) + MOVD R1, 32(RSP) MOVD 112(R0), R9 MOVD 128(R0), R1 - MOVD R1, 32(RSP) + MOVD R1, 40(RSP) MOVD 144(R0), R10 MOVD 136(R0), R11 MOVD 200(R0), R1 - MOVD R1, 56(RSP) + MOVD R1, 64(RSP) MOVD 176(R0), R1 - MOVD R1, 48(RSP) + MOVD R1, 56(RSP) MOVD 184(R0), R0 - MOVD R0, 40(RSP) - MOVD 40(RSP), R0 - MOVD 48(RSP), R16 + MOVD R0, 48(RSP) + MOVD 48(RSP), R0 + MOVD 56(RSP), R16 ADD R0, R16, R16 - MOVD R16, 48(RSP) + MOVD R16, 56(RSP) // Calculate pointer to s.out[cap(s.out)] (a past-end pointer) - MOVD 32(RSP), R16 + MOVD 40(RSP), R16 ADD R9, R16, R16 - MOVD R16, 32(RSP) + MOVD R16, 40(RSP) // outBase += outPosition ADD R11, R9, R9 sequenceDecs_decodeSync_safe_amd64_main_loop: - MOVD (RSP), R12 + MOVD 8(RSP), R12 // Fill bitreader to have enough for the offset and match length. CMP $0x08, R5 @@ -2047,7 +2078,8 @@ sequenceDecs_decodeSync_safe_amd64_fill_end: MOVD R3, R1 MOVD R2, R13 LSL R1, R13, R13 - UBFX $8, R0, $8, R1 + UBFX $8, R0, $8, R16 + BFI $0, R16, $8, R1 LSR $0x20, R0, R0 TST R1, R1 BEQ sequenceDecs_decodeSync_safe_amd64_of_update_zero @@ -2061,14 +2093,15 @@ sequenceDecs_decodeSync_safe_amd64_fill_end: ADD R13, R0, R0 sequenceDecs_decodeSync_safe_amd64_of_update_zero: - MOVD R0, 8(RSP) + MOVD R0, 16(RSP) // Update match length MOVD R7, R0 MOVD R3, R1 MOVD R2, R13 LSL R1, R13, R13 - UBFX $8, R0, $8, R1 + UBFX $8, R0, $8, R16 + BFI $0, R16, $8, R1 LSR $0x20, R0, R0 TST R1, R1 BEQ sequenceDecs_decodeSync_safe_amd64_ml_update_zero @@ -2082,7 +2115,7 @@ sequenceDecs_decodeSync_safe_amd64_of_update_zero: ADD R13, R0, R0 sequenceDecs_decodeSync_safe_amd64_ml_update_zero: - MOVD R0, 16(RSP) + MOVD R0, 24(RSP) // Fill bitreader to have enough for the remaining CMP $0x08, R5 @@ -2118,7 +2151,8 @@ sequenceDecs_decodeSync_safe_amd64_fill_2_end: MOVD R3, R1 MOVD R2, R13 LSL R1, R13, R13 - UBFX $8, R0, $8, R1 + UBFX $8, R0, $8, R16 + BFI $0, R16, $8, R1 LSR $0x20, R0, R0 TST R1, R1 BEQ sequenceDecs_decodeSync_safe_amd64_ll_update_zero @@ -2132,10 +2166,10 @@ sequenceDecs_decodeSync_safe_amd64_fill_2_end: ADD R13, R0, R0 sequenceDecs_decodeSync_safe_amd64_ll_update_zero: - MOVD R0, 24(RSP) + MOVD R0, 32(RSP) // Fill bitreader for state updates - MOVD R12, (RSP) + MOVD R12, 8(RSP) MOVD R8, R0 LSR $0x08, R0, R0 MOVBU R0, R0 @@ -2153,7 +2187,7 @@ sequenceDecs_decodeSync_safe_amd64_ll_update_zero: NEG R1, R16 ROR R16, R13, R13 MOVD $0x00000001, R14 - MOVB R12, R1 + BFI $0, R12, $8, R1 LSLW R1, R14, R14 SUBW $1, R14, R14 AND R14, R13, R13 @@ -2174,7 +2208,7 @@ sequenceDecs_decodeSync_safe_amd64_ll_update_zero: NEG R1, R16 ROR R16, R13, R13 MOVD $0x00000001, R14 - MOVB R12, R1 + BFI $0, R12, $8, R1 LSLW R1, R14, R14 SUBW $1, R14, R14 AND R14, R13, R13 @@ -2195,7 +2229,7 @@ sequenceDecs_decodeSync_safe_amd64_ll_update_zero: NEG R1, R16 ROR R16, R13, R13 MOVD $0x00000001, R14 - MOVB R12, R1 + BFI $0, R12, $8, R1 LSLW R1, R14, R14 SUBW $1, R14, R14 AND R14, R13, R13 @@ -2210,7 +2244,7 @@ sequenceDecs_decodeSync_safe_amd64_ll_update_zero: sequenceDecs_decodeSync_safe_amd64_skip_update: // Adjust offset MOVD s+0(FP), R1 - MOVD 8(RSP), R12 + MOVD 16(RSP), R12 CMP $0x01, R0 BLS sequenceDecs_decodeSync_safe_amd64_adjust_offsetB_1_or_0 ADD $144, R1, R15 @@ -2221,7 +2255,7 @@ sequenceDecs_decodeSync_safe_amd64_skip_update: JMP sequenceDecs_decodeSync_safe_amd64_after_adjust sequenceDecs_decodeSync_safe_amd64_adjust_offsetB_1_or_0: - MOVD 24(RSP), R16 + MOVD 32(RSP), R16 CMP $0x00000000, R16 BNE sequenceDecs_decodeSync_safe_amd64_adjust_offset_maybezero ADD $1, R12, R12 @@ -2259,11 +2293,11 @@ sequenceDecs_decodeSync_safe_amd64_adjust_skip: MOVD R13, R12 sequenceDecs_decodeSync_safe_amd64_after_adjust: - MOVD R12, 8(RSP) + MOVD R12, 16(RSP) // Check values - MOVD 16(RSP), R0 - MOVD 24(RSP), R1 + MOVD 24(RSP), R0 + MOVD 32(RSP), R1 ADD R1, R0, R13 MOVD s+0(FP), R14 MOVD 256(R14), R16 @@ -2282,14 +2316,14 @@ sequenceDecs_decodeSync_safe_amd64_after_adjust: BNE sequenceDecs_decodeSync_safe_amd64_error_match_len_ofs_mismatch sequenceDecs_decodeSync_safe_amd64_match_len_ofs_ok: - MOVD 24(RSP), R0 - MOVD 8(RSP), R1 - MOVD 16(RSP), R12 + MOVD 32(RSP), R0 + MOVD 16(RSP), R1 + MOVD 24(RSP), R12 // Check if we have enough space in s.out ADD R12, R0, R13 ADD R9, R13, R13 - MOVD 32(RSP), R16 + MOVD 40(RSP), R16 CMP R16, R13 BHI error_not_enough_space @@ -2326,24 +2360,27 @@ copy_1_small: JMP copy_1_move_8through16 copy_1_move_1or2: - MOVB (R10), R13 - ADD R0, R10, R15 - MOVB -1(R15), R14 - MOVB R13, (R9) - ADD R0, R9, R15 - MOVB R14, -1(R15) - ADD R0, R10, R10 - ADD R0, R9, R9 - JMP copy_1_end + MOVBU (R10), R16 + BFI $0, R16, $8, R13 + ADD R0, R10, R15 + MOVBU -1(R15), R16 + BFI $0, R16, $8, R14 + MOVB R13, (R9) + ADD R0, R9, R15 + MOVB R14, -1(R15) + ADD R0, R10, R10 + ADD R0, R9, R9 + JMP copy_1_end copy_1_move_3: - MOVH (R10), R13 - MOVB 2(R10), R14 - MOVH R13, (R9) - MOVB R14, 2(R9) - ADD R0, R10, R10 - ADD R0, R9, R9 - JMP copy_1_end + MOVHU (R10), R13 + MOVBU 2(R10), R16 + BFI $0, R16, $8, R14 + MOVH R13, (R9) + MOVB R14, 2(R9) + ADD R0, R10, R10 + ADD R0, R9, R9 + JMP copy_1_end copy_1_move_4through7: MOVWU (R10), R13 @@ -2372,11 +2409,11 @@ copy_1_end: // Malformed input if seq.mo > t+len(hist) || seq.mo > s.windowSize) check_offset: MOVD R11, R0 - MOVD 40(RSP), R16 + MOVD 48(RSP), R16 ADD R16, R0, R0 CMP R0, R1 BGT error_match_off_too_big - MOVD 56(RSP), R16 + MOVD 64(RSP), R16 CMP R16, R1 BGT error_match_off_too_big @@ -2384,7 +2421,7 @@ check_offset: MOVD R1, R0 SUBS R11, R0, R0 BLS copy_match - MOVD 48(RSP), R13 + MOVD 56(RSP), R13 SUB R0, R13, R13 CMP R0, R12 BGT copy_all_from_history @@ -2417,13 +2454,14 @@ copy_4_small: JMP copy_4_move_8through16 copy_4_move_3: - MOVH (R13), R0 - MOVB 2(R13), R1 - MOVH R0, (R9) - MOVB R1, 2(R9) - ADD R12, R13, R13 - ADD R12, R9, R9 - JMP copy_4_end + MOVHU (R13), R0 + MOVBU 2(R13), R16 + BFI $0, R16, $8, R1 + MOVH R0, (R9) + MOVB R1, 2(R9) + ADD R12, R13, R13 + ADD R12, R9, R9 + JMP copy_4_end copy_4_move_4through7: MOVWU (R13), R0 @@ -2482,24 +2520,27 @@ copy_5_small: JMP copy_5_move_8through16 copy_5_move_1or2: - MOVB (R13), R14 - ADD R0, R13, R15 - MOVB -1(R15), R4 - MOVB R14, (R9) - ADD R0, R9, R15 - MOVB R4, -1(R15) - ADD R0, R13, R13 - ADD R0, R9, R9 - JMP copy_5_end + MOVBU (R13), R16 + BFI $0, R16, $8, R14 + ADD R0, R13, R15 + MOVBU -1(R15), R16 + BFI $0, R16, $8, R4 + MOVB R14, (R9) + ADD R0, R9, R15 + MOVB R4, -1(R15) + ADD R0, R13, R13 + ADD R0, R9, R9 + JMP copy_5_end copy_5_move_3: - MOVH (R13), R14 - MOVB 2(R13), R4 - MOVH R14, (R9) - MOVB R4, 2(R9) - ADD R0, R13, R13 - ADD R0, R9, R9 - JMP copy_5_end + MOVHU (R13), R14 + MOVBU 2(R13), R16 + BFI $0, R16, $8, R4 + MOVH R14, (R9) + MOVB R4, 2(R9) + ADD R0, R13, R13 + ADD R0, R9, R9 + JMP copy_5_end copy_5_move_4through7: MOVWU (R13), R14 @@ -2567,24 +2608,27 @@ copy_2_small: JMP copy_2_move_8through16 copy_2_move_1or2: - MOVB (R0), R1 - ADD R12, R0, R15 - MOVB -1(R15), R13 - MOVB R1, (R9) - ADD R12, R9, R15 - MOVB R13, -1(R15) - ADD R12, R0, R0 - ADD R12, R9, R9 - JMP copy_2_end + MOVBU (R0), R16 + BFI $0, R16, $8, R1 + ADD R12, R0, R15 + MOVBU -1(R15), R16 + BFI $0, R16, $8, R13 + MOVB R1, (R9) + ADD R12, R9, R15 + MOVB R13, -1(R15) + ADD R12, R0, R0 + ADD R12, R9, R9 + JMP copy_2_end copy_2_move_3: - MOVH (R0), R1 - MOVB 2(R0), R13 - MOVH R1, (R9) - MOVB R13, 2(R9) - ADD R12, R0, R0 - ADD R12, R9, R9 - JMP copy_2_end + MOVHU (R0), R1 + MOVBU 2(R0), R16 + BFI $0, R16, $8, R13 + MOVH R1, (R9) + MOVB R13, 2(R9) + ADD R12, R0, R0 + ADD R12, R9, R9 + JMP copy_2_end copy_2_move_4through7: MOVWU (R0), R1 @@ -2615,12 +2659,13 @@ copy_overlapping_match: ADD R12, R11, R11 copy_slow_3: - MOVB (R0), R1 - MOVB R1, (R9) - ADD $1, R0, R0 - ADD $1, R9, R9 - SUBS $1, R12, R12 - BNE copy_slow_3 + MOVBU (R0), R16 + BFI $0, R16, $8, R1 + MOVB R1, (R9) + ADD $1, R0, R0 + ADD $1, R9, R9 + SUBS $1, R12, R12 + BNE copy_slow_3 handle_loop: MOVD ctx+16(FP), R0 @@ -2649,7 +2694,7 @@ loop_finished: // Return with match length error sequenceDecs_decodeSync_safe_amd64_error_match_len_ofs_mismatch: - MOVD 16(RSP), R0 + MOVD 24(RSP), R0 MOVD ctx+16(FP), R1 MOVD R0, 216(R1) MOVD $0x00000001, R16 @@ -2659,7 +2704,7 @@ sequenceDecs_decodeSync_safe_amd64_error_match_len_ofs_mismatch: // Return with match too long error sequenceDecs_decodeSync_safe_amd64_error_match_len_too_big: MOVD ctx+16(FP), R0 - MOVD 16(RSP), R1 + MOVD 24(RSP), R1 MOVD R1, 216(R0) MOVD $0x00000002, R16 MOVD R16, ret+24(FP) @@ -2668,7 +2713,7 @@ sequenceDecs_decodeSync_safe_amd64_error_match_len_too_big: // Return with match offset too long error error_match_off_too_big: MOVD ctx+16(FP), R0 - MOVD 8(RSP), R1 + MOVD 16(RSP), R1 MOVD R1, 224(R0) MOVD R11, 136(R0) MOVD $0x00000003, R16 @@ -2678,7 +2723,7 @@ error_match_off_too_big: // Return with not enough literals error error_not_enough_literals: MOVD ctx+16(FP), R0 - MOVD 24(RSP), R1 + MOVD 32(RSP), R1 MOVD R1, 208(R0) MOVD $0x00000004, R16 MOVD R16, ret+24(FP) @@ -2693,9 +2738,9 @@ error_overread: // Return with not enough output space error error_not_enough_space: MOVD ctx+16(FP), R0 - MOVD 24(RSP), R1 + MOVD 32(RSP), R1 MOVD R1, 208(R0) - MOVD 16(RSP), R1 + MOVD 24(RSP), R1 MOVD R1, 216(R0) MOVD R11, 136(R0) MOVD $0x00000005, R16 diff --git a/vendor/github.com/klauspost/compress/zstd/seqdec_asm.go b/vendor/github.com/klauspost/compress/zstd/seqdec_asm.go index 55405f3914..42ce5de716 100644 --- a/vendor/github.com/klauspost/compress/zstd/seqdec_asm.go +++ b/vendor/github.com/klauspost/compress/zstd/seqdec_asm.go @@ -77,6 +77,35 @@ const errorNotEnoughSpace = 5 // error reported when bits are overread. const errorOverread = 6 +// useSafeDecodeSync reports whether decodeSyncSimple must use the bounds-exact +// ("safe") copy variants for the current buffer geometry. +// +// When the output and literal buffers have compressedBlockOverAlloc (16) +// bytes of slack past their logical use, the assembly may use extended +// memory copies that read and write in 16-byte blocks, overrunning the end +// of a literal run or match by up to 15 bytes. Otherwise it must use the +// bounds-exact ("safe") copies. This mirrors the analogous, always-dynamic +// selection in executeSimple below. +// +// The unsafe copies were disabled in #644 (2022) as a mitigation for a +// crash, but that crash's root cause — an unguarded bitReader overread that +// produced out-of-range match offsets/lengths — was fixed three days later +// in #645, which also added the fuzz corpus that has guarded this path since. +// See #1168. An asan-instrumented fuzz job (see .github/workflows/go.yml) +// covers the extended-copy path, which -race and plain fuzzing cannot. +func (s *sequenceDecs) useSafeDecodeSync() bool { + if s.maxSyncLen == 0 && cap(s.out)-len(s.out) < maxCompressedBlockSizeAlloc { + return true + } + if s.maxSyncLen > 0 && cap(s.out)-len(s.out)-compressedBlockOverAlloc < int(s.maxSyncLen) { + return true + } + if cap(s.literals) < len(s.literals)+compressedBlockOverAlloc { + return true + } + return false +} + // decode sequences from the stream with the provided history but without a dictionary. func (s *sequenceDecs) decodeSyncSimple(hist []byte) (bool, error) { if len(s.dict) > 0 { @@ -86,9 +115,7 @@ func (s *sequenceDecs) decodeSyncSimple(hist []byte) (bool, error) { return false, nil } - // FIXME: Using unsafe memory copies leads to rare, random crashes - // with fuzz testing. It is therefore disabled for now. - const useSafe = true + useSafe := s.useSafeDecodeSync() br := s.br diff --git a/vendor/github.com/mattn/go-sqlite3/callback.go b/vendor/github.com/mattn/go-sqlite3/callback.go index 8ea17db9d2..b7df2be7f6 100644 --- a/vendor/github.com/mattn/go-sqlite3/callback.go +++ b/vendor/github.com/mattn/go-sqlite3/callback.go @@ -131,6 +131,27 @@ func lookupHandle(handle unsafe.Pointer) any { return lookupHandleVal(handle).val } +// deleteHandle releases a single handle created by newHandle. It is a no-op +// if the handle is unknown (e.g. already released). +func deleteHandle(handle unsafe.Pointer) { + handleLock.Lock() + defer handleLock.Unlock() + + current := loadHandleVals() + if _, ok := current[handle]; !ok { + return + } + next := make(map[unsafe.Pointer]handleVal, len(current)-1) + for h, v := range current { + if h == handle { + continue + } + next[h] = v + } + handleVals.Store(next) + C.free(handle) +} + func deleteHandles(db *SQLiteConn) { handleLock.Lock() defer handleLock.Unlock() diff --git a/vendor/github.com/mattn/go-sqlite3/sqlite3-binding.c b/vendor/github.com/mattn/go-sqlite3/sqlite3-binding.c index 337af9e47c..4a3437f57d 100644 --- a/vendor/github.com/mattn/go-sqlite3/sqlite3-binding.c +++ b/vendor/github.com/mattn/go-sqlite3/sqlite3-binding.c @@ -1,7 +1,7 @@ #ifndef USE_LIBSQLITE3 /****************************************************************************** ** This file is an amalgamation of many separate C source files from SQLite -** version 3.53.3. By combining all the individual C code files into this +** version 3.53.4. By combining all the individual C code files into this ** single large file, the entire code can be compiled as a single translation ** unit. This allows many compilers to do optimizations that would not be ** possible if the files were compiled separately. Performance improvements @@ -19,7 +19,7 @@ ** separate file. This file contains only code for the core SQLite library. ** ** The content in this amalgamation comes from Fossil check-in -** d4c0e51e4aeb96955b99185ab9cde75c339e with changes in files: +** bf7c7f30031888f4e796e429ab3978879485 with changes in files: ** ** */ @@ -468,12 +468,12 @@ extern "C" { ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ -#define SQLITE_VERSION "3.53.3" -#define SQLITE_VERSION_NUMBER 3053003 -#define SQLITE_SOURCE_ID "2026-06-26 20:14:12 d4c0e51e4aeb96955b99185ab9cde75c339e2c29c3f3f12428d364a10d782c62" +#define SQLITE_VERSION "3.53.4" +#define SQLITE_VERSION_NUMBER 3053004 +#define SQLITE_SOURCE_ID "2026-07-24 19:02:57 bf7c7f30031888f4e796e429ab3978879485813aaca6f641c7b33e4e09459bcc" #define SQLITE_SCM_BRANCH "branch-3.53" -#define SQLITE_SCM_TAGS "release version-3.53.3" -#define SQLITE_SCM_DATETIME "2026-06-26T20:14:12.354Z" +#define SQLITE_SCM_TAGS "release version-3.53.4" +#define SQLITE_SCM_DATETIME "2026-07-24T19:02:57.525Z" /* ** CAPI3REF: Run-Time Library Version Numbers @@ -27592,7 +27592,7 @@ SQLITE_PRIVATE int sqlite3OsCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *p }else{ double r; rc = pVfs->xCurrentTime(pVfs, &r); - *pTimeOut = (sqlite3_int64)(r*86400000.0); + *pTimeOut = sqlite3RealToI64(r*86400000.0); } return rc; } @@ -60970,7 +60970,7 @@ static int readSuperJournal(sqlite3_file *pJrnl, u64 nSuper, char **pzSuper){ cksum -= zOut[u]; } } - if( rc!=SQLITE_OK || cksum ){ + if( rc!=SQLITE_OK || cksum || zOut[0]==0 ){ /* If the checksum doesn't add up, then one or more of the disk sectors ** containing the super-journal filename is corrupted. This means ** definitely roll back, so just return SQLITE_OK and report a (nul) @@ -111438,11 +111438,20 @@ static SQLITE_NOINLINE void resolveSetExprSubtypeArg(ExprList *pList){ nn = pList ? pList->nExpr : 0; for(ii=0; iia[ii].pExpr; - ExprSetProperty(pExpr, EP_SubtArg); - if( pExpr->op==TK_SELECT ){ - assert( ExprUseXSelect(pExpr) ); - assert( pExpr->x.pSelect!=0 ); - resolveSetExprSubtypeArg(pExpr->x.pSelect->pEList); + while( 1 /*exit-by-break*/ ){ + ExprSetProperty(pExpr, EP_SubtArg); + if( pExpr->op==TK_SELECT ){ + assert( ExprUseXSelect(pExpr) ); + assert( pExpr->x.pSelect!=0 ); + resolveSetExprSubtypeArg(pExpr->x.pSelect->pEList); + break; + } + if( pExpr->op==TK_UPLUS ){ + pExpr = pExpr->pLeft; + assert( pExpr!=0 ); + }else{ + break; + } } } } @@ -176955,7 +176964,7 @@ static void nth_valueStepFunc( break; case SQLITE_FLOAT: { double fVal = sqlite3_value_double(apArg[1]); - if( ((i64)fVal)!=fVal ) goto error_out; + if( sqlite3RealToI64(fVal)!=fVal ) goto error_out; iVal = (i64)fVal; break; } @@ -210777,8 +210786,8 @@ static int fts3StringAppend( ** to grow the buffer until so that it is big enough to accommodate the ** appended data. */ - if( pStr->n+nAppend+1>=pStr->nAlloc ){ - sqlite3_int64 nAlloc = pStr->nAlloc+(sqlite3_int64)nAppend+100; + if( (i64)pStr->n+(i64)nAppend+1>=(i64)pStr->nAlloc ){ + i64 nAlloc = pStr->nAlloc+(i64)nAppend+100; char *zNew = sqlite3_realloc64(pStr->z, nAlloc); if( !zNew ){ return SQLITE_NOMEM; @@ -214982,7 +214991,8 @@ static u32 jsonTranslateBlobToText( if( sz==0 ) goto malformed_jsonb; if( zIn[0]=='-' ){ jsonAppendChar(pOut, '-'); - k++; + if( sz<=1 ) goto malformed_jsonb; + k = 1; } if( zIn[k]=='.' ){ jsonAppendChar(pOut, '0'); @@ -217946,7 +217956,9 @@ static int jsonSkipLabel(JsonEachCursor *p){ if( p->eType==JSONB_OBJECT ){ u32 sz = 0; u32 n = jsonbPayloadSize(&p->sParse, p->i, &sz); - return p->i + n + sz; + sz += p->i + n; + if( sz >= p->sParse.nBlob ) sz = p->i; + return sz; }else{ return p->i; } @@ -226907,8 +226919,8 @@ static int rbuDeltaApply( int lenDelta, /* Length of the delta */ char *zOut /* Write the output into this preallocated buffer */ ){ - unsigned int limit; - unsigned int total = 0; + sqlite3_uint64 limit; + sqlite3_uint64 total = 0; #if RBU_ENABLE_DELTA_CKSUM char *zOrigOut = zOut; #endif @@ -226918,8 +226930,8 @@ static int rbuDeltaApply( /* ERROR: size integer not terminated by "\n" */ return -1; } - zDelta++; lenDelta--; - while( *zDelta && lenDelta>0 ){ + zDelta++; lenDelta--; /* Skip the \n */ + while( lenDelta>0 && zDelta[0] ){ unsigned int cnt, ofst; cnt = rbuDeltaGetInt(&zDelta, &lenDelta); if( lenDelta<=0 ) return -1; @@ -226927,7 +226939,7 @@ static int rbuDeltaApply( case '@': { zDelta++; lenDelta--; ofst = rbuDeltaGetInt(&zDelta, &lenDelta); - if( lenDelta>0 || zDelta[0]!=',' ){ + if( lenDelta>0 && zDelta[0]!=',' ){ /* ERROR: copy command not terminated by ',' */ return -1; } @@ -226952,7 +226964,7 @@ static int rbuDeltaApply( /* ERROR: insert command gives an output larger than predicted */ return -1; } - if( (i64)cnt>(i64)lenDelta ){ + if( cnt>lenDelta ){ /* ERROR: insert count exceeds size of delta */ return -1; } @@ -228965,13 +228977,13 @@ static int rbuGetUpdateStmt( char *zUpdate = 0; pUp->zMask = (char*)&pUp[1]; - memcpy(pUp->zMask, zMask, pIter->nTblCol); pUp->pNext = pIter->pRbuUpdate; pIter->pRbuUpdate = pUp; if( zSet ){ const char *zPrefix = ""; - + assert( p->rc==SQLITE_OK ); + memcpy(pUp->zMask, zMask, pIter->nTblCol); if( pIter->eType!=RBU_PK_VTAB ) zPrefix = "rbu_imp_"; zUpdate = sqlite3_mprintf("UPDATE \"%s%w\" SET %s WHERE %s", zPrefix, pIter->zTbl, zSet, zWhere @@ -229061,6 +229073,9 @@ static RbuState *rbuLoadState(sqlite3rbu *p){ case RBU_STATE_ROW: pRet->nRow = sqlite3_column_int(pStmt, 1); + if( pRet->nRow<0 ){ + rc = SQLITE_CORRUPT; + } break; case RBU_STATE_PROGRESS: @@ -240297,7 +240312,12 @@ static int sessionChangesetToHash( pIter->in.bNoDiscard = 1; while( SQLITE_ROW==(sessionChangesetNext(pIter, &aRec, &nRec, 0)) ){ - rc = sessionOneChangeIterToHash(pGrp, pIter, bRebase); + if( bRebase && pIter->bPatchset ){ + /* A patchset may not be used as a rebase */ + rc = SQLITE_ERROR; + }else{ + rc = sessionOneChangeIterToHash(pGrp, pIter, bRebase); + } if( rc!=SQLITE_OK ) break; } @@ -240674,13 +240694,14 @@ static void sessionAppendPartialUpdate( int i; u8 *a1 = aRec; u8 *a2 = aChange; + u8 *a2Eof = &a2[nChange]; *pOut++ = SQLITE_UPDATE; *pOut++ = pIter->bIndirect; for(i=0; inCol; i++){ int n1 = sessionSerialLen(a1); - int n2 = sessionSerialLen(a2); - if( pIter->abPK[i] || a2[0]==0 ){ + int n2 = (a2>=a2Eof) ? 0 : sessionSerialLen(a2); + if( n2<=0 || pIter->abPK[i] || a2[0]==0 ){ if( !pIter->abPK[i] && a1[0] ) bData = 1; memcpy(pOut, a1, n1); pOut += n1; @@ -240881,8 +240902,8 @@ SQLITE_API int sqlite3rebaser_configure( sqlite3_rebaser *p, int nRebase, const void *pRebase ){ - sqlite3_changeset_iter *pIter = 0; /* Iterator opened on pData/nData */ int rc; /* Return code */ + sqlite3_changeset_iter *pIter = 0; /* Iterator opened on pData/nData */ rc = sqlite3changeset_start(&pIter, nRebase, (void*)pRebase); if( rc==SQLITE_OK ){ rc = sessionChangesetToHash(pIter, &p->grp, 1); @@ -251702,6 +251723,7 @@ static Fts5Data *fts5DataRead(Fts5Index *p, i64 iRowid){ pRet = (Fts5Data*)sqlite3_malloc64(nAlloc); if( pRet ){ pRet->nn = nByte; + pRet->szLeaf = 0; aOut = pRet->p = (u8*)pRet + szData; }else{ rc = SQLITE_NOMEM; @@ -251714,10 +251736,8 @@ static Fts5Data *fts5DataRead(Fts5Index *p, i64 iRowid){ sqlite3_free(pRet); pRet = 0; }else{ - /* TODO1: Fix this */ pRet->p[nByte] = 0x00; pRet->p[nByte+1] = 0x00; - pRet->szLeaf = fts5GetU16(&pRet->p[2]); } } p->rc = rc; @@ -251738,9 +251758,17 @@ static void fts5DataRelease(Fts5Data *pData){ sqlite3_free(pData); } +/* +** Read a leaf-page record. This is similar to fts5DataRead(), except that +** it fills in the Fts5Data.szLeaf value before returning. +*/ static Fts5Data *fts5LeafRead(Fts5Index *p, i64 iRowid){ Fts5Data *pRet = fts5DataRead(p, iRowid); if( pRet ){ + assert( pRet->szLeaf==0 ); + if( pRet->nn>=4 ){ + pRet->szLeaf = fts5GetU16(&pRet->p[2]); + } if( pRet->szLeaf<4 || pRet->szLeaf>pRet->nn ){ FTS5_CORRUPT_ROWID(p, iRowid); fts5DataRelease(pRet); @@ -253650,6 +253678,10 @@ static void fts5SegIterNextInit( pIter->iPgidxOff = pIter->pLeaf->szLeaf; pIter->iPgidxOff += fts5GetVarint32(&a[pIter->iPgidxOff], iTermOff); + if( iTermOff > pIter->pLeaf->szLeaf ){ + p->rc = FTS5_CORRUPT; + return; + } pIter->iLeafOffset = iTermOff; fts5SegIterLoadTerm(p, pIter, 0); fts5SegIterLoadNPos(p, pIter); @@ -255976,7 +256008,7 @@ static void fts5SecureDeleteOverflow( int iNext = 0; u8 *aPg = 0; - pLeaf = fts5DataRead(p, iRowid); + pLeaf = fts5LeafRead(p, iRowid); if( pLeaf==0 ) break; aPg = pLeaf->p; @@ -255984,7 +256016,7 @@ static void fts5SecureDeleteOverflow( if( iNext!=0 ){ *pbLastInDoclist = 0; } - if( iNext==0 && pLeaf->szLeaf!=pLeaf->nn ){ + if( iNext==0 && pLeaf->szLeafnn ){ fts5GetVarint32(&aPg[pLeaf->szLeaf], iNext); } @@ -256271,7 +256303,7 @@ static void fts5DoSecureDelete( /* The entry being removed may be the only position list in ** its doclist. */ for(iPgno=pSeg->iLeafPgno-1; iPgno>pSeg->iTermLeafPgno; iPgno-- ){ - Fts5Data *pPg = fts5DataRead(p, FTS5_SEGMENT_ROWID(iSegid, iPgno)); + Fts5Data *pPg = fts5LeafRead(p, FTS5_SEGMENT_ROWID(iSegid, iPgno)); int bEmpty = (pPg && pPg->nn==4); fts5DataRelease(pPg); if( bEmpty==0 ) break; @@ -256279,7 +256311,7 @@ static void fts5DoSecureDelete( if( iPgno==pSeg->iTermLeafPgno ){ i64 iId = FTS5_SEGMENT_ROWID(iSegid, pSeg->iTermLeafPgno); - Fts5Data *pTerm = fts5DataRead(p, iId); + Fts5Data *pTerm = fts5LeafRead(p, iId); if( pTerm && pTerm->szLeaf==pSeg->iTermLeafOffset ){ u8 *aTermIdx = &pTerm->p[pTerm->szLeaf]; int nTermIdx = pTerm->nn - pTerm->szLeaf; @@ -259231,7 +259263,7 @@ static void fts5IndexIntegrityCheckEmpty( /* Now check that the iter.nEmpty leaves following the current leaf ** (a) exist and (b) contain no terms. */ for(i=iFirst; p->rc==SQLITE_OK && i<=iLast; i++){ - Fts5Data *pLeaf = fts5DataRead(p, FTS5_SEGMENT_ROWID(pSeg->iSegid, i)); + Fts5Data *pLeaf = fts5LeafRead(p, FTS5_SEGMENT_ROWID(pSeg->iSegid, i)); if( pLeaf ){ if( !fts5LeafIsTermless(pLeaf) || (i>=iNoRowid && 0!=fts5LeafFirstRowidOff(pLeaf)) @@ -259359,7 +259391,7 @@ static void fts5IndexIntegrityCheckSegment( FTS5_CORRUPT_ROWID(p, iRow); }else{ iOff += fts5GetVarint32(&pLeaf->p[iOff], nTerm); - if( iOff+nTerm>pLeaf->szLeaf ){ + if( (i64)iOff+(i64)nTerm>(i64)pLeaf->szLeaf ){ FTS5_CORRUPT_ROWID(p, iRow); }else{ res = fts5Memcmp(&pLeaf->p[iOff], zIdxTerm, MIN(nTerm, nIdxTerm)); @@ -263087,19 +263119,23 @@ static int fts5ApiPhraseFirstColumn( if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){ Fts5Sorter *pSorter = pCsr->pSorter; - int n; - if( pSorter ){ - int i1 = (iPhrase==0 ? 0 : pSorter->aIdx[iPhrase-1]); - n = pSorter->aIdx[iPhrase] - i1; - pIter->a = &pSorter->aPoslist[i1]; + if( iPhrase<0 || iPhrase>=sqlite3Fts5ExprPhraseCount(pCsr->pExpr) ){ + rc = SQLITE_RANGE; }else{ - rc = sqlite3Fts5ExprPhraseCollist(pCsr->pExpr, iPhrase, &pIter->a, &n); - } - if( rc==SQLITE_OK ){ - assert( pIter->a || n==0 ); - pIter->b = (pIter->a ? &pIter->a[n] : 0); - *piCol = 0; - fts5ApiPhraseNextColumn(pCtx, pIter, piCol); + int n; + if( pSorter ){ + int i1 = (iPhrase==0 ? 0 : pSorter->aIdx[iPhrase-1]); + n = pSorter->aIdx[iPhrase] - i1; + pIter->a = &pSorter->aPoslist[i1]; + }else{ + rc = sqlite3Fts5ExprPhraseCollist(pCsr->pExpr, iPhrase, &pIter->a, &n); + } + if( rc==SQLITE_OK ){ + assert( pIter->a || n==0 ); + pIter->b = (pIter->a ? &pIter->a[n] : 0); + *piCol = 0; + fts5ApiPhraseNextColumn(pCtx, pIter, piCol); + } } }else{ int n; @@ -264007,7 +264043,7 @@ static void fts5SourceIdFunc( ){ assert( nArg==0 ); UNUSED_PARAM2(nArg, apUnused); - sqlite3_result_text(pCtx, "fts5: 2026-06-26 20:14:12 d4c0e51e4aeb96955b99185ab9cde75c339e2c29c3f3f12428d364a10d782c62", -1, SQLITE_TRANSIENT); + sqlite3_result_text(pCtx, "fts5: 2026-07-24 19:02:57 bf7c7f30031888f4e796e429ab3978879485813aaca6f641c7b33e4e09459bcc", -1, SQLITE_TRANSIENT); } /* diff --git a/vendor/github.com/mattn/go-sqlite3/sqlite3-binding.h b/vendor/github.com/mattn/go-sqlite3/sqlite3-binding.h index 9417bce8d5..aecd0f8385 100644 --- a/vendor/github.com/mattn/go-sqlite3/sqlite3-binding.h +++ b/vendor/github.com/mattn/go-sqlite3/sqlite3-binding.h @@ -147,12 +147,12 @@ extern "C" { ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ -#define SQLITE_VERSION "3.53.3" -#define SQLITE_VERSION_NUMBER 3053003 -#define SQLITE_SOURCE_ID "2026-06-26 20:14:12 d4c0e51e4aeb96955b99185ab9cde75c339e2c29c3f3f12428d364a10d782c62" +#define SQLITE_VERSION "3.53.4" +#define SQLITE_VERSION_NUMBER 3053004 +#define SQLITE_SOURCE_ID "2026-07-24 19:02:57 bf7c7f30031888f4e796e429ab3978879485813aaca6f641c7b33e4e09459bcc" #define SQLITE_SCM_BRANCH "branch-3.53" -#define SQLITE_SCM_TAGS "release version-3.53.3" -#define SQLITE_SCM_DATETIME "2026-06-26T20:14:12.354Z" +#define SQLITE_SCM_TAGS "release version-3.53.4" +#define SQLITE_SCM_DATETIME "2026-07-24T19:02:57.525Z" /* ** CAPI3REF: Run-Time Library Version Numbers diff --git a/vendor/github.com/mattn/go-sqlite3/sqlite3_opt_vtable.go b/vendor/github.com/mattn/go-sqlite3/sqlite3_opt_vtable.go index 9e916ea8cb..b2b2404bcb 100644 --- a/vendor/github.com/mattn/go-sqlite3/sqlite3_opt_vtable.go +++ b/vendor/github.com/mattn/go-sqlite3/sqlite3_opt_vtable.go @@ -423,6 +423,9 @@ func goVRelease(pVTab unsafe.Pointer, isDestroy C.int) *C.char { } else { err = vt.vTab.Disconnect() } + // The vtab is gone as far as SQLite is concerned regardless of the + // callback result, so release the handle either way. + deleteHandle(pVTab) if err != nil { return mPrintf("%s", err.Error()) } @@ -451,6 +454,9 @@ func goVBestIndex(pVTab unsafe.Pointer, icp unsafe.Pointer) *C.char { if err != nil { return mPrintf("%s", err.Error()) } + if res == nil { + return mPrintf("%s", "BestIndex returned a nil IndexResult") + } if len(res.Used) != len(csts) { return mPrintf("Result.Used != expected value", "") } @@ -460,7 +466,11 @@ func goVBestIndex(pVTab unsafe.Pointer, icp unsafe.Pointer) *C.char { slice := unsafe.Slice(info.aConstraintUsage, int(info.nConstraint)) index := 1 for i := range slice { - if res.Used[i] { + // SQLite returns "xBestIndex malfunction" when an argvIndex is + // assigned to a constraint it marked as not usable, so ignore + // Used for those; they may become usable on a later xBestIndex + // invocation for a different plan. + if res.Used[i] && csts[i].Usable { slice[i].argvIndex = C.int(index) slice[i].omit = C.uchar(1) index++ @@ -482,8 +492,23 @@ func goVBestIndex(pVTab unsafe.Pointer, icp unsafe.Pointer) *C.char { if res.AlreadyOrdered { info.orderByConsumed = C.int(1) } - info.estimatedCost = C.double(res.EstimatedCost) - info.estimatedRows = C.sqlite3_int64(res.EstimatedRows) + // SQLite pre-initializes estimatedCost and estimatedRows with sensible + // defaults; overwriting them with the Go zero value would make every + // candidate plan look free and break query planning, so only pass + // values the implementation actually set. + if res.EstimatedCost > 0 { + info.estimatedCost = C.double(res.EstimatedCost) + } + if res.EstimatedRows > 0 { + var rows int64 + if res.EstimatedRows >= float64(math.MaxInt64) { + rows = math.MaxInt64 + } else if rows = int64(res.EstimatedRows); rows < 1 { + // A positive fractional estimate must not truncate to 0. + rows = 1 + } + info.estimatedRows = C.sqlite3_int64(rows) + } return nil } @@ -492,6 +517,9 @@ func goVBestIndex(pVTab unsafe.Pointer, icp unsafe.Pointer) *C.char { func goVClose(pCursor unsafe.Pointer) *C.char { vtc := lookupHandle(pCursor).(*sqliteVTabCursor) err := vtc.vTabCursor.Close() + // The cursor is gone as far as SQLite is concerned regardless of the + // callback result, so release the handle either way. + deleteHandle(pCursor) if err != nil { return mPrintf("%s", err.Error()) } @@ -502,6 +530,7 @@ func goVClose(pCursor unsafe.Pointer) *C.char { func goMDestroy(pClientData unsafe.Pointer) { m := lookupHandle(pClientData).(*sqliteModule) m.module.DestroyModule() + deleteHandle(pClientData) } //export goVFilter @@ -514,7 +543,14 @@ func goVFilter(pCursor unsafe.Pointer, idxNum C.int, idxName *C.char, argc C.int if err != nil { return mPrintf("%s", err.Error()) } - vals = append(vals, conv.Interface()) + + // work around for SQLITE_NULL + x := conv.Interface() + if z, ok := x.([]byte); ok && z == nil { + x = nil + } + + vals = append(vals, x) } err := vtc.vTabCursor.Filter(int(idxNum), C.GoString(idxName), vals) if err != nil { @@ -608,7 +644,15 @@ func goVUpdate(pVTab unsafe.Pointer, argc C.int, argv **C.sqlite3_value, pRowid } case argc > 1: - err = v.Update(vals[1], vals[2:]) + // Per the xUpdate contract argv[0] identifies the row being + // updated while argv[1] is its new rowid. VTabUpdater has no + // way to convey a rowid change, so reject it instead of + // silently updating values under the old rowid. + if vals[0] != vals[1] { + err = fmt.Errorf("virtual %s table %sdoes not support changing the rowid", vt.module.name, tname) + } else { + err = v.Update(vals[0], vals[2:]) + } } } @@ -708,5 +752,5 @@ func (c *SQLiteConn) CreateModule(moduleName string, module Module) error { } return nil } - return nil + return fmt.Errorf("sqlite3: CreateModule requires a non-nil module") } diff --git a/vendor/github.com/stretchr/testify/assert/assertion_format.go b/vendor/github.com/stretchr/testify/assert/assertion_format.go index c592f6ad5f..a19a89279c 100644 --- a/vendor/github.com/stretchr/testify/assert/assertion_format.go +++ b/vendor/github.com/stretchr/testify/assert/assertion_format.go @@ -84,7 +84,7 @@ func Equalf(t TestingT, expected interface{}, actual interface{}, msg string, ar return Equal(t, expected, actual, append([]interface{}{msg}, args...)...) } -// EqualErrorf asserts that a function returned an error (i.e. not `nil`) +// EqualErrorf asserts that a function returned a non-nil error (i.e. an error) // and that it is equal to the provided error. // // actualObj, err := SomeFunction() @@ -124,7 +124,7 @@ func EqualValuesf(t TestingT, expected interface{}, actual interface{}, msg stri return EqualValues(t, expected, actual, append([]interface{}{msg}, args...)...) } -// Errorf asserts that a function returned an error (i.e. not `nil`). +// Errorf asserts that a function returned a non-nil error (ie. an error). // // actualObj, err := SomeFunction() // assert.Errorf(t, err, "error message %s", "formatted") @@ -144,8 +144,8 @@ func ErrorAsf(t TestingT, err error, target interface{}, msg string, args ...int return ErrorAs(t, err, target, append([]interface{}{msg}, args...)...) } -// ErrorContainsf asserts that a function returned an error (i.e. not `nil`) -// and that the error contains the specified substring. +// ErrorContainsf asserts that a function returned a non-nil error (i.e. an +// error) and that the error contains the specified substring. // // actualObj, err := SomeFunction() // assert.ErrorContainsf(t, err, expectedErrorSubString, "error message %s", "formatted") @@ -190,10 +190,10 @@ func Eventuallyf(t TestingT, condition func() bool, waitFor time.Duration, tick // time.Sleep(8*time.Second) // externalValue = true // }() -// assert.EventuallyWithTf(t, func(c *assert.CollectT, "error message %s", "formatted") { +// assert.EventuallyWithTf(t, func(c *assert.CollectT) { // // add assertions as needed; any assertion failure will fail the current tick // assert.True(c, externalValue, "expected 'externalValue' to be true") -// }, 10*time.Second, 1*time.Second, "external state has not changed to 'true'; still false") +// }, 10*time.Second, 1*time.Second, "error message %s", "formatted") func EventuallyWithTf(t TestingT, condition func(collect *CollectT), waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -552,7 +552,7 @@ func NoDirExistsf(t TestingT, path string, msg string, args ...interface{}) bool return NoDirExists(t, path, append([]interface{}{msg}, args...)...) } -// NoErrorf asserts that a function returned no error (i.e. `nil`). +// NoErrorf asserts that a function returned a nil error (ie. no error). // // actualObj, err := SomeFunction() // if assert.NoErrorf(t, err, "error message %s", "formatted") { @@ -849,7 +849,19 @@ func WithinRangef(t TestingT, actual time.Time, start time.Time, end time.Time, return WithinRange(t, actual, start, end, append([]interface{}{msg}, args...)...) } -// YAMLEqf asserts that two YAML strings are equivalent. +// YAMLEqf asserts that the first documents in the two YAML strings are equivalent. +// +// expected := `--- +// key: value +// --- +// key: this is a second document, it is not evaluated +// ` +// actual := `--- +// key: value +// --- +// key: this is a subsequent document, it is not evaluated +// ` +// assert.YAMLEqf(t, expected, actual, "error message %s", "formatted") func YAMLEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() diff --git a/vendor/github.com/stretchr/testify/assert/assertion_forward.go b/vendor/github.com/stretchr/testify/assert/assertion_forward.go index 58db928450..cd2a86061c 100644 --- a/vendor/github.com/stretchr/testify/assert/assertion_forward.go +++ b/vendor/github.com/stretchr/testify/assert/assertion_forward.go @@ -146,7 +146,7 @@ func (a *Assertions) Equal(expected interface{}, actual interface{}, msgAndArgs return Equal(a.t, expected, actual, msgAndArgs...) } -// EqualError asserts that a function returned an error (i.e. not `nil`) +// EqualError asserts that a function returned a non-nil error (i.e. an error) // and that it is equal to the provided error. // // actualObj, err := SomeFunction() @@ -158,7 +158,7 @@ func (a *Assertions) EqualError(theError error, errString string, msgAndArgs ... return EqualError(a.t, theError, errString, msgAndArgs...) } -// EqualErrorf asserts that a function returned an error (i.e. not `nil`) +// EqualErrorf asserts that a function returned a non-nil error (i.e. an error) // and that it is equal to the provided error. // // actualObj, err := SomeFunction() @@ -240,7 +240,7 @@ func (a *Assertions) Equalf(expected interface{}, actual interface{}, msg string return Equalf(a.t, expected, actual, msg, args...) } -// Error asserts that a function returned an error (i.e. not `nil`). +// Error asserts that a function returned a non-nil error (ie. an error). // // actualObj, err := SomeFunction() // a.Error(err) @@ -269,8 +269,8 @@ func (a *Assertions) ErrorAsf(err error, target interface{}, msg string, args .. return ErrorAsf(a.t, err, target, msg, args...) } -// ErrorContains asserts that a function returned an error (i.e. not `nil`) -// and that the error contains the specified substring. +// ErrorContains asserts that a function returned a non-nil error (i.e. an +// error) and that the error contains the specified substring. // // actualObj, err := SomeFunction() // a.ErrorContains(err, expectedErrorSubString) @@ -281,8 +281,8 @@ func (a *Assertions) ErrorContains(theError error, contains string, msgAndArgs . return ErrorContains(a.t, theError, contains, msgAndArgs...) } -// ErrorContainsf asserts that a function returned an error (i.e. not `nil`) -// and that the error contains the specified substring. +// ErrorContainsf asserts that a function returned a non-nil error (i.e. an +// error) and that the error contains the specified substring. // // actualObj, err := SomeFunction() // a.ErrorContainsf(err, expectedErrorSubString, "error message %s", "formatted") @@ -311,7 +311,7 @@ func (a *Assertions) ErrorIsf(err error, target error, msg string, args ...inter return ErrorIsf(a.t, err, target, msg, args...) } -// Errorf asserts that a function returned an error (i.e. not `nil`). +// Errorf asserts that a function returned a non-nil error (ie. an error). // // actualObj, err := SomeFunction() // a.Errorf(err, "error message %s", "formatted") @@ -372,10 +372,10 @@ func (a *Assertions) EventuallyWithT(condition func(collect *CollectT), waitFor // time.Sleep(8*time.Second) // externalValue = true // }() -// a.EventuallyWithTf(func(c *assert.CollectT, "error message %s", "formatted") { +// a.EventuallyWithTf(func(c *assert.CollectT) { // // add assertions as needed; any assertion failure will fail the current tick // assert.True(c, externalValue, "expected 'externalValue' to be true") -// }, 10*time.Second, 1*time.Second, "external state has not changed to 'true'; still false") +// }, 10*time.Second, 1*time.Second, "error message %s", "formatted") func (a *Assertions) EventuallyWithTf(condition func(collect *CollectT), waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1096,7 +1096,7 @@ func (a *Assertions) NoDirExistsf(path string, msg string, args ...interface{}) return NoDirExistsf(a.t, path, msg, args...) } -// NoError asserts that a function returned no error (i.e. `nil`). +// NoError asserts that a function returned a nil error (ie. no error). // // actualObj, err := SomeFunction() // if a.NoError(err) { @@ -1109,7 +1109,7 @@ func (a *Assertions) NoError(err error, msgAndArgs ...interface{}) bool { return NoError(a.t, err, msgAndArgs...) } -// NoErrorf asserts that a function returned no error (i.e. `nil`). +// NoErrorf asserts that a function returned a nil error (ie. no error). // // actualObj, err := SomeFunction() // if a.NoErrorf(err, "error message %s", "formatted") { @@ -1690,7 +1690,19 @@ func (a *Assertions) WithinRangef(actual time.Time, start time.Time, end time.Ti return WithinRangef(a.t, actual, start, end, msg, args...) } -// YAMLEq asserts that two YAML strings are equivalent. +// YAMLEq asserts that the first documents in the two YAML strings are equivalent. +// +// expected := `--- +// key: value +// --- +// key: this is a second document, it is not evaluated +// ` +// actual := `--- +// key: value +// --- +// key: this is a subsequent document, it is not evaluated +// ` +// a.YAMLEq(expected, actual) func (a *Assertions) YAMLEq(expected string, actual string, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1698,7 +1710,19 @@ func (a *Assertions) YAMLEq(expected string, actual string, msgAndArgs ...interf return YAMLEq(a.t, expected, actual, msgAndArgs...) } -// YAMLEqf asserts that two YAML strings are equivalent. +// YAMLEqf asserts that the first documents in the two YAML strings are equivalent. +// +// expected := `--- +// key: value +// --- +// key: this is a second document, it is not evaluated +// ` +// actual := `--- +// key: value +// --- +// key: this is a subsequent document, it is not evaluated +// ` +// a.YAMLEqf(expected, actual, "error message %s", "formatted") func (a *Assertions) YAMLEqf(expected string, actual string, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() diff --git a/vendor/github.com/stretchr/testify/assert/assertion_order.go b/vendor/github.com/stretchr/testify/assert/assertion_order.go index 2fdf80fdd3..a44b40ed3f 100644 --- a/vendor/github.com/stretchr/testify/assert/assertion_order.go +++ b/vendor/github.com/stretchr/testify/assert/assertion_order.go @@ -9,7 +9,7 @@ import ( func isOrdered(t TestingT, object interface{}, allowedComparesResults []compareResult, failMessage string, msgAndArgs ...interface{}) bool { objKind := reflect.TypeOf(object).Kind() if objKind != reflect.Slice && objKind != reflect.Array { - return false + return Fail(t, fmt.Sprintf("object %T is not an ordered collection", object), msgAndArgs...) } objValue := reflect.ValueOf(object) @@ -50,6 +50,9 @@ func isOrdered(t TestingT, object interface{}, allowedComparesResults []compareR // assert.IsIncreasing(t, []float{1, 2}) // assert.IsIncreasing(t, []string{"a", "b"}) func IsIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } return isOrdered(t, object, []compareResult{compareLess}, "\"%v\" is not less than \"%v\"", msgAndArgs...) } @@ -59,6 +62,9 @@ func IsIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) boo // assert.IsNonIncreasing(t, []float{2, 1}) // assert.IsNonIncreasing(t, []string{"b", "a"}) func IsNonIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } return isOrdered(t, object, []compareResult{compareEqual, compareGreater}, "\"%v\" is not greater than or equal to \"%v\"", msgAndArgs...) } @@ -68,6 +74,9 @@ func IsNonIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) // assert.IsDecreasing(t, []float{2, 1}) // assert.IsDecreasing(t, []string{"b", "a"}) func IsDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } return isOrdered(t, object, []compareResult{compareGreater}, "\"%v\" is not greater than \"%v\"", msgAndArgs...) } @@ -77,5 +86,8 @@ func IsDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) boo // assert.IsNonDecreasing(t, []float{1, 2}) // assert.IsNonDecreasing(t, []string{"a", "b"}) func IsNonDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } return isOrdered(t, object, []compareResult{compareLess, compareEqual}, "\"%v\" is not less than or equal to \"%v\"", msgAndArgs...) } diff --git a/vendor/github.com/stretchr/testify/assert/assertions.go b/vendor/github.com/stretchr/testify/assert/assertions.go index de8de0cb6c..166f63726c 100644 --- a/vendor/github.com/stretchr/testify/assert/assertions.go +++ b/vendor/github.com/stretchr/testify/assert/assertions.go @@ -17,11 +17,10 @@ import ( "unicode" "unicode/utf8" - "github.com/davecgh/go-spew/spew" - "github.com/pmezard/go-difflib/difflib" - - // Wrapper around gopkg.in/yaml.v3 + // Wrapper around go.yaml.in/yaml/v3 "github.com/stretchr/testify/assert/yaml" + "github.com/stretchr/testify/internal/difflib" + "github.com/stretchr/testify/internal/spew" ) //go:generate sh -c "cd ../_codegen && go build && cd - && ../_codegen/_codegen -output-package=assert -template=assertion_format.go.tmpl" @@ -33,19 +32,19 @@ type TestingT interface { // ComparisonAssertionFunc is a common function prototype when comparing two values. Can be useful // for table driven tests. -type ComparisonAssertionFunc func(TestingT, interface{}, interface{}, ...interface{}) bool +type ComparisonAssertionFunc = func(TestingT, interface{}, interface{}, ...interface{}) bool // ValueAssertionFunc is a common function prototype when validating a single value. Can be useful // for table driven tests. -type ValueAssertionFunc func(TestingT, interface{}, ...interface{}) bool +type ValueAssertionFunc = func(TestingT, interface{}, ...interface{}) bool // BoolAssertionFunc is a common function prototype when validating a bool value. Can be useful // for table driven tests. -type BoolAssertionFunc func(TestingT, bool, ...interface{}) bool +type BoolAssertionFunc = func(TestingT, bool, ...interface{}) bool // ErrorAssertionFunc is a common function prototype when validating an error value. Can be useful // for table driven tests. -type ErrorAssertionFunc func(TestingT, error, ...interface{}) bool +type ErrorAssertionFunc = func(TestingT, error, ...interface{}) bool // PanicAssertionFunc is a common function prototype when validating a panic value. Can be useful // for table driven tests. @@ -325,13 +324,15 @@ func messageFromMsgAndArgs(msgAndArgs ...interface{}) string { func indentMessageLines(message string, longestLabelLen int) string { outBuf := new(bytes.Buffer) - for i, scanner := 0, bufio.NewScanner(strings.NewReader(message)); scanner.Scan(); i++ { - // no need to align first line because it starts at the correct location (after the label) - if i != 0 { - // append alignLen+1 spaces to align with "{{longestLabel}}:" before adding tab - outBuf.WriteString("\n\t" + strings.Repeat(" ", longestLabelLen+1) + "\t") + scanner := bufio.NewScanner(strings.NewReader(message)) + for firstLine := true; scanner.Scan(); firstLine = false { + if !firstLine { + fmt.Fprint(outBuf, "\n\t"+strings.Repeat(" ", longestLabelLen+1)+"\t") } - outBuf.WriteString(scanner.Text()) + fmt.Fprint(outBuf, scanner.Text()) + } + if err := scanner.Err(); err != nil { + return fmt.Sprintf("cannot display message: %s", err) } return outBuf.String() @@ -544,9 +545,8 @@ func Same(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) b if !same { // both are pointers but not the same type & pointing to the same address return Fail(t, fmt.Sprintf("Not same: \n"+ - "expected: %p %#[1]v\n"+ - "actual : %p %#[2]v", - expected, actual), msgAndArgs...) + "expected: %[2]s (%[1]T)(%[1]p)\n"+ + "actual : %[4]s (%[3]T)(%[3]p)", expected, truncatingFormat("%#v", expected), actual, truncatingFormat("%#v", actual)), msgAndArgs...) } return true @@ -571,8 +571,8 @@ func NotSame(t TestingT, expected, actual interface{}, msgAndArgs ...interface{} if same { return Fail(t, fmt.Sprintf( - "Expected and actual point to the same object: %p %#[1]v", - expected), msgAndArgs...) + "Expected and actual point to the same object: %p %s", + expected, truncatingFormat("%#v", expected)), msgAndArgs...) } return true } @@ -604,25 +604,26 @@ func samePointers(first, second interface{}) (same bool, ok bool) { // to a type conversion in the Go grammar. func formatUnequalValues(expected, actual interface{}) (e string, a string) { if reflect.TypeOf(expected) != reflect.TypeOf(actual) { - return fmt.Sprintf("%T(%s)", expected, truncatingFormat(expected)), - fmt.Sprintf("%T(%s)", actual, truncatingFormat(actual)) + return fmt.Sprintf("%T(%s)", expected, truncatingFormat("%#v", expected)), + fmt.Sprintf("%T(%s)", actual, truncatingFormat("%#v", actual)) } switch expected.(type) { case time.Duration: return fmt.Sprintf("%v", expected), fmt.Sprintf("%v", actual) } - return truncatingFormat(expected), truncatingFormat(actual) + return truncatingFormat("%#v", expected), truncatingFormat("%#v", actual) } // truncatingFormat formats the data and truncates it if it's too long. // // This helps keep formatted error messages lines from exceeding the // bufio.MaxScanTokenSize max line length that the go testing framework imposes. -func truncatingFormat(data interface{}) string { - value := fmt.Sprintf("%#v", data) - max := bufio.MaxScanTokenSize - 100 // Give us some space the type info too if needed. - if len(value) > max { - value = value[0:max] + "<... truncated>" +func truncatingFormat(format string, data interface{}) string { + value := fmt.Sprintf(format, data) + // Give us space for two truncated objects and the surrounding sentence. + maxMessageSize := bufio.MaxScanTokenSize/2 - 100 + if len(value) > maxMessageSize { + value = value[0:maxMessageSize] + "<... truncated>" } return value } @@ -743,7 +744,7 @@ func Nil(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } - return Fail(t, fmt.Sprintf("Expected nil, but got: %#v", object), msgAndArgs...) + return Fail(t, fmt.Sprintf("Expected nil, but got: %s", truncatingFormat("%#v", object)), msgAndArgs...) } // isEmpty gets whether the specified object is considered empty or not. @@ -793,7 +794,7 @@ func Empty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } - Fail(t, fmt.Sprintf("Should be empty, but was %v", object), msgAndArgs...) + Fail(t, fmt.Sprintf("Should be empty, but was %s", truncatingFormat("%v", object)), msgAndArgs...) } return pass @@ -836,11 +837,11 @@ func Len(t TestingT, object interface{}, length int, msgAndArgs ...interface{}) } l, ok := getLen(object) if !ok { - return Fail(t, fmt.Sprintf("\"%v\" could not be applied builtin len()", object), msgAndArgs...) + return Fail(t, fmt.Sprintf("%q could not be applied builtin len()", truncatingFormat("%v", object)), msgAndArgs...) } if l != length { - return Fail(t, fmt.Sprintf("\"%v\" should have %d item(s), but has %d", object, length, l), msgAndArgs...) + return Fail(t, fmt.Sprintf("%q should have %d item(s), but has %d", truncatingFormat("%v", object), length, l), msgAndArgs...) } return true } @@ -889,7 +890,7 @@ func NotEqual(t TestingT, expected, actual interface{}, msgAndArgs ...interface{ } if ObjectsAreEqual(expected, actual) { - return Fail(t, fmt.Sprintf("Should not be: %#v\n", actual), msgAndArgs...) + return Fail(t, fmt.Sprintf("Should not be: %s\n", truncatingFormat("%#v", actual)), msgAndArgs...) } return true @@ -904,7 +905,7 @@ func NotEqualValues(t TestingT, expected, actual interface{}, msgAndArgs ...inte } if ObjectsAreEqualValues(expected, actual) { - return Fail(t, fmt.Sprintf("Should not be: %#v\n", actual), msgAndArgs...) + return Fail(t, fmt.Sprintf("Should not be: %s\n", truncatingFormat("%#v", actual)), msgAndArgs...) } return true @@ -964,10 +965,10 @@ func Contains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bo ok, found := containsElement(s, contains) if !ok { - return Fail(t, fmt.Sprintf("%#v could not be applied builtin len()", s), msgAndArgs...) + return Fail(t, fmt.Sprintf("%s could not be applied builtin len()", truncatingFormat("%#v", s)), msgAndArgs...) } if !found { - return Fail(t, fmt.Sprintf("%#v does not contain %#v", s, contains), msgAndArgs...) + return Fail(t, fmt.Sprintf("%s does not contain %#v", truncatingFormat("%#v", s), contains), msgAndArgs...) } return true @@ -986,10 +987,10 @@ func NotContains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) ok, found := containsElement(s, contains) if !ok { - return Fail(t, fmt.Sprintf("%#v could not be applied builtin len()", s), msgAndArgs...) + return Fail(t, fmt.Sprintf("%s could not be applied builtin len()", truncatingFormat("%#v", s)), msgAndArgs...) } if found { - return Fail(t, fmt.Sprintf("%#v should not contain %#v", s, contains), msgAndArgs...) + return Fail(t, fmt.Sprintf("%s should not contain %#v", truncatingFormat("%#v", s), contains), msgAndArgs...) } return true @@ -1031,10 +1032,10 @@ func Subset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) (ok av := actualMap.MapIndex(k) if !av.IsValid() { - return Fail(t, fmt.Sprintf("%#v does not contain %#v", list, subset), msgAndArgs...) + return Fail(t, fmt.Sprintf("%s does not contain %s", truncatingFormat("%#v", list), truncatingFormat("%#v", subset)), msgAndArgs...) } if !ObjectsAreEqual(ev.Interface(), av.Interface()) { - return Fail(t, fmt.Sprintf("%#v does not contain %#v", list, subset), msgAndArgs...) + return Fail(t, fmt.Sprintf("%s does not contain %s", truncatingFormat("%#v", list), truncatingFormat("%#v", subset)), msgAndArgs...) } } @@ -1056,7 +1057,7 @@ func Subset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) (ok return Fail(t, fmt.Sprintf("%#v could not be applied builtin len()", list), msgAndArgs...) } if !found { - return Fail(t, fmt.Sprintf("%#v does not contain %#v", list, element), msgAndArgs...) + return Fail(t, fmt.Sprintf("%s does not contain %#v", truncatingFormat("%#v", list), element), msgAndArgs...) } } @@ -1082,12 +1083,12 @@ func NotSubset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) listKind := reflect.TypeOf(list).Kind() if listKind != reflect.Array && listKind != reflect.Slice && listKind != reflect.Map { - return Fail(t, fmt.Sprintf("%q has an unsupported type %s", list, listKind), msgAndArgs...) + return Fail(t, fmt.Sprintf("%#v has an unsupported type %s", list, listKind), msgAndArgs...) } subsetKind := reflect.TypeOf(subset).Kind() if subsetKind != reflect.Array && subsetKind != reflect.Slice && subsetKind != reflect.Map { - return Fail(t, fmt.Sprintf("%q has an unsupported type %s", subset, subsetKind), msgAndArgs...) + return Fail(t, fmt.Sprintf("%#v has an unsupported type %s", subset, subsetKind), msgAndArgs...) } if subsetKind == reflect.Map && listKind == reflect.Map { @@ -1106,7 +1107,7 @@ func NotSubset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) } } - return Fail(t, fmt.Sprintf("%q is a subset of %q", subset, list), msgAndArgs...) + return Fail(t, fmt.Sprintf("%s is a subset of %s", truncatingFormat("%#v", subset), truncatingFormat("%#v", list)), msgAndArgs...) } subsetList := reflect.ValueOf(subset) @@ -1121,14 +1122,14 @@ func NotSubset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) element := subsetList.Index(i).Interface() ok, found := containsElement(list, element) if !ok { - return Fail(t, fmt.Sprintf("%q could not be applied builtin len()", list), msgAndArgs...) + return Fail(t, fmt.Sprintf("%#v could not be applied builtin len()", list), msgAndArgs...) } if !found { return true } } - return Fail(t, fmt.Sprintf("%q is a subset of %q", subset, list), msgAndArgs...) + return Fail(t, fmt.Sprintf("%s is a subset of %s", truncatingFormat("%#v", subset), truncatingFormat("%#v", list)), msgAndArgs...) } // ElementsMatch asserts that the specified listA(array, slice...) is equal to specified @@ -1343,9 +1344,15 @@ func PanicsWithError(t TestingT, errString string, f PanicTestFunc, msgAndArgs . if !funcDidPanic { return Fail(t, fmt.Sprintf("func %#v should panic\n\tPanic value:\t%#v", f, panicValue), msgAndArgs...) } - panicErr, ok := panicValue.(error) - if !ok || panicErr.Error() != errString { - return Fail(t, fmt.Sprintf("func %#v should panic with error message:\t%#v\n\tPanic value:\t%#v\n\tPanic stack:\t%s", f, errString, panicValue, panickedStack), msgAndArgs...) + panicErr, isError := panicValue.(error) + if !isError || panicErr.Error() != errString { + msg := fmt.Sprintf("func %#v should panic with error message:\t%#v\n", f, errString) + if isError { + msg += fmt.Sprintf("\tError message:\t%#v\n", panicErr.Error()) + } + msg += fmt.Sprintf("\tPanic value:\t%#v\n", panicValue) + msg += fmt.Sprintf("\tPanic stack:\t%s\n", panickedStack) + return Fail(t, msg, msgAndArgs...) } return true @@ -1624,7 +1631,7 @@ func InEpsilonSlice(t TestingT, expected, actual interface{}, epsilon float64, m Errors */ -// NoError asserts that a function returned no error (i.e. `nil`). +// NoError asserts that a function returned a nil error (ie. no error). // // actualObj, err := SomeFunction() // if assert.NoError(t, err) { @@ -1635,13 +1642,13 @@ func NoError(t TestingT, err error, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() } - return Fail(t, fmt.Sprintf("Received unexpected error:\n%+v", err), msgAndArgs...) + return Fail(t, fmt.Sprintf("Received unexpected error:\n%s", truncatingFormat("%+v", err)), msgAndArgs...) } return true } -// Error asserts that a function returned an error (i.e. not `nil`). +// Error asserts that a function returned a non-nil error (ie. an error). // // actualObj, err := SomeFunction() // assert.Error(t, err) @@ -1656,7 +1663,7 @@ func Error(t TestingT, err error, msgAndArgs ...interface{}) bool { return true } -// EqualError asserts that a function returned an error (i.e. not `nil`) +// EqualError asserts that a function returned a non-nil error (i.e. an error) // and that it is equal to the provided error. // // actualObj, err := SomeFunction() @@ -1674,13 +1681,13 @@ func EqualError(t TestingT, theError error, errString string, msgAndArgs ...inte if expected != actual { return Fail(t, fmt.Sprintf("Error message not equal:\n"+ "expected: %q\n"+ - "actual : %q", expected, actual), msgAndArgs...) + "actual : %s", expected, truncatingFormat("%q", actual)), msgAndArgs...) } return true } -// ErrorContains asserts that a function returned an error (i.e. not `nil`) -// and that the error contains the specified substring. +// ErrorContains asserts that a function returned a non-nil error (i.e. an +// error) and that the error contains the specified substring. // // actualObj, err := SomeFunction() // assert.ErrorContains(t, err, expectedErrorSubString) @@ -1694,7 +1701,7 @@ func ErrorContains(t TestingT, theError error, contains string, msgAndArgs ...in actual := theError.Error() if !strings.Contains(actual, contains) { - return Fail(t, fmt.Sprintf("Error %#v does not contain %#v", actual, contains), msgAndArgs...) + return Fail(t, fmt.Sprintf("Error %s does not contain %#v", truncatingFormat("%#v", actual), contains), msgAndArgs...) } return true @@ -1760,7 +1767,7 @@ func Zero(t TestingT, i interface{}, msgAndArgs ...interface{}) bool { h.Helper() } if i != nil && !reflect.DeepEqual(i, reflect.Zero(reflect.TypeOf(i)).Interface()) { - return Fail(t, fmt.Sprintf("Should be zero, but was %v", i), msgAndArgs...) + return Fail(t, fmt.Sprintf("Should be zero, but was %s", truncatingFormat("%v", i)), msgAndArgs...) } return true } @@ -1874,7 +1881,19 @@ func JSONEq(t TestingT, expected string, actual string, msgAndArgs ...interface{ return Equal(t, expectedJSONAsInterface, actualJSONAsInterface, msgAndArgs...) } -// YAMLEq asserts that two YAML strings are equivalent. +// YAMLEq asserts that the first documents in the two YAML strings are equivalent. +// +// expected := `--- +// key: value +// --- +// key: this is a second document, it is not evaluated +// ` +// actual := `--- +// key: value +// --- +// key: this is a subsequent document, it is not evaluated +// ` +// assert.YAMLEq(t, expected, actual) func YAMLEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -2188,8 +2207,8 @@ func ErrorIs(t TestingT, err, target error, msgAndArgs ...interface{}) bool { chain := buildErrorChainString(err, false) return Fail(t, fmt.Sprintf("Target error should be in err chain:\n"+ - "expected: %q\n"+ - "in chain: %s", expectedText, chain, + "expected: %s\n"+ + "in chain: %s", truncatingFormat("%q", expectedText), truncatingFormat("%s", chain), ), msgAndArgs...) } @@ -2211,8 +2230,8 @@ func NotErrorIs(t TestingT, err, target error, msgAndArgs ...interface{}) bool { chain := buildErrorChainString(err, false) return Fail(t, fmt.Sprintf("Target error should not be in err chain:\n"+ - "found: %q\n"+ - "in chain: %s", expectedText, chain, + "found: %s\n"+ + "in chain: %s", truncatingFormat("%q", expectedText), truncatingFormat("%s", chain), ), msgAndArgs...) } @@ -2236,7 +2255,7 @@ func ErrorAs(t TestingT, err error, target interface{}, msgAndArgs ...interface{ return Fail(t, fmt.Sprintf("Should be in error chain:\n"+ "expected: %s\n"+ - "in chain: %s", expectedType, chain, + "in chain: %s", expectedType, truncatingFormat("%s", chain), ), msgAndArgs...) } @@ -2254,7 +2273,7 @@ func NotErrorAs(t TestingT, err error, target interface{}, msgAndArgs ...interfa return Fail(t, fmt.Sprintf("Target error should not be in err chain:\n"+ "found: %s\n"+ - "in chain: %s", reflect.TypeOf(target).Elem().String(), chain, + "in chain: %s", reflect.TypeOf(target).Elem().String(), truncatingFormat("%s", chain), ), msgAndArgs...) } diff --git a/vendor/github.com/stretchr/testify/assert/doc.go b/vendor/github.com/stretchr/testify/assert/doc.go index a0b953aa5c..c111589c7e 100644 --- a/vendor/github.com/stretchr/testify/assert/doc.go +++ b/vendor/github.com/stretchr/testify/assert/doc.go @@ -40,8 +40,8 @@ // // # Assertions // -// Assertions allow you to easily write test code, and are global funcs in the `assert` package. -// All assertion functions take, as the first argument, the `*testing.T` object provided by the +// Assertions allow you to easily write test code, and are global funcs in the assert package. +// All assertion functions take, as the first argument, the [*testing.T] object provided by the // testing framework. This allows the assertion funcs to write the failings and other details to // the correct place. // diff --git a/vendor/github.com/stretchr/testify/assert/yaml/yaml_custom.go b/vendor/github.com/stretchr/testify/assert/yaml/yaml_custom.go index 5a74c4f4d5..956227ca27 100644 --- a/vendor/github.com/stretchr/testify/assert/yaml/yaml_custom.go +++ b/vendor/github.com/stretchr/testify/assert/yaml/yaml_custom.go @@ -7,7 +7,7 @@ // go test -tags testify_yaml_custom // // This implementation can be used at build time to replace the default implementation -// to avoid linking with [gopkg.in/yaml.v3]. +// to avoid linking with [go.yaml.in/yaml/v3]. // // In your test package: // diff --git a/vendor/github.com/stretchr/testify/assert/yaml/yaml_default.go b/vendor/github.com/stretchr/testify/assert/yaml/yaml_default.go index 0bae80e34a..dd89ac03aa 100644 --- a/vendor/github.com/stretchr/testify/assert/yaml/yaml_default.go +++ b/vendor/github.com/stretchr/testify/assert/yaml/yaml_default.go @@ -6,7 +6,7 @@ // indirection with an alternative implementation of this package that uses // another implementation of YAML deserialization. This allows to not either not // use YAML deserialization at all, or to use another implementation than -// [gopkg.in/yaml.v3] (for example for license compatibility reasons, see [PR #1120]). +// [go.yaml.in/yaml/v3] (for example for license compatibility reasons, see [PR #1120]). // // Alternative implementations are selected using build tags: // @@ -28,9 +28,9 @@ // [PR #1120]: https://github.com/stretchr/testify/pull/1120 package yaml -import goyaml "gopkg.in/yaml.v3" +import goyaml "go.yaml.in/yaml/v3" -// Unmarshal is just a wrapper of [gopkg.in/yaml.v3.Unmarshal]. +// Unmarshal is just a wrapper of [go.yaml.in/yaml/v3.Unmarshal]. func Unmarshal(in []byte, out interface{}) error { return goyaml.Unmarshal(in, out) } diff --git a/vendor/github.com/stretchr/testify/assert/yaml/yaml_fail.go b/vendor/github.com/stretchr/testify/assert/yaml/yaml_fail.go index 8041803fd2..a51d279250 100644 --- a/vendor/github.com/stretchr/testify/assert/yaml/yaml_fail.go +++ b/vendor/github.com/stretchr/testify/assert/yaml/yaml_fail.go @@ -3,7 +3,7 @@ // Package yaml is an implementation of YAML functions that always fail. // // This implementation can be used at build time to replace the default implementation -// to avoid linking with [gopkg.in/yaml.v3]: +// to avoid linking with [go.yaml.in/yaml/v3]: // // go test -tags testify_yaml_fail package yaml diff --git a/vendor/github.com/stretchr/testify/internal/difflib/LICENSE b/vendor/github.com/stretchr/testify/internal/difflib/LICENSE new file mode 100644 index 0000000000..485be13c67 --- /dev/null +++ b/vendor/github.com/stretchr/testify/internal/difflib/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2013, Patrick Mezard +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + The names of its contributors may not be used to endorse or promote +products derived from this software without specific prior written +permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/vendor/github.com/stretchr/testify/internal/difflib/difflib.go b/vendor/github.com/stretchr/testify/internal/difflib/difflib.go new file mode 100644 index 0000000000..9984599b4f --- /dev/null +++ b/vendor/github.com/stretchr/testify/internal/difflib/difflib.go @@ -0,0 +1,592 @@ +// Package difflib is a partial port of Python difflib module. +// +// It provides tools to compare sequences of strings and generate textual diffs. +// +// The following class and functions have been ported: +// +// - SequenceMatcher +// +// - unified_diff +// +// Getting unified diffs was the main goal of the port. Keep in mind this code +// is mostly suitable to output text differences in a human friendly way, there +// are no guarantees generated diffs are consumable by patch(1). +// +// This package was adopted from [github.com/pmezard/go-difflib] which +// is no longer maintained. +// +// [github.com/pmezard/go-difflib]: https://github.com/pmezard/go-difflib +package difflib + +import ( + "bufio" + "bytes" + "fmt" + "io" + "strings" +) + +func min(a, b int) int { + if a < b { + return a + } + return b +} + +func max(a, b int) int { + if a > b { + return a + } + return b +} + +type Match struct { + A int + B int + Size int +} + +type OpCode struct { + Tag byte + I1 int + I2 int + J1 int + J2 int +} + +// SequenceMatcher compares sequence of strings. The basic +// algorithm predates, and is a little fancier than, an algorithm +// published in the late 1980's by Ratcliff and Obershelp under the +// hyperbolic name "gestalt pattern matching". The basic idea is to find +// the longest contiguous matching subsequence that contains no "junk" +// elements (R-O doesn't address junk). The same idea is then applied +// recursively to the pieces of the sequences to the left and to the right +// of the matching subsequence. This does not yield minimal edit +// sequences, but does tend to yield matches that "look right" to people. +// +// SequenceMatcher tries to compute a "human-friendly diff" between two +// sequences. Unlike e.g. UNIX(tm) diff, the fundamental notion is the +// longest *contiguous* & junk-free matching subsequence. That's what +// catches peoples' eyes. The Windows(tm) windiff has another interesting +// notion, pairing up elements that appear uniquely in each sequence. +// That, and the method here, appear to yield more intuitive difference +// reports than does diff. This method appears to be the least vulnerable +// to synching up on blocks of "junk lines", though (like blank lines in +// ordinary text files, or maybe "

" lines in HTML files). That may be +// because this is the only method of the 3 that has a *concept* of +// "junk" . +// +// Timing: Basic R-O is cubic time worst case and quadratic time expected +// case. SequenceMatcher is quadratic time for the worst case and has +// expected-case behavior dependent in a complicated way on how many +// elements the sequences have in common; best case time is linear. +type SequenceMatcher struct { + a []string + b []string + b2j map[string][]int + IsJunk func(string) bool + autoJunk bool + bJunk map[string]struct{} + matchingBlocks []Match + fullBCount map[string]int + bPopular map[string]struct{} + opCodes []OpCode +} + +func NewMatcher(a, b []string) *SequenceMatcher { + m := SequenceMatcher{autoJunk: true} + m.SetSeqs(a, b) + return &m +} + +// Set two sequences to be compared. +func (m *SequenceMatcher) SetSeqs(a, b []string) { + m.SetSeq1(a) + m.SetSeq2(b) +} + +// Set the first sequence to be compared. The second sequence to be compared is +// not changed. +// +// SequenceMatcher computes and caches detailed information about the second +// sequence, so if you want to compare one sequence S against many sequences, +// use .SetSeq2(s) once and call .SetSeq1(x) repeatedly for each of the other +// sequences. +// +// See also SetSeqs() and SetSeq2(). +func (m *SequenceMatcher) SetSeq1(a []string) { + if &a == &m.a { + return + } + m.a = a + m.matchingBlocks = nil + m.opCodes = nil +} + +// Set the second sequence to be compared. The first sequence to be compared is +// not changed. +func (m *SequenceMatcher) SetSeq2(b []string) { + if &b == &m.b { + return + } + m.b = b + m.matchingBlocks = nil + m.opCodes = nil + m.fullBCount = nil + m.chainB() +} + +func (m *SequenceMatcher) chainB() { + // Populate line -> index mapping + b2j := map[string][]int{} + for i, s := range m.b { + indices := b2j[s] + indices = append(indices, i) + b2j[s] = indices + } + + // Purge junk elements + m.bJunk = map[string]struct{}{} + if m.IsJunk != nil { + junk := m.bJunk + for s, _ := range b2j { + if m.IsJunk(s) { + junk[s] = struct{}{} + } + } + for s, _ := range junk { + delete(b2j, s) + } + } + + // Purge remaining popular elements + popular := map[string]struct{}{} + n := len(m.b) + if m.autoJunk && n >= 200 { + ntest := n/100 + 1 + for s, indices := range b2j { + if len(indices) > ntest { + popular[s] = struct{}{} + } + } + for s, _ := range popular { + delete(b2j, s) + } + } + m.bPopular = popular + m.b2j = b2j +} + +func (m *SequenceMatcher) isBJunk(s string) bool { + _, ok := m.bJunk[s] + return ok +} + +// Find longest matching block in a[alo:ahi] and b[blo:bhi]. +// +// If IsJunk is not defined: +// +// Return (i,j,k) such that a[i:i+k] is equal to b[j:j+k], where +// +// alo <= i <= i+k <= ahi +// blo <= j <= j+k <= bhi +// +// and for all (i',j',k') meeting those conditions, +// +// k >= k' +// i <= i' +// and if i == i', j <= j' +// +// In other words, of all maximal matching blocks, return one that +// starts earliest in a, and of all those maximal matching blocks that +// start earliest in a, return the one that starts earliest in b. +// +// If IsJunk is defined, first the longest matching block is +// determined as above, but with the additional restriction that no +// junk element appears in the block. Then that block is extended as +// far as possible by matching (only) junk elements on both sides. So +// the resulting block never matches on junk except as identical junk +// happens to be adjacent to an "interesting" match. +// +// If no blocks match, return (alo, blo, 0). +func (m *SequenceMatcher) findLongestMatch(alo, ahi, blo, bhi int) Match { + // CAUTION: stripping common prefix or suffix would be incorrect. + // E.g., + // ab + // acab + // Longest matching block is "ab", but if common prefix is + // stripped, it's "a" (tied with "b"). UNIX(tm) diff does so + // strip, so ends up claiming that ab is changed to acab by + // inserting "ca" in the middle. That's minimal but unintuitive: + // "it's obvious" that someone inserted "ac" at the front. + // Windiff ends up at the same place as diff, but by pairing up + // the unique 'b's and then matching the first two 'a's. + besti, bestj, bestsize := alo, blo, 0 + + // find longest junk-free match + // during an iteration of the loop, j2len[j] = length of longest + // junk-free match ending with a[i-1] and b[j] + j2len := map[int]int{} + for i := alo; i != ahi; i++ { + // look at all instances of a[i] in b; note that because + // b2j has no junk keys, the loop is skipped if a[i] is junk + newj2len := map[int]int{} + for _, j := range m.b2j[m.a[i]] { + // a[i] matches b[j] + if j < blo { + continue + } + if j >= bhi { + break + } + k := j2len[j-1] + 1 + newj2len[j] = k + if k > bestsize { + besti, bestj, bestsize = i-k+1, j-k+1, k + } + } + j2len = newj2len + } + + // Extend the best by non-junk elements on each end. In particular, + // "popular" non-junk elements aren't in b2j, which greatly speeds + // the inner loop above, but also means "the best" match so far + // doesn't contain any junk *or* popular non-junk elements. + for besti > alo && bestj > blo && !m.isBJunk(m.b[bestj-1]) && + m.a[besti-1] == m.b[bestj-1] { + besti, bestj, bestsize = besti-1, bestj-1, bestsize+1 + } + for besti+bestsize < ahi && bestj+bestsize < bhi && + !m.isBJunk(m.b[bestj+bestsize]) && + m.a[besti+bestsize] == m.b[bestj+bestsize] { + bestsize += 1 + } + + // Now that we have a wholly interesting match (albeit possibly + // empty!), we may as well suck up the matching junk on each + // side of it too. Can't think of a good reason not to, and it + // saves post-processing the (possibly considerable) expense of + // figuring out what to do with it. In the case of an empty + // interesting match, this is clearly the right thing to do, + // because no other kind of match is possible in the regions. + for besti > alo && bestj > blo && m.isBJunk(m.b[bestj-1]) && + m.a[besti-1] == m.b[bestj-1] { + besti, bestj, bestsize = besti-1, bestj-1, bestsize+1 + } + for besti+bestsize < ahi && bestj+bestsize < bhi && + m.isBJunk(m.b[bestj+bestsize]) && + m.a[besti+bestsize] == m.b[bestj+bestsize] { + bestsize += 1 + } + + return Match{A: besti, B: bestj, Size: bestsize} +} + +// Return list of triples describing matching subsequences. +// +// Each triple is of the form (i, j, n), and means that +// a[i:i+n] == b[j:j+n]. The triples are monotonically increasing in +// i and in j. It's also guaranteed that if (i, j, n) and (i', j', n') are +// adjacent triples in the list, and the second is not the last triple in the +// list, then i+n != i' or j+n != j'. IOW, adjacent triples never describe +// adjacent equal blocks. +// +// The last triple is a dummy, (len(a), len(b), 0), and is the only +// triple with n==0. +func (m *SequenceMatcher) GetMatchingBlocks() []Match { + if m.matchingBlocks != nil { + return m.matchingBlocks + } + + var matchBlocks func(alo, ahi, blo, bhi int, matched []Match) []Match + matchBlocks = func(alo, ahi, blo, bhi int, matched []Match) []Match { + match := m.findLongestMatch(alo, ahi, blo, bhi) + i, j, k := match.A, match.B, match.Size + if match.Size > 0 { + if alo < i && blo < j { + matched = matchBlocks(alo, i, blo, j, matched) + } + matched = append(matched, match) + if i+k < ahi && j+k < bhi { + matched = matchBlocks(i+k, ahi, j+k, bhi, matched) + } + } + return matched + } + matched := matchBlocks(0, len(m.a), 0, len(m.b), nil) + + // It's possible that we have adjacent equal blocks in the + // matching_blocks list now. + nonAdjacent := []Match{} + i1, j1, k1 := 0, 0, 0 + for _, b := range matched { + // Is this block adjacent to i1, j1, k1? + i2, j2, k2 := b.A, b.B, b.Size + if i1+k1 == i2 && j1+k1 == j2 { + // Yes, so collapse them -- this just increases the length of + // the first block by the length of the second, and the first + // block so lengthened remains the block to compare against. + k1 += k2 + } else { + // Not adjacent. Remember the first block (k1==0 means it's + // the dummy we started with), and make the second block the + // new block to compare against. + if k1 > 0 { + nonAdjacent = append(nonAdjacent, Match{i1, j1, k1}) + } + i1, j1, k1 = i2, j2, k2 + } + } + if k1 > 0 { + nonAdjacent = append(nonAdjacent, Match{i1, j1, k1}) + } + + nonAdjacent = append(nonAdjacent, Match{len(m.a), len(m.b), 0}) + m.matchingBlocks = nonAdjacent + return m.matchingBlocks +} + +// Return list of 5-tuples describing how to turn a into b. +// +// Each tuple is of the form (tag, i1, i2, j1, j2). The first tuple +// has i1 == j1 == 0, and remaining tuples have i1 == the i2 from the +// tuple preceding it, and likewise for j1 == the previous j2. +// +// The tags are characters, with these meanings: +// +// 'r' (replace): a[i1:i2] should be replaced by b[j1:j2] +// +// 'd' (delete): a[i1:i2] should be deleted, j1==j2 in this case. +// +// 'i' (insert): b[j1:j2] should be inserted at a[i1:i1], i1==i2 in this case. +// +// 'e' (equal): a[i1:i2] == b[j1:j2] +func (m *SequenceMatcher) GetOpCodes() []OpCode { + if m.opCodes != nil { + return m.opCodes + } + i, j := 0, 0 + matching := m.GetMatchingBlocks() + opCodes := make([]OpCode, 0, len(matching)) + for _, m := range matching { + // invariant: we've pumped out correct diffs to change + // a[:i] into b[:j], and the next matching block is + // a[ai:ai+size] == b[bj:bj+size]. So we need to pump + // out a diff to change a[i:ai] into b[j:bj], pump out + // the matching block, and move (i,j) beyond the match + ai, bj, size := m.A, m.B, m.Size + tag := byte(0) + if i < ai && j < bj { + tag = 'r' + } else if i < ai { + tag = 'd' + } else if j < bj { + tag = 'i' + } + if tag > 0 { + opCodes = append(opCodes, OpCode{tag, i, ai, j, bj}) + } + i, j = ai+size, bj+size + // the list of matching blocks is terminated by a + // sentinel with size 0 + if size > 0 { + opCodes = append(opCodes, OpCode{'e', ai, i, bj, j}) + } + } + m.opCodes = opCodes + return m.opCodes +} + +// Isolate change clusters by eliminating ranges with no changes. +// +// Return a generator of groups with up to n lines of context. +// Each group is in the same format as returned by GetOpCodes(). +func (m *SequenceMatcher) GetGroupedOpCodes(n int) [][]OpCode { + if n < 0 { + n = 3 + } + codes := m.GetOpCodes() + if len(codes) == 0 { + codes = []OpCode{OpCode{'e', 0, 1, 0, 1}} + } + // Fixup leading and trailing groups if they show no changes. + if codes[0].Tag == 'e' { + c := codes[0] + i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2 + codes[0] = OpCode{c.Tag, max(i1, i2-n), i2, max(j1, j2-n), j2} + } + if codes[len(codes)-1].Tag == 'e' { + c := codes[len(codes)-1] + i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2 + codes[len(codes)-1] = OpCode{c.Tag, i1, min(i2, i1+n), j1, min(j2, j1+n)} + } + nn := n + n + groups := [][]OpCode{} + group := []OpCode{} + for _, c := range codes { + i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2 + // End the current group and start a new one whenever + // there is a large range with no changes. + if c.Tag == 'e' && i2-i1 > nn { + group = append(group, OpCode{c.Tag, i1, min(i2, i1+n), + j1, min(j2, j1+n)}) + groups = append(groups, group) + group = []OpCode{} + i1, j1 = max(i1, i2-n), max(j1, j2-n) + } + group = append(group, OpCode{c.Tag, i1, i2, j1, j2}) + } + if len(group) > 0 && !(len(group) == 1 && group[0].Tag == 'e') { + groups = append(groups, group) + } + return groups +} + +// Convert range to the "ed" format +func formatRangeUnified(start, stop int) string { + // Per the diff spec at http://www.unix.org/single_unix_specification/ + beginning := start + 1 // lines start numbering with one + length := stop - start + if length == 1 { + return fmt.Sprintf("%d", beginning) + } + if length == 0 { + beginning -= 1 // empty ranges begin at line just before the range + } + return fmt.Sprintf("%d,%d", beginning, length) +} + +// Unified diff parameters +type UnifiedDiff struct { + A []string // First sequence lines + FromFile string // First file name + FromDate string // First file time + B []string // Second sequence lines + ToFile string // Second file name + ToDate string // Second file time + Eol string // Headers end of line, defaults to LF + Context int // Number of context lines +} + +// Compare two sequences of lines; generate the delta as a unified diff. +// +// Unified diffs are a compact way of showing line changes and a few +// lines of context. The number of context lines is set by 'n' which +// defaults to three. +// +// By default, the diff control lines (those with ---, +++, or @@) are +// created with a trailing newline. This is helpful so that inputs +// created from file.readlines() result in diffs that are suitable for +// file.writelines() since both the inputs and outputs have trailing +// newlines. +// +// For inputs that do not have trailing newlines, set the lineterm +// argument to "" so that the output will be uniformly newline free. +// +// The unidiff format normally has a header for filenames and modification +// times. Any or all of these may be specified using strings for +// 'fromfile', 'tofile', 'fromfiledate', and 'tofiledate'. +// The modification times are normally expressed in the ISO 8601 format. +func WriteUnifiedDiff(writer io.Writer, diff UnifiedDiff) error { + buf := bufio.NewWriter(writer) + defer buf.Flush() + wf := func(format string, args ...interface{}) error { + _, err := buf.WriteString(fmt.Sprintf(format, args...)) + return err + } + ws := func(s string) error { + _, err := buf.WriteString(s) + return err + } + + if len(diff.Eol) == 0 { + diff.Eol = "\n" + } + + started := false + m := NewMatcher(diff.A, diff.B) + for _, g := range m.GetGroupedOpCodes(diff.Context) { + if !started { + started = true + fromDate := "" + if len(diff.FromDate) > 0 { + fromDate = "\t" + diff.FromDate + } + toDate := "" + if len(diff.ToDate) > 0 { + toDate = "\t" + diff.ToDate + } + if diff.FromFile != "" || diff.ToFile != "" { + err := wf("--- %s%s%s", diff.FromFile, fromDate, diff.Eol) + if err != nil { + return err + } + err = wf("+++ %s%s%s", diff.ToFile, toDate, diff.Eol) + if err != nil { + return err + } + } + } + first, last := g[0], g[len(g)-1] + range1 := formatRangeUnified(first.I1, last.I2) + range2 := formatRangeUnified(first.J1, last.J2) + if err := wf("@@ -%s +%s @@%s", range1, range2, diff.Eol); err != nil { + return err + } + for _, c := range g { + i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2 + if c.Tag == 'e' { + for _, line := range diff.A[i1:i2] { + if err := ws(" " + line); err != nil { + return err + } + } + continue + } + if c.Tag == 'r' || c.Tag == 'd' { + for _, line := range diff.A[i1:i2] { + if err := ws("-" + line); err != nil { + return err + } + } + } + if c.Tag == 'r' || c.Tag == 'i' { + for _, line := range diff.B[j1:j2] { + if err := ws("+" + line); err != nil { + return err + } + } + } + } + } + return nil +} + +// Like WriteUnifiedDiff but returns the diff a string. +func GetUnifiedDiffString(diff UnifiedDiff) (string, error) { + w := &bytes.Buffer{} + err := WriteUnifiedDiff(w, diff) + return string(w.Bytes()), err +} + +// Convert range to the "ed" format. +func formatRangeContext(start, stop int) string { + // Per the diff spec at http://www.unix.org/single_unix_specification/ + beginning := start + 1 // lines start numbering with one + length := stop - start + if length == 0 { + beginning -= 1 // empty ranges begin at line just before the range + } + if length <= 1 { + return fmt.Sprintf("%d", beginning) + } + return fmt.Sprintf("%d,%d", beginning, beginning+length-1) +} + +// Split a string on "\n" while preserving them. The output can be used +// as input for UnifiedDiff and ContextDiff structures. +func SplitLines(s string) []string { + lines := strings.SplitAfter(s, "\n") + lines[len(lines)-1] += "\n" + return lines +} diff --git a/vendor/github.com/stretchr/testify/internal/spew/LICENSE b/vendor/github.com/stretchr/testify/internal/spew/LICENSE new file mode 100644 index 0000000000..bc52e96f2b --- /dev/null +++ b/vendor/github.com/stretchr/testify/internal/spew/LICENSE @@ -0,0 +1,15 @@ +ISC License + +Copyright (c) 2012-2016 Dave Collins + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/vendor/github.com/stretchr/testify/internal/spew/README.md b/vendor/github.com/stretchr/testify/internal/spew/README.md new file mode 100644 index 0000000000..51a909e2ef --- /dev/null +++ b/vendor/github.com/stretchr/testify/internal/spew/README.md @@ -0,0 +1,12 @@ +go-spew +======= + +[![ISC License](http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org) + +Go-spew implements a deep pretty printer for Go data structures to aid in +debugging. A comprehensive suite of tests with 100% test coverage is provided +to ensure proper functionality. + +## License + +Go-spew is licensed under the [copyfree](http://copyfree.org) ISC License. diff --git a/vendor/github.com/stretchr/testify/internal/spew/bypass.go b/vendor/github.com/stretchr/testify/internal/spew/bypass.go new file mode 100644 index 0000000000..70ddeaad3e --- /dev/null +++ b/vendor/github.com/stretchr/testify/internal/spew/bypass.go @@ -0,0 +1,146 @@ +// Copyright (c) 2015-2016 Dave Collins +// +// Permission to use, copy, modify, and distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +// NOTE: Due to the following build constraints, this file will only be compiled +// when the code is not running on Google App Engine, compiled by GopherJS, and +// "-tags safe" is not added to the go build command line. The "disableunsafe" +// tag is deprecated and thus should not be used. +// Go versions prior to 1.4 are disabled because they use a different layout +// for interfaces which make the implementation of unsafeReflectValue more complex. +//go:build !js && !appengine && !safe && !disableunsafe && go1.4 +// +build !js,!appengine,!safe,!disableunsafe,go1.4 + +package spew + +import ( + "reflect" + "unsafe" +) + +const ( + // UnsafeDisabled is a build-time constant which specifies whether or + // not access to the unsafe package is available. + UnsafeDisabled = false + + // ptrSize is the size of a pointer on the current arch. + ptrSize = unsafe.Sizeof((*byte)(nil)) +) + +type flag uintptr + +var ( + // flagRO indicates whether the value field of a reflect.Value + // is read-only. + flagRO flag + + // flagAddr indicates whether the address of the reflect.Value's + // value may be taken. + flagAddr flag +) + +// flagKindMask holds the bits that make up the kind +// part of the flags field. In all the supported versions, +// it is in the lower 5 bits. +const flagKindMask = flag(0x1f) + +// Different versions of Go have used different +// bit layouts for the flags type. This table +// records the known combinations. +var okFlags = []struct { + ro, addr flag +}{{ + // From Go 1.4 to 1.5 + ro: 1 << 5, + addr: 1 << 7, +}, { + // Up to Go tip. + ro: 1<<5 | 1<<6, + addr: 1 << 8, +}} + +var flagValOffset = func() uintptr { + field, ok := reflect.TypeOf(reflect.Value{}).FieldByName("flag") + if !ok { + panic("reflect.Value has no flag field") + } + return field.Offset +}() + +// flagField returns a pointer to the flag field of a reflect.Value. +func flagField(v *reflect.Value) *flag { + return (*flag)(unsafe.Pointer(uintptr(unsafe.Pointer(v)) + flagValOffset)) +} + +// unsafeReflectValue converts the passed reflect.Value into a one that bypasses +// the typical safety restrictions preventing access to unaddressable and +// unexported data. It works by digging the raw pointer to the underlying +// value out of the protected value and generating a new unprotected (unsafe) +// reflect.Value to it. +// +// This allows us to check for implementations of the Stringer and error +// interfaces to be used for pretty printing ordinarily unaddressable and +// inaccessible values such as unexported struct fields. +func unsafeReflectValue(v reflect.Value) reflect.Value { + if !v.IsValid() || (v.CanInterface() && v.CanAddr()) { + return v + } + flagFieldPtr := flagField(&v) + *flagFieldPtr &^= flagRO + *flagFieldPtr |= flagAddr + return v +} + +// Sanity checks against future reflect package changes +// to the type or semantics of the Value.flag field. +func init() { + field, ok := reflect.TypeOf(reflect.Value{}).FieldByName("flag") + if !ok { + panic("reflect.Value has no flag field") + } + if field.Type.Kind() != reflect.TypeOf(flag(0)).Kind() { + panic("reflect.Value flag field has changed kind") + } + type t0 int + var t struct { + A t0 + // t0 will have flagEmbedRO set. + t0 + // a will have flagStickyRO set + a t0 + } + vA := reflect.ValueOf(t).FieldByName("A") + va := reflect.ValueOf(t).FieldByName("a") + vt0 := reflect.ValueOf(t).FieldByName("t0") + + // Infer flagRO from the difference between the flags + // for the (otherwise identical) fields in t. + flagPublic := *flagField(&vA) + flagWithRO := *flagField(&va) | *flagField(&vt0) + flagRO = flagPublic ^ flagWithRO + + // Infer flagAddr from the difference between a value + // taken from a pointer and not. + vPtrA := reflect.ValueOf(&t).Elem().FieldByName("A") + flagNoPtr := *flagField(&vA) + flagPtr := *flagField(&vPtrA) + flagAddr = flagNoPtr ^ flagPtr + + // Check that the inferred flags tally with one of the known versions. + for _, f := range okFlags { + if flagRO == f.ro && flagAddr == f.addr { + return + } + } + panic("reflect.Value read-only flag has changed semantics") +} diff --git a/vendor/github.com/stretchr/testify/internal/spew/bypasssafe.go b/vendor/github.com/stretchr/testify/internal/spew/bypasssafe.go new file mode 100644 index 0000000000..5e2d890d6a --- /dev/null +++ b/vendor/github.com/stretchr/testify/internal/spew/bypasssafe.go @@ -0,0 +1,39 @@ +// Copyright (c) 2015-2016 Dave Collins +// +// Permission to use, copy, modify, and distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +// NOTE: Due to the following build constraints, this file will only be compiled +// when the code is running on Google App Engine, compiled by GopherJS, or +// "-tags safe" is added to the go build command line. The "disableunsafe" +// tag is deprecated and thus should not be used. +//go:build js || appengine || safe || disableunsafe || !go1.4 +// +build js appengine safe disableunsafe !go1.4 + +package spew + +import "reflect" + +const ( + // UnsafeDisabled is a build-time constant which specifies whether or + // not access to the unsafe package is available. + UnsafeDisabled = true +) + +// unsafeReflectValue typically converts the passed reflect.Value into a one +// that bypasses the typical safety restrictions preventing access to +// unaddressable and unexported data. However, doing this relies on access to +// the unsafe package. This is a stub version which simply returns the passed +// reflect.Value when the unsafe package is not available. +func unsafeReflectValue(v reflect.Value) reflect.Value { + return v +} diff --git a/vendor/github.com/stretchr/testify/internal/spew/common.go b/vendor/github.com/stretchr/testify/internal/spew/common.go new file mode 100644 index 0000000000..1be8ce9457 --- /dev/null +++ b/vendor/github.com/stretchr/testify/internal/spew/common.go @@ -0,0 +1,341 @@ +/* + * Copyright (c) 2013-2016 Dave Collins + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package spew + +import ( + "bytes" + "fmt" + "io" + "reflect" + "sort" + "strconv" +) + +// Some constants in the form of bytes to avoid string overhead. This mirrors +// the technique used in the fmt package. +var ( + panicBytes = []byte("(PANIC=") + plusBytes = []byte("+") + iBytes = []byte("i") + trueBytes = []byte("true") + falseBytes = []byte("false") + interfaceBytes = []byte("(interface {})") + commaNewlineBytes = []byte(",\n") + newlineBytes = []byte("\n") + openBraceBytes = []byte("{") + openBraceNewlineBytes = []byte("{\n") + closeBraceBytes = []byte("}") + asteriskBytes = []byte("*") + colonBytes = []byte(":") + colonSpaceBytes = []byte(": ") + openParenBytes = []byte("(") + closeParenBytes = []byte(")") + spaceBytes = []byte(" ") + pointerChainBytes = []byte("->") + nilAngleBytes = []byte("") + maxNewlineBytes = []byte("\n") + maxShortBytes = []byte("") + circularBytes = []byte("") + circularShortBytes = []byte("") + invalidAngleBytes = []byte("") + openBracketBytes = []byte("[") + closeBracketBytes = []byte("]") + percentBytes = []byte("%") + precisionBytes = []byte(".") + openAngleBytes = []byte("<") + closeAngleBytes = []byte(">") + openMapBytes = []byte("map[") + closeMapBytes = []byte("]") + lenEqualsBytes = []byte("len=") + capEqualsBytes = []byte("cap=") +) + +// hexDigits is used to map a decimal value to a hex digit. +var hexDigits = "0123456789abcdef" + +// catchPanic handles any panics that might occur during the handleMethods +// calls. +func catchPanic(w io.Writer, v reflect.Value) { + if err := recover(); err != nil { + w.Write(panicBytes) + fmt.Fprintf(w, "%v", err) + w.Write(closeParenBytes) + } +} + +// handleMethods attempts to call the Error and String methods on the underlying +// type the passed reflect.Value represents and outputes the result to Writer w. +// +// It handles panics in any called methods by catching and displaying the error +// as the formatted value. +func handleMethods(cs *ConfigState, w io.Writer, v reflect.Value) (handled bool) { + // We need an interface to check if the type implements the error or + // Stringer interface. However, the reflect package won't give us an + // interface on certain things like unexported struct fields in order + // to enforce visibility rules. We use unsafe, when it's available, + // to bypass these restrictions since this package does not mutate the + // values. + if !v.CanInterface() { + if UnsafeDisabled { + return false + } + + v = unsafeReflectValue(v) + } + + // Choose whether or not to do error and Stringer interface lookups against + // the base type or a pointer to the base type depending on settings. + // Technically calling one of these methods with a pointer receiver can + // mutate the value, however, types which choose to satisify an error or + // Stringer interface with a pointer receiver should not be mutating their + // state inside these interface methods. + if !cs.DisablePointerMethods && !UnsafeDisabled && !v.CanAddr() { + v = unsafeReflectValue(v) + } + if v.CanAddr() { + v = v.Addr() + } + + // Is it an error or Stringer? + switch iface := v.Interface().(type) { + case error: + defer catchPanic(w, v) + if cs.ContinueOnMethod { + w.Write(openParenBytes) + w.Write([]byte(iface.Error())) + w.Write(closeParenBytes) + w.Write(spaceBytes) + return false + } + + w.Write([]byte(iface.Error())) + return true + + case fmt.Stringer: + defer catchPanic(w, v) + if cs.ContinueOnMethod { + w.Write(openParenBytes) + w.Write([]byte(iface.String())) + w.Write(closeParenBytes) + w.Write(spaceBytes) + return false + } + w.Write([]byte(iface.String())) + return true + } + return false +} + +// printBool outputs a boolean value as true or false to Writer w. +func printBool(w io.Writer, val bool) { + if val { + w.Write(trueBytes) + } else { + w.Write(falseBytes) + } +} + +// printInt outputs a signed integer value to Writer w. +func printInt(w io.Writer, val int64, base int) { + w.Write([]byte(strconv.FormatInt(val, base))) +} + +// printUint outputs an unsigned integer value to Writer w. +func printUint(w io.Writer, val uint64, base int) { + w.Write([]byte(strconv.FormatUint(val, base))) +} + +// printFloat outputs a floating point value using the specified precision, +// which is expected to be 32 or 64bit, to Writer w. +func printFloat(w io.Writer, val float64, precision int) { + w.Write([]byte(strconv.FormatFloat(val, 'g', -1, precision))) +} + +// printComplex outputs a complex value using the specified float precision +// for the real and imaginary parts to Writer w. +func printComplex(w io.Writer, c complex128, floatPrecision int) { + r := real(c) + w.Write(openParenBytes) + w.Write([]byte(strconv.FormatFloat(r, 'g', -1, floatPrecision))) + i := imag(c) + if i >= 0 { + w.Write(plusBytes) + } + w.Write([]byte(strconv.FormatFloat(i, 'g', -1, floatPrecision))) + w.Write(iBytes) + w.Write(closeParenBytes) +} + +// printHexPtr outputs a uintptr formatted as hexadecimal with a leading '0x' +// prefix to Writer w. +func printHexPtr(w io.Writer, p uintptr) { + // Null pointer. + num := uint64(p) + if num == 0 { + w.Write(nilAngleBytes) + return + } + + // Max uint64 is 16 bytes in hex + 2 bytes for '0x' prefix + buf := make([]byte, 18) + + // It's simpler to construct the hex string right to left. + base := uint64(16) + i := len(buf) - 1 + for num >= base { + buf[i] = hexDigits[num%base] + num /= base + i-- + } + buf[i] = hexDigits[num] + + // Add '0x' prefix. + i-- + buf[i] = 'x' + i-- + buf[i] = '0' + + // Strip unused leading bytes. + buf = buf[i:] + w.Write(buf) +} + +// valuesSorter implements sort.Interface to allow a slice of reflect.Value +// elements to be sorted. +type valuesSorter struct { + values []reflect.Value + strings []string // either nil or same len and values + cs *ConfigState +} + +// newValuesSorter initializes a valuesSorter instance, which holds a set of +// surrogate keys on which the data should be sorted. It uses flags in +// ConfigState to decide if and how to populate those surrogate keys. +func newValuesSorter(values []reflect.Value, cs *ConfigState) sort.Interface { + vs := &valuesSorter{values: values, cs: cs} + if canSortSimply(vs.values[0].Kind()) { + return vs + } + if !cs.DisableMethods { + vs.strings = make([]string, len(values)) + for i := range vs.values { + b := bytes.Buffer{} + if !handleMethods(cs, &b, vs.values[i]) { + vs.strings = nil + break + } + vs.strings[i] = b.String() + } + } + if vs.strings == nil && cs.SpewKeys { + vs.strings = make([]string, len(values)) + for i := range vs.values { + vs.strings[i] = Sprintf("%#v", vs.values[i].Interface()) + } + } + return vs +} + +// canSortSimply tests whether a reflect.Kind is a primitive that can be sorted +// directly, or whether it should be considered for sorting by surrogate keys +// (if the ConfigState allows it). +func canSortSimply(kind reflect.Kind) bool { + // This switch parallels valueSortLess, except for the default case. + switch kind { + case reflect.Bool: + return true + case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: + return true + case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: + return true + case reflect.Float32, reflect.Float64: + return true + case reflect.String: + return true + case reflect.Uintptr: + return true + case reflect.Array: + return true + } + return false +} + +// Len returns the number of values in the slice. It is part of the +// sort.Interface implementation. +func (s *valuesSorter) Len() int { + return len(s.values) +} + +// Swap swaps the values at the passed indices. It is part of the +// sort.Interface implementation. +func (s *valuesSorter) Swap(i, j int) { + s.values[i], s.values[j] = s.values[j], s.values[i] + if s.strings != nil { + s.strings[i], s.strings[j] = s.strings[j], s.strings[i] + } +} + +// valueSortLess returns whether the first value should sort before the second +// value. It is used by valueSorter.Less as part of the sort.Interface +// implementation. +func valueSortLess(a, b reflect.Value) bool { + switch a.Kind() { + case reflect.Bool: + return !a.Bool() && b.Bool() + case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: + return a.Int() < b.Int() + case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: + return a.Uint() < b.Uint() + case reflect.Float32, reflect.Float64: + return a.Float() < b.Float() + case reflect.String: + return a.String() < b.String() + case reflect.Uintptr: + return a.Uint() < b.Uint() + case reflect.Array: + // Compare the contents of both arrays. + l := a.Len() + for i := 0; i < l; i++ { + av := a.Index(i) + bv := b.Index(i) + if av.Interface() == bv.Interface() { + continue + } + return valueSortLess(av, bv) + } + } + return a.String() < b.String() +} + +// Less returns whether the value at index i should sort before the +// value at index j. It is part of the sort.Interface implementation. +func (s *valuesSorter) Less(i, j int) bool { + if s.strings == nil { + return valueSortLess(s.values[i], s.values[j]) + } + return s.strings[i] < s.strings[j] +} + +// sortValues is a sort function that handles both native types and any type that +// can be converted to error or Stringer. Other inputs are sorted according to +// their Value.String() value to ensure display stability. +func sortValues(values []reflect.Value, cs *ConfigState) { + if len(values) == 0 { + return + } + sort.Sort(newValuesSorter(values, cs)) +} diff --git a/vendor/github.com/stretchr/testify/internal/spew/config.go b/vendor/github.com/stretchr/testify/internal/spew/config.go new file mode 100644 index 0000000000..161895fc6d --- /dev/null +++ b/vendor/github.com/stretchr/testify/internal/spew/config.go @@ -0,0 +1,306 @@ +/* + * Copyright (c) 2013-2016 Dave Collins + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package spew + +import ( + "bytes" + "fmt" + "io" + "os" +) + +// ConfigState houses the configuration options used by spew to format and +// display values. There is a global instance, Config, that is used to control +// all top-level Formatter and Dump functionality. Each ConfigState instance +// provides methods equivalent to the top-level functions. +// +// The zero value for ConfigState provides no indentation. You would typically +// want to set it to a space or a tab. +// +// Alternatively, you can use NewDefaultConfig to get a ConfigState instance +// with default settings. See the documentation of NewDefaultConfig for default +// values. +type ConfigState struct { + // Indent specifies the string to use for each indentation level. The + // global config instance that all top-level functions use set this to a + // single space by default. If you would like more indentation, you might + // set this to a tab with "\t" or perhaps two spaces with " ". + Indent string + + // MaxDepth controls the maximum number of levels to descend into nested + // data structures. The default, 0, means there is no limit. + // + // NOTE: Circular data structures are properly detected, so it is not + // necessary to set this value unless you specifically want to limit deeply + // nested data structures. + MaxDepth int + + // DisableMethods specifies whether or not error and Stringer interfaces are + // invoked for types that implement them. + DisableMethods bool + + // DisablePointerMethods specifies whether or not to check for and invoke + // error and Stringer interfaces on types which only accept a pointer + // receiver when the current type is not a pointer. + // + // NOTE: This might be an unsafe action since calling one of these methods + // with a pointer receiver could technically mutate the value, however, + // in practice, types which choose to satisify an error or Stringer + // interface with a pointer receiver should not be mutating their state + // inside these interface methods. As a result, this option relies on + // access to the unsafe package, so it will not have any effect when + // running in environments without access to the unsafe package such as + // Google App Engine or with the "safe" build tag specified. + DisablePointerMethods bool + + // DisablePointerAddresses specifies whether to disable the printing of + // pointer addresses. This is useful when diffing data structures in tests. + DisablePointerAddresses bool + + // DisableCapacities specifies whether to disable the printing of capacities + // for arrays, slices, maps and channels. This is useful when diffing + // data structures in tests. + DisableCapacities bool + + // ContinueOnMethod specifies whether or not recursion should continue once + // a custom error or Stringer interface is invoked. The default, false, + // means it will print the results of invoking the custom error or Stringer + // interface and return immediately instead of continuing to recurse into + // the internals of the data type. + // + // NOTE: This flag does not have any effect if method invocation is disabled + // via the DisableMethods or DisablePointerMethods options. + ContinueOnMethod bool + + // SortKeys specifies map keys should be sorted before being printed. Use + // this to have a more deterministic, diffable output. Note that only + // native types (bool, int, uint, floats, uintptr and string) and types + // that support the error or Stringer interfaces (if methods are + // enabled) are supported, with other types sorted according to the + // reflect.Value.String() output which guarantees display stability. + SortKeys bool + + // SpewKeys specifies that, as a last resort attempt, map keys should + // be spewed to strings and sorted by those strings. This is only + // considered if SortKeys is true. + SpewKeys bool +} + +// Config is the active configuration of the top-level functions. +// The configuration can be changed by modifying the contents of spew.Config. +var Config = ConfigState{Indent: " "} + +// Errorf is a wrapper for fmt.Errorf that treats each argument as if it were +// passed with a Formatter interface returned by c.NewFormatter. It returns +// the formatted string as a value that satisfies error. See NewFormatter +// for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Errorf(format, c.NewFormatter(a), c.NewFormatter(b)) +func (c *ConfigState) Errorf(format string, a ...interface{}) (err error) { + return fmt.Errorf(format, c.convertArgs(a)...) +} + +// Fprint is a wrapper for fmt.Fprint that treats each argument as if it were +// passed with a Formatter interface returned by c.NewFormatter. It returns +// the number of bytes written and any write error encountered. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Fprint(w, c.NewFormatter(a), c.NewFormatter(b)) +func (c *ConfigState) Fprint(w io.Writer, a ...interface{}) (n int, err error) { + return fmt.Fprint(w, c.convertArgs(a)...) +} + +// Fprintf is a wrapper for fmt.Fprintf that treats each argument as if it were +// passed with a Formatter interface returned by c.NewFormatter. It returns +// the number of bytes written and any write error encountered. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Fprintf(w, format, c.NewFormatter(a), c.NewFormatter(b)) +func (c *ConfigState) Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) { + return fmt.Fprintf(w, format, c.convertArgs(a)...) +} + +// Fprintln is a wrapper for fmt.Fprintln that treats each argument as if it +// passed with a Formatter interface returned by c.NewFormatter. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Fprintln(w, c.NewFormatter(a), c.NewFormatter(b)) +func (c *ConfigState) Fprintln(w io.Writer, a ...interface{}) (n int, err error) { + return fmt.Fprintln(w, c.convertArgs(a)...) +} + +// Print is a wrapper for fmt.Print that treats each argument as if it were +// passed with a Formatter interface returned by c.NewFormatter. It returns +// the number of bytes written and any write error encountered. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Print(c.NewFormatter(a), c.NewFormatter(b)) +func (c *ConfigState) Print(a ...interface{}) (n int, err error) { + return fmt.Print(c.convertArgs(a)...) +} + +// Printf is a wrapper for fmt.Printf that treats each argument as if it were +// passed with a Formatter interface returned by c.NewFormatter. It returns +// the number of bytes written and any write error encountered. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Printf(format, c.NewFormatter(a), c.NewFormatter(b)) +func (c *ConfigState) Printf(format string, a ...interface{}) (n int, err error) { + return fmt.Printf(format, c.convertArgs(a)...) +} + +// Println is a wrapper for fmt.Println that treats each argument as if it were +// passed with a Formatter interface returned by c.NewFormatter. It returns +// the number of bytes written and any write error encountered. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Println(c.NewFormatter(a), c.NewFormatter(b)) +func (c *ConfigState) Println(a ...interface{}) (n int, err error) { + return fmt.Println(c.convertArgs(a)...) +} + +// Sprint is a wrapper for fmt.Sprint that treats each argument as if it were +// passed with a Formatter interface returned by c.NewFormatter. It returns +// the resulting string. See NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Sprint(c.NewFormatter(a), c.NewFormatter(b)) +func (c *ConfigState) Sprint(a ...interface{}) string { + return fmt.Sprint(c.convertArgs(a)...) +} + +// Sprintf is a wrapper for fmt.Sprintf that treats each argument as if it were +// passed with a Formatter interface returned by c.NewFormatter. It returns +// the resulting string. See NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Sprintf(format, c.NewFormatter(a), c.NewFormatter(b)) +func (c *ConfigState) Sprintf(format string, a ...interface{}) string { + return fmt.Sprintf(format, c.convertArgs(a)...) +} + +// Sprintln is a wrapper for fmt.Sprintln that treats each argument as if it +// were passed with a Formatter interface returned by c.NewFormatter. It +// returns the resulting string. See NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Sprintln(c.NewFormatter(a), c.NewFormatter(b)) +func (c *ConfigState) Sprintln(a ...interface{}) string { + return fmt.Sprintln(c.convertArgs(a)...) +} + +/* +NewFormatter returns a custom formatter that satisfies the fmt.Formatter +interface. As a result, it integrates cleanly with standard fmt package +printing functions. The formatter is useful for inline printing of smaller data +types similar to the standard %v format specifier. + +The custom formatter only responds to the %v (most compact), %+v (adds pointer +addresses), %#v (adds types), and %#+v (adds types and pointer addresses) verb +combinations. Any other verbs such as %x and %q will be sent to the the +standard fmt package for formatting. In addition, the custom formatter ignores +the width and precision arguments (however they will still work on the format +specifiers not handled by the custom formatter). + +Typically this function shouldn't be called directly. It is much easier to make +use of the custom formatter by calling one of the convenience functions such as +c.Printf, c.Println, or c.Printf. +*/ +func (c *ConfigState) NewFormatter(v interface{}) fmt.Formatter { + return newFormatter(c, v) +} + +// Fdump formats and displays the passed arguments to io.Writer w. It formats +// exactly the same as Dump. +func (c *ConfigState) Fdump(w io.Writer, a ...interface{}) { + fdump(c, w, a...) +} + +/* +Dump displays the passed parameters to standard out with newlines, customizable +indentation, and additional debug information such as complete types and all +pointer addresses used to indirect to the final value. It provides the +following features over the built-in printing facilities provided by the fmt +package: + + - Pointers are dereferenced and followed + - Circular data structures are detected and handled properly + - Custom Stringer/error interfaces are optionally invoked, including + on unexported types + - Custom types which only implement the Stringer/error interfaces via + a pointer receiver are optionally invoked when passing non-pointer + variables + - Byte arrays and slices are dumped like the hexdump -C command which + includes offsets, byte values in hex, and ASCII output + +The configuration options are controlled by modifying the public members +of c. See ConfigState for options documentation. + +See Fdump if you would prefer dumping to an arbitrary io.Writer or Sdump to +get the formatted result as a string. +*/ +func (c *ConfigState) Dump(a ...interface{}) { + fdump(c, os.Stdout, a...) +} + +// Sdump returns a string with the passed arguments formatted exactly the same +// as Dump. +func (c *ConfigState) Sdump(a ...interface{}) string { + var buf bytes.Buffer + fdump(c, &buf, a...) + return buf.String() +} + +// convertArgs accepts a slice of arguments and returns a slice of the same +// length with each argument converted to a spew Formatter interface using +// the ConfigState associated with s. +func (c *ConfigState) convertArgs(args []interface{}) (formatters []interface{}) { + formatters = make([]interface{}, len(args)) + for index, arg := range args { + formatters[index] = newFormatter(c, arg) + } + return formatters +} + +// NewDefaultConfig returns a ConfigState with the following default settings. +// +// Indent: " " +// MaxDepth: 0 +// DisableMethods: false +// DisablePointerMethods: false +// ContinueOnMethod: false +// SortKeys: false +func NewDefaultConfig() *ConfigState { + return &ConfigState{Indent: " "} +} diff --git a/vendor/github.com/stretchr/testify/internal/spew/doc.go b/vendor/github.com/stretchr/testify/internal/spew/doc.go new file mode 100644 index 0000000000..722e9aa791 --- /dev/null +++ b/vendor/github.com/stretchr/testify/internal/spew/doc.go @@ -0,0 +1,217 @@ +/* + * Copyright (c) 2013-2016 Dave Collins + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* +Package spew implements a deep pretty printer for Go data structures to aid in +debugging. + +A quick overview of the additional features spew provides over the built-in +printing facilities for Go data types are as follows: + + - Pointers are dereferenced and followed + - Circular data structures are detected and handled properly + - Custom Stringer/error interfaces are optionally invoked, including + on unexported types + - Custom types which only implement the Stringer/error interfaces via + a pointer receiver are optionally invoked when passing non-pointer + variables + - Byte arrays and slices are dumped like the hexdump -C command which + includes offsets, byte values in hex, and ASCII output (only when using + Dump style) + +There are two different approaches spew allows for dumping Go data structures: + + - Dump style which prints with newlines, customizable indentation, + and additional debug information such as types and all pointer addresses + used to indirect to the final value + - A custom Formatter interface that integrates cleanly with the standard fmt + package and replaces %v, %+v, %#v, and %#+v to provide inline printing + similar to the default %v while providing the additional functionality + outlined above and passing unsupported format verbs such as %x and %q + along to fmt + +# Quick Start + +This section demonstrates how to quickly get started with spew. See the +sections below for further details on formatting and configuration options. + +To dump a variable with full newlines, indentation, type, and pointer +information use Dump, Fdump, or Sdump: + + spew.Dump(myVar1, myVar2, ...) + spew.Fdump(someWriter, myVar1, myVar2, ...) + str := spew.Sdump(myVar1, myVar2, ...) + +Alternatively, if you would prefer to use format strings with a compacted inline +printing style, use the convenience wrappers Printf, Fprintf, etc with +%v (most compact), %+v (adds pointer addresses), %#v (adds types), or +%#+v (adds types and pointer addresses): + + spew.Printf("myVar1: %v -- myVar2: %+v", myVar1, myVar2) + spew.Printf("myVar3: %#v -- myVar4: %#+v", myVar3, myVar4) + spew.Fprintf(someWriter, "myVar1: %v -- myVar2: %+v", myVar1, myVar2) + spew.Fprintf(someWriter, "myVar3: %#v -- myVar4: %#+v", myVar3, myVar4) + +# Configuration Options + +Configuration of spew is handled by fields in the ConfigState type. For +convenience, all of the top-level functions use a global state available +via the spew.Config global. + +It is also possible to create a ConfigState instance that provides methods +equivalent to the top-level functions. This allows concurrent configuration +options. See the ConfigState documentation for more details. + +The following configuration options are available: + + - Indent + String to use for each indentation level for Dump functions. + It is a single space by default. A popular alternative is "\t". + + - MaxDepth + Maximum number of levels to descend into nested data structures. + There is no limit by default. + + - DisableMethods + Disables invocation of error and Stringer interface methods. + Method invocation is enabled by default. + + - DisablePointerMethods + Disables invocation of error and Stringer interface methods on types + which only accept pointer receivers from non-pointer variables. + Pointer method invocation is enabled by default. + + - DisablePointerAddresses + DisablePointerAddresses specifies whether to disable the printing of + pointer addresses. This is useful when diffing data structures in tests. + + - DisableCapacities + DisableCapacities specifies whether to disable the printing of + capacities for arrays, slices, maps and channels. This is useful when + diffing data structures in tests. + + - ContinueOnMethod + Enables recursion into types after invoking error and Stringer interface + methods. Recursion after method invocation is disabled by default. + + - SortKeys + Specifies map keys should be sorted before being printed. Use + this to have a more deterministic, diffable output. Note that + only native types (bool, int, uint, floats, uintptr and string) + and types which implement error or Stringer interfaces are + supported with other types sorted according to the + reflect.Value.String() output which guarantees display + stability. Natural map order is used by default. + + - SpewKeys + Specifies that, as a last resort attempt, map keys should be + spewed to strings and sorted by those strings. This is only + considered if SortKeys is true. + +# Dump Usage + +Simply call spew.Dump with a list of variables you want to dump: + + spew.Dump(myVar1, myVar2, ...) + +You may also call spew.Fdump if you would prefer to output to an arbitrary +io.Writer. For example, to dump to standard error: + + spew.Fdump(os.Stderr, myVar1, myVar2, ...) + +A third option is to call spew.Sdump to get the formatted output as a string: + + str := spew.Sdump(myVar1, myVar2, ...) + +# Sample Dump Output + +See the Dump example for details on the setup of the types and variables being +shown here. + + (main.Foo) { + unexportedField: (*main.Bar)(0xf84002e210)({ + flag: (main.Flag) flagTwo, + data: (uintptr) + }), + ExportedField: (map[interface {}]interface {}) (len=1) { + (string) (len=3) "one": (bool) true + } + } + +Byte (and uint8) arrays and slices are displayed uniquely like the hexdump -C +command as shown. + + ([]uint8) (len=32 cap=32) { + 00000000 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 |............... | + 00000010 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 |!"#$%&'()*+,-./0| + 00000020 31 32 |12| + } + +# Custom Formatter + +Spew provides a custom formatter that implements the fmt.Formatter interface +so that it integrates cleanly with standard fmt package printing functions. The +formatter is useful for inline printing of smaller data types similar to the +standard %v format specifier. + +The custom formatter only responds to the %v (most compact), %+v (adds pointer +addresses), %#v (adds types), or %#+v (adds types and pointer addresses) verb +combinations. Any other verbs such as %x and %q will be sent to the the +standard fmt package for formatting. In addition, the custom formatter ignores +the width and precision arguments (however they will still work on the format +specifiers not handled by the custom formatter). + +# Custom Formatter Usage + +The simplest way to make use of the spew custom formatter is to call one of the +convenience functions such as spew.Printf, spew.Println, or spew.Printf. The +functions have syntax you are most likely already familiar with: + + spew.Printf("myVar1: %v -- myVar2: %+v", myVar1, myVar2) + spew.Printf("myVar3: %#v -- myVar4: %#+v", myVar3, myVar4) + spew.Println(myVar, myVar2) + spew.Fprintf(os.Stderr, "myVar1: %v -- myVar2: %+v", myVar1, myVar2) + spew.Fprintf(os.Stderr, "myVar3: %#v -- myVar4: %#+v", myVar3, myVar4) + +See the Index for the full list convenience functions. + +# Sample Formatter Output + +Double pointer to a uint8: + + %v: <**>5 + %+v: <**>(0xf8400420d0->0xf8400420c8)5 + %#v: (**uint8)5 + %#+v: (**uint8)(0xf8400420d0->0xf8400420c8)5 + +Pointer to circular struct with a uint8 field and a pointer to itself: + + %v: <*>{1 <*>} + %+v: <*>(0xf84003e260){ui8:1 c:<*>(0xf84003e260)} + %#v: (*main.circular){ui8:(uint8)1 c:(*main.circular)} + %#+v: (*main.circular)(0xf84003e260){ui8:(uint8)1 c:(*main.circular)(0xf84003e260)} + +See the Printf example for details on the setup of variables being shown +here. + +# Errors + +Since it is possible for custom Stringer/error interfaces to panic, spew +detects them and handles them internally by printing the panic information +inline with the output. Since spew is intended to provide deep pretty printing +capabilities on structures, it intentionally does not return any errors. +*/ +package spew diff --git a/vendor/github.com/stretchr/testify/internal/spew/dump.go b/vendor/github.com/stretchr/testify/internal/spew/dump.go new file mode 100644 index 0000000000..8323041a48 --- /dev/null +++ b/vendor/github.com/stretchr/testify/internal/spew/dump.go @@ -0,0 +1,509 @@ +/* + * Copyright (c) 2013-2016 Dave Collins + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package spew + +import ( + "bytes" + "encoding/hex" + "fmt" + "io" + "os" + "reflect" + "regexp" + "strconv" + "strings" +) + +var ( + // uint8Type is a reflect.Type representing a uint8. It is used to + // convert cgo types to uint8 slices for hexdumping. + uint8Type = reflect.TypeOf(uint8(0)) + + // cCharRE is a regular expression that matches a cgo char. + // It is used to detect character arrays to hexdump them. + cCharRE = regexp.MustCompile(`^.*\._Ctype_char$`) + + // cUnsignedCharRE is a regular expression that matches a cgo unsigned + // char. It is used to detect unsigned character arrays to hexdump + // them. + cUnsignedCharRE = regexp.MustCompile(`^.*\._Ctype_unsignedchar$`) + + // cUint8tCharRE is a regular expression that matches a cgo uint8_t. + // It is used to detect uint8_t arrays to hexdump them. + cUint8tCharRE = regexp.MustCompile(`^.*\._Ctype_uint8_t$`) +) + +// dumpState contains information about the state of a dump operation. +type dumpState struct { + w io.Writer + depth int + pointers map[uintptr]int + ignoreNextType bool + ignoreNextIndent bool + cs *ConfigState +} + +// indent performs indentation according to the depth level and cs.Indent +// option. +func (d *dumpState) indent() { + if d.ignoreNextIndent { + d.ignoreNextIndent = false + return + } + d.w.Write(bytes.Repeat([]byte(d.cs.Indent), d.depth)) +} + +// unpackValue returns values inside of non-nil interfaces when possible. +// This is useful for data types like structs, arrays, slices, and maps which +// can contain varying types packed inside an interface. +func (d *dumpState) unpackValue(v reflect.Value) reflect.Value { + if v.Kind() == reflect.Interface && !v.IsNil() { + v = v.Elem() + } + return v +} + +// dumpPtr handles formatting of pointers by indirecting them as necessary. +func (d *dumpState) dumpPtr(v reflect.Value) { + // Remove pointers at or below the current depth from map used to detect + // circular refs. + for k, depth := range d.pointers { + if depth >= d.depth { + delete(d.pointers, k) + } + } + + // Keep list of all dereferenced pointers to show later. + pointerChain := make([]uintptr, 0) + + // Figure out how many levels of indirection there are by dereferencing + // pointers and unpacking interfaces down the chain while detecting circular + // references. + nilFound := false + cycleFound := false + indirects := 0 + ve := v + for ve.Kind() == reflect.Ptr { + if ve.IsNil() { + nilFound = true + break + } + indirects++ + addr := ve.Pointer() + pointerChain = append(pointerChain, addr) + if pd, ok := d.pointers[addr]; ok && pd < d.depth { + cycleFound = true + indirects-- + break + } + d.pointers[addr] = d.depth + + ve = ve.Elem() + if ve.Kind() == reflect.Interface { + if ve.IsNil() { + nilFound = true + break + } + ve = ve.Elem() + } + } + + // Display type information. + d.w.Write(openParenBytes) + d.w.Write(bytes.Repeat(asteriskBytes, indirects)) + d.w.Write([]byte(ve.Type().String())) + d.w.Write(closeParenBytes) + + // Display pointer information. + if !d.cs.DisablePointerAddresses && len(pointerChain) > 0 { + d.w.Write(openParenBytes) + for i, addr := range pointerChain { + if i > 0 { + d.w.Write(pointerChainBytes) + } + printHexPtr(d.w, addr) + } + d.w.Write(closeParenBytes) + } + + // Display dereferenced value. + d.w.Write(openParenBytes) + switch { + case nilFound: + d.w.Write(nilAngleBytes) + + case cycleFound: + d.w.Write(circularBytes) + + default: + d.ignoreNextType = true + d.dump(ve) + } + d.w.Write(closeParenBytes) +} + +// dumpSlice handles formatting of arrays and slices. Byte (uint8 under +// reflection) arrays and slices are dumped in hexdump -C fashion. +func (d *dumpState) dumpSlice(v reflect.Value) { + // Determine whether this type should be hex dumped or not. Also, + // for types which should be hexdumped, try to use the underlying data + // first, then fall back to trying to convert them to a uint8 slice. + var buf []uint8 + doConvert := false + doHexDump := false + numEntries := v.Len() + if numEntries > 0 { + vt := v.Index(0).Type() + vts := vt.String() + switch { + // C types that need to be converted. + case cCharRE.MatchString(vts): + fallthrough + case cUnsignedCharRE.MatchString(vts): + fallthrough + case cUint8tCharRE.MatchString(vts): + doConvert = true + + // Try to use existing uint8 slices and fall back to converting + // and copying if that fails. + case vt.Kind() == reflect.Uint8: + // We need an addressable interface to convert the type + // to a byte slice. However, the reflect package won't + // give us an interface on certain things like + // unexported struct fields in order to enforce + // visibility rules. We use unsafe, when available, to + // bypass these restrictions since this package does not + // mutate the values. + vs := v + if !vs.CanInterface() || !vs.CanAddr() { + vs = unsafeReflectValue(vs) + } + if !UnsafeDisabled { + vs = vs.Slice(0, numEntries) + + // Use the existing uint8 slice if it can be + // type asserted. + iface := vs.Interface() + if slice, ok := iface.([]uint8); ok { + buf = slice + doHexDump = true + break + } + } + + // The underlying data needs to be converted if it can't + // be type asserted to a uint8 slice. + doConvert = true + } + + // Copy and convert the underlying type if needed. + if doConvert && vt.ConvertibleTo(uint8Type) { + // Convert and copy each element into a uint8 byte + // slice. + buf = make([]uint8, numEntries) + for i := 0; i < numEntries; i++ { + vv := v.Index(i) + buf[i] = uint8(vv.Convert(uint8Type).Uint()) + } + doHexDump = true + } + } + + // Hexdump the entire slice as needed. + if doHexDump { + indent := strings.Repeat(d.cs.Indent, d.depth) + str := indent + hex.Dump(buf) + str = strings.Replace(str, "\n", "\n"+indent, -1) + str = strings.TrimRight(str, d.cs.Indent) + d.w.Write([]byte(str)) + return + } + + // Recursively call dump for each item. + for i := 0; i < numEntries; i++ { + d.dump(d.unpackValue(v.Index(i))) + if i < (numEntries - 1) { + d.w.Write(commaNewlineBytes) + } else { + d.w.Write(newlineBytes) + } + } +} + +// dump is the main workhorse for dumping a value. It uses the passed reflect +// value to figure out what kind of object we are dealing with and formats it +// appropriately. It is a recursive function, however circular data structures +// are detected and handled properly. +func (d *dumpState) dump(v reflect.Value) { + // Handle invalid reflect values immediately. + kind := v.Kind() + if kind == reflect.Invalid { + d.w.Write(invalidAngleBytes) + return + } + + // Handle pointers specially. + if kind == reflect.Ptr { + d.indent() + d.dumpPtr(v) + return + } + + // Print type information unless already handled elsewhere. + if !d.ignoreNextType { + d.indent() + d.w.Write(openParenBytes) + d.w.Write([]byte(v.Type().String())) + d.w.Write(closeParenBytes) + d.w.Write(spaceBytes) + } + d.ignoreNextType = false + + // Display length and capacity if the built-in len and cap functions + // work with the value's kind and the len/cap itself is non-zero. + valueLen, valueCap := 0, 0 + switch v.Kind() { + case reflect.Array, reflect.Slice, reflect.Chan: + valueLen, valueCap = v.Len(), v.Cap() + case reflect.Map, reflect.String: + valueLen = v.Len() + } + if valueLen != 0 || !d.cs.DisableCapacities && valueCap != 0 { + d.w.Write(openParenBytes) + if valueLen != 0 { + d.w.Write(lenEqualsBytes) + printInt(d.w, int64(valueLen), 10) + } + if !d.cs.DisableCapacities && valueCap != 0 { + if valueLen != 0 { + d.w.Write(spaceBytes) + } + d.w.Write(capEqualsBytes) + printInt(d.w, int64(valueCap), 10) + } + d.w.Write(closeParenBytes) + d.w.Write(spaceBytes) + } + + // Call Stringer/error interfaces if they exist and the handle methods flag + // is enabled + if !d.cs.DisableMethods { + if (kind != reflect.Invalid) && (kind != reflect.Interface) { + if handled := handleMethods(d.cs, d.w, v); handled { + return + } + } + } + + switch kind { + case reflect.Invalid: + // Do nothing. We should never get here since invalid has already + // been handled above. + + case reflect.Bool: + printBool(d.w, v.Bool()) + + case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: + printInt(d.w, v.Int(), 10) + + case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: + printUint(d.w, v.Uint(), 10) + + case reflect.Float32: + printFloat(d.w, v.Float(), 32) + + case reflect.Float64: + printFloat(d.w, v.Float(), 64) + + case reflect.Complex64: + printComplex(d.w, v.Complex(), 32) + + case reflect.Complex128: + printComplex(d.w, v.Complex(), 64) + + case reflect.Slice: + if v.IsNil() { + d.w.Write(nilAngleBytes) + break + } + fallthrough + + case reflect.Array: + d.w.Write(openBraceNewlineBytes) + d.depth++ + if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) { + d.indent() + d.w.Write(maxNewlineBytes) + } else { + d.dumpSlice(v) + } + d.depth-- + d.indent() + d.w.Write(closeBraceBytes) + + case reflect.String: + d.w.Write([]byte(strconv.Quote(v.String()))) + + case reflect.Interface: + // The only time we should get here is for nil interfaces due to + // unpackValue calls. + if v.IsNil() { + d.w.Write(nilAngleBytes) + } + + case reflect.Ptr: + // Do nothing. We should never get here since pointers have already + // been handled above. + + case reflect.Map: + // nil maps should be indicated as different than empty maps + if v.IsNil() { + d.w.Write(nilAngleBytes) + break + } + + d.w.Write(openBraceNewlineBytes) + d.depth++ + if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) { + d.indent() + d.w.Write(maxNewlineBytes) + } else { + numEntries := v.Len() + keys := v.MapKeys() + if d.cs.SortKeys { + sortValues(keys, d.cs) + } + for i, key := range keys { + d.dump(d.unpackValue(key)) + d.w.Write(colonSpaceBytes) + d.ignoreNextIndent = true + d.dump(d.unpackValue(v.MapIndex(key))) + if i < (numEntries - 1) { + d.w.Write(commaNewlineBytes) + } else { + d.w.Write(newlineBytes) + } + } + } + d.depth-- + d.indent() + d.w.Write(closeBraceBytes) + + case reflect.Struct: + d.w.Write(openBraceNewlineBytes) + d.depth++ + if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) { + d.indent() + d.w.Write(maxNewlineBytes) + } else { + vt := v.Type() + numFields := v.NumField() + for i := 0; i < numFields; i++ { + d.indent() + vtf := vt.Field(i) + d.w.Write([]byte(vtf.Name)) + d.w.Write(colonSpaceBytes) + d.ignoreNextIndent = true + d.dump(d.unpackValue(v.Field(i))) + if i < (numFields - 1) { + d.w.Write(commaNewlineBytes) + } else { + d.w.Write(newlineBytes) + } + } + } + d.depth-- + d.indent() + d.w.Write(closeBraceBytes) + + case reflect.Uintptr: + printHexPtr(d.w, uintptr(v.Uint())) + + case reflect.UnsafePointer, reflect.Chan, reflect.Func: + printHexPtr(d.w, v.Pointer()) + + // There were not any other types at the time this code was written, but + // fall back to letting the default fmt package handle it in case any new + // types are added. + default: + if v.CanInterface() { + fmt.Fprintf(d.w, "%v", v.Interface()) + } else { + fmt.Fprintf(d.w, "%v", v.String()) + } + } +} + +// fdump is a helper function to consolidate the logic from the various public +// methods which take varying writers and config states. +func fdump(cs *ConfigState, w io.Writer, a ...interface{}) { + for _, arg := range a { + if arg == nil { + w.Write(interfaceBytes) + w.Write(spaceBytes) + w.Write(nilAngleBytes) + w.Write(newlineBytes) + continue + } + + d := dumpState{w: w, cs: cs} + d.pointers = make(map[uintptr]int) + d.dump(reflect.ValueOf(arg)) + d.w.Write(newlineBytes) + } +} + +// Fdump formats and displays the passed arguments to io.Writer w. It formats +// exactly the same as Dump. +func Fdump(w io.Writer, a ...interface{}) { + fdump(&Config, w, a...) +} + +// Sdump returns a string with the passed arguments formatted exactly the same +// as Dump. +func Sdump(a ...interface{}) string { + var buf bytes.Buffer + fdump(&Config, &buf, a...) + return buf.String() +} + +/* +Dump displays the passed parameters to standard out with newlines, customizable +indentation, and additional debug information such as complete types and all +pointer addresses used to indirect to the final value. It provides the +following features over the built-in printing facilities provided by the fmt +package: + + - Pointers are dereferenced and followed + - Circular data structures are detected and handled properly + - Custom Stringer/error interfaces are optionally invoked, including + on unexported types + - Custom types which only implement the Stringer/error interfaces via + a pointer receiver are optionally invoked when passing non-pointer + variables + - Byte arrays and slices are dumped like the hexdump -C command which + includes offsets, byte values in hex, and ASCII output + +The configuration options are controlled by an exported package global, +spew.Config. See ConfigState for options documentation. + +See Fdump if you would prefer dumping to an arbitrary io.Writer or Sdump to +get the formatted result as a string. +*/ +func Dump(a ...interface{}) { + fdump(&Config, os.Stdout, a...) +} diff --git a/vendor/github.com/stretchr/testify/internal/spew/format.go b/vendor/github.com/stretchr/testify/internal/spew/format.go new file mode 100644 index 0000000000..b04edb7d7a --- /dev/null +++ b/vendor/github.com/stretchr/testify/internal/spew/format.go @@ -0,0 +1,419 @@ +/* + * Copyright (c) 2013-2016 Dave Collins + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package spew + +import ( + "bytes" + "fmt" + "reflect" + "strconv" + "strings" +) + +// supportedFlags is a list of all the character flags supported by fmt package. +const supportedFlags = "0-+# " + +// formatState implements the fmt.Formatter interface and contains information +// about the state of a formatting operation. The NewFormatter function can +// be used to get a new Formatter which can be used directly as arguments +// in standard fmt package printing calls. +type formatState struct { + value interface{} + fs fmt.State + depth int + pointers map[uintptr]int + ignoreNextType bool + cs *ConfigState +} + +// buildDefaultFormat recreates the original format string without precision +// and width information to pass in to fmt.Sprintf in the case of an +// unrecognized type. Unless new types are added to the language, this +// function won't ever be called. +func (f *formatState) buildDefaultFormat() (format string) { + buf := bytes.NewBuffer(percentBytes) + + for _, flag := range supportedFlags { + if f.fs.Flag(int(flag)) { + buf.WriteRune(flag) + } + } + + buf.WriteRune('v') + + format = buf.String() + return format +} + +// constructOrigFormat recreates the original format string including precision +// and width information to pass along to the standard fmt package. This allows +// automatic deferral of all format strings this package doesn't support. +func (f *formatState) constructOrigFormat(verb rune) (format string) { + buf := bytes.NewBuffer(percentBytes) + + for _, flag := range supportedFlags { + if f.fs.Flag(int(flag)) { + buf.WriteRune(flag) + } + } + + if width, ok := f.fs.Width(); ok { + buf.WriteString(strconv.Itoa(width)) + } + + if precision, ok := f.fs.Precision(); ok { + buf.Write(precisionBytes) + buf.WriteString(strconv.Itoa(precision)) + } + + buf.WriteRune(verb) + + format = buf.String() + return format +} + +// unpackValue returns values inside of non-nil interfaces when possible and +// ensures that types for values which have been unpacked from an interface +// are displayed when the show types flag is also set. +// This is useful for data types like structs, arrays, slices, and maps which +// can contain varying types packed inside an interface. +func (f *formatState) unpackValue(v reflect.Value) reflect.Value { + if v.Kind() == reflect.Interface { + f.ignoreNextType = false + if !v.IsNil() { + v = v.Elem() + } + } + return v +} + +// formatPtr handles formatting of pointers by indirecting them as necessary. +func (f *formatState) formatPtr(v reflect.Value) { + // Display nil if top level pointer is nil. + showTypes := f.fs.Flag('#') + if v.IsNil() && (!showTypes || f.ignoreNextType) { + f.fs.Write(nilAngleBytes) + return + } + + // Remove pointers at or below the current depth from map used to detect + // circular refs. + for k, depth := range f.pointers { + if depth >= f.depth { + delete(f.pointers, k) + } + } + + // Keep list of all dereferenced pointers to possibly show later. + pointerChain := make([]uintptr, 0) + + // Figure out how many levels of indirection there are by derferencing + // pointers and unpacking interfaces down the chain while detecting circular + // references. + nilFound := false + cycleFound := false + indirects := 0 + ve := v + for ve.Kind() == reflect.Ptr { + if ve.IsNil() { + nilFound = true + break + } + indirects++ + addr := ve.Pointer() + pointerChain = append(pointerChain, addr) + if pd, ok := f.pointers[addr]; ok && pd < f.depth { + cycleFound = true + indirects-- + break + } + f.pointers[addr] = f.depth + + ve = ve.Elem() + if ve.Kind() == reflect.Interface { + if ve.IsNil() { + nilFound = true + break + } + ve = ve.Elem() + } + } + + // Display type or indirection level depending on flags. + if showTypes && !f.ignoreNextType { + f.fs.Write(openParenBytes) + f.fs.Write(bytes.Repeat(asteriskBytes, indirects)) + f.fs.Write([]byte(ve.Type().String())) + f.fs.Write(closeParenBytes) + } else { + if nilFound || cycleFound { + indirects += strings.Count(ve.Type().String(), "*") + } + f.fs.Write(openAngleBytes) + f.fs.Write([]byte(strings.Repeat("*", indirects))) + f.fs.Write(closeAngleBytes) + } + + // Display pointer information depending on flags. + if f.fs.Flag('+') && (len(pointerChain) > 0) { + f.fs.Write(openParenBytes) + for i, addr := range pointerChain { + if i > 0 { + f.fs.Write(pointerChainBytes) + } + printHexPtr(f.fs, addr) + } + f.fs.Write(closeParenBytes) + } + + // Display dereferenced value. + switch { + case nilFound: + f.fs.Write(nilAngleBytes) + + case cycleFound: + f.fs.Write(circularShortBytes) + + default: + f.ignoreNextType = true + f.format(ve) + } +} + +// format is the main workhorse for providing the Formatter interface. It +// uses the passed reflect value to figure out what kind of object we are +// dealing with and formats it appropriately. It is a recursive function, +// however circular data structures are detected and handled properly. +func (f *formatState) format(v reflect.Value) { + // Handle invalid reflect values immediately. + kind := v.Kind() + if kind == reflect.Invalid { + f.fs.Write(invalidAngleBytes) + return + } + + // Handle pointers specially. + if kind == reflect.Ptr { + f.formatPtr(v) + return + } + + // Print type information unless already handled elsewhere. + if !f.ignoreNextType && f.fs.Flag('#') { + f.fs.Write(openParenBytes) + f.fs.Write([]byte(v.Type().String())) + f.fs.Write(closeParenBytes) + } + f.ignoreNextType = false + + // Call Stringer/error interfaces if they exist and the handle methods + // flag is enabled. + if !f.cs.DisableMethods { + if (kind != reflect.Invalid) && (kind != reflect.Interface) { + if handled := handleMethods(f.cs, f.fs, v); handled { + return + } + } + } + + switch kind { + case reflect.Invalid: + // Do nothing. We should never get here since invalid has already + // been handled above. + + case reflect.Bool: + printBool(f.fs, v.Bool()) + + case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: + printInt(f.fs, v.Int(), 10) + + case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: + printUint(f.fs, v.Uint(), 10) + + case reflect.Float32: + printFloat(f.fs, v.Float(), 32) + + case reflect.Float64: + printFloat(f.fs, v.Float(), 64) + + case reflect.Complex64: + printComplex(f.fs, v.Complex(), 32) + + case reflect.Complex128: + printComplex(f.fs, v.Complex(), 64) + + case reflect.Slice: + if v.IsNil() { + f.fs.Write(nilAngleBytes) + break + } + fallthrough + + case reflect.Array: + f.fs.Write(openBracketBytes) + f.depth++ + if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) { + f.fs.Write(maxShortBytes) + } else { + numEntries := v.Len() + for i := 0; i < numEntries; i++ { + if i > 0 { + f.fs.Write(spaceBytes) + } + f.ignoreNextType = true + f.format(f.unpackValue(v.Index(i))) + } + } + f.depth-- + f.fs.Write(closeBracketBytes) + + case reflect.String: + f.fs.Write([]byte(v.String())) + + case reflect.Interface: + // The only time we should get here is for nil interfaces due to + // unpackValue calls. + if v.IsNil() { + f.fs.Write(nilAngleBytes) + } + + case reflect.Ptr: + // Do nothing. We should never get here since pointers have already + // been handled above. + + case reflect.Map: + // nil maps should be indicated as different than empty maps + if v.IsNil() { + f.fs.Write(nilAngleBytes) + break + } + + f.fs.Write(openMapBytes) + f.depth++ + if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) { + f.fs.Write(maxShortBytes) + } else { + keys := v.MapKeys() + if f.cs.SortKeys { + sortValues(keys, f.cs) + } + for i, key := range keys { + if i > 0 { + f.fs.Write(spaceBytes) + } + f.ignoreNextType = true + f.format(f.unpackValue(key)) + f.fs.Write(colonBytes) + f.ignoreNextType = true + f.format(f.unpackValue(v.MapIndex(key))) + } + } + f.depth-- + f.fs.Write(closeMapBytes) + + case reflect.Struct: + numFields := v.NumField() + f.fs.Write(openBraceBytes) + f.depth++ + if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) { + f.fs.Write(maxShortBytes) + } else { + vt := v.Type() + for i := 0; i < numFields; i++ { + if i > 0 { + f.fs.Write(spaceBytes) + } + vtf := vt.Field(i) + if f.fs.Flag('+') || f.fs.Flag('#') { + f.fs.Write([]byte(vtf.Name)) + f.fs.Write(colonBytes) + } + f.format(f.unpackValue(v.Field(i))) + } + } + f.depth-- + f.fs.Write(closeBraceBytes) + + case reflect.Uintptr: + printHexPtr(f.fs, uintptr(v.Uint())) + + case reflect.UnsafePointer, reflect.Chan, reflect.Func: + printHexPtr(f.fs, v.Pointer()) + + // There were not any other types at the time this code was written, but + // fall back to letting the default fmt package handle it if any get added. + default: + format := f.buildDefaultFormat() + if v.CanInterface() { + fmt.Fprintf(f.fs, format, v.Interface()) + } else { + fmt.Fprintf(f.fs, format, v.String()) + } + } +} + +// Format satisfies the fmt.Formatter interface. See NewFormatter for usage +// details. +func (f *formatState) Format(fs fmt.State, verb rune) { + f.fs = fs + + // Use standard formatting for verbs that are not v. + if verb != 'v' { + format := f.constructOrigFormat(verb) + fmt.Fprintf(fs, format, f.value) + return + } + + if f.value == nil { + if fs.Flag('#') { + fs.Write(interfaceBytes) + } + fs.Write(nilAngleBytes) + return + } + + f.format(reflect.ValueOf(f.value)) +} + +// newFormatter is a helper function to consolidate the logic from the various +// public methods which take varying config states. +func newFormatter(cs *ConfigState, v interface{}) fmt.Formatter { + fs := &formatState{value: v, cs: cs} + fs.pointers = make(map[uintptr]int) + return fs +} + +/* +NewFormatter returns a custom formatter that satisfies the fmt.Formatter +interface. As a result, it integrates cleanly with standard fmt package +printing functions. The formatter is useful for inline printing of smaller data +types similar to the standard %v format specifier. + +The custom formatter only responds to the %v (most compact), %+v (adds pointer +addresses), %#v (adds types), or %#+v (adds types and pointer addresses) verb +combinations. Any other verbs such as %x and %q will be sent to the the +standard fmt package for formatting. In addition, the custom formatter ignores +the width and precision arguments (however they will still work on the format +specifiers not handled by the custom formatter). + +Typically this function shouldn't be called directly. It is much easier to make +use of the custom formatter by calling one of the convenience functions such as +Printf, Println, or Fprintf. +*/ +func NewFormatter(v interface{}) fmt.Formatter { + return newFormatter(&Config, v) +} diff --git a/vendor/github.com/stretchr/testify/internal/spew/spew.go b/vendor/github.com/stretchr/testify/internal/spew/spew.go new file mode 100644 index 0000000000..32c0e33882 --- /dev/null +++ b/vendor/github.com/stretchr/testify/internal/spew/spew.go @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2013-2016 Dave Collins + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package spew + +import ( + "fmt" + "io" +) + +// Errorf is a wrapper for fmt.Errorf that treats each argument as if it were +// passed with a default Formatter interface returned by NewFormatter. It +// returns the formatted string as a value that satisfies error. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Errorf(format, spew.NewFormatter(a), spew.NewFormatter(b)) +func Errorf(format string, a ...interface{}) (err error) { + return fmt.Errorf(format, convertArgs(a)...) +} + +// Fprint is a wrapper for fmt.Fprint that treats each argument as if it were +// passed with a default Formatter interface returned by NewFormatter. It +// returns the number of bytes written and any write error encountered. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Fprint(w, spew.NewFormatter(a), spew.NewFormatter(b)) +func Fprint(w io.Writer, a ...interface{}) (n int, err error) { + return fmt.Fprint(w, convertArgs(a)...) +} + +// Fprintf is a wrapper for fmt.Fprintf that treats each argument as if it were +// passed with a default Formatter interface returned by NewFormatter. It +// returns the number of bytes written and any write error encountered. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Fprintf(w, format, spew.NewFormatter(a), spew.NewFormatter(b)) +func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) { + return fmt.Fprintf(w, format, convertArgs(a)...) +} + +// Fprintln is a wrapper for fmt.Fprintln that treats each argument as if it +// passed with a default Formatter interface returned by NewFormatter. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Fprintln(w, spew.NewFormatter(a), spew.NewFormatter(b)) +func Fprintln(w io.Writer, a ...interface{}) (n int, err error) { + return fmt.Fprintln(w, convertArgs(a)...) +} + +// Print is a wrapper for fmt.Print that treats each argument as if it were +// passed with a default Formatter interface returned by NewFormatter. It +// returns the number of bytes written and any write error encountered. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Print(spew.NewFormatter(a), spew.NewFormatter(b)) +func Print(a ...interface{}) (n int, err error) { + return fmt.Print(convertArgs(a)...) +} + +// Printf is a wrapper for fmt.Printf that treats each argument as if it were +// passed with a default Formatter interface returned by NewFormatter. It +// returns the number of bytes written and any write error encountered. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Printf(format, spew.NewFormatter(a), spew.NewFormatter(b)) +func Printf(format string, a ...interface{}) (n int, err error) { + return fmt.Printf(format, convertArgs(a)...) +} + +// Println is a wrapper for fmt.Println that treats each argument as if it were +// passed with a default Formatter interface returned by NewFormatter. It +// returns the number of bytes written and any write error encountered. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Println(spew.NewFormatter(a), spew.NewFormatter(b)) +func Println(a ...interface{}) (n int, err error) { + return fmt.Println(convertArgs(a)...) +} + +// Sprint is a wrapper for fmt.Sprint that treats each argument as if it were +// passed with a default Formatter interface returned by NewFormatter. It +// returns the resulting string. See NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Sprint(spew.NewFormatter(a), spew.NewFormatter(b)) +func Sprint(a ...interface{}) string { + return fmt.Sprint(convertArgs(a)...) +} + +// Sprintf is a wrapper for fmt.Sprintf that treats each argument as if it were +// passed with a default Formatter interface returned by NewFormatter. It +// returns the resulting string. See NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Sprintf(format, spew.NewFormatter(a), spew.NewFormatter(b)) +func Sprintf(format string, a ...interface{}) string { + return fmt.Sprintf(format, convertArgs(a)...) +} + +// Sprintln is a wrapper for fmt.Sprintln that treats each argument as if it +// were passed with a default Formatter interface returned by NewFormatter. It +// returns the resulting string. See NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Sprintln(spew.NewFormatter(a), spew.NewFormatter(b)) +func Sprintln(a ...interface{}) string { + return fmt.Sprintln(convertArgs(a)...) +} + +// convertArgs accepts a slice of arguments and returns a slice of the same +// length with each argument converted to a default spew Formatter interface. +func convertArgs(args []interface{}) (formatters []interface{}) { + formatters = make([]interface{}, len(args)) + for index, arg := range args { + formatters[index] = NewFormatter(arg) + } + return formatters +} diff --git a/vendor/github.com/stretchr/testify/require/doc.go b/vendor/github.com/stretchr/testify/require/doc.go index c8e3f94a80..ee84cc4791 100644 --- a/vendor/github.com/stretchr/testify/require/doc.go +++ b/vendor/github.com/stretchr/testify/require/doc.go @@ -1,4 +1,4 @@ -// Package require implements the same assertions as the `assert` package but +// Package require implements the same assertions as the assert package but // stops test execution when a test fails. // // # Example Usage @@ -21,8 +21,8 @@ // // # Assertions // -// The `require` package have same global functions as in the `assert` package, -// but instead of returning a boolean result they call `t.FailNow()`. +// The require package have same global functions as in the assert package, +// but instead of returning a boolean result they call [testing.T.FailNow]. // A consequence of this is that it must be called from the goroutine running // the test function, not from other goroutines created during the test. // diff --git a/vendor/github.com/stretchr/testify/require/require.go b/vendor/github.com/stretchr/testify/require/require.go index 2d02f9bcef..652871f2eb 100644 --- a/vendor/github.com/stretchr/testify/require/require.go +++ b/vendor/github.com/stretchr/testify/require/require.go @@ -180,7 +180,7 @@ func Equal(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...i t.FailNow() } -// EqualError asserts that a function returned an error (i.e. not `nil`) +// EqualError asserts that a function returned a non-nil error (i.e. an error) // and that it is equal to the provided error. // // actualObj, err := SomeFunction() @@ -195,7 +195,7 @@ func EqualError(t TestingT, theError error, errString string, msgAndArgs ...inte t.FailNow() } -// EqualErrorf asserts that a function returned an error (i.e. not `nil`) +// EqualErrorf asserts that a function returned a non-nil error (i.e. an error) // and that it is equal to the provided error. // // actualObj, err := SomeFunction() @@ -295,7 +295,7 @@ func Equalf(t TestingT, expected interface{}, actual interface{}, msg string, ar t.FailNow() } -// Error asserts that a function returned an error (i.e. not `nil`). +// Error asserts that a function returned a non-nil error (ie. an error). // // actualObj, err := SomeFunction() // require.Error(t, err) @@ -333,8 +333,8 @@ func ErrorAsf(t TestingT, err error, target interface{}, msg string, args ...int t.FailNow() } -// ErrorContains asserts that a function returned an error (i.e. not `nil`) -// and that the error contains the specified substring. +// ErrorContains asserts that a function returned a non-nil error (i.e. an +// error) and that the error contains the specified substring. // // actualObj, err := SomeFunction() // require.ErrorContains(t, err, expectedErrorSubString) @@ -348,8 +348,8 @@ func ErrorContains(t TestingT, theError error, contains string, msgAndArgs ...in t.FailNow() } -// ErrorContainsf asserts that a function returned an error (i.e. not `nil`) -// and that the error contains the specified substring. +// ErrorContainsf asserts that a function returned a non-nil error (i.e. an +// error) and that the error contains the specified substring. // // actualObj, err := SomeFunction() // require.ErrorContainsf(t, err, expectedErrorSubString, "error message %s", "formatted") @@ -387,7 +387,7 @@ func ErrorIsf(t TestingT, err error, target error, msg string, args ...interface t.FailNow() } -// Errorf asserts that a function returned an error (i.e. not `nil`). +// Errorf asserts that a function returned a non-nil error (ie. an error). // // actualObj, err := SomeFunction() // require.Errorf(t, err, "error message %s", "formatted") @@ -429,7 +429,7 @@ func Eventually(t TestingT, condition func() bool, waitFor time.Duration, tick t // time.Sleep(8*time.Second) // externalValue = true // }() -// require.EventuallyWithT(t, func(c *require.CollectT) { +// require.EventuallyWithT(t, func(c *assert.CollectT) { // // add assertions as needed; any assertion failure will fail the current tick // require.True(c, externalValue, "expected 'externalValue' to be true") // }, 10*time.Second, 1*time.Second, "external state has not changed to 'true'; still false") @@ -457,10 +457,10 @@ func EventuallyWithT(t TestingT, condition func(collect *assert.CollectT), waitF // time.Sleep(8*time.Second) // externalValue = true // }() -// require.EventuallyWithTf(t, func(c *require.CollectT, "error message %s", "formatted") { +// require.EventuallyWithTf(t, func(c *assert.CollectT) { // // add assertions as needed; any assertion failure will fail the current tick // require.True(c, externalValue, "expected 'externalValue' to be true") -// }, 10*time.Second, 1*time.Second, "external state has not changed to 'true'; still false") +// }, 10*time.Second, 1*time.Second, "error message %s", "formatted") func EventuallyWithTf(t TestingT, condition func(collect *assert.CollectT), waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -671,8 +671,6 @@ func Greaterf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...in // body that contains a string. // // require.HTTPBodyContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") -// -// Returns whether the assertion was successful (true) or not (false). func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -687,8 +685,6 @@ func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method string, url s // body that contains a string. // // require.HTTPBodyContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") -// -// Returns whether the assertion was successful (true) or not (false). func HTTPBodyContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -703,8 +699,6 @@ func HTTPBodyContainsf(t TestingT, handler http.HandlerFunc, method string, url // body that does not contain a string. // // require.HTTPBodyNotContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") -// -// Returns whether the assertion was successful (true) or not (false). func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -719,8 +713,6 @@ func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method string, ur // body that does not contain a string. // // require.HTTPBodyNotContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") -// -// Returns whether the assertion was successful (true) or not (false). func HTTPBodyNotContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -734,8 +726,6 @@ func HTTPBodyNotContainsf(t TestingT, handler http.HandlerFunc, method string, u // HTTPError asserts that a specified handler returns an error status code. // // require.HTTPError(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} -// -// Returns whether the assertion was successful (true) or not (false). func HTTPError(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -749,8 +739,6 @@ func HTTPError(t TestingT, handler http.HandlerFunc, method string, url string, // HTTPErrorf asserts that a specified handler returns an error status code. // // require.HTTPErrorf(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} -// -// Returns whether the assertion was successful (true) or not (false). func HTTPErrorf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -764,8 +752,6 @@ func HTTPErrorf(t TestingT, handler http.HandlerFunc, method string, url string, // HTTPRedirect asserts that a specified handler returns a redirect status code. // // require.HTTPRedirect(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} -// -// Returns whether the assertion was successful (true) or not (false). func HTTPRedirect(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -779,8 +765,6 @@ func HTTPRedirect(t TestingT, handler http.HandlerFunc, method string, url strin // HTTPRedirectf asserts that a specified handler returns a redirect status code. // // require.HTTPRedirectf(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} -// -// Returns whether the assertion was successful (true) or not (false). func HTTPRedirectf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -794,8 +778,6 @@ func HTTPRedirectf(t TestingT, handler http.HandlerFunc, method string, url stri // HTTPStatusCode asserts that a specified handler returns a specified status code. // // require.HTTPStatusCode(t, myHandler, "GET", "/notImplemented", nil, 501) -// -// Returns whether the assertion was successful (true) or not (false). func HTTPStatusCode(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -809,8 +791,6 @@ func HTTPStatusCode(t TestingT, handler http.HandlerFunc, method string, url str // HTTPStatusCodef asserts that a specified handler returns a specified status code. // // require.HTTPStatusCodef(t, myHandler, "GET", "/notImplemented", nil, 501, "error message %s", "formatted") -// -// Returns whether the assertion was successful (true) or not (false). func HTTPStatusCodef(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -824,8 +804,6 @@ func HTTPStatusCodef(t TestingT, handler http.HandlerFunc, method string, url st // HTTPSuccess asserts that a specified handler returns a success status code. // // require.HTTPSuccess(t, myHandler, "POST", "http://www.google.com", nil) -// -// Returns whether the assertion was successful (true) or not (false). func HTTPSuccess(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -839,8 +817,6 @@ func HTTPSuccess(t TestingT, handler http.HandlerFunc, method string, url string // HTTPSuccessf asserts that a specified handler returns a success status code. // // require.HTTPSuccessf(t, myHandler, "POST", "http://www.google.com", nil, "error message %s", "formatted") -// -// Returns whether the assertion was successful (true) or not (false). func HTTPSuccessf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1385,12 +1361,11 @@ func NoDirExistsf(t TestingT, path string, msg string, args ...interface{}) { t.FailNow() } -// NoError asserts that a function returned no error (i.e. `nil`). +// NoError asserts that a function returned a nil error (ie. no error). // -// actualObj, err := SomeFunction() -// if require.NoError(t, err) { -// require.Equal(t, expectedObj, actualObj) -// } +// actualObj, err := SomeFunction() +// require.NoError(t, err) +// require.Equal(t, expectedObj, actualObj) func NoError(t TestingT, err error, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1401,12 +1376,11 @@ func NoError(t TestingT, err error, msgAndArgs ...interface{}) { t.FailNow() } -// NoErrorf asserts that a function returned no error (i.e. `nil`). +// NoErrorf asserts that a function returned a nil error (ie. no error). // -// actualObj, err := SomeFunction() -// if require.NoErrorf(t, err, "error message %s", "formatted") { -// require.Equal(t, expectedObj, actualObj) -// } +// actualObj, err := SomeFunction() +// require.NoErrorf(t, err, "error message %s", "formatted") +// require.Equal(t, expectedObj, actualObj) func NoErrorf(t TestingT, err error, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1515,9 +1489,8 @@ func NotElementsMatchf(t TestingT, listA interface{}, listB interface{}, msg str // NotEmpty asserts that the specified object is NOT [Empty]. // -// if require.NotEmpty(t, obj) { -// require.Equal(t, "two", obj[1]) -// } +// require.NotEmpty(t, obj) +// require.Equal(t, "two", obj[1]) func NotEmpty(t TestingT, object interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -1530,9 +1503,8 @@ func NotEmpty(t TestingT, object interface{}, msgAndArgs ...interface{}) { // NotEmptyf asserts that the specified object is NOT [Empty]. // -// if require.NotEmptyf(t, obj, "error message %s", "formatted") { -// require.Equal(t, "two", obj[1]) -// } +// require.NotEmptyf(t, obj, "error message %s", "formatted") +// require.Equal(t, "two", obj[1]) func NotEmptyf(t TestingT, object interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -2135,7 +2107,19 @@ func WithinRangef(t TestingT, actual time.Time, start time.Time, end time.Time, t.FailNow() } -// YAMLEq asserts that two YAML strings are equivalent. +// YAMLEq asserts that the first documents in the two YAML strings are equivalent. +// +// expected := `--- +// key: value +// --- +// key: this is a second document, it is not evaluated +// ` +// actual := `--- +// key: value +// --- +// key: this is a subsequent document, it is not evaluated +// ` +// require.YAMLEq(t, expected, actual) func YAMLEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -2146,7 +2130,19 @@ func YAMLEq(t TestingT, expected string, actual string, msgAndArgs ...interface{ t.FailNow() } -// YAMLEqf asserts that two YAML strings are equivalent. +// YAMLEqf asserts that the first documents in the two YAML strings are equivalent. +// +// expected := `--- +// key: value +// --- +// key: this is a second document, it is not evaluated +// ` +// actual := `--- +// key: value +// --- +// key: this is a subsequent document, it is not evaluated +// ` +// require.YAMLEqf(t, expected, actual, "error message %s", "formatted") func YAMLEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() diff --git a/vendor/github.com/stretchr/testify/require/require.go.tmpl b/vendor/github.com/stretchr/testify/require/require.go.tmpl index 8b32836850..6a975501ee 100644 --- a/vendor/github.com/stretchr/testify/require/require.go.tmpl +++ b/vendor/github.com/stretchr/testify/require/require.go.tmpl @@ -1,4 +1,4 @@ -{{ replace .Comment "assert." "require."}} +{{.CommentRequire}} func {{.DocInfo.Name}}(t TestingT, {{.Params}}) { if h, ok := t.(tHelper); ok { h.Helper() } if assert.{{.DocInfo.Name}}(t, {{.ForwardedParams}}) { return } diff --git a/vendor/github.com/stretchr/testify/require/require_forward.go b/vendor/github.com/stretchr/testify/require/require_forward.go index e6f7e94468..edac147ef4 100644 --- a/vendor/github.com/stretchr/testify/require/require_forward.go +++ b/vendor/github.com/stretchr/testify/require/require_forward.go @@ -147,7 +147,7 @@ func (a *Assertions) Equal(expected interface{}, actual interface{}, msgAndArgs Equal(a.t, expected, actual, msgAndArgs...) } -// EqualError asserts that a function returned an error (i.e. not `nil`) +// EqualError asserts that a function returned a non-nil error (i.e. an error) // and that it is equal to the provided error. // // actualObj, err := SomeFunction() @@ -159,7 +159,7 @@ func (a *Assertions) EqualError(theError error, errString string, msgAndArgs ... EqualError(a.t, theError, errString, msgAndArgs...) } -// EqualErrorf asserts that a function returned an error (i.e. not `nil`) +// EqualErrorf asserts that a function returned a non-nil error (i.e. an error) // and that it is equal to the provided error. // // actualObj, err := SomeFunction() @@ -241,7 +241,7 @@ func (a *Assertions) Equalf(expected interface{}, actual interface{}, msg string Equalf(a.t, expected, actual, msg, args...) } -// Error asserts that a function returned an error (i.e. not `nil`). +// Error asserts that a function returned a non-nil error (ie. an error). // // actualObj, err := SomeFunction() // a.Error(err) @@ -270,8 +270,8 @@ func (a *Assertions) ErrorAsf(err error, target interface{}, msg string, args .. ErrorAsf(a.t, err, target, msg, args...) } -// ErrorContains asserts that a function returned an error (i.e. not `nil`) -// and that the error contains the specified substring. +// ErrorContains asserts that a function returned a non-nil error (i.e. an +// error) and that the error contains the specified substring. // // actualObj, err := SomeFunction() // a.ErrorContains(err, expectedErrorSubString) @@ -282,8 +282,8 @@ func (a *Assertions) ErrorContains(theError error, contains string, msgAndArgs . ErrorContains(a.t, theError, contains, msgAndArgs...) } -// ErrorContainsf asserts that a function returned an error (i.e. not `nil`) -// and that the error contains the specified substring. +// ErrorContainsf asserts that a function returned a non-nil error (i.e. an +// error) and that the error contains the specified substring. // // actualObj, err := SomeFunction() // a.ErrorContainsf(err, expectedErrorSubString, "error message %s", "formatted") @@ -312,7 +312,7 @@ func (a *Assertions) ErrorIsf(err error, target error, msg string, args ...inter ErrorIsf(a.t, err, target, msg, args...) } -// Errorf asserts that a function returned an error (i.e. not `nil`). +// Errorf asserts that a function returned a non-nil error (ie. an error). // // actualObj, err := SomeFunction() // a.Errorf(err, "error message %s", "formatted") @@ -373,10 +373,10 @@ func (a *Assertions) EventuallyWithT(condition func(collect *assert.CollectT), w // time.Sleep(8*time.Second) // externalValue = true // }() -// a.EventuallyWithTf(func(c *assert.CollectT, "error message %s", "formatted") { +// a.EventuallyWithTf(func(c *assert.CollectT) { // // add assertions as needed; any assertion failure will fail the current tick // assert.True(c, externalValue, "expected 'externalValue' to be true") -// }, 10*time.Second, 1*time.Second, "external state has not changed to 'true'; still false") +// }, 10*time.Second, 1*time.Second, "error message %s", "formatted") func (a *Assertions) EventuallyWithTf(condition func(collect *assert.CollectT), waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -539,8 +539,6 @@ func (a *Assertions) Greaterf(e1 interface{}, e2 interface{}, msg string, args . // body that contains a string. // // a.HTTPBodyContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") -// -// Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -552,8 +550,6 @@ func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, method string, u // body that contains a string. // // a.HTTPBodyContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") -// -// Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPBodyContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -565,8 +561,6 @@ func (a *Assertions) HTTPBodyContainsf(handler http.HandlerFunc, method string, // body that does not contain a string. // // a.HTTPBodyNotContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") -// -// Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -578,8 +572,6 @@ func (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, method string // body that does not contain a string. // // a.HTTPBodyNotContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") -// -// Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPBodyNotContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -590,8 +582,6 @@ func (a *Assertions) HTTPBodyNotContainsf(handler http.HandlerFunc, method strin // HTTPError asserts that a specified handler returns an error status code. // // a.HTTPError(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} -// -// Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPError(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -602,8 +592,6 @@ func (a *Assertions) HTTPError(handler http.HandlerFunc, method string, url stri // HTTPErrorf asserts that a specified handler returns an error status code. // // a.HTTPErrorf(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} -// -// Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPErrorf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -614,8 +602,6 @@ func (a *Assertions) HTTPErrorf(handler http.HandlerFunc, method string, url str // HTTPRedirect asserts that a specified handler returns a redirect status code. // // a.HTTPRedirect(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} -// -// Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPRedirect(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -626,8 +612,6 @@ func (a *Assertions) HTTPRedirect(handler http.HandlerFunc, method string, url s // HTTPRedirectf asserts that a specified handler returns a redirect status code. // // a.HTTPRedirectf(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} -// -// Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPRedirectf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -638,8 +622,6 @@ func (a *Assertions) HTTPRedirectf(handler http.HandlerFunc, method string, url // HTTPStatusCode asserts that a specified handler returns a specified status code. // // a.HTTPStatusCode(myHandler, "GET", "/notImplemented", nil, 501) -// -// Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPStatusCode(handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -650,8 +632,6 @@ func (a *Assertions) HTTPStatusCode(handler http.HandlerFunc, method string, url // HTTPStatusCodef asserts that a specified handler returns a specified status code. // // a.HTTPStatusCodef(myHandler, "GET", "/notImplemented", nil, 501, "error message %s", "formatted") -// -// Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPStatusCodef(handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -662,8 +642,6 @@ func (a *Assertions) HTTPStatusCodef(handler http.HandlerFunc, method string, ur // HTTPSuccess asserts that a specified handler returns a success status code. // // a.HTTPSuccess(myHandler, "POST", "http://www.google.com", nil) -// -// Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPSuccess(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -674,8 +652,6 @@ func (a *Assertions) HTTPSuccess(handler http.HandlerFunc, method string, url st // HTTPSuccessf asserts that a specified handler returns a success status code. // // a.HTTPSuccessf(myHandler, "POST", "http://www.google.com", nil, "error message %s", "formatted") -// -// Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPSuccessf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1097,12 +1073,11 @@ func (a *Assertions) NoDirExistsf(path string, msg string, args ...interface{}) NoDirExistsf(a.t, path, msg, args...) } -// NoError asserts that a function returned no error (i.e. `nil`). +// NoError asserts that a function returned a nil error (ie. no error). // -// actualObj, err := SomeFunction() -// if a.NoError(err) { -// assert.Equal(t, expectedObj, actualObj) -// } +// actualObj, err := SomeFunction() +// a.NoError(err) +// a.Equal(expectedObj, actualObj) func (a *Assertions) NoError(err error, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1110,12 +1085,11 @@ func (a *Assertions) NoError(err error, msgAndArgs ...interface{}) { NoError(a.t, err, msgAndArgs...) } -// NoErrorf asserts that a function returned no error (i.e. `nil`). +// NoErrorf asserts that a function returned a nil error (ie. no error). // -// actualObj, err := SomeFunction() -// if a.NoErrorf(err, "error message %s", "formatted") { -// assert.Equal(t, expectedObj, actualObj) -// } +// actualObj, err := SomeFunction() +// a.NoErrorf(err, "error message %s", "formatted") +// a.Equal(expectedObj, actualObj) func (a *Assertions) NoErrorf(err error, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1203,9 +1177,8 @@ func (a *Assertions) NotElementsMatchf(listA interface{}, listB interface{}, msg // NotEmpty asserts that the specified object is NOT [Empty]. // -// if a.NotEmpty(obj) { -// assert.Equal(t, "two", obj[1]) -// } +// a.NotEmpty(obj) +// a.Equal("two", obj[1]) func (a *Assertions) NotEmpty(object interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1215,9 +1188,8 @@ func (a *Assertions) NotEmpty(object interface{}, msgAndArgs ...interface{}) { // NotEmptyf asserts that the specified object is NOT [Empty]. // -// if a.NotEmptyf(obj, "error message %s", "formatted") { -// assert.Equal(t, "two", obj[1]) -// } +// a.NotEmptyf(obj, "error message %s", "formatted") +// a.Equal("two", obj[1]) func (a *Assertions) NotEmptyf(object interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1691,7 +1663,19 @@ func (a *Assertions) WithinRangef(actual time.Time, start time.Time, end time.Ti WithinRangef(a.t, actual, start, end, msg, args...) } -// YAMLEq asserts that two YAML strings are equivalent. +// YAMLEq asserts that the first documents in the two YAML strings are equivalent. +// +// expected := `--- +// key: value +// --- +// key: this is a second document, it is not evaluated +// ` +// actual := `--- +// key: value +// --- +// key: this is a subsequent document, it is not evaluated +// ` +// a.YAMLEq(expected, actual) func (a *Assertions) YAMLEq(expected string, actual string, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -1699,7 +1683,19 @@ func (a *Assertions) YAMLEq(expected string, actual string, msgAndArgs ...interf YAMLEq(a.t, expected, actual, msgAndArgs...) } -// YAMLEqf asserts that two YAML strings are equivalent. +// YAMLEqf asserts that the first documents in the two YAML strings are equivalent. +// +// expected := `--- +// key: value +// --- +// key: this is a second document, it is not evaluated +// ` +// actual := `--- +// key: value +// --- +// key: this is a subsequent document, it is not evaluated +// ` +// a.YAMLEqf(expected, actual, "error message %s", "formatted") func (a *Assertions) YAMLEqf(expected string, actual string, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() diff --git a/vendor/github.com/stretchr/testify/require/require_forward.go.tmpl b/vendor/github.com/stretchr/testify/require/require_forward.go.tmpl index 54124df1d3..b3b751de48 100644 --- a/vendor/github.com/stretchr/testify/require/require_forward.go.tmpl +++ b/vendor/github.com/stretchr/testify/require/require_forward.go.tmpl @@ -1,4 +1,4 @@ -{{.CommentWithoutT "a"}} +{{.CommentRequireWithoutT "a"}} func (a *Assertions) {{.DocInfo.Name}}({{.Params}}) { if h, ok := a.t.(tHelper); ok { h.Helper() } {{.DocInfo.Name}}(a.t, {{.ForwardedParams}}) diff --git a/vendor/github.com/stretchr/testify/require/requirements.go b/vendor/github.com/stretchr/testify/require/requirements.go index 6b7ce929eb..375adb0a6a 100644 --- a/vendor/github.com/stretchr/testify/require/requirements.go +++ b/vendor/github.com/stretchr/testify/require/requirements.go @@ -12,18 +12,18 @@ type tHelper = interface { // ComparisonAssertionFunc is a common function prototype when comparing two values. Can be useful // for table driven tests. -type ComparisonAssertionFunc func(TestingT, interface{}, interface{}, ...interface{}) +type ComparisonAssertionFunc = func(TestingT, interface{}, interface{}, ...interface{}) // ValueAssertionFunc is a common function prototype when validating a single value. Can be useful // for table driven tests. -type ValueAssertionFunc func(TestingT, interface{}, ...interface{}) +type ValueAssertionFunc = func(TestingT, interface{}, ...interface{}) // BoolAssertionFunc is a common function prototype when validating a bool value. Can be useful // for table driven tests. -type BoolAssertionFunc func(TestingT, bool, ...interface{}) +type BoolAssertionFunc = func(TestingT, bool, ...interface{}) // ErrorAssertionFunc is a common function prototype when validating an error value. Can be useful // for table driven tests. -type ErrorAssertionFunc func(TestingT, error, ...interface{}) +type ErrorAssertionFunc = func(TestingT, error, ...interface{}) //go:generate sh -c "cd ../_codegen && go build && cd - && ../_codegen/_codegen -output-package=require -template=require.go.tmpl -include-format-funcs" diff --git a/vendor/go.podman.io/common/pkg/auth/auth.go b/vendor/go.podman.io/common/pkg/auth/auth.go index 1a04716150..3042396b25 100644 --- a/vendor/go.podman.io/common/pkg/auth/auth.go +++ b/vendor/go.podman.io/common/pkg/auth/auth.go @@ -182,6 +182,9 @@ func Login(ctx context.Context, systemContext *types.SystemContext, opts *LoginO for scanner.Scan() { fmt.Fprint(&stdinPasswordStrBuilder, scanner.Text()) } + if err := scanner.Err(); err != nil { + return fmt.Errorf("reading password from stdin: %w", err) + } password = stdinPasswordStrBuilder.String() } diff --git a/vendor/go.podman.io/image/v5/docker/docker_image_src.go b/vendor/go.podman.io/image/v5/docker/docker_image_src.go index e93d338d28..4a4a029198 100644 --- a/vendor/go.podman.io/image/v5/docker/docker_image_src.go +++ b/vendor/go.podman.io/image/v5/docker/docker_image_src.go @@ -8,15 +8,20 @@ import ( "fmt" "io" "math" + "math/rand/v2" "mime" "mime/multipart" + "net" "net/http" "net/url" "os" "os/exec" "strings" "sync" + "time" + "github.com/docker/distribution/registry/api/errcode" + v2 "github.com/docker/distribution/registry/api/v2" digest "github.com/opencontainers/go-digest" "github.com/sirupsen/logrus" "go.podman.io/image/v5/docker/reference" @@ -48,6 +53,31 @@ type dockerImageSource struct { // State cachedManifest []byte // nil if not loaded yet cachedManifestMIMEType string // Only valid if cachedManifest != nil + + // Mirror fallback: when a blob fetch fails with a fallback-worthy error, + // try remaining pull sources before giving up. Protected by mirrorMu. + mirrorMu sync.Mutex + mirrorOverride *mirrorSource // If non-nil, this is the mirror and physicalRef for the override client + prevOverrides []*dockerClient // mirror clients replaced by a newer mirrorOverride; kept open because other goroutines may still be reading blobs through them, closed in Close() + remainingSources []sysregistriesv2.PullSource // later pull sources not yet tried, consumed front-to-back during fallback; nil when selected source is already the original source. + fallbackSys *types.SystemContext + fallbackRegConfig *registryConfiguration +} + +type mirrorSource struct { + client *dockerClient + ref dockerReference +} + +type pullEndpoint struct { + client *dockerClient + ref dockerReference + endpointSys *types.SystemContext +} + +type sourceAttempt struct { + ref reference.Named + err error } // newImageSource creates a new ImageSource for the specified image reference. @@ -86,12 +116,8 @@ func newImageSource(ctx context.Context, sys *types.SystemContext, ref dockerRef if err != nil { return nil, err } - type attempt struct { - ref reference.Named - err error - } - attempts := []attempt{} - for _, pullSource := range pullSources { + attempts := []sourceAttempt{} + for i, pullSource := range pullSources { if sys != nil && sys.DockerLogMirrorChoice { logrus.Infof("Trying to access %q", pullSource.Reference) } else { @@ -99,10 +125,15 @@ func newImageSource(ctx context.Context, sys *types.SystemContext, ref dockerRef } s, err := newImageSourceAttempt(ctx, sys, ref, pullSource, registryConfig) if err == nil { + if i+1 < len(pullSources) { + s.remainingSources = pullSources[i+1:] + s.fallbackSys = sys + s.fallbackRegConfig = registryConfig + } return s, nil } logrus.Debugf("Accessing %q failed: %v", pullSource.Reference, err) - attempts = append(attempts, attempt{ + attempts = append(attempts, sourceAttempt{ ref: pullSource.Reference, err: err, }) @@ -131,53 +162,37 @@ func newImageSource(ctx context.Context, sys *types.SystemContext, ref dockerRef func newImageSourceAttempt(ctx context.Context, sys *types.SystemContext, logicalRef dockerReference, pullSource sysregistriesv2.PullSource, registryConfig *registryConfiguration, ) (*dockerImageSource, error) { - physicalRef, err := newReference(pullSource.Reference, false) + endpoint, err := newPullClient(sys, logicalRef, pullSource, registryConfig) if err != nil { return nil, err } - endpointSys := sys - // sys.DockerAuthConfig does not explicitly specify a registry; we must not blindly send the credentials intended for the primary endpoint to mirrors. - if endpointSys != nil && endpointSys.DockerAuthConfig != nil && reference.Domain(physicalRef.ref) != reference.Domain(logicalRef.ref) { - copy := *endpointSys - copy.DockerAuthConfig = nil - copy.DockerBearerRegistryToken = "" - endpointSys = © - } - - client, err := newDockerClientFromRef(endpointSys, physicalRef, registryConfig, false, "pull") - if err != nil { - return nil, err - } - client.tlsClientConfig.InsecureSkipVerify = pullSource.Endpoint.Insecure - client.namespaceProxy = pullSource.Endpoint.NamespaceProxy - s := &dockerImageSource{ PropertyMethodsInitialize: impl.PropertyMethods(impl.Properties{ HasThreadSafeGetBlob: true, }), logicalRef: logicalRef, - physicalRef: physicalRef, - c: client, + physicalRef: endpoint.ref, + c: endpoint.client, } s.Compat = impl.AddCompat(s) if err := s.ensureManifestIsLoaded(ctx); err != nil { - client.Close() + endpoint.client.Close() return nil, err } - if h, err := sysregistriesv2.AdditionalLayerStoreAuthHelper(endpointSys); err == nil && h != "" { + if h, err := sysregistriesv2.AdditionalLayerStoreAuthHelper(endpoint.endpointSys); err == nil && h != "" { acf := map[string]struct { Username string `json:"username,omitempty"` Password string `json:"password,omitempty"` IdentityToken string `json:"identityToken,omitempty"` }{ - physicalRef.ref.String(): { - Username: client.auth.Username, - Password: client.auth.Password, - IdentityToken: client.auth.IdentityToken, + endpoint.ref.ref.String(): { + Username: endpoint.client.auth.Username, + Password: endpoint.client.auth.Password, + IdentityToken: endpoint.client.auth.IdentityToken, }, } acfD, err := json.Marshal(acf) @@ -198,6 +213,36 @@ func newImageSourceAttempt(ctx context.Context, sys *types.SystemContext, logica return s, nil } +// newPullClient creates a dockerClient, reference, and endpoint-specific SystemContext +// for the given pull source. +// The caller must call client.Close() when done. +func newPullClient(sys *types.SystemContext, logicalRef dockerReference, pullSource sysregistriesv2.PullSource, + registryConfig *registryConfiguration, +) (*pullEndpoint, error) { + physicalRef, err := newReference(pullSource.Reference, false) + if err != nil { + return nil, err + } + + endpointSys := sys + // sys.DockerAuthConfig does not explicitly specify a registry; we must not blindly send the credentials intended for the primary endpoint to mirrors. + if endpointSys != nil && endpointSys.DockerAuthConfig != nil && reference.Domain(physicalRef.ref) != reference.Domain(logicalRef.ref) { + copy := *endpointSys + copy.DockerAuthConfig = nil + copy.DockerBearerRegistryToken = "" + endpointSys = © + } + + client, err := newDockerClientFromRef(endpointSys, physicalRef, registryConfig, false, "pull") + if err != nil { + return nil, err + } + client.tlsClientConfig.InsecureSkipVerify = pullSource.Endpoint.Insecure + client.namespaceProxy = pullSource.Endpoint.NamespaceProxy + + return &pullEndpoint{client: client, ref: physicalRef, endpointSys: endpointSys}, nil +} + // Reference returns the reference used to set up this source, _as specified by the user_ // (not as the image itself, or its underlying storage, claims). This can be used e.g. to determine which public keys are trusted for this image. func (s *dockerImageSource) Reference() types.ImageReference { @@ -206,6 +251,18 @@ func (s *dockerImageSource) Reference() types.ImageReference { // Close removes resources associated with an initialized ImageSource, if any. func (s *dockerImageSource) Close() error { + s.mirrorMu.Lock() + prev := s.prevOverrides + override := s.mirrorOverride + s.prevOverrides = nil + s.mirrorOverride = nil + s.mirrorMu.Unlock() + for _, m := range prev { + m.Close() + } + if override != nil { + override.client.Close() + } return s.c.Close() } @@ -416,9 +473,88 @@ func (s *dockerImageSource) GetBlobAt(ctx context.Context, info types.BlobInfo, if err := info.Digest.Validate(); err != nil { // Make sure info.Digest.String() does not contain any unexpected characters return nil, nil, err } - path := fmt.Sprintf(blobsPath, reference.Path(s.physicalRef.ref), info.Digest.String()) + + client, physRef, hasRemaining := s.getActiveSource() + streams, errs, err := tryGetBlobAt(ctx, client, physRef, info, chunks, headers, hasRemaining) + if err == nil || !hasRemaining { + return streams, errs, err + } + if isMirrorTransientError(err) || isMirrorFallbackError(err) { + logrus.Debugf("Partial blob %s fetch from %q failed (%v), trying fallback sources", info.Digest, physRef.ref, err) + return s.getBlobAtWithMirrorFallback(ctx, info, chunks, headers, err, client) + } + return streams, errs, err +} + +// GetBlob returns a stream for the specified blob, and the blob’s size (or -1 if unknown). +// The Digest field in BlobInfo is guaranteed to be provided, Size may be -1 and MediaType may be optionally provided. +// May update BlobInfoCache, preferably after it knows for certain that a blob truly exists at a specific location. +func (s *dockerImageSource) GetBlob(ctx context.Context, info types.BlobInfo, cache types.BlobInfoCache) (io.ReadCloser, int64, error) { + client, physRef, hasRemaining := s.getActiveSource() + reader, size, err := tryGetBlob(ctx, client, physRef, info, cache, hasRemaining) + if err == nil || !hasRemaining { + return reader, size, err + } + if isMirrorTransientError(err) || isMirrorFallbackError(err) { + logrus.Debugf("Blob %s fetch from %q failed (%v), trying fallback sources", info.Digest, physRef.ref, err) + return s.getBlobWithMirrorFallback(ctx, info, cache, err, client) + } + return reader, size, err +} + +func (s *dockerImageSource) getActiveSource() (*dockerClient, dockerReference, bool) { + s.mirrorMu.Lock() + defer s.mirrorMu.Unlock() + hasRemaining := len(s.remainingSources) > 0 + if s.mirrorOverride != nil { + return s.mirrorOverride.client, s.mirrorOverride.ref, hasRemaining + } + return s.c, s.physicalRef, hasRemaining +} + +// tryGetBlob attempts to fetch a blob, retrying once on transient errors if fallback mirrors remain. +func tryGetBlob(ctx context.Context, client *dockerClient, physRef dockerReference, + info types.BlobInfo, cache types.BlobInfoCache, hasRemainingSources bool, +) (io.ReadCloser, int64, error) { + reader, size, err := client.getBlob(ctx, physRef, info, cache) + if err != nil && hasRemainingSources && isMirrorTransientError(err) { + logrus.Debugf("Transient error fetching blob %s from %q, retrying: %v", info.Digest, physRef.ref, err) + delay := time.Second + rand.N(time.Second/10) // same as retry.IfNecessary first attempt: 1s + 10% jitter + select { + case <-ctx.Done(): + return nil, 0, fmt.Errorf("%w (while retrying after: %v)", ctx.Err(), err) + case <-time.After(delay): + } + reader, size, err = client.getBlob(ctx, physRef, info, cache) + } + return reader, size, err +} + +// tryGetBlobAt attempts to fetch a partial blob (range request), retrying once on transient errors +// if fallback mirrors remain. Mirrors tryGetBlob for the partial-pull (zstd:chunked) path. +func tryGetBlobAt(ctx context.Context, client *dockerClient, physRef dockerReference, + info types.BlobInfo, chunks []private.ImageSourceChunk, headers map[string][]string, hasRemainingSources bool, +) (chan io.ReadCloser, chan error, error) { + streams, errs, err := fetchBlobAt(ctx, client, physRef, info, chunks, headers) + if err != nil && hasRemainingSources && isMirrorTransientError(err) { + logrus.Debugf("Transient error fetching partial blob %s from %q, retrying: %v", info.Digest, physRef.ref, err) + delay := time.Second + rand.N(time.Second/10) + select { + case <-ctx.Done(): + return nil, nil, fmt.Errorf("%w (while retrying after: %v)", ctx.Err(), err) + case <-time.After(delay): + } + streams, errs, err = fetchBlobAt(ctx, client, physRef, info, chunks, headers) + } + return streams, errs, err +} + +func fetchBlobAt(ctx context.Context, client *dockerClient, physRef dockerReference, + info types.BlobInfo, chunks []private.ImageSourceChunk, headers map[string][]string, +) (chan io.ReadCloser, chan error, error) { + path := fmt.Sprintf(blobsPath, reference.Path(physRef.ref), info.Digest.String()) logrus.Debugf("Downloading %s", path) - res, err := s.c.makeRequest(ctx, http.MethodGet, path, headers, nil, v2Auth, nil) + res, err := client.makeRequest(ctx, http.MethodGet, path, headers, nil, v2Auth, nil) if err != nil { return nil, nil, err } @@ -436,27 +572,195 @@ func (s *dockerImageSource) GetBlobAt(ctx context.Context, info types.BlobInfo, if err != nil { return nil, nil, err } - streams := make(chan io.ReadCloser) errs := make(chan error) - go handle206Response(streams, errs, res.Body, chunks, mediaType, params) return streams, errs, nil case http.StatusBadRequest: res.Body.Close() return nil, nil, private.BadPartialRequestError{Status: res.Status} default: - err := registryHTTPResponseToError(res) + httpErr := registryHTTPResponseToError(res) res.Body.Close() - return nil, nil, fmt.Errorf("fetching partial blob: %w", err) + return nil, nil, fmt.Errorf("fetching partial blob: %w", httpErr) } } -// GetBlob returns a stream for the specified blob, and the blob’s size (or -1 if unknown). -// The Digest field in BlobInfo is guaranteed to be provided, Size may be -1 and MediaType may be optionally provided. -// May update BlobInfoCache, preferably after it knows for certain that a blob truly exists at a specific location. -func (s *dockerImageSource) GetBlob(ctx context.Context, info types.BlobInfo, cache types.BlobInfoCache) (io.ReadCloser, int64, error) { - return s.c.getBlob(ctx, s.physicalRef, info, cache) +// isMirrorFallbackError returns true for errors where the blob is not present +// on this source but may be available from another — warranting a fallback attempt. +// All tested registries (docker.io, registry.redhat.io, quay.io, registry.access.redhat.com) +// return BLOB_UNKNOWN for blob 404s, matching the OCI distribution spec. +func isMirrorFallbackError(err error) bool { + var ec errcode.ErrorCoder + if errors.As(err, &ec) { + switch ec.ErrorCode() { + case v2.ErrorCodeBlobUnknown: + // Blob endpoint returns HTTP 404 with errcode JSON body + // {"errors":[{"code":"BLOB_UNKNOWN",...}]}. + // registryHTTPResponseToError calls handleErrorResponse → parseHTTPErrorResponse, + // then unwraps errcode.Errors to the first errcode.Error. + return true + case errcode.ErrorCodeTooManyRequests: + // makeRequestToResolvedURL already retried 5 times with exponential + // backoff. This source's rate limit is exhausted — skip straight to + // the next mirror which has its own rate limit budget. + return true + } + } + + // UnexpectedHTTPStatusError (capital U) is NOT matched here — for regular blobs, + // handleErrorResponse never produces it for 4xx (only for 5xx). For external blobs, + // getExternalBlob() produces it via newUnexpectedHTTPStatusError() directly for any + // non-200 including 404, but external URLs are fixed and mirror-independent — + // a different registry mirror cannot serve them. + return false +} + +// isMirrorTransientError returns true for errors that are transient; the source +// probably has the blob but temporarily cannot serve it. +func isMirrorTransientError(err error) bool { + // HTTP 5xx: handleErrorResponse returns UnexpectedHTTPStatusError for status + // codes outside 400–499. Server-side error, another mirror may succeed. + var httpErr UnexpectedHTTPStatusError + if errors.As(err, &httpErr) && httpErr.StatusCode >= 500 { + return true + } + + // Network timeout: makeRequest returns net.Error with Timeout() == true. + // The mirror is reachable but slow — worth retrying on another. + var netErr net.Error + return errors.As(err, &netErr) && netErr.Timeout() +} + +// retireStaleOverride checks if the current mirrorOverride was set by another +// goroutine and differs from failedClient. If so, it returns the override's +// client and ref for the caller to retry. If the override is the same client +// that already failed, or is nil, it returns nil. Must be called with mirrorMu held. +func (s *dockerImageSource) retireStaleOverride(failedClient *dockerClient) (*dockerClient, dockerReference, bool) { + if s.mirrorOverride != nil && s.mirrorOverride.client != failedClient { + return s.mirrorOverride.client, s.mirrorOverride.ref, true + } + return nil, dockerReference{}, false +} + +// retireCurrentOverride moves the current mirrorOverride to prevOverrides. +// Must be called with mirrorMu held. +func (s *dockerImageSource) retireCurrentOverride() { + if s.mirrorOverride != nil { + s.prevOverrides = append(s.prevOverrides, s.mirrorOverride.client) + s.mirrorOverride = nil + } +} + +func formatFallbackError(attempts []sourceAttempt, originalErr error) error { + if len(attempts) == 0 { + return originalErr + } + extras := make([]string, 0, len(attempts)) + for _, a := range attempts { + extras = append(extras, fmt.Sprintf("[%s: %v]", a.ref.String(), a.err)) + } + return fmt.Errorf("(Fallback sources also failed: %s): %w", strings.Join(extras, "\n"), originalErr) +} + +func (s *dockerImageSource) getBlobWithMirrorFallback(ctx context.Context, info types.BlobInfo, cache types.BlobInfoCache, originalErr error, failedClient *dockerClient) (io.ReadCloser, int64, error) { + // Held for the full fallback loop, including network I/O. This serializes + // concurrent blob fetchers during fallback — only one goroutine probes + // sources while the rest block on getActiveSource(). Acceptable trade-off: + // fallback is rare and serialization prevents thundering-herd probing. + s.mirrorMu.Lock() + defer s.mirrorMu.Unlock() + + if client, physRef, ok := s.retireStaleOverride(failedClient); ok { + reader, size, err := tryGetBlob(ctx, client, physRef, info, cache, len(s.remainingSources) > 0) + if err == nil { + return reader, size, nil + } + s.retireCurrentOverride() + } + + attempts := []sourceAttempt{} + for len(s.remainingSources) > 0 { + pullSource := s.remainingSources[0] + s.remainingSources = s.remainingSources[1:] + + logrus.Debugf("Trying to access %q", pullSource.Reference) + + fallbackEndpoint, clientErr := newPullClient(s.fallbackSys, s.logicalRef, pullSource, s.fallbackRegConfig) + if clientErr != nil { + logrus.Debugf("Accessing %q failed: %v", pullSource.Reference, clientErr) + attempts = append(attempts, sourceAttempt{ref: pullSource.Reference, err: clientErr}) + continue + } + + reader, size, err := tryGetBlob(ctx, fallbackEndpoint.client, fallbackEndpoint.ref, info, cache, len(s.remainingSources) > 0) + if err != nil { + fallbackEndpoint.client.Close() + logrus.Debugf("Accessing %q failed: %v", pullSource.Reference, err) + attempts = append(attempts, sourceAttempt{ref: pullSource.Reference, err: err}) + if !isMirrorTransientError(err) && !isMirrorFallbackError(err) { + // non-transient errors are unlikely to be resolved by trying another source: stop probing further. + // break here to log the attempts and return originalErr below. + break + } + continue + } + + s.retireCurrentOverride() + s.mirrorOverride = &mirrorSource{client: fallbackEndpoint.client, ref: fallbackEndpoint.ref} + logrus.Debugf("Blob fetch succeeded from fallback source %q, switching to it for future requests", pullSource.Reference) + + return reader, size, nil + } + return nil, 0, formatFallbackError(attempts, originalErr) +} + +func (s *dockerImageSource) getBlobAtWithMirrorFallback(ctx context.Context, info types.BlobInfo, chunks []private.ImageSourceChunk, headers map[string][]string, originalErr error, failedClient *dockerClient) (chan io.ReadCloser, chan error, error) { + s.mirrorMu.Lock() + defer s.mirrorMu.Unlock() + + if client, physRef, ok := s.retireStaleOverride(failedClient); ok { + streams, errs, err := tryGetBlobAt(ctx, client, physRef, info, chunks, headers, len(s.remainingSources) > 0) + if err == nil { + return streams, errs, nil + } + s.retireCurrentOverride() + } + + attempts := []sourceAttempt{} + for len(s.remainingSources) > 0 { + pullSource := s.remainingSources[0] + s.remainingSources = s.remainingSources[1:] + + logrus.Debugf("Trying to access %q", pullSource.Reference) + + fallbackEndpoint, clientErr := newPullClient(s.fallbackSys, s.logicalRef, pullSource, s.fallbackRegConfig) + if clientErr != nil { + logrus.Debugf("Accessing %q failed: %v", pullSource.Reference, clientErr) + attempts = append(attempts, sourceAttempt{ref: pullSource.Reference, err: clientErr}) + continue + } + + streams, errs, err := tryGetBlobAt(ctx, fallbackEndpoint.client, fallbackEndpoint.ref, info, chunks, headers, len(s.remainingSources) > 0) + if err != nil { + fallbackEndpoint.client.Close() + logrus.Debugf("Accessing %q failed: %v", pullSource.Reference, err) + attempts = append(attempts, sourceAttempt{ref: pullSource.Reference, err: err}) + if !isMirrorTransientError(err) && !isMirrorFallbackError(err) { + // non-transient errors are unlikely to be resolved by trying another source: stop probing further. + // break here to log the attempts and return originalErr below. + break + } + continue + } + + s.retireCurrentOverride() + s.mirrorOverride = &mirrorSource{client: fallbackEndpoint.client, ref: fallbackEndpoint.ref} + logrus.Debugf("Partial blob fetch succeeded from fallback source %q, switching to it for future requests", pullSource.Reference) + + return streams, errs, nil + } + return nil, nil, formatFallbackError(attempts, originalErr) } // GetSignaturesWithFormat returns the image's signatures. It may use a remote (= slow) service. diff --git a/vendor/go.podman.io/image/v5/version/version.go b/vendor/go.podman.io/image/v5/version/version.go index adb2667d4f..40852fed62 100644 --- a/vendor/go.podman.io/image/v5/version/version.go +++ b/vendor/go.podman.io/image/v5/version/version.go @@ -8,7 +8,7 @@ const ( // VersionMinor is for functionality in a backwards-compatible manner VersionMinor = 41 // VersionPatch is for backwards-compatible bug fixes - VersionPatch = 0 + VersionPatch = 1 // VersionDev indicates development branch. Releases will be empty string. VersionDev = "" diff --git a/vendor/golang.org/x/crypto/internal/poly1305/mac_noasm.go b/vendor/golang.org/x/crypto/internal/poly1305/mac_noasm.go index 8d99551fee..b1da45687c 100644 --- a/vendor/golang.org/x/crypto/internal/poly1305/mac_noasm.go +++ b/vendor/golang.org/x/crypto/internal/poly1305/mac_noasm.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build (!amd64 && !loong64 && !ppc64le && !ppc64 && !s390x) || !gc || purego +//go:build (!amd64 && !loong64 && !ppc64le && !ppc64 && !riscv64 && !s390x) || !gc || purego package poly1305 diff --git a/vendor/golang.org/x/crypto/internal/poly1305/sum_asm.go b/vendor/golang.org/x/crypto/internal/poly1305/sum_asm.go index 315b84ac39..55041bf51d 100644 --- a/vendor/golang.org/x/crypto/internal/poly1305/sum_asm.go +++ b/vendor/golang.org/x/crypto/internal/poly1305/sum_asm.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build gc && !purego && (amd64 || loong64 || ppc64 || ppc64le) +//go:build gc && !purego && (amd64 || loong64 || ppc64 || ppc64le || riscv64) package poly1305 diff --git a/vendor/golang.org/x/crypto/internal/poly1305/sum_riscv64.s b/vendor/golang.org/x/crypto/internal/poly1305/sum_riscv64.s new file mode 100644 index 0000000000..ce5eb3d43d --- /dev/null +++ b/vendor/golang.org/x/crypto/internal/poly1305/sum_riscv64.s @@ -0,0 +1,158 @@ +// Copyright 2026 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build gc && !purego + +#define LOAD64U(base, offset, t0, t1, t2, t3, dst) \ + MOVBU (offset+0*1)(base), t0; \ + MOVBU (offset+1*1)(base), t1; \ + MOVBU (offset+2*1)(base), t2; \ + MOVBU (offset+3*1)(base), t3; \ + SLL $8, t1; \ + SLL $16, t2; \ + SLL $24, t3; \ + OR t1, t0; \ + OR t3, t2; \ + OR t2, t0, dst; \ + MOVBU (offset+4*1)(base), t0; \ + MOVBU (offset+5*1)(base), t1; \ + MOVBU (offset+6*1)(base), t2; \ + MOVBU (offset+7*1)(base), t3; \ + SLL $32, t0; \ + SLL $40, t1; \ + SLL $48, t2; \ + SLL $56, t3; \ + OR t1, t0; \ + OR t3, t2; \ + OR t2, t0; \ + OR t0, dst + +// func update(state *macState, msg []byte) +TEXT ·update(SB), $0-32 + MOV state+0(FP), X5 + MOV msg_base+8(FP), X6 + MOV msg_len+16(FP), X7 + + MOV $16, X8 + + AND $7, X6, X28 + + MOV (0*8)(X5), X9 // h0 + MOV (1*8)(X5), X10 // h1 + MOV (2*8)(X5), X11 // h2 + MOV (3*8)(X5), X12 // r0 + MOV (4*8)(X5), X13 // r1 + + BLT X7, X8, tail + +loop: + BEQZ X28, aligned_load + + LOAD64U(X6, 0*8, X16, X18, X19, X20, X15) // msg[0:8] + LOAD64U(X6, 1*8, X16, X18, X19, X20, X17) // msg[8:16] + JMP block + +aligned_load: + MOV (0*8)(X6), X15 // msg[0:8] + MOV (1*8)(X6), X17 // msg[8:16] + +block: + ADD X15, X9 // h0 (x1 + y1 = z1', if z1' < x1 then z1' overflow) + SLTU X15, X9, X19 // h0.carry + ADD X17, X10, X22 + SLTU X17, X22, X23 + ADD X22, X19, X10 // h1 + SLTU X22, X10, X19 + OR X23, X19 // h1.carry + ADD $1, X19 + ADD X19, X11 // h2 + + ADD $16, X6 // msg = msg[16:] + +multiply: + MULHU X9, X12, X16 // h0r0.hi + MUL X9, X12, X15 // h0r0.lo + MULHU X10, X12, X17 // h1r0.hi + MUL X10, X12, X14 // h1r0.lo + ADD X14, X16 + SLTU X14, X16, X19 + ADD X19, X17 + MUL X11, X12, X20 + ADD X17, X20 + MULHU X9, X13, X17 // h0r1.hi + MUL X9, X13, X14 // h0r1.lo + ADD X14, X16 + SLTU X14, X16, X19 + ADD X19, X17 + MOV X17, X9 + MUL X11, X13, X21 // h2r1 + MULHU X10, X13, X17 // h1r1.hi + MUL X10, X13, X14 // h1r1.lo + ADD X14, X20 + ADD X17, X21, X22 + SLTU X14, X20, X19 + ADD X22, X19, X21 + ADD X9, X20 + SLTU X9, X20, X19 + ADD X19, X21 + AND $3, X20, X11 + AND $-4, X20, X18 + ADD X18, X15, X9 + ADD X21, X16, X22 + SLTU X18, X9, X19 + SLTU X21, X22, X23 + ADD X22, X19, X10 + SLTU X22, X10, X19 + OR X19, X23, X19 + ADD X19, X11 + SLL $62, X21, X22 + SRL $2, X20, X23 + SRL $2, X21, X21 + OR X22, X23, X20 + ADD X20, X9, X9 + ADD X21, X10, X22 + SLTU X20, X9, X19 + SLTU X21, X22, X23 + ADD X22, X19, X10 + SLTU X22, X10, X19 + OR X19, X23, X19 + ADD X19, X11, X11 + + SUB $16, X7, X7 + BGE X7, X8, loop + +tail: + BEQ X7, X0, done + MOV $1, X15 + MOV $0, X16 + ADD X7, X6, X6 + +flush_buffer: + MOVBU -1(X6), X20 + SRL $56, X15, X19 + SLL $8, X16, X23 + SLL $8, X15, X15 + OR X19, X23, X16 + XOR X20, X15 + SUB $1, X7, X7 + SUB $1, X6, X6 + BNE X7, X0, flush_buffer + + ADD X15, X9 + SLTU X15, X9, X19 + ADD X16, X10, X22 + SLTU X16, X22, X23 + ADD X22, X19, X10 + SLTU X22, X10, X19 + OR X23, X19 + ADD X19, X11 + + MOV $16, X7 + JMP multiply + +done: + MOV X9, (0*8)(X5) // h0 + MOV X10, (1*8)(X5) + MOV X11, (2*8)(X5) + RET diff --git a/vendor/golang.org/x/crypto/openpgp/armor/armor.go b/vendor/golang.org/x/crypto/openpgp/armor/armor.go deleted file mode 100644 index 453e4810c0..0000000000 --- a/vendor/golang.org/x/crypto/openpgp/armor/armor.go +++ /dev/null @@ -1,234 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package armor implements OpenPGP ASCII Armor, see RFC 4880. OpenPGP Armor is -// very similar to PEM except that it has an additional CRC checksum. -// -// Deprecated: this package is unsafe by design, and has numerous known security -// issues. It is not maintained, and should not be used. New applications should -// consider a more focused, modern alternative to OpenPGP for their specific -// task. If you are required to interoperate with OpenPGP systems and need a -// maintained package, consider github.com/ProtonMail/go-crypto/openpgp, which -// is a maintained fork that aims to be a drop-in replacement for this package. -package armor - -import ( - "bufio" - "bytes" - "encoding/base64" - "io" - - "golang.org/x/crypto/openpgp/errors" -) - -// A Block represents an OpenPGP armored structure. -// -// The encoded form is: -// -// -----BEGIN Type----- -// Headers -// -// base64-encoded Bytes -// '=' base64 encoded checksum -// -----END Type----- -// -// where Headers is a possibly empty sequence of Key: Value lines. -// -// Since the armored data can be very large, this package presents a streaming -// interface. -type Block struct { - Type string // The type, taken from the preamble (i.e. "PGP SIGNATURE"). - Header map[string]string // Optional headers. - Body io.Reader // A Reader from which the contents can be read - lReader lineReader - oReader openpgpReader -} - -var ArmorCorrupt error = errors.StructuralError("armor invalid") - -const crc24Init = 0xb704ce -const crc24Poly = 0x1864cfb -const crc24Mask = 0xffffff - -// crc24 calculates the OpenPGP checksum as specified in RFC 4880, section 6.1 -func crc24(crc uint32, d []byte) uint32 { - for _, b := range d { - crc ^= uint32(b) << 16 - for i := 0; i < 8; i++ { - crc <<= 1 - if crc&0x1000000 != 0 { - crc ^= crc24Poly - } - } - } - return crc -} - -var armorStart = []byte("-----BEGIN ") -var armorEnd = []byte("-----END ") -var armorEndOfLine = []byte("-----") - -// lineReader wraps a line based reader. It watches for the end of an armor -// block and records the expected CRC value. -type lineReader struct { - in *bufio.Reader - buf []byte - eof bool - crc uint32 - crcSet bool -} - -func (l *lineReader) Read(p []byte) (n int, err error) { - if l.eof { - return 0, io.EOF - } - - if len(l.buf) > 0 { - n = copy(p, l.buf) - l.buf = l.buf[n:] - return - } - - line, isPrefix, err := l.in.ReadLine() - if err != nil { - return - } - if isPrefix { - return 0, ArmorCorrupt - } - - if bytes.HasPrefix(line, armorEnd) { - l.eof = true - return 0, io.EOF - } - - if len(line) == 5 && line[0] == '=' { - // This is the checksum line - var expectedBytes [3]byte - var m int - m, err = base64.StdEncoding.Decode(expectedBytes[0:], line[1:]) - if m != 3 || err != nil { - return - } - l.crc = uint32(expectedBytes[0])<<16 | - uint32(expectedBytes[1])<<8 | - uint32(expectedBytes[2]) - - line, _, err = l.in.ReadLine() - if err != nil && err != io.EOF { - return - } - if !bytes.HasPrefix(line, armorEnd) { - return 0, ArmorCorrupt - } - - l.eof = true - l.crcSet = true - return 0, io.EOF - } - - if len(line) > 96 { - return 0, ArmorCorrupt - } - - n = copy(p, line) - bytesToSave := len(line) - n - if bytesToSave > 0 { - if cap(l.buf) < bytesToSave { - l.buf = make([]byte, 0, bytesToSave) - } - l.buf = l.buf[0:bytesToSave] - copy(l.buf, line[n:]) - } - - return -} - -// openpgpReader passes Read calls to the underlying base64 decoder, but keeps -// a running CRC of the resulting data and checks the CRC against the value -// found by the lineReader at EOF. -type openpgpReader struct { - lReader *lineReader - b64Reader io.Reader - currentCRC uint32 -} - -func (r *openpgpReader) Read(p []byte) (n int, err error) { - n, err = r.b64Reader.Read(p) - r.currentCRC = crc24(r.currentCRC, p[:n]) - - if err == io.EOF && r.lReader.crcSet && r.lReader.crc != r.currentCRC&crc24Mask { - return 0, ArmorCorrupt - } - - return -} - -// Decode reads a PGP armored block from the given Reader. It will ignore -// leading garbage. If it doesn't find a block, it will return nil, io.EOF. The -// given Reader is not usable after calling this function: an arbitrary amount -// of data may have been read past the end of the block. -func Decode(in io.Reader) (p *Block, err error) { - r := bufio.NewReaderSize(in, 100) - var line []byte - ignoreNext := false - -TryNextBlock: - p = nil - - // Skip leading garbage - for { - ignoreThis := ignoreNext - line, ignoreNext, err = r.ReadLine() - if err != nil { - return - } - if ignoreNext || ignoreThis { - continue - } - line = bytes.TrimSpace(line) - if len(line) > len(armorStart)+len(armorEndOfLine) && bytes.HasPrefix(line, armorStart) { - break - } - } - - p = new(Block) - p.Type = string(line[len(armorStart) : len(line)-len(armorEndOfLine)]) - p.Header = make(map[string]string) - nextIsContinuation := false - var lastKey string - - // Read headers - for { - isContinuation := nextIsContinuation - line, nextIsContinuation, err = r.ReadLine() - if err != nil { - p = nil - return - } - if isContinuation { - p.Header[lastKey] += string(line) - continue - } - line = bytes.TrimSpace(line) - if len(line) == 0 { - break - } - - i := bytes.Index(line, []byte(": ")) - if i == -1 { - goto TryNextBlock - } - lastKey = string(line[:i]) - p.Header[lastKey] = string(line[i+2:]) - } - - p.lReader.in = r - p.oReader.currentCRC = crc24Init - p.oReader.lReader = &p.lReader - p.oReader.b64Reader = base64.NewDecoder(base64.StdEncoding, &p.lReader) - p.Body = &p.oReader - - return -} diff --git a/vendor/golang.org/x/crypto/openpgp/armor/encode.go b/vendor/golang.org/x/crypto/openpgp/armor/encode.go deleted file mode 100644 index 5b6e16c19d..0000000000 --- a/vendor/golang.org/x/crypto/openpgp/armor/encode.go +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package armor - -import ( - "encoding/base64" - "io" -) - -var armorHeaderSep = []byte(": ") -var blockEnd = []byte("\n=") -var newline = []byte("\n") -var armorEndOfLineOut = []byte("-----\n") - -// writeSlices writes its arguments to the given Writer. -func writeSlices(out io.Writer, slices ...[]byte) (err error) { - for _, s := range slices { - _, err = out.Write(s) - if err != nil { - return err - } - } - return -} - -// lineBreaker breaks data across several lines, all of the same byte length -// (except possibly the last). Lines are broken with a single '\n'. -type lineBreaker struct { - lineLength int - line []byte - used int - out io.Writer - haveWritten bool -} - -func newLineBreaker(out io.Writer, lineLength int) *lineBreaker { - return &lineBreaker{ - lineLength: lineLength, - line: make([]byte, lineLength), - used: 0, - out: out, - } -} - -func (l *lineBreaker) Write(b []byte) (n int, err error) { - n = len(b) - - if n == 0 { - return - } - - if l.used == 0 && l.haveWritten { - _, err = l.out.Write([]byte{'\n'}) - if err != nil { - return - } - } - - if l.used+len(b) < l.lineLength { - l.used += copy(l.line[l.used:], b) - return - } - - l.haveWritten = true - _, err = l.out.Write(l.line[0:l.used]) - if err != nil { - return - } - excess := l.lineLength - l.used - l.used = 0 - - _, err = l.out.Write(b[0:excess]) - if err != nil { - return - } - - _, err = l.Write(b[excess:]) - return -} - -func (l *lineBreaker) Close() (err error) { - if l.used > 0 { - _, err = l.out.Write(l.line[0:l.used]) - if err != nil { - return - } - } - - return -} - -// encoding keeps track of a running CRC24 over the data which has been written -// to it and outputs a OpenPGP checksum when closed, followed by an armor -// trailer. -// -// It's built into a stack of io.Writers: -// -// encoding -> base64 encoder -> lineBreaker -> out -type encoding struct { - out io.Writer - breaker *lineBreaker - b64 io.WriteCloser - crc uint32 - blockType []byte -} - -func (e *encoding) Write(data []byte) (n int, err error) { - e.crc = crc24(e.crc, data) - return e.b64.Write(data) -} - -func (e *encoding) Close() (err error) { - err = e.b64.Close() - if err != nil { - return - } - e.breaker.Close() - - var checksumBytes [3]byte - checksumBytes[0] = byte(e.crc >> 16) - checksumBytes[1] = byte(e.crc >> 8) - checksumBytes[2] = byte(e.crc) - - var b64ChecksumBytes [4]byte - base64.StdEncoding.Encode(b64ChecksumBytes[:], checksumBytes[:]) - - return writeSlices(e.out, blockEnd, b64ChecksumBytes[:], newline, armorEnd, e.blockType, armorEndOfLine) -} - -// Encode returns a WriteCloser which will encode the data written to it in -// OpenPGP armor. -func Encode(out io.Writer, blockType string, headers map[string]string) (w io.WriteCloser, err error) { - bType := []byte(blockType) - err = writeSlices(out, armorStart, bType, armorEndOfLineOut) - if err != nil { - return - } - - for k, v := range headers { - err = writeSlices(out, []byte(k), armorHeaderSep, []byte(v), newline) - if err != nil { - return - } - } - - _, err = out.Write(newline) - if err != nil { - return - } - - e := &encoding{ - out: out, - breaker: newLineBreaker(out, 64), - crc: crc24Init, - blockType: bType, - } - e.b64 = base64.NewEncoder(base64.StdEncoding, e.breaker) - return e, nil -} diff --git a/vendor/golang.org/x/crypto/openpgp/canonical_text.go b/vendor/golang.org/x/crypto/openpgp/canonical_text.go deleted file mode 100644 index e601e389f1..0000000000 --- a/vendor/golang.org/x/crypto/openpgp/canonical_text.go +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package openpgp - -import "hash" - -// NewCanonicalTextHash reformats text written to it into the canonical -// form and then applies the hash h. See RFC 4880, section 5.2.1. -func NewCanonicalTextHash(h hash.Hash) hash.Hash { - return &canonicalTextHash{h, 0} -} - -type canonicalTextHash struct { - h hash.Hash - s int -} - -var newline = []byte{'\r', '\n'} - -func (cth *canonicalTextHash) Write(buf []byte) (int, error) { - start := 0 - - for i, c := range buf { - switch cth.s { - case 0: - if c == '\r' { - cth.s = 1 - } else if c == '\n' { - cth.h.Write(buf[start:i]) - cth.h.Write(newline) - start = i + 1 - } - case 1: - cth.s = 0 - } - } - - cth.h.Write(buf[start:]) - return len(buf), nil -} - -func (cth *canonicalTextHash) Sum(in []byte) []byte { - return cth.h.Sum(in) -} - -func (cth *canonicalTextHash) Reset() { - cth.h.Reset() - cth.s = 0 -} - -func (cth *canonicalTextHash) Size() int { - return cth.h.Size() -} - -func (cth *canonicalTextHash) BlockSize() int { - return cth.h.BlockSize() -} diff --git a/vendor/golang.org/x/crypto/openpgp/elgamal/elgamal.go b/vendor/golang.org/x/crypto/openpgp/elgamal/elgamal.go deleted file mode 100644 index f922bdbcaa..0000000000 --- a/vendor/golang.org/x/crypto/openpgp/elgamal/elgamal.go +++ /dev/null @@ -1,130 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package elgamal implements ElGamal encryption, suitable for OpenPGP, -// as specified in "A Public-Key Cryptosystem and a Signature Scheme Based on -// Discrete Logarithms," IEEE Transactions on Information Theory, v. IT-31, -// n. 4, 1985, pp. 469-472. -// -// This form of ElGamal embeds PKCS#1 v1.5 padding, which may make it -// unsuitable for other protocols. RSA should be used in preference in any -// case. -// -// Deprecated: this package was only provided to support ElGamal encryption in -// OpenPGP. The golang.org/x/crypto/openpgp package is now deprecated (see -// https://golang.org/issue/44226), and ElGamal in the OpenPGP ecosystem has -// compatibility and security issues (see https://eprint.iacr.org/2021/923). -// Moreover, this package doesn't protect against side-channel attacks. -package elgamal - -import ( - "crypto/rand" - "crypto/subtle" - "errors" - "io" - "math/big" -) - -// PublicKey represents an ElGamal public key. -type PublicKey struct { - G, P, Y *big.Int -} - -// PrivateKey represents an ElGamal private key. -type PrivateKey struct { - PublicKey - X *big.Int -} - -// Encrypt encrypts the given message to the given public key. The result is a -// pair of integers. Errors can result from reading random, or because msg is -// too large to be encrypted to the public key. -func Encrypt(random io.Reader, pub *PublicKey, msg []byte) (c1, c2 *big.Int, err error) { - pLen := (pub.P.BitLen() + 7) / 8 - if len(msg) > pLen-11 { - err = errors.New("elgamal: message too long") - return - } - - // EM = 0x02 || PS || 0x00 || M - em := make([]byte, pLen-1) - em[0] = 2 - ps, mm := em[1:len(em)-len(msg)-1], em[len(em)-len(msg):] - err = nonZeroRandomBytes(ps, random) - if err != nil { - return - } - em[len(em)-len(msg)-1] = 0 - copy(mm, msg) - - m := new(big.Int).SetBytes(em) - - k, err := rand.Int(random, pub.P) - if err != nil { - return - } - - c1 = new(big.Int).Exp(pub.G, k, pub.P) - s := new(big.Int).Exp(pub.Y, k, pub.P) - c2 = s.Mul(s, m) - c2.Mod(c2, pub.P) - - return -} - -// Decrypt takes two integers, resulting from an ElGamal encryption, and -// returns the plaintext of the message. An error can result only if the -// ciphertext is invalid. Users should keep in mind that this is a padding -// oracle and thus, if exposed to an adaptive chosen ciphertext attack, can -// be used to break the cryptosystem. See “Chosen Ciphertext Attacks -// Against Protocols Based on the RSA Encryption Standard PKCS #1”, Daniel -// Bleichenbacher, Advances in Cryptology (Crypto '98), -func Decrypt(priv *PrivateKey, c1, c2 *big.Int) (msg []byte, err error) { - s := new(big.Int).Exp(c1, priv.X, priv.P) - if s.ModInverse(s, priv.P) == nil { - return nil, errors.New("elgamal: invalid private key") - } - s.Mul(s, c2) - s.Mod(s, priv.P) - em := s.Bytes() - - firstByteIsTwo := subtle.ConstantTimeByteEq(em[0], 2) - - // The remainder of the plaintext must be a string of non-zero random - // octets, followed by a 0, followed by the message. - // lookingForIndex: 1 iff we are still looking for the zero. - // index: the offset of the first zero byte. - var lookingForIndex, index int - lookingForIndex = 1 - - for i := 1; i < len(em); i++ { - equals0 := subtle.ConstantTimeByteEq(em[i], 0) - index = subtle.ConstantTimeSelect(lookingForIndex&equals0, i, index) - lookingForIndex = subtle.ConstantTimeSelect(equals0, 0, lookingForIndex) - } - - if firstByteIsTwo != 1 || lookingForIndex != 0 || index < 9 { - return nil, errors.New("elgamal: decryption error") - } - return em[index+1:], nil -} - -// nonZeroRandomBytes fills the given slice with non-zero random octets. -func nonZeroRandomBytes(s []byte, rand io.Reader) (err error) { - _, err = io.ReadFull(rand, s) - if err != nil { - return - } - - for i := 0; i < len(s); i++ { - for s[i] == 0 { - _, err = io.ReadFull(rand, s[i:i+1]) - if err != nil { - return - } - } - } - - return -} diff --git a/vendor/golang.org/x/crypto/openpgp/errors/errors.go b/vendor/golang.org/x/crypto/openpgp/errors/errors.go deleted file mode 100644 index 2009e2acee..0000000000 --- a/vendor/golang.org/x/crypto/openpgp/errors/errors.go +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package errors contains common error types for the OpenPGP packages. -// -// Deprecated: this package is unsafe by design, and has numerous known security -// issues. It is not maintained, and should not be used. New applications should -// consider a more focused, modern alternative to OpenPGP for their specific -// task. If you are required to interoperate with OpenPGP systems and need a -// maintained package, consider github.com/ProtonMail/go-crypto/openpgp, which -// is a maintained fork that aims to be a drop-in replacement for this package. -package errors - -import ( - "strconv" -) - -// A StructuralError is returned when OpenPGP data is found to be syntactically -// invalid. -type StructuralError string - -func (s StructuralError) Error() string { - return "openpgp: invalid data: " + string(s) -} - -// UnsupportedError indicates that, although the OpenPGP data is valid, it -// makes use of currently unimplemented features. -type UnsupportedError string - -func (s UnsupportedError) Error() string { - return "openpgp: unsupported feature: " + string(s) -} - -// InvalidArgumentError indicates that the caller is in error and passed an -// incorrect value. -type InvalidArgumentError string - -func (i InvalidArgumentError) Error() string { - return "openpgp: invalid argument: " + string(i) -} - -// SignatureError indicates that a syntactically valid signature failed to -// validate. -type SignatureError string - -func (b SignatureError) Error() string { - return "openpgp: invalid signature: " + string(b) -} - -type keyIncorrectError int - -func (ki keyIncorrectError) Error() string { - return "openpgp: incorrect key" -} - -var ErrKeyIncorrect error = keyIncorrectError(0) - -type unknownIssuerError int - -func (unknownIssuerError) Error() string { - return "openpgp: signature made by unknown entity" -} - -var ErrUnknownIssuer error = unknownIssuerError(0) - -type keyRevokedError int - -func (keyRevokedError) Error() string { - return "openpgp: signature made by revoked key" -} - -var ErrKeyRevoked error = keyRevokedError(0) - -type UnknownPacketTypeError uint8 - -func (upte UnknownPacketTypeError) Error() string { - return "openpgp: unknown packet type: " + strconv.Itoa(int(upte)) -} diff --git a/vendor/golang.org/x/crypto/openpgp/keys.go b/vendor/golang.org/x/crypto/openpgp/keys.go deleted file mode 100644 index d62f787e9d..0000000000 --- a/vendor/golang.org/x/crypto/openpgp/keys.go +++ /dev/null @@ -1,693 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package openpgp - -import ( - "crypto/rsa" - "io" - "time" - - "golang.org/x/crypto/openpgp/armor" - "golang.org/x/crypto/openpgp/errors" - "golang.org/x/crypto/openpgp/packet" -) - -// PublicKeyType is the armor type for a PGP public key. -var PublicKeyType = "PGP PUBLIC KEY BLOCK" - -// PrivateKeyType is the armor type for a PGP private key. -var PrivateKeyType = "PGP PRIVATE KEY BLOCK" - -// An Entity represents the components of an OpenPGP key: a primary public key -// (which must be a signing key), one or more identities claimed by that key, -// and zero or more subkeys, which may be encryption keys. -type Entity struct { - PrimaryKey *packet.PublicKey - PrivateKey *packet.PrivateKey - Identities map[string]*Identity // indexed by Identity.Name - Revocations []*packet.Signature - Subkeys []Subkey -} - -// An Identity represents an identity claimed by an Entity and zero or more -// assertions by other entities about that claim. -type Identity struct { - Name string // by convention, has the form "Full Name (comment) " - UserId *packet.UserId - SelfSignature *packet.Signature - Signatures []*packet.Signature -} - -// A Subkey is an additional public key in an Entity. Subkeys can be used for -// encryption. -type Subkey struct { - PublicKey *packet.PublicKey - PrivateKey *packet.PrivateKey - Sig *packet.Signature -} - -// A Key identifies a specific public key in an Entity. This is either the -// Entity's primary key or a subkey. -type Key struct { - Entity *Entity - PublicKey *packet.PublicKey - PrivateKey *packet.PrivateKey - SelfSignature *packet.Signature -} - -// A KeyRing provides access to public and private keys. -type KeyRing interface { - // KeysById returns the set of keys that have the given key id. - KeysById(id uint64) []Key - // KeysByIdUsage returns the set of keys with the given id - // that also meet the key usage given by requiredUsage. - // The requiredUsage is expressed as the bitwise-OR of - // packet.KeyFlag* values. - KeysByIdUsage(id uint64, requiredUsage byte) []Key - // DecryptionKeys returns all private keys that are valid for - // decryption. - DecryptionKeys() []Key -} - -// primaryIdentity returns the Identity marked as primary or the first identity -// if none are so marked. -func (e *Entity) primaryIdentity() *Identity { - var firstIdentity *Identity - for _, ident := range e.Identities { - if firstIdentity == nil { - firstIdentity = ident - } - if ident.SelfSignature.IsPrimaryId != nil && *ident.SelfSignature.IsPrimaryId { - return ident - } - } - return firstIdentity -} - -// encryptionKey returns the best candidate Key for encrypting a message to the -// given Entity. -func (e *Entity) encryptionKey(now time.Time) (Key, bool) { - candidateSubkey := -1 - - // Iterate the keys to find the newest key - var maxTime time.Time - for i, subkey := range e.Subkeys { - if subkey.Sig.FlagsValid && - subkey.Sig.FlagEncryptCommunications && - subkey.PublicKey.PubKeyAlgo.CanEncrypt() && - !subkey.Sig.KeyExpired(now) && - (maxTime.IsZero() || subkey.Sig.CreationTime.After(maxTime)) { - candidateSubkey = i - maxTime = subkey.Sig.CreationTime - } - } - - if candidateSubkey != -1 { - subkey := e.Subkeys[candidateSubkey] - return Key{e, subkey.PublicKey, subkey.PrivateKey, subkey.Sig}, true - } - - // If we don't have any candidate subkeys for encryption and - // the primary key doesn't have any usage metadata then we - // assume that the primary key is ok. Or, if the primary key is - // marked as ok to encrypt to, then we can obviously use it. - i := e.primaryIdentity() - if !i.SelfSignature.FlagsValid || i.SelfSignature.FlagEncryptCommunications && - e.PrimaryKey.PubKeyAlgo.CanEncrypt() && - !i.SelfSignature.KeyExpired(now) { - return Key{e, e.PrimaryKey, e.PrivateKey, i.SelfSignature}, true - } - - // This Entity appears to be signing only. - return Key{}, false -} - -// signingKey return the best candidate Key for signing a message with this -// Entity. -func (e *Entity) signingKey(now time.Time) (Key, bool) { - candidateSubkey := -1 - - for i, subkey := range e.Subkeys { - if subkey.Sig.FlagsValid && - subkey.Sig.FlagSign && - subkey.PublicKey.PubKeyAlgo.CanSign() && - !subkey.Sig.KeyExpired(now) { - candidateSubkey = i - break - } - } - - if candidateSubkey != -1 { - subkey := e.Subkeys[candidateSubkey] - return Key{e, subkey.PublicKey, subkey.PrivateKey, subkey.Sig}, true - } - - // If we have no candidate subkey then we assume that it's ok to sign - // with the primary key. - i := e.primaryIdentity() - if !i.SelfSignature.FlagsValid || i.SelfSignature.FlagSign && - !i.SelfSignature.KeyExpired(now) { - return Key{e, e.PrimaryKey, e.PrivateKey, i.SelfSignature}, true - } - - return Key{}, false -} - -// An EntityList contains one or more Entities. -type EntityList []*Entity - -// KeysById returns the set of keys that have the given key id. -func (el EntityList) KeysById(id uint64) (keys []Key) { - for _, e := range el { - if e.PrimaryKey.KeyId == id { - var selfSig *packet.Signature - for _, ident := range e.Identities { - if selfSig == nil { - selfSig = ident.SelfSignature - } else if ident.SelfSignature.IsPrimaryId != nil && *ident.SelfSignature.IsPrimaryId { - selfSig = ident.SelfSignature - break - } - } - keys = append(keys, Key{e, e.PrimaryKey, e.PrivateKey, selfSig}) - } - - for _, subKey := range e.Subkeys { - if subKey.PublicKey.KeyId == id { - keys = append(keys, Key{e, subKey.PublicKey, subKey.PrivateKey, subKey.Sig}) - } - } - } - return -} - -// KeysByIdUsage returns the set of keys with the given id that also meet -// the key usage given by requiredUsage. The requiredUsage is expressed as -// the bitwise-OR of packet.KeyFlag* values. -func (el EntityList) KeysByIdUsage(id uint64, requiredUsage byte) (keys []Key) { - for _, key := range el.KeysById(id) { - if len(key.Entity.Revocations) > 0 { - continue - } - - if key.SelfSignature.RevocationReason != nil { - continue - } - - if key.SelfSignature.FlagsValid && requiredUsage != 0 { - var usage byte - if key.SelfSignature.FlagCertify { - usage |= packet.KeyFlagCertify - } - if key.SelfSignature.FlagSign { - usage |= packet.KeyFlagSign - } - if key.SelfSignature.FlagEncryptCommunications { - usage |= packet.KeyFlagEncryptCommunications - } - if key.SelfSignature.FlagEncryptStorage { - usage |= packet.KeyFlagEncryptStorage - } - if usage&requiredUsage != requiredUsage { - continue - } - } - - keys = append(keys, key) - } - return -} - -// DecryptionKeys returns all private keys that are valid for decryption. -func (el EntityList) DecryptionKeys() (keys []Key) { - for _, e := range el { - for _, subKey := range e.Subkeys { - if subKey.PrivateKey != nil && (!subKey.Sig.FlagsValid || subKey.Sig.FlagEncryptStorage || subKey.Sig.FlagEncryptCommunications) { - keys = append(keys, Key{e, subKey.PublicKey, subKey.PrivateKey, subKey.Sig}) - } - } - } - return -} - -// ReadArmoredKeyRing reads one or more public/private keys from an armor keyring file. -func ReadArmoredKeyRing(r io.Reader) (EntityList, error) { - block, err := armor.Decode(r) - if err == io.EOF { - return nil, errors.InvalidArgumentError("no armored data found") - } - if err != nil { - return nil, err - } - if block.Type != PublicKeyType && block.Type != PrivateKeyType { - return nil, errors.InvalidArgumentError("expected public or private key block, got: " + block.Type) - } - - return ReadKeyRing(block.Body) -} - -// ReadKeyRing reads one or more public/private keys. Unsupported keys are -// ignored as long as at least a single valid key is found. -func ReadKeyRing(r io.Reader) (el EntityList, err error) { - packets := packet.NewReader(r) - var lastUnsupportedError error - - for { - var e *Entity - e, err = ReadEntity(packets) - if err != nil { - // TODO: warn about skipped unsupported/unreadable keys - if _, ok := err.(errors.UnsupportedError); ok { - lastUnsupportedError = err - err = readToNextPublicKey(packets) - } else if _, ok := err.(errors.StructuralError); ok { - // Skip unreadable, badly-formatted keys - lastUnsupportedError = err - err = readToNextPublicKey(packets) - } - if err == io.EOF { - err = nil - break - } - if err != nil { - el = nil - break - } - } else { - el = append(el, e) - } - } - - if len(el) == 0 && err == nil { - err = lastUnsupportedError - } - return -} - -// readToNextPublicKey reads packets until the start of the entity and leaves -// the first packet of the new entity in the Reader. -func readToNextPublicKey(packets *packet.Reader) (err error) { - var p packet.Packet - for { - p, err = packets.Next() - if err == io.EOF { - return - } else if err != nil { - if _, ok := err.(errors.UnsupportedError); ok { - err = nil - continue - } - return - } - - if pk, ok := p.(*packet.PublicKey); ok && !pk.IsSubkey { - packets.Unread(p) - return - } - } -} - -// ReadEntity reads an entity (public key, identities, subkeys etc) from the -// given Reader. -func ReadEntity(packets *packet.Reader) (*Entity, error) { - e := new(Entity) - e.Identities = make(map[string]*Identity) - - p, err := packets.Next() - if err != nil { - return nil, err - } - - var ok bool - if e.PrimaryKey, ok = p.(*packet.PublicKey); !ok { - if e.PrivateKey, ok = p.(*packet.PrivateKey); !ok { - packets.Unread(p) - return nil, errors.StructuralError("first packet was not a public/private key") - } - e.PrimaryKey = &e.PrivateKey.PublicKey - } - - if !e.PrimaryKey.PubKeyAlgo.CanSign() { - return nil, errors.StructuralError("primary key cannot be used for signatures") - } - - var revocations []*packet.Signature -EachPacket: - for { - p, err := packets.Next() - if err == io.EOF { - break - } else if err != nil { - return nil, err - } - - switch pkt := p.(type) { - case *packet.UserId: - if err := addUserID(e, packets, pkt); err != nil { - return nil, err - } - case *packet.Signature: - if pkt.SigType == packet.SigTypeKeyRevocation { - revocations = append(revocations, pkt) - } else if pkt.SigType == packet.SigTypeDirectSignature { - // TODO: RFC4880 5.2.1 permits signatures - // directly on keys (eg. to bind additional - // revocation keys). - } - // Else, ignoring the signature as it does not follow anything - // we would know to attach it to. - case *packet.PrivateKey: - if pkt.IsSubkey == false { - packets.Unread(p) - break EachPacket - } - err = addSubkey(e, packets, &pkt.PublicKey, pkt) - if err != nil { - return nil, err - } - case *packet.PublicKey: - if pkt.IsSubkey == false { - packets.Unread(p) - break EachPacket - } - err = addSubkey(e, packets, pkt, nil) - if err != nil { - return nil, err - } - default: - // we ignore unknown packets - } - } - - if len(e.Identities) == 0 { - return nil, errors.StructuralError("entity without any identities") - } - - for _, revocation := range revocations { - err = e.PrimaryKey.VerifyRevocationSignature(revocation) - if err == nil { - e.Revocations = append(e.Revocations, revocation) - } else { - // TODO: RFC 4880 5.2.3.15 defines revocation keys. - return nil, errors.StructuralError("revocation signature signed by alternate key") - } - } - - return e, nil -} - -func addUserID(e *Entity, packets *packet.Reader, pkt *packet.UserId) error { - // Make a new Identity object, that we might wind up throwing away. - // We'll only add it if we get a valid self-signature over this - // userID. - identity := new(Identity) - identity.Name = pkt.Id - identity.UserId = pkt - - for { - p, err := packets.Next() - if err == io.EOF { - break - } else if err != nil { - return err - } - - sig, ok := p.(*packet.Signature) - if !ok { - packets.Unread(p) - break - } - - if (sig.SigType == packet.SigTypePositiveCert || sig.SigType == packet.SigTypeGenericCert) && sig.IssuerKeyId != nil && *sig.IssuerKeyId == e.PrimaryKey.KeyId { - if err = e.PrimaryKey.VerifyUserIdSignature(pkt.Id, e.PrimaryKey, sig); err != nil { - return errors.StructuralError("user ID self-signature invalid: " + err.Error()) - } - identity.SelfSignature = sig - e.Identities[pkt.Id] = identity - } else { - identity.Signatures = append(identity.Signatures, sig) - } - } - - return nil -} - -func addSubkey(e *Entity, packets *packet.Reader, pub *packet.PublicKey, priv *packet.PrivateKey) error { - var subKey Subkey - subKey.PublicKey = pub - subKey.PrivateKey = priv - - for { - p, err := packets.Next() - if err == io.EOF { - break - } else if err != nil { - return errors.StructuralError("subkey signature invalid: " + err.Error()) - } - - sig, ok := p.(*packet.Signature) - if !ok { - packets.Unread(p) - break - } - - if sig.SigType != packet.SigTypeSubkeyBinding && sig.SigType != packet.SigTypeSubkeyRevocation { - return errors.StructuralError("subkey signature with wrong type") - } - - if err := e.PrimaryKey.VerifyKeySignature(subKey.PublicKey, sig); err != nil { - return errors.StructuralError("subkey signature invalid: " + err.Error()) - } - - switch sig.SigType { - case packet.SigTypeSubkeyRevocation: - subKey.Sig = sig - case packet.SigTypeSubkeyBinding: - - if shouldReplaceSubkeySig(subKey.Sig, sig) { - subKey.Sig = sig - } - } - } - - if subKey.Sig == nil { - return errors.StructuralError("subkey packet not followed by signature") - } - - e.Subkeys = append(e.Subkeys, subKey) - - return nil -} - -func shouldReplaceSubkeySig(existingSig, potentialNewSig *packet.Signature) bool { - if potentialNewSig == nil { - return false - } - - if existingSig == nil { - return true - } - - if existingSig.SigType == packet.SigTypeSubkeyRevocation { - return false // never override a revocation signature - } - - return potentialNewSig.CreationTime.After(existingSig.CreationTime) -} - -const defaultRSAKeyBits = 2048 - -// NewEntity returns an Entity that contains a fresh RSA/RSA keypair with a -// single identity composed of the given full name, comment and email, any of -// which may be empty but must not contain any of "()<>\x00". -// If config is nil, sensible defaults will be used. -func NewEntity(name, comment, email string, config *packet.Config) (*Entity, error) { - creationTime := config.Now() - - bits := defaultRSAKeyBits - if config != nil && config.RSABits != 0 { - bits = config.RSABits - } - - uid := packet.NewUserId(name, comment, email) - if uid == nil { - return nil, errors.InvalidArgumentError("user id field contained invalid characters") - } - signingPriv, err := rsa.GenerateKey(config.Random(), bits) - if err != nil { - return nil, err - } - encryptingPriv, err := rsa.GenerateKey(config.Random(), bits) - if err != nil { - return nil, err - } - - e := &Entity{ - PrimaryKey: packet.NewRSAPublicKey(creationTime, &signingPriv.PublicKey), - PrivateKey: packet.NewRSAPrivateKey(creationTime, signingPriv), - Identities: make(map[string]*Identity), - } - isPrimaryId := true - e.Identities[uid.Id] = &Identity{ - Name: uid.Id, - UserId: uid, - SelfSignature: &packet.Signature{ - CreationTime: creationTime, - SigType: packet.SigTypePositiveCert, - PubKeyAlgo: packet.PubKeyAlgoRSA, - Hash: config.Hash(), - IsPrimaryId: &isPrimaryId, - FlagsValid: true, - FlagSign: true, - FlagCertify: true, - IssuerKeyId: &e.PrimaryKey.KeyId, - }, - } - err = e.Identities[uid.Id].SelfSignature.SignUserId(uid.Id, e.PrimaryKey, e.PrivateKey, config) - if err != nil { - return nil, err - } - - // If the user passes in a DefaultHash via packet.Config, - // set the PreferredHash for the SelfSignature. - if config != nil && config.DefaultHash != 0 { - e.Identities[uid.Id].SelfSignature.PreferredHash = []uint8{hashToHashId(config.DefaultHash)} - } - - // Likewise for DefaultCipher. - if config != nil && config.DefaultCipher != 0 { - e.Identities[uid.Id].SelfSignature.PreferredSymmetric = []uint8{uint8(config.DefaultCipher)} - } - - e.Subkeys = make([]Subkey, 1) - e.Subkeys[0] = Subkey{ - PublicKey: packet.NewRSAPublicKey(creationTime, &encryptingPriv.PublicKey), - PrivateKey: packet.NewRSAPrivateKey(creationTime, encryptingPriv), - Sig: &packet.Signature{ - CreationTime: creationTime, - SigType: packet.SigTypeSubkeyBinding, - PubKeyAlgo: packet.PubKeyAlgoRSA, - Hash: config.Hash(), - FlagsValid: true, - FlagEncryptStorage: true, - FlagEncryptCommunications: true, - IssuerKeyId: &e.PrimaryKey.KeyId, - }, - } - e.Subkeys[0].PublicKey.IsSubkey = true - e.Subkeys[0].PrivateKey.IsSubkey = true - err = e.Subkeys[0].Sig.SignKey(e.Subkeys[0].PublicKey, e.PrivateKey, config) - if err != nil { - return nil, err - } - return e, nil -} - -// SerializePrivate serializes an Entity, including private key material, but -// excluding signatures from other entities, to the given Writer. -// Identities and subkeys are re-signed in case they changed since NewEntry. -// If config is nil, sensible defaults will be used. -func (e *Entity) SerializePrivate(w io.Writer, config *packet.Config) (err error) { - err = e.PrivateKey.Serialize(w) - if err != nil { - return - } - for _, ident := range e.Identities { - err = ident.UserId.Serialize(w) - if err != nil { - return - } - err = ident.SelfSignature.SignUserId(ident.UserId.Id, e.PrimaryKey, e.PrivateKey, config) - if err != nil { - return - } - err = ident.SelfSignature.Serialize(w) - if err != nil { - return - } - } - for _, subkey := range e.Subkeys { - err = subkey.PrivateKey.Serialize(w) - if err != nil { - return - } - err = subkey.Sig.SignKey(subkey.PublicKey, e.PrivateKey, config) - if err != nil { - return - } - err = subkey.Sig.Serialize(w) - if err != nil { - return - } - } - return nil -} - -// Serialize writes the public part of the given Entity to w, including -// signatures from other entities. No private key material will be output. -func (e *Entity) Serialize(w io.Writer) error { - err := e.PrimaryKey.Serialize(w) - if err != nil { - return err - } - for _, ident := range e.Identities { - err = ident.UserId.Serialize(w) - if err != nil { - return err - } - err = ident.SelfSignature.Serialize(w) - if err != nil { - return err - } - for _, sig := range ident.Signatures { - err = sig.Serialize(w) - if err != nil { - return err - } - } - } - for _, subkey := range e.Subkeys { - err = subkey.PublicKey.Serialize(w) - if err != nil { - return err - } - err = subkey.Sig.Serialize(w) - if err != nil { - return err - } - } - return nil -} - -// SignIdentity adds a signature to e, from signer, attesting that identity is -// associated with e. The provided identity must already be an element of -// e.Identities and the private key of signer must have been decrypted if -// necessary. -// If config is nil, sensible defaults will be used. -func (e *Entity) SignIdentity(identity string, signer *Entity, config *packet.Config) error { - if signer.PrivateKey == nil { - return errors.InvalidArgumentError("signing Entity must have a private key") - } - if signer.PrivateKey.Encrypted { - return errors.InvalidArgumentError("signing Entity's private key must be decrypted") - } - ident, ok := e.Identities[identity] - if !ok { - return errors.InvalidArgumentError("given identity string not found in Entity") - } - - sig := &packet.Signature{ - SigType: packet.SigTypeGenericCert, - PubKeyAlgo: signer.PrivateKey.PubKeyAlgo, - Hash: config.Hash(), - CreationTime: config.Now(), - IssuerKeyId: &signer.PrivateKey.KeyId, - } - if err := sig.SignUserId(identity, e.PrimaryKey, signer.PrivateKey, config); err != nil { - return err - } - ident.Signatures = append(ident.Signatures, sig) - return nil -} diff --git a/vendor/golang.org/x/crypto/openpgp/packet/compressed.go b/vendor/golang.org/x/crypto/openpgp/packet/compressed.go deleted file mode 100644 index 353f945247..0000000000 --- a/vendor/golang.org/x/crypto/openpgp/packet/compressed.go +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package packet - -import ( - "compress/bzip2" - "compress/flate" - "compress/zlib" - "golang.org/x/crypto/openpgp/errors" - "io" - "strconv" -) - -// Compressed represents a compressed OpenPGP packet. The decompressed contents -// will contain more OpenPGP packets. See RFC 4880, section 5.6. -type Compressed struct { - Body io.Reader -} - -const ( - NoCompression = flate.NoCompression - BestSpeed = flate.BestSpeed - BestCompression = flate.BestCompression - DefaultCompression = flate.DefaultCompression -) - -// CompressionConfig contains compressor configuration settings. -type CompressionConfig struct { - // Level is the compression level to use. It must be set to - // between -1 and 9, with -1 causing the compressor to use the - // default compression level, 0 causing the compressor to use - // no compression and 1 to 9 representing increasing (better, - // slower) compression levels. If Level is less than -1 or - // more then 9, a non-nil error will be returned during - // encryption. See the constants above for convenient common - // settings for Level. - Level int -} - -func (c *Compressed) parse(r io.Reader) error { - var buf [1]byte - _, err := readFull(r, buf[:]) - if err != nil { - return err - } - - switch buf[0] { - case 1: - c.Body = flate.NewReader(r) - case 2: - c.Body, err = zlib.NewReader(r) - case 3: - c.Body = bzip2.NewReader(r) - default: - err = errors.UnsupportedError("unknown compression algorithm: " + strconv.Itoa(int(buf[0]))) - } - - return err -} - -// compressedWriteCloser represents the serialized compression stream -// header and the compressor. Its Close() method ensures that both the -// compressor and serialized stream header are closed. Its Write() -// method writes to the compressor. -type compressedWriteCloser struct { - sh io.Closer // Stream Header - c io.WriteCloser // Compressor -} - -func (cwc compressedWriteCloser) Write(p []byte) (int, error) { - return cwc.c.Write(p) -} - -func (cwc compressedWriteCloser) Close() (err error) { - err = cwc.c.Close() - if err != nil { - return err - } - - return cwc.sh.Close() -} - -// SerializeCompressed serializes a compressed data packet to w and -// returns a WriteCloser to which the literal data packets themselves -// can be written and which MUST be closed on completion. If cc is -// nil, sensible defaults will be used to configure the compression -// algorithm. -func SerializeCompressed(w io.WriteCloser, algo CompressionAlgo, cc *CompressionConfig) (literaldata io.WriteCloser, err error) { - compressed, err := serializeStreamHeader(w, packetTypeCompressed) - if err != nil { - return - } - - _, err = compressed.Write([]byte{uint8(algo)}) - if err != nil { - return - } - - level := DefaultCompression - if cc != nil { - level = cc.Level - } - - var compressor io.WriteCloser - switch algo { - case CompressionZIP: - compressor, err = flate.NewWriter(compressed, level) - case CompressionZLIB: - compressor, err = zlib.NewWriterLevel(compressed, level) - default: - s := strconv.Itoa(int(algo)) - err = errors.UnsupportedError("Unsupported compression algorithm: " + s) - } - if err != nil { - return - } - - literaldata = compressedWriteCloser{compressed, compressor} - - return -} diff --git a/vendor/golang.org/x/crypto/openpgp/packet/config.go b/vendor/golang.org/x/crypto/openpgp/packet/config.go deleted file mode 100644 index c76eecc963..0000000000 --- a/vendor/golang.org/x/crypto/openpgp/packet/config.go +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package packet - -import ( - "crypto" - "crypto/rand" - "io" - "time" -) - -// Config collects a number of parameters along with sensible defaults. -// A nil *Config is valid and results in all default values. -type Config struct { - // Rand provides the source of entropy. - // If nil, the crypto/rand Reader is used. - Rand io.Reader - // DefaultHash is the default hash function to be used. - // If zero, SHA-256 is used. - DefaultHash crypto.Hash - // DefaultCipher is the cipher to be used. - // If zero, AES-128 is used. - DefaultCipher CipherFunction - // Time returns the current time as the number of seconds since the - // epoch. If Time is nil, time.Now is used. - Time func() time.Time - // DefaultCompressionAlgo is the compression algorithm to be - // applied to the plaintext before encryption. If zero, no - // compression is done. - DefaultCompressionAlgo CompressionAlgo - // CompressionConfig configures the compression settings. - CompressionConfig *CompressionConfig - // S2KCount is only used for symmetric encryption. It - // determines the strength of the passphrase stretching when - // the said passphrase is hashed to produce a key. S2KCount - // should be between 1024 and 65011712, inclusive. If Config - // is nil or S2KCount is 0, the value 65536 used. Not all - // values in the above range can be represented. S2KCount will - // be rounded up to the next representable value if it cannot - // be encoded exactly. When set, it is strongly encrouraged to - // use a value that is at least 65536. See RFC 4880 Section - // 3.7.1.3. - S2KCount int - // RSABits is the number of bits in new RSA keys made with NewEntity. - // If zero, then 2048 bit keys are created. - RSABits int -} - -func (c *Config) Random() io.Reader { - if c == nil || c.Rand == nil { - return rand.Reader - } - return c.Rand -} - -func (c *Config) Hash() crypto.Hash { - if c == nil || uint(c.DefaultHash) == 0 { - return crypto.SHA256 - } - return c.DefaultHash -} - -func (c *Config) Cipher() CipherFunction { - if c == nil || uint8(c.DefaultCipher) == 0 { - return CipherAES128 - } - return c.DefaultCipher -} - -func (c *Config) Now() time.Time { - if c == nil || c.Time == nil { - return time.Now() - } - return c.Time() -} - -func (c *Config) Compression() CompressionAlgo { - if c == nil { - return CompressionNone - } - return c.DefaultCompressionAlgo -} - -func (c *Config) PasswordHashIterations() int { - if c == nil || c.S2KCount == 0 { - return 0 - } - return c.S2KCount -} diff --git a/vendor/golang.org/x/crypto/openpgp/packet/encrypted_key.go b/vendor/golang.org/x/crypto/openpgp/packet/encrypted_key.go deleted file mode 100644 index 6d7639722c..0000000000 --- a/vendor/golang.org/x/crypto/openpgp/packet/encrypted_key.go +++ /dev/null @@ -1,208 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package packet - -import ( - "crypto" - "crypto/rsa" - "encoding/binary" - "io" - "math/big" - "strconv" - - "golang.org/x/crypto/openpgp/elgamal" - "golang.org/x/crypto/openpgp/errors" -) - -const encryptedKeyVersion = 3 - -// EncryptedKey represents a public-key encrypted session key. See RFC 4880, -// section 5.1. -type EncryptedKey struct { - KeyId uint64 - Algo PublicKeyAlgorithm - CipherFunc CipherFunction // only valid after a successful Decrypt - Key []byte // only valid after a successful Decrypt - - encryptedMPI1, encryptedMPI2 parsedMPI -} - -func (e *EncryptedKey) parse(r io.Reader) (err error) { - var buf [10]byte - _, err = readFull(r, buf[:]) - if err != nil { - return - } - if buf[0] != encryptedKeyVersion { - return errors.UnsupportedError("unknown EncryptedKey version " + strconv.Itoa(int(buf[0]))) - } - e.KeyId = binary.BigEndian.Uint64(buf[1:9]) - e.Algo = PublicKeyAlgorithm(buf[9]) - switch e.Algo { - case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly: - e.encryptedMPI1.bytes, e.encryptedMPI1.bitLength, err = readMPI(r) - if err != nil { - return - } - case PubKeyAlgoElGamal: - e.encryptedMPI1.bytes, e.encryptedMPI1.bitLength, err = readMPI(r) - if err != nil { - return - } - e.encryptedMPI2.bytes, e.encryptedMPI2.bitLength, err = readMPI(r) - if err != nil { - return - } - } - _, err = consumeAll(r) - return -} - -func checksumKeyMaterial(key []byte) uint16 { - var checksum uint16 - for _, v := range key { - checksum += uint16(v) - } - return checksum -} - -// Decrypt decrypts an encrypted session key with the given private key. The -// private key must have been decrypted first. -// If config is nil, sensible defaults will be used. -func (e *EncryptedKey) Decrypt(priv *PrivateKey, config *Config) error { - var err error - var b []byte - - // TODO(agl): use session key decryption routines here to avoid - // padding oracle attacks. - switch priv.PubKeyAlgo { - case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly: - // Supports both *rsa.PrivateKey and crypto.Decrypter - k := priv.PrivateKey.(crypto.Decrypter) - b, err = k.Decrypt(config.Random(), padToKeySize(k.Public().(*rsa.PublicKey), e.encryptedMPI1.bytes), nil) - case PubKeyAlgoElGamal: - c1 := new(big.Int).SetBytes(e.encryptedMPI1.bytes) - c2 := new(big.Int).SetBytes(e.encryptedMPI2.bytes) - b, err = elgamal.Decrypt(priv.PrivateKey.(*elgamal.PrivateKey), c1, c2) - default: - err = errors.InvalidArgumentError("cannot decrypted encrypted session key with private key of type " + strconv.Itoa(int(priv.PubKeyAlgo))) - } - - if err != nil { - return err - } - - e.CipherFunc = CipherFunction(b[0]) - e.Key = b[1 : len(b)-2] - expectedChecksum := uint16(b[len(b)-2])<<8 | uint16(b[len(b)-1]) - checksum := checksumKeyMaterial(e.Key) - if checksum != expectedChecksum { - return errors.StructuralError("EncryptedKey checksum incorrect") - } - - return nil -} - -// Serialize writes the encrypted key packet, e, to w. -func (e *EncryptedKey) Serialize(w io.Writer) error { - var mpiLen int - switch e.Algo { - case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly: - mpiLen = 2 + len(e.encryptedMPI1.bytes) - case PubKeyAlgoElGamal: - mpiLen = 2 + len(e.encryptedMPI1.bytes) + 2 + len(e.encryptedMPI2.bytes) - default: - return errors.InvalidArgumentError("don't know how to serialize encrypted key type " + strconv.Itoa(int(e.Algo))) - } - - serializeHeader(w, packetTypeEncryptedKey, 1 /* version */ +8 /* key id */ +1 /* algo */ +mpiLen) - - w.Write([]byte{encryptedKeyVersion}) - binary.Write(w, binary.BigEndian, e.KeyId) - w.Write([]byte{byte(e.Algo)}) - - switch e.Algo { - case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly: - writeMPIs(w, e.encryptedMPI1) - case PubKeyAlgoElGamal: - writeMPIs(w, e.encryptedMPI1, e.encryptedMPI2) - default: - panic("internal error") - } - - return nil -} - -// SerializeEncryptedKey serializes an encrypted key packet to w that contains -// key, encrypted to pub. -// If config is nil, sensible defaults will be used. -func SerializeEncryptedKey(w io.Writer, pub *PublicKey, cipherFunc CipherFunction, key []byte, config *Config) error { - var buf [10]byte - buf[0] = encryptedKeyVersion - binary.BigEndian.PutUint64(buf[1:9], pub.KeyId) - buf[9] = byte(pub.PubKeyAlgo) - - keyBlock := make([]byte, 1 /* cipher type */ +len(key)+2 /* checksum */) - keyBlock[0] = byte(cipherFunc) - copy(keyBlock[1:], key) - checksum := checksumKeyMaterial(key) - keyBlock[1+len(key)] = byte(checksum >> 8) - keyBlock[1+len(key)+1] = byte(checksum) - - switch pub.PubKeyAlgo { - case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly: - return serializeEncryptedKeyRSA(w, config.Random(), buf, pub.PublicKey.(*rsa.PublicKey), keyBlock) - case PubKeyAlgoElGamal: - return serializeEncryptedKeyElGamal(w, config.Random(), buf, pub.PublicKey.(*elgamal.PublicKey), keyBlock) - case PubKeyAlgoDSA, PubKeyAlgoRSASignOnly: - return errors.InvalidArgumentError("cannot encrypt to public key of type " + strconv.Itoa(int(pub.PubKeyAlgo))) - } - - return errors.UnsupportedError("encrypting a key to public key of type " + strconv.Itoa(int(pub.PubKeyAlgo))) -} - -func serializeEncryptedKeyRSA(w io.Writer, rand io.Reader, header [10]byte, pub *rsa.PublicKey, keyBlock []byte) error { - cipherText, err := rsa.EncryptPKCS1v15(rand, pub, keyBlock) - if err != nil { - return errors.InvalidArgumentError("RSA encryption failed: " + err.Error()) - } - - packetLen := 10 /* header length */ + 2 /* mpi size */ + len(cipherText) - - err = serializeHeader(w, packetTypeEncryptedKey, packetLen) - if err != nil { - return err - } - _, err = w.Write(header[:]) - if err != nil { - return err - } - return writeMPI(w, 8*uint16(len(cipherText)), cipherText) -} - -func serializeEncryptedKeyElGamal(w io.Writer, rand io.Reader, header [10]byte, pub *elgamal.PublicKey, keyBlock []byte) error { - c1, c2, err := elgamal.Encrypt(rand, pub, keyBlock) - if err != nil { - return errors.InvalidArgumentError("ElGamal encryption failed: " + err.Error()) - } - - packetLen := 10 /* header length */ - packetLen += 2 /* mpi size */ + (c1.BitLen()+7)/8 - packetLen += 2 /* mpi size */ + (c2.BitLen()+7)/8 - - err = serializeHeader(w, packetTypeEncryptedKey, packetLen) - if err != nil { - return err - } - _, err = w.Write(header[:]) - if err != nil { - return err - } - err = writeBig(w, c1) - if err != nil { - return err - } - return writeBig(w, c2) -} diff --git a/vendor/golang.org/x/crypto/openpgp/packet/literal.go b/vendor/golang.org/x/crypto/openpgp/packet/literal.go deleted file mode 100644 index 1a9ec6e51e..0000000000 --- a/vendor/golang.org/x/crypto/openpgp/packet/literal.go +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package packet - -import ( - "encoding/binary" - "io" -) - -// LiteralData represents an encrypted file. See RFC 4880, section 5.9. -type LiteralData struct { - IsBinary bool - FileName string - Time uint32 // Unix epoch time. Either creation time or modification time. 0 means undefined. - Body io.Reader -} - -// ForEyesOnly returns whether the contents of the LiteralData have been marked -// as especially sensitive. -func (l *LiteralData) ForEyesOnly() bool { - return l.FileName == "_CONSOLE" -} - -func (l *LiteralData) parse(r io.Reader) (err error) { - var buf [256]byte - - _, err = readFull(r, buf[:2]) - if err != nil { - return - } - - l.IsBinary = buf[0] == 'b' - fileNameLen := int(buf[1]) - - _, err = readFull(r, buf[:fileNameLen]) - if err != nil { - return - } - - l.FileName = string(buf[:fileNameLen]) - - _, err = readFull(r, buf[:4]) - if err != nil { - return - } - - l.Time = binary.BigEndian.Uint32(buf[:4]) - l.Body = r - return -} - -// SerializeLiteral serializes a literal data packet to w and returns a -// WriteCloser to which the data itself can be written and which MUST be closed -// on completion. The fileName is truncated to 255 bytes. -func SerializeLiteral(w io.WriteCloser, isBinary bool, fileName string, time uint32) (plaintext io.WriteCloser, err error) { - var buf [4]byte - buf[0] = 't' - if isBinary { - buf[0] = 'b' - } - if len(fileName) > 255 { - fileName = fileName[:255] - } - buf[1] = byte(len(fileName)) - - inner, err := serializeStreamHeader(w, packetTypeLiteralData) - if err != nil { - return - } - - _, err = inner.Write(buf[:2]) - if err != nil { - return - } - _, err = inner.Write([]byte(fileName)) - if err != nil { - return - } - binary.BigEndian.PutUint32(buf[:], time) - _, err = inner.Write(buf[:]) - if err != nil { - return - } - - plaintext = inner - return -} diff --git a/vendor/golang.org/x/crypto/openpgp/packet/ocfb.go b/vendor/golang.org/x/crypto/openpgp/packet/ocfb.go deleted file mode 100644 index ce2a33a547..0000000000 --- a/vendor/golang.org/x/crypto/openpgp/packet/ocfb.go +++ /dev/null @@ -1,143 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// OpenPGP CFB Mode. http://tools.ietf.org/html/rfc4880#section-13.9 - -package packet - -import ( - "crypto/cipher" -) - -type ocfbEncrypter struct { - b cipher.Block - fre []byte - outUsed int -} - -// An OCFBResyncOption determines if the "resynchronization step" of OCFB is -// performed. -type OCFBResyncOption bool - -const ( - OCFBResync OCFBResyncOption = true - OCFBNoResync OCFBResyncOption = false -) - -// NewOCFBEncrypter returns a cipher.Stream which encrypts data with OpenPGP's -// cipher feedback mode using the given cipher.Block, and an initial amount of -// ciphertext. randData must be random bytes and be the same length as the -// cipher.Block's block size. Resync determines if the "resynchronization step" -// from RFC 4880, 13.9 step 7 is performed. Different parts of OpenPGP vary on -// this point. -func NewOCFBEncrypter(block cipher.Block, randData []byte, resync OCFBResyncOption) (cipher.Stream, []byte) { - blockSize := block.BlockSize() - if len(randData) != blockSize { - return nil, nil - } - - x := &ocfbEncrypter{ - b: block, - fre: make([]byte, blockSize), - outUsed: 0, - } - prefix := make([]byte, blockSize+2) - - block.Encrypt(x.fre, x.fre) - for i := 0; i < blockSize; i++ { - prefix[i] = randData[i] ^ x.fre[i] - } - - block.Encrypt(x.fre, prefix[:blockSize]) - prefix[blockSize] = x.fre[0] ^ randData[blockSize-2] - prefix[blockSize+1] = x.fre[1] ^ randData[blockSize-1] - - if resync { - block.Encrypt(x.fre, prefix[2:]) - } else { - x.fre[0] = prefix[blockSize] - x.fre[1] = prefix[blockSize+1] - x.outUsed = 2 - } - return x, prefix -} - -func (x *ocfbEncrypter) XORKeyStream(dst, src []byte) { - for i := 0; i < len(src); i++ { - if x.outUsed == len(x.fre) { - x.b.Encrypt(x.fre, x.fre) - x.outUsed = 0 - } - - x.fre[x.outUsed] ^= src[i] - dst[i] = x.fre[x.outUsed] - x.outUsed++ - } -} - -type ocfbDecrypter struct { - b cipher.Block - fre []byte - outUsed int -} - -// NewOCFBDecrypter returns a cipher.Stream which decrypts data with OpenPGP's -// cipher feedback mode using the given cipher.Block. Prefix must be the first -// blockSize + 2 bytes of the ciphertext, where blockSize is the cipher.Block's -// block size. If an incorrect key is detected then nil is returned. On -// successful exit, blockSize+2 bytes of decrypted data are written into -// prefix. Resync determines if the "resynchronization step" from RFC 4880, -// 13.9 step 7 is performed. Different parts of OpenPGP vary on this point. -func NewOCFBDecrypter(block cipher.Block, prefix []byte, resync OCFBResyncOption) cipher.Stream { - blockSize := block.BlockSize() - if len(prefix) != blockSize+2 { - return nil - } - - x := &ocfbDecrypter{ - b: block, - fre: make([]byte, blockSize), - outUsed: 0, - } - prefixCopy := make([]byte, len(prefix)) - copy(prefixCopy, prefix) - - block.Encrypt(x.fre, x.fre) - for i := 0; i < blockSize; i++ { - prefixCopy[i] ^= x.fre[i] - } - - block.Encrypt(x.fre, prefix[:blockSize]) - prefixCopy[blockSize] ^= x.fre[0] - prefixCopy[blockSize+1] ^= x.fre[1] - - if prefixCopy[blockSize-2] != prefixCopy[blockSize] || - prefixCopy[blockSize-1] != prefixCopy[blockSize+1] { - return nil - } - - if resync { - block.Encrypt(x.fre, prefix[2:]) - } else { - x.fre[0] = prefix[blockSize] - x.fre[1] = prefix[blockSize+1] - x.outUsed = 2 - } - copy(prefix, prefixCopy) - return x -} - -func (x *ocfbDecrypter) XORKeyStream(dst, src []byte) { - for i := 0; i < len(src); i++ { - if x.outUsed == len(x.fre) { - x.b.Encrypt(x.fre, x.fre) - x.outUsed = 0 - } - - c := src[i] - dst[i] = x.fre[x.outUsed] ^ src[i] - x.fre[x.outUsed] = c - x.outUsed++ - } -} diff --git a/vendor/golang.org/x/crypto/openpgp/packet/one_pass_signature.go b/vendor/golang.org/x/crypto/openpgp/packet/one_pass_signature.go deleted file mode 100644 index 1713503395..0000000000 --- a/vendor/golang.org/x/crypto/openpgp/packet/one_pass_signature.go +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package packet - -import ( - "crypto" - "encoding/binary" - "golang.org/x/crypto/openpgp/errors" - "golang.org/x/crypto/openpgp/s2k" - "io" - "strconv" -) - -// OnePassSignature represents a one-pass signature packet. See RFC 4880, -// section 5.4. -type OnePassSignature struct { - SigType SignatureType - Hash crypto.Hash - PubKeyAlgo PublicKeyAlgorithm - KeyId uint64 - IsLast bool -} - -const onePassSignatureVersion = 3 - -func (ops *OnePassSignature) parse(r io.Reader) (err error) { - var buf [13]byte - - _, err = readFull(r, buf[:]) - if err != nil { - return - } - if buf[0] != onePassSignatureVersion { - err = errors.UnsupportedError("one-pass-signature packet version " + strconv.Itoa(int(buf[0]))) - } - - var ok bool - ops.Hash, ok = s2k.HashIdToHash(buf[2]) - if !ok { - return errors.UnsupportedError("hash function: " + strconv.Itoa(int(buf[2]))) - } - - ops.SigType = SignatureType(buf[1]) - ops.PubKeyAlgo = PublicKeyAlgorithm(buf[3]) - ops.KeyId = binary.BigEndian.Uint64(buf[4:12]) - ops.IsLast = buf[12] != 0 - return -} - -// Serialize marshals the given OnePassSignature to w. -func (ops *OnePassSignature) Serialize(w io.Writer) error { - var buf [13]byte - buf[0] = onePassSignatureVersion - buf[1] = uint8(ops.SigType) - var ok bool - buf[2], ok = s2k.HashToHashId(ops.Hash) - if !ok { - return errors.UnsupportedError("hash type: " + strconv.Itoa(int(ops.Hash))) - } - buf[3] = uint8(ops.PubKeyAlgo) - binary.BigEndian.PutUint64(buf[4:12], ops.KeyId) - if ops.IsLast { - buf[12] = 1 - } - - if err := serializeHeader(w, packetTypeOnePassSignature, len(buf)); err != nil { - return err - } - _, err := w.Write(buf[:]) - return err -} diff --git a/vendor/golang.org/x/crypto/openpgp/packet/opaque.go b/vendor/golang.org/x/crypto/openpgp/packet/opaque.go deleted file mode 100644 index 3984477310..0000000000 --- a/vendor/golang.org/x/crypto/openpgp/packet/opaque.go +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package packet - -import ( - "bytes" - "io" - - "golang.org/x/crypto/openpgp/errors" -) - -// OpaquePacket represents an OpenPGP packet as raw, unparsed data. This is -// useful for splitting and storing the original packet contents separately, -// handling unsupported packet types or accessing parts of the packet not yet -// implemented by this package. -type OpaquePacket struct { - // Packet type - Tag uint8 - // Reason why the packet was parsed opaquely - Reason error - // Binary contents of the packet data - Contents []byte -} - -func (op *OpaquePacket) parse(r io.Reader) (err error) { - op.Contents, err = io.ReadAll(r) - return -} - -// Serialize marshals the packet to a writer in its original form, including -// the packet header. -func (op *OpaquePacket) Serialize(w io.Writer) (err error) { - err = serializeHeader(w, packetType(op.Tag), len(op.Contents)) - if err == nil { - _, err = w.Write(op.Contents) - } - return -} - -// Parse attempts to parse the opaque contents into a structure supported by -// this package. If the packet is not known then the result will be another -// OpaquePacket. -func (op *OpaquePacket) Parse() (p Packet, err error) { - hdr := bytes.NewBuffer(nil) - err = serializeHeader(hdr, packetType(op.Tag), len(op.Contents)) - if err != nil { - op.Reason = err - return op, err - } - p, err = Read(io.MultiReader(hdr, bytes.NewBuffer(op.Contents))) - if err != nil { - op.Reason = err - p = op - } - return -} - -// OpaqueReader reads OpaquePackets from an io.Reader. -type OpaqueReader struct { - r io.Reader -} - -func NewOpaqueReader(r io.Reader) *OpaqueReader { - return &OpaqueReader{r: r} -} - -// Read the next OpaquePacket. -func (or *OpaqueReader) Next() (op *OpaquePacket, err error) { - tag, _, contents, err := readHeader(or.r) - if err != nil { - return - } - op = &OpaquePacket{Tag: uint8(tag), Reason: err} - err = op.parse(contents) - if err != nil { - consumeAll(contents) - } - return -} - -// OpaqueSubpacket represents an unparsed OpenPGP subpacket, -// as found in signature and user attribute packets. -type OpaqueSubpacket struct { - SubType uint8 - Contents []byte -} - -// OpaqueSubpackets extracts opaque, unparsed OpenPGP subpackets from -// their byte representation. -func OpaqueSubpackets(contents []byte) (result []*OpaqueSubpacket, err error) { - var ( - subHeaderLen int - subPacket *OpaqueSubpacket - ) - for len(contents) > 0 { - subHeaderLen, subPacket, err = nextSubpacket(contents) - if err != nil { - break - } - result = append(result, subPacket) - contents = contents[subHeaderLen+len(subPacket.Contents):] - } - return -} - -func nextSubpacket(contents []byte) (subHeaderLen int, subPacket *OpaqueSubpacket, err error) { - // RFC 4880, section 5.2.3.1 - var subLen uint32 - if len(contents) < 1 { - goto Truncated - } - subPacket = &OpaqueSubpacket{} - switch { - case contents[0] < 192: - subHeaderLen = 2 // 1 length byte, 1 subtype byte - if len(contents) < subHeaderLen { - goto Truncated - } - subLen = uint32(contents[0]) - contents = contents[1:] - case contents[0] < 255: - subHeaderLen = 3 // 2 length bytes, 1 subtype - if len(contents) < subHeaderLen { - goto Truncated - } - subLen = uint32(contents[0]-192)<<8 + uint32(contents[1]) + 192 - contents = contents[2:] - default: - subHeaderLen = 6 // 5 length bytes, 1 subtype - if len(contents) < subHeaderLen { - goto Truncated - } - subLen = uint32(contents[1])<<24 | - uint32(contents[2])<<16 | - uint32(contents[3])<<8 | - uint32(contents[4]) - contents = contents[5:] - } - if subLen > uint32(len(contents)) || subLen == 0 { - goto Truncated - } - subPacket.SubType = contents[0] - subPacket.Contents = contents[1:subLen] - return -Truncated: - err = errors.StructuralError("subpacket truncated") - return -} - -func (osp *OpaqueSubpacket) Serialize(w io.Writer) (err error) { - buf := make([]byte, 6) - n := serializeSubpacketLength(buf, len(osp.Contents)+1) - buf[n] = osp.SubType - if _, err = w.Write(buf[:n+1]); err != nil { - return - } - _, err = w.Write(osp.Contents) - return -} diff --git a/vendor/golang.org/x/crypto/openpgp/packet/packet.go b/vendor/golang.org/x/crypto/openpgp/packet/packet.go deleted file mode 100644 index 5e3a25ad85..0000000000 --- a/vendor/golang.org/x/crypto/openpgp/packet/packet.go +++ /dev/null @@ -1,591 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package packet implements parsing and serialization of OpenPGP packets, as -// specified in RFC 4880. -// -// Deprecated: this package is unsafe by design, and has numerous known security -// issues. It is not maintained, and should not be used. New applications should -// consider a more focused, modern alternative to OpenPGP for their specific -// task. If you are required to interoperate with OpenPGP systems and need a -// maintained package, consider github.com/ProtonMail/go-crypto/openpgp, which -// is a maintained fork that aims to be a drop-in replacement for this package. -package packet - -import ( - "bufio" - "crypto/aes" - "crypto/cipher" - "crypto/des" - "crypto/rsa" - "io" - "math/big" - "math/bits" - - "golang.org/x/crypto/cast5" - "golang.org/x/crypto/openpgp/errors" -) - -// readFull is the same as io.ReadFull except that reading zero bytes returns -// ErrUnexpectedEOF rather than EOF. -func readFull(r io.Reader, buf []byte) (n int, err error) { - n, err = io.ReadFull(r, buf) - if err == io.EOF { - err = io.ErrUnexpectedEOF - } - return -} - -// readLength reads an OpenPGP length from r. See RFC 4880, section 4.2.2. -func readLength(r io.Reader) (length int64, isPartial bool, err error) { - var buf [4]byte - _, err = readFull(r, buf[:1]) - if err != nil { - return - } - switch { - case buf[0] < 192: - length = int64(buf[0]) - case buf[0] < 224: - length = int64(buf[0]-192) << 8 - _, err = readFull(r, buf[0:1]) - if err != nil { - return - } - length += int64(buf[0]) + 192 - case buf[0] < 255: - length = int64(1) << (buf[0] & 0x1f) - isPartial = true - default: - _, err = readFull(r, buf[0:4]) - if err != nil { - return - } - length = int64(buf[0])<<24 | - int64(buf[1])<<16 | - int64(buf[2])<<8 | - int64(buf[3]) - } - return -} - -// partialLengthReader wraps an io.Reader and handles OpenPGP partial lengths. -// The continuation lengths are parsed and removed from the stream and EOF is -// returned at the end of the packet. See RFC 4880, section 4.2.2.4. -type partialLengthReader struct { - r io.Reader - remaining int64 - isPartial bool -} - -func (r *partialLengthReader) Read(p []byte) (n int, err error) { - for r.remaining == 0 { - if !r.isPartial { - return 0, io.EOF - } - r.remaining, r.isPartial, err = readLength(r.r) - if err != nil { - return 0, err - } - } - - toRead := int64(len(p)) - if toRead > r.remaining { - toRead = r.remaining - } - - n, err = r.r.Read(p[:int(toRead)]) - r.remaining -= int64(n) - if n < int(toRead) && err == io.EOF { - err = io.ErrUnexpectedEOF - } - return -} - -// partialLengthWriter writes a stream of data using OpenPGP partial lengths. -// See RFC 4880, section 4.2.2.4. -type partialLengthWriter struct { - w io.WriteCloser - lengthByte [1]byte - sentFirst bool - buf []byte -} - -// RFC 4880 4.2.2.4: the first partial length MUST be at least 512 octets long. -const minFirstPartialWrite = 512 - -func (w *partialLengthWriter) Write(p []byte) (n int, err error) { - off := 0 - if !w.sentFirst { - if len(w.buf) > 0 || len(p) < minFirstPartialWrite { - off = len(w.buf) - w.buf = append(w.buf, p...) - if len(w.buf) < minFirstPartialWrite { - return len(p), nil - } - p = w.buf - w.buf = nil - } - w.sentFirst = true - } - - power := uint8(30) - for len(p) > 0 { - l := 1 << power - if len(p) < l { - power = uint8(bits.Len32(uint32(len(p)))) - 1 - l = 1 << power - } - w.lengthByte[0] = 224 + power - _, err = w.w.Write(w.lengthByte[:]) - if err == nil { - var m int - m, err = w.w.Write(p[:l]) - n += m - } - if err != nil { - if n < off { - return 0, err - } - return n - off, err - } - p = p[l:] - } - return n - off, nil -} - -func (w *partialLengthWriter) Close() error { - if len(w.buf) > 0 { - // In this case we can't send a 512 byte packet. - // Just send what we have. - p := w.buf - w.sentFirst = true - w.buf = nil - if _, err := w.Write(p); err != nil { - return err - } - } - - w.lengthByte[0] = 0 - _, err := w.w.Write(w.lengthByte[:]) - if err != nil { - return err - } - return w.w.Close() -} - -// A spanReader is an io.LimitReader, but it returns ErrUnexpectedEOF if the -// underlying Reader returns EOF before the limit has been reached. -type spanReader struct { - r io.Reader - n int64 -} - -func (l *spanReader) Read(p []byte) (n int, err error) { - if l.n <= 0 { - return 0, io.EOF - } - if int64(len(p)) > l.n { - p = p[0:l.n] - } - n, err = l.r.Read(p) - l.n -= int64(n) - if l.n > 0 && err == io.EOF { - err = io.ErrUnexpectedEOF - } - return -} - -// readHeader parses a packet header and returns an io.Reader which will return -// the contents of the packet. See RFC 4880, section 4.2. -func readHeader(r io.Reader) (tag packetType, length int64, contents io.Reader, err error) { - var buf [4]byte - _, err = io.ReadFull(r, buf[:1]) - if err != nil { - return - } - if buf[0]&0x80 == 0 { - err = errors.StructuralError("tag byte does not have MSB set") - return - } - if buf[0]&0x40 == 0 { - // Old format packet - tag = packetType((buf[0] & 0x3f) >> 2) - lengthType := buf[0] & 3 - if lengthType == 3 { - length = -1 - contents = r - return - } - lengthBytes := 1 << lengthType - _, err = readFull(r, buf[0:lengthBytes]) - if err != nil { - return - } - for i := 0; i < lengthBytes; i++ { - length <<= 8 - length |= int64(buf[i]) - } - contents = &spanReader{r, length} - return - } - - // New format packet - tag = packetType(buf[0] & 0x3f) - length, isPartial, err := readLength(r) - if err != nil { - return - } - if isPartial { - contents = &partialLengthReader{ - remaining: length, - isPartial: true, - r: r, - } - length = -1 - } else { - contents = &spanReader{r, length} - } - return -} - -// serializeHeader writes an OpenPGP packet header to w. See RFC 4880, section -// 4.2. -func serializeHeader(w io.Writer, ptype packetType, length int) (err error) { - var buf [6]byte - var n int - - buf[0] = 0x80 | 0x40 | byte(ptype) - if length < 192 { - buf[1] = byte(length) - n = 2 - } else if length < 8384 { - length -= 192 - buf[1] = 192 + byte(length>>8) - buf[2] = byte(length) - n = 3 - } else { - buf[1] = 255 - buf[2] = byte(length >> 24) - buf[3] = byte(length >> 16) - buf[4] = byte(length >> 8) - buf[5] = byte(length) - n = 6 - } - - _, err = w.Write(buf[:n]) - return -} - -// serializeStreamHeader writes an OpenPGP packet header to w where the -// length of the packet is unknown. It returns a io.WriteCloser which can be -// used to write the contents of the packet. See RFC 4880, section 4.2. -func serializeStreamHeader(w io.WriteCloser, ptype packetType) (out io.WriteCloser, err error) { - var buf [1]byte - buf[0] = 0x80 | 0x40 | byte(ptype) - _, err = w.Write(buf[:]) - if err != nil { - return - } - out = &partialLengthWriter{w: w} - return -} - -// Packet represents an OpenPGP packet. Users are expected to try casting -// instances of this interface to specific packet types. -type Packet interface { - parse(io.Reader) error -} - -// consumeAll reads from the given Reader until error, returning the number of -// bytes read. -func consumeAll(r io.Reader) (n int64, err error) { - var m int - var buf [1024]byte - - for { - m, err = r.Read(buf[:]) - n += int64(m) - if err == io.EOF { - err = nil - return - } - if err != nil { - return - } - } -} - -// packetType represents the numeric ids of the different OpenPGP packet types. See -// http://www.iana.org/assignments/pgp-parameters/pgp-parameters.xhtml#pgp-parameters-2 -type packetType uint8 - -const ( - packetTypeEncryptedKey packetType = 1 - packetTypeSignature packetType = 2 - packetTypeSymmetricKeyEncrypted packetType = 3 - packetTypeOnePassSignature packetType = 4 - packetTypePrivateKey packetType = 5 - packetTypePublicKey packetType = 6 - packetTypePrivateSubkey packetType = 7 - packetTypeCompressed packetType = 8 - packetTypeSymmetricallyEncrypted packetType = 9 - packetTypeLiteralData packetType = 11 - packetTypeUserId packetType = 13 - packetTypePublicSubkey packetType = 14 - packetTypeUserAttribute packetType = 17 - packetTypeSymmetricallyEncryptedMDC packetType = 18 -) - -// peekVersion detects the version of a public key packet about to -// be read. A bufio.Reader at the original position of the io.Reader -// is returned. -func peekVersion(r io.Reader) (bufr *bufio.Reader, ver byte, err error) { - bufr = bufio.NewReader(r) - var verBuf []byte - if verBuf, err = bufr.Peek(1); err != nil { - return - } - ver = verBuf[0] - return -} - -// Read reads a single OpenPGP packet from the given io.Reader. If there is an -// error parsing a packet, the whole packet is consumed from the input. -func Read(r io.Reader) (p Packet, err error) { - tag, _, contents, err := readHeader(r) - if err != nil { - return - } - - switch tag { - case packetTypeEncryptedKey: - p = new(EncryptedKey) - case packetTypeSignature: - var version byte - // Detect signature version - if contents, version, err = peekVersion(contents); err != nil { - return - } - if version < 4 { - p = new(SignatureV3) - } else { - p = new(Signature) - } - case packetTypeSymmetricKeyEncrypted: - p = new(SymmetricKeyEncrypted) - case packetTypeOnePassSignature: - p = new(OnePassSignature) - case packetTypePrivateKey, packetTypePrivateSubkey: - pk := new(PrivateKey) - if tag == packetTypePrivateSubkey { - pk.IsSubkey = true - } - p = pk - case packetTypePublicKey, packetTypePublicSubkey: - var version byte - if contents, version, err = peekVersion(contents); err != nil { - return - } - isSubkey := tag == packetTypePublicSubkey - if version < 4 { - p = &PublicKeyV3{IsSubkey: isSubkey} - } else { - p = &PublicKey{IsSubkey: isSubkey} - } - case packetTypeCompressed: - p = new(Compressed) - case packetTypeSymmetricallyEncrypted: - p = new(SymmetricallyEncrypted) - case packetTypeLiteralData: - p = new(LiteralData) - case packetTypeUserId: - p = new(UserId) - case packetTypeUserAttribute: - p = new(UserAttribute) - case packetTypeSymmetricallyEncryptedMDC: - se := new(SymmetricallyEncrypted) - se.MDC = true - p = se - default: - err = errors.UnknownPacketTypeError(tag) - } - if p != nil { - err = p.parse(contents) - } - if err != nil { - consumeAll(contents) - } - return -} - -// SignatureType represents the different semantic meanings of an OpenPGP -// signature. See RFC 4880, section 5.2.1. -type SignatureType uint8 - -const ( - SigTypeBinary SignatureType = 0 - SigTypeText = 1 - SigTypeGenericCert = 0x10 - SigTypePersonaCert = 0x11 - SigTypeCasualCert = 0x12 - SigTypePositiveCert = 0x13 - SigTypeSubkeyBinding = 0x18 - SigTypePrimaryKeyBinding = 0x19 - SigTypeDirectSignature = 0x1F - SigTypeKeyRevocation = 0x20 - SigTypeSubkeyRevocation = 0x28 -) - -// PublicKeyAlgorithm represents the different public key system specified for -// OpenPGP. See -// http://www.iana.org/assignments/pgp-parameters/pgp-parameters.xhtml#pgp-parameters-12 -type PublicKeyAlgorithm uint8 - -const ( - PubKeyAlgoRSA PublicKeyAlgorithm = 1 - PubKeyAlgoElGamal PublicKeyAlgorithm = 16 - PubKeyAlgoDSA PublicKeyAlgorithm = 17 - // RFC 6637, Section 5. - PubKeyAlgoECDH PublicKeyAlgorithm = 18 - PubKeyAlgoECDSA PublicKeyAlgorithm = 19 - - // Deprecated in RFC 4880, Section 13.5. Use key flags instead. - PubKeyAlgoRSAEncryptOnly PublicKeyAlgorithm = 2 - PubKeyAlgoRSASignOnly PublicKeyAlgorithm = 3 -) - -// CanEncrypt returns true if it's possible to encrypt a message to a public -// key of the given type. -func (pka PublicKeyAlgorithm) CanEncrypt() bool { - switch pka { - case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoElGamal: - return true - } - return false -} - -// CanSign returns true if it's possible for a public key of the given type to -// sign a message. -func (pka PublicKeyAlgorithm) CanSign() bool { - switch pka { - case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly, PubKeyAlgoDSA, PubKeyAlgoECDSA: - return true - } - return false -} - -// CipherFunction represents the different block ciphers specified for OpenPGP. See -// http://www.iana.org/assignments/pgp-parameters/pgp-parameters.xhtml#pgp-parameters-13 -type CipherFunction uint8 - -const ( - Cipher3DES CipherFunction = 2 - CipherCAST5 CipherFunction = 3 - CipherAES128 CipherFunction = 7 - CipherAES192 CipherFunction = 8 - CipherAES256 CipherFunction = 9 -) - -// KeySize returns the key size, in bytes, of cipher. -func (cipher CipherFunction) KeySize() int { - switch cipher { - case Cipher3DES: - return 24 - case CipherCAST5: - return cast5.KeySize - case CipherAES128: - return 16 - case CipherAES192: - return 24 - case CipherAES256: - return 32 - } - return 0 -} - -// blockSize returns the block size, in bytes, of cipher. -func (cipher CipherFunction) blockSize() int { - switch cipher { - case Cipher3DES: - return des.BlockSize - case CipherCAST5: - return 8 - case CipherAES128, CipherAES192, CipherAES256: - return 16 - } - return 0 -} - -// new returns a fresh instance of the given cipher. -func (cipher CipherFunction) new(key []byte) (block cipher.Block) { - switch cipher { - case Cipher3DES: - block, _ = des.NewTripleDESCipher(key) - case CipherCAST5: - block, _ = cast5.NewCipher(key) - case CipherAES128, CipherAES192, CipherAES256: - block, _ = aes.NewCipher(key) - } - return -} - -// readMPI reads a big integer from r. The bit length returned is the bit -// length that was specified in r. This is preserved so that the integer can be -// reserialized exactly. -func readMPI(r io.Reader) (mpi []byte, bitLength uint16, err error) { - var buf [2]byte - _, err = readFull(r, buf[0:]) - if err != nil { - return - } - bitLength = uint16(buf[0])<<8 | uint16(buf[1]) - numBytes := (int(bitLength) + 7) / 8 - mpi = make([]byte, numBytes) - _, err = readFull(r, mpi) - // According to RFC 4880 3.2. we should check that the MPI has no leading - // zeroes (at least when not an encrypted MPI?), but this implementation - // does generate leading zeroes, so we keep accepting them. - return -} - -// writeMPI serializes a big integer to w. -func writeMPI(w io.Writer, bitLength uint16, mpiBytes []byte) (err error) { - // Note that we can produce leading zeroes, in violation of RFC 4880 3.2. - // Implementations seem to be tolerant of them, and stripping them would - // make it complex to guarantee matching re-serialization. - _, err = w.Write([]byte{byte(bitLength >> 8), byte(bitLength)}) - if err == nil { - _, err = w.Write(mpiBytes) - } - return -} - -// writeBig serializes a *big.Int to w. -func writeBig(w io.Writer, i *big.Int) error { - return writeMPI(w, uint16(i.BitLen()), i.Bytes()) -} - -// padToKeySize left-pads a MPI with zeroes to match the length of the -// specified RSA public. -func padToKeySize(pub *rsa.PublicKey, b []byte) []byte { - k := (pub.N.BitLen() + 7) / 8 - if len(b) >= k { - return b - } - bb := make([]byte, k) - copy(bb[len(bb)-len(b):], b) - return bb -} - -// CompressionAlgo Represents the different compression algorithms -// supported by OpenPGP (except for BZIP2, which is not currently -// supported). See Section 9.3 of RFC 4880. -type CompressionAlgo uint8 - -const ( - CompressionNone CompressionAlgo = 0 - CompressionZIP CompressionAlgo = 1 - CompressionZLIB CompressionAlgo = 2 -) diff --git a/vendor/golang.org/x/crypto/openpgp/packet/private_key.go b/vendor/golang.org/x/crypto/openpgp/packet/private_key.go deleted file mode 100644 index 192aac376d..0000000000 --- a/vendor/golang.org/x/crypto/openpgp/packet/private_key.go +++ /dev/null @@ -1,384 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package packet - -import ( - "bytes" - "crypto" - "crypto/cipher" - "crypto/dsa" - "crypto/ecdsa" - "crypto/rsa" - "crypto/sha1" - "io" - "math/big" - "strconv" - "time" - - "golang.org/x/crypto/openpgp/elgamal" - "golang.org/x/crypto/openpgp/errors" - "golang.org/x/crypto/openpgp/s2k" -) - -// PrivateKey represents a possibly encrypted private key. See RFC 4880, -// section 5.5.3. -type PrivateKey struct { - PublicKey - Encrypted bool // if true then the private key is unavailable until Decrypt has been called. - encryptedData []byte - cipher CipherFunction - s2k func(out, in []byte) - PrivateKey interface{} // An *{rsa|dsa|ecdsa}.PrivateKey or crypto.Signer/crypto.Decrypter (Decryptor RSA only). - sha1Checksum bool - iv []byte -} - -func NewRSAPrivateKey(creationTime time.Time, priv *rsa.PrivateKey) *PrivateKey { - pk := new(PrivateKey) - pk.PublicKey = *NewRSAPublicKey(creationTime, &priv.PublicKey) - pk.PrivateKey = priv - return pk -} - -func NewDSAPrivateKey(creationTime time.Time, priv *dsa.PrivateKey) *PrivateKey { - pk := new(PrivateKey) - pk.PublicKey = *NewDSAPublicKey(creationTime, &priv.PublicKey) - pk.PrivateKey = priv - return pk -} - -func NewElGamalPrivateKey(creationTime time.Time, priv *elgamal.PrivateKey) *PrivateKey { - pk := new(PrivateKey) - pk.PublicKey = *NewElGamalPublicKey(creationTime, &priv.PublicKey) - pk.PrivateKey = priv - return pk -} - -func NewECDSAPrivateKey(creationTime time.Time, priv *ecdsa.PrivateKey) *PrivateKey { - pk := new(PrivateKey) - pk.PublicKey = *NewECDSAPublicKey(creationTime, &priv.PublicKey) - pk.PrivateKey = priv - return pk -} - -// NewSignerPrivateKey creates a PrivateKey from a crypto.Signer that -// implements RSA or ECDSA. -func NewSignerPrivateKey(creationTime time.Time, signer crypto.Signer) *PrivateKey { - pk := new(PrivateKey) - // In general, the public Keys should be used as pointers. We still - // type-switch on the values, for backwards-compatibility. - switch pubkey := signer.Public().(type) { - case *rsa.PublicKey: - pk.PublicKey = *NewRSAPublicKey(creationTime, pubkey) - case rsa.PublicKey: - pk.PublicKey = *NewRSAPublicKey(creationTime, &pubkey) - case *ecdsa.PublicKey: - pk.PublicKey = *NewECDSAPublicKey(creationTime, pubkey) - case ecdsa.PublicKey: - pk.PublicKey = *NewECDSAPublicKey(creationTime, &pubkey) - default: - panic("openpgp: unknown crypto.Signer type in NewSignerPrivateKey") - } - pk.PrivateKey = signer - return pk -} - -func (pk *PrivateKey) parse(r io.Reader) (err error) { - err = (&pk.PublicKey).parse(r) - if err != nil { - return - } - var buf [1]byte - _, err = readFull(r, buf[:]) - if err != nil { - return - } - - s2kType := buf[0] - - switch s2kType { - case 0: - pk.s2k = nil - pk.Encrypted = false - case 254, 255: - _, err = readFull(r, buf[:]) - if err != nil { - return - } - pk.cipher = CipherFunction(buf[0]) - pk.Encrypted = true - pk.s2k, err = s2k.Parse(r) - if err != nil { - return - } - if s2kType == 254 { - pk.sha1Checksum = true - } - default: - return errors.UnsupportedError("deprecated s2k function in private key") - } - - if pk.Encrypted { - blockSize := pk.cipher.blockSize() - if blockSize == 0 { - return errors.UnsupportedError("unsupported cipher in private key: " + strconv.Itoa(int(pk.cipher))) - } - pk.iv = make([]byte, blockSize) - _, err = readFull(r, pk.iv) - if err != nil { - return - } - } - - pk.encryptedData, err = io.ReadAll(r) - if err != nil { - return - } - - if !pk.Encrypted { - return pk.parsePrivateKey(pk.encryptedData) - } - - return -} - -func mod64kHash(d []byte) uint16 { - var h uint16 - for _, b := range d { - h += uint16(b) - } - return h -} - -func (pk *PrivateKey) Serialize(w io.Writer) (err error) { - // TODO(agl): support encrypted private keys - buf := bytes.NewBuffer(nil) - err = pk.PublicKey.serializeWithoutHeaders(buf) - if err != nil { - return - } - buf.WriteByte(0 /* no encryption */) - - privateKeyBuf := bytes.NewBuffer(nil) - - switch priv := pk.PrivateKey.(type) { - case *rsa.PrivateKey: - err = serializeRSAPrivateKey(privateKeyBuf, priv) - case *dsa.PrivateKey: - err = serializeDSAPrivateKey(privateKeyBuf, priv) - case *elgamal.PrivateKey: - err = serializeElGamalPrivateKey(privateKeyBuf, priv) - case *ecdsa.PrivateKey: - err = serializeECDSAPrivateKey(privateKeyBuf, priv) - default: - err = errors.InvalidArgumentError("unknown private key type") - } - if err != nil { - return - } - - ptype := packetTypePrivateKey - contents := buf.Bytes() - privateKeyBytes := privateKeyBuf.Bytes() - if pk.IsSubkey { - ptype = packetTypePrivateSubkey - } - err = serializeHeader(w, ptype, len(contents)+len(privateKeyBytes)+2) - if err != nil { - return - } - _, err = w.Write(contents) - if err != nil { - return - } - _, err = w.Write(privateKeyBytes) - if err != nil { - return - } - - checksum := mod64kHash(privateKeyBytes) - var checksumBytes [2]byte - checksumBytes[0] = byte(checksum >> 8) - checksumBytes[1] = byte(checksum) - _, err = w.Write(checksumBytes[:]) - - return -} - -func serializeRSAPrivateKey(w io.Writer, priv *rsa.PrivateKey) error { - err := writeBig(w, priv.D) - if err != nil { - return err - } - err = writeBig(w, priv.Primes[1]) - if err != nil { - return err - } - err = writeBig(w, priv.Primes[0]) - if err != nil { - return err - } - return writeBig(w, priv.Precomputed.Qinv) -} - -func serializeDSAPrivateKey(w io.Writer, priv *dsa.PrivateKey) error { - return writeBig(w, priv.X) -} - -func serializeElGamalPrivateKey(w io.Writer, priv *elgamal.PrivateKey) error { - return writeBig(w, priv.X) -} - -func serializeECDSAPrivateKey(w io.Writer, priv *ecdsa.PrivateKey) error { - return writeBig(w, priv.D) -} - -// Decrypt decrypts an encrypted private key using a passphrase. -func (pk *PrivateKey) Decrypt(passphrase []byte) error { - if !pk.Encrypted { - return nil - } - - key := make([]byte, pk.cipher.KeySize()) - pk.s2k(key, passphrase) - block := pk.cipher.new(key) - cfb := cipher.NewCFBDecrypter(block, pk.iv) - - data := make([]byte, len(pk.encryptedData)) - cfb.XORKeyStream(data, pk.encryptedData) - - if pk.sha1Checksum { - if len(data) < sha1.Size { - return errors.StructuralError("truncated private key data") - } - h := sha1.New() - h.Write(data[:len(data)-sha1.Size]) - sum := h.Sum(nil) - if !bytes.Equal(sum, data[len(data)-sha1.Size:]) { - return errors.StructuralError("private key checksum failure") - } - data = data[:len(data)-sha1.Size] - } else { - if len(data) < 2 { - return errors.StructuralError("truncated private key data") - } - var sum uint16 - for i := 0; i < len(data)-2; i++ { - sum += uint16(data[i]) - } - if data[len(data)-2] != uint8(sum>>8) || - data[len(data)-1] != uint8(sum) { - return errors.StructuralError("private key checksum failure") - } - data = data[:len(data)-2] - } - - return pk.parsePrivateKey(data) -} - -func (pk *PrivateKey) parsePrivateKey(data []byte) (err error) { - switch pk.PublicKey.PubKeyAlgo { - case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly, PubKeyAlgoRSAEncryptOnly: - return pk.parseRSAPrivateKey(data) - case PubKeyAlgoDSA: - return pk.parseDSAPrivateKey(data) - case PubKeyAlgoElGamal: - return pk.parseElGamalPrivateKey(data) - case PubKeyAlgoECDSA: - return pk.parseECDSAPrivateKey(data) - } - panic("impossible") -} - -func (pk *PrivateKey) parseRSAPrivateKey(data []byte) (err error) { - rsaPub := pk.PublicKey.PublicKey.(*rsa.PublicKey) - rsaPriv := new(rsa.PrivateKey) - rsaPriv.PublicKey = *rsaPub - - buf := bytes.NewBuffer(data) - d, _, err := readMPI(buf) - if err != nil { - return - } - p, _, err := readMPI(buf) - if err != nil { - return - } - q, _, err := readMPI(buf) - if err != nil { - return - } - - rsaPriv.D = new(big.Int).SetBytes(d) - rsaPriv.Primes = make([]*big.Int, 2) - rsaPriv.Primes[0] = new(big.Int).SetBytes(p) - rsaPriv.Primes[1] = new(big.Int).SetBytes(q) - if err := rsaPriv.Validate(); err != nil { - return err - } - rsaPriv.Precompute() - pk.PrivateKey = rsaPriv - pk.Encrypted = false - pk.encryptedData = nil - - return nil -} - -func (pk *PrivateKey) parseDSAPrivateKey(data []byte) (err error) { - dsaPub := pk.PublicKey.PublicKey.(*dsa.PublicKey) - dsaPriv := new(dsa.PrivateKey) - dsaPriv.PublicKey = *dsaPub - - buf := bytes.NewBuffer(data) - x, _, err := readMPI(buf) - if err != nil { - return - } - - dsaPriv.X = new(big.Int).SetBytes(x) - pk.PrivateKey = dsaPriv - pk.Encrypted = false - pk.encryptedData = nil - - return nil -} - -func (pk *PrivateKey) parseElGamalPrivateKey(data []byte) (err error) { - pub := pk.PublicKey.PublicKey.(*elgamal.PublicKey) - priv := new(elgamal.PrivateKey) - priv.PublicKey = *pub - - buf := bytes.NewBuffer(data) - x, _, err := readMPI(buf) - if err != nil { - return - } - - priv.X = new(big.Int).SetBytes(x) - pk.PrivateKey = priv - pk.Encrypted = false - pk.encryptedData = nil - - return nil -} - -func (pk *PrivateKey) parseECDSAPrivateKey(data []byte) (err error) { - ecdsaPub := pk.PublicKey.PublicKey.(*ecdsa.PublicKey) - - buf := bytes.NewBuffer(data) - d, _, err := readMPI(buf) - if err != nil { - return - } - - pk.PrivateKey = &ecdsa.PrivateKey{ - PublicKey: *ecdsaPub, - D: new(big.Int).SetBytes(d), - } - pk.Encrypted = false - pk.encryptedData = nil - - return nil -} diff --git a/vendor/golang.org/x/crypto/openpgp/packet/public_key.go b/vendor/golang.org/x/crypto/openpgp/packet/public_key.go deleted file mode 100644 index fcd5f52519..0000000000 --- a/vendor/golang.org/x/crypto/openpgp/packet/public_key.go +++ /dev/null @@ -1,753 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package packet - -import ( - "bytes" - "crypto" - "crypto/dsa" - "crypto/ecdsa" - "crypto/elliptic" - "crypto/rsa" - "crypto/sha1" - _ "crypto/sha256" - _ "crypto/sha512" - "encoding/binary" - "fmt" - "hash" - "io" - "math/big" - "strconv" - "time" - - "golang.org/x/crypto/openpgp/elgamal" - "golang.org/x/crypto/openpgp/errors" -) - -var ( - // NIST curve P-256 - oidCurveP256 []byte = []byte{0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07} - // NIST curve P-384 - oidCurveP384 []byte = []byte{0x2B, 0x81, 0x04, 0x00, 0x22} - // NIST curve P-521 - oidCurveP521 []byte = []byte{0x2B, 0x81, 0x04, 0x00, 0x23} -) - -const maxOIDLength = 8 - -// ecdsaKey stores the algorithm-specific fields for ECDSA keys. -// as defined in RFC 6637, Section 9. -type ecdsaKey struct { - // oid contains the OID byte sequence identifying the elliptic curve used - oid []byte - // p contains the elliptic curve point that represents the public key - p parsedMPI -} - -// parseOID reads the OID for the curve as defined in RFC 6637, Section 9. -func parseOID(r io.Reader) (oid []byte, err error) { - buf := make([]byte, maxOIDLength) - if _, err = readFull(r, buf[:1]); err != nil { - return - } - oidLen := buf[0] - if int(oidLen) > len(buf) { - err = errors.UnsupportedError("invalid oid length: " + strconv.Itoa(int(oidLen))) - return - } - oid = buf[:oidLen] - _, err = readFull(r, oid) - return -} - -func (f *ecdsaKey) parse(r io.Reader) (err error) { - if f.oid, err = parseOID(r); err != nil { - return err - } - f.p.bytes, f.p.bitLength, err = readMPI(r) - return -} - -func (f *ecdsaKey) serialize(w io.Writer) (err error) { - buf := make([]byte, maxOIDLength+1) - buf[0] = byte(len(f.oid)) - copy(buf[1:], f.oid) - if _, err = w.Write(buf[:len(f.oid)+1]); err != nil { - return - } - return writeMPIs(w, f.p) -} - -func (f *ecdsaKey) newECDSA() (*ecdsa.PublicKey, error) { - var c elliptic.Curve - if bytes.Equal(f.oid, oidCurveP256) { - c = elliptic.P256() - } else if bytes.Equal(f.oid, oidCurveP384) { - c = elliptic.P384() - } else if bytes.Equal(f.oid, oidCurveP521) { - c = elliptic.P521() - } else { - return nil, errors.UnsupportedError(fmt.Sprintf("unsupported oid: %x", f.oid)) - } - x, y := elliptic.Unmarshal(c, f.p.bytes) - if x == nil { - return nil, errors.UnsupportedError("failed to parse EC point") - } - return &ecdsa.PublicKey{Curve: c, X: x, Y: y}, nil -} - -func (f *ecdsaKey) byteLen() int { - return 1 + len(f.oid) + 2 + len(f.p.bytes) -} - -type kdfHashFunction byte -type kdfAlgorithm byte - -// ecdhKdf stores key derivation function parameters -// used for ECDH encryption. See RFC 6637, Section 9. -type ecdhKdf struct { - KdfHash kdfHashFunction - KdfAlgo kdfAlgorithm -} - -func (f *ecdhKdf) parse(r io.Reader) (err error) { - buf := make([]byte, 1) - if _, err = readFull(r, buf); err != nil { - return - } - kdfLen := int(buf[0]) - if kdfLen < 3 { - return errors.UnsupportedError("Unsupported ECDH KDF length: " + strconv.Itoa(kdfLen)) - } - buf = make([]byte, kdfLen) - if _, err = readFull(r, buf); err != nil { - return - } - reserved := int(buf[0]) - f.KdfHash = kdfHashFunction(buf[1]) - f.KdfAlgo = kdfAlgorithm(buf[2]) - if reserved != 0x01 { - return errors.UnsupportedError("Unsupported KDF reserved field: " + strconv.Itoa(reserved)) - } - return -} - -func (f *ecdhKdf) serialize(w io.Writer) (err error) { - buf := make([]byte, 4) - // See RFC 6637, Section 9, Algorithm-Specific Fields for ECDH keys. - buf[0] = byte(0x03) // Length of the following fields - buf[1] = byte(0x01) // Reserved for future extensions, must be 1 for now - buf[2] = byte(f.KdfHash) - buf[3] = byte(f.KdfAlgo) - _, err = w.Write(buf[:]) - return -} - -func (f *ecdhKdf) byteLen() int { - return 4 -} - -// PublicKey represents an OpenPGP public key. See RFC 4880, section 5.5.2. -type PublicKey struct { - CreationTime time.Time - PubKeyAlgo PublicKeyAlgorithm - PublicKey interface{} // *rsa.PublicKey, *dsa.PublicKey or *ecdsa.PublicKey - Fingerprint [20]byte - KeyId uint64 - IsSubkey bool - - n, e, p, q, g, y parsedMPI - - // RFC 6637 fields - ec *ecdsaKey - ecdh *ecdhKdf -} - -// signingKey provides a convenient abstraction over signature verification -// for v3 and v4 public keys. -type signingKey interface { - SerializeSignaturePrefix(io.Writer) - serializeWithoutHeaders(io.Writer) error -} - -func fromBig(n *big.Int) parsedMPI { - return parsedMPI{ - bytes: n.Bytes(), - bitLength: uint16(n.BitLen()), - } -} - -// NewRSAPublicKey returns a PublicKey that wraps the given rsa.PublicKey. -func NewRSAPublicKey(creationTime time.Time, pub *rsa.PublicKey) *PublicKey { - pk := &PublicKey{ - CreationTime: creationTime, - PubKeyAlgo: PubKeyAlgoRSA, - PublicKey: pub, - n: fromBig(pub.N), - e: fromBig(big.NewInt(int64(pub.E))), - } - - pk.setFingerPrintAndKeyId() - return pk -} - -// NewDSAPublicKey returns a PublicKey that wraps the given dsa.PublicKey. -func NewDSAPublicKey(creationTime time.Time, pub *dsa.PublicKey) *PublicKey { - pk := &PublicKey{ - CreationTime: creationTime, - PubKeyAlgo: PubKeyAlgoDSA, - PublicKey: pub, - p: fromBig(pub.P), - q: fromBig(pub.Q), - g: fromBig(pub.G), - y: fromBig(pub.Y), - } - - pk.setFingerPrintAndKeyId() - return pk -} - -// NewElGamalPublicKey returns a PublicKey that wraps the given elgamal.PublicKey. -func NewElGamalPublicKey(creationTime time.Time, pub *elgamal.PublicKey) *PublicKey { - pk := &PublicKey{ - CreationTime: creationTime, - PubKeyAlgo: PubKeyAlgoElGamal, - PublicKey: pub, - p: fromBig(pub.P), - g: fromBig(pub.G), - y: fromBig(pub.Y), - } - - pk.setFingerPrintAndKeyId() - return pk -} - -func NewECDSAPublicKey(creationTime time.Time, pub *ecdsa.PublicKey) *PublicKey { - pk := &PublicKey{ - CreationTime: creationTime, - PubKeyAlgo: PubKeyAlgoECDSA, - PublicKey: pub, - ec: new(ecdsaKey), - } - - switch pub.Curve { - case elliptic.P256(): - pk.ec.oid = oidCurveP256 - case elliptic.P384(): - pk.ec.oid = oidCurveP384 - case elliptic.P521(): - pk.ec.oid = oidCurveP521 - default: - panic("unknown elliptic curve") - } - - pk.ec.p.bytes = elliptic.Marshal(pub.Curve, pub.X, pub.Y) - - // The bit length is 3 (for the 0x04 specifying an uncompressed key) - // plus two field elements (for x and y), which are rounded up to the - // nearest byte. See https://tools.ietf.org/html/rfc6637#section-6 - fieldBytes := (pub.Curve.Params().BitSize + 7) & ^7 - pk.ec.p.bitLength = uint16(3 + fieldBytes + fieldBytes) - - pk.setFingerPrintAndKeyId() - return pk -} - -func (pk *PublicKey) parse(r io.Reader) (err error) { - // RFC 4880, section 5.5.2 - var buf [6]byte - _, err = readFull(r, buf[:]) - if err != nil { - return - } - if buf[0] != 4 { - return errors.UnsupportedError("public key version") - } - pk.CreationTime = time.Unix(int64(uint32(buf[1])<<24|uint32(buf[2])<<16|uint32(buf[3])<<8|uint32(buf[4])), 0) - pk.PubKeyAlgo = PublicKeyAlgorithm(buf[5]) - switch pk.PubKeyAlgo { - case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly: - err = pk.parseRSA(r) - case PubKeyAlgoDSA: - err = pk.parseDSA(r) - case PubKeyAlgoElGamal: - err = pk.parseElGamal(r) - case PubKeyAlgoECDSA: - pk.ec = new(ecdsaKey) - if err = pk.ec.parse(r); err != nil { - return err - } - pk.PublicKey, err = pk.ec.newECDSA() - case PubKeyAlgoECDH: - pk.ec = new(ecdsaKey) - if err = pk.ec.parse(r); err != nil { - return - } - pk.ecdh = new(ecdhKdf) - if err = pk.ecdh.parse(r); err != nil { - return - } - // The ECDH key is stored in an ecdsa.PublicKey for convenience. - pk.PublicKey, err = pk.ec.newECDSA() - default: - err = errors.UnsupportedError("public key type: " + strconv.Itoa(int(pk.PubKeyAlgo))) - } - if err != nil { - return - } - - pk.setFingerPrintAndKeyId() - return -} - -func (pk *PublicKey) setFingerPrintAndKeyId() { - // RFC 4880, section 12.2 - fingerPrint := sha1.New() - pk.SerializeSignaturePrefix(fingerPrint) - pk.serializeWithoutHeaders(fingerPrint) - copy(pk.Fingerprint[:], fingerPrint.Sum(nil)) - pk.KeyId = binary.BigEndian.Uint64(pk.Fingerprint[12:20]) -} - -// parseRSA parses RSA public key material from the given Reader. See RFC 4880, -// section 5.5.2. -func (pk *PublicKey) parseRSA(r io.Reader) (err error) { - pk.n.bytes, pk.n.bitLength, err = readMPI(r) - if err != nil { - return - } - pk.e.bytes, pk.e.bitLength, err = readMPI(r) - if err != nil { - return - } - - if len(pk.e.bytes) > 3 { - err = errors.UnsupportedError("large public exponent") - return - } - rsa := &rsa.PublicKey{ - N: new(big.Int).SetBytes(pk.n.bytes), - E: 0, - } - for i := 0; i < len(pk.e.bytes); i++ { - rsa.E <<= 8 - rsa.E |= int(pk.e.bytes[i]) - } - pk.PublicKey = rsa - return -} - -// parseDSA parses DSA public key material from the given Reader. See RFC 4880, -// section 5.5.2. -func (pk *PublicKey) parseDSA(r io.Reader) (err error) { - pk.p.bytes, pk.p.bitLength, err = readMPI(r) - if err != nil { - return - } - pk.q.bytes, pk.q.bitLength, err = readMPI(r) - if err != nil { - return - } - pk.g.bytes, pk.g.bitLength, err = readMPI(r) - if err != nil { - return - } - pk.y.bytes, pk.y.bitLength, err = readMPI(r) - if err != nil { - return - } - - dsa := new(dsa.PublicKey) - dsa.P = new(big.Int).SetBytes(pk.p.bytes) - dsa.Q = new(big.Int).SetBytes(pk.q.bytes) - dsa.G = new(big.Int).SetBytes(pk.g.bytes) - dsa.Y = new(big.Int).SetBytes(pk.y.bytes) - pk.PublicKey = dsa - return -} - -// parseElGamal parses ElGamal public key material from the given Reader. See -// RFC 4880, section 5.5.2. -func (pk *PublicKey) parseElGamal(r io.Reader) (err error) { - pk.p.bytes, pk.p.bitLength, err = readMPI(r) - if err != nil { - return - } - pk.g.bytes, pk.g.bitLength, err = readMPI(r) - if err != nil { - return - } - pk.y.bytes, pk.y.bitLength, err = readMPI(r) - if err != nil { - return - } - - elgamal := new(elgamal.PublicKey) - elgamal.P = new(big.Int).SetBytes(pk.p.bytes) - elgamal.G = new(big.Int).SetBytes(pk.g.bytes) - elgamal.Y = new(big.Int).SetBytes(pk.y.bytes) - pk.PublicKey = elgamal - return -} - -// SerializeSignaturePrefix writes the prefix for this public key to the given Writer. -// The prefix is used when calculating a signature over this public key. See -// RFC 4880, section 5.2.4. -func (pk *PublicKey) SerializeSignaturePrefix(h io.Writer) { - var pLength uint16 - switch pk.PubKeyAlgo { - case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly: - pLength += 2 + uint16(len(pk.n.bytes)) - pLength += 2 + uint16(len(pk.e.bytes)) - case PubKeyAlgoDSA: - pLength += 2 + uint16(len(pk.p.bytes)) - pLength += 2 + uint16(len(pk.q.bytes)) - pLength += 2 + uint16(len(pk.g.bytes)) - pLength += 2 + uint16(len(pk.y.bytes)) - case PubKeyAlgoElGamal: - pLength += 2 + uint16(len(pk.p.bytes)) - pLength += 2 + uint16(len(pk.g.bytes)) - pLength += 2 + uint16(len(pk.y.bytes)) - case PubKeyAlgoECDSA: - pLength += uint16(pk.ec.byteLen()) - case PubKeyAlgoECDH: - pLength += uint16(pk.ec.byteLen()) - pLength += uint16(pk.ecdh.byteLen()) - default: - panic("unknown public key algorithm") - } - pLength += 6 - h.Write([]byte{0x99, byte(pLength >> 8), byte(pLength)}) - return -} - -func (pk *PublicKey) Serialize(w io.Writer) (err error) { - length := 6 // 6 byte header - - switch pk.PubKeyAlgo { - case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly: - length += 2 + len(pk.n.bytes) - length += 2 + len(pk.e.bytes) - case PubKeyAlgoDSA: - length += 2 + len(pk.p.bytes) - length += 2 + len(pk.q.bytes) - length += 2 + len(pk.g.bytes) - length += 2 + len(pk.y.bytes) - case PubKeyAlgoElGamal: - length += 2 + len(pk.p.bytes) - length += 2 + len(pk.g.bytes) - length += 2 + len(pk.y.bytes) - case PubKeyAlgoECDSA: - length += pk.ec.byteLen() - case PubKeyAlgoECDH: - length += pk.ec.byteLen() - length += pk.ecdh.byteLen() - default: - panic("unknown public key algorithm") - } - - packetType := packetTypePublicKey - if pk.IsSubkey { - packetType = packetTypePublicSubkey - } - err = serializeHeader(w, packetType, length) - if err != nil { - return - } - return pk.serializeWithoutHeaders(w) -} - -// serializeWithoutHeaders marshals the PublicKey to w in the form of an -// OpenPGP public key packet, not including the packet header. -func (pk *PublicKey) serializeWithoutHeaders(w io.Writer) (err error) { - var buf [6]byte - buf[0] = 4 - t := uint32(pk.CreationTime.Unix()) - buf[1] = byte(t >> 24) - buf[2] = byte(t >> 16) - buf[3] = byte(t >> 8) - buf[4] = byte(t) - buf[5] = byte(pk.PubKeyAlgo) - - _, err = w.Write(buf[:]) - if err != nil { - return - } - - switch pk.PubKeyAlgo { - case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly: - return writeMPIs(w, pk.n, pk.e) - case PubKeyAlgoDSA: - return writeMPIs(w, pk.p, pk.q, pk.g, pk.y) - case PubKeyAlgoElGamal: - return writeMPIs(w, pk.p, pk.g, pk.y) - case PubKeyAlgoECDSA: - return pk.ec.serialize(w) - case PubKeyAlgoECDH: - if err = pk.ec.serialize(w); err != nil { - return - } - return pk.ecdh.serialize(w) - } - return errors.InvalidArgumentError("bad public-key algorithm") -} - -// CanSign returns true iff this public key can generate signatures -func (pk *PublicKey) CanSign() bool { - return pk.PubKeyAlgo != PubKeyAlgoRSAEncryptOnly && pk.PubKeyAlgo != PubKeyAlgoElGamal -} - -// VerifySignature returns nil iff sig is a valid signature, made by this -// public key, of the data hashed into signed. signed is mutated by this call. -func (pk *PublicKey) VerifySignature(signed hash.Hash, sig *Signature) (err error) { - if !pk.CanSign() { - return errors.InvalidArgumentError("public key cannot generate signatures") - } - - signed.Write(sig.HashSuffix) - hashBytes := signed.Sum(nil) - - if hashBytes[0] != sig.HashTag[0] || hashBytes[1] != sig.HashTag[1] { - return errors.SignatureError("hash tag doesn't match") - } - - if pk.PubKeyAlgo != sig.PubKeyAlgo { - return errors.InvalidArgumentError("public key and signature use different algorithms") - } - - switch pk.PubKeyAlgo { - case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly: - rsaPublicKey, _ := pk.PublicKey.(*rsa.PublicKey) - err = rsa.VerifyPKCS1v15(rsaPublicKey, sig.Hash, hashBytes, padToKeySize(rsaPublicKey, sig.RSASignature.bytes)) - if err != nil { - return errors.SignatureError("RSA verification failure") - } - return nil - case PubKeyAlgoDSA: - dsaPublicKey, _ := pk.PublicKey.(*dsa.PublicKey) - // Need to truncate hashBytes to match FIPS 186-3 section 4.6. - subgroupSize := (dsaPublicKey.Q.BitLen() + 7) / 8 - if len(hashBytes) > subgroupSize { - hashBytes = hashBytes[:subgroupSize] - } - if !dsa.Verify(dsaPublicKey, hashBytes, new(big.Int).SetBytes(sig.DSASigR.bytes), new(big.Int).SetBytes(sig.DSASigS.bytes)) { - return errors.SignatureError("DSA verification failure") - } - return nil - case PubKeyAlgoECDSA: - ecdsaPublicKey := pk.PublicKey.(*ecdsa.PublicKey) - if !ecdsa.Verify(ecdsaPublicKey, hashBytes, new(big.Int).SetBytes(sig.ECDSASigR.bytes), new(big.Int).SetBytes(sig.ECDSASigS.bytes)) { - return errors.SignatureError("ECDSA verification failure") - } - return nil - default: - return errors.SignatureError("Unsupported public key algorithm used in signature") - } -} - -// VerifySignatureV3 returns nil iff sig is a valid signature, made by this -// public key, of the data hashed into signed. signed is mutated by this call. -func (pk *PublicKey) VerifySignatureV3(signed hash.Hash, sig *SignatureV3) (err error) { - if !pk.CanSign() { - return errors.InvalidArgumentError("public key cannot generate signatures") - } - - suffix := make([]byte, 5) - suffix[0] = byte(sig.SigType) - binary.BigEndian.PutUint32(suffix[1:], uint32(sig.CreationTime.Unix())) - signed.Write(suffix) - hashBytes := signed.Sum(nil) - - if hashBytes[0] != sig.HashTag[0] || hashBytes[1] != sig.HashTag[1] { - return errors.SignatureError("hash tag doesn't match") - } - - if pk.PubKeyAlgo != sig.PubKeyAlgo { - return errors.InvalidArgumentError("public key and signature use different algorithms") - } - - switch pk.PubKeyAlgo { - case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly: - rsaPublicKey := pk.PublicKey.(*rsa.PublicKey) - if err = rsa.VerifyPKCS1v15(rsaPublicKey, sig.Hash, hashBytes, padToKeySize(rsaPublicKey, sig.RSASignature.bytes)); err != nil { - return errors.SignatureError("RSA verification failure") - } - return - case PubKeyAlgoDSA: - dsaPublicKey := pk.PublicKey.(*dsa.PublicKey) - // Need to truncate hashBytes to match FIPS 186-3 section 4.6. - subgroupSize := (dsaPublicKey.Q.BitLen() + 7) / 8 - if len(hashBytes) > subgroupSize { - hashBytes = hashBytes[:subgroupSize] - } - if !dsa.Verify(dsaPublicKey, hashBytes, new(big.Int).SetBytes(sig.DSASigR.bytes), new(big.Int).SetBytes(sig.DSASigS.bytes)) { - return errors.SignatureError("DSA verification failure") - } - return nil - default: - panic("shouldn't happen") - } -} - -// keySignatureHash returns a Hash of the message that needs to be signed for -// pk to assert a subkey relationship to signed. -func keySignatureHash(pk, signed signingKey, hashFunc crypto.Hash) (h hash.Hash, err error) { - if !hashFunc.Available() { - return nil, errors.UnsupportedError("hash function") - } - h = hashFunc.New() - - // RFC 4880, section 5.2.4 - pk.SerializeSignaturePrefix(h) - pk.serializeWithoutHeaders(h) - signed.SerializeSignaturePrefix(h) - signed.serializeWithoutHeaders(h) - return -} - -// VerifyKeySignature returns nil iff sig is a valid signature, made by this -// public key, of signed. -func (pk *PublicKey) VerifyKeySignature(signed *PublicKey, sig *Signature) error { - h, err := keySignatureHash(pk, signed, sig.Hash) - if err != nil { - return err - } - if err = pk.VerifySignature(h, sig); err != nil { - return err - } - - if sig.FlagSign { - // Signing subkeys must be cross-signed. See - // https://www.gnupg.org/faq/subkey-cross-certify.html. - if sig.EmbeddedSignature == nil { - return errors.StructuralError("signing subkey is missing cross-signature") - } - // Verify the cross-signature. This is calculated over the same - // data as the main signature, so we cannot just recursively - // call signed.VerifyKeySignature(...) - if h, err = keySignatureHash(pk, signed, sig.EmbeddedSignature.Hash); err != nil { - return errors.StructuralError("error while hashing for cross-signature: " + err.Error()) - } - if err := signed.VerifySignature(h, sig.EmbeddedSignature); err != nil { - return errors.StructuralError("error while verifying cross-signature: " + err.Error()) - } - } - - return nil -} - -func keyRevocationHash(pk signingKey, hashFunc crypto.Hash) (h hash.Hash, err error) { - if !hashFunc.Available() { - return nil, errors.UnsupportedError("hash function") - } - h = hashFunc.New() - - // RFC 4880, section 5.2.4 - pk.SerializeSignaturePrefix(h) - pk.serializeWithoutHeaders(h) - - return -} - -// VerifyRevocationSignature returns nil iff sig is a valid signature, made by this -// public key. -func (pk *PublicKey) VerifyRevocationSignature(sig *Signature) (err error) { - h, err := keyRevocationHash(pk, sig.Hash) - if err != nil { - return err - } - return pk.VerifySignature(h, sig) -} - -// userIdSignatureHash returns a Hash of the message that needs to be signed -// to assert that pk is a valid key for id. -func userIdSignatureHash(id string, pk *PublicKey, hashFunc crypto.Hash) (h hash.Hash, err error) { - if !hashFunc.Available() { - return nil, errors.UnsupportedError("hash function") - } - h = hashFunc.New() - - // RFC 4880, section 5.2.4 - pk.SerializeSignaturePrefix(h) - pk.serializeWithoutHeaders(h) - - var buf [5]byte - buf[0] = 0xb4 - buf[1] = byte(len(id) >> 24) - buf[2] = byte(len(id) >> 16) - buf[3] = byte(len(id) >> 8) - buf[4] = byte(len(id)) - h.Write(buf[:]) - h.Write([]byte(id)) - - return -} - -// VerifyUserIdSignature returns nil iff sig is a valid signature, made by this -// public key, that id is the identity of pub. -func (pk *PublicKey) VerifyUserIdSignature(id string, pub *PublicKey, sig *Signature) (err error) { - h, err := userIdSignatureHash(id, pub, sig.Hash) - if err != nil { - return err - } - return pk.VerifySignature(h, sig) -} - -// VerifyUserIdSignatureV3 returns nil iff sig is a valid signature, made by this -// public key, that id is the identity of pub. -func (pk *PublicKey) VerifyUserIdSignatureV3(id string, pub *PublicKey, sig *SignatureV3) (err error) { - h, err := userIdSignatureV3Hash(id, pub, sig.Hash) - if err != nil { - return err - } - return pk.VerifySignatureV3(h, sig) -} - -// KeyIdString returns the public key's fingerprint in capital hex -// (e.g. "6C7EE1B8621CC013"). -func (pk *PublicKey) KeyIdString() string { - return fmt.Sprintf("%X", pk.Fingerprint[12:20]) -} - -// KeyIdShortString returns the short form of public key's fingerprint -// in capital hex, as shown by gpg --list-keys (e.g. "621CC013"). -func (pk *PublicKey) KeyIdShortString() string { - return fmt.Sprintf("%X", pk.Fingerprint[16:20]) -} - -// A parsedMPI is used to store the contents of a big integer, along with the -// bit length that was specified in the original input. This allows the MPI to -// be reserialized exactly. -type parsedMPI struct { - bytes []byte - bitLength uint16 -} - -// writeMPIs is a utility function for serializing several big integers to the -// given Writer. -func writeMPIs(w io.Writer, mpis ...parsedMPI) (err error) { - for _, mpi := range mpis { - err = writeMPI(w, mpi.bitLength, mpi.bytes) - if err != nil { - return - } - } - return -} - -// BitLength returns the bit length for the given public key. -func (pk *PublicKey) BitLength() (bitLength uint16, err error) { - switch pk.PubKeyAlgo { - case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly: - bitLength = pk.n.bitLength - case PubKeyAlgoDSA: - bitLength = pk.p.bitLength - case PubKeyAlgoElGamal: - bitLength = pk.p.bitLength - default: - err = errors.InvalidArgumentError("bad public-key algorithm") - } - return -} diff --git a/vendor/golang.org/x/crypto/openpgp/packet/public_key_v3.go b/vendor/golang.org/x/crypto/openpgp/packet/public_key_v3.go deleted file mode 100644 index 5daf7b6cfd..0000000000 --- a/vendor/golang.org/x/crypto/openpgp/packet/public_key_v3.go +++ /dev/null @@ -1,279 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package packet - -import ( - "crypto" - "crypto/md5" - "crypto/rsa" - "encoding/binary" - "fmt" - "hash" - "io" - "math/big" - "strconv" - "time" - - "golang.org/x/crypto/openpgp/errors" -) - -// PublicKeyV3 represents older, version 3 public keys. These keys are less secure and -// should not be used for signing or encrypting. They are supported here only for -// parsing version 3 key material and validating signatures. -// See RFC 4880, section 5.5.2. -type PublicKeyV3 struct { - CreationTime time.Time - DaysToExpire uint16 - PubKeyAlgo PublicKeyAlgorithm - PublicKey *rsa.PublicKey - Fingerprint [16]byte - KeyId uint64 - IsSubkey bool - - n, e parsedMPI -} - -// newRSAPublicKeyV3 returns a PublicKey that wraps the given rsa.PublicKey. -// Included here for testing purposes only. RFC 4880, section 5.5.2: -// "an implementation MUST NOT generate a V3 key, but MAY accept it." -func newRSAPublicKeyV3(creationTime time.Time, pub *rsa.PublicKey) *PublicKeyV3 { - pk := &PublicKeyV3{ - CreationTime: creationTime, - PublicKey: pub, - n: fromBig(pub.N), - e: fromBig(big.NewInt(int64(pub.E))), - } - - pk.setFingerPrintAndKeyId() - return pk -} - -func (pk *PublicKeyV3) parse(r io.Reader) (err error) { - // RFC 4880, section 5.5.2 - var buf [8]byte - if _, err = readFull(r, buf[:]); err != nil { - return - } - if buf[0] < 2 || buf[0] > 3 { - return errors.UnsupportedError("public key version") - } - pk.CreationTime = time.Unix(int64(uint32(buf[1])<<24|uint32(buf[2])<<16|uint32(buf[3])<<8|uint32(buf[4])), 0) - pk.DaysToExpire = binary.BigEndian.Uint16(buf[5:7]) - pk.PubKeyAlgo = PublicKeyAlgorithm(buf[7]) - switch pk.PubKeyAlgo { - case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly: - err = pk.parseRSA(r) - default: - err = errors.UnsupportedError("public key type: " + strconv.Itoa(int(pk.PubKeyAlgo))) - } - if err != nil { - return - } - - pk.setFingerPrintAndKeyId() - return -} - -func (pk *PublicKeyV3) setFingerPrintAndKeyId() { - // RFC 4880, section 12.2 - fingerPrint := md5.New() - fingerPrint.Write(pk.n.bytes) - fingerPrint.Write(pk.e.bytes) - fingerPrint.Sum(pk.Fingerprint[:0]) - pk.KeyId = binary.BigEndian.Uint64(pk.n.bytes[len(pk.n.bytes)-8:]) -} - -// parseRSA parses RSA public key material from the given Reader. See RFC 4880, -// section 5.5.2. -func (pk *PublicKeyV3) parseRSA(r io.Reader) (err error) { - if pk.n.bytes, pk.n.bitLength, err = readMPI(r); err != nil { - return - } - if pk.e.bytes, pk.e.bitLength, err = readMPI(r); err != nil { - return - } - - // RFC 4880 Section 12.2 requires the low 8 bytes of the - // modulus to form the key id. - if len(pk.n.bytes) < 8 { - return errors.StructuralError("v3 public key modulus is too short") - } - if len(pk.e.bytes) > 3 { - err = errors.UnsupportedError("large public exponent") - return - } - rsa := &rsa.PublicKey{N: new(big.Int).SetBytes(pk.n.bytes)} - for i := 0; i < len(pk.e.bytes); i++ { - rsa.E <<= 8 - rsa.E |= int(pk.e.bytes[i]) - } - pk.PublicKey = rsa - return -} - -// SerializeSignaturePrefix writes the prefix for this public key to the given Writer. -// The prefix is used when calculating a signature over this public key. See -// RFC 4880, section 5.2.4. -func (pk *PublicKeyV3) SerializeSignaturePrefix(w io.Writer) { - var pLength uint16 - switch pk.PubKeyAlgo { - case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly: - pLength += 2 + uint16(len(pk.n.bytes)) - pLength += 2 + uint16(len(pk.e.bytes)) - default: - panic("unknown public key algorithm") - } - pLength += 6 - w.Write([]byte{0x99, byte(pLength >> 8), byte(pLength)}) - return -} - -func (pk *PublicKeyV3) Serialize(w io.Writer) (err error) { - length := 8 // 8 byte header - - switch pk.PubKeyAlgo { - case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly: - length += 2 + len(pk.n.bytes) - length += 2 + len(pk.e.bytes) - default: - panic("unknown public key algorithm") - } - - packetType := packetTypePublicKey - if pk.IsSubkey { - packetType = packetTypePublicSubkey - } - if err = serializeHeader(w, packetType, length); err != nil { - return - } - return pk.serializeWithoutHeaders(w) -} - -// serializeWithoutHeaders marshals the PublicKey to w in the form of an -// OpenPGP public key packet, not including the packet header. -func (pk *PublicKeyV3) serializeWithoutHeaders(w io.Writer) (err error) { - var buf [8]byte - // Version 3 - buf[0] = 3 - // Creation time - t := uint32(pk.CreationTime.Unix()) - buf[1] = byte(t >> 24) - buf[2] = byte(t >> 16) - buf[3] = byte(t >> 8) - buf[4] = byte(t) - // Days to expire - buf[5] = byte(pk.DaysToExpire >> 8) - buf[6] = byte(pk.DaysToExpire) - // Public key algorithm - buf[7] = byte(pk.PubKeyAlgo) - - if _, err = w.Write(buf[:]); err != nil { - return - } - - switch pk.PubKeyAlgo { - case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly: - return writeMPIs(w, pk.n, pk.e) - } - return errors.InvalidArgumentError("bad public-key algorithm") -} - -// CanSign returns true iff this public key can generate signatures -func (pk *PublicKeyV3) CanSign() bool { - return pk.PubKeyAlgo != PubKeyAlgoRSAEncryptOnly -} - -// VerifySignatureV3 returns nil iff sig is a valid signature, made by this -// public key, of the data hashed into signed. signed is mutated by this call. -func (pk *PublicKeyV3) VerifySignatureV3(signed hash.Hash, sig *SignatureV3) (err error) { - if !pk.CanSign() { - return errors.InvalidArgumentError("public key cannot generate signatures") - } - - suffix := make([]byte, 5) - suffix[0] = byte(sig.SigType) - binary.BigEndian.PutUint32(suffix[1:], uint32(sig.CreationTime.Unix())) - signed.Write(suffix) - hashBytes := signed.Sum(nil) - - if hashBytes[0] != sig.HashTag[0] || hashBytes[1] != sig.HashTag[1] { - return errors.SignatureError("hash tag doesn't match") - } - - if pk.PubKeyAlgo != sig.PubKeyAlgo { - return errors.InvalidArgumentError("public key and signature use different algorithms") - } - - switch pk.PubKeyAlgo { - case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly: - if err = rsa.VerifyPKCS1v15(pk.PublicKey, sig.Hash, hashBytes, sig.RSASignature.bytes); err != nil { - return errors.SignatureError("RSA verification failure") - } - return - default: - // V3 public keys only support RSA. - panic("shouldn't happen") - } -} - -// VerifyUserIdSignatureV3 returns nil iff sig is a valid signature, made by this -// public key, that id is the identity of pub. -func (pk *PublicKeyV3) VerifyUserIdSignatureV3(id string, pub *PublicKeyV3, sig *SignatureV3) (err error) { - h, err := userIdSignatureV3Hash(id, pk, sig.Hash) - if err != nil { - return err - } - return pk.VerifySignatureV3(h, sig) -} - -// VerifyKeySignatureV3 returns nil iff sig is a valid signature, made by this -// public key, of signed. -func (pk *PublicKeyV3) VerifyKeySignatureV3(signed *PublicKeyV3, sig *SignatureV3) (err error) { - h, err := keySignatureHash(pk, signed, sig.Hash) - if err != nil { - return err - } - return pk.VerifySignatureV3(h, sig) -} - -// userIdSignatureV3Hash returns a Hash of the message that needs to be signed -// to assert that pk is a valid key for id. -func userIdSignatureV3Hash(id string, pk signingKey, hfn crypto.Hash) (h hash.Hash, err error) { - if !hfn.Available() { - return nil, errors.UnsupportedError("hash function") - } - h = hfn.New() - - // RFC 4880, section 5.2.4 - pk.SerializeSignaturePrefix(h) - pk.serializeWithoutHeaders(h) - - h.Write([]byte(id)) - - return -} - -// KeyIdString returns the public key's fingerprint in capital hex -// (e.g. "6C7EE1B8621CC013"). -func (pk *PublicKeyV3) KeyIdString() string { - return fmt.Sprintf("%X", pk.KeyId) -} - -// KeyIdShortString returns the short form of public key's fingerprint -// in capital hex, as shown by gpg --list-keys (e.g. "621CC013"). -func (pk *PublicKeyV3) KeyIdShortString() string { - return fmt.Sprintf("%X", pk.KeyId&0xFFFFFFFF) -} - -// BitLength returns the bit length for the given public key. -func (pk *PublicKeyV3) BitLength() (bitLength uint16, err error) { - switch pk.PubKeyAlgo { - case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly: - bitLength = pk.n.bitLength - default: - err = errors.InvalidArgumentError("bad public-key algorithm") - } - return -} diff --git a/vendor/golang.org/x/crypto/openpgp/packet/reader.go b/vendor/golang.org/x/crypto/openpgp/packet/reader.go deleted file mode 100644 index 34bc7c613e..0000000000 --- a/vendor/golang.org/x/crypto/openpgp/packet/reader.go +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package packet - -import ( - "golang.org/x/crypto/openpgp/errors" - "io" -) - -// Reader reads packets from an io.Reader and allows packets to be 'unread' so -// that they result from the next call to Next. -type Reader struct { - q []Packet - readers []io.Reader -} - -// New io.Readers are pushed when a compressed or encrypted packet is processed -// and recursively treated as a new source of packets. However, a carefully -// crafted packet can trigger an infinite recursive sequence of packets. See -// http://mumble.net/~campbell/misc/pgp-quine -// https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2013-4402 -// This constant limits the number of recursive packets that may be pushed. -const maxReaders = 32 - -// Next returns the most recently unread Packet, or reads another packet from -// the top-most io.Reader. Unknown packet types are skipped. -func (r *Reader) Next() (p Packet, err error) { - if len(r.q) > 0 { - p = r.q[len(r.q)-1] - r.q = r.q[:len(r.q)-1] - return - } - - for len(r.readers) > 0 { - p, err = Read(r.readers[len(r.readers)-1]) - if err == nil { - return - } - if err == io.EOF { - r.readers = r.readers[:len(r.readers)-1] - continue - } - if _, ok := err.(errors.UnknownPacketTypeError); !ok { - return nil, err - } - } - - return nil, io.EOF -} - -// Push causes the Reader to start reading from a new io.Reader. When an EOF -// error is seen from the new io.Reader, it is popped and the Reader continues -// to read from the next most recent io.Reader. Push returns a StructuralError -// if pushing the reader would exceed the maximum recursion level, otherwise it -// returns nil. -func (r *Reader) Push(reader io.Reader) (err error) { - if len(r.readers) >= maxReaders { - return errors.StructuralError("too many layers of packets") - } - r.readers = append(r.readers, reader) - return nil -} - -// Unread causes the given Packet to be returned from the next call to Next. -func (r *Reader) Unread(p Packet) { - r.q = append(r.q, p) -} - -func NewReader(r io.Reader) *Reader { - return &Reader{ - q: nil, - readers: []io.Reader{r}, - } -} diff --git a/vendor/golang.org/x/crypto/openpgp/packet/signature.go b/vendor/golang.org/x/crypto/openpgp/packet/signature.go deleted file mode 100644 index b2a24a5323..0000000000 --- a/vendor/golang.org/x/crypto/openpgp/packet/signature.go +++ /dev/null @@ -1,731 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package packet - -import ( - "bytes" - "crypto" - "crypto/dsa" - "crypto/ecdsa" - "encoding/asn1" - "encoding/binary" - "hash" - "io" - "math/big" - "strconv" - "time" - - "golang.org/x/crypto/openpgp/errors" - "golang.org/x/crypto/openpgp/s2k" -) - -const ( - // See RFC 4880, section 5.2.3.21 for details. - KeyFlagCertify = 1 << iota - KeyFlagSign - KeyFlagEncryptCommunications - KeyFlagEncryptStorage -) - -// Signature represents a signature. See RFC 4880, section 5.2. -type Signature struct { - SigType SignatureType - PubKeyAlgo PublicKeyAlgorithm - Hash crypto.Hash - - // HashSuffix is extra data that is hashed in after the signed data. - HashSuffix []byte - // HashTag contains the first two bytes of the hash for fast rejection - // of bad signed data. - HashTag [2]byte - CreationTime time.Time - - RSASignature parsedMPI - DSASigR, DSASigS parsedMPI - ECDSASigR, ECDSASigS parsedMPI - - // rawSubpackets contains the unparsed subpackets, in order. - rawSubpackets []outputSubpacket - - // The following are optional so are nil when not included in the - // signature. - - SigLifetimeSecs, KeyLifetimeSecs *uint32 - PreferredSymmetric, PreferredHash, PreferredCompression []uint8 - IssuerKeyId *uint64 - IsPrimaryId *bool - - // FlagsValid is set if any flags were given. See RFC 4880, section - // 5.2.3.21 for details. - FlagsValid bool - FlagCertify, FlagSign, FlagEncryptCommunications, FlagEncryptStorage bool - - // RevocationReason is set if this signature has been revoked. - // See RFC 4880, section 5.2.3.23 for details. - RevocationReason *uint8 - RevocationReasonText string - - // MDC is set if this signature has a feature packet that indicates - // support for MDC subpackets. - MDC bool - - // EmbeddedSignature, if non-nil, is a signature of the parent key, by - // this key. This prevents an attacker from claiming another's signing - // subkey as their own. - EmbeddedSignature *Signature - - outSubpackets []outputSubpacket -} - -func (sig *Signature) parse(r io.Reader) (err error) { - // RFC 4880, section 5.2.3 - var buf [5]byte - _, err = readFull(r, buf[:1]) - if err != nil { - return - } - if buf[0] != 4 { - err = errors.UnsupportedError("signature packet version " + strconv.Itoa(int(buf[0]))) - return - } - - _, err = readFull(r, buf[:5]) - if err != nil { - return - } - sig.SigType = SignatureType(buf[0]) - sig.PubKeyAlgo = PublicKeyAlgorithm(buf[1]) - switch sig.PubKeyAlgo { - case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly, PubKeyAlgoDSA, PubKeyAlgoECDSA: - default: - err = errors.UnsupportedError("public key algorithm " + strconv.Itoa(int(sig.PubKeyAlgo))) - return - } - - var ok bool - sig.Hash, ok = s2k.HashIdToHash(buf[2]) - if !ok { - return errors.UnsupportedError("hash function " + strconv.Itoa(int(buf[2]))) - } - - hashedSubpacketsLength := int(buf[3])<<8 | int(buf[4]) - l := 6 + hashedSubpacketsLength - sig.HashSuffix = make([]byte, l+6) - sig.HashSuffix[0] = 4 - copy(sig.HashSuffix[1:], buf[:5]) - hashedSubpackets := sig.HashSuffix[6:l] - _, err = readFull(r, hashedSubpackets) - if err != nil { - return - } - // See RFC 4880, section 5.2.4 - trailer := sig.HashSuffix[l:] - trailer[0] = 4 - trailer[1] = 0xff - trailer[2] = uint8(l >> 24) - trailer[3] = uint8(l >> 16) - trailer[4] = uint8(l >> 8) - trailer[5] = uint8(l) - - err = parseSignatureSubpackets(sig, hashedSubpackets, true) - if err != nil { - return - } - - _, err = readFull(r, buf[:2]) - if err != nil { - return - } - unhashedSubpacketsLength := int(buf[0])<<8 | int(buf[1]) - unhashedSubpackets := make([]byte, unhashedSubpacketsLength) - _, err = readFull(r, unhashedSubpackets) - if err != nil { - return - } - err = parseSignatureSubpackets(sig, unhashedSubpackets, false) - if err != nil { - return - } - - _, err = readFull(r, sig.HashTag[:2]) - if err != nil { - return - } - - switch sig.PubKeyAlgo { - case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly: - sig.RSASignature.bytes, sig.RSASignature.bitLength, err = readMPI(r) - case PubKeyAlgoDSA: - sig.DSASigR.bytes, sig.DSASigR.bitLength, err = readMPI(r) - if err == nil { - sig.DSASigS.bytes, sig.DSASigS.bitLength, err = readMPI(r) - } - case PubKeyAlgoECDSA: - sig.ECDSASigR.bytes, sig.ECDSASigR.bitLength, err = readMPI(r) - if err == nil { - sig.ECDSASigS.bytes, sig.ECDSASigS.bitLength, err = readMPI(r) - } - default: - panic("unreachable") - } - return -} - -// parseSignatureSubpackets parses subpackets of the main signature packet. See -// RFC 4880, section 5.2.3.1. -func parseSignatureSubpackets(sig *Signature, subpackets []byte, isHashed bool) (err error) { - for len(subpackets) > 0 { - subpackets, err = parseSignatureSubpacket(sig, subpackets, isHashed) - if err != nil { - return - } - } - - if sig.CreationTime.IsZero() { - err = errors.StructuralError("no creation time in signature") - } - - return -} - -type signatureSubpacketType uint8 - -const ( - creationTimeSubpacket signatureSubpacketType = 2 - signatureExpirationSubpacket signatureSubpacketType = 3 - keyExpirationSubpacket signatureSubpacketType = 9 - prefSymmetricAlgosSubpacket signatureSubpacketType = 11 - issuerSubpacket signatureSubpacketType = 16 - prefHashAlgosSubpacket signatureSubpacketType = 21 - prefCompressionSubpacket signatureSubpacketType = 22 - primaryUserIdSubpacket signatureSubpacketType = 25 - keyFlagsSubpacket signatureSubpacketType = 27 - reasonForRevocationSubpacket signatureSubpacketType = 29 - featuresSubpacket signatureSubpacketType = 30 - embeddedSignatureSubpacket signatureSubpacketType = 32 -) - -// parseSignatureSubpacket parses a single subpacket. len(subpacket) is >= 1. -func parseSignatureSubpacket(sig *Signature, subpacket []byte, isHashed bool) (rest []byte, err error) { - // RFC 4880, section 5.2.3.1 - var ( - length uint32 - packetType signatureSubpacketType - isCritical bool - ) - switch { - case subpacket[0] < 192: - length = uint32(subpacket[0]) - subpacket = subpacket[1:] - case subpacket[0] < 255: - if len(subpacket) < 2 { - goto Truncated - } - length = uint32(subpacket[0]-192)<<8 + uint32(subpacket[1]) + 192 - subpacket = subpacket[2:] - default: - if len(subpacket) < 5 { - goto Truncated - } - length = uint32(subpacket[1])<<24 | - uint32(subpacket[2])<<16 | - uint32(subpacket[3])<<8 | - uint32(subpacket[4]) - subpacket = subpacket[5:] - } - if length > uint32(len(subpacket)) { - goto Truncated - } - rest = subpacket[length:] - subpacket = subpacket[:length] - if len(subpacket) == 0 { - err = errors.StructuralError("zero length signature subpacket") - return - } - packetType = signatureSubpacketType(subpacket[0] & 0x7f) - isCritical = subpacket[0]&0x80 == 0x80 - subpacket = subpacket[1:] - sig.rawSubpackets = append(sig.rawSubpackets, outputSubpacket{isHashed, packetType, isCritical, subpacket}) - switch packetType { - case creationTimeSubpacket: - if !isHashed { - err = errors.StructuralError("signature creation time in non-hashed area") - return - } - if len(subpacket) != 4 { - err = errors.StructuralError("signature creation time not four bytes") - return - } - t := binary.BigEndian.Uint32(subpacket) - sig.CreationTime = time.Unix(int64(t), 0) - case signatureExpirationSubpacket: - // Signature expiration time, section 5.2.3.10 - if !isHashed { - return - } - if len(subpacket) != 4 { - err = errors.StructuralError("expiration subpacket with bad length") - return - } - sig.SigLifetimeSecs = new(uint32) - *sig.SigLifetimeSecs = binary.BigEndian.Uint32(subpacket) - case keyExpirationSubpacket: - // Key expiration time, section 5.2.3.6 - if !isHashed { - return - } - if len(subpacket) != 4 { - err = errors.StructuralError("key expiration subpacket with bad length") - return - } - sig.KeyLifetimeSecs = new(uint32) - *sig.KeyLifetimeSecs = binary.BigEndian.Uint32(subpacket) - case prefSymmetricAlgosSubpacket: - // Preferred symmetric algorithms, section 5.2.3.7 - if !isHashed { - return - } - sig.PreferredSymmetric = make([]byte, len(subpacket)) - copy(sig.PreferredSymmetric, subpacket) - case issuerSubpacket: - // Issuer, section 5.2.3.5 - if len(subpacket) != 8 { - err = errors.StructuralError("issuer subpacket with bad length") - return - } - sig.IssuerKeyId = new(uint64) - *sig.IssuerKeyId = binary.BigEndian.Uint64(subpacket) - case prefHashAlgosSubpacket: - // Preferred hash algorithms, section 5.2.3.8 - if !isHashed { - return - } - sig.PreferredHash = make([]byte, len(subpacket)) - copy(sig.PreferredHash, subpacket) - case prefCompressionSubpacket: - // Preferred compression algorithms, section 5.2.3.9 - if !isHashed { - return - } - sig.PreferredCompression = make([]byte, len(subpacket)) - copy(sig.PreferredCompression, subpacket) - case primaryUserIdSubpacket: - // Primary User ID, section 5.2.3.19 - if !isHashed { - return - } - if len(subpacket) != 1 { - err = errors.StructuralError("primary user id subpacket with bad length") - return - } - sig.IsPrimaryId = new(bool) - if subpacket[0] > 0 { - *sig.IsPrimaryId = true - } - case keyFlagsSubpacket: - // Key flags, section 5.2.3.21 - if !isHashed { - return - } - if len(subpacket) == 0 { - err = errors.StructuralError("empty key flags subpacket") - return - } - sig.FlagsValid = true - if subpacket[0]&KeyFlagCertify != 0 { - sig.FlagCertify = true - } - if subpacket[0]&KeyFlagSign != 0 { - sig.FlagSign = true - } - if subpacket[0]&KeyFlagEncryptCommunications != 0 { - sig.FlagEncryptCommunications = true - } - if subpacket[0]&KeyFlagEncryptStorage != 0 { - sig.FlagEncryptStorage = true - } - case reasonForRevocationSubpacket: - // Reason For Revocation, section 5.2.3.23 - if !isHashed { - return - } - if len(subpacket) == 0 { - err = errors.StructuralError("empty revocation reason subpacket") - return - } - sig.RevocationReason = new(uint8) - *sig.RevocationReason = subpacket[0] - sig.RevocationReasonText = string(subpacket[1:]) - case featuresSubpacket: - // Features subpacket, section 5.2.3.24 specifies a very general - // mechanism for OpenPGP implementations to signal support for new - // features. In practice, the subpacket is used exclusively to - // indicate support for MDC-protected encryption. - sig.MDC = len(subpacket) >= 1 && subpacket[0]&1 == 1 - case embeddedSignatureSubpacket: - // Only usage is in signatures that cross-certify - // signing subkeys. section 5.2.3.26 describes the - // format, with its usage described in section 11.1 - if sig.EmbeddedSignature != nil { - err = errors.StructuralError("Cannot have multiple embedded signatures") - return - } - sig.EmbeddedSignature = new(Signature) - // Embedded signatures are required to be v4 signatures see - // section 12.1. However, we only parse v4 signatures in this - // file anyway. - if err := sig.EmbeddedSignature.parse(bytes.NewBuffer(subpacket)); err != nil { - return nil, err - } - if sigType := sig.EmbeddedSignature.SigType; sigType != SigTypePrimaryKeyBinding { - return nil, errors.StructuralError("cross-signature has unexpected type " + strconv.Itoa(int(sigType))) - } - default: - if isCritical { - err = errors.UnsupportedError("unknown critical signature subpacket type " + strconv.Itoa(int(packetType))) - return - } - } - return - -Truncated: - err = errors.StructuralError("signature subpacket truncated") - return -} - -// subpacketLengthLength returns the length, in bytes, of an encoded length value. -func subpacketLengthLength(length int) int { - if length < 192 { - return 1 - } - if length < 16320 { - return 2 - } - return 5 -} - -// serializeSubpacketLength marshals the given length into to. -func serializeSubpacketLength(to []byte, length int) int { - // RFC 4880, Section 4.2.2. - if length < 192 { - to[0] = byte(length) - return 1 - } - if length < 16320 { - length -= 192 - to[0] = byte((length >> 8) + 192) - to[1] = byte(length) - return 2 - } - to[0] = 255 - to[1] = byte(length >> 24) - to[2] = byte(length >> 16) - to[3] = byte(length >> 8) - to[4] = byte(length) - return 5 -} - -// subpacketsLength returns the serialized length, in bytes, of the given -// subpackets. -func subpacketsLength(subpackets []outputSubpacket, hashed bool) (length int) { - for _, subpacket := range subpackets { - if subpacket.hashed == hashed { - length += subpacketLengthLength(len(subpacket.contents) + 1) - length += 1 // type byte - length += len(subpacket.contents) - } - } - return -} - -// serializeSubpackets marshals the given subpackets into to. -func serializeSubpackets(to []byte, subpackets []outputSubpacket, hashed bool) { - for _, subpacket := range subpackets { - if subpacket.hashed == hashed { - n := serializeSubpacketLength(to, len(subpacket.contents)+1) - to[n] = byte(subpacket.subpacketType) - to = to[1+n:] - n = copy(to, subpacket.contents) - to = to[n:] - } - } - return -} - -// KeyExpired returns whether sig is a self-signature of a key that has -// expired. -func (sig *Signature) KeyExpired(currentTime time.Time) bool { - if sig.KeyLifetimeSecs == nil { - return false - } - expiry := sig.CreationTime.Add(time.Duration(*sig.KeyLifetimeSecs) * time.Second) - return currentTime.After(expiry) -} - -// buildHashSuffix constructs the HashSuffix member of sig in preparation for signing. -func (sig *Signature) buildHashSuffix() (err error) { - hashedSubpacketsLen := subpacketsLength(sig.outSubpackets, true) - - var ok bool - l := 6 + hashedSubpacketsLen - sig.HashSuffix = make([]byte, l+6) - sig.HashSuffix[0] = 4 - sig.HashSuffix[1] = uint8(sig.SigType) - sig.HashSuffix[2] = uint8(sig.PubKeyAlgo) - sig.HashSuffix[3], ok = s2k.HashToHashId(sig.Hash) - if !ok { - sig.HashSuffix = nil - return errors.InvalidArgumentError("hash cannot be represented in OpenPGP: " + strconv.Itoa(int(sig.Hash))) - } - sig.HashSuffix[4] = byte(hashedSubpacketsLen >> 8) - sig.HashSuffix[5] = byte(hashedSubpacketsLen) - serializeSubpackets(sig.HashSuffix[6:l], sig.outSubpackets, true) - trailer := sig.HashSuffix[l:] - trailer[0] = 4 - trailer[1] = 0xff - trailer[2] = byte(l >> 24) - trailer[3] = byte(l >> 16) - trailer[4] = byte(l >> 8) - trailer[5] = byte(l) - return -} - -func (sig *Signature) signPrepareHash(h hash.Hash) (digest []byte, err error) { - err = sig.buildHashSuffix() - if err != nil { - return - } - - h.Write(sig.HashSuffix) - digest = h.Sum(nil) - copy(sig.HashTag[:], digest) - return -} - -// Sign signs a message with a private key. The hash, h, must contain -// the hash of the message to be signed and will be mutated by this function. -// On success, the signature is stored in sig. Call Serialize to write it out. -// If config is nil, sensible defaults will be used. -func (sig *Signature) Sign(h hash.Hash, priv *PrivateKey, config *Config) (err error) { - sig.outSubpackets = sig.buildSubpackets() - digest, err := sig.signPrepareHash(h) - if err != nil { - return - } - - switch priv.PubKeyAlgo { - case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly: - // supports both *rsa.PrivateKey and crypto.Signer - sig.RSASignature.bytes, err = priv.PrivateKey.(crypto.Signer).Sign(config.Random(), digest, sig.Hash) - sig.RSASignature.bitLength = uint16(8 * len(sig.RSASignature.bytes)) - case PubKeyAlgoDSA: - dsaPriv := priv.PrivateKey.(*dsa.PrivateKey) - - // Need to truncate hashBytes to match FIPS 186-3 section 4.6. - subgroupSize := (dsaPriv.Q.BitLen() + 7) / 8 - if len(digest) > subgroupSize { - digest = digest[:subgroupSize] - } - r, s, err := dsa.Sign(config.Random(), dsaPriv, digest) - if err == nil { - sig.DSASigR.bytes = r.Bytes() - sig.DSASigR.bitLength = uint16(8 * len(sig.DSASigR.bytes)) - sig.DSASigS.bytes = s.Bytes() - sig.DSASigS.bitLength = uint16(8 * len(sig.DSASigS.bytes)) - } - case PubKeyAlgoECDSA: - var r, s *big.Int - if pk, ok := priv.PrivateKey.(*ecdsa.PrivateKey); ok { - // direct support, avoid asn1 wrapping/unwrapping - r, s, err = ecdsa.Sign(config.Random(), pk, digest) - } else { - var b []byte - b, err = priv.PrivateKey.(crypto.Signer).Sign(config.Random(), digest, sig.Hash) - if err == nil { - r, s, err = unwrapECDSASig(b) - } - } - if err == nil { - sig.ECDSASigR = fromBig(r) - sig.ECDSASigS = fromBig(s) - } - default: - err = errors.UnsupportedError("public key algorithm: " + strconv.Itoa(int(sig.PubKeyAlgo))) - } - - return -} - -// unwrapECDSASig parses the two integer components of an ASN.1-encoded ECDSA -// signature. -func unwrapECDSASig(b []byte) (r, s *big.Int, err error) { - var ecsdaSig struct { - R, S *big.Int - } - _, err = asn1.Unmarshal(b, &ecsdaSig) - if err != nil { - return - } - return ecsdaSig.R, ecsdaSig.S, nil -} - -// SignUserId computes a signature from priv, asserting that pub is a valid -// key for the identity id. On success, the signature is stored in sig. Call -// Serialize to write it out. -// If config is nil, sensible defaults will be used. -func (sig *Signature) SignUserId(id string, pub *PublicKey, priv *PrivateKey, config *Config) error { - h, err := userIdSignatureHash(id, pub, sig.Hash) - if err != nil { - return err - } - return sig.Sign(h, priv, config) -} - -// SignKey computes a signature from priv, asserting that pub is a subkey. On -// success, the signature is stored in sig. Call Serialize to write it out. -// If config is nil, sensible defaults will be used. -func (sig *Signature) SignKey(pub *PublicKey, priv *PrivateKey, config *Config) error { - h, err := keySignatureHash(&priv.PublicKey, pub, sig.Hash) - if err != nil { - return err - } - return sig.Sign(h, priv, config) -} - -// Serialize marshals sig to w. Sign, SignUserId or SignKey must have been -// called first. -func (sig *Signature) Serialize(w io.Writer) (err error) { - if len(sig.outSubpackets) == 0 { - sig.outSubpackets = sig.rawSubpackets - } - if sig.RSASignature.bytes == nil && sig.DSASigR.bytes == nil && sig.ECDSASigR.bytes == nil { - return errors.InvalidArgumentError("Signature: need to call Sign, SignUserId or SignKey before Serialize") - } - - sigLength := 0 - switch sig.PubKeyAlgo { - case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly: - sigLength = 2 + len(sig.RSASignature.bytes) - case PubKeyAlgoDSA: - sigLength = 2 + len(sig.DSASigR.bytes) - sigLength += 2 + len(sig.DSASigS.bytes) - case PubKeyAlgoECDSA: - sigLength = 2 + len(sig.ECDSASigR.bytes) - sigLength += 2 + len(sig.ECDSASigS.bytes) - default: - panic("impossible") - } - - unhashedSubpacketsLen := subpacketsLength(sig.outSubpackets, false) - length := len(sig.HashSuffix) - 6 /* trailer not included */ + - 2 /* length of unhashed subpackets */ + unhashedSubpacketsLen + - 2 /* hash tag */ + sigLength - err = serializeHeader(w, packetTypeSignature, length) - if err != nil { - return - } - - _, err = w.Write(sig.HashSuffix[:len(sig.HashSuffix)-6]) - if err != nil { - return - } - - unhashedSubpackets := make([]byte, 2+unhashedSubpacketsLen) - unhashedSubpackets[0] = byte(unhashedSubpacketsLen >> 8) - unhashedSubpackets[1] = byte(unhashedSubpacketsLen) - serializeSubpackets(unhashedSubpackets[2:], sig.outSubpackets, false) - - _, err = w.Write(unhashedSubpackets) - if err != nil { - return - } - _, err = w.Write(sig.HashTag[:]) - if err != nil { - return - } - - switch sig.PubKeyAlgo { - case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly: - err = writeMPIs(w, sig.RSASignature) - case PubKeyAlgoDSA: - err = writeMPIs(w, sig.DSASigR, sig.DSASigS) - case PubKeyAlgoECDSA: - err = writeMPIs(w, sig.ECDSASigR, sig.ECDSASigS) - default: - panic("impossible") - } - return -} - -// outputSubpacket represents a subpacket to be marshaled. -type outputSubpacket struct { - hashed bool // true if this subpacket is in the hashed area. - subpacketType signatureSubpacketType - isCritical bool - contents []byte -} - -func (sig *Signature) buildSubpackets() (subpackets []outputSubpacket) { - creationTime := make([]byte, 4) - binary.BigEndian.PutUint32(creationTime, uint32(sig.CreationTime.Unix())) - subpackets = append(subpackets, outputSubpacket{true, creationTimeSubpacket, false, creationTime}) - - if sig.IssuerKeyId != nil { - keyId := make([]byte, 8) - binary.BigEndian.PutUint64(keyId, *sig.IssuerKeyId) - subpackets = append(subpackets, outputSubpacket{true, issuerSubpacket, false, keyId}) - } - - if sig.SigLifetimeSecs != nil && *sig.SigLifetimeSecs != 0 { - sigLifetime := make([]byte, 4) - binary.BigEndian.PutUint32(sigLifetime, *sig.SigLifetimeSecs) - subpackets = append(subpackets, outputSubpacket{true, signatureExpirationSubpacket, true, sigLifetime}) - } - - // Key flags may only appear in self-signatures or certification signatures. - - if sig.FlagsValid { - var flags byte - if sig.FlagCertify { - flags |= KeyFlagCertify - } - if sig.FlagSign { - flags |= KeyFlagSign - } - if sig.FlagEncryptCommunications { - flags |= KeyFlagEncryptCommunications - } - if sig.FlagEncryptStorage { - flags |= KeyFlagEncryptStorage - } - subpackets = append(subpackets, outputSubpacket{true, keyFlagsSubpacket, false, []byte{flags}}) - } - - // The following subpackets may only appear in self-signatures - - if sig.KeyLifetimeSecs != nil && *sig.KeyLifetimeSecs != 0 { - keyLifetime := make([]byte, 4) - binary.BigEndian.PutUint32(keyLifetime, *sig.KeyLifetimeSecs) - subpackets = append(subpackets, outputSubpacket{true, keyExpirationSubpacket, true, keyLifetime}) - } - - if sig.IsPrimaryId != nil && *sig.IsPrimaryId { - subpackets = append(subpackets, outputSubpacket{true, primaryUserIdSubpacket, false, []byte{1}}) - } - - if len(sig.PreferredSymmetric) > 0 { - subpackets = append(subpackets, outputSubpacket{true, prefSymmetricAlgosSubpacket, false, sig.PreferredSymmetric}) - } - - if len(sig.PreferredHash) > 0 { - subpackets = append(subpackets, outputSubpacket{true, prefHashAlgosSubpacket, false, sig.PreferredHash}) - } - - if len(sig.PreferredCompression) > 0 { - subpackets = append(subpackets, outputSubpacket{true, prefCompressionSubpacket, false, sig.PreferredCompression}) - } - - return -} diff --git a/vendor/golang.org/x/crypto/openpgp/packet/signature_v3.go b/vendor/golang.org/x/crypto/openpgp/packet/signature_v3.go deleted file mode 100644 index 6edff88934..0000000000 --- a/vendor/golang.org/x/crypto/openpgp/packet/signature_v3.go +++ /dev/null @@ -1,146 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package packet - -import ( - "crypto" - "encoding/binary" - "fmt" - "io" - "strconv" - "time" - - "golang.org/x/crypto/openpgp/errors" - "golang.org/x/crypto/openpgp/s2k" -) - -// SignatureV3 represents older version 3 signatures. These signatures are less secure -// than version 4 and should not be used to create new signatures. They are included -// here for backwards compatibility to read and validate with older key material. -// See RFC 4880, section 5.2.2. -type SignatureV3 struct { - SigType SignatureType - CreationTime time.Time - IssuerKeyId uint64 - PubKeyAlgo PublicKeyAlgorithm - Hash crypto.Hash - HashTag [2]byte - - RSASignature parsedMPI - DSASigR, DSASigS parsedMPI -} - -func (sig *SignatureV3) parse(r io.Reader) (err error) { - // RFC 4880, section 5.2.2 - var buf [8]byte - if _, err = readFull(r, buf[:1]); err != nil { - return - } - if buf[0] < 2 || buf[0] > 3 { - err = errors.UnsupportedError("signature packet version " + strconv.Itoa(int(buf[0]))) - return - } - if _, err = readFull(r, buf[:1]); err != nil { - return - } - if buf[0] != 5 { - err = errors.UnsupportedError( - "invalid hashed material length " + strconv.Itoa(int(buf[0]))) - return - } - - // Read hashed material: signature type + creation time - if _, err = readFull(r, buf[:5]); err != nil { - return - } - sig.SigType = SignatureType(buf[0]) - t := binary.BigEndian.Uint32(buf[1:5]) - sig.CreationTime = time.Unix(int64(t), 0) - - // Eight-octet Key ID of signer. - if _, err = readFull(r, buf[:8]); err != nil { - return - } - sig.IssuerKeyId = binary.BigEndian.Uint64(buf[:]) - - // Public-key and hash algorithm - if _, err = readFull(r, buf[:2]); err != nil { - return - } - sig.PubKeyAlgo = PublicKeyAlgorithm(buf[0]) - switch sig.PubKeyAlgo { - case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly, PubKeyAlgoDSA: - default: - err = errors.UnsupportedError("public key algorithm " + strconv.Itoa(int(sig.PubKeyAlgo))) - return - } - var ok bool - if sig.Hash, ok = s2k.HashIdToHash(buf[1]); !ok { - return errors.UnsupportedError("hash function " + strconv.Itoa(int(buf[2]))) - } - - // Two-octet field holding left 16 bits of signed hash value. - if _, err = readFull(r, sig.HashTag[:2]); err != nil { - return - } - - switch sig.PubKeyAlgo { - case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly: - sig.RSASignature.bytes, sig.RSASignature.bitLength, err = readMPI(r) - case PubKeyAlgoDSA: - if sig.DSASigR.bytes, sig.DSASigR.bitLength, err = readMPI(r); err != nil { - return - } - sig.DSASigS.bytes, sig.DSASigS.bitLength, err = readMPI(r) - default: - panic("unreachable") - } - return -} - -// Serialize marshals sig to w. Sign, SignUserId or SignKey must have been -// called first. -func (sig *SignatureV3) Serialize(w io.Writer) (err error) { - buf := make([]byte, 8) - - // Write the sig type and creation time - buf[0] = byte(sig.SigType) - binary.BigEndian.PutUint32(buf[1:5], uint32(sig.CreationTime.Unix())) - if _, err = w.Write(buf[:5]); err != nil { - return - } - - // Write the issuer long key ID - binary.BigEndian.PutUint64(buf[:8], sig.IssuerKeyId) - if _, err = w.Write(buf[:8]); err != nil { - return - } - - // Write public key algorithm, hash ID, and hash value - buf[0] = byte(sig.PubKeyAlgo) - hashId, ok := s2k.HashToHashId(sig.Hash) - if !ok { - return errors.UnsupportedError(fmt.Sprintf("hash function %v", sig.Hash)) - } - buf[1] = hashId - copy(buf[2:4], sig.HashTag[:]) - if _, err = w.Write(buf[:4]); err != nil { - return - } - - if sig.RSASignature.bytes == nil && sig.DSASigR.bytes == nil { - return errors.InvalidArgumentError("Signature: need to call Sign, SignUserId or SignKey before Serialize") - } - - switch sig.PubKeyAlgo { - case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly: - err = writeMPIs(w, sig.RSASignature) - case PubKeyAlgoDSA: - err = writeMPIs(w, sig.DSASigR, sig.DSASigS) - default: - panic("impossible") - } - return -} diff --git a/vendor/golang.org/x/crypto/openpgp/packet/symmetric_key_encrypted.go b/vendor/golang.org/x/crypto/openpgp/packet/symmetric_key_encrypted.go deleted file mode 100644 index 744c2d2c42..0000000000 --- a/vendor/golang.org/x/crypto/openpgp/packet/symmetric_key_encrypted.go +++ /dev/null @@ -1,155 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package packet - -import ( - "bytes" - "crypto/cipher" - "io" - "strconv" - - "golang.org/x/crypto/openpgp/errors" - "golang.org/x/crypto/openpgp/s2k" -) - -// This is the largest session key that we'll support. Since no 512-bit cipher -// has even been seriously used, this is comfortably large. -const maxSessionKeySizeInBytes = 64 - -// SymmetricKeyEncrypted represents a passphrase protected session key. See RFC -// 4880, section 5.3. -type SymmetricKeyEncrypted struct { - CipherFunc CipherFunction - s2k func(out, in []byte) - encryptedKey []byte -} - -const symmetricKeyEncryptedVersion = 4 - -func (ske *SymmetricKeyEncrypted) parse(r io.Reader) error { - // RFC 4880, section 5.3. - var buf [2]byte - if _, err := readFull(r, buf[:]); err != nil { - return err - } - if buf[0] != symmetricKeyEncryptedVersion { - return errors.UnsupportedError("SymmetricKeyEncrypted version") - } - ske.CipherFunc = CipherFunction(buf[1]) - - if ske.CipherFunc.KeySize() == 0 { - return errors.UnsupportedError("unknown cipher: " + strconv.Itoa(int(buf[1]))) - } - - var err error - ske.s2k, err = s2k.Parse(r) - if err != nil { - return err - } - - encryptedKey := make([]byte, maxSessionKeySizeInBytes) - // The session key may follow. We just have to try and read to find - // out. If it exists then we limit it to maxSessionKeySizeInBytes. - n, err := readFull(r, encryptedKey) - if err != nil && err != io.ErrUnexpectedEOF { - return err - } - - if n != 0 { - if n == maxSessionKeySizeInBytes { - return errors.UnsupportedError("oversized encrypted session key") - } - ske.encryptedKey = encryptedKey[:n] - } - - return nil -} - -// Decrypt attempts to decrypt an encrypted session key and returns the key and -// the cipher to use when decrypting a subsequent Symmetrically Encrypted Data -// packet. -func (ske *SymmetricKeyEncrypted) Decrypt(passphrase []byte) ([]byte, CipherFunction, error) { - key := make([]byte, ske.CipherFunc.KeySize()) - ske.s2k(key, passphrase) - - if len(ske.encryptedKey) == 0 { - return key, ske.CipherFunc, nil - } - - // the IV is all zeros - iv := make([]byte, ske.CipherFunc.blockSize()) - c := cipher.NewCFBDecrypter(ske.CipherFunc.new(key), iv) - plaintextKey := make([]byte, len(ske.encryptedKey)) - c.XORKeyStream(plaintextKey, ske.encryptedKey) - cipherFunc := CipherFunction(plaintextKey[0]) - if cipherFunc.blockSize() == 0 { - return nil, ske.CipherFunc, errors.UnsupportedError("unknown cipher: " + strconv.Itoa(int(cipherFunc))) - } - plaintextKey = plaintextKey[1:] - if l, cipherKeySize := len(plaintextKey), cipherFunc.KeySize(); l != cipherFunc.KeySize() { - return nil, cipherFunc, errors.StructuralError("length of decrypted key (" + strconv.Itoa(l) + ") " + - "not equal to cipher keysize (" + strconv.Itoa(cipherKeySize) + ")") - } - return plaintextKey, cipherFunc, nil -} - -// SerializeSymmetricKeyEncrypted serializes a symmetric key packet to w. The -// packet contains a random session key, encrypted by a key derived from the -// given passphrase. The session key is returned and must be passed to -// SerializeSymmetricallyEncrypted. -// If config is nil, sensible defaults will be used. -func SerializeSymmetricKeyEncrypted(w io.Writer, passphrase []byte, config *Config) (key []byte, err error) { - cipherFunc := config.Cipher() - keySize := cipherFunc.KeySize() - if keySize == 0 { - return nil, errors.UnsupportedError("unknown cipher: " + strconv.Itoa(int(cipherFunc))) - } - - s2kBuf := new(bytes.Buffer) - keyEncryptingKey := make([]byte, keySize) - // s2k.Serialize salts and stretches the passphrase, and writes the - // resulting key to keyEncryptingKey and the s2k descriptor to s2kBuf. - err = s2k.Serialize(s2kBuf, keyEncryptingKey, config.Random(), passphrase, &s2k.Config{Hash: config.Hash(), S2KCount: config.PasswordHashIterations()}) - if err != nil { - return - } - s2kBytes := s2kBuf.Bytes() - - packetLength := 2 /* header */ + len(s2kBytes) + 1 /* cipher type */ + keySize - err = serializeHeader(w, packetTypeSymmetricKeyEncrypted, packetLength) - if err != nil { - return - } - - var buf [2]byte - buf[0] = symmetricKeyEncryptedVersion - buf[1] = byte(cipherFunc) - _, err = w.Write(buf[:]) - if err != nil { - return - } - _, err = w.Write(s2kBytes) - if err != nil { - return - } - - sessionKey := make([]byte, keySize) - _, err = io.ReadFull(config.Random(), sessionKey) - if err != nil { - return - } - iv := make([]byte, cipherFunc.blockSize()) - c := cipher.NewCFBEncrypter(cipherFunc.new(keyEncryptingKey), iv) - encryptedCipherAndKey := make([]byte, keySize+1) - c.XORKeyStream(encryptedCipherAndKey, buf[1:]) - c.XORKeyStream(encryptedCipherAndKey[1:], sessionKey) - _, err = w.Write(encryptedCipherAndKey) - if err != nil { - return - } - - key = sessionKey - return -} diff --git a/vendor/golang.org/x/crypto/openpgp/packet/symmetrically_encrypted.go b/vendor/golang.org/x/crypto/openpgp/packet/symmetrically_encrypted.go deleted file mode 100644 index 1a1a62964f..0000000000 --- a/vendor/golang.org/x/crypto/openpgp/packet/symmetrically_encrypted.go +++ /dev/null @@ -1,290 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package packet - -import ( - "crypto/cipher" - "crypto/sha1" - "crypto/subtle" - "golang.org/x/crypto/openpgp/errors" - "hash" - "io" - "strconv" -) - -// SymmetricallyEncrypted represents a symmetrically encrypted byte string. The -// encrypted contents will consist of more OpenPGP packets. See RFC 4880, -// sections 5.7 and 5.13. -type SymmetricallyEncrypted struct { - MDC bool // true iff this is a type 18 packet and thus has an embedded MAC. - contents io.Reader - prefix []byte -} - -const symmetricallyEncryptedVersion = 1 - -func (se *SymmetricallyEncrypted) parse(r io.Reader) error { - if se.MDC { - // See RFC 4880, section 5.13. - var buf [1]byte - _, err := readFull(r, buf[:]) - if err != nil { - return err - } - if buf[0] != symmetricallyEncryptedVersion { - return errors.UnsupportedError("unknown SymmetricallyEncrypted version") - } - } - se.contents = r - return nil -} - -// Decrypt returns a ReadCloser, from which the decrypted contents of the -// packet can be read. An incorrect key can, with high probability, be detected -// immediately and this will result in a KeyIncorrect error being returned. -func (se *SymmetricallyEncrypted) Decrypt(c CipherFunction, key []byte) (io.ReadCloser, error) { - keySize := c.KeySize() - if keySize == 0 { - return nil, errors.UnsupportedError("unknown cipher: " + strconv.Itoa(int(c))) - } - if len(key) != keySize { - return nil, errors.InvalidArgumentError("SymmetricallyEncrypted: incorrect key length") - } - - if se.prefix == nil { - se.prefix = make([]byte, c.blockSize()+2) - _, err := readFull(se.contents, se.prefix) - if err != nil { - return nil, err - } - } else if len(se.prefix) != c.blockSize()+2 { - return nil, errors.InvalidArgumentError("can't try ciphers with different block lengths") - } - - ocfbResync := OCFBResync - if se.MDC { - // MDC packets use a different form of OCFB mode. - ocfbResync = OCFBNoResync - } - - s := NewOCFBDecrypter(c.new(key), se.prefix, ocfbResync) - if s == nil { - return nil, errors.ErrKeyIncorrect - } - - plaintext := cipher.StreamReader{S: s, R: se.contents} - - if se.MDC { - // MDC packets have an embedded hash that we need to check. - h := sha1.New() - h.Write(se.prefix) - return &seMDCReader{in: plaintext, h: h}, nil - } - - // Otherwise, we just need to wrap plaintext so that it's a valid ReadCloser. - return seReader{plaintext}, nil -} - -// seReader wraps an io.Reader with a no-op Close method. -type seReader struct { - in io.Reader -} - -func (ser seReader) Read(buf []byte) (int, error) { - return ser.in.Read(buf) -} - -func (ser seReader) Close() error { - return nil -} - -const mdcTrailerSize = 1 /* tag byte */ + 1 /* length byte */ + sha1.Size - -// An seMDCReader wraps an io.Reader, maintains a running hash and keeps hold -// of the most recent 22 bytes (mdcTrailerSize). Upon EOF, those bytes form an -// MDC packet containing a hash of the previous contents which is checked -// against the running hash. See RFC 4880, section 5.13. -type seMDCReader struct { - in io.Reader - h hash.Hash - trailer [mdcTrailerSize]byte - scratch [mdcTrailerSize]byte - trailerUsed int - error bool - eof bool -} - -func (ser *seMDCReader) Read(buf []byte) (n int, err error) { - if ser.error { - err = io.ErrUnexpectedEOF - return - } - if ser.eof { - err = io.EOF - return - } - - // If we haven't yet filled the trailer buffer then we must do that - // first. - for ser.trailerUsed < mdcTrailerSize { - n, err = ser.in.Read(ser.trailer[ser.trailerUsed:]) - ser.trailerUsed += n - if err == io.EOF { - if ser.trailerUsed != mdcTrailerSize { - n = 0 - err = io.ErrUnexpectedEOF - ser.error = true - return - } - ser.eof = true - n = 0 - return - } - - if err != nil { - n = 0 - return - } - } - - // If it's a short read then we read into a temporary buffer and shift - // the data into the caller's buffer. - if len(buf) <= mdcTrailerSize { - n, err = readFull(ser.in, ser.scratch[:len(buf)]) - copy(buf, ser.trailer[:n]) - ser.h.Write(buf[:n]) - copy(ser.trailer[:], ser.trailer[n:]) - copy(ser.trailer[mdcTrailerSize-n:], ser.scratch[:]) - if n < len(buf) { - ser.eof = true - err = io.EOF - } - return - } - - n, err = ser.in.Read(buf[mdcTrailerSize:]) - copy(buf, ser.trailer[:]) - ser.h.Write(buf[:n]) - copy(ser.trailer[:], buf[n:]) - - if err == io.EOF { - ser.eof = true - } - return -} - -// This is a new-format packet tag byte for a type 19 (MDC) packet. -const mdcPacketTagByte = byte(0x80) | 0x40 | 19 - -func (ser *seMDCReader) Close() error { - if ser.error { - return errors.SignatureError("error during reading") - } - - for !ser.eof { - // We haven't seen EOF so we need to read to the end - var buf [1024]byte - _, err := ser.Read(buf[:]) - if err == io.EOF { - break - } - if err != nil { - return errors.SignatureError("error during reading") - } - } - - if ser.trailer[0] != mdcPacketTagByte || ser.trailer[1] != sha1.Size { - return errors.SignatureError("MDC packet not found") - } - ser.h.Write(ser.trailer[:2]) - - final := ser.h.Sum(nil) - if subtle.ConstantTimeCompare(final, ser.trailer[2:]) != 1 { - return errors.SignatureError("hash mismatch") - } - return nil -} - -// An seMDCWriter writes through to an io.WriteCloser while maintains a running -// hash of the data written. On close, it emits an MDC packet containing the -// running hash. -type seMDCWriter struct { - w io.WriteCloser - h hash.Hash -} - -func (w *seMDCWriter) Write(buf []byte) (n int, err error) { - w.h.Write(buf) - return w.w.Write(buf) -} - -func (w *seMDCWriter) Close() (err error) { - var buf [mdcTrailerSize]byte - - buf[0] = mdcPacketTagByte - buf[1] = sha1.Size - w.h.Write(buf[:2]) - digest := w.h.Sum(nil) - copy(buf[2:], digest) - - _, err = w.w.Write(buf[:]) - if err != nil { - return - } - return w.w.Close() -} - -// noOpCloser is like an io.NopCloser, but for an io.Writer. -type noOpCloser struct { - w io.Writer -} - -func (c noOpCloser) Write(data []byte) (n int, err error) { - return c.w.Write(data) -} - -func (c noOpCloser) Close() error { - return nil -} - -// SerializeSymmetricallyEncrypted serializes a symmetrically encrypted packet -// to w and returns a WriteCloser to which the to-be-encrypted packets can be -// written. -// If config is nil, sensible defaults will be used. -func SerializeSymmetricallyEncrypted(w io.Writer, c CipherFunction, key []byte, config *Config) (contents io.WriteCloser, err error) { - if c.KeySize() != len(key) { - return nil, errors.InvalidArgumentError("SymmetricallyEncrypted.Serialize: bad key length") - } - writeCloser := noOpCloser{w} - ciphertext, err := serializeStreamHeader(writeCloser, packetTypeSymmetricallyEncryptedMDC) - if err != nil { - return - } - - _, err = ciphertext.Write([]byte{symmetricallyEncryptedVersion}) - if err != nil { - return - } - - block := c.new(key) - blockSize := block.BlockSize() - iv := make([]byte, blockSize) - _, err = config.Random().Read(iv) - if err != nil { - return - } - s, prefix := NewOCFBEncrypter(block, iv, OCFBNoResync) - _, err = ciphertext.Write(prefix) - if err != nil { - return - } - plaintext := cipher.StreamWriter{S: s, W: ciphertext} - - h := sha1.New() - h.Write(iv) - h.Write(iv[blockSize-2:]) - contents = &seMDCWriter{w: plaintext, h: h} - return -} diff --git a/vendor/golang.org/x/crypto/openpgp/packet/userattribute.go b/vendor/golang.org/x/crypto/openpgp/packet/userattribute.go deleted file mode 100644 index ff7ef53075..0000000000 --- a/vendor/golang.org/x/crypto/openpgp/packet/userattribute.go +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package packet - -import ( - "bytes" - "image" - "image/jpeg" - "io" -) - -const UserAttrImageSubpacket = 1 - -// UserAttribute is capable of storing other types of data about a user -// beyond name, email and a text comment. In practice, user attributes are typically used -// to store a signed thumbnail photo JPEG image of the user. -// See RFC 4880, section 5.12. -type UserAttribute struct { - Contents []*OpaqueSubpacket -} - -// NewUserAttributePhoto creates a user attribute packet -// containing the given images. -func NewUserAttributePhoto(photos ...image.Image) (uat *UserAttribute, err error) { - uat = new(UserAttribute) - for _, photo := range photos { - var buf bytes.Buffer - // RFC 4880, Section 5.12.1. - data := []byte{ - 0x10, 0x00, // Little-endian image header length (16 bytes) - 0x01, // Image header version 1 - 0x01, // JPEG - 0, 0, 0, 0, // 12 reserved octets, must be all zero. - 0, 0, 0, 0, - 0, 0, 0, 0} - if _, err = buf.Write(data); err != nil { - return - } - if err = jpeg.Encode(&buf, photo, nil); err != nil { - return - } - uat.Contents = append(uat.Contents, &OpaqueSubpacket{ - SubType: UserAttrImageSubpacket, - Contents: buf.Bytes()}) - } - return -} - -// NewUserAttribute creates a new user attribute packet containing the given subpackets. -func NewUserAttribute(contents ...*OpaqueSubpacket) *UserAttribute { - return &UserAttribute{Contents: contents} -} - -func (uat *UserAttribute) parse(r io.Reader) (err error) { - // RFC 4880, section 5.13 - b, err := io.ReadAll(r) - if err != nil { - return - } - uat.Contents, err = OpaqueSubpackets(b) - return -} - -// Serialize marshals the user attribute to w in the form of an OpenPGP packet, including -// header. -func (uat *UserAttribute) Serialize(w io.Writer) (err error) { - var buf bytes.Buffer - for _, sp := range uat.Contents { - sp.Serialize(&buf) - } - if err = serializeHeader(w, packetTypeUserAttribute, buf.Len()); err != nil { - return err - } - _, err = w.Write(buf.Bytes()) - return -} - -// ImageData returns zero or more byte slices, each containing -// JPEG File Interchange Format (JFIF), for each photo in the -// user attribute packet. -func (uat *UserAttribute) ImageData() (imageData [][]byte) { - for _, sp := range uat.Contents { - if sp.SubType == UserAttrImageSubpacket && len(sp.Contents) > 16 { - imageData = append(imageData, sp.Contents[16:]) - } - } - return -} diff --git a/vendor/golang.org/x/crypto/openpgp/packet/userid.go b/vendor/golang.org/x/crypto/openpgp/packet/userid.go deleted file mode 100644 index 359a462eb8..0000000000 --- a/vendor/golang.org/x/crypto/openpgp/packet/userid.go +++ /dev/null @@ -1,159 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package packet - -import ( - "io" - "strings" -) - -// UserId contains text that is intended to represent the name and email -// address of the key holder. See RFC 4880, section 5.11. By convention, this -// takes the form "Full Name (Comment) " -type UserId struct { - Id string // By convention, this takes the form "Full Name (Comment) " which is split out in the fields below. - - Name, Comment, Email string -} - -func hasInvalidCharacters(s string) bool { - for _, c := range s { - switch c { - case '(', ')', '<', '>', 0: - return true - } - } - return false -} - -// NewUserId returns a UserId or nil if any of the arguments contain invalid -// characters. The invalid characters are '\x00', '(', ')', '<' and '>' -func NewUserId(name, comment, email string) *UserId { - // RFC 4880 doesn't deal with the structure of userid strings; the - // name, comment and email form is just a convention. However, there's - // no convention about escaping the metacharacters and GPG just refuses - // to create user ids where, say, the name contains a '('. We mirror - // this behaviour. - - if hasInvalidCharacters(name) || hasInvalidCharacters(comment) || hasInvalidCharacters(email) { - return nil - } - - uid := new(UserId) - uid.Name, uid.Comment, uid.Email = name, comment, email - uid.Id = name - if len(comment) > 0 { - if len(uid.Id) > 0 { - uid.Id += " " - } - uid.Id += "(" - uid.Id += comment - uid.Id += ")" - } - if len(email) > 0 { - if len(uid.Id) > 0 { - uid.Id += " " - } - uid.Id += "<" - uid.Id += email - uid.Id += ">" - } - return uid -} - -func (uid *UserId) parse(r io.Reader) (err error) { - // RFC 4880, section 5.11 - b, err := io.ReadAll(r) - if err != nil { - return - } - uid.Id = string(b) - uid.Name, uid.Comment, uid.Email = parseUserId(uid.Id) - return -} - -// Serialize marshals uid to w in the form of an OpenPGP packet, including -// header. -func (uid *UserId) Serialize(w io.Writer) error { - err := serializeHeader(w, packetTypeUserId, len(uid.Id)) - if err != nil { - return err - } - _, err = w.Write([]byte(uid.Id)) - return err -} - -// parseUserId extracts the name, comment and email from a user id string that -// is formatted as "Full Name (Comment) ". -func parseUserId(id string) (name, comment, email string) { - var n, c, e struct { - start, end int - } - var state int - - for offset, rune := range id { - switch state { - case 0: - // Entering name - n.start = offset - state = 1 - fallthrough - case 1: - // In name - if rune == '(' { - state = 2 - n.end = offset - } else if rune == '<' { - state = 5 - n.end = offset - } - case 2: - // Entering comment - c.start = offset - state = 3 - fallthrough - case 3: - // In comment - if rune == ')' { - state = 4 - c.end = offset - } - case 4: - // Between comment and email - if rune == '<' { - state = 5 - } - case 5: - // Entering email - e.start = offset - state = 6 - fallthrough - case 6: - // In email - if rune == '>' { - state = 7 - e.end = offset - } - default: - // After email - } - } - switch state { - case 1: - // ended in the name - n.end = len(id) - case 3: - // ended in comment - c.end = len(id) - case 6: - // ended in email - e.end = len(id) - } - - name = strings.TrimSpace(id[n.start:n.end]) - comment = strings.TrimSpace(id[c.start:c.end]) - email = strings.TrimSpace(id[e.start:e.end]) - return -} diff --git a/vendor/golang.org/x/crypto/openpgp/read.go b/vendor/golang.org/x/crypto/openpgp/read.go deleted file mode 100644 index 28905a9073..0000000000 --- a/vendor/golang.org/x/crypto/openpgp/read.go +++ /dev/null @@ -1,449 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package openpgp implements high level operations on OpenPGP messages. -// -// Deprecated: this package is unsafe by design, and has numerous known security -// issues. It is not maintained, and should not be used. New applications should -// consider a more focused, modern alternative to OpenPGP for their specific -// task. If you are required to interoperate with OpenPGP systems and need a -// maintained package, consider github.com/ProtonMail/go-crypto/openpgp, which -// is a maintained fork that aims to be a drop-in replacement for this package. -package openpgp - -import ( - "crypto" - _ "crypto/sha256" - "hash" - "io" - "strconv" - - "golang.org/x/crypto/openpgp/armor" - "golang.org/x/crypto/openpgp/errors" - "golang.org/x/crypto/openpgp/packet" -) - -// SignatureType is the armor type for a PGP signature. -var SignatureType = "PGP SIGNATURE" - -// readArmored reads an armored block with the given type. -func readArmored(r io.Reader, expectedType string) (body io.Reader, err error) { - block, err := armor.Decode(r) - if err != nil { - return - } - - if block.Type != expectedType { - return nil, errors.InvalidArgumentError("expected '" + expectedType + "', got: " + block.Type) - } - - return block.Body, nil -} - -// MessageDetails contains the result of parsing an OpenPGP encrypted and/or -// signed message. -type MessageDetails struct { - IsEncrypted bool // true if the message was encrypted. - EncryptedToKeyIds []uint64 // the list of recipient key ids. - IsSymmetricallyEncrypted bool // true if a passphrase could have decrypted the message. - DecryptedWith Key // the private key used to decrypt the message, if any. - IsSigned bool // true if the message is signed. - SignedByKeyId uint64 // the key id of the signer, if any. - SignedBy *Key // the key of the signer, if available. - LiteralData *packet.LiteralData // the metadata of the contents - UnverifiedBody io.Reader // the contents of the message. - - // If IsSigned is true and SignedBy is non-zero then the signature will - // be verified as UnverifiedBody is read. The signature cannot be - // checked until the whole of UnverifiedBody is read so UnverifiedBody - // must be consumed until EOF before the data can be trusted. Even if a - // message isn't signed (or the signer is unknown) the data may contain - // an authentication code that is only checked once UnverifiedBody has - // been consumed. Once EOF has been seen, the following fields are - // valid. (An authentication code failure is reported as a - // SignatureError error when reading from UnverifiedBody.) - SignatureError error // nil if the signature is good. - Signature *packet.Signature // the signature packet itself, if v4 (default) - SignatureV3 *packet.SignatureV3 // the signature packet if it is a v2 or v3 signature - - decrypted io.ReadCloser -} - -// A PromptFunction is used as a callback by functions that may need to decrypt -// a private key, or prompt for a passphrase. It is called with a list of -// acceptable, encrypted private keys and a boolean that indicates whether a -// passphrase is usable. It should either decrypt a private key or return a -// passphrase to try. If the decrypted private key or given passphrase isn't -// correct, the function will be called again, forever. Any error returned will -// be passed up. -type PromptFunction func(keys []Key, symmetric bool) ([]byte, error) - -// A keyEnvelopePair is used to store a private key with the envelope that -// contains a symmetric key, encrypted with that key. -type keyEnvelopePair struct { - key Key - encryptedKey *packet.EncryptedKey -} - -// ReadMessage parses an OpenPGP message that may be signed and/or encrypted. -// The given KeyRing should contain both public keys (for signature -// verification) and, possibly encrypted, private keys for decrypting. -// If config is nil, sensible defaults will be used. -func ReadMessage(r io.Reader, keyring KeyRing, prompt PromptFunction, config *packet.Config) (md *MessageDetails, err error) { - var p packet.Packet - - var symKeys []*packet.SymmetricKeyEncrypted - var pubKeys []keyEnvelopePair - var se *packet.SymmetricallyEncrypted - - packets := packet.NewReader(r) - md = new(MessageDetails) - md.IsEncrypted = true - - // The message, if encrypted, starts with a number of packets - // containing an encrypted decryption key. The decryption key is either - // encrypted to a public key, or with a passphrase. This loop - // collects these packets. -ParsePackets: - for { - p, err = packets.Next() - if err != nil { - return nil, err - } - switch p := p.(type) { - case *packet.SymmetricKeyEncrypted: - // This packet contains the decryption key encrypted with a passphrase. - md.IsSymmetricallyEncrypted = true - symKeys = append(symKeys, p) - case *packet.EncryptedKey: - // This packet contains the decryption key encrypted to a public key. - md.EncryptedToKeyIds = append(md.EncryptedToKeyIds, p.KeyId) - switch p.Algo { - case packet.PubKeyAlgoRSA, packet.PubKeyAlgoRSAEncryptOnly, packet.PubKeyAlgoElGamal: - break - default: - continue - } - var keys []Key - if p.KeyId == 0 { - keys = keyring.DecryptionKeys() - } else { - keys = keyring.KeysById(p.KeyId) - } - for _, k := range keys { - pubKeys = append(pubKeys, keyEnvelopePair{k, p}) - } - case *packet.SymmetricallyEncrypted: - se = p - break ParsePackets - case *packet.Compressed, *packet.LiteralData, *packet.OnePassSignature: - // This message isn't encrypted. - if len(symKeys) != 0 || len(pubKeys) != 0 { - return nil, errors.StructuralError("key material not followed by encrypted message") - } - packets.Unread(p) - return readSignedMessage(packets, nil, keyring) - } - } - - var candidates []Key - var decrypted io.ReadCloser - - // Now that we have the list of encrypted keys we need to decrypt at - // least one of them or, if we cannot, we need to call the prompt - // function so that it can decrypt a key or give us a passphrase. -FindKey: - for { - // See if any of the keys already have a private key available - candidates = candidates[:0] - candidateFingerprints := make(map[string]bool) - - for _, pk := range pubKeys { - if pk.key.PrivateKey == nil { - continue - } - if !pk.key.PrivateKey.Encrypted { - if len(pk.encryptedKey.Key) == 0 { - pk.encryptedKey.Decrypt(pk.key.PrivateKey, config) - } - if len(pk.encryptedKey.Key) == 0 { - continue - } - decrypted, err = se.Decrypt(pk.encryptedKey.CipherFunc, pk.encryptedKey.Key) - if err != nil && err != errors.ErrKeyIncorrect { - return nil, err - } - if decrypted != nil { - md.DecryptedWith = pk.key - break FindKey - } - } else { - fpr := string(pk.key.PublicKey.Fingerprint[:]) - if v := candidateFingerprints[fpr]; v { - continue - } - candidates = append(candidates, pk.key) - candidateFingerprints[fpr] = true - } - } - - if len(candidates) == 0 && len(symKeys) == 0 { - return nil, errors.ErrKeyIncorrect - } - - if prompt == nil { - return nil, errors.ErrKeyIncorrect - } - - passphrase, err := prompt(candidates, len(symKeys) != 0) - if err != nil { - return nil, err - } - - // Try the symmetric passphrase first - if len(symKeys) != 0 && passphrase != nil { - for _, s := range symKeys { - key, cipherFunc, err := s.Decrypt(passphrase) - if err == nil { - decrypted, err = se.Decrypt(cipherFunc, key) - if err != nil && err != errors.ErrKeyIncorrect { - return nil, err - } - if decrypted != nil { - break FindKey - } - } - - } - } - } - - md.decrypted = decrypted - if err := packets.Push(decrypted); err != nil { - return nil, err - } - return readSignedMessage(packets, md, keyring) -} - -// readSignedMessage reads a possibly signed message if mdin is non-zero then -// that structure is updated and returned. Otherwise a fresh MessageDetails is -// used. -func readSignedMessage(packets *packet.Reader, mdin *MessageDetails, keyring KeyRing) (md *MessageDetails, err error) { - if mdin == nil { - mdin = new(MessageDetails) - } - md = mdin - - var p packet.Packet - var h hash.Hash - var wrappedHash hash.Hash -FindLiteralData: - for { - p, err = packets.Next() - if err != nil { - return nil, err - } - switch p := p.(type) { - case *packet.Compressed: - if err := packets.Push(p.Body); err != nil { - return nil, err - } - case *packet.OnePassSignature: - if !p.IsLast { - return nil, errors.UnsupportedError("nested signatures") - } - - h, wrappedHash, err = hashForSignature(p.Hash, p.SigType) - if err != nil { - md = nil - return - } - - md.IsSigned = true - md.SignedByKeyId = p.KeyId - keys := keyring.KeysByIdUsage(p.KeyId, packet.KeyFlagSign) - if len(keys) > 0 { - md.SignedBy = &keys[0] - } - case *packet.LiteralData: - md.LiteralData = p - break FindLiteralData - } - } - - if md.SignedBy != nil { - md.UnverifiedBody = &signatureCheckReader{packets, h, wrappedHash, md} - } else if md.decrypted != nil { - md.UnverifiedBody = checkReader{md} - } else { - md.UnverifiedBody = md.LiteralData.Body - } - - return md, nil -} - -// hashForSignature returns a pair of hashes that can be used to verify a -// signature. The signature may specify that the contents of the signed message -// should be preprocessed (i.e. to normalize line endings). Thus this function -// returns two hashes. The second should be used to hash the message itself and -// performs any needed preprocessing. -func hashForSignature(hashId crypto.Hash, sigType packet.SignatureType) (hash.Hash, hash.Hash, error) { - if !hashId.Available() { - return nil, nil, errors.UnsupportedError("hash not available: " + strconv.Itoa(int(hashId))) - } - h := hashId.New() - - switch sigType { - case packet.SigTypeBinary: - return h, h, nil - case packet.SigTypeText: - return h, NewCanonicalTextHash(h), nil - } - - return nil, nil, errors.UnsupportedError("unsupported signature type: " + strconv.Itoa(int(sigType))) -} - -// checkReader wraps an io.Reader from a LiteralData packet. When it sees EOF -// it closes the ReadCloser from any SymmetricallyEncrypted packet to trigger -// MDC checks. -type checkReader struct { - md *MessageDetails -} - -func (cr checkReader) Read(buf []byte) (n int, err error) { - n, err = cr.md.LiteralData.Body.Read(buf) - if err == io.EOF { - mdcErr := cr.md.decrypted.Close() - if mdcErr != nil { - err = mdcErr - } - } - return -} - -// signatureCheckReader wraps an io.Reader from a LiteralData packet and hashes -// the data as it is read. When it sees an EOF from the underlying io.Reader -// it parses and checks a trailing Signature packet and triggers any MDC checks. -type signatureCheckReader struct { - packets *packet.Reader - h, wrappedHash hash.Hash - md *MessageDetails -} - -func (scr *signatureCheckReader) Read(buf []byte) (n int, err error) { - n, err = scr.md.LiteralData.Body.Read(buf) - scr.wrappedHash.Write(buf[:n]) - if err == io.EOF { - var p packet.Packet - p, scr.md.SignatureError = scr.packets.Next() - if scr.md.SignatureError != nil { - return - } - - var ok bool - if scr.md.Signature, ok = p.(*packet.Signature); ok { - scr.md.SignatureError = scr.md.SignedBy.PublicKey.VerifySignature(scr.h, scr.md.Signature) - } else if scr.md.SignatureV3, ok = p.(*packet.SignatureV3); ok { - scr.md.SignatureError = scr.md.SignedBy.PublicKey.VerifySignatureV3(scr.h, scr.md.SignatureV3) - } else { - scr.md.SignatureError = errors.StructuralError("LiteralData not followed by Signature") - return - } - - // The SymmetricallyEncrypted packet, if any, might have an - // unsigned hash of its own. In order to check this we need to - // close that Reader. - if scr.md.decrypted != nil { - mdcErr := scr.md.decrypted.Close() - if mdcErr != nil { - err = mdcErr - } - } - } - return -} - -// CheckDetachedSignature takes a signed file and a detached signature and -// returns the signer if the signature is valid. If the signer isn't known, -// ErrUnknownIssuer is returned. -func CheckDetachedSignature(keyring KeyRing, signed, signature io.Reader) (signer *Entity, err error) { - var issuerKeyId uint64 - var hashFunc crypto.Hash - var sigType packet.SignatureType - var keys []Key - var p packet.Packet - - packets := packet.NewReader(signature) - for { - p, err = packets.Next() - if err == io.EOF { - return nil, errors.ErrUnknownIssuer - } - if err != nil { - return nil, err - } - - switch sig := p.(type) { - case *packet.Signature: - if sig.IssuerKeyId == nil { - return nil, errors.StructuralError("signature doesn't have an issuer") - } - issuerKeyId = *sig.IssuerKeyId - hashFunc = sig.Hash - sigType = sig.SigType - case *packet.SignatureV3: - issuerKeyId = sig.IssuerKeyId - hashFunc = sig.Hash - sigType = sig.SigType - default: - return nil, errors.StructuralError("non signature packet found") - } - - keys = keyring.KeysByIdUsage(issuerKeyId, packet.KeyFlagSign) - if len(keys) > 0 { - break - } - } - - if len(keys) == 0 { - panic("unreachable") - } - - h, wrappedHash, err := hashForSignature(hashFunc, sigType) - if err != nil { - return nil, err - } - - if _, err := io.Copy(wrappedHash, signed); err != nil && err != io.EOF { - return nil, err - } - - for _, key := range keys { - switch sig := p.(type) { - case *packet.Signature: - err = key.PublicKey.VerifySignature(h, sig) - case *packet.SignatureV3: - err = key.PublicKey.VerifySignatureV3(h, sig) - default: - panic("unreachable") - } - - if err == nil { - return key.Entity, nil - } - } - - return nil, err -} - -// CheckArmoredDetachedSignature performs the same actions as -// CheckDetachedSignature but expects the signature to be armored. -func CheckArmoredDetachedSignature(keyring KeyRing, signed, signature io.Reader) (signer *Entity, err error) { - body, err := readArmored(signature, SignatureType) - if err != nil { - return - } - - return CheckDetachedSignature(keyring, signed, body) -} diff --git a/vendor/golang.org/x/crypto/openpgp/s2k/s2k.go b/vendor/golang.org/x/crypto/openpgp/s2k/s2k.go deleted file mode 100644 index b5fe4c1605..0000000000 --- a/vendor/golang.org/x/crypto/openpgp/s2k/s2k.go +++ /dev/null @@ -1,280 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package s2k implements the various OpenPGP string-to-key transforms as -// specified in RFC 4800 section 3.7.1. -// -// Deprecated: this package is unsafe by design, and has numerous known security -// issues. It is not maintained, and should not be used. New applications should -// consider a more focused, modern alternative to OpenPGP for their specific -// task. If you are required to interoperate with OpenPGP systems and need a -// maintained package, consider github.com/ProtonMail/go-crypto/openpgp, which -// is a maintained fork that aims to be a drop-in replacement for this package. -package s2k - -import ( - "crypto" - "hash" - "io" - "strconv" - - "golang.org/x/crypto/openpgp/errors" -) - -// Config collects configuration parameters for s2k key-stretching -// transformatioms. A nil *Config is valid and results in all default -// values. Currently, Config is used only by the Serialize function in -// this package. -type Config struct { - // Hash is the default hash function to be used. If - // nil, SHA1 is used. - Hash crypto.Hash - // S2KCount is only used for symmetric encryption. It - // determines the strength of the passphrase stretching when - // the said passphrase is hashed to produce a key. S2KCount - // should be between 1024 and 65011712, inclusive. If Config - // is nil or S2KCount is 0, the value 65536 used. Not all - // values in the above range can be represented. S2KCount will - // be rounded up to the next representable value if it cannot - // be encoded exactly. When set, it is strongly encrouraged to - // use a value that is at least 65536. See RFC 4880 Section - // 3.7.1.3. - S2KCount int -} - -func (c *Config) hash() crypto.Hash { - if c == nil || uint(c.Hash) == 0 { - // SHA1 is the historical default in this package. - return crypto.SHA1 - } - - return c.Hash -} - -func (c *Config) encodedCount() uint8 { - if c == nil || c.S2KCount == 0 { - return 96 // The common case. Corresponding to 65536 - } - - i := c.S2KCount - switch { - // Behave like GPG. Should we make 65536 the lowest value used? - case i < 1024: - i = 1024 - case i > 65011712: - i = 65011712 - } - - return encodeCount(i) -} - -// encodeCount converts an iterative "count" in the range 1024 to -// 65011712, inclusive, to an encoded count. The return value is the -// octet that is actually stored in the GPG file. encodeCount panics -// if i is not in the above range (encodedCount above takes care to -// pass i in the correct range). See RFC 4880 Section 3.7.7.1. -func encodeCount(i int) uint8 { - if i < 1024 || i > 65011712 { - panic("count arg i outside the required range") - } - - for encoded := 0; encoded < 256; encoded++ { - count := decodeCount(uint8(encoded)) - if count >= i { - return uint8(encoded) - } - } - - return 255 -} - -// decodeCount returns the s2k mode 3 iterative "count" corresponding to -// the encoded octet c. -func decodeCount(c uint8) int { - return (16 + int(c&15)) << (uint32(c>>4) + 6) -} - -// Simple writes to out the result of computing the Simple S2K function (RFC -// 4880, section 3.7.1.1) using the given hash and input passphrase. -func Simple(out []byte, h hash.Hash, in []byte) { - Salted(out, h, in, nil) -} - -var zero [1]byte - -// Salted writes to out the result of computing the Salted S2K function (RFC -// 4880, section 3.7.1.2) using the given hash, input passphrase and salt. -func Salted(out []byte, h hash.Hash, in []byte, salt []byte) { - done := 0 - var digest []byte - - for i := 0; done < len(out); i++ { - h.Reset() - for j := 0; j < i; j++ { - h.Write(zero[:]) - } - h.Write(salt) - h.Write(in) - digest = h.Sum(digest[:0]) - n := copy(out[done:], digest) - done += n - } -} - -// Iterated writes to out the result of computing the Iterated and Salted S2K -// function (RFC 4880, section 3.7.1.3) using the given hash, input passphrase, -// salt and iteration count. -func Iterated(out []byte, h hash.Hash, in []byte, salt []byte, count int) { - combined := make([]byte, len(in)+len(salt)) - copy(combined, salt) - copy(combined[len(salt):], in) - - if count < len(combined) { - count = len(combined) - } - - done := 0 - var digest []byte - for i := 0; done < len(out); i++ { - h.Reset() - for j := 0; j < i; j++ { - h.Write(zero[:]) - } - written := 0 - for written < count { - if written+len(combined) > count { - todo := count - written - h.Write(combined[:todo]) - written = count - } else { - h.Write(combined) - written += len(combined) - } - } - digest = h.Sum(digest[:0]) - n := copy(out[done:], digest) - done += n - } -} - -// Parse reads a binary specification for a string-to-key transformation from r -// and returns a function which performs that transform. -func Parse(r io.Reader) (f func(out, in []byte), err error) { - var buf [9]byte - - _, err = io.ReadFull(r, buf[:2]) - if err != nil { - return - } - - hash, ok := HashIdToHash(buf[1]) - if !ok { - return nil, errors.UnsupportedError("hash for S2K function: " + strconv.Itoa(int(buf[1]))) - } - if !hash.Available() { - return nil, errors.UnsupportedError("hash not available: " + strconv.Itoa(int(hash))) - } - h := hash.New() - - switch buf[0] { - case 0: - f := func(out, in []byte) { - Simple(out, h, in) - } - return f, nil - case 1: - _, err = io.ReadFull(r, buf[:8]) - if err != nil { - return - } - f := func(out, in []byte) { - Salted(out, h, in, buf[:8]) - } - return f, nil - case 3: - _, err = io.ReadFull(r, buf[:9]) - if err != nil { - return - } - count := decodeCount(buf[8]) - f := func(out, in []byte) { - Iterated(out, h, in, buf[:8], count) - } - return f, nil - } - - return nil, errors.UnsupportedError("S2K function") -} - -// Serialize salts and stretches the given passphrase and writes the -// resulting key into key. It also serializes an S2K descriptor to -// w. The key stretching can be configured with c, which may be -// nil. In that case, sensible defaults will be used. -func Serialize(w io.Writer, key []byte, rand io.Reader, passphrase []byte, c *Config) error { - var buf [11]byte - buf[0] = 3 /* iterated and salted */ - buf[1], _ = HashToHashId(c.hash()) - salt := buf[2:10] - if _, err := io.ReadFull(rand, salt); err != nil { - return err - } - encodedCount := c.encodedCount() - count := decodeCount(encodedCount) - buf[10] = encodedCount - if _, err := w.Write(buf[:]); err != nil { - return err - } - - Iterated(key, c.hash().New(), passphrase, salt, count) - return nil -} - -// hashToHashIdMapping contains pairs relating OpenPGP's hash identifier with -// Go's crypto.Hash type. See RFC 4880, section 9.4. -var hashToHashIdMapping = []struct { - id byte - hash crypto.Hash - name string -}{ - {1, crypto.MD5, "MD5"}, - {2, crypto.SHA1, "SHA1"}, - {3, crypto.RIPEMD160, "RIPEMD160"}, - {8, crypto.SHA256, "SHA256"}, - {9, crypto.SHA384, "SHA384"}, - {10, crypto.SHA512, "SHA512"}, - {11, crypto.SHA224, "SHA224"}, -} - -// HashIdToHash returns a crypto.Hash which corresponds to the given OpenPGP -// hash id. -func HashIdToHash(id byte) (h crypto.Hash, ok bool) { - for _, m := range hashToHashIdMapping { - if m.id == id { - return m.hash, true - } - } - return 0, false -} - -// HashIdToString returns the name of the hash function corresponding to the -// given OpenPGP hash id. -func HashIdToString(id byte) (name string, ok bool) { - for _, m := range hashToHashIdMapping { - if m.id == id { - return m.name, true - } - } - - return "", false -} - -// HashToHashId returns an OpenPGP hash id which corresponds the given Hash. -func HashToHashId(h crypto.Hash) (id byte, ok bool) { - for _, m := range hashToHashIdMapping { - if m.hash == h { - return m.id, true - } - } - return 0, false -} diff --git a/vendor/golang.org/x/crypto/openpgp/write.go b/vendor/golang.org/x/crypto/openpgp/write.go deleted file mode 100644 index b89d48b81d..0000000000 --- a/vendor/golang.org/x/crypto/openpgp/write.go +++ /dev/null @@ -1,418 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package openpgp - -import ( - "crypto" - "hash" - "io" - "strconv" - "time" - - "golang.org/x/crypto/openpgp/armor" - "golang.org/x/crypto/openpgp/errors" - "golang.org/x/crypto/openpgp/packet" - "golang.org/x/crypto/openpgp/s2k" -) - -// DetachSign signs message with the private key from signer (which must -// already have been decrypted) and writes the signature to w. -// If config is nil, sensible defaults will be used. -func DetachSign(w io.Writer, signer *Entity, message io.Reader, config *packet.Config) error { - return detachSign(w, signer, message, packet.SigTypeBinary, config) -} - -// ArmoredDetachSign signs message with the private key from signer (which -// must already have been decrypted) and writes an armored signature to w. -// If config is nil, sensible defaults will be used. -func ArmoredDetachSign(w io.Writer, signer *Entity, message io.Reader, config *packet.Config) (err error) { - return armoredDetachSign(w, signer, message, packet.SigTypeBinary, config) -} - -// DetachSignText signs message (after canonicalising the line endings) with -// the private key from signer (which must already have been decrypted) and -// writes the signature to w. -// If config is nil, sensible defaults will be used. -func DetachSignText(w io.Writer, signer *Entity, message io.Reader, config *packet.Config) error { - return detachSign(w, signer, message, packet.SigTypeText, config) -} - -// ArmoredDetachSignText signs message (after canonicalising the line endings) -// with the private key from signer (which must already have been decrypted) -// and writes an armored signature to w. -// If config is nil, sensible defaults will be used. -func ArmoredDetachSignText(w io.Writer, signer *Entity, message io.Reader, config *packet.Config) error { - return armoredDetachSign(w, signer, message, packet.SigTypeText, config) -} - -func armoredDetachSign(w io.Writer, signer *Entity, message io.Reader, sigType packet.SignatureType, config *packet.Config) (err error) { - out, err := armor.Encode(w, SignatureType, nil) - if err != nil { - return - } - err = detachSign(out, signer, message, sigType, config) - if err != nil { - return - } - return out.Close() -} - -func detachSign(w io.Writer, signer *Entity, message io.Reader, sigType packet.SignatureType, config *packet.Config) (err error) { - if signer.PrivateKey == nil { - return errors.InvalidArgumentError("signing key doesn't have a private key") - } - if signer.PrivateKey.Encrypted { - return errors.InvalidArgumentError("signing key is encrypted") - } - - sig := new(packet.Signature) - sig.SigType = sigType - sig.PubKeyAlgo = signer.PrivateKey.PubKeyAlgo - sig.Hash = config.Hash() - sig.CreationTime = config.Now() - sig.IssuerKeyId = &signer.PrivateKey.KeyId - - h, wrappedHash, err := hashForSignature(sig.Hash, sig.SigType) - if err != nil { - return - } - io.Copy(wrappedHash, message) - - err = sig.Sign(h, signer.PrivateKey, config) - if err != nil { - return - } - - return sig.Serialize(w) -} - -// FileHints contains metadata about encrypted files. This metadata is, itself, -// encrypted. -type FileHints struct { - // IsBinary can be set to hint that the contents are binary data. - IsBinary bool - // FileName hints at the name of the file that should be written. It's - // truncated to 255 bytes if longer. It may be empty to suggest that the - // file should not be written to disk. It may be equal to "_CONSOLE" to - // suggest the data should not be written to disk. - FileName string - // ModTime contains the modification time of the file, or the zero time if not applicable. - ModTime time.Time -} - -// SymmetricallyEncrypt acts like gpg -c: it encrypts a file with a passphrase. -// The resulting WriteCloser must be closed after the contents of the file have -// been written. -// If config is nil, sensible defaults will be used. -func SymmetricallyEncrypt(ciphertext io.Writer, passphrase []byte, hints *FileHints, config *packet.Config) (plaintext io.WriteCloser, err error) { - if hints == nil { - hints = &FileHints{} - } - - key, err := packet.SerializeSymmetricKeyEncrypted(ciphertext, passphrase, config) - if err != nil { - return - } - w, err := packet.SerializeSymmetricallyEncrypted(ciphertext, config.Cipher(), key, config) - if err != nil { - return - } - - literaldata := w - if algo := config.Compression(); algo != packet.CompressionNone { - var compConfig *packet.CompressionConfig - if config != nil { - compConfig = config.CompressionConfig - } - literaldata, err = packet.SerializeCompressed(w, algo, compConfig) - if err != nil { - return - } - } - - var epochSeconds uint32 - if !hints.ModTime.IsZero() { - epochSeconds = uint32(hints.ModTime.Unix()) - } - return packet.SerializeLiteral(literaldata, hints.IsBinary, hints.FileName, epochSeconds) -} - -// intersectPreferences mutates and returns a prefix of a that contains only -// the values in the intersection of a and b. The order of a is preserved. -func intersectPreferences(a []uint8, b []uint8) (intersection []uint8) { - var j int - for _, v := range a { - for _, v2 := range b { - if v == v2 { - a[j] = v - j++ - break - } - } - } - - return a[:j] -} - -func hashToHashId(h crypto.Hash) uint8 { - v, ok := s2k.HashToHashId(h) - if !ok { - panic("tried to convert unknown hash") - } - return v -} - -// writeAndSign writes the data as a payload package and, optionally, signs -// it. hints contains optional information, that is also encrypted, -// that aids the recipients in processing the message. The resulting -// WriteCloser must be closed after the contents of the file have been -// written. If config is nil, sensible defaults will be used. -func writeAndSign(payload io.WriteCloser, candidateHashes []uint8, signed *Entity, hints *FileHints, config *packet.Config) (plaintext io.WriteCloser, err error) { - var signer *packet.PrivateKey - if signed != nil { - signKey, ok := signed.signingKey(config.Now()) - if !ok { - return nil, errors.InvalidArgumentError("no valid signing keys") - } - signer = signKey.PrivateKey - if signer == nil { - return nil, errors.InvalidArgumentError("no private key in signing key") - } - if signer.Encrypted { - return nil, errors.InvalidArgumentError("signing key must be decrypted") - } - } - - var hash crypto.Hash - for _, hashId := range candidateHashes { - if h, ok := s2k.HashIdToHash(hashId); ok && h.Available() { - hash = h - break - } - } - - // If the hash specified by config is a candidate, we'll use that. - if configuredHash := config.Hash(); configuredHash.Available() { - for _, hashId := range candidateHashes { - if h, ok := s2k.HashIdToHash(hashId); ok && h == configuredHash { - hash = h - break - } - } - } - - if hash == 0 { - hashId := candidateHashes[0] - name, ok := s2k.HashIdToString(hashId) - if !ok { - name = "#" + strconv.Itoa(int(hashId)) - } - return nil, errors.InvalidArgumentError("cannot encrypt because no candidate hash functions are compiled in. (Wanted " + name + " in this case.)") - } - - if signer != nil { - ops := &packet.OnePassSignature{ - SigType: packet.SigTypeBinary, - Hash: hash, - PubKeyAlgo: signer.PubKeyAlgo, - KeyId: signer.KeyId, - IsLast: true, - } - if err := ops.Serialize(payload); err != nil { - return nil, err - } - } - - if hints == nil { - hints = &FileHints{} - } - - w := payload - if signer != nil { - // If we need to write a signature packet after the literal - // data then we need to stop literalData from closing - // encryptedData. - w = noOpCloser{w} - - } - var epochSeconds uint32 - if !hints.ModTime.IsZero() { - epochSeconds = uint32(hints.ModTime.Unix()) - } - literalData, err := packet.SerializeLiteral(w, hints.IsBinary, hints.FileName, epochSeconds) - if err != nil { - return nil, err - } - - if signer != nil { - return signatureWriter{payload, literalData, hash, hash.New(), signer, config}, nil - } - return literalData, nil -} - -// Encrypt encrypts a message to a number of recipients and, optionally, signs -// it. hints contains optional information, that is also encrypted, that aids -// the recipients in processing the message. The resulting WriteCloser must -// be closed after the contents of the file have been written. -// If config is nil, sensible defaults will be used. -func Encrypt(ciphertext io.Writer, to []*Entity, signed *Entity, hints *FileHints, config *packet.Config) (plaintext io.WriteCloser, err error) { - if len(to) == 0 { - return nil, errors.InvalidArgumentError("no encryption recipient provided") - } - - // These are the possible ciphers that we'll use for the message. - candidateCiphers := []uint8{ - uint8(packet.CipherAES128), - uint8(packet.CipherAES256), - uint8(packet.CipherCAST5), - } - // These are the possible hash functions that we'll use for the signature. - candidateHashes := []uint8{ - hashToHashId(crypto.SHA256), - hashToHashId(crypto.SHA384), - hashToHashId(crypto.SHA512), - hashToHashId(crypto.SHA1), - hashToHashId(crypto.RIPEMD160), - } - // In the event that a recipient doesn't specify any supported ciphers - // or hash functions, these are the ones that we assume that every - // implementation supports. - defaultCiphers := candidateCiphers[len(candidateCiphers)-1:] - defaultHashes := candidateHashes[len(candidateHashes)-1:] - - encryptKeys := make([]Key, len(to)) - for i := range to { - var ok bool - encryptKeys[i], ok = to[i].encryptionKey(config.Now()) - if !ok { - return nil, errors.InvalidArgumentError("cannot encrypt a message to key id " + strconv.FormatUint(to[i].PrimaryKey.KeyId, 16) + " because it has no encryption keys") - } - - sig := to[i].primaryIdentity().SelfSignature - - preferredSymmetric := sig.PreferredSymmetric - if len(preferredSymmetric) == 0 { - preferredSymmetric = defaultCiphers - } - preferredHashes := sig.PreferredHash - if len(preferredHashes) == 0 { - preferredHashes = defaultHashes - } - candidateCiphers = intersectPreferences(candidateCiphers, preferredSymmetric) - candidateHashes = intersectPreferences(candidateHashes, preferredHashes) - } - - if len(candidateCiphers) == 0 || len(candidateHashes) == 0 { - return nil, errors.InvalidArgumentError("cannot encrypt because recipient set shares no common algorithms") - } - - cipher := packet.CipherFunction(candidateCiphers[0]) - // If the cipher specified by config is a candidate, we'll use that. - configuredCipher := config.Cipher() - for _, c := range candidateCiphers { - cipherFunc := packet.CipherFunction(c) - if cipherFunc == configuredCipher { - cipher = cipherFunc - break - } - } - - symKey := make([]byte, cipher.KeySize()) - if _, err := io.ReadFull(config.Random(), symKey); err != nil { - return nil, err - } - - for _, key := range encryptKeys { - if err := packet.SerializeEncryptedKey(ciphertext, key.PublicKey, cipher, symKey, config); err != nil { - return nil, err - } - } - - payload, err := packet.SerializeSymmetricallyEncrypted(ciphertext, cipher, symKey, config) - if err != nil { - return - } - - return writeAndSign(payload, candidateHashes, signed, hints, config) -} - -// Sign signs a message. The resulting WriteCloser must be closed after the -// contents of the file have been written. hints contains optional information -// that aids the recipients in processing the message. -// If config is nil, sensible defaults will be used. -func Sign(output io.Writer, signed *Entity, hints *FileHints, config *packet.Config) (input io.WriteCloser, err error) { - if signed == nil { - return nil, errors.InvalidArgumentError("no signer provided") - } - - // These are the possible hash functions that we'll use for the signature. - candidateHashes := []uint8{ - hashToHashId(crypto.SHA256), - hashToHashId(crypto.SHA384), - hashToHashId(crypto.SHA512), - hashToHashId(crypto.SHA1), - hashToHashId(crypto.RIPEMD160), - } - defaultHashes := candidateHashes[len(candidateHashes)-1:] - preferredHashes := signed.primaryIdentity().SelfSignature.PreferredHash - if len(preferredHashes) == 0 { - preferredHashes = defaultHashes - } - candidateHashes = intersectPreferences(candidateHashes, preferredHashes) - return writeAndSign(noOpCloser{output}, candidateHashes, signed, hints, config) -} - -// signatureWriter hashes the contents of a message while passing it along to -// literalData. When closed, it closes literalData, writes a signature packet -// to encryptedData and then also closes encryptedData. -type signatureWriter struct { - encryptedData io.WriteCloser - literalData io.WriteCloser - hashType crypto.Hash - h hash.Hash - signer *packet.PrivateKey - config *packet.Config -} - -func (s signatureWriter) Write(data []byte) (int, error) { - s.h.Write(data) - return s.literalData.Write(data) -} - -func (s signatureWriter) Close() error { - sig := &packet.Signature{ - SigType: packet.SigTypeBinary, - PubKeyAlgo: s.signer.PubKeyAlgo, - Hash: s.hashType, - CreationTime: s.config.Now(), - IssuerKeyId: &s.signer.KeyId, - } - - if err := sig.Sign(s.h, s.signer, s.config); err != nil { - return err - } - if err := s.literalData.Close(); err != nil { - return err - } - if err := sig.Serialize(s.encryptedData); err != nil { - return err - } - return s.encryptedData.Close() -} - -// noOpCloser is like an io.NopCloser, but for an io.Writer. -// TODO: we have two of these in OpenPGP packages alone. This probably needs -// to be promoted somewhere more common. -type noOpCloser struct { - w io.Writer -} - -func (c noOpCloser) Write(data []byte) (n int, err error) { - return c.w.Write(data) -} - -func (c noOpCloser) Close() error { - return nil -} diff --git a/vendor/golang.org/x/net/http2/hpack/encode.go b/vendor/golang.org/x/net/http2/hpack/encode.go index 46219da2b0..e6d0c265ac 100644 --- a/vendor/golang.org/x/net/http2/hpack/encode.go +++ b/vendor/golang.org/x/net/http2/hpack/encode.go @@ -39,7 +39,6 @@ func NewEncoder(w io.Writer) *Encoder { tableSizeUpdate: false, w: w, } - e.dynTab.table.init() e.dynTab.setMaxSize(initialHeaderTableSize) return e } diff --git a/vendor/golang.org/x/net/http2/hpack/hpack.go b/vendor/golang.org/x/net/http2/hpack/hpack.go index 7a1d976696..ecd3eeca99 100644 --- a/vendor/golang.org/x/net/http2/hpack/hpack.go +++ b/vendor/golang.org/x/net/http2/hpack/hpack.go @@ -105,7 +105,6 @@ func NewDecoder(maxDynamicTableSize uint32, emitFunc func(f HeaderField)) *Decod emitEnabled: true, firstField: true, } - d.dynTab.table.init() d.dynTab.allowedMaxSize = maxDynamicTableSize d.dynTab.setMaxSize(maxDynamicTableSize) return d diff --git a/vendor/golang.org/x/net/http2/hpack/tables.go b/vendor/golang.org/x/net/http2/hpack/tables.go index 8cbdf3f019..3bd7eb7533 100644 --- a/vendor/golang.org/x/net/http2/hpack/tables.go +++ b/vendor/golang.org/x/net/http2/hpack/tables.go @@ -31,10 +31,18 @@ type headerFieldTable struct { // byName maps a HeaderField name to the unique id of the newest entry with // the same name. See above for a definition of "unique id". + // + // byName and byNameValue are used only by search, which is only called + // for tables used by encoders. For tables used only by decoders, the + // maps are never built, as a memory optimization for servers with many + // mostly-idle connections, each pinning a dynamic table. The maps are + // built lazily by the first search call and are nil until then. The two + // maps are always both nil or both non-nil. byName map[string]uint64 // byNameValue maps a HeaderField name/value pair to the unique id of the newest // entry with the same name and value. See above for a definition of "unique id". + // See byName for when this map is non-nil. byNameValue map[pairNameValue]uint64 } @@ -42,9 +50,17 @@ type pairNameValue struct { name, value string } -func (t *headerFieldTable) init() { - t.byName = make(map[string]uint64) - t.byNameValue = make(map[pairNameValue]uint64) +// buildMaps initializes byName and byNameValue from ents. +func (t *headerFieldTable) buildMaps() { + t.byName = make(map[string]uint64, len(t.ents)) + t.byNameValue = make(map[pairNameValue]uint64, len(t.ents)) + for k, f := range t.ents { + // Map to the newest matching entry: later (newer) entries + // overwrite earlier ones, matching addEntry's behavior. + id := t.evictCount + uint64(k) + 1 + t.byName[f.Name] = id + t.byNameValue[pairNameValue{f.Name, f.Value}] = id + } } // len reports the number of entries in the table. @@ -54,9 +70,11 @@ func (t *headerFieldTable) len() int { // addEntry adds a new entry. func (t *headerFieldTable) addEntry(f HeaderField) { - id := uint64(t.len()) + t.evictCount + 1 - t.byName[f.Name] = id - t.byNameValue[pairNameValue{f.Name, f.Value}] = id + if t.byName != nil { + id := uint64(t.len()) + t.evictCount + 1 + t.byName[f.Name] = id + t.byNameValue[pairNameValue{f.Name, f.Value}] = id + } t.ents = append(t.ents, f) } @@ -65,14 +83,16 @@ func (t *headerFieldTable) evictOldest(n int) { if n > t.len() { panic(fmt.Sprintf("evictOldest(%v) on table with %v entries", n, t.len())) } - for k := 0; k < n; k++ { - f := t.ents[k] - id := t.evictCount + uint64(k) + 1 - if t.byName[f.Name] == id { - delete(t.byName, f.Name) - } - if p := (pairNameValue{f.Name, f.Value}); t.byNameValue[p] == id { - delete(t.byNameValue, p) + if t.byName != nil { + for k := 0; k < n; k++ { + f := t.ents[k] + id := t.evictCount + uint64(k) + 1 + if t.byName[f.Name] == id { + delete(t.byName, f.Name) + } + if p := (pairNameValue{f.Name, f.Value}); t.byNameValue[p] == id { + delete(t.byNameValue, p) + } } } copy(t.ents, t.ents[n:]) @@ -100,6 +120,9 @@ func (t *headerFieldTable) evictOldest(n int) { // // See Section 2.3.3. func (t *headerFieldTable) search(f HeaderField) (i uint64, nameValueMatch bool) { + if t.byName == nil { + t.buildMaps() + } if !f.Sensitive { if id := t.byNameValue[pairNameValue{f.Name, f.Value}]; id != 0 { return t.idToIndex(id), true diff --git a/vendor/golang.org/x/net/http2/transport_wrap.go b/vendor/golang.org/x/net/http2/transport_wrap.go index 534e77ab96..741fb97062 100644 --- a/vendor/golang.org/x/net/http2/transport_wrap.go +++ b/vendor/golang.org/x/net/http2/transport_wrap.go @@ -237,32 +237,40 @@ type ClientConn struct { } func (cc *ClientConn) roundTrip(req *http.Request) (*http.Response, error) { - err := func() error { + haveReservation, err := func() (bool, error) { cc.mu.Lock() defer cc.mu.Unlock() if cc.doNotReuse { - return errClientConnUnusable - } - cc.roundTrips++ - if cc.reserved > 0 { - // We've already reserved a concurrency slot for this request. - cc.reserved-- - } else if cc.cc.Reserve() != nil { - // We don't seem to have an available concurrency slot, - // so bump the pending count (requests waiting for a slot). - cc.pending++ + return false, errClientConnUnusable } + // ClientConn.Shutdown will not shut down the conn while // cc.starting > 0 or cc.cc.InFlight() > 0. // // The starting state covers the gap between us deciding to // start sending the request, and actually sending it. cc.starting++ - return nil + + cc.roundTrips++ + if cc.reserved == 0 { + // We do not have a concurrency slot reserved for this request. + return false, nil + } + cc.reserved-- + return true, nil }() if err != nil { return nil, err } + // If we have no reservation, try to acquire one. + // (This must be done without cc.mu held, since Reserve may call back to the state hook.) + if !haveReservation && cc.cc.Reserve() != nil { + // We could not acquire a concurrency slot, so bump the pending count + // (requests waiting for a slot). + cc.mu.Lock() + cc.pending++ + cc.mu.Unlock() + } resp, err := cc.cc.RoundTrip(req) cc.mu.Lock() cc.starting-- @@ -293,16 +301,21 @@ func (cc *ClientConn) ping(ctx context.Context) error { } func (cc *ClientConn) reserveNewRequest() bool { + if err := cc.cc.Reserve(); err != nil { + return false + } + reserved := true cc.mu.Lock() - defer cc.mu.Unlock() if cc.doNotReuse { - return false + reserved = false + } else { + cc.reserved++ } - if err := cc.cc.Reserve(); err != nil { - return false + cc.mu.Unlock() + if !reserved { + cc.cc.Release() } - cc.reserved++ - return true + return reserved } func (cc *ClientConn) setDoNotReuse() { diff --git a/vendor/golang.org/x/tools/go/analysis/analysistest/analysistest.go b/vendor/golang.org/x/tools/go/analysis/analysistest/analysistest.go index ef339a4d00..b448fb4496 100644 --- a/vendor/golang.org/x/tools/go/analysis/analysistest/analysistest.go +++ b/vendor/golang.org/x/tools/go/analysis/analysistest/analysistest.go @@ -419,7 +419,7 @@ func Run(t Testing, dir string, a *analysis.Analyzer, patterns ...string) []*Res }) } - res, err := checker.Analyze([]*analysis.Analyzer{a}, pkgs, nil) + res, err := checker.Analyze([]*analysis.Analyzer{a}, pkgs, &checker.Options{SanityCheck: true}) if err != nil { t.Errorf("Analyze: %v", err) return nil diff --git a/vendor/golang.org/x/tools/go/analysis/checker/checker.go b/vendor/golang.org/x/tools/go/analysis/checker/checker.go index bb69dacc1b..bc844ca3ea 100644 --- a/vendor/golang.org/x/tools/go/analysis/checker/checker.go +++ b/vendor/golang.org/x/tools/go/analysis/checker/checker.go @@ -401,7 +401,7 @@ func inheritFacts(act, dep *Action) { if act.opts.SanityCheck { encodedFact, err := codeFact(fact) if err != nil { - log.Panicf("internal error: encoding of %T fact failed in %v", fact, act) + log.Panicf("internal error: encoding of %T fact failed in %v: %v", fact, act, err) } fact = encodedFact } @@ -435,7 +435,7 @@ func inheritFacts(act, dep *Action) { if act.opts.SanityCheck { encodedFact, err := codeFact(fact) if err != nil { - log.Panicf("internal error: encoding of %T fact failed in %v", fact, act) + log.Panicf("internal error: encoding of %T fact failed in %v: %v", fact, act, err) } fact = encodedFact } diff --git a/vendor/golang.org/x/tools/go/analysis/unitchecker/unitchecker.go b/vendor/golang.org/x/tools/go/analysis/unitchecker/unitchecker.go index f6f3cd5ecf..018b4bce3c 100644 --- a/vendor/golang.org/x/tools/go/analysis/unitchecker/unitchecker.go +++ b/vendor/golang.org/x/tools/go/analysis/unitchecker/unitchecker.go @@ -59,7 +59,7 @@ import ( // whose name ends with ".cfg". type Config struct { ID string // e.g. "fmt [fmt.test]" - Compiler string // gc or gccgo, provided to MakeImporter + Compiler string // gc or gccgo, provided to makeTypesImporter Dir string // (unused) ImportPath string // package path GoVersion string // minimum required Go version, such as "go1.21.0" @@ -296,7 +296,7 @@ var ( return importerFunc(func(importPath string) (*types.Package, error) { path, ok := cfg.ImportMap[importPath] // resolve vendoring, etc if !ok { - return nil, fmt.Errorf("can't resolve import %q", path) + return nil, fmt.Errorf("can't resolve import %q", importPath) } return compilerImporter.Import(path) }) diff --git a/vendor/golang.org/x/tools/go/ast/inspector/cursor.go b/vendor/golang.org/x/tools/go/ast/inspector/cursor.go index 239b10c4da..1c482252da 100644 --- a/vendor/golang.org/x/tools/go/ast/inspector/cursor.go +++ b/vendor/golang.org/x/tools/go/ast/inspector/cursor.go @@ -10,6 +10,7 @@ import ( "go/token" "iter" "reflect" + "strings" "golang.org/x/tools/go/ast/edge" ) @@ -110,6 +111,46 @@ func (c Cursor) String() string { return reflect.TypeOf(c.Node()).String() } +// GoString returns a string describing the cursor's path from the +// root, if any. +func (c Cursor) GoString() string { + if !c.Valid() { + return "(invalid)" + } + if c.index < 0 { + return "(root)" + } + // e.g "File.Decls[1].(*ast.GenDecl).Specs[0].(*ast.TypeSpec)" + // + // In hindsight even the File node should have reported a + // virtual ParentEdge of (Root_Files, i) where i is the index + // among the files passed to NewInspector. Then the path would + // read "(root).Files[i]", etc; but we missed the boat. + var buf strings.Builder + buf.WriteString("File") + var visit func(Cursor) + visit = func(c Cursor) { + ek, idx := c.ParentEdge() + if ek == edge.Invalid { + return // File + } + visit(c.Parent()) + fmt.Fprintf(&buf, ".%s", ek.FieldName()) + if idx >= 0 { + fmt.Fprintf(&buf, "[%d]", idx) + } + ftype := ek.FieldType() + if idx >= 0 { + ftype = ftype.Elem() // []T -> T + } + if ftype.Kind() == reflect.Interface { + fmt.Fprintf(&buf, ".(%T)", c.Node()) + } + } + visit(c) + return buf.String() +} + // indices return the [start, end) half-open interval of event indices. func (c Cursor) indices() (int32, int32) { if c.index < 0 { diff --git a/vendor/golang.org/x/tools/go/packages/visit.go b/vendor/golang.org/x/tools/go/packages/visit.go index c546b1b63e..06747a9df7 100644 --- a/vendor/golang.org/x/tools/go/packages/visit.go +++ b/vendor/golang.org/x/tools/go/packages/visit.go @@ -5,11 +5,11 @@ package packages import ( - "cmp" "fmt" "iter" "os" - "slices" + + "golang.org/x/tools/internal/moremaps" ) // Visit visits all the packages in the import graph whose roots are @@ -40,7 +40,7 @@ func Visit(pkgs []*Package, pre func(*Package) bool, post func(*Package)) { seen[pkg] = true if pre == nil || pre(pkg) { - for _, imp := range sorted(pkg.Imports) { // for determinism + for _, imp := range moremaps.Sorted(pkg.Imports) { // for determinism visit(imp) } } @@ -88,7 +88,7 @@ func Postorder(pkgs []*Package) iter.Seq[*Package] { visit = func(pkg *Package) bool { if !seen[pkg] { seen[pkg] = true - for _, imp := range sorted(pkg.Imports) { // for determinism + for _, imp := range moremaps.Sorted(pkg.Imports) { // for determinism if !visit(imp) { return false } @@ -106,28 +106,3 @@ func Postorder(pkgs []*Package) iter.Seq[*Package] { } } } - -// -- copied from golang.org.x/tools/gopls/internal/util/moremaps -- - -// sorted returns an iterator over the entries of m in key order. -func sorted[M ~map[K]V, K cmp.Ordered, V any](m M) iter.Seq2[K, V] { - // TODO(adonovan): use maps.Sorted if proposal #68598 is accepted. - return func(yield func(K, V) bool) { - keys := keySlice(m) - slices.Sort(keys) - for _, k := range keys { - if !yield(k, m[k]) { - break - } - } - } -} - -// KeySlice returns the keys of the map M, like slices.Collect(maps.Keys(m)). -func keySlice[M ~map[K]V, K comparable, V any](m M) []K { - r := make([]K, 0, len(m)) - for k := range m { - r = append(r, k) - } - return r -} diff --git a/vendor/golang.org/x/tools/go/types/typeutil/callee.go b/vendor/golang.org/x/tools/go/types/typeutil/callee.go deleted file mode 100644 index 3d24a8c637..0000000000 --- a/vendor/golang.org/x/tools/go/types/typeutil/callee.go +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package typeutil - -import ( - "go/ast" - "go/types" - _ "unsafe" // for linkname -) - -// Callee returns the named target of a function call, if any: -// a function, method, builtin, or variable. -// It returns nil for a T(x) conversion. -// -// Functions and methods may potentially have type parameters. -// -// Note: for calls of instantiated functions and methods, Callee returns -// the corresponding generic function or method on the generic type. -func Callee(info *types.Info, call *ast.CallExpr) types.Object { - obj := info.Uses[usedIdent(info, call.Fun)] - if obj == nil { - return nil - } - if _, ok := obj.(*types.TypeName); ok { - return nil - } - return obj -} - -// StaticCallee returns the target (function or method) of a static function -// call, if any. It returns nil for calls to builtins. -// -// Note: for calls of instantiated functions and methods, StaticCallee returns -// the corresponding generic function or method on the generic type. -func StaticCallee(info *types.Info, call *ast.CallExpr) *types.Func { - obj := info.Uses[usedIdent(info, call.Fun)] - fn, _ := obj.(*types.Func) - if fn == nil || interfaceMethod(fn) { - return nil - } - return fn -} - -// usedIdent is the implementation of [internal/typesinternal.UsedIdent]. -// It returns the identifier associated with e. -// See typesinternal.UsedIdent for a fuller description. -// This function should live in typesinternal, but cannot because it would -// create an import cycle. -// -//go:linkname usedIdent golang.org/x/tools/go/types/typeutil.usedIdent -func usedIdent(info *types.Info, e ast.Expr) *ast.Ident { - if info.Types == nil || info.Uses == nil { - panic("one of info.Types or info.Uses is nil; both must be populated") - } - // Look through type instantiation if necessary. - switch d := ast.Unparen(e).(type) { - case *ast.IndexExpr: - if info.Types[d.Index].IsType() { - e = d.X - } - case *ast.IndexListExpr: - e = d.X - } - - switch e := ast.Unparen(e).(type) { - // info.Uses always has the object we want, even for selector expressions. - // We don't need info.Selections. - // See go/types/recording.go:recordSelection. - case *ast.Ident: - return e - case *ast.SelectorExpr: - return e.Sel - } - return nil -} - -// interfaceMethod reports whether its argument is a method of an interface. -// This function should live in typesinternal, but cannot because it would create an import cycle. -// -//go:linkname interfaceMethod golang.org/x/tools/go/types/typeutil.interfaceMethod -func interfaceMethod(f *types.Func) bool { - recv := f.Signature().Recv() - return recv != nil && types.IsInterface(recv.Type()) -} diff --git a/vendor/golang.org/x/tools/go/types/typeutil/imports.go b/vendor/golang.org/x/tools/go/types/typeutil/imports.go deleted file mode 100644 index b81ce0c330..0000000000 --- a/vendor/golang.org/x/tools/go/types/typeutil/imports.go +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package typeutil - -import "go/types" - -// Dependencies returns all dependencies of the specified packages. -// -// Dependent packages appear in topological order: if package P imports -// package Q, Q appears earlier than P in the result. -// The algorithm follows import statements in the order they -// appear in the source code, so the result is a total order. -func Dependencies(pkgs ...*types.Package) []*types.Package { - var result []*types.Package - seen := make(map[*types.Package]bool) - var visit func(pkgs []*types.Package) - visit = func(pkgs []*types.Package) { - for _, p := range pkgs { - if !seen[p] { - seen[p] = true - visit(p.Imports()) - result = append(result, p) - } - } - } - visit(pkgs) - return result -} diff --git a/vendor/golang.org/x/tools/go/types/typeutil/map.go b/vendor/golang.org/x/tools/go/types/typeutil/map.go deleted file mode 100644 index 36624572a6..0000000000 --- a/vendor/golang.org/x/tools/go/types/typeutil/map.go +++ /dev/null @@ -1,459 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package typeutil defines various utilities for types, such as [Map], -// a hash table that maps [types.Type] to any value. -package typeutil - -import ( - "bytes" - "fmt" - "go/types" - "hash/maphash" - - "golang.org/x/tools/internal/typeparams" -) - -// Map is a hash-table-based mapping from types (types.Type) to -// arbitrary values. The concrete types that implement -// the Type interface are pointers. Since they are not canonicalized, -// == cannot be used to check for equivalence, and thus we cannot -// simply use a Go map. -// -// Just as with map[K]V, a nil *Map is a valid empty map. -// -// Read-only map operations ([Map.At], [Map.Len], and so on) may -// safely be called concurrently. -// -// TODO(adonovan): deprecate in favor of https://go.dev/issues/69420 -// and 69559, if the latter proposals for a generic hash-map type and -// a types.Hash function are accepted. -type Map struct { - table map[uint32][]entry // maps hash to bucket; entry.key==nil means unused - length int // number of map entries -} - -// entry is an entry (key/value association) in a hash bucket. -type entry struct { - key types.Type - value any -} - -// SetHasher has no effect. -// -// It is a relic of an optimization that is no longer profitable. Do -// not use [Hasher], [MakeHasher], or [SetHasher] in new code. -func (m *Map) SetHasher(Hasher) {} - -// Delete removes the entry with the given key, if any. -// It returns true if the entry was found. -func (m *Map) Delete(key types.Type) bool { - if m != nil && m.table != nil { - hash := hash(key) - bucket := m.table[hash] - for i, e := range bucket { - if e.key != nil && types.Identical(key, e.key) { - // We can't compact the bucket as it - // would disturb iterators. - bucket[i] = entry{} - m.length-- - return true - } - } - } - return false -} - -// At returns the map entry for the given key. -// The result is nil if the entry is not present. -func (m *Map) At(key types.Type) any { - if m != nil && m.table != nil { - for _, e := range m.table[hash(key)] { - if e.key != nil && types.Identical(key, e.key) { - return e.value - } - } - } - return nil -} - -// Set sets the map entry for key to val, -// and returns the previous entry, if any. -func (m *Map) Set(key types.Type, value any) (prev any) { - if m.table != nil { - hash := hash(key) - bucket := m.table[hash] - var hole *entry - for i, e := range bucket { - if e.key == nil { - hole = &bucket[i] - } else if types.Identical(key, e.key) { - prev = e.value - bucket[i].value = value - return - } - } - - if hole != nil { - *hole = entry{key, value} // overwrite deleted entry - } else { - m.table[hash] = append(bucket, entry{key, value}) - } - } else { - hash := hash(key) - m.table = map[uint32][]entry{hash: {entry{key, value}}} - } - - m.length++ - return -} - -// Len returns the number of map entries. -func (m *Map) Len() int { - if m != nil { - return m.length - } - return 0 -} - -// Iterate calls function f on each entry in the map in unspecified order. -// -// If f should mutate the map, Iterate provides the same guarantees as -// Go maps: if f deletes a map entry that Iterate has not yet reached, -// f will not be invoked for it, but if f inserts a map entry that -// Iterate has not yet reached, whether or not f will be invoked for -// it is unspecified. -func (m *Map) Iterate(f func(key types.Type, value any)) { - if m != nil { - for _, bucket := range m.table { - for _, e := range bucket { - if e.key != nil { - f(e.key, e.value) - } - } - } - } -} - -// Keys returns a new slice containing the set of map keys. -// The order is unspecified. -func (m *Map) Keys() []types.Type { - keys := make([]types.Type, 0, m.Len()) - m.Iterate(func(key types.Type, _ any) { - keys = append(keys, key) - }) - return keys -} - -func (m *Map) toString(values bool) string { - if m == nil { - return "{}" - } - var buf bytes.Buffer - fmt.Fprint(&buf, "{") - sep := "" - m.Iterate(func(key types.Type, value any) { - fmt.Fprint(&buf, sep) - sep = ", " - fmt.Fprint(&buf, key) - if values { - fmt.Fprintf(&buf, ": %q", value) - } - }) - fmt.Fprint(&buf, "}") - return buf.String() -} - -// String returns a string representation of the map's entries. -// Values are printed using fmt.Sprintf("%v", v). -// Order is unspecified. -func (m *Map) String() string { - return m.toString(true) -} - -// KeysString returns a string representation of the map's key set. -// Order is unspecified. -func (m *Map) KeysString() string { - return m.toString(false) -} - -// -- Hasher -- - -// hash returns the hash of type t. -// TODO(adonovan): replace by types.Hash when Go proposal #69420 is accepted. -func hash(t types.Type) uint32 { - return theHasher.Hash(t) -} - -// A Hasher provides a [Hasher.Hash] method to map a type to its hash value. -// Hashers are stateless, and all are equivalent. -type Hasher struct{} - -var theHasher Hasher - -// MakeHasher returns Hasher{}. -// Hashers are stateless; all are equivalent. -func MakeHasher() Hasher { return theHasher } - -// Hash computes a hash value for the given type t such that -// Identical(t, t') => Hash(t) == Hash(t'). -func (h Hasher) Hash(t types.Type) uint32 { - return hasher{inGenericSig: false}.hash(t) -} - -// hasher holds the state of a single Hash traversal: whether we are -// inside the signature of a generic function; this is used to -// optimize [hasher.hashTypeParam]. -type hasher struct{ inGenericSig bool } - -// hashString computes the Fowler–Noll–Vo hash of s. -func hashString(s string) uint32 { - var h uint32 - for i := 0; i < len(s); i++ { - h ^= uint32(s[i]) - h *= 16777619 - } - return h -} - -// hash computes the hash of t. -func (h hasher) hash(t types.Type) uint32 { - // See Identical for rationale. - switch t := t.(type) { - case *types.Basic: - return uint32(t.Kind()) - - case *types.Alias: - return h.hash(types.Unalias(t)) - - case *types.Array: - return 9043 + 2*uint32(t.Len()) + 3*h.hash(t.Elem()) - - case *types.Slice: - return 9049 + 2*h.hash(t.Elem()) - - case *types.Struct: - var hash uint32 = 9059 - for i, n := 0, t.NumFields(); i < n; i++ { - f := t.Field(i) - if f.Anonymous() { - hash += 8861 - } - hash += hashString(t.Tag(i)) - hash += hashString(f.Name()) // (ignore f.Pkg) - hash += h.hash(f.Type()) - } - return hash - - case *types.Pointer: - return 9067 + 2*h.hash(t.Elem()) - - case *types.Signature: - var hash uint32 = 9091 - if t.Variadic() { - hash *= 8863 - } - - tparams := t.TypeParams() - if n := tparams.Len(); n > 0 { - h.inGenericSig = true // affects constraints, params, and results - - for i := range n { - tparam := tparams.At(i) - hash += 7 * h.hash(tparam.Constraint()) - } - } - - return hash + 3*h.hashTuple(t.Params()) + 5*h.hashTuple(t.Results()) - - case *types.Union: - return h.hashUnion(t) - - case *types.Interface: - // Interfaces are identical if they have the same set of methods, with - // identical names and types, and they have the same set of type - // restrictions. See go/types.identical for more details. - var hash uint32 = 9103 - - // Hash methods. - for i, n := 0, t.NumMethods(); i < n; i++ { - // Method order is not significant. - // Ignore m.Pkg(). - m := t.Method(i) - // Use shallow hash on method signature to - // avoid anonymous interface cycles. - hash += 3*hashString(m.Name()) + 5*h.shallowHash(m.Type()) - } - - // Hash type restrictions. - terms, err := typeparams.InterfaceTermSet(t) - // if err != nil t has invalid type restrictions. - if err == nil { - hash += h.hashTermSet(terms) - } - - return hash - - case *types.Map: - return 9109 + 2*h.hash(t.Key()) + 3*h.hash(t.Elem()) - - case *types.Chan: - return 9127 + 2*uint32(t.Dir()) + 3*h.hash(t.Elem()) - - case *types.Named: - hash := h.hashTypeName(t.Obj()) - targs := t.TypeArgs() - for targ := range targs.Types() { - hash += 2 * h.hash(targ) - } - return hash - - case *types.TypeParam: - return h.hashTypeParam(t) - - case *types.Tuple: - return h.hashTuple(t) - } - - panic(fmt.Sprintf("%T: %v", t, t)) -} - -func (h hasher) hashTuple(tuple *types.Tuple) uint32 { - // See go/types.identicalTypes for rationale. - n := tuple.Len() - hash := 9137 + 2*uint32(n) - for i := range n { - hash += 3 * h.hash(tuple.At(i).Type()) - } - return hash -} - -func (h hasher) hashUnion(t *types.Union) uint32 { - // Hash type restrictions. - terms, err := typeparams.UnionTermSet(t) - // if err != nil t has invalid type restrictions. Fall back on a non-zero - // hash. - if err != nil { - return 9151 - } - return h.hashTermSet(terms) -} - -func (h hasher) hashTermSet(terms []*types.Term) uint32 { - hash := 9157 + 2*uint32(len(terms)) - for _, term := range terms { - // term order is not significant. - termHash := h.hash(term.Type()) - if term.Tilde() { - termHash *= 9161 - } - hash += 3 * termHash - } - return hash -} - -// hashTypeParam returns the hash of a type parameter. -func (h hasher) hashTypeParam(t *types.TypeParam) uint32 { - // Within the signature of a generic function, TypeParams are - // identical if they have the same index and constraint, so we - // hash them based on index. - // - // When we are outside a generic function, free TypeParams are - // identical iff they are the same object, so we can use a - // more discriminating hash consistent with object identity. - // This optimization saves [Map] about 4% when hashing all the - // types.Info.Types in the forward closure of net/http. - if !h.inGenericSig { - // Optimization: outside a generic function signature, - // use a more discrimating hash consistent with object identity. - return h.hashTypeName(t.Obj()) - } - return 9173 + 3*uint32(t.Index()) -} - -var theSeed = maphash.MakeSeed() - -// hashTypeName hashes the pointer of tname. -func (hasher) hashTypeName(tname *types.TypeName) uint32 { - // Since types.Identical uses == to compare TypeNames, - // the Hash function uses maphash.Comparable. - hash := maphash.Comparable(theSeed, tname) - return uint32(hash ^ (hash >> 32)) -} - -// shallowHash computes a hash of t without looking at any of its -// element Types, to avoid potential anonymous cycles in the types of -// interface methods. -// -// When an unnamed non-empty interface type appears anywhere among the -// arguments or results of an interface method, there is a potential -// for endless recursion. Consider: -// -// type X interface { m() []*interface { X } } -// -// The problem is that the Methods of the interface in m's result type -// include m itself; there is no mention of the named type X that -// might help us break the cycle. -// (See comment in go/types.identical, case *Interface, for more.) -func (h hasher) shallowHash(t types.Type) uint32 { - // t is the type of an interface method (Signature), - // its params or results (Tuples), or their immediate - // elements (mostly Slice, Pointer, Basic, Named), - // so there's no need to optimize anything else. - switch t := t.(type) { - case *types.Alias: - return h.shallowHash(types.Unalias(t)) - - case *types.Signature: - var hash uint32 = 604171 - if t.Variadic() { - hash *= 971767 - } - // The Signature/Tuple recursion is always finite - // and invariably shallow. - return hash + 1062599*h.shallowHash(t.Params()) + 1282529*h.shallowHash(t.Results()) - - case *types.Tuple: - n := t.Len() - hash := 9137 + 2*uint32(n) - for i := range n { - hash += 53471161 * h.shallowHash(t.At(i).Type()) - } - return hash - - case *types.Basic: - return 45212177 * uint32(t.Kind()) - - case *types.Array: - return 1524181 + 2*uint32(t.Len()) - - case *types.Slice: - return 2690201 - - case *types.Struct: - return 3326489 - - case *types.Pointer: - return 4393139 - - case *types.Union: - return 562448657 - - case *types.Interface: - return 2124679 // no recursion here - - case *types.Map: - return 9109 - - case *types.Chan: - return 9127 - - case *types.Named: - return h.hashTypeName(t.Obj()) - - case *types.TypeParam: - return h.hashTypeParam(t) - } - panic(fmt.Sprintf("shallowHash: %T: %v", t, t)) -} diff --git a/vendor/golang.org/x/tools/go/types/typeutil/methodsetcache.go b/vendor/golang.org/x/tools/go/types/typeutil/methodsetcache.go deleted file mode 100644 index f7666028fe..0000000000 --- a/vendor/golang.org/x/tools/go/types/typeutil/methodsetcache.go +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// This file implements a cache of method sets. - -package typeutil - -import ( - "go/types" - "sync" -) - -// A MethodSetCache records the method set of each type T for which -// MethodSet(T) is called so that repeat queries are fast. -// The zero value is a ready-to-use cache instance. -type MethodSetCache struct { - mu sync.Mutex - named map[*types.Named]struct{ value, pointer *types.MethodSet } // method sets for named N and *N - others map[types.Type]*types.MethodSet // all other types -} - -// MethodSet returns the method set of type T. It is thread-safe. -// -// If cache is nil, this function is equivalent to types.NewMethodSet(T). -// Utility functions can thus expose an optional *MethodSetCache -// parameter to clients that care about performance. -func (cache *MethodSetCache) MethodSet(T types.Type) *types.MethodSet { - if cache == nil { - return types.NewMethodSet(T) - } - cache.mu.Lock() - defer cache.mu.Unlock() - - switch T := types.Unalias(T).(type) { - case *types.Named: - return cache.lookupNamed(T).value - - case *types.Pointer: - if N, ok := types.Unalias(T.Elem()).(*types.Named); ok { - return cache.lookupNamed(N).pointer - } - } - - // all other types - // (The map uses pointer equivalence, not type identity.) - mset := cache.others[T] - if mset == nil { - mset = types.NewMethodSet(T) - if cache.others == nil { - cache.others = make(map[types.Type]*types.MethodSet) - } - cache.others[T] = mset - } - return mset -} - -func (cache *MethodSetCache) lookupNamed(named *types.Named) struct{ value, pointer *types.MethodSet } { - if cache.named == nil { - cache.named = make(map[*types.Named]struct{ value, pointer *types.MethodSet }) - } - // Avoid recomputing mset(*T) for each distinct Pointer - // instance whose underlying type is a named type. - msets, ok := cache.named[named] - if !ok { - msets.value = types.NewMethodSet(named) - msets.pointer = types.NewMethodSet(types.NewPointer(named)) - cache.named[named] = msets - } - return msets -} diff --git a/vendor/golang.org/x/tools/go/types/typeutil/ui.go b/vendor/golang.org/x/tools/go/types/typeutil/ui.go deleted file mode 100644 index 9dda6a25df..0000000000 --- a/vendor/golang.org/x/tools/go/types/typeutil/ui.go +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package typeutil - -// This file defines utilities for user interfaces that display types. - -import ( - "go/types" -) - -// IntuitiveMethodSet returns the intuitive method set of a type T, -// which is the set of methods you can call on an addressable value of -// that type. -// -// The result always contains MethodSet(T), and is exactly MethodSet(T) -// for interface types and for pointer-to-concrete types. -// For all other concrete types T, the result additionally -// contains each method belonging to *T if there is no identically -// named method on T itself. -// -// This corresponds to user intuition about method sets; -// this function is intended only for user interfaces. -// -// The order of the result is as for types.MethodSet(T). -func IntuitiveMethodSet(T types.Type, msets *MethodSetCache) []*types.Selection { - isPointerToConcrete := func(T types.Type) bool { - ptr, ok := types.Unalias(T).(*types.Pointer) - return ok && !types.IsInterface(ptr.Elem()) - } - - var result []*types.Selection - mset := msets.MethodSet(T) - if types.IsInterface(T) || isPointerToConcrete(T) { - for i, n := 0, mset.Len(); i < n; i++ { - result = append(result, mset.At(i)) - } - } else { - // T is some other concrete type. - // Report methods of T and *T, preferring those of T. - pmset := msets.MethodSet(types.NewPointer(T)) - for i, n := 0, pmset.Len(); i < n; i++ { - meth := pmset.At(i) - if m := mset.Lookup(meth.Obj().Pkg(), meth.Obj().Name()); m != nil { - meth = m - } - result = append(result, meth) - } - - } - return result -} diff --git a/vendor/golang.org/x/tools/internal/moremaps/maps.go b/vendor/golang.org/x/tools/internal/moremaps/maps.go new file mode 100644 index 0000000000..a1bae078b1 --- /dev/null +++ b/vendor/golang.org/x/tools/internal/moremaps/maps.go @@ -0,0 +1,116 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package moremaps contains more functions for working with maps. +package moremaps + +import ( + "cmp" + "iter" + "maps" + "slices" +) + +// Arbitrary returns an arbitrary (key, value) entry from the map and ok is true, if +// the map is not empty. Otherwise, it returns zero values for K and V, and false. +func Arbitrary[K comparable, V any](m map[K]V) (_ K, _ V, ok bool) { + for k, v := range m { + return k, v, true + } + return +} + +// Group returns a new non-nil map containing the elements of s grouped by the +// keys returned from the key func. +func Group[K comparable, V any](s []V, key func(V) K) map[K][]V { + m := make(map[K][]V) + for _, v := range s { + k := key(v) + m[k] = append(m[k], v) + } + return m +} + +// KeySlice returns the keys of the map M, like slices.Collect(maps.Keys(m)). +func KeySlice[M ~map[K]V, K comparable, V any](m M) []K { + r := make([]K, 0, len(m)) + for k := range m { + r = append(r, k) + } + return r +} + +// ValueSlice returns the values of the map M, like slices.Collect(maps.Values(m)). +func ValueSlice[M ~map[K]V, K comparable, V any](m M) []V { + r := make([]V, 0, len(m)) + for _, v := range m { + r = append(r, v) + } + return r +} + +// SameKeys reports whether x and y have equal sets of keys. +func SameKeys[K comparable, V1, V2 any](x map[K]V1, y map[K]V2) bool { + ignoreValues := func(V1, V2) bool { return true } + return maps.EqualFunc(x, y, ignoreValues) +} + +// Sorted returns an iterator over the entries of m in key order. +func Sorted[M ~map[K]V, K cmp.Ordered, V any](m M) iter.Seq2[K, V] { + // TODO(adonovan): use maps.Sorted if proposal #68598 is accepted. + return func(yield func(K, V) bool) { + keys := KeySlice(m) + slices.Sort(keys) + for _, k := range keys { + if !yield(k, m[k]) { + break + } + } + } +} + +// SortedFunc returns an iterator over the entries of m in the key order determined by cmp. +func SortedFunc[M ~map[K]V, K comparable, V any](m M, cmp func(x, y K) int) iter.Seq2[K, V] { + // TODO(adonovan): use maps.SortedFunc if proposal #68598 is accepted. + return func(yield func(K, V) bool) { + keys := KeySlice(m) + slices.SortFunc(keys, cmp) + for _, k := range keys { + if !yield(k, m[k]) { + break + } + } + } +} + +// Delete is like delete(m, k) but reports whether deletion occurred. +func Delete[M ~map[K]V, K comparable, V any](m M, k K) bool { + pre := len(m) + delete(m, k) + return pre != len(m) +} + +// Entry is a key-value pair obtained from a map. +type Entry[K comparable, V any] struct { + Key K + Value V +} + +// Entries returns a new unordered array of the entries of a map. +func Entries[M ~map[K]V, K comparable, V any](m M) []Entry[K, V] { + entries := make([]Entry[K, V], 0, len(m)) + for k, v := range m { + entries = append(entries, Entry[K, V]{k, v}) + } + return entries +} + +// FromEntries returns a new map into which the entries have been inserted in order. +func FromEntries[K comparable, V any](entries []Entry[K, V]) map[K]V { + m := make(map[K]V, len(entries)) + for _, e := range entries { + m[e.Key] = e.Value + } + return m +} diff --git a/vendor/golang.org/x/tools/internal/typeparams/common.go b/vendor/golang.org/x/tools/internal/typeparams/common.go deleted file mode 100644 index cdae2b8e81..0000000000 --- a/vendor/golang.org/x/tools/internal/typeparams/common.go +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2021 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package typeparams contains common utilities for writing tools that -// interact with generic Go code, as introduced with Go 1.18. It -// supplements the standard library APIs. Notably, the StructuralTerms -// API computes a minimal representation of the structural -// restrictions on a type parameter. -// -// An external version of these APIs is available in the -// golang.org/x/exp/typeparams module. -package typeparams - -import ( - "go/ast" - "go/token" - "go/types" -) - -// UnpackIndexExpr extracts data from AST nodes that represent index -// expressions. -// -// For an ast.IndexExpr, the resulting indices slice will contain exactly one -// index expression. For an ast.IndexListExpr (go1.18+), it may have a variable -// number of index expressions. -// -// For nodes that don't represent index expressions, the first return value of -// UnpackIndexExpr will be nil. -func UnpackIndexExpr(n ast.Node) (x ast.Expr, lbrack token.Pos, indices []ast.Expr, rbrack token.Pos) { - switch e := n.(type) { - case *ast.IndexExpr: - return e.X, e.Lbrack, []ast.Expr{e.Index}, e.Rbrack - case *ast.IndexListExpr: - return e.X, e.Lbrack, e.Indices, e.Rbrack - } - return nil, token.NoPos, nil, token.NoPos -} - -// PackIndexExpr returns an *ast.IndexExpr or *ast.IndexListExpr, depending on -// the cardinality of indices. Calling PackIndexExpr with len(indices) == 0 -// will panic. -func PackIndexExpr(x ast.Expr, lbrack token.Pos, indices []ast.Expr, rbrack token.Pos) ast.Expr { - switch len(indices) { - case 0: - panic("empty indices") - case 1: - return &ast.IndexExpr{ - X: x, - Lbrack: lbrack, - Index: indices[0], - Rbrack: rbrack, - } - default: - return &ast.IndexListExpr{ - X: x, - Lbrack: lbrack, - Indices: indices, - Rbrack: rbrack, - } - } -} - -// IsTypeParam reports whether t is a type parameter (or an alias of one). -func IsTypeParam(t types.Type) bool { - _, ok := types.Unalias(t).(*types.TypeParam) - return ok -} diff --git a/vendor/golang.org/x/tools/internal/typeparams/coretype.go b/vendor/golang.org/x/tools/internal/typeparams/coretype.go deleted file mode 100644 index 2e05de4649..0000000000 --- a/vendor/golang.org/x/tools/internal/typeparams/coretype.go +++ /dev/null @@ -1,157 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package typeparams - -import ( - "fmt" - "go/types" -) - -// CoreType returns the core type of T or nil if T does not have a core type. -// -// As of Go1.25, the notion of a core type has been removed from the language spec. -// See https://go.dev/blog/coretypes for more details. -// TODO(mkalil): We should eventually consider removing all uses of CoreType. -func CoreType(T types.Type) types.Type { - U := T.Underlying() - if _, ok := U.(*types.Interface); !ok { - return U // for non-interface types, - } - - terms, err := NormalTerms(U) - if len(terms) == 0 || err != nil { - // len(terms) -> empty type set of interface. - // err != nil => U is invalid, exceeds complexity bounds, or has an empty type set. - return nil // no core type. - } - - U = terms[0].Type().Underlying() - var identical int // i in [0,identical) => Identical(U, terms[i].Type().Underlying()) - for identical = 1; identical < len(terms); identical++ { - if !types.Identical(U, terms[identical].Type().Underlying()) { - break - } - } - - if identical == len(terms) { - // From the deprecated core types spec: - // "There is a single type U which is the underlying type of all types in the type set of T" - return U - } - ch, ok := U.(*types.Chan) - if !ok { - return nil // no core type as identical < len(terms) and U is not a channel. - } - // From the deprecated core types spec: - // "the type chan E if T contains only bidirectional channels, or the type chan<- E or - // <-chan E depending on the direction of the directional channels present." - for chans := identical; chans < len(terms); chans++ { - curr, ok := terms[chans].Type().Underlying().(*types.Chan) - if !ok { - return nil - } - if !types.Identical(ch.Elem(), curr.Elem()) { - return nil // channel elements are not identical. - } - if ch.Dir() == types.SendRecv { - // ch is bidirectional. We can safely always use curr's direction. - ch = curr - } else if curr.Dir() != types.SendRecv && ch.Dir() != curr.Dir() { - // ch and curr are not bidirectional and not the same direction. - return nil - } - } - return ch -} - -// NormalTerms returns a slice of terms representing the normalized structural -// type restrictions of a type, if any. -// -// For all types other than *types.TypeParam, *types.Interface, and -// *types.Union, this is just a single term with Tilde() == false and -// Type() == typ. For *types.TypeParam, *types.Interface, and *types.Union, see -// below. -// -// Structural type restrictions of a type parameter are created via -// non-interface types embedded in its constraint interface (directly, or via a -// chain of interface embeddings). For example, in the declaration type -// T[P interface{~int; m()}] int the structural restriction of the type -// parameter P is ~int. -// -// With interface embedding and unions, the specification of structural type -// restrictions may be arbitrarily complex. For example, consider the -// following: -// -// type A interface{ ~string|~[]byte } -// -// type B interface{ int|string } -// -// type C interface { ~string|~int } -// -// type T[P interface{ A|B; C }] int -// -// In this example, the structural type restriction of P is ~string|int: A|B -// expands to ~string|~[]byte|int|string, which reduces to ~string|~[]byte|int, -// which when intersected with C (~string|~int) yields ~string|int. -// -// NormalTerms computes these expansions and reductions, producing a -// "normalized" form of the embeddings. A structural restriction is normalized -// if it is a single union containing no interface terms, and is minimal in the -// sense that removing any term changes the set of types satisfying the -// constraint. It is left as a proof for the reader that, modulo sorting, there -// is exactly one such normalized form. -// -// Because the minimal representation always takes this form, NormalTerms -// returns a slice of tilde terms corresponding to the terms of the union in -// the normalized structural restriction. An error is returned if the type is -// invalid, exceeds complexity bounds, or has an empty type set. In the latter -// case, NormalTerms returns ErrEmptyTypeSet. -// -// NormalTerms makes no guarantees about the order of terms, except that it -// is deterministic. -func NormalTerms(T types.Type) ([]*types.Term, error) { - // typeSetOf(T) == typeSetOf(Unalias(T)) - typ := types.Unalias(T) - if named, ok := typ.(*types.Named); ok { - typ = named.Underlying() - } - switch typ := typ.(type) { - case *types.TypeParam: - return StructuralTerms(typ) - case *types.Union: - return UnionTermSet(typ) - case *types.Interface: - return InterfaceTermSet(typ) - default: - return []*types.Term{types.NewTerm(false, T)}, nil - } -} - -// Deref returns the type of the variable pointed to by t, -// if t's core type is a pointer; otherwise it returns t. -// -// Do not assume that Deref(T)==T implies T is not a pointer: -// consider "type T *T", for example. -// -// TODO(adonovan): ideally this would live in typesinternal, but that -// creates an import cycle. Move there when we melt this package down. -func Deref(t types.Type) types.Type { - if ptr, ok := CoreType(t).(*types.Pointer); ok { - return ptr.Elem() - } - return t -} - -// MustDeref returns the type of the variable pointed to by t. -// It panics if t's core type is not a pointer. -// -// TODO(adonovan): ideally this would live in typesinternal, but that -// creates an import cycle. Move there when we melt this package down. -func MustDeref(t types.Type) types.Type { - if ptr, ok := CoreType(t).(*types.Pointer); ok { - return ptr.Elem() - } - panic(fmt.Sprintf("%v is not a pointer", t)) -} diff --git a/vendor/golang.org/x/tools/internal/typeparams/free.go b/vendor/golang.org/x/tools/internal/typeparams/free.go deleted file mode 100644 index 4c391876e4..0000000000 --- a/vendor/golang.org/x/tools/internal/typeparams/free.go +++ /dev/null @@ -1,129 +0,0 @@ -// Copyright 2024 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package typeparams - -import ( - "go/types" -) - -// Free is a memoization of the set of free type parameters within a -// type. It makes a sequence of calls to [Free.Has] for overlapping -// types more efficient. The zero value is ready for use. -// -// NOTE: Adapted from go/types/infer.go. If it is later exported, factor. -type Free struct { - seen map[types.Type]bool -} - -// Has reports whether the specified type has a free type parameter. -func (w *Free) Has(typ types.Type) (res bool) { - // detect cycles - if x, ok := w.seen[typ]; ok { - return x - } - if w.seen == nil { - w.seen = make(map[types.Type]bool) - } - w.seen[typ] = false - defer func() { - w.seen[typ] = res - }() - - switch t := typ.(type) { - case nil, *types.Basic: // TODO(gri) should nil be handled here? - break - - case *types.Alias: - if t.TypeParams().Len() > t.TypeArgs().Len() { - return true // This is an uninstantiated Alias. - } - // The expansion of an alias can have free type parameters, - // whether or not the alias itself has type parameters: - // - // func _[K comparable]() { - // type Set = map[K]bool // free(Set) = {K} - // type MapTo[V] = map[K]V // free(Map[foo]) = {V} - // } - // - // So, we must Unalias. - return w.Has(types.Unalias(t)) - - case *types.Array: - return w.Has(t.Elem()) - - case *types.Slice: - return w.Has(t.Elem()) - - case *types.Struct: - for i, n := 0, t.NumFields(); i < n; i++ { - if w.Has(t.Field(i).Type()) { - return true - } - } - - case *types.Pointer: - return w.Has(t.Elem()) - - case *types.Tuple: - n := t.Len() - for i := range n { - if w.Has(t.At(i).Type()) { - return true - } - } - - case *types.Signature: - // t.tparams may not be nil if we are looking at a signature - // of a generic function type (or an interface method) that is - // part of the type we're testing. We don't care about these type - // parameters. - // Similarly, the receiver of a method may declare (rather than - // use) type parameters, we don't care about those either. - // Thus, we only need to look at the input and result parameters. - return w.Has(t.Params()) || w.Has(t.Results()) - - case *types.Interface: - for i, n := 0, t.NumMethods(); i < n; i++ { - if w.Has(t.Method(i).Type()) { - return true - } - } - terms, err := InterfaceTermSet(t) - if err != nil { - return false // ill typed - } - for _, term := range terms { - if w.Has(term.Type()) { - return true - } - } - - case *types.Map: - return w.Has(t.Key()) || w.Has(t.Elem()) - - case *types.Chan: - return w.Has(t.Elem()) - - case *types.Named: - args := t.TypeArgs() - if params := t.TypeParams(); params.Len() > args.Len() { - return true // this is an uninstantiated named type. - } - for i, n := 0, args.Len(); i < n; i++ { - if w.Has(args.At(i)) { - return true - } - } - return w.Has(t.Underlying()) // recurse for types local to parameterized functions - - case *types.TypeParam: - return true - - default: - panic(t) // unreachable - } - - return false -} diff --git a/vendor/golang.org/x/tools/internal/typeparams/normalize.go b/vendor/golang.org/x/tools/internal/typeparams/normalize.go deleted file mode 100644 index 8d13f12147..0000000000 --- a/vendor/golang.org/x/tools/internal/typeparams/normalize.go +++ /dev/null @@ -1,216 +0,0 @@ -// Copyright 2021 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package typeparams - -import ( - "errors" - "fmt" - "go/types" - "os" - "strings" -) - -//go:generate go run copytermlist.go - -const debug = false - -var ErrEmptyTypeSet = errors.New("empty type set") - -// StructuralTerms returns a slice of terms representing the normalized -// structural type restrictions of a type parameter, if any. -// -// Structural type restrictions of a type parameter are created via -// non-interface types embedded in its constraint interface (directly, or via a -// chain of interface embeddings). For example, in the declaration -// -// type T[P interface{~int; m()}] int -// -// the structural restriction of the type parameter P is ~int. -// -// With interface embedding and unions, the specification of structural type -// restrictions may be arbitrarily complex. For example, consider the -// following: -// -// type A interface{ ~string|~[]byte } -// -// type B interface{ int|string } -// -// type C interface { ~string|~int } -// -// type T[P interface{ A|B; C }] int -// -// In this example, the structural type restriction of P is ~string|int: A|B -// expands to ~string|~[]byte|int|string, which reduces to ~string|~[]byte|int, -// which when intersected with C (~string|~int) yields ~string|int. -// -// StructuralTerms computes these expansions and reductions, producing a -// "normalized" form of the embeddings. A structural restriction is normalized -// if it is a single union containing no interface terms, and is minimal in the -// sense that removing any term changes the set of types satisfying the -// constraint. It is left as a proof for the reader that, modulo sorting, there -// is exactly one such normalized form. -// -// Because the minimal representation always takes this form, StructuralTerms -// returns a slice of tilde terms corresponding to the terms of the union in -// the normalized structural restriction. An error is returned if the -// constraint interface is invalid, exceeds complexity bounds, or has an empty -// type set. In the latter case, StructuralTerms returns ErrEmptyTypeSet. -// -// StructuralTerms makes no guarantees about the order of terms, except that it -// is deterministic. -func StructuralTerms(tparam *types.TypeParam) ([]*types.Term, error) { - constraint := tparam.Constraint() - if constraint == nil { - return nil, fmt.Errorf("%s has nil constraint", tparam) - } - iface, _ := constraint.Underlying().(*types.Interface) - if iface == nil { - return nil, fmt.Errorf("constraint is %T, not *types.Interface", constraint.Underlying()) - } - return InterfaceTermSet(iface) -} - -// InterfaceTermSet computes the normalized terms for a constraint interface, -// returning an error if the term set cannot be computed or is empty. In the -// latter case, the error will be ErrEmptyTypeSet. -// -// See the documentation of StructuralTerms for more information on -// normalization. -func InterfaceTermSet(iface *types.Interface) ([]*types.Term, error) { - return computeTermSet(iface) -} - -// UnionTermSet computes the normalized terms for a union, returning an error -// if the term set cannot be computed or is empty. In the latter case, the -// error will be ErrEmptyTypeSet. -// -// See the documentation of StructuralTerms for more information on -// normalization. -func UnionTermSet(union *types.Union) ([]*types.Term, error) { - return computeTermSet(union) -} - -func computeTermSet(typ types.Type) ([]*types.Term, error) { - tset, err := computeTermSetInternal(typ, make(map[types.Type]*termSet), 0) - if err != nil { - return nil, err - } - if tset.terms.isEmpty() { - return nil, ErrEmptyTypeSet - } - if tset.terms.isAll() { - return nil, nil - } - var terms []*types.Term - for _, term := range tset.terms { - terms = append(terms, types.NewTerm(term.tilde, term.typ)) - } - return terms, nil -} - -// A termSet holds the normalized set of terms for a given type. -// -// The name termSet is intentionally distinct from 'type set': a type set is -// all types that implement a type (and includes method restrictions), whereas -// a term set just represents the structural restrictions on a type. -type termSet struct { - complete bool - terms termlist -} - -func indentf(depth int, format string, args ...any) { - fmt.Fprintf(os.Stderr, strings.Repeat(".", depth)+format+"\n", args...) -} - -func computeTermSetInternal(t types.Type, seen map[types.Type]*termSet, depth int) (res *termSet, err error) { - if t == nil { - panic("nil type") - } - - if debug { - indentf(depth, "%s", t.String()) - defer func() { - if err != nil { - indentf(depth, "=> %s", err) - } else { - indentf(depth, "=> %s", res.terms.String()) - } - }() - } - - const maxTermCount = 100 - if tset, ok := seen[t]; ok { - if !tset.complete { - return nil, fmt.Errorf("cycle detected in the declaration of %s", t) - } - return tset, nil - } - - // Mark the current type as seen to avoid infinite recursion. - tset := new(termSet) - defer func() { - tset.complete = true - }() - seen[t] = tset - - switch u := t.Underlying().(type) { - case *types.Interface: - // The term set of an interface is the intersection of the term sets of its - // embedded types. - tset.terms = allTermlist - for embedded := range u.EmbeddedTypes() { - if _, ok := embedded.Underlying().(*types.TypeParam); ok { - return nil, fmt.Errorf("invalid embedded type %T", embedded) - } - tset2, err := computeTermSetInternal(embedded, seen, depth+1) - if err != nil { - return nil, err - } - tset.terms = tset.terms.intersect(tset2.terms) - } - case *types.Union: - // The term set of a union is the union of term sets of its terms. - tset.terms = nil - for t := range u.Terms() { - var terms termlist - switch t.Type().Underlying().(type) { - case *types.Interface: - tset2, err := computeTermSetInternal(t.Type(), seen, depth+1) - if err != nil { - return nil, err - } - terms = tset2.terms - case *types.TypeParam, *types.Union: - // A stand-alone type parameter or union is not permitted as union - // term. - return nil, fmt.Errorf("invalid union term %T", t) - default: - if t.Type() == types.Typ[types.Invalid] { - continue - } - terms = termlist{{t.Tilde(), t.Type()}} - } - tset.terms = tset.terms.union(terms) - if len(tset.terms) > maxTermCount { - return nil, fmt.Errorf("exceeded max term count %d", maxTermCount) - } - } - case *types.TypeParam: - panic("unreachable") - default: - // For all other types, the term set is just a single non-tilde term - // holding the type itself. - if u != types.Typ[types.Invalid] { - tset.terms = termlist{{false, t}} - } - } - return tset, nil -} - -// under is a facade for the go/types internal function of the same name. It is -// used by typeterm.go. -func under(t types.Type) types.Type { - return t.Underlying() -} diff --git a/vendor/golang.org/x/tools/internal/typeparams/termlist.go b/vendor/golang.org/x/tools/internal/typeparams/termlist.go deleted file mode 100644 index 9bc29143f6..0000000000 --- a/vendor/golang.org/x/tools/internal/typeparams/termlist.go +++ /dev/null @@ -1,169 +0,0 @@ -// Code generated by "go test -run=Generate -write=all"; DO NOT EDIT. -// Source: ../../cmd/compile/internal/types2/termlist.go - -// Copyright 2021 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Code generated by copytermlist.go DO NOT EDIT. - -package typeparams - -import ( - "go/types" - "strings" -) - -// A termlist represents the type set represented by the union -// t1 ∪ y2 ∪ ... tn of the type sets of the terms t1 to tn. -// A termlist is in normal form if all terms are disjoint. -// termlist operations don't require the operands to be in -// normal form. -type termlist []*term - -// allTermlist represents the set of all types. -// It is in normal form. -var allTermlist = termlist{new(term)} - -// termSep is the separator used between individual terms. -const termSep = " | " - -// String prints the termlist exactly (without normalization). -func (xl termlist) String() string { - if len(xl) == 0 { - return "∅" - } - var buf strings.Builder - for i, x := range xl { - if i > 0 { - buf.WriteString(termSep) - } - buf.WriteString(x.String()) - } - return buf.String() -} - -// isEmpty reports whether the termlist xl represents the empty set of types. -func (xl termlist) isEmpty() bool { - // If there's a non-nil term, the entire list is not empty. - // If the termlist is in normal form, this requires at most - // one iteration. - for _, x := range xl { - if x != nil { - return false - } - } - return true -} - -// isAll reports whether the termlist xl represents the set of all types. -func (xl termlist) isAll() bool { - // If there's a 𝓤 term, the entire list is 𝓤. - // If the termlist is in normal form, this requires at most - // one iteration. - for _, x := range xl { - if x != nil && x.typ == nil { - return true - } - } - return false -} - -// norm returns the normal form of xl. -func (xl termlist) norm() termlist { - // Quadratic algorithm, but good enough for now. - // TODO(gri) fix asymptotic performance - used := make([]bool, len(xl)) - var rl termlist - for i, xi := range xl { - if xi == nil || used[i] { - continue - } - for j := i + 1; j < len(xl); j++ { - xj := xl[j] - if xj == nil || used[j] { - continue - } - if u1, u2 := xi.union(xj); u2 == nil { - // If we encounter a 𝓤 term, the entire list is 𝓤. - // Exit early. - // (Note that this is not just an optimization; - // if we continue, we may end up with a 𝓤 term - // and other terms and the result would not be - // in normal form.) - if u1.typ == nil { - return allTermlist - } - xi = u1 - used[j] = true // xj is now unioned into xi - ignore it in future iterations - } - } - rl = append(rl, xi) - } - return rl -} - -// union returns the union xl ∪ yl. -func (xl termlist) union(yl termlist) termlist { - return append(xl, yl...).norm() -} - -// intersect returns the intersection xl ∩ yl. -func (xl termlist) intersect(yl termlist) termlist { - if xl.isEmpty() || yl.isEmpty() { - return nil - } - - // Quadratic algorithm, but good enough for now. - // TODO(gri) fix asymptotic performance - var rl termlist - for _, x := range xl { - for _, y := range yl { - if r := x.intersect(y); r != nil { - rl = append(rl, r) - } - } - } - return rl.norm() -} - -// equal reports whether xl and yl represent the same type set. -func (xl termlist) equal(yl termlist) bool { - // TODO(gri) this should be more efficient - return xl.subsetOf(yl) && yl.subsetOf(xl) -} - -// includes reports whether t ∈ xl. -func (xl termlist) includes(t types.Type) bool { - for _, x := range xl { - if x.includes(t) { - return true - } - } - return false -} - -// supersetOf reports whether y ⊆ xl. -func (xl termlist) supersetOf(y *term) bool { - for _, x := range xl { - if y.subsetOf(x) { - return true - } - } - return false -} - -// subsetOf reports whether xl ⊆ yl. -func (xl termlist) subsetOf(yl termlist) bool { - if yl.isEmpty() { - return xl.isEmpty() - } - - // each term x of xl must be a subset of yl - for _, x := range xl { - if !yl.supersetOf(x) { - return false // x is not a subset yl - } - } - return true -} diff --git a/vendor/golang.org/x/tools/internal/typeparams/typeterm.go b/vendor/golang.org/x/tools/internal/typeparams/typeterm.go deleted file mode 100644 index fa758cdc98..0000000000 --- a/vendor/golang.org/x/tools/internal/typeparams/typeterm.go +++ /dev/null @@ -1,172 +0,0 @@ -// Code generated by "go test -run=Generate -write=all"; DO NOT EDIT. -// Source: ../../cmd/compile/internal/types2/typeterm.go - -// Copyright 2021 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Code generated by copytermlist.go DO NOT EDIT. - -package typeparams - -import "go/types" - -// A term describes elementary type sets: -// -// ∅: (*term)(nil) == ∅ // set of no types (empty set) -// 𝓤: &term{} == 𝓤 // set of all types (𝓤niverse) -// T: &term{false, T} == {T} // set of type T -// ~t: &term{true, t} == {t' | under(t') == t} // set of types with underlying type t -type term struct { - tilde bool // valid if typ != nil - typ types.Type -} - -func (x *term) String() string { - switch { - case x == nil: - return "∅" - case x.typ == nil: - return "𝓤" - case x.tilde: - return "~" + x.typ.String() - default: - return x.typ.String() - } -} - -// equal reports whether x and y represent the same type set. -func (x *term) equal(y *term) bool { - // easy cases - switch { - case x == nil || y == nil: - return x == y - case x.typ == nil || y.typ == nil: - return x.typ == y.typ - } - // ∅ ⊂ x, y ⊂ 𝓤 - - return x.tilde == y.tilde && types.Identical(x.typ, y.typ) -} - -// union returns the union x ∪ y: zero, one, or two non-nil terms. -func (x *term) union(y *term) (_, _ *term) { - // easy cases - switch { - case x == nil && y == nil: - return nil, nil // ∅ ∪ ∅ == ∅ - case x == nil: - return y, nil // ∅ ∪ y == y - case y == nil: - return x, nil // x ∪ ∅ == x - case x.typ == nil: - return x, nil // 𝓤 ∪ y == 𝓤 - case y.typ == nil: - return y, nil // x ∪ 𝓤 == 𝓤 - } - // ∅ ⊂ x, y ⊂ 𝓤 - - if x.disjoint(y) { - return x, y // x ∪ y == (x, y) if x ∩ y == ∅ - } - // x.typ == y.typ - - // ~t ∪ ~t == ~t - // ~t ∪ T == ~t - // T ∪ ~t == ~t - // T ∪ T == T - if x.tilde || !y.tilde { - return x, nil - } - return y, nil -} - -// intersect returns the intersection x ∩ y. -func (x *term) intersect(y *term) *term { - // easy cases - switch { - case x == nil || y == nil: - return nil // ∅ ∩ y == ∅ and ∩ ∅ == ∅ - case x.typ == nil: - return y // 𝓤 ∩ y == y - case y.typ == nil: - return x // x ∩ 𝓤 == x - } - // ∅ ⊂ x, y ⊂ 𝓤 - - if x.disjoint(y) { - return nil // x ∩ y == ∅ if x ∩ y == ∅ - } - // x.typ == y.typ - - // ~t ∩ ~t == ~t - // ~t ∩ T == T - // T ∩ ~t == T - // T ∩ T == T - if !x.tilde || y.tilde { - return x - } - return y -} - -// includes reports whether t ∈ x. -func (x *term) includes(t types.Type) bool { - // easy cases - switch { - case x == nil: - return false // t ∈ ∅ == false - case x.typ == nil: - return true // t ∈ 𝓤 == true - } - // ∅ ⊂ x ⊂ 𝓤 - - u := t - if x.tilde { - u = under(u) - } - return types.Identical(x.typ, u) -} - -// subsetOf reports whether x ⊆ y. -func (x *term) subsetOf(y *term) bool { - // easy cases - switch { - case x == nil: - return true // ∅ ⊆ y == true - case y == nil: - return false // x ⊆ ∅ == false since x != ∅ - case y.typ == nil: - return true // x ⊆ 𝓤 == true - case x.typ == nil: - return false // 𝓤 ⊆ y == false since y != 𝓤 - } - // ∅ ⊂ x, y ⊂ 𝓤 - - if x.disjoint(y) { - return false // x ⊆ y == false if x ∩ y == ∅ - } - // x.typ == y.typ - - // ~t ⊆ ~t == true - // ~t ⊆ T == false - // T ⊆ ~t == true - // T ⊆ T == true - return !x.tilde || y.tilde -} - -// disjoint reports whether x ∩ y == ∅. -// x.typ and y.typ must not be nil. -func (x *term) disjoint(y *term) bool { - if debug && (x.typ == nil || y.typ == nil) { - panic("invalid argument(s)") - } - ux := x.typ - if y.tilde { - ux = under(ux) - } - uy := y.typ - if x.tilde { - uy = under(uy) - } - return !types.Identical(ux, uy) -} diff --git a/vendor/golang.org/x/tools/internal/typesinternal/assignedaddress.go b/vendor/golang.org/x/tools/internal/typesinternal/assignedaddress.go new file mode 100644 index 0000000000..020defc383 --- /dev/null +++ b/vendor/golang.org/x/tools/internal/typesinternal/assignedaddress.go @@ -0,0 +1,128 @@ +// Copyright 2026 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package typesinternal + +import ( + "go/ast" + "go/token" + "go/types" + + "golang.org/x/tools/go/ast/edge" + "golang.org/x/tools/go/ast/inspector" +) + +// IsAssignedOrAddressTaken reports whether the expression cur denotes a +// variable and appears in a context that assigns it or that takes its address, +// potentially leading to indirect assignment. +// +// These examples cause IsAssignedOrAddressTaken on the identifier for x to +// return true: +// +// x = 1 +// x++ +// x[i] = 1 (assume x is an array) +// x.a[i] = 1 (assume x.a is a non-pointer struct field) +// use(&x) +// +// whereas these cause it to return false: +// +// y = x +// f(x) +// use(x.a[i]) +// use(*x) +// +// The expression may itself be a compound, for example: +// +// use(&(*ptr)) => IsAssignedOrAddressTaken("*ptr") = true +// x.a[i] = 1 => IsAssignedOrAddressTaken("x.a") = true +// _ = x.a[i] => IsAssignedOrAddressTaken("x.a") = false +// +// A variable's declaration is not considered to be an assignment: +// +// var x int => IsAssignedOrAddressTaken(x) = false +// x := 1 => IsAssignedOrAddressTaken(x) = false +// +// TODO(adonovan): revisit the surprising behavior for declarations. +func IsAssignedOrAddressTaken(info *types.Info, cur inspector.Cursor) bool { + // Unfortunately we can't simply use info.Types[e].Assignable() + // as it is always true for a variable even when that variable is + // used only as an r-value. So we must inspect enclosing syntax. +outer: + // Ascend to outermost aggregate of which + // original cur is a part: + // x -> (x) | x.f | x[i] | x[i:j] + for cur = range cur.Enclosing() { + switch cur.ParentEdgeKind() { + case edge.ParenExpr_X: + // If x is an lvalue, then (x) is an lvalue. + case edge.SelectorExpr_X: + // If x is an lvalue, then x.f is an lvalue iff + // the selection does not traverse a pointer. + sel := cur.Parent().Node().(*ast.SelectorExpr) + if seln, ok := info.Selections[sel]; ok { + // Note: there is a bug in Indirect() where it spuriously returns true + // when both the selection receiver and parameter are pointers. However, + // it's okay in this case because there is no address taken when a + // pointer receiver method is called on a pointer type. + if seln.Indirect() { + return false + } + if seln.Kind() == types.MethodVal { + sig := seln.Obj().Type().(*types.Signature) + if is[*types.Pointer](sig.Recv().Type().Underlying()) { + t := seln.Recv() + // The receiver may be an embedded field, so we need + // to get the inner-most type (right before the method + // call in seln.Index()) + for _, idx := range seln.Index()[:len(seln.Index())-1] { + t = t.Underlying().(*types.Struct).Field(idx).Type() + } + if !is[*types.Pointer](t.Underlying()) { + return true // takes address of receiver + } + } + return false + } + } + case edge.IndexExpr_X, edge.SliceExpr_X: + // If x[i] or x[i:j] is an lvalue, + // then x is an lvalue iff x is an array. + if !is[*types.Array](info.TypeOf(cur.Node().(ast.Expr)).Underlying()) { + return false + } + default: + break outer + } + } + switch cur.ParentEdgeKind() { + case edge.AssignStmt_Lhs: + assign := cur.Parent().Node().(*ast.AssignStmt) + if assign.Tok != token.DEFINE { + return true // x = j or x += j + } + id := cur.Node().(*ast.Ident) + // Re-assigned identifiers are recorded in the Uses map. + if _, ok := info.Uses[id]; ok { + return true // reassignment of x (x, y := 1, 2) + } + case edge.RangeStmt_Key, edge.RangeStmt_Value: + rng := cur.Parent().Node().(*ast.RangeStmt) + if rng.Tok == token.ASSIGN { + return true // "for k, v = range x" is like an AssignStmt to k, v + } + case edge.IncDecStmt_X: + return true // x++, x-- + case edge.UnaryExpr_X: + if cur.Parent().Node().(*ast.UnaryExpr).Op == token.AND { + return true // &x + } + } + return false +} + +func is[T any](x any) bool { + _, ok := x.(T) + return ok +} diff --git a/vendor/golang.org/x/tools/internal/typesinternal/classify_call.go b/vendor/golang.org/x/tools/internal/typesinternal/classify_call.go index 7ebe9768bc..d5c40a2e50 100644 --- a/vendor/golang.org/x/tools/internal/typesinternal/classify_call.go +++ b/vendor/golang.org/x/tools/internal/typesinternal/classify_call.go @@ -8,7 +8,6 @@ import ( "fmt" "go/ast" "go/types" - _ "unsafe" // for go:linkname hack ) // CallKind describes the function position of an [*ast.CallExpr]. @@ -72,11 +71,15 @@ func ClassifyCall(info *types.Info, call *ast.CallExpr) CallKind { if tv.IsBuiltin() { return CallBuiltin } - obj := info.Uses[UsedIdent(info, call.Fun)] + id := UsedIdent(info, call.Fun) + if id == nil { + return CallDynamic + } + obj := info.Uses[id] // Classify the call by the type of the object, if any. switch obj := obj.(type) { case *types.Func: - if interfaceMethod(obj) { + if isInterfaceMethod(obj) { return CallInterface } return CallStatic @@ -127,11 +130,69 @@ func ClassifyCall(info *types.Info, call *ast.CallExpr) CallKind { // Note: if e is an instantiated function or method, UsedIdent returns // the corresponding generic function or method on the generic type. func UsedIdent(info *types.Info, e ast.Expr) *ast.Ident { - return usedIdent(info, e) + if info.Types == nil || info.Uses == nil { + panic("one of info.Types or info.Uses is nil; both must be populated") + } + // Look through type instantiation if necessary. + switch d := ast.Unparen(e).(type) { + case *ast.IndexExpr: + if info.Types[d.Index].IsType() { + e = d.X + } + case *ast.IndexListExpr: + e = d.X + } + + switch e := ast.Unparen(e).(type) { + // info.Uses always has the object we want, even for selector expressions. + // We don't need info.Selections. + // See go/types/recording.go:recordSelection. + case *ast.Ident: + return e + case *ast.SelectorExpr: + return e.Sel + } + return nil +} + +// See [golang.org/x/tools/go/types/typeutil.Callee]. +func Callee(info *types.Info, call *ast.CallExpr) types.Object { + id := UsedIdent(info, call.Fun) + if id == nil { + return nil + } + obj := info.Uses[id] + if obj == nil { + return nil + } + if _, ok := obj.(*types.TypeName); ok { + return nil + } + if fn, ok := obj.(*types.Func); ok { + return fn.Origin() + } + return obj } -//go:linkname usedIdent golang.org/x/tools/go/types/typeutil.usedIdent -func usedIdent(info *types.Info, e ast.Expr) *ast.Ident +// See [golang.org/x/tools/go/types/typeutil.StaticCallee]. +func StaticCallee(info *types.Info, call *ast.CallExpr) *types.Func { + id := UsedIdent(info, call.Fun) + if id == nil { + return nil + } + obj := info.Uses[id] + if obj == nil { + return nil + } + fn, _ := obj.(*types.Func) + if fn == nil || isInterfaceMethod(fn) { + return nil + } + return fn.Origin() +} -//go:linkname interfaceMethod golang.org/x/tools/go/types/typeutil.interfaceMethod -func interfaceMethod(f *types.Func) bool +// isInterfaceMethod reports whether its argument is a method of an interface. +func isInterfaceMethod(f *types.Func) bool { + recv := f.Signature().Recv() + return recv != nil && types.IsInterface(recv.Type()) +} diff --git a/vendor/golang.org/x/tools/internal/typesinternal/element.go b/vendor/golang.org/x/tools/internal/typesinternal/element.go index 89eeea1653..bab37fbfe0 100644 --- a/vendor/golang.org/x/tools/internal/typesinternal/element.go +++ b/vendor/golang.org/x/tools/internal/typesinternal/element.go @@ -7,8 +7,6 @@ package typesinternal import ( "fmt" "go/types" - - "golang.org/x/tools/go/types/typeutil" ) // ForEachElement calls f for type T and each type reachable from its @@ -16,25 +14,24 @@ import ( // type constructors; in addition, for each named type N, the type *N // is added to the result as it may have additional methods. // -// The caller must provide an initially empty set used to de-duplicate -// identical types, potentially across multiple calls to ForEachElement. -// (Its final value holds all the elements seen, matching the arguments -// passed to f.) +// The access argument passed to f indicates whether the type is +// inaccessible to reflection (for example, intermediate tuple types +// or underlying types of named types). // -// TODO(adonovan): share/harmonize with go/callgraph/rta. -func ForEachElement(rtypes *typeutil.Map, msets *typeutil.MethodSetCache, T types.Type, f func(types.Type)) { - var visit func(T types.Type, skip bool) - visit = func(T types.Type, skip bool) { - if !skip { - if seen, _ := rtypes.Set(T, true).(bool); seen { - return // de-dup - } - - f(T) // notify caller of new element type +// The result of f indicates whether the caller has seen this type +// already, so we can prune the traversal. +// +// methodSetOf abstracts (*typeutil.MethodSetCache).MethodSet, +// avoiding an import cycle. +func ForEachElement(methodSetOf func(types.Type) *types.MethodSet, T types.Type, f func(T types.Type, access bool) bool) { + var visit func(T types.Type, access bool) + visit = func(T types.Type, access bool) { + if f(T, access) { + return // duplicate; prune descent } // Recursion over signatures of each method. - tmset := msets.MethodSet(T) + tmset := methodSetOf(T) for method := range tmset.Methods() { sig := method.Type().(*types.Signature) if sig.TypeParams() != nil { @@ -65,13 +62,13 @@ func ForEachElement(rtypes *typeutil.Map, msets *typeutil.MethodSetCache, T type // // TODO(adonovan): document whether or not it is // safe to skip non-exported methods (as RTA does). - visit(sig.Params(), true) // skip the Tuple - visit(sig.Results(), true) // skip the Tuple + visit(sig.Params(), false) // the Tuple is inaccessible + visit(sig.Results(), false) // the Tuple is inaccessible } switch T := T.(type) { case *types.Alias: - visit(types.Unalias(T), skip) // emulates the pre-Alias behavior + visit(types.Unalias(T), access) // emulates the pre-Alias behavior case *types.Basic: // nop @@ -80,49 +77,49 @@ func ForEachElement(rtypes *typeutil.Map, msets *typeutil.MethodSetCache, T type // nop---handled by recursion over method set. case *types.Pointer: - visit(T.Elem(), false) + visit(T.Elem(), true) case *types.Slice: - visit(T.Elem(), false) + visit(T.Elem(), true) case *types.Chan: - visit(T.Elem(), false) + visit(T.Elem(), true) case *types.Map: - visit(T.Key(), false) - visit(T.Elem(), false) + visit(T.Key(), true) + visit(T.Elem(), true) case *types.Signature: if T.Recv() != nil { panic(fmt.Sprintf("Signature %s has Recv %s", T, T.Recv())) } - visit(T.Params(), true) // skip the Tuple - visit(T.Results(), true) // skip the Tuple + visit(T.Params(), false) // the Tuple is inaccessible + visit(T.Results(), false) // the Tuple is inaccessible case *types.Named: // A pointer-to-named type can be derived from a named // type via reflection. It may have methods too. - visit(types.NewPointer(T), false) + visit(types.NewPointer(T), true) // Consider 'type T struct{S}' where S has methods. // Reflection provides no way to get from T to struct{S}, // only to S, so the method set of struct{S} is unwanted, - // so set 'skip' flag during recursion. - visit(T.Underlying(), true) // skip the unnamed type + // so mark it inaccessible during recursion. + visit(T.Underlying(), false) // skip the unnamed type case *types.Array: - visit(T.Elem(), false) + visit(T.Elem(), true) case *types.Struct: for i, n := 0, T.NumFields(); i < n; i++ { // TODO(adonovan): document whether or not // it is safe to skip non-exported fields. - visit(T.Field(i).Type(), false) + visit(T.Field(i).Type(), true) } case *types.Tuple: for i, n := 0, T.Len(); i < n; i++ { - visit(T.At(i).Type(), false) + visit(T.At(i).Type(), true) } case *types.TypeParam, *types.Union: @@ -133,5 +130,5 @@ func ForEachElement(rtypes *typeutil.Map, msets *typeutil.MethodSetCache, T type panic(fmt.Sprintf("ForEachElement called on unexpected type %T", T)) } } - visit(T, false) + visit(T, true) } diff --git a/vendor/golang.org/x/tools/internal/typesinternal/toonew.go b/vendor/golang.org/x/tools/internal/typesinternal/toonew.go index cc86487eaa..386c59c740 100644 --- a/vendor/golang.org/x/tools/internal/typesinternal/toonew.go +++ b/vendor/golang.org/x/tools/internal/typesinternal/toonew.go @@ -13,20 +13,30 @@ import ( // TooNewStdSymbols computes the set of package-level symbols // exported by pkg that are not available at the specified version. -// The result maps each symbol to its minimum version. // // The pkg is allowed to contain type errors. -func TooNewStdSymbols(pkg *types.Package, version string) map[types.Object]string { - disallowed := make(map[types.Object]string) +func TooNewStdSymbols(pkg *types.Package, version string) map[types.Object]stdlib.Symbol { + disallowed := make(map[types.Object]stdlib.Symbol) + + // Some symbols are accessible before their release but + // only with specific build tags unknown to us here. + // Avoid false positives in such cases. + if pkg.Path() == "testing/synctest" && versions.AtLeast(version, "go1.24") { + // requires go1.24 && goexperiment.synctest || go1.25 + return disallowed + } + if (pkg.Path() == "encoding/json/v2" || pkg.Path() == "encoding/json/jsontext") && versions.AtLeast(version, "go1.25") { + // requires go1.25 && goexperiment.jsonv2 || go1.27 + return disallowed + } // Pass 1: package-level symbols. symbols := stdlib.PackageSymbols[pkg.Path()] for _, sym := range symbols { - symver := sym.Version.String() - if versions.Before(version, symver) { + if versions.Before(version, sym.Version.String()) { switch sym.Kind { case stdlib.Func, stdlib.Var, stdlib.Const, stdlib.Type: - disallowed[pkg.Scope().Lookup(sym.Name)] = symver + disallowed[pkg.Scope().Lookup(sym.Name)] = sym } } } @@ -60,28 +70,36 @@ func TooNewStdSymbols(pkg *types.Package, version string) map[types.Object]strin // spuriously cause the analyzer to report a reference to a // too-new symbol even though this expression compiles just // fine (with the fake implementation) using go1.21. + var noSym stdlib.Symbol + depth := make(map[types.Object]int) for _, sym := range symbols { - symVersion := sym.Version.String() - if !versions.Before(version, symVersion) { + if !versions.Before(version, sym.Version.String()) { continue // allowed } var obj types.Object + var indices []int switch sym.Kind { case stdlib.Field: typename, name := sym.SplitField() - if t := pkg.Scope().Lookup(typename); t != nil && disallowed[t] == "" { - obj, _, _ = types.LookupFieldOrMethod(t.Type(), false, pkg, name) + if t := pkg.Scope().Lookup(typename); t != nil && disallowed[t] == noSym { + obj, indices, _ = types.LookupFieldOrMethod(t.Type(), false, pkg, name) } case stdlib.Method: ptr, recvname, name := sym.SplitMethod() - if t := pkg.Scope().Lookup(recvname); t != nil && disallowed[t] == "" { - obj, _, _ = types.LookupFieldOrMethod(t.Type(), ptr, pkg, name) + if t := pkg.Scope().Lookup(recvname); t != nil && disallowed[t] == noSym { + obj, indices, _ = types.LookupFieldOrMethod(t.Type(), ptr, pkg, name) } } if obj != nil { - disallowed[obj] = symVersion + // In the presence of embedding, two or more "pkg.T.name" + // strings may map to the same types.Object. + // Prefer the Object with the shorter index path. + if min, ok := depth[obj]; !ok || len(indices) < min { + depth[obj] = len(indices) + disallowed[obj] = sym + } } } diff --git a/vendor/golang.org/x/tools/internal/typesinternal/types.go b/vendor/golang.org/x/tools/internal/typesinternal/types.go index d2c0b4c5ff..9fd48b088f 100644 --- a/vendor/golang.org/x/tools/internal/typesinternal/types.go +++ b/vendor/golang.org/x/tools/internal/typesinternal/types.go @@ -270,3 +270,11 @@ func ImplicitFieldSelections(seln types.Selection) iter.Seq2[*types.Var, bool] { } } } + +func TupleOf(elems ...types.Type) *types.Tuple { + params := make([]*types.Var, len(elems)) + for i, elem := range elems { + params[i] = types.NewParam(token.NoPos, nil, "", elem) + } + return types.NewTuple(params...) +} diff --git a/vendor/google.golang.org/grpc/clientconn.go b/vendor/google.golang.org/grpc/clientconn.go index c4bca5203e..b27c7e84a3 100644 --- a/vendor/google.golang.org/grpc/clientconn.go +++ b/vendor/google.golang.org/grpc/clientconn.go @@ -24,12 +24,10 @@ import ( "fmt" "math" "net/url" - "os" "slices" "strings" "sync" "sync/atomic" - "syscall" "time" "google.golang.org/grpc/balancer" @@ -1573,26 +1571,13 @@ func (ac *addrConn) createTransport(ctx context.Context, addr resolver.Address, // to the provided transport.GoAwayInfo, as specified by gRFC A94: // https://github.com/grpc/proposal/blob/master/A94-grpc-subchannel-disconnections-metrics.md func disconnectErrorString(info transport.GoAwayInfo) string { - err := info.Err - var sysErr syscall.Errno - switch { - case info.Reason != transport.GoAwayInvalid: + if info.Reason != transport.GoAwayInvalid { return fmt.Sprintf("GOAWAY %s", info.GoAwayCode.String()) - case err == nil: - return "unknown" - case errors.Is(err, context.Canceled): - return "subchannel shutdown" - case errors.Is(err, syscall.ECONNRESET): - return "connection reset" - case errors.Is(err, syscall.ETIMEDOUT), errors.Is(err, context.DeadlineExceeded), errors.Is(err, os.ErrDeadlineExceeded): - return "connection timed out" - case errors.Is(err, syscall.ECONNABORTED): - return "connection aborted" - case errors.As(err, &sysErr): - return "socket error" - default: + } + if info.Err == nil { return "unknown" } + return disconnectErrorLabel(info.Err) } // startHealthCheck starts the health checking stream (RPC) to watch the health diff --git a/vendor/google.golang.org/grpc/clientconn_disconnect_reason_noplan9.go b/vendor/google.golang.org/grpc/clientconn_disconnect_reason_noplan9.go new file mode 100644 index 0000000000..f0fcd88423 --- /dev/null +++ b/vendor/google.golang.org/grpc/clientconn_disconnect_reason_noplan9.go @@ -0,0 +1,48 @@ +//go:build !plan9 + +/* + * + * Copyright 2026 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package grpc + +import ( + "context" + "errors" + "os" + "syscall" +) + +// disconnectErrorLabel returns the grpc.disconnect_error metric label for a +// transport error, as specified by gRFC A94. +func disconnectErrorLabel(err error) string { + var sysErr syscall.Errno + switch { + case errors.Is(err, context.Canceled): + return "subchannel shutdown" + case errors.Is(err, syscall.ECONNRESET): + return "connection reset" + case errors.Is(err, syscall.ETIMEDOUT), errors.Is(err, context.DeadlineExceeded), errors.Is(err, os.ErrDeadlineExceeded): + return "connection timed out" + case errors.Is(err, syscall.ECONNABORTED): + return "connection aborted" + case errors.As(err, &sysErr): + return "socket error" + default: + return "unknown" + } +} diff --git a/vendor/google.golang.org/grpc/clientconn_disconnect_reason_plan9.go b/vendor/google.golang.org/grpc/clientconn_disconnect_reason_plan9.go new file mode 100644 index 0000000000..930b12664c --- /dev/null +++ b/vendor/google.golang.org/grpc/clientconn_disconnect_reason_plan9.go @@ -0,0 +1,39 @@ +/* + * + * Copyright 2026 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package grpc + +import ( + "context" + "errors" + "os" +) + +// disconnectErrorLabel returns the grpc.disconnect_error metric label for a +// transport error, as specified by gRFC A94. syscall.Errno does not exist on +// plan9, so only the portable classifications are available. +func disconnectErrorLabel(err error) string { + switch { + case errors.Is(err, context.Canceled): + return "subchannel shutdown" + case errors.Is(err, context.DeadlineExceeded), errors.Is(err, os.ErrDeadlineExceeded): + return "connection timed out" + default: + return "unknown" + } +} diff --git a/vendor/google.golang.org/grpc/internal/envconfig/envconfig.go b/vendor/google.golang.org/grpc/internal/envconfig/envconfig.go index 29d332e7b6..3334481274 100644 --- a/vendor/google.golang.org/grpc/internal/envconfig/envconfig.go +++ b/vendor/google.golang.org/grpc/internal/envconfig/envconfig.go @@ -150,8 +150,18 @@ var ( // throttling limit if unforeseen issues arise, and it will be removed in a // future release. // - // TODO: Remove this env var once v1.83.0 is release. + // TODO: Remove this env var once v1.83.0 is released. ControlBufferThrottleLimit = uint64FromEnv("GRPC_GO_EXPERIMENTAL_CONTROL_BUFFER_THROTTLE_LIMIT", 100, 1, 10000) + + // EnableReceiveBufferCompaction enables the compaction of data buffers + // to reduce the number of buffers in the receive buffer. + // + // This environment variable serves as an escape hatch to disable the + // feature if unforeseen issues arise, and it will be removed in a future + // release. + // + // TODO: Remove this env var once v1.85.0 is released. + EnableReceiveBufferCompaction = boolFromEnv("GRPC_GO_EXPERIMENTAL_ENABLE_RECEIVE_BUFFER_COMPACTION", true) ) func boolFromEnv(envVar string, def bool) bool { diff --git a/vendor/google.golang.org/grpc/internal/envconfig/xds.go b/vendor/google.golang.org/grpc/internal/envconfig/xds.go index a2312f8eac..e4b6919138 100644 --- a/vendor/google.golang.org/grpc/internal/envconfig/xds.go +++ b/vendor/google.golang.org/grpc/internal/envconfig/xds.go @@ -69,9 +69,8 @@ var ( // https://github.com/grpc/proposal/blob/master/A87-mtls-spiffe-support.md XDSSPIFFEEnabled = boolFromEnv("GRPC_EXPERIMENTAL_XDS_MTLS_SPIFFE", false) - // XDSHTTPConnectEnabled is true if gRPC should parse custom Metadata - // configuring use of an HTTP CONNECT proxy via xDS from cluster resources. - // For more details, see: + // XDSHTTPConnectEnabled controls support for dynamic HTTP CONNECT proxying + // configured via the xDS control plane. For more details, see: // https://github.com/grpc/proposal/blob/master/A86-xds-http-connect.md XDSHTTPConnectEnabled = boolFromEnv("GRPC_EXPERIMENTAL_XDS_HTTP_CONNECT", false) @@ -88,7 +87,7 @@ var ( // XDSORCAToLRSPropEnabled controls whether ORCA metrics are explicitly // filtered and prefix-propagated to the LRS server. For more details, see: // https://github.com/grpc/proposal/blob/master/A85-lrs-custom-metrics-changes.md - XDSORCAToLRSPropEnabled = boolFromEnv("GRPC_EXPERIMENTAL_XDS_ORCA_LRS_PROPAGATION", false) + XDSORCAToLRSPropEnabled = boolFromEnv("GRPC_EXPERIMENTAL_XDS_ORCA_LRS_PROPAGATION", true) // XDSClientExtProcEnabled indicates whether ExtProc filter is enabled on // the client side. For more details, see: diff --git a/vendor/google.golang.org/grpc/internal/grpcsync/callback_serializer.go b/vendor/google.golang.org/grpc/internal/grpcsync/callback_serializer.go index 9b6d8a1fa3..d4999fcca8 100644 --- a/vendor/google.golang.org/grpc/internal/grpcsync/callback_serializer.go +++ b/vendor/google.golang.org/grpc/internal/grpcsync/callback_serializer.go @@ -20,10 +20,15 @@ package grpcsync import ( "context" + "errors" "google.golang.org/grpc/internal/buffer" ) +// ErrSerializerClosed is returned by ScheduleAndWait if the CallbackSerializer +// was closed before the callback could be scheduled. +var ErrSerializerClosed = errors.New("callback serializer is closed") + // CallbackSerializer provides a mechanism to schedule callbacks in a // synchronized manner. It provides a FIFO guarantee on the order of execution // of scheduled callbacks. New callbacks can be scheduled by invoking the @@ -77,6 +82,27 @@ func (cs *CallbackSerializer) ScheduleOr(f func(ctx context.Context), onFailure } } +// ScheduleAndWait schedules the provided callback function f to be executed in +// the order it was added and blocks until f has run. If the context passed to +// NewCallbackSerializer was canceled before this method is called, f is not run +// and ScheduleAndWait returns ErrSerializerClosed. +// +// Callbacks are expected to honor the context when performing any blocking +// operations, and should return early when the context is canceled. +func (cs *CallbackSerializer) ScheduleAndWait(f func(ctx context.Context)) error { + done := make(chan struct{}) + var err error + cs.ScheduleOr(func(ctx context.Context) { + f(ctx) + close(done) + }, func() { + err = ErrSerializerClosed + close(done) + }) + <-done + return err +} + func (cs *CallbackSerializer) run(ctx context.Context) { defer close(cs.done) diff --git a/vendor/google.golang.org/grpc/internal/mem/buffer_pool.go b/vendor/google.golang.org/grpc/internal/mem/buffer_pool.go index 2d83b2eced..00aeca419f 100644 --- a/vendor/google.golang.org/grpc/internal/mem/buffer_pool.go +++ b/vendor/google.golang.org/grpc/internal/mem/buffer_pool.go @@ -26,12 +26,26 @@ import ( "slices" "sort" "sync" + + "google.golang.org/grpc/internal" ) const ( goPageSize = 4 * 1024 // 4KiB. N.B. this must be a power of 2. ) +var ( + // BufferPoolingThreshold is the minimum size of a buffer that can be pooled. + // This is used to determine whether to pool buffers or allocate them directly. + BufferPoolingThreshold = 1 << 10 +) + +func init() { + internal.SetBufferPoolingThresholdForTesting = func(threshold int) { + BufferPoolingThreshold = threshold + } +} + var uintSize = bits.UintSize // use a variable for mocking during tests. // bufferPool is a copy of the public bufferPool interface used to avoid diff --git a/vendor/google.golang.org/grpc/internal/resolver/config_selector.go b/vendor/google.golang.org/grpc/internal/resolver/config_selector.go index 6320e9b576..238950bbbf 100644 --- a/vendor/google.golang.org/grpc/internal/resolver/config_selector.go +++ b/vendor/google.golang.org/grpc/internal/resolver/config_selector.go @@ -24,7 +24,6 @@ import ( "sync" "google.golang.org/grpc/internal/serviceconfig" - "google.golang.org/grpc/metadata" "google.golang.org/grpc/resolver" ) @@ -52,82 +51,7 @@ type RPCConfig struct { Context context.Context MethodConfig serviceconfig.MethodConfig // configuration to use for this RPC OnCommitted func() // Called when the RPC has been committed (retries no longer possible) - Interceptor ClientInterceptor -} - -// ClientStream is the same as grpc.ClientStream, but defined here for circular -// dependency reasons. -type ClientStream interface { - // Header returns the header metadata received from the server if there - // is any. It blocks if the metadata is not ready to read. - Header() (metadata.MD, error) - // Trailer returns the trailer metadata from the server, if there is any. - // It must only be called after stream.CloseAndRecv has returned, or - // stream.Recv has returned a non-nil error (including io.EOF). - Trailer() metadata.MD - // CloseSend closes the send direction of the stream. It closes the stream - // when non-nil error is met. It is also not safe to call CloseSend - // concurrently with SendMsg. - CloseSend() error - // Context returns the context for this stream. - // - // It should not be called until after Header or RecvMsg has returned. Once - // called, subsequent client-side retries are disabled. - Context() context.Context - // SendMsg is generally called by generated code. On error, SendMsg aborts - // the stream. If the error was generated by the client, the status is - // returned directly; otherwise, io.EOF is returned and the status of - // the stream may be discovered using RecvMsg. - // - // SendMsg blocks until: - // - There is sufficient flow control to schedule m with the transport, or - // - The stream is done, or - // - The stream breaks. - // - // SendMsg does not wait until the message is received by the server. An - // untimely stream closure may result in lost messages. To ensure delivery, - // users should ensure the RPC completed successfully using RecvMsg. - // - // It is safe to have a goroutine calling SendMsg and another goroutine - // calling RecvMsg on the same stream at the same time, but it is not safe - // to call SendMsg on the same stream in different goroutines. It is also - // not safe to call CloseSend concurrently with SendMsg. - SendMsg(m any) error - // RecvMsg blocks until it receives a message into m or the stream is - // done. It returns io.EOF when the stream completes successfully. On - // any other error, the stream is aborted and the error contains the RPC - // status. - // - // It is safe to have a goroutine calling SendMsg and another goroutine - // calling RecvMsg on the same stream at the same time, but it is not - // safe to call RecvMsg on the same stream in different goroutines. - RecvMsg(m any) error -} - -// ClientInterceptor is an interceptor for gRPC client streams. -type ClientInterceptor interface { - // NewStream creates a ClientStream for an RPC. - // - // Implementations must delegate stream creation to the provided newStream - // function. To intercept or override stream behavior, implementations - // may wrap the ClientStream returned by the delegate. - // - // Note: RPCInfo.Context is currently unused and will be nil. - // - // The done function is invoked when the RPC has finished using its - // underlying connection or if a connection could not be assigned. Because - // interceptors operate at the application layer, RPC operations may - // continue on the ClientStream even after done has been called. The - // caller must ensure done is non-nil. - // - // To ensure RPC completion notifications propagate through the entire - // interceptor chain, implementations must ensure that the done function - // passed to the delegate newStream invokes the done function passed to - // NewStream. - NewStream(ctx context.Context, ri RPCInfo, done func(), newStream func(ctx context.Context, done func()) (ClientStream, error)) (ClientStream, error) - // Close closes the interceptor. Once called, no new calls to NewStream are - // accepted. Ongoing calls to NewStream are allowed to complete. - Close() + Interceptor any } // ServerInterceptor is an interceptor for incoming RPC's on gRPC server side. diff --git a/vendor/google.golang.org/grpc/internal/transport/client_stream.go b/vendor/google.golang.org/grpc/internal/transport/client_stream.go index ad382b0fda..046f0a5557 100644 --- a/vendor/google.golang.org/grpc/internal/transport/client_stream.go +++ b/vendor/google.golang.org/grpc/internal/transport/client_stream.go @@ -39,9 +39,8 @@ const nonGRPCDataMaxLen = 1024 type ClientStream struct { Stream // Embed for common stream functionality. - ct *http2Client - done chan struct{} // closed at the end of stream to unblock writers. - doneFunc func() // invoked at the end of stream. + ct *http2Client + done chan struct{} // closed at the end of stream to unblock writers. headerChan chan struct{} // closed to indicate the end of header metadata. header metadata.MD // the received header metadata diff --git a/vendor/google.golang.org/grpc/internal/transport/handler_server.go b/vendor/google.golang.org/grpc/internal/transport/handler_server.go index a8356c9adb..9cd8d28d33 100644 --- a/vendor/google.golang.org/grpc/internal/transport/handler_server.go +++ b/vendor/google.golang.org/grpc/internal/transport/handler_server.go @@ -424,7 +424,7 @@ func (ht *serverHandlerTransport) HandleStreams(ctx context.Context, startStream st: ht, headerWireLength: 0, // won't have access to header wire length until golang/go#18997. } - s.Stream.buf.init() + s.Stream.buf.init(ht.bufferPool) s.readRequester = s s.trReader = transportReader{ reader: recvBufferReader{ctx: s.ctx, ctxDone: s.ctx.Done(), recv: &s.buf}, diff --git a/vendor/google.golang.org/grpc/internal/transport/http2_client.go b/vendor/google.golang.org/grpc/internal/transport/http2_client.go index 822c09ba62..10d1977415 100644 --- a/vendor/google.golang.org/grpc/internal/transport/http2_client.go +++ b/vendor/google.golang.org/grpc/internal/transport/http2_client.go @@ -498,10 +498,9 @@ func (t *http2Client) newStream(ctx context.Context, callHdr *CallHdr, handler s ct: t, done: make(chan struct{}), headerChan: make(chan struct{}), - doneFunc: callHdr.DoneFunc, statsHandler: handler, } - s.Stream.buf.init() + s.Stream.buf.init(t.bufferPool) s.Stream.wq.init(defaultWriteQuota, s.done) s.readRequester = s // The client side stream context should have exactly the same life cycle with the user provided context. @@ -998,9 +997,6 @@ func (t *http2Client) closeStream(s *ClientStream, err error, rst bool, rstCode t.controlBuf.executeAndPut(addBackStreamQuota, cleanup) // This will unblock write. close(s.done) - if s.doneFunc != nil { - s.doneFunc() - } } // Close kicks off the shutdown process of the transport. This should be called diff --git a/vendor/google.golang.org/grpc/internal/transport/http2_server.go b/vendor/google.golang.org/grpc/internal/transport/http2_server.go index be8ae9f9c5..63c6539a3d 100644 --- a/vendor/google.golang.org/grpc/internal/transport/http2_server.go +++ b/vendor/google.golang.org/grpc/internal/transport/http2_server.go @@ -407,7 +407,7 @@ func (t *http2Server) operateHeaders(ctx context.Context, frame *http2.MetaHeade st: t, headerWireLength: int(frame.Header().Length), } - s.Stream.buf.init() + s.Stream.buf.init(t.bufferPool) var ( // if false, content-type was missing or invalid isGRPC = false diff --git a/vendor/google.golang.org/grpc/internal/transport/transport.go b/vendor/google.golang.org/grpc/internal/transport/transport.go index 6dfae39849..5fc901e5cf 100644 --- a/vendor/google.golang.org/grpc/internal/transport/transport.go +++ b/vendor/google.golang.org/grpc/internal/transport/transport.go @@ -30,11 +30,14 @@ import ( "sync" "sync/atomic" "time" + "unsafe" "golang.org/x/net/http2" "google.golang.org/grpc/codes" "google.golang.org/grpc/credentials" "google.golang.org/grpc/internal/channelz" + "google.golang.org/grpc/internal/envconfig" + imem "google.golang.org/grpc/internal/mem" "google.golang.org/grpc/internal/transport/internal" "google.golang.org/grpc/keepalive" "google.golang.org/grpc/mem" @@ -45,7 +48,30 @@ import ( "google.golang.org/grpc/tap" ) -const logLevel = 2 +const ( + logLevel = 2 + // recvMsgSize estimates the memory overhead of a recvMsg in the backlog. + // It accounts for the recvMsg struct itself and the slice header of the + // underlying buffer's data. + recvMsgSize = int(unsafe.Sizeof(recvMsg{}) + unsafe.Sizeof([]byte{})) + + // utilizationFactor controls when we consider memory utilization acceptable. + // When backlogHeapSize / payloadSize <= utilizationFactor (meaning at least + // 50% of the heap memory is actual payload data), compaction is skipped. + utilizationFactor = 2 +) + +var ( + // compactionThreshold is approx 57KB (on 64-bit systems). It allows + // accumulating up to 1024 1-byte payloads before triggering compaction. + // + // Because individual payloads <= 1024 bytes are allocated on the heap + // outside mem.BufferPool, waiting for at least 1024 bytes to accumulate + // ensures that compaction coalesces those small heap allocations into a + // single large buffer from mem.BufferPool, enabling buffer reuse while + // avoiding frequent copying for small bursts of frames. + compactionThreshold = imem.BufferPoolingThreshold * (recvMsgSize + 1) +) func init() { internal.TimeNowFunc = func() int64 { return time.Now().UnixNano() } @@ -71,23 +97,31 @@ type recvBuffer struct { c chan recvMsg mu sync.Mutex backlog []recvMsg - err error + // uncompactedSuffixLen tracks the number of consecutive data messages at + // the tail of backlog that have not been compacted. + uncompactedSuffixLen int + // uncompactedBytes tracks the total payload bytes across the trailing + // uncompactedSuffixLen messages. + uncompactedBytes int + err error + bufPool mem.BufferPool } // init allows a recvBuffer to be initialized in-place, which is useful // for resetting a buffer or for avoiding a heap allocation when the buffer // is embedded in another struct. -func (b *recvBuffer) init() { +func (b *recvBuffer) init(pool mem.BufferPool) { b.c = make(chan recvMsg, 1) + b.bufPool = pool } func (b *recvBuffer) put(r recvMsg) { b.mu.Lock() + defer b.mu.Unlock() if b.err != nil { // drop the buffer on the floor. Since b.err is not nil, any subsequent reads // will always return an error, making this buffer inaccessible. r.buffer.Free() - b.mu.Unlock() // An error had occurred earlier, don't accept more // data or errors. return @@ -96,13 +130,70 @@ func (b *recvBuffer) put(r recvMsg) { if len(b.backlog) == 0 { select { case b.c <- r: - b.mu.Unlock() return default: } } b.backlog = append(b.backlog, r) - b.mu.Unlock() + b.compactBacklogLocked(r) +} + +func (b *recvBuffer) compactBacklogLocked(r recvMsg) { + if !envconfig.EnableReceiveBufferCompaction { + return + } + if r.buffer == nil { + b.uncompactedBytes = 0 + b.uncompactedSuffixLen = 0 + return + } + + b.uncompactedSuffixLen++ + b.uncompactedBytes += r.buffer.Len() + backlogHeapSize := b.uncompactedSuffixLen*recvMsgSize + b.uncompactedBytes + + // If the memory overhead is less than 50% of the heap usage (e.g., because + // a large DATA frame arrived), the average message size in the suffix is + // large enough that memory bloat is not a concern. Reset suffix tracking. + if backlogHeapSize <= utilizationFactor*b.uncompactedBytes { + b.uncompactedBytes = 0 + b.uncompactedSuffixLen = 0 + return + } + // Avoid compacting too frequently for short bursts of small frames. + // Wait until we have accumulated at least ~1024 small messages (~57 KB). + if backlogHeapSize <= compactionThreshold { + // Still can accumulate more payloads. + return + } + + // Since the memory utilization is less than 50%, the average payload size + // of each recvMsg must be less than recvMsgSize (approx 56 bytes). + // In the worst case for bytes copied (where the average payload is just + // below recvMsgSize), compaction will occur once every: + // compactionThreshold / (recvMsgSize + avg_payload) = ~520 messages, + // copying ~29KB of data. + + start := 0 + newBuf := b.bufPool.Get(b.uncompactedBytes) + startIdx := len(b.backlog) - b.uncompactedSuffixLen + + for i := startIdx; i < len(b.backlog); i++ { + m := b.backlog[i] + b.backlog[i] = recvMsg{} + start += copy((*newBuf)[start:], m.buffer.ReadOnlyData()) + m.buffer.Free() + } + b.backlog[startIdx] = recvMsg{ + buffer: mem.NewBuffer(newBuf, b.bufPool), + } + b.backlog = b.backlog[:startIdx+1] + // After compaction, the suffix is replaced with a single message containing + // the combined payload. The new utilization is close to 1.0 (overhead of + // one recvMsg relative to the large compacted payload), which is well + // below the utilization factor of 2. + b.uncompactedBytes = 0 + b.uncompactedSuffixLen = 0 } func (b *recvBuffer) load() { @@ -110,6 +201,13 @@ func (b *recvBuffer) load() { if len(b.backlog) > 0 { select { case b.c <- b.backlog[0]: + // backlog[0] is only part of the tracked uncompacted suffix if the + // entire backlog currently consists of the suffix. If an earlier + // compaction or reset occurred, backlog[0] is already compacted. + if envconfig.EnableReceiveBufferCompaction && b.uncompactedSuffixLen == len(b.backlog) { + b.uncompactedSuffixLen-- + b.uncompactedBytes -= b.backlog[0].buffer.Len() + } b.backlog[0] = recvMsg{} b.backlog = b.backlog[1:] default: @@ -594,8 +692,6 @@ type CallHdr struct { PreviousAttempts int // value of grpc-previous-rpc-attempts header to set - DoneFunc func() // called when the stream is finished - // Authority is used to explicitly override the `:authority` header. // // This value comes from one of two sources: diff --git a/vendor/google.golang.org/grpc/mem/buffer_pool.go b/vendor/google.golang.org/grpc/mem/buffer_pool.go index 3b02b90916..aa121379fd 100644 --- a/vendor/google.golang.org/grpc/mem/buffer_pool.go +++ b/vendor/google.golang.org/grpc/mem/buffer_pool.go @@ -59,10 +59,6 @@ func init() { internal.SetDefaultBufferPool = func(pool BufferPool) { defaultBufferPool = pool } - - internal.SetBufferPoolingThresholdForTesting = func(threshold int) { - bufferPoolingThreshold = threshold - } } // DefaultBufferPool returns the current default buffer pool. It is a BufferPool diff --git a/vendor/google.golang.org/grpc/mem/buffers.go b/vendor/google.golang.org/grpc/mem/buffers.go index 2b410b16eb..9b355d4465 100644 --- a/vendor/google.golang.org/grpc/mem/buffers.go +++ b/vendor/google.golang.org/grpc/mem/buffers.go @@ -29,6 +29,8 @@ import ( "fmt" "sync" "sync/atomic" + + "google.golang.org/grpc/internal/mem" ) // A Buffer represents a reference counted piece of data (in bytes) that can be @@ -63,8 +65,6 @@ type Buffer interface { } var ( - bufferPoolingThreshold = 1 << 10 - bufferObjectPool = sync.Pool{New: func() any { return new(buffer) }} ) @@ -72,7 +72,7 @@ var ( // equal to the threshold for buffer pooling. This is used to determine whether // to pool buffers or allocate them directly. func IsBelowBufferPoolingThreshold(size int) bool { - return size <= bufferPoolingThreshold + return size <= mem.BufferPoolingThreshold } type buffer struct { diff --git a/vendor/google.golang.org/grpc/stream.go b/vendor/google.golang.org/grpc/stream.go index 4aac644a83..51aff85dfb 100644 --- a/vendor/google.golang.org/grpc/stream.go +++ b/vendor/google.golang.org/grpc/stream.go @@ -201,6 +201,15 @@ func endOfClientStream(cc *ClientConn, err error, opts ...CallOption) { } } +// clientInterceptor is structurally identical to the ClientInterceptor defined +// in internal/xds/httpfilter/httpfilter.go. It is defined locally here so that +// we can type-assert the generic Interceptor field in iresolver.RPCConfig +// without introducing a dependency on xDS packages. +type clientInterceptor interface { + NewStream(ctx context.Context, ri iresolver.RPCInfo, newStream func(ctx context.Context, opts ...CallOption) (ClientStream, error), opts ...CallOption) (ClientStream, error) + Close() +} + func newClientStream(ctx context.Context, desc *StreamDesc, cc *ClientConn, method string, opts ...CallOption) (_ ClientStream, err error) { if channelz.IsOn() { cc.incrCallsStarted() @@ -244,8 +253,11 @@ func newClientStream(ctx context.Context, desc *StreamDesc, cc *ClientConn, meth mc := &emptyMethodConfig var onCommit func() - newStream := func(ctx context.Context, done func()) (iresolver.ClientStream, error) { - return newClientStreamWithParams(ctx, desc, cc, method, mc, onCommit, done, nameResolutionDelayed, opts...) + newStream := func(ctx context.Context, filterOpts ...CallOption) (ClientStream, error) { + if filterOpts != nil { + opts = combine(opts, filterOpts) + } + return newClientStreamWithParams(ctx, desc, cc, method, mc, onCommit, nameResolutionDelayed, opts...) } rpcInfo := iresolver.RPCInfo{Context: ctx, Method: method} @@ -270,20 +282,24 @@ func newClientStream(ctx context.Context, desc *StreamDesc, cc *ClientConn, meth if rpcConfig.Interceptor != nil { rpcInfo.Context = nil ns := newStream - newStream = func(ctx context.Context, done func()) (iresolver.ClientStream, error) { - cs, err := rpcConfig.Interceptor.NewStream(ctx, rpcInfo, done, ns) - if err != nil { - return nil, toRPCErr(err) + if interceptor, ok := rpcConfig.Interceptor.(clientInterceptor); ok { + newStream = func(ctx context.Context, filterOpts ...CallOption) (ClientStream, error) { + cs, err := interceptor.NewStream(ctx, rpcInfo, ns, filterOpts...) + if err != nil { + return nil, toRPCErr(err) + } + return cs, nil } - return cs, nil + } else { + return nil, status.Errorf(codes.Internal, "invalid client interceptor type %T", rpcConfig.Interceptor) } } } - return newStream(ctx, func() {}) + return newStream(ctx) } -func newClientStreamWithParams(ctx context.Context, desc *StreamDesc, cc *ClientConn, method string, mc *serviceconfig.MethodConfig, onCommit, doneFunc func(), nameResolutionDelayed bool, opts ...CallOption) (_ iresolver.ClientStream, err error) { +func newClientStreamWithParams(ctx context.Context, desc *StreamDesc, cc *ClientConn, method string, mc *serviceconfig.MethodConfig, onCommit func(), nameResolutionDelayed bool, opts ...CallOption) (_ ClientStream, err error) { callInfo := defaultCallInfo() if mc.WaitForReady != nil { callInfo.failFast = !*mc.WaitForReady @@ -321,7 +337,6 @@ func newClientStreamWithParams(ctx context.Context, desc *StreamDesc, cc *Client Host: cc.authority, Method: method, ContentSubtype: callInfo.contentSubtype, - DoneFunc: doneFunc, Authority: callInfo.authority, } if allowed := callInfo.acceptedResponseCompressors; len(allowed) > 0 { diff --git a/vendor/google.golang.org/grpc/version.go b/vendor/google.golang.org/grpc/version.go index 53c737feeb..64ec3b3cfd 100644 --- a/vendor/google.golang.org/grpc/version.go +++ b/vendor/google.golang.org/grpc/version.go @@ -19,4 +19,4 @@ package grpc // Version is the current grpc version. -const Version = "1.82.1" +const Version = "1.83.1" diff --git a/vendor/helm.sh/helm/v3/pkg/engine/files.go b/vendor/helm.sh/helm/v3/pkg/engine/files.go index f2cfdb3f38..7b23afd6bb 100644 --- a/vendor/helm.sh/helm/v3/pkg/engine/files.go +++ b/vendor/helm.sh/helm/v3/pkg/engine/files.go @@ -154,7 +154,7 @@ func (f files) AsSecrets() string { // {{ range .Files.Lines "foo/bar.html" }} // {{ . }}{{ end }} func (f files) Lines(path string) []string { - if f == nil || f[path] == nil { + if f == nil || len(f[path]) == 0 { return []string{} } s := string(f[path]) diff --git a/vendor/helm.sh/helm/v3/pkg/provenance/sign.go b/vendor/helm.sh/helm/v3/pkg/provenance/sign.go index 7f89ef3f53..31279336da 100644 --- a/vendor/helm.sh/helm/v3/pkg/provenance/sign.go +++ b/vendor/helm.sh/helm/v3/pkg/provenance/sign.go @@ -24,10 +24,10 @@ import ( "path/filepath" "strings" + "github.com/ProtonMail/go-crypto/openpgp" + "github.com/ProtonMail/go-crypto/openpgp/clearsign" + "github.com/ProtonMail/go-crypto/openpgp/packet" "github.com/pkg/errors" - "golang.org/x/crypto/openpgp" //nolint - "golang.org/x/crypto/openpgp/clearsign" //nolint - "golang.org/x/crypto/openpgp/packet" //nolint "sigs.k8s.io/yaml" hapi "helm.sh/helm/v3/pkg/chart" @@ -314,8 +314,9 @@ func (s *Signatory) decodeSignature(filename string) (*clearsign.Block, error) { func (s *Signatory) verifySignature(block *clearsign.Block) (*openpgp.Entity, error) { return openpgp.CheckDetachedSignature( s.KeyRing, - bytes.NewBuffer(block.Bytes), + bytes.NewReader(block.Bytes), block.ArmoredSignature.Body, + &defaultPGPConfig, ) } diff --git a/vendor/modules.txt b/vendor/modules.txt index f4d1500460..64aa941947 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -78,6 +78,7 @@ github.com/ProtonMail/go-crypto/ocb github.com/ProtonMail/go-crypto/openpgp github.com/ProtonMail/go-crypto/openpgp/aes/keywrap github.com/ProtonMail/go-crypto/openpgp/armor +github.com/ProtonMail/go-crypto/openpgp/clearsign github.com/ProtonMail/go-crypto/openpgp/ecdh github.com/ProtonMail/go-crypto/openpgp/ecdsa github.com/ProtonMail/go-crypto/openpgp/ed25519 @@ -245,8 +246,11 @@ github.com/containers/ocicrypt/utils/keyprovider # github.com/cucumber/gherkin/go/v26 v26.2.0 ## explicit; go 1.19 github.com/cucumber/gherkin/go/v26 -# github.com/cucumber/godog v0.15.1 -## explicit; go 1.16 +# github.com/cucumber/gherkin/go/v42 v42.0.0 +## explicit; go 1.19 +github.com/cucumber/gherkin/go/v42 +# github.com/cucumber/godog v0.16.0 +## explicit; go 1.18 github.com/cucumber/godog github.com/cucumber/godog/colors github.com/cucumber/godog/formatters @@ -261,6 +265,9 @@ github.com/cucumber/godog/internal/utils # github.com/cucumber/messages/go/v21 v21.0.1 ## explicit; go 1.19 github.com/cucumber/messages/go/v21 +# github.com/cucumber/messages/go/v34 v34.2.0 +## explicit; go 1.19 +github.com/cucumber/messages/go/v34 # github.com/cyberphone/json-canonicalization v0.0.0-20241213102144-19d51d7fe467 ## explicit github.com/cyberphone/json-canonicalization/go/src/webpki.org/jsoncanonicalizer @@ -274,7 +281,7 @@ github.com/davecgh/go-spew/spew # github.com/distribution/reference v0.6.0 ## explicit; go 1.20 github.com/distribution/reference -# github.com/docker/cli v29.6.2+incompatible +# github.com/docker/cli v29.7.1+incompatible ## explicit github.com/docker/cli/cli/config github.com/docker/cli/cli/config/configfile @@ -471,7 +478,7 @@ github.com/google/go-cmp/cmp/internal/diff github.com/google/go-cmp/cmp/internal/flags github.com/google/go-cmp/cmp/internal/function github.com/google/go-cmp/cmp/internal/value -# github.com/google/go-containerregistry v0.21.7 +# github.com/google/go-containerregistry v0.21.9 ## explicit; go 1.25.0 github.com/google/go-containerregistry/internal/and github.com/google/go-containerregistry/internal/compression @@ -585,7 +592,7 @@ github.com/joelanford/ignore # github.com/json-iterator/go v1.1.12 ## explicit; go 1.12 github.com/json-iterator/go -# github.com/klauspost/compress v1.19.1 +# github.com/klauspost/compress v1.19.2 ## explicit; go 1.24 github.com/klauspost/compress github.com/klauspost/compress/flate @@ -634,7 +641,7 @@ github.com/mattn/go-isatty # github.com/mattn/go-runewidth v0.0.27 ## explicit; go 1.23 github.com/mattn/go-runewidth -# github.com/mattn/go-sqlite3 v1.14.48 +# github.com/mattn/go-sqlite3 v1.14.49 ## explicit; go 1.21 github.com/mattn/go-sqlite3 # github.com/miekg/pkcs11 v1.1.2 @@ -732,7 +739,7 @@ github.com/operator-framework/helm-operator-plugins/pkg/storage github.com/operator-framework/operator-lib/handler github.com/operator-framework/operator-lib/handler/internal/metrics github.com/operator-framework/operator-lib/internal/annotation -# github.com/operator-framework/operator-registry v1.73.0 +# github.com/operator-framework/operator-registry v1.74.0 ## explicit; go 1.26.3 github.com/operator-framework/operator-registry/alpha/declcfg github.com/operator-framework/operator-registry/alpha/model @@ -838,10 +845,12 @@ github.com/spf13/pflag # github.com/stefanberger/go-pkcs11uri v0.0.0-20230803200340-78284954bff6 ## explicit; go 1.19 github.com/stefanberger/go-pkcs11uri -# github.com/stretchr/testify v1.11.1 +# github.com/stretchr/testify v1.12.1 ## explicit; go 1.17 github.com/stretchr/testify/assert github.com/stretchr/testify/assert/yaml +github.com/stretchr/testify/internal/difflib +github.com/stretchr/testify/internal/spew github.com/stretchr/testify/require # github.com/ulikunitz/xz v0.5.16 ## explicit; go 1.20 @@ -961,13 +970,13 @@ go.opentelemetry.io/proto/otlp/collector/trace/v1 go.opentelemetry.io/proto/otlp/common/v1 go.opentelemetry.io/proto/otlp/resource/v1 go.opentelemetry.io/proto/otlp/trace/v1 -# go.podman.io/common v0.68.1 -## explicit; go 1.25.6 +# go.podman.io/common v0.69.0 +## explicit; go 1.25.7 go.podman.io/common/pkg/auth go.podman.io/common/pkg/capabilities go.podman.io/common/pkg/completion go.podman.io/common/pkg/password -# go.podman.io/image/v5 v5.41.0 +# go.podman.io/image/v5 v5.41.1 ## explicit; go 1.25.7 go.podman.io/image/v5/copy go.podman.io/image/v5/directory/explicitfilepath @@ -1054,7 +1063,7 @@ go.yaml.in/yaml/v2 # go.yaml.in/yaml/v3 v3.0.5 ## explicit; go 1.16 go.yaml.in/yaml/v3 -# golang.org/x/crypto v0.54.0 +# golang.org/x/crypto v0.55.0 ## explicit; go 1.25.0 golang.org/x/crypto/argon2 golang.org/x/crypto/bcrypt @@ -1067,13 +1076,6 @@ golang.org/x/crypto/hkdf golang.org/x/crypto/internal/alias golang.org/x/crypto/internal/poly1305 golang.org/x/crypto/nacl/secretbox -golang.org/x/crypto/openpgp -golang.org/x/crypto/openpgp/armor -golang.org/x/crypto/openpgp/clearsign -golang.org/x/crypto/openpgp/elgamal -golang.org/x/crypto/openpgp/errors -golang.org/x/crypto/openpgp/packet -golang.org/x/crypto/openpgp/s2k golang.org/x/crypto/pbkdf2 golang.org/x/crypto/salsa20/salsa golang.org/x/crypto/scrypt @@ -1082,13 +1084,13 @@ golang.org/x/crypto/sha3 ## explicit; go 1.25.0 golang.org/x/exp/maps golang.org/x/exp/slices -# golang.org/x/mod v0.38.0 +# golang.org/x/mod v0.39.0 ## explicit; go 1.25.0 golang.org/x/mod/internal/lazyregexp golang.org/x/mod/modfile golang.org/x/mod/module golang.org/x/mod/semver -# golang.org/x/net v0.57.0 +# golang.org/x/net v0.58.0 ## explicit; go 1.25.0 golang.org/x/net/context golang.org/x/net/http/httpguts @@ -1121,7 +1123,7 @@ golang.org/x/sys/windows/registry # golang.org/x/term v0.45.0 ## explicit; go 1.25.0 golang.org/x/term -# golang.org/x/text v0.40.0 +# golang.org/x/text v0.41.0 ## explicit; go 1.25.0 golang.org/x/text/cases golang.org/x/text/encoding @@ -1149,7 +1151,7 @@ golang.org/x/text/unicode/norm # golang.org/x/time v0.15.0 ## explicit; go 1.25.0 golang.org/x/time/rate -# golang.org/x/tools v0.48.0 +# golang.org/x/tools v0.49.0 ## explicit; go 1.25.0 golang.org/x/tools/go/analysis golang.org/x/tools/go/analysis/analysistest @@ -1163,7 +1165,6 @@ golang.org/x/tools/go/ast/inspector golang.org/x/tools/go/gcexportdata golang.org/x/tools/go/packages golang.org/x/tools/go/types/objectpath -golang.org/x/tools/go/types/typeutil golang.org/x/tools/internal/aliases golang.org/x/tools/internal/analysis/driverutil golang.org/x/tools/internal/astutil/free @@ -1176,11 +1177,11 @@ golang.org/x/tools/internal/event/label golang.org/x/tools/internal/facts golang.org/x/tools/internal/gcimporter golang.org/x/tools/internal/gocommand +golang.org/x/tools/internal/moremaps golang.org/x/tools/internal/packagesinternal golang.org/x/tools/internal/pkgbits golang.org/x/tools/internal/stdlib golang.org/x/tools/internal/testenv -golang.org/x/tools/internal/typeparams golang.org/x/tools/internal/typesinternal golang.org/x/tools/internal/versions golang.org/x/tools/txtar @@ -1200,7 +1201,7 @@ google.golang.org/genproto/googleapis/api/httpbody ## explicit; go 1.25.0 google.golang.org/genproto/googleapis/rpc/errdetails google.golang.org/genproto/googleapis/rpc/status -# google.golang.org/grpc v1.82.1 +# google.golang.org/grpc v1.83.1 ## explicit; go 1.25.0 google.golang.org/grpc google.golang.org/grpc/attributes @@ -1328,7 +1329,7 @@ gopkg.in/yaml.v2 # gopkg.in/yaml.v3 v3.0.1 ## explicit gopkg.in/yaml.v3 -# helm.sh/helm/v3 v3.21.3 +# helm.sh/helm/v3 v3.21.4 ## explicit; go 1.26.0 helm.sh/helm/v3/internal/fileutil helm.sh/helm/v3/internal/resolver @@ -1427,7 +1428,7 @@ k8s.io/api/storage/v1 k8s.io/api/storage/v1alpha1 k8s.io/api/storage/v1beta1 k8s.io/api/storagemigration/v1beta1 -# k8s.io/apiextensions-apiserver v0.36.2 +# k8s.io/apiextensions-apiserver v0.36.3 ## explicit; go 1.26.0 k8s.io/apiextensions-apiserver/pkg/apihelpers k8s.io/apiextensions-apiserver/pkg/apis/apiextensions