github.com/crossplane/upjet@v1.3.0/pkg/pipeline/conversion_spoke.go (about) 1 // SPDX-FileCopyrightText: 2023 The Crossplane Authors <https://crossplane.io> 2 // 3 // SPDX-License-Identifier: Apache-2.0 4 5 package pipeline 6 7 import ( 8 "fmt" 9 "go/types" 10 "os" 11 "path/filepath" 12 "regexp" 13 "strings" 14 15 "github.com/muvaf/typewriter/pkg/wrapper" 16 "github.com/pkg/errors" 17 18 "github.com/crossplane/upjet/pkg/pipeline/templates" 19 ) 20 21 var ( 22 regexTypeFile = regexp.MustCompile(`zz_(.+)_types.go`) 23 ) 24 25 // NewConversionSpokeGenerator returns a new ConversionSpokeGenerator. 26 func NewConversionSpokeGenerator(pkg *types.Package, rootDir, group, version string) *ConversionSpokeGenerator { 27 return &ConversionSpokeGenerator{ 28 LocalDirectoryPath: filepath.Join(rootDir, "apis", strings.ToLower(strings.Split(group, ".")[0])), 29 LicenseHeaderPath: filepath.Join(rootDir, "hack", "boilerplate.go.txt"), 30 SpokeVersionsMap: make(map[string][]string), 31 pkg: pkg, 32 version: version, 33 } 34 } 35 36 // ConversionSpokeGenerator generates conversion methods implementing the 37 // conversion.Convertible interface on the CRD structs. 38 type ConversionSpokeGenerator struct { 39 LocalDirectoryPath string 40 LicenseHeaderPath string 41 SpokeVersionsMap map[string][]string 42 43 pkg *types.Package 44 version string 45 } 46 47 // Generate writes generated conversion.Convertible interface functions 48 func (cg *ConversionSpokeGenerator) Generate(cfgs []*terraformedInput) error { //nolint:gocyclo 49 entries, err := os.ReadDir(cg.LocalDirectoryPath) 50 if err != nil { 51 return errors.Wrapf(err, "cannot list the directory entries for the source folder %s while generating the conversion.Convertible interface functions", cg.LocalDirectoryPath) 52 } 53 54 for _, e := range entries { 55 if !e.IsDir() || e.Name() == cg.version { 56 // we skip spoke generation for the current version as the assumption is 57 // the current CRD version is the hub version. 58 continue 59 } 60 trFile := wrapper.NewFile(cg.pkg.Path(), cg.pkg.Name(), templates.ConversionSpokeTemplate, 61 wrapper.WithGenStatement(GenStatement), 62 wrapper.WithHeaderPath(cg.LicenseHeaderPath), 63 ) 64 filePath := filepath.Join(cg.LocalDirectoryPath, e.Name(), "zz_generated.conversion_spokes.go") 65 vars := map[string]any{ 66 "APIVersion": e.Name(), 67 } 68 69 var resources []map[string]any 70 versionDir := filepath.Join(cg.LocalDirectoryPath, e.Name()) 71 files, err := os.ReadDir(versionDir) 72 if err != nil { 73 return errors.Wrapf(err, "cannot list the directory entries for the source folder %s while looking for the generated types", versionDir) 74 } 75 for _, f := range files { 76 if f.IsDir() { 77 continue 78 } 79 m := regexTypeFile.FindStringSubmatch(f.Name()) 80 if len(m) < 2 { 81 continue 82 } 83 c := findKindTerraformedInput(cfgs, m[1]) 84 if c == nil { 85 // type may not be available in the new version => 86 // no conversion is possible. 87 continue 88 } 89 resources = append(resources, map[string]any{ 90 "CRD": map[string]string{ 91 "Kind": c.Kind, 92 }, 93 }) 94 sk := fmt.Sprintf("%s.%s", c.ShortGroup, c.Kind) 95 cg.SpokeVersionsMap[sk] = append(cg.SpokeVersionsMap[sk], filepath.Base(versionDir)) 96 } 97 98 vars["Resources"] = resources 99 if len(resources) == 0 { 100 continue 101 } 102 if err := trFile.Write(filePath, vars, os.ModePerm); err != nil { 103 return errors.Wrapf(err, "cannot write the generated conversion Hub functions file %s", filePath) 104 } 105 } 106 return nil 107 } 108 109 func findKindTerraformedInput(cfgs []*terraformedInput, name string) *terraformedInput { 110 for _, c := range cfgs { 111 if strings.EqualFold(name, c.Kind) { 112 return c 113 } 114 } 115 return nil 116 }