...

Source file src/edge-infra.dev/hack/build/rules/kustomize/gazelle/language/generate.go

Documentation: edge-infra.dev/hack/build/rules/kustomize/gazelle/language

     1  package kustomize
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"path/filepath"
     7  
     8  	"github.com/bazelbuild/bazel-gazelle/label"
     9  	"github.com/bazelbuild/bazel-gazelle/language"
    10  	"github.com/bazelbuild/bazel-gazelle/resolve"
    11  	"github.com/bazelbuild/bazel-gazelle/rule"
    12  	"gopkg.in/yaml.v3"
    13  	"sigs.k8s.io/kustomize/api/types"
    14  
    15  	container "edge-infra.dev/hack/build/rules/container/gazelle/language"
    16  )
    17  
    18  const (
    19  	visibility       = "visibility"
    20  	visibilityPublic = "//visibility:public"
    21  )
    22  
    23  var kustFileNames = map[string]interface{}{
    24  	"kustomization.yaml": nil,
    25  	"kustomization.yml":  nil,
    26  	"Kustomization":      nil,
    27  }
    28  
    29  // kustomizationRuleName takes a path and returns the directory name + kustomization language name
    30  // as a formatting string for a kustomization rule name
    31  func kustomizationRuleName(dir string, ruleFile *rule.File, otherGen []*rule.Rule) string {
    32  	// Determine name for our generated kustomization rule. If there is already
    33  	// a rule in the package or one will be generated with the same name as the
    34  	// package (eg //pkg/foo:foo), use an alternative name, "kustomization"
    35  	//
    36  	// We can use a constant name because there can only be one kustomization per
    37  	// package, or directory.
    38  	rName := filepath.Base(dir)
    39  	var fileRules []*rule.Rule
    40  	if ruleFile != nil {
    41  		fileRules = append(fileRules, ruleFile.Rules...)
    42  	}
    43  	for _, r := range append(fileRules, otherGen...) {
    44  		// Another non-kustomization rule is named after the package.
    45  		// Check the rule kind so we don't get tripped up on an existing rule we
    46  		// generated previously.
    47  		// TODO(aj185259): If this does happen, the toImportSpec will likely break
    48  		// since it's going to try to find the rule with the directory name
    49  		// but it should be "kustomization" instead
    50  		//
    51  		// An optional solution would be to refer to all kustomization
    52  		// rule names as "{dir}_kustomization" which I think I'm a fan of
    53  		if r.Name() == rName && r.Kind() != kustomizationLangName {
    54  			rName = kustomizationLangName
    55  		}
    56  	}
    57  	return rName
    58  }
    59  
    60  // toImportSpec takes a rel relative path to the current directory i.e. args.Rel
    61  // and dep which is a relative path to a dependency i.e. ../base
    62  // These are joined together and added as the Imp member of the resolve.ImportSpec
    63  // as well as the language name constant for the Lang.
    64  func toImportSpec(rel, dep string) resolve.ImportSpec {
    65  	return resolve.ImportSpec{Lang: kustomizationLangName, Imp: filepath.Join(rel, dep)}
    66  }
    67  
    68  // toRemoteSrc returns an absolute package path of the supplied src
    69  func toRemoteSrc(rel, dep string) string {
    70  	targetPath := filepath.Join(rel, dep)
    71  	l := label.New("", filepath.Dir(targetPath), filepath.Base(targetPath))
    72  	return l.String()
    73  }
    74  
    75  func (k *Kustomize) KnownDirectives() []string {
    76  	return []string{
    77  		"kustomize-prefix",
    78  	}
    79  }
    80  
    81  // GenerateRules for Kustomize implements the GenerateRules function for the Gazelle
    82  // Language interface
    83  func (k *Kustomize) GenerateRules(args language.GenerateArgs) language.GenerateResult {
    84  	gr := language.GenerateResult{
    85  		Gen:     []*rule.Rule{},
    86  		Imports: []any{},
    87  	}
    88  
    89  	// Detect Kustomization file and read it
    90  	file := ""
    91  	for _, f := range args.RegularFiles {
    92  		if _, found := kustFileNames[f]; found {
    93  			file = f
    94  		}
    95  	}
    96  	if file == "" {
    97  		return language.GenerateResult{}
    98  	}
    99  
   100  	yamlBytes, err := os.ReadFile(filepath.Join(args.Dir, file))
   101  	if err != nil {
   102  		fmt.Println("can't read file")
   103  		fmt.Println(err)
   104  		return language.GenerateResult{}
   105  	}
   106  
   107  	kcfg := &types.Kustomization{}
   108  	if err := yaml.Unmarshal(yamlBytes, kcfg); err != nil {
   109  		fmt.Println("can't unmarshal yaml")
   110  		fmt.Println(err)
   111  		return language.GenerateResult{}
   112  	}
   113  
   114  	rName := kustomizationRuleName(args.Dir, args.File, args.OtherGen)
   115  
   116  	// Create kustomization rule
   117  	r := rule.NewRule(kustomizationLangName, rName)
   118  
   119  	makeDefaults(r)
   120  
   121  	var (
   122  		srcs             []string
   123  		kustomizeImports []resolve.ImportSpec
   124  	)
   125  
   126  	// Resources
   127  	resSrcs, resImgs, resKustImps, err := GenerateResources(args, kcfg.Resources)
   128  	if err != nil {
   129  		return language.GenerateResult{}
   130  	}
   131  	srcs = append(srcs, resSrcs...)
   132  	kustomizeImports = append(kustomizeImports, resKustImps...)
   133  	// if images are generated, create a private attr to ensure mapping of images to this rule
   134  
   135  	// Patches
   136  	patchSrcs := GeneratePatches(args, kcfg.Patches)
   137  	srcs = append(srcs, patchSrcs...)
   138  
   139  	// PatchesStrategicMerge
   140  	psmSrcs, psmKustImps, err := GeneratePatchesStrategicMerge(args, kcfg.Patches)
   141  	if err != nil {
   142  		return language.GenerateResult{}
   143  	}
   144  	srcs = append(srcs, psmSrcs...)
   145  	kustomizeImports = append(kustomizeImports, psmKustImps...)
   146  
   147  	// Configurations
   148  	cfgSrcs := GenerateConfigurations(args, kcfg.Configurations)
   149  	srcs = append(srcs, cfgSrcs...)
   150  
   151  	// Components
   152  	compKustImps := GenerateComponents(args, kcfg.Components)
   153  	kustomizeImports = append(kustomizeImports, compKustImps...)
   154  
   155  	// Bases - Deprecated but covering our bases
   156  	baseSrcs, baseKustImps, err := GenerateBases(args, kcfg.Bases) //nolint: staticcheck
   157  	if err != nil {
   158  		return language.GenerateResult{}
   159  	}
   160  	srcs = append(srcs, baseSrcs...)
   161  	kustomizeImports = append(kustomizeImports, baseKustImps...)
   162  
   163  	// PatchsJson6902 - Deprecated but covering our bases
   164  	pjSrcs := GeneratePatchesJSON6902(args, kcfg.PatchesJson6902) //nolint: staticcheck
   165  	srcs = append(srcs, pjSrcs...)
   166  
   167  	// ConfigmapGenerator
   168  	cmgSrcs := GenerateConfigmapGenerators(args, kcfg.ConfigMapGenerator)
   169  	srcs = append(srcs, cmgSrcs...)
   170  
   171  	if len(srcs) > 0 {
   172  		r.SetAttr(srcsAttr, srcs)
   173  	}
   174  
   175  	r.SetAttr("kustomization_yaml", file)
   176  
   177  	// Create import for each image name found
   178  	for _, img := range resImgs {
   179  		kustomizeImports = append(kustomizeImports, resolve.ImportSpec{
   180  			Lang: container.ContainerLangName,
   181  			Imp:  img,
   182  		})
   183  	}
   184  
   185  	gr.Gen = append(gr.Gen, r)
   186  	gr.Imports = append(gr.Imports, kustomizeImports)
   187  
   188  	return gr
   189  }
   190  
   191  func makeDefaults(r *rule.Rule) {
   192  	r.SetAttr(visibility, []string{visibilityPublic})
   193  }
   194  

View as plain text