Skip to content
This repository has been archived by the owner on Jun 27, 2023. It is now read-only.

Generate mocks from archives/*types.Type data #424

Open
robbertvanginkel opened this issue Apr 6, 2020 · 3 comments · May be fixed by #633
Open

Generate mocks from archives/*types.Type data #424

robbertvanginkel opened this issue Apr 6, 2020 · 3 comments · May be fixed by #633

Comments

@robbertvanginkel
Copy link

robbertvanginkel commented Apr 6, 2020

Requested feature
Mockgen supports creating github.com/golang/mock/mockgen/model.Interface models from reflect.Type data using

func InterfaceFromInterfaceType(it reflect.Type) (*Interface, error) {

But there is no analogue for creating model.Interface's for mock generation from go/types.Type data.

Why the feature is needed
The go compiler writes serialized type information for the public interface of each package, which can be read using golang.org/x/tools/go/gcexportdata to get a types.Package.
This blog post gives a good indication of what the export data is good for: https://jayconrod.com/posts/112/export-data--the-secret-of-go-s-fast-builds.

We implemented a utility tool that takes an archive (that was generated by a previous build step from bazel), reads the type data, converts it to a gomock model.Interface and uses it for codegen. Using this instead of source/reflect mode presented significant efficiency and speed win for us over using gomock in reflect mode.

(Optional) Proposed solution
Although the internal tool works fine for us, there's some rough edges and some opportunity to share some of our benefits with the community. There's two things I have in mind for improvement:

  • We maintain separate code for converting types.Type to model.Interface. This is pretty much analogous to whats implemented in func InterfaceFromInterfaceType(it reflect.Type) (*model.Interface, error) on https://github.com/golang/mock/blob/master/mockgen/model/model.go#L293-L470. reflect.Type and types.Type are similar (archives contain all the same typedata as the binary they later get compiled into), but unfortunately don't have an overarching interface. Would there be any interest in having support for converting types.Type to model.Interface in golang/mock?
  • golang/mock doesn't have any go api to take a model.Package and run codegen. Our current tool uses a bit of a workaround to do codegeneration: run gomock with -exec_only pointing to a stub binary, the stub binary reads the archive file, converts the types.Package into a model.Package and similar to a reflect binary encodes the model.Package with encoding/gob to a file for mockgen to read. In addition to its existing cli api for doing mockgen on a gob encoded model.Package, would it be possible to add a public go api to do codegen based on a model.Package object?
@codyoss
Copy link
Member

codyoss commented Apr 24, 2020

This is a really interesting use case. I did not knew anyone used this package directly. I will need to research this space a little more and get back to you.

@cvgw
Copy link
Collaborator

cvgw commented Oct 23, 2020

We maintain separate code for converting types.Type to model.Interface. This is pretty much analogous to whats implemented in func InterfaceFromInterfaceType(it reflect.Type) (*model.Interface, error) on https://github.com/golang/mock/blob/master/mockgen/model/model.go#L293-L470. reflect.Type and types.Type are similar (archives contain all the same typedata as the binary they later get compiled into), but unfortunately don't have an overarching interface. Would there be any interest in having support for converting types.Type to model.Interface in golang/mock?

I think at the moment there isn't a strong need/use for conversion from types.Type to model.Interface in mockgen, but I can see how this might be something we explore more in the future.

golang/mock doesn't have any go api to take a model.Package and run codegen. Our current tool uses a bit of a workaround to do codegeneration: run gomock with -exec_only pointing to a stub binary, the stub binary reads the archive file, converts the types.Package into a model.Package and similar to a reflect binary encodes the model.Package with encoding/gob to a file for mockgen to read. In addition to its existing cli api for doing mockgen on a gob encoded model.Package, would it be possible to add a public go api to do codegen based on a model.Package object?

This seems totally reasonable to me as the existing code for consuming a model.Package is mostly separated from the code used to generate a model.Package. Open to contributions.

@ashi009
Copy link

ashi009 commented Mar 15, 2022

@robbertvanginkel interestingly enough, we end up doing the same for running mockgen with bazel.

I believe the only reason why mockgen is not using go/types is due to the fact that the package arrives 3 years after gomock.

As an archive contains all transitive typing info, we can safely delegate all the tricky parts to go build, and mockgen just works for any compiled pkg. i.e. either get the package with https://pkg.go.dev/golang.org/x/tools/go/gcexportdata#Find or https://pkg.go.dev/golang.org/x/tools/go/gcexportdata#Read from an archive file.

It's a net gain compared to the current implementation.

  • no more manual dependency resolution in source mode
  • no more manual compilation in reflect mode

@dr-dime dr-dime linked a pull request Mar 25, 2022 that will close this issue
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants