mirror of
https://github.com/kubernetes-sigs/descheduler.git
synced 2026-08-30 12:47:17 +00:00
Compare commits
11
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2908b43089 | ||
|
|
9ba1aa1c43 | ||
|
|
8dd18a45a0 | ||
|
|
4a0d41a96a | ||
|
|
a8c092f8e1 | ||
|
|
d4ed42c71f | ||
|
|
0e8dd36ac3 | ||
|
|
6b3276a0f7 | ||
|
|
550923c2c3 | ||
|
|
bb35cf9614 | ||
|
|
658b6cd30a |
@@ -1 +0,0 @@
|
||||
vendor/**
|
||||
@@ -20,25 +20,25 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Helm
|
||||
uses: azure/setup-helm@fe7b79cd5ee1e45176fcad797de68ecaf3ca4814 # v4.2.0
|
||||
uses: azure/setup-helm@v4.2.0
|
||||
with:
|
||||
version: v3.15.1
|
||||
|
||||
- uses: actions/setup-python@39cd14951b08e74b54015e9e001cdefcf80e669f # v5.1.1
|
||||
- uses: actions/setup-python@v5.1.1
|
||||
with:
|
||||
python-version: 3.12
|
||||
|
||||
- uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version-file: 'go.mod'
|
||||
|
||||
- name: Set up chart-testing
|
||||
uses: helm/chart-testing-action@6ec842c01de15ebb84c8627d2744a0c2f2755c9f # v2.8.0
|
||||
uses: helm/chart-testing-action@v2.8.0
|
||||
with:
|
||||
version: v3.11.0
|
||||
|
||||
|
||||
@@ -7,35 +7,23 @@ jobs:
|
||||
deploy:
|
||||
strategy:
|
||||
matrix:
|
||||
k8s-version: ["v1.36.1"]
|
||||
build-kind-node-image: [true]
|
||||
kind-node-image: ["localhost/kindest/node:v1.36.1"]
|
||||
descheduler-version: ["v0.36.0"]
|
||||
k8s-version: ["v1.35.1"]
|
||||
descheduler-version: ["v0.35.0"]
|
||||
descheduler-api: ["v1alpha2"]
|
||||
manifest: ["deployment"]
|
||||
kind-version: ["v0.31.0"] # keep in sync with test/run-e2e-tests.sh
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Repo
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # git ls-remote https://github.com/actions/checkout.git refs/tags/v6.0.2
|
||||
- name: Install kind
|
||||
uses: helm/kind-action@ef37e7f390d99f746eb8b610417061a60e82a6cc # git ls-remote https://github.com/helm/kind-action.git refs/tags/v1.14.0
|
||||
with:
|
||||
version: ${{ matrix.kind-version }}
|
||||
kubectl_version: ${{ matrix.k8s-version }}
|
||||
install_only: true
|
||||
- name: Build kind node image
|
||||
if: ${{ matrix.build-kind-node-image == true }}
|
||||
run: |
|
||||
kind build node-image ${{ matrix.k8s-version }} --image ${{ matrix.kind-node-image }}
|
||||
uses: actions/checkout@v4
|
||||
- name: Create kind cluster
|
||||
uses: helm/kind-action@ef37e7f390d99f746eb8b610417061a60e82a6cc # git ls-remote https://github.com/helm/kind-action.git refs/tags/v1.14.0
|
||||
uses: helm/kind-action@v1.12.0
|
||||
with:
|
||||
node_image: ${{ matrix.kind-node-image }}
|
||||
node_image: kindest/node:${{ matrix.k8s-version }}
|
||||
kubectl_version: ${{ matrix.k8s-version }}
|
||||
config: test/kind-config.yaml
|
||||
version: ${{ matrix.kind-version }}
|
||||
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # git ls-remote https://github.com/actions/setup-go.git refs/tags/v6.4.0
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
cache: true
|
||||
|
||||
@@ -13,7 +13,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
@@ -23,12 +23,12 @@ jobs:
|
||||
git config user.email "$GITHUB_ACTOR@users.noreply.github.com"
|
||||
|
||||
- name: Install Helm
|
||||
uses: azure/setup-helm@fe7b79cd5ee1e45176fcad797de68ecaf3ca4814 # v4.2.0
|
||||
uses: azure/setup-helm@v4.2.0
|
||||
with:
|
||||
version: v3.15.1
|
||||
|
||||
- name: Run chart-releaser
|
||||
uses: helm/chart-releaser-action@a917fd15b20e8b64b94d9158ad54cd6345335584 # v1.6.0
|
||||
uses: helm/chart-releaser-action@v1.6.0
|
||||
env:
|
||||
CR_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
|
||||
CR_RELEASE_NAME_TEMPLATE: "descheduler-helm-chart-{{ .Version }}"
|
||||
|
||||
@@ -19,7 +19,7 @@ jobs:
|
||||
security-events: write
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
@@ -29,7 +29,7 @@ jobs:
|
||||
IMAGE_TAG=${HELM_IMAGE_TAG:-security-test}
|
||||
VERSION=security-test make image
|
||||
- name: Run Trivy vulnerability scanner
|
||||
uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1 # v0.35.0
|
||||
uses: aquasecurity/trivy-action@master
|
||||
with:
|
||||
image-ref: 'descheduler:security-test'
|
||||
format: 'sarif'
|
||||
@@ -38,6 +38,6 @@ jobs:
|
||||
output: 'trivy-results.sarif'
|
||||
|
||||
- name: Upload Trivy scan results to GitHub Security tab
|
||||
uses: github/codeql-action/upload-sarif@7c1e4cf0b20d7c1872b26569c00ba908797a59bf # v4
|
||||
uses: github/codeql-action/upload-sarif@v4
|
||||
with:
|
||||
sarif_file: 'trivy-results.sarif'
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
FROM golang:1.26.0
|
||||
FROM golang:1.25.1
|
||||
|
||||
WORKDIR /go/src/sigs.k8s.io/descheduler
|
||||
COPY . .
|
||||
|
||||
@@ -29,7 +29,7 @@ LDFLAGS=-ldflags "-X ${LDFLAG_LOCATION}.version=${VERSION} -X ${LDFLAG_LOCATION}
|
||||
GOLANGCI_VERSION := v2.8.0
|
||||
HAS_GOLANGCI := $(shell ls _output/bin/golangci-lint 2> /dev/null)
|
||||
|
||||
GOFUMPT_VERSION := v0.10.0
|
||||
GOFUMPT_VERSION := v0.7.0
|
||||
HAS_GOFUMPT := $(shell command -v gofumpt 2> /dev/null)
|
||||
|
||||
GO_VERSION := $(shell (command -v jq > /dev/null && (go mod edit -json | jq -r .Go)) || (sed -En 's/^go (.*)$$/\1/p' go.mod))
|
||||
@@ -146,7 +146,7 @@ verify-gen:
|
||||
|
||||
lint:
|
||||
ifndef HAS_GOLANGCI
|
||||
GOBIN=$(CURRENT_DIR)/_output/bin go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@${GOLANGCI_VERSION}
|
||||
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b ./_output/bin ${GOLANGCI_VERSION}
|
||||
endif
|
||||
./_output/bin/golangci-lint run -v
|
||||
./_output/bin/golangci-lint fmt -v
|
||||
|
||||
@@ -33,12 +33,11 @@ but relies on the default scheduler for that.
|
||||
## ⚠️ Documentation Versions by Release
|
||||
|
||||
If you are using a published release of Descheduler (such as
|
||||
`registry.k8s.io/descheduler/descheduler:v0.36.0`), follow the documentation in
|
||||
`registry.k8s.io/descheduler/descheduler:v0.35.0`), follow the documentation in
|
||||
that version's release branch, as listed below:
|
||||
|
||||
|Descheduler Version|Docs link|
|
||||
|---|---|
|
||||
|v0.36.x|[`release-1.36`](https://github.com/kubernetes-sigs/descheduler/blob/release-1.36/README.md)|
|
||||
|v0.35.x|[`release-1.35`](https://github.com/kubernetes-sigs/descheduler/blob/release-1.35/README.md)|
|
||||
|v0.34.x|[`release-1.34`](https://github.com/kubernetes-sigs/descheduler/blob/release-1.34/README.md)|
|
||||
|v0.33.x|[`release-1.33`](https://github.com/kubernetes-sigs/descheduler/blob/release-1.33/README.md)|
|
||||
@@ -1160,7 +1159,6 @@ packages that it is compiled with.
|
||||
|
||||
| Descheduler | Supported Kubernetes Version |
|
||||
|-------------|------------------------------|
|
||||
| v0.36 | v1.36 |
|
||||
| v0.35 | v1.35 |
|
||||
| v0.34 | v1.34 |
|
||||
| v0.33 | v1.33 |
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
apiVersion: v1
|
||||
name: descheduler
|
||||
version: 0.36.0
|
||||
appVersion: 0.36.0
|
||||
version: 0.35.0
|
||||
appVersion: 0.35.0
|
||||
description: Descheduler for Kubernetes is used to rebalance clusters by evicting pods that can potentially be scheduled on better nodes. In the current implementation, descheduler does not schedule replacement of evicted pods but relies on the default scheduler for that.
|
||||
keywords:
|
||||
- kubernetes
|
||||
|
||||
@@ -79,7 +79,6 @@ The following table lists the configurable parameters of the _descheduler_ chart
|
||||
| `nodeSelector` | Node selectors to run the descheduler cronjob/deployment on specific nodes | `nil` |
|
||||
| `service.enabled` | If `true`, create a service for deployment | `false` |
|
||||
| `serviceMonitor.enabled` | If `true`, create a ServiceMonitor for deployment | `false` |
|
||||
| `serviceMonitor.apiVersion` | API version used by the ServiceMonitor resource | `monitoring.coreos.com/v1` |
|
||||
| `serviceMonitor.namespace` | The namespace where Prometheus expects to find service monitors | `nil` |
|
||||
| `serviceMonitor.additionalLabels` | Add custom labels to the ServiceMonitor resource | `{}` |
|
||||
| `serviceMonitor.interval` | The scrape interval. If not set, the Prometheus default scrape interval is used | `nil` |
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{{- if eq .Values.kind "Deployment" }}
|
||||
{{- if eq .Values.serviceMonitor.enabled true }}
|
||||
apiVersion: {{ .Values.serviceMonitor.apiVersion | default "monitoring.coreos.com/v1" }}
|
||||
apiVersion: monitoring.coreos.com/v1
|
||||
kind: ServiceMonitor
|
||||
metadata:
|
||||
name: {{ template "descheduler.fullname" . }}-servicemonitor
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
suite: Test ServiceMonitor
|
||||
|
||||
templates:
|
||||
- "*.yaml"
|
||||
|
||||
release:
|
||||
name: descheduler
|
||||
|
||||
set:
|
||||
kind: Deployment
|
||||
serviceMonitor:
|
||||
enabled: true
|
||||
|
||||
tests:
|
||||
- it: uses default ServiceMonitor apiVersion
|
||||
template: templates/servicemonitor.yaml
|
||||
asserts:
|
||||
- equal:
|
||||
path: apiVersion
|
||||
value: monitoring.coreos.com/v1
|
||||
|
||||
- it: supports overriding ServiceMonitor apiVersion
|
||||
set:
|
||||
serviceMonitor:
|
||||
enabled: true
|
||||
apiVersion: azmonitoring.coreos.com/v1
|
||||
template: templates/servicemonitor.yaml
|
||||
asserts:
|
||||
- equal:
|
||||
path: apiVersion
|
||||
value: azmonitoring.coreos.com/v1
|
||||
@@ -255,7 +255,6 @@ service:
|
||||
|
||||
serviceMonitor:
|
||||
enabled: false
|
||||
apiVersion: "monitoring.coreos.com/v1"
|
||||
# The namespace where Prometheus expects to find service monitors.
|
||||
# namespace: ""
|
||||
# Add custom labels to the ServiceMonitor resource
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ timeout: 3600s
|
||||
options:
|
||||
substitution_option: ALLOW_LOOSE
|
||||
steps:
|
||||
- name: 'gcr.io/k8s-staging-test-infra/gcb-docker-gcloud@sha256:ff388e0dc16351e96f8464e2e185b74a7578a5ccb7a112cf3393468e59e6e2d2' # v20260205-38cfa9523f
|
||||
- name: 'gcr.io/k8s-staging-test-infra/gcb-docker-gcloud:v20211118-2f2d816b90'
|
||||
entrypoint: make
|
||||
env:
|
||||
- DOCKER_CLI_EXPERIMENTAL=enabled
|
||||
|
||||
@@ -57,7 +57,6 @@ descheduler [flags]
|
||||
--tls-cipher-suites strings Comma-separated list of cipher suites for the server. If omitted, the default Go cipher suites will be used.
|
||||
Preferred values: TLS_AES_128_GCM_SHA256, TLS_AES_256_GCM_SHA384, TLS_CHACHA20_POLY1305_SHA256, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256.
|
||||
Insecure values: TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, TLS_ECDHE_RSA_WITH_RC4_128_SHA, TLS_RSA_WITH_3DES_EDE_CBC_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_128_CBC_SHA256, TLS_RSA_WITH_AES_128_GCM_SHA256, TLS_RSA_WITH_AES_256_CBC_SHA, TLS_RSA_WITH_AES_256_GCM_SHA384, TLS_RSA_WITH_RC4_128_SHA.
|
||||
--tls-curve-preferences int32Slice Comma-separated list of numeric Go crypto/tls CurveID values, as the allowed key exchange mechanisms for the server. The supported values depend on the Go version used. See https://pkg.go.dev/crypto/tls#CurveID for values supported for each Go version. The order of the list is ignored, and key exchange mechanisms are chosen by Go from this list using an internal preference order. If omitted, the default Go curves will be used. (default [])
|
||||
--tls-min-version string Minimum TLS version supported. Possible values: VersionTLS10, VersionTLS11, VersionTLS12, VersionTLS13
|
||||
--tls-private-key-file string File containing the default x509 private key matching --tls-cert-file.
|
||||
--tls-sni-cert-key namedCertKey A pair of x509 certificate and private key file paths, optionally suffixed with a list of domain patterns which are fully qualified domain names, possibly with prefixed wildcard segments. The domain patterns also allow IP addresses, but IPs should only be used if the apiserver has visibility to the IP address requested by a client. If no domain patterns are provided, the names of the certificate are extracted. Non-wildcard matches trump over wildcard matches, explicit domain patterns trump over extracted names. For multiple key/certificate pairs, use the --tls-sni-cert-key multiple times. Examples: "example.crt,example.key" or "foo.crt,foo.key:*.foo.com,foo.com". (default [])
|
||||
|
||||
@@ -4,7 +4,6 @@ Starting with descheduler release v0.10.0 container images are available in the
|
||||
|
||||
Descheduler Version | Container Image | Architectures |
|
||||
------------------- |-------------------------------------------------|-------------------------|
|
||||
v0.36.0 | registry.k8s.io/descheduler/descheduler:v0.36.0 | AMD64<br>ARM64<br>ARMv7 |
|
||||
v0.35.0 | registry.k8s.io/descheduler/descheduler:v0.35.0 | AMD64<br>ARM64<br>ARMv7 |
|
||||
v0.34.0 | registry.k8s.io/descheduler/descheduler:v0.34.0 | AMD64<br>ARM64<br>ARMv7 |
|
||||
v0.33.0 | registry.k8s.io/descheduler/descheduler:v0.33.0 | AMD64<br>ARM64<br>ARMv7 |
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
module sigs.k8s.io/descheduler
|
||||
|
||||
go 1.26.0
|
||||
go 1.25.0
|
||||
|
||||
godebug default=go1.26
|
||||
toolchain go1.25.1
|
||||
|
||||
godebug default=go1.25
|
||||
|
||||
require (
|
||||
github.com/client9/misspell v0.3.4
|
||||
@@ -11,25 +13,25 @@ require (
|
||||
github.com/prometheus/common v0.67.5
|
||||
github.com/spf13/cobra v1.10.2
|
||||
github.com/spf13/pflag v1.0.10
|
||||
go.opentelemetry.io/otel v1.43.0
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.43.0
|
||||
go.opentelemetry.io/otel/sdk v1.43.0
|
||||
go.opentelemetry.io/otel/trace v1.43.0
|
||||
golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93
|
||||
google.golang.org/grpc v1.81.1
|
||||
k8s.io/api v0.36.1
|
||||
k8s.io/apimachinery v0.36.1
|
||||
k8s.io/apiserver v0.36.1
|
||||
k8s.io/client-go v0.36.1
|
||||
k8s.io/code-generator v0.36.1
|
||||
k8s.io/component-base v0.36.1
|
||||
k8s.io/component-helpers v0.36.1
|
||||
k8s.io/klog/v2 v2.140.0
|
||||
k8s.io/metrics v0.36.1
|
||||
k8s.io/utils v0.0.0-20260507154919-ff6756f316d2
|
||||
kubevirt.io/api v1.8.2
|
||||
kubevirt.io/client-go v1.8.2
|
||||
go.opentelemetry.io/otel v1.41.0
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.41.0
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.41.0
|
||||
go.opentelemetry.io/otel/sdk v1.41.0
|
||||
go.opentelemetry.io/otel/trace v1.41.0
|
||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56
|
||||
google.golang.org/grpc v1.79.1
|
||||
k8s.io/api v0.35.1
|
||||
k8s.io/apimachinery v0.35.1
|
||||
k8s.io/apiserver v0.35.1
|
||||
k8s.io/client-go v0.35.1
|
||||
k8s.io/code-generator v0.35.1
|
||||
k8s.io/component-base v0.35.1
|
||||
k8s.io/component-helpers v0.35.1
|
||||
k8s.io/klog/v2 v2.130.1
|
||||
k8s.io/metrics v0.35.1
|
||||
k8s.io/utils v0.0.0-20260108192941-914a6e750570
|
||||
kubevirt.io/api v1.3.0
|
||||
kubevirt.io/client-go v1.3.0
|
||||
sigs.k8s.io/mdtoc v1.4.0
|
||||
sigs.k8s.io/yaml v1.6.0
|
||||
)
|
||||
@@ -45,13 +47,14 @@ require (
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be // indirect
|
||||
github.com/coreos/go-semver v0.3.1 // indirect
|
||||
github.com/coreos/go-systemd/v22 v22.7.0 // indirect
|
||||
github.com/coreos/go-systemd/v22 v22.5.0 // 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/emicklei/go-restful/v3 v3.13.0 // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.12.2 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/fsnotify/fsnotify v1.9.0 // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.9.0 // indirect
|
||||
github.com/go-kit/kit v0.13.0 // indirect
|
||||
github.com/go-kit/log v0.2.1 // indirect
|
||||
github.com/go-logfmt/logfmt v0.6.0 // indirect
|
||||
github.com/go-logr/logr v1.4.3 // indirect
|
||||
@@ -59,85 +62,78 @@ require (
|
||||
github.com/go-logr/zapr v1.3.0 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.21.0 // indirect
|
||||
github.com/go-openapi/jsonreference v0.20.2 // indirect
|
||||
github.com/go-openapi/swag v0.25.4 // indirect
|
||||
github.com/go-openapi/swag/cmdutils v0.25.4 // indirect
|
||||
github.com/go-openapi/swag/conv v0.25.4 // indirect
|
||||
github.com/go-openapi/swag/fileutils v0.25.4 // indirect
|
||||
github.com/go-openapi/swag/jsonname v0.25.4 // indirect
|
||||
github.com/go-openapi/swag/jsonutils v0.25.4 // indirect
|
||||
github.com/go-openapi/swag/loading v0.25.4 // indirect
|
||||
github.com/go-openapi/swag/mangling v0.25.4 // indirect
|
||||
github.com/go-openapi/swag/netutils v0.25.4 // indirect
|
||||
github.com/go-openapi/swag/stringutils v0.25.4 // indirect
|
||||
github.com/go-openapi/swag/typeutils v0.25.4 // indirect
|
||||
github.com/go-openapi/swag/yamlutils v0.25.4 // indirect
|
||||
github.com/go-openapi/swag v0.23.0 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang-jwt/jwt/v5 v5.3.0 // indirect
|
||||
github.com/golang/glog v1.2.5 // indirect
|
||||
github.com/golang/protobuf v1.5.4 // indirect
|
||||
github.com/gomarkdown/markdown v0.0.0-20260217112301-37c66b85d6ab // indirect
|
||||
github.com/google/btree v1.1.3 // indirect
|
||||
github.com/google/cel-go v0.26.0 // indirect
|
||||
github.com/google/gnostic-models v0.7.0 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect
|
||||
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0 // indirect
|
||||
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.3 // indirect
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/jpillora/backoff v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/kylelemons/godebug v1.1.0 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // 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/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect
|
||||
github.com/openshift/api v0.0.0-20230503133300-8bbcb7ca7183 // indirect
|
||||
github.com/openshift/custom-resource-status v1.1.2 // 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.19.2 // indirect
|
||||
github.com/prometheus/procfs v0.16.1 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/stoewer/go-strcase v1.3.0 // indirect
|
||||
github.com/x448/float16 v0.8.4 // indirect
|
||||
go.etcd.io/etcd/api/v3 v3.6.8 // indirect
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.6.8 // indirect
|
||||
go.etcd.io/etcd/client/v3 v3.6.8 // indirect
|
||||
go.etcd.io/etcd/api/v3 v3.6.5 // indirect
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.6.5 // indirect
|
||||
go.etcd.io/etcd/client/v3 v3.6.5 // indirect
|
||||
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.65.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.65.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.43.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v1.10.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.66.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.66.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.41.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v1.9.0 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
go.uber.org/zap v1.27.1 // indirect
|
||||
go.uber.org/zap v1.27.0 // indirect
|
||||
go.yaml.in/yaml/v2 v2.4.3 // indirect
|
||||
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
||||
golang.org/x/crypto v0.49.0 // indirect
|
||||
golang.org/x/mod v0.33.0 // indirect
|
||||
golang.org/x/net v0.52.0 // indirect
|
||||
golang.org/x/oauth2 v0.36.0 // indirect
|
||||
golang.org/x/sync v0.20.0 // indirect
|
||||
golang.org/x/sys v0.42.0 // indirect
|
||||
golang.org/x/term v0.41.0 // indirect
|
||||
golang.org/x/text v0.35.0 // indirect
|
||||
golang.org/x/time v0.14.0 // indirect
|
||||
golang.org/x/tools v0.42.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20260401024825-9d38bb4040a9 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9 // indirect
|
||||
google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af // indirect
|
||||
golang.org/x/crypto v0.48.0 // indirect
|
||||
golang.org/x/mod v0.32.0 // indirect
|
||||
golang.org/x/net v0.50.0 // indirect
|
||||
golang.org/x/oauth2 v0.35.0 // indirect
|
||||
golang.org/x/sync v0.19.0 // indirect
|
||||
golang.org/x/sys v0.41.0 // indirect
|
||||
golang.org/x/term v0.40.0 // indirect
|
||||
golang.org/x/text v0.34.0 // indirect
|
||||
golang.org/x/time v0.9.0 // indirect
|
||||
golang.org/x/tools v0.41.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20260209200024-4cfbd4190f57 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57 // indirect
|
||||
google.golang.org/protobuf v1.36.11 // indirect
|
||||
gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
|
||||
k8s.io/apiextensions-apiserver v0.34.3 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
k8s.io/apiextensions-apiserver v0.30.0 // indirect
|
||||
k8s.io/gengo/v2 v2.0.0-20250922181213-ec3ebc5fd46b // indirect
|
||||
k8s.io/kms v0.36.1 // indirect
|
||||
k8s.io/kube-openapi v0.31.0 // indirect
|
||||
k8s.io/streaming v0.36.1 // indirect
|
||||
kubevirt.io/containerized-data-importer-api v1.64.0 // indirect
|
||||
kubevirt.io/controller-lifecycle-operator-sdk/api v0.2.4 // indirect
|
||||
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.34.0 // indirect
|
||||
k8s.io/kms v0.35.1 // indirect
|
||||
k8s.io/kube-openapi v0.30.0 // indirect
|
||||
kubevirt.io/containerized-data-importer-api v1.57.0-alpha1 // 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/json v0.0.0-20250730193827-2d320260d730 // indirect
|
||||
sigs.k8s.io/randfill v1.0.0 // indirect
|
||||
sigs.k8s.io/release-utils v0.8.3 // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v6 v6.3.2 // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v6 v6.3.0 // indirect
|
||||
)
|
||||
|
||||
replace k8s.io/kube-openapi => k8s.io/kube-openapi v0.0.0-20260512234627-ef417d054102
|
||||
replace k8s.io/kube-openapi => k8s.io/kube-openapi v0.0.0-20260127142750-a19766b6e2d4
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
cel.dev/expr v0.24.0 h1:56OvJKSH3hDGL0ml5uSxZmz3/3Pq4tJ+fb1unVLAFcY=
|
||||
cel.dev/expr v0.24.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw=
|
||||
cel.dev/expr v0.25.1 h1:1KrZg61W6TWSxuNZ37Xy49ps13NUovb66QLprthtwi4=
|
||||
cel.dev/expr v0.25.1/go.mod h1:hrXvqGP6G6gyx8UAHSHJ5RGk//1Oj5nXQ2NI02Nrsg4=
|
||||
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/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0=
|
||||
github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
|
||||
github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I=
|
||||
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=
|
||||
@@ -18,17 +22,23 @@ github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F9
|
||||
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/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/chromedp/cdproto v0.0.0-20230802225258-3cf4e6d46a89/go.mod h1:GKljq0VrfU4D5yc+2qA6OVr8pmO/MBbPEWqWQ/oqGEs=
|
||||
github.com/chromedp/chromedp v0.9.2/go.mod h1:LkSXJKONWTCHAfQasKFUZI+mxqS4tZqhmtGzzhLsnLs=
|
||||
github.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moAV0xufSww=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8=
|
||||
github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be h1:J5BL2kskAlV9ckgEsNQXscjIaLiOYiZ75d4e94E6dcQ=
|
||||
github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be/go.mod h1:mk5IQ+Y0ZeO87b858TlA645sVcEcbiX6YqP98kt+7+w=
|
||||
github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4=
|
||||
github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec=
|
||||
github.com/coreos/go-systemd/v22 v22.7.0 h1:LAEzFkke61DFROc7zNLX/WA2i5J8gYqe0rSj9KI28KA=
|
||||
github.com/coreos/go-systemd/v22 v22.7.0/go.mod h1:xNUYtjHu2EDXbsxz1i41wouACIwT7Ybq9o0BQhMwD0w=
|
||||
github.com/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/cpuguy83/go-md2man/v2 v2.0.6 h1:XJtiaUW6dEEqVuZiMTn1ldk455QWwEIsMIJlo5vtkx0=
|
||||
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=
|
||||
@@ -42,8 +52,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/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/v3 v3.13.0 h1:C4Bl2xDndpU6nJ4bc1jXd+uTmYPVUwkD6bFY/oTyCes=
|
||||
github.com/emicklei/go-restful/v3 v3.13.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/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=
|
||||
@@ -55,6 +66,8 @@ github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S
|
||||
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
||||
github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM=
|
||||
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/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/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
|
||||
github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4=
|
||||
@@ -63,6 +76,8 @@ github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7
|
||||
github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
|
||||
github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||
@@ -77,52 +92,31 @@ github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1
|
||||
github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
|
||||
github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg=
|
||||
github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns=
|
||||
github.com/go-openapi/jsonreference v0.20.1/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k=
|
||||
github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE=
|
||||
github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k=
|
||||
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||
github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
|
||||
github.com/go-openapi/swag v0.21.1/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
|
||||
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
|
||||
github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
|
||||
github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
|
||||
github.com/go-openapi/swag v0.25.4 h1:OyUPUFYDPDBMkqyxOTkqDYFnrhuhi9NR6QVUvIochMU=
|
||||
github.com/go-openapi/swag v0.25.4/go.mod h1:zNfJ9WZABGHCFg2RnY0S4IOkAcVTzJ6z2Bi+Q4i6qFQ=
|
||||
github.com/go-openapi/swag/cmdutils v0.25.4 h1:8rYhB5n6WawR192/BfUu2iVlxqVR9aRgGJP6WaBoW+4=
|
||||
github.com/go-openapi/swag/cmdutils v0.25.4/go.mod h1:pdae/AFo6WxLl5L0rq87eRzVPm/XRHM3MoYgRMvG4A0=
|
||||
github.com/go-openapi/swag/conv v0.25.4 h1:/Dd7p0LZXczgUcC/Ikm1+YqVzkEeCc9LnOWjfkpkfe4=
|
||||
github.com/go-openapi/swag/conv v0.25.4/go.mod h1:3LXfie/lwoAv0NHoEuY1hjoFAYkvlqI/Bn5EQDD3PPU=
|
||||
github.com/go-openapi/swag/fileutils v0.25.4 h1:2oI0XNW5y6UWZTC7vAxC8hmsK/tOkWXHJQH4lKjqw+Y=
|
||||
github.com/go-openapi/swag/fileutils v0.25.4/go.mod h1:cdOT/PKbwcysVQ9Tpr0q20lQKH7MGhOEb6EwmHOirUk=
|
||||
github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI=
|
||||
github.com/go-openapi/swag/jsonname v0.25.4/go.mod h1:GPVEk9CWVhNvWhZgrnvRA6utbAltopbKwDu8mXNUMag=
|
||||
github.com/go-openapi/swag/jsonutils v0.25.4 h1:VSchfbGhD4UTf4vCdR2F4TLBdLwHyUDTd1/q4i+jGZA=
|
||||
github.com/go-openapi/swag/jsonutils v0.25.4/go.mod h1:7OYGXpvVFPn4PpaSdPHJBtF0iGnbEaTk8AvBkoWnaAY=
|
||||
github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4 h1:IACsSvBhiNJwlDix7wq39SS2Fh7lUOCJRmx/4SN4sVo=
|
||||
github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4/go.mod h1:Mt0Ost9l3cUzVv4OEZG+WSeoHwjWLnarzMePNDAOBiM=
|
||||
github.com/go-openapi/swag/loading v0.25.4 h1:jN4MvLj0X6yhCDduRsxDDw1aHe+ZWoLjW+9ZQWIKn2s=
|
||||
github.com/go-openapi/swag/loading v0.25.4/go.mod h1:rpUM1ZiyEP9+mNLIQUdMiD7dCETXvkkC30z53i+ftTE=
|
||||
github.com/go-openapi/swag/mangling v0.25.4 h1:2b9kBJk9JvPgxr36V23FxJLdwBrpijI26Bx5JH4Hp48=
|
||||
github.com/go-openapi/swag/mangling v0.25.4/go.mod h1:6dxwu6QyORHpIIApsdZgb6wBk/DPU15MdyYj/ikn0Hg=
|
||||
github.com/go-openapi/swag/netutils v0.25.4 h1:Gqe6K71bGRb3ZQLusdI8p/y1KLgV4M/k+/HzVSqT8H0=
|
||||
github.com/go-openapi/swag/netutils v0.25.4/go.mod h1:m2W8dtdaoX7oj9rEttLyTeEFFEBvnAx9qHd5nJEBzYg=
|
||||
github.com/go-openapi/swag/stringutils v0.25.4 h1:O6dU1Rd8bej4HPA3/CLPciNBBDwZj9HiEpdVsb8B5A8=
|
||||
github.com/go-openapi/swag/stringutils v0.25.4/go.mod h1:GTsRvhJW5xM5gkgiFe0fV3PUlFm0dr8vki6/VSRaZK0=
|
||||
github.com/go-openapi/swag/typeutils v0.25.4 h1:1/fbZOUN472NTc39zpa+YGHn3jzHWhv42wAJSN91wRw=
|
||||
github.com/go-openapi/swag/typeutils v0.25.4/go.mod h1:Ou7g//Wx8tTLS9vG0UmzfCsjZjKhpjxayRKTHXf2pTE=
|
||||
github.com/go-openapi/swag/yamlutils v0.25.4 h1:6jdaeSItEUb7ioS9lFoCZ65Cne1/RZtPBZ9A56h92Sw=
|
||||
github.com/go-openapi/swag/yamlutils v0.25.4/go.mod h1:MNzq1ulQu+yd8Kl7wPOut/YHAAU/H6hL91fF+E2RFwc=
|
||||
github.com/go-openapi/testify/enable/yaml/v2 v2.0.2 h1:0+Y41Pz1NkbTHz8NngxTuAXxEodtNSI1WG1c/m5Akw4=
|
||||
github.com/go-openapi/testify/enable/yaml/v2 v2.0.2/go.mod h1:kme83333GCtJQHXQ8UKX3IBZu6z8T5Dvy5+CW3NLUUg=
|
||||
github.com/go-openapi/testify/v2 v2.0.2 h1:X999g3jeLcoY8qctY/c/Z8iBHTbwLz7R2WXd6Ub6wls=
|
||||
github.com/go-openapi/testify/v2 v2.0.2/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54=
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
|
||||
github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
|
||||
github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
|
||||
github.com/gobwas/ws v1.2.1/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY=
|
||||
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/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo=
|
||||
github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/glog v1.2.5 h1:DrW6hGnjIhtvhOIiAKT6Psh/Kd/ldepEa81DKeiRJ5I=
|
||||
github.com/golang/glog v1.2.5/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
@@ -135,6 +129,7 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/gomarkdown/markdown v0.0.0-20260217112301-37c66b85d6ab h1:VYNivV7P8IRHUam2swVUNkhIdp0LRRFKe4hXNnoZKTc=
|
||||
@@ -150,6 +145,7 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
@@ -157,8 +153,10 @@ github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX
|
||||
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/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
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-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-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J0b1vyeLSOYI8bm5wbJM/8yDe8=
|
||||
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
@@ -166,18 +164,25 @@ github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97Dwqy
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
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/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0 h1:QGLs/O40yoNK9vmy4rhUGBVyMf1lISBGtXRpsu/Qu/o=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0/go.mod h1:hM2alZsMUni80N33RBe6J0e423LB+odMj7d3EMP9l20=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.3 h1:B+8ClL/kCQkRiU82d9xajRPKYMrB7E0MbtzWVi1K4ns=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.3/go.mod h1:NbCUVmiS4foBGBHOYlCT25+YmGpJ32dZPi75pGEUpj4=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw=
|
||||
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/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.7 h1:X+2YciYSxvMQK0UZ7sg45ZVabVZBeBuvMkmuI2V3Fak=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.7/go.mod h1:lW34nIZuQ8UDPdkon5fmfp2l3+ZkQ2me/+oecHYLOII=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 h1:HWRh5R2+9EifMyIHV7ZV+MIZqgz+PMpZ14Jynv3O2Zs=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0/go.mod h1:JfhWUomR1baixubs02l85lZYYOm7LV6om4ceouMv45c=
|
||||
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-20240312041847-bd984b5ce465/go.mod h1:gx7rwoVhcfuVKG5uya9Hs3Sxj7EIvldVofAWIUtGouw=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/jonboulle/clockwork v0.5.0 h1:Hyh9A8u51kptdkR+cqRpT1EebBwTn1oK9YfGYbdFz6I=
|
||||
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/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||
github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA=
|
||||
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
|
||||
@@ -199,9 +204,11 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
||||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||
github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80/go.mod h1:imJHygn/1yfhB7XSJJKlFZKl/J+dCPAknuiaGOshXAs=
|
||||
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/mmarkdown/mmark v2.0.40+incompatible h1:vMeUeDzBK3H+/mU0oMVfMuhSXJlIA+DE/DMPQNAj5C4=
|
||||
github.com/mmarkdown/mmark v2.0.40+incompatible/go.mod h1:Uvmoz7tvsWpr7bMVxIpqZPyN3FbOtzDmnsJDFp7ltJs=
|
||||
@@ -227,16 +234,54 @@ github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9k
|
||||
github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
|
||||
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
|
||||
github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
|
||||
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.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
|
||||
github.com/onsi/ginkgo/v2 v2.1.4/go.mod h1:um6tUpWM/cxCK3/FK8BXqEiUMUwRgSM4JXG47RKZmLU=
|
||||
github.com/onsi/ginkgo/v2 v2.1.6/go.mod h1:MEH45j8TBi6u9BMogfbp0stKC5cdGjumZj5Y7AG4VIk=
|
||||
github.com/onsi/ginkgo/v2 v2.3.0/go.mod h1:Eew0uilEqZmIEZr8JrvYlvOM7Rr6xzTmMV8AyFNU9d0=
|
||||
github.com/onsi/ginkgo/v2 v2.4.0/go.mod h1:iHkDK1fKGcBoEHT5W7YBq4RFWaQulw+caOMkAt4OrFo=
|
||||
github.com/onsi/ginkgo/v2 v2.5.0/go.mod h1:Luc4sArBICYCS8THh8v3i3i5CuSZO+RaQRaJoeNwomw=
|
||||
github.com/onsi/ginkgo/v2 v2.7.0/go.mod h1:yjiuMwPokqY1XauOgju45q3sJt6VzQ/Fict1LFVcsAo=
|
||||
github.com/onsi/ginkgo/v2 v2.8.1/go.mod h1:N1/NbDngAFcSLdyZ+/aYTYGSlq9qMCS/cNKGJjy+csc=
|
||||
github.com/onsi/ginkgo/v2 v2.9.0/go.mod h1:4xkjoL/tZv4SMWeww56BU5kAt19mVB47gTWxmrTcxyk=
|
||||
github.com/onsi/ginkgo/v2 v2.9.1/go.mod h1:FEcmzVcCHl+4o9bQZVab+4dC9+j+91t2FHSzmGAPfuo=
|
||||
github.com/onsi/ginkgo/v2 v2.9.2/go.mod h1:WHcJJG2dIlcCqVfBAwUCrJxSPFb6v4azBwgxeMeDuts=
|
||||
github.com/onsi/ginkgo/v2 v2.9.5/go.mod h1:tvAoo1QUJwNEU2ITftXTpR7R1RbCzoZUOs3RonqW57k=
|
||||
github.com/onsi/ginkgo/v2 v2.9.7/go.mod h1:cxrmXWykAwTwhQsJOPfdIDiJ+l2RYq7U8hFU+M/1uw0=
|
||||
github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM=
|
||||
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.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.27.2 h1:LzwLj0b89qtIy6SSASkzlNvX6WktqurSHwkk2ipF/Ns=
|
||||
github.com/onsi/ginkgo/v2 v2.27.2/go.mod h1:ArE1D/XhNXBXCBkKOLkbsb2c81dQHCRcF5zwn/ykDRo=
|
||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
|
||||
github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs=
|
||||
github.com/onsi/gomega v1.35.1 h1:Cwbd75ZBPxFSuZ6T+rN/WCb/gOc6YgFBXLlZLhC7Ds4=
|
||||
github.com/onsi/gomega v1.35.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog=
|
||||
github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro=
|
||||
github.com/onsi/gomega v1.20.1/go.mod h1:DtrZpjmvpn2mPm4YWQa0/ALMDj9v4YxLgojwPeREyVo=
|
||||
github.com/onsi/gomega v1.21.1/go.mod h1:iYAIXgPSaDHak0LCMA+AWBpIKBr8WZicMxnE8luStNc=
|
||||
github.com/onsi/gomega v1.22.1/go.mod h1:x6n7VNe4hw0vkyYUM4mjIXx3JbLiPaBPNgB7PRQ1tuM=
|
||||
github.com/onsi/gomega v1.24.0/go.mod h1:Z/NWtiqwBrwUt4/2loMmHL63EDLnYHmVbuBpDr2vQAg=
|
||||
github.com/onsi/gomega v1.24.1/go.mod h1:3AOiACssS3/MajrniINInwbfOOtfZvplPzuRSmvt1jM=
|
||||
github.com/onsi/gomega v1.26.0/go.mod h1:r+zV744Re+DiYCIPRlYOTxn0YkOLcAnW8k1xXdMPGhM=
|
||||
github.com/onsi/gomega v1.27.1/go.mod h1:aHX5xOykVYzWOV4WqQy0sy8BQptgukenXpCXfadcIAw=
|
||||
github.com/onsi/gomega v1.27.3/go.mod h1:5vG284IBtfDAmDyrK+eGyZmUgUlmi+Wngqo557cZ6Gw=
|
||||
github.com/onsi/gomega v1.27.4/go.mod h1:riYq/GJKh8hhoM01HN6Vmuy93AarCXCBGpvFDK3q3fQ=
|
||||
github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg=
|
||||
github.com/onsi/gomega v1.27.7/go.mod h1:1p8OOlwo2iUUDsHnOrjE5UKYJ+e3W8eQ3qSlRahPmr4=
|
||||
github.com/onsi/gomega v1.27.8/go.mod h1:2J8vzI/s+2shY9XHRApDkdgPo1TKT7P2u6fXeJKFnNQ=
|
||||
github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M=
|
||||
github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ=
|
||||
github.com/onsi/gomega v1.33.0/go.mod h1:+925n5YtiFsLzzafLUHzVMBpvvRAzrydIBiSIxjX3wY=
|
||||
github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0=
|
||||
github.com/onsi/gomega v1.38.2 h1:eZCjf2xjZAqe+LeWvKb5weQ+NcPwX84kqJ0cZNxok2A=
|
||||
github.com/onsi/gomega v1.38.2/go.mod h1:W2MJcYxRGV63b418Ai34Ud0hEdTVXq9NW9+Sx6uXf3k=
|
||||
github.com/openshift/api v0.0.0-20230503133300-8bbcb7ca7183 h1:t/CahSnpqY46sQR01SoS+Jt0jtjgmhgE6lFmRnO4q70=
|
||||
github.com/openshift/api v0.0.0-20230503133300-8bbcb7ca7183/go.mod h1:4VWG+W22wrB4HfBL88P40DxLEpSOaiBVxUnfalfJo9k=
|
||||
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/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/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
@@ -249,9 +294,10 @@ github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNw
|
||||
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
|
||||
github.com/prometheus/common v0.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTUGI4=
|
||||
github.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw=
|
||||
github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws=
|
||||
github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw=
|
||||
github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg=
|
||||
github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is=
|
||||
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.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||
@@ -299,46 +345,63 @@ github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
go.etcd.io/bbolt v1.4.3 h1:dEadXpI6G79deX5prL3QRNP6JB8UxVkqo4UPnHaNXJo=
|
||||
go.etcd.io/bbolt v1.4.3/go.mod h1:tKQlpPaYCVFctUIgFKFnAlvbmB3tpy1vkTnDWohtc0E=
|
||||
go.etcd.io/etcd/api/v3 v3.6.8 h1:gqb1VN92TAI6G2FiBvWcqKtHiIjr4SU2GdXxTwyexbM=
|
||||
go.etcd.io/etcd/api/v3 v3.6.8/go.mod h1:qyQj1HZPUV3B5cbAL8scG62+fyz5dSxxu0w8pn28N6Q=
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.6.8 h1:Qs/5C0LNFiqXxYf2GU8MVjYUEXJ6sZaYOz0zEqQgy50=
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.6.8/go.mod h1:GsiTRUZE2318PggZkAo6sWb6l8JLVrnckTNfbG8PWtw=
|
||||
go.etcd.io/etcd/client/v3 v3.6.8 h1:B3G76t1UykqAOrbio7s/EPatixQDkQBevN8/mwiplrY=
|
||||
go.etcd.io/etcd/client/v3 v3.6.8/go.mod h1:MVG4BpSIuumPi+ELF7wYtySETmoTWBHVcDoHdVupwt8=
|
||||
go.etcd.io/etcd/pkg/v3 v3.6.8 h1:Xe+LIL974spy8b4nEx3H0KMr1ofq3r0kh6FbU3aw4es=
|
||||
go.etcd.io/etcd/pkg/v3 v3.6.8/go.mod h1:TRibVNe+FqJIe1abOAA1PsuQ4wqO87ZaOoprg09Tn8c=
|
||||
go.etcd.io/etcd/server/v3 v3.6.8 h1:U2strdSEy1U8qcSzRIdkYpvOPtBy/9i/IfaaCI9flZ4=
|
||||
go.etcd.io/etcd/server/v3 v3.6.8/go.mod h1:88dCtwUnSirkUoJbflQxxWXqtBSZa6lSG0Kuej+dois=
|
||||
go.etcd.io/etcd/api/v3 v3.6.5 h1:pMMc42276sgR1j1raO/Qv3QI9Af/AuyQUW6CBAWuntA=
|
||||
go.etcd.io/etcd/api/v3 v3.6.5/go.mod h1:ob0/oWA/UQQlT1BmaEkWQzI0sJ1M0Et0mMpaABxguOQ=
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.6.5 h1:Duz9fAzIZFhYWgRjp/FgNq2gO1jId9Yae/rLn3RrBP8=
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.6.5/go.mod h1:8Wx3eGRPiy0qOFMZT/hfvdos+DjEaPxdIDiCDUv/FQk=
|
||||
go.etcd.io/etcd/client/v3 v3.6.5 h1:yRwZNFBx/35VKHTcLDeO7XVLbCBFbPi+XV4OC3QJf2U=
|
||||
go.etcd.io/etcd/client/v3 v3.6.5/go.mod h1:ZqwG/7TAFZ0BJ0jXRPoJjKQJtbFo/9NIY8uoFFKcCyo=
|
||||
go.etcd.io/etcd/pkg/v3 v3.6.5 h1:byxWB4AqIKI4SBmquZUG1WGtvMfMaorXFoCcFbVeoxM=
|
||||
go.etcd.io/etcd/pkg/v3 v3.6.5/go.mod h1:uqrXrzmMIJDEy5j00bCqhVLzR5jEJIwDp5wTlLwPGOU=
|
||||
go.etcd.io/etcd/server/v3 v3.6.5 h1:4RbUb1Bd4y1WkBHmuF+cZII83JNQMuNXzyjwigQ06y0=
|
||||
go.etcd.io/etcd/server/v3 v3.6.5/go.mod h1:PLuhyVXz8WWRhzXDsl3A3zv/+aK9e4A9lpQkqawIaH0=
|
||||
go.etcd.io/raft/v3 v3.6.0 h1:5NtvbDVYpnfZWcIHgGRk9DyzkBIXOi8j+DDp1IcnUWQ=
|
||||
go.etcd.io/raft/v3 v3.6.0/go.mod h1:nLvLevg6+xrVtHUmVaTcTz603gQPHfh7kUAwV6YpfGo=
|
||||
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
|
||||
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.65.0 h1:XmiuHzgJt067+a6kwyAzkhXooYVv3/TOw9cM2VfJgUM=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.65.0/go.mod h1:KDgtbWKTQs4bM+VPUr6WlL9m/WXcmkCcBlIzqxPGzmI=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.65.0 h1:7iP2uCb7sGddAr30RRS6xjKy7AZ2JtTOPA3oolgVSw8=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.65.0/go.mod h1:c7hN3ddxs/z6q9xwvfLPk+UHlWRQyaeR1LdgfL/66l0=
|
||||
go.opentelemetry.io/otel v1.43.0 h1:mYIM03dnh5zfN7HautFE4ieIig9amkNANT+xcVxAj9I=
|
||||
go.opentelemetry.io/otel v1.43.0/go.mod h1:JuG+u74mvjvcm8vj8pI5XiHy1zDeoCS2LB1spIq7Ay0=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0 h1:88Y4s2C8oTui1LGM6bTWkw0ICGcOLCAI5l6zsD1j20k=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0/go.mod h1:Vl1/iaggsuRlrHf/hfPJPvVag77kKyvrLeD10kpMl+A=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.43.0 h1:RAE+JPfvEmvy+0LzyUA25/SGawPwIUbZ6u0Wug54sLc=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.43.0/go.mod h1:AGmbycVGEsRx9mXMZ75CsOyhSP6MFIcj/6dnG+vhVjk=
|
||||
go.opentelemetry.io/otel/metric v1.43.0 h1:d7638QeInOnuwOONPp4JAOGfbCEpYb+K6DVWvdxGzgM=
|
||||
go.opentelemetry.io/otel/metric v1.43.0/go.mod h1:RDnPtIxvqlgO8GRW18W6Z/4P462ldprJtfxHxyKd2PY=
|
||||
go.opentelemetry.io/otel/sdk v1.43.0 h1:pi5mE86i5rTeLXqoF/hhiBtUNcrAGHLKQdhg4h4V9Dg=
|
||||
go.opentelemetry.io/otel/sdk v1.43.0/go.mod h1:P+IkVU3iWukmiit/Yf9AWvpyRDlUeBaRg6Y+C58QHzg=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.43.0 h1:S88dyqXjJkuBNLeMcVPRFXpRw2fuwdvfCGLEo89fDkw=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.43.0/go.mod h1:C/RJtwSEJ5hzTiUz5pXF1kILHStzb9zFlIEe85bhj6A=
|
||||
go.opentelemetry.io/otel/trace v1.43.0 h1:BkNrHpup+4k4w+ZZ86CZoHHEkohws8AY+WTX09nk+3A=
|
||||
go.opentelemetry.io/otel/trace v1.43.0/go.mod h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLhe+8WVFxiFff0=
|
||||
go.opentelemetry.io/proto/otlp v1.10.0 h1:IQRWgT5srOCYfiWnpqUYz9CVmbO8bFmKcwYxpuCSL2g=
|
||||
go.opentelemetry.io/proto/otlp v1.10.0/go.mod h1:/CV4QoCR/S9yaPj8utp3lvQPoqMtxXdzn7ozvvozVqk=
|
||||
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.60.0/go.mod h1:rg+RlpR5dKwaS95IyyZqj5Wd4E13lk/msnTS0Xl9lJM=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.66.0 h1:w/o339tDd6Qtu3+ytwt+/jon2yjAs3Ot8Xq8pelfhSo=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.66.0/go.mod h1:pdhNtM9C4H5fRdrnwO7NjxzQWhKSSxCHk/KluVqDVC0=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.66.0 h1:PnV4kVnw0zOmwwFkAzCN5O07fw1YOIQor120zrh0AVo=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.66.0/go.mod h1:ofAwF4uinaf8SXdVzzbL4OsxJ3VfeEg3f/F6CeF49/Y=
|
||||
go.opentelemetry.io/otel v1.40.0 h1:oA5YeOcpRTXq6NN7frwmwFR0Cn3RhTVZvXsP4duvCms=
|
||||
go.opentelemetry.io/otel v1.40.0/go.mod h1:IMb+uXZUKkMXdPddhwAHm6UfOwJyh4ct1ybIlV14J0g=
|
||||
go.opentelemetry.io/otel v1.41.0 h1:YlEwVsGAlCvczDILpUXpIpPSL/VPugt7zHThEMLce1c=
|
||||
go.opentelemetry.io/otel v1.41.0/go.mod h1:Yt4UwgEKeT05QbLwbyHXEwhnjxNO6D8L5PQP51/46dE=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.36.0 h1:dNzwXjZKpMpE2JhmO+9HsPl42NIXFIFSUSSs0fiqra0=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.36.0/go.mod h1:90PoxvaEB5n6AOdZvi+yWJQoE95U8Dhhw2bSyRqnTD0=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.41.0 h1:ao6Oe+wSebTlQ1OEht7jlYTzQKE+pnx/iNywFvTbuuI=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.41.0/go.mod h1:u3T6vz0gh/NVzgDgiwkgLxpsSF6PaPmo2il0apGJbls=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.36.0 h1:JgtbA0xkWHnTmYk7YusopJFX6uleBmAuZ8n05NEh8nQ=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.36.0/go.mod h1:179AK5aar5R3eS9FucPy6rggvU0g52cvKId8pv4+v0c=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.41.0 h1:mq/Qcf28TWz719lE3/hMB4KkyDuLJIvgJnFGcd0kEUI=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.41.0/go.mod h1:yk5LXEYhsL2htyDNJbEq7fWzNEigeEdV5xBF/Y+kAv0=
|
||||
go.opentelemetry.io/otel/metric v1.40.0 h1:rcZe317KPftE2rstWIBitCdVp89A2HqjkxR3c11+p9g=
|
||||
go.opentelemetry.io/otel/metric v1.40.0/go.mod h1:ib/crwQH7N3r5kfiBZQbwrTge743UDc7DTFVZrrXnqc=
|
||||
go.opentelemetry.io/otel/metric v1.41.0 h1:rFnDcs4gRzBcsO9tS8LCpgR0dxg4aaxWlJxCno7JlTQ=
|
||||
go.opentelemetry.io/otel/metric v1.41.0/go.mod h1:xPvCwd9pU0VN8tPZYzDZV/BMj9CM9vs00GuBjeKhJps=
|
||||
go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=
|
||||
go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=
|
||||
go.opentelemetry.io/otel/sdk v1.41.0 h1:YPIEXKmiAwkGl3Gu1huk1aYWwtpRLeskpV+wPisxBp8=
|
||||
go.opentelemetry.io/otel/sdk v1.41.0/go.mod h1:ahFdU0G5y8IxglBf0QBJXgSe7agzjE4GiTJ6HT9ud90=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.41.0 h1:siZQIYBAUd1rlIWQT2uCxWJxcCO7q3TriaMlf08rXw8=
|
||||
go.opentelemetry.io/otel/trace v1.40.0 h1:WA4etStDttCSYuhwvEa8OP8I5EWu24lkOzp+ZYblVjw=
|
||||
go.opentelemetry.io/otel/trace v1.40.0/go.mod h1:zeAhriXecNGP/s2SEG3+Y8X9ujcJOTqQ5RgdEJcawiA=
|
||||
go.opentelemetry.io/otel/trace v1.41.0 h1:Vbk2co6bhj8L59ZJ6/xFTskY+tGAbOnCtQGVVa9TIN0=
|
||||
go.opentelemetry.io/otel/trace v1.41.0/go.mod h1:U1NU4ULCoxeDKc09yCWdWe+3QoyweJcISEVa1RBzOis=
|
||||
go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A=
|
||||
go.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4=
|
||||
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/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||
go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc=
|
||||
go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
||||
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
|
||||
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
||||
go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU=
|
||||
go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0=
|
||||
go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8=
|
||||
@@ -349,26 +412,28 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
|
||||
golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio=
|
||||
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
|
||||
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
||||
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
||||
golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
|
||||
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
|
||||
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.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
|
||||
golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw=
|
||||
golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U=
|
||||
golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY=
|
||||
golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc=
|
||||
golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8=
|
||||
golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0=
|
||||
golang.org/x/crypto v0.44.0/go.mod h1:013i+Nw79BMiQiMsOPcVCB5ZIJbYkerPrGnOa00tvmc=
|
||||
golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0=
|
||||
golang.org/x/crypto v0.47.0 h1:V6e3FRj+n4dbpw86FJ8Fv7XVOql7TEwpHapKoMJ/GO8=
|
||||
golang.org/x/crypto v0.47.0/go.mod h1:ff3Y9VzzKbwSSEzWqJsJVBnWmRwRSHt/6Op5n9bQc4A=
|
||||
golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts=
|
||||
golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos=
|
||||
golang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4=
|
||||
golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93 h1:fQsdNF2N+/YewlRZiricy4P1iimyPKZ/xwniHj8Q2a0=
|
||||
golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93/go.mod h1:EPRbTFwzwjXj9NpYyyrvenVh9Y+GFeEvMNh7Xuz7xgU=
|
||||
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/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
@@ -376,24 +441,25 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI=
|
||||
golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
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.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.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
|
||||
golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
|
||||
golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
|
||||
golang.org/x/mod v0.26.0/go.mod h1:/j6NAhSk8iQ723BGAUyoAcn7SlD7s15Dp9Nd/SfeaFQ=
|
||||
golang.org/x/mod v0.27.0/go.mod h1:rWI627Fq0DEoudcK+MBkNkCe0EetEaDSwJJkCcjpazc=
|
||||
golang.org/x/mod v0.28.0/go.mod h1:yfB/L0NOf/kmEbXjzCPOx1iK1fRutOydrCMsqRhEBxI=
|
||||
golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w=
|
||||
golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc=
|
||||
golang.org/x/mod v0.31.0 h1:HaW9xtz0+kOcWKwli0ZXy79Ix+UW/vOfmWI5QVd2tgI=
|
||||
golang.org/x/mod v0.31.0/go.mod h1:43JraMp9cGx1Rx3AqioxrbrhNsLl2l/iNAvuBkrezpg=
|
||||
golang.org/x/mod v0.32.0 h1:9F4d3PHLljb6x//jOyokMv3eX+YDeepZSEo3mFJy93c=
|
||||
golang.org/x/mod v0.32.0/go.mod h1:SgipZ/3h2Ci89DlEtEXWUk/HteuRin+HHhN+WbNhguU=
|
||||
golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8=
|
||||
golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@@ -412,30 +478,40 @@ golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qx
|
||||
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
|
||||
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
|
||||
golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
|
||||
golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
|
||||
golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
|
||||
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
||||
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
|
||||
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.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||
golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
|
||||
golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
|
||||
golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
|
||||
golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8=
|
||||
golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg=
|
||||
golang.org/x/net v0.44.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY=
|
||||
golang.org/x/net v0.45.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY=
|
||||
golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210=
|
||||
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
|
||||
golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY=
|
||||
golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o=
|
||||
golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8=
|
||||
golang.org/x/net v0.50.0 h1:ucWh9eiCGyDR3vtzso0WMQinm2Dnt8cFMuQa9K33J60=
|
||||
golang.org/x/net v0.50.0/go.mod h1:UgoSli3F/pBgdJBHCTc+tp3gmrU4XswgGRgtnwWTfyM=
|
||||
golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0=
|
||||
golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs=
|
||||
golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q=
|
||||
golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw=
|
||||
golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
|
||||
golang.org/x/oauth2 v0.35.0 h1:Mv2mzuHuZuY2+bkyWXIHMfhNdJAdwW3FuWeCPYN5GVQ=
|
||||
golang.org/x/oauth2 v0.35.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
|
||||
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-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -444,19 +520,16 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
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.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
|
||||
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
|
||||
golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
|
||||
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-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@@ -478,81 +551,92 @@ golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
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.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.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ=
|
||||
golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k=
|
||||
golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=
|
||||
golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||
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/telemetry v0.0.0-20250710130107-8d8967aff50b/go.mod h1:4ZwOYna0/zsOKwuR5X/m0QFOJpSZvAxFfkQT+Erd9D4=
|
||||
golang.org/x/telemetry v0.0.0-20250807160809-1a19826ec488/go.mod h1:fGb/2+tgXXjhjHsTNdVEEMZNWA0quBnfrO+AfoDSAKw=
|
||||
golang.org/x/telemetry v0.0.0-20250908211612-aef8a434d053/go.mod h1:+nZKN+XVh4LCiA9DV3ywrzN4gumyCnKjau3NGb9SGoE=
|
||||
golang.org/x/telemetry v0.0.0-20251008203120-078029d740a8/go.mod h1:Pi4ztBfryZoJEkyFTI5/Ocsu2jXyDr6iSdgJiYE/uwE=
|
||||
golang.org/x/telemetry v0.0.0-20251111182119-bc8e575c7b54/go.mod h1:hKdjCMrbv9skySur+Nek8Hd0uJ0GuxJIoIX2payrIdQ=
|
||||
golang.org/x/telemetry v0.0.0-20251203150158-8fff8a5912fc/go.mod h1:hKdjCMrbv9skySur+Nek8Hd0uJ0GuxJIoIX2payrIdQ=
|
||||
golang.org/x/telemetry v0.0.0-20260109210033-bd525da824e2/go.mod h1:b7fPSJ0pKZ3ccUh8gnTONJxhn3c/PS6tyzQvyqw4iA8=
|
||||
golang.org/x/telemetry v0.0.0-20260209163413-e7419c687ee4/go.mod h1:g5NllXBEermZrmR51cJDQxmJUHUOfRAaNyWBM+R+548=
|
||||
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.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
||||
golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=
|
||||
golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
|
||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||
golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o=
|
||||
golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU=
|
||||
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
|
||||
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
|
||||
golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
|
||||
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.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.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||
golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M=
|
||||
golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ=
|
||||
golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0=
|
||||
golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw=
|
||||
golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA=
|
||||
golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss=
|
||||
golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254=
|
||||
golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg=
|
||||
golang.org/x/term v0.39.0 h1:RclSuaJf32jOqZz74CkPA9qFuVTX7vhLlpfj/IGWlqY=
|
||||
golang.org/x/term v0.39.0/go.mod h1:yxzUCTP/U+FzoxfdKmLaA0RV1WgE0VY7hXBwKtY/4ww=
|
||||
golang.org/x/term v0.40.0 h1:36e4zGLqU4yhjlmxEaagx2KuYbJq3EwY8K943ZsHcvg=
|
||||
golang.org/x/term v0.40.0/go.mod h1:w2P8uVp06p2iyKKuvXIm7N/y0UCRt3UfJTfZ7oOpglM=
|
||||
golang.org/x/term v0.41.0 h1:QCgPso/Q3RTJx2Th4bDLqML4W6iJiaXFq2/ftQF13YU=
|
||||
golang.org/x/term v0.41.0/go.mod h1:3pfBgksrReYfZ5lvYM0kSO0LIkAl4Yl2bXOkKP7Ec2A=
|
||||
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.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
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.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||
golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
|
||||
golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
|
||||
golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU=
|
||||
golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
|
||||
golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4=
|
||||
golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
|
||||
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
|
||||
golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY=
|
||||
golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE=
|
||||
golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8=
|
||||
golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk=
|
||||
golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA=
|
||||
golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8=
|
||||
golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA=
|
||||
golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI=
|
||||
golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
|
||||
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/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
@@ -565,24 +649,30 @@ golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4f
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.6-0.20210820212750-d4cc65f0b2ff/go.mod h1:YD9qOF0M9xpSpdWTBbzEl5e/RnCefISl8E5Noe10jFM=
|
||||
golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
|
||||
golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA=
|
||||
golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s=
|
||||
golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc=
|
||||
golang.org/x/tools v0.9.3/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc=
|
||||
golang.org/x/tools v0.12.0/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM=
|
||||
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.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps=
|
||||
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.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=
|
||||
golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI=
|
||||
golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg=
|
||||
golang.org/x/tools v0.34.1-0.20250613162507-3f93fece84c7/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg=
|
||||
golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw=
|
||||
golang.org/x/tools v0.36.0/go.mod h1:WBDiHKJK8YgLHlcQPYQzNCkUxUypCaa5ZegCVutKm+s=
|
||||
golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w=
|
||||
golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs=
|
||||
golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ=
|
||||
golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA=
|
||||
golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc=
|
||||
golang.org/x/tools v0.41.0 h1:a9b8iMweWG+S0OBnlU36rzLp20z1Rp10w+IY2czHTQc=
|
||||
golang.org/x/tools v0.41.0/go.mod h1:XSY6eDqxVNiYgezAVqqCeihT4j1U2CCsqvH3WhQpnlg=
|
||||
golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k=
|
||||
golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0=
|
||||
golang.org/x/tools/go/expect v0.1.0-deprecated/go.mod h1:eihoPOH+FgIqa3FpoTwguz/bVUSGBlGQU67vpBeOrBY=
|
||||
golang.org/x/tools/go/expect v0.1.1-deprecated h1:jpBZDwmgPhXsKZC6WhL20P4b/wmnpsEAGHaNy0n/rJM=
|
||||
golang.org/x/tools/go/expect v0.1.1-deprecated/go.mod h1:eihoPOH+FgIqa3FpoTwguz/bVUSGBlGQU67vpBeOrBY=
|
||||
@@ -592,23 +682,29 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4=
|
||||
gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E=
|
||||
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
||||
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
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-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20260401024825-9d38bb4040a9 h1:VPWxll4HlMw1Vs/qXtN7BvhZqsS9cdAittCNvVENElA=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20260401024825-9d38bb4040a9/go.mod h1:7QBABkRtR8z+TEnmXTqIqwJLlzrZKVfAUm7tY3yGv0M=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9 h1:m8qni9SQFH0tJc1X0vmnpw/0t+AImlSvp30sEupozUg=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20260128011058-8636f8732409 h1:merA0rdPeUV3YIIfHHcH4qBkiQAc1nfCKSI7lB4cV2M=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20260128011058-8636f8732409/go.mod h1:fl8J1IvUjCilwZzQowmw2b7HQB2eAuYBabMXzWurF+I=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20260209200024-4cfbd4190f57 h1:JLQynH/LBHfCTSbDWl+py8C+Rg/k1OVH3xfcaiANuF0=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20260209200024-4cfbd4190f57/go.mod h1:kSJwQxqmFXeo79zOmbrALdflXQeAYcUbgS7PbpMknCY=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260128011058-8636f8732409 h1:H86B94AW+VfJWDqFeEbBPhEtHzJwJfTbgE2lZa54ZAQ=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260128011058-8636f8732409/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57 h1:mWPCjDEyshlQYzBpMNHaEof6UX1PmHcaUODUywQ0uac=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
|
||||
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.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.81.1 h1:VnnIIZ88UzOOKLukQi+ImGz8O1Wdp8nAGGnvOfEIWQQ=
|
||||
google.golang.org/grpc v1.81.1/go.mod h1:xGH9GfzOyMTGIOXBJmXt+BX/V0kcdQbdcuwQ/zNw42I=
|
||||
google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc=
|
||||
google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U=
|
||||
google.golang.org/grpc v1.79.1 h1:zGhSi45ODB9/p3VAawt9a+O/MULLl9dpizzNNpq7flY=
|
||||
google.golang.org/grpc v1.79.1/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
@@ -620,9 +716,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.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.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.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af h1:+5/Sw3GsDNlEmu7TfklWKPdQ0Ykja5VEmq2i817+jbI=
|
||||
google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||
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-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
@@ -649,26 +747,27 @@ 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-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
k8s.io/api v0.23.3/go.mod h1:w258XdGyvCmnBj/vGzQMj6kzdufJZVUwEM1U2fRJwSQ=
|
||||
k8s.io/api v0.36.1 h1:XbL/EMj8K2aJpJtePmqUyQMsM0D4QI2pvl7YKJ20FTY=
|
||||
k8s.io/api v0.36.1/go.mod h1:KOWo4ey3TINlXjeHVuwB3i+tXXnu+UcwFBHlI/9dvEo=
|
||||
k8s.io/apiextensions-apiserver v0.34.3 h1:p10fGlkDY09eWKOTeUSioxwLukJnm+KuDZdrW71y40g=
|
||||
k8s.io/apiextensions-apiserver v0.34.3/go.mod h1:aujxvqGFRdb/cmXYfcRTeppN7S2XV/t7WMEc64zB5A0=
|
||||
k8s.io/api v0.35.1 h1:0PO/1FhlK/EQNVK5+txc4FuhQibV25VLSdLMmGpDE/Q=
|
||||
k8s.io/api v0.35.1/go.mod h1:28uR9xlXWml9eT0uaGo6y71xK86JBELShLy4wR1XtxM=
|
||||
k8s.io/apiextensions-apiserver v0.30.0 h1:jcZFKMqnICJfRxTgnC4E+Hpcq8UEhT8B2lhBcQ+6uAs=
|
||||
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.36.1 h1:G63Gjx2W+q0YD+72Vo8oY0nDnePVwnuzTmmy5ENrVSA=
|
||||
k8s.io/apimachinery v0.36.1/go.mod h1:ibYOR00vW/I1kzvi5SF0dRuJ52BvKtfvRdOn35GPQ+8=
|
||||
k8s.io/apiserver v0.36.1 h1:iMS5V+rPUertv5P9RaqJgmHHTuh4quWpoxchvMUY+JY=
|
||||
k8s.io/apiserver v0.36.1/go.mod h1:Cby1PbLWztu0GDOxoO6iFOyyqIsziHNEW+w9zVQ22Kw=
|
||||
k8s.io/client-go v0.36.1 h1:FN/K8QIT2CEDt+2WB2HnWrUANZ50AP5GII43/SP2JR0=
|
||||
k8s.io/client-go v0.36.1/go.mod h1:s6rAnCtTGYDQnpNjEhSaISV+2O8jwruZ6m3QOYBFbtU=
|
||||
k8s.io/apimachinery v0.35.1 h1:yxO6gV555P1YV0SANtnTjXYfiivaTPvCTKX6w6qdDsU=
|
||||
k8s.io/apimachinery v0.35.1/go.mod h1:jQCgFZFR1F4Ik7hvr2g84RTJSZegBc8yHgFWKn//hns=
|
||||
k8s.io/apiserver v0.35.1 h1:potxdhhTL4i6AYAa2QCwtlhtB1eCdWQFvJV6fXgJzxs=
|
||||
k8s.io/apiserver v0.35.1/go.mod h1:BiL6Dd3A2I/0lBnteXfWmCFobHM39vt5+hJQd7Lbpi4=
|
||||
k8s.io/client-go v0.35.1 h1:+eSfZHwuo/I19PaSxqumjqZ9l5XiTEKbIaJ+j1wLcLM=
|
||||
k8s.io/client-go v0.35.1/go.mod h1:1p1KxDt3a0ruRfc/pG4qT/3oHmUj1AhSHEcxNSGg+OA=
|
||||
k8s.io/code-generator v0.23.3/go.mod h1:S0Q1JVA+kSzTI1oUvbKAxZY/DYbA/ZUb4Uknog12ETk=
|
||||
k8s.io/code-generator v0.36.1 h1:5bHQ7NbBcFFLHcoyo/hgU3m2tQV5RLz2nv4QNDlsbXc=
|
||||
k8s.io/code-generator v0.36.1/go.mod h1:oCv8WmrW2RGdcMyvSk1aYbBfSs51ggtSFQr1YNeuAuo=
|
||||
k8s.io/component-base v0.36.1 h1:iG6GsELftXqTNG9HG6kiVjatSgAw1sf5pJ6R5a6N0kA=
|
||||
k8s.io/component-base v0.36.1/go.mod h1:nf9XPlntRdqO6WMeEWAA5F93Y4ICZQdeT9GeqLDB3JI=
|
||||
k8s.io/component-helpers v0.36.1 h1:BTrr5fzNSm8TkQfXrKT3N9ioWwiC4n2FTIwGTUo/ccg=
|
||||
k8s.io/component-helpers v0.36.1/go.mod h1:s38HnzKQRurbUnhI5IV8GwyL/a3lVuNCYZMTd+rITMM=
|
||||
k8s.io/code-generator v0.35.1 h1:yLKR2la7Z9cWT5qmk67ayx8xXLM4RRKQMnC8YPvTWRI=
|
||||
k8s.io/code-generator v0.35.1/go.mod h1:F2Fhm7aA69tC/VkMXLDokdovltXEF026Tb9yfQXQWKg=
|
||||
k8s.io/component-base v0.35.1 h1:XgvpRf4srp037QWfGBLFsYMUQJkE5yMa94UsJU7pmcE=
|
||||
k8s.io/component-base v0.35.1/go.mod h1:HI/6jXlwkiOL5zL9bqA3en1Ygv60F03oEpnuU1G56Bs=
|
||||
k8s.io/component-helpers v0.35.1 h1:vwQ/cAfnVwaPeSXTu4DdK3d3n11Lugc5vMb6EV809ZY=
|
||||
k8s.io/component-helpers v0.35.1/go.mod h1:HQqMwUk68Yyxgj92dJ+J1w/qbx9M0QR0eZ680m/o+Rk=
|
||||
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/v2 v2.0.0-20250604051438-85fd79dbfd9f/go.mod h1:EJykeLsmFC60UQbYJezXkEsG2FLrt0GPNkU5iK5GWxU=
|
||||
k8s.io/gengo/v2 v2.0.0-20250922181213-ec3ebc5fd46b h1:gMplByicHV/TJBizHd9aVEsTYoJBnnUAT5MHlTkbjhQ=
|
||||
k8s.io/gengo/v2 v2.0.0-20250922181213-ec3ebc5fd46b/go.mod h1:CgujABENc3KuTrcsdpGmrrASjtQsWCT7R99mEV4U/fM=
|
||||
k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
|
||||
@@ -676,31 +775,30 @@ 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.40.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
|
||||
k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
|
||||
k8s.io/klog/v2 v2.140.0 h1:Tf+J3AH7xnUzZyVVXhTgGhEKnFqye14aadWv7bzXdzc=
|
||||
k8s.io/klog/v2 v2.140.0/go.mod h1:o+/RWfJ6PwpnFn7OyAG3QnO47BFsymfEfrz6XyYSSp0=
|
||||
k8s.io/kms v0.36.1 h1:XdvKpywoW4k7YUHDh5uYP4mahJXECswHGfCddBBYLZs=
|
||||
k8s.io/kms v0.36.1/go.mod h1:g91diTD9h0oJCCHkTb00krlF+Qm5HTnkWLi9Q/TpRoc=
|
||||
k8s.io/kube-openapi v0.0.0-20260512234627-ef417d054102 h1:xs2ux1MvyrOdfKwS3vuFWrGuLgDOHk6id975Twx2Jss=
|
||||
k8s.io/kube-openapi v0.0.0-20260512234627-ef417d054102/go.mod h1:V/QaCUYDa+0QpcHhVVc5l99Uz56wEMEXBSj9oCDkNDY=
|
||||
k8s.io/metrics v0.36.1 h1:MQPb+G4RhrKEpt8NETPssbW8QgGUc4Jbqu1jx+kPqGk=
|
||||
k8s.io/metrics v0.36.1/go.mod h1:xqS8XcWLjDzo6E7DJm/GfjKpRKdN5/MtJAQFuV6nLUc=
|
||||
k8s.io/streaming v0.36.1 h1:L+K68n4Gg940BGNNYtUBvL1WTLL0YnKT3s+P1MNAmR4=
|
||||
k8s.io/streaming v0.36.1/go.mod h1:z6fV3D+NVkoeqRMtWwlUZK6U17SY/LqNzOxWL6GyR/s=
|
||||
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
|
||||
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
|
||||
k8s.io/kms v0.35.1 h1:kjv2r9g1mY7uL+l1RhyAZvWVZIA/4qIfBHXyjFGLRhU=
|
||||
k8s.io/kms v0.35.1/go.mod h1:VT+4ekZAdrZDMgShK37vvlyHUVhwI9t/9tvh0AyCWmQ=
|
||||
k8s.io/kube-openapi v0.0.0-20260127142750-a19766b6e2d4 h1:HhDfevmPS+OalTjQRKbTHppRIz01AWi8s45TMXStgYY=
|
||||
k8s.io/kube-openapi v0.0.0-20260127142750-a19766b6e2d4/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ=
|
||||
k8s.io/metrics v0.35.1 h1:MUcrUcWlq81XiripkydzCGsY9zQawDXfP9IICNNcVVw=
|
||||
k8s.io/metrics v0.35.1/go.mod h1:9x7xWOAOiWzHA0vaqLgSE4PXF3vyT5ts5XIbx8OSjiI=
|
||||
k8s.io/utils v0.0.0-20211116205334-6203023598ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||
k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2/go.mod h1:xDxuJ0whA3d0I4mf/C4ppKHxXynQ+fxnkmQH0vTHnuk=
|
||||
k8s.io/utils v0.0.0-20260507154919-ff6756f316d2 h1:wU4tMEhLGgIbLvXQb1cfN+EcM0wf7zC6CPF+C79jroc=
|
||||
k8s.io/utils v0.0.0-20260507154919-ff6756f316d2/go.mod h1:xDxuJ0whA3d0I4mf/C4ppKHxXynQ+fxnkmQH0vTHnuk=
|
||||
kubevirt.io/api v1.8.2 h1:h8AACJlity2n8gRE6e9PgikLAwzmNz6gzVjT1kbsDZY=
|
||||
kubevirt.io/api v1.8.2/go.mod h1:EUaPeD1GQK4IIEp8TVtk5dsFlYQGzFfcWi4CV4rs0rY=
|
||||
kubevirt.io/client-go v1.8.2 h1:jKJe5j/M7GDfpqTreoBA+BVoyQPCPTbLpuGHHaBfjdk=
|
||||
kubevirt.io/client-go v1.8.2/go.mod h1:eoH34Z/Wa1JuHeIezT/tcGDMa6zLLEf3FPRx5beJU3k=
|
||||
kubevirt.io/containerized-data-importer-api v1.64.0 h1:yBLY6qEogUp8F+XSJvabIkx9uEEDeToYDfRr0mbUxJc=
|
||||
kubevirt.io/containerized-data-importer-api v1.64.0/go.mod h1:VGp35wxpLXU18b7cnEpmcThI3AjcZUSfg/Zfql44U4o=
|
||||
kubevirt.io/controller-lifecycle-operator-sdk/api v0.2.4 h1:fZYvD3/Vnitfkx6IJxjLAk8ugnZQ7CXVYcRfkSKmuZY=
|
||||
kubevirt.io/controller-lifecycle-operator-sdk/api v0.2.4/go.mod h1:018lASpFYBsYN6XwmA2TIrPCx6e0gviTd/ZNtSitKgc=
|
||||
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.34.0 h1:hSfpvjjTQXQY2Fol2CS0QHMNs/WI1MOSGzCm1KhM5ec=
|
||||
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.34.0/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw=
|
||||
k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
||||
k8s.io/utils v0.0.0-20260108192941-914a6e750570 h1:JT4W8lsdrGENg9W+YwwdLJxklIuKWdRm+BC+xt33FOY=
|
||||
k8s.io/utils v0.0.0-20260108192941-914a6e750570/go.mod h1:xDxuJ0whA3d0I4mf/C4ppKHxXynQ+fxnkmQH0vTHnuk=
|
||||
kubevirt.io/api v1.3.0 h1:9sGElMmnRU50pGED+MPPD2OwQl4S5lvjCUjm+t0mI90=
|
||||
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/go.mod h1:qmcJZvUjbmggY1pp7irO3zesBJj7wwGIWAdnYEoh3yc=
|
||||
kubevirt.io/containerized-data-importer-api v1.57.0-alpha1 h1:IWo12+ei3jltSN5jQN1xjgakfvRSF3G3Rr4GXVOOy2I=
|
||||
kubevirt.io/containerized-data-importer-api v1.57.0-alpha1/go.mod h1:Y/8ETgHS1GjO89bl682DPtQOYEU/1ctPFBz6Sjxm4DM=
|
||||
kubevirt.io/controller-lifecycle-operator-sdk/api v0.0.0-20220329064328-f3cc58c6ed90 h1:QMrd0nKP0BGbnxTqakhDZAUhGKxPiPiN5gSDqKUmGGc=
|
||||
kubevirt.io/controller-lifecycle-operator-sdk/api v0.0.0-20220329064328-f3cc58c6ed90/go.mod h1:018lASpFYBsYN6XwmA2TIrPCx6e0gviTd/ZNtSitKgc=
|
||||
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 h1:jpcvIRr3GLoUoEKRkHKSmGjxb6lWwrBlJsXc+eUYQHM=
|
||||
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-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
|
||||
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg=
|
||||
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg=
|
||||
sigs.k8s.io/mdtoc v1.4.0 h1:2pDEwJSjoVrGr5BPkG+LoLkYLKvgtGYurrBY8ul3SxQ=
|
||||
@@ -711,9 +809,11 @@ sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxO
|
||||
sigs.k8s.io/release-utils v0.8.3 h1:KtOtA4qDmzJyeQ2zkDsFVI25+NViwms/o5eL2NftFdA=
|
||||
sigs.k8s.io/release-utils v0.8.3/go.mod h1:fp82Fma06OXBhEJ+GUJKqvcplDBomruK1R/1fWJnsrQ=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.1/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4=
|
||||
sigs.k8s.io/structured-merge-diff/v6 v6.3.2 h1:kwVWMx5yS1CrnFWA/2QHyRVJ8jM6dBA80uLmm0wJkk8=
|
||||
sigs.k8s.io/structured-merge-diff/v6 v6.3.2/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE=
|
||||
sigs.k8s.io/structured-merge-diff/v6 v6.2.0/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE=
|
||||
sigs.k8s.io/structured-merge-diff/v6 v6.3.0 h1:jTijUJbW353oVOd9oTlifJqOGEkUw2jB/fXCbTiQEco=
|
||||
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.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
|
||||
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=
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@
|
||||
go::verify_version() {
|
||||
GO_VERSION=($(go version))
|
||||
|
||||
if [[ -z $(echo "${GO_VERSION[2]}" | grep -E 'go1.24|go1.25|go1.26') ]]; then
|
||||
if [[ -z $(echo "${GO_VERSION[2]}" | grep -E 'go1.23|go1.24|go1.25') ]]; then
|
||||
echo "Unknown go version '${GO_VERSION[2]}', skipping gofmt."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -16,7 +16,7 @@ spec:
|
||||
priorityClassName: system-cluster-critical
|
||||
containers:
|
||||
- name: descheduler
|
||||
image: registry.k8s.io/descheduler/descheduler:v0.36.0
|
||||
image: registry.k8s.io/descheduler/descheduler:v0.35.0
|
||||
volumeMounts:
|
||||
- mountPath: /policy-dir
|
||||
name: policy-volume
|
||||
|
||||
@@ -19,7 +19,7 @@ spec:
|
||||
serviceAccountName: descheduler-sa
|
||||
containers:
|
||||
- name: descheduler
|
||||
image: registry.k8s.io/descheduler/descheduler:v0.36.0
|
||||
image: registry.k8s.io/descheduler/descheduler:v0.35.0
|
||||
imagePullPolicy: IfNotPresent
|
||||
command:
|
||||
- "/bin/descheduler"
|
||||
|
||||
@@ -14,7 +14,7 @@ spec:
|
||||
priorityClassName: system-cluster-critical
|
||||
containers:
|
||||
- name: descheduler
|
||||
image: registry.k8s.io/descheduler/descheduler:v0.36.0
|
||||
image: registry.k8s.io/descheduler/descheduler:v0.35.0
|
||||
volumeMounts:
|
||||
- mountPath: /policy-dir
|
||||
name: policy-volume
|
||||
|
||||
@@ -57,7 +57,6 @@ var (
|
||||
|
||||
type evictionRequestItem struct {
|
||||
podName, podNamespace, podNodeName string
|
||||
strategyName, profileName string
|
||||
evictionAssumed bool
|
||||
assumedTimestamp metav1.Time
|
||||
}
|
||||
@@ -150,35 +149,17 @@ func (erc *evictionRequestsCache) addPod(pod *v1.Pod) {
|
||||
erc.requestsTotal++
|
||||
}
|
||||
|
||||
func (erc *evictionRequestsCache) assumePod(pod *v1.Pod, profileName, strategyName string) {
|
||||
func (erc *evictionRequestsCache) assumePod(pod *v1.Pod) {
|
||||
erc.mu.Lock()
|
||||
defer erc.mu.Unlock()
|
||||
uid := getPodKey(pod)
|
||||
if item, exists := erc.requests[uid]; exists {
|
||||
if item.evictionAssumed {
|
||||
// Pod already assumed by a previous strategy/profile; first one wins.
|
||||
return
|
||||
}
|
||||
// The informer's UpdateFunc called addPod (evictionAssumed=false) before
|
||||
// the TooManyRequests response arrived. Upgrade the entry in place without
|
||||
// bumping the counters a second time.
|
||||
erc.requests[uid] = evictionRequestItem{
|
||||
podNamespace: item.podNamespace,
|
||||
podName: item.podName,
|
||||
podNodeName: item.podNodeName,
|
||||
strategyName: strategyName,
|
||||
profileName: profileName,
|
||||
evictionAssumed: true,
|
||||
assumedTimestamp: metav1.NewTime(time.Now()),
|
||||
}
|
||||
if _, exists := erc.requests[uid]; exists {
|
||||
return
|
||||
}
|
||||
erc.requests[uid] = evictionRequestItem{
|
||||
podNamespace: pod.Namespace,
|
||||
podName: pod.Name,
|
||||
podNodeName: pod.Spec.NodeName,
|
||||
strategyName: strategyName,
|
||||
profileName: profileName,
|
||||
evictionAssumed: true,
|
||||
assumedTimestamp: metav1.NewTime(time.Now()),
|
||||
}
|
||||
@@ -210,14 +191,6 @@ func (erc *evictionRequestsCache) deletePod(pod *v1.Pod) {
|
||||
}
|
||||
}
|
||||
|
||||
func (erc *evictionRequestsCache) getPod(pod *v1.Pod) (evictionRequestItem, bool) {
|
||||
erc.mu.RLock()
|
||||
defer erc.mu.RUnlock()
|
||||
uid := getPodKey(pod)
|
||||
item, exists := erc.requests[uid]
|
||||
return item, exists
|
||||
}
|
||||
|
||||
func (erc *evictionRequestsCache) hasPod(pod *v1.Pod) bool {
|
||||
erc.mu.RLock()
|
||||
defer erc.mu.RUnlock()
|
||||
@@ -374,12 +347,8 @@ func NewPodEvictor(
|
||||
klog.ErrorS(nil, "Cannot convert to *v1.Pod", "obj", t)
|
||||
return
|
||||
}
|
||||
if item, exists := erCache.getPod(pod); exists {
|
||||
if erCache.hasPod(pod) {
|
||||
klog.V(3).InfoS("Pod with eviction in background deleted/evicted. Removing pod from the cache.", "pod", klog.KObj(pod))
|
||||
if item.evictionAssumed && podEvictor.metricsEnabled {
|
||||
metrics.PodsEvicted.With(map[string]string{"result": "success", "strategy": item.strategyName, "namespace": item.podNamespace, "node": item.podNodeName, "profile": item.profileName}).Inc()
|
||||
metrics.PodsEvictedTotal.With(map[string]string{"result": "success", "strategy": item.strategyName, "namespace": item.podNamespace, "node": item.podNodeName, "profile": item.profileName}).Inc()
|
||||
}
|
||||
}
|
||||
erCache.deletePod(pod)
|
||||
},
|
||||
@@ -639,11 +608,7 @@ func (pe *PodEvictor) evictPod(ctx context.Context, pod *v1.Pod, opts EvictOptio
|
||||
return true, nil
|
||||
}
|
||||
klog.V(3).InfoS("Eviction in background assumed", "pod", klog.KObj(pod))
|
||||
pe.erCache.assumePod(pod, opts.ProfileName, opts.StrategyName)
|
||||
if pe.metricsEnabled {
|
||||
metrics.PodsEvicted.With(map[string]string{"result": "background", "strategy": opts.StrategyName, "namespace": pod.Namespace, "node": pod.Spec.NodeName, "profile": opts.ProfileName}).Inc()
|
||||
metrics.PodsEvictedTotal.With(map[string]string{"result": "background", "strategy": opts.StrategyName, "namespace": pod.Namespace, "node": pod.Spec.NodeName, "profile": opts.ProfileName}).Inc()
|
||||
}
|
||||
pe.erCache.assumePod(pod)
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,9 +39,6 @@ import (
|
||||
"k8s.io/klog/v2"
|
||||
utilptr "k8s.io/utils/ptr"
|
||||
|
||||
metricstest "k8s.io/component-base/metrics/testutil"
|
||||
|
||||
deschedulermetrics "sigs.k8s.io/descheduler/metrics"
|
||||
podutil "sigs.k8s.io/descheduler/pkg/descheduler/pod"
|
||||
"sigs.k8s.io/descheduler/pkg/features"
|
||||
"sigs.k8s.io/descheduler/pkg/utils"
|
||||
@@ -466,223 +463,6 @@ func TestEvictionRequestsCacheCleanup(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestEvictionInBackgroundMetrics(t *testing.T) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), wait.ForeverTestTimeout)
|
||||
defer cancel()
|
||||
|
||||
deschedulermetrics.Register()
|
||||
deschedulermetrics.PodsEvicted.Reset()
|
||||
deschedulermetrics.PodsEvictedTotal.Reset()
|
||||
|
||||
node1 := test.BuildTestNode("n1", 2000, 3000, 10, nil)
|
||||
|
||||
ownerRef1 := test.GetReplicaSetOwnerRefList()
|
||||
updatePod := func(pod *v1.Pod) {
|
||||
pod.Namespace = "dev"
|
||||
pod.ObjectMeta.OwnerReferences = ownerRef1
|
||||
}
|
||||
updatePodWithEvictionAnnotation := func(pod *v1.Pod) {
|
||||
updatePod(pod)
|
||||
pod.Annotations = map[string]string{
|
||||
EvictionRequestAnnotationKey: "",
|
||||
}
|
||||
}
|
||||
|
||||
// p1, p2: will be evicted in background
|
||||
// p3, p4: will be evicted normally
|
||||
p1 := test.BuildTestPod("p1", 100, 0, node1.Name, updatePodWithEvictionAnnotation)
|
||||
p2 := test.BuildTestPod("p2", 100, 0, node1.Name, updatePodWithEvictionAnnotation)
|
||||
p3 := test.BuildTestPod("p3", 100, 0, node1.Name, updatePod)
|
||||
p4 := test.BuildTestPod("p4", 100, 0, node1.Name, updatePod)
|
||||
|
||||
client := fakeclientset.NewSimpleClientset(node1, p1, p2, p3, p4)
|
||||
sharedInformerFactory := informers.NewSharedInformerFactory(client, 0)
|
||||
_, eventRecorder := utils.GetRecorderAndBroadcaster(ctx, client)
|
||||
|
||||
podEvictor, err := NewPodEvictor(
|
||||
ctx,
|
||||
client,
|
||||
eventRecorder,
|
||||
sharedInformerFactory.Core().V1().Pods().Informer(),
|
||||
initFeatureGates(),
|
||||
NewOptions().WithMetricsEnabled(true),
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error when creating a pod evictor: %v", err)
|
||||
}
|
||||
|
||||
client.PrependReactor("create", "pods", func(action core.Action) (bool, runtime.Object, error) {
|
||||
if action.GetSubresource() == "eviction" {
|
||||
createAct, matched := action.(core.CreateActionImpl)
|
||||
if !matched {
|
||||
return false, nil, fmt.Errorf("unable to convert action to core.CreateActionImpl")
|
||||
}
|
||||
if eviction, matched := createAct.Object.(*policy.Eviction); matched {
|
||||
if eviction.GetName() == "p1" || eviction.GetName() == "p2" {
|
||||
return true, nil, &apierrors.StatusError{
|
||||
ErrStatus: metav1.Status{
|
||||
Reason: metav1.StatusReasonTooManyRequests,
|
||||
Message: "Eviction triggered evacuation",
|
||||
},
|
||||
}
|
||||
}
|
||||
return true, nil, nil
|
||||
}
|
||||
}
|
||||
return false, nil, nil
|
||||
})
|
||||
|
||||
sharedInformerFactory.Start(ctx.Done())
|
||||
sharedInformerFactory.WaitForCacheSync(ctx.Done())
|
||||
|
||||
evictOpts := EvictOptions{StrategyName: "TestStrategy", ProfileName: "TestProfile"}
|
||||
|
||||
// Cycle 1: p1/p2 go to background, p3/p4 are evicted normally.
|
||||
podEvictor.EvictPod(ctx, p1, evictOpts)
|
||||
podEvictor.EvictPod(ctx, p2, evictOpts)
|
||||
podEvictor.EvictPod(ctx, p3, evictOpts)
|
||||
podEvictor.EvictPod(ctx, p4, evictOpts)
|
||||
|
||||
// After cycle 1: 2 "background" (p1, p2), 2 "success" (p3, p4).
|
||||
metricstest.AssertVectorCount(t, "descheduler_pods_evicted_total", map[string]string{"result": "background"}, 2)
|
||||
metricstest.AssertVectorCount(t, "descheduler_pods_evicted_total", map[string]string{"result": "success"}, 2)
|
||||
|
||||
// Cycle 2: p1/p2 are still running (background eviction in progress).
|
||||
// Re-attempting them must not emit any additional metrics.
|
||||
podEvictor.EvictPod(ctx, p1, evictOpts)
|
||||
podEvictor.EvictPod(ctx, p2, evictOpts)
|
||||
|
||||
// Counts must be unchanged after cycle 2.
|
||||
metricstest.AssertVectorCount(t, "descheduler_pods_evicted_total", map[string]string{"result": "background"}, 2)
|
||||
metricstest.AssertVectorCount(t, "descheduler_pods_evicted_total", map[string]string{"result": "success"}, 2)
|
||||
|
||||
// The background evictions complete: p1 and p2 are deleted.
|
||||
// The informer's DeleteFunc fires and emits a "success" metric for each assumed pod.
|
||||
client.CoreV1().Pods(p1.Namespace).Delete(ctx, p1.Name, metav1.DeleteOptions{})
|
||||
client.CoreV1().Pods(p2.Namespace).Delete(ctx, p2.Name, metav1.DeleteOptions{})
|
||||
|
||||
// Poll until DeleteFunc has fired for both pods (informer is async).
|
||||
if err := wait.PollUntilContextTimeout(ctx, 100*time.Millisecond, wait.ForeverTestTimeout, true, func(ctx context.Context) (bool, error) {
|
||||
return !podEvictor.erCache.hasPod(p1) && !podEvictor.erCache.hasPod(p2), nil
|
||||
}); err != nil {
|
||||
t.Fatalf("Timed out waiting for background evictions to complete: %v", err)
|
||||
}
|
||||
|
||||
// After deletion: "success" grows by 2 (p1, p2 completed), "background" stays at 2.
|
||||
metricstest.AssertVectorCount(t, "descheduler_pods_evicted_total", map[string]string{"result": "success"}, 4)
|
||||
metricstest.AssertVectorCount(t, "descheduler_pods_evicted_total", map[string]string{"result": "background"}, 2)
|
||||
}
|
||||
|
||||
// TestEvictionInBackgroundMetrics_InformerRace reproduces the race where the
|
||||
// informer's UpdateFunc calls addPod (evictionAssumed=false) before evictPod's
|
||||
// assumePod call, causing the "success" metric to be silently dropped when the
|
||||
// pod is later deleted.
|
||||
//
|
||||
// The race: evictPod sends the eviction request; the KubeVirt handler sets
|
||||
// EvictionInProgressAnnotationKey before returning TooManyRequests, so the
|
||||
// informer's UpdateFunc fires and calls addPod (evictionAssumed=false) while
|
||||
// evictPod is still waiting for the HTTP response. When the response arrives,
|
||||
// assumePod finds the entry already present and returns early, leaving
|
||||
// evictionAssumed=false. DeleteFunc then skips the "success" metric.
|
||||
func TestEvictionInBackgroundMetrics_InformerRace(t *testing.T) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), wait.ForeverTestTimeout)
|
||||
defer cancel()
|
||||
|
||||
deschedulermetrics.Register()
|
||||
deschedulermetrics.PodsEvicted.Reset()
|
||||
deschedulermetrics.PodsEvictedTotal.Reset()
|
||||
|
||||
node1 := test.BuildTestNode("n1", 2000, 3000, 10, nil)
|
||||
|
||||
ownerRef1 := test.GetReplicaSetOwnerRefList()
|
||||
p1 := test.BuildTestPod("p1", 100, 0, node1.Name, func(pod *v1.Pod) {
|
||||
pod.Namespace = "dev"
|
||||
pod.ObjectMeta.OwnerReferences = ownerRef1
|
||||
pod.Annotations = map[string]string{
|
||||
EvictionRequestAnnotationKey: "",
|
||||
}
|
||||
})
|
||||
|
||||
client := fakeclientset.NewSimpleClientset(node1, p1)
|
||||
sharedInformerFactory := informers.NewSharedInformerFactory(client, 0)
|
||||
_, eventRecorder := utils.GetRecorderAndBroadcaster(ctx, client)
|
||||
|
||||
podEvictor, err := NewPodEvictor(
|
||||
ctx,
|
||||
client,
|
||||
eventRecorder,
|
||||
sharedInformerFactory.Core().V1().Pods().Informer(),
|
||||
initFeatureGates(),
|
||||
NewOptions().WithMetricsEnabled(true),
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error when creating a pod evictor: %v", err)
|
||||
}
|
||||
|
||||
// calling erCache.addPod from a goroutine.
|
||||
triggerAddPod := make(chan struct{})
|
||||
addPodDone := make(chan struct{})
|
||||
|
||||
go func() {
|
||||
<-triggerAddPod
|
||||
// Simulate what UpdateFunc does when KubeVirt sets
|
||||
// EvictionInProgressAnnotationKey before the TooManyRequests response
|
||||
// arrives: addPod inserts the entry with evictionAssumed=false.
|
||||
podEvictor.erCache.addPod(p1)
|
||||
close(addPodDone)
|
||||
}()
|
||||
|
||||
client.PrependReactor("create", "pods", func(action core.Action) (bool, runtime.Object, error) {
|
||||
if action.GetSubresource() != "eviction" {
|
||||
return false, nil, nil
|
||||
}
|
||||
createAct, ok := action.(core.CreateActionImpl)
|
||||
if !ok {
|
||||
return false, nil, fmt.Errorf("unable to convert action to core.CreateActionImpl")
|
||||
}
|
||||
eviction, ok := createAct.Object.(*policy.Eviction)
|
||||
if !ok || eviction.GetName() != "p1" {
|
||||
return false, nil, nil
|
||||
}
|
||||
|
||||
// Trigger addPod and wait for it to complete before returning
|
||||
// TooManyRequests, ensuring assumePod will find the entry already present.
|
||||
close(triggerAddPod)
|
||||
<-addPodDone
|
||||
|
||||
return true, nil, &apierrors.StatusError{
|
||||
ErrStatus: metav1.Status{
|
||||
Reason: metav1.StatusReasonTooManyRequests,
|
||||
Message: "Eviction triggered evacuation",
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
sharedInformerFactory.Start(ctx.Done())
|
||||
sharedInformerFactory.WaitForCacheSync(ctx.Done())
|
||||
|
||||
evictOpts := EvictOptions{StrategyName: "TestStrategy", ProfileName: "TestProfile"}
|
||||
podEvictor.EvictPod(ctx, p1, evictOpts)
|
||||
|
||||
// The "background" metric must have been emitted.
|
||||
metricstest.AssertVectorCount(t, "descheduler_pods_evicted_total", map[string]string{"result": "background"}, 1)
|
||||
|
||||
// Simulate the background eviction completing: the pod is deleted.
|
||||
client.CoreV1().Pods(p1.Namespace).Delete(ctx, p1.Name, metav1.DeleteOptions{})
|
||||
|
||||
// Wait until DeleteFunc has fired and removed the pod from the cache.
|
||||
if err := wait.PollUntilContextTimeout(ctx, 100*time.Millisecond, wait.ForeverTestTimeout, true, func(ctx context.Context) (bool, error) {
|
||||
return !podEvictor.erCache.hasPod(p1), nil
|
||||
}); err != nil {
|
||||
t.Fatalf("Timed out waiting for background eviction to complete: %v", err)
|
||||
}
|
||||
|
||||
// "success" must also be 1: the background eviction completed.
|
||||
// Without the fix this will be 0 because assumePod returned early (entry
|
||||
// already present from addPod) leaving evictionAssumed=false.
|
||||
metricstest.AssertVectorCount(t, "descheduler_pods_evicted_total", map[string]string{"result": "success"}, 1)
|
||||
}
|
||||
|
||||
func assertEqualEvents(t *testing.T, expected []string, actual <-chan string) {
|
||||
t.Logf("Assert for events: %v", expected)
|
||||
c := time.After(wait.ForeverTestTimeout)
|
||||
|
||||
@@ -23,7 +23,6 @@ import (
|
||||
|
||||
v1 "k8s.io/api/core/v1"
|
||||
policy "k8s.io/api/policy/v1"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
@@ -64,26 +63,6 @@ func setupTestSandbox(ctx context.Context, t *testing.T, initialObjects ...runti
|
||||
realFactory.Start(ctx.Done())
|
||||
realFactory.WaitForCacheSync(ctx.Done())
|
||||
|
||||
// Wait for initial objects to propagate from real client to fake client via event handlers.
|
||||
for _, obj := range initialObjects {
|
||||
if err := wait.PollUntilContextTimeout(ctx, time.Second, 5*time.Second, true, func(ctx context.Context) (bool, error) {
|
||||
exists, err := sandbox.hasRuntimeObjectInIndexer(obj)
|
||||
if err != nil {
|
||||
t.Logf("Error checking if object propagated to fake indexer: %v", err)
|
||||
return false, nil
|
||||
}
|
||||
if !exists {
|
||||
metaObj, _ := meta.Accessor(obj)
|
||||
t.Logf("Initial object %s/%s has not propagated to fake indexer yet, waiting...", metaObj.GetNamespace(), metaObj.GetName())
|
||||
}
|
||||
return exists, nil
|
||||
}); err != nil {
|
||||
metaObj, _ := meta.Accessor(obj)
|
||||
t.Fatalf("Initial object %s/%s did not propagate to fake indexer within timeout: %v",
|
||||
metaObj.GetNamespace(), metaObj.GetName(), err)
|
||||
}
|
||||
}
|
||||
|
||||
return sandbox, realFactory, realClient
|
||||
}
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@ func New(ctx context.Context, args runtime.Object, handle frameworktypes.Handle)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if ev.args.NamespaceLabelSelector != nil && (len(ev.args.NamespaceLabelSelector.MatchLabels) > 0 || len(ev.args.NamespaceLabelSelector.MatchExpressions) > 0) {
|
||||
if ev.args.NamespaceLabelSelector != nil && len(ev.args.NamespaceLabelSelector.MatchLabels) > 0 {
|
||||
selector, nslErr := metav1.LabelSelectorAsSelector(ev.args.NamespaceLabelSelector)
|
||||
if nslErr != nil {
|
||||
return nil, fmt.Errorf("unable to convert namespaceLabelSelector to label selector: %w", nslErr)
|
||||
@@ -447,7 +447,7 @@ func (d *DefaultEvictor) PreEvictionFilter(pod *v1.Pod) bool {
|
||||
}
|
||||
}
|
||||
|
||||
if d.args.NamespaceLabelSelector == nil || (len(d.args.NamespaceLabelSelector.MatchLabels) == 0 && len(d.args.NamespaceLabelSelector.MatchExpressions) == 0) {
|
||||
if d.args.NamespaceLabelSelector == nil || len(d.args.NamespaceLabelSelector.MatchLabels) == 0 {
|
||||
return true
|
||||
}
|
||||
indexName := namespaceWithLabelSelector + d.handle.PluginInstanceID()
|
||||
|
||||
@@ -1030,13 +1030,13 @@ func initializePlugin(ctx context.Context, test testCase) (frameworktypes.Plugin
|
||||
objs = append(objs, ns)
|
||||
}
|
||||
|
||||
fakeClient := fake.NewClientset(objs...)
|
||||
fakeClient := fake.NewSimpleClientset(objs...)
|
||||
|
||||
sharedInformerFactory := informers.NewSharedInformerFactory(fakeClient, 0)
|
||||
podInformer := sharedInformerFactory.Core().V1().Pods().Informer()
|
||||
_ = sharedInformerFactory.Policy().V1().PodDisruptionBudgets().Lister()
|
||||
_ = sharedInformerFactory.Core().V1().PersistentVolumeClaims().Lister()
|
||||
_ = sharedInformerFactory.Core().V1().Namespaces().Informer()
|
||||
_ = sharedInformerFactory.Core().V1().Namespaces().Lister()
|
||||
getPodsAssignedToNode, err := podutil.BuildGetPodsAssignedToNodeFunc(podInformer)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("build get pods assigned to node function error: %v", err)
|
||||
@@ -1283,7 +1283,9 @@ func TestMultipleProfilesWithDifferentNamespaceLabelSelectors(t *testing.T) {
|
||||
fakeClient := fake.NewClientset(node, nsProd, nsBackend, nsTest, podInProd, podInBackend, podInTest)
|
||||
sharedInformerFactory := informers.NewSharedInformerFactory(fakeClient, 0)
|
||||
|
||||
_ = sharedInformerFactory.Core().V1().Namespaces().Informer()
|
||||
_ = sharedInformerFactory.Core().V1().Namespaces().Lister()
|
||||
sharedInformerFactory.Start(ctx.Done())
|
||||
sharedInformerFactory.WaitForCacheSync(ctx.Done())
|
||||
|
||||
// Create Profile 1: targets namespaces with env=prod
|
||||
profile1Args := &DefaultEvictorArgs{
|
||||
@@ -1326,9 +1328,6 @@ func TestMultipleProfilesWithDifferentNamespaceLabelSelectors(t *testing.T) {
|
||||
t.Fatalf("unable to initialize profile2 plugin: %v", err)
|
||||
}
|
||||
|
||||
sharedInformerFactory.Start(ctx.Done())
|
||||
sharedInformerFactory.WaitForCacheSync(ctx.Done())
|
||||
|
||||
// Test Profile 1: evicts pods in ns-prod, reject others
|
||||
t.Run("profile1", func(t *testing.T) {
|
||||
profile1 := profile1Plugin.(*DefaultEvictor)
|
||||
@@ -1363,145 +1362,3 @@ func TestMultipleProfilesWithDifferentNamespaceLabelSelectors(t *testing.T) {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestNamespaceLabelSelectorAllOperations(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
node := test.BuildTestNode("node1", 1000, 2000, 10, nil)
|
||||
|
||||
nsProd := test.BuildTestNamespace("ns-prod")
|
||||
nsProd.Labels = map[string]string{"env": "prod", "tier": "frontend"}
|
||||
|
||||
nsStaging := test.BuildTestNamespace("ns-staging")
|
||||
nsStaging.Labels = map[string]string{"env": "staging", "tier": "backend"}
|
||||
|
||||
nsTest := test.BuildTestNamespace("ns-test")
|
||||
nsTest.Labels = map[string]string{"env": "test"}
|
||||
|
||||
nsNoLabels := test.BuildTestNamespace("ns-nolabels")
|
||||
nsNoLabels.Labels = map[string]string{}
|
||||
|
||||
podInProdFrontend := test.BuildTestPod("pod-in-prod", 100, 100, node.Name, func(pod *v1.Pod) {
|
||||
pod.Namespace = nsProd.Name
|
||||
test.SetNormalOwnerRef(pod)
|
||||
})
|
||||
|
||||
podInStagingBackend := test.BuildTestPod("pod-in-staging", 100, 100, node.Name, func(pod *v1.Pod) {
|
||||
pod.Namespace = nsStaging.Name
|
||||
test.SetNormalOwnerRef(pod)
|
||||
})
|
||||
|
||||
podInTest := test.BuildTestPod("pod-in-test", 100, 100, node.Name, func(pod *v1.Pod) {
|
||||
pod.Namespace = nsTest.Name
|
||||
test.SetNormalOwnerRef(pod)
|
||||
})
|
||||
|
||||
podInNoLabels := test.BuildTestPod("pod-in-nolabels", 100, 100, node.Name, func(pod *v1.Pod) {
|
||||
pod.Namespace = nsNoLabels.Name
|
||||
test.SetNormalOwnerRef(pod)
|
||||
})
|
||||
|
||||
fakeClient := fake.NewClientset(node, nsProd, nsStaging, nsTest, nsNoLabels, podInProdFrontend, podInStagingBackend, podInTest, podInNoLabels)
|
||||
sharedInformerFactory := informers.NewSharedInformerFactory(fakeClient, 0)
|
||||
getPodAssignedToNode, _ := podutil.BuildGetPodsAssignedToNodeFunc(sharedInformerFactory.Core().V1().Pods().Informer())
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
args *DefaultEvictorArgs
|
||||
pass []*v1.Pod
|
||||
fail []*v1.Pod
|
||||
}{
|
||||
{
|
||||
name: "MatchLabels and MatchExpressions In",
|
||||
args: &DefaultEvictorArgs{
|
||||
NamespaceLabelSelector: &metav1.LabelSelector{
|
||||
MatchLabels: map[string]string{"tier": "frontend"},
|
||||
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||
{Key: "env", Operator: metav1.LabelSelectorOpIn, Values: []string{"prod", "staging"}},
|
||||
},
|
||||
},
|
||||
},
|
||||
pass: []*v1.Pod{podInProdFrontend},
|
||||
fail: []*v1.Pod{podInStagingBackend, podInTest},
|
||||
},
|
||||
{
|
||||
name: "MatchLabels and MatchExpressions Exists",
|
||||
args: &DefaultEvictorArgs{
|
||||
NamespaceLabelSelector: &metav1.LabelSelector{
|
||||
MatchLabels: map[string]string{"tier": "backend"},
|
||||
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||
{Key: "env", Operator: metav1.LabelSelectorOpExists},
|
||||
},
|
||||
},
|
||||
},
|
||||
pass: []*v1.Pod{podInStagingBackend},
|
||||
fail: []*v1.Pod{podInProdFrontend, podInTest},
|
||||
},
|
||||
{
|
||||
name: "Exists and In",
|
||||
args: &DefaultEvictorArgs{
|
||||
NamespaceLabelSelector: &metav1.LabelSelector{
|
||||
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||
{Key: "tier", Operator: metav1.LabelSelectorOpExists},
|
||||
{Key: "env", Operator: metav1.LabelSelectorOpIn, Values: []string{"staging"}},
|
||||
},
|
||||
},
|
||||
},
|
||||
pass: []*v1.Pod{podInStagingBackend},
|
||||
fail: []*v1.Pod{podInProdFrontend, podInTest},
|
||||
},
|
||||
{
|
||||
name: "DoesNotExist",
|
||||
args: &DefaultEvictorArgs{
|
||||
NamespaceLabelSelector: &metav1.LabelSelector{
|
||||
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||
{Key: "tier", Operator: metav1.LabelSelectorOpDoesNotExist},
|
||||
},
|
||||
},
|
||||
},
|
||||
pass: []*v1.Pod{podInTest, podInNoLabels},
|
||||
fail: []*v1.Pod{podInProdFrontend, podInStagingBackend},
|
||||
},
|
||||
{
|
||||
name: "NotIn",
|
||||
args: &DefaultEvictorArgs{
|
||||
NamespaceLabelSelector: &metav1.LabelSelector{
|
||||
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||
{Key: "env", Operator: metav1.LabelSelectorOpNotIn, Values: []string{"prod", "test"}},
|
||||
},
|
||||
},
|
||||
},
|
||||
pass: []*v1.Pod{podInStagingBackend},
|
||||
fail: []*v1.Pod{podInProdFrontend, podInTest},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
plugin, err := New(ctx, tc.args, &frameworkfake.HandleImpl{
|
||||
ClientsetImpl: fakeClient,
|
||||
GetPodsAssignedToNodeFuncImpl: getPodAssignedToNode,
|
||||
SharedInformerFactoryImpl: sharedInformerFactory,
|
||||
PluginInstanceIDImpl: "test-" + tc.name,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("unable to initialize plugin: %v", err)
|
||||
}
|
||||
|
||||
sharedInformerFactory.Start(ctx.Done())
|
||||
sharedInformerFactory.WaitForCacheSync(ctx.Done())
|
||||
|
||||
evictor := plugin.(*DefaultEvictor)
|
||||
for _, pod := range tc.pass {
|
||||
if result := evictor.PreEvictionFilter(pod); !result {
|
||||
t.Errorf("pod %s expected to pass (true), got false", pod.Name)
|
||||
}
|
||||
}
|
||||
for _, pod := range tc.fail {
|
||||
if result := evictor.PreEvictionFilter(pod); result {
|
||||
t.Errorf("pod %s expected to fail (false), got true", pod.Name)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,13 +103,18 @@ func NewLowNodeUtilization(
|
||||
}
|
||||
|
||||
// this plugins supports different ways of collecting usage data. each
|
||||
// different way provides its own "usageClient". the metrics-based client
|
||||
// is reset at every extension point so we always get the latest prometheus
|
||||
// client (whose SA token can be rotated after plugin creation).
|
||||
// XXX MetricsServer is deprecated, removed once dropped.
|
||||
// different way provides its own "usageClient". here we make sure we
|
||||
// have the correct one or an error is triggered. XXX MetricsServer is
|
||||
// deprecated, removed once dropped.
|
||||
var usageClient usageClient = newRequestedUsageClient(
|
||||
extendedResourceNames, handle.GetPodsAssignedToNodeFunc(),
|
||||
)
|
||||
if metrics != nil {
|
||||
usageClient, err = usageClientForMetrics(args, handle, extendedResourceNames)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return &LowNodeUtilization{
|
||||
logger: logger,
|
||||
@@ -129,33 +134,12 @@ func (l *LowNodeUtilization) Name() string {
|
||||
return LowNodeUtilizationPluginName
|
||||
}
|
||||
|
||||
// resetUsageClient refreshes the usageClient field from the current handle
|
||||
// state. It must be called at the start of every extension point so that a
|
||||
// rotated prometheus SA token is picked up without restarting the process.
|
||||
func (l *LowNodeUtilization) resetUsageClient() error {
|
||||
if l.args.MetricsUtilization == nil {
|
||||
return nil
|
||||
}
|
||||
client, err := usageClientForMetrics(l.args, l.handle, l.extendedResourceNames)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
l.usageClient = client
|
||||
return nil
|
||||
}
|
||||
|
||||
// Balance holds the main logic of the plugin. It evicts pods from over
|
||||
// utilized nodes to under utilized nodes. The goal here is to evenly
|
||||
// distribute pods across nodes.
|
||||
func (l *LowNodeUtilization) Balance(ctx context.Context, nodes []*v1.Node) *frameworktypes.Status {
|
||||
logger := klog.FromContext(klog.NewContext(ctx, l.logger)).WithValues("ExtensionPoint", frameworktypes.BalanceExtensionPoint)
|
||||
|
||||
if err := l.resetUsageClient(); err != nil {
|
||||
return &frameworktypes.Status{
|
||||
Err: fmt.Errorf("error initializing usage client: %v", err),
|
||||
}
|
||||
}
|
||||
|
||||
if err := l.usageClient.sync(ctx, nodes); err != nil {
|
||||
return &frameworktypes.Status{
|
||||
Err: fmt.Errorf("error getting node usage: %v", err),
|
||||
|
||||
@@ -1661,83 +1661,3 @@ func TestLowNodeUtilizationWithPrometheusMetrics(t *testing.T) {
|
||||
t.Run(tc.name, testFnc(false, tc.expectedPodsEvicted))
|
||||
}
|
||||
}
|
||||
|
||||
// TestLowNodeUtilizationPrometheusClientNilAtCreation ensures the plugin
|
||||
// tolerates a nil prometheus client at creation time (e.g. in-cluster SA token
|
||||
// not yet reconciled) and correctly picks up the client exposed by the handle
|
||||
// at Balance call time.
|
||||
func TestLowNodeUtilizationPrometheusClientNilAtCreation(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
n1NodeName := "n1"
|
||||
n2NodeName := "n2"
|
||||
n3NodeName := "n3"
|
||||
|
||||
nodes := []*v1.Node{
|
||||
test.BuildTestNode(n1NodeName, 4000, 3000, 9, nil),
|
||||
test.BuildTestNode(n2NodeName, 4000, 3000, 10, nil),
|
||||
test.BuildTestNode(n3NodeName, 4000, 3000, 10, nil),
|
||||
}
|
||||
pods := []*v1.Pod{
|
||||
test.BuildTestPod("p1", 400, 0, n1NodeName, test.SetRSOwnerRef),
|
||||
test.BuildTestPod("p2", 400, 0, n1NodeName, test.SetRSOwnerRef),
|
||||
test.BuildTestPod("p3", 400, 0, n1NodeName, test.SetRSOwnerRef),
|
||||
test.BuildTestPod("p4", 400, 0, n1NodeName, test.SetRSOwnerRef),
|
||||
test.BuildTestPod("p5", 400, 0, n1NodeName, test.SetRSOwnerRef),
|
||||
test.BuildTestPod("p6", 400, 0, n2NodeName, test.SetRSOwnerRef),
|
||||
}
|
||||
|
||||
var objs []runtime.Object
|
||||
for _, node := range nodes {
|
||||
objs = append(objs, node)
|
||||
}
|
||||
for _, pod := range pods {
|
||||
objs = append(objs, pod)
|
||||
}
|
||||
fakeClient := fake.NewSimpleClientset(objs...)
|
||||
|
||||
handle, podEvictor, err := frameworktesting.InitFrameworkHandle(
|
||||
ctx, fakeClient, nil, defaultevictor.DefaultEvictorArgs{NodeFit: true}, nil,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to initialize a framework handle: %v", err)
|
||||
}
|
||||
|
||||
// PrometheusClientImpl is intentionally nil here — the in-cluster SA token
|
||||
// has not been reconciled yet at plugin-creation time.
|
||||
args := &LowNodeUtilizationArgs{
|
||||
Thresholds: api.ResourceThresholds{MetricResource: 30},
|
||||
TargetThresholds: api.ResourceThresholds{MetricResource: 50},
|
||||
MetricsUtilization: &MetricsUtilization{
|
||||
Source: api.PrometheusMetrics,
|
||||
Prometheus: &Prometheus{
|
||||
Query: "instance:node_cpu:rate:sum",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
plugin, err := NewLowNodeUtilization(ctx, args, handle)
|
||||
if err != nil {
|
||||
t.Fatalf("plugin creation must succeed even when prometheus client is nil: %v", err)
|
||||
}
|
||||
|
||||
// Simulate the SA token becoming available before the first descheduling cycle.
|
||||
handle.PrometheusClientImpl = &fakePromClient{
|
||||
result: model.Vector{
|
||||
sample("instance:node_cpu:rate:sum", n1NodeName, 0.57), // over target
|
||||
sample("instance:node_cpu:rate:sum", n2NodeName, 0.42), // over target
|
||||
sample("instance:node_cpu:rate:sum", n3NodeName, 0.20), // under threshold
|
||||
},
|
||||
dataType: model.ValVector,
|
||||
}
|
||||
|
||||
status := plugin.(frameworktypes.BalancePlugin).Balance(ctx, nodes)
|
||||
if status != nil {
|
||||
t.Fatalf("Balance failed: %v", status.Err)
|
||||
}
|
||||
|
||||
if podEvictor.TotalEvicted() == 0 {
|
||||
t.Error("expected at least one pod to be evicted")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ import (
|
||||
"go.opentelemetry.io/otel/propagation"
|
||||
sdkresource "go.opentelemetry.io/otel/sdk/resource"
|
||||
sdktrace "go.opentelemetry.io/otel/sdk/trace"
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.40.0"
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.39.0"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
"go.opentelemetry.io/otel/trace/noop"
|
||||
"google.golang.org/grpc/credentials"
|
||||
|
||||
@@ -23,7 +23,7 @@ import (
|
||||
utilptr "k8s.io/utils/ptr"
|
||||
|
||||
kvcorev1 "kubevirt.io/api/core/v1"
|
||||
kubevirtclient "kubevirt.io/client-go/kubevirt"
|
||||
generatedclient "kubevirt.io/client-go/generated/kubevirt/clientset/versioned"
|
||||
|
||||
"sigs.k8s.io/descheduler/pkg/api"
|
||||
apiv1alpha2 "sigs.k8s.io/descheduler/pkg/api/v1alpha2"
|
||||
@@ -110,7 +110,7 @@ ethernets:
|
||||
}
|
||||
}
|
||||
|
||||
func waitForKubevirtReady(t *testing.T, ctx context.Context, kvClient kubevirtclient.Interface) {
|
||||
func waitForKubevirtReady(t *testing.T, ctx context.Context, kvClient generatedclient.Interface) {
|
||||
obj, err := kvClient.KubevirtV1().KubeVirts("kubevirt").Get(ctx, "kubevirt", metav1.GetOptions{})
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to get kubevirt/kubevirt: %v", err)
|
||||
@@ -129,7 +129,7 @@ func waitForKubevirtReady(t *testing.T, ctx context.Context, kvClient kubevirtcl
|
||||
klog.Infof("Kubevirt is available")
|
||||
}
|
||||
|
||||
func allVMIsHaveRunningPods(t *testing.T, ctx context.Context, kubeClient clientset.Interface, kvClient kubevirtclient.Interface) (bool, error) {
|
||||
func allVMIsHaveRunningPods(t *testing.T, ctx context.Context, kubeClient clientset.Interface, kvClient generatedclient.Interface) (bool, error) {
|
||||
klog.Infof("Checking all vmi active pods are running")
|
||||
uidMap := make(map[types.UID]*corev1.Pod)
|
||||
podList, err := kubeClient.CoreV1().Pods("default").List(ctx, metav1.ListOptions{})
|
||||
@@ -368,7 +368,7 @@ func updateDeschedulerPolicy(t *testing.T, ctx context.Context, kubeClient clien
|
||||
}
|
||||
}
|
||||
|
||||
func createKubevirtClient() (kubevirtclient.Interface, error) {
|
||||
func createKubevirtClient() (generatedclient.Interface, error) {
|
||||
loadingRules := clientcmd.NewDefaultClientConfigLoadingRules()
|
||||
loadingRules.DefaultClientConfig = &clientcmd.DefaultClientConfig
|
||||
overrides := &clientcmd.ConfigOverrides{}
|
||||
@@ -382,7 +382,7 @@ func createKubevirtClient() (kubevirtclient.Interface, error) {
|
||||
config.APIPath = "/apis"
|
||||
config.ContentType = runtime.ContentTypeJSON
|
||||
|
||||
return kubevirtclient.NewForConfig(config)
|
||||
return generatedclient.NewForConfig(config)
|
||||
}
|
||||
|
||||
func TestLiveMigrationInBackground(t *testing.T) {
|
||||
|
||||
+3
-11
@@ -27,13 +27,7 @@ KIND_VERSION=${KIND_VERSION:-v0.31.0}
|
||||
SKIP_KUBECTL_INSTALL=${SKIP_KUBECTL_INSTALL:-}
|
||||
SKIP_KIND_INSTALL=${SKIP_KIND_INSTALL:-}
|
||||
SKIP_KUBEVIRT_INSTALL=${SKIP_KUBEVIRT_INSTALL:-}
|
||||
# v1.9.0-alpha.0 (or newer) is required for Kubernetes v1.36+, which
|
||||
# enforces stricter CRD numeric format validation
|
||||
# (https://github.com/kubernetes/kubernetes/pull/136582) and rejects the
|
||||
# pre-fix VMI checksum status schema present in v1.8.x. Fixed upstream
|
||||
# by https://github.com/kubevirt/kubevirt/pull/17469 (not backported to
|
||||
# v1.8.x). See https://github.com/kubevirt/kubevirt/issues/17858.
|
||||
KUBEVIRT_VERSION=${KUBEVIRT_VERSION:-v1.9.0-alpha.0}
|
||||
KUBEVIRT_VERSION=${KUBEVIRT_VERSION:-v1.6.2}
|
||||
|
||||
# Build a descheduler image
|
||||
IMAGE_TAG=v$(date +%Y%m%d)-$(git describe --tags)
|
||||
@@ -45,8 +39,7 @@ echo "DESCHEDULER_IMAGE: ${DESCHEDULER_IMAGE}"
|
||||
|
||||
# This just runs e2e tests.
|
||||
if [ -n "$KIND_E2E" ]; then
|
||||
K8S_VERSION=${KUBERNETES_VERSION:-v1.36.1}
|
||||
KIND_NODE_IMAGE=${KIND_NODE_IMAGE:-localhost/kindest/node:${K8S_VERSION}}
|
||||
K8S_VERSION=${KUBERNETES_VERSION:-v1.35.1}
|
||||
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/
|
||||
fi
|
||||
@@ -59,8 +52,7 @@ if [ -n "$KIND_E2E" ]; then
|
||||
|
||||
# If we did not set SKIP_INSTALL
|
||||
if [ -z "$SKIP_INSTALL" ]; then
|
||||
${KIND_SUDO} kind build node-image ${K8S_VERSION} --image ${KIND_NODE_IMAGE}
|
||||
${KIND_SUDO} kind create cluster --image ${KIND_NODE_IMAGE} --config=./hack/kind_config.yaml
|
||||
${KIND_SUDO} kind create cluster --image kindest/node:${K8S_VERSION} --config=./hack/kind_config.yaml
|
||||
fi
|
||||
${CONTAINER_ENGINE} pull registry.k8s.io/pause
|
||||
if [ "${CONTAINER_ENGINE}" == "podman" ]; then
|
||||
|
||||
-36
@@ -1,36 +0,0 @@
|
||||
// Copyright 2025
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//go:build unix
|
||||
|
||||
package daemon
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// SdNotifyMonotonicUsec returns a MONOTONIC_USEC=... assignment for the current time
|
||||
// with a trailing newline included. This is typically used with [SdNotifyReloading].
|
||||
//
|
||||
// If the monotonic clock is not available on the system, the empty string is returned.
|
||||
func SdNotifyMonotonicUsec() string {
|
||||
var ts unix.Timespec
|
||||
if err := unix.ClockGettime(unix.CLOCK_MONOTONIC, &ts); err != nil {
|
||||
// Monotonic clock is not available on this system.
|
||||
return ""
|
||||
}
|
||||
return "MONOTONIC_USEC=" + strconv.FormatInt(ts.Nano()/1000, 10) + "\n"
|
||||
}
|
||||
+3
-4
@@ -15,7 +15,6 @@
|
||||
package daemon
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
@@ -52,10 +51,10 @@ func SdWatchdogEnabled(unsetEnvironment bool) (time.Duration, error) {
|
||||
}
|
||||
s, err := strconv.Atoi(wusec)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("error converting WATCHDOG_USEC: %w", err)
|
||||
return 0, fmt.Errorf("error converting WATCHDOG_USEC: %s", err)
|
||||
}
|
||||
if s <= 0 {
|
||||
return 0, errors.New("error WATCHDOG_USEC must be a positive number")
|
||||
return 0, fmt.Errorf("error WATCHDOG_USEC must be a positive number")
|
||||
}
|
||||
interval := time.Duration(s) * time.Microsecond
|
||||
|
||||
@@ -64,7 +63,7 @@ func SdWatchdogEnabled(unsetEnvironment bool) (time.Duration, error) {
|
||||
}
|
||||
p, err := strconv.Atoi(wpid)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("error converting WATCHDOG_PID: %w", err)
|
||||
return 0, fmt.Errorf("error converting WATCHDOG_PID: %s", err)
|
||||
}
|
||||
if os.Getpid() != p {
|
||||
return 0, nil
|
||||
|
||||
+1
-1
@@ -41,6 +41,6 @@ const (
|
||||
)
|
||||
|
||||
// Print prints a message to the local systemd journal using Send().
|
||||
func Print(priority Priority, format string, a ...any) error {
|
||||
func Print(priority Priority, format string, a ...interface{}) error {
|
||||
return Send(fmt.Sprintf(format, a...), priority, nil)
|
||||
}
|
||||
|
||||
+6
-4
@@ -13,6 +13,7 @@
|
||||
// limitations under the License.
|
||||
|
||||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
// Package journal provides write bindings to the local systemd journal.
|
||||
// It is implemented in pure Go and connects to the journal directly over its
|
||||
@@ -30,6 +31,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"os"
|
||||
"strconv"
|
||||
@@ -106,7 +108,7 @@ func fdIsJournalStream(fd int) (bool, error) {
|
||||
var expectedStat syscall.Stat_t
|
||||
_, err := fmt.Sscanf(journalStream, "%d:%d", &expectedStat.Dev, &expectedStat.Ino)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("failed to parse JOURNAL_STREAM=%q: %w", journalStream, err)
|
||||
return false, fmt.Errorf("failed to parse JOURNAL_STREAM=%q: %v", journalStream, err)
|
||||
}
|
||||
|
||||
var stat syscall.Stat_t
|
||||
@@ -192,7 +194,7 @@ func appendVariable(w io.Writer, name, value string) {
|
||||
* - the data, followed by a newline
|
||||
*/
|
||||
fmt.Fprintln(w, name)
|
||||
_ = binary.Write(w, binary.LittleEndian, uint64(len(value)))
|
||||
binary.Write(w, binary.LittleEndian, uint64(len(value)))
|
||||
fmt.Fprintln(w, value)
|
||||
} else {
|
||||
/* just write the variable and value all on one line */
|
||||
@@ -212,7 +214,7 @@ func validVarName(name string) error {
|
||||
}
|
||||
|
||||
for _, c := range name {
|
||||
if ('A' > c || c > 'Z') && ('0' > c || c > '9') && c != '_' {
|
||||
if !(('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_') {
|
||||
return errors.New("Variable name contains invalid characters")
|
||||
}
|
||||
}
|
||||
@@ -237,7 +239,7 @@ func isSocketSpaceError(err error) bool {
|
||||
|
||||
// tempFd creates a temporary, unlinked file under `/dev/shm`.
|
||||
func tempFd() (*os.File, error) {
|
||||
file, err := os.CreateTemp("/dev/shm/", "journal.XXXXX")
|
||||
file, err := ioutil.TempFile("/dev/shm/", "journal.XXXXX")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.x
|
||||
|
||||
before_install:
|
||||
- go test -v
|
||||
|
||||
script:
|
||||
- go test -race -coverprofile=coverage.txt -covermode=atomic
|
||||
|
||||
after_success:
|
||||
- bash <(curl -s https://codecov.io/bash)
|
||||
-4
@@ -1,9 +1,5 @@
|
||||
# Change history of go-restful
|
||||
|
||||
## [v3.13.0] - 2025-08-14
|
||||
|
||||
- optimize performance of path matching in CurlyRouter ( thanks @wenhuang, Wen Huang)
|
||||
|
||||
## [v3.12.2] - 2025-02-21
|
||||
|
||||
- allow empty payloads in post,put,patch, issue #580 ( thanks @liggitt, Jordan Liggitt)
|
||||
|
||||
-1
@@ -84,7 +84,6 @@ func (u UserResource) findUser(request *restful.Request, response *restful.Respo
|
||||
- Configurable (trace) logging
|
||||
- Customizable gzip/deflate readers and writers using CompressorProvider registration
|
||||
- Inject your own http.Handler using the `HttpMiddlewareHandlerToFilter` function
|
||||
- Added `SetPathTokenCacheEnabled` and `SetCustomVerbCacheEnabled` to disable regexp caching (default=true)
|
||||
|
||||
## How to customize
|
||||
There are several hooks to customize the behavior of the go-restful package.
|
||||
|
||||
+3
-47
@@ -9,35 +9,11 @@ import (
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// CurlyRouter expects Routes with paths that contain zero or more parameters in curly brackets.
|
||||
type CurlyRouter struct{}
|
||||
|
||||
var (
|
||||
regexCache sync.Map // Cache for compiled regex patterns
|
||||
pathTokenCacheEnabled = true // Enable/disable path token regex caching
|
||||
)
|
||||
|
||||
// SetPathTokenCacheEnabled enables or disables path token regex caching for CurlyRouter.
|
||||
// When disabled, regex patterns will be compiled on every request.
|
||||
// When enabled (default), compiled regex patterns are cached for better performance.
|
||||
func SetPathTokenCacheEnabled(enabled bool) {
|
||||
pathTokenCacheEnabled = enabled
|
||||
}
|
||||
|
||||
// getCachedRegexp retrieves a compiled regex from the cache if found and valid.
|
||||
// Returns the regex and true if found and valid, nil and false otherwise.
|
||||
func getCachedRegexp(cache *sync.Map, pattern string) (*regexp.Regexp, bool) {
|
||||
if cached, found := cache.Load(pattern); found {
|
||||
if regex, ok := cached.(*regexp.Regexp); ok {
|
||||
return regex, true
|
||||
}
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// SelectRoute is part of the Router interface and returns the best match
|
||||
// for the WebService and its Route for the given Request.
|
||||
func (c CurlyRouter) SelectRoute(
|
||||
@@ -137,28 +113,8 @@ func (c CurlyRouter) regularMatchesPathToken(routeToken string, colon int, reque
|
||||
}
|
||||
return true, true
|
||||
}
|
||||
|
||||
// Check cache first (if enabled)
|
||||
if pathTokenCacheEnabled {
|
||||
if regex, found := getCachedRegexp(®exCache, regPart); found {
|
||||
matched := regex.MatchString(requestToken)
|
||||
return matched, false
|
||||
}
|
||||
}
|
||||
|
||||
// Compile the regex
|
||||
regex, err := regexp.Compile(regPart)
|
||||
if err != nil {
|
||||
return false, false
|
||||
}
|
||||
|
||||
// Cache the regex (if enabled)
|
||||
if pathTokenCacheEnabled {
|
||||
regexCache.Store(regPart, regex)
|
||||
}
|
||||
|
||||
matched := regex.MatchString(requestToken)
|
||||
return matched, false
|
||||
matched, err := regexp.MatchString(regPart, requestToken)
|
||||
return (matched && err == nil), false
|
||||
}
|
||||
|
||||
var jsr311Router = RouterJSR311{}
|
||||
@@ -212,7 +168,7 @@ func (c CurlyRouter) computeWebserviceScore(requestTokens []string, routeTokens
|
||||
if matchesToken {
|
||||
score++ // extra score for regex match
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// not a parameter
|
||||
if eachRequestToken != eachRouteToken {
|
||||
|
||||
+2
-32
@@ -1,28 +1,14 @@
|
||||
package restful
|
||||
|
||||
// Copyright 2025 Ernest Micklei. All rights reserved.
|
||||
// Use of this source code is governed by a license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var (
|
||||
customVerbReg = regexp.MustCompile(":([A-Za-z]+)$")
|
||||
customVerbCache sync.Map // Cache for compiled custom verb regexes
|
||||
customVerbCacheEnabled = true // Enable/disable custom verb regex caching
|
||||
customVerbReg = regexp.MustCompile(":([A-Za-z]+)$")
|
||||
)
|
||||
|
||||
// SetCustomVerbCacheEnabled enables or disables custom verb regex caching.
|
||||
// When disabled, custom verb regex patterns will be compiled on every request.
|
||||
// When enabled (default), compiled custom verb regex patterns are cached for better performance.
|
||||
func SetCustomVerbCacheEnabled(enabled bool) {
|
||||
customVerbCacheEnabled = enabled
|
||||
}
|
||||
|
||||
func hasCustomVerb(routeToken string) bool {
|
||||
return customVerbReg.MatchString(routeToken)
|
||||
}
|
||||
@@ -34,23 +20,7 @@ func isMatchCustomVerb(routeToken string, pathToken string) bool {
|
||||
}
|
||||
|
||||
customVerb := rs[1]
|
||||
regexPattern := fmt.Sprintf(":%s$", customVerb)
|
||||
|
||||
// Check cache first (if enabled)
|
||||
if customVerbCacheEnabled {
|
||||
if specificVerbReg, found := getCachedRegexp(&customVerbCache, regexPattern); found {
|
||||
return specificVerbReg.MatchString(pathToken)
|
||||
}
|
||||
}
|
||||
|
||||
// Compile the regex
|
||||
specificVerbReg := regexp.MustCompile(regexPattern)
|
||||
|
||||
// Cache the regex (if enabled)
|
||||
if customVerbCacheEnabled {
|
||||
customVerbCache.Store(regexPattern, specificVerbReg)
|
||||
}
|
||||
|
||||
specificVerbReg := regexp.MustCompile(fmt.Sprintf(":%s$", customVerb))
|
||||
return specificVerbReg.MatchString(pathToken)
|
||||
}
|
||||
|
||||
|
||||
+23
-19
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
Package restful , a lean package for creating REST-style WebServices without magic.
|
||||
|
||||
### WebServices and Routes
|
||||
WebServices and Routes
|
||||
|
||||
A WebService has a collection of Route objects that dispatch incoming Http Requests to a function calls.
|
||||
Typically, a WebService has a root path (e.g. /users) and defines common MIME types for its routes.
|
||||
@@ -30,14 +30,14 @@ The (*Request, *Response) arguments provide functions for reading information fr
|
||||
|
||||
See the example https://github.com/emicklei/go-restful/blob/v3/examples/user-resource/restful-user-resource.go with a full implementation.
|
||||
|
||||
### Regular expression matching Routes
|
||||
Regular expression matching Routes
|
||||
|
||||
A Route parameter can be specified using the format "uri/{var[:regexp]}" or the special version "uri/{var:*}" for matching the tail of the path.
|
||||
For example, /persons/{name:[A-Z][A-Z]} can be used to restrict values for the parameter "name" to only contain capital alphabetic characters.
|
||||
Regular expressions must use the standard Go syntax as described in the regexp package. (https://code.google.com/p/re2/wiki/Syntax)
|
||||
This feature requires the use of a CurlyRouter.
|
||||
|
||||
### Containers
|
||||
Containers
|
||||
|
||||
A Container holds a collection of WebServices, Filters and a http.ServeMux for multiplexing http requests.
|
||||
Using the statements "restful.Add(...) and restful.Filter(...)" will register WebServices and Filters to the Default Container.
|
||||
@@ -47,7 +47,7 @@ You can create your own Container and create a new http.Server for that particul
|
||||
container := restful.NewContainer()
|
||||
server := &http.Server{Addr: ":8081", Handler: container}
|
||||
|
||||
### Filters
|
||||
Filters
|
||||
|
||||
A filter dynamically intercepts requests and responses to transform or use the information contained in the requests or responses.
|
||||
You can use filters to perform generic logging, measurement, authentication, redirect, set response headers etc.
|
||||
@@ -60,21 +60,22 @@ Use the following statement to pass the request,response pair to the next filter
|
||||
|
||||
chain.ProcessFilter(req, resp)
|
||||
|
||||
### Container Filters
|
||||
Container Filters
|
||||
|
||||
These are processed before any registered WebService.
|
||||
|
||||
// install a (global) filter for the default container (processed before any webservice)
|
||||
restful.Filter(globalLogging)
|
||||
|
||||
### WebService Filters
|
||||
WebService Filters
|
||||
|
||||
These are processed before any Route of a WebService.
|
||||
|
||||
// install a webservice filter (processed before any route)
|
||||
ws.Filter(webserviceLogging).Filter(measureTime)
|
||||
|
||||
### Route Filters
|
||||
|
||||
Route Filters
|
||||
|
||||
These are processed before calling the function associated with the Route.
|
||||
|
||||
@@ -83,7 +84,7 @@ These are processed before calling the function associated with the Route.
|
||||
|
||||
See the example https://github.com/emicklei/go-restful/blob/v3/examples/filters/restful-filters.go with full implementations.
|
||||
|
||||
### Response Encoding
|
||||
Response Encoding
|
||||
|
||||
Two encodings are supported: gzip and deflate. To enable this for all responses:
|
||||
|
||||
@@ -94,20 +95,20 @@ Alternatively, you can create a Filter that performs the encoding and install it
|
||||
|
||||
See the example https://github.com/emicklei/go-restful/blob/v3/examples/encoding/restful-encoding-filter.go
|
||||
|
||||
### OPTIONS support
|
||||
OPTIONS support
|
||||
|
||||
By installing a pre-defined container filter, your Webservice(s) can respond to the OPTIONS Http request.
|
||||
|
||||
Filter(OPTIONSFilter())
|
||||
|
||||
### CORS
|
||||
CORS
|
||||
|
||||
By installing the filter of a CrossOriginResourceSharing (CORS), your WebService(s) can handle CORS requests.
|
||||
|
||||
cors := CrossOriginResourceSharing{ExposeHeaders: []string{"X-My-Header"}, CookiesAllowed: false, Container: DefaultContainer}
|
||||
Filter(cors.Filter)
|
||||
|
||||
### Error Handling
|
||||
Error Handling
|
||||
|
||||
Unexpected things happen. If a request cannot be processed because of a failure, your service needs to tell via the response what happened and why.
|
||||
For this reason HTTP status codes exist and it is important to use the correct code in every exceptional situation.
|
||||
@@ -136,11 +137,11 @@ The request does not have or has an unknown Accept Header set for this operation
|
||||
|
||||
The request does not have or has an unknown Content-Type Header set for this operation.
|
||||
|
||||
### ServiceError
|
||||
ServiceError
|
||||
|
||||
In addition to setting the correct (error) Http status code, you can choose to write a ServiceError message on the response.
|
||||
|
||||
### Performance options
|
||||
Performance options
|
||||
|
||||
This package has several options that affect the performance of your service. It is important to understand them and how you can change it.
|
||||
|
||||
@@ -155,27 +156,30 @@ Default value is true
|
||||
If content encoding is enabled then the default strategy for getting new gzip/zlib writers and readers is to use a sync.Pool.
|
||||
Because writers are expensive structures, performance is even more improved when using a preloaded cache. You can also inject your own implementation.
|
||||
|
||||
### Trouble shooting
|
||||
Trouble shooting
|
||||
|
||||
This package has the means to produce detail logging of the complete Http request matching process and filter invocation.
|
||||
Enabling this feature requires you to set an implementation of restful.StdLogger (e.g. log.Logger) instance such as:
|
||||
|
||||
restful.TraceLogger(log.New(os.Stdout, "[restful] ", log.LstdFlags|log.Lshortfile))
|
||||
|
||||
### Logging
|
||||
Logging
|
||||
|
||||
The restful.SetLogger() method allows you to override the logger used by the package. By default restful
|
||||
uses the standard library `log` package and logs to stdout. Different logging packages are supported as
|
||||
long as they conform to `StdLogger` interface defined in the `log` sub-package, writing an adapter for your
|
||||
preferred package is simple.
|
||||
|
||||
### Resources
|
||||
|
||||
(c) 2012-2025, http://ernestmicklei.com. MIT License
|
||||
Resources
|
||||
|
||||
[project]: https://github.com/emicklei/go-restful
|
||||
|
||||
[examples]: https://github.com/emicklei/go-restful/blob/master/examples
|
||||
[design]: http://ernestmicklei.com/2012/11/11/go-restful-api-design/
|
||||
|
||||
[design]: http://ernestmicklei.com/2012/11/11/go-restful-api-design/
|
||||
|
||||
[showcases]: https://github.com/emicklei/mora, https://github.com/emicklei/landskape
|
||||
|
||||
(c) 2012-2015, http://ernestmicklei.com. MIT License
|
||||
*/
|
||||
package restful
|
||||
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Peter Bourgon
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
+160
@@ -0,0 +1,160 @@
|
||||
# package log
|
||||
|
||||
**Deprecation notice:** The core Go kit log packages (log, log/level, log/term, and
|
||||
log/syslog) have been moved to their own repository at github.com/go-kit/log.
|
||||
The corresponding packages in this directory remain for backwards compatibility.
|
||||
Their types alias the types and their functions call the functions provided by
|
||||
the new repository. Using either import path should be equivalent. Prefer the
|
||||
new import path when practical.
|
||||
|
||||
______
|
||||
|
||||
`package log` provides a minimal interface for structured logging in services.
|
||||
It may be wrapped to encode conventions, enforce type-safety, provide leveled
|
||||
logging, and so on. It can be used for both typical application log events,
|
||||
and log-structured data streams.
|
||||
|
||||
## Structured logging
|
||||
|
||||
Structured logging is, basically, conceding to the reality that logs are
|
||||
_data_, and warrant some level of schematic rigor. Using a stricter,
|
||||
key/value-oriented message format for our logs, containing contextual and
|
||||
semantic information, makes it much easier to get insight into the
|
||||
operational activity of the systems we build. Consequently, `package log` is
|
||||
of the strong belief that "[the benefits of structured logging outweigh the
|
||||
minimal effort involved](https://www.thoughtworks.com/radar/techniques/structured-logging)".
|
||||
|
||||
Migrating from unstructured to structured logging is probably a lot easier
|
||||
than you'd expect.
|
||||
|
||||
```go
|
||||
// Unstructured
|
||||
log.Printf("HTTP server listening on %s", addr)
|
||||
|
||||
// Structured
|
||||
logger.Log("transport", "HTTP", "addr", addr, "msg", "listening")
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Typical application logging
|
||||
|
||||
```go
|
||||
w := log.NewSyncWriter(os.Stderr)
|
||||
logger := log.NewLogfmtLogger(w)
|
||||
logger.Log("question", "what is the meaning of life?", "answer", 42)
|
||||
|
||||
// Output:
|
||||
// question="what is the meaning of life?" answer=42
|
||||
```
|
||||
|
||||
### Contextual Loggers
|
||||
|
||||
```go
|
||||
func main() {
|
||||
var logger log.Logger
|
||||
logger = log.NewLogfmtLogger(log.NewSyncWriter(os.Stderr))
|
||||
logger = log.With(logger, "instance_id", 123)
|
||||
|
||||
logger.Log("msg", "starting")
|
||||
NewWorker(log.With(logger, "component", "worker")).Run()
|
||||
NewSlacker(log.With(logger, "component", "slacker")).Run()
|
||||
}
|
||||
|
||||
// Output:
|
||||
// instance_id=123 msg=starting
|
||||
// instance_id=123 component=worker msg=running
|
||||
// instance_id=123 component=slacker msg=running
|
||||
```
|
||||
|
||||
### Interact with stdlib logger
|
||||
|
||||
Redirect stdlib logger to Go kit logger.
|
||||
|
||||
```go
|
||||
import (
|
||||
"os"
|
||||
stdlog "log"
|
||||
kitlog "github.com/go-kit/kit/log"
|
||||
)
|
||||
|
||||
func main() {
|
||||
logger := kitlog.NewJSONLogger(kitlog.NewSyncWriter(os.Stdout))
|
||||
stdlog.SetOutput(kitlog.NewStdlibAdapter(logger))
|
||||
stdlog.Print("I sure like pie")
|
||||
}
|
||||
|
||||
// Output:
|
||||
// {"msg":"I sure like pie","ts":"2016/01/01 12:34:56"}
|
||||
```
|
||||
|
||||
Or, if, for legacy reasons, you need to pipe all of your logging through the
|
||||
stdlib log package, you can redirect Go kit logger to the stdlib logger.
|
||||
|
||||
```go
|
||||
logger := kitlog.NewLogfmtLogger(kitlog.StdlibWriter{})
|
||||
logger.Log("legacy", true, "msg", "at least it's something")
|
||||
|
||||
// Output:
|
||||
// 2016/01/01 12:34:56 legacy=true msg="at least it's something"
|
||||
```
|
||||
|
||||
### Timestamps and callers
|
||||
|
||||
```go
|
||||
var logger log.Logger
|
||||
logger = log.NewLogfmtLogger(log.NewSyncWriter(os.Stderr))
|
||||
logger = log.With(logger, "ts", log.DefaultTimestampUTC, "caller", log.DefaultCaller)
|
||||
|
||||
logger.Log("msg", "hello")
|
||||
|
||||
// Output:
|
||||
// ts=2016-01-01T12:34:56Z caller=main.go:15 msg=hello
|
||||
```
|
||||
|
||||
## Levels
|
||||
|
||||
Log levels are supported via the [level package](https://godoc.org/github.com/go-kit/kit/log/level).
|
||||
|
||||
## Supported output formats
|
||||
|
||||
- [Logfmt](https://brandur.org/logfmt) ([see also](https://blog.codeship.com/logfmt-a-log-format-thats-easy-to-read-and-write))
|
||||
- JSON
|
||||
|
||||
## Enhancements
|
||||
|
||||
`package log` is centered on the one-method Logger interface.
|
||||
|
||||
```go
|
||||
type Logger interface {
|
||||
Log(keyvals ...interface{}) error
|
||||
}
|
||||
```
|
||||
|
||||
This interface, and its supporting code like is the product of much iteration
|
||||
and evaluation. For more details on the evolution of the Logger interface,
|
||||
see [The Hunt for a Logger Interface](http://go-talks.appspot.com/github.com/ChrisHines/talks/structured-logging/structured-logging.slide#1),
|
||||
a talk by [Chris Hines](https://github.com/ChrisHines).
|
||||
Also, please see
|
||||
[#63](https://github.com/go-kit/kit/issues/63),
|
||||
[#76](https://github.com/go-kit/kit/pull/76),
|
||||
[#131](https://github.com/go-kit/kit/issues/131),
|
||||
[#157](https://github.com/go-kit/kit/pull/157),
|
||||
[#164](https://github.com/go-kit/kit/issues/164), and
|
||||
[#252](https://github.com/go-kit/kit/pull/252)
|
||||
to review historical conversations about package log and the Logger interface.
|
||||
|
||||
Value-add packages and suggestions,
|
||||
like improvements to [the leveled logger](https://godoc.org/github.com/go-kit/kit/log/level),
|
||||
are of course welcome. Good proposals should
|
||||
|
||||
- Be composable with [contextual loggers](https://godoc.org/github.com/go-kit/kit/log#With),
|
||||
- Not break the behavior of [log.Caller](https://godoc.org/github.com/go-kit/kit/log#Caller) in any wrapped contextual loggers, and
|
||||
- Be friendly to packages that accept only an unadorned log.Logger.
|
||||
|
||||
## Benchmarks & comparisons
|
||||
|
||||
There are a few Go logging benchmarks and comparisons that include Go kit's package log.
|
||||
|
||||
- [imkira/go-loggers-bench](https://github.com/imkira/go-loggers-bench) includes kit/log
|
||||
- [uber-common/zap](https://github.com/uber-common/zap), a zero-alloc logging library, includes a comparison with kit/log
|
||||
+118
@@ -0,0 +1,118 @@
|
||||
// Package log provides a structured logger.
|
||||
//
|
||||
// Deprecated: Use github.com/go-kit/log instead.
|
||||
//
|
||||
// Structured logging produces logs easily consumed later by humans or
|
||||
// machines. Humans might be interested in debugging errors, or tracing
|
||||
// specific requests. Machines might be interested in counting interesting
|
||||
// events, or aggregating information for off-line processing. In both cases,
|
||||
// it is important that the log messages are structured and actionable.
|
||||
// Package log is designed to encourage both of these best practices.
|
||||
//
|
||||
// Basic Usage
|
||||
//
|
||||
// The fundamental interface is Logger. Loggers create log events from
|
||||
// key/value data. The Logger interface has a single method, Log, which
|
||||
// accepts a sequence of alternating key/value pairs, which this package names
|
||||
// keyvals.
|
||||
//
|
||||
// type Logger interface {
|
||||
// Log(keyvals ...interface{}) error
|
||||
// }
|
||||
//
|
||||
// Here is an example of a function using a Logger to create log events.
|
||||
//
|
||||
// func RunTask(task Task, logger log.Logger) string {
|
||||
// logger.Log("taskID", task.ID, "event", "starting task")
|
||||
// ...
|
||||
// logger.Log("taskID", task.ID, "event", "task complete")
|
||||
// }
|
||||
//
|
||||
// The keys in the above example are "taskID" and "event". The values are
|
||||
// task.ID, "starting task", and "task complete". Every key is followed
|
||||
// immediately by its value.
|
||||
//
|
||||
// Keys are usually plain strings. Values may be any type that has a sensible
|
||||
// encoding in the chosen log format. With structured logging it is a good
|
||||
// idea to log simple values without formatting them. This practice allows
|
||||
// the chosen logger to encode values in the most appropriate way.
|
||||
//
|
||||
// Contextual Loggers
|
||||
//
|
||||
// A contextual logger stores keyvals that it includes in all log events.
|
||||
// Building appropriate contextual loggers reduces repetition and aids
|
||||
// consistency in the resulting log output. With, WithPrefix, and WithSuffix
|
||||
// add context to a logger. We can use With to improve the RunTask example.
|
||||
//
|
||||
// func RunTask(task Task, logger log.Logger) string {
|
||||
// logger = log.With(logger, "taskID", task.ID)
|
||||
// logger.Log("event", "starting task")
|
||||
// ...
|
||||
// taskHelper(task.Cmd, logger)
|
||||
// ...
|
||||
// logger.Log("event", "task complete")
|
||||
// }
|
||||
//
|
||||
// The improved version emits the same log events as the original for the
|
||||
// first and last calls to Log. Passing the contextual logger to taskHelper
|
||||
// enables each log event created by taskHelper to include the task.ID even
|
||||
// though taskHelper does not have access to that value. Using contextual
|
||||
// loggers this way simplifies producing log output that enables tracing the
|
||||
// life cycle of individual tasks. (See the Contextual example for the full
|
||||
// code of the above snippet.)
|
||||
//
|
||||
// Dynamic Contextual Values
|
||||
//
|
||||
// A Valuer function stored in a contextual logger generates a new value each
|
||||
// time an event is logged. The Valuer example demonstrates how this feature
|
||||
// works.
|
||||
//
|
||||
// Valuers provide the basis for consistently logging timestamps and source
|
||||
// code location. The log package defines several valuers for that purpose.
|
||||
// See Timestamp, DefaultTimestamp, DefaultTimestampUTC, Caller, and
|
||||
// DefaultCaller. A common logger initialization sequence that ensures all log
|
||||
// entries contain a timestamp and source location looks like this:
|
||||
//
|
||||
// logger := log.NewLogfmtLogger(log.NewSyncWriter(os.Stdout))
|
||||
// logger = log.With(logger, "ts", log.DefaultTimestampUTC, "caller", log.DefaultCaller)
|
||||
//
|
||||
// Concurrent Safety
|
||||
//
|
||||
// Applications with multiple goroutines want each log event written to the
|
||||
// same logger to remain separate from other log events. Package log provides
|
||||
// two simple solutions for concurrent safe logging.
|
||||
//
|
||||
// NewSyncWriter wraps an io.Writer and serializes each call to its Write
|
||||
// method. Using a SyncWriter has the benefit that the smallest practical
|
||||
// portion of the logging logic is performed within a mutex, but it requires
|
||||
// the formatting Logger to make only one call to Write per log event.
|
||||
//
|
||||
// NewSyncLogger wraps any Logger and serializes each call to its Log method.
|
||||
// Using a SyncLogger has the benefit that it guarantees each log event is
|
||||
// handled atomically within the wrapped logger, but it typically serializes
|
||||
// both the formatting and output logic. Use a SyncLogger if the formatting
|
||||
// logger may perform multiple writes per log event.
|
||||
//
|
||||
// Error Handling
|
||||
//
|
||||
// This package relies on the practice of wrapping or decorating loggers with
|
||||
// other loggers to provide composable pieces of functionality. It also means
|
||||
// that Logger.Log must return an error because some
|
||||
// implementations—especially those that output log data to an io.Writer—may
|
||||
// encounter errors that cannot be handled locally. This in turn means that
|
||||
// Loggers that wrap other loggers should return errors from the wrapped
|
||||
// logger up the stack.
|
||||
//
|
||||
// Fortunately, the decorator pattern also provides a way to avoid the
|
||||
// necessity to check for errors every time an application calls Logger.Log.
|
||||
// An application required to panic whenever its Logger encounters
|
||||
// an error could initialize its logger as follows.
|
||||
//
|
||||
// fmtlogger := log.NewLogfmtLogger(log.NewSyncWriter(os.Stdout))
|
||||
// logger := log.LoggerFunc(func(keyvals ...interface{}) error {
|
||||
// if err := fmtlogger.Log(keyvals...); err != nil {
|
||||
// panic(err)
|
||||
// }
|
||||
// return nil
|
||||
// })
|
||||
package log
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package log
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/go-kit/log"
|
||||
)
|
||||
|
||||
// NewJSONLogger returns a Logger that encodes keyvals to the Writer as a
|
||||
// single JSON object. Each log event produces no more than one call to
|
||||
// w.Write. The passed Writer must be safe for concurrent use by multiple
|
||||
// goroutines if the returned Logger will be used concurrently.
|
||||
func NewJSONLogger(w io.Writer) Logger {
|
||||
return log.NewJSONLogger(w)
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
package log
|
||||
|
||||
import (
|
||||
"github.com/go-kit/log"
|
||||
)
|
||||
|
||||
// Logger is the fundamental interface for all log operations. Log creates a
|
||||
// log event from keyvals, a variadic sequence of alternating keys and values.
|
||||
// Implementations must be safe for concurrent use by multiple goroutines. In
|
||||
// particular, any implementation of Logger that appends to keyvals or
|
||||
// modifies or retains any of its elements must make a copy first.
|
||||
type Logger = log.Logger
|
||||
|
||||
// ErrMissingValue is appended to keyvals slices with odd length to substitute
|
||||
// the missing value.
|
||||
var ErrMissingValue = log.ErrMissingValue
|
||||
|
||||
// With returns a new contextual logger with keyvals prepended to those passed
|
||||
// to calls to Log. If logger is also a contextual logger created by With,
|
||||
// WithPrefix, or WithSuffix, keyvals is appended to the existing context.
|
||||
//
|
||||
// The returned Logger replaces all value elements (odd indexes) containing a
|
||||
// Valuer with their generated value for each call to its Log method.
|
||||
func With(logger Logger, keyvals ...interface{}) Logger {
|
||||
return log.With(logger, keyvals...)
|
||||
}
|
||||
|
||||
// WithPrefix returns a new contextual logger with keyvals prepended to those
|
||||
// passed to calls to Log. If logger is also a contextual logger created by
|
||||
// With, WithPrefix, or WithSuffix, keyvals is prepended to the existing context.
|
||||
//
|
||||
// The returned Logger replaces all value elements (odd indexes) containing a
|
||||
// Valuer with their generated value for each call to its Log method.
|
||||
func WithPrefix(logger Logger, keyvals ...interface{}) Logger {
|
||||
return log.WithPrefix(logger, keyvals...)
|
||||
}
|
||||
|
||||
// WithSuffix returns a new contextual logger with keyvals appended to those
|
||||
// passed to calls to Log. If logger is also a contextual logger created by
|
||||
// With, WithPrefix, or WithSuffix, keyvals is appended to the existing context.
|
||||
//
|
||||
// The returned Logger replaces all value elements (odd indexes) containing a
|
||||
// Valuer with their generated value for each call to its Log method.
|
||||
func WithSuffix(logger Logger, keyvals ...interface{}) Logger {
|
||||
return log.WithSuffix(logger, keyvals...)
|
||||
}
|
||||
|
||||
// LoggerFunc is an adapter to allow use of ordinary functions as Loggers. If
|
||||
// f is a function with the appropriate signature, LoggerFunc(f) is a Logger
|
||||
// object that calls f.
|
||||
type LoggerFunc = log.LoggerFunc
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package log
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/go-kit/log"
|
||||
)
|
||||
|
||||
// NewLogfmtLogger returns a logger that encodes keyvals to the Writer in
|
||||
// logfmt format. Each log event produces no more than one call to w.Write.
|
||||
// The passed Writer must be safe for concurrent use by multiple goroutines if
|
||||
// the returned Logger will be used concurrently.
|
||||
func NewLogfmtLogger(w io.Writer) Logger {
|
||||
return log.NewLogfmtLogger(w)
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
package log
|
||||
|
||||
import "github.com/go-kit/log"
|
||||
|
||||
// NewNopLogger returns a logger that doesn't do anything.
|
||||
func NewNopLogger() Logger {
|
||||
return log.NewNopLogger()
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
package log
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/go-kit/log"
|
||||
)
|
||||
|
||||
// StdlibWriter implements io.Writer by invoking the stdlib log.Print. It's
|
||||
// designed to be passed to a Go kit logger as the writer, for cases where
|
||||
// it's necessary to redirect all Go kit log output to the stdlib logger.
|
||||
//
|
||||
// If you have any choice in the matter, you shouldn't use this. Prefer to
|
||||
// redirect the stdlib log to the Go kit logger via NewStdlibAdapter.
|
||||
type StdlibWriter = log.StdlibWriter
|
||||
|
||||
// StdlibAdapter wraps a Logger and allows it to be passed to the stdlib
|
||||
// logger's SetOutput. It will extract date/timestamps, filenames, and
|
||||
// messages, and place them under relevant keys.
|
||||
type StdlibAdapter = log.StdlibAdapter
|
||||
|
||||
// StdlibAdapterOption sets a parameter for the StdlibAdapter.
|
||||
type StdlibAdapterOption = log.StdlibAdapterOption
|
||||
|
||||
// TimestampKey sets the key for the timestamp field. By default, it's "ts".
|
||||
func TimestampKey(key string) StdlibAdapterOption {
|
||||
return log.TimestampKey(key)
|
||||
}
|
||||
|
||||
// FileKey sets the key for the file and line field. By default, it's "caller".
|
||||
func FileKey(key string) StdlibAdapterOption {
|
||||
return log.FileKey(key)
|
||||
}
|
||||
|
||||
// MessageKey sets the key for the actual log message. By default, it's "msg".
|
||||
func MessageKey(key string) StdlibAdapterOption {
|
||||
return log.MessageKey(key)
|
||||
}
|
||||
|
||||
// Prefix configures the adapter to parse a prefix from stdlib log events. If
|
||||
// you provide a non-empty prefix to the stdlib logger, then your should provide
|
||||
// that same prefix to the adapter via this option.
|
||||
//
|
||||
// By default, the prefix isn't included in the msg key. Set joinPrefixToMsg to
|
||||
// true if you want to include the parsed prefix in the msg.
|
||||
func Prefix(prefix string, joinPrefixToMsg bool) StdlibAdapterOption {
|
||||
return log.Prefix(prefix, joinPrefixToMsg)
|
||||
}
|
||||
|
||||
// NewStdlibAdapter returns a new StdlibAdapter wrapper around the passed
|
||||
// logger. It's designed to be passed to log.SetOutput.
|
||||
func NewStdlibAdapter(logger Logger, options ...StdlibAdapterOption) io.Writer {
|
||||
return log.NewStdlibAdapter(logger, options...)
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
package log
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/go-kit/log"
|
||||
)
|
||||
|
||||
// SwapLogger wraps another logger that may be safely replaced while other
|
||||
// goroutines use the SwapLogger concurrently. The zero value for a SwapLogger
|
||||
// will discard all log events without error.
|
||||
//
|
||||
// SwapLogger serves well as a package global logger that can be changed by
|
||||
// importers.
|
||||
type SwapLogger = log.SwapLogger
|
||||
|
||||
// NewSyncWriter returns a new writer that is safe for concurrent use by
|
||||
// multiple goroutines. Writes to the returned writer are passed on to w. If
|
||||
// another write is already in progress, the calling goroutine blocks until
|
||||
// the writer is available.
|
||||
//
|
||||
// If w implements the following interface, so does the returned writer.
|
||||
//
|
||||
// interface {
|
||||
// Fd() uintptr
|
||||
// }
|
||||
func NewSyncWriter(w io.Writer) io.Writer {
|
||||
return log.NewSyncWriter(w)
|
||||
}
|
||||
|
||||
// NewSyncLogger returns a logger that synchronizes concurrent use of the
|
||||
// wrapped logger. When multiple goroutines use the SyncLogger concurrently
|
||||
// only one goroutine will be allowed to log to the wrapped logger at a time.
|
||||
// The other goroutines will block until the logger is available.
|
||||
func NewSyncLogger(logger Logger) Logger {
|
||||
return log.NewSyncLogger(logger)
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
package log
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/go-kit/log"
|
||||
)
|
||||
|
||||
// A Valuer generates a log value. When passed to With, WithPrefix, or
|
||||
// WithSuffix in a value element (odd indexes), it represents a dynamic
|
||||
// value which is re-evaluated with each log event.
|
||||
type Valuer = log.Valuer
|
||||
|
||||
// Timestamp returns a timestamp Valuer. It invokes the t function to get the
|
||||
// time; unless you are doing something tricky, pass time.Now.
|
||||
//
|
||||
// Most users will want to use DefaultTimestamp or DefaultTimestampUTC, which
|
||||
// are TimestampFormats that use the RFC3339Nano format.
|
||||
func Timestamp(t func() time.Time) Valuer {
|
||||
return log.Timestamp(t)
|
||||
}
|
||||
|
||||
// TimestampFormat returns a timestamp Valuer with a custom time format. It
|
||||
// invokes the t function to get the time to format; unless you are doing
|
||||
// something tricky, pass time.Now. The layout string is passed to
|
||||
// Time.Format.
|
||||
//
|
||||
// Most users will want to use DefaultTimestamp or DefaultTimestampUTC, which
|
||||
// are TimestampFormats that use the RFC3339Nano format.
|
||||
func TimestampFormat(t func() time.Time, layout string) Valuer {
|
||||
return log.TimestampFormat(t, layout)
|
||||
}
|
||||
|
||||
// Caller returns a Valuer that returns a file and line from a specified depth
|
||||
// in the callstack. Users will probably want to use DefaultCaller.
|
||||
func Caller(depth int) Valuer {
|
||||
return log.Caller(depth)
|
||||
}
|
||||
|
||||
var (
|
||||
// DefaultTimestamp is a Valuer that returns the current wallclock time,
|
||||
// respecting time zones, when bound.
|
||||
DefaultTimestamp = log.DefaultTimestamp
|
||||
|
||||
// DefaultTimestampUTC is a Valuer that returns the current time in UTC
|
||||
// when bound.
|
||||
DefaultTimestampUTC = log.DefaultTimestampUTC
|
||||
|
||||
// DefaultCaller is a Valuer that returns the file and line where the Log
|
||||
// method was invoked. It can only be used with log.With.
|
||||
DefaultCaller = log.DefaultCaller
|
||||
)
|
||||
-4
@@ -1,4 +0,0 @@
|
||||
ignore:
|
||||
- jsonutils/fixtures_test
|
||||
- jsonutils/adapters/ifaces/mocks
|
||||
- jsonutils/adapters/testintegration/benchmarks
|
||||
+54
-72
@@ -1,78 +1,60 @@
|
||||
version: "2"
|
||||
linters-settings:
|
||||
govet:
|
||||
check-shadowing: true
|
||||
golint:
|
||||
min-confidence: 0
|
||||
gocyclo:
|
||||
min-complexity: 45
|
||||
maligned:
|
||||
suggest-new: true
|
||||
dupl:
|
||||
threshold: 200
|
||||
goconst:
|
||||
min-len: 3
|
||||
min-occurrences: 3
|
||||
|
||||
linters:
|
||||
default: all
|
||||
enable-all: true
|
||||
disable:
|
||||
- cyclop
|
||||
- maligned
|
||||
- lll
|
||||
- gochecknoinits
|
||||
- gochecknoglobals
|
||||
- funlen
|
||||
- godox
|
||||
- gocognit
|
||||
- whitespace
|
||||
- wsl
|
||||
- wrapcheck
|
||||
- testpackage
|
||||
- nlreturn
|
||||
- gomnd
|
||||
- exhaustivestruct
|
||||
- goerr113
|
||||
- errorlint
|
||||
- nestif
|
||||
- godot
|
||||
- gofumpt
|
||||
- paralleltest
|
||||
- tparallel
|
||||
- thelper
|
||||
- ifshort
|
||||
- exhaustruct
|
||||
- varnamelen
|
||||
- gci
|
||||
- depguard
|
||||
- errchkjson
|
||||
- errorlint
|
||||
- exhaustruct
|
||||
- forcetypeassert
|
||||
- funlen
|
||||
- gochecknoglobals
|
||||
- gochecknoinits
|
||||
- gocognit
|
||||
- godot
|
||||
- godox
|
||||
- gomoddirectives
|
||||
- gosmopolitan
|
||||
- inamedparam
|
||||
- intrange
|
||||
- ireturn
|
||||
- lll
|
||||
- musttag
|
||||
- modernize
|
||||
- nestif
|
||||
- nlreturn
|
||||
- nonamedreturns
|
||||
- noinlineerr
|
||||
- paralleltest
|
||||
- recvcheck
|
||||
- testpackage
|
||||
- thelper
|
||||
- tagliatelle
|
||||
- tparallel
|
||||
- unparam
|
||||
- varnamelen
|
||||
- whitespace
|
||||
- wrapcheck
|
||||
- wsl
|
||||
- wsl_v5
|
||||
settings:
|
||||
dupl:
|
||||
threshold: 200
|
||||
goconst:
|
||||
min-len: 2
|
||||
min-occurrences: 3
|
||||
gocyclo:
|
||||
min-complexity: 45
|
||||
exclusions:
|
||||
generated: lax
|
||||
presets:
|
||||
- comments
|
||||
- common-false-positives
|
||||
- legacy
|
||||
- std-error-handling
|
||||
paths:
|
||||
- third_party$
|
||||
- builtin$
|
||||
- examples$
|
||||
formatters:
|
||||
enable:
|
||||
- gofmt
|
||||
- goimports
|
||||
exclusions:
|
||||
generated: lax
|
||||
paths:
|
||||
- third_party$
|
||||
- builtin$
|
||||
- examples$
|
||||
issues:
|
||||
# Maximum issues count per one linter.
|
||||
# Set to 0 to disable.
|
||||
# Default: 50
|
||||
max-issues-per-linter: 0
|
||||
# Maximum count of issues with the same text.
|
||||
# Set to 0 to disable.
|
||||
# Default: 3
|
||||
max-same-issues: 0
|
||||
- musttag
|
||||
- ireturn
|
||||
- forcetypeassert
|
||||
- cyclop
|
||||
# deprecated linters
|
||||
- deadcode
|
||||
- interfacer
|
||||
- scopelint
|
||||
- varcheck
|
||||
- structcheck
|
||||
- golint
|
||||
- nosnakecase
|
||||
|
||||
-30
@@ -1,30 +0,0 @@
|
||||
all: false
|
||||
dir: '{{.InterfaceDir}}'
|
||||
filename: mocks_test.go
|
||||
force-file-write: true
|
||||
formatter: goimports
|
||||
include-auto-generated: false
|
||||
log-level: info
|
||||
structname: '{{.Mock}}{{.InterfaceName}}'
|
||||
pkgname: '{{.SrcPackageName}}'
|
||||
recursive: false
|
||||
require-template-schema-exists: true
|
||||
template: matryer
|
||||
template-schema: '{{.Template}}.schema.json'
|
||||
packages:
|
||||
github.com/go-openapi/swag/jsonutils/adapters/ifaces:
|
||||
config:
|
||||
dir: jsonutils/adapters/ifaces/mocks
|
||||
filename: mocks.go
|
||||
pkgname: 'mocks'
|
||||
force-file-write: true
|
||||
all: true
|
||||
github.com/go-openapi/swag/jsonutils/adapters/testintegration:
|
||||
config:
|
||||
inpackage: true
|
||||
dir: jsonutils/adapters/testintegration
|
||||
force-file-write: true
|
||||
all: true
|
||||
interfaces:
|
||||
EJMarshaler:
|
||||
EJUnmarshaler:
|
||||
Generated
Vendored
+5
-43
@@ -1,10 +1,12 @@
|
||||
# Benchmarking name mangling utilities
|
||||
# Benchmarks
|
||||
|
||||
## Name mangling utilities
|
||||
|
||||
```bash
|
||||
go test -bench XXX -run XXX -benchtime 30s
|
||||
```
|
||||
|
||||
## Benchmarks at b3e7a5386f996177e4808f11acb2aa93a0f660df
|
||||
### Benchmarks at b3e7a5386f996177e4808f11acb2aa93a0f660df
|
||||
|
||||
```
|
||||
goos: linux
|
||||
@@ -19,7 +21,7 @@ BenchmarkToXXXName/ToHumanNameLower-4 895334 40354 ns/op 10472 B/op
|
||||
BenchmarkToXXXName/ToHumanNameTitle-4 882441 40678 ns/op 10566 B/op 749 allocs/op
|
||||
```
|
||||
|
||||
## Benchmarks after PR #79
|
||||
### Benchmarks after PR #79
|
||||
|
||||
~ x10 performance improvement and ~ /100 memory allocations.
|
||||
|
||||
@@ -48,43 +50,3 @@ BenchmarkToXXXName/ToCommandName-16 32256634 1137 ns/op 147 B/op
|
||||
BenchmarkToXXXName/ToHumanNameLower-16 18599661 1946 ns/op 92 B/op 6 allocs/op
|
||||
BenchmarkToXXXName/ToHumanNameTitle-16 17581353 2054 ns/op 105 B/op 6 allocs/op
|
||||
```
|
||||
|
||||
## Benchmarks at d7d2d1b895f5b6747afaff312dd2a402e69e818b
|
||||
|
||||
go1.24
|
||||
|
||||
```
|
||||
goos: linux
|
||||
goarch: amd64
|
||||
pkg: github.com/go-openapi/swag
|
||||
cpu: AMD Ryzen 7 5800X 8-Core Processor
|
||||
BenchmarkToXXXName/ToGoName-16 19757858 1881 ns/op 42 B/op 5 allocs/op
|
||||
BenchmarkToXXXName/ToVarName-16 17494111 2094 ns/op 74 B/op 7 allocs/op
|
||||
BenchmarkToXXXName/ToFileName-16 28161226 1492 ns/op 158 B/op 7 allocs/op
|
||||
BenchmarkToXXXName/ToCommandName-16 23787333 1489 ns/op 158 B/op 7 allocs/op
|
||||
BenchmarkToXXXName/ToHumanNameLower-16 17537257 2030 ns/op 103 B/op 6 allocs/op
|
||||
BenchmarkToXXXName/ToHumanNameTitle-16 16977453 2156 ns/op 105 B/op 6 allocs/op
|
||||
```
|
||||
|
||||
## Benchmarks after PR #106
|
||||
|
||||
Moving the scope of everything down to a struct allowed to reduce a bit garbage and pooling.
|
||||
|
||||
On top of that, ToGoName (and thus ToVarName) have been subject to a minor optimization, removing a few allocations.
|
||||
|
||||
Overall timings improve by ~ -10%.
|
||||
|
||||
go1.24
|
||||
|
||||
```
|
||||
goos: linux
|
||||
goarch: amd64
|
||||
pkg: github.com/go-openapi/swag/mangling
|
||||
cpu: AMD Ryzen 7 5800X 8-Core Processor
|
||||
BenchmarkToXXXName/ToGoName-16 22496130 1618 ns/op 31 B/op 3 allocs/op
|
||||
BenchmarkToXXXName/ToVarName-16 22538068 1618 ns/op 33 B/op 3 allocs/op
|
||||
BenchmarkToXXXName/ToFileName-16 27722977 1236 ns/op 105 B/op 6 allocs/op
|
||||
BenchmarkToXXXName/ToCommandName-16 27967395 1258 ns/op 105 B/op 6 allocs/op
|
||||
BenchmarkToXXXName/ToHumanNameLower-16 18587901 1917 ns/op 103 B/op 6 allocs/op
|
||||
BenchmarkToXXXName/ToHumanNameTitle-16 17193208 2019 ns/op 108 B/op 7 allocs/op
|
||||
```
|
||||
+11
-227
@@ -1,239 +1,23 @@
|
||||
# Swag [](https://github.com/go-openapi/swag/actions?query=workflow%3A"go+test") [](https://codecov.io/gh/go-openapi/swag)
|
||||
|
||||
[](https://slackin.goswagger.io)
|
||||
[](https://raw.githubusercontent.com/go-openapi/swag/master/LICENSE)
|
||||
[](https://raw.githubusercontent.com/go-openapi/swag/master/LICENSE)
|
||||
[](https://pkg.go.dev/github.com/go-openapi/swag)
|
||||
[](https://goreportcard.com/report/github.com/go-openapi/swag)
|
||||
|
||||
Package `swag` contains a bunch of helper functions for go-openapi and go-swagger projects.
|
||||
Contains a bunch of helper functions for go-openapi and go-swagger projects.
|
||||
|
||||
You may also use it standalone for your projects.
|
||||
|
||||
> **NOTE**
|
||||
> `swag` is one of the foundational building blocks of the go-openapi initiative.
|
||||
> Most repositories in `github.com/go-openapi/...` depend on it in some way.
|
||||
> And so does our CLI tool `github.com/go-swagger/go-swagger`,
|
||||
> as well as the code generated by this tool.
|
||||
|
||||
* [Contents](#contents)
|
||||
* [Dependencies](#dependencies)
|
||||
* [Release Notes](#release-notes)
|
||||
* [Licensing](#licensing)
|
||||
* [Note to contributors](#note-to-contributors)
|
||||
* [TODOs, suggestions and plans](#todos-suggestions-and-plans)
|
||||
|
||||
## Contents
|
||||
|
||||
`go-openapi/swag` exposes a collection of relatively independent modules.
|
||||
|
||||
Moving forward, no additional feature will be added to the `swag` API directly at the root package level,
|
||||
which remains there for backward-compatibility purposes. All exported top-level features are now deprecated.
|
||||
|
||||
Child modules will continue to evolve and some new ones may be added in the future.
|
||||
|
||||
| Module | Content | Main features |
|
||||
|---------------|---------|---------------|
|
||||
| `cmdutils` | utilities to work with CLIs ||
|
||||
| `conv` | type conversion utilities | convert between values and pointers for any types<br />convert from string to builtin types (wraps `strconv`)<br />require `./typeutils` (test dependency)<br /> |
|
||||
| `fileutils` | file utilities | |
|
||||
| `jsonname` | JSON utilities | infer JSON names from `go` properties<br /> |
|
||||
| `jsonutils` | JSON utilities | fast json concatenation<br />read and write JSON from and to dynamic `go` data structures<br />~require `github.com/mailru/easyjson`~<br /> |
|
||||
| `loading` | file loading | load from file or http<br />require `./yamlutils`<br /> |
|
||||
| `mangling` | safe name generation | name mangling for `go`<br /> |
|
||||
| `netutils` | networking utilities | host, port from address<br /> |
|
||||
| `stringutils` | `string` utilities | search in slice (with case-insensitive)<br />split/join query parameters as arrays<br /> |
|
||||
| `typeutils` | `go` types utilities | check the zero value for any type<br />safe check for a nil value<br /> |
|
||||
| `yamlutils` | YAML utilities | converting YAML to JSON<br />loading YAML into a dynamic YAML document<br />maintaining the original order of keys in YAML objects<br />require `./jsonutils`<br />~require `github.com/mailru/easyjson`~<br />require `go.yaml.in/yaml/v3`<br /> |
|
||||
|
||||
---
|
||||
|
||||
## Dependencies
|
||||
|
||||
The root module `github.com/go-openapi/swag` at the repo level maintains a few
|
||||
dependencies outside of the standard library.
|
||||
|
||||
* YAML utilities depend on `go.yaml.in/yaml/v3`
|
||||
* JSON utilities depend on their registered adapter module:
|
||||
* by default, only the standard library is used
|
||||
* `github.com/mailru/easyjson` is now only a dependency for module
|
||||
`github.com/go-openapi/swag/jsonutils/adapters/easyjson/json`,
|
||||
for users willing to import that module.
|
||||
* integration tests and benchmarks use all the dependencies are published as their own module
|
||||
* other dependencies are test dependencies drawn from `github.com/stretchr/testify`
|
||||
|
||||
## Release notes
|
||||
|
||||
### v0.25.4
|
||||
|
||||
** mangling**
|
||||
|
||||
Bug fix
|
||||
|
||||
* [x] mangler may panic with pluralized overlapping initialisms
|
||||
|
||||
Tests
|
||||
|
||||
* [x] introduced fuzz tests
|
||||
|
||||
### v0.25.3
|
||||
|
||||
** mangling**
|
||||
|
||||
Bug fix
|
||||
|
||||
* [x] mangler may panic with pluralized initialisms
|
||||
|
||||
### v0.25.2
|
||||
|
||||
Minor changes due to internal maintenance that don't affect the behavior of the library.
|
||||
|
||||
* [x] removed indirect test dependencies by switching all tests to `go-openapi/testify`,
|
||||
a fork of `stretch/testify` with zero-dependencies.
|
||||
* [x] improvements to CI to catch test reports.
|
||||
* [x] modernized licensing annotations in source code, using the more compact SPDX annotations
|
||||
rather than the full license terms.
|
||||
* [x] simplified a bit JSON & YAML testing by using newly available assertions
|
||||
* started the journey to an OpenSSF score card badge:
|
||||
* [x] explicited permissions in CI workflows
|
||||
* [x] published security policy
|
||||
* pinned dependencies to github actions
|
||||
* introduced fuzzing in tests
|
||||
|
||||
### v0.25.1
|
||||
|
||||
* fixes a data race that could occur when using the standard library implementation of a JSON ordered map
|
||||
|
||||
### v0.25.0
|
||||
|
||||
**New with this release**:
|
||||
|
||||
* requires `go1.24`, as iterators are being introduced
|
||||
* removes the dependency to `mailru/easyjson` by default (#68)
|
||||
* functionality remains the same, but performance may somewhat degrade for applications
|
||||
that relied on `easyjson`
|
||||
* users of the JSON or YAML utilities who want to use `easyjson` as their preferred JSON serializer library
|
||||
will be able to do so by registering this the corresponding JSON adapter at runtime. See below.
|
||||
* ordered keys in JSON and YAML objects: this feature used to rely solely on `easyjson`.
|
||||
With this release, an implementation relying on the standard `encoding/json` is provided.
|
||||
* an independent [benchmark](./jsonutils/adapters/testintegration/benchmarks/README.md) to compare the different adapters
|
||||
* improves the "float is integer" check (`conv.IsFloat64AJSONInteger`) (#59)
|
||||
* removes the _direct_ dependency to `gopkg.in/yaml.v3` (indirect dependency is still incurred through `stretchr/testify`) (#127)
|
||||
* exposed `conv.IsNil()` (previously kept private): a safe nil check (accounting for the "non-nil interface with nil value" nonsensical go trick)
|
||||
|
||||
**What coming next?**
|
||||
|
||||
Moving forward, we want to :
|
||||
* provide an implementation of the JSON adapter based on `encoding/json/v2`, for `go1.25` builds.
|
||||
* provide similar implementations for `goccy/go-json` and `jsoniterator/go`, and perhaps some other
|
||||
similar libraries may be interesting too.
|
||||
* convert between value and pointers for builtin types
|
||||
* convert from string to builtin types (wraps strconv)
|
||||
* fast json concatenation
|
||||
* search in path
|
||||
* load from file or http
|
||||
* name mangling
|
||||
|
||||
|
||||
**How to explicitly register a dependency at runtime**?
|
||||
This repo has only few dependencies outside of the standard library:
|
||||
|
||||
The following would maintain how JSON utilities proposed by `swag` used work, up to `v0.24.1`.
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/go-openapi/swag/jsonutils/adapters"
|
||||
easyjson "github.com/go-openapi/swag/jsonutils/adapters/easyjson/json"
|
||||
)
|
||||
|
||||
func init() {
|
||||
easyjson.Register(adapters.Registry)
|
||||
}
|
||||
```
|
||||
|
||||
Subsequent calls to `jsonutils.ReadJSON()` or `jsonutils.WriteJSON()` will switch to `easyjson`
|
||||
whenever the passed data structures implement the `easyjson.Unmarshaler` or `easyjson.Marshaler` respectively,
|
||||
or fallback to the standard library.
|
||||
|
||||
For more details, you may also look at our
|
||||
[integration tests](jsonutils/adapters/testintegration/integration_suite_test.go#29).
|
||||
|
||||
### v0.24.0
|
||||
|
||||
With this release, we have largely modernized the API of `swag`:
|
||||
|
||||
* The traditional `swag` API is still supported: code that imports `swag` will still
|
||||
compile and work the same.
|
||||
* A deprecation notice is published to encourage consumers of this library to adopt
|
||||
the newer API
|
||||
* **Deprecation notice**
|
||||
* configuration through global variables is now deprecated, in favor of options passed as parameters
|
||||
* all helper functions are moved to more specialized packages, which are exposed as
|
||||
go modules. Importing such a module would reduce the footprint of dependencies.
|
||||
* _all_ functions, variables, constants exposed by the deprecated API have now moved, so
|
||||
that consumers of the new API no longer need to import github.com/go-openapi/swag, but
|
||||
should import the desired sub-module(s).
|
||||
|
||||
**New with this release**:
|
||||
|
||||
* [x] type converters and pointer to value helpers now support generic types
|
||||
* [x] name mangling now support pluralized initialisms (issue #46)
|
||||
Strings like "contact IDs" are now recognized as such a plural form and mangled as a linter would expect.
|
||||
* [x] performance: small improvements to reduce the overhead of convert/format wrappers (see issues #110, or PR #108)
|
||||
* [x] performance: name mangling utilities run ~ 10% faster (PR #115)
|
||||
|
||||
---
|
||||
|
||||
## Licensing
|
||||
|
||||
This library ships under the [SPDX-License-Identifier: Apache-2.0](./LICENSE).
|
||||
|
||||
## Note to contributors
|
||||
|
||||
A mono-repo structure comes with some unavoidable extra pains...
|
||||
|
||||
* Testing
|
||||
|
||||
> The usual `go test ./...` command, run from the root of this repo won't work any longer to test all submodules.
|
||||
>
|
||||
> Each module constitutes an independant unit of test. So you have to run `go test` inside each module.
|
||||
> Or you may take a look at how this is achieved by CI
|
||||
> [here] https://github.com/go-openapi/swag/blob/master/.github/workflows/go-test.yml).
|
||||
>
|
||||
> There are also some alternative tricks using `go work`, for local development, if you feel comfortable with
|
||||
> go workspaces. Perhaps some day, we'll have a `go work test` to run all tests without any hack.
|
||||
|
||||
* Releasing
|
||||
|
||||
> Each module follows its own independant module versioning.
|
||||
>
|
||||
> So you have tags like `mangling/v0.24.0`, `fileutils/v0.24.0` etc that are used by `go mod` and `go get`
|
||||
> to refer to the tagged version of each module specifically.
|
||||
>
|
||||
> This means we may release patches etc to each module independently.
|
||||
>
|
||||
> We'd like to adopt the rule that modules in this repo would only differ by a patch version
|
||||
> (e.g. `v0.24.5` vs `v0.24.3`), and we'll level all modules whenever a minor version is introduced.
|
||||
>
|
||||
> A script in `./hack` is provided to tag all modules with the same version in one go.
|
||||
|
||||
* Continuous integration
|
||||
|
||||
> At this moment, all tests in all modules are systematically run over the full test matrix (3 platform x 2 go releases).
|
||||
> This generates quite a lot of jobs.
|
||||
>
|
||||
> We ought to reduce the number of jobs required to test a PR focused on only a few modules.
|
||||
|
||||
## Todos, suggestions and plans
|
||||
|
||||
All kinds of contributions are welcome.
|
||||
|
||||
A few ideas:
|
||||
|
||||
* [x] Complete the split of dependencies to isolate easyjson from the rest
|
||||
* [x] Improve CI to reduce needed tests
|
||||
* [x] Replace dependency to `gopkg.in/yaml.v3` (`yamlutil`)
|
||||
* [ ] Improve mangling utilities (improve readability, support for capitalized words,
|
||||
better word substitution for non-letter symbols...)
|
||||
* [ ] Move back to this common shared pot a few of the technical features introduced by go-swagger independently
|
||||
(e.g. mangle go package names, search package with go modules support, ...)
|
||||
* [ ] Apply a similar mono-repo approach to go-openapi/strfmt which suffer from similar woes: bloated API,
|
||||
imposed dependency to some database driver.
|
||||
* [ ] Adapt `go-swagger` (incl. generated code) to the new `swag` API.
|
||||
* [ ] Factorize some tests, as there is a lot of redundant testing code in `jsonutils`
|
||||
* [ ] Benchmark & profiling: publish independently the tool built to analyze and chart benchmarks (e.g. similar to `benchvisual`)
|
||||
* [ ] more thorough testing for nil / null case
|
||||
* [ ] ci pipeline to manage releases
|
||||
* [ ] cleaner mockery generation (doesn't work out of the box for all sub-modules)
|
||||
* YAML utilities depend on `gopkg.in/yaml.v3`
|
||||
* `github.com/mailru/easyjson v0.7.7`
|
||||
|
||||
-19
@@ -1,19 +0,0 @@
|
||||
# Security Policy
|
||||
|
||||
This policy outlines the commitment and practices of the go-openapi maintainers regarding security.
|
||||
|
||||
## Supported Versions
|
||||
|
||||
| Version | Supported |
|
||||
| ------- | ------------------ |
|
||||
| 0.25.x | :white_check_mark: |
|
||||
|
||||
## Reporting a vulnerability
|
||||
|
||||
If you become aware of a security vulnerability that affects the current repository,
|
||||
please report it privately to the maintainers.
|
||||
|
||||
Please follow the instructions provided by github to
|
||||
[Privately report a security vulnerability](https://docs.github.com/en/code-security/security-advisories/guidance-on-reporting-and-writing-information-about-vulnerabilities/privately-reporting-a-security-vulnerability#privately-reporting-a-security-vulnerability).
|
||||
|
||||
TL;DR: on Github, navigate to the project's "Security" tab then click on "Report a vulnerability".
|
||||
-13
@@ -1,13 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package cmdutils
|
||||
|
||||
// CommandLineOptionsGroup represents a group of user-defined command line options.
|
||||
//
|
||||
// This is for instance used to configure command line arguments in API servers generated by go-swagger.
|
||||
type CommandLineOptionsGroup struct {
|
||||
ShortDescription string
|
||||
LongDescription string
|
||||
Options any
|
||||
}
|
||||
-5
@@ -1,5 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package cmdutils brings helpers for CLIs produced by go-openapi
|
||||
package cmdutils
|
||||
-11
@@ -1,11 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package swag
|
||||
|
||||
import "github.com/go-openapi/swag/cmdutils"
|
||||
|
||||
// CommandLineOptionsGroup represents a group of user-defined command line options.
|
||||
//
|
||||
// Deprecated: use [cmdutils.CommandLineOptionsGroup] instead.
|
||||
type CommandLineOptionsGroup = cmdutils.CommandLineOptionsGroup
|
||||
-161
@@ -1,161 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package conv
|
||||
|
||||
import (
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// same as ECMA Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER
|
||||
const (
|
||||
maxJSONFloat = float64(1<<53 - 1) // 9007199254740991.0 2^53 - 1
|
||||
minJSONFloat = -float64(1<<53 - 1) //-9007199254740991.0 -2^53 - 1
|
||||
epsilon float64 = 1e-9
|
||||
)
|
||||
|
||||
// IsFloat64AJSONInteger allows for integers [-2^53, 2^53-1] inclusive.
|
||||
func IsFloat64AJSONInteger(f float64) bool {
|
||||
if math.IsNaN(f) || math.IsInf(f, 0) || f < minJSONFloat || f > maxJSONFloat {
|
||||
return false
|
||||
}
|
||||
rounded := math.Round(f)
|
||||
if f == rounded {
|
||||
return true
|
||||
}
|
||||
if rounded == 0 { // f = 0.0 exited above
|
||||
return false
|
||||
}
|
||||
|
||||
diff := math.Abs(f - rounded)
|
||||
if diff == 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
// relative error Abs{f - Round(f)) / Round(f)} < ε ; Round(f)
|
||||
return diff < epsilon*math.Abs(rounded)
|
||||
}
|
||||
|
||||
// ConvertFloat turns a string into a float numerical value.
|
||||
func ConvertFloat[T Float](str string) (T, error) {
|
||||
var v T
|
||||
f, err := strconv.ParseFloat(str, bitsize(v))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return T(f), nil
|
||||
}
|
||||
|
||||
// ConvertInteger turns a string into a signed integer.
|
||||
func ConvertInteger[T Signed](str string) (T, error) {
|
||||
var v T
|
||||
f, err := strconv.ParseInt(str, 10, bitsize(v))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return T(f), nil
|
||||
}
|
||||
|
||||
// ConvertUinteger turns a string into an unsigned integer.
|
||||
func ConvertUinteger[T Unsigned](str string) (T, error) {
|
||||
var v T
|
||||
f, err := strconv.ParseUint(str, 10, bitsize(v))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return T(f), nil
|
||||
}
|
||||
|
||||
// ConvertBool turns a string into a boolean.
|
||||
//
|
||||
// It supports a few more "true" strings than [strconv.ParseBool]:
|
||||
//
|
||||
// - it is not case sensitive ("trUe" or "FalsE" work)
|
||||
// - "ok", "yes", "y", "on", "selected", "checked", "enabled" are all true
|
||||
// - everything that is not true is false: there is never an actual error returned
|
||||
func ConvertBool(str string) (bool, error) {
|
||||
switch strings.ToLower(str) {
|
||||
case "true",
|
||||
"1",
|
||||
"yes",
|
||||
"ok",
|
||||
"y",
|
||||
"on",
|
||||
"selected",
|
||||
"checked",
|
||||
"t",
|
||||
"enabled":
|
||||
return true, nil
|
||||
default:
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
|
||||
// ConvertFloat32 turns a string into a float32.
|
||||
func ConvertFloat32(str string) (float32, error) { return ConvertFloat[float32](str) }
|
||||
|
||||
// ConvertFloat64 turns a string into a float64
|
||||
func ConvertFloat64(str string) (float64, error) { return ConvertFloat[float64](str) }
|
||||
|
||||
// ConvertInt8 turns a string into an int8
|
||||
func ConvertInt8(str string) (int8, error) { return ConvertInteger[int8](str) }
|
||||
|
||||
// ConvertInt16 turns a string into an int16
|
||||
func ConvertInt16(str string) (int16, error) {
|
||||
i, err := strconv.ParseInt(str, 10, 16)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return int16(i), nil
|
||||
}
|
||||
|
||||
// ConvertInt32 turns a string into an int32
|
||||
func ConvertInt32(str string) (int32, error) {
|
||||
i, err := strconv.ParseInt(str, 10, 32)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return int32(i), nil
|
||||
}
|
||||
|
||||
// ConvertInt64 turns a string into an int64
|
||||
func ConvertInt64(str string) (int64, error) {
|
||||
return strconv.ParseInt(str, 10, 64)
|
||||
}
|
||||
|
||||
// ConvertUint8 turns a string into an uint8
|
||||
func ConvertUint8(str string) (uint8, error) {
|
||||
i, err := strconv.ParseUint(str, 10, 8)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return uint8(i), nil
|
||||
}
|
||||
|
||||
// ConvertUint16 turns a string into an uint16
|
||||
func ConvertUint16(str string) (uint16, error) {
|
||||
i, err := strconv.ParseUint(str, 10, 16)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return uint16(i), nil
|
||||
}
|
||||
|
||||
// ConvertUint32 turns a string into an uint32
|
||||
func ConvertUint32(str string) (uint32, error) {
|
||||
i, err := strconv.ParseUint(str, 10, 32)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return uint32(i), nil
|
||||
}
|
||||
|
||||
// ConvertUint64 turns a string into an uint64
|
||||
func ConvertUint64(str string) (uint64, error) {
|
||||
return strconv.ParseUint(str, 10, 64)
|
||||
}
|
||||
-72
@@ -1,72 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package conv
|
||||
|
||||
// Unlicensed credits (idea, concept)
|
||||
//
|
||||
// The idea to convert values to pointers and the other way around, was inspired, eons ago, by the aws go sdk.
|
||||
//
|
||||
// Nowadays, all sensible API sdk's expose a similar functionality.
|
||||
|
||||
// Pointer returns a pointer to the value passed in.
|
||||
func Pointer[T any](v T) *T {
|
||||
return &v
|
||||
}
|
||||
|
||||
// Value returns a shallow copy of the value of the pointer passed in.
|
||||
//
|
||||
// If the pointer is nil, the returned value is the zero value.
|
||||
func Value[T any](v *T) T {
|
||||
if v != nil {
|
||||
return *v
|
||||
}
|
||||
|
||||
var zero T
|
||||
return zero
|
||||
}
|
||||
|
||||
// PointerSlice converts a slice of values into a slice of pointers.
|
||||
func PointerSlice[T any](src []T) []*T {
|
||||
dst := make([]*T, len(src))
|
||||
for i := 0; i < len(src); i++ {
|
||||
dst[i] = &(src[i])
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// ValueSlice converts a slice of pointers into a slice of values.
|
||||
//
|
||||
// nil elements are zero values.
|
||||
func ValueSlice[T any](src []*T) []T {
|
||||
dst := make([]T, len(src))
|
||||
for i := 0; i < len(src); i++ {
|
||||
if src[i] != nil {
|
||||
dst[i] = *(src[i])
|
||||
}
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// PointerMap converts a map of values into a map of pointers.
|
||||
func PointerMap[K comparable, T any](src map[K]T) map[K]*T {
|
||||
dst := make(map[K]*T)
|
||||
for k, val := range src {
|
||||
v := val
|
||||
dst[k] = &v
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// ValueMap converts a map of pointers into a map of values.
|
||||
//
|
||||
// nil elements are skipped.
|
||||
func ValueMap[K comparable, T any](src map[K]*T) map[K]T {
|
||||
dst := make(map[K]T)
|
||||
for k, val := range src {
|
||||
if val != nil {
|
||||
dst[k] = *val
|
||||
}
|
||||
}
|
||||
return dst
|
||||
}
|
||||
-15
@@ -1,15 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package conv exposes utilities to convert types.
|
||||
//
|
||||
// The Convert and Format families of functions are essentially a shorthand to [strconv] functions,
|
||||
// using the decimal representation of numbers.
|
||||
//
|
||||
// Features:
|
||||
//
|
||||
// - from string representation to value ("Convert*") and reciprocally ("Format*")
|
||||
// - from pointer to value ([Value]) and reciprocally ([Pointer])
|
||||
// - from slice of values to slice of pointers ([PointerSlice]) and reciprocally ([ValueSlice])
|
||||
// - from map of values to map of pointers ([PointerMap]) and reciprocally ([ValueMap])
|
||||
package conv
|
||||
-28
@@ -1,28 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package conv
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// FormatInteger turns an integer type into a string.
|
||||
func FormatInteger[T Signed](value T) string {
|
||||
return strconv.FormatInt(int64(value), 10)
|
||||
}
|
||||
|
||||
// FormatUinteger turns an unsigned integer type into a string.
|
||||
func FormatUinteger[T Unsigned](value T) string {
|
||||
return strconv.FormatUint(uint64(value), 10)
|
||||
}
|
||||
|
||||
// FormatFloat turns a floating point numerical value into a string.
|
||||
func FormatFloat[T Float](value T) string {
|
||||
return strconv.FormatFloat(float64(value), 'f', -1, bitsize(value))
|
||||
}
|
||||
|
||||
// FormatBool turns a boolean into a string.
|
||||
func FormatBool(value bool) string {
|
||||
return strconv.FormatBool(value)
|
||||
}
|
||||
-20
@@ -1,20 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package conv
|
||||
|
||||
import "unsafe"
|
||||
|
||||
// bitsize returns the size in bits of a type.
|
||||
//
|
||||
// NOTE: [unsafe.SizeOf] simply returns the size in bytes of the value.
|
||||
// For primitive types T, the generic stencil is precompiled and this value
|
||||
// is resolved at compile time, resulting in an immediate call to [strconv.ParseFloat].
|
||||
//
|
||||
// We may leave up to the go compiler to simplify this function into a
|
||||
// constant value, which happens in practice at least for primitive types
|
||||
// (e.g. numerical types).
|
||||
func bitsize[T Numerical](value T) int {
|
||||
const bitsPerByte = 8
|
||||
return int(unsafe.Sizeof(value)) * bitsPerByte
|
||||
}
|
||||
-29
@@ -1,29 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package conv
|
||||
|
||||
type (
|
||||
// these type constraints are redefined after golang.org/x/exp/constraints,
|
||||
// because importing that package causes an undesired go upgrade.
|
||||
|
||||
// Signed integer types, cf. [golang.org/x/exp/constraints.Signed]
|
||||
Signed interface {
|
||||
~int | ~int8 | ~int16 | ~int32 | ~int64
|
||||
}
|
||||
|
||||
// Unsigned integer types, cf. [golang.org/x/exp/constraints.Unsigned]
|
||||
Unsigned interface {
|
||||
~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr
|
||||
}
|
||||
|
||||
// Float numerical types, cf. [golang.org/x/exp/constraints.Float]
|
||||
Float interface {
|
||||
~float32 | ~float64
|
||||
}
|
||||
|
||||
// Numerical types
|
||||
Numerical interface {
|
||||
Signed | Unsigned | Float
|
||||
}
|
||||
)
|
||||
-486
@@ -1,486 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package swag
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/go-openapi/swag/conv"
|
||||
)
|
||||
|
||||
// IsFloat64AJSONInteger allows for integers [-2^53, 2^53-1] inclusive.
|
||||
//
|
||||
// Deprecated: use [conv.IsFloat64AJSONInteger] instead.
|
||||
func IsFloat64AJSONInteger(f float64) bool { return conv.IsFloat64AJSONInteger(f) }
|
||||
|
||||
// ConvertBool turns a string into a boolean.
|
||||
//
|
||||
// Deprecated: use [conv.ConvertBool] instead.
|
||||
func ConvertBool(str string) (bool, error) { return conv.ConvertBool(str) }
|
||||
|
||||
// ConvertFloat32 turns a string into a float32.
|
||||
//
|
||||
// Deprecated: use [conv.ConvertFloat32] instead. Alternatively, you may use the generic version [conv.ConvertFloat].
|
||||
func ConvertFloat32(str string) (float32, error) { return conv.ConvertFloat[float32](str) }
|
||||
|
||||
// ConvertFloat64 turns a string into a float64.
|
||||
//
|
||||
// Deprecated: use [conv.ConvertFloat64] instead. Alternatively, you may use the generic version [conv.ConvertFloat].
|
||||
func ConvertFloat64(str string) (float64, error) { return conv.ConvertFloat[float64](str) }
|
||||
|
||||
// ConvertInt8 turns a string into an int8.
|
||||
//
|
||||
// Deprecated: use [conv.ConvertInt8] instead. Alternatively, you may use the generic version [conv.ConvertInteger].
|
||||
func ConvertInt8(str string) (int8, error) { return conv.ConvertInteger[int8](str) }
|
||||
|
||||
// ConvertInt16 turns a string into an int16.
|
||||
//
|
||||
// Deprecated: use [conv.ConvertInt16] instead. Alternatively, you may use the generic version [conv.ConvertInteger].
|
||||
func ConvertInt16(str string) (int16, error) { return conv.ConvertInteger[int16](str) }
|
||||
|
||||
// ConvertInt32 turns a string into an int32.
|
||||
//
|
||||
// Deprecated: use [conv.ConvertInt32] instead. Alternatively, you may use the generic version [conv.ConvertInteger].
|
||||
func ConvertInt32(str string) (int32, error) { return conv.ConvertInteger[int32](str) }
|
||||
|
||||
// ConvertInt64 turns a string into an int64.
|
||||
//
|
||||
// Deprecated: use [conv.ConvertInt64] instead. Alternatively, you may use the generic version [conv.ConvertInteger].
|
||||
func ConvertInt64(str string) (int64, error) { return conv.ConvertInteger[int64](str) }
|
||||
|
||||
// ConvertUint8 turns a string into an uint8.
|
||||
//
|
||||
// Deprecated: use [conv.ConvertUint8] instead. Alternatively, you may use the generic version [conv.ConvertUinteger].
|
||||
func ConvertUint8(str string) (uint8, error) { return conv.ConvertUinteger[uint8](str) }
|
||||
|
||||
// ConvertUint16 turns a string into an uint16.
|
||||
//
|
||||
// Deprecated: use [conv.ConvertUint16] instead. Alternatively, you may use the generic version [conv.ConvertUinteger].
|
||||
func ConvertUint16(str string) (uint16, error) { return conv.ConvertUinteger[uint16](str) }
|
||||
|
||||
// ConvertUint32 turns a string into an uint32.
|
||||
//
|
||||
// Deprecated: use [conv.ConvertUint32] instead. Alternatively, you may use the generic version [conv.ConvertUinteger].
|
||||
func ConvertUint32(str string) (uint32, error) { return conv.ConvertUinteger[uint32](str) }
|
||||
|
||||
// ConvertUint64 turns a string into an uint64.
|
||||
//
|
||||
// Deprecated: use [conv.ConvertUint64] instead. Alternatively, you may use the generic version [conv.ConvertUinteger].
|
||||
func ConvertUint64(str string) (uint64, error) { return conv.ConvertUinteger[uint64](str) }
|
||||
|
||||
// FormatBool turns a boolean into a string.
|
||||
//
|
||||
// Deprecated: use [conv.FormatBool] instead.
|
||||
func FormatBool(value bool) string { return conv.FormatBool(value) }
|
||||
|
||||
// FormatFloat32 turns a float32 into a string.
|
||||
//
|
||||
// Deprecated: use [conv.FormatFloat] instead.
|
||||
func FormatFloat32(value float32) string { return conv.FormatFloat(value) }
|
||||
|
||||
// FormatFloat64 turns a float64 into a string.
|
||||
//
|
||||
// Deprecated: use [conv.FormatFloat] instead.
|
||||
func FormatFloat64(value float64) string { return conv.FormatFloat(value) }
|
||||
|
||||
// FormatInt8 turns an int8 into a string.
|
||||
//
|
||||
// Deprecated: use [conv.FormatInteger] instead.
|
||||
func FormatInt8(value int8) string { return conv.FormatInteger(value) }
|
||||
|
||||
// FormatInt16 turns an int16 into a string.
|
||||
//
|
||||
// Deprecated: use [conv.FormatInteger] instead.
|
||||
func FormatInt16(value int16) string { return conv.FormatInteger(value) }
|
||||
|
||||
// FormatInt32 turns an int32 into a string
|
||||
//
|
||||
// Deprecated: use [conv.FormatInteger] instead.
|
||||
func FormatInt32(value int32) string { return conv.FormatInteger(value) }
|
||||
|
||||
// FormatInt64 turns an int64 into a string.
|
||||
//
|
||||
// Deprecated: use [conv.FormatInteger] instead.
|
||||
func FormatInt64(value int64) string { return conv.FormatInteger(value) }
|
||||
|
||||
// FormatUint8 turns an uint8 into a string.
|
||||
//
|
||||
// Deprecated: use [conv.FormatUinteger] instead.
|
||||
func FormatUint8(value uint8) string { return conv.FormatUinteger(value) }
|
||||
|
||||
// FormatUint16 turns an uint16 into a string.
|
||||
//
|
||||
// Deprecated: use [conv.FormatUinteger] instead.
|
||||
func FormatUint16(value uint16) string { return conv.FormatUinteger(value) }
|
||||
|
||||
// FormatUint32 turns an uint32 into a string.
|
||||
//
|
||||
// Deprecated: use [conv.FormatUinteger] instead.
|
||||
func FormatUint32(value uint32) string { return conv.FormatUinteger(value) }
|
||||
|
||||
// FormatUint64 turns an uint64 into a string.
|
||||
//
|
||||
// Deprecated: use [conv.FormatUinteger] instead.
|
||||
func FormatUint64(value uint64) string { return conv.FormatUinteger(value) }
|
||||
|
||||
// String turn a pointer to of the string value passed in.
|
||||
//
|
||||
// Deprecated: use [conv.Pointer] instead.
|
||||
func String(v string) *string { return conv.Pointer(v) }
|
||||
|
||||
// StringValue turn the value of the string pointer passed in or
|
||||
// "" if the pointer is nil.
|
||||
//
|
||||
// Deprecated: use [conv.Value] instead.
|
||||
func StringValue(v *string) string { return conv.Value(v) }
|
||||
|
||||
// StringSlice converts a slice of string values into a slice of string pointers.
|
||||
//
|
||||
// Deprecated: use [conv.PointerSlice] instead.
|
||||
func StringSlice(src []string) []*string { return conv.PointerSlice(src) }
|
||||
|
||||
// StringValueSlice converts a slice of string pointers into a slice of string values.
|
||||
//
|
||||
// Deprecated: use [conv.ValueSlice] instead.
|
||||
func StringValueSlice(src []*string) []string { return conv.ValueSlice(src) }
|
||||
|
||||
// StringMap converts a string map of string values into a string map of string pointers.
|
||||
//
|
||||
// Deprecated: use [conv.PointerMap] instead.
|
||||
func StringMap(src map[string]string) map[string]*string { return conv.PointerMap(src) }
|
||||
|
||||
// StringValueMap converts a string map of string pointers into a string map of string values.
|
||||
//
|
||||
// Deprecated: use [conv.ValueMap] instead.
|
||||
func StringValueMap(src map[string]*string) map[string]string { return conv.ValueMap(src) }
|
||||
|
||||
// Bool turn a pointer to of the bool value passed in.
|
||||
//
|
||||
// Deprecated: use [conv.Pointer] instead.
|
||||
func Bool(v bool) *bool { return conv.Pointer(v) }
|
||||
|
||||
// BoolValue turn the value of the bool pointer passed in or false if the pointer is nil.
|
||||
//
|
||||
// Deprecated: use [conv.Value] instead.
|
||||
func BoolValue(v *bool) bool { return conv.Value(v) }
|
||||
|
||||
// BoolSlice converts a slice of bool values into a slice of bool pointers.
|
||||
//
|
||||
// Deprecated: use [conv.PointerSlice] instead.
|
||||
func BoolSlice(src []bool) []*bool { return conv.PointerSlice(src) }
|
||||
|
||||
// BoolValueSlice converts a slice of bool pointers into a slice of bool values.
|
||||
//
|
||||
// Deprecated: use [conv.ValueSlice] instead.
|
||||
func BoolValueSlice(src []*bool) []bool { return conv.ValueSlice(src) }
|
||||
|
||||
// BoolMap converts a string map of bool values into a string map of bool pointers.
|
||||
//
|
||||
// Deprecated: use [conv.PointerMap] instead.
|
||||
func BoolMap(src map[string]bool) map[string]*bool { return conv.PointerMap(src) }
|
||||
|
||||
// BoolValueMap converts a string map of bool pointers into a string map of bool values.
|
||||
//
|
||||
// Deprecated: use [conv.ValueMap] instead.
|
||||
func BoolValueMap(src map[string]*bool) map[string]bool { return conv.ValueMap(src) }
|
||||
|
||||
// Int turn a pointer to of the int value passed in.
|
||||
//
|
||||
// Deprecated: use [conv.Pointer] instead.
|
||||
func Int(v int) *int { return conv.Pointer(v) }
|
||||
|
||||
// IntValue turn the value of the int pointer passed in or 0 if the pointer is nil.
|
||||
//
|
||||
// Deprecated: use [conv.Value] instead.
|
||||
func IntValue(v *int) int { return conv.Value(v) }
|
||||
|
||||
// IntSlice converts a slice of int values into a slice of int pointers.
|
||||
//
|
||||
// Deprecated: use [conv.PointerSlice] instead.
|
||||
func IntSlice(src []int) []*int { return conv.PointerSlice(src) }
|
||||
|
||||
// IntValueSlice converts a slice of int pointers into a slice of int values.
|
||||
//
|
||||
// Deprecated: use [conv.ValueSlice] instead.
|
||||
func IntValueSlice(src []*int) []int { return conv.ValueSlice(src) }
|
||||
|
||||
// IntMap converts a string map of int values into a string map of int pointers.
|
||||
//
|
||||
// Deprecated: use [conv.PointerMap] instead.
|
||||
func IntMap(src map[string]int) map[string]*int { return conv.PointerMap(src) }
|
||||
|
||||
// IntValueMap converts a string map of int pointers into a string map of int values.
|
||||
//
|
||||
// Deprecated: use [conv.ValueMap] instead.
|
||||
func IntValueMap(src map[string]*int) map[string]int { return conv.ValueMap(src) }
|
||||
|
||||
// Int32 turn a pointer to of the int32 value passed in.
|
||||
//
|
||||
// Deprecated: use [conv.Pointer] instead.
|
||||
func Int32(v int32) *int32 { return conv.Pointer(v) }
|
||||
|
||||
// Int32Value turn the value of the int32 pointer passed in or 0 if the pointer is nil.
|
||||
//
|
||||
// Deprecated: use [conv.Value] instead.
|
||||
func Int32Value(v *int32) int32 { return conv.Value(v) }
|
||||
|
||||
// Int32Slice converts a slice of int32 values into a slice of int32 pointers.
|
||||
//
|
||||
// Deprecated: use [conv.PointerSlice] instead.
|
||||
func Int32Slice(src []int32) []*int32 { return conv.PointerSlice(src) }
|
||||
|
||||
// Int32ValueSlice converts a slice of int32 pointers into a slice of int32 values.
|
||||
//
|
||||
// Deprecated: use [conv.ValueSlice] instead.
|
||||
func Int32ValueSlice(src []*int32) []int32 { return conv.ValueSlice(src) }
|
||||
|
||||
// Int32Map converts a string map of int32 values into a string map of int32 pointers.
|
||||
//
|
||||
// Deprecated: use [conv.PointerMap] instead.
|
||||
func Int32Map(src map[string]int32) map[string]*int32 { return conv.PointerMap(src) }
|
||||
|
||||
// Int32ValueMap converts a string map of int32 pointers into a string map of int32 values.
|
||||
//
|
||||
// Deprecated: use [conv.ValueMap] instead.
|
||||
func Int32ValueMap(src map[string]*int32) map[string]int32 { return conv.ValueMap(src) }
|
||||
|
||||
// Int64 turn a pointer to of the int64 value passed in.
|
||||
//
|
||||
// Deprecated: use [conv.Pointer] instead.
|
||||
func Int64(v int64) *int64 { return conv.Pointer(v) }
|
||||
|
||||
// Int64Value turn the value of the int64 pointer passed in or 0 if the pointer is nil.
|
||||
//
|
||||
// Deprecated: use [conv.Value] instead.
|
||||
func Int64Value(v *int64) int64 { return conv.Value(v) }
|
||||
|
||||
// Int64Slice converts a slice of int64 values into a slice of int64 pointers.
|
||||
//
|
||||
// Deprecated: use [conv.PointerSlice] instead.
|
||||
func Int64Slice(src []int64) []*int64 { return conv.PointerSlice(src) }
|
||||
|
||||
// Int64ValueSlice converts a slice of int64 pointers into a slice of int64 values.
|
||||
//
|
||||
// Deprecated: use [conv.ValueSlice] instead.
|
||||
func Int64ValueSlice(src []*int64) []int64 { return conv.ValueSlice(src) }
|
||||
|
||||
// Int64Map converts a string map of int64 values into a string map of int64 pointers.
|
||||
//
|
||||
// Deprecated: use [conv.PointerMap] instead.
|
||||
func Int64Map(src map[string]int64) map[string]*int64 { return conv.PointerMap(src) }
|
||||
|
||||
// Int64ValueMap converts a string map of int64 pointers into a string map of int64 values.
|
||||
//
|
||||
// Deprecated: use [conv.ValueMap] instead.
|
||||
func Int64ValueMap(src map[string]*int64) map[string]int64 { return conv.ValueMap(src) }
|
||||
|
||||
// Uint16 turn a pointer to of the uint16 value passed in.
|
||||
//
|
||||
// Deprecated: use [conv.Pointer] instead.
|
||||
func Uint16(v uint16) *uint16 { return conv.Pointer(v) }
|
||||
|
||||
// Uint16Value turn the value of the uint16 pointer passed in or 0 if the pointer is nil.
|
||||
//
|
||||
// Deprecated: use [conv.Value] instead.
|
||||
func Uint16Value(v *uint16) uint16 { return conv.Value(v) }
|
||||
|
||||
// Uint16Slice converts a slice of uint16 values into a slice of uint16 pointers.
|
||||
//
|
||||
// Deprecated: use [conv.PointerSlice] instead.
|
||||
func Uint16Slice(src []uint16) []*uint16 { return conv.PointerSlice(src) }
|
||||
|
||||
// Uint16ValueSlice converts a slice of uint16 pointers into a slice of uint16 values.
|
||||
//
|
||||
// Deprecated: use [conv.ValueSlice] instead.
|
||||
func Uint16ValueSlice(src []*uint16) []uint16 { return conv.ValueSlice(src) }
|
||||
|
||||
// Uint16Map converts a string map of uint16 values into a string map of uint16 pointers.
|
||||
//
|
||||
// Deprecated: use [conv.PointerMap] instead.
|
||||
func Uint16Map(src map[string]uint16) map[string]*uint16 { return conv.PointerMap(src) }
|
||||
|
||||
// Uint16ValueMap converts a string map of uint16 pointers into a string map of uint16 values.
|
||||
//
|
||||
// Deprecated: use [conv.ValueMap] instead.
|
||||
func Uint16ValueMap(src map[string]*uint16) map[string]uint16 { return conv.ValueMap(src) }
|
||||
|
||||
// Uint turn a pointer to of the uint value passed in.
|
||||
//
|
||||
// Deprecated: use [conv.Pointer] instead.
|
||||
func Uint(v uint) *uint { return conv.Pointer(v) }
|
||||
|
||||
// UintValue turn the value of the uint pointer passed in or 0 if the pointer is nil.
|
||||
//
|
||||
// Deprecated: use [conv.Value] instead.
|
||||
func UintValue(v *uint) uint { return conv.Value(v) }
|
||||
|
||||
// UintSlice converts a slice of uint values into a slice of uint pointers.
|
||||
//
|
||||
// Deprecated: use [conv.PointerSlice] instead.
|
||||
func UintSlice(src []uint) []*uint { return conv.PointerSlice(src) }
|
||||
|
||||
// UintValueSlice converts a slice of uint pointers into a slice of uint values.
|
||||
//
|
||||
// Deprecated: use [conv.ValueSlice] instead.
|
||||
func UintValueSlice(src []*uint) []uint { return conv.ValueSlice(src) }
|
||||
|
||||
// UintMap converts a string map of uint values into a string map of uint pointers.
|
||||
//
|
||||
// Deprecated: use [conv.PointerMap] instead.
|
||||
func UintMap(src map[string]uint) map[string]*uint { return conv.PointerMap(src) }
|
||||
|
||||
// UintValueMap converts a string map of uint pointers into a string map of uint values.
|
||||
//
|
||||
// Deprecated: use [conv.ValueMap] instead.
|
||||
func UintValueMap(src map[string]*uint) map[string]uint { return conv.ValueMap(src) }
|
||||
|
||||
// Uint32 turn a pointer to of the uint32 value passed in.
|
||||
//
|
||||
// Deprecated: use [conv.Pointer] instead.
|
||||
func Uint32(v uint32) *uint32 { return conv.Pointer(v) }
|
||||
|
||||
// Uint32Value turn the value of the uint32 pointer passed in or 0 if the pointer is nil.
|
||||
//
|
||||
// Deprecated: use [conv.Value] instead.
|
||||
func Uint32Value(v *uint32) uint32 { return conv.Value(v) }
|
||||
|
||||
// Uint32Slice converts a slice of uint32 values into a slice of uint32 pointers.
|
||||
//
|
||||
// Deprecated: use [conv.PointerSlice] instead.
|
||||
func Uint32Slice(src []uint32) []*uint32 { return conv.PointerSlice(src) }
|
||||
|
||||
// Uint32ValueSlice converts a slice of uint32 pointers into a slice of uint32 values.
|
||||
//
|
||||
// Deprecated: use [conv.ValueSlice] instead.
|
||||
func Uint32ValueSlice(src []*uint32) []uint32 { return conv.ValueSlice(src) }
|
||||
|
||||
// Uint32Map converts a string map of uint32 values into a string map of uint32 pointers.
|
||||
//
|
||||
// Deprecated: use [conv.PointerMap] instead.
|
||||
func Uint32Map(src map[string]uint32) map[string]*uint32 { return conv.PointerMap(src) }
|
||||
|
||||
// Uint32ValueMap converts a string map of uint32 pointers into a string map of uint32 values.
|
||||
//
|
||||
// Deprecated: use [conv.ValueMap] instead.
|
||||
func Uint32ValueMap(src map[string]*uint32) map[string]uint32 { return conv.ValueMap(src) }
|
||||
|
||||
// Uint64 turn a pointer to of the uint64 value passed in.
|
||||
//
|
||||
// Deprecated: use [conv.Pointer] instead.
|
||||
func Uint64(v uint64) *uint64 { return conv.Pointer(v) }
|
||||
|
||||
// Uint64Value turn the value of the uint64 pointer passed in or 0 if the pointer is nil.
|
||||
//
|
||||
// Deprecated: use [conv.Value] instead.
|
||||
func Uint64Value(v *uint64) uint64 { return conv.Value(v) }
|
||||
|
||||
// Uint64Slice converts a slice of uint64 values into a slice of uint64 pointers.
|
||||
//
|
||||
// Deprecated: use [conv.PointerSlice] instead.
|
||||
func Uint64Slice(src []uint64) []*uint64 { return conv.PointerSlice(src) }
|
||||
|
||||
// Uint64ValueSlice converts a slice of uint64 pointers into a slice of uint64 values.
|
||||
//
|
||||
// Deprecated: use [conv.ValueSlice] instead.
|
||||
func Uint64ValueSlice(src []*uint64) []uint64 { return conv.ValueSlice(src) }
|
||||
|
||||
// Uint64Map converts a string map of uint64 values into a string map of uint64 pointers.
|
||||
//
|
||||
// Deprecated: use [conv.PointerMap] instead.
|
||||
func Uint64Map(src map[string]uint64) map[string]*uint64 { return conv.PointerMap(src) }
|
||||
|
||||
// Uint64ValueMap converts a string map of uint64 pointers into a string map of uint64 values.
|
||||
//
|
||||
// Deprecated: use [conv.ValueMap] instead.
|
||||
func Uint64ValueMap(src map[string]*uint64) map[string]uint64 { return conv.ValueMap(src) }
|
||||
|
||||
// Float32 turn a pointer to of the float32 value passed in.
|
||||
//
|
||||
// Deprecated: use [conv.Pointer] instead.
|
||||
func Float32(v float32) *float32 { return conv.Pointer(v) }
|
||||
|
||||
// Float32Value turn the value of the float32 pointer passed in or 0 if the pointer is nil.
|
||||
//
|
||||
// Deprecated: use [conv.Value] instead.
|
||||
func Float32Value(v *float32) float32 { return conv.Value(v) }
|
||||
|
||||
// Float32Slice converts a slice of float32 values into a slice of float32 pointers.
|
||||
//
|
||||
// Deprecated: use [conv.PointerSlice] instead.
|
||||
func Float32Slice(src []float32) []*float32 { return conv.PointerSlice(src) }
|
||||
|
||||
// Float32ValueSlice converts a slice of float32 pointers into a slice of float32 values.
|
||||
//
|
||||
// Deprecated: use [conv.ValueSlice] instead.
|
||||
func Float32ValueSlice(src []*float32) []float32 { return conv.ValueSlice(src) }
|
||||
|
||||
// Float32Map converts a string map of float32 values into a string map of float32 pointers.
|
||||
//
|
||||
// Deprecated: use [conv.PointerMap] instead.
|
||||
func Float32Map(src map[string]float32) map[string]*float32 { return conv.PointerMap(src) }
|
||||
|
||||
// Float32ValueMap converts a string map of float32 pointers into a string map of float32 values.
|
||||
//
|
||||
// Deprecated: use [conv.ValueMap] instead.
|
||||
func Float32ValueMap(src map[string]*float32) map[string]float32 { return conv.ValueMap(src) }
|
||||
|
||||
// Float64 turn a pointer to of the float64 value passed in.
|
||||
//
|
||||
// Deprecated: use [conv.Pointer] instead.
|
||||
func Float64(v float64) *float64 { return conv.Pointer(v) }
|
||||
|
||||
// Float64Value turn the value of the float64 pointer passed in or 0 if the pointer is nil.
|
||||
//
|
||||
// Deprecated: use [conv.Value] instead.
|
||||
func Float64Value(v *float64) float64 { return conv.Value(v) }
|
||||
|
||||
// Float64Slice converts a slice of float64 values into a slice of float64 pointers.
|
||||
//
|
||||
// Deprecated: use [conv.PointerSlice] instead.
|
||||
func Float64Slice(src []float64) []*float64 { return conv.PointerSlice(src) }
|
||||
|
||||
// Float64ValueSlice converts a slice of float64 pointers into a slice of float64 values.
|
||||
//
|
||||
// Deprecated: use [conv.ValueSlice] instead.
|
||||
func Float64ValueSlice(src []*float64) []float64 { return conv.ValueSlice(src) }
|
||||
|
||||
// Float64Map converts a string map of float64 values into a string map of float64 pointers.
|
||||
//
|
||||
// Deprecated: use [conv.PointerMap] instead.
|
||||
func Float64Map(src map[string]float64) map[string]*float64 { return conv.PointerMap(src) }
|
||||
|
||||
// Float64ValueMap converts a string map of float64 pointers into a string map of float64 values.
|
||||
//
|
||||
// Deprecated: use [conv.ValueMap] instead.
|
||||
func Float64ValueMap(src map[string]*float64) map[string]float64 { return conv.ValueMap(src) }
|
||||
|
||||
// Time turn a pointer to of the time.Time value passed in.
|
||||
//
|
||||
// Deprecated: use [conv.Pointer] instead.
|
||||
func Time(v time.Time) *time.Time { return conv.Pointer(v) }
|
||||
|
||||
// TimeValue turn the value of the time.Time pointer passed in or time.Time{} if the pointer is nil.
|
||||
//
|
||||
// Deprecated: use [conv.Value] instead.
|
||||
func TimeValue(v *time.Time) time.Time { return conv.Value(v) }
|
||||
|
||||
// TimeSlice converts a slice of time.Time values into a slice of time.Time pointers.
|
||||
//
|
||||
// Deprecated: use [conv.PointerSlice] instead.
|
||||
func TimeSlice(src []time.Time) []*time.Time { return conv.PointerSlice(src) }
|
||||
|
||||
// TimeValueSlice converts a slice of time.Time pointers into a slice of time.Time values
|
||||
//
|
||||
// Deprecated: use [conv.ValueSlice] instead.
|
||||
func TimeValueSlice(src []*time.Time) []time.Time { return conv.ValueSlice(src) }
|
||||
|
||||
// TimeMap converts a string map of time.Time values into a string map of time.Time pointers.
|
||||
//
|
||||
// Deprecated: use [conv.PointerMap] instead.
|
||||
func TimeMap(src map[string]time.Time) map[string]*time.Time { return conv.PointerMap(src) }
|
||||
|
||||
// TimeValueMap converts a string map of time.Time pointers into a string map of time.Time values.
|
||||
//
|
||||
// Deprecated: use [conv.ValueMap] instead.
|
||||
func TimeValueMap(src map[string]*time.Time) map[string]time.Time { return conv.ValueMap(src) }
|
||||
+208
@@ -0,0 +1,208 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package swag
|
||||
|
||||
import (
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// same as ECMA Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER
|
||||
const (
|
||||
maxJSONFloat = float64(1<<53 - 1) // 9007199254740991.0 2^53 - 1
|
||||
minJSONFloat = -float64(1<<53 - 1) //-9007199254740991.0 -2^53 - 1
|
||||
epsilon float64 = 1e-9
|
||||
)
|
||||
|
||||
// IsFloat64AJSONInteger allow for integers [-2^53, 2^53-1] inclusive
|
||||
func IsFloat64AJSONInteger(f float64) bool {
|
||||
if math.IsNaN(f) || math.IsInf(f, 0) || f < minJSONFloat || f > maxJSONFloat {
|
||||
return false
|
||||
}
|
||||
fa := math.Abs(f)
|
||||
g := float64(uint64(f))
|
||||
ga := math.Abs(g)
|
||||
|
||||
diff := math.Abs(f - g)
|
||||
|
||||
// more info: https://floating-point-gui.de/errors/comparison/#look-out-for-edge-cases
|
||||
switch {
|
||||
case f == g: // best case
|
||||
return true
|
||||
case f == float64(int64(f)) || f == float64(uint64(f)): // optimistic case
|
||||
return true
|
||||
case f == 0 || g == 0 || diff < math.SmallestNonzeroFloat64: // very close to 0 values
|
||||
return diff < (epsilon * math.SmallestNonzeroFloat64)
|
||||
}
|
||||
// check the relative error
|
||||
return diff/math.Min(fa+ga, math.MaxFloat64) < epsilon
|
||||
}
|
||||
|
||||
var evaluatesAsTrue map[string]struct{}
|
||||
|
||||
func init() {
|
||||
evaluatesAsTrue = map[string]struct{}{
|
||||
"true": {},
|
||||
"1": {},
|
||||
"yes": {},
|
||||
"ok": {},
|
||||
"y": {},
|
||||
"on": {},
|
||||
"selected": {},
|
||||
"checked": {},
|
||||
"t": {},
|
||||
"enabled": {},
|
||||
}
|
||||
}
|
||||
|
||||
// ConvertBool turn a string into a boolean
|
||||
func ConvertBool(str string) (bool, error) {
|
||||
_, ok := evaluatesAsTrue[strings.ToLower(str)]
|
||||
return ok, nil
|
||||
}
|
||||
|
||||
// ConvertFloat32 turn a string into a float32
|
||||
func ConvertFloat32(str string) (float32, error) {
|
||||
f, err := strconv.ParseFloat(str, 32)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return float32(f), nil
|
||||
}
|
||||
|
||||
// ConvertFloat64 turn a string into a float64
|
||||
func ConvertFloat64(str string) (float64, error) {
|
||||
return strconv.ParseFloat(str, 64)
|
||||
}
|
||||
|
||||
// ConvertInt8 turn a string into an int8
|
||||
func ConvertInt8(str string) (int8, error) {
|
||||
i, err := strconv.ParseInt(str, 10, 8)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return int8(i), nil
|
||||
}
|
||||
|
||||
// ConvertInt16 turn a string into an int16
|
||||
func ConvertInt16(str string) (int16, error) {
|
||||
i, err := strconv.ParseInt(str, 10, 16)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return int16(i), nil
|
||||
}
|
||||
|
||||
// ConvertInt32 turn a string into an int32
|
||||
func ConvertInt32(str string) (int32, error) {
|
||||
i, err := strconv.ParseInt(str, 10, 32)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return int32(i), nil
|
||||
}
|
||||
|
||||
// ConvertInt64 turn a string into an int64
|
||||
func ConvertInt64(str string) (int64, error) {
|
||||
return strconv.ParseInt(str, 10, 64)
|
||||
}
|
||||
|
||||
// ConvertUint8 turn a string into an uint8
|
||||
func ConvertUint8(str string) (uint8, error) {
|
||||
i, err := strconv.ParseUint(str, 10, 8)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return uint8(i), nil
|
||||
}
|
||||
|
||||
// ConvertUint16 turn a string into an uint16
|
||||
func ConvertUint16(str string) (uint16, error) {
|
||||
i, err := strconv.ParseUint(str, 10, 16)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return uint16(i), nil
|
||||
}
|
||||
|
||||
// ConvertUint32 turn a string into an uint32
|
||||
func ConvertUint32(str string) (uint32, error) {
|
||||
i, err := strconv.ParseUint(str, 10, 32)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return uint32(i), nil
|
||||
}
|
||||
|
||||
// ConvertUint64 turn a string into an uint64
|
||||
func ConvertUint64(str string) (uint64, error) {
|
||||
return strconv.ParseUint(str, 10, 64)
|
||||
}
|
||||
|
||||
// FormatBool turns a boolean into a string
|
||||
func FormatBool(value bool) string {
|
||||
return strconv.FormatBool(value)
|
||||
}
|
||||
|
||||
// FormatFloat32 turns a float32 into a string
|
||||
func FormatFloat32(value float32) string {
|
||||
return strconv.FormatFloat(float64(value), 'f', -1, 32)
|
||||
}
|
||||
|
||||
// FormatFloat64 turns a float64 into a string
|
||||
func FormatFloat64(value float64) string {
|
||||
return strconv.FormatFloat(value, 'f', -1, 64)
|
||||
}
|
||||
|
||||
// FormatInt8 turns an int8 into a string
|
||||
func FormatInt8(value int8) string {
|
||||
return strconv.FormatInt(int64(value), 10)
|
||||
}
|
||||
|
||||
// FormatInt16 turns an int16 into a string
|
||||
func FormatInt16(value int16) string {
|
||||
return strconv.FormatInt(int64(value), 10)
|
||||
}
|
||||
|
||||
// FormatInt32 turns an int32 into a string
|
||||
func FormatInt32(value int32) string {
|
||||
return strconv.Itoa(int(value))
|
||||
}
|
||||
|
||||
// FormatInt64 turns an int64 into a string
|
||||
func FormatInt64(value int64) string {
|
||||
return strconv.FormatInt(value, 10)
|
||||
}
|
||||
|
||||
// FormatUint8 turns an uint8 into a string
|
||||
func FormatUint8(value uint8) string {
|
||||
return strconv.FormatUint(uint64(value), 10)
|
||||
}
|
||||
|
||||
// FormatUint16 turns an uint16 into a string
|
||||
func FormatUint16(value uint16) string {
|
||||
return strconv.FormatUint(uint64(value), 10)
|
||||
}
|
||||
|
||||
// FormatUint32 turns an uint32 into a string
|
||||
func FormatUint32(value uint32) string {
|
||||
return strconv.FormatUint(uint64(value), 10)
|
||||
}
|
||||
|
||||
// FormatUint64 turns an uint64 into a string
|
||||
func FormatUint64(value uint64) string {
|
||||
return strconv.FormatUint(value, 10)
|
||||
}
|
||||
+730
@@ -0,0 +1,730 @@
|
||||
package swag
|
||||
|
||||
import "time"
|
||||
|
||||
// This file was taken from the aws go sdk
|
||||
|
||||
// String returns a pointer to of the string value passed in.
|
||||
func String(v string) *string {
|
||||
return &v
|
||||
}
|
||||
|
||||
// StringValue returns the value of the string pointer passed in or
|
||||
// "" if the pointer is nil.
|
||||
func StringValue(v *string) string {
|
||||
if v != nil {
|
||||
return *v
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// StringSlice converts a slice of string values into a slice of
|
||||
// string pointers
|
||||
func StringSlice(src []string) []*string {
|
||||
dst := make([]*string, len(src))
|
||||
for i := 0; i < len(src); i++ {
|
||||
dst[i] = &(src[i])
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// StringValueSlice converts a slice of string pointers into a slice of
|
||||
// string values
|
||||
func StringValueSlice(src []*string) []string {
|
||||
dst := make([]string, len(src))
|
||||
for i := 0; i < len(src); i++ {
|
||||
if src[i] != nil {
|
||||
dst[i] = *(src[i])
|
||||
}
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// StringMap converts a string map of string values into a string
|
||||
// map of string pointers
|
||||
func StringMap(src map[string]string) map[string]*string {
|
||||
dst := make(map[string]*string)
|
||||
for k, val := range src {
|
||||
v := val
|
||||
dst[k] = &v
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// StringValueMap converts a string map of string pointers into a string
|
||||
// map of string values
|
||||
func StringValueMap(src map[string]*string) map[string]string {
|
||||
dst := make(map[string]string)
|
||||
for k, val := range src {
|
||||
if val != nil {
|
||||
dst[k] = *val
|
||||
}
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// Bool returns a pointer to of the bool value passed in.
|
||||
func Bool(v bool) *bool {
|
||||
return &v
|
||||
}
|
||||
|
||||
// BoolValue returns the value of the bool pointer passed in or
|
||||
// false if the pointer is nil.
|
||||
func BoolValue(v *bool) bool {
|
||||
if v != nil {
|
||||
return *v
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// BoolSlice converts a slice of bool values into a slice of
|
||||
// bool pointers
|
||||
func BoolSlice(src []bool) []*bool {
|
||||
dst := make([]*bool, len(src))
|
||||
for i := 0; i < len(src); i++ {
|
||||
dst[i] = &(src[i])
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// BoolValueSlice converts a slice of bool pointers into a slice of
|
||||
// bool values
|
||||
func BoolValueSlice(src []*bool) []bool {
|
||||
dst := make([]bool, len(src))
|
||||
for i := 0; i < len(src); i++ {
|
||||
if src[i] != nil {
|
||||
dst[i] = *(src[i])
|
||||
}
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// BoolMap converts a string map of bool values into a string
|
||||
// map of bool pointers
|
||||
func BoolMap(src map[string]bool) map[string]*bool {
|
||||
dst := make(map[string]*bool)
|
||||
for k, val := range src {
|
||||
v := val
|
||||
dst[k] = &v
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// BoolValueMap converts a string map of bool pointers into a string
|
||||
// map of bool values
|
||||
func BoolValueMap(src map[string]*bool) map[string]bool {
|
||||
dst := make(map[string]bool)
|
||||
for k, val := range src {
|
||||
if val != nil {
|
||||
dst[k] = *val
|
||||
}
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// Int returns a pointer to of the int value passed in.
|
||||
func Int(v int) *int {
|
||||
return &v
|
||||
}
|
||||
|
||||
// IntValue returns the value of the int pointer passed in or
|
||||
// 0 if the pointer is nil.
|
||||
func IntValue(v *int) int {
|
||||
if v != nil {
|
||||
return *v
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// IntSlice converts a slice of int values into a slice of
|
||||
// int pointers
|
||||
func IntSlice(src []int) []*int {
|
||||
dst := make([]*int, len(src))
|
||||
for i := 0; i < len(src); i++ {
|
||||
dst[i] = &(src[i])
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// IntValueSlice converts a slice of int pointers into a slice of
|
||||
// int values
|
||||
func IntValueSlice(src []*int) []int {
|
||||
dst := make([]int, len(src))
|
||||
for i := 0; i < len(src); i++ {
|
||||
if src[i] != nil {
|
||||
dst[i] = *(src[i])
|
||||
}
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// IntMap converts a string map of int values into a string
|
||||
// map of int pointers
|
||||
func IntMap(src map[string]int) map[string]*int {
|
||||
dst := make(map[string]*int)
|
||||
for k, val := range src {
|
||||
v := val
|
||||
dst[k] = &v
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// IntValueMap converts a string map of int pointers into a string
|
||||
// map of int values
|
||||
func IntValueMap(src map[string]*int) map[string]int {
|
||||
dst := make(map[string]int)
|
||||
for k, val := range src {
|
||||
if val != nil {
|
||||
dst[k] = *val
|
||||
}
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// Int32 returns a pointer to of the int32 value passed in.
|
||||
func Int32(v int32) *int32 {
|
||||
return &v
|
||||
}
|
||||
|
||||
// Int32Value returns the value of the int32 pointer passed in or
|
||||
// 0 if the pointer is nil.
|
||||
func Int32Value(v *int32) int32 {
|
||||
if v != nil {
|
||||
return *v
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// Int32Slice converts a slice of int32 values into a slice of
|
||||
// int32 pointers
|
||||
func Int32Slice(src []int32) []*int32 {
|
||||
dst := make([]*int32, len(src))
|
||||
for i := 0; i < len(src); i++ {
|
||||
dst[i] = &(src[i])
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// Int32ValueSlice converts a slice of int32 pointers into a slice of
|
||||
// int32 values
|
||||
func Int32ValueSlice(src []*int32) []int32 {
|
||||
dst := make([]int32, len(src))
|
||||
for i := 0; i < len(src); i++ {
|
||||
if src[i] != nil {
|
||||
dst[i] = *(src[i])
|
||||
}
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// Int32Map converts a string map of int32 values into a string
|
||||
// map of int32 pointers
|
||||
func Int32Map(src map[string]int32) map[string]*int32 {
|
||||
dst := make(map[string]*int32)
|
||||
for k, val := range src {
|
||||
v := val
|
||||
dst[k] = &v
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// Int32ValueMap converts a string map of int32 pointers into a string
|
||||
// map of int32 values
|
||||
func Int32ValueMap(src map[string]*int32) map[string]int32 {
|
||||
dst := make(map[string]int32)
|
||||
for k, val := range src {
|
||||
if val != nil {
|
||||
dst[k] = *val
|
||||
}
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// Int64 returns a pointer to of the int64 value passed in.
|
||||
func Int64(v int64) *int64 {
|
||||
return &v
|
||||
}
|
||||
|
||||
// Int64Value returns the value of the int64 pointer passed in or
|
||||
// 0 if the pointer is nil.
|
||||
func Int64Value(v *int64) int64 {
|
||||
if v != nil {
|
||||
return *v
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// Int64Slice converts a slice of int64 values into a slice of
|
||||
// int64 pointers
|
||||
func Int64Slice(src []int64) []*int64 {
|
||||
dst := make([]*int64, len(src))
|
||||
for i := 0; i < len(src); i++ {
|
||||
dst[i] = &(src[i])
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// Int64ValueSlice converts a slice of int64 pointers into a slice of
|
||||
// int64 values
|
||||
func Int64ValueSlice(src []*int64) []int64 {
|
||||
dst := make([]int64, len(src))
|
||||
for i := 0; i < len(src); i++ {
|
||||
if src[i] != nil {
|
||||
dst[i] = *(src[i])
|
||||
}
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// Int64Map converts a string map of int64 values into a string
|
||||
// map of int64 pointers
|
||||
func Int64Map(src map[string]int64) map[string]*int64 {
|
||||
dst := make(map[string]*int64)
|
||||
for k, val := range src {
|
||||
v := val
|
||||
dst[k] = &v
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// Int64ValueMap converts a string map of int64 pointers into a string
|
||||
// map of int64 values
|
||||
func Int64ValueMap(src map[string]*int64) map[string]int64 {
|
||||
dst := make(map[string]int64)
|
||||
for k, val := range src {
|
||||
if val != nil {
|
||||
dst[k] = *val
|
||||
}
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// Uint16 returns a pointer to of the uint16 value passed in.
|
||||
func Uint16(v uint16) *uint16 {
|
||||
return &v
|
||||
}
|
||||
|
||||
// Uint16Value returns the value of the uint16 pointer passed in or
|
||||
// 0 if the pointer is nil.
|
||||
func Uint16Value(v *uint16) uint16 {
|
||||
if v != nil {
|
||||
return *v
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
// Uint16Slice converts a slice of uint16 values into a slice of
|
||||
// uint16 pointers
|
||||
func Uint16Slice(src []uint16) []*uint16 {
|
||||
dst := make([]*uint16, len(src))
|
||||
for i := 0; i < len(src); i++ {
|
||||
dst[i] = &(src[i])
|
||||
}
|
||||
|
||||
return dst
|
||||
}
|
||||
|
||||
// Uint16ValueSlice converts a slice of uint16 pointers into a slice of
|
||||
// uint16 values
|
||||
func Uint16ValueSlice(src []*uint16) []uint16 {
|
||||
dst := make([]uint16, len(src))
|
||||
|
||||
for i := 0; i < len(src); i++ {
|
||||
if src[i] != nil {
|
||||
dst[i] = *(src[i])
|
||||
}
|
||||
}
|
||||
|
||||
return dst
|
||||
}
|
||||
|
||||
// Uint16Map converts a string map of uint16 values into a string
|
||||
// map of uint16 pointers
|
||||
func Uint16Map(src map[string]uint16) map[string]*uint16 {
|
||||
dst := make(map[string]*uint16)
|
||||
|
||||
for k, val := range src {
|
||||
v := val
|
||||
dst[k] = &v
|
||||
}
|
||||
|
||||
return dst
|
||||
}
|
||||
|
||||
// Uint16ValueMap converts a string map of uint16 pointers into a string
|
||||
// map of uint16 values
|
||||
func Uint16ValueMap(src map[string]*uint16) map[string]uint16 {
|
||||
dst := make(map[string]uint16)
|
||||
|
||||
for k, val := range src {
|
||||
if val != nil {
|
||||
dst[k] = *val
|
||||
}
|
||||
}
|
||||
|
||||
return dst
|
||||
}
|
||||
|
||||
// Uint returns a pointer to of the uint value passed in.
|
||||
func Uint(v uint) *uint {
|
||||
return &v
|
||||
}
|
||||
|
||||
// UintValue returns the value of the uint pointer passed in or
|
||||
// 0 if the pointer is nil.
|
||||
func UintValue(v *uint) uint {
|
||||
if v != nil {
|
||||
return *v
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// UintSlice converts a slice of uint values into a slice of
|
||||
// uint pointers
|
||||
func UintSlice(src []uint) []*uint {
|
||||
dst := make([]*uint, len(src))
|
||||
for i := 0; i < len(src); i++ {
|
||||
dst[i] = &(src[i])
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// UintValueSlice converts a slice of uint pointers into a slice of
|
||||
// uint values
|
||||
func UintValueSlice(src []*uint) []uint {
|
||||
dst := make([]uint, len(src))
|
||||
for i := 0; i < len(src); i++ {
|
||||
if src[i] != nil {
|
||||
dst[i] = *(src[i])
|
||||
}
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// UintMap converts a string map of uint values into a string
|
||||
// map of uint pointers
|
||||
func UintMap(src map[string]uint) map[string]*uint {
|
||||
dst := make(map[string]*uint)
|
||||
for k, val := range src {
|
||||
v := val
|
||||
dst[k] = &v
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// UintValueMap converts a string map of uint pointers into a string
|
||||
// map of uint values
|
||||
func UintValueMap(src map[string]*uint) map[string]uint {
|
||||
dst := make(map[string]uint)
|
||||
for k, val := range src {
|
||||
if val != nil {
|
||||
dst[k] = *val
|
||||
}
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// Uint32 returns a pointer to of the uint32 value passed in.
|
||||
func Uint32(v uint32) *uint32 {
|
||||
return &v
|
||||
}
|
||||
|
||||
// Uint32Value returns the value of the uint32 pointer passed in or
|
||||
// 0 if the pointer is nil.
|
||||
func Uint32Value(v *uint32) uint32 {
|
||||
if v != nil {
|
||||
return *v
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// Uint32Slice converts a slice of uint32 values into a slice of
|
||||
// uint32 pointers
|
||||
func Uint32Slice(src []uint32) []*uint32 {
|
||||
dst := make([]*uint32, len(src))
|
||||
for i := 0; i < len(src); i++ {
|
||||
dst[i] = &(src[i])
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// Uint32ValueSlice converts a slice of uint32 pointers into a slice of
|
||||
// uint32 values
|
||||
func Uint32ValueSlice(src []*uint32) []uint32 {
|
||||
dst := make([]uint32, len(src))
|
||||
for i := 0; i < len(src); i++ {
|
||||
if src[i] != nil {
|
||||
dst[i] = *(src[i])
|
||||
}
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// Uint32Map converts a string map of uint32 values into a string
|
||||
// map of uint32 pointers
|
||||
func Uint32Map(src map[string]uint32) map[string]*uint32 {
|
||||
dst := make(map[string]*uint32)
|
||||
for k, val := range src {
|
||||
v := val
|
||||
dst[k] = &v
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// Uint32ValueMap converts a string map of uint32 pointers into a string
|
||||
// map of uint32 values
|
||||
func Uint32ValueMap(src map[string]*uint32) map[string]uint32 {
|
||||
dst := make(map[string]uint32)
|
||||
for k, val := range src {
|
||||
if val != nil {
|
||||
dst[k] = *val
|
||||
}
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// Uint64 returns a pointer to of the uint64 value passed in.
|
||||
func Uint64(v uint64) *uint64 {
|
||||
return &v
|
||||
}
|
||||
|
||||
// Uint64Value returns the value of the uint64 pointer passed in or
|
||||
// 0 if the pointer is nil.
|
||||
func Uint64Value(v *uint64) uint64 {
|
||||
if v != nil {
|
||||
return *v
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// Uint64Slice converts a slice of uint64 values into a slice of
|
||||
// uint64 pointers
|
||||
func Uint64Slice(src []uint64) []*uint64 {
|
||||
dst := make([]*uint64, len(src))
|
||||
for i := 0; i < len(src); i++ {
|
||||
dst[i] = &(src[i])
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// Uint64ValueSlice converts a slice of uint64 pointers into a slice of
|
||||
// uint64 values
|
||||
func Uint64ValueSlice(src []*uint64) []uint64 {
|
||||
dst := make([]uint64, len(src))
|
||||
for i := 0; i < len(src); i++ {
|
||||
if src[i] != nil {
|
||||
dst[i] = *(src[i])
|
||||
}
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// Uint64Map converts a string map of uint64 values into a string
|
||||
// map of uint64 pointers
|
||||
func Uint64Map(src map[string]uint64) map[string]*uint64 {
|
||||
dst := make(map[string]*uint64)
|
||||
for k, val := range src {
|
||||
v := val
|
||||
dst[k] = &v
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// Uint64ValueMap converts a string map of uint64 pointers into a string
|
||||
// map of uint64 values
|
||||
func Uint64ValueMap(src map[string]*uint64) map[string]uint64 {
|
||||
dst := make(map[string]uint64)
|
||||
for k, val := range src {
|
||||
if val != nil {
|
||||
dst[k] = *val
|
||||
}
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// Float32 returns a pointer to of the float32 value passed in.
|
||||
func Float32(v float32) *float32 {
|
||||
return &v
|
||||
}
|
||||
|
||||
// Float32Value returns the value of the float32 pointer passed in or
|
||||
// 0 if the pointer is nil.
|
||||
func Float32Value(v *float32) float32 {
|
||||
if v != nil {
|
||||
return *v
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
// Float32Slice converts a slice of float32 values into a slice of
|
||||
// float32 pointers
|
||||
func Float32Slice(src []float32) []*float32 {
|
||||
dst := make([]*float32, len(src))
|
||||
|
||||
for i := 0; i < len(src); i++ {
|
||||
dst[i] = &(src[i])
|
||||
}
|
||||
|
||||
return dst
|
||||
}
|
||||
|
||||
// Float32ValueSlice converts a slice of float32 pointers into a slice of
|
||||
// float32 values
|
||||
func Float32ValueSlice(src []*float32) []float32 {
|
||||
dst := make([]float32, len(src))
|
||||
|
||||
for i := 0; i < len(src); i++ {
|
||||
if src[i] != nil {
|
||||
dst[i] = *(src[i])
|
||||
}
|
||||
}
|
||||
|
||||
return dst
|
||||
}
|
||||
|
||||
// Float32Map converts a string map of float32 values into a string
|
||||
// map of float32 pointers
|
||||
func Float32Map(src map[string]float32) map[string]*float32 {
|
||||
dst := make(map[string]*float32)
|
||||
|
||||
for k, val := range src {
|
||||
v := val
|
||||
dst[k] = &v
|
||||
}
|
||||
|
||||
return dst
|
||||
}
|
||||
|
||||
// Float32ValueMap converts a string map of float32 pointers into a string
|
||||
// map of float32 values
|
||||
func Float32ValueMap(src map[string]*float32) map[string]float32 {
|
||||
dst := make(map[string]float32)
|
||||
|
||||
for k, val := range src {
|
||||
if val != nil {
|
||||
dst[k] = *val
|
||||
}
|
||||
}
|
||||
|
||||
return dst
|
||||
}
|
||||
|
||||
// Float64 returns a pointer to of the float64 value passed in.
|
||||
func Float64(v float64) *float64 {
|
||||
return &v
|
||||
}
|
||||
|
||||
// Float64Value returns the value of the float64 pointer passed in or
|
||||
// 0 if the pointer is nil.
|
||||
func Float64Value(v *float64) float64 {
|
||||
if v != nil {
|
||||
return *v
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// Float64Slice converts a slice of float64 values into a slice of
|
||||
// float64 pointers
|
||||
func Float64Slice(src []float64) []*float64 {
|
||||
dst := make([]*float64, len(src))
|
||||
for i := 0; i < len(src); i++ {
|
||||
dst[i] = &(src[i])
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// Float64ValueSlice converts a slice of float64 pointers into a slice of
|
||||
// float64 values
|
||||
func Float64ValueSlice(src []*float64) []float64 {
|
||||
dst := make([]float64, len(src))
|
||||
for i := 0; i < len(src); i++ {
|
||||
if src[i] != nil {
|
||||
dst[i] = *(src[i])
|
||||
}
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// Float64Map converts a string map of float64 values into a string
|
||||
// map of float64 pointers
|
||||
func Float64Map(src map[string]float64) map[string]*float64 {
|
||||
dst := make(map[string]*float64)
|
||||
for k, val := range src {
|
||||
v := val
|
||||
dst[k] = &v
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// Float64ValueMap converts a string map of float64 pointers into a string
|
||||
// map of float64 values
|
||||
func Float64ValueMap(src map[string]*float64) map[string]float64 {
|
||||
dst := make(map[string]float64)
|
||||
for k, val := range src {
|
||||
if val != nil {
|
||||
dst[k] = *val
|
||||
}
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// Time returns a pointer to of the time.Time value passed in.
|
||||
func Time(v time.Time) *time.Time {
|
||||
return &v
|
||||
}
|
||||
|
||||
// TimeValue returns the value of the time.Time pointer passed in or
|
||||
// time.Time{} if the pointer is nil.
|
||||
func TimeValue(v *time.Time) time.Time {
|
||||
if v != nil {
|
||||
return *v
|
||||
}
|
||||
return time.Time{}
|
||||
}
|
||||
|
||||
// TimeSlice converts a slice of time.Time values into a slice of
|
||||
// time.Time pointers
|
||||
func TimeSlice(src []time.Time) []*time.Time {
|
||||
dst := make([]*time.Time, len(src))
|
||||
for i := 0; i < len(src); i++ {
|
||||
dst[i] = &(src[i])
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// TimeValueSlice converts a slice of time.Time pointers into a slice of
|
||||
// time.Time values
|
||||
func TimeValueSlice(src []*time.Time) []time.Time {
|
||||
dst := make([]time.Time, len(src))
|
||||
for i := 0; i < len(src); i++ {
|
||||
if src[i] != nil {
|
||||
dst[i] = *(src[i])
|
||||
}
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// TimeMap converts a string map of time.Time values into a string
|
||||
// map of time.Time pointers
|
||||
func TimeMap(src map[string]time.Time) map[string]*time.Time {
|
||||
dst := make(map[string]*time.Time)
|
||||
for k, val := range src {
|
||||
v := val
|
||||
dst[k] = &v
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// TimeValueMap converts a string map of time.Time pointers into a string
|
||||
// map of time.Time values
|
||||
func TimeValueMap(src map[string]*time.Time) map[string]time.Time {
|
||||
dst := make(map[string]time.Time)
|
||||
for k, val := range src {
|
||||
if val != nil {
|
||||
dst[k] = *val
|
||||
}
|
||||
}
|
||||
return dst
|
||||
}
|
||||
+29
-45
@@ -1,47 +1,31 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package swag contains a bunch of helper functions for go-openapi and go-swagger projects.
|
||||
//
|
||||
// You may also use it standalone for your projects.
|
||||
//
|
||||
// NOTE: all features that used to be exposed as package-level members (constants, variables,
|
||||
// functions and types) are now deprecated and are superseded by equivalent features in
|
||||
// more specialized sub-packages.
|
||||
// Moving forward, no additional feature will be added to the [swag] API directly at the root package level,
|
||||
// which remains there for backward-compatibility purposes.
|
||||
//
|
||||
// Child modules will continue to evolve or some new ones may be added in the future.
|
||||
//
|
||||
// # Modules
|
||||
//
|
||||
// - [cmdutils] utilities to work with CLIs
|
||||
//
|
||||
// - [conv] type conversion utilities
|
||||
//
|
||||
// - [fileutils] file utilities
|
||||
//
|
||||
// - [jsonname] JSON utilities
|
||||
//
|
||||
// - [jsonutils] JSON utilities
|
||||
//
|
||||
// - [loading] file loading
|
||||
//
|
||||
// - [mangling] safe name generation
|
||||
//
|
||||
// - [netutils] networking utilities
|
||||
//
|
||||
// - [stringutils] `string` utilities
|
||||
//
|
||||
// - [typeutils] `go` types utilities
|
||||
//
|
||||
// - [yamlutils] YAML utilities
|
||||
//
|
||||
// # Dependencies
|
||||
//
|
||||
// This repo has a few dependencies outside of the standard library:
|
||||
//
|
||||
// - YAML utilities depend on [go.yaml.in/yaml/v3]
|
||||
/*
|
||||
Package swag contains a bunch of helper functions for go-openapi and go-swagger projects.
|
||||
|
||||
You may also use it standalone for your projects.
|
||||
|
||||
- convert between value and pointers for builtin types
|
||||
- convert from string to builtin types (wraps strconv)
|
||||
- fast json concatenation
|
||||
- search in path
|
||||
- load from file or http
|
||||
- name mangling
|
||||
|
||||
This repo has only few dependencies outside of the standard library:
|
||||
|
||||
- YAML utilities depend on gopkg.in/yaml.v2
|
||||
*/
|
||||
package swag
|
||||
|
||||
//go:generate mockery
|
||||
|
||||
Generated
Vendored
+17
-6
@@ -1,4 +1,4 @@
|
||||
// Copyright 2025
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@@ -12,11 +12,22 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//go:build !unix
|
||||
package swag
|
||||
|
||||
package daemon
|
||||
import "mime/multipart"
|
||||
|
||||
// SdNotifyMonotonicUsec returns the empty string on unsupported platforms.
|
||||
func SdNotifyMonotonicUsec() string {
|
||||
return ""
|
||||
// File represents an uploaded file.
|
||||
type File struct {
|
||||
Data multipart.File
|
||||
Header *multipart.FileHeader
|
||||
}
|
||||
|
||||
// Read bytes from the file
|
||||
func (f *File) Read(p []byte) (n int, err error) {
|
||||
return f.Data.Read(p)
|
||||
}
|
||||
|
||||
// Close the file
|
||||
func (f *File) Close() error {
|
||||
return f.Data.Close()
|
||||
}
|
||||
-202
@@ -1,202 +0,0 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-10
@@ -1,10 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package fileutils exposes utilities to deal with files and paths.
|
||||
//
|
||||
// Currently, there is:
|
||||
// - [File] to represent an abstraction of an uploaded file.
|
||||
// For instance, this is used by [github.com/go-openapi/runtime.File].
|
||||
// - path search utilities (e.g. finding packages in the GO search path)
|
||||
package fileutils
|
||||
-22
@@ -1,22 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package fileutils
|
||||
|
||||
import "mime/multipart"
|
||||
|
||||
// File represents an uploaded file.
|
||||
type File struct {
|
||||
Data multipart.File
|
||||
Header *multipart.FileHeader
|
||||
}
|
||||
|
||||
// Read bytes from the file
|
||||
func (f *File) Read(p []byte) (n int, err error) {
|
||||
return f.Data.Read(p)
|
||||
}
|
||||
|
||||
// Close the file
|
||||
func (f *File) Close() error {
|
||||
return f.Data.Close()
|
||||
}
|
||||
-33
@@ -1,33 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package swag
|
||||
|
||||
import "github.com/go-openapi/swag/fileutils"
|
||||
|
||||
// GOPATHKey represents the env key for gopath
|
||||
//
|
||||
// Deprecated: use [fileutils.GOPATHKey] instead.
|
||||
const GOPATHKey = fileutils.GOPATHKey
|
||||
|
||||
// File represents an uploaded file.
|
||||
//
|
||||
// Deprecated: use [fileutils.File] instead.
|
||||
type File = fileutils.File
|
||||
|
||||
// FindInSearchPath finds a package in a provided lists of paths.
|
||||
//
|
||||
// Deprecated: use [fileutils.FindInSearchPath] instead.
|
||||
func FindInSearchPath(searchPath, pkg string) string {
|
||||
return fileutils.FindInSearchPath(searchPath, pkg)
|
||||
}
|
||||
|
||||
// FindInGoSearchPath finds a package in the $GOPATH:$GOROOT
|
||||
//
|
||||
// Deprecated: use [fileutils.FindInGoSearchPath] instead.
|
||||
func FindInGoSearchPath(pkg string) string { return fileutils.FindInGoSearchPath(pkg) }
|
||||
|
||||
// FullGoSearchPath gets the search paths for finding packages
|
||||
//
|
||||
// Deprecated: use [fileutils.FullGoSearchPath] instead.
|
||||
func FullGoSearchPath() string { return fileutils.FullGoSearchPath() }
|
||||
-20
@@ -1,20 +0,0 @@
|
||||
use (
|
||||
.
|
||||
./cmdutils
|
||||
./conv
|
||||
./fileutils
|
||||
./jsonname
|
||||
./jsonutils
|
||||
./jsonutils/adapters/easyjson
|
||||
./jsonutils/adapters/testintegration
|
||||
./jsonutils/adapters/testintegration/benchmarks
|
||||
./jsonutils/fixtures_test
|
||||
./loading
|
||||
./mangling
|
||||
./netutils
|
||||
./stringutils
|
||||
./typeutils
|
||||
./yamlutils
|
||||
)
|
||||
|
||||
go 1.24.0
|
||||
-7
@@ -1,7 +0,0 @@
|
||||
github.com/go-openapi/testify/v2 v2.0.1/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54=
|
||||
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/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
|
||||
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
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=
|
||||
+202
@@ -0,0 +1,202 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package swag
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var (
|
||||
// commonInitialisms are common acronyms that are kept as whole uppercased words.
|
||||
commonInitialisms *indexOfInitialisms
|
||||
|
||||
// initialisms is a slice of sorted initialisms
|
||||
initialisms []string
|
||||
|
||||
// a copy of initialisms pre-baked as []rune
|
||||
initialismsRunes [][]rune
|
||||
initialismsUpperCased [][]rune
|
||||
|
||||
isInitialism func(string) bool
|
||||
|
||||
maxAllocMatches int
|
||||
)
|
||||
|
||||
func init() {
|
||||
// Taken from https://github.com/golang/lint/blob/3390df4df2787994aea98de825b964ac7944b817/lint.go#L732-L769
|
||||
configuredInitialisms := map[string]bool{
|
||||
"ACL": true,
|
||||
"API": true,
|
||||
"ASCII": true,
|
||||
"CPU": true,
|
||||
"CSS": true,
|
||||
"DNS": true,
|
||||
"EOF": true,
|
||||
"GUID": true,
|
||||
"HTML": true,
|
||||
"HTTPS": true,
|
||||
"HTTP": true,
|
||||
"ID": true,
|
||||
"IP": true,
|
||||
"IPv4": true,
|
||||
"IPv6": true,
|
||||
"JSON": true,
|
||||
"LHS": true,
|
||||
"OAI": true,
|
||||
"QPS": true,
|
||||
"RAM": true,
|
||||
"RHS": true,
|
||||
"RPC": true,
|
||||
"SLA": true,
|
||||
"SMTP": true,
|
||||
"SQL": true,
|
||||
"SSH": true,
|
||||
"TCP": true,
|
||||
"TLS": true,
|
||||
"TTL": true,
|
||||
"UDP": true,
|
||||
"UI": true,
|
||||
"UID": true,
|
||||
"UUID": true,
|
||||
"URI": true,
|
||||
"URL": true,
|
||||
"UTF8": true,
|
||||
"VM": true,
|
||||
"XML": true,
|
||||
"XMPP": true,
|
||||
"XSRF": true,
|
||||
"XSS": true,
|
||||
}
|
||||
|
||||
// a thread-safe index of initialisms
|
||||
commonInitialisms = newIndexOfInitialisms().load(configuredInitialisms)
|
||||
initialisms = commonInitialisms.sorted()
|
||||
initialismsRunes = asRunes(initialisms)
|
||||
initialismsUpperCased = asUpperCased(initialisms)
|
||||
maxAllocMatches = maxAllocHeuristic(initialismsRunes)
|
||||
|
||||
// a test function
|
||||
isInitialism = commonInitialisms.isInitialism
|
||||
}
|
||||
|
||||
func asRunes(in []string) [][]rune {
|
||||
out := make([][]rune, len(in))
|
||||
for i, initialism := range in {
|
||||
out[i] = []rune(initialism)
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
func asUpperCased(in []string) [][]rune {
|
||||
out := make([][]rune, len(in))
|
||||
|
||||
for i, initialism := range in {
|
||||
out[i] = []rune(upper(trim(initialism)))
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
func maxAllocHeuristic(in [][]rune) int {
|
||||
heuristic := make(map[rune]int)
|
||||
for _, initialism := range in {
|
||||
heuristic[initialism[0]]++
|
||||
}
|
||||
|
||||
var maxAlloc int
|
||||
for _, val := range heuristic {
|
||||
if val > maxAlloc {
|
||||
maxAlloc = val
|
||||
}
|
||||
}
|
||||
|
||||
return maxAlloc
|
||||
}
|
||||
|
||||
// AddInitialisms add additional initialisms
|
||||
func AddInitialisms(words ...string) {
|
||||
for _, word := range words {
|
||||
// commonInitialisms[upper(word)] = true
|
||||
commonInitialisms.add(upper(word))
|
||||
}
|
||||
// sort again
|
||||
initialisms = commonInitialisms.sorted()
|
||||
initialismsRunes = asRunes(initialisms)
|
||||
initialismsUpperCased = asUpperCased(initialisms)
|
||||
}
|
||||
|
||||
// indexOfInitialisms is a thread-safe implementation of the sorted index of initialisms.
|
||||
// Since go1.9, this may be implemented with sync.Map.
|
||||
type indexOfInitialisms struct {
|
||||
sortMutex *sync.Mutex
|
||||
index *sync.Map
|
||||
}
|
||||
|
||||
func newIndexOfInitialisms() *indexOfInitialisms {
|
||||
return &indexOfInitialisms{
|
||||
sortMutex: new(sync.Mutex),
|
||||
index: new(sync.Map),
|
||||
}
|
||||
}
|
||||
|
||||
func (m *indexOfInitialisms) load(initial map[string]bool) *indexOfInitialisms {
|
||||
m.sortMutex.Lock()
|
||||
defer m.sortMutex.Unlock()
|
||||
for k, v := range initial {
|
||||
m.index.Store(k, v)
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
func (m *indexOfInitialisms) isInitialism(key string) bool {
|
||||
_, ok := m.index.Load(key)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (m *indexOfInitialisms) add(key string) *indexOfInitialisms {
|
||||
m.index.Store(key, true)
|
||||
return m
|
||||
}
|
||||
|
||||
func (m *indexOfInitialisms) sorted() (result []string) {
|
||||
m.sortMutex.Lock()
|
||||
defer m.sortMutex.Unlock()
|
||||
m.index.Range(func(key, _ interface{}) bool {
|
||||
k := key.(string)
|
||||
result = append(result, k)
|
||||
return true
|
||||
})
|
||||
sort.Sort(sort.Reverse(byInitialism(result)))
|
||||
return
|
||||
}
|
||||
|
||||
type byInitialism []string
|
||||
|
||||
func (s byInitialism) Len() int {
|
||||
return len(s)
|
||||
}
|
||||
func (s byInitialism) Swap(i, j int) {
|
||||
s[i], s[j] = s[j], s[i]
|
||||
}
|
||||
func (s byInitialism) Less(i, j int) bool {
|
||||
if len(s[i]) != len(s[j]) {
|
||||
return len(s[i]) < len(s[j])
|
||||
}
|
||||
|
||||
return strings.Compare(s[i], s[j]) > 0
|
||||
}
|
||||
+312
@@ -0,0 +1,312 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package swag
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"log"
|
||||
"reflect"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/mailru/easyjson/jlexer"
|
||||
"github.com/mailru/easyjson/jwriter"
|
||||
)
|
||||
|
||||
// nullJSON represents a JSON object with null type
|
||||
var nullJSON = []byte("null")
|
||||
|
||||
// DefaultJSONNameProvider the default cache for types
|
||||
var DefaultJSONNameProvider = NewNameProvider()
|
||||
|
||||
const comma = byte(',')
|
||||
|
||||
var closers map[byte]byte
|
||||
|
||||
func init() {
|
||||
closers = map[byte]byte{
|
||||
'{': '}',
|
||||
'[': ']',
|
||||
}
|
||||
}
|
||||
|
||||
type ejMarshaler interface {
|
||||
MarshalEasyJSON(w *jwriter.Writer)
|
||||
}
|
||||
|
||||
type ejUnmarshaler interface {
|
||||
UnmarshalEasyJSON(w *jlexer.Lexer)
|
||||
}
|
||||
|
||||
// WriteJSON writes json data, prefers finding an appropriate interface to short-circuit the marshaler
|
||||
// so it takes the fastest option available.
|
||||
func WriteJSON(data interface{}) ([]byte, error) {
|
||||
if d, ok := data.(ejMarshaler); ok {
|
||||
jw := new(jwriter.Writer)
|
||||
d.MarshalEasyJSON(jw)
|
||||
return jw.BuildBytes()
|
||||
}
|
||||
if d, ok := data.(json.Marshaler); ok {
|
||||
return d.MarshalJSON()
|
||||
}
|
||||
return json.Marshal(data)
|
||||
}
|
||||
|
||||
// ReadJSON reads json data, prefers finding an appropriate interface to short-circuit the unmarshaler
|
||||
// so it takes the fastest option available
|
||||
func ReadJSON(data []byte, value interface{}) error {
|
||||
trimmedData := bytes.Trim(data, "\x00")
|
||||
if d, ok := value.(ejUnmarshaler); ok {
|
||||
jl := &jlexer.Lexer{Data: trimmedData}
|
||||
d.UnmarshalEasyJSON(jl)
|
||||
return jl.Error()
|
||||
}
|
||||
if d, ok := value.(json.Unmarshaler); ok {
|
||||
return d.UnmarshalJSON(trimmedData)
|
||||
}
|
||||
return json.Unmarshal(trimmedData, value)
|
||||
}
|
||||
|
||||
// DynamicJSONToStruct converts an untyped json structure into a struct
|
||||
func DynamicJSONToStruct(data interface{}, target interface{}) error {
|
||||
// TODO: convert straight to a json typed map (mergo + iterate?)
|
||||
b, err := WriteJSON(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return ReadJSON(b, target)
|
||||
}
|
||||
|
||||
// ConcatJSON concatenates multiple json objects efficiently
|
||||
func ConcatJSON(blobs ...[]byte) []byte {
|
||||
if len(blobs) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
last := len(blobs) - 1
|
||||
for blobs[last] == nil || bytes.Equal(blobs[last], nullJSON) {
|
||||
// strips trailing null objects
|
||||
last--
|
||||
if last < 0 {
|
||||
// there was nothing but "null"s or nil...
|
||||
return nil
|
||||
}
|
||||
}
|
||||
if last == 0 {
|
||||
return blobs[0]
|
||||
}
|
||||
|
||||
var opening, closing byte
|
||||
var idx, a int
|
||||
buf := bytes.NewBuffer(nil)
|
||||
|
||||
for i, b := range blobs[:last+1] {
|
||||
if b == nil || bytes.Equal(b, nullJSON) {
|
||||
// a null object is in the list: skip it
|
||||
continue
|
||||
}
|
||||
if len(b) > 0 && opening == 0 { // is this an array or an object?
|
||||
opening, closing = b[0], closers[b[0]]
|
||||
}
|
||||
|
||||
if opening != '{' && opening != '[' {
|
||||
continue // don't know how to concatenate non container objects
|
||||
}
|
||||
|
||||
if len(b) < 3 { // yep empty but also the last one, so closing this thing
|
||||
if i == last && a > 0 {
|
||||
if err := buf.WriteByte(closing); err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
idx = 0
|
||||
if a > 0 { // we need to join with a comma for everything beyond the first non-empty item
|
||||
if err := buf.WriteByte(comma); err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
idx = 1 // this is not the first or the last so we want to drop the leading bracket
|
||||
}
|
||||
|
||||
if i != last { // not the last one, strip brackets
|
||||
if _, err := buf.Write(b[idx : len(b)-1]); err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
} else { // last one, strip only the leading bracket
|
||||
if _, err := buf.Write(b[idx:]); err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
a++
|
||||
}
|
||||
// somehow it ended up being empty, so provide a default value
|
||||
if buf.Len() == 0 {
|
||||
if err := buf.WriteByte(opening); err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
if err := buf.WriteByte(closing); err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
// ToDynamicJSON turns an object into a properly JSON typed structure
|
||||
func ToDynamicJSON(data interface{}) interface{} {
|
||||
// TODO: convert straight to a json typed map (mergo + iterate?)
|
||||
b, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
var res interface{}
|
||||
if err := json.Unmarshal(b, &res); err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// FromDynamicJSON turns an object into a properly JSON typed structure
|
||||
func FromDynamicJSON(data, target interface{}) error {
|
||||
b, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
return json.Unmarshal(b, target)
|
||||
}
|
||||
|
||||
// NameProvider represents an object capable of translating from go property names
|
||||
// to json property names
|
||||
// This type is thread-safe.
|
||||
type NameProvider struct {
|
||||
lock *sync.Mutex
|
||||
index map[reflect.Type]nameIndex
|
||||
}
|
||||
|
||||
type nameIndex struct {
|
||||
jsonNames map[string]string
|
||||
goNames map[string]string
|
||||
}
|
||||
|
||||
// NewNameProvider creates a new name provider
|
||||
func NewNameProvider() *NameProvider {
|
||||
return &NameProvider{
|
||||
lock: &sync.Mutex{},
|
||||
index: make(map[reflect.Type]nameIndex),
|
||||
}
|
||||
}
|
||||
|
||||
func buildnameIndex(tpe reflect.Type, idx, reverseIdx map[string]string) {
|
||||
for i := 0; i < tpe.NumField(); i++ {
|
||||
targetDes := tpe.Field(i)
|
||||
|
||||
if targetDes.PkgPath != "" { // unexported
|
||||
continue
|
||||
}
|
||||
|
||||
if targetDes.Anonymous { // walk embedded structures tree down first
|
||||
buildnameIndex(targetDes.Type, idx, reverseIdx)
|
||||
continue
|
||||
}
|
||||
|
||||
if tag := targetDes.Tag.Get("json"); tag != "" {
|
||||
|
||||
parts := strings.Split(tag, ",")
|
||||
if len(parts) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
nm := parts[0]
|
||||
if nm == "-" {
|
||||
continue
|
||||
}
|
||||
if nm == "" { // empty string means we want to use the Go name
|
||||
nm = targetDes.Name
|
||||
}
|
||||
|
||||
idx[nm] = targetDes.Name
|
||||
reverseIdx[targetDes.Name] = nm
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func newNameIndex(tpe reflect.Type) nameIndex {
|
||||
var idx = make(map[string]string, tpe.NumField())
|
||||
var reverseIdx = make(map[string]string, tpe.NumField())
|
||||
|
||||
buildnameIndex(tpe, idx, reverseIdx)
|
||||
return nameIndex{jsonNames: idx, goNames: reverseIdx}
|
||||
}
|
||||
|
||||
// GetJSONNames gets all the json property names for a type
|
||||
func (n *NameProvider) GetJSONNames(subject interface{}) []string {
|
||||
n.lock.Lock()
|
||||
defer n.lock.Unlock()
|
||||
tpe := reflect.Indirect(reflect.ValueOf(subject)).Type()
|
||||
names, ok := n.index[tpe]
|
||||
if !ok {
|
||||
names = n.makeNameIndex(tpe)
|
||||
}
|
||||
|
||||
res := make([]string, 0, len(names.jsonNames))
|
||||
for k := range names.jsonNames {
|
||||
res = append(res, k)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// GetJSONName gets the json name for a go property name
|
||||
func (n *NameProvider) GetJSONName(subject interface{}, name string) (string, bool) {
|
||||
tpe := reflect.Indirect(reflect.ValueOf(subject)).Type()
|
||||
return n.GetJSONNameForType(tpe, name)
|
||||
}
|
||||
|
||||
// GetJSONNameForType gets the json name for a go property name on a given type
|
||||
func (n *NameProvider) GetJSONNameForType(tpe reflect.Type, name string) (string, bool) {
|
||||
n.lock.Lock()
|
||||
defer n.lock.Unlock()
|
||||
names, ok := n.index[tpe]
|
||||
if !ok {
|
||||
names = n.makeNameIndex(tpe)
|
||||
}
|
||||
nme, ok := names.goNames[name]
|
||||
return nme, ok
|
||||
}
|
||||
|
||||
func (n *NameProvider) makeNameIndex(tpe reflect.Type) nameIndex {
|
||||
names := newNameIndex(tpe)
|
||||
n.index[tpe] = names
|
||||
return names
|
||||
}
|
||||
|
||||
// GetGoName gets the go name for a json property name
|
||||
func (n *NameProvider) GetGoName(subject interface{}, name string) (string, bool) {
|
||||
tpe := reflect.Indirect(reflect.ValueOf(subject)).Type()
|
||||
return n.GetGoNameForType(tpe, name)
|
||||
}
|
||||
|
||||
// GetGoNameForType gets the go name for a given type for a json property name
|
||||
func (n *NameProvider) GetGoNameForType(tpe reflect.Type, name string) (string, bool) {
|
||||
n.lock.Lock()
|
||||
defer n.lock.Unlock()
|
||||
names, ok := n.index[tpe]
|
||||
if !ok {
|
||||
names = n.makeNameIndex(tpe)
|
||||
}
|
||||
nme, ok := names.jsonNames[name]
|
||||
return nme, ok
|
||||
}
|
||||
-202
@@ -1,202 +0,0 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-5
@@ -1,5 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package jsonname is a provider of json property names from go properties.
|
||||
package jsonname
|
||||
-138
@@ -1,138 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package jsonname
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// DefaultJSONNameProvider is the default cache for types.
|
||||
var DefaultJSONNameProvider = NewNameProvider()
|
||||
|
||||
// NameProvider represents an object capable of translating from go property names
|
||||
// to json property names.
|
||||
//
|
||||
// This type is thread-safe.
|
||||
//
|
||||
// See [github.com/go-openapi/jsonpointer.Pointer] for an example.
|
||||
type NameProvider struct {
|
||||
lock *sync.Mutex
|
||||
index map[reflect.Type]nameIndex
|
||||
}
|
||||
|
||||
type nameIndex struct {
|
||||
jsonNames map[string]string
|
||||
goNames map[string]string
|
||||
}
|
||||
|
||||
// NewNameProvider creates a new name provider
|
||||
func NewNameProvider() *NameProvider {
|
||||
return &NameProvider{
|
||||
lock: &sync.Mutex{},
|
||||
index: make(map[reflect.Type]nameIndex),
|
||||
}
|
||||
}
|
||||
|
||||
func buildnameIndex(tpe reflect.Type, idx, reverseIdx map[string]string) {
|
||||
for i := 0; i < tpe.NumField(); i++ {
|
||||
targetDes := tpe.Field(i)
|
||||
|
||||
if targetDes.PkgPath != "" { // unexported
|
||||
continue
|
||||
}
|
||||
|
||||
if targetDes.Anonymous { // walk embedded structures tree down first
|
||||
buildnameIndex(targetDes.Type, idx, reverseIdx)
|
||||
continue
|
||||
}
|
||||
|
||||
if tag := targetDes.Tag.Get("json"); tag != "" {
|
||||
|
||||
parts := strings.Split(tag, ",")
|
||||
if len(parts) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
nm := parts[0]
|
||||
if nm == "-" {
|
||||
continue
|
||||
}
|
||||
if nm == "" { // empty string means we want to use the Go name
|
||||
nm = targetDes.Name
|
||||
}
|
||||
|
||||
idx[nm] = targetDes.Name
|
||||
reverseIdx[targetDes.Name] = nm
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func newNameIndex(tpe reflect.Type) nameIndex {
|
||||
var idx = make(map[string]string, tpe.NumField())
|
||||
var reverseIdx = make(map[string]string, tpe.NumField())
|
||||
|
||||
buildnameIndex(tpe, idx, reverseIdx)
|
||||
return nameIndex{jsonNames: idx, goNames: reverseIdx}
|
||||
}
|
||||
|
||||
// GetJSONNames gets all the json property names for a type
|
||||
func (n *NameProvider) GetJSONNames(subject any) []string {
|
||||
n.lock.Lock()
|
||||
defer n.lock.Unlock()
|
||||
tpe := reflect.Indirect(reflect.ValueOf(subject)).Type()
|
||||
names, ok := n.index[tpe]
|
||||
if !ok {
|
||||
names = n.makeNameIndex(tpe)
|
||||
}
|
||||
|
||||
res := make([]string, 0, len(names.jsonNames))
|
||||
for k := range names.jsonNames {
|
||||
res = append(res, k)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// GetJSONName gets the json name for a go property name
|
||||
func (n *NameProvider) GetJSONName(subject any, name string) (string, bool) {
|
||||
tpe := reflect.Indirect(reflect.ValueOf(subject)).Type()
|
||||
return n.GetJSONNameForType(tpe, name)
|
||||
}
|
||||
|
||||
// GetJSONNameForType gets the json name for a go property name on a given type
|
||||
func (n *NameProvider) GetJSONNameForType(tpe reflect.Type, name string) (string, bool) {
|
||||
n.lock.Lock()
|
||||
defer n.lock.Unlock()
|
||||
names, ok := n.index[tpe]
|
||||
if !ok {
|
||||
names = n.makeNameIndex(tpe)
|
||||
}
|
||||
nme, ok := names.goNames[name]
|
||||
return nme, ok
|
||||
}
|
||||
|
||||
// GetGoName gets the go name for a json property name
|
||||
func (n *NameProvider) GetGoName(subject any, name string) (string, bool) {
|
||||
tpe := reflect.Indirect(reflect.ValueOf(subject)).Type()
|
||||
return n.GetGoNameForType(tpe, name)
|
||||
}
|
||||
|
||||
// GetGoNameForType gets the go name for a given type for a json property name
|
||||
func (n *NameProvider) GetGoNameForType(tpe reflect.Type, name string) (string, bool) {
|
||||
n.lock.Lock()
|
||||
defer n.lock.Unlock()
|
||||
names, ok := n.index[tpe]
|
||||
if !ok {
|
||||
names = n.makeNameIndex(tpe)
|
||||
}
|
||||
nme, ok := names.jsonNames[name]
|
||||
return nme, ok
|
||||
}
|
||||
|
||||
func (n *NameProvider) makeNameIndex(tpe reflect.Type) nameIndex {
|
||||
names := newNameIndex(tpe)
|
||||
n.index[tpe] = names
|
||||
return names
|
||||
}
|
||||
-24
@@ -1,24 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package swag
|
||||
|
||||
import (
|
||||
"github.com/go-openapi/swag/jsonname"
|
||||
)
|
||||
|
||||
// DefaultJSONNameProvider is the default cache for types
|
||||
//
|
||||
// Deprecated: use [jsonname.DefaultJSONNameProvider] instead.
|
||||
var DefaultJSONNameProvider = jsonname.DefaultJSONNameProvider
|
||||
|
||||
// NameProvider represents an object capable of translating from go property names
|
||||
// to json property names.
|
||||
//
|
||||
// Deprecated: use [jsonname.NameProvider] instead.
|
||||
type NameProvider = jsonname.NameProvider
|
||||
|
||||
// NewNameProvider creates a new name provider
|
||||
//
|
||||
// Deprecated: use [jsonname.NewNameProvider] instead.
|
||||
func NewNameProvider() *NameProvider { return jsonname.NewNameProvider() }
|
||||
-202
@@ -1,202 +0,0 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-108
@@ -1,108 +0,0 @@
|
||||
# jsonutils
|
||||
|
||||
`jsonutils` exposes a few tools to work with JSON:
|
||||
|
||||
- a fast, simple `Concat` to concatenate (not merge) JSON objects and arrays
|
||||
- `FromDynamicJSON` to convert a data structure into a "dynamic JSON" data structure
|
||||
- `ReadJSON` and `WriteJSON` behave like `json.Unmarshal` and `json.Marshal`,
|
||||
with the ability to use another underlying serialization library through an `Adapter`
|
||||
configured at runtime
|
||||
- a `JSONMapSlice` structure that may be used to store JSON objects with the order of keys maintained
|
||||
|
||||
## Dynamic JSON
|
||||
|
||||
We call "dynamic JSON" the go data structure that results from unmarshaling JSON like this:
|
||||
|
||||
```go
|
||||
var value any
|
||||
jsonBytes := `{"a": 1, ... }`
|
||||
_ = json.Unmarshal(jsonBytes, &value)
|
||||
```
|
||||
|
||||
In this configuration, the standard library mappings are as follows:
|
||||
|
||||
| JSON | go |
|
||||
|-----------|------------------|
|
||||
| `number` | `float64` |
|
||||
| `string` | `string` |
|
||||
| `boolean` | `bool` |
|
||||
| `null` | `nil` |
|
||||
| `object` | `map[string]any` |
|
||||
| `array` | `[]any` |
|
||||
|
||||
## Map slices
|
||||
|
||||
When using `JSONMapSlice`, the ordering of keys is ensured by replacing
|
||||
mappings to `map[string]any` by a `JSONMapSlice` which is an (ordered)
|
||||
slice of `JSONMapItem`s.
|
||||
|
||||
Notice that a similar feature is available for YAML (see [`yamlutils`](../yamlutils)),
|
||||
with a `YAMLMapSlice` type based on the `JSONMapSlice`.
|
||||
|
||||
`JSONMapSlice` is similar to an ordered map, but the keys are not retrieved
|
||||
in constant time.
|
||||
|
||||
Another difference with the the above standard mappings is that numbers don't always map
|
||||
to a `float64`: if the value is a JSON integer, it unmarshals to `int64`.
|
||||
|
||||
See also [some examples](https://pkg.go.dev/github.com/go-openapi/swag/jsonutils#pkg-examples)
|
||||
|
||||
## Adapters
|
||||
|
||||
`ReadJSON`, `WriteJSON` and `FromDynamicJSON` (which is a combination of the latter two)
|
||||
are wrappers on top of `json.Unmarshal` and `json.Marshal`.
|
||||
|
||||
By default, the adapter merely wraps the standard library.
|
||||
|
||||
The adapter may be used to register other JSON serialization libraries,
|
||||
possibly several ones at the same time.
|
||||
|
||||
If the value passed is identified as an "ordered map" (i.e. implements `ifaces.Ordered`
|
||||
or `ifaces.SetOrdered`, the adapter favors the "ordered" JSON behavior and tries to
|
||||
find a registered implementation that support ordered keys in objects.
|
||||
|
||||
Our standard library implementation supports this.
|
||||
|
||||
As of `v0.25.0`, we support through such an adapter the popular `mailru/easyjson`
|
||||
library, which kicks in when the passed values support the `easyjson.Unmarshaler`
|
||||
or `easyjson.Marshaler` interfaces.
|
||||
|
||||
In the future, we plan to add more similar libraries that compete on the go JSON
|
||||
serializers scene.
|
||||
|
||||
## Registering an adapter
|
||||
|
||||
In package `github.com/go-openapi/swag/easyjson/adapters`, several adapters are available.
|
||||
|
||||
Each adapter is an independent go module. Hence you'll pick its dependencies only if you import it.
|
||||
|
||||
At this moment we provide:
|
||||
* `stdlib`: JSON adapter based on the standard library
|
||||
* `easyjson`: JSON adapter based on the `github.com/mailru/easyjson`
|
||||
|
||||
The adapters provide the basic `Marshal` and `Unmarshal` capabilities, plus an implementation
|
||||
of the `MapSlice` pattern.
|
||||
|
||||
You may also build your own adapter based on your specific use-case. An adapter is not required to implement
|
||||
all capabilities.
|
||||
|
||||
Every adapter comes with a `Register` function, possibly with some options, to register the adapter
|
||||
to a global registry.
|
||||
|
||||
For example, to enable `easyjson` to be used in `ReadJSON` and `WriteJSON`, you would write something like:
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/go-openapi/swag/jsonutils/adapters"
|
||||
easyjson "github.com/go-openapi/swag/jsonutils/adapters/easyjson/json"
|
||||
)
|
||||
|
||||
func init() {
|
||||
easyjson.Register(adapters.Registry)
|
||||
}
|
||||
```
|
||||
|
||||
You may register several adapters. In this case, capability matching is evaluated from the last registered
|
||||
adapters (LIFO).
|
||||
|
||||
## [Benchmarks](./adapters/testintegration/benchmarks/README.md)
|
||||
-8
@@ -1,8 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package adapters exposes a registry of adapters to multiple
|
||||
// JSON serialization libraries.
|
||||
//
|
||||
// All interfaces are defined in package [ifaces.Adapter].
|
||||
package adapters
|
||||
-5
@@ -1,5 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package ifaces exposes all interfaces to work with adapters.
|
||||
package ifaces
|
||||
-84
@@ -1,84 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package ifaces
|
||||
|
||||
import (
|
||||
_ "encoding/json" // for documentation purpose
|
||||
"iter"
|
||||
)
|
||||
|
||||
// Ordered knows how to iterate over the (key,value) pairs of a JSON object.
|
||||
type Ordered interface {
|
||||
OrderedItems() iter.Seq2[string, any]
|
||||
}
|
||||
|
||||
// SetOrdered knows how to append or update the keys of a JSON object,
|
||||
// given an iterator over (key,value) pairs.
|
||||
//
|
||||
// If the provided iterator is nil then the receiver should be set to nil.
|
||||
type SetOrdered interface {
|
||||
SetOrderedItems(iter.Seq2[string, any])
|
||||
}
|
||||
|
||||
// OrderedMap represent a JSON object (i.e. like a map[string,any]),
|
||||
// and knows how to serialize and deserialize JSON with the order of keys maintained.
|
||||
type OrderedMap interface {
|
||||
Ordered
|
||||
SetOrdered
|
||||
|
||||
OrderedMarshalJSON() ([]byte, error)
|
||||
OrderedUnmarshalJSON([]byte) error
|
||||
}
|
||||
|
||||
// MarshalAdapter behaves likes the standard library [json.Marshal].
|
||||
type MarshalAdapter interface {
|
||||
Poolable
|
||||
|
||||
Marshal(any) ([]byte, error)
|
||||
}
|
||||
|
||||
// OrderedMarshalAdapter behaves likes the standard library [json.Marshal], preserving the order of keys in objects.
|
||||
type OrderedMarshalAdapter interface {
|
||||
Poolable
|
||||
|
||||
OrderedMarshal(Ordered) ([]byte, error)
|
||||
}
|
||||
|
||||
// UnmarshalAdapter behaves likes the standard library [json.Unmarshal].
|
||||
type UnmarshalAdapter interface {
|
||||
Poolable
|
||||
|
||||
Unmarshal([]byte, any) error
|
||||
}
|
||||
|
||||
// OrderedUnmarshalAdapter behaves likes the standard library [json.Unmarshal], preserving the order of keys in objects.
|
||||
type OrderedUnmarshalAdapter interface {
|
||||
Poolable
|
||||
|
||||
OrderedUnmarshal([]byte, SetOrdered) error
|
||||
}
|
||||
|
||||
// Adapter exposes an interface like the standard [json] library.
|
||||
type Adapter interface {
|
||||
MarshalAdapter
|
||||
UnmarshalAdapter
|
||||
|
||||
OrderedAdapter
|
||||
}
|
||||
|
||||
// OrderedAdapter exposes interfaces to process JSON and keep the order of object keys.
|
||||
type OrderedAdapter interface {
|
||||
OrderedMarshalAdapter
|
||||
OrderedUnmarshalAdapter
|
||||
NewOrderedMap(capacity int) OrderedMap
|
||||
}
|
||||
|
||||
type Poolable interface {
|
||||
// Self-redeem: for [Adapter] s that are allocated from a pool.
|
||||
// The [Adapter] must not be used after calling [Redeem].
|
||||
Redeem()
|
||||
|
||||
// Reset the state of the [Adapter], if any.
|
||||
Reset()
|
||||
}
|
||||
-91
@@ -1,91 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package ifaces
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Capability indicates what a JSON adapter is capable of.
|
||||
type Capability uint8
|
||||
|
||||
const (
|
||||
CapabilityMarshalJSON Capability = 1 << iota
|
||||
CapabilityUnmarshalJSON
|
||||
CapabilityOrderedMarshalJSON
|
||||
CapabilityOrderedUnmarshalJSON
|
||||
CapabilityOrderedMap
|
||||
)
|
||||
|
||||
func (c Capability) String() string {
|
||||
switch c {
|
||||
case CapabilityMarshalJSON:
|
||||
return "MarshalJSON"
|
||||
case CapabilityUnmarshalJSON:
|
||||
return "UnmarshalJSON"
|
||||
case CapabilityOrderedMarshalJSON:
|
||||
return "OrderedMarshalJSON"
|
||||
case CapabilityOrderedUnmarshalJSON:
|
||||
return "OrderedUnmarshalJSON"
|
||||
case CapabilityOrderedMap:
|
||||
return "OrderedMap"
|
||||
default:
|
||||
return "<unknown>"
|
||||
}
|
||||
}
|
||||
|
||||
// Capabilities holds several unitary capability flags
|
||||
type Capabilities uint8
|
||||
|
||||
// Has some capability flag enabled.
|
||||
func (c Capabilities) Has(capability Capability) bool {
|
||||
return Capability(c)&capability > 0
|
||||
}
|
||||
|
||||
func (c Capabilities) String() string {
|
||||
var w strings.Builder
|
||||
|
||||
first := true
|
||||
for _, capability := range []Capability{
|
||||
CapabilityMarshalJSON,
|
||||
CapabilityUnmarshalJSON,
|
||||
CapabilityOrderedMarshalJSON,
|
||||
CapabilityOrderedUnmarshalJSON,
|
||||
CapabilityOrderedMap,
|
||||
} {
|
||||
if c.Has(capability) {
|
||||
if !first {
|
||||
w.WriteByte('|')
|
||||
} else {
|
||||
first = false
|
||||
}
|
||||
w.WriteString(capability.String())
|
||||
}
|
||||
}
|
||||
|
||||
return w.String()
|
||||
}
|
||||
|
||||
const (
|
||||
AllCapabilities Capabilities = Capabilities(uint8(CapabilityMarshalJSON) |
|
||||
uint8(CapabilityUnmarshalJSON) |
|
||||
uint8(CapabilityOrderedMarshalJSON) |
|
||||
uint8(CapabilityOrderedUnmarshalJSON) |
|
||||
uint8(CapabilityOrderedMap))
|
||||
|
||||
AllUnorderedCapabilities Capabilities = Capabilities(uint8(CapabilityMarshalJSON) | uint8(CapabilityUnmarshalJSON))
|
||||
)
|
||||
|
||||
// RegistryEntry describes how any given adapter registers its capabilities to the [Registrar].
|
||||
type RegistryEntry struct {
|
||||
Who string
|
||||
What Capabilities
|
||||
Constructor func() Adapter
|
||||
Support func(what Capability, value any) bool
|
||||
}
|
||||
|
||||
// Registrar is a type that knows how to keep registration calls from adapters.
|
||||
type Registrar interface {
|
||||
RegisterFor(RegistryEntry)
|
||||
}
|
||||
-229
@@ -1,229 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package adapters
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"slices"
|
||||
"sync"
|
||||
|
||||
"github.com/go-openapi/swag/jsonutils/adapters/ifaces"
|
||||
stdlib "github.com/go-openapi/swag/jsonutils/adapters/stdlib/json"
|
||||
)
|
||||
|
||||
// Registry holds the global registry for registered adapters.
|
||||
var Registry = NewRegistrar()
|
||||
|
||||
var (
|
||||
defaultRegistered = stdlib.Register
|
||||
|
||||
_ ifaces.Registrar = &Registrar{}
|
||||
)
|
||||
|
||||
type registryError string
|
||||
|
||||
func (e registryError) Error() string {
|
||||
return string(e)
|
||||
}
|
||||
|
||||
// ErrRegistry indicates an error returned by the [Registrar].
|
||||
var ErrRegistry registryError = "JSON adapters registry error"
|
||||
|
||||
type registry []*ifaces.RegistryEntry
|
||||
|
||||
// Registrar holds registered [ifaces.Adapters] for different serialization capabilities.
|
||||
//
|
||||
// Internally, it maintains a cache for data types that favor a given adapter.
|
||||
type Registrar struct {
|
||||
marshalerRegistry registry
|
||||
unmarshalerRegistry registry
|
||||
orderedMarshalerRegistry registry
|
||||
orderedUnmarshalerRegistry registry
|
||||
orderedMapRegistry registry
|
||||
|
||||
gmx sync.RWMutex
|
||||
|
||||
// cache indexed by value type, so we don't have to lookup
|
||||
marshalerCache map[reflect.Type]*ifaces.RegistryEntry
|
||||
unmarshalerCache map[reflect.Type]*ifaces.RegistryEntry
|
||||
orderedMarshalerCache map[reflect.Type]*ifaces.RegistryEntry
|
||||
orderedUnmarshalerCache map[reflect.Type]*ifaces.RegistryEntry
|
||||
orderedMapCache map[reflect.Type]*ifaces.RegistryEntry
|
||||
}
|
||||
|
||||
func NewRegistrar() *Registrar {
|
||||
r := &Registrar{}
|
||||
|
||||
r.marshalerRegistry = make(registry, 0, 1)
|
||||
r.unmarshalerRegistry = make(registry, 0, 1)
|
||||
r.orderedMarshalerRegistry = make(registry, 0, 1)
|
||||
r.orderedUnmarshalerRegistry = make(registry, 0, 1)
|
||||
r.orderedMapRegistry = make(registry, 0, 1)
|
||||
|
||||
r.marshalerCache = make(map[reflect.Type]*ifaces.RegistryEntry)
|
||||
r.unmarshalerCache = make(map[reflect.Type]*ifaces.RegistryEntry)
|
||||
r.orderedMarshalerCache = make(map[reflect.Type]*ifaces.RegistryEntry)
|
||||
r.orderedUnmarshalerCache = make(map[reflect.Type]*ifaces.RegistryEntry)
|
||||
r.orderedMapCache = make(map[reflect.Type]*ifaces.RegistryEntry)
|
||||
|
||||
defaultRegistered(r)
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
// ClearCache resets the internal type cache.
|
||||
func (r *Registrar) ClearCache() {
|
||||
r.gmx.Lock()
|
||||
r.clearCache()
|
||||
r.gmx.Unlock()
|
||||
}
|
||||
|
||||
// Reset the [Registrar] to its defaults.
|
||||
func (r *Registrar) Reset() {
|
||||
r.gmx.Lock()
|
||||
r.clearCache()
|
||||
r.marshalerRegistry = r.marshalerRegistry[:0]
|
||||
r.unmarshalerRegistry = r.unmarshalerRegistry[:0]
|
||||
r.orderedMarshalerRegistry = r.orderedMarshalerRegistry[:0]
|
||||
r.orderedUnmarshalerRegistry = r.orderedUnmarshalerRegistry[:0]
|
||||
r.orderedMapRegistry = r.orderedMapRegistry[:0]
|
||||
r.gmx.Unlock()
|
||||
|
||||
defaultRegistered(r)
|
||||
}
|
||||
|
||||
// RegisterFor registers an adapter for some JSON capabilities.
|
||||
func (r *Registrar) RegisterFor(entry ifaces.RegistryEntry) {
|
||||
r.gmx.Lock()
|
||||
if entry.What.Has(ifaces.CapabilityMarshalJSON) {
|
||||
e := entry
|
||||
e.What &= ifaces.Capabilities(ifaces.CapabilityMarshalJSON)
|
||||
r.marshalerRegistry = slices.Insert(r.marshalerRegistry, 0, &e)
|
||||
}
|
||||
if entry.What.Has(ifaces.CapabilityUnmarshalJSON) {
|
||||
e := entry
|
||||
e.What &= ifaces.Capabilities(ifaces.CapabilityUnmarshalJSON)
|
||||
r.unmarshalerRegistry = slices.Insert(r.unmarshalerRegistry, 0, &e)
|
||||
}
|
||||
if entry.What.Has(ifaces.CapabilityOrderedMarshalJSON) {
|
||||
e := entry
|
||||
e.What &= ifaces.Capabilities(ifaces.CapabilityOrderedMarshalJSON)
|
||||
r.orderedMarshalerRegistry = slices.Insert(r.orderedMarshalerRegistry, 0, &e)
|
||||
}
|
||||
if entry.What.Has(ifaces.CapabilityOrderedUnmarshalJSON) {
|
||||
e := entry
|
||||
e.What &= ifaces.Capabilities(ifaces.CapabilityOrderedUnmarshalJSON)
|
||||
r.orderedUnmarshalerRegistry = slices.Insert(r.orderedUnmarshalerRegistry, 0, &e)
|
||||
}
|
||||
if entry.What.Has(ifaces.CapabilityOrderedMap) {
|
||||
e := entry
|
||||
e.What &= ifaces.Capabilities(ifaces.CapabilityOrderedMap)
|
||||
r.orderedMapRegistry = slices.Insert(r.orderedMapRegistry, 0, &e)
|
||||
}
|
||||
r.gmx.Unlock()
|
||||
}
|
||||
|
||||
// AdapterFor returns an [ifaces.Adapter] that supports this capability for this type of value.
|
||||
//
|
||||
// The [ifaces.Adapter] may be redeemed to its pool using its Redeem() method, for adapters that support global
|
||||
// pooling. When this is not the case, the redeem function is just a no-operation.
|
||||
func (r *Registrar) AdapterFor(capability ifaces.Capability, value any) ifaces.Adapter {
|
||||
entry := r.findFirstFor(capability, value)
|
||||
if entry == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return entry.Constructor()
|
||||
}
|
||||
|
||||
func (r *Registrar) clearCache() {
|
||||
clear(r.marshalerCache)
|
||||
clear(r.unmarshalerCache)
|
||||
clear(r.orderedMarshalerCache)
|
||||
clear(r.orderedUnmarshalerCache)
|
||||
clear(r.orderedMapCache)
|
||||
}
|
||||
|
||||
func (r *Registrar) findFirstFor(capability ifaces.Capability, value any) *ifaces.RegistryEntry {
|
||||
switch capability {
|
||||
case ifaces.CapabilityMarshalJSON:
|
||||
return r.findFirstInRegistryFor(r.marshalerRegistry, r.marshalerCache, capability, value)
|
||||
case ifaces.CapabilityUnmarshalJSON:
|
||||
return r.findFirstInRegistryFor(r.unmarshalerRegistry, r.unmarshalerCache, capability, value)
|
||||
case ifaces.CapabilityOrderedMarshalJSON:
|
||||
return r.findFirstInRegistryFor(r.orderedMarshalerRegistry, r.orderedMarshalerCache, capability, value)
|
||||
case ifaces.CapabilityOrderedUnmarshalJSON:
|
||||
return r.findFirstInRegistryFor(r.orderedUnmarshalerRegistry, r.orderedUnmarshalerCache, capability, value)
|
||||
case ifaces.CapabilityOrderedMap:
|
||||
return r.findFirstInRegistryFor(r.orderedMapRegistry, r.orderedMapCache, capability, value)
|
||||
default:
|
||||
panic(fmt.Errorf("unsupported capability %d: %w", capability, ErrRegistry))
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Registrar) findFirstInRegistryFor(reg registry, cache map[reflect.Type]*ifaces.RegistryEntry, capability ifaces.Capability, value any) *ifaces.RegistryEntry {
|
||||
r.gmx.RLock()
|
||||
if len(reg) > 1 {
|
||||
if entry, ok := cache[reflect.TypeOf(value)]; ok {
|
||||
// cache hit
|
||||
r.gmx.RUnlock()
|
||||
return entry
|
||||
}
|
||||
}
|
||||
|
||||
for _, entry := range reg {
|
||||
if !entry.Support(capability, value) {
|
||||
continue
|
||||
}
|
||||
|
||||
r.gmx.RUnlock()
|
||||
|
||||
// update the internal cache
|
||||
r.gmx.Lock()
|
||||
cache[reflect.TypeOf(value)] = entry
|
||||
r.gmx.Unlock()
|
||||
|
||||
return entry
|
||||
}
|
||||
|
||||
// no adapter found
|
||||
r.gmx.RUnlock()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalAdapterFor returns the first adapter that knows how to Marshal this type of value.
|
||||
func MarshalAdapterFor(value any) ifaces.MarshalAdapter {
|
||||
return Registry.AdapterFor(ifaces.CapabilityMarshalJSON, value)
|
||||
}
|
||||
|
||||
// OrderedMarshalAdapterFor returns the first adapter that knows how to OrderedMarshal this type of value.
|
||||
func OrderedMarshalAdapterFor(value ifaces.Ordered) ifaces.OrderedMarshalAdapter {
|
||||
return Registry.AdapterFor(ifaces.CapabilityOrderedMarshalJSON, value)
|
||||
}
|
||||
|
||||
// UnmarshalAdapterFor returns the first adapter that knows how to Unmarshal this type of value.
|
||||
func UnmarshalAdapterFor(value any) ifaces.UnmarshalAdapter {
|
||||
return Registry.AdapterFor(ifaces.CapabilityUnmarshalJSON, value)
|
||||
}
|
||||
|
||||
// OrderedUnmarshalAdapterFor provides the first adapter that knows how to OrderedUnmarshal this type of value.
|
||||
func OrderedUnmarshalAdapterFor(value ifaces.SetOrdered) ifaces.OrderedUnmarshalAdapter {
|
||||
return Registry.AdapterFor(ifaces.CapabilityOrderedUnmarshalJSON, value)
|
||||
}
|
||||
|
||||
// NewOrderedMap provides the "ordered map" implementation provided by the registry.
|
||||
func NewOrderedMap(capacity int) ifaces.OrderedMap {
|
||||
var v any
|
||||
adapter := Registry.AdapterFor(ifaces.CapabilityOrderedUnmarshalJSON, v)
|
||||
if adapter == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
defer adapter.Redeem()
|
||||
return adapter.NewOrderedMap(capacity)
|
||||
}
|
||||
|
||||
func noopRedeemer() {}
|
||||
-115
@@ -1,115 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package json
|
||||
|
||||
import (
|
||||
stdjson "encoding/json"
|
||||
|
||||
"github.com/go-openapi/swag/jsonutils/adapters/ifaces"
|
||||
"github.com/go-openapi/swag/typeutils"
|
||||
)
|
||||
|
||||
const sensibleBufferSize = 8192
|
||||
|
||||
type jsonError string
|
||||
|
||||
func (e jsonError) Error() string {
|
||||
return string(e)
|
||||
}
|
||||
|
||||
// ErrStdlib indicates that an error comes from the stdlib JSON adapter
|
||||
var ErrStdlib jsonError = "error from the JSON adapter stdlib"
|
||||
|
||||
var _ ifaces.Adapter = &Adapter{}
|
||||
|
||||
type Adapter struct {
|
||||
}
|
||||
|
||||
// NewAdapter yields an [ifaces.Adapter] using the standard library.
|
||||
func NewAdapter() *Adapter {
|
||||
return &Adapter{}
|
||||
}
|
||||
|
||||
func (a *Adapter) Marshal(value any) ([]byte, error) {
|
||||
return stdjson.Marshal(value)
|
||||
}
|
||||
|
||||
func (a *Adapter) Unmarshal(data []byte, value any) error {
|
||||
return stdjson.Unmarshal(data, value)
|
||||
}
|
||||
|
||||
func (a *Adapter) OrderedMarshal(value ifaces.Ordered) ([]byte, error) {
|
||||
w := poolOfWriters.Borrow()
|
||||
defer func() {
|
||||
poolOfWriters.Redeem(w)
|
||||
}()
|
||||
|
||||
if typeutils.IsNil(value) {
|
||||
w.RawString("null")
|
||||
|
||||
return w.BuildBytes()
|
||||
}
|
||||
|
||||
w.RawByte('{')
|
||||
first := true
|
||||
for k, v := range value.OrderedItems() {
|
||||
if first {
|
||||
first = false
|
||||
} else {
|
||||
w.RawByte(',')
|
||||
}
|
||||
|
||||
w.String(k)
|
||||
w.RawByte(':')
|
||||
|
||||
switch val := v.(type) {
|
||||
case ifaces.Ordered:
|
||||
w.Raw(a.OrderedMarshal(val))
|
||||
default:
|
||||
w.Raw(stdjson.Marshal(v))
|
||||
}
|
||||
}
|
||||
|
||||
w.RawByte('}')
|
||||
|
||||
return w.BuildBytes()
|
||||
}
|
||||
|
||||
func (a *Adapter) OrderedUnmarshal(data []byte, value ifaces.SetOrdered) error {
|
||||
var m MapSlice
|
||||
if err := m.OrderedUnmarshalJSON(data); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if typeutils.IsNil(m) {
|
||||
// force input value to nil
|
||||
value.SetOrderedItems(nil)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
value.SetOrderedItems(m.OrderedItems())
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *Adapter) NewOrderedMap(capacity int) ifaces.OrderedMap {
|
||||
m := make(MapSlice, 0, capacity)
|
||||
|
||||
return &m
|
||||
}
|
||||
|
||||
// Redeem the [Adapter] when it comes from a pool.
|
||||
//
|
||||
// The adapter becomes immediately unusable once redeemed.
|
||||
func (a *Adapter) Redeem() {
|
||||
if a == nil {
|
||||
return
|
||||
}
|
||||
|
||||
RedeemAdapter(a)
|
||||
}
|
||||
|
||||
func (a *Adapter) Reset() {
|
||||
}
|
||||
-5
@@ -1,5 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package json implements an [ifaces.Adapter] using the standard library.
|
||||
package json
|
||||
-320
@@ -1,320 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package json
|
||||
|
||||
import (
|
||||
stdjson "encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"strconv"
|
||||
|
||||
"github.com/go-openapi/swag/conv"
|
||||
)
|
||||
|
||||
type token struct {
|
||||
stdjson.Token
|
||||
}
|
||||
|
||||
func (t token) String() string {
|
||||
if t == invalidToken {
|
||||
return "invalid token"
|
||||
}
|
||||
if t == eofToken {
|
||||
return "EOF"
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%v", t.Token)
|
||||
}
|
||||
|
||||
func (t token) Kind() tokenKind {
|
||||
switch t.Token.(type) {
|
||||
case nil:
|
||||
return tokenNull
|
||||
case stdjson.Delim:
|
||||
return tokenDelim
|
||||
case bool:
|
||||
return tokenBool
|
||||
case float64:
|
||||
return tokenFloat
|
||||
case stdjson.Number:
|
||||
return tokenNumber
|
||||
case string:
|
||||
return tokenString
|
||||
default:
|
||||
return tokenUndef
|
||||
}
|
||||
}
|
||||
|
||||
func (t token) Delim() byte {
|
||||
r, ok := t.Token.(stdjson.Delim)
|
||||
if !ok {
|
||||
return 0
|
||||
}
|
||||
|
||||
return byte(r)
|
||||
}
|
||||
|
||||
type tokenKind uint8
|
||||
|
||||
const (
|
||||
tokenUndef tokenKind = iota
|
||||
tokenString
|
||||
tokenNumber
|
||||
tokenFloat
|
||||
tokenBool
|
||||
tokenNull
|
||||
tokenDelim
|
||||
)
|
||||
|
||||
var (
|
||||
invalidToken = token{
|
||||
Token: stdjson.Token(struct{}{}),
|
||||
}
|
||||
|
||||
eofToken = token{
|
||||
Token: stdjson.Token(&struct{}{}),
|
||||
}
|
||||
|
||||
undefToken = token{
|
||||
Token: stdjson.Token(uint8(0)),
|
||||
}
|
||||
)
|
||||
|
||||
// jlexer apes easyjson's jlexer, but uses the standard library decoder under the hood.
|
||||
type jlexer struct {
|
||||
buf *bytesReader
|
||||
dec *stdjson.Decoder
|
||||
err error
|
||||
// current token
|
||||
next token
|
||||
// started bool
|
||||
}
|
||||
|
||||
type bytesReader struct {
|
||||
buf []byte
|
||||
offset int
|
||||
}
|
||||
|
||||
func (b *bytesReader) Reset() {
|
||||
b.buf = nil
|
||||
b.offset = 0
|
||||
}
|
||||
|
||||
func (b *bytesReader) Read(p []byte) (int, error) {
|
||||
if b.offset >= len(b.buf) {
|
||||
return 0, io.EOF
|
||||
}
|
||||
|
||||
n := len(p)
|
||||
buf := b.buf[b.offset:]
|
||||
m := len(buf)
|
||||
|
||||
if n >= m {
|
||||
copy(p, buf)
|
||||
b.offset += m
|
||||
|
||||
return m, nil
|
||||
}
|
||||
|
||||
copy(p, buf[:n])
|
||||
b.offset += n
|
||||
|
||||
return n, nil
|
||||
}
|
||||
|
||||
var _ io.Reader = &bytesReader{}
|
||||
|
||||
func newLexer(data []byte) *jlexer {
|
||||
l := &jlexer{
|
||||
// current: undefToken,
|
||||
next: undefToken,
|
||||
}
|
||||
l.buf = &bytesReader{
|
||||
buf: data,
|
||||
}
|
||||
l.dec = stdjson.NewDecoder(l.buf) // unfortunately, cannot pool this
|
||||
|
||||
return l
|
||||
}
|
||||
|
||||
func (l *jlexer) Reset() {
|
||||
l.err = nil
|
||||
l.next = undefToken
|
||||
// leave l.dec and l.buf alone, since they are replaced at every Borrow
|
||||
}
|
||||
|
||||
func (l *jlexer) Error() error {
|
||||
return l.err
|
||||
}
|
||||
|
||||
func (l *jlexer) SetErr(err error) {
|
||||
l.err = err
|
||||
}
|
||||
|
||||
func (l *jlexer) Ok() bool {
|
||||
return l.err == nil
|
||||
}
|
||||
|
||||
// NextToken consumes a token
|
||||
func (l *jlexer) NextToken() token {
|
||||
if !l.Ok() {
|
||||
return invalidToken
|
||||
}
|
||||
|
||||
if l.next != undefToken {
|
||||
next := l.next
|
||||
l.next = undefToken
|
||||
|
||||
return next
|
||||
}
|
||||
|
||||
return l.fetchToken()
|
||||
}
|
||||
|
||||
// PeekToken returns the next token without consuming it
|
||||
func (l *jlexer) PeekToken() token {
|
||||
if l.next == undefToken {
|
||||
l.next = l.fetchToken()
|
||||
}
|
||||
|
||||
return l.next
|
||||
}
|
||||
|
||||
func (l *jlexer) Skip() {
|
||||
_ = l.NextToken()
|
||||
}
|
||||
|
||||
func (l *jlexer) IsDelim(c byte) bool {
|
||||
if !l.Ok() {
|
||||
return false
|
||||
}
|
||||
|
||||
next := l.PeekToken()
|
||||
if next.Kind() != tokenDelim {
|
||||
return false
|
||||
}
|
||||
|
||||
if next.Delim() != c {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (l *jlexer) IsNull() bool {
|
||||
if !l.Ok() {
|
||||
return false
|
||||
}
|
||||
|
||||
next := l.PeekToken()
|
||||
|
||||
return next.Kind() == tokenNull
|
||||
}
|
||||
|
||||
func (l *jlexer) Delim(c byte) {
|
||||
if !l.Ok() {
|
||||
return
|
||||
}
|
||||
|
||||
tok := l.NextToken()
|
||||
if tok.Kind() != tokenDelim {
|
||||
l.err = fmt.Errorf("expected a delimiter token but got '%v': %w", tok, ErrStdlib)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if tok.Delim() != c {
|
||||
l.err = fmt.Errorf("expected delimiter '%q' but got '%q': %w", c, tok.Delim(), ErrStdlib)
|
||||
}
|
||||
}
|
||||
|
||||
func (l *jlexer) Null() {
|
||||
if !l.Ok() {
|
||||
return
|
||||
}
|
||||
|
||||
tok := l.NextToken()
|
||||
if tok.Kind() != tokenNull {
|
||||
l.err = fmt.Errorf("expected a null token but got '%v': %w", tok, ErrStdlib)
|
||||
}
|
||||
}
|
||||
|
||||
func (l *jlexer) Number() any {
|
||||
if !l.Ok() {
|
||||
return 0
|
||||
}
|
||||
|
||||
tok := l.NextToken()
|
||||
|
||||
switch tok.Kind() { //nolint:exhaustive
|
||||
case tokenNumber:
|
||||
n := tok.Token.(stdjson.Number).String()
|
||||
f, _ := strconv.ParseFloat(n, 64)
|
||||
if conv.IsFloat64AJSONInteger(f) {
|
||||
return int64(math.Trunc(f))
|
||||
}
|
||||
|
||||
return f
|
||||
|
||||
case tokenFloat:
|
||||
f := tok.Token.(float64)
|
||||
if conv.IsFloat64AJSONInteger(f) {
|
||||
return int64(math.Trunc(f))
|
||||
}
|
||||
|
||||
return f
|
||||
|
||||
default:
|
||||
l.err = fmt.Errorf("expected a number token but got '%v': %w", tok, ErrStdlib)
|
||||
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
func (l *jlexer) Bool() bool {
|
||||
if !l.Ok() {
|
||||
return false
|
||||
}
|
||||
|
||||
tok := l.NextToken()
|
||||
if tok.Kind() != tokenBool {
|
||||
l.err = fmt.Errorf("expected a bool token but got '%v': %w", tok, ErrStdlib)
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
return tok.Token.(bool)
|
||||
}
|
||||
|
||||
func (l *jlexer) String() string {
|
||||
if !l.Ok() {
|
||||
return ""
|
||||
}
|
||||
|
||||
tok := l.NextToken()
|
||||
if tok.Kind() != tokenString {
|
||||
l.err = fmt.Errorf("expected a string token but got '%v': %w", tok, ErrStdlib)
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
return tok.Token.(string)
|
||||
}
|
||||
|
||||
// Commas and colons are elided.
|
||||
func (l *jlexer) fetchToken() token {
|
||||
jtok, err := l.dec.Token()
|
||||
if err != nil {
|
||||
if errors.Is(err, io.EOF) {
|
||||
return eofToken
|
||||
}
|
||||
|
||||
l.err = errors.Join(err, ErrStdlib)
|
||||
return invalidToken
|
||||
}
|
||||
|
||||
return token{Token: jtok}
|
||||
}
|
||||
-266
@@ -1,266 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package json
|
||||
|
||||
import (
|
||||
stdjson "encoding/json"
|
||||
"fmt"
|
||||
"iter"
|
||||
|
||||
"github.com/go-openapi/swag/jsonutils/adapters/ifaces"
|
||||
)
|
||||
|
||||
var _ ifaces.OrderedMap = &MapSlice{}
|
||||
|
||||
// MapSlice represents a JSON object, with the order of keys maintained.
|
||||
type MapSlice []MapItem
|
||||
|
||||
func (s MapSlice) OrderedItems() iter.Seq2[string, any] {
|
||||
return func(yield func(string, any) bool) {
|
||||
for _, item := range s {
|
||||
if !yield(item.Key, item.Value) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *MapSlice) SetOrderedItems(items iter.Seq2[string, any]) {
|
||||
if items == nil {
|
||||
*s = nil
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
m := *s
|
||||
if len(m) > 0 {
|
||||
// update mode
|
||||
idx := make(map[string]int, len(m))
|
||||
|
||||
for i, item := range m {
|
||||
idx[item.Key] = i
|
||||
}
|
||||
|
||||
for k, v := range items {
|
||||
idx, ok := idx[k]
|
||||
if ok {
|
||||
m[idx].Value = v
|
||||
|
||||
continue
|
||||
}
|
||||
m = append(m, MapItem{Key: k, Value: v})
|
||||
}
|
||||
|
||||
*s = m
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
for k, v := range items {
|
||||
m = append(m, MapItem{Key: k, Value: v})
|
||||
}
|
||||
|
||||
*s = m
|
||||
}
|
||||
|
||||
// MarshalJSON renders a [MapSlice] as JSON bytes, preserving the order of keys.
|
||||
func (s MapSlice) MarshalJSON() ([]byte, error) {
|
||||
return s.OrderedMarshalJSON()
|
||||
}
|
||||
|
||||
func (s MapSlice) OrderedMarshalJSON() ([]byte, error) {
|
||||
w := poolOfWriters.Borrow()
|
||||
defer func() {
|
||||
poolOfWriters.Redeem(w)
|
||||
}()
|
||||
|
||||
s.marshalObject(w)
|
||||
|
||||
return w.BuildBytes() // this clones data, so it's okay to redeem the writer and its buffer
|
||||
}
|
||||
|
||||
// UnmarshalJSON builds a [MapSlice] from JSON bytes, preserving the order of keys.
|
||||
//
|
||||
// Inner objects are unmarshaled as [MapSlice] slices and not map[string]any.
|
||||
func (s *MapSlice) UnmarshalJSON(data []byte) error {
|
||||
return s.OrderedUnmarshalJSON(data)
|
||||
}
|
||||
|
||||
func (s *MapSlice) OrderedUnmarshalJSON(data []byte) error {
|
||||
l := poolOfLexers.Borrow(data)
|
||||
defer func() {
|
||||
poolOfLexers.Redeem(l)
|
||||
}()
|
||||
|
||||
s.unmarshalObject(l)
|
||||
|
||||
return l.Error()
|
||||
}
|
||||
|
||||
func (s MapSlice) marshalObject(w *jwriter) {
|
||||
if s == nil {
|
||||
w.RawString("null")
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
w.RawByte('{')
|
||||
|
||||
if len(s) == 0 {
|
||||
w.RawByte('}')
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
s[0].marshalJSON(w)
|
||||
|
||||
for i := 1; i < len(s); i++ {
|
||||
w.RawByte(',')
|
||||
s[i].marshalJSON(w)
|
||||
}
|
||||
|
||||
w.RawByte('}')
|
||||
}
|
||||
|
||||
func (s *MapSlice) unmarshalObject(in *jlexer) {
|
||||
if in.IsNull() {
|
||||
in.Skip()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
in.Delim('{') // consume token
|
||||
if !in.Ok() {
|
||||
return
|
||||
}
|
||||
|
||||
result := make(MapSlice, 0)
|
||||
|
||||
for in.Ok() && !in.IsDelim('}') {
|
||||
var mi MapItem
|
||||
|
||||
mi.unmarshalKeyValue(in)
|
||||
result = append(result, mi)
|
||||
}
|
||||
|
||||
in.Delim('}')
|
||||
|
||||
if !in.Ok() {
|
||||
return
|
||||
}
|
||||
|
||||
*s = result
|
||||
}
|
||||
|
||||
// MapItem represents the value of a key in a JSON object held by [MapSlice].
|
||||
//
|
||||
// Notice that [MapItem] should not be marshaled to or unmarshaled from JSON directly,
|
||||
// use this type as part of a [MapSlice] when dealing with JSON bytes.
|
||||
type MapItem struct {
|
||||
Key string
|
||||
Value any
|
||||
}
|
||||
|
||||
func (s MapItem) marshalJSON(w *jwriter) {
|
||||
w.String(s.Key)
|
||||
w.RawByte(':')
|
||||
w.Raw(stdjson.Marshal(s.Value))
|
||||
}
|
||||
|
||||
func (s *MapItem) unmarshalKeyValue(in *jlexer) {
|
||||
key := in.String() // consume string
|
||||
value := s.asInterface(in) // consume any value, including termination tokens '}' or ']'
|
||||
|
||||
if !in.Ok() {
|
||||
return
|
||||
}
|
||||
|
||||
s.Key = key
|
||||
s.Value = value
|
||||
}
|
||||
|
||||
func (s *MapItem) unmarshalArray(in *jlexer) []any {
|
||||
if in.IsNull() {
|
||||
in.Skip()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
in.Delim('[') // consume token
|
||||
if !in.Ok() {
|
||||
return nil
|
||||
}
|
||||
|
||||
ret := make([]any, 0)
|
||||
|
||||
for in.Ok() && !in.IsDelim(']') {
|
||||
ret = append(ret, s.asInterface(in))
|
||||
}
|
||||
|
||||
in.Delim(']')
|
||||
if !in.Ok() {
|
||||
return nil
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
// asInterface is very much like [jlexer.Lexer.Interface], but unmarshals an object
|
||||
// into a [MapSlice], not a map[string]any.
|
||||
//
|
||||
// We have to force parsing errors somehow, since [jlexer.Lexer] doesn't let us
|
||||
// set a parsing error directly.
|
||||
func (s *MapItem) asInterface(in *jlexer) any {
|
||||
if !in.Ok() {
|
||||
return nil
|
||||
}
|
||||
|
||||
tok := in.PeekToken() // look-ahead what the next token looks like
|
||||
kind := tok.Kind()
|
||||
|
||||
switch kind {
|
||||
case tokenString:
|
||||
return in.String() // consume string
|
||||
|
||||
case tokenNumber, tokenFloat:
|
||||
return in.Number()
|
||||
|
||||
case tokenBool:
|
||||
return in.Bool()
|
||||
|
||||
case tokenNull:
|
||||
in.Null()
|
||||
|
||||
return nil
|
||||
|
||||
case tokenDelim:
|
||||
switch tok.Delim() {
|
||||
case '{': // not consumed yet
|
||||
ret := make(MapSlice, 0)
|
||||
ret.unmarshalObject(in) // consumes the terminating '}'
|
||||
|
||||
if in.Ok() {
|
||||
return ret
|
||||
}
|
||||
|
||||
// lexer is in an error state: will exhaust
|
||||
return nil
|
||||
|
||||
case '[': // not consumed yet
|
||||
return s.unmarshalArray(in) // consumes the terminating ']'
|
||||
default:
|
||||
in.SetErr(fmt.Errorf("unexpected delimiter: %v: %w", tok, ErrStdlib)) // force error
|
||||
return nil
|
||||
}
|
||||
|
||||
case tokenUndef:
|
||||
fallthrough
|
||||
default:
|
||||
if in.Ok() {
|
||||
in.SetErr(fmt.Errorf("unexpected token: %v: %w", tok, ErrStdlib)) // force error
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
-143
@@ -1,143 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package json
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"sync"
|
||||
|
||||
"github.com/go-openapi/swag/jsonutils/adapters/ifaces"
|
||||
)
|
||||
|
||||
type adaptersPool struct {
|
||||
sync.Pool
|
||||
}
|
||||
|
||||
func (p *adaptersPool) Borrow() *Adapter {
|
||||
return p.Get().(*Adapter)
|
||||
}
|
||||
|
||||
func (p *adaptersPool) BorrowIface() ifaces.Adapter {
|
||||
return p.Get().(*Adapter)
|
||||
}
|
||||
|
||||
func (p *adaptersPool) Redeem(a *Adapter) {
|
||||
p.Put(a)
|
||||
}
|
||||
|
||||
type writersPool struct {
|
||||
sync.Pool
|
||||
}
|
||||
|
||||
func (p *writersPool) Borrow() *jwriter {
|
||||
ptr := p.Get()
|
||||
|
||||
jw := ptr.(*jwriter)
|
||||
jw.Reset()
|
||||
|
||||
return jw
|
||||
}
|
||||
|
||||
func (p *writersPool) Redeem(w *jwriter) {
|
||||
p.Put(w)
|
||||
}
|
||||
|
||||
type lexersPool struct {
|
||||
sync.Pool
|
||||
}
|
||||
|
||||
func (p *lexersPool) Borrow(data []byte) *jlexer {
|
||||
ptr := p.Get()
|
||||
|
||||
l := ptr.(*jlexer)
|
||||
l.buf = poolOfReaders.Borrow(data)
|
||||
l.dec = json.NewDecoder(l.buf) // cannot pool, not exposed by the encoding/json API
|
||||
l.Reset()
|
||||
|
||||
return l
|
||||
}
|
||||
|
||||
func (p *lexersPool) Redeem(l *jlexer) {
|
||||
l.dec = nil
|
||||
discard := l.buf
|
||||
l.buf = nil
|
||||
poolOfReaders.Redeem(discard)
|
||||
p.Put(l)
|
||||
}
|
||||
|
||||
type readersPool struct {
|
||||
sync.Pool
|
||||
}
|
||||
|
||||
func (p *readersPool) Borrow(data []byte) *bytesReader {
|
||||
ptr := p.Get()
|
||||
|
||||
b := ptr.(*bytesReader)
|
||||
b.Reset()
|
||||
b.buf = data
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
func (p *readersPool) Redeem(b *bytesReader) {
|
||||
p.Put(b)
|
||||
}
|
||||
|
||||
var (
|
||||
poolOfAdapters = &adaptersPool{
|
||||
Pool: sync.Pool{
|
||||
New: func() any {
|
||||
return NewAdapter()
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
poolOfWriters = &writersPool{
|
||||
Pool: sync.Pool{
|
||||
New: func() any {
|
||||
return newJWriter()
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
poolOfLexers = &lexersPool{
|
||||
Pool: sync.Pool{
|
||||
New: func() any {
|
||||
return newLexer(nil)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
poolOfReaders = &readersPool{
|
||||
Pool: sync.Pool{
|
||||
New: func() any {
|
||||
return &bytesReader{}
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
// BorrowAdapter borrows an [Adapter] from the pool, recycling already allocated instances.
|
||||
func BorrowAdapter() *Adapter {
|
||||
return poolOfAdapters.Borrow()
|
||||
}
|
||||
|
||||
// BorrowAdapterIface borrows a stdlib [Adapter] and converts it directly
|
||||
// to [ifaces.Adapter]. This is useful to avoid further allocations when
|
||||
// translating the concrete type into an interface.
|
||||
func BorrowAdapterIface() ifaces.Adapter {
|
||||
return poolOfAdapters.BorrowIface()
|
||||
}
|
||||
|
||||
// RedeemAdapter redeems an [Adapter] to the pool, so it may be recycled.
|
||||
func RedeemAdapter(a *Adapter) {
|
||||
poolOfAdapters.Redeem(a)
|
||||
}
|
||||
|
||||
func RedeemAdapterIface(a ifaces.Adapter) {
|
||||
concrete, ok := a.(*Adapter)
|
||||
if ok {
|
||||
poolOfAdapters.Redeem(concrete)
|
||||
}
|
||||
}
|
||||
-26
@@ -1,26 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package json
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/go-openapi/swag/jsonutils/adapters/ifaces"
|
||||
)
|
||||
|
||||
func Register(dispatcher ifaces.Registrar) {
|
||||
t := reflect.TypeOf(Adapter{})
|
||||
dispatcher.RegisterFor(
|
||||
ifaces.RegistryEntry{
|
||||
Who: fmt.Sprintf("%s.%s", t.PkgPath(), t.Name()),
|
||||
What: ifaces.AllCapabilities,
|
||||
Constructor: BorrowAdapterIface,
|
||||
Support: support,
|
||||
})
|
||||
}
|
||||
|
||||
func support(_ ifaces.Capability, _ any) bool {
|
||||
return true
|
||||
}
|
||||
-75
@@ -1,75 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package json
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type jwriter struct {
|
||||
buf *bytes.Buffer
|
||||
err error
|
||||
}
|
||||
|
||||
func newJWriter() *jwriter {
|
||||
buf := make([]byte, 0, sensibleBufferSize)
|
||||
|
||||
return &jwriter{buf: bytes.NewBuffer(buf)}
|
||||
}
|
||||
|
||||
func (w *jwriter) Reset() {
|
||||
w.buf.Reset()
|
||||
w.err = nil
|
||||
}
|
||||
|
||||
func (w *jwriter) RawString(s string) {
|
||||
if w.err != nil {
|
||||
return
|
||||
}
|
||||
w.buf.WriteString(s)
|
||||
}
|
||||
|
||||
func (w *jwriter) Raw(b []byte, err error) {
|
||||
if w.err != nil {
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
w.err = err
|
||||
return
|
||||
}
|
||||
|
||||
_, _ = w.buf.Write(b)
|
||||
}
|
||||
|
||||
func (w *jwriter) RawByte(c byte) {
|
||||
if w.err != nil {
|
||||
return
|
||||
}
|
||||
w.buf.WriteByte(c)
|
||||
}
|
||||
|
||||
var quoteReplacer = strings.NewReplacer(`"`, `\"`, `\`, `\\`)
|
||||
|
||||
func (w *jwriter) String(s string) {
|
||||
if w.err != nil {
|
||||
return
|
||||
}
|
||||
// escape quotes and \
|
||||
s = quoteReplacer.Replace(s)
|
||||
|
||||
_ = w.buf.WriteByte('"')
|
||||
json.HTMLEscape(w.buf, []byte(s))
|
||||
_ = w.buf.WriteByte('"')
|
||||
}
|
||||
|
||||
// BuildBytes returns a clone of the internal buffer.
|
||||
func (w *jwriter) BuildBytes() ([]byte, error) {
|
||||
if w.err != nil {
|
||||
return nil, w.err
|
||||
}
|
||||
|
||||
return bytes.Clone(w.buf.Bytes()), nil
|
||||
}
|
||||
-92
@@ -1,92 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package jsonutils
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
)
|
||||
|
||||
// nullJSON represents a JSON object with null type
|
||||
var nullJSON = []byte("null")
|
||||
|
||||
const comma = byte(',')
|
||||
|
||||
var closers map[byte]byte
|
||||
|
||||
func init() {
|
||||
closers = map[byte]byte{
|
||||
'{': '}',
|
||||
'[': ']',
|
||||
}
|
||||
}
|
||||
|
||||
// ConcatJSON concatenates multiple json objects or arrays efficiently.
|
||||
//
|
||||
// Note that [ConcatJSON] performs a very simple (and fast) concatenation
|
||||
// operation: it does not attempt to merge objects.
|
||||
func ConcatJSON(blobs ...[]byte) []byte {
|
||||
if len(blobs) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
last := len(blobs) - 1
|
||||
for blobs[last] == nil || bytes.Equal(blobs[last], nullJSON) {
|
||||
// strips trailing null objects
|
||||
last--
|
||||
if last < 0 {
|
||||
// there was nothing but "null"s or nil...
|
||||
return nil
|
||||
}
|
||||
}
|
||||
if last == 0 {
|
||||
return blobs[0]
|
||||
}
|
||||
|
||||
var opening, closing byte
|
||||
var idx, a int
|
||||
buf := bytes.NewBuffer(nil)
|
||||
|
||||
for i, b := range blobs[:last+1] {
|
||||
if b == nil || bytes.Equal(b, nullJSON) {
|
||||
// a null object is in the list: skip it
|
||||
continue
|
||||
}
|
||||
if len(b) > 0 && opening == 0 { // is this an array or an object?
|
||||
opening, closing = b[0], closers[b[0]]
|
||||
}
|
||||
|
||||
if opening != '{' && opening != '[' {
|
||||
continue // don't know how to concatenate non container objects
|
||||
}
|
||||
|
||||
const minLengthIfNotEmpty = 3
|
||||
if len(b) < minLengthIfNotEmpty { // yep empty but also the last one, so closing this thing
|
||||
if i == last && a > 0 {
|
||||
_ = buf.WriteByte(closing) // never returns err != nil
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
idx = 0
|
||||
if a > 0 { // we need to join with a comma for everything beyond the first non-empty item
|
||||
_ = buf.WriteByte(comma) // never returns err != nil
|
||||
idx = 1 // this is not the first or the last so we want to drop the leading bracket
|
||||
}
|
||||
|
||||
if i != last { // not the last one, strip brackets
|
||||
_, _ = buf.Write(b[idx : len(b)-1]) // never returns err != nil
|
||||
} else { // last one, strip only the leading bracket
|
||||
_, _ = buf.Write(b[idx:])
|
||||
}
|
||||
a++
|
||||
}
|
||||
|
||||
// somehow it ended up being empty, so provide a default value
|
||||
if buf.Len() == 0 && (opening == '{' || opening == '[') {
|
||||
_ = buf.WriteByte(opening) // never returns err != nil
|
||||
_ = buf.WriteByte(closing)
|
||||
}
|
||||
|
||||
return buf.Bytes()
|
||||
}
|
||||
-7
@@ -1,7 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package jsonutils provides helpers to work with JSON.
|
||||
//
|
||||
// These utilities work with dynamic go structures to and from JSON.
|
||||
package jsonutils
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user