1
15
16 package resolve
17
18 import (
19 "flag"
20 "log"
21 "regexp"
22 "strings"
23
24 "github.com/bazelbuild/bazel-gazelle/config"
25 "github.com/bazelbuild/bazel-gazelle/label"
26 "github.com/bazelbuild/bazel-gazelle/rule"
27 )
28
29
30
31
32
33 func FindRuleWithOverride(c *config.Config, imp ImportSpec, lang string) (label.Label, bool) {
34 rc := getResolveConfig(c)
35 if dep, ok := rc.findOverride(imp, lang); ok {
36 return dep, true
37 }
38 for i := len(rc.regexpOverrides) - 1; i >= 0; i-- {
39 o := rc.regexpOverrides[i]
40 if o.matches(imp, lang) {
41 return o.dep, true
42 }
43 }
44 return label.NoLabel, false
45 }
46
47 type overrideKey struct {
48 imp ImportSpec
49 lang string
50 }
51
52 type regexpOverrideSpec struct {
53 ImpLang string
54 ImpRegex *regexp.Regexp
55 lang string
56 dep label.Label
57 }
58
59 func (o regexpOverrideSpec) matches(imp ImportSpec, lang string) bool {
60 return imp.Lang == o.ImpLang &&
61 o.ImpRegex.MatchString(imp.Imp) &&
62 (o.lang == "" || o.lang == lang)
63 }
64
65 type resolveConfig struct {
66 overrides map[overrideKey]label.Label
67 regexpOverrides []regexpOverrideSpec
68 parent *resolveConfig
69 }
70
71
72
73
74 func newResolveConfig(parent *resolveConfig, newOverrides map[overrideKey]label.Label, regexpOverrides []regexpOverrideSpec) *resolveConfig {
75 if len(newOverrides) == 0 && len(regexpOverrides) == len(parent.regexpOverrides) {
76 return parent
77 }
78 return &resolveConfig{
79 overrides: newOverrides,
80 regexpOverrides: regexpOverrides,
81 parent: parent,
82 }
83 }
84
85
86
87
88 func (rc *resolveConfig) findOverride(imp ImportSpec, lang string) (label.Label, bool) {
89 key := overrideKey{imp: imp, lang: lang}
90 if dep, ok := rc.overrides[key]; ok {
91 return dep, ok
92 }
93 if rc.parent != nil {
94 return rc.parent.findOverride(imp, lang)
95 }
96 return label.NoLabel, false
97 }
98
99 const resolveName = "_resolve"
100
101 func getResolveConfig(c *config.Config) *resolveConfig {
102 return c.Exts[resolveName].(*resolveConfig)
103 }
104
105 type Configurer struct{}
106
107 func (*Configurer) RegisterFlags(fs *flag.FlagSet, cmd string, c *config.Config) {
108 c.Exts[resolveName] = &resolveConfig{}
109 }
110
111 func (*Configurer) CheckFlags(fs *flag.FlagSet, c *config.Config) error { return nil }
112
113 func (*Configurer) KnownDirectives() []string {
114 return []string{"resolve", "resolve_regexp"}
115 }
116
117 func (*Configurer) Configure(c *config.Config, rel string, f *rule.File) {
118 if f == nil || len(f.Directives) == 0 {
119 return
120 }
121
122 rc := getResolveConfig(c)
123 var newOverrides map[overrideKey]label.Label
124 regexpOverrides := rc.regexpOverrides[:len(rc.regexpOverrides):len(rc.regexpOverrides)]
125
126 for _, d := range f.Directives {
127 if d.Key == "resolve" {
128 parts := strings.Fields(d.Value)
129 key := overrideKey{}
130 var lbl string
131 if len(parts) == 3 {
132 key.imp.Lang = parts[0]
133 key.lang = parts[0]
134 key.imp.Imp = parts[1]
135 lbl = parts[2]
136 } else if len(parts) == 4 {
137 key.imp.Lang = parts[0]
138 key.lang = parts[1]
139 key.imp.Imp = parts[2]
140 lbl = parts[3]
141 } else {
142 log.Printf("could not parse directive: %s\n\texpected gazelle:resolve source-language [import-language] import-string label", d.Value)
143 continue
144 }
145 dep, err := label.Parse(lbl)
146 if err != nil {
147 log.Printf("gazelle:resolve %s: %v", d.Value, err)
148 continue
149 }
150 dep = dep.Abs("", rel)
151 if newOverrides == nil {
152 newOverrides = make(map[overrideKey]label.Label, len(f.Directives))
153 }
154 newOverrides[key] = dep
155 } else if d.Key == "resolve_regexp" {
156 parts := strings.Fields(d.Value)
157 o := regexpOverrideSpec{}
158 var lbl string
159 if len(parts) == 3 {
160 o.ImpLang = parts[0]
161 var err error
162 o.ImpRegex, err = regexp.Compile(parts[1])
163 if err != nil {
164 log.Printf("gazelle:resolve_regexp %s: %v", d.Value, err)
165 continue
166 }
167 lbl = parts[2]
168 } else if len(parts) == 4 {
169 o.ImpLang = parts[0]
170 o.lang = parts[1]
171 var err error
172 o.ImpRegex, err = regexp.Compile(parts[2])
173 if err != nil {
174 log.Printf("gazelle:resolve_regexp %s: %v", d.Value, err)
175 continue
176 }
177
178 lbl = parts[3]
179 } else {
180 log.Printf("could not parse directive: %s\n\texpected gazelle:resolve_regexp source-language [import-language] import-string-regex label", d.Value)
181 continue
182 }
183 var err error
184 o.dep, err = label.Parse(lbl)
185 if err != nil {
186 log.Printf("gazelle:resolve_regexp %s: %v", d.Value, err)
187 continue
188 }
189 o.dep = o.dep.Abs("", rel)
190 regexpOverrides = append(regexpOverrides, o)
191 }
192 }
193
194 c.Exts[resolveName] = newResolveConfig(rc, newOverrides, regexpOverrides)
195 }
196
View as plain text