mirror of
https://github.com/grafana/grafana.git
synced 2025-02-11 16:15:42 -06:00
* Update thema to latest * Deal with s/Library/*Runtime/ * Commit new, working results of codegen * We like pointers now * Always take runtime arg for NewBase() * Sketchy handwavy pass at entity meta framework * Little nibbles * Update pkg/framework/coremodel/entityframework.cue Co-authored-by: Artur Wierzbicki <wierzbicki.artur.94@gmail.com> * Move file into new framework location * Introduce loaders, Go code * Complete rename to kind * Flesh out framework, add svg/dashboard examples * Cruft removal * Remove generated kind go files from gitignore * Refine maturity concept, add SlotKind * Update embed and go deps * Export PrefixWithGrafanaCUE * Make the loader actually work, holy crap * Many small tweaks to type.cue * Add Apache 2 licensing exceptions for kinds * Add new kinds dir, start of generator * Roll back to earlier oapi-codegen * Introduce new grafana-specific CUE loaders * Introduce new tidy code generators framework * Catch up kind framework with tinkering * Add slices for the generators * Add write/verify step to main generator * Many renames * Split up kind framework cue files * Use kind.Decl within generated kinds * Create kind.SomeDecl wrapper type to cache lineages * Better names again * Get one generated implemented, hopefully * Copy dashboard schema into new kind.cue * Small fixes to make the initial gen work * Put svg kind in its new home * Add generated Go dashboard type * More renames and cleanups * Add base kind registry and generator * Stop blacklisting *_gen.go files This is not the Go best practice, anyway. All we actually want to ignore for enterprise is generated wire files. * Change codegen output directories pkg/kind -> pkg/kinds pkg/registry/kindreg -> pkg/registry/corekind * Rename pkg/framework/kind to pkg/kindsys * Add core structured kind generator * Add plural and machine names to kind spec * Copy playlist over to kind system * Consolidate kindsys files * Add raw kind generator * Update CODEOWNERS for kind framework * Touch up comments a bit * More docs tweaks * Remove generated types to reduce noise for review * Split each generator into its own file * Rename Slot kind to Composable kind * Add handwavy types for customkind loading * Guard against init calls to framework loader * First pass at doc on extending the kind system * Improve attribute example in docs * Fix wire imports * Add basic TS types generator * Fix composable kind category def * No need for a separate file with generate directive * Catch dashboard schema up * Rename generator types to something saner and generic * Make version configurable in ts/go generators * Add CommonMeta to ease property access * Add kindsys prop indicating whether lineage is group * Put all kind categories back in a single file * Finish with kindsys group props * Refactor maturity progression per discussion - Replace "committed" with "merged" - All kindcats can use all maturity levels, at least for now * Convert ts veneer index generator to modular system * Move over to new jennywrites framework * Strip down old coremodel generator * Use public version of jennywrites * Pull latest thema * Commit generated Go types * Add header injection postprocessor * Move sdboyer/jennywrites to grafana/codejen * Tweak header output * Remove dashboard and playlist coremodels * Fix up backend dashboards devenv test * Fix TS import patterns to new gen filename * Update internal imports, remove coremodel registry * Fix compilation errors, wire generation * Export and replace the prefix dropper * More Go struct and field name changes * Last name fixes, hopefully * Fix lint errors * Last lint error Co-authored-by: Artur Wierzbicki <wierzbicki.artur.94@gmail.com>
151 lines
3.5 KiB
Go
151 lines
3.5 KiB
Go
package codegen
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"go/ast"
|
|
"go/format"
|
|
"go/parser"
|
|
"go/token"
|
|
"os"
|
|
"path/filepath"
|
|
"regexp"
|
|
"strings"
|
|
|
|
"golang.org/x/tools/go/ast/astutil"
|
|
"golang.org/x/tools/imports"
|
|
)
|
|
|
|
type genGoFile struct {
|
|
path string
|
|
walker astutil.ApplyFunc
|
|
in []byte
|
|
}
|
|
|
|
func postprocessGoFile(cfg genGoFile) ([]byte, error) {
|
|
fname := filepath.Base(cfg.path)
|
|
buf := new(bytes.Buffer)
|
|
fset := token.NewFileSet()
|
|
gf, err := parser.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 {
|
|
astutil.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 {
|
|
str string
|
|
base string
|
|
rxp *regexp.Regexp
|
|
rxpsuff *regexp.Regexp
|
|
}
|
|
|
|
// PrefixDropper returns an astutil.ApplyFunc that removes the provided prefix
|
|
// string when it appears as a leading sequence in type names, var names, and
|
|
// comments in a generated Go file.
|
|
func PrefixDropper(prefix string) astutil.ApplyFunc {
|
|
return (&prefixmod{
|
|
str: prefix,
|
|
rxpsuff: regexp.MustCompile(fmt.Sprintf(`%s([a-zA-Z_]+)`, prefix)),
|
|
rxp: regexp.MustCompile(fmt.Sprintf(`%s([\s.,;-])`, prefix)),
|
|
}).applyfunc
|
|
}
|
|
|
|
func depoint(e ast.Expr) ast.Expr {
|
|
if star, is := e.(*ast.StarExpr); is {
|
|
return star.X
|
|
}
|
|
return e
|
|
}
|
|
|
|
func (d prefixmod) applyfunc(c *astutil.Cursor) bool {
|
|
n := c.Node()
|
|
|
|
switch x := n.(type) {
|
|
case *ast.ValueSpec:
|
|
d.handleExpr(x.Type)
|
|
for _, id := range x.Names {
|
|
d.do(id)
|
|
}
|
|
case *ast.TypeSpec:
|
|
// Always do typespecs
|
|
d.do(x.Name)
|
|
case *ast.Field:
|
|
// Don't rename struct fields. We just want to rename type declarations, and
|
|
// field value specifications that reference those types.
|
|
d.handleExpr(x.Type)
|
|
|
|
case *ast.CommentGroup:
|
|
for _, c := range x.List {
|
|
c.Text = d.rxpsuff.ReplaceAllString(c.Text, "$1")
|
|
if d.base != "" {
|
|
c.Text = d.rxp.ReplaceAllString(c.Text, d.base+"$1")
|
|
}
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
func (d prefixmod) handleExpr(e ast.Expr) {
|
|
// Deref a StarExpr, if there is one
|
|
expr := depoint(e)
|
|
switch x := expr.(type) {
|
|
case *ast.Ident:
|
|
d.do(x)
|
|
case *ast.ArrayType:
|
|
if id, is := depoint(x.Elt).(*ast.Ident); is {
|
|
d.do(id)
|
|
}
|
|
case *ast.MapType:
|
|
if id, is := depoint(x.Key).(*ast.Ident); is {
|
|
d.do(id)
|
|
}
|
|
if id, is := depoint(x.Value).(*ast.Ident); is {
|
|
d.do(id)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (d prefixmod) do(n *ast.Ident) {
|
|
if n.Name != d.str {
|
|
n.Name = strings.TrimPrefix(n.Name, d.str)
|
|
} else if d.base != "" {
|
|
n.Name = d.base
|
|
}
|
|
}
|