mirror of
https://github.com/kubernetes-sigs/descheduler.git
synced 2026-01-26 05:14:13 +01:00
[v0.34.0] bump to kubernetes 1.34 deps
Signed-off-by: Amir Alavi <amiralavi7@gmail.com>
This commit is contained in:
4
.github/workflows/manifests.yaml
vendored
4
.github/workflows/manifests.yaml
vendored
@@ -7,11 +7,11 @@ jobs:
|
|||||||
deploy:
|
deploy:
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
k8s-version: ["v1.33.0"]
|
k8s-version: ["v1.34.0"]
|
||||||
descheduler-version: ["v0.33.0"]
|
descheduler-version: ["v0.33.0"]
|
||||||
descheduler-api: ["v1alpha2"]
|
descheduler-api: ["v1alpha2"]
|
||||||
manifest: ["deployment"]
|
manifest: ["deployment"]
|
||||||
kind-version: ["v0.27.0"] # keep in sync with test/run-e2e-tests.sh
|
kind-version: ["v0.30.0"] # keep in sync with test/run-e2e-tests.sh
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout Repo
|
- name: Checkout Repo
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
FROM golang:1.24.2
|
FROM golang:1.24.6
|
||||||
|
|
||||||
WORKDIR /go/src/sigs.k8s.io/descheduler
|
WORKDIR /go/src/sigs.k8s.io/descheduler
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|||||||
113
go.mod
113
go.mod
@@ -1,57 +1,60 @@
|
|||||||
module sigs.k8s.io/descheduler
|
module sigs.k8s.io/descheduler
|
||||||
|
|
||||||
go 1.24.2
|
go 1.24.0
|
||||||
|
|
||||||
|
toolchain go1.24.3
|
||||||
|
|
||||||
|
godebug default=go1.24
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/client9/misspell v0.3.4
|
github.com/client9/misspell v0.3.4
|
||||||
github.com/google/go-cmp v0.7.0
|
github.com/google/go-cmp v0.7.0
|
||||||
github.com/prometheus/client_golang v1.22.0
|
github.com/prometheus/client_golang v1.22.0
|
||||||
github.com/prometheus/common v0.62.0
|
github.com/prometheus/common v0.64.0
|
||||||
github.com/spf13/cobra v1.8.1
|
github.com/spf13/cobra v1.10.0
|
||||||
github.com/spf13/pflag v1.0.5
|
github.com/spf13/pflag v1.0.9
|
||||||
go.opentelemetry.io/otel v1.33.0
|
go.opentelemetry.io/otel v1.36.0
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.33.0
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.36.0
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.33.0
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.36.0
|
||||||
go.opentelemetry.io/otel/sdk v1.33.0
|
go.opentelemetry.io/otel/sdk v1.36.0
|
||||||
go.opentelemetry.io/otel/trace v1.33.0
|
go.opentelemetry.io/otel/trace v1.36.0
|
||||||
google.golang.org/grpc v1.68.1
|
google.golang.org/grpc v1.72.2
|
||||||
k8s.io/api v0.33.0
|
k8s.io/api v0.34.0
|
||||||
k8s.io/apimachinery v0.33.0
|
k8s.io/apimachinery v0.34.0
|
||||||
k8s.io/apiserver v0.33.0
|
k8s.io/apiserver v0.34.0
|
||||||
k8s.io/client-go v0.33.0
|
k8s.io/client-go v0.34.0
|
||||||
k8s.io/code-generator v0.33.0
|
k8s.io/code-generator v0.34.0
|
||||||
k8s.io/component-base v0.33.0
|
k8s.io/component-base v0.34.0
|
||||||
k8s.io/component-helpers v0.33.0
|
k8s.io/component-helpers v0.34.0
|
||||||
k8s.io/klog/v2 v2.130.1
|
k8s.io/klog/v2 v2.130.1
|
||||||
k8s.io/metrics v0.33.0
|
k8s.io/metrics v0.34.0
|
||||||
k8s.io/utils v0.0.0-20250321185631-1f6e0b77f77e
|
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397
|
||||||
kubevirt.io/api v1.3.0
|
kubevirt.io/api v1.3.0
|
||||||
kubevirt.io/client-go v1.3.0
|
kubevirt.io/client-go v1.3.0
|
||||||
kubevirt.io/containerized-data-importer-api v1.60.1 // indirect; drops dependency on o/api
|
kubevirt.io/containerized-data-importer-api v1.60.1 // indirect; drops dependency on o/api
|
||||||
sigs.k8s.io/mdtoc v1.1.0
|
sigs.k8s.io/mdtoc v1.1.0
|
||||||
sigs.k8s.io/yaml v1.4.0
|
sigs.k8s.io/yaml v1.6.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56
|
require golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56
|
||||||
|
|
||||||
require (
|
require (
|
||||||
cel.dev/expr v0.19.1 // indirect
|
cel.dev/expr v0.24.0 // indirect
|
||||||
github.com/BurntSushi/toml v0.3.1 // indirect
|
github.com/BurntSushi/toml v0.3.1 // indirect
|
||||||
github.com/NYTimes/gziphandler v1.1.1 // indirect
|
github.com/NYTimes/gziphandler v1.1.1 // indirect
|
||||||
github.com/antlr4-go/antlr/v4 v4.13.0 // indirect
|
github.com/antlr4-go/antlr/v4 v4.13.0 // indirect
|
||||||
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a // indirect
|
|
||||||
github.com/beorn7/perks v1.0.1 // indirect
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
github.com/blang/semver/v4 v4.0.0 // indirect
|
github.com/blang/semver/v4 v4.0.0 // indirect
|
||||||
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
github.com/cenkalti/backoff/v5 v5.0.2 // indirect
|
||||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||||
github.com/coreos/go-semver v0.3.1 // indirect
|
github.com/coreos/go-semver v0.3.1 // indirect
|
||||||
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
|
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect
|
github.com/cpuguy83/go-md2man/v2 v2.0.6 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||||
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
|
github.com/emicklei/go-restful/v3 v3.12.2 // indirect
|
||||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||||
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
github.com/fsnotify/fsnotify v1.9.0 // indirect
|
||||||
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
|
github.com/fxamacker/cbor/v2 v2.9.0 // indirect
|
||||||
github.com/go-kit/kit v0.13.0 // indirect
|
github.com/go-kit/kit v0.13.0 // indirect
|
||||||
github.com/go-kit/log v0.2.1 // indirect
|
github.com/go-kit/log v0.2.1 // indirect
|
||||||
github.com/go-logfmt/logfmt v0.6.0 // indirect
|
github.com/go-logfmt/logfmt v0.6.0 // indirect
|
||||||
@@ -66,13 +69,12 @@ require (
|
|||||||
github.com/golang/protobuf v1.5.4 // indirect
|
github.com/golang/protobuf v1.5.4 // indirect
|
||||||
github.com/gomarkdown/markdown v0.0.0-20210514010506-3b9f47219fe7 // indirect
|
github.com/gomarkdown/markdown v0.0.0-20210514010506-3b9f47219fe7 // indirect
|
||||||
github.com/google/btree v1.1.3 // indirect
|
github.com/google/btree v1.1.3 // indirect
|
||||||
github.com/google/cel-go v0.23.2 // indirect
|
github.com/google/cel-go v0.26.0 // indirect
|
||||||
github.com/google/gnostic-models v0.6.9 // indirect
|
github.com/google/gnostic-models v0.7.0 // indirect
|
||||||
github.com/google/gofuzz v1.2.0 // indirect
|
|
||||||
github.com/google/uuid v1.6.0 // indirect
|
github.com/google/uuid v1.6.0 // indirect
|
||||||
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect
|
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect
|
||||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect
|
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect
|
||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0 // indirect
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 // indirect
|
||||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||||
github.com/josharian/intern v1.0.0 // indirect
|
github.com/josharian/intern v1.0.0 // indirect
|
||||||
github.com/jpillora/backoff v1.0.0 // indirect
|
github.com/jpillora/backoff v1.0.0 // indirect
|
||||||
@@ -81,53 +83,56 @@ require (
|
|||||||
github.com/mailru/easyjson v0.7.7 // indirect
|
github.com/mailru/easyjson v0.7.7 // indirect
|
||||||
github.com/mmarkdown/mmark v2.0.40+incompatible // indirect
|
github.com/mmarkdown/mmark v2.0.40+incompatible // indirect
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||||
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect
|
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect
|
||||||
github.com/openshift/custom-resource-status v1.1.2 // indirect
|
github.com/openshift/custom-resource-status v1.1.2 // indirect
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
github.com/prometheus/client_model v0.6.1 // indirect
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||||
|
github.com/prometheus/client_model v0.6.2 // indirect
|
||||||
github.com/prometheus/procfs v0.15.1 // indirect
|
github.com/prometheus/procfs v0.15.1 // indirect
|
||||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||||
github.com/stoewer/go-strcase v1.3.0 // indirect
|
github.com/stoewer/go-strcase v1.3.0 // indirect
|
||||||
github.com/x448/float16 v0.8.4 // indirect
|
github.com/x448/float16 v0.8.4 // indirect
|
||||||
go.etcd.io/etcd/api/v3 v3.5.21 // indirect
|
go.etcd.io/etcd/api/v3 v3.6.4 // indirect
|
||||||
go.etcd.io/etcd/client/pkg/v3 v3.5.21 // indirect
|
go.etcd.io/etcd/client/pkg/v3 v3.6.4 // indirect
|
||||||
go.etcd.io/etcd/client/v3 v3.5.21 // indirect
|
go.etcd.io/etcd/client/v3 v3.6.4 // indirect
|
||||||
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
||||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.58.0 // indirect
|
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0 // indirect
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0 // indirect
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0 // indirect
|
||||||
go.opentelemetry.io/otel/metric v1.33.0 // indirect
|
go.opentelemetry.io/otel/metric v1.36.0 // indirect
|
||||||
go.opentelemetry.io/proto/otlp v1.4.0 // indirect
|
go.opentelemetry.io/proto/otlp v1.6.0 // indirect
|
||||||
go.uber.org/multierr v1.11.0 // indirect
|
go.uber.org/multierr v1.11.0 // indirect
|
||||||
go.uber.org/zap v1.27.0 // indirect
|
go.uber.org/zap v1.27.0 // indirect
|
||||||
golang.org/x/crypto v0.36.0 // indirect
|
go.yaml.in/yaml/v2 v2.4.2 // indirect
|
||||||
|
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
||||||
|
golang.org/x/crypto v0.38.0 // indirect
|
||||||
golang.org/x/mod v0.21.0 // indirect
|
golang.org/x/mod v0.21.0 // indirect
|
||||||
golang.org/x/net v0.38.0 // indirect
|
golang.org/x/net v0.40.0 // indirect
|
||||||
golang.org/x/oauth2 v0.27.0 // indirect
|
golang.org/x/oauth2 v0.30.0 // indirect
|
||||||
golang.org/x/sync v0.12.0 // indirect
|
golang.org/x/sync v0.14.0 // indirect
|
||||||
golang.org/x/sys v0.31.0 // indirect
|
golang.org/x/sys v0.33.0 // indirect
|
||||||
golang.org/x/term v0.30.0 // indirect
|
golang.org/x/term v0.32.0 // indirect
|
||||||
golang.org/x/text v0.23.0 // indirect
|
golang.org/x/text v0.25.0 // indirect
|
||||||
golang.org/x/time v0.9.0 // indirect
|
golang.org/x/time v0.9.0 // indirect
|
||||||
golang.org/x/tools v0.26.0 // indirect
|
golang.org/x/tools v0.26.0 // indirect
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576 // indirect
|
google.golang.org/genproto/googleapis/api v0.0.0-20250519155744-55703ea1f237 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20250519155744-55703ea1f237 // indirect
|
||||||
google.golang.org/protobuf v1.36.5 // indirect
|
google.golang.org/protobuf v1.36.6 // indirect
|
||||||
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
|
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
|
||||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
|
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
|
||||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
k8s.io/apiextensions-apiserver v0.30.0 // indirect
|
k8s.io/apiextensions-apiserver v0.30.0 // indirect
|
||||||
k8s.io/gengo/v2 v2.0.0-20250207200755-1244d31929d7 // indirect
|
k8s.io/gengo/v2 v2.0.0-20250604051438-85fd79dbfd9f // indirect
|
||||||
k8s.io/kms v0.33.0 // indirect
|
k8s.io/kms v0.34.0 // indirect
|
||||||
k8s.io/kube-openapi v0.30.0 // indirect
|
k8s.io/kube-openapi v0.30.0 // indirect
|
||||||
kubevirt.io/controller-lifecycle-operator-sdk/api v0.0.0-20220329064328-f3cc58c6ed90 // indirect
|
kubevirt.io/controller-lifecycle-operator-sdk/api v0.0.0-20220329064328-f3cc58c6ed90 // indirect
|
||||||
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 // indirect
|
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 // indirect
|
||||||
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect
|
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect
|
||||||
sigs.k8s.io/randfill v1.0.0 // indirect
|
sigs.k8s.io/randfill v1.0.0 // indirect
|
||||||
sigs.k8s.io/structured-merge-diff/v4 v4.6.0 // indirect
|
sigs.k8s.io/structured-merge-diff/v6 v6.3.0 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
replace k8s.io/kube-openapi => k8s.io/kube-openapi v0.0.0-20240430033511-f0e62f92d13f
|
replace k8s.io/kube-openapi => k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b
|
||||||
|
|||||||
282
go.sum
282
go.sum
@@ -1,23 +1,20 @@
|
|||||||
cel.dev/expr v0.19.1 h1:NciYrtDRIR0lNCnH1LFJegdjspNx9fI59O7TWcua/W4=
|
cel.dev/expr v0.24.0 h1:56OvJKSH3hDGL0ml5uSxZmz3/3Pq4tJ+fb1unVLAFcY=
|
||||||
cel.dev/expr v0.19.1/go.mod h1:MrpN08Q+lEBs+bGYdLxxHkZoUSsCp0nSKTs0nTymJgw=
|
cel.dev/expr v0.24.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw=
|
||||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
|
|
||||||
github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I=
|
github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I=
|
||||||
github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c=
|
github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c=
|
||||||
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||||
github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI=
|
github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI=
|
||||||
github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g=
|
github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g=
|
||||||
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a h1:idn718Q4B6AGu/h5Sxe66HYVdqdGu2l9Iebqhi/AEoA=
|
|
||||||
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
|
|
||||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||||
github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
|
github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
|
||||||
github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
|
github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
|
||||||
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
|
github.com/cenkalti/backoff/v5 v5.0.2 h1:rIfFVxEf1QsI7E1ZHfp/B4DF/6QBAUhmgkxc0H7Zss8=
|
||||||
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
github.com/cenkalti/backoff/v5 v5.0.2/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=
|
||||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
@@ -36,8 +33,8 @@ 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-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec=
|
||||||
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
|
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
|
||||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4=
|
github.com/cpuguy83/go-md2man/v2 v2.0.6 h1:XJtiaUW6dEEqVuZiMTn1ldk455QWwEIsMIJlo5vtkx0=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
@@ -49,9 +46,9 @@ github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+m
|
|||||||
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
|
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
|
||||||
github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
|
github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
|
||||||
github.com/emicklei/go-restful v2.15.0+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
|
github.com/emicklei/go-restful v2.15.0+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
|
||||||
github.com/emicklei/go-restful/v3 v3.8.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
|
||||||
github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g=
|
|
||||||
github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
||||||
|
github.com/emicklei/go-restful/v3 v3.12.2 h1:DhwDP0vY3k8ZzE0RunuJy8GhNpPL6zqLkDf9B/a0/xU=
|
||||||
|
github.com/emicklei/go-restful/v3 v3.12.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||||
github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
||||||
@@ -59,10 +56,10 @@ github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2
|
|||||||
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||||
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
|
||||||
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
||||||
github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
|
github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM=
|
||||||
github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
|
github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
|
||||||
github.com/go-kit/kit v0.13.0 h1:OoneCcHKHQ03LfBpoQCUfCluwd2Vt3ohz+kvbJneZAU=
|
github.com/go-kit/kit v0.13.0 h1:OoneCcHKHQ03LfBpoQCUfCluwd2Vt3ohz+kvbJneZAU=
|
||||||
github.com/go-kit/kit v0.13.0/go.mod h1:phqEHMMUbyrCFCTgH48JueqrM3md2HcAZ8N3XE4FKDg=
|
github.com/go-kit/kit v0.13.0/go.mod h1:phqEHMMUbyrCFCTgH48JueqrM3md2HcAZ8N3XE4FKDg=
|
||||||
github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU=
|
github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU=
|
||||||
@@ -108,8 +105,8 @@ github.com/gobwas/ws v1.2.1/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/K
|
|||||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||||
github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI=
|
github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8=
|
||||||
github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
github.com/golang/glog v1.2.4 h1:CNNw5U8lSiiBk7druxtSHHTsRWcxKoac6kZKm2peBBc=
|
github.com/golang/glog v1.2.4 h1:CNNw5U8lSiiBk7druxtSHHTsRWcxKoac6kZKm2peBBc=
|
||||||
github.com/golang/glog v1.2.4/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w=
|
github.com/golang/glog v1.2.4/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w=
|
||||||
@@ -132,11 +129,10 @@ github.com/gomarkdown/markdown v0.0.0-20210514010506-3b9f47219fe7 h1:oKYOfNR7Hp6
|
|||||||
github.com/gomarkdown/markdown v0.0.0-20210514010506-3b9f47219fe7/go.mod h1:aii0r/K0ZnHv7G0KF7xy1v0A7s2Ljrb5byB7MO5p6TU=
|
github.com/gomarkdown/markdown v0.0.0-20210514010506-3b9f47219fe7/go.mod h1:aii0r/K0ZnHv7G0KF7xy1v0A7s2Ljrb5byB7MO5p6TU=
|
||||||
github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
|
github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
|
||||||
github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
|
github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
|
||||||
github.com/google/cel-go v0.23.2 h1:UdEe3CvQh3Nv+E/j9r1Y//WO0K0cSyD7/y0bzyLIMI4=
|
github.com/google/cel-go v0.26.0 h1:DPGjXackMpJWH680oGY4lZhYjIameYmR+/6RBdDGmaI=
|
||||||
github.com/google/cel-go v0.23.2/go.mod h1:52Pb6QsDbC5kvgxvZhiL9QX1oZEkcUF/ZqaPx1J5Wwo=
|
github.com/google/cel-go v0.26.0/go.mod h1:A9O8OU9rdvrK5MQyrqfIxo1a0u4g3sF8KB6PUIaryMM=
|
||||||
github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U=
|
github.com/google/gnostic-models v0.7.0 h1:qwTtogB15McXDaNqTZdzPJRHvaVJlAl+HVQnLmJEJxo=
|
||||||
github.com/google/gnostic-models v0.6.9 h1:MU/8wDLif2qCXZmzncUQ/BOfxWfthHi63KqpoNbWqVw=
|
github.com/google/gnostic-models v0.7.0/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ=
|
||||||
github.com/google/gnostic-models v0.6.9/go.mod h1:CiWsm0s6BSQd1hRn8/QmxqB6BesYcbSZxsz9b0KuDBw=
|
|
||||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
@@ -149,10 +145,9 @@ 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-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.1.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=
|
|
||||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||||
github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw=
|
github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw=
|
||||||
|
github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo=
|
||||||
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo=
|
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo=
|
||||||
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
|
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
|
||||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
@@ -163,20 +158,21 @@ github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/ad
|
|||||||
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo=
|
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo=
|
||||||
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA=
|
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA=
|
||||||
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw=
|
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw=
|
||||||
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y=
|
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1 h1:qnpSQwGEnkcRpTqNOIR6bJbR0gAorgP9CSALpRcKoAA=
|
||||||
|
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1/go.mod h1:lXGCsh6c22WGtjr+qGHj1otzZpV/1kwTMAqkwZsnWRU=
|
||||||
|
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.0 h1:FbSCl+KggFl+Ocym490i/EyXF4lPgLoUtcSWquBM0Rs=
|
||||||
|
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.0/go.mod h1:qOchhhIlmRcqk/O9uCo/puJlyo07YINaIqdZfZG3Jkc=
|
||||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho=
|
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho=
|
||||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo=
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 h1:5ZPtiqj0JL5oKWmcsq4VMaAW5ukBEgSGXEN89zeH1Jo=
|
||||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3/go.mod h1:ndYquD05frm2vACXE1nsccT4oJzjhw2arTS2cpUD1PI=
|
||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0 h1:TmHmbvxPmaegwhDubVz0lICL0J5Ka2vwTzhoePEXsGE=
|
|
||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0/go.mod h1:qztMSjm835F2bXf+5HKAPIS5qsmQDqZna/PgVt4rWtI=
|
|
||||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||||
github.com/ianlancetaylor/demangle v0.0.0-20240312041847-bd984b5ce465/go.mod h1:gx7rwoVhcfuVKG5uya9Hs3Sxj7EIvldVofAWIUtGouw=
|
github.com/ianlancetaylor/demangle v0.0.0-20240312041847-bd984b5ce465/go.mod h1:gx7rwoVhcfuVKG5uya9Hs3Sxj7EIvldVofAWIUtGouw=
|
||||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||||
github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4=
|
github.com/jonboulle/clockwork v0.5.0 h1:Hyh9A8u51kptdkR+cqRpT1EebBwTn1oK9YfGYbdFz6I=
|
||||||
github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc=
|
github.com/jonboulle/clockwork v0.5.0/go.mod h1:3mZlmanh0g2NDKO5TWZVJAfofYk64M7XN3SzBPjZF60=
|
||||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||||
github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA=
|
github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA=
|
||||||
@@ -212,9 +208,9 @@ github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJ
|
|||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
|
||||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||||
github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8=
|
||||||
|
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||||
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU=
|
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU=
|
||||||
@@ -246,6 +242,7 @@ github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7
|
|||||||
github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o=
|
github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o=
|
||||||
github.com/onsi/ginkgo/v2 v2.17.1/go.mod h1:llBI3WDLL9Z6taip6f33H76YcWtJv+7R3HigUjbIBOs=
|
github.com/onsi/ginkgo/v2 v2.17.1/go.mod h1:llBI3WDLL9Z6taip6f33H76YcWtJv+7R3HigUjbIBOs=
|
||||||
github.com/onsi/ginkgo/v2 v2.17.2/go.mod h1:nP2DPOQoNsQmsVyv5rDA8JkXQoCs6goXIvr/PRJ1eCc=
|
github.com/onsi/ginkgo/v2 v2.17.2/go.mod h1:nP2DPOQoNsQmsVyv5rDA8JkXQoCs6goXIvr/PRJ1eCc=
|
||||||
|
github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To=
|
||||||
github.com/onsi/ginkgo/v2 v2.21.0 h1:7rg/4f3rB88pb5obDgNZrNHrQ4e6WpjonchcpuBRnZM=
|
github.com/onsi/ginkgo/v2 v2.21.0 h1:7rg/4f3rB88pb5obDgNZrNHrQ4e6WpjonchcpuBRnZM=
|
||||||
github.com/onsi/ginkgo/v2 v2.21.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo=
|
github.com/onsi/ginkgo/v2 v2.21.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo=
|
||||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||||
@@ -274,6 +271,7 @@ github.com/onsi/gomega v1.35.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7y
|
|||||||
github.com/openshift/custom-resource-status v1.1.2 h1:C3DL44LEbvlbItfd8mT5jWrqPfHnSOQoQf/sypqA6A4=
|
github.com/openshift/custom-resource-status v1.1.2 h1:C3DL44LEbvlbItfd8mT5jWrqPfHnSOQoQf/sypqA6A4=
|
||||||
github.com/openshift/custom-resource-status v1.1.2/go.mod h1:DB/Mf2oTeiAmVVX1gN+NEqweonAPY0TKUwADizj8+ZA=
|
github.com/openshift/custom-resource-status v1.1.2/go.mod h1:DB/Mf2oTeiAmVVX1gN+NEqweonAPY0TKUwADizj8+ZA=
|
||||||
github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0=
|
github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0=
|
||||||
|
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
@@ -282,12 +280,14 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH
|
|||||||
github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q=
|
github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q=
|
||||||
github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0=
|
github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0=
|
||||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
|
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
|
||||||
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
|
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
|
||||||
github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io=
|
github.com/prometheus/common v0.64.0 h1:pdZeA+g617P7oGv1CzdTzyeShxAGrTBsolKNOLQPGO4=
|
||||||
github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I=
|
github.com/prometheus/common v0.64.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8=
|
||||||
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
|
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
|
||||||
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
|
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
|
||||||
|
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||||
|
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
||||||
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
|
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
|
||||||
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
|
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
|
||||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||||
@@ -297,10 +297,12 @@ github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVs
|
|||||||
github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js=
|
github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js=
|
||||||
github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0=
|
github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0=
|
||||||
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
|
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
|
||||||
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
|
github.com/spf13/cobra v1.10.0 h1:a5/WeUlSDCvV5a45ljW2ZFtV0bTDpkfSAj3uqB6Sc+0=
|
||||||
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
|
github.com/spf13/cobra v1.10.0/go.mod h1:9dhySC7dnTtEiqzmqfkLj47BslqLCUPMXjG2lj/NgoE=
|
||||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
|
||||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
|
github.com/spf13/pflag v1.0.8/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
|
github.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY=
|
||||||
|
github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
|
github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
|
||||||
github.com/stoewer/go-strcase v1.3.0 h1:g0eASXYtp+yvN9fK8sH94oCIk0fau9uV1/ZdJ0AVEzs=
|
github.com/stoewer/go-strcase v1.3.0 h1:g0eASXYtp+yvN9fK8sH94oCIk0fau9uV1/ZdJ0AVEzs=
|
||||||
github.com/stoewer/go-strcase v1.3.0/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo=
|
github.com/stoewer/go-strcase v1.3.0/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo=
|
||||||
@@ -317,6 +319,7 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
|||||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
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.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||||
|
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75 h1:6fotK7otjonDflCTK0BCfls4SPy3NcCVb5dqqmbRknE=
|
github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75 h1:6fotK7otjonDflCTK0BCfls4SPy3NcCVb5dqqmbRknE=
|
||||||
@@ -330,48 +333,53 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec
|
|||||||
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||||
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||||
go.etcd.io/bbolt v1.3.11 h1:yGEzV1wPz2yVCLsD8ZAiGHhHVlczyC9d1rP43/VCRJ0=
|
go.etcd.io/bbolt v1.4.2 h1:IrUHp260R8c+zYx/Tm8QZr04CX+qWS5PGfPdevhdm1I=
|
||||||
go.etcd.io/bbolt v1.3.11/go.mod h1:dksAq7YMXoljX0xu6VF5DMZGbhYYoLUalEiSySYAS4I=
|
go.etcd.io/bbolt v1.4.2/go.mod h1:Is8rSHO/b4f3XigBC0lL0+4FwAQv3HXEEIgFMuKHceM=
|
||||||
go.etcd.io/etcd/api/v3 v3.5.21 h1:A6O2/JDb3tvHhiIz3xf9nJ7REHvtEFJJ3veW3FbCnS8=
|
go.etcd.io/etcd/api/v3 v3.6.4 h1:7F6N7toCKcV72QmoUKa23yYLiiljMrT4xCeBL9BmXdo=
|
||||||
go.etcd.io/etcd/api/v3 v3.5.21/go.mod h1:c3aH5wcvXv/9dqIw2Y810LDXJfhSYdHQ0vxmP3CCHVY=
|
go.etcd.io/etcd/api/v3 v3.6.4/go.mod h1:eFhhvfR8Px1P6SEuLT600v+vrhdDTdcfMzmnxVXXSbk=
|
||||||
go.etcd.io/etcd/client/pkg/v3 v3.5.21 h1:lPBu71Y7osQmzlflM9OfeIV2JlmpBjqBNlLtcoBqUTc=
|
go.etcd.io/etcd/client/pkg/v3 v3.6.4 h1:9HBYrjppeOfFjBjaMTRxT3R7xT0GLK8EJMVC4xg6ok0=
|
||||||
go.etcd.io/etcd/client/pkg/v3 v3.5.21/go.mod h1:BgqT/IXPjK9NkeSDjbzwsHySX3yIle2+ndz28nVsjUs=
|
go.etcd.io/etcd/client/pkg/v3 v3.6.4/go.mod h1:sbdzr2cl3HzVmxNw//PH7aLGVtY4QySjQFuaCgcRFAI=
|
||||||
go.etcd.io/etcd/client/v2 v2.305.21 h1:eLiFfexc2mE+pTLz9WwnoEsX5JTTpLCYVivKkmVXIRA=
|
go.etcd.io/etcd/client/v3 v3.6.4 h1:YOMrCfMhRzY8NgtzUsHl8hC2EBSnuqbR3dh84Uryl7A=
|
||||||
go.etcd.io/etcd/client/v2 v2.305.21/go.mod h1:OKkn4hlYNf43hpjEM3Ke3aRdUkhSl8xjKjSf8eCq2J8=
|
go.etcd.io/etcd/client/v3 v3.6.4/go.mod h1:jaNNHCyg2FdALyKWnd7hxZXZxZANb0+KGY+YQaEMISo=
|
||||||
go.etcd.io/etcd/client/v3 v3.5.21 h1:T6b1Ow6fNjOLOtM0xSoKNQt1ASPCLWrF9XMHcH9pEyY=
|
go.etcd.io/etcd/pkg/v3 v3.6.4 h1:fy8bmXIec1Q35/jRZ0KOes8vuFxbvdN0aAFqmEfJZWA=
|
||||||
go.etcd.io/etcd/client/v3 v3.5.21/go.mod h1:mFYy67IOqmbRf/kRUvsHixzo3iG+1OF2W2+jVIQRAnU=
|
go.etcd.io/etcd/pkg/v3 v3.6.4/go.mod h1:kKcYWP8gHuBRcteyv6MXWSN0+bVMnfgqiHueIZnKMtE=
|
||||||
go.etcd.io/etcd/pkg/v3 v3.5.21 h1:jUItxeKyrDuVuWhdh0HtjUANwyuzcb7/FAeUfABmQsk=
|
go.etcd.io/etcd/server/v3 v3.6.4 h1:LsCA7CzjVt+8WGrdsnh6RhC0XqCsLkBly3ve5rTxMAU=
|
||||||
go.etcd.io/etcd/pkg/v3 v3.5.21/go.mod h1:wpZx8Egv1g4y+N7JAsqi2zoUiBIUWznLjqJbylDjWgU=
|
go.etcd.io/etcd/server/v3 v3.6.4/go.mod h1:aYCL/h43yiONOv0QIR82kH/2xZ7m+IWYjzRmyQfnCAg=
|
||||||
go.etcd.io/etcd/raft/v3 v3.5.21 h1:dOmE0mT55dIUsX77TKBLq+RgyumsQuYeiRQnW/ylugk=
|
go.etcd.io/raft/v3 v3.6.0 h1:5NtvbDVYpnfZWcIHgGRk9DyzkBIXOi8j+DDp1IcnUWQ=
|
||||||
go.etcd.io/etcd/raft/v3 v3.5.21/go.mod h1:fmcuY5R2SNkklU4+fKVBQi2biVp5vafMrWUEj4TJ4Cs=
|
go.etcd.io/raft/v3 v3.6.0/go.mod h1:nLvLevg6+xrVtHUmVaTcTz603gQPHfh7kUAwV6YpfGo=
|
||||||
go.etcd.io/etcd/server/v3 v3.5.21 h1:9w0/k12majtgarGmlMVuhwXRI2ob3/d1Ik3X5TKo0yU=
|
|
||||||
go.etcd.io/etcd/server/v3 v3.5.21/go.mod h1:G1mOzdwuzKT1VRL7SqRchli/qcFrtLBTAQ4lV20sXXo=
|
|
||||||
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
||||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
||||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.58.0 h1:PS8wXpbyaDJQ2VDHHncMe9Vct0Zn1fEjpsjrLxGJoSc=
|
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0 h1:x7wzEgXfnzJcHDwStJT+mxOz4etr2EcexjqhBvmoakw=
|
||||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.58.0/go.mod h1:HDBUsEjOuRC0EzKZ1bSaRGZWUBAzo+MhAcUUORSr4D0=
|
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0/go.mod h1:rg+RlpR5dKwaS95IyyZqj5Wd4E13lk/msnTS0Xl9lJM=
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0 h1:yd02MEjBdJkG3uabWP9apV+OuWRIXGDuJEUJbOHmCFU=
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0 h1:yd02MEjBdJkG3uabWP9apV+OuWRIXGDuJEUJbOHmCFU=
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0/go.mod h1:umTcuxiv1n/s/S6/c2AT/g2CQ7u5C59sHDNmfSwgz7Q=
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0/go.mod h1:umTcuxiv1n/s/S6/c2AT/g2CQ7u5C59sHDNmfSwgz7Q=
|
||||||
go.opentelemetry.io/otel v1.33.0 h1:/FerN9bax5LoK51X/sI0SVYrjSE0/yUL7DpxW4K3FWw=
|
go.opentelemetry.io/otel v1.36.0 h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg=
|
||||||
go.opentelemetry.io/otel v1.33.0/go.mod h1:SUUkR6csvUQl+yjReHu5uM3EtVV7MBm5FHKRlNx4I8I=
|
go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.33.0 h1:Vh5HayB/0HHfOQA7Ctx69E/Y/DcQSMPpKANYVMQ7fBA=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.36.0 h1:dNzwXjZKpMpE2JhmO+9HsPl42NIXFIFSUSSs0fiqra0=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.33.0/go.mod h1:cpgtDBaqD/6ok/UG0jT15/uKjAY8mRA53diogHBg3UI=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.36.0/go.mod h1:90PoxvaEB5n6AOdZvi+yWJQoE95U8Dhhw2bSyRqnTD0=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.33.0 h1:5pojmb1U1AogINhN3SurB+zm/nIcusopeBNp42f45QM=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.36.0 h1:JgtbA0xkWHnTmYk7YusopJFX6uleBmAuZ8n05NEh8nQ=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.33.0/go.mod h1:57gTHJSE5S1tqg+EKsLPlTWhpHMsWlVmer+LA926XiA=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.36.0/go.mod h1:179AK5aar5R3eS9FucPy6rggvU0g52cvKId8pv4+v0c=
|
||||||
go.opentelemetry.io/otel/metric v1.33.0 h1:r+JOocAyeRVXD8lZpjdQjzMadVZp2M4WmQ+5WtEnklQ=
|
go.opentelemetry.io/otel/metric v1.36.0 h1:MoWPKVhQvJ+eeXWHFBOPoBOi20jh6Iq2CcCREuTYufE=
|
||||||
go.opentelemetry.io/otel/metric v1.33.0/go.mod h1:L9+Fyctbp6HFTddIxClbQkjtubW6O9QS3Ann/M82u6M=
|
go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs=
|
||||||
go.opentelemetry.io/otel/sdk v1.33.0 h1:iax7M131HuAm9QkZotNHEfstof92xM+N8sr3uHXc2IM=
|
go.opentelemetry.io/otel/sdk v1.36.0 h1:b6SYIuLRs88ztox4EyrvRti80uXIFy+Sqzoh9kFULbs=
|
||||||
go.opentelemetry.io/otel/sdk v1.33.0/go.mod h1:A1Q5oi7/9XaMlIWzPSxLRWOI8nG3FnzHJNbiENQuihM=
|
go.opentelemetry.io/otel/sdk v1.36.0/go.mod h1:+lC+mTgD+MUWfjJubi2vvXWcVxyr9rmlshZni72pXeY=
|
||||||
go.opentelemetry.io/otel/trace v1.33.0 h1:cCJuF7LRjUFso9LPnEAHJDB2pqzp+hbO8eu1qqW2d/s=
|
go.opentelemetry.io/otel/sdk/metric v1.34.0 h1:5CeK9ujjbFVL5c1PhLuStg1wxA7vQv7ce1EK0Gyvahk=
|
||||||
go.opentelemetry.io/otel/trace v1.33.0/go.mod h1:uIcdVUZMpTAmz0tI1z04GoVSezK37CbGV4fr1f2nBck=
|
go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w=
|
||||||
go.opentelemetry.io/proto/otlp v1.4.0 h1:TA9WRvW6zMwP+Ssb6fLoUIuirti1gGbP28GcKG1jgeg=
|
go.opentelemetry.io/otel/trace v1.36.0 h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKrsNd4w=
|
||||||
go.opentelemetry.io/proto/otlp v1.4.0/go.mod h1:PPBWZIP98o2ElSqI35IHfu7hIhSwvc5N38Jw8pXuGFY=
|
go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA=
|
||||||
|
go.opentelemetry.io/proto/otlp v1.6.0 h1:jQjP+AQyTf+Fe7OKj/MfkDrmK4MNVtw2NpXsf9fefDI=
|
||||||
|
go.opentelemetry.io/proto/otlp v1.6.0/go.mod h1:cicgGehlFuNdgZkcALOCh3VE6K/u2tAjzlRhDwmVpZc=
|
||||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||||
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
|
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
|
||||||
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
||||||
|
go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI=
|
||||||
|
go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU=
|
||||||
|
go.yaml.in/yaml/v3 v3.0.3/go.mod h1:tBHosrYAkRZjRAOREWbDnBXUf08JOwYq++0QNwQiWzI=
|
||||||
|
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
|
||||||
|
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
|
||||||
golang.org/dl v0.0.0-20190829154251-82a15e2f2ead/go.mod h1:IUMfjQLJQd4UTqG1Z90tenwKoCX93Gn3MAQJMOSBsDQ=
|
golang.org/dl v0.0.0-20190829154251-82a15e2f2ead/go.mod h1:IUMfjQLJQd4UTqG1Z90tenwKoCX93Gn3MAQJMOSBsDQ=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
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-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
@@ -387,8 +395,10 @@ golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1m
|
|||||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||||
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
|
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
|
||||||
golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
|
golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
|
||||||
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
|
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||||
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
|
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
|
||||||
|
golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8=
|
||||||
|
golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
|
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
|
||||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
|
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
|
||||||
@@ -410,6 +420,7 @@ golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
|||||||
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
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.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
|
golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0=
|
golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0=
|
||||||
golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
|
golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
|
||||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
@@ -450,11 +461,13 @@ golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
|
|||||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||||
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||||
golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
|
golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
|
||||||
golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
|
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||||
golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
|
golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
|
||||||
|
golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
|
||||||
|
golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.27.0 h1:da9Vo7/tDv5RH/7nZDz1eMGS/q1Vv1N/7FCrBhI9I3M=
|
golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
|
||||||
golang.org/x/oauth2 v0.27.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8=
|
golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
@@ -468,8 +481,9 @@ golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
|||||||
golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
|
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ=
|
||||||
|
golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
@@ -513,9 +527,12 @@ golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
|||||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
|
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
|
||||||
|
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||||
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
|
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
|
||||||
|
golang.org/x/telemetry v0.0.0-20240521205824-bda55230c457/go.mod h1:pRgIJT+bRLFKnoM1ldnzKoxTIn14Yxz928LQRYYgIN0=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
@@ -534,8 +551,10 @@ golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
|
|||||||
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||||
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
|
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
|
||||||
golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk=
|
golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk=
|
||||||
golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y=
|
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||||
golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g=
|
golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk=
|
||||||
|
golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg=
|
||||||
|
golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
@@ -551,8 +570,10 @@ golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
|||||||
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
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.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
|
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
|
golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||||
|
golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=
|
||||||
|
golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
|
||||||
golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY=
|
golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY=
|
||||||
golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
@@ -580,6 +601,9 @@ golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58
|
|||||||
golang.org/x/tools v0.16.1/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0=
|
golang.org/x/tools v0.16.1/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0=
|
||||||
golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps=
|
golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps=
|
||||||
golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg=
|
golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg=
|
||||||
|
golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||||
|
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||||
|
golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
|
||||||
golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ=
|
golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ=
|
||||||
golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=
|
golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
@@ -592,17 +616,15 @@ google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoA
|
|||||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||||
google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80 h1:KAeGQVN3M9nD0/bQXnr/ClcEMJ968gUXJQ9pwfSynuQ=
|
google.golang.org/genproto/googleapis/api v0.0.0-20250519155744-55703ea1f237 h1:Kog3KlB4xevJlAcbbbzPfRG0+X9fdoGM+UBRKVz6Wr0=
|
||||||
google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80/go.mod h1:cc8bqMqtv9gMOr0zHg2Vzff5ULhhL2IXP4sbcn32Dro=
|
google.golang.org/genproto/googleapis/api v0.0.0-20250519155744-55703ea1f237/go.mod h1:ezi0AVyMKDWy5xAncvjLWH7UcLBB5n7y2fQ8MzjJcto=
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576 h1:CkkIfIt50+lT6NHAVoRYEyAvQGFM7xEwXUUywFvEb3Q=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20250519155744-55703ea1f237 h1:cJfm9zPbe1e873mHJzmQ1nwVEeRDU/T1wXDK2kUSU34=
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576/go.mod h1:1R3kvZ1dtP3+4p4d3G8uJ8rFk/fWlScl38vanWACI08=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20250519155744-55703ea1f237/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576 h1:8ZmaLZE4XWrtU3MyClkYqqtl6Oegr3235h7jxsDyqCY=
|
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU=
|
|
||||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||||
google.golang.org/grpc v1.68.1 h1:oI5oTa11+ng8r8XMMN7jAOmWfPZWbYpCFaMUTACxkM0=
|
google.golang.org/grpc v1.72.2 h1:TdbGzwb82ty4OusHWepvFWGLgIbNo1/SUynEN0ssqv8=
|
||||||
google.golang.org/grpc v1.68.1/go.mod h1:+q1XYFJjShcqn0QZHvCyeR4CXPA+llXIeUIfIe00waw=
|
google.golang.org/grpc v1.72.2/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM=
|
||||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
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-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||||
@@ -614,11 +636,11 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD
|
|||||||
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
||||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
|
||||||
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||||
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||||
google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
|
google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||||
google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
|
||||||
|
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
@@ -641,53 +663,50 @@ gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
|||||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
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=
|
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
k8s.io/api v0.23.3/go.mod h1:w258XdGyvCmnBj/vGzQMj6kzdufJZVUwEM1U2fRJwSQ=
|
k8s.io/api v0.23.3/go.mod h1:w258XdGyvCmnBj/vGzQMj6kzdufJZVUwEM1U2fRJwSQ=
|
||||||
k8s.io/api v0.33.0 h1:yTgZVn1XEe6opVpP1FylmNrIFWuDqe2H0V8CT5gxfIU=
|
k8s.io/api v0.34.0 h1:L+JtP2wDbEYPUeNGbeSa/5GwFtIA662EmT2YSLOkAVE=
|
||||||
k8s.io/api v0.33.0/go.mod h1:CTO61ECK/KU7haa3qq8sarQ0biLq2ju405IZAd9zsiM=
|
k8s.io/api v0.34.0/go.mod h1:YzgkIzOOlhl9uwWCZNqpw6RJy9L2FK4dlJeayUoydug=
|
||||||
k8s.io/apiextensions-apiserver v0.30.0 h1:jcZFKMqnICJfRxTgnC4E+Hpcq8UEhT8B2lhBcQ+6uAs=
|
k8s.io/apiextensions-apiserver v0.30.0 h1:jcZFKMqnICJfRxTgnC4E+Hpcq8UEhT8B2lhBcQ+6uAs=
|
||||||
k8s.io/apiextensions-apiserver v0.30.0/go.mod h1:N9ogQFGcrbWqAY9p2mUAL5mGxsLqwgtUce127VtRX5Y=
|
k8s.io/apiextensions-apiserver v0.30.0/go.mod h1:N9ogQFGcrbWqAY9p2mUAL5mGxsLqwgtUce127VtRX5Y=
|
||||||
k8s.io/apimachinery v0.23.3/go.mod h1:BEuFMMBaIbcOqVIJqNZJXGFTP4W6AycEpb5+m/97hrM=
|
k8s.io/apimachinery v0.23.3/go.mod h1:BEuFMMBaIbcOqVIJqNZJXGFTP4W6AycEpb5+m/97hrM=
|
||||||
k8s.io/apimachinery v0.33.0 h1:1a6kHrJxb2hs4t8EE5wuR/WxKDwGN1FKH3JvDtA0CIQ=
|
k8s.io/apimachinery v0.34.0 h1:eR1WO5fo0HyoQZt1wdISpFDffnWOvFLOOeJ7MgIv4z0=
|
||||||
k8s.io/apimachinery v0.33.0/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM=
|
k8s.io/apimachinery v0.34.0/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw=
|
||||||
k8s.io/apiserver v0.33.0 h1:QqcM6c+qEEjkOODHppFXRiw/cE2zP85704YrQ9YaBbc=
|
k8s.io/apiserver v0.34.0 h1:Z51fw1iGMqN7uJ1kEaynf2Aec1Y774PqU+FVWCFV3Jg=
|
||||||
k8s.io/apiserver v0.33.0/go.mod h1:EixYOit0YTxt8zrO2kBU7ixAtxFce9gKGq367nFmqI8=
|
k8s.io/apiserver v0.34.0/go.mod h1:52ti5YhxAvewmmpVRqlASvaqxt0gKJxvCeW7ZrwgazQ=
|
||||||
k8s.io/client-go v0.33.0 h1:UASR0sAYVUzs2kYuKn/ZakZlcs2bEHaizrrHUZg0G98=
|
k8s.io/client-go v0.34.0 h1:YoWv5r7bsBfb0Hs2jh8SOvFbKzzxyNo0nSb0zC19KZo=
|
||||||
k8s.io/client-go v0.33.0/go.mod h1:kGkd+l/gNGg8GYWAPr0xF1rRKvVWvzh9vmZAMXtaKOg=
|
k8s.io/client-go v0.34.0/go.mod h1:ozgMnEKXkRjeMvBZdV1AijMHLTh3pbACPvK7zFR+QQY=
|
||||||
k8s.io/code-generator v0.23.3/go.mod h1:S0Q1JVA+kSzTI1oUvbKAxZY/DYbA/ZUb4Uknog12ETk=
|
k8s.io/code-generator v0.23.3/go.mod h1:S0Q1JVA+kSzTI1oUvbKAxZY/DYbA/ZUb4Uknog12ETk=
|
||||||
k8s.io/code-generator v0.33.0 h1:B212FVl6EFqNmlgdOZYWNi77yBv+ed3QgQsMR8YQCw4=
|
k8s.io/code-generator v0.34.0 h1:Ze2i1QsvUprIlX3oHiGv09BFQRLCz+StA8qKwwFzees=
|
||||||
k8s.io/code-generator v0.33.0/go.mod h1:KnJRokGxjvbBQkSJkbVuBbu6z4B0rC7ynkpY5Aw6m9o=
|
k8s.io/code-generator v0.34.0/go.mod h1:Py2+4w2HXItL8CGhks8uI/wS3Y93wPKO/9mBQUYNua0=
|
||||||
k8s.io/component-base v0.33.0 h1:Ot4PyJI+0JAD9covDhwLp9UNkUja209OzsJ4FzScBNk=
|
k8s.io/component-base v0.34.0 h1:bS8Ua3zlJzapklsB1dZgjEJuJEeHjj8yTu1gxE2zQX8=
|
||||||
k8s.io/component-base v0.33.0/go.mod h1:aXYZLbw3kihdkOPMDhWbjGCO6sg+luw554KP51t8qCU=
|
k8s.io/component-base v0.34.0/go.mod h1:RSCqUdvIjjrEm81epPcjQ/DS+49fADvGSCkIP3IC6vg=
|
||||||
k8s.io/component-helpers v0.33.0 h1:0AdW0A0mIgljLgtG0hJDdJl52PPqTrtMgOgtm/9i/Ys=
|
k8s.io/component-helpers v0.34.0 h1:5T7P9XGMoUy1JDNKzHf0p/upYbeUf8ZaSf9jbx0QlIo=
|
||||||
k8s.io/component-helpers v0.33.0/go.mod h1:9SRiXfLldPw9lEEuSsapMtvT8j/h1JyFFapbtybwKvU=
|
k8s.io/component-helpers v0.34.0/go.mod h1:kaOyl5tdtnymriYcVZg4uwDBe2d1wlIpXyDkt6sVnt4=
|
||||||
k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
|
k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
|
||||||
k8s.io/gengo v0.0.0-20211129171323-c02415ce4185/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
|
k8s.io/gengo v0.0.0-20211129171323-c02415ce4185/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
|
||||||
k8s.io/gengo/v2 v2.0.0-20240228010128-51d4e06bde70/go.mod h1:VH3AT8AaQOqiGjMF9p0/IM1Dj+82ZwjfxUP1IxaHE+8=
|
k8s.io/gengo/v2 v2.0.0-20250604051438-85fd79dbfd9f h1:SLb+kxmzfA87x4E4brQzB33VBbT2+x7Zq9ROIHmGn9Q=
|
||||||
k8s.io/gengo/v2 v2.0.0-20250207200755-1244d31929d7 h1:2OX19X59HxDprNCVrWi6jb7LW1PoqTlYqEq5H2oetog=
|
k8s.io/gengo/v2 v2.0.0-20250604051438-85fd79dbfd9f/go.mod h1:EJykeLsmFC60UQbYJezXkEsG2FLrt0GPNkU5iK5GWxU=
|
||||||
k8s.io/gengo/v2 v2.0.0-20250207200755-1244d31929d7/go.mod h1:EJykeLsmFC60UQbYJezXkEsG2FLrt0GPNkU5iK5GWxU=
|
|
||||||
k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
|
k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
|
||||||
k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
|
k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
|
||||||
k8s.io/klog/v2 v2.30.0/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
|
k8s.io/klog/v2 v2.30.0/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
|
||||||
k8s.io/klog/v2 v2.40.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
|
k8s.io/klog/v2 v2.40.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
|
||||||
k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
|
k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
|
||||||
k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
|
|
||||||
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
|
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
|
||||||
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
|
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
|
||||||
k8s.io/kms v0.33.0 h1:fhQSW/vyaWDhMp0vDuO/sLg2RlGZf4F77beSXcB4/eE=
|
k8s.io/kms v0.34.0 h1:u+/rcxQ3Jr7gC9AY5nXuEnBcGEB7ZOIJ9cdLdyHyEjQ=
|
||||||
k8s.io/kms v0.33.0/go.mod h1:C1I8mjFFBNzfUZXYt9FZVJ8MJl7ynFbGgZFbBzkBJ3E=
|
k8s.io/kms v0.34.0/go.mod h1:s1CFkLG7w9eaTYvctOxosx88fl4spqmixnNpys0JAtM=
|
||||||
k8s.io/kube-openapi v0.0.0-20240430033511-f0e62f92d13f h1:0LQagt0gDpKqvIkAMPaRGcXawNMouPECM1+F9BVxEaM=
|
k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b h1:MloQ9/bdJyIu9lb1PzujOPolHyvO06MXG5TUIj2mNAA=
|
||||||
k8s.io/kube-openapi v0.0.0-20240430033511-f0e62f92d13f/go.mod h1:S9tOR0FxgyusSNR+MboCuiDpVWkAifZvaYI1Q2ubgro=
|
k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b/go.mod h1:UZ2yyWbFTpuhSbFhv24aGNOdoRdJZgsIObGBUaYVsts=
|
||||||
k8s.io/metrics v0.33.0 h1:sKe5sC9qb1RakMhs8LWYNuN2ne6OTCWexj8Jos3rO2Y=
|
k8s.io/metrics v0.34.0 h1:nYSfG2+tnL6/MRC2I+sGHjtNEGoEoM/KktgGOoQFwws=
|
||||||
k8s.io/metrics v0.33.0/go.mod h1:XewckTFXmE2AJiP7PT3EXaY7hi7bler3t2ZLyOdQYzU=
|
k8s.io/metrics v0.34.0/go.mod h1:KCuXmotE0v4AvoARKUP8NC4lUnbK/Du1mluGdor5h4M=
|
||||||
k8s.io/utils v0.0.0-20211116205334-6203023598ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
k8s.io/utils v0.0.0-20211116205334-6203023598ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||||
k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
||||||
k8s.io/utils v0.0.0-20250321185631-1f6e0b77f77e h1:KqK5c/ghOm8xkHYhlodbp6i6+r+ChV2vuAuVRdFbLro=
|
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 h1:hwvWFiBzdWw1FhfY1FooPn3kzWuJ8tmbZBHi4zVsl1Y=
|
||||||
k8s.io/utils v0.0.0-20250321185631-1f6e0b77f77e/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
||||||
kubevirt.io/api v1.3.0 h1:9sGElMmnRU50pGED+MPPD2OwQl4S5lvjCUjm+t0mI90=
|
kubevirt.io/api v1.3.0 h1:9sGElMmnRU50pGED+MPPD2OwQl4S5lvjCUjm+t0mI90=
|
||||||
kubevirt.io/api v1.3.0/go.mod h1:e6LkElYZZm8NcP2gKlFVHZS9pgNhIARHIjSBSfeiP1s=
|
kubevirt.io/api v1.3.0/go.mod h1:e6LkElYZZm8NcP2gKlFVHZS9pgNhIARHIjSBSfeiP1s=
|
||||||
kubevirt.io/client-go v1.3.0 h1:/HKn4exzwsctEVTwVtEFaeT9D2v4TgWr2SmxITVEZ/4=
|
kubevirt.io/client-go v1.3.0 h1:/HKn4exzwsctEVTwVtEFaeT9D2v4TgWr2SmxITVEZ/4=
|
||||||
@@ -700,18 +719,19 @@ sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 h1:jpcvIRr3GLoUo
|
|||||||
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw=
|
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw=
|
||||||
sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6/go.mod h1:p4QtZmO4uMYipTQNzagwnNoseA6OxSUutVw05NhYDRs=
|
sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6/go.mod h1:p4QtZmO4uMYipTQNzagwnNoseA6OxSUutVw05NhYDRs=
|
||||||
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
|
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
|
||||||
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 h1:/Rv+M11QRah1itp8VhT6HoVx1Ray9eB4DBr+K+/sCJ8=
|
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 h1:gBQPwqORJ8d8/YNZWEjoZs7npUVDpVXUUOFfW6CgAqE=
|
||||||
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3/go.mod h1:18nIHnGi6636UCz6m8i4DhaJ65T6EruyzmoQqI2BVDo=
|
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg=
|
||||||
sigs.k8s.io/mdtoc v1.1.0 h1:q3YtqYzmC2e0hgLXRIOm7/QLuPux1CX3ZHCwlbABxZo=
|
sigs.k8s.io/mdtoc v1.1.0 h1:q3YtqYzmC2e0hgLXRIOm7/QLuPux1CX3ZHCwlbABxZo=
|
||||||
sigs.k8s.io/mdtoc v1.1.0/go.mod h1:QZLVEdHH2iNIR4uHAZyvFRtjloHgVItk8lo/mzCtq3w=
|
sigs.k8s.io/mdtoc v1.1.0/go.mod h1:QZLVEdHH2iNIR4uHAZyvFRtjloHgVItk8lo/mzCtq3w=
|
||||||
sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
|
sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
|
||||||
sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU=
|
sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU=
|
||||||
sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
|
sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
|
||||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.1/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4=
|
sigs.k8s.io/structured-merge-diff/v4 v4.2.1/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4=
|
||||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E=
|
sigs.k8s.io/structured-merge-diff/v6 v6.2.0/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE=
|
||||||
sigs.k8s.io/structured-merge-diff/v4 v4.6.0 h1:IUA9nvMmnKWcj5jl84xn+T5MnlZKThmUW1TdblaLVAc=
|
sigs.k8s.io/structured-merge-diff/v6 v6.3.0 h1:jTijUJbW353oVOd9oTlifJqOGEkUw2jB/fXCbTiQEco=
|
||||||
sigs.k8s.io/structured-merge-diff/v4 v4.6.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps=
|
sigs.k8s.io/structured-merge-diff/v6 v6.3.0/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE=
|
||||||
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
|
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
|
||||||
sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
|
sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
|
||||||
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
|
|
||||||
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
|
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
|
||||||
|
sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs=
|
||||||
|
sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4=
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ func TestValidateRemoveFailedPodsArgs(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
errInfo: fmt.Errorf(`failed to get label selectors from strategy's params: [key: Invalid value: "": name part must be non-empty; name part must consist of alphanumeric characters, '-', '_' or '.', and must start and end with an alphanumeric character (e.g. 'MyName', or 'my.name', or '123-abc', regex used for validation is '([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]'), values: Invalid value: []string(nil): for 'in', 'notin' operators, values set can't be empty]`),
|
errInfo: fmt.Errorf(`failed to get label selectors from strategy's params: [key: Invalid value: "": name part must be non-empty; name part must consist of alphanumeric characters, '-', '_' or '.', and must start and end with an alphanumeric character (e.g. 'MyName', or 'my.name', or '123-abc', regex used for validation is '([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]'), values: Invalid value: null: for 'in', 'notin' operators, values set can't be empty]`),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ func TestValidateRemovePodsViolatingInterPodAntiAffinityArgs(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
errInfo: fmt.Errorf(`failed to get label selectors from strategy's params: [key: Invalid value: "": name part must be non-empty; name part must consist of alphanumeric characters, '-', '_' or '.', and must start and end with an alphanumeric character (e.g. 'MyName', or 'my.name', or '123-abc', regex used for validation is '([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]'), values: Invalid value: []string(nil): for 'in', 'notin' operators, values set can't be empty]`),
|
errInfo: fmt.Errorf(`failed to get label selectors from strategy's params: [key: Invalid value: "": name part must be non-empty; name part must consist of alphanumeric characters, '-', '_' or '.', and must start and end with an alphanumeric character (e.g. 'MyName', or 'my.name', or '123-abc', regex used for validation is '([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]'), values: Invalid value: null: for 'in', 'notin' operators, values set can't be empty]`),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ func TestValidateRemovePodsViolatingNodeTaintsArgs(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
errInfo: fmt.Errorf(`failed to get label selectors from strategy's params: [key: Invalid value: "": name part must be non-empty; name part must consist of alphanumeric characters, '-', '_' or '.', and must start and end with an alphanumeric character (e.g. 'MyName', or 'my.name', or '123-abc', regex used for validation is '([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]'), values: Invalid value: []string(nil): for 'in', 'notin' operators, values set can't be empty]`),
|
errInfo: fmt.Errorf(`failed to get label selectors from strategy's params: [key: Invalid value: "": name part must be non-empty; name part must consist of alphanumeric characters, '-', '_' or '.', and must start and end with an alphanumeric character (e.g. 'MyName', or 'my.name', or '123-abc', regex used for validation is '([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]'), values: Invalid value: null: for 'in', 'notin' operators, values set can't be empty]`),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
description: "valid taint filters, no errors",
|
description: "valid taint filters, no errors",
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ func TestValidateRemovePodsViolatingTopologySpreadConstraintArgs(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
errInfo: fmt.Errorf(`failed to get label selectors from strategy's params: [key: Invalid value: "": name part must be non-empty; name part must consist of alphanumeric characters, '-', '_' or '.', and must start and end with an alphanumeric character (e.g. 'MyName', or 'my.name', or '123-abc', regex used for validation is '([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]'), values: Invalid value: []string(nil): for 'in', 'notin' operators, values set can't be empty]`),
|
errInfo: fmt.Errorf(`failed to get label selectors from strategy's params: [key: Invalid value: "": name part must be non-empty; name part must consist of alphanumeric characters, '-', '_' or '.', and must start and end with an alphanumeric character (e.g. 'MyName', or 'my.name', or '123-abc', regex used for validation is '([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]'), values: Invalid value: null: for 'in', 'notin' operators, values set can't be empty]`),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
description: "valid constraints args, no errors",
|
description: "valid constraints args, no errors",
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ echo "DESCHEDULER_IMAGE: ${DESCHEDULER_IMAGE}"
|
|||||||
|
|
||||||
# This just runs e2e tests.
|
# This just runs e2e tests.
|
||||||
if [ -n "$KIND_E2E" ]; then
|
if [ -n "$KIND_E2E" ]; then
|
||||||
K8S_VERSION=${KUBERNETES_VERSION:-v1.33.0}
|
K8S_VERSION=${KUBERNETES_VERSION:-v1.34.0}
|
||||||
if [ -z "${SKIP_KUBECTL_INSTALL}" ]; then
|
if [ -z "${SKIP_KUBECTL_INSTALL}" ]; then
|
||||||
curl -Lo kubectl https://dl.k8s.io/release/${K8S_VERSION}/bin/linux/amd64/kubectl && chmod +x kubectl && mv kubectl /usr/local/bin/
|
curl -Lo kubectl https://dl.k8s.io/release/${K8S_VERSION}/bin/linux/amd64/kubectl && chmod +x kubectl && mv kubectl /usr/local/bin/
|
||||||
fi
|
fi
|
||||||
|
|||||||
2
vendor/cel.dev/expr/.bazelversion
vendored
2
vendor/cel.dev/expr/.bazelversion
vendored
@@ -1,2 +1,2 @@
|
|||||||
7.0.1
|
7.3.2
|
||||||
# Keep this pinned version in parity with cel-go
|
# Keep this pinned version in parity with cel-go
|
||||||
|
|||||||
34
vendor/cel.dev/expr/MODULE.bazel
vendored
34
vendor/cel.dev/expr/MODULE.bazel
vendored
@@ -8,26 +8,38 @@ bazel_dep(
|
|||||||
)
|
)
|
||||||
bazel_dep(
|
bazel_dep(
|
||||||
name = "gazelle",
|
name = "gazelle",
|
||||||
version = "0.36.0",
|
version = "0.39.1",
|
||||||
repo_name = "bazel_gazelle",
|
repo_name = "bazel_gazelle",
|
||||||
)
|
)
|
||||||
bazel_dep(
|
bazel_dep(
|
||||||
name = "googleapis",
|
name = "googleapis",
|
||||||
version = "0.0.0-20240819-fe8ba054a",
|
version = "0.0.0-20241220-5e258e33.bcr.1",
|
||||||
repo_name = "com_google_googleapis",
|
repo_name = "com_google_googleapis",
|
||||||
)
|
)
|
||||||
|
bazel_dep(
|
||||||
|
name = "googleapis-cc",
|
||||||
|
version = "1.0.0",
|
||||||
|
)
|
||||||
|
bazel_dep(
|
||||||
|
name = "googleapis-java",
|
||||||
|
version = "1.0.0",
|
||||||
|
)
|
||||||
|
bazel_dep(
|
||||||
|
name = "googleapis-go",
|
||||||
|
version = "1.0.0",
|
||||||
|
)
|
||||||
bazel_dep(
|
bazel_dep(
|
||||||
name = "protobuf",
|
name = "protobuf",
|
||||||
version = "26.0",
|
version = "27.0",
|
||||||
repo_name = "com_google_protobuf",
|
repo_name = "com_google_protobuf",
|
||||||
)
|
)
|
||||||
bazel_dep(
|
bazel_dep(
|
||||||
name = "rules_cc",
|
name = "rules_cc",
|
||||||
version = "0.0.9",
|
version = "0.0.17",
|
||||||
)
|
)
|
||||||
bazel_dep(
|
bazel_dep(
|
||||||
name = "rules_go",
|
name = "rules_go",
|
||||||
version = "0.49.0",
|
version = "0.53.0",
|
||||||
repo_name = "io_bazel_rules_go",
|
repo_name = "io_bazel_rules_go",
|
||||||
)
|
)
|
||||||
bazel_dep(
|
bazel_dep(
|
||||||
@@ -36,7 +48,7 @@ bazel_dep(
|
|||||||
)
|
)
|
||||||
bazel_dep(
|
bazel_dep(
|
||||||
name = "rules_proto",
|
name = "rules_proto",
|
||||||
version = "6.0.0",
|
version = "7.0.2",
|
||||||
)
|
)
|
||||||
bazel_dep(
|
bazel_dep(
|
||||||
name = "rules_python",
|
name = "rules_python",
|
||||||
@@ -50,16 +62,8 @@ python.toolchain(
|
|||||||
python_version = "3.11",
|
python_version = "3.11",
|
||||||
)
|
)
|
||||||
|
|
||||||
switched_rules = use_extension("@com_google_googleapis//:extensions.bzl", "switched_rules")
|
|
||||||
switched_rules.use_languages(
|
|
||||||
cc = True,
|
|
||||||
go = True,
|
|
||||||
java = True,
|
|
||||||
)
|
|
||||||
use_repo(switched_rules, "com_google_googleapis_imports")
|
|
||||||
|
|
||||||
go_sdk = use_extension("@io_bazel_rules_go//go:extensions.bzl", "go_sdk")
|
go_sdk = use_extension("@io_bazel_rules_go//go:extensions.bzl", "go_sdk")
|
||||||
go_sdk.download(version = "1.21.1")
|
go_sdk.download(version = "1.22.0")
|
||||||
|
|
||||||
go_deps = use_extension("@bazel_gazelle//:extensions.bzl", "go_deps")
|
go_deps = use_extension("@bazel_gazelle//:extensions.bzl", "go_deps")
|
||||||
go_deps.from_file(go_mod = "//:go.mod")
|
go_deps.from_file(go_mod = "//:go.mod")
|
||||||
|
|||||||
2
vendor/cel.dev/expr/README.md
vendored
2
vendor/cel.dev/expr/README.md
vendored
@@ -69,5 +69,3 @@ For more detail, see:
|
|||||||
* [Language Definition](doc/langdef.md)
|
* [Language Definition](doc/langdef.md)
|
||||||
|
|
||||||
Released under the [Apache License](LICENSE).
|
Released under the [Apache License](LICENSE).
|
||||||
|
|
||||||
Disclaimer: This is not an official Google product.
|
|
||||||
|
|||||||
2
vendor/cel.dev/expr/cloudbuild.yaml
vendored
2
vendor/cel.dev/expr/cloudbuild.yaml
vendored
@@ -1,5 +1,5 @@
|
|||||||
steps:
|
steps:
|
||||||
- name: 'gcr.io/cloud-builders/bazel:7.0.1'
|
- name: 'gcr.io/cloud-builders/bazel:7.3.2'
|
||||||
entrypoint: bazel
|
entrypoint: bazel
|
||||||
args: ['build', '...']
|
args: ['build', '...']
|
||||||
id: bazel-build
|
id: bazel-build
|
||||||
|
|||||||
361
vendor/cel.dev/expr/eval.pb.go
generated
vendored
361
vendor/cel.dev/expr/eval.pb.go
generated
vendored
@@ -1,15 +1,15 @@
|
|||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// protoc-gen-go v1.28.1
|
// protoc-gen-go v1.36.3
|
||||||
// protoc v3.21.5
|
// protoc v5.27.1
|
||||||
// source: cel/expr/eval.proto
|
// source: cel/expr/eval.proto
|
||||||
|
|
||||||
package expr
|
package expr
|
||||||
|
|
||||||
import (
|
import (
|
||||||
status "google.golang.org/genproto/googleapis/rpc/status"
|
|
||||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||||
|
anypb "google.golang.org/protobuf/types/known/anypb"
|
||||||
reflect "reflect"
|
reflect "reflect"
|
||||||
sync "sync"
|
sync "sync"
|
||||||
)
|
)
|
||||||
@@ -22,21 +22,18 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type EvalState struct {
|
type EvalState struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
sizeCache protoimpl.SizeCache
|
Values []*ExprValue `protobuf:"bytes,1,rep,name=values,proto3" json:"values,omitempty"`
|
||||||
|
Results []*EvalState_Result `protobuf:"bytes,3,rep,name=results,proto3" json:"results,omitempty"`
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
Values []*ExprValue `protobuf:"bytes,1,rep,name=values,proto3" json:"values,omitempty"`
|
|
||||||
Results []*EvalState_Result `protobuf:"bytes,3,rep,name=results,proto3" json:"results,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *EvalState) Reset() {
|
func (x *EvalState) Reset() {
|
||||||
*x = EvalState{}
|
*x = EvalState{}
|
||||||
if protoimpl.UnsafeEnabled {
|
mi := &file_cel_expr_eval_proto_msgTypes[0]
|
||||||
mi := &file_cel_expr_eval_proto_msgTypes[0]
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms.StoreMessageInfo(mi)
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *EvalState) String() string {
|
func (x *EvalState) String() string {
|
||||||
@@ -47,7 +44,7 @@ func (*EvalState) ProtoMessage() {}
|
|||||||
|
|
||||||
func (x *EvalState) ProtoReflect() protoreflect.Message {
|
func (x *EvalState) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_cel_expr_eval_proto_msgTypes[0]
|
mi := &file_cel_expr_eval_proto_msgTypes[0]
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
if x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
@@ -77,25 +74,22 @@ func (x *EvalState) GetResults() []*EvalState_Result {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ExprValue struct {
|
type ExprValue struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
sizeCache protoimpl.SizeCache
|
// Types that are valid to be assigned to Kind:
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
|
|
||||||
// Types that are assignable to Kind:
|
|
||||||
//
|
//
|
||||||
// *ExprValue_Value
|
// *ExprValue_Value
|
||||||
// *ExprValue_Error
|
// *ExprValue_Error
|
||||||
// *ExprValue_Unknown
|
// *ExprValue_Unknown
|
||||||
Kind isExprValue_Kind `protobuf_oneof:"kind"`
|
Kind isExprValue_Kind `protobuf_oneof:"kind"`
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *ExprValue) Reset() {
|
func (x *ExprValue) Reset() {
|
||||||
*x = ExprValue{}
|
*x = ExprValue{}
|
||||||
if protoimpl.UnsafeEnabled {
|
mi := &file_cel_expr_eval_proto_msgTypes[1]
|
||||||
mi := &file_cel_expr_eval_proto_msgTypes[1]
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms.StoreMessageInfo(mi)
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *ExprValue) String() string {
|
func (x *ExprValue) String() string {
|
||||||
@@ -106,7 +100,7 @@ func (*ExprValue) ProtoMessage() {}
|
|||||||
|
|
||||||
func (x *ExprValue) ProtoReflect() protoreflect.Message {
|
func (x *ExprValue) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_cel_expr_eval_proto_msgTypes[1]
|
mi := &file_cel_expr_eval_proto_msgTypes[1]
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
if x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
@@ -121,30 +115,36 @@ func (*ExprValue) Descriptor() ([]byte, []int) {
|
|||||||
return file_cel_expr_eval_proto_rawDescGZIP(), []int{1}
|
return file_cel_expr_eval_proto_rawDescGZIP(), []int{1}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *ExprValue) GetKind() isExprValue_Kind {
|
func (x *ExprValue) GetKind() isExprValue_Kind {
|
||||||
if m != nil {
|
if x != nil {
|
||||||
return m.Kind
|
return x.Kind
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *ExprValue) GetValue() *Value {
|
func (x *ExprValue) GetValue() *Value {
|
||||||
if x, ok := x.GetKind().(*ExprValue_Value); ok {
|
if x != nil {
|
||||||
return x.Value
|
if x, ok := x.Kind.(*ExprValue_Value); ok {
|
||||||
|
return x.Value
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *ExprValue) GetError() *ErrorSet {
|
func (x *ExprValue) GetError() *ErrorSet {
|
||||||
if x, ok := x.GetKind().(*ExprValue_Error); ok {
|
if x != nil {
|
||||||
return x.Error
|
if x, ok := x.Kind.(*ExprValue_Error); ok {
|
||||||
|
return x.Error
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *ExprValue) GetUnknown() *UnknownSet {
|
func (x *ExprValue) GetUnknown() *UnknownSet {
|
||||||
if x, ok := x.GetKind().(*ExprValue_Unknown); ok {
|
if x != nil {
|
||||||
return x.Unknown
|
if x, ok := x.Kind.(*ExprValue_Unknown); ok {
|
||||||
|
return x.Unknown
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -172,20 +172,17 @@ func (*ExprValue_Error) isExprValue_Kind() {}
|
|||||||
func (*ExprValue_Unknown) isExprValue_Kind() {}
|
func (*ExprValue_Unknown) isExprValue_Kind() {}
|
||||||
|
|
||||||
type ErrorSet struct {
|
type ErrorSet struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
sizeCache protoimpl.SizeCache
|
Errors []*Status `protobuf:"bytes,1,rep,name=errors,proto3" json:"errors,omitempty"`
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
Errors []*status.Status `protobuf:"bytes,1,rep,name=errors,proto3" json:"errors,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *ErrorSet) Reset() {
|
func (x *ErrorSet) Reset() {
|
||||||
*x = ErrorSet{}
|
*x = ErrorSet{}
|
||||||
if protoimpl.UnsafeEnabled {
|
mi := &file_cel_expr_eval_proto_msgTypes[2]
|
||||||
mi := &file_cel_expr_eval_proto_msgTypes[2]
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms.StoreMessageInfo(mi)
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *ErrorSet) String() string {
|
func (x *ErrorSet) String() string {
|
||||||
@@ -196,7 +193,7 @@ func (*ErrorSet) ProtoMessage() {}
|
|||||||
|
|
||||||
func (x *ErrorSet) ProtoReflect() protoreflect.Message {
|
func (x *ErrorSet) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_cel_expr_eval_proto_msgTypes[2]
|
mi := &file_cel_expr_eval_proto_msgTypes[2]
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
if x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
@@ -211,28 +208,85 @@ func (*ErrorSet) Descriptor() ([]byte, []int) {
|
|||||||
return file_cel_expr_eval_proto_rawDescGZIP(), []int{2}
|
return file_cel_expr_eval_proto_rawDescGZIP(), []int{2}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *ErrorSet) GetErrors() []*status.Status {
|
func (x *ErrorSet) GetErrors() []*Status {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.Errors
|
return x.Errors
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type UnknownSet struct {
|
type Status struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
sizeCache protoimpl.SizeCache
|
Code int32 `protobuf:"varint,1,opt,name=code,proto3" json:"code,omitempty"`
|
||||||
|
Message string `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"`
|
||||||
|
Details []*anypb.Any `protobuf:"bytes,3,rep,name=details,proto3" json:"details,omitempty"`
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
}
|
||||||
|
|
||||||
Exprs []int64 `protobuf:"varint,1,rep,packed,name=exprs,proto3" json:"exprs,omitempty"`
|
func (x *Status) Reset() {
|
||||||
|
*x = Status{}
|
||||||
|
mi := &file_cel_expr_eval_proto_msgTypes[3]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Status) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*Status) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *Status) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_cel_expr_eval_proto_msgTypes[3]
|
||||||
|
if x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use Status.ProtoReflect.Descriptor instead.
|
||||||
|
func (*Status) Descriptor() ([]byte, []int) {
|
||||||
|
return file_cel_expr_eval_proto_rawDescGZIP(), []int{3}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Status) GetCode() int32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.Code
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Status) GetMessage() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Message
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Status) GetDetails() []*anypb.Any {
|
||||||
|
if x != nil {
|
||||||
|
return x.Details
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type UnknownSet struct {
|
||||||
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
|
Exprs []int64 `protobuf:"varint,1,rep,packed,name=exprs,proto3" json:"exprs,omitempty"`
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *UnknownSet) Reset() {
|
func (x *UnknownSet) Reset() {
|
||||||
*x = UnknownSet{}
|
*x = UnknownSet{}
|
||||||
if protoimpl.UnsafeEnabled {
|
mi := &file_cel_expr_eval_proto_msgTypes[4]
|
||||||
mi := &file_cel_expr_eval_proto_msgTypes[3]
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms.StoreMessageInfo(mi)
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *UnknownSet) String() string {
|
func (x *UnknownSet) String() string {
|
||||||
@@ -242,8 +296,8 @@ func (x *UnknownSet) String() string {
|
|||||||
func (*UnknownSet) ProtoMessage() {}
|
func (*UnknownSet) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *UnknownSet) ProtoReflect() protoreflect.Message {
|
func (x *UnknownSet) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_cel_expr_eval_proto_msgTypes[3]
|
mi := &file_cel_expr_eval_proto_msgTypes[4]
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
if x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
@@ -255,7 +309,7 @@ func (x *UnknownSet) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use UnknownSet.ProtoReflect.Descriptor instead.
|
// Deprecated: Use UnknownSet.ProtoReflect.Descriptor instead.
|
||||||
func (*UnknownSet) Descriptor() ([]byte, []int) {
|
func (*UnknownSet) Descriptor() ([]byte, []int) {
|
||||||
return file_cel_expr_eval_proto_rawDescGZIP(), []int{3}
|
return file_cel_expr_eval_proto_rawDescGZIP(), []int{4}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *UnknownSet) GetExprs() []int64 {
|
func (x *UnknownSet) GetExprs() []int64 {
|
||||||
@@ -266,21 +320,18 @@ func (x *UnknownSet) GetExprs() []int64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type EvalState_Result struct {
|
type EvalState_Result struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
sizeCache protoimpl.SizeCache
|
Expr int64 `protobuf:"varint,1,opt,name=expr,proto3" json:"expr,omitempty"`
|
||||||
|
Value int64 `protobuf:"varint,2,opt,name=value,proto3" json:"value,omitempty"`
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
Expr int64 `protobuf:"varint,1,opt,name=expr,proto3" json:"expr,omitempty"`
|
|
||||||
Value int64 `protobuf:"varint,2,opt,name=value,proto3" json:"value,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *EvalState_Result) Reset() {
|
func (x *EvalState_Result) Reset() {
|
||||||
*x = EvalState_Result{}
|
*x = EvalState_Result{}
|
||||||
if protoimpl.UnsafeEnabled {
|
mi := &file_cel_expr_eval_proto_msgTypes[5]
|
||||||
mi := &file_cel_expr_eval_proto_msgTypes[4]
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms.StoreMessageInfo(mi)
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *EvalState_Result) String() string {
|
func (x *EvalState_Result) String() string {
|
||||||
@@ -290,8 +341,8 @@ func (x *EvalState_Result) String() string {
|
|||||||
func (*EvalState_Result) ProtoMessage() {}
|
func (*EvalState_Result) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *EvalState_Result) ProtoReflect() protoreflect.Message {
|
func (x *EvalState_Result) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_cel_expr_eval_proto_msgTypes[4]
|
mi := &file_cel_expr_eval_proto_msgTypes[5]
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
if x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
@@ -325,39 +376,45 @@ var File_cel_expr_eval_proto protoreflect.FileDescriptor
|
|||||||
var file_cel_expr_eval_proto_rawDesc = []byte{
|
var file_cel_expr_eval_proto_rawDesc = []byte{
|
||||||
0x0a, 0x13, 0x63, 0x65, 0x6c, 0x2f, 0x65, 0x78, 0x70, 0x72, 0x2f, 0x65, 0x76, 0x61, 0x6c, 0x2e,
|
0x0a, 0x13, 0x63, 0x65, 0x6c, 0x2f, 0x65, 0x78, 0x70, 0x72, 0x2f, 0x65, 0x76, 0x61, 0x6c, 0x2e,
|
||||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x08, 0x63, 0x65, 0x6c, 0x2e, 0x65, 0x78, 0x70, 0x72, 0x1a,
|
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x08, 0x63, 0x65, 0x6c, 0x2e, 0x65, 0x78, 0x70, 0x72, 0x1a,
|
||||||
0x14, 0x63, 0x65, 0x6c, 0x2f, 0x65, 0x78, 0x70, 0x72, 0x2f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2e,
|
0x19, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,
|
||||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x17, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x72, 0x70,
|
0x2f, 0x61, 0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x14, 0x63, 0x65, 0x6c, 0x2f,
|
||||||
0x63, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xa2,
|
0x65, 0x78, 0x70, 0x72, 0x2f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||||
0x01, 0x0a, 0x09, 0x45, 0x76, 0x61, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x2b, 0x0a, 0x06,
|
0x22, 0xa2, 0x01, 0x0a, 0x09, 0x45, 0x76, 0x61, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x2b,
|
||||||
0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63,
|
0x0a, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13,
|
||||||
0x65, 0x6c, 0x2e, 0x65, 0x78, 0x70, 0x72, 0x2e, 0x45, 0x78, 0x70, 0x72, 0x56, 0x61, 0x6c, 0x75,
|
0x2e, 0x63, 0x65, 0x6c, 0x2e, 0x65, 0x78, 0x70, 0x72, 0x2e, 0x45, 0x78, 0x70, 0x72, 0x56, 0x61,
|
||||||
0x65, 0x52, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x34, 0x0a, 0x07, 0x72, 0x65, 0x73,
|
0x6c, 0x75, 0x65, 0x52, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x34, 0x0a, 0x07, 0x72,
|
||||||
0x75, 0x6c, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x63, 0x65, 0x6c,
|
0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x63,
|
||||||
0x2e, 0x65, 0x78, 0x70, 0x72, 0x2e, 0x45, 0x76, 0x61, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x2e,
|
0x65, 0x6c, 0x2e, 0x65, 0x78, 0x70, 0x72, 0x2e, 0x45, 0x76, 0x61, 0x6c, 0x53, 0x74, 0x61, 0x74,
|
||||||
0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x1a,
|
0x65, 0x2e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74,
|
||||||
0x32, 0x0a, 0x06, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x78, 0x70,
|
0x73, 0x1a, 0x32, 0x0a, 0x06, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x65,
|
||||||
0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x65, 0x78, 0x70, 0x72, 0x12, 0x14, 0x0a,
|
0x78, 0x70, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x65, 0x78, 0x70, 0x72, 0x12,
|
||||||
0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x76, 0x61,
|
0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05,
|
||||||
0x6c, 0x75, 0x65, 0x22, 0x9a, 0x01, 0x0a, 0x09, 0x45, 0x78, 0x70, 0x72, 0x56, 0x61, 0x6c, 0x75,
|
0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x9a, 0x01, 0x0a, 0x09, 0x45, 0x78, 0x70, 0x72, 0x56, 0x61,
|
||||||
0x65, 0x12, 0x27, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b,
|
0x6c, 0x75, 0x65, 0x12, 0x27, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01,
|
||||||
0x32, 0x0f, 0x2e, 0x63, 0x65, 0x6c, 0x2e, 0x65, 0x78, 0x70, 0x72, 0x2e, 0x56, 0x61, 0x6c, 0x75,
|
0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x63, 0x65, 0x6c, 0x2e, 0x65, 0x78, 0x70, 0x72, 0x2e, 0x56, 0x61,
|
||||||
0x65, 0x48, 0x00, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x2a, 0x0a, 0x05, 0x65, 0x72,
|
0x6c, 0x75, 0x65, 0x48, 0x00, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x2a, 0x0a, 0x05,
|
||||||
0x72, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x63, 0x65, 0x6c, 0x2e,
|
0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x63, 0x65,
|
||||||
0x65, 0x78, 0x70, 0x72, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x53, 0x65, 0x74, 0x48, 0x00, 0x52,
|
0x6c, 0x2e, 0x65, 0x78, 0x70, 0x72, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x53, 0x65, 0x74, 0x48,
|
||||||
0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x30, 0x0a, 0x07, 0x75, 0x6e, 0x6b, 0x6e, 0x6f, 0x77,
|
0x00, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x30, 0x0a, 0x07, 0x75, 0x6e, 0x6b, 0x6e,
|
||||||
0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x63, 0x65, 0x6c, 0x2e, 0x65, 0x78,
|
0x6f, 0x77, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x63, 0x65, 0x6c, 0x2e,
|
||||||
0x70, 0x72, 0x2e, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x53, 0x65, 0x74, 0x48, 0x00, 0x52,
|
0x65, 0x78, 0x70, 0x72, 0x2e, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x53, 0x65, 0x74, 0x48,
|
||||||
0x07, 0x75, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x42, 0x06, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64,
|
0x00, 0x52, 0x07, 0x75, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x42, 0x06, 0x0a, 0x04, 0x6b, 0x69,
|
||||||
0x22, 0x36, 0x0a, 0x08, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x53, 0x65, 0x74, 0x12, 0x2a, 0x0a, 0x06,
|
0x6e, 0x64, 0x22, 0x34, 0x0a, 0x08, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x53, 0x65, 0x74, 0x12, 0x28,
|
||||||
0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x67,
|
0x0a, 0x06, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10,
|
||||||
0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73,
|
0x2e, 0x63, 0x65, 0x6c, 0x2e, 0x65, 0x78, 0x70, 0x72, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73,
|
||||||
0x52, 0x06, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x22, 0x22, 0x0a, 0x0a, 0x55, 0x6e, 0x6b, 0x6e,
|
0x52, 0x06, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x22, 0x66, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74,
|
||||||
0x6f, 0x77, 0x6e, 0x53, 0x65, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x78, 0x70, 0x72, 0x73, 0x18,
|
0x75, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05,
|
||||||
0x01, 0x20, 0x03, 0x28, 0x03, 0x52, 0x05, 0x65, 0x78, 0x70, 0x72, 0x73, 0x42, 0x2c, 0x0a, 0x0c,
|
0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67,
|
||||||
0x64, 0x65, 0x76, 0x2e, 0x63, 0x65, 0x6c, 0x2e, 0x65, 0x78, 0x70, 0x72, 0x42, 0x09, 0x45, 0x76,
|
0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
|
||||||
0x61, 0x6c, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x0c, 0x63, 0x65, 0x6c, 0x2e, 0x64,
|
0x12, 0x2e, 0x0a, 0x07, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28,
|
||||||
0x65, 0x76, 0x2f, 0x65, 0x78, 0x70, 0x72, 0xf8, 0x01, 0x01, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
|
0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||||
0x6f, 0x33,
|
0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x07, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73,
|
||||||
|
0x22, 0x22, 0x0a, 0x0a, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x53, 0x65, 0x74, 0x12, 0x14,
|
||||||
|
0x0a, 0x05, 0x65, 0x78, 0x70, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x03, 0x52, 0x05, 0x65,
|
||||||
|
0x78, 0x70, 0x72, 0x73, 0x42, 0x2c, 0x0a, 0x0c, 0x64, 0x65, 0x76, 0x2e, 0x63, 0x65, 0x6c, 0x2e,
|
||||||
|
0x65, 0x78, 0x70, 0x72, 0x42, 0x09, 0x45, 0x76, 0x61, 0x6c, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50,
|
||||||
|
0x01, 0x5a, 0x0c, 0x63, 0x65, 0x6c, 0x2e, 0x64, 0x65, 0x76, 0x2f, 0x65, 0x78, 0x70, 0x72, 0xf8,
|
||||||
|
0x01, 0x01, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -372,28 +429,30 @@ func file_cel_expr_eval_proto_rawDescGZIP() []byte {
|
|||||||
return file_cel_expr_eval_proto_rawDescData
|
return file_cel_expr_eval_proto_rawDescData
|
||||||
}
|
}
|
||||||
|
|
||||||
var file_cel_expr_eval_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
|
var file_cel_expr_eval_proto_msgTypes = make([]protoimpl.MessageInfo, 6)
|
||||||
var file_cel_expr_eval_proto_goTypes = []interface{}{
|
var file_cel_expr_eval_proto_goTypes = []any{
|
||||||
(*EvalState)(nil), // 0: cel.expr.EvalState
|
(*EvalState)(nil), // 0: cel.expr.EvalState
|
||||||
(*ExprValue)(nil), // 1: cel.expr.ExprValue
|
(*ExprValue)(nil), // 1: cel.expr.ExprValue
|
||||||
(*ErrorSet)(nil), // 2: cel.expr.ErrorSet
|
(*ErrorSet)(nil), // 2: cel.expr.ErrorSet
|
||||||
(*UnknownSet)(nil), // 3: cel.expr.UnknownSet
|
(*Status)(nil), // 3: cel.expr.Status
|
||||||
(*EvalState_Result)(nil), // 4: cel.expr.EvalState.Result
|
(*UnknownSet)(nil), // 4: cel.expr.UnknownSet
|
||||||
(*Value)(nil), // 5: cel.expr.Value
|
(*EvalState_Result)(nil), // 5: cel.expr.EvalState.Result
|
||||||
(*status.Status)(nil), // 6: google.rpc.Status
|
(*Value)(nil), // 6: cel.expr.Value
|
||||||
|
(*anypb.Any)(nil), // 7: google.protobuf.Any
|
||||||
}
|
}
|
||||||
var file_cel_expr_eval_proto_depIdxs = []int32{
|
var file_cel_expr_eval_proto_depIdxs = []int32{
|
||||||
1, // 0: cel.expr.EvalState.values:type_name -> cel.expr.ExprValue
|
1, // 0: cel.expr.EvalState.values:type_name -> cel.expr.ExprValue
|
||||||
4, // 1: cel.expr.EvalState.results:type_name -> cel.expr.EvalState.Result
|
5, // 1: cel.expr.EvalState.results:type_name -> cel.expr.EvalState.Result
|
||||||
5, // 2: cel.expr.ExprValue.value:type_name -> cel.expr.Value
|
6, // 2: cel.expr.ExprValue.value:type_name -> cel.expr.Value
|
||||||
2, // 3: cel.expr.ExprValue.error:type_name -> cel.expr.ErrorSet
|
2, // 3: cel.expr.ExprValue.error:type_name -> cel.expr.ErrorSet
|
||||||
3, // 4: cel.expr.ExprValue.unknown:type_name -> cel.expr.UnknownSet
|
4, // 4: cel.expr.ExprValue.unknown:type_name -> cel.expr.UnknownSet
|
||||||
6, // 5: cel.expr.ErrorSet.errors:type_name -> google.rpc.Status
|
3, // 5: cel.expr.ErrorSet.errors:type_name -> cel.expr.Status
|
||||||
6, // [6:6] is the sub-list for method output_type
|
7, // 6: cel.expr.Status.details:type_name -> google.protobuf.Any
|
||||||
6, // [6:6] is the sub-list for method input_type
|
7, // [7:7] is the sub-list for method output_type
|
||||||
6, // [6:6] is the sub-list for extension type_name
|
7, // [7:7] is the sub-list for method input_type
|
||||||
6, // [6:6] is the sub-list for extension extendee
|
7, // [7:7] is the sub-list for extension type_name
|
||||||
0, // [0:6] is the sub-list for field type_name
|
7, // [7:7] is the sub-list for extension extendee
|
||||||
|
0, // [0:7] is the sub-list for field type_name
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() { file_cel_expr_eval_proto_init() }
|
func init() { file_cel_expr_eval_proto_init() }
|
||||||
@@ -402,69 +461,7 @@ func file_cel_expr_eval_proto_init() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
file_cel_expr_value_proto_init()
|
file_cel_expr_value_proto_init()
|
||||||
if !protoimpl.UnsafeEnabled {
|
file_cel_expr_eval_proto_msgTypes[1].OneofWrappers = []any{
|
||||||
file_cel_expr_eval_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
|
||||||
switch v := v.(*EvalState); i {
|
|
||||||
case 0:
|
|
||||||
return &v.state
|
|
||||||
case 1:
|
|
||||||
return &v.sizeCache
|
|
||||||
case 2:
|
|
||||||
return &v.unknownFields
|
|
||||||
default:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
file_cel_expr_eval_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
|
||||||
switch v := v.(*ExprValue); i {
|
|
||||||
case 0:
|
|
||||||
return &v.state
|
|
||||||
case 1:
|
|
||||||
return &v.sizeCache
|
|
||||||
case 2:
|
|
||||||
return &v.unknownFields
|
|
||||||
default:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
file_cel_expr_eval_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
|
|
||||||
switch v := v.(*ErrorSet); i {
|
|
||||||
case 0:
|
|
||||||
return &v.state
|
|
||||||
case 1:
|
|
||||||
return &v.sizeCache
|
|
||||||
case 2:
|
|
||||||
return &v.unknownFields
|
|
||||||
default:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
file_cel_expr_eval_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
|
|
||||||
switch v := v.(*UnknownSet); i {
|
|
||||||
case 0:
|
|
||||||
return &v.state
|
|
||||||
case 1:
|
|
||||||
return &v.sizeCache
|
|
||||||
case 2:
|
|
||||||
return &v.unknownFields
|
|
||||||
default:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
file_cel_expr_eval_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
|
|
||||||
switch v := v.(*EvalState_Result); i {
|
|
||||||
case 0:
|
|
||||||
return &v.state
|
|
||||||
case 1:
|
|
||||||
return &v.sizeCache
|
|
||||||
case 2:
|
|
||||||
return &v.unknownFields
|
|
||||||
default:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
file_cel_expr_eval_proto_msgTypes[1].OneofWrappers = []interface{}{
|
|
||||||
(*ExprValue_Value)(nil),
|
(*ExprValue_Value)(nil),
|
||||||
(*ExprValue_Error)(nil),
|
(*ExprValue_Error)(nil),
|
||||||
(*ExprValue_Unknown)(nil),
|
(*ExprValue_Unknown)(nil),
|
||||||
@@ -475,7 +472,7 @@ func file_cel_expr_eval_proto_init() {
|
|||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
RawDescriptor: file_cel_expr_eval_proto_rawDesc,
|
RawDescriptor: file_cel_expr_eval_proto_rawDesc,
|
||||||
NumEnums: 0,
|
NumEnums: 0,
|
||||||
NumMessages: 5,
|
NumMessages: 6,
|
||||||
NumExtensions: 0,
|
NumExtensions: 0,
|
||||||
NumServices: 0,
|
NumServices: 0,
|
||||||
},
|
},
|
||||||
|
|||||||
14
vendor/github.com/asaskevich/govalidator/.travis.yml
generated
vendored
14
vendor/github.com/asaskevich/govalidator/.travis.yml
generated
vendored
@@ -1,14 +0,0 @@
|
|||||||
language: go
|
|
||||||
|
|
||||||
go:
|
|
||||||
- 1.1
|
|
||||||
- 1.2
|
|
||||||
- 1.3
|
|
||||||
- 1.4
|
|
||||||
- 1.5
|
|
||||||
- 1.6
|
|
||||||
- tip
|
|
||||||
|
|
||||||
notifications:
|
|
||||||
email:
|
|
||||||
- bwatas@gmail.com
|
|
||||||
63
vendor/github.com/asaskevich/govalidator/CONTRIBUTING.md
generated
vendored
63
vendor/github.com/asaskevich/govalidator/CONTRIBUTING.md
generated
vendored
@@ -1,63 +0,0 @@
|
|||||||
#### Support
|
|
||||||
If you do have a contribution to the package, feel free to create a Pull Request or an Issue.
|
|
||||||
|
|
||||||
#### What to contribute
|
|
||||||
If you don't know what to do, there are some features and functions that need to be done
|
|
||||||
|
|
||||||
- [ ] Refactor code
|
|
||||||
- [ ] Edit docs and [README](https://github.com/asaskevich/govalidator/README.md): spellcheck, grammar and typo check
|
|
||||||
- [ ] Create actual list of contributors and projects that currently using this package
|
|
||||||
- [ ] Resolve [issues and bugs](https://github.com/asaskevich/govalidator/issues)
|
|
||||||
- [ ] Update actual [list of functions](https://github.com/asaskevich/govalidator#list-of-functions)
|
|
||||||
- [ ] Update [list of validators](https://github.com/asaskevich/govalidator#validatestruct-2) that available for `ValidateStruct` and add new
|
|
||||||
- [ ] Implement new validators: `IsFQDN`, `IsIMEI`, `IsPostalCode`, `IsISIN`, `IsISRC` etc
|
|
||||||
- [ ] Implement [validation by maps](https://github.com/asaskevich/govalidator/issues/224)
|
|
||||||
- [ ] Implement fuzzing testing
|
|
||||||
- [ ] Implement some struct/map/array utilities
|
|
||||||
- [ ] Implement map/array validation
|
|
||||||
- [ ] Implement benchmarking
|
|
||||||
- [ ] Implement batch of examples
|
|
||||||
- [ ] Look at forks for new features and fixes
|
|
||||||
|
|
||||||
#### Advice
|
|
||||||
Feel free to create what you want, but keep in mind when you implement new features:
|
|
||||||
- Code must be clear and readable, names of variables/constants clearly describes what they are doing
|
|
||||||
- Public functions must be documented and described in source file and added to README.md to the list of available functions
|
|
||||||
- There are must be unit-tests for any new functions and improvements
|
|
||||||
|
|
||||||
## Financial contributions
|
|
||||||
|
|
||||||
We also welcome financial contributions in full transparency on our [open collective](https://opencollective.com/govalidator).
|
|
||||||
Anyone can file an expense. If the expense makes sense for the development of the community, it will be "merged" in the ledger of our open collective by the core contributors and the person who filed the expense will be reimbursed.
|
|
||||||
|
|
||||||
|
|
||||||
## Credits
|
|
||||||
|
|
||||||
|
|
||||||
### Contributors
|
|
||||||
|
|
||||||
Thank you to all the people who have already contributed to govalidator!
|
|
||||||
<a href="graphs/contributors"><img src="https://opencollective.com/govalidator/contributors.svg?width=890" /></a>
|
|
||||||
|
|
||||||
|
|
||||||
### Backers
|
|
||||||
|
|
||||||
Thank you to all our backers! [[Become a backer](https://opencollective.com/govalidator#backer)]
|
|
||||||
|
|
||||||
<a href="https://opencollective.com/govalidator#backers" target="_blank"><img src="https://opencollective.com/govalidator/backers.svg?width=890"></a>
|
|
||||||
|
|
||||||
|
|
||||||
### Sponsors
|
|
||||||
|
|
||||||
Thank you to all our sponsors! (please ask your company to also support this open source project by [becoming a sponsor](https://opencollective.com/govalidator#sponsor))
|
|
||||||
|
|
||||||
<a href="https://opencollective.com/govalidator/sponsor/0/website" target="_blank"><img src="https://opencollective.com/govalidator/sponsor/0/avatar.svg"></a>
|
|
||||||
<a href="https://opencollective.com/govalidator/sponsor/1/website" target="_blank"><img src="https://opencollective.com/govalidator/sponsor/1/avatar.svg"></a>
|
|
||||||
<a href="https://opencollective.com/govalidator/sponsor/2/website" target="_blank"><img src="https://opencollective.com/govalidator/sponsor/2/avatar.svg"></a>
|
|
||||||
<a href="https://opencollective.com/govalidator/sponsor/3/website" target="_blank"><img src="https://opencollective.com/govalidator/sponsor/3/avatar.svg"></a>
|
|
||||||
<a href="https://opencollective.com/govalidator/sponsor/4/website" target="_blank"><img src="https://opencollective.com/govalidator/sponsor/4/avatar.svg"></a>
|
|
||||||
<a href="https://opencollective.com/govalidator/sponsor/5/website" target="_blank"><img src="https://opencollective.com/govalidator/sponsor/5/avatar.svg"></a>
|
|
||||||
<a href="https://opencollective.com/govalidator/sponsor/6/website" target="_blank"><img src="https://opencollective.com/govalidator/sponsor/6/avatar.svg"></a>
|
|
||||||
<a href="https://opencollective.com/govalidator/sponsor/7/website" target="_blank"><img src="https://opencollective.com/govalidator/sponsor/7/avatar.svg"></a>
|
|
||||||
<a href="https://opencollective.com/govalidator/sponsor/8/website" target="_blank"><img src="https://opencollective.com/govalidator/sponsor/8/avatar.svg"></a>
|
|
||||||
<a href="https://opencollective.com/govalidator/sponsor/9/website" target="_blank"><img src="https://opencollective.com/govalidator/sponsor/9/avatar.svg"></a>
|
|
||||||
507
vendor/github.com/asaskevich/govalidator/README.md
generated
vendored
507
vendor/github.com/asaskevich/govalidator/README.md
generated
vendored
@@ -1,507 +0,0 @@
|
|||||||
govalidator
|
|
||||||
===========
|
|
||||||
[](https://gitter.im/asaskevich/govalidator?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) [](https://godoc.org/github.com/asaskevich/govalidator) [](https://coveralls.io/r/asaskevich/govalidator?branch=master) [](https://app.wercker.com/project/bykey/1ec990b09ea86c910d5f08b0e02c6043)
|
|
||||||
[](https://travis-ci.org/asaskevich/govalidator) [](https://goreportcard.com/report/github.com/asaskevich/govalidator) [](http://go-search.org/view?id=github.com%2Fasaskevich%2Fgovalidator) [](#backers) [](#sponsors) [](https://app.fossa.io/projects/git%2Bgithub.com%2Fasaskevich%2Fgovalidator?ref=badge_shield)
|
|
||||||
|
|
||||||
A package of validators and sanitizers for strings, structs and collections. Based on [validator.js](https://github.com/chriso/validator.js).
|
|
||||||
|
|
||||||
#### Installation
|
|
||||||
Make sure that Go is installed on your computer.
|
|
||||||
Type the following command in your terminal:
|
|
||||||
|
|
||||||
go get github.com/asaskevich/govalidator
|
|
||||||
|
|
||||||
or you can get specified release of the package with `gopkg.in`:
|
|
||||||
|
|
||||||
go get gopkg.in/asaskevich/govalidator.v4
|
|
||||||
|
|
||||||
After it the package is ready to use.
|
|
||||||
|
|
||||||
|
|
||||||
#### Import package in your project
|
|
||||||
Add following line in your `*.go` file:
|
|
||||||
```go
|
|
||||||
import "github.com/asaskevich/govalidator"
|
|
||||||
```
|
|
||||||
If you are unhappy to use long `govalidator`, you can do something like this:
|
|
||||||
```go
|
|
||||||
import (
|
|
||||||
valid "github.com/asaskevich/govalidator"
|
|
||||||
)
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Activate behavior to require all fields have a validation tag by default
|
|
||||||
`SetFieldsRequiredByDefault` causes validation to fail when struct fields do not include validations or are not explicitly marked as exempt (using `valid:"-"` or `valid:"email,optional"`). A good place to activate this is a package init function or the main() function.
|
|
||||||
|
|
||||||
`SetNilPtrAllowedByRequired` causes validation to pass when struct fields marked by `required` are set to nil. This is disabled by default for consistency, but some packages that need to be able to determine between `nil` and `zero value` state can use this. If disabled, both `nil` and `zero` values cause validation errors.
|
|
||||||
|
|
||||||
```go
|
|
||||||
import "github.com/asaskevich/govalidator"
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
govalidator.SetFieldsRequiredByDefault(true)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Here's some code to explain it:
|
|
||||||
```go
|
|
||||||
// this struct definition will fail govalidator.ValidateStruct() (and the field values do not matter):
|
|
||||||
type exampleStruct struct {
|
|
||||||
Name string ``
|
|
||||||
Email string `valid:"email"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// this, however, will only fail when Email is empty or an invalid email address:
|
|
||||||
type exampleStruct2 struct {
|
|
||||||
Name string `valid:"-"`
|
|
||||||
Email string `valid:"email"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// lastly, this will only fail when Email is an invalid email address but not when it's empty:
|
|
||||||
type exampleStruct2 struct {
|
|
||||||
Name string `valid:"-"`
|
|
||||||
Email string `valid:"email,optional"`
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Recent breaking changes (see [#123](https://github.com/asaskevich/govalidator/pull/123))
|
|
||||||
##### Custom validator function signature
|
|
||||||
A context was added as the second parameter, for structs this is the object being validated – this makes dependent validation possible.
|
|
||||||
```go
|
|
||||||
import "github.com/asaskevich/govalidator"
|
|
||||||
|
|
||||||
// old signature
|
|
||||||
func(i interface{}) bool
|
|
||||||
|
|
||||||
// new signature
|
|
||||||
func(i interface{}, o interface{}) bool
|
|
||||||
```
|
|
||||||
|
|
||||||
##### Adding a custom validator
|
|
||||||
This was changed to prevent data races when accessing custom validators.
|
|
||||||
```go
|
|
||||||
import "github.com/asaskevich/govalidator"
|
|
||||||
|
|
||||||
// before
|
|
||||||
govalidator.CustomTypeTagMap["customByteArrayValidator"] = CustomTypeValidator(func(i interface{}, o interface{}) bool {
|
|
||||||
// ...
|
|
||||||
})
|
|
||||||
|
|
||||||
// after
|
|
||||||
govalidator.CustomTypeTagMap.Set("customByteArrayValidator", CustomTypeValidator(func(i interface{}, o interface{}) bool {
|
|
||||||
// ...
|
|
||||||
}))
|
|
||||||
```
|
|
||||||
|
|
||||||
#### List of functions:
|
|
||||||
```go
|
|
||||||
func Abs(value float64) float64
|
|
||||||
func BlackList(str, chars string) string
|
|
||||||
func ByteLength(str string, params ...string) bool
|
|
||||||
func CamelCaseToUnderscore(str string) string
|
|
||||||
func Contains(str, substring string) bool
|
|
||||||
func Count(array []interface{}, iterator ConditionIterator) int
|
|
||||||
func Each(array []interface{}, iterator Iterator)
|
|
||||||
func ErrorByField(e error, field string) string
|
|
||||||
func ErrorsByField(e error) map[string]string
|
|
||||||
func Filter(array []interface{}, iterator ConditionIterator) []interface{}
|
|
||||||
func Find(array []interface{}, iterator ConditionIterator) interface{}
|
|
||||||
func GetLine(s string, index int) (string, error)
|
|
||||||
func GetLines(s string) []string
|
|
||||||
func InRange(value, left, right float64) bool
|
|
||||||
func IsASCII(str string) bool
|
|
||||||
func IsAlpha(str string) bool
|
|
||||||
func IsAlphanumeric(str string) bool
|
|
||||||
func IsBase64(str string) bool
|
|
||||||
func IsByteLength(str string, min, max int) bool
|
|
||||||
func IsCIDR(str string) bool
|
|
||||||
func IsCreditCard(str string) bool
|
|
||||||
func IsDNSName(str string) bool
|
|
||||||
func IsDataURI(str string) bool
|
|
||||||
func IsDialString(str string) bool
|
|
||||||
func IsDivisibleBy(str, num string) bool
|
|
||||||
func IsEmail(str string) bool
|
|
||||||
func IsFilePath(str string) (bool, int)
|
|
||||||
func IsFloat(str string) bool
|
|
||||||
func IsFullWidth(str string) bool
|
|
||||||
func IsHalfWidth(str string) bool
|
|
||||||
func IsHexadecimal(str string) bool
|
|
||||||
func IsHexcolor(str string) bool
|
|
||||||
func IsHost(str string) bool
|
|
||||||
func IsIP(str string) bool
|
|
||||||
func IsIPv4(str string) bool
|
|
||||||
func IsIPv6(str string) bool
|
|
||||||
func IsISBN(str string, version int) bool
|
|
||||||
func IsISBN10(str string) bool
|
|
||||||
func IsISBN13(str string) bool
|
|
||||||
func IsISO3166Alpha2(str string) bool
|
|
||||||
func IsISO3166Alpha3(str string) bool
|
|
||||||
func IsISO693Alpha2(str string) bool
|
|
||||||
func IsISO693Alpha3b(str string) bool
|
|
||||||
func IsISO4217(str string) bool
|
|
||||||
func IsIn(str string, params ...string) bool
|
|
||||||
func IsInt(str string) bool
|
|
||||||
func IsJSON(str string) bool
|
|
||||||
func IsLatitude(str string) bool
|
|
||||||
func IsLongitude(str string) bool
|
|
||||||
func IsLowerCase(str string) bool
|
|
||||||
func IsMAC(str string) bool
|
|
||||||
func IsMongoID(str string) bool
|
|
||||||
func IsMultibyte(str string) bool
|
|
||||||
func IsNatural(value float64) bool
|
|
||||||
func IsNegative(value float64) bool
|
|
||||||
func IsNonNegative(value float64) bool
|
|
||||||
func IsNonPositive(value float64) bool
|
|
||||||
func IsNull(str string) bool
|
|
||||||
func IsNumeric(str string) bool
|
|
||||||
func IsPort(str string) bool
|
|
||||||
func IsPositive(value float64) bool
|
|
||||||
func IsPrintableASCII(str string) bool
|
|
||||||
func IsRFC3339(str string) bool
|
|
||||||
func IsRFC3339WithoutZone(str string) bool
|
|
||||||
func IsRGBcolor(str string) bool
|
|
||||||
func IsRequestURI(rawurl string) bool
|
|
||||||
func IsRequestURL(rawurl string) bool
|
|
||||||
func IsSSN(str string) bool
|
|
||||||
func IsSemver(str string) bool
|
|
||||||
func IsTime(str string, format string) bool
|
|
||||||
func IsURL(str string) bool
|
|
||||||
func IsUTFDigit(str string) bool
|
|
||||||
func IsUTFLetter(str string) bool
|
|
||||||
func IsUTFLetterNumeric(str string) bool
|
|
||||||
func IsUTFNumeric(str string) bool
|
|
||||||
func IsUUID(str string) bool
|
|
||||||
func IsUUIDv3(str string) bool
|
|
||||||
func IsUUIDv4(str string) bool
|
|
||||||
func IsUUIDv5(str string) bool
|
|
||||||
func IsUpperCase(str string) bool
|
|
||||||
func IsVariableWidth(str string) bool
|
|
||||||
func IsWhole(value float64) bool
|
|
||||||
func LeftTrim(str, chars string) string
|
|
||||||
func Map(array []interface{}, iterator ResultIterator) []interface{}
|
|
||||||
func Matches(str, pattern string) bool
|
|
||||||
func NormalizeEmail(str string) (string, error)
|
|
||||||
func PadBoth(str string, padStr string, padLen int) string
|
|
||||||
func PadLeft(str string, padStr string, padLen int) string
|
|
||||||
func PadRight(str string, padStr string, padLen int) string
|
|
||||||
func Range(str string, params ...string) bool
|
|
||||||
func RemoveTags(s string) string
|
|
||||||
func ReplacePattern(str, pattern, replace string) string
|
|
||||||
func Reverse(s string) string
|
|
||||||
func RightTrim(str, chars string) string
|
|
||||||
func RuneLength(str string, params ...string) bool
|
|
||||||
func SafeFileName(str string) string
|
|
||||||
func SetFieldsRequiredByDefault(value bool)
|
|
||||||
func Sign(value float64) float64
|
|
||||||
func StringLength(str string, params ...string) bool
|
|
||||||
func StringMatches(s string, params ...string) bool
|
|
||||||
func StripLow(str string, keepNewLines bool) string
|
|
||||||
func ToBoolean(str string) (bool, error)
|
|
||||||
func ToFloat(str string) (float64, error)
|
|
||||||
func ToInt(str string) (int64, error)
|
|
||||||
func ToJSON(obj interface{}) (string, error)
|
|
||||||
func ToString(obj interface{}) string
|
|
||||||
func Trim(str, chars string) string
|
|
||||||
func Truncate(str string, length int, ending string) string
|
|
||||||
func UnderscoreToCamelCase(s string) string
|
|
||||||
func ValidateStruct(s interface{}) (bool, error)
|
|
||||||
func WhiteList(str, chars string) string
|
|
||||||
type ConditionIterator
|
|
||||||
type CustomTypeValidator
|
|
||||||
type Error
|
|
||||||
func (e Error) Error() string
|
|
||||||
type Errors
|
|
||||||
func (es Errors) Error() string
|
|
||||||
func (es Errors) Errors() []error
|
|
||||||
type ISO3166Entry
|
|
||||||
type Iterator
|
|
||||||
type ParamValidator
|
|
||||||
type ResultIterator
|
|
||||||
type UnsupportedTypeError
|
|
||||||
func (e *UnsupportedTypeError) Error() string
|
|
||||||
type Validator
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Examples
|
|
||||||
###### IsURL
|
|
||||||
```go
|
|
||||||
println(govalidator.IsURL(`http://user@pass:domain.com/path/page`))
|
|
||||||
```
|
|
||||||
###### ToString
|
|
||||||
```go
|
|
||||||
type User struct {
|
|
||||||
FirstName string
|
|
||||||
LastName string
|
|
||||||
}
|
|
||||||
|
|
||||||
str := govalidator.ToString(&User{"John", "Juan"})
|
|
||||||
println(str)
|
|
||||||
```
|
|
||||||
###### Each, Map, Filter, Count for slices
|
|
||||||
Each iterates over the slice/array and calls Iterator for every item
|
|
||||||
```go
|
|
||||||
data := []interface{}{1, 2, 3, 4, 5}
|
|
||||||
var fn govalidator.Iterator = func(value interface{}, index int) {
|
|
||||||
println(value.(int))
|
|
||||||
}
|
|
||||||
govalidator.Each(data, fn)
|
|
||||||
```
|
|
||||||
```go
|
|
||||||
data := []interface{}{1, 2, 3, 4, 5}
|
|
||||||
var fn govalidator.ResultIterator = func(value interface{}, index int) interface{} {
|
|
||||||
return value.(int) * 3
|
|
||||||
}
|
|
||||||
_ = govalidator.Map(data, fn) // result = []interface{}{1, 6, 9, 12, 15}
|
|
||||||
```
|
|
||||||
```go
|
|
||||||
data := []interface{}{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
|
|
||||||
var fn govalidator.ConditionIterator = func(value interface{}, index int) bool {
|
|
||||||
return value.(int)%2 == 0
|
|
||||||
}
|
|
||||||
_ = govalidator.Filter(data, fn) // result = []interface{}{2, 4, 6, 8, 10}
|
|
||||||
_ = govalidator.Count(data, fn) // result = 5
|
|
||||||
```
|
|
||||||
###### ValidateStruct [#2](https://github.com/asaskevich/govalidator/pull/2)
|
|
||||||
If you want to validate structs, you can use tag `valid` for any field in your structure. All validators used with this field in one tag are separated by comma. If you want to skip validation, place `-` in your tag. If you need a validator that is not on the list below, you can add it like this:
|
|
||||||
```go
|
|
||||||
govalidator.TagMap["duck"] = govalidator.Validator(func(str string) bool {
|
|
||||||
return str == "duck"
|
|
||||||
})
|
|
||||||
```
|
|
||||||
For completely custom validators (interface-based), see below.
|
|
||||||
|
|
||||||
Here is a list of available validators for struct fields (validator - used function):
|
|
||||||
```go
|
|
||||||
"email": IsEmail,
|
|
||||||
"url": IsURL,
|
|
||||||
"dialstring": IsDialString,
|
|
||||||
"requrl": IsRequestURL,
|
|
||||||
"requri": IsRequestURI,
|
|
||||||
"alpha": IsAlpha,
|
|
||||||
"utfletter": IsUTFLetter,
|
|
||||||
"alphanum": IsAlphanumeric,
|
|
||||||
"utfletternum": IsUTFLetterNumeric,
|
|
||||||
"numeric": IsNumeric,
|
|
||||||
"utfnumeric": IsUTFNumeric,
|
|
||||||
"utfdigit": IsUTFDigit,
|
|
||||||
"hexadecimal": IsHexadecimal,
|
|
||||||
"hexcolor": IsHexcolor,
|
|
||||||
"rgbcolor": IsRGBcolor,
|
|
||||||
"lowercase": IsLowerCase,
|
|
||||||
"uppercase": IsUpperCase,
|
|
||||||
"int": IsInt,
|
|
||||||
"float": IsFloat,
|
|
||||||
"null": IsNull,
|
|
||||||
"uuid": IsUUID,
|
|
||||||
"uuidv3": IsUUIDv3,
|
|
||||||
"uuidv4": IsUUIDv4,
|
|
||||||
"uuidv5": IsUUIDv5,
|
|
||||||
"creditcard": IsCreditCard,
|
|
||||||
"isbn10": IsISBN10,
|
|
||||||
"isbn13": IsISBN13,
|
|
||||||
"json": IsJSON,
|
|
||||||
"multibyte": IsMultibyte,
|
|
||||||
"ascii": IsASCII,
|
|
||||||
"printableascii": IsPrintableASCII,
|
|
||||||
"fullwidth": IsFullWidth,
|
|
||||||
"halfwidth": IsHalfWidth,
|
|
||||||
"variablewidth": IsVariableWidth,
|
|
||||||
"base64": IsBase64,
|
|
||||||
"datauri": IsDataURI,
|
|
||||||
"ip": IsIP,
|
|
||||||
"port": IsPort,
|
|
||||||
"ipv4": IsIPv4,
|
|
||||||
"ipv6": IsIPv6,
|
|
||||||
"dns": IsDNSName,
|
|
||||||
"host": IsHost,
|
|
||||||
"mac": IsMAC,
|
|
||||||
"latitude": IsLatitude,
|
|
||||||
"longitude": IsLongitude,
|
|
||||||
"ssn": IsSSN,
|
|
||||||
"semver": IsSemver,
|
|
||||||
"rfc3339": IsRFC3339,
|
|
||||||
"rfc3339WithoutZone": IsRFC3339WithoutZone,
|
|
||||||
"ISO3166Alpha2": IsISO3166Alpha2,
|
|
||||||
"ISO3166Alpha3": IsISO3166Alpha3,
|
|
||||||
```
|
|
||||||
Validators with parameters
|
|
||||||
|
|
||||||
```go
|
|
||||||
"range(min|max)": Range,
|
|
||||||
"length(min|max)": ByteLength,
|
|
||||||
"runelength(min|max)": RuneLength,
|
|
||||||
"stringlength(min|max)": StringLength,
|
|
||||||
"matches(pattern)": StringMatches,
|
|
||||||
"in(string1|string2|...|stringN)": IsIn,
|
|
||||||
"rsapub(keylength)" : IsRsaPub,
|
|
||||||
```
|
|
||||||
|
|
||||||
And here is small example of usage:
|
|
||||||
```go
|
|
||||||
type Post struct {
|
|
||||||
Title string `valid:"alphanum,required"`
|
|
||||||
Message string `valid:"duck,ascii"`
|
|
||||||
Message2 string `valid:"animal(dog)"`
|
|
||||||
AuthorIP string `valid:"ipv4"`
|
|
||||||
Date string `valid:"-"`
|
|
||||||
}
|
|
||||||
post := &Post{
|
|
||||||
Title: "My Example Post",
|
|
||||||
Message: "duck",
|
|
||||||
Message2: "dog",
|
|
||||||
AuthorIP: "123.234.54.3",
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add your own struct validation tags
|
|
||||||
govalidator.TagMap["duck"] = govalidator.Validator(func(str string) bool {
|
|
||||||
return str == "duck"
|
|
||||||
})
|
|
||||||
|
|
||||||
// Add your own struct validation tags with parameter
|
|
||||||
govalidator.ParamTagMap["animal"] = govalidator.ParamValidator(func(str string, params ...string) bool {
|
|
||||||
species := params[0]
|
|
||||||
return str == species
|
|
||||||
})
|
|
||||||
govalidator.ParamTagRegexMap["animal"] = regexp.MustCompile("^animal\\((\\w+)\\)$")
|
|
||||||
|
|
||||||
result, err := govalidator.ValidateStruct(post)
|
|
||||||
if err != nil {
|
|
||||||
println("error: " + err.Error())
|
|
||||||
}
|
|
||||||
println(result)
|
|
||||||
```
|
|
||||||
###### WhiteList
|
|
||||||
```go
|
|
||||||
// Remove all characters from string ignoring characters between "a" and "z"
|
|
||||||
println(govalidator.WhiteList("a3a43a5a4a3a2a23a4a5a4a3a4", "a-z") == "aaaaaaaaaaaa")
|
|
||||||
```
|
|
||||||
|
|
||||||
###### Custom validation functions
|
|
||||||
Custom validation using your own domain specific validators is also available - here's an example of how to use it:
|
|
||||||
```go
|
|
||||||
import "github.com/asaskevich/govalidator"
|
|
||||||
|
|
||||||
type CustomByteArray [6]byte // custom types are supported and can be validated
|
|
||||||
|
|
||||||
type StructWithCustomByteArray struct {
|
|
||||||
ID CustomByteArray `valid:"customByteArrayValidator,customMinLengthValidator"` // multiple custom validators are possible as well and will be evaluated in sequence
|
|
||||||
Email string `valid:"email"`
|
|
||||||
CustomMinLength int `valid:"-"`
|
|
||||||
}
|
|
||||||
|
|
||||||
govalidator.CustomTypeTagMap.Set("customByteArrayValidator", CustomTypeValidator(func(i interface{}, context interface{}) bool {
|
|
||||||
switch v := context.(type) { // you can type switch on the context interface being validated
|
|
||||||
case StructWithCustomByteArray:
|
|
||||||
// you can check and validate against some other field in the context,
|
|
||||||
// return early or not validate against the context at all – your choice
|
|
||||||
case SomeOtherType:
|
|
||||||
// ...
|
|
||||||
default:
|
|
||||||
// expecting some other type? Throw/panic here or continue
|
|
||||||
}
|
|
||||||
|
|
||||||
switch v := i.(type) { // type switch on the struct field being validated
|
|
||||||
case CustomByteArray:
|
|
||||||
for _, e := range v { // this validator checks that the byte array is not empty, i.e. not all zeroes
|
|
||||||
if e != 0 {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}))
|
|
||||||
govalidator.CustomTypeTagMap.Set("customMinLengthValidator", CustomTypeValidator(func(i interface{}, context interface{}) bool {
|
|
||||||
switch v := context.(type) { // this validates a field against the value in another field, i.e. dependent validation
|
|
||||||
case StructWithCustomByteArray:
|
|
||||||
return len(v.ID) >= v.CustomMinLength
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}))
|
|
||||||
```
|
|
||||||
|
|
||||||
###### Custom error messages
|
|
||||||
Custom error messages are supported via annotations by adding the `~` separator - here's an example of how to use it:
|
|
||||||
```go
|
|
||||||
type Ticket struct {
|
|
||||||
Id int64 `json:"id"`
|
|
||||||
FirstName string `json:"firstname" valid:"required~First name is blank"`
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Notes
|
|
||||||
Documentation is available here: [godoc.org](https://godoc.org/github.com/asaskevich/govalidator).
|
|
||||||
Full information about code coverage is also available here: [govalidator on gocover.io](http://gocover.io/github.com/asaskevich/govalidator).
|
|
||||||
|
|
||||||
#### Support
|
|
||||||
If you do have a contribution to the package, feel free to create a Pull Request or an Issue.
|
|
||||||
|
|
||||||
#### What to contribute
|
|
||||||
If you don't know what to do, there are some features and functions that need to be done
|
|
||||||
|
|
||||||
- [ ] Refactor code
|
|
||||||
- [ ] Edit docs and [README](https://github.com/asaskevich/govalidator/README.md): spellcheck, grammar and typo check
|
|
||||||
- [ ] Create actual list of contributors and projects that currently using this package
|
|
||||||
- [ ] Resolve [issues and bugs](https://github.com/asaskevich/govalidator/issues)
|
|
||||||
- [ ] Update actual [list of functions](https://github.com/asaskevich/govalidator#list-of-functions)
|
|
||||||
- [ ] Update [list of validators](https://github.com/asaskevich/govalidator#validatestruct-2) that available for `ValidateStruct` and add new
|
|
||||||
- [ ] Implement new validators: `IsFQDN`, `IsIMEI`, `IsPostalCode`, `IsISIN`, `IsISRC` etc
|
|
||||||
- [ ] Implement [validation by maps](https://github.com/asaskevich/govalidator/issues/224)
|
|
||||||
- [ ] Implement fuzzing testing
|
|
||||||
- [ ] Implement some struct/map/array utilities
|
|
||||||
- [ ] Implement map/array validation
|
|
||||||
- [ ] Implement benchmarking
|
|
||||||
- [ ] Implement batch of examples
|
|
||||||
- [ ] Look at forks for new features and fixes
|
|
||||||
|
|
||||||
#### Advice
|
|
||||||
Feel free to create what you want, but keep in mind when you implement new features:
|
|
||||||
- Code must be clear and readable, names of variables/constants clearly describes what they are doing
|
|
||||||
- Public functions must be documented and described in source file and added to README.md to the list of available functions
|
|
||||||
- There are must be unit-tests for any new functions and improvements
|
|
||||||
|
|
||||||
## Credits
|
|
||||||
### Contributors
|
|
||||||
|
|
||||||
This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)].
|
|
||||||
|
|
||||||
#### Special thanks to [contributors](https://github.com/asaskevich/govalidator/graphs/contributors)
|
|
||||||
* [Daniel Lohse](https://github.com/annismckenzie)
|
|
||||||
* [Attila Oláh](https://github.com/attilaolah)
|
|
||||||
* [Daniel Korner](https://github.com/Dadie)
|
|
||||||
* [Steven Wilkin](https://github.com/stevenwilkin)
|
|
||||||
* [Deiwin Sarjas](https://github.com/deiwin)
|
|
||||||
* [Noah Shibley](https://github.com/slugmobile)
|
|
||||||
* [Nathan Davies](https://github.com/nathj07)
|
|
||||||
* [Matt Sanford](https://github.com/mzsanford)
|
|
||||||
* [Simon ccl1115](https://github.com/ccl1115)
|
|
||||||
|
|
||||||
<a href="graphs/contributors"><img src="https://opencollective.com/govalidator/contributors.svg?width=890" /></a>
|
|
||||||
|
|
||||||
|
|
||||||
### Backers
|
|
||||||
|
|
||||||
Thank you to all our backers! 🙏 [[Become a backer](https://opencollective.com/govalidator#backer)]
|
|
||||||
|
|
||||||
<a href="https://opencollective.com/govalidator#backers" target="_blank"><img src="https://opencollective.com/govalidator/backers.svg?width=890"></a>
|
|
||||||
|
|
||||||
|
|
||||||
### Sponsors
|
|
||||||
|
|
||||||
Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [[Become a sponsor](https://opencollective.com/govalidator#sponsor)]
|
|
||||||
|
|
||||||
<a href="https://opencollective.com/govalidator/sponsor/0/website" target="_blank"><img src="https://opencollective.com/govalidator/sponsor/0/avatar.svg"></a>
|
|
||||||
<a href="https://opencollective.com/govalidator/sponsor/1/website" target="_blank"><img src="https://opencollective.com/govalidator/sponsor/1/avatar.svg"></a>
|
|
||||||
<a href="https://opencollective.com/govalidator/sponsor/2/website" target="_blank"><img src="https://opencollective.com/govalidator/sponsor/2/avatar.svg"></a>
|
|
||||||
<a href="https://opencollective.com/govalidator/sponsor/3/website" target="_blank"><img src="https://opencollective.com/govalidator/sponsor/3/avatar.svg"></a>
|
|
||||||
<a href="https://opencollective.com/govalidator/sponsor/4/website" target="_blank"><img src="https://opencollective.com/govalidator/sponsor/4/avatar.svg"></a>
|
|
||||||
<a href="https://opencollective.com/govalidator/sponsor/5/website" target="_blank"><img src="https://opencollective.com/govalidator/sponsor/5/avatar.svg"></a>
|
|
||||||
<a href="https://opencollective.com/govalidator/sponsor/6/website" target="_blank"><img src="https://opencollective.com/govalidator/sponsor/6/avatar.svg"></a>
|
|
||||||
<a href="https://opencollective.com/govalidator/sponsor/7/website" target="_blank"><img src="https://opencollective.com/govalidator/sponsor/7/avatar.svg"></a>
|
|
||||||
<a href="https://opencollective.com/govalidator/sponsor/8/website" target="_blank"><img src="https://opencollective.com/govalidator/sponsor/8/avatar.svg"></a>
|
|
||||||
<a href="https://opencollective.com/govalidator/sponsor/9/website" target="_blank"><img src="https://opencollective.com/govalidator/sponsor/9/avatar.svg"></a>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## License
|
|
||||||
[](https://app.fossa.io/projects/git%2Bgithub.com%2Fasaskevich%2Fgovalidator?ref=badge_large)
|
|
||||||
58
vendor/github.com/asaskevich/govalidator/arrays.go
generated
vendored
58
vendor/github.com/asaskevich/govalidator/arrays.go
generated
vendored
@@ -1,58 +0,0 @@
|
|||||||
package govalidator
|
|
||||||
|
|
||||||
// Iterator is the function that accepts element of slice/array and its index
|
|
||||||
type Iterator func(interface{}, int)
|
|
||||||
|
|
||||||
// ResultIterator is the function that accepts element of slice/array and its index and returns any result
|
|
||||||
type ResultIterator func(interface{}, int) interface{}
|
|
||||||
|
|
||||||
// ConditionIterator is the function that accepts element of slice/array and its index and returns boolean
|
|
||||||
type ConditionIterator func(interface{}, int) bool
|
|
||||||
|
|
||||||
// Each iterates over the slice and apply Iterator to every item
|
|
||||||
func Each(array []interface{}, iterator Iterator) {
|
|
||||||
for index, data := range array {
|
|
||||||
iterator(data, index)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Map iterates over the slice and apply ResultIterator to every item. Returns new slice as a result.
|
|
||||||
func Map(array []interface{}, iterator ResultIterator) []interface{} {
|
|
||||||
var result = make([]interface{}, len(array))
|
|
||||||
for index, data := range array {
|
|
||||||
result[index] = iterator(data, index)
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find iterates over the slice and apply ConditionIterator to every item. Returns first item that meet ConditionIterator or nil otherwise.
|
|
||||||
func Find(array []interface{}, iterator ConditionIterator) interface{} {
|
|
||||||
for index, data := range array {
|
|
||||||
if iterator(data, index) {
|
|
||||||
return data
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Filter iterates over the slice and apply ConditionIterator to every item. Returns new slice.
|
|
||||||
func Filter(array []interface{}, iterator ConditionIterator) []interface{} {
|
|
||||||
var result = make([]interface{}, 0)
|
|
||||||
for index, data := range array {
|
|
||||||
if iterator(data, index) {
|
|
||||||
result = append(result, data)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
// Count iterates over the slice and apply ConditionIterator to every item. Returns count of items that meets ConditionIterator.
|
|
||||||
func Count(array []interface{}, iterator ConditionIterator) int {
|
|
||||||
count := 0
|
|
||||||
for index, data := range array {
|
|
||||||
if iterator(data, index) {
|
|
||||||
count = count + 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return count
|
|
||||||
}
|
|
||||||
64
vendor/github.com/asaskevich/govalidator/converter.go
generated
vendored
64
vendor/github.com/asaskevich/govalidator/converter.go
generated
vendored
@@ -1,64 +0,0 @@
|
|||||||
package govalidator
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"reflect"
|
|
||||||
"strconv"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ToString convert the input to a string.
|
|
||||||
func ToString(obj interface{}) string {
|
|
||||||
res := fmt.Sprintf("%v", obj)
|
|
||||||
return string(res)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ToJSON convert the input to a valid JSON string
|
|
||||||
func ToJSON(obj interface{}) (string, error) {
|
|
||||||
res, err := json.Marshal(obj)
|
|
||||||
if err != nil {
|
|
||||||
res = []byte("")
|
|
||||||
}
|
|
||||||
return string(res), err
|
|
||||||
}
|
|
||||||
|
|
||||||
// ToFloat convert the input string to a float, or 0.0 if the input is not a float.
|
|
||||||
func ToFloat(str string) (float64, error) {
|
|
||||||
res, err := strconv.ParseFloat(str, 64)
|
|
||||||
if err != nil {
|
|
||||||
res = 0.0
|
|
||||||
}
|
|
||||||
return res, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// ToInt convert the input string or any int type to an integer type 64, or 0 if the input is not an integer.
|
|
||||||
func ToInt(value interface{}) (res int64, err error) {
|
|
||||||
val := reflect.ValueOf(value)
|
|
||||||
|
|
||||||
switch value.(type) {
|
|
||||||
case int, int8, int16, int32, int64:
|
|
||||||
res = val.Int()
|
|
||||||
case uint, uint8, uint16, uint32, uint64:
|
|
||||||
res = int64(val.Uint())
|
|
||||||
case string:
|
|
||||||
if IsInt(val.String()) {
|
|
||||||
res, err = strconv.ParseInt(val.String(), 0, 64)
|
|
||||||
if err != nil {
|
|
||||||
res = 0
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
err = fmt.Errorf("math: square root of negative number %g", value)
|
|
||||||
res = 0
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
err = fmt.Errorf("math: square root of negative number %g", value)
|
|
||||||
res = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// ToBoolean convert the input string to a boolean.
|
|
||||||
func ToBoolean(str string) (bool, error) {
|
|
||||||
return strconv.ParseBool(str)
|
|
||||||
}
|
|
||||||
43
vendor/github.com/asaskevich/govalidator/error.go
generated
vendored
43
vendor/github.com/asaskevich/govalidator/error.go
generated
vendored
@@ -1,43 +0,0 @@
|
|||||||
package govalidator
|
|
||||||
|
|
||||||
import "strings"
|
|
||||||
|
|
||||||
// Errors is an array of multiple errors and conforms to the error interface.
|
|
||||||
type Errors []error
|
|
||||||
|
|
||||||
// Errors returns itself.
|
|
||||||
func (es Errors) Errors() []error {
|
|
||||||
return es
|
|
||||||
}
|
|
||||||
|
|
||||||
func (es Errors) Error() string {
|
|
||||||
var errs []string
|
|
||||||
for _, e := range es {
|
|
||||||
errs = append(errs, e.Error())
|
|
||||||
}
|
|
||||||
return strings.Join(errs, ";")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Error encapsulates a name, an error and whether there's a custom error message or not.
|
|
||||||
type Error struct {
|
|
||||||
Name string
|
|
||||||
Err error
|
|
||||||
CustomErrorMessageExists bool
|
|
||||||
|
|
||||||
// Validator indicates the name of the validator that failed
|
|
||||||
Validator string
|
|
||||||
Path []string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e Error) Error() string {
|
|
||||||
if e.CustomErrorMessageExists {
|
|
||||||
return e.Err.Error()
|
|
||||||
}
|
|
||||||
|
|
||||||
errName := e.Name
|
|
||||||
if len(e.Path) > 0 {
|
|
||||||
errName = strings.Join(append(e.Path, e.Name), ".")
|
|
||||||
}
|
|
||||||
|
|
||||||
return errName + ": " + e.Err.Error()
|
|
||||||
}
|
|
||||||
97
vendor/github.com/asaskevich/govalidator/numerics.go
generated
vendored
97
vendor/github.com/asaskevich/govalidator/numerics.go
generated
vendored
@@ -1,97 +0,0 @@
|
|||||||
package govalidator
|
|
||||||
|
|
||||||
import (
|
|
||||||
"math"
|
|
||||||
"reflect"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Abs returns absolute value of number
|
|
||||||
func Abs(value float64) float64 {
|
|
||||||
return math.Abs(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sign returns signum of number: 1 in case of value > 0, -1 in case of value < 0, 0 otherwise
|
|
||||||
func Sign(value float64) float64 {
|
|
||||||
if value > 0 {
|
|
||||||
return 1
|
|
||||||
} else if value < 0 {
|
|
||||||
return -1
|
|
||||||
} else {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsNegative returns true if value < 0
|
|
||||||
func IsNegative(value float64) bool {
|
|
||||||
return value < 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsPositive returns true if value > 0
|
|
||||||
func IsPositive(value float64) bool {
|
|
||||||
return value > 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsNonNegative returns true if value >= 0
|
|
||||||
func IsNonNegative(value float64) bool {
|
|
||||||
return value >= 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsNonPositive returns true if value <= 0
|
|
||||||
func IsNonPositive(value float64) bool {
|
|
||||||
return value <= 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// InRange returns true if value lies between left and right border
|
|
||||||
func InRangeInt(value, left, right interface{}) bool {
|
|
||||||
value64, _ := ToInt(value)
|
|
||||||
left64, _ := ToInt(left)
|
|
||||||
right64, _ := ToInt(right)
|
|
||||||
if left64 > right64 {
|
|
||||||
left64, right64 = right64, left64
|
|
||||||
}
|
|
||||||
return value64 >= left64 && value64 <= right64
|
|
||||||
}
|
|
||||||
|
|
||||||
// InRange returns true if value lies between left and right border
|
|
||||||
func InRangeFloat32(value, left, right float32) bool {
|
|
||||||
if left > right {
|
|
||||||
left, right = right, left
|
|
||||||
}
|
|
||||||
return value >= left && value <= right
|
|
||||||
}
|
|
||||||
|
|
||||||
// InRange returns true if value lies between left and right border
|
|
||||||
func InRangeFloat64(value, left, right float64) bool {
|
|
||||||
if left > right {
|
|
||||||
left, right = right, left
|
|
||||||
}
|
|
||||||
return value >= left && value <= right
|
|
||||||
}
|
|
||||||
|
|
||||||
// InRange returns true if value lies between left and right border, generic type to handle int, float32 or float64, all types must the same type
|
|
||||||
func InRange(value interface{}, left interface{}, right interface{}) bool {
|
|
||||||
|
|
||||||
reflectValue := reflect.TypeOf(value).Kind()
|
|
||||||
reflectLeft := reflect.TypeOf(left).Kind()
|
|
||||||
reflectRight := reflect.TypeOf(right).Kind()
|
|
||||||
|
|
||||||
if reflectValue == reflect.Int && reflectLeft == reflect.Int && reflectRight == reflect.Int {
|
|
||||||
return InRangeInt(value.(int), left.(int), right.(int))
|
|
||||||
} else if reflectValue == reflect.Float32 && reflectLeft == reflect.Float32 && reflectRight == reflect.Float32 {
|
|
||||||
return InRangeFloat32(value.(float32), left.(float32), right.(float32))
|
|
||||||
} else if reflectValue == reflect.Float64 && reflectLeft == reflect.Float64 && reflectRight == reflect.Float64 {
|
|
||||||
return InRangeFloat64(value.(float64), left.(float64), right.(float64))
|
|
||||||
} else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsWhole returns true if value is whole number
|
|
||||||
func IsWhole(value float64) bool {
|
|
||||||
return math.Remainder(value, 1) == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsNatural returns true if value is natural number (positive and whole)
|
|
||||||
func IsNatural(value float64) bool {
|
|
||||||
return IsWhole(value) && IsPositive(value)
|
|
||||||
}
|
|
||||||
101
vendor/github.com/asaskevich/govalidator/patterns.go
generated
vendored
101
vendor/github.com/asaskevich/govalidator/patterns.go
generated
vendored
@@ -1,101 +0,0 @@
|
|||||||
package govalidator
|
|
||||||
|
|
||||||
import "regexp"
|
|
||||||
|
|
||||||
// Basic regular expressions for validating strings
|
|
||||||
const (
|
|
||||||
Email string = "^(((([a-zA-Z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])+(\\.([a-zA-Z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])+)*)|((\\x22)((((\\x20|\\x09)*(\\x0d\\x0a))?(\\x20|\\x09)+)?(([\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]|\\x21|[\\x23-\\x5b]|[\\x5d-\\x7e]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(\\([\\x01-\\x09\\x0b\\x0c\\x0d-\\x7f]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}]))))*(((\\x20|\\x09)*(\\x0d\\x0a))?(\\x20|\\x09)+)?(\\x22)))@((([a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(([a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])([a-zA-Z]|\\d|-|\\.|_|~|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])*([a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])))\\.)+(([a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(([a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])([a-zA-Z]|\\d|-|_|~|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])*([a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])))\\.?$"
|
|
||||||
CreditCard string = "^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|6(?:011|5[0-9][0-9])[0-9]{12}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35\\d{3})\\d{11})$"
|
|
||||||
ISBN10 string = "^(?:[0-9]{9}X|[0-9]{10})$"
|
|
||||||
ISBN13 string = "^(?:[0-9]{13})$"
|
|
||||||
UUID3 string = "^[0-9a-f]{8}-[0-9a-f]{4}-3[0-9a-f]{3}-[0-9a-f]{4}-[0-9a-f]{12}$"
|
|
||||||
UUID4 string = "^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$"
|
|
||||||
UUID5 string = "^[0-9a-f]{8}-[0-9a-f]{4}-5[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$"
|
|
||||||
UUID string = "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"
|
|
||||||
Alpha string = "^[a-zA-Z]+$"
|
|
||||||
Alphanumeric string = "^[a-zA-Z0-9]+$"
|
|
||||||
Numeric string = "^[0-9]+$"
|
|
||||||
Int string = "^(?:[-+]?(?:0|[1-9][0-9]*))$"
|
|
||||||
Float string = "^(?:[-+]?(?:[0-9]+))?(?:\\.[0-9]*)?(?:[eE][\\+\\-]?(?:[0-9]+))?$"
|
|
||||||
Hexadecimal string = "^[0-9a-fA-F]+$"
|
|
||||||
Hexcolor string = "^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$"
|
|
||||||
RGBcolor string = "^rgb\\(\\s*(0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*,\\s*(0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*,\\s*(0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*\\)$"
|
|
||||||
ASCII string = "^[\x00-\x7F]+$"
|
|
||||||
Multibyte string = "[^\x00-\x7F]"
|
|
||||||
FullWidth string = "[^\u0020-\u007E\uFF61-\uFF9F\uFFA0-\uFFDC\uFFE8-\uFFEE0-9a-zA-Z]"
|
|
||||||
HalfWidth string = "[\u0020-\u007E\uFF61-\uFF9F\uFFA0-\uFFDC\uFFE8-\uFFEE0-9a-zA-Z]"
|
|
||||||
Base64 string = "^(?:[A-Za-z0-9+\\/]{4})*(?:[A-Za-z0-9+\\/]{2}==|[A-Za-z0-9+\\/]{3}=|[A-Za-z0-9+\\/]{4})$"
|
|
||||||
PrintableASCII string = "^[\x20-\x7E]+$"
|
|
||||||
DataURI string = "^data:.+\\/(.+);base64$"
|
|
||||||
Latitude string = "^[-+]?([1-8]?\\d(\\.\\d+)?|90(\\.0+)?)$"
|
|
||||||
Longitude string = "^[-+]?(180(\\.0+)?|((1[0-7]\\d)|([1-9]?\\d))(\\.\\d+)?)$"
|
|
||||||
DNSName string = `^([a-zA-Z0-9_]{1}[a-zA-Z0-9_-]{0,62}){1}(\.[a-zA-Z0-9_]{1}[a-zA-Z0-9_-]{0,62})*[\._]?$`
|
|
||||||
IP string = `(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))`
|
|
||||||
URLSchema string = `((ftp|tcp|udp|wss?|https?):\/\/)`
|
|
||||||
URLUsername string = `(\S+(:\S*)?@)`
|
|
||||||
URLPath string = `((\/|\?|#)[^\s]*)`
|
|
||||||
URLPort string = `(:(\d{1,5}))`
|
|
||||||
URLIP string = `([1-9]\d?|1\d\d|2[01]\d|22[0-3])(\.(1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.([0-9]\d?|1\d\d|2[0-4]\d|25[0-4]))`
|
|
||||||
URLSubdomain string = `((www\.)|([a-zA-Z0-9]+([-_\.]?[a-zA-Z0-9])*[a-zA-Z0-9]\.[a-zA-Z0-9]+))`
|
|
||||||
URL string = `^` + URLSchema + `?` + URLUsername + `?` + `((` + URLIP + `|(\[` + IP + `\])|(([a-zA-Z0-9]([a-zA-Z0-9-_]+)?[a-zA-Z0-9]([-\.][a-zA-Z0-9]+)*)|(` + URLSubdomain + `?))?(([a-zA-Z\x{00a1}-\x{ffff}0-9]+-?-?)*[a-zA-Z\x{00a1}-\x{ffff}0-9]+)(?:\.([a-zA-Z\x{00a1}-\x{ffff}]{1,}))?))\.?` + URLPort + `?` + URLPath + `?$`
|
|
||||||
SSN string = `^\d{3}[- ]?\d{2}[- ]?\d{4}$`
|
|
||||||
WinPath string = `^[a-zA-Z]:\\(?:[^\\/:*?"<>|\r\n]+\\)*[^\\/:*?"<>|\r\n]*$`
|
|
||||||
UnixPath string = `^(/[^/\x00]*)+/?$`
|
|
||||||
Semver string = "^v?(?:0|[1-9]\\d*)\\.(?:0|[1-9]\\d*)\\.(?:0|[1-9]\\d*)(-(0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(\\.(0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*)?(\\+[0-9a-zA-Z-]+(\\.[0-9a-zA-Z-]+)*)?$"
|
|
||||||
tagName string = "valid"
|
|
||||||
hasLowerCase string = ".*[[:lower:]]"
|
|
||||||
hasUpperCase string = ".*[[:upper:]]"
|
|
||||||
hasWhitespace string = ".*[[:space:]]"
|
|
||||||
hasWhitespaceOnly string = "^[[:space:]]+$"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Used by IsFilePath func
|
|
||||||
const (
|
|
||||||
// Unknown is unresolved OS type
|
|
||||||
Unknown = iota
|
|
||||||
// Win is Windows type
|
|
||||||
Win
|
|
||||||
// Unix is *nix OS types
|
|
||||||
Unix
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
userRegexp = regexp.MustCompile("^[a-zA-Z0-9!#$%&'*+/=?^_`{|}~.-]+$")
|
|
||||||
hostRegexp = regexp.MustCompile("^[^\\s]+\\.[^\\s]+$")
|
|
||||||
userDotRegexp = regexp.MustCompile("(^[.]{1})|([.]{1}$)|([.]{2,})")
|
|
||||||
rxEmail = regexp.MustCompile(Email)
|
|
||||||
rxCreditCard = regexp.MustCompile(CreditCard)
|
|
||||||
rxISBN10 = regexp.MustCompile(ISBN10)
|
|
||||||
rxISBN13 = regexp.MustCompile(ISBN13)
|
|
||||||
rxUUID3 = regexp.MustCompile(UUID3)
|
|
||||||
rxUUID4 = regexp.MustCompile(UUID4)
|
|
||||||
rxUUID5 = regexp.MustCompile(UUID5)
|
|
||||||
rxUUID = regexp.MustCompile(UUID)
|
|
||||||
rxAlpha = regexp.MustCompile(Alpha)
|
|
||||||
rxAlphanumeric = regexp.MustCompile(Alphanumeric)
|
|
||||||
rxNumeric = regexp.MustCompile(Numeric)
|
|
||||||
rxInt = regexp.MustCompile(Int)
|
|
||||||
rxFloat = regexp.MustCompile(Float)
|
|
||||||
rxHexadecimal = regexp.MustCompile(Hexadecimal)
|
|
||||||
rxHexcolor = regexp.MustCompile(Hexcolor)
|
|
||||||
rxRGBcolor = regexp.MustCompile(RGBcolor)
|
|
||||||
rxASCII = regexp.MustCompile(ASCII)
|
|
||||||
rxPrintableASCII = regexp.MustCompile(PrintableASCII)
|
|
||||||
rxMultibyte = regexp.MustCompile(Multibyte)
|
|
||||||
rxFullWidth = regexp.MustCompile(FullWidth)
|
|
||||||
rxHalfWidth = regexp.MustCompile(HalfWidth)
|
|
||||||
rxBase64 = regexp.MustCompile(Base64)
|
|
||||||
rxDataURI = regexp.MustCompile(DataURI)
|
|
||||||
rxLatitude = regexp.MustCompile(Latitude)
|
|
||||||
rxLongitude = regexp.MustCompile(Longitude)
|
|
||||||
rxDNSName = regexp.MustCompile(DNSName)
|
|
||||||
rxURL = regexp.MustCompile(URL)
|
|
||||||
rxSSN = regexp.MustCompile(SSN)
|
|
||||||
rxWinPath = regexp.MustCompile(WinPath)
|
|
||||||
rxUnixPath = regexp.MustCompile(UnixPath)
|
|
||||||
rxSemver = regexp.MustCompile(Semver)
|
|
||||||
rxHasLowerCase = regexp.MustCompile(hasLowerCase)
|
|
||||||
rxHasUpperCase = regexp.MustCompile(hasUpperCase)
|
|
||||||
rxHasWhitespace = regexp.MustCompile(hasWhitespace)
|
|
||||||
rxHasWhitespaceOnly = regexp.MustCompile(hasWhitespaceOnly)
|
|
||||||
)
|
|
||||||
636
vendor/github.com/asaskevich/govalidator/types.go
generated
vendored
636
vendor/github.com/asaskevich/govalidator/types.go
generated
vendored
@@ -1,636 +0,0 @@
|
|||||||
package govalidator
|
|
||||||
|
|
||||||
import (
|
|
||||||
"reflect"
|
|
||||||
"regexp"
|
|
||||||
"sort"
|
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Validator is a wrapper for a validator function that returns bool and accepts string.
|
|
||||||
type Validator func(str string) bool
|
|
||||||
|
|
||||||
// CustomTypeValidator is a wrapper for validator functions that returns bool and accepts any type.
|
|
||||||
// The second parameter should be the context (in the case of validating a struct: the whole object being validated).
|
|
||||||
type CustomTypeValidator func(i interface{}, o interface{}) bool
|
|
||||||
|
|
||||||
// ParamValidator is a wrapper for validator functions that accepts additional parameters.
|
|
||||||
type ParamValidator func(str string, params ...string) bool
|
|
||||||
type tagOptionsMap map[string]tagOption
|
|
||||||
|
|
||||||
func (t tagOptionsMap) orderedKeys() []string {
|
|
||||||
var keys []string
|
|
||||||
for k := range t {
|
|
||||||
keys = append(keys, k)
|
|
||||||
}
|
|
||||||
|
|
||||||
sort.Slice(keys, func(a, b int) bool {
|
|
||||||
return t[keys[a]].order < t[keys[b]].order
|
|
||||||
})
|
|
||||||
|
|
||||||
return keys
|
|
||||||
}
|
|
||||||
|
|
||||||
type tagOption struct {
|
|
||||||
name string
|
|
||||||
customErrorMessage string
|
|
||||||
order int
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnsupportedTypeError is a wrapper for reflect.Type
|
|
||||||
type UnsupportedTypeError struct {
|
|
||||||
Type reflect.Type
|
|
||||||
}
|
|
||||||
|
|
||||||
// stringValues is a slice of reflect.Value holding *reflect.StringValue.
|
|
||||||
// It implements the methods to sort by string.
|
|
||||||
type stringValues []reflect.Value
|
|
||||||
|
|
||||||
// ParamTagMap is a map of functions accept variants parameters
|
|
||||||
var ParamTagMap = map[string]ParamValidator{
|
|
||||||
"length": ByteLength,
|
|
||||||
"range": Range,
|
|
||||||
"runelength": RuneLength,
|
|
||||||
"stringlength": StringLength,
|
|
||||||
"matches": StringMatches,
|
|
||||||
"in": isInRaw,
|
|
||||||
"rsapub": IsRsaPub,
|
|
||||||
}
|
|
||||||
|
|
||||||
// ParamTagRegexMap maps param tags to their respective regexes.
|
|
||||||
var ParamTagRegexMap = map[string]*regexp.Regexp{
|
|
||||||
"range": regexp.MustCompile("^range\\((\\d+)\\|(\\d+)\\)$"),
|
|
||||||
"length": regexp.MustCompile("^length\\((\\d+)\\|(\\d+)\\)$"),
|
|
||||||
"runelength": regexp.MustCompile("^runelength\\((\\d+)\\|(\\d+)\\)$"),
|
|
||||||
"stringlength": regexp.MustCompile("^stringlength\\((\\d+)\\|(\\d+)\\)$"),
|
|
||||||
"in": regexp.MustCompile(`^in\((.*)\)`),
|
|
||||||
"matches": regexp.MustCompile(`^matches\((.+)\)$`),
|
|
||||||
"rsapub": regexp.MustCompile("^rsapub\\((\\d+)\\)$"),
|
|
||||||
}
|
|
||||||
|
|
||||||
type customTypeTagMap struct {
|
|
||||||
validators map[string]CustomTypeValidator
|
|
||||||
|
|
||||||
sync.RWMutex
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tm *customTypeTagMap) Get(name string) (CustomTypeValidator, bool) {
|
|
||||||
tm.RLock()
|
|
||||||
defer tm.RUnlock()
|
|
||||||
v, ok := tm.validators[name]
|
|
||||||
return v, ok
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tm *customTypeTagMap) Set(name string, ctv CustomTypeValidator) {
|
|
||||||
tm.Lock()
|
|
||||||
defer tm.Unlock()
|
|
||||||
tm.validators[name] = ctv
|
|
||||||
}
|
|
||||||
|
|
||||||
// CustomTypeTagMap is a map of functions that can be used as tags for ValidateStruct function.
|
|
||||||
// Use this to validate compound or custom types that need to be handled as a whole, e.g.
|
|
||||||
// `type UUID [16]byte` (this would be handled as an array of bytes).
|
|
||||||
var CustomTypeTagMap = &customTypeTagMap{validators: make(map[string]CustomTypeValidator)}
|
|
||||||
|
|
||||||
// TagMap is a map of functions, that can be used as tags for ValidateStruct function.
|
|
||||||
var TagMap = map[string]Validator{
|
|
||||||
"email": IsEmail,
|
|
||||||
"url": IsURL,
|
|
||||||
"dialstring": IsDialString,
|
|
||||||
"requrl": IsRequestURL,
|
|
||||||
"requri": IsRequestURI,
|
|
||||||
"alpha": IsAlpha,
|
|
||||||
"utfletter": IsUTFLetter,
|
|
||||||
"alphanum": IsAlphanumeric,
|
|
||||||
"utfletternum": IsUTFLetterNumeric,
|
|
||||||
"numeric": IsNumeric,
|
|
||||||
"utfnumeric": IsUTFNumeric,
|
|
||||||
"utfdigit": IsUTFDigit,
|
|
||||||
"hexadecimal": IsHexadecimal,
|
|
||||||
"hexcolor": IsHexcolor,
|
|
||||||
"rgbcolor": IsRGBcolor,
|
|
||||||
"lowercase": IsLowerCase,
|
|
||||||
"uppercase": IsUpperCase,
|
|
||||||
"int": IsInt,
|
|
||||||
"float": IsFloat,
|
|
||||||
"null": IsNull,
|
|
||||||
"uuid": IsUUID,
|
|
||||||
"uuidv3": IsUUIDv3,
|
|
||||||
"uuidv4": IsUUIDv4,
|
|
||||||
"uuidv5": IsUUIDv5,
|
|
||||||
"creditcard": IsCreditCard,
|
|
||||||
"isbn10": IsISBN10,
|
|
||||||
"isbn13": IsISBN13,
|
|
||||||
"json": IsJSON,
|
|
||||||
"multibyte": IsMultibyte,
|
|
||||||
"ascii": IsASCII,
|
|
||||||
"printableascii": IsPrintableASCII,
|
|
||||||
"fullwidth": IsFullWidth,
|
|
||||||
"halfwidth": IsHalfWidth,
|
|
||||||
"variablewidth": IsVariableWidth,
|
|
||||||
"base64": IsBase64,
|
|
||||||
"datauri": IsDataURI,
|
|
||||||
"ip": IsIP,
|
|
||||||
"port": IsPort,
|
|
||||||
"ipv4": IsIPv4,
|
|
||||||
"ipv6": IsIPv6,
|
|
||||||
"dns": IsDNSName,
|
|
||||||
"host": IsHost,
|
|
||||||
"mac": IsMAC,
|
|
||||||
"latitude": IsLatitude,
|
|
||||||
"longitude": IsLongitude,
|
|
||||||
"ssn": IsSSN,
|
|
||||||
"semver": IsSemver,
|
|
||||||
"rfc3339": IsRFC3339,
|
|
||||||
"rfc3339WithoutZone": IsRFC3339WithoutZone,
|
|
||||||
"ISO3166Alpha2": IsISO3166Alpha2,
|
|
||||||
"ISO3166Alpha3": IsISO3166Alpha3,
|
|
||||||
"ISO4217": IsISO4217,
|
|
||||||
}
|
|
||||||
|
|
||||||
// ISO3166Entry stores country codes
|
|
||||||
type ISO3166Entry struct {
|
|
||||||
EnglishShortName string
|
|
||||||
FrenchShortName string
|
|
||||||
Alpha2Code string
|
|
||||||
Alpha3Code string
|
|
||||||
Numeric string
|
|
||||||
}
|
|
||||||
|
|
||||||
//ISO3166List based on https://www.iso.org/obp/ui/#search/code/ Code Type "Officially Assigned Codes"
|
|
||||||
var ISO3166List = []ISO3166Entry{
|
|
||||||
{"Afghanistan", "Afghanistan (l')", "AF", "AFG", "004"},
|
|
||||||
{"Albania", "Albanie (l')", "AL", "ALB", "008"},
|
|
||||||
{"Antarctica", "Antarctique (l')", "AQ", "ATA", "010"},
|
|
||||||
{"Algeria", "Algérie (l')", "DZ", "DZA", "012"},
|
|
||||||
{"American Samoa", "Samoa américaines (les)", "AS", "ASM", "016"},
|
|
||||||
{"Andorra", "Andorre (l')", "AD", "AND", "020"},
|
|
||||||
{"Angola", "Angola (l')", "AO", "AGO", "024"},
|
|
||||||
{"Antigua and Barbuda", "Antigua-et-Barbuda", "AG", "ATG", "028"},
|
|
||||||
{"Azerbaijan", "Azerbaïdjan (l')", "AZ", "AZE", "031"},
|
|
||||||
{"Argentina", "Argentine (l')", "AR", "ARG", "032"},
|
|
||||||
{"Australia", "Australie (l')", "AU", "AUS", "036"},
|
|
||||||
{"Austria", "Autriche (l')", "AT", "AUT", "040"},
|
|
||||||
{"Bahamas (the)", "Bahamas (les)", "BS", "BHS", "044"},
|
|
||||||
{"Bahrain", "Bahreïn", "BH", "BHR", "048"},
|
|
||||||
{"Bangladesh", "Bangladesh (le)", "BD", "BGD", "050"},
|
|
||||||
{"Armenia", "Arménie (l')", "AM", "ARM", "051"},
|
|
||||||
{"Barbados", "Barbade (la)", "BB", "BRB", "052"},
|
|
||||||
{"Belgium", "Belgique (la)", "BE", "BEL", "056"},
|
|
||||||
{"Bermuda", "Bermudes (les)", "BM", "BMU", "060"},
|
|
||||||
{"Bhutan", "Bhoutan (le)", "BT", "BTN", "064"},
|
|
||||||
{"Bolivia (Plurinational State of)", "Bolivie (État plurinational de)", "BO", "BOL", "068"},
|
|
||||||
{"Bosnia and Herzegovina", "Bosnie-Herzégovine (la)", "BA", "BIH", "070"},
|
|
||||||
{"Botswana", "Botswana (le)", "BW", "BWA", "072"},
|
|
||||||
{"Bouvet Island", "Bouvet (l'Île)", "BV", "BVT", "074"},
|
|
||||||
{"Brazil", "Brésil (le)", "BR", "BRA", "076"},
|
|
||||||
{"Belize", "Belize (le)", "BZ", "BLZ", "084"},
|
|
||||||
{"British Indian Ocean Territory (the)", "Indien (le Territoire britannique de l'océan)", "IO", "IOT", "086"},
|
|
||||||
{"Solomon Islands", "Salomon (Îles)", "SB", "SLB", "090"},
|
|
||||||
{"Virgin Islands (British)", "Vierges britanniques (les Îles)", "VG", "VGB", "092"},
|
|
||||||
{"Brunei Darussalam", "Brunéi Darussalam (le)", "BN", "BRN", "096"},
|
|
||||||
{"Bulgaria", "Bulgarie (la)", "BG", "BGR", "100"},
|
|
||||||
{"Myanmar", "Myanmar (le)", "MM", "MMR", "104"},
|
|
||||||
{"Burundi", "Burundi (le)", "BI", "BDI", "108"},
|
|
||||||
{"Belarus", "Bélarus (le)", "BY", "BLR", "112"},
|
|
||||||
{"Cambodia", "Cambodge (le)", "KH", "KHM", "116"},
|
|
||||||
{"Cameroon", "Cameroun (le)", "CM", "CMR", "120"},
|
|
||||||
{"Canada", "Canada (le)", "CA", "CAN", "124"},
|
|
||||||
{"Cabo Verde", "Cabo Verde", "CV", "CPV", "132"},
|
|
||||||
{"Cayman Islands (the)", "Caïmans (les Îles)", "KY", "CYM", "136"},
|
|
||||||
{"Central African Republic (the)", "République centrafricaine (la)", "CF", "CAF", "140"},
|
|
||||||
{"Sri Lanka", "Sri Lanka", "LK", "LKA", "144"},
|
|
||||||
{"Chad", "Tchad (le)", "TD", "TCD", "148"},
|
|
||||||
{"Chile", "Chili (le)", "CL", "CHL", "152"},
|
|
||||||
{"China", "Chine (la)", "CN", "CHN", "156"},
|
|
||||||
{"Taiwan (Province of China)", "Taïwan (Province de Chine)", "TW", "TWN", "158"},
|
|
||||||
{"Christmas Island", "Christmas (l'Île)", "CX", "CXR", "162"},
|
|
||||||
{"Cocos (Keeling) Islands (the)", "Cocos (les Îles)/ Keeling (les Îles)", "CC", "CCK", "166"},
|
|
||||||
{"Colombia", "Colombie (la)", "CO", "COL", "170"},
|
|
||||||
{"Comoros (the)", "Comores (les)", "KM", "COM", "174"},
|
|
||||||
{"Mayotte", "Mayotte", "YT", "MYT", "175"},
|
|
||||||
{"Congo (the)", "Congo (le)", "CG", "COG", "178"},
|
|
||||||
{"Congo (the Democratic Republic of the)", "Congo (la République démocratique du)", "CD", "COD", "180"},
|
|
||||||
{"Cook Islands (the)", "Cook (les Îles)", "CK", "COK", "184"},
|
|
||||||
{"Costa Rica", "Costa Rica (le)", "CR", "CRI", "188"},
|
|
||||||
{"Croatia", "Croatie (la)", "HR", "HRV", "191"},
|
|
||||||
{"Cuba", "Cuba", "CU", "CUB", "192"},
|
|
||||||
{"Cyprus", "Chypre", "CY", "CYP", "196"},
|
|
||||||
{"Czech Republic (the)", "tchèque (la République)", "CZ", "CZE", "203"},
|
|
||||||
{"Benin", "Bénin (le)", "BJ", "BEN", "204"},
|
|
||||||
{"Denmark", "Danemark (le)", "DK", "DNK", "208"},
|
|
||||||
{"Dominica", "Dominique (la)", "DM", "DMA", "212"},
|
|
||||||
{"Dominican Republic (the)", "dominicaine (la République)", "DO", "DOM", "214"},
|
|
||||||
{"Ecuador", "Équateur (l')", "EC", "ECU", "218"},
|
|
||||||
{"El Salvador", "El Salvador", "SV", "SLV", "222"},
|
|
||||||
{"Equatorial Guinea", "Guinée équatoriale (la)", "GQ", "GNQ", "226"},
|
|
||||||
{"Ethiopia", "Éthiopie (l')", "ET", "ETH", "231"},
|
|
||||||
{"Eritrea", "Érythrée (l')", "ER", "ERI", "232"},
|
|
||||||
{"Estonia", "Estonie (l')", "EE", "EST", "233"},
|
|
||||||
{"Faroe Islands (the)", "Féroé (les Îles)", "FO", "FRO", "234"},
|
|
||||||
{"Falkland Islands (the) [Malvinas]", "Falkland (les Îles)/Malouines (les Îles)", "FK", "FLK", "238"},
|
|
||||||
{"South Georgia and the South Sandwich Islands", "Géorgie du Sud-et-les Îles Sandwich du Sud (la)", "GS", "SGS", "239"},
|
|
||||||
{"Fiji", "Fidji (les)", "FJ", "FJI", "242"},
|
|
||||||
{"Finland", "Finlande (la)", "FI", "FIN", "246"},
|
|
||||||
{"Åland Islands", "Åland(les Îles)", "AX", "ALA", "248"},
|
|
||||||
{"France", "France (la)", "FR", "FRA", "250"},
|
|
||||||
{"French Guiana", "Guyane française (la )", "GF", "GUF", "254"},
|
|
||||||
{"French Polynesia", "Polynésie française (la)", "PF", "PYF", "258"},
|
|
||||||
{"French Southern Territories (the)", "Terres australes françaises (les)", "TF", "ATF", "260"},
|
|
||||||
{"Djibouti", "Djibouti", "DJ", "DJI", "262"},
|
|
||||||
{"Gabon", "Gabon (le)", "GA", "GAB", "266"},
|
|
||||||
{"Georgia", "Géorgie (la)", "GE", "GEO", "268"},
|
|
||||||
{"Gambia (the)", "Gambie (la)", "GM", "GMB", "270"},
|
|
||||||
{"Palestine, State of", "Palestine, État de", "PS", "PSE", "275"},
|
|
||||||
{"Germany", "Allemagne (l')", "DE", "DEU", "276"},
|
|
||||||
{"Ghana", "Ghana (le)", "GH", "GHA", "288"},
|
|
||||||
{"Gibraltar", "Gibraltar", "GI", "GIB", "292"},
|
|
||||||
{"Kiribati", "Kiribati", "KI", "KIR", "296"},
|
|
||||||
{"Greece", "Grèce (la)", "GR", "GRC", "300"},
|
|
||||||
{"Greenland", "Groenland (le)", "GL", "GRL", "304"},
|
|
||||||
{"Grenada", "Grenade (la)", "GD", "GRD", "308"},
|
|
||||||
{"Guadeloupe", "Guadeloupe (la)", "GP", "GLP", "312"},
|
|
||||||
{"Guam", "Guam", "GU", "GUM", "316"},
|
|
||||||
{"Guatemala", "Guatemala (le)", "GT", "GTM", "320"},
|
|
||||||
{"Guinea", "Guinée (la)", "GN", "GIN", "324"},
|
|
||||||
{"Guyana", "Guyana (le)", "GY", "GUY", "328"},
|
|
||||||
{"Haiti", "Haïti", "HT", "HTI", "332"},
|
|
||||||
{"Heard Island and McDonald Islands", "Heard-et-Îles MacDonald (l'Île)", "HM", "HMD", "334"},
|
|
||||||
{"Holy See (the)", "Saint-Siège (le)", "VA", "VAT", "336"},
|
|
||||||
{"Honduras", "Honduras (le)", "HN", "HND", "340"},
|
|
||||||
{"Hong Kong", "Hong Kong", "HK", "HKG", "344"},
|
|
||||||
{"Hungary", "Hongrie (la)", "HU", "HUN", "348"},
|
|
||||||
{"Iceland", "Islande (l')", "IS", "ISL", "352"},
|
|
||||||
{"India", "Inde (l')", "IN", "IND", "356"},
|
|
||||||
{"Indonesia", "Indonésie (l')", "ID", "IDN", "360"},
|
|
||||||
{"Iran (Islamic Republic of)", "Iran (République Islamique d')", "IR", "IRN", "364"},
|
|
||||||
{"Iraq", "Iraq (l')", "IQ", "IRQ", "368"},
|
|
||||||
{"Ireland", "Irlande (l')", "IE", "IRL", "372"},
|
|
||||||
{"Israel", "Israël", "IL", "ISR", "376"},
|
|
||||||
{"Italy", "Italie (l')", "IT", "ITA", "380"},
|
|
||||||
{"Côte d'Ivoire", "Côte d'Ivoire (la)", "CI", "CIV", "384"},
|
|
||||||
{"Jamaica", "Jamaïque (la)", "JM", "JAM", "388"},
|
|
||||||
{"Japan", "Japon (le)", "JP", "JPN", "392"},
|
|
||||||
{"Kazakhstan", "Kazakhstan (le)", "KZ", "KAZ", "398"},
|
|
||||||
{"Jordan", "Jordanie (la)", "JO", "JOR", "400"},
|
|
||||||
{"Kenya", "Kenya (le)", "KE", "KEN", "404"},
|
|
||||||
{"Korea (the Democratic People's Republic of)", "Corée (la République populaire démocratique de)", "KP", "PRK", "408"},
|
|
||||||
{"Korea (the Republic of)", "Corée (la République de)", "KR", "KOR", "410"},
|
|
||||||
{"Kuwait", "Koweït (le)", "KW", "KWT", "414"},
|
|
||||||
{"Kyrgyzstan", "Kirghizistan (le)", "KG", "KGZ", "417"},
|
|
||||||
{"Lao People's Democratic Republic (the)", "Lao, République démocratique populaire", "LA", "LAO", "418"},
|
|
||||||
{"Lebanon", "Liban (le)", "LB", "LBN", "422"},
|
|
||||||
{"Lesotho", "Lesotho (le)", "LS", "LSO", "426"},
|
|
||||||
{"Latvia", "Lettonie (la)", "LV", "LVA", "428"},
|
|
||||||
{"Liberia", "Libéria (le)", "LR", "LBR", "430"},
|
|
||||||
{"Libya", "Libye (la)", "LY", "LBY", "434"},
|
|
||||||
{"Liechtenstein", "Liechtenstein (le)", "LI", "LIE", "438"},
|
|
||||||
{"Lithuania", "Lituanie (la)", "LT", "LTU", "440"},
|
|
||||||
{"Luxembourg", "Luxembourg (le)", "LU", "LUX", "442"},
|
|
||||||
{"Macao", "Macao", "MO", "MAC", "446"},
|
|
||||||
{"Madagascar", "Madagascar", "MG", "MDG", "450"},
|
|
||||||
{"Malawi", "Malawi (le)", "MW", "MWI", "454"},
|
|
||||||
{"Malaysia", "Malaisie (la)", "MY", "MYS", "458"},
|
|
||||||
{"Maldives", "Maldives (les)", "MV", "MDV", "462"},
|
|
||||||
{"Mali", "Mali (le)", "ML", "MLI", "466"},
|
|
||||||
{"Malta", "Malte", "MT", "MLT", "470"},
|
|
||||||
{"Martinique", "Martinique (la)", "MQ", "MTQ", "474"},
|
|
||||||
{"Mauritania", "Mauritanie (la)", "MR", "MRT", "478"},
|
|
||||||
{"Mauritius", "Maurice", "MU", "MUS", "480"},
|
|
||||||
{"Mexico", "Mexique (le)", "MX", "MEX", "484"},
|
|
||||||
{"Monaco", "Monaco", "MC", "MCO", "492"},
|
|
||||||
{"Mongolia", "Mongolie (la)", "MN", "MNG", "496"},
|
|
||||||
{"Moldova (the Republic of)", "Moldova , République de", "MD", "MDA", "498"},
|
|
||||||
{"Montenegro", "Monténégro (le)", "ME", "MNE", "499"},
|
|
||||||
{"Montserrat", "Montserrat", "MS", "MSR", "500"},
|
|
||||||
{"Morocco", "Maroc (le)", "MA", "MAR", "504"},
|
|
||||||
{"Mozambique", "Mozambique (le)", "MZ", "MOZ", "508"},
|
|
||||||
{"Oman", "Oman", "OM", "OMN", "512"},
|
|
||||||
{"Namibia", "Namibie (la)", "NA", "NAM", "516"},
|
|
||||||
{"Nauru", "Nauru", "NR", "NRU", "520"},
|
|
||||||
{"Nepal", "Népal (le)", "NP", "NPL", "524"},
|
|
||||||
{"Netherlands (the)", "Pays-Bas (les)", "NL", "NLD", "528"},
|
|
||||||
{"Curaçao", "Curaçao", "CW", "CUW", "531"},
|
|
||||||
{"Aruba", "Aruba", "AW", "ABW", "533"},
|
|
||||||
{"Sint Maarten (Dutch part)", "Saint-Martin (partie néerlandaise)", "SX", "SXM", "534"},
|
|
||||||
{"Bonaire, Sint Eustatius and Saba", "Bonaire, Saint-Eustache et Saba", "BQ", "BES", "535"},
|
|
||||||
{"New Caledonia", "Nouvelle-Calédonie (la)", "NC", "NCL", "540"},
|
|
||||||
{"Vanuatu", "Vanuatu (le)", "VU", "VUT", "548"},
|
|
||||||
{"New Zealand", "Nouvelle-Zélande (la)", "NZ", "NZL", "554"},
|
|
||||||
{"Nicaragua", "Nicaragua (le)", "NI", "NIC", "558"},
|
|
||||||
{"Niger (the)", "Niger (le)", "NE", "NER", "562"},
|
|
||||||
{"Nigeria", "Nigéria (le)", "NG", "NGA", "566"},
|
|
||||||
{"Niue", "Niue", "NU", "NIU", "570"},
|
|
||||||
{"Norfolk Island", "Norfolk (l'Île)", "NF", "NFK", "574"},
|
|
||||||
{"Norway", "Norvège (la)", "NO", "NOR", "578"},
|
|
||||||
{"Northern Mariana Islands (the)", "Mariannes du Nord (les Îles)", "MP", "MNP", "580"},
|
|
||||||
{"United States Minor Outlying Islands (the)", "Îles mineures éloignées des États-Unis (les)", "UM", "UMI", "581"},
|
|
||||||
{"Micronesia (Federated States of)", "Micronésie (États fédérés de)", "FM", "FSM", "583"},
|
|
||||||
{"Marshall Islands (the)", "Marshall (Îles)", "MH", "MHL", "584"},
|
|
||||||
{"Palau", "Palaos (les)", "PW", "PLW", "585"},
|
|
||||||
{"Pakistan", "Pakistan (le)", "PK", "PAK", "586"},
|
|
||||||
{"Panama", "Panama (le)", "PA", "PAN", "591"},
|
|
||||||
{"Papua New Guinea", "Papouasie-Nouvelle-Guinée (la)", "PG", "PNG", "598"},
|
|
||||||
{"Paraguay", "Paraguay (le)", "PY", "PRY", "600"},
|
|
||||||
{"Peru", "Pérou (le)", "PE", "PER", "604"},
|
|
||||||
{"Philippines (the)", "Philippines (les)", "PH", "PHL", "608"},
|
|
||||||
{"Pitcairn", "Pitcairn", "PN", "PCN", "612"},
|
|
||||||
{"Poland", "Pologne (la)", "PL", "POL", "616"},
|
|
||||||
{"Portugal", "Portugal (le)", "PT", "PRT", "620"},
|
|
||||||
{"Guinea-Bissau", "Guinée-Bissau (la)", "GW", "GNB", "624"},
|
|
||||||
{"Timor-Leste", "Timor-Leste (le)", "TL", "TLS", "626"},
|
|
||||||
{"Puerto Rico", "Porto Rico", "PR", "PRI", "630"},
|
|
||||||
{"Qatar", "Qatar (le)", "QA", "QAT", "634"},
|
|
||||||
{"Réunion", "Réunion (La)", "RE", "REU", "638"},
|
|
||||||
{"Romania", "Roumanie (la)", "RO", "ROU", "642"},
|
|
||||||
{"Russian Federation (the)", "Russie (la Fédération de)", "RU", "RUS", "643"},
|
|
||||||
{"Rwanda", "Rwanda (le)", "RW", "RWA", "646"},
|
|
||||||
{"Saint Barthélemy", "Saint-Barthélemy", "BL", "BLM", "652"},
|
|
||||||
{"Saint Helena, Ascension and Tristan da Cunha", "Sainte-Hélène, Ascension et Tristan da Cunha", "SH", "SHN", "654"},
|
|
||||||
{"Saint Kitts and Nevis", "Saint-Kitts-et-Nevis", "KN", "KNA", "659"},
|
|
||||||
{"Anguilla", "Anguilla", "AI", "AIA", "660"},
|
|
||||||
{"Saint Lucia", "Sainte-Lucie", "LC", "LCA", "662"},
|
|
||||||
{"Saint Martin (French part)", "Saint-Martin (partie française)", "MF", "MAF", "663"},
|
|
||||||
{"Saint Pierre and Miquelon", "Saint-Pierre-et-Miquelon", "PM", "SPM", "666"},
|
|
||||||
{"Saint Vincent and the Grenadines", "Saint-Vincent-et-les Grenadines", "VC", "VCT", "670"},
|
|
||||||
{"San Marino", "Saint-Marin", "SM", "SMR", "674"},
|
|
||||||
{"Sao Tome and Principe", "Sao Tomé-et-Principe", "ST", "STP", "678"},
|
|
||||||
{"Saudi Arabia", "Arabie saoudite (l')", "SA", "SAU", "682"},
|
|
||||||
{"Senegal", "Sénégal (le)", "SN", "SEN", "686"},
|
|
||||||
{"Serbia", "Serbie (la)", "RS", "SRB", "688"},
|
|
||||||
{"Seychelles", "Seychelles (les)", "SC", "SYC", "690"},
|
|
||||||
{"Sierra Leone", "Sierra Leone (la)", "SL", "SLE", "694"},
|
|
||||||
{"Singapore", "Singapour", "SG", "SGP", "702"},
|
|
||||||
{"Slovakia", "Slovaquie (la)", "SK", "SVK", "703"},
|
|
||||||
{"Viet Nam", "Viet Nam (le)", "VN", "VNM", "704"},
|
|
||||||
{"Slovenia", "Slovénie (la)", "SI", "SVN", "705"},
|
|
||||||
{"Somalia", "Somalie (la)", "SO", "SOM", "706"},
|
|
||||||
{"South Africa", "Afrique du Sud (l')", "ZA", "ZAF", "710"},
|
|
||||||
{"Zimbabwe", "Zimbabwe (le)", "ZW", "ZWE", "716"},
|
|
||||||
{"Spain", "Espagne (l')", "ES", "ESP", "724"},
|
|
||||||
{"South Sudan", "Soudan du Sud (le)", "SS", "SSD", "728"},
|
|
||||||
{"Sudan (the)", "Soudan (le)", "SD", "SDN", "729"},
|
|
||||||
{"Western Sahara*", "Sahara occidental (le)*", "EH", "ESH", "732"},
|
|
||||||
{"Suriname", "Suriname (le)", "SR", "SUR", "740"},
|
|
||||||
{"Svalbard and Jan Mayen", "Svalbard et l'Île Jan Mayen (le)", "SJ", "SJM", "744"},
|
|
||||||
{"Swaziland", "Swaziland (le)", "SZ", "SWZ", "748"},
|
|
||||||
{"Sweden", "Suède (la)", "SE", "SWE", "752"},
|
|
||||||
{"Switzerland", "Suisse (la)", "CH", "CHE", "756"},
|
|
||||||
{"Syrian Arab Republic", "République arabe syrienne (la)", "SY", "SYR", "760"},
|
|
||||||
{"Tajikistan", "Tadjikistan (le)", "TJ", "TJK", "762"},
|
|
||||||
{"Thailand", "Thaïlande (la)", "TH", "THA", "764"},
|
|
||||||
{"Togo", "Togo (le)", "TG", "TGO", "768"},
|
|
||||||
{"Tokelau", "Tokelau (les)", "TK", "TKL", "772"},
|
|
||||||
{"Tonga", "Tonga (les)", "TO", "TON", "776"},
|
|
||||||
{"Trinidad and Tobago", "Trinité-et-Tobago (la)", "TT", "TTO", "780"},
|
|
||||||
{"United Arab Emirates (the)", "Émirats arabes unis (les)", "AE", "ARE", "784"},
|
|
||||||
{"Tunisia", "Tunisie (la)", "TN", "TUN", "788"},
|
|
||||||
{"Turkey", "Turquie (la)", "TR", "TUR", "792"},
|
|
||||||
{"Turkmenistan", "Turkménistan (le)", "TM", "TKM", "795"},
|
|
||||||
{"Turks and Caicos Islands (the)", "Turks-et-Caïcos (les Îles)", "TC", "TCA", "796"},
|
|
||||||
{"Tuvalu", "Tuvalu (les)", "TV", "TUV", "798"},
|
|
||||||
{"Uganda", "Ouganda (l')", "UG", "UGA", "800"},
|
|
||||||
{"Ukraine", "Ukraine (l')", "UA", "UKR", "804"},
|
|
||||||
{"Macedonia (the former Yugoslav Republic of)", "Macédoine (l'ex‑République yougoslave de)", "MK", "MKD", "807"},
|
|
||||||
{"Egypt", "Égypte (l')", "EG", "EGY", "818"},
|
|
||||||
{"United Kingdom of Great Britain and Northern Ireland (the)", "Royaume-Uni de Grande-Bretagne et d'Irlande du Nord (le)", "GB", "GBR", "826"},
|
|
||||||
{"Guernsey", "Guernesey", "GG", "GGY", "831"},
|
|
||||||
{"Jersey", "Jersey", "JE", "JEY", "832"},
|
|
||||||
{"Isle of Man", "Île de Man", "IM", "IMN", "833"},
|
|
||||||
{"Tanzania, United Republic of", "Tanzanie, République-Unie de", "TZ", "TZA", "834"},
|
|
||||||
{"United States of America (the)", "États-Unis d'Amérique (les)", "US", "USA", "840"},
|
|
||||||
{"Virgin Islands (U.S.)", "Vierges des États-Unis (les Îles)", "VI", "VIR", "850"},
|
|
||||||
{"Burkina Faso", "Burkina Faso (le)", "BF", "BFA", "854"},
|
|
||||||
{"Uruguay", "Uruguay (l')", "UY", "URY", "858"},
|
|
||||||
{"Uzbekistan", "Ouzbékistan (l')", "UZ", "UZB", "860"},
|
|
||||||
{"Venezuela (Bolivarian Republic of)", "Venezuela (République bolivarienne du)", "VE", "VEN", "862"},
|
|
||||||
{"Wallis and Futuna", "Wallis-et-Futuna", "WF", "WLF", "876"},
|
|
||||||
{"Samoa", "Samoa (le)", "WS", "WSM", "882"},
|
|
||||||
{"Yemen", "Yémen (le)", "YE", "YEM", "887"},
|
|
||||||
{"Zambia", "Zambie (la)", "ZM", "ZMB", "894"},
|
|
||||||
}
|
|
||||||
|
|
||||||
// ISO4217List is the list of ISO currency codes
|
|
||||||
var ISO4217List = []string{
|
|
||||||
"AED", "AFN", "ALL", "AMD", "ANG", "AOA", "ARS", "AUD", "AWG", "AZN",
|
|
||||||
"BAM", "BBD", "BDT", "BGN", "BHD", "BIF", "BMD", "BND", "BOB", "BOV", "BRL", "BSD", "BTN", "BWP", "BYN", "BZD",
|
|
||||||
"CAD", "CDF", "CHE", "CHF", "CHW", "CLF", "CLP", "CNY", "COP", "COU", "CRC", "CUC", "CUP", "CVE", "CZK",
|
|
||||||
"DJF", "DKK", "DOP", "DZD",
|
|
||||||
"EGP", "ERN", "ETB", "EUR",
|
|
||||||
"FJD", "FKP",
|
|
||||||
"GBP", "GEL", "GHS", "GIP", "GMD", "GNF", "GTQ", "GYD",
|
|
||||||
"HKD", "HNL", "HRK", "HTG", "HUF",
|
|
||||||
"IDR", "ILS", "INR", "IQD", "IRR", "ISK",
|
|
||||||
"JMD", "JOD", "JPY",
|
|
||||||
"KES", "KGS", "KHR", "KMF", "KPW", "KRW", "KWD", "KYD", "KZT",
|
|
||||||
"LAK", "LBP", "LKR", "LRD", "LSL", "LYD",
|
|
||||||
"MAD", "MDL", "MGA", "MKD", "MMK", "MNT", "MOP", "MRO", "MUR", "MVR", "MWK", "MXN", "MXV", "MYR", "MZN",
|
|
||||||
"NAD", "NGN", "NIO", "NOK", "NPR", "NZD",
|
|
||||||
"OMR",
|
|
||||||
"PAB", "PEN", "PGK", "PHP", "PKR", "PLN", "PYG",
|
|
||||||
"QAR",
|
|
||||||
"RON", "RSD", "RUB", "RWF",
|
|
||||||
"SAR", "SBD", "SCR", "SDG", "SEK", "SGD", "SHP", "SLL", "SOS", "SRD", "SSP", "STD", "SVC", "SYP", "SZL",
|
|
||||||
"THB", "TJS", "TMT", "TND", "TOP", "TRY", "TTD", "TWD", "TZS",
|
|
||||||
"UAH", "UGX", "USD", "USN", "UYI", "UYU", "UZS",
|
|
||||||
"VEF", "VND", "VUV",
|
|
||||||
"WST",
|
|
||||||
"XAF", "XAG", "XAU", "XBA", "XBB", "XBC", "XBD", "XCD", "XDR", "XOF", "XPD", "XPF", "XPT", "XSU", "XTS", "XUA", "XXX",
|
|
||||||
"YER",
|
|
||||||
"ZAR", "ZMW", "ZWL",
|
|
||||||
}
|
|
||||||
|
|
||||||
// ISO693Entry stores ISO language codes
|
|
||||||
type ISO693Entry struct {
|
|
||||||
Alpha3bCode string
|
|
||||||
Alpha2Code string
|
|
||||||
English string
|
|
||||||
}
|
|
||||||
|
|
||||||
//ISO693List based on http://data.okfn.org/data/core/language-codes/r/language-codes-3b2.json
|
|
||||||
var ISO693List = []ISO693Entry{
|
|
||||||
{Alpha3bCode: "aar", Alpha2Code: "aa", English: "Afar"},
|
|
||||||
{Alpha3bCode: "abk", Alpha2Code: "ab", English: "Abkhazian"},
|
|
||||||
{Alpha3bCode: "afr", Alpha2Code: "af", English: "Afrikaans"},
|
|
||||||
{Alpha3bCode: "aka", Alpha2Code: "ak", English: "Akan"},
|
|
||||||
{Alpha3bCode: "alb", Alpha2Code: "sq", English: "Albanian"},
|
|
||||||
{Alpha3bCode: "amh", Alpha2Code: "am", English: "Amharic"},
|
|
||||||
{Alpha3bCode: "ara", Alpha2Code: "ar", English: "Arabic"},
|
|
||||||
{Alpha3bCode: "arg", Alpha2Code: "an", English: "Aragonese"},
|
|
||||||
{Alpha3bCode: "arm", Alpha2Code: "hy", English: "Armenian"},
|
|
||||||
{Alpha3bCode: "asm", Alpha2Code: "as", English: "Assamese"},
|
|
||||||
{Alpha3bCode: "ava", Alpha2Code: "av", English: "Avaric"},
|
|
||||||
{Alpha3bCode: "ave", Alpha2Code: "ae", English: "Avestan"},
|
|
||||||
{Alpha3bCode: "aym", Alpha2Code: "ay", English: "Aymara"},
|
|
||||||
{Alpha3bCode: "aze", Alpha2Code: "az", English: "Azerbaijani"},
|
|
||||||
{Alpha3bCode: "bak", Alpha2Code: "ba", English: "Bashkir"},
|
|
||||||
{Alpha3bCode: "bam", Alpha2Code: "bm", English: "Bambara"},
|
|
||||||
{Alpha3bCode: "baq", Alpha2Code: "eu", English: "Basque"},
|
|
||||||
{Alpha3bCode: "bel", Alpha2Code: "be", English: "Belarusian"},
|
|
||||||
{Alpha3bCode: "ben", Alpha2Code: "bn", English: "Bengali"},
|
|
||||||
{Alpha3bCode: "bih", Alpha2Code: "bh", English: "Bihari languages"},
|
|
||||||
{Alpha3bCode: "bis", Alpha2Code: "bi", English: "Bislama"},
|
|
||||||
{Alpha3bCode: "bos", Alpha2Code: "bs", English: "Bosnian"},
|
|
||||||
{Alpha3bCode: "bre", Alpha2Code: "br", English: "Breton"},
|
|
||||||
{Alpha3bCode: "bul", Alpha2Code: "bg", English: "Bulgarian"},
|
|
||||||
{Alpha3bCode: "bur", Alpha2Code: "my", English: "Burmese"},
|
|
||||||
{Alpha3bCode: "cat", Alpha2Code: "ca", English: "Catalan; Valencian"},
|
|
||||||
{Alpha3bCode: "cha", Alpha2Code: "ch", English: "Chamorro"},
|
|
||||||
{Alpha3bCode: "che", Alpha2Code: "ce", English: "Chechen"},
|
|
||||||
{Alpha3bCode: "chi", Alpha2Code: "zh", English: "Chinese"},
|
|
||||||
{Alpha3bCode: "chu", Alpha2Code: "cu", English: "Church Slavic; Old Slavonic; Church Slavonic; Old Bulgarian; Old Church Slavonic"},
|
|
||||||
{Alpha3bCode: "chv", Alpha2Code: "cv", English: "Chuvash"},
|
|
||||||
{Alpha3bCode: "cor", Alpha2Code: "kw", English: "Cornish"},
|
|
||||||
{Alpha3bCode: "cos", Alpha2Code: "co", English: "Corsican"},
|
|
||||||
{Alpha3bCode: "cre", Alpha2Code: "cr", English: "Cree"},
|
|
||||||
{Alpha3bCode: "cze", Alpha2Code: "cs", English: "Czech"},
|
|
||||||
{Alpha3bCode: "dan", Alpha2Code: "da", English: "Danish"},
|
|
||||||
{Alpha3bCode: "div", Alpha2Code: "dv", English: "Divehi; Dhivehi; Maldivian"},
|
|
||||||
{Alpha3bCode: "dut", Alpha2Code: "nl", English: "Dutch; Flemish"},
|
|
||||||
{Alpha3bCode: "dzo", Alpha2Code: "dz", English: "Dzongkha"},
|
|
||||||
{Alpha3bCode: "eng", Alpha2Code: "en", English: "English"},
|
|
||||||
{Alpha3bCode: "epo", Alpha2Code: "eo", English: "Esperanto"},
|
|
||||||
{Alpha3bCode: "est", Alpha2Code: "et", English: "Estonian"},
|
|
||||||
{Alpha3bCode: "ewe", Alpha2Code: "ee", English: "Ewe"},
|
|
||||||
{Alpha3bCode: "fao", Alpha2Code: "fo", English: "Faroese"},
|
|
||||||
{Alpha3bCode: "fij", Alpha2Code: "fj", English: "Fijian"},
|
|
||||||
{Alpha3bCode: "fin", Alpha2Code: "fi", English: "Finnish"},
|
|
||||||
{Alpha3bCode: "fre", Alpha2Code: "fr", English: "French"},
|
|
||||||
{Alpha3bCode: "fry", Alpha2Code: "fy", English: "Western Frisian"},
|
|
||||||
{Alpha3bCode: "ful", Alpha2Code: "ff", English: "Fulah"},
|
|
||||||
{Alpha3bCode: "geo", Alpha2Code: "ka", English: "Georgian"},
|
|
||||||
{Alpha3bCode: "ger", Alpha2Code: "de", English: "German"},
|
|
||||||
{Alpha3bCode: "gla", Alpha2Code: "gd", English: "Gaelic; Scottish Gaelic"},
|
|
||||||
{Alpha3bCode: "gle", Alpha2Code: "ga", English: "Irish"},
|
|
||||||
{Alpha3bCode: "glg", Alpha2Code: "gl", English: "Galician"},
|
|
||||||
{Alpha3bCode: "glv", Alpha2Code: "gv", English: "Manx"},
|
|
||||||
{Alpha3bCode: "gre", Alpha2Code: "el", English: "Greek, Modern (1453-)"},
|
|
||||||
{Alpha3bCode: "grn", Alpha2Code: "gn", English: "Guarani"},
|
|
||||||
{Alpha3bCode: "guj", Alpha2Code: "gu", English: "Gujarati"},
|
|
||||||
{Alpha3bCode: "hat", Alpha2Code: "ht", English: "Haitian; Haitian Creole"},
|
|
||||||
{Alpha3bCode: "hau", Alpha2Code: "ha", English: "Hausa"},
|
|
||||||
{Alpha3bCode: "heb", Alpha2Code: "he", English: "Hebrew"},
|
|
||||||
{Alpha3bCode: "her", Alpha2Code: "hz", English: "Herero"},
|
|
||||||
{Alpha3bCode: "hin", Alpha2Code: "hi", English: "Hindi"},
|
|
||||||
{Alpha3bCode: "hmo", Alpha2Code: "ho", English: "Hiri Motu"},
|
|
||||||
{Alpha3bCode: "hrv", Alpha2Code: "hr", English: "Croatian"},
|
|
||||||
{Alpha3bCode: "hun", Alpha2Code: "hu", English: "Hungarian"},
|
|
||||||
{Alpha3bCode: "ibo", Alpha2Code: "ig", English: "Igbo"},
|
|
||||||
{Alpha3bCode: "ice", Alpha2Code: "is", English: "Icelandic"},
|
|
||||||
{Alpha3bCode: "ido", Alpha2Code: "io", English: "Ido"},
|
|
||||||
{Alpha3bCode: "iii", Alpha2Code: "ii", English: "Sichuan Yi; Nuosu"},
|
|
||||||
{Alpha3bCode: "iku", Alpha2Code: "iu", English: "Inuktitut"},
|
|
||||||
{Alpha3bCode: "ile", Alpha2Code: "ie", English: "Interlingue; Occidental"},
|
|
||||||
{Alpha3bCode: "ina", Alpha2Code: "ia", English: "Interlingua (International Auxiliary Language Association)"},
|
|
||||||
{Alpha3bCode: "ind", Alpha2Code: "id", English: "Indonesian"},
|
|
||||||
{Alpha3bCode: "ipk", Alpha2Code: "ik", English: "Inupiaq"},
|
|
||||||
{Alpha3bCode: "ita", Alpha2Code: "it", English: "Italian"},
|
|
||||||
{Alpha3bCode: "jav", Alpha2Code: "jv", English: "Javanese"},
|
|
||||||
{Alpha3bCode: "jpn", Alpha2Code: "ja", English: "Japanese"},
|
|
||||||
{Alpha3bCode: "kal", Alpha2Code: "kl", English: "Kalaallisut; Greenlandic"},
|
|
||||||
{Alpha3bCode: "kan", Alpha2Code: "kn", English: "Kannada"},
|
|
||||||
{Alpha3bCode: "kas", Alpha2Code: "ks", English: "Kashmiri"},
|
|
||||||
{Alpha3bCode: "kau", Alpha2Code: "kr", English: "Kanuri"},
|
|
||||||
{Alpha3bCode: "kaz", Alpha2Code: "kk", English: "Kazakh"},
|
|
||||||
{Alpha3bCode: "khm", Alpha2Code: "km", English: "Central Khmer"},
|
|
||||||
{Alpha3bCode: "kik", Alpha2Code: "ki", English: "Kikuyu; Gikuyu"},
|
|
||||||
{Alpha3bCode: "kin", Alpha2Code: "rw", English: "Kinyarwanda"},
|
|
||||||
{Alpha3bCode: "kir", Alpha2Code: "ky", English: "Kirghiz; Kyrgyz"},
|
|
||||||
{Alpha3bCode: "kom", Alpha2Code: "kv", English: "Komi"},
|
|
||||||
{Alpha3bCode: "kon", Alpha2Code: "kg", English: "Kongo"},
|
|
||||||
{Alpha3bCode: "kor", Alpha2Code: "ko", English: "Korean"},
|
|
||||||
{Alpha3bCode: "kua", Alpha2Code: "kj", English: "Kuanyama; Kwanyama"},
|
|
||||||
{Alpha3bCode: "kur", Alpha2Code: "ku", English: "Kurdish"},
|
|
||||||
{Alpha3bCode: "lao", Alpha2Code: "lo", English: "Lao"},
|
|
||||||
{Alpha3bCode: "lat", Alpha2Code: "la", English: "Latin"},
|
|
||||||
{Alpha3bCode: "lav", Alpha2Code: "lv", English: "Latvian"},
|
|
||||||
{Alpha3bCode: "lim", Alpha2Code: "li", English: "Limburgan; Limburger; Limburgish"},
|
|
||||||
{Alpha3bCode: "lin", Alpha2Code: "ln", English: "Lingala"},
|
|
||||||
{Alpha3bCode: "lit", Alpha2Code: "lt", English: "Lithuanian"},
|
|
||||||
{Alpha3bCode: "ltz", Alpha2Code: "lb", English: "Luxembourgish; Letzeburgesch"},
|
|
||||||
{Alpha3bCode: "lub", Alpha2Code: "lu", English: "Luba-Katanga"},
|
|
||||||
{Alpha3bCode: "lug", Alpha2Code: "lg", English: "Ganda"},
|
|
||||||
{Alpha3bCode: "mac", Alpha2Code: "mk", English: "Macedonian"},
|
|
||||||
{Alpha3bCode: "mah", Alpha2Code: "mh", English: "Marshallese"},
|
|
||||||
{Alpha3bCode: "mal", Alpha2Code: "ml", English: "Malayalam"},
|
|
||||||
{Alpha3bCode: "mao", Alpha2Code: "mi", English: "Maori"},
|
|
||||||
{Alpha3bCode: "mar", Alpha2Code: "mr", English: "Marathi"},
|
|
||||||
{Alpha3bCode: "may", Alpha2Code: "ms", English: "Malay"},
|
|
||||||
{Alpha3bCode: "mlg", Alpha2Code: "mg", English: "Malagasy"},
|
|
||||||
{Alpha3bCode: "mlt", Alpha2Code: "mt", English: "Maltese"},
|
|
||||||
{Alpha3bCode: "mon", Alpha2Code: "mn", English: "Mongolian"},
|
|
||||||
{Alpha3bCode: "nau", Alpha2Code: "na", English: "Nauru"},
|
|
||||||
{Alpha3bCode: "nav", Alpha2Code: "nv", English: "Navajo; Navaho"},
|
|
||||||
{Alpha3bCode: "nbl", Alpha2Code: "nr", English: "Ndebele, South; South Ndebele"},
|
|
||||||
{Alpha3bCode: "nde", Alpha2Code: "nd", English: "Ndebele, North; North Ndebele"},
|
|
||||||
{Alpha3bCode: "ndo", Alpha2Code: "ng", English: "Ndonga"},
|
|
||||||
{Alpha3bCode: "nep", Alpha2Code: "ne", English: "Nepali"},
|
|
||||||
{Alpha3bCode: "nno", Alpha2Code: "nn", English: "Norwegian Nynorsk; Nynorsk, Norwegian"},
|
|
||||||
{Alpha3bCode: "nob", Alpha2Code: "nb", English: "Bokmål, Norwegian; Norwegian Bokmål"},
|
|
||||||
{Alpha3bCode: "nor", Alpha2Code: "no", English: "Norwegian"},
|
|
||||||
{Alpha3bCode: "nya", Alpha2Code: "ny", English: "Chichewa; Chewa; Nyanja"},
|
|
||||||
{Alpha3bCode: "oci", Alpha2Code: "oc", English: "Occitan (post 1500); Provençal"},
|
|
||||||
{Alpha3bCode: "oji", Alpha2Code: "oj", English: "Ojibwa"},
|
|
||||||
{Alpha3bCode: "ori", Alpha2Code: "or", English: "Oriya"},
|
|
||||||
{Alpha3bCode: "orm", Alpha2Code: "om", English: "Oromo"},
|
|
||||||
{Alpha3bCode: "oss", Alpha2Code: "os", English: "Ossetian; Ossetic"},
|
|
||||||
{Alpha3bCode: "pan", Alpha2Code: "pa", English: "Panjabi; Punjabi"},
|
|
||||||
{Alpha3bCode: "per", Alpha2Code: "fa", English: "Persian"},
|
|
||||||
{Alpha3bCode: "pli", Alpha2Code: "pi", English: "Pali"},
|
|
||||||
{Alpha3bCode: "pol", Alpha2Code: "pl", English: "Polish"},
|
|
||||||
{Alpha3bCode: "por", Alpha2Code: "pt", English: "Portuguese"},
|
|
||||||
{Alpha3bCode: "pus", Alpha2Code: "ps", English: "Pushto; Pashto"},
|
|
||||||
{Alpha3bCode: "que", Alpha2Code: "qu", English: "Quechua"},
|
|
||||||
{Alpha3bCode: "roh", Alpha2Code: "rm", English: "Romansh"},
|
|
||||||
{Alpha3bCode: "rum", Alpha2Code: "ro", English: "Romanian; Moldavian; Moldovan"},
|
|
||||||
{Alpha3bCode: "run", Alpha2Code: "rn", English: "Rundi"},
|
|
||||||
{Alpha3bCode: "rus", Alpha2Code: "ru", English: "Russian"},
|
|
||||||
{Alpha3bCode: "sag", Alpha2Code: "sg", English: "Sango"},
|
|
||||||
{Alpha3bCode: "san", Alpha2Code: "sa", English: "Sanskrit"},
|
|
||||||
{Alpha3bCode: "sin", Alpha2Code: "si", English: "Sinhala; Sinhalese"},
|
|
||||||
{Alpha3bCode: "slo", Alpha2Code: "sk", English: "Slovak"},
|
|
||||||
{Alpha3bCode: "slv", Alpha2Code: "sl", English: "Slovenian"},
|
|
||||||
{Alpha3bCode: "sme", Alpha2Code: "se", English: "Northern Sami"},
|
|
||||||
{Alpha3bCode: "smo", Alpha2Code: "sm", English: "Samoan"},
|
|
||||||
{Alpha3bCode: "sna", Alpha2Code: "sn", English: "Shona"},
|
|
||||||
{Alpha3bCode: "snd", Alpha2Code: "sd", English: "Sindhi"},
|
|
||||||
{Alpha3bCode: "som", Alpha2Code: "so", English: "Somali"},
|
|
||||||
{Alpha3bCode: "sot", Alpha2Code: "st", English: "Sotho, Southern"},
|
|
||||||
{Alpha3bCode: "spa", Alpha2Code: "es", English: "Spanish; Castilian"},
|
|
||||||
{Alpha3bCode: "srd", Alpha2Code: "sc", English: "Sardinian"},
|
|
||||||
{Alpha3bCode: "srp", Alpha2Code: "sr", English: "Serbian"},
|
|
||||||
{Alpha3bCode: "ssw", Alpha2Code: "ss", English: "Swati"},
|
|
||||||
{Alpha3bCode: "sun", Alpha2Code: "su", English: "Sundanese"},
|
|
||||||
{Alpha3bCode: "swa", Alpha2Code: "sw", English: "Swahili"},
|
|
||||||
{Alpha3bCode: "swe", Alpha2Code: "sv", English: "Swedish"},
|
|
||||||
{Alpha3bCode: "tah", Alpha2Code: "ty", English: "Tahitian"},
|
|
||||||
{Alpha3bCode: "tam", Alpha2Code: "ta", English: "Tamil"},
|
|
||||||
{Alpha3bCode: "tat", Alpha2Code: "tt", English: "Tatar"},
|
|
||||||
{Alpha3bCode: "tel", Alpha2Code: "te", English: "Telugu"},
|
|
||||||
{Alpha3bCode: "tgk", Alpha2Code: "tg", English: "Tajik"},
|
|
||||||
{Alpha3bCode: "tgl", Alpha2Code: "tl", English: "Tagalog"},
|
|
||||||
{Alpha3bCode: "tha", Alpha2Code: "th", English: "Thai"},
|
|
||||||
{Alpha3bCode: "tib", Alpha2Code: "bo", English: "Tibetan"},
|
|
||||||
{Alpha3bCode: "tir", Alpha2Code: "ti", English: "Tigrinya"},
|
|
||||||
{Alpha3bCode: "ton", Alpha2Code: "to", English: "Tonga (Tonga Islands)"},
|
|
||||||
{Alpha3bCode: "tsn", Alpha2Code: "tn", English: "Tswana"},
|
|
||||||
{Alpha3bCode: "tso", Alpha2Code: "ts", English: "Tsonga"},
|
|
||||||
{Alpha3bCode: "tuk", Alpha2Code: "tk", English: "Turkmen"},
|
|
||||||
{Alpha3bCode: "tur", Alpha2Code: "tr", English: "Turkish"},
|
|
||||||
{Alpha3bCode: "twi", Alpha2Code: "tw", English: "Twi"},
|
|
||||||
{Alpha3bCode: "uig", Alpha2Code: "ug", English: "Uighur; Uyghur"},
|
|
||||||
{Alpha3bCode: "ukr", Alpha2Code: "uk", English: "Ukrainian"},
|
|
||||||
{Alpha3bCode: "urd", Alpha2Code: "ur", English: "Urdu"},
|
|
||||||
{Alpha3bCode: "uzb", Alpha2Code: "uz", English: "Uzbek"},
|
|
||||||
{Alpha3bCode: "ven", Alpha2Code: "ve", English: "Venda"},
|
|
||||||
{Alpha3bCode: "vie", Alpha2Code: "vi", English: "Vietnamese"},
|
|
||||||
{Alpha3bCode: "vol", Alpha2Code: "vo", English: "Volapük"},
|
|
||||||
{Alpha3bCode: "wel", Alpha2Code: "cy", English: "Welsh"},
|
|
||||||
{Alpha3bCode: "wln", Alpha2Code: "wa", English: "Walloon"},
|
|
||||||
{Alpha3bCode: "wol", Alpha2Code: "wo", English: "Wolof"},
|
|
||||||
{Alpha3bCode: "xho", Alpha2Code: "xh", English: "Xhosa"},
|
|
||||||
{Alpha3bCode: "yid", Alpha2Code: "yi", English: "Yiddish"},
|
|
||||||
{Alpha3bCode: "yor", Alpha2Code: "yo", English: "Yoruba"},
|
|
||||||
{Alpha3bCode: "zha", Alpha2Code: "za", English: "Zhuang; Chuang"},
|
|
||||||
{Alpha3bCode: "zul", Alpha2Code: "zu", English: "Zulu"},
|
|
||||||
}
|
|
||||||
270
vendor/github.com/asaskevich/govalidator/utils.go
generated
vendored
270
vendor/github.com/asaskevich/govalidator/utils.go
generated
vendored
@@ -1,270 +0,0 @@
|
|||||||
package govalidator
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"html"
|
|
||||||
"math"
|
|
||||||
"path"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
"unicode"
|
|
||||||
"unicode/utf8"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Contains check if the string contains the substring.
|
|
||||||
func Contains(str, substring string) bool {
|
|
||||||
return strings.Contains(str, substring)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Matches check if string matches the pattern (pattern is regular expression)
|
|
||||||
// In case of error return false
|
|
||||||
func Matches(str, pattern string) bool {
|
|
||||||
match, _ := regexp.MatchString(pattern, str)
|
|
||||||
return match
|
|
||||||
}
|
|
||||||
|
|
||||||
// LeftTrim trim characters from the left-side of the input.
|
|
||||||
// If second argument is empty, it's will be remove leading spaces.
|
|
||||||
func LeftTrim(str, chars string) string {
|
|
||||||
if chars == "" {
|
|
||||||
return strings.TrimLeftFunc(str, unicode.IsSpace)
|
|
||||||
}
|
|
||||||
r, _ := regexp.Compile("^[" + chars + "]+")
|
|
||||||
return r.ReplaceAllString(str, "")
|
|
||||||
}
|
|
||||||
|
|
||||||
// RightTrim trim characters from the right-side of the input.
|
|
||||||
// If second argument is empty, it's will be remove spaces.
|
|
||||||
func RightTrim(str, chars string) string {
|
|
||||||
if chars == "" {
|
|
||||||
return strings.TrimRightFunc(str, unicode.IsSpace)
|
|
||||||
}
|
|
||||||
r, _ := regexp.Compile("[" + chars + "]+$")
|
|
||||||
return r.ReplaceAllString(str, "")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Trim trim characters from both sides of the input.
|
|
||||||
// If second argument is empty, it's will be remove spaces.
|
|
||||||
func Trim(str, chars string) string {
|
|
||||||
return LeftTrim(RightTrim(str, chars), chars)
|
|
||||||
}
|
|
||||||
|
|
||||||
// WhiteList remove characters that do not appear in the whitelist.
|
|
||||||
func WhiteList(str, chars string) string {
|
|
||||||
pattern := "[^" + chars + "]+"
|
|
||||||
r, _ := regexp.Compile(pattern)
|
|
||||||
return r.ReplaceAllString(str, "")
|
|
||||||
}
|
|
||||||
|
|
||||||
// BlackList remove characters that appear in the blacklist.
|
|
||||||
func BlackList(str, chars string) string {
|
|
||||||
pattern := "[" + chars + "]+"
|
|
||||||
r, _ := regexp.Compile(pattern)
|
|
||||||
return r.ReplaceAllString(str, "")
|
|
||||||
}
|
|
||||||
|
|
||||||
// StripLow remove characters with a numerical value < 32 and 127, mostly control characters.
|
|
||||||
// If keep_new_lines is true, newline characters are preserved (\n and \r, hex 0xA and 0xD).
|
|
||||||
func StripLow(str string, keepNewLines bool) string {
|
|
||||||
chars := ""
|
|
||||||
if keepNewLines {
|
|
||||||
chars = "\x00-\x09\x0B\x0C\x0E-\x1F\x7F"
|
|
||||||
} else {
|
|
||||||
chars = "\x00-\x1F\x7F"
|
|
||||||
}
|
|
||||||
return BlackList(str, chars)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReplacePattern replace regular expression pattern in string
|
|
||||||
func ReplacePattern(str, pattern, replace string) string {
|
|
||||||
r, _ := regexp.Compile(pattern)
|
|
||||||
return r.ReplaceAllString(str, replace)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Escape replace <, >, & and " with HTML entities.
|
|
||||||
var Escape = html.EscapeString
|
|
||||||
|
|
||||||
func addSegment(inrune, segment []rune) []rune {
|
|
||||||
if len(segment) == 0 {
|
|
||||||
return inrune
|
|
||||||
}
|
|
||||||
if len(inrune) != 0 {
|
|
||||||
inrune = append(inrune, '_')
|
|
||||||
}
|
|
||||||
inrune = append(inrune, segment...)
|
|
||||||
return inrune
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnderscoreToCamelCase converts from underscore separated form to camel case form.
|
|
||||||
// Ex.: my_func => MyFunc
|
|
||||||
func UnderscoreToCamelCase(s string) string {
|
|
||||||
return strings.Replace(strings.Title(strings.Replace(strings.ToLower(s), "_", " ", -1)), " ", "", -1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// CamelCaseToUnderscore converts from camel case form to underscore separated form.
|
|
||||||
// Ex.: MyFunc => my_func
|
|
||||||
func CamelCaseToUnderscore(str string) string {
|
|
||||||
var output []rune
|
|
||||||
var segment []rune
|
|
||||||
for _, r := range str {
|
|
||||||
|
|
||||||
// not treat number as separate segment
|
|
||||||
if !unicode.IsLower(r) && string(r) != "_" && !unicode.IsNumber(r) {
|
|
||||||
output = addSegment(output, segment)
|
|
||||||
segment = nil
|
|
||||||
}
|
|
||||||
segment = append(segment, unicode.ToLower(r))
|
|
||||||
}
|
|
||||||
output = addSegment(output, segment)
|
|
||||||
return string(output)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reverse return reversed string
|
|
||||||
func Reverse(s string) string {
|
|
||||||
r := []rune(s)
|
|
||||||
for i, j := 0, len(r)-1; i < j; i, j = i+1, j-1 {
|
|
||||||
r[i], r[j] = r[j], r[i]
|
|
||||||
}
|
|
||||||
return string(r)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetLines split string by "\n" and return array of lines
|
|
||||||
func GetLines(s string) []string {
|
|
||||||
return strings.Split(s, "\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetLine return specified line of multiline string
|
|
||||||
func GetLine(s string, index int) (string, error) {
|
|
||||||
lines := GetLines(s)
|
|
||||||
if index < 0 || index >= len(lines) {
|
|
||||||
return "", errors.New("line index out of bounds")
|
|
||||||
}
|
|
||||||
return lines[index], nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoveTags remove all tags from HTML string
|
|
||||||
func RemoveTags(s string) string {
|
|
||||||
return ReplacePattern(s, "<[^>]*>", "")
|
|
||||||
}
|
|
||||||
|
|
||||||
// SafeFileName return safe string that can be used in file names
|
|
||||||
func SafeFileName(str string) string {
|
|
||||||
name := strings.ToLower(str)
|
|
||||||
name = path.Clean(path.Base(name))
|
|
||||||
name = strings.Trim(name, " ")
|
|
||||||
separators, err := regexp.Compile(`[ &_=+:]`)
|
|
||||||
if err == nil {
|
|
||||||
name = separators.ReplaceAllString(name, "-")
|
|
||||||
}
|
|
||||||
legal, err := regexp.Compile(`[^[:alnum:]-.]`)
|
|
||||||
if err == nil {
|
|
||||||
name = legal.ReplaceAllString(name, "")
|
|
||||||
}
|
|
||||||
for strings.Contains(name, "--") {
|
|
||||||
name = strings.Replace(name, "--", "-", -1)
|
|
||||||
}
|
|
||||||
return name
|
|
||||||
}
|
|
||||||
|
|
||||||
// NormalizeEmail canonicalize an email address.
|
|
||||||
// The local part of the email address is lowercased for all domains; the hostname is always lowercased and
|
|
||||||
// the local part of the email address is always lowercased for hosts that are known to be case-insensitive (currently only GMail).
|
|
||||||
// Normalization follows special rules for known providers: currently, GMail addresses have dots removed in the local part and
|
|
||||||
// are stripped of tags (e.g. some.one+tag@gmail.com becomes someone@gmail.com) and all @googlemail.com addresses are
|
|
||||||
// normalized to @gmail.com.
|
|
||||||
func NormalizeEmail(str string) (string, error) {
|
|
||||||
if !IsEmail(str) {
|
|
||||||
return "", fmt.Errorf("%s is not an email", str)
|
|
||||||
}
|
|
||||||
parts := strings.Split(str, "@")
|
|
||||||
parts[0] = strings.ToLower(parts[0])
|
|
||||||
parts[1] = strings.ToLower(parts[1])
|
|
||||||
if parts[1] == "gmail.com" || parts[1] == "googlemail.com" {
|
|
||||||
parts[1] = "gmail.com"
|
|
||||||
parts[0] = strings.Split(ReplacePattern(parts[0], `\.`, ""), "+")[0]
|
|
||||||
}
|
|
||||||
return strings.Join(parts, "@"), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Truncate a string to the closest length without breaking words.
|
|
||||||
func Truncate(str string, length int, ending string) string {
|
|
||||||
var aftstr, befstr string
|
|
||||||
if len(str) > length {
|
|
||||||
words := strings.Fields(str)
|
|
||||||
before, present := 0, 0
|
|
||||||
for i := range words {
|
|
||||||
befstr = aftstr
|
|
||||||
before = present
|
|
||||||
aftstr = aftstr + words[i] + " "
|
|
||||||
present = len(aftstr)
|
|
||||||
if present > length && i != 0 {
|
|
||||||
if (length - before) < (present - length) {
|
|
||||||
return Trim(befstr, " /\\.,\"'#!?&@+-") + ending
|
|
||||||
}
|
|
||||||
return Trim(aftstr, " /\\.,\"'#!?&@+-") + ending
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return str
|
|
||||||
}
|
|
||||||
|
|
||||||
// PadLeft pad left side of string if size of string is less then indicated pad length
|
|
||||||
func PadLeft(str string, padStr string, padLen int) string {
|
|
||||||
return buildPadStr(str, padStr, padLen, true, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
// PadRight pad right side of string if size of string is less then indicated pad length
|
|
||||||
func PadRight(str string, padStr string, padLen int) string {
|
|
||||||
return buildPadStr(str, padStr, padLen, false, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
// PadBoth pad sides of string if size of string is less then indicated pad length
|
|
||||||
func PadBoth(str string, padStr string, padLen int) string {
|
|
||||||
return buildPadStr(str, padStr, padLen, true, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
// PadString either left, right or both sides, not the padding string can be unicode and more then one
|
|
||||||
// character
|
|
||||||
func buildPadStr(str string, padStr string, padLen int, padLeft bool, padRight bool) string {
|
|
||||||
|
|
||||||
// When padded length is less then the current string size
|
|
||||||
if padLen < utf8.RuneCountInString(str) {
|
|
||||||
return str
|
|
||||||
}
|
|
||||||
|
|
||||||
padLen -= utf8.RuneCountInString(str)
|
|
||||||
|
|
||||||
targetLen := padLen
|
|
||||||
|
|
||||||
targetLenLeft := targetLen
|
|
||||||
targetLenRight := targetLen
|
|
||||||
if padLeft && padRight {
|
|
||||||
targetLenLeft = padLen / 2
|
|
||||||
targetLenRight = padLen - targetLenLeft
|
|
||||||
}
|
|
||||||
|
|
||||||
strToRepeatLen := utf8.RuneCountInString(padStr)
|
|
||||||
|
|
||||||
repeatTimes := int(math.Ceil(float64(targetLen) / float64(strToRepeatLen)))
|
|
||||||
repeatedString := strings.Repeat(padStr, repeatTimes)
|
|
||||||
|
|
||||||
leftSide := ""
|
|
||||||
if padLeft {
|
|
||||||
leftSide = repeatedString[0:targetLenLeft]
|
|
||||||
}
|
|
||||||
|
|
||||||
rightSide := ""
|
|
||||||
if padRight {
|
|
||||||
rightSide = repeatedString[0:targetLenRight]
|
|
||||||
}
|
|
||||||
|
|
||||||
return leftSide + str + rightSide
|
|
||||||
}
|
|
||||||
|
|
||||||
// TruncatingErrorf removes extra args from fmt.Errorf if not formatted in the str object
|
|
||||||
func TruncatingErrorf(str string, args ...interface{}) error {
|
|
||||||
n := strings.Count(str, "%s")
|
|
||||||
return fmt.Errorf(str, args[:n]...)
|
|
||||||
}
|
|
||||||
1278
vendor/github.com/asaskevich/govalidator/validator.go
generated
vendored
1278
vendor/github.com/asaskevich/govalidator/validator.go
generated
vendored
File diff suppressed because it is too large
Load Diff
15
vendor/github.com/asaskevich/govalidator/wercker.yml
generated
vendored
15
vendor/github.com/asaskevich/govalidator/wercker.yml
generated
vendored
@@ -1,15 +0,0 @@
|
|||||||
box: golang
|
|
||||||
build:
|
|
||||||
steps:
|
|
||||||
- setup-go-workspace
|
|
||||||
|
|
||||||
- script:
|
|
||||||
name: go get
|
|
||||||
code: |
|
|
||||||
go version
|
|
||||||
go get -t ./...
|
|
||||||
|
|
||||||
- script:
|
|
||||||
name: go test
|
|
||||||
code: |
|
|
||||||
go test -race ./...
|
|
||||||
62
vendor/github.com/cenkalti/backoff/v4/context.go
generated
vendored
62
vendor/github.com/cenkalti/backoff/v4/context.go
generated
vendored
@@ -1,62 +0,0 @@
|
|||||||
package backoff
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// BackOffContext is a backoff policy that stops retrying after the context
|
|
||||||
// is canceled.
|
|
||||||
type BackOffContext interface { // nolint: golint
|
|
||||||
BackOff
|
|
||||||
Context() context.Context
|
|
||||||
}
|
|
||||||
|
|
||||||
type backOffContext struct {
|
|
||||||
BackOff
|
|
||||||
ctx context.Context
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithContext returns a BackOffContext with context ctx
|
|
||||||
//
|
|
||||||
// ctx must not be nil
|
|
||||||
func WithContext(b BackOff, ctx context.Context) BackOffContext { // nolint: golint
|
|
||||||
if ctx == nil {
|
|
||||||
panic("nil context")
|
|
||||||
}
|
|
||||||
|
|
||||||
if b, ok := b.(*backOffContext); ok {
|
|
||||||
return &backOffContext{
|
|
||||||
BackOff: b.BackOff,
|
|
||||||
ctx: ctx,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return &backOffContext{
|
|
||||||
BackOff: b,
|
|
||||||
ctx: ctx,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func getContext(b BackOff) context.Context {
|
|
||||||
if cb, ok := b.(BackOffContext); ok {
|
|
||||||
return cb.Context()
|
|
||||||
}
|
|
||||||
if tb, ok := b.(*backOffTries); ok {
|
|
||||||
return getContext(tb.delegate)
|
|
||||||
}
|
|
||||||
return context.Background()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *backOffContext) Context() context.Context {
|
|
||||||
return b.ctx
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *backOffContext) NextBackOff() time.Duration {
|
|
||||||
select {
|
|
||||||
case <-b.ctx.Done():
|
|
||||||
return Stop
|
|
||||||
default:
|
|
||||||
return b.BackOff.NextBackOff()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
216
vendor/github.com/cenkalti/backoff/v4/exponential.go
generated
vendored
216
vendor/github.com/cenkalti/backoff/v4/exponential.go
generated
vendored
@@ -1,216 +0,0 @@
|
|||||||
package backoff
|
|
||||||
|
|
||||||
import (
|
|
||||||
"math/rand"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
/*
|
|
||||||
ExponentialBackOff is a backoff implementation that increases the backoff
|
|
||||||
period for each retry attempt using a randomization function that grows exponentially.
|
|
||||||
|
|
||||||
NextBackOff() is calculated using the following formula:
|
|
||||||
|
|
||||||
randomized interval =
|
|
||||||
RetryInterval * (random value in range [1 - RandomizationFactor, 1 + RandomizationFactor])
|
|
||||||
|
|
||||||
In other words NextBackOff() will range between the randomization factor
|
|
||||||
percentage below and above the retry interval.
|
|
||||||
|
|
||||||
For example, given the following parameters:
|
|
||||||
|
|
||||||
RetryInterval = 2
|
|
||||||
RandomizationFactor = 0.5
|
|
||||||
Multiplier = 2
|
|
||||||
|
|
||||||
the actual backoff period used in the next retry attempt will range between 1 and 3 seconds,
|
|
||||||
multiplied by the exponential, that is, between 2 and 6 seconds.
|
|
||||||
|
|
||||||
Note: MaxInterval caps the RetryInterval and not the randomized interval.
|
|
||||||
|
|
||||||
If the time elapsed since an ExponentialBackOff instance is created goes past the
|
|
||||||
MaxElapsedTime, then the method NextBackOff() starts returning backoff.Stop.
|
|
||||||
|
|
||||||
The elapsed time can be reset by calling Reset().
|
|
||||||
|
|
||||||
Example: Given the following default arguments, for 10 tries the sequence will be,
|
|
||||||
and assuming we go over the MaxElapsedTime on the 10th try:
|
|
||||||
|
|
||||||
Request # RetryInterval (seconds) Randomized Interval (seconds)
|
|
||||||
|
|
||||||
1 0.5 [0.25, 0.75]
|
|
||||||
2 0.75 [0.375, 1.125]
|
|
||||||
3 1.125 [0.562, 1.687]
|
|
||||||
4 1.687 [0.8435, 2.53]
|
|
||||||
5 2.53 [1.265, 3.795]
|
|
||||||
6 3.795 [1.897, 5.692]
|
|
||||||
7 5.692 [2.846, 8.538]
|
|
||||||
8 8.538 [4.269, 12.807]
|
|
||||||
9 12.807 [6.403, 19.210]
|
|
||||||
10 19.210 backoff.Stop
|
|
||||||
|
|
||||||
Note: Implementation is not thread-safe.
|
|
||||||
*/
|
|
||||||
type ExponentialBackOff struct {
|
|
||||||
InitialInterval time.Duration
|
|
||||||
RandomizationFactor float64
|
|
||||||
Multiplier float64
|
|
||||||
MaxInterval time.Duration
|
|
||||||
// After MaxElapsedTime the ExponentialBackOff returns Stop.
|
|
||||||
// It never stops if MaxElapsedTime == 0.
|
|
||||||
MaxElapsedTime time.Duration
|
|
||||||
Stop time.Duration
|
|
||||||
Clock Clock
|
|
||||||
|
|
||||||
currentInterval time.Duration
|
|
||||||
startTime time.Time
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clock is an interface that returns current time for BackOff.
|
|
||||||
type Clock interface {
|
|
||||||
Now() time.Time
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExponentialBackOffOpts is a function type used to configure ExponentialBackOff options.
|
|
||||||
type ExponentialBackOffOpts func(*ExponentialBackOff)
|
|
||||||
|
|
||||||
// Default values for ExponentialBackOff.
|
|
||||||
const (
|
|
||||||
DefaultInitialInterval = 500 * time.Millisecond
|
|
||||||
DefaultRandomizationFactor = 0.5
|
|
||||||
DefaultMultiplier = 1.5
|
|
||||||
DefaultMaxInterval = 60 * time.Second
|
|
||||||
DefaultMaxElapsedTime = 15 * time.Minute
|
|
||||||
)
|
|
||||||
|
|
||||||
// NewExponentialBackOff creates an instance of ExponentialBackOff using default values.
|
|
||||||
func NewExponentialBackOff(opts ...ExponentialBackOffOpts) *ExponentialBackOff {
|
|
||||||
b := &ExponentialBackOff{
|
|
||||||
InitialInterval: DefaultInitialInterval,
|
|
||||||
RandomizationFactor: DefaultRandomizationFactor,
|
|
||||||
Multiplier: DefaultMultiplier,
|
|
||||||
MaxInterval: DefaultMaxInterval,
|
|
||||||
MaxElapsedTime: DefaultMaxElapsedTime,
|
|
||||||
Stop: Stop,
|
|
||||||
Clock: SystemClock,
|
|
||||||
}
|
|
||||||
for _, fn := range opts {
|
|
||||||
fn(b)
|
|
||||||
}
|
|
||||||
b.Reset()
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithInitialInterval sets the initial interval between retries.
|
|
||||||
func WithInitialInterval(duration time.Duration) ExponentialBackOffOpts {
|
|
||||||
return func(ebo *ExponentialBackOff) {
|
|
||||||
ebo.InitialInterval = duration
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithRandomizationFactor sets the randomization factor to add jitter to intervals.
|
|
||||||
func WithRandomizationFactor(randomizationFactor float64) ExponentialBackOffOpts {
|
|
||||||
return func(ebo *ExponentialBackOff) {
|
|
||||||
ebo.RandomizationFactor = randomizationFactor
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithMultiplier sets the multiplier for increasing the interval after each retry.
|
|
||||||
func WithMultiplier(multiplier float64) ExponentialBackOffOpts {
|
|
||||||
return func(ebo *ExponentialBackOff) {
|
|
||||||
ebo.Multiplier = multiplier
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithMaxInterval sets the maximum interval between retries.
|
|
||||||
func WithMaxInterval(duration time.Duration) ExponentialBackOffOpts {
|
|
||||||
return func(ebo *ExponentialBackOff) {
|
|
||||||
ebo.MaxInterval = duration
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithMaxElapsedTime sets the maximum total time for retries.
|
|
||||||
func WithMaxElapsedTime(duration time.Duration) ExponentialBackOffOpts {
|
|
||||||
return func(ebo *ExponentialBackOff) {
|
|
||||||
ebo.MaxElapsedTime = duration
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithRetryStopDuration sets the duration after which retries should stop.
|
|
||||||
func WithRetryStopDuration(duration time.Duration) ExponentialBackOffOpts {
|
|
||||||
return func(ebo *ExponentialBackOff) {
|
|
||||||
ebo.Stop = duration
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithClockProvider sets the clock used to measure time.
|
|
||||||
func WithClockProvider(clock Clock) ExponentialBackOffOpts {
|
|
||||||
return func(ebo *ExponentialBackOff) {
|
|
||||||
ebo.Clock = clock
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type systemClock struct{}
|
|
||||||
|
|
||||||
func (t systemClock) Now() time.Time {
|
|
||||||
return time.Now()
|
|
||||||
}
|
|
||||||
|
|
||||||
// SystemClock implements Clock interface that uses time.Now().
|
|
||||||
var SystemClock = systemClock{}
|
|
||||||
|
|
||||||
// Reset the interval back to the initial retry interval and restarts the timer.
|
|
||||||
// Reset must be called before using b.
|
|
||||||
func (b *ExponentialBackOff) Reset() {
|
|
||||||
b.currentInterval = b.InitialInterval
|
|
||||||
b.startTime = b.Clock.Now()
|
|
||||||
}
|
|
||||||
|
|
||||||
// NextBackOff calculates the next backoff interval using the formula:
|
|
||||||
// Randomized interval = RetryInterval * (1 ± RandomizationFactor)
|
|
||||||
func (b *ExponentialBackOff) NextBackOff() time.Duration {
|
|
||||||
// Make sure we have not gone over the maximum elapsed time.
|
|
||||||
elapsed := b.GetElapsedTime()
|
|
||||||
next := getRandomValueFromInterval(b.RandomizationFactor, rand.Float64(), b.currentInterval)
|
|
||||||
b.incrementCurrentInterval()
|
|
||||||
if b.MaxElapsedTime != 0 && elapsed+next > b.MaxElapsedTime {
|
|
||||||
return b.Stop
|
|
||||||
}
|
|
||||||
return next
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetElapsedTime returns the elapsed time since an ExponentialBackOff instance
|
|
||||||
// is created and is reset when Reset() is called.
|
|
||||||
//
|
|
||||||
// The elapsed time is computed using time.Now().UnixNano(). It is
|
|
||||||
// safe to call even while the backoff policy is used by a running
|
|
||||||
// ticker.
|
|
||||||
func (b *ExponentialBackOff) GetElapsedTime() time.Duration {
|
|
||||||
return b.Clock.Now().Sub(b.startTime)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Increments the current interval by multiplying it with the multiplier.
|
|
||||||
func (b *ExponentialBackOff) incrementCurrentInterval() {
|
|
||||||
// Check for overflow, if overflow is detected set the current interval to the max interval.
|
|
||||||
if float64(b.currentInterval) >= float64(b.MaxInterval)/b.Multiplier {
|
|
||||||
b.currentInterval = b.MaxInterval
|
|
||||||
} else {
|
|
||||||
b.currentInterval = time.Duration(float64(b.currentInterval) * b.Multiplier)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns a random value from the following interval:
|
|
||||||
// [currentInterval - randomizationFactor * currentInterval, currentInterval + randomizationFactor * currentInterval].
|
|
||||||
func getRandomValueFromInterval(randomizationFactor, random float64, currentInterval time.Duration) time.Duration {
|
|
||||||
if randomizationFactor == 0 {
|
|
||||||
return currentInterval // make sure no randomness is used when randomizationFactor is 0.
|
|
||||||
}
|
|
||||||
var delta = randomizationFactor * float64(currentInterval)
|
|
||||||
var minInterval = float64(currentInterval) - delta
|
|
||||||
var maxInterval = float64(currentInterval) + delta
|
|
||||||
|
|
||||||
// Get a random value from the range [minInterval, maxInterval].
|
|
||||||
// The formula used below has a +1 because if the minInterval is 1 and the maxInterval is 3 then
|
|
||||||
// we want a 33% chance for selecting either 1, 2 or 3.
|
|
||||||
return time.Duration(minInterval + (random * (maxInterval - minInterval + 1)))
|
|
||||||
}
|
|
||||||
146
vendor/github.com/cenkalti/backoff/v4/retry.go
generated
vendored
146
vendor/github.com/cenkalti/backoff/v4/retry.go
generated
vendored
@@ -1,146 +0,0 @@
|
|||||||
package backoff
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// An OperationWithData is executing by RetryWithData() or RetryNotifyWithData().
|
|
||||||
// The operation will be retried using a backoff policy if it returns an error.
|
|
||||||
type OperationWithData[T any] func() (T, error)
|
|
||||||
|
|
||||||
// An Operation is executing by Retry() or RetryNotify().
|
|
||||||
// The operation will be retried using a backoff policy if it returns an error.
|
|
||||||
type Operation func() error
|
|
||||||
|
|
||||||
func (o Operation) withEmptyData() OperationWithData[struct{}] {
|
|
||||||
return func() (struct{}, error) {
|
|
||||||
return struct{}{}, o()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Notify is a notify-on-error function. It receives an operation error and
|
|
||||||
// backoff delay if the operation failed (with an error).
|
|
||||||
//
|
|
||||||
// NOTE that if the backoff policy stated to stop retrying,
|
|
||||||
// the notify function isn't called.
|
|
||||||
type Notify func(error, time.Duration)
|
|
||||||
|
|
||||||
// Retry the operation o until it does not return error or BackOff stops.
|
|
||||||
// o is guaranteed to be run at least once.
|
|
||||||
//
|
|
||||||
// If o returns a *PermanentError, the operation is not retried, and the
|
|
||||||
// wrapped error is returned.
|
|
||||||
//
|
|
||||||
// Retry sleeps the goroutine for the duration returned by BackOff after a
|
|
||||||
// failed operation returns.
|
|
||||||
func Retry(o Operation, b BackOff) error {
|
|
||||||
return RetryNotify(o, b, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// RetryWithData is like Retry but returns data in the response too.
|
|
||||||
func RetryWithData[T any](o OperationWithData[T], b BackOff) (T, error) {
|
|
||||||
return RetryNotifyWithData(o, b, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// RetryNotify calls notify function with the error and wait duration
|
|
||||||
// for each failed attempt before sleep.
|
|
||||||
func RetryNotify(operation Operation, b BackOff, notify Notify) error {
|
|
||||||
return RetryNotifyWithTimer(operation, b, notify, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// RetryNotifyWithData is like RetryNotify but returns data in the response too.
|
|
||||||
func RetryNotifyWithData[T any](operation OperationWithData[T], b BackOff, notify Notify) (T, error) {
|
|
||||||
return doRetryNotify(operation, b, notify, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// RetryNotifyWithTimer calls notify function with the error and wait duration using the given Timer
|
|
||||||
// for each failed attempt before sleep.
|
|
||||||
// A default timer that uses system timer is used when nil is passed.
|
|
||||||
func RetryNotifyWithTimer(operation Operation, b BackOff, notify Notify, t Timer) error {
|
|
||||||
_, err := doRetryNotify(operation.withEmptyData(), b, notify, t)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// RetryNotifyWithTimerAndData is like RetryNotifyWithTimer but returns data in the response too.
|
|
||||||
func RetryNotifyWithTimerAndData[T any](operation OperationWithData[T], b BackOff, notify Notify, t Timer) (T, error) {
|
|
||||||
return doRetryNotify(operation, b, notify, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func doRetryNotify[T any](operation OperationWithData[T], b BackOff, notify Notify, t Timer) (T, error) {
|
|
||||||
var (
|
|
||||||
err error
|
|
||||||
next time.Duration
|
|
||||||
res T
|
|
||||||
)
|
|
||||||
if t == nil {
|
|
||||||
t = &defaultTimer{}
|
|
||||||
}
|
|
||||||
|
|
||||||
defer func() {
|
|
||||||
t.Stop()
|
|
||||||
}()
|
|
||||||
|
|
||||||
ctx := getContext(b)
|
|
||||||
|
|
||||||
b.Reset()
|
|
||||||
for {
|
|
||||||
res, err = operation()
|
|
||||||
if err == nil {
|
|
||||||
return res, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var permanent *PermanentError
|
|
||||||
if errors.As(err, &permanent) {
|
|
||||||
return res, permanent.Err
|
|
||||||
}
|
|
||||||
|
|
||||||
if next = b.NextBackOff(); next == Stop {
|
|
||||||
if cerr := ctx.Err(); cerr != nil {
|
|
||||||
return res, cerr
|
|
||||||
}
|
|
||||||
|
|
||||||
return res, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if notify != nil {
|
|
||||||
notify(err, next)
|
|
||||||
}
|
|
||||||
|
|
||||||
t.Start(next)
|
|
||||||
|
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
return res, ctx.Err()
|
|
||||||
case <-t.C():
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// PermanentError signals that the operation should not be retried.
|
|
||||||
type PermanentError struct {
|
|
||||||
Err error
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *PermanentError) Error() string {
|
|
||||||
return e.Err.Error()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *PermanentError) Unwrap() error {
|
|
||||||
return e.Err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *PermanentError) Is(target error) bool {
|
|
||||||
_, ok := target.(*PermanentError)
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
// Permanent wraps the given err in a *PermanentError.
|
|
||||||
func Permanent(err error) error {
|
|
||||||
if err == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return &PermanentError{
|
|
||||||
Err: err,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
38
vendor/github.com/cenkalti/backoff/v4/tries.go
generated
vendored
38
vendor/github.com/cenkalti/backoff/v4/tries.go
generated
vendored
@@ -1,38 +0,0 @@
|
|||||||
package backoff
|
|
||||||
|
|
||||||
import "time"
|
|
||||||
|
|
||||||
/*
|
|
||||||
WithMaxRetries creates a wrapper around another BackOff, which will
|
|
||||||
return Stop if NextBackOff() has been called too many times since
|
|
||||||
the last time Reset() was called
|
|
||||||
|
|
||||||
Note: Implementation is not thread-safe.
|
|
||||||
*/
|
|
||||||
func WithMaxRetries(b BackOff, max uint64) BackOff {
|
|
||||||
return &backOffTries{delegate: b, maxTries: max}
|
|
||||||
}
|
|
||||||
|
|
||||||
type backOffTries struct {
|
|
||||||
delegate BackOff
|
|
||||||
maxTries uint64
|
|
||||||
numTries uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *backOffTries) NextBackOff() time.Duration {
|
|
||||||
if b.maxTries == 0 {
|
|
||||||
return Stop
|
|
||||||
}
|
|
||||||
if b.maxTries > 0 {
|
|
||||||
if b.maxTries <= b.numTries {
|
|
||||||
return Stop
|
|
||||||
}
|
|
||||||
b.numTries++
|
|
||||||
}
|
|
||||||
return b.delegate.NextBackOff()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *backOffTries) Reset() {
|
|
||||||
b.numTries = 0
|
|
||||||
b.delegate.Reset()
|
|
||||||
}
|
|
||||||
29
vendor/github.com/cenkalti/backoff/v5/CHANGELOG.md
generated
vendored
Normal file
29
vendor/github.com/cenkalti/backoff/v5/CHANGELOG.md
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
||||||
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [5.0.0] - 2024-12-19
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- RetryAfterError can be returned from an operation to indicate how long to wait before the next retry.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Retry function now accepts additional options for specifying max number of tries and max elapsed time.
|
||||||
|
- Retry function now accepts a context.Context.
|
||||||
|
- Operation function signature changed to return result (any type) and error.
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
|
||||||
|
- RetryNotify* and RetryWithData functions. Only single Retry function remains.
|
||||||
|
- Optional arguments from ExponentialBackoff constructor.
|
||||||
|
- Clock and Timer interfaces.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- The original error is returned from Retry if there's a PermanentError. (#144)
|
||||||
|
- The Retry function respects the wrapped PermanentError. (#140)
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
# Exponential Backoff [![GoDoc][godoc image]][godoc] [![Coverage Status][coveralls image]][coveralls]
|
# Exponential Backoff [![GoDoc][godoc image]][godoc]
|
||||||
|
|
||||||
This is a Go port of the exponential backoff algorithm from [Google's HTTP Client Library for Java][google-http-java-client].
|
This is a Go port of the exponential backoff algorithm from [Google's HTTP Client Library for Java][google-http-java-client].
|
||||||
|
|
||||||
@@ -9,9 +9,11 @@ The retries exponentially increase and stop increasing when a certain threshold
|
|||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
Import path is `github.com/cenkalti/backoff/v4`. Please note the version part at the end.
|
Import path is `github.com/cenkalti/backoff/v5`. Please note the version part at the end.
|
||||||
|
|
||||||
Use https://pkg.go.dev/github.com/cenkalti/backoff/v4 to view the documentation.
|
For most cases, use `Retry` function. See [example_test.go][example] for an example.
|
||||||
|
|
||||||
|
If you have specific needs, copy `Retry` function (from [retry.go][retry-src]) into your code and modify it as needed.
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
@@ -19,12 +21,11 @@ Use https://pkg.go.dev/github.com/cenkalti/backoff/v4 to view the documentation.
|
|||||||
* Please don't send a PR without opening an issue and discussing it first.
|
* Please don't send a PR without opening an issue and discussing it first.
|
||||||
* If proposed change is not a common use case, I will probably not accept it.
|
* If proposed change is not a common use case, I will probably not accept it.
|
||||||
|
|
||||||
[godoc]: https://pkg.go.dev/github.com/cenkalti/backoff/v4
|
[godoc]: https://pkg.go.dev/github.com/cenkalti/backoff/v5
|
||||||
[godoc image]: https://godoc.org/github.com/cenkalti/backoff?status.png
|
[godoc image]: https://godoc.org/github.com/cenkalti/backoff?status.png
|
||||||
[coveralls]: https://coveralls.io/github/cenkalti/backoff?branch=master
|
|
||||||
[coveralls image]: https://coveralls.io/repos/github/cenkalti/backoff/badge.svg?branch=master
|
|
||||||
|
|
||||||
[google-http-java-client]: https://github.com/google/google-http-java-client/blob/da1aa993e90285ec18579f1553339b00e19b3ab5/google-http-client/src/main/java/com/google/api/client/util/ExponentialBackOff.java
|
[google-http-java-client]: https://github.com/google/google-http-java-client/blob/da1aa993e90285ec18579f1553339b00e19b3ab5/google-http-client/src/main/java/com/google/api/client/util/ExponentialBackOff.java
|
||||||
[exponential backoff wiki]: http://en.wikipedia.org/wiki/Exponential_backoff
|
[exponential backoff wiki]: http://en.wikipedia.org/wiki/Exponential_backoff
|
||||||
|
|
||||||
[advanced example]: https://pkg.go.dev/github.com/cenkalti/backoff/v4?tab=doc#pkg-examples
|
[retry-src]: https://github.com/cenkalti/backoff/blob/v5/retry.go
|
||||||
|
[example]: https://github.com/cenkalti/backoff/blob/v5/example_test.go
|
||||||
@@ -15,16 +15,16 @@ import "time"
|
|||||||
// BackOff is a backoff policy for retrying an operation.
|
// BackOff is a backoff policy for retrying an operation.
|
||||||
type BackOff interface {
|
type BackOff interface {
|
||||||
// NextBackOff returns the duration to wait before retrying the operation,
|
// NextBackOff returns the duration to wait before retrying the operation,
|
||||||
// or backoff. Stop to indicate that no more retries should be made.
|
// backoff.Stop to indicate that no more retries should be made.
|
||||||
//
|
//
|
||||||
// Example usage:
|
// Example usage:
|
||||||
//
|
//
|
||||||
// duration := backoff.NextBackOff();
|
// duration := backoff.NextBackOff()
|
||||||
// if (duration == backoff.Stop) {
|
// if duration == backoff.Stop {
|
||||||
// // Do not retry operation.
|
// // Do not retry operation.
|
||||||
// } else {
|
// } else {
|
||||||
// // Sleep for duration and retry operation.
|
// // Sleep for duration and retry operation.
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
NextBackOff() time.Duration
|
NextBackOff() time.Duration
|
||||||
|
|
||||||
46
vendor/github.com/cenkalti/backoff/v5/error.go
generated
vendored
Normal file
46
vendor/github.com/cenkalti/backoff/v5/error.go
generated
vendored
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
package backoff
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// PermanentError signals that the operation should not be retried.
|
||||||
|
type PermanentError struct {
|
||||||
|
Err error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Permanent wraps the given err in a *PermanentError.
|
||||||
|
func Permanent(err error) error {
|
||||||
|
if err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &PermanentError{
|
||||||
|
Err: err,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error returns a string representation of the Permanent error.
|
||||||
|
func (e *PermanentError) Error() string {
|
||||||
|
return e.Err.Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unwrap returns the wrapped error.
|
||||||
|
func (e *PermanentError) Unwrap() error {
|
||||||
|
return e.Err
|
||||||
|
}
|
||||||
|
|
||||||
|
// RetryAfterError signals that the operation should be retried after the given duration.
|
||||||
|
type RetryAfterError struct {
|
||||||
|
Duration time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
// RetryAfter returns a RetryAfter error that specifies how long to wait before retrying.
|
||||||
|
func RetryAfter(seconds int) error {
|
||||||
|
return &RetryAfterError{Duration: time.Duration(seconds) * time.Second}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error returns a string representation of the RetryAfter error.
|
||||||
|
func (e *RetryAfterError) Error() string {
|
||||||
|
return fmt.Sprintf("retry after %s", e.Duration)
|
||||||
|
}
|
||||||
125
vendor/github.com/cenkalti/backoff/v5/exponential.go
generated
vendored
Normal file
125
vendor/github.com/cenkalti/backoff/v5/exponential.go
generated
vendored
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
package backoff
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/rand"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
ExponentialBackOff is a backoff implementation that increases the backoff
|
||||||
|
period for each retry attempt using a randomization function that grows exponentially.
|
||||||
|
|
||||||
|
NextBackOff() is calculated using the following formula:
|
||||||
|
|
||||||
|
randomized interval =
|
||||||
|
RetryInterval * (random value in range [1 - RandomizationFactor, 1 + RandomizationFactor])
|
||||||
|
|
||||||
|
In other words NextBackOff() will range between the randomization factor
|
||||||
|
percentage below and above the retry interval.
|
||||||
|
|
||||||
|
For example, given the following parameters:
|
||||||
|
|
||||||
|
RetryInterval = 2
|
||||||
|
RandomizationFactor = 0.5
|
||||||
|
Multiplier = 2
|
||||||
|
|
||||||
|
the actual backoff period used in the next retry attempt will range between 1 and 3 seconds,
|
||||||
|
multiplied by the exponential, that is, between 2 and 6 seconds.
|
||||||
|
|
||||||
|
Note: MaxInterval caps the RetryInterval and not the randomized interval.
|
||||||
|
|
||||||
|
If the time elapsed since an ExponentialBackOff instance is created goes past the
|
||||||
|
MaxElapsedTime, then the method NextBackOff() starts returning backoff.Stop.
|
||||||
|
|
||||||
|
The elapsed time can be reset by calling Reset().
|
||||||
|
|
||||||
|
Example: Given the following default arguments, for 10 tries the sequence will be,
|
||||||
|
and assuming we go over the MaxElapsedTime on the 10th try:
|
||||||
|
|
||||||
|
Request # RetryInterval (seconds) Randomized Interval (seconds)
|
||||||
|
|
||||||
|
1 0.5 [0.25, 0.75]
|
||||||
|
2 0.75 [0.375, 1.125]
|
||||||
|
3 1.125 [0.562, 1.687]
|
||||||
|
4 1.687 [0.8435, 2.53]
|
||||||
|
5 2.53 [1.265, 3.795]
|
||||||
|
6 3.795 [1.897, 5.692]
|
||||||
|
7 5.692 [2.846, 8.538]
|
||||||
|
8 8.538 [4.269, 12.807]
|
||||||
|
9 12.807 [6.403, 19.210]
|
||||||
|
10 19.210 backoff.Stop
|
||||||
|
|
||||||
|
Note: Implementation is not thread-safe.
|
||||||
|
*/
|
||||||
|
type ExponentialBackOff struct {
|
||||||
|
InitialInterval time.Duration
|
||||||
|
RandomizationFactor float64
|
||||||
|
Multiplier float64
|
||||||
|
MaxInterval time.Duration
|
||||||
|
|
||||||
|
currentInterval time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default values for ExponentialBackOff.
|
||||||
|
const (
|
||||||
|
DefaultInitialInterval = 500 * time.Millisecond
|
||||||
|
DefaultRandomizationFactor = 0.5
|
||||||
|
DefaultMultiplier = 1.5
|
||||||
|
DefaultMaxInterval = 60 * time.Second
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewExponentialBackOff creates an instance of ExponentialBackOff using default values.
|
||||||
|
func NewExponentialBackOff() *ExponentialBackOff {
|
||||||
|
return &ExponentialBackOff{
|
||||||
|
InitialInterval: DefaultInitialInterval,
|
||||||
|
RandomizationFactor: DefaultRandomizationFactor,
|
||||||
|
Multiplier: DefaultMultiplier,
|
||||||
|
MaxInterval: DefaultMaxInterval,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset the interval back to the initial retry interval and restarts the timer.
|
||||||
|
// Reset must be called before using b.
|
||||||
|
func (b *ExponentialBackOff) Reset() {
|
||||||
|
b.currentInterval = b.InitialInterval
|
||||||
|
}
|
||||||
|
|
||||||
|
// NextBackOff calculates the next backoff interval using the formula:
|
||||||
|
//
|
||||||
|
// Randomized interval = RetryInterval * (1 ± RandomizationFactor)
|
||||||
|
func (b *ExponentialBackOff) NextBackOff() time.Duration {
|
||||||
|
if b.currentInterval == 0 {
|
||||||
|
b.currentInterval = b.InitialInterval
|
||||||
|
}
|
||||||
|
|
||||||
|
next := getRandomValueFromInterval(b.RandomizationFactor, rand.Float64(), b.currentInterval)
|
||||||
|
b.incrementCurrentInterval()
|
||||||
|
return next
|
||||||
|
}
|
||||||
|
|
||||||
|
// Increments the current interval by multiplying it with the multiplier.
|
||||||
|
func (b *ExponentialBackOff) incrementCurrentInterval() {
|
||||||
|
// Check for overflow, if overflow is detected set the current interval to the max interval.
|
||||||
|
if float64(b.currentInterval) >= float64(b.MaxInterval)/b.Multiplier {
|
||||||
|
b.currentInterval = b.MaxInterval
|
||||||
|
} else {
|
||||||
|
b.currentInterval = time.Duration(float64(b.currentInterval) * b.Multiplier)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns a random value from the following interval:
|
||||||
|
//
|
||||||
|
// [currentInterval - randomizationFactor * currentInterval, currentInterval + randomizationFactor * currentInterval].
|
||||||
|
func getRandomValueFromInterval(randomizationFactor, random float64, currentInterval time.Duration) time.Duration {
|
||||||
|
if randomizationFactor == 0 {
|
||||||
|
return currentInterval // make sure no randomness is used when randomizationFactor is 0.
|
||||||
|
}
|
||||||
|
var delta = randomizationFactor * float64(currentInterval)
|
||||||
|
var minInterval = float64(currentInterval) - delta
|
||||||
|
var maxInterval = float64(currentInterval) + delta
|
||||||
|
|
||||||
|
// Get a random value from the range [minInterval, maxInterval].
|
||||||
|
// The formula used below has a +1 because if the minInterval is 1 and the maxInterval is 3 then
|
||||||
|
// we want a 33% chance for selecting either 1, 2 or 3.
|
||||||
|
return time.Duration(minInterval + (random * (maxInterval - minInterval + 1)))
|
||||||
|
}
|
||||||
139
vendor/github.com/cenkalti/backoff/v5/retry.go
generated
vendored
Normal file
139
vendor/github.com/cenkalti/backoff/v5/retry.go
generated
vendored
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
package backoff
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DefaultMaxElapsedTime sets a default limit for the total retry duration.
|
||||||
|
const DefaultMaxElapsedTime = 15 * time.Minute
|
||||||
|
|
||||||
|
// Operation is a function that attempts an operation and may be retried.
|
||||||
|
type Operation[T any] func() (T, error)
|
||||||
|
|
||||||
|
// Notify is a function called on operation error with the error and backoff duration.
|
||||||
|
type Notify func(error, time.Duration)
|
||||||
|
|
||||||
|
// retryOptions holds configuration settings for the retry mechanism.
|
||||||
|
type retryOptions struct {
|
||||||
|
BackOff BackOff // Strategy for calculating backoff periods.
|
||||||
|
Timer timer // Timer to manage retry delays.
|
||||||
|
Notify Notify // Optional function to notify on each retry error.
|
||||||
|
MaxTries uint // Maximum number of retry attempts.
|
||||||
|
MaxElapsedTime time.Duration // Maximum total time for all retries.
|
||||||
|
}
|
||||||
|
|
||||||
|
type RetryOption func(*retryOptions)
|
||||||
|
|
||||||
|
// WithBackOff configures a custom backoff strategy.
|
||||||
|
func WithBackOff(b BackOff) RetryOption {
|
||||||
|
return func(args *retryOptions) {
|
||||||
|
args.BackOff = b
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// withTimer sets a custom timer for managing delays between retries.
|
||||||
|
func withTimer(t timer) RetryOption {
|
||||||
|
return func(args *retryOptions) {
|
||||||
|
args.Timer = t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithNotify sets a notification function to handle retry errors.
|
||||||
|
func WithNotify(n Notify) RetryOption {
|
||||||
|
return func(args *retryOptions) {
|
||||||
|
args.Notify = n
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithMaxTries limits the number of retry attempts.
|
||||||
|
func WithMaxTries(n uint) RetryOption {
|
||||||
|
return func(args *retryOptions) {
|
||||||
|
args.MaxTries = n
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithMaxElapsedTime limits the total duration for retry attempts.
|
||||||
|
func WithMaxElapsedTime(d time.Duration) RetryOption {
|
||||||
|
return func(args *retryOptions) {
|
||||||
|
args.MaxElapsedTime = d
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retry attempts the operation until success, a permanent error, or backoff completion.
|
||||||
|
// It ensures the operation is executed at least once.
|
||||||
|
//
|
||||||
|
// Returns the operation result or error if retries are exhausted or context is cancelled.
|
||||||
|
func Retry[T any](ctx context.Context, operation Operation[T], opts ...RetryOption) (T, error) {
|
||||||
|
// Initialize default retry options.
|
||||||
|
args := &retryOptions{
|
||||||
|
BackOff: NewExponentialBackOff(),
|
||||||
|
Timer: &defaultTimer{},
|
||||||
|
MaxElapsedTime: DefaultMaxElapsedTime,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply user-provided options to the default settings.
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(args)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer args.Timer.Stop()
|
||||||
|
|
||||||
|
startedAt := time.Now()
|
||||||
|
args.BackOff.Reset()
|
||||||
|
for numTries := uint(1); ; numTries++ {
|
||||||
|
// Execute the operation.
|
||||||
|
res, err := operation()
|
||||||
|
if err == nil {
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop retrying if maximum tries exceeded.
|
||||||
|
if args.MaxTries > 0 && numTries >= args.MaxTries {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle permanent errors without retrying.
|
||||||
|
var permanent *PermanentError
|
||||||
|
if errors.As(err, &permanent) {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop retrying if context is cancelled.
|
||||||
|
if cerr := context.Cause(ctx); cerr != nil {
|
||||||
|
return res, cerr
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate next backoff duration.
|
||||||
|
next := args.BackOff.NextBackOff()
|
||||||
|
if next == Stop {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset backoff if RetryAfterError is encountered.
|
||||||
|
var retryAfter *RetryAfterError
|
||||||
|
if errors.As(err, &retryAfter) {
|
||||||
|
next = retryAfter.Duration
|
||||||
|
args.BackOff.Reset()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop retrying if maximum elapsed time exceeded.
|
||||||
|
if args.MaxElapsedTime > 0 && time.Since(startedAt)+next > args.MaxElapsedTime {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Notify on error if a notifier function is provided.
|
||||||
|
if args.Notify != nil {
|
||||||
|
args.Notify(err, next)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for the next backoff period or context cancellation.
|
||||||
|
args.Timer.Start(next)
|
||||||
|
select {
|
||||||
|
case <-args.Timer.C():
|
||||||
|
case <-ctx.Done():
|
||||||
|
return res, context.Cause(ctx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
package backoff
|
package backoff
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@@ -14,8 +13,7 @@ type Ticker struct {
|
|||||||
C <-chan time.Time
|
C <-chan time.Time
|
||||||
c chan time.Time
|
c chan time.Time
|
||||||
b BackOff
|
b BackOff
|
||||||
ctx context.Context
|
timer timer
|
||||||
timer Timer
|
|
||||||
stop chan struct{}
|
stop chan struct{}
|
||||||
stopOnce sync.Once
|
stopOnce sync.Once
|
||||||
}
|
}
|
||||||
@@ -27,22 +25,12 @@ type Ticker struct {
|
|||||||
// provided backoff policy (notably calling NextBackOff or Reset)
|
// provided backoff policy (notably calling NextBackOff or Reset)
|
||||||
// while the ticker is running.
|
// while the ticker is running.
|
||||||
func NewTicker(b BackOff) *Ticker {
|
func NewTicker(b BackOff) *Ticker {
|
||||||
return NewTickerWithTimer(b, &defaultTimer{})
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewTickerWithTimer returns a new Ticker with a custom timer.
|
|
||||||
// A default timer that uses system timer is used when nil is passed.
|
|
||||||
func NewTickerWithTimer(b BackOff, timer Timer) *Ticker {
|
|
||||||
if timer == nil {
|
|
||||||
timer = &defaultTimer{}
|
|
||||||
}
|
|
||||||
c := make(chan time.Time)
|
c := make(chan time.Time)
|
||||||
t := &Ticker{
|
t := &Ticker{
|
||||||
C: c,
|
C: c,
|
||||||
c: c,
|
c: c,
|
||||||
b: b,
|
b: b,
|
||||||
ctx: getContext(b),
|
timer: &defaultTimer{},
|
||||||
timer: timer,
|
|
||||||
stop: make(chan struct{}),
|
stop: make(chan struct{}),
|
||||||
}
|
}
|
||||||
t.b.Reset()
|
t.b.Reset()
|
||||||
@@ -73,8 +61,6 @@ func (t *Ticker) run() {
|
|||||||
case <-t.stop:
|
case <-t.stop:
|
||||||
t.c = nil // Prevent future ticks from being sent to the channel.
|
t.c = nil // Prevent future ticks from being sent to the channel.
|
||||||
return
|
return
|
||||||
case <-t.ctx.Done():
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,7 +2,7 @@ package backoff
|
|||||||
|
|
||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
type Timer interface {
|
type timer interface {
|
||||||
Start(duration time.Duration)
|
Start(duration time.Duration)
|
||||||
Stop()
|
Stop()
|
||||||
C() <-chan time.Time
|
C() <-chan time.Time
|
||||||
62
vendor/github.com/cpuguy83/go-md2man/v2/md2man/debug.go
generated
vendored
Normal file
62
vendor/github.com/cpuguy83/go-md2man/v2/md2man/debug.go
generated
vendored
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
package md2man
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/russross/blackfriday/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func fmtListFlags(flags blackfriday.ListType) string {
|
||||||
|
knownFlags := []struct {
|
||||||
|
name string
|
||||||
|
flag blackfriday.ListType
|
||||||
|
}{
|
||||||
|
{"ListTypeOrdered", blackfriday.ListTypeOrdered},
|
||||||
|
{"ListTypeDefinition", blackfriday.ListTypeDefinition},
|
||||||
|
{"ListTypeTerm", blackfriday.ListTypeTerm},
|
||||||
|
{"ListItemContainsBlock", blackfriday.ListItemContainsBlock},
|
||||||
|
{"ListItemBeginningOfList", blackfriday.ListItemBeginningOfList},
|
||||||
|
{"ListItemEndOfList", blackfriday.ListItemEndOfList},
|
||||||
|
}
|
||||||
|
|
||||||
|
var f []string
|
||||||
|
for _, kf := range knownFlags {
|
||||||
|
if flags&kf.flag != 0 {
|
||||||
|
f = append(f, kf.name)
|
||||||
|
flags &^= kf.flag
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if flags != 0 {
|
||||||
|
f = append(f, fmt.Sprintf("Unknown(%#x)", flags))
|
||||||
|
}
|
||||||
|
return strings.Join(f, "|")
|
||||||
|
}
|
||||||
|
|
||||||
|
type debugDecorator struct {
|
||||||
|
blackfriday.Renderer
|
||||||
|
}
|
||||||
|
|
||||||
|
func depth(node *blackfriday.Node) int {
|
||||||
|
d := 0
|
||||||
|
for n := node.Parent; n != nil; n = n.Parent {
|
||||||
|
d++
|
||||||
|
}
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *debugDecorator) RenderNode(w io.Writer, node *blackfriday.Node, entering bool) blackfriday.WalkStatus {
|
||||||
|
fmt.Fprintf(os.Stderr, "%s%s %v %v\n",
|
||||||
|
strings.Repeat(" ", depth(node)),
|
||||||
|
map[bool]string{true: "+", false: "-"}[entering],
|
||||||
|
node,
|
||||||
|
fmtListFlags(node.ListFlags))
|
||||||
|
var b strings.Builder
|
||||||
|
status := d.Renderer.RenderNode(io.MultiWriter(&b, w), node, entering)
|
||||||
|
if b.Len() > 0 {
|
||||||
|
fmt.Fprintf(os.Stderr, ">> %q\n", b.String())
|
||||||
|
}
|
||||||
|
return status
|
||||||
|
}
|
||||||
9
vendor/github.com/cpuguy83/go-md2man/v2/md2man/md2man.go
generated
vendored
9
vendor/github.com/cpuguy83/go-md2man/v2/md2man/md2man.go
generated
vendored
@@ -1,16 +1,23 @@
|
|||||||
package md2man
|
package md2man
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
"github.com/russross/blackfriday/v2"
|
"github.com/russross/blackfriday/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Render converts a markdown document into a roff formatted document.
|
// Render converts a markdown document into a roff formatted document.
|
||||||
func Render(doc []byte) []byte {
|
func Render(doc []byte) []byte {
|
||||||
renderer := NewRoffRenderer()
|
renderer := NewRoffRenderer()
|
||||||
|
var r blackfriday.Renderer = renderer
|
||||||
|
if v, _ := strconv.ParseBool(os.Getenv("MD2MAN_DEBUG")); v {
|
||||||
|
r = &debugDecorator{Renderer: r}
|
||||||
|
}
|
||||||
|
|
||||||
return blackfriday.Run(doc,
|
return blackfriday.Run(doc,
|
||||||
[]blackfriday.Option{
|
[]blackfriday.Option{
|
||||||
blackfriday.WithRenderer(renderer),
|
blackfriday.WithRenderer(r),
|
||||||
blackfriday.WithExtensions(renderer.GetExtensions()),
|
blackfriday.WithExtensions(renderer.GetExtensions()),
|
||||||
}...)
|
}...)
|
||||||
}
|
}
|
||||||
|
|||||||
97
vendor/github.com/cpuguy83/go-md2man/v2/md2man/roff.go
generated
vendored
97
vendor/github.com/cpuguy83/go-md2man/v2/md2man/roff.go
generated
vendored
@@ -14,10 +14,8 @@ import (
|
|||||||
// roffRenderer implements the blackfriday.Renderer interface for creating
|
// roffRenderer implements the blackfriday.Renderer interface for creating
|
||||||
// roff format (manpages) from markdown text
|
// roff format (manpages) from markdown text
|
||||||
type roffRenderer struct {
|
type roffRenderer struct {
|
||||||
extensions blackfriday.Extensions
|
|
||||||
listCounters []int
|
listCounters []int
|
||||||
firstHeader bool
|
firstHeader bool
|
||||||
firstDD bool
|
|
||||||
listDepth int
|
listDepth int
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,7 +41,7 @@ const (
|
|||||||
quoteTag = "\n.PP\n.RS\n"
|
quoteTag = "\n.PP\n.RS\n"
|
||||||
quoteCloseTag = "\n.RE\n"
|
quoteCloseTag = "\n.RE\n"
|
||||||
listTag = "\n.RS\n"
|
listTag = "\n.RS\n"
|
||||||
listCloseTag = "\n.RE\n"
|
listCloseTag = ".RE\n"
|
||||||
dtTag = "\n.TP\n"
|
dtTag = "\n.TP\n"
|
||||||
dd2Tag = "\n"
|
dd2Tag = "\n"
|
||||||
tableStart = "\n.TS\nallbox;\n"
|
tableStart = "\n.TS\nallbox;\n"
|
||||||
@@ -56,23 +54,18 @@ const (
|
|||||||
// NewRoffRenderer creates a new blackfriday Renderer for generating roff documents
|
// NewRoffRenderer creates a new blackfriday Renderer for generating roff documents
|
||||||
// from markdown
|
// from markdown
|
||||||
func NewRoffRenderer() *roffRenderer { // nolint: golint
|
func NewRoffRenderer() *roffRenderer { // nolint: golint
|
||||||
var extensions blackfriday.Extensions
|
return &roffRenderer{}
|
||||||
|
|
||||||
extensions |= blackfriday.NoIntraEmphasis
|
|
||||||
extensions |= blackfriday.Tables
|
|
||||||
extensions |= blackfriday.FencedCode
|
|
||||||
extensions |= blackfriday.SpaceHeadings
|
|
||||||
extensions |= blackfriday.Footnotes
|
|
||||||
extensions |= blackfriday.Titleblock
|
|
||||||
extensions |= blackfriday.DefinitionLists
|
|
||||||
return &roffRenderer{
|
|
||||||
extensions: extensions,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetExtensions returns the list of extensions used by this renderer implementation
|
// GetExtensions returns the list of extensions used by this renderer implementation
|
||||||
func (r *roffRenderer) GetExtensions() blackfriday.Extensions {
|
func (*roffRenderer) GetExtensions() blackfriday.Extensions {
|
||||||
return r.extensions
|
return blackfriday.NoIntraEmphasis |
|
||||||
|
blackfriday.Tables |
|
||||||
|
blackfriday.FencedCode |
|
||||||
|
blackfriday.SpaceHeadings |
|
||||||
|
blackfriday.Footnotes |
|
||||||
|
blackfriday.Titleblock |
|
||||||
|
blackfriday.DefinitionLists
|
||||||
}
|
}
|
||||||
|
|
||||||
// RenderHeader handles outputting the header at document start
|
// RenderHeader handles outputting the header at document start
|
||||||
@@ -103,7 +96,23 @@ func (r *roffRenderer) RenderNode(w io.Writer, node *blackfriday.Node, entering
|
|||||||
|
|
||||||
switch node.Type {
|
switch node.Type {
|
||||||
case blackfriday.Text:
|
case blackfriday.Text:
|
||||||
escapeSpecialChars(w, node.Literal)
|
// Special case: format the NAME section as required for proper whatis parsing.
|
||||||
|
// Refer to the lexgrog(1) and groff_man(7) manual pages for details.
|
||||||
|
if node.Parent != nil &&
|
||||||
|
node.Parent.Type == blackfriday.Paragraph &&
|
||||||
|
node.Parent.Prev != nil &&
|
||||||
|
node.Parent.Prev.Type == blackfriday.Heading &&
|
||||||
|
node.Parent.Prev.FirstChild != nil &&
|
||||||
|
bytes.EqualFold(node.Parent.Prev.FirstChild.Literal, []byte("NAME")) {
|
||||||
|
before, after, found := bytesCut(node.Literal, []byte(" - "))
|
||||||
|
escapeSpecialChars(w, before)
|
||||||
|
if found {
|
||||||
|
out(w, ` \- `)
|
||||||
|
escapeSpecialChars(w, after)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
escapeSpecialChars(w, node.Literal)
|
||||||
|
}
|
||||||
case blackfriday.Softbreak:
|
case blackfriday.Softbreak:
|
||||||
out(w, crTag)
|
out(w, crTag)
|
||||||
case blackfriday.Hardbreak:
|
case blackfriday.Hardbreak:
|
||||||
@@ -141,14 +150,25 @@ func (r *roffRenderer) RenderNode(w io.Writer, node *blackfriday.Node, entering
|
|||||||
case blackfriday.Document:
|
case blackfriday.Document:
|
||||||
break
|
break
|
||||||
case blackfriday.Paragraph:
|
case blackfriday.Paragraph:
|
||||||
// roff .PP markers break lists
|
|
||||||
if r.listDepth > 0 {
|
|
||||||
return blackfriday.GoToNext
|
|
||||||
}
|
|
||||||
if entering {
|
if entering {
|
||||||
out(w, paraTag)
|
if r.listDepth > 0 {
|
||||||
|
// roff .PP markers break lists
|
||||||
|
if node.Prev != nil { // continued paragraph
|
||||||
|
if node.Prev.Type == blackfriday.List && node.Prev.ListFlags&blackfriday.ListTypeDefinition == 0 {
|
||||||
|
out(w, ".IP\n")
|
||||||
|
} else {
|
||||||
|
out(w, crTag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if node.Prev != nil && node.Prev.Type == blackfriday.Heading {
|
||||||
|
out(w, crTag)
|
||||||
|
} else {
|
||||||
|
out(w, paraTag)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
out(w, crTag)
|
if node.Next == nil || node.Next.Type != blackfriday.List {
|
||||||
|
out(w, crTag)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
case blackfriday.BlockQuote:
|
case blackfriday.BlockQuote:
|
||||||
if entering {
|
if entering {
|
||||||
@@ -211,6 +231,10 @@ func (r *roffRenderer) handleHeading(w io.Writer, node *blackfriday.Node, enteri
|
|||||||
func (r *roffRenderer) handleList(w io.Writer, node *blackfriday.Node, entering bool) {
|
func (r *roffRenderer) handleList(w io.Writer, node *blackfriday.Node, entering bool) {
|
||||||
openTag := listTag
|
openTag := listTag
|
||||||
closeTag := listCloseTag
|
closeTag := listCloseTag
|
||||||
|
if (entering && r.listDepth == 0) || (!entering && r.listDepth == 1) {
|
||||||
|
openTag = crTag
|
||||||
|
closeTag = ""
|
||||||
|
}
|
||||||
if node.ListFlags&blackfriday.ListTypeDefinition != 0 {
|
if node.ListFlags&blackfriday.ListTypeDefinition != 0 {
|
||||||
// tags for definition lists handled within Item node
|
// tags for definition lists handled within Item node
|
||||||
openTag = ""
|
openTag = ""
|
||||||
@@ -239,23 +263,25 @@ func (r *roffRenderer) handleItem(w io.Writer, node *blackfriday.Node, entering
|
|||||||
} else if node.ListFlags&blackfriday.ListTypeTerm != 0 {
|
} else if node.ListFlags&blackfriday.ListTypeTerm != 0 {
|
||||||
// DT (definition term): line just before DD (see below).
|
// DT (definition term): line just before DD (see below).
|
||||||
out(w, dtTag)
|
out(w, dtTag)
|
||||||
r.firstDD = true
|
|
||||||
} else if node.ListFlags&blackfriday.ListTypeDefinition != 0 {
|
} else if node.ListFlags&blackfriday.ListTypeDefinition != 0 {
|
||||||
// DD (definition description): line that starts with ": ".
|
// DD (definition description): line that starts with ": ".
|
||||||
//
|
//
|
||||||
// We have to distinguish between the first DD and the
|
// We have to distinguish between the first DD and the
|
||||||
// subsequent ones, as there should be no vertical
|
// subsequent ones, as there should be no vertical
|
||||||
// whitespace between the DT and the first DD.
|
// whitespace between the DT and the first DD.
|
||||||
if r.firstDD {
|
if node.Prev != nil && node.Prev.ListFlags&(blackfriday.ListTypeTerm|blackfriday.ListTypeDefinition) == blackfriday.ListTypeDefinition {
|
||||||
r.firstDD = false
|
if node.Prev.Type == blackfriday.Item &&
|
||||||
} else {
|
node.Prev.LastChild != nil &&
|
||||||
out(w, dd2Tag)
|
node.Prev.LastChild.Type == blackfriday.List &&
|
||||||
|
node.Prev.LastChild.ListFlags&blackfriday.ListTypeDefinition == 0 {
|
||||||
|
out(w, ".IP\n")
|
||||||
|
} else {
|
||||||
|
out(w, dd2Tag)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
out(w, ".IP \\(bu 2\n")
|
out(w, ".IP \\(bu 2\n")
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
out(w, "\n")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -380,3 +406,12 @@ func escapeSpecialCharsLine(w io.Writer, text []byte) {
|
|||||||
w.Write([]byte{'\\', text[i]}) // nolint: errcheck
|
w.Write([]byte{'\\', text[i]}) // nolint: errcheck
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// bytesCut is a copy of [bytes.Cut] to provide compatibility with go1.17
|
||||||
|
// and older. We can remove this once we drop support for go1.17 and older.
|
||||||
|
func bytesCut(s, sep []byte) (before, after []byte, found bool) {
|
||||||
|
if i := bytes.Index(s, sep); i >= 0 {
|
||||||
|
return s[:i], s[i+len(sep):], true
|
||||||
|
}
|
||||||
|
return s, nil, false
|
||||||
|
}
|
||||||
|
|||||||
21
vendor/github.com/emicklei/go-restful/v3/CHANGES.md
generated
vendored
21
vendor/github.com/emicklei/go-restful/v3/CHANGES.md
generated
vendored
@@ -1,5 +1,26 @@
|
|||||||
# Change history of go-restful
|
# Change history of go-restful
|
||||||
|
|
||||||
|
## [v3.12.2] - 2025-02-21
|
||||||
|
|
||||||
|
- allow empty payloads in post,put,patch, issue #580 ( thanks @liggitt, Jordan Liggitt)
|
||||||
|
|
||||||
|
## [v3.12.1] - 2024-05-28
|
||||||
|
|
||||||
|
- fix misroute when dealing multiple webservice with regex (#549) (thanks Haitao Chen)
|
||||||
|
|
||||||
|
## [v3.12.0] - 2024-03-11
|
||||||
|
|
||||||
|
- add Flush method #529 (#538)
|
||||||
|
- fix: Improper handling of empty POST requests (#543)
|
||||||
|
|
||||||
|
## [v3.11.3] - 2024-01-09
|
||||||
|
|
||||||
|
- better not have 2 tags on one commit
|
||||||
|
|
||||||
|
## [v3.11.1, v3.11.2] - 2024-01-09
|
||||||
|
|
||||||
|
- fix by restoring custom JSON handler functions (Mike Beaumont #540)
|
||||||
|
|
||||||
## [v3.11.0] - 2023-08-19
|
## [v3.11.0] - 2023-08-19
|
||||||
|
|
||||||
- restored behavior as <= v3.9.0 with option to change path strategy using TrimRightSlashEnabled.
|
- restored behavior as <= v3.9.0 with option to change path strategy using TrimRightSlashEnabled.
|
||||||
|
|||||||
6
vendor/github.com/emicklei/go-restful/v3/README.md
generated
vendored
6
vendor/github.com/emicklei/go-restful/v3/README.md
generated
vendored
@@ -2,9 +2,8 @@ go-restful
|
|||||||
==========
|
==========
|
||||||
package for building REST-style Web Services using Google Go
|
package for building REST-style Web Services using Google Go
|
||||||
|
|
||||||
[](https://travis-ci.org/emicklei/go-restful)
|
|
||||||
[](https://goreportcard.com/report/github.com/emicklei/go-restful)
|
[](https://goreportcard.com/report/github.com/emicklei/go-restful)
|
||||||
[](https://pkg.go.dev/github.com/emicklei/go-restful)
|
[](https://pkg.go.dev/github.com/emicklei/go-restful/v3)
|
||||||
[](https://codecov.io/gh/emicklei/go-restful)
|
[](https://codecov.io/gh/emicklei/go-restful)
|
||||||
|
|
||||||
- [Code examples use v3](https://github.com/emicklei/go-restful/tree/v3/examples)
|
- [Code examples use v3](https://github.com/emicklei/go-restful/tree/v3/examples)
|
||||||
@@ -95,8 +94,7 @@ There are several hooks to customize the behavior of the go-restful package.
|
|||||||
- Trace logging
|
- Trace logging
|
||||||
- Compression
|
- Compression
|
||||||
- Encoders for other serializers
|
- Encoders for other serializers
|
||||||
- Use [jsoniter](https://github.com/json-iterator/go) by building this package using a build tag, e.g. `go build -tags=jsoniter .`
|
- Use the package variable `TrimRightSlashEnabled` (default true) to control the behavior of matching routes that end with a slash `/`
|
||||||
- Use the package variable `TrimRightSlashEnabled` (default true) to control the behavior of matching routes that end with a slash `/`
|
|
||||||
|
|
||||||
## Resources
|
## Resources
|
||||||
|
|
||||||
|
|||||||
10
vendor/github.com/emicklei/go-restful/v3/compress.go
generated
vendored
10
vendor/github.com/emicklei/go-restful/v3/compress.go
generated
vendored
@@ -49,6 +49,16 @@ func (c *CompressingResponseWriter) CloseNotify() <-chan bool {
|
|||||||
return c.writer.(http.CloseNotifier).CloseNotify()
|
return c.writer.(http.CloseNotifier).CloseNotify()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Flush is part of http.Flusher interface. Noop if the underlying writer doesn't support it.
|
||||||
|
func (c *CompressingResponseWriter) Flush() {
|
||||||
|
flusher, ok := c.writer.(http.Flusher)
|
||||||
|
if !ok {
|
||||||
|
// writer doesn't support http.Flusher interface
|
||||||
|
return
|
||||||
|
}
|
||||||
|
flusher.Flush()
|
||||||
|
}
|
||||||
|
|
||||||
// Close the underlying compressor
|
// Close the underlying compressor
|
||||||
func (c *CompressingResponseWriter) Close() error {
|
func (c *CompressingResponseWriter) Close() error {
|
||||||
if c.isCompressorClosed() {
|
if c.isCompressorClosed() {
|
||||||
|
|||||||
48
vendor/github.com/emicklei/go-restful/v3/curly.go
generated
vendored
48
vendor/github.com/emicklei/go-restful/v3/curly.go
generated
vendored
@@ -46,10 +46,10 @@ func (c CurlyRouter) SelectRoute(
|
|||||||
// selectRoutes return a collection of Route from a WebService that matches the path tokens from the request.
|
// selectRoutes return a collection of Route from a WebService that matches the path tokens from the request.
|
||||||
func (c CurlyRouter) selectRoutes(ws *WebService, requestTokens []string) sortableCurlyRoutes {
|
func (c CurlyRouter) selectRoutes(ws *WebService, requestTokens []string) sortableCurlyRoutes {
|
||||||
candidates := make(sortableCurlyRoutes, 0, 8)
|
candidates := make(sortableCurlyRoutes, 0, 8)
|
||||||
for _, each := range ws.routes {
|
for _, eachRoute := range ws.routes {
|
||||||
matches, paramCount, staticCount := c.matchesRouteByPathTokens(each.pathParts, requestTokens, each.hasCustomVerb)
|
matches, paramCount, staticCount := c.matchesRouteByPathTokens(eachRoute.pathParts, requestTokens, eachRoute.hasCustomVerb)
|
||||||
if matches {
|
if matches {
|
||||||
candidates.add(curlyRoute{each, paramCount, staticCount}) // TODO make sure Routes() return pointers?
|
candidates.add(curlyRoute{eachRoute, paramCount, staticCount}) // TODO make sure Routes() return pointers?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sort.Sort(candidates)
|
sort.Sort(candidates)
|
||||||
@@ -72,7 +72,7 @@ func (c CurlyRouter) matchesRouteByPathTokens(routeTokens, requestTokens []strin
|
|||||||
return false, 0, 0
|
return false, 0, 0
|
||||||
}
|
}
|
||||||
requestToken := requestTokens[i]
|
requestToken := requestTokens[i]
|
||||||
if routeHasCustomVerb && hasCustomVerb(routeToken){
|
if routeHasCustomVerb && hasCustomVerb(routeToken) {
|
||||||
if !isMatchCustomVerb(routeToken, requestToken) {
|
if !isMatchCustomVerb(routeToken, requestToken) {
|
||||||
return false, 0, 0
|
return false, 0, 0
|
||||||
}
|
}
|
||||||
@@ -129,44 +129,52 @@ func (c CurlyRouter) detectRoute(candidateRoutes sortableCurlyRoutes, httpReques
|
|||||||
// detectWebService returns the best matching webService given the list of path tokens.
|
// detectWebService returns the best matching webService given the list of path tokens.
|
||||||
// see also computeWebserviceScore
|
// see also computeWebserviceScore
|
||||||
func (c CurlyRouter) detectWebService(requestTokens []string, webServices []*WebService) *WebService {
|
func (c CurlyRouter) detectWebService(requestTokens []string, webServices []*WebService) *WebService {
|
||||||
var best *WebService
|
var bestWs *WebService
|
||||||
score := -1
|
score := -1
|
||||||
for _, each := range webServices {
|
for _, eachWS := range webServices {
|
||||||
matches, eachScore := c.computeWebserviceScore(requestTokens, each.pathExpr.tokens)
|
matches, eachScore := c.computeWebserviceScore(requestTokens, eachWS.pathExpr.tokens)
|
||||||
if matches && (eachScore > score) {
|
if matches && (eachScore > score) {
|
||||||
best = each
|
bestWs = eachWS
|
||||||
score = eachScore
|
score = eachScore
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return best
|
return bestWs
|
||||||
}
|
}
|
||||||
|
|
||||||
// computeWebserviceScore returns whether tokens match and
|
// computeWebserviceScore returns whether tokens match and
|
||||||
// the weighted score of the longest matching consecutive tokens from the beginning.
|
// the weighted score of the longest matching consecutive tokens from the beginning.
|
||||||
func (c CurlyRouter) computeWebserviceScore(requestTokens []string, tokens []string) (bool, int) {
|
func (c CurlyRouter) computeWebserviceScore(requestTokens []string, routeTokens []string) (bool, int) {
|
||||||
if len(tokens) > len(requestTokens) {
|
if len(routeTokens) > len(requestTokens) {
|
||||||
return false, 0
|
return false, 0
|
||||||
}
|
}
|
||||||
score := 0
|
score := 0
|
||||||
for i := 0; i < len(tokens); i++ {
|
for i := 0; i < len(routeTokens); i++ {
|
||||||
each := requestTokens[i]
|
eachRequestToken := requestTokens[i]
|
||||||
other := tokens[i]
|
eachRouteToken := routeTokens[i]
|
||||||
if len(each) == 0 && len(other) == 0 {
|
if len(eachRequestToken) == 0 && len(eachRouteToken) == 0 {
|
||||||
score++
|
score++
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if len(other) > 0 && strings.HasPrefix(other, "{") {
|
if len(eachRouteToken) > 0 && strings.HasPrefix(eachRouteToken, "{") {
|
||||||
// no empty match
|
// no empty match
|
||||||
if len(each) == 0 {
|
if len(eachRequestToken) == 0 {
|
||||||
return false, score
|
return false, score
|
||||||
}
|
}
|
||||||
score += 1
|
score++
|
||||||
|
|
||||||
|
if colon := strings.Index(eachRouteToken, ":"); colon != -1 {
|
||||||
|
// match by regex
|
||||||
|
matchesToken, _ := c.regularMatchesPathToken(eachRouteToken, colon, eachRequestToken)
|
||||||
|
if matchesToken {
|
||||||
|
score++ // extra score for regex match
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// not a parameter
|
// not a parameter
|
||||||
if each != other {
|
if eachRequestToken != eachRouteToken {
|
||||||
return false, score
|
return false, score
|
||||||
}
|
}
|
||||||
score += (len(tokens) - i) * 10 //fuzzy
|
score += (len(routeTokens) - i) * 10 //fuzzy
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true, score
|
return true, score
|
||||||
|
|||||||
7
vendor/github.com/emicklei/go-restful/v3/entity_accessors.go
generated
vendored
7
vendor/github.com/emicklei/go-restful/v3/entity_accessors.go
generated
vendored
@@ -5,11 +5,18 @@ package restful
|
|||||||
// that can be found in the LICENSE file.
|
// that can be found in the LICENSE file.
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"encoding/xml"
|
"encoding/xml"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
MarshalIndent = json.MarshalIndent
|
||||||
|
NewDecoder = json.NewDecoder
|
||||||
|
NewEncoder = json.NewEncoder
|
||||||
|
)
|
||||||
|
|
||||||
// EntityReaderWriter can read and write values using an encoding such as JSON,XML.
|
// EntityReaderWriter can read and write values using an encoding such as JSON,XML.
|
||||||
type EntityReaderWriter interface {
|
type EntityReaderWriter interface {
|
||||||
// Read a serialized version of the value from the request.
|
// Read a serialized version of the value from the request.
|
||||||
|
|||||||
11
vendor/github.com/emicklei/go-restful/v3/json.go
generated
vendored
11
vendor/github.com/emicklei/go-restful/v3/json.go
generated
vendored
@@ -1,11 +0,0 @@
|
|||||||
// +build !jsoniter
|
|
||||||
|
|
||||||
package restful
|
|
||||||
|
|
||||||
import "encoding/json"
|
|
||||||
|
|
||||||
var (
|
|
||||||
MarshalIndent = json.MarshalIndent
|
|
||||||
NewDecoder = json.NewDecoder
|
|
||||||
NewEncoder = json.NewEncoder
|
|
||||||
)
|
|
||||||
12
vendor/github.com/emicklei/go-restful/v3/jsoniter.go
generated
vendored
12
vendor/github.com/emicklei/go-restful/v3/jsoniter.go
generated
vendored
@@ -1,12 +0,0 @@
|
|||||||
// +build jsoniter
|
|
||||||
|
|
||||||
package restful
|
|
||||||
|
|
||||||
import "github.com/json-iterator/go"
|
|
||||||
|
|
||||||
var (
|
|
||||||
json = jsoniter.ConfigCompatibleWithStandardLibrary
|
|
||||||
MarshalIndent = json.MarshalIndent
|
|
||||||
NewDecoder = json.NewDecoder
|
|
||||||
NewEncoder = json.NewEncoder
|
|
||||||
)
|
|
||||||
19
vendor/github.com/emicklei/go-restful/v3/jsr311.go
generated
vendored
19
vendor/github.com/emicklei/go-restful/v3/jsr311.go
generated
vendored
@@ -65,7 +65,7 @@ func (RouterJSR311) extractParams(pathExpr *pathExpression, matches []string) ma
|
|||||||
return params
|
return params
|
||||||
}
|
}
|
||||||
|
|
||||||
// http://jsr311.java.net/nonav/releases/1.1/spec/spec3.html#x3-360003.7.2
|
// https://download.oracle.com/otndocs/jcp/jaxrs-1.1-mrel-eval-oth-JSpec/
|
||||||
func (r RouterJSR311) detectRoute(routes []Route, httpRequest *http.Request) (*Route, error) {
|
func (r RouterJSR311) detectRoute(routes []Route, httpRequest *http.Request) (*Route, error) {
|
||||||
candidates := make([]*Route, 0, 8)
|
candidates := make([]*Route, 0, 8)
|
||||||
for i, each := range routes {
|
for i, each := range routes {
|
||||||
@@ -126,9 +126,7 @@ func (r RouterJSR311) detectRoute(routes []Route, httpRequest *http.Request) (*R
|
|||||||
if trace {
|
if trace {
|
||||||
traceLogger.Printf("no Route found (from %d) that matches HTTP Content-Type: %s\n", len(previous), contentType)
|
traceLogger.Printf("no Route found (from %d) that matches HTTP Content-Type: %s\n", len(previous), contentType)
|
||||||
}
|
}
|
||||||
if httpRequest.ContentLength > 0 {
|
return nil, NewError(http.StatusUnsupportedMediaType, "415: Unsupported Media Type")
|
||||||
return nil, NewError(http.StatusUnsupportedMediaType, "415: Unsupported Media Type")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// accept
|
// accept
|
||||||
@@ -151,20 +149,9 @@ func (r RouterJSR311) detectRoute(routes []Route, httpRequest *http.Request) (*R
|
|||||||
for _, candidate := range previous {
|
for _, candidate := range previous {
|
||||||
available = append(available, candidate.Produces...)
|
available = append(available, candidate.Produces...)
|
||||||
}
|
}
|
||||||
// if POST,PUT,PATCH without body
|
|
||||||
method, length := httpRequest.Method, httpRequest.Header.Get("Content-Length")
|
|
||||||
if (method == http.MethodPost ||
|
|
||||||
method == http.MethodPut ||
|
|
||||||
method == http.MethodPatch) && length == "" {
|
|
||||||
return nil, NewError(
|
|
||||||
http.StatusUnsupportedMediaType,
|
|
||||||
fmt.Sprintf("415: Unsupported Media Type\n\nAvailable representations: %s", strings.Join(available, ", ")),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return nil, NewError(
|
return nil, NewError(
|
||||||
http.StatusNotAcceptable,
|
http.StatusNotAcceptable,
|
||||||
fmt.Sprintf("406: Not Acceptable\n\nAvailable representations: %s", strings.Join(available, ", ")),
|
fmt.Sprintf("406: Not Acceptable\n\nAvailable representations: %s", strings.Join(available, ", ")))
|
||||||
)
|
|
||||||
}
|
}
|
||||||
// return r.bestMatchByMedia(outputMediaOk, contentType, accept), nil
|
// return r.bestMatchByMedia(outputMediaOk, contentType, accept), nil
|
||||||
return candidates[0], nil
|
return candidates[0], nil
|
||||||
|
|||||||
2
vendor/github.com/emicklei/go-restful/v3/route.go
generated
vendored
2
vendor/github.com/emicklei/go-restful/v3/route.go
generated
vendored
@@ -111,6 +111,8 @@ func (r Route) matchesAccept(mimeTypesWithQuality string) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Return whether this Route can consume content with a type specified by mimeTypes (can be empty).
|
// Return whether this Route can consume content with a type specified by mimeTypes (can be empty).
|
||||||
|
// If the route does not specify Consumes then return true (*/*).
|
||||||
|
// If no content type is set then return true for GET,HEAD,OPTIONS,DELETE and TRACE.
|
||||||
func (r Route) matchesContentType(mimeTypes string) bool {
|
func (r Route) matchesContentType(mimeTypes string) bool {
|
||||||
|
|
||||||
if len(r.Consumes) == 0 {
|
if len(r.Consumes) == 0 {
|
||||||
|
|||||||
7
vendor/github.com/fsnotify/fsnotify/.cirrus.yml
generated
vendored
7
vendor/github.com/fsnotify/fsnotify/.cirrus.yml
generated
vendored
@@ -1,7 +1,7 @@
|
|||||||
freebsd_task:
|
freebsd_task:
|
||||||
name: 'FreeBSD'
|
name: 'FreeBSD'
|
||||||
freebsd_instance:
|
freebsd_instance:
|
||||||
image_family: freebsd-13-2
|
image_family: freebsd-14-2
|
||||||
install_script:
|
install_script:
|
||||||
- pkg update -f
|
- pkg update -f
|
||||||
- pkg install -y go
|
- pkg install -y go
|
||||||
@@ -9,5 +9,6 @@ freebsd_task:
|
|||||||
# run tests as user "cirrus" instead of root
|
# run tests as user "cirrus" instead of root
|
||||||
- pw useradd cirrus -m
|
- pw useradd cirrus -m
|
||||||
- chown -R cirrus:cirrus .
|
- chown -R cirrus:cirrus .
|
||||||
- FSNOTIFY_BUFFER=4096 sudo --preserve-env=FSNOTIFY_BUFFER -u cirrus go test -parallel 1 -race ./...
|
- FSNOTIFY_BUFFER=4096 sudo --preserve-env=FSNOTIFY_BUFFER -u cirrus go test -parallel 1 -race ./...
|
||||||
- sudo --preserve-env=FSNOTIFY_BUFFER -u cirrus go test -parallel 1 -race ./...
|
- sudo --preserve-env=FSNOTIFY_BUFFER -u cirrus go test -parallel 1 -race ./...
|
||||||
|
- FSNOTIFY_DEBUG=1 sudo --preserve-env=FSNOTIFY_BUFFER -u cirrus go test -parallel 1 -race -v ./...
|
||||||
|
|||||||
1
vendor/github.com/fsnotify/fsnotify/.gitattributes
generated
vendored
1
vendor/github.com/fsnotify/fsnotify/.gitattributes
generated
vendored
@@ -1 +0,0 @@
|
|||||||
go.sum linguist-generated
|
|
||||||
3
vendor/github.com/fsnotify/fsnotify/.gitignore
generated
vendored
3
vendor/github.com/fsnotify/fsnotify/.gitignore
generated
vendored
@@ -5,3 +5,6 @@
|
|||||||
# Output of go build ./cmd/fsnotify
|
# Output of go build ./cmd/fsnotify
|
||||||
/fsnotify
|
/fsnotify
|
||||||
/fsnotify.exe
|
/fsnotify.exe
|
||||||
|
|
||||||
|
/test/kqueue
|
||||||
|
/test/a.out
|
||||||
|
|||||||
67
vendor/github.com/fsnotify/fsnotify/CHANGELOG.md
generated
vendored
67
vendor/github.com/fsnotify/fsnotify/CHANGELOG.md
generated
vendored
@@ -1,8 +1,69 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
Unreleased
|
1.9.0 2024-04-04
|
||||||
----------
|
----------------
|
||||||
Nothing yet.
|
|
||||||
|
### Changes and fixes
|
||||||
|
|
||||||
|
- all: make BufferedWatcher buffered again ([#657])
|
||||||
|
|
||||||
|
- inotify: fix race when adding/removing watches while a watched path is being
|
||||||
|
deleted ([#678], [#686])
|
||||||
|
|
||||||
|
- inotify: don't send empty event if a watched path is unmounted ([#655])
|
||||||
|
|
||||||
|
- inotify: don't register duplicate watches when watching both a symlink and its
|
||||||
|
target; previously that would get "half-added" and removing the second would
|
||||||
|
panic ([#679])
|
||||||
|
|
||||||
|
- kqueue: fix watching relative symlinks ([#681])
|
||||||
|
|
||||||
|
- kqueue: correctly mark pre-existing entries when watching a link to a dir on
|
||||||
|
kqueue ([#682])
|
||||||
|
|
||||||
|
- illumos: don't send error if changed file is deleted while processing the
|
||||||
|
event ([#678])
|
||||||
|
|
||||||
|
|
||||||
|
[#657]: https://github.com/fsnotify/fsnotify/pull/657
|
||||||
|
[#678]: https://github.com/fsnotify/fsnotify/pull/678
|
||||||
|
[#686]: https://github.com/fsnotify/fsnotify/pull/686
|
||||||
|
[#655]: https://github.com/fsnotify/fsnotify/pull/655
|
||||||
|
[#681]: https://github.com/fsnotify/fsnotify/pull/681
|
||||||
|
[#679]: https://github.com/fsnotify/fsnotify/pull/679
|
||||||
|
[#682]: https://github.com/fsnotify/fsnotify/pull/682
|
||||||
|
|
||||||
|
1.8.0 2024-10-31
|
||||||
|
----------------
|
||||||
|
|
||||||
|
### Additions
|
||||||
|
|
||||||
|
- all: add `FSNOTIFY_DEBUG` to print debug logs to stderr ([#619])
|
||||||
|
|
||||||
|
### Changes and fixes
|
||||||
|
|
||||||
|
- windows: fix behaviour of `WatchList()` to be consistent with other platforms ([#610])
|
||||||
|
|
||||||
|
- kqueue: ignore events with Ident=0 ([#590])
|
||||||
|
|
||||||
|
- kqueue: set O_CLOEXEC to prevent passing file descriptors to children ([#617])
|
||||||
|
|
||||||
|
- kqueue: emit events as "/path/dir/file" instead of "path/link/file" when watching a symlink ([#625])
|
||||||
|
|
||||||
|
- inotify: don't send event for IN_DELETE_SELF when also watching the parent ([#620])
|
||||||
|
|
||||||
|
- inotify: fix panic when calling Remove() in a goroutine ([#650])
|
||||||
|
|
||||||
|
- fen: allow watching subdirectories of watched directories ([#621])
|
||||||
|
|
||||||
|
[#590]: https://github.com/fsnotify/fsnotify/pull/590
|
||||||
|
[#610]: https://github.com/fsnotify/fsnotify/pull/610
|
||||||
|
[#617]: https://github.com/fsnotify/fsnotify/pull/617
|
||||||
|
[#619]: https://github.com/fsnotify/fsnotify/pull/619
|
||||||
|
[#620]: https://github.com/fsnotify/fsnotify/pull/620
|
||||||
|
[#621]: https://github.com/fsnotify/fsnotify/pull/621
|
||||||
|
[#625]: https://github.com/fsnotify/fsnotify/pull/625
|
||||||
|
[#650]: https://github.com/fsnotify/fsnotify/pull/650
|
||||||
|
|
||||||
1.7.0 - 2023-10-22
|
1.7.0 - 2023-10-22
|
||||||
------------------
|
------------------
|
||||||
|
|||||||
121
vendor/github.com/fsnotify/fsnotify/CONTRIBUTING.md
generated
vendored
121
vendor/github.com/fsnotify/fsnotify/CONTRIBUTING.md
generated
vendored
@@ -1,7 +1,7 @@
|
|||||||
Thank you for your interest in contributing to fsnotify! We try to review and
|
Thank you for your interest in contributing to fsnotify! We try to review and
|
||||||
merge PRs in a reasonable timeframe, but please be aware that:
|
merge PRs in a reasonable timeframe, but please be aware that:
|
||||||
|
|
||||||
- To avoid "wasted" work, please discus changes on the issue tracker first. You
|
- To avoid "wasted" work, please discuss changes on the issue tracker first. You
|
||||||
can just send PRs, but they may end up being rejected for one reason or the
|
can just send PRs, but they may end up being rejected for one reason or the
|
||||||
other.
|
other.
|
||||||
|
|
||||||
@@ -20,6 +20,125 @@ platforms. Testing different platforms locally can be done with something like
|
|||||||
|
|
||||||
Use the `-short` flag to make the "stress test" run faster.
|
Use the `-short` flag to make the "stress test" run faster.
|
||||||
|
|
||||||
|
Writing new tests
|
||||||
|
-----------------
|
||||||
|
Scripts in the testdata directory allow creating test cases in a "shell-like"
|
||||||
|
syntax. The basic format is:
|
||||||
|
|
||||||
|
script
|
||||||
|
|
||||||
|
Output:
|
||||||
|
desired output
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
# Create a new empty file with some data.
|
||||||
|
watch /
|
||||||
|
echo data >/file
|
||||||
|
|
||||||
|
Output:
|
||||||
|
create /file
|
||||||
|
write /file
|
||||||
|
|
||||||
|
Just create a new file to add a new test; select which tests to run with
|
||||||
|
`-run TestScript/[path]`.
|
||||||
|
|
||||||
|
script
|
||||||
|
------
|
||||||
|
The script is a "shell-like" script:
|
||||||
|
|
||||||
|
cmd arg arg
|
||||||
|
|
||||||
|
Comments are supported with `#`:
|
||||||
|
|
||||||
|
# Comment
|
||||||
|
cmd arg arg # Comment
|
||||||
|
|
||||||
|
All operations are done in a temp directory; a path like "/foo" is rewritten to
|
||||||
|
"/tmp/TestFoo/foo".
|
||||||
|
|
||||||
|
Arguments can be quoted with `"` or `'`; there are no escapes and they're
|
||||||
|
functionally identical right now, but this may change in the future, so best to
|
||||||
|
assume shell-like rules.
|
||||||
|
|
||||||
|
touch "/file with spaces"
|
||||||
|
|
||||||
|
End-of-line escapes with `\` are not supported.
|
||||||
|
|
||||||
|
### Supported commands
|
||||||
|
|
||||||
|
watch path [ops] # Watch the path, reporting events for it. Nothing is
|
||||||
|
# watched by default. Optionally a list of ops can be
|
||||||
|
# given, as with AddWith(path, WithOps(...)).
|
||||||
|
unwatch path # Stop watching the path.
|
||||||
|
watchlist n # Assert watchlist length.
|
||||||
|
|
||||||
|
stop # Stop running the script; for debugging.
|
||||||
|
debug [yes/no] # Enable/disable FSNOTIFY_DEBUG (tests are run in
|
||||||
|
parallel by default, so -parallel=1 is probably a good
|
||||||
|
idea).
|
||||||
|
print [any strings] # Print text to stdout; for debugging.
|
||||||
|
|
||||||
|
touch path
|
||||||
|
mkdir [-p] dir
|
||||||
|
ln -s target link # Only ln -s supported.
|
||||||
|
mkfifo path
|
||||||
|
mknod dev path
|
||||||
|
mv src dst
|
||||||
|
rm [-r] path
|
||||||
|
chmod mode path # Octal only
|
||||||
|
sleep time-in-ms
|
||||||
|
|
||||||
|
cat path # Read path (does nothing with the data; just reads it).
|
||||||
|
echo str >>path # Append "str" to "path".
|
||||||
|
echo str >path # Truncate "path" and write "str".
|
||||||
|
|
||||||
|
require reason # Skip the test if "reason" is true; "skip" and
|
||||||
|
skip reason # "require" behave identical; it supports both for
|
||||||
|
# readability. Possible reasons are:
|
||||||
|
#
|
||||||
|
# always Always skip this test.
|
||||||
|
# symlink Symlinks are supported (requires admin
|
||||||
|
# permissions on Windows).
|
||||||
|
# mkfifo Platform doesn't support FIFO named sockets.
|
||||||
|
# mknod Platform doesn't support device nodes.
|
||||||
|
|
||||||
|
|
||||||
|
output
|
||||||
|
------
|
||||||
|
After `Output:` the desired output is given; this is indented by convention, but
|
||||||
|
that's not required.
|
||||||
|
|
||||||
|
The format of that is:
|
||||||
|
|
||||||
|
# Comment
|
||||||
|
event path # Comment
|
||||||
|
|
||||||
|
system:
|
||||||
|
event path
|
||||||
|
system2:
|
||||||
|
event path
|
||||||
|
|
||||||
|
Every event is one line, and any whitespace between the event and path are
|
||||||
|
ignored. The path can optionally be surrounded in ". Anything after a "#" is
|
||||||
|
ignored.
|
||||||
|
|
||||||
|
Platform-specific tests can be added after GOOS; for example:
|
||||||
|
|
||||||
|
watch /
|
||||||
|
touch /file
|
||||||
|
|
||||||
|
Output:
|
||||||
|
# Tested if nothing else matches
|
||||||
|
create /file
|
||||||
|
|
||||||
|
# Windows-specific test.
|
||||||
|
windows:
|
||||||
|
write /file
|
||||||
|
|
||||||
|
You can specify multiple platforms with a comma (e.g. "windows, linux:").
|
||||||
|
"kqueue" is a shortcut for all kqueue systems (BSD, macOS).
|
||||||
|
|
||||||
|
|
||||||
[goon]: https://github.com/arp242/goon
|
[goon]: https://github.com/arp242/goon
|
||||||
[Vagrant]: https://www.vagrantup.com/
|
[Vagrant]: https://www.vagrantup.com/
|
||||||
|
|||||||
2
vendor/github.com/fsnotify/fsnotify/README.md
generated
vendored
2
vendor/github.com/fsnotify/fsnotify/README.md
generated
vendored
@@ -15,7 +15,6 @@ Platform support:
|
|||||||
| ReadDirectoryChangesW | Windows | Supported |
|
| ReadDirectoryChangesW | Windows | Supported |
|
||||||
| FEN | illumos | Supported |
|
| FEN | illumos | Supported |
|
||||||
| fanotify | Linux 5.9+ | [Not yet](https://github.com/fsnotify/fsnotify/issues/114) |
|
| fanotify | Linux 5.9+ | [Not yet](https://github.com/fsnotify/fsnotify/issues/114) |
|
||||||
| AHAFS | AIX | [aix branch]; experimental due to lack of maintainer and test environment |
|
|
||||||
| FSEvents | macOS | [Needs support in x/sys/unix][fsevents] |
|
| FSEvents | macOS | [Needs support in x/sys/unix][fsevents] |
|
||||||
| USN Journals | Windows | [Needs support in x/sys/windows][usn] |
|
| USN Journals | Windows | [Needs support in x/sys/windows][usn] |
|
||||||
| Polling | *All* | [Not yet](https://github.com/fsnotify/fsnotify/issues/9) |
|
| Polling | *All* | [Not yet](https://github.com/fsnotify/fsnotify/issues/9) |
|
||||||
@@ -25,7 +24,6 @@ untested.
|
|||||||
|
|
||||||
[fsevents]: https://github.com/fsnotify/fsnotify/issues/11#issuecomment-1279133120
|
[fsevents]: https://github.com/fsnotify/fsnotify/issues/11#issuecomment-1279133120
|
||||||
[usn]: https://github.com/fsnotify/fsnotify/issues/53#issuecomment-1279829847
|
[usn]: https://github.com/fsnotify/fsnotify/issues/53#issuecomment-1279829847
|
||||||
[aix branch]: https://github.com/fsnotify/fsnotify/issues/353#issuecomment-1284590129
|
|
||||||
|
|
||||||
Usage
|
Usage
|
||||||
-----
|
-----
|
||||||
|
|||||||
401
vendor/github.com/fsnotify/fsnotify/backend_fen.go
generated
vendored
401
vendor/github.com/fsnotify/fsnotify/backend_fen.go
generated
vendored
@@ -1,162 +1,44 @@
|
|||||||
//go:build solaris
|
//go:build solaris
|
||||||
// +build solaris
|
|
||||||
|
|
||||||
// Note: the documentation on the Watcher type and methods is generated from
|
// FEN backend for illumos (supported) and Solaris (untested, but should work).
|
||||||
// mkdoc.zsh
|
//
|
||||||
|
// See port_create(3c) etc. for docs. https://www.illumos.org/man/3C/port_create
|
||||||
|
|
||||||
package fsnotify
|
package fsnotify
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sync"
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/fsnotify/fsnotify/internal"
|
||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Watcher watches a set of paths, delivering events on a channel.
|
type fen struct {
|
||||||
//
|
*shared
|
||||||
// A watcher should not be copied (e.g. pass it by pointer, rather than by
|
|
||||||
// value).
|
|
||||||
//
|
|
||||||
// # Linux notes
|
|
||||||
//
|
|
||||||
// When a file is removed a Remove event won't be emitted until all file
|
|
||||||
// descriptors are closed, and deletes will always emit a Chmod. For example:
|
|
||||||
//
|
|
||||||
// fp := os.Open("file")
|
|
||||||
// os.Remove("file") // Triggers Chmod
|
|
||||||
// fp.Close() // Triggers Remove
|
|
||||||
//
|
|
||||||
// This is the event that inotify sends, so not much can be changed about this.
|
|
||||||
//
|
|
||||||
// The fs.inotify.max_user_watches sysctl variable specifies the upper limit
|
|
||||||
// for the number of watches per user, and fs.inotify.max_user_instances
|
|
||||||
// specifies the maximum number of inotify instances per user. Every Watcher you
|
|
||||||
// create is an "instance", and every path you add is a "watch".
|
|
||||||
//
|
|
||||||
// These are also exposed in /proc as /proc/sys/fs/inotify/max_user_watches and
|
|
||||||
// /proc/sys/fs/inotify/max_user_instances
|
|
||||||
//
|
|
||||||
// To increase them you can use sysctl or write the value to the /proc file:
|
|
||||||
//
|
|
||||||
// # Default values on Linux 5.18
|
|
||||||
// sysctl fs.inotify.max_user_watches=124983
|
|
||||||
// sysctl fs.inotify.max_user_instances=128
|
|
||||||
//
|
|
||||||
// To make the changes persist on reboot edit /etc/sysctl.conf or
|
|
||||||
// /usr/lib/sysctl.d/50-default.conf (details differ per Linux distro; check
|
|
||||||
// your distro's documentation):
|
|
||||||
//
|
|
||||||
// fs.inotify.max_user_watches=124983
|
|
||||||
// fs.inotify.max_user_instances=128
|
|
||||||
//
|
|
||||||
// Reaching the limit will result in a "no space left on device" or "too many open
|
|
||||||
// files" error.
|
|
||||||
//
|
|
||||||
// # kqueue notes (macOS, BSD)
|
|
||||||
//
|
|
||||||
// kqueue requires opening a file descriptor for every file that's being watched;
|
|
||||||
// so if you're watching a directory with five files then that's six file
|
|
||||||
// descriptors. You will run in to your system's "max open files" limit faster on
|
|
||||||
// these platforms.
|
|
||||||
//
|
|
||||||
// The sysctl variables kern.maxfiles and kern.maxfilesperproc can be used to
|
|
||||||
// control the maximum number of open files, as well as /etc/login.conf on BSD
|
|
||||||
// systems.
|
|
||||||
//
|
|
||||||
// # Windows notes
|
|
||||||
//
|
|
||||||
// Paths can be added as "C:\path\to\dir", but forward slashes
|
|
||||||
// ("C:/path/to/dir") will also work.
|
|
||||||
//
|
|
||||||
// When a watched directory is removed it will always send an event for the
|
|
||||||
// directory itself, but may not send events for all files in that directory.
|
|
||||||
// Sometimes it will send events for all times, sometimes it will send no
|
|
||||||
// events, and often only for some files.
|
|
||||||
//
|
|
||||||
// The default ReadDirectoryChangesW() buffer size is 64K, which is the largest
|
|
||||||
// value that is guaranteed to work with SMB filesystems. If you have many
|
|
||||||
// events in quick succession this may not be enough, and you will have to use
|
|
||||||
// [WithBufferSize] to increase the value.
|
|
||||||
type Watcher struct {
|
|
||||||
// Events sends the filesystem change events.
|
|
||||||
//
|
|
||||||
// fsnotify can send the following events; a "path" here can refer to a
|
|
||||||
// file, directory, symbolic link, or special file like a FIFO.
|
|
||||||
//
|
|
||||||
// fsnotify.Create A new path was created; this may be followed by one
|
|
||||||
// or more Write events if data also gets written to a
|
|
||||||
// file.
|
|
||||||
//
|
|
||||||
// fsnotify.Remove A path was removed.
|
|
||||||
//
|
|
||||||
// fsnotify.Rename A path was renamed. A rename is always sent with the
|
|
||||||
// old path as Event.Name, and a Create event will be
|
|
||||||
// sent with the new name. Renames are only sent for
|
|
||||||
// paths that are currently watched; e.g. moving an
|
|
||||||
// unmonitored file into a monitored directory will
|
|
||||||
// show up as just a Create. Similarly, renaming a file
|
|
||||||
// to outside a monitored directory will show up as
|
|
||||||
// only a Rename.
|
|
||||||
//
|
|
||||||
// fsnotify.Write A file or named pipe was written to. A Truncate will
|
|
||||||
// also trigger a Write. A single "write action"
|
|
||||||
// initiated by the user may show up as one or multiple
|
|
||||||
// writes, depending on when the system syncs things to
|
|
||||||
// disk. For example when compiling a large Go program
|
|
||||||
// you may get hundreds of Write events, and you may
|
|
||||||
// want to wait until you've stopped receiving them
|
|
||||||
// (see the dedup example in cmd/fsnotify).
|
|
||||||
//
|
|
||||||
// Some systems may send Write event for directories
|
|
||||||
// when the directory content changes.
|
|
||||||
//
|
|
||||||
// fsnotify.Chmod Attributes were changed. On Linux this is also sent
|
|
||||||
// when a file is removed (or more accurately, when a
|
|
||||||
// link to an inode is removed). On kqueue it's sent
|
|
||||||
// when a file is truncated. On Windows it's never
|
|
||||||
// sent.
|
|
||||||
Events chan Event
|
Events chan Event
|
||||||
|
|
||||||
// Errors sends any errors.
|
|
||||||
//
|
|
||||||
// ErrEventOverflow is used to indicate there are too many events:
|
|
||||||
//
|
|
||||||
// - inotify: There are too many queued events (fs.inotify.max_queued_events sysctl)
|
|
||||||
// - windows: The buffer size is too small; WithBufferSize() can be used to increase it.
|
|
||||||
// - kqueue, fen: Not used.
|
|
||||||
Errors chan error
|
Errors chan error
|
||||||
|
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
port *unix.EventPort
|
port *unix.EventPort
|
||||||
done chan struct{} // Channel for sending a "quit message" to the reader goroutine
|
dirs map[string]Op // Explicitly watched directories
|
||||||
dirs map[string]struct{} // Explicitly watched directories
|
watches map[string]Op // Explicitly watched non-directories
|
||||||
watches map[string]struct{} // Explicitly watched non-directories
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewWatcher creates a new Watcher.
|
var defaultBufferSize = 0
|
||||||
func NewWatcher() (*Watcher, error) {
|
|
||||||
return NewBufferedWatcher(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewBufferedWatcher creates a new Watcher with a buffered Watcher.Events
|
func newBackend(ev chan Event, errs chan error) (backend, error) {
|
||||||
// channel.
|
w := &fen{
|
||||||
//
|
shared: newShared(ev, errs),
|
||||||
// The main use case for this is situations with a very large number of events
|
Events: ev,
|
||||||
// where the kernel buffer size can't be increased (e.g. due to lack of
|
Errors: errs,
|
||||||
// permissions). An unbuffered Watcher will perform better for almost all use
|
dirs: make(map[string]Op),
|
||||||
// cases, and whenever possible you will be better off increasing the kernel
|
watches: make(map[string]Op),
|
||||||
// buffers instead of adding a large userspace buffer.
|
|
||||||
func NewBufferedWatcher(sz uint) (*Watcher, error) {
|
|
||||||
w := &Watcher{
|
|
||||||
Events: make(chan Event, sz),
|
|
||||||
Errors: make(chan error),
|
|
||||||
dirs: make(map[string]struct{}),
|
|
||||||
watches: make(map[string]struct{}),
|
|
||||||
done: make(chan struct{}),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
@@ -169,104 +51,28 @@ func NewBufferedWatcher(sz uint) (*Watcher, error) {
|
|||||||
return w, nil
|
return w, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// sendEvent attempts to send an event to the user, returning true if the event
|
func (w *fen) Close() error {
|
||||||
// was put in the channel successfully and false if the watcher has been closed.
|
if w.shared.close() {
|
||||||
func (w *Watcher) sendEvent(name string, op Op) (sent bool) {
|
|
||||||
select {
|
|
||||||
case w.Events <- Event{Name: name, Op: op}:
|
|
||||||
return true
|
|
||||||
case <-w.done:
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// sendError attempts to send an error to the user, returning true if the error
|
|
||||||
// was put in the channel successfully and false if the watcher has been closed.
|
|
||||||
func (w *Watcher) sendError(err error) (sent bool) {
|
|
||||||
select {
|
|
||||||
case w.Errors <- err:
|
|
||||||
return true
|
|
||||||
case <-w.done:
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *Watcher) isClosed() bool {
|
|
||||||
select {
|
|
||||||
case <-w.done:
|
|
||||||
return true
|
|
||||||
default:
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close removes all watches and closes the Events channel.
|
|
||||||
func (w *Watcher) Close() error {
|
|
||||||
// Take the lock used by associateFile to prevent lingering events from
|
|
||||||
// being processed after the close
|
|
||||||
w.mu.Lock()
|
|
||||||
defer w.mu.Unlock()
|
|
||||||
if w.isClosed() {
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
close(w.done)
|
|
||||||
return w.port.Close()
|
return w.port.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add starts monitoring the path for changes.
|
func (w *fen) Add(name string) error { return w.AddWith(name) }
|
||||||
//
|
|
||||||
// A path can only be watched once; watching it more than once is a no-op and will
|
|
||||||
// not return an error. Paths that do not yet exist on the filesystem cannot be
|
|
||||||
// watched.
|
|
||||||
//
|
|
||||||
// A watch will be automatically removed if the watched path is deleted or
|
|
||||||
// renamed. The exception is the Windows backend, which doesn't remove the
|
|
||||||
// watcher on renames.
|
|
||||||
//
|
|
||||||
// Notifications on network filesystems (NFS, SMB, FUSE, etc.) or special
|
|
||||||
// filesystems (/proc, /sys, etc.) generally don't work.
|
|
||||||
//
|
|
||||||
// Returns [ErrClosed] if [Watcher.Close] was called.
|
|
||||||
//
|
|
||||||
// See [Watcher.AddWith] for a version that allows adding options.
|
|
||||||
//
|
|
||||||
// # Watching directories
|
|
||||||
//
|
|
||||||
// All files in a directory are monitored, including new files that are created
|
|
||||||
// after the watcher is started. Subdirectories are not watched (i.e. it's
|
|
||||||
// non-recursive).
|
|
||||||
//
|
|
||||||
// # Watching files
|
|
||||||
//
|
|
||||||
// Watching individual files (rather than directories) is generally not
|
|
||||||
// recommended as many programs (especially editors) update files atomically: it
|
|
||||||
// will write to a temporary file which is then moved to to destination,
|
|
||||||
// overwriting the original (or some variant thereof). The watcher on the
|
|
||||||
// original file is now lost, as that no longer exists.
|
|
||||||
//
|
|
||||||
// The upshot of this is that a power failure or crash won't leave a
|
|
||||||
// half-written file.
|
|
||||||
//
|
|
||||||
// Watch the parent directory and use Event.Name to filter out files you're not
|
|
||||||
// interested in. There is an example of this in cmd/fsnotify/file.go.
|
|
||||||
func (w *Watcher) Add(name string) error { return w.AddWith(name) }
|
|
||||||
|
|
||||||
// AddWith is like [Watcher.Add], but allows adding options. When using Add()
|
func (w *fen) AddWith(name string, opts ...addOpt) error {
|
||||||
// the defaults described below are used.
|
|
||||||
//
|
|
||||||
// Possible options are:
|
|
||||||
//
|
|
||||||
// - [WithBufferSize] sets the buffer size for the Windows backend; no-op on
|
|
||||||
// other platforms. The default is 64K (65536 bytes).
|
|
||||||
func (w *Watcher) AddWith(name string, opts ...addOpt) error {
|
|
||||||
if w.isClosed() {
|
if w.isClosed() {
|
||||||
return ErrClosed
|
return ErrClosed
|
||||||
}
|
}
|
||||||
if w.port.PathIsWatched(name) {
|
if debug {
|
||||||
return nil
|
fmt.Fprintf(os.Stderr, "FSNOTIFY_DEBUG: %s AddWith(%q)\n",
|
||||||
|
time.Now().Format("15:04:05.000000000"), name)
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = getOptions(opts...)
|
with := getOptions(opts...)
|
||||||
|
if !w.xSupports(with.op) {
|
||||||
|
return fmt.Errorf("%w: %s", xErrUnsupported, with.op)
|
||||||
|
}
|
||||||
|
|
||||||
// Currently we resolve symlinks that were explicitly requested to be
|
// Currently we resolve symlinks that were explicitly requested to be
|
||||||
// watched. Otherwise we would use LStat here.
|
// watched. Otherwise we would use LStat here.
|
||||||
@@ -283,7 +89,7 @@ func (w *Watcher) AddWith(name string, opts ...addOpt) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
w.mu.Lock()
|
w.mu.Lock()
|
||||||
w.dirs[name] = struct{}{}
|
w.dirs[name] = with.op
|
||||||
w.mu.Unlock()
|
w.mu.Unlock()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -294,26 +100,22 @@ func (w *Watcher) AddWith(name string, opts ...addOpt) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
w.mu.Lock()
|
w.mu.Lock()
|
||||||
w.watches[name] = struct{}{}
|
w.watches[name] = with.op
|
||||||
w.mu.Unlock()
|
w.mu.Unlock()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove stops monitoring the path for changes.
|
func (w *fen) Remove(name string) error {
|
||||||
//
|
|
||||||
// Directories are always removed non-recursively. For example, if you added
|
|
||||||
// /tmp/dir and /tmp/dir/subdir then you will need to remove both.
|
|
||||||
//
|
|
||||||
// Removing a path that has not yet been added returns [ErrNonExistentWatch].
|
|
||||||
//
|
|
||||||
// Returns nil if [Watcher.Close] was called.
|
|
||||||
func (w *Watcher) Remove(name string) error {
|
|
||||||
if w.isClosed() {
|
if w.isClosed() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if !w.port.PathIsWatched(name) {
|
if !w.port.PathIsWatched(name) {
|
||||||
return fmt.Errorf("%w: %s", ErrNonExistentWatch, name)
|
return fmt.Errorf("%w: %s", ErrNonExistentWatch, name)
|
||||||
}
|
}
|
||||||
|
if debug {
|
||||||
|
fmt.Fprintf(os.Stderr, "FSNOTIFY_DEBUG: %s Remove(%q)\n",
|
||||||
|
time.Now().Format("15:04:05.000000000"), name)
|
||||||
|
}
|
||||||
|
|
||||||
// The user has expressed an intent. Immediately remove this name from
|
// The user has expressed an intent. Immediately remove this name from
|
||||||
// whichever watch list it might be in. If it's not in there the delete
|
// whichever watch list it might be in. If it's not in there the delete
|
||||||
@@ -346,7 +148,7 @@ func (w *Watcher) Remove(name string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// readEvents contains the main loop that runs in a goroutine watching for events.
|
// readEvents contains the main loop that runs in a goroutine watching for events.
|
||||||
func (w *Watcher) readEvents() {
|
func (w *fen) readEvents() {
|
||||||
// If this function returns, the watcher has been closed and we can close
|
// If this function returns, the watcher has been closed and we can close
|
||||||
// these channels
|
// these channels
|
||||||
defer func() {
|
defer func() {
|
||||||
@@ -367,7 +169,7 @@ func (w *Watcher) readEvents() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
// There was an error not caused by calling w.Close()
|
// There was an error not caused by calling w.Close()
|
||||||
if !w.sendError(err) {
|
if !w.sendError(fmt.Errorf("port.Get: %w", err)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -382,17 +184,19 @@ func (w *Watcher) readEvents() {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if debug {
|
||||||
|
internal.Debug(pevent.Path, pevent.Events)
|
||||||
|
}
|
||||||
|
|
||||||
err = w.handleEvent(&pevent)
|
err = w.handleEvent(&pevent)
|
||||||
if err != nil {
|
if !w.sendError(err) {
|
||||||
if !w.sendError(err) {
|
return
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Watcher) handleDirectory(path string, stat os.FileInfo, follow bool, handler func(string, os.FileInfo, bool) error) error {
|
func (w *fen) handleDirectory(path string, stat os.FileInfo, follow bool, handler func(string, os.FileInfo, bool) error) error {
|
||||||
files, err := os.ReadDir(path)
|
files, err := os.ReadDir(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -418,7 +222,7 @@ func (w *Watcher) handleDirectory(path string, stat os.FileInfo, follow bool, ha
|
|||||||
// bitmap matches more than one event type (e.g. the file was both modified and
|
// bitmap matches more than one event type (e.g. the file was both modified and
|
||||||
// had the attributes changed between when the association was created and the
|
// had the attributes changed between when the association was created and the
|
||||||
// when event was returned)
|
// when event was returned)
|
||||||
func (w *Watcher) handleEvent(event *unix.PortEvent) error {
|
func (w *fen) handleEvent(event *unix.PortEvent) error {
|
||||||
var (
|
var (
|
||||||
events = event.Events
|
events = event.Events
|
||||||
path = event.Path
|
path = event.Path
|
||||||
@@ -433,13 +237,13 @@ func (w *Watcher) handleEvent(event *unix.PortEvent) error {
|
|||||||
isWatched := watchedDir || watchedPath
|
isWatched := watchedDir || watchedPath
|
||||||
|
|
||||||
if events&unix.FILE_DELETE != 0 {
|
if events&unix.FILE_DELETE != 0 {
|
||||||
if !w.sendEvent(path, Remove) {
|
if !w.sendEvent(Event{Name: path, Op: Remove}) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
reRegister = false
|
reRegister = false
|
||||||
}
|
}
|
||||||
if events&unix.FILE_RENAME_FROM != 0 {
|
if events&unix.FILE_RENAME_FROM != 0 {
|
||||||
if !w.sendEvent(path, Rename) {
|
if !w.sendEvent(Event{Name: path, Op: Rename}) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
// Don't keep watching the new file name
|
// Don't keep watching the new file name
|
||||||
@@ -453,7 +257,7 @@ func (w *Watcher) handleEvent(event *unix.PortEvent) error {
|
|||||||
|
|
||||||
// inotify reports a Remove event in this case, so we simulate this
|
// inotify reports a Remove event in this case, so we simulate this
|
||||||
// here.
|
// here.
|
||||||
if !w.sendEvent(path, Remove) {
|
if !w.sendEvent(Event{Name: path, Op: Remove}) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
// Don't keep watching the file that was removed
|
// Don't keep watching the file that was removed
|
||||||
@@ -487,7 +291,7 @@ func (w *Watcher) handleEvent(event *unix.PortEvent) error {
|
|||||||
// get here, the sudirectory is already gone. Clearly we were watching
|
// get here, the sudirectory is already gone. Clearly we were watching
|
||||||
// this path but now it is gone. Let's tell the user that it was
|
// this path but now it is gone. Let's tell the user that it was
|
||||||
// removed.
|
// removed.
|
||||||
if !w.sendEvent(path, Remove) {
|
if !w.sendEvent(Event{Name: path, Op: Remove}) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
// Suppress extra write events on removed directories; they are not
|
// Suppress extra write events on removed directories; they are not
|
||||||
@@ -502,7 +306,7 @@ func (w *Watcher) handleEvent(event *unix.PortEvent) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
// The symlink still exists, but the target is gone. Report the
|
// The symlink still exists, but the target is gone. Report the
|
||||||
// Remove similar to above.
|
// Remove similar to above.
|
||||||
if !w.sendEvent(path, Remove) {
|
if !w.sendEvent(Event{Name: path, Op: Remove}) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
// Don't return the error
|
// Don't return the error
|
||||||
@@ -510,18 +314,12 @@ func (w *Watcher) handleEvent(event *unix.PortEvent) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if events&unix.FILE_MODIFIED != 0 {
|
if events&unix.FILE_MODIFIED != 0 {
|
||||||
if fmode.IsDir() {
|
if fmode.IsDir() && watchedDir {
|
||||||
if watchedDir {
|
if err := w.updateDirectory(path); err != nil {
|
||||||
if err := w.updateDirectory(path); err != nil {
|
return err
|
||||||
return err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if !w.sendEvent(path, Write) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if !w.sendEvent(path, Write) {
|
if !w.sendEvent(Event{Name: path, Op: Write}) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -529,7 +327,7 @@ func (w *Watcher) handleEvent(event *unix.PortEvent) error {
|
|||||||
if events&unix.FILE_ATTRIB != 0 && stat != nil {
|
if events&unix.FILE_ATTRIB != 0 && stat != nil {
|
||||||
// Only send Chmod if perms changed
|
// Only send Chmod if perms changed
|
||||||
if stat.Mode().Perm() != fmode.Perm() {
|
if stat.Mode().Perm() != fmode.Perm() {
|
||||||
if !w.sendEvent(path, Chmod) {
|
if !w.sendEvent(Event{Name: path, Op: Chmod}) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -538,17 +336,27 @@ func (w *Watcher) handleEvent(event *unix.PortEvent) error {
|
|||||||
if stat != nil {
|
if stat != nil {
|
||||||
// If we get here, it means we've hit an event above that requires us to
|
// If we get here, it means we've hit an event above that requires us to
|
||||||
// continue watching the file or directory
|
// continue watching the file or directory
|
||||||
return w.associateFile(path, stat, isWatched)
|
err := w.associateFile(path, stat, isWatched)
|
||||||
|
if errors.Is(err, fs.ErrNotExist) {
|
||||||
|
// Path may have been removed since the stat.
|
||||||
|
err = nil
|
||||||
|
}
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Watcher) updateDirectory(path string) error {
|
// The directory was modified, so we must find unwatched entities and watch
|
||||||
// The directory was modified, so we must find unwatched entities and watch
|
// them. If something was removed from the directory, nothing will happen, as
|
||||||
// them. If something was removed from the directory, nothing will happen,
|
// everything else should still be watched.
|
||||||
// as everything else should still be watched.
|
func (w *fen) updateDirectory(path string) error {
|
||||||
files, err := os.ReadDir(path)
|
files, err := os.ReadDir(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
// Directory no longer exists: probably just deleted since we got the
|
||||||
|
// event.
|
||||||
|
if errors.Is(err, fs.ErrNotExist) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -563,19 +371,22 @@ func (w *Watcher) updateDirectory(path string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = w.associateFile(path, finfo, false)
|
err = w.associateFile(path, finfo, false)
|
||||||
if err != nil {
|
if errors.Is(err, fs.ErrNotExist) {
|
||||||
if !w.sendError(err) {
|
// File may have disappeared between getting the dir listing and
|
||||||
return nil
|
// adding the port: that's okay to ignore.
|
||||||
}
|
continue
|
||||||
}
|
}
|
||||||
if !w.sendEvent(path, Create) {
|
if !w.sendError(err) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if !w.sendEvent(Event{Name: path, Op: Create}) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Watcher) associateFile(path string, stat os.FileInfo, follow bool) error {
|
func (w *fen) associateFile(path string, stat os.FileInfo, follow bool) error {
|
||||||
if w.isClosed() {
|
if w.isClosed() {
|
||||||
return ErrClosed
|
return ErrClosed
|
||||||
}
|
}
|
||||||
@@ -593,34 +404,42 @@ func (w *Watcher) associateFile(path string, stat os.FileInfo, follow bool) erro
|
|||||||
// cleared up that discrepancy. The most likely cause is that the event
|
// cleared up that discrepancy. The most likely cause is that the event
|
||||||
// has fired but we haven't processed it yet.
|
// has fired but we haven't processed it yet.
|
||||||
err := w.port.DissociatePath(path)
|
err := w.port.DissociatePath(path)
|
||||||
if err != nil && err != unix.ENOENT {
|
if err != nil && !errors.Is(err, unix.ENOENT) {
|
||||||
return err
|
return fmt.Errorf("port.DissociatePath(%q): %w", path, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// FILE_NOFOLLOW means we watch symlinks themselves rather than their
|
|
||||||
// targets.
|
var events int
|
||||||
events := unix.FILE_MODIFIED | unix.FILE_ATTRIB | unix.FILE_NOFOLLOW
|
if !follow {
|
||||||
if follow {
|
// Watch symlinks themselves rather than their targets unless this entry
|
||||||
// We *DO* follow symlinks for explicitly watched entries.
|
// is explicitly watched.
|
||||||
events = unix.FILE_MODIFIED | unix.FILE_ATTRIB
|
events |= unix.FILE_NOFOLLOW
|
||||||
}
|
}
|
||||||
return w.port.AssociatePath(path, stat,
|
if true { // TODO: implement withOps()
|
||||||
events,
|
events |= unix.FILE_MODIFIED
|
||||||
stat.Mode())
|
}
|
||||||
|
if true {
|
||||||
|
events |= unix.FILE_ATTRIB
|
||||||
|
}
|
||||||
|
err := w.port.AssociatePath(path, stat, events, stat.Mode())
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("port.AssociatePath(%q): %w", path, err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Watcher) dissociateFile(path string, stat os.FileInfo, unused bool) error {
|
func (w *fen) dissociateFile(path string, stat os.FileInfo, unused bool) error {
|
||||||
if !w.port.PathIsWatched(path) {
|
if !w.port.PathIsWatched(path) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return w.port.DissociatePath(path)
|
err := w.port.DissociatePath(path)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("port.DissociatePath(%q): %w", path, err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// WatchList returns all paths explicitly added with [Watcher.Add] (and are not
|
func (w *fen) WatchList() []string {
|
||||||
// yet removed).
|
|
||||||
//
|
|
||||||
// Returns nil if [Watcher.Close] was called.
|
|
||||||
func (w *Watcher) WatchList() []string {
|
|
||||||
if w.isClosed() {
|
if w.isClosed() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -638,3 +457,11 @@ func (w *Watcher) WatchList() []string {
|
|||||||
|
|
||||||
return entries
|
return entries
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w *fen) xSupports(op Op) bool {
|
||||||
|
if op.Has(xUnportableOpen) || op.Has(xUnportableRead) ||
|
||||||
|
op.Has(xUnportableCloseWrite) || op.Has(xUnportableCloseRead) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|||||||
735
vendor/github.com/fsnotify/fsnotify/backend_inotify.go
generated
vendored
735
vendor/github.com/fsnotify/fsnotify/backend_inotify.go
generated
vendored
@@ -1,8 +1,4 @@
|
|||||||
//go:build linux && !appengine
|
//go:build linux && !appengine
|
||||||
// +build linux,!appengine
|
|
||||||
|
|
||||||
// Note: the documentation on the Watcher type and methods is generated from
|
|
||||||
// mkdoc.zsh
|
|
||||||
|
|
||||||
package fsnotify
|
package fsnotify
|
||||||
|
|
||||||
@@ -10,127 +6,21 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
"time"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/fsnotify/fsnotify/internal"
|
||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Watcher watches a set of paths, delivering events on a channel.
|
type inotify struct {
|
||||||
//
|
*shared
|
||||||
// A watcher should not be copied (e.g. pass it by pointer, rather than by
|
|
||||||
// value).
|
|
||||||
//
|
|
||||||
// # Linux notes
|
|
||||||
//
|
|
||||||
// When a file is removed a Remove event won't be emitted until all file
|
|
||||||
// descriptors are closed, and deletes will always emit a Chmod. For example:
|
|
||||||
//
|
|
||||||
// fp := os.Open("file")
|
|
||||||
// os.Remove("file") // Triggers Chmod
|
|
||||||
// fp.Close() // Triggers Remove
|
|
||||||
//
|
|
||||||
// This is the event that inotify sends, so not much can be changed about this.
|
|
||||||
//
|
|
||||||
// The fs.inotify.max_user_watches sysctl variable specifies the upper limit
|
|
||||||
// for the number of watches per user, and fs.inotify.max_user_instances
|
|
||||||
// specifies the maximum number of inotify instances per user. Every Watcher you
|
|
||||||
// create is an "instance", and every path you add is a "watch".
|
|
||||||
//
|
|
||||||
// These are also exposed in /proc as /proc/sys/fs/inotify/max_user_watches and
|
|
||||||
// /proc/sys/fs/inotify/max_user_instances
|
|
||||||
//
|
|
||||||
// To increase them you can use sysctl or write the value to the /proc file:
|
|
||||||
//
|
|
||||||
// # Default values on Linux 5.18
|
|
||||||
// sysctl fs.inotify.max_user_watches=124983
|
|
||||||
// sysctl fs.inotify.max_user_instances=128
|
|
||||||
//
|
|
||||||
// To make the changes persist on reboot edit /etc/sysctl.conf or
|
|
||||||
// /usr/lib/sysctl.d/50-default.conf (details differ per Linux distro; check
|
|
||||||
// your distro's documentation):
|
|
||||||
//
|
|
||||||
// fs.inotify.max_user_watches=124983
|
|
||||||
// fs.inotify.max_user_instances=128
|
|
||||||
//
|
|
||||||
// Reaching the limit will result in a "no space left on device" or "too many open
|
|
||||||
// files" error.
|
|
||||||
//
|
|
||||||
// # kqueue notes (macOS, BSD)
|
|
||||||
//
|
|
||||||
// kqueue requires opening a file descriptor for every file that's being watched;
|
|
||||||
// so if you're watching a directory with five files then that's six file
|
|
||||||
// descriptors. You will run in to your system's "max open files" limit faster on
|
|
||||||
// these platforms.
|
|
||||||
//
|
|
||||||
// The sysctl variables kern.maxfiles and kern.maxfilesperproc can be used to
|
|
||||||
// control the maximum number of open files, as well as /etc/login.conf on BSD
|
|
||||||
// systems.
|
|
||||||
//
|
|
||||||
// # Windows notes
|
|
||||||
//
|
|
||||||
// Paths can be added as "C:\path\to\dir", but forward slashes
|
|
||||||
// ("C:/path/to/dir") will also work.
|
|
||||||
//
|
|
||||||
// When a watched directory is removed it will always send an event for the
|
|
||||||
// directory itself, but may not send events for all files in that directory.
|
|
||||||
// Sometimes it will send events for all times, sometimes it will send no
|
|
||||||
// events, and often only for some files.
|
|
||||||
//
|
|
||||||
// The default ReadDirectoryChangesW() buffer size is 64K, which is the largest
|
|
||||||
// value that is guaranteed to work with SMB filesystems. If you have many
|
|
||||||
// events in quick succession this may not be enough, and you will have to use
|
|
||||||
// [WithBufferSize] to increase the value.
|
|
||||||
type Watcher struct {
|
|
||||||
// Events sends the filesystem change events.
|
|
||||||
//
|
|
||||||
// fsnotify can send the following events; a "path" here can refer to a
|
|
||||||
// file, directory, symbolic link, or special file like a FIFO.
|
|
||||||
//
|
|
||||||
// fsnotify.Create A new path was created; this may be followed by one
|
|
||||||
// or more Write events if data also gets written to a
|
|
||||||
// file.
|
|
||||||
//
|
|
||||||
// fsnotify.Remove A path was removed.
|
|
||||||
//
|
|
||||||
// fsnotify.Rename A path was renamed. A rename is always sent with the
|
|
||||||
// old path as Event.Name, and a Create event will be
|
|
||||||
// sent with the new name. Renames are only sent for
|
|
||||||
// paths that are currently watched; e.g. moving an
|
|
||||||
// unmonitored file into a monitored directory will
|
|
||||||
// show up as just a Create. Similarly, renaming a file
|
|
||||||
// to outside a monitored directory will show up as
|
|
||||||
// only a Rename.
|
|
||||||
//
|
|
||||||
// fsnotify.Write A file or named pipe was written to. A Truncate will
|
|
||||||
// also trigger a Write. A single "write action"
|
|
||||||
// initiated by the user may show up as one or multiple
|
|
||||||
// writes, depending on when the system syncs things to
|
|
||||||
// disk. For example when compiling a large Go program
|
|
||||||
// you may get hundreds of Write events, and you may
|
|
||||||
// want to wait until you've stopped receiving them
|
|
||||||
// (see the dedup example in cmd/fsnotify).
|
|
||||||
//
|
|
||||||
// Some systems may send Write event for directories
|
|
||||||
// when the directory content changes.
|
|
||||||
//
|
|
||||||
// fsnotify.Chmod Attributes were changed. On Linux this is also sent
|
|
||||||
// when a file is removed (or more accurately, when a
|
|
||||||
// link to an inode is removed). On kqueue it's sent
|
|
||||||
// when a file is truncated. On Windows it's never
|
|
||||||
// sent.
|
|
||||||
Events chan Event
|
Events chan Event
|
||||||
|
|
||||||
// Errors sends any errors.
|
|
||||||
//
|
|
||||||
// ErrEventOverflow is used to indicate there are too many events:
|
|
||||||
//
|
|
||||||
// - inotify: There are too many queued events (fs.inotify.max_queued_events sysctl)
|
|
||||||
// - windows: The buffer size is too small; WithBufferSize() can be used to increase it.
|
|
||||||
// - kqueue, fen: Not used.
|
|
||||||
Errors chan error
|
Errors chan error
|
||||||
|
|
||||||
// Store fd here as os.File.Read() will no longer return on close after
|
// Store fd here as os.File.Read() will no longer return on close after
|
||||||
@@ -138,21 +28,41 @@ type Watcher struct {
|
|||||||
fd int
|
fd int
|
||||||
inotifyFile *os.File
|
inotifyFile *os.File
|
||||||
watches *watches
|
watches *watches
|
||||||
done chan struct{} // Channel for sending a "quit message" to the reader goroutine
|
|
||||||
closeMu sync.Mutex
|
|
||||||
doneResp chan struct{} // Channel to respond to Close
|
doneResp chan struct{} // Channel to respond to Close
|
||||||
|
|
||||||
|
// Store rename cookies in an array, with the index wrapping to 0. Almost
|
||||||
|
// all of the time what we get is a MOVED_FROM to set the cookie and the
|
||||||
|
// next event inotify sends will be MOVED_TO to read it. However, this is
|
||||||
|
// not guaranteed – as described in inotify(7) – and we may get other events
|
||||||
|
// between the two MOVED_* events (including other MOVED_* ones).
|
||||||
|
//
|
||||||
|
// A second issue is that moving a file outside the watched directory will
|
||||||
|
// trigger a MOVED_FROM to set the cookie, but we never see the MOVED_TO to
|
||||||
|
// read and delete it. So just storing it in a map would slowly leak memory.
|
||||||
|
//
|
||||||
|
// Doing it like this gives us a simple fast LRU-cache that won't allocate.
|
||||||
|
// Ten items should be more than enough for our purpose, and a loop over
|
||||||
|
// such a short array is faster than a map access anyway (not that it hugely
|
||||||
|
// matters since we're talking about hundreds of ns at the most, but still).
|
||||||
|
cookies [10]koekje
|
||||||
|
cookieIndex uint8
|
||||||
|
cookiesMu sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
type (
|
type (
|
||||||
watches struct {
|
watches struct {
|
||||||
mu sync.RWMutex
|
|
||||||
wd map[uint32]*watch // wd → watch
|
wd map[uint32]*watch // wd → watch
|
||||||
path map[string]uint32 // pathname → wd
|
path map[string]uint32 // pathname → wd
|
||||||
}
|
}
|
||||||
watch struct {
|
watch struct {
|
||||||
wd uint32 // Watch descriptor (as returned by the inotify_add_watch() syscall)
|
wd uint32 // Watch descriptor (as returned by the inotify_add_watch() syscall)
|
||||||
flags uint32 // inotify flags of this watch (see inotify(7) for the list of valid flags)
|
flags uint32 // inotify flags of this watch (see inotify(7) for the list of valid flags)
|
||||||
path string // Watch path.
|
path string // Watch path.
|
||||||
|
recurse bool // Recursion with ./...?
|
||||||
|
}
|
||||||
|
koekje struct {
|
||||||
|
cookie uint32
|
||||||
|
path string
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -163,57 +73,43 @@ func newWatches() *watches {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *watches) len() int {
|
func (w *watches) byPath(path string) *watch { return w.wd[w.path[path]] }
|
||||||
w.mu.RLock()
|
func (w *watches) byWd(wd uint32) *watch { return w.wd[wd] }
|
||||||
defer w.mu.RUnlock()
|
func (w *watches) len() int { return len(w.wd) }
|
||||||
return len(w.wd)
|
func (w *watches) add(ww *watch) { w.wd[ww.wd] = ww; w.path[ww.path] = ww.wd }
|
||||||
}
|
func (w *watches) remove(watch *watch) { delete(w.path, watch.path); delete(w.wd, watch.wd) }
|
||||||
|
|
||||||
func (w *watches) add(ww *watch) {
|
|
||||||
w.mu.Lock()
|
|
||||||
defer w.mu.Unlock()
|
|
||||||
w.wd[ww.wd] = ww
|
|
||||||
w.path[ww.path] = ww.wd
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *watches) remove(wd uint32) {
|
|
||||||
w.mu.Lock()
|
|
||||||
defer w.mu.Unlock()
|
|
||||||
delete(w.path, w.wd[wd].path)
|
|
||||||
delete(w.wd, wd)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *watches) removePath(path string) (uint32, bool) {
|
|
||||||
w.mu.Lock()
|
|
||||||
defer w.mu.Unlock()
|
|
||||||
|
|
||||||
|
func (w *watches) removePath(path string) ([]uint32, error) {
|
||||||
|
path, recurse := recursivePath(path)
|
||||||
wd, ok := w.path[path]
|
wd, ok := w.path[path]
|
||||||
if !ok {
|
if !ok {
|
||||||
return 0, false
|
return nil, fmt.Errorf("%w: %s", ErrNonExistentWatch, path)
|
||||||
|
}
|
||||||
|
|
||||||
|
watch := w.wd[wd]
|
||||||
|
if recurse && !watch.recurse {
|
||||||
|
return nil, fmt.Errorf("can't use /... with non-recursive watch %q", path)
|
||||||
}
|
}
|
||||||
|
|
||||||
delete(w.path, path)
|
delete(w.path, path)
|
||||||
delete(w.wd, wd)
|
delete(w.wd, wd)
|
||||||
|
if !watch.recurse {
|
||||||
|
return []uint32{wd}, nil
|
||||||
|
}
|
||||||
|
|
||||||
return wd, true
|
wds := make([]uint32, 0, 8)
|
||||||
}
|
wds = append(wds, wd)
|
||||||
|
for p, rwd := range w.path {
|
||||||
func (w *watches) byPath(path string) *watch {
|
if strings.HasPrefix(p, path) {
|
||||||
w.mu.RLock()
|
delete(w.path, p)
|
||||||
defer w.mu.RUnlock()
|
delete(w.wd, rwd)
|
||||||
return w.wd[w.path[path]]
|
wds = append(wds, rwd)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
func (w *watches) byWd(wd uint32) *watch {
|
return wds, nil
|
||||||
w.mu.RLock()
|
|
||||||
defer w.mu.RUnlock()
|
|
||||||
return w.wd[wd]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *watches) updatePath(path string, f func(*watch) (*watch, error)) error {
|
func (w *watches) updatePath(path string, f func(*watch) (*watch, error)) error {
|
||||||
w.mu.Lock()
|
|
||||||
defer w.mu.Unlock()
|
|
||||||
|
|
||||||
var existing *watch
|
var existing *watch
|
||||||
wd, ok := w.path[path]
|
wd, ok := w.path[path]
|
||||||
if ok {
|
if ok {
|
||||||
@@ -236,20 +132,9 @@ func (w *watches) updatePath(path string, f func(*watch) (*watch, error)) error
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewWatcher creates a new Watcher.
|
var defaultBufferSize = 0
|
||||||
func NewWatcher() (*Watcher, error) {
|
|
||||||
return NewBufferedWatcher(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewBufferedWatcher creates a new Watcher with a buffered Watcher.Events
|
func newBackend(ev chan Event, errs chan error) (backend, error) {
|
||||||
// channel.
|
|
||||||
//
|
|
||||||
// The main use case for this is situations with a very large number of events
|
|
||||||
// where the kernel buffer size can't be increased (e.g. due to lack of
|
|
||||||
// permissions). An unbuffered Watcher will perform better for almost all use
|
|
||||||
// cases, and whenever possible you will be better off increasing the kernel
|
|
||||||
// buffers instead of adding a large userspace buffer.
|
|
||||||
func NewBufferedWatcher(sz uint) (*Watcher, error) {
|
|
||||||
// Need to set nonblocking mode for SetDeadline to work, otherwise blocking
|
// Need to set nonblocking mode for SetDeadline to work, otherwise blocking
|
||||||
// I/O operations won't terminate on close.
|
// I/O operations won't terminate on close.
|
||||||
fd, errno := unix.InotifyInit1(unix.IN_CLOEXEC | unix.IN_NONBLOCK)
|
fd, errno := unix.InotifyInit1(unix.IN_CLOEXEC | unix.IN_NONBLOCK)
|
||||||
@@ -257,13 +142,13 @@ func NewBufferedWatcher(sz uint) (*Watcher, error) {
|
|||||||
return nil, errno
|
return nil, errno
|
||||||
}
|
}
|
||||||
|
|
||||||
w := &Watcher{
|
w := &inotify{
|
||||||
|
shared: newShared(ev, errs),
|
||||||
|
Events: ev,
|
||||||
|
Errors: errs,
|
||||||
fd: fd,
|
fd: fd,
|
||||||
inotifyFile: os.NewFile(uintptr(fd), ""),
|
inotifyFile: os.NewFile(uintptr(fd), ""),
|
||||||
watches: newWatches(),
|
watches: newWatches(),
|
||||||
Events: make(chan Event, sz),
|
|
||||||
Errors: make(chan error),
|
|
||||||
done: make(chan struct{}),
|
|
||||||
doneResp: make(chan struct{}),
|
doneResp: make(chan struct{}),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -271,44 +156,10 @@ func NewBufferedWatcher(sz uint) (*Watcher, error) {
|
|||||||
return w, nil
|
return w, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true if the event was sent, or false if watcher is closed.
|
func (w *inotify) Close() error {
|
||||||
func (w *Watcher) sendEvent(e Event) bool {
|
if w.shared.close() {
|
||||||
select {
|
|
||||||
case w.Events <- e:
|
|
||||||
return true
|
|
||||||
case <-w.done:
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns true if the error was sent, or false if watcher is closed.
|
|
||||||
func (w *Watcher) sendError(err error) bool {
|
|
||||||
select {
|
|
||||||
case w.Errors <- err:
|
|
||||||
return true
|
|
||||||
case <-w.done:
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *Watcher) isClosed() bool {
|
|
||||||
select {
|
|
||||||
case <-w.done:
|
|
||||||
return true
|
|
||||||
default:
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close removes all watches and closes the Events channel.
|
|
||||||
func (w *Watcher) Close() error {
|
|
||||||
w.closeMu.Lock()
|
|
||||||
if w.isClosed() {
|
|
||||||
w.closeMu.Unlock()
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
close(w.done)
|
|
||||||
w.closeMu.Unlock()
|
|
||||||
|
|
||||||
// Causes any blocking reads to return with an error, provided the file
|
// Causes any blocking reads to return with an error, provided the file
|
||||||
// still supports deadline operations.
|
// still supports deadline operations.
|
||||||
@@ -317,84 +168,114 @@ func (w *Watcher) Close() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait for goroutine to close
|
<-w.doneResp // Wait for readEvents() to finish.
|
||||||
<-w.doneResp
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add starts monitoring the path for changes.
|
func (w *inotify) Add(name string) error { return w.AddWith(name) }
|
||||||
//
|
|
||||||
// A path can only be watched once; watching it more than once is a no-op and will
|
|
||||||
// not return an error. Paths that do not yet exist on the filesystem cannot be
|
|
||||||
// watched.
|
|
||||||
//
|
|
||||||
// A watch will be automatically removed if the watched path is deleted or
|
|
||||||
// renamed. The exception is the Windows backend, which doesn't remove the
|
|
||||||
// watcher on renames.
|
|
||||||
//
|
|
||||||
// Notifications on network filesystems (NFS, SMB, FUSE, etc.) or special
|
|
||||||
// filesystems (/proc, /sys, etc.) generally don't work.
|
|
||||||
//
|
|
||||||
// Returns [ErrClosed] if [Watcher.Close] was called.
|
|
||||||
//
|
|
||||||
// See [Watcher.AddWith] for a version that allows adding options.
|
|
||||||
//
|
|
||||||
// # Watching directories
|
|
||||||
//
|
|
||||||
// All files in a directory are monitored, including new files that are created
|
|
||||||
// after the watcher is started. Subdirectories are not watched (i.e. it's
|
|
||||||
// non-recursive).
|
|
||||||
//
|
|
||||||
// # Watching files
|
|
||||||
//
|
|
||||||
// Watching individual files (rather than directories) is generally not
|
|
||||||
// recommended as many programs (especially editors) update files atomically: it
|
|
||||||
// will write to a temporary file which is then moved to to destination,
|
|
||||||
// overwriting the original (or some variant thereof). The watcher on the
|
|
||||||
// original file is now lost, as that no longer exists.
|
|
||||||
//
|
|
||||||
// The upshot of this is that a power failure or crash won't leave a
|
|
||||||
// half-written file.
|
|
||||||
//
|
|
||||||
// Watch the parent directory and use Event.Name to filter out files you're not
|
|
||||||
// interested in. There is an example of this in cmd/fsnotify/file.go.
|
|
||||||
func (w *Watcher) Add(name string) error { return w.AddWith(name) }
|
|
||||||
|
|
||||||
// AddWith is like [Watcher.Add], but allows adding options. When using Add()
|
func (w *inotify) AddWith(path string, opts ...addOpt) error {
|
||||||
// the defaults described below are used.
|
|
||||||
//
|
|
||||||
// Possible options are:
|
|
||||||
//
|
|
||||||
// - [WithBufferSize] sets the buffer size for the Windows backend; no-op on
|
|
||||||
// other platforms. The default is 64K (65536 bytes).
|
|
||||||
func (w *Watcher) AddWith(name string, opts ...addOpt) error {
|
|
||||||
if w.isClosed() {
|
if w.isClosed() {
|
||||||
return ErrClosed
|
return ErrClosed
|
||||||
}
|
}
|
||||||
|
if debug {
|
||||||
|
fmt.Fprintf(os.Stderr, "FSNOTIFY_DEBUG: %s AddWith(%q)\n",
|
||||||
|
time.Now().Format("15:04:05.000000000"), path)
|
||||||
|
}
|
||||||
|
|
||||||
name = filepath.Clean(name)
|
with := getOptions(opts...)
|
||||||
_ = getOptions(opts...)
|
if !w.xSupports(with.op) {
|
||||||
|
return fmt.Errorf("%w: %s", xErrUnsupported, with.op)
|
||||||
|
}
|
||||||
|
|
||||||
var flags uint32 = unix.IN_MOVED_TO | unix.IN_MOVED_FROM |
|
add := func(path string, with withOpts, recurse bool) error {
|
||||||
unix.IN_CREATE | unix.IN_ATTRIB | unix.IN_MODIFY |
|
var flags uint32
|
||||||
unix.IN_MOVE_SELF | unix.IN_DELETE | unix.IN_DELETE_SELF
|
if with.noFollow {
|
||||||
|
flags |= unix.IN_DONT_FOLLOW
|
||||||
|
}
|
||||||
|
if with.op.Has(Create) {
|
||||||
|
flags |= unix.IN_CREATE
|
||||||
|
}
|
||||||
|
if with.op.Has(Write) {
|
||||||
|
flags |= unix.IN_MODIFY
|
||||||
|
}
|
||||||
|
if with.op.Has(Remove) {
|
||||||
|
flags |= unix.IN_DELETE | unix.IN_DELETE_SELF
|
||||||
|
}
|
||||||
|
if with.op.Has(Rename) {
|
||||||
|
flags |= unix.IN_MOVED_TO | unix.IN_MOVED_FROM | unix.IN_MOVE_SELF
|
||||||
|
}
|
||||||
|
if with.op.Has(Chmod) {
|
||||||
|
flags |= unix.IN_ATTRIB
|
||||||
|
}
|
||||||
|
if with.op.Has(xUnportableOpen) {
|
||||||
|
flags |= unix.IN_OPEN
|
||||||
|
}
|
||||||
|
if with.op.Has(xUnportableRead) {
|
||||||
|
flags |= unix.IN_ACCESS
|
||||||
|
}
|
||||||
|
if with.op.Has(xUnportableCloseWrite) {
|
||||||
|
flags |= unix.IN_CLOSE_WRITE
|
||||||
|
}
|
||||||
|
if with.op.Has(xUnportableCloseRead) {
|
||||||
|
flags |= unix.IN_CLOSE_NOWRITE
|
||||||
|
}
|
||||||
|
return w.register(path, flags, recurse)
|
||||||
|
}
|
||||||
|
|
||||||
return w.watches.updatePath(name, func(existing *watch) (*watch, error) {
|
w.mu.Lock()
|
||||||
|
defer w.mu.Unlock()
|
||||||
|
path, recurse := recursivePath(path)
|
||||||
|
if recurse {
|
||||||
|
return filepath.WalkDir(path, func(root string, d fs.DirEntry, err error) error {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !d.IsDir() {
|
||||||
|
if root == path {
|
||||||
|
return fmt.Errorf("fsnotify: not a directory: %q", path)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send a Create event when adding new directory from a recursive
|
||||||
|
// watch; this is for "mkdir -p one/two/three". Usually all those
|
||||||
|
// directories will be created before we can set up watchers on the
|
||||||
|
// subdirectories, so only "one" would be sent as a Create event and
|
||||||
|
// not "one/two" and "one/two/three" (inotifywait -r has the same
|
||||||
|
// problem).
|
||||||
|
if with.sendCreate && root != path {
|
||||||
|
w.sendEvent(Event{Name: root, Op: Create})
|
||||||
|
}
|
||||||
|
|
||||||
|
return add(root, with, true)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return add(path, with, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *inotify) register(path string, flags uint32, recurse bool) error {
|
||||||
|
return w.watches.updatePath(path, func(existing *watch) (*watch, error) {
|
||||||
if existing != nil {
|
if existing != nil {
|
||||||
flags |= existing.flags | unix.IN_MASK_ADD
|
flags |= existing.flags | unix.IN_MASK_ADD
|
||||||
}
|
}
|
||||||
|
|
||||||
wd, err := unix.InotifyAddWatch(w.fd, name, flags)
|
wd, err := unix.InotifyAddWatch(w.fd, path, flags)
|
||||||
if wd == -1 {
|
if wd == -1 {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if e, ok := w.watches.wd[uint32(wd)]; ok {
|
||||||
|
return e, nil
|
||||||
|
}
|
||||||
|
|
||||||
if existing == nil {
|
if existing == nil {
|
||||||
return &watch{
|
return &watch{
|
||||||
wd: uint32(wd),
|
wd: uint32(wd),
|
||||||
path: name,
|
path: path,
|
||||||
flags: flags,
|
flags: flags,
|
||||||
|
recurse: recurse,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -404,87 +285,80 @@ func (w *Watcher) AddWith(name string, opts ...addOpt) error {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove stops monitoring the path for changes.
|
func (w *inotify) Remove(name string) error {
|
||||||
//
|
|
||||||
// Directories are always removed non-recursively. For example, if you added
|
|
||||||
// /tmp/dir and /tmp/dir/subdir then you will need to remove both.
|
|
||||||
//
|
|
||||||
// Removing a path that has not yet been added returns [ErrNonExistentWatch].
|
|
||||||
//
|
|
||||||
// Returns nil if [Watcher.Close] was called.
|
|
||||||
func (w *Watcher) Remove(name string) error {
|
|
||||||
if w.isClosed() {
|
if w.isClosed() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
if debug {
|
||||||
|
fmt.Fprintf(os.Stderr, "FSNOTIFY_DEBUG: %s Remove(%q)\n",
|
||||||
|
time.Now().Format("15:04:05.000000000"), name)
|
||||||
|
}
|
||||||
|
|
||||||
|
w.mu.Lock()
|
||||||
|
defer w.mu.Unlock()
|
||||||
return w.remove(filepath.Clean(name))
|
return w.remove(filepath.Clean(name))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Watcher) remove(name string) error {
|
func (w *inotify) remove(name string) error {
|
||||||
wd, ok := w.watches.removePath(name)
|
wds, err := w.watches.removePath(name)
|
||||||
if !ok {
|
if err != nil {
|
||||||
return fmt.Errorf("%w: %s", ErrNonExistentWatch, name)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
success, errno := unix.InotifyRmWatch(w.fd, wd)
|
for _, wd := range wds {
|
||||||
if success == -1 {
|
_, err := unix.InotifyRmWatch(w.fd, wd)
|
||||||
// TODO: Perhaps it's not helpful to return an error here in every case;
|
if err != nil {
|
||||||
// The only two possible errors are:
|
// TODO: Perhaps it's not helpful to return an error here in every
|
||||||
//
|
// case; the only two possible errors are:
|
||||||
// - EBADF, which happens when w.fd is not a valid file descriptor
|
//
|
||||||
// of any kind.
|
// EBADF, which happens when w.fd is not a valid file descriptor of
|
||||||
// - EINVAL, which is when fd is not an inotify descriptor or wd
|
// any kind.
|
||||||
// is not a valid watch descriptor. Watch descriptors are
|
//
|
||||||
// invalidated when they are removed explicitly or implicitly;
|
// EINVAL, which is when fd is not an inotify descriptor or wd is
|
||||||
// explicitly by inotify_rm_watch, implicitly when the file they
|
// not a valid watch descriptor. Watch descriptors are invalidated
|
||||||
// are watching is deleted.
|
// when they are removed explicitly or implicitly; explicitly by
|
||||||
return errno
|
// inotify_rm_watch, implicitly when the file they are watching is
|
||||||
|
// deleted.
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// WatchList returns all paths explicitly added with [Watcher.Add] (and are not
|
func (w *inotify) WatchList() []string {
|
||||||
// yet removed).
|
|
||||||
//
|
|
||||||
// Returns nil if [Watcher.Close] was called.
|
|
||||||
func (w *Watcher) WatchList() []string {
|
|
||||||
if w.isClosed() {
|
if w.isClosed() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
w.mu.Lock()
|
||||||
|
defer w.mu.Unlock()
|
||||||
entries := make([]string, 0, w.watches.len())
|
entries := make([]string, 0, w.watches.len())
|
||||||
w.watches.mu.RLock()
|
|
||||||
for pathname := range w.watches.path {
|
for pathname := range w.watches.path {
|
||||||
entries = append(entries, pathname)
|
entries = append(entries, pathname)
|
||||||
}
|
}
|
||||||
w.watches.mu.RUnlock()
|
|
||||||
|
|
||||||
return entries
|
return entries
|
||||||
}
|
}
|
||||||
|
|
||||||
// readEvents reads from the inotify file descriptor, converts the
|
// readEvents reads from the inotify file descriptor, converts the
|
||||||
// received events into Event objects and sends them via the Events channel
|
// received events into Event objects and sends them via the Events channel
|
||||||
func (w *Watcher) readEvents() {
|
func (w *inotify) readEvents() {
|
||||||
defer func() {
|
defer func() {
|
||||||
close(w.doneResp)
|
close(w.doneResp)
|
||||||
close(w.Errors)
|
close(w.Errors)
|
||||||
close(w.Events)
|
close(w.Events)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
var (
|
var buf [unix.SizeofInotifyEvent * 4096]byte // Buffer for a maximum of 4096 raw events
|
||||||
buf [unix.SizeofInotifyEvent * 4096]byte // Buffer for a maximum of 4096 raw events
|
|
||||||
errno error // Syscall errno
|
|
||||||
)
|
|
||||||
for {
|
for {
|
||||||
// See if we have been closed.
|
|
||||||
if w.isClosed() {
|
if w.isClosed() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
n, err := w.inotifyFile.Read(buf[:])
|
n, err := w.inotifyFile.Read(buf[:])
|
||||||
switch {
|
if err != nil {
|
||||||
case errors.Unwrap(err) == os.ErrClosed:
|
if errors.Is(err, os.ErrClosed) {
|
||||||
return
|
return
|
||||||
case err != nil:
|
}
|
||||||
if !w.sendError(err) {
|
if !w.sendError(err) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -492,13 +366,9 @@ func (w *Watcher) readEvents() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if n < unix.SizeofInotifyEvent {
|
if n < unix.SizeofInotifyEvent {
|
||||||
var err error
|
err := errors.New("notify: short read in readEvents()") // Read was too short.
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
err = io.EOF // If EOF is received. This should really never happen.
|
err = io.EOF // If EOF is received. This should really never happen.
|
||||||
} else if n < 0 {
|
|
||||||
err = errno // If an error occurred while reading.
|
|
||||||
} else {
|
|
||||||
err = errors.New("notify: short read in readEvents()") // Read was too short.
|
|
||||||
}
|
}
|
||||||
if !w.sendError(err) {
|
if !w.sendError(err) {
|
||||||
return
|
return
|
||||||
@@ -506,74 +376,146 @@ func (w *Watcher) readEvents() {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We don't know how many events we just read into the buffer While the
|
||||||
|
// offset points to at least one whole event.
|
||||||
var offset uint32
|
var offset uint32
|
||||||
// We don't know how many events we just read into the buffer
|
|
||||||
// While the offset points to at least one whole event...
|
|
||||||
for offset <= uint32(n-unix.SizeofInotifyEvent) {
|
for offset <= uint32(n-unix.SizeofInotifyEvent) {
|
||||||
var (
|
// Point to the event in the buffer.
|
||||||
// Point "raw" to the event in the buffer
|
inEvent := (*unix.InotifyEvent)(unsafe.Pointer(&buf[offset]))
|
||||||
raw = (*unix.InotifyEvent)(unsafe.Pointer(&buf[offset]))
|
|
||||||
mask = uint32(raw.Mask)
|
|
||||||
nameLen = uint32(raw.Len)
|
|
||||||
)
|
|
||||||
|
|
||||||
if mask&unix.IN_Q_OVERFLOW != 0 {
|
if inEvent.Mask&unix.IN_Q_OVERFLOW != 0 {
|
||||||
if !w.sendError(ErrEventOverflow) {
|
if !w.sendError(ErrEventOverflow) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the event happened to the watched directory or the watched file, the kernel
|
ev, ok := w.handleEvent(inEvent, &buf, offset)
|
||||||
// doesn't append the filename to the event, but we would like to always fill the
|
if !ok {
|
||||||
// the "Name" field with a valid filename. We retrieve the path of the watch from
|
return
|
||||||
// the "paths" map.
|
|
||||||
watch := w.watches.byWd(uint32(raw.Wd))
|
|
||||||
|
|
||||||
// inotify will automatically remove the watch on deletes; just need
|
|
||||||
// to clean our state here.
|
|
||||||
if watch != nil && mask&unix.IN_DELETE_SELF == unix.IN_DELETE_SELF {
|
|
||||||
w.watches.remove(watch.wd)
|
|
||||||
}
|
}
|
||||||
// We can't really update the state when a watched path is moved;
|
if !w.sendEvent(ev) {
|
||||||
// only IN_MOVE_SELF is sent and not IN_MOVED_{FROM,TO}. So remove
|
return
|
||||||
// the watch.
|
|
||||||
if watch != nil && mask&unix.IN_MOVE_SELF == unix.IN_MOVE_SELF {
|
|
||||||
err := w.remove(watch.path)
|
|
||||||
if err != nil && !errors.Is(err, ErrNonExistentWatch) {
|
|
||||||
if !w.sendError(err) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var name string
|
|
||||||
if watch != nil {
|
|
||||||
name = watch.path
|
|
||||||
}
|
|
||||||
if nameLen > 0 {
|
|
||||||
// Point "bytes" at the first byte of the filename
|
|
||||||
bytes := (*[unix.PathMax]byte)(unsafe.Pointer(&buf[offset+unix.SizeofInotifyEvent]))[:nameLen:nameLen]
|
|
||||||
// The filename is padded with NULL bytes. TrimRight() gets rid of those.
|
|
||||||
name += "/" + strings.TrimRight(string(bytes[0:nameLen]), "\000")
|
|
||||||
}
|
|
||||||
|
|
||||||
event := w.newEvent(name, mask)
|
|
||||||
|
|
||||||
// Send the events that are not ignored on the events channel
|
|
||||||
if mask&unix.IN_IGNORED == 0 {
|
|
||||||
if !w.sendEvent(event) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move to the next event in the buffer
|
// Move to the next event in the buffer
|
||||||
offset += unix.SizeofInotifyEvent + nameLen
|
offset += unix.SizeofInotifyEvent + inEvent.Len
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// newEvent returns an platform-independent Event based on an inotify mask.
|
func (w *inotify) handleEvent(inEvent *unix.InotifyEvent, buf *[65536]byte, offset uint32) (Event, bool) {
|
||||||
func (w *Watcher) newEvent(name string, mask uint32) Event {
|
w.mu.Lock()
|
||||||
|
defer w.mu.Unlock()
|
||||||
|
|
||||||
|
/// If the event happened to the watched directory or the watched file, the
|
||||||
|
/// kernel doesn't append the filename to the event, but we would like to
|
||||||
|
/// always fill the the "Name" field with a valid filename. We retrieve the
|
||||||
|
/// path of the watch from the "paths" map.
|
||||||
|
///
|
||||||
|
/// Can be nil if Remove() was called in another goroutine for this path
|
||||||
|
/// inbetween reading the events from the kernel and reading the internal
|
||||||
|
/// state. Not much we can do about it, so just skip. See #616.
|
||||||
|
watch := w.watches.byWd(uint32(inEvent.Wd))
|
||||||
|
if watch == nil {
|
||||||
|
return Event{}, true
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
name = watch.path
|
||||||
|
nameLen = uint32(inEvent.Len)
|
||||||
|
)
|
||||||
|
if nameLen > 0 {
|
||||||
|
/// Point "bytes" at the first byte of the filename
|
||||||
|
bb := *buf
|
||||||
|
bytes := (*[unix.PathMax]byte)(unsafe.Pointer(&bb[offset+unix.SizeofInotifyEvent]))[:nameLen:nameLen]
|
||||||
|
/// The filename is padded with NULL bytes. TrimRight() gets rid of those.
|
||||||
|
name += "/" + strings.TrimRight(string(bytes[0:nameLen]), "\x00")
|
||||||
|
}
|
||||||
|
|
||||||
|
if debug {
|
||||||
|
internal.Debug(name, inEvent.Mask, inEvent.Cookie)
|
||||||
|
}
|
||||||
|
|
||||||
|
if inEvent.Mask&unix.IN_IGNORED != 0 || inEvent.Mask&unix.IN_UNMOUNT != 0 {
|
||||||
|
w.watches.remove(watch)
|
||||||
|
return Event{}, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// inotify will automatically remove the watch on deletes; just need
|
||||||
|
// to clean our state here.
|
||||||
|
if inEvent.Mask&unix.IN_DELETE_SELF == unix.IN_DELETE_SELF {
|
||||||
|
w.watches.remove(watch)
|
||||||
|
}
|
||||||
|
|
||||||
|
// We can't really update the state when a watched path is moved; only
|
||||||
|
// IN_MOVE_SELF is sent and not IN_MOVED_{FROM,TO}. So remove the watch.
|
||||||
|
if inEvent.Mask&unix.IN_MOVE_SELF == unix.IN_MOVE_SELF {
|
||||||
|
if watch.recurse { // Do nothing
|
||||||
|
return Event{}, true
|
||||||
|
}
|
||||||
|
|
||||||
|
err := w.remove(watch.path)
|
||||||
|
if err != nil && !errors.Is(err, ErrNonExistentWatch) {
|
||||||
|
if !w.sendError(err) {
|
||||||
|
return Event{}, false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Skip if we're watching both this path and the parent; the parent will
|
||||||
|
/// already send a delete so no need to do it twice.
|
||||||
|
if inEvent.Mask&unix.IN_DELETE_SELF != 0 {
|
||||||
|
_, ok := w.watches.path[filepath.Dir(watch.path)]
|
||||||
|
if ok {
|
||||||
|
return Event{}, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ev := w.newEvent(name, inEvent.Mask, inEvent.Cookie)
|
||||||
|
// Need to update watch path for recurse.
|
||||||
|
if watch.recurse {
|
||||||
|
isDir := inEvent.Mask&unix.IN_ISDIR == unix.IN_ISDIR
|
||||||
|
/// New directory created: set up watch on it.
|
||||||
|
if isDir && ev.Has(Create) {
|
||||||
|
err := w.register(ev.Name, watch.flags, true)
|
||||||
|
if !w.sendError(err) {
|
||||||
|
return Event{}, false
|
||||||
|
}
|
||||||
|
|
||||||
|
// This was a directory rename, so we need to update all the
|
||||||
|
// children.
|
||||||
|
//
|
||||||
|
// TODO: this is of course pretty slow; we should use a better data
|
||||||
|
// structure for storing all of this, e.g. store children in the
|
||||||
|
// watch. I have some code for this in my kqueue refactor we can use
|
||||||
|
// in the future. For now I'm okay with this as it's not publicly
|
||||||
|
// available. Correctness first, performance second.
|
||||||
|
if ev.renamedFrom != "" {
|
||||||
|
for k, ww := range w.watches.wd {
|
||||||
|
if k == watch.wd || ww.path == ev.Name {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(ww.path, ev.renamedFrom) {
|
||||||
|
ww.path = strings.Replace(ww.path, ev.renamedFrom, ev.Name, 1)
|
||||||
|
w.watches.wd[k] = ww
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ev, true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *inotify) isRecursive(path string) bool {
|
||||||
|
ww := w.watches.byPath(path)
|
||||||
|
if ww == nil { // path could be a file, so also check the Dir.
|
||||||
|
ww = w.watches.byPath(filepath.Dir(path))
|
||||||
|
}
|
||||||
|
return ww != nil && ww.recurse
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *inotify) newEvent(name string, mask, cookie uint32) Event {
|
||||||
e := Event{Name: name}
|
e := Event{Name: name}
|
||||||
if mask&unix.IN_CREATE == unix.IN_CREATE || mask&unix.IN_MOVED_TO == unix.IN_MOVED_TO {
|
if mask&unix.IN_CREATE == unix.IN_CREATE || mask&unix.IN_MOVED_TO == unix.IN_MOVED_TO {
|
||||||
e.Op |= Create
|
e.Op |= Create
|
||||||
@@ -584,11 +526,58 @@ func (w *Watcher) newEvent(name string, mask uint32) Event {
|
|||||||
if mask&unix.IN_MODIFY == unix.IN_MODIFY {
|
if mask&unix.IN_MODIFY == unix.IN_MODIFY {
|
||||||
e.Op |= Write
|
e.Op |= Write
|
||||||
}
|
}
|
||||||
|
if mask&unix.IN_OPEN == unix.IN_OPEN {
|
||||||
|
e.Op |= xUnportableOpen
|
||||||
|
}
|
||||||
|
if mask&unix.IN_ACCESS == unix.IN_ACCESS {
|
||||||
|
e.Op |= xUnportableRead
|
||||||
|
}
|
||||||
|
if mask&unix.IN_CLOSE_WRITE == unix.IN_CLOSE_WRITE {
|
||||||
|
e.Op |= xUnportableCloseWrite
|
||||||
|
}
|
||||||
|
if mask&unix.IN_CLOSE_NOWRITE == unix.IN_CLOSE_NOWRITE {
|
||||||
|
e.Op |= xUnportableCloseRead
|
||||||
|
}
|
||||||
if mask&unix.IN_MOVE_SELF == unix.IN_MOVE_SELF || mask&unix.IN_MOVED_FROM == unix.IN_MOVED_FROM {
|
if mask&unix.IN_MOVE_SELF == unix.IN_MOVE_SELF || mask&unix.IN_MOVED_FROM == unix.IN_MOVED_FROM {
|
||||||
e.Op |= Rename
|
e.Op |= Rename
|
||||||
}
|
}
|
||||||
if mask&unix.IN_ATTRIB == unix.IN_ATTRIB {
|
if mask&unix.IN_ATTRIB == unix.IN_ATTRIB {
|
||||||
e.Op |= Chmod
|
e.Op |= Chmod
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if cookie != 0 {
|
||||||
|
if mask&unix.IN_MOVED_FROM == unix.IN_MOVED_FROM {
|
||||||
|
w.cookiesMu.Lock()
|
||||||
|
w.cookies[w.cookieIndex] = koekje{cookie: cookie, path: e.Name}
|
||||||
|
w.cookieIndex++
|
||||||
|
if w.cookieIndex > 9 {
|
||||||
|
w.cookieIndex = 0
|
||||||
|
}
|
||||||
|
w.cookiesMu.Unlock()
|
||||||
|
} else if mask&unix.IN_MOVED_TO == unix.IN_MOVED_TO {
|
||||||
|
w.cookiesMu.Lock()
|
||||||
|
var prev string
|
||||||
|
for _, c := range w.cookies {
|
||||||
|
if c.cookie == cookie {
|
||||||
|
prev = c.path
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
w.cookiesMu.Unlock()
|
||||||
|
e.renamedFrom = prev
|
||||||
|
}
|
||||||
|
}
|
||||||
return e
|
return e
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w *inotify) xSupports(op Op) bool {
|
||||||
|
return true // Supports everything.
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *inotify) state() {
|
||||||
|
w.mu.Lock()
|
||||||
|
defer w.mu.Unlock()
|
||||||
|
for wd, ww := range w.watches.wd {
|
||||||
|
fmt.Fprintf(os.Stderr, "%4d: recurse=%t %q\n", wd, ww.recurse, ww.path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
791
vendor/github.com/fsnotify/fsnotify/backend_kqueue.go
generated
vendored
791
vendor/github.com/fsnotify/fsnotify/backend_kqueue.go
generated
vendored
File diff suppressed because it is too large
Load Diff
203
vendor/github.com/fsnotify/fsnotify/backend_other.go
generated
vendored
203
vendor/github.com/fsnotify/fsnotify/backend_other.go
generated
vendored
@@ -1,205 +1,22 @@
|
|||||||
//go:build appengine || (!darwin && !dragonfly && !freebsd && !openbsd && !linux && !netbsd && !solaris && !windows)
|
//go:build appengine || (!darwin && !dragonfly && !freebsd && !openbsd && !linux && !netbsd && !solaris && !windows)
|
||||||
// +build appengine !darwin,!dragonfly,!freebsd,!openbsd,!linux,!netbsd,!solaris,!windows
|
|
||||||
|
|
||||||
// Note: the documentation on the Watcher type and methods is generated from
|
|
||||||
// mkdoc.zsh
|
|
||||||
|
|
||||||
package fsnotify
|
package fsnotify
|
||||||
|
|
||||||
import "errors"
|
import "errors"
|
||||||
|
|
||||||
// Watcher watches a set of paths, delivering events on a channel.
|
type other struct {
|
||||||
//
|
|
||||||
// A watcher should not be copied (e.g. pass it by pointer, rather than by
|
|
||||||
// value).
|
|
||||||
//
|
|
||||||
// # Linux notes
|
|
||||||
//
|
|
||||||
// When a file is removed a Remove event won't be emitted until all file
|
|
||||||
// descriptors are closed, and deletes will always emit a Chmod. For example:
|
|
||||||
//
|
|
||||||
// fp := os.Open("file")
|
|
||||||
// os.Remove("file") // Triggers Chmod
|
|
||||||
// fp.Close() // Triggers Remove
|
|
||||||
//
|
|
||||||
// This is the event that inotify sends, so not much can be changed about this.
|
|
||||||
//
|
|
||||||
// The fs.inotify.max_user_watches sysctl variable specifies the upper limit
|
|
||||||
// for the number of watches per user, and fs.inotify.max_user_instances
|
|
||||||
// specifies the maximum number of inotify instances per user. Every Watcher you
|
|
||||||
// create is an "instance", and every path you add is a "watch".
|
|
||||||
//
|
|
||||||
// These are also exposed in /proc as /proc/sys/fs/inotify/max_user_watches and
|
|
||||||
// /proc/sys/fs/inotify/max_user_instances
|
|
||||||
//
|
|
||||||
// To increase them you can use sysctl or write the value to the /proc file:
|
|
||||||
//
|
|
||||||
// # Default values on Linux 5.18
|
|
||||||
// sysctl fs.inotify.max_user_watches=124983
|
|
||||||
// sysctl fs.inotify.max_user_instances=128
|
|
||||||
//
|
|
||||||
// To make the changes persist on reboot edit /etc/sysctl.conf or
|
|
||||||
// /usr/lib/sysctl.d/50-default.conf (details differ per Linux distro; check
|
|
||||||
// your distro's documentation):
|
|
||||||
//
|
|
||||||
// fs.inotify.max_user_watches=124983
|
|
||||||
// fs.inotify.max_user_instances=128
|
|
||||||
//
|
|
||||||
// Reaching the limit will result in a "no space left on device" or "too many open
|
|
||||||
// files" error.
|
|
||||||
//
|
|
||||||
// # kqueue notes (macOS, BSD)
|
|
||||||
//
|
|
||||||
// kqueue requires opening a file descriptor for every file that's being watched;
|
|
||||||
// so if you're watching a directory with five files then that's six file
|
|
||||||
// descriptors. You will run in to your system's "max open files" limit faster on
|
|
||||||
// these platforms.
|
|
||||||
//
|
|
||||||
// The sysctl variables kern.maxfiles and kern.maxfilesperproc can be used to
|
|
||||||
// control the maximum number of open files, as well as /etc/login.conf on BSD
|
|
||||||
// systems.
|
|
||||||
//
|
|
||||||
// # Windows notes
|
|
||||||
//
|
|
||||||
// Paths can be added as "C:\path\to\dir", but forward slashes
|
|
||||||
// ("C:/path/to/dir") will also work.
|
|
||||||
//
|
|
||||||
// When a watched directory is removed it will always send an event for the
|
|
||||||
// directory itself, but may not send events for all files in that directory.
|
|
||||||
// Sometimes it will send events for all times, sometimes it will send no
|
|
||||||
// events, and often only for some files.
|
|
||||||
//
|
|
||||||
// The default ReadDirectoryChangesW() buffer size is 64K, which is the largest
|
|
||||||
// value that is guaranteed to work with SMB filesystems. If you have many
|
|
||||||
// events in quick succession this may not be enough, and you will have to use
|
|
||||||
// [WithBufferSize] to increase the value.
|
|
||||||
type Watcher struct {
|
|
||||||
// Events sends the filesystem change events.
|
|
||||||
//
|
|
||||||
// fsnotify can send the following events; a "path" here can refer to a
|
|
||||||
// file, directory, symbolic link, or special file like a FIFO.
|
|
||||||
//
|
|
||||||
// fsnotify.Create A new path was created; this may be followed by one
|
|
||||||
// or more Write events if data also gets written to a
|
|
||||||
// file.
|
|
||||||
//
|
|
||||||
// fsnotify.Remove A path was removed.
|
|
||||||
//
|
|
||||||
// fsnotify.Rename A path was renamed. A rename is always sent with the
|
|
||||||
// old path as Event.Name, and a Create event will be
|
|
||||||
// sent with the new name. Renames are only sent for
|
|
||||||
// paths that are currently watched; e.g. moving an
|
|
||||||
// unmonitored file into a monitored directory will
|
|
||||||
// show up as just a Create. Similarly, renaming a file
|
|
||||||
// to outside a monitored directory will show up as
|
|
||||||
// only a Rename.
|
|
||||||
//
|
|
||||||
// fsnotify.Write A file or named pipe was written to. A Truncate will
|
|
||||||
// also trigger a Write. A single "write action"
|
|
||||||
// initiated by the user may show up as one or multiple
|
|
||||||
// writes, depending on when the system syncs things to
|
|
||||||
// disk. For example when compiling a large Go program
|
|
||||||
// you may get hundreds of Write events, and you may
|
|
||||||
// want to wait until you've stopped receiving them
|
|
||||||
// (see the dedup example in cmd/fsnotify).
|
|
||||||
//
|
|
||||||
// Some systems may send Write event for directories
|
|
||||||
// when the directory content changes.
|
|
||||||
//
|
|
||||||
// fsnotify.Chmod Attributes were changed. On Linux this is also sent
|
|
||||||
// when a file is removed (or more accurately, when a
|
|
||||||
// link to an inode is removed). On kqueue it's sent
|
|
||||||
// when a file is truncated. On Windows it's never
|
|
||||||
// sent.
|
|
||||||
Events chan Event
|
Events chan Event
|
||||||
|
|
||||||
// Errors sends any errors.
|
|
||||||
//
|
|
||||||
// ErrEventOverflow is used to indicate there are too many events:
|
|
||||||
//
|
|
||||||
// - inotify: There are too many queued events (fs.inotify.max_queued_events sysctl)
|
|
||||||
// - windows: The buffer size is too small; WithBufferSize() can be used to increase it.
|
|
||||||
// - kqueue, fen: Not used.
|
|
||||||
Errors chan error
|
Errors chan error
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewWatcher creates a new Watcher.
|
var defaultBufferSize = 0
|
||||||
func NewWatcher() (*Watcher, error) {
|
|
||||||
|
func newBackend(ev chan Event, errs chan error) (backend, error) {
|
||||||
return nil, errors.New("fsnotify not supported on the current platform")
|
return nil, errors.New("fsnotify not supported on the current platform")
|
||||||
}
|
}
|
||||||
|
func (w *other) Close() error { return nil }
|
||||||
// NewBufferedWatcher creates a new Watcher with a buffered Watcher.Events
|
func (w *other) WatchList() []string { return nil }
|
||||||
// channel.
|
func (w *other) Add(name string) error { return nil }
|
||||||
//
|
func (w *other) AddWith(name string, opts ...addOpt) error { return nil }
|
||||||
// The main use case for this is situations with a very large number of events
|
func (w *other) Remove(name string) error { return nil }
|
||||||
// where the kernel buffer size can't be increased (e.g. due to lack of
|
func (w *other) xSupports(op Op) bool { return false }
|
||||||
// permissions). An unbuffered Watcher will perform better for almost all use
|
|
||||||
// cases, and whenever possible you will be better off increasing the kernel
|
|
||||||
// buffers instead of adding a large userspace buffer.
|
|
||||||
func NewBufferedWatcher(sz uint) (*Watcher, error) { return NewWatcher() }
|
|
||||||
|
|
||||||
// Close removes all watches and closes the Events channel.
|
|
||||||
func (w *Watcher) Close() error { return nil }
|
|
||||||
|
|
||||||
// WatchList returns all paths explicitly added with [Watcher.Add] (and are not
|
|
||||||
// yet removed).
|
|
||||||
//
|
|
||||||
// Returns nil if [Watcher.Close] was called.
|
|
||||||
func (w *Watcher) WatchList() []string { return nil }
|
|
||||||
|
|
||||||
// Add starts monitoring the path for changes.
|
|
||||||
//
|
|
||||||
// A path can only be watched once; watching it more than once is a no-op and will
|
|
||||||
// not return an error. Paths that do not yet exist on the filesystem cannot be
|
|
||||||
// watched.
|
|
||||||
//
|
|
||||||
// A watch will be automatically removed if the watched path is deleted or
|
|
||||||
// renamed. The exception is the Windows backend, which doesn't remove the
|
|
||||||
// watcher on renames.
|
|
||||||
//
|
|
||||||
// Notifications on network filesystems (NFS, SMB, FUSE, etc.) or special
|
|
||||||
// filesystems (/proc, /sys, etc.) generally don't work.
|
|
||||||
//
|
|
||||||
// Returns [ErrClosed] if [Watcher.Close] was called.
|
|
||||||
//
|
|
||||||
// See [Watcher.AddWith] for a version that allows adding options.
|
|
||||||
//
|
|
||||||
// # Watching directories
|
|
||||||
//
|
|
||||||
// All files in a directory are monitored, including new files that are created
|
|
||||||
// after the watcher is started. Subdirectories are not watched (i.e. it's
|
|
||||||
// non-recursive).
|
|
||||||
//
|
|
||||||
// # Watching files
|
|
||||||
//
|
|
||||||
// Watching individual files (rather than directories) is generally not
|
|
||||||
// recommended as many programs (especially editors) update files atomically: it
|
|
||||||
// will write to a temporary file which is then moved to to destination,
|
|
||||||
// overwriting the original (or some variant thereof). The watcher on the
|
|
||||||
// original file is now lost, as that no longer exists.
|
|
||||||
//
|
|
||||||
// The upshot of this is that a power failure or crash won't leave a
|
|
||||||
// half-written file.
|
|
||||||
//
|
|
||||||
// Watch the parent directory and use Event.Name to filter out files you're not
|
|
||||||
// interested in. There is an example of this in cmd/fsnotify/file.go.
|
|
||||||
func (w *Watcher) Add(name string) error { return nil }
|
|
||||||
|
|
||||||
// AddWith is like [Watcher.Add], but allows adding options. When using Add()
|
|
||||||
// the defaults described below are used.
|
|
||||||
//
|
|
||||||
// Possible options are:
|
|
||||||
//
|
|
||||||
// - [WithBufferSize] sets the buffer size for the Windows backend; no-op on
|
|
||||||
// other platforms. The default is 64K (65536 bytes).
|
|
||||||
func (w *Watcher) AddWith(name string, opts ...addOpt) error { return nil }
|
|
||||||
|
|
||||||
// Remove stops monitoring the path for changes.
|
|
||||||
//
|
|
||||||
// Directories are always removed non-recursively. For example, if you added
|
|
||||||
// /tmp/dir and /tmp/dir/subdir then you will need to remove both.
|
|
||||||
//
|
|
||||||
// Removing a path that has not yet been added returns [ErrNonExistentWatch].
|
|
||||||
//
|
|
||||||
// Returns nil if [Watcher.Close] was called.
|
|
||||||
func (w *Watcher) Remove(name string) error { return nil }
|
|
||||||
|
|||||||
321
vendor/github.com/fsnotify/fsnotify/backend_windows.go
generated
vendored
321
vendor/github.com/fsnotify/fsnotify/backend_windows.go
generated
vendored
@@ -1,12 +1,8 @@
|
|||||||
//go:build windows
|
//go:build windows
|
||||||
// +build windows
|
|
||||||
|
|
||||||
// Windows backend based on ReadDirectoryChangesW()
|
// Windows backend based on ReadDirectoryChangesW()
|
||||||
//
|
//
|
||||||
// https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-readdirectorychangesw
|
// https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-readdirectorychangesw
|
||||||
//
|
|
||||||
// Note: the documentation on the Watcher type and methods is generated from
|
|
||||||
// mkdoc.zsh
|
|
||||||
|
|
||||||
package fsnotify
|
package fsnotify
|
||||||
|
|
||||||
@@ -19,196 +15,80 @@ import (
|
|||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
"time"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/fsnotify/fsnotify/internal"
|
||||||
"golang.org/x/sys/windows"
|
"golang.org/x/sys/windows"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Watcher watches a set of paths, delivering events on a channel.
|
type readDirChangesW struct {
|
||||||
//
|
|
||||||
// A watcher should not be copied (e.g. pass it by pointer, rather than by
|
|
||||||
// value).
|
|
||||||
//
|
|
||||||
// # Linux notes
|
|
||||||
//
|
|
||||||
// When a file is removed a Remove event won't be emitted until all file
|
|
||||||
// descriptors are closed, and deletes will always emit a Chmod. For example:
|
|
||||||
//
|
|
||||||
// fp := os.Open("file")
|
|
||||||
// os.Remove("file") // Triggers Chmod
|
|
||||||
// fp.Close() // Triggers Remove
|
|
||||||
//
|
|
||||||
// This is the event that inotify sends, so not much can be changed about this.
|
|
||||||
//
|
|
||||||
// The fs.inotify.max_user_watches sysctl variable specifies the upper limit
|
|
||||||
// for the number of watches per user, and fs.inotify.max_user_instances
|
|
||||||
// specifies the maximum number of inotify instances per user. Every Watcher you
|
|
||||||
// create is an "instance", and every path you add is a "watch".
|
|
||||||
//
|
|
||||||
// These are also exposed in /proc as /proc/sys/fs/inotify/max_user_watches and
|
|
||||||
// /proc/sys/fs/inotify/max_user_instances
|
|
||||||
//
|
|
||||||
// To increase them you can use sysctl or write the value to the /proc file:
|
|
||||||
//
|
|
||||||
// # Default values on Linux 5.18
|
|
||||||
// sysctl fs.inotify.max_user_watches=124983
|
|
||||||
// sysctl fs.inotify.max_user_instances=128
|
|
||||||
//
|
|
||||||
// To make the changes persist on reboot edit /etc/sysctl.conf or
|
|
||||||
// /usr/lib/sysctl.d/50-default.conf (details differ per Linux distro; check
|
|
||||||
// your distro's documentation):
|
|
||||||
//
|
|
||||||
// fs.inotify.max_user_watches=124983
|
|
||||||
// fs.inotify.max_user_instances=128
|
|
||||||
//
|
|
||||||
// Reaching the limit will result in a "no space left on device" or "too many open
|
|
||||||
// files" error.
|
|
||||||
//
|
|
||||||
// # kqueue notes (macOS, BSD)
|
|
||||||
//
|
|
||||||
// kqueue requires opening a file descriptor for every file that's being watched;
|
|
||||||
// so if you're watching a directory with five files then that's six file
|
|
||||||
// descriptors. You will run in to your system's "max open files" limit faster on
|
|
||||||
// these platforms.
|
|
||||||
//
|
|
||||||
// The sysctl variables kern.maxfiles and kern.maxfilesperproc can be used to
|
|
||||||
// control the maximum number of open files, as well as /etc/login.conf on BSD
|
|
||||||
// systems.
|
|
||||||
//
|
|
||||||
// # Windows notes
|
|
||||||
//
|
|
||||||
// Paths can be added as "C:\path\to\dir", but forward slashes
|
|
||||||
// ("C:/path/to/dir") will also work.
|
|
||||||
//
|
|
||||||
// When a watched directory is removed it will always send an event for the
|
|
||||||
// directory itself, but may not send events for all files in that directory.
|
|
||||||
// Sometimes it will send events for all times, sometimes it will send no
|
|
||||||
// events, and often only for some files.
|
|
||||||
//
|
|
||||||
// The default ReadDirectoryChangesW() buffer size is 64K, which is the largest
|
|
||||||
// value that is guaranteed to work with SMB filesystems. If you have many
|
|
||||||
// events in quick succession this may not be enough, and you will have to use
|
|
||||||
// [WithBufferSize] to increase the value.
|
|
||||||
type Watcher struct {
|
|
||||||
// Events sends the filesystem change events.
|
|
||||||
//
|
|
||||||
// fsnotify can send the following events; a "path" here can refer to a
|
|
||||||
// file, directory, symbolic link, or special file like a FIFO.
|
|
||||||
//
|
|
||||||
// fsnotify.Create A new path was created; this may be followed by one
|
|
||||||
// or more Write events if data also gets written to a
|
|
||||||
// file.
|
|
||||||
//
|
|
||||||
// fsnotify.Remove A path was removed.
|
|
||||||
//
|
|
||||||
// fsnotify.Rename A path was renamed. A rename is always sent with the
|
|
||||||
// old path as Event.Name, and a Create event will be
|
|
||||||
// sent with the new name. Renames are only sent for
|
|
||||||
// paths that are currently watched; e.g. moving an
|
|
||||||
// unmonitored file into a monitored directory will
|
|
||||||
// show up as just a Create. Similarly, renaming a file
|
|
||||||
// to outside a monitored directory will show up as
|
|
||||||
// only a Rename.
|
|
||||||
//
|
|
||||||
// fsnotify.Write A file or named pipe was written to. A Truncate will
|
|
||||||
// also trigger a Write. A single "write action"
|
|
||||||
// initiated by the user may show up as one or multiple
|
|
||||||
// writes, depending on when the system syncs things to
|
|
||||||
// disk. For example when compiling a large Go program
|
|
||||||
// you may get hundreds of Write events, and you may
|
|
||||||
// want to wait until you've stopped receiving them
|
|
||||||
// (see the dedup example in cmd/fsnotify).
|
|
||||||
//
|
|
||||||
// Some systems may send Write event for directories
|
|
||||||
// when the directory content changes.
|
|
||||||
//
|
|
||||||
// fsnotify.Chmod Attributes were changed. On Linux this is also sent
|
|
||||||
// when a file is removed (or more accurately, when a
|
|
||||||
// link to an inode is removed). On kqueue it's sent
|
|
||||||
// when a file is truncated. On Windows it's never
|
|
||||||
// sent.
|
|
||||||
Events chan Event
|
Events chan Event
|
||||||
|
|
||||||
// Errors sends any errors.
|
|
||||||
//
|
|
||||||
// ErrEventOverflow is used to indicate there are too many events:
|
|
||||||
//
|
|
||||||
// - inotify: There are too many queued events (fs.inotify.max_queued_events sysctl)
|
|
||||||
// - windows: The buffer size is too small; WithBufferSize() can be used to increase it.
|
|
||||||
// - kqueue, fen: Not used.
|
|
||||||
Errors chan error
|
Errors chan error
|
||||||
|
|
||||||
port windows.Handle // Handle to completion port
|
port windows.Handle // Handle to completion port
|
||||||
input chan *input // Inputs to the reader are sent on this channel
|
input chan *input // Inputs to the reader are sent on this channel
|
||||||
quit chan chan<- error
|
done chan chan<- error
|
||||||
|
|
||||||
mu sync.Mutex // Protects access to watches, closed
|
mu sync.Mutex // Protects access to watches, closed
|
||||||
watches watchMap // Map of watches (key: i-number)
|
watches watchMap // Map of watches (key: i-number)
|
||||||
closed bool // Set to true when Close() is first called
|
closed bool // Set to true when Close() is first called
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewWatcher creates a new Watcher.
|
var defaultBufferSize = 50
|
||||||
func NewWatcher() (*Watcher, error) {
|
|
||||||
return NewBufferedWatcher(50)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewBufferedWatcher creates a new Watcher with a buffered Watcher.Events
|
func newBackend(ev chan Event, errs chan error) (backend, error) {
|
||||||
// channel.
|
|
||||||
//
|
|
||||||
// The main use case for this is situations with a very large number of events
|
|
||||||
// where the kernel buffer size can't be increased (e.g. due to lack of
|
|
||||||
// permissions). An unbuffered Watcher will perform better for almost all use
|
|
||||||
// cases, and whenever possible you will be better off increasing the kernel
|
|
||||||
// buffers instead of adding a large userspace buffer.
|
|
||||||
func NewBufferedWatcher(sz uint) (*Watcher, error) {
|
|
||||||
port, err := windows.CreateIoCompletionPort(windows.InvalidHandle, 0, 0, 0)
|
port, err := windows.CreateIoCompletionPort(windows.InvalidHandle, 0, 0, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, os.NewSyscallError("CreateIoCompletionPort", err)
|
return nil, os.NewSyscallError("CreateIoCompletionPort", err)
|
||||||
}
|
}
|
||||||
w := &Watcher{
|
w := &readDirChangesW{
|
||||||
|
Events: ev,
|
||||||
|
Errors: errs,
|
||||||
port: port,
|
port: port,
|
||||||
watches: make(watchMap),
|
watches: make(watchMap),
|
||||||
input: make(chan *input, 1),
|
input: make(chan *input, 1),
|
||||||
Events: make(chan Event, sz),
|
done: make(chan chan<- error, 1),
|
||||||
Errors: make(chan error),
|
|
||||||
quit: make(chan chan<- error, 1),
|
|
||||||
}
|
}
|
||||||
go w.readEvents()
|
go w.readEvents()
|
||||||
return w, nil
|
return w, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Watcher) isClosed() bool {
|
func (w *readDirChangesW) isClosed() bool {
|
||||||
w.mu.Lock()
|
w.mu.Lock()
|
||||||
defer w.mu.Unlock()
|
defer w.mu.Unlock()
|
||||||
return w.closed
|
return w.closed
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Watcher) sendEvent(name string, mask uint64) bool {
|
func (w *readDirChangesW) sendEvent(name, renamedFrom string, mask uint64) bool {
|
||||||
if mask == 0 {
|
if mask == 0 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
event := w.newEvent(name, uint32(mask))
|
event := w.newEvent(name, uint32(mask))
|
||||||
|
event.renamedFrom = renamedFrom
|
||||||
select {
|
select {
|
||||||
case ch := <-w.quit:
|
case ch := <-w.done:
|
||||||
w.quit <- ch
|
w.done <- ch
|
||||||
case w.Events <- event:
|
case w.Events <- event:
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true if the error was sent, or false if watcher is closed.
|
// Returns true if the error was sent, or false if watcher is closed.
|
||||||
func (w *Watcher) sendError(err error) bool {
|
func (w *readDirChangesW) sendError(err error) bool {
|
||||||
|
if err == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
select {
|
select {
|
||||||
|
case <-w.done:
|
||||||
|
return false
|
||||||
case w.Errors <- err:
|
case w.Errors <- err:
|
||||||
return true
|
return true
|
||||||
case <-w.quit:
|
|
||||||
}
|
}
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close removes all watches and closes the Events channel.
|
func (w *readDirChangesW) Close() error {
|
||||||
func (w *Watcher) Close() error {
|
|
||||||
if w.isClosed() {
|
if w.isClosed() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -217,66 +97,30 @@ func (w *Watcher) Close() error {
|
|||||||
w.closed = true
|
w.closed = true
|
||||||
w.mu.Unlock()
|
w.mu.Unlock()
|
||||||
|
|
||||||
// Send "quit" message to the reader goroutine
|
// Send "done" message to the reader goroutine
|
||||||
ch := make(chan error)
|
ch := make(chan error)
|
||||||
w.quit <- ch
|
w.done <- ch
|
||||||
if err := w.wakeupReader(); err != nil {
|
if err := w.wakeupReader(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return <-ch
|
return <-ch
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add starts monitoring the path for changes.
|
func (w *readDirChangesW) Add(name string) error { return w.AddWith(name) }
|
||||||
//
|
|
||||||
// A path can only be watched once; watching it more than once is a no-op and will
|
|
||||||
// not return an error. Paths that do not yet exist on the filesystem cannot be
|
|
||||||
// watched.
|
|
||||||
//
|
|
||||||
// A watch will be automatically removed if the watched path is deleted or
|
|
||||||
// renamed. The exception is the Windows backend, which doesn't remove the
|
|
||||||
// watcher on renames.
|
|
||||||
//
|
|
||||||
// Notifications on network filesystems (NFS, SMB, FUSE, etc.) or special
|
|
||||||
// filesystems (/proc, /sys, etc.) generally don't work.
|
|
||||||
//
|
|
||||||
// Returns [ErrClosed] if [Watcher.Close] was called.
|
|
||||||
//
|
|
||||||
// See [Watcher.AddWith] for a version that allows adding options.
|
|
||||||
//
|
|
||||||
// # Watching directories
|
|
||||||
//
|
|
||||||
// All files in a directory are monitored, including new files that are created
|
|
||||||
// after the watcher is started. Subdirectories are not watched (i.e. it's
|
|
||||||
// non-recursive).
|
|
||||||
//
|
|
||||||
// # Watching files
|
|
||||||
//
|
|
||||||
// Watching individual files (rather than directories) is generally not
|
|
||||||
// recommended as many programs (especially editors) update files atomically: it
|
|
||||||
// will write to a temporary file which is then moved to to destination,
|
|
||||||
// overwriting the original (or some variant thereof). The watcher on the
|
|
||||||
// original file is now lost, as that no longer exists.
|
|
||||||
//
|
|
||||||
// The upshot of this is that a power failure or crash won't leave a
|
|
||||||
// half-written file.
|
|
||||||
//
|
|
||||||
// Watch the parent directory and use Event.Name to filter out files you're not
|
|
||||||
// interested in. There is an example of this in cmd/fsnotify/file.go.
|
|
||||||
func (w *Watcher) Add(name string) error { return w.AddWith(name) }
|
|
||||||
|
|
||||||
// AddWith is like [Watcher.Add], but allows adding options. When using Add()
|
func (w *readDirChangesW) AddWith(name string, opts ...addOpt) error {
|
||||||
// the defaults described below are used.
|
|
||||||
//
|
|
||||||
// Possible options are:
|
|
||||||
//
|
|
||||||
// - [WithBufferSize] sets the buffer size for the Windows backend; no-op on
|
|
||||||
// other platforms. The default is 64K (65536 bytes).
|
|
||||||
func (w *Watcher) AddWith(name string, opts ...addOpt) error {
|
|
||||||
if w.isClosed() {
|
if w.isClosed() {
|
||||||
return ErrClosed
|
return ErrClosed
|
||||||
}
|
}
|
||||||
|
if debug {
|
||||||
|
fmt.Fprintf(os.Stderr, "FSNOTIFY_DEBUG: %s AddWith(%q)\n",
|
||||||
|
time.Now().Format("15:04:05.000000000"), filepath.ToSlash(name))
|
||||||
|
}
|
||||||
|
|
||||||
with := getOptions(opts...)
|
with := getOptions(opts...)
|
||||||
|
if !w.xSupports(with.op) {
|
||||||
|
return fmt.Errorf("%w: %s", xErrUnsupported, with.op)
|
||||||
|
}
|
||||||
if with.bufsize < 4096 {
|
if with.bufsize < 4096 {
|
||||||
return fmt.Errorf("fsnotify.WithBufferSize: buffer size cannot be smaller than 4096 bytes")
|
return fmt.Errorf("fsnotify.WithBufferSize: buffer size cannot be smaller than 4096 bytes")
|
||||||
}
|
}
|
||||||
@@ -295,18 +139,14 @@ func (w *Watcher) AddWith(name string, opts ...addOpt) error {
|
|||||||
return <-in.reply
|
return <-in.reply
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove stops monitoring the path for changes.
|
func (w *readDirChangesW) Remove(name string) error {
|
||||||
//
|
|
||||||
// Directories are always removed non-recursively. For example, if you added
|
|
||||||
// /tmp/dir and /tmp/dir/subdir then you will need to remove both.
|
|
||||||
//
|
|
||||||
// Removing a path that has not yet been added returns [ErrNonExistentWatch].
|
|
||||||
//
|
|
||||||
// Returns nil if [Watcher.Close] was called.
|
|
||||||
func (w *Watcher) Remove(name string) error {
|
|
||||||
if w.isClosed() {
|
if w.isClosed() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
if debug {
|
||||||
|
fmt.Fprintf(os.Stderr, "FSNOTIFY_DEBUG: %s Remove(%q)\n",
|
||||||
|
time.Now().Format("15:04:05.000000000"), filepath.ToSlash(name))
|
||||||
|
}
|
||||||
|
|
||||||
in := &input{
|
in := &input{
|
||||||
op: opRemoveWatch,
|
op: opRemoveWatch,
|
||||||
@@ -320,11 +160,7 @@ func (w *Watcher) Remove(name string) error {
|
|||||||
return <-in.reply
|
return <-in.reply
|
||||||
}
|
}
|
||||||
|
|
||||||
// WatchList returns all paths explicitly added with [Watcher.Add] (and are not
|
func (w *readDirChangesW) WatchList() []string {
|
||||||
// yet removed).
|
|
||||||
//
|
|
||||||
// Returns nil if [Watcher.Close] was called.
|
|
||||||
func (w *Watcher) WatchList() []string {
|
|
||||||
if w.isClosed() {
|
if w.isClosed() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -335,7 +171,13 @@ func (w *Watcher) WatchList() []string {
|
|||||||
entries := make([]string, 0, len(w.watches))
|
entries := make([]string, 0, len(w.watches))
|
||||||
for _, entry := range w.watches {
|
for _, entry := range w.watches {
|
||||||
for _, watchEntry := range entry {
|
for _, watchEntry := range entry {
|
||||||
entries = append(entries, watchEntry.path)
|
for name := range watchEntry.names {
|
||||||
|
entries = append(entries, filepath.Join(watchEntry.path, name))
|
||||||
|
}
|
||||||
|
// the directory itself is being watched
|
||||||
|
if watchEntry.mask != 0 {
|
||||||
|
entries = append(entries, watchEntry.path)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -361,7 +203,7 @@ const (
|
|||||||
sysFSIGNORED = 0x8000
|
sysFSIGNORED = 0x8000
|
||||||
)
|
)
|
||||||
|
|
||||||
func (w *Watcher) newEvent(name string, mask uint32) Event {
|
func (w *readDirChangesW) newEvent(name string, mask uint32) Event {
|
||||||
e := Event{Name: name}
|
e := Event{Name: name}
|
||||||
if mask&sysFSCREATE == sysFSCREATE || mask&sysFSMOVEDTO == sysFSMOVEDTO {
|
if mask&sysFSCREATE == sysFSCREATE || mask&sysFSMOVEDTO == sysFSMOVEDTO {
|
||||||
e.Op |= Create
|
e.Op |= Create
|
||||||
@@ -417,7 +259,7 @@ type (
|
|||||||
watchMap map[uint32]indexMap
|
watchMap map[uint32]indexMap
|
||||||
)
|
)
|
||||||
|
|
||||||
func (w *Watcher) wakeupReader() error {
|
func (w *readDirChangesW) wakeupReader() error {
|
||||||
err := windows.PostQueuedCompletionStatus(w.port, 0, 0, nil)
|
err := windows.PostQueuedCompletionStatus(w.port, 0, 0, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return os.NewSyscallError("PostQueuedCompletionStatus", err)
|
return os.NewSyscallError("PostQueuedCompletionStatus", err)
|
||||||
@@ -425,7 +267,7 @@ func (w *Watcher) wakeupReader() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Watcher) getDir(pathname string) (dir string, err error) {
|
func (w *readDirChangesW) getDir(pathname string) (dir string, err error) {
|
||||||
attr, err := windows.GetFileAttributes(windows.StringToUTF16Ptr(pathname))
|
attr, err := windows.GetFileAttributes(windows.StringToUTF16Ptr(pathname))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", os.NewSyscallError("GetFileAttributes", err)
|
return "", os.NewSyscallError("GetFileAttributes", err)
|
||||||
@@ -439,7 +281,7 @@ func (w *Watcher) getDir(pathname string) (dir string, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Watcher) getIno(path string) (ino *inode, err error) {
|
func (w *readDirChangesW) getIno(path string) (ino *inode, err error) {
|
||||||
h, err := windows.CreateFile(windows.StringToUTF16Ptr(path),
|
h, err := windows.CreateFile(windows.StringToUTF16Ptr(path),
|
||||||
windows.FILE_LIST_DIRECTORY,
|
windows.FILE_LIST_DIRECTORY,
|
||||||
windows.FILE_SHARE_READ|windows.FILE_SHARE_WRITE|windows.FILE_SHARE_DELETE,
|
windows.FILE_SHARE_READ|windows.FILE_SHARE_WRITE|windows.FILE_SHARE_DELETE,
|
||||||
@@ -482,9 +324,8 @@ func (m watchMap) set(ino *inode, watch *watch) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Must run within the I/O thread.
|
// Must run within the I/O thread.
|
||||||
func (w *Watcher) addWatch(pathname string, flags uint64, bufsize int) error {
|
func (w *readDirChangesW) addWatch(pathname string, flags uint64, bufsize int) error {
|
||||||
//pathname, recurse := recursivePath(pathname)
|
pathname, recurse := recursivePath(pathname)
|
||||||
recurse := false
|
|
||||||
|
|
||||||
dir, err := w.getDir(pathname)
|
dir, err := w.getDir(pathname)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -538,7 +379,7 @@ func (w *Watcher) addWatch(pathname string, flags uint64, bufsize int) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Must run within the I/O thread.
|
// Must run within the I/O thread.
|
||||||
func (w *Watcher) remWatch(pathname string) error {
|
func (w *readDirChangesW) remWatch(pathname string) error {
|
||||||
pathname, recurse := recursivePath(pathname)
|
pathname, recurse := recursivePath(pathname)
|
||||||
|
|
||||||
dir, err := w.getDir(pathname)
|
dir, err := w.getDir(pathname)
|
||||||
@@ -566,11 +407,11 @@ func (w *Watcher) remWatch(pathname string) error {
|
|||||||
return fmt.Errorf("%w: %s", ErrNonExistentWatch, pathname)
|
return fmt.Errorf("%w: %s", ErrNonExistentWatch, pathname)
|
||||||
}
|
}
|
||||||
if pathname == dir {
|
if pathname == dir {
|
||||||
w.sendEvent(watch.path, watch.mask&sysFSIGNORED)
|
w.sendEvent(watch.path, "", watch.mask&sysFSIGNORED)
|
||||||
watch.mask = 0
|
watch.mask = 0
|
||||||
} else {
|
} else {
|
||||||
name := filepath.Base(pathname)
|
name := filepath.Base(pathname)
|
||||||
w.sendEvent(filepath.Join(watch.path, name), watch.names[name]&sysFSIGNORED)
|
w.sendEvent(filepath.Join(watch.path, name), "", watch.names[name]&sysFSIGNORED)
|
||||||
delete(watch.names, name)
|
delete(watch.names, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -578,23 +419,23 @@ func (w *Watcher) remWatch(pathname string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Must run within the I/O thread.
|
// Must run within the I/O thread.
|
||||||
func (w *Watcher) deleteWatch(watch *watch) {
|
func (w *readDirChangesW) deleteWatch(watch *watch) {
|
||||||
for name, mask := range watch.names {
|
for name, mask := range watch.names {
|
||||||
if mask&provisional == 0 {
|
if mask&provisional == 0 {
|
||||||
w.sendEvent(filepath.Join(watch.path, name), mask&sysFSIGNORED)
|
w.sendEvent(filepath.Join(watch.path, name), "", mask&sysFSIGNORED)
|
||||||
}
|
}
|
||||||
delete(watch.names, name)
|
delete(watch.names, name)
|
||||||
}
|
}
|
||||||
if watch.mask != 0 {
|
if watch.mask != 0 {
|
||||||
if watch.mask&provisional == 0 {
|
if watch.mask&provisional == 0 {
|
||||||
w.sendEvent(watch.path, watch.mask&sysFSIGNORED)
|
w.sendEvent(watch.path, "", watch.mask&sysFSIGNORED)
|
||||||
}
|
}
|
||||||
watch.mask = 0
|
watch.mask = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Must run within the I/O thread.
|
// Must run within the I/O thread.
|
||||||
func (w *Watcher) startRead(watch *watch) error {
|
func (w *readDirChangesW) startRead(watch *watch) error {
|
||||||
err := windows.CancelIo(watch.ino.handle)
|
err := windows.CancelIo(watch.ino.handle)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.sendError(os.NewSyscallError("CancelIo", err))
|
w.sendError(os.NewSyscallError("CancelIo", err))
|
||||||
@@ -624,7 +465,7 @@ func (w *Watcher) startRead(watch *watch) error {
|
|||||||
err := os.NewSyscallError("ReadDirectoryChanges", rdErr)
|
err := os.NewSyscallError("ReadDirectoryChanges", rdErr)
|
||||||
if rdErr == windows.ERROR_ACCESS_DENIED && watch.mask&provisional == 0 {
|
if rdErr == windows.ERROR_ACCESS_DENIED && watch.mask&provisional == 0 {
|
||||||
// Watched directory was probably removed
|
// Watched directory was probably removed
|
||||||
w.sendEvent(watch.path, watch.mask&sysFSDELETESELF)
|
w.sendEvent(watch.path, "", watch.mask&sysFSDELETESELF)
|
||||||
err = nil
|
err = nil
|
||||||
}
|
}
|
||||||
w.deleteWatch(watch)
|
w.deleteWatch(watch)
|
||||||
@@ -637,7 +478,7 @@ func (w *Watcher) startRead(watch *watch) error {
|
|||||||
// readEvents reads from the I/O completion port, converts the
|
// readEvents reads from the I/O completion port, converts the
|
||||||
// received events into Event objects and sends them via the Events channel.
|
// received events into Event objects and sends them via the Events channel.
|
||||||
// Entry point to the I/O thread.
|
// Entry point to the I/O thread.
|
||||||
func (w *Watcher) readEvents() {
|
func (w *readDirChangesW) readEvents() {
|
||||||
var (
|
var (
|
||||||
n uint32
|
n uint32
|
||||||
key uintptr
|
key uintptr
|
||||||
@@ -652,7 +493,7 @@ func (w *Watcher) readEvents() {
|
|||||||
watch := (*watch)(unsafe.Pointer(ov))
|
watch := (*watch)(unsafe.Pointer(ov))
|
||||||
if watch == nil {
|
if watch == nil {
|
||||||
select {
|
select {
|
||||||
case ch := <-w.quit:
|
case ch := <-w.done:
|
||||||
w.mu.Lock()
|
w.mu.Lock()
|
||||||
var indexes []indexMap
|
var indexes []indexMap
|
||||||
for _, index := range w.watches {
|
for _, index := range w.watches {
|
||||||
@@ -700,7 +541,7 @@ func (w *Watcher) readEvents() {
|
|||||||
}
|
}
|
||||||
case windows.ERROR_ACCESS_DENIED:
|
case windows.ERROR_ACCESS_DENIED:
|
||||||
// Watched directory was probably removed
|
// Watched directory was probably removed
|
||||||
w.sendEvent(watch.path, watch.mask&sysFSDELETESELF)
|
w.sendEvent(watch.path, "", watch.mask&sysFSDELETESELF)
|
||||||
w.deleteWatch(watch)
|
w.deleteWatch(watch)
|
||||||
w.startRead(watch)
|
w.startRead(watch)
|
||||||
continue
|
continue
|
||||||
@@ -733,6 +574,10 @@ func (w *Watcher) readEvents() {
|
|||||||
name := windows.UTF16ToString(buf)
|
name := windows.UTF16ToString(buf)
|
||||||
fullname := filepath.Join(watch.path, name)
|
fullname := filepath.Join(watch.path, name)
|
||||||
|
|
||||||
|
if debug {
|
||||||
|
internal.Debug(fullname, raw.Action)
|
||||||
|
}
|
||||||
|
|
||||||
var mask uint64
|
var mask uint64
|
||||||
switch raw.Action {
|
switch raw.Action {
|
||||||
case windows.FILE_ACTION_REMOVED:
|
case windows.FILE_ACTION_REMOVED:
|
||||||
@@ -761,21 +606,22 @@ func (w *Watcher) readEvents() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sendNameEvent := func() {
|
|
||||||
w.sendEvent(fullname, watch.names[name]&mask)
|
|
||||||
}
|
|
||||||
if raw.Action != windows.FILE_ACTION_RENAMED_NEW_NAME {
|
if raw.Action != windows.FILE_ACTION_RENAMED_NEW_NAME {
|
||||||
sendNameEvent()
|
w.sendEvent(fullname, "", watch.names[name]&mask)
|
||||||
}
|
}
|
||||||
if raw.Action == windows.FILE_ACTION_REMOVED {
|
if raw.Action == windows.FILE_ACTION_REMOVED {
|
||||||
w.sendEvent(fullname, watch.names[name]&sysFSIGNORED)
|
w.sendEvent(fullname, "", watch.names[name]&sysFSIGNORED)
|
||||||
delete(watch.names, name)
|
delete(watch.names, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
w.sendEvent(fullname, watch.mask&w.toFSnotifyFlags(raw.Action))
|
if watch.rename != "" && raw.Action == windows.FILE_ACTION_RENAMED_NEW_NAME {
|
||||||
|
w.sendEvent(fullname, filepath.Join(watch.path, watch.rename), watch.mask&w.toFSnotifyFlags(raw.Action))
|
||||||
|
} else {
|
||||||
|
w.sendEvent(fullname, "", watch.mask&w.toFSnotifyFlags(raw.Action))
|
||||||
|
}
|
||||||
|
|
||||||
if raw.Action == windows.FILE_ACTION_RENAMED_NEW_NAME {
|
if raw.Action == windows.FILE_ACTION_RENAMED_NEW_NAME {
|
||||||
fullname = filepath.Join(watch.path, watch.rename)
|
w.sendEvent(filepath.Join(watch.path, watch.rename), "", watch.names[name]&mask)
|
||||||
sendNameEvent()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move to the next event in the buffer
|
// Move to the next event in the buffer
|
||||||
@@ -787,8 +633,7 @@ func (w *Watcher) readEvents() {
|
|||||||
// Error!
|
// Error!
|
||||||
if offset >= n {
|
if offset >= n {
|
||||||
//lint:ignore ST1005 Windows should be capitalized
|
//lint:ignore ST1005 Windows should be capitalized
|
||||||
w.sendError(errors.New(
|
w.sendError(errors.New("Windows system assumed buffer larger than it is, events have likely been missed"))
|
||||||
"Windows system assumed buffer larger than it is, events have likely been missed"))
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -799,7 +644,7 @@ func (w *Watcher) readEvents() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Watcher) toWindowsFlags(mask uint64) uint32 {
|
func (w *readDirChangesW) toWindowsFlags(mask uint64) uint32 {
|
||||||
var m uint32
|
var m uint32
|
||||||
if mask&sysFSMODIFY != 0 {
|
if mask&sysFSMODIFY != 0 {
|
||||||
m |= windows.FILE_NOTIFY_CHANGE_LAST_WRITE
|
m |= windows.FILE_NOTIFY_CHANGE_LAST_WRITE
|
||||||
@@ -810,7 +655,7 @@ func (w *Watcher) toWindowsFlags(mask uint64) uint32 {
|
|||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Watcher) toFSnotifyFlags(action uint32) uint64 {
|
func (w *readDirChangesW) toFSnotifyFlags(action uint32) uint64 {
|
||||||
switch action {
|
switch action {
|
||||||
case windows.FILE_ACTION_ADDED:
|
case windows.FILE_ACTION_ADDED:
|
||||||
return sysFSCREATE
|
return sysFSCREATE
|
||||||
@@ -825,3 +670,11 @@ func (w *Watcher) toFSnotifyFlags(action uint32) uint64 {
|
|||||||
}
|
}
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w *readDirChangesW) xSupports(op Op) bool {
|
||||||
|
if op.Has(xUnportableOpen) || op.Has(xUnportableRead) ||
|
||||||
|
op.Has(xUnportableCloseWrite) || op.Has(xUnportableCloseRead) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|||||||
370
vendor/github.com/fsnotify/fsnotify/fsnotify.go
generated
vendored
370
vendor/github.com/fsnotify/fsnotify/fsnotify.go
generated
vendored
@@ -3,19 +3,146 @@
|
|||||||
//
|
//
|
||||||
// Currently supported systems:
|
// Currently supported systems:
|
||||||
//
|
//
|
||||||
// Linux 2.6.32+ via inotify
|
// - Linux via inotify
|
||||||
// BSD, macOS via kqueue
|
// - BSD, macOS via kqueue
|
||||||
// Windows via ReadDirectoryChangesW
|
// - Windows via ReadDirectoryChangesW
|
||||||
// illumos via FEN
|
// - illumos via FEN
|
||||||
|
//
|
||||||
|
// # FSNOTIFY_DEBUG
|
||||||
|
//
|
||||||
|
// Set the FSNOTIFY_DEBUG environment variable to "1" to print debug messages to
|
||||||
|
// stderr. This can be useful to track down some problems, especially in cases
|
||||||
|
// where fsnotify is used as an indirect dependency.
|
||||||
|
//
|
||||||
|
// Every event will be printed as soon as there's something useful to print,
|
||||||
|
// with as little processing from fsnotify.
|
||||||
|
//
|
||||||
|
// Example output:
|
||||||
|
//
|
||||||
|
// FSNOTIFY_DEBUG: 11:34:23.633087586 256:IN_CREATE → "/tmp/file-1"
|
||||||
|
// FSNOTIFY_DEBUG: 11:34:23.633202319 4:IN_ATTRIB → "/tmp/file-1"
|
||||||
|
// FSNOTIFY_DEBUG: 11:34:28.989728764 512:IN_DELETE → "/tmp/file-1"
|
||||||
package fsnotify
|
package fsnotify
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Watcher watches a set of paths, delivering events on a channel.
|
||||||
|
//
|
||||||
|
// A watcher should not be copied (e.g. pass it by pointer, rather than by
|
||||||
|
// value).
|
||||||
|
//
|
||||||
|
// # Linux notes
|
||||||
|
//
|
||||||
|
// When a file is removed a Remove event won't be emitted until all file
|
||||||
|
// descriptors are closed, and deletes will always emit a Chmod. For example:
|
||||||
|
//
|
||||||
|
// fp := os.Open("file")
|
||||||
|
// os.Remove("file") // Triggers Chmod
|
||||||
|
// fp.Close() // Triggers Remove
|
||||||
|
//
|
||||||
|
// This is the event that inotify sends, so not much can be changed about this.
|
||||||
|
//
|
||||||
|
// The fs.inotify.max_user_watches sysctl variable specifies the upper limit
|
||||||
|
// for the number of watches per user, and fs.inotify.max_user_instances
|
||||||
|
// specifies the maximum number of inotify instances per user. Every Watcher you
|
||||||
|
// create is an "instance", and every path you add is a "watch".
|
||||||
|
//
|
||||||
|
// These are also exposed in /proc as /proc/sys/fs/inotify/max_user_watches and
|
||||||
|
// /proc/sys/fs/inotify/max_user_instances
|
||||||
|
//
|
||||||
|
// To increase them you can use sysctl or write the value to the /proc file:
|
||||||
|
//
|
||||||
|
// # Default values on Linux 5.18
|
||||||
|
// sysctl fs.inotify.max_user_watches=124983
|
||||||
|
// sysctl fs.inotify.max_user_instances=128
|
||||||
|
//
|
||||||
|
// To make the changes persist on reboot edit /etc/sysctl.conf or
|
||||||
|
// /usr/lib/sysctl.d/50-default.conf (details differ per Linux distro; check
|
||||||
|
// your distro's documentation):
|
||||||
|
//
|
||||||
|
// fs.inotify.max_user_watches=124983
|
||||||
|
// fs.inotify.max_user_instances=128
|
||||||
|
//
|
||||||
|
// Reaching the limit will result in a "no space left on device" or "too many open
|
||||||
|
// files" error.
|
||||||
|
//
|
||||||
|
// # kqueue notes (macOS, BSD)
|
||||||
|
//
|
||||||
|
// kqueue requires opening a file descriptor for every file that's being watched;
|
||||||
|
// so if you're watching a directory with five files then that's six file
|
||||||
|
// descriptors. You will run in to your system's "max open files" limit faster on
|
||||||
|
// these platforms.
|
||||||
|
//
|
||||||
|
// The sysctl variables kern.maxfiles and kern.maxfilesperproc can be used to
|
||||||
|
// control the maximum number of open files, as well as /etc/login.conf on BSD
|
||||||
|
// systems.
|
||||||
|
//
|
||||||
|
// # Windows notes
|
||||||
|
//
|
||||||
|
// Paths can be added as "C:\\path\\to\\dir", but forward slashes
|
||||||
|
// ("C:/path/to/dir") will also work.
|
||||||
|
//
|
||||||
|
// When a watched directory is removed it will always send an event for the
|
||||||
|
// directory itself, but may not send events for all files in that directory.
|
||||||
|
// Sometimes it will send events for all files, sometimes it will send no
|
||||||
|
// events, and often only for some files.
|
||||||
|
//
|
||||||
|
// The default ReadDirectoryChangesW() buffer size is 64K, which is the largest
|
||||||
|
// value that is guaranteed to work with SMB filesystems. If you have many
|
||||||
|
// events in quick succession this may not be enough, and you will have to use
|
||||||
|
// [WithBufferSize] to increase the value.
|
||||||
|
type Watcher struct {
|
||||||
|
b backend
|
||||||
|
|
||||||
|
// Events sends the filesystem change events.
|
||||||
|
//
|
||||||
|
// fsnotify can send the following events; a "path" here can refer to a
|
||||||
|
// file, directory, symbolic link, or special file like a FIFO.
|
||||||
|
//
|
||||||
|
// fsnotify.Create A new path was created; this may be followed by one
|
||||||
|
// or more Write events if data also gets written to a
|
||||||
|
// file.
|
||||||
|
//
|
||||||
|
// fsnotify.Remove A path was removed.
|
||||||
|
//
|
||||||
|
// fsnotify.Rename A path was renamed. A rename is always sent with the
|
||||||
|
// old path as Event.Name, and a Create event will be
|
||||||
|
// sent with the new name. Renames are only sent for
|
||||||
|
// paths that are currently watched; e.g. moving an
|
||||||
|
// unmonitored file into a monitored directory will
|
||||||
|
// show up as just a Create. Similarly, renaming a file
|
||||||
|
// to outside a monitored directory will show up as
|
||||||
|
// only a Rename.
|
||||||
|
//
|
||||||
|
// fsnotify.Write A file or named pipe was written to. A Truncate will
|
||||||
|
// also trigger a Write. A single "write action"
|
||||||
|
// initiated by the user may show up as one or multiple
|
||||||
|
// writes, depending on when the system syncs things to
|
||||||
|
// disk. For example when compiling a large Go program
|
||||||
|
// you may get hundreds of Write events, and you may
|
||||||
|
// want to wait until you've stopped receiving them
|
||||||
|
// (see the dedup example in cmd/fsnotify).
|
||||||
|
//
|
||||||
|
// Some systems may send Write event for directories
|
||||||
|
// when the directory content changes.
|
||||||
|
//
|
||||||
|
// fsnotify.Chmod Attributes were changed. On Linux this is also sent
|
||||||
|
// when a file is removed (or more accurately, when a
|
||||||
|
// link to an inode is removed). On kqueue it's sent
|
||||||
|
// when a file is truncated. On Windows it's never
|
||||||
|
// sent.
|
||||||
|
Events chan Event
|
||||||
|
|
||||||
|
// Errors sends any errors.
|
||||||
|
Errors chan error
|
||||||
|
}
|
||||||
|
|
||||||
// Event represents a file system notification.
|
// Event represents a file system notification.
|
||||||
type Event struct {
|
type Event struct {
|
||||||
// Path to the file or directory.
|
// Path to the file or directory.
|
||||||
@@ -30,6 +157,16 @@ type Event struct {
|
|||||||
// This is a bitmask and some systems may send multiple operations at once.
|
// This is a bitmask and some systems may send multiple operations at once.
|
||||||
// Use the Event.Has() method instead of comparing with ==.
|
// Use the Event.Has() method instead of comparing with ==.
|
||||||
Op Op
|
Op Op
|
||||||
|
|
||||||
|
// Create events will have this set to the old path if it's a rename. This
|
||||||
|
// only works when both the source and destination are watched. It's not
|
||||||
|
// reliable when watching individual files, only directories.
|
||||||
|
//
|
||||||
|
// For example "mv /tmp/file /tmp/rename" will emit:
|
||||||
|
//
|
||||||
|
// Event{Op: Rename, Name: "/tmp/file"}
|
||||||
|
// Event{Op: Create, Name: "/tmp/rename", RenamedFrom: "/tmp/file"}
|
||||||
|
renamedFrom string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Op describes a set of file operations.
|
// Op describes a set of file operations.
|
||||||
@@ -50,7 +187,7 @@ const (
|
|||||||
// example "remove to trash" is often a rename).
|
// example "remove to trash" is often a rename).
|
||||||
Remove
|
Remove
|
||||||
|
|
||||||
// The path was renamed to something else; any watched on it will be
|
// The path was renamed to something else; any watches on it will be
|
||||||
// removed.
|
// removed.
|
||||||
Rename
|
Rename
|
||||||
|
|
||||||
@@ -60,15 +197,157 @@ const (
|
|||||||
// get triggered very frequently by some software. For example, Spotlight
|
// get triggered very frequently by some software. For example, Spotlight
|
||||||
// indexing on macOS, anti-virus software, backup software, etc.
|
// indexing on macOS, anti-virus software, backup software, etc.
|
||||||
Chmod
|
Chmod
|
||||||
|
|
||||||
|
// File descriptor was opened.
|
||||||
|
//
|
||||||
|
// Only works on Linux and FreeBSD.
|
||||||
|
xUnportableOpen
|
||||||
|
|
||||||
|
// File was read from.
|
||||||
|
//
|
||||||
|
// Only works on Linux and FreeBSD.
|
||||||
|
xUnportableRead
|
||||||
|
|
||||||
|
// File opened for writing was closed.
|
||||||
|
//
|
||||||
|
// Only works on Linux and FreeBSD.
|
||||||
|
//
|
||||||
|
// The advantage of using this over Write is that it's more reliable than
|
||||||
|
// waiting for Write events to stop. It's also faster (if you're not
|
||||||
|
// listening to Write events): copying a file of a few GB can easily
|
||||||
|
// generate tens of thousands of Write events in a short span of time.
|
||||||
|
xUnportableCloseWrite
|
||||||
|
|
||||||
|
// File opened for reading was closed.
|
||||||
|
//
|
||||||
|
// Only works on Linux and FreeBSD.
|
||||||
|
xUnportableCloseRead
|
||||||
)
|
)
|
||||||
|
|
||||||
// Common errors that can be reported.
|
|
||||||
var (
|
var (
|
||||||
|
// ErrNonExistentWatch is used when Remove() is called on a path that's not
|
||||||
|
// added.
|
||||||
ErrNonExistentWatch = errors.New("fsnotify: can't remove non-existent watch")
|
ErrNonExistentWatch = errors.New("fsnotify: can't remove non-existent watch")
|
||||||
ErrEventOverflow = errors.New("fsnotify: queue or buffer overflow")
|
|
||||||
ErrClosed = errors.New("fsnotify: watcher already closed")
|
// ErrClosed is used when trying to operate on a closed Watcher.
|
||||||
|
ErrClosed = errors.New("fsnotify: watcher already closed")
|
||||||
|
|
||||||
|
// ErrEventOverflow is reported from the Errors channel when there are too
|
||||||
|
// many events:
|
||||||
|
//
|
||||||
|
// - inotify: inotify returns IN_Q_OVERFLOW – because there are too
|
||||||
|
// many queued events (the fs.inotify.max_queued_events
|
||||||
|
// sysctl can be used to increase this).
|
||||||
|
// - windows: The buffer size is too small; WithBufferSize() can be used to increase it.
|
||||||
|
// - kqueue, fen: Not used.
|
||||||
|
ErrEventOverflow = errors.New("fsnotify: queue or buffer overflow")
|
||||||
|
|
||||||
|
// ErrUnsupported is returned by AddWith() when WithOps() specified an
|
||||||
|
// Unportable event that's not supported on this platform.
|
||||||
|
//lint:ignore ST1012 not relevant
|
||||||
|
xErrUnsupported = errors.New("fsnotify: not supported with this backend")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// NewWatcher creates a new Watcher.
|
||||||
|
func NewWatcher() (*Watcher, error) {
|
||||||
|
ev, errs := make(chan Event, defaultBufferSize), make(chan error)
|
||||||
|
b, err := newBackend(ev, errs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &Watcher{b: b, Events: ev, Errors: errs}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewBufferedWatcher creates a new Watcher with a buffered Watcher.Events
|
||||||
|
// channel.
|
||||||
|
//
|
||||||
|
// The main use case for this is situations with a very large number of events
|
||||||
|
// where the kernel buffer size can't be increased (e.g. due to lack of
|
||||||
|
// permissions). An unbuffered Watcher will perform better for almost all use
|
||||||
|
// cases, and whenever possible you will be better off increasing the kernel
|
||||||
|
// buffers instead of adding a large userspace buffer.
|
||||||
|
func NewBufferedWatcher(sz uint) (*Watcher, error) {
|
||||||
|
ev, errs := make(chan Event, sz), make(chan error)
|
||||||
|
b, err := newBackend(ev, errs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &Watcher{b: b, Events: ev, Errors: errs}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add starts monitoring the path for changes.
|
||||||
|
//
|
||||||
|
// A path can only be watched once; watching it more than once is a no-op and will
|
||||||
|
// not return an error. Paths that do not yet exist on the filesystem cannot be
|
||||||
|
// watched.
|
||||||
|
//
|
||||||
|
// A watch will be automatically removed if the watched path is deleted or
|
||||||
|
// renamed. The exception is the Windows backend, which doesn't remove the
|
||||||
|
// watcher on renames.
|
||||||
|
//
|
||||||
|
// Notifications on network filesystems (NFS, SMB, FUSE, etc.) or special
|
||||||
|
// filesystems (/proc, /sys, etc.) generally don't work.
|
||||||
|
//
|
||||||
|
// Returns [ErrClosed] if [Watcher.Close] was called.
|
||||||
|
//
|
||||||
|
// See [Watcher.AddWith] for a version that allows adding options.
|
||||||
|
//
|
||||||
|
// # Watching directories
|
||||||
|
//
|
||||||
|
// All files in a directory are monitored, including new files that are created
|
||||||
|
// after the watcher is started. Subdirectories are not watched (i.e. it's
|
||||||
|
// non-recursive).
|
||||||
|
//
|
||||||
|
// # Watching files
|
||||||
|
//
|
||||||
|
// Watching individual files (rather than directories) is generally not
|
||||||
|
// recommended as many programs (especially editors) update files atomically: it
|
||||||
|
// will write to a temporary file which is then moved to destination,
|
||||||
|
// overwriting the original (or some variant thereof). The watcher on the
|
||||||
|
// original file is now lost, as that no longer exists.
|
||||||
|
//
|
||||||
|
// The upshot of this is that a power failure or crash won't leave a
|
||||||
|
// half-written file.
|
||||||
|
//
|
||||||
|
// Watch the parent directory and use Event.Name to filter out files you're not
|
||||||
|
// interested in. There is an example of this in cmd/fsnotify/file.go.
|
||||||
|
func (w *Watcher) Add(path string) error { return w.b.Add(path) }
|
||||||
|
|
||||||
|
// AddWith is like [Watcher.Add], but allows adding options. When using Add()
|
||||||
|
// the defaults described below are used.
|
||||||
|
//
|
||||||
|
// Possible options are:
|
||||||
|
//
|
||||||
|
// - [WithBufferSize] sets the buffer size for the Windows backend; no-op on
|
||||||
|
// other platforms. The default is 64K (65536 bytes).
|
||||||
|
func (w *Watcher) AddWith(path string, opts ...addOpt) error { return w.b.AddWith(path, opts...) }
|
||||||
|
|
||||||
|
// Remove stops monitoring the path for changes.
|
||||||
|
//
|
||||||
|
// Directories are always removed non-recursively. For example, if you added
|
||||||
|
// /tmp/dir and /tmp/dir/subdir then you will need to remove both.
|
||||||
|
//
|
||||||
|
// Removing a path that has not yet been added returns [ErrNonExistentWatch].
|
||||||
|
//
|
||||||
|
// Returns nil if [Watcher.Close] was called.
|
||||||
|
func (w *Watcher) Remove(path string) error { return w.b.Remove(path) }
|
||||||
|
|
||||||
|
// Close removes all watches and closes the Events channel.
|
||||||
|
func (w *Watcher) Close() error { return w.b.Close() }
|
||||||
|
|
||||||
|
// WatchList returns all paths explicitly added with [Watcher.Add] (and are not
|
||||||
|
// yet removed).
|
||||||
|
//
|
||||||
|
// The order is undefined, and may differ per call. Returns nil if
|
||||||
|
// [Watcher.Close] was called.
|
||||||
|
func (w *Watcher) WatchList() []string { return w.b.WatchList() }
|
||||||
|
|
||||||
|
// Supports reports if all the listed operations are supported by this platform.
|
||||||
|
//
|
||||||
|
// Create, Write, Remove, Rename, and Chmod are always supported. It can only
|
||||||
|
// return false for an Op starting with Unportable.
|
||||||
|
func (w *Watcher) xSupports(op Op) bool { return w.b.xSupports(op) }
|
||||||
|
|
||||||
func (o Op) String() string {
|
func (o Op) String() string {
|
||||||
var b strings.Builder
|
var b strings.Builder
|
||||||
if o.Has(Create) {
|
if o.Has(Create) {
|
||||||
@@ -80,6 +359,18 @@ func (o Op) String() string {
|
|||||||
if o.Has(Write) {
|
if o.Has(Write) {
|
||||||
b.WriteString("|WRITE")
|
b.WriteString("|WRITE")
|
||||||
}
|
}
|
||||||
|
if o.Has(xUnportableOpen) {
|
||||||
|
b.WriteString("|OPEN")
|
||||||
|
}
|
||||||
|
if o.Has(xUnportableRead) {
|
||||||
|
b.WriteString("|READ")
|
||||||
|
}
|
||||||
|
if o.Has(xUnportableCloseWrite) {
|
||||||
|
b.WriteString("|CLOSE_WRITE")
|
||||||
|
}
|
||||||
|
if o.Has(xUnportableCloseRead) {
|
||||||
|
b.WriteString("|CLOSE_READ")
|
||||||
|
}
|
||||||
if o.Has(Rename) {
|
if o.Has(Rename) {
|
||||||
b.WriteString("|RENAME")
|
b.WriteString("|RENAME")
|
||||||
}
|
}
|
||||||
@@ -100,24 +391,48 @@ func (e Event) Has(op Op) bool { return e.Op.Has(op) }
|
|||||||
|
|
||||||
// String returns a string representation of the event with their path.
|
// String returns a string representation of the event with their path.
|
||||||
func (e Event) String() string {
|
func (e Event) String() string {
|
||||||
|
if e.renamedFrom != "" {
|
||||||
|
return fmt.Sprintf("%-13s %q ← %q", e.Op.String(), e.Name, e.renamedFrom)
|
||||||
|
}
|
||||||
return fmt.Sprintf("%-13s %q", e.Op.String(), e.Name)
|
return fmt.Sprintf("%-13s %q", e.Op.String(), e.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
type (
|
type (
|
||||||
|
backend interface {
|
||||||
|
Add(string) error
|
||||||
|
AddWith(string, ...addOpt) error
|
||||||
|
Remove(string) error
|
||||||
|
WatchList() []string
|
||||||
|
Close() error
|
||||||
|
xSupports(Op) bool
|
||||||
|
}
|
||||||
addOpt func(opt *withOpts)
|
addOpt func(opt *withOpts)
|
||||||
withOpts struct {
|
withOpts struct {
|
||||||
bufsize int
|
bufsize int
|
||||||
|
op Op
|
||||||
|
noFollow bool
|
||||||
|
sendCreate bool
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var debug = func() bool {
|
||||||
|
// Check for exactly "1" (rather than mere existence) so we can add
|
||||||
|
// options/flags in the future. I don't know if we ever want that, but it's
|
||||||
|
// nice to leave the option open.
|
||||||
|
return os.Getenv("FSNOTIFY_DEBUG") == "1"
|
||||||
|
}()
|
||||||
|
|
||||||
var defaultOpts = withOpts{
|
var defaultOpts = withOpts{
|
||||||
bufsize: 65536, // 64K
|
bufsize: 65536, // 64K
|
||||||
|
op: Create | Write | Remove | Rename | Chmod,
|
||||||
}
|
}
|
||||||
|
|
||||||
func getOptions(opts ...addOpt) withOpts {
|
func getOptions(opts ...addOpt) withOpts {
|
||||||
with := defaultOpts
|
with := defaultOpts
|
||||||
for _, o := range opts {
|
for _, o := range opts {
|
||||||
o(&with)
|
if o != nil {
|
||||||
|
o(&with)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return with
|
return with
|
||||||
}
|
}
|
||||||
@@ -136,9 +451,44 @@ func WithBufferSize(bytes int) addOpt {
|
|||||||
return func(opt *withOpts) { opt.bufsize = bytes }
|
return func(opt *withOpts) { opt.bufsize = bytes }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithOps sets which operations to listen for. The default is [Create],
|
||||||
|
// [Write], [Remove], [Rename], and [Chmod].
|
||||||
|
//
|
||||||
|
// Excluding operations you're not interested in can save quite a bit of CPU
|
||||||
|
// time; in some use cases there may be hundreds of thousands of useless Write
|
||||||
|
// or Chmod operations per second.
|
||||||
|
//
|
||||||
|
// This can also be used to add unportable operations not supported by all
|
||||||
|
// platforms; unportable operations all start with "Unportable":
|
||||||
|
// [UnportableOpen], [UnportableRead], [UnportableCloseWrite], and
|
||||||
|
// [UnportableCloseRead].
|
||||||
|
//
|
||||||
|
// AddWith returns an error when using an unportable operation that's not
|
||||||
|
// supported. Use [Watcher.Support] to check for support.
|
||||||
|
func withOps(op Op) addOpt {
|
||||||
|
return func(opt *withOpts) { opt.op = op }
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithNoFollow disables following symlinks, so the symlinks themselves are
|
||||||
|
// watched.
|
||||||
|
func withNoFollow() addOpt {
|
||||||
|
return func(opt *withOpts) { opt.noFollow = true }
|
||||||
|
}
|
||||||
|
|
||||||
|
// "Internal" option for recursive watches on inotify.
|
||||||
|
func withCreate() addOpt {
|
||||||
|
return func(opt *withOpts) { opt.sendCreate = true }
|
||||||
|
}
|
||||||
|
|
||||||
|
var enableRecurse = false
|
||||||
|
|
||||||
// Check if this path is recursive (ends with "/..." or "\..."), and return the
|
// Check if this path is recursive (ends with "/..." or "\..."), and return the
|
||||||
// path with the /... stripped.
|
// path with the /... stripped.
|
||||||
func recursivePath(path string) (string, bool) {
|
func recursivePath(path string) (string, bool) {
|
||||||
|
path = filepath.Clean(path)
|
||||||
|
if !enableRecurse { // Only enabled in tests for now.
|
||||||
|
return path, false
|
||||||
|
}
|
||||||
if filepath.Base(path) == "..." {
|
if filepath.Base(path) == "..." {
|
||||||
return filepath.Dir(path), true
|
return filepath.Dir(path), true
|
||||||
}
|
}
|
||||||
|
|||||||
39
vendor/github.com/fsnotify/fsnotify/internal/darwin.go
generated
vendored
Normal file
39
vendor/github.com/fsnotify/fsnotify/internal/darwin.go
generated
vendored
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
//go:build darwin
|
||||||
|
|
||||||
|
package internal
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrSyscallEACCES = syscall.EACCES
|
||||||
|
ErrUnixEACCES = unix.EACCES
|
||||||
|
)
|
||||||
|
|
||||||
|
var maxfiles uint64
|
||||||
|
|
||||||
|
func SetRlimit() {
|
||||||
|
// Go 1.19 will do this automatically: https://go-review.googlesource.com/c/go/+/393354/
|
||||||
|
var l syscall.Rlimit
|
||||||
|
err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &l)
|
||||||
|
if err == nil && l.Cur != l.Max {
|
||||||
|
l.Cur = l.Max
|
||||||
|
syscall.Setrlimit(syscall.RLIMIT_NOFILE, &l)
|
||||||
|
}
|
||||||
|
maxfiles = l.Cur
|
||||||
|
|
||||||
|
if n, err := syscall.SysctlUint32("kern.maxfiles"); err == nil && uint64(n) < maxfiles {
|
||||||
|
maxfiles = uint64(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if n, err := syscall.SysctlUint32("kern.maxfilesperproc"); err == nil && uint64(n) < maxfiles {
|
||||||
|
maxfiles = uint64(n)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Maxfiles() uint64 { return maxfiles }
|
||||||
|
func Mkfifo(path string, mode uint32) error { return unix.Mkfifo(path, mode) }
|
||||||
|
func Mknod(path string, mode uint32, dev int) error { return unix.Mknod(path, mode, dev) }
|
||||||
57
vendor/github.com/fsnotify/fsnotify/internal/debug_darwin.go
generated
vendored
Normal file
57
vendor/github.com/fsnotify/fsnotify/internal/debug_darwin.go
generated
vendored
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
package internal
|
||||||
|
|
||||||
|
import "golang.org/x/sys/unix"
|
||||||
|
|
||||||
|
var names = []struct {
|
||||||
|
n string
|
||||||
|
m uint32
|
||||||
|
}{
|
||||||
|
{"NOTE_ABSOLUTE", unix.NOTE_ABSOLUTE},
|
||||||
|
{"NOTE_ATTRIB", unix.NOTE_ATTRIB},
|
||||||
|
{"NOTE_BACKGROUND", unix.NOTE_BACKGROUND},
|
||||||
|
{"NOTE_CHILD", unix.NOTE_CHILD},
|
||||||
|
{"NOTE_CRITICAL", unix.NOTE_CRITICAL},
|
||||||
|
{"NOTE_DELETE", unix.NOTE_DELETE},
|
||||||
|
{"NOTE_EXEC", unix.NOTE_EXEC},
|
||||||
|
{"NOTE_EXIT", unix.NOTE_EXIT},
|
||||||
|
{"NOTE_EXITSTATUS", unix.NOTE_EXITSTATUS},
|
||||||
|
{"NOTE_EXIT_CSERROR", unix.NOTE_EXIT_CSERROR},
|
||||||
|
{"NOTE_EXIT_DECRYPTFAIL", unix.NOTE_EXIT_DECRYPTFAIL},
|
||||||
|
{"NOTE_EXIT_DETAIL", unix.NOTE_EXIT_DETAIL},
|
||||||
|
{"NOTE_EXIT_DETAIL_MASK", unix.NOTE_EXIT_DETAIL_MASK},
|
||||||
|
{"NOTE_EXIT_MEMORY", unix.NOTE_EXIT_MEMORY},
|
||||||
|
{"NOTE_EXIT_REPARENTED", unix.NOTE_EXIT_REPARENTED},
|
||||||
|
{"NOTE_EXTEND", unix.NOTE_EXTEND},
|
||||||
|
{"NOTE_FFAND", unix.NOTE_FFAND},
|
||||||
|
{"NOTE_FFCOPY", unix.NOTE_FFCOPY},
|
||||||
|
{"NOTE_FFCTRLMASK", unix.NOTE_FFCTRLMASK},
|
||||||
|
{"NOTE_FFLAGSMASK", unix.NOTE_FFLAGSMASK},
|
||||||
|
{"NOTE_FFNOP", unix.NOTE_FFNOP},
|
||||||
|
{"NOTE_FFOR", unix.NOTE_FFOR},
|
||||||
|
{"NOTE_FORK", unix.NOTE_FORK},
|
||||||
|
{"NOTE_FUNLOCK", unix.NOTE_FUNLOCK},
|
||||||
|
{"NOTE_LEEWAY", unix.NOTE_LEEWAY},
|
||||||
|
{"NOTE_LINK", unix.NOTE_LINK},
|
||||||
|
{"NOTE_LOWAT", unix.NOTE_LOWAT},
|
||||||
|
{"NOTE_MACHTIME", unix.NOTE_MACHTIME},
|
||||||
|
{"NOTE_MACH_CONTINUOUS_TIME", unix.NOTE_MACH_CONTINUOUS_TIME},
|
||||||
|
{"NOTE_NONE", unix.NOTE_NONE},
|
||||||
|
{"NOTE_NSECONDS", unix.NOTE_NSECONDS},
|
||||||
|
{"NOTE_OOB", unix.NOTE_OOB},
|
||||||
|
//{"NOTE_PCTRLMASK", unix.NOTE_PCTRLMASK}, -0x100000 (?!)
|
||||||
|
{"NOTE_PDATAMASK", unix.NOTE_PDATAMASK},
|
||||||
|
{"NOTE_REAP", unix.NOTE_REAP},
|
||||||
|
{"NOTE_RENAME", unix.NOTE_RENAME},
|
||||||
|
{"NOTE_REVOKE", unix.NOTE_REVOKE},
|
||||||
|
{"NOTE_SECONDS", unix.NOTE_SECONDS},
|
||||||
|
{"NOTE_SIGNAL", unix.NOTE_SIGNAL},
|
||||||
|
{"NOTE_TRACK", unix.NOTE_TRACK},
|
||||||
|
{"NOTE_TRACKERR", unix.NOTE_TRACKERR},
|
||||||
|
{"NOTE_TRIGGER", unix.NOTE_TRIGGER},
|
||||||
|
{"NOTE_USECONDS", unix.NOTE_USECONDS},
|
||||||
|
{"NOTE_VM_ERROR", unix.NOTE_VM_ERROR},
|
||||||
|
{"NOTE_VM_PRESSURE", unix.NOTE_VM_PRESSURE},
|
||||||
|
{"NOTE_VM_PRESSURE_SUDDEN_TERMINATE", unix.NOTE_VM_PRESSURE_SUDDEN_TERMINATE},
|
||||||
|
{"NOTE_VM_PRESSURE_TERMINATE", unix.NOTE_VM_PRESSURE_TERMINATE},
|
||||||
|
{"NOTE_WRITE", unix.NOTE_WRITE},
|
||||||
|
}
|
||||||
33
vendor/github.com/fsnotify/fsnotify/internal/debug_dragonfly.go
generated
vendored
Normal file
33
vendor/github.com/fsnotify/fsnotify/internal/debug_dragonfly.go
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
package internal
|
||||||
|
|
||||||
|
import "golang.org/x/sys/unix"
|
||||||
|
|
||||||
|
var names = []struct {
|
||||||
|
n string
|
||||||
|
m uint32
|
||||||
|
}{
|
||||||
|
{"NOTE_ATTRIB", unix.NOTE_ATTRIB},
|
||||||
|
{"NOTE_CHILD", unix.NOTE_CHILD},
|
||||||
|
{"NOTE_DELETE", unix.NOTE_DELETE},
|
||||||
|
{"NOTE_EXEC", unix.NOTE_EXEC},
|
||||||
|
{"NOTE_EXIT", unix.NOTE_EXIT},
|
||||||
|
{"NOTE_EXTEND", unix.NOTE_EXTEND},
|
||||||
|
{"NOTE_FFAND", unix.NOTE_FFAND},
|
||||||
|
{"NOTE_FFCOPY", unix.NOTE_FFCOPY},
|
||||||
|
{"NOTE_FFCTRLMASK", unix.NOTE_FFCTRLMASK},
|
||||||
|
{"NOTE_FFLAGSMASK", unix.NOTE_FFLAGSMASK},
|
||||||
|
{"NOTE_FFNOP", unix.NOTE_FFNOP},
|
||||||
|
{"NOTE_FFOR", unix.NOTE_FFOR},
|
||||||
|
{"NOTE_FORK", unix.NOTE_FORK},
|
||||||
|
{"NOTE_LINK", unix.NOTE_LINK},
|
||||||
|
{"NOTE_LOWAT", unix.NOTE_LOWAT},
|
||||||
|
{"NOTE_OOB", unix.NOTE_OOB},
|
||||||
|
{"NOTE_PCTRLMASK", unix.NOTE_PCTRLMASK},
|
||||||
|
{"NOTE_PDATAMASK", unix.NOTE_PDATAMASK},
|
||||||
|
{"NOTE_RENAME", unix.NOTE_RENAME},
|
||||||
|
{"NOTE_REVOKE", unix.NOTE_REVOKE},
|
||||||
|
{"NOTE_TRACK", unix.NOTE_TRACK},
|
||||||
|
{"NOTE_TRACKERR", unix.NOTE_TRACKERR},
|
||||||
|
{"NOTE_TRIGGER", unix.NOTE_TRIGGER},
|
||||||
|
{"NOTE_WRITE", unix.NOTE_WRITE},
|
||||||
|
}
|
||||||
42
vendor/github.com/fsnotify/fsnotify/internal/debug_freebsd.go
generated
vendored
Normal file
42
vendor/github.com/fsnotify/fsnotify/internal/debug_freebsd.go
generated
vendored
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
package internal
|
||||||
|
|
||||||
|
import "golang.org/x/sys/unix"
|
||||||
|
|
||||||
|
var names = []struct {
|
||||||
|
n string
|
||||||
|
m uint32
|
||||||
|
}{
|
||||||
|
{"NOTE_ABSTIME", unix.NOTE_ABSTIME},
|
||||||
|
{"NOTE_ATTRIB", unix.NOTE_ATTRIB},
|
||||||
|
{"NOTE_CHILD", unix.NOTE_CHILD},
|
||||||
|
{"NOTE_CLOSE", unix.NOTE_CLOSE},
|
||||||
|
{"NOTE_CLOSE_WRITE", unix.NOTE_CLOSE_WRITE},
|
||||||
|
{"NOTE_DELETE", unix.NOTE_DELETE},
|
||||||
|
{"NOTE_EXEC", unix.NOTE_EXEC},
|
||||||
|
{"NOTE_EXIT", unix.NOTE_EXIT},
|
||||||
|
{"NOTE_EXTEND", unix.NOTE_EXTEND},
|
||||||
|
{"NOTE_FFAND", unix.NOTE_FFAND},
|
||||||
|
{"NOTE_FFCOPY", unix.NOTE_FFCOPY},
|
||||||
|
{"NOTE_FFCTRLMASK", unix.NOTE_FFCTRLMASK},
|
||||||
|
{"NOTE_FFLAGSMASK", unix.NOTE_FFLAGSMASK},
|
||||||
|
{"NOTE_FFNOP", unix.NOTE_FFNOP},
|
||||||
|
{"NOTE_FFOR", unix.NOTE_FFOR},
|
||||||
|
{"NOTE_FILE_POLL", unix.NOTE_FILE_POLL},
|
||||||
|
{"NOTE_FORK", unix.NOTE_FORK},
|
||||||
|
{"NOTE_LINK", unix.NOTE_LINK},
|
||||||
|
{"NOTE_LOWAT", unix.NOTE_LOWAT},
|
||||||
|
{"NOTE_MSECONDS", unix.NOTE_MSECONDS},
|
||||||
|
{"NOTE_NSECONDS", unix.NOTE_NSECONDS},
|
||||||
|
{"NOTE_OPEN", unix.NOTE_OPEN},
|
||||||
|
{"NOTE_PCTRLMASK", unix.NOTE_PCTRLMASK},
|
||||||
|
{"NOTE_PDATAMASK", unix.NOTE_PDATAMASK},
|
||||||
|
{"NOTE_READ", unix.NOTE_READ},
|
||||||
|
{"NOTE_RENAME", unix.NOTE_RENAME},
|
||||||
|
{"NOTE_REVOKE", unix.NOTE_REVOKE},
|
||||||
|
{"NOTE_SECONDS", unix.NOTE_SECONDS},
|
||||||
|
{"NOTE_TRACK", unix.NOTE_TRACK},
|
||||||
|
{"NOTE_TRACKERR", unix.NOTE_TRACKERR},
|
||||||
|
{"NOTE_TRIGGER", unix.NOTE_TRIGGER},
|
||||||
|
{"NOTE_USECONDS", unix.NOTE_USECONDS},
|
||||||
|
{"NOTE_WRITE", unix.NOTE_WRITE},
|
||||||
|
}
|
||||||
32
vendor/github.com/fsnotify/fsnotify/internal/debug_kqueue.go
generated
vendored
Normal file
32
vendor/github.com/fsnotify/fsnotify/internal/debug_kqueue.go
generated
vendored
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
//go:build freebsd || openbsd || netbsd || dragonfly || darwin
|
||||||
|
|
||||||
|
package internal
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Debug(name string, kevent *unix.Kevent_t) {
|
||||||
|
mask := uint32(kevent.Fflags)
|
||||||
|
|
||||||
|
var (
|
||||||
|
l []string
|
||||||
|
unknown = mask
|
||||||
|
)
|
||||||
|
for _, n := range names {
|
||||||
|
if mask&n.m == n.m {
|
||||||
|
l = append(l, n.n)
|
||||||
|
unknown ^= n.m
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if unknown > 0 {
|
||||||
|
l = append(l, fmt.Sprintf("0x%x", unknown))
|
||||||
|
}
|
||||||
|
fmt.Fprintf(os.Stderr, "FSNOTIFY_DEBUG: %s %10d:%-60s → %q\n",
|
||||||
|
time.Now().Format("15:04:05.000000000"), mask, strings.Join(l, " | "), name)
|
||||||
|
}
|
||||||
56
vendor/github.com/fsnotify/fsnotify/internal/debug_linux.go
generated
vendored
Normal file
56
vendor/github.com/fsnotify/fsnotify/internal/debug_linux.go
generated
vendored
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
package internal
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Debug(name string, mask, cookie uint32) {
|
||||||
|
names := []struct {
|
||||||
|
n string
|
||||||
|
m uint32
|
||||||
|
}{
|
||||||
|
{"IN_ACCESS", unix.IN_ACCESS},
|
||||||
|
{"IN_ATTRIB", unix.IN_ATTRIB},
|
||||||
|
{"IN_CLOSE", unix.IN_CLOSE},
|
||||||
|
{"IN_CLOSE_NOWRITE", unix.IN_CLOSE_NOWRITE},
|
||||||
|
{"IN_CLOSE_WRITE", unix.IN_CLOSE_WRITE},
|
||||||
|
{"IN_CREATE", unix.IN_CREATE},
|
||||||
|
{"IN_DELETE", unix.IN_DELETE},
|
||||||
|
{"IN_DELETE_SELF", unix.IN_DELETE_SELF},
|
||||||
|
{"IN_IGNORED", unix.IN_IGNORED},
|
||||||
|
{"IN_ISDIR", unix.IN_ISDIR},
|
||||||
|
{"IN_MODIFY", unix.IN_MODIFY},
|
||||||
|
{"IN_MOVE", unix.IN_MOVE},
|
||||||
|
{"IN_MOVED_FROM", unix.IN_MOVED_FROM},
|
||||||
|
{"IN_MOVED_TO", unix.IN_MOVED_TO},
|
||||||
|
{"IN_MOVE_SELF", unix.IN_MOVE_SELF},
|
||||||
|
{"IN_OPEN", unix.IN_OPEN},
|
||||||
|
{"IN_Q_OVERFLOW", unix.IN_Q_OVERFLOW},
|
||||||
|
{"IN_UNMOUNT", unix.IN_UNMOUNT},
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
l []string
|
||||||
|
unknown = mask
|
||||||
|
)
|
||||||
|
for _, n := range names {
|
||||||
|
if mask&n.m == n.m {
|
||||||
|
l = append(l, n.n)
|
||||||
|
unknown ^= n.m
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if unknown > 0 {
|
||||||
|
l = append(l, fmt.Sprintf("0x%x", unknown))
|
||||||
|
}
|
||||||
|
var c string
|
||||||
|
if cookie > 0 {
|
||||||
|
c = fmt.Sprintf("(cookie: %d) ", cookie)
|
||||||
|
}
|
||||||
|
fmt.Fprintf(os.Stderr, "FSNOTIFY_DEBUG: %s %-30s → %s%q\n",
|
||||||
|
time.Now().Format("15:04:05.000000000"), strings.Join(l, "|"), c, name)
|
||||||
|
}
|
||||||
25
vendor/github.com/fsnotify/fsnotify/internal/debug_netbsd.go
generated
vendored
Normal file
25
vendor/github.com/fsnotify/fsnotify/internal/debug_netbsd.go
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
package internal
|
||||||
|
|
||||||
|
import "golang.org/x/sys/unix"
|
||||||
|
|
||||||
|
var names = []struct {
|
||||||
|
n string
|
||||||
|
m uint32
|
||||||
|
}{
|
||||||
|
{"NOTE_ATTRIB", unix.NOTE_ATTRIB},
|
||||||
|
{"NOTE_CHILD", unix.NOTE_CHILD},
|
||||||
|
{"NOTE_DELETE", unix.NOTE_DELETE},
|
||||||
|
{"NOTE_EXEC", unix.NOTE_EXEC},
|
||||||
|
{"NOTE_EXIT", unix.NOTE_EXIT},
|
||||||
|
{"NOTE_EXTEND", unix.NOTE_EXTEND},
|
||||||
|
{"NOTE_FORK", unix.NOTE_FORK},
|
||||||
|
{"NOTE_LINK", unix.NOTE_LINK},
|
||||||
|
{"NOTE_LOWAT", unix.NOTE_LOWAT},
|
||||||
|
{"NOTE_PCTRLMASK", unix.NOTE_PCTRLMASK},
|
||||||
|
{"NOTE_PDATAMASK", unix.NOTE_PDATAMASK},
|
||||||
|
{"NOTE_RENAME", unix.NOTE_RENAME},
|
||||||
|
{"NOTE_REVOKE", unix.NOTE_REVOKE},
|
||||||
|
{"NOTE_TRACK", unix.NOTE_TRACK},
|
||||||
|
{"NOTE_TRACKERR", unix.NOTE_TRACKERR},
|
||||||
|
{"NOTE_WRITE", unix.NOTE_WRITE},
|
||||||
|
}
|
||||||
28
vendor/github.com/fsnotify/fsnotify/internal/debug_openbsd.go
generated
vendored
Normal file
28
vendor/github.com/fsnotify/fsnotify/internal/debug_openbsd.go
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
package internal
|
||||||
|
|
||||||
|
import "golang.org/x/sys/unix"
|
||||||
|
|
||||||
|
var names = []struct {
|
||||||
|
n string
|
||||||
|
m uint32
|
||||||
|
}{
|
||||||
|
{"NOTE_ATTRIB", unix.NOTE_ATTRIB},
|
||||||
|
// {"NOTE_CHANGE", unix.NOTE_CHANGE}, // Not on 386?
|
||||||
|
{"NOTE_CHILD", unix.NOTE_CHILD},
|
||||||
|
{"NOTE_DELETE", unix.NOTE_DELETE},
|
||||||
|
{"NOTE_EOF", unix.NOTE_EOF},
|
||||||
|
{"NOTE_EXEC", unix.NOTE_EXEC},
|
||||||
|
{"NOTE_EXIT", unix.NOTE_EXIT},
|
||||||
|
{"NOTE_EXTEND", unix.NOTE_EXTEND},
|
||||||
|
{"NOTE_FORK", unix.NOTE_FORK},
|
||||||
|
{"NOTE_LINK", unix.NOTE_LINK},
|
||||||
|
{"NOTE_LOWAT", unix.NOTE_LOWAT},
|
||||||
|
{"NOTE_PCTRLMASK", unix.NOTE_PCTRLMASK},
|
||||||
|
{"NOTE_PDATAMASK", unix.NOTE_PDATAMASK},
|
||||||
|
{"NOTE_RENAME", unix.NOTE_RENAME},
|
||||||
|
{"NOTE_REVOKE", unix.NOTE_REVOKE},
|
||||||
|
{"NOTE_TRACK", unix.NOTE_TRACK},
|
||||||
|
{"NOTE_TRACKERR", unix.NOTE_TRACKERR},
|
||||||
|
{"NOTE_TRUNCATE", unix.NOTE_TRUNCATE},
|
||||||
|
{"NOTE_WRITE", unix.NOTE_WRITE},
|
||||||
|
}
|
||||||
45
vendor/github.com/fsnotify/fsnotify/internal/debug_solaris.go
generated
vendored
Normal file
45
vendor/github.com/fsnotify/fsnotify/internal/debug_solaris.go
generated
vendored
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
package internal
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Debug(name string, mask int32) {
|
||||||
|
names := []struct {
|
||||||
|
n string
|
||||||
|
m int32
|
||||||
|
}{
|
||||||
|
{"FILE_ACCESS", unix.FILE_ACCESS},
|
||||||
|
{"FILE_MODIFIED", unix.FILE_MODIFIED},
|
||||||
|
{"FILE_ATTRIB", unix.FILE_ATTRIB},
|
||||||
|
{"FILE_TRUNC", unix.FILE_TRUNC},
|
||||||
|
{"FILE_NOFOLLOW", unix.FILE_NOFOLLOW},
|
||||||
|
{"FILE_DELETE", unix.FILE_DELETE},
|
||||||
|
{"FILE_RENAME_TO", unix.FILE_RENAME_TO},
|
||||||
|
{"FILE_RENAME_FROM", unix.FILE_RENAME_FROM},
|
||||||
|
{"UNMOUNTED", unix.UNMOUNTED},
|
||||||
|
{"MOUNTEDOVER", unix.MOUNTEDOVER},
|
||||||
|
{"FILE_EXCEPTION", unix.FILE_EXCEPTION},
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
l []string
|
||||||
|
unknown = mask
|
||||||
|
)
|
||||||
|
for _, n := range names {
|
||||||
|
if mask&n.m == n.m {
|
||||||
|
l = append(l, n.n)
|
||||||
|
unknown ^= n.m
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if unknown > 0 {
|
||||||
|
l = append(l, fmt.Sprintf("0x%x", unknown))
|
||||||
|
}
|
||||||
|
fmt.Fprintf(os.Stderr, "FSNOTIFY_DEBUG: %s %10d:%-30s → %q\n",
|
||||||
|
time.Now().Format("15:04:05.000000000"), mask, strings.Join(l, " | "), name)
|
||||||
|
}
|
||||||
40
vendor/github.com/fsnotify/fsnotify/internal/debug_windows.go
generated
vendored
Normal file
40
vendor/github.com/fsnotify/fsnotify/internal/debug_windows.go
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
package internal
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Debug(name string, mask uint32) {
|
||||||
|
names := []struct {
|
||||||
|
n string
|
||||||
|
m uint32
|
||||||
|
}{
|
||||||
|
{"FILE_ACTION_ADDED", windows.FILE_ACTION_ADDED},
|
||||||
|
{"FILE_ACTION_REMOVED", windows.FILE_ACTION_REMOVED},
|
||||||
|
{"FILE_ACTION_MODIFIED", windows.FILE_ACTION_MODIFIED},
|
||||||
|
{"FILE_ACTION_RENAMED_OLD_NAME", windows.FILE_ACTION_RENAMED_OLD_NAME},
|
||||||
|
{"FILE_ACTION_RENAMED_NEW_NAME", windows.FILE_ACTION_RENAMED_NEW_NAME},
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
l []string
|
||||||
|
unknown = mask
|
||||||
|
)
|
||||||
|
for _, n := range names {
|
||||||
|
if mask&n.m == n.m {
|
||||||
|
l = append(l, n.n)
|
||||||
|
unknown ^= n.m
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if unknown > 0 {
|
||||||
|
l = append(l, fmt.Sprintf("0x%x", unknown))
|
||||||
|
}
|
||||||
|
fmt.Fprintf(os.Stderr, "FSNOTIFY_DEBUG: %s %-65s → %q\n",
|
||||||
|
time.Now().Format("15:04:05.000000000"), strings.Join(l, " | "), filepath.ToSlash(name))
|
||||||
|
}
|
||||||
31
vendor/github.com/fsnotify/fsnotify/internal/freebsd.go
generated
vendored
Normal file
31
vendor/github.com/fsnotify/fsnotify/internal/freebsd.go
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
//go:build freebsd
|
||||||
|
|
||||||
|
package internal
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrSyscallEACCES = syscall.EACCES
|
||||||
|
ErrUnixEACCES = unix.EACCES
|
||||||
|
)
|
||||||
|
|
||||||
|
var maxfiles uint64
|
||||||
|
|
||||||
|
func SetRlimit() {
|
||||||
|
// Go 1.19 will do this automatically: https://go-review.googlesource.com/c/go/+/393354/
|
||||||
|
var l syscall.Rlimit
|
||||||
|
err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &l)
|
||||||
|
if err == nil && l.Cur != l.Max {
|
||||||
|
l.Cur = l.Max
|
||||||
|
syscall.Setrlimit(syscall.RLIMIT_NOFILE, &l)
|
||||||
|
}
|
||||||
|
maxfiles = uint64(l.Cur)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Maxfiles() uint64 { return maxfiles }
|
||||||
|
func Mkfifo(path string, mode uint32) error { return unix.Mkfifo(path, mode) }
|
||||||
|
func Mknod(path string, mode uint32, dev int) error { return unix.Mknod(path, mode, uint64(dev)) }
|
||||||
2
vendor/github.com/fsnotify/fsnotify/internal/internal.go
generated
vendored
Normal file
2
vendor/github.com/fsnotify/fsnotify/internal/internal.go
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
// Package internal contains some helpers.
|
||||||
|
package internal
|
||||||
31
vendor/github.com/fsnotify/fsnotify/internal/unix.go
generated
vendored
Normal file
31
vendor/github.com/fsnotify/fsnotify/internal/unix.go
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
//go:build !windows && !darwin && !freebsd && !plan9
|
||||||
|
|
||||||
|
package internal
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrSyscallEACCES = syscall.EACCES
|
||||||
|
ErrUnixEACCES = unix.EACCES
|
||||||
|
)
|
||||||
|
|
||||||
|
var maxfiles uint64
|
||||||
|
|
||||||
|
func SetRlimit() {
|
||||||
|
// Go 1.19 will do this automatically: https://go-review.googlesource.com/c/go/+/393354/
|
||||||
|
var l syscall.Rlimit
|
||||||
|
err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &l)
|
||||||
|
if err == nil && l.Cur != l.Max {
|
||||||
|
l.Cur = l.Max
|
||||||
|
syscall.Setrlimit(syscall.RLIMIT_NOFILE, &l)
|
||||||
|
}
|
||||||
|
maxfiles = uint64(l.Cur)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Maxfiles() uint64 { return maxfiles }
|
||||||
|
func Mkfifo(path string, mode uint32) error { return unix.Mkfifo(path, mode) }
|
||||||
|
func Mknod(path string, mode uint32, dev int) error { return unix.Mknod(path, mode, dev) }
|
||||||
7
vendor/github.com/fsnotify/fsnotify/internal/unix2.go
generated
vendored
Normal file
7
vendor/github.com/fsnotify/fsnotify/internal/unix2.go
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
//go:build !windows
|
||||||
|
|
||||||
|
package internal
|
||||||
|
|
||||||
|
func HasPrivilegesForSymlink() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
41
vendor/github.com/fsnotify/fsnotify/internal/windows.go
generated
vendored
Normal file
41
vendor/github.com/fsnotify/fsnotify/internal/windows.go
generated
vendored
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
//go:build windows
|
||||||
|
|
||||||
|
package internal
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Just a dummy.
|
||||||
|
var (
|
||||||
|
ErrSyscallEACCES = errors.New("dummy")
|
||||||
|
ErrUnixEACCES = errors.New("dummy")
|
||||||
|
)
|
||||||
|
|
||||||
|
func SetRlimit() {}
|
||||||
|
func Maxfiles() uint64 { return 1<<64 - 1 }
|
||||||
|
func Mkfifo(path string, mode uint32) error { return errors.New("no FIFOs on Windows") }
|
||||||
|
func Mknod(path string, mode uint32, dev int) error { return errors.New("no device nodes on Windows") }
|
||||||
|
|
||||||
|
func HasPrivilegesForSymlink() bool {
|
||||||
|
var sid *windows.SID
|
||||||
|
err := windows.AllocateAndInitializeSid(
|
||||||
|
&windows.SECURITY_NT_AUTHORITY,
|
||||||
|
2,
|
||||||
|
windows.SECURITY_BUILTIN_DOMAIN_RID,
|
||||||
|
windows.DOMAIN_ALIAS_RID_ADMINS,
|
||||||
|
0, 0, 0, 0, 0, 0,
|
||||||
|
&sid)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
defer windows.FreeSid(sid)
|
||||||
|
token := windows.Token(0)
|
||||||
|
member, err := token.IsMember(sid)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return member || token.IsElevated()
|
||||||
|
}
|
||||||
259
vendor/github.com/fsnotify/fsnotify/mkdoc.zsh
generated
vendored
259
vendor/github.com/fsnotify/fsnotify/mkdoc.zsh
generated
vendored
@@ -1,259 +0,0 @@
|
|||||||
#!/usr/bin/env zsh
|
|
||||||
[ "${ZSH_VERSION:-}" = "" ] && echo >&2 "Only works with zsh" && exit 1
|
|
||||||
setopt err_exit no_unset pipefail extended_glob
|
|
||||||
|
|
||||||
# Simple script to update the godoc comments on all watchers so you don't need
|
|
||||||
# to update the same comment 5 times.
|
|
||||||
|
|
||||||
watcher=$(<<EOF
|
|
||||||
// Watcher watches a set of paths, delivering events on a channel.
|
|
||||||
//
|
|
||||||
// A watcher should not be copied (e.g. pass it by pointer, rather than by
|
|
||||||
// value).
|
|
||||||
//
|
|
||||||
// # Linux notes
|
|
||||||
//
|
|
||||||
// When a file is removed a Remove event won't be emitted until all file
|
|
||||||
// descriptors are closed, and deletes will always emit a Chmod. For example:
|
|
||||||
//
|
|
||||||
// fp := os.Open("file")
|
|
||||||
// os.Remove("file") // Triggers Chmod
|
|
||||||
// fp.Close() // Triggers Remove
|
|
||||||
//
|
|
||||||
// This is the event that inotify sends, so not much can be changed about this.
|
|
||||||
//
|
|
||||||
// The fs.inotify.max_user_watches sysctl variable specifies the upper limit
|
|
||||||
// for the number of watches per user, and fs.inotify.max_user_instances
|
|
||||||
// specifies the maximum number of inotify instances per user. Every Watcher you
|
|
||||||
// create is an "instance", and every path you add is a "watch".
|
|
||||||
//
|
|
||||||
// These are also exposed in /proc as /proc/sys/fs/inotify/max_user_watches and
|
|
||||||
// /proc/sys/fs/inotify/max_user_instances
|
|
||||||
//
|
|
||||||
// To increase them you can use sysctl or write the value to the /proc file:
|
|
||||||
//
|
|
||||||
// # Default values on Linux 5.18
|
|
||||||
// sysctl fs.inotify.max_user_watches=124983
|
|
||||||
// sysctl fs.inotify.max_user_instances=128
|
|
||||||
//
|
|
||||||
// To make the changes persist on reboot edit /etc/sysctl.conf or
|
|
||||||
// /usr/lib/sysctl.d/50-default.conf (details differ per Linux distro; check
|
|
||||||
// your distro's documentation):
|
|
||||||
//
|
|
||||||
// fs.inotify.max_user_watches=124983
|
|
||||||
// fs.inotify.max_user_instances=128
|
|
||||||
//
|
|
||||||
// Reaching the limit will result in a "no space left on device" or "too many open
|
|
||||||
// files" error.
|
|
||||||
//
|
|
||||||
// # kqueue notes (macOS, BSD)
|
|
||||||
//
|
|
||||||
// kqueue requires opening a file descriptor for every file that's being watched;
|
|
||||||
// so if you're watching a directory with five files then that's six file
|
|
||||||
// descriptors. You will run in to your system's "max open files" limit faster on
|
|
||||||
// these platforms.
|
|
||||||
//
|
|
||||||
// The sysctl variables kern.maxfiles and kern.maxfilesperproc can be used to
|
|
||||||
// control the maximum number of open files, as well as /etc/login.conf on BSD
|
|
||||||
// systems.
|
|
||||||
//
|
|
||||||
// # Windows notes
|
|
||||||
//
|
|
||||||
// Paths can be added as "C:\\path\\to\\dir", but forward slashes
|
|
||||||
// ("C:/path/to/dir") will also work.
|
|
||||||
//
|
|
||||||
// When a watched directory is removed it will always send an event for the
|
|
||||||
// directory itself, but may not send events for all files in that directory.
|
|
||||||
// Sometimes it will send events for all times, sometimes it will send no
|
|
||||||
// events, and often only for some files.
|
|
||||||
//
|
|
||||||
// The default ReadDirectoryChangesW() buffer size is 64K, which is the largest
|
|
||||||
// value that is guaranteed to work with SMB filesystems. If you have many
|
|
||||||
// events in quick succession this may not be enough, and you will have to use
|
|
||||||
// [WithBufferSize] to increase the value.
|
|
||||||
EOF
|
|
||||||
)
|
|
||||||
|
|
||||||
new=$(<<EOF
|
|
||||||
// NewWatcher creates a new Watcher.
|
|
||||||
EOF
|
|
||||||
)
|
|
||||||
|
|
||||||
newbuffered=$(<<EOF
|
|
||||||
// NewBufferedWatcher creates a new Watcher with a buffered Watcher.Events
|
|
||||||
// channel.
|
|
||||||
//
|
|
||||||
// The main use case for this is situations with a very large number of events
|
|
||||||
// where the kernel buffer size can't be increased (e.g. due to lack of
|
|
||||||
// permissions). An unbuffered Watcher will perform better for almost all use
|
|
||||||
// cases, and whenever possible you will be better off increasing the kernel
|
|
||||||
// buffers instead of adding a large userspace buffer.
|
|
||||||
EOF
|
|
||||||
)
|
|
||||||
|
|
||||||
add=$(<<EOF
|
|
||||||
// Add starts monitoring the path for changes.
|
|
||||||
//
|
|
||||||
// A path can only be watched once; watching it more than once is a no-op and will
|
|
||||||
// not return an error. Paths that do not yet exist on the filesystem cannot be
|
|
||||||
// watched.
|
|
||||||
//
|
|
||||||
// A watch will be automatically removed if the watched path is deleted or
|
|
||||||
// renamed. The exception is the Windows backend, which doesn't remove the
|
|
||||||
// watcher on renames.
|
|
||||||
//
|
|
||||||
// Notifications on network filesystems (NFS, SMB, FUSE, etc.) or special
|
|
||||||
// filesystems (/proc, /sys, etc.) generally don't work.
|
|
||||||
//
|
|
||||||
// Returns [ErrClosed] if [Watcher.Close] was called.
|
|
||||||
//
|
|
||||||
// See [Watcher.AddWith] for a version that allows adding options.
|
|
||||||
//
|
|
||||||
// # Watching directories
|
|
||||||
//
|
|
||||||
// All files in a directory are monitored, including new files that are created
|
|
||||||
// after the watcher is started. Subdirectories are not watched (i.e. it's
|
|
||||||
// non-recursive).
|
|
||||||
//
|
|
||||||
// # Watching files
|
|
||||||
//
|
|
||||||
// Watching individual files (rather than directories) is generally not
|
|
||||||
// recommended as many programs (especially editors) update files atomically: it
|
|
||||||
// will write to a temporary file which is then moved to to destination,
|
|
||||||
// overwriting the original (or some variant thereof). The watcher on the
|
|
||||||
// original file is now lost, as that no longer exists.
|
|
||||||
//
|
|
||||||
// The upshot of this is that a power failure or crash won't leave a
|
|
||||||
// half-written file.
|
|
||||||
//
|
|
||||||
// Watch the parent directory and use Event.Name to filter out files you're not
|
|
||||||
// interested in. There is an example of this in cmd/fsnotify/file.go.
|
|
||||||
EOF
|
|
||||||
)
|
|
||||||
|
|
||||||
addwith=$(<<EOF
|
|
||||||
// AddWith is like [Watcher.Add], but allows adding options. When using Add()
|
|
||||||
// the defaults described below are used.
|
|
||||||
//
|
|
||||||
// Possible options are:
|
|
||||||
//
|
|
||||||
// - [WithBufferSize] sets the buffer size for the Windows backend; no-op on
|
|
||||||
// other platforms. The default is 64K (65536 bytes).
|
|
||||||
EOF
|
|
||||||
)
|
|
||||||
|
|
||||||
remove=$(<<EOF
|
|
||||||
// Remove stops monitoring the path for changes.
|
|
||||||
//
|
|
||||||
// Directories are always removed non-recursively. For example, if you added
|
|
||||||
// /tmp/dir and /tmp/dir/subdir then you will need to remove both.
|
|
||||||
//
|
|
||||||
// Removing a path that has not yet been added returns [ErrNonExistentWatch].
|
|
||||||
//
|
|
||||||
// Returns nil if [Watcher.Close] was called.
|
|
||||||
EOF
|
|
||||||
)
|
|
||||||
|
|
||||||
close=$(<<EOF
|
|
||||||
// Close removes all watches and closes the Events channel.
|
|
||||||
EOF
|
|
||||||
)
|
|
||||||
|
|
||||||
watchlist=$(<<EOF
|
|
||||||
// WatchList returns all paths explicitly added with [Watcher.Add] (and are not
|
|
||||||
// yet removed).
|
|
||||||
//
|
|
||||||
// Returns nil if [Watcher.Close] was called.
|
|
||||||
EOF
|
|
||||||
)
|
|
||||||
|
|
||||||
events=$(<<EOF
|
|
||||||
// Events sends the filesystem change events.
|
|
||||||
//
|
|
||||||
// fsnotify can send the following events; a "path" here can refer to a
|
|
||||||
// file, directory, symbolic link, or special file like a FIFO.
|
|
||||||
//
|
|
||||||
// fsnotify.Create A new path was created; this may be followed by one
|
|
||||||
// or more Write events if data also gets written to a
|
|
||||||
// file.
|
|
||||||
//
|
|
||||||
// fsnotify.Remove A path was removed.
|
|
||||||
//
|
|
||||||
// fsnotify.Rename A path was renamed. A rename is always sent with the
|
|
||||||
// old path as Event.Name, and a Create event will be
|
|
||||||
// sent with the new name. Renames are only sent for
|
|
||||||
// paths that are currently watched; e.g. moving an
|
|
||||||
// unmonitored file into a monitored directory will
|
|
||||||
// show up as just a Create. Similarly, renaming a file
|
|
||||||
// to outside a monitored directory will show up as
|
|
||||||
// only a Rename.
|
|
||||||
//
|
|
||||||
// fsnotify.Write A file or named pipe was written to. A Truncate will
|
|
||||||
// also trigger a Write. A single "write action"
|
|
||||||
// initiated by the user may show up as one or multiple
|
|
||||||
// writes, depending on when the system syncs things to
|
|
||||||
// disk. For example when compiling a large Go program
|
|
||||||
// you may get hundreds of Write events, and you may
|
|
||||||
// want to wait until you've stopped receiving them
|
|
||||||
// (see the dedup example in cmd/fsnotify).
|
|
||||||
//
|
|
||||||
// Some systems may send Write event for directories
|
|
||||||
// when the directory content changes.
|
|
||||||
//
|
|
||||||
// fsnotify.Chmod Attributes were changed. On Linux this is also sent
|
|
||||||
// when a file is removed (or more accurately, when a
|
|
||||||
// link to an inode is removed). On kqueue it's sent
|
|
||||||
// when a file is truncated. On Windows it's never
|
|
||||||
// sent.
|
|
||||||
EOF
|
|
||||||
)
|
|
||||||
|
|
||||||
errors=$(<<EOF
|
|
||||||
// Errors sends any errors.
|
|
||||||
//
|
|
||||||
// ErrEventOverflow is used to indicate there are too many events:
|
|
||||||
//
|
|
||||||
// - inotify: There are too many queued events (fs.inotify.max_queued_events sysctl)
|
|
||||||
// - windows: The buffer size is too small; WithBufferSize() can be used to increase it.
|
|
||||||
// - kqueue, fen: Not used.
|
|
||||||
EOF
|
|
||||||
)
|
|
||||||
|
|
||||||
set-cmt() {
|
|
||||||
local pat=$1
|
|
||||||
local cmt=$2
|
|
||||||
|
|
||||||
IFS=$'\n' local files=($(grep -n $pat backend_*~*_test.go))
|
|
||||||
for f in $files; do
|
|
||||||
IFS=':' local fields=($=f)
|
|
||||||
local file=$fields[1]
|
|
||||||
local end=$(( $fields[2] - 1 ))
|
|
||||||
|
|
||||||
# Find start of comment.
|
|
||||||
local start=0
|
|
||||||
IFS=$'\n' local lines=($(head -n$end $file))
|
|
||||||
for (( i = 1; i <= $#lines; i++ )); do
|
|
||||||
local line=$lines[-$i]
|
|
||||||
if ! grep -q '^[[:space:]]*//' <<<$line; then
|
|
||||||
start=$(( end - (i - 2) ))
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
head -n $(( start - 1 )) $file >/tmp/x
|
|
||||||
print -r -- $cmt >>/tmp/x
|
|
||||||
tail -n+$(( end + 1 )) $file >>/tmp/x
|
|
||||||
mv /tmp/x $file
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
set-cmt '^type Watcher struct ' $watcher
|
|
||||||
set-cmt '^func NewWatcher(' $new
|
|
||||||
set-cmt '^func NewBufferedWatcher(' $newbuffered
|
|
||||||
set-cmt '^func (w \*Watcher) Add(' $add
|
|
||||||
set-cmt '^func (w \*Watcher) AddWith(' $addwith
|
|
||||||
set-cmt '^func (w \*Watcher) Remove(' $remove
|
|
||||||
set-cmt '^func (w \*Watcher) Close(' $close
|
|
||||||
set-cmt '^func (w \*Watcher) WatchList(' $watchlist
|
|
||||||
set-cmt '^[[:space:]]*Events *chan Event$' $events
|
|
||||||
set-cmt '^[[:space:]]*Errors *chan error$' $errors
|
|
||||||
64
vendor/github.com/fsnotify/fsnotify/shared.go
generated
vendored
Normal file
64
vendor/github.com/fsnotify/fsnotify/shared.go
generated
vendored
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
package fsnotify
|
||||||
|
|
||||||
|
import "sync"
|
||||||
|
|
||||||
|
type shared struct {
|
||||||
|
Events chan Event
|
||||||
|
Errors chan error
|
||||||
|
done chan struct{}
|
||||||
|
mu sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func newShared(ev chan Event, errs chan error) *shared {
|
||||||
|
return &shared{
|
||||||
|
Events: ev,
|
||||||
|
Errors: errs,
|
||||||
|
done: make(chan struct{}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true if the event was sent, or false if watcher is closed.
|
||||||
|
func (w *shared) sendEvent(e Event) bool {
|
||||||
|
if e.Op == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
case <-w.done:
|
||||||
|
return false
|
||||||
|
case w.Events <- e:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true if the error was sent, or false if watcher is closed.
|
||||||
|
func (w *shared) sendError(err error) bool {
|
||||||
|
if err == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
case <-w.done:
|
||||||
|
return false
|
||||||
|
case w.Errors <- err:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *shared) isClosed() bool {
|
||||||
|
select {
|
||||||
|
case <-w.done:
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mark as closed; returns true if it was already closed.
|
||||||
|
func (w *shared) close() bool {
|
||||||
|
w.mu.Lock()
|
||||||
|
defer w.mu.Unlock()
|
||||||
|
if w.isClosed() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
close(w.done)
|
||||||
|
return false
|
||||||
|
}
|
||||||
3
vendor/github.com/fsnotify/fsnotify/staticcheck.conf
generated
vendored
Normal file
3
vendor/github.com/fsnotify/fsnotify/staticcheck.conf
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
checks = ['all',
|
||||||
|
'-U1000', # Don't complain about unused functions.
|
||||||
|
]
|
||||||
1
vendor/github.com/fsnotify/fsnotify/system_bsd.go
generated
vendored
1
vendor/github.com/fsnotify/fsnotify/system_bsd.go
generated
vendored
@@ -1,5 +1,4 @@
|
|||||||
//go:build freebsd || openbsd || netbsd || dragonfly
|
//go:build freebsd || openbsd || netbsd || dragonfly
|
||||||
// +build freebsd openbsd netbsd dragonfly
|
|
||||||
|
|
||||||
package fsnotify
|
package fsnotify
|
||||||
|
|
||||||
|
|||||||
1
vendor/github.com/fsnotify/fsnotify/system_darwin.go
generated
vendored
1
vendor/github.com/fsnotify/fsnotify/system_darwin.go
generated
vendored
@@ -1,5 +1,4 @@
|
|||||||
//go:build darwin
|
//go:build darwin
|
||||||
// +build darwin
|
|
||||||
|
|
||||||
package fsnotify
|
package fsnotify
|
||||||
|
|
||||||
|
|||||||
591
vendor/github.com/fxamacker/cbor/v2/README.md
generated
vendored
591
vendor/github.com/fxamacker/cbor/v2/README.md
generated
vendored
@@ -1,30 +1,31 @@
|
|||||||
# CBOR Codec in Go
|
<h1>CBOR Codec <a href="https://pkg.go.dev/github.com/fxamacker/cbor/v2"><img src="https://raw.githubusercontent.com/fxamacker/images/refs/heads/master/cbor/go-logo-blue.svg" alt="Go logo" style="height: 1em;" align="right"></a></h1>
|
||||||
|
|
||||||
<!-- [](#cbor-library-in-go) -->
|
|
||||||
|
|
||||||
[fxamacker/cbor](https://github.com/fxamacker/cbor) is a library for encoding and decoding [CBOR](https://www.rfc-editor.org/info/std94) and [CBOR Sequences](https://www.rfc-editor.org/rfc/rfc8742.html).
|
[fxamacker/cbor](https://github.com/fxamacker/cbor) is a library for encoding and decoding [CBOR](https://www.rfc-editor.org/info/std94) and [CBOR Sequences](https://www.rfc-editor.org/rfc/rfc8742.html).
|
||||||
|
|
||||||
CBOR is a [trusted alternative](https://www.rfc-editor.org/rfc/rfc8949.html#name-comparison-of-other-binary-) to JSON, MessagePack, Protocol Buffers, etc. CBOR is an Internet Standard defined by [IETF STD 94 (RFC 8949)](https://www.rfc-editor.org/info/std94) and is designed to be relevant for decades.
|
CBOR is a [trusted alternative](https://www.rfc-editor.org/rfc/rfc8949.html#name-comparison-of-other-binary-) to JSON, MessagePack, Protocol Buffers, etc. CBOR is an Internet Standard defined by [IETF STD 94 (RFC 8949)](https://www.rfc-editor.org/info/std94) and is designed to be relevant for decades.
|
||||||
|
|
||||||
`fxamacker/cbor` is used in projects by Arm Ltd., Cisco, EdgeX Foundry, Flow Foundation, Fraunhofer‑AISEC, Kubernetes, Let's Encrypt (ISRG), Linux Foundation, Microsoft, Mozilla, Oasis Protocol, Tailscale, Teleport, [etc](https://github.com/fxamacker/cbor#who-uses-fxamackercbor).
|
`fxamacker/cbor` is used in projects by Arm Ltd., EdgeX Foundry, Flow Foundation, Fraunhofer‑AISEC, IBM, Kubernetes[*](https://github.com/search?q=org%3Akubernetes%20fxamacker%2Fcbor&type=code), Let's Encrypt, Linux Foundation, Microsoft, Oasis Protocol, Red Hat[*](https://github.com/search?q=org%3Aopenshift+fxamacker%2Fcbor&type=code), Tailscale[*](https://github.com/search?q=org%3Atailscale+fxamacker%2Fcbor&type=code), Veraison[*](https://github.com/search?q=org%3Averaison+fxamacker%2Fcbor&type=code), [etc](https://github.com/fxamacker/cbor#who-uses-fxamackercbor).
|
||||||
|
|
||||||
See [Quick Start](#quick-start) and [Releases](https://github.com/fxamacker/cbor/releases/). 🆕 `UnmarshalFirst` and `DiagnoseFirst` can decode CBOR Sequences. `cbor.MarshalToBuffer()` and `UserBufferEncMode` accepts user-specified buffer.
|
See [Quick Start](#quick-start) and [Releases](https://github.com/fxamacker/cbor/releases/). 🆕 `UnmarshalFirst` and `DiagnoseFirst` can decode CBOR Sequences. `MarshalToBuffer` and `UserBufferEncMode` accepts user-specified buffer.
|
||||||
|
|
||||||
## fxamacker/cbor
|
## fxamacker/cbor
|
||||||
|
|
||||||
[](https://github.com/fxamacker/cbor/actions?query=workflow%3Aci)
|
[](https://github.com/fxamacker/cbor/actions?query=workflow%3Aci)
|
||||||
[](https://github.com/fxamacker/cbor/actions?query=workflow%3A%22cover+%E2%89%A596%25%22)
|
[](https://github.com/fxamacker/cbor/actions?query=workflow%3A%22cover+%E2%89%A597%25%22)
|
||||||
[](https://github.com/fxamacker/cbor/actions/workflows/codeql-analysis.yml)
|
[](https://github.com/fxamacker/cbor/actions/workflows/codeql-analysis.yml)
|
||||||
[](#fuzzing-and-code-coverage)
|
[](#fuzzing-and-code-coverage)
|
||||||
[](https://goreportcard.com/report/github.com/fxamacker/cbor)
|
[](https://goreportcard.com/report/github.com/fxamacker/cbor)
|
||||||
|
[](https://github.com/fxamacker/cbor#fuzzing-and-code-coverage)
|
||||||
|
|
||||||
`fxamacker/cbor` is a CBOR codec in full conformance with [IETF STD 94 (RFC 8949)](https://www.rfc-editor.org/info/std94). It also supports CBOR Sequences ([RFC 8742](https://www.rfc-editor.org/rfc/rfc8742.html)) and Extended Diagnostic Notation ([Appendix G of RFC 8610](https://www.rfc-editor.org/rfc/rfc8610.html#appendix-G)).
|
`fxamacker/cbor` is a CBOR codec in full conformance with [IETF STD 94 (RFC 8949)](https://www.rfc-editor.org/info/std94). It also supports CBOR Sequences ([RFC 8742](https://www.rfc-editor.org/rfc/rfc8742.html)) and Extended Diagnostic Notation ([Appendix G of RFC 8610](https://www.rfc-editor.org/rfc/rfc8610.html#appendix-G)).
|
||||||
|
|
||||||
Features include full support for CBOR tags, [Core Deterministic Encoding](https://www.rfc-editor.org/rfc/rfc8949.html#name-core-deterministic-encoding), duplicate map key detection, etc.
|
Features include full support for CBOR tags, [Core Deterministic Encoding](https://www.rfc-editor.org/rfc/rfc8949.html#name-core-deterministic-encoding), duplicate map key detection, etc.
|
||||||
|
|
||||||
|
API is mostly same as `encoding/json`, plus interfaces that simplify concurrency and CBOR options.
|
||||||
|
|
||||||
Design balances trade-offs between security, speed, concurrency, encoded data size, usability, etc.
|
Design balances trade-offs between security, speed, concurrency, encoded data size, usability, etc.
|
||||||
|
|
||||||
<details><summary>Highlights</summary><p/>
|
<details><summary> 🔎 Highlights</summary><p/>
|
||||||
|
|
||||||
__🚀 Speed__
|
__🚀 Speed__
|
||||||
|
|
||||||
@@ -38,7 +39,7 @@ Codec passed multiple confidential security assessments in 2022. No vulnerabili
|
|||||||
|
|
||||||
__🗜️ Data Size__
|
__🗜️ Data Size__
|
||||||
|
|
||||||
Struct tags (`toarray`, `keyasint`, `omitempty`) automatically reduce size of encoded structs. Encoding optionally shrinks float64→32→16 when values fit.
|
Struct tag options (`toarray`, `keyasint`, `omitempty`, `omitzero`) and field tag "-" automatically reduce size of encoded structs. Encoding optionally shrinks float64→32→16 when values fit.
|
||||||
|
|
||||||
__:jigsaw: Usability__
|
__:jigsaw: Usability__
|
||||||
|
|
||||||
@@ -58,164 +59,205 @@ Features include CBOR [extension points](https://www.rfc-editor.org/rfc/rfc8949.
|
|||||||
|
|
||||||
`fxamacker/cbor` has configurable limits, etc. that defend against malicious CBOR data.
|
`fxamacker/cbor` has configurable limits, etc. that defend against malicious CBOR data.
|
||||||
|
|
||||||
By contrast, `encoding/gob` is [not designed to be hardened against adversarial inputs](https://pkg.go.dev/encoding/gob#hdr-Security).
|
Notably, `fxamacker/cbor` is fast at rejecting malformed CBOR data.
|
||||||
|
|
||||||
<details><summary>Example decoding with encoding/gob 💥 fatal error (out of memory)</summary><p/>
|
> [!NOTE]
|
||||||
|
> Benchmarks rejecting 10 bytes of malicious CBOR data decoding to `[]byte`:
|
||||||
|
>
|
||||||
|
> | Codec | Speed (ns/op) | Memory | Allocs |
|
||||||
|
> | :---- | ------------: | -----: | -----: |
|
||||||
|
> | fxamacker/cbor 2.7.0 | 47 ± 7% | 32 B/op | 2 allocs/op |
|
||||||
|
> | ugorji/go 1.2.12 | 5878187 ± 3% | 67111556 B/op | 13 allocs/op |
|
||||||
|
>
|
||||||
|
> Faster hardware (overclocked DDR4 or DDR5) can reduce speed difference.
|
||||||
|
>
|
||||||
|
> <details><summary> 🔎 Benchmark details </summary><p/>
|
||||||
|
>
|
||||||
|
> Latest comparison for decoding CBOR data to Go `[]byte`:
|
||||||
|
> - Input: `[]byte{0x9B, 0x00, 0x00, 0x42, 0xFA, 0x42, 0xFA, 0x42, 0xFA, 0x42}`
|
||||||
|
> - go1.22.7, linux/amd64, i5-13600K (DDR4-2933, disabled e-cores)
|
||||||
|
> - go test -bench=. -benchmem -count=20
|
||||||
|
>
|
||||||
|
> #### Prior comparisons
|
||||||
|
>
|
||||||
|
> | Codec | Speed (ns/op) | Memory | Allocs |
|
||||||
|
> | :---- | ------------: | -----: | -----: |
|
||||||
|
> | fxamacker/cbor 2.5.0-beta2 | 44.33 ± 2% | 32 B/op | 2 allocs/op |
|
||||||
|
> | fxamacker/cbor 0.1.0 - 2.4.0 | ~44.68 ± 6% | 32 B/op | 2 allocs/op |
|
||||||
|
> | ugorji/go 1.2.10 | 5524792.50 ± 3% | 67110491 B/op | 12 allocs/op |
|
||||||
|
> | ugorji/go 1.1.0 - 1.2.6 | 💥 runtime: | out of memory: | cannot allocate |
|
||||||
|
>
|
||||||
|
> - Input: `[]byte{0x9B, 0x00, 0x00, 0x42, 0xFA, 0x42, 0xFA, 0x42, 0xFA, 0x42}`
|
||||||
|
> - go1.19.6, linux/amd64, i5-13600K (DDR4)
|
||||||
|
> - go test -bench=. -benchmem -count=20
|
||||||
|
>
|
||||||
|
> </details>
|
||||||
|
|
||||||
```Go
|
In contrast, some codecs can crash or use excessive resources while decoding bad data.
|
||||||
// Example of encoding/gob having "fatal error: runtime: out of memory"
|
|
||||||
// while decoding 181 bytes.
|
|
||||||
package main
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"encoding/gob"
|
|
||||||
"encoding/hex"
|
|
||||||
"fmt"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Example data is from https://github.com/golang/go/issues/24446
|
> [!WARNING]
|
||||||
// (shortened to 181 bytes).
|
> Go's `encoding/gob` is [not designed to be hardened against adversarial inputs](https://pkg.go.dev/encoding/gob#hdr-Security).
|
||||||
const data = "4dffb503010102303001ff30000109010130010800010130010800010130" +
|
>
|
||||||
"01ffb80001014a01ffb60001014b01ff860001013001ff860001013001ff" +
|
> <details><summary> 🔎 gob fatal error (out of memory) 💥 decoding 181 bytes</summary><p/>
|
||||||
"860001013001ff860001013001ffb80000001eff850401010e3030303030" +
|
>
|
||||||
"30303030303030303001ff3000010c0104000016ffb70201010830303030" +
|
> ```Go
|
||||||
"3030303001ff3000010c000030ffb6040405fcff00303030303030303030" +
|
> // Example of encoding/gob having "fatal error: runtime: out of memory"
|
||||||
"303030303030303030303030303030303030303030303030303030303030" +
|
> // while decoding 181 bytes (all Go versions as of Dec. 8, 2024).
|
||||||
"30"
|
> package main
|
||||||
|
> import (
|
||||||
|
> "bytes"
|
||||||
|
> "encoding/gob"
|
||||||
|
> "encoding/hex"
|
||||||
|
> "fmt"
|
||||||
|
> )
|
||||||
|
>
|
||||||
|
> // Example data is from https://github.com/golang/go/issues/24446
|
||||||
|
> // (shortened to 181 bytes).
|
||||||
|
> const data = "4dffb503010102303001ff30000109010130010800010130010800010130" +
|
||||||
|
> "01ffb80001014a01ffb60001014b01ff860001013001ff860001013001ff" +
|
||||||
|
> "860001013001ff860001013001ffb80000001eff850401010e3030303030" +
|
||||||
|
> "30303030303030303001ff3000010c0104000016ffb70201010830303030" +
|
||||||
|
> "3030303001ff3000010c000030ffb6040405fcff00303030303030303030" +
|
||||||
|
> "303030303030303030303030303030303030303030303030303030303030" +
|
||||||
|
> "30"
|
||||||
|
>
|
||||||
|
> type X struct {
|
||||||
|
> J *X
|
||||||
|
> K map[string]int
|
||||||
|
> }
|
||||||
|
>
|
||||||
|
> func main() {
|
||||||
|
> raw, _ := hex.DecodeString(data)
|
||||||
|
> decoder := gob.NewDecoder(bytes.NewReader(raw))
|
||||||
|
>
|
||||||
|
> var x X
|
||||||
|
> decoder.Decode(&x) // fatal error: runtime: out of memory
|
||||||
|
> fmt.Println("Decoding finished.")
|
||||||
|
> }
|
||||||
|
> ```
|
||||||
|
>
|
||||||
|
>
|
||||||
|
> </details>
|
||||||
|
|
||||||
type X struct {
|
### Smaller Encodings with Struct Tag Options
|
||||||
J *X
|
|
||||||
K map[string]int
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
Struct tags automatically reduce encoded size of structs and improve speed.
|
||||||
raw, _ := hex.DecodeString(data)
|
|
||||||
decoder := gob.NewDecoder(bytes.NewReader(raw))
|
|
||||||
|
|
||||||
var x X
|
We can write less code by using struct tag options:
|
||||||
decoder.Decode(&x) // fatal error: runtime: out of memory
|
- `toarray`: encode without field names (decode back to original struct)
|
||||||
fmt.Println("Decoding finished.")
|
- `keyasint`: encode field names as integers (decode back to original struct)
|
||||||
}
|
- `omitempty`: omit empty field when encoding
|
||||||
```
|
- `omitzero`: omit zero-value field when encoding
|
||||||
|
|
||||||
<hr/>
|
As a special case, struct field tag "-" omits the field.
|
||||||
|
|
||||||
</details>
|
NOTE: When a struct uses `toarray`, the encoder will ignore `omitempty` and `omitzero` to prevent position of encoded array elements from changing. This allows decoder to match encoded elements to their Go struct field.
|
||||||
|
|
||||||
`fxamacker/cbor` is fast at rejecting malformed CBOR data. E.g. attempts to
|
|
||||||
decode 10 bytes of malicious CBOR data to `[]byte` (with default settings):
|
|
||||||
|
|
||||||
| Codec | Speed (ns/op) | Memory | Allocs |
|
|
||||||
| :---- | ------------: | -----: | -----: |
|
|
||||||
| fxamacker/cbor 2.5.0 | 44 ± 5% | 32 B/op | 2 allocs/op |
|
|
||||||
| ugorji/go 1.2.11 | 5353261 ± 4% | 67111321 B/op | 13 allocs/op |
|
|
||||||
|
|
||||||
<details><summary>Benchmark details</summary><p/>
|
|
||||||
|
|
||||||
Latest comparison used:
|
|
||||||
- Input: `[]byte{0x9B, 0x00, 0x00, 0x42, 0xFA, 0x42, 0xFA, 0x42, 0xFA, 0x42}`
|
|
||||||
- go1.19.10, linux/amd64, i5-13600K (disabled all e-cores, DDR4 @2933)
|
|
||||||
- go test -bench=. -benchmem -count=20
|
|
||||||
|
|
||||||
#### Prior comparisons
|
|
||||||
|
|
||||||
| Codec | Speed (ns/op) | Memory | Allocs |
|
|
||||||
| :---- | ------------: | -----: | -----: |
|
|
||||||
| fxamacker/cbor 2.5.0-beta2 | 44.33 ± 2% | 32 B/op | 2 allocs/op |
|
|
||||||
| fxamacker/cbor 0.1.0 - 2.4.0 | ~44.68 ± 6% | 32 B/op | 2 allocs/op |
|
|
||||||
| ugorji/go 1.2.10 | 5524792.50 ± 3% | 67110491 B/op | 12 allocs/op |
|
|
||||||
| ugorji/go 1.1.0 - 1.2.6 | 💥 runtime: | out of memory: | cannot allocate |
|
|
||||||
|
|
||||||
- Input: `[]byte{0x9B, 0x00, 0x00, 0x42, 0xFA, 0x42, 0xFA, 0x42, 0xFA, 0x42}`
|
|
||||||
- go1.19.6, linux/amd64, i5-13600K (DDR4)
|
|
||||||
- go test -bench=. -benchmem -count=20
|
|
||||||
|
|
||||||
<hr/>
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
### Smaller Encodings with Struct Tags
|
|
||||||
|
|
||||||
Struct tags (`toarray`, `keyasint`, `omitempty`) reduce encoded size of structs.
|
|
||||||
|
|
||||||
<details><summary>Example encoding 3-level nested Go struct to 1 byte CBOR</summary><p/>
|
|
||||||
|
|
||||||
https://go.dev/play/p/YxwvfPdFQG2
|
|
||||||
|
|
||||||
```Go
|
|
||||||
// Example encoding nested struct (with omitempty tag)
|
|
||||||
// - encoding/json: 18 byte JSON
|
|
||||||
// - fxamacker/cbor: 1 byte CBOR
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/hex"
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/fxamacker/cbor/v2"
|
|
||||||
)
|
|
||||||
|
|
||||||
type GrandChild struct {
|
|
||||||
Quux int `json:",omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Child struct {
|
|
||||||
Baz int `json:",omitempty"`
|
|
||||||
Qux GrandChild `json:",omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Parent struct {
|
|
||||||
Foo Child `json:",omitempty"`
|
|
||||||
Bar int `json:",omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func cb() {
|
|
||||||
results, _ := cbor.Marshal(Parent{})
|
|
||||||
fmt.Println("hex(CBOR): " + hex.EncodeToString(results))
|
|
||||||
|
|
||||||
text, _ := cbor.Diagnose(results) // Diagnostic Notation
|
|
||||||
fmt.Println("DN: " + text)
|
|
||||||
}
|
|
||||||
|
|
||||||
func js() {
|
|
||||||
results, _ := json.Marshal(Parent{})
|
|
||||||
fmt.Println("hex(JSON): " + hex.EncodeToString(results))
|
|
||||||
|
|
||||||
text := string(results) // JSON
|
|
||||||
fmt.Println("JSON: " + text)
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
cb()
|
|
||||||
fmt.Println("-------------")
|
|
||||||
js()
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Output (DN is Diagnostic Notation):
|
|
||||||
```
|
|
||||||
hex(CBOR): a0
|
|
||||||
DN: {}
|
|
||||||
-------------
|
|
||||||
hex(JSON): 7b22466f6f223a7b22517578223a7b7d7d7d
|
|
||||||
JSON: {"Foo":{"Qux":{}}}
|
|
||||||
```
|
|
||||||
|
|
||||||
<hr/>
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
Example using different struct tags together:
|
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
API is mostly same as `encoding/json`, plus interfaces that simplify concurrency for CBOR options.
|
> [!NOTE]
|
||||||
|
> `fxamacker/cbor` can encode a 3-level nested Go struct to 1 byte!
|
||||||
|
> - `encoding/json`: 18 bytes of JSON
|
||||||
|
> - `fxamacker/cbor`: 1 byte of CBOR
|
||||||
|
>
|
||||||
|
> <details><summary> 🔎 Encoding 3-level nested Go struct with omitempty</summary><p/>
|
||||||
|
>
|
||||||
|
> https://go.dev/play/p/YxwvfPdFQG2
|
||||||
|
>
|
||||||
|
> ```Go
|
||||||
|
> // Example encoding nested struct (with omitempty tag)
|
||||||
|
> // - encoding/json: 18 byte JSON
|
||||||
|
> // - fxamacker/cbor: 1 byte CBOR
|
||||||
|
>
|
||||||
|
> package main
|
||||||
|
>
|
||||||
|
> import (
|
||||||
|
> "encoding/hex"
|
||||||
|
> "encoding/json"
|
||||||
|
> "fmt"
|
||||||
|
>
|
||||||
|
> "github.com/fxamacker/cbor/v2"
|
||||||
|
> )
|
||||||
|
>
|
||||||
|
> type GrandChild struct {
|
||||||
|
> Quux int `json:",omitempty"`
|
||||||
|
> }
|
||||||
|
>
|
||||||
|
> type Child struct {
|
||||||
|
> Baz int `json:",omitempty"`
|
||||||
|
> Qux GrandChild `json:",omitempty"`
|
||||||
|
> }
|
||||||
|
>
|
||||||
|
> type Parent struct {
|
||||||
|
> Foo Child `json:",omitempty"`
|
||||||
|
> Bar int `json:",omitempty"`
|
||||||
|
> }
|
||||||
|
>
|
||||||
|
> func cb() {
|
||||||
|
> results, _ := cbor.Marshal(Parent{})
|
||||||
|
> fmt.Println("hex(CBOR): " + hex.EncodeToString(results))
|
||||||
|
>
|
||||||
|
> text, _ := cbor.Diagnose(results) // Diagnostic Notation
|
||||||
|
> fmt.Println("DN: " + text)
|
||||||
|
> }
|
||||||
|
>
|
||||||
|
> func js() {
|
||||||
|
> results, _ := json.Marshal(Parent{})
|
||||||
|
> fmt.Println("hex(JSON): " + hex.EncodeToString(results))
|
||||||
|
>
|
||||||
|
> text := string(results) // JSON
|
||||||
|
> fmt.Println("JSON: " + text)
|
||||||
|
> }
|
||||||
|
>
|
||||||
|
> func main() {
|
||||||
|
> cb()
|
||||||
|
> fmt.Println("-------------")
|
||||||
|
> js()
|
||||||
|
> }
|
||||||
|
> ```
|
||||||
|
>
|
||||||
|
> Output (DN is Diagnostic Notation):
|
||||||
|
> ```
|
||||||
|
> hex(CBOR): a0
|
||||||
|
> DN: {}
|
||||||
|
> -------------
|
||||||
|
> hex(JSON): 7b22466f6f223a7b22517578223a7b7d7d7d
|
||||||
|
> JSON: {"Foo":{"Qux":{}}}
|
||||||
|
> ```
|
||||||
|
>
|
||||||
|
> </details>
|
||||||
|
|
||||||
|
|
||||||
## Quick Start
|
## Quick Start
|
||||||
|
|
||||||
__Install__: `go get github.com/fxamacker/cbor/v2` and `import "github.com/fxamacker/cbor/v2"`.
|
__Install__: `go get github.com/fxamacker/cbor/v2` and `import "github.com/fxamacker/cbor/v2"`.
|
||||||
|
|
||||||
|
> [!TIP]
|
||||||
|
>
|
||||||
|
> Tinygo users can try beta/experimental branch [feature/cbor-tinygo-beta](https://github.com/fxamacker/cbor/tree/feature/cbor-tinygo-beta).
|
||||||
|
>
|
||||||
|
> <details><summary> 🔎 More about tinygo feature branch</summary>
|
||||||
|
>
|
||||||
|
> ### Tinygo
|
||||||
|
>
|
||||||
|
> Branch [feature/cbor-tinygo-beta](https://github.com/fxamacker/cbor/tree/feature/cbor-tinygo-beta) is based on fxamacker/cbor v2.7.0 and it can be compiled using tinygo v0.33 (also compiles with golang/go).
|
||||||
|
>
|
||||||
|
> It passes unit tests (with both go1.22 and tinygo v0.33) and is considered beta/experimental for tinygo.
|
||||||
|
>
|
||||||
|
> :warning: The `feature/cbor-tinygo-beta` branch does not get fuzz tested yet.
|
||||||
|
>
|
||||||
|
> Changes in this feature branch only affect tinygo compiled software. Summary of changes:
|
||||||
|
> - default `DecOptions.MaxNestedLevels` is reduced to 16 (was 32). User can specify higher limit but 24+ crashes tests when compiled with tinygo v0.33.
|
||||||
|
> - disabled decoding CBOR tag data to Go interface because tinygo v0.33 is missing needed feature.
|
||||||
|
> - encoding error message can be different when encoding function type.
|
||||||
|
>
|
||||||
|
> Related tinygo issues:
|
||||||
|
> - https://github.com/tinygo-org/tinygo/issues/4277
|
||||||
|
> - https://github.com/tinygo-org/tinygo/issues/4458
|
||||||
|
>
|
||||||
|
> </details>
|
||||||
|
|
||||||
|
|
||||||
### Key Points
|
### Key Points
|
||||||
|
|
||||||
This library can encode and decode CBOR (RFC 8949) and CBOR Sequences (RFC 8742).
|
This library can encode and decode CBOR (RFC 8949) and CBOR Sequences (RFC 8742).
|
||||||
@@ -252,16 +294,17 @@ rest, err = cbor.UnmarshalFirst(b, &v) // decode []byte b to v
|
|||||||
// DiagnoseFirst translates first CBOR data item to text and returns remaining bytes.
|
// DiagnoseFirst translates first CBOR data item to text and returns remaining bytes.
|
||||||
text, rest, err = cbor.DiagnoseFirst(b) // decode []byte b to Diagnostic Notation text
|
text, rest, err = cbor.DiagnoseFirst(b) // decode []byte b to Diagnostic Notation text
|
||||||
|
|
||||||
// NOTE: Unmarshal returns ExtraneousDataError if there are remaining bytes,
|
// NOTE: Unmarshal() returns ExtraneousDataError if there are remaining bytes, but
|
||||||
// but new funcs UnmarshalFirst and DiagnoseFirst do not.
|
// UnmarshalFirst() and DiagnoseFirst() allow trailing bytes.
|
||||||
```
|
```
|
||||||
|
|
||||||
__IMPORTANT__: 👉 CBOR settings allow trade-offs between speed, security, encoding size, etc.
|
> [!IMPORTANT]
|
||||||
|
> CBOR settings allow trade-offs between speed, security, encoding size, etc.
|
||||||
- Different CBOR libraries may use different default settings.
|
>
|
||||||
- CBOR-based formats or protocols usually require specific settings.
|
> - Different CBOR libraries may use different default settings.
|
||||||
|
> - CBOR-based formats or protocols usually require specific settings.
|
||||||
For example, WebAuthn uses "CTAP2 Canonical CBOR" which is available as a preset.
|
>
|
||||||
|
> For example, WebAuthn uses "CTAP2 Canonical CBOR" which is available as a preset.
|
||||||
|
|
||||||
### Presets
|
### Presets
|
||||||
|
|
||||||
@@ -312,9 +355,63 @@ err = em.MarshalToBuffer(v, &buf) // encode v to provided buf
|
|||||||
|
|
||||||
### Struct Tags
|
### Struct Tags
|
||||||
|
|
||||||
Struct tags (`toarray`, `keyasint`, `omitempty`) reduce encoded size of structs.
|
Struct tag options (`toarray`, `keyasint`, `omitempty`, `omitzero`) reduce encoded size of structs.
|
||||||
|
|
||||||
<details><summary>Example encoding 3-level nested Go struct to 1 byte CBOR</summary><p/>
|
As a special case, struct field tag "-" omits the field.
|
||||||
|
|
||||||
|
<details><summary> 🔎 Example encoding with struct field tag "-"</summary><p/>
|
||||||
|
|
||||||
|
https://go.dev/play/p/aWEIFxd7InX
|
||||||
|
|
||||||
|
```Go
|
||||||
|
// https://github.com/fxamacker/cbor/issues/652
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/fxamacker/cbor/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
// The `cbor:"-"` tag omits the Type field when encoding to CBOR.
|
||||||
|
type Entity struct {
|
||||||
|
_ struct{} `cbor:",toarray"`
|
||||||
|
ID uint64 `json:"id"`
|
||||||
|
Type string `cbor:"-" json:"typeOf"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
entity := Entity{
|
||||||
|
ID: 1,
|
||||||
|
Type: "int64",
|
||||||
|
Name: "Identifier",
|
||||||
|
}
|
||||||
|
|
||||||
|
c, _ := cbor.Marshal(entity)
|
||||||
|
diag, _ := cbor.Diagnose(c)
|
||||||
|
fmt.Printf("CBOR in hex: %x\n", c)
|
||||||
|
fmt.Printf("CBOR in edn: %s\n", diag)
|
||||||
|
|
||||||
|
j, _ := json.Marshal(entity)
|
||||||
|
fmt.Printf("JSON: %s\n", string(j))
|
||||||
|
|
||||||
|
fmt.Printf("JSON encoding is %d bytes\n", len(j))
|
||||||
|
fmt.Printf("CBOR encoding is %d bytes\n", len(c))
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// CBOR in hex: 82016a4964656e746966696572
|
||||||
|
// CBOR in edn: [1, "Identifier"]
|
||||||
|
// JSON: {"id":1,"typeOf":"int64","name":"Identifier"}
|
||||||
|
// JSON encoding is 45 bytes
|
||||||
|
// CBOR encoding is 13 bytes
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details><summary> 🔎 Example encoding 3-level nested Go struct to 1 byte CBOR</summary><p/>
|
||||||
|
|
||||||
https://go.dev/play/p/YxwvfPdFQG2
|
https://go.dev/play/p/YxwvfPdFQG2
|
||||||
|
|
||||||
@@ -382,13 +479,13 @@ JSON: {"Foo":{"Qux":{}}}
|
|||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
<details><summary>Example using several struct tags</summary><p/>
|
<details><summary> 🔎 Example using struct tag options</summary><p/>
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
Struct tags simplify use of CBOR-based protocols that require CBOR arrays or maps with integer keys.
|
Struct tag options simplify use of CBOR-based protocols that require CBOR arrays or maps with integer keys.
|
||||||
|
|
||||||
### CBOR Tags
|
### CBOR Tags
|
||||||
|
|
||||||
@@ -404,7 +501,7 @@ em, err := opts.EncModeWithSharedTags(ts) // mutable shared CBOR tags
|
|||||||
|
|
||||||
`TagSet` and modes using it are safe for concurrent use. Equivalent API is available for `DecMode`.
|
`TagSet` and modes using it are safe for concurrent use. Equivalent API is available for `DecMode`.
|
||||||
|
|
||||||
<details><summary>Example using TagSet and TagOptions</summary><p/>
|
<details><summary> 🔎 Example using TagSet and TagOptions</summary><p/>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// Use signedCWT struct defined in "Decoding CWT" example.
|
// Use signedCWT struct defined in "Decoding CWT" example.
|
||||||
@@ -430,16 +527,149 @@ if err := dm.Unmarshal(data, &v); err != nil {
|
|||||||
em, _ := cbor.EncOptions{}.EncModeWithTags(tags)
|
em, _ := cbor.EncOptions{}.EncModeWithTags(tags)
|
||||||
|
|
||||||
// Marshal signedCWT with tag number.
|
// Marshal signedCWT with tag number.
|
||||||
if data, err := cbor.Marshal(v); err != nil {
|
if data, err := em.Marshal(v); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
👉 `fxamacker/cbor` allows user apps to use almost any current or future CBOR tag number by implementing `cbor.Marshaler` and `cbor.Unmarshaler` interfaces.
|
||||||
|
|
||||||
|
Basically, `MarshalCBOR` and `UnmarshalCBOR` functions can be implemented by user apps and those functions will automatically be called by this CBOR codec's `Marshal`, `Unmarshal`, etc.
|
||||||
|
|
||||||
|
The following [example](https://github.com/fxamacker/cbor/blob/master/example_embedded_json_tag_for_cbor_test.go) shows how to encode and decode a tagged CBOR data item with tag number 262. The tag content is a JSON object "embedded" as a CBOR byte string (major type 2).
|
||||||
|
|
||||||
|
<details><summary> 🔎 Example using Embedded JSON Tag for CBOR (tag 262)</summary>
|
||||||
|
|
||||||
|
```go
|
||||||
|
// https://github.com/fxamacker/cbor/issues/657
|
||||||
|
|
||||||
|
package cbor_test
|
||||||
|
|
||||||
|
// NOTE: RFC 8949 does not mention tag number 262. IANA assigned
|
||||||
|
// CBOR tag number 262 as "Embedded JSON Object" specified by the
|
||||||
|
// document Embedded JSON Tag for CBOR:
|
||||||
|
//
|
||||||
|
// "Tag 262 can be applied to a byte string (major type 2) to indicate
|
||||||
|
// that the byte string is a JSON Object. The length of the byte string
|
||||||
|
// indicates the content."
|
||||||
|
//
|
||||||
|
// For more info, see Embedded JSON Tag for CBOR at:
|
||||||
|
// https://github.com/toravir/CBOR-Tag-Specs/blob/master/embeddedJSON.md
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/fxamacker/cbor/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
// cborTagNumForEmbeddedJSON is the CBOR tag number 262.
|
||||||
|
const cborTagNumForEmbeddedJSON = 262
|
||||||
|
|
||||||
|
// EmbeddedJSON represents a Go value to be encoded as a tagged CBOR data item
|
||||||
|
// with tag number 262 and the tag content is a JSON object "embedded" as a
|
||||||
|
// CBOR byte string (major type 2).
|
||||||
|
type EmbeddedJSON struct {
|
||||||
|
any
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewEmbeddedJSON(val any) EmbeddedJSON {
|
||||||
|
return EmbeddedJSON{val}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalCBOR encodes EmbeddedJSON to a tagged CBOR data item with the
|
||||||
|
// tag number 262 and the tag content is a JSON object that is
|
||||||
|
// "embedded" as a CBOR byte string.
|
||||||
|
func (v EmbeddedJSON) MarshalCBOR() ([]byte, error) {
|
||||||
|
// Encode v to JSON object.
|
||||||
|
data, err := json.Marshal(v)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create cbor.Tag representing a tagged CBOR data item.
|
||||||
|
tag := cbor.Tag{
|
||||||
|
Number: cborTagNumForEmbeddedJSON,
|
||||||
|
Content: data,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Marshal to a tagged CBOR data item.
|
||||||
|
return cbor.Marshal(tag)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalCBOR decodes a tagged CBOR data item to EmbeddedJSON.
|
||||||
|
// The byte slice provided to this function must contain a single
|
||||||
|
// tagged CBOR data item with the tag number 262 and tag content
|
||||||
|
// must be a JSON object "embedded" as a CBOR byte string.
|
||||||
|
func (v *EmbeddedJSON) UnmarshalCBOR(b []byte) error {
|
||||||
|
// Unmarshal tagged CBOR data item.
|
||||||
|
var tag cbor.Tag
|
||||||
|
if err := cbor.Unmarshal(b, &tag); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check tag number.
|
||||||
|
if tag.Number != cborTagNumForEmbeddedJSON {
|
||||||
|
return fmt.Errorf("got tag number %d, expect tag number %d", tag.Number, cborTagNumForEmbeddedJSON)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check tag content.
|
||||||
|
jsonData, isByteString := tag.Content.([]byte)
|
||||||
|
if !isByteString {
|
||||||
|
return fmt.Errorf("got tag content type %T, expect tag content []byte", tag.Content)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmarshal JSON object.
|
||||||
|
return json.Unmarshal(jsonData, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON encodes EmbeddedJSON to a JSON object.
|
||||||
|
func (v EmbeddedJSON) MarshalJSON() ([]byte, error) {
|
||||||
|
return json.Marshal(v.any)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON decodes a JSON object.
|
||||||
|
func (v *EmbeddedJSON) UnmarshalJSON(b []byte) error {
|
||||||
|
dec := json.NewDecoder(bytes.NewReader(b))
|
||||||
|
dec.UseNumber()
|
||||||
|
return dec.Decode(&v.any)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Example_embeddedJSONTagForCBOR() {
|
||||||
|
value := NewEmbeddedJSON(map[string]any{
|
||||||
|
"name": "gopher",
|
||||||
|
"id": json.Number("42"),
|
||||||
|
})
|
||||||
|
|
||||||
|
data, err := cbor.Marshal(value)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("cbor: %x\n", data)
|
||||||
|
|
||||||
|
var v EmbeddedJSON
|
||||||
|
err = cbor.Unmarshal(data, &v)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("%+v\n", v.any)
|
||||||
|
for k, v := range v.any.(map[string]any) {
|
||||||
|
fmt.Printf(" %s: %v (%T)\n", k, v, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
|
||||||
### Functions and Interfaces
|
### Functions and Interfaces
|
||||||
|
|
||||||
<details><summary>Functions and interfaces at a glance</summary><p/>
|
<details><summary> 🔎 Functions and interfaces at a glance</summary><p/>
|
||||||
|
|
||||||
Common functions with same API as `encoding/json`:
|
Common functions with same API as `encoding/json`:
|
||||||
- `Marshal`, `Unmarshal`
|
- `Marshal`, `Unmarshal`
|
||||||
@@ -453,7 +683,7 @@ because RFC 8949 treats CBOR data item with remaining bytes as malformed.
|
|||||||
Other useful functions:
|
Other useful functions:
|
||||||
- `Diagnose`, `DiagnoseFirst` produce human-readable [Extended Diagnostic Notation](https://www.rfc-editor.org/rfc/rfc8610.html#appendix-G) from CBOR data.
|
- `Diagnose`, `DiagnoseFirst` produce human-readable [Extended Diagnostic Notation](https://www.rfc-editor.org/rfc/rfc8610.html#appendix-G) from CBOR data.
|
||||||
- `UnmarshalFirst` decodes first CBOR data item and return any remaining bytes.
|
- `UnmarshalFirst` decodes first CBOR data item and return any remaining bytes.
|
||||||
- `Wellformed` returns true if the the CBOR data item is well-formed.
|
- `Wellformed` returns true if the CBOR data item is well-formed.
|
||||||
|
|
||||||
Interfaces identical or comparable to Go `encoding` packages include:
|
Interfaces identical or comparable to Go `encoding` packages include:
|
||||||
`Marshaler`, `Unmarshaler`, `BinaryMarshaler`, and `BinaryUnmarshaler`.
|
`Marshaler`, `Unmarshaler`, `BinaryMarshaler`, and `BinaryUnmarshaler`.
|
||||||
@@ -472,15 +702,28 @@ Default limits may need to be increased for systems handling very large data (e.
|
|||||||
|
|
||||||
## Status
|
## Status
|
||||||
|
|
||||||
v2.7.0 (June 23, 2024) adds features and improvements that help large projects (e.g. Kubernetes) use CBOR as an alternative to JSON and Protocol Buffers. Other improvements include speedups, improved memory use, bug fixes, new serialization options, etc. It passed fuzz tests (5+ billion executions) and is production quality.
|
[v2.9.0](https://github.com/fxamacker/cbor/releases/tag/v2.9.0) (Jul 13, 2025) improved interoperability/transcoding between CBOR & JSON, refactored tests, and improved docs.
|
||||||
|
- Add opt-in support for `encoding.TextMarshaler` and `encoding.TextUnmarshaler` to encode and decode from CBOR text string.
|
||||||
|
- Add opt-in support for `json.Marshaler` and `json.Unmarshaler` via user-provided transcoding function.
|
||||||
|
- Update docs for TimeMode, Tag, RawTag, and add example for Embedded JSON Tag for CBOR.
|
||||||
|
|
||||||
|
v2.9.0 passed fuzz tests and is production quality.
|
||||||
|
|
||||||
|
The minimum version of Go required to build:
|
||||||
|
- v2.8.0 and newer releases require go 1.20+.
|
||||||
|
- v2.7.1 and older releases require go 1.17+.
|
||||||
|
|
||||||
For more details, see [release notes](https://github.com/fxamacker/cbor/releases).
|
For more details, see [release notes](https://github.com/fxamacker/cbor/releases).
|
||||||
|
|
||||||
### Prior Release
|
### Prior Releases
|
||||||
|
|
||||||
|
[v2.8.0](https://github.com/fxamacker/cbor/releases/tag/v2.8.0) (March 30, 2025) is a small release primarily to add `omitzero` option to struct field tags and fix bugs. It passed fuzz tests (billions of executions) and is production quality.
|
||||||
|
|
||||||
|
[v2.7.0](https://github.com/fxamacker/cbor/releases/tag/v2.7.0) (June 23, 2024) adds features and improvements that help large projects (e.g. Kubernetes) use CBOR as an alternative to JSON and Protocol Buffers. Other improvements include speedups, improved memory use, bug fixes, new serialization options, etc. It passed fuzz tests (5+ billion executions) and is production quality.
|
||||||
|
|
||||||
[v2.6.0](https://github.com/fxamacker/cbor/releases/tag/v2.6.0) (February 2024) adds important new features, optimizations, and bug fixes. It is especially useful to systems that need to convert data between CBOR and JSON. New options and optimizations improve handling of bignum, integers, maps, and strings.
|
[v2.6.0](https://github.com/fxamacker/cbor/releases/tag/v2.6.0) (February 2024) adds important new features, optimizations, and bug fixes. It is especially useful to systems that need to convert data between CBOR and JSON. New options and optimizations improve handling of bignum, integers, maps, and strings.
|
||||||
|
|
||||||
v2.5.0 was released on Sunday, August 13, 2023 with new features and important bug fixes. It is fuzz tested and production quality after extended beta [v2.5.0-beta](https://github.com/fxamacker/cbor/releases/tag/v2.5.0-beta) (Dec 2022) -> [v2.5.0](https://github.com/fxamacker/cbor/releases/tag/v2.5.0) (Aug 2023).
|
[v2.5.0](https://github.com/fxamacker/cbor/releases/tag/v2.5.0) was released on Sunday, August 13, 2023 with new features and important bug fixes. It is fuzz tested and production quality after extended beta [v2.5.0-beta](https://github.com/fxamacker/cbor/releases/tag/v2.5.0-beta) (Dec 2022) -> [v2.5.0](https://github.com/fxamacker/cbor/releases/tag/v2.5.0) (Aug 2023).
|
||||||
|
|
||||||
__IMPORTANT__: 👉 Before upgrading from v2.4 or older release, please read the notable changes highlighted in the release notes. v2.5.0 is a large release with bug fixes to error handling for extraneous data in `Unmarshal`, etc. that should be reviewed before upgrading.
|
__IMPORTANT__: 👉 Before upgrading from v2.4 or older release, please read the notable changes highlighted in the release notes. v2.5.0 is a large release with bug fixes to error handling for extraneous data in `Unmarshal`, etc. that should be reviewed before upgrading.
|
||||||
|
|
||||||
@@ -489,7 +732,7 @@ See [v2.5.0 release notes](https://github.com/fxamacker/cbor/releases/tag/v2.5.0
|
|||||||
See ["Version and API Changes"](https://github.com/fxamacker/cbor#versions-and-api-changes) section for more info about version numbering, etc.
|
See ["Version and API Changes"](https://github.com/fxamacker/cbor#versions-and-api-changes) section for more info about version numbering, etc.
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
<details><summary>👉 Benchmark Comparison: v2.4.0 vs v2.5.0</summary><p/>
|
<details><summary> 🔎 Benchmark Comparison: v2.4.0 vs v2.5.0</summary><p/>
|
||||||
|
|
||||||
TODO: Update to v2.4.0 vs 2.5.0 (not beta2).
|
TODO: Update to v2.4.0 vs 2.5.0 (not beta2).
|
||||||
|
|
||||||
@@ -549,9 +792,9 @@ geomean 2.782
|
|||||||
|
|
||||||
## Who uses fxamacker/cbor
|
## Who uses fxamacker/cbor
|
||||||
|
|
||||||
`fxamacker/cbor` is used in projects by Arm Ltd., Berlin Institute of Health at Charité, Chainlink, Cisco, Confidential Computing Consortium, ConsenSys, Dapper Labs, EdgeX Foundry, F5, FIDO Alliance, Fraunhofer‑AISEC, Kubernetes, Let's Encrypt (ISRG), Linux Foundation, Matrix.org, Microsoft, Mozilla, National Cybersecurity Agency of France (govt), Netherlands (govt), Oasis Protocol, Smallstep, Tailscale, Taurus SA, Teleport, TIBCO, and others.
|
`fxamacker/cbor` is used in projects by Arm Ltd., Berlin Institute of Health at Charité, Chainlink, Confidential Computing Consortium, ConsenSys, EdgeX Foundry, F5, Flow Foundation, Fraunhofer‑AISEC, IBM, Kubernetes, Let's Encrypt (ISRG), Linaro, Linux Foundation, Matrix.org, Microsoft, National Cybersecurity Agency of France (govt), Netherlands (govt), Oasis Protocol, Red Hat OpenShift, Smallstep, Tailscale, Taurus SA, TIBCO, Veraison, and others.
|
||||||
|
|
||||||
`fxamacker/cbor` passed multiple confidential security assessments. A [nonconfidential security assessment](https://github.com/veraison/go-cose/blob/v1.0.0-rc.1/reports/NCC_Microsoft-go-cose-Report_2022-05-26_v1.0.pdf) (prepared by NCC Group for Microsoft Corporation) includes a subset of fxamacker/cbor v2.4.0 in its scope.
|
`fxamacker/cbor` passed multiple confidential security assessments in 2022. A [nonconfidential security assessment](https://github.com/veraison/go-cose/blob/v1.0.0-rc.1/reports/NCC_Microsoft-go-cose-Report_2022-05-26_v1.0.pdf) (prepared by NCC Group for Microsoft Corporation) assessed a subset of fxamacker/cbor v2.4.
|
||||||
|
|
||||||
## Standards
|
## Standards
|
||||||
|
|
||||||
@@ -588,7 +831,7 @@ By default, decoder treats time values of floating-point NaN and Infinity as if
|
|||||||
__Click to expand topic:__
|
__Click to expand topic:__
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary>Duplicate Map Keys</summary><p>
|
<summary> 🔎 Duplicate Map Keys</summary><p>
|
||||||
|
|
||||||
This library provides options for fast detection and rejection of duplicate map keys based on applying a Go-specific data model to CBOR's extended generic data model in order to determine duplicate vs distinct map keys. Detection relies on whether the CBOR map key would be a duplicate "key" when decoded and applied to the user-provided Go map or struct.
|
This library provides options for fast detection and rejection of duplicate map keys based on applying a Go-specific data model to CBOR's extended generic data model in order to determine duplicate vs distinct map keys. Detection relies on whether the CBOR map key would be a duplicate "key" when decoded and applied to the user-provided Go map or struct.
|
||||||
|
|
||||||
@@ -601,7 +844,7 @@ APF suffix means "Allow Partial Fill" so the destination map or struct can conta
|
|||||||
</details>
|
</details>
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary>Tag Validity</summary><p>
|
<summary> 🔎 Tag Validity</summary><p>
|
||||||
|
|
||||||
This library checks tag validity for built-in tags (currently tag numbers 0, 1, 2, 3, and 55799):
|
This library checks tag validity for built-in tags (currently tag numbers 0, 1, 2, 3, and 55799):
|
||||||
|
|
||||||
|
|||||||
27
vendor/github.com/fxamacker/cbor/v2/bytestring.go
generated
vendored
27
vendor/github.com/fxamacker/cbor/v2/bytestring.go
generated
vendored
@@ -38,11 +38,38 @@ func (bs ByteString) MarshalCBOR() ([]byte, error) {
|
|||||||
|
|
||||||
// UnmarshalCBOR decodes CBOR byte string (major type 2) to ByteString.
|
// UnmarshalCBOR decodes CBOR byte string (major type 2) to ByteString.
|
||||||
// Decoding CBOR null and CBOR undefined sets ByteString to be empty.
|
// Decoding CBOR null and CBOR undefined sets ByteString to be empty.
|
||||||
|
//
|
||||||
|
// Deprecated: No longer used by this codec; kept for compatibility
|
||||||
|
// with user apps that directly call this function.
|
||||||
func (bs *ByteString) UnmarshalCBOR(data []byte) error {
|
func (bs *ByteString) UnmarshalCBOR(data []byte) error {
|
||||||
if bs == nil {
|
if bs == nil {
|
||||||
return errors.New("cbor.ByteString: UnmarshalCBOR on nil pointer")
|
return errors.New("cbor.ByteString: UnmarshalCBOR on nil pointer")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
d := decoder{data: data, dm: defaultDecMode}
|
||||||
|
|
||||||
|
// Check well-formedness of CBOR data item.
|
||||||
|
// ByteString.UnmarshalCBOR() is exported, so
|
||||||
|
// the codec needs to support same behavior for:
|
||||||
|
// - Unmarshal(data, *ByteString)
|
||||||
|
// - ByteString.UnmarshalCBOR(data)
|
||||||
|
err := d.wellformed(false, false)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return bs.unmarshalCBOR(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// unmarshalCBOR decodes CBOR byte string (major type 2) to ByteString.
|
||||||
|
// Decoding CBOR null and CBOR undefined sets ByteString to be empty.
|
||||||
|
// This function assumes data is well-formed, and does not perform bounds checking.
|
||||||
|
// This function is called by Unmarshal().
|
||||||
|
func (bs *ByteString) unmarshalCBOR(data []byte) error {
|
||||||
|
if bs == nil {
|
||||||
|
return errors.New("cbor.ByteString: UnmarshalCBOR on nil pointer")
|
||||||
|
}
|
||||||
|
|
||||||
// Decoding CBOR null and CBOR undefined to ByteString resets data.
|
// Decoding CBOR null and CBOR undefined to ByteString resets data.
|
||||||
// This behavior is similar to decoding CBOR null and CBOR undefined to []byte.
|
// This behavior is similar to decoding CBOR null and CBOR undefined to []byte.
|
||||||
if len(data) == 1 && (data[0] == 0xf6 || data[0] == 0xf7) {
|
if len(data) == 1 && (data[0] == 0xf6 || data[0] == 0xf7) {
|
||||||
|
|||||||
25
vendor/github.com/fxamacker/cbor/v2/cache.go
generated
vendored
25
vendor/github.com/fxamacker/cbor/v2/cache.go
generated
vendored
@@ -17,6 +17,7 @@ import (
|
|||||||
type encodeFuncs struct {
|
type encodeFuncs struct {
|
||||||
ef encodeFunc
|
ef encodeFunc
|
||||||
ief isEmptyFunc
|
ief isEmptyFunc
|
||||||
|
izf isZeroFunc
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -31,10 +32,12 @@ type specialType int
|
|||||||
const (
|
const (
|
||||||
specialTypeNone specialType = iota
|
specialTypeNone specialType = iota
|
||||||
specialTypeUnmarshalerIface
|
specialTypeUnmarshalerIface
|
||||||
|
specialTypeUnexportedUnmarshalerIface
|
||||||
specialTypeEmptyIface
|
specialTypeEmptyIface
|
||||||
specialTypeIface
|
specialTypeIface
|
||||||
specialTypeTag
|
specialTypeTag
|
||||||
specialTypeTime
|
specialTypeTime
|
||||||
|
specialTypeJSONUnmarshalerIface
|
||||||
)
|
)
|
||||||
|
|
||||||
type typeInfo struct {
|
type typeInfo struct {
|
||||||
@@ -50,7 +53,7 @@ type typeInfo struct {
|
|||||||
func newTypeInfo(t reflect.Type) *typeInfo {
|
func newTypeInfo(t reflect.Type) *typeInfo {
|
||||||
tInfo := typeInfo{typ: t, kind: t.Kind()}
|
tInfo := typeInfo{typ: t, kind: t.Kind()}
|
||||||
|
|
||||||
for t.Kind() == reflect.Ptr {
|
for t.Kind() == reflect.Pointer {
|
||||||
t = t.Elem()
|
t = t.Elem()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,8 +72,12 @@ func newTypeInfo(t reflect.Type) *typeInfo {
|
|||||||
tInfo.spclType = specialTypeTag
|
tInfo.spclType = specialTypeTag
|
||||||
} else if t == typeTime {
|
} else if t == typeTime {
|
||||||
tInfo.spclType = specialTypeTime
|
tInfo.spclType = specialTypeTime
|
||||||
} else if reflect.PtrTo(t).Implements(typeUnmarshaler) {
|
} else if reflect.PointerTo(t).Implements(typeUnexportedUnmarshaler) {
|
||||||
|
tInfo.spclType = specialTypeUnexportedUnmarshalerIface
|
||||||
|
} else if reflect.PointerTo(t).Implements(typeUnmarshaler) {
|
||||||
tInfo.spclType = specialTypeUnmarshalerIface
|
tInfo.spclType = specialTypeUnmarshalerIface
|
||||||
|
} else if reflect.PointerTo(t).Implements(typeJSONUnmarshaler) {
|
||||||
|
tInfo.spclType = specialTypeJSONUnmarshalerIface
|
||||||
}
|
}
|
||||||
|
|
||||||
switch k {
|
switch k {
|
||||||
@@ -237,7 +244,7 @@ func getEncodingStructType(t reflect.Type) (*encodingStructType, error) {
|
|||||||
e := getEncodeBuffer()
|
e := getEncodeBuffer()
|
||||||
for i := 0; i < len(flds); i++ {
|
for i := 0; i < len(flds); i++ {
|
||||||
// Get field's encodeFunc
|
// Get field's encodeFunc
|
||||||
flds[i].ef, flds[i].ief = getEncodeFunc(flds[i].typ)
|
flds[i].ef, flds[i].ief, flds[i].izf = getEncodeFunc(flds[i].typ)
|
||||||
if flds[i].ef == nil {
|
if flds[i].ef == nil {
|
||||||
err = &UnsupportedTypeError{t}
|
err = &UnsupportedTypeError{t}
|
||||||
break
|
break
|
||||||
@@ -321,7 +328,7 @@ func getEncodingStructType(t reflect.Type) (*encodingStructType, error) {
|
|||||||
func getEncodingStructToArrayType(t reflect.Type, flds fields) (*encodingStructType, error) {
|
func getEncodingStructToArrayType(t reflect.Type, flds fields) (*encodingStructType, error) {
|
||||||
for i := 0; i < len(flds); i++ {
|
for i := 0; i < len(flds); i++ {
|
||||||
// Get field's encodeFunc
|
// Get field's encodeFunc
|
||||||
flds[i].ef, flds[i].ief = getEncodeFunc(flds[i].typ)
|
flds[i].ef, flds[i].ief, flds[i].izf = getEncodeFunc(flds[i].typ)
|
||||||
if flds[i].ef == nil {
|
if flds[i].ef == nil {
|
||||||
structType := &encodingStructType{err: &UnsupportedTypeError{t}}
|
structType := &encodingStructType{err: &UnsupportedTypeError{t}}
|
||||||
encodingStructTypeCache.Store(t, structType)
|
encodingStructTypeCache.Store(t, structType)
|
||||||
@@ -337,14 +344,14 @@ func getEncodingStructToArrayType(t reflect.Type, flds fields) (*encodingStructT
|
|||||||
return structType, structType.err
|
return structType, structType.err
|
||||||
}
|
}
|
||||||
|
|
||||||
func getEncodeFunc(t reflect.Type) (encodeFunc, isEmptyFunc) {
|
func getEncodeFunc(t reflect.Type) (encodeFunc, isEmptyFunc, isZeroFunc) {
|
||||||
if v, _ := encodeFuncCache.Load(t); v != nil {
|
if v, _ := encodeFuncCache.Load(t); v != nil {
|
||||||
fs := v.(encodeFuncs)
|
fs := v.(encodeFuncs)
|
||||||
return fs.ef, fs.ief
|
return fs.ef, fs.ief, fs.izf
|
||||||
}
|
}
|
||||||
ef, ief := getEncodeFuncInternal(t)
|
ef, ief, izf := getEncodeFuncInternal(t)
|
||||||
encodeFuncCache.Store(t, encodeFuncs{ef, ief})
|
encodeFuncCache.Store(t, encodeFuncs{ef, ief, izf})
|
||||||
return ef, ief
|
return ef, ief, izf
|
||||||
}
|
}
|
||||||
|
|
||||||
func getTypeInfo(t reflect.Type) *typeInfo {
|
func getTypeInfo(t reflect.Type) *typeInfo {
|
||||||
|
|||||||
9
vendor/github.com/fxamacker/cbor/v2/common.go
generated
vendored
9
vendor/github.com/fxamacker/cbor/v2/common.go
generated
vendored
@@ -5,6 +5,7 @@ package cbor
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -180,3 +181,11 @@ func validBuiltinTag(tagNum uint64, contentHead byte) error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Transcoder is a scheme for transcoding a single CBOR encoded data item to or from a different
|
||||||
|
// data format.
|
||||||
|
type Transcoder interface {
|
||||||
|
// Transcode reads the data item in its source format from a Reader and writes a
|
||||||
|
// corresponding representation in its destination format to a Writer.
|
||||||
|
Transcode(dst io.Writer, src io.Reader) error
|
||||||
|
}
|
||||||
|
|||||||
425
vendor/github.com/fxamacker/cbor/v2/decode.go
generated
vendored
425
vendor/github.com/fxamacker/cbor/v2/decode.go
generated
vendored
@@ -4,6 +4,7 @@
|
|||||||
package cbor
|
package cbor
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"encoding"
|
"encoding"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
@@ -94,7 +95,7 @@ import (
|
|||||||
//
|
//
|
||||||
// To unmarshal CBOR null (0xf6) and undefined (0xf7) values into a
|
// To unmarshal CBOR null (0xf6) and undefined (0xf7) values into a
|
||||||
// slice/map/pointer, Unmarshal sets Go value to nil. Because null is often
|
// slice/map/pointer, Unmarshal sets Go value to nil. Because null is often
|
||||||
// used to mean "not present", unmarshalling CBOR null and undefined value
|
// used to mean "not present", unmarshaling CBOR null and undefined value
|
||||||
// into any other Go type has no effect and returns no error.
|
// into any other Go type has no effect and returns no error.
|
||||||
//
|
//
|
||||||
// Unmarshal supports CBOR tag 55799 (self-describe CBOR), tag 0 and 1 (time),
|
// Unmarshal supports CBOR tag 55799 (self-describe CBOR), tag 0 and 1 (time),
|
||||||
@@ -104,7 +105,7 @@ import (
|
|||||||
// if there are any remaining bytes following the first valid CBOR data item.
|
// if there are any remaining bytes following the first valid CBOR data item.
|
||||||
// See UnmarshalFirst, if you want to unmarshal only the first
|
// See UnmarshalFirst, if you want to unmarshal only the first
|
||||||
// CBOR data item without ExtraneousDataError caused by remaining bytes.
|
// CBOR data item without ExtraneousDataError caused by remaining bytes.
|
||||||
func Unmarshal(data []byte, v interface{}) error {
|
func Unmarshal(data []byte, v any) error {
|
||||||
return defaultDecMode.Unmarshal(data, v)
|
return defaultDecMode.Unmarshal(data, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,7 +115,7 @@ func Unmarshal(data []byte, v interface{}) error {
|
|||||||
// If v is nil, not a pointer, or a nil pointer, UnmarshalFirst returns an error.
|
// If v is nil, not a pointer, or a nil pointer, UnmarshalFirst returns an error.
|
||||||
//
|
//
|
||||||
// See the documentation for Unmarshal for details.
|
// See the documentation for Unmarshal for details.
|
||||||
func UnmarshalFirst(data []byte, v interface{}) (rest []byte, err error) {
|
func UnmarshalFirst(data []byte, v any) (rest []byte, err error) {
|
||||||
return defaultDecMode.UnmarshalFirst(data, v)
|
return defaultDecMode.UnmarshalFirst(data, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,6 +152,10 @@ type Unmarshaler interface {
|
|||||||
UnmarshalCBOR([]byte) error
|
UnmarshalCBOR([]byte) error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type unmarshaler interface {
|
||||||
|
unmarshalCBOR([]byte) error
|
||||||
|
}
|
||||||
|
|
||||||
// InvalidUnmarshalError describes an invalid argument passed to Unmarshal.
|
// InvalidUnmarshalError describes an invalid argument passed to Unmarshal.
|
||||||
type InvalidUnmarshalError struct {
|
type InvalidUnmarshalError struct {
|
||||||
s string
|
s string
|
||||||
@@ -193,12 +198,12 @@ func (e *InvalidMapKeyTypeError) Error() string {
|
|||||||
|
|
||||||
// DupMapKeyError describes detected duplicate map key in CBOR map.
|
// DupMapKeyError describes detected duplicate map key in CBOR map.
|
||||||
type DupMapKeyError struct {
|
type DupMapKeyError struct {
|
||||||
Key interface{}
|
Key any
|
||||||
Index int
|
Index int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *DupMapKeyError) Error() string {
|
func (e *DupMapKeyError) Error() string {
|
||||||
return fmt.Sprintf("cbor: found duplicate map key \"%v\" at map element index %d", e.Key, e.Index)
|
return fmt.Sprintf("cbor: found duplicate map key %#v at map element index %d", e.Key, e.Index)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnknownFieldError describes detected unknown field in CBOR map when decoding to Go struct.
|
// UnknownFieldError describes detected unknown field in CBOR map when decoding to Go struct.
|
||||||
@@ -383,7 +388,7 @@ const (
|
|||||||
// - return UnmarshalTypeError if value doesn't fit into int64
|
// - return UnmarshalTypeError if value doesn't fit into int64
|
||||||
IntDecConvertSignedOrFail
|
IntDecConvertSignedOrFail
|
||||||
|
|
||||||
// IntDecConvertSigned affects how CBOR integers (major type 0 and 1) decode to Go interface{}.
|
// IntDecConvertSignedOrBigInt affects how CBOR integers (major type 0 and 1) decode to Go interface{}.
|
||||||
// It makes CBOR integers (major type 0 and 1) decode to:
|
// It makes CBOR integers (major type 0 and 1) decode to:
|
||||||
// - int64 if value fits
|
// - int64 if value fits
|
||||||
// - big.Int or *big.Int (see BigIntDecMode) if value doesn't fit into int64
|
// - big.Int or *big.Int (see BigIntDecMode) if value doesn't fit into int64
|
||||||
@@ -489,11 +494,11 @@ type BigIntDecMode int
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
// BigIntDecodeValue makes CBOR bignum decode to big.Int (instead of *big.Int)
|
// BigIntDecodeValue makes CBOR bignum decode to big.Int (instead of *big.Int)
|
||||||
// when unmarshalling into a Go interface{}.
|
// when unmarshaling into a Go interface{}.
|
||||||
BigIntDecodeValue BigIntDecMode = iota
|
BigIntDecodeValue BigIntDecMode = iota
|
||||||
|
|
||||||
// BigIntDecodePointer makes CBOR bignum decode to *big.Int when
|
// BigIntDecodePointer makes CBOR bignum decode to *big.Int when
|
||||||
// unmarshalling into a Go interface{}.
|
// unmarshaling into a Go interface{}.
|
||||||
BigIntDecodePointer
|
BigIntDecodePointer
|
||||||
|
|
||||||
maxBigIntDecMode
|
maxBigIntDecMode
|
||||||
@@ -745,6 +750,25 @@ func (bum BinaryUnmarshalerMode) valid() bool {
|
|||||||
return bum >= 0 && bum < maxBinaryUnmarshalerMode
|
return bum >= 0 && bum < maxBinaryUnmarshalerMode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TextUnmarshalerMode specifies how to decode into types that implement
|
||||||
|
// encoding.TextUnmarshaler.
|
||||||
|
type TextUnmarshalerMode int
|
||||||
|
|
||||||
|
const (
|
||||||
|
// TextUnmarshalerNone does not recognize TextUnmarshaler implementations during decode.
|
||||||
|
TextUnmarshalerNone TextUnmarshalerMode = iota
|
||||||
|
|
||||||
|
// TextUnmarshalerTextString will invoke UnmarshalText on the contents of a CBOR text
|
||||||
|
// string when decoding into a value that implements TextUnmarshaler.
|
||||||
|
TextUnmarshalerTextString
|
||||||
|
|
||||||
|
maxTextUnmarshalerMode
|
||||||
|
)
|
||||||
|
|
||||||
|
func (tum TextUnmarshalerMode) valid() bool {
|
||||||
|
return tum >= 0 && tum < maxTextUnmarshalerMode
|
||||||
|
}
|
||||||
|
|
||||||
// DecOptions specifies decoding options.
|
// DecOptions specifies decoding options.
|
||||||
type DecOptions struct {
|
type DecOptions struct {
|
||||||
// DupMapKey specifies whether to enforce duplicate map key.
|
// DupMapKey specifies whether to enforce duplicate map key.
|
||||||
@@ -793,7 +817,7 @@ type DecOptions struct {
|
|||||||
// TagsMd specifies whether to allow CBOR tags (major type 6).
|
// TagsMd specifies whether to allow CBOR tags (major type 6).
|
||||||
TagsMd TagsMode
|
TagsMd TagsMode
|
||||||
|
|
||||||
// IntDec specifies which Go integer type (int64 or uint64) to use
|
// IntDec specifies which Go integer type (int64, uint64, or [big.Int]) to use
|
||||||
// when decoding CBOR int (major type 0 and 1) to Go interface{}.
|
// when decoding CBOR int (major type 0 and 1) to Go interface{}.
|
||||||
IntDec IntDecMode
|
IntDec IntDecMode
|
||||||
|
|
||||||
@@ -807,7 +831,7 @@ type DecOptions struct {
|
|||||||
ExtraReturnErrors ExtraDecErrorCond
|
ExtraReturnErrors ExtraDecErrorCond
|
||||||
|
|
||||||
// DefaultMapType specifies Go map type to create and decode to
|
// DefaultMapType specifies Go map type to create and decode to
|
||||||
// when unmarshalling CBOR into an empty interface value.
|
// when unmarshaling CBOR into an empty interface value.
|
||||||
// By default, unmarshal uses map[interface{}]interface{}.
|
// By default, unmarshal uses map[interface{}]interface{}.
|
||||||
DefaultMapType reflect.Type
|
DefaultMapType reflect.Type
|
||||||
|
|
||||||
@@ -879,6 +903,15 @@ type DecOptions struct {
|
|||||||
// BinaryUnmarshaler specifies how to decode into types that implement
|
// BinaryUnmarshaler specifies how to decode into types that implement
|
||||||
// encoding.BinaryUnmarshaler.
|
// encoding.BinaryUnmarshaler.
|
||||||
BinaryUnmarshaler BinaryUnmarshalerMode
|
BinaryUnmarshaler BinaryUnmarshalerMode
|
||||||
|
|
||||||
|
// TextUnmarshaler specifies how to decode into types that implement
|
||||||
|
// encoding.TextUnmarshaler.
|
||||||
|
TextUnmarshaler TextUnmarshalerMode
|
||||||
|
|
||||||
|
// JSONUnmarshalerTranscoder sets the transcoding scheme used to unmarshal types that
|
||||||
|
// implement json.Unmarshaler but do not also implement cbor.Unmarshaler. If nil, decoding
|
||||||
|
// behavior is not influenced by whether or not a type implements json.Unmarshaler.
|
||||||
|
JSONUnmarshalerTranscoder Transcoder
|
||||||
}
|
}
|
||||||
|
|
||||||
// DecMode returns DecMode with immutable options and no tags (safe for concurrency).
|
// DecMode returns DecMode with immutable options and no tags (safe for concurrency).
|
||||||
@@ -1091,33 +1124,39 @@ func (opts DecOptions) decMode() (*decMode, error) { //nolint:gocritic // ignore
|
|||||||
return nil, errors.New("cbor: invalid BinaryUnmarshaler " + strconv.Itoa(int(opts.BinaryUnmarshaler)))
|
return nil, errors.New("cbor: invalid BinaryUnmarshaler " + strconv.Itoa(int(opts.BinaryUnmarshaler)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !opts.TextUnmarshaler.valid() {
|
||||||
|
return nil, errors.New("cbor: invalid TextUnmarshaler " + strconv.Itoa(int(opts.TextUnmarshaler)))
|
||||||
|
}
|
||||||
|
|
||||||
dm := decMode{
|
dm := decMode{
|
||||||
dupMapKey: opts.DupMapKey,
|
dupMapKey: opts.DupMapKey,
|
||||||
timeTag: opts.TimeTag,
|
timeTag: opts.TimeTag,
|
||||||
maxNestedLevels: opts.MaxNestedLevels,
|
maxNestedLevels: opts.MaxNestedLevels,
|
||||||
maxArrayElements: opts.MaxArrayElements,
|
maxArrayElements: opts.MaxArrayElements,
|
||||||
maxMapPairs: opts.MaxMapPairs,
|
maxMapPairs: opts.MaxMapPairs,
|
||||||
indefLength: opts.IndefLength,
|
indefLength: opts.IndefLength,
|
||||||
tagsMd: opts.TagsMd,
|
tagsMd: opts.TagsMd,
|
||||||
intDec: opts.IntDec,
|
intDec: opts.IntDec,
|
||||||
mapKeyByteString: opts.MapKeyByteString,
|
mapKeyByteString: opts.MapKeyByteString,
|
||||||
extraReturnErrors: opts.ExtraReturnErrors,
|
extraReturnErrors: opts.ExtraReturnErrors,
|
||||||
defaultMapType: opts.DefaultMapType,
|
defaultMapType: opts.DefaultMapType,
|
||||||
utf8: opts.UTF8,
|
utf8: opts.UTF8,
|
||||||
fieldNameMatching: opts.FieldNameMatching,
|
fieldNameMatching: opts.FieldNameMatching,
|
||||||
bigIntDec: opts.BigIntDec,
|
bigIntDec: opts.BigIntDec,
|
||||||
defaultByteStringType: opts.DefaultByteStringType,
|
defaultByteStringType: opts.DefaultByteStringType,
|
||||||
byteStringToString: opts.ByteStringToString,
|
byteStringToString: opts.ByteStringToString,
|
||||||
fieldNameByteString: opts.FieldNameByteString,
|
fieldNameByteString: opts.FieldNameByteString,
|
||||||
unrecognizedTagToAny: opts.UnrecognizedTagToAny,
|
unrecognizedTagToAny: opts.UnrecognizedTagToAny,
|
||||||
timeTagToAny: opts.TimeTagToAny,
|
timeTagToAny: opts.TimeTagToAny,
|
||||||
simpleValues: simpleValues,
|
simpleValues: simpleValues,
|
||||||
nanDec: opts.NaN,
|
nanDec: opts.NaN,
|
||||||
infDec: opts.Inf,
|
infDec: opts.Inf,
|
||||||
byteStringToTime: opts.ByteStringToTime,
|
byteStringToTime: opts.ByteStringToTime,
|
||||||
byteStringExpectedFormat: opts.ByteStringExpectedFormat,
|
byteStringExpectedFormat: opts.ByteStringExpectedFormat,
|
||||||
bignumTag: opts.BignumTag,
|
bignumTag: opts.BignumTag,
|
||||||
binaryUnmarshaler: opts.BinaryUnmarshaler,
|
binaryUnmarshaler: opts.BinaryUnmarshaler,
|
||||||
|
textUnmarshaler: opts.TextUnmarshaler,
|
||||||
|
jsonUnmarshalerTranscoder: opts.JSONUnmarshalerTranscoder,
|
||||||
}
|
}
|
||||||
|
|
||||||
return &dm, nil
|
return &dm, nil
|
||||||
@@ -1130,7 +1169,7 @@ type DecMode interface {
|
|||||||
// Unmarshal returns an error.
|
// Unmarshal returns an error.
|
||||||
//
|
//
|
||||||
// See the documentation for Unmarshal for details.
|
// See the documentation for Unmarshal for details.
|
||||||
Unmarshal(data []byte, v interface{}) error
|
Unmarshal(data []byte, v any) error
|
||||||
|
|
||||||
// UnmarshalFirst parses the first CBOR data item into the value pointed to by v
|
// UnmarshalFirst parses the first CBOR data item into the value pointed to by v
|
||||||
// using the decoding mode. Any remaining bytes are returned in rest.
|
// using the decoding mode. Any remaining bytes are returned in rest.
|
||||||
@@ -1138,7 +1177,7 @@ type DecMode interface {
|
|||||||
// If v is nil, not a pointer, or a nil pointer, UnmarshalFirst returns an error.
|
// If v is nil, not a pointer, or a nil pointer, UnmarshalFirst returns an error.
|
||||||
//
|
//
|
||||||
// See the documentation for Unmarshal for details.
|
// See the documentation for Unmarshal for details.
|
||||||
UnmarshalFirst(data []byte, v interface{}) (rest []byte, err error)
|
UnmarshalFirst(data []byte, v any) (rest []byte, err error)
|
||||||
|
|
||||||
// Valid checks whether data is a well-formed encoded CBOR data item and
|
// Valid checks whether data is a well-formed encoded CBOR data item and
|
||||||
// that it complies with configurable restrictions such as MaxNestedLevels,
|
// that it complies with configurable restrictions such as MaxNestedLevels,
|
||||||
@@ -1170,33 +1209,35 @@ type DecMode interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type decMode struct {
|
type decMode struct {
|
||||||
tags tagProvider
|
tags tagProvider
|
||||||
dupMapKey DupMapKeyMode
|
dupMapKey DupMapKeyMode
|
||||||
timeTag DecTagMode
|
timeTag DecTagMode
|
||||||
maxNestedLevels int
|
maxNestedLevels int
|
||||||
maxArrayElements int
|
maxArrayElements int
|
||||||
maxMapPairs int
|
maxMapPairs int
|
||||||
indefLength IndefLengthMode
|
indefLength IndefLengthMode
|
||||||
tagsMd TagsMode
|
tagsMd TagsMode
|
||||||
intDec IntDecMode
|
intDec IntDecMode
|
||||||
mapKeyByteString MapKeyByteStringMode
|
mapKeyByteString MapKeyByteStringMode
|
||||||
extraReturnErrors ExtraDecErrorCond
|
extraReturnErrors ExtraDecErrorCond
|
||||||
defaultMapType reflect.Type
|
defaultMapType reflect.Type
|
||||||
utf8 UTF8Mode
|
utf8 UTF8Mode
|
||||||
fieldNameMatching FieldNameMatchingMode
|
fieldNameMatching FieldNameMatchingMode
|
||||||
bigIntDec BigIntDecMode
|
bigIntDec BigIntDecMode
|
||||||
defaultByteStringType reflect.Type
|
defaultByteStringType reflect.Type
|
||||||
byteStringToString ByteStringToStringMode
|
byteStringToString ByteStringToStringMode
|
||||||
fieldNameByteString FieldNameByteStringMode
|
fieldNameByteString FieldNameByteStringMode
|
||||||
unrecognizedTagToAny UnrecognizedTagToAnyMode
|
unrecognizedTagToAny UnrecognizedTagToAnyMode
|
||||||
timeTagToAny TimeTagToAnyMode
|
timeTagToAny TimeTagToAnyMode
|
||||||
simpleValues *SimpleValueRegistry
|
simpleValues *SimpleValueRegistry
|
||||||
nanDec NaNMode
|
nanDec NaNMode
|
||||||
infDec InfMode
|
infDec InfMode
|
||||||
byteStringToTime ByteStringToTimeMode
|
byteStringToTime ByteStringToTimeMode
|
||||||
byteStringExpectedFormat ByteStringExpectedFormatMode
|
byteStringExpectedFormat ByteStringExpectedFormatMode
|
||||||
bignumTag BignumTagMode
|
bignumTag BignumTagMode
|
||||||
binaryUnmarshaler BinaryUnmarshalerMode
|
binaryUnmarshaler BinaryUnmarshalerMode
|
||||||
|
textUnmarshaler TextUnmarshalerMode
|
||||||
|
jsonUnmarshalerTranscoder Transcoder
|
||||||
}
|
}
|
||||||
|
|
||||||
var defaultDecMode, _ = DecOptions{}.decMode()
|
var defaultDecMode, _ = DecOptions{}.decMode()
|
||||||
@@ -1211,32 +1252,34 @@ func (dm *decMode) DecOptions() DecOptions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return DecOptions{
|
return DecOptions{
|
||||||
DupMapKey: dm.dupMapKey,
|
DupMapKey: dm.dupMapKey,
|
||||||
TimeTag: dm.timeTag,
|
TimeTag: dm.timeTag,
|
||||||
MaxNestedLevels: dm.maxNestedLevels,
|
MaxNestedLevels: dm.maxNestedLevels,
|
||||||
MaxArrayElements: dm.maxArrayElements,
|
MaxArrayElements: dm.maxArrayElements,
|
||||||
MaxMapPairs: dm.maxMapPairs,
|
MaxMapPairs: dm.maxMapPairs,
|
||||||
IndefLength: dm.indefLength,
|
IndefLength: dm.indefLength,
|
||||||
TagsMd: dm.tagsMd,
|
TagsMd: dm.tagsMd,
|
||||||
IntDec: dm.intDec,
|
IntDec: dm.intDec,
|
||||||
MapKeyByteString: dm.mapKeyByteString,
|
MapKeyByteString: dm.mapKeyByteString,
|
||||||
ExtraReturnErrors: dm.extraReturnErrors,
|
ExtraReturnErrors: dm.extraReturnErrors,
|
||||||
DefaultMapType: dm.defaultMapType,
|
DefaultMapType: dm.defaultMapType,
|
||||||
UTF8: dm.utf8,
|
UTF8: dm.utf8,
|
||||||
FieldNameMatching: dm.fieldNameMatching,
|
FieldNameMatching: dm.fieldNameMatching,
|
||||||
BigIntDec: dm.bigIntDec,
|
BigIntDec: dm.bigIntDec,
|
||||||
DefaultByteStringType: dm.defaultByteStringType,
|
DefaultByteStringType: dm.defaultByteStringType,
|
||||||
ByteStringToString: dm.byteStringToString,
|
ByteStringToString: dm.byteStringToString,
|
||||||
FieldNameByteString: dm.fieldNameByteString,
|
FieldNameByteString: dm.fieldNameByteString,
|
||||||
UnrecognizedTagToAny: dm.unrecognizedTagToAny,
|
UnrecognizedTagToAny: dm.unrecognizedTagToAny,
|
||||||
TimeTagToAny: dm.timeTagToAny,
|
TimeTagToAny: dm.timeTagToAny,
|
||||||
SimpleValues: simpleValues,
|
SimpleValues: simpleValues,
|
||||||
NaN: dm.nanDec,
|
NaN: dm.nanDec,
|
||||||
Inf: dm.infDec,
|
Inf: dm.infDec,
|
||||||
ByteStringToTime: dm.byteStringToTime,
|
ByteStringToTime: dm.byteStringToTime,
|
||||||
ByteStringExpectedFormat: dm.byteStringExpectedFormat,
|
ByteStringExpectedFormat: dm.byteStringExpectedFormat,
|
||||||
BignumTag: dm.bignumTag,
|
BignumTag: dm.bignumTag,
|
||||||
BinaryUnmarshaler: dm.binaryUnmarshaler,
|
BinaryUnmarshaler: dm.binaryUnmarshaler,
|
||||||
|
TextUnmarshaler: dm.textUnmarshaler,
|
||||||
|
JSONUnmarshalerTranscoder: dm.jsonUnmarshalerTranscoder,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1245,7 +1288,7 @@ func (dm *decMode) DecOptions() DecOptions {
|
|||||||
// Unmarshal returns an error.
|
// Unmarshal returns an error.
|
||||||
//
|
//
|
||||||
// See the documentation for Unmarshal for details.
|
// See the documentation for Unmarshal for details.
|
||||||
func (dm *decMode) Unmarshal(data []byte, v interface{}) error {
|
func (dm *decMode) Unmarshal(data []byte, v any) error {
|
||||||
d := decoder{data: data, dm: dm}
|
d := decoder{data: data, dm: dm}
|
||||||
|
|
||||||
// Check well-formedness.
|
// Check well-formedness.
|
||||||
@@ -1265,7 +1308,7 @@ func (dm *decMode) Unmarshal(data []byte, v interface{}) error {
|
|||||||
// If v is nil, not a pointer, or a nil pointer, UnmarshalFirst returns an error.
|
// If v is nil, not a pointer, or a nil pointer, UnmarshalFirst returns an error.
|
||||||
//
|
//
|
||||||
// See the documentation for Unmarshal for details.
|
// See the documentation for Unmarshal for details.
|
||||||
func (dm *decMode) UnmarshalFirst(data []byte, v interface{}) (rest []byte, err error) {
|
func (dm *decMode) UnmarshalFirst(data []byte, v any) (rest []byte, err error) {
|
||||||
d := decoder{data: data, dm: dm}
|
d := decoder{data: data, dm: dm}
|
||||||
|
|
||||||
// check well-formedness.
|
// check well-formedness.
|
||||||
@@ -1341,13 +1384,13 @@ type decoder struct {
|
|||||||
// If CBOR data item fails to be decoded into v,
|
// If CBOR data item fails to be decoded into v,
|
||||||
// error is returned and offset is moved to the next CBOR data item.
|
// error is returned and offset is moved to the next CBOR data item.
|
||||||
// Precondition: d.data contains at least one well-formed CBOR data item.
|
// Precondition: d.data contains at least one well-formed CBOR data item.
|
||||||
func (d *decoder) value(v interface{}) error {
|
func (d *decoder) value(v any) error {
|
||||||
// v can't be nil, non-pointer, or nil pointer value.
|
// v can't be nil, non-pointer, or nil pointer value.
|
||||||
if v == nil {
|
if v == nil {
|
||||||
return &InvalidUnmarshalError{"cbor: Unmarshal(nil)"}
|
return &InvalidUnmarshalError{"cbor: Unmarshal(nil)"}
|
||||||
}
|
}
|
||||||
rv := reflect.ValueOf(v)
|
rv := reflect.ValueOf(v)
|
||||||
if rv.Kind() != reflect.Ptr {
|
if rv.Kind() != reflect.Pointer {
|
||||||
return &InvalidUnmarshalError{"cbor: Unmarshal(non-pointer " + rv.Type().String() + ")"}
|
return &InvalidUnmarshalError{"cbor: Unmarshal(non-pointer " + rv.Type().String() + ")"}
|
||||||
} else if rv.IsNil() {
|
} else if rv.IsNil() {
|
||||||
return &InvalidUnmarshalError{"cbor: Unmarshal(nil " + rv.Type().String() + ")"}
|
return &InvalidUnmarshalError{"cbor: Unmarshal(nil " + rv.Type().String() + ")"}
|
||||||
@@ -1361,9 +1404,9 @@ func (d *decoder) value(v interface{}) error {
|
|||||||
func (d *decoder) parseToValue(v reflect.Value, tInfo *typeInfo) error { //nolint:gocyclo
|
func (d *decoder) parseToValue(v reflect.Value, tInfo *typeInfo) error { //nolint:gocyclo
|
||||||
|
|
||||||
// Decode CBOR nil or CBOR undefined to pointer value by setting pointer value to nil.
|
// Decode CBOR nil or CBOR undefined to pointer value by setting pointer value to nil.
|
||||||
if d.nextCBORNil() && v.Kind() == reflect.Ptr {
|
if d.nextCBORNil() && v.Kind() == reflect.Pointer {
|
||||||
d.skip()
|
d.skip()
|
||||||
v.Set(reflect.Zero(v.Type()))
|
v.SetZero()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1387,7 +1430,7 @@ func (d *decoder) parseToValue(v reflect.Value, tInfo *typeInfo) error { //nolin
|
|||||||
registeredType := d.dm.tags.getTypeFromTagNum(tagNums)
|
registeredType := d.dm.tags.getTypeFromTagNum(tagNums)
|
||||||
if registeredType != nil {
|
if registeredType != nil {
|
||||||
if registeredType.Implements(tInfo.nonPtrType) ||
|
if registeredType.Implements(tInfo.nonPtrType) ||
|
||||||
reflect.PtrTo(registeredType).Implements(tInfo.nonPtrType) {
|
reflect.PointerTo(registeredType).Implements(tInfo.nonPtrType) {
|
||||||
v.Set(reflect.New(registeredType))
|
v.Set(reflect.New(registeredType))
|
||||||
v = v.Elem()
|
v = v.Elem()
|
||||||
tInfo = getTypeInfo(registeredType)
|
tInfo = getTypeInfo(registeredType)
|
||||||
@@ -1399,7 +1442,7 @@ func (d *decoder) parseToValue(v reflect.Value, tInfo *typeInfo) error { //nolin
|
|||||||
|
|
||||||
// Create new value for the pointer v to point to.
|
// Create new value for the pointer v to point to.
|
||||||
// At this point, CBOR value is not nil/undefined if v is a pointer.
|
// At this point, CBOR value is not nil/undefined if v is a pointer.
|
||||||
for v.Kind() == reflect.Ptr {
|
for v.Kind() == reflect.Pointer {
|
||||||
if v.IsNil() {
|
if v.IsNil() {
|
||||||
if !v.CanSet() {
|
if !v.CanSet() {
|
||||||
d.skip()
|
d.skip()
|
||||||
@@ -1460,6 +1503,17 @@ func (d *decoder) parseToValue(v reflect.Value, tInfo *typeInfo) error { //nolin
|
|||||||
|
|
||||||
case specialTypeUnmarshalerIface:
|
case specialTypeUnmarshalerIface:
|
||||||
return d.parseToUnmarshaler(v)
|
return d.parseToUnmarshaler(v)
|
||||||
|
|
||||||
|
case specialTypeUnexportedUnmarshalerIface:
|
||||||
|
return d.parseToUnexportedUnmarshaler(v)
|
||||||
|
|
||||||
|
case specialTypeJSONUnmarshalerIface:
|
||||||
|
// This special type implies that the type does not also implement
|
||||||
|
// cbor.Umarshaler.
|
||||||
|
if d.dm.jsonUnmarshalerTranscoder == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return d.parseToJSONUnmarshaler(v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1516,14 +1570,14 @@ func (d *decoder) parseToValue(v reflect.Value, tInfo *typeInfo) error { //nolin
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
copied = copied || converted
|
copied = copied || converted
|
||||||
return fillByteString(t, b, !copied, v, d.dm.byteStringToString, d.dm.binaryUnmarshaler)
|
return fillByteString(t, b, !copied, v, d.dm.byteStringToString, d.dm.binaryUnmarshaler, d.dm.textUnmarshaler)
|
||||||
|
|
||||||
case cborTypeTextString:
|
case cborTypeTextString:
|
||||||
b, err := d.parseTextString()
|
b, err := d.parseTextString()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return fillTextString(t, b, v)
|
return fillTextString(t, b, v, d.dm.textUnmarshaler)
|
||||||
|
|
||||||
case cborTypePrimitives:
|
case cborTypePrimitives:
|
||||||
_, ai, val := d.getHead()
|
_, ai, val := d.getHead()
|
||||||
@@ -1575,7 +1629,7 @@ func (d *decoder) parseToValue(v reflect.Value, tInfo *typeInfo) error { //nolin
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if tInfo.nonPtrKind == reflect.Slice || tInfo.nonPtrKind == reflect.Array {
|
if tInfo.nonPtrKind == reflect.Slice || tInfo.nonPtrKind == reflect.Array {
|
||||||
return fillByteString(t, b, !copied, v, ByteStringToStringForbidden, d.dm.binaryUnmarshaler)
|
return fillByteString(t, b, !copied, v, ByteStringToStringForbidden, d.dm.binaryUnmarshaler, d.dm.textUnmarshaler)
|
||||||
}
|
}
|
||||||
if bi.IsUint64() {
|
if bi.IsUint64() {
|
||||||
return fillPositiveInt(t, bi.Uint64(), v)
|
return fillPositiveInt(t, bi.Uint64(), v)
|
||||||
@@ -1598,7 +1652,7 @@ func (d *decoder) parseToValue(v reflect.Value, tInfo *typeInfo) error { //nolin
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if tInfo.nonPtrKind == reflect.Slice || tInfo.nonPtrKind == reflect.Array {
|
if tInfo.nonPtrKind == reflect.Slice || tInfo.nonPtrKind == reflect.Array {
|
||||||
return fillByteString(t, b, !copied, v, ByteStringToStringForbidden, d.dm.binaryUnmarshaler)
|
return fillByteString(t, b, !copied, v, ByteStringToStringForbidden, d.dm.binaryUnmarshaler, d.dm.textUnmarshaler)
|
||||||
}
|
}
|
||||||
if bi.IsInt64() {
|
if bi.IsInt64() {
|
||||||
return fillNegativeInt(t, bi.Int64(), v)
|
return fillNegativeInt(t, bi.Int64(), v)
|
||||||
@@ -1788,12 +1842,12 @@ func (d *decoder) parseToTime() (time.Time, bool, error) {
|
|||||||
// parseToUnmarshaler parses CBOR data to value implementing Unmarshaler interface.
|
// parseToUnmarshaler parses CBOR data to value implementing Unmarshaler interface.
|
||||||
// It assumes data is well-formed, and does not perform bounds checking.
|
// It assumes data is well-formed, and does not perform bounds checking.
|
||||||
func (d *decoder) parseToUnmarshaler(v reflect.Value) error {
|
func (d *decoder) parseToUnmarshaler(v reflect.Value) error {
|
||||||
if d.nextCBORNil() && v.Kind() == reflect.Ptr && v.IsNil() {
|
if d.nextCBORNil() && v.Kind() == reflect.Pointer && v.IsNil() {
|
||||||
d.skip()
|
d.skip()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if v.Kind() != reflect.Ptr && v.CanAddr() {
|
if v.Kind() != reflect.Pointer && v.CanAddr() {
|
||||||
v = v.Addr()
|
v = v.Addr()
|
||||||
}
|
}
|
||||||
if u, ok := v.Interface().(Unmarshaler); ok {
|
if u, ok := v.Interface().(Unmarshaler); ok {
|
||||||
@@ -1805,9 +1859,55 @@ func (d *decoder) parseToUnmarshaler(v reflect.Value) error {
|
|||||||
return errors.New("cbor: failed to assert " + v.Type().String() + " as cbor.Unmarshaler")
|
return errors.New("cbor: failed to assert " + v.Type().String() + " as cbor.Unmarshaler")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// parseToUnexportedUnmarshaler parses CBOR data to value implementing unmarshaler interface.
|
||||||
|
// It assumes data is well-formed, and does not perform bounds checking.
|
||||||
|
func (d *decoder) parseToUnexportedUnmarshaler(v reflect.Value) error {
|
||||||
|
if d.nextCBORNil() && v.Kind() == reflect.Pointer && v.IsNil() {
|
||||||
|
d.skip()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if v.Kind() != reflect.Pointer && v.CanAddr() {
|
||||||
|
v = v.Addr()
|
||||||
|
}
|
||||||
|
if u, ok := v.Interface().(unmarshaler); ok {
|
||||||
|
start := d.off
|
||||||
|
d.skip()
|
||||||
|
return u.unmarshalCBOR(d.data[start:d.off])
|
||||||
|
}
|
||||||
|
d.skip()
|
||||||
|
return errors.New("cbor: failed to assert " + v.Type().String() + " as cbor.unmarshaler")
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseToJSONUnmarshaler parses CBOR data to be transcoded to JSON and passed to the value's
|
||||||
|
// implementation of the json.Unmarshaler interface. It assumes data is well-formed, and does not
|
||||||
|
// perform bounds checking.
|
||||||
|
func (d *decoder) parseToJSONUnmarshaler(v reflect.Value) error {
|
||||||
|
if d.nextCBORNil() && v.Kind() == reflect.Pointer && v.IsNil() {
|
||||||
|
d.skip()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if v.Kind() != reflect.Pointer && v.CanAddr() {
|
||||||
|
v = v.Addr()
|
||||||
|
}
|
||||||
|
if u, ok := v.Interface().(jsonUnmarshaler); ok {
|
||||||
|
start := d.off
|
||||||
|
d.skip()
|
||||||
|
e := getEncodeBuffer()
|
||||||
|
defer putEncodeBuffer(e)
|
||||||
|
if err := d.dm.jsonUnmarshalerTranscoder.Transcode(e, bytes.NewReader(d.data[start:d.off])); err != nil {
|
||||||
|
return &TranscodeError{err: err, rtype: v.Type(), sourceFormat: "cbor", targetFormat: "json"}
|
||||||
|
}
|
||||||
|
return u.UnmarshalJSON(e.Bytes())
|
||||||
|
}
|
||||||
|
d.skip()
|
||||||
|
return errors.New("cbor: failed to assert " + v.Type().String() + " as json.Unmarshaler")
|
||||||
|
}
|
||||||
|
|
||||||
// parse parses CBOR data and returns value in default Go type.
|
// parse parses CBOR data and returns value in default Go type.
|
||||||
// It assumes data is well-formed, and does not perform bounds checking.
|
// It assumes data is well-formed, and does not perform bounds checking.
|
||||||
func (d *decoder) parse(skipSelfDescribedTag bool) (interface{}, error) { //nolint:gocyclo
|
func (d *decoder) parse(skipSelfDescribedTag bool) (any, error) { //nolint:gocyclo
|
||||||
// Strip self-described CBOR tag number.
|
// Strip self-described CBOR tag number.
|
||||||
if skipSelfDescribedTag {
|
if skipSelfDescribedTag {
|
||||||
for d.nextCBORType() == cborTypeTag {
|
for d.nextCBORType() == cborTypeTag {
|
||||||
@@ -2224,15 +2324,15 @@ func (d *decoder) parseTextString() ([]byte, error) {
|
|||||||
return b, nil
|
return b, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *decoder) parseArray() ([]interface{}, error) {
|
func (d *decoder) parseArray() ([]any, error) {
|
||||||
_, _, val, indefiniteLength := d.getHeadWithIndefiniteLengthFlag()
|
_, _, val, indefiniteLength := d.getHeadWithIndefiniteLengthFlag()
|
||||||
hasSize := !indefiniteLength
|
hasSize := !indefiniteLength
|
||||||
count := int(val)
|
count := int(val)
|
||||||
if !hasSize {
|
if !hasSize {
|
||||||
count = d.numOfItemsUntilBreak() // peek ahead to get array size to preallocate slice for better performance
|
count = d.numOfItemsUntilBreak() // peek ahead to get array size to preallocate slice for better performance
|
||||||
}
|
}
|
||||||
v := make([]interface{}, count)
|
v := make([]any, count)
|
||||||
var e interface{}
|
var e any
|
||||||
var err, lastErr error
|
var err, lastErr error
|
||||||
for i := 0; (hasSize && i < count) || (!hasSize && !d.foundBreak()); i++ {
|
for i := 0; (hasSize && i < count) || (!hasSize && !d.foundBreak()); i++ {
|
||||||
if e, lastErr = d.parse(true); lastErr != nil {
|
if e, lastErr = d.parse(true); lastErr != nil {
|
||||||
@@ -2290,20 +2390,19 @@ func (d *decoder) parseArrayToArray(v reflect.Value, tInfo *typeInfo) error {
|
|||||||
}
|
}
|
||||||
// Set remaining Go array elements to zero values.
|
// Set remaining Go array elements to zero values.
|
||||||
if gi < vLen {
|
if gi < vLen {
|
||||||
zeroV := reflect.Zero(tInfo.elemTypeInfo.typ)
|
|
||||||
for ; gi < vLen; gi++ {
|
for ; gi < vLen; gi++ {
|
||||||
v.Index(gi).Set(zeroV)
|
v.Index(gi).SetZero()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *decoder) parseMap() (interface{}, error) {
|
func (d *decoder) parseMap() (any, error) {
|
||||||
_, _, val, indefiniteLength := d.getHeadWithIndefiniteLengthFlag()
|
_, _, val, indefiniteLength := d.getHeadWithIndefiniteLengthFlag()
|
||||||
hasSize := !indefiniteLength
|
hasSize := !indefiniteLength
|
||||||
count := int(val)
|
count := int(val)
|
||||||
m := make(map[interface{}]interface{})
|
m := make(map[any]any)
|
||||||
var k, e interface{}
|
var k, e any
|
||||||
var err, lastErr error
|
var err, lastErr error
|
||||||
keyCount := 0
|
keyCount := 0
|
||||||
for i := 0; (hasSize && i < count) || (!hasSize && !d.foundBreak()); i++ {
|
for i := 0; (hasSize && i < count) || (!hasSize && !d.foundBreak()); i++ {
|
||||||
@@ -2376,13 +2475,13 @@ func (d *decoder) parseMapToMap(v reflect.Value, tInfo *typeInfo) error { //noli
|
|||||||
}
|
}
|
||||||
keyType, eleType := tInfo.keyTypeInfo.typ, tInfo.elemTypeInfo.typ
|
keyType, eleType := tInfo.keyTypeInfo.typ, tInfo.elemTypeInfo.typ
|
||||||
reuseKey, reuseEle := isImmutableKind(tInfo.keyTypeInfo.kind), isImmutableKind(tInfo.elemTypeInfo.kind)
|
reuseKey, reuseEle := isImmutableKind(tInfo.keyTypeInfo.kind), isImmutableKind(tInfo.elemTypeInfo.kind)
|
||||||
var keyValue, eleValue, zeroKeyValue, zeroEleValue reflect.Value
|
var keyValue, eleValue reflect.Value
|
||||||
keyIsInterfaceType := keyType == typeIntf // If key type is interface{}, need to check if key value is hashable.
|
keyIsInterfaceType := keyType == typeIntf // If key type is interface{}, need to check if key value is hashable.
|
||||||
var err, lastErr error
|
var err, lastErr error
|
||||||
keyCount := v.Len()
|
keyCount := v.Len()
|
||||||
var existingKeys map[interface{}]bool // Store existing map keys, used for detecting duplicate map key.
|
var existingKeys map[any]bool // Store existing map keys, used for detecting duplicate map key.
|
||||||
if d.dm.dupMapKey == DupMapKeyEnforcedAPF {
|
if d.dm.dupMapKey == DupMapKeyEnforcedAPF {
|
||||||
existingKeys = make(map[interface{}]bool, keyCount)
|
existingKeys = make(map[any]bool, keyCount)
|
||||||
if keyCount > 0 {
|
if keyCount > 0 {
|
||||||
vKeys := v.MapKeys()
|
vKeys := v.MapKeys()
|
||||||
for i := 0; i < len(vKeys); i++ {
|
for i := 0; i < len(vKeys); i++ {
|
||||||
@@ -2395,10 +2494,7 @@ func (d *decoder) parseMapToMap(v reflect.Value, tInfo *typeInfo) error { //noli
|
|||||||
if !keyValue.IsValid() {
|
if !keyValue.IsValid() {
|
||||||
keyValue = reflect.New(keyType).Elem()
|
keyValue = reflect.New(keyType).Elem()
|
||||||
} else if !reuseKey {
|
} else if !reuseKey {
|
||||||
if !zeroKeyValue.IsValid() {
|
keyValue.SetZero()
|
||||||
zeroKeyValue = reflect.Zero(keyType)
|
|
||||||
}
|
|
||||||
keyValue.Set(zeroKeyValue)
|
|
||||||
}
|
}
|
||||||
if lastErr = d.parseToValue(keyValue, tInfo.keyTypeInfo); lastErr != nil {
|
if lastErr = d.parseToValue(keyValue, tInfo.keyTypeInfo); lastErr != nil {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@@ -2413,7 +2509,7 @@ func (d *decoder) parseMapToMap(v reflect.Value, tInfo *typeInfo) error { //noli
|
|||||||
if !isHashableValue(keyValue.Elem()) {
|
if !isHashableValue(keyValue.Elem()) {
|
||||||
var converted bool
|
var converted bool
|
||||||
if d.dm.mapKeyByteString == MapKeyByteStringAllowed {
|
if d.dm.mapKeyByteString == MapKeyByteStringAllowed {
|
||||||
var k interface{}
|
var k any
|
||||||
k, converted = convertByteSliceToByteString(keyValue.Elem().Interface())
|
k, converted = convertByteSliceToByteString(keyValue.Elem().Interface())
|
||||||
if converted {
|
if converted {
|
||||||
keyValue.Set(reflect.ValueOf(k))
|
keyValue.Set(reflect.ValueOf(k))
|
||||||
@@ -2433,10 +2529,7 @@ func (d *decoder) parseMapToMap(v reflect.Value, tInfo *typeInfo) error { //noli
|
|||||||
if !eleValue.IsValid() {
|
if !eleValue.IsValid() {
|
||||||
eleValue = reflect.New(eleType).Elem()
|
eleValue = reflect.New(eleType).Elem()
|
||||||
} else if !reuseEle {
|
} else if !reuseEle {
|
||||||
if !zeroEleValue.IsValid() {
|
eleValue.SetZero()
|
||||||
zeroEleValue = reflect.Zero(eleType)
|
|
||||||
}
|
|
||||||
eleValue.Set(zeroEleValue)
|
|
||||||
}
|
}
|
||||||
if lastErr := d.parseToValue(eleValue, tInfo.elemTypeInfo); lastErr != nil {
|
if lastErr := d.parseToValue(eleValue, tInfo.elemTypeInfo); lastErr != nil {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@@ -2584,7 +2677,7 @@ func (d *decoder) parseMapToStruct(v reflect.Value, tInfo *typeInfo) error { //n
|
|||||||
|
|
||||||
// Keeps track of CBOR map keys to detect duplicate map key
|
// Keeps track of CBOR map keys to detect duplicate map key
|
||||||
keyCount := 0
|
keyCount := 0
|
||||||
var mapKeys map[interface{}]struct{}
|
var mapKeys map[any]struct{}
|
||||||
|
|
||||||
errOnUnknownField := (d.dm.extraReturnErrors & ExtraDecErrorUnknownField) > 0
|
errOnUnknownField := (d.dm.extraReturnErrors & ExtraDecErrorUnknownField) > 0
|
||||||
|
|
||||||
@@ -2594,7 +2687,7 @@ MapEntryLoop:
|
|||||||
|
|
||||||
// If duplicate field detection is enabled and the key at index j did not match any
|
// If duplicate field detection is enabled and the key at index j did not match any
|
||||||
// field, k will hold the map key.
|
// field, k will hold the map key.
|
||||||
var k interface{}
|
var k any
|
||||||
|
|
||||||
t := d.nextCBORType()
|
t := d.nextCBORType()
|
||||||
if t == cborTypeTextString || (t == cborTypeByteString && d.dm.fieldNameByteString == FieldNameByteStringAllowed) {
|
if t == cborTypeTextString || (t == cborTypeByteString && d.dm.fieldNameByteString == FieldNameByteStringAllowed) {
|
||||||
@@ -2764,7 +2857,7 @@ MapEntryLoop:
|
|||||||
// check is never reached.
|
// check is never reached.
|
||||||
if d.dm.dupMapKey == DupMapKeyEnforcedAPF {
|
if d.dm.dupMapKey == DupMapKeyEnforcedAPF {
|
||||||
if mapKeys == nil {
|
if mapKeys == nil {
|
||||||
mapKeys = make(map[interface{}]struct{}, 1)
|
mapKeys = make(map[any]struct{}, 1)
|
||||||
}
|
}
|
||||||
mapKeys[k] = struct{}{}
|
mapKeys[k] = struct{}{}
|
||||||
newKeyCount := len(mapKeys)
|
newKeyCount := len(mapKeys)
|
||||||
@@ -2968,20 +3061,25 @@ func (d *decoder) nextCBORNil() bool {
|
|||||||
return d.data[d.off] == 0xf6 || d.data[d.off] == 0xf7
|
return d.data[d.off] == 0xf6 || d.data[d.off] == 0xf7
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type jsonUnmarshaler interface{ UnmarshalJSON([]byte) error }
|
||||||
|
|
||||||
var (
|
var (
|
||||||
typeIntf = reflect.TypeOf([]interface{}(nil)).Elem()
|
typeIntf = reflect.TypeOf([]any(nil)).Elem()
|
||||||
typeTime = reflect.TypeOf(time.Time{})
|
typeTime = reflect.TypeOf(time.Time{})
|
||||||
typeBigInt = reflect.TypeOf(big.Int{})
|
typeBigInt = reflect.TypeOf(big.Int{})
|
||||||
typeUnmarshaler = reflect.TypeOf((*Unmarshaler)(nil)).Elem()
|
typeUnmarshaler = reflect.TypeOf((*Unmarshaler)(nil)).Elem()
|
||||||
typeBinaryUnmarshaler = reflect.TypeOf((*encoding.BinaryUnmarshaler)(nil)).Elem()
|
typeUnexportedUnmarshaler = reflect.TypeOf((*unmarshaler)(nil)).Elem()
|
||||||
typeString = reflect.TypeOf("")
|
typeBinaryUnmarshaler = reflect.TypeOf((*encoding.BinaryUnmarshaler)(nil)).Elem()
|
||||||
typeByteSlice = reflect.TypeOf([]byte(nil))
|
typeTextUnmarshaler = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem()
|
||||||
|
typeJSONUnmarshaler = reflect.TypeOf((*jsonUnmarshaler)(nil)).Elem()
|
||||||
|
typeString = reflect.TypeOf("")
|
||||||
|
typeByteSlice = reflect.TypeOf([]byte(nil))
|
||||||
)
|
)
|
||||||
|
|
||||||
func fillNil(_ cborType, v reflect.Value) error {
|
func fillNil(_ cborType, v reflect.Value) error {
|
||||||
switch v.Kind() {
|
switch v.Kind() {
|
||||||
case reflect.Slice, reflect.Map, reflect.Interface, reflect.Ptr:
|
case reflect.Slice, reflect.Map, reflect.Interface, reflect.Pointer:
|
||||||
v.Set(reflect.Zero(v.Type()))
|
v.SetZero()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@@ -3082,8 +3180,8 @@ func fillFloat(t cborType, val float64, v reflect.Value) error {
|
|||||||
return &UnmarshalTypeError{CBORType: t.String(), GoType: v.Type().String()}
|
return &UnmarshalTypeError{CBORType: t.String(), GoType: v.Type().String()}
|
||||||
}
|
}
|
||||||
|
|
||||||
func fillByteString(t cborType, val []byte, shared bool, v reflect.Value, bsts ByteStringToStringMode, bum BinaryUnmarshalerMode) error {
|
func fillByteString(t cborType, val []byte, shared bool, v reflect.Value, bsts ByteStringToStringMode, bum BinaryUnmarshalerMode, tum TextUnmarshalerMode) error {
|
||||||
if bum == BinaryUnmarshalerByteString && reflect.PtrTo(v.Type()).Implements(typeBinaryUnmarshaler) {
|
if bum == BinaryUnmarshalerByteString && reflect.PointerTo(v.Type()).Implements(typeBinaryUnmarshaler) {
|
||||||
if v.CanAddr() {
|
if v.CanAddr() {
|
||||||
v = v.Addr()
|
v = v.Addr()
|
||||||
if u, ok := v.Interface().(encoding.BinaryUnmarshaler); ok {
|
if u, ok := v.Interface().(encoding.BinaryUnmarshaler); ok {
|
||||||
@@ -3095,9 +3193,26 @@ func fillByteString(t cborType, val []byte, shared bool, v reflect.Value, bsts B
|
|||||||
}
|
}
|
||||||
return errors.New("cbor: cannot set new value for " + v.Type().String())
|
return errors.New("cbor: cannot set new value for " + v.Type().String())
|
||||||
}
|
}
|
||||||
if bsts != ByteStringToStringForbidden && v.Kind() == reflect.String {
|
if bsts != ByteStringToStringForbidden {
|
||||||
v.SetString(string(val))
|
if tum == TextUnmarshalerTextString && reflect.PointerTo(v.Type()).Implements(typeTextUnmarshaler) {
|
||||||
return nil
|
if v.CanAddr() {
|
||||||
|
v = v.Addr()
|
||||||
|
if u, ok := v.Interface().(encoding.TextUnmarshaler); ok {
|
||||||
|
// The contract of TextUnmarshaler forbids retaining the input
|
||||||
|
// bytes, so no copying is required even if val is shared.
|
||||||
|
if err := u.UnmarshalText(val); err != nil {
|
||||||
|
return fmt.Errorf("cbor: cannot unmarshal text for %s: %w", v.Type(), err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return errors.New("cbor: cannot set new value for " + v.Type().String())
|
||||||
|
}
|
||||||
|
|
||||||
|
if v.Kind() == reflect.String {
|
||||||
|
v.SetString(string(val))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if v.Kind() == reflect.Slice && v.Type().Elem().Kind() == reflect.Uint8 {
|
if v.Kind() == reflect.Slice && v.Type().Elem().Kind() == reflect.Uint8 {
|
||||||
src := val
|
src := val
|
||||||
@@ -3117,9 +3232,8 @@ func fillByteString(t cborType, val []byte, shared bool, v reflect.Value, bsts B
|
|||||||
}
|
}
|
||||||
// Set remaining Go array elements to zero values.
|
// Set remaining Go array elements to zero values.
|
||||||
if i < vLen {
|
if i < vLen {
|
||||||
zeroV := reflect.Zero(reflect.TypeOf(byte(0)))
|
|
||||||
for ; i < vLen; i++ {
|
for ; i < vLen; i++ {
|
||||||
v.Index(i).Set(zeroV)
|
v.Index(i).SetZero()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@@ -3127,11 +3241,28 @@ func fillByteString(t cborType, val []byte, shared bool, v reflect.Value, bsts B
|
|||||||
return &UnmarshalTypeError{CBORType: t.String(), GoType: v.Type().String()}
|
return &UnmarshalTypeError{CBORType: t.String(), GoType: v.Type().String()}
|
||||||
}
|
}
|
||||||
|
|
||||||
func fillTextString(t cborType, val []byte, v reflect.Value) error {
|
func fillTextString(t cborType, val []byte, v reflect.Value, tum TextUnmarshalerMode) error {
|
||||||
|
// Check if the value implements TextUnmarshaler and the mode allows it
|
||||||
|
if tum == TextUnmarshalerTextString && reflect.PointerTo(v.Type()).Implements(typeTextUnmarshaler) {
|
||||||
|
if v.CanAddr() {
|
||||||
|
v = v.Addr()
|
||||||
|
if u, ok := v.Interface().(encoding.TextUnmarshaler); ok {
|
||||||
|
// The contract of TextUnmarshaler forbids retaining the input
|
||||||
|
// bytes, so no copying is required even if val is shared.
|
||||||
|
if err := u.UnmarshalText(val); err != nil {
|
||||||
|
return fmt.Errorf("cbor: cannot unmarshal text for %s: %w", v.Type(), err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return errors.New("cbor: cannot set new value for " + v.Type().String())
|
||||||
|
}
|
||||||
|
|
||||||
if v.Kind() == reflect.String {
|
if v.Kind() == reflect.String {
|
||||||
v.SetString(string(val))
|
v.SetString(string(val))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return &UnmarshalTypeError{CBORType: t.String(), GoType: v.Type().String()}
|
return &UnmarshalTypeError{CBORType: t.String(), GoType: v.Type().String()}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3172,7 +3303,7 @@ func isHashableValue(rv reflect.Value) bool {
|
|||||||
// This function also handles nested tags.
|
// This function also handles nested tags.
|
||||||
// CBOR data is already verified to be well-formed before this function is used,
|
// CBOR data is already verified to be well-formed before this function is used,
|
||||||
// so the recursion won't exceed max nested levels.
|
// so the recursion won't exceed max nested levels.
|
||||||
func convertByteSliceToByteString(v interface{}) (interface{}, bool) {
|
func convertByteSliceToByteString(v any) (any, bool) {
|
||||||
switch v := v.(type) {
|
switch v := v.(type) {
|
||||||
case []byte:
|
case []byte:
|
||||||
return ByteString(v), true
|
return ByteString(v), true
|
||||||
|
|||||||
51
vendor/github.com/fxamacker/cbor/v2/doc.go
generated
vendored
51
vendor/github.com/fxamacker/cbor/v2/doc.go
generated
vendored
@@ -2,15 +2,15 @@
|
|||||||
// Licensed under the MIT License. See LICENSE in the project root for license information.
|
// Licensed under the MIT License. See LICENSE in the project root for license information.
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Package cbor is a modern CBOR codec (RFC 8949 & RFC 7049) with CBOR tags,
|
Package cbor is a modern CBOR codec (RFC 8949 & RFC 8742) with CBOR tags,
|
||||||
Go struct tags (toarray/keyasint/omitempty), Core Deterministic Encoding,
|
Go struct tag options (toarray/keyasint/omitempty/omitzero), Core Deterministic Encoding,
|
||||||
CTAP2, Canonical CBOR, float64->32->16, and duplicate map key detection.
|
CTAP2, Canonical CBOR, float64->32->16, and duplicate map key detection.
|
||||||
|
|
||||||
Encoding options allow "preferred serialization" by encoding integers and floats
|
Encoding options allow "preferred serialization" by encoding integers and floats
|
||||||
to their smallest forms (e.g. float16) when values fit.
|
to their smallest forms (e.g. float16) when values fit.
|
||||||
|
|
||||||
Struct tags like "keyasint", "toarray" and "omitempty" make CBOR data smaller
|
Struct tag options "keyasint", "toarray", "omitempty", and "omitzero" reduce encoding size
|
||||||
and easier to use with structs.
|
and reduce programming effort.
|
||||||
|
|
||||||
For example, "toarray" tag makes struct fields encode to CBOR array elements. And
|
For example, "toarray" tag makes struct fields encode to CBOR array elements. And
|
||||||
"keyasint" makes a field encode to an element of CBOR map with specified int key.
|
"keyasint" makes a field encode to an element of CBOR map with specified int key.
|
||||||
@@ -23,11 +23,19 @@ The Quick Start guide is at https://github.com/fxamacker/cbor#quick-start
|
|||||||
|
|
||||||
Function signatures identical to encoding/json include:
|
Function signatures identical to encoding/json include:
|
||||||
|
|
||||||
Marshal, Unmarshal, NewEncoder, NewDecoder, (*Encoder).Encode, (*Decoder).Decode.
|
Marshal, Unmarshal, NewEncoder, NewDecoder, (*Encoder).Encode, (*Decoder).Decode
|
||||||
|
|
||||||
Standard interfaces include:
|
Standard interfaces include:
|
||||||
|
|
||||||
BinaryMarshaler, BinaryUnmarshaler, Marshaler, and Unmarshaler.
|
BinaryMarshaler, BinaryUnmarshaler, Marshaler, and Unmarshaler
|
||||||
|
|
||||||
|
Diagnostic functions translate CBOR data item into Diagnostic Notation:
|
||||||
|
|
||||||
|
Diagnose, DiagnoseFirst
|
||||||
|
|
||||||
|
Functions that simplify using CBOR Sequences (RFC 8742) include:
|
||||||
|
|
||||||
|
UnmarshalFirst
|
||||||
|
|
||||||
Custom encoding and decoding is possible by implementing standard interfaces for
|
Custom encoding and decoding is possible by implementing standard interfaces for
|
||||||
user-defined Go types.
|
user-defined Go types.
|
||||||
@@ -50,19 +58,19 @@ Modes are intended to be reused and are safe for concurrent use.
|
|||||||
|
|
||||||
EncMode and DecMode Interfaces
|
EncMode and DecMode Interfaces
|
||||||
|
|
||||||
// EncMode interface uses immutable options and is safe for concurrent use.
|
// EncMode interface uses immutable options and is safe for concurrent use.
|
||||||
type EncMode interface {
|
type EncMode interface {
|
||||||
Marshal(v interface{}) ([]byte, error)
|
Marshal(v interface{}) ([]byte, error)
|
||||||
NewEncoder(w io.Writer) *Encoder
|
NewEncoder(w io.Writer) *Encoder
|
||||||
EncOptions() EncOptions // returns copy of options
|
EncOptions() EncOptions // returns copy of options
|
||||||
}
|
}
|
||||||
|
|
||||||
// DecMode interface uses immutable options and is safe for concurrent use.
|
// DecMode interface uses immutable options and is safe for concurrent use.
|
||||||
type DecMode interface {
|
type DecMode interface {
|
||||||
Unmarshal(data []byte, v interface{}) error
|
Unmarshal(data []byte, v interface{}) error
|
||||||
NewDecoder(r io.Reader) *Decoder
|
NewDecoder(r io.Reader) *Decoder
|
||||||
DecOptions() DecOptions // returns copy of options
|
DecOptions() DecOptions // returns copy of options
|
||||||
}
|
}
|
||||||
|
|
||||||
Using Default Encoding Mode
|
Using Default Encoding Mode
|
||||||
|
|
||||||
@@ -78,6 +86,16 @@ Using Default Decoding Mode
|
|||||||
decoder := cbor.NewDecoder(r)
|
decoder := cbor.NewDecoder(r)
|
||||||
err = decoder.Decode(&v)
|
err = decoder.Decode(&v)
|
||||||
|
|
||||||
|
Using Default Mode of UnmarshalFirst to Decode CBOR Sequences
|
||||||
|
|
||||||
|
// Decode the first CBOR data item and return remaining bytes:
|
||||||
|
rest, err = cbor.UnmarshalFirst(b, &v) // decode []byte b to v
|
||||||
|
|
||||||
|
Using Extended Diagnostic Notation (EDN) to represent CBOR data
|
||||||
|
|
||||||
|
// Translate the first CBOR data item into text and return remaining bytes.
|
||||||
|
text, rest, err = cbor.DiagnoseFirst(b) // decode []byte b to text
|
||||||
|
|
||||||
Creating and Using Encoding Modes
|
Creating and Using Encoding Modes
|
||||||
|
|
||||||
// Create EncOptions using either struct literal or a function.
|
// Create EncOptions using either struct literal or a function.
|
||||||
@@ -111,15 +129,20 @@ Decoding Options: https://github.com/fxamacker/cbor#decoding-options
|
|||||||
Struct tags like `cbor:"name,omitempty"` and `json:"name,omitempty"` work as expected.
|
Struct tags like `cbor:"name,omitempty"` and `json:"name,omitempty"` work as expected.
|
||||||
If both struct tags are specified then `cbor` is used.
|
If both struct tags are specified then `cbor` is used.
|
||||||
|
|
||||||
Struct tags like "keyasint", "toarray", and "omitempty" make it easy to use
|
Struct tag options like "keyasint", "toarray", "omitempty", and "omitzero" make it easy to use
|
||||||
very compact formats like COSE and CWT (CBOR Web Tokens) with structs.
|
very compact formats like COSE and CWT (CBOR Web Tokens) with structs.
|
||||||
|
|
||||||
|
The "omitzero" option omits zero values from encoding, matching
|
||||||
|
[stdlib encoding/json behavior](https://pkg.go.dev/encoding/json#Marshal).
|
||||||
|
When specified in the `cbor` tag, the option is always honored.
|
||||||
|
When specified in the `json` tag, the option is honored when building with Go 1.24+.
|
||||||
|
|
||||||
For example, "toarray" makes struct fields encode to array elements. And "keyasint"
|
For example, "toarray" makes struct fields encode to array elements. And "keyasint"
|
||||||
makes struct fields encode to elements of CBOR map with int keys.
|
makes struct fields encode to elements of CBOR map with int keys.
|
||||||
|
|
||||||
https://raw.githubusercontent.com/fxamacker/images/master/cbor/v2.0.0/cbor_easy_api.png
|
https://raw.githubusercontent.com/fxamacker/images/master/cbor/v2.0.0/cbor_easy_api.png
|
||||||
|
|
||||||
Struct tags are listed at https://github.com/fxamacker/cbor#struct-tags-1
|
Struct tag options are listed at https://github.com/fxamacker/cbor#struct-tags-1
|
||||||
|
|
||||||
# Tests and Fuzzing
|
# Tests and Fuzzing
|
||||||
|
|
||||||
|
|||||||
442
vendor/github.com/fxamacker/cbor/v2/encode.go
generated
vendored
442
vendor/github.com/fxamacker/cbor/v2/encode.go
generated
vendored
@@ -58,8 +58,10 @@ import (
|
|||||||
//
|
//
|
||||||
// Marshal supports format string stored under the "cbor" key in the struct
|
// Marshal supports format string stored under the "cbor" key in the struct
|
||||||
// field's tag. CBOR format string can specify the name of the field,
|
// field's tag. CBOR format string can specify the name of the field,
|
||||||
// "omitempty" and "keyasint" options, and special case "-" for field omission.
|
// "omitempty", "omitzero" and "keyasint" options, and special case "-" for
|
||||||
// If "cbor" key is absent, Marshal uses "json" key.
|
// field omission. If "cbor" key is absent, Marshal uses "json" key.
|
||||||
|
// When using the "json" key, the "omitzero" option is honored when building
|
||||||
|
// with Go 1.24+ to match stdlib encoding/json behavior.
|
||||||
//
|
//
|
||||||
// Struct field name is treated as integer if it has "keyasint" option in
|
// Struct field name is treated as integer if it has "keyasint" option in
|
||||||
// its format string. The format string must specify an integer as its
|
// its format string. The format string must specify an integer as its
|
||||||
@@ -67,8 +69,8 @@ import (
|
|||||||
//
|
//
|
||||||
// Special struct field "_" is used to specify struct level options, such as
|
// Special struct field "_" is used to specify struct level options, such as
|
||||||
// "toarray". "toarray" option enables Go struct to be encoded as CBOR array.
|
// "toarray". "toarray" option enables Go struct to be encoded as CBOR array.
|
||||||
// "omitempty" is disabled by "toarray" to ensure that the same number
|
// "omitempty" and "omitzero" are disabled by "toarray" to ensure that the
|
||||||
// of elements are encoded every time.
|
// same number of elements are encoded every time.
|
||||||
//
|
//
|
||||||
// Anonymous struct fields are marshaled as if their exported fields
|
// Anonymous struct fields are marshaled as if their exported fields
|
||||||
// were fields in the outer struct. Marshal follows the same struct fields
|
// were fields in the outer struct. Marshal follows the same struct fields
|
||||||
@@ -92,7 +94,7 @@ import (
|
|||||||
//
|
//
|
||||||
// Values of other types cannot be encoded in CBOR. Attempting
|
// Values of other types cannot be encoded in CBOR. Attempting
|
||||||
// to encode such a value causes Marshal to return an UnsupportedTypeError.
|
// to encode such a value causes Marshal to return an UnsupportedTypeError.
|
||||||
func Marshal(v interface{}) ([]byte, error) {
|
func Marshal(v any) ([]byte, error) {
|
||||||
return defaultEncMode.Marshal(v)
|
return defaultEncMode.Marshal(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,7 +105,7 @@ func Marshal(v interface{}) ([]byte, error) {
|
|||||||
// partially encoded data if error is returned.
|
// partially encoded data if error is returned.
|
||||||
//
|
//
|
||||||
// See Marshal for more details.
|
// See Marshal for more details.
|
||||||
func MarshalToBuffer(v interface{}, buf *bytes.Buffer) error {
|
func MarshalToBuffer(v any, buf *bytes.Buffer) error {
|
||||||
return defaultEncMode.MarshalToBuffer(v, buf)
|
return defaultEncMode.MarshalToBuffer(v, buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,6 +132,20 @@ func (e *MarshalerError) Unwrap() error {
|
|||||||
return e.err
|
return e.err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type TranscodeError struct {
|
||||||
|
err error
|
||||||
|
rtype reflect.Type
|
||||||
|
sourceFormat, targetFormat string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e TranscodeError) Error() string {
|
||||||
|
return "cbor: cannot transcode from " + e.sourceFormat + " to " + e.targetFormat + ": " + e.err.Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e TranscodeError) Unwrap() error {
|
||||||
|
return e.err
|
||||||
|
}
|
||||||
|
|
||||||
// UnsupportedTypeError is returned by Marshal when attempting to encode value
|
// UnsupportedTypeError is returned by Marshal when attempting to encode value
|
||||||
// of an unsupported type.
|
// of an unsupported type.
|
||||||
type UnsupportedTypeError struct {
|
type UnsupportedTypeError struct {
|
||||||
@@ -291,24 +307,51 @@ func (icm InfConvertMode) valid() bool {
|
|||||||
return icm >= 0 && icm < maxInfConvert
|
return icm >= 0 && icm < maxInfConvert
|
||||||
}
|
}
|
||||||
|
|
||||||
// TimeMode specifies how to encode time.Time values.
|
// TimeMode specifies how to encode time.Time values in compliance with RFC 8949 (CBOR):
|
||||||
|
// - Section 3.4.1: Standard Date/Time String
|
||||||
|
// - Section 3.4.2: Epoch-Based Date/Time
|
||||||
|
// For more info, see:
|
||||||
|
// - https://www.rfc-editor.org/rfc/rfc8949.html
|
||||||
|
// NOTE: User applications that prefer to encode time with fractional seconds to an integer
|
||||||
|
// (instead of floating point or text string) can use a CBOR tag number not assigned by IANA:
|
||||||
|
// 1. Define a user-defined type in Go with just a time.Time or int64 as its data.
|
||||||
|
// 2. Implement the cbor.Marshaler and cbor.Unmarshaler interface for that user-defined type
|
||||||
|
// to encode or decode the tagged data item with an enclosed integer content.
|
||||||
type TimeMode int
|
type TimeMode int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// TimeUnix causes time.Time to be encoded as epoch time in integer with second precision.
|
// TimeUnix causes time.Time to encode to a CBOR time (tag 1) with an integer content
|
||||||
|
// representing seconds elapsed (with 1-second precision) since UNIX Epoch UTC.
|
||||||
|
// The TimeUnix option is location independent and has a clear precision guarantee.
|
||||||
TimeUnix TimeMode = iota
|
TimeUnix TimeMode = iota
|
||||||
|
|
||||||
// TimeUnixMicro causes time.Time to be encoded as epoch time in float-point rounded to microsecond precision.
|
// TimeUnixMicro causes time.Time to encode to a CBOR time (tag 1) with a floating point content
|
||||||
|
// representing seconds elapsed (with up to 1-microsecond precision) since UNIX Epoch UTC.
|
||||||
|
// NOTE: The floating point content is encoded to the shortest floating-point encoding that preserves
|
||||||
|
// the 64-bit floating point value. I.e., the floating point encoding can be IEEE 764:
|
||||||
|
// binary64, binary32, or binary16 depending on the content's value.
|
||||||
TimeUnixMicro
|
TimeUnixMicro
|
||||||
|
|
||||||
// TimeUnixDynamic causes time.Time to be encoded as integer if time.Time doesn't have fractional seconds,
|
// TimeUnixDynamic causes time.Time to encode to a CBOR time (tag 1) with either an integer content or
|
||||||
// otherwise float-point rounded to microsecond precision.
|
// a floating point content, depending on the content's value. This option is equivalent to dynamically
|
||||||
|
// choosing TimeUnix if time.Time doesn't have fractional seconds, and using TimeUnixMicro if time.Time
|
||||||
|
// has fractional seconds.
|
||||||
TimeUnixDynamic
|
TimeUnixDynamic
|
||||||
|
|
||||||
// TimeRFC3339 causes time.Time to be encoded as RFC3339 formatted string with second precision.
|
// TimeRFC3339 causes time.Time to encode to a CBOR time (tag 0) with a text string content
|
||||||
|
// representing the time using 1-second precision in RFC3339 format. If the time.Time has a
|
||||||
|
// non-UTC timezone then a "localtime - UTC" numeric offset will be included as specified in RFC3339.
|
||||||
|
// NOTE: User applications can avoid including the RFC3339 numeric offset by:
|
||||||
|
// - providing a time.Time value set to UTC, or
|
||||||
|
// - using the TimeUnix, TimeUnixMicro, or TimeUnixDynamic option instead of TimeRFC3339.
|
||||||
TimeRFC3339
|
TimeRFC3339
|
||||||
|
|
||||||
// TimeRFC3339Nano causes time.Time to be encoded as RFC3339 formatted string with nanosecond precision.
|
// TimeRFC3339Nano causes time.Time to encode to a CBOR time (tag 0) with a text string content
|
||||||
|
// representing the time using 1-nanosecond precision in RFC3339 format. If the time.Time has a
|
||||||
|
// non-UTC timezone then a "localtime - UTC" numeric offset will be included as specified in RFC3339.
|
||||||
|
// NOTE: User applications can avoid including the RFC3339 numeric offset by:
|
||||||
|
// - providing a time.Time value set to UTC, or
|
||||||
|
// - using the TimeUnix, TimeUnixMicro, or TimeUnixDynamic option instead of TimeRFC3339Nano.
|
||||||
TimeRFC3339Nano
|
TimeRFC3339Nano
|
||||||
|
|
||||||
maxTimeMode
|
maxTimeMode
|
||||||
@@ -481,6 +524,24 @@ func (bmm BinaryMarshalerMode) valid() bool {
|
|||||||
return bmm >= 0 && bmm < maxBinaryMarshalerMode
|
return bmm >= 0 && bmm < maxBinaryMarshalerMode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TextMarshalerMode specifies how to encode types that implement encoding.TextMarshaler.
|
||||||
|
type TextMarshalerMode int
|
||||||
|
|
||||||
|
const (
|
||||||
|
// TextMarshalerNone does not recognize TextMarshaler implementations during encode.
|
||||||
|
// This is the default behavior.
|
||||||
|
TextMarshalerNone TextMarshalerMode = iota
|
||||||
|
|
||||||
|
// TextMarshalerTextString encodes the output of MarshalText to a CBOR text string.
|
||||||
|
TextMarshalerTextString
|
||||||
|
|
||||||
|
maxTextMarshalerMode
|
||||||
|
)
|
||||||
|
|
||||||
|
func (tmm TextMarshalerMode) valid() bool {
|
||||||
|
return tmm >= 0 && tmm < maxTextMarshalerMode
|
||||||
|
}
|
||||||
|
|
||||||
// EncOptions specifies encoding options.
|
// EncOptions specifies encoding options.
|
||||||
type EncOptions struct {
|
type EncOptions struct {
|
||||||
// Sort specifies sorting order.
|
// Sort specifies sorting order.
|
||||||
@@ -538,6 +599,14 @@ type EncOptions struct {
|
|||||||
|
|
||||||
// BinaryMarshaler specifies how to encode types that implement encoding.BinaryMarshaler.
|
// BinaryMarshaler specifies how to encode types that implement encoding.BinaryMarshaler.
|
||||||
BinaryMarshaler BinaryMarshalerMode
|
BinaryMarshaler BinaryMarshalerMode
|
||||||
|
|
||||||
|
// TextMarshaler specifies how to encode types that implement encoding.TextMarshaler.
|
||||||
|
TextMarshaler TextMarshalerMode
|
||||||
|
|
||||||
|
// JSONMarshalerTranscoder sets the transcoding scheme used to marshal types that implement
|
||||||
|
// json.Marshaler but do not also implement cbor.Marshaler. If nil, encoding behavior is not
|
||||||
|
// influenced by whether or not a type implements json.Marshaler.
|
||||||
|
JSONMarshalerTranscoder Transcoder
|
||||||
}
|
}
|
||||||
|
|
||||||
// CanonicalEncOptions returns EncOptions for "Canonical CBOR" encoding,
|
// CanonicalEncOptions returns EncOptions for "Canonical CBOR" encoding,
|
||||||
@@ -748,6 +817,9 @@ func (opts EncOptions) encMode() (*encMode, error) { //nolint:gocritic // ignore
|
|||||||
if !opts.BinaryMarshaler.valid() {
|
if !opts.BinaryMarshaler.valid() {
|
||||||
return nil, errors.New("cbor: invalid BinaryMarshaler " + strconv.Itoa(int(opts.BinaryMarshaler)))
|
return nil, errors.New("cbor: invalid BinaryMarshaler " + strconv.Itoa(int(opts.BinaryMarshaler)))
|
||||||
}
|
}
|
||||||
|
if !opts.TextMarshaler.valid() {
|
||||||
|
return nil, errors.New("cbor: invalid TextMarshaler " + strconv.Itoa(int(opts.TextMarshaler)))
|
||||||
|
}
|
||||||
em := encMode{
|
em := encMode{
|
||||||
sort: opts.Sort,
|
sort: opts.Sort,
|
||||||
shortestFloat: opts.ShortestFloat,
|
shortestFloat: opts.ShortestFloat,
|
||||||
@@ -767,13 +839,15 @@ func (opts EncOptions) encMode() (*encMode, error) { //nolint:gocritic // ignore
|
|||||||
byteSliceLaterEncodingTag: byteSliceLaterEncodingTag,
|
byteSliceLaterEncodingTag: byteSliceLaterEncodingTag,
|
||||||
byteArray: opts.ByteArray,
|
byteArray: opts.ByteArray,
|
||||||
binaryMarshaler: opts.BinaryMarshaler,
|
binaryMarshaler: opts.BinaryMarshaler,
|
||||||
|
textMarshaler: opts.TextMarshaler,
|
||||||
|
jsonMarshalerTranscoder: opts.JSONMarshalerTranscoder,
|
||||||
}
|
}
|
||||||
return &em, nil
|
return &em, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// EncMode is the main interface for CBOR encoding.
|
// EncMode is the main interface for CBOR encoding.
|
||||||
type EncMode interface {
|
type EncMode interface {
|
||||||
Marshal(v interface{}) ([]byte, error)
|
Marshal(v any) ([]byte, error)
|
||||||
NewEncoder(w io.Writer) *Encoder
|
NewEncoder(w io.Writer) *Encoder
|
||||||
EncOptions() EncOptions
|
EncOptions() EncOptions
|
||||||
}
|
}
|
||||||
@@ -783,7 +857,7 @@ type EncMode interface {
|
|||||||
// into the built-in buffer pool.
|
// into the built-in buffer pool.
|
||||||
type UserBufferEncMode interface {
|
type UserBufferEncMode interface {
|
||||||
EncMode
|
EncMode
|
||||||
MarshalToBuffer(v interface{}, buf *bytes.Buffer) error
|
MarshalToBuffer(v any, buf *bytes.Buffer) error
|
||||||
|
|
||||||
// This private method is to prevent users implementing
|
// This private method is to prevent users implementing
|
||||||
// this interface and so future additions to it will
|
// this interface and so future additions to it will
|
||||||
@@ -812,6 +886,8 @@ type encMode struct {
|
|||||||
byteSliceLaterEncodingTag uint64
|
byteSliceLaterEncodingTag uint64
|
||||||
byteArray ByteArrayMode
|
byteArray ByteArrayMode
|
||||||
binaryMarshaler BinaryMarshalerMode
|
binaryMarshaler BinaryMarshalerMode
|
||||||
|
textMarshaler TextMarshalerMode
|
||||||
|
jsonMarshalerTranscoder Transcoder
|
||||||
}
|
}
|
||||||
|
|
||||||
var defaultEncMode, _ = EncOptions{}.encMode()
|
var defaultEncMode, _ = EncOptions{}.encMode()
|
||||||
@@ -888,22 +964,24 @@ func getMarshalerDecMode(indefLength IndefLengthMode, tagsMd TagsMode) *decMode
|
|||||||
// EncOptions returns user specified options used to create this EncMode.
|
// EncOptions returns user specified options used to create this EncMode.
|
||||||
func (em *encMode) EncOptions() EncOptions {
|
func (em *encMode) EncOptions() EncOptions {
|
||||||
return EncOptions{
|
return EncOptions{
|
||||||
Sort: em.sort,
|
Sort: em.sort,
|
||||||
ShortestFloat: em.shortestFloat,
|
ShortestFloat: em.shortestFloat,
|
||||||
NaNConvert: em.nanConvert,
|
NaNConvert: em.nanConvert,
|
||||||
InfConvert: em.infConvert,
|
InfConvert: em.infConvert,
|
||||||
BigIntConvert: em.bigIntConvert,
|
BigIntConvert: em.bigIntConvert,
|
||||||
Time: em.time,
|
Time: em.time,
|
||||||
TimeTag: em.timeTag,
|
TimeTag: em.timeTag,
|
||||||
IndefLength: em.indefLength,
|
IndefLength: em.indefLength,
|
||||||
NilContainers: em.nilContainers,
|
NilContainers: em.nilContainers,
|
||||||
TagsMd: em.tagsMd,
|
TagsMd: em.tagsMd,
|
||||||
OmitEmpty: em.omitEmpty,
|
OmitEmpty: em.omitEmpty,
|
||||||
String: em.stringType,
|
String: em.stringType,
|
||||||
FieldName: em.fieldName,
|
FieldName: em.fieldName,
|
||||||
ByteSliceLaterFormat: em.byteSliceLaterFormat,
|
ByteSliceLaterFormat: em.byteSliceLaterFormat,
|
||||||
ByteArray: em.byteArray,
|
ByteArray: em.byteArray,
|
||||||
BinaryMarshaler: em.binaryMarshaler,
|
BinaryMarshaler: em.binaryMarshaler,
|
||||||
|
TextMarshaler: em.textMarshaler,
|
||||||
|
JSONMarshalerTranscoder: em.jsonMarshalerTranscoder,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -921,7 +999,7 @@ func (em *encMode) encTagBytes(t reflect.Type) []byte {
|
|||||||
// Marshal returns the CBOR encoding of v using em encoding mode.
|
// Marshal returns the CBOR encoding of v using em encoding mode.
|
||||||
//
|
//
|
||||||
// See the documentation for Marshal for details.
|
// See the documentation for Marshal for details.
|
||||||
func (em *encMode) Marshal(v interface{}) ([]byte, error) {
|
func (em *encMode) Marshal(v any) ([]byte, error) {
|
||||||
e := getEncodeBuffer()
|
e := getEncodeBuffer()
|
||||||
|
|
||||||
if err := encode(e, em, reflect.ValueOf(v)); err != nil {
|
if err := encode(e, em, reflect.ValueOf(v)); err != nil {
|
||||||
@@ -943,7 +1021,7 @@ func (em *encMode) Marshal(v interface{}) ([]byte, error) {
|
|||||||
// partially encoded data if error is returned.
|
// partially encoded data if error is returned.
|
||||||
//
|
//
|
||||||
// See Marshal for more details.
|
// See Marshal for more details.
|
||||||
func (em *encMode) MarshalToBuffer(v interface{}, buf *bytes.Buffer) error {
|
func (em *encMode) MarshalToBuffer(v any, buf *bytes.Buffer) error {
|
||||||
if buf == nil {
|
if buf == nil {
|
||||||
return fmt.Errorf("cbor: encoding buffer provided by user is nil")
|
return fmt.Errorf("cbor: encoding buffer provided by user is nil")
|
||||||
}
|
}
|
||||||
@@ -957,7 +1035,7 @@ func (em *encMode) NewEncoder(w io.Writer) *Encoder {
|
|||||||
|
|
||||||
// encodeBufferPool caches unused bytes.Buffer objects for later reuse.
|
// encodeBufferPool caches unused bytes.Buffer objects for later reuse.
|
||||||
var encodeBufferPool = sync.Pool{
|
var encodeBufferPool = sync.Pool{
|
||||||
New: func() interface{} {
|
New: func() any {
|
||||||
e := new(bytes.Buffer)
|
e := new(bytes.Buffer)
|
||||||
e.Grow(32) // TODO: make this configurable
|
e.Grow(32) // TODO: make this configurable
|
||||||
return e
|
return e
|
||||||
@@ -975,6 +1053,7 @@ func putEncodeBuffer(e *bytes.Buffer) {
|
|||||||
|
|
||||||
type encodeFunc func(e *bytes.Buffer, em *encMode, v reflect.Value) error
|
type encodeFunc func(e *bytes.Buffer, em *encMode, v reflect.Value) error
|
||||||
type isEmptyFunc func(em *encMode, v reflect.Value) (empty bool, err error)
|
type isEmptyFunc func(em *encMode, v reflect.Value) (empty bool, err error)
|
||||||
|
type isZeroFunc func(v reflect.Value) (zero bool, err error)
|
||||||
|
|
||||||
func encode(e *bytes.Buffer, em *encMode, v reflect.Value) error {
|
func encode(e *bytes.Buffer, em *encMode, v reflect.Value) error {
|
||||||
if !v.IsValid() {
|
if !v.IsValid() {
|
||||||
@@ -983,7 +1062,7 @@ func encode(e *bytes.Buffer, em *encMode, v reflect.Value) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
vt := v.Type()
|
vt := v.Type()
|
||||||
f, _ := getEncodeFunc(vt)
|
f, _, _ := getEncodeFunc(vt)
|
||||||
if f == nil {
|
if f == nil {
|
||||||
return &UnsupportedTypeError{vt}
|
return &UnsupportedTypeError{vt}
|
||||||
}
|
}
|
||||||
@@ -1483,6 +1562,15 @@ func encodeStruct(e *bytes.Buffer, em *encMode, v reflect.Value) (err error) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if f.omitZero {
|
||||||
|
zero, err := f.izf(fv)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if zero {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if !f.keyAsInt && em.fieldName == FieldNameToByteString {
|
if !f.keyAsInt && em.fieldName == FieldNameToByteString {
|
||||||
e.Write(f.cborNameByteString)
|
e.Write(f.cborNameByteString)
|
||||||
@@ -1665,6 +1753,107 @@ func (bme binaryMarshalerEncoder) isEmpty(em *encMode, v reflect.Value) (bool, e
|
|||||||
return len(data) == 0, nil
|
return len(data) == 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type textMarshalerEncoder struct {
|
||||||
|
alternateEncode encodeFunc
|
||||||
|
alternateIsEmpty isEmptyFunc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tme textMarshalerEncoder) encode(e *bytes.Buffer, em *encMode, v reflect.Value) error {
|
||||||
|
if em.textMarshaler == TextMarshalerNone {
|
||||||
|
return tme.alternateEncode(e, em, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
vt := v.Type()
|
||||||
|
m, ok := v.Interface().(encoding.TextMarshaler)
|
||||||
|
if !ok {
|
||||||
|
pv := reflect.New(vt)
|
||||||
|
pv.Elem().Set(v)
|
||||||
|
m = pv.Interface().(encoding.TextMarshaler)
|
||||||
|
}
|
||||||
|
data, err := m.MarshalText()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("cbor: cannot marshal text for %s: %w", vt, err)
|
||||||
|
}
|
||||||
|
if b := em.encTagBytes(vt); b != nil {
|
||||||
|
e.Write(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
encodeHead(e, byte(cborTypeTextString), uint64(len(data)))
|
||||||
|
e.Write(data)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tme textMarshalerEncoder) isEmpty(em *encMode, v reflect.Value) (bool, error) {
|
||||||
|
if em.textMarshaler == TextMarshalerNone {
|
||||||
|
return tme.alternateIsEmpty(em, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
m, ok := v.Interface().(encoding.TextMarshaler)
|
||||||
|
if !ok {
|
||||||
|
pv := reflect.New(v.Type())
|
||||||
|
pv.Elem().Set(v)
|
||||||
|
m = pv.Interface().(encoding.TextMarshaler)
|
||||||
|
}
|
||||||
|
data, err := m.MarshalText()
|
||||||
|
if err != nil {
|
||||||
|
return false, fmt.Errorf("cbor: cannot marshal text for %s: %w", v.Type(), err)
|
||||||
|
}
|
||||||
|
return len(data) == 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type jsonMarshalerEncoder struct {
|
||||||
|
alternateEncode encodeFunc
|
||||||
|
alternateIsEmpty isEmptyFunc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (jme jsonMarshalerEncoder) encode(e *bytes.Buffer, em *encMode, v reflect.Value) error {
|
||||||
|
if em.jsonMarshalerTranscoder == nil {
|
||||||
|
return jme.alternateEncode(e, em, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
vt := v.Type()
|
||||||
|
m, ok := v.Interface().(jsonMarshaler)
|
||||||
|
if !ok {
|
||||||
|
pv := reflect.New(vt)
|
||||||
|
pv.Elem().Set(v)
|
||||||
|
m = pv.Interface().(jsonMarshaler)
|
||||||
|
}
|
||||||
|
|
||||||
|
json, err := m.MarshalJSON()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
offset := e.Len()
|
||||||
|
|
||||||
|
if b := em.encTagBytes(vt); b != nil {
|
||||||
|
e.Write(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := em.jsonMarshalerTranscoder.Transcode(e, bytes.NewReader(json)); err != nil {
|
||||||
|
return &TranscodeError{err: err, rtype: vt, sourceFormat: "json", targetFormat: "cbor"}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate that the transcode function has written exactly one well-formed data item.
|
||||||
|
d := decoder{data: e.Bytes()[offset:], dm: getMarshalerDecMode(em.indefLength, em.tagsMd)}
|
||||||
|
if err := d.wellformed(false, true); err != nil {
|
||||||
|
e.Truncate(offset)
|
||||||
|
return &TranscodeError{err: err, rtype: vt, sourceFormat: "json", targetFormat: "cbor"}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (jme jsonMarshalerEncoder) isEmpty(em *encMode, v reflect.Value) (bool, error) {
|
||||||
|
if em.jsonMarshalerTranscoder == nil {
|
||||||
|
return jme.alternateIsEmpty(em, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// As with types implementing cbor.Marshaler, transcoded json.Marshaler values always encode
|
||||||
|
// as exactly one complete CBOR data item.
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
func encodeMarshalerType(e *bytes.Buffer, em *encMode, v reflect.Value) error {
|
func encodeMarshalerType(e *bytes.Buffer, em *encMode, v reflect.Value) error {
|
||||||
if em.tagsMd == TagsForbidden && v.Type() == typeRawTag {
|
if em.tagsMd == TagsForbidden && v.Type() == typeRawTag {
|
||||||
return errors.New("cbor: cannot encode cbor.RawTag when TagsMd is TagsForbidden")
|
return errors.New("cbor: cannot encode cbor.RawTag when TagsMd is TagsForbidden")
|
||||||
@@ -1768,41 +1957,45 @@ func encodeHead(e *bytes.Buffer, t byte, n uint64) int {
|
|||||||
return headSize
|
return headSize
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type jsonMarshaler interface{ MarshalJSON() ([]byte, error) }
|
||||||
|
|
||||||
var (
|
var (
|
||||||
typeMarshaler = reflect.TypeOf((*Marshaler)(nil)).Elem()
|
typeMarshaler = reflect.TypeOf((*Marshaler)(nil)).Elem()
|
||||||
typeBinaryMarshaler = reflect.TypeOf((*encoding.BinaryMarshaler)(nil)).Elem()
|
typeBinaryMarshaler = reflect.TypeOf((*encoding.BinaryMarshaler)(nil)).Elem()
|
||||||
|
typeTextMarshaler = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem()
|
||||||
|
typeJSONMarshaler = reflect.TypeOf((*jsonMarshaler)(nil)).Elem()
|
||||||
typeRawMessage = reflect.TypeOf(RawMessage(nil))
|
typeRawMessage = reflect.TypeOf(RawMessage(nil))
|
||||||
typeByteString = reflect.TypeOf(ByteString(""))
|
typeByteString = reflect.TypeOf(ByteString(""))
|
||||||
)
|
)
|
||||||
|
|
||||||
func getEncodeFuncInternal(t reflect.Type) (ef encodeFunc, ief isEmptyFunc) {
|
func getEncodeFuncInternal(t reflect.Type) (ef encodeFunc, ief isEmptyFunc, izf isZeroFunc) {
|
||||||
k := t.Kind()
|
k := t.Kind()
|
||||||
if k == reflect.Ptr {
|
if k == reflect.Pointer {
|
||||||
return getEncodeIndirectValueFunc(t), isEmptyPtr
|
return getEncodeIndirectValueFunc(t), isEmptyPtr, getIsZeroFunc(t)
|
||||||
}
|
}
|
||||||
switch t {
|
switch t {
|
||||||
case typeSimpleValue:
|
case typeSimpleValue:
|
||||||
return encodeMarshalerType, isEmptyUint
|
return encodeMarshalerType, isEmptyUint, getIsZeroFunc(t)
|
||||||
|
|
||||||
case typeTag:
|
case typeTag:
|
||||||
return encodeTag, alwaysNotEmpty
|
return encodeTag, alwaysNotEmpty, getIsZeroFunc(t)
|
||||||
|
|
||||||
case typeTime:
|
case typeTime:
|
||||||
return encodeTime, alwaysNotEmpty
|
return encodeTime, alwaysNotEmpty, getIsZeroFunc(t)
|
||||||
|
|
||||||
case typeBigInt:
|
case typeBigInt:
|
||||||
return encodeBigInt, alwaysNotEmpty
|
return encodeBigInt, alwaysNotEmpty, getIsZeroFunc(t)
|
||||||
|
|
||||||
case typeRawMessage:
|
case typeRawMessage:
|
||||||
return encodeMarshalerType, isEmptySlice
|
return encodeMarshalerType, isEmptySlice, getIsZeroFunc(t)
|
||||||
|
|
||||||
case typeByteString:
|
case typeByteString:
|
||||||
return encodeMarshalerType, isEmptyString
|
return encodeMarshalerType, isEmptyString, getIsZeroFunc(t)
|
||||||
}
|
}
|
||||||
if reflect.PtrTo(t).Implements(typeMarshaler) {
|
if reflect.PointerTo(t).Implements(typeMarshaler) {
|
||||||
return encodeMarshalerType, alwaysNotEmpty
|
return encodeMarshalerType, alwaysNotEmpty, getIsZeroFunc(t)
|
||||||
}
|
}
|
||||||
if reflect.PtrTo(t).Implements(typeBinaryMarshaler) {
|
if reflect.PointerTo(t).Implements(typeBinaryMarshaler) {
|
||||||
defer func() {
|
defer func() {
|
||||||
// capture encoding method used for modes that disable BinaryMarshaler
|
// capture encoding method used for modes that disable BinaryMarshaler
|
||||||
bme := binaryMarshalerEncoder{
|
bme := binaryMarshalerEncoder{
|
||||||
@@ -1813,41 +2006,65 @@ func getEncodeFuncInternal(t reflect.Type) (ef encodeFunc, ief isEmptyFunc) {
|
|||||||
ief = bme.isEmpty
|
ief = bme.isEmpty
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
if reflect.PointerTo(t).Implements(typeTextMarshaler) {
|
||||||
|
defer func() {
|
||||||
|
// capture encoding method used for modes that disable TextMarshaler
|
||||||
|
tme := textMarshalerEncoder{
|
||||||
|
alternateEncode: ef,
|
||||||
|
alternateIsEmpty: ief,
|
||||||
|
}
|
||||||
|
ef = tme.encode
|
||||||
|
ief = tme.isEmpty
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
if reflect.PointerTo(t).Implements(typeJSONMarshaler) {
|
||||||
|
defer func() {
|
||||||
|
// capture encoding method used for modes that don't support transcoding
|
||||||
|
// from types that implement json.Marshaler.
|
||||||
|
jme := jsonMarshalerEncoder{
|
||||||
|
alternateEncode: ef,
|
||||||
|
alternateIsEmpty: ief,
|
||||||
|
}
|
||||||
|
ef = jme.encode
|
||||||
|
ief = jme.isEmpty
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
switch k {
|
switch k {
|
||||||
case reflect.Bool:
|
case reflect.Bool:
|
||||||
return encodeBool, isEmptyBool
|
return encodeBool, isEmptyBool, getIsZeroFunc(t)
|
||||||
|
|
||||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||||
return encodeInt, isEmptyInt
|
return encodeInt, isEmptyInt, getIsZeroFunc(t)
|
||||||
|
|
||||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||||
return encodeUint, isEmptyUint
|
return encodeUint, isEmptyUint, getIsZeroFunc(t)
|
||||||
|
|
||||||
case reflect.Float32, reflect.Float64:
|
case reflect.Float32, reflect.Float64:
|
||||||
return encodeFloat, isEmptyFloat
|
return encodeFloat, isEmptyFloat, getIsZeroFunc(t)
|
||||||
|
|
||||||
case reflect.String:
|
case reflect.String:
|
||||||
return encodeString, isEmptyString
|
return encodeString, isEmptyString, getIsZeroFunc(t)
|
||||||
|
|
||||||
case reflect.Slice:
|
case reflect.Slice:
|
||||||
if t.Elem().Kind() == reflect.Uint8 {
|
if t.Elem().Kind() == reflect.Uint8 {
|
||||||
return encodeByteString, isEmptySlice
|
return encodeByteString, isEmptySlice, getIsZeroFunc(t)
|
||||||
}
|
}
|
||||||
fallthrough
|
fallthrough
|
||||||
|
|
||||||
case reflect.Array:
|
case reflect.Array:
|
||||||
f, _ := getEncodeFunc(t.Elem())
|
f, _, _ := getEncodeFunc(t.Elem())
|
||||||
if f == nil {
|
if f == nil {
|
||||||
return nil, nil
|
return nil, nil, nil
|
||||||
}
|
}
|
||||||
return arrayEncodeFunc{f: f}.encode, isEmptySlice
|
return arrayEncodeFunc{f: f}.encode, isEmptySlice, getIsZeroFunc(t)
|
||||||
|
|
||||||
case reflect.Map:
|
case reflect.Map:
|
||||||
f := getEncodeMapFunc(t)
|
f := getEncodeMapFunc(t)
|
||||||
if f == nil {
|
if f == nil {
|
||||||
return nil, nil
|
return nil, nil, nil
|
||||||
}
|
}
|
||||||
return f, isEmptyMap
|
return f, isEmptyMap, getIsZeroFunc(t)
|
||||||
|
|
||||||
case reflect.Struct:
|
case reflect.Struct:
|
||||||
// Get struct's special field "_" tag options
|
// Get struct's special field "_" tag options
|
||||||
@@ -1855,31 +2072,31 @@ func getEncodeFuncInternal(t reflect.Type) (ef encodeFunc, ief isEmptyFunc) {
|
|||||||
tag := f.Tag.Get("cbor")
|
tag := f.Tag.Get("cbor")
|
||||||
if tag != "-" {
|
if tag != "-" {
|
||||||
if hasToArrayOption(tag) {
|
if hasToArrayOption(tag) {
|
||||||
return encodeStructToArray, isEmptyStruct
|
return encodeStructToArray, isEmptyStruct, isZeroFieldStruct
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return encodeStruct, isEmptyStruct
|
return encodeStruct, isEmptyStruct, getIsZeroFunc(t)
|
||||||
|
|
||||||
case reflect.Interface:
|
case reflect.Interface:
|
||||||
return encodeIntf, isEmptyIntf
|
return encodeIntf, isEmptyIntf, getIsZeroFunc(t)
|
||||||
}
|
}
|
||||||
return nil, nil
|
return nil, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getEncodeIndirectValueFunc(t reflect.Type) encodeFunc {
|
func getEncodeIndirectValueFunc(t reflect.Type) encodeFunc {
|
||||||
for t.Kind() == reflect.Ptr {
|
for t.Kind() == reflect.Pointer {
|
||||||
t = t.Elem()
|
t = t.Elem()
|
||||||
}
|
}
|
||||||
f, _ := getEncodeFunc(t)
|
f, _, _ := getEncodeFunc(t)
|
||||||
if f == nil {
|
if f == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return func(e *bytes.Buffer, em *encMode, v reflect.Value) error {
|
return func(e *bytes.Buffer, em *encMode, v reflect.Value) error {
|
||||||
for v.Kind() == reflect.Ptr && !v.IsNil() {
|
for v.Kind() == reflect.Pointer && !v.IsNil() {
|
||||||
v = v.Elem()
|
v = v.Elem()
|
||||||
}
|
}
|
||||||
if v.Kind() == reflect.Ptr && v.IsNil() {
|
if v.Kind() == reflect.Pointer && v.IsNil() {
|
||||||
e.Write(cborNil)
|
e.Write(cborNil)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -1987,3 +2204,96 @@ func float32NaNFromReflectValue(v reflect.Value) float32 {
|
|||||||
f32 := p.Convert(reflect.TypeOf((*float32)(nil))).Elem().Interface().(float32)
|
f32 := p.Convert(reflect.TypeOf((*float32)(nil))).Elem().Interface().(float32)
|
||||||
return f32
|
return f32
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type isZeroer interface {
|
||||||
|
IsZero() bool
|
||||||
|
}
|
||||||
|
|
||||||
|
var isZeroerType = reflect.TypeOf((*isZeroer)(nil)).Elem()
|
||||||
|
|
||||||
|
// getIsZeroFunc returns a function for the given type that can be called to determine if a given value is zero.
|
||||||
|
// Types that implement `IsZero() bool` are delegated to for non-nil values.
|
||||||
|
// Types that do not implement `IsZero() bool` use the reflect.Value#IsZero() implementation.
|
||||||
|
// The returned function matches behavior of stdlib encoding/json behavior in Go 1.24+.
|
||||||
|
func getIsZeroFunc(t reflect.Type) isZeroFunc {
|
||||||
|
// Provide a function that uses a type's IsZero method if defined.
|
||||||
|
switch {
|
||||||
|
case t == nil:
|
||||||
|
return isZeroDefault
|
||||||
|
case t.Kind() == reflect.Interface && t.Implements(isZeroerType):
|
||||||
|
return isZeroInterfaceCustom
|
||||||
|
case t.Kind() == reflect.Pointer && t.Implements(isZeroerType):
|
||||||
|
return isZeroPointerCustom
|
||||||
|
case t.Implements(isZeroerType):
|
||||||
|
return isZeroCustom
|
||||||
|
case reflect.PointerTo(t).Implements(isZeroerType):
|
||||||
|
return isZeroAddrCustom
|
||||||
|
default:
|
||||||
|
return isZeroDefault
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// isZeroInterfaceCustom returns true for nil or pointer-to-nil values,
|
||||||
|
// and delegates to the custom IsZero() implementation otherwise.
|
||||||
|
func isZeroInterfaceCustom(v reflect.Value) (bool, error) {
|
||||||
|
kind := v.Kind()
|
||||||
|
|
||||||
|
switch kind {
|
||||||
|
case reflect.Chan, reflect.Func, reflect.Map, reflect.Pointer, reflect.Interface, reflect.Slice:
|
||||||
|
if v.IsNil() {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch kind {
|
||||||
|
case reflect.Interface, reflect.Pointer:
|
||||||
|
if elem := v.Elem(); elem.Kind() == reflect.Pointer && elem.IsNil() {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return v.Interface().(isZeroer).IsZero(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// isZeroPointerCustom returns true for nil values,
|
||||||
|
// and delegates to the custom IsZero() implementation otherwise.
|
||||||
|
func isZeroPointerCustom(v reflect.Value) (bool, error) {
|
||||||
|
if v.IsNil() {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
return v.Interface().(isZeroer).IsZero(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// isZeroCustom delegates to the custom IsZero() implementation.
|
||||||
|
func isZeroCustom(v reflect.Value) (bool, error) {
|
||||||
|
return v.Interface().(isZeroer).IsZero(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// isZeroAddrCustom delegates to the custom IsZero() implementation of the addr of the value.
|
||||||
|
func isZeroAddrCustom(v reflect.Value) (bool, error) {
|
||||||
|
if !v.CanAddr() {
|
||||||
|
// Temporarily box v so we can take the address.
|
||||||
|
v2 := reflect.New(v.Type()).Elem()
|
||||||
|
v2.Set(v)
|
||||||
|
v = v2
|
||||||
|
}
|
||||||
|
return v.Addr().Interface().(isZeroer).IsZero(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// isZeroDefault calls reflect.Value#IsZero()
|
||||||
|
func isZeroDefault(v reflect.Value) (bool, error) {
|
||||||
|
if !v.IsValid() {
|
||||||
|
// v is zero value
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
return v.IsZero(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// isZeroFieldStruct is used to determine whether to omit toarray structs
|
||||||
|
func isZeroFieldStruct(v reflect.Value) (bool, error) {
|
||||||
|
structType, err := getEncodingStructType(v.Type())
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return len(structType.fields) == 0, nil
|
||||||
|
}
|
||||||
|
|||||||
10
vendor/github.com/fxamacker/cbor/v2/encode_map.go
generated
vendored
10
vendor/github.com/fxamacker/cbor/v2/encode_map.go
generated
vendored
@@ -1,8 +1,6 @@
|
|||||||
// Copyright (c) Faye Amacker. All rights reserved.
|
// Copyright (c) Faye Amacker. All rights reserved.
|
||||||
// Licensed under the MIT License. See LICENSE in the project root for license information.
|
// Licensed under the MIT License. See LICENSE in the project root for license information.
|
||||||
|
|
||||||
//go:build go1.20
|
|
||||||
|
|
||||||
package cbor
|
package cbor
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -67,8 +65,8 @@ func (me *mapKeyValueEncodeFunc) encodeKeyValues(e *bytes.Buffer, em *encMode, v
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getEncodeMapFunc(t reflect.Type) encodeFunc {
|
func getEncodeMapFunc(t reflect.Type) encodeFunc {
|
||||||
kf, _ := getEncodeFunc(t.Key())
|
kf, _, _ := getEncodeFunc(t.Key())
|
||||||
ef, _ := getEncodeFunc(t.Elem())
|
ef, _, _ := getEncodeFunc(t.Elem())
|
||||||
if kf == nil || ef == nil {
|
if kf == nil || ef == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -76,13 +74,13 @@ func getEncodeMapFunc(t reflect.Type) encodeFunc {
|
|||||||
kf: kf,
|
kf: kf,
|
||||||
ef: ef,
|
ef: ef,
|
||||||
kpool: sync.Pool{
|
kpool: sync.Pool{
|
||||||
New: func() interface{} {
|
New: func() any {
|
||||||
rk := reflect.New(t.Key()).Elem()
|
rk := reflect.New(t.Key()).Elem()
|
||||||
return &rk
|
return &rk
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
vpool: sync.Pool{
|
vpool: sync.Pool{
|
||||||
New: func() interface{} {
|
New: func() any {
|
||||||
rv := reflect.New(t.Elem()).Elem()
|
rv := reflect.New(t.Elem()).Elem()
|
||||||
return &rv
|
return &rv
|
||||||
},
|
},
|
||||||
|
|||||||
60
vendor/github.com/fxamacker/cbor/v2/encode_map_go117.go
generated
vendored
60
vendor/github.com/fxamacker/cbor/v2/encode_map_go117.go
generated
vendored
@@ -1,60 +0,0 @@
|
|||||||
// Copyright (c) Faye Amacker. All rights reserved.
|
|
||||||
// Licensed under the MIT License. See LICENSE in the project root for license information.
|
|
||||||
|
|
||||||
//go:build !go1.20
|
|
||||||
|
|
||||||
package cbor
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"reflect"
|
|
||||||
)
|
|
||||||
|
|
||||||
type mapKeyValueEncodeFunc struct {
|
|
||||||
kf, ef encodeFunc
|
|
||||||
}
|
|
||||||
|
|
||||||
func (me *mapKeyValueEncodeFunc) encodeKeyValues(e *bytes.Buffer, em *encMode, v reflect.Value, kvs []keyValue) error {
|
|
||||||
if kvs == nil {
|
|
||||||
for i, iter := 0, v.MapRange(); iter.Next(); i++ {
|
|
||||||
if err := me.kf(e, em, iter.Key()); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := me.ef(e, em, iter.Value()); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
initial := e.Len()
|
|
||||||
for i, iter := 0, v.MapRange(); iter.Next(); i++ {
|
|
||||||
offset := e.Len()
|
|
||||||
if err := me.kf(e, em, iter.Key()); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
valueOffset := e.Len()
|
|
||||||
if err := me.ef(e, em, iter.Value()); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
kvs[i] = keyValue{
|
|
||||||
offset: offset - initial,
|
|
||||||
valueOffset: valueOffset - initial,
|
|
||||||
nextOffset: e.Len() - initial,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getEncodeMapFunc(t reflect.Type) encodeFunc {
|
|
||||||
kf, _ := getEncodeFunc(t.Key())
|
|
||||||
ef, _ := getEncodeFunc(t.Elem())
|
|
||||||
if kf == nil || ef == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
mkv := &mapKeyValueEncodeFunc{kf: kf, ef: ef}
|
|
||||||
return mapEncodeFunc{
|
|
||||||
e: mkv.encodeKeyValues,
|
|
||||||
}.encode
|
|
||||||
}
|
|
||||||
8
vendor/github.com/fxamacker/cbor/v2/omitzero_go124.go
generated
vendored
Normal file
8
vendor/github.com/fxamacker/cbor/v2/omitzero_go124.go
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
// Copyright (c) Faye Amacker. All rights reserved.
|
||||||
|
// Licensed under the MIT License. See LICENSE in the project root for license information.
|
||||||
|
|
||||||
|
//go:build go1.24
|
||||||
|
|
||||||
|
package cbor
|
||||||
|
|
||||||
|
var jsonStdlibSupportsOmitzero = true
|
||||||
8
vendor/github.com/fxamacker/cbor/v2/omitzero_pre_go124.go
generated
vendored
Normal file
8
vendor/github.com/fxamacker/cbor/v2/omitzero_pre_go124.go
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
// Copyright (c) Faye Amacker. All rights reserved.
|
||||||
|
// Licensed under the MIT License. See LICENSE in the project root for license information.
|
||||||
|
|
||||||
|
//go:build !go1.24
|
||||||
|
|
||||||
|
package cbor
|
||||||
|
|
||||||
|
var jsonStdlibSupportsOmitzero = false
|
||||||
29
vendor/github.com/fxamacker/cbor/v2/simplevalue.go
generated
vendored
29
vendor/github.com/fxamacker/cbor/v2/simplevalue.go
generated
vendored
@@ -1,3 +1,6 @@
|
|||||||
|
// Copyright (c) Faye Amacker. All rights reserved.
|
||||||
|
// Licensed under the MIT License. See LICENSE in the project root for license information.
|
||||||
|
|
||||||
package cbor
|
package cbor
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -45,6 +48,9 @@ func (sv SimpleValue) MarshalCBOR() ([]byte, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// UnmarshalCBOR decodes CBOR simple value (major type 7) to SimpleValue.
|
// UnmarshalCBOR decodes CBOR simple value (major type 7) to SimpleValue.
|
||||||
|
//
|
||||||
|
// Deprecated: No longer used by this codec; kept for compatibility
|
||||||
|
// with user apps that directly call this function.
|
||||||
func (sv *SimpleValue) UnmarshalCBOR(data []byte) error {
|
func (sv *SimpleValue) UnmarshalCBOR(data []byte) error {
|
||||||
if sv == nil {
|
if sv == nil {
|
||||||
return errors.New("cbor.SimpleValue: UnmarshalCBOR on nil pointer")
|
return errors.New("cbor.SimpleValue: UnmarshalCBOR on nil pointer")
|
||||||
@@ -52,6 +58,29 @@ func (sv *SimpleValue) UnmarshalCBOR(data []byte) error {
|
|||||||
|
|
||||||
d := decoder{data: data, dm: defaultDecMode}
|
d := decoder{data: data, dm: defaultDecMode}
|
||||||
|
|
||||||
|
// Check well-formedness of CBOR data item.
|
||||||
|
// SimpleValue.UnmarshalCBOR() is exported, so
|
||||||
|
// the codec needs to support same behavior for:
|
||||||
|
// - Unmarshal(data, *SimpleValue)
|
||||||
|
// - SimpleValue.UnmarshalCBOR(data)
|
||||||
|
err := d.wellformed(false, false)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return sv.unmarshalCBOR(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// unmarshalCBOR decodes CBOR simple value (major type 7) to SimpleValue.
|
||||||
|
// This function assumes data is well-formed, and does not perform bounds checking.
|
||||||
|
// This function is called by Unmarshal().
|
||||||
|
func (sv *SimpleValue) unmarshalCBOR(data []byte) error {
|
||||||
|
if sv == nil {
|
||||||
|
return errors.New("cbor.SimpleValue: UnmarshalCBOR on nil pointer")
|
||||||
|
}
|
||||||
|
|
||||||
|
d := decoder{data: data, dm: defaultDecMode}
|
||||||
|
|
||||||
typ, ai, val := d.getHead()
|
typ, ai, val := d.getHead()
|
||||||
|
|
||||||
if typ != cborTypePrimitives {
|
if typ != cborTypePrimitives {
|
||||||
|
|||||||
4
vendor/github.com/fxamacker/cbor/v2/stream.go
generated
vendored
4
vendor/github.com/fxamacker/cbor/v2/stream.go
generated
vendored
@@ -26,7 +26,7 @@ func NewDecoder(r io.Reader) *Decoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Decode reads CBOR value and decodes it into the value pointed to by v.
|
// Decode reads CBOR value and decodes it into the value pointed to by v.
|
||||||
func (dec *Decoder) Decode(v interface{}) error {
|
func (dec *Decoder) Decode(v any) error {
|
||||||
_, err := dec.readNext()
|
_, err := dec.readNext()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Return validation error or read error.
|
// Return validation error or read error.
|
||||||
@@ -170,7 +170,7 @@ func NewEncoder(w io.Writer) *Encoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Encode writes the CBOR encoding of v.
|
// Encode writes the CBOR encoding of v.
|
||||||
func (enc *Encoder) Encode(v interface{}) error {
|
func (enc *Encoder) Encode(v any) error {
|
||||||
if len(enc.indefTypes) > 0 && v != nil {
|
if len(enc.indefTypes) > 0 && v != nil {
|
||||||
indefType := enc.indefTypes[len(enc.indefTypes)-1]
|
indefType := enc.indefTypes[len(enc.indefTypes)-1]
|
||||||
if indefType == cborTypeTextString {
|
if indefType == cborTypeTextString {
|
||||||
|
|||||||
18
vendor/github.com/fxamacker/cbor/v2/structfields.go
generated
vendored
18
vendor/github.com/fxamacker/cbor/v2/structfields.go
generated
vendored
@@ -18,9 +18,11 @@ type field struct {
|
|||||||
typ reflect.Type
|
typ reflect.Type
|
||||||
ef encodeFunc
|
ef encodeFunc
|
||||||
ief isEmptyFunc
|
ief isEmptyFunc
|
||||||
|
izf isZeroFunc
|
||||||
typInfo *typeInfo // used to decoder to reuse type info
|
typInfo *typeInfo // used to decoder to reuse type info
|
||||||
tagged bool // used to choose dominant field (at the same level tagged fields dominate untagged fields)
|
tagged bool // used to choose dominant field (at the same level tagged fields dominate untagged fields)
|
||||||
omitEmpty bool // used to skip empty field
|
omitEmpty bool // used to skip empty field
|
||||||
|
omitZero bool // used to skip zero field
|
||||||
keyAsInt bool // used to encode/decode field name as int
|
keyAsInt bool // used to encode/decode field name as int
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,7 +159,7 @@ func appendFields(
|
|||||||
f := t.Field(i)
|
f := t.Field(i)
|
||||||
|
|
||||||
ft := f.Type
|
ft := f.Type
|
||||||
for ft.Kind() == reflect.Ptr {
|
for ft.Kind() == reflect.Pointer {
|
||||||
ft = ft.Elem()
|
ft = ft.Elem()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,9 +167,11 @@ func appendFields(
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cborTag := true
|
||||||
tag := f.Tag.Get("cbor")
|
tag := f.Tag.Get("cbor")
|
||||||
if tag == "" {
|
if tag == "" {
|
||||||
tag = f.Tag.Get("json")
|
tag = f.Tag.Get("json")
|
||||||
|
cborTag = false
|
||||||
}
|
}
|
||||||
if tag == "-" {
|
if tag == "-" {
|
||||||
continue
|
continue
|
||||||
@@ -177,7 +181,7 @@ func appendFields(
|
|||||||
|
|
||||||
// Parse field tag options
|
// Parse field tag options
|
||||||
var tagFieldName string
|
var tagFieldName string
|
||||||
var omitempty, keyasint bool
|
var omitempty, omitzero, keyasint bool
|
||||||
for j := 0; tag != ""; j++ {
|
for j := 0; tag != ""; j++ {
|
||||||
var token string
|
var token string
|
||||||
idx := strings.IndexByte(tag, ',')
|
idx := strings.IndexByte(tag, ',')
|
||||||
@@ -192,6 +196,10 @@ func appendFields(
|
|||||||
switch token {
|
switch token {
|
||||||
case "omitempty":
|
case "omitempty":
|
||||||
omitempty = true
|
omitempty = true
|
||||||
|
case "omitzero":
|
||||||
|
if cborTag || jsonStdlibSupportsOmitzero {
|
||||||
|
omitzero = true
|
||||||
|
}
|
||||||
case "keyasint":
|
case "keyasint":
|
||||||
keyasint = true
|
keyasint = true
|
||||||
}
|
}
|
||||||
@@ -213,6 +221,7 @@ func appendFields(
|
|||||||
idx: fIdx,
|
idx: fIdx,
|
||||||
typ: f.Type,
|
typ: f.Type,
|
||||||
omitEmpty: omitempty,
|
omitEmpty: omitempty,
|
||||||
|
omitZero: omitzero,
|
||||||
keyAsInt: keyasint,
|
keyAsInt: keyasint,
|
||||||
tagged: tagged})
|
tagged: tagged})
|
||||||
} else {
|
} else {
|
||||||
@@ -230,8 +239,7 @@ func appendFields(
|
|||||||
// a nonexportable anonymous field of struct type.
|
// a nonexportable anonymous field of struct type.
|
||||||
// Nonexportable anonymous field of struct type can contain exportable fields.
|
// Nonexportable anonymous field of struct type can contain exportable fields.
|
||||||
func isFieldExportable(f reflect.StructField, fk reflect.Kind) bool { //nolint:gocritic // ignore hugeParam
|
func isFieldExportable(f reflect.StructField, fk reflect.Kind) bool { //nolint:gocritic // ignore hugeParam
|
||||||
exportable := f.PkgPath == ""
|
return f.IsExported() || (f.Anonymous && fk == reflect.Struct)
|
||||||
return exportable || (f.Anonymous && fk == reflect.Struct)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type embeddedFieldNullPtrFunc func(reflect.Value) (reflect.Value, error)
|
type embeddedFieldNullPtrFunc func(reflect.Value) (reflect.Value, error)
|
||||||
@@ -244,7 +252,7 @@ func getFieldValue(v reflect.Value, idx []int, f embeddedFieldNullPtrFunc) (fv r
|
|||||||
fv = fv.Field(n)
|
fv = fv.Field(n)
|
||||||
|
|
||||||
if i < len(idx)-1 {
|
if i < len(idx)-1 {
|
||||||
if fv.Kind() == reflect.Ptr && fv.Type().Elem().Kind() == reflect.Struct {
|
if fv.Kind() == reflect.Pointer && fv.Type().Elem().Kind() == reflect.Struct {
|
||||||
if fv.IsNil() {
|
if fv.IsNil() {
|
||||||
// Null pointer to embedded struct field
|
// Null pointer to embedded struct field
|
||||||
fv, err = f(fv)
|
fv, err = f(fv)
|
||||||
|
|||||||
48
vendor/github.com/fxamacker/cbor/v2/tag.go
generated
vendored
48
vendor/github.com/fxamacker/cbor/v2/tag.go
generated
vendored
@@ -1,3 +1,6 @@
|
|||||||
|
// Copyright (c) Faye Amacker. All rights reserved.
|
||||||
|
// Licensed under the MIT License. See LICENSE in the project root for license information.
|
||||||
|
|
||||||
package cbor
|
package cbor
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -7,27 +10,54 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Tag represents CBOR tag data, including tag number and unmarshaled tag content. Marshaling and
|
// Tag represents a tagged data item (CBOR major type 6), comprising a tag number and the unmarshaled tag content.
|
||||||
// unmarshaling of tag content is subject to any encode and decode options that would apply to
|
// NOTE: The same encoding and decoding options that apply to untagged CBOR data items also applies to tag content
|
||||||
// enclosed data item if it were to appear outside of a tag.
|
// during encoding and decoding.
|
||||||
type Tag struct {
|
type Tag struct {
|
||||||
Number uint64
|
Number uint64
|
||||||
Content interface{}
|
Content any
|
||||||
}
|
}
|
||||||
|
|
||||||
// RawTag represents CBOR tag data, including tag number and raw tag content.
|
// RawTag represents a tagged data item (CBOR major type 6), comprising a tag number and the raw tag content.
|
||||||
// RawTag implements Unmarshaler and Marshaler interfaces.
|
// The raw tag content (enclosed data item) is a CBOR-encoded data item.
|
||||||
|
// RawTag can be used to delay decoding a CBOR data item or precompute encoding a CBOR data item.
|
||||||
type RawTag struct {
|
type RawTag struct {
|
||||||
Number uint64
|
Number uint64
|
||||||
Content RawMessage
|
Content RawMessage
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnmarshalCBOR sets *t with tag number and raw tag content copied from data.
|
// UnmarshalCBOR sets *t with the tag number and the raw tag content copied from data.
|
||||||
|
//
|
||||||
|
// Deprecated: No longer used by this codec; kept for compatibility
|
||||||
|
// with user apps that directly call this function.
|
||||||
func (t *RawTag) UnmarshalCBOR(data []byte) error {
|
func (t *RawTag) UnmarshalCBOR(data []byte) error {
|
||||||
if t == nil {
|
if t == nil {
|
||||||
return errors.New("cbor.RawTag: UnmarshalCBOR on nil pointer")
|
return errors.New("cbor.RawTag: UnmarshalCBOR on nil pointer")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
d := decoder{data: data, dm: defaultDecMode}
|
||||||
|
|
||||||
|
// Check if data is a well-formed CBOR data item.
|
||||||
|
// RawTag.UnmarshalCBOR() is exported, so
|
||||||
|
// the codec needs to support same behavior for:
|
||||||
|
// - Unmarshal(data, *RawTag)
|
||||||
|
// - RawTag.UnmarshalCBOR(data)
|
||||||
|
err := d.wellformed(false, false)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return t.unmarshalCBOR(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// unmarshalCBOR sets *t with the tag number and the raw tag content copied from data.
|
||||||
|
// This function assumes data is well-formed, and does not perform bounds checking.
|
||||||
|
// This function is called by Unmarshal().
|
||||||
|
func (t *RawTag) unmarshalCBOR(data []byte) error {
|
||||||
|
if t == nil {
|
||||||
|
return errors.New("cbor.RawTag: UnmarshalCBOR on nil pointer")
|
||||||
|
}
|
||||||
|
|
||||||
// Decoding CBOR null and undefined to cbor.RawTag is no-op.
|
// Decoding CBOR null and undefined to cbor.RawTag is no-op.
|
||||||
if len(data) == 1 && (data[0] == 0xf6 || data[0] == 0xf7) {
|
if len(data) == 1 && (data[0] == 0xf6 || data[0] == 0xf7) {
|
||||||
return nil
|
return nil
|
||||||
@@ -193,7 +223,7 @@ func (t *syncTagSet) Add(opts TagOptions, contentType reflect.Type, num uint64,
|
|||||||
if contentType == nil {
|
if contentType == nil {
|
||||||
return errors.New("cbor: cannot add nil content type to TagSet")
|
return errors.New("cbor: cannot add nil content type to TagSet")
|
||||||
}
|
}
|
||||||
for contentType.Kind() == reflect.Ptr {
|
for contentType.Kind() == reflect.Pointer {
|
||||||
contentType = contentType.Elem()
|
contentType = contentType.Elem()
|
||||||
}
|
}
|
||||||
tag, err := newTagItem(opts, contentType, num, nestedNum...)
|
tag, err := newTagItem(opts, contentType, num, nestedNum...)
|
||||||
@@ -216,7 +246,7 @@ func (t *syncTagSet) Add(opts TagOptions, contentType reflect.Type, num uint64,
|
|||||||
|
|
||||||
// Remove removes given tag content type from TagSet.
|
// Remove removes given tag content type from TagSet.
|
||||||
func (t *syncTagSet) Remove(contentType reflect.Type) {
|
func (t *syncTagSet) Remove(contentType reflect.Type) {
|
||||||
for contentType.Kind() == reflect.Ptr {
|
for contentType.Kind() == reflect.Pointer {
|
||||||
contentType = contentType.Elem()
|
contentType = contentType.Elem()
|
||||||
}
|
}
|
||||||
t.Lock()
|
t.Lock()
|
||||||
|
|||||||
82
vendor/github.com/go-logfmt/logfmt/README.md
generated
vendored
82
vendor/github.com/go-logfmt/logfmt/README.md
generated
vendored
@@ -1,41 +1,41 @@
|
|||||||
# logfmt
|
# logfmt
|
||||||
|
|
||||||
[](https://pkg.go.dev/github.com/go-logfmt/logfmt)
|
[](https://pkg.go.dev/github.com/go-logfmt/logfmt)
|
||||||
[](https://goreportcard.com/report/go-logfmt/logfmt)
|
[](https://goreportcard.com/report/go-logfmt/logfmt)
|
||||||
[](https://github.com/go-logfmt/logfmt/actions/workflows/test.yml)
|
[](https://github.com/go-logfmt/logfmt/actions/workflows/test.yml)
|
||||||
[](https://coveralls.io/github/go-logfmt/logfmt?branch=main)
|
[](https://coveralls.io/github/go-logfmt/logfmt?branch=main)
|
||||||
|
|
||||||
Package logfmt implements utilities to marshal and unmarshal data in the [logfmt
|
Package logfmt implements utilities to marshal and unmarshal data in the [logfmt
|
||||||
format][fmt]. It provides an API similar to [encoding/json][json] and
|
format][fmt]. It provides an API similar to [encoding/json][json] and
|
||||||
[encoding/xml][xml].
|
[encoding/xml][xml].
|
||||||
|
|
||||||
[fmt]: https://brandur.org/logfmt
|
[fmt]: https://brandur.org/logfmt
|
||||||
[json]: https://pkg.go.dev/encoding/json
|
[json]: https://pkg.go.dev/encoding/json
|
||||||
[xml]: https://pkg.go.dev/encoding/xml
|
[xml]: https://pkg.go.dev/encoding/xml
|
||||||
|
|
||||||
The logfmt format was first documented by Brandur Leach in [this
|
The logfmt format was first documented by Brandur Leach in [this
|
||||||
article][origin]. The format has not been formally standardized. The most
|
article][origin]. The format has not been formally standardized. The most
|
||||||
authoritative public specification to date has been the documentation of a Go
|
authoritative public specification to date has been the documentation of a Go
|
||||||
Language [package][parser] written by Blake Mizerany and Keith Rarick.
|
Language [package][parser] written by Blake Mizerany and Keith Rarick.
|
||||||
|
|
||||||
[origin]: https://brandur.org/logfmt
|
[origin]: https://brandur.org/logfmt
|
||||||
[parser]: https://pkg.go.dev/github.com/kr/logfmt
|
[parser]: https://pkg.go.dev/github.com/kr/logfmt
|
||||||
|
|
||||||
## Goals
|
## Goals
|
||||||
|
|
||||||
This project attempts to conform as closely as possible to the prior art, while
|
This project attempts to conform as closely as possible to the prior art, while
|
||||||
also removing ambiguity where necessary to provide well behaved encoder and
|
also removing ambiguity where necessary to provide well behaved encoder and
|
||||||
decoder implementations.
|
decoder implementations.
|
||||||
|
|
||||||
## Non-goals
|
## Non-goals
|
||||||
|
|
||||||
This project does not attempt to formally standardize the logfmt format. In the
|
This project does not attempt to formally standardize the logfmt format. In the
|
||||||
event that logfmt is standardized this project would take conforming to the
|
event that logfmt is standardized this project would take conforming to the
|
||||||
standard as a goal.
|
standard as a goal.
|
||||||
|
|
||||||
## Versioning
|
## Versioning
|
||||||
|
|
||||||
This project publishes releases according to the Go language guidelines for
|
This project publishes releases according to the Go language guidelines for
|
||||||
[developing and publishing modules][pub].
|
[developing and publishing modules][pub].
|
||||||
|
|
||||||
[pub]: https://go.dev/doc/modules/developing
|
[pub]: https://go.dev/doc/modules/developing
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user