mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Schema: Refactor plugin code generation (#58901)
* wip * wip * almost there.. * wip - change so it can run. * treelist is working. * support CODEGEN_VERIFY env variable * use log.fatal * comment out old PluginTreeList code generation * cleanup * rename corelist package files * fix makefile * move pkg/codegen/pluggen.go to pkg/plugins/codegen * copy and refactor files to pkg/plugins/codegen * use pkg/plugins/codegen instead of pkg/codegen for core plugins code gen * remove unneeded files * remove unused code to resolve linting errors * adapters first hack * added flattener * add back ignore build tags to go generate file * cleaned up the code a bit. * seems to work, needs to do some refactoring of the GoTypesJenns and TSTypesJenny. * one more step, going to get upstream changes in this branch. * working but need to run import tmpl in jenny_schemapath to have the proper imports. * added header to generated files. * added missing jenny. * preventing plugins with multiple decls/schemas to insert multiple lines in corelist. * fixed so we use Slot type from kindsys to detect if its group. * adding a go jenny that only runs if the plugin has a backend. * added version object to generated ts. * generating the ts types with the same output as prior to this refactoring. * removed code that is replaced by the jenny pattern. * removed the go code that isn't used anymore. * removed some more unused code and renamed pluggen to util_ts * fixed linting issue. * removed unused vars. * use a jenny list postprocessor for header injection * moved decl and decl_parser to pfs. * removed the pre-pended header in the gotypes jenny since it is done in the postprocess. * moved decl to pfs. * removed unused template. Co-authored-by: Marcus Efraimsson <marcus.efraimsson@gmail.com>
This commit is contained in:
@@ -1,18 +1,22 @@
|
||||
//go:build ignore
|
||||
// +build ignore
|
||||
|
||||
//go:generate go run gen.go
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/grafana/grafana/pkg/codegen"
|
||||
"github.com/grafana/codejen"
|
||||
corecodegen "github.com/grafana/grafana/pkg/codegen"
|
||||
"github.com/grafana/grafana/pkg/cuectx"
|
||||
"github.com/grafana/grafana/pkg/plugins/codegen"
|
||||
"github.com/grafana/grafana/pkg/plugins/pfs"
|
||||
)
|
||||
|
||||
@@ -33,106 +37,55 @@ const sep = string(filepath.Separator)
|
||||
|
||||
func main() {
|
||||
if len(os.Args) > 1 {
|
||||
fmt.Fprintf(os.Stderr, "plugin thema code generator does not currently accept any arguments\n, got %q", os.Args)
|
||||
os.Exit(1)
|
||||
log.Fatal(fmt.Errorf("plugin thema code generator does not currently accept any arguments\n, got %q", os.Args))
|
||||
}
|
||||
|
||||
cwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "could not get working directory: %s", err)
|
||||
os.Exit(1)
|
||||
log.Fatal(fmt.Errorf("could not get working directory: %s", err))
|
||||
}
|
||||
grootp := strings.Split(cwd, sep)
|
||||
groot := filepath.Join(sep, filepath.Join(grootp[:len(grootp)-3]...))
|
||||
rt := cuectx.GrafanaThemaRuntime()
|
||||
|
||||
wd := codegen.NewWriteDiffer()
|
||||
lib := cuectx.GrafanaThemaRuntime()
|
||||
|
||||
type ptreepath struct {
|
||||
Path string
|
||||
Tree *codegen.PluginTree
|
||||
}
|
||||
var ptrees []codegen.TreeAndPath
|
||||
for _, typ := range []string{"datasource", "panel"} {
|
||||
dir := filepath.Join(cwd, typ)
|
||||
treeor, err := codegen.ExtractPluginTrees(os.DirFS(dir), lib)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "extracting plugin trees failed for %s: %s\n", dir, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
for name, option := range treeor {
|
||||
if skipPlugins[name] {
|
||||
continue
|
||||
}
|
||||
|
||||
if option.Tree != nil {
|
||||
ptrees = append(ptrees, codegen.TreeAndPath{
|
||||
Path: filepath.Join(typ, name),
|
||||
Tree: option.Tree,
|
||||
})
|
||||
} else if !errors.Is(option.Err, pfs.ErrNoRootFile) {
|
||||
fmt.Fprintf(os.Stderr, "error parsing plugin directory %s: %s\n", filepath.Join(dir, name), option.Err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure ptrees are sorted, so that visit order is deterministic. Otherwise
|
||||
// having multiple core plugins with errors can cause confusing error
|
||||
// flip-flopping
|
||||
sort.Slice(ptrees, func(i, j int) bool {
|
||||
return ptrees[i].Path < ptrees[j].Path
|
||||
pluginKindGen := codejen.JennyListWithNamer(func(d *pfs.PluginDecl) string {
|
||||
return d.PluginMeta.Id
|
||||
})
|
||||
|
||||
var wdm codegen.WriteDiffer
|
||||
for _, ptp := range ptrees {
|
||||
tfast, err := ptp.Tree.GenerateTypeScriptAST()
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "generating typescript failed for %s: %s\n", ptp.Path, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
// nil return if there was nothing to generate (no slot implementations)
|
||||
if tfast != nil {
|
||||
wd[filepath.Join(ptp.Path, "models.gen.ts")] = []byte(tfast.String())
|
||||
}
|
||||
pluginKindGen.Append(
|
||||
codegen.PluginTreeListJenny(),
|
||||
codegen.PluginGoTypesJenny("pkg/tsdb", adaptToPipeline(corecodegen.GoTypesJenny{})),
|
||||
codegen.PluginTSTypesJenny("public/app/plugins", adaptToPipeline(corecodegen.TSTypesJenny{})),
|
||||
)
|
||||
|
||||
relp, _ := filepath.Rel(groot, ptp.Path)
|
||||
wdm, err = ptp.Tree.GenerateGo(ptp.Path, codegen.GoGenConfig{
|
||||
Types: isDatasource(ptp.Tree),
|
||||
// TODO false until we decide on a consistent codegen format for core and external plugins
|
||||
ThemaBindings: false,
|
||||
DocPathPrefix: relp,
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "generating Go failed for %s: %s\n", ptp.Path, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
wd.Merge(wdm)
|
||||
}
|
||||
pluginKindGen.AddPostprocessors(corecodegen.SlashHeaderMapper("public/app/plugins/gen.go"))
|
||||
|
||||
wdm, err = codegen.GenPluginTreeList(ptrees, "github.com/grafana/grafana/public/app/plugins", filepath.Join(groot, "pkg", "plugins", "pfs", "corelist", "loadlist_gen.go"), false)
|
||||
declParser := pfs.NewDeclParser(rt, skipPlugins)
|
||||
decls, err := declParser.Parse(os.DirFS(cwd))
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "generating plugin loader registry failed: %s\n", err)
|
||||
os.Exit(1)
|
||||
log.Fatalln(fmt.Errorf("parsing plugins in dir failed %s: %s", cwd, err))
|
||||
}
|
||||
|
||||
jfs, err := pluginKindGen.GenerateFS(decls...)
|
||||
if err != nil {
|
||||
log.Fatalln(fmt.Errorf("error writing files to disk: %s", err))
|
||||
}
|
||||
wd.Merge(wdm)
|
||||
|
||||
if _, set := os.LookupEnv("CODEGEN_VERIFY"); set {
|
||||
err = wd.Verify()
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "generated code is out of sync with inputs:\n%s\nrun `make gen-cue` to regenerate\n\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
} else {
|
||||
err = wd.Write()
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "error while writing generated code to disk:\n%s\n", err)
|
||||
os.Exit(1)
|
||||
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))
|
||||
}
|
||||
} else if err = jfs.Write(context.Background(), groot); err != nil {
|
||||
log.Fatal(fmt.Errorf("error while writing generated code to disk:\n%s", err))
|
||||
}
|
||||
}
|
||||
|
||||
func isDatasource(pt *codegen.PluginTree) bool {
|
||||
return string((*pfs.Tree)(pt).RootPlugin().Meta().Type) == "datasource"
|
||||
func adaptToPipeline(j codejen.OneToOne[corecodegen.SchemaForGen]) codejen.OneToOne[*pfs.PluginDecl] {
|
||||
return codejen.AdaptOneToOne(j, func(pd *pfs.PluginDecl) corecodegen.SchemaForGen {
|
||||
return corecodegen.SchemaForGen{
|
||||
Name: pd.PluginMeta.Name,
|
||||
Schema: pd.Lineage.Latest(),
|
||||
IsGroup: pd.Slot.IsGroup(),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user