-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Replace "sandbox" main files by a unified CLI
- Loading branch information
Showing
14 changed files
with
345 additions
and
391 deletions.
There are no files selected for viewing
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
package generate | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"strings" | ||
|
||
"github.com/grafana/codejen" | ||
"github.com/grafana/cog/internal/ast" | ||
"github.com/grafana/cog/internal/jennies" | ||
"github.com/spf13/cobra" | ||
) | ||
|
||
type options struct { | ||
outputDir string | ||
entrypoints []string | ||
schemasType string | ||
|
||
// Cue-specific options | ||
cueImports []string | ||
} | ||
|
||
func (opts options) cueIncludeImports() ([]cueIncludeImport, error) { | ||
if len(opts.cueImports) == 0 { | ||
return nil, nil | ||
} | ||
|
||
imports := make([]cueIncludeImport, len(opts.cueImports)) | ||
for i, importDefinition := range opts.cueImports { | ||
parts := strings.Split(importDefinition, ":") | ||
if len(parts) != 2 { | ||
return nil, fmt.Errorf("'%s' is not a valid import definition", importDefinition) | ||
} | ||
|
||
imports[i].fsPath = parts[0] | ||
imports[i].importPath = parts[1] | ||
} | ||
|
||
return imports, nil | ||
} | ||
|
||
func Command() *cobra.Command { | ||
opts := options{} | ||
|
||
cmd := &cobra.Command{ | ||
Use: "generate", | ||
Short: "Generates code from schemas.", // TODO: better descriptions | ||
Long: `Generates code from schemas.`, | ||
RunE: func(cmd *cobra.Command, args []string) error { | ||
return doGenerate(opts) | ||
}, | ||
} | ||
|
||
cmd.Flags().StringVarP(&opts.schemasType, "loader", "l", "cue", "Schemas type.") // TODO: better usage text | ||
cmd.Flags().StringVarP(&opts.outputDir, "output", "o", "generated", "Output directory.") // TODO: better usage text | ||
cmd.Flags().StringArrayVarP(&opts.entrypoints, "input", "i", nil, "Schema.") // TODO: better usage text | ||
cmd.Flags().StringArrayVarP(&opts.cueImports, "include-cue-import", "I", nil, "Specify an additional library import directory. Format: [path]:[import]. Example: '../grafana/common-library:github.com/grafana/grafana/packages/grafana-schema/src/common") | ||
|
||
_ = cmd.MarkFlagRequired("input") | ||
_ = cmd.MarkFlagDirname("input") | ||
_ = cmd.MarkFlagDirname("output") | ||
|
||
return cmd | ||
} | ||
|
||
func doGenerate(opts options) error { | ||
loaders := map[string]func(opts options) ([]*ast.File, error){ | ||
"cue": cueLoader, | ||
"kindsys-core": kindsysCoreLoader, | ||
"kindsys-custom": kindsysCustomLoader, | ||
"jsonschema": jsonschemaLoader, | ||
} | ||
loader, ok := loaders[opts.schemasType] | ||
if !ok { | ||
return fmt.Errorf("no loader found for '%s'", opts.schemasType) | ||
} | ||
|
||
schemas, err := loader(opts) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
// Here begins the code generation setup | ||
targetsByLanguage := jennies.All() | ||
rootCodeJenFS := codejen.NewFS() | ||
|
||
for language, target := range targetsByLanguage { | ||
fmt.Printf("Running '%s' jennies...\n", language) | ||
|
||
var err error | ||
processedAsts := schemas | ||
|
||
for _, compilerPass := range target.CompilerPasses { | ||
processedAsts, err = compilerPass.Process(processedAsts) | ||
if err != nil { | ||
return err | ||
} | ||
} | ||
|
||
fs, err := target.Jennies.GenerateFS(processedAsts) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
err = rootCodeJenFS.Merge(fs) | ||
if err != nil { | ||
return err | ||
} | ||
} | ||
|
||
err = rootCodeJenFS.Write(context.Background(), opts.outputDir) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
package generate | ||
|
||
import ( | ||
"os" | ||
"path/filepath" | ||
|
||
"github.com/grafana/cog/internal/ast" | ||
"github.com/grafana/cog/internal/jsonschema" | ||
) | ||
|
||
func jsonschemaLoader(opts options) ([]*ast.File, error) { | ||
allSchemas := make([]*ast.File, 0, len(opts.entrypoints)) | ||
for _, entrypoint := range opts.entrypoints { | ||
pkg := filepath.Base(filepath.Dir(entrypoint)) | ||
|
||
reader, err := os.Open(entrypoint) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
schemaAst, err := jsonschema.GenerateAST(reader, jsonschema.Config{ | ||
Package: pkg, // TODO: extract from input schema/folder? | ||
}) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
allSchemas = append(allSchemas, schemaAst) | ||
} | ||
|
||
return allSchemas, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
package generate | ||
|
||
import ( | ||
"fmt" | ||
"path/filepath" | ||
|
||
"cuelang.org/go/cue" | ||
"cuelang.org/go/cue/cuecontext" | ||
"github.com/grafana/cog/internal/ast" | ||
"github.com/grafana/cog/internal/simplecue" | ||
"github.com/grafana/kindsys" | ||
"github.com/grafana/thema" | ||
) | ||
|
||
func kindsysCoreLoader(opts options) ([]*ast.File, error) { | ||
themaRuntime := thema.NewRuntime(cuecontext.New()) | ||
|
||
allSchemas := make([]*ast.File, 0, len(opts.entrypoints)) | ||
for _, entrypoint := range opts.entrypoints { | ||
pkg := filepath.Base(entrypoint) | ||
|
||
overlayFS, err := dirToPrefixedFS(entrypoint, "") | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
cueInstance, err := kindsys.BuildInstance(themaRuntime.Context(), ".", "kind", overlayFS) | ||
if err != nil { | ||
return nil, fmt.Errorf("could not load kindsys instance: %w", err) | ||
} | ||
|
||
props, err := kindsys.ToKindProps[kindsys.CoreProperties](cueInstance) | ||
if err != nil { | ||
return nil, fmt.Errorf("could not convert cue value to kindsys props: %w", err) | ||
} | ||
|
||
kindDefinition := kindsys.Def[kindsys.CoreProperties]{ | ||
V: cueInstance, | ||
Properties: props, | ||
} | ||
|
||
boundKind, err := kindsys.BindCore(themaRuntime, kindDefinition) | ||
if err != nil { | ||
return nil, fmt.Errorf("could not bind kind definition to kind: %w", err) | ||
} | ||
|
||
rawLatestSchemaAsCue := boundKind.Lineage().Latest().Underlying() | ||
latestSchemaAsCue := rawLatestSchemaAsCue.LookupPath(cue.MakePath(cue.Hid("_#schema", "github.com/grafana/thema"))) | ||
|
||
schemaAst, err := simplecue.GenerateAST(latestSchemaAsCue, simplecue.Config{ | ||
Package: pkg, // TODO: extract from input schema/folder? | ||
}) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
allSchemas = append(allSchemas, schemaAst) | ||
} | ||
|
||
return allSchemas, nil | ||
} |
Oops, something went wrong.