From 473898e47ceae0d09bd28a3bcc819c42488e3a33 Mon Sep 17 00:00:00 2001 From: Selene Date: Thu, 21 Mar 2024 11:11:29 +0100 Subject: [PATCH] Core: Remove thema and kindsys dependencies (#84499) * Move some thema code inside grafana * Use new codegen instead of thema for core kinds * Replace TS generator * Use new generator for go types * Remove thema from oapi generator * Remove thema from generators * Don't use kindsys/thema for core kinds * Remove kindsys/thema from plugins * Remove last thema related * Remove most of cuectx and move utils_ts into codegen. It also deletes wire dependency * Merge plugins generators * Delete thema dependency :tada: * Fix CODEOWNERS * Fix package name * Fix TS output names * More path fixes * Fix mod codeowners * Use original plugin's name * Remove kindsys dependency :tada: * Modify oapi schema and create an apply function to fix elasticsearch errors * cue.mod was deleted by mistake * Fix TS panels * sort imports * Fixing elasticsearch output * Downgrade oapi-codegen library * Update output ts files * More fixes * Restore old elasticsearch generated file and skip its generation. Remove core imports into plugins * More lint fixes * Add codeowners * restore embed.go file * Fix embed.go --- .github/CODEOWNERS | 2 +- embed.go | 2 +- go.mod | 48 +-- go.sum | 155 +++------ kinds/constraint.cue | 7 - kinds/gen.go | 157 ++++----- pkg/codegen/generators.go | 31 +- pkg/codegen/generators/decorators.go | 282 +++++++++++++++++ pkg/codegen/generators/go_generator.go | 193 ++++++++++++ pkg/codegen/generators/openapi_generator.go | 199 ++++++++++++ pkg/codegen/generators/ts_generator.go | 56 ++++ pkg/codegen/generators/utils.go | 130 ++++++++ pkg/codegen/jenny_core_registry.go | 16 +- pkg/codegen/jenny_eachmajor.go | 20 +- pkg/codegen/jenny_go_spec.go | 29 +- pkg/codegen/jenny_k8_resources.go | 22 +- pkg/codegen/jenny_ts_types.go | 23 +- pkg/codegen/jenny_tsveneerindex.go | 56 ++-- pkg/codegen/util_go.go | 15 - pkg/{cuectx => codegen}/util_ts.go | 6 +- pkg/cuectx/ctx.go | 73 ----- pkg/cuectx/load.go | 239 -------------- pkg/plugins/codegen/jenny_plugin_registry.go | 18 +- pkg/plugins/codegen/jenny_plugingotypes.go | 19 +- pkg/plugins/codegen/jenny_plugintstypes.go | 47 ++- pkg/plugins/pfs/corelist/corelist.go | 30 -- pkg/plugins/pfs/corelist/corelist_load_gen.go | 87 ----- pkg/plugins/pfs/decl.go | 20 +- pkg/plugins/pfs/decl_parser.go | 50 +-- pkg/plugins/pfs/pfs.go | 159 +++------- pkg/plugins/pfs/pfs_test.go | 297 ------------------ pkg/plugins/pfs/plugin.go | 31 +- pkg/plugins/pfs/plugin_test.go | 31 -- pkg/server/wire.go | 7 +- .../kinds/dataquery/types_dataquery_gen.go | 119 +++---- .../azure-log-analytics-datasource.go | 4 +- .../kinds/dataquery/types_dataquery_gen.go | 25 +- pkg/tsdb/cloudwatch/annotation_query.go | 14 +- pkg/tsdb/cloudwatch/cloudwatch.go | 8 +- .../kinds/dataquery/types_dataquery_gen.go | 56 ++-- pkg/tsdb/cloudwatch/log_actions.go | 8 +- pkg/tsdb/cloudwatch/log_sync_query.go | 7 +- .../cloudwatch/models/cloudwatch_query.go | 9 +- .../models/cloudwatch_query_test.go | 12 +- pkg/tsdb/cloudwatch/utils/utils.go | 9 + .../kinds/dataquery/types_dataquery_gen.go | 13 +- .../grafana-pyroscope-datasource/query.go | 20 +- .../kinds/dataquery/types_dataquery_gen.go | 70 +++-- pkg/tsdb/loki/healthcheck.go | 3 +- .../kinds/dataquery/types_dataquery_gen.go | 9 +- pkg/tsdb/loki/parse_query.go | 11 +- pkg/tsdb/loki/streaming.go | 8 +- .../kinds/dataquery/types_dataquery_gen.go | 11 +- pkg/tsdb/parca/query.go | 8 +- .../kinds/dataquery/types_dataquery_gen.go | 9 +- public/app/plugins/gen.go | 74 +---- 56 files changed, 1433 insertions(+), 1631 deletions(-) delete mode 100644 kinds/constraint.cue create mode 100644 pkg/codegen/generators/decorators.go create mode 100644 pkg/codegen/generators/go_generator.go create mode 100644 pkg/codegen/generators/openapi_generator.go create mode 100644 pkg/codegen/generators/ts_generator.go create mode 100644 pkg/codegen/generators/utils.go rename pkg/{cuectx => codegen}/util_ts.go (92%) delete mode 100644 pkg/cuectx/ctx.go delete mode 100644 pkg/cuectx/load.go delete mode 100644 pkg/plugins/pfs/corelist/corelist.go delete mode 100644 pkg/plugins/pfs/corelist/corelist_load_gen.go delete mode 100644 pkg/plugins/pfs/pfs_test.go delete mode 100644 pkg/plugins/pfs/plugin_test.go diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 9df8a70c52a..025493d4c65 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -624,10 +624,10 @@ playwright.config.ts @grafana/plugins-platform-frontend # Kind system and code generation embed.go @grafana/grafana-as-code /pkg/kinds/ @grafana/grafana-as-code -/pkg/cuectx/ @grafana/grafana-as-code /pkg/registry/ @grafana/grafana-as-code /pkg/registry/apis/ @grafana/grafana-app-platform-squad /pkg/codegen/ @grafana/grafana-as-code +/pkg/codegen/generators @grafana/grafana-as-code /pkg/kinds/*/*_gen.go @grafana/grafana-as-code /pkg/registry/schemas/ @grafana/grafana-as-code /public/app/plugins/*gen.go @grafana/grafana-as-code diff --git a/embed.go b/embed.go index e022a032c45..b968d1ca455 100644 --- a/embed.go +++ b/embed.go @@ -6,5 +6,5 @@ import ( // CueSchemaFS embeds all schema-related CUE files in the Grafana project. // -//go:embed cue.mod/module.cue kinds/*.cue kinds/*/*.cue packages/grafana-schema/src/common/*.cue public/app/plugins/*/*/*.cue public/app/plugins/*/*/plugin.json +//go:embed cue.mod/module.cue var CueSchemaFS embed.FS diff --git a/go.mod b/go.mod index bc5d53b614c..113f394dfe8 100644 --- a/go.mod +++ b/go.mod @@ -15,9 +15,6 @@ replace cuelang.org/go => github.com/grafana/cue v0.0.0-20230926092038-971951014 // import that instead of v0.X even though v0.X is newer. replace github.com/prometheus/prometheus => github.com/prometheus/prometheus v0.49.0 -// The v0.120.0 is needed for now to be compatible with grafana/thema. -replace github.com/getkin/kin-openapi => github.com/getkin/kin-openapi v0.120.0 - require ( cloud.google.com/go/storage v1.36.0 // @grafana/backend-platform cuelang.org/go v0.6.0-0.dev // @grafana/grafana-as-code @@ -90,7 +87,6 @@ require ( github.com/uber/jaeger-client-go v2.30.0+incompatible // indirect github.com/urfave/cli/v2 v2.25.0 // @grafana/backend-platform github.com/vectordotdev/go-datemath v0.1.1-0.20220323213446-f3954d0b18ae // @grafana/backend-platform - github.com/yalue/merged_fs v1.2.2 // @grafana/grafana-as-code github.com/yudai/gojsondiff v1.0.0 // @grafana/backend-platform go.opentelemetry.io/collector/pdata v1.0.1 // @grafana/backend-platform go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.49.0 // @grafana/grafana-operator-experience-squad @@ -103,7 +99,7 @@ require ( golang.org/x/oauth2 v0.16.0 // @grafana/grafana-authnz-team golang.org/x/sync v0.6.0 // @grafana/alerting-squad-backend golang.org/x/time v0.5.0 // @grafana/backend-platform - golang.org/x/tools v0.17.0 // indirect; @grafana/grafana-as-code + golang.org/x/tools v0.17.0 // @grafana/grafana-as-code gonum.org/v1/gonum v0.12.0 // @grafana/observability-metrics google.golang.org/api v0.155.0 // @grafana/backend-platform google.golang.org/grpc v1.62.1 // @grafana/plugins-platform-backend @@ -113,7 +109,7 @@ require ( gopkg.in/mail.v2 v2.3.1 // @grafana/backend-platform gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // @grafana/alerting-squad-backend - xorm.io/builder v0.3.6 // @grafana/backend-platform + xorm.io/builder v0.3.6 // indirect; @grafana/backend-platform xorm.io/core v0.7.3 // @grafana/backend-platform xorm.io/xorm v0.8.2 // @grafana/alerting-squad-backend ) @@ -135,7 +131,7 @@ require ( github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/cheekybits/genny v1.0.0 // indirect github.com/cockroachdb/apd/v2 v2.0.2 // indirect - github.com/deepmap/oapi-codegen v1.12.4 // indirect + github.com/deepmap/oapi-codegen v1.13.0 // @grafana/grafana-as-code github.com/dennwc/varint v1.0.0 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/docker/go-units v0.5.0 // indirect @@ -160,12 +156,12 @@ require ( github.com/google/btree v1.1.2 // indirect github.com/google/flatbuffers v23.5.26+incompatible // indirect github.com/googleapis/gax-go/v2 v2.12.0 // @grafana/backend-platform - github.com/gorilla/mux v1.8.0 // @grafana/backend-platform + github.com/gorilla/mux v1.8.1 // @grafana/backend-platform github.com/grafana/grafana-google-sdk-go v0.1.0 // @grafana/partner-datasources github.com/grpc-ecosystem/go-grpc-prometheus v1.2.1-0.20191002090509-6af20e3a5340 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-msgpack v0.5.5 // indirect - github.com/hashicorp/go-multierror v1.1.1 // @grafana/alerting-squad + github.com/hashicorp/go-multierror v1.1.1 // indirect; @grafana/alerting-squad github.com/hashicorp/go-sockaddr v1.0.6 // indirect github.com/hashicorp/golang-lru v0.6.0 // indirect github.com/hashicorp/yamux v0.1.1 // indirect @@ -177,7 +173,7 @@ require ( github.com/mailru/easyjson v0.7.7 // indirect github.com/mattermost/xml-roundtrip-validator v0.1.0 // indirect github.com/mattetti/filebuffer v1.0.1 // indirect - github.com/mattn/go-runewidth v0.0.13 // indirect + github.com/mattn/go-runewidth v0.0.15 // indirect github.com/miekg/dns v1.1.57 // indirect github.com/mitchellh/go-testing-interface v1.14.1 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect @@ -224,7 +220,6 @@ require ( github.com/bufbuild/connect-go v1.10.0 // @grafana/observability-traces-and-profiling github.com/dlmiddlecote/sqlstats v1.0.2 // @grafana/backend-platform github.com/drone/drone-cli v1.6.1 // @grafana/grafana-release-guild - github.com/getkin/kin-openapi v0.120.0 // @grafana/grafana-operator-experience-squad github.com/golang-migrate/migrate/v4 v4.7.0 // @grafana/backend-platform github.com/google/go-github v17.0.0+incompatible // @grafana/grafana-release-guild github.com/google/go-github/v45 v45.2.0 // @grafana/grafana-release-guild @@ -250,11 +245,9 @@ require ( github.com/go-jose/go-jose/v3 v3.0.3 // @grafana/grafana-authnz-team github.com/grafana/dataplane/examples v0.0.1 // @grafana/observability-metrics github.com/grafana/dataplane/sdata v0.0.7 // @grafana/observability-metrics - github.com/grafana/kindsys v0.0.0-20230508162304-452481b63482 // @grafana/grafana-as-code github.com/grafana/tempo v1.5.1-0.20230524121406-1dc1bfe7085b // @grafana/observability-traces-and-profiling - github.com/grafana/thema v0.0.0-20230712153715-375c1b45f3ed // @grafana/grafana-as-code github.com/microsoft/go-mssqldb v1.6.1-0.20240214161942-b65008136246 // @grafana/grafana-bi-squad - github.com/redis/go-redis/v9 v9.0.2 // @grafana/alerting-squad-backend + github.com/redis/go-redis/v9 v9.1.0 // @grafana/alerting-squad-backend go.opentelemetry.io/contrib/samplers/jaegerremote v0.18.0 // @grafana/backend-platform golang.org/x/mod v0.14.0 // @grafana/backend-platform k8s.io/utils v0.0.0-20230726121419-3b25d923346b // @grafana/partner-datasources @@ -298,9 +291,6 @@ require ( github.com/bwmarrin/snowflake v0.3.0 // @grafan/grafana-app-platform-squad github.com/centrifugal/protocol v0.10.0 // indirect github.com/cloudflare/circl v1.3.7 // indirect - github.com/cockroachdb/errors v1.9.1 // indirect - github.com/cockroachdb/logtags v0.0.0-20211118104740-dabe8e521a4f // indirect - github.com/cockroachdb/redact v1.1.3 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect @@ -315,7 +305,6 @@ require ( github.com/evanphx/json-patch v5.6.0+incompatible // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect - github.com/getsentry/sentry-go v0.12.0 // indirect github.com/go-asn1-ber/asn1-ber v1.5.4 // indirect github.com/goccy/go-json v0.10.2 // indirect github.com/gogo/googleapis v1.4.1 // indirect @@ -328,13 +317,12 @@ require ( github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect github.com/grafana/regexp v0.0.0-20221123153739-15dc172cd2db // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect - github.com/hashicorp/golang-lru/v2 v2.0.7 // @grafana/alerting-squad-backend + github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect; @grafana/alerting-squad-backend github.com/hashicorp/memberlist v0.5.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/invopop/yaml v0.2.0 // indirect github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect github.com/klauspost/cpuid/v2 v2.2.5 // indirect - github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-ieproxy v0.0.3 // indirect @@ -350,7 +338,6 @@ require ( github.com/redis/rueidis v1.0.16 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/rivo/uniseg v0.3.4 // indirect - github.com/rogpeppe/go-internal v1.11.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/segmentio/asm v1.2.0 // indirect github.com/shopspring/decimal v1.2.0 // indirect @@ -427,7 +414,7 @@ require ( github.com/imdario/mergo v0.3.16 // indirect github.com/klauspost/compress v1.17.4 // indirect github.com/kylelemons/godebug v1.1.0 // indirect - github.com/labstack/echo/v4 v4.10.2 // indirect + github.com/labstack/echo/v4 v4.11.1 // indirect github.com/labstack/gommon v0.4.0 // indirect github.com/mitchellh/go-wordwrap v1.0.1 // indirect github.com/mschoch/smat v0.2.0 // indirect @@ -440,7 +427,6 @@ require ( require ( github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df // indirect - github.com/go-errors/errors v1.4.2 // indirect github.com/golang-jwt/jwt/v5 v5.2.1 // indirect github.com/google/gnostic-models v0.6.8 // indirect github.com/grafana/grafana-openapi-client-go v0.0.0-20231213163343-bd475d63fb79 // @grafana/backend-platform @@ -486,9 +472,19 @@ require ( require github.com/jackc/pgx/v5 v5.5.5 // @grafana/oss-big-tent +require github.com/getkin/kin-openapi v0.120.0 // @grafana/grafana-as-code + require ( github.com/bahlo/generic-list-go v0.2.0 // indirect github.com/buger/jsonparser v1.1.1 // indirect + github.com/bytedance/sonic v1.9.1 // indirect + github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect + github.com/gabriel-vasile/mimetype v1.4.2 // indirect + github.com/gin-contrib/sse v0.1.0 // indirect + github.com/gin-gonic/gin v1.9.1 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-playground/validator/v10 v10.14.0 // indirect github.com/hashicorp/go-uuid v1.0.3 // indirect github.com/invopop/jsonschema v0.12.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect @@ -500,7 +496,13 @@ require ( github.com/jcmturner/goidentity/v6 v6.0.1 // indirect github.com/jcmturner/gokrb5/v8 v8.4.4 // indirect github.com/jcmturner/rpc/v2 v2.0.3 // indirect + github.com/leodido/go-urn v1.2.4 // indirect + github.com/pelletier/go-toml/v2 v2.0.8 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/ugorji/go/codec v1.2.11 // indirect github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect + github.com/yudai/pp v2.0.1+incompatible // indirect + golang.org/x/arch v0.3.0 // indirect ) // Use fork of crewjam/saml with fixes for some issues until changes get merged into upstream diff --git a/go.sum b/go.sum index 3e92878e262..6f0b28792fe 100644 --- a/go.sum +++ b/go.sum @@ -1181,7 +1181,6 @@ gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zum git.sr.ht/~sbinet/gg v0.3.1/go.mod h1:KGYtlADtqsqANL9ueOFkWymvzUvLMQllU5Ixo+8v3pc= github.com/99designs/basicauth-go v0.0.0-20160802081356-2a93ba0f464d/go.mod h1:3cARGAK9CfW3HoxCy1a0G4TKrdiKke8ftOMEOHyySYs= github.com/99designs/httpsignatures-go v0.0.0-20170731043157-88528bf4ca7e/go.mod h1:Xa6lInWHNQnuWoF0YPSsx+INFA9qk7/7pTjwb3PInkY= -github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/Azure/azure-amqp-common-go/v3 v3.2.1/go.mod h1:O6X1iYHP7s2x7NjUKsXVhkwWrQhxrd+d8/3rRadj4CI= github.com/Azure/azure-amqp-common-go/v3 v3.2.2/go.mod h1:O6X1iYHP7s2x7NjUKsXVhkwWrQhxrd+d8/3rRadj4CI= github.com/Azure/azure-pipeline-go v0.2.3 h1:7U9HBg1JFK3jHl5qmo4CTZKFTVgMwdFHMVtCdfBE21U= @@ -1278,8 +1277,6 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno= -github.com/CloudyKit/jet/v3 v3.0.0/go.mod h1:HKQPgSJmdK8hdoAbKUUWajkHyHo4RaU5rMdUywE7VMo= github.com/Code-Hex/go-generics-cache v1.3.1 h1:i8rLwyhoyhaerr7JpjtYjJZUcCbWOdiYO3fZXLiEC4g= github.com/Code-Hex/go-generics-cache v1.3.1/go.mod h1:qxcC9kRVrct9rHeiYpFWSoW1vxyillCVzX13KZG8dl4= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= @@ -1291,7 +1288,6 @@ github.com/HdrHistogram/hdrhistogram-go v1.1.2 h1:5IcZpTvzydCQeHzK4Ef/D5rrSqwxob github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c h1:RGWPOewvKIROun94nF7v2cua9qP+thov/7M50KEoeSU= github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod h1:X0CRv0ky0k6m906ixxpzmDRLvX58TFUKS2eePweuyxk= -github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= @@ -1320,7 +1316,6 @@ github.com/RoaringBitmap/real-roaring-datasets v0.0.0-20190726190000-eb7c87156f7 github.com/RoaringBitmap/roaring v0.9.1/go.mod h1:h1B7iIUOmnAeb5ytYMvnHJwxMc6LUrwBnzXWRuqTQUc= github.com/RoaringBitmap/roaring v0.9.4 h1:ckvZSX5gwCRaJYBNe7syNawCU5oruY9gQmjXlp4riwo= github.com/RoaringBitmap/roaring v0.9.4/go.mod h1:icnadbWcNyfEHlYdr+tDlOTih1Bf/h+rzPpv4sbomAA= -github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= @@ -1329,7 +1324,6 @@ github.com/VividCortex/mysqlerr v0.0.0-20170204212430-6c6b55f8796f/go.mod h1:f3H github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= github.com/agext/levenshtein v1.2.1 h1:QmvMAjj2aEICytGiWzmxoE0x2KZvE0fvmqMOfy2tjT8= github.com/agext/levenshtein v1.2.1/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= -github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= github.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9/go.mod h1:JynElWSGnm/4RlzPXRlREEwqTHAN3T56Bv2ITsFT3gY= github.com/ajstarks/deck/generate v0.0.0-20210309230005-c3f852c02e19/go.mod h1:T13YZdzov6OU0A1+RfKZiZN9ca6VeKdBdyDV+BY97Tk= github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= @@ -1447,7 +1441,6 @@ github.com/aws/smithy-go v1.11.2 h1:eG/N+CcUMAvsdffgMvjMKwfyDzIkjM6pfxMJ8Mzc6mE= github.com/aws/smithy-go v1.11.2/go.mod h1:3xHYmszWVx2c0kIwQeEVf9uSm4fYZt67FBJnwub1bgM= github.com/axiomhq/hyperloglog v0.0.0-20191112132149-a4c4c47bc57f h1:y06x6vGnFYfXUoVMbrcP1Uzpj4JG01eB5vRps9G8agM= github.com/axiomhq/hyperloglog v0.0.0-20191112132149-a4c4c47bc57f/go.mod h1:2stgcRjl6QmW+gU2h5E7BQXg4HU0gzxKWDuT5HviN9s= -github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg= github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A= @@ -1493,10 +1486,10 @@ github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b h1:L/QXpzIa3pOvUGt1D1lA5KjYhPBAN/3iWdP7xeFS9F0= github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA= -github.com/bsm/ginkgo/v2 v2.5.0 h1:aOAnND1T40wEdAtkGSkvSICWeQ8L3UASX7YVCqQx+eQ= -github.com/bsm/ginkgo/v2 v2.5.0/go.mod h1:AiKlXPm7ItEHNc/2+OkrNG4E0ITzojb9/xWzvQ9XZ9w= -github.com/bsm/gomega v1.20.0 h1:JhAwLmtRzXFTx2AkALSLa8ijZafntmhSoU63Ok18Uq8= -github.com/bsm/gomega v1.20.0/go.mod h1:JifAceMQ4crZIWYUKrlGcmbN3bqHogVTADMD2ATsbwk= +github.com/bsm/ginkgo/v2 v2.9.5 h1:rtVBYPs3+TC5iLUVOis1B9tjLTup7Cj5IfzosKtvTJ0= +github.com/bsm/ginkgo/v2 v2.9.5/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= +github.com/bsm/gomega v1.26.0 h1:LhQm+AFcgV2M0WyKroMASzAzCAJVpAxQXv4SaI9a69Y= +github.com/bsm/gomega v1.26.0/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= github.com/bufbuild/connect-go v1.10.0 h1:QAJ3G9A1OYQW2Jbk3DeoJbkCxuKArrvZgDt47mjdTbg= github.com/bufbuild/connect-go v1.10.0/go.mod h1:CAIePUgkDR5pAFaylSMtNK45ANQjp9JvpluG20rhpV8= github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZlaQsNA= @@ -1508,6 +1501,9 @@ github.com/buildkite/yaml v2.1.0+incompatible/go.mod h1:UoU8vbcwu1+vjZq01+KrpSeL github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/bwmarrin/snowflake v0.3.0 h1:xm67bEhkKh6ij1790JB83OujPR5CzNe8QuQqAgISZN0= github.com/bwmarrin/snowflake v0.3.0/go.mod h1:NdZxfVWX+oR6y2K0o6qAYv6gIOP9rjG0/E9WsDpxqwE= +github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= +github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= +github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= github.com/caio/go-tdigest v3.1.0+incompatible h1:uoVMJ3Q5lXmVLCCqaMGHLBWnbGoN6Lpu7OAUPR60cds= github.com/caio/go-tdigest v3.1.0+incompatible/go.mod h1:sHQM/ubZStBUmF1WbB8FAm8q9GjDajLC5T7ydxE3JHI= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= @@ -1530,6 +1526,9 @@ github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE= github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ= +github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= github.com/chromedp/cdproto v0.0.0-20230802225258-3cf4e6d46a89 h1:aPflPkRFkVwbW6dmcVqfgwp1i+UWGFH6VgR1Jim5Ygc= github.com/chromedp/cdproto v0.0.0-20230802225258-3cf4e6d46a89/go.mod h1:GKljq0VrfU4D5yc+2qA6OVr8pmO/MBbPEWqWQ/oqGEs= github.com/chromedp/chromedp v0.9.2/go.mod h1:LkSXJKONWTCHAfQasKFUZI+mxqS4tZqhmtGzzhLsnLs= @@ -1570,15 +1569,7 @@ github.com/cockroachdb/apd/v2 v2.0.2 h1:weh8u7Cneje73dDh+2tEVLUvyBc89iwepWCD8b80 github.com/cockroachdb/apd/v2 v2.0.2/go.mod h1:DDxRlzC2lo3/vSlmSoS7JkqbbrARPuFOGr0B9pvN3Gw= github.com/cockroachdb/cockroach-go v0.0.0-20181001143604-e0a95dfd547c/go.mod h1:XGLbWH/ujMcbPbhZq52Nv6UrCghb1yGn//133kEsvDk= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= -github.com/cockroachdb/datadriven v1.0.2/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= -github.com/cockroachdb/errors v1.9.1 h1:yFVvsI0VxmRShfawbt/laCIDy/mtTqqnvoNgiy5bEV8= -github.com/cockroachdb/errors v1.9.1/go.mod h1:2sxOtL2WIc096WSZqZ5h8fa17rdDq9HZOZLBCor4mBk= -github.com/cockroachdb/logtags v0.0.0-20211118104740-dabe8e521a4f h1:6jduT9Hfc0njg5jJ1DdKCFPdMBrp/mdZfCpa5h+WM74= -github.com/cockroachdb/logtags v0.0.0-20211118104740-dabe8e521a4f/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= -github.com/cockroachdb/redact v1.1.3 h1:AKZds10rFSIj7qADf0g46UixK8NNLwWTNdCIGS5wfSQ= -github.com/cockroachdb/redact v1.1.3/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= -github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= github.com/containerd/containerd v1.2.7/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= github.com/containerd/containerd v1.3.4/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= @@ -1621,16 +1612,14 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dchest/uniuri v0.0.0-20160212164326-8902c56451e9/go.mod h1:GgB8SF9nRG+GqaDtLcwJZsQFhcogVCJ79j4EdT0c2V4= -github.com/deepmap/oapi-codegen v1.12.4 h1:pPmn6qI9MuOtCz82WY2Xaw46EQjgvxednXXrP7g5Q2s= -github.com/deepmap/oapi-codegen v1.12.4/go.mod h1:3lgHGMu6myQ2vqbbTXH2H1o4eXFTGnFiDaOaKKl5yas= +github.com/deepmap/oapi-codegen v1.13.0 h1:cnFHelhsRQbYvanCUAbRSn/ZpkUb1HPRlQcu8YqSORQ= +github.com/deepmap/oapi-codegen v1.13.0/go.mod h1:Amy7tbubKY9qkZOXqymI3Z6xSbndmu+atMJheLdyg44= github.com/denisenkom/go-mssqldb v0.0.0-20190515213511-eb9f6a1743f3/go.mod h1:zAg7JM8CkOJ43xKXIj7eRO9kmWm/TW578qo+oDO6tuM= github.com/denisenkom/go-mssqldb v0.12.0/go.mod h1:iiK0YP1ZeepvmBQk/QpLEhhTNJgfzrpArPY/aFvc9yU= github.com/dennwc/varint v1.0.0 h1:kGNFFSSw8ToIy3obO/kKr8U9GZYUAxQEVuix4zfDWzE= github.com/dennwc/varint v1.0.0/go.mod h1:hnItb35rvZvJrbTALZtY/iQfDs48JKRG1RPpgziApxA= github.com/devigned/tab v0.1.1/go.mod h1:XG9mPq0dFghrYvoBF3xdRrJzSTX1b7IQrvaL9mzjeJY= -github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= -github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-metro v0.0.0-20180109044635-280f6062b5bc/go.mod h1:c9O8+fpSOX1DM8cPNSkX/qsBWdkD4yd2dpciOWQjpBw= github.com/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140 h1:y7y0Oa6UawqTFPCDw9JG6pdKt4F9pAhHv0B7FMGaGD0= github.com/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140/go.mod h1:c9O8+fpSOX1DM8cPNSkX/qsBWdkD4yd2dpciOWQjpBw= @@ -1681,7 +1670,6 @@ github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/edsrzf/mmap-go v1.1.0 h1:6EUwBLQ/Mcr1EYLE4Tn1VdW1A4ckqCQWZBw8Hr0kjpQ= github.com/edsrzf/mmap-go v1.1.0/go.mod h1:19H/e8pUPLicwkyNgOykDXkJ9F0MHE+Z52B8EIth78Q= -github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= github.com/elazarl/goproxy v0.0.0-20230731152917-f99041a5c027 h1:1L0aalTpPz7YlMxETKpmQoWMBkeiuorElZIXoNmgiPE= github.com/elazarl/goproxy v0.0.0-20230731152917-f99041a5c027/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8= @@ -1719,11 +1707,9 @@ github.com/envoyproxy/protoc-gen-validate v1.0.1/go.mod h1:0vj8bNkYbSTNS2PIyH87K github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE= github.com/envoyproxy/protoc-gen-validate v1.0.4 h1:gVPz/FMfvh57HdSJQyvBtF00j8JU4zdyUgIUNhlgg0A= github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew= -github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U= github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= @@ -1732,7 +1718,6 @@ github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYF github.com/fatih/color v1.14.1/go.mod h1:2oHN61fhTpgcxD3TSWCgKDiH1+x4OiDVVGH8WlgGZGg= github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= -github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= @@ -1754,27 +1739,23 @@ github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyT github.com/fsouza/fake-gcs-server v1.7.0/go.mod h1:5XIRs4YvwNbNoz+1JF8j6KLAyDh7RHGAyAK3EP2EsNk= github.com/fullstorydev/grpchan v1.1.1 h1:heQqIJlAv5Cnks9a70GRL2EJke6QQoUB25VGR6TZQas= github.com/fullstorydev/grpchan v1.1.1/go.mod h1:f4HpiV8V6htfY/K44GWV1ESQzHBTq7DinhzqQ95lpgc= -github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc= +github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= +github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= github.com/gchaincl/sqlhooks v1.3.0 h1:yKPXxW9a5CjXaVf2HkQn6wn7TZARvbAOAelr3H8vK2Y= github.com/gchaincl/sqlhooks v1.3.0/go.mod h1:9BypXnereMT0+Ys8WGWHqzgkkOfHIhyeUCqXC24ra34= github.com/getkin/kin-openapi v0.120.0 h1:MqJcNJFrMDFNc07iwE8iFC5eT2k/NPUFDIpNeiZv8Jg= github.com/getkin/kin-openapi v0.120.0/go.mod h1:PCWw/lfBrJY4HcdqE3jj+QFkaFK8ABoqo7PvqVhXXqw= -github.com/getsentry/sentry-go v0.12.0 h1:era7g0re5iY13bHSdN/xMkyV+5zZppjRVQhZrXCaEIk= -github.com/getsentry/sentry-go v0.12.0/go.mod h1:NSap0JBYWzHND8oMbyi0+XZhUalc1TBdRL1M71JZW2c= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32 h1:Mn26/9ZMNWSw9C9ERFA1PUxfmGpolnw2v0bKOREu5ew= github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32/go.mod h1:GIjDIg/heH5DOkXY3YJ/wNhfHsQHoXGjl8G8amsYQ1I= -github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= +github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= -github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM= github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= github.com/gin-gonic/gin v1.7.3/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY= +github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= +github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= github.com/go-asn1-ber/asn1-ber v1.5.4 h1:vXT6d/FNDiELJnLb6hGNa309LMsrCoYFvpwHDF0+Y1A= github.com/go-asn1-ber/asn1-ber v1.5.4/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= -github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= -github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= -github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= -github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-fonts/dejavu v0.1.0/go.mod h1:4Wt4I4OU2Nq9asgDCteaAaWZOV24E+0/Pwo0gppep4g= github.com/go-fonts/latin-modern v0.2.0/go.mod h1:rQVLdDMK+mK1xscDwsqM5J8U2jrRa3T0ecnM9pNujks= github.com/go-fonts/liberation v0.1.1/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= @@ -1817,7 +1798,6 @@ github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-logr/zapr v1.2.3 h1:a9vnzlIBPQBBkeaR9IuMUfmVOrQlkoC4YfPoFkX3T7A= github.com/go-logr/zapr v1.2.3/go.mod h1:eIauM6P8qSvTw5o2ez6UEAfGjQKrxQTl5EoK+Qa2oG4= -github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8= github.com/go-openapi/analysis v0.21.2/go.mod h1:HZwRk4RRisyG8vx2Oe6aqeSQcoxRp47Xkp3+K6q+LdY= github.com/go-openapi/analysis v0.21.4/go.mod h1:4zQ35W4neeZTqh3ol0rv/O8JBbka9QyAgQRPp9y3pfo= github.com/go-openapi/analysis v0.21.5/go.mod h1:25YcZosX9Lwz2wBsrFrrsL8bmjjXdlyP6zsr2AMy29M= @@ -1881,10 +1861,18 @@ github.com/go-openapi/validate v0.23.0/go.mod h1:EeiAZ5bmpSIOJV1WLfyYF9qp/B1ZgSa github.com/go-pdf/fpdf v0.5.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= github.com/go-pdf/fpdf v0.6.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= +github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= +github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= github.com/go-resty/resty/v2 v2.9.1/go.mod h1:4/GYJVjh9nhkhGR6AUNW3XhpDYNUr+Uvy9gV/VGZIy4= @@ -1961,11 +1949,9 @@ github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7a github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/gogo/status v1.1.0/go.mod h1:BFv9nrluPLmrS0EmGVvLaPNmRosr9KapBYd5/hpY1WM= github.com/gogo/status v1.1.1 h1:DuHXlSFHNKqTQ+/ACf5Vs6r4X/dH2EgIzR9Vr+H65kg= github.com/gogo/status v1.1.1/go.mod h1:jpG3dM5QPcqu19Hg8lkUhBFBa3TcLs1DG7+2Jqci7oU= github.com/golang-jwt/jwt v3.2.1+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= -github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang-jwt/jwt/v4 v4.4.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= @@ -2033,7 +2019,6 @@ github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219 h1:utua3L2IbQJmauC5IXdEA547bcoU5dozgQAfc8Onsg4= github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219/go.mod h1:/X8TswGSh1pIozq4ZwCfxS0WA5JGXguxk94ar/4c87Y= -github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= @@ -2163,9 +2148,11 @@ github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2z github.com/gorilla/mux v1.7.1/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= -github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= -github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= +github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= +github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ= github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= +github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI= github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= @@ -2190,8 +2177,6 @@ github.com/grafana/gofpdf v0.0.0-20231002120153-857cc45be447 h1:jxJJ5z0GxqhWFbQU github.com/grafana/gofpdf v0.0.0-20231002120153-857cc45be447/go.mod h1:IxsY6mns6Q5sAnWcrptrgUrSglTZJXH/kXr9nbpb/9I= github.com/grafana/grafana-aws-sdk v0.25.0 h1:XNi3iA/C/KPArmVbQfbwKQROaIotd38nCRjNE6P1UP0= github.com/grafana/grafana-aws-sdk v0.25.0/go.mod h1:3zghFF6edrxn0d6k6X9HpGZXDH+VfA+MwD2Pc/9X0ec= -github.com/grafana/grafana-azure-sdk-go v1.13.1 h1:zYw5kNYf4zS4mG+yuB0Izn1Z4rsrPdLLivWF2JHUXPk= -github.com/grafana/grafana-azure-sdk-go v1.13.1/go.mod h1:SAlwLdEuox4vw8ZaeQwnepYXnhznnQQdstJbcw8LH68= github.com/grafana/grafana-azure-sdk-go/v2 v2.0.1 h1:a/zb8uX7EvmS2YAFbYPyGEnZP8jMp7WppAm05Qtunok= github.com/grafana/grafana-azure-sdk-go/v2 v2.0.1/go.mod h1:nW7pr7POOGafhyOrq8V0ouXBcXTmpRCer3sDAfeSV+Y= github.com/grafana/grafana-google-sdk-go v0.1.0 h1:LKGY8z2DSxKjYfr2flZsWgTRTZ6HGQbTqewE3JvRaNA= @@ -2209,8 +2194,6 @@ github.com/grafana/grafana/pkg/promlib v0.0.2 h1:yy7iwHlHH7Hl/n7ix9+RPIKg3CcKCAS github.com/grafana/grafana/pkg/promlib v0.0.2/go.mod h1:3El4NlsfALz8QQCbEGHGFvJUG+538QLMuALRhZ3pcoo= github.com/grafana/grafana/pkg/util/xorm v0.0.1 h1:72QZjxWIWpSeOF8ob4aMV058kfgZyeetkAB8dmeti2o= github.com/grafana/grafana/pkg/util/xorm v0.0.1/go.mod h1:eNfbB9f2jM8o9RfwqwjY8SYm5tvowJ8Ly+iE4P9rXII= -github.com/grafana/kindsys v0.0.0-20230508162304-452481b63482 h1:1YNoeIhii4UIIQpCPU+EXidnqf449d0C3ZntAEt4KSo= -github.com/grafana/kindsys v0.0.0-20230508162304-452481b63482/go.mod h1:GNcfpy5+SY6RVbNGQW264gC0r336Dm+0zgQ5vt6+M8Y= github.com/grafana/prometheus-alertmanager v0.25.1-0.20240208102907-e82436ce63e6 h1:CBm0rwLCPDyarg9/bHJ50rBLYmyMDoyCWpgRMITZhdA= github.com/grafana/prometheus-alertmanager v0.25.1-0.20240208102907-e82436ce63e6/go.mod h1:8Ia/R3urPmbzJ8OsdvmZvIprDwvwmYCmUbwBL+jlPOE= github.com/grafana/pyroscope-go/godeltaprof v0.1.6 h1:nEdZ8louGAplSvIJi1HVp7kWvFvdiiYg3COLlTwJiFo= @@ -2226,8 +2209,6 @@ github.com/grafana/sqlds/v3 v3.2.0 h1:WXuYEaFfiCvgm8kK2ixx44/zAEjFzCylA2+RF3GBqZ github.com/grafana/sqlds/v3 v3.2.0/go.mod h1:kH0WuHUR3j0Q7IEymbm2JiaPckUhRCbqjV9ajaBAnmM= github.com/grafana/tempo v1.5.1-0.20230524121406-1dc1bfe7085b h1:mDlkqgTEJuK7vjPG44f3ZMtId5AAYLWHvBVbiGqIOOQ= github.com/grafana/tempo v1.5.1-0.20230524121406-1dc1bfe7085b/go.mod h1:UK7kTP5llPeRcGBOe5mm4QTNTd0k/mAqTVSOFdDH6AU= -github.com/grafana/thema v0.0.0-20230712153715-375c1b45f3ed h1:TMtHc+B0SSNw2in6Ro1dAiBYSPRp4NzKgndFDfupt18= -github.com/grafana/thema v0.0.0-20230712153715-375c1b45f3ed/go.mod h1:3zLJnssFRPCnebCBRlq53t5LgYv9P1mbj0XMozZMTww= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= @@ -2340,7 +2321,6 @@ github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= github.com/hudl/fargo v1.4.0/go.mod h1:9Ai6uvFy5fQNq6VPKtg+Ceq1+eTY4nKUlR2JElEOcDo= -github.com/hydrogen18/memlistener v0.0.0-20200120041712-dcc25e7acd91/go.mod h1:qEIFzExnS6016fRpRfxrExeVn2gbClQA99gQhnIcdhE= github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= @@ -2351,7 +2331,6 @@ github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJ github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= -github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= @@ -2368,11 +2347,6 @@ github.com/invopop/yaml v0.2.0 h1:7zky/qH+O0DwAyoobXUqvVBwgBFRxKoQ/3FjcVpjTMY= github.com/invopop/yaml v0.2.0/go.mod h1:2XuRLgs/ouIrW3XNzuNj7J3Nvu/Dig5MXvbCEdiBN3Q= github.com/ionos-cloud/sdk-go/v6 v6.1.10 h1:3815Q2Hw/wc4cJ8wD7bwfsmDsdfIEp80B7BQMj0YP2w= github.com/ionos-cloud/sdk-go/v6 v6.1.10/go.mod h1:EzEgRIDxBELvfoa/uBN0kOQaqovLjUWEB7iW4/Q+t4k= -github.com/iris-contrib/blackfriday v2.0.0+incompatible/go.mod h1:UzZ2bDEoaSGPbkg6SAB4att1aAwTmVIx/5gCVqeyUdI= -github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/+fafWORmlnuysV2EMP8MW+qe0= -github.com/iris-contrib/jade v1.1.3/go.mod h1:H/geBymxJhShH5kecoiOCSssPX7QWYH7UaeZTSWddIk= -github.com/iris-contrib/pongo2 v0.0.1/go.mod h1:Ssh+00+3GAZqSQb30AvBRNxBx7rf0GqwkjqxNd0u65g= -github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw= github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= @@ -2477,15 +2451,9 @@ github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7V github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= -github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8= github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4= github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= -github.com/kataras/golog v0.0.10/go.mod h1:yJ8YKCmyL+nWjERB90Qwn+bdyBZsaQwU3bTVFgkFIp8= -github.com/kataras/iris/v12 v12.1.8/go.mod h1:LMYy4VlP67TQ3Zgriz8RE2h2kMZV2SgMYbq3UhfoFmE= -github.com/kataras/neffos v0.0.14/go.mod h1:8lqADm8PnbeFfL7CLXh1WHw53dG27MC3pgi2R1rmoTE= -github.com/kataras/pio v0.0.2/go.mod h1:hAoW0t9UmXi4R5Oyq5Z4irTbaTsOemSrDGUtaTl7Dro= -github.com/kataras/sitemap v0.0.5/go.mod h1:KY2eugMKiPwsJgx7+U103YZehfvNGOXURubcGyk0Bz8= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= @@ -2494,8 +2462,6 @@ github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/asmfmt v1.3.2 h1:4Ri7ox3EwapiOjCki+hw14RyKk201CN4rzyCJRFLpK4= github.com/klauspost/asmfmt v1.3.2/go.mod h1:AG8TuvYojzulgDAMCnYn50l/5QV3Bs/tp6j0HLHbNSE= -github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= -github.com/klauspost/compress v1.9.7/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.13.1/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= @@ -2505,7 +2471,6 @@ github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHU github.com/klauspost/compress v1.17.3/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4= github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= -github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= @@ -2533,16 +2498,16 @@ github.com/kshvakov/clickhouse v1.3.5/go.mod h1:DMzX7FxRymoNkVgizH0DWAL8Cur7wHLg github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/labstack/echo/v4 v4.5.0/go.mod h1:czIriw4a0C1dFun+ObrXp7ok03xON0N1awStJ6ArI7Y= -github.com/labstack/echo/v4 v4.10.2 h1:n1jAhnq/elIFTHr1EYpiYtyKgx4RW9ccVgkqByZaN2M= -github.com/labstack/echo/v4 v4.10.2/go.mod h1:OEyqf2//K1DFdE57vw2DRgWY0M7s65IVQO2FzvI4J5k= -github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= +github.com/labstack/echo/v4 v4.11.1 h1:dEpLU2FLg4UVmvCGPuk/APjlH6GDpbEPti61srUUUs4= +github.com/labstack/echo/v4 v4.11.1/go.mod h1:YuYRTSM3CHs2ybfrL8Px48bO6BAnYIN4l8wSTMP6BDQ= github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8= github.com/labstack/gommon v0.4.0/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM= github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80/go.mod h1:imJHygn/1yfhB7XSJJKlFZKl/J+dCPAknuiaGOshXAs= github.com/leesper/go_rng v0.0.0-20190531154944-a612b043e353 h1:X/79QL0b4YJVO5+OsPH9rF2u428CIrGL/jLmPsoOQQ4= github.com/leesper/go_rng v0.0.0-20190531154944-a612b043e353/go.mod h1:N0SVk0uhy+E1PZ3C9ctsPRlvOPAFPkCNlcPBDkt0N3U= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= +github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= +github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= @@ -2583,7 +2548,6 @@ github.com/mattetti/filebuffer v1.0.1 h1:gG7pyfnSIZCxdoKq+cPa8T0hhYtD9NxCdI4D7PT github.com/mattetti/filebuffer v1.0.1/go.mod h1:YdMURNDOttIiruleeVr6f56OrMc+MydEnTcXwtkxNVs= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= -github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= @@ -2600,7 +2564,6 @@ github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNx github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= @@ -2611,22 +2574,19 @@ github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APP github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= -github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= -github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= +github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v1.14.14/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/mattn/go-sqlite3 v1.14.19 h1:fhGleo2h1p8tVChob4I9HpmVFIAkKGpiukdrgQbWfGI= github.com/mattn/go-sqlite3 v1.14.19/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= -github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k= github.com/maxatome/go-testdeep v1.12.0/go.mod h1:lPZc/HAcJMP92l7yI6TRz1aZN5URwUBUAfUNvrclaNM= -github.com/mediocregopher/radix/v3 v3.4.2/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i4n7wVopoX3x7Bv8= -github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc= github.com/microsoft/go-mssqldb v1.6.1-0.20240214161942-b65008136246 h1:KT4vTYcHqj5C5hMK5kSpyAk7MnFqfHVWLL4VqMq66S8= github.com/microsoft/go-mssqldb v1.6.1-0.20240214161942-b65008136246/go.mod h1:00mDtPbeQCRGC1HwOOR5K/gr30P1NcEG0vx6Kbv2aJU= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= @@ -2703,7 +2663,6 @@ github.com/montanaflynn/stats v0.7.0/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= -github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= github.com/mpvl/unique v0.0.0-20150818121801-cbe035fff7de h1:D5x39vF5KCwKQaw+OC9ZPiLVHXz3UFw2+psEX+gYcto= github.com/mpvl/unique v0.0.0-20150818121801-cbe035fff7de/go.mod h1:kJun4WP5gFuHZgRjZUWWuH1DTxCtxbHDOIJsudS8jzY= github.com/mschoch/smat v0.2.0 h1:8imxQsjDm8yFEAVBe7azKmKSgzSkZXDuKkSq9374khM= @@ -2746,7 +2705,6 @@ github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= @@ -2819,6 +2777,8 @@ github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/9 github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas= +github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= +github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= github.com/performancecopilot/speed/v4 v4.0.0/go.mod h1:qxrSyuDGrTOWfV+uKRFhfxw6h/4HXRGUiZiufxo49BM= github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s= @@ -2834,8 +2794,6 @@ github.com/pierrec/lz4/v4 v4.1.8/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuR github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pierrec/lz4/v4 v4.1.18 h1:xaKrnTkyoqfh1YItXl56+6KJNVYWlEEPuAQW9xsplYQ= github.com/pierrec/lz4/v4 v4.1.18/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= -github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= -github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA= github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4/go.mod h1:N6UoU20jOqggOuDwUaBQpluzLNDqif3kq9z2wpdYEfQ= github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= @@ -2924,8 +2882,8 @@ github.com/prometheus/prometheus v0.49.0/go.mod h1:aDogiyqmv3aBIWDb5z5Sdcxuuf2BO github.com/protocolbuffers/txtpbfmt v0.0.0-20220428173112-74888fd59c2b h1:zd/2RNzIRkoGGMjE+YIsZ85CnDIz672JK2F3Zl4vux4= github.com/protocolbuffers/txtpbfmt v0.0.0-20220428173112-74888fd59c2b/go.mod h1:KjY0wibdYKc4DYkerHSbguaf3JeIPGhNJBp2BNiFH78= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= -github.com/redis/go-redis/v9 v9.0.2 h1:BA426Zqe/7r56kCcvxYLWe1mkaz71LKF77GwgFzSxfE= -github.com/redis/go-redis/v9 v9.0.2/go.mod h1:/xDTe9EF1LM61hek62Poq2nzQSGj0xSrEtEHbBQevps= +github.com/redis/go-redis/v9 v9.1.0 h1:137FnGdk+EQdCbye1FW+qOEcY5S+SpY9T0NiuqvtfMY= +github.com/redis/go-redis/v9 v9.1.0/go.mod h1:urWj3He21Dj5k4TK1y59xH8Uj6ATueP8AH1cY3lZl4c= github.com/redis/rueidis v1.0.16 h1:ieB3AqZe9GcuTWZL8PFu1Mfn+pfqjBZAJEZh7zOcwSI= github.com/redis/rueidis v1.0.16/go.mod h1:8B+r5wdnjwK3lTFml5VtxjzGOQAC+5UmujoD12pDrEo= github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= @@ -2944,7 +2902,6 @@ github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= -github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= @@ -2971,7 +2928,6 @@ github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0 github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/scaleway/scaleway-sdk-go v1.0.0-beta.21 h1:yWfiTPwYxB0l5fGMhl/G+liULugVIHD9AU77iNLrURQ= github.com/scaleway/scaleway-sdk-go v1.0.0-beta.21/go.mod h1:fCa7OJZ/9DRTnOKmxvT6pn+LPWUptQAmHF/SBJUGEcg= -github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g= github.com/scottlepp/go-duck v0.0.15 h1:qrSF3pXlXAA4a7uxAfLYajqXLkeBjv8iW1wPdSfkMj0= github.com/scottlepp/go-duck v0.0.15/go.mod h1:GL+hHuKdueJRrFCduwBc7A7TQk+Tetc5BPXPVtduihY= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= @@ -2981,7 +2937,6 @@ github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys= github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= github.com/segmentio/encoding v0.3.6 h1:E6lVLyDPseWEulBmCmAKPanDd3jiyGDo5gMcugCRwZQ= github.com/segmentio/encoding v0.3.6/go.mod h1:n0JeuIqEQrQoPDGsjo8UNd1iA0U8d8+oHAA4E3G3OxM= -github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= github.com/shoenig/test v0.6.6/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= @@ -3079,19 +3034,19 @@ github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1 github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75 h1:6fotK7otjonDflCTK0BCfls4SPy3NcCVb5dqqmbRknE= github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75/go.mod h1:KO6IkyS8Y3j8OdNO85qEYBsRPuteD+YciPomcXdrMnk= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= +github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ua-parser/uap-go v0.0.0-20211112212520-00c877edfe0f h1:A+MmlgpvrHLeUP8dkBVn4Pnf5Bp5Yk2OALm7SEJLLE8= github.com/ua-parser/uap-go v0.0.0-20211112212520-00c877edfe0f/go.mod h1:OBcG9bn7sHtXgarhUEb3OfCnNsgtGnkVf41ilSZ3K3E= github.com/uber/jaeger-client-go v2.30.0+incompatible h1:D6wyKGCecFaSRUpo8lCVbaOOb6ThwMmTEbhRwtKR97o= github.com/uber/jaeger-client-go v2.30.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= github.com/uber/jaeger-lib v2.4.1+incompatible h1:td4jdvLcExb4cBISKIpHuGoVXh+dVKhn2Um6rjCsSsg= github.com/uber/jaeger-lib v2.4.1+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U= -github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= -github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= -github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0= -github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= +github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= +github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/unknwon/bra v0.0.0-20200517080246-1e3013ecaff8 h1:aVGB3YnaS/JNfOW3tiHIlmNmTDg618va+eT0mVomgyI= github.com/unknwon/bra v0.0.0-20200517080246-1e3013ecaff8/go.mod h1:fVle4kNr08ydeohzYafr20oZzbAkhQT39gKK/pFQ5M4= github.com/unknwon/com v1.0.1 h1:3d1LTxD+Lnf3soQiD4Cp/0BRB+Rsa/+RTvz8GMMzIXs= @@ -3104,15 +3059,11 @@ github.com/urfave/cli v1.22.14 h1:ebbhrRiGK2i4naQJr+1Xj92HXZCrK7MsyTS/ob3HnAk= github.com/urfave/cli v1.22.14/go.mod h1:X0eDS6pD6Exaclxm99NJ3FiCDRED7vIHpx2mDOHLvkA= github.com/urfave/cli/v2 v2.25.0 h1:ykdZKuQey2zq0yin/l7JOm9Mh+pg72ngYMeB0ABn6q8= github.com/urfave/cli/v2 v2.25.0/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc= -github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasthttp v1.6.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w= -github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= -github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= github.com/vectordotdev/go-datemath v0.1.1-0.20220323213446-f3954d0b18ae h1:oyiy3uBj1F4O3AaFh7hUGBrJjAssJhKyAbwxtkslxqo= github.com/vectordotdev/go-datemath v0.1.1-0.20220323213446-f3954d0b18ae/go.mod h1:PnwzbSst7KD3vpBzzlntZU5gjVa455Uqa5QPiKSYJzQ= github.com/vultr/govultr/v2 v2.17.2 h1:gej/rwr91Puc/tgh+j33p/BLR16UrIPnSr+AIwYWZQs= @@ -3145,9 +3096,6 @@ github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRT github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= github.com/xwb1989/sqlparser v0.0.0-20180606152119-120387863bf2 h1:zzrxE1FKn5ryBNl9eKOeqQ58Y/Qpo3Q9QNxKHX5uzzQ= github.com/xwb1989/sqlparser v0.0.0-20180606152119-120387863bf2/go.mod h1:hzfGeIUDq/j97IG+FhNqkowIyEcD88LrW6fyU3K3WqY= -github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI= -github.com/yalue/merged_fs v1.2.2 h1:vXHTpJBluJryju7BBpytr3PDIkzsPMpiEknxVGPhN/I= -github.com/yalue/merged_fs v1.2.2/go.mod h1:WqqchfVYQyclV2tnR7wtRhBddzBvLVR83Cjw9BKQw0M= github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= github.com/yudai/gojsondiff v1.0.0 h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCOA= github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= @@ -3301,6 +3249,9 @@ go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= gocloud.dev v0.25.0 h1:Y7vDq8xj7SyM848KXf32Krda2e6jQ4CLh/mTeCSqXtk= gocloud.dev v0.25.0/go.mod h1:7HegHVCYZrMiU3IE1qtnzf/vRrDwLYnRNR3EhWX8x9Y= +golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= +golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -3316,7 +3267,6 @@ golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -3326,7 +3276,6 @@ golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210314154223-e6e6c4f2bb5b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= @@ -3441,7 +3390,6 @@ golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190424112056-4829fb13d2c6/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -3452,7 +3400,6 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191112182307-2180aed22343/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -3490,7 +3437,6 @@ golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210917221730-978cfadd31cf/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211008194852-3b03d305991f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211020060615-d418f374d309/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= @@ -3622,7 +3568,6 @@ golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -3796,7 +3741,6 @@ golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20220224211638-0e9765cccd65/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -3809,14 +3753,12 @@ golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181221001348-537d06c36207/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190327201419-c70d86f8b7cf/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190329151228-23e29df326fe/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190416151739-9c9e1878f421/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= @@ -4332,18 +4274,14 @@ gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMy gopkg.in/fsnotify/fsnotify.v1 v1.4.7 h1:XNNYLJHt73EyYiCZi6+xjupS9CpvmiDgjPTAjrBlQbo= gopkg.in/fsnotify/fsnotify.v1 v1.4.7/go.mod h1:Fyux9zXlo4rWoMSIzpn9fDAYjalPqJ/K1qJ27s+7ltE= gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= -gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= -gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.66.6/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/mail.v2 v2.3.1 h1:WYFn/oANrAGP2C0dcV6/pbkPzv8yGzqTjPmTeO7qoXk= gopkg.in/mail.v2 v2.3.1/go.mod h1:htwXN1Qh09vZJ1NVKxQqHPBaCBbzKhp5GzuJEA4VJWw= -gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= @@ -4361,7 +4299,6 @@ gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= -gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/kinds/constraint.cue b/kinds/constraint.cue deleted file mode 100644 index 2bc9f6c16c9..00000000000 --- a/kinds/constraint.cue +++ /dev/null @@ -1,7 +0,0 @@ -package kind - -import "github.com/grafana/kindsys" - -// In each child directory, the set of .cue files with 'package kind' -// must be an instance of kindsys.Core - a declaration of a core kind. -kindsys.Core diff --git a/kinds/gen.go b/kinds/gen.go index 32b7be8eba6..f0a1441cded 100644 --- a/kinds/gen.go +++ b/kinds/gen.go @@ -15,37 +15,49 @@ import ( "sort" "strings" - "cuelang.org/go/cue/errors" + "cuelang.org/go/cue" + "cuelang.org/go/cue/cuecontext" + "cuelang.org/go/cue/load" "github.com/grafana/codejen" "github.com/grafana/cuetsy" - "github.com/grafana/kindsys" - "github.com/grafana/grafana/pkg/codegen" - "github.com/grafana/grafana/pkg/cuectx" ) +// CoreDefParentPath is the path, relative to the repository root, where +// each child directory is expected to contain .cue files defining one +// Core kind. +var CoreDefParentPath = "kinds" + +// TSCoreKindParentPath is the path, relative to the repository root, to the directory that +// contains one directory per kind, full of generated TS kind output: types and default consts. +var TSCoreKindParentPath = filepath.Join("packages", "grafana-schema", "src", "raw") + func main() { if len(os.Args) > 1 { - fmt.Fprintf(os.Stderr, "plugin thema code generator does not currently accept any arguments\n, got %q", os.Args) + fmt.Fprintf(os.Stderr, "code generator does not currently accept any arguments\n, got %q", os.Args) os.Exit(1) } // Core kinds composite code generator. Produces all generated code in // grafana/grafana that derives from core kinds. - coreKindsGen := codejen.JennyListWithNamer(func(def kindsys.Kind) string { - return def.Props().Common().MachineName + coreKindsGen := codejen.JennyListWithNamer(func(def codegen.SchemaForGen) string { + return def.Name }) // All the jennies that comprise the core kinds generator pipeline coreKindsGen.Append( &codegen.GoSpecJenny{}, - codegen.LatestMajorsOrXJenny(cuectx.TSCoreKindParentPath), + &codegen.K8ResourcesJenny{}, + &codegen.CoreRegistryJenny{}, + codegen.LatestMajorsOrXJenny(TSCoreKindParentPath), codegen.TSVeneerIndexJenny(filepath.Join("packages", "grafana-schema", "src")), ) header := codegen.SlashHeaderMapper("kinds/gen.go") coreKindsGen.AddPostprocessors(header) + ctx := cuecontext.New() + cwd, err := os.Getwd() if err != nil { fmt.Fprintf(os.Stderr, "could not get working directory: %s", err) @@ -53,29 +65,15 @@ func main() { } groot := filepath.Dir(cwd) - rt := cuectx.GrafanaThemaRuntime() - var all []kindsys.Kind - - f := os.DirFS(filepath.Join(groot, cuectx.CoreDefParentPath)) + f := os.DirFS(filepath.Join(groot, CoreDefParentPath)) kinddirs := elsedie(fs.ReadDir(f, "."))("error reading core kind fs root directory") - for _, kinddir := range kinddirs { - if !kinddir.IsDir() { - continue - } - rel := filepath.Join(cuectx.CoreDefParentPath, kinddir.Name()) - def, err := cuectx.LoadCoreKindDef(rel, rt.Context(), nil) - if err != nil { - die(fmt.Errorf("%s is not a valid kind: %s", rel, errors.Details(err, nil))) - } - if def.Properties.MachineName != kinddir.Name() { - die(fmt.Errorf("%s: kind's machine name (%s) must equal parent dir name (%s)", rel, def.Properties.Name, kinddir.Name())) - } - - all = append(all, elsedie(kindsys.BindCore(rt, def))(rel)) + all, err := loadCueFiles(ctx, kinddirs) + if err != nil { + die(err) } sort.Slice(all, func(i, j int) bool { - return nameFor(all[i].Props()) < nameFor(all[j].Props()) + return all[i].Name < all[j].Name }) jfs, err := coreKindsGen.GenerateFS(all...) @@ -83,22 +81,12 @@ func main() { die(fmt.Errorf("core kinddirs codegen failed: %w", err)) } - commfsys := elsedie(genCommon(filepath.Join(groot, "pkg", "kindsys")))("common schemas failed") + commfsys := elsedie(genCommon(ctx, groot))("common schemas failed") commfsys = elsedie(commfsys.Map(header))("failed gen header on common fsys") if err = jfs.Merge(commfsys); err != nil { die(err) } - // Merging k8 resources - rawResources, err := genRawResources(kinddirs) - if err != nil { - die(err) - } - - if err = jfs.Merge(rawResources); err != nil { - die(err) - } - if _, set := os.LookupEnv("CODEGEN_VERIFY"); set { if err = jfs.Verify(context.Background(), groot); err != nil { die(fmt.Errorf("generated code is out of sync with inputs:\n%s\nrun `make gen-cue` to regenerate", err)) @@ -108,43 +96,28 @@ func main() { } } -func nameFor(m kindsys.SomeKindProperties) string { - switch x := m.(type) { - case kindsys.CoreProperties: - return x.Name - case kindsys.CustomProperties: - return x.Name - case kindsys.ComposableProperties: - return x.Name - default: - // unreachable so long as all the possibilities in KindProperties have switch branches - panic("unreachable") - } -} - type dummyCommonJenny struct{} -func genCommon(kp string) (*codejen.FS, error) { +func genCommon(ctx *cue.Context, groot string) (*codejen.FS, error) { fsys := codejen.NewFS() - - // kp := filepath.Join("pkg", "kindsys") path := filepath.Join("packages", "grafana-schema", "src", "common") - // Grab all the common_* files from kindsys and load them in - dfsys := os.DirFS(kp) - matches := elsedie(fs.Glob(dfsys, "common_*.cue"))("could not glob kindsys cue files") - for _, fname := range matches { - fpath := filepath.Join(path, strings.TrimPrefix(fname, "common_")) - fpath = fpath[:len(fpath)-4] + "_gen.cue" - data := elsedie(fs.ReadFile(dfsys, fname))("error reading " + fname) - _ = fsys.Add(*codejen.NewFile(fpath, data, dummyCommonJenny{})) - } fsys = elsedie(fsys.Map(packageMapper))("failed remapping fs") - v, err := cuectx.BuildGrafanaInstance(nil, path, "", nil) - if err != nil { - return nil, err + commonFiles := make([]string, 0) + filepath.WalkDir(filepath.Join(groot, path), func(path string, d fs.DirEntry, err error) error { + if d.IsDir() || filepath.Ext(d.Name()) != ".cue" { + return nil + } + commonFiles = append(commonFiles, path) + return nil + }) + + instance := load.Instances(commonFiles, &load.Config{})[0] + if instance.Err != nil { + return nil, instance.Err } + v := ctx.BuildInstance(instance) b := elsedie(cuetsy.Generate(v, cuetsy.Config{ Export: true, }))("failed to generate common schema TS") @@ -186,26 +159,8 @@ func die(err error) { os.Exit(1) } -// Resource generation without using Thema -func genRawResources(dirs []os.DirEntry) (*codejen.FS, error) { - jenny := codejen.JennyListWithNamer[[]codegen.CueSchema](func(_ []codegen.CueSchema) string { - return "RawResources" - }) - - jenny.Append( - &codegen.K8ResourcesJenny{}, - &codegen.CoreRegistryJenny{}, - ) - - header := codegen.SlashHeaderMapper("kinds/gen.go") - jenny.AddPostprocessors(header) - - return jenny.GenerateFS(loadCueFiles(dirs)) -} - -func loadCueFiles(dirs []os.DirEntry) []codegen.CueSchema { - ctx := cuectx.GrafanaCUEContext() - values := make([]codegen.CueSchema, 0) +func loadCueFiles(ctx *cue.Context, dirs []os.DirEntry) ([]codegen.SchemaForGen, error) { + values := make([]codegen.SchemaForGen, 0) for _, dir := range dirs { if !dir.IsDir() { continue @@ -225,13 +180,33 @@ func loadCueFiles(dirs []os.DirEntry) []codegen.CueSchema { os.Exit(1) } - sch := codegen.CueSchema{ - FilePath: "./" + filepath.Join(cuectx.CoreDefParentPath, entry), - CueFile: ctx.CompileBytes(cueFile), + v := ctx.CompileBytes(cueFile) + name, err := getSchemaName(v) + if err != nil { + return nil, err + } + + sch := codegen.SchemaForGen{ + Name: name, + FilePath: "./" + filepath.Join(CoreDefParentPath, entry), + CueFile: v, + IsGroup: false, + OutputName: strings.ToLower(name), } values = append(values, sch) } - return values + return values, nil +} + +func getSchemaName(v cue.Value) (string, error) { + namePath := v.LookupPath(cue.ParsePath("name")) + name, err := namePath.String() + if err != nil { + return "", fmt.Errorf("file doesn't have name field set: %s", err) + } + + name = strings.Replace(name, "-", "_", -1) + return name, nil } diff --git a/pkg/codegen/generators.go b/pkg/codegen/generators.go index 6aadfd45ae8..35cee5de1ca 100644 --- a/pkg/codegen/generators.go +++ b/pkg/codegen/generators.go @@ -7,14 +7,12 @@ import ( "cuelang.org/go/cue" "github.com/grafana/codejen" - "github.com/grafana/kindsys" - "github.com/grafana/thema" ) -type OneToOne codejen.OneToOne[kindsys.Kind] -type OneToMany codejen.OneToMany[kindsys.Kind] -type ManyToOne codejen.ManyToOne[kindsys.Kind] -type ManyToMany codejen.ManyToMany[kindsys.Kind] +type OneToOne codejen.OneToOne[SchemaForGen] +type OneToMany codejen.OneToMany[SchemaForGen] +type ManyToOne codejen.ManyToOne[SchemaForGen] +type ManyToMany codejen.ManyToMany[SchemaForGen] // SlashHeaderMapper produces a FileMapper that injects a comment header onto // a [codejen.File] indicating the main generator that produced it (via the provided @@ -47,21 +45,10 @@ func SlashHeaderMapper(maingen string) codejen.FileMapper { } } -// SchemaForGen is an intermediate values type for jennies that holds both a thema.Schema, -// and values relevant to generating the schema that should properly, eventually, be in -// thema itself. -// -// TODO this will be replaced by thema-native constructs type SchemaForGen struct { - // The PascalCase name of the schematized type. - Name string - // The schema to be rendered for the type itself. - Schema thema.Schema - // Whether the schema is grouped. See https://github.com/grafana/thema/issues/62 - IsGroup bool -} - -type CueSchema struct { - CueFile cue.Value - FilePath string + Name string + CueFile cue.Value + FilePath string + IsGroup bool + OutputName string // Some TS output files are capitalised and others not. } diff --git a/pkg/codegen/generators/decorators.go b/pkg/codegen/generators/decorators.go new file mode 100644 index 00000000000..5d9500f6a54 --- /dev/null +++ b/pkg/codegen/generators/decorators.go @@ -0,0 +1,282 @@ +package generators + +import ( + "fmt" + "regexp" + "strings" + "unicode" + + "github.com/dave/dst" + "github.com/dave/dst/dstutil" +) + +// depointerizer returns an AST manipulator that removes redundant +// pointer indirection from the defined types. +func depointerizer() dstutil.ApplyFunc { + return func(c *dstutil.Cursor) bool { + switch x := c.Node().(type) { + case *dst.Field: + if s, is := x.Type.(*dst.StarExpr); is { + switch deref := depoint(s).(type) { + case *dst.ArrayType, *dst.MapType: + x.Type = deref + } + } + } + return true + } +} + +func depoint(e dst.Expr) dst.Expr { + if star, is := e.(*dst.StarExpr); is { + return star.X + } + return e +} + +func setStar(e dst.Expr) string { + if _, is := e.(*dst.StarExpr); is { + return "*" + } + return "" +} + +func fixTODOComments() dstutil.ApplyFunc { + return func(cursor *dstutil.Cursor) bool { + switch f := cursor.Node().(type) { + case *dst.File: + for _, d := range f.Decls { + if isTypeSpec(d) { + removeGoFieldComment(d.Decorations().Start.All()) + } + fixTODOComment(d.Decorations().Start.All()) + } + case *dst.Field: + if len(f.Names) > 0 { + removeGoFieldComment(f.Decorations().Start.All()) + } + } + + return true + } +} + +func fixTODOComment(comments []string) { + todoRegex := regexp.MustCompile("(//) (.*) (TODO.*)") + if len(comments) > 0 { + comments[0] = todoRegex.ReplaceAllString(comments[0], "$1 $3") + } +} + +func removeGoFieldComment(comments []string) { + todoRegex := regexp.MustCompile("(//) ([A-Z].*?) ([A-Z]?.*?) (.*)") + if len(comments) > 0 { + matches := todoRegex.FindAllStringSubmatch(comments[0], -1) + if len(matches) > 0 { + if strings.EqualFold(matches[0][3], matches[0][2]) { + comments[0] = fmt.Sprintf("%s %s %s", matches[0][1], matches[0][3], matches[0][4]) + } else { + r := []rune(matches[0][3]) + if !unicode.IsLower(r[0]) { + comments[0] = fmt.Sprintf("%s %s %s", matches[0][1], matches[0][3], matches[0][4]) + } + } + } + } +} + +func isTypeSpec(d dst.Decl) bool { + gd, ok := d.(*dst.GenDecl) + if !ok { + return false + } + + _, is := gd.Specs[0].(*dst.TypeSpec) + return is +} + +// It fixes the "generic" fields. It happens when a value in cue could be different structs. +// For Go it generates a struct with a json.RawMessage field inside and multiple functions to map it between the different possibilities. +func fixRawData() dstutil.ApplyFunc { + return func(c *dstutil.Cursor) bool { + f, is := c.Node().(*dst.File) + if !is { + return false + } + + rawFields := make(map[string]bool) + existingRawFields := make(map[string]bool) + for _, decl := range f.Decls { + switch x := decl.(type) { + // Find the structs that only contains one json.RawMessage inside + case *dst.GenDecl: + for _, t := range x.Specs { + if ts, ok := t.(*dst.TypeSpec); ok { + if tp, ok := ts.Type.(*dst.StructType); ok && len(tp.Fields.List) == 1 { + if fn, ok := tp.Fields.List[0].Type.(*dst.SelectorExpr); ok { + if fmt.Sprintf("%s.%s", fn.X, fn.Sel.Name) == "json.RawMessage" { + rawFields[ts.Name.Name] = true + } + } + } + } + } + // Find the functions of the previous structs to verify that are the ones that we are looking for. + case *dst.FuncDecl: + for _, recv := range x.Recv.List { + fnType := depoint(recv.Type).(*dst.Ident).Name + if rawFields[fnType] { + existingRawFields[fnType] = true + } + } + } + } + + dstutil.Apply(f, func(c *dstutil.Cursor) bool { + switch x := c.Node().(type) { + // Delete the functions + case *dst.FuncDecl: + c.Delete() + case *dst.GenDecl: + // Deletes all "generics" generated for these json.RawMessage structs + comments := x.Decorations().Start.All() + if len(comments) > 0 { + if strings.HasSuffix(comments[0], "defines model for .") { + c.Delete() + } + } + for _, spec := range x.Specs { + if tp, ok := spec.(*dst.TypeSpec); ok { + // Delete structs with only json.RawMessage + if existingRawFields[tp.Name.Name] && tp.Name.Name != "MetricAggregation2" { + c.Delete() + continue + } + // Set types that was using these structs as interface{} + if st, ok := tp.Type.(*dst.StructType); ok { + iterateStruct(st, withoutRawData(existingRawFields)) + } + if mt, ok := tp.Type.(*dst.MapType); ok { + iterateMap(mt, withoutRawData(existingRawFields)) + } + if at, ok := tp.Type.(*dst.ArrayType); ok { + iterateArray(at, withoutRawData(existingRawFields)) + } + } + } + } + return true + }, nil) + + return true + } +} + +// Fixes type name containing underscores in the generated Go files +func fixUnderscoreInTypeName() dstutil.ApplyFunc { + return func(c *dstutil.Cursor) bool { + switch x := c.Node().(type) { + case *dst.GenDecl: + if specs, isType := x.Specs[0].(*dst.TypeSpec); isType { + if strings.Contains(specs.Name.Name, "_") { + oldName := specs.Name.Name + specs.Name.Name = strings.ReplaceAll(specs.Name.Name, "_", "") + x.Decs.Start[0] = strings.ReplaceAll(x.Decs.Start[0], oldName, specs.Name.Name) + } + if st, ok := specs.Type.(*dst.StructType); ok { + iterateStruct(st, withoutUnderscore) + } + if mt, ok := specs.Type.(*dst.MapType); ok { + iterateMap(mt, withoutUnderscore) + } + if at, ok := specs.Type.(*dst.ArrayType); ok { + iterateArray(at, withoutUnderscore) + } + } + case *dst.Field: + findFieldsWithUnderscores(x) + } + return true + } +} + +func findFieldsWithUnderscores(x *dst.Field) { + switch t := x.Type.(type) { + case *dst.Ident: + withoutUnderscore(t) + case *dst.StarExpr: + if i, is := t.X.(*dst.Ident); is { + withoutUnderscore(i) + } + case *dst.ArrayType: + iterateArray(t, withoutUnderscore) + case *dst.MapType: + iterateMap(t, withoutUnderscore) + } +} + +func withoutUnderscore(i *dst.Ident) { + if strings.Contains(i.Name, "_") { + i.Name = strings.ReplaceAll(i.Name, "_", "") + } +} + +func withoutRawData(existingFields map[string]bool) func(ident *dst.Ident) { + return func(i *dst.Ident) { + if existingFields[i.Name] { + i.Name = setStar(i) + "any" + } + } +} + +func iterateStruct(s *dst.StructType, fn func(i *dst.Ident)) { + for i, f := range s.Fields.List { + switch mx := depoint(f.Type).(type) { + case *dst.Ident: + fn(mx) + case *dst.ArrayType: + iterateArray(mx, fn) + case *dst.MapType: + iterateMap(mx, fn) + case *dst.StructType: + iterateStruct(mx, fn) + case *dst.InterfaceType: + s.Fields.List[i].Type = interfaceToAny(f.Type) + } + } +} + +func iterateMap(s *dst.MapType, fn func(i *dst.Ident)) { + switch mx := s.Value.(type) { + case *dst.Ident: + fn(mx) + case *dst.ArrayType: + iterateArray(mx, fn) + case *dst.MapType: + iterateMap(mx, fn) + case *dst.InterfaceType: + s.Value = interfaceToAny(s.Value) + } +} + +func iterateArray(a *dst.ArrayType, fn func(i *dst.Ident)) { + switch mx := a.Elt.(type) { + case *dst.Ident: + fn(mx) + case *dst.ArrayType: + iterateArray(mx, fn) + case *dst.StructType: + iterateStruct(mx, fn) + case *dst.InterfaceType: + a.Elt = interfaceToAny(a.Elt) + } +} + +func interfaceToAny(i dst.Expr) dst.Expr { + star := "" + if _, is := i.(*dst.StarExpr); is { + star = "*" + } + + return &dst.Ident{Name: star + "any"} +} diff --git a/pkg/codegen/generators/go_generator.go b/pkg/codegen/generators/go_generator.go new file mode 100644 index 00000000000..a3744803dff --- /dev/null +++ b/pkg/codegen/generators/go_generator.go @@ -0,0 +1,193 @@ +package generators + +import ( + "bytes" + "fmt" + "go/parser" + "go/token" + "path/filepath" + "strings" + + "cuelang.org/go/cue" + "cuelang.org/go/pkg/encoding/yaml" + "github.com/dave/dst/decorator" + "github.com/dave/dst/dstutil" + "github.com/deepmap/oapi-codegen/pkg/codegen" + "github.com/getkin/kin-openapi/openapi3" + "golang.org/x/tools/imports" +) + +type GoConfig struct { + Config *OpenApiConfig + PackageName string + ApplyFuncs []dstutil.ApplyFunc +} + +func GenerateTypesGo(v cue.Value, cfg *GoConfig) ([]byte, error) { + if cfg == nil { + return nil, fmt.Errorf("configuration cannot be nil") + } + + applyFuncs := []dstutil.ApplyFunc{depointerizer(), fixRawData(), fixUnderscoreInTypeName(), fixTODOComments()} + applyFuncs = append(applyFuncs, cfg.ApplyFuncs...) + + f, err := generateOpenAPI(v, cfg.Config) + if err != nil { + return nil, err + } + + str, err := yaml.Marshal(v.Context().BuildFile(f)) + if err != nil { + return nil, fmt.Errorf("cue-yaml marshaling failed: %w", err) + } + + loader := openapi3.NewLoader() + oT, err := loader.LoadFromData([]byte(str)) + if err != nil { + return nil, fmt.Errorf("loading generated openapi failed: %w", err) + } + + schemaName, err := getSchemaName(v) + if err != nil { + return nil, err + } + + if cfg.PackageName == "" { + cfg.PackageName = schemaName + } + + // Hack to fix https://github.com/grafana/thema/pull/127 issue without importing + // to avoid to add the whole vendor in Grafana code + if cfg.PackageName == "dataquery" { + fixDataQuery(oT) + } + + ccfg := codegen.Configuration{ + PackageName: cfg.PackageName, + Compatibility: codegen.CompatibilityOptions{ + AlwaysPrefixEnumValues: true, + }, + Generate: codegen.GenerateOptions{ + Models: true, + }, + OutputOptions: codegen.OutputOptions{ + SkipPrune: true, + UserTemplates: map[string]string{ + "imports.tmpl": importstmpl, + }, + }, + } + + gostr, err := codegen.Generate(oT, ccfg) + if err != nil { + return nil, fmt.Errorf("openapi generation failed: %w", err) + } + + return postprocessGoFile(genGoFile{ + path: fmt.Sprintf("%s_type_gen.go", schemaName), + appliers: applyFuncs, + in: []byte(gostr), + }) +} + +type genGoFile struct { + path string + appliers []dstutil.ApplyFunc + in []byte +} + +func postprocessGoFile(cfg genGoFile) ([]byte, error) { + fname := sanitizeLabelString(filepath.Base(cfg.path)) + buf := new(bytes.Buffer) + fset := token.NewFileSet() + gf, err := decorator.ParseFile(fset, fname, string(cfg.in), parser.ParseComments) + if err != nil { + return nil, fmt.Errorf("error parsing generated file: %w", err) + } + + for _, af := range cfg.appliers { + dstutil.Apply(gf, af, nil) + } + + err = decorator.Fprint(buf, gf) + if err != nil { + return nil, fmt.Errorf("error formatting generated file: %w", err) + } + + byt, err := imports.Process(fname, buf.Bytes(), nil) + if err != nil { + return nil, fmt.Errorf("goimports processing of generated file failed: %w", err) + } + + // Compare imports before and after; warn about performance if some were added + gfa, _ := parser.ParseFile(fset, fname, string(byt), parser.ParseComments) + imap := make(map[string]bool) + for _, im := range gf.Imports { + imap[im.Path.Value] = true + } + var added []string + for _, im := range gfa.Imports { + if !imap[im.Path.Value] { + added = append(added, im.Path.Value) + } + } + + if len(added) != 0 { + // TODO improve the guidance in this error if/when we better abstract over imports to generate + return nil, fmt.Errorf("goimports added the following import statements to %s: \n\t%s\nRelying on goimports to find imports significantly slows down code generation. Either add these imports with an AST manipulation in cfg.ApplyFuncs, or set cfg.IgnoreDiscoveredImports to true", cfg.path, strings.Join(added, "\n\t")) + } + return byt, nil +} + +// fixDataQuery extends the properties for the AllOf schemas when a DataQuery exists. +// deep/oapi-codegen library ignores the properties of the models and only ones have references. +// It doesn't apply this change https://github.com/grafana/thema/pull/154 since it modifies the +// vendor implementation, and we don't import it. +func fixDataQuery(spec *openapi3.T) *openapi3.T { + for _, sch := range spec.Components.Schemas { + if sch.Value != nil && len(sch.Value.AllOf) > 0 { + for _, allOf := range sch.Value.AllOf { + for n, p := range allOf.Value.Properties { + sch.Value.Properties[n] = p + } + } + sch.Value.AllOf = nil + } + } + return spec +} + +// Almost all of the below imports are eliminated by dst transformers and calls +// to goimports - but if they're not present in the template, then the internal +// call to goimports that oapi-codegen makes will trigger a search for them, +// which can slow down codegen by orders of magnitude. +var importstmpl = `package {{ .PackageName }} + +import ( + "bytes" + "compress/gzip" + "context" + "encoding/base64" + "encoding/json" + "encoding/xml" + "errors" + "fmt" + "gopkg.in/yaml.v2" + "io" + "io/ioutil" + "os" + "net/http" + "net/url" + "path" + "strings" + "time" + + "github.com/deepmap/oapi-codegen/pkg/runtime" + openapi_types "github.com/deepmap/oapi-codegen/pkg/types" + "github.com/getkin/kin-openapi/openapi3" + "github.com/go-chi/chi/v5" + "github.com/labstack/echo/v4" + "github.com/gin-gonic/gin" + "github.com/gorilla/mux" +) +` diff --git a/pkg/codegen/generators/openapi_generator.go b/pkg/codegen/generators/openapi_generator.go new file mode 100644 index 00000000000..19e02aa5488 --- /dev/null +++ b/pkg/codegen/generators/openapi_generator.go @@ -0,0 +1,199 @@ +package generators + +import ( + "fmt" + "strings" + + "cuelang.org/go/cue" + "cuelang.org/go/cue/ast" + "cuelang.org/go/encoding/openapi" +) + +type OpenApiConfig struct { + Config *openapi.Config + IsGroup bool + RootName string + SubPath cue.Path +} + +func generateOpenAPI(v cue.Value, cfg *OpenApiConfig) (*ast.File, error) { + if cfg == nil { + return nil, fmt.Errorf("missing openapi configuration") + } + + if cfg.Config == nil { + cfg.Config = &openapi.Config{} + } + + name, err := getSchemaName(v) + if err != nil { + return nil, err + } + + gen := &oapiGen{ + cfg: cfg, + name: name, + val: v.LookupPath(cue.ParsePath("lineage.schemas[0].schema")), + subpath: cfg.SubPath, + bpath: v.LookupPath(cue.ParsePath("lineage.schemas[0]")).Path(), + } + + declFunc := genSchema + if cfg.IsGroup { + declFunc = genGroup + } + + decls, err := declFunc(gen) + + if err != nil { + return nil, err + } + + // TODO recursively sort output to improve stability of output + return &ast.File{ + Decls: []ast.Decl{ + ast.NewStruct( + "openapi", ast.NewString("3.0.0"), + "paths", ast.NewStruct(), + "components", ast.NewStruct( + "schemas", &ast.StructLit{Elts: decls}, + ), + ), + }, + }, nil +} + +type oapiGen struct { + cfg *OpenApiConfig + val cue.Value + subpath cue.Path + + // overall name for the generated oapi doc + name string + + // original NameFunc + onf func(cue.Value, cue.Path) string + + // full prefix path that leads up to the #SchemaDef, e.g. lin._sortedSchemas[0] + bpath cue.Path +} + +func genGroup(gen *oapiGen) ([]ast.Decl, error) { + ctx := gen.val.Context() + iter, err := gen.val.Fields(cue.Definitions(true), cue.Optional(true)) + if err != nil { + panic(fmt.Errorf("unreachable - should always be able to get iter for struct kinds: %w", err)) + } + + var decls []ast.Decl + for iter.Next() { + val, sel := iter.Value(), iter.Selector() + name := strings.Trim(sel.String(), "?#") + + v := ctx.CompileString(fmt.Sprintf("#%s: _", name)) + defpath := cue.MakePath(cue.Def(name)) + defsch := v.FillPath(defpath, val) + + cfgi := *gen.cfg.Config + cfgi.NameFunc = func(val cue.Value, path cue.Path) string { + return gen.nfSingle(val, path, defpath, name) + } + + part, err := openapi.Generate(defsch, &cfgi) + if err != nil { + return nil, fmt.Errorf("failed generation for grouped field %s: %w", sel, err) + } + + decls = append(decls, getSchemas(part)...) + } + + return decls, nil +} + +func genSchema(gen *oapiGen) ([]ast.Decl, error) { + hasSubpath := len(gen.cfg.SubPath.Selectors()) > 0 + name := sanitizeLabelString(gen.name) + if gen.cfg.RootName != "" { + name = gen.cfg.RootName + } else if hasSubpath { + sel := gen.cfg.SubPath.Selectors() + name = sel[len(sel)-1].String() + } + + val := gen.val + if hasSubpath { + for i, sel := range gen.cfg.SubPath.Selectors() { + if !gen.val.Allows(sel) { + return nil, fmt.Errorf("subpath %q not present in schema", cue.MakePath(gen.cfg.SubPath.Selectors()[:i+1]...)) + } + } + val = val.LookupPath(gen.cfg.SubPath) + } + + v := gen.val.Context().CompileString(fmt.Sprintf("#%s: _", name)) + defpath := cue.MakePath(cue.Def(name)) + defsch := v.FillPath(defpath, val) + + gen.cfg.Config.NameFunc = func(val cue.Value, path cue.Path) string { + return gen.nfSingle(val, path, defpath, name) + } + + f, err := openapi.Generate(defsch.Eval(), gen.cfg.Config) + if err != nil { + return nil, err + } + + return getSchemas(f), nil +} + +// For generating a single, our NameFunc must: +// - Eliminate any path prefixes on the element, both internal lineage and wrapping +// - Replace the name "_#schema" with the desired name +// - Call the user-provided NameFunc, if any +// - Remove CUE markers like #, !, ? +func (gen *oapiGen) nfSingle(val cue.Value, path, defpath cue.Path, name string) string { + tpath := trimPathPrefix(trimThemaPathPrefix(path, gen.bpath), defpath) + + if path.String() == "" || tpath.String() == defpath.String() { + return name + } + + if val == gen.val { + return "" + } + + if gen.onf != nil { + return gen.onf(val, tpath) + } + return strings.Trim(tpath.String(), "?#") +} + +func getSchemas(f *ast.File) []ast.Decl { + compos := orp(getFieldByLabel(f, "components")) + schemas := orp(getFieldByLabel(compos.Value, "schemas")) + return schemas.Value.(*ast.StructLit).Elts +} + +func orp[T any](t T, err error) T { + if err != nil { + panic(err) + } + return t +} + +func trimThemaPathPrefix(p, base cue.Path) cue.Path { + if !pathHasPrefix(p, base) { + return p + } + + rest := p.Selectors()[len(base.Selectors()):] + if len(rest) == 0 { + return cue.Path{} + } + switch rest[0].String() { + case "schema", "_#schema", "_join", "joinSchema": + return cue.MakePath(rest[1:]...) + default: + return cue.MakePath(rest...) + } +} diff --git a/pkg/codegen/generators/ts_generator.go b/pkg/codegen/generators/ts_generator.go new file mode 100644 index 00000000000..33321652079 --- /dev/null +++ b/pkg/codegen/generators/ts_generator.go @@ -0,0 +1,56 @@ +package generators + +import ( + "fmt" + + "cuelang.org/go/cue" + "cuelang.org/go/cue/cuecontext" + "github.com/grafana/cuetsy" + "github.com/grafana/cuetsy/ts" + "github.com/grafana/cuetsy/ts/ast" +) + +type TSConfig struct { + CuetsyConfig *cuetsy.Config + IsGroup bool + RootName string +} + +// GenerateTypesTS generates native TypeScript types and defaults corresponding to +// the provided Schema. +func GenerateTypesTS(v cue.Value, cfg *TSConfig) (*ast.File, error) { + if cfg == nil { + return nil, fmt.Errorf("configuration cannot be empty") + } + if cfg.CuetsyConfig == nil { + cfg.CuetsyConfig = &cuetsy.Config{ + Export: true, + } + } + + // Thema #schema was a unification between the schema and cue.TopKind(_). For any reason, without this unification, + // cuetsy fails finding some enums ¯\_(ツ)_/¯. + oldSchema := cuecontext.New().CompileBytes([]byte("_")) + schdef := v.LookupPath(cue.ParsePath("lineage.schemas[0].schema")).Unify(oldSchema) + tf, err := cuetsy.GenerateAST(schdef, *cfg.CuetsyConfig) + if err != nil { + return nil, fmt.Errorf("generating TS for child elements of schema failed: %w", err) + } + + file := &ts.File{ + Nodes: tf.Nodes, + } + + if !cfg.IsGroup { + top, err := cuetsy.GenerateSingleAST(cfg.RootName, schdef, cuetsy.TypeInterface) + if err != nil { + return nil, fmt.Errorf("generating TS for schema root failed: %w", err) + } + file.Nodes = append(file.Nodes, top.T) + if top.D != nil { + file.Nodes = append(file.Nodes, top.D) + } + } + + return file, nil +} diff --git a/pkg/codegen/generators/utils.go b/pkg/codegen/generators/utils.go new file mode 100644 index 00000000000..382e9ed2078 --- /dev/null +++ b/pkg/codegen/generators/utils.go @@ -0,0 +1,130 @@ +package generators + +import ( + "fmt" + "strconv" + "strings" + + "cuelang.org/go/cue" + "cuelang.org/go/cue/ast" + "cuelang.org/go/cue/token" +) + +// sanitizeLabelString strips characters from a string that are not allowed for +// use in a CUE label. +func sanitizeLabelString(s string) string { + return strings.Map(func(r rune) rune { + switch { + case r >= 'a' && r <= 'z': + fallthrough + case r >= 'A' && r <= 'Z': + fallthrough + case r >= '0' && r <= '9': + fallthrough + case r == '_': + return r + default: + return -1 + } + }, s) +} + +// trimPathPrefix strips the provided prefix from the provided path, if the +// prefix exists. +// +// If path and prefix are equivalent, and there is at least one additional +// selector in the provided path. +func trimPathPrefix(path, prefix cue.Path) cue.Path { + sels, psels := path.Selectors(), prefix.Selectors() + if len(sels) == 1 { + return path + } + var i int + for ; i < len(psels) && i < len(sels); i++ { + if !selEq(psels[i], sels[i]) { + break + } + } + return cue.MakePath(sels[i:]...) +} + +// selEq indicates whether two selectors are equivalent. Selectors are equivalent if +// they are either exactly equal, or if they are equal ignoring path optionality. +func selEq(s1, s2 cue.Selector) bool { + return s1 == s2 || s1.Optional() == s2.Optional() +} + +// getFieldByLabel returns the ast.Field with a given label from a struct-ish input. +func getFieldByLabel(n ast.Node, label string) (*ast.Field, error) { + var d []ast.Decl + switch x := n.(type) { + case *ast.File: + d = x.Decls + case *ast.StructLit: + d = x.Elts + default: + return nil, fmt.Errorf("not an *ast.File or *ast.StructLit") + } + + for _, el := range d { + if isFieldWithLabel(el, label) { + return el.(*ast.Field), nil + } + } + + return nil, fmt.Errorf("no field with label %q", label) +} + +func isFieldWithLabel(n ast.Node, label string) bool { + if x, is := n.(*ast.Field); is { + if l, is := x.Label.(*ast.BasicLit); is { + return strEq(l, label) + } + if l, is := x.Label.(*ast.Ident); is { + return identStrEq(l, label) + } + } + return false +} + +func strEq(lit *ast.BasicLit, str string) bool { + if lit.Kind != token.STRING { + return false + } + ls, _ := strconv.Unquote(lit.Value) + return str == ls || str == lit.Value +} + +func identStrEq(id *ast.Ident, str string) bool { + if str == id.Name { + return true + } + ls, _ := strconv.Unquote(id.Name) + return str == ls +} + +// pathHasPrefix tests whether the [cue.Path] p begins with prefix. +func pathHasPrefix(p, prefix cue.Path) bool { + ps, pres := p.Selectors(), prefix.Selectors() + if len(pres) > len(ps) { + return false + } + return pathsAreEq(ps[:len(pres)], pres) +} + +func pathsAreEq(p1s, p2s []cue.Selector) bool { + if len(p1s) != len(p2s) { + return false + } + for i := 0; i < len(p2s); i++ { + if !selEq(p2s[i], p1s[i]) { + return false + } + } + return true +} + +func getSchemaName(v cue.Value) (string, error) { + nameValue := v.LookupPath(cue.ParsePath("name")) + return nameValue.String() +} diff --git a/pkg/codegen/jenny_core_registry.go b/pkg/codegen/jenny_core_registry.go index 2db4702e96d..c2f77794406 100644 --- a/pkg/codegen/jenny_core_registry.go +++ b/pkg/codegen/jenny_core_registry.go @@ -7,7 +7,6 @@ import ( "path/filepath" "strings" - "cuelang.org/go/cue" "github.com/grafana/codejen" ) @@ -21,10 +20,10 @@ func (jenny *CoreRegistryJenny) JennyName() string { return "CoreRegistryJenny" } -func (jenny *CoreRegistryJenny) Generate(cueFiles []CueSchema) (codejen.Files, error) { +func (jenny *CoreRegistryJenny) Generate(cueFiles ...SchemaForGen) (codejen.Files, error) { schemas := make([]Schema, len(cueFiles)) for i, v := range cueFiles { - name, err := getSchemaName(v.CueFile) + name, err := getSchemaName(v.Name) if err != nil { return nil, err } @@ -51,12 +50,7 @@ func (jenny *CoreRegistryJenny) Generate(cueFiles []CueSchema) (codejen.Files, e return codejen.Files{*file}, nil } -func getSchemaName(v cue.Value) (string, error) { - name, err := getPackageName(v) - if err != nil { - return "", err - } - - name = strings.Replace(name, "-", "_", -1) - return strings.ToLower(name), nil +func getSchemaName(pkg string) (string, error) { + pkg = strings.Replace(pkg, "-", "_", -1) + return strings.ToLower(pkg), nil } diff --git a/pkg/codegen/jenny_eachmajor.go b/pkg/codegen/jenny_eachmajor.go index 5fcc83028d2..a0ba440b1f7 100644 --- a/pkg/codegen/jenny_eachmajor.go +++ b/pkg/codegen/jenny_eachmajor.go @@ -7,7 +7,6 @@ import ( "github.com/grafana/codejen" "github.com/grafana/cuetsy/ts" "github.com/grafana/cuetsy/ts/ast" - "github.com/grafana/kindsys" ) // LatestMajorsOrXJenny returns a jenny that repeats the input for the latest in each major version. @@ -27,28 +26,17 @@ func (j *lmox) JennyName() string { return "LatestMajorsOrXJenny" } -func (j *lmox) Generate(kind kindsys.Kind) (codejen.Files, error) { - // TODO remove this once codejen catches nils https://github.com/grafana/codejen/issues/5 - if kind == nil { - return nil, nil - } - - comm := kind.Props().Common() - sfg := SchemaForGen{ - Name: comm.Name, - IsGroup: true, - Schema: kind.Lineage().Latest(), - } - +func (j *lmox) Generate(sfg SchemaForGen) (codejen.Files, error) { + sfg.IsGroup = true f, err := j.inner.Generate(sfg) if err != nil { - return nil, fmt.Errorf("%s jenny failed on %s schema for %s: %w", j.inner.JennyName(), sfg.Schema.Version(), kind.Props().Common().Name, err) + return nil, fmt.Errorf("%s jenny failed for %s: %w", j.inner.JennyName(), sfg.Name, err) } if f == nil || !f.Exists() { return nil, nil } - f.RelativePath = filepath.Join(j.parentdir, comm.MachineName, "x", f.RelativePath) + f.RelativePath = filepath.Join(j.parentdir, sfg.OutputName, "x", f.RelativePath) f.From = append(f.From, j) return codejen.Files{*f}, nil } diff --git a/pkg/codegen/jenny_go_spec.go b/pkg/codegen/jenny_go_spec.go index 82cab5c3831..caefbdbbe4d 100644 --- a/pkg/codegen/jenny_go_spec.go +++ b/pkg/codegen/jenny_go_spec.go @@ -2,13 +2,12 @@ package codegen import ( "fmt" + "strings" "cuelang.org/go/cue" "github.com/dave/dst/dstutil" "github.com/grafana/codejen" - "github.com/grafana/kindsys" - "github.com/grafana/thema/encoding/gocode" - "github.com/grafana/thema/encoding/openapi" + "github.com/grafana/grafana/pkg/codegen/generators" ) type GoSpecJenny struct { @@ -19,19 +18,19 @@ func (jenny *GoSpecJenny) JennyName() string { return "GoResourceTypes" } -func (jenny *GoSpecJenny) Generate(kinds ...kindsys.Kind) (codejen.Files, error) { - files := make(codejen.Files, len(kinds)) - for i, v := range kinds { - name := v.Lineage().Name() - b, err := gocode.GenerateTypesOpenAPI(v.Lineage().Latest(), - &gocode.TypeConfigOpenAPI{ - Config: &openapi.Config{ - Group: false, +func (jenny *GoSpecJenny) Generate(sfg ...SchemaForGen) (codejen.Files, error) { + files := make(codejen.Files, len(sfg)) + for i, v := range sfg { + packageName := strings.ToLower(v.Name) + b, err := generators.GenerateTypesGo(v.CueFile, + &generators.GoConfig{ + Config: &generators.OpenApiConfig{ + IsGroup: false, RootName: "Spec", - Subpath: cue.MakePath(cue.Str("spec")), + SubPath: cue.MakePath(cue.Str("spec")), }, - PackageName: name, - ApplyFuncs: append(jenny.ApplyFuncs, PrefixDropper(v.Props().Common().Name)), + PackageName: packageName, + ApplyFuncs: append(jenny.ApplyFuncs, PrefixDropper(v.Name)), }, ) @@ -39,7 +38,7 @@ func (jenny *GoSpecJenny) Generate(kinds ...kindsys.Kind) (codejen.Files, error) return nil, err } - files[i] = *codejen.NewFile(fmt.Sprintf("pkg/kinds/%s/%s_spec_gen.go", name, name), b, jenny) + files[i] = *codejen.NewFile(fmt.Sprintf("pkg/kinds/%s/%s_spec_gen.go", packageName, packageName), b, jenny) } return files, nil diff --git a/pkg/codegen/jenny_k8_resources.go b/pkg/codegen/jenny_k8_resources.go index 547ca2bcc71..ccc84eeb4e5 100644 --- a/pkg/codegen/jenny_k8_resources.go +++ b/pkg/codegen/jenny_k8_resources.go @@ -18,25 +18,20 @@ func (jenny *K8ResourcesJenny) JennyName() string { return "K8ResourcesJenny" } -func (jenny *K8ResourcesJenny) Generate(cueFiles []CueSchema) (codejen.Files, error) { +func (jenny *K8ResourcesJenny) Generate(cueFiles ...SchemaForGen) (codejen.Files, error) { files := make(codejen.Files, 0) for _, val := range cueFiles { - pkg, err := getPackageName(val.CueFile) + resource, err := jenny.genResource(val.Name, val.CueFile) if err != nil { return nil, err } - resource, err := jenny.genResource(pkg, val.CueFile) + metadata, err := jenny.genMetadata(val.Name) if err != nil { return nil, err } - metadata, err := jenny.genMetadata(pkg) - if err != nil { - return nil, err - } - - status, err := jenny.genStatus(pkg) + status, err := jenny.genStatus(val.Name) if err != nil { return nil, err } @@ -100,15 +95,6 @@ func (jenny *K8ResourcesJenny) genStatus(pkg string) (codejen.File, error) { return *codejen.NewFile(fmt.Sprintf("pkg/kinds/%s/%s_status_gen.go", pkg, pkg), buf.Bytes(), jenny), nil } -func getPackageName(val cue.Value) (string, error) { - name := val.LookupPath(cue.ParsePath("name")) - pkg, err := name.String() - if err != nil { - return "", fmt.Errorf("file doesn't have name field set: %s", err) - } - return pkg, nil -} - func getVersion(val cue.Value) (string, error) { val = val.LookupPath(cue.ParsePath("lineage.schemas[0].version")) versionValues, err := val.List() diff --git a/pkg/codegen/jenny_ts_types.go b/pkg/codegen/jenny_ts_types.go index 3eb5b078d65..913788c51bb 100644 --- a/pkg/codegen/jenny_ts_types.go +++ b/pkg/codegen/jenny_ts_types.go @@ -4,17 +4,12 @@ import ( "github.com/grafana/codejen" "github.com/grafana/cuetsy" "github.com/grafana/cuetsy/ts/ast" - "github.com/grafana/grafana/pkg/cuectx" - "github.com/grafana/thema/encoding/typescript" + "github.com/grafana/grafana/pkg/codegen/generators" ) type ApplyFunc func(sfg SchemaForGen, file *ast.File) -// TSTypesJenny is a [OneToOne] that produces TypeScript types and -// defaults for a Thema schema. -// -// Thema's generic TS jenny will be able to replace this one once -// https://github.com/grafana/thema/issues/89 is complete. +// TSTypesJenny is a [OneToOne] that produces TypeScript types and defaults. type TSTypesJenny struct { ApplyFuncs []ApplyFunc } @@ -26,14 +21,13 @@ func (j TSTypesJenny) JennyName() string { } func (j TSTypesJenny) Generate(sfg SchemaForGen) (*codejen.File, error) { - // TODO allow using name instead of machine name in thema generator - f, err := typescript.GenerateTypes(sfg.Schema, &typescript.TypeConfig{ + f, err := generators.GenerateTypesTS(sfg.CueFile, &generators.TSConfig{ CuetsyConfig: &cuetsy.Config{ Export: true, - ImportMapper: cuectx.MapCUEImportToTS, + ImportMapper: MapCUEImportToTS, }, RootName: sfg.Name, - Group: sfg.IsGroup, + IsGroup: sfg.IsGroup, }) for _, renameFunc := range j.ApplyFuncs { @@ -44,5 +38,10 @@ func (j TSTypesJenny) Generate(sfg SchemaForGen) (*codejen.File, error) { return nil, err } - return codejen.NewFile(sfg.Schema.Lineage().Name()+"_types.gen.ts", []byte(f.String()), j), nil + outputName := sfg.Name + if sfg.OutputName != "" { + outputName = sfg.OutputName + } + + return codejen.NewFile(outputName+"_types.gen.ts", []byte(f.String()), j), nil } diff --git a/pkg/codegen/jenny_tsveneerindex.go b/pkg/codegen/jenny_tsveneerindex.go index 96160bdfdd2..87bea1da7b1 100644 --- a/pkg/codegen/jenny_tsveneerindex.go +++ b/pkg/codegen/jenny_tsveneerindex.go @@ -12,14 +12,9 @@ import ( "github.com/grafana/cuetsy" "github.com/grafana/cuetsy/ts" "github.com/grafana/cuetsy/ts/ast" - "github.com/grafana/grafana/pkg/cuectx" - "github.com/grafana/kindsys" - "github.com/grafana/thema" - "github.com/grafana/thema/encoding/typescript" + "github.com/grafana/grafana/pkg/codegen/generators" ) -var schPath = cue.MakePath(cue.Hid("_#schema", "github.com/grafana/thema")) - // TSVeneerIndexJenny generates an index.gen.ts file with references to all // generated TS types. Elements with the attribute @grafana(TSVeneer="type") are // exported from a handwritten file, rather than the raw generated types. @@ -43,19 +38,18 @@ func (gen *genTSVeneerIndex) JennyName() string { return "TSVeneerIndexJenny" } -func (gen *genTSVeneerIndex) Generate(kinds ...kindsys.Kind) (*codejen.File, error) { +func (gen *genTSVeneerIndex) Generate(sfg ...SchemaForGen) (*codejen.File, error) { tsf := new(ast.File) - for _, def := range kinds { - sch := def.Lineage().Latest() - f, err := typescript.GenerateTypes(sch, &typescript.TypeConfig{ + for _, def := range sfg { + f, err := generators.GenerateTypesTS(def.CueFile, &generators.TSConfig{ CuetsyConfig: &cuetsy.Config{ - ImportMapper: cuectx.MapCUEImportToTS, + ImportMapper: MapCUEImportToTS, }, - RootName: def.Props().Common().Name, - Group: def.Props().Common().LineageIsGroup, + RootName: def.Name, + IsGroup: def.IsGroup, }) if err != nil { - return nil, fmt.Errorf("%s: %w", def.Props().Common().Name, err) + return nil, fmt.Errorf("%s: %w", def.Name, err) } // The obvious approach would be calling renameSpecNode() here, same as in the ts resource jenny, // to rename the "spec" field to the name of the kind. But that was causing extra @@ -66,7 +60,7 @@ func (gen *genTSVeneerIndex) Generate(kinds ...kindsys.Kind) (*codejen.File, err elems, err := gen.extractTSIndexVeneerElements(def, f) if err != nil { - return nil, fmt.Errorf("%s: %w", def.Props().Common().Name, err) + return nil, fmt.Errorf("%s: %w", def.Name, err) } tsf.Nodes = append(tsf.Nodes, elems...) } @@ -74,12 +68,9 @@ func (gen *genTSVeneerIndex) Generate(kinds ...kindsys.Kind) (*codejen.File, err return codejen.NewFile(filepath.Join(gen.dir, "index.gen.ts"), []byte(tsf.String()), gen), nil } -func (gen *genTSVeneerIndex) extractTSIndexVeneerElements(def kindsys.Kind, tf *ast.File) ([]ast.Decl, error) { - lin := def.Lineage() - comm := def.Props().Common() - +func (gen *genTSVeneerIndex) extractTSIndexVeneerElements(def SchemaForGen, tf *ast.File) ([]ast.Decl, error) { // Check the root, then walk the tree - rootv := lin.Latest().Underlying().LookupPath(schPath) + rootv := def.CueFile.LookupPath(cue.ParsePath("lineage.schemas[0].schema")) var raw, custom, rawD, customD ast.Idents @@ -105,7 +96,7 @@ func (gen *genTSVeneerIndex) extractTSIndexVeneerElements(def kindsys.Kind, tf * } // Search the generated TS AST for the type and default def nodes - pair := findDeclNode(name, comm.Name, tf) + pair := findDeclNode(name, def.Name, tf) if pair.T == nil { // No generated type for this item, skip it return false @@ -152,29 +143,32 @@ func (gen *genTSVeneerIndex) extractTSIndexVeneerElements(def kindsys.Kind, tf * return nil, terr } - vpath := fmt.Sprintf("v%v", thema.Lineage.Latest(lin).Version()) - if def.Props().Common().Maturity.Less(kindsys.MaturityStable) { - vpath = "x" - } + vpath := "x" + machineName := strings.ToLower(def.Name) ret := make([]ast.Decl, 0) if len(raw) > 0 { ret = append(ret, ast.ExportSet{ - CommentList: []ast.Comment{ts.CommentFromString(fmt.Sprintf("Raw generated types from %s kind.", comm.Name), 80, false)}, + CommentList: []ast.Comment{ts.CommentFromString(fmt.Sprintf("Raw generated types from %s kind.", def.Name), 80, false)}, TypeOnly: true, Exports: raw, - From: ast.Str{Value: fmt.Sprintf("./raw/%s/%s/%s_types.gen", comm.MachineName, vpath, comm.MachineName)}, + From: ast.Str{Value: fmt.Sprintf("./raw/%s/%s/%s_types.gen", machineName, vpath, machineName)}, }) } if len(rawD) > 0 { ret = append(ret, ast.ExportSet{ - CommentList: []ast.Comment{ts.CommentFromString(fmt.Sprintf("Raw generated enums and default consts from %s kind.", lin.Name()), 80, false)}, + CommentList: []ast.Comment{ts.CommentFromString(fmt.Sprintf("Raw generated enums and default consts from %s kind.", machineName), 80, false)}, TypeOnly: false, Exports: rawD, - From: ast.Str{Value: fmt.Sprintf("./raw/%s/%s/%s_types.gen", comm.MachineName, vpath, comm.MachineName)}, + From: ast.Str{Value: fmt.Sprintf("./raw/%s/%s/%s_types.gen", machineName, vpath, machineName)}, }) } - vtfile := fmt.Sprintf("./veneer/%s.types", lin.Name()) + vtfile := fmt.Sprintf("./veneer/%s.types", machineName) + version, err := getVersion(def.CueFile) + if err != nil { + return nil, err + } + customstr := fmt.Sprintf(`// The following exported declarations correspond to types in the %s@%s kind's // schema with attribute @grafana(TSVeneer="type"). // @@ -184,7 +178,7 @@ func (gen *genTSVeneerIndex) extractTSIndexVeneerElements(def kindsys.Kind, tf * // and exports all the symbols in the list. // // TODO generate code such that tsc enforces type compatibility between raw and veneer decls`, - lin.Name(), thema.Lineage.Latest(lin).Version(), filepath.ToSlash(filepath.Join(gen.dir, vtfile))) + machineName, strings.ReplaceAll(version, "-", "."), filepath.ToSlash(filepath.Join(gen.dir, vtfile))) customComments := []ast.Comment{{Text: customstr}} if len(custom) > 0 { diff --git a/pkg/codegen/util_go.go b/pkg/codegen/util_go.go index faecaae57c7..54441c5dd31 100644 --- a/pkg/codegen/util_go.go +++ b/pkg/codegen/util_go.go @@ -27,21 +27,6 @@ func PrefixDropper(prefix string) dstutil.ApplyFunc { }).applyfunc } -// PrefixReplacer returns a dstutil.ApplyFunc that removes the provided prefix -// string when it appears as a leading sequence in type names, var names, and -// comments in a generated Go file. -// -// When an exact match for prefix is found, the provided replace string -// is substituted. -func PrefixReplacer(prefix, replace string) dstutil.ApplyFunc { - return (&prefixmod{ - prefix: prefix, - replace: replace, - rxpsuff: regexp.MustCompile(fmt.Sprintf(`%s([a-zA-Z_]+)`, prefix)), - rxp: regexp.MustCompile(fmt.Sprintf(`%s([\s.,;-])`, prefix)), - }).applyfunc -} - func depoint(e dst.Expr) dst.Expr { if star, is := e.(*dst.StarExpr); is { return star.X diff --git a/pkg/cuectx/util_ts.go b/pkg/codegen/util_ts.go similarity index 92% rename from pkg/cuectx/util_ts.go rename to pkg/codegen/util_ts.go index 4f3bb7a0d88..01f1efad920 100644 --- a/pkg/cuectx/util_ts.go +++ b/pkg/codegen/util_ts.go @@ -1,4 +1,4 @@ -package cuectx +package codegen import ( "fmt" @@ -13,8 +13,6 @@ import ( // indicates the import path should be dropped in the conversion to TS. Imports // not present in the list are not allowed, and code generation will fail. var importMap = map[string]string{ - "github.com/grafana/thema": "", - "github.com/grafana/kindsys": "", "github.com/grafana/grafana/pkg/plugins/pfs": "", "github.com/grafana/grafana/packages/grafana-schema/src/common": "@grafana/schema", } @@ -37,8 +35,6 @@ func init() { // Grafana kind definitions. func PermittedCUEImports() []string { return []string{ - "github.com/grafana/thema", - "github.com/grafana/kindsys", "github.com/grafana/grafana/pkg/plugins/pfs", "github.com/grafana/grafana/packages/grafana-schema/src/common", } diff --git a/pkg/cuectx/ctx.go b/pkg/cuectx/ctx.go deleted file mode 100644 index 038d61a95cd..00000000000 --- a/pkg/cuectx/ctx.go +++ /dev/null @@ -1,73 +0,0 @@ -// Package cuectx provides a single, central ["cuelang.org/go/cue".Context] and -// ["github.com/grafana/thema".Runtime] that can be used uniformly across -// Grafana, and related helper functions for loading Thema lineages. - -package cuectx - -import ( - "path/filepath" - "sync" - - "cuelang.org/go/cue" - "cuelang.org/go/cue/cuecontext" - "github.com/grafana/thema" - "github.com/grafana/thema/vmux" -) - -// CoreDefParentPath is the path, relative to the repository root, where -// each child directory is expected to contain .cue files defining one -// Core kind. -var CoreDefParentPath = "kinds" - -// GoCoreKindParentPath is the path, relative to the repository root, to the directory -// containing one directory per kind, full of generated Go kind output: types and bindings. -var GoCoreKindParentPath = filepath.Join("pkg", "kinds") - -// TSCoreKindParentPath is the path, relative to the repository root, to the directory that -// contains one directory per kind, full of generated TS kind output: types and default consts. -var TSCoreKindParentPath = filepath.Join("packages", "grafana-schema", "src", "raw") - -var ( - ctx *cue.Context - rt *thema.Runtime - once sync.Once -) - -func initContext() { - once.Do(func() { - ctx = cuecontext.New() - rt = thema.NewRuntime(ctx) - }) -} - -// GrafanaCUEContext returns Grafana's singleton instance of [cue.Context]. -// -// All code within grafana/grafana that needs a *cue.Context should get it -// from this function, when one was not otherwise provided. -func GrafanaCUEContext() *cue.Context { - initContext() - return ctx -} - -// GrafanaThemaRuntime returns Grafana's singleton instance of [thema.Runtime]. -// -// All code within grafana/grafana that needs a *thema.Runtime should get it -// from this function, when one was not otherwise provided. -func GrafanaThemaRuntime() *thema.Runtime { - initContext() - return rt -} - -// JSONtoCUE attempts to decode the given []byte into a cue.Value, relying on -// the central Grafana cue.Context provided in this package. -// -// The provided path argument determines the name given to the input bytes if -// later CUE operations (e.g. Thema validation) produce errors related to the -// returned cue.Value. -// -// This is a convenience function for one-off JSON decoding. It's wasteful to -// call it repeatedly. Most use cases should probably prefer making -// their own Thema/CUE decoders. -func JSONtoCUE(path string, b []byte) (cue.Value, error) { - return vmux.NewJSONCodec(path).Decode(GrafanaCUEContext(), b) -} diff --git a/pkg/cuectx/load.go b/pkg/cuectx/load.go deleted file mode 100644 index e42af45c434..00000000000 --- a/pkg/cuectx/load.go +++ /dev/null @@ -1,239 +0,0 @@ -package cuectx - -import ( - "fmt" - "io/fs" - "path/filepath" - "testing/fstest" - - "cuelang.org/go/cue" - "cuelang.org/go/cue/build" - "cuelang.org/go/cue/cuecontext" - "github.com/grafana/kindsys" - "github.com/grafana/thema" - "github.com/grafana/thema/load" - "github.com/yalue/merged_fs" - - "github.com/grafana/grafana" -) - -// LoadGrafanaInstancesWithThema loads CUE files containing a lineage -// representing some Grafana core model schema. It is expected to be used when -// implementing a thema.LineageFactory. -// -// This function primarily juggles paths to make CUE's loader happy. Provide the -// path from the grafana root to the directory containing the lineage.cue. The -// lineage.cue file must be the sole contents of the provided fs.FS. -// -// More details on underlying behavior can be found in the docs for github.com/grafana/thema/load.InstanceWithThema. -// -// TODO this approach is complicated and confusing, refactor to something understandable -func LoadGrafanaInstancesWithThema(path string, cueFS fs.FS, rt *thema.Runtime, opts ...thema.BindOption) (thema.Lineage, error) { - prefix := filepath.FromSlash(path) - fs, err := prefixWithGrafanaCUE(prefix, cueFS) - if err != nil { - return nil, err - } - inst, err := load.InstanceWithThema(fs, prefix) - - // Need to trick loading by creating the embedded file and - // making it look like a module in the root dir. - if err != nil { - return nil, err - } - - val := rt.Context().BuildInstance(inst) - - lin, err := thema.BindLineage(val, rt, opts...) - if err != nil { - return nil, err - } - - return lin, nil -} - -// prefixWithGrafanaCUE constructs an fs.FS that merges the provided fs.FS with -// the embedded FS containing Grafana's core CUE files, [grafana.CueSchemaFS]. -// The provided prefix should be the relative path from the grafana repository -// root to the directory root of the provided inputfs. -// -// The returned fs.FS is suitable for passing to a CUE loader, such as [load.InstanceWithThema]. -func prefixWithGrafanaCUE(prefix string, inputfs fs.FS) (fs.FS, error) { - m, err := prefixFS(prefix, inputfs) - if err != nil { - return nil, err - } - return merged_fs.NewMergedFS(m, grafana.CueSchemaFS), nil -} - -// TODO such a waste, replace with stateless impl that just transforms paths on the fly -func prefixFS(prefix string, fsys fs.FS) (fs.FS, error) { - m := make(fstest.MapFS) - - prefix = filepath.FromSlash(prefix) - err := fs.WalkDir(fsys, ".", func(path string, d fs.DirEntry, err error) error { - if err != nil { - return err - } - - if d.IsDir() { - return nil - } - - b, err := fs.ReadFile(fsys, filepath.ToSlash(path)) - if err != nil { - return err - } - // fstest can recognize only forward slashes. - m[filepath.ToSlash(filepath.Join(prefix, path))] = &fstest.MapFile{Data: b} - return nil - }) - return m, err -} - -// LoadGrafanaInstance wraps [load.InstanceWithThema] to load a -// [*build.Instance] corresponding to a particular path within the -// github.com/grafana/grafana CUE module. -// -// This allows resolution of imports within the grafana or thema CUE modules to -// work correctly and consistently by relying on the embedded FS at -// [grafana.CueSchemaFS] and [thema.CueFS]. -// -// relpath should be a relative path path within [grafana.CueSchemaFS] to be -// loaded. Optionally, the caller may provide an additional fs.FS via the -// overlay parameter, which will be merged with [grafana.CueSchemaFS] at -// relpath, and loaded. -// -// pkg, if non-empty, is set as the value of -// ["cuelang.org/go/cue/load".Config.Package]. If the CUE package to be loaded -// is the same as the parent directory name, it should be omitted. -// -// NOTE this function will be deprecated in favor of a more generic loader -func LoadGrafanaInstance(relpath string, pkg string, overlay fs.FS) (*build.Instance, error) { - // notes about how this crap needs to work - // - // Within grafana/grafana, need: - // - pass in an fs.FS that, in its root, contains the .cue files to load - // - has no cue.mod - // - gets prefixed with the appropriate path within grafana/grafana - // - and merged with all the other .cue files from grafana/grafana - // notes about how this crap needs to work - // - // Need a prefixing instance loader that: - // - can take multiple fs.FS, each one representing a CUE module (nesting?) - // - reconcile at most one of the provided fs with cwd - // - behavior must differ depending on whether cwd is in a cue module - // - behavior should(?) be controllable depending on - relpath = filepath.ToSlash(relpath) - - var f fs.FS = grafana.CueSchemaFS - // merge the kindsys filesystem with ours for the kind categories - f = merged_fs.NewMergedFS(kindsys.CueSchemaFS, f) - - var err error - if overlay != nil { - f, err = prefixWithGrafanaCUE(relpath, overlay) - if err != nil { - return nil, err - } - - // merge the kindsys filesystem with ours for the kind categories - f = merged_fs.NewMergedFS(kindsys.CueSchemaFS, f) - } - - if pkg != "" { - return load.InstanceWithThema(f, relpath, load.Package(pkg)) - } - return load.InstanceWithThema(f, relpath) -} - -// BuildGrafanaInstance wraps [LoadGrafanaInstance], additionally building -// the returned [*build.Instance] into a [cue.Value]. -// -// An error is returned if: -// - The underlying call to [LoadGrafanaInstance] returns an error -// - The built [cue.Value] has an error ([cue.Value.Err] returns non-nil) -// -// NOTE this function will be deprecated in favor of a more generic builder -func BuildGrafanaInstance(ctx *cue.Context, relpath string, pkg string, overlay fs.FS) (cue.Value, error) { - bi, err := LoadGrafanaInstance(relpath, pkg, overlay) - if err != nil { - return cue.Value{}, err - } - - if ctx == nil { - ctx = GrafanaCUEContext() - } - v := ctx.BuildInstance(bi) - if v.Err() != nil { - return v, fmt.Errorf("%s not a valid CUE instance: %w", relpath, v.Err()) - } - return v, nil -} - -// LoadInstanceWithGrafana loads a [*build.Instance] from .cue files -// in the provided modFS as ["cuelang.org/go/cue/load".Instances], but -// fulfilling any imports of CUE packages under: -// -// - github.com/grafana/grafana -// - github.com/grafana/thema -// -// This function is modeled after [load.InstanceWithThema]. It has the same -// signature and expectations for the modFS. -// -// Attempting to use this func to load files within the -// github.com/grafana/grafana CUE module will result in an error. Use -// [LoadGrafanaInstance] instead. -// -// NOTE This function will be deprecated in favor of a more generic loader -func LoadInstanceWithGrafana(fsys fs.FS, dir string, opts ...load.Option) (*build.Instance, error) { - if modf, err := fs.ReadFile(fsys, "cue.mod/module.cue"); err != nil { - // delegate error handling - return load.InstanceWithThema(fsys, dir, opts...) - } else if modname, err := cuecontext.New().CompileBytes(modf).LookupPath(cue.MakePath(cue.Str("module"))).String(); err != nil { - // delegate error handling - return load.InstanceWithThema(fsys, dir, opts...) - } else if modname == "github.com/grafana/grafana" { - return nil, fmt.Errorf("use cuectx.LoadGrafanaInstance to load .cue files within github.com/grafana/grafana CUE module") - } - - // TODO wasteful, doing this every time - make that stateless prefixfs! - depFS, err := prefixFS("cue.mod/pkg/github.com/grafana/grafana", grafana.CueSchemaFS) - if err != nil { - panic(err) - } - // TODO wasteful, doing this every time - make that stateless prefixfs! - kindsysFS, err := prefixFS("cue.mod/pkg/github.com/grafana/kindsys", kindsys.CueSchemaFS) - if err != nil { - panic(err) - } - - allTheFs := merged_fs.MergeMultiple(kindsysFS, depFS, fsys) - - // FIXME remove grafana from cue.mod/pkg if it exists, otherwise external thing can inject files to be loaded - return load.InstanceWithThema(allTheFs, dir, opts...) -} - -// LoadCoreKindDef loads and validates a core kind definition of the kind -// category indicated by the type parameter. On success, it returns a [Def] -// which contains the entire contents of the kind definition. -// -// defpath is the path to the directory containing the core kind definition, -// relative to the root of the caller's repository. For example, under -// dashboards are in "kinds/dashboard". -func LoadCoreKindDef(defpath string, ctx *cue.Context, overlay fs.FS) (kindsys.Def[kindsys.CoreProperties], error) { - vk, err := BuildGrafanaInstance(ctx, defpath, "kind", overlay) - if err != nil { - return kindsys.Def[kindsys.CoreProperties]{}, err - } - - props, err := kindsys.ToKindProps[kindsys.CoreProperties](vk) - if err != nil { - return kindsys.Def[kindsys.CoreProperties]{}, err - } - - return kindsys.Def[kindsys.CoreProperties]{ - V: vk, - Properties: props, - }, nil -} diff --git a/pkg/plugins/codegen/jenny_plugin_registry.go b/pkg/plugins/codegen/jenny_plugin_registry.go index e28b3222ee0..ecd2712aa6e 100644 --- a/pkg/plugins/codegen/jenny_plugin_registry.go +++ b/pkg/plugins/codegen/jenny_plugin_registry.go @@ -8,6 +8,7 @@ import ( "strings" "github.com/grafana/codejen" + "github.com/grafana/grafana/pkg/plugins/pfs" ) var registryPath = filepath.Join("pkg", "registry", "schemas") @@ -27,21 +28,22 @@ func (jenny *PluginRegistryJenny) JennyName() string { return "PluginRegistryJenny" } -func (jenny *PluginRegistryJenny) Generate(files []string) (*codejen.File, error) { - if len(files) == 0 { +func (jenny *PluginRegistryJenny) Generate(decls ...*pfs.PluginDecl) (*codejen.File, error) { + if len(decls) == 0 { return nil, nil } - schemas := make([]Schema, len(files)) - for i, file := range files { - name, err := getSchemaName(file) + schemas := make([]Schema, len(decls)) + for i, decl := range decls { + variant := fmt.Sprintf("%s.cue", strings.ToLower(decl.SchemaInterface.Name)) + name, err := getSchemaName(decl.PluginPath) if err != nil { return nil, fmt.Errorf("unable to find schema name: %s", err) } schemas[i] = Schema{ Name: name, - Filename: filepath.Base(file), - FilePath: file, + Filename: variant, + FilePath: "./" + filepath.Join("public", "app", "plugins", decl.PluginPath, variant), } } @@ -65,7 +67,7 @@ func getSchemaName(path string) (string, error) { if len(parts) < 2 { return "", fmt.Errorf("path should contain more than 2 elements") } - folderName := parts[len(parts)-2] + folderName := parts[len(parts)-1] if renamed, ok := renamedPlugins[folderName]; ok { folderName = renamed } diff --git a/pkg/plugins/codegen/jenny_plugingotypes.go b/pkg/plugins/codegen/jenny_plugingotypes.go index 16062b60e2a..5d756637e16 100644 --- a/pkg/plugins/codegen/jenny_plugingotypes.go +++ b/pkg/plugins/codegen/jenny_plugingotypes.go @@ -6,12 +6,9 @@ import ( "strings" copenapi "cuelang.org/go/encoding/openapi" - "github.com/dave/dst/dstutil" "github.com/grafana/codejen" - corecodegen "github.com/grafana/grafana/pkg/codegen" + "github.com/grafana/grafana/pkg/codegen/generators" "github.com/grafana/grafana/pkg/plugins/pfs" - "github.com/grafana/thema/encoding/gocode" - "github.com/grafana/thema/encoding/openapi" ) // TODO this is duplicative of other Go type jennies. Remove it in favor of a better-abstracted version in thema itself @@ -30,22 +27,22 @@ func (j *pgoJenny) JennyName() string { } func (j *pgoJenny) Generate(decl *pfs.PluginDecl) (*codejen.File, error) { - b := decl.PluginMeta.Backend - if b == nil || !*b || !decl.HasSchema() { + hasBackend := decl.PluginMeta.Backend + // We skip elasticsearch since we have problems with the generated file. + // This is temporal until we migrate to the new system. + if hasBackend == nil || !*hasBackend || decl.PluginMeta.Id == "elasticsearch" { return nil, nil } slotname := strings.ToLower(decl.SchemaInterface.Name) - byt, err := gocode.GenerateTypesOpenAPI(decl.Lineage.Latest(), &gocode.TypeConfigOpenAPI{ - Config: &openapi.Config{ - Group: decl.SchemaInterface.IsGroup, + byt, err := generators.GenerateTypesGo(decl.CueFile, &generators.GoConfig{ + Config: &generators.OpenApiConfig{ Config: &copenapi.Config{ MaxCycleDepth: 10, }, - SplitSchema: true, + IsGroup: decl.SchemaInterface.IsGroup, }, PackageName: slotname, - ApplyFuncs: []dstutil.ApplyFunc{corecodegen.PrefixDropper(decl.Lineage.Name())}, }) if err != nil { return nil, err diff --git a/pkg/plugins/codegen/jenny_plugintstypes.go b/pkg/plugins/codegen/jenny_plugintstypes.go index c82f1be00f7..6f84ebdb53d 100644 --- a/pkg/plugins/codegen/jenny_plugintstypes.go +++ b/pkg/plugins/codegen/jenny_plugintstypes.go @@ -11,7 +11,6 @@ import ( tsast "github.com/grafana/cuetsy/ts/ast" "github.com/grafana/grafana/pkg/build" "github.com/grafana/grafana/pkg/codegen" - "github.com/grafana/grafana/pkg/cuectx" "github.com/grafana/grafana/pkg/plugins/pfs" ) @@ -34,15 +33,11 @@ func (j *ptsJenny) JennyName() string { } func (j *ptsJenny) Generate(decl *pfs.PluginDecl) (codejen.Files, error) { - if !decl.HasSchema() { - return nil, nil - } - genFile := &tsast.File{} versionedFile := &tsast.File{} for _, im := range decl.Imports { - if tsim, err := cuectx.ConvertImport(im); err != nil { + if tsim, err := codegen.ConvertImport(im); err != nil { return nil, err } else if tsim.From.Value != "" { genFile.Imports = append(genFile.Imports, tsim) @@ -94,18 +89,46 @@ func getPluginVersion(pluginVersion *string) string { func adaptToPipeline(j codejen.OneToOne[codegen.SchemaForGen]) codejen.OneToOne[*pfs.PluginDecl] { return codejen.AdaptOneToOne(j, func(pd *pfs.PluginDecl) codegen.SchemaForGen { - name := strings.ReplaceAll(pd.PluginMeta.Name, " ", "") - if pd.SchemaInterface.Name == "DataQuery" { - name = name + "DataQuery" - } return codegen.SchemaForGen{ - Name: name, - Schema: pd.Lineage.Latest(), + Name: derivePascalName(pd.PluginMeta.Id, pd.PluginMeta.Name) + pd.SchemaInterface.Name, + CueFile: pd.CueFile, IsGroup: pd.SchemaInterface.IsGroup, } }) } +func derivePascalName(id string, name string) string { + sani := func(s string) string { + ret := strings.Title(strings.Map(func(r rune) rune { + switch { + case r >= 'a' && r <= 'z': + return r + case r >= 'A' && r <= 'Z': + return r + default: + return -1 + } + }, strings.Title(strings.Map(func(r rune) rune { + switch r { + case '-', '_': + return ' ' + default: + return r + } + }, s)))) + if len(ret) > 63 { + return ret[:63] + } + return ret + } + + fromname := sani(name) + if len(fromname) != 0 { + return fromname + } + return sani(strings.Split(id, "-")[1]) +} + func getGrafanaVersion() string { dir, err := os.Getwd() if err != nil { diff --git a/pkg/plugins/pfs/corelist/corelist.go b/pkg/plugins/pfs/corelist/corelist.go deleted file mode 100644 index 5113e3e63ab..00000000000 --- a/pkg/plugins/pfs/corelist/corelist.go +++ /dev/null @@ -1,30 +0,0 @@ -package corelist - -import ( - "sync" - - "github.com/grafana/grafana/pkg/cuectx" - "github.com/grafana/grafana/pkg/plugins/pfs" - "github.com/grafana/thema" -) - -var coreTrees []pfs.ParsedPlugin -var coreOnce sync.Once - -// New returns a pfs.PluginList containing the plugin trees for all core plugins -// in the current version of Grafana. -// -// Go code within the grafana codebase should only ever call this with nil. -func New(rt *thema.Runtime) []pfs.ParsedPlugin { - var pl []pfs.ParsedPlugin - if rt == nil { - coreOnce.Do(func() { - coreTrees = corePlugins(cuectx.GrafanaThemaRuntime()) - }) - pl = make([]pfs.ParsedPlugin, len(coreTrees)) - copy(pl, coreTrees) - } else { - return corePlugins(rt) - } - return pl -} diff --git a/pkg/plugins/pfs/corelist/corelist_load_gen.go b/pkg/plugins/pfs/corelist/corelist_load_gen.go deleted file mode 100644 index dbdaf7b1e85..00000000000 --- a/pkg/plugins/pfs/corelist/corelist_load_gen.go +++ /dev/null @@ -1,87 +0,0 @@ -// Code generated - EDITING IS FUTILE. DO NOT EDIT. -// -// Generated by: -// public/app/plugins/gen.go -// Using jennies: -// PluginTreeListJenny -// -// Run 'make gen-cue' from repository root to regenerate. - -package corelist - -import ( - "fmt" - "io/fs" - - "github.com/grafana/grafana" - "github.com/grafana/grafana/pkg/plugins/pfs" - "github.com/grafana/thema" -) - -func parsePluginOrPanic(path string, pkgname string, rt *thema.Runtime) pfs.ParsedPlugin { - sub, err := fs.Sub(grafana.CueSchemaFS, path) - if err != nil { - panic("could not create fs sub to " + path) - } - pp, err := pfs.ParsePluginFS(sub, rt) - if err != nil { - panic(fmt.Sprintf("error parsing plugin metadata for %s: %s", pkgname, err)) - } - return pp -} - -func corePlugins(rt *thema.Runtime) []pfs.ParsedPlugin { - return []pfs.ParsedPlugin{ - parsePluginOrPanic("public/app/plugins/datasource/alertmanager", "alertmanager", rt), - parsePluginOrPanic("public/app/plugins/datasource/azuremonitor", "grafana_azure_monitor_datasource", rt), - parsePluginOrPanic("public/app/plugins/datasource/cloud-monitoring", "stackdriver", rt), - parsePluginOrPanic("public/app/plugins/datasource/cloudwatch", "cloudwatch", rt), - parsePluginOrPanic("public/app/plugins/datasource/dashboard", "dashboard", rt), - parsePluginOrPanic("public/app/plugins/datasource/elasticsearch", "elasticsearch", rt), - parsePluginOrPanic("public/app/plugins/datasource/grafana", "grafana", rt), - parsePluginOrPanic("public/app/plugins/datasource/grafana-postgresql-datasource", "grafana_postgresql_datasource", rt), - parsePluginOrPanic("public/app/plugins/datasource/grafana-pyroscope-datasource", "grafana_pyroscope_datasource", rt), - parsePluginOrPanic("public/app/plugins/datasource/grafana-testdata-datasource", "grafana_testdata_datasource", rt), - parsePluginOrPanic("public/app/plugins/datasource/graphite", "graphite", rt), - parsePluginOrPanic("public/app/plugins/datasource/jaeger", "jaeger", rt), - parsePluginOrPanic("public/app/plugins/datasource/loki", "loki", rt), - parsePluginOrPanic("public/app/plugins/datasource/mssql", "mssql", rt), - parsePluginOrPanic("public/app/plugins/datasource/mysql", "mysql", rt), - parsePluginOrPanic("public/app/plugins/datasource/parca", "parca", rt), - parsePluginOrPanic("public/app/plugins/datasource/prometheus", "prometheus", rt), - parsePluginOrPanic("public/app/plugins/datasource/tempo", "tempo", rt), - parsePluginOrPanic("public/app/plugins/datasource/zipkin", "zipkin", rt), - parsePluginOrPanic("public/app/plugins/panel/alertlist", "alertlist", rt), - parsePluginOrPanic("public/app/plugins/panel/annolist", "annolist", rt), - parsePluginOrPanic("public/app/plugins/panel/barchart", "barchart", rt), - parsePluginOrPanic("public/app/plugins/panel/bargauge", "bargauge", rt), - parsePluginOrPanic("public/app/plugins/panel/candlestick", "candlestick", rt), - parsePluginOrPanic("public/app/plugins/panel/canvas", "canvas", rt), - parsePluginOrPanic("public/app/plugins/panel/dashlist", "dashlist", rt), - parsePluginOrPanic("public/app/plugins/panel/datagrid", "datagrid", rt), - parsePluginOrPanic("public/app/plugins/panel/debug", "debug", rt), - parsePluginOrPanic("public/app/plugins/panel/flamegraph", "flamegraph", rt), - parsePluginOrPanic("public/app/plugins/panel/gauge", "gauge", rt), - parsePluginOrPanic("public/app/plugins/panel/geomap", "geomap", rt), - parsePluginOrPanic("public/app/plugins/panel/gettingstarted", "gettingstarted", rt), - parsePluginOrPanic("public/app/plugins/panel/graph", "graph", rt), - parsePluginOrPanic("public/app/plugins/panel/heatmap", "heatmap", rt), - parsePluginOrPanic("public/app/plugins/panel/histogram", "histogram", rt), - parsePluginOrPanic("public/app/plugins/panel/live", "live", rt), - parsePluginOrPanic("public/app/plugins/panel/logs", "logs", rt), - parsePluginOrPanic("public/app/plugins/panel/news", "news", rt), - parsePluginOrPanic("public/app/plugins/panel/nodeGraph", "nodeGraph", rt), - parsePluginOrPanic("public/app/plugins/panel/piechart", "piechart", rt), - parsePluginOrPanic("public/app/plugins/panel/stat", "stat", rt), - parsePluginOrPanic("public/app/plugins/panel/state-timeline", "state_timeline", rt), - parsePluginOrPanic("public/app/plugins/panel/status-history", "status_history", rt), - parsePluginOrPanic("public/app/plugins/panel/table", "table", rt), - parsePluginOrPanic("public/app/plugins/panel/table-old", "table_old", rt), - parsePluginOrPanic("public/app/plugins/panel/text", "text", rt), - parsePluginOrPanic("public/app/plugins/panel/timeseries", "timeseries", rt), - parsePluginOrPanic("public/app/plugins/panel/traces", "traces", rt), - parsePluginOrPanic("public/app/plugins/panel/trend", "trend", rt), - parsePluginOrPanic("public/app/plugins/panel/welcome", "welcome", rt), - parsePluginOrPanic("public/app/plugins/panel/xychart", "xychart", rt), - } -} diff --git a/pkg/plugins/pfs/decl.go b/pkg/plugins/pfs/decl.go index 406275d3c85..0c24479467b 100644 --- a/pkg/plugins/pfs/decl.go +++ b/pkg/plugins/pfs/decl.go @@ -1,18 +1,16 @@ package pfs import ( + "cuelang.org/go/cue" "cuelang.org/go/cue/ast" - "github.com/grafana/kindsys" - "github.com/grafana/thema" ) type PluginDecl struct { - SchemaInterface *SchemaInterface - Lineage thema.Lineage + SchemaInterface SchemaInterface + CueFile cue.Value Imports []*ast.ImportSpec PluginPath string PluginMeta Metadata - KindDecl kindsys.Def[kindsys.ComposableProperties] } type SchemaInterface struct { @@ -26,15 +24,3 @@ type Metadata struct { Backend *bool Version *string } - -func EmptyPluginDecl(path string, meta Metadata) *PluginDecl { - return &PluginDecl{ - PluginPath: path, - PluginMeta: meta, - Imports: make([]*ast.ImportSpec, 0), - } -} - -func (decl *PluginDecl) HasSchema() bool { - return decl.Lineage != nil && decl.SchemaInterface != nil -} diff --git a/pkg/plugins/pfs/decl_parser.go b/pkg/plugins/pfs/decl_parser.go index 4e909b16ab0..374615c3737 100644 --- a/pkg/plugins/pfs/decl_parser.go +++ b/pkg/plugins/pfs/decl_parser.go @@ -6,35 +6,22 @@ import ( "path/filepath" "sort" - "github.com/grafana/thema" + "cuelang.org/go/cue/cuecontext" ) -type declParser struct { - rt *thema.Runtime +type DeclParser struct { skip map[string]bool } -// Extracted from kindsys repository -var schemaInterfaces = map[string]*SchemaInterface{ - "PanelCfg": { - Name: "PanelCfg", - IsGroup: true, - }, - "DataQuery": { - Name: "DataQuery", - IsGroup: false, - }, -} - -func NewDeclParser(rt *thema.Runtime, skip map[string]bool) *declParser { - return &declParser{ - rt: rt, +func NewDeclParser(skip map[string]bool) *DeclParser { + return &DeclParser{ skip: skip, } } // TODO convert this to be the new parser for Tree -func (psr *declParser) Parse(root fs.FS) ([]*PluginDecl, error) { +func (psr *DeclParser) Parse(root fs.FS) ([]*PluginDecl, error) { + ctx := cuecontext.New() // TODO remove hardcoded tree structure assumption, work from root of provided fs plugins, err := fs.Glob(root, "**/**/plugin.json") if err != nil { @@ -50,29 +37,22 @@ func (psr *declParser) Parse(root fs.FS) ([]*PluginDecl, error) { } dir, _ := fs.Sub(root, path) - pp, err := ParsePluginFS(dir, psr.rt) + pp, err := ParsePluginFS(ctx, dir, path) if err != nil { return nil, fmt.Errorf("parsing plugin failed for %s: %s", dir, err) } - if len(pp.ComposableKinds) == 0 { - decls = append(decls, EmptyPluginDecl(path, pp.Properties)) + if !pp.CueFile.Exists() { continue } - for slotName, kind := range pp.ComposableKinds { - if err != nil { - return nil, fmt.Errorf("parsing plugin failed for %s: %s", dir, err) - } - decls = append(decls, &PluginDecl{ - SchemaInterface: schemaInterfaces[slotName], - Lineage: kind.Lineage(), - Imports: pp.CUEImports, - PluginMeta: pp.Properties, - PluginPath: path, - KindDecl: kind.Def(), - }) - } + decls = append(decls, &PluginDecl{ + SchemaInterface: pp.Variant, + CueFile: pp.CueFile, + Imports: pp.CUEImports, + PluginMeta: pp.Properties, + PluginPath: path, + }) } sort.Slice(decls, func(i, j int) bool { diff --git a/pkg/plugins/pfs/pfs.go b/pkg/plugins/pfs/pfs.go index b56f5fdf652..a3dc8bd8735 100644 --- a/pkg/plugins/pfs/pfs.go +++ b/pkg/plugins/pfs/pfs.go @@ -4,29 +4,32 @@ import ( "encoding/json" "fmt" "io/fs" - "sort" "strings" - "testing/fstest" "cuelang.org/go/cue" - "cuelang.org/go/cue/cuecontext" "cuelang.org/go/cue/errors" - "cuelang.org/go/cue/token" - "github.com/grafana/kindsys" - "github.com/grafana/thema" - "github.com/grafana/thema/load" - "github.com/yalue/merged_fs" - - "github.com/grafana/grafana/pkg/cuectx" + "cuelang.org/go/cue/load" + "github.com/grafana/grafana/pkg/codegen" ) // PackageName is the name of the CUE package that Grafana will load when // looking for a Grafana plugin's kind declarations. const PackageName = "grafanaplugin" +var schemaInterface = map[string]SchemaInterface{ + "DataQuery": { + Name: "DataQuery", + IsGroup: false, + }, + "PanelCfg": { + Name: "PanelCfg", + IsGroup: true, + }, +} + // PermittedCUEImports returns the list of import paths that may be used in a // plugin's grafanaplugin cue package. -var PermittedCUEImports = cuectx.PermittedCUEImports +var PermittedCUEImports = codegen.PermittedCUEImports func importAllowed(path string) bool { for _, p := range PermittedCUEImports() { @@ -39,22 +42,12 @@ func importAllowed(path string) bool { var allowedImportsStr string -var allsi []kindsys.SchemaInterface - func init() { all := make([]string, 0, len(PermittedCUEImports())) for _, im := range PermittedCUEImports() { all = append(all, fmt.Sprintf("\t%s", im)) } allowedImportsStr = strings.Join(all, "\n") - - for _, s := range kindsys.SchemaInterfaces(nil) { - allsi = append(allsi, s) - } - - sort.Slice(allsi, func(i, j int) bool { - return allsi[i].Name() < allsi[j].Name() - }) } // ParsePluginFS takes a virtual filesystem and checks that it contains a valid @@ -69,17 +62,17 @@ func init() { // This function parses exactly one plugin. It does not descend into // subdirectories to search for additional plugin.json or .cue files. // -// Calling this with a nil [thema.Runtime] (the singleton returned from -// [cuectx.GrafanaThemaRuntime] is used) will memoize certain CUE operations. -// Prefer passing nil unless a different thema.Runtime is specifically required. -// // [GrafanaPlugin]: https://github.com/grafana/grafana/blob/main/pkg/plugins/pfs/grafanaplugin.cue -func ParsePluginFS(fsys fs.FS, rt *thema.Runtime) (ParsedPlugin, error) { +func ParsePluginFS(ctx *cue.Context, fsys fs.FS, dir string) (ParsedPlugin, error) { if fsys == nil { return ParsedPlugin{}, ErrEmptyFS } - if rt == nil { - rt = cuectx.GrafanaThemaRuntime() + + cuefiles, err := fs.Glob(fsys, "*.cue") + if err != nil { + return ParsedPlugin{}, fmt.Errorf("error globbing for cue files in fsys: %w", err) + } else if len(cuefiles) == 0 { + return ParsedPlugin{}, nil } metadata, err := getPluginMetadata(fsys) @@ -88,27 +81,19 @@ func ParsePluginFS(fsys fs.FS, rt *thema.Runtime) (ParsedPlugin, error) { } pp := ParsedPlugin{ - ComposableKinds: make(map[string]kindsys.Composable), - Properties: metadata, + Properties: metadata, } - if cuefiles, err := fs.Glob(fsys, "*.cue"); err != nil { - return ParsedPlugin{}, fmt.Errorf("error globbing for cue files in fsys: %w", err) - } else if len(cuefiles) == 0 { - return pp, nil - } - - fsys, err = ensureCueMod(fsys, pp.Properties) if err != nil { - return ParsedPlugin{}, fmt.Errorf("%s has invalid cue.mod: %w", pp.Properties.Id, err) + return ParsedPlugin{}, err } - bi, err := cuectx.LoadInstanceWithGrafana(fsys, "", load.Package(PackageName)) - if err != nil || bi.Err != nil { - if err == nil { - err = bi.Err - } - return ParsedPlugin{}, errors.Wrap(errors.Newf(token.NoPos, "%s did not load", pp.Properties.Id), err) + bi := load.Instances(cuefiles, &load.Config{ + Package: PackageName, + Dir: dir, + })[0] + if bi.Err != nil { + return ParsedPlugin{}, bi.Err } for _, f := range bi.Files { @@ -132,105 +117,35 @@ func ParsePluginFS(fsys fs.FS, rt *thema.Runtime) (ParsedPlugin, error) { panic("Refactor required - upstream CUE implementation changed, bi.Files is no longer populated") } - gpi := rt.Context().BuildInstance(bi) + gpi := ctx.BuildInstance(bi) if gpi.Err() != nil { return ParsedPlugin{}, errors.Wrap(errors.Promote(ErrInvalidGrafanaPluginInstance, pp.Properties.Id), gpi.Err()) } - for _, si := range allsi { - iv := gpi.LookupPath(cue.MakePath(cue.Str("composableKinds"), cue.Str(si.Name()))) + for name, si := range schemaInterface { + iv := gpi.LookupPath(cue.MakePath(cue.Str("composableKinds"), cue.Str(name))) if !iv.Exists() { continue } - iv = iv.FillPath(cue.MakePath(cue.Str("schemaInterface")), si.Name()) - iv = iv.FillPath(cue.MakePath(cue.Str("name")), derivePascalName(pp.Properties.Id, pp.Properties.Name)+si.Name()) + iv = iv.FillPath(cue.MakePath(cue.Str("schemaInterface")), name) + iv = iv.FillPath(cue.MakePath(cue.Str("name")), derivePascalName(pp.Properties.Id, pp.Properties.Name)+name) lineageNamePath := iv.LookupPath(cue.MakePath(cue.Str("lineage"), cue.Str("name"))) if !lineageNamePath.Exists() { - iv = iv.FillPath(cue.MakePath(cue.Str("lineage"), cue.Str("name")), derivePascalName(pp.Properties.Id, pp.Properties.Name)+si.Name()) + iv = iv.FillPath(cue.MakePath(cue.Str("lineage"), cue.Str("name")), derivePascalName(pp.Properties.Id, pp.Properties.Name)+name) } validSchema := iv.LookupPath(cue.ParsePath("lineage.schemas[0].schema")) if !validSchema.Exists() { return ParsedPlugin{}, errors.Wrap(errors.Promote(ErrInvalidGrafanaPluginInstance, pp.Properties.Id), validSchema.Err()) } - - props, err := kindsys.ToKindProps[kindsys.ComposableProperties](iv) - if err != nil { - return ParsedPlugin{}, err - } - - compo, err := kindsys.BindComposable(rt, kindsys.Def[kindsys.ComposableProperties]{ - Properties: props, - V: iv, - }) - if err != nil { - return ParsedPlugin{}, err - } - pp.ComposableKinds[si.Name()] = compo + pp.Variant = si + pp.CueFile = iv } return pp, nil } -// LoadComposableKindDef loads and validates a composable kind definition. -// On success, it returns a [Def] which contains the entire contents of the kind definition. -// -// defpath is the path to the directory containing the composable kind definition, -// relative to the root of the caller's repository. -// -// NOTE This function will be deprecated in favor of a more generic loader when kind -// providers will be implemented. -func LoadComposableKindDef(fsys fs.FS, rt *thema.Runtime, defpath string) (kindsys.Def[kindsys.ComposableProperties], error) { - pp := ParsedPlugin{ - ComposableKinds: make(map[string]kindsys.Composable), - Properties: Metadata{ - Id: defpath, - }, - } - - fsys, err := ensureCueMod(fsys, pp.Properties) - if err != nil { - return kindsys.Def[kindsys.ComposableProperties]{}, fmt.Errorf("%s has invalid cue.mod: %w", pp.Properties.Id, err) - } - - bi, err := cuectx.LoadInstanceWithGrafana(fsys, "", load.Package(PackageName)) - if err != nil { - return kindsys.Def[kindsys.ComposableProperties]{}, err - } - - ctx := rt.Context() - v := ctx.BuildInstance(bi) - if v.Err() != nil { - return kindsys.Def[kindsys.ComposableProperties]{}, fmt.Errorf("%s not a valid CUE instance: %w", defpath, v.Err()) - } - - props, err := kindsys.ToKindProps[kindsys.ComposableProperties](v) - if err != nil { - return kindsys.Def[kindsys.ComposableProperties]{}, err - } - - return kindsys.Def[kindsys.ComposableProperties]{ - V: v, - Properties: props, - }, nil -} - -func ensureCueMod(fsys fs.FS, metadata Metadata) (fs.FS, error) { - if modf, err := fs.ReadFile(fsys, "cue.mod/module.cue"); err != nil { - if !errors.Is(err, fs.ErrNotExist) { - return nil, err - } - return merged_fs.NewMergedFS(fsys, fstest.MapFS{ - "cue.mod/module.cue": &fstest.MapFile{Data: []byte(fmt.Sprintf(`module: "grafana.com/grafana/plugins/%s"`, metadata.Id))}, - }), nil - } else if _, err := cuecontext.New().CompileBytes(modf).LookupPath(cue.MakePath(cue.Str("module"))).String(); err != nil { - return nil, fmt.Errorf("error reading cue module name: %w", err) - } - - return fsys, nil -} - func getPluginMetadata(fsys fs.FS) (Metadata, error) { b, err := fs.ReadFile(fsys, "plugin.json") if err != nil { diff --git a/pkg/plugins/pfs/pfs_test.go b/pkg/plugins/pfs/pfs_test.go deleted file mode 100644 index 8980e593455..00000000000 --- a/pkg/plugins/pfs/pfs_test.go +++ /dev/null @@ -1,297 +0,0 @@ -package pfs - -import ( - "archive/zip" - "io/fs" - "os" - "path/filepath" - "sort" - "testing" - - "github.com/google/go-cmp/cmp" - "github.com/grafana/grafana/pkg/cuectx" - "github.com/stretchr/testify/require" -) - -func TestParsePluginTestdata(t *testing.T) { - type tt struct { - tfs fs.FS - // TODO could remove this by getting rid of inconsistent subdirs - subpath string - skip string - err error - // TODO could remove this by expecting that dirname == id - rootid string - } - tab := map[string]tt{ - "app-with-child": { - rootid: "myorgid-simple-app", - subpath: "dist", - skip: "schema violation, weirdness in info.version field", - }, - "duplicate-plugins": { - rootid: "test-app", - subpath: "nested", - skip: "schema violation, dependencies don't follow naming constraints", - }, - "includes-symlinks": { - skip: "schema violation, dependencies don't follow naming constraints", - }, - "installer": { - rootid: "test-datasource", - subpath: "plugin", - }, - "invalid-plugin-json": { - rootid: "test-app", - err: ErrInvalidRootFile, - }, - "invalid-v1-signature": { - rootid: "test-datasource", - subpath: "plugin", - }, - "invalid-v2-extra-file": { - rootid: "test-datasource", - subpath: "plugin", - }, - "invalid-v2-missing-file": { - rootid: "test-datasource", - subpath: "plugin", - }, - "lacking-files": { - rootid: "test-datasource", - subpath: "plugin", - }, - "nested-plugins": { - rootid: "test-datasource", - subpath: "parent", - }, - "non-pvt-with-root-url": { - rootid: "test-datasource", - subpath: "plugin", - }, - "renderer-added-file": { - rootid: "test-renderer", - subpath: "plugin", - }, - "symbolic-plugin-dirs": { - skip: "io/fs-based scanner will not traverse symlinks; caller of ParsePluginFS() must do it", - }, - "test-app": { - skip: "schema violation, dependencies don't follow naming constraints", - rootid: "test-app", - }, - "test-app-with-includes": { - rootid: "test-app", - skip: "has a 'page'-type include which isn't a known part of spec", - }, - "test-app-with-roles": { - rootid: "test-app", - }, - "unsigned-datasource": { - rootid: "test-datasource", - subpath: "plugin", - }, - "unsigned-panel": { - rootid: "test-panel", - subpath: "plugin", - }, - "valid-v2-pvt-signature": { - rootid: "test-datasource", - subpath: "plugin", - }, - "valid-v2-pvt-signature-root-url-uri": { - rootid: "test-datasource", - subpath: "plugin", - }, - "valid-v2-signature": { - rootid: "test-datasource", - subpath: "plugin", - }, - "plugin-with-dist": { - rootid: "test-datasource", - subpath: "plugin", - }, - "no-rootfile": { - err: ErrNoRootFile, - }, - "valid-model-panel": {}, - "valid-model-datasource": {}, - "missing-kind-datasource": {}, - "panel-conflicting-joinschema": { - err: ErrInvalidLineage, - skip: "TODO implement BindOption in thema, SatisfiesJoinSchema, then use it here", - }, - "panel-does-not-follow-slot-joinschema": { - err: ErrInvalidLineage, - skip: "TODO implement BindOption in thema, SatisfiesJoinSchema, then use it here", - }, - "pluginRootWithDist": { - err: ErrNoRootFile, - skip: "This folder is used to test multiple plugins in the same folder", - }, - "name-mismatch-panel": { - err: ErrInvalidGrafanaPluginInstance, - }, - "disallowed-cue-import": { - err: ErrDisallowedCUEImport, - }, - "cdn": { - rootid: "grafana-worldmap-panel", - subpath: "plugin", - }, - "external-registration": { - rootid: "grafana-test-datasource", - }, - } - - staticRootPath, err := filepath.Abs(filepath.Join("..", "manager", "testdata")) - require.NoError(t, err) - dfs := os.DirFS(staticRootPath) - ents, err := fs.ReadDir(dfs, ".") - require.NoError(t, err) - - // Ensure table test and dir list are == - var dirs, tts []string - for k := range tab { - tts = append(tts, k) - } - for _, ent := range ents { - dirs = append(dirs, ent.Name()) - } - sort.Strings(tts) - sort.Strings(dirs) - if !cmp.Equal(tts, dirs) { - t.Fatalf("table test map (-) and pkg/plugins/manager/testdata dirs (+) differ: %s", cmp.Diff(tts, dirs)) - } - - for _, ent := range ents { - tst := tab[ent.Name()] - tst.tfs, err = fs.Sub(dfs, filepath.Join(ent.Name(), tst.subpath)) - require.NoError(t, err) - tab[ent.Name()] = tst - } - - lib := cuectx.GrafanaThemaRuntime() - for name, otst := range tab { - tst := otst // otherwise var is shadowed within func by looping - t.Run(name, func(t *testing.T) { - if tst.skip != "" { - t.Skip(tst.skip) - } - - pp, err := ParsePluginFS(tst.tfs, lib) - if tst.err == nil { - require.NoError(t, err, "unexpected error while parsing plugin tree") - } else { - require.Error(t, err) - t.Logf("%T %s", err, err) - require.ErrorIs(t, err, tst.err, "unexpected error type while parsing plugin tree") - return - } - - if tst.rootid == "" { - tst.rootid = name - } - - require.Equal(t, tst.rootid, pp.Properties.Id, "expected plugin id and actual plugin id differ") - }) - } -} - -func TestParseTreeZips(t *testing.T) { - type tt struct { - tfs fs.FS - // TODO could remove this by getting rid of inconsistent subdirs - subpath string - skip string - err error - // TODO could remove this by expecting that dirname == id - rootid string - } - - tab := map[string]tt{ - "grafana-simple-json-datasource-ec18fa4da8096a952608a7e4c7782b4260b41bcf.zip": { - skip: "binary plugin", - }, - "plugin-with-absolute-member.zip": { - skip: "not actually a plugin, no plugin.json?", - }, - "plugin-with-absolute-symlink-dir.zip": { - skip: "not actually a plugin, no plugin.json?", - }, - "plugin-with-absolute-symlink.zip": { - skip: "not actually a plugin, no plugin.json?", - }, - "plugin-with-parent-member.zip": { - skip: "not actually a plugin, no plugin.json?", - }, - "plugin-with-symlink-dir.zip": { - skip: "not actually a plugin, no plugin.json?", - }, - "plugin-with-symlink.zip": { - skip: "not actually a plugin, no plugin.json?", - }, - "plugin-with-symlinks.zip": { - subpath: "test-app", - rootid: "test-app", - }, - } - - staticRootPath, err := filepath.Abs(filepath.Join("..", "storage", "testdata")) - require.NoError(t, err) - ents, err := os.ReadDir(staticRootPath) - require.NoError(t, err) - - // Ensure table test and dir list are == - var dirs, tts []string - for k := range tab { - tts = append(tts, k) - } - for _, ent := range ents { - dirs = append(dirs, ent.Name()) - } - sort.Strings(tts) - sort.Strings(dirs) - if !cmp.Equal(tts, dirs) { - t.Fatalf("table test map (-) and pkg/plugins/installer/testdata dirs (+) differ: %s", cmp.Diff(tts, dirs)) - } - - for _, ent := range ents { - tst := tab[ent.Name()] - r, err := zip.OpenReader(filepath.Join(staticRootPath, ent.Name())) - require.NoError(t, err) - defer r.Close() //nolint:errcheck - if tst.subpath != "" { - tst.tfs, err = fs.Sub(r, tst.subpath) - require.NoError(t, err) - } else { - tst.tfs = r - } - - tab[ent.Name()] = tst - } - - lib := cuectx.GrafanaThemaRuntime() - for name, otst := range tab { - tst := otst // otherwise var is shadowed within func by looping - t.Run(name, func(t *testing.T) { - if tst.skip != "" { - t.Skip(tst.skip) - } - - pp, err := ParsePluginFS(tst.tfs, lib) - if tst.err == nil { - require.NoError(t, err, "unexpected error while parsing plugin fs") - } else { - require.ErrorIs(t, err, tst.err, "unexpected error type while parsing plugin fs") - return - } - - if tst.rootid == "" { - tst.rootid = name - } - - require.Equal(t, tst.rootid, pp.Properties.Id, "expected plugin id and actual plugin id differ") - }) - } -} diff --git a/pkg/plugins/pfs/plugin.go b/pkg/plugins/pfs/plugin.go index 2829a81046d..66ed3912417 100644 --- a/pkg/plugins/pfs/plugin.go +++ b/pkg/plugins/pfs/plugin.go @@ -1,8 +1,8 @@ package pfs import ( + "cuelang.org/go/cue" "cuelang.org/go/cue/ast" - "github.com/grafana/kindsys" ) // ParsedPlugin represents everything knowable about a single plugin from static @@ -13,35 +13,10 @@ import ( type ParsedPlugin struct { // Properties contains the plugin's definition, as declared in plugin.json. Properties Metadata - - // ComposableKinds is a map of all the composable kinds declared in this plugin. - // Keys are the name of the [kindsys.SchemaInterface] implemented by the value. - // - // Composable kind defs are only populated in this map by [ParsePluginFS] if - // they are implementations of a known schema interface, or are for - // an unknown schema interface. - ComposableKinds map[string]kindsys.Composable - - // CustomKinds is a map of all the custom kinds declared in this plugin. - // Keys are the machineName of the custom kind. - // CustomKinds map[string]kindsys.Custom + CueFile cue.Value + Variant SchemaInterface // CUEImports lists the CUE import statements in the plugin's grafanaplugin CUE // package, if any. CUEImports []*ast.ImportSpec } - -// TODO is this static approach worth using, akin to core generated registries? instead of the ParsedPlugins.ComposableKinds map? in addition to it? -// ComposableKinds represents all the possible composable kinds that may be -// defined in a Grafana plugin. -// -// The value of each field, if non-nil, is a standard [kindsys.Def] -// representing a CUE definition of a composable kind that implements the -// schema interface corresponding to the field's name. (This invariant is -// only enforced in [ComposableKinds] returned from [ParsePluginFS].) -// -// type ComposableKinds struct { -// PanelCfg kindsys.Def[kindsys.ComposableProperties] -// Queries kindsys.Def[kindsys.ComposableProperties] -// DSCfg kindsys.Def[kindsys.ComposableProperties] -// } diff --git a/pkg/plugins/pfs/plugin_test.go b/pkg/plugins/pfs/plugin_test.go deleted file mode 100644 index 99330b241f0..00000000000 --- a/pkg/plugins/pfs/plugin_test.go +++ /dev/null @@ -1,31 +0,0 @@ -package pfs - -import ( - "sort" - "testing" - - "github.com/google/go-cmp/cmp" - "github.com/grafana/kindsys" -) - -// This is a brick-dumb test that just ensures known schema interfaces are being -// loaded correctly from their declarations in .cue files. -// -// If this test fails, it's either because: -// - They're not being loaded correctly - there's a bug in kindsys or pfs somewhere, fix it -// - The set of schema interfaces has been modified - update the static list here -func TestSchemaInterfacesAreLoaded(t *testing.T) { - knownSI := []string{"PanelCfg", "DataQuery", "DataSourceCfg"} - all := kindsys.SchemaInterfaces(nil) - var loadedSI []string - for k := range all { - loadedSI = append(loadedSI, k) - } - - sort.Strings(knownSI) - sort.Strings(loadedSI) - - if diff := cmp.Diff(knownSI, loadedSI); diff != "" { - t.Fatalf("kindsys cue-declared schema interfaces differ from ComposableKinds go struct:\n%s", diff) - } -} diff --git a/pkg/server/wire.go b/pkg/server/wire.go index e2548922582..517a949240f 100644 --- a/pkg/server/wire.go +++ b/pkg/server/wire.go @@ -8,14 +8,13 @@ package server import ( "github.com/google/wire" - + sdkhttpclient "github.com/grafana/grafana-plugin-sdk-go/backend/httpclient" - + "github.com/grafana/grafana/pkg/api" "github.com/grafana/grafana/pkg/api/avatar" "github.com/grafana/grafana/pkg/api/routing" "github.com/grafana/grafana/pkg/bus" - "github.com/grafana/grafana/pkg/cuectx" "github.com/grafana/grafana/pkg/expr" "github.com/grafana/grafana/pkg/infra/db" "github.com/grafana/grafana/pkg/infra/httpclient" @@ -306,8 +305,6 @@ var wireBasicSet = wire.NewSet( secretsStore.ProvideService, avatar.ProvideAvatarCacheServer, statscollector.ProvideService, - cuectx.GrafanaCUEContext, - cuectx.GrafanaThemaRuntime, csrf.ProvideCSRFFilter, wire.Bind(new(csrf.Service), new(*csrf.CSRF)), ossaccesscontrol.ProvideTeamPermissions, diff --git a/pkg/tsdb/azuremonitor/kinds/dataquery/types_dataquery_gen.go b/pkg/tsdb/azuremonitor/kinds/dataquery/types_dataquery_gen.go index 95a779e019b..12ff462ae85 100644 --- a/pkg/tsdb/azuremonitor/kinds/dataquery/types_dataquery_gen.go +++ b/pkg/tsdb/azuremonitor/kinds/dataquery/types_dataquery_gen.go @@ -98,10 +98,9 @@ const ( // AppInsightsGroupByQuery defines model for AppInsightsGroupByQuery. type AppInsightsGroupByQuery struct { - BaseGrafanaTemplateVariableQuery - Kind AppInsightsGroupByQueryKind `json:"kind"` - MetricName string `json:"metricName"` - RawQuery *string `json:"rawQuery,omitempty"` + Kind *AppInsightsGroupByQueryKind `json:"kind,omitempty"` + MetricName *string `json:"metricName,omitempty"` + RawQuery *string `json:"rawQuery,omitempty"` } // AppInsightsGroupByQueryKind defines model for AppInsightsGroupByQuery.Kind. @@ -109,9 +108,8 @@ type AppInsightsGroupByQueryKind string // AppInsightsMetricNameQuery defines model for AppInsightsMetricNameQuery. type AppInsightsMetricNameQuery struct { - BaseGrafanaTemplateVariableQuery - Kind AppInsightsMetricNameQueryKind `json:"kind"` - RawQuery *string `json:"rawQuery,omitempty"` + Kind *AppInsightsMetricNameQueryKind `json:"kind,omitempty"` + RawQuery *string `json:"rawQuery,omitempty"` } // AppInsightsMetricNameQueryKind defines model for AppInsightsMetricNameQuery.Kind. @@ -221,20 +219,35 @@ type AzureMonitorDataQuery = map[string]any // AzureMonitorQuery defines model for AzureMonitorQuery. type AzureMonitorQuery struct { - // DataQuery These are the common properties available to all queries in all datasources. - // Specific implementations will *extend* this interface, adding the required - // properties for the given context. - DataQuery - // Azure Monitor Logs sub-query properties AzureLogAnalytics *AzureLogsQuery `json:"azureLogAnalytics,omitempty"` AzureMonitor *AzureMetricQuery `json:"azureMonitor,omitempty"` AzureResourceGraph *AzureResourceGraphQuery `json:"azureResourceGraph,omitempty"` // Application Insights Traces sub-query properties - AzureTraces *AzureTracesQuery `json:"azureTraces,omitempty"` - GrafanaTemplateVariableFn *any `json:"grafanaTemplateVariableFn,omitempty"` - Namespace *string `json:"namespace,omitempty"` + AzureTraces *AzureTracesQuery `json:"azureTraces,omitempty"` + + // For mixed data sources the selected datasource is on the query level. + // For non mixed scenarios this is undefined. + // TODO find a better way to do this ^ that's friendly to schema + // TODO this shouldn't be unknown but DataSourceRef | null + Datasource *any `json:"datasource,omitempty"` + GrafanaTemplateVariableFn *any `json:"grafanaTemplateVariableFn,omitempty"` + + // Hide true if query is disabled (ie should not be returned to the dashboard) + // Note this does not always imply that the query should not be executed since + // the results from a hidden query may be used as the input to other queries (SSE etc) + Hide *bool `json:"hide,omitempty"` + Namespace *string `json:"namespace,omitempty"` + + // Specify the query flavor + // TODO make this required and give it a default + QueryType *string `json:"queryType,omitempty"` + + // A unique identifier for the query within the list of targets. + // In server side expressions, the refId is used as a variable name to identify results. + // By default, the UI will assign A->Z; however setting meaningful names may be useful. + RefId *string `json:"refId,omitempty"` // Azure Monitor query type. // queryType: #AzureQueryType @@ -336,15 +349,14 @@ type DataQuery struct { // GrafanaTemplateVariableQueryType defines model for GrafanaTemplateVariableQueryType. type GrafanaTemplateVariableQueryType string -// MetricDefinitionsQuery defines model for MetricDefinitionsQuery. +// @deprecated Use MetricNamespaceQuery instead type MetricDefinitionsQuery struct { - BaseGrafanaTemplateVariableQuery - Kind MetricDefinitionsQueryKind `json:"kind"` - MetricNamespace *string `json:"metricNamespace,omitempty"` - RawQuery *string `json:"rawQuery,omitempty"` - ResourceGroup string `json:"resourceGroup"` - ResourceName *string `json:"resourceName,omitempty"` - Subscription string `json:"subscription"` + Kind *MetricDefinitionsQueryKind `json:"kind,omitempty"` + MetricNamespace *string `json:"metricNamespace,omitempty"` + RawQuery *string `json:"rawQuery,omitempty"` + ResourceGroup *string `json:"resourceGroup,omitempty"` + ResourceName *string `json:"resourceName,omitempty"` + Subscription *string `json:"subscription,omitempty"` } // MetricDefinitionsQueryKind defines model for MetricDefinitionsQuery.Kind. @@ -352,13 +364,12 @@ type MetricDefinitionsQueryKind string // MetricNamesQuery defines model for MetricNamesQuery. type MetricNamesQuery struct { - BaseGrafanaTemplateVariableQuery - Kind MetricNamesQueryKind `json:"kind"` - MetricNamespace string `json:"metricNamespace"` - RawQuery *string `json:"rawQuery,omitempty"` - ResourceGroup string `json:"resourceGroup"` - ResourceName string `json:"resourceName"` - Subscription string `json:"subscription"` + Kind *MetricNamesQueryKind `json:"kind,omitempty"` + MetricNamespace *string `json:"metricNamespace,omitempty"` + RawQuery *string `json:"rawQuery,omitempty"` + ResourceGroup *string `json:"resourceGroup,omitempty"` + ResourceName *string `json:"resourceName,omitempty"` + Subscription *string `json:"subscription,omitempty"` } // MetricNamesQueryKind defines model for MetricNamesQuery.Kind. @@ -366,13 +377,12 @@ type MetricNamesQueryKind string // MetricNamespaceQuery defines model for MetricNamespaceQuery. type MetricNamespaceQuery struct { - BaseGrafanaTemplateVariableQuery - Kind MetricNamespaceQueryKind `json:"kind"` - MetricNamespace *string `json:"metricNamespace,omitempty"` - RawQuery *string `json:"rawQuery,omitempty"` - ResourceGroup string `json:"resourceGroup"` - ResourceName *string `json:"resourceName,omitempty"` - Subscription string `json:"subscription"` + Kind *MetricNamespaceQueryKind `json:"kind,omitempty"` + MetricNamespace *string `json:"metricNamespace,omitempty"` + RawQuery *string `json:"rawQuery,omitempty"` + ResourceGroup *string `json:"resourceGroup,omitempty"` + ResourceName *string `json:"resourceName,omitempty"` + Subscription *string `json:"subscription,omitempty"` } // MetricNamespaceQueryKind defines model for MetricNamespaceQuery.Kind. @@ -380,10 +390,9 @@ type MetricNamespaceQueryKind string // ResourceGroupsQuery defines model for ResourceGroupsQuery. type ResourceGroupsQuery struct { - BaseGrafanaTemplateVariableQuery - Kind ResourceGroupsQueryKind `json:"kind"` - RawQuery *string `json:"rawQuery,omitempty"` - Subscription string `json:"subscription"` + Kind *ResourceGroupsQueryKind `json:"kind,omitempty"` + RawQuery *string `json:"rawQuery,omitempty"` + Subscription *string `json:"subscription,omitempty"` } // ResourceGroupsQueryKind defines model for ResourceGroupsQuery.Kind. @@ -391,12 +400,11 @@ type ResourceGroupsQueryKind string // ResourceNamesQuery defines model for ResourceNamesQuery. type ResourceNamesQuery struct { - BaseGrafanaTemplateVariableQuery - Kind ResourceNamesQueryKind `json:"kind"` - MetricNamespace string `json:"metricNamespace"` - RawQuery *string `json:"rawQuery,omitempty"` - ResourceGroup string `json:"resourceGroup"` - Subscription string `json:"subscription"` + Kind *ResourceNamesQueryKind `json:"kind,omitempty"` + MetricNamespace *string `json:"metricNamespace,omitempty"` + RawQuery *string `json:"rawQuery,omitempty"` + ResourceGroup *string `json:"resourceGroup,omitempty"` + Subscription *string `json:"subscription,omitempty"` } // ResourceNamesQueryKind defines model for ResourceNamesQuery.Kind. @@ -407,9 +415,8 @@ type ResultFormat string // SubscriptionsQuery defines model for SubscriptionsQuery. type SubscriptionsQuery struct { - BaseGrafanaTemplateVariableQuery - Kind SubscriptionsQueryKind `json:"kind"` - RawQuery *string `json:"rawQuery,omitempty"` + Kind *SubscriptionsQueryKind `json:"kind,omitempty"` + RawQuery *string `json:"rawQuery,omitempty"` } // SubscriptionsQueryKind defines model for SubscriptionsQuery.Kind. @@ -417,9 +424,8 @@ type SubscriptionsQueryKind string // UnknownQuery defines model for UnknownQuery. type UnknownQuery struct { - BaseGrafanaTemplateVariableQuery - Kind UnknownQueryKind `json:"kind"` - RawQuery *string `json:"rawQuery,omitempty"` + Kind *UnknownQueryKind `json:"kind,omitempty"` + RawQuery *string `json:"rawQuery,omitempty"` } // UnknownQueryKind defines model for UnknownQuery.Kind. @@ -427,10 +433,9 @@ type UnknownQueryKind string // WorkspacesQuery defines model for WorkspacesQuery. type WorkspacesQuery struct { - BaseGrafanaTemplateVariableQuery - Kind WorkspacesQueryKind `json:"kind"` - RawQuery *string `json:"rawQuery,omitempty"` - Subscription string `json:"subscription"` + Kind *WorkspacesQueryKind `json:"kind,omitempty"` + RawQuery *string `json:"rawQuery,omitempty"` + Subscription *string `json:"subscription,omitempty"` } // WorkspacesQueryKind defines model for WorkspacesQuery.Kind. diff --git a/pkg/tsdb/azuremonitor/loganalytics/azure-log-analytics-datasource.go b/pkg/tsdb/azuremonitor/loganalytics/azure-log-analytics-datasource.go index 69e0886333f..cdfdc6a147d 100644 --- a/pkg/tsdb/azuremonitor/loganalytics/azure-log-analytics-datasource.go +++ b/pkg/tsdb/azuremonitor/loganalytics/azure-log-analytics-datasource.go @@ -410,9 +410,7 @@ func addTraceDataLinksToFields(query *AzureLogAnalyticsQuery, azurePortalBaseUrl logsQueryType := string(dataquery.AzureQueryTypeAzureLogAnalytics) logsJSONModel := dataquery.AzureMonitorQuery{ - DataQuery: dataquery.DataQuery{ - QueryType: &logsQueryType, - }, + QueryType: &logsQueryType, AzureLogAnalytics: &dataquery.AzureLogsQuery{ Query: &query.TraceLogsExploreQuery, Resources: []string{queryJSONModel.AzureTraces.Resources[0]}, diff --git a/pkg/tsdb/cloud-monitoring/kinds/dataquery/types_dataquery_gen.go b/pkg/tsdb/cloud-monitoring/kinds/dataquery/types_dataquery_gen.go index 08f2f3899d7..a508d09084c 100644 --- a/pkg/tsdb/cloud-monitoring/kinds/dataquery/types_dataquery_gen.go +++ b/pkg/tsdb/cloud-monitoring/kinds/dataquery/types_dataquery_gen.go @@ -89,20 +89,35 @@ type AlignmentTypes string // CloudMonitoringQuery defines model for CloudMonitoringQuery. type CloudMonitoringQuery struct { - // DataQuery These are the common properties available to all queries in all datasources. - // Specific implementations will *extend* this interface, adding the required - // properties for the given context. - DataQuery - // Aliases can be set to modify the legend labels. e.g. {{metric.label.xxx}}. See docs for more detail. AliasBy *string `json:"aliasBy,omitempty"` + // For mixed data sources the selected datasource is on the query level. + // For non mixed scenarios this is undefined. + // TODO find a better way to do this ^ that's friendly to schema + // TODO this shouldn't be unknown but DataSourceRef | null + Datasource *any `json:"datasource,omitempty"` + + // Hide true if query is disabled (ie should not be returned to the dashboard) + // Note this does not always imply that the query should not be executed since + // the results from a hidden query may be used as the input to other queries (SSE etc) + Hide *bool `json:"hide,omitempty"` + // Time interval in milliseconds. IntervalMs *float32 `json:"intervalMs,omitempty"` // PromQL sub-query properties. PromQLQuery *PromQLQuery `json:"promQLQuery,omitempty"` + // Specify the query flavor + // TODO make this required and give it a default + QueryType *string `json:"queryType,omitempty"` + + // A unique identifier for the query within the list of targets. + // In server side expressions, the refId is used as a variable name to identify results. + // By default, the UI will assign A->Z; however setting meaningful names may be useful. + RefId *string `json:"refId,omitempty"` + // SLO sub-query properties. SloQuery *SLOQuery `json:"sloQuery,omitempty"` diff --git a/pkg/tsdb/cloudwatch/annotation_query.go b/pkg/tsdb/cloudwatch/annotation_query.go index ce390c71d5e..c65bece8c2e 100644 --- a/pkg/tsdb/cloudwatch/annotation_query.go +++ b/pkg/tsdb/cloudwatch/annotation_query.go @@ -12,6 +12,7 @@ import ( "github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana-plugin-sdk-go/data" "github.com/grafana/grafana/pkg/tsdb/cloudwatch/kinds/dataquery" + "github.com/grafana/grafana/pkg/tsdb/cloudwatch/utils" ) type annotationEvent struct { @@ -50,7 +51,12 @@ func (e *cloudWatchExecutor) executeAnnotationQuery(ctx context.Context, pluginC actionPrefix := model.ActionPrefix alarmNamePrefix := model.AlarmNamePrefix - cli, err := e.getCWClient(ctx, pluginCtx, model.Region) + region := "" + if model.Region != nil { + region = *model.Region + } + + cli, err := e.getCWClient(ctx, pluginCtx, region) if err != nil { return nil, err } @@ -76,9 +82,9 @@ func (e *cloudWatchExecutor) executeAnnotationQuery(ctx context.Context, pluginC if err != nil { return nil, fmt.Errorf("%v: %w", "failed to call cloudwatch:DescribeAlarms", err) } - alarmNames = filterAlarms(resp, model.Namespace, metricName, dimensions, statistic, period) + alarmNames = filterAlarms(resp, utils.Depointerizer(model.Namespace), metricName, dimensions, statistic, period) } else { - if model.Region == "" || model.Namespace == "" || metricName == "" || statistic == "" { + if model.Region == nil || model.Namespace == nil || metricName == "" || statistic == "" { return result, errors.New("invalid annotations query") } @@ -96,7 +102,7 @@ func (e *cloudWatchExecutor) executeAnnotationQuery(ctx context.Context, pluginC } } params := &cloudwatch.DescribeAlarmsForMetricInput{ - Namespace: aws.String(model.Namespace), + Namespace: aws.String(utils.Depointerizer(model.Namespace)), MetricName: aws.String(metricName), Dimensions: qd, Statistic: aws.String(statistic), diff --git a/pkg/tsdb/cloudwatch/cloudwatch.go b/pkg/tsdb/cloudwatch/cloudwatch.go index 16d89678b01..11a83b05572 100644 --- a/pkg/tsdb/cloudwatch/cloudwatch.go +++ b/pkg/tsdb/cloudwatch/cloudwatch.go @@ -210,8 +210,12 @@ func (e *cloudWatchExecutor) QueryData(ctx context.Context, req *backend.QueryDa // Public dashboard queries execute like alert queries, i.e. they execute on the backend, therefore, we need to handle them synchronously. // Since `model.Type` is set during execution on the frontend by the query runner and isn't saved with the query, we are checking here is // missing the `model.Type` property and if it is a log query in order to determine if it is a public dashboard query. - fromPublicDashboard := (model.Type == "" && model.QueryMode == logsQueryMode) - isSyncLogQuery := ((fromAlert || fromExpression) && model.QueryMode == logsQueryMode) || fromPublicDashboard + queryMode := "" + if model.QueryMode != nil { + queryMode = string(*model.QueryMode) + } + fromPublicDashboard := model.Type == "" && queryMode == logsQueryMode + isSyncLogQuery := ((fromAlert || fromExpression) && queryMode == logsQueryMode) || fromPublicDashboard if isSyncLogQuery { return executeSyncLogQuery(ctx, e, req) } diff --git a/pkg/tsdb/cloudwatch/kinds/dataquery/types_dataquery_gen.go b/pkg/tsdb/cloudwatch/kinds/dataquery/types_dataquery_gen.go index a7c64c0de2e..ae27a172f9a 100644 --- a/pkg/tsdb/cloudwatch/kinds/dataquery/types_dataquery_gen.go +++ b/pkg/tsdb/cloudwatch/kinds/dataquery/types_dataquery_gen.go @@ -105,14 +105,11 @@ const ( QueryEditorPropertyTypeString QueryEditorPropertyType = "string" ) -// CloudWatchAnnotationQuery defines model for CloudWatchAnnotationQuery. +// Shape of a CloudWatch Annotation query +// +// TS type is CloudWatchDefaultQuery = Omit & CloudWatchMetricsQuery, declared in veneer +// #CloudWatchDefaultQuery: #CloudWatchLogsQuery & #CloudWatchMetricsQuery @cuetsy(kind="type") type CloudWatchAnnotationQuery struct { - // DataQuery These are the common properties available to all queries in all datasources. - // Specific implementations will *extend* this interface, adding the required - // properties for the given context. - DataQuery - MetricStat - // The ID of the AWS account to query for the metric, specifying `all` will query all accounts that the monitoring account is permitted to query. AccountId *string `json:"accountId,omitempty"` @@ -149,14 +146,14 @@ type CloudWatchAnnotationQuery struct { MetricName *string `json:"metricName,omitempty"` // A namespace is a container for CloudWatch metrics. Metrics in different namespaces are isolated from each other, so that metrics from different applications are not mistakenly aggregated into the same statistics. For example, Amazon EC2 uses the AWS/EC2 namespace. - Namespace string `json:"namespace"` + Namespace *string `json:"namespace,omitempty"` // The length of time associated with a specific Amazon CloudWatch statistic. Can be specified by a number of seconds, 'auto', or as a duration string e.g. '15m' being 15 minutes Period *string `json:"period,omitempty"` // Enable matching on the prefix of the action name or alarm name, specify the prefixes with actionPrefix and/or alarmNamePrefix - PrefixMatching *bool `json:"prefixMatching,omitempty"` - QueryMode CloudWatchQueryMode `json:"queryMode"` + PrefixMatching *bool `json:"prefixMatching,omitempty"` + QueryMode *CloudWatchQueryMode `json:"queryMode,omitempty"` // Specify the query flavor // TODO make this required and give it a default @@ -165,10 +162,10 @@ type CloudWatchAnnotationQuery struct { // A unique identifier for the query within the list of targets. // In server side expressions, the refId is used as a variable name to identify results. // By default, the UI will assign A->Z; however setting meaningful names may be useful. - RefId string `json:"refId"` + RefId *string `json:"refId,omitempty"` // AWS region to query for the metric - Region string `json:"region"` + Region *string `json:"region,omitempty"` // Metric data aggregations over specified periods of time. For detailed definitions of the statistics supported by CloudWatch, see https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Statistics-definitions.html. Statistic *string `json:"statistic,omitempty"` @@ -180,13 +177,8 @@ type CloudWatchAnnotationQuery struct { // CloudWatchDataQuery defines model for CloudWatchDataQuery. type CloudWatchDataQuery = map[string]any -// CloudWatchLogsQuery defines model for CloudWatchLogsQuery. +// Shape of a CloudWatch Logs query type CloudWatchLogsQuery struct { - // DataQuery These are the common properties available to all queries in all datasources. - // Specific implementations will *extend* this interface, adding the required - // properties for the given context. - DataQuery - // For mixed data sources the selected datasource is on the query level. // For non mixed scenarios this is undefined. // TODO find a better way to do this ^ that's friendly to schema @@ -199,15 +191,15 @@ type CloudWatchLogsQuery struct { // Hide true if query is disabled (ie should not be returned to the dashboard) // Note this does not always imply that the query should not be executed since // the results from a hidden query may be used as the input to other queries (SSE etc) - Hide *bool `json:"hide,omitempty"` - Id string `json:"id"` + Hide *bool `json:"hide,omitempty"` + Id *string `json:"id,omitempty"` // @deprecated use logGroups LogGroupNames []string `json:"logGroupNames,omitempty"` // Log groups to query - LogGroups []LogGroup `json:"logGroups,omitempty"` - QueryMode CloudWatchQueryMode `json:"queryMode"` + LogGroups []LogGroup `json:"logGroups,omitempty"` + QueryMode *CloudWatchQueryMode `json:"queryMode,omitempty"` // Specify the query flavor // TODO make this required and give it a default @@ -216,23 +208,17 @@ type CloudWatchLogsQuery struct { // A unique identifier for the query within the list of targets. // In server side expressions, the refId is used as a variable name to identify results. // By default, the UI will assign A->Z; however setting meaningful names may be useful. - RefId string `json:"refId"` + RefId *string `json:"refId,omitempty"` // AWS region to query for the logs - Region string `json:"region"` + Region *string `json:"region,omitempty"` // Fields to group the results by, this field is automatically populated whenever the query is updated StatsGroups []string `json:"statsGroups,omitempty"` } -// CloudWatchMetricsQuery defines model for CloudWatchMetricsQuery. +// Shape of a CloudWatch Metrics query type CloudWatchMetricsQuery struct { - // DataQuery These are the common properties available to all queries in all datasources. - // Specific implementations will *extend* this interface, adding the required - // properties for the given context. - DataQuery - MetricStat - // The ID of the AWS account to query for the metric, specifying `all` will query all accounts that the monitoring account is permitted to query. AccountId *string `json:"accountId,omitempty"` @@ -258,7 +244,7 @@ type CloudWatchMetricsQuery struct { Hide *bool `json:"hide,omitempty"` // ID can be used to reference other queries in math expressions. The ID can include numbers, letters, and underscore, and must start with a lowercase letter. - Id string `json:"id"` + Id *string `json:"id,omitempty"` // Change the time series legend names using dynamic labels. See https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/graph-dynamic-labels.html for more details. Label *string `json:"label,omitempty"` @@ -272,7 +258,7 @@ type CloudWatchMetricsQuery struct { MetricQueryType *MetricQueryType `json:"metricQueryType,omitempty"` // A namespace is a container for CloudWatch metrics. Metrics in different namespaces are isolated from each other, so that metrics from different applications are not mistakenly aggregated into the same statistics. For example, Amazon EC2 uses the AWS/EC2 namespace. - Namespace string `json:"namespace"` + Namespace *string `json:"namespace,omitempty"` // The length of time associated with a specific Amazon CloudWatch statistic. Can be specified by a number of seconds, 'auto', or as a duration string e.g. '15m' being 15 minutes Period *string `json:"period,omitempty"` @@ -285,10 +271,10 @@ type CloudWatchMetricsQuery struct { // A unique identifier for the query within the list of targets. // In server side expressions, the refId is used as a variable name to identify results. // By default, the UI will assign A->Z; however setting meaningful names may be useful. - RefId string `json:"refId"` + RefId *string `json:"refId,omitempty"` // AWS region to query for the metric - Region string `json:"region"` + Region *string `json:"region,omitempty"` Sql *SQLExpression `json:"sql,omitempty"` // When the metric query type is `metricQueryType` is set to `Query`, this field is used to specify the query string. diff --git a/pkg/tsdb/cloudwatch/log_actions.go b/pkg/tsdb/cloudwatch/log_actions.go index 416aaa676cc..ebf8e85058c 100644 --- a/pkg/tsdb/cloudwatch/log_actions.go +++ b/pkg/tsdb/cloudwatch/log_actions.go @@ -102,8 +102,8 @@ func (e *cloudWatchExecutor) executeLogAction(ctx context.Context, logsQuery mod } region := instance.Settings.Region - if logsQuery.Region != "" { - region = logsQuery.Region + if logsQuery.Region != nil { + region = *logsQuery.Region } logsClient, err := e.getCWLogsClient(ctx, pluginCtx, region) @@ -248,8 +248,8 @@ func (e *cloudWatchExecutor) handleStartQuery(ctx context.Context, logsClient cl dataFrame.RefID = refID region := "default" - if logsQuery.Region != "" { - region = logsQuery.Region + if logsQuery.Region != nil { + region = *logsQuery.Region } dataFrame.Meta = &data.FrameMeta{ diff --git a/pkg/tsdb/cloudwatch/log_sync_query.go b/pkg/tsdb/cloudwatch/log_sync_query.go index b64a2db8d92..9243058184b 100644 --- a/pkg/tsdb/cloudwatch/log_sync_query.go +++ b/pkg/tsdb/cloudwatch/log_sync_query.go @@ -12,6 +12,7 @@ import ( "github.com/grafana/grafana-plugin-sdk-go/data" "github.com/grafana/grafana/pkg/tsdb/cloudwatch/kinds/dataquery" "github.com/grafana/grafana/pkg/tsdb/cloudwatch/models" + "github.com/grafana/grafana/pkg/tsdb/cloudwatch/utils" ) const initialAlertPollPeriod = time.Second @@ -36,9 +37,9 @@ var executeSyncLogQuery = func(ctx context.Context, e *cloudWatchExecutor, req * logsQuery.QueryString = *logsQuery.Expression } - region := logsQuery.Region - if logsQuery.Region == "" || region == defaultRegion { - logsQuery.Region = instance.Settings.Region + region := utils.Depointerizer(logsQuery.Region) + if region == "" || region == defaultRegion { + logsQuery.Region = utils.Pointer(instance.Settings.Region) } logsClient, err := e.getCWLogsClient(ctx, req.PluginContext, region) diff --git a/pkg/tsdb/cloudwatch/models/cloudwatch_query.go b/pkg/tsdb/cloudwatch/models/cloudwatch_query.go index a6775cd404d..4d6afa1e9e7 100644 --- a/pkg/tsdb/cloudwatch/models/cloudwatch_query.go +++ b/pkg/tsdb/cloudwatch/models/cloudwatch_query.go @@ -17,6 +17,7 @@ import ( "github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana-plugin-sdk-go/backend/log" "github.com/grafana/grafana/pkg/tsdb/cloudwatch/kinds/dataquery" + "github.com/grafana/grafana/pkg/tsdb/cloudwatch/utils" ) type ( @@ -239,9 +240,9 @@ func ParseMetricDataQueries(dataQueries []backend.DataQuery, startTime time.Time cwQuery := &CloudWatchQuery{ logger: logger, RefId: refId, - Id: mdq.Id, - Region: mdq.Region, - Namespace: mdq.Namespace, + Id: utils.Depointerizer(mdq.Id), + Region: utils.Depointerizer(mdq.Region), + Namespace: utils.Depointerizer(mdq.Namespace), TimezoneUTCOffset: mdq.TimezoneUTCOffset, } @@ -314,7 +315,7 @@ func (q *CloudWatchQuery) validateAndSetDefaults(refId string, metricsDataQuery q.AccountId = metricsDataQuery.AccountId } - if metricsDataQuery.Id == "" { + if utils.Depointerizer(metricsDataQuery.Id) == "" { // Why not just use refId if id is not specified in the frontend? When specifying an id in the editor, // and alphabetical must be used. The id must be unique, so if an id like for example a, b or c would be used, // it would likely collide with some ref id. That's why the `query` prefix is used. diff --git a/pkg/tsdb/cloudwatch/models/cloudwatch_query_test.go b/pkg/tsdb/cloudwatch/models/cloudwatch_query_test.go index 7256d61c62f..f1d2ebc21c9 100644 --- a/pkg/tsdb/cloudwatch/models/cloudwatch_query_test.go +++ b/pkg/tsdb/cloudwatch/models/cloudwatch_query_test.go @@ -7,8 +7,6 @@ import ( "testing" "time" - "github.com/grafana/kindsys" - "github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana-plugin-sdk-go/backend/log" "github.com/grafana/grafana/pkg/tsdb/cloudwatch/kinds/dataquery" @@ -898,15 +896,15 @@ func Test_migrateAliasToDynamicLabel_single_query_preserves_old_alias_and_create queryToMigrate := metricsDataQuery{ CloudWatchMetricsQuery: dataquery.CloudWatchMetricsQuery{ - Region: "us-east-1", - Namespace: "ec2", - MetricName: kindsys.Ptr("CPUUtilization"), - Alias: kindsys.Ptr(tc.inputAlias), + Region: utils.Pointer("us-east-1"), + Namespace: utils.Pointer("ec2"), + MetricName: utils.Pointer("CPUUtilization"), + Alias: utils.Pointer(tc.inputAlias), Dimensions: &dataquery.Dimensions{ "InstanceId": []any{"test"}, }, Statistic: &average, - Period: kindsys.Ptr("600"), + Period: utils.Pointer("600"), Hide: &false, }, } diff --git a/pkg/tsdb/cloudwatch/utils/utils.go b/pkg/tsdb/cloudwatch/utils/utils.go index 55163896228..bf5e8f9d0a7 100644 --- a/pkg/tsdb/cloudwatch/utils/utils.go +++ b/pkg/tsdb/cloudwatch/utils/utils.go @@ -4,6 +4,15 @@ import "github.com/go-stack/stack" func Pointer[T any](arg T) *T { return &arg } +func Depointerizer[T any](v *T) T { + var emptyValue T + if v != nil { + emptyValue = *v + } + + return emptyValue +} + // Stack is copied from grafana/pkg/infra/log // TODO: maybe this should live in grafana-plugin-sdk-go? func Stack(skip int) string { diff --git a/pkg/tsdb/grafana-pyroscope-datasource/kinds/dataquery/types_dataquery_gen.go b/pkg/tsdb/grafana-pyroscope-datasource/kinds/dataquery/types_dataquery_gen.go index 44f2fb912bd..7f10cf02697 100644 --- a/pkg/tsdb/grafana-pyroscope-datasource/kinds/dataquery/types_dataquery_gen.go +++ b/pkg/tsdb/grafana-pyroscope-datasource/kinds/dataquery/types_dataquery_gen.go @@ -43,11 +43,6 @@ type DataQuery struct { // GrafanaPyroscopeDataQuery defines model for GrafanaPyroscopeDataQuery. type GrafanaPyroscopeDataQuery struct { - // DataQuery These are the common properties available to all queries in all datasources. - // Specific implementations will *extend* this interface, adding the required - // properties for the given context. - DataQuery - // For mixed data sources the selected datasource is on the query level. // For non mixed scenarios this is undefined. // TODO find a better way to do this ^ that's friendly to schema @@ -55,7 +50,7 @@ type GrafanaPyroscopeDataQuery struct { Datasource *any `json:"datasource,omitempty"` // Allows to group the results. - GroupBy []string `json:"groupBy"` + GroupBy []string `json:"groupBy,omitempty"` // Hide true if query is disabled (ie should not be returned to the dashboard) // Note this does not always imply that the query should not be executed since @@ -63,13 +58,13 @@ type GrafanaPyroscopeDataQuery struct { Hide *bool `json:"hide,omitempty"` // Specifies the query label selectors. - LabelSelector string `json:"labelSelector"` + LabelSelector *string `json:"labelSelector,omitempty"` // Sets the maximum number of nodes in the flamegraph. MaxNodes *int64 `json:"maxNodes,omitempty"` // Specifies the type of profile to query. - ProfileTypeId string `json:"profileTypeId"` + ProfileTypeId *string `json:"profileTypeId,omitempty"` // Specify the query flavor // TODO make this required and give it a default @@ -78,7 +73,7 @@ type GrafanaPyroscopeDataQuery struct { // A unique identifier for the query within the list of targets. // In server side expressions, the refId is used as a variable name to identify results. // By default, the UI will assign A->Z; however setting meaningful names may be useful. - RefId string `json:"refId"` + RefId *string `json:"refId,omitempty"` // Specifies the query span selectors. SpanSelector []string `json:"spanSelector,omitempty"` diff --git a/pkg/tsdb/grafana-pyroscope-datasource/query.go b/pkg/tsdb/grafana-pyroscope-datasource/query.go index f62df698798..5d6d0ce17ae 100644 --- a/pkg/tsdb/grafana-pyroscope-datasource/query.go +++ b/pkg/tsdb/grafana-pyroscope-datasource/query.go @@ -52,6 +52,9 @@ func (d *PyroscopeDatasource) query(ctx context.Context, pCtx backend.PluginCont return response } + profileTypeId := depointerizer(qm.ProfileTypeId) + labelSelector := depointerizer(qm.LabelSelector) + responseMutex := sync.Mutex{} g, gCtx := errgroup.WithContext(ctx) if query.QueryType == queryTypeMetrics || query.QueryType == queryTypeBoth { @@ -75,8 +78,8 @@ func (d *PyroscopeDatasource) query(ctx context.Context, pCtx backend.PluginCont logger.Debug("Sending SelectSeriesRequest", "queryModel", qm, "function", logEntrypoint()) seriesResp, err := d.client.GetSeries( gCtx, - qm.ProfileTypeId, - qm.LabelSelector, + profileTypeId, + labelSelector, query.TimeRange.From.UnixMilli(), query.TimeRange.To.UnixMilli(), qm.GroupBy, @@ -101,7 +104,7 @@ func (d *PyroscopeDatasource) query(ctx context.Context, pCtx backend.PluginCont var profileResp *ProfileResponse if len(qm.SpanSelector) > 0 { logger.Debug("Calling GetSpanProfile", "queryModel", qm, "function", logEntrypoint()) - prof, err := d.client.GetSpanProfile(gCtx, qm.ProfileTypeId, qm.LabelSelector, qm.SpanSelector, query.TimeRange.From.UnixMilli(), query.TimeRange.To.UnixMilli(), qm.MaxNodes) + prof, err := d.client.GetSpanProfile(gCtx, profileTypeId, labelSelector, qm.SpanSelector, query.TimeRange.From.UnixMilli(), query.TimeRange.To.UnixMilli(), qm.MaxNodes) if err != nil { span.RecordError(err) span.SetStatus(codes.Error, err.Error()) @@ -111,7 +114,7 @@ func (d *PyroscopeDatasource) query(ctx context.Context, pCtx backend.PluginCont profileResp = prof } else { logger.Debug("Calling GetProfile", "queryModel", qm, "function", logEntrypoint()) - prof, err := d.client.GetProfile(gCtx, qm.ProfileTypeId, qm.LabelSelector, query.TimeRange.From.UnixMilli(), query.TimeRange.To.UnixMilli(), qm.MaxNodes) + prof, err := d.client.GetProfile(gCtx, profileTypeId, labelSelector, query.TimeRange.From.UnixMilli(), query.TimeRange.To.UnixMilli(), qm.MaxNodes) if err != nil { span.RecordError(err) span.SetStatus(codes.Error, err.Error()) @@ -450,3 +453,12 @@ func seriesToDataFrames(resp *SeriesResponse) []*data.Frame { } return frames } + +func depointerizer[T any](v *T) T { + var emptyValue T + if v != nil { + emptyValue = *v + } + + return emptyValue +} diff --git a/pkg/tsdb/grafana-testdata-datasource/kinds/dataquery/types_dataquery_gen.go b/pkg/tsdb/grafana-testdata-datasource/kinds/dataquery/types_dataquery_gen.go index 95fec94c962..f69bc0c6c4f 100644 --- a/pkg/tsdb/grafana-testdata-datasource/kinds/dataquery/types_dataquery_gen.go +++ b/pkg/tsdb/grafana-testdata-datasource/kinds/dataquery/types_dataquery_gen.go @@ -26,11 +26,11 @@ const ( StreamingQueryTypeTraces StreamingQueryType = "traces" ) -// Defines values for ErrorType. +// Defines values for TestDataDataQueryErrorType. const ( - ErrorTypeFrontendException ErrorType = "frontend_exception" - ErrorTypeFrontendObservable ErrorType = "frontend_observable" - ErrorTypeServerPanic ErrorType = "server_panic" + TestDataDataQueryErrorTypeFrontendException TestDataDataQueryErrorType = "frontend_exception" + TestDataDataQueryErrorTypeFrontendObservable TestDataDataQueryErrorType = "frontend_observable" + TestDataDataQueryErrorTypeServerPanic TestDataDataQueryErrorType = "server_panic" ) // Defines values for TestDataQueryType. @@ -154,38 +154,54 @@ type StreamingQueryType string // TestDataDataQuery defines model for TestDataDataQuery. type TestDataDataQuery struct { - // DataQuery These are the common properties available to all queries in all datasources. - // Specific implementations will *extend* this interface, adding the required - // properties for the given context. - DataQuery Alias *string `json:"alias,omitempty"` Channel *string `json:"channel,omitempty"` CsvContent *string `json:"csvContent,omitempty"` CsvFileName *string `json:"csvFileName,omitempty"` CsvWave []CSVWave `json:"csvWave,omitempty"` + // For mixed data sources the selected datasource is on the query level. + // For non mixed scenarios this is undefined. + // TODO find a better way to do this ^ that's friendly to schema + // TODO this shouldn't be unknown but DataSourceRef | null + Datasource *any `json:"datasource,omitempty"` + // Drop percentage (the chance we will lose a point 0-100) - DropPercent *float64 `json:"dropPercent,omitempty"` - ErrorType *ErrorType `json:"errorType,omitempty"` - FlamegraphDiff *bool `json:"flamegraphDiff,omitempty"` - Labels *string `json:"labels,omitempty"` - LevelColumn *bool `json:"levelColumn,omitempty"` - Lines *int64 `json:"lines,omitempty"` - Nodes *NodesQuery `json:"nodes,omitempty"` - Points [][]any `json:"points,omitempty"` - PulseWave *PulseWaveQuery `json:"pulseWave,omitempty"` - RawFrameContent *string `json:"rawFrameContent,omitempty"` - ScenarioId *TestDataQueryType `json:"scenarioId,omitempty"` - SeriesCount *int32 `json:"seriesCount,omitempty"` - Sim *SimulationQuery `json:"sim,omitempty"` - SpanCount *int32 `json:"spanCount,omitempty"` - Stream *StreamingQuery `json:"stream,omitempty"` - StringInput *string `json:"stringInput,omitempty"` - Usa *USAQuery `json:"usa,omitempty"` + DropPercent *float64 `json:"dropPercent,omitempty"` + ErrorType *TestDataDataQueryErrorType `json:"errorType,omitempty"` + FlamegraphDiff *bool `json:"flamegraphDiff,omitempty"` + + // Hide true if query is disabled (ie should not be returned to the dashboard) + // Note this does not always imply that the query should not be executed since + // the results from a hidden query may be used as the input to other queries (SSE etc) + Hide *bool `json:"hide,omitempty"` + Labels *string `json:"labels,omitempty"` + LevelColumn *bool `json:"levelColumn,omitempty"` + Lines *int64 `json:"lines,omitempty"` + Nodes *NodesQuery `json:"nodes,omitempty"` + Points [][]any `json:"points,omitempty"` + PulseWave *PulseWaveQuery `json:"pulseWave,omitempty"` + + // Specify the query flavor + // TODO make this required and give it a default + QueryType *string `json:"queryType,omitempty"` + RawFrameContent *string `json:"rawFrameContent,omitempty"` + + // A unique identifier for the query within the list of targets. + // In server side expressions, the refId is used as a variable name to identify results. + // By default, the UI will assign A->Z; however setting meaningful names may be useful. + RefId *string `json:"refId,omitempty"` + ScenarioId *TestDataQueryType `json:"scenarioId,omitempty"` + SeriesCount *int32 `json:"seriesCount,omitempty"` + Sim *SimulationQuery `json:"sim,omitempty"` + SpanCount *int32 `json:"spanCount,omitempty"` + Stream *StreamingQuery `json:"stream,omitempty"` + StringInput *string `json:"stringInput,omitempty"` + Usa *USAQuery `json:"usa,omitempty"` } -// ErrorType defines model for TestDataDataQuery.ErrorType. -type ErrorType string +// TestDataDataQueryErrorType defines model for TestDataDataQuery.ErrorType. +type TestDataDataQueryErrorType string // TestDataQueryType defines model for TestDataQueryType. type TestDataQueryType string diff --git a/pkg/tsdb/loki/healthcheck.go b/pkg/tsdb/loki/healthcheck.go index fe7e56661b2..1bcd17e6be2 100644 --- a/pkg/tsdb/loki/healthcheck.go +++ b/pkg/tsdb/loki/healthcheck.go @@ -11,6 +11,7 @@ import ( "github.com/grafana/grafana-plugin-sdk-go/backend/log" "github.com/grafana/grafana/pkg/tsdb/loki/kinds/dataquery" + "github.com/grafana/grafana/pkg/util" ) const ( @@ -39,7 +40,7 @@ func healthcheck(ctx context.Context, req *backend.CheckHealthRequest, s *Servic step := "1s" qt := "instant" qm := dataquery.LokiDataQuery{ - Expr: "vector(1)+vector(1)", + Expr: util.Pointer("vector(1)+vector(1)"), Step: &step, QueryType: &qt, } diff --git a/pkg/tsdb/loki/kinds/dataquery/types_dataquery_gen.go b/pkg/tsdb/loki/kinds/dataquery/types_dataquery_gen.go index db33add2813..85ea8bf1688 100644 --- a/pkg/tsdb/loki/kinds/dataquery/types_dataquery_gen.go +++ b/pkg/tsdb/loki/kinds/dataquery/types_dataquery_gen.go @@ -63,11 +63,6 @@ type DataQuery struct { // LokiDataQuery defines model for LokiDataQuery. type LokiDataQuery struct { - // DataQuery These are the common properties available to all queries in all datasources. - // Specific implementations will *extend* this interface, adding the required - // properties for the given context. - DataQuery - // For mixed data sources the selected datasource is on the query level. // For non mixed scenarios this is undefined. // TODO find a better way to do this ^ that's friendly to schema @@ -76,7 +71,7 @@ type LokiDataQuery struct { EditorMode *QueryEditorMode `json:"editorMode,omitempty"` // The LogQL query. - Expr string `json:"expr"` + Expr *string `json:"expr,omitempty"` // Hide true if query is disabled (ie should not be returned to the dashboard) // Note this does not always imply that the query should not be executed since @@ -102,7 +97,7 @@ type LokiDataQuery struct { // A unique identifier for the query within the list of targets. // In server side expressions, the refId is used as a variable name to identify results. // By default, the UI will assign A->Z; however setting meaningful names may be useful. - RefId string `json:"refId"` + RefId *string `json:"refId,omitempty"` // @deprecated, now use step. Resolution *int64 `json:"resolution,omitempty"` diff --git a/pkg/tsdb/loki/parse_query.go b/pkg/tsdb/loki/parse_query.go index 60ace2430c8..950e360fd85 100644 --- a/pkg/tsdb/loki/parse_query.go +++ b/pkg/tsdb/loki/parse_query.go @@ -149,7 +149,7 @@ func parseQuery(queryContext *backend.QueryDataRequest) ([]*lokiQuery, error) { return nil, err } - expr := interpolateVariables(model.Expr, interval, timeRange, queryType, step) + expr := interpolateVariables(depointerizer(model.Expr), interval, timeRange, queryType, step) direction, err := parseDirection(model.Direction) if err != nil { @@ -187,3 +187,12 @@ func parseQuery(queryContext *backend.QueryDataRequest) ([]*lokiQuery, error) { return qs, nil } + +func depointerizer[T any](v *T) T { + var emptyValue T + if v != nil { + emptyValue = *v + } + + return emptyValue +} diff --git a/pkg/tsdb/loki/streaming.go b/pkg/tsdb/loki/streaming.go index 49eb287e9d3..29eb7be93a5 100644 --- a/pkg/tsdb/loki/streaming.go +++ b/pkg/tsdb/loki/streaming.go @@ -34,7 +34,7 @@ func (s *Service) SubscribeStream(ctx context.Context, req *backend.SubscribeStr if err != nil { return nil, err } - if query.Expr == "" { + if query.Expr != nil { return &backend.SubscribeStreamResponse{ Status: backend.SubscribeStreamStatusNotFound, }, fmt.Errorf("missing expr in channel (subscribe)") @@ -69,7 +69,7 @@ func (s *Service) RunStream(ctx context.Context, req *backend.RunStreamRequest, if err != nil { return err } - if query.Expr == "" { + if query.Expr != nil { return fmt.Errorf("missing expr in cuannel") } @@ -80,7 +80,7 @@ func (s *Service) RunStream(ctx context.Context, req *backend.RunStreamRequest, signal.Notify(interrupt, os.Interrupt) params := url.Values{} - params.Add("query", query.Expr) + params.Add("query", *query.Expr) wsurl, _ := url.Parse(dsInfo.URL) @@ -149,7 +149,7 @@ func (s *Service) RunStream(ctx context.Context, req *backend.RunStreamRequest, } }() - ticker := time.NewTicker(time.Second * 60) //.Step) + ticker := time.NewTicker(time.Second * 60) // .Step) defer ticker.Stop() for { diff --git a/pkg/tsdb/parca/kinds/dataquery/types_dataquery_gen.go b/pkg/tsdb/parca/kinds/dataquery/types_dataquery_gen.go index 346237c487a..fb1550812c2 100644 --- a/pkg/tsdb/parca/kinds/dataquery/types_dataquery_gen.go +++ b/pkg/tsdb/parca/kinds/dataquery/types_dataquery_gen.go @@ -43,11 +43,6 @@ type DataQuery struct { // ParcaDataQuery defines model for ParcaDataQuery. type ParcaDataQuery struct { - // DataQuery These are the common properties available to all queries in all datasources. - // Specific implementations will *extend* this interface, adding the required - // properties for the given context. - DataQuery - // For mixed data sources the selected datasource is on the query level. // For non mixed scenarios this is undefined. // TODO find a better way to do this ^ that's friendly to schema @@ -60,10 +55,10 @@ type ParcaDataQuery struct { Hide *bool `json:"hide,omitempty"` // Specifies the query label selectors. - LabelSelector string `json:"labelSelector"` + LabelSelector *string `json:"labelSelector,omitempty"` // Specifies the type of profile to query. - ProfileTypeId string `json:"profileTypeId"` + ProfileTypeId *string `json:"profileTypeId,omitempty"` // Specify the query flavor // TODO make this required and give it a default @@ -72,7 +67,7 @@ type ParcaDataQuery struct { // A unique identifier for the query within the list of targets. // In server side expressions, the refId is used as a variable name to identify results. // By default, the UI will assign A->Z; however setting meaningful names may be useful. - RefId string `json:"refId"` + RefId *string `json:"refId,omitempty"` } // ParcaQueryType defines model for ParcaQueryType. diff --git a/pkg/tsdb/parca/query.go b/pkg/tsdb/parca/query.go index a01346bcde8..97e6a3e1ec5 100644 --- a/pkg/tsdb/parca/query.go +++ b/pkg/tsdb/parca/query.go @@ -12,6 +12,7 @@ import ( "github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana-plugin-sdk-go/backend/tracing" "github.com/grafana/grafana-plugin-sdk-go/data" + "github.com/grafana/grafana/pkg/tsdb/cloudwatch/utils" "github.com/grafana/grafana/pkg/tsdb/parca/kinds/dataquery" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/codes" @@ -56,7 +57,8 @@ func (d *ParcaDatasource) query(ctx context.Context, pCtx backend.PluginContext, span.SetStatus(codes.Error, response.Error.Error()) return response } - response.Frames = append(response.Frames, seriesToDataFrame(seriesResp, qm.ProfileTypeId)...) + + response.Frames = append(response.Frames, seriesToDataFrame(seriesResp, utils.Depointerizer(qm.ProfileTypeId))...) } if query.QueryType == queryTypeProfile || query.QueryType == queryTypeBoth { @@ -82,7 +84,7 @@ func makeProfileRequest(qm queryModel, query backend.DataQuery) *connect.Request Mode: v1alpha1.QueryRequest_MODE_MERGE, Options: &v1alpha1.QueryRequest_Merge{ Merge: &v1alpha1.MergeProfile{ - Query: fmt.Sprintf("%s%s", qm.ProfileTypeId, qm.LabelSelector), + Query: fmt.Sprintf("%s%s", utils.Depointerizer(qm.ProfileTypeId), utils.Depointerizer(qm.LabelSelector)), Start: ×tamppb.Timestamp{ Seconds: query.TimeRange.From.Unix(), }, @@ -101,7 +103,7 @@ func makeProfileRequest(qm queryModel, query backend.DataQuery) *connect.Request func makeMetricRequest(qm queryModel, query backend.DataQuery) *connect.Request[v1alpha1.QueryRangeRequest] { return &connect.Request[v1alpha1.QueryRangeRequest]{ Msg: &v1alpha1.QueryRangeRequest{ - Query: fmt.Sprintf("%s%s", qm.ProfileTypeId, qm.LabelSelector), + Query: fmt.Sprintf("%s%s", utils.Depointerizer(qm.ProfileTypeId), utils.Depointerizer(qm.LabelSelector)), Start: ×tamppb.Timestamp{ Seconds: query.TimeRange.From.Unix(), }, diff --git a/pkg/tsdb/tempo/kinds/dataquery/types_dataquery_gen.go b/pkg/tsdb/tempo/kinds/dataquery/types_dataquery_gen.go index 032df5714f2..b9ef0ee1895 100644 --- a/pkg/tsdb/tempo/kinds/dataquery/types_dataquery_gen.go +++ b/pkg/tsdb/tempo/kinds/dataquery/types_dataquery_gen.go @@ -78,17 +78,12 @@ type TempoDataQuery = map[string]any // TempoQuery defines model for TempoQuery. type TempoQuery struct { - // DataQuery These are the common properties available to all queries in all datasources. - // Specific implementations will *extend* this interface, adding the required - // properties for the given context. - DataQuery - // For mixed data sources the selected datasource is on the query level. // For non mixed scenarios this is undefined. // TODO find a better way to do this ^ that's friendly to schema // TODO this shouldn't be unknown but DataSourceRef | null Datasource *any `json:"datasource,omitempty"` - Filters []TraceqlFilter `json:"filters"` + Filters []TraceqlFilter `json:"filters,omitempty"` // Filters that are used to query the metrics summary GroupBy []TraceqlFilter `json:"groupBy,omitempty"` @@ -117,7 +112,7 @@ type TempoQuery struct { // A unique identifier for the query within the list of targets. // In server side expressions, the refId is used as a variable name to identify results. // By default, the UI will assign A->Z; however setting meaningful names may be useful. - RefId string `json:"refId"` + RefId *string `json:"refId,omitempty"` // @deprecated Logfmt query to filter traces by their tags. Example: http.status_code=200 error=true Search *string `json:"search,omitempty"` diff --git a/public/app/plugins/gen.go b/public/app/plugins/gen.go index 693a8af0fa2..9d1d9bb691c 100644 --- a/public/app/plugins/gen.go +++ b/public/app/plugins/gen.go @@ -8,18 +8,15 @@ package main import ( "context" "fmt" - "github.com/grafana/codejen" - corecodegen "github.com/grafana/grafana/pkg/codegen" - "github.com/grafana/grafana/pkg/cuectx" - "github.com/grafana/grafana/pkg/plugins/codegen" - "github.com/grafana/grafana/pkg/plugins/pfs" - "github.com/grafana/kindsys" - "github.com/grafana/thema" - "io/fs" "log" "os" "path/filepath" "strings" + + "github.com/grafana/codejen" + corecodegen "github.com/grafana/grafana/pkg/codegen" + "github.com/grafana/grafana/pkg/plugins/codegen" + "github.com/grafana/grafana/pkg/plugins/pfs" ) var skipPlugins = map[string]bool{ @@ -40,25 +37,20 @@ func main() { log.Fatal(fmt.Errorf("could not get working directory: %s", err)) } groot := filepath.Clean(filepath.Join(cwd, "../../..")) - rt := cuectx.GrafanaThemaRuntime() pluginKindGen := codejen.JennyListWithNamer(func(d *pfs.PluginDecl) string { return d.PluginMeta.Id }) pluginKindGen.Append( + &codegen.PluginRegistryJenny{}, codegen.PluginGoTypesJenny("pkg/tsdb"), codegen.PluginTSTypesJenny("public/app/plugins"), ) - schifs := kindsys.SchemaInterfaces(rt.Context()) - schifnames := make([]string, 0, len(schifs)) - for _, schif := range schifs { - schifnames = append(schifnames, strings.ToLower(schif.Name())) - } - pluginKindGen.AddPostprocessors(corecodegen.SlashHeaderMapper("public/app/plugins/gen.go"), splitSchiffer(schifnames)) + pluginKindGen.AddPostprocessors(corecodegen.SlashHeaderMapper("public/app/plugins/gen.go"), splitSchiffer()) - declParser := pfs.NewDeclParser(rt, skipPlugins) + declParser := pfs.NewDeclParser(skipPlugins) decls, err := declParser.Parse(os.DirFS(cwd)) if err != nil { log.Fatalln(fmt.Errorf("parsing plugins in dir failed %s: %s", cwd, err)) @@ -69,15 +61,6 @@ func main() { log.Fatalln(fmt.Errorf("error writing files to disk: %s", err)) } - rawResources, err := genRawResources() - if err != nil { - log.Fatalln(fmt.Errorf("error generating raw plugin resources: %s", err)) - } - - if err := jfs.Merge(rawResources); err != nil { - log.Fatalln(fmt.Errorf("Unable to merge raw resources: %s", err)) - } - if _, set := os.LookupEnv("CODEGEN_VERIFY"); set { if err = jfs.Verify(context.Background(), groot); err != nil { log.Fatal(fmt.Errorf("generated code is out of sync with inputs:\n%s\nrun `make gen-cue` to regenerate", err)) @@ -87,20 +70,8 @@ func main() { } } -func kind2pd(rt *thema.Runtime, j codejen.OneToOne[kindsys.Kind]) codejen.OneToOne[*pfs.PluginDecl] { - return codejen.AdaptOneToOne(j, func(pd *pfs.PluginDecl) kindsys.Kind { - kd, err := kindsys.BindComposable(rt, pd.KindDecl) - if err != nil { - return nil - } - return kd - }) -} - -func splitSchiffer(names []string) codejen.FileMapper { - for i := range names { - names[i] = names[i] + "/" - } +func splitSchiffer() codejen.FileMapper { + names := []string{"panelcfg", "dataquery"} return func(f codejen.File) (codejen.File, error) { // TODO it's terrible that this has to exist, CODEJEN NEEDS TO BE BETTER path := filepath.ToSlash(f.RelativePath) @@ -113,28 +84,3 @@ func splitSchiffer(names []string) codejen.FileMapper { return f, nil } } - -func genRawResources() (*codejen.FS, error) { - jennies := codejen.JennyListWithNamer(func(d []string) string { - return "PluginsRawResources" - }) - jennies.Append(&codegen.PluginRegistryJenny{}) - - schemas := make([]string, 0) - filepath.WalkDir(".", func(path string, d fs.DirEntry, err error) error { - if d.IsDir() { - return nil - } - - if !strings.HasSuffix(d.Name(), ".cue") { - return nil - } - - schemas = append(schemas, "./"+filepath.Join("public", "app", "plugins", path)) - return nil - }) - - jennies.AddPostprocessors(corecodegen.SlashHeaderMapper("public/app/plugins/gen.go")) - - return jennies.GenerateFS(schemas) -}