go: cmd/go: do not allow the main module to replace (to or from) itself
What version of Go are you using (go version
)?
$ go version go version go1.13 darwin/amd64
This problem is also seen on Linux using go1.12.3
$ go version go version go1.12.3 linux/amd64
And on Mac with the tip branch
$ gotip version go version devel +fe2ed50 Thu Sep 19 16:26:58 2019 +0000 darwin/amd64
Does this issue reproduce with the latest release?
Yes.
What operating system and processor architecture are you using (go env
)?
go env
Output
$ go env GO111MODULE="" GOARCH="amd64" GOBIN="" GOCACHE="/Users/rselph/Library/Caches/go-build" GOENV="/Users/rselph/Library/Application Support/go/env" GOEXE="" GOFLAGS="" GOHOSTARCH="amd64" GOHOSTOS="darwin" GONOPROXY="" GONOSUMDB="" GOOS="darwin" GOPATH="/Users/rselph/go" GOPRIVATE="" GOPROXY="https://proxy.golang.org,direct" GOROOT="/opt/local/lib/go" GOSUMDB="sum.golang.org" GOTMPDIR="" GOTOOLDIR="/opt/local/lib/go/pkg/tool/darwin_amd64" GCCGO="gccgo" AR="ar" CC="/usr/bin/clang" CXX="clang++" CGO_ENABLED="1" GOMOD="" CGO_CFLAGS="-g -O2" CGO_CPPFLAGS="" CGO_CXXFLAGS="-g -O2" CGO_FFLAGS="-g -O2" CGO_LDFLAGS="-g -O2" PKG_CONFIG="pkg-config" GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/4w/6dmz_gmd6fj_qy_nwdwclg8c0000gp/T/go-build675848548=/tmp/go-build -gno-record-gcc-switches -fno-common" GOROOT/bin/go version: go version go1.13 darwin/amd64 GOROOT/bin/go tool compile -V: compile version go1.13 uname -v: Darwin Kernel Version 18.7.0: Tue Aug 20 16:57:14 PDT 2019; root:xnu-4903.271.2~2/RELEASE_X86_64 ProductName: Mac OS X ProductVersion: 10.14.6 BuildVersion: 18G95 lldb --version: lldb-1001.0.13.3 Swift-5.0
What did you do?
Option A:
$ git clone https://github.com/rselph-tibco/go-unstable-mods.git
$ cd go-unstable-mods
$ git checkout start_here
$ git switch -c new_branch
$ ./run.sh
The git repository will be updated with the results of each step. Optionally, comment out the git commands to simply produce the error without recording results along the way.
This is equivalent to:
- Start with the contents of the attached file go-unstable-mods-start_here.tar.gz
- Set GOPATH and GOCACHE to point at empty directories
- From the sample1 directory run
go mod tidy
- From the sample2 directory run
go mod tidy
- From the sample2 directory run
go install ./...
- From the sample1 directory run
go install ./...
- Repeat the last step indefinitely
At this point, sample1/go.mod will never stabilize.
What did you expect to see?
go.mod should stabilize when the build is given the same inputs over and over.
What did you see instead?
go.mod eventually oscillates between two states, preventing -mod readonly
from ever working, and wreaking
havoc with source control.
About this issue
- Original URL
- State: open
- Created 5 years ago
- Reactions: 3
- Comments: 24 (16 by maintainers)
Commits related to this issue
- go.mod: cut circular dependency on github.com/containerd/containerd This forces vendoring to only take dependencies of this repository to be taken into account, effectively cutting the circular depen... — committed to thaJeztah/containerd by thaJeztah 3 years ago
- go.mod: cut circular dependency on github.com/containerd/containerd This forces vendoring to only take dependencies of this repository to be taken into account, effectively cutting the circular depen... — committed to thaJeztah/containerd by thaJeztah 3 years ago
- go.mod: cut circular dependency on github.com/containerd/containerd This forces vendoring to only take dependencies of this repository to be taken into account, effectively cutting the circular depen... — committed to fahedouch/containerd by thaJeztah 3 years ago
- go.mod: cut circular dependency on github.com/containerd/containerd This forces vendoring to only take dependencies of this repository to be taken into account, effectively cutting the circular depen... — committed to dims/containerd-api-only by thaJeztah 3 years ago
- go.mod: cut circular dependency on github.com/containerd/containerd This forces vendoring to only take dependencies of this repository to be taken into account, effectively cutting the circular depen... — committed to dims/containerd-api-only by thaJeztah 3 years ago
- go.mod: cut circular dependency on github.com/containerd/containerd This forces vendoring to only take dependencies of this repository to be taken into account, effectively cutting the circular depen... — committed to dims/containerd-api-only by thaJeztah 3 years ago
- go.mod: cut circular dependency on github.com/containerd/containerd This forces vendoring to only take dependencies of this repository to be taken into account, effectively cutting the circular depen... — committed to dims/containerd-api-only by thaJeztah 3 years ago
- go.mod: cut circular dependency on github.com/containerd/containerd This forces vendoring to only take dependencies of this repository to be taken into account, effectively cutting the circular depen... — committed to dims/containerd-api-only by thaJeztah 3 years ago
- go.mod: cut circular dependency on github.com/containerd/containerd This forces vendoring to only take dependencies of this repository to be taken into account, effectively cutting the circular depen... — committed to akhilerm/containerd-api by thaJeztah 3 years ago
- go.mod: cut circular dependency on github.com/containerd/containerd This forces vendoring to only take dependencies of this repository to be taken into account, effectively cutting the circular depen... — committed to akhilerm/containerd-api by thaJeztah 3 years ago
- go.mod: cut circular dependency on github.com/containerd/containerd This forces vendoring to only take dependencies of this repository to be taken into account, effectively cutting the circular depen... — committed to akhilerm/containerd-api by thaJeztah 3 years ago
- go.mod: cut circular dependency on github.com/containerd/containerd This forces vendoring to only take dependencies of this repository to be taken into account, effectively cutting the circular depen... — committed to akhilerm/containerd-api by thaJeztah 3 years ago
- go.mod: cut circular dependency on github.com/containerd/containerd This forces vendoring to only take dependencies of this repository to be taken into account, effectively cutting the circular depen... — committed to akhilerm/containerd-api by thaJeztah 3 years ago
- go.mod: cut circular dependency on github.com/containerd/containerd This forces vendoring to only take dependencies of this repository to be taken into account, effectively cutting the circular depen... — committed to akhilerm/containerd-api by thaJeztah 3 years ago
- go.mod: cut circular dependency on github.com/containerd/containerd This forces vendoring to only take dependencies of this repository to be taken into account, effectively cutting the circular depen... — committed to akhilerm/containerd-test by thaJeztah 3 years ago
- go.mod: cut circular dependency on github.com/containerd/containerd This forces vendoring to only take dependencies of this repository to be taken into account, effectively cutting the circular depen... — committed to akhilerm/containerd-test by thaJeztah 3 years ago
To be clear, a dummy commit is not strictly necessary.
The root of the complexity here is that the main module must always be the selected version of itself. It cannot be replaced with anything else, and since it has no explicit version, its effective version must be interpreted to be higher than any other version of the same module path.
Since the main module cannot be replaced with anything else, the
replace
directive for an older version of the main module must name some explicit version: it cannot be versionless.One solution, as you found, is to push an empty commit and name that version.
However, another is to decide on the version that names the initial
tls.dns
commit ahead of time (for example,v0.1.0
) and name that explicitly in thecaddy/v2
go.mod
file, and havetls.dns
replace that specific version of its own path instead of using a wildcard version: https://play.golang.org/p/TM8Q-jI2QXX#33370 is very relevant to this use-case, but as noted in https://github.com/golang/go/issues/33370#issuecomment-542377792, we probably shouldn’t be writing out an explicit
require
at all if the latest version of an unresolved dependency is the subject of areplace
directive.I took a quick look at this, need to investigate further though.
The first
go install ./...
command insample1
removes a bunch of requirements from go.mod. The only reason that would happen is if the requirements are implied or redundant with some transitive requirement. Since each module is replacing itself and requiring the other module at an invalid version, I thinksample1
is seeing its own go.mod file as a go.mod in a different version ofsample1
, so it sees its own requirements as redundant.As I said, need to investigate further, but this seems like a strange edge case of
replace
. We should forbid modules from replacing themselves without specifying a version.