From 3cc08a50d62fbd013729cf216407146889caafb3 Mon Sep 17 00:00:00 2001 From: Sebastian Widmer Date: Wed, 19 Jun 2024 13:35:37 +0200 Subject: [PATCH] Draft: automate exporting CV spec --- tools/importcvspec/importcvspec.go | 97 ++++++++++++++++++++++++++++++ tools/impt/impt_test.go | 48 +++++++++++++++ tools/toimp/toimp.go | 15 +++++ 3 files changed, 160 insertions(+) create mode 100644 tools/importcvspec/importcvspec.go create mode 100644 tools/impt/impt_test.go create mode 100644 tools/toimp/toimp.go diff --git a/tools/importcvspec/importcvspec.go b/tools/importcvspec/importcvspec.go new file mode 100644 index 0000000..4f48c4b --- /dev/null +++ b/tools/importcvspec/importcvspec.go @@ -0,0 +1,97 @@ +package main + +import ( + "fmt" + "go/ast" + "go/build" + "go/importer" + "go/parser" + "go/token" + "go/types" + "log" + + "golang.org/x/exp/maps" +) + +func main() { + fset := token.NewFileSet() + + pkg := parseWithTypes(fset) + fmt.Println("Package parsed and type checked", pkg.Name()) + + cvs := pkg.Scope().Lookup("ClusterVersionSpec") + if cvs == nil { + log.Fatal("ClusterVersionSpec not found") + } + fmt.Println("ClusterVersionSpec found") + fmt.Println(types.ObjectString(cvs, types.RelativeTo(pkg))) + str, ok := cvs.Type().Underlying().(*types.Struct) + if !ok { + log.Fatal("ClusterVersionSpec is not a struct") + } + + toExport := extractNamed([]types.Object{cvs}, str) + + fmt.Println("####################") + + for _, obj := range toExport { + fmt.Println(types.ObjectString(obj, types.RelativeTo(pkg))) + } + + fmt.Println("####################") + +} + +func extractNamed(toExport []types.Object, cvs types.Type) []types.Object { + switch t := cvs.(type) { + case *types.Named: + fmt.Println("Named type", t.Obj()) + toExport = append(toExport, t.Obj()) + toExport = extractNamed(toExport, t.Underlying()) + case *types.Basic: + case *types.Pointer: + toExport = extractNamed(toExport, t.Elem()) + case *types.Array: + toExport = extractNamed(toExport, t.Elem()) + case *types.Slice: + toExport = extractNamed(toExport, t.Elem()) + case *types.Map: + toExport = extractNamed(toExport, t.Key()) + toExport = extractNamed(toExport, t.Elem()) + case *types.Struct: + for i := 0; i < t.NumFields(); i++ { + field := t.Field(i) + fmt.Printf("%s (%T)\n", field.String(), field.Type()) + toExport = extractNamed(toExport, field.Type()) + } + default: + log.Fatalf("Type not yet supported %T", t) + } + return toExport +} + +func parseWithTypes(fset *token.FileSet) *types.Package { + imp, err := build.Import("github.com/openshift/api/config/v1", "", build.FindOnly) + if err != nil { + log.Fatal(err) + } + fmt.Println("Import from: ", imp.Dir) + rawPkgs, err := parser.ParseDir(fset, imp.Dir, nil, parser.SkipObjectResolution) + if err != nil { + log.Fatal(err) + } + rawPkg := rawPkgs["v1"] + info := types.Info{ + Types: make(map[ast.Expr]types.TypeAndValue), + Defs: make(map[*ast.Ident]types.Object), + Uses: make(map[*ast.Ident]types.Object), + } + conf := types.Config{ + Importer: importer.ForCompiler(fset, "source", nil), + } + pkg, err := conf.Check(imp.Dir, fset, maps.Values(rawPkg.Files), &info) + if err != nil { + log.Fatal(err) + } + return pkg +} diff --git a/tools/impt/impt_test.go b/tools/impt/impt_test.go new file mode 100644 index 0000000..9a5652d --- /dev/null +++ b/tools/impt/impt_test.go @@ -0,0 +1,48 @@ +package impt_test + +import ( + "fmt" + "go/ast" + "go/build" + "go/importer" + "go/parser" + "go/token" + "go/types" + "log" + "testing" + + "golang.org/x/exp/maps" +) + +func TestImport(t *testing.T) { + fset := token.NewFileSet() + pt := parseWithTypes(fset) + fmt.Println("Package parsed and type checked", pt.Name()) + fmt.Println("Package path", pt) +} + +func parseWithTypes(fset *token.FileSet) *types.Package { + imp, err := build.Import("github.com/appuio/openshift-upgrade-controller/tools/toimp", "", build.FindOnly) + if err != nil { + log.Fatal(err) + } + fmt.Println("Import from: ", imp.Dir) + rawPkgs, err := parser.ParseDir(fset, imp.Dir, nil, parser.SkipObjectResolution) + if err != nil { + log.Fatal(err) + } + rawPkg := rawPkgs["toimp"] + info := types.Info{ + Types: make(map[ast.Expr]types.TypeAndValue), + Defs: make(map[*ast.Ident]types.Object), + Uses: make(map[*ast.Ident]types.Object), + } + conf := types.Config{ + Importer: importer.ForCompiler(fset, "source", nil), + } + pkg, err := conf.Check(imp.Dir, fset, maps.Values(rawPkg.Files), &info) + if err != nil { + log.Fatal(err) + } + return pkg +} diff --git a/tools/toimp/toimp.go b/tools/toimp/toimp.go new file mode 100644 index 0000000..df35736 --- /dev/null +++ b/tools/toimp/toimp.go @@ -0,0 +1,15 @@ +package toimp + +import configv1 "github.com/openshift/api/config/v1" + +type ClusterID string + +type LocalSpec struct { + ClusterID ClusterID `json:"clusterID"` +} + +func Convert(ls LocalSpec) configv1.ClusterVersionSpec { + cvs := configv1.ClusterVersionSpec{} + cvs.ClusterID = configv1.ClusterID(ls.ClusterID) + return cvs +}