mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
coremodels: Automatically generate coremodel registries (#50057)
* coremodel: Generate static registry * Actually make codegen work Also, remove the per-coremodel assignability test from generator set. * Make wire gen depend on cue gen This is necessary now that we're generating a wire set as part of coremodel registry generation. * Add wire inject bits to http server * s/staticregistry/registry/ * move to static and dynamic wording * Move registry type into registry package * Use static registry in http handler * Oi comments
This commit is contained in:
@@ -62,21 +62,28 @@ func main() {
|
||||
|
||||
wd := gcgen.NewWriteDiffer()
|
||||
for _, ls := range lins {
|
||||
wdg, err := ls.GenerateGoCoremodel(filepath.Join(cmroot, ls.Lineage.Name()))
|
||||
gofiles, err := ls.GenerateGoCoremodel(filepath.Join(cmroot, ls.Lineage.Name()))
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "failed to generate Go for %s: %s\n", ls.Lineage.Name(), err)
|
||||
os.Exit(1)
|
||||
}
|
||||
wd.Merge(wdg)
|
||||
wd.Merge(gofiles)
|
||||
|
||||
wdt, err := ls.GenerateTypescriptCoremodel(filepath.Join(tsroot, ls.Lineage.Name()))
|
||||
tsfiles, err := ls.GenerateTypescriptCoremodel(filepath.Join(tsroot, ls.Lineage.Name()))
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "failed to generate TypeScript for %s: %s\n", ls.Lineage.Name(), err)
|
||||
os.Exit(1)
|
||||
}
|
||||
wd.Merge(wdt)
|
||||
wd.Merge(tsfiles)
|
||||
}
|
||||
|
||||
regfiles, err := gcgen.GenerateCoremodelRegistry(filepath.Join(groot, "pkg", "framework", "coremodel", "registry", "registry_gen.go"), lins)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "failed to generate coremodel registry: %s\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
wd.Merge(regfiles)
|
||||
|
||||
if _, set := os.LookupEnv("CODEGEN_VERIFY"); set {
|
||||
err = wd.Verify()
|
||||
if err != nil {
|
||||
|
||||
25
pkg/framework/coremodel/registry/assignability_test.go
Normal file
25
pkg/framework/coremodel/registry/assignability_test.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package registry_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/grafana/grafana/pkg/framework/coremodel/registry"
|
||||
"github.com/grafana/thema"
|
||||
)
|
||||
|
||||
func TestSchemaAssignability(t *testing.T) {
|
||||
reg, err := registry.ProvideGeneric()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for _, cm := range reg.List() {
|
||||
tcm := cm
|
||||
t.Run(tcm.Lineage().Name(), func(t *testing.T) {
|
||||
err := thema.AssignableTo(tcm.CurrentSchema(), tcm.GoType())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
40
pkg/framework/coremodel/registry/provide.go
Normal file
40
pkg/framework/coremodel/registry/provide.go
Normal file
@@ -0,0 +1,40 @@
|
||||
package registry
|
||||
|
||||
import (
|
||||
"github.com/grafana/thema"
|
||||
)
|
||||
|
||||
// ProvideStatic provides access to individual coremodels via explicit method calls.
|
||||
//
|
||||
// Prefer this to the ProvideGeneric type when your code works with known,
|
||||
// specific coremodels(s), rather than generically across all of them. This
|
||||
// allows standard Go static analysis tools to determine which code is depending
|
||||
// on particular coremodels.
|
||||
//
|
||||
// This will use the default Grafana thema.Library, defined in pkg/cuectx, which
|
||||
// will avoid duplicate parsing of Thema CUE schemas. If you need control over the
|
||||
// thema.Library in use, use ProvideStaticWithLib instead.
|
||||
func ProvideStatic() (*Static, error) {
|
||||
return provideStatic(nil)
|
||||
}
|
||||
|
||||
// ProvideStaticWithLib is the same as ProvideStatic, but
|
||||
// allows control over the thema.Library used to initialize the underlying
|
||||
// coremodels.
|
||||
//
|
||||
// Prefer ProvideStatic unless you absolutely need this control.
|
||||
func ProvideStaticWithLib(lib thema.Library) (*Static, error) {
|
||||
return provideStatic(&lib)
|
||||
}
|
||||
|
||||
// ProvideGeneric provides a simple Generic registry of all coremodels.
|
||||
//
|
||||
// Prefer this to the static ProvideStatic when your code needs to
|
||||
// work with all coremodels generically, rather than specific coremodels.
|
||||
func ProvideGeneric() (*Generic, error) {
|
||||
return provideGeneric()
|
||||
}
|
||||
|
||||
// NOTE - no ProvideRegistryWithLib is defined because there are no anticipated
|
||||
// cases where a caller would need to operate generically across all coremodels,
|
||||
// and control the library they're initialized with. If that changes, add one.
|
||||
@@ -1,30 +1,32 @@
|
||||
package coremodel
|
||||
package registry
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/grafana/grafana/pkg/framework/coremodel"
|
||||
"github.com/grafana/thema"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrModelAlreadyRegistered is returned when trying to register duplicate model to Registry.
|
||||
// ErrModelAlreadyRegistered is returned when trying to register duplicate model to Generic.
|
||||
ErrModelAlreadyRegistered = errors.New("error registering duplicate model")
|
||||
)
|
||||
|
||||
// Registry is a registry of coremodel instances.
|
||||
type Registry struct {
|
||||
// Generic is a registry of coremodel instances. It is intended for use in cases where
|
||||
// generic operations limited to coremodel.Interface are being performed.
|
||||
type Generic struct {
|
||||
lock sync.RWMutex
|
||||
models []Interface
|
||||
modelIdx map[string]Interface
|
||||
models []coremodel.Interface
|
||||
modelIdx map[string]coremodel.Interface
|
||||
}
|
||||
|
||||
// NewRegistry returns a new Registry with the provided coremodel instances.
|
||||
func NewRegistry(models ...Interface) (*Registry, error) {
|
||||
r := &Registry{
|
||||
models: make([]Interface, 0, len(models)),
|
||||
modelIdx: make(map[string]Interface, len(models)),
|
||||
// NewRegistry returns a new Generic with the provided coremodel instances.
|
||||
func NewRegistry(models ...coremodel.Interface) (*Generic, error) {
|
||||
r := &Generic{
|
||||
models: make([]coremodel.Interface, 0, len(models)),
|
||||
modelIdx: make(map[string]coremodel.Interface, len(models)),
|
||||
}
|
||||
|
||||
if err := r.addModels(models); err != nil {
|
||||
@@ -34,20 +36,20 @@ func NewRegistry(models ...Interface) (*Registry, error) {
|
||||
return r, nil
|
||||
}
|
||||
|
||||
// Register adds coremodels to the Registry.
|
||||
func (r *Registry) Register(models ...Interface) error {
|
||||
// Register adds coremodels to the Generic.
|
||||
func (r *Generic) Register(models ...coremodel.Interface) error {
|
||||
return r.addModels(models)
|
||||
}
|
||||
|
||||
// List returns all coremodels registered in this Registry.
|
||||
func (r *Registry) List() []Interface {
|
||||
// List returns all coremodels registered in this Generic.
|
||||
func (r *Generic) List() []coremodel.Interface {
|
||||
r.lock.RLock()
|
||||
defer r.lock.RUnlock()
|
||||
|
||||
return r.models
|
||||
}
|
||||
|
||||
func (r *Registry) addModels(models []Interface) error {
|
||||
func (r *Generic) addModels(models []coremodel.Interface) error {
|
||||
r.lock.Lock()
|
||||
defer r.lock.Unlock()
|
||||
|
||||
@@ -76,12 +78,3 @@ func (r *Registry) addModels(models []Interface) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get retrieves a coremodel with the given string identifier. nil, false
|
||||
// is returned if no such coremodel exists.
|
||||
func (r *Registry) Get(name string) (cm Interface, has bool) {
|
||||
r.lock.RLock()
|
||||
cm, has = r.modelIdx[name]
|
||||
r.lock.RUnlock()
|
||||
return
|
||||
}
|
||||
91
pkg/framework/coremodel/registry/registry_gen.go
Normal file
91
pkg/framework/coremodel/registry/registry_gen.go
Normal file
@@ -0,0 +1,91 @@
|
||||
// This file is autogenerated. DO NOT EDIT.
|
||||
//
|
||||
// Generated by pkg/framework/coremodel/gen.go
|
||||
// Run "make gen-cue" from repository root to regenerate.
|
||||
|
||||
package registry
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/google/wire"
|
||||
|
||||
"github.com/grafana/grafana/pkg/coremodel/dashboard"
|
||||
"github.com/grafana/grafana/pkg/cuectx"
|
||||
"github.com/grafana/grafana/pkg/framework/coremodel"
|
||||
"github.com/grafana/thema"
|
||||
)
|
||||
|
||||
// CoremodelSet contains all of the wire-style providers related to coremodels.
|
||||
var CoremodelSet = wire.NewSet(
|
||||
ProvideStatic,
|
||||
ProvideGeneric,
|
||||
)
|
||||
|
||||
var (
|
||||
staticOnce sync.Once
|
||||
defaultStatic *Static
|
||||
defaultStaticErr error
|
||||
|
||||
genericOnce sync.Once
|
||||
defaultGeneric *Generic
|
||||
defaultGenericErr error
|
||||
)
|
||||
|
||||
// Static is a registry that provides access to individual coremodels via
|
||||
// explicit method calls, to aid with static analysis.
|
||||
type Static struct {
|
||||
dashboard *dashboard.Coremodel
|
||||
}
|
||||
|
||||
// type guards
|
||||
var (
|
||||
_ coremodel.Interface = &dashboard.Coremodel{}
|
||||
)
|
||||
|
||||
// Dashboard returns the dashboard coremodel. The return value is guaranteed to
|
||||
// implement coremodel.Interface.
|
||||
func (s *Static) Dashboard() *dashboard.Coremodel {
|
||||
return s.dashboard
|
||||
}
|
||||
|
||||
func provideStatic(lib *thema.Library) (*Static, error) {
|
||||
if lib == nil {
|
||||
staticOnce.Do(func() {
|
||||
defaultStatic, defaultStaticErr = doProvideStatic(cuectx.ProvideThemaLibrary())
|
||||
})
|
||||
return defaultStatic, defaultStaticErr
|
||||
}
|
||||
|
||||
return doProvideStatic(*lib)
|
||||
}
|
||||
|
||||
func doProvideStatic(lib thema.Library) (*Static, error) {
|
||||
var err error
|
||||
reg := &Static{}
|
||||
|
||||
reg.dashboard, err = dashboard.New(lib)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return reg, nil
|
||||
}
|
||||
|
||||
func provideGeneric() (*Generic, error) {
|
||||
ereg, err := provideStatic(nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
genericOnce.Do(func() {
|
||||
defaultGeneric, defaultGenericErr = doProvideGeneric(ereg)
|
||||
})
|
||||
return defaultGeneric, defaultGenericErr
|
||||
}
|
||||
|
||||
func doProvideGeneric(ereg *Static) (*Generic, error) {
|
||||
return NewRegistry(
|
||||
ereg.Dashboard(),
|
||||
)
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
package staticregistry
|
||||
|
||||
import (
|
||||
"github.com/grafana/grafana/pkg/coremodel/dashboard"
|
||||
"github.com/grafana/grafana/pkg/framework/coremodel"
|
||||
)
|
||||
|
||||
// ProvideRegistry provides a simple static Registry for coremodels.
|
||||
// Coremodels have to be manually added.
|
||||
// TODO dynamism
|
||||
func ProvideRegistry(
|
||||
dashboard *dashboard.Coremodel,
|
||||
) (*coremodel.Registry, error) {
|
||||
cmlist := []coremodel.Interface{
|
||||
dashboard,
|
||||
}
|
||||
|
||||
return coremodel.NewRegistry(cmlist...)
|
||||
}
|
||||
Reference in New Issue
Block a user