reva-bump-2.42.2
This commit is contained in:
committed by
Ralf Haferkamp
parent
f21207ed96
commit
2bf70a6f70
@@ -35,14 +35,14 @@ require (
|
||||
github.com/go-micro/plugins/v4/wrapper/trace/opentelemetry v1.2.0
|
||||
github.com/go-playground/validator/v10 v10.30.1
|
||||
github.com/go-resty/resty/v2 v2.17.1
|
||||
github.com/golang-jwt/jwt/v5 v5.3.0
|
||||
github.com/golang-jwt/jwt/v5 v5.3.1
|
||||
github.com/golang/protobuf v1.5.4
|
||||
github.com/google/go-cmp v0.7.0
|
||||
github.com/google/go-tika v0.3.1
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/gookit/config/v2 v2.2.7
|
||||
github.com/gorilla/mux v1.8.1
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.6
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.7
|
||||
github.com/invopop/validation v0.8.0
|
||||
github.com/jellydator/ttlcache/v2 v2.11.1
|
||||
github.com/jellydator/ttlcache/v3 v3.4.0
|
||||
@@ -55,17 +55,17 @@ require (
|
||||
github.com/mitchellh/mapstructure v1.5.0
|
||||
github.com/mna/pigeon v1.3.0
|
||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826
|
||||
github.com/nats-io/nats-server/v2 v2.12.3
|
||||
github.com/nats-io/nats-server/v2 v2.12.4
|
||||
github.com/nats-io/nats.go v1.48.0
|
||||
github.com/oklog/run v1.2.0
|
||||
github.com/olekukonko/tablewriter v1.1.3
|
||||
github.com/onsi/ginkgo v1.16.5
|
||||
github.com/onsi/ginkgo/v2 v2.27.5
|
||||
github.com/onsi/gomega v1.39.0
|
||||
github.com/onsi/ginkgo/v2 v2.28.0
|
||||
github.com/onsi/gomega v1.39.1
|
||||
github.com/open-policy-agent/opa v1.12.3
|
||||
github.com/opencloud-eu/icap-client v0.0.0-20250930132611-28a2afe62d89
|
||||
github.com/opencloud-eu/libre-graph-api-go v1.0.8-0.20250724122329-41ba6b191e76
|
||||
github.com/opencloud-eu/reva/v2 v2.42.1
|
||||
github.com/opencloud-eu/reva/v2 v2.42.2
|
||||
github.com/opensearch-project/opensearch-go/v4 v4.6.0
|
||||
github.com/orcaman/concurrent-map v1.0.0
|
||||
github.com/pkg/errors v0.9.1
|
||||
@@ -98,11 +98,11 @@ require (
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.64.0
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.64.0
|
||||
go.opentelemetry.io/contrib/zpages v0.64.0
|
||||
go.opentelemetry.io/otel v1.39.0
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0
|
||||
go.opentelemetry.io/otel v1.40.0
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.40.0
|
||||
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.39.0
|
||||
go.opentelemetry.io/otel/sdk v1.39.0
|
||||
go.opentelemetry.io/otel/trace v1.39.0
|
||||
go.opentelemetry.io/otel/sdk v1.40.0
|
||||
go.opentelemetry.io/otel/trace v1.40.0
|
||||
golang.org/x/crypto v0.47.0
|
||||
golang.org/x/exp v0.0.0-20250210185358-939b2ce775ac
|
||||
golang.org/x/image v0.35.0
|
||||
@@ -241,8 +241,8 @@ require (
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/gomodule/redigo v1.9.3 // indirect
|
||||
github.com/google/go-querystring v1.1.0 // indirect
|
||||
github.com/google/go-tpm v0.9.7 // indirect
|
||||
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 // indirect
|
||||
github.com/google/go-tpm v0.9.8 // indirect
|
||||
github.com/google/pprof v0.0.0-20260115054156-294ebfa9ad83 // indirect
|
||||
github.com/google/renameio/v2 v2.0.1 // indirect
|
||||
github.com/gookit/goutil v0.7.1 // indirect
|
||||
github.com/gorilla/handlers v1.5.1 // indirect
|
||||
@@ -261,7 +261,7 @@ require (
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/juliangruber/go-intersect v1.1.0 // indirect
|
||||
github.com/kevinburke/ssh_config v1.2.0 // indirect
|
||||
github.com/klauspost/compress v1.18.2 // indirect
|
||||
github.com/klauspost/compress v1.18.3 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.11 // indirect
|
||||
github.com/klauspost/crc32 v1.3.0 // indirect
|
||||
github.com/kovidgoyal/go-parallel v1.1.1 // indirect
|
||||
@@ -384,17 +384,17 @@ require (
|
||||
go.etcd.io/etcd/client/v3 v3.6.7 // indirect
|
||||
go.opencensus.io v0.24.0 // indirect
|
||||
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.39.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.40.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.40.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.0 // indirect
|
||||
go.yaml.in/yaml/v2 v2.4.3 // indirect
|
||||
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
||||
golang.org/x/mod v0.31.0 // indirect
|
||||
golang.org/x/mod v0.32.0 // indirect
|
||||
golang.org/x/sys v0.40.0 // indirect
|
||||
golang.org/x/time v0.14.0 // indirect
|
||||
golang.org/x/tools v0.40.0 // indirect
|
||||
golang.org/x/tools v0.41.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20250303144028-a0af3efb3deb // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260128011058-8636f8732409 // indirect
|
||||
gopkg.in/cenkalti/backoff.v1 v1.1.0 // indirect
|
||||
|
||||
@@ -504,8 +504,8 @@ github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69
|
||||
github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A=
|
||||
github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI=
|
||||
github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
||||
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-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY=
|
||||
github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
@@ -575,8 +575,8 @@ github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD
|
||||
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
|
||||
github.com/google/go-tika v0.3.1 h1:l+jr10hDhZjcgxFRfcQChRLo1bPXQeLFluMyvDhXTTA=
|
||||
github.com/google/go-tika v0.3.1/go.mod h1:DJh5N8qxXIl85QkqmXknd+PeeRkUOTbvwyYf7ieDz6c=
|
||||
github.com/google/go-tpm v0.9.7 h1:u89J4tUUeDTlH8xxC3CTW7OHZjbjKoHdQ9W7gCUhtxA=
|
||||
github.com/google/go-tpm v0.9.7/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY=
|
||||
github.com/google/go-tpm v0.9.8 h1:slArAR9Ft+1ybZu0lBwpSmpwhRXaa85hWtMinMyRAWo=
|
||||
github.com/google/go-tpm v0.9.8/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
@@ -587,8 +587,8 @@ github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hf
|
||||
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
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/pprof v0.0.0-20260115054156-294ebfa9ad83 h1:z2ogiKUYzX5Is6zr/vP9vJGqPwcdqsWjOt+V8J7+bTc=
|
||||
github.com/google/pprof v0.0.0-20260115054156-294ebfa9ad83/go.mod h1:MxpfABSjhmINe3F1It9d+8exIHFvUqtLIRCdOGNXqiI=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/renameio/v2 v2.0.1 h1:HyOM6qd9gF9sf15AvhbptGHUnaLTpEI9akAFFU3VyW0=
|
||||
github.com/google/renameio/v2 v2.0.1/go.mod h1:BtmJXm5YlszgC+TD4HOEEUFgkJP3nLxehU6hfe7jRt4=
|
||||
@@ -624,8 +624,8 @@ github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vb
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.6 h1:1ufTZkFXIQQ9EmgPjcIPIi2krfxG03lQ8OLoY1MJ3UM=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.6/go.mod h1:lW34nIZuQ8UDPdkon5fmfp2l3+ZkQ2me/+oecHYLOII=
|
||||
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/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI=
|
||||
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
|
||||
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
|
||||
@@ -730,8 +730,8 @@ github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF
|
||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.18.2 h1:iiPHWW0YrcFgpBYhsA6D1+fqHssJscY/Tm/y2Uqnapk=
|
||||
github.com/klauspost/compress v1.18.2/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4=
|
||||
github.com/klauspost/compress v1.18.3 h1:9PJRvfbmTabkOX8moIpXPbMMbYN60bWImDDU7L+/6zw=
|
||||
github.com/klauspost/compress v1.18.3/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4=
|
||||
github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/klauspost/cpuid/v2 v2.2.11 h1:0OwqZRYI2rFrjS4kvkDnqJkKHdHaRnCm68/DY4OxRzU=
|
||||
github.com/klauspost/cpuid/v2 v2.2.11/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
|
||||
@@ -916,8 +916,8 @@ github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRW
|
||||
github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04/go.mod h1:5sN+Lt1CaY4wsPvgQH/jsuJi4XO2ssZbdsIizr4CVC8=
|
||||
github.com/nats-io/jwt/v2 v2.8.0 h1:K7uzyz50+yGZDO5o772eRE7atlcSEENpL7P+b74JV1g=
|
||||
github.com/nats-io/jwt/v2 v2.8.0/go.mod h1:me11pOkwObtcBNR8AiMrUbtVOUGkqYjMQZ6jnSdVUIA=
|
||||
github.com/nats-io/nats-server/v2 v2.12.3 h1:KRv+1n7lddMVgkJPQer+pt36TcO0ENxjilBmeWdjcHs=
|
||||
github.com/nats-io/nats-server/v2 v2.12.3/go.mod h1:MQXjG9WjyXKz9koWzUc3jYUMKD8x3CLmTNy91IQQz3Y=
|
||||
github.com/nats-io/nats-server/v2 v2.12.4 h1:ZnT10v2LU2Xcoiy8ek9X6Se4YG8EuMfIfvAEuFVx1Ts=
|
||||
github.com/nats-io/nats-server/v2 v2.12.4/go.mod h1:5MCp/pqm5SEfsvVZ31ll1088ZTwEUdvRX1Hmh/mTTDg=
|
||||
github.com/nats-io/nats.go v1.48.0 h1:pSFyXApG+yWU/TgbKCjmm5K4wrHu86231/w84qRVR+U=
|
||||
github.com/nats-io/nats.go v1.48.0/go.mod h1:iRWIPokVIFbVijxuMQq4y9ttaBTMe0SFdlZfMDd+33g=
|
||||
github.com/nats-io/nkeys v0.4.12 h1:nssm7JKOG9/x4J8II47VWCL1Ds29avyiQDRn0ckMvDc=
|
||||
@@ -952,13 +952,13 @@ github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W
|
||||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
|
||||
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
|
||||
github.com/onsi/ginkgo/v2 v2.27.5 h1:ZeVgZMx2PDMdJm/+w5fE/OyG6ILo1Y3e+QX4zSR0zTE=
|
||||
github.com/onsi/ginkgo/v2 v2.27.5/go.mod h1:ArE1D/XhNXBXCBkKOLkbsb2c81dQHCRcF5zwn/ykDRo=
|
||||
github.com/onsi/ginkgo/v2 v2.28.0 h1:Rrf+lVLmtlBIKv6KrIGJCjyY8N36vDVcutbGJkyqjJc=
|
||||
github.com/onsi/ginkgo/v2 v2.28.0/go.mod h1:ArE1D/XhNXBXCBkKOLkbsb2c81dQHCRcF5zwn/ykDRo=
|
||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
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.39.0 h1:y2ROC3hKFmQZJNFeGAMeHZKkjBL65mIZcvrLQBF9k6Q=
|
||||
github.com/onsi/gomega v1.39.0/go.mod h1:ZCU1pkQcXDO5Sl9/VVEGlDyp+zm0m1cmeG5TOzLgdh4=
|
||||
github.com/onsi/gomega v1.39.1 h1:1IJLAad4zjPn2PsnhH70V4DKRFlrCzGBNrNaru+Vf28=
|
||||
github.com/onsi/gomega v1.39.1/go.mod h1:hL6yVALoTOxeWudERyfppUcZXjMwIMLnuSfruD2lcfg=
|
||||
github.com/open-policy-agent/opa v1.12.3 h1:qe3m/w52baKC/HJtippw+hYBUKCzuBCPjB+D5P9knfc=
|
||||
github.com/open-policy-agent/opa v1.12.3/go.mod h1:RnDgm04GA1RjEXJvrsG9uNT/+FyBNmozcPvA2qz60M4=
|
||||
github.com/opencloud-eu/go-micro-plugins/v4/store/nats-js-kv v0.0.0-20250512152754-23325793059a h1:Sakl76blJAaM6NxylVkgSzktjo2dS504iDotEFJsh3M=
|
||||
@@ -969,8 +969,8 @@ github.com/opencloud-eu/inotifywaitgo v0.0.0-20251111171128-a390bae3c5e9 h1:dIft
|
||||
github.com/opencloud-eu/inotifywaitgo v0.0.0-20251111171128-a390bae3c5e9/go.mod h1:JWyDC6H+5oZRdUJUgKuaye+8Ph5hEs6HVzVoPKzWSGI=
|
||||
github.com/opencloud-eu/libre-graph-api-go v1.0.8-0.20250724122329-41ba6b191e76 h1:vD/EdfDUrv4omSFjrinT8Mvf+8D7f9g4vgQ2oiDrVUI=
|
||||
github.com/opencloud-eu/libre-graph-api-go v1.0.8-0.20250724122329-41ba6b191e76/go.mod h1:pzatilMEHZFT3qV7C/X3MqOa3NlRQuYhlRhZTL+hN6Q=
|
||||
github.com/opencloud-eu/reva/v2 v2.42.1 h1:QUZOLSfAhb7bw+qsVSFMFY644rUz4/NtnOiJ0QQxj2o=
|
||||
github.com/opencloud-eu/reva/v2 v2.42.1/go.mod h1:pv+w23JG0/qJweZbTzNNev//YEvlUML1L/2iXgKGkkg=
|
||||
github.com/opencloud-eu/reva/v2 v2.42.2 h1:2v2RXsD9qX3L4vhu3Pl4QEXgx6jANeKz3FSFhZ3oU5E=
|
||||
github.com/opencloud-eu/reva/v2 v2.42.2/go.mod h1:LrMYMcSrH9nvTywiE1ry0i2w38yGLFKUPYxWjvKulBo=
|
||||
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||
github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
|
||||
@@ -1317,24 +1317,24 @@ go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.64.0 h1:ssfIgGN
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.64.0/go.mod h1:GQ/474YrbE4Jx8gZ4q5I4hrhUzM6UPzyrqJYV2AqPoQ=
|
||||
go.opentelemetry.io/contrib/zpages v0.64.0 h1:iMybqKVR8AHHxFX4DuEWJ9dY75+9E7+IPwUK3Ll7NxM=
|
||||
go.opentelemetry.io/contrib/zpages v0.64.0/go.mod h1:DnkiyoQ7Yx/NmmKn10b6M2YBXreUqq0qhFa/kYgSZME=
|
||||
go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48=
|
||||
go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0 h1:f0cb2XPmrqn4XMy9PNliTgRKJgS5WcL/u0/WRYGz4t0=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0/go.mod h1:vnakAaFckOMiMtOIhFI2MNH4FYrZzXCYxmb1LlhoGz8=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0 h1:in9O8ESIOlwJAEGTkkf34DesGRAc/Pn8qJ7k3r/42LM=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0/go.mod h1:Rp0EXBm5tfnv0WL+ARyO/PHBEaEAT8UUHQ6AGJcSq6c=
|
||||
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/exporters/otlp/otlptrace v1.40.0 h1:QKdN8ly8zEMrByybbQgv8cWBcdAarwmIPZ6FThrWXJs=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.40.0/go.mod h1:bTdK1nhqF76qiPoCCdyFIV+N/sRHYXYCTQc+3VCi3MI=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.40.0 h1:DvJDOPmSWQHWywQS6lKL+pb8s3gBLOZUtw4N+mavW1I=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.40.0/go.mod h1:EtekO9DEJb4/jRyN4v4Qjc2yA7AtfCBuz2FynRUWTXs=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 h1:aTL7F04bJHUlztTsNGJ2l+6he8c+y/b//eR0jjjemT4=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0/go.mod h1:kldtb7jDTeol0l3ewcmd8SDvx3EmIE7lyvqbasU3QC4=
|
||||
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.39.0 h1:8UPA4IbVZxpsD76ihGOQiFml99GPAEZLohDXvqHdi6U=
|
||||
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.39.0/go.mod h1:MZ1T/+51uIVKlRzGw1Fo46KEWThjlCBZKl2LzY5nv4g=
|
||||
go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0=
|
||||
go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs=
|
||||
go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18=
|
||||
go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew=
|
||||
go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI=
|
||||
go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA=
|
||||
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/sdk v1.40.0 h1:KHW/jUzgo6wsPh9At46+h4upjtccTmuZCFAc9OJ71f8=
|
||||
go.opentelemetry.io/otel/sdk v1.40.0/go.mod h1:Ph7EFdYvxq72Y8Li9q8KebuYUr2KoeyHx0DRMKrYBUE=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.40.0 h1:mtmdVqgQkeRxHgRv4qhyJduP3fYJRMX4AtAlbuWdCYw=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.40.0/go.mod h1:4Z2bGMf0KSK3uRjlczMOeMhKU2rhUqdWNoKcYrtcBPg=
|
||||
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/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/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
@@ -1420,8 +1420,8 @@ golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.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/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=
|
||||
@@ -1680,8 +1680,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||
golang.org/x/tools v0.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/godoc v0.1.0-deprecated h1:o+aZ1BOj6Hsx/GBdJO/s815sqftjSnrZZwyYTHODvtk=
|
||||
golang.org/x/tools/godoc v0.1.0-deprecated/go.mod h1:qM63CriJ961IHWmnWa9CjZnBndniPt4a3CK0PVB9bIg=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
||||
@@ -34,7 +34,7 @@ var (
|
||||
// LatestTag is the latest released version plus the dev meta version.
|
||||
// Will be overwritten by the release pipeline
|
||||
// Needs a manual change for every tagged release
|
||||
LatestTag = "5.0.1+dev"
|
||||
LatestTag = "5.0.2+dev"
|
||||
|
||||
// Date indicates the build date.
|
||||
// This has been removed, it looks like you can only replace static strings with recent go versions
|
||||
|
||||
+6
-5
@@ -140,11 +140,12 @@ A common use case would be integrating with different 3rd party signature
|
||||
providers, like key management services from various cloud providers or Hardware
|
||||
Security Modules (HSMs) or to implement additional standards.
|
||||
|
||||
| Extension | Purpose | Repo |
|
||||
| --------- | -------------------------------------------------------------------------------------------------------- | ------------------------------------------ |
|
||||
| GCP | Integrates with multiple Google Cloud Platform signing tools (AppEngine, IAM API, Cloud KMS) | https://github.com/someone1/gcp-jwt-go |
|
||||
| AWS | Integrates with AWS Key Management Service, KMS | https://github.com/matelang/jwt-go-aws-kms |
|
||||
| JWKS | Provides support for JWKS ([RFC 7517](https://datatracker.ietf.org/doc/html/rfc7517)) as a `jwt.Keyfunc` | https://github.com/MicahParks/keyfunc |
|
||||
| Extension | Purpose | Repo |
|
||||
| --------- | -------------------------------------------------------------------------------------------------------- | ------------------------------------------------- |
|
||||
| GCP | Integrates with multiple Google Cloud Platform signing tools (AppEngine, IAM API, Cloud KMS) | https://github.com/someone1/gcp-jwt-go |
|
||||
| AWS | Integrates with AWS Key Management Service, KMS | https://github.com/matelang/jwt-go-aws-kms |
|
||||
| JWKS | Provides support for JWKS ([RFC 7517](https://datatracker.ietf.org/doc/html/rfc7517)) as a `jwt.Keyfunc` | https://github.com/MicahParks/keyfunc |
|
||||
| TPM | Integrates with Trusted Platform Module (TPM) | https://github.com/salrashid123/golang-jwt-tpm |
|
||||
|
||||
*Disclaimer*: Unless otherwise specified, these integrations are maintained by
|
||||
third parties and should not be considered as a primary offer by any of the
|
||||
|
||||
+1
-1
@@ -97,7 +97,7 @@ Backwards compatible API change that was missed in 2.0.0.
|
||||
|
||||
There were two major reasons for breaking backwards compatibility with this update. The first was a refactor required to expand the width of the RSA and HMAC-SHA signing implementations. There will likely be no required code changes to support this change.
|
||||
|
||||
The second update, while unfortunately requiring a small change in integration, is required to open up this library to other signing methods. Not all keys used for all signing methods have a single standard on-disk representation. Requiring `[]byte` as the type for all keys proved too limiting. Additionally, this implementation allows for pre-parsed tokens to be reused, which might matter in an application that parses a high volume of tokens with a small set of keys. Backwards compatibilty has been maintained for passing `[]byte` to the RSA signing methods, but they will also accept `*rsa.PublicKey` and `*rsa.PrivateKey`.
|
||||
The second update, while unfortunately requiring a small change in integration, is required to open up this library to other signing methods. Not all keys used for all signing methods have a single standard on-disk representation. Requiring `[]byte` as the type for all keys proved too limiting. Additionally, this implementation allows for pre-parsed tokens to be reused, which might matter in an application that parses a high volume of tokens with a small set of keys. Backwards compatibility has been maintained for passing `[]byte` to the RSA signing methods, but they will also accept `*rsa.PublicKey` and `*rsa.PrivateKey`.
|
||||
|
||||
It is likely the only integration change required here will be to change `func(t *jwt.Token) ([]byte, error)` to `func(t *jwt.Token) (interface{}, error)` when calling `Parse`.
|
||||
|
||||
|
||||
+13
-11
@@ -76,13 +76,6 @@ func (p *Parser) ParseWithClaims(tokenString string, claims Claims, keyFunc Keyf
|
||||
}
|
||||
}
|
||||
|
||||
// Decode signature
|
||||
token.Signature, err = p.DecodeSegment(parts[2])
|
||||
if err != nil {
|
||||
return token, newError("could not base64 decode signature", ErrTokenMalformed, err)
|
||||
}
|
||||
text := strings.Join(parts[0:2], ".")
|
||||
|
||||
// Lookup key(s)
|
||||
if keyFunc == nil {
|
||||
// keyFunc was not provided. short circuiting validation
|
||||
@@ -94,11 +87,14 @@ func (p *Parser) ParseWithClaims(tokenString string, claims Claims, keyFunc Keyf
|
||||
return token, newError("error while executing keyfunc", ErrTokenUnverifiable, err)
|
||||
}
|
||||
|
||||
// Join together header and claims in order to verify them with the signature
|
||||
text := strings.Join(parts[0:2], ".")
|
||||
switch have := got.(type) {
|
||||
case VerificationKeySet:
|
||||
if len(have.Keys) == 0 {
|
||||
return token, newError("keyfunc returned empty verification key set", ErrTokenUnverifiable)
|
||||
}
|
||||
|
||||
// Iterate through keys and verify signature, skipping the rest when a match is found.
|
||||
// Return the last error if no match is found.
|
||||
for _, key := range have.Keys {
|
||||
@@ -131,7 +127,7 @@ func (p *Parser) ParseWithClaims(tokenString string, claims Claims, keyFunc Keyf
|
||||
return token, nil
|
||||
}
|
||||
|
||||
// ParseUnverified parses the token but doesn't validate the signature.
|
||||
// ParseUnverified parses the token but does not validate the signature.
|
||||
//
|
||||
// WARNING: Don't use this method unless you know what you're doing.
|
||||
//
|
||||
@@ -146,7 +142,7 @@ func (p *Parser) ParseUnverified(tokenString string, claims Claims) (token *Toke
|
||||
|
||||
token = &Token{Raw: tokenString}
|
||||
|
||||
// parse Header
|
||||
// Parse Header
|
||||
var headerBytes []byte
|
||||
if headerBytes, err = p.DecodeSegment(parts[0]); err != nil {
|
||||
return token, parts, newError("could not base64 decode header", ErrTokenMalformed, err)
|
||||
@@ -155,7 +151,7 @@ func (p *Parser) ParseUnverified(tokenString string, claims Claims) (token *Toke
|
||||
return token, parts, newError("could not JSON decode header", ErrTokenMalformed, err)
|
||||
}
|
||||
|
||||
// parse Claims
|
||||
// Parse Claims
|
||||
token.Claims = claims
|
||||
|
||||
claimBytes, err := p.DecodeSegment(parts[1])
|
||||
@@ -196,6 +192,12 @@ func (p *Parser) ParseUnverified(tokenString string, claims Claims) (token *Toke
|
||||
return token, parts, newError("signing method (alg) is unspecified", ErrTokenUnverifiable)
|
||||
}
|
||||
|
||||
// Parse token signature
|
||||
token.Signature, err = p.DecodeSegment(parts[2])
|
||||
if err != nil {
|
||||
return token, parts, newError("could not base64 decode signature", ErrTokenMalformed, err)
|
||||
}
|
||||
|
||||
return token, parts, nil
|
||||
}
|
||||
|
||||
@@ -216,7 +218,7 @@ func splitToken(token string) ([]string, bool) {
|
||||
parts[1] = claims
|
||||
// One more cut to ensure the signature is the last part of the token and there are no more
|
||||
// delimiters. This avoids an issue where malicious input could contain additional delimiters
|
||||
// causing unecessary overhead parsing tokens.
|
||||
// causing unnecessary overhead parsing tokens.
|
||||
signature, _, unexpected := strings.Cut(remain, tokenDelimiter)
|
||||
if unexpected {
|
||||
return nil, false
|
||||
|
||||
+9
-3
@@ -3,9 +3,7 @@ package jwt
|
||||
import "time"
|
||||
|
||||
// ParserOption is used to implement functional-style options that modify the
|
||||
// behavior of the parser. To add new options, just create a function (ideally
|
||||
// beginning with With or Without) that returns an anonymous function that takes
|
||||
// a *Parser type as input and manipulates its configuration accordingly.
|
||||
// behavior of the parser.
|
||||
type ParserOption func(*Parser)
|
||||
|
||||
// WithValidMethods is an option to supply algorithm methods that the parser
|
||||
@@ -66,6 +64,14 @@ func WithExpirationRequired() ParserOption {
|
||||
}
|
||||
}
|
||||
|
||||
// WithNotBeforeRequired returns the ParserOption to make nbf claim required.
|
||||
// By default nbf claim is optional.
|
||||
func WithNotBeforeRequired() ParserOption {
|
||||
return func(p *Parser) {
|
||||
p.validator.requireNbf = true
|
||||
}
|
||||
}
|
||||
|
||||
// WithAudience configures the validator to require any of the specified
|
||||
// audiences in the `aud` claim. Validation will fail if the audience is not
|
||||
// listed in the token or the `aud` claim is missing.
|
||||
|
||||
+4
-2
@@ -32,8 +32,8 @@ type Token struct {
|
||||
Method SigningMethod // Method is the signing method used or to be used
|
||||
Header map[string]any // Header is the first segment of the token in decoded form
|
||||
Claims Claims // Claims is the second segment of the token in decoded form
|
||||
Signature []byte // Signature is the third segment of the token in decoded form. Populated when you Parse a token
|
||||
Valid bool // Valid specifies if the token is valid. Populated when you Parse/Verify a token
|
||||
Signature []byte // Signature is the third segment of the token in decoded form. Populated when you [Parse] or sign a token
|
||||
Valid bool // Valid specifies if the token is valid. Populated when you [Parse] a token
|
||||
}
|
||||
|
||||
// New creates a new [Token] with the specified signing method and an empty map
|
||||
@@ -71,6 +71,8 @@ func (t *Token) SignedString(key any) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
|
||||
t.Signature = sig
|
||||
|
||||
return sstr + "." + t.EncodeSegment(sig), nil
|
||||
}
|
||||
|
||||
|
||||
+6
-2
@@ -44,6 +44,9 @@ type Validator struct {
|
||||
// requireExp specifies whether the exp claim is required
|
||||
requireExp bool
|
||||
|
||||
// requireNbf specifies whether the nbf claim is required
|
||||
requireNbf bool
|
||||
|
||||
// verifyIat specifies whether the iat (Issued At) claim will be verified.
|
||||
// According to https://www.rfc-editor.org/rfc/rfc7519#section-4.1.6 this
|
||||
// only specifies the age of the token, but no validation check is
|
||||
@@ -111,8 +114,9 @@ func (v *Validator) Validate(claims Claims) error {
|
||||
}
|
||||
|
||||
// We always need to check not-before, but usage of the claim itself is
|
||||
// OPTIONAL.
|
||||
if err = v.verifyNotBefore(claims, now, false); err != nil {
|
||||
// OPTIONAL by default. requireNbf overrides this behavior and makes
|
||||
// the nbf claim mandatory.
|
||||
if err = v.verifyNotBefore(claims, now, v.requireNbf); err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
|
||||
|
||||
+5
-6
@@ -17,6 +17,7 @@ package profile
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"slices"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -78,12 +79,10 @@ func Merge(srcs []*Profile) (*Profile, error) {
|
||||
}
|
||||
}
|
||||
|
||||
for _, s := range p.Sample {
|
||||
if isZeroSample(s) {
|
||||
// If there are any zero samples, re-merge the profile to GC
|
||||
// them.
|
||||
return Merge([]*Profile{p})
|
||||
}
|
||||
if slices.ContainsFunc(p.Sample, isZeroSample) {
|
||||
// If there are any zero samples, re-merge the profile to GC
|
||||
// them.
|
||||
return Merge([]*Profile{p})
|
||||
}
|
||||
|
||||
return p, nil
|
||||
|
||||
+14
-8
@@ -24,6 +24,7 @@ import (
|
||||
"math"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"slices"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
@@ -277,7 +278,7 @@ func (p *Profile) massageMappings() {
|
||||
|
||||
// Use heuristics to identify main binary and move it to the top of the list of mappings
|
||||
for i, m := range p.Mapping {
|
||||
file := strings.TrimSpace(strings.Replace(m.File, "(deleted)", "", -1))
|
||||
file := strings.TrimSpace(strings.ReplaceAll(m.File, "(deleted)", ""))
|
||||
if len(file) == 0 {
|
||||
continue
|
||||
}
|
||||
@@ -734,12 +735,7 @@ func (p *Profile) RemoveLabel(key string) {
|
||||
|
||||
// HasLabel returns true if a sample has a label with indicated key and value.
|
||||
func (s *Sample) HasLabel(key, value string) bool {
|
||||
for _, v := range s.Label[key] {
|
||||
if v == value {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
return slices.Contains(s.Label[key], value)
|
||||
}
|
||||
|
||||
// SetNumLabel sets the specified key to the specified value for all samples in the
|
||||
@@ -852,7 +848,17 @@ func (p *Profile) HasFileLines() bool {
|
||||
// "[vdso]", "[vsyscall]" and some others, see the code.
|
||||
func (m *Mapping) Unsymbolizable() bool {
|
||||
name := filepath.Base(m.File)
|
||||
return strings.HasPrefix(name, "[") || strings.HasPrefix(name, "linux-vdso") || strings.HasPrefix(m.File, "/dev/dri/") || m.File == "//anon"
|
||||
switch {
|
||||
case strings.HasPrefix(name, "["):
|
||||
case strings.HasPrefix(name, "linux-vdso"):
|
||||
case strings.HasPrefix(m.File, "/dev/dri/"):
|
||||
case m.File == "//anon":
|
||||
case m.File == "":
|
||||
case strings.HasPrefix(m.File, "/memfd:"):
|
||||
default:
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Copy makes a fully independent copy of a profile.
|
||||
|
||||
+18
-1
@@ -36,6 +36,7 @@ package profile
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"slices"
|
||||
)
|
||||
|
||||
type buffer struct {
|
||||
@@ -187,6 +188,16 @@ func le32(p []byte) uint32 {
|
||||
return uint32(p[0]) | uint32(p[1])<<8 | uint32(p[2])<<16 | uint32(p[3])<<24
|
||||
}
|
||||
|
||||
func peekNumVarints(data []byte) (numVarints int) {
|
||||
for ; len(data) > 0; numVarints++ {
|
||||
var err error
|
||||
if _, data, err = decodeVarint(data); err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
return numVarints
|
||||
}
|
||||
|
||||
func decodeVarint(data []byte) (uint64, []byte, error) {
|
||||
var u uint64
|
||||
for i := 0; ; i++ {
|
||||
@@ -286,6 +297,9 @@ func decodeInt64(b *buffer, x *int64) error {
|
||||
func decodeInt64s(b *buffer, x *[]int64) error {
|
||||
if b.typ == 2 {
|
||||
// Packed encoding
|
||||
dataLen := peekNumVarints(b.data)
|
||||
*x = slices.Grow(*x, dataLen)
|
||||
|
||||
data := b.data
|
||||
for len(data) > 0 {
|
||||
var u uint64
|
||||
@@ -316,8 +330,11 @@ func decodeUint64(b *buffer, x *uint64) error {
|
||||
|
||||
func decodeUint64s(b *buffer, x *[]uint64) error {
|
||||
if b.typ == 2 {
|
||||
data := b.data
|
||||
// Packed encoding
|
||||
dataLen := peekNumVarints(b.data)
|
||||
*x = slices.Grow(*x, dataLen)
|
||||
|
||||
data := b.data
|
||||
for len(data) > 0 {
|
||||
var u uint64
|
||||
var err error
|
||||
|
||||
+2
-7
@@ -19,6 +19,7 @@ package profile
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"slices"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@@ -40,13 +41,7 @@ func simplifyFunc(f string) string {
|
||||
// Account for unsimplified names -- try to remove the argument list by trimming
|
||||
// starting from the first '(', but skipping reserved names that have '('.
|
||||
for _, ind := range bracketRx.FindAllStringSubmatchIndex(funcName, -1) {
|
||||
foundReserved := false
|
||||
for _, res := range reservedNames {
|
||||
if funcName[ind[0]:ind[1]] == res {
|
||||
foundReserved = true
|
||||
break
|
||||
}
|
||||
}
|
||||
foundReserved := slices.Contains(reservedNames, funcName[ind[0]:ind[1]])
|
||||
if !foundReserved {
|
||||
funcName = funcName[:ind[0]]
|
||||
break
|
||||
|
||||
+46
-15
@@ -60,6 +60,9 @@ type parser struct {
|
||||
|
||||
// pedantic reports error when configuration is not correct.
|
||||
pedantic bool
|
||||
|
||||
// Tracks environment variable references, to avoid cycles
|
||||
envVarReferences map[string]bool
|
||||
}
|
||||
|
||||
// Parse will return a map of keys to any, although concrete types
|
||||
@@ -180,16 +183,37 @@ func (t *token) Position() int {
|
||||
return t.item.pos
|
||||
}
|
||||
|
||||
func parse(data, fp string, pedantic bool) (p *parser, err error) {
|
||||
p = &parser{
|
||||
mapping: make(map[string]any),
|
||||
lx: lex(data),
|
||||
ctxs: make([]any, 0, 4),
|
||||
keys: make([]string, 0, 4),
|
||||
ikeys: make([]item, 0, 4),
|
||||
fp: filepath.Dir(fp),
|
||||
pedantic: pedantic,
|
||||
func newParser(data, fp string, pedantic bool) *parser {
|
||||
return &parser{
|
||||
mapping: make(map[string]any),
|
||||
lx: lex(data),
|
||||
ctxs: make([]any, 0, 4),
|
||||
keys: make([]string, 0, 4),
|
||||
ikeys: make([]item, 0, 4),
|
||||
fp: filepath.Dir(fp),
|
||||
pedantic: pedantic,
|
||||
envVarReferences: make(map[string]bool),
|
||||
}
|
||||
}
|
||||
|
||||
func parse(data, fp string, pedantic bool) (*parser, error) {
|
||||
p := newParser(data, fp, pedantic)
|
||||
if err := p.parse(fp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return p, nil
|
||||
}
|
||||
|
||||
func parseEnv(data string, parent *parser) (*parser, error) {
|
||||
p := newParser(data, "", false)
|
||||
p.envVarReferences = parent.envVarReferences
|
||||
if err := p.parse(""); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return p, nil
|
||||
}
|
||||
|
||||
func (p *parser) parse(fp string) error {
|
||||
p.pushContext(p.mapping)
|
||||
|
||||
var prevItem item
|
||||
@@ -199,16 +223,16 @@ func parse(data, fp string, pedantic bool) (p *parser, err error) {
|
||||
// Here we allow the final character to be a bracket '}'
|
||||
// in order to support JSON like configurations.
|
||||
if prevItem.typ == itemKey && prevItem.val != mapEndString {
|
||||
return nil, fmt.Errorf("config is invalid (%s:%d:%d)", fp, it.line, it.pos)
|
||||
return fmt.Errorf("config is invalid (%s:%d:%d)", fp, it.line, it.pos)
|
||||
}
|
||||
break
|
||||
}
|
||||
prevItem = it
|
||||
if err := p.processItem(it, fp); err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
}
|
||||
return p, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *parser) next() item {
|
||||
@@ -453,11 +477,18 @@ func (p *parser) lookupVariable(varReference string) (any, bool, error) {
|
||||
}
|
||||
|
||||
// If we are here, we have exhausted our context maps and still not found anything.
|
||||
// Parse from the environment.
|
||||
// Detect reference cycles
|
||||
if p.envVarReferences[varReference] {
|
||||
return nil, false, fmt.Errorf("variable reference cycle for '%s'", varReference)
|
||||
}
|
||||
p.envVarReferences[varReference] = true
|
||||
defer delete(p.envVarReferences, varReference)
|
||||
|
||||
// Parse from the environment
|
||||
if vStr, ok := os.LookupEnv(varReference); ok {
|
||||
// Everything we get here will be a string value, so we need to process as a parser would.
|
||||
if vmap, err := Parse(fmt.Sprintf("%s=%s", pkey, vStr)); err == nil {
|
||||
v, ok := vmap[pkey]
|
||||
if subp, err := parseEnv(fmt.Sprintf("%s=%s", pkey, vStr), p); err == nil {
|
||||
v, ok := subp.mapping[pkey]
|
||||
return v, ok, nil
|
||||
} else {
|
||||
return nil, false, err
|
||||
|
||||
+1
@@ -299,6 +299,7 @@ func (a *Account) shallowCopy(na *Account) {
|
||||
na.Nkey = a.Nkey
|
||||
na.Issuer = a.Issuer
|
||||
na.traceDest, na.traceDestSampling = a.traceDest, a.traceDestSampling
|
||||
na.nrgAccount = a.nrgAccount
|
||||
|
||||
if a.imports.streams != nil {
|
||||
na.imports.streams = make([]*streamImport, 0, len(a.imports.streams))
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// Copyright 2023-2024 The NATS Authors
|
||||
// Copyright 2023-2025 The NATS Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
+54
-9
@@ -1,4 +1,4 @@
|
||||
// Copyright 2012-2025 The NATS Authors
|
||||
// Copyright 2012-2026 The NATS Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
@@ -23,6 +23,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"math/rand"
|
||||
"net"
|
||||
"net/http"
|
||||
@@ -35,8 +36,6 @@ import (
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"slices"
|
||||
|
||||
"github.com/klauspost/compress/s2"
|
||||
"github.com/nats-io/jwt/v2"
|
||||
"github.com/nats-io/nats-server/v2/internal/fastrand"
|
||||
@@ -2732,9 +2731,12 @@ func (c *client) updateS2AutoCompressionLevel(co *CompressionOpts, compression *
|
||||
}
|
||||
|
||||
// Will return the parts from the raw wire msg.
|
||||
// We return the `hdr` as a slice that is capped to the length of the headers
|
||||
// so that if the caller later tries to append to the returned header slice it
|
||||
// does not affect the message content.
|
||||
func (c *client) msgParts(data []byte) (hdr []byte, msg []byte) {
|
||||
if c != nil && c.pa.hdr > 0 {
|
||||
return data[:c.pa.hdr], data[c.pa.hdr:]
|
||||
return data[:c.pa.hdr:c.pa.hdr], data[c.pa.hdr:]
|
||||
}
|
||||
return nil, data
|
||||
}
|
||||
@@ -3337,7 +3339,7 @@ func (c *client) unsubscribe(acc *Account, sub *subscription, force, remove bool
|
||||
sub.shadow = nil
|
||||
if len(shadowSubs) > 0 {
|
||||
isSpokeLeaf = c.isSpokeLeafNode()
|
||||
updateRoute = !isSpokeLeaf && (c.kind == CLIENT || c.kind == SYSTEM || c.kind == LEAF) && c.srv != nil
|
||||
updateRoute = !isSpokeLeaf && (c.kind == CLIENT || c.kind == SYSTEM || c.kind == LEAF || c.kind == JETSTREAM) && c.srv != nil
|
||||
}
|
||||
sub.close()
|
||||
c.mu.Unlock()
|
||||
@@ -4565,6 +4567,19 @@ func getHeaderKeyIndex(key string, hdr []byte) int {
|
||||
}
|
||||
}
|
||||
|
||||
// setHeader will replace the value of the first existing key `key`
|
||||
// with the given value `val`, or add this new key at the end of
|
||||
// the headers.
|
||||
//
|
||||
// Note: If the key does not exist, or if it exists but the new value
|
||||
// would make the resulting byte slice larger than the original one,
|
||||
// a new byte slice is returned and the original is left untouched.
|
||||
// This is to prevent situations where caller may have a `hdr` and
|
||||
// `msg` that are the parts of an underlying buffer. Extending the
|
||||
// `hdr` would otherwise overwrite the `msg` part.
|
||||
//
|
||||
// If the new value is smaller, then the original `hdr` byte slice
|
||||
// is modified.
|
||||
func setHeader(key, val string, hdr []byte) []byte {
|
||||
start := getHeaderKeyIndex(key, hdr)
|
||||
if start >= 0 {
|
||||
@@ -4579,15 +4594,45 @@ func setHeader(key, val string, hdr []byte) []byte {
|
||||
return hdr // malformed headers
|
||||
}
|
||||
valEnd += valStart
|
||||
suffix := slices.Clone(hdr[valEnd:])
|
||||
newHdr := append(hdr[:valStart], val...)
|
||||
return append(newHdr, suffix...)
|
||||
// Length of the existing value (before the `\r`)
|
||||
oldValLen := valEnd - valStart
|
||||
// This is how many extra bytes we need for the new value.
|
||||
// If <= 0, it means that we need less and so will reuse the `hdr` buffer.
|
||||
if extra := len(val) - oldValLen; extra > 0 {
|
||||
// Check that we don't overflow an "int".
|
||||
if rem := math.MaxInt - hdrLen; rem < extra {
|
||||
// We don't grow, and return the existing header.
|
||||
return hdr
|
||||
}
|
||||
// The new size is the old size plus the extra bytes.
|
||||
newHdrSize := hdrLen + extra
|
||||
newHdr := make([]byte, newHdrSize)
|
||||
// Copy the parts from `hdr` and `val` into the new buffer.
|
||||
n := copy(newHdr, hdr[:valStart])
|
||||
n += copy(newHdr[n:], val)
|
||||
copy(newHdr[n:], hdr[valEnd:])
|
||||
return newHdr
|
||||
}
|
||||
// We can write in place since it fits in the existing `hdr` buffer.
|
||||
n := copy(hdr[valStart:], val)
|
||||
n += copy(hdr[valStart+n:], hdr[valEnd:])
|
||||
hdr = hdr[:valStart+n]
|
||||
return hdr
|
||||
}
|
||||
if len(hdr) > 0 && bytes.HasSuffix(hdr, []byte("\r\n")) {
|
||||
hdr = hdr[:len(hdr)-2]
|
||||
val += "\r\n"
|
||||
}
|
||||
return fmt.Appendf(hdr, "%s: %s\r\n", key, val)
|
||||
// Create the new buffer based on length of existing one and
|
||||
// length of the new "<key>: <value>\r\n". Protect against "int" overflow.
|
||||
newSize := uint64(len(hdr)) + uint64(len(key)) + 1 + 1 + uint64(len(val)) + 2
|
||||
if newSize > uint64(math.MaxInt) {
|
||||
// We don't grow, and return the existing header.
|
||||
return hdr
|
||||
}
|
||||
newHdr := make([]byte, 0, int(newSize))
|
||||
newHdr = append(newHdr, hdr...)
|
||||
return fmt.Appendf(newHdr, "%s: %s\r\n", key, val)
|
||||
}
|
||||
|
||||
// For bytes.HasPrefix below.
|
||||
|
||||
+1
-1
@@ -66,7 +66,7 @@ func init() {
|
||||
|
||||
const (
|
||||
// VERSION is the current version for the server.
|
||||
VERSION = "2.12.3"
|
||||
VERSION = "2.12.4"
|
||||
|
||||
// PROTO is the currently supported protocol.
|
||||
// 0 was the original
|
||||
|
||||
+49
-27
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2025 The NATS Authors
|
||||
// Copyright 2019-2026 The NATS Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
@@ -1030,11 +1030,11 @@ func (mset *stream) addConsumerWithAssignment(config *ConsumerConfig, oname stri
|
||||
}
|
||||
if cName != _EMPTY_ {
|
||||
if eo, ok := mset.consumers[cName]; ok {
|
||||
mset.mu.Unlock()
|
||||
if action == ActionCreate {
|
||||
ocfg := eo.config()
|
||||
copyConsumerMetadata(config, &ocfg)
|
||||
if !reflect.DeepEqual(config, &ocfg) {
|
||||
mset.mu.Unlock()
|
||||
return nil, NewJSConsumerAlreadyExistsError()
|
||||
}
|
||||
}
|
||||
@@ -1042,9 +1042,11 @@ func (mset *stream) addConsumerWithAssignment(config *ConsumerConfig, oname stri
|
||||
if cfg.Retention == WorkQueuePolicy {
|
||||
subjects := gatherSubjectFilters(config.FilterSubject, config.FilterSubjects)
|
||||
if !mset.partitionUnique(cName, subjects) {
|
||||
mset.mu.Unlock()
|
||||
return nil, NewJSConsumerWQConsumerNotUniqueError()
|
||||
}
|
||||
}
|
||||
mset.mu.Unlock()
|
||||
err := eo.updateConfig(config)
|
||||
if err == nil {
|
||||
return eo, nil
|
||||
@@ -1542,7 +1544,6 @@ func (o *consumer) setLeader(isLeader bool) {
|
||||
if o.cfg.AckPolicy != AckNone {
|
||||
if o.ackSub, err = o.subscribeInternal(o.ackSubj, o.pushAck); err != nil {
|
||||
o.mu.Unlock()
|
||||
o.deleteWithoutAdvisory()
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -1551,7 +1552,6 @@ func (o *consumer) setLeader(isLeader bool) {
|
||||
// Will error if wrong mode to provide feedback to users.
|
||||
if o.reqSub, err = o.subscribeInternal(o.nextMsgSubj, o.processNextMsgReq); err != nil {
|
||||
o.mu.Unlock()
|
||||
o.deleteWithoutAdvisory()
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1561,7 +1561,6 @@ func (o *consumer) setLeader(isLeader bool) {
|
||||
fcsubj := fmt.Sprintf(jsFlowControl, stream, o.name)
|
||||
if o.fcSub, err = o.subscribeInternal(fcsubj, o.processFlowControl); err != nil {
|
||||
o.mu.Unlock()
|
||||
o.deleteWithoutAdvisory()
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -2401,7 +2400,8 @@ func (o *consumer) updateConfig(cfg *ConsumerConfig) error {
|
||||
|
||||
// Check for Subject Filters update.
|
||||
newSubjects := gatherSubjectFilters(cfg.FilterSubject, cfg.FilterSubjects)
|
||||
if !subjectSliceEqual(newSubjects, o.subjf.subjects()) {
|
||||
updatedFilters := !subjectSliceEqual(newSubjects, o.subjf.subjects())
|
||||
if updatedFilters {
|
||||
newSubjf := make(subjectFilters, 0, len(newSubjects))
|
||||
for _, newFilter := range newSubjects {
|
||||
fs := &subjectFilter{
|
||||
@@ -2440,15 +2440,17 @@ func (o *consumer) updateConfig(cfg *ConsumerConfig) error {
|
||||
// Allowed but considered no-op, [Description, SampleFrequency, MaxWaiting, HeadersOnly]
|
||||
o.cfg = *cfg
|
||||
|
||||
// Cleanup messages that lost interest.
|
||||
if o.retention == InterestPolicy {
|
||||
o.mu.Unlock()
|
||||
o.cleanupNoInterestMessages(o.mset, false)
|
||||
o.mu.Lock()
|
||||
}
|
||||
if updatedFilters {
|
||||
// Cleanup messages that lost interest.
|
||||
if o.retention == InterestPolicy {
|
||||
o.mu.Unlock()
|
||||
o.cleanupNoInterestMessages(o.mset, false)
|
||||
o.mu.Lock()
|
||||
}
|
||||
|
||||
// Re-calculate num pending on update.
|
||||
o.streamNumPending()
|
||||
// Re-calculate num pending on update.
|
||||
o.streamNumPending()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -5115,9 +5117,14 @@ func (o *consumer) checkNumPending() (uint64, error) {
|
||||
var state StreamState
|
||||
o.mset.store.FastState(&state)
|
||||
npc := o.numPending()
|
||||
if o.sseq > state.LastSeq && npc > 0 || npc > state.Msgs {
|
||||
// Re-calculate.
|
||||
return o.streamNumPending()
|
||||
// Make sure we can't report more messages than there are.
|
||||
// TODO(nat): It's not great that this means consumer info has side effects,
|
||||
// since we can't know whether anyone will call it or not. The previous num
|
||||
// pending calculation that this replaces had the same problem though.
|
||||
if o.sseq > state.LastSeq {
|
||||
o.npc = 0
|
||||
} else if npc > 0 {
|
||||
o.npc = int64(min(npc, state.Msgs, state.LastSeq-o.sseq+1))
|
||||
}
|
||||
}
|
||||
return o.numPending(), nil
|
||||
@@ -5365,6 +5372,15 @@ func (o *consumer) trackPending(sseq, dseq uint64) {
|
||||
o.pending = make(map[uint64]*Pending)
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
if p, ok := o.pending[sseq]; ok {
|
||||
// Update timestamp but keep original consumer delivery sequence.
|
||||
// So do not update p.Sequence.
|
||||
p.Timestamp = now.UnixNano()
|
||||
} else {
|
||||
o.pending[sseq] = &Pending{dseq, now.UnixNano()}
|
||||
}
|
||||
|
||||
// We could have a backoff that set a timer higher than what we need for this message.
|
||||
// In that case, reset to lowest backoff required for a message redelivery.
|
||||
minDelay := o.ackWait(0)
|
||||
@@ -5377,18 +5393,10 @@ func (o *consumer) trackPending(sseq, dseq uint64) {
|
||||
}
|
||||
minDelay = o.ackWait(o.cfg.BackOff[bi])
|
||||
}
|
||||
minDeadline := time.Now().Add(minDelay)
|
||||
minDeadline := now.Add(minDelay)
|
||||
if o.ptmr == nil || o.ptmrEnd.After(minDeadline) {
|
||||
o.resetPtmr(minDelay)
|
||||
}
|
||||
|
||||
if p, ok := o.pending[sseq]; ok {
|
||||
// Update timestamp but keep original consumer delivery sequence.
|
||||
// So do not update p.Sequence.
|
||||
p.Timestamp = time.Now().UnixNano()
|
||||
} else {
|
||||
o.pending[sseq] = &Pending{dseq, time.Now().UnixNano()}
|
||||
}
|
||||
}
|
||||
|
||||
// Credit back a failed delivery.
|
||||
@@ -6503,6 +6511,10 @@ func (o *consumer) checkStateForInterestStream(ss *StreamState) error {
|
||||
retryAsflr = seq
|
||||
}
|
||||
} else if seq <= dflr {
|
||||
// Store the first entry above our ack floor, so we don't need to look it up again on retryAsflr=0.
|
||||
if retryAsflr == 0 {
|
||||
retryAsflr = seq
|
||||
}
|
||||
// If we have pending, we will need to walk through to delivered in case we missed any of those acks as well.
|
||||
if _, ok := state.Pending[seq]; !ok {
|
||||
// The filters are already taken into account,
|
||||
@@ -6514,8 +6526,18 @@ func (o *consumer) checkStateForInterestStream(ss *StreamState) error {
|
||||
}
|
||||
}
|
||||
// If retry floor was not overwritten, set to ack floor+1, we don't need to account for any retries below it.
|
||||
// However, our ack floor may be lower than the next message we can receive, so we correct it upward if needed.
|
||||
if retryAsflr == 0 {
|
||||
retryAsflr = asflr + 1
|
||||
if filters != nil {
|
||||
_, nseq, err = store.LoadNextMsgMulti(filters, asflr+1, &smv)
|
||||
} else {
|
||||
_, nseq, err = store.LoadNextMsg(filter, wc, asflr+1, &smv)
|
||||
}
|
||||
if err == nil {
|
||||
retryAsflr = max(asflr+1, nseq)
|
||||
} else if err == ErrStoreEOF {
|
||||
retryAsflr = ss.LastSeq + 1
|
||||
}
|
||||
}
|
||||
|
||||
o.mu.Lock()
|
||||
|
||||
+268
-103
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2025 The NATS Authors
|
||||
// Copyright 2019-2026 The NATS Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
@@ -201,7 +201,7 @@ type fileStore struct {
|
||||
sips int
|
||||
dirty int
|
||||
closing bool
|
||||
closed bool
|
||||
closed atomic.Bool // Atomic to reduce contention on ConsumerStores.
|
||||
fip bool
|
||||
receivedAny bool
|
||||
firstMoved bool
|
||||
@@ -473,10 +473,18 @@ func newFileStoreWithCreated(fcfg FileStoreConfig, cfg StreamConfig, created tim
|
||||
}
|
||||
|
||||
keyFile := filepath.Join(fs.fcfg.StoreDir, JetStreamMetaFileKey)
|
||||
_, err = os.Stat(keyFile)
|
||||
// Either the file should exist (err=nil), or it shouldn't. Any other error is reported.
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return nil, err
|
||||
}
|
||||
// Make sure we do not have an encrypted store underneath of us but no main key.
|
||||
if fs.prf == nil {
|
||||
if _, err := os.Stat(keyFile); err == nil {
|
||||
return nil, errNoMainKey
|
||||
if fs.prf == nil && err == nil {
|
||||
return nil, errNoMainKey
|
||||
} else if fs.prf != nil && err == nil {
|
||||
// If encryption is configured and the key file exists, recover our keys.
|
||||
if err = fs.recoverAEK(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1784,16 +1792,14 @@ func (fs *fileStore) recoverFullState() (rerr error) {
|
||||
}
|
||||
|
||||
// Decrypt if needed.
|
||||
if fs.prf != nil {
|
||||
// We can be setup for encryption but if this is a snapshot restore we will be missing the keyfile
|
||||
// since snapshots strip encryption.
|
||||
if err := fs.recoverAEK(); err == nil {
|
||||
ns := fs.aek.NonceSize()
|
||||
buf, err = fs.aek.Open(nil, buf[:ns], buf[ns:], nil)
|
||||
if err != nil {
|
||||
fs.warn("Stream state error reading encryption key: %v", err)
|
||||
return err
|
||||
}
|
||||
// We can be setup for encryption but if this is a snapshot restore we will be missing the keyfile
|
||||
// since snapshots strip encryption.
|
||||
if fs.prf != nil && fs.aek != nil {
|
||||
ns := fs.aek.NonceSize()
|
||||
buf, err = fs.aek.Open(nil, buf[:ns], buf[ns:], nil)
|
||||
if err != nil {
|
||||
fs.warn("Stream state error reading encryption key: %v", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2346,7 +2352,7 @@ func (fs *fileStore) recoverMsgs() error {
|
||||
if fs.ld != nil {
|
||||
var emptyBlks []*msgBlock
|
||||
for _, mb := range fs.blks {
|
||||
if mb.msgs == 0 && mb.rbytes == 0 {
|
||||
if mb.msgs == 0 && mb.rbytes == 0 && mb != fs.lmb {
|
||||
emptyBlks = append(emptyBlks, mb)
|
||||
}
|
||||
}
|
||||
@@ -2588,7 +2594,7 @@ func copyMsgBlocks(src []*msgBlock) []*msgBlock {
|
||||
func (fs *fileStore) GetSeqFromTime(t time.Time) uint64 {
|
||||
fs.mu.RLock()
|
||||
lastSeq := fs.state.LastSeq
|
||||
closed := fs.closed
|
||||
closed := fs.isClosed()
|
||||
fs.mu.RUnlock()
|
||||
|
||||
if closed {
|
||||
@@ -2603,20 +2609,51 @@ func (fs *fileStore) GetSeqFromTime(t time.Time) uint64 {
|
||||
fseq := atomic.LoadUint64(&mb.first.seq)
|
||||
lseq := atomic.LoadUint64(&mb.last.seq)
|
||||
|
||||
var smv StoreMsg
|
||||
var (
|
||||
smv StoreMsg
|
||||
cts int64
|
||||
cseq uint64
|
||||
off uint64
|
||||
)
|
||||
ts := t.UnixNano()
|
||||
|
||||
// Because sort.Search expects range [0,off), we have to manually
|
||||
// calculate the offset from the first sequence.
|
||||
off := int(lseq - fseq + 1)
|
||||
i := sort.Search(off, func(i int) bool {
|
||||
sm, _, _ := mb.fetchMsgNoCopy(fseq+uint64(i), &smv)
|
||||
return sm != nil && sm.ts >= ts
|
||||
})
|
||||
if i < off {
|
||||
return fseq + uint64(i)
|
||||
// Using a binary search, but need to be aware of interior deletes in the block.
|
||||
seq := lseq + 1
|
||||
loop:
|
||||
for fseq <= lseq {
|
||||
mid := fseq + (lseq-fseq)/2
|
||||
off = 0
|
||||
// Potentially skip over gaps. We keep the original middle but keep track of a
|
||||
// potential delete range with an offset.
|
||||
for {
|
||||
sm, _, err := mb.fetchMsgNoCopy(mid+off, &smv)
|
||||
if err != nil || sm == nil {
|
||||
off++
|
||||
if mid+off <= lseq {
|
||||
continue
|
||||
} else {
|
||||
// Continue search to the left. Purposely ignore the skipped deletes here.
|
||||
lseq = mid - 1
|
||||
continue loop
|
||||
}
|
||||
}
|
||||
cts = sm.ts
|
||||
cseq = sm.seq
|
||||
break
|
||||
}
|
||||
if cts >= ts {
|
||||
seq = cseq
|
||||
if mid == fseq {
|
||||
break
|
||||
}
|
||||
// Continue search to the left.
|
||||
lseq = mid - 1
|
||||
} else {
|
||||
// Continue search to the right (potentially skipping over interior deletes).
|
||||
fseq = mid + off + 1
|
||||
}
|
||||
}
|
||||
return 0
|
||||
return seq
|
||||
}
|
||||
|
||||
// Find the first matching message against a sublist.
|
||||
@@ -2632,13 +2669,15 @@ func (mb *msgBlock) firstMatchingMulti(sl *gsl.SimpleSublist, start uint64, sm *
|
||||
mb.mu.Unlock()
|
||||
}()
|
||||
|
||||
// Need messages loaded from here on out.
|
||||
if mb.cacheNotLoaded() {
|
||||
if mb.fssNotLoaded() {
|
||||
// Make sure we have fss loaded.
|
||||
if err := mb.loadMsgsWithLock(); err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
didLoad = true
|
||||
}
|
||||
// Mark fss activity.
|
||||
mb.lsts = ats.AccessTime()
|
||||
|
||||
// Make sure to start at mb.first.seq if fseq < mb.first.seq
|
||||
if seq := atomic.LoadUint64(&mb.first.seq); seq > start {
|
||||
@@ -2646,10 +2685,6 @@ func (mb *msgBlock) firstMatchingMulti(sl *gsl.SimpleSublist, start uint64, sm *
|
||||
}
|
||||
lseq := atomic.LoadUint64(&mb.last.seq)
|
||||
|
||||
if sm == nil {
|
||||
sm = new(StoreMsg)
|
||||
}
|
||||
|
||||
// If the FSS state has fewer entries than sequences in the linear scan,
|
||||
// then use intersection instead as likely going to be cheaper. This will
|
||||
// often be the case with high numbers of deletes, as well as a smaller
|
||||
@@ -2657,7 +2692,11 @@ func (mb *msgBlock) firstMatchingMulti(sl *gsl.SimpleSublist, start uint64, sm *
|
||||
if uint64(mb.fss.Size()) < lseq-start {
|
||||
// If there are no subject matches then this is effectively no-op.
|
||||
hseq := uint64(math.MaxUint64)
|
||||
gsl.IntersectStree(mb.fss, sl, func(subj []byte, ss *SimpleState) {
|
||||
var ierr error
|
||||
stree.IntersectGSL(mb.fss, sl, func(subj []byte, ss *SimpleState) {
|
||||
if ierr != nil {
|
||||
return
|
||||
}
|
||||
if ss.firstNeedsUpdate || ss.lastNeedsUpdate {
|
||||
// mb is already loaded into the cache so should be fast-ish.
|
||||
mb.recalculateForSubj(bytesToString(subj), ss)
|
||||
@@ -2669,6 +2708,16 @@ func (mb *msgBlock) firstMatchingMulti(sl *gsl.SimpleSublist, start uint64, sm *
|
||||
// than our first seq for this subject.
|
||||
return
|
||||
}
|
||||
// Need messages loaded from here on out.
|
||||
if mb.cacheNotLoaded() {
|
||||
if ierr = mb.loadMsgsWithLock(); ierr != nil {
|
||||
return
|
||||
}
|
||||
didLoad = true
|
||||
}
|
||||
if sm == nil {
|
||||
sm = new(StoreMsg)
|
||||
}
|
||||
if first == ss.First {
|
||||
// If the start floor is below where this subject starts then we can
|
||||
// short-circuit, avoiding needing to scan for the next message.
|
||||
@@ -2703,10 +2752,24 @@ func (mb *msgBlock) firstMatchingMulti(sl *gsl.SimpleSublist, start uint64, sm *
|
||||
mb.llseq = llseq
|
||||
}
|
||||
})
|
||||
if ierr != nil {
|
||||
return nil, false, ierr
|
||||
}
|
||||
if hseq < uint64(math.MaxUint64) && sm != nil {
|
||||
return sm, didLoad && start == lseq, nil
|
||||
}
|
||||
} else {
|
||||
// Need messages loaded from here on out.
|
||||
if mb.cacheNotLoaded() {
|
||||
if err := mb.loadMsgsWithLock(); err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
didLoad = true
|
||||
}
|
||||
if sm == nil {
|
||||
sm = new(StoreMsg)
|
||||
}
|
||||
|
||||
for seq := start; seq <= lseq; seq++ {
|
||||
if mb.dmap.Exists(seq) {
|
||||
// Optimisation to avoid calling cacheLookup which hits time.Now().
|
||||
@@ -2773,6 +2836,10 @@ func (mb *msgBlock) firstMatching(filter string, wc bool, start uint64, sm *Stor
|
||||
isAll = true
|
||||
})
|
||||
}
|
||||
// If the only subject in this block isn't our filter, can simply short-circuit.
|
||||
if !isAll {
|
||||
return nil, didLoad, ErrStoreMsgNotFound
|
||||
}
|
||||
}
|
||||
// Make sure to start at mb.first.seq if fseq < mb.first.seq
|
||||
fseq = max(fseq, atomic.LoadUint64(&mb.first.seq))
|
||||
@@ -2909,7 +2976,7 @@ func (mb *msgBlock) prevMatchingMulti(sl *gsl.SimpleSublist, start uint64, sm *S
|
||||
if uint64(mb.fss.Size()) < start-lseq {
|
||||
// If there are no subject matches then this is effectively no-op.
|
||||
hseq := uint64(0)
|
||||
gsl.IntersectStree(mb.fss, sl, func(subj []byte, ss *SimpleState) {
|
||||
stree.IntersectGSL(mb.fss, sl, func(subj []byte, ss *SimpleState) {
|
||||
if ss.firstNeedsUpdate || ss.lastNeedsUpdate {
|
||||
// mb is already loaded into the cache so should be fast-ish.
|
||||
mb.recalculateForSubj(bytesToString(subj), ss)
|
||||
@@ -3188,6 +3255,30 @@ func (fs *fileStore) checkSkipFirstBlock(filter string, wc bool, bi int) (int, e
|
||||
if start == uint32(math.MaxUint32) {
|
||||
return -1, ErrStoreEOF
|
||||
}
|
||||
return fs.selectSkipFirstBlock(bi, start, stop)
|
||||
}
|
||||
|
||||
// This is used to see if we can selectively jump start blocks based on filter subjects and a starting block index.
|
||||
// Will return -1 and ErrStoreEOF if no matches at all or no more from where we are.
|
||||
func (fs *fileStore) checkSkipFirstBlockMulti(sl *gsl.SimpleSublist, bi int) (int, error) {
|
||||
// Move through psim to gather start and stop bounds.
|
||||
start, stop := uint32(math.MaxUint32), uint32(0)
|
||||
stree.IntersectGSL(fs.psim, sl, func(subj []byte, psi *psi) {
|
||||
if psi.fblk < start {
|
||||
start = psi.fblk
|
||||
}
|
||||
if psi.lblk > stop {
|
||||
stop = psi.lblk
|
||||
}
|
||||
})
|
||||
// Nothing was found.
|
||||
if start == uint32(math.MaxUint32) {
|
||||
return -1, ErrStoreEOF
|
||||
}
|
||||
return fs.selectSkipFirstBlock(bi, start, stop)
|
||||
}
|
||||
|
||||
func (fs *fileStore) selectSkipFirstBlock(bi int, start, stop uint32) (int, error) {
|
||||
// Can not be nil so ok to inline dereference.
|
||||
mbi := fs.blks[bi].getIndex()
|
||||
// All matching msgs are behind us.
|
||||
@@ -4006,7 +4097,7 @@ func (fs *fileStore) NumPendingMulti(sseq uint64, sl *gsl.SimpleSublist, lastPer
|
||||
mb := fs.blks[seqStart]
|
||||
bi := mb.index
|
||||
|
||||
gsl.IntersectStree(fs.psim, sl, func(subj []byte, psi *psi) {
|
||||
stree.IntersectGSL(fs.psim, sl, func(subj []byte, psi *psi) {
|
||||
// If the select blk start is greater than entry's last blk skip.
|
||||
if bi > psi.lblk {
|
||||
return
|
||||
@@ -4105,7 +4196,7 @@ func (fs *fileStore) NumPendingMulti(sseq uint64, sl *gsl.SimpleSublist, lastPer
|
||||
var t uint64
|
||||
var havePartial bool
|
||||
var updateLLTS bool
|
||||
gsl.IntersectStree[SimpleState](mb.fss, sl, func(bsubj []byte, ss *SimpleState) {
|
||||
stree.IntersectGSL[SimpleState](mb.fss, sl, func(bsubj []byte, ss *SimpleState) {
|
||||
subj := bytesToString(bsubj)
|
||||
if havePartial {
|
||||
// If we already found a partial then don't do anything else.
|
||||
@@ -4168,7 +4259,7 @@ func (fs *fileStore) NumPendingMulti(sseq uint64, sl *gsl.SimpleSublist, lastPer
|
||||
|
||||
// If we are here it's better to calculate totals from psim and adjust downward by scanning less blocks.
|
||||
start := uint32(math.MaxUint32)
|
||||
gsl.IntersectStree(fs.psim, sl, func(subj []byte, psi *psi) {
|
||||
stree.IntersectGSL(fs.psim, sl, func(subj []byte, psi *psi) {
|
||||
total += psi.total
|
||||
// Keep track of start index for this subject.
|
||||
if psi.fblk < start {
|
||||
@@ -4219,7 +4310,7 @@ func (fs *fileStore) NumPendingMulti(sseq uint64, sl *gsl.SimpleSublist, lastPer
|
||||
}
|
||||
// Mark fss activity.
|
||||
mb.lsts = ats.AccessTime()
|
||||
gsl.IntersectStree(mb.fss, sl, func(bsubj []byte, ss *SimpleState) {
|
||||
stree.IntersectGSL(mb.fss, sl, func(bsubj []byte, ss *SimpleState) {
|
||||
adjust += ss.Msgs
|
||||
})
|
||||
}
|
||||
@@ -4486,7 +4577,7 @@ func (fs *fileStore) genEncryptionKeysForBlock(mb *msgBlock) error {
|
||||
// Stores a raw message with expected sequence number and timestamp.
|
||||
// Lock should be held.
|
||||
func (fs *fileStore) storeRawMsg(subj string, hdr, msg []byte, seq uint64, ts, ttl int64) (err error) {
|
||||
if fs.closed {
|
||||
if fs.isClosed() {
|
||||
return ErrStoreClosed
|
||||
}
|
||||
|
||||
@@ -5159,7 +5250,7 @@ func (fs *fileStore) removeMsg(seq uint64, secure, viaLimits, needFSLock bool) (
|
||||
|
||||
fsLock()
|
||||
|
||||
if fs.closed {
|
||||
if fs.isClosed() {
|
||||
fsUnlock()
|
||||
return false, ErrStoreClosed
|
||||
}
|
||||
@@ -5369,14 +5460,8 @@ func (fs *fileStore) removeMsg(seq uint64, secure, viaLimits, needFSLock bool) (
|
||||
// If we have a callback registered we need to release lock regardless since cb might need it to lookup msg, etc.
|
||||
fs.mu.Unlock()
|
||||
// Storage updates.
|
||||
if cb != nil {
|
||||
var subj string
|
||||
if sm != nil {
|
||||
subj = sm.subj
|
||||
}
|
||||
delta := int64(msz)
|
||||
cb(-1, -delta, seq, subj)
|
||||
}
|
||||
delta := int64(msz)
|
||||
cb(-1, -delta, seq, sm.subj)
|
||||
|
||||
if !needFSLock {
|
||||
fs.mu.Lock()
|
||||
@@ -5611,10 +5696,7 @@ func (mb *msgBlock) slotInfo(slot int) (uint32, uint32, bool, error) {
|
||||
}
|
||||
|
||||
func (fs *fileStore) isClosed() bool {
|
||||
fs.mu.RLock()
|
||||
closed := fs.closed
|
||||
fs.mu.RUnlock()
|
||||
return closed
|
||||
return fs.closed.Load()
|
||||
}
|
||||
|
||||
// Will spin up our flush loop.
|
||||
@@ -6995,11 +7077,10 @@ func (mb *msgBlock) ensureRawBytesLoaded() error {
|
||||
|
||||
// Sync msg and index files as needed. This is called from a timer.
|
||||
func (fs *fileStore) syncBlocks() {
|
||||
fs.mu.Lock()
|
||||
if fs.closed {
|
||||
fs.mu.Unlock()
|
||||
if fs.isClosed() {
|
||||
return
|
||||
}
|
||||
fs.mu.Lock()
|
||||
blks := append([]*msgBlock(nil), fs.blks...)
|
||||
lmb, firstMoved, firstSeq := fs.lmb, fs.firstMoved, fs.state.FirstSeq
|
||||
// Clear first moved.
|
||||
@@ -7089,11 +7170,10 @@ func (fs *fileStore) syncBlocks() {
|
||||
}
|
||||
}
|
||||
|
||||
fs.mu.Lock()
|
||||
if fs.closed {
|
||||
fs.mu.Unlock()
|
||||
if fs.isClosed() {
|
||||
return
|
||||
}
|
||||
fs.mu.Lock()
|
||||
fs.setSyncTimer()
|
||||
if markDirty {
|
||||
fs.dirty++
|
||||
@@ -7939,17 +8019,14 @@ func (fs *fileStore) msgForSeq(seq uint64, sm *StoreMsg) (*StoreMsg, error) {
|
||||
|
||||
// Will return message for the given sequence number.
|
||||
func (fs *fileStore) msgForSeqLocked(seq uint64, sm *StoreMsg, needFSLock bool) (*StoreMsg, error) {
|
||||
if fs.isClosed() {
|
||||
return nil, ErrStoreClosed
|
||||
}
|
||||
// TODO(dlc) - Since Store, Remove, Skip all hold the write lock on fs this will
|
||||
// be stalled. Need another lock if want to happen in parallel.
|
||||
if needFSLock {
|
||||
fs.mu.RLock()
|
||||
}
|
||||
if fs.closed {
|
||||
if needFSLock {
|
||||
fs.mu.RUnlock()
|
||||
}
|
||||
return nil, ErrStoreClosed
|
||||
}
|
||||
// Indicates we want first msg.
|
||||
if seq == 0 {
|
||||
seq = fs.state.FirstSeq
|
||||
@@ -8128,10 +8205,14 @@ func (fs *fileStore) LoadMsg(seq uint64, sm *StoreMsg) (*StoreMsg, error) {
|
||||
|
||||
// loadLast will load the last message for a subject. Subject should be non empty and not ">".
|
||||
func (fs *fileStore) loadLast(subj string, sm *StoreMsg) (lsm *StoreMsg, err error) {
|
||||
if fs.isClosed() {
|
||||
return nil, ErrStoreClosed
|
||||
}
|
||||
|
||||
fs.mu.RLock()
|
||||
defer fs.mu.RUnlock()
|
||||
|
||||
if fs.closed || fs.lmb == nil {
|
||||
if fs.lmb == nil {
|
||||
return nil, ErrStoreClosed
|
||||
}
|
||||
|
||||
@@ -8228,15 +8309,15 @@ func (fs *fileStore) LoadLastMsg(subject string, smv *StoreMsg) (sm *StoreMsg, e
|
||||
|
||||
// LoadNextMsgMulti will find the next message matching any entry in the sublist.
|
||||
func (fs *fileStore) LoadNextMsgMulti(sl *gsl.SimpleSublist, start uint64, smp *StoreMsg) (sm *StoreMsg, skip uint64, err error) {
|
||||
if fs.isClosed() {
|
||||
return nil, 0, ErrStoreClosed
|
||||
}
|
||||
if sl == nil {
|
||||
return fs.LoadNextMsg(_EMPTY_, false, start, smp)
|
||||
}
|
||||
fs.mu.RLock()
|
||||
defer fs.mu.RUnlock()
|
||||
|
||||
if fs.closed {
|
||||
return nil, 0, ErrStoreClosed
|
||||
}
|
||||
if fs.state.Msgs == 0 || start > fs.state.LastSeq {
|
||||
return nil, fs.state.LastSeq, ErrStoreEOF
|
||||
}
|
||||
@@ -8244,6 +8325,31 @@ func (fs *fileStore) LoadNextMsgMulti(sl *gsl.SimpleSublist, start uint64, smp *
|
||||
start = fs.state.FirstSeq
|
||||
}
|
||||
|
||||
// If start is less than or equal to beginning of our stream, meaning our first call,
|
||||
// let's check the psim to see if we can skip ahead.
|
||||
if start <= fs.state.FirstSeq {
|
||||
var total uint64
|
||||
blkStart := uint32(math.MaxUint32)
|
||||
stree.IntersectGSL(fs.psim, sl, func(subj []byte, psi *psi) {
|
||||
total += psi.total
|
||||
// Keep track of start index for this subject.
|
||||
if psi.fblk < blkStart {
|
||||
blkStart = psi.fblk
|
||||
}
|
||||
})
|
||||
// Nothing available.
|
||||
if total == 0 {
|
||||
return nil, fs.state.LastSeq, ErrStoreEOF
|
||||
}
|
||||
// We can skip ahead.
|
||||
if mb := fs.bim[blkStart]; mb != nil {
|
||||
fseq := atomic.LoadUint64(&mb.first.seq)
|
||||
if fseq > start {
|
||||
start = fseq
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if bi, _ := fs.selectMsgBlockWithIndex(start); bi >= 0 {
|
||||
for i := bi; i < len(fs.blks); i++ {
|
||||
mb := fs.blks[i]
|
||||
@@ -8254,8 +8360,28 @@ func (fs *fileStore) LoadNextMsgMulti(sl *gsl.SimpleSublist, start uint64, smp *
|
||||
return sm, sm.seq, nil
|
||||
} else if err != ErrStoreMsgNotFound {
|
||||
return nil, 0, err
|
||||
} else if expireOk {
|
||||
mb.tryForceExpireCache()
|
||||
} else {
|
||||
// Nothing found in this block. We missed, if first block (bi) check psim.
|
||||
// Similar to above if start <= first seq.
|
||||
// TODO(dlc) - For v2 track these by filter subject since they will represent filtered consumers.
|
||||
// We should not do this at all if we are already on the last block.
|
||||
if i == bi && i < len(fs.blks)-1 {
|
||||
nbi, err := fs.checkSkipFirstBlockMulti(sl, bi)
|
||||
// Nothing available.
|
||||
if err == ErrStoreEOF {
|
||||
return nil, fs.state.LastSeq, ErrStoreEOF
|
||||
}
|
||||
// See if we can jump ahead here.
|
||||
// Right now we can only spin on first, so if we have interior sparseness need to favor checking per block fss if loaded.
|
||||
// For v2 will track all blocks that have matches for psim.
|
||||
if nbi > i {
|
||||
i = nbi - 1 // For the iterator condition i++
|
||||
}
|
||||
}
|
||||
// Check if we can expire.
|
||||
if expireOk {
|
||||
mb.tryForceExpireCache()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8265,12 +8391,13 @@ func (fs *fileStore) LoadNextMsgMulti(sl *gsl.SimpleSublist, start uint64, smp *
|
||||
}
|
||||
|
||||
func (fs *fileStore) LoadNextMsg(filter string, wc bool, start uint64, sm *StoreMsg) (*StoreMsg, uint64, error) {
|
||||
if fs.isClosed() {
|
||||
return nil, 0, ErrStoreClosed
|
||||
}
|
||||
|
||||
fs.mu.RLock()
|
||||
defer fs.mu.RUnlock()
|
||||
|
||||
if fs.closed {
|
||||
return nil, 0, ErrStoreClosed
|
||||
}
|
||||
if fs.state.Msgs == 0 || start > fs.state.LastSeq {
|
||||
return nil, fs.state.LastSeq, ErrStoreEOF
|
||||
}
|
||||
@@ -8323,7 +8450,7 @@ func (fs *fileStore) LoadNextMsg(filter string, wc bool, start uint64, sm *Store
|
||||
i = nbi - 1 // For the iterator condition i++
|
||||
}
|
||||
}
|
||||
// Check is we can expire.
|
||||
// Check if we can expire.
|
||||
if expireOk {
|
||||
mb.tryForceExpireCache()
|
||||
}
|
||||
@@ -8336,12 +8463,13 @@ func (fs *fileStore) LoadNextMsg(filter string, wc bool, start uint64, sm *Store
|
||||
|
||||
// Will load the next non-deleted msg starting at the start sequence and walking backwards.
|
||||
func (fs *fileStore) LoadPrevMsg(start uint64, smp *StoreMsg) (sm *StoreMsg, err error) {
|
||||
if fs.isClosed() {
|
||||
return nil, ErrStoreClosed
|
||||
}
|
||||
|
||||
fs.mu.RLock()
|
||||
defer fs.mu.RUnlock()
|
||||
|
||||
if fs.closed {
|
||||
return nil, ErrStoreClosed
|
||||
}
|
||||
if fs.state.Msgs == 0 || start < fs.state.FirstSeq {
|
||||
return nil, ErrStoreEOF
|
||||
}
|
||||
@@ -8389,6 +8517,10 @@ func (fs *fileStore) LoadPrevMsg(start uint64, smp *StoreMsg) (sm *StoreMsg, err
|
||||
|
||||
// LoadPrevMsgMulti will find the previous message matching any entry in the sublist.
|
||||
func (fs *fileStore) LoadPrevMsgMulti(sl *gsl.SimpleSublist, start uint64, smp *StoreMsg) (sm *StoreMsg, skip uint64, err error) {
|
||||
if fs.isClosed() {
|
||||
return nil, 0, ErrStoreClosed
|
||||
}
|
||||
|
||||
if sl == nil {
|
||||
sm, err = fs.LoadPrevMsg(start, smp)
|
||||
return
|
||||
@@ -8396,9 +8528,6 @@ func (fs *fileStore) LoadPrevMsgMulti(sl *gsl.SimpleSublist, start uint64, smp *
|
||||
fs.mu.RLock()
|
||||
defer fs.mu.RUnlock()
|
||||
|
||||
if fs.closed {
|
||||
return nil, 0, ErrStoreClosed
|
||||
}
|
||||
if fs.state.Msgs == 0 || start < fs.state.FirstSeq {
|
||||
return nil, fs.state.FirstSeq, ErrStoreEOF
|
||||
}
|
||||
@@ -8952,12 +9081,12 @@ func (fs *fileStore) Purge() (uint64, error) {
|
||||
}
|
||||
|
||||
func (fs *fileStore) purge(fseq uint64) (uint64, error) {
|
||||
fs.mu.Lock()
|
||||
if fs.closed {
|
||||
fs.mu.Unlock()
|
||||
if fs.isClosed() {
|
||||
return 0, ErrStoreClosed
|
||||
}
|
||||
|
||||
fs.mu.Lock()
|
||||
|
||||
purged := fs.state.Msgs
|
||||
rbytes := int64(fs.state.Bytes)
|
||||
|
||||
@@ -9065,6 +9194,11 @@ func (fs *fileStore) compact(seq uint64) (uint64, error) {
|
||||
fs.mu.Unlock()
|
||||
return fs.purge(seq)
|
||||
}
|
||||
// Short-circuit if the store was already compacted past this point.
|
||||
if fs.state.FirstSeq > seq {
|
||||
fs.mu.Unlock()
|
||||
return purged, nil
|
||||
}
|
||||
// We have to delete interior messages.
|
||||
smb := fs.selectMsgBlock(seq)
|
||||
if smb == nil {
|
||||
@@ -9112,7 +9246,12 @@ func (fs *fileStore) compact(seq uint64) (uint64, error) {
|
||||
if err = smb.loadMsgsWithLock(); err != nil {
|
||||
goto SKIP
|
||||
}
|
||||
defer smb.finishedWithCache()
|
||||
defer func() {
|
||||
// The lock is released once we get here, so need to re-acquire.
|
||||
smb.mu.Lock()
|
||||
smb.finishedWithCache()
|
||||
smb.mu.Unlock()
|
||||
}()
|
||||
}
|
||||
for mseq := atomic.LoadUint64(&smb.first.seq); mseq < seq; mseq++ {
|
||||
sm, err := smb.cacheLookupNoCopy(mseq, &smv)
|
||||
@@ -9290,12 +9429,12 @@ SKIP:
|
||||
|
||||
// Will completely reset our store.
|
||||
func (fs *fileStore) reset() error {
|
||||
fs.mu.Lock()
|
||||
if fs.closed {
|
||||
fs.mu.Unlock()
|
||||
if fs.isClosed() {
|
||||
return ErrStoreClosed
|
||||
}
|
||||
|
||||
fs.mu.Lock()
|
||||
|
||||
var purged, bytes uint64
|
||||
cb := fs.scb
|
||||
|
||||
@@ -9381,6 +9520,10 @@ func (mb *msgBlock) tombsLocked() []msgId {
|
||||
|
||||
// Truncate will truncate a stream store up to seq. Sequence needs to be valid.
|
||||
func (fs *fileStore) Truncate(seq uint64) error {
|
||||
if fs.isClosed() {
|
||||
return ErrStoreClosed
|
||||
}
|
||||
|
||||
// Check for request to reset.
|
||||
if seq == 0 {
|
||||
return fs.reset()
|
||||
@@ -9388,11 +9531,6 @@ func (fs *fileStore) Truncate(seq uint64) error {
|
||||
|
||||
fs.mu.Lock()
|
||||
|
||||
if fs.closed {
|
||||
fs.mu.Unlock()
|
||||
return ErrStoreClosed
|
||||
}
|
||||
|
||||
// Any existing state file will no longer be applicable. We will force write a new one
|
||||
// at the end, after we release the lock.
|
||||
os.Remove(filepath.Join(fs.fcfg.StoreDir, msgDir, streamStreamStateFile))
|
||||
@@ -9682,6 +9820,14 @@ func (fs *fileStore) purgeMsgBlock(mb *msgBlock) {
|
||||
mb.finishedWithCache()
|
||||
mb.mu.Unlock()
|
||||
fs.selectNextFirst()
|
||||
|
||||
if cb := fs.scb; cb != nil {
|
||||
// If we have a callback registered, we need to release lock regardless since consumers will recalculate pending.
|
||||
fs.mu.Unlock()
|
||||
// Storage updates.
|
||||
cb(-int64(msgs), -int64(bytes), 0, _EMPTY_)
|
||||
fs.mu.Lock()
|
||||
}
|
||||
}
|
||||
|
||||
// Called by purge to simply get rid of the cache and close our fds.
|
||||
@@ -9893,6 +10039,9 @@ func (mb *msgBlock) recalculateForSubj(subj string, ss *SimpleState) {
|
||||
func (fs *fileStore) resetGlobalPerSubjectInfo() {
|
||||
// Clear any global subject state.
|
||||
fs.psim, fs.tsl = fs.psim.Empty(), 0
|
||||
if fs.noTrackSubjects() {
|
||||
return
|
||||
}
|
||||
for _, mb := range fs.blks {
|
||||
fs.populateGlobalPerSubjectInfo(mb)
|
||||
}
|
||||
@@ -10230,6 +10379,10 @@ func (fs *fileStore) forceWriteFullStateLocked() error {
|
||||
// 3. MBs - Index, Bytes, First and Last Sequence and Timestamps, and the deleted map (avl.seqset).
|
||||
// 4. Last block index and hash of record inclusive to this stream state.
|
||||
func (fs *fileStore) _writeFullState(force, needLock bool) error {
|
||||
if fs.isClosed() {
|
||||
return nil
|
||||
}
|
||||
|
||||
fsLock := func() {
|
||||
if needLock {
|
||||
fs.mu.Lock()
|
||||
@@ -10243,7 +10396,7 @@ func (fs *fileStore) _writeFullState(force, needLock bool) error {
|
||||
|
||||
start := time.Now()
|
||||
fsLock()
|
||||
if fs.closed || fs.dirty == 0 {
|
||||
if fs.dirty == 0 {
|
||||
fsUnlock()
|
||||
return nil
|
||||
}
|
||||
@@ -10494,8 +10647,12 @@ func (fs *fileStore) Stop() error {
|
||||
|
||||
// Stop the current filestore.
|
||||
func (fs *fileStore) stop(delete, writeState bool) error {
|
||||
if fs.isClosed() {
|
||||
return ErrStoreClosed
|
||||
}
|
||||
|
||||
fs.mu.Lock()
|
||||
if fs.closed || fs.closing {
|
||||
if fs.closing {
|
||||
fs.mu.Unlock()
|
||||
return ErrStoreClosed
|
||||
}
|
||||
@@ -10531,7 +10688,7 @@ func (fs *fileStore) stop(delete, writeState bool) error {
|
||||
|
||||
// Mark as closed. Last message block needs to be cleared after
|
||||
// writeFullState has completed.
|
||||
fs.closed = true
|
||||
fs.closed.Store(true)
|
||||
fs.lmb = nil
|
||||
|
||||
// We should update the upper usage layer on a stop.
|
||||
@@ -10750,11 +10907,12 @@ func (fs *fileStore) streamSnapshot(w io.WriteCloser, includeConsumers bool, err
|
||||
|
||||
// Create a snapshot of this stream and its consumer's state along with messages.
|
||||
func (fs *fileStore) Snapshot(deadline time.Duration, checkMsgs, includeConsumers bool) (*SnapshotResult, error) {
|
||||
fs.mu.Lock()
|
||||
if fs.closed {
|
||||
fs.mu.Unlock()
|
||||
if fs.isClosed() {
|
||||
return nil, ErrStoreClosed
|
||||
}
|
||||
|
||||
fs.mu.Lock()
|
||||
|
||||
// Only allow one at a time.
|
||||
if fs.sips > 0 {
|
||||
fs.mu.Unlock()
|
||||
@@ -11074,7 +11232,9 @@ func (fs *fileStore) ConsumerStore(name string, created time.Time, cfg *Consumer
|
||||
go o.flushLoop(o.fch, o.qch)
|
||||
|
||||
// Make sure to load in our state from disk if needed.
|
||||
o.loadState()
|
||||
if err = o.loadState(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Assign to filestore.
|
||||
fs.AddConsumer(o)
|
||||
@@ -11764,10 +11924,15 @@ func (o *consumerFileStore) stateWithCopyLocked(doCopy bool) (*ConsumerState, er
|
||||
}
|
||||
|
||||
// Lock should be held. Called at startup.
|
||||
func (o *consumerFileStore) loadState() {
|
||||
func (o *consumerFileStore) loadState() error {
|
||||
if _, err := os.Stat(o.ifn); err == nil {
|
||||
// This will load our state in from disk.
|
||||
o.stateWithCopyLocked(false)
|
||||
_, err = o.stateWithCopyLocked(false)
|
||||
return err
|
||||
} else if os.IsNotExist(err) {
|
||||
return nil
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+42
-84
@@ -17,9 +17,6 @@ import (
|
||||
"errors"
|
||||
"strings"
|
||||
"sync"
|
||||
"unsafe"
|
||||
|
||||
"github.com/nats-io/nats-server/v2/server/stree"
|
||||
)
|
||||
|
||||
// Sublist is a routing mechanism to handle subject distribution and
|
||||
@@ -251,7 +248,9 @@ func matchLevelForAny[T comparable](l *level[T], toks []string, np *int) bool {
|
||||
if np != nil {
|
||||
*np += len(n.subs)
|
||||
}
|
||||
return len(n.subs) > 0
|
||||
if len(n.subs) > 0 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
if pwc != nil {
|
||||
if np != nil {
|
||||
@@ -370,6 +369,36 @@ func (s *GenericSublist[T]) Remove(subject string, value T) error {
|
||||
return s.remove(subject, value, true)
|
||||
}
|
||||
|
||||
// HasInterestStartingIn is a helper for subject tree intersection.
|
||||
func (s *GenericSublist[T]) HasInterestStartingIn(subj string) bool {
|
||||
s.RLock()
|
||||
defer s.RUnlock()
|
||||
var _tokens [64]string
|
||||
tokens := tokenizeSubjectIntoSlice(_tokens[:0], subj)
|
||||
return hasInterestStartingIn(s.root, tokens)
|
||||
}
|
||||
|
||||
func hasInterestStartingIn[T comparable](l *level[T], tokens []string) bool {
|
||||
if l == nil {
|
||||
return false
|
||||
}
|
||||
if len(tokens) == 0 {
|
||||
return true
|
||||
}
|
||||
token := tokens[0]
|
||||
if l.fwc != nil {
|
||||
return true
|
||||
}
|
||||
found := false
|
||||
if pwc := l.pwc; pwc != nil {
|
||||
found = found || hasInterestStartingIn(pwc.next, tokens[1:])
|
||||
}
|
||||
if n := l.nodes[token]; n != nil {
|
||||
found = found || hasInterestStartingIn(n.next, tokens[1:])
|
||||
}
|
||||
return found
|
||||
}
|
||||
|
||||
// pruneNode is used to prune an empty node from the tree.
|
||||
func (l *level[T]) pruneNode(n *node[T], t string) {
|
||||
if n == nil {
|
||||
@@ -463,86 +492,15 @@ func visitLevel[T comparable](l *level[T], depth int) int {
|
||||
return maxDepth
|
||||
}
|
||||
|
||||
// IntersectStree will match all items in the given subject tree that
|
||||
// have interest expressed in the given sublist. The callback will only be called
|
||||
// once for each subject, regardless of overlapping subscriptions in the sublist.
|
||||
func IntersectStree[T1 any, T2 comparable](st *stree.SubjectTree[T1], sl *GenericSublist[T2], cb func(subj []byte, entry *T1)) {
|
||||
var _subj [255]byte
|
||||
intersectStree(st, sl.root, _subj[:0], cb)
|
||||
}
|
||||
|
||||
func intersectStree[T1 any, T2 comparable](st *stree.SubjectTree[T1], r *level[T2], subj []byte, cb func(subj []byte, entry *T1)) {
|
||||
nsubj := subj
|
||||
if len(nsubj) > 0 {
|
||||
nsubj = append(subj, '.')
|
||||
}
|
||||
if r.fwc != nil {
|
||||
// We've reached a full wildcard, do a FWC match on the stree at this point
|
||||
// and don't keep iterating downward.
|
||||
nsubj := append(nsubj, '>')
|
||||
st.Match(nsubj, cb)
|
||||
return
|
||||
}
|
||||
if r.pwc != nil {
|
||||
// We've found a partial wildcard. We'll keep iterating downwards, but first
|
||||
// check whether there's interest at this level (without triggering dupes) and
|
||||
// match if so.
|
||||
var done bool
|
||||
nsubj := append(nsubj, '*')
|
||||
if len(r.pwc.subs) > 0 {
|
||||
st.Match(nsubj, cb)
|
||||
done = true
|
||||
}
|
||||
if r.pwc.next.numNodes() > 0 {
|
||||
intersectStree(st, r.pwc.next, nsubj, cb)
|
||||
}
|
||||
if done {
|
||||
return
|
||||
}
|
||||
}
|
||||
// Normal node with subject literals, keep iterating.
|
||||
for t, n := range r.nodes {
|
||||
if r.pwc != nil && r.pwc.next.numNodes() > 0 && n.next.numNodes() > 0 {
|
||||
// A wildcard at the next level will already visit these descendents
|
||||
// so skip so we don't callback the same subject more than once.
|
||||
continue
|
||||
// use similar to append. meaning, the updated slice will be returned
|
||||
func tokenizeSubjectIntoSlice(tts []string, subject string) []string {
|
||||
start := 0
|
||||
for i := 0; i < len(subject); i++ {
|
||||
if subject[i] == btsep {
|
||||
tts = append(tts, subject[start:i])
|
||||
start = i + 1
|
||||
}
|
||||
nsubj := append(nsubj, t...)
|
||||
if len(n.subs) > 0 {
|
||||
if subjectHasWildcard(bytesToString(nsubj)) {
|
||||
st.Match(nsubj, cb)
|
||||
} else {
|
||||
if e, ok := st.Find(nsubj); ok {
|
||||
cb(nsubj, e)
|
||||
}
|
||||
}
|
||||
}
|
||||
if n.next.numNodes() > 0 {
|
||||
intersectStree(st, n.next, nsubj, cb)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Determine if a subject has any wildcard tokens.
|
||||
func subjectHasWildcard(subject string) bool {
|
||||
// This one exits earlier then !subjectIsLiteral(subject)
|
||||
for i, c := range subject {
|
||||
if c == pwc || c == fwc {
|
||||
if (i == 0 || subject[i-1] == btsep) &&
|
||||
(i+1 == len(subject) || subject[i+1] == btsep) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Note this will avoid a copy of the data used for the string, but it will also reference the existing slice's data pointer.
|
||||
// So this should be used sparingly when we know the encompassing byte slice's lifetime is the same.
|
||||
func bytesToString(b []byte) string {
|
||||
if len(b) == 0 {
|
||||
return _EMPTY_
|
||||
}
|
||||
p := unsafe.SliceData(b)
|
||||
return unsafe.String(p, len(b))
|
||||
tts = append(tts, subject[start:])
|
||||
return tts
|
||||
}
|
||||
|
||||
+8
-5
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2025 The NATS Authors
|
||||
// Copyright 2019-2026 The NATS Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
@@ -1142,6 +1142,12 @@ func (a *Account) EnableJetStream(limits map[string]JetStreamAccountLimits, tq c
|
||||
}
|
||||
|
||||
js.mu.Lock()
|
||||
// Accounts get reset to nil on shutdown, since we re-acquire the locks here, we need to check again.
|
||||
if js.accounts == nil {
|
||||
js.mu.Unlock()
|
||||
return NewJSNotEnabledError()
|
||||
}
|
||||
|
||||
if jsa, ok := js.accounts[a.Name]; ok {
|
||||
a.mu.Lock()
|
||||
a.js = jsa
|
||||
@@ -1370,7 +1376,7 @@ func (a *Account) EnableJetStream(limits map[string]JetStreamAccountLimits, tq c
|
||||
}
|
||||
obs, err := mset.addConsumerWithAssignment(&cfg.ConsumerConfig, _EMPTY_, nil, true, ActionCreateOrUpdate, false)
|
||||
if err != nil {
|
||||
s.Warnf(" Error adding consumer %q: %v", cfg.Name, err)
|
||||
s.Warnf(" Error adding consumer '%s > %s > %s': %v", a.Name, mset.name(), cfg.Name, err)
|
||||
continue
|
||||
}
|
||||
if isEphemeral {
|
||||
@@ -1379,9 +1385,6 @@ func (a *Account) EnableJetStream(limits map[string]JetStreamAccountLimits, tq c
|
||||
if !cfg.Created.IsZero() {
|
||||
obs.setCreatedTime(cfg.Created)
|
||||
}
|
||||
if err != nil {
|
||||
s.Warnf(" Error restoring consumer %q state: %v", cfg.Name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+150
-133
@@ -1,4 +1,4 @@
|
||||
// Copyright 2020-2025 The NATS Authors
|
||||
// Copyright 2020-2026 The NATS Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
@@ -1296,11 +1296,6 @@ func (s *Server) jsAccountInfoRequest(sub *subscription, c *client, _ *Account,
|
||||
}
|
||||
|
||||
var resp = JSApiAccountInfoResponse{ApiResponse: ApiResponse{Type: JSApiAccountInfoResponseType}}
|
||||
if errorOnRequiredApiLevel(hdr) {
|
||||
resp.Error = NewJSRequiredApiLevelError()
|
||||
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
|
||||
return
|
||||
}
|
||||
|
||||
// Determine if we should proceed here when we are in clustered mode.
|
||||
if s.JetStreamIsClustered() {
|
||||
@@ -1319,6 +1314,12 @@ func (s *Server) jsAccountInfoRequest(sub *subscription, c *client, _ *Account,
|
||||
}
|
||||
}
|
||||
|
||||
if errorOnRequiredApiLevel(hdr) {
|
||||
resp.Error = NewJSRequiredApiLevelError()
|
||||
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
|
||||
return
|
||||
}
|
||||
|
||||
if hasJS, doErr := acc.checkJetStream(); !hasJS {
|
||||
if !doErr {
|
||||
return
|
||||
@@ -1612,11 +1613,6 @@ func (s *Server) jsStreamCreateRequest(sub *subscription, c *client, _ *Account,
|
||||
}
|
||||
|
||||
var resp = JSApiStreamCreateResponse{ApiResponse: ApiResponse{Type: JSApiStreamCreateResponseType}}
|
||||
if errorOnRequiredApiLevel(hdr) {
|
||||
resp.Error = NewJSRequiredApiLevelError()
|
||||
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
|
||||
return
|
||||
}
|
||||
|
||||
// Determine if we should proceed here when we are in clustered mode.
|
||||
if s.JetStreamIsClustered() {
|
||||
@@ -1635,6 +1631,12 @@ func (s *Server) jsStreamCreateRequest(sub *subscription, c *client, _ *Account,
|
||||
}
|
||||
}
|
||||
|
||||
if errorOnRequiredApiLevel(hdr) {
|
||||
resp.Error = NewJSRequiredApiLevelError()
|
||||
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
|
||||
return
|
||||
}
|
||||
|
||||
if hasJS, doErr := acc.checkJetStream(); !hasJS {
|
||||
if doErr {
|
||||
resp.Error = NewJSNotEnabledForAccountError()
|
||||
@@ -1729,11 +1731,6 @@ func (s *Server) jsStreamUpdateRequest(sub *subscription, c *client, _ *Account,
|
||||
}
|
||||
|
||||
var resp = JSApiStreamUpdateResponse{ApiResponse: ApiResponse{Type: JSApiStreamUpdateResponseType}}
|
||||
if errorOnRequiredApiLevel(hdr) {
|
||||
resp.Error = NewJSRequiredApiLevelError()
|
||||
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
|
||||
return
|
||||
}
|
||||
|
||||
// Determine if we should proceed here when we are in clustered mode.
|
||||
if s.JetStreamIsClustered() {
|
||||
@@ -1752,6 +1749,12 @@ func (s *Server) jsStreamUpdateRequest(sub *subscription, c *client, _ *Account,
|
||||
}
|
||||
}
|
||||
|
||||
if errorOnRequiredApiLevel(hdr) {
|
||||
resp.Error = NewJSRequiredApiLevelError()
|
||||
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
|
||||
return
|
||||
}
|
||||
|
||||
if hasJS, doErr := acc.checkJetStream(); !hasJS {
|
||||
if doErr {
|
||||
resp.Error = NewJSNotEnabledForAccountError()
|
||||
@@ -1832,11 +1835,6 @@ func (s *Server) jsStreamNamesRequest(sub *subscription, c *client, _ *Account,
|
||||
}
|
||||
|
||||
var resp = JSApiStreamNamesResponse{ApiResponse: ApiResponse{Type: JSApiStreamNamesResponseType}}
|
||||
if errorOnRequiredApiLevel(hdr) {
|
||||
resp.Error = NewJSRequiredApiLevelError()
|
||||
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
|
||||
return
|
||||
}
|
||||
|
||||
// Determine if we should proceed here when we are in clustered mode.
|
||||
if s.JetStreamIsClustered() {
|
||||
@@ -1855,6 +1853,12 @@ func (s *Server) jsStreamNamesRequest(sub *subscription, c *client, _ *Account,
|
||||
}
|
||||
}
|
||||
|
||||
if errorOnRequiredApiLevel(hdr) {
|
||||
resp.Error = NewJSRequiredApiLevelError()
|
||||
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
|
||||
return
|
||||
}
|
||||
|
||||
if hasJS, doErr := acc.checkJetStream(); !hasJS {
|
||||
if doErr {
|
||||
resp.Error = NewJSNotEnabledForAccountError()
|
||||
@@ -1967,11 +1971,6 @@ func (s *Server) jsStreamListRequest(sub *subscription, c *client, _ *Account, s
|
||||
ApiResponse: ApiResponse{Type: JSApiStreamListResponseType},
|
||||
Streams: []*StreamInfo{},
|
||||
}
|
||||
if errorOnRequiredApiLevel(hdr) {
|
||||
resp.Error = NewJSRequiredApiLevelError()
|
||||
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
|
||||
return
|
||||
}
|
||||
|
||||
// Determine if we should proceed here when we are in clustered mode.
|
||||
if s.JetStreamIsClustered() {
|
||||
@@ -1990,6 +1989,12 @@ func (s *Server) jsStreamListRequest(sub *subscription, c *client, _ *Account, s
|
||||
}
|
||||
}
|
||||
|
||||
if errorOnRequiredApiLevel(hdr) {
|
||||
resp.Error = NewJSRequiredApiLevelError()
|
||||
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
|
||||
return
|
||||
}
|
||||
|
||||
if hasJS, doErr := acc.checkJetStream(); !hasJS {
|
||||
if doErr {
|
||||
resp.Error = NewJSNotEnabledForAccountError()
|
||||
@@ -2090,11 +2095,6 @@ func (s *Server) jsStreamInfoRequest(sub *subscription, c *client, a *Account, s
|
||||
if rt := getHeader(JSResponseType, hdr); len(rt) > 0 && string(rt) == jsCreateResponse {
|
||||
resp.ApiResponse.Type = JSApiStreamCreateResponseType
|
||||
}
|
||||
if errorOnRequiredApiLevel(hdr) {
|
||||
resp.Error = NewJSRequiredApiLevelError()
|
||||
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
|
||||
return
|
||||
}
|
||||
|
||||
var clusterWideConsCount int
|
||||
|
||||
@@ -2184,6 +2184,12 @@ func (s *Server) jsStreamInfoRequest(sub *subscription, c *client, a *Account, s
|
||||
}
|
||||
}
|
||||
|
||||
if errorOnRequiredApiLevel(hdr) {
|
||||
resp.Error = NewJSRequiredApiLevelError()
|
||||
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
|
||||
return
|
||||
}
|
||||
|
||||
if hasJS, doErr := acc.checkJetStream(); !hasJS {
|
||||
if doErr {
|
||||
resp.Error = NewJSNotEnabledForAccountError()
|
||||
@@ -2309,11 +2315,6 @@ func (s *Server) jsStreamLeaderStepDownRequest(sub *subscription, c *client, _ *
|
||||
name := tokenAt(subject, 6)
|
||||
|
||||
var resp = JSApiStreamLeaderStepDownResponse{ApiResponse: ApiResponse{Type: JSApiStreamLeaderStepDownResponseType}}
|
||||
if errorOnRequiredApiLevel(hdr) {
|
||||
resp.Error = NewJSRequiredApiLevelError()
|
||||
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
|
||||
return
|
||||
}
|
||||
|
||||
// If we are not in clustered mode this is a failed request.
|
||||
if !s.JetStreamIsClustered() {
|
||||
@@ -2345,6 +2346,12 @@ func (s *Server) jsStreamLeaderStepDownRequest(sub *subscription, c *client, _ *
|
||||
return
|
||||
}
|
||||
|
||||
if errorOnRequiredApiLevel(hdr) {
|
||||
resp.Error = NewJSRequiredApiLevelError()
|
||||
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
|
||||
return
|
||||
}
|
||||
|
||||
if hasJS, doErr := acc.checkJetStream(); !hasJS {
|
||||
if doErr {
|
||||
resp.Error = NewJSNotEnabledForAccountError()
|
||||
@@ -2421,11 +2428,6 @@ func (s *Server) jsConsumerLeaderStepDownRequest(sub *subscription, c *client, _
|
||||
}
|
||||
|
||||
var resp = JSApiConsumerLeaderStepDownResponse{ApiResponse: ApiResponse{Type: JSApiConsumerLeaderStepDownResponseType}}
|
||||
if errorOnRequiredApiLevel(hdr) {
|
||||
resp.Error = NewJSRequiredApiLevelError()
|
||||
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
|
||||
return
|
||||
}
|
||||
|
||||
// If we are not in clustered mode this is a failed request.
|
||||
if !s.JetStreamIsClustered() {
|
||||
@@ -2460,6 +2462,13 @@ func (s *Server) jsConsumerLeaderStepDownRequest(sub *subscription, c *client, _
|
||||
} else if sa == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if errorOnRequiredApiLevel(hdr) {
|
||||
resp.Error = NewJSRequiredApiLevelError()
|
||||
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
|
||||
return
|
||||
}
|
||||
|
||||
var ca *consumerAssignment
|
||||
if sa.consumers != nil {
|
||||
ca = sa.consumers[consumer]
|
||||
@@ -2547,11 +2556,6 @@ func (s *Server) jsStreamRemovePeerRequest(sub *subscription, c *client, _ *Acco
|
||||
name := tokenAt(subject, 6)
|
||||
|
||||
var resp = JSApiStreamRemovePeerResponse{ApiResponse: ApiResponse{Type: JSApiStreamRemovePeerResponseType}}
|
||||
if errorOnRequiredApiLevel(hdr) {
|
||||
resp.Error = NewJSRequiredApiLevelError()
|
||||
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
|
||||
return
|
||||
}
|
||||
|
||||
// If we are not in clustered mode this is a failed request.
|
||||
if !s.JetStreamIsClustered() {
|
||||
@@ -2580,6 +2584,12 @@ func (s *Server) jsStreamRemovePeerRequest(sub *subscription, c *client, _ *Acco
|
||||
return
|
||||
}
|
||||
|
||||
if errorOnRequiredApiLevel(hdr) {
|
||||
resp.Error = NewJSRequiredApiLevelError()
|
||||
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
|
||||
return
|
||||
}
|
||||
|
||||
if hasJS, doErr := acc.checkJetStream(); !hasJS {
|
||||
if doErr {
|
||||
resp.Error = NewJSNotEnabledForAccountError()
|
||||
@@ -3072,11 +3082,6 @@ func (s *Server) jsLeaderAccountPurgeRequest(sub *subscription, c *client, _ *Ac
|
||||
accName := tokenAt(subject, 5)
|
||||
|
||||
var resp = JSApiAccountPurgeResponse{ApiResponse: ApiResponse{Type: JSApiAccountPurgeResponseType}}
|
||||
if errorOnRequiredApiLevel(hdr) {
|
||||
resp.Error = NewJSRequiredApiLevelError()
|
||||
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
|
||||
return
|
||||
}
|
||||
|
||||
if !s.JetStreamIsClustered() {
|
||||
var streams []*stream
|
||||
@@ -3117,6 +3122,12 @@ func (s *Server) jsLeaderAccountPurgeRequest(sub *subscription, c *client, _ *Ac
|
||||
return
|
||||
}
|
||||
|
||||
if errorOnRequiredApiLevel(hdr) {
|
||||
resp.Error = NewJSRequiredApiLevelError()
|
||||
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
|
||||
return
|
||||
}
|
||||
|
||||
if js.isMetaRecovering() {
|
||||
// While in recovery mode, the data structures are not fully initialized
|
||||
resp.Error = NewJSClusterNotAvailError()
|
||||
@@ -3339,11 +3350,6 @@ func (s *Server) jsStreamDeleteRequest(sub *subscription, c *client, _ *Account,
|
||||
}
|
||||
|
||||
var resp = JSApiStreamDeleteResponse{ApiResponse: ApiResponse{Type: JSApiStreamDeleteResponseType}}
|
||||
if errorOnRequiredApiLevel(hdr) {
|
||||
resp.Error = NewJSRequiredApiLevelError()
|
||||
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
|
||||
return
|
||||
}
|
||||
|
||||
// Determine if we should proceed here when we are in clustered mode.
|
||||
if s.JetStreamIsClustered() {
|
||||
@@ -3362,6 +3368,12 @@ func (s *Server) jsStreamDeleteRequest(sub *subscription, c *client, _ *Account,
|
||||
}
|
||||
}
|
||||
|
||||
if errorOnRequiredApiLevel(hdr) {
|
||||
resp.Error = NewJSRequiredApiLevelError()
|
||||
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
|
||||
return
|
||||
}
|
||||
|
||||
if hasJS, doErr := acc.checkJetStream(); !hasJS {
|
||||
if doErr {
|
||||
resp.Error = NewJSNotEnabledForAccountError()
|
||||
@@ -3414,11 +3426,6 @@ func (s *Server) jsMsgDeleteRequest(sub *subscription, c *client, _ *Account, su
|
||||
stream := tokenAt(subject, 6)
|
||||
|
||||
var resp = JSApiMsgDeleteResponse{ApiResponse: ApiResponse{Type: JSApiMsgDeleteResponseType}}
|
||||
if errorOnRequiredApiLevel(hdr) {
|
||||
resp.Error = NewJSRequiredApiLevelError()
|
||||
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
|
||||
return
|
||||
}
|
||||
|
||||
// If we are in clustered mode we need to be the stream leader to proceed.
|
||||
if s.JetStreamIsClustered() {
|
||||
@@ -3467,6 +3474,12 @@ func (s *Server) jsMsgDeleteRequest(sub *subscription, c *client, _ *Account, su
|
||||
}
|
||||
}
|
||||
|
||||
if errorOnRequiredApiLevel(hdr) {
|
||||
resp.Error = NewJSRequiredApiLevelError()
|
||||
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
|
||||
return
|
||||
}
|
||||
|
||||
if hasJS, doErr := acc.checkJetStream(); !hasJS {
|
||||
if doErr {
|
||||
resp.Error = NewJSNotEnabledForAccountError()
|
||||
@@ -3538,11 +3551,6 @@ func (s *Server) jsMsgGetRequest(sub *subscription, c *client, _ *Account, subje
|
||||
stream := tokenAt(subject, 6)
|
||||
|
||||
var resp = JSApiMsgGetResponse{ApiResponse: ApiResponse{Type: JSApiMsgGetResponseType}}
|
||||
if errorOnRequiredApiLevel(hdr) {
|
||||
resp.Error = NewJSRequiredApiLevelError()
|
||||
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
|
||||
return
|
||||
}
|
||||
|
||||
// If we are in clustered mode we need to be the stream leader to proceed.
|
||||
if s.JetStreamIsClustered() {
|
||||
@@ -3591,6 +3599,12 @@ func (s *Server) jsMsgGetRequest(sub *subscription, c *client, _ *Account, subje
|
||||
}
|
||||
}
|
||||
|
||||
if errorOnRequiredApiLevel(hdr) {
|
||||
resp.Error = NewJSRequiredApiLevelError()
|
||||
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
|
||||
return
|
||||
}
|
||||
|
||||
if hasJS, doErr := acc.checkJetStream(); !hasJS {
|
||||
if doErr {
|
||||
resp.Error = NewJSNotEnabledForAccountError()
|
||||
@@ -3695,31 +3709,8 @@ func (s *Server) jsConsumerUnpinRequest(sub *subscription, c *client, _ *Account
|
||||
stream := streamNameFromSubject(subject)
|
||||
consumer := consumerNameFromSubject(subject)
|
||||
|
||||
var req JSApiConsumerUnpinRequest
|
||||
var resp = JSApiConsumerUnpinResponse{ApiResponse: ApiResponse{Type: JSApiConsumerUnpinResponseType}}
|
||||
if errorOnRequiredApiLevel(hdr) {
|
||||
resp.Error = NewJSRequiredApiLevelError()
|
||||
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
|
||||
return
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(msg, &req); err != nil {
|
||||
resp.Error = NewJSInvalidJSONError(err)
|
||||
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
|
||||
return
|
||||
}
|
||||
|
||||
if req.Group == _EMPTY_ {
|
||||
resp.Error = NewJSInvalidJSONError(errors.New("consumer group not specified"))
|
||||
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
|
||||
return
|
||||
}
|
||||
|
||||
if !validGroupName.MatchString(req.Group) {
|
||||
resp.Error = NewJSConsumerInvalidGroupNameError()
|
||||
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
|
||||
return
|
||||
}
|
||||
if s.JetStreamIsClustered() {
|
||||
// Check to make sure the stream is assigned.
|
||||
js, cc := s.getJetStreamCluster()
|
||||
@@ -3771,6 +3762,31 @@ func (s *Server) jsConsumerUnpinRequest(sub *subscription, c *client, _ *Account
|
||||
}
|
||||
}
|
||||
|
||||
if errorOnRequiredApiLevel(hdr) {
|
||||
resp.Error = NewJSRequiredApiLevelError()
|
||||
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
|
||||
return
|
||||
}
|
||||
|
||||
var req JSApiConsumerUnpinRequest
|
||||
if err := json.Unmarshal(msg, &req); err != nil {
|
||||
resp.Error = NewJSInvalidJSONError(err)
|
||||
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
|
||||
return
|
||||
}
|
||||
|
||||
if req.Group == _EMPTY_ {
|
||||
resp.Error = NewJSInvalidJSONError(errors.New("consumer group not specified"))
|
||||
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
|
||||
return
|
||||
}
|
||||
|
||||
if !validGroupName.MatchString(req.Group) {
|
||||
resp.Error = NewJSConsumerInvalidGroupNameError()
|
||||
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
|
||||
return
|
||||
}
|
||||
|
||||
if hasJS, doErr := acc.checkJetStream(); !hasJS {
|
||||
if doErr {
|
||||
resp.Error = NewJSNotEnabledForAccountError()
|
||||
@@ -3834,11 +3850,6 @@ func (s *Server) jsStreamPurgeRequest(sub *subscription, c *client, _ *Account,
|
||||
stream := streamNameFromSubject(subject)
|
||||
|
||||
var resp = JSApiStreamPurgeResponse{ApiResponse: ApiResponse{Type: JSApiStreamPurgeResponseType}}
|
||||
if errorOnRequiredApiLevel(hdr) {
|
||||
resp.Error = NewJSRequiredApiLevelError()
|
||||
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
|
||||
return
|
||||
}
|
||||
|
||||
// If we are in clustered mode we need to be the stream leader to proceed.
|
||||
if s.JetStreamIsClustered() {
|
||||
@@ -3890,6 +3901,12 @@ func (s *Server) jsStreamPurgeRequest(sub *subscription, c *client, _ *Account,
|
||||
}
|
||||
}
|
||||
|
||||
if errorOnRequiredApiLevel(hdr) {
|
||||
resp.Error = NewJSRequiredApiLevelError()
|
||||
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
|
||||
return
|
||||
}
|
||||
|
||||
if hasJS, doErr := acc.checkJetStream(); !hasJS {
|
||||
if doErr {
|
||||
resp.Error = NewJSNotEnabledForAccountError()
|
||||
@@ -4507,11 +4524,6 @@ func (s *Server) jsConsumerCreateRequest(sub *subscription, c *client, a *Accoun
|
||||
}
|
||||
|
||||
var resp = JSApiConsumerCreateResponse{ApiResponse: ApiResponse{Type: JSApiConsumerCreateResponseType}}
|
||||
if errorOnRequiredApiLevel(hdr) {
|
||||
resp.Error = NewJSRequiredApiLevelError()
|
||||
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
|
||||
return
|
||||
}
|
||||
|
||||
var req CreateConsumerRequest
|
||||
if err := s.unmarshalRequest(c, acc, subject, msg, &req); err != nil {
|
||||
@@ -4548,6 +4560,20 @@ func (s *Server) jsConsumerCreateRequest(sub *subscription, c *client, a *Accoun
|
||||
}
|
||||
}
|
||||
|
||||
if errorOnRequiredApiLevel(hdr) {
|
||||
resp.Error = NewJSRequiredApiLevelError()
|
||||
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
|
||||
return
|
||||
}
|
||||
|
||||
if hasJS, doErr := acc.checkJetStream(); !hasJS {
|
||||
if doErr {
|
||||
resp.Error = NewJSNotEnabledForAccountError()
|
||||
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
var streamName, consumerName, filteredSubject string
|
||||
var rt ccReqType
|
||||
|
||||
@@ -4580,14 +4606,6 @@ func (s *Server) jsConsumerCreateRequest(sub *subscription, c *client, a *Accoun
|
||||
}
|
||||
}
|
||||
|
||||
if hasJS, doErr := acc.checkJetStream(); !hasJS {
|
||||
if doErr {
|
||||
resp.Error = NewJSNotEnabledForAccountError()
|
||||
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if streamName != req.Stream {
|
||||
resp.Error = NewJSStreamMismatchError()
|
||||
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
|
||||
@@ -4732,11 +4750,6 @@ func (s *Server) jsConsumerNamesRequest(sub *subscription, c *client, _ *Account
|
||||
ApiResponse: ApiResponse{Type: JSApiConsumerNamesResponseType},
|
||||
Consumers: []string{},
|
||||
}
|
||||
if errorOnRequiredApiLevel(hdr) {
|
||||
resp.Error = NewJSRequiredApiLevelError()
|
||||
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
|
||||
return
|
||||
}
|
||||
|
||||
// Determine if we should proceed here when we are in clustered mode.
|
||||
if s.JetStreamIsClustered() {
|
||||
@@ -4755,6 +4768,12 @@ func (s *Server) jsConsumerNamesRequest(sub *subscription, c *client, _ *Account
|
||||
}
|
||||
}
|
||||
|
||||
if errorOnRequiredApiLevel(hdr) {
|
||||
resp.Error = NewJSRequiredApiLevelError()
|
||||
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
|
||||
return
|
||||
}
|
||||
|
||||
if hasJS, doErr := acc.checkJetStream(); !hasJS {
|
||||
if doErr {
|
||||
resp.Error = NewJSNotEnabledForAccountError()
|
||||
@@ -4859,11 +4878,6 @@ func (s *Server) jsConsumerListRequest(sub *subscription, c *client, _ *Account,
|
||||
ApiResponse: ApiResponse{Type: JSApiConsumerListResponseType},
|
||||
Consumers: []*ConsumerInfo{},
|
||||
}
|
||||
if errorOnRequiredApiLevel(hdr) {
|
||||
resp.Error = NewJSRequiredApiLevelError()
|
||||
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
|
||||
return
|
||||
}
|
||||
|
||||
// Determine if we should proceed here when we are in clustered mode.
|
||||
if s.JetStreamIsClustered() {
|
||||
@@ -4883,7 +4897,7 @@ func (s *Server) jsConsumerListRequest(sub *subscription, c *client, _ *Account,
|
||||
}
|
||||
|
||||
if errorOnRequiredApiLevel(hdr) {
|
||||
resp.Error = NewJSClusterNotAvailError()
|
||||
resp.Error = NewJSRequiredApiLevelError()
|
||||
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
|
||||
return
|
||||
}
|
||||
@@ -4973,11 +4987,6 @@ func (s *Server) jsConsumerInfoRequest(sub *subscription, c *client, _ *Account,
|
||||
consumerName := consumerNameFromSubject(subject)
|
||||
|
||||
var resp = JSApiConsumerInfoResponse{ApiResponse: ApiResponse{Type: JSApiConsumerInfoResponseType}}
|
||||
if errorOnRequiredApiLevel(hdr) {
|
||||
resp.Error = NewJSRequiredApiLevelError()
|
||||
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
|
||||
return
|
||||
}
|
||||
|
||||
if !isEmptyRequest(msg) {
|
||||
resp.Error = NewJSNotEmptyRequestError()
|
||||
@@ -5128,6 +5137,12 @@ func (s *Server) jsConsumerInfoRequest(sub *subscription, c *client, _ *Account,
|
||||
}
|
||||
}
|
||||
|
||||
if errorOnRequiredApiLevel(hdr) {
|
||||
resp.Error = NewJSRequiredApiLevelError()
|
||||
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
|
||||
return
|
||||
}
|
||||
|
||||
if !acc.JetStreamEnabled() {
|
||||
resp.Error = NewJSNotEnabledForAccountError()
|
||||
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
|
||||
@@ -5175,11 +5190,6 @@ func (s *Server) jsConsumerDeleteRequest(sub *subscription, c *client, _ *Accoun
|
||||
}
|
||||
|
||||
var resp = JSApiConsumerDeleteResponse{ApiResponse: ApiResponse{Type: JSApiConsumerDeleteResponseType}}
|
||||
if errorOnRequiredApiLevel(hdr) {
|
||||
resp.Error = NewJSRequiredApiLevelError()
|
||||
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
|
||||
return
|
||||
}
|
||||
|
||||
// Determine if we should proceed here when we are in clustered mode.
|
||||
if s.JetStreamIsClustered() {
|
||||
@@ -5198,6 +5208,12 @@ func (s *Server) jsConsumerDeleteRequest(sub *subscription, c *client, _ *Accoun
|
||||
}
|
||||
}
|
||||
|
||||
if errorOnRequiredApiLevel(hdr) {
|
||||
resp.Error = NewJSRequiredApiLevelError()
|
||||
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
|
||||
return
|
||||
}
|
||||
|
||||
if hasJS, doErr := acc.checkJetStream(); !hasJS {
|
||||
if doErr {
|
||||
resp.Error = NewJSNotEnabledForAccountError()
|
||||
@@ -5253,11 +5269,6 @@ func (s *Server) jsConsumerPauseRequest(sub *subscription, c *client, _ *Account
|
||||
|
||||
var req JSApiConsumerPauseRequest
|
||||
var resp = JSApiConsumerPauseResponse{ApiResponse: ApiResponse{Type: JSApiConsumerPauseResponseType}}
|
||||
if errorOnRequiredApiLevel(hdr) {
|
||||
resp.Error = NewJSRequiredApiLevelError()
|
||||
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
|
||||
return
|
||||
}
|
||||
|
||||
if isJSONObjectOrArray(msg) {
|
||||
if err := s.unmarshalRequest(c, acc, subject, msg, &req); err != nil {
|
||||
@@ -5285,6 +5296,12 @@ func (s *Server) jsConsumerPauseRequest(sub *subscription, c *client, _ *Account
|
||||
}
|
||||
}
|
||||
|
||||
if errorOnRequiredApiLevel(hdr) {
|
||||
resp.Error = NewJSRequiredApiLevelError()
|
||||
s.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))
|
||||
return
|
||||
}
|
||||
|
||||
if hasJS, doErr := acc.checkJetStream(); !hasJS {
|
||||
if doErr {
|
||||
resp.Error = NewJSNotEnabledForAccountError()
|
||||
|
||||
+8
-8
@@ -3142,20 +3142,20 @@ func (mset *stream) resetClusteredState(err error) bool {
|
||||
stype, tierName, replicas := mset.cfg.Storage, mset.tier, mset.cfg.Replicas
|
||||
mset.mu.RUnlock()
|
||||
|
||||
// The stream might already be deleted and not assigned to us anymore.
|
||||
// In any case, don't revive the stream if it's already closed.
|
||||
if mset.closed.Load() || (node != nil && node.IsDeleted()) {
|
||||
s.Warnf("Will not reset stream '%s > %s', stream is closed", acc, mset.name())
|
||||
// Explicitly returning true here, we want the outside to break out of the monitoring loop as well.
|
||||
return true
|
||||
}
|
||||
|
||||
assert.Unreachable("Reset clustered state", map[string]any{
|
||||
"stream": name,
|
||||
"account": acc.Name,
|
||||
"err": err,
|
||||
})
|
||||
|
||||
// The stream might already be deleted and not assigned to us anymore.
|
||||
// In any case, don't revive the stream if it's already closed.
|
||||
if mset.closed.Load() {
|
||||
s.Warnf("Will not reset stream '%s > %s', stream is closed", acc, mset.name())
|
||||
// Explicitly returning true here, we want the outside to break out of the monitoring loop as well.
|
||||
return true
|
||||
}
|
||||
|
||||
// Stepdown regardless if we are the leader here.
|
||||
if node != nil {
|
||||
node.StepDown()
|
||||
|
||||
+53
-10
@@ -19,7 +19,6 @@ import (
|
||||
"fmt"
|
||||
"math"
|
||||
"slices"
|
||||
"sort"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@@ -445,7 +444,6 @@ func (ms *memStore) RegisterProcessJetStreamMsg(cb ProcessJetStreamMsgHandler) {
|
||||
|
||||
// GetSeqFromTime looks for the first sequence number that has the message
|
||||
// with >= timestamp.
|
||||
// FIXME(dlc) - inefficient.
|
||||
func (ms *memStore) GetSeqFromTime(t time.Time) uint64 {
|
||||
ts := t.UnixNano()
|
||||
ms.mu.RLock()
|
||||
@@ -469,18 +467,57 @@ func (ms *memStore) GetSeqFromTime(t time.Time) uint64 {
|
||||
|
||||
last := lmsg.ts
|
||||
if ts == last {
|
||||
return ms.state.LastSeq
|
||||
return lmsg.seq
|
||||
}
|
||||
if ts > last {
|
||||
return ms.state.LastSeq + 1
|
||||
}
|
||||
index := sort.Search(len(ms.msgs), func(i int) bool {
|
||||
if msg := ms.msgs[ms.state.FirstSeq+uint64(i)]; msg != nil {
|
||||
return msg.ts >= ts
|
||||
|
||||
var (
|
||||
cts int64
|
||||
cseq uint64
|
||||
off uint64
|
||||
)
|
||||
|
||||
// Using a binary search, but need to be aware of interior deletes.
|
||||
fseq := ms.state.FirstSeq
|
||||
lseq := ms.state.LastSeq
|
||||
seq := lseq + 1
|
||||
loop:
|
||||
for fseq <= lseq {
|
||||
mid := fseq + (lseq-fseq)/2
|
||||
off = 0
|
||||
// Potentially skip over gaps. We keep the original middle but keep track of a
|
||||
// potential delete range with an offset.
|
||||
for {
|
||||
msg := ms.msgs[mid+off]
|
||||
if msg == nil {
|
||||
off++
|
||||
if mid+off <= lseq {
|
||||
continue
|
||||
} else {
|
||||
// Continue search to the left. Purposely ignore the skipped deletes here.
|
||||
lseq = mid - 1
|
||||
continue loop
|
||||
}
|
||||
}
|
||||
cts = msg.ts
|
||||
cseq = msg.seq
|
||||
break
|
||||
}
|
||||
return false
|
||||
})
|
||||
return uint64(index) + ms.state.FirstSeq
|
||||
if cts >= ts {
|
||||
seq = cseq
|
||||
if mid == fseq {
|
||||
break
|
||||
}
|
||||
// Continue search to the left.
|
||||
lseq = mid - 1
|
||||
} else {
|
||||
// Continue search to the right (potentially skipping over interior deletes).
|
||||
fseq = mid + off + 1
|
||||
}
|
||||
}
|
||||
return seq
|
||||
}
|
||||
|
||||
// FilteredState will return the SimpleState associated with the filtered subject and a proposed starting sequence.
|
||||
@@ -906,7 +943,7 @@ func (ms *memStore) NumPendingMulti(sseq uint64, sl *gsl.SimpleSublist, lastPerS
|
||||
var havePartial bool
|
||||
var totalSkipped uint64
|
||||
// We will track start and end sequences as we go.
|
||||
gsl.IntersectStree[SimpleState](ms.fss, sl, func(subj []byte, fss *SimpleState) {
|
||||
stree.IntersectGSL[SimpleState](ms.fss, sl, func(subj []byte, fss *SimpleState) {
|
||||
if fss.firstNeedsUpdate || fss.lastNeedsUpdate {
|
||||
ms.recalculateForSubj(bytesToString(subj), fss)
|
||||
}
|
||||
@@ -1463,6 +1500,12 @@ func (ms *memStore) compact(seq uint64) (uint64, error) {
|
||||
var purged, bytes uint64
|
||||
|
||||
ms.mu.Lock()
|
||||
// Short-circuit if the store was already compacted past this point.
|
||||
if ms.state.FirstSeq > seq {
|
||||
ms.mu.Unlock()
|
||||
return purged, nil
|
||||
}
|
||||
|
||||
cb := ms.scb
|
||||
if seq <= ms.state.LastSeq {
|
||||
fseq := ms.state.FirstSeq
|
||||
|
||||
+59
-25
@@ -1,4 +1,4 @@
|
||||
// Copyright 2013-2025 The NATS Authors
|
||||
// Copyright 2013-2026 The NATS Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
@@ -1279,6 +1279,7 @@ type Varz struct {
|
||||
SlowConsumersStats *SlowConsumersStats `json:"slow_consumer_stats"` // SlowConsumersStats are statistics about all detected Slow Consumer
|
||||
StaleConnectionStats *StaleConnectionStats `json:"stale_connection_stats,omitempty"` // StaleConnectionStats are statistics about all detected Stale Connections
|
||||
Proxies *ProxiesOptsVarz `json:"proxies,omitempty"` // Proxies hold information about network proxy devices
|
||||
TLSCertNotAfter time.Time `json:"tls_cert_not_after,omitzero"` // TLSCertNotAfter is the expiration date of the TLS certificate of this server
|
||||
}
|
||||
|
||||
// JetStreamVarz contains basic runtime information about jetstream
|
||||
@@ -1291,34 +1292,36 @@ type JetStreamVarz struct {
|
||||
|
||||
// ClusterOptsVarz contains monitoring cluster information
|
||||
type ClusterOptsVarz struct {
|
||||
Name string `json:"name,omitempty"` // Name is the configured cluster name
|
||||
Host string `json:"addr,omitempty"` // Host is the host the cluster listens on for connections
|
||||
Port int `json:"cluster_port,omitempty"` // Port is the port the cluster listens on for connections
|
||||
AuthTimeout float64 `json:"auth_timeout,omitempty"` // AuthTimeout is the time cluster connections have to complete authentication
|
||||
URLs []string `json:"urls,omitempty"` // URLs is the list of cluster URLs
|
||||
TLSTimeout float64 `json:"tls_timeout,omitempty"` // TLSTimeout is how long TLS operations have to complete
|
||||
TLSRequired bool `json:"tls_required,omitempty"` // TLSRequired indicates if TLS is required for connections
|
||||
TLSVerify bool `json:"tls_verify,omitempty"` // TLSVerify indicates if full verification of TLS connections is performed
|
||||
PoolSize int `json:"pool_size,omitempty"` // PoolSize is the configured route connection pool size
|
||||
WriteDeadline time.Duration `json:"write_deadline,omitempty"` // WriteDeadline is the maximum time writes to sockets have to complete
|
||||
WriteTimeout string `json:"write_timeout,omitempty"` // WriteTimeout is the closure policy for write deadline errors
|
||||
Name string `json:"name,omitempty"` // Name is the configured cluster name
|
||||
Host string `json:"addr,omitempty"` // Host is the host the cluster listens on for connections
|
||||
Port int `json:"cluster_port,omitempty"` // Port is the port the cluster listens on for connections
|
||||
AuthTimeout float64 `json:"auth_timeout,omitempty"` // AuthTimeout is the time cluster connections have to complete authentication
|
||||
URLs []string `json:"urls,omitempty"` // URLs is the list of cluster URLs
|
||||
TLSTimeout float64 `json:"tls_timeout,omitempty"` // TLSTimeout is how long TLS operations have to complete
|
||||
TLSRequired bool `json:"tls_required,omitempty"` // TLSRequired indicates if TLS is required for connections
|
||||
TLSVerify bool `json:"tls_verify,omitempty"` // TLSVerify indicates if full verification of TLS connections is performed
|
||||
PoolSize int `json:"pool_size,omitempty"` // PoolSize is the configured route connection pool size
|
||||
WriteDeadline time.Duration `json:"write_deadline,omitempty"` // WriteDeadline is the maximum time writes to sockets have to complete
|
||||
WriteTimeout string `json:"write_timeout,omitempty"` // WriteTimeout is the closure policy for write deadline errors
|
||||
TLSCertNotAfter time.Time `json:"tls_cert_not_after,omitzero"` // TLSCertNotAfter is the expiration date of the TLS certificate
|
||||
}
|
||||
|
||||
// GatewayOptsVarz contains monitoring gateway information
|
||||
type GatewayOptsVarz struct {
|
||||
Name string `json:"name,omitempty"` // Name is the configured cluster name
|
||||
Host string `json:"host,omitempty"` // Host is the host the gateway listens on for connections
|
||||
Port int `json:"port,omitempty"` // Port is the post gateway connections listens on
|
||||
AuthTimeout float64 `json:"auth_timeout,omitempty"` // AuthTimeout is the time cluster connections have to complete authentication
|
||||
TLSTimeout float64 `json:"tls_timeout,omitempty"` // TLSTimeout is how long TLS operations have to complete
|
||||
TLSRequired bool `json:"tls_required,omitempty"` // TLSRequired indicates if TLS is required for connections
|
||||
TLSVerify bool `json:"tls_verify,omitempty"` // TLSVerify indicates if full verification of TLS connections is performed
|
||||
Advertise string `json:"advertise,omitempty"` // Advertise is the URL advertised to remote gateway clients
|
||||
ConnectRetries int `json:"connect_retries,omitempty"` // ConnectRetries is how many connection attempts the route will make
|
||||
Gateways []RemoteGatewayOptsVarz `json:"gateways,omitempty"` // Gateways is state of configured gateway remotes
|
||||
RejectUnknown bool `json:"reject_unknown,omitempty"` // RejectUnknown indicates if unknown cluster connections will be rejected
|
||||
WriteDeadline time.Duration `json:"write_deadline,omitempty"` // WriteDeadline is the maximum time writes to sockets have to complete
|
||||
WriteTimeout string `json:"write_timeout,omitempty"` // WriteTimeout is the closure policy for write deadline errors
|
||||
Name string `json:"name,omitempty"` // Name is the configured cluster name
|
||||
Host string `json:"host,omitempty"` // Host is the host the gateway listens on for connections
|
||||
Port int `json:"port,omitempty"` // Port is the post gateway connections listens on
|
||||
AuthTimeout float64 `json:"auth_timeout,omitempty"` // AuthTimeout is the time cluster connections have to complete authentication
|
||||
TLSTimeout float64 `json:"tls_timeout,omitempty"` // TLSTimeout is how long TLS operations have to complete
|
||||
TLSRequired bool `json:"tls_required,omitempty"` // TLSRequired indicates if TLS is required for connections
|
||||
TLSVerify bool `json:"tls_verify,omitempty"` // TLSVerify indicates if full verification of TLS connections is performed
|
||||
Advertise string `json:"advertise,omitempty"` // Advertise is the URL advertised to remote gateway clients
|
||||
ConnectRetries int `json:"connect_retries,omitempty"` // ConnectRetries is how many connection attempts the route will make
|
||||
Gateways []RemoteGatewayOptsVarz `json:"gateways,omitempty"` // Gateways is state of configured gateway remotes
|
||||
RejectUnknown bool `json:"reject_unknown,omitempty"` // RejectUnknown indicates if unknown cluster connections will be rejected
|
||||
WriteDeadline time.Duration `json:"write_deadline,omitempty"` // WriteDeadline is the maximum time writes to sockets have to complete
|
||||
WriteTimeout string `json:"write_timeout,omitempty"` // WriteTimeout is the closure policy for write deadline errors
|
||||
TLSCertNotAfter time.Time `json:"tls_cert_not_after,omitzero"` // TLSCertNotAfter is the expiration date of the TLS certificaet
|
||||
}
|
||||
|
||||
// RemoteGatewayOptsVarz contains monitoring remote gateway information
|
||||
@@ -1340,6 +1343,7 @@ type LeafNodeOptsVarz struct {
|
||||
TLSOCSPPeerVerify bool `json:"tls_ocsp_peer_verify,omitempty"` // TLSOCSPPeerVerify indicates if OCSP verification will be performed
|
||||
WriteDeadline time.Duration `json:"write_deadline,omitempty"` // WriteDeadline is the maximum time writes to sockets have to complete
|
||||
WriteTimeout string `json:"write_timeout,omitempty"` // WriteTimeout is the closure policy for write deadline errors
|
||||
TLSCertNotAfter time.Time `json:"tls_cert_not_after,omitzero"` // TLSCertNotAfter is the expiration date of the TLS certificate
|
||||
}
|
||||
|
||||
// DenyRules Contains lists of subjects not allowed to be imported/exported
|
||||
@@ -1370,6 +1374,7 @@ type MQTTOptsVarz struct {
|
||||
AckWait time.Duration `json:"ack_wait,omitempty"` // AckWait is how long the internal JetStream state store will allow acks to complete
|
||||
MaxAckPending uint16 `json:"max_ack_pending,omitempty"` // MaxAckPending is how many outstanding acks the internal JetStream state store will allow
|
||||
TLSOCSPPeerVerify bool `json:"tls_ocsp_peer_verify,omitempty"` // TLSOCSPPeerVerify indicates if OCSP verification will be done
|
||||
TLSCertNotAfter time.Time `json:"tls_cert_not_after,omitzero"` // TLSCertNotAfter is the expiration date of the TLS certificate
|
||||
}
|
||||
|
||||
// WebsocketOptsVarz contains monitoring websocket information
|
||||
@@ -1388,6 +1393,7 @@ type WebsocketOptsVarz struct {
|
||||
AllowedOrigins []string `json:"allowed_origins,omitempty"` // AllowedOrigins list of configured trusted origins
|
||||
Compression bool `json:"compression,omitempty"` // Compression indicates if compression is supported
|
||||
TLSOCSPPeerVerify bool `json:"tls_ocsp_peer_verify,omitempty"` // TLSOCSPPeerVerify indicates if OCSP verification will be done
|
||||
TLSCertNotAfter time.Time `json:"tls_cert_not_after,omitzero"` // TLSCertNotAfter is the expiration date of the TLS certificate
|
||||
}
|
||||
|
||||
// OCSPResponseCacheVarz contains OCSP response cache information
|
||||
@@ -1454,6 +1460,22 @@ func myUptime(d time.Duration) string {
|
||||
return fmt.Sprintf("%ds", tsecs)
|
||||
}
|
||||
|
||||
func tlsCertNotAfter(config *tls.Config) time.Time {
|
||||
if config == nil || len(config.Certificates) == 0 {
|
||||
return time.Time{}
|
||||
}
|
||||
cert := config.Certificates[0]
|
||||
leaf := cert.Leaf
|
||||
if leaf == nil {
|
||||
var err error
|
||||
leaf, err = x509.ParseCertificate(cert.Certificate[0])
|
||||
if err != nil {
|
||||
return time.Time{}
|
||||
}
|
||||
}
|
||||
return leaf.NotAfter
|
||||
}
|
||||
|
||||
// HandleRoot will show basic info and links to others handlers.
|
||||
func (s *Server) HandleRoot(w http.ResponseWriter, r *http.Request) {
|
||||
// This feels dumb to me, but is required: https://code.google.com/p/go/issues/detail?id=4799
|
||||
@@ -1779,6 +1801,13 @@ func (s *Server) updateVarzConfigReloadableFields(v *Varz) {
|
||||
|
||||
v.TLSOCSPPeerVerify = s.ocspPeerVerify && v.TLSRequired && s.opts.tlsConfigOpts != nil && s.opts.tlsConfigOpts.OCSPPeerConfig != nil && s.opts.tlsConfigOpts.OCSPPeerConfig.Verify
|
||||
|
||||
v.TLSCertNotAfter = tlsCertNotAfter(opts.TLSConfig)
|
||||
v.Cluster.TLSCertNotAfter = tlsCertNotAfter(opts.Cluster.TLSConfig)
|
||||
v.Gateway.TLSCertNotAfter = tlsCertNotAfter(opts.Gateway.TLSConfig)
|
||||
v.LeafNode.TLSCertNotAfter = tlsCertNotAfter(opts.LeafNode.TLSConfig)
|
||||
v.MQTT.TLSCertNotAfter = tlsCertNotAfter(opts.MQTT.TLSConfig)
|
||||
v.Websocket.TLSCertNotAfter = tlsCertNotAfter(opts.Websocket.TLSConfig)
|
||||
|
||||
if opts.Proxies != nil {
|
||||
if v.Proxies == nil {
|
||||
v.Proxies = &ProxiesOptsVarz{}
|
||||
@@ -3982,6 +4011,11 @@ func (s *Server) healthz(opts *HealthzOptions) *HealthStatus {
|
||||
return health
|
||||
}
|
||||
|
||||
// Healthz returns the health status of the server.
|
||||
func (s *Server) Healthz(opts *HealthzOptions) *HealthStatus {
|
||||
return s.healthz(opts)
|
||||
}
|
||||
|
||||
type ExpvarzStatus struct {
|
||||
Memstats json.RawMessage `json:"memstats"`
|
||||
Cmdline json.RawMessage `json:"cmdline"`
|
||||
|
||||
+1
-1
@@ -2326,7 +2326,7 @@ func parseJetStreamForAccount(v any, acc *Account, errors *[]error) error {
|
||||
case "cluster_traffic":
|
||||
vv, ok := mv.(string)
|
||||
if !ok {
|
||||
return &configErr{tk, fmt.Sprintf("Expected either 'system' or 'account' string value for %q, got %v", mk, mv)}
|
||||
return &configErr{tk, fmt.Sprintf("Expected either 'system' or 'owner' string value for %q, got %v", mk, mv)}
|
||||
}
|
||||
switch vv {
|
||||
case "system", _EMPTY_:
|
||||
|
||||
+16
-13
@@ -1,4 +1,4 @@
|
||||
// Copyright 2020-2025 The NATS Authors
|
||||
// Copyright 2020-2026 The NATS Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
@@ -83,6 +83,7 @@ type RaftNode interface {
|
||||
Stop()
|
||||
WaitForStop()
|
||||
Delete()
|
||||
IsDeleted() bool
|
||||
RecreateInternalSubs() error
|
||||
IsSystemAccount() bool
|
||||
GetTrafficAccountName() string
|
||||
@@ -231,6 +232,7 @@ type raft struct {
|
||||
initializing bool // The node is new, and "empty log" checks can be temporarily relaxed.
|
||||
scaleUp bool // The node is part of a scale up, puts us in observer mode until the log contains data.
|
||||
membChanging bool // There is a membership change proposal in progress
|
||||
deleted bool // If the node was deleted.
|
||||
}
|
||||
|
||||
type proposedEntry struct {
|
||||
@@ -1735,11 +1737,6 @@ func (n *raft) StepDown(preferred ...string) error {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clear our vote state.
|
||||
n.vote = noVote
|
||||
n.writeTermVote()
|
||||
|
||||
n.Unlock()
|
||||
|
||||
if len(preferred) > 0 && maybeLeader == noLeader {
|
||||
@@ -1920,6 +1917,7 @@ func (n *raft) Delete() {
|
||||
n.Lock()
|
||||
defer n.Unlock()
|
||||
|
||||
n.deleted = true
|
||||
if wal := n.wal; wal != nil {
|
||||
wal.Delete(false)
|
||||
}
|
||||
@@ -1927,6 +1925,12 @@ func (n *raft) Delete() {
|
||||
n.debug("Deleted")
|
||||
}
|
||||
|
||||
func (n *raft) IsDeleted() bool {
|
||||
n.RLock()
|
||||
defer n.RUnlock()
|
||||
return n.deleted
|
||||
}
|
||||
|
||||
func (n *raft) shutdown() {
|
||||
// First call to Stop or Delete should close the quit chan
|
||||
// to notify the runAs goroutines to stop what they're doing.
|
||||
@@ -3401,9 +3405,9 @@ func (n *raft) runAsCandidate() {
|
||||
n.requestVote()
|
||||
|
||||
// We vote for ourselves.
|
||||
votes := map[string]struct{}{
|
||||
n.ID(): {},
|
||||
}
|
||||
n.votes.push(&voteResponse{term: n.term, peer: n.ID(), granted: true})
|
||||
|
||||
votes := map[string]struct{}{}
|
||||
emptyVotes := map[string]struct{}{}
|
||||
|
||||
for n.State() == Candidate {
|
||||
@@ -3968,10 +3972,6 @@ CONTINUE:
|
||||
// Here we can become a leader but need to wait for resume of the apply queue.
|
||||
n.lxfer = true
|
||||
}
|
||||
} else if n.vote != noVote {
|
||||
// Since we are here we are not the chosen one but we should clear any vote preference.
|
||||
n.vote = noVote
|
||||
n.writeTermVote()
|
||||
}
|
||||
}
|
||||
case EntryAddPeer:
|
||||
@@ -4211,6 +4211,9 @@ func (n *raft) sendAppendEntryLocked(entries []*Entry, checkLeader bool) error {
|
||||
if !shouldStore {
|
||||
ae.returnToPool()
|
||||
}
|
||||
if n.csz == 1 {
|
||||
n.tryCommit(n.pindex)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
+54
-33
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2025 The NATS Authors
|
||||
// Copyright 2019-2026 The NATS Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
@@ -425,6 +425,7 @@ type stream struct {
|
||||
active bool // Indicates that there are active internal subscriptions (for the subject filters)
|
||||
// and/or mirror/sources consumers are scheduled to be established or already started.
|
||||
closed atomic.Bool // Set to true when stop() is called on the stream.
|
||||
cisrun atomic.Bool // Indicates one checkInterestState is already running.
|
||||
|
||||
// Mirror
|
||||
mirror *sourceInfo
|
||||
@@ -837,9 +838,9 @@ func (a *Account) addStreamWithAssignment(config *StreamConfig, fsConfig *FileSt
|
||||
|
||||
// Add created timestamp used for the store, must match that of the stream assignment if it exists.
|
||||
if sa != nil {
|
||||
js.mu.RLock()
|
||||
// The following assignment does not require mutex
|
||||
// protection: sa.Created is immutable.
|
||||
mset.created = sa.Created
|
||||
js.mu.RUnlock()
|
||||
}
|
||||
|
||||
// Start our signaling routine to process consumers.
|
||||
@@ -1821,7 +1822,7 @@ func (s *Server) checkStreamCfg(config *StreamConfig, acc *Account, pedantic boo
|
||||
// check for duplicates
|
||||
var iNames = make(map[string]struct{})
|
||||
for _, src := range cfg.Sources {
|
||||
if !isValidName(src.Name) {
|
||||
if src == nil || !isValidName(src.Name) {
|
||||
return StreamConfig{}, NewJSSourceInvalidStreamNameError()
|
||||
}
|
||||
if _, ok := iNames[src.composeIName()]; !ok {
|
||||
@@ -3162,7 +3163,6 @@ func (mset *stream) setupMirrorConsumer() error {
|
||||
}
|
||||
|
||||
mirror := mset.mirror
|
||||
mirrorWg := &mirror.wg
|
||||
|
||||
// We want to throttle here in terms of how fast we request new consumers,
|
||||
// or if the previous is still in progress.
|
||||
@@ -3321,7 +3321,16 @@ func (mset *stream) setupMirrorConsumer() error {
|
||||
|
||||
// Wait for previous processMirrorMsgs go routine to be completely done.
|
||||
// If none is running, this will not block.
|
||||
mirrorWg.Wait()
|
||||
mset.mu.Lock()
|
||||
if mset.mirror == nil {
|
||||
// Mirror config has been removed.
|
||||
mset.mu.Unlock()
|
||||
return
|
||||
} else {
|
||||
wg := &mset.mirror.wg
|
||||
mset.mu.Unlock()
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
select {
|
||||
case ccr := <-respCh:
|
||||
@@ -6045,13 +6054,6 @@ func (mset *stream) processJetStreamMsg(subject, reply string, hdr, msg []byte,
|
||||
return nil
|
||||
}
|
||||
|
||||
// If here we will attempt to store the message.
|
||||
// Assume this will succeed.
|
||||
olmsgId := mset.lmsgId
|
||||
mset.lmsgId = msgId
|
||||
mset.lseq++
|
||||
tierName := mset.tier
|
||||
|
||||
// Republish state if needed.
|
||||
var tsubj string
|
||||
var tlseq uint64
|
||||
@@ -6075,7 +6077,7 @@ func (mset *stream) processJetStreamMsg(subject, reply string, hdr, msg []byte,
|
||||
// If clustered this was already checked and we do not want to check here and possibly introduce skew.
|
||||
// Don't error and log if we're tracing when clustered.
|
||||
if !isClustered {
|
||||
if exceeded, err := jsa.wouldExceedLimits(stype, tierName, mset.cfg.Replicas, subject, hdr, msg); exceeded {
|
||||
if exceeded, err := jsa.wouldExceedLimits(stype, mset.tier, mset.cfg.Replicas, subject, hdr, msg); exceeded {
|
||||
if err == nil {
|
||||
err = NewJSAccountResourcesExceededError()
|
||||
}
|
||||
@@ -6134,11 +6136,7 @@ func (mset *stream) processJetStreamMsg(subject, reply string, hdr, msg []byte,
|
||||
mset.srv.Warnf("Filesystem permission denied while writing msg, disabling JetStream: %v", err)
|
||||
return err
|
||||
}
|
||||
// If we did not succeed put those values back and increment clfs in case we are clustered.
|
||||
var state StreamState
|
||||
mset.store.FastState(&state)
|
||||
mset.lseq = state.LastSeq
|
||||
mset.lmsgId = olmsgId
|
||||
// If we did not succeed increment clfs in case we are clustered.
|
||||
bumpCLFS()
|
||||
|
||||
switch err {
|
||||
@@ -6159,6 +6157,8 @@ func (mset *stream) processJetStreamMsg(subject, reply string, hdr, msg []byte,
|
||||
}
|
||||
|
||||
// If here we succeeded in storing the message.
|
||||
mset.lmsgId = msgId
|
||||
mset.lseq = seq
|
||||
|
||||
// If we have a msgId make sure to save.
|
||||
// This will replace our estimate from the cluster layer if we are clustered.
|
||||
@@ -7298,11 +7298,30 @@ func (mset *stream) checkInterestState() {
|
||||
return
|
||||
}
|
||||
|
||||
// Ensure only one of these runs at the same time.
|
||||
if !mset.cisrun.CompareAndSwap(false, true) {
|
||||
return
|
||||
}
|
||||
defer mset.cisrun.Store(false)
|
||||
|
||||
var ss StreamState
|
||||
mset.store.FastState(&ss)
|
||||
|
||||
asflr := uint64(math.MaxUint64)
|
||||
for _, o := range mset.getConsumers() {
|
||||
o.checkStateForInterestStream(&ss)
|
||||
o.mu.RLock()
|
||||
chkflr := o.chkflr
|
||||
o.mu.RUnlock()
|
||||
asflr = min(asflr, chkflr)
|
||||
}
|
||||
|
||||
mset.cfgMu.RLock()
|
||||
rp := mset.cfg.Retention
|
||||
mset.cfgMu.RUnlock()
|
||||
// Remove as many messages from the "head" of the stream if there's no interest anymore.
|
||||
if rp == InterestPolicy && asflr != math.MaxUint64 {
|
||||
mset.store.Compact(asflr)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7389,20 +7408,18 @@ func (mset *stream) swapSigSubs(o *consumer, newFilters []string) {
|
||||
o.sigSubs = nil
|
||||
}
|
||||
|
||||
if o.isLeader() {
|
||||
if mset.csl == nil {
|
||||
mset.csl = gsl.NewSublist[*consumer]()
|
||||
}
|
||||
// If no filters are preset, add fwcs to sublist for that consumer.
|
||||
if newFilters == nil {
|
||||
mset.csl.Insert(fwcs, o)
|
||||
o.sigSubs = append(o.sigSubs, fwcs)
|
||||
// If there are filters, add their subjects to sublist.
|
||||
} else {
|
||||
for _, filter := range newFilters {
|
||||
mset.csl.Insert(filter, o)
|
||||
o.sigSubs = append(o.sigSubs, filter)
|
||||
}
|
||||
if mset.csl == nil {
|
||||
mset.csl = gsl.NewSublist[*consumer]()
|
||||
}
|
||||
// If no filters are present, add fwcs to sublist for that consumer.
|
||||
if newFilters == nil {
|
||||
mset.csl.Insert(fwcs, o)
|
||||
o.sigSubs = append(o.sigSubs, fwcs)
|
||||
} else {
|
||||
// If there are filters, add their subjects to sublist.
|
||||
for _, filter := range newFilters {
|
||||
mset.csl.Insert(filter, o)
|
||||
o.sigSubs = append(o.sigSubs, filter)
|
||||
}
|
||||
}
|
||||
o.mu.Unlock()
|
||||
@@ -7479,14 +7496,18 @@ func (mset *stream) partitionUnique(name string, partitions []string) bool {
|
||||
if n == name {
|
||||
continue
|
||||
}
|
||||
o.mu.RLock()
|
||||
if o.subjf == nil {
|
||||
o.mu.RUnlock()
|
||||
return false
|
||||
}
|
||||
for _, filter := range o.subjf {
|
||||
if SubjectsCollide(partition, filter.subject) {
|
||||
o.mu.RUnlock()
|
||||
return false
|
||||
}
|
||||
}
|
||||
o.mu.RUnlock()
|
||||
}
|
||||
}
|
||||
return true
|
||||
|
||||
+60
@@ -16,6 +16,9 @@ package stree
|
||||
import (
|
||||
"bytes"
|
||||
"slices"
|
||||
"unsafe"
|
||||
|
||||
"github.com/nats-io/nats-server/v2/server/gsl"
|
||||
)
|
||||
|
||||
// SubjectTree is an adaptive radix trie (ART) for storing subject information on literal subjects.
|
||||
@@ -448,3 +451,60 @@ func LazyIntersect[TL, TR any](tl *SubjectTree[TL], tr *SubjectTree[TR], cb func
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// IntersectGSL will match all items in the given subject tree that
|
||||
// have interest expressed in the given sublist. The callback will only be called
|
||||
// once for each subject, regardless of overlapping subscriptions in the sublist.
|
||||
func IntersectGSL[T any, SL comparable](t *SubjectTree[T], sl *gsl.GenericSublist[SL], cb func(subject []byte, val *T)) {
|
||||
if t == nil || t.root == nil || sl == nil {
|
||||
return
|
||||
}
|
||||
var _pre [256]byte
|
||||
_intersectGSL(t.root, _pre[:0], sl, cb)
|
||||
}
|
||||
|
||||
func _intersectGSL[T any, SL comparable](n node, pre []byte, sl *gsl.GenericSublist[SL], cb func(subject []byte, val *T)) {
|
||||
if n.isLeaf() {
|
||||
ln := n.(*leaf[T])
|
||||
subj := append(pre, ln.suffix...)
|
||||
if sl.HasInterest(bytesToString(subj)) {
|
||||
cb(subj, &ln.value)
|
||||
}
|
||||
return
|
||||
}
|
||||
bn := n.base()
|
||||
pre = append(pre, bn.prefix...)
|
||||
for _, cn := range n.children() {
|
||||
if cn == nil {
|
||||
continue
|
||||
}
|
||||
subj := append(pre, cn.path()...)
|
||||
if !hasInterestForTokens(sl, subj, len(pre)) {
|
||||
continue
|
||||
}
|
||||
_intersectGSL(cn, pre, sl, cb)
|
||||
}
|
||||
}
|
||||
|
||||
// The subject tree can return partial tokens so we need to check starting interest
|
||||
// only from whole tokens when we encounter a tsep.
|
||||
func hasInterestForTokens[SL comparable](sl *gsl.GenericSublist[SL], subj []byte, since int) bool {
|
||||
for i := since; i < len(subj); i++ {
|
||||
if subj[i] == tsep {
|
||||
if !sl.HasInterestStartingIn(bytesToString(subj[:i])) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Note this will avoid a copy of the data used for the string, but it will also reference the existing slice's data pointer.
|
||||
// So this should be used sparingly when we know the encompassing byte slice's lifetime is the same.
|
||||
func bytesToString(b []byte) string {
|
||||
if len(b) == 0 {
|
||||
return ""
|
||||
}
|
||||
p := unsafe.SliceData(b)
|
||||
return unsafe.String(p, len(b))
|
||||
}
|
||||
|
||||
+3
-63
@@ -21,8 +21,6 @@ import (
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/nats-io/nats-server/v2/server/stree"
|
||||
)
|
||||
|
||||
// Sublist is a routing mechanism to handle subject distribution and
|
||||
@@ -818,7 +816,9 @@ func matchLevelForAny(l *level, toks []string, np, nq *int) bool {
|
||||
*nq += len(qsub)
|
||||
}
|
||||
}
|
||||
return len(n.plist) > 0 || len(n.psubs) > 0 || len(n.qsubs) > 0
|
||||
if len(n.plist) > 0 || len(n.psubs) > 0 || len(n.qsubs) > 0 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
if pwc != nil {
|
||||
if np != nil && nq != nil {
|
||||
@@ -1726,63 +1726,3 @@ func getAllNodes(l *level, results *SublistResult) {
|
||||
getAllNodes(n.next, results)
|
||||
}
|
||||
}
|
||||
|
||||
// IntersectStree will match all items in the given subject tree that
|
||||
// have interest expressed in the given sublist. The callback will only be called
|
||||
// once for each subject, regardless of overlapping subscriptions in the sublist.
|
||||
func IntersectStree[T any](st *stree.SubjectTree[T], sl *Sublist, cb func(subj []byte, entry *T)) {
|
||||
var _subj [255]byte
|
||||
intersectStree(st, sl.root, _subj[:0], cb)
|
||||
}
|
||||
|
||||
func intersectStree[T any](st *stree.SubjectTree[T], r *level, subj []byte, cb func(subj []byte, entry *T)) {
|
||||
nsubj := subj
|
||||
if len(nsubj) > 0 {
|
||||
nsubj = append(subj, '.')
|
||||
}
|
||||
if r.fwc != nil {
|
||||
// We've reached a full wildcard, do a FWC match on the stree at this point
|
||||
// and don't keep iterating downward.
|
||||
nsubj := append(nsubj, '>')
|
||||
st.Match(nsubj, cb)
|
||||
return
|
||||
}
|
||||
if r.pwc != nil {
|
||||
// We've found a partial wildcard. We'll keep iterating downwards, but first
|
||||
// check whether there's interest at this level (without triggering dupes) and
|
||||
// match if so.
|
||||
var done bool
|
||||
nsubj := append(nsubj, '*')
|
||||
if len(r.pwc.psubs)+len(r.pwc.qsubs) > 0 {
|
||||
st.Match(nsubj, cb)
|
||||
done = true
|
||||
}
|
||||
if r.pwc.next.numNodes() > 0 {
|
||||
intersectStree(st, r.pwc.next, nsubj, cb)
|
||||
}
|
||||
if done {
|
||||
return
|
||||
}
|
||||
}
|
||||
// Normal node with subject literals, keep iterating.
|
||||
for t, n := range r.nodes {
|
||||
if r.pwc != nil && r.pwc.next.numNodes() > 0 && n.next.numNodes() > 0 {
|
||||
// A wildcard at the next level will already visit these descendents
|
||||
// so skip so we don't callback the same subject more than once.
|
||||
continue
|
||||
}
|
||||
nsubj := append(nsubj, t...)
|
||||
if len(n.psubs)+len(n.qsubs) > 0 {
|
||||
if subjectHasWildcard(bytesToString(nsubj)) {
|
||||
st.Match(nsubj, cb)
|
||||
} else {
|
||||
if e, ok := st.Find(nsubj); ok {
|
||||
cb(nsubj, e)
|
||||
}
|
||||
}
|
||||
}
|
||||
if n.next.numNodes() > 0 {
|
||||
intersectStree(st, n.next, nsubj, cb)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// Copyright 2012-2024 The NATS Authors
|
||||
// Copyright 2012-2025 The NATS Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
+18
@@ -1,3 +1,21 @@
|
||||
## 2.28.0
|
||||
|
||||
Ginkgo's SemVer filter now supports filtering multiple components by SemVer version:
|
||||
|
||||
```go
|
||||
It("should work in a specific version range (1.0.0, 2.0.0) and third-party dependency redis in [8.0.0, ~)", SemVerConstraint(">= 3.2.0"), ComponentSemVerConstraint("redis", ">= 8.0.0") func() {
|
||||
// This test will only run when version is between 1.0.0 (exclusive) and 2.0.0 (exclusive) and redis version is >= 8.0.0
|
||||
})
|
||||
```
|
||||
|
||||
can be filtered in or out with an invocation like:
|
||||
|
||||
```bash
|
||||
ginkgo --sem-ver-filter="2.1.1, redis=8.2.0"
|
||||
```
|
||||
|
||||
Huge thanks to @Icarus9913 for working on this!
|
||||
|
||||
## 2.27.5
|
||||
|
||||
### Fixes
|
||||
|
||||
+13
-6
@@ -20,6 +20,7 @@ import (
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
@@ -268,7 +269,7 @@ func RunSpecs(t GinkgoTestingT, description string, args ...any) bool {
|
||||
}
|
||||
defer global.PopClone()
|
||||
|
||||
suiteLabels, suiteSemVerConstraints, suiteAroundNodes := extractSuiteConfiguration(args)
|
||||
suiteLabels, suiteSemVerConstraints, suiteComponentSemVerConstraints, suiteAroundNodes := extractSuiteConfiguration(args)
|
||||
|
||||
var reporter reporters.Reporter
|
||||
if suiteConfig.ParallelTotal == 1 {
|
||||
@@ -311,7 +312,7 @@ func RunSpecs(t GinkgoTestingT, description string, args ...any) bool {
|
||||
suitePath, err = filepath.Abs(suitePath)
|
||||
exitIfErr(err)
|
||||
|
||||
passed, hasFocusedTests := global.Suite.Run(description, suiteLabels, suiteSemVerConstraints, suiteAroundNodes, suitePath, global.Failer, reporter, writer, outputInterceptor, interrupt_handler.NewInterruptHandler(client), client, internal.RegisterForProgressSignal, suiteConfig)
|
||||
passed, hasFocusedTests := global.Suite.Run(description, suiteLabels, suiteSemVerConstraints, suiteComponentSemVerConstraints, suiteAroundNodes, suitePath, global.Failer, reporter, writer, outputInterceptor, interrupt_handler.NewInterruptHandler(client), client, internal.RegisterForProgressSignal, suiteConfig)
|
||||
outputInterceptor.Shutdown()
|
||||
|
||||
flagSet.ValidateDeprecations(deprecationTracker)
|
||||
@@ -330,9 +331,10 @@ func RunSpecs(t GinkgoTestingT, description string, args ...any) bool {
|
||||
return passed
|
||||
}
|
||||
|
||||
func extractSuiteConfiguration(args []any) (Labels, SemVerConstraints, types.AroundNodes) {
|
||||
func extractSuiteConfiguration(args []any) (Labels, SemVerConstraints, ComponentSemVerConstraints, types.AroundNodes) {
|
||||
suiteLabels := Labels{}
|
||||
suiteSemVerConstraints := SemVerConstraints{}
|
||||
suiteComponentSemVerConstraints := ComponentSemVerConstraints{}
|
||||
aroundNodes := types.AroundNodes{}
|
||||
configErrors := []error{}
|
||||
for _, arg := range args {
|
||||
@@ -345,6 +347,11 @@ func extractSuiteConfiguration(args []any) (Labels, SemVerConstraints, types.Aro
|
||||
suiteLabels = append(suiteLabels, arg...)
|
||||
case SemVerConstraints:
|
||||
suiteSemVerConstraints = append(suiteSemVerConstraints, arg...)
|
||||
case ComponentSemVerConstraints:
|
||||
for component, constraints := range arg {
|
||||
suiteComponentSemVerConstraints[component] = append(suiteComponentSemVerConstraints[component], constraints...)
|
||||
suiteComponentSemVerConstraints[component] = slices.Compact(suiteComponentSemVerConstraints[component])
|
||||
}
|
||||
case types.AroundNodeDecorator:
|
||||
aroundNodes = append(aroundNodes, arg)
|
||||
default:
|
||||
@@ -362,7 +369,7 @@ func extractSuiteConfiguration(args []any) (Labels, SemVerConstraints, types.Aro
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
return suiteLabels, suiteSemVerConstraints, aroundNodes
|
||||
return suiteLabels, suiteSemVerConstraints, suiteComponentSemVerConstraints, aroundNodes
|
||||
}
|
||||
|
||||
func getwd() (string, error) {
|
||||
@@ -385,7 +392,7 @@ func PreviewSpecs(description string, args ...any) Report {
|
||||
}
|
||||
defer global.PopClone()
|
||||
|
||||
suiteLabels, suiteSemVerConstraints, suiteAroundNodes := extractSuiteConfiguration(args)
|
||||
suiteLabels, suiteSemVerConstraints, suiteComponentSemVerConstraints, suiteAroundNodes := extractSuiteConfiguration(args)
|
||||
priorDryRun, priorParallelTotal, priorParallelProcess := suiteConfig.DryRun, suiteConfig.ParallelTotal, suiteConfig.ParallelProcess
|
||||
suiteConfig.DryRun, suiteConfig.ParallelTotal, suiteConfig.ParallelProcess = true, 1, 1
|
||||
defer func() {
|
||||
@@ -403,7 +410,7 @@ func PreviewSpecs(description string, args ...any) Report {
|
||||
suitePath, err = filepath.Abs(suitePath)
|
||||
exitIfErr(err)
|
||||
|
||||
global.Suite.Run(description, suiteLabels, suiteSemVerConstraints, suiteAroundNodes, suitePath, global.Failer, reporter, writer, outputInterceptor, interrupt_handler.NewInterruptHandler(client), client, internal.RegisterForProgressSignal, suiteConfig)
|
||||
global.Suite.Run(description, suiteLabels, suiteSemVerConstraints, suiteComponentSemVerConstraints, suiteAroundNodes, suitePath, global.Failer, reporter, writer, outputInterceptor, interrupt_handler.NewInterruptHandler(client), client, internal.RegisterForProgressSignal, suiteConfig)
|
||||
|
||||
return global.Suite.GetPreviewReport()
|
||||
}
|
||||
|
||||
+21
@@ -117,6 +117,27 @@ You can learn more here: https://onsi.github.io/ginkgo/#spec-semantic-version-fi
|
||||
*/
|
||||
type SemVerConstraints = internal.SemVerConstraints
|
||||
|
||||
/*
|
||||
ComponentSemVerConstraint decorates specs with ComponentSemVerConstraints. Multiple components semantic version constraints can be passed to ComponentSemVerConstraint and the component can't be empy, also the version strings must follow the semantic version constraint rules.
|
||||
ComponentSemVerConstraints can be applied to container and subject nodes, but not setup nodes. You can provide multiple ComponentSemVerConstraints to a given node and a spec's component semantic version constraints is the union of all component semantic version constraints in its node hierarchy.
|
||||
|
||||
You can learn more here: https://onsi.github.io/ginkgo/#spec-semantic-version-filtering
|
||||
You can learn more about decorators here: https://onsi.github.io/ginkgo/#decorator-reference
|
||||
*/
|
||||
func ComponentSemVerConstraint(component string, semVerConstraints ...string) ComponentSemVerConstraints {
|
||||
componentSemVerConstraints := ComponentSemVerConstraints{
|
||||
component: semVerConstraints,
|
||||
}
|
||||
|
||||
return componentSemVerConstraints
|
||||
}
|
||||
|
||||
/*
|
||||
ComponentSemVerConstraints are the type for spec ComponentSemVerConstraint decorators. Use ComponentSemVerConstraint(...) to construct ComponentSemVerConstraints.
|
||||
You can learn more here: https://onsi.github.io/ginkgo/#spec-semantic-version-filtering
|
||||
*/
|
||||
type ComponentSemVerConstraints = internal.ComponentSemVerConstraints
|
||||
|
||||
/*
|
||||
PollProgressAfter allows you to override the configured value for --poll-progress-after for a particular node.
|
||||
|
||||
|
||||
+1
-1
@@ -33,7 +33,7 @@ func BuildRunCommand() command.Command {
|
||||
Usage: "ginkgo run <FLAGS> <PACKAGES> -- <PASS-THROUGHS>",
|
||||
ShortDoc: "Run the tests in the passed in <PACKAGES> (or the package in the current directory if left blank)",
|
||||
Documentation: "Any arguments after -- will be passed to the test.",
|
||||
DocLink: "running-tests",
|
||||
DocLink: "running-specs",
|
||||
Command: func(args []string, additionalArgs []string) {
|
||||
var errors []error
|
||||
cliConfig, goFlagsConfig, errors = types.VetAndInitializeCLIAndGoConfig(cliConfig, goFlagsConfig)
|
||||
|
||||
+19
-2
@@ -56,7 +56,7 @@ This function sets the `Skip` property on specs by applying Ginkgo's focus polic
|
||||
|
||||
*Note:* specs with pending nodes are Skipped when created by NewSpec.
|
||||
*/
|
||||
func ApplyFocusToSpecs(specs Specs, description string, suiteLabels Labels, suiteSemVerConstraints SemVerConstraints, suiteConfig types.SuiteConfig) (Specs, bool) {
|
||||
func ApplyFocusToSpecs(specs Specs, description string, suiteLabels Labels, suiteSemVerConstraints SemVerConstraints, suiteComponentSemVerConstraints ComponentSemVerConstraints, suiteConfig types.SuiteConfig) (Specs, bool) {
|
||||
focusString := strings.Join(suiteConfig.FocusStrings, "|")
|
||||
skipString := strings.Join(suiteConfig.SkipStrings, "|")
|
||||
|
||||
@@ -87,7 +87,24 @@ func ApplyFocusToSpecs(specs Specs, description string, suiteLabels Labels, suit
|
||||
if suiteConfig.SemVerFilter != "" {
|
||||
semVerFilter, _ := types.ParseSemVerFilter(suiteConfig.SemVerFilter)
|
||||
skipChecks = append(skipChecks, func(spec Spec) bool {
|
||||
return !semVerFilter(UnionOfSemVerConstraints(suiteSemVerConstraints, spec.Nodes.UnionOfSemVerConstraints()))
|
||||
noRun := false
|
||||
|
||||
// non-component-specific constraints
|
||||
constraints := UnionOfSemVerConstraints(suiteSemVerConstraints, spec.Nodes.UnionOfSemVerConstraints())
|
||||
if len(constraints) != 0 && semVerFilter("", constraints) == false {
|
||||
noRun = true
|
||||
}
|
||||
|
||||
// component-specific constraints
|
||||
componentConstraints := UnionOfComponentSemVerConstraints(suiteComponentSemVerConstraints, spec.Nodes.UnionOfComponentSemVerConstraints())
|
||||
for component, constraints := range componentConstraints {
|
||||
if semVerFilter(component, constraints) == false {
|
||||
noRun = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return noRun
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
+19
-16
@@ -113,22 +113,24 @@ func newGroup(suite *Suite) *group {
|
||||
// initialReportForSpec constructs a new SpecReport right before running the spec.
|
||||
func (g *group) initialReportForSpec(spec Spec) types.SpecReport {
|
||||
return types.SpecReport{
|
||||
ContainerHierarchyTexts: spec.Nodes.WithType(types.NodeTypeContainer).Texts(),
|
||||
ContainerHierarchyLocations: spec.Nodes.WithType(types.NodeTypeContainer).CodeLocations(),
|
||||
ContainerHierarchyLabels: spec.Nodes.WithType(types.NodeTypeContainer).Labels(),
|
||||
ContainerHierarchySemVerConstraints: spec.Nodes.WithType(types.NodeTypeContainer).SemVerConstraints(),
|
||||
LeafNodeLocation: spec.FirstNodeWithType(types.NodeTypeIt).CodeLocation,
|
||||
LeafNodeType: types.NodeTypeIt,
|
||||
LeafNodeText: spec.FirstNodeWithType(types.NodeTypeIt).Text,
|
||||
LeafNodeLabels: []string(spec.FirstNodeWithType(types.NodeTypeIt).Labels),
|
||||
LeafNodeSemVerConstraints: []string(spec.FirstNodeWithType(types.NodeTypeIt).SemVerConstraints),
|
||||
ParallelProcess: g.suite.config.ParallelProcess,
|
||||
RunningInParallel: g.suite.isRunningInParallel(),
|
||||
IsSerial: spec.Nodes.HasNodeMarkedSerial(),
|
||||
IsInOrderedContainer: !spec.Nodes.FirstNodeMarkedOrdered().IsZero(),
|
||||
MaxFlakeAttempts: spec.Nodes.GetMaxFlakeAttempts(),
|
||||
MaxMustPassRepeatedly: spec.Nodes.GetMaxMustPassRepeatedly(),
|
||||
SpecPriority: spec.Nodes.GetSpecPriority(),
|
||||
ContainerHierarchyTexts: spec.Nodes.WithType(types.NodeTypeContainer).Texts(),
|
||||
ContainerHierarchyLocations: spec.Nodes.WithType(types.NodeTypeContainer).CodeLocations(),
|
||||
ContainerHierarchyLabels: spec.Nodes.WithType(types.NodeTypeContainer).Labels(),
|
||||
ContainerHierarchySemVerConstraints: spec.Nodes.WithType(types.NodeTypeContainer).SemVerConstraints(),
|
||||
ContainerHierarchyComponentSemVerConstraints: spec.Nodes.WithType(types.NodeTypeContainer).ComponentSemVerConstraints(),
|
||||
LeafNodeLocation: spec.FirstNodeWithType(types.NodeTypeIt).CodeLocation,
|
||||
LeafNodeType: types.NodeTypeIt,
|
||||
LeafNodeText: spec.FirstNodeWithType(types.NodeTypeIt).Text,
|
||||
LeafNodeLabels: []string(spec.FirstNodeWithType(types.NodeTypeIt).Labels),
|
||||
LeafNodeSemVerConstraints: []string(spec.FirstNodeWithType(types.NodeTypeIt).SemVerConstraints),
|
||||
LeafNodeComponentSemVerConstraints: map[string][]string(spec.FirstNodeWithType(types.NodeTypeIt).ComponentSemVerConstraints),
|
||||
ParallelProcess: g.suite.config.ParallelProcess,
|
||||
RunningInParallel: g.suite.isRunningInParallel(),
|
||||
IsSerial: spec.Nodes.HasNodeMarkedSerial(),
|
||||
IsInOrderedContainer: !spec.Nodes.FirstNodeMarkedOrdered().IsZero(),
|
||||
MaxFlakeAttempts: spec.Nodes.GetMaxFlakeAttempts(),
|
||||
MaxMustPassRepeatedly: spec.Nodes.GetMaxMustPassRepeatedly(),
|
||||
SpecPriority: spec.Nodes.GetSpecPriority(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,6 +154,7 @@ func addNodeToReportForNode(report *types.ConstructionNodeReport, node *TreeNode
|
||||
report.ContainerHierarchyLocations = append(report.ContainerHierarchyLocations, node.Node.CodeLocation)
|
||||
report.ContainerHierarchyLabels = append(report.ContainerHierarchyLabels, node.Node.Labels)
|
||||
report.ContainerHierarchySemVerConstraints = append(report.ContainerHierarchySemVerConstraints, node.Node.SemVerConstraints)
|
||||
report.ContainerHierarchyComponentSemVerConstraints = append(report.ContainerHierarchyComponentSemVerConstraints, node.Node.ComponentSemVerConstraints)
|
||||
if node.Node.MarkedSerial {
|
||||
report.IsSerial = true
|
||||
}
|
||||
|
||||
+100
-11
@@ -57,6 +57,7 @@ type Node struct {
|
||||
MustPassRepeatedly int
|
||||
Labels Labels
|
||||
SemVerConstraints SemVerConstraints
|
||||
ComponentSemVerConstraints ComponentSemVerConstraints
|
||||
PollProgressAfter time.Duration
|
||||
PollProgressInterval time.Duration
|
||||
NodeTimeout time.Duration
|
||||
@@ -106,7 +107,24 @@ func (l Labels) MatchesLabelFilter(query string) bool {
|
||||
type SemVerConstraints []string
|
||||
|
||||
func (svc SemVerConstraints) MatchesSemVerFilter(version string) bool {
|
||||
return types.MustParseSemVerFilter(version)(svc)
|
||||
return types.MustParseSemVerFilter(version)("", svc)
|
||||
}
|
||||
|
||||
type ComponentSemVerConstraints map[string][]string
|
||||
|
||||
func (csvc ComponentSemVerConstraints) MatchesSemVerFilter(component, version string) bool {
|
||||
for comp, constraints := range csvc {
|
||||
if comp != component {
|
||||
continue
|
||||
}
|
||||
|
||||
input := version
|
||||
if len(component) > 0 {
|
||||
input = fmt.Sprintf("%s=%s", component, version)
|
||||
}
|
||||
return types.MustParseSemVerFilter(input)(component, constraints)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func unionOf[S ~[]E, E comparable](slices ...S) S {
|
||||
@@ -131,6 +149,16 @@ func UnionOfSemVerConstraints(semVerConstraints ...SemVerConstraints) SemVerCons
|
||||
return unionOf(semVerConstraints...)
|
||||
}
|
||||
|
||||
func UnionOfComponentSemVerConstraints(componentSemVerConstraintsSlice ...ComponentSemVerConstraints) ComponentSemVerConstraints {
|
||||
unionComponentSemVerConstraints := ComponentSemVerConstraints{}
|
||||
for _, componentSemVerConstraints := range componentSemVerConstraintsSlice {
|
||||
for component, constraints := range componentSemVerConstraints {
|
||||
unionComponentSemVerConstraints[component] = unionOf(unionComponentSemVerConstraints[component], constraints)
|
||||
}
|
||||
}
|
||||
return unionComponentSemVerConstraints
|
||||
}
|
||||
|
||||
func PartitionDecorations(args ...any) ([]any, []any) {
|
||||
decorations := []any{}
|
||||
remainingArgs := []any{}
|
||||
@@ -174,6 +202,8 @@ func isDecoration(arg any) bool {
|
||||
return true
|
||||
case t == reflect.TypeOf(SemVerConstraints{}):
|
||||
return true
|
||||
case t == reflect.TypeOf(ComponentSemVerConstraints{}):
|
||||
return true
|
||||
case t == reflect.TypeOf(PollProgressInterval(0)):
|
||||
return true
|
||||
case t == reflect.TypeOf(PollProgressAfter(0)):
|
||||
@@ -214,16 +244,17 @@ var specContextType = reflect.TypeOf(new(SpecContext)).Elem()
|
||||
func NewNode(deprecationTracker *types.DeprecationTracker, nodeType types.NodeType, text string, args ...any) (Node, []error) {
|
||||
baseOffset := 2
|
||||
node := Node{
|
||||
ID: UniqueNodeID(),
|
||||
NodeType: nodeType,
|
||||
Text: text,
|
||||
Labels: Labels{},
|
||||
SemVerConstraints: SemVerConstraints{},
|
||||
CodeLocation: types.NewCodeLocation(baseOffset),
|
||||
NestingLevel: -1,
|
||||
PollProgressAfter: -1,
|
||||
PollProgressInterval: -1,
|
||||
GracePeriod: -1,
|
||||
ID: UniqueNodeID(),
|
||||
NodeType: nodeType,
|
||||
Text: text,
|
||||
Labels: Labels{},
|
||||
SemVerConstraints: SemVerConstraints{},
|
||||
ComponentSemVerConstraints: ComponentSemVerConstraints{},
|
||||
CodeLocation: types.NewCodeLocation(baseOffset),
|
||||
NestingLevel: -1,
|
||||
PollProgressAfter: -1,
|
||||
PollProgressInterval: -1,
|
||||
GracePeriod: -1,
|
||||
}
|
||||
|
||||
errors := []error{}
|
||||
@@ -360,6 +391,36 @@ func NewNode(deprecationTracker *types.DeprecationTracker, nodeType types.NodeTy
|
||||
appendError(err)
|
||||
}
|
||||
}
|
||||
case t == reflect.TypeOf(ComponentSemVerConstraints{}):
|
||||
if !nodeType.Is(types.NodeTypesForContainerAndIt) {
|
||||
appendError(types.GinkgoErrors.InvalidDecoratorForNodeType(node.CodeLocation, nodeType, "ComponentSemVerConstraint"))
|
||||
}
|
||||
for component, semVerConstraints := range arg.(ComponentSemVerConstraints) {
|
||||
// while using ComponentSemVerConstraints, we should not allow empty component names.
|
||||
// you should use SemVerConstraints for that.
|
||||
hasErr := false
|
||||
if len(component) == 0 {
|
||||
appendError(types.GinkgoErrors.InvalidEmptyComponentForSemVerConstraint(node.CodeLocation))
|
||||
hasErr = true
|
||||
}
|
||||
for _, semVerConstraint := range semVerConstraints {
|
||||
_, err := types.ValidateAndCleanupSemVerConstraint(semVerConstraint, node.CodeLocation)
|
||||
if err != nil {
|
||||
appendError(err)
|
||||
hasErr = true
|
||||
}
|
||||
}
|
||||
|
||||
if !hasErr {
|
||||
// merge constraints if the component already exists
|
||||
constraints := slices.Clone(semVerConstraints)
|
||||
if existingConstraints, exists := node.ComponentSemVerConstraints[component]; exists {
|
||||
constraints = UnionOfSemVerConstraints([]string(existingConstraints), constraints)
|
||||
}
|
||||
|
||||
node.ComponentSemVerConstraints[component] = slices.Clone(constraints)
|
||||
}
|
||||
}
|
||||
case t.Kind() == reflect.Func:
|
||||
if nodeType.Is(types.NodeTypeContainer) {
|
||||
if node.Body != nil {
|
||||
@@ -899,6 +960,34 @@ func (n Nodes) UnionOfSemVerConstraints() []string {
|
||||
return out
|
||||
}
|
||||
|
||||
func (n Nodes) ComponentSemVerConstraints() []map[string][]string {
|
||||
out := make([]map[string][]string, len(n))
|
||||
for i := range n {
|
||||
if n[i].ComponentSemVerConstraints == nil {
|
||||
out[i] = map[string][]string{}
|
||||
} else {
|
||||
out[i] = map[string][]string(n[i].ComponentSemVerConstraints)
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func (n Nodes) UnionOfComponentSemVerConstraints() map[string][]string {
|
||||
out := map[string][]string{}
|
||||
seen := map[string]bool{}
|
||||
for i := range n {
|
||||
for component := range n[i].ComponentSemVerConstraints {
|
||||
if !seen[component] {
|
||||
seen[component] = true
|
||||
out[component] = n[i].ComponentSemVerConstraints[component]
|
||||
} else {
|
||||
out[component] = UnionOfSemVerConstraints(out[component], n[i].ComponentSemVerConstraints[component])
|
||||
}
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func (n Nodes) CodeLocations() []types.CodeLocation {
|
||||
out := make([]types.CodeLocation, len(n))
|
||||
for i := range n {
|
||||
|
||||
+30
-17
@@ -83,7 +83,7 @@ func goJSONActionFromSpecState(state types.SpecState) GoJSONAction {
|
||||
type gojsonReport struct {
|
||||
o types.Report
|
||||
// Extra calculated fields
|
||||
goPkg string
|
||||
goPkg string
|
||||
elapsed float64
|
||||
}
|
||||
|
||||
@@ -109,8 +109,8 @@ type gojsonSpecReport struct {
|
||||
o types.SpecReport
|
||||
// extra calculated fields
|
||||
testName string
|
||||
elapsed float64
|
||||
action GoJSONAction
|
||||
elapsed float64
|
||||
action GoJSONAction
|
||||
}
|
||||
|
||||
func newSpecReport(in types.SpecReport) *gojsonSpecReport {
|
||||
@@ -141,18 +141,31 @@ func suitePathToPkg(dir string) (string, error) {
|
||||
}
|
||||
|
||||
func createTestName(spec types.SpecReport) string {
|
||||
name := fmt.Sprintf("[%s]", spec.LeafNodeType)
|
||||
if spec.FullText() != "" {
|
||||
name = name + " " + spec.FullText()
|
||||
}
|
||||
labels := spec.Labels()
|
||||
if len(labels) > 0 {
|
||||
name = name + " [" + strings.Join(labels, ", ") + "]"
|
||||
}
|
||||
semVerConstraints := spec.SemVerConstraints()
|
||||
if len(semVerConstraints) > 0 {
|
||||
name = name + " [" + strings.Join(semVerConstraints, ", ") + "]"
|
||||
}
|
||||
name = strings.TrimSpace(name)
|
||||
return name
|
||||
name := fmt.Sprintf("[%s]", spec.LeafNodeType)
|
||||
if spec.FullText() != "" {
|
||||
name = name + " " + spec.FullText()
|
||||
}
|
||||
labels := spec.Labels()
|
||||
if len(labels) > 0 {
|
||||
name = name + " [" + strings.Join(labels, ", ") + "]"
|
||||
}
|
||||
semVerConstraints := spec.SemVerConstraints()
|
||||
if len(semVerConstraints) > 0 {
|
||||
name = name + " [" + strings.Join(semVerConstraints, ", ") + "]"
|
||||
}
|
||||
componentSemVerConstraints := spec.ComponentSemVerConstraints()
|
||||
if len(componentSemVerConstraints) > 0 {
|
||||
name = name + " [" + formatComponentSemVerConstraintsToString(componentSemVerConstraints) + "]"
|
||||
}
|
||||
name = strings.TrimSpace(name)
|
||||
return name
|
||||
}
|
||||
|
||||
func formatComponentSemVerConstraintsToString(componentSemVerConstraints map[string][]string) string {
|
||||
var tmpStr string
|
||||
for component, semVerConstraints := range componentSemVerConstraints {
|
||||
tmpStr = tmpStr + fmt.Sprintf("%s: %s, ", component, semVerConstraints)
|
||||
}
|
||||
tmpStr = strings.TrimSuffix(tmpStr, ", ")
|
||||
return tmpStr
|
||||
}
|
||||
|
||||
+11
-10
@@ -108,13 +108,13 @@ func (suite *Suite) BuildTree() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (suite *Suite) Run(description string, suiteLabels Labels, suiteSemVerConstraints SemVerConstraints, suiteAroundNodes types.AroundNodes, suitePath string, failer *Failer, reporter reporters.Reporter, writer WriterInterface, outputInterceptor OutputInterceptor, interruptHandler interrupt_handler.InterruptHandlerInterface, client parallel_support.Client, progressSignalRegistrar ProgressSignalRegistrar, suiteConfig types.SuiteConfig) (bool, bool) {
|
||||
func (suite *Suite) Run(description string, suiteLabels Labels, suiteSemVerConstraints SemVerConstraints, suiteComponentSemVerConstraints ComponentSemVerConstraints, suiteAroundNodes types.AroundNodes, suitePath string, failer *Failer, reporter reporters.Reporter, writer WriterInterface, outputInterceptor OutputInterceptor, interruptHandler interrupt_handler.InterruptHandlerInterface, client parallel_support.Client, progressSignalRegistrar ProgressSignalRegistrar, suiteConfig types.SuiteConfig) (bool, bool) {
|
||||
if suite.phase != PhaseBuildTree {
|
||||
panic("cannot run before building the tree = call suite.BuildTree() first")
|
||||
}
|
||||
ApplyNestedFocusPolicyToTree(suite.tree)
|
||||
specs := GenerateSpecsFromTreeRoot(suite.tree)
|
||||
specs, hasProgrammaticFocus := ApplyFocusToSpecs(specs, description, suiteLabels, suiteSemVerConstraints, suiteConfig)
|
||||
specs, hasProgrammaticFocus := ApplyFocusToSpecs(specs, description, suiteLabels, suiteSemVerConstraints, suiteComponentSemVerConstraints, suiteConfig)
|
||||
specs = ComputeAroundNodes(specs)
|
||||
|
||||
suite.phase = PhaseRun
|
||||
@@ -133,7 +133,7 @@ func (suite *Suite) Run(description string, suiteLabels Labels, suiteSemVerConst
|
||||
|
||||
cancelProgressHandler := progressSignalRegistrar(suite.handleProgressSignal)
|
||||
|
||||
success := suite.runSpecs(description, suiteLabels, suiteSemVerConstraints, suitePath, hasProgrammaticFocus, specs)
|
||||
success := suite.runSpecs(description, suiteLabels, suiteSemVerConstraints, suiteComponentSemVerConstraints, suitePath, hasProgrammaticFocus, specs)
|
||||
|
||||
cancelProgressHandler()
|
||||
|
||||
@@ -456,16 +456,17 @@ func (suite *Suite) processCurrentSpecReport() {
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *Suite) runSpecs(description string, suiteLabels Labels, suiteSemVerConstraints SemVerConstraints, suitePath string, hasProgrammaticFocus bool, specs Specs) bool {
|
||||
func (suite *Suite) runSpecs(description string, suiteLabels Labels, suiteSemVerConstraints SemVerConstraints, suiteComponentSemVerConstraints ComponentSemVerConstraints, suitePath string, hasProgrammaticFocus bool, specs Specs) bool {
|
||||
numSpecsThatWillBeRun := specs.CountWithoutSkip()
|
||||
|
||||
suite.report = types.Report{
|
||||
SuitePath: suitePath,
|
||||
SuiteDescription: description,
|
||||
SuiteLabels: suiteLabels,
|
||||
SuiteSemVerConstraints: suiteSemVerConstraints,
|
||||
SuiteConfig: suite.config,
|
||||
SuiteHasProgrammaticFocus: hasProgrammaticFocus,
|
||||
SuitePath: suitePath,
|
||||
SuiteDescription: description,
|
||||
SuiteLabels: suiteLabels,
|
||||
SuiteSemVerConstraints: suiteSemVerConstraints,
|
||||
SuiteComponentSemVerConstraints: suiteComponentSemVerConstraints,
|
||||
SuiteConfig: suite.config,
|
||||
SuiteHasProgrammaticFocus: hasProgrammaticFocus,
|
||||
PreRunStats: types.PreRunStats{
|
||||
TotalSpecs: len(specs),
|
||||
SpecsThatWillRun: numSpecsThatWillBeRun,
|
||||
|
||||
+25
-2
@@ -75,6 +75,9 @@ func (r *DefaultReporter) SuiteWillBegin(report types.Report) {
|
||||
if len(report.SuiteSemVerConstraints) > 0 {
|
||||
r.emit(r.f("{{coral}}[%s]{{/}} ", strings.Join(report.SuiteSemVerConstraints, ", ")))
|
||||
}
|
||||
if len(report.SuiteComponentSemVerConstraints) > 0 {
|
||||
r.emit(r.f("{{coral}}[Components: %s]{{/}} ", formatComponentSemVerConstraintsToString(report.SuiteComponentSemVerConstraints)))
|
||||
}
|
||||
r.emit(r.f("- %d/%d specs ", report.PreRunStats.SpecsThatWillRun, report.PreRunStats.TotalSpecs))
|
||||
if report.SuiteConfig.ParallelTotal > 1 {
|
||||
r.emit(r.f("- %d procs ", report.SuiteConfig.ParallelTotal))
|
||||
@@ -97,6 +100,13 @@ func (r *DefaultReporter) SuiteWillBegin(report types.Report) {
|
||||
bannerWidth = len(semVerConstraints) + 2
|
||||
}
|
||||
}
|
||||
if len(report.SuiteComponentSemVerConstraints) > 0 {
|
||||
componentSemVerConstraints := formatComponentSemVerConstraintsToString(report.SuiteComponentSemVerConstraints)
|
||||
r.emitBlock(r.f("{{coral}}[Components: %s]{{/}} ", componentSemVerConstraints))
|
||||
if len(componentSemVerConstraints)+2 > bannerWidth {
|
||||
bannerWidth = len(componentSemVerConstraints) + 2
|
||||
}
|
||||
}
|
||||
r.emitBlock(strings.Repeat("=", bannerWidth))
|
||||
|
||||
out := r.f("Random Seed: {{bold}}%d{{/}}", report.SuiteConfig.RandomSeed)
|
||||
@@ -725,8 +735,12 @@ func (r *DefaultReporter) cycleJoin(elements []string, joiner string) string {
|
||||
}
|
||||
|
||||
func (r *DefaultReporter) codeLocationBlock(report types.SpecReport, highlightColor string, veryVerbose bool, usePreciseFailureLocation bool) string {
|
||||
texts, locations, labels, semVerConstraints := []string{}, []types.CodeLocation{}, [][]string{}, [][]string{}
|
||||
texts, locations, labels, semVerConstraints = append(texts, report.ContainerHierarchyTexts...), append(locations, report.ContainerHierarchyLocations...), append(labels, report.ContainerHierarchyLabels...), append(semVerConstraints, report.ContainerHierarchySemVerConstraints...)
|
||||
texts, locations, labels, semVerConstraints, componentSemVerConstraints := []string{}, []types.CodeLocation{}, [][]string{}, [][]string{}, []map[string][]string{}
|
||||
texts = append(texts, report.ContainerHierarchyTexts...)
|
||||
locations = append(locations, report.ContainerHierarchyLocations...)
|
||||
labels = append(labels, report.ContainerHierarchyLabels...)
|
||||
semVerConstraints = append(semVerConstraints, report.ContainerHierarchySemVerConstraints...)
|
||||
componentSemVerConstraints = append(componentSemVerConstraints, report.ContainerHierarchyComponentSemVerConstraints...)
|
||||
|
||||
if report.LeafNodeType.Is(types.NodeTypesForSuiteLevelNodes) {
|
||||
texts = append(texts, r.f("[%s] %s", report.LeafNodeType, report.LeafNodeText))
|
||||
@@ -735,6 +749,7 @@ func (r *DefaultReporter) codeLocationBlock(report types.SpecReport, highlightCo
|
||||
}
|
||||
labels = append(labels, report.LeafNodeLabels)
|
||||
semVerConstraints = append(semVerConstraints, report.LeafNodeSemVerConstraints)
|
||||
componentSemVerConstraints = append(componentSemVerConstraints, report.LeafNodeComponentSemVerConstraints)
|
||||
locations = append(locations, report.LeafNodeLocation)
|
||||
|
||||
failureLocation := report.Failure.FailureNodeLocation
|
||||
@@ -749,6 +764,7 @@ func (r *DefaultReporter) codeLocationBlock(report types.SpecReport, highlightCo
|
||||
locations = append([]types.CodeLocation{failureLocation}, locations...)
|
||||
labels = append([][]string{{}}, labels...)
|
||||
semVerConstraints = append([][]string{{}}, semVerConstraints...)
|
||||
componentSemVerConstraints = append([]map[string][]string{{}}, componentSemVerConstraints...)
|
||||
highlightIndex = 0
|
||||
case types.FailureNodeInContainer:
|
||||
i := report.Failure.FailureNodeContainerIndex
|
||||
@@ -779,6 +795,9 @@ func (r *DefaultReporter) codeLocationBlock(report types.SpecReport, highlightCo
|
||||
if len(semVerConstraints[i]) > 0 {
|
||||
out += r.f(" {{coral}}[%s]{{/}}", strings.Join(semVerConstraints[i], ", "))
|
||||
}
|
||||
if len(componentSemVerConstraints[i]) > 0 {
|
||||
out += r.f(" {{coral}}[%s]{{/}}", formatComponentSemVerConstraintsToString(componentSemVerConstraints[i]))
|
||||
}
|
||||
out += "\n"
|
||||
out += r.fi(uint(i), "{{gray}}%s{{/}}\n", locations[i])
|
||||
}
|
||||
@@ -806,6 +825,10 @@ func (r *DefaultReporter) codeLocationBlock(report types.SpecReport, highlightCo
|
||||
if len(flattenedSemVerConstraints) > 0 {
|
||||
out += r.f(" {{coral}}[%s]{{/}}", strings.Join(flattenedSemVerConstraints, ", "))
|
||||
}
|
||||
flattenedComponentSemVerConstraints := report.ComponentSemVerConstraints()
|
||||
if len(flattenedComponentSemVerConstraints) > 0 {
|
||||
out += r.f(" {{coral}}[%s]{{/}}", formatComponentSemVerConstraintsToString(flattenedComponentSemVerConstraints))
|
||||
}
|
||||
out += "\n"
|
||||
if usePreciseFailureLocation {
|
||||
out += r.f("{{gray}}%s{{/}}", failureLocation)
|
||||
|
||||
+20
@@ -13,9 +13,11 @@ package reporters
|
||||
import (
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"maps"
|
||||
"os"
|
||||
"path"
|
||||
"regexp"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/onsi/ginkgo/v2/config"
|
||||
@@ -39,6 +41,9 @@ type JunitReportConfig struct {
|
||||
// Enable OmitSpecSemVerConstraints to prevent semantic version constraints from appearing in the spec name
|
||||
OmitSpecSemVerConstraints bool
|
||||
|
||||
// Enable OmitSpecComponentSemVerConstraints to prevent component semantic version constraints from appearing in the spec name
|
||||
OmitSpecComponentSemVerConstraints bool
|
||||
|
||||
// Enable OmitLeafNodeType to prevent the spec leaf node type from appearing in the spec name
|
||||
OmitLeafNodeType bool
|
||||
|
||||
@@ -173,6 +178,7 @@ func GenerateJUnitReportWithConfig(report types.Report, dst string, config Junit
|
||||
{"SpecialSuiteFailureReason", strings.Join(report.SpecialSuiteFailureReasons, ",")},
|
||||
{"SuiteLabels", fmt.Sprintf("[%s]", strings.Join(report.SuiteLabels, ","))},
|
||||
{"SuiteSemVerConstraints", fmt.Sprintf("[%s]", strings.Join(report.SuiteSemVerConstraints, ","))},
|
||||
{"SuiteComponentSemVerConstraints", fmt.Sprintf("[%s]", formatComponentSemVerConstraintsToString(report.SuiteComponentSemVerConstraints))},
|
||||
{"RandomSeed", fmt.Sprintf("%d", report.SuiteConfig.RandomSeed)},
|
||||
{"RandomizeAllSpecs", fmt.Sprintf("%t", report.SuiteConfig.RandomizeAllSpecs)},
|
||||
{"LabelFilter", report.SuiteConfig.LabelFilter},
|
||||
@@ -216,6 +222,10 @@ func GenerateJUnitReportWithConfig(report types.Report, dst string, config Junit
|
||||
if len(semVerConstraints) > 0 && !config.OmitSpecSemVerConstraints {
|
||||
name = name + " [" + strings.Join(semVerConstraints, ", ") + "]"
|
||||
}
|
||||
componentSemVerConstraints := spec.ComponentSemVerConstraints()
|
||||
if len(componentSemVerConstraints) > 0 && !config.OmitSpecComponentSemVerConstraints {
|
||||
name = name + " [" + formatComponentSemVerConstraintsToString(componentSemVerConstraints) + "]"
|
||||
}
|
||||
name = strings.TrimSpace(name)
|
||||
|
||||
test := JUnitTestCase{
|
||||
@@ -387,6 +397,16 @@ func systemOutForUnstructuredReporters(spec types.SpecReport) string {
|
||||
return spec.CapturedStdOutErr
|
||||
}
|
||||
|
||||
func formatComponentSemVerConstraintsToString(componentSemVerConstraints map[string][]string) string {
|
||||
var tmpStr string
|
||||
for _, key := range slices.Sorted(maps.Keys(componentSemVerConstraints)) {
|
||||
tmpStr = tmpStr + fmt.Sprintf("%s: %s, ", key, componentSemVerConstraints[key])
|
||||
}
|
||||
|
||||
tmpStr = strings.TrimSuffix(tmpStr, ", ")
|
||||
return tmpStr
|
||||
}
|
||||
|
||||
// Deprecated JUnitReporter (so folks can still compile their suites)
|
||||
type JUnitReporter struct{}
|
||||
|
||||
|
||||
+8
@@ -39,12 +39,16 @@ func GenerateTeamcityReport(report types.Report, dst string) error {
|
||||
name := report.SuiteDescription
|
||||
labels := report.SuiteLabels
|
||||
semVerConstraints := report.SuiteSemVerConstraints
|
||||
componentSemVerConstraints := report.SuiteComponentSemVerConstraints
|
||||
if len(labels) > 0 {
|
||||
name = name + " [" + strings.Join(labels, ", ") + "]"
|
||||
}
|
||||
if len(semVerConstraints) > 0 {
|
||||
name = name + " [" + strings.Join(semVerConstraints, ", ") + "]"
|
||||
}
|
||||
if len(componentSemVerConstraints) > 0 {
|
||||
name = name + " [" + formatComponentSemVerConstraintsToString(componentSemVerConstraints) + "]"
|
||||
}
|
||||
fmt.Fprintf(f, "##teamcity[testSuiteStarted name='%s']\n", tcEscape(name))
|
||||
for _, spec := range report.SpecReports {
|
||||
name := fmt.Sprintf("[%s]", spec.LeafNodeType)
|
||||
@@ -59,6 +63,10 @@ func GenerateTeamcityReport(report types.Report, dst string) error {
|
||||
if len(semVerConstraints) > 0 {
|
||||
name = name + " [" + strings.Join(semVerConstraints, ", ") + "]"
|
||||
}
|
||||
componentSemVerConstraints := spec.ComponentSemVerConstraints()
|
||||
if len(componentSemVerConstraints) > 0 {
|
||||
name = name + " [" + formatComponentSemVerConstraintsToString(componentSemVerConstraints) + "]"
|
||||
}
|
||||
|
||||
name = tcEscape(name)
|
||||
fmt.Fprintf(f, "##teamcity[testStarted name='%s']\n", name)
|
||||
|
||||
+9
@@ -450,6 +450,15 @@ func (g ginkgoErrors) InvalidEmptySemVerConstraint(cl CodeLocation) error {
|
||||
}
|
||||
}
|
||||
|
||||
func (g ginkgoErrors) InvalidEmptyComponentForSemVerConstraint(cl CodeLocation) error {
|
||||
return GinkgoError{
|
||||
Heading: "Invalid Empty Component for ComponentSemVerConstraint",
|
||||
Message: "ComponentSemVerConstraint requires a non-empty component name",
|
||||
CodeLocation: cl,
|
||||
DocLink: "spec-semantic-version-filtering",
|
||||
}
|
||||
}
|
||||
|
||||
/* Table errors */
|
||||
func (g ginkgoErrors) MultipleEntryBodyFunctionsForTable(cl CodeLocation) error {
|
||||
return GinkgoError{
|
||||
|
||||
+77
-16
@@ -2,11 +2,12 @@ package types
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/Masterminds/semver/v3"
|
||||
)
|
||||
|
||||
type SemVerFilter func([]string) bool
|
||||
type SemVerFilter func(component string, constraints []string) bool
|
||||
|
||||
func MustParseSemVerFilter(input string) SemVerFilter {
|
||||
filter, err := ParseSemVerFilter(input)
|
||||
@@ -16,30 +17,90 @@ func MustParseSemVerFilter(input string) SemVerFilter {
|
||||
return filter
|
||||
}
|
||||
|
||||
func ParseSemVerFilter(filterVersion string) (SemVerFilter, error) {
|
||||
if filterVersion == "" {
|
||||
return func(_ []string) bool { return true }, nil
|
||||
// ParseSemVerFilter parses non-component and component-specific semantic version filter string.
|
||||
// The filter string can contain multiple non-component and component-specific versions separated by commas.
|
||||
// Each component-specific version is in the format "component=version".
|
||||
// If a version is specified without a component, it applies to non-component-specific constraints.
|
||||
func ParseSemVerFilter(componentFilterVersions string) (SemVerFilter, error) {
|
||||
if componentFilterVersions == "" {
|
||||
return func(_ string, _ []string) bool { return true }, nil
|
||||
}
|
||||
|
||||
targetVersion, err := semver.NewVersion(filterVersion)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid filter version: %w", err)
|
||||
result := map[string]*semver.Version{}
|
||||
parts := strings.Split(componentFilterVersions, ",")
|
||||
for _, part := range parts {
|
||||
part = strings.TrimSpace(part)
|
||||
if len(part) == 0 {
|
||||
continue
|
||||
}
|
||||
if strings.Contains(part, "=") {
|
||||
// validate component-specific version string
|
||||
invalidPart, invalidErr := false, fmt.Errorf("invalid component filter version: %s", part)
|
||||
subParts := strings.Split(part, "=")
|
||||
if len(subParts) != 2 {
|
||||
invalidPart = true
|
||||
}
|
||||
component := strings.TrimSpace(subParts[0])
|
||||
versionStr := strings.TrimSpace(subParts[1])
|
||||
if len(component) == 0 || len(versionStr) == 0 {
|
||||
invalidPart = true
|
||||
}
|
||||
if invalidPart {
|
||||
return nil, invalidErr
|
||||
}
|
||||
|
||||
// validate semver
|
||||
v, err := semver.NewVersion(versionStr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid component filter version: %s, error: %w", part, err)
|
||||
}
|
||||
result[component] = v
|
||||
} else {
|
||||
v, err := semver.NewVersion(part)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid filter version: %s, error: %w", part, err)
|
||||
}
|
||||
result[""] = v
|
||||
}
|
||||
}
|
||||
|
||||
return func(constraints []string) bool {
|
||||
return func(component string, constraints []string) bool {
|
||||
// unconstrained specs always run
|
||||
if len(constraints) == 0 {
|
||||
if len(component) == 0 && len(constraints) == 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
for _, constraintStr := range constraints {
|
||||
constraint, err := semver.NewConstraint(constraintStr)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
// check non-component specific version constraints
|
||||
if len(component) == 0 && len(constraints) != 0 {
|
||||
v := result[""]
|
||||
if v != nil {
|
||||
for _, constraintStr := range constraints {
|
||||
constraint, err := semver.NewConstraint(constraintStr)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
if !constraint.Check(targetVersion) {
|
||||
return false
|
||||
if !constraint.Check(v) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check component-specific version constraints
|
||||
if len(component) != 0 && len(constraints) != 0 {
|
||||
v := result[component]
|
||||
if v != nil {
|
||||
for _, constraintStr := range constraints {
|
||||
constraint, err := semver.NewConstraint(constraintStr)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
if !constraint.Check(v) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+108
-51
@@ -38,6 +38,10 @@ type ConstructionNodeReport struct {
|
||||
// all Describe/Context/When containers in this spec's hierarchy
|
||||
ContainerHierarchySemVerConstraints [][]string
|
||||
|
||||
// ContainerHierarchyComponentSemVerConstraints is a slice containing the component-specific semVerConstraints of
|
||||
// all Describe/Context/When containers in this spec's hierarchy
|
||||
ContainerHierarchyComponentSemVerConstraints []map[string][]string
|
||||
|
||||
// IsSerial captures whether the any container has the Serial decorator
|
||||
IsSerial bool
|
||||
|
||||
@@ -85,6 +89,9 @@ type Report struct {
|
||||
//SuiteSemVerConstraints captures any semVerConstraints attached to the suite by the DSL's RunSpecs() function
|
||||
SuiteSemVerConstraints []string
|
||||
|
||||
//SuiteComponentSemVerConstraints captures any component-specific semVerConstraints attached to the suite by the DSL's RunSpecs() function
|
||||
SuiteComponentSemVerConstraints map[string][]string
|
||||
|
||||
//SuiteSucceeded captures the success or failure status of the test run
|
||||
//If true, the test run is considered successful.
|
||||
//If false, the test run is considered unsuccessful
|
||||
@@ -188,14 +195,19 @@ type SpecReport struct {
|
||||
// all Describe/Context/When containers in this spec's hierarchy
|
||||
ContainerHierarchySemVerConstraints [][]string
|
||||
|
||||
// ContainerHierarchyComponentSemVerConstraints is a slice containing the component-specific semVerConstraints of
|
||||
// all Describe/Context/When containers in this spec's hierarchy
|
||||
ContainerHierarchyComponentSemVerConstraints []map[string][]string
|
||||
|
||||
// LeafNodeType, LeafNodeLocation, LeafNodeLabels, LeafNodeSemVerConstraints and LeafNodeText capture the NodeType, CodeLocation, and text
|
||||
// of the Ginkgo node being tested (typically an NodeTypeIt node, though this can also be
|
||||
// one of the NodeTypesForSuiteLevelNodes node types)
|
||||
LeafNodeType NodeType
|
||||
LeafNodeLocation CodeLocation
|
||||
LeafNodeLabels []string
|
||||
LeafNodeSemVerConstraints []string
|
||||
LeafNodeText string
|
||||
LeafNodeType NodeType
|
||||
LeafNodeLocation CodeLocation
|
||||
LeafNodeLabels []string
|
||||
LeafNodeSemVerConstraints []string
|
||||
LeafNodeComponentSemVerConstraints map[string][]string
|
||||
LeafNodeText string
|
||||
|
||||
// Captures the Spec Priority
|
||||
SpecPriority int
|
||||
@@ -261,52 +273,54 @@ type SpecReport struct {
|
||||
func (report SpecReport) MarshalJSON() ([]byte, error) {
|
||||
//All this to avoid emitting an empty Failure struct in the JSON
|
||||
out := struct {
|
||||
ContainerHierarchyTexts []string
|
||||
ContainerHierarchyLocations []CodeLocation
|
||||
ContainerHierarchyLabels [][]string
|
||||
ContainerHierarchySemVerConstraints [][]string
|
||||
LeafNodeType NodeType
|
||||
LeafNodeLocation CodeLocation
|
||||
LeafNodeLabels []string
|
||||
LeafNodeSemVerConstraints []string
|
||||
LeafNodeText string
|
||||
State SpecState
|
||||
StartTime time.Time
|
||||
EndTime time.Time
|
||||
RunTime time.Duration
|
||||
ParallelProcess int
|
||||
Failure *Failure `json:",omitempty"`
|
||||
NumAttempts int
|
||||
MaxFlakeAttempts int
|
||||
MaxMustPassRepeatedly int
|
||||
CapturedGinkgoWriterOutput string `json:",omitempty"`
|
||||
CapturedStdOutErr string `json:",omitempty"`
|
||||
ReportEntries ReportEntries `json:",omitempty"`
|
||||
ProgressReports []ProgressReport `json:",omitempty"`
|
||||
AdditionalFailures []AdditionalFailure `json:",omitempty"`
|
||||
SpecEvents SpecEvents `json:",omitempty"`
|
||||
ContainerHierarchyTexts []string
|
||||
ContainerHierarchyLocations []CodeLocation
|
||||
ContainerHierarchyLabels [][]string
|
||||
ContainerHierarchySemVerConstraints [][]string
|
||||
ContainerHierarchyComponentSemVerConstraints []map[string][]string
|
||||
LeafNodeType NodeType
|
||||
LeafNodeLocation CodeLocation
|
||||
LeafNodeLabels []string
|
||||
LeafNodeSemVerConstraints []string
|
||||
LeafNodeText string
|
||||
State SpecState
|
||||
StartTime time.Time
|
||||
EndTime time.Time
|
||||
RunTime time.Duration
|
||||
ParallelProcess int
|
||||
Failure *Failure `json:",omitempty"`
|
||||
NumAttempts int
|
||||
MaxFlakeAttempts int
|
||||
MaxMustPassRepeatedly int
|
||||
CapturedGinkgoWriterOutput string `json:",omitempty"`
|
||||
CapturedStdOutErr string `json:",omitempty"`
|
||||
ReportEntries ReportEntries `json:",omitempty"`
|
||||
ProgressReports []ProgressReport `json:",omitempty"`
|
||||
AdditionalFailures []AdditionalFailure `json:",omitempty"`
|
||||
SpecEvents SpecEvents `json:",omitempty"`
|
||||
}{
|
||||
ContainerHierarchyTexts: report.ContainerHierarchyTexts,
|
||||
ContainerHierarchyLocations: report.ContainerHierarchyLocations,
|
||||
ContainerHierarchyLabels: report.ContainerHierarchyLabels,
|
||||
ContainerHierarchySemVerConstraints: report.ContainerHierarchySemVerConstraints,
|
||||
LeafNodeType: report.LeafNodeType,
|
||||
LeafNodeLocation: report.LeafNodeLocation,
|
||||
LeafNodeLabels: report.LeafNodeLabels,
|
||||
LeafNodeSemVerConstraints: report.LeafNodeSemVerConstraints,
|
||||
LeafNodeText: report.LeafNodeText,
|
||||
State: report.State,
|
||||
StartTime: report.StartTime,
|
||||
EndTime: report.EndTime,
|
||||
RunTime: report.RunTime,
|
||||
ParallelProcess: report.ParallelProcess,
|
||||
Failure: nil,
|
||||
ReportEntries: nil,
|
||||
NumAttempts: report.NumAttempts,
|
||||
MaxFlakeAttempts: report.MaxFlakeAttempts,
|
||||
MaxMustPassRepeatedly: report.MaxMustPassRepeatedly,
|
||||
CapturedGinkgoWriterOutput: report.CapturedGinkgoWriterOutput,
|
||||
CapturedStdOutErr: report.CapturedStdOutErr,
|
||||
ContainerHierarchyTexts: report.ContainerHierarchyTexts,
|
||||
ContainerHierarchyLocations: report.ContainerHierarchyLocations,
|
||||
ContainerHierarchyLabels: report.ContainerHierarchyLabels,
|
||||
ContainerHierarchySemVerConstraints: report.ContainerHierarchySemVerConstraints,
|
||||
ContainerHierarchyComponentSemVerConstraints: report.ContainerHierarchyComponentSemVerConstraints,
|
||||
LeafNodeType: report.LeafNodeType,
|
||||
LeafNodeLocation: report.LeafNodeLocation,
|
||||
LeafNodeLabels: report.LeafNodeLabels,
|
||||
LeafNodeSemVerConstraints: report.LeafNodeSemVerConstraints,
|
||||
LeafNodeText: report.LeafNodeText,
|
||||
State: report.State,
|
||||
StartTime: report.StartTime,
|
||||
EndTime: report.EndTime,
|
||||
RunTime: report.RunTime,
|
||||
ParallelProcess: report.ParallelProcess,
|
||||
Failure: nil,
|
||||
ReportEntries: nil,
|
||||
NumAttempts: report.NumAttempts,
|
||||
MaxFlakeAttempts: report.MaxFlakeAttempts,
|
||||
MaxMustPassRepeatedly: report.MaxMustPassRepeatedly,
|
||||
CapturedGinkgoWriterOutput: report.CapturedGinkgoWriterOutput,
|
||||
CapturedStdOutErr: report.CapturedStdOutErr,
|
||||
}
|
||||
|
||||
if !report.Failure.IsZero() {
|
||||
@@ -404,6 +418,34 @@ func (report SpecReport) SemVerConstraints() []string {
|
||||
return out
|
||||
}
|
||||
|
||||
// ComponentSemVerConstraints returns a deduped map of all the spec's component-specific SemVerConstraints.
|
||||
func (report SpecReport) ComponentSemVerConstraints() map[string][]string {
|
||||
out := map[string][]string{}
|
||||
seen := map[string]bool{}
|
||||
for _, compSemVerConstraints := range report.ContainerHierarchyComponentSemVerConstraints {
|
||||
for component := range compSemVerConstraints {
|
||||
if !seen[component] {
|
||||
seen[component] = true
|
||||
out[component] = compSemVerConstraints[component]
|
||||
} else {
|
||||
out[component] = append(out[component], compSemVerConstraints[component]...)
|
||||
out[component] = slices.Compact(out[component])
|
||||
}
|
||||
}
|
||||
}
|
||||
for component := range report.LeafNodeComponentSemVerConstraints {
|
||||
if !seen[component] {
|
||||
seen[component] = true
|
||||
out[component] = report.LeafNodeComponentSemVerConstraints[component]
|
||||
} else {
|
||||
out[component] = append(out[component], report.LeafNodeComponentSemVerConstraints[component]...)
|
||||
out[component] = slices.Compact(out[component])
|
||||
}
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
// MatchesLabelFilter returns true if the spec satisfies the passed in label filter query
|
||||
func (report SpecReport) MatchesLabelFilter(query string) (bool, error) {
|
||||
filter, err := ParseLabelFilter(query)
|
||||
@@ -419,7 +461,22 @@ func (report SpecReport) MatchesSemVerFilter(version string) (bool, error) {
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return filter(report.SemVerConstraints()), nil
|
||||
|
||||
semVerConstraints := report.SemVerConstraints()
|
||||
if len(semVerConstraints) != 0 && filter("", report.SemVerConstraints()) == false {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
componentSemVerConstraints := report.ComponentSemVerConstraints()
|
||||
if len(componentSemVerConstraints) != 0 {
|
||||
for component, constraints := range componentSemVerConstraints {
|
||||
if filter(component, constraints) == false {
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// FileName() returns the name of the file containing the spec
|
||||
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
package types
|
||||
|
||||
const VERSION = "2.27.5"
|
||||
const VERSION = "2.28.0"
|
||||
|
||||
+4
@@ -1,3 +1,7 @@
|
||||
## 1.39.1
|
||||
|
||||
Update all dependencies. This auto-updated the required version of Go to 1.24, consistent with the fact that Go 1.23 has been out of support for almost six months.
|
||||
|
||||
## 1.39.0
|
||||
|
||||
### Features
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ import (
|
||||
"github.com/onsi/gomega/types"
|
||||
)
|
||||
|
||||
const GOMEGA_VERSION = "1.39.0"
|
||||
const GOMEGA_VERSION = "1.39.1"
|
||||
|
||||
const nilGomegaPanic = `You are trying to make an assertion, but haven't registered Gomega's fail handler.
|
||||
If you're using Ginkgo then you probably forgot to put your assertion in an It().
|
||||
|
||||
+38
-107
@@ -75,11 +75,6 @@ func expandAndVerifyScope(ctx context.Context, req interface{}, tokenScope map[s
|
||||
return nil
|
||||
}
|
||||
|
||||
case strings.HasPrefix(k, "share"):
|
||||
if err = resolveUserShare(ctx, ref, tokenScope[k], client, mgr); err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
case strings.HasPrefix(k, "lightweight"):
|
||||
if err = resolveLightweightScope(ctx, ref, tokenScope[k], user, client, mgr); err == nil {
|
||||
return nil
|
||||
@@ -130,8 +125,13 @@ func expandAndVerifyScope(ctx context.Context, req interface{}, tokenScope map[s
|
||||
}
|
||||
|
||||
func resolveLightweightScope(ctx context.Context, ref *provider.Reference, scope *authpb.Scope, user *userpb.User, client gateway.GatewayAPIClient, mgr token.Manager) error {
|
||||
refString, err := storagespace.FormatReference(ref)
|
||||
if err != nil {
|
||||
// cannot format reference, so cannot be valid
|
||||
return errtypes.PermissionDenied("invalid reference")
|
||||
}
|
||||
// Check if this ref is cached
|
||||
key := "lw:" + user.Id.OpaqueId + scopeDelimiter + getRefKey(ref)
|
||||
key := "lw:" + user.Id.OpaqueId + scopeDelimiter + refString
|
||||
if _, err := scopeExpansionCache.Get(key); err == nil {
|
||||
return nil
|
||||
}
|
||||
@@ -164,13 +164,7 @@ func resolvePublicShare(ctx context.Context, ref *provider.Reference, scope *aut
|
||||
return err
|
||||
}
|
||||
|
||||
if err := checkCacheForNestedResource(ctx, ref, share.ResourceId, client, mgr); err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Some services like wopi don't access the shared resource relative to the
|
||||
// share root but instead relative to the shared resources parent.
|
||||
return checkRelativeReference(ctx, ref, share.ResourceId, client)
|
||||
return checkCacheForNestedResource(ctx, ref, share.ResourceId, client, mgr)
|
||||
}
|
||||
|
||||
func resolveOCMShare(ctx context.Context, ref *provider.Reference, scope *authpb.Scope, client gateway.GatewayAPIClient, mgr token.Manager) error {
|
||||
@@ -184,69 +178,18 @@ func resolveOCMShare(ctx context.Context, ref *provider.Reference, scope *authpb
|
||||
ref.ResourceId = share.GetResourceId()
|
||||
}
|
||||
|
||||
if err := checkCacheForNestedResource(ctx, ref, share.ResourceId, client, mgr); err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Some services like wopi don't access the shared resource relative to the
|
||||
// share root but instead relative to the shared resources parent.
|
||||
return checkRelativeReference(ctx, ref, share.ResourceId, client)
|
||||
}
|
||||
|
||||
// checkRelativeReference checks if the shared resource is being accessed via a relative reference
|
||||
// e.g.:
|
||||
// storage: abcd, space: efgh
|
||||
// /root (id: efgh)
|
||||
// - New file.txt (id: ijkl) <- shared resource
|
||||
//
|
||||
// If the requested reference looks like this:
|
||||
// Reference{ResourceId: {StorageId: "abcd", SpaceId: "efgh"}, Path: "./New file.txt"}
|
||||
// then the request is considered relative and this function would return true.
|
||||
// Only references which are relative to the immediate parent of a resource are considered valid.
|
||||
func checkRelativeReference(ctx context.Context, requested *provider.Reference, sharedResourceID *provider.ResourceId, client gateway.GatewayAPIClient) error {
|
||||
sRes, err := client.Stat(ctx, &provider.StatRequest{Ref: &provider.Reference{ResourceId: sharedResourceID}})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if sRes.Status.Code != rpc.Code_CODE_OK {
|
||||
return statuspkg.NewErrorFromCode(sRes.Status.Code, "auth interceptor")
|
||||
}
|
||||
|
||||
sharedResource := sRes.Info
|
||||
|
||||
// Is this a shared space
|
||||
if sharedResource.ParentId == nil {
|
||||
// Is the requested resource part of the shared space?
|
||||
if requested.ResourceId.StorageId != sharedResource.Id.StorageId || requested.ResourceId.SpaceId != sharedResource.Id.SpaceId {
|
||||
return errtypes.PermissionDenied("space access forbidden via public link")
|
||||
}
|
||||
} else {
|
||||
parentID := sharedResource.ParentId
|
||||
parentID.StorageId = sharedResource.Id.StorageId
|
||||
|
||||
if !utils.ResourceIDEqual(parentID, requested.ResourceId) && utils.MakeRelativePath(sharedResource.Path) != requested.Path {
|
||||
return errtypes.PermissionDenied("access forbidden via public link")
|
||||
}
|
||||
}
|
||||
|
||||
key := storagespace.FormatResourceID(sharedResourceID) + scopeDelimiter + getRefKey(requested)
|
||||
_ = scopeExpansionCache.SetWithExpire(key, nil, scopeCacheExpiration*time.Second)
|
||||
return nil
|
||||
}
|
||||
|
||||
func resolveUserShare(ctx context.Context, ref *provider.Reference, scope *authpb.Scope, client gateway.GatewayAPIClient, mgr token.Manager) error {
|
||||
var share collaboration.Share
|
||||
err := utils.UnmarshalJSONToProtoV1(scope.Resource.Value, &share)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return checkCacheForNestedResource(ctx, ref, share.ResourceId, client, mgr)
|
||||
}
|
||||
|
||||
func checkCacheForNestedResource(ctx context.Context, ref *provider.Reference, resource *provider.ResourceId, client gateway.GatewayAPIClient, mgr token.Manager) error {
|
||||
refString, err := storagespace.FormatReference(ref)
|
||||
if err != nil {
|
||||
// cannot format reference, so cannot be valid
|
||||
return errtypes.PermissionDenied("invalid reference")
|
||||
}
|
||||
|
||||
// Check if this ref is cached
|
||||
key := storagespace.FormatResourceID(resource) + scopeDelimiter + getRefKey(ref)
|
||||
key := storagespace.FormatResourceID(resource) + scopeDelimiter + refString
|
||||
if _, err := scopeExpansionCache.Get(key); err == nil {
|
||||
return nil
|
||||
}
|
||||
@@ -270,40 +213,25 @@ func checkIfNestedResource(ctx context.Context, ref *provider.Reference, parent
|
||||
return false, statuspkg.NewErrorFromCode(statResponse.Status.Code, "auth interceptor")
|
||||
}
|
||||
|
||||
pathResp, err := client.GetPath(ctx, &provider.GetPathRequest{ResourceId: statResponse.GetInfo().GetId()})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if pathResp.Status.Code != rpc.Code_CODE_OK {
|
||||
return false, statuspkg.NewErrorFromCode(pathResp.Status.Code, "auth interceptor")
|
||||
}
|
||||
parentPath := pathResp.Path
|
||||
parentInfo := statResponse.GetInfo()
|
||||
|
||||
childPath := ref.GetPath()
|
||||
if childPath != "" && childPath != "." && strings.HasPrefix(childPath, parentPath) {
|
||||
// if the request is relative from the root, we can return directly
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// The request is not relative to the root. We need to find out if the requested resource is child of the `parent` (coming from token scope)
|
||||
// We need to find out if the requested resource is child of the `parent` (coming from token scope)
|
||||
// We mint a token as the owner of the public share and try to stat the reference
|
||||
// TODO(ishank011): We need to find a better alternative to this
|
||||
// NOTE: did somebody say service accounts? ...
|
||||
|
||||
var user *userpb.User
|
||||
if statResponse.GetInfo().GetOwner().GetType() == userpb.UserType_USER_TYPE_SPACE_OWNER {
|
||||
if parentInfo.GetOwner().GetType() == userpb.UserType_USER_TYPE_SPACE_OWNER {
|
||||
// fake a space owner user
|
||||
user = &userpb.User{
|
||||
Id: statResponse.GetInfo().GetOwner(),
|
||||
Id: parentInfo.GetOwner(),
|
||||
}
|
||||
} else {
|
||||
userResp, err := client.GetUser(ctx, &userpb.GetUserRequest{UserId: statResponse.Info.Owner, SkipFetchingUserGroups: true})
|
||||
userResp, err := client.GetUser(ctx, &userpb.GetUserRequest{UserId: parentInfo.GetOwner(), SkipFetchingUserGroups: true})
|
||||
if err != nil || userResp.Status.Code != rpc.Code_CODE_OK {
|
||||
return false, err
|
||||
}
|
||||
user = userResp.User
|
||||
}
|
||||
|
||||
scope, err := scope.AddOwnerScope(map[string]*authpb.Scope{})
|
||||
if err != nil {
|
||||
return false, err
|
||||
@@ -329,6 +257,24 @@ func checkIfNestedResource(ctx context.Context, ref *provider.Reference, parent
|
||||
if childStat.GetStatus().GetCode() != rpc.Code_CODE_OK {
|
||||
return false, statuspkg.NewErrorFromCode(childStat.Status.Code, "auth interceptor")
|
||||
}
|
||||
childInfo := childStat.GetInfo()
|
||||
|
||||
// child can only be a nested resource if it is within the same space as parent
|
||||
if childInfo.GetId().GetStorageId() != parentInfo.GetId().GetStorageId() ||
|
||||
childInfo.GetId().GetSpaceId() != parentInfo.GetId().GetSpaceId() {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// Both resources are in the same space, now check paths
|
||||
pathResp, err := client.GetPath(ctx, &provider.GetPathRequest{ResourceId: statResponse.GetInfo().GetId()})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if pathResp.Status.Code != rpc.Code_CODE_OK {
|
||||
return false, statuspkg.NewErrorFromCode(pathResp.Status.Code, "auth interceptor")
|
||||
}
|
||||
parentPath := pathResp.Path
|
||||
|
||||
pathResp, err = client.GetPath(ctx, &provider.GetPathRequest{ResourceId: childStat.GetInfo().GetId()})
|
||||
if err != nil {
|
||||
return false, err
|
||||
@@ -336,10 +282,9 @@ func checkIfNestedResource(ctx context.Context, ref *provider.Reference, parent
|
||||
if pathResp.GetStatus().GetCode() != rpc.Code_CODE_OK {
|
||||
return false, statuspkg.NewErrorFromCode(pathResp.Status.Code, "auth interceptor")
|
||||
}
|
||||
childPath = pathResp.Path
|
||||
childPath := pathResp.Path
|
||||
|
||||
return strings.HasPrefix(childPath, parentPath), nil
|
||||
|
||||
}
|
||||
|
||||
func extractRefFromListProvidersReq(v *registry.ListStorageProvidersRequest) (*provider.Reference, bool) {
|
||||
@@ -513,17 +458,3 @@ func extractShareRef(req interface{}) (*collaboration.ShareReference, bool) {
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func getRefKey(ref *provider.Reference) string {
|
||||
if ref.GetPath() != "" {
|
||||
return ref.Path
|
||||
}
|
||||
|
||||
if ref.GetResourceId() != nil {
|
||||
return storagespace.FormatResourceID(ref.ResourceId)
|
||||
}
|
||||
|
||||
// on malicious request both path and rid could be empty
|
||||
// we still should not panic
|
||||
return ""
|
||||
}
|
||||
|
||||
Generated
Vendored
+57
-32
@@ -21,6 +21,7 @@ package ocdav
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"path"
|
||||
"path/filepath"
|
||||
@@ -274,7 +275,7 @@ func (s *svc) executePathCopy(ctx context.Context, selector pool.Selectable[gate
|
||||
|
||||
var uploadEP, uploadToken string
|
||||
for _, p := range uRes.Protocols {
|
||||
if p.Protocol == "simple" {
|
||||
if p.Protocol == "tus" {
|
||||
uploadEP, uploadToken = p.UploadEndpoint, p.Token
|
||||
}
|
||||
}
|
||||
@@ -303,24 +304,10 @@ func (s *svc) executePathCopy(ctx context.Context, selector pool.Selectable[gate
|
||||
}
|
||||
|
||||
// 4. do upload
|
||||
|
||||
httpUploadReq, err := rhttp.NewRequest(ctx, "PUT", uploadEP, httpDownloadRes.Body)
|
||||
fileid, err = s.tusUpload(ctx, uploadEP, uploadToken, httpDownloadRes.Body, int64(cp.sourceInfo.GetSize()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
httpUploadReq.Header.Set(datagateway.TokenTransportHeader, uploadToken)
|
||||
httpUploadReq.ContentLength = int64(cp.sourceInfo.GetSize())
|
||||
|
||||
httpUploadRes, err := s.client.Do(httpUploadReq)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer httpUploadRes.Body.Close()
|
||||
if httpUploadRes.StatusCode != http.StatusOK {
|
||||
return err
|
||||
}
|
||||
|
||||
fileid = httpUploadRes.Header.Get(net.HeaderOCFileID)
|
||||
}
|
||||
|
||||
w.Header().Set(net.HeaderOCFileID, fileid)
|
||||
@@ -498,7 +485,7 @@ func (s *svc) executeSpacesCopy(ctx context.Context, w http.ResponseWriter, sele
|
||||
|
||||
var uploadEP, uploadToken string
|
||||
for _, p := range uRes.Protocols {
|
||||
if p.Protocol == "simple" {
|
||||
if p.Protocol == "tus" {
|
||||
uploadEP, uploadToken = p.UploadEndpoint, p.Token
|
||||
}
|
||||
}
|
||||
@@ -530,24 +517,10 @@ func (s *svc) executeSpacesCopy(ctx context.Context, w http.ResponseWriter, sele
|
||||
}
|
||||
|
||||
// 4. do upload
|
||||
|
||||
httpUploadReq, err := rhttp.NewRequest(ctx, http.MethodPut, uploadEP, httpDownloadRes.Body)
|
||||
fileid, err = s.tusUpload(ctx, uploadEP, uploadToken, httpDownloadRes.Body, int64(cp.sourceInfo.GetSize()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
httpUploadReq.Header.Set(datagateway.TokenTransportHeader, uploadToken)
|
||||
httpUploadReq.ContentLength = int64(cp.sourceInfo.GetSize())
|
||||
|
||||
httpUploadRes, err := s.client.Do(httpUploadReq)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer httpUploadRes.Body.Close()
|
||||
if httpUploadRes.StatusCode != http.StatusOK {
|
||||
return err
|
||||
}
|
||||
|
||||
fileid = httpUploadRes.Header.Get(net.HeaderOCFileID)
|
||||
}
|
||||
|
||||
w.Header().Set(net.HeaderOCFileID, fileid)
|
||||
@@ -756,3 +729,55 @@ func (s *svc) prepareCopy(ctx context.Context, w http.ResponseWriter, r *http.Re
|
||||
|
||||
return ©{source: srcRef, sourceInfo: srcStatRes.Info, depth: depth, successCode: successCode, destination: dstRef}
|
||||
}
|
||||
|
||||
func (s *svc) tusUpload(ctx context.Context, uploadEP, uploadToken string, body io.Reader, size int64) (string, error) {
|
||||
chunkSize := int64(10000000)
|
||||
var offset int64
|
||||
var fileid string
|
||||
|
||||
for offset < size {
|
||||
n := chunkSize
|
||||
if offset+n > size {
|
||||
n = size - offset
|
||||
}
|
||||
|
||||
req, err := rhttp.NewRequest(ctx, http.MethodPatch, uploadEP, io.LimitReader(body, n))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
req.Header.Set(datagateway.TokenTransportHeader, uploadToken)
|
||||
req.Header.Set(net.HeaderTusResumable, "1.0.0")
|
||||
req.Header.Set(net.HeaderUploadOffset, strconv.FormatInt(offset, 10))
|
||||
req.Header.Set(net.HeaderContentType, "application/offset+octet-stream")
|
||||
req.ContentLength = n
|
||||
|
||||
res, err := s.client.Do(req)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if res.StatusCode != http.StatusNoContent && res.StatusCode != http.StatusOK && res.StatusCode != http.StatusCreated {
|
||||
res.Body.Close()
|
||||
return "", fmt.Errorf("unexpected status code during TUS upload: %d", res.StatusCode)
|
||||
}
|
||||
|
||||
if id := res.Header.Get(net.HeaderOCFileID); id != "" {
|
||||
fileid = id
|
||||
}
|
||||
|
||||
newOffsetStr := res.Header.Get(net.HeaderUploadOffset)
|
||||
res.Body.Close()
|
||||
|
||||
if newOffsetStr != "" {
|
||||
newOffset, err := strconv.ParseInt(newOffsetStr, 10, 64)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("invalid Upload-Offset header: %v", err)
|
||||
}
|
||||
offset = newOffset
|
||||
} else {
|
||||
offset += n
|
||||
}
|
||||
}
|
||||
return fileid, nil
|
||||
}
|
||||
|
||||
-75
@@ -1,75 +0,0 @@
|
||||
// Copyright 2018-2021 CERN
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// In applying this license, CERN does not waive the privileges and immunities
|
||||
// granted to it by virtue of its status as an Intergovernmental Organization
|
||||
// or submit itself to any jurisdiction.
|
||||
|
||||
package scope
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
authpb "github.com/cs3org/go-cs3apis/cs3/auth/provider/v1beta1"
|
||||
collaboration "github.com/cs3org/go-cs3apis/cs3/sharing/collaboration/v1beta1"
|
||||
types "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/errtypes"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/utils"
|
||||
"github.com/rs/zerolog"
|
||||
)
|
||||
|
||||
func receivedShareScope(_ context.Context, scope *authpb.Scope, resource interface{}, logger *zerolog.Logger) (bool, error) {
|
||||
var share collaboration.ReceivedShare
|
||||
err := utils.UnmarshalJSONToProtoV1(scope.Resource.Value, &share)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
switch v := resource.(type) {
|
||||
case *collaboration.GetReceivedShareRequest:
|
||||
return checkShareRef(share.Share, v.GetRef()), nil
|
||||
case *collaboration.UpdateReceivedShareRequest:
|
||||
return checkShare(share.Share, v.GetShare().GetShare()), nil
|
||||
case string:
|
||||
return checkSharePath(v) || checkResourcePath(v), nil
|
||||
}
|
||||
|
||||
msg := fmt.Sprintf("resource type assertion failed: %+v", resource)
|
||||
logger.Debug().Str("scope", "receivedShareScope").Msg(msg)
|
||||
return false, errtypes.InternalError(msg)
|
||||
}
|
||||
|
||||
// AddReceivedShareScope adds the scope to allow access to a received user/group share and
|
||||
// the shared resource.
|
||||
func AddReceivedShareScope(share *collaboration.ReceivedShare, role authpb.Role, scopes map[string]*authpb.Scope) (map[string]*authpb.Scope, error) {
|
||||
// Create a new "scope share" to only expose the required fields to the scope.
|
||||
scopeShare := &collaboration.Share{Id: share.Share.Id, Owner: share.Share.Owner, Creator: share.Share.Creator, ResourceId: share.Share.ResourceId}
|
||||
|
||||
val, err := utils.MarshalProtoV1ToJSON(&collaboration.ReceivedShare{Share: scopeShare})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if scopes == nil {
|
||||
scopes = make(map[string]*authpb.Scope)
|
||||
}
|
||||
scopes["receivedshare:"+share.Share.Id.OpaqueId] = &authpb.Scope{
|
||||
Resource: &types.OpaqueEntry{
|
||||
Decoder: "json",
|
||||
Value: val,
|
||||
},
|
||||
Role: role,
|
||||
}
|
||||
return scopes, nil
|
||||
}
|
||||
+5
-7
@@ -31,13 +31,11 @@ import (
|
||||
type Verifier func(context.Context, *authpb.Scope, interface{}, *zerolog.Logger) (bool, error)
|
||||
|
||||
var supportedScopes = map[string]Verifier{
|
||||
"user": userScope,
|
||||
"publicshare": publicshareScope,
|
||||
"resourceinfo": resourceinfoScope,
|
||||
"share": shareScope,
|
||||
"receivedshare": receivedShareScope,
|
||||
"lightweight": lightweightAccountScope,
|
||||
"ocmshare": ocmShareScope,
|
||||
"user": userScope,
|
||||
"publicshare": publicshareScope,
|
||||
"resourceinfo": resourceinfoScope,
|
||||
"lightweight": lightweightAccountScope,
|
||||
"ocmshare": ocmShareScope,
|
||||
}
|
||||
|
||||
// VerifyScope is the function to be called when dismantling tokens to check if
|
||||
|
||||
-142
@@ -1,142 +0,0 @@
|
||||
// Copyright 2018-2021 CERN
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// In applying this license, CERN does not waive the privileges and immunities
|
||||
// granted to it by virtue of its status as an Intergovernmental Organization
|
||||
// or submit itself to any jurisdiction.
|
||||
|
||||
package scope
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
authpb "github.com/cs3org/go-cs3apis/cs3/auth/provider/v1beta1"
|
||||
collaboration "github.com/cs3org/go-cs3apis/cs3/sharing/collaboration/v1beta1"
|
||||
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
|
||||
registry "github.com/cs3org/go-cs3apis/cs3/storage/registry/v1beta1"
|
||||
types "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/errtypes"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/utils"
|
||||
"github.com/rs/zerolog"
|
||||
)
|
||||
|
||||
func shareScope(_ context.Context, scope *authpb.Scope, resource interface{}, logger *zerolog.Logger) (bool, error) {
|
||||
var share collaboration.Share
|
||||
err := utils.UnmarshalJSONToProtoV1(scope.Resource.Value, &share)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
switch v := resource.(type) {
|
||||
// Viewer role
|
||||
case *registry.GetStorageProvidersRequest:
|
||||
return checkShareStorageRef(&share, v.GetRef()), nil
|
||||
case *provider.StatRequest:
|
||||
return checkShareStorageRef(&share, v.GetRef()), nil
|
||||
case *provider.ListContainerRequest:
|
||||
return checkShareStorageRef(&share, v.GetRef()), nil
|
||||
case *provider.InitiateFileDownloadRequest:
|
||||
return checkShareStorageRef(&share, v.GetRef()), nil
|
||||
|
||||
// Editor role
|
||||
// TODO(ishank011): Add role checks,
|
||||
// need to return appropriate status codes in the ocs/ocdav layers.
|
||||
case *provider.CreateContainerRequest:
|
||||
return checkShareStorageRef(&share, v.GetRef()), nil
|
||||
case *provider.TouchFileRequest:
|
||||
return checkShareStorageRef(&share, v.GetRef()), nil
|
||||
case *provider.DeleteRequest:
|
||||
return checkShareStorageRef(&share, v.GetRef()), nil
|
||||
case *provider.MoveRequest:
|
||||
return checkShareStorageRef(&share, v.GetSource()) && checkShareStorageRef(&share, v.GetDestination()), nil
|
||||
case *provider.InitiateFileUploadRequest:
|
||||
return checkShareStorageRef(&share, v.GetRef()), nil
|
||||
|
||||
case *collaboration.ListReceivedSharesRequest:
|
||||
return true, nil
|
||||
case *collaboration.GetReceivedShareRequest:
|
||||
return checkShareRef(&share, v.GetRef()), nil
|
||||
case string:
|
||||
return checkSharePath(v) || checkResourcePath(v), nil
|
||||
}
|
||||
|
||||
msg := fmt.Sprintf("resource type assertion failed: %+v", resource)
|
||||
logger.Debug().Str("scope", "shareScope").Msg(msg)
|
||||
return false, errtypes.InternalError(msg)
|
||||
}
|
||||
|
||||
func checkShareStorageRef(s *collaboration.Share, r *provider.Reference) bool {
|
||||
// ref: <id:<storage_id:$storageID opaque_id:$opaqueID > >
|
||||
if r.GetResourceId() != nil && r.Path == "" { // path must be empty
|
||||
return utils.ResourceIDEqual(s.ResourceId, r.GetResourceId())
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func checkShareRef(s *collaboration.Share, ref *collaboration.ShareReference) bool {
|
||||
if ref.GetId() != nil {
|
||||
return ref.GetId().OpaqueId == s.Id.OpaqueId
|
||||
}
|
||||
if key := ref.GetKey(); key != nil {
|
||||
return (utils.UserEqual(key.Owner, s.Owner) || utils.UserEqual(key.Owner, s.Creator)) &&
|
||||
utils.ResourceIDEqual(key.ResourceId, s.ResourceId) && utils.GranteeEqual(key.Grantee, s.Grantee)
|
||||
}
|
||||
return false
|
||||
}
|
||||
func checkShare(s1 *collaboration.Share, s2 *collaboration.Share) bool {
|
||||
if s2.GetId() != nil {
|
||||
return s2.GetId().OpaqueId == s1.Id.OpaqueId
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func checkSharePath(path string) bool {
|
||||
paths := []string{
|
||||
"/ocs/v2.php/apps/files_sharing/api/v1/shares",
|
||||
"/ocs/v1.php/apps/files_sharing/api/v1/shares",
|
||||
"/remote.php/webdav",
|
||||
"/remote.php/dav/files",
|
||||
}
|
||||
for _, p := range paths {
|
||||
if strings.HasPrefix(path, p) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// AddShareScope adds the scope to allow access to a user/group share and
|
||||
// the shared resource.
|
||||
func AddShareScope(share *collaboration.Share, role authpb.Role, scopes map[string]*authpb.Scope) (map[string]*authpb.Scope, error) {
|
||||
// Create a new "scope share" to only expose the required fields to the scope.
|
||||
scopeShare := &collaboration.Share{Id: share.Id, Owner: share.Owner, Creator: share.Creator, ResourceId: share.ResourceId}
|
||||
|
||||
val, err := utils.MarshalProtoV1ToJSON(scopeShare)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if scopes == nil {
|
||||
scopes = make(map[string]*authpb.Scope)
|
||||
}
|
||||
scopes["share:"+share.Id.OpaqueId] = &authpb.Scope{
|
||||
Resource: &types.OpaqueEntry{
|
||||
Decoder: "json",
|
||||
Value: val,
|
||||
},
|
||||
Role: role,
|
||||
}
|
||||
return scopes, nil
|
||||
}
|
||||
+4
@@ -16,6 +16,7 @@ linters:
|
||||
- govet
|
||||
- ineffassign
|
||||
- misspell
|
||||
- modernize
|
||||
- perfsprint
|
||||
- revive
|
||||
- staticcheck
|
||||
@@ -111,6 +112,9 @@ linters:
|
||||
locale: US
|
||||
ignore-rules:
|
||||
- cancelled
|
||||
modernize:
|
||||
disable:
|
||||
- omitzero
|
||||
perfsprint:
|
||||
int-conversion: true
|
||||
err-error: true
|
||||
|
||||
+39
-1
@@ -11,6 +11,43 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
|
||||
<!-- Released section -->
|
||||
<!-- Don't change this section unless doing release -->
|
||||
|
||||
## [1.40.0/0.62.0/0.16.0] 2026-02-02
|
||||
|
||||
### Added
|
||||
|
||||
- Add `AlwaysRecord` sampler in `go.opentelemetry.io/otel/sdk/trace`. (#7724)
|
||||
- Add `Enabled` method to all synchronous instrument interfaces (`Float64Counter`, `Float64UpDownCounter`, `Float64Histogram`, `Float64Gauge`, `Int64Counter`, `Int64UpDownCounter`, `Int64Histogram`, `Int64Gauge`,) in `go.opentelemetry.io/otel/metric`.
|
||||
This stabilizes the synchronous instrument enabled feature, allowing users to check if an instrument will process measurements before performing computationally expensive operations. (#7763)
|
||||
- Add `go.opentelemetry.io/otel/semconv/v1.39.0` package.
|
||||
The package contains semantic conventions from the `v1.39.0` version of the OpenTelemetry Semantic Conventions.
|
||||
See the [migration documentation](./semconv/v1.39.0/MIGRATION.md) for information on how to upgrade from `go.opentelemetry.io/otel/semconv/v1.38.0.` (#7783, #7789)
|
||||
|
||||
### Changed
|
||||
|
||||
- Improve the concurrent performance of `HistogramReservoir` in `go.opentelemetry.io/otel/sdk/metric/exemplar` by 4x. (#7443)
|
||||
- Improve the concurrent performance of `FixedSizeReservoir` in `go.opentelemetry.io/otel/sdk/metric/exemplar`. (#7447)
|
||||
- Improve performance of concurrent histogram measurements in `go.opentelemetry.io/otel/sdk/metric`. (#7474)
|
||||
- Improve performance of concurrent synchronous gauge measurements in `go.opentelemetry.io/otel/sdk/metric`. (#7478)
|
||||
- Add experimental observability metrics in `go.opentelemetry.io/otel/exporters/stdout/stdoutmetric`. (#7492)
|
||||
- `Exporter` in `go.opentelemetry.io/otel/exporters/prometheus` ignores metrics with the scope `go.opentelemetry.io/contrib/bridges/prometheus`.
|
||||
This prevents scrape failures when the Prometheus exporter is misconfigured to get data from the Prometheus bridge. (#7688)
|
||||
- Improve performance of concurrent exponential histogram measurements in `go.opentelemetry.io/otel/sdk/metric`. (#7702)
|
||||
- The `rpc.grpc.status_code` attribute in the experimental metrics emitted from `go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc` is replaced with the `rpc.response.status_code` attribute to align with the semantic conventions. (#7854)
|
||||
- The `rpc.grpc.status_code` attribute in the experimental metrics emitted from `go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc` is replaced with the `rpc.response.status_code` attribute to align with the semantic conventions. (#7854)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix bad log message when key-value pairs are dropped because of key duplication in `go.opentelemetry.io/otel/sdk/log`. (#7662)
|
||||
- Fix `DroppedAttributes` on `Record` in `go.opentelemetry.io/otel/sdk/log` to not count the non-attribute key-value pairs dropped because of key duplication. (#7662)
|
||||
- Fix `SetAttributes` on `Record` in `go.opentelemetry.io/otel/sdk/log` to not log that attributes are dropped when they are actually not dropped. (#7662)
|
||||
- Fix missing `request.GetBody` in `go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp` to correctly handle HTTP/2 `GOAWAY` frame. (#7794)
|
||||
- `WithHostID` detector in `go.opentelemetry.io/otel/sdk/resource` to use full path for `ioreg` command on Darwin (macOS). (#7818)
|
||||
|
||||
### Deprecated
|
||||
|
||||
- Deprecate `go.opentelemetry.io/otel/exporters/zipkin`.
|
||||
For more information, see the [OTel blog post deprecating the Zipkin exporter](https://opentelemetry.io/blog/2025/deprecating-zipkin-exporters/). (#7670)
|
||||
|
||||
## [1.39.0/0.61.0/0.15.0/0.0.14] 2025-12-05
|
||||
|
||||
### Added
|
||||
@@ -3498,7 +3535,8 @@ It contains api and sdk for trace and meter.
|
||||
- CircleCI build CI manifest files.
|
||||
- CODEOWNERS file to track owners of this project.
|
||||
|
||||
[Unreleased]: https://github.com/open-telemetry/opentelemetry-go/compare/v1.39.0...HEAD
|
||||
[Unreleased]: https://github.com/open-telemetry/opentelemetry-go/compare/v1.40.0...HEAD
|
||||
[1.40.0/0.62.0/0.16.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.40.0
|
||||
[1.39.0/0.61.0/0.15.0/0.0.14]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.39.0
|
||||
[1.38.0/0.60.0/0.14.0/0.0.13]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.38.0
|
||||
[0.59.1]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/exporters/prometheus/v0.59.1
|
||||
|
||||
+3
-3
@@ -746,8 +746,8 @@ Encapsulate setup in constructor functions, ensuring clear ownership and scope:
|
||||
import (
|
||||
"errors"
|
||||
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.37.0"
|
||||
"go.opentelemetry.io/otel/semconv/v1.37.0/otelconv"
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.39.0"
|
||||
"go.opentelemetry.io/otel/semconv/v1.39.0/otelconv"
|
||||
)
|
||||
|
||||
type SDKComponent struct {
|
||||
@@ -1039,7 +1039,7 @@ func (e *Exporter) ExportSpans(ctx context.Context, spans []trace.ReadOnlySpan)
|
||||
|
||||
All observability metrics should follow the [OpenTelemetry Semantic Conventions for SDK metrics](https://github.com/open-telemetry/semantic-conventions/blob/1cf2476ae5e518225a766990a28a6d5602bd5a30/docs/otel/sdk-metrics.md).
|
||||
|
||||
Use the metric semantic conventions convenience package [otelconv](./semconv/v1.37.0/otelconv/metric.go).
|
||||
Use the metric semantic conventions convenience package [otelconv](./semconv/v1.39.0/otelconv/metric.go).
|
||||
|
||||
##### Component Identification
|
||||
|
||||
|
||||
+4
-8
@@ -13,32 +13,28 @@ import (
|
||||
|
||||
// BoolSliceValue converts a bool slice into an array with same elements as slice.
|
||||
func BoolSliceValue(v []bool) any {
|
||||
var zero bool
|
||||
cp := reflect.New(reflect.ArrayOf(len(v), reflect.TypeOf(zero))).Elem()
|
||||
cp := reflect.New(reflect.ArrayOf(len(v), reflect.TypeFor[bool]())).Elem()
|
||||
reflect.Copy(cp, reflect.ValueOf(v))
|
||||
return cp.Interface()
|
||||
}
|
||||
|
||||
// Int64SliceValue converts an int64 slice into an array with same elements as slice.
|
||||
func Int64SliceValue(v []int64) any {
|
||||
var zero int64
|
||||
cp := reflect.New(reflect.ArrayOf(len(v), reflect.TypeOf(zero))).Elem()
|
||||
cp := reflect.New(reflect.ArrayOf(len(v), reflect.TypeFor[int64]())).Elem()
|
||||
reflect.Copy(cp, reflect.ValueOf(v))
|
||||
return cp.Interface()
|
||||
}
|
||||
|
||||
// Float64SliceValue converts a float64 slice into an array with same elements as slice.
|
||||
func Float64SliceValue(v []float64) any {
|
||||
var zero float64
|
||||
cp := reflect.New(reflect.ArrayOf(len(v), reflect.TypeOf(zero))).Elem()
|
||||
cp := reflect.New(reflect.ArrayOf(len(v), reflect.TypeFor[float64]())).Elem()
|
||||
reflect.Copy(cp, reflect.ValueOf(v))
|
||||
return cp.Interface()
|
||||
}
|
||||
|
||||
// StringSliceValue converts a string slice into an array with same elements as slice.
|
||||
func StringSliceValue(v []string) any {
|
||||
var zero string
|
||||
cp := reflect.New(reflect.ArrayOf(len(v), reflect.TypeOf(zero))).Elem()
|
||||
cp := reflect.New(reflect.ArrayOf(len(v), reflect.TypeFor[string]())).Elem()
|
||||
reflect.Copy(cp, reflect.ValueOf(v))
|
||||
return cp.Interface()
|
||||
}
|
||||
|
||||
+1
-1
@@ -58,7 +58,7 @@ func isComparable[T comparable](t T) T { return t }
|
||||
|
||||
var (
|
||||
// keyValueType is used in computeDistinctReflect.
|
||||
keyValueType = reflect.TypeOf(KeyValue{})
|
||||
keyValueType = reflect.TypeFor[KeyValue]()
|
||||
|
||||
// emptyHash is the hash of an empty set.
|
||||
emptyHash = xxhash.New().Sum64()
|
||||
|
||||
+1
-2
@@ -66,8 +66,7 @@ func IntValue(v int) Value {
|
||||
|
||||
// IntSliceValue creates an INTSLICE Value.
|
||||
func IntSliceValue(v []int) Value {
|
||||
var int64Val int64
|
||||
cp := reflect.New(reflect.ArrayOf(len(v), reflect.TypeOf(int64Val)))
|
||||
cp := reflect.New(reflect.ArrayOf(len(v), reflect.TypeFor[int64]()))
|
||||
for i, val := range v {
|
||||
cp.Elem().Index(i).SetInt(int64(val))
|
||||
}
|
||||
|
||||
+2
-2
@@ -317,7 +317,7 @@ func parseMember(member string) (Member, error) {
|
||||
keyValue, properties, found := strings.Cut(member, propertyDelimiter)
|
||||
if found {
|
||||
// Parse the member properties.
|
||||
for _, pStr := range strings.Split(properties, propertyDelimiter) {
|
||||
for pStr := range strings.SplitSeq(properties, propertyDelimiter) {
|
||||
p, err := parseProperty(pStr)
|
||||
if err != nil {
|
||||
return newInvalidMember(), err
|
||||
@@ -480,7 +480,7 @@ func Parse(bStr string) (Baggage, error) {
|
||||
}
|
||||
|
||||
b := make(baggage.List)
|
||||
for _, memberStr := range strings.Split(bStr, listDelimiter) {
|
||||
for memberStr := range strings.SplitSeq(bStr, listDelimiter) {
|
||||
m, err := parseMember(memberStr)
|
||||
if err != nil {
|
||||
return Baggage{}, err
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
# This is a renovate-friendly source of Docker images.
|
||||
FROM python:3.13.6-slim-bullseye@sha256:e98b521460ee75bca92175c16247bdf7275637a8faaeb2bcfa19d879ae5c4b9a AS python
|
||||
FROM otel/weaver:v0.19.0@sha256:3d20814cef548f1d31f27f054fb4cd6a05125641a9f7cc29fc7eb234e8052cd9 AS weaver
|
||||
FROM otel/weaver:v0.20.0@sha256:fa4f1c6954ecea78ab1a4e865bd6f5b4aaba80c1896f9f4a11e2c361d04e197e AS weaver
|
||||
FROM avtodev/markdown-lint:v1@sha256:6aeedc2f49138ce7a1cd0adffc1b1c0321b841dc2102408967d9301c031949ee AS markdown
|
||||
|
||||
Generated
Vendored
+6
-5
@@ -18,8 +18,8 @@ import (
|
||||
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc/internal/x"
|
||||
"go.opentelemetry.io/otel/internal/global"
|
||||
"go.opentelemetry.io/otel/metric"
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.37.0"
|
||||
"go.opentelemetry.io/otel/semconv/v1.37.0/otelconv"
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.39.0"
|
||||
"go.opentelemetry.io/otel/semconv/v1.39.0/otelconv"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -116,7 +116,9 @@ func NewInstrumentation(id int64, target string) (*Instrumentation, error) {
|
||||
// Do not modify attrs (NewSet sorts in-place), make a new slice.
|
||||
recOpt: metric.WithAttributeSet(attribute.NewSet(append(
|
||||
// Default to OK status code.
|
||||
[]attribute.KeyValue{semconv.RPCGRPCStatusCodeOk},
|
||||
[]attribute.KeyValue{
|
||||
semconv.RPCResponseStatusCode(codes.OK.String()),
|
||||
},
|
||||
attrs...,
|
||||
)...)),
|
||||
}
|
||||
@@ -291,8 +293,7 @@ func (i *Instrumentation) recordOption(err error, code codes.Code) metric.Record
|
||||
defer put(measureAttrsPool, attrs)
|
||||
*attrs = append(*attrs, i.attrs...)
|
||||
|
||||
c := int64(code) // uint32 -> int64.
|
||||
*attrs = append(*attrs, semconv.RPCGRPCStatusCodeKey.Int64(c))
|
||||
*attrs = append(*attrs, semconv.RPCResponseStatusCode(code.String()))
|
||||
if err != nil {
|
||||
*attrs = append(*attrs, semconv.ErrorType(err))
|
||||
}
|
||||
|
||||
Generated
Vendored
+1
-1
@@ -5,4 +5,4 @@ package internal // import "go.opentelemetry.io/otel/exporters/otlp/otlptrace/ot
|
||||
|
||||
// Version is the current release version of the OpenTelemetry OTLP gRPC trace
|
||||
// exporter in use.
|
||||
const Version = "1.39.0"
|
||||
const Version = "1.40.0"
|
||||
|
||||
+1
-1
@@ -5,5 +5,5 @@ package otlptrace // import "go.opentelemetry.io/otel/exporters/otlp/otlptrace"
|
||||
|
||||
// Version is the current release version of the OpenTelemetry OTLP trace exporter in use.
|
||||
func Version() string {
|
||||
return "1.39.0"
|
||||
return "1.40.0"
|
||||
}
|
||||
|
||||
+56
@@ -229,6 +229,13 @@ func (i *sfCounter) Add(ctx context.Context, incr float64, opts ...metric.AddOpt
|
||||
}
|
||||
}
|
||||
|
||||
func (i *sfCounter) Enabled(ctx context.Context) bool {
|
||||
if ctr := i.delegate.Load(); ctr != nil {
|
||||
return ctr.(metric.Float64Counter).Enabled(ctx)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type sfUpDownCounter struct {
|
||||
embedded.Float64UpDownCounter
|
||||
|
||||
@@ -255,6 +262,13 @@ func (i *sfUpDownCounter) Add(ctx context.Context, incr float64, opts ...metric.
|
||||
}
|
||||
}
|
||||
|
||||
func (i *sfUpDownCounter) Enabled(ctx context.Context) bool {
|
||||
if ctr := i.delegate.Load(); ctr != nil {
|
||||
return ctr.(metric.Float64UpDownCounter).Enabled(ctx)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type sfHistogram struct {
|
||||
embedded.Float64Histogram
|
||||
|
||||
@@ -281,6 +295,13 @@ func (i *sfHistogram) Record(ctx context.Context, x float64, opts ...metric.Reco
|
||||
}
|
||||
}
|
||||
|
||||
func (i *sfHistogram) Enabled(ctx context.Context) bool {
|
||||
if ctr := i.delegate.Load(); ctr != nil {
|
||||
return ctr.(metric.Float64Histogram).Enabled(ctx)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type sfGauge struct {
|
||||
embedded.Float64Gauge
|
||||
|
||||
@@ -307,6 +328,13 @@ func (i *sfGauge) Record(ctx context.Context, x float64, opts ...metric.RecordOp
|
||||
}
|
||||
}
|
||||
|
||||
func (i *sfGauge) Enabled(ctx context.Context) bool {
|
||||
if ctr := i.delegate.Load(); ctr != nil {
|
||||
return ctr.(metric.Float64Gauge).Enabled(ctx)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type siCounter struct {
|
||||
embedded.Int64Counter
|
||||
|
||||
@@ -333,6 +361,13 @@ func (i *siCounter) Add(ctx context.Context, x int64, opts ...metric.AddOption)
|
||||
}
|
||||
}
|
||||
|
||||
func (i *siCounter) Enabled(ctx context.Context) bool {
|
||||
if ctr := i.delegate.Load(); ctr != nil {
|
||||
return ctr.(metric.Int64Counter).Enabled(ctx)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type siUpDownCounter struct {
|
||||
embedded.Int64UpDownCounter
|
||||
|
||||
@@ -359,6 +394,13 @@ func (i *siUpDownCounter) Add(ctx context.Context, x int64, opts ...metric.AddOp
|
||||
}
|
||||
}
|
||||
|
||||
func (i *siUpDownCounter) Enabled(ctx context.Context) bool {
|
||||
if ctr := i.delegate.Load(); ctr != nil {
|
||||
return ctr.(metric.Int64UpDownCounter).Enabled(ctx)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type siHistogram struct {
|
||||
embedded.Int64Histogram
|
||||
|
||||
@@ -385,6 +427,13 @@ func (i *siHistogram) Record(ctx context.Context, x int64, opts ...metric.Record
|
||||
}
|
||||
}
|
||||
|
||||
func (i *siHistogram) Enabled(ctx context.Context) bool {
|
||||
if ctr := i.delegate.Load(); ctr != nil {
|
||||
return ctr.(metric.Int64Histogram).Enabled(ctx)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type siGauge struct {
|
||||
embedded.Int64Gauge
|
||||
|
||||
@@ -410,3 +459,10 @@ func (i *siGauge) Record(ctx context.Context, x int64, opts ...metric.RecordOpti
|
||||
ctr.(metric.Int64Gauge).Record(ctx, x, opts...)
|
||||
}
|
||||
}
|
||||
|
||||
func (i *siGauge) Enabled(ctx context.Context) bool {
|
||||
if ctr := i.delegate.Load(); ctr != nil {
|
||||
return ctr.(metric.Int64Gauge).Enabled(ctx)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
+14
-14
@@ -157,7 +157,7 @@ func (m *meter) Int64Counter(name string, options ...metric.Int64CounterOption)
|
||||
cfg := metric.NewInt64CounterConfig(options...)
|
||||
id := instID{
|
||||
name: name,
|
||||
kind: reflect.TypeOf((*siCounter)(nil)),
|
||||
kind: reflect.TypeFor[*siCounter](),
|
||||
description: cfg.Description(),
|
||||
unit: cfg.Unit(),
|
||||
}
|
||||
@@ -183,7 +183,7 @@ func (m *meter) Int64UpDownCounter(
|
||||
cfg := metric.NewInt64UpDownCounterConfig(options...)
|
||||
id := instID{
|
||||
name: name,
|
||||
kind: reflect.TypeOf((*siUpDownCounter)(nil)),
|
||||
kind: reflect.TypeFor[*siUpDownCounter](),
|
||||
description: cfg.Description(),
|
||||
unit: cfg.Unit(),
|
||||
}
|
||||
@@ -206,7 +206,7 @@ func (m *meter) Int64Histogram(name string, options ...metric.Int64HistogramOpti
|
||||
cfg := metric.NewInt64HistogramConfig(options...)
|
||||
id := instID{
|
||||
name: name,
|
||||
kind: reflect.TypeOf((*siHistogram)(nil)),
|
||||
kind: reflect.TypeFor[*siHistogram](),
|
||||
description: cfg.Description(),
|
||||
unit: cfg.Unit(),
|
||||
}
|
||||
@@ -229,7 +229,7 @@ func (m *meter) Int64Gauge(name string, options ...metric.Int64GaugeOption) (met
|
||||
cfg := metric.NewInt64GaugeConfig(options...)
|
||||
id := instID{
|
||||
name: name,
|
||||
kind: reflect.TypeOf((*siGauge)(nil)),
|
||||
kind: reflect.TypeFor[*siGauge](),
|
||||
description: cfg.Description(),
|
||||
unit: cfg.Unit(),
|
||||
}
|
||||
@@ -255,7 +255,7 @@ func (m *meter) Int64ObservableCounter(
|
||||
cfg := metric.NewInt64ObservableCounterConfig(options...)
|
||||
id := instID{
|
||||
name: name,
|
||||
kind: reflect.TypeOf((*aiCounter)(nil)),
|
||||
kind: reflect.TypeFor[*aiCounter](),
|
||||
description: cfg.Description(),
|
||||
unit: cfg.Unit(),
|
||||
}
|
||||
@@ -281,7 +281,7 @@ func (m *meter) Int64ObservableUpDownCounter(
|
||||
cfg := metric.NewInt64ObservableUpDownCounterConfig(options...)
|
||||
id := instID{
|
||||
name: name,
|
||||
kind: reflect.TypeOf((*aiUpDownCounter)(nil)),
|
||||
kind: reflect.TypeFor[*aiUpDownCounter](),
|
||||
description: cfg.Description(),
|
||||
unit: cfg.Unit(),
|
||||
}
|
||||
@@ -307,7 +307,7 @@ func (m *meter) Int64ObservableGauge(
|
||||
cfg := metric.NewInt64ObservableGaugeConfig(options...)
|
||||
id := instID{
|
||||
name: name,
|
||||
kind: reflect.TypeOf((*aiGauge)(nil)),
|
||||
kind: reflect.TypeFor[*aiGauge](),
|
||||
description: cfg.Description(),
|
||||
unit: cfg.Unit(),
|
||||
}
|
||||
@@ -330,7 +330,7 @@ func (m *meter) Float64Counter(name string, options ...metric.Float64CounterOpti
|
||||
cfg := metric.NewFloat64CounterConfig(options...)
|
||||
id := instID{
|
||||
name: name,
|
||||
kind: reflect.TypeOf((*sfCounter)(nil)),
|
||||
kind: reflect.TypeFor[*sfCounter](),
|
||||
description: cfg.Description(),
|
||||
unit: cfg.Unit(),
|
||||
}
|
||||
@@ -356,7 +356,7 @@ func (m *meter) Float64UpDownCounter(
|
||||
cfg := metric.NewFloat64UpDownCounterConfig(options...)
|
||||
id := instID{
|
||||
name: name,
|
||||
kind: reflect.TypeOf((*sfUpDownCounter)(nil)),
|
||||
kind: reflect.TypeFor[*sfUpDownCounter](),
|
||||
description: cfg.Description(),
|
||||
unit: cfg.Unit(),
|
||||
}
|
||||
@@ -382,7 +382,7 @@ func (m *meter) Float64Histogram(
|
||||
cfg := metric.NewFloat64HistogramConfig(options...)
|
||||
id := instID{
|
||||
name: name,
|
||||
kind: reflect.TypeOf((*sfHistogram)(nil)),
|
||||
kind: reflect.TypeFor[*sfHistogram](),
|
||||
description: cfg.Description(),
|
||||
unit: cfg.Unit(),
|
||||
}
|
||||
@@ -405,7 +405,7 @@ func (m *meter) Float64Gauge(name string, options ...metric.Float64GaugeOption)
|
||||
cfg := metric.NewFloat64GaugeConfig(options...)
|
||||
id := instID{
|
||||
name: name,
|
||||
kind: reflect.TypeOf((*sfGauge)(nil)),
|
||||
kind: reflect.TypeFor[*sfGauge](),
|
||||
description: cfg.Description(),
|
||||
unit: cfg.Unit(),
|
||||
}
|
||||
@@ -431,7 +431,7 @@ func (m *meter) Float64ObservableCounter(
|
||||
cfg := metric.NewFloat64ObservableCounterConfig(options...)
|
||||
id := instID{
|
||||
name: name,
|
||||
kind: reflect.TypeOf((*afCounter)(nil)),
|
||||
kind: reflect.TypeFor[*afCounter](),
|
||||
description: cfg.Description(),
|
||||
unit: cfg.Unit(),
|
||||
}
|
||||
@@ -457,7 +457,7 @@ func (m *meter) Float64ObservableUpDownCounter(
|
||||
cfg := metric.NewFloat64ObservableUpDownCounterConfig(options...)
|
||||
id := instID{
|
||||
name: name,
|
||||
kind: reflect.TypeOf((*afUpDownCounter)(nil)),
|
||||
kind: reflect.TypeFor[*afUpDownCounter](),
|
||||
description: cfg.Description(),
|
||||
unit: cfg.Unit(),
|
||||
}
|
||||
@@ -483,7 +483,7 @@ func (m *meter) Float64ObservableGauge(
|
||||
cfg := metric.NewFloat64ObservableGaugeConfig(options...)
|
||||
id := instID{
|
||||
name: name,
|
||||
kind: reflect.TypeOf((*afGauge)(nil)),
|
||||
kind: reflect.TypeFor[*afGauge](),
|
||||
description: cfg.Description(),
|
||||
unit: cfg.Unit(),
|
||||
}
|
||||
|
||||
+5
-1
@@ -227,7 +227,11 @@ type Float64Observer interface {
|
||||
// attributes as another Float64Callbacks also registered for the same
|
||||
// instrument.
|
||||
//
|
||||
// The function needs to be concurrent safe.
|
||||
// The function needs to be reentrant and concurrent safe.
|
||||
//
|
||||
// Note that Go's mutexes are not reentrant, and locking a mutex takes
|
||||
// an indefinite amount of time. It is therefore advised to avoid
|
||||
// using mutexes inside callbacks.
|
||||
type Float64Callback func(context.Context, Float64Observer) error
|
||||
|
||||
// Float64ObservableOption applies options to float64 Observer instruments.
|
||||
|
||||
+5
-1
@@ -225,7 +225,11 @@ type Int64Observer interface {
|
||||
// attributes as another Int64Callbacks also registered for the same
|
||||
// instrument.
|
||||
//
|
||||
// The function needs to be concurrent safe.
|
||||
// The function needs to be reentrant and concurrent safe.
|
||||
//
|
||||
// Note that Go's mutexes are not reentrant, and locking a mutex takes
|
||||
// an indefinite amount of time. It is therefore advised to avoid
|
||||
// using mutexes inside callbacks.
|
||||
type Int64Callback func(context.Context, Int64Observer) error
|
||||
|
||||
// Int64ObservableOption applies options to int64 Observer instruments.
|
||||
|
||||
+5
-1
@@ -244,7 +244,11 @@ type Meter interface {
|
||||
// Callbacks. Meaning, it should not report measurements for an instrument with
|
||||
// the same attributes as another Callback will report.
|
||||
//
|
||||
// The function needs to be concurrent safe.
|
||||
// The function needs to be reentrant and concurrent safe.
|
||||
//
|
||||
// Note that Go's mutexes are not reentrant, and locking a mutex takes
|
||||
// an indefinite amount of time. It is therefore advised to avoid
|
||||
// using mutexes inside callbacks.
|
||||
type Callback func(context.Context, Observer) error
|
||||
|
||||
// Observer records measurements for multiple instruments in a Callback.
|
||||
|
||||
+24
@@ -191,6 +191,9 @@ type Int64Counter struct{ embedded.Int64Counter }
|
||||
// Add performs no operation.
|
||||
func (Int64Counter) Add(context.Context, int64, ...metric.AddOption) {}
|
||||
|
||||
// Enabled performs no operation.
|
||||
func (Int64Counter) Enabled(context.Context) bool { return false }
|
||||
|
||||
// Float64Counter is an OpenTelemetry Counter used to record float64
|
||||
// measurements. It produces no telemetry.
|
||||
type Float64Counter struct{ embedded.Float64Counter }
|
||||
@@ -198,6 +201,9 @@ type Float64Counter struct{ embedded.Float64Counter }
|
||||
// Add performs no operation.
|
||||
func (Float64Counter) Add(context.Context, float64, ...metric.AddOption) {}
|
||||
|
||||
// Enabled performs no operation.
|
||||
func (Float64Counter) Enabled(context.Context) bool { return false }
|
||||
|
||||
// Int64UpDownCounter is an OpenTelemetry UpDownCounter used to record int64
|
||||
// measurements. It produces no telemetry.
|
||||
type Int64UpDownCounter struct{ embedded.Int64UpDownCounter }
|
||||
@@ -205,6 +211,9 @@ type Int64UpDownCounter struct{ embedded.Int64UpDownCounter }
|
||||
// Add performs no operation.
|
||||
func (Int64UpDownCounter) Add(context.Context, int64, ...metric.AddOption) {}
|
||||
|
||||
// Enabled performs no operation.
|
||||
func (Int64UpDownCounter) Enabled(context.Context) bool { return false }
|
||||
|
||||
// Float64UpDownCounter is an OpenTelemetry UpDownCounter used to record
|
||||
// float64 measurements. It produces no telemetry.
|
||||
type Float64UpDownCounter struct{ embedded.Float64UpDownCounter }
|
||||
@@ -212,6 +221,9 @@ type Float64UpDownCounter struct{ embedded.Float64UpDownCounter }
|
||||
// Add performs no operation.
|
||||
func (Float64UpDownCounter) Add(context.Context, float64, ...metric.AddOption) {}
|
||||
|
||||
// Enabled performs no operation.
|
||||
func (Float64UpDownCounter) Enabled(context.Context) bool { return false }
|
||||
|
||||
// Int64Histogram is an OpenTelemetry Histogram used to record int64
|
||||
// measurements. It produces no telemetry.
|
||||
type Int64Histogram struct{ embedded.Int64Histogram }
|
||||
@@ -219,6 +231,9 @@ type Int64Histogram struct{ embedded.Int64Histogram }
|
||||
// Record performs no operation.
|
||||
func (Int64Histogram) Record(context.Context, int64, ...metric.RecordOption) {}
|
||||
|
||||
// Enabled performs no operation.
|
||||
func (Int64Histogram) Enabled(context.Context) bool { return false }
|
||||
|
||||
// Float64Histogram is an OpenTelemetry Histogram used to record float64
|
||||
// measurements. It produces no telemetry.
|
||||
type Float64Histogram struct{ embedded.Float64Histogram }
|
||||
@@ -226,6 +241,9 @@ type Float64Histogram struct{ embedded.Float64Histogram }
|
||||
// Record performs no operation.
|
||||
func (Float64Histogram) Record(context.Context, float64, ...metric.RecordOption) {}
|
||||
|
||||
// Enabled performs no operation.
|
||||
func (Float64Histogram) Enabled(context.Context) bool { return false }
|
||||
|
||||
// Int64Gauge is an OpenTelemetry Gauge used to record instantaneous int64
|
||||
// measurements. It produces no telemetry.
|
||||
type Int64Gauge struct{ embedded.Int64Gauge }
|
||||
@@ -233,6 +251,9 @@ type Int64Gauge struct{ embedded.Int64Gauge }
|
||||
// Record performs no operation.
|
||||
func (Int64Gauge) Record(context.Context, int64, ...metric.RecordOption) {}
|
||||
|
||||
// Enabled performs no operation.
|
||||
func (Int64Gauge) Enabled(context.Context) bool { return false }
|
||||
|
||||
// Float64Gauge is an OpenTelemetry Gauge used to record instantaneous float64
|
||||
// measurements. It produces no telemetry.
|
||||
type Float64Gauge struct{ embedded.Float64Gauge }
|
||||
@@ -240,6 +261,9 @@ type Float64Gauge struct{ embedded.Float64Gauge }
|
||||
// Record performs no operation.
|
||||
func (Float64Gauge) Record(context.Context, float64, ...metric.RecordOption) {}
|
||||
|
||||
// Enabled performs no operation.
|
||||
func (Float64Gauge) Enabled(context.Context) bool { return false }
|
||||
|
||||
// Int64ObservableCounter is an OpenTelemetry ObservableCounter used to record
|
||||
// int64 measurements. It produces no telemetry.
|
||||
type Int64ObservableCounter struct {
|
||||
|
||||
+24
@@ -25,6 +25,12 @@ type Float64Counter interface {
|
||||
// Use the WithAttributeSet (or, if performance is not a concern,
|
||||
// the WithAttributes) option to include measurement attributes.
|
||||
Add(ctx context.Context, incr float64, options ...AddOption)
|
||||
|
||||
// Enabled reports whether the instrument will process measurements for the given context.
|
||||
//
|
||||
// This function can be used in places where measuring an instrument
|
||||
// would result in computationally expensive operations.
|
||||
Enabled(context.Context) bool
|
||||
}
|
||||
|
||||
// Float64CounterConfig contains options for synchronous counter instruments that
|
||||
@@ -78,6 +84,12 @@ type Float64UpDownCounter interface {
|
||||
// Use the WithAttributeSet (or, if performance is not a concern,
|
||||
// the WithAttributes) option to include measurement attributes.
|
||||
Add(ctx context.Context, incr float64, options ...AddOption)
|
||||
|
||||
// Enabled reports whether the instrument will process measurements for the given context.
|
||||
//
|
||||
// This function can be used in places where measuring an instrument
|
||||
// would result in computationally expensive operations.
|
||||
Enabled(context.Context) bool
|
||||
}
|
||||
|
||||
// Float64UpDownCounterConfig contains options for synchronous counter
|
||||
@@ -131,6 +143,12 @@ type Float64Histogram interface {
|
||||
// Use the WithAttributeSet (or, if performance is not a concern,
|
||||
// the WithAttributes) option to include measurement attributes.
|
||||
Record(ctx context.Context, incr float64, options ...RecordOption)
|
||||
|
||||
// Enabled reports whether the instrument will process measurements for the given context.
|
||||
//
|
||||
// This function can be used in places where measuring an instrument
|
||||
// would result in computationally expensive operations.
|
||||
Enabled(context.Context) bool
|
||||
}
|
||||
|
||||
// Float64HistogramConfig contains options for synchronous histogram
|
||||
@@ -189,6 +207,12 @@ type Float64Gauge interface {
|
||||
// Use the WithAttributeSet (or, if performance is not a concern,
|
||||
// the WithAttributes) option to include measurement attributes.
|
||||
Record(ctx context.Context, value float64, options ...RecordOption)
|
||||
|
||||
// Enabled reports whether the instrument will process measurements for the given context.
|
||||
//
|
||||
// This function can be used in places where measuring an instrument
|
||||
// would result in computationally expensive operations.
|
||||
Enabled(context.Context) bool
|
||||
}
|
||||
|
||||
// Float64GaugeConfig contains options for synchronous gauge instruments that
|
||||
|
||||
+24
@@ -25,6 +25,12 @@ type Int64Counter interface {
|
||||
// Use the WithAttributeSet (or, if performance is not a concern,
|
||||
// the WithAttributes) option to include measurement attributes.
|
||||
Add(ctx context.Context, incr int64, options ...AddOption)
|
||||
|
||||
// Enabled reports whether the instrument will process measurements for the given context.
|
||||
//
|
||||
// This function can be used in places where measuring an instrument
|
||||
// would result in computationally expensive operations.
|
||||
Enabled(context.Context) bool
|
||||
}
|
||||
|
||||
// Int64CounterConfig contains options for synchronous counter instruments that
|
||||
@@ -78,6 +84,12 @@ type Int64UpDownCounter interface {
|
||||
// Use the WithAttributeSet (or, if performance is not a concern,
|
||||
// the WithAttributes) option to include measurement attributes.
|
||||
Add(ctx context.Context, incr int64, options ...AddOption)
|
||||
|
||||
// Enabled reports whether the instrument will process measurements for the given context.
|
||||
//
|
||||
// This function can be used in places where measuring an instrument
|
||||
// would result in computationally expensive operations.
|
||||
Enabled(context.Context) bool
|
||||
}
|
||||
|
||||
// Int64UpDownCounterConfig contains options for synchronous counter
|
||||
@@ -131,6 +143,12 @@ type Int64Histogram interface {
|
||||
// Use the WithAttributeSet (or, if performance is not a concern,
|
||||
// the WithAttributes) option to include measurement attributes.
|
||||
Record(ctx context.Context, incr int64, options ...RecordOption)
|
||||
|
||||
// Enabled reports whether the instrument will process measurements for the given context.
|
||||
//
|
||||
// This function can be used in places where measuring an instrument
|
||||
// would result in computationally expensive operations.
|
||||
Enabled(context.Context) bool
|
||||
}
|
||||
|
||||
// Int64HistogramConfig contains options for synchronous histogram instruments
|
||||
@@ -189,6 +207,12 @@ type Int64Gauge interface {
|
||||
// Use the WithAttributeSet (or, if performance is not a concern,
|
||||
// the WithAttributes) option to include measurement attributes.
|
||||
Record(ctx context.Context, value int64, options ...RecordOption)
|
||||
|
||||
// Enabled reports whether the instrument will process measurements for the given context.
|
||||
//
|
||||
// This function can be used in places where measuring an instrument
|
||||
// would result in computationally expensive operations.
|
||||
Enabled(context.Context) bool
|
||||
}
|
||||
|
||||
// Int64GaugeConfig contains options for synchronous gauge instruments that
|
||||
|
||||
+1
-1
@@ -13,7 +13,7 @@ import (
|
||||
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/sdk"
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.37.0"
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.39.0"
|
||||
)
|
||||
|
||||
type (
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@ import (
|
||||
"os"
|
||||
"regexp"
|
||||
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.37.0"
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.39.0"
|
||||
)
|
||||
|
||||
type containerIDProvider func() (string, error)
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@ import (
|
||||
|
||||
"go.opentelemetry.io/otel"
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.37.0"
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.39.0"
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
+4
-5
@@ -8,7 +8,7 @@ import (
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.37.0"
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.39.0"
|
||||
)
|
||||
|
||||
type hostIDProvider func() (string, error)
|
||||
@@ -51,17 +51,16 @@ type hostIDReaderDarwin struct {
|
||||
execCommand commandExecutor
|
||||
}
|
||||
|
||||
// read executes `ioreg -rd1 -c "IOPlatformExpertDevice"` and parses host id
|
||||
// read executes `/usr/sbin/ioreg -rd1 -c "IOPlatformExpertDevice"` and parses host id
|
||||
// from the IOPlatformUUID line. If the command fails or the uuid cannot be
|
||||
// parsed an error will be returned.
|
||||
func (r *hostIDReaderDarwin) read() (string, error) {
|
||||
result, err := r.execCommand("ioreg", "-rd1", "-c", "IOPlatformExpertDevice")
|
||||
result, err := r.execCommand("/usr/sbin/ioreg", "-rd1", "-c", "IOPlatformExpertDevice")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
lines := strings.Split(result, "\n")
|
||||
for _, line := range lines {
|
||||
for line := range strings.SplitSeq(result, "\n") {
|
||||
if strings.Contains(line, "IOPlatformUUID") {
|
||||
parts := strings.Split(line, " = ")
|
||||
if len(parts) == 2 {
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.37.0"
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.39.0"
|
||||
)
|
||||
|
||||
type osDescriptionProvider func() (string, error)
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@ import (
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.37.0"
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.39.0"
|
||||
)
|
||||
|
||||
type (
|
||||
|
||||
Generated
Vendored
+2
-2
@@ -13,8 +13,8 @@ import (
|
||||
"go.opentelemetry.io/otel/metric"
|
||||
"go.opentelemetry.io/otel/sdk"
|
||||
"go.opentelemetry.io/otel/sdk/internal/x"
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.37.0"
|
||||
"go.opentelemetry.io/otel/semconv/v1.37.0/otelconv"
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.39.0"
|
||||
"go.opentelemetry.io/otel/semconv/v1.39.0/otelconv"
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
Generated
Vendored
+2
-2
@@ -13,8 +13,8 @@ import (
|
||||
"go.opentelemetry.io/otel/metric"
|
||||
"go.opentelemetry.io/otel/sdk"
|
||||
"go.opentelemetry.io/otel/sdk/internal/x"
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.37.0"
|
||||
"go.opentelemetry.io/otel/semconv/v1.37.0/otelconv"
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.39.0"
|
||||
"go.opentelemetry.io/otel/semconv/v1.39.0/otelconv"
|
||||
)
|
||||
|
||||
var measureAttrsPool = sync.Pool{
|
||||
|
||||
+1
-1
@@ -13,7 +13,7 @@ import (
|
||||
"go.opentelemetry.io/otel/metric"
|
||||
"go.opentelemetry.io/otel/sdk"
|
||||
"go.opentelemetry.io/otel/sdk/internal/x"
|
||||
"go.opentelemetry.io/otel/semconv/v1.37.0/otelconv"
|
||||
"go.opentelemetry.io/otel/semconv/v1.39.0/otelconv"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
)
|
||||
|
||||
|
||||
+28
@@ -280,3 +280,31 @@ func (pb parentBased) Description() string {
|
||||
pb.config.localParentNotSampled.Description(),
|
||||
)
|
||||
}
|
||||
|
||||
// AlwaysRecord returns a sampler decorator which ensures that every span
|
||||
// is passed to the SpanProcessor, even those that would be normally dropped.
|
||||
// It converts `Drop` decisions from the root sampler into `RecordOnly` decisions,
|
||||
// allowing processors to see all spans without sending them to exporters. This is
|
||||
// typically used to enable accurate span-to-metrics processing.
|
||||
func AlwaysRecord(root Sampler) Sampler {
|
||||
return alwaysRecord{root}
|
||||
}
|
||||
|
||||
type alwaysRecord struct {
|
||||
root Sampler
|
||||
}
|
||||
|
||||
func (ar alwaysRecord) ShouldSample(p SamplingParameters) SamplingResult {
|
||||
rootSamplerSamplingResult := ar.root.ShouldSample(p)
|
||||
if rootSamplerSamplingResult.Decision == Drop {
|
||||
return SamplingResult{
|
||||
Decision: RecordOnly,
|
||||
Tracestate: trace.SpanContextFromContext(p.ParentContext).TraceState(),
|
||||
}
|
||||
}
|
||||
return rootSamplerSamplingResult
|
||||
}
|
||||
|
||||
func (ar alwaysRecord) Description() string {
|
||||
return "AlwaysRecord{root:" + ar.root.Description() + "}"
|
||||
}
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@ import (
|
||||
"go.opentelemetry.io/otel/internal/global"
|
||||
"go.opentelemetry.io/otel/sdk/instrumentation"
|
||||
"go.opentelemetry.io/otel/sdk/resource"
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.37.0"
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.39.0"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
"go.opentelemetry.io/otel/trace/embedded"
|
||||
)
|
||||
|
||||
+1
-1
@@ -6,5 +6,5 @@ package sdk // import "go.opentelemetry.io/otel/sdk"
|
||||
|
||||
// Version is the current release version of the OpenTelemetry SDK in use.
|
||||
func Version() string {
|
||||
return "1.39.0"
|
||||
return "1.40.0"
|
||||
}
|
||||
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
<!-- Generated. DO NOT MODIFY. -->
|
||||
# Migration from v1.38.0 to v1.39.0
|
||||
|
||||
The `go.opentelemetry.io/otel/semconv/v1.39.0` package should be a drop-in replacement for `go.opentelemetry.io/otel/semconv/v1.38.0` with the following exceptions.
|
||||
|
||||
## Removed
|
||||
|
||||
The following declarations have been removed.
|
||||
Refer to the [OpenTelemetry Semantic Conventions documentation] for deprecation instructions.
|
||||
|
||||
If the type is not listed in the documentation as deprecated, it has been removed in this version due to lack of applicability or use.
|
||||
If you use any of these non-deprecated declarations in your Go application, please [open an issue] describing your use-case.
|
||||
|
||||
- `LinuxMemorySlabStateKey`
|
||||
- `LinuxMemorySlabStateReclaimable`
|
||||
- `LinuxMemorySlabStateUnreclaimable`
|
||||
- `PeerService`
|
||||
- `PeerServiceKey`
|
||||
- `RPCConnectRPCErrorCodeAborted`
|
||||
- `RPCConnectRPCErrorCodeAlreadyExists`
|
||||
- `RPCConnectRPCErrorCodeCancelled`
|
||||
- `RPCConnectRPCErrorCodeDataLoss`
|
||||
- `RPCConnectRPCErrorCodeDeadlineExceeded`
|
||||
- `RPCConnectRPCErrorCodeFailedPrecondition`
|
||||
- `RPCConnectRPCErrorCodeInternal`
|
||||
- `RPCConnectRPCErrorCodeInvalidArgument`
|
||||
- `RPCConnectRPCErrorCodeKey`
|
||||
- `RPCConnectRPCErrorCodeNotFound`
|
||||
- `RPCConnectRPCErrorCodeOutOfRange`
|
||||
- `RPCConnectRPCErrorCodePermissionDenied`
|
||||
- `RPCConnectRPCErrorCodeResourceExhausted`
|
||||
- `RPCConnectRPCErrorCodeUnauthenticated`
|
||||
- `RPCConnectRPCErrorCodeUnavailable`
|
||||
- `RPCConnectRPCErrorCodeUnimplemented`
|
||||
- `RPCConnectRPCErrorCodeUnknown`
|
||||
- `RPCConnectRPCRequestMetadata`
|
||||
- `RPCConnectRPCResponseMetadata`
|
||||
- `RPCGRPCRequestMetadata`
|
||||
- `RPCGRPCResponseMetadata`
|
||||
- `RPCGRPCStatusCodeAborted`
|
||||
- `RPCGRPCStatusCodeAlreadyExists`
|
||||
- `RPCGRPCStatusCodeCancelled`
|
||||
- `RPCGRPCStatusCodeDataLoss`
|
||||
- `RPCGRPCStatusCodeDeadlineExceeded`
|
||||
- `RPCGRPCStatusCodeFailedPrecondition`
|
||||
- `RPCGRPCStatusCodeInternal`
|
||||
- `RPCGRPCStatusCodeInvalidArgument`
|
||||
- `RPCGRPCStatusCodeKey`
|
||||
- `RPCGRPCStatusCodeNotFound`
|
||||
- `RPCGRPCStatusCodeOk`
|
||||
- `RPCGRPCStatusCodeOutOfRange`
|
||||
- `RPCGRPCStatusCodePermissionDenied`
|
||||
- `RPCGRPCStatusCodeResourceExhausted`
|
||||
- `RPCGRPCStatusCodeUnauthenticated`
|
||||
- `RPCGRPCStatusCodeUnavailable`
|
||||
- `RPCGRPCStatusCodeUnimplemented`
|
||||
- `RPCGRPCStatusCodeUnknown`
|
||||
- `RPCJSONRPCErrorCode`
|
||||
- `RPCJSONRPCErrorCodeKey`
|
||||
- `RPCJSONRPCErrorMessage`
|
||||
- `RPCJSONRPCErrorMessageKey`
|
||||
- `RPCJSONRPCRequestID`
|
||||
- `RPCJSONRPCRequestIDKey`
|
||||
- `RPCJSONRPCVersion`
|
||||
- `RPCJSONRPCVersionKey`
|
||||
- `RPCService`
|
||||
- `RPCServiceKey`
|
||||
- `RPCSystemApacheDubbo`
|
||||
- `RPCSystemConnectRPC`
|
||||
- `RPCSystemDotnetWcf`
|
||||
- `RPCSystemGRPC`
|
||||
- `RPCSystemJSONRPC`
|
||||
- `RPCSystemJavaRmi`
|
||||
- `RPCSystemKey`
|
||||
- `RPCSystemOncRPC`
|
||||
|
||||
[OpenTelemetry Semantic Conventions documentation]: https://github.com/open-telemetry/semantic-conventions
|
||||
[open an issue]: https://github.com/open-telemetry/opentelemetry-go/issues/new?template=Blank+issue
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
# Semconv v1.39.0
|
||||
|
||||
[](https://pkg.go.dev/go.opentelemetry.io/otel/semconv/v1.39.0)
|
||||
+16239
File diff suppressed because it is too large
Load Diff
+9
@@ -0,0 +1,9 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package semconv implements OpenTelemetry semantic conventions.
|
||||
//
|
||||
// OpenTelemetry semantic conventions are agreed standardized naming
|
||||
// patterns for OpenTelemetry things. This package represents the v1.39.0
|
||||
// version of the OpenTelemetry semantic conventions.
|
||||
package semconv // import "go.opentelemetry.io/otel/semconv/v1.39.0"
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package semconv // import "go.opentelemetry.io/otel/semconv/v1.39.0"
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
)
|
||||
|
||||
// ErrorType returns an [attribute.KeyValue] identifying the error type of err.
|
||||
//
|
||||
// If err is nil, the returned attribute has the default value
|
||||
// [ErrorTypeOther].
|
||||
//
|
||||
// If err's type has the method
|
||||
//
|
||||
// ErrorType() string
|
||||
//
|
||||
// then the returned attribute has the value of err.ErrorType(). Otherwise, the
|
||||
// returned attribute has a value derived from the concrete type of err.
|
||||
//
|
||||
// The key of the returned attribute is [ErrorTypeKey].
|
||||
func ErrorType(err error) attribute.KeyValue {
|
||||
if err == nil {
|
||||
return ErrorTypeOther
|
||||
}
|
||||
|
||||
return ErrorTypeKey.String(errorType(err))
|
||||
}
|
||||
|
||||
func errorType(err error) string {
|
||||
var s string
|
||||
if et, ok := err.(interface{ ErrorType() string }); ok {
|
||||
// Prioritize the ErrorType method if available.
|
||||
s = et.ErrorType()
|
||||
}
|
||||
if s == "" {
|
||||
// Fallback to reflection if the ErrorType method is not supported or
|
||||
// returns an empty value.
|
||||
|
||||
t := reflect.TypeOf(err)
|
||||
pkg, name := t.PkgPath(), t.Name()
|
||||
if pkg != "" && name != "" {
|
||||
s = pkg + "." + name
|
||||
} else {
|
||||
// The type has no package path or name (predeclared, not-defined,
|
||||
// or alias for a not-defined type).
|
||||
//
|
||||
// This is not guaranteed to be unique, but is a best effort.
|
||||
s = t.String()
|
||||
}
|
||||
}
|
||||
return s
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package semconv // import "go.opentelemetry.io/otel/semconv/v1.39.0"
|
||||
|
||||
const (
|
||||
// ExceptionEventName is the name of the Span event representing an exception.
|
||||
ExceptionEventName = "exception"
|
||||
)
|
||||
+2222
File diff suppressed because it is too large
Load Diff
+9
@@ -0,0 +1,9 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package semconv // import "go.opentelemetry.io/otel/semconv/v1.39.0"
|
||||
|
||||
// SchemaURL is the schema URL that matches the version of the semantic conventions
|
||||
// that this package defines. Semconv packages starting from v1.4.0 must declare
|
||||
// non-empty schema URL in the form https://opentelemetry.io/schemas/<version>
|
||||
const SchemaURL = "https://opentelemetry.io/schemas/1.39.0"
|
||||
+1
-1
@@ -20,7 +20,7 @@ import (
|
||||
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/codes"
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.37.0"
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.39.0"
|
||||
"go.opentelemetry.io/otel/trace/embedded"
|
||||
"go.opentelemetry.io/otel/trace/internal/telemetry"
|
||||
)
|
||||
|
||||
+1
-1
@@ -5,5 +5,5 @@ package otel // import "go.opentelemetry.io/otel"
|
||||
|
||||
// Version is the current release version of OpenTelemetry in use.
|
||||
func Version() string {
|
||||
return "1.39.0"
|
||||
return "1.40.0"
|
||||
}
|
||||
|
||||
+6
-3
@@ -3,7 +3,7 @@
|
||||
|
||||
module-sets:
|
||||
stable-v1:
|
||||
version: v1.39.0
|
||||
version: v1.40.0
|
||||
modules:
|
||||
- go.opentelemetry.io/otel
|
||||
- go.opentelemetry.io/otel/bridge/opencensus
|
||||
@@ -22,11 +22,11 @@ module-sets:
|
||||
- go.opentelemetry.io/otel/sdk/metric
|
||||
- go.opentelemetry.io/otel/trace
|
||||
experimental-metrics:
|
||||
version: v0.61.0
|
||||
version: v0.62.0
|
||||
modules:
|
||||
- go.opentelemetry.io/otel/exporters/prometheus
|
||||
experimental-logs:
|
||||
version: v0.15.0
|
||||
version: v0.16.0
|
||||
modules:
|
||||
- go.opentelemetry.io/otel/log
|
||||
- go.opentelemetry.io/otel/log/logtest
|
||||
@@ -46,6 +46,9 @@ modules:
|
||||
go.opentelemetry.io/otel/exporters/stdout/stdouttrace:
|
||||
version-refs:
|
||||
- ./internal/version.go
|
||||
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric:
|
||||
version-refs:
|
||||
- ./internal/version.go
|
||||
go.opentelemetry.io/otel/exporters/prometheus:
|
||||
version-refs:
|
||||
- ./internal/version.go
|
||||
|
||||
+10
@@ -453,6 +453,9 @@ func (c Cursor) FindNode(n ast.Node) (Cursor, bool) {
|
||||
// rooted at c such that n.Pos() <= start && end <= n.End().
|
||||
// (For an *ast.File, it uses the bounds n.FileStart-n.FileEnd.)
|
||||
//
|
||||
// An empty range (start == end) between two adjacent nodes is
|
||||
// considered to belong to the first node.
|
||||
//
|
||||
// It returns zero if none is found.
|
||||
// Precondition: start <= end.
|
||||
//
|
||||
@@ -501,10 +504,17 @@ func (c Cursor) FindByPos(start, end token.Pos) (Cursor, bool) {
|
||||
break // disjoint, after; stop
|
||||
}
|
||||
}
|
||||
|
||||
// Inv: node.{Pos,FileStart} <= start
|
||||
if end <= nodeEnd {
|
||||
// node fully contains target range
|
||||
best = i
|
||||
|
||||
// Don't search beyond end of the first match.
|
||||
// This is important only for an empty range (start=end)
|
||||
// between two adjoining nodes, which would otherwise
|
||||
// match both nodes; we want to match only the first.
|
||||
limit = ev.index
|
||||
} else if nodeEnd < start {
|
||||
i = ev.index // disjoint, before; skip forward
|
||||
}
|
||||
|
||||
+8
-3
@@ -10,7 +10,6 @@ import (
|
||||
"encoding/csv"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
@@ -107,14 +106,14 @@ var IndexDir string = func() string {
|
||||
var err error
|
||||
dir, err = os.UserCacheDir()
|
||||
// shouldn't happen, but TempDir is better than
|
||||
// creating ./go/imports
|
||||
// creating ./goimports
|
||||
if err != nil {
|
||||
dir = os.TempDir()
|
||||
}
|
||||
}
|
||||
dir = filepath.Join(dir, "goimports")
|
||||
if err := os.MkdirAll(dir, 0777); err != nil {
|
||||
log.Printf("failed to create modcache index dir: %v", err)
|
||||
dir = "" // #75505, people complain about the error message
|
||||
}
|
||||
return dir
|
||||
}()
|
||||
@@ -127,6 +126,9 @@ func Read(gomodcache string) (*Index, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if IndexDir == "" {
|
||||
return nil, os.ErrNotExist
|
||||
}
|
||||
|
||||
// Read the "link" file for the specified gomodcache directory.
|
||||
// It names the payload file.
|
||||
@@ -227,6 +229,9 @@ func readIndexFrom(gomodcache string, r io.Reader) (*Index, error) {
|
||||
|
||||
// write writes the index file and updates the index directory to refer to it.
|
||||
func write(gomodcache string, ix *Index) error {
|
||||
if IndexDir == "" {
|
||||
return os.ErrNotExist
|
||||
}
|
||||
// Write the index into a payload file with a fresh name.
|
||||
f, err := os.CreateTemp(IndexDir, fmt.Sprintf("index-%d-*", CurrentVersion))
|
||||
if err != nil {
|
||||
|
||||
+316
-314
@@ -12,364 +12,366 @@ type pkginfo struct {
|
||||
}
|
||||
|
||||
var deps = [...]pkginfo{
|
||||
{"archive/tar", "\x03p\x03F=\x01\n\x01$\x01\x01\x02\x05\b\x02\x01\x02\x02\f"},
|
||||
{"archive/zip", "\x02\x04f\a\x03\x13\x021=\x01+\x05\x01\x0f\x03\x02\x0e\x04"},
|
||||
{"bufio", "\x03p\x86\x01D\x14"},
|
||||
{"bytes", "s+[\x03\fG\x02\x02"},
|
||||
{"archive/tar", "\x03q\x03F=\x01\n\x01$\x01\x01\x02\x05\b\x02\x01\x02\x02\r"},
|
||||
{"archive/zip", "\x02\x04g\a\x03\x13\x021=\x01+\x05\x01\x0f\x03\x02\x0f\x04"},
|
||||
{"bufio", "\x03q\x86\x01D\x15"},
|
||||
{"bytes", "t+[\x03\fH\x02\x02"},
|
||||
{"cmp", ""},
|
||||
{"compress/bzip2", "\x02\x02\xf5\x01A"},
|
||||
{"compress/flate", "\x02q\x03\x83\x01\f\x033\x01\x03"},
|
||||
{"compress/gzip", "\x02\x04f\a\x03\x15nT"},
|
||||
{"compress/lzw", "\x02q\x03\x83\x01"},
|
||||
{"compress/zlib", "\x02\x04f\a\x03\x13\x01o"},
|
||||
{"container/heap", "\xbb\x02"},
|
||||
{"compress/bzip2", "\x02\x02\xf6\x01A"},
|
||||
{"compress/flate", "\x02r\x03\x83\x01\f\x033\x01\x03"},
|
||||
{"compress/gzip", "\x02\x04g\a\x03\x15nU"},
|
||||
{"compress/lzw", "\x02r\x03\x83\x01"},
|
||||
{"compress/zlib", "\x02\x04g\a\x03\x13\x01o"},
|
||||
{"container/heap", "\xbc\x02"},
|
||||
{"container/list", ""},
|
||||
{"container/ring", ""},
|
||||
{"context", "s\\p\x01\r"},
|
||||
{"crypto", "\x89\x01pC"},
|
||||
{"crypto/aes", "\x10\n\t\x99\x02"},
|
||||
{"crypto/cipher", "\x03 \x01\x01 \x12\x1c,Z"},
|
||||
{"crypto/des", "\x10\x15 .,\x9d\x01\x03"},
|
||||
{"crypto/dsa", "E\x04*\x86\x01\r"},
|
||||
{"crypto/ecdh", "\x03\v\f\x10\x04\x17\x04\x0e\x1c\x86\x01"},
|
||||
{"crypto/ecdsa", "\x0e\x05\x03\x04\x01\x10\b\v\x06\x01\x04\r\x01\x1c\x86\x01\r\x05K\x01"},
|
||||
{"crypto/ed25519", "\x0e\x1e\x12\a\v\a\x1c\x86\x01C"},
|
||||
{"crypto/elliptic", "3@\x86\x01\r9"},
|
||||
{"crypto/fips140", "\"\x05"},
|
||||
{"crypto/hkdf", "/\x15\x01.\x16"},
|
||||
{"crypto/hmac", "\x1a\x16\x14\x01\x122"},
|
||||
{"crypto/internal/boring", "\x0e\x02\rl"},
|
||||
{"crypto/internal/boring/bbig", "\x1a\xec\x01M"},
|
||||
{"crypto/internal/boring/bcache", "\xc0\x02\x13"},
|
||||
{"context", "t\\p\x01\x0e"},
|
||||
{"crypto", "\x8a\x01pC"},
|
||||
{"crypto/aes", "\x10\v\t\x99\x02"},
|
||||
{"crypto/cipher", "\x03!\x01\x01 \x12\x1c,Z"},
|
||||
{"crypto/des", "\x10\x16 .,\x9d\x01\x03"},
|
||||
{"crypto/dsa", "F\x03+\x86\x01\r"},
|
||||
{"crypto/ecdh", "\x03\v\r\x10\x04\x17\x03\x0f\x1c\x86\x01"},
|
||||
{"crypto/ecdsa", "\x0e\x05\x03\x05\x01\x10\b\v\x06\x01\x03\x0e\x01\x1c\x86\x01\r\x05L\x01"},
|
||||
{"crypto/ed25519", "\x0e\x1f\x12\a\x03\b\a\x1cI=C"},
|
||||
{"crypto/elliptic", "4@\x86\x01\r9"},
|
||||
{"crypto/fips140", "#\x05\x95\x01\x98\x01"},
|
||||
{"crypto/hkdf", "0\x15\x01.\x16"},
|
||||
{"crypto/hmac", "\x1b\x16\x14\x01\x122"},
|
||||
{"crypto/hpke", "\x03\v\x02\x03\x04\x01\f\x01\x05\x1f\x05\a\x01\x01\x1d\x03\x13\x16\x9b\x01\x1c"},
|
||||
{"crypto/internal/boring", "\x0e\x02\x0el"},
|
||||
{"crypto/internal/boring/bbig", "\x1b\xec\x01N"},
|
||||
{"crypto/internal/boring/bcache", "\xc1\x02\x14"},
|
||||
{"crypto/internal/boring/sig", ""},
|
||||
{"crypto/internal/constanttime", ""},
|
||||
{"crypto/internal/cryptotest", "\x03\r\n\b&\x0f\x19\x06\x13\x12 \x04\x06\t\x19\x01\x11\x11\x1b\x01\a\x05\b\x03\x05\v"},
|
||||
{"crypto/internal/entropy", "J"},
|
||||
{"crypto/internal/entropy/v1.0.0", "C0\x95\x018\x13"},
|
||||
{"crypto/internal/fips140", "B1\xbf\x01\v\x16"},
|
||||
{"crypto/internal/fips140/aes", "\x03\x1f\x03\x02\x14\x05\x01\x01\x06+\x95\x014"},
|
||||
{"crypto/internal/fips140/aes/gcm", "\"\x01\x02\x02\x02\x12\x05\x01\a+\x92\x01"},
|
||||
{"crypto/internal/fips140/alias", "\xd3\x02"},
|
||||
{"crypto/internal/fips140/bigmod", "'\x19\x01\a+\x95\x01"},
|
||||
{"crypto/internal/fips140/check", "\"\x0e\a\t\x02\xb7\x01Z"},
|
||||
{"crypto/internal/fips140/check/checktest", "'\x8b\x02!"},
|
||||
{"crypto/internal/fips140/drbg", "\x03\x1e\x01\x01\x04\x14\x05\t\x01)\x86\x01\x0f7\x01"},
|
||||
{"crypto/internal/fips140/ecdh", "\x03\x1f\x05\x02\n\r3\x86\x01\x0f7"},
|
||||
{"crypto/internal/fips140/ecdsa", "\x03\x1f\x04\x01\x02\a\x03\x06:\x16pF"},
|
||||
{"crypto/internal/fips140/ed25519", "\x03\x1f\x05\x02\x04\f:\xc9\x01\x03"},
|
||||
{"crypto/internal/fips140/edwards25519", "\x1e\t\a\x123\x95\x017"},
|
||||
{"crypto/internal/fips140/edwards25519/field", "'\x14\x053\x95\x01"},
|
||||
{"crypto/internal/fips140/hkdf", "\x03\x1f\x05\t\a<\x16"},
|
||||
{"crypto/internal/fips140/hmac", "\x03\x1f\x15\x01\x01:\x16"},
|
||||
{"crypto/internal/fips140/mldsa", "\x03\x1b\x04\x05\x02\x0e\x01\x03\x053\x95\x017"},
|
||||
{"crypto/internal/fips140/mlkem", "\x03\x1f\x05\x02\x0f\x03\x053\xcc\x01"},
|
||||
{"crypto/internal/fips140/nistec", "\x1e\t\r\f3\x95\x01*\r\x14"},
|
||||
{"crypto/internal/fips140/nistec/fiat", "'\x148\x95\x01"},
|
||||
{"crypto/internal/fips140/pbkdf2", "\x03\x1f\x05\t\a<\x16"},
|
||||
{"crypto/internal/fips140/rsa", "\x03\x1b\x04\x04\x01\x02\x0e\x01\x01\x028\x16pF"},
|
||||
{"crypto/internal/fips140/sha256", "\x03\x1f\x1e\x01\a+\x16\x7f"},
|
||||
{"crypto/internal/fips140/sha3", "\x03\x1f\x19\x05\x012\x95\x01K"},
|
||||
{"crypto/internal/fips140/sha512", "\x03\x1f\x1e\x01\a+\x16\x7f"},
|
||||
{"crypto/internal/fips140/ssh", "'b"},
|
||||
{"crypto/internal/fips140/subtle", "\x1e\a\x1b\xc8\x01"},
|
||||
{"crypto/internal/fips140/tls12", "\x03\x1f\x05\t\a\x02:\x16"},
|
||||
{"crypto/internal/fips140/tls13", "\x03\x1f\x05\b\b\t3\x16"},
|
||||
{"crypto/internal/fips140cache", "\xb2\x02\r&"},
|
||||
{"crypto/internal/cryptotest", "\x03\r\v\b%\x10\x19\x06\x13\x12 \x04\x06\t\x19\x01\x11\x11\x1b\x01\a\x05\b\x03\x05\f"},
|
||||
{"crypto/internal/entropy", "K"},
|
||||
{"crypto/internal/entropy/v1.0.0", "D0\x95\x018\x14"},
|
||||
{"crypto/internal/fips140", "C1\xbf\x01\v\x17"},
|
||||
{"crypto/internal/fips140/aes", "\x03 \x03\x02\x14\x05\x01\x01\x05,\x95\x014"},
|
||||
{"crypto/internal/fips140/aes/gcm", "#\x01\x02\x02\x02\x12\x05\x01\x06,\x92\x01"},
|
||||
{"crypto/internal/fips140/alias", "\xd5\x02"},
|
||||
{"crypto/internal/fips140/bigmod", "(\x19\x01\x06,\x95\x01"},
|
||||
{"crypto/internal/fips140/check", "#\x0e\a\t\x02\xb7\x01["},
|
||||
{"crypto/internal/fips140/check/checktest", "(\x8b\x02\""},
|
||||
{"crypto/internal/fips140/drbg", "\x03\x1f\x01\x01\x04\x14\x05\n)\x86\x01\x0f7\x01"},
|
||||
{"crypto/internal/fips140/ecdh", "\x03 \x05\x02\n\r3\x86\x01\x0f7"},
|
||||
{"crypto/internal/fips140/ecdsa", "\x03 \x04\x01\x02\a\x03\x06:\x16pF"},
|
||||
{"crypto/internal/fips140/ed25519", "\x03 \x05\x02\x04\f:\xc9\x01\x03"},
|
||||
{"crypto/internal/fips140/edwards25519", "\x1f\t\a\x123\x95\x017"},
|
||||
{"crypto/internal/fips140/edwards25519/field", "(\x14\x053\x95\x01"},
|
||||
{"crypto/internal/fips140/hkdf", "\x03 \x05\t\a<\x16"},
|
||||
{"crypto/internal/fips140/hmac", "\x03 \x15\x01\x01:\x16"},
|
||||
{"crypto/internal/fips140/mldsa", "\x03\x1c\x04\x05\x02\x0e\x01\x03\x053\x95\x017"},
|
||||
{"crypto/internal/fips140/mlkem", "\x03 \x05\x02\x0f\x03\x053\xcc\x01"},
|
||||
{"crypto/internal/fips140/nistec", "\x1f\t\r\f3\x95\x01*\r\x15"},
|
||||
{"crypto/internal/fips140/nistec/fiat", "(\x148\x95\x01"},
|
||||
{"crypto/internal/fips140/pbkdf2", "\x03 \x05\t\a<\x16"},
|
||||
{"crypto/internal/fips140/rsa", "\x03\x1c\x04\x04\x01\x02\x0e\x01\x01\x028\x16pF"},
|
||||
{"crypto/internal/fips140/sha256", "\x03 \x1e\x01\x06,\x16\x7f"},
|
||||
{"crypto/internal/fips140/sha3", "\x03 \x19\x05\x012\x95\x01L"},
|
||||
{"crypto/internal/fips140/sha512", "\x03 \x1e\x01\x06,\x16\x7f"},
|
||||
{"crypto/internal/fips140/ssh", "(b"},
|
||||
{"crypto/internal/fips140/subtle", "\x1f\a\x1b\xc8\x01"},
|
||||
{"crypto/internal/fips140/tls12", "\x03 \x05\t\a\x02:\x16"},
|
||||
{"crypto/internal/fips140/tls13", "\x03 \x05\b\b\t3\x16"},
|
||||
{"crypto/internal/fips140cache", "\xb3\x02\r'"},
|
||||
{"crypto/internal/fips140deps", ""},
|
||||
{"crypto/internal/fips140deps/byteorder", "\x9f\x01"},
|
||||
{"crypto/internal/fips140deps/cpu", "\xb4\x01\a"},
|
||||
{"crypto/internal/fips140deps/godebug", "\xbc\x01"},
|
||||
{"crypto/internal/fips140deps/time", "\xcd\x02"},
|
||||
{"crypto/internal/fips140hash", "8\x1d4\xca\x01"},
|
||||
{"crypto/internal/fips140only", ")\x0e\x01\x01P3="},
|
||||
{"crypto/internal/fips140deps/byteorder", "\xa0\x01"},
|
||||
{"crypto/internal/fips140deps/cpu", "\xb5\x01\a"},
|
||||
{"crypto/internal/fips140deps/godebug", "\xbd\x01"},
|
||||
{"crypto/internal/fips140deps/time", "\xcf\x02"},
|
||||
{"crypto/internal/fips140hash", "9\x1d4\xcb\x01"},
|
||||
{"crypto/internal/fips140only", "\x17\x13\x0e\x01\x01Pp"},
|
||||
{"crypto/internal/fips140test", ""},
|
||||
{"crypto/internal/hpke", "\x03\v\x01\x01\x03\x055\x03\x04\x01\x01\x16\a\x03\x13\xcc\x01"},
|
||||
{"crypto/internal/impl", "\xbd\x02"},
|
||||
{"crypto/internal/randutil", "\xf9\x01\x12"},
|
||||
{"crypto/internal/sysrand", "sq! \r\r\x01\x01\f\x06"},
|
||||
{"crypto/internal/sysrand/internal/seccomp", "s"},
|
||||
{"crypto/md5", "\x0e7.\x16\x16i"},
|
||||
{"crypto/mlkem", "\x0e$"},
|
||||
{"crypto/mlkem/mlkemtest", "2\x1b&"},
|
||||
{"crypto/pbkdf2", "5\x0f\x01.\x16"},
|
||||
{"crypto/rand", "\x1a\b\a\x1c\x04\x01)\x86\x01\rM"},
|
||||
{"crypto/rc4", "% .\xc9\x01"},
|
||||
{"crypto/rsa", "\x0e\f\x01\v\x10\x0e\x01\x04\a\a\x1c\x03\x133=\f\x01"},
|
||||
{"crypto/sha1", "\x0e\f+\x03+\x16\x16\x15T"},
|
||||
{"crypto/sha256", "\x0e\f\x1dR"},
|
||||
{"crypto/sha3", "\x0e*Q\xca\x01"},
|
||||
{"crypto/sha512", "\x0e\f\x1fP"},
|
||||
{"crypto/subtle", "\x1e\x1d\x9f\x01X"},
|
||||
{"crypto/tls", "\x03\b\x02\x01\x01\x01\x01\x02\x01\x01\x01\x02\x01\x01\t\x01\x0e\n\x01\n\x05\x04\x01\x01\x01\x01\x02\x01\x02\x01\x17\x02\x03\x13\x16\x15\b=\x16\x16\r\b\x01\x01\x01\x02\x01\r\x06\x02\x01\x0f"},
|
||||
{"crypto/tls/internal/fips140tls", "\x17\xa9\x02"},
|
||||
{"crypto/x509", "\x03\v\x01\x01\x01\x01\x01\x01\x01\x016\x06\x01\x01\x02\x05\x0e\x06\x02\x02\x03F\x03:\x01\x02\b\x01\x01\x02\a\x10\x05\x01\x06\a\b\x02\x01\x02\x0e\x02\x01\x01\x02\x03\x01"},
|
||||
{"crypto/x509/pkix", "i\x06\a\x90\x01G"},
|
||||
{"database/sql", "\x03\nP\x16\x03\x83\x01\v\a\"\x05\b\x02\x03\x01\r\x02\x02\x02"},
|
||||
{"database/sql/driver", "\rf\x03\xb7\x01\x0f\x11"},
|
||||
{"debug/buildinfo", "\x03]\x02\x01\x01\b\a\x03g\x1a\x02\x01+\x0f\x1f"},
|
||||
{"debug/dwarf", "\x03i\a\x03\x83\x011\x11\x01\x01"},
|
||||
{"debug/elf", "\x03\x06V\r\a\x03g\x1b\x01\f \x17\x01\x16"},
|
||||
{"debug/gosym", "\x03i\n\xc5\x01\x01\x01\x02"},
|
||||
{"debug/macho", "\x03\x06V\r\ng\x1c,\x17\x01"},
|
||||
{"debug/pe", "\x03\x06V\r\a\x03g\x1c,\x17\x01\x16"},
|
||||
{"debug/plan9obj", "l\a\x03g\x1c,"},
|
||||
{"embed", "s+B\x19\x01S"},
|
||||
{"crypto/internal/impl", "\xbe\x02"},
|
||||
{"crypto/internal/rand", "\x1b\x0f s=["},
|
||||
{"crypto/internal/randutil", "\xfa\x01\x12"},
|
||||
{"crypto/internal/sysrand", "tq! \r\r\x01\x01\r\x06"},
|
||||
{"crypto/internal/sysrand/internal/seccomp", "t"},
|
||||
{"crypto/md5", "\x0e8.\x16\x16i"},
|
||||
{"crypto/mlkem", "\x0e%"},
|
||||
{"crypto/mlkem/mlkemtest", "3\x13\b&"},
|
||||
{"crypto/pbkdf2", "6\x0f\x01.\x16"},
|
||||
{"crypto/rand", "\x1b\x0f\x1c\x03+\x86\x01\rN"},
|
||||
{"crypto/rc4", "& .\xc9\x01"},
|
||||
{"crypto/rsa", "\x0e\r\x01\v\x10\x0e\x01\x03\b\a\x1c\x03\x133=\f\x01"},
|
||||
{"crypto/sha1", "\x0e\r+\x02,\x16\x16\x15T"},
|
||||
{"crypto/sha256", "\x0e\r\x1dR"},
|
||||
{"crypto/sha3", "\x0e+Q\xcb\x01"},
|
||||
{"crypto/sha512", "\x0e\r\x1fP"},
|
||||
{"crypto/subtle", "\x1f\x1d\x9f\x01z"},
|
||||
{"crypto/tls", "\x03\b\x02\x01\x01\x01\x01\x02\x01\x01\x01\x02\x01\x01\x01\t\x01\x18\x01\x0f\x01\x03\x01\x01\x01\x01\x02\x01\x02\x01\x17\x02\x03\x13\x16\x15\b=\x16\x16\r\b\x01\x01\x01\x02\x01\x0e\x06\x02\x01\x0f"},
|
||||
{"crypto/tls/internal/fips140tls", "\x17\xaa\x02"},
|
||||
{"crypto/x509", "\x03\v\x01\x01\x01\x01\x01\x01\x01\x017\x06\x01\x01\x02\x05\x0e\x06\x02\x02\x03F\x03:\x01\x02\b\x01\x01\x02\a\x10\x05\x01\x06\a\b\x02\x01\x02\x0f\x02\x01\x01\x02\x03\x01"},
|
||||
{"crypto/x509/pkix", "j\x06\a\x90\x01H"},
|
||||
{"database/sql", "\x03\nQ\x16\x03\x83\x01\v\a\"\x05\b\x02\x03\x01\x0e\x02\x02\x02"},
|
||||
{"database/sql/driver", "\rg\x03\xb7\x01\x0f\x12"},
|
||||
{"debug/buildinfo", "\x03^\x02\x01\x01\b\a\x03g\x1a\x02\x01+\x0f "},
|
||||
{"debug/dwarf", "\x03j\a\x03\x83\x011\x11\x01\x01"},
|
||||
{"debug/elf", "\x03\x06W\r\a\x03g\x1b\x01\f \x17\x01\x17"},
|
||||
{"debug/gosym", "\x03j\n$\xa1\x01\x01\x01\x02"},
|
||||
{"debug/macho", "\x03\x06W\r\ng\x1c,\x17\x01"},
|
||||
{"debug/pe", "\x03\x06W\r\a\x03g\x1c,\x17\x01\x17"},
|
||||
{"debug/plan9obj", "m\a\x03g\x1c,"},
|
||||
{"embed", "t+B\x19\x01T"},
|
||||
{"embed/internal/embedtest", ""},
|
||||
{"encoding", ""},
|
||||
{"encoding/ascii85", "\xf9\x01C"},
|
||||
{"encoding/asn1", "\x03p\x03g(\x01'\r\x02\x01\x10\x03\x01"},
|
||||
{"encoding/base32", "\xf9\x01A\x02"},
|
||||
{"encoding/base64", "\x9f\x01ZA\x02"},
|
||||
{"encoding/binary", "s\x86\x01\f(\r\x05"},
|
||||
{"encoding/csv", "\x02\x01p\x03\x83\x01D\x12\x02"},
|
||||
{"encoding/gob", "\x02e\x05\a\x03g\x1c\v\x01\x03\x1d\b\x12\x01\x0f\x02"},
|
||||
{"encoding/hex", "s\x03\x83\x01A\x03"},
|
||||
{"encoding/json", "\x03\x01c\x04\b\x03\x83\x01\f(\r\x02\x01\x02\x10\x01\x01\x02"},
|
||||
{"encoding/pem", "\x03h\b\x86\x01A\x03"},
|
||||
{"encoding/xml", "\x02\x01d\f\x03\x83\x014\x05\n\x01\x02\x10\x02"},
|
||||
{"errors", "\xcf\x01\x84\x01"},
|
||||
{"expvar", "pLA\b\v\x15\r\b\x02\x03\x01\x11"},
|
||||
{"flag", "g\f\x03\x83\x01,\b\x05\b\x02\x01\x10"},
|
||||
{"fmt", "sF'\x19\f \b\r\x02\x03\x12"},
|
||||
{"go/ast", "\x03\x01r\x0f\x01s\x03)\b\r\x02\x01\x12\x02"},
|
||||
{"go/build", "\x02\x01p\x03\x01\x02\x02\b\x02\x01\x17\x1f\x04\x02\b\x1c\x13\x01+\x01\x04\x01\a\b\x02\x01\x12\x02\x02"},
|
||||
{"go/build/constraint", "s\xc9\x01\x01\x12\x02"},
|
||||
{"go/constant", "v\x10\x7f\x01\x024\x01\x02\x12"},
|
||||
{"go/doc", "\x04r\x01\x05\n=61\x10\x02\x01\x12\x02"},
|
||||
{"go/doc/comment", "\x03s\xc4\x01\x01\x01\x01\x12\x02"},
|
||||
{"go/format", "\x03s\x01\f\x01\x02sD"},
|
||||
{"go/importer", "x\a\x01\x02\x04\x01r9"},
|
||||
{"go/internal/gccgoimporter", "\x02\x01]\x13\x03\x04\f\x01p\x02,\x01\x05\x11\x01\f\b"},
|
||||
{"go/internal/gcimporter", "\x02t\x10\x010\x05\r0,\x15\x03\x02"},
|
||||
{"go/internal/scannerhooks", "\x86\x01"},
|
||||
{"go/internal/srcimporter", "v\x01\x01\v\x03\x01r,\x01\x05\x12\x02\x14"},
|
||||
{"go/parser", "\x03p\x03\x01\x02\b\x04\x01s\x01+\x06\x12"},
|
||||
{"go/printer", "v\x01\x02\x03\ns\f \x15\x02\x01\x02\v\x05\x02"},
|
||||
{"go/scanner", "\x03s\v\x05s2\x10\x01\x13\x02"},
|
||||
{"go/token", "\x04r\x86\x01>\x02\x03\x01\x0f\x02"},
|
||||
{"go/types", "\x03\x01\x06i\x03\x01\x03\t\x03\x024\x063\x04\x03\t \x06\a\b\x01\x01\x01\x02\x01\x0f\x02\x02"},
|
||||
{"go/version", "\xc1\x01|"},
|
||||
{"hash", "\xf9\x01"},
|
||||
{"hash/adler32", "s\x16\x16"},
|
||||
{"hash/crc32", "s\x16\x16\x15\x8b\x01\x01\x13"},
|
||||
{"hash/crc64", "s\x16\x16\xa0\x01"},
|
||||
{"hash/fnv", "s\x16\x16i"},
|
||||
{"hash/maphash", "\x89\x01\x11<}"},
|
||||
{"html", "\xbd\x02\x02\x12"},
|
||||
{"html/template", "\x03m\x06\x19-=\x01\n!\x05\x01\x02\x03\f\x01\x02\f\x01\x03\x02"},
|
||||
{"image", "\x02q\x1fg\x0f4\x03\x01"},
|
||||
{"encoding/ascii85", "\xfa\x01C"},
|
||||
{"encoding/asn1", "\x03q\x03g(\x01'\r\x02\x01\x11\x03\x01"},
|
||||
{"encoding/base32", "\xfa\x01A\x02"},
|
||||
{"encoding/base64", "\xa0\x01ZA\x02"},
|
||||
{"encoding/binary", "t\x86\x01\f(\r\x05"},
|
||||
{"encoding/csv", "\x02\x01q\x03\x83\x01D\x13\x02"},
|
||||
{"encoding/gob", "\x02f\x05\a\x03g\x1c\v\x01\x03\x1d\b\x12\x01\x10\x02"},
|
||||
{"encoding/hex", "t\x03\x83\x01A\x03"},
|
||||
{"encoding/json", "\x03\x01d\x04\b\x03\x83\x01\f(\r\x02\x01\x02\x11\x01\x01\x02"},
|
||||
{"encoding/pem", "\x03i\b\x86\x01A\x03"},
|
||||
{"encoding/xml", "\x02\x01e\f\x03\x83\x014\x05\n\x01\x02\x11\x02"},
|
||||
{"errors", "\xd0\x01\x85\x01"},
|
||||
{"expvar", "qLA\b\v\x15\r\b\x02\x03\x01\x12"},
|
||||
{"flag", "h\f\x03\x83\x01,\b\x05\b\x02\x01\x11"},
|
||||
{"fmt", "tF'\x19\f \b\r\x02\x03\x13"},
|
||||
{"go/ast", "\x03\x01s\x0f\x01s\x03)\b\r\x02\x01\x13\x02"},
|
||||
{"go/build", "\x02\x01q\x03\x01\x02\x02\b\x02\x01\x17\x1f\x04\x02\b\x1c\x13\x01+\x01\x04\x01\a\b\x02\x01\x13\x02\x02"},
|
||||
{"go/build/constraint", "t\xc9\x01\x01\x13\x02"},
|
||||
{"go/constant", "w\x10\x7f\x01\x024\x01\x02\x13"},
|
||||
{"go/doc", "\x04s\x01\x05\n=61\x10\x02\x01\x13\x02"},
|
||||
{"go/doc/comment", "\x03t\xc4\x01\x01\x01\x01\x13\x02"},
|
||||
{"go/format", "\x03t\x01\f\x01\x02sD"},
|
||||
{"go/importer", "y\a\x01\x02\x04\x01r9"},
|
||||
{"go/internal/gccgoimporter", "\x02\x01^\x13\x03\x04\f\x01p\x02,\x01\x05\x11\x01\r\b"},
|
||||
{"go/internal/gcimporter", "\x02u\x10\x010\x05\r0,\x15\x03\x02"},
|
||||
{"go/internal/scannerhooks", "\x87\x01"},
|
||||
{"go/internal/srcimporter", "w\x01\x01\v\x03\x01r,\x01\x05\x12\x02\x15"},
|
||||
{"go/parser", "\x03q\x03\x01\x02\b\x04\x01s\x01+\x06\x12"},
|
||||
{"go/printer", "w\x01\x02\x03\ns\f \x15\x02\x01\x02\f\x05\x02"},
|
||||
{"go/scanner", "\x03t\v\x05s2\x10\x01\x14\x02"},
|
||||
{"go/token", "\x04s\x86\x01>\x02\x03\x01\x10\x02"},
|
||||
{"go/types", "\x03\x01\x06j\x03\x01\x03\t\x03\x024\x063\x04\x03\t \x06\a\b\x01\x01\x01\x02\x01\x10\x02\x02"},
|
||||
{"go/version", "\xc2\x01|"},
|
||||
{"hash", "\xfa\x01"},
|
||||
{"hash/adler32", "t\x16\x16"},
|
||||
{"hash/crc32", "t\x16\x16\x15\x8b\x01\x01\x14"},
|
||||
{"hash/crc64", "t\x16\x16\xa0\x01"},
|
||||
{"hash/fnv", "t\x16\x16i"},
|
||||
{"hash/maphash", "\x8a\x01\x11<~"},
|
||||
{"html", "\xbe\x02\x02\x13"},
|
||||
{"html/template", "\x03n\x06\x19-=\x01\n!\x05\x01\x02\x03\f\x01\x02\r\x01\x03\x02"},
|
||||
{"image", "\x02r\x1fg\x0f4\x03\x01"},
|
||||
{"image/color", ""},
|
||||
{"image/color/palette", "\x92\x01"},
|
||||
{"image/draw", "\x91\x01\x01\x04"},
|
||||
{"image/gif", "\x02\x01\x05k\x03\x1b\x01\x01\x01\vZ\x0f"},
|
||||
{"image/internal/imageutil", "\x91\x01"},
|
||||
{"image/jpeg", "\x02q\x1e\x01\x04c"},
|
||||
{"image/png", "\x02\ac\n\x13\x02\x06\x01gC"},
|
||||
{"index/suffixarray", "\x03i\a\x86\x01\f+\n\x01"},
|
||||
{"internal/abi", "\xbb\x01\x98\x01"},
|
||||
{"internal/asan", "\xd3\x02"},
|
||||
{"internal/bisect", "\xb2\x02\r\x01"},
|
||||
{"internal/buildcfg", "vHg\x06\x02\x05\n\x01"},
|
||||
{"internal/bytealg", "\xb4\x01\x9f\x01"},
|
||||
{"image/color/palette", "\x93\x01"},
|
||||
{"image/draw", "\x92\x01\x01\x04"},
|
||||
{"image/gif", "\x02\x01\x05l\x03\x1b\x01\x01\x01\vZ\x0f"},
|
||||
{"image/internal/imageutil", "\x92\x01"},
|
||||
{"image/jpeg", "\x02r\x1e\x01\x04c"},
|
||||
{"image/png", "\x02\ad\n\x13\x02\x06\x01gC"},
|
||||
{"index/suffixarray", "\x03j\a\x86\x01\f+\n\x01"},
|
||||
{"internal/abi", "\xbc\x01\x99\x01"},
|
||||
{"internal/asan", "\xd5\x02"},
|
||||
{"internal/bisect", "\xb3\x02\r\x01"},
|
||||
{"internal/buildcfg", "wHg\x06\x02\x05\n\x01"},
|
||||
{"internal/bytealg", "\xb5\x01\xa0\x01"},
|
||||
{"internal/byteorder", ""},
|
||||
{"internal/cfg", ""},
|
||||
{"internal/cgrouptest", "v[T\x06\x0f\x02\x01\x04\x01"},
|
||||
{"internal/chacha8rand", "\x9f\x01\x15\a\x98\x01"},
|
||||
{"internal/cgrouptest", "w[T\x06\x0f\x02\x01\x04\x01"},
|
||||
{"internal/chacha8rand", "\xa0\x01\x15\a\x99\x01"},
|
||||
{"internal/copyright", ""},
|
||||
{"internal/coverage", ""},
|
||||
{"internal/coverage/calloc", ""},
|
||||
{"internal/coverage/cfile", "p\x06\x17\x17\x01\x02\x01\x01\x01\x01\x01\x01\x01\"\x02',\x06\a\n\x01\x03\r\x06"},
|
||||
{"internal/coverage/cformat", "\x04r.\x04Q\v6\x01\x02\r"},
|
||||
{"internal/coverage/cmerge", "v.a"},
|
||||
{"internal/coverage/decodecounter", "l\n.\v\x02H,\x17\x17"},
|
||||
{"internal/coverage/decodemeta", "\x02j\n\x17\x17\v\x02H,"},
|
||||
{"internal/coverage/encodecounter", "\x02j\n.\f\x01\x02F\v!\x15"},
|
||||
{"internal/coverage/encodemeta", "\x02\x01i\n\x13\x04\x17\r\x02F,."},
|
||||
{"internal/coverage/pods", "\x04r.\x81\x01\x06\x05\n\x02\x01"},
|
||||
{"internal/coverage/rtcov", "\xd3\x02"},
|
||||
{"internal/coverage/slicereader", "l\n\x83\x01Z"},
|
||||
{"internal/coverage/slicewriter", "v\x83\x01"},
|
||||
{"internal/coverage/stringtab", "v9\x04F"},
|
||||
{"internal/coverage/cfile", "q\x06\x17\x17\x01\x02\x01\x01\x01\x01\x01\x01\x01\"\x02',\x06\a\n\x01\x03\x0e\x06"},
|
||||
{"internal/coverage/cformat", "\x04s.\x04Q\v6\x01\x02\x0e"},
|
||||
{"internal/coverage/cmerge", "w.a"},
|
||||
{"internal/coverage/decodecounter", "m\n.\v\x02H,\x17\x18"},
|
||||
{"internal/coverage/decodemeta", "\x02k\n\x17\x17\v\x02H,"},
|
||||
{"internal/coverage/encodecounter", "\x02k\n.\f\x01\x02F\v!\x15"},
|
||||
{"internal/coverage/encodemeta", "\x02\x01j\n\x13\x04\x17\r\x02F,/"},
|
||||
{"internal/coverage/pods", "\x04s.\x81\x01\x06\x05\n\x02\x01"},
|
||||
{"internal/coverage/rtcov", "\xd5\x02"},
|
||||
{"internal/coverage/slicereader", "m\n\x83\x01["},
|
||||
{"internal/coverage/slicewriter", "w\x83\x01"},
|
||||
{"internal/coverage/stringtab", "w9\x04F"},
|
||||
{"internal/coverage/test", ""},
|
||||
{"internal/coverage/uleb128", ""},
|
||||
{"internal/cpu", "\xd3\x02"},
|
||||
{"internal/dag", "\x04r\xc4\x01\x03"},
|
||||
{"internal/diff", "\x03s\xc5\x01\x02"},
|
||||
{"internal/exportdata", "\x02\x01p\x03\x02e\x1c,\x01\x05\x11\x01\x02"},
|
||||
{"internal/filepathlite", "s+B\x1a@"},
|
||||
{"internal/fmtsort", "\x04\xa9\x02\r"},
|
||||
{"internal/fuzz", "\x03\nG\x18\x04\x03\x03\x01\f\x036=\f\x03\x1d\x01\x05\x02\x05\n\x01\x02\x01\x01\f\x04\x02"},
|
||||
{"internal/cpu", "\xd5\x02"},
|
||||
{"internal/dag", "\x04s\xc4\x01\x03"},
|
||||
{"internal/diff", "\x03t\xc5\x01\x02"},
|
||||
{"internal/exportdata", "\x02\x01q\x03\x02e\x1c,\x01\x05\x11\x01\x02"},
|
||||
{"internal/filepathlite", "t+B\x1a@"},
|
||||
{"internal/fmtsort", "\x04\xaa\x02\r"},
|
||||
{"internal/fuzz", "\x03\nH\x18\x04\x03\x03\x01\f\x036=\f\x03\x1d\x01\x05\x02\x05\n\x01\x02\x01\x01\r\x04\x02"},
|
||||
{"internal/goarch", ""},
|
||||
{"internal/godebug", "\x9c\x01!\x82\x01\x01\x13"},
|
||||
{"internal/godebug", "\x9d\x01!\x82\x01\x01\x14"},
|
||||
{"internal/godebugs", ""},
|
||||
{"internal/goexperiment", ""},
|
||||
{"internal/goos", ""},
|
||||
{"internal/goroot", "\xa5\x02\x01\x05\x12\x02"},
|
||||
{"internal/goroot", "\xa6\x02\x01\x05\x12\x02"},
|
||||
{"internal/gover", "\x04"},
|
||||
{"internal/goversion", ""},
|
||||
{"internal/lazyregexp", "\xa5\x02\v\r\x02"},
|
||||
{"internal/lazytemplate", "\xf9\x01,\x18\x02\f"},
|
||||
{"internal/msan", "\xd3\x02"},
|
||||
{"internal/lazyregexp", "\xa6\x02\v\r\x02"},
|
||||
{"internal/lazytemplate", "\xfa\x01,\x18\x02\r"},
|
||||
{"internal/msan", "\xd5\x02"},
|
||||
{"internal/nettrace", ""},
|
||||
{"internal/obscuretestdata", "k\x8e\x01,"},
|
||||
{"internal/oserror", "s"},
|
||||
{"internal/pkgbits", "\x03Q\x18\a\x03\x04\fs\r\x1f\r\n\x01"},
|
||||
{"internal/obscuretestdata", "l\x8e\x01,"},
|
||||
{"internal/oserror", "t"},
|
||||
{"internal/pkgbits", "\x03R\x18\a\x03\x04\fs\r\x1f\r\n\x01"},
|
||||
{"internal/platform", ""},
|
||||
{"internal/poll", "sl\x05\x159\r\x01\x01\f\x06"},
|
||||
{"internal/profile", "\x03\x04l\x03\x83\x017\n\x01\x01\x01\x10"},
|
||||
{"internal/poll", "tl\x05\x159\r\x01\x01\r\x06"},
|
||||
{"internal/profile", "\x03\x04m\x03\x83\x017\n\x01\x01\x01\x11"},
|
||||
{"internal/profilerecord", ""},
|
||||
{"internal/race", "\x9a\x01\xb9\x01"},
|
||||
{"internal/reflectlite", "\x9a\x01!;<!"},
|
||||
{"internal/runtime/atomic", "\xbb\x01\x98\x01"},
|
||||
{"internal/runtime/cgroup", "\x9e\x01=\x04t"},
|
||||
{"internal/runtime/exithook", "\xd0\x01\x83\x01"},
|
||||
{"internal/runtime/gc", "\xbb\x01"},
|
||||
{"internal/runtime/gc/internal/gen", "\nb\n\x18k\x04\v\x1d\b\x10\x02"},
|
||||
{"internal/runtime/gc/scan", "\xb4\x01\a\x18\ay"},
|
||||
{"internal/runtime/maps", "\x9a\x01\x01 \n\t\t\x03y"},
|
||||
{"internal/runtime/math", "\xbb\x01"},
|
||||
{"internal/race", "\x9b\x01\xba\x01"},
|
||||
{"internal/reflectlite", "\x9b\x01!;<\""},
|
||||
{"internal/runtime/atomic", "\xbc\x01\x99\x01"},
|
||||
{"internal/runtime/cgroup", "\x9f\x01=\x04u"},
|
||||
{"internal/runtime/exithook", "\xd1\x01\x84\x01"},
|
||||
{"internal/runtime/gc", "\xbc\x01"},
|
||||
{"internal/runtime/gc/internal/gen", "\nc\n\x18k\x04\v\x1d\b\x10\x02"},
|
||||
{"internal/runtime/gc/scan", "\xb5\x01\a\x18\az"},
|
||||
{"internal/runtime/maps", "\x9b\x01\x01 \n\t\t\x03z"},
|
||||
{"internal/runtime/math", "\xbc\x01"},
|
||||
{"internal/runtime/pprof/label", ""},
|
||||
{"internal/runtime/startlinetest", ""},
|
||||
{"internal/runtime/sys", "\xbb\x01\x04"},
|
||||
{"internal/runtime/syscall/linux", "\xbb\x01\x98\x01"},
|
||||
{"internal/runtime/sys", "\xbc\x01\x04"},
|
||||
{"internal/runtime/syscall/linux", "\xbc\x01\x99\x01"},
|
||||
{"internal/runtime/wasitest", ""},
|
||||
{"internal/saferio", "\xf9\x01Z"},
|
||||
{"internal/singleflight", "\xbf\x02"},
|
||||
{"internal/strconv", "\x88\x02K"},
|
||||
{"internal/stringslite", "\x9e\x01\xb5\x01"},
|
||||
{"internal/sync", "\x9a\x01!\x13r\x13"},
|
||||
{"internal/synctest", "\x9a\x01\xb9\x01"},
|
||||
{"internal/syscall/execenv", "\xc1\x02"},
|
||||
{"internal/syscall/unix", "\xb2\x02\x0e\x01\x12"},
|
||||
{"internal/sysinfo", "\x02\x01\xb1\x01E,\x18\x02"},
|
||||
{"internal/saferio", "\xfa\x01["},
|
||||
{"internal/singleflight", "\xc0\x02"},
|
||||
{"internal/strconv", "\x89\x02L"},
|
||||
{"internal/stringslite", "\x9f\x01\xb6\x01"},
|
||||
{"internal/sync", "\x9b\x01!\x13r\x14"},
|
||||
{"internal/synctest", "\x9b\x01\xba\x01"},
|
||||
{"internal/syscall/execenv", "\xc2\x02"},
|
||||
{"internal/syscall/unix", "\xb3\x02\x0e\x01\x13"},
|
||||
{"internal/sysinfo", "\x02\x01\xb2\x01E,\x18\x02"},
|
||||
{"internal/syslist", ""},
|
||||
{"internal/testenv", "\x03\nf\x02\x01*\x1b\x0f0+\x01\x05\a\n\x01\x02\x02\x01\v"},
|
||||
{"internal/testhash", "\x03\x86\x01p\x118\v"},
|
||||
{"internal/testlog", "\xbf\x02\x01\x13"},
|
||||
{"internal/testpty", "s\x03\xaf\x01"},
|
||||
{"internal/trace", "\x02\x01\x01\x06b\a\x03w\x03\x03\x06\x03\t5\x01\x01\x01\x10\x06"},
|
||||
{"internal/trace/internal/testgen", "\x03i\nu\x03\x02\x03\x011\v\r\x10"},
|
||||
{"internal/trace/internal/tracev1", "\x03\x01h\a\x03}\x06\f5\x01"},
|
||||
{"internal/trace/raw", "\x02j\nz\x03\x06C\x01\x12"},
|
||||
{"internal/trace/testtrace", "\x02\x01p\x03q\x04\x03\x05\x01\x05,\v\x02\b\x02\x01\x05"},
|
||||
{"internal/testenv", "\x03\ng\x02\x01*\x1b\x0f0+\x01\x05\a\n\x01\x02\x02\x01\f"},
|
||||
{"internal/testhash", "\x03\x87\x01p\x118\f"},
|
||||
{"internal/testlog", "\xc0\x02\x01\x14"},
|
||||
{"internal/testpty", "t\x03\xaf\x01"},
|
||||
{"internal/trace", "\x02\x01\x01\x06c\a\x03w\x03\x03\x06\x03\t+\n\x01\x01\x01\x11\x06"},
|
||||
{"internal/trace/internal/testgen", "\x03j\nu\x03\x02\x03\x011\v\r\x11"},
|
||||
{"internal/trace/internal/tracev1", "\x03\x01i\a\x03}\x06\f5\x01"},
|
||||
{"internal/trace/raw", "\x02k\nz\x03\x06C\x01\x13"},
|
||||
{"internal/trace/testtrace", "\x02\x01q\x03q\x04\x03\x05\x01\x05,\v\x02\b\x02\x01\x05"},
|
||||
{"internal/trace/tracev2", ""},
|
||||
{"internal/trace/traceviewer", "\x02c\v\x06\x1a<\x1f\a\a\x04\b\v\x15\x01\x05\a\n\x01\x02\x0e"},
|
||||
{"internal/trace/traceviewer", "\x02d\v\x06\x1a<\x1f\a\a\x04\b\v\x15\x01\x05\a\n\x01\x02\x0f"},
|
||||
{"internal/trace/traceviewer/format", ""},
|
||||
{"internal/trace/version", "vz\t"},
|
||||
{"internal/txtar", "\x03s\xaf\x01\x18"},
|
||||
{"internal/types/errors", "\xbc\x02"},
|
||||
{"internal/unsafeheader", "\xd3\x02"},
|
||||
{"internal/xcoff", "_\r\a\x03g\x1c,\x17\x01"},
|
||||
{"internal/zstd", "l\a\x03\x83\x01\x0f"},
|
||||
{"io", "s\xcc\x01"},
|
||||
{"io/fs", "s+*11\x10\x13\x04"},
|
||||
{"io/ioutil", "\xf9\x01\x01+\x15\x03"},
|
||||
{"iter", "\xce\x01d!"},
|
||||
{"log", "v\x83\x01\x05'\r\r\x01\r"},
|
||||
{"internal/trace/version", "wz\t"},
|
||||
{"internal/txtar", "\x03t\xaf\x01\x18"},
|
||||
{"internal/types/errors", "\xbd\x02"},
|
||||
{"internal/unsafeheader", "\xd5\x02"},
|
||||
{"internal/xcoff", "`\r\a\x03g\x1c,\x17\x01"},
|
||||
{"internal/zstd", "m\a\x03\x83\x01\x0f"},
|
||||
{"io", "t\xcc\x01"},
|
||||
{"io/fs", "t+*11\x10\x14\x04"},
|
||||
{"io/ioutil", "\xfa\x01\x01+\x15\x03"},
|
||||
{"iter", "\xcf\x01d\""},
|
||||
{"log", "w\x83\x01\x05'\r\r\x01\x0e"},
|
||||
{"log/internal", ""},
|
||||
{"log/slog", "\x03\nZ\t\x03\x03\x83\x01\x04\x01\x02\x02\x03(\x05\b\x02\x01\x02\x01\r\x02\x02\x02"},
|
||||
{"log/slog", "\x03\n[\t\x03\x03\x83\x01\x04\x01\x02\x02\x03(\x05\b\x02\x01\x02\x01\x0e\x02\x02\x02"},
|
||||
{"log/slog/internal", ""},
|
||||
{"log/slog/internal/benchmarks", "\rf\x03\x83\x01\x06\x03:\x11"},
|
||||
{"log/slog/internal/buffer", "\xbf\x02"},
|
||||
{"log/syslog", "s\x03\x87\x01\x12\x16\x18\x02\x0e"},
|
||||
{"maps", "\xfc\x01W"},
|
||||
{"math", "\xb4\x01TK"},
|
||||
{"math/big", "\x03p\x03)\x15E\f\x03\x020\x02\x01\x02\x14"},
|
||||
{"math/big/internal/asmgen", "\x03\x01r\x92\x012\x03"},
|
||||
{"math/bits", "\xd3\x02"},
|
||||
{"math/cmplx", "\x85\x02\x03"},
|
||||
{"math/rand", "\xbc\x01I:\x01\x13"},
|
||||
{"math/rand/v2", "s,\x03c\x03K"},
|
||||
{"mime", "\x02\x01h\b\x03\x83\x01\v!\x15\x03\x02\x10\x02"},
|
||||
{"mime/multipart", "\x02\x01M#\x03F=\v\x01\a\x02\x15\x02\x06\x0f\x02\x01\x16"},
|
||||
{"mime/quotedprintable", "\x02\x01s\x83\x01"},
|
||||
{"net", "\x04\tf+\x1e\n\x05\x13\x01\x01\x04\x15\x01%\x06\r\b\x05\x01\x01\f\x06\a"},
|
||||
{"net/http", "\x02\x01\x03\x01\x04\x02C\b\x13\x01\a\x03F=\x01\x03\a\x01\x03\x02\x02\x01\x02\x06\x02\x01\x01\n\x01\x01\x05\x01\x02\x05\b\x01\x01\x01\x02\x01\r\x02\x02\x02\b\x01\x01\x01"},
|
||||
{"net/http/cgi", "\x02V\x1b\x03\x83\x01\x04\a\v\x01\x13\x01\x01\x01\x04\x01\x05\x02\b\x02\x01\x10\x0e"},
|
||||
{"net/http/cookiejar", "\x04o\x03\x99\x01\x01\b\a\x05\x16\x03\x02\x0e\x04"},
|
||||
{"net/http/fcgi", "\x02\x01\n_\a\x03\x83\x01\x16\x01\x01\x14\x18\x02\x0e"},
|
||||
{"net/http/httptest", "\x02\x01\nK\x02\x1b\x01\x83\x01\x04\x12\x01\n\t\x02\x17\x01\x02\x0e\x0e"},
|
||||
{"net/http/httptrace", "\rKnI\x14\n "},
|
||||
{"net/http/httputil", "\x02\x01\nf\x03\x83\x01\x04\x0f\x03\x01\x05\x02\x01\v\x01\x19\x02\x01\r\x0e"},
|
||||
{"net/http/internal", "\x02\x01p\x03\x83\x01"},
|
||||
{"net/http/internal/ascii", "\xbd\x02\x12"},
|
||||
{"net/http/internal/httpcommon", "\rf\x03\x9f\x01\x0e\x01\x17\x01\x01\x02\x1c\x02"},
|
||||
{"net/http/internal/testcert", "\xbd\x02"},
|
||||
{"net/http/pprof", "\x02\x01\ni\x19-\x02\x0e-\x04\x13\x14\x01\r\x04\x03\x01\x02\x01\x10"},
|
||||
{"log/slog/internal/benchmarks", "\rg\x03\x83\x01\x06\x03:\x12"},
|
||||
{"log/slog/internal/buffer", "\xc0\x02"},
|
||||
{"log/syslog", "t\x03\x87\x01\x12\x16\x18\x02\x0f"},
|
||||
{"maps", "\xfd\x01X"},
|
||||
{"math", "\xb5\x01TL"},
|
||||
{"math/big", "\x03q\x03)\x15E\f\x03\x020\x02\x01\x02\x15"},
|
||||
{"math/big/internal/asmgen", "\x03\x01s\x92\x012\x03"},
|
||||
{"math/bits", "\xd5\x02"},
|
||||
{"math/cmplx", "\x86\x02\x03"},
|
||||
{"math/rand", "\xbd\x01I:\x01\x14"},
|
||||
{"math/rand/v2", "t,\x03c\x03L"},
|
||||
{"mime", "\x02\x01i\b\x03\x83\x01\v!\x15\x03\x02\x11\x02"},
|
||||
{"mime/multipart", "\x02\x01N#\x03F=\v\x01\a\x02\x15\x02\x06\x0f\x02\x01\x17"},
|
||||
{"mime/quotedprintable", "\x02\x01t\x83\x01"},
|
||||
{"net", "\x04\tg+\x1e\n\x05\x13\x01\x01\x04\x15\x01%\x06\r\b\x05\x01\x01\r\x06\a"},
|
||||
{"net/http", "\x02\x01\x03\x01\x04\x02D\b\x13\x01\a\x03F=\x01\x03\a\x01\x03\x02\x02\x01\x02\x06\x02\x01\x01\n\x01\x01\x05\x01\x02\x05\b\x01\x01\x01\x02\x01\x0e\x02\x02\x02\b\x01\x01\x01"},
|
||||
{"net/http/cgi", "\x02W\x1b\x03\x83\x01\x04\a\v\x01\x13\x01\x01\x01\x04\x01\x05\x02\b\x02\x01\x11\x0e"},
|
||||
{"net/http/cookiejar", "\x04p\x03\x99\x01\x01\b\a\x05\x16\x03\x02\x0f\x04"},
|
||||
{"net/http/fcgi", "\x02\x01\n`\a\x03\x83\x01\x16\x01\x01\x14\x18\x02\x0f"},
|
||||
{"net/http/httptest", "\x02\x01\nL\x02\x1b\x01\x83\x01\x04\x12\x01\n\t\x02\x17\x01\x02\x0f\x0e"},
|
||||
{"net/http/httptrace", "\rLnI\x14\n!"},
|
||||
{"net/http/httputil", "\x02\x01\ng\x03\x83\x01\x04\x0f\x03\x01\x05\x02\x01\v\x01\x19\x02\x01\x0e\x0e"},
|
||||
{"net/http/internal", "\x02\x01q\x03\x83\x01"},
|
||||
{"net/http/internal/ascii", "\xbe\x02\x13"},
|
||||
{"net/http/internal/httpcommon", "\rg\x03\x9f\x01\x0e\x01\x17\x01\x01\x02\x1d\x02"},
|
||||
{"net/http/internal/testcert", "\xbe\x02"},
|
||||
{"net/http/pprof", "\x02\x01\nj\x19-\x02\x0e-\x04\x13\x14\x01\r\x04\x03\x01\x02\x01\x11"},
|
||||
{"net/internal/cgotest", ""},
|
||||
{"net/internal/socktest", "v\xc9\x01\x02"},
|
||||
{"net/mail", "\x02q\x03\x83\x01\x04\x0f\x03\x14\x1a\x02\x0e\x04"},
|
||||
{"net/netip", "\x04o+\x01f\x034\x16"},
|
||||
{"net/rpc", "\x02l\x05\x03\x10\ni\x04\x12\x01\x1d\r\x03\x02"},
|
||||
{"net/rpc/jsonrpc", "p\x03\x03\x83\x01\x16\x11\x1f"},
|
||||
{"net/smtp", "\x193\f\x13\b\x03\x83\x01\x16\x14\x1a"},
|
||||
{"net/textproto", "\x02\x01p\x03\x83\x01\f\n-\x01\x02\x14"},
|
||||
{"net/url", "s\x03Fc\v\x10\x02\x01\x16"},
|
||||
{"os", "s+\x01\x19\x03\x10\x14\x01\x03\x01\x05\x10\x018\b\x05\x01\x01\f\x06"},
|
||||
{"os/exec", "\x03\nfI'\x01\x15\x01+\x06\a\n\x01\x04\f"},
|
||||
{"os/exec/internal/fdtest", "\xc1\x02"},
|
||||
{"os/signal", "\r\x98\x02\x15\x05\x02"},
|
||||
{"os/user", "\x02\x01p\x03\x83\x01,\r\n\x01\x02"},
|
||||
{"path", "s+\xb3\x01"},
|
||||
{"path/filepath", "s+\x1aB+\r\b\x03\x04\x10"},
|
||||
{"plugin", "s"},
|
||||
{"reflect", "s'\x04\x1d\x13\b\x04\x05\x17\x06\t-\n\x03\x10\x02\x02"},
|
||||
{"net/internal/socktest", "w\xc9\x01\x02"},
|
||||
{"net/mail", "\x02r\x03\x83\x01\x04\x0f\x03\x14\x1a\x02\x0f\x04"},
|
||||
{"net/netip", "\x04p+\x01f\x034\x17"},
|
||||
{"net/rpc", "\x02m\x05\x03\x10\ni\x04\x12\x01\x1d\r\x03\x02"},
|
||||
{"net/rpc/jsonrpc", "q\x03\x03\x83\x01\x16\x11\x1f"},
|
||||
{"net/smtp", "\x194\f\x13\b\x03\x83\x01\x16\x14\x1a"},
|
||||
{"net/textproto", "\x02\x01q\x03\x83\x01\f\n-\x01\x02\x15"},
|
||||
{"net/url", "t\x03Fc\v\x10\x02\x01\x17"},
|
||||
{"os", "t+\x01\x19\x03\x10\x14\x01\x03\x01\x05\x10\x018\b\x05\x01\x01\r\x06"},
|
||||
{"os/exec", "\x03\ngI'\x01\x15\x01+\x06\a\n\x01\x04\r"},
|
||||
{"os/exec/internal/fdtest", "\xc2\x02"},
|
||||
{"os/signal", "\r\x99\x02\x15\x05\x02"},
|
||||
{"os/user", "\x02\x01q\x03\x83\x01,\r\n\x01\x02"},
|
||||
{"path", "t+\xb4\x01"},
|
||||
{"path/filepath", "t+\x1aB+\r\b\x03\x04\x11"},
|
||||
{"plugin", "t"},
|
||||
{"reflect", "t'\x04\x1d\x13\b\x04\x05\x17\x06\t-\n\x03\x11\x02\x02"},
|
||||
{"reflect/internal/example1", ""},
|
||||
{"reflect/internal/example2", ""},
|
||||
{"regexp", "\x03\xf6\x018\t\x02\x01\x02\x10\x02"},
|
||||
{"regexp/syntax", "\xba\x02\x01\x01\x01\x02\x10\x02"},
|
||||
{"runtime", "\x9a\x01\x04\x01\x03\f\x06\a\x02\x01\x01\x0e\x03\x01\x01\x01\x02\x01\x01\x01\x02\x01\x04\x01\x10\x18K"},
|
||||
{"runtime/coverage", "\xa6\x01S"},
|
||||
{"runtime/debug", "vUZ\r\b\x02\x01\x10\x06"},
|
||||
{"runtime/metrics", "\xbd\x01H-!"},
|
||||
{"runtime/pprof", "\x02\x01\x01\x03\x06_\a\x03$$\x0f\v!\f \r\b\x01\x01\x01\x02\x02\t\x03\x06"},
|
||||
{"runtime/race", "\xb8\x02"},
|
||||
{"regexp", "\x03\xf7\x018\t\x02\x01\x02\x11\x02"},
|
||||
{"regexp/syntax", "\xbb\x02\x01\x01\x01\x02\x11\x02"},
|
||||
{"runtime", "\x9b\x01\x04\x01\x03\f\x06\a\x02\x01\x01\x0e\x03\x01\x01\x01\x02\x01\x01\x01\x02\x01\x04\x01\x10\x18L"},
|
||||
{"runtime/coverage", "\xa7\x01S"},
|
||||
{"runtime/debug", "wUZ\r\b\x02\x01\x11\x06"},
|
||||
{"runtime/metrics", "\xbe\x01H-\""},
|
||||
{"runtime/pprof", "\x02\x01\x01\x03\x06`\a\x03$$\x0f\v!\f \r\b\x01\x01\x01\x02\x02\n\x03\x06"},
|
||||
{"runtime/race", "\xb9\x02"},
|
||||
{"runtime/race/internal/amd64v1", ""},
|
||||
{"runtime/trace", "\rf\x03z\t9\b\x05\x01\r\x06"},
|
||||
{"slices", "\x04\xf8\x01\fK"},
|
||||
{"sort", "\xcf\x0192"},
|
||||
{"strconv", "s+A\x01q"},
|
||||
{"strings", "s'\x04B\x19\x03\f7\x10\x02\x02"},
|
||||
{"runtime/trace", "\rg\x03z\t9\b\x05\x01\x0e\x06"},
|
||||
{"slices", "\x04\xf9\x01\fL"},
|
||||
{"sort", "\xd0\x0192"},
|
||||
{"strconv", "t+A\x01r"},
|
||||
{"strings", "t'\x04B\x19\x03\f7\x11\x02\x02"},
|
||||
{"structs", ""},
|
||||
{"sync", "\xce\x01\x13\x01P\x0e\x13"},
|
||||
{"sync/atomic", "\xd3\x02"},
|
||||
{"syscall", "s(\x03\x01\x1c\n\x03\x06\r\x04S\b\x05\x01\x13"},
|
||||
{"testing", "\x03\nf\x02\x01X\x17\x14\f\x05\x1b\x06\x02\x05\x02\x05\x01\x02\x01\x02\x01\r\x02\x04"},
|
||||
{"testing/fstest", "s\x03\x83\x01\x01\n&\x10\x03\b\b"},
|
||||
{"testing/internal/testdeps", "\x02\v\xad\x01/\x10,\x03\x05\x03\x06\a\x02\x0e"},
|
||||
{"testing/iotest", "\x03p\x03\x83\x01\x04"},
|
||||
{"testing/quick", "u\x01\x8f\x01\x05#\x10\x10"},
|
||||
{"testing/slogtest", "\rf\x03\x89\x01.\x05\x10\v"},
|
||||
{"testing/synctest", "\xe2\x01`\x11"},
|
||||
{"text/scanner", "\x03s\x83\x01,*\x02"},
|
||||
{"text/tabwriter", "v\x83\x01X"},
|
||||
{"text/template", "s\x03C@\x01\n \x01\x05\x01\x02\x05\v\x02\r\x03\x02"},
|
||||
{"text/template/parse", "\x03s\xbc\x01\n\x01\x12\x02"},
|
||||
{"time", "s+\x1e$(*\r\x02\x12"},
|
||||
{"time/tzdata", "s\xce\x01\x12"},
|
||||
{"sync", "\xcf\x01\x13\x01P\x0e\x14"},
|
||||
{"sync/atomic", "\xd5\x02"},
|
||||
{"syscall", "t(\x03\x01\x1c\n\x03\x06\r\x04S\b\x05\x01\x14"},
|
||||
{"testing", "\x03\ng\x02\x01X\x17\x14\f\x05\x1b\x06\x02\x05\x02\x05\x01\x02\x01\x02\x01\x0e\x02\x04"},
|
||||
{"testing/cryptotest", "QOZ\x124\x03\x12"},
|
||||
{"testing/fstest", "t\x03\x83\x01\x01\n&\x10\x03\t\b"},
|
||||
{"testing/internal/testdeps", "\x02\v\xae\x01/\x10,\x03\x05\x03\x06\a\x02\x0f"},
|
||||
{"testing/iotest", "\x03q\x03\x83\x01\x04"},
|
||||
{"testing/quick", "v\x01\x8f\x01\x05#\x10\x11"},
|
||||
{"testing/slogtest", "\rg\x03\x89\x01.\x05\x10\f"},
|
||||
{"testing/synctest", "\xe3\x01`\x12"},
|
||||
{"text/scanner", "\x03t\x83\x01,+\x02"},
|
||||
{"text/tabwriter", "w\x83\x01Y"},
|
||||
{"text/template", "t\x03C@\x01\n \x01\x05\x01\x02\x05\v\x02\x0e\x03\x02"},
|
||||
{"text/template/parse", "\x03t\xbc\x01\n\x01\x13\x02"},
|
||||
{"time", "t+\x1e$(*\r\x02\x13"},
|
||||
{"time/tzdata", "t\xce\x01\x13"},
|
||||
{"unicode", ""},
|
||||
{"unicode/utf16", ""},
|
||||
{"unicode/utf8", ""},
|
||||
{"unique", "\x9a\x01!%\x01Q\r\x01\x13\x12"},
|
||||
{"unique", "\x9b\x01!%\x01Q\r\x01\x14\x12"},
|
||||
{"unsafe", ""},
|
||||
{"vendor/golang.org/x/crypto/chacha20", "\x10\\\a\x95\x01*&"},
|
||||
{"vendor/golang.org/x/crypto/chacha20poly1305", "\x10\\\a\xe1\x01\x04\x01\a"},
|
||||
{"vendor/golang.org/x/crypto/cryptobyte", "i\n\x03\x90\x01' \n"},
|
||||
{"vendor/golang.org/x/crypto/chacha20", "\x10]\a\x95\x01*'"},
|
||||
{"vendor/golang.org/x/crypto/chacha20poly1305", "\x10\aV\a\xe2\x01\x04\x01\a"},
|
||||
{"vendor/golang.org/x/crypto/cryptobyte", "j\n\x03\x90\x01'!\n"},
|
||||
{"vendor/golang.org/x/crypto/cryptobyte/asn1", ""},
|
||||
{"vendor/golang.org/x/crypto/internal/alias", "\xd3\x02"},
|
||||
{"vendor/golang.org/x/crypto/internal/poly1305", "W\x15\x9c\x01"},
|
||||
{"vendor/golang.org/x/net/dns/dnsmessage", "s\xc7\x01"},
|
||||
{"vendor/golang.org/x/net/http/httpguts", "\x8f\x02\x14\x1a\x14\r"},
|
||||
{"vendor/golang.org/x/net/http/httpproxy", "s\x03\x99\x01\x10\x05\x01\x18\x14\r"},
|
||||
{"vendor/golang.org/x/net/http2/hpack", "\x03p\x03\x83\x01F"},
|
||||
{"vendor/golang.org/x/net/idna", "v\x8f\x018\x14\x10\x02\x01"},
|
||||
{"vendor/golang.org/x/net/nettest", "\x03i\a\x03\x83\x01\x11\x05\x16\x01\f\n\x01\x02\x02\x01\v"},
|
||||
{"vendor/golang.org/x/sys/cpu", "\xa5\x02\r\n\x01\x16"},
|
||||
{"vendor/golang.org/x/text/secure/bidirule", "s\xde\x01\x11\x01"},
|
||||
{"vendor/golang.org/x/text/transform", "\x03p\x86\x01X"},
|
||||
{"vendor/golang.org/x/text/unicode/bidi", "\x03\bk\x87\x01>\x16"},
|
||||
{"vendor/golang.org/x/text/unicode/norm", "l\n\x83\x01F\x12\x11"},
|
||||
{"weak", "\x9a\x01\x98\x01!"},
|
||||
{"vendor/golang.org/x/crypto/internal/alias", "\xd5\x02"},
|
||||
{"vendor/golang.org/x/crypto/internal/poly1305", "X\x15\x9c\x01"},
|
||||
{"vendor/golang.org/x/net/dns/dnsmessage", "t\xc7\x01"},
|
||||
{"vendor/golang.org/x/net/http/httpguts", "\x90\x02\x14\x1a\x15\r"},
|
||||
{"vendor/golang.org/x/net/http/httpproxy", "t\x03\x99\x01\x10\x05\x01\x18\x15\r"},
|
||||
{"vendor/golang.org/x/net/http2/hpack", "\x03q\x03\x83\x01F"},
|
||||
{"vendor/golang.org/x/net/idna", "w\x8f\x018\x15\x10\x02\x01"},
|
||||
{"vendor/golang.org/x/net/nettest", "\x03j\a\x03\x83\x01\x11\x05\x16\x01\f\n\x01\x02\x02\x01\f"},
|
||||
{"vendor/golang.org/x/sys/cpu", "\xa6\x02\r\n\x01\x17"},
|
||||
{"vendor/golang.org/x/text/secure/bidirule", "t\xdf\x01\x11\x01"},
|
||||
{"vendor/golang.org/x/text/transform", "\x03q\x86\x01Y"},
|
||||
{"vendor/golang.org/x/text/unicode/bidi", "\x03\bl\x87\x01>\x17"},
|
||||
{"vendor/golang.org/x/text/unicode/norm", "m\n\x83\x01F\x13\x11"},
|
||||
{"weak", "\x9b\x01\x98\x01\""},
|
||||
}
|
||||
|
||||
// bootstrap is the list of bootstrap packages extracted from cmd/dist.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user