-
Notifications
You must be signed in to change notification settings - Fork 17.8k
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
cmd/go: flags to control changes to go.mod, go.sum #34506
Comments
Per #32027 (comment), we'll probably want to make the If we do that, presumably the |
but
If |
I think |
I contradicted myself a bit here. Updated the text. |
Regarding the file flags: I think having to specify both This is also a good precedent to set in case there's ever a third file, since nobody will know to override its location before it exists. |
@jayconrod regarding the "gopls (various issues)" motivation. I'm not entirely clear on what the issue here is and hence why Is the problem that people are not used to Because for me, I would expect that anything I do inside my editor, e.g. adding an import for a package whose module is not in my Could you give a bit more background? |
While not part of the original issue, the consensus for a while seemed to be that a "global" install should also obey replace directives. At least, this is what @ianthehat said in #30515 (comment). Has the team's position generally changed to not obeying replace directives at all? I'm also a bit confused by the multiple flags, like @heschik. How about a |
Sorry, I should have clarified. There were initially some comments about applying non-directory replace directives, but the consensus seemed that we either apply all of them or none of them - to not add a third build mode. @ianthehat's comment that I linked seemed to lean towards applying all replace directives. |
Personally, I'm in favour of applying directory replacements only when the source is in a user-controlled directory (as opposed to in global mode where the source is in the module cache). But I feel strongly that installs in global mode should respect other replacements, FWIW. |
@mvdan, @rogpeppe: see #30515 (comment) and #30515 (comment). Furthermore, given that the proposed semantics of the |
We should probably make that even stronger: the |
@myitcv, @ianthehat and @stamblerre have told me there's no canonical issue for this, but they've had to close a lot of issues as "working as intended", pointing to #29452, and they explain this frequently on Slack. They mentioned one egregious example where someone in a clean workspace switched branches, then tried to switch back but were unable to because go.mod had uncommitted changes. Their editor (and gopls) was open in the background. It had detected changes in open files, run
|
I like the simplicity of just saying what both files should be, but I couldn't actually come up with a scenario where you'd want to set How about this: there's no |
I don't think that solves the same set of problems. |
After thinking through all the weird edge cases and trying out a bunch of things, I came to the conclusion that applying replace directives is a confusing and dangerous ball of scary, and the only sane thing to do is not to apply them, in fact the only sane thing to do is to never ever check replace directives in to your repository in the first place.
That would not allow most of the useful patterns (having multiple .mod files in the same directory that you can choose between, or a cache directory with modified .mod files for a bunch of different modules etc) It would also mean that you have to specify what happens in a bunch of interesting edge cases (thinks like relative paths, are they from the original module or the alternate root?) I think that specifying the .sum file would/should be incredibly rare, leaving it as the original one would be fine for the majority of use cases. |
On replacements:
Personally, I think the downsides of (2) outweigh the benefits, and it's better to have something very simple like |
Maybe split the difference? If the original is As far as I can tell, that handles both the |
@bcmils Could work, but it seems a little subtle. If a module only depends on |
@jayconrod re #34506 (comment)
But what about the situations where you do want |
Without a On the other hand, I think it is probably reasonable to expect |
@myitcv It would be up to gopls and the editor to provide a sensible way to do that. Perhaps it could show a warning that There are situations where modifying go.mod is not wanted, and |
@bcmills There's a lot of nuance here. Assuming no go.mod is present, should Should |
Re-milestoning this for Go1.14 since I'd like to direct further discussion on |
Change https://golang.org/cl/208236 mentions this issue: |
Verify that 'go generate' works with -modfile. Also check that go commands starts with 'go generate' do not inherit -modfile, but they should still work if -modfile is set in GOFLAGS. Updates #34506 Change-Id: I5e1f897b4e38e4fdaccc0fbb7a71b8d0e9fc0660 Reviewed-on: https://go-review.googlesource.com/c/go/+/208236 Run-TryBot: Jay Conrod <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Bryan C. Mills <[email protected]>
@jayconrod What's the status of this issue? Thanks. |
@ianlancetaylor |
Change https://golang.org/cl/211538 mentions this issue: |
In the upcoming Go 1.14 release, there is an introduction of the -modfile flag which allows a user to run a go command but choose where to direct the go.mod file updates. The information about this can be found here: golang/go#34506. This change starts setting up the infrastructure to handle the seperate modfile rather than keep changing a user's go.mod file. To support versions of Go that are not 1.14, we run a modified "go list" command that checks the release tags to see if 1.14 is contained. Updates golang/go#31999 Change-Id: Icb71b6402ec4fa07e5f6f1a63954c25520e860b0 Reviewed-on: https://go-review.googlesource.com/c/tools/+/211538 Run-TryBot: Rohan Challa <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Rebecca Stambler <[email protected]>
Change https://golang.org/cl/212100 mentions this issue: |
When the -modfile flag is in use (either explicitly or from GOFLAGS), 'go list -m' will now print the effective go.mod file for the main module in the GoMod field in -f or -json output. Fixes #36220 Updates #34506 Change-Id: I89c2ee40f20e07854bb37c6e4e13eeea0cce7b0d Reviewed-on: https://go-review.googlesource.com/c/go/+/212100 Run-TryBot: Jay Conrod <[email protected]> Reviewed-by: Bryan C. Mills <[email protected]>
Closing this issue since 1.14rc1 is imminent. @stamblerre @ridersofrohan @ianthehat Let me know if you have any other feedback on this feature. |
@jayconrod If I have a Makefile which does something like this: How should I change this Makefile when go 1.14 is released to use the Can I specify something like |
@rodrigc It looks like this Makefile is installing then running several tools at the latest versions in I think the module-mode equivalent of this (using That would get you predictable versions of tools without interfering with your main |
@jayconrod Is this the recommended way to install tools now instead of the |
This seems strange to me. I will maintain a file with the names and constraints of executables I need, which makes sense. But then, I want to just point the tool at that file when I use the command for "use this file to give me the things I enumerate". Instead, it seems like the recommendation is to pass each tool enumerated to a different |
@jayconrod Could you summarize how to use it pls? Is the following still hold 100%?
And what is the minimum requirement to use it pls. |
@suntong That's all still correct. Right now, |
Proposed changes
I propose we add three new flags to go subcommands that deal with modules.
-modfile=go.mod
- instead of reading and writing go.mod from the current directory or a parent directory, the go command would read and write the specified file. The original go.mod would still determine the module root directory, so this file could be in any directory (perhaps/tmp
). It would be an error to use this flag when no actual go.mod file is present.-sumfile=go.sum
- instead of reading and writing go.sum from the directory containing go.mod, the go command would read and write the specified file. It would be an error to use this flag when no original go.mod file is present.-g
- "global mode" - the go command would behave as if no go.mod file were present.These flags would be allowed when
GO111MODULE
is set toon
orauto
(the current default) and rejected whenGO111MODULE
is set tooff
.-modfile
and-sumfile
both require an actual go.mod to be present, so modules must be enabled when they're used.-g
does not require an actual go.mod to be present, and inauto
mode, it implies that modules are enabled.Background
The go command updates go.mod and go.sum after any command that needs to find a module for a package not provided by any module currently in the build list. This ensures reproducibility: if you run the same command twice, it should build (or list or test) the same packages at the same versions, even if new versions have been published since the first invocation.
For example, if you run
go build .
, and a .go file in the current directory importsexample.com/m/pkg
which is not provided by any known module, the go command will add a requirement on the latest version of the moduleexample.com/m
to go.mod. Future runs ofgo build .
will produce the same result.While these updates are usually helpful, there are many situations where they're not desirable.
Selected issues
gopls (various issues)
gopls loads information about source files in a workspace using
golang.org/x/tools/go/packages
, which invokesgo list
. gopls may also rungo list
directly. In either case, gopls may trigger changes to go.mod and go.sum. This may be caused by user actions that seem unrelated to building anything, for example, opening a file. go.mod appears to change mysteriously on its own, and users don't realize gopls is triggering it.It's not usually important that the information gopls loads is reproducible; files it operates on are frequently changing. However, it is important that when it resolves an unknown import path to a module, it doesn't need to do so repeatedly since this can add a lot of latency, especially on slow connections.
gopls could set
-modfile
and-sumfile
to temporary copies of the original go.mod and go.sum. The original go.mod and go.sum would not be modified (until the user explicitly runs a command likego build
). Resolved module requirements would stay in the temporary files so they would not need to be resolved again.#25922 - clarify best practice for tool dependencies
Developers need a way to express module requirements that aren't implied by package imports. This is especially useful for tools invoked by
go generate
. Authors can add tool requirements to go.mod manually or withgo get
, but these requirements are erased bygo mod tidy
.The current recommendation is to create a tools.go file, tag it with
// +build tools
, then import main packages of needed tools. tools.go will never be built because of the tag, butgo mod tidy
will read the imports and preserve the requirements. This feels like a hacky workaround rather than a best practice. It also pushes requirements which may not otherwise be needed on downstream modules.A better solution would be to keep a separate go.tools.mod file with tool requirements, then point to that with
-modfile=go.tools.mod
when running commands that require tools.#26640 - allow go.mod.local to contain replace/exclude lines
This is a feature request to keep some go.mod statements out of source control. It's frequently useful for module authors to check out dependencies and point to them with
replace
statements for local development and debugging. These statements shouldn't necessarily be exposed to users or other developers on the same project though.Setting
-modfile=go.local.mod
and-sumfile=go.local.sum
would solve this problem, at least partially. The two files could be copied from the regular go.mod and go.sum files and added to .gitignore. Note however, that these local files are used instead of the regular files, not in addition to, so some synchronization might be required.#30515 - offer a consistent "global install" command
Developers want to be able to install tools from any directory, regardless of the requirements of the current module.
go get tool@version
may update the current go.mod, so users need to change to a temporary directory without a go.mod file to run commands like this. Tool authors need to be careful when writing installation instructions because of this.The
-g
flag would address this issue. It would tell the go command to run as if it were outside any module. Tool authors could writego get -g tool@latest
in their installation instructions: this would install the latest version of the tool, regardless of the current directory.Note that "missing go.mod" is being reconsidered (#32027), so the actual semantics of
-g
may change: this issue is just about ignoring the current module.#33710 - module mode removes concept of global docs
In module mode,
go doc example.com/pkg
prints documentation for the packages named on the command line at the same version they would be built with. Likego build
,go doc
may add or update requirements in go.mod. This may be undesirable, especially if you're using the documentation to decide whether you want to depend on a package that is not currently imported.The
-g
flag would partially solve this. The current module would be ignored, and "global" documentation would be shown.Note that
go doc
does not currently work in "missing go.mod" for packages outsidestd
. #33710 would need to be fixed, but-g
would provide a useful way to access that mode.Other related issues
There are a large number of open issues about unexpected and unwanted go.mod changes. The flags suggested here won't solve all these problems, but they provide useful context.
The text was updated successfully, but these errors were encountered: