1
15
16 package proto
17
18 import (
19 "errors"
20 "fmt"
21 "log"
22 "path"
23 "sort"
24 "strings"
25
26 "github.com/bazelbuild/bazel-gazelle/config"
27 "github.com/bazelbuild/bazel-gazelle/label"
28 "github.com/bazelbuild/bazel-gazelle/pathtools"
29 "github.com/bazelbuild/bazel-gazelle/repo"
30 "github.com/bazelbuild/bazel-gazelle/resolve"
31 "github.com/bazelbuild/bazel-gazelle/rule"
32 )
33
34 func (*protoLang) Imports(c *config.Config, r *rule.Rule, f *rule.File) []resolve.ImportSpec {
35 rel := f.Pkg
36 srcs := r.AttrStrings("srcs")
37 imports := make([]resolve.ImportSpec, len(srcs))
38 pc := GetProtoConfig(c)
39 prefix := rel
40 if stripImportPrefix := r.AttrString("strip_import_prefix"); stripImportPrefix != "" {
41
42
43
44
45
46
47
48
49
50
51
52
53 if strings.HasPrefix(stripImportPrefix, "/") {
54 prefix = pathtools.TrimPrefix(rel, stripImportPrefix[len("/"):])
55 } else {
56 prefix = pathtools.TrimPrefix(rel, path.Join(rel, pc.StripImportPrefix))
57 }
58 if rel == prefix {
59
60
61 return nil
62 }
63 }
64 if importPrefix := r.AttrString("import_prefix"); importPrefix != "" {
65 prefix = path.Join(importPrefix, prefix)
66 }
67 for i, src := range srcs {
68 imports[i] = resolve.ImportSpec{Lang: "proto", Imp: path.Join(prefix, src)}
69 }
70 return imports
71 }
72
73 func (*protoLang) Embeds(r *rule.Rule, from label.Label) []label.Label {
74 return nil
75 }
76
77 func (*protoLang) Resolve(c *config.Config, ix *resolve.RuleIndex, rc *repo.RemoteCache, r *rule.Rule, importsRaw interface{}, from label.Label) {
78 if importsRaw == nil {
79
80 return
81 }
82 imports := importsRaw.([]string)
83 r.DelAttr("deps")
84 depSet := make(map[string]bool)
85 for _, imp := range imports {
86 l, err := resolveProto(c, ix, r, imp, from)
87 if err == errSkipImport {
88 continue
89 } else if err != nil {
90 log.Print(err)
91 } else {
92 l = l.Rel(from.Repo, from.Pkg)
93 depSet[l.String()] = true
94 }
95 }
96 if len(depSet) > 0 {
97 deps := make([]string, 0, len(depSet))
98 for dep := range depSet {
99 deps = append(deps, dep)
100 }
101 sort.Strings(deps)
102 r.SetAttr("deps", deps)
103 }
104 }
105
106 var (
107 errSkipImport = errors.New("std import")
108 errNotFound = errors.New("not found")
109 )
110
111 func resolveProto(c *config.Config, ix *resolve.RuleIndex, r *rule.Rule, imp string, from label.Label) (label.Label, error) {
112 pc := GetProtoConfig(c)
113 if !strings.HasSuffix(imp, ".proto") {
114 return label.NoLabel, fmt.Errorf("can't import non-proto: %q", imp)
115 }
116
117 if l, ok := resolve.FindRuleWithOverride(c, resolve.ImportSpec{Imp: imp, Lang: "proto"}, "proto"); ok {
118 return l, nil
119 }
120
121 if l, ok := knownImports[imp]; ok && pc.Mode.ShouldUseKnownImports() {
122 if l.Equal(from) {
123 return label.NoLabel, errSkipImport
124 } else {
125 if workspaceName, isModule := bazelModuleRepos[l.Repo]; isModule {
126 apparentRepoName := c.ModuleToApparentName(l.Repo)
127 if apparentRepoName == "" {
128
129
130
131 l.Repo = workspaceName
132 } else {
133 l.Repo = apparentRepoName
134 }
135 }
136 return l, nil
137 }
138 }
139
140 if l, err := resolveWithIndex(c, ix, imp, from); err == nil || err == errSkipImport {
141 return l, err
142 } else if err != errNotFound {
143 return label.NoLabel, err
144 }
145
146 rel := path.Dir(imp)
147 if rel == "." {
148 rel = ""
149 }
150 name := RuleName(rel)
151 return label.New("", rel, name), nil
152 }
153
154 func resolveWithIndex(c *config.Config, ix *resolve.RuleIndex, imp string, from label.Label) (label.Label, error) {
155 matches := ix.FindRulesByImportWithConfig(c, resolve.ImportSpec{Lang: "proto", Imp: imp}, "proto")
156 if len(matches) == 0 {
157 return label.NoLabel, errNotFound
158 }
159 if len(matches) > 1 {
160 return label.NoLabel, fmt.Errorf("multiple rules (%s and %s) may be imported with %q from %s", matches[0].Label, matches[1].Label, imp, from)
161 }
162 if matches[0].IsSelfImport(from) {
163 return label.NoLabel, errSkipImport
164 }
165 return matches[0].Label, nil
166 }
167
168
169 func (*protoLang) CrossResolve(c *config.Config, ix *resolve.RuleIndex, imp resolve.ImportSpec, lang string) []resolve.FindResult {
170 if lang != "go" {
171 return nil
172 }
173 pc := GetProtoConfig(c)
174 if imp.Lang == "proto" && pc.Mode.ShouldUseKnownImports() {
175 if l, ok := knownProtoImports[imp.Imp]; ok {
176 return []resolve.FindResult{{Label: l}}
177 }
178 }
179 if imp.Lang == "go" && pc.Mode.ShouldUseKnownImports() {
180
181
182
183
184
185
186 switch imp.Imp {
187 case "github.com/golang/protobuf/proto":
188 return []resolve.FindResult{{Label: label.New("com_github_golang_protobuf", "proto", "go_default_library")}}
189 case "github.com/golang/protobuf/jsonpb":
190 return []resolve.FindResult{{Label: label.New("com_github_golang_protobuf", "jsonpb", "go_default_library_gen")}}
191 case "github.com/golang/protobuf/descriptor":
192 return []resolve.FindResult{{Label: label.New("com_github_golang_protobuf", "descriptor", "go_default_library_gen")}}
193 case "github.com/golang/protobuf/ptypes":
194 return []resolve.FindResult{{Label: label.New("com_github_golang_protobuf", "ptypes", "go_default_library_gen")}}
195 case "github.com/golang/protobuf/protoc-gen-go/generator":
196 return []resolve.FindResult{{Label: label.New("com_github_golang_protobuf", "protoc-gen-go/generator", "go_default_library_gen")}}
197 case "google.golang.org/grpc":
198 return []resolve.FindResult{{Label: label.New("org_golang_google_grpc", "", "go_default_library")}}
199 }
200 if l, ok := knownGoProtoImports[imp.Imp]; ok {
201 return []resolve.FindResult{{Label: l}}
202 }
203 }
204 return nil
205 }
206
View as plain text