-
-
Notifications
You must be signed in to change notification settings - Fork 112
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
gofumpt's behaviour depends on the version of Go used to build it #244
Comments
For better or worse, that will always be the case, and the same applies to In particular, what you are seeing is https://go-review.googlesource.com/c/go/+/384264/, a There is literally no way to work around this without having one fork of I know that for reformatting godoc comments it may seem obvious to just disable that bit of code if I think perhaps So the flag was never intended to mean "format exactly like Go version 1.x" - hopefully that's clear. I'd be interested to hear where you got that impression, so I can improve the docs :) |
It could always be possible for gofumpt to give an error if its |
Thanks for the quick, detailed, and illuminating reply—I appreciate it. Thanks for your work on
The triggering scenario for me was the following; I believe you're right about its rarity. My employer has a repository that requires the use of Go 1.18. This repository has a CI pipeline that uses golangci-lint. The binaries that are distributed with golangci-lint are built using Go 1.19: go version -v $(which golangci-lint) This inconsistency can cause CI pipelines to fail. There are obvious solutions to that immediate problem, of course; I'll build
It was a breezy, optimistic assumption on my part. The documentation I saw was from the struct definition of
I didn't realise that this meant that the version is only used for that purpose; I assumed more than was written. It's a behaviour that resists a pithy explanation, though. You're, of course, right that it'd be an unsustainable and unreasonable burden on you to maintain forks of One possibility would be for releases of |
Thanks for being understanding! This is a tricky situation so I understand where you were coming from. I actually made a proposal to upstream to provide versioned gofmt downloads for a very similar reason, so that at a previous company we could all use exactly the same Go formatting even if some of the developers were on slightly newer Go versions: golang/go#26397
Arguably, that may be a problem for more than just formatting. If your work project builds and tests with Go 1.18, you should also use your tools (formatting, static analysis, editors with LSP, etc) with 1.18 as well. Using 1.19 may lead to subtle differences in behavior beyond just formatting.
I'll think about making the docs clearer - I'll ping you for a PR review if that's OK.
Personally, the only reason I thought the project didn't need release binaries is because it is a tool for Go developers. For them, I imagine that running Perhaps you're right that each gofumpt release should advocate what Go version it mainly targets. https://github.com/mvdan/gofumpt/releases/tag/v0.3.0 did say it was based on Go 1.18's gofmt, and that relates to code in |
Yes: as good as Go is with its backward-compatibility guarantees, it'd be better if everything were on the same version. I'll have a look into what I can do.
By all means!
I think that'd definitely help. An additional possibility would be for |
I'm not sure about the warning. Without any flags, when running gofumpt on its own codebase today with Go 1.19, it would default to |
Yes, quite right—sorry. It's all a bit tricky! Perhaps the least bad solution would be:
I'll defer to you and your judgement, of course. I'm happy to try and help however I can, whether it's writing documentation, reviewing things, or working on a pipeline. |
Your points about the docs are certainly a good idea - happy to review a PR :) I'm less convinced that providing so many gofumpt binaries will be a net benefit. My guess is that it would confuse users more than anything. We should recommend using a gofumpt version with one major version of Go, and that's easy enough. If a project absolutely cannot use that Go version just yet, they can either use our prebuilt binary, or they can choose to stay on a slightly older version for a bit. I also just realised that having gofumpt's formatting be independent of the Go version isn't such a difficult task. Yes, we would have to keep a vendored copy of Part of me still thinks that's nasty, as it would lead to some downstreams like |
Note that we're starting to recommend a particular Go version for building gofumpt, as that is the go/printer version we've tested the most with, and a consistent version will also bring consistent behavior. See #244.
I think you're right, having reflected on it; I think providing a single simple recommendation makes the most sense. Opinionated tools are, after all, opinionated. |
I think I do want to go in the direction of gofumpt versioning its use of go/printer. It will make using it as a library slightly more bloated, but so be it. If users can't trust on a pinned gofumpt version to behave consistently, then the tool isn't particularly useful. gofmt does not have this problem as it ships with Go itself. |
These two packages affect the formatting of gofmt, and by extension gofumpt as well. For example, most changes in formatting to gofmt are done in go/printer, as it implements most of the formatting logic. This tight coupling between gofmt and std packages like go/printer is not a problem for gofmt, as gofmt is released with Go itself. It is very unlikely that any user would build a version of gofmt with a different version of those std packages. gofumpt is a separate Go module, so when users `go install` it, they may currently be using Go 1.18.x or 1.19.x. This can cause problems, as choosing a different major version can easily lead to different behavior. To get the same tight coupling that gofmt has, vendor the two libraries which affect formatting. go/doc/comment is also in this bag since it affects how gofmt reformats godoc comments. Note that this vendoring is not ideal, as it adds code duplication. This shouldn't bloat the size of gofumpt binaries, as they simply swap out the original packages for the vendored ones. For users of the mvdan.cc/gofumpt/format library such as gopls, they may get duplication if they use packages like go/printer elsewhere. This is a small amount of unfortunate bloat, but I don't see a better way to ensure that each version of gofumpt behaves in a consistent way. Note that we're not vendoring std packages for parsing Go code like go/parser or go/token, and neither are we vendoring go/ast. If a project uses new Go syntax, such as generics, they will still need to build gofumpt with a new enough version of Go. The copied code comes from Go 1.19.4 and will be updated regularly. The copying was done manually this time, skipping test files and rewriting imports as necessary. In the future, we an automate it. Also note that we ran gofumpt on the copied code. Fixes #244.
These two packages affect the formatting of gofmt, and by extension gofumpt as well. For example, most changes in formatting to gofmt are done in go/printer, as it implements most of the formatting logic. This tight coupling between gofmt and std packages like go/printer is not a problem for gofmt, as gofmt is released with Go itself. It is very unlikely that any user would build a version of gofmt with a different version of those std packages. gofumpt is a separate Go module, so when users `go install` it, they may currently be using Go 1.18.x or 1.19.x. This can cause problems, as choosing a different major version can easily lead to different behavior. To get the same tight coupling that gofmt has, vendor the two libraries which affect formatting. go/doc/comment is also in this bag since it affects how gofmt reformats godoc comments. Note that this vendoring is not ideal, as it adds code duplication. This shouldn't bloat the size of gofumpt binaries, as they simply swap out the original packages for the vendored ones. For users of the mvdan.cc/gofumpt/format library such as gopls, they may get duplication if they use packages like go/printer elsewhere. This is a small amount of unfortunate bloat, but I don't see a better way to ensure that each version of gofumpt behaves in a consistent way. Note that we're not vendoring std packages for parsing Go code like go/parser or go/token, and neither are we vendoring go/ast. If a project uses new Go syntax, such as generics, they will still need to build gofumpt with a new enough version of Go. The copied code comes from Go 1.19.4 and will be updated regularly. The copying was done manually this time, skipping test files and rewriting imports as necessary. In the future, we an automate it. Also note that we ran gofumpt on the copied code. Fixes #244.
I'm finding that the behaviour of
gofumpt
is sensitive to the version of Go used to build the binary. It also looks to not fully respect the-lang
flag (ed.: this was a misreading on my part; see the discussion below). A reproducing example follows.This was first raised here; I misattributed things.
(I'll try and fix the problem rather than only whinge like an ingrate, but I think it's a good idea to raise the issue here first.)
Reproducing example
Preparing
Prepare an empty directory with the following files:
Then run:
Installing via
go install
Building with Go 1.18, running in a Go 1.19 context
Building with Go 1.19, running in a Go 1.18 context
Cleaning up
The text was updated successfully, but these errors were encountered: