feat: initial draft of SDK

This commit is contained in:
Peter 2023-05-08 15:21:31 +02:00
parent 208424de98
commit e9ef69ca1f
No known key found for this signature in database
35 changed files with 4481 additions and 80 deletions

View file

@ -1,2 +1,28 @@
# wasi-module-sdk-go
# Module SDK for Go
This module provides glue code to implement a buildr WASI module easily and quickly.
To implement a new buildr WASI module:
1. Create a new Go module
1. Reference this SDK (`go get -u code.icb4dc0.de/buildr/wasi-module-sdk`)
1. create a `main.go` with an **empty** `main()` function
1. implement the `sdk.Module` interface for your module
1. implement an `init()` function that registers your module and the SDK's type registry
1. compile the module e.g. with tinygo
See also the [examples](./examples) directory to get started.
## Dependencies
### easyjson
Right now the SDK depends on [easyjson](https://github.com/mailru/easyjson) to unmarshal the modules state as defined in the HCL configuration.
The main reason for this is that the reflection support in TinyGo is limited and for instance `encoding/json` heavily depends on reflection.
The SDK itself uses protobuf (vtprotobuf) to exchange data with the host without reflection but this is not generic enough to support every possibility of module configuration (e.g. `map<string, string>` would require extra encoding/decoding steps, same for `map<string, bytes`).
Therefore, the SDK requires you to generate `easyjson` compatible unmarshal functions.
### slog
*buildr* is using [`slog`](https://pkg.go.dev/golang.org/x/exp/slog) for logging (as soon as Go 1.21 is released it will move to the final version) and also the SDK is using it to allow modules log messages.
When using the SDK there's nothing to be done except using the logger the is provided by the `ExecutionContext`.
Alternatively it'd be possible to log to `STDOUT`/`STDERR` but keep in mind that logs written to these streams directly will be 'mixed' with the output of other processes.

72
api.go Normal file
View file

@ -0,0 +1,72 @@
package sdk
import (
"context"
"fmt"
"github.com/mailru/easyjson"
"golang.org/x/exp/slog"
"io"
"time"
)
type Category string
func (t Category) String() string {
return string(t)
}
func (t Category) GroupName() string {
return fmt.Sprintf("%ss", t)
}
const (
CategoryTool Category = "tool"
CategoryTask Category = "task"
CategoryBuild Category = "build"
CategoryPackage Category = "package"
)
type StateMetadata struct {
ModifiedAt time.Time
TTL *time.Time
}
type ExecutionContext interface {
context.Context
WorkingDir() string
OutDir() string
BinariesDir() string
StdOut() io.Writer
StdErr() io.Writer
Logger() *slog.Logger
GetState(ctx context.Context, key string) ([]byte, StateMetadata, error)
SetState(ctx context.Context, key string, value []byte) error
}
type Module interface {
easyjson.Unmarshaler
Execute(ctx ExecutionContext) error
Category() Category
Type() string
}
type BinaryNamer interface {
BinaryName() string
}
type ToolModule interface {
Module
BinaryNamer
}
type Factory interface {
Create() Module
}
var _ Factory = (*ModuleFactoryFunc)(nil)
type ModuleFactoryFunc func() Module
func (f ModuleFactoryFunc) Create() Module {
return f()
}

11
api/README.md Normal file
View file

@ -0,0 +1,11 @@
# WASI host - module data exchange
The module SDK re-uses a subset of protobuf messages also used in the remote protocol except for the `TaskOutput` message because WASI handles `STDOUT`/`STDERR` already.
The protobuf messages are not used with gRPC but only as binary encoded messages shared via pointers in the WASI modules memory.
The following 'RPC' calls are supported:
- `log_msg` accepting a pointer and an offset to a `TaskLog` message - won't return anything
- `get_state` accepting a pointer and an offset to a `GetStateRequest` message, returning a 64-bit integer (32-bit pointer, 32-bit size) to a `GetStateResponse` message
- `set_state` accepting a pointer and an offset to a `SetState` message, returning a 64-bit integer (32-bit pointer, 32-bit size) to a `Result` message optionally containing error details

11
api/buf.yaml Normal file
View file

@ -0,0 +1,11 @@
version: v1
name: buf.build/buildr/buildr
breaking:
use:
- FILE
lint:
use:
- DEFAULT
except:
- PACKAGE_DIRECTORY_MATCH
allow_comment_ignores: true

64
api/rpc/v1/executor.proto Normal file
View file

@ -0,0 +1,64 @@
syntax = "proto3";
package buildr.rpc.v1;
message Buildr {
message Repo {
string root = 1;
}
message GitHub {
string api_token = 1;
}
Repo repo = 1;
GitHub github = 2;
}
message ModuleReference {
string task_id = 1;
string module_category = 2;
string module_type = 3;
string module_name = 4;
}
message StartTaskRequest {
ModuleReference reference = 1;
Buildr buildr = 2;
bytes raw_task = 3;
}
message TaskResult {
string error = 1;
string modified_files_archive_path = 2;
}
message TaskLog {
message LogAttribute {
string key = 1;
string value = 2;
}
int64 time = 1;
string message = 2;
int32 level = 3;
repeated LogAttribute attributes = 4;
}
message SetState {
bytes key = 1;
bytes data = 2;
}
message GetStateRequest {
bytes key = 1;
}
message GetStateResponse {
bytes key = 1;
bytes data = 2;
}
message Result {
bool success = 1;
string error = 2;
}

17
buf.gen.yaml Normal file
View file

@ -0,0 +1,17 @@
version: v1
managed:
enabled: true
go_package_prefix:
default: code.icb4dc0.de/buildr/wasi-module-sdk/internal
except:
- buf.build/googleapis/googleapis
plugins:
- plugin: buf.build/protocolbuffers/go:v1.30.0
out: ./protocol/generated/
opt: paths=source_relative
- plugin: go-vtproto
out: ./protocol/generated/
opt:
- features=marshal+unmarshal+size+pool
- paths=source_relative
revision: 1

3
buf.work.yaml Normal file
View file

@ -0,0 +1,3 @@
version: v1
directories:
- api/

4
buf.yaml Normal file
View file

@ -0,0 +1,4 @@
version: v1
name: buf.build/buildr/module-sdk-go
deps:
- buf.build/buildr/buildr

85
context.go Normal file
View file

@ -0,0 +1,85 @@
package sdk
import (
"context"
"crypto/md5"
"golang.org/x/exp/slog"
"io"
"os"
)
var _ ExecutionContext = (*wasiExecutionContext)(nil)
func newWasiExecutionContext(
ctx context.Context,
logger *slog.Logger,
modName string,
mod Module,
repoRoot, binDir, outDir string,
) *wasiExecutionContext {
return &wasiExecutionContext{
Context: ctx,
logger: logger,
modName: modName,
mod: mod,
repoRoot: repoRoot,
outDir: outDir,
binDir: binDir,
}
}
type wasiExecutionContext struct {
context.Context
stateProxy StateProxy
logger *slog.Logger
mod Module
modName string
repoRoot string
outDir string
binDir string
}
func (w wasiExecutionContext) WorkingDir() string {
return w.repoRoot
}
func (w wasiExecutionContext) OutDir() string {
return w.outDir
}
func (w wasiExecutionContext) BinariesDir() string {
return w.binDir
}
func (w wasiExecutionContext) StdOut() io.Writer {
return os.Stdout
}
func (w wasiExecutionContext) StdErr() io.Writer {
return os.Stderr
}
func (w wasiExecutionContext) Logger() *slog.Logger {
return w.logger
}
func (w wasiExecutionContext) GetState(_ context.Context, key string) ([]byte, StateMetadata, error) {
return w.stateProxy.Get(w.keyBytes(w.mod.Category().String(), w.modName, key))
}
func (w wasiExecutionContext) SetState(_ context.Context, key string, value []byte) error {
return w.stateProxy.Set(w.keyBytes(w.mod.Category().String(), w.modName, key), value)
}
func (w wasiExecutionContext) keyBytes(parts ...string) []byte {
if len(parts) == 0 {
return nil
}
h := md5.New()
for i := range parts {
_, _ = h.Write([]byte(parts[i]))
}
return h.Sum(nil)
}

34
entrypoint.go Normal file
View file

@ -0,0 +1,34 @@
package sdk
import (
"code.icb4dc0.de/buildr/wasi-module-sdk/internal/mem"
rpcv1 "code.icb4dc0.de/buildr/wasi-module-sdk/protocol/generated/rpc/v1"
"context"
"github.com/mailru/easyjson"
_ "github.com/tetratelabs/tinymem"
)
var defaultRegistry = NewTypeRegistry()
func Register(cat Category, moduleName string, factory Factory) {
defaultRegistry.Add(cat, moduleName, factory)
}
//export run
func Run(specPtr, specSize uint32) {
var startTask rpcv1.StartTaskRequest
if err := startTask.UnmarshalVT(mem.DataFromPtr(specPtr, specSize)); err != nil {
panic(err)
}
executor := NewExecutor(startTask.Buildr.Repo.Root, "", "")
reference := startTask.GetReference()
module := defaultRegistry.Get(Category(reference.GetModuleCategory()), reference.GetModuleType())
if err := easyjson.Unmarshal(startTask.RawTask, module); err != nil {
panic(err)
}
executor.Run(context.Background(), startTask.Reference.ModuleName, module)
}

View file

@ -1,11 +0,0 @@
module hello_world
go 1.20
require (
code.icb4dc0.de/buildr/wasi-module-sdk latest
)
replace (
code.icb4dc0.de/buildr/wasi-module-sdk => ../../
)

2
examples/hello_world_go/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
*.wasm
*_easyjson.go

View file

@ -0,0 +1,23 @@
module hello_world
go 1.20
require (
code.icb4dc0.de/buildr/wasi-module-sdk v0.0.0-00010101000000-000000000000
code.icb4dc0.de/buildr/wasi-module-sdk/integration v0.0.0-00010101000000-000000000000
github.com/mailru/easyjson v0.7.7
golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53
)
replace (
code.icb4dc0.de/buildr/wasi-module-sdk => ../../
code.icb4dc0.de/buildr/wasi-module-sdk/integration => ../../integration
)
require (
github.com/google/uuid v1.3.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/tetratelabs/tinymem v0.1.0 // indirect
github.com/tetratelabs/wazero v1.1.0 // indirect
google.golang.org/protobuf v1.30.0 // indirect
)

View file

@ -0,0 +1,19 @@
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/tetratelabs/tinymem v0.1.0 h1:Qza1JAg9lquPPJ/CIei5qQYx7t18KLie83O2WR6CM58=
github.com/tetratelabs/tinymem v0.1.0/go.mod h1:WFFTZFhLod6lTL+UetFAopVbGaB+KFsVcIY+RUv7NeY=
github.com/tetratelabs/wazero v1.1.0 h1:EByoAhC+QcYpwSZJSs/aV0uokxPwBgKxfiokSUwAknQ=
github.com/tetratelabs/wazero v1.1.0/go.mod h1:wYx2gNRg8/WihJfSDxA1TIL8H+GkfLYm+bIfbblu9VQ=
golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53 h1:5llv2sWeaMSnA3w2kS57ouQQ4pudlXrR0dCgw51QK9o=
golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=

View file

@ -0,0 +1,17 @@
package main
//go:generate tinygo build -o hello_world.wasm -scheduler=none -gc=leaking --no-debug -target=wasi main.go
import (
sdk "code.icb4dc0.de/buildr/wasi-module-sdk"
"hello_world/module"
)
func init() {
sdk.Register(sdk.CategoryTask, "hello_world", sdk.ModuleFactoryFunc(func() sdk.Module {
return new(module.HelloWorld)
}))
}
func main() {
}

View file

@ -0,0 +1,31 @@
package main_test
import (
sdk "code.icb4dc0.de/buildr/wasi-module-sdk"
"code.icb4dc0.de/buildr/wasi-module-sdk/integration"
"context"
_ "embed"
"golang.org/x/exp/slog"
"testing"
)
//go:embed hello_world.wasm
var payload []byte
func TestModule(t *testing.T) {
h := integration.NewHost(
slog.New(slog.NewTextHandler(integration.NewTestWriter(t))),
integration.WithState(integration.StateKey(sdk.CategoryTask, "test", "hello"), []byte("world")),
)
s := integration.TestSpec{
ModuleCategory: sdk.CategoryTask,
ModuleType: "hello_world",
ModuleName: "test",
RawTaskSpec: []byte(`{"Name": "Ted"}`),
}
if err := h.Run(context.Background(), payload, s); err != nil {
t.Errorf("Failed to run module: %v", err)
}
}

View file

@ -0,0 +1,41 @@
package module
//go:generate go run -mod=mod github.com/mailru/easyjson/easyjson -all hello_world.go
import (
sdk "code.icb4dc0.de/buildr/wasi-module-sdk"
"golang.org/x/exp/slog"
)
var _ sdk.Module = (*HelloWorld)(nil)
type HelloWorld struct {
Name string
}
func (h HelloWorld) Execute(ctx sdk.ExecutionContext) error {
logger := ctx.Logger()
logger.Info("Executing hello world")
val, _, err := ctx.GetState(ctx, "hello")
if err != nil {
return err
}
if err := ctx.SetState(ctx, "state", []byte(`{"hello":"world"}`)); err != nil {
return err
}
logger.Info("Got value from state", slog.String("value", string(val)))
return nil
}
func (HelloWorld) Category() sdk.Category {
return sdk.CategoryTask
}
func (HelloWorld) Type() string {
return "hello_world"
}

29
executor.go Normal file
View file

@ -0,0 +1,29 @@
package sdk
import (
"context"
"golang.org/x/exp/slog"
)
func NewExecutor(repoRoot, outDir, binDir string) Executor {
return Executor{
logger: slog.New(NewWASIHandler()),
repoRoot: repoRoot,
outDir: outDir,
binDir: binDir,
}
}
type Executor struct {
logger *slog.Logger
repoRoot string
outDir string
binDir string
}
func (e Executor) Run(ctx context.Context, modName string, m Module) {
execCtx := newWasiExecutionContext(ctx, e.logger, modName, m, e.repoRoot, e.binDir, e.outDir)
if err := m.Execute(execCtx); err != nil {
e.logger.Error("Failed to execute module", slog.String("err", err.Error()))
}
}

11
go.mod
View file

@ -3,6 +3,13 @@ module code.icb4dc0.de/buildr/wasi-module-sdk
go 1.20
require (
buf.build/gen/go/buildr/buildr/protocolbuffers/go v1.30.0-20230504155321-a2ad89049f80.1 // indirect
github.com/tetratelabs/wazero v1.1.0 // indirect
github.com/mailru/easyjson v0.7.7
github.com/tetratelabs/tinymem v0.1.0
golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53
google.golang.org/protobuf v1.30.0
)
require (
github.com/google/go-cmp v0.5.9 // indirect
github.com/josharian/intern v1.0.0 // indirect
)

15
go.sum
View file

@ -1,9 +1,16 @@
buf.build/gen/go/buildr/buildr/protocolbuffers/go v1.30.0-20230504155321-a2ad89049f80.1 h1:gDR2MbPrmDLMU4SU83sLG53G1BO2jWLZRSwA7Zx/ORs=
buf.build/gen/go/buildr/buildr/protocolbuffers/go v1.30.0-20230504155321-a2ad89049f80.1/go.mod h1:HnJwr6AoSkS1h+Fr8+UR7MDcZMzmv7lJPJWeTjdclPs=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/tetratelabs/wazero v1.1.0 h1:EByoAhC+QcYpwSZJSs/aV0uokxPwBgKxfiokSUwAknQ=
github.com/tetratelabs/wazero v1.1.0/go.mod h1:wYx2gNRg8/WihJfSDxA1TIL8H+GkfLYm+bIfbblu9VQ=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/tetratelabs/tinymem v0.1.0 h1:Qza1JAg9lquPPJ/CIei5qQYx7t18KLie83O2WR6CM58=
github.com/tetratelabs/tinymem v0.1.0/go.mod h1:WFFTZFhLod6lTL+UetFAopVbGaB+KFsVcIY+RUv7NeY=
golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53 h1:5llv2sWeaMSnA3w2kS57ouQQ4pudlXrR0dCgw51QK9o=
golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=

9
imports_stub.go Normal file
View file

@ -0,0 +1,9 @@
//go:build !wasi
package sdk
func _log_msg(ptr, size uint32) {}
func _get_state(ptr, size uint32) (ptrSize uint64) { return 0 }
func _set_state(ptr, size uint32) (ptrSize uint64) { return 0 }

15
imports_wasi.go Normal file
View file

@ -0,0 +1,15 @@
//go:build wasi
package sdk
//go:wasm-module buildr
//export log_msg
func _log_msg(ptr, size uint32)
//go:wasm-module buildr
//export get_state
func _get_state(ptr, size uint32) (ptrSize uint64)
//go:wasm-module buildr
//export set_state
func _set_state(ptr, size uint32) (ptrSize uint64)

13
integration/README.md Normal file
View file

@ -0,0 +1,13 @@
# Integration module
The integration module is meant as a helper to blackbox test a WASI module.
It's a shortcut to instantiate and execute a module in the context of buildr.
The workflow basically looks like this:
1. Compile module e.g. with tinygo to `*.wasm` file
1. Create a `integration.Host` (with `integration.NewHost(...)` function)
1. Specify the scenario (category, type, ...)
1. Execute the module
A very basic example can be found in the [`hello_world_go` example](../examples/hello_world_go/main_test.go)

19
integration/go.mod Normal file
View file

@ -0,0 +1,19 @@
module code.icb4dc0.de/buildr/wasi-module-sdk/integration
go 1.20
require (
code.icb4dc0.de/buildr/wasi-module-sdk v0.0.0-00010101000000-000000000000
github.com/google/uuid v1.3.0
github.com/tetratelabs/wazero v1.1.0
golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53
)
require (
github.com/josharian/intern v1.0.0 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/tetratelabs/tinymem v0.1.0 // indirect
google.golang.org/protobuf v1.30.0 // indirect
)
replace code.icb4dc0.de/buildr/wasi-module-sdk => ../

19
integration/go.sum Normal file
View file

@ -0,0 +1,19 @@
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/tetratelabs/tinymem v0.1.0 h1:Qza1JAg9lquPPJ/CIei5qQYx7t18KLie83O2WR6CM58=
github.com/tetratelabs/tinymem v0.1.0/go.mod h1:WFFTZFhLod6lTL+UetFAopVbGaB+KFsVcIY+RUv7NeY=
github.com/tetratelabs/wazero v1.1.0 h1:EByoAhC+QcYpwSZJSs/aV0uokxPwBgKxfiokSUwAknQ=
github.com/tetratelabs/wazero v1.1.0/go.mod h1:wYx2gNRg8/WihJfSDxA1TIL8H+GkfLYm+bIfbblu9VQ=
golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53 h1:5llv2sWeaMSnA3w2kS57ouQQ4pudlXrR0dCgw51QK9o=
golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=

23
integration/logging.go Normal file
View file

@ -0,0 +1,23 @@
package integration
import (
"io"
"testing"
)
var _ io.Writer = (*TestWriter)(nil)
func NewTestWriter(tb testing.TB) TestWriter {
return TestWriter{
TB: tb,
}
}
type TestWriter struct {
TB testing.TB
}
func (t TestWriter) Write(p []byte) (n int, err error) {
t.TB.Log(string(p))
return len(p), nil
}

75
integration/mem_mgr.go Normal file
View file

@ -0,0 +1,75 @@
package integration
import (
"context"
"errors"
"github.com/tetratelabs/wazero/api"
)
type Message interface {
MarshalVT() (dAtA []byte, err error)
UnmarshalVT(dAtA []byte) error
}
func newMemoryManager(mod api.Module) *memoryManager {
return &memoryManager{
allocate: mod.ExportedFunction("malloc"),
deallocate: mod.ExportedFunction("free"),
}
}
type memoryManager struct {
allocate api.Function
deallocate api.Function
danglingAllocations []uint64
}
func (m *memoryManager) WriteMessage(ctx context.Context, mod api.Module, msg Message) (uint64, error) {
data, err := msg.MarshalVT()
if err != nil {
return 0, err
}
ptr, err := m.Allocate(ctx, uint64(len(data)))
if err != nil {
return 0, err
}
if !mod.Memory().Write(uint32(ptr), data) {
return 0, errors.New("failed to write message to memory")
}
return (ptr << uint64(32)) | uint64(len(data)), nil
}
func (m *memoryManager) Allocate(ctx context.Context, size uint64) (ptr uint64, err error) {
results, err := m.allocate.Call(ctx, size)
if err != nil {
return 0, err
}
m.danglingAllocations = append(m.danglingAllocations, results[0])
return results[0], nil
}
func (m *memoryManager) WithMem(ctx context.Context, size uint64, delegate func(ptr uint64) error) error {
results, err := m.allocate.Call(ctx, size)
if err != nil {
return err
}
defer m.deallocate.Call(ctx, results[0])
return delegate(results[0])
}
func (m *memoryManager) Close() (err error) {
ctx := context.Background()
for i := range m.danglingAllocations {
_, e := m.deallocate.Call(ctx, m.danglingAllocations[i])
err = errors.Join(err, e)
}
return err
}

224
integration/test_host.go Normal file
View file

@ -0,0 +1,224 @@
package integration
import (
"context"
"crypto/md5"
"errors"
"os"
"time"
sdk "code.icb4dc0.de/buildr/wasi-module-sdk"
rpcv1 "code.icb4dc0.de/buildr/wasi-module-sdk/protocol/generated/rpc/v1"
"github.com/google/uuid"
"github.com/tetratelabs/wazero"
"github.com/tetratelabs/wazero/api"
"github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1"
"golang.org/x/exp/slog"
)
func StateKey(cat sdk.Category, modName, key string) string {
h := md5.New()
_, _ = h.Write([]byte(cat.String()))
_, _ = h.Write([]byte(modName))
_, _ = h.Write([]byte(key))
return string(h.Sum(nil))
}
type TestSpec struct {
ModuleCategory sdk.Category
ModuleType string
ModuleName string
RawTaskSpec []byte
}
type HostOption func(h *Host)
func WithState(key string, value []byte) HostOption {
return func(h *Host) {
h.state[key] = value
}
}
func NewHost(logger *slog.Logger, opts ...HostOption) *Host {
h := &Host{
Logger: logger,
state: make(map[string][]byte),
}
for i := range opts {
opts[i](h)
}
return h
}
type Host struct {
memMgr *memoryManager
state map[string][]byte
Logger *slog.Logger
}
func (h *Host) Run(ctx context.Context, wasiPayload []byte, spec TestSpec) (err error) {
runtimeConfig := wazero.NewRuntimeConfig().
WithCloseOnContextDone(true)
r := wazero.NewRuntimeWithConfig(ctx, runtimeConfig)
defer func() {
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
defer cancel()
err = errors.Join(err, r.Close(ctx))
}()
_, err = r.NewHostModuleBuilder("buildr").
NewFunctionBuilder().WithFunc(h.log).Export("log_msg").
NewFunctionBuilder().WithFunc(h.getState).Export("get_state").
NewFunctionBuilder().WithFunc(h.setState).Export("set_state").
Instantiate(ctx)
if err != nil {
return err
}
closer, err := wasi_snapshot_preview1.Instantiate(ctx, r)
if err != nil {
return err
}
defer func() {
err = errors.Join(err, closer.Close(context.Background()))
}()
config := wazero.NewFSConfig().
WithDirMount(".", "/work")
moduleConfig := wazero.NewModuleConfig().
WithStdout(os.Stdout).
WithStderr(os.Stderr).
WithFSConfig(config)
mod, err := r.InstantiateWithConfig(ctx, wasiPayload, moduleConfig)
if err != nil {
return err
}
startTask := &rpcv1.StartTaskRequest{
Reference: &rpcv1.ModuleReference{
TaskId: uuid.NewString(),
ModuleCategory: spec.ModuleCategory.String(),
ModuleType: spec.ModuleType,
ModuleName: spec.ModuleName,
},
Buildr: &rpcv1.Buildr{
Repo: &rpcv1.Buildr_Repo{
Root: "/work",
},
},
RawTask: spec.RawTaskSpec,
}
data, err := startTask.MarshalVT()
if err != nil {
return err
}
run := mod.ExportedFunction("run")
h.memMgr = newMemoryManager(mod)
defer func() {
err = errors.Join(err, h.memMgr.Close())
}()
err = h.memMgr.WithMem(ctx, uint64(len(data)), func(ptr uint64) error {
if !mod.Memory().Write(uint32(ptr), data) {
return errors.New("failed to write to memory")
}
_, err = run.Call(ctx, ptr, uint64(len(data)))
return err
})
return err
}
func (h *Host) getState(ctx context.Context, m api.Module, offset, byteCount uint32) uint64 {
if h.state == nil {
h.state = make(map[string][]byte)
}
buf, ok := m.Memory().Read(offset, byteCount)
if !ok {
return 0
}
getStateReq := new(rpcv1.GetStateRequest)
if err := getStateReq.UnmarshalVT(buf); err != nil {
h.Logger.Error("failed to unmarshal getStateRequest", slog.String("err", err.Error()))
return 0
}
resp := new(rpcv1.GetStateResponse)
resp.Data, _ = h.state[string(getStateReq.Key)]
if ptr, err := h.memMgr.WriteMessage(ctx, m, resp); err != nil {
h.Logger.Error("Failed to write message", slog.String("err", err.Error()))
return 0
} else {
return ptr
}
}
func (h *Host) setState(ctx context.Context, m api.Module, offset, byteCount uint32) (result uint64) {
if h.state == nil {
h.state = make(map[string][]byte)
}
buf, ok := m.Memory().Read(offset, byteCount)
if !ok {
return 0
}
setState := new(rpcv1.SetState)
if err := setState.UnmarshalVT(buf); err != nil {
h.Logger.Error("failed to unmarshal SetState", slog.String("err", err.Error()))
return 0
}
var resp rpcv1.Result
if len(setState.Key) < 1 {
resp.Error = "key might not be empty"
} else {
h.state[string(setState.Key)] = setState.Data
resp.Success = true
}
if ptr, err := h.memMgr.WriteMessage(ctx, m, &resp); err != nil {
h.Logger.Error("Failed to write message", slog.String("err", err.Error()))
return 0
} else {
return ptr
}
}
func (h *Host) log(ctx context.Context, m api.Module, offset, byteCount uint32) {
buf, ok := m.Memory().Read(offset, byteCount)
if !ok {
return
}
taskLog := new(rpcv1.TaskLog)
if err := taskLog.UnmarshalVT(buf); err != nil {
h.Logger.Warn("failed to unmarshal task log", slog.String("err", err.Error()))
return
}
rec := slog.NewRecord(time.UnixMicro(taskLog.Time), slog.Level(taskLog.Level), taskLog.Message, 0)
for i := range taskLog.Attributes {
attr := taskLog.Attributes[i]
rec.AddAttrs(slog.String(attr.Key, attr.Value))
}
_ = h.Logger.Handler().Handle(ctx, rec)
}

17
internal/mem/unmanaged.go Normal file
View file

@ -0,0 +1,17 @@
package mem
import "unsafe"
func DataToManagedPtr(data []byte) (uint32, uint32) {
ptr := unsafe.Pointer(unsafe.SliceData(data))
return uint32(uintptr(ptr)), uint32(len(data))
}
func DataFromPtr(ptr, size uint32) []byte {
p := unsafe.Pointer(uintptr(ptr))
return unsafe.Slice((*byte)(p), int(size))
}
func PtrToData(ptr uint32, size uint32) []byte {
return unsafe.Slice((*byte)(unsafe.Pointer(uintptr(ptr))), size)
}

78
logger.go Normal file
View file

@ -0,0 +1,78 @@
package sdk
// #include <stdlib.h>
import "C"
import (
"code.icb4dc0.de/buildr/wasi-module-sdk/internal/mem"
rpcv1 "code.icb4dc0.de/buildr/wasi-module-sdk/protocol/generated/rpc/v1"
"context"
"golang.org/x/exp/slog"
)
var _ slog.Handler = (*WASIHandler)(nil)
func NewWASIHandler() WASIHandler {
return WASIHandler{}
}
type WASIHandler struct {
Level slog.Level
attrs []slog.Attr
group string
}
func (h WASIHandler) Enabled(_ context.Context, level slog.Level) bool {
return h.Level <= level
}
func (h WASIHandler) Handle(ctx context.Context, record slog.Record) error {
taskLog := rpcv1.TaskLog{
Time: record.Time.UnixMicro(),
Message: record.Message,
Level: int32(record.Level),
Attributes: make([]*rpcv1.TaskLog_LogAttribute, 0, record.NumAttrs()),
}
record.Attrs(func(attr slog.Attr) bool {
taskLog.Attributes = append(taskLog.Attributes, &rpcv1.TaskLog_LogAttribute{
Key: attr.Key,
Value: attr.Value.String(),
})
return true
})
data, err := taskLog.MarshalVT()
if err != nil {
return err
}
_log_msg(mem.DataToManagedPtr(data))
return nil
}
func (h WASIHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
newHandler := WASIHandler{
Level: h.Level,
attrs: make([]slog.Attr, 0, len(attrs)+len(h.attrs)),
}
newHandler.attrs = append(newHandler.attrs, h.attrs...)
newHandler.attrs = append(newHandler.attrs, attrs...)
return newHandler
}
func (h WASIHandler) WithGroup(name string) slog.Handler {
newHandler := WASIHandler{
Level: h.Level,
attrs: make([]slog.Attr, len(h.attrs)),
}
copy(newHandler.attrs, h.attrs)
newHandler.group = name
return newHandler
}

View file

@ -0,0 +1,990 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.30.0
// protoc (unknown)
// source: rpc/v1/executor.proto
package rpcv1
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type Buildr struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Repo *Buildr_Repo `protobuf:"bytes,1,opt,name=repo,proto3" json:"repo,omitempty"`
Github *Buildr_GitHub `protobuf:"bytes,2,opt,name=github,proto3" json:"github,omitempty"`
}
func (x *Buildr) Reset() {
*x = Buildr{}
if protoimpl.UnsafeEnabled {
mi := &file_rpc_v1_executor_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Buildr) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Buildr) ProtoMessage() {}
func (x *Buildr) ProtoReflect() protoreflect.Message {
mi := &file_rpc_v1_executor_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Buildr.ProtoReflect.Descriptor instead.
func (*Buildr) Descriptor() ([]byte, []int) {
return file_rpc_v1_executor_proto_rawDescGZIP(), []int{0}
}
func (x *Buildr) GetRepo() *Buildr_Repo {
if x != nil {
return x.Repo
}
return nil
}
func (x *Buildr) GetGithub() *Buildr_GitHub {
if x != nil {
return x.Github
}
return nil
}
type ModuleReference struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
TaskId string `protobuf:"bytes,1,opt,name=task_id,json=taskId,proto3" json:"task_id,omitempty"`
ModuleCategory string `protobuf:"bytes,2,opt,name=module_category,json=moduleCategory,proto3" json:"module_category,omitempty"`
ModuleType string `protobuf:"bytes,3,opt,name=module_type,json=moduleType,proto3" json:"module_type,omitempty"`
ModuleName string `protobuf:"bytes,4,opt,name=module_name,json=moduleName,proto3" json:"module_name,omitempty"`
}
func (x *ModuleReference) Reset() {
*x = ModuleReference{}
if protoimpl.UnsafeEnabled {
mi := &file_rpc_v1_executor_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ModuleReference) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ModuleReference) ProtoMessage() {}
func (x *ModuleReference) ProtoReflect() protoreflect.Message {
mi := &file_rpc_v1_executor_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ModuleReference.ProtoReflect.Descriptor instead.
func (*ModuleReference) Descriptor() ([]byte, []int) {
return file_rpc_v1_executor_proto_rawDescGZIP(), []int{1}
}
func (x *ModuleReference) GetTaskId() string {
if x != nil {
return x.TaskId
}
return ""
}
func (x *ModuleReference) GetModuleCategory() string {
if x != nil {
return x.ModuleCategory
}
return ""
}
func (x *ModuleReference) GetModuleType() string {
if x != nil {
return x.ModuleType
}
return ""
}
func (x *ModuleReference) GetModuleName() string {
if x != nil {
return x.ModuleName
}
return ""
}
type StartTaskRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Reference *ModuleReference `protobuf:"bytes,1,opt,name=reference,proto3" json:"reference,omitempty"`
Buildr *Buildr `protobuf:"bytes,2,opt,name=buildr,proto3" json:"buildr,omitempty"`
RawTask []byte `protobuf:"bytes,3,opt,name=raw_task,json=rawTask,proto3" json:"raw_task,omitempty"`
}
func (x *StartTaskRequest) Reset() {
*x = StartTaskRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_rpc_v1_executor_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *StartTaskRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*StartTaskRequest) ProtoMessage() {}
func (x *StartTaskRequest) ProtoReflect() protoreflect.Message {
mi := &file_rpc_v1_executor_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use StartTaskRequest.ProtoReflect.Descriptor instead.
func (*StartTaskRequest) Descriptor() ([]byte, []int) {
return file_rpc_v1_executor_proto_rawDescGZIP(), []int{2}
}
func (x *StartTaskRequest) GetReference() *ModuleReference {
if x != nil {
return x.Reference
}
return nil
}
func (x *StartTaskRequest) GetBuildr() *Buildr {
if x != nil {
return x.Buildr
}
return nil
}
func (x *StartTaskRequest) GetRawTask() []byte {
if x != nil {
return x.RawTask
}
return nil
}
type TaskResult struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Error string `protobuf:"bytes,1,opt,name=error,proto3" json:"error,omitempty"`
ModifiedFilesArchivePath string `protobuf:"bytes,2,opt,name=modified_files_archive_path,json=modifiedFilesArchivePath,proto3" json:"modified_files_archive_path,omitempty"`
}
func (x *TaskResult) Reset() {
*x = TaskResult{}
if protoimpl.UnsafeEnabled {
mi := &file_rpc_v1_executor_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *TaskResult) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*TaskResult) ProtoMessage() {}
func (x *TaskResult) ProtoReflect() protoreflect.Message {
mi := &file_rpc_v1_executor_proto_msgTypes[3]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use TaskResult.ProtoReflect.Descriptor instead.
func (*TaskResult) Descriptor() ([]byte, []int) {
return file_rpc_v1_executor_proto_rawDescGZIP(), []int{3}
}
func (x *TaskResult) GetError() string {
if x != nil {
return x.Error
}
return ""
}
func (x *TaskResult) GetModifiedFilesArchivePath() string {
if x != nil {
return x.ModifiedFilesArchivePath
}
return ""
}
type TaskLog struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Time int64 `protobuf:"varint,1,opt,name=time,proto3" json:"time,omitempty"`
Message string `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"`
Level int32 `protobuf:"varint,3,opt,name=level,proto3" json:"level,omitempty"`
Attributes []*TaskLog_LogAttribute `protobuf:"bytes,4,rep,name=attributes,proto3" json:"attributes,omitempty"`
}
func (x *TaskLog) Reset() {
*x = TaskLog{}
if protoimpl.UnsafeEnabled {
mi := &file_rpc_v1_executor_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *TaskLog) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*TaskLog) ProtoMessage() {}
func (x *TaskLog) ProtoReflect() protoreflect.Message {
mi := &file_rpc_v1_executor_proto_msgTypes[4]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use TaskLog.ProtoReflect.Descriptor instead.
func (*TaskLog) Descriptor() ([]byte, []int) {
return file_rpc_v1_executor_proto_rawDescGZIP(), []int{4}
}
func (x *TaskLog) GetTime() int64 {
if x != nil {
return x.Time
}
return 0
}
func (x *TaskLog) GetMessage() string {
if x != nil {
return x.Message
}
return ""
}
func (x *TaskLog) GetLevel() int32 {
if x != nil {
return x.Level
}
return 0
}
func (x *TaskLog) GetAttributes() []*TaskLog_LogAttribute {
if x != nil {
return x.Attributes
}
return nil
}
type SetState struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Key []byte `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"`
}
func (x *SetState) Reset() {
*x = SetState{}
if protoimpl.UnsafeEnabled {
mi := &file_rpc_v1_executor_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *SetState) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SetState) ProtoMessage() {}
func (x *SetState) ProtoReflect() protoreflect.Message {
mi := &file_rpc_v1_executor_proto_msgTypes[5]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SetState.ProtoReflect.Descriptor instead.
func (*SetState) Descriptor() ([]byte, []int) {
return file_rpc_v1_executor_proto_rawDescGZIP(), []int{5}
}
func (x *SetState) GetKey() []byte {
if x != nil {
return x.Key
}
return nil
}
func (x *SetState) GetData() []byte {
if x != nil {
return x.Data
}
return nil
}
type GetStateRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Key []byte `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
}
func (x *GetStateRequest) Reset() {
*x = GetStateRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_rpc_v1_executor_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *GetStateRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GetStateRequest) ProtoMessage() {}
func (x *GetStateRequest) ProtoReflect() protoreflect.Message {
mi := &file_rpc_v1_executor_proto_msgTypes[6]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GetStateRequest.ProtoReflect.Descriptor instead.
func (*GetStateRequest) Descriptor() ([]byte, []int) {
return file_rpc_v1_executor_proto_rawDescGZIP(), []int{6}
}
func (x *GetStateRequest) GetKey() []byte {
if x != nil {
return x.Key
}
return nil
}
type GetStateResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Key []byte `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"`
}
func (x *GetStateResponse) Reset() {
*x = GetStateResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_rpc_v1_executor_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *GetStateResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GetStateResponse) ProtoMessage() {}
func (x *GetStateResponse) ProtoReflect() protoreflect.Message {
mi := &file_rpc_v1_executor_proto_msgTypes[7]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GetStateResponse.ProtoReflect.Descriptor instead.
func (*GetStateResponse) Descriptor() ([]byte, []int) {
return file_rpc_v1_executor_proto_rawDescGZIP(), []int{7}
}
func (x *GetStateResponse) GetKey() []byte {
if x != nil {
return x.Key
}
return nil
}
func (x *GetStateResponse) GetData() []byte {
if x != nil {
return x.Data
}
return nil
}
type Result struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Success bool `protobuf:"varint,1,opt,name=success,proto3" json:"success,omitempty"`
Error string `protobuf:"bytes,2,opt,name=error,proto3" json:"error,omitempty"`
}
func (x *Result) Reset() {
*x = Result{}
if protoimpl.UnsafeEnabled {
mi := &file_rpc_v1_executor_proto_msgTypes[8]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Result) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Result) ProtoMessage() {}
func (x *Result) ProtoReflect() protoreflect.Message {
mi := &file_rpc_v1_executor_proto_msgTypes[8]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Result.ProtoReflect.Descriptor instead.
func (*Result) Descriptor() ([]byte, []int) {
return file_rpc_v1_executor_proto_rawDescGZIP(), []int{8}
}
func (x *Result) GetSuccess() bool {
if x != nil {
return x.Success
}
return false
}
func (x *Result) GetError() string {
if x != nil {
return x.Error
}
return ""
}
type Buildr_Repo struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Root string `protobuf:"bytes,1,opt,name=root,proto3" json:"root,omitempty"`
}
func (x *Buildr_Repo) Reset() {
*x = Buildr_Repo{}
if protoimpl.UnsafeEnabled {
mi := &file_rpc_v1_executor_proto_msgTypes[9]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Buildr_Repo) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Buildr_Repo) ProtoMessage() {}
func (x *Buildr_Repo) ProtoReflect() protoreflect.Message {
mi := &file_rpc_v1_executor_proto_msgTypes[9]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Buildr_Repo.ProtoReflect.Descriptor instead.
func (*Buildr_Repo) Descriptor() ([]byte, []int) {
return file_rpc_v1_executor_proto_rawDescGZIP(), []int{0, 0}
}
func (x *Buildr_Repo) GetRoot() string {
if x != nil {
return x.Root
}
return ""
}
type Buildr_GitHub struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
ApiToken string `protobuf:"bytes,1,opt,name=api_token,json=apiToken,proto3" json:"api_token,omitempty"`
}
func (x *Buildr_GitHub) Reset() {
*x = Buildr_GitHub{}
if protoimpl.UnsafeEnabled {
mi := &file_rpc_v1_executor_proto_msgTypes[10]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Buildr_GitHub) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Buildr_GitHub) ProtoMessage() {}
func (x *Buildr_GitHub) ProtoReflect() protoreflect.Message {
mi := &file_rpc_v1_executor_proto_msgTypes[10]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Buildr_GitHub.ProtoReflect.Descriptor instead.
func (*Buildr_GitHub) Descriptor() ([]byte, []int) {
return file_rpc_v1_executor_proto_rawDescGZIP(), []int{0, 1}
}
func (x *Buildr_GitHub) GetApiToken() string {
if x != nil {
return x.ApiToken
}
return ""
}
type TaskLog_LogAttribute struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
Value string `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"`
}
func (x *TaskLog_LogAttribute) Reset() {
*x = TaskLog_LogAttribute{}
if protoimpl.UnsafeEnabled {
mi := &file_rpc_v1_executor_proto_msgTypes[11]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *TaskLog_LogAttribute) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*TaskLog_LogAttribute) ProtoMessage() {}
func (x *TaskLog_LogAttribute) ProtoReflect() protoreflect.Message {
mi := &file_rpc_v1_executor_proto_msgTypes[11]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use TaskLog_LogAttribute.ProtoReflect.Descriptor instead.
func (*TaskLog_LogAttribute) Descriptor() ([]byte, []int) {
return file_rpc_v1_executor_proto_rawDescGZIP(), []int{4, 0}
}
func (x *TaskLog_LogAttribute) GetKey() string {
if x != nil {
return x.Key
}
return ""
}
func (x *TaskLog_LogAttribute) GetValue() string {
if x != nil {
return x.Value
}
return ""
}
var File_rpc_v1_executor_proto protoreflect.FileDescriptor
var file_rpc_v1_executor_proto_rawDesc = []byte{
0x0a, 0x15, 0x72, 0x70, 0x63, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x6f,
0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0d, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x72, 0x2e,
0x72, 0x70, 0x63, 0x2e, 0x76, 0x31, 0x22, 0xb1, 0x01, 0x0a, 0x06, 0x42, 0x75, 0x69, 0x6c, 0x64,
0x72, 0x12, 0x2e, 0x0a, 0x04, 0x72, 0x65, 0x70, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x1a, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x72, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x76, 0x31, 0x2e,
0x42, 0x75, 0x69, 0x6c, 0x64, 0x72, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x52, 0x04, 0x72, 0x65, 0x70,
0x6f, 0x12, 0x34, 0x0a, 0x06, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x18, 0x02, 0x20, 0x01, 0x28,
0x0b, 0x32, 0x1c, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x72, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x76,
0x31, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x72, 0x2e, 0x47, 0x69, 0x74, 0x48, 0x75, 0x62, 0x52,
0x06, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x1a, 0x1a, 0x0a, 0x04, 0x52, 0x65, 0x70, 0x6f, 0x12,
0x12, 0x0a, 0x04, 0x72, 0x6f, 0x6f, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x72,
0x6f, 0x6f, 0x74, 0x1a, 0x25, 0x0a, 0x06, 0x47, 0x69, 0x74, 0x48, 0x75, 0x62, 0x12, 0x1b, 0x0a,
0x09, 0x61, 0x70, 0x69, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
0x52, 0x08, 0x61, 0x70, 0x69, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x95, 0x01, 0x0a, 0x0f, 0x4d,
0x6f, 0x64, 0x75, 0x6c, 0x65, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x17,
0x0a, 0x07, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
0x06, 0x74, 0x61, 0x73, 0x6b, 0x49, 0x64, 0x12, 0x27, 0x0a, 0x0f, 0x6d, 0x6f, 0x64, 0x75, 0x6c,
0x65, 0x5f, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
0x52, 0x0e, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79,
0x12, 0x1f, 0x0a, 0x0b, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18,
0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x79, 0x70,
0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65,
0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x4e, 0x61,
0x6d, 0x65, 0x22, 0x9a, 0x01, 0x0a, 0x10, 0x53, 0x74, 0x61, 0x72, 0x74, 0x54, 0x61, 0x73, 0x6b,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3c, 0x0a, 0x09, 0x72, 0x65, 0x66, 0x65, 0x72,
0x65, 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x62, 0x75, 0x69,
0x6c, 0x64, 0x72, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x6f, 0x64, 0x75, 0x6c,
0x65, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x52, 0x09, 0x72, 0x65, 0x66, 0x65,
0x72, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x2d, 0x0a, 0x06, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x72, 0x18,
0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x72, 0x2e, 0x72,
0x70, 0x63, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x72, 0x52, 0x06, 0x62, 0x75,
0x69, 0x6c, 0x64, 0x72, 0x12, 0x19, 0x0a, 0x08, 0x72, 0x61, 0x77, 0x5f, 0x74, 0x61, 0x73, 0x6b,
0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x72, 0x61, 0x77, 0x54, 0x61, 0x73, 0x6b, 0x22,
0x61, 0x0a, 0x0a, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x14, 0x0a,
0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72,
0x72, 0x6f, 0x72, 0x12, 0x3d, 0x0a, 0x1b, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x5f,
0x66, 0x69, 0x6c, 0x65, 0x73, 0x5f, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x5f, 0x70, 0x61,
0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x18, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69,
0x65, 0x64, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x50, 0x61,
0x74, 0x68, 0x22, 0xca, 0x01, 0x0a, 0x07, 0x54, 0x61, 0x73, 0x6b, 0x4c, 0x6f, 0x67, 0x12, 0x12,
0x0a, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x74, 0x69,
0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20,
0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05,
0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x6c, 0x65, 0x76,
0x65, 0x6c, 0x12, 0x43, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73,
0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x72, 0x2e,
0x72, 0x70, 0x63, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x61, 0x73, 0x6b, 0x4c, 0x6f, 0x67, 0x2e, 0x4c,
0x6f, 0x67, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x52, 0x0a, 0x61, 0x74, 0x74,
0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x1a, 0x36, 0x0a, 0x0c, 0x4c, 0x6f, 0x67, 0x41, 0x74,
0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01,
0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c,
0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22,
0x30, 0x0a, 0x08, 0x53, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6b,
0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x12, 0x0a,
0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74,
0x61, 0x22, 0x23, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28,
0x0c, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x22, 0x38, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61,
0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65,
0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x12, 0x0a, 0x04,
0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61,
0x22, 0x38, 0x0a, 0x06, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75,
0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, 0x75, 0x63,
0x63, 0x65, 0x73, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x02, 0x20,
0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x42, 0xb6, 0x01, 0x0a, 0x11, 0x63,
0x6f, 0x6d, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x72, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x76, 0x31,
0x42, 0x0d, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x6f, 0x72, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50,
0x01, 0x5a, 0x3c, 0x63, 0x6f, 0x64, 0x65, 0x2e, 0x69, 0x63, 0x62, 0x34, 0x64, 0x63, 0x30, 0x2e,
0x64, 0x65, 0x2f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x72, 0x2f, 0x77, 0x61, 0x73, 0x69, 0x2d, 0x6d,
0x6f, 0x64, 0x75, 0x6c, 0x65, 0x2d, 0x73, 0x64, 0x6b, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e,
0x61, 0x6c, 0x2f, 0x72, 0x70, 0x63, 0x2f, 0x76, 0x31, 0x3b, 0x72, 0x70, 0x63, 0x76, 0x31, 0xa2,
0x02, 0x03, 0x42, 0x52, 0x58, 0xaa, 0x02, 0x0d, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x72, 0x2e, 0x52,
0x70, 0x63, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x0d, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x72, 0x5c, 0x52,
0x70, 0x63, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x19, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x72, 0x5c, 0x52,
0x70, 0x63, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74,
0x61, 0xea, 0x02, 0x0f, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x72, 0x3a, 0x3a, 0x52, 0x70, 0x63, 0x3a,
0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_rpc_v1_executor_proto_rawDescOnce sync.Once
file_rpc_v1_executor_proto_rawDescData = file_rpc_v1_executor_proto_rawDesc
)
func file_rpc_v1_executor_proto_rawDescGZIP() []byte {
file_rpc_v1_executor_proto_rawDescOnce.Do(func() {
file_rpc_v1_executor_proto_rawDescData = protoimpl.X.CompressGZIP(file_rpc_v1_executor_proto_rawDescData)
})
return file_rpc_v1_executor_proto_rawDescData
}
var file_rpc_v1_executor_proto_msgTypes = make([]protoimpl.MessageInfo, 12)
var file_rpc_v1_executor_proto_goTypes = []interface{}{
(*Buildr)(nil), // 0: buildr.rpc.v1.Buildr
(*ModuleReference)(nil), // 1: buildr.rpc.v1.ModuleReference
(*StartTaskRequest)(nil), // 2: buildr.rpc.v1.StartTaskRequest
(*TaskResult)(nil), // 3: buildr.rpc.v1.TaskResult
(*TaskLog)(nil), // 4: buildr.rpc.v1.TaskLog
(*SetState)(nil), // 5: buildr.rpc.v1.SetState
(*GetStateRequest)(nil), // 6: buildr.rpc.v1.GetStateRequest
(*GetStateResponse)(nil), // 7: buildr.rpc.v1.GetStateResponse
(*Result)(nil), // 8: buildr.rpc.v1.Result
(*Buildr_Repo)(nil), // 9: buildr.rpc.v1.Buildr.Repo
(*Buildr_GitHub)(nil), // 10: buildr.rpc.v1.Buildr.GitHub
(*TaskLog_LogAttribute)(nil), // 11: buildr.rpc.v1.TaskLog.LogAttribute
}
var file_rpc_v1_executor_proto_depIdxs = []int32{
9, // 0: buildr.rpc.v1.Buildr.repo:type_name -> buildr.rpc.v1.Buildr.Repo
10, // 1: buildr.rpc.v1.Buildr.github:type_name -> buildr.rpc.v1.Buildr.GitHub
1, // 2: buildr.rpc.v1.StartTaskRequest.reference:type_name -> buildr.rpc.v1.ModuleReference
0, // 3: buildr.rpc.v1.StartTaskRequest.buildr:type_name -> buildr.rpc.v1.Buildr
11, // 4: buildr.rpc.v1.TaskLog.attributes:type_name -> buildr.rpc.v1.TaskLog.LogAttribute
5, // [5:5] is the sub-list for method output_type
5, // [5:5] is the sub-list for method input_type
5, // [5:5] is the sub-list for extension type_name
5, // [5:5] is the sub-list for extension extendee
0, // [0:5] is the sub-list for field type_name
}
func init() { file_rpc_v1_executor_proto_init() }
func file_rpc_v1_executor_proto_init() {
if File_rpc_v1_executor_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_rpc_v1_executor_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Buildr); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_rpc_v1_executor_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ModuleReference); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_rpc_v1_executor_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*StartTaskRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_rpc_v1_executor_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*TaskResult); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_rpc_v1_executor_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*TaskLog); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_rpc_v1_executor_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*SetState); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_rpc_v1_executor_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*GetStateRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_rpc_v1_executor_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*GetStateResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_rpc_v1_executor_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Result); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_rpc_v1_executor_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Buildr_Repo); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_rpc_v1_executor_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Buildr_GitHub); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_rpc_v1_executor_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*TaskLog_LogAttribute); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_rpc_v1_executor_proto_rawDesc,
NumEnums: 0,
NumMessages: 12,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_rpc_v1_executor_proto_goTypes,
DependencyIndexes: file_rpc_v1_executor_proto_depIdxs,
MessageInfos: file_rpc_v1_executor_proto_msgTypes,
}.Build()
File_rpc_v1_executor_proto = out.File
file_rpc_v1_executor_proto_rawDesc = nil
file_rpc_v1_executor_proto_goTypes = nil
file_rpc_v1_executor_proto_depIdxs = nil
}

File diff suppressed because it is too large Load diff

47
registry.go Normal file
View file

@ -0,0 +1,47 @@
package sdk
import (
"fmt"
"sync"
)
type Registration interface {
RegisterAt(registry *TypeRegistry)
}
type RegistrationFunc func(registry *TypeRegistry)
func (f RegistrationFunc) RegisterAt(registry *TypeRegistry) {
f(registry)
}
func NewTypeRegistry() *TypeRegistry {
return &TypeRegistry{
registrations: make(map[string]Factory),
}
}
type TypeRegistry struct {
lock sync.Mutex
registrations map[string]Factory
}
func (r *TypeRegistry) Add(cat Category, moduleName string, factory Factory) {
r.lock.Lock()
defer r.lock.Unlock()
r.registrations[specOf(cat, moduleName)] = factory
}
func (r *TypeRegistry) Get(cat Category, moduleName string) Module {
f, ok := r.registrations[specOf(cat, moduleName)]
if !ok {
return nil
}
return f.Create()
}
func specOf(cat Category, moduleName string) string {
return fmt.Sprintf("%s/%s", cat.String(), moduleName)
}

67
state_proxy.go Normal file
View file

@ -0,0 +1,67 @@
package sdk
import (
"code.icb4dc0.de/buildr/wasi-module-sdk/internal/mem"
rpcv1 "code.icb4dc0.de/buildr/wasi-module-sdk/protocol/generated/rpc/v1"
"errors"
)
type StateProxy struct {
}
func (s StateProxy) Set(key, state []byte) error {
setCmd := &rpcv1.SetState{
Key: key,
Data: state,
}
data, err := setCmd.MarshalVT()
if err != nil {
return err
}
result := _set_state(mem.DataToManagedPtr(data))
if result == 0 {
return errors.New("unknown error occurred")
}
resultPtr := uint32(result >> 32)
resultSize := uint32(result)
resultMsg := new(rpcv1.Result)
if err := resultMsg.UnmarshalVT(mem.PtrToData(resultPtr, resultSize)); err != nil {
return err
}
if !resultMsg.Success {
if resultMsg.Error != "" {
return errors.New(resultMsg.Error)
}
return errors.New("unknown error occurred")
}
return nil
}
func (s StateProxy) Get(key []byte) (state []byte, meta StateMetadata, err error) {
getCmd := &rpcv1.GetStateRequest{
Key: key,
}
data, err := getCmd.MarshalVT()
if err != nil {
return nil, StateMetadata{}, err
}
result := _get_state(mem.DataToManagedPtr(data))
if result == 0 {
return nil, StateMetadata{}, errors.New("error occurred while processing request")
}
resultPtr := uint32(result >> 32)
resultSize := uint32(result)
getStateResult := new(rpcv1.GetStateResponse)
if err := getStateResult.UnmarshalVT(mem.PtrToData(resultPtr, resultSize)); err != nil {
return nil, StateMetadata{}, err
}
return getStateResult.Data, StateMetadata{}, nil
}

View file

@ -1,62 +0,0 @@
package test
import (
rpcv1 "buf.build/gen/go/buildr/buildr/protocolbuffers/go/rpc/v1"
"context"
"errors"
"github.com/tetratelabs/wazero"
"github.com/tetratelabs/wazero/api"
"github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1"
"golang.org/x/exp/slog"
"google.golang.org/protobuf/proto"
)
type Host struct {
Logger *slog.Logger
}
func (h *Host) Run(ctx context.Context) (err error) {
r := wazero.NewRuntime(ctx)
defer r.Close(context.Background())
_, err = r.NewHostModuleBuilder("test").
NewFunctionBuilder().WithFunc(h.log).Export("log").
Instantiate(ctx)
if err != nil {
return err
}
closer, err := wasi_snapshot_preview1.Instantiate(ctx, r)
if err != nil {
return err
}
defer func() {
err = errors.Join(err, closer.Close(context.Background()))
}()
return nil
}
func (h *Host) log(ctx context.Context, m api.Module, offset, byteCount uint32) {
buf, ok := m.Memory().Read(offset, byteCount)
if !ok {
return
}
var taskLog *rpcv1.TaskLog
if err := proto.Unmarshal(buf, taskLog); err != nil {
h.Logger.Warn("failed to unmarshal task log", slog.String("err", err.Error()))
return
}
rec := slog.NewRecord(taskLog.Time.AsTime(), slog.Level(taskLog.Level), taskLog.Message, -1)
for i := range taskLog.Attributes {
attr := taskLog.Attributes[i]
rec.AddAttrs(slog.String(attr.Key, attr.Value))
}
_ = h.Logger.Handler().Handle(ctx, rec)
}