Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for local Wasm plugins #3349

Merged
merged 50 commits into from
Oct 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
6cd7178
Init support for WASM plugins
emcfarlane Sep 23, 2024
a17f1c1
Remove custom look path
emcfarlane Sep 30, 2024
58c9e6f
Fix test
emcfarlane Sep 30, 2024
ccdb801
Fix test
emcfarlane Sep 30, 2024
1fb09fe
Fix test
emcfarlane Sep 30, 2024
4084811
Use Wasm abbr
emcfarlane Sep 30, 2024
cc42495
Fix description
emcfarlane Oct 1, 2024
5cd84ca
Move RunnerProvider to bufpluginrunner pkg
emcfarlane Oct 1, 2024
0b4321b
Rename Plugin to CompiledModule
emcfarlane Oct 1, 2024
ce2c42a
Use tracer
emcfarlane Oct 2, 2024
8ef1070
Unimplemented as var
emcfarlane Oct 2, 2024
fa26987
Move wasm pkg
emcfarlane Oct 2, 2024
9429c87
move to bufpluginrpcutil
emcfarlane Oct 2, 2024
9634e9d
Fixes
emcfarlane Oct 2, 2024
3498241
use wasmruntime cache dir
emcfarlane Oct 2, 2024
767897e
doc RunnerProvider config
emcfarlane Oct 2, 2024
a69da63
fix wasm args
emcfarlane Oct 2, 2024
87676c0
cleanup wasm module docs
emcfarlane Oct 2, 2024
e42f48d
fix bufconfig
emcfarlane Oct 2, 2024
88ffcb7
fix naming
emcfarlane Oct 2, 2024
85c7fbc
fix banimports
emcfarlane Oct 2, 2024
6a45022
Merge branch 'main' into ed/pluginWASM
emcfarlane Oct 2, 2024
41f8127
fix pluginrpcutil
emcfarlane Oct 2, 2024
2be37aa
fix doc
emcfarlane Oct 2, 2024
0aacd54
fix once
emcfarlane Oct 2, 2024
a073aed
add changelog
emcfarlane Oct 2, 2024
e3c329d
fix docs
emcfarlane Oct 2, 2024
e1c589b
doc wasm cache
emcfarlane Oct 2, 2024
f035402
Fix runtime options
emcfarlane Oct 2, 2024
4e161a6
fix naming to Close
emcfarlane Oct 2, 2024
cec3d6d
fix var names
emcfarlane Oct 2, 2024
64764cc
fix unimplemented
emcfarlane Oct 2, 2024
75fe87e
fix changelog
emcfarlane Oct 2, 2024
a5e1c43
fix commandRunner naming
emcfarlane Oct 2, 2024
799658a
fix delegate
emcfarlane Oct 2, 2024
41705f9
clarify args
emcfarlane Oct 2, 2024
4bfc10c
use filepath.Ext
emcfarlane Oct 2, 2024
d09ddbf
expand doc on limits
emcfarlane Oct 2, 2024
2fc5bf6
doc instantiation
emcfarlane Oct 2, 2024
1415eea
fix see docs
emcfarlane Oct 2, 2024
dc11fe5
doc memory page limits
emcfarlane Oct 2, 2024
086a6ce
note about size restriction
emcfarlane Oct 2, 2024
6ab5dcb
fix
emcfarlane Oct 2, 2024
5e8e9d9
doc limits
emcfarlane Oct 2, 2024
1866ce1
fix Runtime
emcfarlane Oct 2, 2024
ef0d8a8
fix closed
emcfarlane Oct 2, 2024
6c4030a
fix doc
emcfarlane Oct 2, 2024
bf634a5
move unimplemented runtime
emcfarlane Oct 3, 2024
423e044
fix global var position
emcfarlane Oct 3, 2024
ef1a275
Merge branch 'main' into ed/pluginWASM
emcfarlane Oct 3, 2024
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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
they satisfy the field constraints, and are only present if constraints are present.
- Update the `PROTOVALIDATE` lint rule to check predefined rules. Predefined rules will be checked
that they compile.
- Add support for a WebAssembly (Wasm) runtime for custom lint and breaking changes plugins. Use the
`.wasm` file extension to specify a path to a Wasm plugin.

## [v1.43.0] - 2024-09-30

Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ require (
github.com/spf13/cobra v1.8.1
github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.9.0
github.com/tetratelabs/wazero v1.8.0
go.lsp.dev/jsonrpc2 v0.10.0
go.lsp.dev/protocol v0.12.0
go.opentelemetry.io/otel v1.30.0
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,8 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/tetratelabs/wazero v1.8.0 h1:iEKu0d4c2Pd+QSRieYbnQC9yiFlMS9D+Jr0LsRmcF4g=
github.com/tetratelabs/wazero v1.8.0/go.mod h1:yAI0XTsMBhREkM/YDAK/zNou3GoiAce1P6+rp/wQhjs=
github.com/vbatts/tar-split v0.11.6 h1:4SjTW5+PU11n6fZenf2IPoV8/tz3AaYHMWjf23envGs=
github.com/vbatts/tar-split v0.11.6/go.mod h1:dqKNtesIOr2j2Qv3W/cHjnvk9I8+G7oAkFDFN6TCBEI=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
Expand Down
2 changes: 2 additions & 0 deletions make/buf/all.mk
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ GO_TEST_BINS := $(GO_TEST_BINS) \
private/bufpkg/bufcheck/internal/cmd/buf-plugin-rpc-ext \
private/bufpkg/bufcheck/internal/cmd/buf-plugin-duplicate-category \
private/bufpkg/bufcheck/internal/cmd/buf-plugin-duplicate-rule
GO_TEST_WASM_BINS := $(GO_TEST_WASM_BINS) \
private/bufpkg/bufcheck/internal/cmd/buf-plugin-suffix
GO_MOD_VERSION := 1.22
DOCKER_BINS := $(DOCKER_BINS) buf
FILE_IGNORES := $(FILE_IGNORES) \
Expand Down
18 changes: 17 additions & 1 deletion make/go/go.mk
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ GO_BINS ?=
# Settable
GO_TEST_BINS ?=
# Settable
GO_TEST_WASM_BINS ?=
# Settable
GO_GET_PKGS ?=
# Settable
GO_MOD_VERSION ?= 1.22
Expand Down Expand Up @@ -142,7 +144,7 @@ build: prebuild ## Run go build.
pretest::

.PHONY: test
test: pretest installtest ## Run all go tests.
test: pretest installtest installtestwasm ## Run all go tests.
go test $(GO_TEST_FLAGS) $(GOPKGS)

.PHONY: testrace
Expand Down Expand Up @@ -203,3 +205,17 @@ endef

$(foreach gobin,$(sort $(GO_TEST_BINS)),$(eval $(call gotestbinfunc,$(gobin))))
$(foreach gobin,$(sort $(GO_TEST_BINS)),$(eval FILE_IGNORES := $(FILE_IGNORES) $(gobin)/$(notdir $(gobin))))

.PHONY: installtestwasm
installtestwasm::

define gotestwasmfunc
.PHONY: installtestwasm$(notdir $(1))
installtestwasm$(notdir $(1)):
GOOS=wasip1 GOARCH=wasm go build -o $(GOBIN)/$(notdir $(1)).wasm ./$(1)

installtestwasm:: installtestwasm$(notdir $(1))
endef

$(foreach gobin,$(sort $(GO_TEST_WASM_BINS)),$(eval $(call gotestwasmfunc,$(gobin))))
$(foreach gobin,$(sort $(GO_TEST_WASM_BINS)),$(eval FILE_IGNORES := $(FILE_IGNORES) $(gobin)/$(notdir $(gobin))))
18 changes: 18 additions & 0 deletions private/buf/bufcli/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,11 @@ var (
//
// Normalized.
v3CacheModuleLockRelDirPath = normalpath.Join("v3", "modulelocks")
// v3CacheWasmRuntimeRelDirPath is the relative path to the Wasm runtime cache directory in its newest iteration.
// This directory is used to store the Wasm runtime cache. This is an implementation specific cache and opaque outside of the runtime.
//
// Normalized.
v3CacheWasmRuntimeRelDirPath = normalpath.Join("v3", "wasmruntime")
)

// NewModuleDataProvider returns a new ModuleDataProvider while creating the
Expand Down Expand Up @@ -135,6 +140,19 @@ func NewCommitProvider(container appext.Container) (bufmodule.CommitProvider, er
)
}

// CreateWasmRuntimeCacheDir creates the cache directory for the Wasm runtime.
//
// This is used by the Wasm runtime to cache compiled Wasm plugins. This is an
// implementation specific cache and opaque outside of the runtime. The runtime
// will manage the cache versioning itself within this directory.
func CreateWasmRuntimeCacheDir(container appext.Container) (string, error) {
if err := createCacheDir(container.CacheDirPath(), v3CacheWasmRuntimeRelDirPath); err != nil {
return "", err
}
fullCacheDirPath := normalpath.Join(container.CacheDirPath(), v3CacheWasmRuntimeRelDirPath)
return fullCacheDirPath, nil
}

// newWKTStore returns a new bufwktstore.Store while creating the required cache directories.
func newWKTStore(container appext.Container) (bufwktstore.Store, error) {
if err := createCacheDir(container.CacheDirPath(), v3CacheWKTRelDirPath); err != nil {
Expand Down
10 changes: 2 additions & 8 deletions private/buf/buflsp/buflsp.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ import (
"github.com/bufbuild/buf/private/bufpkg/bufcheck"
"github.com/bufbuild/buf/private/bufpkg/bufimage"
"github.com/bufbuild/buf/private/pkg/app/appext"
"github.com/bufbuild/buf/private/pkg/command"
"github.com/bufbuild/buf/private/pkg/storage"
"github.com/bufbuild/buf/private/pkg/storage/storageos"
"github.com/bufbuild/buf/private/pkg/tracing"
Expand All @@ -43,6 +42,7 @@ func Serve(
ctx context.Context,
container appext.Container,
controller bufctl.Controller,
checkClient bufcheck.Client,
stream jsonrpc2.Stream,
) (jsonrpc2.Conn, error) {
// The LSP protocol deals with absolute filesystem paths. This requires us to
Expand All @@ -57,12 +57,6 @@ func Serve(
return nil, err
}

tracer := tracing.NewTracer(container.Tracer())
checkClient, err := bufcheck.NewClient(container.Logger(), tracer, bufcheck.NewRunnerProvider(command.NewRunner()), bufcheck.ClientWithStderr(container.Stderr()))
if err != nil {
return nil, err
}

conn := jsonrpc2.NewConn(stream)
lsp := &lsp{
conn: conn,
Expand All @@ -71,7 +65,7 @@ func Serve(
zap.NewNop(), // The logging from protocol itself isn't very good, we've replaced it with connAdapter here.
),
logger: container.Logger(),
tracer: tracer,
tracer: tracing.NewTracer(container.Tracer()),
controller: controller,
checkClient: checkClient,
rootBucket: bucket,
Expand Down
3 changes: 2 additions & 1 deletion private/buf/bufmigrate/migrator.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import (
"github.com/bufbuild/buf/private/pkg/storage"
"github.com/bufbuild/buf/private/pkg/storage/storagemem"
"github.com/bufbuild/buf/private/pkg/tracing"
"github.com/bufbuild/buf/private/pkg/wasm"
"github.com/google/uuid"
"go.uber.org/multierr"
"go.uber.org/zap"
Expand Down Expand Up @@ -712,7 +713,7 @@ func equivalentCheckConfigInV2(
) (bufconfig.CheckConfig, error) {
// No need for custom lint/breaking plugins since there's no plugins to migrate from <=v1.
// TODO: If we ever need v3, then we will have to deal with this.
client, err := bufcheck.NewClient(logger, tracer, bufcheck.NewRunnerProvider(runner))
client, err := bufcheck.NewClient(logger, tracer, bufcheck.NewRunnerProvider(runner, wasm.UnimplementedRuntime))
if err != nil {
return nil, err
}
Expand Down
3 changes: 2 additions & 1 deletion private/buf/cmd/buf/buf_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import (
"github.com/bufbuild/buf/private/pkg/storage/storageos"
"github.com/bufbuild/buf/private/pkg/storage/storagetesting"
"github.com/bufbuild/buf/private/pkg/tracing"
"github.com/bufbuild/buf/private/pkg/wasm"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/zap"
Expand Down Expand Up @@ -1349,7 +1350,7 @@ func TestCheckLsBreakingRulesFromConfigExceptDeprecated(t *testing.T) {
t.Run(version.String(), func(t *testing.T) {
t.Parallel()
// Do not need any custom lint/breaking plugins here.
client, err := bufcheck.NewClient(zap.NewNop(), tracing.NopTracer, bufcheck.NewRunnerProvider(command.NewRunner()))
client, err := bufcheck.NewClient(zap.NewNop(), tracing.NopTracer, bufcheck.NewRunnerProvider(command.NewRunner(), wasm.UnimplementedRuntime))
require.NoError(t, err)
allRules, err := client.AllRules(context.Background(), check.RuleTypeBreaking, version)
require.NoError(t, err)
Expand Down
30 changes: 28 additions & 2 deletions private/buf/cmd/buf/command/beta/lsp/lsp.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,16 @@ import (

"github.com/bufbuild/buf/private/buf/bufcli"
"github.com/bufbuild/buf/private/buf/buflsp"
"github.com/bufbuild/buf/private/bufpkg/bufcheck"
"github.com/bufbuild/buf/private/pkg/app/appcmd"
"github.com/bufbuild/buf/private/pkg/app/appext"
"github.com/bufbuild/buf/private/pkg/command"
"github.com/bufbuild/buf/private/pkg/ioext"
"github.com/bufbuild/buf/private/pkg/tracing"
"github.com/bufbuild/buf/private/pkg/wasm"
"github.com/spf13/pflag"
"go.lsp.dev/jsonrpc2"
"go.uber.org/multierr"
)

const (
Expand Down Expand Up @@ -77,7 +82,7 @@ func run(
ctx context.Context,
container appext.Container,
flags *flags,
) error {
) (retErr error) {
bufcli.WarnBetaCommand(ctx, container)

transport, err := dial(container, flags)
Expand All @@ -90,7 +95,28 @@ func run(
return err
}

conn, err := buflsp.Serve(ctx, container, controller, jsonrpc2.NewStream(transport))
wasmRuntimeCacheDir, err := bufcli.CreateWasmRuntimeCacheDir(container)
if err != nil {
return err
}
wasmRuntime, err := wasm.NewRuntime(ctx, wasm.WithLocalCacheDir(wasmRuntimeCacheDir))
if err != nil {
return err
}
defer func() {
retErr = multierr.Append(retErr, wasmRuntime.Close(ctx))
}()
checkClient, err := bufcheck.NewClient(
container.Logger(),
tracing.NewTracer(container.Tracer()),
bufcheck.NewRunnerProvider(command.NewRunner(), wasmRuntime),
bufcheck.ClientWithStderr(container.Stderr()),
)
if err != nil {
return err
}

conn, err := buflsp.Serve(ctx, container, controller, checkClient, jsonrpc2.NewStream(transport))
if err != nil {
return err
}
Expand Down
22 changes: 20 additions & 2 deletions private/buf/cmd/buf/command/breaking/breaking.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ import (
"github.com/bufbuild/buf/private/pkg/slicesext"
"github.com/bufbuild/buf/private/pkg/stringutil"
"github.com/bufbuild/buf/private/pkg/tracing"
"github.com/bufbuild/buf/private/pkg/wasm"
"github.com/spf13/pflag"
"go.uber.org/multierr"
)

const (
Expand Down Expand Up @@ -145,7 +147,7 @@ func run(
ctx context.Context,
container appext.Container,
flags *flags,
) error {
) (retErr error) {
if err := bufcli.ValidateRequiredFlag(againstFlagName, flags.Against); err != nil {
return err
}
Expand Down Expand Up @@ -206,10 +208,26 @@ func run(
len(againstImageWithConfigs),
)
}
wasmRuntimeCacheDir, err := bufcli.CreateWasmRuntimeCacheDir(container)
if err != nil {
return err
}
wasmRuntime, err := wasm.NewRuntime(ctx, wasm.WithLocalCacheDir(wasmRuntimeCacheDir))
if err != nil {
return err
}
defer func() {
retErr = multierr.Append(retErr, wasmRuntime.Close(ctx))
}()
tracer := tracing.NewTracer(container.Tracer())
var allFileAnnotations []bufanalysis.FileAnnotation
for i, imageWithConfig := range imageWithConfigs {
client, err := bufcheck.NewClient(container.Logger(), tracer, bufcheck.NewRunnerProvider(command.NewRunner()), bufcheck.ClientWithStderr(container.Stderr()))
client, err := bufcheck.NewClient(
container.Logger(),
tracer,
bufcheck.NewRunnerProvider(command.NewRunner(), wasmRuntime),
bufcheck.ClientWithStderr(container.Stderr()),
)
if err != nil {
return err
}
Expand Down
22 changes: 20 additions & 2 deletions private/buf/cmd/buf/command/config/internal/internal.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ import (
"github.com/bufbuild/buf/private/pkg/stringutil"
"github.com/bufbuild/buf/private/pkg/syserror"
"github.com/bufbuild/buf/private/pkg/tracing"
"github.com/bufbuild/buf/private/pkg/wasm"
"github.com/spf13/pflag"
"go.uber.org/multierr"
)

const (
Expand Down Expand Up @@ -149,7 +151,7 @@ func lsRun(
flags *flags,
commandName string,
ruleType check.RuleType,
) error {
) (retErr error) {
if flags.ConfiguredOnly {
if flags.Version != "" {
return appcmd.NewInvalidArgumentErrorf("--%s cannot be specified if --%s is specified", versionFlagName, configFlagName)
Expand Down Expand Up @@ -184,8 +186,24 @@ func lsRun(
return err
}
}
wasmRuntimeCacheDir, err := bufcli.CreateWasmRuntimeCacheDir(container)
if err != nil {
return err
}
wasmRuntime, err := wasm.NewRuntime(ctx, wasm.WithLocalCacheDir(wasmRuntimeCacheDir))
if err != nil {
return err
}
defer func() {
retErr = multierr.Append(retErr, wasmRuntime.Close(ctx))
}()
tracer := tracing.NewTracer(container.Tracer())
client, err := bufcheck.NewClient(container.Logger(), tracer, bufcheck.NewRunnerProvider(command.NewRunner()), bufcheck.ClientWithStderr(container.Stderr()))
client, err := bufcheck.NewClient(
container.Logger(),
tracer,
bufcheck.NewRunnerProvider(command.NewRunner(), wasmRuntime),
bufcheck.ClientWithStderr(container.Stderr()),
)
if err != nil {
return err
}
Expand Down
20 changes: 19 additions & 1 deletion private/buf/cmd/buf/command/lint/lint.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ import (
"github.com/bufbuild/buf/private/pkg/command"
"github.com/bufbuild/buf/private/pkg/stringutil"
"github.com/bufbuild/buf/private/pkg/tracing"
"github.com/bufbuild/buf/private/pkg/wasm"
"github.com/spf13/pflag"
"go.uber.org/multierr"
)

const (
Expand Down Expand Up @@ -131,10 +133,26 @@ func run(
if err != nil {
return err
}
wasmRuntimeCacheDir, err := bufcli.CreateWasmRuntimeCacheDir(container)
if err != nil {
return err
}
wasmRuntime, err := wasm.NewRuntime(ctx, wasm.WithLocalCacheDir(wasmRuntimeCacheDir))
if err != nil {
return err
}
defer func() {
retErr = multierr.Append(retErr, wasmRuntime.Close(ctx))
}()
tracer := tracing.NewTracer(container.Tracer())
var allFileAnnotations []bufanalysis.FileAnnotation
for _, imageWithConfig := range imageWithConfigs {
client, err := bufcheck.NewClient(container.Logger(), tracer, bufcheck.NewRunnerProvider(command.NewRunner()), bufcheck.ClientWithStderr(container.Stderr()))
client, err := bufcheck.NewClient(
container.Logger(),
tracer,
bufcheck.NewRunnerProvider(command.NewRunner(), wasmRuntime),
bufcheck.ClientWithStderr(container.Stderr()),
)
if err != nil {
return err
}
Expand Down
8 changes: 7 additions & 1 deletion private/buf/cmd/buf/command/mod/internal/internal.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import (
"github.com/bufbuild/buf/private/pkg/stringutil"
"github.com/bufbuild/buf/private/pkg/syserror"
"github.com/bufbuild/buf/private/pkg/tracing"
"github.com/bufbuild/buf/private/pkg/wasm"
"github.com/spf13/pflag"
)

Expand Down Expand Up @@ -175,7 +176,12 @@ func lsRun(
}
// BufYAMLFiles <=v1 never had plugins.
tracer := tracing.NewTracer(container.Tracer())
client, err := bufcheck.NewClient(container.Logger(), tracer, bufcheck.NewRunnerProvider(command.NewRunner()), bufcheck.ClientWithStderr(container.Stderr()))
client, err := bufcheck.NewClient(
container.Logger(),
tracer,
bufcheck.NewRunnerProvider(command.NewRunner(), wasm.UnimplementedRuntime),
bufcheck.ClientWithStderr(container.Stderr()),
)
if err != nil {
return err
}
Expand Down
Loading