Skip to content
Merged
Show file tree
Hide file tree
Changes from 46 commits
Commits
Show all changes
83 commits
Select commit Hold shift + click to select a range
7aab46c
Add exclude_options configuration for generation
emcfarlane Feb 5, 2025
e2608aa
Fix lint issues and file iter
emcfarlane Feb 7, 2025
d05d210
Use protoreflect for remapping
emcfarlane Feb 12, 2025
5940c75
Remap dependencies
emcfarlane Feb 12, 2025
f763966
Refactor for image filtering
emcfarlane Feb 14, 2025
4935430
Refactor for include and exclude of types
emcfarlane Feb 24, 2025
400f958
Fix handling of extensions
emcfarlane Feb 25, 2025
2a66cf2
Fix import types
emcfarlane Feb 25, 2025
2c4378d
Fix extension inclusions
emcfarlane Feb 25, 2025
a0b373e
Checkpoint
emcfarlane Feb 26, 2025
11a88a9
Refactor for transitive closure
emcfarlane Feb 27, 2025
99902e6
Cleanup testcase
emcfarlane Feb 27, 2025
b5b7daa
Cleanup
emcfarlane Feb 27, 2025
e2c5f8b
Fix import dropping for options
emcfarlane Feb 27, 2025
8e286f4
Fix build
emcfarlane Feb 27, 2025
cb5a8ee
Mutate in place
emcfarlane Feb 27, 2025
00ebe13
Add mutate in place option
emcfarlane Feb 27, 2025
20b720b
Update docs
emcfarlane Feb 28, 2025
3cec9b8
Fix generation per image
emcfarlane Mar 3, 2025
5997223
Cleanup
emcfarlane Mar 3, 2025
764626a
Cleanup
emcfarlane Mar 3, 2025
dc449ef
Remove gosec workarounds
emcfarlane Mar 3, 2025
90cc4a0
Cleanup
emcfarlane Mar 3, 2025
cffd97c
Remove pointers from trailing slice
emcfarlane Mar 4, 2025
b460387
Drop extension TODO
emcfarlane Mar 4, 2025
e531a7a
Add types and options for inputs and plugins
emcfarlane Mar 7, 2025
2a2017a
Sort key parts
emcfarlane Mar 10, 2025
49cf91c
Only exclusion of types
emcfarlane Mar 11, 2025
07ea2e0
Docs
emcfarlane Mar 11, 2025
c43b74e
Remove inclusion of extension restriction
emcfarlane Mar 11, 2025
347120a
Merge branch 'main' into ed/excludeOptions
emcfarlane Mar 11, 2025
d66e197
Add exclude-types flag
emcfarlane Mar 11, 2025
883527c
Add CHANGELOG
emcfarlane Mar 11, 2025
5decf0b
Add testcases
emcfarlane Mar 11, 2025
e07f2b7
Fix lint
emcfarlane Mar 11, 2025
a3f2055
Cleanup
emcfarlane Mar 11, 2025
b8ed6d7
Cleanup
emcfarlane Mar 11, 2025
cbfb29f
Cleanup
emcfarlane Mar 11, 2025
13c3882
Use slices.Backward
emcfarlane Mar 14, 2025
3124c00
Improve generator key
emcfarlane Mar 14, 2025
eaf49d2
Fix unused deps
emcfarlane Mar 17, 2025
59f5d78
Add unused deps testcase
emcfarlane Mar 17, 2025
07152c5
Fix changelog
emcfarlane Mar 17, 2025
bf07344
Merge branch 'main' into ed/excludeOptions
emcfarlane Mar 17, 2025
cd43600
Fix mutate in place source code locations
emcfarlane Mar 18, 2025
f291c2a
Update docs
emcfarlane Mar 18, 2025
e78e983
Fix name pluginConfigForKey
emcfarlane Mar 19, 2025
e39dddd
Fix pluginConfig ref for local job
emcfarlane Mar 19, 2025
56c5fda
Fix indexedPluginConfig consistency
emcfarlane Mar 19, 2025
9a80424
Update --exclude-types comment
emcfarlane Mar 19, 2025
60dbf41
Remove dead comment
emcfarlane Mar 19, 2025
a57873e
Clarify test comment
emcfarlane Mar 19, 2025
986a33f
Use IncludeTypes
emcfarlane Mar 19, 2025
e7de3e8
Clarify input config ExcludeType docs
emcfarlane Mar 19, 2025
d7849e1
Remove options == nil checks
emcfarlane Mar 19, 2025
62dc5d4
Move exclude set
emcfarlane Mar 19, 2025
4c75c24
Move TODO for globs
emcfarlane Mar 19, 2025
cd9d8a1
Improve excludeElement extendee check
emcfarlane Mar 19, 2025
219ff4b
Clarify hasOption on unknown types
emcfarlane Mar 19, 2025
c20a21c
Doc check is import used
emcfarlane Mar 19, 2025
9e8f745
TODO for better enclosing isDirty check
emcfarlane Mar 19, 2025
bc52487
Clarify input config docs for ExcludeTypes
emcfarlane Mar 19, 2025
7b12e98
Do TODO for enclosingType
emcfarlane Mar 19, 2025
5035d61
Simplify default check
emcfarlane Mar 19, 2025
12ce214
Fix include method but exclude input or output
emcfarlane Mar 20, 2025
f5cfcd5
Fix empty oneofs
emcfarlane Mar 20, 2025
01f7b09
Fix spacing
emcfarlane Mar 20, 2025
f5398e5
Cleanup
emcfarlane Mar 20, 2025
62b4402
Check extendee valid for extension inclusions
emcfarlane Mar 20, 2025
1696cca
Use IncludeTypes naming
emcfarlane Mar 20, 2025
584bde7
Use includeTypes names
emcfarlane Mar 20, 2025
1585379
Merge branch 'main' into ed/excludeOptions
emcfarlane Mar 25, 2025
304f0af
Set options as unrecognized bytes
emcfarlane Mar 25, 2025
698e350
Revert "Set options as unrecognized bytes"
emcfarlane Mar 25, 2025
d57a7d9
Move import check to closure
emcfarlane Mar 27, 2025
7b1f6bf
Fix docs
emcfarlane Mar 27, 2025
d327c23
Add range check
emcfarlane Mar 27, 2025
b4c1f56
Remove options remap
emcfarlane Mar 27, 2025
b6a92ee
Remap depencies to catch changes
emcfarlane Mar 28, 2025
412b940
Fix race on bufimage.NewImageForProto
emcfarlane Mar 28, 2025
c6b0e6a
Fix source paths remaps for deps
emcfarlane Mar 28, 2025
3c13e37
Format testdata
emcfarlane Mar 28, 2025
1c78fc9
Test consecutive fitlers
emcfarlane Mar 28, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 0 additions & 6 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -349,12 +349,6 @@ issues:
# from the fileDescriptor set, the operation should be safe.
path: private/bufpkg/bufprotosource/paths.go
text: "G115:"
- linters:
- gosec
# bufimageutil is handling images and converting loop indices to int32. Since it is
# parsing from an Image, the operation should be safe.
path: private/bufpkg/bufimage/bufimageutil/bufimageutil.go
text: "G115:"
- linters:
- gosec
# Bounds checks have been added with assertion statements to ensure safe int -> int32
Expand Down
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@

- Fix `buf convert` to allow for zero length for `binpb`, `txtpb`, and `yaml` formats.
- Fix use of deprecated flag `--include-types` for `buf generate`.
- Improve type filtering for `buf generate`. Adds the ability to exclude types with the parameter
`exclude_types` in `buf.gen.yaml` and a flag `--exclude-types` in the CLI.
Type filters may now also be specified as plugin parameters in `buf.gen.yaml`.

## [v1.50.1] - 2025-03-10

Expand Down
11 changes: 9 additions & 2 deletions private/buf/bufctl/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -1337,8 +1337,15 @@ func filterImage(
if functionOptions.imageExcludeImports {
newImage = bufimage.ImageWithoutImports(newImage)
}
if len(functionOptions.imageTypes) > 0 {
newImage, err = bufimageutil.ImageFilteredByTypes(newImage, functionOptions.imageTypes...)
includeTypes := functionOptions.imageTypes
excludeTypes := functionOptions.imageExcludeTypes
if len(includeTypes) > 0 || len(excludeTypes) > 0 {
newImage, err = bufimageutil.FilterImage(
newImage,
bufimageutil.WithIncludeTypes(includeTypes...),
bufimageutil.WithExcludeTypes(excludeTypes...),
bufimageutil.WithMutateInPlace(),
)
if err != nil {
return nil, err
}
Expand Down
7 changes: 7 additions & 0 deletions private/buf/bufctl/option.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,12 @@ func WithImageTypes(imageTypes []string) FunctionOption {
}
}

func WithImageExcludeTypes(imageExcludeTypes []string) FunctionOption {
return func(functionOptions *functionOptions) {
functionOptions.imageExcludeTypes = imageExcludeTypes
}
}

func WithImageAsFileDescriptorSet(imageAsFileDescriptorSet bool) FunctionOption {
return func(functionOptions *functionOptions) {
functionOptions.imageAsFileDescriptorSet = imageAsFileDescriptorSet
Expand Down Expand Up @@ -134,6 +140,7 @@ type functionOptions struct {
imageExcludeSourceInfo bool
imageExcludeImports bool
imageTypes []string
imageExcludeTypes []string
imageAsFileDescriptorSet bool
configOverride string
ignoreAndDisallowV1BufWorkYAMLs bool
Expand Down
173 changes: 103 additions & 70 deletions private/buf/bufgen/generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,14 @@ import (
"fmt"
"log/slog"
"path/filepath"
"sort"

connect "connectrpc.com/connect"
"github.com/bufbuild/buf/private/buf/bufprotopluginexec"
"github.com/bufbuild/buf/private/bufpkg/bufconfig"
"github.com/bufbuild/buf/private/bufpkg/bufimage"
"github.com/bufbuild/buf/private/bufpkg/bufimage/bufimagemodify"
"github.com/bufbuild/buf/private/bufpkg/bufimage/bufimageutil"
"github.com/bufbuild/buf/private/bufpkg/bufprotoplugin"
"github.com/bufbuild/buf/private/bufpkg/bufprotoplugin/bufprotopluginos"
"github.com/bufbuild/buf/private/bufpkg/bufremoteplugin"
Expand Down Expand Up @@ -204,72 +206,91 @@ func (g *generator) execPlugins(
includeImportsOverride *bool,
includeWellKnownTypesOverride *bool,
) ([]*pluginpb.CodeGeneratorResponse, error) {
imageProvider := newImageProvider(image)
// Collect all of the plugin jobs so that they can be executed in parallel.
jobs := make([]func(context.Context) error, 0, len(pluginConfigs))
responses := make([]*pluginpb.CodeGeneratorResponse, len(pluginConfigs))
requiredFeatures := computeRequiredFeatures(image)
remotePluginConfigTable := make(map[string][]*remotePluginExecArgs, len(pluginConfigs))
for i, pluginConfig := range pluginConfigs {
index := i
currentPluginConfig := pluginConfig
// We're using this as a proxy for Type() == PluginConfigTypeRemote.
//
// We should be using the enum here.
remote := currentPluginConfig.RemoteHost()
if remote != "" {
remotePluginConfigTable[remote] = append(
remotePluginConfigTable[remote],
&remotePluginExecArgs{
Index: index,
PluginConfig: currentPluginConfig,
},

// Group the pluginConfigs by similar properties to batch image processing.
pluginConfigsForImage := slicesext.ToIndexedValuesMap(pluginConfigs, createPluginConfigKeyForImage)
for _, indexedPluginConfigs := range pluginConfigsForImage {
image := image
hashPluginConfig := indexedPluginConfigs[0].Value
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This name is a little odd. I think you're just trying to recover the values in the key, except the key had to mangle the slices to make things comparable. So maybe naming it pluginConfigForKey would be more clear?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


// Apply per-plugin filters.
includeTypes := hashPluginConfig.Types()
excludeTypes := hashPluginConfig.ExcludeTypes()
if len(includeTypes) > 0 || len(excludeTypes) > 0 {
var err error
image, err = bufimageutil.FilterImage(
image,
bufimageutil.WithIncludeTypes(includeTypes...),
bufimageutil.WithExcludeTypes(excludeTypes...),
)
} else {
if err != nil {
return nil, err
}
}

// Batch for each remote.
if remote := hashPluginConfig.RemoteHost(); remote != "" {
jobs = append(jobs, func(ctx context.Context) error {
includeImports := currentPluginConfig.IncludeImports()
if includeImportsOverride != nil {
includeImports = *includeImportsOverride
}
includeWellKnownTypes := currentPluginConfig.IncludeWKT()
if includeWellKnownTypesOverride != nil {
includeWellKnownTypes = *includeWellKnownTypesOverride
}
response, err := g.execLocalPlugin(
results, err := g.execRemotePluginsV2(
ctx,
container,
imageProvider,
currentPluginConfig,
includeImports,
includeWellKnownTypes,
image,
remote,
indexedPluginConfigs,
includeImportsOverride,
includeWellKnownTypesOverride,
)
if err != nil {
return err
}
responses[index] = response
for _, result := range results {
responses[result.Index] = result.Value
}
return nil
})
continue
}
}
// Batch for each remote.
for remote, indexedPluginConfigs := range remotePluginConfigTable {
if len(indexedPluginConfigs) > 0 {

// Local plugins.
var images []bufimage.Image
switch Strategy(hashPluginConfig.Strategy()) {
case StrategyAll:
images = []bufimage.Image{image}
case StrategyDirectory:
var err error
images, err = bufimage.ImageByDir(image)
if err != nil {
return nil, err
}
default:
return nil, fmt.Errorf("unknown strategy: %v", hashPluginConfig.Strategy())
}
for _, indexedPluginConfig := range indexedPluginConfigs {
jobs = append(jobs, func(ctx context.Context) error {
results, err := g.execRemotePluginsV2(
includeImports := hashPluginConfig.IncludeImports()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this using hashPluginConfig? This flag is not part of the key, so why then would the first plugin config for the key be relevant here? I suspect maybe you instead want:

Suggested change
includeImports := hashPluginConfig.IncludeImports()
includeImports := indexedPluginConfig.Value.IncludeImports()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done e39dddd

if includeImportsOverride != nil {
includeImports = *includeImportsOverride
}
includeWellKnownTypes := hashPluginConfig.IncludeWKT()
if includeWellKnownTypesOverride != nil {
includeWellKnownTypes = *includeWellKnownTypesOverride
}
response, err := g.execLocalPlugin(
ctx,
container,
image,
remote,
indexedPluginConfigs,
includeImportsOverride,
includeWellKnownTypesOverride,
images,
indexedPluginConfig.Value,
includeImports,
includeWellKnownTypes,
)
if err != nil {
return err
}
for _, result := range results {
responses[result.Index] = result.CodeGeneratorResponse
}
responses[indexedPluginConfig.Index] = response
return nil
})
}
Expand Down Expand Up @@ -305,15 +326,11 @@ func (g *generator) execPlugins(
func (g *generator) execLocalPlugin(
ctx context.Context,
container app.EnvStdioContainer,
imageProvider *imageProvider,
pluginImages []bufimage.Image,
pluginConfig bufconfig.GeneratePluginConfig,
includeImports bool,
includeWellKnownTypes bool,
) (*pluginpb.CodeGeneratorResponse, error) {
pluginImages, err := imageProvider.GetImages(Strategy(pluginConfig.Strategy()))
if err != nil {
return nil, err
}
requests, err := bufimage.ImagesToCodeGeneratorRequests(
pluginImages,
pluginConfig.Opt(),
Expand All @@ -338,37 +355,27 @@ func (g *generator) execLocalPlugin(
return response, nil
}

type remotePluginExecArgs struct {
Index int
PluginConfig bufconfig.GeneratePluginConfig
}

type remotePluginExecutionResult struct {
CodeGeneratorResponse *pluginpb.CodeGeneratorResponse
Index int
}

func (g *generator) execRemotePluginsV2(
ctx context.Context,
container app.EnvStdioContainer,
image bufimage.Image,
remote string,
pluginConfigs []*remotePluginExecArgs,
indexedPluginConfigs []slicesext.Indexed[bufconfig.GeneratePluginConfig],
includeImportsOverride *bool,
includeWellKnownTypesOverride *bool,
) ([]*remotePluginExecutionResult, error) {
requests := make([]*registryv1alpha1.PluginGenerationRequest, len(pluginConfigs))
for i, pluginConfig := range pluginConfigs {
includeImports := pluginConfig.PluginConfig.IncludeImports()
) ([]slicesext.Indexed[*pluginpb.CodeGeneratorResponse], error) {
requests := make([]*registryv1alpha1.PluginGenerationRequest, len(indexedPluginConfigs))
for i, pluginConfig := range indexedPluginConfigs {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Above, the loop variable was named indexedPluginConfig. Maybe use the same name here, for consistency?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

includeImports := pluginConfig.Value.IncludeImports()
if includeImportsOverride != nil {
includeImports = *includeImportsOverride
}
includeWellKnownTypes := pluginConfig.PluginConfig.IncludeWKT()
includeWellKnownTypes := pluginConfig.Value.IncludeWKT()
if includeWellKnownTypesOverride != nil {
includeWellKnownTypes = *includeWellKnownTypesOverride
}
request, err := getPluginGenerationRequest(
pluginConfig.PluginConfig,
pluginConfig.Value,
includeImports,
includeWellKnownTypes,
)
Expand Down Expand Up @@ -398,15 +405,15 @@ func (g *generator) execRemotePluginsV2(
if len(responses) != len(requests) {
return nil, fmt.Errorf("unexpected number of responses received, got %d, wanted %d", len(responses), len(requests))
}
result := make([]*remotePluginExecutionResult, 0, len(responses))
result := make([]slicesext.Indexed[*pluginpb.CodeGeneratorResponse], 0, len(responses))
for i := range requests {
codeGeneratorResponse := responses[i].GetResponse()
if codeGeneratorResponse == nil {
return nil, errors.New("expected code generator response")
}
result = append(result, &remotePluginExecutionResult{
CodeGeneratorResponse: codeGeneratorResponse,
Index: pluginConfigs[i].Index,
result = append(result, slicesext.Indexed[*pluginpb.CodeGeneratorResponse]{
Value: codeGeneratorResponse,
Index: indexedPluginConfigs[i].Index,
})
}
return result, nil
Expand Down Expand Up @@ -482,3 +489,29 @@ type generateOptions struct {
func newGenerateOptions() *generateOptions {
return &generateOptions{}
}

type pluginConfigKeyForImage struct {
includeTypes string // string representation of []string
excludeTypes string // string representation of []string
strategy Strategy
remoteHost string
}

// createPluginConfigKeyForImage returns a key of the plugin config with
// a subset of properties. This is used to batch plugins that have similar
// configuration. The key is based on the following properties:
// - Types
// - ExcludeTypes
// - Strategy
// - RemoteHost
func createPluginConfigKeyForImage(pluginConfig bufconfig.GeneratePluginConfig) pluginConfigKeyForImage {
// Sort the types and excludeTypes so that the key is deterministic.
sort.Strings(pluginConfig.Types())
sort.Strings(pluginConfig.ExcludeTypes())
return pluginConfigKeyForImage{
includeTypes: fmt.Sprintf("%v", pluginConfig.Types()),
excludeTypes: fmt.Sprintf("%v", pluginConfig.ExcludeTypes()),
strategy: Strategy(pluginConfig.Strategy()),
remoteHost: pluginConfig.RemoteHost(),
}
}
60 changes: 0 additions & 60 deletions private/buf/bufgen/image_provider.go

This file was deleted.

Loading