Yep I did.
But oh boy I didn’t know what was coming.
I’m the kind of person who likes to support things for a long time. I don’t enjoy breaking my users. In short, I wanted the following to work:
go get golang.org/dl/go1.9.7 go1.9.7 download go1.9.7 get github.com/maruel/panicparse/cmd/pp go get golang.org/dl/go1.16beta1 go1.16beta1 download go1.16beta1 get github.com/maruel/panicparse/cmd/pp
In practice, I only needed go1.11 to work, but I got up to 1.9.7 for free. I hit a few challenges:
go get github.com/maruel/panicparse/cmd/ppdid the wrong thing (fetch v1) silently from the perspective of the users and had a hard time figuring out a way to fix this.
go getwill fetch the previous version without any mention of the more recent broken one. The only way to know if to specifically request a broken version. It will print you an error message. Thankfully I had a OSS toy project that I knew nobody dependended on that was already at v3 that I could test on. The error looks like this when toying with versioned subdirectories (which is incorrect):
$ go get -u email@example.com go get firstname.lastname@example.org: email@example.com: invalid version: module contains a go.mod file, so major version must be compatible: should be v0 or v1, not v3
In addition to the challenges mentioned above, I also found many annoyances but I’ll save them for another day.
My goal was simple:
ppexecutable) independently from the library stack so that getting the v1 CLI tool provides the v2 (race detector parsing) functionality.
I worked it out with a combination of a few tricks.
I think my main take away is that in go modules days, you should seriously consider using separate git repositories for your executables and the packages. That’s all. In abstract it makes sense, you make separate versions, and it’s generally surprising for users if they get bumped to a new major version silently. Where this breaks down is in the following format (which panicparse follows):
- LICENSE - go.mod - cmd/ - tool_foo/ - main.go - foo/ - foo.go
and you want to make a breaking change to the reusable package
having to bump the version of the CLI tool
The challenge is that often I’ll write a toy CLI tool, then will carve out a
package that I think has potential for reuse, which leads to a period of
uncertainty for the API. Is it too specific for the tool use case or is it too
generic? Fleshing an API out requires time, but in the meantime as a tool
maintainer you have a useful CLI tool that you don’t want to break in the
process. That’s where I find the status quo hurts the most, because the git tag
and the versions must match starting with v3 so versioning directories do not
help, and having go.mod files in subdirectories breaks
go test ./....
Anyhow, I’m glad I found a way and hope the learnings here will help another package maintainer write Go packages that predate Go modules.