resolve.go 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  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/config"
  21. "github.com/bazelbuild/bazel-gazelle/label"
  22. "github.com/bazelbuild/bazel-gazelle/repo"
  23. "github.com/bazelbuild/bazel-gazelle/resolve"
  24. "github.com/bazelbuild/bazel-gazelle/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. pc := GetProtoConfig(c)
  31. prefix := rel
  32. if pc.stripImportPrefix != "" {
  33. prefix = strings.TrimPrefix(rel, pc.stripImportPrefix[1:])
  34. if rel == prefix {
  35. return nil
  36. }
  37. }
  38. if pc.importPrefix != "" {
  39. prefix = path.Join(pc.importPrefix, prefix)
  40. }
  41. for i, src := range srcs {
  42. imports[i] = resolve.ImportSpec{Lang: "proto", Imp: path.Join(prefix, src)}
  43. }
  44. return imports
  45. }
  46. func (_ *protoLang) Embeds(r *rule.Rule, from label.Label) []label.Label {
  47. return nil
  48. }
  49. func (_ *protoLang) Resolve(c *config.Config, ix *resolve.RuleIndex, rc *repo.RemoteCache, r *rule.Rule, importsRaw interface{}, from label.Label) {
  50. if importsRaw == nil {
  51. // may not be set in tests.
  52. return
  53. }
  54. imports := importsRaw.([]string)
  55. r.DelAttr("deps")
  56. depSet := make(map[string]bool)
  57. for _, imp := range imports {
  58. l, err := resolveProto(c, ix, r, imp, from)
  59. if err == skipImportError {
  60. continue
  61. } else if err != nil {
  62. log.Print(err)
  63. } else {
  64. l = l.Rel(from.Repo, from.Pkg)
  65. depSet[l.String()] = true
  66. }
  67. }
  68. if len(depSet) > 0 {
  69. deps := make([]string, 0, len(depSet))
  70. for dep := range depSet {
  71. deps = append(deps, dep)
  72. }
  73. sort.Strings(deps)
  74. r.SetAttr("deps", deps)
  75. }
  76. }
  77. var (
  78. skipImportError = errors.New("std import")
  79. notFoundError = errors.New("not found")
  80. )
  81. func resolveProto(c *config.Config, ix *resolve.RuleIndex, r *rule.Rule, imp string, from label.Label) (label.Label, error) {
  82. pc := GetProtoConfig(c)
  83. if !strings.HasSuffix(imp, ".proto") {
  84. return label.NoLabel, fmt.Errorf("can't import non-proto: %q", imp)
  85. }
  86. if l, ok := resolve.FindRuleWithOverride(c, resolve.ImportSpec{Imp: imp, Lang: "proto"}, "proto"); ok {
  87. return l, nil
  88. }
  89. if l, ok := knownImports[imp]; ok && pc.Mode.ShouldUseKnownImports() {
  90. if l.Equal(from) {
  91. return label.NoLabel, skipImportError
  92. } else {
  93. return l, nil
  94. }
  95. }
  96. if l, err := resolveWithIndex(ix, imp, from); err == nil || err == skipImportError {
  97. return l, err
  98. } else if err != notFoundError {
  99. return label.NoLabel, err
  100. }
  101. rel := path.Dir(imp)
  102. if rel == "." {
  103. rel = ""
  104. }
  105. name := RuleName(rel)
  106. return label.New("", rel, name), nil
  107. }
  108. func resolveWithIndex(ix *resolve.RuleIndex, imp string, from label.Label) (label.Label, error) {
  109. matches := ix.FindRulesByImport(resolve.ImportSpec{Lang: "proto", Imp: imp}, "proto")
  110. if len(matches) == 0 {
  111. return label.NoLabel, notFoundError
  112. }
  113. if len(matches) > 1 {
  114. 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)
  115. }
  116. if matches[0].IsSelfImport(from) {
  117. return label.NoLabel, skipImportError
  118. }
  119. return matches[0].Label, nil
  120. }