1 package container
2
3 import (
4 "fmt"
5 "os"
6 "path/filepath"
7 "strings"
8
9 "github.com/bazelbuild/bazel-gazelle/language"
10 "github.com/bazelbuild/bazel-gazelle/resolve"
11 "github.com/bazelbuild/bazel-gazelle/rule"
12 "github.com/bazelbuild/buildtools/build"
13
14 "edge-infra.dev/hack/build/rules/gazelle/constants"
15 )
16
17 const (
18 visibility = "visibility"
19 visibilityPublic = "//visibility:public"
20 )
21
22 func (c *Container) GenerateRules(args language.GenerateArgs) language.GenerateResult {
23 gr := language.GenerateResult{
24 Gen: []*rule.Rule{},
25 Imports: []any{},
26 }
27
28 files := []string{}
29 for _, f := range args.RegularFiles {
30 if strings.HasSuffix(f, ".bzl") {
31 files = append(files, f)
32 }
33 }
34
35 if len(files) == 0 {
36 return language.GenerateResult{}
37 }
38
39 pushRules := []*rule.Rule{}
40 pushImports := []resolve.ImportSpec{}
41 var err error
42 for _, file := range files {
43 pushRules, pushImports, err = generateTPPushRulesFromFile(file, args, pushRules, pushImports)
44 if err != nil {
45 fmt.Println(fmt.Errorf("error generating rule: %w", err))
46 return language.GenerateResult{}
47 }
48 }
49
50 containerImports := make([]interface{}, len(pushRules))
51 for i, importSpec := range pushImports {
52 containerImports[i] = importSpec
53 }
54
55 gr.Gen = append(gr.Gen, pushRules...)
56 gr.Imports = append(gr.Imports, containerImports...)
57
58 return gr
59 }
60
61 func generateTPPushRulesFromFile(file string, args language.GenerateArgs, pushRules []*rule.Rule, importSpecs []resolve.ImportSpec) ([]*rule.Rule, []resolve.ImportSpec, error) {
62 bzlBytes, err := os.ReadFile(filepath.Join(args.Dir, file))
63 if err != nil {
64 return pushRules, importSpecs, fmt.Errorf("file %s found, but error reading: %w", file, err)
65 }
66
67 bazelFile, err := build.ParseBzl(file, bzlBytes)
68 if err != nil {
69 err = fmt.Errorf("file %s read, but error parsing to bzl file: %w", file, err)
70 fmt.Println(err)
71 return pushRules, importSpecs, err
72 }
73
74 tpDepRules := bazelFile.Rules(ThirdPartyContainerDepRuleName)
75 if len(tpDepRules) == 0 {
76 return pushRules, importSpecs, nil
77 }
78
79 bazelConsts := constants.BazelConstMap{}
80 bazelConsts, err = constants.ResolveConstants(args, bazelFile, bazelConsts)
81 if err != nil {
82 return pushRules, importSpecs, fmt.Errorf("error parsing constants: %w", err)
83 }
84
85 for _, tpRule := range tpDepRules {
86 pullName := constants.ResolveAttr(tpRule, "name", bazelConsts)
87 pullName = strings.ReplaceAll(pullName, "-", "_")
88
89 registry := constants.ResolveAttr(tpRule, "registry", bazelConsts)
90 repository := constants.ResolveAttr(tpRule, "repository", bazelConsts)
91 tag := constants.ResolveAttr(tpRule, "tag", bazelConsts)
92
93 destinationRepo := constants.ResolveAttr(tpRule, "destination_repo", bazelConsts)
94 var destinationImageName string
95
96 if destinationRepo != "" {
97 destinationImageName = destinationRepo
98 } else {
99 destinationImageName = repository
100 if registry != "index.docker.io" {
101 destinationImageName = fmt.Sprintf("%s/%s", registry, destinationImageName)
102 }
103 }
104
105 name := fmt.Sprintf("%s_container_push", pullName)
106 tpPushRule := rule.NewRule(ContainerPushRuleName, name)
107
108 makeDefaults(tpPushRule)
109
110
111 tpPushRule.SetAttr("name", name)
112 tpPushRule.SetAttr("image_name", destinationImageName)
113 tpPushRule.SetAttr("image", fmt.Sprintf("@%s//:%s", pullName, pullName))
114 tpPushRule.SetAttr("digest", fmt.Sprintf("@%s//:digest", pullName))
115 tpPushRule.SetAttr("repository_file", "//hack/build/rules/container:thirdparty-repo")
116 tpPushRule.SetAttr("from_third_party", true)
117
118 importSpec := toImportSpec(tpPushRule, args.File)
119
120
121 if tag != "" {
122 tpPushRule.SetAttr("tag", tag)
123 }
124
125 pushRules = append(pushRules, tpPushRule)
126 importSpecs = append(importSpecs, importSpec)
127 }
128
129 return pushRules, importSpecs, nil
130 }
131
132 func makeDefaults(r *rule.Rule) {
133 r.SetAttr(visibility, []string{visibilityPublic})
134 }
135
View as plain text