github.com/stackb/rules_proto@v0.0.0-20240221195024-5428336c51f1/pkg/language/protobuf/config.go (about)

     1  package protobuf
     2  
     3  import (
     4  	"flag"
     5  	"fmt"
     6  	"log"
     7  	"strings"
     8  
     9  	"github.com/bazelbuild/bazel-gazelle/config"
    10  	"github.com/bazelbuild/bazel-gazelle/label"
    11  	"github.com/bazelbuild/bazel-gazelle/rule"
    12  
    13  	"github.com/stackb/rules_proto/pkg/protoc"
    14  )
    15  
    16  // The following methods are implemented to satisfy the
    17  // https://pkg.go.dev/github.com/bazelbuild/bazel-gazelle/resolve?tab=doc#Resolver
    18  // interface, but are otherwise unused.
    19  func (pl *protobufLang) RegisterFlags(fs *flag.FlagSet, cmd string, c *config.Config) {
    20  	fs.StringVar(&pl.configFiles,
    21  		"proto_configs", "",
    22  		"optional config.yaml file(s) that provide preconfiguration")
    23  	fs.StringVar(&pl.importsInFiles,
    24  		"proto_imports_in", "",
    25  		"index files to parse and load symbols from")
    26  	fs.StringVar(&pl.importsOutFile,
    27  		"proto_imports_out", "",
    28  		"filename where index should be written")
    29  	fs.StringVar(&pl.repoName,
    30  		"proto_repo_name", "",
    31  		"external name of this repository")
    32  	fs.BoolVar(&pl.reresolveKnownProtoImports,
    33  		"reresolve_known_proto_imports", false,
    34  		"if true, re-resolve hardcoded proto_library deps on go_googleapis and com_google_protobuf from language/proto from the index")
    35  	fs.Var(&pl.starlarkRules,
    36  		"proto_rule",
    37  		"register custom starlark rule of the form `<file_name>%<rule_name>`")
    38  	fs.Var(&pl.starlarkPlugins,
    39  		"proto_plugin",
    40  		"register custom starlark plugin of the form `<file_name>%<plugin_name>`")
    41  
    42  	registerWellKnownProtos(protoc.GlobalResolver())
    43  }
    44  
    45  func (pl *protobufLang) CheckFlags(fs *flag.FlagSet, c *config.Config) error {
    46  	cfg := protoc.NewPackageConfig(c)
    47  	c.Exts[pl.name] = cfg
    48  
    49  	for _, starlarkPlugin := range pl.starlarkPlugins {
    50  		if err := protoc.RegisterStarlarkPlugin(c, starlarkPlugin); err != nil {
    51  			return err
    52  		}
    53  	}
    54  
    55  	for _, starlarkRule := range pl.starlarkRules {
    56  		if err := protoc.RegisterStarlarkRule(c, starlarkRule); err != nil {
    57  			return err
    58  		}
    59  	}
    60  
    61  	if pl.configFiles != "" {
    62  		for _, filename := range strings.Split(pl.configFiles, ",") {
    63  			if err := protoc.LoadYConfigFile(c, cfg, filename); err != nil {
    64  				return fmt.Errorf("loading -proto_configs %s: %w", filename, err)
    65  			}
    66  		}
    67  	}
    68  
    69  	if pl.importsInFiles != "" {
    70  		for _, filename := range strings.Split(pl.importsInFiles, ",") {
    71  			if err := protoc.GlobalResolver().LoadFile(filename); err != nil {
    72  				return fmt.Errorf("loading %s: %w", filename, err)
    73  			}
    74  		}
    75  	}
    76  
    77  	return nil
    78  }
    79  
    80  func (*protobufLang) KnownDirectives() []string {
    81  	return []string{
    82  		protoc.LanguageDirective,
    83  		protoc.PluginDirective,
    84  		protoc.RuleDirective,
    85  	}
    86  }
    87  
    88  // Configure implements config.Configurer
    89  func (pl *protobufLang) Configure(c *config.Config, rel string, f *rule.File) {
    90  	if rel == "" {
    91  		// if this is the root BUILD file, we are beginning the configuration
    92  		// sequence.  Perform the equivalent of writing relevant
    93  		// 'gazelle:resolve proto IMP LABEL` entries.
    94  		protoc.GlobalResolver().Install(c)
    95  
    96  		// some special handling for certain directives
    97  		if f != nil {
    98  			for _, d := range f.Directives {
    99  				switch d.Key {
   100  				case "prefix":
   101  					// encode the prefix in the resolver.  The name is not used, but
   102  					// the string 'go' is used to reflect the language of origin.
   103  					protoc.GlobalResolver().Provide("gazelle", "directive", "prefix", label.New("", d.Value, "go"))
   104  				}
   105  			}
   106  		}
   107  	}
   108  
   109  	if f == nil {
   110  		return
   111  	}
   112  
   113  	if err := pl.getOrCreatePackageConfig(c).ParseDirectives(rel, f.Directives); err != nil {
   114  		log.Fatalf("error while parsing rule directives in package %q: %v", rel, err)
   115  	}
   116  }
   117  
   118  // getOrCreatePackageConfig either inserts a new config into the map under the
   119  // language name or replaces it with a clone.
   120  func (pl *protobufLang) getOrCreatePackageConfig(config *config.Config) *protoc.PackageConfig {
   121  	var cfg *protoc.PackageConfig
   122  	if existingExt, ok := config.Exts[pl.name]; ok {
   123  		cfg = existingExt.(*protoc.PackageConfig).Clone()
   124  	} else {
   125  		cfg = protoc.NewPackageConfig(config)
   126  	}
   127  	config.Exts[pl.name] = cfg
   128  	return cfg
   129  }
   130  
   131  func registerWellKnownProtos(resolver protoc.ImportResolver) {
   132  	for k, v := range map[string]label.Label{
   133  		"google/protobuf/any.proto":             label.New("com_google_protobuf", "", "any_proto"),
   134  		"google/protobuf/api.proto":             label.New("com_google_protobuf", "", "api_proto"),
   135  		"google/protobuf/compiler/plugin.proto": label.New("com_google_protobuf", "", "compiler_plugin_proto"),
   136  		"google/protobuf/descriptor.proto":      label.New("com_google_protobuf", "", "descriptor_proto"),
   137  		"google/protobuf/duration.proto":        label.New("com_google_protobuf", "", "duration_proto"),
   138  		"google/protobuf/empty.proto":           label.New("com_google_protobuf", "", "empty_proto"),
   139  		"google/protobuf/field_mask.proto":      label.New("com_google_protobuf", "", "field_mask_proto"),
   140  		"google/protobuf/source_context.proto":  label.New("com_google_protobuf", "", "source_context_proto"),
   141  		"google/protobuf/struct.proto":          label.New("com_google_protobuf", "", "struct_proto"),
   142  		"google/protobuf/timestamp.proto":       label.New("com_google_protobuf", "", "timestamp_proto"),
   143  		"google/protobuf/type.proto":            label.New("com_google_protobuf", "", "type_proto"),
   144  		"google/protobuf/wrappers.proto":        label.New("com_google_protobuf", "", "wrappers_proto"),
   145  	} {
   146  		resolver.Provide("proto", "proto", k, v)
   147  	}
   148  }
   149  
   150  type arrayFlags []string
   151  
   152  func (i *arrayFlags) String() string {
   153  	return strings.Join(*i, ",")
   154  }
   155  
   156  func (i *arrayFlags) Set(value string) error {
   157  	*i = append(*i, value)
   158  	return nil
   159  }