An open API service indexing awesome lists of open source software.

https://github.com/stackb/protoc-gen-starlark

Scriptable protoc plugins
https://github.com/stackb/protoc-gen-starlark

Last synced: 10 months ago
JSON representation

Scriptable protoc plugins

Awesome Lists containing this project

README

          

[![CI](https://github.com/stackb/protoc-gen-starlark/actions/workflows/ci.yaml/badge.svg)](https://github.com/stackb/protoc-gen-starlark/actions/workflows/ci.yaml)

# protoc-gen-starlark







protobuf
starlark

`protoc-gen-starlark` is a scriptable protocol buffer plugin. It might just be
the the easiest way to write a protoc plugin! 😍

## Installation

Download a binary from the [releases
page](https://github.com/stackb/protoc-gen-starlark/releases), or install from source:

```sh
go install github.com/stackb/protoc-gen-starlark/cmd/protoc-gen-starlark@latest
```

## Usage

`protoc-gen-starlark` works like any other typical protoc plugin: it reads an
encoded `CodeGeneratorRequest` from stdin and writes an encoded
`CodeGeneratorResponse` to stdout.

The logic of generating a response is performed within a starlark script that
you must write. The simplest such script looks something like:

```py
pb = proto.package("google.protobuf.compiler")

def generate(request):
"""generate prepares the response.

Args:
request: the pb.CodeGeneratorRequest that was read from stdin.
Returns:
a pb.CodeGeneratorResponse
"""
return pb.CodeGeneratorResponse(
error = "not implemented",
)

def main(ctx):
"""main is the entrypoint function.

Args:
ctx: the script context. It has a struct member named
'vars' which is a StringDict of variables injected into
the entrypoint. vars is guaranteed to have an entry named
"request" that is the pb.CodeGeneratorRequest read from stdin.
Returns:
A single pb.CodeGeneratorResponse. Per skycfg semantics,
the return value from `main` must be a list however so it
is wrapped accordingly.

"""
return [generate(ctx.vars["request"])]
```

Although starlark is an interpreted language, the protobuf message types are stongly typed: it is an error to set/get fields that are not part of the message definition. See [stackb/grpc-starlark](https://github.com/stackb/grpc-starlark) and [stripe/skycfg](https://github.com/stripe/skycfg) for more details about this.

> `protoc-gen-starlark` is built using
> [stackb/grpc-starlark](https://github.com/stackb/grpc-starlark) and shares the
> same command line flags.

A sample protoc invocation might look something like:

```sh
$ export PROTOC_GEN_STARLARK_SCRIPT=foo.star
$ protoc \
--foo_out=./gendir \
--plugin=protoc-gen-foo=/usr/bin/protoc-gen-starlark
```

In this case `protoc-gen-starlark` discovers which script to evaluate using the
`PROTOC_GEN_STARLARK_SCRIPT` environment variable.

Another strategy is to copy/rename `protoc-gen-starlark` and the script to a
common name. If a file named `$0.star` exists where `$0` is the name of the
executable itself, this will be loaded. For example:

```sh
$ ln -s /usr/bin/protoc-gen-starlark tools/protoc-gen-foo
$ mv foo.plugin.star tools/protoc-gen-foo.star
$ ln -s /usr/bin/protoc-gen-starlark tools/protoc-gen-bar
$ mv bar.plugin.star tools/protoc-gen-bar.star

$ protoc \
--foo_out=./gendir \
--plugin=protoc-gen-foo=./tools/protoc-gen-foo
--bar_out=./gendir \
--plugin=protoc-gen-bar=./tools/protoc-gen-bar
```

Alternatively, a shell script can be used to wrap the invocation of the plugin:

```sh
#!/bin/bash

# protoc-gen-foo.sh wraps protoc-gen-starlark and sets
# the file argument explicitly.

set -euox pipefail

/usr/bin/protoc-gen-starlark \
-file ./tools/protoc-gen-foo.star
```

```sh
$ protoc \
--foo_out=./gendir \
--plugin=protoc-gen-foo=./tools/protoc-gen-foo.sh
```

By default, the message types from
[plugin.proto](https://github.com/protocolbuffers/protobuf/blob/main/src/google/protobuf/compiler/plugin.proto)
are pre-loaded. You can make additional types available to `proto.package`
using the `--protoset=/path/to/a/descriptor_set_out.pb` flag.