resolve.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. /* Copyright 2018 The Bazel Authors. All rights reserved.
  2. Licensed under the Apache License, Version 2.0 (the "License");
  3. you may not use this file except in compliance with the License.
  4. You may obtain a copy of the License at
  5. http://www.apache.org/licenses/LICENSE-2.0
  6. Unless required by applicable law or agreed to in writing, software
  7. distributed under the License is distributed on an "AS IS" BASIS,
  8. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  9. See the License for the specific language governing permissions and
  10. limitations under the License.
  11. */
  12. package proto
  13. import (
  14. "errors"
  15. "fmt"
  16. "log"
  17. "path"
  18. "sort"
  19. "strings"
  20. "github.com/bazelbuild/bazel-gazelle/internal/config"
  21. "github.com/bazelbuild/bazel-gazelle/internal/label"
  22. "github.com/bazelbuild/bazel-gazelle/internal/repos"
  23. "github.com/bazelbuild/bazel-gazelle/internal/resolve"
  24. "github.com/bazelbuild/bazel-gazelle/internal/rule"
  25. )
  26. func (_ *protoLang) Imports(c *config.Config, r *rule.Rule, f *rule.File) []resolve.ImportSpec {
  27. rel := f.Pkg
  28. srcs := r.AttrStrings("srcs")
  29. imports := make([]resolve.ImportSpec, len(srcs))
  30. for i, src := range srcs {
  31. imports[i] = resolve.ImportSpec{Lang: "proto", Imp: path.Join(rel, src)}
  32. }
  33. return imports
  34. }
  35. func (_ *protoLang) Embeds(r *rule.Rule, from label.Label) []label.Label {
  36. return nil
  37. }
  38. func (_ *protoLang) Resolve(c *config.Config, ix *resolve.RuleIndex, rc *repos.RemoteCache, r *rule.Rule, from label.Label) {
  39. importsRaw := r.PrivateAttr(config.GazelleImportsKey)
  40. if importsRaw == nil {
  41. // may not be set in tests.
  42. return
  43. }
  44. imports := importsRaw.([]string)
  45. r.DelAttr("deps")
  46. depSet := make(map[string]bool)
  47. for _, imp := range imports {
  48. l, err := resolveProto(c, ix, r, imp, from)
  49. if err == skipImportError {
  50. continue
  51. } else if err != nil {
  52. log.Print(err)
  53. } else {
  54. l = l.Rel(from.Repo, from.Pkg)
  55. depSet[l.String()] = true
  56. }
  57. }
  58. if len(depSet) > 0 {
  59. deps := make([]string, 0, len(depSet))
  60. for dep := range depSet {
  61. deps = append(deps, dep)
  62. }
  63. sort.Strings(deps)
  64. r.SetAttr("deps", deps)
  65. }
  66. }
  67. var (
  68. skipImportError = errors.New("std import")
  69. notFoundError = errors.New("not found")
  70. )
  71. func resolveProto(c *config.Config, ix *resolve.RuleIndex, r *rule.Rule, imp string, from label.Label) (label.Label, error) {
  72. pc := GetProtoConfig(c)
  73. if !strings.HasSuffix(imp, ".proto") {
  74. return label.NoLabel, fmt.Errorf("can't import non-proto: %q", imp)
  75. }
  76. if l, ok := resolve.FindRuleWithOverride(c, resolve.ImportSpec{Imp: imp, Lang: "proto"}, "proto"); ok {
  77. return l, nil
  78. }
  79. if l, ok := knownImports[imp]; ok && pc.Mode.ShouldUseKnownImports() {
  80. if l.Equal(from) {
  81. return label.NoLabel, skipImportError
  82. } else {
  83. return l, nil
  84. }
  85. }
  86. if l, err := resolveWithIndex(ix, imp, from); err == nil || err == skipImportError {
  87. return l, err
  88. } else if err != notFoundError {
  89. return label.NoLabel, err
  90. }
  91. rel := path.Dir(imp)
  92. if rel == "." {
  93. rel = ""
  94. }
  95. name := RuleName(rel)
  96. return label.New("", rel, name), nil
  97. }
  98. func resolveWithIndex(ix *resolve.RuleIndex, imp string, from label.Label) (label.Label, error) {
  99. matches := ix.FindRulesByImport(resolve.ImportSpec{Lang: "proto", Imp: imp}, "proto")
  100. if len(matches) == 0 {
  101. return label.NoLabel, notFoundError
  102. }
  103. if len(matches) > 1 {
  104. 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)
  105. }
  106. if matches[0].IsSelfImport(from) {
  107. return label.NoLabel, skipImportError
  108. }
  109. return matches[0].Label, nil
  110. }