imports: stop using go/packages for modules
go/packages needs to call `go list` multiple times, which causes
redundant work and slows down goimports. If we reimplement `go list` in
memory, we can reuse state, saving time. `go list` also does work we
don't really need, like adding stuff to go.mod, and skipping that saves
more time.
We start with `go list -m`, which does MVS and such. The remaining work
is mostly mapping import paths and directories through the in-scope
modules to make sure we're giving the right answers. Unfortunately this
is quite subtle, and I don't know where all the traps are. I did my
best.
cmd/go already has tests for `go list`, of course, and packagestest is
not well suited to tests of this complexity. So I ripped off the script
tests in cmd/go that seemed relevant and made sure that our logic
returns the right stuff in each case. I'm sure that there are more cases
to cover, but this hit all the stuff I knew about and quite a bit I
didn't.
Since we may want to use the go/packages code path in the future, e.g.
for Bazel, I left that in place. It won't be used unless the magic env
var is set.
Files in internal and imports/testdata/mod were copied verbatim from
cmd/go.
Change-Id: I1248d99c400c1a0c7ef180d4460b9b8a3db0246b
Reviewed-on: https://go-review.googlesource.com/c/158097
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
2019-01-16 14:24:49 -07:00
|
|
|
// +build go1.11
|
|
|
|
|
|
|
|
package imports
|
|
|
|
|
|
|
|
import (
|
|
|
|
"archive/zip"
|
2019-12-26 17:13:58 -07:00
|
|
|
"context"
|
imports: stop using go/packages for modules
go/packages needs to call `go list` multiple times, which causes
redundant work and slows down goimports. If we reimplement `go list` in
memory, we can reuse state, saving time. `go list` also does work we
don't really need, like adding stuff to go.mod, and skipping that saves
more time.
We start with `go list -m`, which does MVS and such. The remaining work
is mostly mapping import paths and directories through the in-scope
modules to make sure we're giving the right answers. Unfortunately this
is quite subtle, and I don't know where all the traps are. I did my
best.
cmd/go already has tests for `go list`, of course, and packagestest is
not well suited to tests of this complexity. So I ripped off the script
tests in cmd/go that seemed relevant and made sure that our logic
returns the right stuff in each case. I'm sure that there are more cases
to cover, but this hit all the stuff I knew about and quite a bit I
didn't.
Since we may want to use the go/packages code path in the future, e.g.
for Bazel, I left that in place. It won't be used unless the magic env
var is set.
Files in internal and imports/testdata/mod were copied verbatim from
cmd/go.
Change-Id: I1248d99c400c1a0c7ef180d4460b9b8a3db0246b
Reviewed-on: https://go-review.googlesource.com/c/158097
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
2019-01-16 14:24:49 -07:00
|
|
|
"fmt"
|
2019-03-15 13:21:23 -06:00
|
|
|
"go/build"
|
imports: stop using go/packages for modules
go/packages needs to call `go list` multiple times, which causes
redundant work and slows down goimports. If we reimplement `go list` in
memory, we can reuse state, saving time. `go list` also does work we
don't really need, like adding stuff to go.mod, and skipping that saves
more time.
We start with `go list -m`, which does MVS and such. The remaining work
is mostly mapping import paths and directories through the in-scope
modules to make sure we're giving the right answers. Unfortunately this
is quite subtle, and I don't know where all the traps are. I did my
best.
cmd/go already has tests for `go list`, of course, and packagestest is
not well suited to tests of this complexity. So I ripped off the script
tests in cmd/go that seemed relevant and made sure that our logic
returns the right stuff in each case. I'm sure that there are more cases
to cover, but this hit all the stuff I knew about and quite a bit I
didn't.
Since we may want to use the go/packages code path in the future, e.g.
for Bazel, I left that in place. It won't be used unless the magic env
var is set.
Files in internal and imports/testdata/mod were copied verbatim from
cmd/go.
Change-Id: I1248d99c400c1a0c7ef180d4460b9b8a3db0246b
Reviewed-on: https://go-review.googlesource.com/c/158097
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
2019-01-16 14:24:49 -07:00
|
|
|
"io/ioutil"
|
2019-10-04 13:38:18 -06:00
|
|
|
"log"
|
imports: stop using go/packages for modules
go/packages needs to call `go list` multiple times, which causes
redundant work and slows down goimports. If we reimplement `go list` in
memory, we can reuse state, saving time. `go list` also does work we
don't really need, like adding stuff to go.mod, and skipping that saves
more time.
We start with `go list -m`, which does MVS and such. The remaining work
is mostly mapping import paths and directories through the in-scope
modules to make sure we're giving the right answers. Unfortunately this
is quite subtle, and I don't know where all the traps are. I did my
best.
cmd/go already has tests for `go list`, of course, and packagestest is
not well suited to tests of this complexity. So I ripped off the script
tests in cmd/go that seemed relevant and made sure that our logic
returns the right stuff in each case. I'm sure that there are more cases
to cover, but this hit all the stuff I knew about and quite a bit I
didn't.
Since we may want to use the go/packages code path in the future, e.g.
for Bazel, I left that in place. It won't be used unless the magic env
var is set.
Files in internal and imports/testdata/mod were copied verbatim from
cmd/go.
Change-Id: I1248d99c400c1a0c7ef180d4460b9b8a3db0246b
Reviewed-on: https://go-review.googlesource.com/c/158097
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
2019-01-16 14:24:49 -07:00
|
|
|
"os"
|
|
|
|
"path/filepath"
|
2019-10-30 14:59:29 -06:00
|
|
|
"reflect"
|
imports: stop using go/packages for modules
go/packages needs to call `go list` multiple times, which causes
redundant work and slows down goimports. If we reimplement `go list` in
memory, we can reuse state, saving time. `go list` also does work we
don't really need, like adding stuff to go.mod, and skipping that saves
more time.
We start with `go list -m`, which does MVS and such. The remaining work
is mostly mapping import paths and directories through the in-scope
modules to make sure we're giving the right answers. Unfortunately this
is quite subtle, and I don't know where all the traps are. I did my
best.
cmd/go already has tests for `go list`, of course, and packagestest is
not well suited to tests of this complexity. So I ripped off the script
tests in cmd/go that seemed relevant and made sure that our logic
returns the right stuff in each case. I'm sure that there are more cases
to cover, but this hit all the stuff I knew about and quite a bit I
didn't.
Since we may want to use the go/packages code path in the future, e.g.
for Bazel, I left that in place. It won't be used unless the magic env
var is set.
Files in internal and imports/testdata/mod were copied verbatim from
cmd/go.
Change-Id: I1248d99c400c1a0c7ef180d4460b9b8a3db0246b
Reviewed-on: https://go-review.googlesource.com/c/158097
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
2019-01-16 14:24:49 -07:00
|
|
|
"regexp"
|
2019-12-27 13:46:49 -07:00
|
|
|
"sort"
|
imports: stop using go/packages for modules
go/packages needs to call `go list` multiple times, which causes
redundant work and slows down goimports. If we reimplement `go list` in
memory, we can reuse state, saving time. `go list` also does work we
don't really need, like adding stuff to go.mod, and skipping that saves
more time.
We start with `go list -m`, which does MVS and such. The remaining work
is mostly mapping import paths and directories through the in-scope
modules to make sure we're giving the right answers. Unfortunately this
is quite subtle, and I don't know where all the traps are. I did my
best.
cmd/go already has tests for `go list`, of course, and packagestest is
not well suited to tests of this complexity. So I ripped off the script
tests in cmd/go that seemed relevant and made sure that our logic
returns the right stuff in each case. I'm sure that there are more cases
to cover, but this hit all the stuff I knew about and quite a bit I
didn't.
Since we may want to use the go/packages code path in the future, e.g.
for Bazel, I left that in place. It won't be used unless the magic env
var is set.
Files in internal and imports/testdata/mod were copied verbatim from
cmd/go.
Change-Id: I1248d99c400c1a0c7ef180d4460b9b8a3db0246b
Reviewed-on: https://go-review.googlesource.com/c/158097
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
2019-01-16 14:24:49 -07:00
|
|
|
"strings"
|
|
|
|
"sync"
|
|
|
|
"testing"
|
|
|
|
|
2020-02-10 11:54:36 -07:00
|
|
|
"golang.org/x/mod/module"
|
2020-03-23 06:35:36 -06:00
|
|
|
"golang.org/x/tools/internal/gocommand"
|
2019-10-04 13:38:18 -06:00
|
|
|
"golang.org/x/tools/internal/gopathwalk"
|
2019-08-29 14:22:26 -06:00
|
|
|
"golang.org/x/tools/internal/testenv"
|
2019-11-19 14:48:20 -07:00
|
|
|
"golang.org/x/tools/txtar"
|
imports: stop using go/packages for modules
go/packages needs to call `go list` multiple times, which causes
redundant work and slows down goimports. If we reimplement `go list` in
memory, we can reuse state, saving time. `go list` also does work we
don't really need, like adding stuff to go.mod, and skipping that saves
more time.
We start with `go list -m`, which does MVS and such. The remaining work
is mostly mapping import paths and directories through the in-scope
modules to make sure we're giving the right answers. Unfortunately this
is quite subtle, and I don't know where all the traps are. I did my
best.
cmd/go already has tests for `go list`, of course, and packagestest is
not well suited to tests of this complexity. So I ripped off the script
tests in cmd/go that seemed relevant and made sure that our logic
returns the right stuff in each case. I'm sure that there are more cases
to cover, but this hit all the stuff I knew about and quite a bit I
didn't.
Since we may want to use the go/packages code path in the future, e.g.
for Bazel, I left that in place. It won't be used unless the magic env
var is set.
Files in internal and imports/testdata/mod were copied verbatim from
cmd/go.
Change-Id: I1248d99c400c1a0c7ef180d4460b9b8a3db0246b
Reviewed-on: https://go-review.googlesource.com/c/158097
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
2019-01-16 14:24:49 -07:00
|
|
|
)
|
|
|
|
|
2019-09-10 14:48:19 -06:00
|
|
|
// Tests that we can find packages in the stdlib.
|
|
|
|
func TestScanStdlib(t *testing.T) {
|
|
|
|
mt := setup(t, `
|
|
|
|
-- go.mod --
|
|
|
|
module x
|
|
|
|
`, "")
|
|
|
|
defer mt.cleanup()
|
|
|
|
|
|
|
|
mt.assertScanFinds("fmt", "fmt")
|
|
|
|
}
|
|
|
|
|
imports: stop using go/packages for modules
go/packages needs to call `go list` multiple times, which causes
redundant work and slows down goimports. If we reimplement `go list` in
memory, we can reuse state, saving time. `go list` also does work we
don't really need, like adding stuff to go.mod, and skipping that saves
more time.
We start with `go list -m`, which does MVS and such. The remaining work
is mostly mapping import paths and directories through the in-scope
modules to make sure we're giving the right answers. Unfortunately this
is quite subtle, and I don't know where all the traps are. I did my
best.
cmd/go already has tests for `go list`, of course, and packagestest is
not well suited to tests of this complexity. So I ripped off the script
tests in cmd/go that seemed relevant and made sure that our logic
returns the right stuff in each case. I'm sure that there are more cases
to cover, but this hit all the stuff I knew about and quite a bit I
didn't.
Since we may want to use the go/packages code path in the future, e.g.
for Bazel, I left that in place. It won't be used unless the magic env
var is set.
Files in internal and imports/testdata/mod were copied verbatim from
cmd/go.
Change-Id: I1248d99c400c1a0c7ef180d4460b9b8a3db0246b
Reviewed-on: https://go-review.googlesource.com/c/158097
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
2019-01-16 14:24:49 -07:00
|
|
|
// Tests that we handle a nested module. This is different from other tests
|
|
|
|
// where the module is in scope -- here we have to figure out the import path
|
|
|
|
// without any help from go list.
|
|
|
|
func TestScanOutOfScopeNestedModule(t *testing.T) {
|
|
|
|
mt := setup(t, `
|
|
|
|
-- go.mod --
|
|
|
|
module x
|
|
|
|
|
|
|
|
-- x.go --
|
|
|
|
package x
|
|
|
|
|
|
|
|
-- v2/go.mod --
|
|
|
|
module x
|
|
|
|
|
|
|
|
-- v2/x.go --
|
|
|
|
package x`, "")
|
|
|
|
defer mt.cleanup()
|
|
|
|
|
|
|
|
pkg := mt.assertScanFinds("x/v2", "x")
|
|
|
|
if pkg != nil && !strings.HasSuffix(filepath.ToSlash(pkg.dir), "main/v2") {
|
|
|
|
t.Errorf("x/v2 was found in %v, wanted .../main/v2", pkg.dir)
|
|
|
|
}
|
|
|
|
// We can't load the package name from the import path, but that should
|
|
|
|
// be okay -- if we end up adding this result, we'll add it with a name
|
|
|
|
// if necessary.
|
|
|
|
}
|
|
|
|
|
|
|
|
// Tests that we don't find a nested module contained in a local replace target.
|
|
|
|
// The code for this case is too annoying to write, so it's just ignored.
|
|
|
|
func TestScanNestedModuleInLocalReplace(t *testing.T) {
|
|
|
|
mt := setup(t, `
|
|
|
|
-- go.mod --
|
|
|
|
module x
|
|
|
|
|
|
|
|
require y v0.0.0
|
|
|
|
replace y => ./y
|
|
|
|
|
|
|
|
-- x.go --
|
|
|
|
package x
|
|
|
|
|
|
|
|
-- y/go.mod --
|
|
|
|
module y
|
|
|
|
|
|
|
|
-- y/y.go --
|
|
|
|
package y
|
|
|
|
|
|
|
|
-- y/z/go.mod --
|
|
|
|
module y/z
|
|
|
|
|
|
|
|
-- y/z/z.go --
|
|
|
|
package z
|
|
|
|
`, "")
|
|
|
|
defer mt.cleanup()
|
|
|
|
|
|
|
|
mt.assertFound("y", "y")
|
|
|
|
|
2019-12-26 17:13:58 -07:00
|
|
|
scan, err := scanToSlice(mt.resolver, nil)
|
imports: stop using go/packages for modules
go/packages needs to call `go list` multiple times, which causes
redundant work and slows down goimports. If we reimplement `go list` in
memory, we can reuse state, saving time. `go list` also does work we
don't really need, like adding stuff to go.mod, and skipping that saves
more time.
We start with `go list -m`, which does MVS and such. The remaining work
is mostly mapping import paths and directories through the in-scope
modules to make sure we're giving the right answers. Unfortunately this
is quite subtle, and I don't know where all the traps are. I did my
best.
cmd/go already has tests for `go list`, of course, and packagestest is
not well suited to tests of this complexity. So I ripped off the script
tests in cmd/go that seemed relevant and made sure that our logic
returns the right stuff in each case. I'm sure that there are more cases
to cover, but this hit all the stuff I knew about and quite a bit I
didn't.
Since we may want to use the go/packages code path in the future, e.g.
for Bazel, I left that in place. It won't be used unless the magic env
var is set.
Files in internal and imports/testdata/mod were copied verbatim from
cmd/go.
Change-Id: I1248d99c400c1a0c7ef180d4460b9b8a3db0246b
Reviewed-on: https://go-review.googlesource.com/c/158097
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
2019-01-16 14:24:49 -07:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
for _, pkg := range scan {
|
|
|
|
if strings.HasSuffix(filepath.ToSlash(pkg.dir), "main/y/z") {
|
|
|
|
t.Errorf("scan found a package %v in dir main/y/z, wanted none", pkg.importPathShort)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Tests that path encoding is handled correctly. Adapted from mod_case.txt.
|
|
|
|
func TestModCase(t *testing.T) {
|
|
|
|
mt := setup(t, `
|
|
|
|
-- go.mod --
|
|
|
|
module x
|
|
|
|
|
|
|
|
require rsc.io/QUOTE v1.5.2
|
|
|
|
|
|
|
|
-- x.go --
|
|
|
|
package x
|
|
|
|
|
|
|
|
import _ "rsc.io/QUOTE/QUOTE"
|
|
|
|
`, "")
|
|
|
|
defer mt.cleanup()
|
|
|
|
mt.assertFound("rsc.io/QUOTE/QUOTE", "QUOTE")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Not obviously relevant to goimports. Adapted from mod_domain_root.txt anyway.
|
|
|
|
func TestModDomainRoot(t *testing.T) {
|
|
|
|
mt := setup(t, `
|
|
|
|
-- go.mod --
|
|
|
|
module x
|
|
|
|
|
|
|
|
require example.com v1.0.0
|
|
|
|
|
|
|
|
-- x.go --
|
|
|
|
package x
|
|
|
|
import _ "example.com"
|
|
|
|
`, "")
|
|
|
|
defer mt.cleanup()
|
|
|
|
mt.assertFound("example.com", "x")
|
|
|
|
}
|
|
|
|
|
2019-07-16 15:37:05 -06:00
|
|
|
// Tests that scanning the module cache > 1 time is able to find the same module.
|
|
|
|
func TestModMultipleScans(t *testing.T) {
|
|
|
|
mt := setup(t, `
|
|
|
|
-- go.mod --
|
|
|
|
module x
|
|
|
|
|
|
|
|
require example.com v1.0.0
|
|
|
|
|
|
|
|
-- x.go --
|
|
|
|
package x
|
|
|
|
import _ "example.com"
|
|
|
|
`, "")
|
|
|
|
defer mt.cleanup()
|
|
|
|
|
|
|
|
mt.assertScanFinds("example.com", "x")
|
|
|
|
mt.assertScanFinds("example.com", "x")
|
|
|
|
}
|
|
|
|
|
2019-07-19 10:41:29 -06:00
|
|
|
// Tests that scanning the module cache > 1 time is able to find the same module
|
|
|
|
// in the module cache.
|
|
|
|
func TestModMultipleScansWithSubdirs(t *testing.T) {
|
|
|
|
mt := setup(t, `
|
|
|
|
-- go.mod --
|
|
|
|
module x
|
|
|
|
|
|
|
|
require rsc.io/quote v1.5.2
|
|
|
|
|
|
|
|
-- x.go --
|
|
|
|
package x
|
|
|
|
import _ "rsc.io/quote"
|
|
|
|
`, "")
|
|
|
|
defer mt.cleanup()
|
|
|
|
|
2019-10-04 13:38:18 -06:00
|
|
|
mt.assertScanFinds("rsc.io/quote", "quote")
|
|
|
|
mt.assertScanFinds("rsc.io/quote", "quote")
|
2019-07-19 10:41:29 -06:00
|
|
|
}
|
|
|
|
|
2019-08-02 12:05:22 -06:00
|
|
|
// Tests that scanning the module cache > 1 after changing a package in module cache to make it unimportable
|
|
|
|
// is able to find the same module.
|
|
|
|
func TestModCacheEditModFile(t *testing.T) {
|
|
|
|
mt := setup(t, `
|
|
|
|
-- go.mod --
|
|
|
|
module x
|
|
|
|
|
|
|
|
require rsc.io/quote v1.5.2
|
|
|
|
-- x.go --
|
|
|
|
package x
|
|
|
|
import _ "rsc.io/quote"
|
|
|
|
`, "")
|
|
|
|
defer mt.cleanup()
|
|
|
|
found := mt.assertScanFinds("rsc.io/quote", "quote")
|
2019-07-19 10:41:29 -06:00
|
|
|
if found == nil {
|
|
|
|
t.Fatal("rsc.io/quote not found in initial scan.")
|
|
|
|
}
|
2019-08-02 12:05:22 -06:00
|
|
|
|
|
|
|
// Update the go.mod file of example.com so that it changes its module path (not allowed).
|
|
|
|
if err := os.Chmod(filepath.Join(found.dir, "go.mod"), 0644); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if err := ioutil.WriteFile(filepath.Join(found.dir, "go.mod"), []byte("module bad.com\n"), 0644); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Test that with its cache of module packages it still finds the package.
|
|
|
|
mt.assertScanFinds("rsc.io/quote", "quote")
|
|
|
|
|
|
|
|
// Rewrite the main package so that rsc.io/quote is not in scope.
|
|
|
|
if err := ioutil.WriteFile(filepath.Join(mt.env.WorkingDir, "go.mod"), []byte("module x\n"), 0644); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if err := ioutil.WriteFile(filepath.Join(mt.env.WorkingDir, "x.go"), []byte("package x\n"), 0644); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Uninitialize the go.mod dependent cached information and make sure it still finds the package.
|
2020-01-02 14:10:45 -07:00
|
|
|
mt.resolver.ClearForNewMod()
|
2019-08-02 12:05:22 -06:00
|
|
|
mt.assertScanFinds("rsc.io/quote", "quote")
|
|
|
|
}
|
|
|
|
|
2019-10-23 15:36:29 -06:00
|
|
|
// Tests that -mod=vendor works. Adapted from mod_vendor_build.txt.
|
|
|
|
func TestModVendorBuild(t *testing.T) {
|
imports: stop using go/packages for modules
go/packages needs to call `go list` multiple times, which causes
redundant work and slows down goimports. If we reimplement `go list` in
memory, we can reuse state, saving time. `go list` also does work we
don't really need, like adding stuff to go.mod, and skipping that saves
more time.
We start with `go list -m`, which does MVS and such. The remaining work
is mostly mapping import paths and directories through the in-scope
modules to make sure we're giving the right answers. Unfortunately this
is quite subtle, and I don't know where all the traps are. I did my
best.
cmd/go already has tests for `go list`, of course, and packagestest is
not well suited to tests of this complexity. So I ripped off the script
tests in cmd/go that seemed relevant and made sure that our logic
returns the right stuff in each case. I'm sure that there are more cases
to cover, but this hit all the stuff I knew about and quite a bit I
didn't.
Since we may want to use the go/packages code path in the future, e.g.
for Bazel, I left that in place. It won't be used unless the magic env
var is set.
Files in internal and imports/testdata/mod were copied verbatim from
cmd/go.
Change-Id: I1248d99c400c1a0c7ef180d4460b9b8a3db0246b
Reviewed-on: https://go-review.googlesource.com/c/158097
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
2019-01-16 14:24:49 -07:00
|
|
|
mt := setup(t, `
|
|
|
|
-- go.mod --
|
2019-10-23 15:36:29 -06:00
|
|
|
module m
|
|
|
|
go 1.12
|
|
|
|
require rsc.io/sampler v1.3.1
|
imports: stop using go/packages for modules
go/packages needs to call `go list` multiple times, which causes
redundant work and slows down goimports. If we reimplement `go list` in
memory, we can reuse state, saving time. `go list` also does work we
don't really need, like adding stuff to go.mod, and skipping that saves
more time.
We start with `go list -m`, which does MVS and such. The remaining work
is mostly mapping import paths and directories through the in-scope
modules to make sure we're giving the right answers. Unfortunately this
is quite subtle, and I don't know where all the traps are. I did my
best.
cmd/go already has tests for `go list`, of course, and packagestest is
not well suited to tests of this complexity. So I ripped off the script
tests in cmd/go that seemed relevant and made sure that our logic
returns the right stuff in each case. I'm sure that there are more cases
to cover, but this hit all the stuff I knew about and quite a bit I
didn't.
Since we may want to use the go/packages code path in the future, e.g.
for Bazel, I left that in place. It won't be used unless the magic env
var is set.
Files in internal and imports/testdata/mod were copied verbatim from
cmd/go.
Change-Id: I1248d99c400c1a0c7ef180d4460b9b8a3db0246b
Reviewed-on: https://go-review.googlesource.com/c/158097
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
2019-01-16 14:24:49 -07:00
|
|
|
-- x.go --
|
|
|
|
package x
|
2019-10-23 15:36:29 -06:00
|
|
|
import _ "rsc.io/sampler"
|
imports: stop using go/packages for modules
go/packages needs to call `go list` multiple times, which causes
redundant work and slows down goimports. If we reimplement `go list` in
memory, we can reuse state, saving time. `go list` also does work we
don't really need, like adding stuff to go.mod, and skipping that saves
more time.
We start with `go list -m`, which does MVS and such. The remaining work
is mostly mapping import paths and directories through the in-scope
modules to make sure we're giving the right answers. Unfortunately this
is quite subtle, and I don't know where all the traps are. I did my
best.
cmd/go already has tests for `go list`, of course, and packagestest is
not well suited to tests of this complexity. So I ripped off the script
tests in cmd/go that seemed relevant and made sure that our logic
returns the right stuff in each case. I'm sure that there are more cases
to cover, but this hit all the stuff I knew about and quite a bit I
didn't.
Since we may want to use the go/packages code path in the future, e.g.
for Bazel, I left that in place. It won't be used unless the magic env
var is set.
Files in internal and imports/testdata/mod were copied verbatim from
cmd/go.
Change-Id: I1248d99c400c1a0c7ef180d4460b9b8a3db0246b
Reviewed-on: https://go-review.googlesource.com/c/158097
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
2019-01-16 14:24:49 -07:00
|
|
|
`, "")
|
|
|
|
defer mt.cleanup()
|
|
|
|
|
2019-10-23 15:36:29 -06:00
|
|
|
// Sanity-check the setup.
|
|
|
|
mt.assertModuleFoundInDir("rsc.io/sampler", "sampler", `pkg.*mod.*/sampler@.*$`)
|
|
|
|
|
|
|
|
// Populate vendor/ and clear out the mod cache so we can't cheat.
|
2020-02-24 14:46:08 -07:00
|
|
|
if _, err := mt.env.invokeGo(context.Background(), "mod", "vendor"); err != nil {
|
imports: stop using go/packages for modules
go/packages needs to call `go list` multiple times, which causes
redundant work and slows down goimports. If we reimplement `go list` in
memory, we can reuse state, saving time. `go list` also does work we
don't really need, like adding stuff to go.mod, and skipping that saves
more time.
We start with `go list -m`, which does MVS and such. The remaining work
is mostly mapping import paths and directories through the in-scope
modules to make sure we're giving the right answers. Unfortunately this
is quite subtle, and I don't know where all the traps are. I did my
best.
cmd/go already has tests for `go list`, of course, and packagestest is
not well suited to tests of this complexity. So I ripped off the script
tests in cmd/go that seemed relevant and made sure that our logic
returns the right stuff in each case. I'm sure that there are more cases
to cover, but this hit all the stuff I knew about and quite a bit I
didn't.
Since we may want to use the go/packages code path in the future, e.g.
for Bazel, I left that in place. It won't be used unless the magic env
var is set.
Files in internal and imports/testdata/mod were copied verbatim from
cmd/go.
Change-Id: I1248d99c400c1a0c7ef180d4460b9b8a3db0246b
Reviewed-on: https://go-review.googlesource.com/c/158097
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
2019-01-16 14:24:49 -07:00
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2020-02-24 14:46:08 -07:00
|
|
|
if _, err := mt.env.invokeGo(context.Background(), "clean", "-modcache"); err != nil {
|
2019-10-23 15:36:29 -06:00
|
|
|
t.Fatal(err)
|
|
|
|
}
|
imports: stop using go/packages for modules
go/packages needs to call `go list` multiple times, which causes
redundant work and slows down goimports. If we reimplement `go list` in
memory, we can reuse state, saving time. `go list` also does work we
don't really need, like adding stuff to go.mod, and skipping that saves
more time.
We start with `go list -m`, which does MVS and such. The remaining work
is mostly mapping import paths and directories through the in-scope
modules to make sure we're giving the right answers. Unfortunately this
is quite subtle, and I don't know where all the traps are. I did my
best.
cmd/go already has tests for `go list`, of course, and packagestest is
not well suited to tests of this complexity. So I ripped off the script
tests in cmd/go that seemed relevant and made sure that our logic
returns the right stuff in each case. I'm sure that there are more cases
to cover, but this hit all the stuff I knew about and quite a bit I
didn't.
Since we may want to use the go/packages code path in the future, e.g.
for Bazel, I left that in place. It won't be used unless the magic env
var is set.
Files in internal and imports/testdata/mod were copied verbatim from
cmd/go.
Change-Id: I1248d99c400c1a0c7ef180d4460b9b8a3db0246b
Reviewed-on: https://go-review.googlesource.com/c/158097
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
2019-01-16 14:24:49 -07:00
|
|
|
|
|
|
|
// Clear out the resolver's cache, since we've changed the environment.
|
2020-01-09 17:14:18 -07:00
|
|
|
mt.resolver = newModuleResolver(mt.env)
|
2019-10-23 15:36:29 -06:00
|
|
|
mt.env.GOFLAGS = "-mod=vendor"
|
|
|
|
mt.assertModuleFoundInDir("rsc.io/sampler", "sampler", `/vendor/`)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Tests that -mod=vendor is auto-enabled only for go1.14 and higher.
|
|
|
|
// Vaguely inspired by mod_vendor_auto.txt.
|
|
|
|
func testModVendorAuto(t *testing.T, wantEnabled bool) {
|
|
|
|
mt := setup(t, `
|
|
|
|
-- go.mod --
|
|
|
|
module m
|
|
|
|
go 1.14
|
|
|
|
require rsc.io/sampler v1.3.1
|
|
|
|
-- x.go --
|
|
|
|
package x
|
|
|
|
import _ "rsc.io/sampler"
|
|
|
|
`, "")
|
|
|
|
defer mt.cleanup()
|
|
|
|
|
|
|
|
// Populate vendor/.
|
2020-02-24 14:46:08 -07:00
|
|
|
if _, err := mt.env.invokeGo(context.Background(), "mod", "vendor"); err != nil {
|
2019-10-23 15:36:29 -06:00
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
wantDir := `pkg.*mod.*/sampler@.*$`
|
|
|
|
if wantEnabled {
|
|
|
|
wantDir = `/vendor/`
|
|
|
|
}
|
|
|
|
mt.assertModuleFoundInDir("rsc.io/sampler", "sampler", wantDir)
|
imports: stop using go/packages for modules
go/packages needs to call `go list` multiple times, which causes
redundant work and slows down goimports. If we reimplement `go list` in
memory, we can reuse state, saving time. `go list` also does work we
don't really need, like adding stuff to go.mod, and skipping that saves
more time.
We start with `go list -m`, which does MVS and such. The remaining work
is mostly mapping import paths and directories through the in-scope
modules to make sure we're giving the right answers. Unfortunately this
is quite subtle, and I don't know where all the traps are. I did my
best.
cmd/go already has tests for `go list`, of course, and packagestest is
not well suited to tests of this complexity. So I ripped off the script
tests in cmd/go that seemed relevant and made sure that our logic
returns the right stuff in each case. I'm sure that there are more cases
to cover, but this hit all the stuff I knew about and quite a bit I
didn't.
Since we may want to use the go/packages code path in the future, e.g.
for Bazel, I left that in place. It won't be used unless the magic env
var is set.
Files in internal and imports/testdata/mod were copied verbatim from
cmd/go.
Change-Id: I1248d99c400c1a0c7ef180d4460b9b8a3db0246b
Reviewed-on: https://go-review.googlesource.com/c/158097
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
2019-01-16 14:24:49 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Tests that a module replace works. Adapted from mod_list.txt. We start with
|
|
|
|
// go.mod2; the first part of the test is irrelevant.
|
|
|
|
func TestModList(t *testing.T) {
|
|
|
|
mt := setup(t, `
|
|
|
|
-- go.mod --
|
|
|
|
module x
|
|
|
|
require rsc.io/quote v1.5.1
|
|
|
|
replace rsc.io/sampler v1.3.0 => rsc.io/sampler v1.3.1
|
|
|
|
|
|
|
|
-- x.go --
|
|
|
|
package x
|
|
|
|
import _ "rsc.io/quote"
|
|
|
|
`, "")
|
|
|
|
defer mt.cleanup()
|
|
|
|
|
|
|
|
mt.assertModuleFoundInDir("rsc.io/sampler", "sampler", `pkg.mod.*/sampler@v1.3.1$`)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Tests that a local replace works. Adapted from mod_local_replace.txt.
|
|
|
|
func TestModLocalReplace(t *testing.T) {
|
|
|
|
mt := setup(t, `
|
|
|
|
-- x/y/go.mod --
|
|
|
|
module x/y
|
|
|
|
require zz v1.0.0
|
|
|
|
replace zz v1.0.0 => ../z
|
|
|
|
|
|
|
|
-- x/y/y.go --
|
|
|
|
package y
|
|
|
|
import _ "zz"
|
|
|
|
|
|
|
|
-- x/z/go.mod --
|
|
|
|
module x/z
|
|
|
|
|
|
|
|
-- x/z/z.go --
|
|
|
|
package z
|
|
|
|
`, "x/y")
|
|
|
|
defer mt.cleanup()
|
|
|
|
|
|
|
|
mt.assertFound("zz", "z")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Tests that the package at the root of the main module can be found.
|
|
|
|
// Adapted from the first part of mod_multirepo.txt.
|
|
|
|
func TestModMultirepo1(t *testing.T) {
|
|
|
|
mt := setup(t, `
|
|
|
|
-- go.mod --
|
|
|
|
module rsc.io/quote
|
|
|
|
|
|
|
|
-- x.go --
|
|
|
|
package quote
|
|
|
|
`, "")
|
|
|
|
defer mt.cleanup()
|
|
|
|
|
|
|
|
mt.assertModuleFoundInDir("rsc.io/quote", "quote", `/main`)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Tests that a simple module dependency is found. Adapted from the third part
|
|
|
|
// of mod_multirepo.txt (We skip the case where it doesn't have a go.mod
|
|
|
|
// entry -- we just don't work in that case.)
|
|
|
|
func TestModMultirepo3(t *testing.T) {
|
|
|
|
mt := setup(t, `
|
|
|
|
-- go.mod --
|
|
|
|
module rsc.io/quote
|
|
|
|
|
|
|
|
require rsc.io/quote/v2 v2.0.1
|
|
|
|
-- x.go --
|
|
|
|
package quote
|
|
|
|
|
|
|
|
import _ "rsc.io/quote/v2"
|
|
|
|
`, "")
|
|
|
|
defer mt.cleanup()
|
|
|
|
|
|
|
|
mt.assertModuleFoundInDir("rsc.io/quote", "quote", `/main`)
|
|
|
|
mt.assertModuleFoundInDir("rsc.io/quote/v2", "quote", `pkg.mod.*/v2@v2.0.1$`)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Tests that a nested module is found in the module cache, even though
|
|
|
|
// it's checked out. Adapted from the fourth part of mod_multirepo.txt.
|
|
|
|
func TestModMultirepo4(t *testing.T) {
|
|
|
|
mt := setup(t, `
|
|
|
|
-- go.mod --
|
|
|
|
module rsc.io/quote
|
|
|
|
require rsc.io/quote/v2 v2.0.1
|
|
|
|
|
|
|
|
-- x.go --
|
|
|
|
package quote
|
|
|
|
import _ "rsc.io/quote/v2"
|
|
|
|
|
|
|
|
-- v2/go.mod --
|
|
|
|
package rsc.io/quote/v2
|
|
|
|
|
|
|
|
-- v2/x.go --
|
|
|
|
package quote
|
|
|
|
import _ "rsc.io/quote/v2"
|
|
|
|
`, "")
|
|
|
|
defer mt.cleanup()
|
|
|
|
|
|
|
|
mt.assertModuleFoundInDir("rsc.io/quote", "quote", `/main`)
|
|
|
|
mt.assertModuleFoundInDir("rsc.io/quote/v2", "quote", `pkg.mod.*/v2@v2.0.1$`)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Tests a simple module dependency. Adapted from the first part of mod_replace.txt.
|
|
|
|
func TestModReplace1(t *testing.T) {
|
|
|
|
mt := setup(t, `
|
|
|
|
-- go.mod --
|
|
|
|
module quoter
|
|
|
|
|
|
|
|
require rsc.io/quote/v3 v3.0.0
|
|
|
|
|
|
|
|
-- main.go --
|
|
|
|
|
|
|
|
package main
|
|
|
|
`, "")
|
|
|
|
defer mt.cleanup()
|
|
|
|
mt.assertFound("rsc.io/quote/v3", "quote")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Tests a local replace. Adapted from the second part of mod_replace.txt.
|
|
|
|
func TestModReplace2(t *testing.T) {
|
|
|
|
mt := setup(t, `
|
|
|
|
-- go.mod --
|
|
|
|
module quoter
|
|
|
|
|
|
|
|
require rsc.io/quote/v3 v3.0.0
|
|
|
|
replace rsc.io/quote/v3 => ./local/rsc.io/quote/v3
|
|
|
|
-- main.go --
|
|
|
|
package main
|
|
|
|
|
|
|
|
-- local/rsc.io/quote/v3/go.mod --
|
|
|
|
module rsc.io/quote/v3
|
|
|
|
|
|
|
|
require rsc.io/sampler v1.3.0
|
|
|
|
|
|
|
|
-- local/rsc.io/quote/v3/quote.go --
|
|
|
|
package quote
|
|
|
|
|
|
|
|
import "rsc.io/sampler"
|
|
|
|
`, "")
|
|
|
|
defer mt.cleanup()
|
|
|
|
mt.assertModuleFoundInDir("rsc.io/quote/v3", "quote", `/local/rsc.io/quote/v3`)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Tests that a module can be replaced by a different module path. Adapted
|
|
|
|
// from the third part of mod_replace.txt.
|
|
|
|
func TestModReplace3(t *testing.T) {
|
|
|
|
mt := setup(t, `
|
|
|
|
-- go.mod --
|
|
|
|
module quoter
|
|
|
|
|
|
|
|
require not-rsc.io/quote/v3 v3.1.0
|
|
|
|
replace not-rsc.io/quote/v3 v3.1.0 => ./local/rsc.io/quote/v3
|
|
|
|
|
|
|
|
-- usenewmodule/main.go --
|
|
|
|
package main
|
|
|
|
|
|
|
|
-- local/rsc.io/quote/v3/go.mod --
|
|
|
|
module rsc.io/quote/v3
|
|
|
|
|
|
|
|
require rsc.io/sampler v1.3.0
|
|
|
|
|
|
|
|
-- local/rsc.io/quote/v3/quote.go --
|
|
|
|
package quote
|
|
|
|
|
|
|
|
-- local/not-rsc.io/quote/v3/go.mod --
|
|
|
|
module not-rsc.io/quote/v3
|
|
|
|
|
|
|
|
-- local/not-rsc.io/quote/v3/quote.go --
|
|
|
|
package quote
|
|
|
|
`, "")
|
|
|
|
defer mt.cleanup()
|
|
|
|
mt.assertModuleFoundInDir("not-rsc.io/quote/v3", "quote", "local/rsc.io/quote/v3")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Tests more local replaces, notably the case where an outer module provides
|
|
|
|
// a package that could also be provided by an inner module. Adapted from
|
|
|
|
// mod_replace_import.txt, with example.com/v changed to /vv because Go 1.11
|
|
|
|
// thinks /v is an invalid major version.
|
|
|
|
func TestModReplaceImport(t *testing.T) {
|
|
|
|
mt := setup(t, `
|
|
|
|
-- go.mod --
|
|
|
|
module example.com/m
|
|
|
|
|
|
|
|
replace (
|
|
|
|
example.com/a => ./a
|
|
|
|
example.com/a/b => ./b
|
|
|
|
)
|
|
|
|
|
|
|
|
replace (
|
|
|
|
example.com/x => ./x
|
|
|
|
example.com/x/v3 => ./v3
|
|
|
|
)
|
|
|
|
|
|
|
|
replace (
|
|
|
|
example.com/y/z/w => ./w
|
|
|
|
example.com/y => ./y
|
|
|
|
)
|
|
|
|
|
|
|
|
replace (
|
|
|
|
example.com/vv v1.11.0 => ./v11
|
|
|
|
example.com/vv v1.12.0 => ./v12
|
|
|
|
example.com/vv => ./vv
|
|
|
|
)
|
|
|
|
|
|
|
|
require (
|
|
|
|
example.com/a/b v0.0.0
|
|
|
|
example.com/x/v3 v3.0.0
|
|
|
|
example.com/y v0.0.0
|
|
|
|
example.com/y/z/w v0.0.0
|
|
|
|
example.com/vv v1.12.0
|
|
|
|
)
|
|
|
|
-- m.go --
|
|
|
|
package main
|
|
|
|
import (
|
|
|
|
_ "example.com/a/b"
|
|
|
|
_ "example.com/x/v3"
|
|
|
|
_ "example.com/y/z/w"
|
|
|
|
_ "example.com/vv"
|
|
|
|
)
|
|
|
|
func main() {}
|
|
|
|
|
|
|
|
-- a/go.mod --
|
|
|
|
module a.localhost
|
|
|
|
-- a/a.go --
|
|
|
|
package a
|
|
|
|
-- a/b/b.go--
|
|
|
|
package b
|
|
|
|
|
|
|
|
-- b/go.mod --
|
|
|
|
module a.localhost/b
|
|
|
|
-- b/b.go --
|
|
|
|
package b
|
|
|
|
|
|
|
|
-- x/go.mod --
|
|
|
|
module x.localhost
|
|
|
|
-- x/x.go --
|
|
|
|
package x
|
|
|
|
-- x/v3.go --
|
|
|
|
package v3
|
|
|
|
import _ "x.localhost/v3"
|
|
|
|
|
|
|
|
-- v3/go.mod --
|
|
|
|
module x.localhost/v3
|
|
|
|
-- v3/x.go --
|
|
|
|
package x
|
|
|
|
|
|
|
|
-- w/go.mod --
|
|
|
|
module w.localhost
|
|
|
|
-- w/skip/skip.go --
|
|
|
|
// Package skip is nested below nonexistent package w.
|
|
|
|
package skip
|
|
|
|
|
|
|
|
-- y/go.mod --
|
|
|
|
module y.localhost
|
|
|
|
-- y/z/w/w.go --
|
|
|
|
package w
|
|
|
|
|
|
|
|
-- v12/go.mod --
|
|
|
|
module v.localhost
|
|
|
|
-- v12/v.go --
|
|
|
|
package v
|
|
|
|
|
|
|
|
-- v11/go.mod --
|
|
|
|
module v.localhost
|
|
|
|
-- v11/v.go --
|
|
|
|
package v
|
|
|
|
|
|
|
|
-- vv/go.mod --
|
|
|
|
module v.localhost
|
|
|
|
-- vv/v.go --
|
|
|
|
package v
|
|
|
|
`, "")
|
|
|
|
defer mt.cleanup()
|
|
|
|
|
|
|
|
mt.assertModuleFoundInDir("example.com/a/b", "b", `main/b$`)
|
|
|
|
mt.assertModuleFoundInDir("example.com/x/v3", "x", `main/v3$`)
|
|
|
|
mt.assertModuleFoundInDir("example.com/y/z/w", "w", `main/y/z/w$`)
|
|
|
|
mt.assertModuleFoundInDir("example.com/vv", "v", `main/v12$`)
|
|
|
|
}
|
|
|
|
|
|
|
|
// assertFound asserts that the package at importPath is found to have pkgName,
|
|
|
|
// and that scanning for pkgName finds it at importPath.
|
|
|
|
func (t *modTest) assertFound(importPath, pkgName string) (string, *pkg) {
|
|
|
|
t.Helper()
|
|
|
|
|
|
|
|
names, err := t.resolver.loadPackageNames([]string{importPath}, t.env.WorkingDir)
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("loading package name for %v: %v", importPath, err)
|
|
|
|
}
|
|
|
|
if names[importPath] != pkgName {
|
|
|
|
t.Errorf("package name for %v = %v, want %v", importPath, names[importPath], pkgName)
|
|
|
|
}
|
|
|
|
pkg := t.assertScanFinds(importPath, pkgName)
|
|
|
|
|
|
|
|
_, foundDir := t.resolver.findPackage(importPath)
|
|
|
|
return foundDir, pkg
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *modTest) assertScanFinds(importPath, pkgName string) *pkg {
|
|
|
|
t.Helper()
|
2019-12-26 17:13:58 -07:00
|
|
|
scan, err := scanToSlice(t.resolver, nil)
|
imports: stop using go/packages for modules
go/packages needs to call `go list` multiple times, which causes
redundant work and slows down goimports. If we reimplement `go list` in
memory, we can reuse state, saving time. `go list` also does work we
don't really need, like adding stuff to go.mod, and skipping that saves
more time.
We start with `go list -m`, which does MVS and such. The remaining work
is mostly mapping import paths and directories through the in-scope
modules to make sure we're giving the right answers. Unfortunately this
is quite subtle, and I don't know where all the traps are. I did my
best.
cmd/go already has tests for `go list`, of course, and packagestest is
not well suited to tests of this complexity. So I ripped off the script
tests in cmd/go that seemed relevant and made sure that our logic
returns the right stuff in each case. I'm sure that there are more cases
to cover, but this hit all the stuff I knew about and quite a bit I
didn't.
Since we may want to use the go/packages code path in the future, e.g.
for Bazel, I left that in place. It won't be used unless the magic env
var is set.
Files in internal and imports/testdata/mod were copied verbatim from
cmd/go.
Change-Id: I1248d99c400c1a0c7ef180d4460b9b8a3db0246b
Reviewed-on: https://go-review.googlesource.com/c/158097
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
2019-01-16 14:24:49 -07:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("scan failed: %v", err)
|
|
|
|
}
|
|
|
|
for _, pkg := range scan {
|
|
|
|
if pkg.importPathShort == importPath {
|
|
|
|
return pkg
|
|
|
|
}
|
|
|
|
}
|
|
|
|
t.Errorf("scanning for %v did not find %v", pkgName, importPath)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-12-26 17:13:58 -07:00
|
|
|
func scanToSlice(resolver Resolver, exclude []gopathwalk.RootType) ([]*pkg, error) {
|
|
|
|
var mu sync.Mutex
|
|
|
|
var result []*pkg
|
|
|
|
filter := &scanCallback{
|
2019-12-30 11:29:41 -07:00
|
|
|
rootFound: func(root gopathwalk.Root) bool {
|
|
|
|
for _, rt := range exclude {
|
|
|
|
if root.Type == rt {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
},
|
2019-12-26 17:13:58 -07:00
|
|
|
dirFound: func(pkg *pkg) bool {
|
|
|
|
return true
|
|
|
|
},
|
|
|
|
packageNameLoaded: func(pkg *pkg) bool {
|
|
|
|
mu.Lock()
|
|
|
|
defer mu.Unlock()
|
|
|
|
result = append(result, pkg)
|
2020-01-02 14:10:45 -07:00
|
|
|
return false
|
2019-12-26 17:13:58 -07:00
|
|
|
},
|
|
|
|
}
|
2019-12-30 11:29:41 -07:00
|
|
|
err := resolver.scan(context.Background(), filter)
|
2019-12-26 17:13:58 -07:00
|
|
|
return result, err
|
|
|
|
}
|
|
|
|
|
imports: stop using go/packages for modules
go/packages needs to call `go list` multiple times, which causes
redundant work and slows down goimports. If we reimplement `go list` in
memory, we can reuse state, saving time. `go list` also does work we
don't really need, like adding stuff to go.mod, and skipping that saves
more time.
We start with `go list -m`, which does MVS and such. The remaining work
is mostly mapping import paths and directories through the in-scope
modules to make sure we're giving the right answers. Unfortunately this
is quite subtle, and I don't know where all the traps are. I did my
best.
cmd/go already has tests for `go list`, of course, and packagestest is
not well suited to tests of this complexity. So I ripped off the script
tests in cmd/go that seemed relevant and made sure that our logic
returns the right stuff in each case. I'm sure that there are more cases
to cover, but this hit all the stuff I knew about and quite a bit I
didn't.
Since we may want to use the go/packages code path in the future, e.g.
for Bazel, I left that in place. It won't be used unless the magic env
var is set.
Files in internal and imports/testdata/mod were copied verbatim from
cmd/go.
Change-Id: I1248d99c400c1a0c7ef180d4460b9b8a3db0246b
Reviewed-on: https://go-review.googlesource.com/c/158097
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
2019-01-16 14:24:49 -07:00
|
|
|
// assertModuleFoundInDir is the same as assertFound, but also checks that the
|
|
|
|
// package was found in an active module whose Dir matches dirRE.
|
|
|
|
func (t *modTest) assertModuleFoundInDir(importPath, pkgName, dirRE string) {
|
|
|
|
t.Helper()
|
|
|
|
dir, pkg := t.assertFound(importPath, pkgName)
|
|
|
|
re, err := regexp.Compile(dirRE)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if dir == "" {
|
|
|
|
t.Errorf("import path %v not found in active modules", importPath)
|
|
|
|
} else {
|
|
|
|
if !re.MatchString(filepath.ToSlash(dir)) {
|
|
|
|
t.Errorf("finding dir for %s: dir = %q did not match regex %q", importPath, dir, dirRE)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if pkg != nil {
|
|
|
|
if !re.MatchString(filepath.ToSlash(pkg.dir)) {
|
|
|
|
t.Errorf("scanning for %s: dir = %q did not match regex %q", pkgName, pkg.dir, dirRE)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
var proxyOnce sync.Once
|
|
|
|
var proxyDir string
|
|
|
|
|
|
|
|
type modTest struct {
|
|
|
|
*testing.T
|
2019-05-06 13:37:46 -06:00
|
|
|
env *ProcessEnv
|
2019-07-03 13:23:05 -06:00
|
|
|
resolver *ModuleResolver
|
imports: stop using go/packages for modules
go/packages needs to call `go list` multiple times, which causes
redundant work and slows down goimports. If we reimplement `go list` in
memory, we can reuse state, saving time. `go list` also does work we
don't really need, like adding stuff to go.mod, and skipping that saves
more time.
We start with `go list -m`, which does MVS and such. The remaining work
is mostly mapping import paths and directories through the in-scope
modules to make sure we're giving the right answers. Unfortunately this
is quite subtle, and I don't know where all the traps are. I did my
best.
cmd/go already has tests for `go list`, of course, and packagestest is
not well suited to tests of this complexity. So I ripped off the script
tests in cmd/go that seemed relevant and made sure that our logic
returns the right stuff in each case. I'm sure that there are more cases
to cover, but this hit all the stuff I knew about and quite a bit I
didn't.
Since we may want to use the go/packages code path in the future, e.g.
for Bazel, I left that in place. It won't be used unless the magic env
var is set.
Files in internal and imports/testdata/mod were copied verbatim from
cmd/go.
Change-Id: I1248d99c400c1a0c7ef180d4460b9b8a3db0246b
Reviewed-on: https://go-review.googlesource.com/c/158097
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
2019-01-16 14:24:49 -07:00
|
|
|
cleanup func()
|
|
|
|
}
|
|
|
|
|
2019-09-11 00:14:36 -06:00
|
|
|
// setup builds a test environment from a txtar and supporting modules
|
imports: stop using go/packages for modules
go/packages needs to call `go list` multiple times, which causes
redundant work and slows down goimports. If we reimplement `go list` in
memory, we can reuse state, saving time. `go list` also does work we
don't really need, like adding stuff to go.mod, and skipping that saves
more time.
We start with `go list -m`, which does MVS and such. The remaining work
is mostly mapping import paths and directories through the in-scope
modules to make sure we're giving the right answers. Unfortunately this
is quite subtle, and I don't know where all the traps are. I did my
best.
cmd/go already has tests for `go list`, of course, and packagestest is
not well suited to tests of this complexity. So I ripped off the script
tests in cmd/go that seemed relevant and made sure that our logic
returns the right stuff in each case. I'm sure that there are more cases
to cover, but this hit all the stuff I knew about and quite a bit I
didn't.
Since we may want to use the go/packages code path in the future, e.g.
for Bazel, I left that in place. It won't be used unless the magic env
var is set.
Files in internal and imports/testdata/mod were copied verbatim from
cmd/go.
Change-Id: I1248d99c400c1a0c7ef180d4460b9b8a3db0246b
Reviewed-on: https://go-review.googlesource.com/c/158097
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
2019-01-16 14:24:49 -07:00
|
|
|
// in testdata/mod, along the lines of TestScript in cmd/go.
|
|
|
|
func setup(t *testing.T, main, wd string) *modTest {
|
|
|
|
t.Helper()
|
2019-08-29 14:22:26 -06:00
|
|
|
testenv.NeedsTool(t, "go")
|
|
|
|
|
imports: stop using go/packages for modules
go/packages needs to call `go list` multiple times, which causes
redundant work and slows down goimports. If we reimplement `go list` in
memory, we can reuse state, saving time. `go list` also does work we
don't really need, like adding stuff to go.mod, and skipping that saves
more time.
We start with `go list -m`, which does MVS and such. The remaining work
is mostly mapping import paths and directories through the in-scope
modules to make sure we're giving the right answers. Unfortunately this
is quite subtle, and I don't know where all the traps are. I did my
best.
cmd/go already has tests for `go list`, of course, and packagestest is
not well suited to tests of this complexity. So I ripped off the script
tests in cmd/go that seemed relevant and made sure that our logic
returns the right stuff in each case. I'm sure that there are more cases
to cover, but this hit all the stuff I knew about and quite a bit I
didn't.
Since we may want to use the go/packages code path in the future, e.g.
for Bazel, I left that in place. It won't be used unless the magic env
var is set.
Files in internal and imports/testdata/mod were copied verbatim from
cmd/go.
Change-Id: I1248d99c400c1a0c7ef180d4460b9b8a3db0246b
Reviewed-on: https://go-review.googlesource.com/c/158097
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
2019-01-16 14:24:49 -07:00
|
|
|
proxyOnce.Do(func() {
|
|
|
|
var err error
|
|
|
|
proxyDir, err = ioutil.TempDir("", "proxy-")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if err := writeProxy(proxyDir, "testdata/mod"); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
dir, err := ioutil.TempDir("", t.Name())
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
mainDir := filepath.Join(dir, "main")
|
|
|
|
if err := writeModule(mainDir, main); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2019-05-06 13:37:46 -06:00
|
|
|
env := &ProcessEnv{
|
2019-03-15 13:21:23 -06:00
|
|
|
GOROOT: build.Default.GOROOT,
|
imports: stop using go/packages for modules
go/packages needs to call `go list` multiple times, which causes
redundant work and slows down goimports. If we reimplement `go list` in
memory, we can reuse state, saving time. `go list` also does work we
don't really need, like adding stuff to go.mod, and skipping that saves
more time.
We start with `go list -m`, which does MVS and such. The remaining work
is mostly mapping import paths and directories through the in-scope
modules to make sure we're giving the right answers. Unfortunately this
is quite subtle, and I don't know where all the traps are. I did my
best.
cmd/go already has tests for `go list`, of course, and packagestest is
not well suited to tests of this complexity. So I ripped off the script
tests in cmd/go that seemed relevant and made sure that our logic
returns the right stuff in each case. I'm sure that there are more cases
to cover, but this hit all the stuff I knew about and quite a bit I
didn't.
Since we may want to use the go/packages code path in the future, e.g.
for Bazel, I left that in place. It won't be used unless the magic env
var is set.
Files in internal and imports/testdata/mod were copied verbatim from
cmd/go.
Change-Id: I1248d99c400c1a0c7ef180d4460b9b8a3db0246b
Reviewed-on: https://go-review.googlesource.com/c/158097
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
2019-01-16 14:24:49 -07:00
|
|
|
GOPATH: filepath.Join(dir, "gopath"),
|
|
|
|
GO111MODULE: "on",
|
2019-04-25 12:11:42 -06:00
|
|
|
GOPROXY: proxyDirToURL(proxyDir),
|
2019-05-24 12:32:38 -06:00
|
|
|
GOSUMDB: "off",
|
imports: stop using go/packages for modules
go/packages needs to call `go list` multiple times, which causes
redundant work and slows down goimports. If we reimplement `go list` in
memory, we can reuse state, saving time. `go list` also does work we
don't really need, like adding stuff to go.mod, and skipping that saves
more time.
We start with `go list -m`, which does MVS and such. The remaining work
is mostly mapping import paths and directories through the in-scope
modules to make sure we're giving the right answers. Unfortunately this
is quite subtle, and I don't know where all the traps are. I did my
best.
cmd/go already has tests for `go list`, of course, and packagestest is
not well suited to tests of this complexity. So I ripped off the script
tests in cmd/go that seemed relevant and made sure that our logic
returns the right stuff in each case. I'm sure that there are more cases
to cover, but this hit all the stuff I knew about and quite a bit I
didn't.
Since we may want to use the go/packages code path in the future, e.g.
for Bazel, I left that in place. It won't be used unless the magic env
var is set.
Files in internal and imports/testdata/mod were copied verbatim from
cmd/go.
Change-Id: I1248d99c400c1a0c7ef180d4460b9b8a3db0246b
Reviewed-on: https://go-review.googlesource.com/c/158097
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
2019-01-16 14:24:49 -07:00
|
|
|
WorkingDir: filepath.Join(mainDir, wd),
|
2020-03-23 06:35:36 -06:00
|
|
|
GocmdRunner: &gocommand.Runner{},
|
2020-02-28 15:03:27 -07:00
|
|
|
}
|
|
|
|
if *testDebug {
|
|
|
|
env.Logf = log.Printf
|
imports: stop using go/packages for modules
go/packages needs to call `go list` multiple times, which causes
redundant work and slows down goimports. If we reimplement `go list` in
memory, we can reuse state, saving time. `go list` also does work we
don't really need, like adding stuff to go.mod, and skipping that saves
more time.
We start with `go list -m`, which does MVS and such. The remaining work
is mostly mapping import paths and directories through the in-scope
modules to make sure we're giving the right answers. Unfortunately this
is quite subtle, and I don't know where all the traps are. I did my
best.
cmd/go already has tests for `go list`, of course, and packagestest is
not well suited to tests of this complexity. So I ripped off the script
tests in cmd/go that seemed relevant and made sure that our logic
returns the right stuff in each case. I'm sure that there are more cases
to cover, but this hit all the stuff I knew about and quite a bit I
didn't.
Since we may want to use the go/packages code path in the future, e.g.
for Bazel, I left that in place. It won't be used unless the magic env
var is set.
Files in internal and imports/testdata/mod were copied verbatim from
cmd/go.
Change-Id: I1248d99c400c1a0c7ef180d4460b9b8a3db0246b
Reviewed-on: https://go-review.googlesource.com/c/158097
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
2019-01-16 14:24:49 -07:00
|
|
|
}
|
|
|
|
|
2019-06-07 16:37:28 -06:00
|
|
|
// go mod download gets mad if we don't have a go.mod, so make sure we do.
|
|
|
|
_, err = os.Stat(filepath.Join(mainDir, "go.mod"))
|
|
|
|
if err != nil && !os.IsNotExist(err) {
|
|
|
|
t.Fatalf("checking if go.mod exists: %v", err)
|
|
|
|
}
|
|
|
|
if err == nil {
|
2020-02-24 14:46:08 -07:00
|
|
|
if _, err := env.invokeGo(context.Background(), "mod", "download"); err != nil {
|
2019-06-07 16:37:28 -06:00
|
|
|
t.Fatal(err)
|
|
|
|
}
|
imports: stop using go/packages for modules
go/packages needs to call `go list` multiple times, which causes
redundant work and slows down goimports. If we reimplement `go list` in
memory, we can reuse state, saving time. `go list` also does work we
don't really need, like adding stuff to go.mod, and skipping that saves
more time.
We start with `go list -m`, which does MVS and such. The remaining work
is mostly mapping import paths and directories through the in-scope
modules to make sure we're giving the right answers. Unfortunately this
is quite subtle, and I don't know where all the traps are. I did my
best.
cmd/go already has tests for `go list`, of course, and packagestest is
not well suited to tests of this complexity. So I ripped off the script
tests in cmd/go that seemed relevant and made sure that our logic
returns the right stuff in each case. I'm sure that there are more cases
to cover, but this hit all the stuff I knew about and quite a bit I
didn't.
Since we may want to use the go/packages code path in the future, e.g.
for Bazel, I left that in place. It won't be used unless the magic env
var is set.
Files in internal and imports/testdata/mod were copied verbatim from
cmd/go.
Change-Id: I1248d99c400c1a0c7ef180d4460b9b8a3db0246b
Reviewed-on: https://go-review.googlesource.com/c/158097
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
2019-01-16 14:24:49 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return &modTest{
|
|
|
|
T: t,
|
|
|
|
env: env,
|
2020-01-09 17:14:18 -07:00
|
|
|
resolver: newModuleResolver(env),
|
2019-09-04 12:24:10 -06:00
|
|
|
cleanup: func() { removeDir(dir) },
|
imports: stop using go/packages for modules
go/packages needs to call `go list` multiple times, which causes
redundant work and slows down goimports. If we reimplement `go list` in
memory, we can reuse state, saving time. `go list` also does work we
don't really need, like adding stuff to go.mod, and skipping that saves
more time.
We start with `go list -m`, which does MVS and such. The remaining work
is mostly mapping import paths and directories through the in-scope
modules to make sure we're giving the right answers. Unfortunately this
is quite subtle, and I don't know where all the traps are. I did my
best.
cmd/go already has tests for `go list`, of course, and packagestest is
not well suited to tests of this complexity. So I ripped off the script
tests in cmd/go that seemed relevant and made sure that our logic
returns the right stuff in each case. I'm sure that there are more cases
to cover, but this hit all the stuff I knew about and quite a bit I
didn't.
Since we may want to use the go/packages code path in the future, e.g.
for Bazel, I left that in place. It won't be used unless the magic env
var is set.
Files in internal and imports/testdata/mod were copied verbatim from
cmd/go.
Change-Id: I1248d99c400c1a0c7ef180d4460b9b8a3db0246b
Reviewed-on: https://go-review.googlesource.com/c/158097
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
2019-01-16 14:24:49 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// writeModule writes the module in the ar, a txtar, to dir.
|
|
|
|
func writeModule(dir, ar string) error {
|
|
|
|
a := txtar.Parse([]byte(ar))
|
|
|
|
|
|
|
|
for _, f := range a.Files {
|
|
|
|
fpath := filepath.Join(dir, f.Name)
|
|
|
|
if err := os.MkdirAll(filepath.Dir(fpath), 0755); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := ioutil.WriteFile(fpath, f.Data, 0644); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// writeProxy writes all the txtar-formatted modules in arDir to a proxy
|
|
|
|
// directory in dir.
|
|
|
|
func writeProxy(dir, arDir string) error {
|
|
|
|
files, err := ioutil.ReadDir(arDir)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, fi := range files {
|
|
|
|
if err := writeProxyModule(dir, filepath.Join(arDir, fi.Name())); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// writeProxyModule writes a txtar-formatted module at arPath to the module
|
|
|
|
// proxy in base.
|
|
|
|
func writeProxyModule(base, arPath string) error {
|
|
|
|
arName := filepath.Base(arPath)
|
|
|
|
i := strings.LastIndex(arName, "_v")
|
|
|
|
ver := strings.TrimSuffix(arName[i+1:], ".txt")
|
|
|
|
modDir := strings.Replace(arName[:i], "_", "/", -1)
|
2020-02-10 11:54:36 -07:00
|
|
|
modPath, err := module.UnescapePath(modDir)
|
imports: stop using go/packages for modules
go/packages needs to call `go list` multiple times, which causes
redundant work and slows down goimports. If we reimplement `go list` in
memory, we can reuse state, saving time. `go list` also does work we
don't really need, like adding stuff to go.mod, and skipping that saves
more time.
We start with `go list -m`, which does MVS and such. The remaining work
is mostly mapping import paths and directories through the in-scope
modules to make sure we're giving the right answers. Unfortunately this
is quite subtle, and I don't know where all the traps are. I did my
best.
cmd/go already has tests for `go list`, of course, and packagestest is
not well suited to tests of this complexity. So I ripped off the script
tests in cmd/go that seemed relevant and made sure that our logic
returns the right stuff in each case. I'm sure that there are more cases
to cover, but this hit all the stuff I knew about and quite a bit I
didn't.
Since we may want to use the go/packages code path in the future, e.g.
for Bazel, I left that in place. It won't be used unless the magic env
var is set.
Files in internal and imports/testdata/mod were copied verbatim from
cmd/go.
Change-Id: I1248d99c400c1a0c7ef180d4460b9b8a3db0246b
Reviewed-on: https://go-review.googlesource.com/c/158097
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
2019-01-16 14:24:49 -07:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
dir := filepath.Join(base, modDir, "@v")
|
|
|
|
a, err := txtar.ParseFile(arPath)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := os.MkdirAll(dir, 0755); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
f, err := os.OpenFile(filepath.Join(dir, ver+".zip"), os.O_CREATE|os.O_WRONLY, 0644)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
z := zip.NewWriter(f)
|
|
|
|
for _, f := range a.Files {
|
|
|
|
if f.Name[0] == '.' {
|
|
|
|
if err := ioutil.WriteFile(filepath.Join(dir, ver+f.Name), f.Data, 0644); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
zf, err := z.Create(modPath + "@" + ver + "/" + f.Name)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if _, err := zf.Write(f.Data); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if err := z.Close(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if err := f.Close(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
list, err := os.OpenFile(filepath.Join(dir, "list"), os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if _, err := fmt.Fprintf(list, "%s\n", ver); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if err := list.Close(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
2019-08-20 13:39:18 -06:00
|
|
|
|
2019-09-04 12:24:10 -06:00
|
|
|
func removeDir(dir string) {
|
|
|
|
_ = filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
|
|
|
|
if err != nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
if info.IsDir() {
|
|
|
|
_ = os.Chmod(path, 0777)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
_ = os.RemoveAll(dir) // ignore errors
|
|
|
|
}
|
|
|
|
|
2019-08-20 13:39:18 -06:00
|
|
|
// Tests that findModFile can find the mod files from a path in the module cache.
|
|
|
|
func TestFindModFileModCache(t *testing.T) {
|
|
|
|
mt := setup(t, `
|
|
|
|
-- go.mod --
|
|
|
|
module x
|
|
|
|
|
|
|
|
require rsc.io/quote v1.5.2
|
|
|
|
-- x.go --
|
|
|
|
package x
|
|
|
|
import _ "rsc.io/quote"
|
|
|
|
`, "")
|
|
|
|
defer mt.cleanup()
|
2019-10-21 15:48:25 -06:00
|
|
|
want := filepath.Join(mt.resolver.env.GOPATH, "pkg/mod", "rsc.io/quote@v1.5.2")
|
2019-08-20 13:39:18 -06:00
|
|
|
|
|
|
|
found := mt.assertScanFinds("rsc.io/quote", "quote")
|
2019-10-21 15:48:25 -06:00
|
|
|
modDir, _ := mt.resolver.modInfo(found.dir)
|
|
|
|
if modDir != want {
|
|
|
|
t.Errorf("expected: %s, got: %s", want, modDir)
|
2019-08-20 13:39:18 -06:00
|
|
|
}
|
|
|
|
}
|
2019-09-04 12:24:10 -06:00
|
|
|
|
|
|
|
// Tests that crud in the module cache is ignored.
|
|
|
|
func TestInvalidModCache(t *testing.T) {
|
|
|
|
dir, err := ioutil.TempDir("", t.Name())
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
defer removeDir(dir)
|
|
|
|
|
|
|
|
// This doesn't have module@version like it should.
|
|
|
|
if err := os.MkdirAll(filepath.Join(dir, "gopath/pkg/mod/sabotage"), 0777); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if err := ioutil.WriteFile(filepath.Join(dir, "gopath/pkg/mod/sabotage/x.go"), []byte("package foo\n"), 0777); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
env := &ProcessEnv{
|
|
|
|
GOROOT: build.Default.GOROOT,
|
|
|
|
GOPATH: filepath.Join(dir, "gopath"),
|
|
|
|
GO111MODULE: "on",
|
|
|
|
GOSUMDB: "off",
|
2020-03-23 06:35:36 -06:00
|
|
|
GocmdRunner: &gocommand.Runner{},
|
2019-09-04 12:24:10 -06:00
|
|
|
WorkingDir: dir,
|
|
|
|
}
|
2020-01-09 17:14:18 -07:00
|
|
|
resolver := newModuleResolver(env)
|
2019-12-26 17:13:58 -07:00
|
|
|
scanToSlice(resolver, nil)
|
2019-10-04 13:38:18 -06:00
|
|
|
}
|
|
|
|
|
2019-10-30 14:59:29 -06:00
|
|
|
func TestGetCandidatesRanking(t *testing.T) {
|
|
|
|
mt := setup(t, `
|
|
|
|
-- go.mod --
|
|
|
|
module example.com
|
|
|
|
|
|
|
|
require rsc.io/quote v1.5.1
|
|
|
|
|
|
|
|
-- rpackage/x.go --
|
|
|
|
package rpackage
|
|
|
|
import _ "rsc.io/quote"
|
|
|
|
`, "")
|
|
|
|
defer mt.cleanup()
|
|
|
|
|
2020-02-24 14:46:08 -07:00
|
|
|
if _, err := mt.env.invokeGo(context.Background(), "mod", "download", "rsc.io/quote/v2@v2.0.1"); err != nil {
|
2019-10-30 14:59:29 -06:00
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
type res struct {
|
2019-12-27 13:46:49 -07:00
|
|
|
relevance int
|
2019-10-30 14:59:29 -06:00
|
|
|
name, path string
|
|
|
|
}
|
|
|
|
want := []res{
|
|
|
|
// Stdlib
|
2019-12-27 13:46:49 -07:00
|
|
|
{7, "bytes", "bytes"},
|
|
|
|
{7, "http", "net/http"},
|
2020-01-16 12:54:35 -07:00
|
|
|
// Main module
|
2019-12-27 13:46:49 -07:00
|
|
|
{6, "rpackage", "example.com/rpackage"},
|
2020-01-16 12:54:35 -07:00
|
|
|
// Direct module deps
|
|
|
|
{5, "quote", "rsc.io/quote"},
|
2019-12-18 17:08:00 -07:00
|
|
|
// Indirect deps
|
2020-01-16 12:54:35 -07:00
|
|
|
{4, "language", "golang.org/x/text/language"},
|
2019-10-30 14:59:29 -06:00
|
|
|
// Out of scope modules
|
2020-01-16 12:54:35 -07:00
|
|
|
{3, "quote", "rsc.io/quote/v2"},
|
2019-10-30 14:59:29 -06:00
|
|
|
}
|
2019-12-27 13:46:49 -07:00
|
|
|
var mu sync.Mutex
|
2019-10-30 14:59:29 -06:00
|
|
|
var got []res
|
2019-12-27 13:46:49 -07:00
|
|
|
add := func(c ImportFix) {
|
|
|
|
mu.Lock()
|
|
|
|
defer mu.Unlock()
|
2019-10-30 14:59:29 -06:00
|
|
|
for _, w := range want {
|
|
|
|
if c.StmtInfo.ImportPath == w.path {
|
2019-12-27 13:46:49 -07:00
|
|
|
got = append(got, res{c.Relevance, c.IdentName, c.StmtInfo.ImportPath})
|
2019-10-30 14:59:29 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-12-30 14:18:34 -07:00
|
|
|
if err := getAllCandidates(context.Background(), add, "", "foo.go", "foo", mt.env); err != nil {
|
2019-12-27 13:46:49 -07:00
|
|
|
t.Fatalf("getAllCandidates() = %v", err)
|
|
|
|
}
|
|
|
|
sort.Slice(got, func(i, j int) bool {
|
|
|
|
ri, rj := got[i], got[j]
|
|
|
|
if ri.relevance != rj.relevance {
|
|
|
|
return ri.relevance > rj.relevance // Highest first.
|
|
|
|
}
|
|
|
|
return ri.name < rj.name
|
|
|
|
})
|
2019-10-30 14:59:29 -06:00
|
|
|
if !reflect.DeepEqual(want, got) {
|
|
|
|
t.Errorf("wanted candidates in order %v, got %v", want, got)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-04 13:38:18 -06:00
|
|
|
func BenchmarkScanModCache(b *testing.B) {
|
|
|
|
env := &ProcessEnv{
|
2020-03-23 06:35:36 -06:00
|
|
|
GOPATH: build.Default.GOPATH,
|
|
|
|
GOROOT: build.Default.GOROOT,
|
|
|
|
GocmdRunner: &gocommand.Runner{},
|
|
|
|
Logf: log.Printf,
|
2019-10-04 13:38:18 -06:00
|
|
|
}
|
2019-10-09 17:05:30 -06:00
|
|
|
exclude := []gopathwalk.RootType{gopathwalk.RootGOROOT}
|
2019-12-26 17:13:58 -07:00
|
|
|
scanToSlice(env.GetResolver(), exclude)
|
2019-10-04 13:38:18 -06:00
|
|
|
b.ResetTimer()
|
|
|
|
for i := 0; i < b.N; i++ {
|
2019-12-26 17:13:58 -07:00
|
|
|
scanToSlice(env.GetResolver(), exclude)
|
2019-10-09 17:05:30 -06:00
|
|
|
env.GetResolver().(*ModuleResolver).ClearForNewScan()
|
2019-10-04 13:38:18 -06:00
|
|
|
}
|
2019-09-04 12:24:10 -06:00
|
|
|
}
|