mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
coremodels: Update to latest Thema with generics (#56602)
* Update thema to latest * Deal with s/Library/*Runtime/ * Commit new, working results of codegen
This commit is contained in:
parent
668cb25b82
commit
e5a6547a94
2
go.mod
2
go.mod
@ -58,7 +58,7 @@ require (
|
|||||||
github.com/grafana/grafana-aws-sdk v0.11.0
|
github.com/grafana/grafana-aws-sdk v0.11.0
|
||||||
github.com/grafana/grafana-azure-sdk-go v1.3.1
|
github.com/grafana/grafana-azure-sdk-go v1.3.1
|
||||||
github.com/grafana/grafana-plugin-sdk-go v0.139.0
|
github.com/grafana/grafana-plugin-sdk-go v0.139.0
|
||||||
github.com/grafana/thema v0.0.0-20220817114012-ebeee841c104
|
github.com/grafana/thema v0.0.0-20220929145912-2c7c4a7bb20b
|
||||||
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0
|
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0
|
||||||
github.com/hashicorp/go-hclog v1.0.0
|
github.com/hashicorp/go-hclog v1.0.0
|
||||||
github.com/hashicorp/go-plugin v1.4.3
|
github.com/hashicorp/go-plugin v1.4.3
|
||||||
|
2
go.sum
2
go.sum
@ -1380,6 +1380,8 @@ github.com/grafana/saml v0.4.9-0.20220727151557-61cd9c9353fc h1:1PY8n+rXuBNr3r1J
|
|||||||
github.com/grafana/saml v0.4.9-0.20220727151557-61cd9c9353fc/go.mod h1:9Zh6dWPtB3MSzTRt8fIFH60Z351QQ+s7hCU3J/tTlA4=
|
github.com/grafana/saml v0.4.9-0.20220727151557-61cd9c9353fc/go.mod h1:9Zh6dWPtB3MSzTRt8fIFH60Z351QQ+s7hCU3J/tTlA4=
|
||||||
github.com/grafana/thema v0.0.0-20220817114012-ebeee841c104 h1:dYpwFYIChrMfpq3wDa/ZBxAbUGSW5NYmYBeSezhaoao=
|
github.com/grafana/thema v0.0.0-20220817114012-ebeee841c104 h1:dYpwFYIChrMfpq3wDa/ZBxAbUGSW5NYmYBeSezhaoao=
|
||||||
github.com/grafana/thema v0.0.0-20220817114012-ebeee841c104/go.mod h1:fCV1rqv6XRQg2GfIQ7pU9zdxd5fLRcEBCnrDVwlK+ZY=
|
github.com/grafana/thema v0.0.0-20220817114012-ebeee841c104/go.mod h1:fCV1rqv6XRQg2GfIQ7pU9zdxd5fLRcEBCnrDVwlK+ZY=
|
||||||
|
github.com/grafana/thema v0.0.0-20220929145912-2c7c4a7bb20b h1:OEGzlaj04LE6Eq7aGMOh0bCplGW5rXNeSSSwgamPBEY=
|
||||||
|
github.com/grafana/thema v0.0.0-20220929145912-2c7c4a7bb20b/go.mod h1:i3/NX50sNrwsPSAQAj56ckjQTb4biaYG/6y+zyKgpb0=
|
||||||
github.com/grafana/xorm v0.8.3-0.20220614223926-2fcda7565af6 h1:I9dh1MXGX0wGyxdV/Sl7+ugnki4Dfsy8lv2s5Yf887o=
|
github.com/grafana/xorm v0.8.3-0.20220614223926-2fcda7565af6 h1:I9dh1MXGX0wGyxdV/Sl7+ugnki4Dfsy8lv2s5Yf887o=
|
||||||
github.com/grafana/xorm v0.8.3-0.20220614223926-2fcda7565af6/go.mod h1:ZkJLEYLoVyg7amJK/5r779bHyzs2AU8f8VMiP6BM7uY=
|
github.com/grafana/xorm v0.8.3-0.20220614223926-2fcda7565af6/go.mod h1:ZkJLEYLoVyg7amJK/5r779bHyzs2AU8f8VMiP6BM7uY=
|
||||||
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
|
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
|
||||||
|
@ -301,8 +301,8 @@ var wireSet = wire.NewSet(
|
|||||||
authproxy.ProvideAuthProxy,
|
authproxy.ProvideAuthProxy,
|
||||||
statscollector.ProvideService,
|
statscollector.ProvideService,
|
||||||
cmreg.CoremodelSet,
|
cmreg.CoremodelSet,
|
||||||
cuectx.ProvideCUEContext,
|
cuectx.GrafanaCUEContext,
|
||||||
cuectx.ProvideThemaLibrary,
|
cuectx.GrafanaThemaRuntime,
|
||||||
csrf.ProvideCSRFFilter,
|
csrf.ProvideCSRFFilter,
|
||||||
ossaccesscontrol.ProvideTeamPermissions,
|
ossaccesscontrol.ProvideTeamPermissions,
|
||||||
wire.Bind(new(accesscontrol.TeamPermissionsService), new(*ossaccesscontrol.TeamPermissionsService)),
|
wire.Bind(new(accesscontrol.TeamPermissionsService), new(*ossaccesscontrol.TeamPermissionsService)),
|
||||||
|
@ -50,7 +50,7 @@ type CoremodelDeclaration struct {
|
|||||||
// This loading approach is intended primarily for use with code generators, or
|
// This loading approach is intended primarily for use with code generators, or
|
||||||
// other use cases external to grafana-server backend. For code within
|
// other use cases external to grafana-server backend. For code within
|
||||||
// grafana-server, prefer lineage loaders provided in e.g. pkg/coremodel/*.
|
// grafana-server, prefer lineage loaders provided in e.g. pkg/coremodel/*.
|
||||||
func ExtractLineage(path string, lib thema.Library) (*CoremodelDeclaration, error) {
|
func ExtractLineage(path string, rt *thema.Runtime) (*CoremodelDeclaration, error) {
|
||||||
if !filepath.IsAbs(path) {
|
if !filepath.IsAbs(path) {
|
||||||
return nil, fmt.Errorf("must provide an absolute path, got %q", path)
|
return nil, fmt.Errorf("must provide an absolute path, got %q", path)
|
||||||
}
|
}
|
||||||
@ -99,7 +99,7 @@ func ExtractLineage(path string, lib thema.Library) (*CoremodelDeclaration, erro
|
|||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
ec.RelativePath = filepath.ToSlash(ec.RelativePath)
|
ec.RelativePath = filepath.ToSlash(ec.RelativePath)
|
||||||
ec.Lineage, err = cuectx.LoadGrafanaInstancesWithThema(filepath.Dir(ec.RelativePath), fs, lib)
|
ec.Lineage, err = cuectx.LoadGrafanaInstancesWithThema(filepath.Dir(ec.RelativePath), fs, rt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ec, err
|
return ec, err
|
||||||
}
|
}
|
||||||
@ -156,7 +156,7 @@ func (cd *CoremodelDeclaration) PathVersion() string {
|
|||||||
// The provided path must be a directory. Generated code files will be written
|
// The provided path must be a directory. Generated code files will be written
|
||||||
// to that path. The final element of the path must match the Lineage.Name().
|
// to that path. The final element of the path must match the Lineage.Name().
|
||||||
func (cd *CoremodelDeclaration) GenerateGoCoremodel(path string) (WriteDiffer, error) {
|
func (cd *CoremodelDeclaration) GenerateGoCoremodel(path string) (WriteDiffer, error) {
|
||||||
lin, lib := cd.Lineage, cd.Lineage.Library()
|
lin, rt := cd.Lineage, cd.Lineage.Runtime()
|
||||||
_, name := filepath.Split(path)
|
_, name := filepath.Split(path)
|
||||||
if name != lin.Name() {
|
if name != lin.Name() {
|
||||||
return nil, fmt.Errorf("lineage name %q must match final element of path, got %q", lin.Name(), path)
|
return nil, fmt.Errorf("lineage name %q must match final element of path, got %q", lin.Name(), path)
|
||||||
@ -168,7 +168,7 @@ func (cd *CoremodelDeclaration) GenerateGoCoremodel(path string) (WriteDiffer, e
|
|||||||
return nil, fmt.Errorf("thema openapi generation failed: %w", err)
|
return nil, fmt.Errorf("thema openapi generation failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
str, err := yaml.Marshal(lib.Context().BuildFile(f))
|
str, err := yaml.Marshal(rt.Context().BuildFile(f))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("cue-yaml marshaling failed: %w", err)
|
return nil, fmt.Errorf("cue-yaml marshaling failed: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -63,7 +63,7 @@ func MapCUEImportToTS(path string) (string, error) {
|
|||||||
// Errors returned from [pfs.ParsePluginFS] are placed in the option map. Only
|
// Errors returned from [pfs.ParsePluginFS] are placed in the option map. Only
|
||||||
// filesystem traversal and read errors will result in a non-nil second return
|
// filesystem traversal and read errors will result in a non-nil second return
|
||||||
// value.
|
// value.
|
||||||
func ExtractPluginTrees(parent fs.FS, lib thema.Library) (map[string]PluginTreeOrErr, error) {
|
func ExtractPluginTrees(parent fs.FS, rt *thema.Runtime) (map[string]PluginTreeOrErr, error) {
|
||||||
ents, err := fs.ReadDir(parent, ".")
|
ents, err := fs.ReadDir(parent, ".")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error reading fs root directory: %w", err)
|
return nil, fmt.Errorf("error reading fs root directory: %w", err)
|
||||||
@ -78,7 +78,7 @@ func ExtractPluginTrees(parent fs.FS, lib thema.Library) (map[string]PluginTreeO
|
|||||||
}
|
}
|
||||||
|
|
||||||
var either PluginTreeOrErr
|
var either PluginTreeOrErr
|
||||||
if ptree, err := pfs.ParsePluginFS(sub, lib); err == nil {
|
if ptree, err := pfs.ParsePluginFS(sub, rt); err == nil {
|
||||||
either.Tree = (*PluginTree)(ptree)
|
either.Tree = (*PluginTree)(ptree)
|
||||||
} else {
|
} else {
|
||||||
either.Err = err
|
either.Err = err
|
||||||
@ -235,7 +235,7 @@ func genGoTypes(plug pfs.PluginInfo, path, subpath, prefix string) (WriteDiffer,
|
|||||||
wd := NewWriteDiffer()
|
wd := NewWriteDiffer()
|
||||||
for slotname, lin := range plug.SlotImplementations() {
|
for slotname, lin := range plug.SlotImplementations() {
|
||||||
lowslot := strings.ToLower(slotname)
|
lowslot := strings.ToLower(slotname)
|
||||||
lib := lin.Library()
|
rt := lin.Runtime()
|
||||||
sch := thema.SchemaP(lin, thema.LatestVersion(lin))
|
sch := thema.SchemaP(lin, thema.LatestVersion(lin))
|
||||||
|
|
||||||
// FIXME gotta hack this out of thema in order to deal with our custom imports :scream:
|
// FIXME gotta hack this out of thema in order to deal with our custom imports :scream:
|
||||||
@ -244,7 +244,7 @@ func genGoTypes(plug pfs.PluginInfo, path, subpath, prefix string) (WriteDiffer,
|
|||||||
return nil, fmt.Errorf("thema openapi generation failed: %w", err)
|
return nil, fmt.Errorf("thema openapi generation failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
str, err := yaml.Marshal(lib.Context().BuildFile(f))
|
str, err := yaml.Marshal(rt.Context().BuildFile(f))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("cue-yaml marshaling failed: %w", err)
|
return nil, fmt.Errorf("cue-yaml marshaling failed: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -18,8 +18,8 @@ var currentVersion = thema.SV({{ .LatestSeqv }}, {{ .LatestSchv }})
|
|||||||
{{- if .IsComposed }}//
|
{{- if .IsComposed }}//
|
||||||
// This is the base variant of the schema. It does not include any composed
|
// This is the base variant of the schema. It does not include any composed
|
||||||
// plugin schemas.{{ end }}
|
// plugin schemas.{{ end }}
|
||||||
func Lineage(lib thema.Library, opts ...thema.BindOption) (thema.Lineage, error) {
|
func Lineage(rt *thema.Runtime, opts ...thema.BindOption) (thema.Lineage, error) {
|
||||||
return cuectx.LoadGrafanaInstancesWithThema(filepath.Join("pkg", "coremodel", "{{ .Name }}"), cueFS, lib, opts...)
|
return cuectx.LoadGrafanaInstancesWithThema(filepath.Join("pkg", "coremodel", "{{ .Name }}"), cueFS, rt, opts...)
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ thema.LineageFactory = Lineage
|
var _ thema.LineageFactory = Lineage
|
||||||
@ -52,8 +52,8 @@ func (c *Coremodel) GoType() interface{} {
|
|||||||
// Note that this function does not cache, and initially loading a Thema lineage
|
// Note that this function does not cache, and initially loading a Thema lineage
|
||||||
// can be expensive. As such, the Grafana backend should prefer to access this
|
// can be expensive. As such, the Grafana backend should prefer to access this
|
||||||
// coremodel through a registry (pkg/framework/coremodel/registry), which does cache.
|
// coremodel through a registry (pkg/framework/coremodel/registry), which does cache.
|
||||||
func New(lib thema.Library) (*Coremodel, error) {
|
func New(rt *thema.Runtime) (*Coremodel, error) {
|
||||||
lin, err := Lineage(lib)
|
lin, err := Lineage(rt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -42,12 +42,12 @@ func (b *Base) {{ .TitleName }}() *{{ .Name }}.Coremodel {
|
|||||||
}
|
}
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
func doProvideBase(lib thema.Library) *Base {
|
func doProvideBase(rt *thema.Runtime) *Base {
|
||||||
var err error
|
var err error
|
||||||
reg := &Base{}
|
reg := &Base{}
|
||||||
|
|
||||||
{{range .Coremodels }}
|
{{range .Coremodels }}
|
||||||
reg.{{ .Name }}, err = {{ .Name }}.New(lib)
|
reg.{{ .Name }}, err = {{ .Name }}.New(rt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Sprintf("error while initializing {{ .Name }} coremodel: %s", err))
|
panic(fmt.Sprintf("error while initializing {{ .Name }} coremodel: %s", err))
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,6 @@ var currentVersion{{ .SlotName }} = thema.SV({{ .LatestSeqv }}, {{ .LatestSchv }
|
|||||||
|
|
||||||
// {{ .SlotName }}Lineage returns the Thema lineage for the {{ .PluginID }} {{ .PluginType }} plugin's
|
// {{ .SlotName }}Lineage returns the Thema lineage for the {{ .PluginID }} {{ .PluginType }} plugin's
|
||||||
// {{ .SlotName }} ["github.com/grafana/grafana/pkg/framework/coremodel".Slot] implementation.
|
// {{ .SlotName }} ["github.com/grafana/grafana/pkg/framework/coremodel".Slot] implementation.
|
||||||
func {{ .SlotName }}Lineage(lib thema.Library, opts ...thema.BindOption) (thema.Lineage, error) {
|
func {{ .SlotName }}Lineage(rt *thema.Runtime, opts ...thema.BindOption) (thema.Lineage, error) {
|
||||||
return cuectx.LoadGrafanaInstancesWithThema(filepath.Join("public", "app", "{{ .Name }}"), cueFS, lib, opts...)
|
return cuectx.LoadGrafanaInstancesWithThema(filepath.Join("public", "app", "{{ .Name }}"), cueFS, rt, opts...)
|
||||||
}
|
}
|
||||||
|
@ -19,14 +19,14 @@ var ptree *pfs.Tree
|
|||||||
var plugFS embed.FS
|
var plugFS embed.FS
|
||||||
|
|
||||||
// PluginTree returns the plugin tree representing the statically analyzable contents of the {{ .PluginID }} plugin.
|
// PluginTree returns the plugin tree representing the statically analyzable contents of the {{ .PluginID }} plugin.
|
||||||
func PluginTree(lib *thema.Library) *pfs.Tree {
|
func PluginTree(rt *thema.Runtime) *pfs.Tree {
|
||||||
var err error
|
var err error
|
||||||
if lib == nil {
|
if rt == nil || rt == cuectx.GrafanaThemaRuntime() {
|
||||||
parseOnce.Do(func() {
|
parseOnce.Do(func() {
|
||||||
ptree, err = pfs.ParsePluginFS(plugFS, cuectx.ProvideThemaLibrary())
|
ptree, err = pfs.ParsePluginFS(plugFS, cuectx.GrafanaThemaRuntime())
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
ptree, err = pfs.ParsePluginFS(plugFS, cuectx.ProvideThemaLibrary())
|
ptree, err = pfs.ParsePluginFS(plugFS, rt)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -40,8 +40,8 @@ func PluginTree(lib *thema.Library) *pfs.Tree {
|
|||||||
{{ $pluginfo := . }}{{ range $slot := .SlotImpls }}
|
{{ $pluginfo := . }}{{ range $slot := .SlotImpls }}
|
||||||
// {{ .SlotName }}Lineage returns the Thema lineage for the {{ $pluginfo.PluginID }} {{ $pluginfo.PluginType }} plugin's
|
// {{ .SlotName }}Lineage returns the Thema lineage for the {{ $pluginfo.PluginID }} {{ $pluginfo.PluginType }} plugin's
|
||||||
// {{ .SlotName }} ["github.com/grafana/grafana/pkg/framework/coremodel".Slot] implementation.
|
// {{ .SlotName }} ["github.com/grafana/grafana/pkg/framework/coremodel".Slot] implementation.
|
||||||
func {{ .SlotName }}Lineage(lib *thema.Library, opts ...thema.BindOption) (thema.Lineage, error) {
|
func {{ .SlotName }}Lineage(rt *thema.Runtime, opts ...thema.BindOption) (thema.Lineage, error) {
|
||||||
t := PluginTree(lib)
|
t := PluginTree(rt)
|
||||||
lin, has := t.RootPlugin().SlotImplementations()["{{ .SlotName }}"]
|
lin, has := t.RootPlugin().SlotImplementations()["{{ .SlotName }}"]
|
||||||
if !has {
|
if !has {
|
||||||
panic("unreachable: lineage for {{ .SlotName }} does not exist, but code is only generated for existing lineages")
|
panic("unreachable: lineage for {{ .SlotName }} does not exist, but code is only generated for existing lineages")
|
||||||
|
@ -10,22 +10,22 @@ import (
|
|||||||
"github.com/grafana/thema"
|
"github.com/grafana/thema"
|
||||||
)
|
)
|
||||||
|
|
||||||
func makeTreeOrPanic(path string, pkgname string, lib thema.Library) *pfs.Tree {
|
func makeTreeOrPanic(path string, pkgname string, rt *thema.Runtime) *pfs.Tree {
|
||||||
sub, err := fs.Sub(grafana.CueSchemaFS, path)
|
sub, err := fs.Sub(grafana.CueSchemaFS, path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic("could not create fs sub to " + path)
|
panic("could not create fs sub to " + path)
|
||||||
}
|
}
|
||||||
tree, err := pfs.ParsePluginFS(sub, lib)
|
tree, err := pfs.ParsePluginFS(sub, rt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Sprintf("error parsing plugin metadata for %s: %s", pkgname, err))
|
panic(fmt.Sprintf("error parsing plugin metadata for %s: %s", pkgname, err))
|
||||||
}
|
}
|
||||||
return tree
|
return tree
|
||||||
}
|
}
|
||||||
|
|
||||||
func coreTreeList(lib thema.Library) pfs.TreeList{
|
func coreTreeList(rt *thema.Runtime) pfs.TreeList{
|
||||||
return pfs.TreeList{
|
return pfs.TreeList{
|
||||||
{{- range .Plugins }}
|
{{- range .Plugins }}
|
||||||
makeTreeOrPanic("{{ .Path }}", "{{ .PkgName }}", lib),
|
makeTreeOrPanic("{{ .Path }}", "{{ .PkgName }}", rt),
|
||||||
{{- end }}
|
{{- end }}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,8 +8,8 @@ import (
|
|||||||
{{ if .NoAlias }}{{ .PkgName }} {{end}}"{{ .Path }}"{{ end }}
|
{{ if .NoAlias }}{{ .PkgName }} {{end}}"{{ .Path }}"{{ end }}
|
||||||
)
|
)
|
||||||
|
|
||||||
func coreTreeLoaders() []func(*thema.Library) *pfs.Tree{
|
func coreTreeLoaders() []func(*thema.Runtime) *pfs.Tree{
|
||||||
return []func(*thema.Library) *pfs.Tree{
|
return []func(*thema.Runtime) *pfs.Tree{
|
||||||
{{- range .Plugins }}
|
{{- range .Plugins }}
|
||||||
{{ .PkgName }}.PluginTree,{{ end }}
|
{{ .PkgName }}.PluginTree,{{ end }}
|
||||||
}
|
}
|
||||||
|
@ -1018,8 +1018,8 @@ var currentVersion = thema.SV(0, 0)
|
|||||||
// The lineage is the canonical specification of the current dashboard schema,
|
// The lineage is the canonical specification of the current dashboard schema,
|
||||||
// all prior schema versions, and the mappings that allow migration between
|
// all prior schema versions, and the mappings that allow migration between
|
||||||
// schema versions.
|
// schema versions.
|
||||||
func Lineage(lib thema.Library, opts ...thema.BindOption) (thema.Lineage, error) {
|
func Lineage(rt *thema.Runtime, opts ...thema.BindOption) (thema.Lineage, error) {
|
||||||
return cuectx.LoadGrafanaInstancesWithThema(filepath.Join("pkg", "coremodel", "dashboard"), cueFS, lib, opts...)
|
return cuectx.LoadGrafanaInstancesWithThema(filepath.Join("pkg", "coremodel", "dashboard"), cueFS, rt, opts...)
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ thema.LineageFactory = Lineage
|
var _ thema.LineageFactory = Lineage
|
||||||
@ -1052,8 +1052,8 @@ func (c *Coremodel) GoType() interface{} {
|
|||||||
// Note that this function does not cache, and initially loading a Thema lineage
|
// Note that this function does not cache, and initially loading a Thema lineage
|
||||||
// can be expensive. As such, the Grafana backend should prefer to access this
|
// can be expensive. As such, the Grafana backend should prefer to access this
|
||||||
// coremodel through a registry (pkg/framework/coremodel/registry), which does cache.
|
// coremodel through a registry (pkg/framework/coremodel/registry), which does cache.
|
||||||
func New(lib thema.Library) (*Coremodel, error) {
|
func New(rt *thema.Runtime) (*Coremodel, error) {
|
||||||
lin, err := Lineage(lib)
|
lin, err := Lineage(rt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ func TestDevenvDashboardValidity(t *testing.T) {
|
|||||||
|
|
||||||
m, err := themaTestableDashboards(os.DirFS(path))
|
m, err := themaTestableDashboards(os.DirFS(path))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
cm, err := dashboard.New(cuectx.ProvideThemaLibrary())
|
cm, err := dashboard.New(cuectx.GrafanaThemaRuntime())
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
for path, b := range m {
|
for path, b := range m {
|
||||||
|
@ -90,8 +90,8 @@ var currentVersion = thema.SV(0, 0)
|
|||||||
// The lineage is the canonical specification of the current playlist schema,
|
// The lineage is the canonical specification of the current playlist schema,
|
||||||
// all prior schema versions, and the mappings that allow migration between
|
// all prior schema versions, and the mappings that allow migration between
|
||||||
// schema versions.
|
// schema versions.
|
||||||
func Lineage(lib thema.Library, opts ...thema.BindOption) (thema.Lineage, error) {
|
func Lineage(rt *thema.Runtime, opts ...thema.BindOption) (thema.Lineage, error) {
|
||||||
return cuectx.LoadGrafanaInstancesWithThema(filepath.Join("pkg", "coremodel", "playlist"), cueFS, lib, opts...)
|
return cuectx.LoadGrafanaInstancesWithThema(filepath.Join("pkg", "coremodel", "playlist"), cueFS, rt, opts...)
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ thema.LineageFactory = Lineage
|
var _ thema.LineageFactory = Lineage
|
||||||
@ -124,8 +124,8 @@ func (c *Coremodel) GoType() interface{} {
|
|||||||
// Note that this function does not cache, and initially loading a Thema lineage
|
// Note that this function does not cache, and initially loading a Thema lineage
|
||||||
// can be expensive. As such, the Grafana backend should prefer to access this
|
// can be expensive. As such, the Grafana backend should prefer to access this
|
||||||
// coremodel through a registry (pkg/framework/coremodel/registry), which does cache.
|
// coremodel through a registry (pkg/framework/coremodel/registry), which does cache.
|
||||||
func New(lib thema.Library) (*Coremodel, error) {
|
func New(rt *thema.Runtime) (*Coremodel, error) {
|
||||||
lin, err := Lineage(lib)
|
lin, err := Lineage(rt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -560,8 +560,8 @@ var currentVersion = thema.SV(0, 0)
|
|||||||
// The lineage is the canonical specification of the current pluginmeta schema,
|
// The lineage is the canonical specification of the current pluginmeta schema,
|
||||||
// all prior schema versions, and the mappings that allow migration between
|
// all prior schema versions, and the mappings that allow migration between
|
||||||
// schema versions.
|
// schema versions.
|
||||||
func Lineage(lib thema.Library, opts ...thema.BindOption) (thema.Lineage, error) {
|
func Lineage(rt *thema.Runtime, opts ...thema.BindOption) (thema.Lineage, error) {
|
||||||
return cuectx.LoadGrafanaInstancesWithThema(filepath.Join("pkg", "coremodel", "pluginmeta"), cueFS, lib, opts...)
|
return cuectx.LoadGrafanaInstancesWithThema(filepath.Join("pkg", "coremodel", "pluginmeta"), cueFS, rt, opts...)
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ thema.LineageFactory = Lineage
|
var _ thema.LineageFactory = Lineage
|
||||||
@ -594,8 +594,8 @@ func (c *Coremodel) GoType() interface{} {
|
|||||||
// Note that this function does not cache, and initially loading a Thema lineage
|
// Note that this function does not cache, and initially loading a Thema lineage
|
||||||
// can be expensive. As such, the Grafana backend should prefer to access this
|
// can be expensive. As such, the Grafana backend should prefer to access this
|
||||||
// coremodel through a registry (pkg/framework/coremodel/registry), which does cache.
|
// coremodel through a registry (pkg/framework/coremodel/registry), which does cache.
|
||||||
func New(lib thema.Library) (*Coremodel, error) {
|
func New(rt *thema.Runtime) (*Coremodel, error) {
|
||||||
lin, err := Lineage(lib)
|
lin, err := Lineage(rt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// Package cuectx provides a single, central CUE context (runtime) and Thema
|
// Package cuectx provides a single, central ["cuelang.org/go/cue".Context] and
|
||||||
// library that can be used uniformly across Grafana, and related helper
|
// ["github.com/grafana/thema".Runtime] that can be used uniformly across
|
||||||
// functions for loading Thema lineages.
|
// Grafana, and related helper functions for loading Thema lineages.
|
||||||
|
|
||||||
package cuectx
|
package cuectx
|
||||||
|
|
||||||
@ -12,21 +12,27 @@ import (
|
|||||||
"cuelang.org/go/cue"
|
"cuelang.org/go/cue"
|
||||||
"cuelang.org/go/cue/cuecontext"
|
"cuelang.org/go/cue/cuecontext"
|
||||||
"github.com/grafana/thema"
|
"github.com/grafana/thema"
|
||||||
"github.com/grafana/thema/kernel"
|
|
||||||
"github.com/grafana/thema/load"
|
"github.com/grafana/thema/load"
|
||||||
|
"github.com/grafana/thema/vmux"
|
||||||
)
|
)
|
||||||
|
|
||||||
var ctx = cuecontext.New()
|
var ctx = cuecontext.New()
|
||||||
var lib = thema.NewLibrary(ctx)
|
var rt = thema.NewRuntime(ctx)
|
||||||
|
|
||||||
// ProvideCUEContext is a wire service provider of a central cue.Context.
|
// GrafanaCUEContext returns Grafana's singleton instance of [cue.Context].
|
||||||
func ProvideCUEContext() *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 {
|
||||||
return ctx
|
return ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProvideThemaLibrary is a wire service provider of a central thema.Library.
|
// GrafanaThemaRuntime returns Grafana's singleton instance of [thema.Runtime].
|
||||||
func ProvideThemaLibrary() thema.Library {
|
//
|
||||||
return lib
|
// 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 {
|
||||||
|
return rt
|
||||||
}
|
}
|
||||||
|
|
||||||
// JSONtoCUE attempts to decode the given []byte into a cue.Value, relying on
|
// JSONtoCUE attempts to decode the given []byte into a cue.Value, relying on
|
||||||
@ -37,10 +43,10 @@ func ProvideThemaLibrary() thema.Library {
|
|||||||
// returned cue.Value.
|
// returned cue.Value.
|
||||||
//
|
//
|
||||||
// This is a convenience function for one-off JSON decoding. It's wasteful to
|
// This is a convenience function for one-off JSON decoding. It's wasteful to
|
||||||
// call it repeatedly. Most use cases use cases should probably prefer making
|
// call it repeatedly. Most use cases should probably prefer making
|
||||||
// their own Thema/CUE decoders.
|
// their own Thema/CUE decoders.
|
||||||
func JSONtoCUE(path string, b []byte) (cue.Value, error) {
|
func JSONtoCUE(path string, b []byte) (cue.Value, error) {
|
||||||
return kernel.NewJSONDecoder(path)(ctx, b)
|
return vmux.NewJSONEndec(path).Decode(ctx, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoadGrafanaInstancesWithThema loads CUE files containing a lineage
|
// LoadGrafanaInstancesWithThema loads CUE files containing a lineage
|
||||||
@ -54,7 +60,7 @@ func JSONtoCUE(path string, b []byte) (cue.Value, error) {
|
|||||||
// More details on underlying behavior can be found in the docs for github.com/grafana/thema/load.InstancesWithThema.
|
// More details on underlying behavior can be found in the docs for github.com/grafana/thema/load.InstancesWithThema.
|
||||||
//
|
//
|
||||||
// TODO this approach is complicated and confusing, refactor to something understandable
|
// TODO this approach is complicated and confusing, refactor to something understandable
|
||||||
func LoadGrafanaInstancesWithThema(path string, cueFS fs.FS, lib thema.Library, opts ...thema.BindOption) (thema.Lineage, error) {
|
func LoadGrafanaInstancesWithThema(path string, cueFS fs.FS, rt *thema.Runtime, opts ...thema.BindOption) (thema.Lineage, error) {
|
||||||
prefix := filepath.FromSlash(path)
|
prefix := filepath.FromSlash(path)
|
||||||
fs, err := prefixWithGrafanaCUE(prefix, cueFS)
|
fs, err := prefixWithGrafanaCUE(prefix, cueFS)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -68,9 +74,9 @@ func LoadGrafanaInstancesWithThema(path string, cueFS fs.FS, lib thema.Library,
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
val := lib.Context().BuildInstance(inst)
|
val := rt.Context().BuildInstance(inst)
|
||||||
|
|
||||||
lin, err := thema.BindLineage(val, lib, opts...)
|
lin, err := thema.BindLineage(val, rt, opts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -20,11 +20,10 @@ import (
|
|||||||
"github.com/grafana/cuetsy/ts"
|
"github.com/grafana/cuetsy/ts"
|
||||||
"github.com/grafana/cuetsy/ts/ast"
|
"github.com/grafana/cuetsy/ts/ast"
|
||||||
gcgen "github.com/grafana/grafana/pkg/codegen"
|
gcgen "github.com/grafana/grafana/pkg/codegen"
|
||||||
|
"github.com/grafana/grafana/pkg/cuectx"
|
||||||
"github.com/grafana/thema"
|
"github.com/grafana/thema"
|
||||||
)
|
)
|
||||||
|
|
||||||
var lib = thema.NewLibrary(cuecontext.New())
|
|
||||||
|
|
||||||
const sep = string(filepath.Separator)
|
const sep = string(filepath.Separator)
|
||||||
|
|
||||||
var tsroot, cmroot, groot string
|
var tsroot, cmroot, groot string
|
||||||
@ -46,6 +45,7 @@ func init() {
|
|||||||
// Generate Go and Typescript implementations for all coremodels, and populate the
|
// Generate Go and Typescript implementations for all coremodels, and populate the
|
||||||
// coremodel static registry.
|
// coremodel static registry.
|
||||||
func main() {
|
func main() {
|
||||||
|
rt := cuectx.GrafanaThemaRuntime()
|
||||||
if len(os.Args) > 1 {
|
if len(os.Args) > 1 {
|
||||||
fmt.Fprintf(os.Stderr, "coremodel code generator does not currently accept any arguments\n, got %q", os.Args)
|
fmt.Fprintf(os.Stderr, "coremodel code generator does not currently accept any arguments\n, got %q", os.Args)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
@ -60,7 +60,7 @@ func main() {
|
|||||||
var lins []*gcgen.CoremodelDeclaration
|
var lins []*gcgen.CoremodelDeclaration
|
||||||
for _, item := range items {
|
for _, item := range items {
|
||||||
if item.IsDir() {
|
if item.IsDir() {
|
||||||
lin, err := gcgen.ExtractLineage(filepath.Join(cmroot, item.Name(), "coremodel.cue"), lib)
|
lin, err := gcgen.ExtractLineage(filepath.Join(cmroot, item.Name(), "coremodel.cue"), rt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "could not process coremodel dir %s: %s\n", filepath.Join(cmroot, item.Name()), err)
|
fmt.Fprintf(os.Stderr, "could not process coremodel dir %s: %s\n", filepath.Join(cmroot, item.Name()), err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
|
@ -9,7 +9,6 @@ import (
|
|||||||
|
|
||||||
"cuelang.org/go/cue"
|
"cuelang.org/go/cue"
|
||||||
"cuelang.org/go/cue/load"
|
"cuelang.org/go/cue/load"
|
||||||
"github.com/grafana/thema/kernel"
|
|
||||||
tload "github.com/grafana/thema/load"
|
tload "github.com/grafana/thema/load"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/cuectx"
|
"github.com/grafana/grafana/pkg/cuectx"
|
||||||
@ -24,7 +23,7 @@ var defaultFramework cue.Value
|
|||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
var err error
|
var err error
|
||||||
defaultFramework, err = doLoadFrameworkCUE(cuectx.ProvideCUEContext())
|
defaultFramework, err = doLoadFrameworkCUE(cuectx.GrafanaCUEContext())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@ -106,81 +105,3 @@ func CUEFrameworkWithContext(ctx *cue.Context) cue.Value {
|
|||||||
v, _ := doLoadFrameworkCUE(ctx) // nolint:errcheck
|
v, _ := doLoadFrameworkCUE(ctx) // nolint:errcheck
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mux takes a coremodel and returns a Thema version muxer that, given a byte
|
|
||||||
// slice containing any version of schema for that coremodel, will translate it
|
|
||||||
// to the Interface.CurrentSchema() version, and optionally decode it onto the
|
|
||||||
// Interface.GoType().
|
|
||||||
//
|
|
||||||
// By default, JSON decoding will be used, and the filename given to any input
|
|
||||||
// bytes (shown in errors, which may be user-facing) will be
|
|
||||||
// "<name>.<encoding>", e.g. dashboard.json.
|
|
||||||
func Mux(cm Interface, opts ...MuxOption) kernel.InputKernel {
|
|
||||||
c := &muxConfig{}
|
|
||||||
for _, opt := range opts {
|
|
||||||
opt(c)
|
|
||||||
}
|
|
||||||
|
|
||||||
cfg := kernel.InputKernelConfig{
|
|
||||||
Typ: cm.GoType(),
|
|
||||||
Lineage: cm.Lineage(),
|
|
||||||
To: cm.CurrentSchema().Version(),
|
|
||||||
}
|
|
||||||
|
|
||||||
switch c.decodetyp {
|
|
||||||
case "", "json": // json by default
|
|
||||||
if c.filename == "" {
|
|
||||||
c.filename = fmt.Sprintf("%s.json", cm.Lineage().Name())
|
|
||||||
}
|
|
||||||
cfg.Loader = kernel.NewJSONDecoder(c.filename)
|
|
||||||
case "yaml":
|
|
||||||
if c.filename == "" {
|
|
||||||
c.filename = fmt.Sprintf("%s.yaml", cm.Lineage().Name())
|
|
||||||
}
|
|
||||||
cfg.Loader = kernel.NewYAMLDecoder(c.filename)
|
|
||||||
default:
|
|
||||||
panic("")
|
|
||||||
}
|
|
||||||
|
|
||||||
mux, err := kernel.NewInputKernel(cfg)
|
|
||||||
if err != nil {
|
|
||||||
// Barring a fundamental bug in Thema's schema->Go type assignability checker or
|
|
||||||
// a direct attempt by a Grafana dev to get around the invariants of coremodel codegen,
|
|
||||||
// this should be unreachable. (And even the latter case should be caught elsewhere
|
|
||||||
// by tests).
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return mux
|
|
||||||
}
|
|
||||||
|
|
||||||
// A MuxOption defines options that may be specified only at initial
|
|
||||||
// construction of a Lineage via BindLineage.
|
|
||||||
type MuxOption muxOption
|
|
||||||
|
|
||||||
// Internal representation of MuxOption.
|
|
||||||
type muxOption func(c *muxConfig)
|
|
||||||
|
|
||||||
type muxConfig struct {
|
|
||||||
filename string
|
|
||||||
decodetyp string
|
|
||||||
}
|
|
||||||
|
|
||||||
// YAML indicates that the resulting Mux should look for YAML in input bytes,
|
|
||||||
// rather than the default JSON.
|
|
||||||
func YAML() MuxOption {
|
|
||||||
return func(c *muxConfig) {
|
|
||||||
c.decodetyp = "yaml"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Filename specifies the filename that is given to input bytes passing through
|
|
||||||
// the mux.
|
|
||||||
//
|
|
||||||
// The filename has no impact on mux behavior, but is used in user-facing error
|
|
||||||
// output, such as schema validation failures. Thus, it is recommended to pick a
|
|
||||||
// name that will make sense in the context a user is expected to see the error.
|
|
||||||
func Filename(name string) MuxOption {
|
|
||||||
return func(c *muxConfig) {
|
|
||||||
c.filename = name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -17,19 +17,20 @@ var CoremodelSet = wire.NewSet(
|
|||||||
// NewBase provides a registry of all coremodels, without any composition of
|
// NewBase provides a registry of all coremodels, without any composition of
|
||||||
// plugin-defined schemas.
|
// plugin-defined schemas.
|
||||||
//
|
//
|
||||||
// The returned registry will use the default Grafana thema.Library, defined in
|
// The returned registry will use Grafana's singleton [thema.Runtime],
|
||||||
// pkg/cuectx. If you need control over the thema.Library used by the coremodel
|
// returned from [cuectx.GrafanaThemaRuntime].
|
||||||
// lineages, use NewBaseWithLib instead.
|
|
||||||
func NewBase() *Base {
|
func NewBase() *Base {
|
||||||
return provideBase(nil)
|
return provideBase(nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewBaseWithLib is the same as NewBase, but allows control over the
|
// NewBaseWithRuntime is the same as NewBase, but allows control over the
|
||||||
// thema.Library used to initialize the underlying coremodels.
|
// [thema.Runtime] used to initialize the underlying coremodels.
|
||||||
//
|
//
|
||||||
// Prefer NewBase unless you absolutely need this control.
|
// Prefer NewBase unless you absolutely need this control.
|
||||||
func NewBaseWithLib(lib thema.Library) *Base {
|
//
|
||||||
return provideBase(&lib)
|
// TODO it's OK to export this if it's ever actually needed
|
||||||
|
func NewBaseWithRuntime(rt *thema.Runtime) *Base {
|
||||||
|
return provideBase(rt)
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -37,15 +38,15 @@ var (
|
|||||||
defaultBase *Base
|
defaultBase *Base
|
||||||
)
|
)
|
||||||
|
|
||||||
func provideBase(lib *thema.Library) *Base {
|
func provideBase(rt *thema.Runtime) *Base {
|
||||||
if lib == nil {
|
if rt == nil {
|
||||||
baseOnce.Do(func() {
|
baseOnce.Do(func() {
|
||||||
defaultBase = doProvideBase(cuectx.ProvideThemaLibrary())
|
defaultBase = doProvideBase(cuectx.GrafanaThemaRuntime())
|
||||||
})
|
})
|
||||||
return defaultBase
|
return defaultBase
|
||||||
}
|
}
|
||||||
|
|
||||||
return doProvideBase(*lib)
|
return doProvideBase(rt)
|
||||||
}
|
}
|
||||||
|
|
||||||
// All returns a slice of all registered coremodels.
|
// All returns a slice of all registered coremodels.
|
||||||
|
@ -57,23 +57,23 @@ func (b *Base) Pluginmeta() *pluginmeta.Coremodel {
|
|||||||
return b.pluginmeta
|
return b.pluginmeta
|
||||||
}
|
}
|
||||||
|
|
||||||
func doProvideBase(lib thema.Library) *Base {
|
func doProvideBase(rt *thema.Runtime) *Base {
|
||||||
var err error
|
var err error
|
||||||
reg := &Base{}
|
reg := &Base{}
|
||||||
|
|
||||||
reg.dashboard, err = dashboard.New(lib)
|
reg.dashboard, err = dashboard.New(rt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Sprintf("error while initializing dashboard coremodel: %s", err))
|
panic(fmt.Sprintf("error while initializing dashboard coremodel: %s", err))
|
||||||
}
|
}
|
||||||
reg.all = append(reg.all, reg.dashboard)
|
reg.all = append(reg.all, reg.dashboard)
|
||||||
|
|
||||||
reg.playlist, err = playlist.New(lib)
|
reg.playlist, err = playlist.New(rt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Sprintf("error while initializing playlist coremodel: %s", err))
|
panic(fmt.Sprintf("error while initializing playlist coremodel: %s", err))
|
||||||
}
|
}
|
||||||
reg.all = append(reg.all, reg.playlist)
|
reg.all = append(reg.all, reg.playlist)
|
||||||
|
|
||||||
reg.pluginmeta, err = pluginmeta.New(lib)
|
reg.pluginmeta, err = pluginmeta.New(rt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Sprintf("error while initializing pluginmeta coremodel: %s", err))
|
panic(fmt.Sprintf("error while initializing pluginmeta coremodel: %s", err))
|
||||||
}
|
}
|
||||||
|
@ -27,61 +27,61 @@ import (
|
|||||||
"github.com/grafana/thema"
|
"github.com/grafana/thema"
|
||||||
)
|
)
|
||||||
|
|
||||||
func makeTreeOrPanic(path string, pkgname string, lib thema.Library) *pfs.Tree {
|
func makeTreeOrPanic(path string, pkgname string, rt *thema.Runtime) *pfs.Tree {
|
||||||
sub, err := fs.Sub(grafana.CueSchemaFS, path)
|
sub, err := fs.Sub(grafana.CueSchemaFS, path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic("could not create fs sub to " + path)
|
panic("could not create fs sub to " + path)
|
||||||
}
|
}
|
||||||
tree, err := pfs.ParsePluginFS(sub, lib)
|
tree, err := pfs.ParsePluginFS(sub, rt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Sprintf("error parsing plugin metadata for %s: %s", pkgname, err))
|
panic(fmt.Sprintf("error parsing plugin metadata for %s: %s", pkgname, err))
|
||||||
}
|
}
|
||||||
return tree
|
return tree
|
||||||
}
|
}
|
||||||
|
|
||||||
func coreTreeList(lib thema.Library) pfs.TreeList {
|
func coreTreeList(rt *thema.Runtime) pfs.TreeList {
|
||||||
return pfs.TreeList{
|
return pfs.TreeList{
|
||||||
makeTreeOrPanic("public/app/plugins/datasource/alertmanager", "alertmanager", lib),
|
makeTreeOrPanic("public/app/plugins/datasource/alertmanager", "alertmanager", rt),
|
||||||
makeTreeOrPanic("public/app/plugins/datasource/cloud-monitoring", "stackdriver", lib),
|
makeTreeOrPanic("public/app/plugins/datasource/cloud-monitoring", "stackdriver", rt),
|
||||||
makeTreeOrPanic("public/app/plugins/datasource/cloudwatch", "cloudwatch", lib),
|
makeTreeOrPanic("public/app/plugins/datasource/cloudwatch", "cloudwatch", rt),
|
||||||
makeTreeOrPanic("public/app/plugins/datasource/dashboard", "dashboard", lib),
|
makeTreeOrPanic("public/app/plugins/datasource/dashboard", "dashboard", rt),
|
||||||
makeTreeOrPanic("public/app/plugins/datasource/elasticsearch", "elasticsearch", lib),
|
makeTreeOrPanic("public/app/plugins/datasource/elasticsearch", "elasticsearch", rt),
|
||||||
makeTreeOrPanic("public/app/plugins/datasource/grafana", "grafana", lib),
|
makeTreeOrPanic("public/app/plugins/datasource/grafana", "grafana", rt),
|
||||||
makeTreeOrPanic("public/app/plugins/datasource/grafana-azure-monitor-datasource", "grafana_azure_monitor_datasource", lib),
|
makeTreeOrPanic("public/app/plugins/datasource/grafana-azure-monitor-datasource", "grafana_azure_monitor_datasource", rt),
|
||||||
makeTreeOrPanic("public/app/plugins/datasource/graphite", "graphite", lib),
|
makeTreeOrPanic("public/app/plugins/datasource/graphite", "graphite", rt),
|
||||||
makeTreeOrPanic("public/app/plugins/datasource/jaeger", "jaeger", lib),
|
makeTreeOrPanic("public/app/plugins/datasource/jaeger", "jaeger", rt),
|
||||||
makeTreeOrPanic("public/app/plugins/datasource/loki", "loki", lib),
|
makeTreeOrPanic("public/app/plugins/datasource/loki", "loki", rt),
|
||||||
makeTreeOrPanic("public/app/plugins/datasource/mssql", "mssql", lib),
|
makeTreeOrPanic("public/app/plugins/datasource/mssql", "mssql", rt),
|
||||||
makeTreeOrPanic("public/app/plugins/datasource/mysql", "mysql", lib),
|
makeTreeOrPanic("public/app/plugins/datasource/mysql", "mysql", rt),
|
||||||
makeTreeOrPanic("public/app/plugins/datasource/postgres", "postgres", lib),
|
makeTreeOrPanic("public/app/plugins/datasource/postgres", "postgres", rt),
|
||||||
makeTreeOrPanic("public/app/plugins/datasource/prometheus", "prometheus", lib),
|
makeTreeOrPanic("public/app/plugins/datasource/prometheus", "prometheus", rt),
|
||||||
makeTreeOrPanic("public/app/plugins/datasource/tempo", "tempo", lib),
|
makeTreeOrPanic("public/app/plugins/datasource/tempo", "tempo", rt),
|
||||||
makeTreeOrPanic("public/app/plugins/datasource/testdata", "testdata", lib),
|
makeTreeOrPanic("public/app/plugins/datasource/testdata", "testdata", rt),
|
||||||
makeTreeOrPanic("public/app/plugins/datasource/zipkin", "zipkin", lib),
|
makeTreeOrPanic("public/app/plugins/datasource/zipkin", "zipkin", rt),
|
||||||
makeTreeOrPanic("public/app/plugins/panel/alertGroups", "alertGroups", lib),
|
makeTreeOrPanic("public/app/plugins/panel/alertGroups", "alertGroups", rt),
|
||||||
makeTreeOrPanic("public/app/plugins/panel/alertlist", "alertlist", lib),
|
makeTreeOrPanic("public/app/plugins/panel/alertlist", "alertlist", rt),
|
||||||
makeTreeOrPanic("public/app/plugins/panel/annolist", "annolist", lib),
|
makeTreeOrPanic("public/app/plugins/panel/annolist", "annolist", rt),
|
||||||
makeTreeOrPanic("public/app/plugins/panel/barchart", "barchart", lib),
|
makeTreeOrPanic("public/app/plugins/panel/barchart", "barchart", rt),
|
||||||
makeTreeOrPanic("public/app/plugins/panel/bargauge", "bargauge", lib),
|
makeTreeOrPanic("public/app/plugins/panel/bargauge", "bargauge", rt),
|
||||||
makeTreeOrPanic("public/app/plugins/panel/dashlist", "dashlist", lib),
|
makeTreeOrPanic("public/app/plugins/panel/dashlist", "dashlist", rt),
|
||||||
makeTreeOrPanic("public/app/plugins/panel/debug", "debug", lib),
|
makeTreeOrPanic("public/app/plugins/panel/debug", "debug", rt),
|
||||||
makeTreeOrPanic("public/app/plugins/panel/flamegraph", "flamegraph", lib),
|
makeTreeOrPanic("public/app/plugins/panel/flamegraph", "flamegraph", rt),
|
||||||
makeTreeOrPanic("public/app/plugins/panel/gauge", "gauge", lib),
|
makeTreeOrPanic("public/app/plugins/panel/gauge", "gauge", rt),
|
||||||
makeTreeOrPanic("public/app/plugins/panel/geomap", "geomap", lib),
|
makeTreeOrPanic("public/app/plugins/panel/geomap", "geomap", rt),
|
||||||
makeTreeOrPanic("public/app/plugins/panel/gettingstarted", "gettingstarted", lib),
|
makeTreeOrPanic("public/app/plugins/panel/gettingstarted", "gettingstarted", rt),
|
||||||
makeTreeOrPanic("public/app/plugins/panel/graph", "graph", lib),
|
makeTreeOrPanic("public/app/plugins/panel/graph", "graph", rt),
|
||||||
makeTreeOrPanic("public/app/plugins/panel/histogram", "histogram", lib),
|
makeTreeOrPanic("public/app/plugins/panel/histogram", "histogram", rt),
|
||||||
makeTreeOrPanic("public/app/plugins/panel/icon", "icon", lib),
|
makeTreeOrPanic("public/app/plugins/panel/icon", "icon", rt),
|
||||||
makeTreeOrPanic("public/app/plugins/panel/live", "live", lib),
|
makeTreeOrPanic("public/app/plugins/panel/live", "live", rt),
|
||||||
makeTreeOrPanic("public/app/plugins/panel/logs", "logs", lib),
|
makeTreeOrPanic("public/app/plugins/panel/logs", "logs", rt),
|
||||||
makeTreeOrPanic("public/app/plugins/panel/news", "news", lib),
|
makeTreeOrPanic("public/app/plugins/panel/news", "news", rt),
|
||||||
makeTreeOrPanic("public/app/plugins/panel/nodeGraph", "nodeGraph", lib),
|
makeTreeOrPanic("public/app/plugins/panel/nodeGraph", "nodeGraph", rt),
|
||||||
makeTreeOrPanic("public/app/plugins/panel/piechart", "piechart", lib),
|
makeTreeOrPanic("public/app/plugins/panel/piechart", "piechart", rt),
|
||||||
makeTreeOrPanic("public/app/plugins/panel/stat", "stat", lib),
|
makeTreeOrPanic("public/app/plugins/panel/stat", "stat", rt),
|
||||||
makeTreeOrPanic("public/app/plugins/panel/table-old", "table_old", lib),
|
makeTreeOrPanic("public/app/plugins/panel/table-old", "table_old", rt),
|
||||||
makeTreeOrPanic("public/app/plugins/panel/text", "text", lib),
|
makeTreeOrPanic("public/app/plugins/panel/text", "text", rt),
|
||||||
makeTreeOrPanic("public/app/plugins/panel/traces", "traces", lib),
|
makeTreeOrPanic("public/app/plugins/panel/traces", "traces", rt),
|
||||||
makeTreeOrPanic("public/app/plugins/panel/welcome", "welcome", lib),
|
makeTreeOrPanic("public/app/plugins/panel/welcome", "welcome", rt),
|
||||||
makeTreeOrPanic("public/app/plugins/panel/xychart", "xychart", lib),
|
makeTreeOrPanic("public/app/plugins/panel/xychart", "xychart", rt),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,16 +15,16 @@ var coreOnce sync.Once
|
|||||||
// in the current version of Grafana.
|
// in the current version of Grafana.
|
||||||
//
|
//
|
||||||
// Go code within the grafana codebase should only ever call this with nil.
|
// Go code within the grafana codebase should only ever call this with nil.
|
||||||
func New(lib *thema.Library) pfs.TreeList {
|
func New(rt *thema.Runtime) pfs.TreeList {
|
||||||
var tl pfs.TreeList
|
var tl pfs.TreeList
|
||||||
if lib == nil {
|
if rt == nil {
|
||||||
coreOnce.Do(func() {
|
coreOnce.Do(func() {
|
||||||
coreTrees = coreTreeList(cuectx.ProvideThemaLibrary())
|
coreTrees = coreTreeList(cuectx.GrafanaThemaRuntime())
|
||||||
})
|
})
|
||||||
tl = make(pfs.TreeList, len(coreTrees))
|
tl = make(pfs.TreeList, len(coreTrees))
|
||||||
copy(tl, coreTrees)
|
copy(tl, coreTrees)
|
||||||
} else {
|
} else {
|
||||||
return coreTreeList(*lib)
|
return coreTreeList(rt)
|
||||||
}
|
}
|
||||||
return tl
|
return tl
|
||||||
}
|
}
|
||||||
|
@ -13,11 +13,11 @@ import (
|
|||||||
"cuelang.org/go/cue/parser"
|
"cuelang.org/go/cue/parser"
|
||||||
"github.com/grafana/grafana"
|
"github.com/grafana/grafana"
|
||||||
"github.com/grafana/grafana/pkg/coremodel/pluginmeta"
|
"github.com/grafana/grafana/pkg/coremodel/pluginmeta"
|
||||||
|
"github.com/grafana/grafana/pkg/cuectx"
|
||||||
"github.com/grafana/grafana/pkg/framework/coremodel"
|
"github.com/grafana/grafana/pkg/framework/coremodel"
|
||||||
"github.com/grafana/grafana/pkg/framework/coremodel/registry"
|
|
||||||
"github.com/grafana/thema"
|
"github.com/grafana/thema"
|
||||||
"github.com/grafana/thema/kernel"
|
|
||||||
"github.com/grafana/thema/load"
|
"github.com/grafana/thema/load"
|
||||||
|
"github.com/grafana/thema/vmux"
|
||||||
"github.com/yalue/merged_fs"
|
"github.com/yalue/merged_fs"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -51,11 +51,9 @@ type slotandname struct {
|
|||||||
|
|
||||||
var allslots []slotandname
|
var allslots []slotandname
|
||||||
|
|
||||||
var plugmux kernel.InputKernel
|
|
||||||
|
|
||||||
// TODO re-enable after go1.18
|
// TODO re-enable after go1.18
|
||||||
// var tsch thema.TypedSchema[pluginmeta.Model]
|
var tsch thema.TypedSchema[*pluginmeta.Model]
|
||||||
// var plugmux vmux.ValueMux[pluginmeta.Model]
|
var plugmux vmux.ValueMux[*pluginmeta.Model]
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
var all []string
|
var all []string
|
||||||
@ -78,13 +76,6 @@ func init() {
|
|||||||
|
|
||||||
var muxonce sync.Once
|
var muxonce sync.Once
|
||||||
|
|
||||||
func loadMux() kernel.InputKernel {
|
|
||||||
muxonce.Do(func() {
|
|
||||||
plugmux = coremodel.Mux(registry.NewBase().Pluginmeta(), coremodel.Filename("plugin.json"))
|
|
||||||
})
|
|
||||||
return plugmux
|
|
||||||
}
|
|
||||||
|
|
||||||
// This used to be in init(), but that creates a risk for codegen.
|
// This used to be in init(), but that creates a risk for codegen.
|
||||||
//
|
//
|
||||||
// thema.BindType ensures that Go type and Thema schema are aligned. If we were
|
// thema.BindType ensures that Go type and Thema schema are aligned. If we were
|
||||||
@ -102,19 +93,22 @@ func loadMux() kernel.InputKernel {
|
|||||||
// called as needed to get our muxer, and internally relies on a sync.Once to avoid
|
// called as needed to get our muxer, and internally relies on a sync.Once to avoid
|
||||||
// repeated processing of thema.BindType.
|
// repeated processing of thema.BindType.
|
||||||
// TODO mux loading is easily generalizable in pkg/f/coremodel, shouldn't need one-off
|
// TODO mux loading is easily generalizable in pkg/f/coremodel, shouldn't need one-off
|
||||||
// TODO switch to this generic signature after go1.18
|
func loadMux() (thema.TypedSchema[*pluginmeta.Model], vmux.ValueMux[*pluginmeta.Model]) {
|
||||||
// func loadMux() (thema.TypedSchema[pluginmeta.Model], vmux.ValueMux[pluginmeta.Model]) {
|
muxonce.Do(func() {
|
||||||
// muxonce.Do(func() {
|
var err error
|
||||||
// var err error
|
t := new(pluginmeta.Model)
|
||||||
// var t pluginmeta.Model
|
pm, err := pluginmeta.New(cuectx.GrafanaThemaRuntime())
|
||||||
// tsch, err = thema.BindType[pluginmeta.Model](pm.CurrentSchema(), t)
|
if err != nil {
|
||||||
// if err != nil {
|
panic(err)
|
||||||
// panic(err)
|
}
|
||||||
// }
|
tsch, err = thema.BindType[*pluginmeta.Model](pm.CurrentSchema(), t)
|
||||||
// plugmux = vmux.NewValueMux(tsch, vmux.NewJSONEndec("plugin.json"))
|
if err != nil {
|
||||||
// })
|
panic(err)
|
||||||
// return tsch, plugmux
|
}
|
||||||
// }
|
plugmux = vmux.NewValueMux(tsch, vmux.NewJSONEndec("plugin.json"))
|
||||||
|
})
|
||||||
|
return tsch, plugmux
|
||||||
|
}
|
||||||
|
|
||||||
// Tree represents the contents of a plugin filesystem tree.
|
// Tree represents the contents of a plugin filesystem tree.
|
||||||
type Tree struct {
|
type Tree struct {
|
||||||
@ -190,13 +184,12 @@ func (pi PluginInfo) Meta() pluginmeta.Model {
|
|||||||
// It does not descend into subdirectories to search for additional plugin.json
|
// It does not descend into subdirectories to search for additional plugin.json
|
||||||
// files.
|
// files.
|
||||||
// TODO no descent is ok for core plugins, but won't cut it in general
|
// TODO no descent is ok for core plugins, but won't cut it in general
|
||||||
func ParsePluginFS(f fs.FS, lib thema.Library) (*Tree, error) {
|
func ParsePluginFS(f fs.FS, rt *thema.Runtime) (*Tree, error) {
|
||||||
if f == nil {
|
if f == nil {
|
||||||
return nil, ErrEmptyFS
|
return nil, ErrEmptyFS
|
||||||
}
|
}
|
||||||
// _, mux := loadMux()
|
_, mux := loadMux()
|
||||||
mux := loadMux()
|
ctx := rt.Context()
|
||||||
ctx := lib.Context()
|
|
||||||
|
|
||||||
b, err := fs.ReadFile(f, "plugin.json")
|
b, err := fs.ReadFile(f, "plugin.json")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -216,13 +209,14 @@ func ParsePluginFS(f fs.FS, lib thema.Library) (*Tree, error) {
|
|||||||
|
|
||||||
// Pass the raw bytes into the muxer, get the populated Model type out that we want.
|
// Pass the raw bytes into the muxer, get the populated Model type out that we want.
|
||||||
// TODO stop ignoring second return. (for now, lacunas are a WIP and can't occur until there's >1 schema in the pluginmeta lineage)
|
// TODO stop ignoring second return. (for now, lacunas are a WIP and can't occur until there's >1 schema in the pluginmeta lineage)
|
||||||
metaany, _, err := mux.Converge(b)
|
// metaany, _, err := mux(b)
|
||||||
|
pmeta, _, err := mux(b)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// TODO more nuanced error handling by class of Thema failure
|
// TODO more nuanced error handling by class of Thema failure
|
||||||
// return nil, fmt.Errorf("plugin.json was invalid: %w", err)
|
// return nil, fmt.Errorf("plugin.json was invalid: %w", err)
|
||||||
return nil, ewrap(err, ErrInvalidRootFile)
|
return nil, ewrap(err, ErrInvalidRootFile)
|
||||||
}
|
}
|
||||||
r.meta = *metaany.(*pluginmeta.Model)
|
r.meta = *pmeta
|
||||||
|
|
||||||
if modbyt, err := fs.ReadFile(f, "models.cue"); err == nil {
|
if modbyt, err := fs.ReadFile(f, "models.cue"); err == nil {
|
||||||
// TODO introduce layered CUE dependency-injecting loader
|
// TODO introduce layered CUE dependency-injecting loader
|
||||||
@ -260,7 +254,7 @@ func ParsePluginFS(f fs.FS, lib thema.Library) (*Tree, error) {
|
|||||||
}
|
}
|
||||||
for _, s := range allslots {
|
for _, s := range allslots {
|
||||||
iv := val.LookupPath(cue.ParsePath(s.slot.Name()))
|
iv := val.LookupPath(cue.ParsePath(s.slot.Name()))
|
||||||
lin, err := bindSlotLineage(iv, s.slot, r.meta, lib)
|
lin, err := bindSlotLineage(iv, s.slot, r.meta, rt)
|
||||||
if lin != nil {
|
if lin != nil {
|
||||||
r.slotimpls[s.slot.Name()] = lin
|
r.slotimpls[s.slot.Name()] = lin
|
||||||
}
|
}
|
||||||
@ -273,7 +267,7 @@ func ParsePluginFS(f fs.FS, lib thema.Library) (*Tree, error) {
|
|||||||
return tree, nil
|
return tree, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func bindSlotLineage(v cue.Value, s *coremodel.Slot, meta pluginmeta.Model, lib thema.Library, opts ...thema.BindOption) (thema.Lineage, error) {
|
func bindSlotLineage(v cue.Value, s *coremodel.Slot, meta pluginmeta.Model, rt *thema.Runtime, opts ...thema.BindOption) (thema.Lineage, error) {
|
||||||
accept, required := s.ForPluginType(string(meta.Type))
|
accept, required := s.ForPluginType(string(meta.Type))
|
||||||
exists := v.Exists()
|
exists := v.Exists()
|
||||||
|
|
||||||
@ -292,8 +286,8 @@ func bindSlotLineage(v cue.Value, s *coremodel.Slot, meta pluginmeta.Model, lib
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO make this opt real in thema, then uncomment to enforce joinSchema
|
// TODO make this opt real in thema, then uncomment to enforce joinSchema
|
||||||
// lin, err := thema.BindLineage(iv, lib, thema.SatisfiesJoinSchema(s.MetaSchema()))
|
// lin, err := thema.BindLineage(iv, rt, thema.SatisfiesJoinSchema(s.MetaSchema()))
|
||||||
lin, err := thema.BindLineage(v, lib, opts...)
|
lin, err := thema.BindLineage(v, rt, opts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, ewrap(fmt.Errorf("%s: invalid thema lineage for slot %s: %w", meta.Id, s.Name(), err), ErrInvalidLineage)
|
return nil, ewrap(fmt.Errorf("%s: invalid thema lineage for slot %s: %w", meta.Id, s.Name(), err), ErrInvalidLineage)
|
||||||
}
|
}
|
||||||
|
@ -157,7 +157,7 @@ func TestParseTreeTestdata(t *testing.T) {
|
|||||||
tab[ent.Name()] = tst
|
tab[ent.Name()] = tst
|
||||||
}
|
}
|
||||||
|
|
||||||
lib := cuectx.ProvideThemaLibrary()
|
lib := cuectx.GrafanaThemaRuntime()
|
||||||
for name, otst := range tab {
|
for name, otst := range tab {
|
||||||
tst := otst // otherwise var is shadowed within func by looping
|
tst := otst // otherwise var is shadowed within func by looping
|
||||||
t.Run(name, func(t *testing.T) {
|
t.Run(name, func(t *testing.T) {
|
||||||
@ -256,7 +256,7 @@ func TestParseTreeZips(t *testing.T) {
|
|||||||
tab[ent.Name()] = tst
|
tab[ent.Name()] = tst
|
||||||
}
|
}
|
||||||
|
|
||||||
lib := cuectx.ProvideThemaLibrary()
|
lib := cuectx.GrafanaThemaRuntime()
|
||||||
for name, otst := range tab {
|
for name, otst := range tab {
|
||||||
tst := otst // otherwise var is shadowed within func by looping
|
tst := otst // otherwise var is shadowed within func by looping
|
||||||
t.Run(name, func(t *testing.T) {
|
t.Run(name, func(t *testing.T) {
|
||||||
|
@ -330,8 +330,8 @@ var wireBasicSet = wire.NewSet(
|
|||||||
authproxy.ProvideAuthProxy,
|
authproxy.ProvideAuthProxy,
|
||||||
statscollector.ProvideService,
|
statscollector.ProvideService,
|
||||||
cmreg.CoremodelSet,
|
cmreg.CoremodelSet,
|
||||||
cuectx.ProvideCUEContext,
|
cuectx.GrafanaCUEContext,
|
||||||
cuectx.ProvideThemaLibrary,
|
cuectx.GrafanaThemaRuntime,
|
||||||
csrf.ProvideCSRFFilter,
|
csrf.ProvideCSRFFilter,
|
||||||
ossaccesscontrol.ProvideTeamPermissions,
|
ossaccesscontrol.ProvideTeamPermissions,
|
||||||
wire.Bind(new(accesscontrol.TeamPermissionsService), new(*ossaccesscontrol.TeamPermissionsService)),
|
wire.Bind(new(accesscontrol.TeamPermissionsService), new(*ossaccesscontrol.TeamPermissionsService)),
|
||||||
|
@ -48,7 +48,7 @@ func main() {
|
|||||||
groot := filepath.Join(sep, filepath.Join(grootp[:len(grootp)-3]...))
|
groot := filepath.Join(sep, filepath.Join(grootp[:len(grootp)-3]...))
|
||||||
|
|
||||||
wd := codegen.NewWriteDiffer()
|
wd := codegen.NewWriteDiffer()
|
||||||
lib := cuectx.ProvideThemaLibrary()
|
lib := cuectx.GrafanaThemaRuntime()
|
||||||
|
|
||||||
type ptreepath struct {
|
type ptreepath struct {
|
||||||
Path string
|
Path string
|
||||||
|
Loading…
Reference in New Issue
Block a user