It would be nice if there was a build tag for detecting if go modules is being used.
I have created a package: https://github.com/rocketlaunchr/dbq. I went out of my way to put v2 in a separate v2 directory so that it would be compatible with go module users and non-go module users. This is supposedly preferred practice.
For v2, I want to introduce a dependency (https://github.com/cenkalti/backoff) that is at v4 but did not use the separate directory approach.
For my package, in order to support Go Modules and non-modules users, I need to use a build tag so that I can use github.com/cenkalti/backoff/v4 for go modules users and gopkg.in/cenkalti/backoff.v4 for non-go modules users.
@propersam
For my package, in order to support Go Modules and non-modules users, I need to use a build tag so that I can use
github.com/cenkalti/backoff/v4for go modules users andgopkg.in/cenkalti/backoff.v4for non-go modules users.
It may not be necessary to use a build tag to achieve compatibility for both modes because of "minimal module-awareness for legacy operation" that was implemented in commit https://github.com/golang/go/commit/d4e21288e444d3ffd30d1a0737f15ea3fc3b8ad9 and issue #25069. Are you familiar with that behavior?
/cc @jayconrod @bcmills @matloob
So how do I achieve my aim? As it stands adding /v4 to imports prevents compilation when go modules is not enabled.
@dmitshur on a separate matter did you get my email from about a week ago?
Minimal module compatibility lets code built in GOPATH mode stay compatible in this situation. The Modules wiki has more information about this.
If a package has a go.mod file in some parent directory within GOPATH, it should import github.com/cenkalti/backoff/v4 (as is required in module mode). If a package does not have a go.mod file, it should import github.com/cenkalti/backoff without the /v4 suffix, matching the directory structure.
The path gopkg.in/cenkalti/backoff.v4 should not be used in either case, even though it's possible to use in GOPATH mode. The module declares its name as github.com/cenkalti/backoff/v4. Referring to a package by multiple names can lead to migration problems, duplicate packages, and conflicts. They will not be de-duplicated.
github.com/cenkalti/backoff default branch is set to v4. When in gopath mode does it use master which is quite old?
Yes. If you want to support GOPATH-mode users with this particular dependency, probably the simplest approach is to use go mod vendor to generate (and check in) a vendor directory for your project.
GOPATH-mode users would then build your dependencies from your vendor directory instead of whatever is in their GOPATH/src.
Is there a way to use this solution just for 1 dependency?
I don't think so, no — but users who are sensitive to extra dependencies should generally be building in module mode anyway.
In the blog post: https://blog.golang.org/v2-go-modules they recommend the separate directory approach. They mention the downsides are maintaining 2 separate codebases (this is a big downside I am already facing). They say the benefits are compatibility with GOPATH mode. They didn't mention the issue I just faced.
Is this still the recommend approach?
For my package, I'd love to abandon the separate directory approach since it looks like supporting GOPATH is not viable (and never was). It's possibly too late now to abandon it because I may have GOPATH users already pointing to the v2 directory.
Also what's wrong with a build tag for detecting GO MODULES enabled?
When in gopath mode does it use master which is quite old?
In GOPATH mode, go get will download the default branch. That's set to v4 for this repo, so GOPATH users will get something pretty recent.
In the blog post: https://blog.golang.org/v2-go-modules they recommend the separate directory approach. They mention the downsides are maintaining 2 separate codebases (this is a big downside I am already facing). They say the benefits are compatibility with GOPATH mode. They didn't mention the issue I just faced.
If you have GOPATH users that need to refer to anything other than the latest version of the default branch, then using separate directories is recommended. For example, if you have the module example.com/mod, and you rewrite your API in example.com/mod/v2, GOPATH users of example.com/mod will be broken unless you have both versions on the default branch with v2 in a subdirectory.
I don't know enough about backoff to judge its compatibility with GOPATH. Since it's at major version v4 on the default branch, not in a subdirectory, it should be imported as github.com/cenkalti/backoff/v4 in projects with a go.mod file and as github.com/cenkalti/backoff in projects without a go.mod file.
As @bcmills mentioned, you may be able to check in a vendor directory to work around compatibility issues with GOPATH users so they get the correct version. As another alternative, you could create a branch named go1 with code for GOPATH users. In GOPATH mode, go get will pick that instead of the default branch if it's present (see go help gopath-get.
Also what's wrong with a build tag for detecting GO MODULES enabled?
We'd rather not add features if there's already a way to solve a problem. There are some options here, and we'd like to be sure none of those can work before pursuing something new.
@jayconrod
In GOPATH mode, go get will download the default branch. That's set to v4 for this repo, so GOPATH users will get something pretty recent.
That doesn't seem to be the case. go get seems to get master instead of the default branch: v4. NOTE: I'm using Go1.12 so maybe it's changed. (I can't use Go1.14)
As @bcmills mentioned, you may be able to check in a vendor directory to work around compatibility issues with GOPATH users so they get the correct version. As another alternative, you could create a branch named go1 with code for GOPATH users. In GOPATH mode, go get will pick that instead of the default branch if it's present (see go help gopath-get.
This is not viable. It's already a nuisance maintaining a v1 and v2 directory. I can't maintain another branch.
Most helpful comment
In
GOPATHmode,go getwill download the default branch. That's set tov4for this repo, soGOPATHusers will get something pretty recent.If you have
GOPATHusers that need to refer to anything other than the latest version of the default branch, then using separate directories is recommended. For example, if you have the moduleexample.com/mod, and you rewrite your API inexample.com/mod/v2,GOPATHusers ofexample.com/modwill be broken unless you have both versions on the default branch withv2in a subdirectory.I don't know enough about
backoffto judge its compatibility withGOPATH. Since it's at major versionv4on the default branch, not in a subdirectory, it should be imported asgithub.com/cenkalti/backoff/v4in projects with ago.modfile and asgithub.com/cenkalti/backoffin projects without ago.modfile.As @bcmills mentioned, you may be able to check in a
vendordirectory to work around compatibility issues withGOPATHusers so they get the correct version. As another alternative, you could create a branch namedgo1with code forGOPATHusers. InGOPATHmode,go getwill pick that instead of the default branch if it's present (seego help gopath-get.We'd rather not add features if there's already a way to solve a problem. There are some options here, and we'd like to be sure none of those can work before pursuing something new.