]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/go: fix 'go test' and 'go fmt' with files outside a module
authorBryan C. Mills <bcmills@google.com>
Mon, 10 Dec 2018 20:02:38 +0000 (15:02 -0500)
committerBryan C. Mills <bcmills@google.com>
Tue, 11 Dec 2018 21:45:00 +0000 (21:45 +0000)
Use the actual loader result in findModule instead of making
assumptions about nesting in the build list.
As a side-effect, this produces much clearer error messages for
packages that (for one reason or another) failed to load.

Adjust the package and module path outside a module to
"command-line-arguments". That string already appears in the output of
a number of (module-mode and GOPATH-mode) commands for file arguments,
and as far as I can tell operation outside a module is currently the
only case in which the module path of a package is not actually a
prefix of the import path.

Fixes #28011
Fixes #27099
Fixes #28943
Updates #27102
Updates #28459
Updates #27063

Change-Id: I61d5556df7b1b7d1efdaffa892f0e3e95b612d87
Reviewed-on: https://go-review.googlesource.com/c/153459
Run-TryBot: Bryan C. Mills <bcmills@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Jay Conrod <jayconrod@google.com>
src/cmd/go/internal/load/pkg.go
src/cmd/go/internal/modload/build.go
src/cmd/go/internal/modload/init.go
src/cmd/go/testdata/script/mod_enabled.txt
src/cmd/go/testdata/script/mod_get_svn.txt
src/cmd/go/testdata/script/mod_outside.txt
src/cmd/go/testdata/script/mod_test_files.txt [new file with mode: 0644]

index 616adcc57ae8073095e86d91384bf9e56f4382d3..228be07f2492a46237d6d8e6a42418598b485745 100644 (file)
@@ -997,10 +997,12 @@ func disallowInternal(srcDir string, importer *Package, importerPath string, p *
        } else {
                // p is in a module, so make it available based on the importer's import path instead
                // of the file path (https://golang.org/issue/23970).
-               if importerPath == "." {
+               if importer.Internal.CmdlineFiles {
                        // The importer is a list of command-line files.
                        // Pretend that the import path is the import path of the
                        // directory containing them.
+                       // If the directory is outside the main module, this will resolve to ".",
+                       // which is not a prefix of any valid module.
                        importerPath = ModDirImportPath(importer.Dir)
                }
                parentOfInternal := p.ImportPath[:i]
@@ -1515,11 +1517,13 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) {
        }
 
        if cfg.ModulesEnabled {
-               if !p.Internal.CmdlineFiles {
-                       p.Module = ModPackageModuleInfo(p.ImportPath)
+               mainPath := p.ImportPath
+               if p.Internal.CmdlineFiles {
+                       mainPath = "command-line-arguments"
                }
+               p.Module = ModPackageModuleInfo(mainPath)
                if p.Name == "main" {
-                       p.Internal.BuildInfo = ModPackageBuildInfo(p.ImportPath, p.Deps)
+                       p.Internal.BuildInfo = ModPackageBuildInfo(mainPath, p.Deps)
                }
        }
 }
@@ -1986,11 +1990,6 @@ func GoFilesPackage(gofiles []string) *Package {
        }
 
        bp, err := ctxt.ImportDir(dir, 0)
-       if ModDirImportPath != nil {
-               // Use the effective import path of the directory
-               // for deciding visibility during pkg.load.
-               bp.ImportPath = ModDirImportPath(dir)
-       }
        pkg := new(Package)
        pkg.Internal.Local = true
        pkg.Internal.CmdlineFiles = true
index b4856a94199c0e76ee99d2ef8446783fcc74d0b1..efeb7a5fd5d055ff584e8db7d7d9add46f0ca05b 100644 (file)
@@ -17,6 +17,7 @@ import (
        "internal/goroot"
        "os"
        "path/filepath"
+       "runtime/debug"
        "strings"
 )
 
@@ -98,11 +99,13 @@ func moduleInfo(m module.Version, fromBuildList bool) *modinfo.ModulePublic {
                        Path:    m.Path,
                        Version: m.Version,
                        Main:    true,
-                       Dir:     ModRoot(),
-                       GoMod:   filepath.Join(ModRoot(), "go.mod"),
                }
-               if modFile.Go != nil {
-                       info.GoVersion = modFile.Go.Version
+               if HasModRoot() {
+                       info.Dir = ModRoot()
+                       info.GoMod = filepath.Join(info.Dir, "go.mod")
+                       if modFile.Go != nil {
+                               info.GoVersion = modFile.Go.Version
+                       }
                }
                return info
        }
@@ -184,6 +187,7 @@ func PackageBuildInfo(path string, deps []string) string {
        if isStandardImportPath(path) || !Enabled() {
                return ""
        }
+
        target := findModule(path, path)
        mdeps := make(map[module.Version]bool)
        for _, dep := range deps {
@@ -223,19 +227,23 @@ func PackageBuildInfo(path string, deps []string) string {
        return buf.String()
 }
 
+// findModule returns the module containing the package at path,
+// needed to build the package at target.
 func findModule(target, path string) module.Version {
-       // TODO: This should use loaded.
-       if path == "." {
-               return buildList[0]
+       pkg, ok := loaded.pkgCache.Get(path).(*loadPkg)
+       if ok {
+               if pkg.err != nil {
+                       base.Fatalf("build %v: cannot load %v: %v", target, path, pkg.err)
+               }
+               return pkg.mod
        }
-       if cfg.BuildMod == "vendor" {
-               readVendorList()
-               return vendorMap[path]
+
+       if path == "command-line-arguments" {
+               return Target
        }
-       for _, mod := range buildList {
-               if maybeInModule(path, mod.Path) {
-                       return mod
-               }
+
+       if printStackInDie {
+               debug.PrintStack()
        }
        base.Fatalf("build %v: cannot find module for path %v", target, path)
        panic("unreachable")
index 97c48be00e12617e15c8c8d9ecc4f0ff9c0be3d3..22d14ccce78b241d780ee526754bd3ca8510144a 100644 (file)
@@ -314,7 +314,7 @@ func InitMod() {
 
        Init()
        if modRoot == "" {
-               Target = module.Version{Path: "main"}
+               Target = module.Version{Path: "command-line-arguments"}
                buildList = []module.Version{Target}
                return
        }
index 1de4719d53d834bcd7f564d96616b7e9949cce7b..ab5ee3d6dfa656cb36e7a311d8699fd5d85788a5 100644 (file)
@@ -39,8 +39,8 @@ stdout z[/\\]go.mod
 cd $GOPATH/src/x/y
 go env GOMOD
 stdout 'NUL|/dev/null'
-go list -m
-stderr 'cannot find main module'
+go list -m
+stdout '^command-line-arguments$'
 
 cd $GOPATH/foo
 go env GOMOD
index ad96fa13575d954d0b62ecc8c5beeafb6336e66a..b3436284aff02712180feb861377f41d40d24a12 100644 (file)
@@ -10,8 +10,7 @@ env GOPROXY=direct # obtain llvm.org directory, not via svn.
 ! go get -d llvm.org/llvm/bindings/go/llvm
 stderr 'ReadZip not implemented for svn'
 ! go install .
-# TODO(bcmills): The error message here should mention ReadZip.
-stderr 'cannot find module for path llvm.org'
+stderr 'ReadZip not implemented for svn'
 
 -- go.mod --
 module golang/go/issues/28943/main
index 25013b6271cfdb601f7a214b26fa00ae63e0fdc5..db994a1656703a8bf711ad0824d362dd6f33ad73 100644 (file)
@@ -12,8 +12,8 @@ stdout 'NUL|/dev/null'
 # which is not in a module.
 ! go list
 stderr 'cannot find main module'
-go list -m
-stderr 'cannot find main module'
+go list -m
+stdout '^command-line-arguments$'
 # 'go list' in the working directory should fail even if there is a a 'package
 # main' present: without a main module, we do not know its package path.
 ! go list ./foo
@@ -148,6 +148,10 @@ stderr 'no such package'
 stderr 'can only use path@version syntax with'
 
 
+# 'go fmt' should be able to format files outside of a module.
+go fmt foo/foo.go
+
+
 # The remainder of the test checks dependencies by linking and running binaries.
 [short] stop
 
@@ -185,8 +189,8 @@ stdout 'using example.com/version v1.0.0'
 
 # 'go run' should use 'main' as the effective module and import path.
 go run ./foo/foo.go
-stdout 'path is \.$'
-stdout 'main is main \(devel\)'
+stdout 'path is command-line-arguments$'
+stdout 'main is command-line-arguments \(devel\)'
 stdout 'using example.com/version v1.1.0'
 
 # 'go generate' should work with file arguments.
diff --git a/src/cmd/go/testdata/script/mod_test_files.txt b/src/cmd/go/testdata/script/mod_test_files.txt
new file mode 100644 (file)
index 0000000..87aecb4
--- /dev/null
@@ -0,0 +1,49 @@
+env GO111MODULE=on
+
+cd foo
+
+# Testing an explicit source file should use the same import visibility as the
+# package in the same directory.
+go list -test -deps
+go list -test -deps foo_test.go
+
+# If the file is inside the main module's vendor directory, it should have
+# visibility based on the vendor-relative import path.
+mkdir vendor/example.com/foo
+cp foo_test.go vendor/example.com/foo
+go list -test -deps vendor/example.com/foo/foo_test.go
+
+# If the file is outside the main module entirely, it should be treated as outside.
+cp foo_test.go ../foo_test.go
+! go list -test -deps ../foo_test.go
+stderr 'use of internal package'
+
+-- foo/go.mod --
+module example.com/foo
+require example.com/internal v0.0.0
+replace example.com/internal => ../internal
+
+-- foo/internal.go --
+package foo
+import _ "example.com/internal"
+
+-- foo/foo_test.go --
+package foo_test
+
+import (
+       "testing"
+       "example.com/internal"
+)
+
+func TestHacksEnabled(t *testing.T) {
+       if !internal.Hacks {
+               t.Fatal("hacks not enabled")
+       }
+}
+
+-- internal/go.mod --
+module example.com/internal
+
+-- internal/internal.go --
+package internal
+const Hacks = true