package container import ( "fmt" "os" "path/filepath" "strings" "github.com/bazelbuild/bazel-gazelle/language" "github.com/bazelbuild/bazel-gazelle/resolve" "github.com/bazelbuild/bazel-gazelle/rule" "github.com/bazelbuild/buildtools/build" "edge-infra.dev/hack/build/rules/gazelle/constants" ) const ( visibility = "visibility" visibilityPublic = "//visibility:public" ) func (c *Container) GenerateRules(args language.GenerateArgs) language.GenerateResult { gr := language.GenerateResult{ Gen: []*rule.Rule{}, Imports: []any{}, } files := []string{} for _, f := range args.RegularFiles { if strings.HasSuffix(f, ".bzl") { files = append(files, f) } } if len(files) == 0 { return language.GenerateResult{} } pushRules := []*rule.Rule{} pushImports := []resolve.ImportSpec{} var err error for _, file := range files { pushRules, pushImports, err = generateTPPushRulesFromFile(file, args, pushRules, pushImports) if err != nil { fmt.Println(fmt.Errorf("error generating rule: %w", err)) return language.GenerateResult{} } } containerImports := make([]interface{}, len(pushRules)) for i, importSpec := range pushImports { containerImports[i] = importSpec } gr.Gen = append(gr.Gen, pushRules...) gr.Imports = append(gr.Imports, containerImports...) return gr } func generateTPPushRulesFromFile(file string, args language.GenerateArgs, pushRules []*rule.Rule, importSpecs []resolve.ImportSpec) ([]*rule.Rule, []resolve.ImportSpec, error) { bzlBytes, err := os.ReadFile(filepath.Join(args.Dir, file)) if err != nil { return pushRules, importSpecs, fmt.Errorf("file %s found, but error reading: %w", file, err) } bazelFile, err := build.ParseBzl(file, bzlBytes) if err != nil { err = fmt.Errorf("file %s read, but error parsing to bzl file: %w", file, err) fmt.Println(err) return pushRules, importSpecs, err } tpDepRules := bazelFile.Rules(ThirdPartyContainerDepRuleName) if len(tpDepRules) == 0 { return pushRules, importSpecs, nil } bazelConsts := constants.BazelConstMap{} bazelConsts, err = constants.ResolveConstants(args, bazelFile, bazelConsts) if err != nil { return pushRules, importSpecs, fmt.Errorf("error parsing constants: %w", err) } for _, tpRule := range tpDepRules { pullName := constants.ResolveAttr(tpRule, "name", bazelConsts) pullName = strings.ReplaceAll(pullName, "-", "_") registry := constants.ResolveAttr(tpRule, "registry", bazelConsts) repository := constants.ResolveAttr(tpRule, "repository", bazelConsts) tag := constants.ResolveAttr(tpRule, "tag", bazelConsts) destinationRepo := constants.ResolveAttr(tpRule, "destination_repo", bazelConsts) var destinationImageName string if destinationRepo != "" { destinationImageName = destinationRepo } else { destinationImageName = repository if registry != "index.docker.io" { destinationImageName = fmt.Sprintf("%s/%s", registry, destinationImageName) } } name := fmt.Sprintf("%s_container_push", pullName) tpPushRule := rule.NewRule(ContainerPushRuleName, name) makeDefaults(tpPushRule) // take attrs from third_party_container_dep and set container_push attrs tpPushRule.SetAttr("name", name) tpPushRule.SetAttr("image_name", destinationImageName) tpPushRule.SetAttr("image", fmt.Sprintf("@%s//:%s", pullName, pullName)) tpPushRule.SetAttr("digest", fmt.Sprintf("@%s//:digest", pullName)) tpPushRule.SetAttr("repository_file", "//hack/build/rules/container:thirdparty-repo") tpPushRule.SetAttr("from_third_party", true) importSpec := toImportSpec(tpPushRule, args.File) // Optionals if tag != "" { tpPushRule.SetAttr("tag", tag) } pushRules = append(pushRules, tpPushRule) importSpecs = append(importSpecs, importSpec) } return pushRules, importSpecs, nil } func makeDefaults(r *rule.Rule) { r.SetAttr(visibility, []string{visibilityPublic}) }