github.com/stackb/rules_proto@v0.0.0-20240221195024-5428336c51f1/pkg/protoc/proto_compile.go (about)

     1  package protoc
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"sort"
     7  
     8  	"github.com/bazelbuild/bazel-gazelle/config"
     9  	"github.com/bazelbuild/bazel-gazelle/label"
    10  	"github.com/bazelbuild/bazel-gazelle/resolve"
    11  	"github.com/bazelbuild/bazel-gazelle/rule"
    12  )
    13  
    14  const (
    15  	// ProtoLibraryKey stores the ProtoLibrary implementation for a rule.
    16  	ProtoLibraryKey = "_proto_library"
    17  )
    18  
    19  func init() {
    20  	Rules().MustRegisterRule("stackb:rules_proto:proto_compile", &protoCompile{})
    21  }
    22  
    23  // protoCompile implements LanguageRule for the 'proto_compile' rule.
    24  type protoCompile struct{}
    25  
    26  // KindInfo implements part of the LanguageRule interface.
    27  func (s *protoCompile) KindInfo() rule.KindInfo {
    28  	return rule.KindInfo{
    29  		NonEmptyAttrs: map[string]bool{
    30  			"outputs": true,
    31  		},
    32  		MergeableAttrs: map[string]bool{
    33  			"outputs":         true,
    34  			"plugins":         true,
    35  			"output_mappings": true,
    36  			"options":         true,
    37  		},
    38  		SubstituteAttrs: map[string]bool{
    39  			"out": true,
    40  		},
    41  	}
    42  }
    43  
    44  // Name implements part of the LanguageRule interface.
    45  func (s *protoCompile) Name() string {
    46  	return "proto_compile"
    47  }
    48  
    49  // LoadInfo implements part of the LanguageRule interface.
    50  func (s *protoCompile) LoadInfo() rule.LoadInfo {
    51  	return rule.LoadInfo{
    52  		Name:    "@build_stack_rules_proto//rules:proto_compile.bzl",
    53  		Symbols: []string{"proto_compile"},
    54  	}
    55  }
    56  
    57  // ProvideRule implements part of the LanguageRule interface.
    58  func (s *protoCompile) ProvideRule(cfg *LanguageRuleConfig, config *ProtocConfiguration) RuleProvider {
    59  	if len(config.Outputs) == 0 {
    60  		return nil
    61  	}
    62  	return &protoCompileRule{
    63  		kind:            "proto_compile",
    64  		nameSuffix:      "compile",
    65  		outputsAttrName: "outputs",
    66  		config:          config,
    67  		ruleConfig:      cfg,
    68  	}
    69  }
    70  
    71  // protoCompile implements RuleProvider for the 'proto_compile' rule.
    72  type protoCompileRule struct {
    73  	kind            string
    74  	nameSuffix      string
    75  	outputsAttrName string
    76  	config          *ProtocConfiguration
    77  	ruleConfig      *LanguageRuleConfig
    78  }
    79  
    80  // Kind implements part of the ruleProvider interface.
    81  func (s *protoCompileRule) Kind() string {
    82  	return s.kind
    83  }
    84  
    85  // Name implements part of the ruleProvider interface.
    86  func (s *protoCompileRule) Name() string {
    87  	return fmt.Sprintf("%s_%s_%s", s.config.Library.BaseName(), s.config.Prefix, s.nameSuffix)
    88  }
    89  
    90  // Visibility provides visibility labels.
    91  func (s *protoCompileRule) Visibility() []string {
    92  	return s.ruleConfig.GetVisibility()
    93  }
    94  
    95  func (s *protoCompileRule) Outputs() []string {
    96  	outputs := s.config.Outputs
    97  	sort.Strings(outputs)
    98  	return outputs
    99  }
   100  
   101  // Rule implements part of the ruleProvider interface.
   102  func (s *protoCompileRule) Rule(otherGen ...*rule.Rule) *rule.Rule {
   103  	newRule := rule.NewRule(s.Kind(), s.Name())
   104  	outputs := s.Outputs()
   105  
   106  	newRule.SetAttr(s.outputsAttrName, outputs)
   107  	newRule.SetAttr("plugins", GetPluginLabels(s.config.Plugins))
   108  	newRule.SetAttr("proto", s.config.Library.Name())
   109  
   110  	if s.config.LanguageConfig.Protoc != "" {
   111  		newRule.SetAttr("protoc", s.config.LanguageConfig.Protoc)
   112  	}
   113  
   114  	if len(s.config.Mappings) > 0 {
   115  		mappings := make([]string, len(s.config.Mappings))
   116  		var i int
   117  		for k, v := range s.config.Mappings {
   118  			mappings[i] = k + "=" + v
   119  			i++
   120  		}
   121  		sort.Strings(mappings)
   122  		newRule.SetAttr("output_mappings", mappings)
   123  	}
   124  
   125  	outs := GetPluginOuts(s.config.Plugins)
   126  	if len(outs) > 0 {
   127  		newRule.SetAttr("outs", MakeStringDict(outs))
   128  	}
   129  
   130  	visibility := s.Visibility()
   131  	if len(visibility) > 0 {
   132  		newRule.SetAttr("visibility", visibility)
   133  	}
   134  
   135  	for _, name := range s.ruleConfig.GetAttrNames() {
   136  		vals := s.ruleConfig.GetAttr(name)
   137  		if len(vals) == 0 {
   138  			continue
   139  		}
   140  		switch name {
   141  		case "verbose":
   142  			val := vals[0]
   143  			if val == "True" || val == "true" {
   144  				newRule.SetAttr("verbose", true)
   145  			} else if val == "False" || val == "false" {
   146  				newRule.SetAttr("verbose", false)
   147  			} else {
   148  				log.Printf("bad attr 'verbose' value: %q", val)
   149  			}
   150  		default:
   151  			newRule.SetAttr(name, vals)
   152  		}
   153  	}
   154  
   155  	return newRule
   156  }
   157  
   158  // Imports implements part of the RuleProvider interface.
   159  func (s *protoCompileRule) Imports(c *config.Config, r *rule.Rule, file *rule.File) []resolve.ImportSpec {
   160  	return nil
   161  }
   162  
   163  // Resolve implements part of the RuleProvider interface.
   164  func (s *protoCompileRule) Resolve(c *config.Config, ix *resolve.RuleIndex, r *rule.Rule, imports []string, from label.Label) {
   165  	options := GetPluginOptions(s.config.Plugins, r, from)
   166  	if len(options) > 0 {
   167  		r.SetAttr("options", MakeStringListDict(options))
   168  	}
   169  }