Commit d6b2b35e authored by Jay Conrod's avatar Jay Conrod

cmd/go: refactor load.LoadPackage into other functions

LoadPackage was used to load a *load.Package for a command line
argument, after pattern expansion. It provided two special cases on
top of LoadImport. First, it ensured that "cmd/" packages in GOROOT
were installed in "$GOROOT/bin" or "$GOROOT/pkg/tool". Second, it
translated absolute paths to packages in GOROOT and GOPATH into
regular import paths.

With this change, LoadImport now ensures "cmd/" packages have the
right Target (without the need for a special case) and
search.ImportPaths translates absolute paths.

LoadPackage no longer handles these special cases and has been renamed
to LoadImportWithFlags, since it's still useful for loading implicit
dependencies.

Updates #29758

Change-Id: I9d54036f90c3ccd9b3a0fe0eaddaa7749593cc91
Reviewed-on: https://go-review.googlesource.com/c/go/+/167748
Run-TryBot: Jay Conrod <jayconrod@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarBryan C. Mills <bcmills@google.com>
parent 4091cf97
...@@ -177,12 +177,6 @@ func runGet(cmd *base.Command, args []string) { ...@@ -177,12 +177,6 @@ func runGet(cmd *base.Command, args []string) {
// everything. // everything.
load.ClearPackageCache() load.ClearPackageCache()
// In order to rebuild packages information completely,
// we need to clear commands cache. Command packages are
// referring to evicted packages from the package cache.
// This leads to duplicated loads of the standard packages.
load.ClearCmdCache()
pkgs := load.PackagesForBuild(args) pkgs := load.PackagesForBuild(args)
// Phase 3. Install. // Phase 3. Install.
...@@ -240,7 +234,8 @@ func download(arg string, parent *load.Package, stk *load.ImportStack, mode int) ...@@ -240,7 +234,8 @@ func download(arg string, parent *load.Package, stk *load.ImportStack, mode int)
} }
load1 := func(path string, mode int) *load.Package { load1 := func(path string, mode int) *load.Package {
if parent == nil { if parent == nil {
return load.LoadPackageNoFlags(path, stk) mode := 0 // don't do module or vendor resolution
return load.LoadImport(path, base.Cwd, nil, stk, nil, mode)
} }
return load.LoadImport(path, parent.Dir, parent, stk, nil, mode|load.ResolveModule) return load.LoadImport(path, parent.Dir, parent, stk, nil, mode|load.ResolveModule)
} }
......
...@@ -377,7 +377,7 @@ func ClearPackageCachePartial(args []string) { ...@@ -377,7 +377,7 @@ func ClearPackageCachePartial(args []string) {
} }
} }
// ReloadPackageNoFlags is like LoadPackageNoFlags but makes sure // ReloadPackageNoFlags is like LoadImport but makes sure
// not to use the package cache. // not to use the package cache.
// It is only for use by GOPATH-based "go get". // It is only for use by GOPATH-based "go get".
// TODO(rsc): When GOPATH-based "go get" is removed, delete this function. // TODO(rsc): When GOPATH-based "go get" is removed, delete this function.
...@@ -387,7 +387,7 @@ func ReloadPackageNoFlags(arg string, stk *ImportStack) *Package { ...@@ -387,7 +387,7 @@ func ReloadPackageNoFlags(arg string, stk *ImportStack) *Package {
delete(packageCache, p.Dir) delete(packageCache, p.Dir)
delete(packageCache, p.ImportPath) delete(packageCache, p.ImportPath)
} }
return LoadPackageNoFlags(arg, stk) return LoadImport(arg, base.Cwd, nil, stk, nil, 0)
} }
// dirToImportPath returns the pseudo-import path we use for a package // dirToImportPath returns the pseudo-import path we use for a package
...@@ -552,7 +552,7 @@ func LoadImport(path, srcDir string, parent *Package, stk *ImportStack, importPo ...@@ -552,7 +552,7 @@ func LoadImport(path, srcDir string, parent *Package, stk *ImportStack, importPo
bp.ImportPath = importPath bp.ImportPath = importPath
if cfg.GOBIN != "" { if cfg.GOBIN != "" {
bp.BinDir = cfg.GOBIN bp.BinDir = cfg.GOBIN
} else if cfg.ModulesEnabled { } else if cfg.ModulesEnabled && !bp.Goroot {
bp.BinDir = ModBinDir() bp.BinDir = ModBinDir()
} }
if modDir == "" && err == nil && !isLocal && bp.ImportComment != "" && bp.ImportComment != path && if modDir == "" && err == nil && !isLocal && bp.ImportComment != "" && bp.ImportComment != path &&
...@@ -1716,99 +1716,17 @@ func TestPackageList(roots []*Package) []*Package { ...@@ -1716,99 +1716,17 @@ func TestPackageList(roots []*Package) []*Package {
return all return all
} }
var cmdCache = map[string]*Package{} // LoadImportWithFlags loads the package with the given import path and
// sets tool flags on that package. This function is useful loading implicit
func ClearCmdCache() { // dependencies (like sync/atomic for coverage).
for name := range cmdCache { // TODO(jayconrod): delete this function and set flags automatically
delete(cmdCache, name) // in LoadImport instead.
} func LoadImportWithFlags(path, srcDir string, parent *Package, stk *ImportStack, importPos []token.Position, mode int) *Package {
} p := LoadImport(path, srcDir, parent, stk, importPos, mode)
// LoadPackage loads the package named by arg.
func LoadPackage(arg string, stk *ImportStack) *Package {
p := loadPackage(arg, stk)
setToolFlags(p) setToolFlags(p)
return 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 {
if arg == "" {
panic("loadPackage called with empty package path")
}
if build.IsLocalImport(arg) {
dir := arg
if !filepath.IsAbs(dir) {
if abs, err := filepath.Abs(dir); err == nil {
// interpret relative to current directory
dir = abs
}
}
if sub, ok := hasSubdir(cfg.GOROOTsrc, dir); ok && strings.HasPrefix(sub, "cmd/") && !strings.Contains(sub[4:], "/") {
arg = sub
}
}
if strings.HasPrefix(arg, "cmd/") && !strings.Contains(arg[4:], "/") {
if p := cmdCache[arg]; p != nil {
return p
}
stk.Push(arg)
defer stk.Pop()
bp, err := cfg.BuildContext.ImportDir(filepath.Join(cfg.GOROOTsrc, arg), 0)
bp.ImportPath = arg
bp.Goroot = true
bp.BinDir = cfg.GOROOTbin
bp.Root = cfg.GOROOT
bp.SrcRoot = cfg.GOROOTsrc
p := new(Package)
cmdCache[arg] = p
p.load(stk, bp, err)
if p.Error == nil && p.Name != "main" {
p.Error = &PackageError{
ImportStack: stk.Copy(),
Err: fmt.Sprintf("expected package main but found package %s in %s", p.Name, p.Dir),
}
}
return p
}
// Wasn't a command; must be a package.
// If it is a local import path but names a standard package,
// we treat it as if the user specified the standard 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) || 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
}
}
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 // command line arguments 'args'. If a named package
// cannot be loaded at all (for example, if the directory does not exist), // cannot be loaded at all (for example, if the directory does not exist),
...@@ -1850,7 +1768,7 @@ func PackagesAndErrors(patterns []string) []*Package { ...@@ -1850,7 +1768,7 @@ func PackagesAndErrors(patterns []string) []*Package {
if pkg == "" { if pkg == "" {
panic(fmt.Sprintf("ImportPaths returned empty package for pattern %s", m.Pattern)) panic(fmt.Sprintf("ImportPaths returned empty package for pattern %s", m.Pattern))
} }
p := loadPackage(pkg, &stk) p := LoadImport(pkg, base.Cwd, nil, &stk, nil, 0)
p.Match = append(p.Match, m.Pattern) p.Match = append(p.Match, m.Pattern)
p.Internal.CmdlinePkg = true p.Internal.CmdlinePkg = true
if m.Literal { if m.Literal {
......
...@@ -327,14 +327,35 @@ func ImportPathsQuiet(patterns []string) []*Match { ...@@ -327,14 +327,35 @@ func ImportPathsQuiet(patterns []string) []*Match {
out = append(out, MatchPackages(a)) out = append(out, MatchPackages(a))
continue continue
} }
if build.IsLocalImport(a) || filepath.IsAbs(a) {
var m *Match
if strings.Contains(a, "...") { if strings.Contains(a, "...") {
if build.IsLocalImport(a) { m = MatchPackagesInFS(a)
out = append(out, MatchPackagesInFS(a))
} else { } else {
out = append(out, MatchPackages(a)) m = &Match{Pattern: a, Literal: true, Pkgs: []string{a}}
}
// Change the file import path to a regular import path if the package
// is in GOPATH or GOROOT. We don't report errors here; LoadImport
// (or something similar) will report them later.
for i, dir := range m.Pkgs {
if !filepath.IsAbs(dir) {
dir = filepath.Join(base.Cwd, dir)
}
if bp, _ := cfg.BuildContext.ImportDir(dir, build.FindOnly); bp.ImportPath != "" && bp.ImportPath != "." {
m.Pkgs[i] = bp.ImportPath
}
} }
out = append(out, m)
continue continue
} }
if strings.Contains(a, "...") {
out = append(out, MatchPackages(a))
continue
}
out = append(out, &Match{Pattern: a, Literal: true, Pkgs: []string{a}}) out = append(out, &Match{Pattern: a, Literal: true, Pkgs: []string{a}})
} }
return out return out
......
...@@ -760,7 +760,7 @@ func ensureImport(p *load.Package, pkg string) { ...@@ -760,7 +760,7 @@ func ensureImport(p *load.Package, pkg string) {
} }
} }
p1 := load.LoadPackage(pkg, &load.ImportStack{}) p1 := load.LoadImportWithFlags(pkg, p.Dir, p, &load.ImportStack{}, nil, 0)
if p1.Error != nil { if p1.Error != nil {
base.Fatalf("load %s: %v", pkg, p1.Error) base.Fatalf("load %s: %v", pkg, p1.Error)
} }
......
...@@ -289,7 +289,7 @@ func readpkglist(shlibpath string) (pkgs []*load.Package) { ...@@ -289,7 +289,7 @@ func readpkglist(shlibpath string) (pkgs []*load.Package) {
if strings.HasPrefix(t, "pkgpath ") { if strings.HasPrefix(t, "pkgpath ") {
t = strings.TrimPrefix(t, "pkgpath ") t = strings.TrimPrefix(t, "pkgpath ")
t = strings.TrimSuffix(t, ";") t = strings.TrimSuffix(t, ";")
pkgs = append(pkgs, load.LoadPackage(t, &stk)) pkgs = append(pkgs, load.LoadImportWithFlags(t, base.Cwd, nil, &stk, nil, 0))
} }
} }
} else { } else {
...@@ -300,7 +300,7 @@ func readpkglist(shlibpath string) (pkgs []*load.Package) { ...@@ -300,7 +300,7 @@ func readpkglist(shlibpath string) (pkgs []*load.Package) {
scanner := bufio.NewScanner(bytes.NewBuffer(pkglistbytes)) scanner := bufio.NewScanner(bytes.NewBuffer(pkglistbytes))
for scanner.Scan() { for scanner.Scan() {
t := scanner.Text() t := scanner.Text()
pkgs = append(pkgs, load.LoadPackage(t, &stk)) pkgs = append(pkgs, load.LoadImportWithFlags(t, base.Cwd, nil, &stk, nil, 0))
} }
} }
return return
...@@ -405,7 +405,7 @@ func (b *Builder) vetAction(mode, depMode BuildMode, p *load.Package) *Action { ...@@ -405,7 +405,7 @@ func (b *Builder) vetAction(mode, depMode BuildMode, p *load.Package) *Action {
// vet expects to be able to import "fmt". // vet expects to be able to import "fmt".
var stk load.ImportStack var stk load.ImportStack
stk.Push("vet") stk.Push("vet")
p1 := load.LoadPackage("fmt", &stk) p1 := load.LoadImportWithFlags("fmt", p.Dir, p, &stk, nil, 0)
stk.Pop() stk.Pop()
aFmt := b.CompileAction(ModeBuild, depMode, p1) aFmt := b.CompileAction(ModeBuild, depMode, p1)
...@@ -705,7 +705,7 @@ func (b *Builder) linkSharedAction(mode, depMode BuildMode, shlib string, a1 *Ac ...@@ -705,7 +705,7 @@ func (b *Builder) linkSharedAction(mode, depMode BuildMode, shlib string, a1 *Ac
} }
} }
var stk load.ImportStack var stk load.ImportStack
p := load.LoadPackage(pkg, &stk) p := load.LoadImportWithFlags(pkg, base.Cwd, nil, &stk, nil, 0)
if p.Error != nil { if p.Error != nil {
base.Fatalf("load %s: %v", pkg, p.Error) base.Fatalf("load %s: %v", pkg, p.Error)
} }
......
...@@ -304,7 +304,7 @@ func (gcToolchain) symabis(b *Builder, a *Action, sfiles []string) (string, erro ...@@ -304,7 +304,7 @@ func (gcToolchain) symabis(b *Builder, a *Action, sfiles []string) (string, erro
otherPkgs = []string{"sync/atomic"} otherPkgs = []string{"sync/atomic"}
} }
for _, p2name := range otherPkgs { for _, p2name := range otherPkgs {
p2 := load.LoadPackage(p2name, &load.ImportStack{}) p2 := load.LoadImportWithFlags(p2name, p.Dir, p, &load.ImportStack{}, nil, 0)
if len(p2.SFiles) == 0 { if len(p2.SFiles) == 0 {
continue continue
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment