From 6a34c96eb0ec79244bd5f4ec59a4f8e2eb83c839 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Agn=C3=A8s=20Toulet?= <35176601+AgnesToulet@users.noreply.github.com> Date: Tue, 7 Mar 2023 10:01:57 +0100 Subject: [PATCH] Start local schema registry --- kinds/gen.go | 1 + pkg/codegen/jenny_schema_reg.go | 44 ++++++++++ scripts/kinds/schemaregistry.go | 150 ++++++++++++++++++++++++++++++++ 3 files changed, 195 insertions(+) create mode 100644 pkg/codegen/jenny_schema_reg.go create mode 100644 scripts/kinds/schemaregistry.go diff --git a/kinds/gen.go b/kinds/gen.go index a8dae5bb021..e93e92ffa50 100644 --- a/kinds/gen.go +++ b/kinds/gen.go @@ -46,6 +46,7 @@ func main() { codegen.YamlCRDJenny(kindsys.GoCoreKindParentPath), codegen.CRDKindRegistryJenny(filepath.Join("pkg", "registry", "corecrd")), codegen.DocsJenny(filepath.Join("docs", "sources", "developers", "kinds", "core")), + codegen.SchemaRegistryJenny(filepath.Join("pkg", "kindsys", "schemaregistry")), ) header := codegen.SlashHeaderMapper("kinds/gen.go") diff --git a/pkg/codegen/jenny_schema_reg.go b/pkg/codegen/jenny_schema_reg.go new file mode 100644 index 00000000000..d84ba0f0fb8 --- /dev/null +++ b/pkg/codegen/jenny_schema_reg.go @@ -0,0 +1,44 @@ +package codegen + +import ( + "path/filepath" + + "cuelang.org/go/cue" + "cuelang.org/go/cue/format" + "github.com/grafana/codejen" + "github.com/grafana/grafana/pkg/kindsys" +) + +// SchemaRegistryJenny generates lineage files into the "next" folder +// of the local schema registry. +func SchemaRegistryJenny(path string) OneToOne { + return &schemaregjenny{ + path: path, + } +} + +type schemaregjenny struct { + path string +} + +func (j *schemaregjenny) JennyName() string { + return "SchemaRegistryJenny" +} + +func (j *schemaregjenny) Generate(kind kindsys.Kind) (*codejen.File, error) { + node := kind.Lineage().Underlying().Syntax( + cue.All(), + cue.Definitions(true), + cue.Docs(true), + ) + + bytes, err := format.Node(node) + if err != nil { + return nil, err + } + + name := kind.Props().Common().MachineName + path := filepath.Join(j.path, "next", name+"_gen.cue") + + return codejen.NewFile(path, bytes, j), nil +} diff --git a/scripts/kinds/schemaregistry.go b/scripts/kinds/schemaregistry.go new file mode 100644 index 00000000000..6a1dd9b7f6b --- /dev/null +++ b/scripts/kinds/schemaregistry.go @@ -0,0 +1,150 @@ +package main + +import ( + "fmt" + "io" + "io/ioutil" + "os" + "path/filepath" + "regexp" + "strconv" + + "github.com/grafana/thema" + "github.com/grafana/thema/load" +) + +// TODO - change this +const SchemaRegistryPath = "./pkg/kindsys/schemaregistry" + +func main() { + version, ok := os.LookupEnv("GRAFANA_VERSION") + if !ok { + panic(fmt.Errorf("GRAFANA_VERSION environment variable is missing")) + } + + latestDir, err := findLatestDir(SchemaRegistryPath) + if err != nil { + panic(err) + } + + nextSchemas, err := ioutil.ReadDir(SchemaRegistryPath + "/next") + if err != nil { + panic(err) + } + + if latestDir == "" { + err = copySchemas(nextSchemas, filepath.Join(SchemaRegistryPath, version)) + if err != nil { + panic(err) + } + } + + for _, file := range nextSchemas { + // File is new - no need to compare with existing + if _, err := os.Stat(filepath.Join(SchemaRegistryPath, version, file.Name())); err != nil { + continue + } + + bytes, err := os.ReadFile(filepath.Join(SchemaRegistryPath, version, file.Name())) + if err != nil { + panic(err) + } + oldLin, err := load.LineageFromBytes(bytes) + if err != nil { + panic(err) + } + + bytes, err = os.ReadFile(filepath.Join(SchemaRegistryPath, "next", file.Name())) + if err != nil { + panic(err) + } + newLin, err := load.LineageFromBytes(bytes) + if err != nil { + panic(err) + } + + isAppendOnly := thema.IsAppendOnly(oldLin, newLin) + fmt.Println(isAppendOnly) + } +} + +func findLatestDir(path string) (string, error) { + re := regexp.MustCompile(`([0-9]+)\.([0-9]+)\.([0-9]+)`) + latestVersion := []uint64{0, 0, 0} + latestDir := "" + + files, err := ioutil.ReadDir(path) + if err != nil { + return "", err + } + + for _, file := range files { + if !file.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 +} + +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 copySchemas(files []os.FileInfo, dest string) error { + _, err := os.Stat(dest) + if err != nil { + if !os.IsNotExist(err) { + return err + } + + if err := os.Mkdir(dest, 0644); err != nil { + return err + } + } + + for _, file := range files { + in, err := os.Open(filepath.Join(SchemaRegistryPath, "next", file.Name())) + if err != nil { + return err + } + defer in.Close() + + out, err := os.Create(filepath.Join(dest, file.Name())) + if err != nil { + return err + } + defer func() { + cerr := out.Close() + if err == nil { + err = cerr + } + }() + + if _, err = io.Copy(out, in); err != nil { + return err + } + err = out.Sync() + } + + return nil +}