https://github.com/golang/mock is a project for automatically generating mocks. Since it generates source files, it would be ideal to have a built-in rule to do this automatically, like go_proto_library does for protobufs.
It would also be nice if it would support https://github.com/vektra/mockery.
It would be nice if generated code could be placed into the workspace to support the "standard toolchain", similar to this request re protobufs: https://github.com/bazelbuild/rules_go/issues/393
Mixing generated code with hand-written is not a good idea.
This is a place where bazel gets it right and Go does not.
However AFAIK (@alandonovan to correct me), they are working on Go tooling that would mesh with the idea of a 'generated' directory of sources to be overlayed with an existing one.
@alandonovan @pmbethe09 Any update on that tooling? This is making some work I'm doing unable to use bazel's proto tooling.
cc @matloob
How will the new workspace abstraction work with generated files?
The workspace abstraction will query bazel and will know where the generated files are located. So it requires that a user bazel builds the generated files, but once generated, the tools will know where to pick up the files.
Ah, interesting! I went to learn more about this workspace abstraction and found your workspace repo (maybe I missed a doc about it!). From it's current state (which I'm sure could change), is the thinking that a different tool, using the stuff in there, would create a GOPATH with FUSE or some other idea that I've not thought of?
Like, maybe mockgen would be taught how to use workspace, instead?
No doc yet because it's still in very early stages but I plan to have something out very soon... I'm in process of moving the repo to code.googlesource.com/goworkspace.
But the basic idea is that we're building updated versions of the loader and related packages from golang.org/x/tools. The tool delegates to programs that understand the workspace (cmd/bazelws and cmd/gobuildws -- names will probably change). So bazelws calls bazel query and gobuildws calls go list and knows where all the files in a package are.
Then if mockgen were written in terms of our new 'loader' and 'package' abstractions, it should work in both bazel and go build.
Thanks for the info!
Hey, looks like the workspace repos have disappeared. Is there work going forward somewhere?
I made the repo private because we want to clean things up a little before folks start depending on it...
We're definitely still working on it and hopefully will be able to share more info soon!
Great to hear! Champing at the bit
Hey, I got pretty far on this with the new go_path function. But I'm doing something wrong and the rule I wrote isn't able to find the go binary.
Here's a gist of what I've got. Any help would be lovely! https://gist.github.com/jmhodges/8037c7fc072979aff8345c620834387d
The entry point is the gomock macro and there's example of its use in there.
The output right now is:
WARNING: /private/var/tmp/_bazel_jmhodges/ee957dabdee1b1a9e1f2fe90369cf80f/external/io_bazel_rules_go/go/private/tools/path.bzl:18:3:
EXPERIMENTAL: the go_path rule is still very experimental
Please do not rely on it for production use, but feel free to use it and file issues
.
INFO: Found 1 target...
ERROR: /Users/jmhodges/founding/src/founding/go/svc/howsmyssl-billing/BUILD:144:1: SkylarkAction go/svc/howsmyssl-billing/stripe_mock2.go failed (Exit 1): mockgen failed: error executing command
(cd /private/var/tmp/_bazel_jmhodges/ee957dabdee1b1a9e1f2fe90369cf80f/execroot/founding && \
exec env - \
GOPATH=bazel-out/darwin_x86_64-fastbuild/bingo/svc/howsmyssl-billing/stripe_mock2_gomock_gopath \
GOROOT=/private/var/tmp/_bazel_jmhodges/ee957dabdee1b1a9e1f2fe90369cf80f/external/go1_9_darwin_amd64 \
bazel-out/host/bin/external/com_github_golang_mock/mockgen/mockgen -package main -destination bazel-out/darwin_x86_64-fastbuild/bin/go/svc/howsmyssl-billing/stripe_mock2.go founding/go/svc/howsmyssl-billing stSubscriptions,stCustomers)
Use --sandbox_debug to see verbose messages from the sandbox.
2017/09/04 07:03:14 Loading input failed: exec: "go": executable file not found in $PATH
Target //go/svc/howsmyssl-billing:stripe_mock2 failed to build
INFO: Elapsed time: 1.448s, Critical Path: 0.06s
Okay, I've got something working for the reflect case! Updated the gist at https://gist.github.com/jmhodges/8037c7fc072979aff8345c620834387d
I'm sure there's a better way to design these rules. I'm up for sending this as a contrib. (And I signed a CLA long ago.)
It has 2 FIXMEs in it: 1) make _MOCKGEN_TOOL overridable in the second spot; 2) support using -source instead of the reflect code in mockgen.
That second one is required for the pretty common case where you have a binary that has some interfaces to let you have an easier time mocking out some third party services in your tests. mockgen's reflect code (that uses looking up by importpath) can't support it because it generates a temporary program that tries to import your binary and that now fails in Go 1.8+. So, we'll have to make a config to pass to the source parameter instead of using the reflection importpath look up.
Sucks, but oh well.
(Tangentially, It makes me wonder if the package-level ast parsing libraries for gocode et al have improved enough we can just use those instead of mockgen's reflection.)
This also exposes some inconveniences when working with go_path. For instance, I had to use $(pwd) and ctx.var["BINDIR"] in order to get the pathing right in a few different places.
Oh, also, those PATH=$GOROOT/bin:$PATH and ctx.attr.gopath_dep.files.to_list() were surprising. Hoping there's an easier way to get all this context loaded in!
Nice!
The changes to the go_path logic that are coming should help make this cleaner, you will be able to build a gopath inside your rule, rather than as a separate one.
I have never used the mock library, so I am not sure what the best design for it's normal use is.
Should it be building a library you can depend on directly, or sources you include into a library?
If you want to put up a PR with an example/test then I guess we could iterate on it there?
Not sure why you have to use pwd and ctx.var["BINDIR"], the go_vet rules were happy with using the relative paths, does something in mockgen cause a cd that means it needs absolute paths?
ctx.attr.gopath_dep.files.to_list() does not surprise me, but having to set the PATH does, if mockgen is not obeying GOROOT but insisting go is on your path, it's doing it wrong.
library vs sources: I've mostly needed mockgen's output for my tests where I'm mocking out a remote service (usually not in my control). I've once or twice made a separate package but norm is well in the other direction. Not sure what the common case is for others, though!
PR: I can totally put it up in a PR.
The pwd and BINDIR is because the go binary, itself, complains about relative GOPATHs when it's run by mockgen. mockgen's reflect code works by creating a Go source file, and then running it and consuming it's output. It exec.Command's the go binary directly.
When run with the relative directory, go says go: GOPATH entry is relative; must be absolute path: "go/svc/fe/mock_sess_gomock_gopath". go_vet does actually use pwd and I believe the BINDIR is required in my code because it's being defined in a repo that's not the same as the one that has go_path? The code is just run a few more directories up than it would otherwise, I think.
It would probably be beneficial for go_path to always return absolute directories.
exec.Command of the go binary described above is where that PATH requirement came from.I made https://github.com/bazelbuild/rules_go/issues/797 for point 3.
Oh, shoot, sorry, one more comment: is that go_path change coming in the next day or so? Deciding how much effort is worth putting into this since those changes and #797 etc might moot a lot of the workarounds
I am currently working on proper proto support, customizing the go toolchains, and support for pure go cross compiles. The go_verify_test rule is very much a background task, probably at a few weeks out.
If it would really help I could extract just the bits that allow using go_path as an action rather than a rule and get it in much quicker.
Thanks for the effort @jmhodges your snippet worked for me with some minor modification - would be great to get this into rules_go.
@ianthehat To get back to your questions if it should generate a library, that is how I am using it and seems to me like it would be a typical way to use it. So to be more specific my go_test has it as one of its deps and it is then imported for usage in the tests.
@Globegitter do you mind sharing your working version? I hope this makes it into rules_go soon.
I've actually open sourced a fully working version of this at https://github.com/jmhodges/bazel_gomock
Thanks! Somehow I missed that.
Jeff -- very nice.
All -- I don't think rules_go is the place for this. It needs to be the core set of things that are used for go+bazel. I think we should explore a new 'rules_go_contrib' or similar for things like gomock which are useful to many but come with less of a certification.
I still have my hopes on that workspace abstraction. Is there any hint when we can expect that?
go_path saved the day for gomock but the rule is a bit heavy.
The workspace abstraction will be needed for Go 1.11, since there are a lot of changes being made around dependency management. I can't guarantee Bazel will be fully supported by that time, but the framework should be done by then.
I am working on it full time, and not on my own.
For this kind of use case, I am confident in the solution we are working on, but we are also trying to fix it for editor integrated tooling. That is a much harder problem because you may have to do an arbitrary amount of work using bazel build to materialize generated source files before you can analyze them (by doing things like type checking a package), something a lot of the tools need to do, and editor tools are very sensitive to latency...
I am unable to make an useful promises about timelines, but it is the highest priority task right now.
I am happy to hear that!! Looking forward to those changes :) It will make adoption much easier.
Closing some old issues.
https://github.com/jmhodges/bazel_gomock can be used for gomock.
Progress is being made on the workspace abstraction. golang.org/x/tools/go/packages is the first public API for this. That is still under active development.
In the short term, there is a new and improved go_path rule.
@jayconrod I think for visibility it would be nice to have some way of including community contributed rules (that may not be fundamental) in this repository. Maybe we can add a contrib directory to include these types of rules there similar to how rules_docker does it: https://github.com/bazelbuild/rules_docker/tree/master/contrib
Otherwise it would be nice to at least have a section where other useful rules in the go space can be referenced.
@Globegitter The extras directory in theory should be used for contributions outside of the core rules. However, I have a couple concerns about adding stuff here:
go_rules_dependencies. Those dependencies need to be tested and updated regularly. They can also conflict with user dependencies.Because of the above, I think it's better for non-essential tools to live in separate repositories. I agree that discoverability is a problem though. Maybe we should add a section in the main repo pointing to tools like this.
@jayconrod Yeah those are valid points, maybe there can be a readme in that directory stating that these rules are just community supported so might not see fixes etc. as quickly as the rest. Then we could also add a separate go_rules_extras_dependencies for these rules. And in the long run I would hope that recursive workspaces would take care of that anyway.
But I do understand the hesitation - I am also happy to start off with adding a section in the documentation. Does https://github.com/bazelbuild/rules_go/blob/master/go/extras.rst seem like a good place for that to you?
@Globegitter Sure, that sounds like a good place. If you want to open a PR that adds a description to extras.rst of bazel_gomock and a link to that repo, I'd be happy to merge it. Later, I may add something to the bottom explaining why there aren't more tools in extras.
Most helpful comment
I am working on it full time, and not on my own.
For this kind of use case, I am confident in the solution we are working on, but we are also trying to fix it for editor integrated tooling. That is a much harder problem because you may have to do an arbitrary amount of work using
bazel buildto materialize generated source files before you can analyze them (by doing things like type checking a package), something a lot of the tools need to do, and editor tools are very sensitive to latency...I am unable to make an useful promises about timelines, but it is the highest priority task right now.