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 }