-
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: make go.mod exclude directives deterministic #36465
Comments
I think (2) is important. As an alternative to (1), we could instead ignore the excluded requirement entirely. (If we know that the main module already has a dependency on a higher version anyway, then replacing the lower version with the higher one has the same effect as dropping the lower one entirely.) That would drop the excluded edges from |
Yes, we should always write down a choice if we decide we have to make a choice. |
I'm guessing that nothing happened for 1.15, so rolling forward to 1.16. |
I'm deep in the guts of the module loader for #36460 anyway, so I'm going to implement the behavior described in #36465 (comment). We will ignore requirements on excluded versions whenever they are encountered, with the result that we will either downgrade to the highest non-excluded version found in the requirement graph or re-resolve the That approach is deterministic: if we do not need to re-resolve, it always yields the same subgraph of the original requirement graph, and if we do need to re-resolve we will record the resulting version as a new requirement (even if it is lower than the excluded version). It also has the nice benefit of enabling users to |
Spot-checking some known open-source
The planned change (to simply ignore all references to the excluded version) will continue to work for both of those categories. |
Change https://golang.org/cl/244773 mentions this issue: |
Change https://golang.org/cl/278596 mentions this issue: |
For #36460 Updates #36465 Change-Id: Id818dce21d39a48cf5fc9c015b30497dce9cd1ef Reviewed-on: https://go-review.googlesource.com/c/go/+/278596 Trust: Bryan C. Mills <[email protected]> Run-TryBot: Bryan C. Mills <[email protected]> TryBot-Result: Go Bot <[email protected]> Reviewed-by: Jay Conrod <[email protected]> Reviewed-by: Michael Matloob <[email protected]>
Change https://golang.org/cl/287414 mentions this issue: |
For golang/go#36465 Change-Id: I2ee22295c9c542697f211ce517866560e33ef480 Reviewed-on: https://go-review.googlesource.com/c/website/+/287414 Trust: Jay Conrod <[email protected]> Reviewed-by: Bryan C. Mills <[email protected]>
Background
exclude
directives ingo.mod
files prevent thego
command from loading specific module versions. When an excluded version would normally be loaded, thego
command instead loads the next higher semantic version that is not excluded. Both release and pre-release versions may be considered the next higher version, but not pseudo-versions. If there is no higher version, thego
command fails with an error.Problem
The "next" higher version depends on the list of available versions and may change over time. When the
go
command encounters an excluded version, it always requests a list of versions from a proxy or the origin repository. Unlike other requests, version lists aren't cached, since versions may be added and removed over time. As a result, these fetches are expensive, and they may not work at all if the user is offline or hasGOPROXY=off
set.This behavior also makes the build non-deterministic. Since the "next" version may change, the build list may vary depending on when the build was run and which proxy was used. A malicious proxy may selectively show and hide versions, but if the checksum database is being used, a proxy can't introduce a version that wasn't created by the module author without being detected.
If an excluded version is required in the main module's
go.mod
file, thego
command will update the requirement with the version chosen by MVS (typically the "next" version, but possibly something higher). However, excluded versions may still be required transitively, so they may still be loaded. Consider the example below:Suppose that
example.com/[email protected]
has thisgo.mod
file:In this example,
example.com/m
still transtively references the excluded versionexample.com/[email protected]
viaexample.com/[email protected]
.This appears to be the root cause of #36453.
Proposed solution
go.mod
, thego
command should use the required version instead of fetching the next version.go
command looks up the next version for an excluded module version (because (1) does not apply), it should add a requirement on that version to the main module'sgo.mod
file if one is not already present.Together, these changes prevent the
go
command from fetching versions more than once after anexclude
directive is added to thego.mod
file. The behavior in (2) causes thego
command to record the next version. The behavior in (1) ensures thego
command acts determinisitically after this information is recorded.In the above example, the
go
command would act as ifexample.com/b
requiredexample.com/[email protected]
instead ofexample.com/[email protected]
. The requirement onexample.com/[email protected]
would be added to the main module'sgo.mod
file if it weren't already present.Impact
exclude
directives are lightly used in publically visible modules. @heschik did an analysis a few weeks ago and found ~1000 module versions usingexclude
. Many of these were versions of the same modules or forks. We found ~50 distinct modules usingexclude
at any version.exclude
directives are likely more common in top-level modules (as opposed to open source libraries).cc @rsc @bcmills @matloob @heschik @FiloSottile
The text was updated successfully, but these errors were encountered: