Description
(Caveat: I'm not sure whether this is actually a good idea, and I'm really not sure whether it's feasible in time for the 1.11 experiment.)
In this golang-dev message, @rsc explains why GO111MODULE=auto
doesn't work inside $GOPATH/src
:
in auto mode we're trying not to break the existing meaning of working in the non-module-aware GOPATH/src/A: it's no good to redefine what the B half of it means.
I think there is a way to make modules work within $GOPATH/src
without changing the existing meaning of $GOPATH/src
.
When GO111MODULE=on
or GO111MODULE=auto
,
-
When the user runs
go get mod/pkg@version
within$GOPATH/src
, update the contents of$GOPATH/src
to match the versions implied by that dependency.- Download (to
$GOPATH/src
) any modules needed to satisfy the (transitive) imports ofmod/pkg
, just like the oldgo get
but taking versions into account.- If any of those packages have been modified,
go get
should fail (the same as it does today if you rungo get -u pkg
with modified dependencies).
- If any of those packages have been modified,
- If any other modules in the build list are present in
$GOPATH/src
, update their contents too — even if they are not needed to satisfy imports. - Leave the
$GOPATH/src
contents unchanged for any module that was removed from the build list entirely.
- Download (to
-
If a build within a module in
$GOPATH/src
imports a package from a module that is not present in$GOPATH/src
, copy that module into$GOPATH/src
(asgo get
would do). -
Whenever any package within any module in
$GOPATH/src
is built, update itsgo.mod
file to reflect the actual contents of$GOPATH/src
. That way, any futurego
commands within that module will produce the same contents as the current build.⚠ This is the difficult part of this proposal!
- For each module involved in the build, compare the contents of that module's
go.mod
file with the contents of its (transitive) dependencies in$GOPATH/src
, ignoring any modules that are not present (e.g., because they were not needed to satisfy transitive imports). - Keep the original
require
directives from that module'sgo.mod
file. Addreplace
directives for any (transitive) dependencies that do not match the versions implied by that module'sgo.mod
. If the source code stored in$GOPATH
still matches a committed (and non-excluded) version, use that version as the replacement; otherwise, use the local filesystem path. - Since
replace
directives do not affect other modules, ignore changes to them when comparing the contents of dependencies, including viago.sum
checksums.
- For each module involved in the build, compare the contents of that module's
-
If a build within a module in
$GOPATH/src
imports a package that is present in$GOPATH/src
but does not have an associated module, addrequire
andreplace
directives (pointing into$GOPATH
) to thego.mod
files for all affected modules, as if there were a top-levelgo.mod
for$GOPATH/src
itself.module github.com/bcmills/module-with-unsatisfied-imports require GOPATH/src v0.0.0 replace GOPATH/src => /home/bcmills/src
I believe that those steps maintain the essential properties of both $GOPATH
and modules. Namely:
- The source files in
$GOPATH/src
are exactly the files used for builds within$GOPATH/src
. - All source files used for builds within
$GOPATH/src
are present in$GOPATH/src
. - The
go.mod
files within$GOPATH/src
accurately describe the sources used for builds. - The
go.mod
files within$GOPATH/src
include requirements for all packages imported during builds.