@@ -19,6 +19,7 @@ import (
1919 "errors"
2020 "fmt"
2121 "io/fs"
22+ "path/filepath"
2223
2324 "buf.build/go/app"
2425 "buf.build/go/app/appext"
@@ -28,52 +29,68 @@ import (
2829 "github.com/bufbuild/protoplugin"
2930)
3031
31- // GetModuleConfigForProtocPlugin gets ModuleConfigs for the protoc plugin implementations.
32+ // GetModuleConfigAndPluginConfigsForProtocPlugin gets the [bufmodule.ModuleConfig] and
33+ // [bufmodule.PluginConfig]s for the specified module for the protoc plugin implementations.
34+ //
35+ // The caller can provide overrides for plugin paths in the plugin configurations. The protoc
36+ // plugin implementations do not support remote plugins. Also, for use-cases such as Bazel,
37+ // access to local binaries might require an explicit path override. So, this allows callers
38+ // to pass a map of plugin name to local path to override the plugin configuration.
39+ //
40+ // We also return all check configs for the option [bufcheck.WithRelatedCheckConfigs] to
41+ // validate the plugin configs when running lint/breaking.
3242//
3343// This is the same in both plugins so we just pulled it out to a common spot.
34- func GetModuleConfigForProtocPlugin (
44+ func GetModuleConfigAndPluginConfigsForProtocPlugin (
3545 ctx context.Context ,
3646 configOverride string ,
3747 module string ,
38- ) (bufconfig.ModuleConfig , error ) {
48+ pluginPathOverrides map [string ]string ,
49+ ) (bufconfig.ModuleConfig , []bufconfig.PluginConfig , []bufconfig.CheckConfig , error ) {
3950 bufYAMLFile , err := bufcli .GetBufYAMLFileForDirPathOrOverride (
4051 ctx ,
4152 "." ,
4253 configOverride ,
4354 )
4455 if err != nil {
4556 if errors .Is (err , fs .ErrNotExist ) {
46- return bufconfig .DefaultModuleConfigV1 , nil
57+ // There are no plugin configs by default.
58+ return bufconfig .DefaultModuleConfigV2 , nil , []bufconfig.CheckConfig {bufconfig .DefaultLintConfigV2 , bufconfig .DefaultBreakingConfigV2 }, nil
4759 }
48- return nil , err
60+ return nil , nil , nil , err
4961 }
5062 if module == "" {
5163 module = "."
5264 }
65+ pluginConfigs , err := getPluginConfigsForPluginPathOverrides (bufYAMLFile .PluginConfigs (), pluginPathOverrides )
66+ if err != nil {
67+ return nil , nil , nil , err
68+ }
69+ var allCheckConfigs []bufconfig.CheckConfig
5370 // Multiple modules in a v2 workspace may have the same moduleDirPath.
5471 moduleConfigsFound := []bufconfig.ModuleConfig {}
5572 for _ , moduleConfig := range bufYAMLFile .ModuleConfigs () {
73+ allCheckConfigs = append (allCheckConfigs , moduleConfig .LintConfig (), moduleConfig .BreakingConfig ())
5674 // If we have a v1beta1 or v1 buf.yaml, dirPath will be ".". Using the ModuleConfig from
5775 // a v1beta1 or v1 buf.yaml file matches the pre-refactor behavior.
5876 //
5977 // If we have a v2 buf.yaml, users have to provide a module path or full name, otherwise
6078 // we can't deduce what ModuleConfig to use.
6179 if fullName := moduleConfig .FullName (); fullName != nil && fullName .String () == module {
62- // Can return here because BufYAMLFile guarantees that module full names are unique across
63- // its module configs.
64- return moduleConfig , nil
80+ moduleConfigsFound = append (moduleConfigsFound , moduleConfig )
81+ continue
6582 }
6683 if dirPath := moduleConfig .DirPath (); dirPath == module {
6784 moduleConfigsFound = append (moduleConfigsFound , moduleConfig )
6885 }
6986 }
7087 switch len (moduleConfigsFound ) {
7188 case 0 :
72- return nil , fmt .Errorf ("no module found for %q" , module )
89+ return nil , nil , nil , fmt .Errorf ("no module found for %q" , module )
7390 case 1 :
74- return moduleConfigsFound [0 ], nil
91+ return moduleConfigsFound [0 ], pluginConfigs , allCheckConfigs , nil
7592 default :
76- return nil , fmt .Errorf ("multiple modules found at %q, specify its full name as <remote/owner/module> instead" , module )
93+ return nil , nil , nil , fmt .Errorf ("multiple modules found at %q, specify its full name as <remote/owner/module> instead" , module )
7794 }
7895}
7996
@@ -136,3 +153,52 @@ func newAppContainerForPluginEnv(pluginEnv protoplugin.PluginEnv) (*appContainer
136153 ArgContainer : app .NewArgContainer (),
137154 }, nil
138155}
156+
157+ // This processes the plugin path overrides for the protoc plugin implementations. It does
158+ // the following:
159+ // - For each plugin config, it checks if a path override was configured
160+ // - If an override was found, then a new config override is created based on whether the
161+ // override is a WASM path.
162+ // - If no override was found, if the plugin config is a remote plugin, we return an error,
163+ // since remote plugins are not supported for protoc plugin implementations. Otherwise,
164+ // we use the plugin config as-is.
165+ func getPluginConfigsForPluginPathOverrides (
166+ pluginConfigs []bufconfig.PluginConfig ,
167+ pluginPathOverrides map [string ]string ,
168+ ) ([]bufconfig.PluginConfig , error ) {
169+ overridePluginConfigs := make ([]bufconfig.PluginConfig , len (pluginConfigs ))
170+ for i , pluginConfig := range pluginConfigs {
171+ if overridePath , ok := pluginPathOverrides [pluginConfig .Name ()]; ok {
172+ var overridePluginConfig bufconfig.PluginConfig
173+ var err error
174+ // Check if the override path is a WASM path, if so, treat as a local WASM plugin
175+ if filepath .Ext (overridePath ) == ".wasm" {
176+ overridePluginConfig , err = bufconfig .NewLocalWasmPluginConfig (
177+ overridePath ,
178+ pluginConfig .Options (),
179+ pluginConfig .Args (),
180+ )
181+ if err != nil {
182+ return nil , err
183+ }
184+ } else {
185+ // Otherwise, treat it as a non-WASM local plugin.
186+ overridePluginConfig , err = bufconfig .NewLocalPluginConfig (
187+ overridePath ,
188+ pluginConfig .Options (),
189+ pluginConfig .Args (),
190+ )
191+ if err != nil {
192+ return nil , err
193+ }
194+ }
195+ overridePluginConfigs [i ] = overridePluginConfig
196+ continue
197+ }
198+ if pluginConfig .Type () == bufconfig .PluginConfigTypeRemoteWasm {
199+ return nil , fmt .Errorf ("remote plugin %s cannot be run with protoc plugin" , pluginConfig .Name ())
200+ }
201+ overridePluginConfigs [i ] = pluginConfig
202+ }
203+ return overridePluginConfigs , nil
204+ }
0 commit comments