mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Schemas: Replace registry generation and github workflow (#83490)
* Create small registries for core and composable kinds * Update workflow with new registries * Fix imports in plugin schemas and deleted old registry generation files * Remove verification and maturity * Modify registries and add missing composable information to make schemas in kind-registry work * Add missing aliases * Remove unused templates * Remove kinds verification * Format generated code * Add gen header * Delete unused code and clean path in composable template * Delete kind-registry loader * Delete unused code * Update License link * Update codeowners path * Sort imports * More cleanup * Remove verify-kinds.yml from codeowners * Fix lint * Update composable_kidns * Fix cue extension * Restore verify-kinds to avoid to push outdated kind's registry * Fix composable format * Restore code owners for verify-kinds * Remove verify check
This commit is contained in:
parent
fd9031ca37
commit
5c7849417b
2
.github/CODEOWNERS
vendored
2
.github/CODEOWNERS
vendored
@ -630,7 +630,7 @@ embed.go @grafana/grafana-as-code
|
|||||||
/pkg/registry/apis/ @grafana/grafana-app-platform-squad
|
/pkg/registry/apis/ @grafana/grafana-app-platform-squad
|
||||||
/pkg/codegen/ @grafana/grafana-as-code
|
/pkg/codegen/ @grafana/grafana-as-code
|
||||||
/pkg/kinds/*/*_gen.go @grafana/grafana-as-code
|
/pkg/kinds/*/*_gen.go @grafana/grafana-as-code
|
||||||
/pkg/registry/corekind/ @grafana/grafana-as-code
|
/pkg/registry/schemas/ @grafana/grafana-as-code
|
||||||
/public/app/plugins/*gen.go @grafana/grafana-as-code
|
/public/app/plugins/*gen.go @grafana/grafana-as-code
|
||||||
/cue.mod/ @grafana/grafana-as-code
|
/cue.mod/ @grafana/grafana-as-code
|
||||||
|
|
||||||
|
385
.github/workflows/scripts/kinds/verify-kinds.go
vendored
385
.github/workflows/scripts/kinds/verify-kinds.go
vendored
@ -1,116 +1,53 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"archive/zip"
|
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"golang.org/x/text/cases"
|
||||||
"net/http"
|
"golang.org/x/text/language"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
"testing/fstest"
|
|
||||||
|
|
||||||
"cuelang.org/go/cue"
|
"cuelang.org/go/cue"
|
||||||
cueformat "cuelang.org/go/cue/format"
|
cueformat "cuelang.org/go/cue/format"
|
||||||
"github.com/google/go-github/github"
|
|
||||||
"github.com/grafana/codejen"
|
"github.com/grafana/codejen"
|
||||||
"github.com/grafana/grafana/pkg/codegen"
|
"github.com/grafana/grafana/pkg/registry/schemas"
|
||||||
"github.com/grafana/grafana/pkg/cuectx"
|
|
||||||
"github.com/grafana/grafana/pkg/plugins/pfs"
|
|
||||||
"github.com/grafana/grafana/pkg/plugins/pfs/corelist"
|
|
||||||
"github.com/grafana/grafana/pkg/registry/corekind"
|
|
||||||
"github.com/grafana/kindsys"
|
|
||||||
"github.com/grafana/thema"
|
|
||||||
"golang.org/x/oauth2"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
var nonAlphaNumRegex = regexp.MustCompile("[^a-zA-Z0-9 ]+")
|
||||||
GITHUB_OWNER = "grafana"
|
|
||||||
GITHUB_REPO = "kind-registry"
|
|
||||||
)
|
|
||||||
|
|
||||||
// main This script verifies that stable kinds are not updated once published (new schemas
|
// main This script verifies that stable kinds are not updated once published (new schemas
|
||||||
// can be added but existing ones cannot be updated).
|
// can be added but existing ones cannot be updated).
|
||||||
// If the env variable CODEGEN_VERIFY is not present, this also generates kind files into a
|
// It generates kind files into a local "next" folder, ready to be published in the kind-registry repo.
|
||||||
// local "next" folder, ready to be published in the kind-registry repo.
|
|
||||||
// If kind names are given as parameters, the script will make the above actions only for the
|
// If kind names are given as parameters, the script will make the above actions only for the
|
||||||
// given kinds.
|
// given kinds.
|
||||||
func main() {
|
func main() {
|
||||||
var corek []kindsys.Kind
|
|
||||||
var compok []kindsys.Composable
|
|
||||||
|
|
||||||
kindRegistry, err := NewKindRegistry()
|
|
||||||
defer kindRegistry.cleanUp()
|
|
||||||
if err != nil {
|
|
||||||
die(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Search for the latest version directory present in the kind-registry repo
|
|
||||||
latestRegistryDir, err := kindRegistry.findLatestDir()
|
|
||||||
if err != nil {
|
|
||||||
die(fmt.Errorf("failed to get latest directory for published kinds: %s", err))
|
|
||||||
}
|
|
||||||
|
|
||||||
errs := make([]error, 0)
|
|
||||||
|
|
||||||
// Kind verification
|
|
||||||
for _, kind := range corekind.NewBase(nil).All() {
|
|
||||||
name := kind.Props().Common().MachineName
|
|
||||||
err := verifyKind(kindRegistry, kind, name, "core", latestRegistryDir)
|
|
||||||
if err != nil {
|
|
||||||
errs = append(errs, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
corek = append(corek, kind)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, pp := range corelist.New(nil) {
|
|
||||||
for _, kind := range pp.ComposableKinds {
|
|
||||||
si, err := kindsys.FindSchemaInterface(kind.Def().Properties.SchemaInterface)
|
|
||||||
if err != nil {
|
|
||||||
errs = append(errs, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
name := strings.ToLower(fmt.Sprintf("%s/%s", strings.TrimSuffix(kind.Lineage().Name(), si.Name()), si.Name()))
|
|
||||||
err = verifyKind(kindRegistry, kind, name, "composable", latestRegistryDir)
|
|
||||||
if err != nil {
|
|
||||||
errs = append(errs, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
compok = append(compok, kind)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
die(errs...)
|
|
||||||
|
|
||||||
if _, set := os.LookupEnv("CODEGEN_VERIFY"); set {
|
|
||||||
os.Exit(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
// File generation
|
// File generation
|
||||||
jfs := codejen.NewFS()
|
jfs := codejen.NewFS()
|
||||||
outputPath := filepath.Join(".github", "workflows", "scripts", "kinds")
|
outputPath := filepath.Join(".github", "workflows", "scripts", "kinds")
|
||||||
|
|
||||||
coreJennies := codejen.JennyList[kindsys.Kind]{}
|
corekinds, err := schemas.GetCoreKinds()
|
||||||
|
die(err)
|
||||||
|
|
||||||
|
composableKinds, err := schemas.GetComposableKinds()
|
||||||
|
die(err)
|
||||||
|
|
||||||
|
coreJennies := codejen.JennyList[schemas.CoreKind]{}
|
||||||
coreJennies.Append(
|
coreJennies.Append(
|
||||||
KindRegistryJenny(outputPath),
|
CoreKindRegistryJenny(outputPath),
|
||||||
)
|
)
|
||||||
corefs, err := coreJennies.GenerateFS(corek...)
|
corefs, err := coreJennies.GenerateFS(corekinds...)
|
||||||
die(err)
|
die(err)
|
||||||
die(jfs.Merge(corefs))
|
die(jfs.Merge(corefs))
|
||||||
|
|
||||||
composableJennies := codejen.JennyList[kindsys.Composable]{}
|
composableJennies := codejen.JennyList[schemas.ComposableKind]{}
|
||||||
composableJennies.Append(
|
composableJennies.Append(
|
||||||
ComposableKindRegistryJenny(outputPath),
|
ComposableKindRegistryJenny(outputPath),
|
||||||
)
|
)
|
||||||
composablefs, err := composableJennies.GenerateFS(compok...)
|
composablefs, err := composableJennies.GenerateFS(composableKinds...)
|
||||||
die(err)
|
die(err)
|
||||||
die(jfs.Merge(composablefs))
|
die(jfs.Merge(composablefs))
|
||||||
|
|
||||||
@ -180,101 +117,8 @@ func die(errs ...error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// verifyKind verifies that stable kinds are not updated once published (new schemas
|
// CoreKindRegistryJenny generates kind files into the "next" folder of the local kind registry.
|
||||||
// can be added but existing ones cannot be updated)
|
func CoreKindRegistryJenny(path string) codejen.OneToOne[schemas.CoreKind] {
|
||||||
func verifyKind(registry *kindRegistry, kind kindsys.Kind, name string, category string, latestRegistryDir string) error {
|
|
||||||
oldKindString, err := registry.getPublishedKind(name, category, latestRegistryDir)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
var oldKind kindsys.Kind
|
|
||||||
if oldKindString != "" {
|
|
||||||
switch category {
|
|
||||||
case "core":
|
|
||||||
oldKind, err = loadCoreKind(name, oldKindString)
|
|
||||||
case "composable":
|
|
||||||
oldKind, err = loadComposableKind(name, oldKindString)
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("kind can only be core or composable")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Kind is new - no need to compare it
|
|
||||||
if oldKind == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check that maturity isn't downgraded
|
|
||||||
if kind.Maturity().Less(oldKind.Maturity()) {
|
|
||||||
return fmt.Errorf("kind maturity can't be downgraded once a kind is published")
|
|
||||||
}
|
|
||||||
|
|
||||||
if oldKind.Maturity().Less(kindsys.MaturityStable) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check that old schemas do not contain updates
|
|
||||||
err = thema.IsAppendOnly(oldKind.Lineage(), kind.Lineage())
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("existing schemas in lineage %s cannot be modified: %w", name, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func isLess(v1 []uint64, v2 []uint64) bool {
|
|
||||||
if len(v1) == 1 || len(v2) == 1 {
|
|
||||||
return v1[0] < v2[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
return v1[0] < v2[0] || (v1[0] == v2[0] && isLess(v1[2:], v2[2:]))
|
|
||||||
}
|
|
||||||
|
|
||||||
func loadCoreKind(name string, kind string) (kindsys.Kind, error) {
|
|
||||||
fs := fstest.MapFS{
|
|
||||||
fmt.Sprintf("%s.cue", name): &fstest.MapFile{
|
|
||||||
Data: []byte(kind),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
rt := cuectx.GrafanaThemaRuntime()
|
|
||||||
|
|
||||||
def, err := cuectx.LoadCoreKindDef(fmt.Sprintf("%s.cue", name), rt.Context(), fs)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("%s is not a valid kind: %w", name, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return kindsys.BindCore(rt, def)
|
|
||||||
}
|
|
||||||
|
|
||||||
func loadComposableKind(name string, kind string) (kindsys.Kind, error) {
|
|
||||||
parts := strings.Split(name, "/")
|
|
||||||
if len(parts) > 1 {
|
|
||||||
name = parts[1]
|
|
||||||
}
|
|
||||||
|
|
||||||
fs := fstest.MapFS{
|
|
||||||
fmt.Sprintf("%s.cue", name): &fstest.MapFile{
|
|
||||||
Data: []byte(kind),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
rt := cuectx.GrafanaThemaRuntime()
|
|
||||||
|
|
||||||
def, err := pfs.LoadComposableKindDef(fs, rt, fmt.Sprintf("%s.cue", name))
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("%s is not a valid kind: %w", name, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return kindsys.BindComposable(rt, def)
|
|
||||||
}
|
|
||||||
|
|
||||||
// KindRegistryJenny generates kind files into the "next" folder of the local kind registry.
|
|
||||||
func KindRegistryJenny(path string) codegen.OneToOne {
|
|
||||||
return &kindregjenny{
|
return &kindregjenny{
|
||||||
path: path,
|
path: path,
|
||||||
}
|
}
|
||||||
@ -288,35 +132,18 @@ func (j *kindregjenny) JennyName() string {
|
|||||||
return "KindRegistryJenny"
|
return "KindRegistryJenny"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (j *kindregjenny) Generate(kind kindsys.Kind) (*codejen.File, error) {
|
func (j *kindregjenny) Generate(kind schemas.CoreKind) (*codejen.File, error) {
|
||||||
name := kind.Props().Common().MachineName
|
newKindBytes, err := kindToBytes(kind.CueFile)
|
||||||
core, ok := kind.(kindsys.Core)
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("kind sent to KindRegistryJenny must be a core kind")
|
|
||||||
}
|
|
||||||
|
|
||||||
newKindBytes, err := kindToBytes(core.Def().V)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
path := filepath.Join(j.path, "next", "core", name, name+".cue")
|
path := filepath.Join(j.path, "next", "core", kind.Name, kind.Name+".cue")
|
||||||
return codejen.NewFile(path, newKindBytes, j), nil
|
return codejen.NewFile(path, newKindBytes, j), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// kindToBytes converts a kind cue value to a .cue file content
|
|
||||||
func kindToBytes(kind cue.Value) ([]byte, error) {
|
|
||||||
node := kind.Syntax(
|
|
||||||
cue.All(),
|
|
||||||
cue.Schema(),
|
|
||||||
cue.Docs(true),
|
|
||||||
)
|
|
||||||
|
|
||||||
return cueformat.Node(node)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ComposableKindRegistryJenny generates kind files into the "next" folder of the local kind registry.
|
// ComposableKindRegistryJenny generates kind files into the "next" folder of the local kind registry.
|
||||||
func ComposableKindRegistryJenny(path string) codejen.OneToOne[kindsys.Composable] {
|
func ComposableKindRegistryJenny(path string) codejen.OneToOne[schemas.ComposableKind] {
|
||||||
return &ckrJenny{
|
return &ckrJenny{
|
||||||
path: path,
|
path: path,
|
||||||
}
|
}
|
||||||
@ -330,149 +157,73 @@ func (j *ckrJenny) JennyName() string {
|
|||||||
return "ComposableKindRegistryJenny"
|
return "ComposableKindRegistryJenny"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (j *ckrJenny) Generate(k kindsys.Composable) (*codejen.File, error) {
|
func (j *ckrJenny) Generate(k schemas.ComposableKind) (*codejen.File, error) {
|
||||||
si, err := kindsys.FindSchemaInterface(k.Def().Properties.SchemaInterface)
|
name := strings.ToLower(fmt.Sprintf("%s/%s", k.Name, k.Filename))
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
name := strings.ToLower(fmt.Sprintf("%s/%s", strings.TrimSuffix(k.Lineage().Name(), si.Name()), si.Name()))
|
v := fixComposableKindFormat(k)
|
||||||
|
|
||||||
newKindBytes, err := kindToBytes(k.Def().V)
|
newKindBytes, err := kindToBytes(v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
newKindBytes = []byte(fmt.Sprintf("package grafanaplugin\n\n%s", newKindBytes))
|
newKindBytes = []byte(fmt.Sprintf("package grafanaplugin\n\n%s", newKindBytes))
|
||||||
|
|
||||||
return codejen.NewFile(filepath.Join(j.path, "next", "composable", name+".cue"), newKindBytes, j), nil
|
return codejen.NewFile(filepath.Join(j.path, "next", "composable", name), newKindBytes, j), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type kindRegistry struct {
|
// kindToBytes converts a kind cue value to a .cue file content
|
||||||
zipDir string
|
func kindToBytes(kind cue.Value) ([]byte, error) {
|
||||||
zipFile *zip.ReadCloser
|
node := kind.Syntax(
|
||||||
|
cue.All(),
|
||||||
|
cue.Schema(),
|
||||||
|
cue.Docs(true),
|
||||||
|
)
|
||||||
|
|
||||||
|
return cueformat.Node(node)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewKindRegistry downloads the archive of the kind-registry GH repository and open it
|
func fixComposableKindFormat(schema schemas.ComposableKind) cue.Value {
|
||||||
func NewKindRegistry() (*kindRegistry, error) {
|
variant := "PanelCfg"
|
||||||
ctx := context.Background()
|
if schema.CueFile.LookupPath(cue.ParsePath("composableKinds.DataQuery")).Exists() {
|
||||||
tc := oauth2.NewClient(ctx, nil)
|
variant = "DataQuery"
|
||||||
client := github.NewClient(tc)
|
|
||||||
|
|
||||||
// Create a temporary file to store the downloaded archive
|
|
||||||
file, err := os.CreateTemp("", "*.zip")
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to create temporary file: %w", err)
|
|
||||||
}
|
|
||||||
defer file.Close()
|
|
||||||
|
|
||||||
// Get the repository archive URL
|
|
||||||
archiveURL, _, err := client.Repositories.GetArchiveLink(ctx, GITHUB_OWNER, GITHUB_REPO, github.Zipball, &github.RepositoryContentGetOptions{})
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to get archive URL: %w", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Download the archive file
|
newCue := schema.CueFile.Context().CompileString(
|
||||||
httpClient := http.DefaultClient
|
fmt.Sprintf("schemaInterface: %q\n", variant) +
|
||||||
resp, err := httpClient.Get(archiveURL.String())
|
fmt.Sprintf("name: %q + %q\n\n", UpperCamelCase(schema.Name), variant) +
|
||||||
if err != nil {
|
"lineage: _",
|
||||||
return nil, fmt.Errorf("failed to download archive: %w", err)
|
)
|
||||||
}
|
|
||||||
defer resp.Body.Close()
|
|
||||||
|
|
||||||
// Save the downloaded archive to the temporary file
|
lineagePath := cue.MakePath(cue.Str("composableKinds"), cue.Str(variant), cue.Str("lineage"))
|
||||||
_, err = io.Copy(file, resp.Body)
|
return newCue.FillPath(cue.MakePath(cue.Str("lineage")), schema.CueFile.LookupPath(lineagePath))
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to save archive: %w", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open the zip file for reading
|
func UpperCamelCase(s string) string {
|
||||||
zipDir := file.Name()
|
s = LowerCamelCase(s)
|
||||||
zipFile, err := zip.OpenReader(zipDir)
|
|
||||||
if err != nil {
|
// Uppercase the first letter
|
||||||
return nil, fmt.Errorf("failed to open zip file %s: %w", zipDir, err)
|
if len(s) > 0 {
|
||||||
|
s = strings.ToUpper(s[:1]) + s[1:]
|
||||||
}
|
}
|
||||||
|
|
||||||
return &kindRegistry{
|
return s
|
||||||
zipDir: zipDir,
|
|
||||||
zipFile: zipFile,
|
|
||||||
}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// cleanUp removes the archive from the temporary files and closes the zip reader
|
func LowerCamelCase(s string) string {
|
||||||
func (registry *kindRegistry) cleanUp() {
|
// Replace all non-alphanumeric characters by spaces
|
||||||
if registry.zipDir != "" {
|
s = nonAlphaNumRegex.ReplaceAllString(s, " ")
|
||||||
err := os.Remove(registry.zipDir)
|
|
||||||
if err != nil {
|
// Title case s
|
||||||
fmt.Fprint(os.Stderr, fmt.Errorf("failed to remove zip archive: %w", err))
|
s = cases.Title(language.AmericanEnglish, cases.NoLower).String(s)
|
||||||
}
|
|
||||||
|
// Remove all spaces
|
||||||
|
s = strings.ReplaceAll(s, " ", "")
|
||||||
|
|
||||||
|
// Lowercase the first letter
|
||||||
|
if len(s) > 0 {
|
||||||
|
s = strings.ToLower(s[:1]) + s[1:]
|
||||||
}
|
}
|
||||||
|
|
||||||
if registry.zipFile != nil {
|
return s
|
||||||
err := registry.zipFile.Close()
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprint(os.Stderr, fmt.Errorf("failed to close zip file reader: %w", err))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// findLatestDir get the latest version directory published in the kind registry
|
|
||||||
func (registry *kindRegistry) findLatestDir() (string, error) {
|
|
||||||
re := regexp.MustCompile(`([0-9]+)\.([0-9]+)\.([0-9]+)`)
|
|
||||||
latestVersion := []uint64{0, 0, 0}
|
|
||||||
latestDir := ""
|
|
||||||
|
|
||||||
for _, file := range registry.zipFile.File {
|
|
||||||
if !file.FileInfo().IsDir() {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
parts := re.FindStringSubmatch(file.Name)
|
|
||||||
if parts == nil || len(parts) < 4 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
version := make([]uint64, len(parts)-1)
|
|
||||||
for i := 1; i < len(parts); i++ {
|
|
||||||
version[i-1], _ = strconv.ParseUint(parts[i], 10, 32)
|
|
||||||
}
|
|
||||||
|
|
||||||
if isLess(latestVersion, version) {
|
|
||||||
latestVersion = version
|
|
||||||
latestDir = file.Name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return latestDir, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// getPublishedKind retrieves the latest published kind from the kind registry
|
|
||||||
func (registry *kindRegistry) getPublishedKind(name string, category string, latestRegistryDir string) (string, error) {
|
|
||||||
if latestRegistryDir == "" {
|
|
||||||
return "", nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var cueFilePath string
|
|
||||||
switch category {
|
|
||||||
case "core":
|
|
||||||
cueFilePath = fmt.Sprintf("%s/%s.cue", name, name)
|
|
||||||
case "composable":
|
|
||||||
cueFilePath = fmt.Sprintf("%s.cue", name)
|
|
||||||
default:
|
|
||||||
return "", fmt.Errorf("kind can only be core or composable")
|
|
||||||
}
|
|
||||||
|
|
||||||
kindPath := filepath.Join(latestRegistryDir, category, cueFilePath)
|
|
||||||
file, err := registry.zipFile.Open(kindPath)
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("failed to open file: %w", err)
|
|
||||||
}
|
|
||||||
defer file.Close()
|
|
||||||
|
|
||||||
data, err := io.ReadAll(file)
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("failed to read file: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return string(data), nil
|
|
||||||
}
|
}
|
||||||
|
1
.github/workflows/verify-kinds.yml
vendored
1
.github/workflows/verify-kinds.yml
vendored
@ -23,5 +23,4 @@ jobs:
|
|||||||
- name: "Verify kinds"
|
- name: "Verify kinds"
|
||||||
run: go run .github/workflows/scripts/kinds/verify-kinds.go
|
run: go run .github/workflows/scripts/kinds/verify-kinds.go
|
||||||
env:
|
env:
|
||||||
CODEGEN_VERIFY: 1
|
|
||||||
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
|
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
|
||||||
|
@ -18,7 +18,7 @@ packaging/
|
|||||||
kinds/
|
kinds/
|
||||||
pkg/kinds/
|
pkg/kinds/
|
||||||
pkg/kindsys/
|
pkg/kindsys/
|
||||||
pkg/registry/corekind/
|
pkg/registry/schemas/
|
||||||
grafana-mixin/
|
grafana-mixin/
|
||||||
public/app/plugins/datasource/tempo
|
public/app/plugins/datasource/tempo
|
||||||
public/app/features/explore/TraceView/components
|
public/app/features/explore/TraceView/components
|
||||||
|
30
kinds/gen.go
30
kinds/gen.go
@ -15,7 +15,6 @@ import (
|
|||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"cuelang.org/go/cue"
|
|
||||||
"cuelang.org/go/cue/errors"
|
"cuelang.org/go/cue/errors"
|
||||||
"github.com/grafana/codejen"
|
"github.com/grafana/codejen"
|
||||||
"github.com/grafana/cuetsy"
|
"github.com/grafana/cuetsy"
|
||||||
@ -40,8 +39,6 @@ func main() {
|
|||||||
// All the jennies that comprise the core kinds generator pipeline
|
// All the jennies that comprise the core kinds generator pipeline
|
||||||
coreKindsGen.Append(
|
coreKindsGen.Append(
|
||||||
&codegen.GoSpecJenny{},
|
&codegen.GoSpecJenny{},
|
||||||
codegen.CoreKindJenny(cuectx.GoCoreKindParentPath, nil),
|
|
||||||
codegen.BaseCoreRegistryJenny(filepath.Join("pkg", "registry", "corekind"), cuectx.GoCoreKindParentPath),
|
|
||||||
codegen.LatestMajorsOrXJenny(cuectx.TSCoreKindParentPath),
|
codegen.LatestMajorsOrXJenny(cuectx.TSCoreKindParentPath),
|
||||||
codegen.TSVeneerIndexJenny(filepath.Join("packages", "grafana-schema", "src")),
|
codegen.TSVeneerIndexJenny(filepath.Join("packages", "grafana-schema", "src")),
|
||||||
)
|
)
|
||||||
@ -93,12 +90,12 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Merging k8 resources
|
// Merging k8 resources
|
||||||
k8Resources, err := genK8Resources(kinddirs)
|
rawResources, err := genRawResources(kinddirs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
die(err)
|
die(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = jfs.Merge(k8Resources); err != nil {
|
if err = jfs.Merge(rawResources); err != nil {
|
||||||
die(err)
|
die(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,12 +186,16 @@ func die(err error) {
|
|||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func genK8Resources(dirs []os.DirEntry) (*codejen.FS, error) {
|
// Resource generation without using Thema
|
||||||
jenny := codejen.JennyListWithNamer[[]cue.Value](func(_ []cue.Value) string {
|
func genRawResources(dirs []os.DirEntry) (*codejen.FS, error) {
|
||||||
return "K8Resources"
|
jenny := codejen.JennyListWithNamer[[]codegen.CueSchema](func(_ []codegen.CueSchema) string {
|
||||||
|
return "RawResources"
|
||||||
})
|
})
|
||||||
|
|
||||||
jenny.Append(&codegen.K8ResourcesJenny{})
|
jenny.Append(
|
||||||
|
&codegen.K8ResourcesJenny{},
|
||||||
|
&codegen.CoreRegistryJenny{},
|
||||||
|
)
|
||||||
|
|
||||||
header := codegen.SlashHeaderMapper("kinds/gen.go")
|
header := codegen.SlashHeaderMapper("kinds/gen.go")
|
||||||
jenny.AddPostprocessors(header)
|
jenny.AddPostprocessors(header)
|
||||||
@ -202,9 +203,9 @@ func genK8Resources(dirs []os.DirEntry) (*codejen.FS, error) {
|
|||||||
return jenny.GenerateFS(loadCueFiles(dirs))
|
return jenny.GenerateFS(loadCueFiles(dirs))
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadCueFiles(dirs []os.DirEntry) []cue.Value {
|
func loadCueFiles(dirs []os.DirEntry) []codegen.CueSchema {
|
||||||
ctx := cuectx.GrafanaCUEContext()
|
ctx := cuectx.GrafanaCUEContext()
|
||||||
values := make([]cue.Value, 0)
|
values := make([]codegen.CueSchema, 0)
|
||||||
for _, dir := range dirs {
|
for _, dir := range dirs {
|
||||||
if !dir.IsDir() {
|
if !dir.IsDir() {
|
||||||
continue
|
continue
|
||||||
@ -224,7 +225,12 @@ func loadCueFiles(dirs []os.DirEntry) []cue.Value {
|
|||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
values = append(values, ctx.CompileBytes(cueFile))
|
sch := codegen.CueSchema{
|
||||||
|
FilePath: "./" + filepath.Join(cuectx.CoreDefParentPath, entry),
|
||||||
|
CueFile: ctx.CompileBytes(cueFile),
|
||||||
|
}
|
||||||
|
|
||||||
|
values = append(values, sch)
|
||||||
}
|
}
|
||||||
|
|
||||||
return values
|
return values
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
|
"cuelang.org/go/cue"
|
||||||
"github.com/grafana/codejen"
|
"github.com/grafana/codejen"
|
||||||
"github.com/grafana/kindsys"
|
"github.com/grafana/kindsys"
|
||||||
"github.com/grafana/thema"
|
"github.com/grafana/thema"
|
||||||
@ -59,3 +60,8 @@ type SchemaForGen struct {
|
|||||||
// Whether the schema is grouped. See https://github.com/grafana/thema/issues/62
|
// Whether the schema is grouped. See https://github.com/grafana/thema/issues/62
|
||||||
IsGroup bool
|
IsGroup bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CueSchema struct {
|
||||||
|
CueFile cue.Value
|
||||||
|
FilePath string
|
||||||
|
}
|
||||||
|
@ -1,64 +0,0 @@
|
|||||||
package codegen
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"path/filepath"
|
|
||||||
|
|
||||||
"github.com/grafana/codejen"
|
|
||||||
"github.com/grafana/kindsys"
|
|
||||||
)
|
|
||||||
|
|
||||||
// BaseCoreRegistryJenny generates a static registry for core kinds that
|
|
||||||
// only initializes their [kindsys.Kind]. No slot kinds are composed.
|
|
||||||
//
|
|
||||||
// Path should be the relative path to the directory that will contain the
|
|
||||||
// generated registry. kindrelroot should be the repo-root-relative path to the
|
|
||||||
// parent directory to all directories that contain generated kind bindings
|
|
||||||
// (e.g. pkg/kind).
|
|
||||||
func BaseCoreRegistryJenny(path, kindrelroot string) ManyToOne {
|
|
||||||
return &genBaseRegistry{
|
|
||||||
path: path,
|
|
||||||
kindrelroot: kindrelroot,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type genBaseRegistry struct {
|
|
||||||
path string
|
|
||||||
kindrelroot string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (gen *genBaseRegistry) JennyName() string {
|
|
||||||
return "BaseCoreRegistryJenny"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (gen *genBaseRegistry) Generate(kinds ...kindsys.Kind) (*codejen.File, error) {
|
|
||||||
cores := make([]kindsys.Core, 0, len(kinds))
|
|
||||||
for _, d := range kinds {
|
|
||||||
if corekind, is := d.(kindsys.Core); is {
|
|
||||||
cores = append(cores, corekind)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(cores) == 0 {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
buf := new(bytes.Buffer)
|
|
||||||
if err := tmpls.Lookup("kind_registry.tmpl").Execute(buf, tvars_kind_registry{
|
|
||||||
PackageName: filepath.Base(gen.path),
|
|
||||||
KindPackagePrefix: filepath.ToSlash(filepath.Join("github.com/grafana/grafana", gen.kindrelroot)),
|
|
||||||
Kinds: cores,
|
|
||||||
}); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed executing kind registry template: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
b, err := postprocessGoFile(genGoFile{
|
|
||||||
path: gen.path,
|
|
||||||
in: buf.Bytes(),
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return codejen.NewFile(filepath.Join(gen.path, "base_gen.go"), b, gen), nil
|
|
||||||
}
|
|
62
pkg/codegen/jenny_core_registry.go
Normal file
62
pkg/codegen/jenny_core_registry.go
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
package codegen
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"go/format"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"cuelang.org/go/cue"
|
||||||
|
"github.com/grafana/codejen"
|
||||||
|
)
|
||||||
|
|
||||||
|
var registryPath = filepath.Join("pkg", "registry", "schemas")
|
||||||
|
|
||||||
|
// CoreRegistryJenny generates a registry with all core kinds.
|
||||||
|
type CoreRegistryJenny struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (jenny *CoreRegistryJenny) JennyName() string {
|
||||||
|
return "CoreRegistryJenny"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (jenny *CoreRegistryJenny) Generate(cueFiles []CueSchema) (codejen.Files, error) {
|
||||||
|
schemas := make([]Schema, len(cueFiles))
|
||||||
|
for i, v := range cueFiles {
|
||||||
|
name, err := getSchemaName(v.CueFile)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
schemas[i] = Schema{
|
||||||
|
Name: name,
|
||||||
|
FilePath: v.FilePath,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
if err := tmpls.Lookup("core_registry.tmpl").Execute(buf, tvars_registry{
|
||||||
|
Schemas: schemas,
|
||||||
|
}); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed executing kind registry template: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err := format.Source(buf.Bytes())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
file := codejen.NewFile(filepath.Join(registryPath, "core_kind.go"), b, jenny)
|
||||||
|
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
|
||||||
|
}
|
@ -1,72 +0,0 @@
|
|||||||
package codegen
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"path/filepath"
|
|
||||||
|
|
||||||
"github.com/grafana/codejen"
|
|
||||||
"github.com/grafana/kindsys"
|
|
||||||
)
|
|
||||||
|
|
||||||
// CoreKindJenny generates the implementation of [kindsys.Core] for the provided
|
|
||||||
// kind declaration.
|
|
||||||
//
|
|
||||||
// gokindsdir should be the relative path to the parent directory that contains
|
|
||||||
// all generated kinds.
|
|
||||||
//
|
|
||||||
// This generator only has output for core structured kinds.
|
|
||||||
func CoreKindJenny(gokindsdir string, cfg *CoreKindJennyConfig) OneToOne {
|
|
||||||
if cfg == nil {
|
|
||||||
cfg = new(CoreKindJennyConfig)
|
|
||||||
}
|
|
||||||
if cfg.GenDirName == nil {
|
|
||||||
cfg.GenDirName = func(def kindsys.Kind) string {
|
|
||||||
return def.Props().Common().MachineName
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return &coreKindJenny{
|
|
||||||
gokindsdir: gokindsdir,
|
|
||||||
cfg: cfg,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// CoreKindJennyConfig holds configuration options for [CoreKindJenny].
|
|
||||||
type CoreKindJennyConfig struct {
|
|
||||||
// GenDirName returns the name of the directory in which the file should be
|
|
||||||
// generated. Defaults to DefForGen.Lineage().Name() if nil.
|
|
||||||
GenDirName func(kindsys.Kind) string
|
|
||||||
}
|
|
||||||
|
|
||||||
type coreKindJenny struct {
|
|
||||||
gokindsdir string
|
|
||||||
cfg *CoreKindJennyConfig
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ OneToOne = &coreKindJenny{}
|
|
||||||
|
|
||||||
func (gen *coreKindJenny) JennyName() string {
|
|
||||||
return "CoreKindJenny"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (gen *coreKindJenny) Generate(kind kindsys.Kind) (*codejen.File, error) {
|
|
||||||
if _, is := kind.(kindsys.Core); !is {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
path := filepath.Join(gen.gokindsdir, gen.cfg.GenDirName(kind), kind.Props().Common().MachineName+"_kind_gen.go")
|
|
||||||
buf := new(bytes.Buffer)
|
|
||||||
if err := tmpls.Lookup("kind_core.tmpl").Execute(buf, kind); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed executing kind_core template for %s: %w", path, err)
|
|
||||||
}
|
|
||||||
b, err := postprocessGoFile(genGoFile{
|
|
||||||
path: path,
|
|
||||||
in: buf.Bytes(),
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return codejen.NewFile(path, b, gen), nil
|
|
||||||
}
|
|
@ -18,15 +18,15 @@ func (jenny *K8ResourcesJenny) JennyName() string {
|
|||||||
return "K8ResourcesJenny"
|
return "K8ResourcesJenny"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (jenny *K8ResourcesJenny) Generate(cueFiles []cue.Value) (codejen.Files, error) {
|
func (jenny *K8ResourcesJenny) Generate(cueFiles []CueSchema) (codejen.Files, error) {
|
||||||
files := make(codejen.Files, 0)
|
files := make(codejen.Files, 0)
|
||||||
for _, val := range cueFiles {
|
for _, val := range cueFiles {
|
||||||
pkg, err := getPackageName(val)
|
pkg, err := getPackageName(val.CueFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
resource, err := jenny.genResource(pkg, val)
|
resource, err := jenny.genResource(pkg, val.CueFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,6 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/grafana/codejen"
|
"github.com/grafana/codejen"
|
||||||
"github.com/grafana/kindsys"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// All the parsed templates in the tmpl subdirectory
|
// All the parsed templates in the tmpl subdirectory
|
||||||
@ -33,11 +32,7 @@ type (
|
|||||||
From string
|
From string
|
||||||
Leader string
|
Leader string
|
||||||
}
|
}
|
||||||
tvars_kind_registry struct {
|
|
||||||
PackageName string
|
|
||||||
KindPackagePrefix string
|
|
||||||
Kinds []kindsys.Core
|
|
||||||
}
|
|
||||||
tvars_resource struct {
|
tvars_resource struct {
|
||||||
PackageName string
|
PackageName string
|
||||||
KindName string
|
KindName string
|
||||||
@ -51,4 +46,13 @@ type (
|
|||||||
tvars_status struct {
|
tvars_status struct {
|
||||||
PackageName string
|
PackageName string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tvars_registry struct {
|
||||||
|
Schemas []Schema
|
||||||
|
}
|
||||||
|
|
||||||
|
Schema struct {
|
||||||
|
Name string
|
||||||
|
FilePath string
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
46
pkg/codegen/tmpl/core_registry.tmpl
Normal file
46
pkg/codegen/tmpl/core_registry.tmpl
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
package schemas
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
|
|
||||||
|
"cuelang.org/go/cue"
|
||||||
|
"cuelang.org/go/cue/cuecontext"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CoreKind struct {
|
||||||
|
Name string
|
||||||
|
CueFile cue.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetCoreKinds() ([]CoreKind, error) {
|
||||||
|
ctx := cuecontext.New()
|
||||||
|
kinds := make([]CoreKind, 0)
|
||||||
|
|
||||||
|
_, caller, _, _ := runtime.Caller(0)
|
||||||
|
root := filepath.Join(caller, "../../../..")
|
||||||
|
|
||||||
|
{{- range .Schemas }}
|
||||||
|
|
||||||
|
{{ .Name }}Cue, err := loadCueFile(ctx, filepath.Join(root, "{{ .FilePath }}"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
kinds = append(kinds, CoreKind{
|
||||||
|
Name: "{{ .Name }}",
|
||||||
|
CueFile: {{ .Name }}Cue,
|
||||||
|
})
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
return kinds, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadCueFile(ctx *cue.Context, path string) (cue.Value, error) {
|
||||||
|
cueFile, err := os.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
return cue.Value{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctx.CompileBytes(cueFile), nil
|
||||||
|
}
|
@ -1,70 +0,0 @@
|
|||||||
package {{ .Props.MachineName }}
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/grafana/kindsys"
|
|
||||||
"github.com/grafana/thema"
|
|
||||||
"github.com/grafana/thema/vmux"
|
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/cuectx"
|
|
||||||
)
|
|
||||||
|
|
||||||
// rootrel is the relative path from the grafana repository root to the
|
|
||||||
// directory containing the .cue files in which this kind is defined. Necessary
|
|
||||||
// for runtime errors related to the definition and/or lineage to provide
|
|
||||||
// a real path to the correct .cue file.
|
|
||||||
const rootrel string = "kinds/{{ .Props.MachineName }}"
|
|
||||||
|
|
||||||
// TODO standard generated docs
|
|
||||||
type Kind struct {
|
|
||||||
kindsys.Core
|
|
||||||
lin thema.ConvergentLineage[*Resource]
|
|
||||||
jcodec vmux.Codec
|
|
||||||
valmux vmux.ValueMux[*Resource]
|
|
||||||
}
|
|
||||||
|
|
||||||
// type guard - ensure generated Kind type satisfies the kindsys.Core interface
|
|
||||||
var _ kindsys.Core = &Kind{}
|
|
||||||
|
|
||||||
// TODO standard generated docs
|
|
||||||
func NewKind(rt *thema.Runtime, opts ...thema.BindOption) (*Kind, error) {
|
|
||||||
def, err := cuectx.LoadCoreKindDef(rootrel, rt.Context(), nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
k := &Kind{}
|
|
||||||
k.Core, err = kindsys.BindCore(rt, def, opts...)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// Get the thema.Schema that the meta says is in the current version (which
|
|
||||||
// codegen ensures is always the latest)
|
|
||||||
cursch := thema.SchemaP(k.Core.Lineage(), def.Properties.CurrentVersion)
|
|
||||||
tsch, err := thema.BindType(cursch, &Resource{})
|
|
||||||
if err != nil {
|
|
||||||
// Should be unreachable, modulo bugs in the Thema->Go code generator
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
k.jcodec = vmux.NewJSONCodec("{{ .Props.MachineName }}.json")
|
|
||||||
k.lin = tsch.ConvergentLineage()
|
|
||||||
k.valmux = vmux.NewValueMux(k.lin.TypedSchema(), k.jcodec)
|
|
||||||
return k, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ConvergentLineage returns the same [thema.Lineage] as Lineage, but bound (see [thema.BindType])
|
|
||||||
// to the the {{ .Props.Name }} [Resource] type generated from the current schema, v{{ .Props.CurrentVersion }}.
|
|
||||||
func (k *Kind) ConvergentLineage() thema.ConvergentLineage[*Resource] {
|
|
||||||
return k.lin
|
|
||||||
}
|
|
||||||
|
|
||||||
// JSONValueMux is a version multiplexer that maps a []byte containing JSON data
|
|
||||||
// at any schematized dashboard version to an instance of {{ .Props.Name }} [Resource].
|
|
||||||
//
|
|
||||||
// Validation and translation errors emitted from this func will identify the
|
|
||||||
// input bytes as "dashboard.json".
|
|
||||||
//
|
|
||||||
// This is a thin wrapper around Thema's [vmux.ValueMux].
|
|
||||||
func (k *Kind) JSONValueMux(b []byte) (*Resource, thema.TranslationLacunas, error) {
|
|
||||||
return k.valmux(b)
|
|
||||||
}
|
|
@ -1,61 +0,0 @@
|
|||||||
package {{ .PackageName }}
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
{{range .Kinds }}
|
|
||||||
"{{ $.KindPackagePrefix }}/{{ .Props.MachineName }}"{{end}}
|
|
||||||
"github.com/grafana/grafana/pkg/cuectx"
|
|
||||||
"github.com/grafana/kindsys"
|
|
||||||
"github.com/grafana/thema"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Base is a registry of all Grafana core kinds. It is designed for use both inside
|
|
||||||
// of Grafana itself, and for import by external Go programs wanting to work with Grafana's
|
|
||||||
// kind system.
|
|
||||||
//
|
|
||||||
// The registry provides two modes for accessing core kinds:
|
|
||||||
// * Per-kind methods, which return the kind-specific type, e.g. Dashboard() returns [dashboard.Dashboard].
|
|
||||||
// * All(), which returns a slice of [kindsys.Core].
|
|
||||||
//
|
|
||||||
// Prefer the individual named methods for use cases where the particular kind(s) that
|
|
||||||
// are needed are known to the caller. For example, a dashboard linter can know that it
|
|
||||||
// specifically wants the dashboard kind.
|
|
||||||
//
|
|
||||||
// Prefer All() when performing operations generically across all kinds. For example,
|
|
||||||
// a generic HTTP middleware for validating request bodies expected to contain some
|
|
||||||
// kind-schematized type.
|
|
||||||
type Base struct {
|
|
||||||
all []kindsys.Core
|
|
||||||
{{- range .Kinds }}
|
|
||||||
{{ .Props.MachineName }} *{{ .Props.MachineName }}.Kind{{end}}
|
|
||||||
}
|
|
||||||
|
|
||||||
// type guards
|
|
||||||
var (
|
|
||||||
{{- range .Kinds }}
|
|
||||||
_ kindsys.Core = &{{ .Props.MachineName }}.Kind{}{{end}}
|
|
||||||
)
|
|
||||||
|
|
||||||
{{range .Kinds }}
|
|
||||||
// {{ .Props.Name }} returns the [kindsys.Interface] implementation for the {{ .Props.MachineName }} kind.
|
|
||||||
func (b *Base) {{ .Props.Name }}() *{{ .Props.MachineName }}.Kind {
|
|
||||||
return b.{{ .Props.MachineName }}
|
|
||||||
}
|
|
||||||
{{end}}
|
|
||||||
|
|
||||||
func doNewBase(rt *thema.Runtime) *Base {
|
|
||||||
var err error
|
|
||||||
reg := &Base{}
|
|
||||||
|
|
||||||
{{range .Kinds }}
|
|
||||||
reg.{{ .Props.MachineName }}, err = {{ .Props.MachineName }}.NewKind(rt)
|
|
||||||
if err != nil {
|
|
||||||
panic(fmt.Sprintf("error while initializing the {{ .Props.MachineName }} Kind: %s", err))
|
|
||||||
}
|
|
||||||
reg.all = append(reg.all, reg.{{ .Props.MachineName }})
|
|
||||||
{{end}}
|
|
||||||
|
|
||||||
return reg
|
|
||||||
}
|
|
@ -1,74 +1,14 @@
|
|||||||
package codegen
|
package codegen
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"go/format"
|
|
||||||
"go/parser"
|
|
||||||
"go/token"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/dave/dst"
|
"github.com/dave/dst"
|
||||||
"github.com/dave/dst/decorator"
|
|
||||||
"github.com/dave/dst/dstutil"
|
"github.com/dave/dst/dstutil"
|
||||||
"golang.org/x/tools/imports"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type genGoFile struct {
|
|
||||||
path string
|
|
||||||
walker dstutil.ApplyFunc
|
|
||||||
in []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
func postprocessGoFile(cfg genGoFile) ([]byte, error) {
|
|
||||||
fname := 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)
|
|
||||||
}
|
|
||||||
|
|
||||||
if cfg.walker != nil {
|
|
||||||
dstutil.Apply(gf, cfg.walker, nil)
|
|
||||||
|
|
||||||
err = format.Node(buf, fset, gf)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("error formatting Go AST: %w", err)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
buf = bytes.NewBuffer(cfg.in)
|
|
||||||
}
|
|
||||||
|
|
||||||
byt, err := imports.Process(fname, buf.Bytes(), nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("goimports processing 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
|
|
||||||
fmt.Fprintf(os.Stderr, "The following imports were added by goimports while generating %s: \n\t%s\nRelying on goimports to find imports significantly slows down code generation. Consider adding these to the relevant template.\n", cfg.path, strings.Join(added, "\n\t"))
|
|
||||||
}
|
|
||||||
|
|
||||||
return byt, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type prefixmod struct {
|
type prefixmod struct {
|
||||||
prefix string
|
prefix string
|
||||||
replace string
|
replace string
|
||||||
|
@ -1,79 +0,0 @@
|
|||||||
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
|
|
||||||
//
|
|
||||||
// Generated by:
|
|
||||||
// kinds/gen.go
|
|
||||||
// Using jennies:
|
|
||||||
// CoreKindJenny
|
|
||||||
//
|
|
||||||
// Run 'make gen-cue' from repository root to regenerate.
|
|
||||||
|
|
||||||
package accesspolicy
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/grafana/kindsys"
|
|
||||||
"github.com/grafana/thema"
|
|
||||||
"github.com/grafana/thema/vmux"
|
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/cuectx"
|
|
||||||
)
|
|
||||||
|
|
||||||
// rootrel is the relative path from the grafana repository root to the
|
|
||||||
// directory containing the .cue files in which this kind is defined. Necessary
|
|
||||||
// for runtime errors related to the definition and/or lineage to provide
|
|
||||||
// a real path to the correct .cue file.
|
|
||||||
const rootrel string = "kinds/accesspolicy"
|
|
||||||
|
|
||||||
// TODO standard generated docs
|
|
||||||
type Kind struct {
|
|
||||||
kindsys.Core
|
|
||||||
lin thema.ConvergentLineage[*Resource]
|
|
||||||
jcodec vmux.Codec
|
|
||||||
valmux vmux.ValueMux[*Resource]
|
|
||||||
}
|
|
||||||
|
|
||||||
// type guard - ensure generated Kind type satisfies the kindsys.Core interface
|
|
||||||
var _ kindsys.Core = &Kind{}
|
|
||||||
|
|
||||||
// TODO standard generated docs
|
|
||||||
func NewKind(rt *thema.Runtime, opts ...thema.BindOption) (*Kind, error) {
|
|
||||||
def, err := cuectx.LoadCoreKindDef(rootrel, rt.Context(), nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
k := &Kind{}
|
|
||||||
k.Core, err = kindsys.BindCore(rt, def, opts...)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// Get the thema.Schema that the meta says is in the current version (which
|
|
||||||
// codegen ensures is always the latest)
|
|
||||||
cursch := thema.SchemaP(k.Core.Lineage(), def.Properties.CurrentVersion)
|
|
||||||
tsch, err := thema.BindType(cursch, &Resource{})
|
|
||||||
if err != nil {
|
|
||||||
// Should be unreachable, modulo bugs in the Thema->Go code generator
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
k.jcodec = vmux.NewJSONCodec("accesspolicy.json")
|
|
||||||
k.lin = tsch.ConvergentLineage()
|
|
||||||
k.valmux = vmux.NewValueMux(k.lin.TypedSchema(), k.jcodec)
|
|
||||||
return k, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ConvergentLineage returns the same [thema.Lineage] as Lineage, but bound (see [thema.BindType])
|
|
||||||
// to the the AccessPolicy [Resource] type generated from the current schema, v0.0.
|
|
||||||
func (k *Kind) ConvergentLineage() thema.ConvergentLineage[*Resource] {
|
|
||||||
return k.lin
|
|
||||||
}
|
|
||||||
|
|
||||||
// JSONValueMux is a version multiplexer that maps a []byte containing JSON data
|
|
||||||
// at any schematized dashboard version to an instance of AccessPolicy [Resource].
|
|
||||||
//
|
|
||||||
// Validation and translation errors emitted from this func will identify the
|
|
||||||
// input bytes as "dashboard.json".
|
|
||||||
//
|
|
||||||
// This is a thin wrapper around Thema's [vmux.ValueMux].
|
|
||||||
func (k *Kind) JSONValueMux(b []byte) (*Resource, thema.TranslationLacunas, error) {
|
|
||||||
return k.valmux(b)
|
|
||||||
}
|
|
@ -1,79 +0,0 @@
|
|||||||
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
|
|
||||||
//
|
|
||||||
// Generated by:
|
|
||||||
// kinds/gen.go
|
|
||||||
// Using jennies:
|
|
||||||
// CoreKindJenny
|
|
||||||
//
|
|
||||||
// Run 'make gen-cue' from repository root to regenerate.
|
|
||||||
|
|
||||||
package dashboard
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/grafana/kindsys"
|
|
||||||
"github.com/grafana/thema"
|
|
||||||
"github.com/grafana/thema/vmux"
|
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/cuectx"
|
|
||||||
)
|
|
||||||
|
|
||||||
// rootrel is the relative path from the grafana repository root to the
|
|
||||||
// directory containing the .cue files in which this kind is defined. Necessary
|
|
||||||
// for runtime errors related to the definition and/or lineage to provide
|
|
||||||
// a real path to the correct .cue file.
|
|
||||||
const rootrel string = "kinds/dashboard"
|
|
||||||
|
|
||||||
// TODO standard generated docs
|
|
||||||
type Kind struct {
|
|
||||||
kindsys.Core
|
|
||||||
lin thema.ConvergentLineage[*Resource]
|
|
||||||
jcodec vmux.Codec
|
|
||||||
valmux vmux.ValueMux[*Resource]
|
|
||||||
}
|
|
||||||
|
|
||||||
// type guard - ensure generated Kind type satisfies the kindsys.Core interface
|
|
||||||
var _ kindsys.Core = &Kind{}
|
|
||||||
|
|
||||||
// TODO standard generated docs
|
|
||||||
func NewKind(rt *thema.Runtime, opts ...thema.BindOption) (*Kind, error) {
|
|
||||||
def, err := cuectx.LoadCoreKindDef(rootrel, rt.Context(), nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
k := &Kind{}
|
|
||||||
k.Core, err = kindsys.BindCore(rt, def, opts...)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// Get the thema.Schema that the meta says is in the current version (which
|
|
||||||
// codegen ensures is always the latest)
|
|
||||||
cursch := thema.SchemaP(k.Core.Lineage(), def.Properties.CurrentVersion)
|
|
||||||
tsch, err := thema.BindType(cursch, &Resource{})
|
|
||||||
if err != nil {
|
|
||||||
// Should be unreachable, modulo bugs in the Thema->Go code generator
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
k.jcodec = vmux.NewJSONCodec("dashboard.json")
|
|
||||||
k.lin = tsch.ConvergentLineage()
|
|
||||||
k.valmux = vmux.NewValueMux(k.lin.TypedSchema(), k.jcodec)
|
|
||||||
return k, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ConvergentLineage returns the same [thema.Lineage] as Lineage, but bound (see [thema.BindType])
|
|
||||||
// to the the Dashboard [Resource] type generated from the current schema, v0.0.
|
|
||||||
func (k *Kind) ConvergentLineage() thema.ConvergentLineage[*Resource] {
|
|
||||||
return k.lin
|
|
||||||
}
|
|
||||||
|
|
||||||
// JSONValueMux is a version multiplexer that maps a []byte containing JSON data
|
|
||||||
// at any schematized dashboard version to an instance of Dashboard [Resource].
|
|
||||||
//
|
|
||||||
// Validation and translation errors emitted from this func will identify the
|
|
||||||
// input bytes as "dashboard.json".
|
|
||||||
//
|
|
||||||
// This is a thin wrapper around Thema's [vmux.ValueMux].
|
|
||||||
func (k *Kind) JSONValueMux(b []byte) (*Resource, thema.TranslationLacunas, error) {
|
|
||||||
return k.valmux(b)
|
|
||||||
}
|
|
@ -1,79 +0,0 @@
|
|||||||
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
|
|
||||||
//
|
|
||||||
// Generated by:
|
|
||||||
// kinds/gen.go
|
|
||||||
// Using jennies:
|
|
||||||
// CoreKindJenny
|
|
||||||
//
|
|
||||||
// Run 'make gen-cue' from repository root to regenerate.
|
|
||||||
|
|
||||||
package librarypanel
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/grafana/kindsys"
|
|
||||||
"github.com/grafana/thema"
|
|
||||||
"github.com/grafana/thema/vmux"
|
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/cuectx"
|
|
||||||
)
|
|
||||||
|
|
||||||
// rootrel is the relative path from the grafana repository root to the
|
|
||||||
// directory containing the .cue files in which this kind is defined. Necessary
|
|
||||||
// for runtime errors related to the definition and/or lineage to provide
|
|
||||||
// a real path to the correct .cue file.
|
|
||||||
const rootrel string = "kinds/librarypanel"
|
|
||||||
|
|
||||||
// TODO standard generated docs
|
|
||||||
type Kind struct {
|
|
||||||
kindsys.Core
|
|
||||||
lin thema.ConvergentLineage[*Resource]
|
|
||||||
jcodec vmux.Codec
|
|
||||||
valmux vmux.ValueMux[*Resource]
|
|
||||||
}
|
|
||||||
|
|
||||||
// type guard - ensure generated Kind type satisfies the kindsys.Core interface
|
|
||||||
var _ kindsys.Core = &Kind{}
|
|
||||||
|
|
||||||
// TODO standard generated docs
|
|
||||||
func NewKind(rt *thema.Runtime, opts ...thema.BindOption) (*Kind, error) {
|
|
||||||
def, err := cuectx.LoadCoreKindDef(rootrel, rt.Context(), nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
k := &Kind{}
|
|
||||||
k.Core, err = kindsys.BindCore(rt, def, opts...)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// Get the thema.Schema that the meta says is in the current version (which
|
|
||||||
// codegen ensures is always the latest)
|
|
||||||
cursch := thema.SchemaP(k.Core.Lineage(), def.Properties.CurrentVersion)
|
|
||||||
tsch, err := thema.BindType(cursch, &Resource{})
|
|
||||||
if err != nil {
|
|
||||||
// Should be unreachable, modulo bugs in the Thema->Go code generator
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
k.jcodec = vmux.NewJSONCodec("librarypanel.json")
|
|
||||||
k.lin = tsch.ConvergentLineage()
|
|
||||||
k.valmux = vmux.NewValueMux(k.lin.TypedSchema(), k.jcodec)
|
|
||||||
return k, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ConvergentLineage returns the same [thema.Lineage] as Lineage, but bound (see [thema.BindType])
|
|
||||||
// to the the LibraryPanel [Resource] type generated from the current schema, v0.0.
|
|
||||||
func (k *Kind) ConvergentLineage() thema.ConvergentLineage[*Resource] {
|
|
||||||
return k.lin
|
|
||||||
}
|
|
||||||
|
|
||||||
// JSONValueMux is a version multiplexer that maps a []byte containing JSON data
|
|
||||||
// at any schematized dashboard version to an instance of LibraryPanel [Resource].
|
|
||||||
//
|
|
||||||
// Validation and translation errors emitted from this func will identify the
|
|
||||||
// input bytes as "dashboard.json".
|
|
||||||
//
|
|
||||||
// This is a thin wrapper around Thema's [vmux.ValueMux].
|
|
||||||
func (k *Kind) JSONValueMux(b []byte) (*Resource, thema.TranslationLacunas, error) {
|
|
||||||
return k.valmux(b)
|
|
||||||
}
|
|
@ -1,79 +0,0 @@
|
|||||||
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
|
|
||||||
//
|
|
||||||
// Generated by:
|
|
||||||
// kinds/gen.go
|
|
||||||
// Using jennies:
|
|
||||||
// CoreKindJenny
|
|
||||||
//
|
|
||||||
// Run 'make gen-cue' from repository root to regenerate.
|
|
||||||
|
|
||||||
package preferences
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/grafana/kindsys"
|
|
||||||
"github.com/grafana/thema"
|
|
||||||
"github.com/grafana/thema/vmux"
|
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/cuectx"
|
|
||||||
)
|
|
||||||
|
|
||||||
// rootrel is the relative path from the grafana repository root to the
|
|
||||||
// directory containing the .cue files in which this kind is defined. Necessary
|
|
||||||
// for runtime errors related to the definition and/or lineage to provide
|
|
||||||
// a real path to the correct .cue file.
|
|
||||||
const rootrel string = "kinds/preferences"
|
|
||||||
|
|
||||||
// TODO standard generated docs
|
|
||||||
type Kind struct {
|
|
||||||
kindsys.Core
|
|
||||||
lin thema.ConvergentLineage[*Resource]
|
|
||||||
jcodec vmux.Codec
|
|
||||||
valmux vmux.ValueMux[*Resource]
|
|
||||||
}
|
|
||||||
|
|
||||||
// type guard - ensure generated Kind type satisfies the kindsys.Core interface
|
|
||||||
var _ kindsys.Core = &Kind{}
|
|
||||||
|
|
||||||
// TODO standard generated docs
|
|
||||||
func NewKind(rt *thema.Runtime, opts ...thema.BindOption) (*Kind, error) {
|
|
||||||
def, err := cuectx.LoadCoreKindDef(rootrel, rt.Context(), nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
k := &Kind{}
|
|
||||||
k.Core, err = kindsys.BindCore(rt, def, opts...)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// Get the thema.Schema that the meta says is in the current version (which
|
|
||||||
// codegen ensures is always the latest)
|
|
||||||
cursch := thema.SchemaP(k.Core.Lineage(), def.Properties.CurrentVersion)
|
|
||||||
tsch, err := thema.BindType(cursch, &Resource{})
|
|
||||||
if err != nil {
|
|
||||||
// Should be unreachable, modulo bugs in the Thema->Go code generator
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
k.jcodec = vmux.NewJSONCodec("preferences.json")
|
|
||||||
k.lin = tsch.ConvergentLineage()
|
|
||||||
k.valmux = vmux.NewValueMux(k.lin.TypedSchema(), k.jcodec)
|
|
||||||
return k, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ConvergentLineage returns the same [thema.Lineage] as Lineage, but bound (see [thema.BindType])
|
|
||||||
// to the the Preferences [Resource] type generated from the current schema, v0.0.
|
|
||||||
func (k *Kind) ConvergentLineage() thema.ConvergentLineage[*Resource] {
|
|
||||||
return k.lin
|
|
||||||
}
|
|
||||||
|
|
||||||
// JSONValueMux is a version multiplexer that maps a []byte containing JSON data
|
|
||||||
// at any schematized dashboard version to an instance of Preferences [Resource].
|
|
||||||
//
|
|
||||||
// Validation and translation errors emitted from this func will identify the
|
|
||||||
// input bytes as "dashboard.json".
|
|
||||||
//
|
|
||||||
// This is a thin wrapper around Thema's [vmux.ValueMux].
|
|
||||||
func (k *Kind) JSONValueMux(b []byte) (*Resource, thema.TranslationLacunas, error) {
|
|
||||||
return k.valmux(b)
|
|
||||||
}
|
|
@ -1,79 +0,0 @@
|
|||||||
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
|
|
||||||
//
|
|
||||||
// Generated by:
|
|
||||||
// kinds/gen.go
|
|
||||||
// Using jennies:
|
|
||||||
// CoreKindJenny
|
|
||||||
//
|
|
||||||
// Run 'make gen-cue' from repository root to regenerate.
|
|
||||||
|
|
||||||
package publicdashboard
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/grafana/kindsys"
|
|
||||||
"github.com/grafana/thema"
|
|
||||||
"github.com/grafana/thema/vmux"
|
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/cuectx"
|
|
||||||
)
|
|
||||||
|
|
||||||
// rootrel is the relative path from the grafana repository root to the
|
|
||||||
// directory containing the .cue files in which this kind is defined. Necessary
|
|
||||||
// for runtime errors related to the definition and/or lineage to provide
|
|
||||||
// a real path to the correct .cue file.
|
|
||||||
const rootrel string = "kinds/publicdashboard"
|
|
||||||
|
|
||||||
// TODO standard generated docs
|
|
||||||
type Kind struct {
|
|
||||||
kindsys.Core
|
|
||||||
lin thema.ConvergentLineage[*Resource]
|
|
||||||
jcodec vmux.Codec
|
|
||||||
valmux vmux.ValueMux[*Resource]
|
|
||||||
}
|
|
||||||
|
|
||||||
// type guard - ensure generated Kind type satisfies the kindsys.Core interface
|
|
||||||
var _ kindsys.Core = &Kind{}
|
|
||||||
|
|
||||||
// TODO standard generated docs
|
|
||||||
func NewKind(rt *thema.Runtime, opts ...thema.BindOption) (*Kind, error) {
|
|
||||||
def, err := cuectx.LoadCoreKindDef(rootrel, rt.Context(), nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
k := &Kind{}
|
|
||||||
k.Core, err = kindsys.BindCore(rt, def, opts...)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// Get the thema.Schema that the meta says is in the current version (which
|
|
||||||
// codegen ensures is always the latest)
|
|
||||||
cursch := thema.SchemaP(k.Core.Lineage(), def.Properties.CurrentVersion)
|
|
||||||
tsch, err := thema.BindType(cursch, &Resource{})
|
|
||||||
if err != nil {
|
|
||||||
// Should be unreachable, modulo bugs in the Thema->Go code generator
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
k.jcodec = vmux.NewJSONCodec("publicdashboard.json")
|
|
||||||
k.lin = tsch.ConvergentLineage()
|
|
||||||
k.valmux = vmux.NewValueMux(k.lin.TypedSchema(), k.jcodec)
|
|
||||||
return k, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ConvergentLineage returns the same [thema.Lineage] as Lineage, but bound (see [thema.BindType])
|
|
||||||
// to the the PublicDashboard [Resource] type generated from the current schema, v0.0.
|
|
||||||
func (k *Kind) ConvergentLineage() thema.ConvergentLineage[*Resource] {
|
|
||||||
return k.lin
|
|
||||||
}
|
|
||||||
|
|
||||||
// JSONValueMux is a version multiplexer that maps a []byte containing JSON data
|
|
||||||
// at any schematized dashboard version to an instance of PublicDashboard [Resource].
|
|
||||||
//
|
|
||||||
// Validation and translation errors emitted from this func will identify the
|
|
||||||
// input bytes as "dashboard.json".
|
|
||||||
//
|
|
||||||
// This is a thin wrapper around Thema's [vmux.ValueMux].
|
|
||||||
func (k *Kind) JSONValueMux(b []byte) (*Resource, thema.TranslationLacunas, error) {
|
|
||||||
return k.valmux(b)
|
|
||||||
}
|
|
@ -1,79 +0,0 @@
|
|||||||
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
|
|
||||||
//
|
|
||||||
// Generated by:
|
|
||||||
// kinds/gen.go
|
|
||||||
// Using jennies:
|
|
||||||
// CoreKindJenny
|
|
||||||
//
|
|
||||||
// Run 'make gen-cue' from repository root to regenerate.
|
|
||||||
|
|
||||||
package role
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/grafana/kindsys"
|
|
||||||
"github.com/grafana/thema"
|
|
||||||
"github.com/grafana/thema/vmux"
|
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/cuectx"
|
|
||||||
)
|
|
||||||
|
|
||||||
// rootrel is the relative path from the grafana repository root to the
|
|
||||||
// directory containing the .cue files in which this kind is defined. Necessary
|
|
||||||
// for runtime errors related to the definition and/or lineage to provide
|
|
||||||
// a real path to the correct .cue file.
|
|
||||||
const rootrel string = "kinds/role"
|
|
||||||
|
|
||||||
// TODO standard generated docs
|
|
||||||
type Kind struct {
|
|
||||||
kindsys.Core
|
|
||||||
lin thema.ConvergentLineage[*Resource]
|
|
||||||
jcodec vmux.Codec
|
|
||||||
valmux vmux.ValueMux[*Resource]
|
|
||||||
}
|
|
||||||
|
|
||||||
// type guard - ensure generated Kind type satisfies the kindsys.Core interface
|
|
||||||
var _ kindsys.Core = &Kind{}
|
|
||||||
|
|
||||||
// TODO standard generated docs
|
|
||||||
func NewKind(rt *thema.Runtime, opts ...thema.BindOption) (*Kind, error) {
|
|
||||||
def, err := cuectx.LoadCoreKindDef(rootrel, rt.Context(), nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
k := &Kind{}
|
|
||||||
k.Core, err = kindsys.BindCore(rt, def, opts...)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// Get the thema.Schema that the meta says is in the current version (which
|
|
||||||
// codegen ensures is always the latest)
|
|
||||||
cursch := thema.SchemaP(k.Core.Lineage(), def.Properties.CurrentVersion)
|
|
||||||
tsch, err := thema.BindType(cursch, &Resource{})
|
|
||||||
if err != nil {
|
|
||||||
// Should be unreachable, modulo bugs in the Thema->Go code generator
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
k.jcodec = vmux.NewJSONCodec("role.json")
|
|
||||||
k.lin = tsch.ConvergentLineage()
|
|
||||||
k.valmux = vmux.NewValueMux(k.lin.TypedSchema(), k.jcodec)
|
|
||||||
return k, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ConvergentLineage returns the same [thema.Lineage] as Lineage, but bound (see [thema.BindType])
|
|
||||||
// to the the Role [Resource] type generated from the current schema, v0.0.
|
|
||||||
func (k *Kind) ConvergentLineage() thema.ConvergentLineage[*Resource] {
|
|
||||||
return k.lin
|
|
||||||
}
|
|
||||||
|
|
||||||
// JSONValueMux is a version multiplexer that maps a []byte containing JSON data
|
|
||||||
// at any schematized dashboard version to an instance of Role [Resource].
|
|
||||||
//
|
|
||||||
// Validation and translation errors emitted from this func will identify the
|
|
||||||
// input bytes as "dashboard.json".
|
|
||||||
//
|
|
||||||
// This is a thin wrapper around Thema's [vmux.ValueMux].
|
|
||||||
func (k *Kind) JSONValueMux(b []byte) (*Resource, thema.TranslationLacunas, error) {
|
|
||||||
return k.valmux(b)
|
|
||||||
}
|
|
@ -1,79 +0,0 @@
|
|||||||
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
|
|
||||||
//
|
|
||||||
// Generated by:
|
|
||||||
// kinds/gen.go
|
|
||||||
// Using jennies:
|
|
||||||
// CoreKindJenny
|
|
||||||
//
|
|
||||||
// Run 'make gen-cue' from repository root to regenerate.
|
|
||||||
|
|
||||||
package rolebinding
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/grafana/kindsys"
|
|
||||||
"github.com/grafana/thema"
|
|
||||||
"github.com/grafana/thema/vmux"
|
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/cuectx"
|
|
||||||
)
|
|
||||||
|
|
||||||
// rootrel is the relative path from the grafana repository root to the
|
|
||||||
// directory containing the .cue files in which this kind is defined. Necessary
|
|
||||||
// for runtime errors related to the definition and/or lineage to provide
|
|
||||||
// a real path to the correct .cue file.
|
|
||||||
const rootrel string = "kinds/rolebinding"
|
|
||||||
|
|
||||||
// TODO standard generated docs
|
|
||||||
type Kind struct {
|
|
||||||
kindsys.Core
|
|
||||||
lin thema.ConvergentLineage[*Resource]
|
|
||||||
jcodec vmux.Codec
|
|
||||||
valmux vmux.ValueMux[*Resource]
|
|
||||||
}
|
|
||||||
|
|
||||||
// type guard - ensure generated Kind type satisfies the kindsys.Core interface
|
|
||||||
var _ kindsys.Core = &Kind{}
|
|
||||||
|
|
||||||
// TODO standard generated docs
|
|
||||||
func NewKind(rt *thema.Runtime, opts ...thema.BindOption) (*Kind, error) {
|
|
||||||
def, err := cuectx.LoadCoreKindDef(rootrel, rt.Context(), nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
k := &Kind{}
|
|
||||||
k.Core, err = kindsys.BindCore(rt, def, opts...)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// Get the thema.Schema that the meta says is in the current version (which
|
|
||||||
// codegen ensures is always the latest)
|
|
||||||
cursch := thema.SchemaP(k.Core.Lineage(), def.Properties.CurrentVersion)
|
|
||||||
tsch, err := thema.BindType(cursch, &Resource{})
|
|
||||||
if err != nil {
|
|
||||||
// Should be unreachable, modulo bugs in the Thema->Go code generator
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
k.jcodec = vmux.NewJSONCodec("rolebinding.json")
|
|
||||||
k.lin = tsch.ConvergentLineage()
|
|
||||||
k.valmux = vmux.NewValueMux(k.lin.TypedSchema(), k.jcodec)
|
|
||||||
return k, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ConvergentLineage returns the same [thema.Lineage] as Lineage, but bound (see [thema.BindType])
|
|
||||||
// to the the RoleBinding [Resource] type generated from the current schema, v0.0.
|
|
||||||
func (k *Kind) ConvergentLineage() thema.ConvergentLineage[*Resource] {
|
|
||||||
return k.lin
|
|
||||||
}
|
|
||||||
|
|
||||||
// JSONValueMux is a version multiplexer that maps a []byte containing JSON data
|
|
||||||
// at any schematized dashboard version to an instance of RoleBinding [Resource].
|
|
||||||
//
|
|
||||||
// Validation and translation errors emitted from this func will identify the
|
|
||||||
// input bytes as "dashboard.json".
|
|
||||||
//
|
|
||||||
// This is a thin wrapper around Thema's [vmux.ValueMux].
|
|
||||||
func (k *Kind) JSONValueMux(b []byte) (*Resource, thema.TranslationLacunas, error) {
|
|
||||||
return k.valmux(b)
|
|
||||||
}
|
|
@ -1,79 +0,0 @@
|
|||||||
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
|
|
||||||
//
|
|
||||||
// Generated by:
|
|
||||||
// kinds/gen.go
|
|
||||||
// Using jennies:
|
|
||||||
// CoreKindJenny
|
|
||||||
//
|
|
||||||
// Run 'make gen-cue' from repository root to regenerate.
|
|
||||||
|
|
||||||
package team
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/grafana/kindsys"
|
|
||||||
"github.com/grafana/thema"
|
|
||||||
"github.com/grafana/thema/vmux"
|
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/cuectx"
|
|
||||||
)
|
|
||||||
|
|
||||||
// rootrel is the relative path from the grafana repository root to the
|
|
||||||
// directory containing the .cue files in which this kind is defined. Necessary
|
|
||||||
// for runtime errors related to the definition and/or lineage to provide
|
|
||||||
// a real path to the correct .cue file.
|
|
||||||
const rootrel string = "kinds/team"
|
|
||||||
|
|
||||||
// TODO standard generated docs
|
|
||||||
type Kind struct {
|
|
||||||
kindsys.Core
|
|
||||||
lin thema.ConvergentLineage[*Resource]
|
|
||||||
jcodec vmux.Codec
|
|
||||||
valmux vmux.ValueMux[*Resource]
|
|
||||||
}
|
|
||||||
|
|
||||||
// type guard - ensure generated Kind type satisfies the kindsys.Core interface
|
|
||||||
var _ kindsys.Core = &Kind{}
|
|
||||||
|
|
||||||
// TODO standard generated docs
|
|
||||||
func NewKind(rt *thema.Runtime, opts ...thema.BindOption) (*Kind, error) {
|
|
||||||
def, err := cuectx.LoadCoreKindDef(rootrel, rt.Context(), nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
k := &Kind{}
|
|
||||||
k.Core, err = kindsys.BindCore(rt, def, opts...)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// Get the thema.Schema that the meta says is in the current version (which
|
|
||||||
// codegen ensures is always the latest)
|
|
||||||
cursch := thema.SchemaP(k.Core.Lineage(), def.Properties.CurrentVersion)
|
|
||||||
tsch, err := thema.BindType(cursch, &Resource{})
|
|
||||||
if err != nil {
|
|
||||||
// Should be unreachable, modulo bugs in the Thema->Go code generator
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
k.jcodec = vmux.NewJSONCodec("team.json")
|
|
||||||
k.lin = tsch.ConvergentLineage()
|
|
||||||
k.valmux = vmux.NewValueMux(k.lin.TypedSchema(), k.jcodec)
|
|
||||||
return k, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ConvergentLineage returns the same [thema.Lineage] as Lineage, but bound (see [thema.BindType])
|
|
||||||
// to the the Team [Resource] type generated from the current schema, v0.0.
|
|
||||||
func (k *Kind) ConvergentLineage() thema.ConvergentLineage[*Resource] {
|
|
||||||
return k.lin
|
|
||||||
}
|
|
||||||
|
|
||||||
// JSONValueMux is a version multiplexer that maps a []byte containing JSON data
|
|
||||||
// at any schematized dashboard version to an instance of Team [Resource].
|
|
||||||
//
|
|
||||||
// Validation and translation errors emitted from this func will identify the
|
|
||||||
// input bytes as "dashboard.json".
|
|
||||||
//
|
|
||||||
// This is a thin wrapper around Thema's [vmux.ValueMux].
|
|
||||||
func (k *Kind) JSONValueMux(b []byte) (*Resource, thema.TranslationLacunas, error) {
|
|
||||||
return k.valmux(b)
|
|
||||||
}
|
|
74
pkg/plugins/codegen/jenny_plugin_registry.go
Normal file
74
pkg/plugins/codegen/jenny_plugin_registry.go
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
package codegen
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"go/format"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/grafana/codejen"
|
||||||
|
)
|
||||||
|
|
||||||
|
var registryPath = filepath.Join("pkg", "registry", "schemas")
|
||||||
|
|
||||||
|
var renamedPlugins = map[string]string{
|
||||||
|
"cloud-monitoring": "googlecloudmonitoring",
|
||||||
|
"grafana-pyroscope-datasource": "grafanapyroscope",
|
||||||
|
"annolist": "annotationslist",
|
||||||
|
"grafanatestdatadatasource": "testdata",
|
||||||
|
"dashlist": "dashboardlist",
|
||||||
|
}
|
||||||
|
|
||||||
|
type PluginRegistryJenny struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (jenny *PluginRegistryJenny) JennyName() string {
|
||||||
|
return "PluginRegistryJenny"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (jenny *PluginRegistryJenny) Generate(files []string) (*codejen.File, error) {
|
||||||
|
if len(files) == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
schemas := make([]Schema, len(files))
|
||||||
|
for i, file := range files {
|
||||||
|
name, err := getSchemaName(file)
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
if err := tmpls.Lookup("composable_registry.tmpl").Execute(buf, tmpl_vars_plugin_registry{
|
||||||
|
Schemas: schemas,
|
||||||
|
}); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed executing kind registry template: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err := format.Source(buf.Bytes())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return codejen.NewFile(filepath.Join(registryPath, "composable_kind.go"), b, jenny), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getSchemaName(path string) (string, error) {
|
||||||
|
parts := strings.Split(path, "/")
|
||||||
|
if len(parts) < 2 {
|
||||||
|
return "", fmt.Errorf("path should contain more than 2 elements")
|
||||||
|
}
|
||||||
|
folderName := parts[len(parts)-2]
|
||||||
|
if renamed, ok := renamedPlugins[folderName]; ok {
|
||||||
|
folderName = renamed
|
||||||
|
}
|
||||||
|
folderName = strings.ReplaceAll(folderName, "-", "")
|
||||||
|
return strings.ToLower(folderName), nil
|
||||||
|
}
|
@ -1,100 +0,0 @@
|
|||||||
package codegen
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"path"
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/grafana/codejen"
|
|
||||||
"github.com/grafana/grafana/pkg/plugins/pfs"
|
|
||||||
)
|
|
||||||
|
|
||||||
const prefix = "github.com/grafana/grafana/public/app/plugins"
|
|
||||||
|
|
||||||
// PluginTreeListJenny creates a [codejen.ManyToOne] that produces Go code
|
|
||||||
// for loading a [pfs.PluginList] given [*kindsys.PluginDecl] as inputs.
|
|
||||||
func PluginTreeListJenny() codejen.ManyToOne[*pfs.PluginDecl] {
|
|
||||||
outputFile := filepath.Join("pkg", "plugins", "pfs", "corelist", "corelist_load_gen.go")
|
|
||||||
|
|
||||||
return &ptlJenny{
|
|
||||||
outputFile: outputFile,
|
|
||||||
plugins: make(map[string]bool, 0),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type ptlJenny struct {
|
|
||||||
outputFile string
|
|
||||||
plugins map[string]bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j *ptlJenny) JennyName() string {
|
|
||||||
return "PluginTreeListJenny"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j *ptlJenny) Generate(decls ...*pfs.PluginDecl) (*codejen.File, error) {
|
|
||||||
buf := new(bytes.Buffer)
|
|
||||||
vars := templateVars_plugin_registry{
|
|
||||||
Plugins: make([]struct {
|
|
||||||
PkgName, Path, ImportPath string
|
|
||||||
NoAlias bool
|
|
||||||
}, 0, len(decls)),
|
|
||||||
}
|
|
||||||
|
|
||||||
type tpl struct {
|
|
||||||
PkgName, Path, ImportPath string
|
|
||||||
NoAlias bool
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, decl := range decls {
|
|
||||||
meta := decl.PluginMeta
|
|
||||||
|
|
||||||
if _, exists := j.plugins[meta.Id]; exists {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
pluginId := j.sanitizePluginId(meta.Id)
|
|
||||||
vars.Plugins = append(vars.Plugins, tpl{
|
|
||||||
PkgName: pluginId,
|
|
||||||
NoAlias: pluginId != filepath.Base(decl.PluginPath),
|
|
||||||
ImportPath: filepath.ToSlash(filepath.Join(prefix, decl.PluginPath)),
|
|
||||||
Path: path.Join(append(strings.Split(prefix, "/")[3:], decl.PluginPath)...),
|
|
||||||
})
|
|
||||||
|
|
||||||
j.plugins[meta.Id] = true
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := tmpls.Lookup("plugin_registry.tmpl").Execute(buf, vars); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed executing plugin registry template: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
byt, err := postprocessGoFile(genGoFile{
|
|
||||||
path: j.outputFile,
|
|
||||||
in: buf.Bytes(),
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("error postprocessing plugin registry: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return codejen.NewFile(j.outputFile, byt, j), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j *ptlJenny) sanitizePluginId(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
|
|
||||||
case r == '-':
|
|
||||||
return '_'
|
|
||||||
default:
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
}, s)
|
|
||||||
}
|
|
@ -22,12 +22,13 @@ var tmplFS embed.FS
|
|||||||
// The following group of types, beginning with templateVars_*, all contain the set
|
// The following group of types, beginning with templateVars_*, all contain the set
|
||||||
// of variables expected by the corresponding named template file under tmpl/
|
// of variables expected by the corresponding named template file under tmpl/
|
||||||
type (
|
type (
|
||||||
templateVars_plugin_registry struct {
|
tmpl_vars_plugin_registry struct {
|
||||||
Plugins []struct {
|
Schemas []Schema
|
||||||
PkgName string
|
|
||||||
Path string
|
|
||||||
ImportPath string
|
|
||||||
NoAlias bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Schema struct {
|
||||||
|
Name string
|
||||||
|
Filename string
|
||||||
|
FilePath string
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
132
pkg/plugins/codegen/tmpl/composable_registry.tmpl
Normal file
132
pkg/plugins/codegen/tmpl/composable_registry.tmpl
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
package schemas
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/fs"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
|
"testing/fstest"
|
||||||
|
|
||||||
|
"cuelang.org/go/cue"
|
||||||
|
"cuelang.org/go/cue/cuecontext"
|
||||||
|
"cuelang.org/go/cue/load"
|
||||||
|
)
|
||||||
|
|
||||||
|
var cueImportsPath = filepath.Join("packages", "grafana-schema", "src", "common")
|
||||||
|
var importPath = "github.com/grafana/grafana/packages/grafana-schema/src/common"
|
||||||
|
|
||||||
|
type ComposableKind struct {
|
||||||
|
Name string
|
||||||
|
Filename string
|
||||||
|
CueFile cue.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetComposableKinds() ([]ComposableKind, error) {
|
||||||
|
kinds := make([]ComposableKind, 0)
|
||||||
|
|
||||||
|
_, caller, _, _ := runtime.Caller(0)
|
||||||
|
root := filepath.Join(caller, "../../../..")
|
||||||
|
|
||||||
|
{{- range .Schemas }}
|
||||||
|
|
||||||
|
{{ .Name }}Cue, err := loadCueFileWithCommon(root, filepath.Join(root, "{{ .FilePath }}"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
kinds = append(kinds, ComposableKind{
|
||||||
|
Name: "{{ .Name }}",
|
||||||
|
Filename: "{{ .Filename }}",
|
||||||
|
CueFile: {{ .Name }}Cue,
|
||||||
|
})
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
return kinds, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadCueFileWithCommon(root string, entrypoint string) (cue.Value, error) {
|
||||||
|
commonFS, err := mockCommonFS(root)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("cannot load common cue files: %s\n", err)
|
||||||
|
return cue.Value{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
overlay, err := buildOverlay(commonFS)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Cannot build overlay: %s\n", err)
|
||||||
|
return cue.Value{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
bis := load.Instances([]string{entrypoint}, &load.Config{
|
||||||
|
ModuleRoot: "/",
|
||||||
|
Overlay: overlay,
|
||||||
|
})
|
||||||
|
|
||||||
|
values, err := cuecontext.New().BuildInstances(bis)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Cannot build instance: %s\n", err)
|
||||||
|
return cue.Value{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return values[0], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func mockCommonFS(root string) (fs.FS, error) {
|
||||||
|
path := filepath.Join(root, cueImportsPath)
|
||||||
|
dir, err := os.ReadDir(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("cannot open common cue files directory: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
prefix := "cue.mod/pkg/" + importPath
|
||||||
|
|
||||||
|
commonFS := fstest.MapFS{}
|
||||||
|
for _, d := range dir {
|
||||||
|
if d.IsDir() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
readPath := filepath.Join(path, d.Name())
|
||||||
|
b, err := os.ReadFile(filepath.Clean(readPath))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
commonFS[filepath.Join(prefix, d.Name())] = &fstest.MapFile{Data: b}
|
||||||
|
}
|
||||||
|
|
||||||
|
return commonFS, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// It loads common cue files into the schema to be able to make import works
|
||||||
|
func buildOverlay(commonFS fs.FS) (map[string]load.Source, error) {
|
||||||
|
overlay := make(map[string]load.Source)
|
||||||
|
|
||||||
|
err := fs.WalkDir(commonFS, ".", func(path string, d fs.DirEntry, err error) error {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.IsDir() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
f, err := commonFS.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer func() { _ = f.Close() }()
|
||||||
|
|
||||||
|
b, err := io.ReadAll(f)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
overlay[filepath.Join("/", path)] = load.FromBytes(b)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
return overlay, err
|
||||||
|
}
|
@ -1,30 +0,0 @@
|
|||||||
package corelist
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io/fs"
|
|
||||||
"sync"
|
|
||||||
"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{
|
|
||||||
{{- range .Plugins }}
|
|
||||||
parsePluginOrPanic("{{ .Path }}", "{{ .PkgName }}", rt),
|
|
||||||
{{- end }}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,68 +0,0 @@
|
|||||||
package codegen
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"go/format"
|
|
||||||
"go/parser"
|
|
||||||
"go/token"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/dave/dst/decorator"
|
|
||||||
"github.com/dave/dst/dstutil"
|
|
||||||
"golang.org/x/tools/imports"
|
|
||||||
)
|
|
||||||
|
|
||||||
type genGoFile struct {
|
|
||||||
path string
|
|
||||||
walker dstutil.ApplyFunc
|
|
||||||
in []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
func postprocessGoFile(cfg genGoFile) ([]byte, error) {
|
|
||||||
fname := 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)
|
|
||||||
}
|
|
||||||
|
|
||||||
if cfg.walker != nil {
|
|
||||||
dstutil.Apply(gf, cfg.walker, nil)
|
|
||||||
|
|
||||||
err = format.Node(buf, fset, gf)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("error formatting Go AST: %w", err)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
buf = bytes.NewBuffer(cfg.in)
|
|
||||||
}
|
|
||||||
|
|
||||||
byt, err := imports.Process(fname, buf.Bytes(), nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("goimports processing 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
|
|
||||||
fmt.Fprintf(os.Stderr, "The following imports were added by goimports while generating %s: \n\t%s\nRelying on goimports to find imports significantly slows down code generation. Consider adding these to the relevant template.\n", cfg.path, strings.Join(added, "\n\t"))
|
|
||||||
}
|
|
||||||
|
|
||||||
return byt, nil
|
|
||||||
}
|
|
@ -1,42 +0,0 @@
|
|||||||
package corekind
|
|
||||||
|
|
||||||
import (
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/grafana/kindsys"
|
|
||||||
"github.com/grafana/thema"
|
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/cuectx"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
baseOnce sync.Once
|
|
||||||
defaultBase *Base
|
|
||||||
)
|
|
||||||
|
|
||||||
// NewBase provides a registry of all core raw and structured kinds, without any
|
|
||||||
// composition of slot kinds.
|
|
||||||
//
|
|
||||||
// All calling code within grafana/grafana is expected to use Grafana's
|
|
||||||
// singleton [thema.Runtime], returned from [cuectx.GrafanaThemaRuntime]. If nil
|
|
||||||
// is passed, the singleton will be used.
|
|
||||||
func NewBase(rt *thema.Runtime) *Base {
|
|
||||||
allrt := cuectx.GrafanaThemaRuntime()
|
|
||||||
if rt == nil || rt == allrt {
|
|
||||||
baseOnce.Do(func() {
|
|
||||||
defaultBase = doNewBase(allrt)
|
|
||||||
})
|
|
||||||
return defaultBase
|
|
||||||
}
|
|
||||||
|
|
||||||
return doNewBase(rt)
|
|
||||||
}
|
|
||||||
|
|
||||||
// All returns a slice of [kindsys.Core] containing all core Grafana kinds.
|
|
||||||
//
|
|
||||||
// The returned slice is sorted lexicographically by kind machine name.
|
|
||||||
func (b *Base) All() []kindsys.Core {
|
|
||||||
ret := make([]kindsys.Core, len(b.all))
|
|
||||||
copy(ret, b.all)
|
|
||||||
return ret
|
|
||||||
}
|
|
@ -1,159 +0,0 @@
|
|||||||
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
|
|
||||||
//
|
|
||||||
// Generated by:
|
|
||||||
// kinds/gen.go
|
|
||||||
// Using jennies:
|
|
||||||
// BaseCoreRegistryJenny
|
|
||||||
//
|
|
||||||
// Run 'make gen-cue' from repository root to regenerate.
|
|
||||||
|
|
||||||
package corekind
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/kinds/accesspolicy"
|
|
||||||
"github.com/grafana/grafana/pkg/kinds/dashboard"
|
|
||||||
"github.com/grafana/grafana/pkg/kinds/librarypanel"
|
|
||||||
"github.com/grafana/grafana/pkg/kinds/preferences"
|
|
||||||
"github.com/grafana/grafana/pkg/kinds/publicdashboard"
|
|
||||||
"github.com/grafana/grafana/pkg/kinds/role"
|
|
||||||
"github.com/grafana/grafana/pkg/kinds/rolebinding"
|
|
||||||
"github.com/grafana/grafana/pkg/kinds/team"
|
|
||||||
"github.com/grafana/kindsys"
|
|
||||||
"github.com/grafana/thema"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Base is a registry of all Grafana core kinds. It is designed for use both inside
|
|
||||||
// of Grafana itself, and for import by external Go programs wanting to work with Grafana's
|
|
||||||
// kind system.
|
|
||||||
//
|
|
||||||
// The registry provides two modes for accessing core kinds:
|
|
||||||
// - Per-kind methods, which return the kind-specific type, e.g. Dashboard() returns [dashboard.Dashboard].
|
|
||||||
// - All(), which returns a slice of [kindsys.Core].
|
|
||||||
//
|
|
||||||
// Prefer the individual named methods for use cases where the particular kind(s) that
|
|
||||||
// are needed are known to the caller. For example, a dashboard linter can know that it
|
|
||||||
// specifically wants the dashboard kind.
|
|
||||||
//
|
|
||||||
// Prefer All() when performing operations generically across all kinds. For example,
|
|
||||||
// a generic HTTP middleware for validating request bodies expected to contain some
|
|
||||||
// kind-schematized type.
|
|
||||||
type Base struct {
|
|
||||||
all []kindsys.Core
|
|
||||||
accesspolicy *accesspolicy.Kind
|
|
||||||
dashboard *dashboard.Kind
|
|
||||||
librarypanel *librarypanel.Kind
|
|
||||||
preferences *preferences.Kind
|
|
||||||
publicdashboard *publicdashboard.Kind
|
|
||||||
role *role.Kind
|
|
||||||
rolebinding *rolebinding.Kind
|
|
||||||
team *team.Kind
|
|
||||||
}
|
|
||||||
|
|
||||||
// type guards
|
|
||||||
var (
|
|
||||||
_ kindsys.Core = &accesspolicy.Kind{}
|
|
||||||
_ kindsys.Core = &dashboard.Kind{}
|
|
||||||
_ kindsys.Core = &librarypanel.Kind{}
|
|
||||||
_ kindsys.Core = &preferences.Kind{}
|
|
||||||
_ kindsys.Core = &publicdashboard.Kind{}
|
|
||||||
_ kindsys.Core = &role.Kind{}
|
|
||||||
_ kindsys.Core = &rolebinding.Kind{}
|
|
||||||
_ kindsys.Core = &team.Kind{}
|
|
||||||
)
|
|
||||||
|
|
||||||
// AccessPolicy returns the [kindsys.Interface] implementation for the accesspolicy kind.
|
|
||||||
func (b *Base) AccessPolicy() *accesspolicy.Kind {
|
|
||||||
return b.accesspolicy
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dashboard returns the [kindsys.Interface] implementation for the dashboard kind.
|
|
||||||
func (b *Base) Dashboard() *dashboard.Kind {
|
|
||||||
return b.dashboard
|
|
||||||
}
|
|
||||||
|
|
||||||
// LibraryPanel returns the [kindsys.Interface] implementation for the librarypanel kind.
|
|
||||||
func (b *Base) LibraryPanel() *librarypanel.Kind {
|
|
||||||
return b.librarypanel
|
|
||||||
}
|
|
||||||
|
|
||||||
// Preferences returns the [kindsys.Interface] implementation for the preferences kind.
|
|
||||||
func (b *Base) Preferences() *preferences.Kind {
|
|
||||||
return b.preferences
|
|
||||||
}
|
|
||||||
|
|
||||||
// PublicDashboard returns the [kindsys.Interface] implementation for the publicdashboard kind.
|
|
||||||
func (b *Base) PublicDashboard() *publicdashboard.Kind {
|
|
||||||
return b.publicdashboard
|
|
||||||
}
|
|
||||||
|
|
||||||
// Role returns the [kindsys.Interface] implementation for the role kind.
|
|
||||||
func (b *Base) Role() *role.Kind {
|
|
||||||
return b.role
|
|
||||||
}
|
|
||||||
|
|
||||||
// RoleBinding returns the [kindsys.Interface] implementation for the rolebinding kind.
|
|
||||||
func (b *Base) RoleBinding() *rolebinding.Kind {
|
|
||||||
return b.rolebinding
|
|
||||||
}
|
|
||||||
|
|
||||||
// Team returns the [kindsys.Interface] implementation for the team kind.
|
|
||||||
func (b *Base) Team() *team.Kind {
|
|
||||||
return b.team
|
|
||||||
}
|
|
||||||
|
|
||||||
func doNewBase(rt *thema.Runtime) *Base {
|
|
||||||
var err error
|
|
||||||
reg := &Base{}
|
|
||||||
|
|
||||||
reg.accesspolicy, err = accesspolicy.NewKind(rt)
|
|
||||||
if err != nil {
|
|
||||||
panic(fmt.Sprintf("error while initializing the accesspolicy Kind: %s", err))
|
|
||||||
}
|
|
||||||
reg.all = append(reg.all, reg.accesspolicy)
|
|
||||||
|
|
||||||
reg.dashboard, err = dashboard.NewKind(rt)
|
|
||||||
if err != nil {
|
|
||||||
panic(fmt.Sprintf("error while initializing the dashboard Kind: %s", err))
|
|
||||||
}
|
|
||||||
reg.all = append(reg.all, reg.dashboard)
|
|
||||||
|
|
||||||
reg.librarypanel, err = librarypanel.NewKind(rt)
|
|
||||||
if err != nil {
|
|
||||||
panic(fmt.Sprintf("error while initializing the librarypanel Kind: %s", err))
|
|
||||||
}
|
|
||||||
reg.all = append(reg.all, reg.librarypanel)
|
|
||||||
|
|
||||||
reg.preferences, err = preferences.NewKind(rt)
|
|
||||||
if err != nil {
|
|
||||||
panic(fmt.Sprintf("error while initializing the preferences Kind: %s", err))
|
|
||||||
}
|
|
||||||
reg.all = append(reg.all, reg.preferences)
|
|
||||||
|
|
||||||
reg.publicdashboard, err = publicdashboard.NewKind(rt)
|
|
||||||
if err != nil {
|
|
||||||
panic(fmt.Sprintf("error while initializing the publicdashboard Kind: %s", err))
|
|
||||||
}
|
|
||||||
reg.all = append(reg.all, reg.publicdashboard)
|
|
||||||
|
|
||||||
reg.role, err = role.NewKind(rt)
|
|
||||||
if err != nil {
|
|
||||||
panic(fmt.Sprintf("error while initializing the role Kind: %s", err))
|
|
||||||
}
|
|
||||||
reg.all = append(reg.all, reg.role)
|
|
||||||
|
|
||||||
reg.rolebinding, err = rolebinding.NewKind(rt)
|
|
||||||
if err != nil {
|
|
||||||
panic(fmt.Sprintf("error while initializing the rolebinding Kind: %s", err))
|
|
||||||
}
|
|
||||||
reg.all = append(reg.all, reg.rolebinding)
|
|
||||||
|
|
||||||
reg.team, err = team.NewKind(rt)
|
|
||||||
if err != nil {
|
|
||||||
panic(fmt.Sprintf("error while initializing the team Kind: %s", err))
|
|
||||||
}
|
|
||||||
reg.all = append(reg.all, reg.team)
|
|
||||||
|
|
||||||
return reg
|
|
||||||
}
|
|
468
pkg/registry/schemas/composable_kind.go
Normal file
468
pkg/registry/schemas/composable_kind.go
Normal file
@ -0,0 +1,468 @@
|
|||||||
|
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
|
||||||
|
//
|
||||||
|
// Generated by:
|
||||||
|
// public/app/plugins/gen.go
|
||||||
|
// Using jennies:
|
||||||
|
// PluginRegistryJenny
|
||||||
|
//
|
||||||
|
// Run 'make gen-cue' from repository root to regenerate.
|
||||||
|
|
||||||
|
package schemas
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/fs"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
|
"testing/fstest"
|
||||||
|
|
||||||
|
"cuelang.org/go/cue"
|
||||||
|
"cuelang.org/go/cue/cuecontext"
|
||||||
|
"cuelang.org/go/cue/load"
|
||||||
|
)
|
||||||
|
|
||||||
|
var cueImportsPath = filepath.Join("packages", "grafana-schema", "src", "common")
|
||||||
|
var importPath = "github.com/grafana/grafana/packages/grafana-schema/src/common"
|
||||||
|
|
||||||
|
type ComposableKind struct {
|
||||||
|
Name string
|
||||||
|
Filename string
|
||||||
|
CueFile cue.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetComposableKinds() ([]ComposableKind, error) {
|
||||||
|
kinds := make([]ComposableKind, 0)
|
||||||
|
|
||||||
|
_, caller, _, _ := runtime.Caller(0)
|
||||||
|
root := filepath.Join(caller, "../../../..")
|
||||||
|
|
||||||
|
azuremonitorCue, err := loadCueFileWithCommon(root, filepath.Join(root, "./public/app/plugins/datasource/azuremonitor/dataquery.cue"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
kinds = append(kinds, ComposableKind{
|
||||||
|
Name: "azuremonitor",
|
||||||
|
Filename: "dataquery.cue",
|
||||||
|
CueFile: azuremonitorCue,
|
||||||
|
})
|
||||||
|
|
||||||
|
googlecloudmonitoringCue, err := loadCueFileWithCommon(root, filepath.Join(root, "./public/app/plugins/datasource/cloud-monitoring/dataquery.cue"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
kinds = append(kinds, ComposableKind{
|
||||||
|
Name: "googlecloudmonitoring",
|
||||||
|
Filename: "dataquery.cue",
|
||||||
|
CueFile: googlecloudmonitoringCue,
|
||||||
|
})
|
||||||
|
|
||||||
|
cloudwatchCue, err := loadCueFileWithCommon(root, filepath.Join(root, "./public/app/plugins/datasource/cloudwatch/dataquery.cue"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
kinds = append(kinds, ComposableKind{
|
||||||
|
Name: "cloudwatch",
|
||||||
|
Filename: "dataquery.cue",
|
||||||
|
CueFile: cloudwatchCue,
|
||||||
|
})
|
||||||
|
|
||||||
|
elasticsearchCue, err := loadCueFileWithCommon(root, filepath.Join(root, "./public/app/plugins/datasource/elasticsearch/dataquery.cue"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
kinds = append(kinds, ComposableKind{
|
||||||
|
Name: "elasticsearch",
|
||||||
|
Filename: "dataquery.cue",
|
||||||
|
CueFile: elasticsearchCue,
|
||||||
|
})
|
||||||
|
|
||||||
|
grafanapyroscopeCue, err := loadCueFileWithCommon(root, filepath.Join(root, "./public/app/plugins/datasource/grafana-pyroscope-datasource/dataquery.cue"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
kinds = append(kinds, ComposableKind{
|
||||||
|
Name: "grafanapyroscope",
|
||||||
|
Filename: "dataquery.cue",
|
||||||
|
CueFile: grafanapyroscopeCue,
|
||||||
|
})
|
||||||
|
|
||||||
|
grafanatestdatadatasourceCue, err := loadCueFileWithCommon(root, filepath.Join(root, "./public/app/plugins/datasource/grafana-testdata-datasource/dataquery.cue"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
kinds = append(kinds, ComposableKind{
|
||||||
|
Name: "grafanatestdatadatasource",
|
||||||
|
Filename: "dataquery.cue",
|
||||||
|
CueFile: grafanatestdatadatasourceCue,
|
||||||
|
})
|
||||||
|
|
||||||
|
lokiCue, err := loadCueFileWithCommon(root, filepath.Join(root, "./public/app/plugins/datasource/loki/dataquery.cue"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
kinds = append(kinds, ComposableKind{
|
||||||
|
Name: "loki",
|
||||||
|
Filename: "dataquery.cue",
|
||||||
|
CueFile: lokiCue,
|
||||||
|
})
|
||||||
|
|
||||||
|
parcaCue, err := loadCueFileWithCommon(root, filepath.Join(root, "./public/app/plugins/datasource/parca/dataquery.cue"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
kinds = append(kinds, ComposableKind{
|
||||||
|
Name: "parca",
|
||||||
|
Filename: "dataquery.cue",
|
||||||
|
CueFile: parcaCue,
|
||||||
|
})
|
||||||
|
|
||||||
|
tempoCue, err := loadCueFileWithCommon(root, filepath.Join(root, "./public/app/plugins/datasource/tempo/dataquery.cue"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
kinds = append(kinds, ComposableKind{
|
||||||
|
Name: "tempo",
|
||||||
|
Filename: "dataquery.cue",
|
||||||
|
CueFile: tempoCue,
|
||||||
|
})
|
||||||
|
|
||||||
|
alertgroupsCue, err := loadCueFileWithCommon(root, filepath.Join(root, "./public/app/plugins/panel/alertGroups/panelcfg.cue"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
kinds = append(kinds, ComposableKind{
|
||||||
|
Name: "alertgroups",
|
||||||
|
Filename: "panelcfg.cue",
|
||||||
|
CueFile: alertgroupsCue,
|
||||||
|
})
|
||||||
|
|
||||||
|
annotationslistCue, err := loadCueFileWithCommon(root, filepath.Join(root, "./public/app/plugins/panel/annolist/panelcfg.cue"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
kinds = append(kinds, ComposableKind{
|
||||||
|
Name: "annotationslist",
|
||||||
|
Filename: "panelcfg.cue",
|
||||||
|
CueFile: annotationslistCue,
|
||||||
|
})
|
||||||
|
|
||||||
|
barchartCue, err := loadCueFileWithCommon(root, filepath.Join(root, "./public/app/plugins/panel/barchart/panelcfg.cue"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
kinds = append(kinds, ComposableKind{
|
||||||
|
Name: "barchart",
|
||||||
|
Filename: "panelcfg.cue",
|
||||||
|
CueFile: barchartCue,
|
||||||
|
})
|
||||||
|
|
||||||
|
bargaugeCue, err := loadCueFileWithCommon(root, filepath.Join(root, "./public/app/plugins/panel/bargauge/panelcfg.cue"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
kinds = append(kinds, ComposableKind{
|
||||||
|
Name: "bargauge",
|
||||||
|
Filename: "panelcfg.cue",
|
||||||
|
CueFile: bargaugeCue,
|
||||||
|
})
|
||||||
|
|
||||||
|
candlestickCue, err := loadCueFileWithCommon(root, filepath.Join(root, "./public/app/plugins/panel/candlestick/panelcfg.cue"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
kinds = append(kinds, ComposableKind{
|
||||||
|
Name: "candlestick",
|
||||||
|
Filename: "panelcfg.cue",
|
||||||
|
CueFile: candlestickCue,
|
||||||
|
})
|
||||||
|
|
||||||
|
canvasCue, err := loadCueFileWithCommon(root, filepath.Join(root, "./public/app/plugins/panel/canvas/panelcfg.cue"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
kinds = append(kinds, ComposableKind{
|
||||||
|
Name: "canvas",
|
||||||
|
Filename: "panelcfg.cue",
|
||||||
|
CueFile: canvasCue,
|
||||||
|
})
|
||||||
|
|
||||||
|
dashboardlistCue, err := loadCueFileWithCommon(root, filepath.Join(root, "./public/app/plugins/panel/dashlist/panelcfg.cue"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
kinds = append(kinds, ComposableKind{
|
||||||
|
Name: "dashboardlist",
|
||||||
|
Filename: "panelcfg.cue",
|
||||||
|
CueFile: dashboardlistCue,
|
||||||
|
})
|
||||||
|
|
||||||
|
datagridCue, err := loadCueFileWithCommon(root, filepath.Join(root, "./public/app/plugins/panel/datagrid/panelcfg.cue"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
kinds = append(kinds, ComposableKind{
|
||||||
|
Name: "datagrid",
|
||||||
|
Filename: "panelcfg.cue",
|
||||||
|
CueFile: datagridCue,
|
||||||
|
})
|
||||||
|
|
||||||
|
debugCue, err := loadCueFileWithCommon(root, filepath.Join(root, "./public/app/plugins/panel/debug/panelcfg.cue"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
kinds = append(kinds, ComposableKind{
|
||||||
|
Name: "debug",
|
||||||
|
Filename: "panelcfg.cue",
|
||||||
|
CueFile: debugCue,
|
||||||
|
})
|
||||||
|
|
||||||
|
gaugeCue, err := loadCueFileWithCommon(root, filepath.Join(root, "./public/app/plugins/panel/gauge/panelcfg.cue"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
kinds = append(kinds, ComposableKind{
|
||||||
|
Name: "gauge",
|
||||||
|
Filename: "panelcfg.cue",
|
||||||
|
CueFile: gaugeCue,
|
||||||
|
})
|
||||||
|
|
||||||
|
geomapCue, err := loadCueFileWithCommon(root, filepath.Join(root, "./public/app/plugins/panel/geomap/panelcfg.cue"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
kinds = append(kinds, ComposableKind{
|
||||||
|
Name: "geomap",
|
||||||
|
Filename: "panelcfg.cue",
|
||||||
|
CueFile: geomapCue,
|
||||||
|
})
|
||||||
|
|
||||||
|
heatmapCue, err := loadCueFileWithCommon(root, filepath.Join(root, "./public/app/plugins/panel/heatmap/panelcfg.cue"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
kinds = append(kinds, ComposableKind{
|
||||||
|
Name: "heatmap",
|
||||||
|
Filename: "panelcfg.cue",
|
||||||
|
CueFile: heatmapCue,
|
||||||
|
})
|
||||||
|
|
||||||
|
histogramCue, err := loadCueFileWithCommon(root, filepath.Join(root, "./public/app/plugins/panel/histogram/panelcfg.cue"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
kinds = append(kinds, ComposableKind{
|
||||||
|
Name: "histogram",
|
||||||
|
Filename: "panelcfg.cue",
|
||||||
|
CueFile: histogramCue,
|
||||||
|
})
|
||||||
|
|
||||||
|
logsCue, err := loadCueFileWithCommon(root, filepath.Join(root, "./public/app/plugins/panel/logs/panelcfg.cue"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
kinds = append(kinds, ComposableKind{
|
||||||
|
Name: "logs",
|
||||||
|
Filename: "panelcfg.cue",
|
||||||
|
CueFile: logsCue,
|
||||||
|
})
|
||||||
|
|
||||||
|
newsCue, err := loadCueFileWithCommon(root, filepath.Join(root, "./public/app/plugins/panel/news/panelcfg.cue"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
kinds = append(kinds, ComposableKind{
|
||||||
|
Name: "news",
|
||||||
|
Filename: "panelcfg.cue",
|
||||||
|
CueFile: newsCue,
|
||||||
|
})
|
||||||
|
|
||||||
|
nodegraphCue, err := loadCueFileWithCommon(root, filepath.Join(root, "./public/app/plugins/panel/nodeGraph/panelcfg.cue"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
kinds = append(kinds, ComposableKind{
|
||||||
|
Name: "nodegraph",
|
||||||
|
Filename: "panelcfg.cue",
|
||||||
|
CueFile: nodegraphCue,
|
||||||
|
})
|
||||||
|
|
||||||
|
piechartCue, err := loadCueFileWithCommon(root, filepath.Join(root, "./public/app/plugins/panel/piechart/panelcfg.cue"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
kinds = append(kinds, ComposableKind{
|
||||||
|
Name: "piechart",
|
||||||
|
Filename: "panelcfg.cue",
|
||||||
|
CueFile: piechartCue,
|
||||||
|
})
|
||||||
|
|
||||||
|
statCue, err := loadCueFileWithCommon(root, filepath.Join(root, "./public/app/plugins/panel/stat/panelcfg.cue"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
kinds = append(kinds, ComposableKind{
|
||||||
|
Name: "stat",
|
||||||
|
Filename: "panelcfg.cue",
|
||||||
|
CueFile: statCue,
|
||||||
|
})
|
||||||
|
|
||||||
|
statetimelineCue, err := loadCueFileWithCommon(root, filepath.Join(root, "./public/app/plugins/panel/state-timeline/panelcfg.cue"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
kinds = append(kinds, ComposableKind{
|
||||||
|
Name: "statetimeline",
|
||||||
|
Filename: "panelcfg.cue",
|
||||||
|
CueFile: statetimelineCue,
|
||||||
|
})
|
||||||
|
|
||||||
|
statushistoryCue, err := loadCueFileWithCommon(root, filepath.Join(root, "./public/app/plugins/panel/status-history/panelcfg.cue"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
kinds = append(kinds, ComposableKind{
|
||||||
|
Name: "statushistory",
|
||||||
|
Filename: "panelcfg.cue",
|
||||||
|
CueFile: statushistoryCue,
|
||||||
|
})
|
||||||
|
|
||||||
|
tableCue, err := loadCueFileWithCommon(root, filepath.Join(root, "./public/app/plugins/panel/table/panelcfg.cue"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
kinds = append(kinds, ComposableKind{
|
||||||
|
Name: "table",
|
||||||
|
Filename: "panelcfg.cue",
|
||||||
|
CueFile: tableCue,
|
||||||
|
})
|
||||||
|
|
||||||
|
textCue, err := loadCueFileWithCommon(root, filepath.Join(root, "./public/app/plugins/panel/text/panelcfg.cue"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
kinds = append(kinds, ComposableKind{
|
||||||
|
Name: "text",
|
||||||
|
Filename: "panelcfg.cue",
|
||||||
|
CueFile: textCue,
|
||||||
|
})
|
||||||
|
|
||||||
|
timeseriesCue, err := loadCueFileWithCommon(root, filepath.Join(root, "./public/app/plugins/panel/timeseries/panelcfg.cue"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
kinds = append(kinds, ComposableKind{
|
||||||
|
Name: "timeseries",
|
||||||
|
Filename: "panelcfg.cue",
|
||||||
|
CueFile: timeseriesCue,
|
||||||
|
})
|
||||||
|
|
||||||
|
trendCue, err := loadCueFileWithCommon(root, filepath.Join(root, "./public/app/plugins/panel/trend/panelcfg.cue"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
kinds = append(kinds, ComposableKind{
|
||||||
|
Name: "trend",
|
||||||
|
Filename: "panelcfg.cue",
|
||||||
|
CueFile: trendCue,
|
||||||
|
})
|
||||||
|
|
||||||
|
xychartCue, err := loadCueFileWithCommon(root, filepath.Join(root, "./public/app/plugins/panel/xychart/panelcfg.cue"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
kinds = append(kinds, ComposableKind{
|
||||||
|
Name: "xychart",
|
||||||
|
Filename: "panelcfg.cue",
|
||||||
|
CueFile: xychartCue,
|
||||||
|
})
|
||||||
|
|
||||||
|
return kinds, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadCueFileWithCommon(root string, entrypoint string) (cue.Value, error) {
|
||||||
|
commonFS, err := mockCommonFS(root)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("cannot load common cue files: %s\n", err)
|
||||||
|
return cue.Value{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
overlay, err := buildOverlay(commonFS)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Cannot build overlay: %s\n", err)
|
||||||
|
return cue.Value{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
bis := load.Instances([]string{entrypoint}, &load.Config{
|
||||||
|
ModuleRoot: "/",
|
||||||
|
Overlay: overlay,
|
||||||
|
})
|
||||||
|
|
||||||
|
values, err := cuecontext.New().BuildInstances(bis)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Cannot build instance: %s\n", err)
|
||||||
|
return cue.Value{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return values[0], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func mockCommonFS(root string) (fs.FS, error) {
|
||||||
|
path := filepath.Join(root, cueImportsPath)
|
||||||
|
dir, err := os.ReadDir(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("cannot open common cue files directory: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
prefix := "cue.mod/pkg/" + importPath
|
||||||
|
|
||||||
|
commonFS := fstest.MapFS{}
|
||||||
|
for _, d := range dir {
|
||||||
|
if d.IsDir() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
readPath := filepath.Join(path, d.Name())
|
||||||
|
b, err := os.ReadFile(filepath.Clean(readPath))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
commonFS[filepath.Join(prefix, d.Name())] = &fstest.MapFile{Data: b}
|
||||||
|
}
|
||||||
|
|
||||||
|
return commonFS, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// It loads common cue files into the schema to be able to make import works
|
||||||
|
func buildOverlay(commonFS fs.FS) (map[string]load.Source, error) {
|
||||||
|
overlay := make(map[string]load.Source)
|
||||||
|
|
||||||
|
err := fs.WalkDir(commonFS, ".", func(path string, d fs.DirEntry, err error) error {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.IsDir() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
f, err := commonFS.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer func() { _ = f.Close() }()
|
||||||
|
|
||||||
|
b, err := io.ReadAll(f)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
overlay[filepath.Join("/", path)] = load.FromBytes(b)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
return overlay, err
|
||||||
|
}
|
115
pkg/registry/schemas/core_kind.go
Normal file
115
pkg/registry/schemas/core_kind.go
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
// Code generated - EDITING IS FUTILE. DO NOT EDIT.
|
||||||
|
//
|
||||||
|
// Generated by:
|
||||||
|
// kinds/gen.go
|
||||||
|
// Using jennies:
|
||||||
|
// CoreRegistryJenny
|
||||||
|
//
|
||||||
|
// Run 'make gen-cue' from repository root to regenerate.
|
||||||
|
|
||||||
|
package schemas
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
|
|
||||||
|
"cuelang.org/go/cue"
|
||||||
|
"cuelang.org/go/cue/cuecontext"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CoreKind struct {
|
||||||
|
Name string
|
||||||
|
CueFile cue.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetCoreKinds() ([]CoreKind, error) {
|
||||||
|
ctx := cuecontext.New()
|
||||||
|
kinds := make([]CoreKind, 0)
|
||||||
|
|
||||||
|
_, caller, _, _ := runtime.Caller(0)
|
||||||
|
root := filepath.Join(caller, "../../../..")
|
||||||
|
|
||||||
|
accesspolicyCue, err := loadCueFile(ctx, filepath.Join(root, "./kinds/accesspolicy/access_policy_kind.cue"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
kinds = append(kinds, CoreKind{
|
||||||
|
Name: "accesspolicy",
|
||||||
|
CueFile: accesspolicyCue,
|
||||||
|
})
|
||||||
|
|
||||||
|
dashboardCue, err := loadCueFile(ctx, filepath.Join(root, "./kinds/dashboard/dashboard_kind.cue"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
kinds = append(kinds, CoreKind{
|
||||||
|
Name: "dashboard",
|
||||||
|
CueFile: dashboardCue,
|
||||||
|
})
|
||||||
|
|
||||||
|
librarypanelCue, err := loadCueFile(ctx, filepath.Join(root, "./kinds/librarypanel/librarypanel_kind.cue"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
kinds = append(kinds, CoreKind{
|
||||||
|
Name: "librarypanel",
|
||||||
|
CueFile: librarypanelCue,
|
||||||
|
})
|
||||||
|
|
||||||
|
preferencesCue, err := loadCueFile(ctx, filepath.Join(root, "./kinds/preferences/preferences_kind.cue"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
kinds = append(kinds, CoreKind{
|
||||||
|
Name: "preferences",
|
||||||
|
CueFile: preferencesCue,
|
||||||
|
})
|
||||||
|
|
||||||
|
publicdashboardCue, err := loadCueFile(ctx, filepath.Join(root, "./kinds/publicdashboard/public_dashboard_kind.cue"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
kinds = append(kinds, CoreKind{
|
||||||
|
Name: "publicdashboard",
|
||||||
|
CueFile: publicdashboardCue,
|
||||||
|
})
|
||||||
|
|
||||||
|
roleCue, err := loadCueFile(ctx, filepath.Join(root, "./kinds/role/role_kind.cue"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
kinds = append(kinds, CoreKind{
|
||||||
|
Name: "role",
|
||||||
|
CueFile: roleCue,
|
||||||
|
})
|
||||||
|
|
||||||
|
rolebindingCue, err := loadCueFile(ctx, filepath.Join(root, "./kinds/rolebinding/role_binding_kind.cue"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
kinds = append(kinds, CoreKind{
|
||||||
|
Name: "rolebinding",
|
||||||
|
CueFile: rolebindingCue,
|
||||||
|
})
|
||||||
|
|
||||||
|
teamCue, err := loadCueFile(ctx, filepath.Join(root, "./kinds/team/team_kind.cue"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
kinds = append(kinds, CoreKind{
|
||||||
|
Name: "team",
|
||||||
|
CueFile: teamCue,
|
||||||
|
})
|
||||||
|
|
||||||
|
return kinds, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadCueFile(ctx *cue.Context, path string) (cue.Value, error) {
|
||||||
|
cueFile, err := os.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
return cue.Value{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctx.CompileBytes(cueFile), nil
|
||||||
|
}
|
@ -8,11 +8,6 @@ package main
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/grafana/codejen"
|
"github.com/grafana/codejen"
|
||||||
corecodegen "github.com/grafana/grafana/pkg/codegen"
|
corecodegen "github.com/grafana/grafana/pkg/codegen"
|
||||||
"github.com/grafana/grafana/pkg/cuectx"
|
"github.com/grafana/grafana/pkg/cuectx"
|
||||||
@ -20,6 +15,11 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/plugins/pfs"
|
"github.com/grafana/grafana/pkg/plugins/pfs"
|
||||||
"github.com/grafana/kindsys"
|
"github.com/grafana/kindsys"
|
||||||
"github.com/grafana/thema"
|
"github.com/grafana/thema"
|
||||||
|
"io/fs"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
var skipPlugins = map[string]bool{
|
var skipPlugins = map[string]bool{
|
||||||
@ -47,7 +47,6 @@ func main() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
pluginKindGen.Append(
|
pluginKindGen.Append(
|
||||||
codegen.PluginTreeListJenny(),
|
|
||||||
codegen.PluginGoTypesJenny("pkg/tsdb"),
|
codegen.PluginGoTypesJenny("pkg/tsdb"),
|
||||||
codegen.PluginTSTypesJenny("public/app/plugins"),
|
codegen.PluginTSTypesJenny("public/app/plugins"),
|
||||||
)
|
)
|
||||||
@ -70,6 +69,15 @@ func main() {
|
|||||||
log.Fatalln(fmt.Errorf("error writing files to disk: %s", err))
|
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 _, set := os.LookupEnv("CODEGEN_VERIFY"); set {
|
||||||
if err = jfs.Verify(context.Background(), groot); err != nil {
|
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))
|
log.Fatal(fmt.Errorf("generated code is out of sync with inputs:\n%s\nrun `make gen-cue` to regenerate", err))
|
||||||
@ -105,3 +113,28 @@ func splitSchiffer(names []string) codejen.FileMapper {
|
|||||||
return f, nil
|
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)
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user