summaryrefslogtreecommitdiff
path: root/libgo/go/cmd/go/internal/load/pkg.go
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/cmd/go/internal/load/pkg.go')
-rw-r--r--libgo/go/cmd/go/internal/load/pkg.go684
1 files changed, 405 insertions, 279 deletions
diff --git a/libgo/go/cmd/go/internal/load/pkg.go b/libgo/go/cmd/go/internal/load/pkg.go
index dfb1ff63afe..0579fd5ca53 100644
--- a/libgo/go/cmd/go/internal/load/pkg.go
+++ b/libgo/go/cmd/go/internal/load/pkg.go
@@ -22,9 +22,26 @@ import (
"cmd/go/internal/base"
"cmd/go/internal/cfg"
+ "cmd/go/internal/modinfo"
+ "cmd/go/internal/search"
"cmd/go/internal/str"
)
+var (
+ // module initialization hook; never nil, no-op if module use is disabled
+ ModInit func()
+
+ // module hooks; nil if module use is disabled
+ ModBinDir func() string // return effective bin directory
+ ModLookup func(path string) (dir, realPath string, err error) // lookup effective meaning of import
+ ModPackageModuleInfo func(path string) *modinfo.ModulePublic // return module info for Package struct
+ ModImportPaths func(args []string) []*search.Match // expand import paths
+ ModPackageBuildInfo func(main string, deps []string) string // return module info to embed in binary
+ ModInfoProg func(info string) []byte // wrap module info in .go code for binary
+ ModImportFromFiles func([]string) // update go.mod to add modules for imports in these files
+ ModDirImportPath func(string) string // return effective import path for directory
+)
+
var IgnoreImports bool // control whether we ignore imports in packages
// A Package describes a single package found in a directory.
@@ -37,18 +54,24 @@ type PackagePublic struct {
// Note: These fields are part of the go command's public API.
// See list.go. It is okay to add fields, but not to change or
// remove existing ones. Keep in sync with list.go
- Dir string `json:",omitempty"` // directory containing package sources
- ImportPath string `json:",omitempty"` // import path of package in dir
- ImportComment string `json:",omitempty"` // path in import comment on package statement
- Name string `json:",omitempty"` // package name
- Doc string `json:",omitempty"` // package documentation string
- Target string `json:",omitempty"` // installed target for this package (may be executable)
- Shlib string `json:",omitempty"` // the shared library that contains this package (only set when -linkshared)
- Goroot bool `json:",omitempty"` // is this package found in the Go root?
- Standard bool `json:",omitempty"` // is this package part of the standard Go library?
- Root string `json:",omitempty"` // Go root or Go path dir containing this package
- ConflictDir string `json:",omitempty"` // Dir is hidden by this other directory
- BinaryOnly bool `json:",omitempty"` // package cannot be recompiled
+ Dir string `json:",omitempty"` // directory containing package sources
+ ImportPath string `json:",omitempty"` // import path of package in dir
+ ImportComment string `json:",omitempty"` // path in import comment on package statement
+ Name string `json:",omitempty"` // package name
+ Doc string `json:",omitempty"` // package documentation string
+ Target string `json:",omitempty"` // installed target for this package (may be executable)
+ Shlib string `json:",omitempty"` // the shared library that contains this package (only set when -linkshared)
+ Root string `json:",omitempty"` // Go root or Go path dir containing this package
+ ConflictDir string `json:",omitempty"` // Dir is hidden by this other directory
+ ForTest string `json:",omitempty"` // package is only for use in named test
+ Export string `json:",omitempty"` // file containing export data (set by go list -export)
+ Module *modinfo.ModulePublic `json:",omitempty"` // info about package's module, if any
+ Match []string `json:",omitempty"` // command-line patterns matching this package
+ Goroot bool `json:",omitempty"` // is this package found in the Go root?
+ Standard bool `json:",omitempty"` // is this package part of the standard Go library?
+ DepOnly bool `json:",omitempty"` // package is only as a dependency, not explicitly listed
+ BinaryOnly bool `json:",omitempty"` // package cannot be recompiled
+ Incomplete bool `json:",omitempty"` // was there an error loading this package or dependencies?
// Stale and StaleReason remain here *only* for the list command.
// They are only initialized in preparation for list execution.
@@ -59,18 +82,19 @@ type PackagePublic struct {
// Source files
// If you add to this list you MUST add to p.AllFiles (below) too.
// Otherwise file name security lists will not apply to any new additions.
- GoFiles []string `json:",omitempty"` // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
- CgoFiles []string `json:",omitempty"` // .go sources files that import "C"
- IgnoredGoFiles []string `json:",omitempty"` // .go sources ignored due to build constraints
- CFiles []string `json:",omitempty"` // .c source files
- CXXFiles []string `json:",omitempty"` // .cc, .cpp and .cxx source files
- MFiles []string `json:",omitempty"` // .m source files
- HFiles []string `json:",omitempty"` // .h, .hh, .hpp and .hxx source files
- FFiles []string `json:",omitempty"` // .f, .F, .for and .f90 Fortran source files
- SFiles []string `json:",omitempty"` // .s source files
- SwigFiles []string `json:",omitempty"` // .swig files
- SwigCXXFiles []string `json:",omitempty"` // .swigcxx files
- SysoFiles []string `json:",omitempty"` // .syso system object files added to package
+ GoFiles []string `json:",omitempty"` // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
+ CgoFiles []string `json:",omitempty"` // .go source files that import "C"
+ CompiledGoFiles []string `json:",omitempty"` // .go output from running cgo on CgoFiles
+ IgnoredGoFiles []string `json:",omitempty"` // .go source files ignored due to build constraints
+ CFiles []string `json:",omitempty"` // .c source files
+ CXXFiles []string `json:",omitempty"` // .cc, .cpp and .cxx source files
+ MFiles []string `json:",omitempty"` // .m source files
+ HFiles []string `json:",omitempty"` // .h, .hh, .hpp and .hxx source files
+ FFiles []string `json:",omitempty"` // .f, .F, .for and .f90 Fortran source files
+ SFiles []string `json:",omitempty"` // .s source files
+ SwigFiles []string `json:",omitempty"` // .swig files
+ SwigCXXFiles []string `json:",omitempty"` // .swigcxx files
+ SysoFiles []string `json:",omitempty"` // .syso system object files added to package
// Cgo directives
CgoCFLAGS []string `json:",omitempty"` // cgo: flags for C compiler
@@ -81,11 +105,12 @@ type PackagePublic struct {
CgoPkgConfig []string `json:",omitempty"` // cgo: pkg-config names
// Dependency information
- Imports []string `json:",omitempty"` // import paths used by this package
- Deps []string `json:",omitempty"` // all (recursively) imported dependencies
+ Imports []string `json:",omitempty"` // import paths used by this package
+ ImportMap map[string]string `json:",omitempty"` // map from source import to ImportPath (identity entries omitted)
+ Deps []string `json:",omitempty"` // all (recursively) imported dependencies
// Error information
- Incomplete bool `json:",omitempty"` // was there an error loading this package or dependencies?
+ // Incomplete is above, packed into the other bools
Error *PackageError `json:",omitempty"` // error loading this package (not dependencies)
DepsErrors []*PackageError `json:",omitempty"` // errors loading dependencies
@@ -107,6 +132,7 @@ func (p *Package) AllFiles() []string {
return str.StringList(
p.GoFiles,
p.CgoFiles,
+ // no p.CompiledGoFiles, because they are from GoFiles or generated by us
p.IgnoredGoFiles,
p.CFiles,
p.CXXFiles,
@@ -122,21 +148,33 @@ func (p *Package) AllFiles() []string {
)
}
+// Desc returns the package "description", for use in b.showOutput.
+func (p *Package) Desc() string {
+ if p.ForTest != "" {
+ return p.ImportPath + " [" + p.ForTest + ".test]"
+ }
+ return p.ImportPath
+}
+
type PackageInternal struct {
// Unexported fields are not part of the public API.
- Build *build.Package
- Imports []*Package // this package's direct imports
- RawImports []string // this package's original imports as they appear in the text of the program
- ForceLibrary bool // this package is a library (even if named "main")
- CmdlineFiles bool // package built from files listed on command line
- CmdlinePkg bool // package listed on command line
- Local bool // imported via local path (./ or ../)
- LocalPrefix string // interpret ./ and ../ imports relative to this prefix
- ExeName string // desired name for temporary executable
- CoverMode string // preprocess Go source files with the coverage tool in this mode
- CoverVars map[string]*CoverVar // variables created by coverage analysis
- OmitDebug bool // tell linker not to write debug information
- GobinSubdir bool // install target would be subdir of GOBIN
+ Build *build.Package
+ Imports []*Package // this package's direct imports
+ CompiledImports []string // additional Imports necessary when using CompiledGoFiles (all from standard library)
+ RawImports []string // this package's original imports as they appear in the text of the program
+ ForceLibrary bool // this package is a library (even if named "main")
+ CmdlineFiles bool // package built from files listed on command line
+ CmdlinePkg bool // package listed on command line
+ CmdlinePkgLiteral bool // package listed as literal on command line (not via wildcard)
+ Local bool // imported via local path (./ or ../)
+ LocalPrefix string // interpret ./ and ../ imports relative to this prefix
+ ExeName string // desired name for temporary executable
+ CoverMode string // preprocess Go source files with the coverage tool in this mode
+ CoverVars map[string]*CoverVar // variables created by coverage analysis
+ OmitDebug bool // tell linker not to write debug information
+ GobinSubdir bool // install target would be subdir of GOBIN
+ BuildInfo string // add this info to package main
+ TestmainGo *[]byte // content for _testmain.go
Asmflags []string // -asmflags for this package
Gcflags []string // -gcflags for this package
@@ -224,7 +262,7 @@ func (p *Package) copyBuild(pp *build.Package) {
// TODO? Target
p.Goroot = pp.Goroot
- p.Standard = p.Goroot && p.ImportPath != "" && isStandardImportPath(p.ImportPath)
+ p.Standard = p.Goroot && p.ImportPath != "" && search.IsStandardImportPath(p.ImportPath)
p.GoFiles = pp.GoFiles
p.CgoFiles = pp.CgoFiles
p.IgnoredGoFiles = pp.IgnoredGoFiles
@@ -253,24 +291,12 @@ func (p *Package) copyBuild(pp *build.Package) {
p.XTestImports = pp.XTestImports
if IgnoreImports {
p.Imports = nil
+ p.Internal.RawImports = nil
p.TestImports = nil
p.XTestImports = nil
}
}
-// isStandardImportPath reports whether $GOROOT/src/path should be considered
-// part of the standard distribution. For historical reasons we allow people to add
-// their own code to $GOROOT instead of using $GOPATH, but we assume that
-// code will start with a domain name (dot in the first element).
-func isStandardImportPath(path string) bool {
- i := strings.Index(path, "/")
- if i < 0 {
- i = len(path)
- }
- elem := path[:i]
- return !strings.Contains(elem, ".")
-}
-
// A PackageError describes an error loading information about a package.
type PackageError struct {
ImportStack []string // shortest path from package named on command line to this one
@@ -296,7 +322,9 @@ func (p *PackageError) Error() string {
return "package " + strings.Join(p.ImportStack, "\n\timports ") + ": " + p.Err
}
-// An ImportStack is a stack of import paths.
+// An ImportStack is a stack of import paths, possibly with the suffix " (test)" appended.
+// The import path of a test package is the import path of the corresponding
+// non-test package with the suffix "_test" added.
type ImportStack []string
func (s *ImportStack) Push(p string) {
@@ -349,15 +377,17 @@ func ClearPackageCachePartial(args []string) {
}
}
-// reloadPackage is like loadPackage but makes sure
+// ReloadPackageNoFlags is like LoadPackageNoFlags but makes sure
// not to use the package cache.
-func ReloadPackage(arg string, stk *ImportStack) *Package {
+// It is only for use by GOPATH-based "go get".
+// TODO(rsc): When GOPATH-based "go get" is removed, delete this function.
+func ReloadPackageNoFlags(arg string, stk *ImportStack) *Package {
p := packageCache[arg]
if p != nil {
delete(packageCache, p.Dir)
delete(packageCache, p.ImportPath)
}
- return LoadPackage(arg, stk)
+ return LoadPackageNoFlags(arg, stk)
}
// dirToImportPath returns the pseudo-import path we use for a package
@@ -406,10 +436,53 @@ const (
// but possibly a local import path (an absolute file system path or one beginning
// with ./ or ../). A local relative path is interpreted relative to srcDir.
// It returns a *Package describing the package found in that directory.
+// LoadImport does not set tool flags and should only be used by
+// this package, as part of a bigger load operation, and by GOPATH-based "go get".
+// TODO(rsc): When GOPATH-based "go get" is removed, unexport this function.
func LoadImport(path, srcDir string, parent *Package, stk *ImportStack, importPos []token.Position, mode int) *Package {
stk.Push(path)
defer stk.Pop()
+ if strings.HasPrefix(path, "mod/") {
+ // Paths beginning with "mod/" might accidentally
+ // look in the module cache directory tree in $GOPATH/pkg/mod/.
+ // This prefix is owned by the Go core for possible use in the
+ // standard library (since it does not begin with a domain name),
+ // so it's OK to disallow entirely.
+ return &Package{
+ PackagePublic: PackagePublic{
+ ImportPath: path,
+ Error: &PackageError{
+ ImportStack: stk.Copy(),
+ Err: fmt.Sprintf("disallowed import path %q", path),
+ },
+ },
+ }
+ }
+
+ if strings.Contains(path, "@") {
+ var text string
+ if cfg.ModulesEnabled {
+ text = "can only use path@version syntax with 'go get'"
+ } else {
+ text = "cannot use path@version syntax in GOPATH mode"
+ }
+ return &Package{
+ PackagePublic: PackagePublic{
+ ImportPath: path,
+ Error: &PackageError{
+ ImportStack: stk.Copy(),
+ Err: text,
+ },
+ },
+ }
+ }
+
+ parentPath := ""
+ if parent != nil {
+ parentPath = parent.ImportPath
+ }
+
// Determine canonical identifier for this package.
// For a local import the identifier is the pseudo-import path
// we create from the full directory to the package.
@@ -418,8 +491,16 @@ func LoadImport(path, srcDir string, parent *Package, stk *ImportStack, importPo
importPath := path
origPath := path
isLocal := build.IsLocalImport(path)
+ var modDir string
+ var modErr error
if isLocal {
importPath = dirToImportPath(filepath.Join(srcDir, path))
+ } else if cfg.ModulesEnabled {
+ var p string
+ modDir, p, modErr = ModLookup(path)
+ if modErr == nil {
+ importPath = p
+ }
} else if mode&ResolveImport != 0 {
// We do our own path resolution, because we want to
// find out the key to use in packageCache without the
@@ -444,17 +525,31 @@ func LoadImport(path, srcDir string, parent *Package, stk *ImportStack, importPo
// Load package.
// Import always returns bp != nil, even if an error occurs,
// in order to return partial information.
- buildMode := build.ImportComment
- if mode&ResolveImport == 0 || path != origPath {
- // Not vendoring, or we already found the vendored path.
- buildMode |= build.IgnoreVendor
+ var bp *build.Package
+ var err error
+ if modDir != "" {
+ bp, err = cfg.BuildContext.ImportDir(modDir, 0)
+ } else if modErr != nil {
+ bp = new(build.Package)
+ err = fmt.Errorf("unknown import path %q: %v", importPath, modErr)
+ } else if cfg.ModulesEnabled && path != "unsafe" {
+ bp = new(build.Package)
+ err = fmt.Errorf("unknown import path %q: internal error: module loader did not resolve import", importPath)
+ } else {
+ buildMode := build.ImportComment
+ if mode&ResolveImport == 0 || path != origPath {
+ // Not vendoring, or we already found the vendored path.
+ buildMode |= build.IgnoreVendor
+ }
+ bp, err = cfg.BuildContext.Import(path, srcDir, buildMode)
}
- bp, err := cfg.BuildContext.Import(path, srcDir, buildMode)
bp.ImportPath = importPath
if cfg.GOBIN != "" {
bp.BinDir = cfg.GOBIN
+ } else if cfg.ModulesEnabled {
+ bp.BinDir = ModBinDir()
}
- if err == nil && !isLocal && bp.ImportComment != "" && bp.ImportComment != path &&
+ if modDir == "" && err == nil && !isLocal && bp.ImportComment != "" && bp.ImportComment != path &&
!strings.Contains(path, "/vendor/") && !strings.HasPrefix(path, "vendor/") {
err = fmt.Errorf("code in directory %s expects import %q", bp.Dir, bp.ImportComment)
}
@@ -463,7 +558,7 @@ func LoadImport(path, srcDir string, parent *Package, stk *ImportStack, importPo
p = setErrorPos(p, importPos)
}
- if origPath != cleanImport(origPath) {
+ if modDir == "" && origPath != cleanImport(origPath) {
p.Error = &PackageError{
ImportStack: stk.Copy(),
Err: fmt.Sprintf("non-canonical import path: %q should be %q", origPath, pathpkg.Clean(origPath)),
@@ -473,11 +568,11 @@ func LoadImport(path, srcDir string, parent *Package, stk *ImportStack, importPo
}
// Checked on every import because the rules depend on the code doing the importing.
- if perr := disallowInternal(srcDir, p, stk); perr != p {
+ if perr := disallowInternal(srcDir, parent, parentPath, p, stk); perr != p {
return setErrorPos(perr, importPos)
}
if mode&ResolveImport != 0 {
- if perr := disallowVendor(srcDir, origPath, p, stk); perr != p {
+ if perr := disallowVendor(srcDir, parent, parentPath, origPath, p, stk); perr != p {
return setErrorPos(perr, importPos)
}
}
@@ -539,8 +634,14 @@ func isDir(path string) bool {
// There are two different resolutions applied.
// First, there is Go 1.5 vendoring (golang.org/s/go15vendor).
// If vendor expansion doesn't trigger, then the path is also subject to
-// Go 1.11 vgo legacy conversion (golang.org/issue/25069).
+// Go 1.11 module legacy conversion (golang.org/issue/25069).
func ResolveImportPath(parent *Package, path string) (found string) {
+ if cfg.ModulesEnabled {
+ if _, p, e := ModLookup(path); e == nil {
+ return p
+ }
+ return path
+ }
found = VendoredImportPath(parent, path)
if found != path {
return found
@@ -828,10 +929,11 @@ func reusePackage(p *Package, stk *ImportStack) *Package {
return p
}
-// disallowInternal checks that srcDir is allowed to import p.
+// disallowInternal checks that srcDir (containing package importerPath, if non-empty)
+// is allowed to import p.
// If the import is allowed, disallowInternal returns the original package p.
// If not, it returns a new package containing just an appropriate error.
-func disallowInternal(srcDir string, p *Package, stk *ImportStack) *Package {
+func disallowInternal(srcDir string, importer *Package, importerPath string, p *Package, stk *ImportStack) *Package {
// golang.org/s/go14internal:
// An import of a path containing the element “internal”
// is disallowed if the importing code is outside the tree
@@ -874,23 +976,40 @@ func disallowInternal(srcDir string, p *Package, stk *ImportStack) *Package {
if i > 0 {
i-- // rewind over slash in ".../internal"
}
- parent := p.Dir[:i+len(p.Dir)-len(p.ImportPath)]
- if str.HasFilePathPrefix(filepath.Clean(srcDir), filepath.Clean(parent)) {
- return p
- }
- // Look for symlinks before reporting error.
- srcDir = expandPath(srcDir)
- parent = expandPath(parent)
- if str.HasFilePathPrefix(filepath.Clean(srcDir), filepath.Clean(parent)) {
- return p
+ if p.Module == nil {
+ parent := p.Dir[:i+len(p.Dir)-len(p.ImportPath)]
+
+ if str.HasFilePathPrefix(filepath.Clean(srcDir), filepath.Clean(parent)) {
+ return p
+ }
+
+ // Look for symlinks before reporting error.
+ srcDir = expandPath(srcDir)
+ parent = expandPath(parent)
+ if str.HasFilePathPrefix(filepath.Clean(srcDir), filepath.Clean(parent)) {
+ return 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 == "." {
+ // The importer is a list of command-line files.
+ // Pretend that the import path is the import path of the
+ // directory containing them.
+ importerPath = ModDirImportPath(importer.Dir)
+ }
+ parentOfInternal := p.ImportPath[:i]
+ if str.HasPathPrefix(importerPath, parentOfInternal) {
+ return p
+ }
}
// Internal is present, and srcDir is outside parent's tree. Not allowed.
perr := *p
perr.Error = &PackageError{
ImportStack: stk.Copy(),
- Err: "use of internal package not allowed",
+ Err: "use of internal package " + p.ImportPath + " not allowed",
}
perr.Incomplete = true
return &perr
@@ -915,10 +1034,11 @@ func findInternal(path string) (index int, ok bool) {
return 0, false
}
-// disallowVendor checks that srcDir is allowed to import p as path.
+// disallowVendor checks that srcDir (containing package importerPath, if non-empty)
+// is allowed to import p as path.
// If the import is allowed, disallowVendor returns the original package p.
// If not, it returns a new package containing just an appropriate error.
-func disallowVendor(srcDir, path string, p *Package, stk *ImportStack) *Package {
+func disallowVendor(srcDir string, importer *Package, importerPath, path string, p *Package, stk *ImportStack) *Package {
// The stack includes p.ImportPath.
// If that's the only thing on the stack, we started
// with a name given on the command line, not an
@@ -927,6 +1047,20 @@ func disallowVendor(srcDir, path string, p *Package, stk *ImportStack) *Package
return p
}
+ // Modules must not import vendor packages in the standard library,
+ // but the usual vendor visibility check will not catch them
+ // because the module loader presents them with an ImportPath starting
+ // with "golang_org/" instead of "vendor/".
+ if p.Standard && !importer.Standard && strings.HasPrefix(p.ImportPath, "golang_org") {
+ perr := *p
+ perr.Error = &PackageError{
+ ImportStack: stk.Copy(),
+ Err: "use of vendored package " + path + " not allowed",
+ }
+ perr.Incomplete = true
+ return &perr
+ }
+
if perr := disallowVendorVisibility(srcDir, p, stk); perr != p {
return perr
}
@@ -1057,26 +1191,6 @@ var foldPath = make(map[string]string)
func (p *Package) load(stk *ImportStack, bp *build.Package, err error) {
p.copyBuild(bp)
- // Decide whether p was listed on the command line.
- // Given that load is called while processing the command line,
- // you might think we could simply pass a flag down into load
- // saying whether we are loading something named on the command
- // line or something to satisfy an import. But the first load of a
- // package named on the command line may be as a dependency
- // of an earlier package named on the command line, not when we
- // get to that package during command line processing.
- // For example "go test fmt reflect" will load reflect as a dependency
- // of fmt before it attempts to load as a command-line argument.
- // Because loads are cached, the later load will be a no-op,
- // so it is important that the first load can fill in CmdlinePkg correctly.
- // Hence the call to an explicit matching check here.
- p.Internal.CmdlinePkg = isCmdlinePkg(p)
-
- p.Internal.Asmflags = BuildAsmflags.For(p)
- p.Internal.Gcflags = BuildGcflags.For(p)
- p.Internal.Ldflags = BuildLdflags.For(p)
- p.Internal.Gccgoflags = BuildGccgoflags.For(p)
-
// The localPrefix is the path we interpret ./ imports relative to.
// Synthesized main packages sometimes override this.
if p.Internal.Local {
@@ -1113,11 +1227,45 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) {
return
}
_, elem := filepath.Split(p.Dir)
+ if cfg.ModulesEnabled {
+ // NOTE(rsc): Using p.ImportPath instead of p.Dir
+ // makes sure we install a package in the root of a
+ // cached module directory as that package name
+ // not name@v1.2.3.
+ // Using p.ImportPath instead of p.Dir
+ // is probably correct all the time,
+ // even for non-module-enabled code,
+ // but I'm not brave enough to change the
+ // non-module behavior this late in the
+ // release cycle. Maybe for Go 1.12.
+ // See golang.org/issue/26869.
+ _, elem = pathpkg.Split(p.ImportPath)
+
+ // If this is example.com/mycmd/v2, it's more useful to install it as mycmd than as v2.
+ // See golang.org/issue/24667.
+ isVersion := func(v string) bool {
+ if len(v) < 2 || v[0] != 'v' || v[1] < '1' || '9' < v[1] {
+ return false
+ }
+ for i := 2; i < len(v); i++ {
+ if c := v[i]; c < '0' || '9' < c {
+ return false
+ }
+ }
+ return true
+ }
+ if isVersion(elem) {
+ _, elem = pathpkg.Split(pathpkg.Dir(p.ImportPath))
+ }
+ }
full := cfg.BuildContext.GOOS + "_" + cfg.BuildContext.GOARCH + "/" + elem
if cfg.BuildContext.GOOS != base.ToolGOOS || cfg.BuildContext.GOARCH != base.ToolGOARCH {
// Install cross-compiled binaries to subdirectories of bin.
elem = full
}
+ if p.Internal.Build.BinDir == "" && cfg.ModulesEnabled {
+ p.Internal.Build.BinDir = ModBinDir()
+ }
if p.Internal.Build.BinDir != "" {
// Install to GOBIN or bin of GOPATH entry.
p.Target = filepath.Join(p.Internal.Build.BinDir, elem)
@@ -1165,31 +1313,37 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) {
// Build augmented import list to add implicit dependencies.
// Be careful not to add imports twice, just to avoid confusion.
importPaths := p.Imports
- addImport := func(path string) {
+ addImport := func(path string, forCompiler bool) {
for _, p := range importPaths {
if path == p {
return
}
}
importPaths = append(importPaths, path)
+ if forCompiler {
+ p.Internal.CompiledImports = append(p.Internal.CompiledImports, path)
+ }
}
- // Cgo translation adds imports of "runtime/cgo" and "syscall",
+ // Cgo translation adds imports of "unsafe", "runtime/cgo" and "syscall",
// except for certain packages, to avoid circular dependencies.
+ if p.UsesCgo() {
+ addImport("unsafe", true)
+ }
if p.UsesCgo() && (!p.Standard || !cgoExclude[p.ImportPath]) && cfg.BuildContext.Compiler != "gccgo" {
- addImport("runtime/cgo")
+ addImport("runtime/cgo", true)
}
if p.UsesCgo() && (!p.Standard || !cgoSyscallExclude[p.ImportPath]) {
- addImport("syscall")
+ addImport("syscall", true)
}
// SWIG adds imports of some standard packages.
if p.UsesSwig() {
if cfg.BuildContext.Compiler != "gccgo" {
- addImport("runtime/cgo")
+ addImport("runtime/cgo", true)
}
- addImport("syscall")
- addImport("sync")
+ addImport("syscall", true)
+ addImport("sync", true)
// TODO: The .swig and .swigcxx files can use
// %go_import directives to import other packages.
@@ -1198,7 +1352,7 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) {
// The linker loads implicit dependencies.
if p.Name == "main" && !p.Internal.ForceLibrary {
for _, dep := range LinkerDeps(p) {
- addImport(dep)
+ addImport(dep, false)
}
}
@@ -1368,6 +1522,13 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) {
setError(fmt.Sprintf("case-insensitive import collision: %q and %q", p.ImportPath, other))
return
}
+
+ if cfg.ModulesEnabled {
+ p.Module = ModPackageModuleInfo(p.ImportPath)
+ if p.Name == "main" {
+ p.Internal.BuildInfo = ModPackageBuildInfo(p.ImportPath, p.Deps)
+ }
+ }
}
// SafeArg reports whether arg is a "safe" command-line argument,
@@ -1466,7 +1627,13 @@ func (p *Package) mkAbs(list []string) []string {
// InternalGoFiles returns the list of Go files being built for the package,
// using absolute paths.
func (p *Package) InternalGoFiles() []string {
- return p.mkAbs(str.StringList(p.GoFiles, p.CgoFiles, p.TestGoFiles, p.XTestGoFiles))
+ return p.mkAbs(str.StringList(p.GoFiles, p.CgoFiles, p.TestGoFiles))
+}
+
+// InternalXGoFiles returns the list of Go files being built for the XTest package,
+// using absolute paths.
+func (p *Package) InternalXGoFiles() []string {
+ return p.mkAbs(p.XTestGoFiles)
}
// InternalGoFiles returns the list of all Go files possibly relevant for the package,
@@ -1492,7 +1659,7 @@ func (p *Package) UsesCgo() bool {
return len(p.CgoFiles) > 0
}
-// packageList returns the list of packages in the dag rooted at roots
+// PackageList returns the list of packages in the dag rooted at roots
// as visited in a depth-first post-order traversal.
func PackageList(roots []*Package) []*Package {
seen := map[*Package]bool{}
@@ -1514,6 +1681,42 @@ func PackageList(roots []*Package) []*Package {
return all
}
+// TestPackageList returns the list of packages in the dag rooted at roots
+// as visited in a depth-first post-order traversal, including the test
+// imports of the roots. This ignores errors in test packages.
+func GetTestPackageList(roots []*Package) []*Package {
+ seen := map[*Package]bool{}
+ all := []*Package{}
+ var walk func(*Package)
+ walk = func(p *Package) {
+ if seen[p] {
+ return
+ }
+ seen[p] = true
+ for _, p1 := range p.Internal.Imports {
+ walk(p1)
+ }
+ all = append(all, p)
+ }
+ walkTest := func(root *Package, path string) {
+ var stk ImportStack
+ p1 := LoadImport(path, root.Dir, root, &stk, root.Internal.Build.TestImportPos[path], ResolveImport)
+ if p1.Error == nil {
+ walk(p1)
+ }
+ }
+ for _, root := range roots {
+ walk(root)
+ for _, path := range root.TestImports {
+ walkTest(root, path)
+ }
+ for _, path := range root.XTestImports {
+ walkTest(root, path)
+ }
+ }
+ return all
+}
+
var cmdCache = map[string]*Package{}
func ClearCmdCache() {
@@ -1522,11 +1725,31 @@ func ClearCmdCache() {
}
}
+// LoadPackage loads the package named by arg.
+func LoadPackage(arg string, stk *ImportStack) *Package {
+ p := loadPackage(arg, stk)
+ setToolFlags(p)
+ return p
+}
+
+// LoadPackageNoFlags is like LoadPackage
+// but does not guarantee that the build tool flags are set in the result.
+// It is only for use by GOPATH-based "go get"
+// and is only appropriate for preliminary loading of packages.
+// A real load using LoadPackage or (more likely)
+// Packages, PackageAndErrors, or PackagesForBuild
+// must be done before passing the package to any build
+// steps, so that the tool flags can be set properly.
+// TODO(rsc): When GOPATH-based "go get" is removed, delete this function.
+func LoadPackageNoFlags(arg string, stk *ImportStack) *Package {
+ return loadPackage(arg, stk)
+}
+
// loadPackage is like loadImport but is used for command-line arguments,
// not for paths found in import statements. In addition to ordinary import paths,
// loadPackage accepts pseudo-paths beginning with cmd/ to denote commands
// in the Go command directory, as well as paths to those directories.
-func LoadPackage(arg string, stk *ImportStack) *Package {
+func loadPackage(arg string, stk *ImportStack) *Package {
if build.IsLocalImport(arg) {
dir := arg
if !filepath.IsAbs(dir) {
@@ -1573,8 +1796,12 @@ func LoadPackage(arg string, stk *ImportStack) *Package {
// This lets you run go test ./ioutil in package io and be
// referring to io/ioutil rather than a hypothetical import of
// "./ioutil".
- if build.IsLocalImport(arg) {
- bp, _ := cfg.BuildContext.ImportDir(filepath.Join(base.Cwd, arg), build.FindOnly)
+ if build.IsLocalImport(arg) || filepath.IsAbs(arg) {
+ dir := arg
+ if !filepath.IsAbs(arg) {
+ dir = filepath.Join(base.Cwd, arg)
+ }
+ bp, _ := cfg.BuildContext.ImportDir(dir, build.FindOnly)
if bp.ImportPath != "" && bp.ImportPath != "." {
arg = bp.ImportPath
}
@@ -1583,7 +1810,7 @@ func LoadPackage(arg string, stk *ImportStack) *Package {
return LoadImport(arg, base.Cwd, nil, stk, nil, 0)
}
-// packages returns the packages named by the
+// Packages returns the packages named by the
// command line arguments 'args'. If a named package
// cannot be loaded at all (for example, if the directory does not exist),
// then packages prints an error and does not include that
@@ -1603,41 +1830,68 @@ func Packages(args []string) []*Package {
return pkgs
}
-// packagesAndErrors is like 'packages' but returns a
+// PackagesAndErrors is like 'packages' but returns a
// *Package for every argument, even the ones that
// cannot be loaded at all.
// The packages that fail to load will have p.Error != nil.
-func PackagesAndErrors(args []string) []*Package {
- if len(args) > 0 && strings.HasSuffix(args[0], ".go") {
- return []*Package{GoFilesPackage(args)}
+func PackagesAndErrors(patterns []string) []*Package {
+ if len(patterns) > 0 && strings.HasSuffix(patterns[0], ".go") {
+ return []*Package{GoFilesPackage(patterns)}
}
- args = ImportPaths(args)
+ matches := ImportPaths(patterns)
var (
pkgs []*Package
stk ImportStack
- seenArg = make(map[string]bool)
seenPkg = make(map[*Package]bool)
)
- for _, arg := range args {
- if seenArg[arg] {
- continue
- }
- seenArg[arg] = true
- pkg := LoadPackage(arg, &stk)
- if seenPkg[pkg] {
- continue
+ for _, m := range matches {
+ for _, pkg := range m.Pkgs {
+ p := loadPackage(pkg, &stk)
+ p.Match = append(p.Match, m.Pattern)
+ p.Internal.CmdlinePkg = true
+ if m.Literal {
+ // Note: do not set = m.Literal unconditionally
+ // because maybe we'll see p matching both
+ // a literal and also a non-literal pattern.
+ p.Internal.CmdlinePkgLiteral = true
+ }
+ if seenPkg[p] {
+ continue
+ }
+ seenPkg[p] = true
+ pkgs = append(pkgs, p)
}
- seenPkg[pkg] = true
- pkgs = append(pkgs, pkg)
}
+ // Now that CmdlinePkg is set correctly,
+ // compute the effective flags for all loaded packages
+ // (not just the ones matching the patterns but also
+ // their dependencies).
+ setToolFlags(pkgs...)
+
return pkgs
}
-// packagesForBuild is like 'packages' but fails if any of
-// the packages or their dependencies have errors
+func setToolFlags(pkgs ...*Package) {
+ for _, p := range PackageList(pkgs) {
+ p.Internal.Asmflags = BuildAsmflags.For(p)
+ p.Internal.Gcflags = BuildGcflags.For(p)
+ p.Internal.Ldflags = BuildLdflags.For(p)
+ p.Internal.Gccgoflags = BuildGccgoflags.For(p)
+ }
+}
+
+func ImportPaths(args []string) []*search.Match {
+ if ModInit(); cfg.ModulesEnabled {
+ return ModImportPaths(args)
+ }
+ return search.ImportPaths(args)
+}
+
+// PackagesForBuild is like Packages but exits
+// if any of the packages or their dependencies have errors
// (cannot be built).
func PackagesForBuild(args []string) []*Package {
pkgs := PackagesAndErrors(args)
@@ -1645,6 +1899,7 @@ func PackagesForBuild(args []string) []*Package {
for _, pkg := range pkgs {
if pkg.Error != nil {
base.Errorf("can't load package: %s", pkg.Error)
+ printed[pkg.Error] = true
}
for _, err := range pkg.DepsErrors {
// Since these are errors in dependencies,
@@ -1682,7 +1937,8 @@ func PackagesForBuild(args []string) []*Package {
// (typically named on the command line). The target is named p.a for
// package p or named after the first Go file for package main.
func GoFilesPackage(gofiles []string) *Package {
- // TODO: Remove this restriction.
+ ModInit()
+
for _, f := range gofiles {
if !strings.HasSuffix(f, ".go") {
base.Fatalf("named files must be .go files")
@@ -1720,6 +1976,10 @@ func GoFilesPackage(gofiles []string) *Package {
}
ctxt.ReadDir = func(string) ([]os.FileInfo, error) { return dirent, nil }
+ if cfg.ModulesEnabled {
+ ModImportFromFiles(gofiles)
+ }
+
var err error
if dir == "" {
dir = base.Cwd
@@ -1730,6 +1990,11 @@ 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
@@ -1739,6 +2004,7 @@ func GoFilesPackage(gofiles []string) *Package {
pkg.Internal.LocalPrefix = dirToImportPath(dir)
pkg.ImportPath = "command-line-arguments"
pkg.Target = ""
+ pkg.Match = gofiles
if pkg.Name == "main" {
_, elem := filepath.Split(gofiles[0])
@@ -1748,152 +2014,12 @@ func GoFilesPackage(gofiles []string) *Package {
}
if cfg.GOBIN != "" {
pkg.Target = filepath.Join(cfg.GOBIN, exe)
+ } else if cfg.ModulesEnabled {
+ pkg.Target = filepath.Join(ModBinDir(), exe)
}
}
- return pkg
-}
-
-// GetTestPackagesFor returns package structs ptest, the package p plus
-// its test files, and pxtest, the external tests of package p.
-// pxtest may be nil. If there are no test files, forceTest decides
-// whether this returns a new package struct or just returns p.
-func GetTestPackagesFor(p *Package, forceTest bool) (ptest, pxtest *Package, err error) {
- var imports, ximports []*Package
- var stk ImportStack
- stk.Push(p.ImportPath + " (test)")
- rawTestImports := str.StringList(p.TestImports)
- for i, path := range p.TestImports {
- p1 := LoadImport(path, p.Dir, p, &stk, p.Internal.Build.TestImportPos[path], ResolveImport)
- if p1.Error != nil {
- return nil, nil, p1.Error
- }
- if len(p1.DepsErrors) > 0 {
- err := p1.DepsErrors[0]
- err.Pos = "" // show full import stack
- return nil, nil, err
- }
- if str.Contains(p1.Deps, p.ImportPath) || p1.ImportPath == p.ImportPath {
- // Same error that loadPackage returns (via reusePackage) in pkg.go.
- // Can't change that code, because that code is only for loading the
- // non-test copy of a package.
- err := &PackageError{
- ImportStack: testImportStack(stk[0], p1, p.ImportPath),
- Err: "import cycle not allowed in test",
- IsImportCycle: true,
- }
- return nil, nil, err
- }
- p.TestImports[i] = p1.ImportPath
- imports = append(imports, p1)
- }
- stk.Pop()
- stk.Push(p.ImportPath + "_test")
- pxtestNeedsPtest := false
- rawXTestImports := str.StringList(p.XTestImports)
- for i, path := range p.XTestImports {
- p1 := LoadImport(path, p.Dir, p, &stk, p.Internal.Build.XTestImportPos[path], ResolveImport)
- if p1.Error != nil {
- return nil, nil, p1.Error
- }
- if len(p1.DepsErrors) > 0 {
- err := p1.DepsErrors[0]
- err.Pos = "" // show full import stack
- return nil, nil, err
- }
- if p1.ImportPath == p.ImportPath {
- pxtestNeedsPtest = true
- } else {
- ximports = append(ximports, p1)
- }
- p.XTestImports[i] = p1.ImportPath
- }
- stk.Pop()
-
- // Test package.
- if len(p.TestGoFiles) > 0 || forceTest {
- ptest = new(Package)
- *ptest = *p
- ptest.GoFiles = nil
- ptest.GoFiles = append(ptest.GoFiles, p.GoFiles...)
- ptest.GoFiles = append(ptest.GoFiles, p.TestGoFiles...)
- ptest.Target = ""
- // Note: The preparation of the vet config requires that common
- // indexes in ptest.Imports, ptest.Internal.Imports, and ptest.Internal.RawImports
- // all line up (but RawImports can be shorter than the others).
- // That is, for 0 ≤ i < len(RawImports),
- // RawImports[i] is the import string in the program text,
- // Imports[i] is the expanded import string (vendoring applied or relative path expanded away),
- // and Internal.Imports[i] is the corresponding *Package.
- // Any implicitly added imports appear in Imports and Internal.Imports
- // but not RawImports (because they were not in the source code).
- // We insert TestImports, imports, and rawTestImports at the start of
- // these lists to preserve the alignment.
- ptest.Imports = str.StringList(p.TestImports, p.Imports)
- ptest.Internal.Imports = append(imports, p.Internal.Imports...)
- ptest.Internal.RawImports = str.StringList(rawTestImports, p.Internal.RawImports)
- ptest.Internal.ForceLibrary = true
- ptest.Internal.Build = new(build.Package)
- *ptest.Internal.Build = *p.Internal.Build
- m := map[string][]token.Position{}
- for k, v := range p.Internal.Build.ImportPos {
- m[k] = append(m[k], v...)
- }
- for k, v := range p.Internal.Build.TestImportPos {
- m[k] = append(m[k], v...)
- }
- ptest.Internal.Build.ImportPos = m
- } else {
- ptest = p
- }
-
- // External test package.
- if len(p.XTestGoFiles) > 0 {
- pxtest = &Package{
- PackagePublic: PackagePublic{
- Name: p.Name + "_test",
- ImportPath: p.ImportPath + "_test",
- Root: p.Root,
- Dir: p.Dir,
- GoFiles: p.XTestGoFiles,
- Imports: p.XTestImports,
- },
- Internal: PackageInternal{
- LocalPrefix: p.Internal.LocalPrefix,
- Build: &build.Package{
- ImportPos: p.Internal.Build.XTestImportPos,
- },
- Imports: ximports,
- RawImports: rawXTestImports,
-
- Asmflags: p.Internal.Asmflags,
- Gcflags: p.Internal.Gcflags,
- Ldflags: p.Internal.Ldflags,
- Gccgoflags: p.Internal.Gccgoflags,
- },
- }
- if pxtestNeedsPtest {
- pxtest.Internal.Imports = append(pxtest.Internal.Imports, ptest)
- }
- }
-
- return ptest, pxtest, nil
-}
+ setToolFlags(pkg)
-func testImportStack(top string, p *Package, target string) []string {
- stk := []string{top, p.ImportPath}
-Search:
- for p.ImportPath != target {
- for _, p1 := range p.Internal.Imports {
- if p1.ImportPath == target || str.Contains(p1.Deps, target) {
- stk = append(stk, p1.ImportPath)
- p = p1
- continue Search
- }
- }
- // Can't happen, but in case it does...
- stk = append(stk, "<lost path to cycle>")
- break
- }
- return stk
+ return pkg
}