Hey Team, looking to write an external tool to sup...
# plugins
r
Hey Team, looking to write an external tool to support twirp, specifically using the twirpy protoc plugin. One requirement to use the tool is to install it via
go
with
Copy code
go install <http://github.com/verloop/twirpy/protoc-gen-twirpy@latest|github.com/verloop/twirpy/protoc-gen-twirpy@latest>
Is it possible to use
go
like this in pants via an external tool? Or would we need to install
go
as an external tool first and then we can install plugins with it?
f
See https://github.com/pantsbuild/pants/pull/13985 for an example of how to install a Go tool for use in Pants.
That PR has not landed yet because of https://github.com/pantsbuild/pants/issues/14258, but the code to install a Go tool should be usable as an example.
Is the generated code going to be in Go or another language?
r
this is great example I'll give that a shot! This is going to be codegen for
Python
f
Cool. So you won't be affected by https://github.com/pantsbuild/pants/issues/14258 then.
r
does this also handle installing
go
for the plugin run or is it required that the host machine has
go
installed?
f
The Go backend requires having
go
already available. We would like to return to Pants managing that but have not done that work yet. (There had been performance issues with unpacking the Go SDK in every execution sandbox.)
2
r
okay got it that make sense not a problem to have it preinstalled.
running into an issue testing a simple plugin:
Copy code
njgrisafi@Nicks-MacBook-Pro ~/workspace/pants-example (twirp-example)$ ./pants export-codegen ::
18:12:54.37 [INFO] Initializing scheduler...
18:12:54.67 [INFO] Scheduler initialized.
18:12:54.74 [ERROR] 1 Exception encountered:

  InvalidFieldException: Unrecognized field `twirp=True` in target app:proto. Valid fields for the target type `protobuf_sources`: ['dependencies', 'description', 'grpc', 'overrides', 'python_interpreter_constraints', 'python_source_root', 'sources', 'tags'].
I'm attempting to extend the existing target
ProtobufSourceTarget
to add a new field for
twirp
. I see the option when running
./pants help protobuf_source
but running any other goal results in the error above. Example repo here for the plugin: https://github.com/njgrisafi/pants-example/tree/twirp-example follow these docs for setup: • https://www.pantsbuild.org/docs/target-api-extending-targetshttps://www.pantsbuild.org/docs/plugins-codegen
f
Is the call to register the plugin field actually being invoked?
i.e., calls to both
ProtobufSourceTarget.register_plugin_field
and
ProtobufSourcesGeneratorTarget.register_plugin_field
and the error is for
protobuf_sources
(plural), so probaly missing the second call
r
hmm actually it doesn't seem to be calling the register for the plugin (it was before). Digging into this
oh no you're right it's enabled on
protobuf_source
but not
protobuf_source*s*
Is this how we would register it on both target types?
Copy code
def rules() -> Iterable[Rule]:
    return [
        ProtobufSourceTarget.register_plugin_field(ProtobufTwirpField),
        ProtobufSourcesGeneratorTarget.register_plugin_field(ProtobufTwirpField),
    ]
ohh that looked like it worked!
it seems to be an issue with this rule: https://github.com/njgrisafi/pants-example/blob/9f07e6488453df63ab8095b797d89c2a87c0b931/pants-plugins/python_twirp/rules.py#L58-L81 when I remove it from rule args the error goes away
ahh fixed this by adding
*sdk.rules()
to the rules list
however, running
./pants export-codegen ::
doesn't seem to be triggering the rule. I have set the option here: https://github.com/njgrisafi/pants-example/blob/aa75626fe1d10ebf311c49be16bf03492ed6162a/app/BUILD#L3 is there something else we need?
f
are you able to put the sources somewhere?
never mind, I see earlier link to sources
the
UnionRule
is commented out
r
I can run the goals but it doesn't trigger the rule
f
the input on the request type is wrong:
input = ProtobufTwirpField
should be
input = ProtobufSourceField
ProtobufTwirpField
is just an extra field that you are registering on the targets. The
GenerateSourcesRequest
needs the input and output source fields
r
I tried that but get the following error:
Copy code
njgrisafi@Nicks-MacBook-Pro ~/workspace/pants-example (twirp-example)$ ./pants export-codegen ::
19:40:59.75 [INFO] Initializing scheduler...
19:41:00.44 [INFO] Scheduler initialized.
19:41:00.52 [ERROR] 1 Exception encountered:

  AmbiguousCodegenImplementationsException: Multiple of the registered code generators can generate PythonSourceField from ProtobufSourceField. It is ambiguous which implementation to use.

Possible implementations:

  * GeneratePythonFromProtobufRequest
  * GeneratePythonFromTwirpRequest
f
you’ll need to disable the
pants.backend.codegen.protobuf.python
backend
we’ve had some discussion in https://github.com/pantsbuild/pants/issues/14041 about other ways to deal with conflicting codegen implementations.
r
Copy code
njgrisafi@Nicks-MacBook-Pro ~/workspace/pants-example (twirp-example)$ ./pants export-codegen ::
19:43:50.95 [INFO] Initializing scheduler...
19:43:51.22 [INFO] Scheduler initialized.
19:43:51.28 [ERROR] 1 Exception encountered:

  MappingError: Failed to parse ./app/BUILD:
Name 'protobuf_sources' is not defined.

If you expect to see more symbols activated in the below list, refer to <https://www.pantsbuild.org/v2.9/docs/enabling-backends> for all available backends to activate.

All registered symbols: ['_python_requirements_file', 'archive', 'docker_image', 'file', 'files', 'pants_requirement', 'pants_requirements', 'pex_binary', 'pipenv_requirements', 'poetry_requirements', 'python_artifact', 'python_distribution', 'python_requirement', 'python_requirements', 'python_source', 'python_sources', 'python_test', 'python_test_utils', 'python_tests', 'relocated_files', 'resource', 'resources', 'setup_py', 'target']
Maybe I just need to register the rule for target type, think I know how to fix this
f
you should just register both protobuf target types in your twirp plugin in the
target_types
method
that is how the existing Python protobuf backend does it
r
yeah Ideally I'd like to have the native python codegen + this additional codegen to generate
twirpy
originally I was thinking that this can probably be added to the existing plugin upstream
yeah Ideally I’d like to have the native python codegen + this additional codegen to generate 
twirpy
 originally I was thinking that this can probably be added to the existing plugin upstream
yeah it might make sense for an upstream contribution to the existing codegen
👍 1
or we figure out a way to make the plugin API more amenable to side-by-side codegen impls for same language / codegen type
r
yeah the only gotcha with
twirpy
is you have to have that go plugin installed for it I believe
so it sounds like now I should just copy the existing
python_protobuf
plugin and extend it to work with
twirpy
and if it works well I can create a PR to upstream
f
idea for better API: modify the existing Python protobuf backend to expose and use a union for RPC codegen backends to be called by the Python protobuf backend at the right time. then refactor grpc to use that union. then twirp could also use that union.
💯 1
so it sounds like now I should just copy the existing 
python_protobuf
 plugin and extend it to work with 
twirpy
  and if it works well I can create a PR to upstream
probably lots of copy pasta, but that would work in the meantime
r
yeah that would be great for the API! Yeah and I don't want to diverge too far from upstream changes just to add one more feature but will work for now. Let me give that a go
f
and to refine the better API idea: the exposed union could be to allow grpc and twirp to add additional protoc plugins (and CLI args) to the protoc invocation
r
looks like this rule is outputting an error: https://github.com/njgrisafi/pants-example/blob/0bbaea7cfb8a39af8839829f85231bf91b49b763/pants-plugins/custom_python_protobuf/rules.py#L71-L93
Copy code
njgrisafi@Nicks-MacBook-Pro ~/workspace/pants-example (twirp-example)$ ./pants export-codegen ::
20:11:23.01 [INFO] Initializing scheduler...
20:11:23.28 [INFO] Scheduler initialized.
20:11:23.80 [ERROR] 1 Exception encountered:

  ProcessExecutionFailure: Process 'Build Go twirpy protobuf plugin for `protoc`.' failed with exit code 1.
stdout:

stderr:
go install: <http://github.com/verloop/twirpy/protoc-gen-twirpy@latest|github.com/verloop/twirpy/protoc-gen-twirpy@latest>: module lookup disabled by GOPROXY=off



Use `--no-process-cleanup` to preserve process chroots for inspection.
oh do I need this?
Copy code
download_sources_result = await Get(
        ProcessResult,
        GoSdkProcess(
            ["mod", "download", "all"],
            input_digest=go_mod_digest,
            output_directories=("gopath",),
            description="Download Go `protoc` plugin sources.",
            allow_downloads=True,
        ),
    )
ohh think it's working after adding
allow_downloads=True,
to the install on
go_twirpy_plugin_build_result
got it working 🎉 if you're interested take a look at the custom plugin here: https://github.com/njgrisafi/pants-example/tree/twirp-example/pants-plugins/custom_python_protobuf when you run
./pants export-codegen ::
you should now see twirp codegen in
dist
thank you so much @fast-nail-55400!!!
🎉 1