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

cmd/protoc-gen-go-grpc: add code generator #3453

Merged
merged 1 commit into from
May 27, 2020
Merged

Conversation

neild
Copy link
Contributor

@neild neild commented Mar 12, 2020

Add a code generator for gRPC services.

No tests included here. A followup PR updates code generation to use
this generator, which acts as a test of the generator as well.


g.P("// ", clientName, " is the client API for ", service.GoName, " service.")
g.P("//")
g.P("// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.")
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we make this link to go.dev?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

Comment on lines 19 to 31
// protoc-gen-go is a plugin for the Google protocol buffer compiler to generate
// Go code. Install it by building this program and making it accessible within
// your PATH with the name:
// protoc-gen-go
//
// The 'go' suffix becomes part of the argument for the protocol compiler,
// such that it can be invoked as:
// protoc --go_out=paths=source_relative:. path/to/file.proto
//
// This generates Go bindings for the protocol buffer defined by file.proto.
// With that input, the output will be written to:
// path/to/file.pb.go
//
// See the README and documentation for protocol buffers to learn more:
// https://developers.google.com/protocol-buffers/
package main
Copy link
Contributor

Choose a reason for hiding this comment

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

This looks wrong

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oops, forgot to update the doc comment when copying this file. Fixed.

Copy link
Member

@jhump jhump left a comment

Choose a reason for hiding this comment

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

Is this something that can be merged soon?

I decided to start a v2 of my protoreflect library, to update it to use the latest APIv2 for the protobuf runtime. But I quickly wound up stuck because the new protoc-gen-go can't generate gRPC stuff. I am keen to start kicking the tires on these things.

I guess in the meantime, I'll just check out this pull request locally and try out the protoc-gen-go-grpc command that way.

@@ -0,0 +1,8 @@
module google.golang.org/grpc/cmd/protoc-gen-go-grpc

go 1.14
Copy link
Member

Choose a reason for hiding this comment

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

I know Go 1.11 is not technically supported by the Go team anymore. But if AppEngine is still a supported target, it still has a Go 1.11 runtime. And Go 1.11 does not gracefully handle these go version declarations.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

1.14 was inadvertent. Changed to 1.9, which is the oldest Go version supported by the protobuf module(s).

It's unfortunate that 1.9 is different than the version supported by the top-level gRPC module, but I think it's better (and possibly necessary) for this to remain in sync with the protobuf module which will import it.

@meling
Copy link
Contributor

meling commented Mar 17, 2020

Seems vet is failing this.

cmd/protoc-gen-go-grpc/internal_gengogrpc/grpc.go:23:1: don't use an underscore in package name

Begs the question, why use underscore in the package name, going against stated package naming guidelines? I was initially wondering if this worked similar to the internal package, but it doesn't, so the package .../internal_gengogrpc is publicly accessible. It is unclear what the intention is.

This is also annoying when opening the project in VSCode, which in the default setup has vet running and calls these out as warnings...

@neild
Copy link
Contributor Author

neild commented Mar 17, 2020

Begs the question, why use underscore in the package name, going against stated package naming guidelines? I was initially wondering if this worked similar to the internal package, but it doesn't, so the package .../internal_gengogrpc is publicly accessible. It is unclear what the intention is.

The intent was to have a clear visual indication to users that this isn't a package intended for general use. Running "internalgengogrpc" together makes the "internal" name fade into the background, for me at least.

Changed to just "gengogrpc", since this package is less internal than it was when it lived in the google.golang.org/protobuf repo; it's now a point of contact between two separate projects, rather than two revisions of the same project.

@pjediny
Copy link

pjediny commented Mar 18, 2020

@neild if you did not want to have it public, why didn't you just put it in subfolder like internal/gengogrpc?

@neild
Copy link
Contributor Author

neild commented Mar 18, 2020

@neild if you did not want to have it public, why didn't you just put it in subfolder like internal/gengogrpc?

We want the github.com/golang/protobuf/protoc-gen-go binary to continue to support gRPC code generation, to avoid breaking users who depend on it doing so. (In contrast, the brand-new google.golang.org/protobuf/cmp/protoc-gen-go binary does not support gRPC and is intended to be used in conjunction with protoc-gen-go-grpc.)

To allow github.com/golang/protobuf/protoc-gen-go to generate gRPC service definitions, it needs to be able to import the gRPC code generator. Therefore, the gengogrpc package can't be internal to the gRPC module.

g.P(deprecationComment)
}
serviceDescVar := "_" + service.GoName + "_serviceDesc"
g.P("func Register", service.GoName, "Server(s *", grpcPackage.Ident("Server"), ", srv ", serverType, ") {")
Copy link

@achew22 achew22 Mar 21, 2020

Choose a reason for hiding this comment

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

Would it be possible to have Register${service.GoName}Server take an interface with RegisterService on it instead of the concrete type? This would be useful in testing to allow registration in other objects.

I attempted this PR in the other protobuf repo, but it seems the princess might be in this castle instead golang/protobuf#1060

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This PR shouldn't introduce any changes from the current implementation; it moves where the generator is located, but not any of the semantics. Any changes to semantics should happen as a followup PR once this is merged.

Copy link

Choose a reason for hiding this comment

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

That's very reasonable. Do you know what the timeline on that is? I'm not looking for a date, O(days), O(weeks), or O(months)? I'm trying to scope of I can postpone my project, or if I should temporarily apply patches to the compiler in my repo.

Also, I'm so excited for the V2 API. It looks like you've done a wonderful job. Thanks for all your hard work!

@baolitoumu
Copy link

Is anyone here. Sorry, because many people are waiting, it is very painful

@dfawley
Copy link
Member

dfawley commented Apr 23, 2020

This is on my plate. Sorry for the delay - I'm behind on many things right now, not just this. I hope to get to it soon.

@tmc
Copy link

tmc commented Apr 27, 2020

Hopefully this can get in this week!

@odsod
Copy link

odsod commented Apr 29, 2020

Is this really a blocker? We bumped our github.com/golang/protobuf/protoc-gen-go plugin to v1.4.0 and are generating v2 proto and gRPC stubs.

It should not be necessary to block on this PR to start using the v2 APIs in gRPC setups. Just bump github.com/golang/protobuf/protoc-gen-go to 1.4.0 and run with plugins=grpc until the new protoc plugin lands on the master branch over here.

Copy link
Member

@dfawley dfawley left a comment

Choose a reason for hiding this comment

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

Sorry for the excessive delay in reviewing.

Comment on lines 63 to 67
// TODO: Remove this. We don't need to include these references any more.
g.P("// Reference imports to suppress errors if they are not otherwise used.")
g.P("var _ ", contextPackage.Ident("Context"))
g.P("var _ ", grpcPackage.Ident("ClientConnInterface"))
g.P()
Copy link
Member

Choose a reason for hiding this comment

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

Why is this a TODO, then?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Removed.

Comment on lines 153 to 148
g.P("// Unimplemented", serverType, " can be embedded to have forward compatible implementations.")
g.P("type Unimplemented", serverType, " struct {")
Copy link
Member

Choose a reason for hiding this comment

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

Is this an acceptable time to change behavior and require this to be embedded for all services? Or is it required that no changes are needed in your code when switching from v1 to v2 proto?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Up to you and whatever your compatibility guarantees are. This would, of course, be a breaking change which would require that all users change their code before using the new generator.

If we were to leave the generator in github.com/golang/protobuf unchanged and independent of the one here, then this might be a reasonable time to make a breaking change--since this is a brand new generator, it has no existing users. On the other hand, doing so will serve as an additional barrier for users migrating from the old one.

Either way, my preference would be to submit this CL with the existing API to provide a baseline identical to the current version and for you to make whatever changes you want in a followup change.

Copy link
Member

Choose a reason for hiding this comment

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

This would be a pretty good opportunity to do this, but it's probably not reasonable to require code changes in order to run the generator from a new location. But if we check this code in without that requirement, then I don't think we'll ever be able to do it.

Comment on lines 21 to 22
// This package is exported to permit github.com/golang/protobuf/protoc-gen-go
// to depend on it. No other packages should depend on it.
Copy link
Member

Choose a reason for hiding this comment

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

So the plan is to delete the code there and reference this code instead?

This has pros and cons:

  • Pro: v1 and v2 codegen do not need to be maintained separately
  • Con: changes here will impact the v1 codegen, meaning we need to test the v1 codegen (in the other repo) if we want to make changes here.

Might it be better to just have separate implementations and allow them to drift? (Also: clearly marking the v1 codegen as deprecated and no longer receiving new features.)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

My plan had been to delete the generator from github.com/golang/protobuf and reference the one here. If you'd rather we deprecate that one and let it drift, I'm fine with that approach. What's your preference?

Copy link
Contributor

Choose a reason for hiding this comment

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

Not sure that the con is as significant, since github.com/golang/protobuf can specify that they depend on a specific version of the generator herein. Since v1 is not meant to be receiving new features, they should not advance to newer versions of the grpc gen, except for important bug fixes that advance only the minor version number. This should reduce the need for cross-repo testing to those bug fixes that are deemed necessary to backport to v1. That said, I think both strategies are fine.

Copy link
Member

Choose a reason for hiding this comment

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

I'd rather let them drift and mark the old one as deprecated. Then we don't need to export code from here that is internal-only, which I see as a win. Even though anyone else would be crazy to use it, if we were to change it, it would be a breaking change for the code in the proto repo referencing it.

@dfawley dfawley merged commit 6c9e30c into grpc:master May 27, 2020
@dfawley
Copy link
Member

dfawley commented May 27, 2020

Even with this merged, it is unreleased (v0.0) and subject to change. We do plan to add a requirement that the Unimplemented service implementation be included in all registered services, with an escape hatch in the form of a command-line arg as suggested by @neild.

@johanbrandhorst
Copy link
Contributor

So happy to finally see this merged, great work!

@chalin
Copy link
Contributor

chalin commented Jun 23, 2020

Even with this merged, it is unreleased (v0.0) and subject to change. We do plan to add ...

@dfawley - is there an issue I can use to track the release?

@dfawley
Copy link
Member

dfawley commented Jun 23, 2020

Let's use #3669 to track this work for now.

@jeffwidman
Copy link

@dfawley is that the correct issue number? That issue looks unrelated, unless I misunderstand something?

@ydnar
Copy link

ydnar commented Jun 23, 2020

Somewhat related: would you consider moving the code-generation parts of this out of package main into a sub-package that can be imported by another program?

@dfawley
Copy link
Member

dfawley commented Jun 26, 2020

@jeffwidman yes, that's the right one :) That's the only thing blocking a 1.0 release of the tool.

Somewhat related: would you consider moving the code-generation parts of this out of package main into a sub-package that can be imported by another program?

Probably not, but it would be interesting to hear your use case(s). I'd rather not have to maintain a separate library for this, guaranteeing backward compatibility forever, unless it's important to do so.

@ydnar
Copy link

ydnar commented Jun 26, 2020

Somewhat related: would you consider moving the code-generation parts of this out of package main into a sub-package that can be imported by another program?

Probably not, but it would be interesting to hear your use case(s). I'd rather not have to maintain a separate library for this, guaranteeing backward compatibility forever, unless it's important to do so.

As the protogen package allows for protoc plugins to adapt the Protobuf AST prior to Go code generation, I think splitting out the generateFile function into its own package would allow adaptation of the AST prior to serialization without forking the entire repo or command.

e.g. something like a cmd/protoc-gen-go-grpc/grpcgen package, with a single entry point (GenerateFile) with the same method signature as the existing generateFile.

A caller would have two opportunities to adapt the output:

  1. Modify the input in the protogen.Plugin
  2. Modify the output in the response.

@dfawley
Copy link
Member

dfawley commented Jun 26, 2020

Interesting. This is a very high level function. Since it's so high level, it should be possible to accomplish these things as a separate step before/after running the generator as a binary. But on the other hand, it would be possible to support this kind of API with minimal effort. Would you mind filing an issue for this?

@neild
Copy link
Contributor Author

neild commented Jun 26, 2020

As the protogen package allows for protoc plugins to adapt the Protobuf AST prior to Go code generation

I'm not certain what this means.

The protogen package is a toolkit for writing protoc plugins that generate Go code. It provides a view of the protobuf descriptors with annotations about the canonical Go names for various objects (messages, fields, etc.).

We do not support modifying the code generated by protoc-gen-go, however. The protogen package does not provide access to the generated code, and it does not support modifying the descriptors handled by protoc-gen-go.

@ydnar
Copy link

ydnar commented Jun 26, 2020

As the protogen package allows for protoc plugins to adapt the Protobuf AST prior to Go code generation

I'm not certain what this means.

The protogen package is a toolkit for writing protoc plugins that generate Go code. It provides a view of the protobuf descriptors with annotations about the canonical Go names for various objects (messages, fields, etc.).

We do not support modifying the code generated by protoc-gen-go, however. The protogen package does not provide access to the generated code, and it does not support modifying the descriptors handled by protoc-gen-go.

You can modify the generated Go identifiers in protogen prior to code generation.

@dsnet
Copy link
Contributor

dsnet commented Jun 26, 2020

As mentioned in another comment, mutation of data structures returned by protogen is not a supported use case and subject to breakage in the future as it will likely violate consistency invariants.

@ydnar
Copy link

ydnar commented Jun 26, 2020

As mentioned in another comment, mutation of data structures returned by protogen is not a supported use case and subject to breakage in the future as it will likely violate consistency invariants.

Then why does the protogen package, and its exported identifiers exist at all?

@dsnet
Copy link
Contributor

dsnet commented Jun 26, 2020

Because other things need read-only access to them are there is no language feature for immutability.

@cee-dub
Copy link

cee-dub commented Jun 26, 2020

Perhaps your team should add some documentation to protogen to this effect since your stance seems to be "nobody should touch this output, if you want different Go code to represent your protos you must fork the generator."

https://github.com/protocolbuffers/protobuf-go/blob/a9513ebdb86068803ccda83ded57e8330a72961e/compiler/protogen/protogen.go#L5-L11

@neild
Copy link
Contributor Author

neild commented Jun 26, 2020

The protogen package doesn't produce generated code. We don't provide any public packages which produce generated protocol buffer code. It's used by the tools which produce generated code (protoc-gen-go, protoc-gen-go-grpc).

@ydnar
Copy link

ydnar commented Jun 26, 2020

The protogen package doesn't produce generated code. We don't provide any public packages which produce generated protocol buffer code. It's used by the tools which produce generated code (protoc-gen-go, protoc-gen-go-grpc).

We’re well aware. We use protogen to fix the non-idiomatic Go code that protoc-gen-go* generates.

https://github.com/alta/protopatch

rolinh added a commit to cilium/cilium that referenced this pull request Jul 27, 2020
Commit `f18fcd9b` updated the following dependencies:

  - github.com/golang/protobuf: v1.3.2  => v1.4.2
  - google.golang.org/genproto
  - google.golang.org/grpc:     v1.26.0 => v1.27.0

However, the protobuf generated files were not re-generated which is
what this commit addresses.

The newly generated files should be backward compatible. However, the
following warning is now emitted when generating them:

  WARNING: Package "github.com/golang/protobuf/protoc-gen-go/generator"
           is deprecated.
           A future release of golang/protobuf will delete this package,
           which has long been excluded from the compatibility promise.

This is because this package was apparently never meant to be public as
explained in this comment[0]. The fix for this is to migrate to
`google.golang.org/protobuf/compiler/protogen` but this can't be done
until a release of `grpc-go` which includes the following patch[1] is
out. Update the Makefile to output a note with regard to this when generating
the files

It appears that with the newly generated files, protobuf now needs to
be marked as an explicit dep. Fix it by by running:

    go mod tidy && go mod vendor && go mod verify

Fix: f18fcd9

[0]: golang/protobuf#1104 (comment)
[1]: grpc/grpc-go#3453

Signed-off-by: Robin Hahling <robin.hahling@gw-computing.net>
gandro pushed a commit to cilium/cilium that referenced this pull request Jul 27, 2020
Commit `f18fcd9b` updated the following dependencies:

  - github.com/golang/protobuf: v1.3.2  => v1.4.2
  - google.golang.org/genproto
  - google.golang.org/grpc:     v1.26.0 => v1.27.0

However, the protobuf generated files were not re-generated which is
what this commit addresses.

The newly generated files should be backward compatible. However, the
following warning is now emitted when generating them:

  WARNING: Package "github.com/golang/protobuf/protoc-gen-go/generator"
           is deprecated.
           A future release of golang/protobuf will delete this package,
           which has long been excluded from the compatibility promise.

This is because this package was apparently never meant to be public as
explained in this comment[0]. The fix for this is to migrate to
`google.golang.org/protobuf/compiler/protogen` but this can't be done
until a release of `grpc-go` which includes the following patch[1] is
out. Update the Makefile to output a note with regard to this when generating
the files

It appears that with the newly generated files, protobuf now needs to
be marked as an explicit dep. Fix it by by running:

    go mod tidy && go mod vendor && go mod verify

Fix: f18fcd9

[0]: golang/protobuf#1104 (comment)
[1]: grpc/grpc-go#3453

Signed-off-by: Robin Hahling <robin.hahling@gw-computing.net>
@github-actions github-actions bot locked as resolved and limited conversation to collaborators May 25, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Type: Feature New features or improvements in behavior
Projects
None yet
Development

Successfully merging this pull request may close these issues.