Commit eb93b20c authored by Russ Cox's avatar Russ Cox

cmd/go: split out cmd/go/internal/load

This is one CL in a long sequence of changes to break up the
go command from one package into a plausible group of packages.

This sequence is concerned only with moving code, not changing
or cleaning up code. There will still be more cleanup after this sequence.

The entire sequence will be submitted together: it is not a goal
for the tree to build at every step.

For #18653.

Change-Id: Ic802483e50598def638f1e2e706d5fdf7822d32d
Reviewed-on: https://go-review.googlesource.com/36196Reviewed-by: default avatarDavid Crawshaw <crawshaw@golang.org>
parent 461c3e52
...@@ -6,8 +6,8 @@ package main ...@@ -6,8 +6,8 @@ package main
import ( import (
"bytes" "bytes"
"cmd/go/internal/cfg"
"cmd/go/internal/base" "cmd/go/internal/base"
"cmd/go/internal/cfg"
"fmt" "fmt"
"io" "io"
"io/ioutil" "io/ioutil"
......
...@@ -30,6 +30,7 @@ import ( ...@@ -30,6 +30,7 @@ import (
"cmd/go/internal/base" "cmd/go/internal/base"
"cmd/go/internal/buildid" "cmd/go/internal/buildid"
"cmd/go/internal/cfg" "cmd/go/internal/cfg"
"cmd/go/internal/load"
"cmd/go/internal/str" "cmd/go/internal/str"
) )
...@@ -288,7 +289,7 @@ func (v *stringsFlag) String() string { ...@@ -288,7 +289,7 @@ func (v *stringsFlag) String() string {
return "<stringsFlag>" return "<stringsFlag>"
} }
func pkgsMain(pkgs []*Package) (res []*Package) { func pkgsMain(pkgs []*load.Package) (res []*load.Package) {
for _, p := range pkgs { for _, p := range pkgs {
if p.Name == "main" { if p.Name == "main" {
res = append(res, p) res = append(res, p)
...@@ -297,7 +298,7 @@ func pkgsMain(pkgs []*Package) (res []*Package) { ...@@ -297,7 +298,7 @@ func pkgsMain(pkgs []*Package) (res []*Package) {
return res return res
} }
func pkgsNotMain(pkgs []*Package) (res []*Package) { func pkgsNotMain(pkgs []*load.Package) (res []*load.Package) {
for _, p := range pkgs { for _, p := range pkgs {
if p.Name != "main" { if p.Name != "main" {
res = append(res, p) res = append(res, p)
...@@ -306,7 +307,7 @@ func pkgsNotMain(pkgs []*Package) (res []*Package) { ...@@ -306,7 +307,7 @@ func pkgsNotMain(pkgs []*Package) (res []*Package) {
return res return res
} }
var pkgsFilter = func(pkgs []*Package) []*Package { return pkgs } var pkgsFilter = func(pkgs []*load.Package) []*load.Package { return pkgs }
func buildModeInit() { func buildModeInit() {
gccgo := cfg.BuildToolchainName == "gccgo" gccgo := cfg.BuildToolchainName == "gccgo"
...@@ -316,7 +317,7 @@ func buildModeInit() { ...@@ -316,7 +317,7 @@ func buildModeInit() {
case "archive": case "archive":
pkgsFilter = pkgsNotMain pkgsFilter = pkgsNotMain
case "c-archive": case "c-archive":
pkgsFilter = func(p []*Package) []*Package { pkgsFilter = func(p []*load.Package) []*load.Package {
if len(p) != 1 || p[0].Name != "main" { if len(p) != 1 || p[0].Name != "main" {
base.Fatalf("-buildmode=c-archive requires exactly one main package") base.Fatalf("-buildmode=c-archive requires exactly one main package")
} }
...@@ -450,7 +451,7 @@ func runBuild(cmd *base.Command, args []string) { ...@@ -450,7 +451,7 @@ func runBuild(cmd *base.Command, args []string) {
var b builder var b builder
b.init() b.init()
pkgs := packagesForBuild(args) pkgs := load.PackagesForBuild(args)
if len(pkgs) == 1 && pkgs[0].Name == "main" && cfg.BuildO == "" { if len(pkgs) == 1 && pkgs[0].Name == "main" && cfg.BuildO == "" {
_, cfg.BuildO = path.Split(pkgs[0].ImportPath) _, cfg.BuildO = path.Split(pkgs[0].ImportPath)
...@@ -489,7 +490,7 @@ func runBuild(cmd *base.Command, args []string) { ...@@ -489,7 +490,7 @@ func runBuild(cmd *base.Command, args []string) {
base.Fatalf("no packages to build") base.Fatalf("no packages to build")
} }
p := pkgs[0] p := pkgs[0]
p.target = cfg.BuildO p.Internal.Target = cfg.BuildO
p.Stale = true // must build - not up to date p.Stale = true // must build - not up to date
p.StaleReason = "build -o flag in use" p.StaleReason = "build -o flag in use"
a := b.action(modeInstall, depMode, p) a := b.action(modeInstall, depMode, p)
...@@ -499,7 +500,7 @@ func runBuild(cmd *base.Command, args []string) { ...@@ -499,7 +500,7 @@ func runBuild(cmd *base.Command, args []string) {
var a *action var a *action
if cfg.BuildBuildmode == "shared" { if cfg.BuildBuildmode == "shared" {
pkgs := pkgsFilter(packages(args)) pkgs := pkgsFilter(load.Packages(args))
if libName, err := libname(args, pkgs); err != nil { if libName, err := libname(args, pkgs); err != nil {
base.Fatalf("%s", err.Error()) base.Fatalf("%s", err.Error())
} else { } else {
...@@ -507,7 +508,7 @@ func runBuild(cmd *base.Command, args []string) { ...@@ -507,7 +508,7 @@ func runBuild(cmd *base.Command, args []string) {
} }
} else { } else {
a = &action{} a = &action{}
for _, p := range pkgsFilter(packages(args)) { for _, p := range pkgsFilter(load.Packages(args)) {
a.deps = append(a.deps, b.action(modeBuild, depMode, p)) a.deps = append(a.deps, b.action(modeBuild, depMode, p))
} }
} }
...@@ -528,11 +529,6 @@ See also: go build, go get, go clean. ...@@ -528,11 +529,6 @@ See also: go build, go get, go clean.
`, `,
} }
// isMetaPackage checks if name is a reserved package name that expands to multiple packages
func isMetaPackage(name string) bool {
return name == "std" || name == "cmd" || name == "all"
}
// libname returns the filename to use for the shared library when using // libname returns the filename to use for the shared library when using
// -buildmode=shared. The rules we use are: // -buildmode=shared. The rules we use are:
// Use arguments for special 'meta' packages: // Use arguments for special 'meta' packages:
...@@ -547,7 +543,7 @@ func isMetaPackage(name string) bool { ...@@ -547,7 +543,7 @@ func isMetaPackage(name string) bool {
// gopkg.in/tomb.v2 -> libgopkg.in-tomb.v2.so // gopkg.in/tomb.v2 -> libgopkg.in-tomb.v2.so
// a/... b/... ---> liba/c,b/d.so - all matching import paths // a/... b/... ---> liba/c,b/d.so - all matching import paths
// Name parts are joined with ','. // Name parts are joined with ','.
func libname(args []string, pkgs []*Package) (string, error) { func libname(args []string, pkgs []*load.Package) (string, error) {
var libname string var libname string
appendName := func(arg string) { appendName := func(arg string) {
if libname == "" { if libname == "" {
...@@ -558,7 +554,7 @@ func libname(args []string, pkgs []*Package) (string, error) { ...@@ -558,7 +554,7 @@ func libname(args []string, pkgs []*Package) (string, error) {
} }
var haveNonMeta bool var haveNonMeta bool
for _, arg := range args { for _, arg := range args {
if isMetaPackage(arg) { if load.IsMetaPackage(arg) {
appendName(arg) appendName(arg)
} else { } else {
haveNonMeta = true haveNonMeta = true
...@@ -594,20 +590,20 @@ func runInstall(cmd *base.Command, args []string) { ...@@ -594,20 +590,20 @@ func runInstall(cmd *base.Command, args []string) {
} }
func installPackages(args []string, forGet bool) { func installPackages(args []string, forGet bool) {
if gobin != "" && !filepath.IsAbs(gobin) { if cfg.GOBIN != "" && !filepath.IsAbs(cfg.GOBIN) {
base.Fatalf("cannot install, GOBIN must be an absolute path") base.Fatalf("cannot install, GOBIN must be an absolute path")
} }
instrumentInit() instrumentInit()
buildModeInit() buildModeInit()
pkgs := pkgsFilter(packagesForBuild(args)) pkgs := pkgsFilter(load.PackagesForBuild(args))
for _, p := range pkgs { for _, p := range pkgs {
if p.Target == "" && (!p.Standard || p.ImportPath != "unsafe") { if p.Target == "" && (!p.Standard || p.ImportPath != "unsafe") {
switch { switch {
case p.gobinSubdir: case p.Internal.GobinSubdir:
base.Errorf("go install: cannot install cross-compiled binaries when GOBIN is set") base.Errorf("go install: cannot install cross-compiled binaries when GOBIN is set")
case p.cmdline: case p.Internal.Cmdline:
base.Errorf("go install: no install location for .go files listed on command line (GOBIN not set)") base.Errorf("go install: no install location for .go files listed on command line (GOBIN not set)")
case p.ConflictDir != "": case p.ConflictDir != "":
base.Errorf("go install: no install location for %s: hidden by %s", p.Dir, p.ConflictDir) base.Errorf("go install: no install location for %s: hidden by %s", p.Dir, p.ConflictDir)
...@@ -640,7 +636,7 @@ func installPackages(args []string, forGet bool) { ...@@ -640,7 +636,7 @@ func installPackages(args []string, forGet bool) {
// cmd/cgo is handled specially in b.action, so that we can // cmd/cgo is handled specially in b.action, so that we can
// both build and use it in the same 'go install'. // both build and use it in the same 'go install'.
action := b.action(modeInstall, modeInstall, p) action := b.action(modeInstall, modeInstall, p)
if goTools[p.ImportPath] == toTool && p.ImportPath != "cmd/cgo" { if load.GoTools[p.ImportPath] == load.ToTool && p.ImportPath != "cmd/cgo" {
a.deps = append(a.deps, action.deps...) a.deps = append(a.deps, action.deps...)
action.deps = append(action.deps, a) action.deps = append(action.deps, a)
tools = append(tools, action) tools = append(tools, action)
...@@ -717,7 +713,7 @@ type builder struct { ...@@ -717,7 +713,7 @@ type builder struct {
// An action represents a single action in the action graph. // An action represents a single action in the action graph.
type action struct { type action struct {
p *Package // the package this action works on p *load.Package // the package this action works on
deps []*action // actions that must happen before this one deps []*action // actions that must happen before this one
triggers []*action // inverse of deps triggers []*action // inverse of deps
cgo *action // action for cgo binary if needed cgo *action // action for cgo binary if needed
...@@ -743,7 +739,7 @@ type action struct { ...@@ -743,7 +739,7 @@ type action struct {
// cacheKey is the key for the action cache. // cacheKey is the key for the action cache.
type cacheKey struct { type cacheKey struct {
mode buildMode mode buildMode
p *Package p *load.Package
shlib string shlib string
} }
...@@ -756,14 +752,6 @@ const ( ...@@ -756,14 +752,6 @@ const (
modeInstall modeInstall
) )
var (
goroot = filepath.Clean(runtime.GOROOT())
gobin = os.Getenv("GOBIN")
gorootBin = filepath.Join(goroot, "bin")
gorootPkg = filepath.Join(goroot, "pkg")
gorootSrc = filepath.Join(goroot, "src")
)
func (b *builder) init() { func (b *builder) init() {
var err error var err error
b.print = func(a ...interface{}) (int, error) { b.print = func(a ...interface{}) (int, error) {
...@@ -789,93 +777,12 @@ func (b *builder) init() { ...@@ -789,93 +777,12 @@ func (b *builder) init() {
} }
} }
// goFilesPackage creates a package for building a collection of Go files
// (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.
for _, f := range gofiles {
if !strings.HasSuffix(f, ".go") {
base.Fatalf("named files must be .go files")
}
}
var stk importStack
ctxt := cfg.BuildContext
ctxt.UseAllFiles = true
// Synthesize fake "directory" that only shows the named files,
// to make it look like this is a standard package or
// command directory. So that local imports resolve
// consistently, the files must all be in the same directory.
var dirent []os.FileInfo
var dir string
for _, file := range gofiles {
fi, err := os.Stat(file)
if err != nil {
base.Fatalf("%s", err)
}
if fi.IsDir() {
base.Fatalf("%s is a directory, should be a Go file", file)
}
dir1, _ := filepath.Split(file)
if dir1 == "" {
dir1 = "./"
}
if dir == "" {
dir = dir1
} else if dir != dir1 {
base.Fatalf("named files must all be in one directory; have %s and %s", dir, dir1)
}
dirent = append(dirent, fi)
}
ctxt.ReadDir = func(string) ([]os.FileInfo, error) { return dirent, nil }
var err error
if dir == "" {
dir = base.Cwd
}
dir, err = filepath.Abs(dir)
if err != nil {
base.Fatalf("%s", err)
}
bp, err := ctxt.ImportDir(dir, 0)
pkg := new(Package)
pkg.local = true
pkg.cmdline = true
stk.push("main")
pkg.load(&stk, bp, err)
stk.pop()
pkg.localPrefix = dirToImportPath(dir)
pkg.ImportPath = "command-line-arguments"
pkg.target = ""
if pkg.Name == "main" {
_, elem := filepath.Split(gofiles[0])
exe := elem[:len(elem)-len(".go")] + cfg.ExeSuffix
if cfg.BuildO == "" {
cfg.BuildO = exe
}
if gobin != "" {
pkg.target = filepath.Join(gobin, exe)
}
}
pkg.Target = pkg.target
pkg.Stale = true
pkg.StaleReason = "files named on command line"
computeStale(pkg)
return pkg
}
// readpkglist returns the list of packages that were built into the shared library // readpkglist returns the list of packages that were built into the shared library
// at shlibpath. For the native toolchain this list is stored, newline separated, in // at shlibpath. For the native toolchain this list is stored, newline separated, in
// an ELF note with name "Go\x00\x00" and type 1. For GCCGO it is extracted from the // an ELF note with name "Go\x00\x00" and type 1. For GCCGO it is extracted from the
// .go_export section. // .go_export section.
func readpkglist(shlibpath string) (pkgs []*Package) { func readpkglist(shlibpath string) (pkgs []*load.Package) {
var stk importStack var stk load.ImportStack
if cfg.BuildToolchainName == "gccgo" { if cfg.BuildToolchainName == "gccgo" {
f, _ := elf.Open(shlibpath) f, _ := elf.Open(shlibpath)
sect := f.Section(".go_export") sect := f.Section(".go_export")
...@@ -886,7 +793,7 @@ func readpkglist(shlibpath string) (pkgs []*Package) { ...@@ -886,7 +793,7 @@ func readpkglist(shlibpath string) (pkgs []*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, loadPackage(t, &stk)) pkgs = append(pkgs, load.LoadPackage(t, &stk))
} }
} }
} else { } else {
...@@ -897,7 +804,7 @@ func readpkglist(shlibpath string) (pkgs []*Package) { ...@@ -897,7 +804,7 @@ func readpkglist(shlibpath string) (pkgs []*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, loadPackage(t, &stk)) pkgs = append(pkgs, load.LoadPackage(t, &stk))
} }
} }
return return
...@@ -907,7 +814,7 @@ func readpkglist(shlibpath string) (pkgs []*Package) { ...@@ -907,7 +814,7 @@ func readpkglist(shlibpath string) (pkgs []*Package) {
// depMode is the action to use when building dependencies. // depMode is the action to use when building dependencies.
// action never looks for p in a shared library, but may find p's dependencies in a // action never looks for p in a shared library, but may find p's dependencies in a
// shared library if buildLinkshared is true. // shared library if buildLinkshared is true.
func (b *builder) action(mode buildMode, depMode buildMode, p *Package) *action { func (b *builder) action(mode buildMode, depMode buildMode, p *load.Package) *action {
return b.action1(mode, depMode, p, false, "") return b.action1(mode, depMode, p, false, "")
} }
...@@ -915,7 +822,7 @@ func (b *builder) action(mode buildMode, depMode buildMode, p *Package) *action ...@@ -915,7 +822,7 @@ func (b *builder) action(mode buildMode, depMode buildMode, p *Package) *action
// depMode is the action to use when building dependencies. // depMode is the action to use when building dependencies.
// action1 will look for p in a shared library if lookshared is true. // action1 will look for p in a shared library if lookshared is true.
// forShlib is the shared library that p will become part of, if any. // forShlib is the shared library that p will become part of, if any.
func (b *builder) action1(mode buildMode, depMode buildMode, p *Package, lookshared bool, forShlib string) *action { func (b *builder) action1(mode buildMode, depMode buildMode, p *load.Package, lookshared bool, forShlib string) *action {
shlib := "" shlib := ""
if lookshared { if lookshared {
shlib = p.Shlib shlib = p.Shlib
...@@ -940,13 +847,13 @@ func (b *builder) action1(mode buildMode, depMode buildMode, p *Package, looksha ...@@ -940,13 +847,13 @@ func (b *builder) action1(mode buildMode, depMode buildMode, p *Package, looksha
return a return a
} }
a = &action{p: p, pkgdir: p.build.PkgRoot} a = &action{p: p, pkgdir: p.Internal.Build.PkgRoot}
if p.pkgdir != "" { // overrides p.t if p.Internal.Pkgdir != "" { // overrides p.t
a.pkgdir = p.pkgdir a.pkgdir = p.Internal.Pkgdir
} }
b.actionCache[key] = a b.actionCache[key] = a
for _, p1 := range p.imports { for _, p1 := range p.Internal.Imports {
if forShlib != "" { if forShlib != "" {
// p is part of a shared library. // p is part of a shared library.
if p1.Shlib != "" && p1.Shlib != forShlib { if p1.Shlib != "" && p1.Shlib != forShlib {
...@@ -973,8 +880,8 @@ func (b *builder) action1(mode buildMode, depMode buildMode, p *Package, looksha ...@@ -973,8 +880,8 @@ func (b *builder) action1(mode buildMode, depMode buildMode, p *Package, looksha
// are writing is not the cgo we need to use. // are writing is not the cgo we need to use.
if cfg.Goos == runtime.GOOS && cfg.Goarch == runtime.GOARCH && !cfg.BuildRace && !cfg.BuildMSan { if cfg.Goos == runtime.GOOS && cfg.Goarch == runtime.GOARCH && !cfg.BuildRace && !cfg.BuildMSan {
if (len(p.CgoFiles) > 0 || p.Standard && p.ImportPath == "runtime/cgo") && !cfg.BuildLinkshared && cfg.BuildBuildmode != "shared" { if (len(p.CgoFiles) > 0 || p.Standard && p.ImportPath == "runtime/cgo") && !cfg.BuildLinkshared && cfg.BuildBuildmode != "shared" {
var stk importStack var stk load.ImportStack
p1 := loadPackage("cmd/cgo", &stk) p1 := load.LoadPackage("cmd/cgo", &stk)
if p1.Error != nil { if p1.Error != nil {
base.Fatalf("load cmd/cgo: %v", p1.Error) base.Fatalf("load cmd/cgo: %v", p1.Error)
} }
...@@ -992,23 +899,23 @@ func (b *builder) action1(mode buildMode, depMode buildMode, p *Package, looksha ...@@ -992,23 +899,23 @@ func (b *builder) action1(mode buildMode, depMode buildMode, p *Package, looksha
// gccgo standard library is "fake" too. // gccgo standard library is "fake" too.
if cfg.BuildToolchainName == "gccgo" { if cfg.BuildToolchainName == "gccgo" {
// the target name is needed for cgo. // the target name is needed for cgo.
a.target = p.target a.target = p.Internal.Target
return a return a
} }
} }
if !p.Stale && p.target != "" { if !p.Stale && p.Internal.Target != "" {
// p.Stale==false implies that p.target is up-to-date. // p.Stale==false implies that p.Internal.Target is up-to-date.
// Record target name for use by actions depending on this one. // Record target name for use by actions depending on this one.
a.target = p.target a.target = p.Internal.Target
return a return a
} }
if p.local && p.target == "" { if p.Internal.Local && p.Internal.Target == "" {
// Imported via local path. No permanent target. // Imported via local path. No permanent target.
mode = modeBuild mode = modeBuild
} }
work := p.pkgdir work := p.Internal.Pkgdir
if work == "" { if work == "" {
work = b.work work = b.work
} }
...@@ -1020,10 +927,10 @@ func (b *builder) action1(mode buildMode, depMode buildMode, p *Package, looksha ...@@ -1020,10 +927,10 @@ func (b *builder) action1(mode buildMode, depMode buildMode, p *Package, looksha
case modeInstall: case modeInstall:
a.f = (*builder).install a.f = (*builder).install
a.deps = []*action{b.action1(modeBuild, depMode, p, lookshared, forShlib)} a.deps = []*action{b.action1(modeBuild, depMode, p, lookshared, forShlib)}
a.target = a.p.target a.target = a.p.Internal.Target
// Install header for cgo in c-archive and c-shared modes. // Install header for cgo in c-archive and c-shared modes.
if p.usesCgo() && (cfg.BuildBuildmode == "c-archive" || cfg.BuildBuildmode == "c-shared") { if p.UsesCgo() && (cfg.BuildBuildmode == "c-archive" || cfg.BuildBuildmode == "c-shared") {
hdrTarget := a.target[:len(a.target)-len(filepath.Ext(a.target))] + ".h" hdrTarget := a.target[:len(a.target)-len(filepath.Ext(a.target))] + ".h"
if cfg.BuildContext.Compiler == "gccgo" { if cfg.BuildContext.Compiler == "gccgo" {
// For the header file, remove the "lib" // For the header file, remove the "lib"
...@@ -1056,15 +963,15 @@ func (b *builder) action1(mode buildMode, depMode buildMode, p *Package, looksha ...@@ -1056,15 +963,15 @@ func (b *builder) action1(mode buildMode, depMode buildMode, p *Package, looksha
// naming conflicts. The only possible conflict is if we were // naming conflicts. The only possible conflict is if we were
// to create a top-level package named exe. // to create a top-level package named exe.
name := "a.out" name := "a.out"
if p.exeName != "" { if p.Internal.ExeName != "" {
name = p.exeName name = p.Internal.ExeName
} else if cfg.Goos == "darwin" && cfg.BuildBuildmode == "c-shared" && p.target != "" { } else if cfg.Goos == "darwin" && cfg.BuildBuildmode == "c-shared" && p.Internal.Target != "" {
// On OS X, the linker output name gets recorded in the // On OS X, the linker output name gets recorded in the
// shared library's LC_ID_DYLIB load command. // shared library's LC_ID_DYLIB load command.
// The code invoking the linker knows to pass only the final // The code invoking the linker knows to pass only the final
// path element. Arrange that the path element matches what // path element. Arrange that the path element matches what
// we'll install it as; otherwise the library is only loadable as "a.out". // we'll install it as; otherwise the library is only loadable as "a.out".
_, name = filepath.Split(p.target) _, name = filepath.Split(p.Internal.Target)
} }
a.target = a.objdir + filepath.Join("exe", name) + cfg.ExeSuffix a.target = a.objdir + filepath.Join("exe", name) + cfg.ExeSuffix
} }
...@@ -1073,7 +980,7 @@ func (b *builder) action1(mode buildMode, depMode buildMode, p *Package, looksha ...@@ -1073,7 +980,7 @@ func (b *builder) action1(mode buildMode, depMode buildMode, p *Package, looksha
return a return a
} }
func (b *builder) libaction(libname string, pkgs []*Package, mode, depMode buildMode) *action { func (b *builder) libaction(libname string, pkgs []*load.Package, mode, depMode buildMode) *action {
a := &action{} a := &action{}
switch mode { switch mode {
default: default:
...@@ -1083,7 +990,7 @@ func (b *builder) libaction(libname string, pkgs []*Package, mode, depMode build ...@@ -1083,7 +990,7 @@ func (b *builder) libaction(libname string, pkgs []*Package, mode, depMode build
a.f = (*builder).linkShared a.f = (*builder).linkShared
a.target = filepath.Join(b.work, libname) a.target = filepath.Join(b.work, libname)
for _, p := range pkgs { for _, p := range pkgs {
if p.target == "" { if p.Internal.Target == "" {
continue continue
} }
a.deps = append(a.deps, b.action(depMode, depMode, p)) a.deps = append(a.deps, b.action(depMode, depMode, p))
...@@ -1101,18 +1008,18 @@ func (b *builder) libaction(libname string, pkgs []*Package, mode, depMode build ...@@ -1101,18 +1008,18 @@ func (b *builder) libaction(libname string, pkgs []*Package, mode, depMode build
seencgo = seencgo || (p.Standard && p.ImportPath == "runtime/cgo") seencgo = seencgo || (p.Standard && p.ImportPath == "runtime/cgo")
} }
if !seencgo { if !seencgo {
var stk importStack var stk load.ImportStack
p := loadPackage("runtime/cgo", &stk) p := load.LoadPackage("runtime/cgo", &stk)
if p.Error != nil { if p.Error != nil {
base.Fatalf("load runtime/cgo: %v", p.Error) base.Fatalf("load runtime/cgo: %v", p.Error)
} }
computeStale(p) load.ComputeStale(p)
// If runtime/cgo is in another shared library, then that's // If runtime/cgo is in another shared library, then that's
// also the shared library that contains runtime, so // also the shared library that contains runtime, so
// something will depend on it and so runtime/cgo's staleness // something will depend on it and so runtime/cgo's staleness
// will be checked when processing that library. // will be checked when processing that library.
if p.Shlib == "" || p.Shlib == libname { if p.Shlib == "" || p.Shlib == libname {
pkgs = append([]*Package{}, pkgs...) pkgs = append([]*load.Package{}, pkgs...)
pkgs = append(pkgs, p) pkgs = append(pkgs, p)
} }
} }
...@@ -1122,18 +1029,18 @@ func (b *builder) libaction(libname string, pkgs []*Package, mode, depMode build ...@@ -1122,18 +1029,18 @@ func (b *builder) libaction(libname string, pkgs []*Package, mode, depMode build
seenmath = seenmath || (p.Standard && p.ImportPath == "math") seenmath = seenmath || (p.Standard && p.ImportPath == "math")
} }
if !seenmath { if !seenmath {
var stk importStack var stk load.ImportStack
p := loadPackage("math", &stk) p := load.LoadPackage("math", &stk)
if p.Error != nil { if p.Error != nil {
base.Fatalf("load math: %v", p.Error) base.Fatalf("load math: %v", p.Error)
} }
computeStale(p) load.ComputeStale(p)
// If math is in another shared library, then that's // If math is in another shared library, then that's
// also the shared library that contains runtime, so // also the shared library that contains runtime, so
// something will depend on it and so math's staleness // something will depend on it and so math's staleness
// will be checked when processing that library. // will be checked when processing that library.
if p.Shlib == "" || p.Shlib == libname { if p.Shlib == "" || p.Shlib == libname {
pkgs = append([]*Package{}, pkgs...) pkgs = append([]*load.Package{}, pkgs...)
pkgs = append(pkgs, p) pkgs = append(pkgs, p)
} }
} }
...@@ -1143,7 +1050,7 @@ func (b *builder) libaction(libname string, pkgs []*Package, mode, depMode build ...@@ -1143,7 +1050,7 @@ func (b *builder) libaction(libname string, pkgs []*Package, mode, depMode build
// Figure out where the library will go. // Figure out where the library will go.
var libdir string var libdir string
for _, p := range pkgs { for _, p := range pkgs {
plibdir := p.build.PkgTargetRoot plibdir := p.Internal.Build.PkgTargetRoot
if gccgo { if gccgo {
plibdir = filepath.Join(plibdir, "shlibs") plibdir = filepath.Join(plibdir, "shlibs")
} }
...@@ -1162,11 +1069,11 @@ func (b *builder) libaction(libname string, pkgs []*Package, mode, depMode build ...@@ -1162,11 +1069,11 @@ func (b *builder) libaction(libname string, pkgs []*Package, mode, depMode build
built = fi.ModTime() built = fi.ModTime()
} }
for _, p := range pkgs { for _, p := range pkgs {
if p.target == "" { if p.Internal.Target == "" {
continue continue
} }
stale = stale || p.Stale stale = stale || p.Stale
lstat, err := os.Stat(p.target) lstat, err := os.Stat(p.Internal.Target)
if err != nil || lstat.ModTime().After(built) { if err != nil || lstat.ModTime().After(built) {
stale = true stale = true
} }
...@@ -1178,12 +1085,12 @@ func (b *builder) libaction(libname string, pkgs []*Package, mode, depMode build ...@@ -1178,12 +1085,12 @@ func (b *builder) libaction(libname string, pkgs []*Package, mode, depMode build
buildAction := b.libaction(libname, pkgs, modeBuild, depMode) buildAction := b.libaction(libname, pkgs, modeBuild, depMode)
a.deps = []*action{buildAction} a.deps = []*action{buildAction}
for _, p := range pkgs { for _, p := range pkgs {
if p.target == "" { if p.Internal.Target == "" {
continue continue
} }
shlibnameaction := &action{} shlibnameaction := &action{}
shlibnameaction.f = (*builder).installShlibname shlibnameaction.f = (*builder).installShlibname
shlibnameaction.target = p.target[:len(p.target)-2] + ".shlibname" shlibnameaction.target = p.Internal.Target[:len(p.Internal.Target)-2] + ".shlibname"
a.deps = append(a.deps, shlibnameaction) a.deps = append(a.deps, shlibnameaction)
shlibnameaction.deps = append(shlibnameaction.deps, buildAction) shlibnameaction.deps = append(shlibnameaction.deps, buildAction)
} }
...@@ -1362,17 +1269,17 @@ func (b *builder) build(a *action) (err error) { ...@@ -1362,17 +1269,17 @@ func (b *builder) build(a *action) (err error) {
// Return an error if the package has CXX files but it's not using // Return an error if the package has CXX files but it's not using
// cgo nor SWIG, since the CXX files can only be processed by cgo // cgo nor SWIG, since the CXX files can only be processed by cgo
// and SWIG. // and SWIG.
if len(a.p.CXXFiles) > 0 && !a.p.usesCgo() && !a.p.usesSwig() { if len(a.p.CXXFiles) > 0 && !a.p.UsesCgo() && !a.p.UsesSwig() {
return fmt.Errorf("can't build package %s because it contains C++ files (%s) but it's not using cgo nor SWIG", return fmt.Errorf("can't build package %s because it contains C++ files (%s) but it's not using cgo nor SWIG",
a.p.ImportPath, strings.Join(a.p.CXXFiles, ",")) a.p.ImportPath, strings.Join(a.p.CXXFiles, ","))
} }
// Same as above for Objective-C files // Same as above for Objective-C files
if len(a.p.MFiles) > 0 && !a.p.usesCgo() && !a.p.usesSwig() { if len(a.p.MFiles) > 0 && !a.p.UsesCgo() && !a.p.UsesSwig() {
return fmt.Errorf("can't build package %s because it contains Objective-C files (%s) but it's not using cgo nor SWIG", return fmt.Errorf("can't build package %s because it contains Objective-C files (%s) but it's not using cgo nor SWIG",
a.p.ImportPath, strings.Join(a.p.MFiles, ",")) a.p.ImportPath, strings.Join(a.p.MFiles, ","))
} }
// Same as above for Fortran files // Same as above for Fortran files
if len(a.p.FFiles) > 0 && !a.p.usesCgo() && !a.p.usesSwig() { if len(a.p.FFiles) > 0 && !a.p.UsesCgo() && !a.p.UsesSwig() {
return fmt.Errorf("can't build package %s because it contains Fortran files (%s) but it's not using cgo nor SWIG", return fmt.Errorf("can't build package %s because it contains Fortran files (%s) but it's not using cgo nor SWIG",
a.p.ImportPath, strings.Join(a.p.FFiles, ",")) a.p.ImportPath, strings.Join(a.p.FFiles, ","))
} }
...@@ -1417,7 +1324,7 @@ func (b *builder) build(a *action) (err error) { ...@@ -1417,7 +1324,7 @@ func (b *builder) build(a *action) (err error) {
sfiles = append(sfiles, a.p.SFiles...) sfiles = append(sfiles, a.p.SFiles...)
cxxfiles = append(cxxfiles, a.p.CXXFiles...) cxxfiles = append(cxxfiles, a.p.CXXFiles...)
if a.p.usesCgo() || a.p.usesSwig() { if a.p.UsesCgo() || a.p.UsesSwig() {
if pcCFLAGS, pcLDFLAGS, err = b.getPkgConfigFlags(a.p); err != nil { if pcCFLAGS, pcLDFLAGS, err = b.getPkgConfigFlags(a.p); err != nil {
return return
} }
...@@ -1426,7 +1333,7 @@ func (b *builder) build(a *action) (err error) { ...@@ -1426,7 +1333,7 @@ func (b *builder) build(a *action) (err error) {
// Run SWIG on each .swig and .swigcxx file. // Run SWIG on each .swig and .swigcxx file.
// Each run will generate two files, a .go file and a .c or .cxx file. // Each run will generate two files, a .go file and a .c or .cxx file.
// The .go file will use import "C" and is to be processed by cgo. // The .go file will use import "C" and is to be processed by cgo.
if a.p.usesSwig() { if a.p.UsesSwig() {
outGo, outC, outCXX, err := b.swig(a.p, obj, pcCFLAGS) outGo, outC, outCXX, err := b.swig(a.p, obj, pcCFLAGS)
if err != nil { if err != nil {
return err return err
...@@ -1437,7 +1344,7 @@ func (b *builder) build(a *action) (err error) { ...@@ -1437,7 +1344,7 @@ func (b *builder) build(a *action) (err error) {
} }
// Run cgo. // Run cgo.
if a.p.usesCgo() || a.p.usesSwig() { if a.p.UsesCgo() || a.p.UsesSwig() {
// In a package using cgo, cgo compiles the C, C++ and assembly files with gcc. // In a package using cgo, cgo compiles the C, C++ and assembly files with gcc.
// There is one exception: runtime/cgo's job is to bridge the // There is one exception: runtime/cgo's job is to bridge the
// cgo and non-cgo worlds, so it necessarily has files in both. // cgo and non-cgo worlds, so it necessarily has files in both.
...@@ -1482,7 +1389,7 @@ func (b *builder) build(a *action) (err error) { ...@@ -1482,7 +1389,7 @@ func (b *builder) build(a *action) (err error) {
} }
// If we're doing coverage, preprocess the .go files and put them in the work directory // If we're doing coverage, preprocess the .go files and put them in the work directory
if a.p.coverMode != "" { if a.p.Internal.CoverMode != "" {
for i, file := range gofiles { for i, file := range gofiles {
var sourceFile string var sourceFile string
var coverFile string var coverFile string
...@@ -1498,7 +1405,7 @@ func (b *builder) build(a *action) (err error) { ...@@ -1498,7 +1405,7 @@ func (b *builder) build(a *action) (err error) {
coverFile = filepath.Join(obj, file) coverFile = filepath.Join(obj, file)
key = file key = file
} }
cover := a.p.coverVars[key] cover := a.p.Internal.CoverVars[key]
if cover == nil || isTestFile(file) { if cover == nil || isTestFile(file) {
// Not covering this file. // Not covering this file.
continue continue
...@@ -1648,7 +1555,7 @@ func splitPkgConfigOutput(out []byte) []string { ...@@ -1648,7 +1555,7 @@ func splitPkgConfigOutput(out []byte) []string {
} }
// Calls pkg-config if needed and returns the cflags/ldflags needed to build the package. // Calls pkg-config if needed and returns the cflags/ldflags needed to build the package.
func (b *builder) getPkgConfigFlags(p *Package) (cflags, ldflags []string, err error) { func (b *builder) getPkgConfigFlags(p *load.Package) (cflags, ldflags []string, err error) {
if pkgs := p.CgoPkgConfig; len(pkgs) > 0 { if pkgs := p.CgoPkgConfig; len(pkgs) > 0 {
var out []byte var out []byte
out, err = b.runOut(p.Dir, p.ImportPath, nil, b.pkgconfigCmd(), "--cflags", pkgs) out, err = b.runOut(p.Dir, p.ImportPath, nil, b.pkgconfigCmd(), "--cflags", pkgs)
...@@ -1735,9 +1642,9 @@ func (b *builder) install(a *action) (err error) { ...@@ -1735,9 +1642,9 @@ func (b *builder) install(a *action) (err error) {
func (b *builder) includeArgs(flag string, all []*action) []string { func (b *builder) includeArgs(flag string, all []*action) []string {
inc := []string{} inc := []string{}
incMap := map[string]bool{ incMap := map[string]bool{
b.work: true, // handled later b.work: true, // handled later
gorootPkg: true, cfg.GOROOTpkg: true,
"": true, // ignore empty strings "": true, // ignore empty strings
} }
// Look in the temporary space for results of test-specific actions. // Look in the temporary space for results of test-specific actions.
...@@ -1747,7 +1654,7 @@ func (b *builder) includeArgs(flag string, all []*action) []string { ...@@ -1747,7 +1654,7 @@ func (b *builder) includeArgs(flag string, all []*action) []string {
if a1.p == nil { if a1.p == nil {
continue continue
} }
if dir := a1.pkgdir; dir != a1.p.build.PkgRoot && !incMap[dir] { if dir := a1.pkgdir; dir != a1.p.Internal.Build.PkgRoot && !incMap[dir] {
incMap[dir] = true incMap[dir] = true
inc = append(inc, flag, dir) inc = append(inc, flag, dir)
} }
...@@ -1762,8 +1669,8 @@ func (b *builder) includeArgs(flag string, all []*action) []string { ...@@ -1762,8 +1669,8 @@ func (b *builder) includeArgs(flag string, all []*action) []string {
// in the original GOPATH order. // in the original GOPATH order.
need := map[string]*build.Package{} need := map[string]*build.Package{}
for _, a1 := range all { for _, a1 := range all {
if a1.p != nil && a1.pkgdir == a1.p.build.PkgRoot { if a1.p != nil && a1.pkgdir == a1.p.Internal.Build.PkgRoot {
need[a1.p.build.Root] = a1.p.build need[a1.p.Internal.Build.Root] = a1.p.Internal.Build
} }
} }
for _, root := range cfg.Gopath { for _, root := range cfg.Gopath {
...@@ -1778,9 +1685,9 @@ func (b *builder) includeArgs(flag string, all []*action) []string { ...@@ -1778,9 +1685,9 @@ func (b *builder) includeArgs(flag string, all []*action) []string {
if a1.p == nil { if a1.p == nil {
continue continue
} }
if dir := a1.pkgdir; dir == a1.p.build.PkgRoot && !incMap[dir] { if dir := a1.pkgdir; dir == a1.p.Internal.Build.PkgRoot && !incMap[dir] {
incMap[dir] = true incMap[dir] = true
inc = append(inc, flag, a1.p.build.PkgTargetRoot) inc = append(inc, flag, a1.p.Internal.Build.PkgTargetRoot)
} }
} }
...@@ -1910,7 +1817,7 @@ func (b *builder) cover(a *action, dst, src string, perm os.FileMode, varName st ...@@ -1910,7 +1817,7 @@ func (b *builder) cover(a *action, dst, src string, perm os.FileMode, varName st
return b.run(a.objdir, "cover "+a.p.ImportPath, nil, return b.run(a.objdir, "cover "+a.p.ImportPath, nil,
cfg.BuildToolexec, cfg.BuildToolexec,
base.Tool("cover"), base.Tool("cover"),
"-mode", a.p.coverMode, "-mode", a.p.Internal.CoverMode,
"-var", varName, "-var", varName,
"-o", dst, "-o", dst,
src) src)
...@@ -2218,19 +2125,19 @@ func mkAbs(dir, f string) string { ...@@ -2218,19 +2125,19 @@ func mkAbs(dir, f string) string {
type toolchain interface { type toolchain interface {
// gc runs the compiler in a specific directory on a set of files // gc runs the compiler in a specific directory on a set of files
// and returns the name of the generated output file. // and returns the name of the generated output file.
gc(b *builder, p *Package, archive, obj string, asmhdr bool, importArgs []string, gofiles []string) (ofile string, out []byte, err error) gc(b *builder, p *load.Package, archive, obj string, asmhdr bool, importArgs []string, gofiles []string) (ofile string, out []byte, err error)
// cc runs the toolchain's C compiler in a directory on a C file // cc runs the toolchain's C compiler in a directory on a C file
// to produce an output file. // to produce an output file.
cc(b *builder, p *Package, objdir, ofile, cfile string) error cc(b *builder, p *load.Package, objdir, ofile, cfile string) error
// asm runs the assembler in a specific directory on specific files // asm runs the assembler in a specific directory on specific files
// and returns a list of named output files. // and returns a list of named output files.
asm(b *builder, p *Package, obj string, sfiles []string) ([]string, error) asm(b *builder, p *load.Package, obj string, sfiles []string) ([]string, error)
// pkgpath builds an appropriate path for a temporary package file. // pkgpath builds an appropriate path for a temporary package file.
pkgpath(basedir string, p *Package) string pkgpath(basedir string, p *load.Package) string
// pack runs the archive packer in a specific directory to create // pack runs the archive packer in a specific directory to create
// an archive from a set of object files. // an archive from a set of object files.
// typically it is run in the object directory. // typically it is run in the object directory.
pack(b *builder, p *Package, objDir, afile string, ofiles []string) error pack(b *builder, p *load.Package, objDir, afile string, ofiles []string) error
// ld runs the linker to create an executable starting at mainpkg. // ld runs the linker to create an executable starting at mainpkg.
ld(b *builder, root *action, out string, allactions []*action, mainpkg string, ofiles []string) error ld(b *builder, root *action, out string, allactions []*action, mainpkg string, ofiles []string) error
// ldShared runs the linker to create a shared library containing the pkgs built by toplevelactions // ldShared runs the linker to create a shared library containing the pkgs built by toplevelactions
...@@ -2257,20 +2164,20 @@ func (noToolchain) linker() string { ...@@ -2257,20 +2164,20 @@ func (noToolchain) linker() string {
return "" return ""
} }
func (noToolchain) gc(b *builder, p *Package, archive, obj string, asmhdr bool, importArgs []string, gofiles []string) (ofile string, out []byte, err error) { func (noToolchain) gc(b *builder, p *load.Package, archive, obj string, asmhdr bool, importArgs []string, gofiles []string) (ofile string, out []byte, err error) {
return "", nil, noCompiler() return "", nil, noCompiler()
} }
func (noToolchain) asm(b *builder, p *Package, obj string, sfiles []string) ([]string, error) { func (noToolchain) asm(b *builder, p *load.Package, obj string, sfiles []string) ([]string, error) {
return nil, noCompiler() return nil, noCompiler()
} }
func (noToolchain) pkgpath(basedir string, p *Package) string { func (noToolchain) pkgpath(basedir string, p *load.Package) string {
noCompiler() noCompiler()
return "" return ""
} }
func (noToolchain) pack(b *builder, p *Package, objDir, afile string, ofiles []string) error { func (noToolchain) pack(b *builder, p *load.Package, objDir, afile string, ofiles []string) error {
return noCompiler() return noCompiler()
} }
...@@ -2282,7 +2189,7 @@ func (noToolchain) ldShared(b *builder, toplevelactions []*action, out string, a ...@@ -2282,7 +2189,7 @@ func (noToolchain) ldShared(b *builder, toplevelactions []*action, out string, a
return noCompiler() return noCompiler()
} }
func (noToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error { func (noToolchain) cc(b *builder, p *load.Package, objdir, ofile, cfile string) error {
return noCompiler() return noCompiler()
} }
...@@ -2297,7 +2204,7 @@ func (gcToolchain) linker() string { ...@@ -2297,7 +2204,7 @@ func (gcToolchain) linker() string {
return base.Tool("link") return base.Tool("link")
} }
func (gcToolchain) gc(b *builder, p *Package, archive, obj string, asmhdr bool, importArgs []string, gofiles []string) (ofile string, output []byte, err error) { func (gcToolchain) gc(b *builder, p *load.Package, archive, obj string, asmhdr bool, importArgs []string, gofiles []string) (ofile string, output []byte, err error) {
if archive != "" { if archive != "" {
ofile = archive ofile = archive
} else { } else {
...@@ -2332,8 +2239,8 @@ func (gcToolchain) gc(b *builder, p *Package, archive, obj string, asmhdr bool, ...@@ -2332,8 +2239,8 @@ func (gcToolchain) gc(b *builder, p *Package, archive, obj string, asmhdr bool,
if cfg.BuildContext.InstallSuffix != "" { if cfg.BuildContext.InstallSuffix != "" {
gcargs = append(gcargs, "-installsuffix", cfg.BuildContext.InstallSuffix) gcargs = append(gcargs, "-installsuffix", cfg.BuildContext.InstallSuffix)
} }
if p.buildID != "" { if p.Internal.BuildID != "" {
gcargs = append(gcargs, "-buildid", p.buildID) gcargs = append(gcargs, "-buildid", p.Internal.BuildID)
} }
for _, path := range p.Imports { for _, path := range p.Imports {
...@@ -2344,7 +2251,7 @@ func (gcToolchain) gc(b *builder, p *Package, archive, obj string, asmhdr bool, ...@@ -2344,7 +2251,7 @@ func (gcToolchain) gc(b *builder, p *Package, archive, obj string, asmhdr bool,
} }
} }
args := []interface{}{cfg.BuildToolexec, base.Tool("compile"), "-o", ofile, "-trimpath", b.work, buildGcflags, gcargs, "-D", p.localPrefix, importArgs} args := []interface{}{cfg.BuildToolexec, base.Tool("compile"), "-o", ofile, "-trimpath", b.work, buildGcflags, gcargs, "-D", p.Internal.LocalPrefix, importArgs}
if ofile == archive { if ofile == archive {
args = append(args, "-pack") args = append(args, "-pack")
} }
...@@ -2359,9 +2266,9 @@ func (gcToolchain) gc(b *builder, p *Package, archive, obj string, asmhdr bool, ...@@ -2359,9 +2266,9 @@ func (gcToolchain) gc(b *builder, p *Package, archive, obj string, asmhdr bool,
return ofile, output, err return ofile, output, err
} }
func (gcToolchain) asm(b *builder, p *Package, obj string, sfiles []string) ([]string, error) { func (gcToolchain) asm(b *builder, p *load.Package, obj string, sfiles []string) ([]string, error) {
// Add -I pkg/GOOS_GOARCH so #include "textflag.h" works in .s files. // Add -I pkg/GOOS_GOARCH so #include "textflag.h" works in .s files.
inc := filepath.Join(goroot, "pkg", "include") inc := filepath.Join(cfg.GOROOT, "pkg", "include")
args := []interface{}{cfg.BuildToolexec, base.Tool("asm"), "-trimpath", b.work, "-I", obj, "-I", inc, "-D", "GOOS_" + cfg.Goos, "-D", "GOARCH_" + cfg.Goarch, buildAsmflags} args := []interface{}{cfg.BuildToolexec, base.Tool("asm"), "-trimpath", b.work, "-I", obj, "-I", inc, "-D", "GOOS_" + cfg.Goos, "-D", "GOARCH_" + cfg.Goarch, buildAsmflags}
if p.ImportPath == "runtime" && cfg.Goarch == "386" { if p.ImportPath == "runtime" && cfg.Goarch == "386" {
for _, arg := range buildAsmflags { for _, arg := range buildAsmflags {
...@@ -2385,7 +2292,7 @@ func (gcToolchain) asm(b *builder, p *Package, obj string, sfiles []string) ([]s ...@@ -2385,7 +2292,7 @@ func (gcToolchain) asm(b *builder, p *Package, obj string, sfiles []string) ([]s
// toolVerify checks that the command line args writes the same output file // toolVerify checks that the command line args writes the same output file
// if run using newTool instead. // if run using newTool instead.
// Unused now but kept around for future use. // Unused now but kept around for future use.
func toolVerify(b *builder, p *Package, newTool string, ofile string, args []interface{}) error { func toolVerify(b *builder, p *load.Package, newTool string, ofile string, args []interface{}) error {
newArgs := make([]interface{}, len(args)) newArgs := make([]interface{}, len(args))
copy(newArgs, args) copy(newArgs, args)
newArgs[1] = base.Tool(newTool) newArgs[1] = base.Tool(newTool)
...@@ -2408,12 +2315,12 @@ func toolVerify(b *builder, p *Package, newTool string, ofile string, args []int ...@@ -2408,12 +2315,12 @@ func toolVerify(b *builder, p *Package, newTool string, ofile string, args []int
return nil return nil
} }
func (gcToolchain) pkgpath(basedir string, p *Package) string { func (gcToolchain) pkgpath(basedir string, p *load.Package) string {
end := filepath.FromSlash(p.ImportPath + ".a") end := filepath.FromSlash(p.ImportPath + ".a")
return filepath.Join(basedir, end) return filepath.Join(basedir, end)
} }
func (gcToolchain) pack(b *builder, p *Package, objDir, afile string, ofiles []string) error { func (gcToolchain) pack(b *builder, p *load.Package, objDir, afile string, ofiles []string) error {
var absOfiles []string var absOfiles []string
for _, f := range ofiles { for _, f := range ofiles {
absOfiles = append(absOfiles, mkAbs(objDir, f)) absOfiles = append(absOfiles, mkAbs(objDir, f))
...@@ -2534,13 +2441,13 @@ func (gcToolchain) ld(b *builder, root *action, out string, allactions []*action ...@@ -2534,13 +2441,13 @@ func (gcToolchain) ld(b *builder, root *action, out string, allactions []*action
if cfg.BuildContext.InstallSuffix != "" { if cfg.BuildContext.InstallSuffix != "" {
ldflags = append(ldflags, "-installsuffix", cfg.BuildContext.InstallSuffix) ldflags = append(ldflags, "-installsuffix", cfg.BuildContext.InstallSuffix)
} }
if root.p.omitDWARF { if root.p.Internal.OmitDWARF {
ldflags = append(ldflags, "-w") ldflags = append(ldflags, "-w")
} }
if cfg.BuildBuildmode == "plugin" { if cfg.BuildBuildmode == "plugin" {
pluginpath := root.p.ImportPath pluginpath := root.p.ImportPath
if pluginpath == "command-line-arguments" { if pluginpath == "command-line-arguments" {
pluginpath = "plugin/unnamed-" + root.p.buildID pluginpath = "plugin/unnamed-" + root.p.Internal.BuildID
} }
ldflags = append(ldflags, "-pluginpath", pluginpath) ldflags = append(ldflags, "-pluginpath", pluginpath)
} }
...@@ -2557,8 +2464,8 @@ func (gcToolchain) ld(b *builder, root *action, out string, allactions []*action ...@@ -2557,8 +2464,8 @@ func (gcToolchain) ld(b *builder, root *action, out string, allactions []*action
} }
ldflags = setextld(ldflags, compiler) ldflags = setextld(ldflags, compiler)
ldflags = append(ldflags, "-buildmode="+ldBuildmode) ldflags = append(ldflags, "-buildmode="+ldBuildmode)
if root.p.buildID != "" { if root.p.Internal.BuildID != "" {
ldflags = append(ldflags, "-buildid="+root.p.buildID) ldflags = append(ldflags, "-buildid="+root.p.Internal.BuildID)
} }
ldflags = append(ldflags, cfg.BuildLdflags...) ldflags = append(ldflags, cfg.BuildLdflags...)
...@@ -2608,7 +2515,7 @@ func (gcToolchain) ldShared(b *builder, toplevelactions []*action, out string, a ...@@ -2608,7 +2515,7 @@ func (gcToolchain) ldShared(b *builder, toplevelactions []*action, out string, a
return b.run(".", out, nil, cfg.BuildToolexec, base.Tool("link"), "-o", out, importArgs, ldflags) return b.run(".", out, nil, cfg.BuildToolexec, base.Tool("link"), "-o", out, importArgs, ldflags)
} }
func (gcToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error { func (gcToolchain) cc(b *builder, p *load.Package, objdir, ofile, cfile string) error {
return fmt.Errorf("%s: C source files not supported without cgo", mkAbs(p.Dir, cfile)) return fmt.Errorf("%s: C source files not supported without cgo", mkAbs(p.Dir, cfile))
} }
...@@ -2633,7 +2540,7 @@ func (gccgoToolchain) linker() string { ...@@ -2633,7 +2540,7 @@ func (gccgoToolchain) linker() string {
return gccgoBin return gccgoBin
} }
func (tools gccgoToolchain) gc(b *builder, p *Package, archive, obj string, asmhdr bool, importArgs []string, gofiles []string) (ofile string, output []byte, err error) { func (tools gccgoToolchain) gc(b *builder, p *load.Package, archive, obj string, asmhdr bool, importArgs []string, gofiles []string) (ofile string, output []byte, err error) {
out := "_go_.o" out := "_go_.o"
ofile = obj + out ofile = obj + out
gcargs := []string{"-g"} gcargs := []string{"-g"}
...@@ -2641,8 +2548,8 @@ func (tools gccgoToolchain) gc(b *builder, p *Package, archive, obj string, asmh ...@@ -2641,8 +2548,8 @@ func (tools gccgoToolchain) gc(b *builder, p *Package, archive, obj string, asmh
if pkgpath := gccgoPkgpath(p); pkgpath != "" { if pkgpath := gccgoPkgpath(p); pkgpath != "" {
gcargs = append(gcargs, "-fgo-pkgpath="+pkgpath) gcargs = append(gcargs, "-fgo-pkgpath="+pkgpath)
} }
if p.localPrefix != "" { if p.Internal.LocalPrefix != "" {
gcargs = append(gcargs, "-fgo-relative-import-path="+p.localPrefix) gcargs = append(gcargs, "-fgo-relative-import-path="+p.Internal.LocalPrefix)
} }
args := str.StringList(tools.compiler(), importArgs, "-c", gcargs, "-o", ofile, buildGccgoflags) args := str.StringList(tools.compiler(), importArgs, "-c", gcargs, "-o", ofile, buildGccgoflags)
for _, f := range gofiles { for _, f := range gofiles {
...@@ -2653,7 +2560,7 @@ func (tools gccgoToolchain) gc(b *builder, p *Package, archive, obj string, asmh ...@@ -2653,7 +2560,7 @@ func (tools gccgoToolchain) gc(b *builder, p *Package, archive, obj string, asmh
return ofile, output, err return ofile, output, err
} }
func (tools gccgoToolchain) asm(b *builder, p *Package, obj string, sfiles []string) ([]string, error) { func (tools gccgoToolchain) asm(b *builder, p *load.Package, obj string, sfiles []string) ([]string, error) {
var ofiles []string var ofiles []string
for _, sfile := range sfiles { for _, sfile := range sfiles {
ofile := obj + sfile[:len(sfile)-len(".s")] + ".o" ofile := obj + sfile[:len(sfile)-len(".s")] + ".o"
...@@ -2673,14 +2580,14 @@ func (tools gccgoToolchain) asm(b *builder, p *Package, obj string, sfiles []str ...@@ -2673,14 +2580,14 @@ func (tools gccgoToolchain) asm(b *builder, p *Package, obj string, sfiles []str
return ofiles, nil return ofiles, nil
} }
func (gccgoToolchain) pkgpath(basedir string, p *Package) string { func (gccgoToolchain) pkgpath(basedir string, p *load.Package) string {
end := filepath.FromSlash(p.ImportPath + ".a") end := filepath.FromSlash(p.ImportPath + ".a")
afile := filepath.Join(basedir, end) afile := filepath.Join(basedir, end)
// add "lib" to the final element // add "lib" to the final element
return filepath.Join(filepath.Dir(afile), "lib"+filepath.Base(afile)) return filepath.Join(filepath.Dir(afile), "lib"+filepath.Base(afile))
} }
func (gccgoToolchain) pack(b *builder, p *Package, objDir, afile string, ofiles []string) error { func (gccgoToolchain) pack(b *builder, p *load.Package, objDir, afile string, ofiles []string) error {
var absOfiles []string var absOfiles []string
for _, f := range ofiles { for _, f := range ofiles {
absOfiles = append(absOfiles, mkAbs(objDir, f)) absOfiles = append(absOfiles, mkAbs(objDir, f))
...@@ -2792,7 +2699,7 @@ func (tools gccgoToolchain) link(b *builder, root *action, out string, allaction ...@@ -2792,7 +2699,7 @@ func (tools gccgoToolchain) link(b *builder, root *action, out string, allaction
if !apackagePathsSeen[a.p.ImportPath] { if !apackagePathsSeen[a.p.ImportPath] {
apackagePathsSeen[a.p.ImportPath] = true apackagePathsSeen[a.p.ImportPath] = true
target := a.target target := a.target
if len(a.p.CgoFiles) > 0 || a.p.usesSwig() { if len(a.p.CgoFiles) > 0 || a.p.UsesSwig() {
target, err = readAndRemoveCgoFlags(target) target, err = readAndRemoveCgoFlags(target)
if err != nil { if err != nil {
return return
...@@ -2833,7 +2740,7 @@ func (tools gccgoToolchain) link(b *builder, root *action, out string, allaction ...@@ -2833,7 +2740,7 @@ func (tools gccgoToolchain) link(b *builder, root *action, out string, allaction
if len(a.p.CgoFiles) > 0 { if len(a.p.CgoFiles) > 0 {
usesCgo = true usesCgo = true
} }
if a.p.usesSwig() { if a.p.UsesSwig() {
usesCgo = true usesCgo = true
} }
if len(a.p.CXXFiles) > 0 || len(a.p.SwigCXXFiles) > 0 { if len(a.p.CXXFiles) > 0 || len(a.p.SwigCXXFiles) > 0 {
...@@ -2964,8 +2871,8 @@ func (tools gccgoToolchain) ldShared(b *builder, toplevelactions []*action, out ...@@ -2964,8 +2871,8 @@ func (tools gccgoToolchain) ldShared(b *builder, toplevelactions []*action, out
return tools.link(b, fakeRoot, out, allactions, "", nil, "shared", out) return tools.link(b, fakeRoot, out, allactions, "", nil, "shared", out)
} }
func (tools gccgoToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error { func (tools gccgoToolchain) cc(b *builder, p *load.Package, objdir, ofile, cfile string) error {
inc := filepath.Join(goroot, "pkg", "include") inc := filepath.Join(cfg.GOROOT, "pkg", "include")
cfile = mkAbs(p.Dir, cfile) cfile = mkAbs(p.Dir, cfile)
defs := []string{"-D", "GOOS_" + cfg.Goos, "-D", "GOARCH_" + cfg.Goarch} defs := []string{"-D", "GOOS_" + cfg.Goos, "-D", "GOARCH_" + cfg.Goarch}
defs = append(defs, b.gccArchArgs()...) defs = append(defs, b.gccArchArgs()...)
...@@ -2990,14 +2897,14 @@ func (tools gccgoToolchain) maybePIC(args []string) []string { ...@@ -2990,14 +2897,14 @@ func (tools gccgoToolchain) maybePIC(args []string) []string {
return args return args
} }
func gccgoPkgpath(p *Package) string { func gccgoPkgpath(p *load.Package) string {
if p.build.IsCommand() && !p.forceLibrary { if p.Internal.Build.IsCommand() && !p.Internal.ForceLibrary {
return "" return ""
} }
return p.ImportPath return p.ImportPath
} }
func gccgoCleanPkgpath(p *Package) string { func gccgoCleanPkgpath(p *load.Package) string {
clean := func(r rune) rune { clean := func(r rune) rune {
switch { switch {
case 'A' <= r && r <= 'Z', 'a' <= r && r <= 'z', case 'A' <= r && r <= 'Z', 'a' <= r && r <= 'z',
...@@ -3010,22 +2917,22 @@ func gccgoCleanPkgpath(p *Package) string { ...@@ -3010,22 +2917,22 @@ func gccgoCleanPkgpath(p *Package) string {
} }
// gcc runs the gcc C compiler to create an object from a single C file. // gcc runs the gcc C compiler to create an object from a single C file.
func (b *builder) gcc(p *Package, out string, flags []string, cfile string) error { func (b *builder) gcc(p *load.Package, out string, flags []string, cfile string) error {
return b.ccompile(p, out, flags, cfile, b.gccCmd(p.Dir)) return b.ccompile(p, out, flags, cfile, b.gccCmd(p.Dir))
} }
// gxx runs the g++ C++ compiler to create an object from a single C++ file. // gxx runs the g++ C++ compiler to create an object from a single C++ file.
func (b *builder) gxx(p *Package, out string, flags []string, cxxfile string) error { func (b *builder) gxx(p *load.Package, out string, flags []string, cxxfile string) error {
return b.ccompile(p, out, flags, cxxfile, b.gxxCmd(p.Dir)) return b.ccompile(p, out, flags, cxxfile, b.gxxCmd(p.Dir))
} }
// gfortran runs the gfortran Fortran compiler to create an object from a single Fortran file. // gfortran runs the gfortran Fortran compiler to create an object from a single Fortran file.
func (b *builder) gfortran(p *Package, out string, flags []string, ffile string) error { func (b *builder) gfortran(p *load.Package, out string, flags []string, ffile string) error {
return b.ccompile(p, out, flags, ffile, b.gfortranCmd(p.Dir)) return b.ccompile(p, out, flags, ffile, b.gfortranCmd(p.Dir))
} }
// ccompile runs the given C or C++ compiler and creates an object from a single source file. // ccompile runs the given C or C++ compiler and creates an object from a single source file.
func (b *builder) ccompile(p *Package, outfile string, flags []string, file string, compiler []string) error { func (b *builder) ccompile(p *load.Package, outfile string, flags []string, file string, compiler []string) error {
file = mkAbs(p.Dir, file) file = mkAbs(p.Dir, file)
desc := p.ImportPath desc := p.ImportPath
output, err := b.runOut(p.Dir, desc, nil, compiler, flags, "-o", outfile, "-c", file) output, err := b.runOut(p.Dir, desc, nil, compiler, flags, "-o", outfile, "-c", file)
...@@ -3041,7 +2948,7 @@ func (b *builder) ccompile(p *Package, outfile string, flags []string, file stri ...@@ -3041,7 +2948,7 @@ func (b *builder) ccompile(p *Package, outfile string, flags []string, file stri
} }
// gccld runs the gcc linker to create an executable from a set of object files. // gccld runs the gcc linker to create an executable from a set of object files.
func (b *builder) gccld(p *Package, out string, flags []string, obj []string) error { func (b *builder) gccld(p *load.Package, out string, flags []string, obj []string) error {
var cmd []string var cmd []string
if len(p.CXXFiles) > 0 || len(p.SwigCXXFiles) > 0 { if len(p.CXXFiles) > 0 || len(p.SwigCXXFiles) > 0 {
cmd = b.gxxCmd(p.Dir) cmd = b.gxxCmd(p.Dir)
...@@ -3193,7 +3100,7 @@ func envList(key, def string) []string { ...@@ -3193,7 +3100,7 @@ func envList(key, def string) []string {
} }
// Return the flags to use when invoking the C, C++ or Fortran compilers, or cgo. // Return the flags to use when invoking the C, C++ or Fortran compilers, or cgo.
func (b *builder) cflags(p *Package) (cppflags, cflags, cxxflags, fflags, ldflags []string) { func (b *builder) cflags(p *load.Package) (cppflags, cflags, cxxflags, fflags, ldflags []string) {
defaults := "-g -O2" defaults := "-g -O2"
cppflags = str.StringList(envList("CGO_CPPFLAGS", ""), p.CgoCPPFLAGS) cppflags = str.StringList(envList("CGO_CPPFLAGS", ""), p.CgoCPPFLAGS)
...@@ -3385,7 +3292,7 @@ func (b *builder) cgo(a *action, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofil ...@@ -3385,7 +3292,7 @@ func (b *builder) cgo(a *action, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofil
// dynimport creates a Go source file named importGo containing // dynimport creates a Go source file named importGo containing
// //go:cgo_import_dynamic directives for each symbol or library // //go:cgo_import_dynamic directives for each symbol or library
// dynamically imported by the object files outObj. // dynamically imported by the object files outObj.
func (b *builder) dynimport(p *Package, obj, importGo, cgoExe string, cflags, cgoLDFLAGS, outObj []string) error { func (b *builder) dynimport(p *load.Package, obj, importGo, cgoExe string, cflags, cgoLDFLAGS, outObj []string) error {
cfile := obj + "_cgo_main.c" cfile := obj + "_cgo_main.c"
ofile := obj + "_cgo_main.o" ofile := obj + "_cgo_main.o"
if err := b.gcc(p, ofile, cflags, cfile); err != nil { if err := b.gcc(p, ofile, cflags, cfile); err != nil {
...@@ -3414,7 +3321,7 @@ func (b *builder) dynimport(p *Package, obj, importGo, cgoExe string, cflags, cg ...@@ -3414,7 +3321,7 @@ func (b *builder) dynimport(p *Package, obj, importGo, cgoExe string, cflags, cg
// collect partially links the object files outObj into a single // collect partially links the object files outObj into a single
// relocatable object file named ofile. // relocatable object file named ofile.
func (b *builder) collect(p *Package, obj, ofile string, cgoLDFLAGS, outObj []string) error { func (b *builder) collect(p *load.Package, obj, ofile string, cgoLDFLAGS, outObj []string) error {
// When linking relocatable objects, various flags need to be // When linking relocatable objects, various flags need to be
// filtered out as they are inapplicable and can cause some linkers // filtered out as they are inapplicable and can cause some linkers
// to fail. // to fail.
...@@ -3474,7 +3381,7 @@ func (b *builder) collect(p *Package, obj, ofile string, cgoLDFLAGS, outObj []st ...@@ -3474,7 +3381,7 @@ func (b *builder) collect(p *Package, obj, ofile string, cgoLDFLAGS, outObj []st
// Run SWIG on all SWIG input files. // Run SWIG on all SWIG input files.
// TODO: Don't build a shared library, once SWIG emits the necessary // TODO: Don't build a shared library, once SWIG emits the necessary
// pragmas for external linking. // pragmas for external linking.
func (b *builder) swig(p *Package, obj string, pcCFLAGS []string) (outGo, outC, outCXX []string, err error) { func (b *builder) swig(p *load.Package, obj string, pcCFLAGS []string) (outGo, outC, outCXX []string, err error) {
if err := b.swigVersionCheck(); err != nil { if err := b.swigVersionCheck(); err != nil {
return nil, nil, nil, err return nil, nil, nil, err
} }
...@@ -3602,7 +3509,7 @@ func (b *builder) swigDoIntSize(obj string) (intsize string, err error) { ...@@ -3602,7 +3509,7 @@ func (b *builder) swigDoIntSize(obj string) (intsize string, err error) {
} }
srcs := []string{src} srcs := []string{src}
p := goFilesPackage(srcs) p := load.GoFilesPackage(srcs)
if _, _, e := buildToolchain.gc(b, p, "", obj, false, nil, srcs); e != nil { if _, _, e := buildToolchain.gc(b, p, "", obj, false, nil, srcs); e != nil {
return "32", nil return "32", nil
...@@ -3620,7 +3527,7 @@ func (b *builder) swigIntSize(obj string) (intsize string, err error) { ...@@ -3620,7 +3527,7 @@ func (b *builder) swigIntSize(obj string) (intsize string, err error) {
} }
// Run SWIG on one SWIG input file. // Run SWIG on one SWIG input file.
func (b *builder) swigOne(p *Package, file, obj string, pcCFLAGS []string, cxx bool, intgosize string) (outGo, outC string, err error) { func (b *builder) swigOne(p *load.Package, file, obj string, pcCFLAGS []string, cxx bool, intgosize string) (outGo, outC string, err error) {
cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, _, _ := b.cflags(p) cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, _, _ := b.cflags(p)
var cflags []string var cflags []string
if cxx { if cxx {
......
...@@ -5,8 +5,9 @@ ...@@ -5,8 +5,9 @@
package main package main
import ( import (
"cmd/go/internal/cfg"
"cmd/go/internal/base" "cmd/go/internal/base"
"cmd/go/internal/cfg"
"cmd/go/internal/load"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"os" "os"
...@@ -77,12 +78,12 @@ func init() { ...@@ -77,12 +78,12 @@ func init() {
} }
func runClean(cmd *base.Command, args []string) { func runClean(cmd *base.Command, args []string) {
for _, pkg := range packagesAndErrors(args) { for _, pkg := range load.PackagesAndErrors(args) {
clean(pkg) clean(pkg)
} }
} }
var cleaned = map[*Package]bool{} var cleaned = map[*load.Package]bool{}
// TODO: These are dregs left by Makefile-based builds. // TODO: These are dregs left by Makefile-based builds.
// Eventually, can stop deleting these. // Eventually, can stop deleting these.
...@@ -107,7 +108,7 @@ var cleanExt = map[string]bool{ ...@@ -107,7 +108,7 @@ var cleanExt = map[string]bool{
".so": true, ".so": true,
} }
func clean(p *Package) { func clean(p *load.Package) {
if cleaned[p] { if cleaned[p] {
return return
} }
...@@ -209,17 +210,17 @@ func clean(p *Package) { ...@@ -209,17 +210,17 @@ func clean(p *Package) {
} }
} }
if cleanI && p.target != "" { if cleanI && p.Internal.Target != "" {
if cfg.BuildN || cfg.BuildX { if cfg.BuildN || cfg.BuildX {
b.showcmd("", "rm -f %s", p.target) b.showcmd("", "rm -f %s", p.Internal.Target)
} }
if !cfg.BuildN { if !cfg.BuildN {
removeFile(p.target) removeFile(p.Internal.Target)
} }
} }
if cleanR { if cleanR {
for _, p1 := range p.imports { for _, p1 := range p.Internal.Imports {
clean(p1) clean(p1)
} }
} }
......
...@@ -7,8 +7,8 @@ ...@@ -7,8 +7,8 @@
package main package main
import ( import (
"cmd/go/internal/cfg"
"cmd/go/internal/base" "cmd/go/internal/base"
"cmd/go/internal/cfg"
) )
var cmdDoc = &base.Command{ var cmdDoc = &base.Command{
......
...@@ -5,8 +5,9 @@ ...@@ -5,8 +5,9 @@
package main package main
import ( import (
"cmd/go/internal/cfg"
"cmd/go/internal/base" "cmd/go/internal/base"
"cmd/go/internal/cfg"
"cmd/go/internal/load"
"fmt" "fmt"
"os" "os"
"runtime" "runtime"
...@@ -33,14 +34,14 @@ func mkEnv() []cfg.EnvVar { ...@@ -33,14 +34,14 @@ func mkEnv() []cfg.EnvVar {
env := []cfg.EnvVar{ env := []cfg.EnvVar{
{"GOARCH", cfg.Goarch}, {"GOARCH", cfg.Goarch},
{"GOBIN", gobin}, {"GOBIN", cfg.GOBIN},
{"GOEXE", cfg.ExeSuffix}, {"GOEXE", cfg.ExeSuffix},
{"GOHOSTARCH", runtime.GOARCH}, {"GOHOSTARCH", runtime.GOARCH},
{"GOHOSTOS", runtime.GOOS}, {"GOHOSTOS", runtime.GOOS},
{"GOOS", cfg.Goos}, {"GOOS", cfg.Goos},
{"GOPATH", cfg.BuildContext.GOPATH}, {"GOPATH", cfg.BuildContext.GOPATH},
{"GORACE", os.Getenv("GORACE")}, {"GORACE", os.Getenv("GORACE")},
{"GOROOT", goroot}, {"GOROOT", cfg.GOROOT},
{"GOTOOLDIR", base.ToolDir}, {"GOTOOLDIR", base.ToolDir},
// disable escape codes in clang errors // disable escape codes in clang errors
...@@ -88,7 +89,7 @@ func findEnv(env []cfg.EnvVar, name string) string { ...@@ -88,7 +89,7 @@ func findEnv(env []cfg.EnvVar, name string) string {
func extraEnvVars() []cfg.EnvVar { func extraEnvVars() []cfg.EnvVar {
var b builder var b builder
b.init() b.init()
cppflags, cflags, cxxflags, fflags, ldflags := b.cflags(&Package{}) cppflags, cflags, cxxflags, fflags, ldflags := b.cflags(&load.Package{})
return []cfg.EnvVar{ return []cfg.EnvVar{
{"PKG_CONFIG", b.pkgconfigCmd()}, {"PKG_CONFIG", b.pkgconfigCmd()},
{"CGO_CFLAGS", strings.Join(cflags, " ")}, {"CGO_CFLAGS", strings.Join(cflags, " ")},
......
...@@ -5,8 +5,9 @@ ...@@ -5,8 +5,9 @@
package main package main
import ( import (
"cmd/go/internal/cfg"
"cmd/go/internal/base" "cmd/go/internal/base"
"cmd/go/internal/cfg"
"cmd/go/internal/load"
"cmd/go/internal/str" "cmd/go/internal/str"
) )
...@@ -27,10 +28,10 @@ See also: go fmt, go vet. ...@@ -27,10 +28,10 @@ See also: go fmt, go vet.
} }
func runFix(cmd *base.Command, args []string) { func runFix(cmd *base.Command, args []string) {
for _, pkg := range packages(args) { for _, pkg := range load.Packages(args) {
// Use pkg.gofiles instead of pkg.Dir so that // Use pkg.gofiles instead of pkg.Dir so that
// the command only applies to this package, // the command only applies to this package,
// not to packages in subdirectories. // not to packages in subdirectories.
base.Run(str.StringList(cfg.BuildToolexec, base.Tool("fix"), base.RelPaths(pkg.allgofiles))) base.Run(str.StringList(cfg.BuildToolexec, base.Tool("fix"), base.RelPaths(pkg.Internal.AllGoFiles)))
} }
} }
...@@ -5,8 +5,9 @@ ...@@ -5,8 +5,9 @@
package main package main
import ( import (
"cmd/go/internal/cfg"
"cmd/go/internal/base" "cmd/go/internal/base"
"cmd/go/internal/cfg"
"cmd/go/internal/load"
"cmd/go/internal/str" "cmd/go/internal/str"
"os" "os"
"path/filepath" "path/filepath"
...@@ -38,11 +39,11 @@ See also: go fix, go vet. ...@@ -38,11 +39,11 @@ See also: go fix, go vet.
func runFmt(cmd *base.Command, args []string) { func runFmt(cmd *base.Command, args []string) {
gofmt := gofmtPath() gofmt := gofmtPath()
for _, pkg := range packages(args) { for _, pkg := range load.Packages(args) {
// Use pkg.gofiles instead of pkg.Dir so that // Use pkg.gofiles instead of pkg.Dir so that
// the command only applies to this package, // the command only applies to this package,
// not to packages in subdirectories. // not to packages in subdirectories.
base.Run(str.StringList(gofmt, "-l", "-w", base.RelPaths(pkg.allgofiles))) base.Run(str.StringList(gofmt, "-l", "-w", base.RelPaths(pkg.Internal.AllGoFiles)))
} }
} }
...@@ -52,12 +53,12 @@ func gofmtPath() string { ...@@ -52,12 +53,12 @@ func gofmtPath() string {
gofmt += base.ToolWindowsExtension gofmt += base.ToolWindowsExtension
} }
gofmtPath := filepath.Join(gobin, gofmt) gofmtPath := filepath.Join(cfg.GOBIN, gofmt)
if _, err := os.Stat(gofmtPath); err == nil { if _, err := os.Stat(gofmtPath); err == nil {
return gofmtPath return gofmtPath
} }
gofmtPath = filepath.Join(goroot, "bin", gofmt) gofmtPath = filepath.Join(cfg.GOROOT, "bin", gofmt)
if _, err := os.Stat(gofmtPath); err == nil { if _, err := os.Stat(gofmtPath); err == nil {
return gofmtPath return gofmtPath
} }
......
...@@ -7,8 +7,9 @@ package main ...@@ -7,8 +7,9 @@ package main
import ( import (
"bufio" "bufio"
"bytes" "bytes"
"cmd/go/internal/cfg"
"cmd/go/internal/base" "cmd/go/internal/base"
"cmd/go/internal/cfg"
"cmd/go/internal/load"
"fmt" "fmt"
"io" "io"
"log" "log"
...@@ -138,7 +139,7 @@ func init() { ...@@ -138,7 +139,7 @@ func init() {
} }
func runGenerate(cmd *base.Command, args []string) { func runGenerate(cmd *base.Command, args []string) {
ignoreImports = true load.IgnoreImports = true
if generateRunFlag != "" { if generateRunFlag != "" {
var err error var err error
...@@ -148,8 +149,8 @@ func runGenerate(cmd *base.Command, args []string) { ...@@ -148,8 +149,8 @@ func runGenerate(cmd *base.Command, args []string) {
} }
} }
// Even if the arguments are .go files, this loop suffices. // Even if the arguments are .go files, this loop suffices.
for _, pkg := range packages(args) { for _, pkg := range load.Packages(args) {
for _, file := range pkg.gofiles { for _, file := range pkg.Internal.GoFiles {
if !generate(pkg.Name, file) { if !generate(pkg.Name, file) {
break break
} }
......
...@@ -5,8 +5,9 @@ ...@@ -5,8 +5,9 @@
package main package main
import ( import (
"cmd/go/internal/cfg"
"cmd/go/internal/base" "cmd/go/internal/base"
"cmd/go/internal/cfg"
"cmd/go/internal/load"
"cmd/go/internal/str" "cmd/go/internal/str"
"fmt" "fmt"
"go/build" "go/build"
...@@ -119,10 +120,10 @@ func runGet(cmd *base.Command, args []string) { ...@@ -119,10 +120,10 @@ func runGet(cmd *base.Command, args []string) {
} }
// Phase 1. Download/update. // Phase 1. Download/update.
var stk importStack var stk load.ImportStack
mode := 0 mode := 0
if *getT { if *getT {
mode |= getTestDeps mode |= load.GetTestDeps
} }
args = downloadPaths(args) args = downloadPaths(args)
for _, arg := range args { for _, arg := range args {
...@@ -137,20 +138,16 @@ func runGet(cmd *base.Command, args []string) { ...@@ -137,20 +138,16 @@ func runGet(cmd *base.Command, args []string) {
// the information will be recomputed. Instead of keeping // the information will be recomputed. Instead of keeping
// track of the reverse dependency information, evict // track of the reverse dependency information, evict
// everything. // everything.
for name := range packageCache { load.ClearPackageCache()
delete(packageCache, name)
}
// In order to rebuild packages information completely, // In order to rebuild packages information completely,
// we need to clear commands cache. Command packages are // we need to clear commands cache. Command packages are
// referring to evicted packages from the package cache. // referring to evicted packages from the package cache.
// This leads to duplicated loads of the standard packages. // This leads to duplicated loads of the standard packages.
for name := range cmdCache { load.ClearCmdCache()
delete(cmdCache, name)
}
args = importPaths(args) args = load.ImportPaths(args)
packagesForBuild(args) load.PackagesForBuild(args)
// Phase 3. Install. // Phase 3. Install.
if *getD { if *getD {
...@@ -169,7 +166,7 @@ func runGet(cmd *base.Command, args []string) { ...@@ -169,7 +166,7 @@ func runGet(cmd *base.Command, args []string) {
// in the hope that we can figure out the repository from the // in the hope that we can figure out the repository from the
// initial ...-free prefix. // initial ...-free prefix.
func downloadPaths(args []string) []string { func downloadPaths(args []string) []string {
args = importPathsNoDotExpansion(args) args = load.ImportPathsNoDotExpansion(args)
var out []string var out []string
for _, a := range args { for _, a := range args {
if strings.Contains(a, "...") { if strings.Contains(a, "...") {
...@@ -178,9 +175,9 @@ func downloadPaths(args []string) []string { ...@@ -178,9 +175,9 @@ func downloadPaths(args []string) []string {
// warnings. They will be printed by the // warnings. They will be printed by the
// eventual call to importPaths instead. // eventual call to importPaths instead.
if build.IsLocalImport(a) { if build.IsLocalImport(a) {
expand = matchPackagesInFS(a) expand = load.MatchPackagesInFS(a)
} else { } else {
expand = matchPackages(a) expand = load.MatchPackages(a)
} }
if len(expand) > 0 { if len(expand) > 0 {
out = append(out, expand...) out = append(out, expand...)
...@@ -207,20 +204,20 @@ var downloadRootCache = map[string]bool{} ...@@ -207,20 +204,20 @@ var downloadRootCache = map[string]bool{}
// download runs the download half of the get command // download runs the download half of the get command
// for the package named by the argument. // for the package named by the argument.
func download(arg string, parent *Package, stk *importStack, mode int) { func download(arg string, parent *load.Package, stk *load.ImportStack, mode int) {
if mode&useVendor != 0 { if mode&load.UseVendor != 0 {
// Caller is responsible for expanding vendor paths. // Caller is responsible for expanding vendor paths.
panic("internal error: download mode has useVendor set") panic("internal error: download mode has useVendor set")
} }
load := func(path string, mode int) *Package { load1 := func(path string, mode int) *load.Package {
if parent == nil { if parent == nil {
return loadPackage(path, stk) return load.LoadPackage(path, stk)
} }
return loadImport(path, parent.Dir, parent, stk, nil, mode) return load.LoadImport(path, parent.Dir, parent, stk, nil, mode)
} }
p := load(arg, mode) p := load1(arg, mode)
if p.Error != nil && p.Error.hard { if p.Error != nil && p.Error.Hard {
base.Errorf("%s", p.Error) base.Errorf("%s", p.Error)
return return
} }
...@@ -243,26 +240,26 @@ func download(arg string, parent *Package, stk *importStack, mode int) { ...@@ -243,26 +240,26 @@ func download(arg string, parent *Package, stk *importStack, mode int) {
// Only process each package once. // Only process each package once.
// (Unless we're fetching test dependencies for this package, // (Unless we're fetching test dependencies for this package,
// in which case we want to process it again.) // in which case we want to process it again.)
if downloadCache[arg] && mode&getTestDeps == 0 { if downloadCache[arg] && mode&load.GetTestDeps == 0 {
return return
} }
downloadCache[arg] = true downloadCache[arg] = true
pkgs := []*Package{p} pkgs := []*load.Package{p}
wildcardOkay := len(*stk) == 0 wildcardOkay := len(*stk) == 0
isWildcard := false isWildcard := false
// Download if the package is missing, or update if we're using -u. // Download if the package is missing, or update if we're using -u.
if p.Dir == "" || *getU { if p.Dir == "" || *getU {
// The actual download. // The actual download.
stk.push(arg) stk.Push(arg)
err := downloadPackage(p) err := downloadPackage(p)
if err != nil { if err != nil {
base.Errorf("%s", &PackageError{ImportStack: stk.copy(), Err: err.Error()}) base.Errorf("%s", &load.PackageError{ImportStack: stk.Copy(), Err: err.Error()})
stk.pop() stk.Pop()
return return
} }
stk.pop() stk.Pop()
args := []string{arg} args := []string{arg}
// If the argument has a wildcard in it, re-evaluate the wildcard. // If the argument has a wildcard in it, re-evaluate the wildcard.
...@@ -270,29 +267,23 @@ func download(arg string, parent *Package, stk *importStack, mode int) { ...@@ -270,29 +267,23 @@ func download(arg string, parent *Package, stk *importStack, mode int) {
// for p has been replaced in the package cache. // for p has been replaced in the package cache.
if wildcardOkay && strings.Contains(arg, "...") { if wildcardOkay && strings.Contains(arg, "...") {
if build.IsLocalImport(arg) { if build.IsLocalImport(arg) {
args = matchPackagesInFS(arg) args = load.MatchPackagesInFS(arg)
} else { } else {
args = matchPackages(arg) args = load.MatchPackages(arg)
} }
isWildcard = true isWildcard = true
} }
// Clear all relevant package cache entries before // Clear all relevant package cache entries before
// doing any new loads. // doing any new loads.
for _, arg := range args { load.ClearPackageCachePartial(args)
p := packageCache[arg]
if p != nil {
delete(packageCache, p.Dir)
delete(packageCache, p.ImportPath)
}
}
pkgs = pkgs[:0] pkgs = pkgs[:0]
for _, arg := range args { for _, arg := range args {
// Note: load calls loadPackage or loadImport, // Note: load calls loadPackage or loadImport,
// which push arg onto stk already. // which push arg onto stk already.
// Do not push here too, or else stk will say arg imports arg. // Do not push here too, or else stk will say arg imports arg.
p := load(arg, mode) p := load1(arg, mode)
if p.Error != nil { if p.Error != nil {
base.Errorf("%s", p.Error) base.Errorf("%s", p.Error)
continue continue
...@@ -305,10 +296,10 @@ func download(arg string, parent *Package, stk *importStack, mode int) { ...@@ -305,10 +296,10 @@ func download(arg string, parent *Package, stk *importStack, mode int) {
// due to wildcard expansion. // due to wildcard expansion.
for _, p := range pkgs { for _, p := range pkgs {
if *getFix { if *getFix {
base.Run(cfg.BuildToolexec, str.StringList(base.Tool("fix"), base.RelPaths(p.allgofiles))) base.Run(cfg.BuildToolexec, str.StringList(base.Tool("fix"), base.RelPaths(p.Internal.AllGoFiles)))
// The imports might have changed, so reload again. // The imports might have changed, so reload again.
p = reloadPackage(arg, stk) p = load.ReloadPackage(arg, stk)
if p.Error != nil { if p.Error != nil {
base.Errorf("%s", p.Error) base.Errorf("%s", p.Error)
return return
...@@ -318,12 +309,12 @@ func download(arg string, parent *Package, stk *importStack, mode int) { ...@@ -318,12 +309,12 @@ func download(arg string, parent *Package, stk *importStack, mode int) {
if isWildcard { if isWildcard {
// Report both the real package and the // Report both the real package and the
// wildcard in any error message. // wildcard in any error message.
stk.push(p.ImportPath) stk.Push(p.ImportPath)
} }
// Process dependencies, now that we know what they are. // Process dependencies, now that we know what they are.
imports := p.Imports imports := p.Imports
if mode&getTestDeps != 0 { if mode&load.GetTestDeps != 0 {
// Process test dependencies when -t is specified. // Process test dependencies when -t is specified.
// (But don't get test dependencies for test dependencies: // (But don't get test dependencies for test dependencies:
// we always pass mode 0 to the recursive calls below.) // we always pass mode 0 to the recursive calls below.)
...@@ -335,18 +326,18 @@ func download(arg string, parent *Package, stk *importStack, mode int) { ...@@ -335,18 +326,18 @@ func download(arg string, parent *Package, stk *importStack, mode int) {
} }
// Fail fast on import naming full vendor path. // Fail fast on import naming full vendor path.
// Otherwise expand path as needed for test imports. // Otherwise expand path as needed for test imports.
// Note that p.Imports can have additional entries beyond p.build.Imports. // Note that p.Imports can have additional entries beyond p.Internal.Build.Imports.
orig := path orig := path
if i < len(p.build.Imports) { if i < len(p.Internal.Build.Imports) {
orig = p.build.Imports[i] orig = p.Internal.Build.Imports[i]
} }
if j, ok := findVendor(orig); ok { if j, ok := load.FindVendor(orig); ok {
stk.push(path) stk.Push(path)
err := &PackageError{ err := &load.PackageError{
ImportStack: stk.copy(), ImportStack: stk.Copy(),
Err: "must be imported as " + path[j+len("vendor/"):], Err: "must be imported as " + path[j+len("vendor/"):],
} }
stk.pop() stk.Pop()
base.Errorf("%s", err) base.Errorf("%s", err)
continue continue
} }
...@@ -355,20 +346,20 @@ func download(arg string, parent *Package, stk *importStack, mode int) { ...@@ -355,20 +346,20 @@ func download(arg string, parent *Package, stk *importStack, mode int) {
// download does caching based on the value of path, // download does caching based on the value of path,
// so it must be the fully qualified path already. // so it must be the fully qualified path already.
if i >= len(p.Imports) { if i >= len(p.Imports) {
path = vendoredImportPath(p, path) path = load.VendoredImportPath(p, path)
} }
download(path, p, stk, 0) download(path, p, stk, 0)
} }
if isWildcard { if isWildcard {
stk.pop() stk.Pop()
} }
} }
} }
// downloadPackage runs the create or download command // downloadPackage runs the create or download command
// to make the first copy of or update a copy of the given package. // to make the first copy of or update a copy of the given package.
func downloadPackage(p *Package) error { func downloadPackage(p *load.Package) error {
var ( var (
vcs *vcsCmd vcs *vcsCmd
repo, rootPath string repo, rootPath string
...@@ -380,9 +371,9 @@ func downloadPackage(p *Package) error { ...@@ -380,9 +371,9 @@ func downloadPackage(p *Package) error {
security = insecure security = insecure
} }
if p.build.SrcRoot != "" { if p.Internal.Build.SrcRoot != "" {
// Directory exists. Look for checkout along path to src. // Directory exists. Look for checkout along path to src.
vcs, rootPath, err = vcsFromDir(p.Dir, p.build.SrcRoot) vcs, rootPath, err = vcsFromDir(p.Dir, p.Internal.Build.SrcRoot)
if err != nil { if err != nil {
return err return err
} }
...@@ -390,7 +381,7 @@ func downloadPackage(p *Package) error { ...@@ -390,7 +381,7 @@ func downloadPackage(p *Package) error {
// Double-check where it came from. // Double-check where it came from.
if *getU && vcs.remoteRepo != nil { if *getU && vcs.remoteRepo != nil {
dir := filepath.Join(p.build.SrcRoot, filepath.FromSlash(rootPath)) dir := filepath.Join(p.Internal.Build.SrcRoot, filepath.FromSlash(rootPath))
remote, err := vcs.remoteRepo(vcs, dir) remote, err := vcs.remoteRepo(vcs, dir)
if err != nil { if err != nil {
return err return err
...@@ -424,24 +415,24 @@ func downloadPackage(p *Package) error { ...@@ -424,24 +415,24 @@ func downloadPackage(p *Package) error {
return fmt.Errorf("cannot download, %v uses insecure protocol", repo) return fmt.Errorf("cannot download, %v uses insecure protocol", repo)
} }
if p.build.SrcRoot == "" { if p.Internal.Build.SrcRoot == "" {
// Package not found. Put in first directory of $GOPATH. // Package not found. Put in first directory of $GOPATH.
list := filepath.SplitList(cfg.BuildContext.GOPATH) list := filepath.SplitList(cfg.BuildContext.GOPATH)
if len(list) == 0 { if len(list) == 0 {
return fmt.Errorf("cannot download, $GOPATH not set. For more details see: 'go help gopath'") return fmt.Errorf("cannot download, $GOPATH not set. For more details see: 'go help gopath'")
} }
// Guard against people setting GOPATH=$GOROOT. // Guard against people setting GOPATH=$GOROOT.
if list[0] == goroot { if list[0] == cfg.GOROOT {
return fmt.Errorf("cannot download, $GOPATH must not be set to $GOROOT. For more details see: 'go help gopath'") return fmt.Errorf("cannot download, $GOPATH must not be set to $GOROOT. For more details see: 'go help gopath'")
} }
if _, err := os.Stat(filepath.Join(list[0], "src/cmd/go/alldocs.go")); err == nil { if _, err := os.Stat(filepath.Join(list[0], "src/cmd/go/alldocs.go")); err == nil {
return fmt.Errorf("cannot download, %s is a GOROOT, not a GOPATH. For more details see: 'go help gopath'", list[0]) return fmt.Errorf("cannot download, %s is a GOROOT, not a GOPATH. For more details see: 'go help gopath'", list[0])
} }
p.build.Root = list[0] p.Internal.Build.Root = list[0]
p.build.SrcRoot = filepath.Join(list[0], "src") p.Internal.Build.SrcRoot = filepath.Join(list[0], "src")
p.build.PkgRoot = filepath.Join(list[0], "pkg") p.Internal.Build.PkgRoot = filepath.Join(list[0], "pkg")
} }
root := filepath.Join(p.build.SrcRoot, filepath.FromSlash(rootPath)) root := filepath.Join(p.Internal.Build.SrcRoot, filepath.FromSlash(rootPath))
// If we've considered this repository already, don't do it again. // If we've considered this repository already, don't do it again.
if downloadRootCache[root] { if downloadRootCache[root] {
return nil return nil
...@@ -467,7 +458,7 @@ func downloadPackage(p *Package) error { ...@@ -467,7 +458,7 @@ func downloadPackage(p *Package) error {
return fmt.Errorf("%s exists but %s does not - stale checkout?", root, meta) return fmt.Errorf("%s exists but %s does not - stale checkout?", root, meta)
} }
_, err := os.Stat(p.build.Root) _, err := os.Stat(p.Internal.Build.Root)
gopathExisted := err == nil gopathExisted := err == nil
// Some version control tools require the parent of the target to exist. // Some version control tools require the parent of the target to exist.
...@@ -475,8 +466,8 @@ func downloadPackage(p *Package) error { ...@@ -475,8 +466,8 @@ func downloadPackage(p *Package) error {
if err = os.MkdirAll(parent, 0777); err != nil { if err = os.MkdirAll(parent, 0777); err != nil {
return err return err
} }
if cfg.BuildV && !gopathExisted && p.build.Root == cfg.BuildContext.GOPATH { if cfg.BuildV && !gopathExisted && p.Internal.Build.Root == cfg.BuildContext.GOPATH {
fmt.Fprintf(os.Stderr, "created GOPATH=%s; see 'go help gopath'\n", p.build.Root) fmt.Fprintf(os.Stderr, "created GOPATH=%s; see 'go help gopath'\n", p.Internal.Build.Root)
} }
if err = vcs.create(root, repo); err != nil { if err = vcs.create(root, repo); err != nil {
......
...@@ -7,10 +7,13 @@ ...@@ -7,10 +7,13 @@
package base package base
import ( import (
"bytes"
"cmd/go/internal/cfg" "cmd/go/internal/cfg"
"cmd/go/internal/str" "cmd/go/internal/str"
"errors"
"flag" "flag"
"fmt" "fmt"
"go/scanner"
"log" "log"
"os" "os"
"os/exec" "os/exec"
...@@ -145,3 +148,25 @@ func RunStdin(cmdline []string) { ...@@ -145,3 +148,25 @@ func RunStdin(cmdline []string) {
// Usage is the usage-reporting function, filled in by package main // Usage is the usage-reporting function, filled in by package main
// but here for reference by other packages. // but here for reference by other packages.
var Usage func() var Usage func()
// ExpandScanner expands a scanner.List error into all the errors in the list.
// The default Error method only shows the first error
// and does not shorten paths.
func ExpandScanner(err error) error {
// Look for parser errors.
if err, ok := err.(scanner.ErrorList); ok {
// Prepare error with \n before each message.
// When printed in something like context: %v
// this will put the leading file positions each on
// its own line. It will also show all the errors
// instead of just the first, as err.Error does.
var buf bytes.Buffer
for _, e := range err {
e.Pos.Filename = ShortPath(e.Pos.Filename)
buf.WriteString("\n")
buf.WriteString(e.Error())
}
return errors.New(buf.String())
}
return err
}
...@@ -9,6 +9,8 @@ package cfg ...@@ -9,6 +9,8 @@ package cfg
import ( import (
"flag" "flag"
"go/build" "go/build"
"os"
"path/filepath"
"runtime" "runtime"
) )
...@@ -64,3 +66,11 @@ func AddBuildFlagsNX(flags *flag.FlagSet) { ...@@ -64,3 +66,11 @@ func AddBuildFlagsNX(flags *flag.FlagSet) {
flags.BoolVar(&BuildN, "n", false, "") flags.BoolVar(&BuildN, "n", false, "")
flags.BoolVar(&BuildX, "x", false, "") flags.BoolVar(&BuildX, "x", false, "")
} }
var (
GOROOT = filepath.Clean(runtime.GOROOT())
GOBIN = os.Getenv("GOBIN")
GOROOTbin = filepath.Join(GOROOT, "bin")
GOROOTpkg = filepath.Join(GOROOT, "pkg")
GOROOTsrc = filepath.Join(GOROOT, "src")
)
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package main package load
import "testing" import "testing"
......
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package load
import (
"path/filepath"
"strings"
)
// hasSubdir reports whether dir is a subdirectory of
// (possibly multiple levels below) root.
// If so, it sets rel to the path fragment that must be
// appended to root to reach dir.
func hasSubdir(root, dir string) (rel string, ok bool) {
if p, err := filepath.EvalSymlinks(root); err == nil {
root = p
}
if p, err := filepath.EvalSymlinks(dir); err == nil {
dir = p
}
const sep = string(filepath.Separator)
root = filepath.Clean(root)
if !strings.HasSuffix(root, sep) {
root += sep
}
dir = filepath.Clean(dir)
if !strings.HasPrefix(dir, root) {
return "", false
}
return filepath.ToSlash(dir[len(root):]), true
}
// hasPathPrefix reports whether the path s begins with the
// elements in prefix.
func hasPathPrefix(s, prefix string) bool {
switch {
default:
return false
case len(s) == len(prefix):
return s == prefix
case len(s) > len(prefix):
if prefix != "" && prefix[len(prefix)-1] == '/' {
return strings.HasPrefix(s, prefix)
}
return s[len(prefix)] == '/' && s[:len(prefix)] == prefix
}
}
// expandPath returns the symlink-expanded form of path.
func expandPath(p string) string {
x, err := filepath.EvalSymlinks(p)
if err == nil {
return x
}
return p
}
// hasFilePathPrefix reports whether the filesystem path s begins with the
// elements in prefix.
func hasFilePathPrefix(s, prefix string) bool {
sv := strings.ToUpper(filepath.VolumeName(s))
pv := strings.ToUpper(filepath.VolumeName(prefix))
s = s[len(sv):]
prefix = prefix[len(pv):]
switch {
default:
return false
case sv != pv:
return false
case len(s) == len(prefix):
return s == prefix
case len(s) > len(prefix):
if prefix != "" && prefix[len(prefix)-1] == filepath.Separator {
return strings.HasPrefix(s, prefix)
}
return s[len(prefix)] == filepath.Separator && s[:len(prefix)] == prefix
}
}
...@@ -2,15 +2,13 @@ ...@@ -2,15 +2,13 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package main // Package load loads packages.
package load
import ( import (
"bytes"
"crypto/sha1" "crypto/sha1"
"errors"
"fmt" "fmt"
"go/build" "go/build"
"go/scanner"
"go/token" "go/token"
"io/ioutil" "io/ioutil"
"os" "os"
...@@ -27,10 +25,15 @@ import ( ...@@ -27,10 +25,15 @@ import (
"cmd/go/internal/str" "cmd/go/internal/str"
) )
var ignoreImports bool // control whether we ignore imports in packages var IgnoreImports bool // control whether we ignore imports in packages
// A Package describes a single package found in a directory. // A Package describes a single package found in a directory.
type Package struct { type Package struct {
PackagePublic // visible in 'go list'
Internal PackageInternal // for use inside go command only
}
type PackagePublic struct {
// Note: These fields are part of the go command's public API. // 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 // See list.go. It is okay to add fields, but not to change or
// remove existing ones. Keep in sync with list.go // remove existing ones. Keep in sync with list.go
...@@ -85,31 +88,33 @@ type Package struct { ...@@ -85,31 +88,33 @@ type Package struct {
TestImports []string `json:",omitempty"` // imports from TestGoFiles TestImports []string `json:",omitempty"` // imports from TestGoFiles
XTestGoFiles []string `json:",omitempty"` // _test.go files outside package XTestGoFiles []string `json:",omitempty"` // _test.go files outside package
XTestImports []string `json:",omitempty"` // imports from XTestGoFiles XTestImports []string `json:",omitempty"` // imports from XTestGoFiles
}
type PackageInternal struct {
// Unexported fields are not part of the public API. // Unexported fields are not part of the public API.
build *build.Package Build *build.Package
pkgdir string // overrides build.PkgDir Pkgdir string // overrides build.PkgDir
imports []*Package Imports []*Package
deps []*Package Deps []*Package
gofiles []string // GoFiles+CgoFiles+TestGoFiles+XTestGoFiles files, absolute paths GoFiles []string // GoFiles+CgoFiles+TestGoFiles+XTestGoFiles files, absolute paths
sfiles []string SFiles []string
allgofiles []string // gofiles + IgnoredGoFiles, absolute paths AllGoFiles []string // gofiles + IgnoredGoFiles, absolute paths
target string // installed file for this package (may be executable) Target string // installed file for this package (may be executable)
fake bool // synthesized package Fake bool // synthesized package
external bool // synthesized external test package External bool // synthesized external test package
forceLibrary bool // this package is a library (even if named "main") ForceLibrary bool // this package is a library (even if named "main")
cmdline bool // defined by files listed on command line Cmdline bool // defined by files listed on command line
local bool // imported via local path (./ or ../) Local bool // imported via local path (./ or ../)
localPrefix string // interpret ./ and ../ imports relative to this prefix LocalPrefix string // interpret ./ and ../ imports relative to this prefix
exeName string // desired name for temporary executable ExeName string // desired name for temporary executable
coverMode string // preprocess Go source files with the coverage tool in this mode CoverMode string // preprocess Go source files with the coverage tool in this mode
coverVars map[string]*CoverVar // variables created by coverage analysis CoverVars map[string]*CoverVar // variables created by coverage analysis
omitDWARF bool // tell linker not to write DWARF information OmitDWARF bool // tell linker not to write DWARF information
buildID string // expected build ID for generated package BuildID string // expected build ID for generated package
gobinSubdir bool // install target would be subdir of GOBIN GobinSubdir bool // install target would be subdir of GOBIN
} }
// vendored returns the vendor-resolved version of imports, // Vendored returns the vendor-resolved version of imports,
// which should be p.TestImports or p.XTestImports, NOT p.Imports. // which should be p.TestImports or p.XTestImports, NOT p.Imports.
// The imports in p.TestImports and p.XTestImports are not recursively // The imports in p.TestImports and p.XTestImports are not recursively
// loaded during the initial load of p, so they list the imports found in // loaded during the initial load of p, so they list the imports found in
...@@ -119,14 +124,14 @@ type Package struct { ...@@ -119,14 +124,14 @@ type Package struct {
// can produce better error messages if it starts with the original paths. // can produce better error messages if it starts with the original paths.
// The initial load of p loads all the non-test imports and rewrites // The initial load of p loads all the non-test imports and rewrites
// the vendored paths, so nothing should ever call p.vendored(p.Imports). // the vendored paths, so nothing should ever call p.vendored(p.Imports).
func (p *Package) vendored(imports []string) []string { func (p *Package) Vendored(imports []string) []string {
if len(imports) > 0 && len(p.Imports) > 0 && &imports[0] == &p.Imports[0] { if len(imports) > 0 && len(p.Imports) > 0 && &imports[0] == &p.Imports[0] {
panic("internal error: p.vendored(p.Imports) called") panic("internal error: p.vendored(p.Imports) called")
} }
seen := make(map[string]bool) seen := make(map[string]bool)
var all []string var all []string
for _, path := range imports { for _, path := range imports {
path = vendoredImportPath(p, path) path = VendoredImportPath(p, path)
if !seen[path] { if !seen[path] {
seen[path] = true seen[path] = true
all = append(all, path) all = append(all, path)
...@@ -143,7 +148,7 @@ type CoverVar struct { ...@@ -143,7 +148,7 @@ type CoverVar struct {
} }
func (p *Package) copyBuild(pp *build.Package) { func (p *Package) copyBuild(pp *build.Package) {
p.build = pp p.Internal.Build = pp
if pp.PkgTargetRoot != "" && cfg.BuildPkgdir != "" { if pp.PkgTargetRoot != "" && cfg.BuildPkgdir != "" {
old := pp.PkgTargetRoot old := pp.PkgTargetRoot
...@@ -188,7 +193,7 @@ func (p *Package) copyBuild(pp *build.Package) { ...@@ -188,7 +193,7 @@ func (p *Package) copyBuild(pp *build.Package) {
p.TestImports = pp.TestImports p.TestImports = pp.TestImports
p.XTestGoFiles = pp.XTestGoFiles p.XTestGoFiles = pp.XTestGoFiles
p.XTestImports = pp.XTestImports p.XTestImports = pp.XTestImports
if ignoreImports { if IgnoreImports {
p.Imports = nil p.Imports = nil
p.TestImports = nil p.TestImports = nil
p.XTestImports = nil p.XTestImports = nil
...@@ -213,13 +218,13 @@ type PackageError struct { ...@@ -213,13 +218,13 @@ type PackageError struct {
ImportStack []string // shortest path from package named on command line to this one ImportStack []string // shortest path from package named on command line to this one
Pos string // position of error Pos string // position of error
Err string // the error itself Err string // the error itself
isImportCycle bool // the error is an import cycle IsImportCycle bool `json:"-"` // the error is an import cycle
hard bool // whether the error is soft or hard; soft errors are ignored in some places Hard bool `json:"-"` // whether the error is soft or hard; soft errors are ignored in some places
} }
func (p *PackageError) Error() string { func (p *PackageError) Error() string {
// Import cycles deserve special treatment. // Import cycles deserve special treatment.
if p.isImportCycle { if p.IsImportCycle {
return fmt.Sprintf("%s\npackage %s\n", p.Err, strings.Join(p.ImportStack, "\n\timports ")) return fmt.Sprintf("%s\npackage %s\n", p.Err, strings.Join(p.ImportStack, "\n\timports "))
} }
if p.Pos != "" { if p.Pos != "" {
...@@ -233,25 +238,25 @@ func (p *PackageError) Error() string { ...@@ -233,25 +238,25 @@ func (p *PackageError) Error() string {
return "package " + strings.Join(p.ImportStack, "\n\timports ") + ": " + p.Err 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.
type importStack []string type ImportStack []string
func (s *importStack) push(p string) { func (s *ImportStack) Push(p string) {
*s = append(*s, p) *s = append(*s, p)
} }
func (s *importStack) pop() { func (s *ImportStack) Pop() {
*s = (*s)[0 : len(*s)-1] *s = (*s)[0 : len(*s)-1]
} }
func (s *importStack) copy() []string { func (s *ImportStack) Copy() []string {
return append([]string{}, *s...) return append([]string{}, *s...)
} }
// shorterThan reports whether sp is shorter than t. // shorterThan reports whether sp is shorter than t.
// We use this to record the shortest import sequence // We use this to record the shortest import sequence
// that leads to a particular package. // that leads to a particular package.
func (sp *importStack) shorterThan(t []string) bool { func (sp *ImportStack) shorterThan(t []string) bool {
s := *sp s := *sp
if len(s) != len(t) { if len(s) != len(t) {
return len(s) < len(t) return len(s) < len(t)
...@@ -270,15 +275,31 @@ func (sp *importStack) shorterThan(t []string) bool { ...@@ -270,15 +275,31 @@ func (sp *importStack) shorterThan(t []string) bool {
// we return the same pointer each time. // we return the same pointer each time.
var packageCache = map[string]*Package{} var packageCache = map[string]*Package{}
func ClearPackageCache() {
for name := range packageCache {
delete(packageCache, name)
}
}
func ClearPackageCachePartial(args []string) {
for _, arg := range args {
p := packageCache[arg]
if p != nil {
delete(packageCache, p.Dir)
delete(packageCache, p.ImportPath)
}
}
}
// reloadPackage is like loadPackage but makes sure // reloadPackage is like loadPackage but makes sure
// not to use the package cache. // not to use the package cache.
func reloadPackage(arg string, stk *importStack) *Package { func ReloadPackage(arg string, stk *ImportStack) *Package {
p := packageCache[arg] p := packageCache[arg]
if p != nil { if p != nil {
delete(packageCache, p.Dir) delete(packageCache, p.Dir)
delete(packageCache, p.ImportPath) delete(packageCache, p.ImportPath)
} }
return loadPackage(arg, stk) return LoadPackage(arg, stk)
} }
// dirToImportPath returns the pseudo-import path we use for a package // dirToImportPath returns the pseudo-import path we use for a package
...@@ -312,20 +333,20 @@ const ( ...@@ -312,20 +333,20 @@ const (
// recorded as the canonical import path. At that point, future loads // recorded as the canonical import path. At that point, future loads
// of that package must not pass useVendor, because // of that package must not pass useVendor, because
// disallowVendor will reject direct use of paths containing /vendor/. // disallowVendor will reject direct use of paths containing /vendor/.
useVendor = 1 << iota UseVendor = 1 << iota
// getTestDeps is for download (part of "go get") and indicates // getTestDeps is for download (part of "go get") and indicates
// that test dependencies should be fetched too. // that test dependencies should be fetched too.
getTestDeps GetTestDeps
) )
// loadImport scans the directory named by path, which must be an import path, // loadImport scans the directory named by path, which must be an import path,
// but possibly a local import path (an absolute file system path or one beginning // 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. // with ./ or ../). A local relative path is interpreted relative to srcDir.
// It returns a *Package describing the package found in that directory. // It returns a *Package describing the package found in that directory.
func loadImport(path, srcDir string, parent *Package, stk *importStack, importPos []token.Position, mode int) *Package { func LoadImport(path, srcDir string, parent *Package, stk *ImportStack, importPos []token.Position, mode int) *Package {
stk.push(path) stk.Push(path)
defer stk.pop() defer stk.Pop()
// Determine canonical identifier for this package. // Determine canonical identifier for this package.
// For a local import the identifier is the pseudo-import path // For a local import the identifier is the pseudo-import path
...@@ -337,12 +358,12 @@ func loadImport(path, srcDir string, parent *Package, stk *importStack, importPo ...@@ -337,12 +358,12 @@ func loadImport(path, srcDir string, parent *Package, stk *importStack, importPo
isLocal := build.IsLocalImport(path) isLocal := build.IsLocalImport(path)
if isLocal { if isLocal {
importPath = dirToImportPath(filepath.Join(srcDir, path)) importPath = dirToImportPath(filepath.Join(srcDir, path))
} else if mode&useVendor != 0 { } else if mode&UseVendor != 0 {
// We do our own vendor resolution, because we want to // We do our own vendor resolution, because we want to
// find out the key to use in packageCache without the // find out the key to use in packageCache without the
// overhead of repeated calls to buildContext.Import. // overhead of repeated calls to buildContext.Import.
// The code is also needed in a few other places anyway. // The code is also needed in a few other places anyway.
path = vendoredImportPath(parent, path) path = VendoredImportPath(parent, path)
importPath = path importPath = path
} }
...@@ -351,7 +372,7 @@ func loadImport(path, srcDir string, parent *Package, stk *importStack, importPo ...@@ -351,7 +372,7 @@ func loadImport(path, srcDir string, parent *Package, stk *importStack, importPo
p = reusePackage(p, stk) p = reusePackage(p, stk)
} else { } else {
p = new(Package) p = new(Package)
p.local = isLocal p.Internal.Local = isLocal
p.ImportPath = importPath p.ImportPath = importPath
packageCache[importPath] = p packageCache[importPath] = p
...@@ -362,14 +383,14 @@ func loadImport(path, srcDir string, parent *Package, stk *importStack, importPo ...@@ -362,14 +383,14 @@ func loadImport(path, srcDir string, parent *Package, stk *importStack, importPo
// TODO: After Go 1, decide when to pass build.AllowBinary here. // TODO: After Go 1, decide when to pass build.AllowBinary here.
// See issue 3268 for mistakes to avoid. // See issue 3268 for mistakes to avoid.
buildMode := build.ImportComment buildMode := build.ImportComment
if mode&useVendor == 0 || path != origPath { if mode&UseVendor == 0 || path != origPath {
// Not vendoring, or we already found the vendored path. // Not vendoring, or we already found the vendored path.
buildMode |= build.IgnoreVendor buildMode |= build.IgnoreVendor
} }
bp, err := cfg.BuildContext.Import(path, srcDir, buildMode) bp, err := cfg.BuildContext.Import(path, srcDir, buildMode)
bp.ImportPath = importPath bp.ImportPath = importPath
if gobin != "" { if cfg.GOBIN != "" {
bp.BinDir = gobin bp.BinDir = cfg.GOBIN
} }
if err == nil && !isLocal && bp.ImportComment != "" && bp.ImportComment != path && if err == nil && !isLocal && bp.ImportComment != "" && bp.ImportComment != path &&
!strings.Contains(path, "/vendor/") && !strings.HasPrefix(path, "vendor/") { !strings.Contains(path, "/vendor/") && !strings.HasPrefix(path, "vendor/") {
...@@ -382,7 +403,7 @@ func loadImport(path, srcDir string, parent *Package, stk *importStack, importPo ...@@ -382,7 +403,7 @@ func loadImport(path, srcDir string, parent *Package, stk *importStack, importPo
if origPath != cleanImport(origPath) { if origPath != cleanImport(origPath) {
p.Error = &PackageError{ p.Error = &PackageError{
ImportStack: stk.copy(), ImportStack: stk.Copy(),
Err: fmt.Sprintf("non-canonical import path: %q should be %q", origPath, pathpkg.Clean(origPath)), Err: fmt.Sprintf("non-canonical import path: %q should be %q", origPath, pathpkg.Clean(origPath)),
} }
p.Incomplete = true p.Incomplete = true
...@@ -393,7 +414,7 @@ func loadImport(path, srcDir string, parent *Package, stk *importStack, importPo ...@@ -393,7 +414,7 @@ func loadImport(path, srcDir string, parent *Package, stk *importStack, importPo
if perr := disallowInternal(srcDir, p, stk); perr != p { if perr := disallowInternal(srcDir, p, stk); perr != p {
return setErrorPos(perr, importPos) return setErrorPos(perr, importPos)
} }
if mode&useVendor != 0 { if mode&UseVendor != 0 {
if perr := disallowVendor(srcDir, origPath, p, stk); perr != p { if perr := disallowVendor(srcDir, origPath, p, stk); perr != p {
return setErrorPos(perr, importPos) return setErrorPos(perr, importPos)
} }
...@@ -402,16 +423,16 @@ func loadImport(path, srcDir string, parent *Package, stk *importStack, importPo ...@@ -402,16 +423,16 @@ func loadImport(path, srcDir string, parent *Package, stk *importStack, importPo
if p.Name == "main" && parent != nil && parent.Dir != p.Dir { if p.Name == "main" && parent != nil && parent.Dir != p.Dir {
perr := *p perr := *p
perr.Error = &PackageError{ perr.Error = &PackageError{
ImportStack: stk.copy(), ImportStack: stk.Copy(),
Err: fmt.Sprintf("import %q is a program, not an importable package", path), Err: fmt.Sprintf("import %q is a program, not an importable package", path),
} }
return setErrorPos(&perr, importPos) return setErrorPos(&perr, importPos)
} }
if p.local && parent != nil && !parent.local { if p.Internal.Local && parent != nil && !parent.Internal.Local {
perr := *p perr := *p
perr.Error = &PackageError{ perr.Error = &PackageError{
ImportStack: stk.copy(), ImportStack: stk.Copy(),
Err: fmt.Sprintf("local import %q in non-local package", path), Err: fmt.Sprintf("local import %q in non-local package", path),
} }
return setErrorPos(&perr, importPos) return setErrorPos(&perr, importPos)
...@@ -452,11 +473,11 @@ func isDir(path string) bool { ...@@ -452,11 +473,11 @@ func isDir(path string) bool {
return result return result
} }
// vendoredImportPath returns the expansion of path when it appears in parent. // VendoredImportPath returns the expansion of path when it appears in parent.
// If parent is x/y/z, then path might expand to x/y/z/vendor/path, x/y/vendor/path, // If parent is x/y/z, then path might expand to x/y/z/vendor/path, x/y/vendor/path,
// x/vendor/path, vendor/path, or else stay path if none of those exist. // x/vendor/path, vendor/path, or else stay path if none of those exist.
// vendoredImportPath returns the expanded path or, if no expansion is found, the original. // VendoredImportPath returns the expanded path or, if no expansion is found, the original.
func vendoredImportPath(parent *Package, path string) (found string) { func VendoredImportPath(parent *Package, path string) (found string) {
if parent == nil || parent.Root == "" { if parent == nil || parent.Root == "" {
return path return path
} }
...@@ -469,7 +490,7 @@ func vendoredImportPath(parent *Package, path string) (found string) { ...@@ -469,7 +490,7 @@ func vendoredImportPath(parent *Package, path string) (found string) {
root = expandPath(root) root = expandPath(root)
} }
if !hasFilePathPrefix(dir, root) || len(dir) <= len(root) || dir[len(root)] != filepath.Separator || parent.ImportPath != "command-line-arguments" && !parent.local && filepath.Join(root, parent.ImportPath) != dir { if !hasFilePathPrefix(dir, root) || len(dir) <= len(root) || dir[len(root)] != filepath.Separator || parent.ImportPath != "command-line-arguments" && !parent.Internal.Local && filepath.Join(root, parent.ImportPath) != dir {
base.Fatalf("unexpected directory layout:\n"+ base.Fatalf("unexpected directory layout:\n"+
" import path: %s\n"+ " import path: %s\n"+
" root: %s\n"+ " root: %s\n"+
...@@ -544,24 +565,24 @@ func hasGoFiles(dir string) bool { ...@@ -544,24 +565,24 @@ func hasGoFiles(dir string) bool {
// reusePackage reuses package p to satisfy the import at the top // reusePackage reuses package p to satisfy the import at the top
// of the import stack stk. If this use causes an import loop, // of the import stack stk. If this use causes an import loop,
// reusePackage updates p's error information to record the loop. // reusePackage updates p's error information to record the loop.
func reusePackage(p *Package, stk *importStack) *Package { func reusePackage(p *Package, stk *ImportStack) *Package {
// We use p.imports==nil to detect a package that // We use p.Internal.Imports==nil to detect a package that
// is in the midst of its own loadPackage call // is in the midst of its own loadPackage call
// (all the recursion below happens before p.imports gets set). // (all the recursion below happens before p.Internal.Imports gets set).
if p.imports == nil { if p.Internal.Imports == nil {
if p.Error == nil { if p.Error == nil {
p.Error = &PackageError{ p.Error = &PackageError{
ImportStack: stk.copy(), ImportStack: stk.Copy(),
Err: "import cycle not allowed", Err: "import cycle not allowed",
isImportCycle: true, IsImportCycle: true,
} }
} }
p.Incomplete = true p.Incomplete = true
} }
// Don't rewrite the import stack in the error if we have an import cycle. // Don't rewrite the import stack in the error if we have an import cycle.
// If we do, we'll lose the path that describes the cycle. // If we do, we'll lose the path that describes the cycle.
if p.Error != nil && !p.Error.isImportCycle && stk.shorterThan(p.Error.ImportStack) { if p.Error != nil && !p.Error.IsImportCycle && stk.shorterThan(p.Error.ImportStack) {
p.Error.ImportStack = stk.copy() p.Error.ImportStack = stk.Copy()
} }
return p return p
} }
...@@ -569,7 +590,7 @@ func reusePackage(p *Package, stk *importStack) *Package { ...@@ -569,7 +590,7 @@ func reusePackage(p *Package, stk *importStack) *Package {
// disallowInternal checks that srcDir is allowed to import p. // disallowInternal checks that srcDir is allowed to import p.
// If the import is allowed, disallowInternal returns the original package p. // If the import is allowed, disallowInternal returns the original package p.
// If not, it returns a new package containing just an appropriate error. // 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, p *Package, stk *ImportStack) *Package {
// golang.org/s/go14internal: // golang.org/s/go14internal:
// An import of a path containing the element “internal” // An import of a path containing the element “internal”
// is disallowed if the importing code is outside the tree // is disallowed if the importing code is outside the tree
...@@ -627,7 +648,7 @@ func disallowInternal(srcDir string, p *Package, stk *importStack) *Package { ...@@ -627,7 +648,7 @@ func disallowInternal(srcDir string, p *Package, stk *importStack) *Package {
// Internal is present, and srcDir is outside parent's tree. Not allowed. // Internal is present, and srcDir is outside parent's tree. Not allowed.
perr := *p perr := *p
perr.Error = &PackageError{ perr.Error = &PackageError{
ImportStack: stk.copy(), ImportStack: stk.Copy(),
Err: "use of internal package not allowed", Err: "use of internal package not allowed",
} }
perr.Incomplete = true perr.Incomplete = true
...@@ -656,7 +677,7 @@ func findInternal(path string) (index int, ok bool) { ...@@ -656,7 +677,7 @@ func findInternal(path string) (index int, ok bool) {
// disallowVendor checks that srcDir is allowed to import p as path. // disallowVendor checks that srcDir is allowed to import p as path.
// If the import is allowed, disallowVendor returns the original package p. // If the import is allowed, disallowVendor returns the original package p.
// If not, it returns a new package containing just an appropriate error. // 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, path string, p *Package, stk *ImportStack) *Package {
// The stack includes p.ImportPath. // The stack includes p.ImportPath.
// If that's the only thing on the stack, we started // If that's the only thing on the stack, we started
// with a name given on the command line, not an // with a name given on the command line, not an
...@@ -670,10 +691,10 @@ func disallowVendor(srcDir, path string, p *Package, stk *importStack) *Package ...@@ -670,10 +691,10 @@ func disallowVendor(srcDir, path string, p *Package, stk *importStack) *Package
} }
// Paths like x/vendor/y must be imported as y, never as x/vendor/y. // Paths like x/vendor/y must be imported as y, never as x/vendor/y.
if i, ok := findVendor(path); ok { if i, ok := FindVendor(path); ok {
perr := *p perr := *p
perr.Error = &PackageError{ perr.Error = &PackageError{
ImportStack: stk.copy(), ImportStack: stk.Copy(),
Err: "must be imported as " + path[i+len("vendor/"):], Err: "must be imported as " + path[i+len("vendor/"):],
} }
perr.Incomplete = true perr.Incomplete = true
...@@ -688,7 +709,7 @@ func disallowVendor(srcDir, path string, p *Package, stk *importStack) *Package ...@@ -688,7 +709,7 @@ func disallowVendor(srcDir, path string, p *Package, stk *importStack) *Package
// is not subject to the rules, only subdirectories of vendor. // is not subject to the rules, only subdirectories of vendor.
// This allows people to have packages and commands named vendor, // This allows people to have packages and commands named vendor,
// for maximal compatibility with existing source trees. // for maximal compatibility with existing source trees.
func disallowVendorVisibility(srcDir string, p *Package, stk *importStack) *Package { func disallowVendorVisibility(srcDir string, p *Package, stk *ImportStack) *Package {
// The stack includes p.ImportPath. // The stack includes p.ImportPath.
// If that's the only thing on the stack, we started // If that's the only thing on the stack, we started
// with a name given on the command line, not an // with a name given on the command line, not an
...@@ -698,7 +719,7 @@ func disallowVendorVisibility(srcDir string, p *Package, stk *importStack) *Pack ...@@ -698,7 +719,7 @@ func disallowVendorVisibility(srcDir string, p *Package, stk *importStack) *Pack
} }
// Check for "vendor" element. // Check for "vendor" element.
i, ok := findVendor(p.ImportPath) i, ok := FindVendor(p.ImportPath)
if !ok { if !ok {
return p return p
} }
...@@ -727,22 +748,22 @@ func disallowVendorVisibility(srcDir string, p *Package, stk *importStack) *Pack ...@@ -727,22 +748,22 @@ func disallowVendorVisibility(srcDir string, p *Package, stk *importStack) *Pack
// Vendor is present, and srcDir is outside parent's tree. Not allowed. // Vendor is present, and srcDir is outside parent's tree. Not allowed.
perr := *p perr := *p
perr.Error = &PackageError{ perr.Error = &PackageError{
ImportStack: stk.copy(), ImportStack: stk.Copy(),
Err: "use of vendored package not allowed", Err: "use of vendored package not allowed",
} }
perr.Incomplete = true perr.Incomplete = true
return &perr return &perr
} }
// findVendor looks for the last non-terminating "vendor" path element in the given import path. // FindVendor looks for the last non-terminating "vendor" path element in the given import path.
// If there isn't one, findVendor returns ok=false. // If there isn't one, FindVendor returns ok=false.
// Otherwise, findVendor returns ok=true and the index of the "vendor". // Otherwise, FindVendor returns ok=true and the index of the "vendor".
// //
// Note that terminating "vendor" elements don't count: "x/vendor" is its own package, // Note that terminating "vendor" elements don't count: "x/vendor" is its own package,
// not the vendored copy of an import "" (the empty import path). // not the vendored copy of an import "" (the empty import path).
// This will allow people to have packages or commands named vendor. // This will allow people to have packages or commands named vendor.
// This may help reduce breakage, or it may just be confusing. We'll see. // This may help reduce breakage, or it may just be confusing. We'll see.
func findVendor(path string) (index int, ok bool) { func FindVendor(path string) (index int, ok bool) {
// Two cases, depending on internal at start of string or not. // Two cases, depending on internal at start of string or not.
// The order matters: we must return the index of the final element, // The order matters: we must return the index of the final element,
// because the final one is where the effective import path starts. // because the final one is where the effective import path starts.
...@@ -758,54 +779,33 @@ func findVendor(path string) (index int, ok bool) { ...@@ -758,54 +779,33 @@ func findVendor(path string) (index int, ok bool) {
type targetDir int type targetDir int
const ( const (
toRoot targetDir = iota // to bin dir inside package root (default) ToRoot targetDir = iota // to bin dir inside package root (default)
toTool // GOROOT/pkg/tool ToTool // GOROOT/pkg/tool
stalePath // the old import path; fail to build StalePath // the old import path; fail to build
) )
// goTools is a map of Go program import path to install target directory. // goTools is a map of Go program import path to install target directory.
var goTools = map[string]targetDir{ var GoTools = map[string]targetDir{
"cmd/addr2line": toTool, "cmd/addr2line": ToTool,
"cmd/api": toTool, "cmd/api": ToTool,
"cmd/asm": toTool, "cmd/asm": ToTool,
"cmd/compile": toTool, "cmd/compile": ToTool,
"cmd/cgo": toTool, "cmd/cgo": ToTool,
"cmd/cover": toTool, "cmd/cover": ToTool,
"cmd/dist": toTool, "cmd/dist": ToTool,
"cmd/doc": toTool, "cmd/doc": ToTool,
"cmd/fix": toTool, "cmd/fix": ToTool,
"cmd/link": toTool, "cmd/link": ToTool,
"cmd/newlink": toTool, "cmd/newlink": ToTool,
"cmd/nm": toTool, "cmd/nm": ToTool,
"cmd/objdump": toTool, "cmd/objdump": ToTool,
"cmd/pack": toTool, "cmd/pack": ToTool,
"cmd/pprof": toTool, "cmd/pprof": ToTool,
"cmd/trace": toTool, "cmd/trace": ToTool,
"cmd/vet": toTool, "cmd/vet": ToTool,
"code.google.com/p/go.tools/cmd/cover": stalePath, "code.google.com/p/go.tools/cmd/cover": StalePath,
"code.google.com/p/go.tools/cmd/godoc": stalePath, "code.google.com/p/go.tools/cmd/godoc": StalePath,
"code.google.com/p/go.tools/cmd/vet": stalePath, "code.google.com/p/go.tools/cmd/vet": StalePath,
}
// expandScanner expands a scanner.List error into all the errors in the list.
// The default Error method only shows the first error.
func expandScanner(err error) error {
// Look for parser errors.
if err, ok := err.(scanner.ErrorList); ok {
// Prepare error with \n before each message.
// When printed in something like context: %v
// this will put the leading file positions each on
// its own line. It will also show all the errors
// instead of just the first, as err.Error does.
var buf bytes.Buffer
for _, e := range err {
e.Pos.Filename = base.ShortPath(e.Pos.Filename)
buf.WriteString("\n")
buf.WriteString(e.Error())
}
return errors.New(buf.String())
}
return err
} }
var raceExclude = map[string]bool{ var raceExclude = map[string]bool{
...@@ -829,18 +829,18 @@ var cgoSyscallExclude = map[string]bool{ ...@@ -829,18 +829,18 @@ var cgoSyscallExclude = map[string]bool{
// load populates p using information from bp, err, which should // load populates p using information from bp, err, which should
// be the result of calling build.Context.Import. // be the result of calling build.Context.Import.
func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package { func (p *Package) load(stk *ImportStack, bp *build.Package, err error) *Package {
p.copyBuild(bp) p.copyBuild(bp)
// The localPrefix is the path we interpret ./ imports relative to. // The localPrefix is the path we interpret ./ imports relative to.
// Synthesized main packages sometimes override this. // Synthesized main packages sometimes override this.
p.localPrefix = dirToImportPath(p.Dir) p.Internal.LocalPrefix = dirToImportPath(p.Dir)
if err != nil { if err != nil {
p.Incomplete = true p.Incomplete = true
err = expandScanner(err) err = base.ExpandScanner(err)
p.Error = &PackageError{ p.Error = &PackageError{
ImportStack: stk.copy(), ImportStack: stk.Copy(),
Err: err.Error(), Err: err.Error(),
} }
return p return p
...@@ -856,7 +856,7 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package ...@@ -856,7 +856,7 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
if useBindir { if useBindir {
// Report an error when the old code.google.com/p/go.tools paths are used. // Report an error when the old code.google.com/p/go.tools paths are used.
if goTools[p.ImportPath] == stalePath { if GoTools[p.ImportPath] == StalePath {
newPath := strings.Replace(p.ImportPath, "code.google.com/p/go.", "golang.org/x/", 1) newPath := strings.Replace(p.ImportPath, "code.google.com/p/go.", "golang.org/x/", 1)
e := fmt.Sprintf("the %v command has moved; use %v instead.", p.ImportPath, newPath) e := fmt.Sprintf("the %v command has moved; use %v instead.", p.ImportPath, newPath)
p.Error = &PackageError{Err: e} p.Error = &PackageError{Err: e}
...@@ -868,38 +868,38 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package ...@@ -868,38 +868,38 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
// Install cross-compiled binaries to subdirectories of bin. // Install cross-compiled binaries to subdirectories of bin.
elem = full elem = full
} }
if p.build.BinDir != "" { if p.Internal.Build.BinDir != "" {
// Install to GOBIN or bin of GOPATH entry. // Install to GOBIN or bin of GOPATH entry.
p.target = filepath.Join(p.build.BinDir, elem) p.Internal.Target = filepath.Join(p.Internal.Build.BinDir, elem)
if !p.Goroot && strings.Contains(elem, "/") && gobin != "" { if !p.Goroot && strings.Contains(elem, "/") && cfg.GOBIN != "" {
// Do not create $GOBIN/goos_goarch/elem. // Do not create $GOBIN/goos_goarch/elem.
p.target = "" p.Internal.Target = ""
p.gobinSubdir = true p.Internal.GobinSubdir = true
} }
} }
if goTools[p.ImportPath] == toTool { if GoTools[p.ImportPath] == ToTool {
// This is for 'go tool'. // This is for 'go tool'.
// Override all the usual logic and force it into the tool directory. // Override all the usual logic and force it into the tool directory.
p.target = filepath.Join(gorootPkg, "tool", full) p.Internal.Target = filepath.Join(cfg.GOROOTpkg, "tool", full)
} }
if p.target != "" && cfg.BuildContext.GOOS == "windows" { if p.Internal.Target != "" && cfg.BuildContext.GOOS == "windows" {
p.target += ".exe" p.Internal.Target += ".Internal.Exe"
} }
} else if p.local { } else if p.Internal.Local {
// Local import turned into absolute path. // Local import turned into absolute path.
// No permanent install target. // No permanent install target.
p.target = "" p.Internal.Target = ""
} else { } else {
p.target = p.build.PkgObj p.Internal.Target = p.Internal.Build.PkgObj
if cfg.BuildLinkshared { if cfg.BuildLinkshared {
shlibnamefile := p.target[:len(p.target)-2] + ".shlibname" shlibnamefile := p.Internal.Target[:len(p.Internal.Target)-2] + ".shlibname"
shlib, err := ioutil.ReadFile(shlibnamefile) shlib, err := ioutil.ReadFile(shlibnamefile)
if err == nil { if err == nil {
libname := strings.TrimSpace(string(shlib)) libname := strings.TrimSpace(string(shlib))
if cfg.BuildContext.Compiler == "gccgo" { if cfg.BuildContext.Compiler == "gccgo" {
p.Shlib = filepath.Join(p.build.PkgTargetRoot, "shlibs", libname) p.Shlib = filepath.Join(p.Internal.Build.PkgTargetRoot, "shlibs", libname)
} else { } else {
p.Shlib = filepath.Join(p.build.PkgTargetRoot, libname) p.Shlib = filepath.Join(p.Internal.Build.PkgTargetRoot, libname)
} }
} else if !os.IsNotExist(err) { } else if !os.IsNotExist(err) {
...@@ -908,16 +908,16 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package ...@@ -908,16 +908,16 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
} }
} }
importPaths := p.Imports ImportPaths := p.Imports
// Packages that use cgo import runtime/cgo implicitly. // Packages that use cgo import runtime/cgo implicitly.
// Packages that use cgo also import syscall implicitly, // Packages that use cgo also import syscall implicitly,
// to wrap errno. // to wrap errno.
// Exclude certain packages to avoid circular dependencies. // Exclude certain packages to avoid circular dependencies.
if len(p.CgoFiles) > 0 && (!p.Standard || !cgoExclude[p.ImportPath]) { if len(p.CgoFiles) > 0 && (!p.Standard || !cgoExclude[p.ImportPath]) {
importPaths = append(importPaths, "runtime/cgo") ImportPaths = append(ImportPaths, "runtime/cgo")
} }
if len(p.CgoFiles) > 0 && (!p.Standard || !cgoSyscallExclude[p.ImportPath]) { if len(p.CgoFiles) > 0 && (!p.Standard || !cgoSyscallExclude[p.ImportPath]) {
importPaths = append(importPaths, "syscall") ImportPaths = append(ImportPaths, "syscall")
} }
if cfg.BuildContext.CgoEnabled && p.Name == "main" && !p.Goroot { if cfg.BuildContext.CgoEnabled && p.Name == "main" && !p.Goroot {
...@@ -937,30 +937,30 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package ...@@ -937,30 +937,30 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
} }
} }
if cfg.BuildBuildmode == "c-shared" || cfg.BuildBuildmode == "plugin" || pieCgo || cfg.BuildLinkshared || linkmodeExternal { if cfg.BuildBuildmode == "c-shared" || cfg.BuildBuildmode == "plugin" || pieCgo || cfg.BuildLinkshared || linkmodeExternal {
importPaths = append(importPaths, "runtime/cgo") ImportPaths = append(ImportPaths, "runtime/cgo")
} }
} }
// Everything depends on runtime, except runtime, its internal // Everything depends on runtime, except runtime, its internal
// subpackages, and unsafe. // subpackages, and unsafe.
if !p.Standard || (p.ImportPath != "runtime" && !strings.HasPrefix(p.ImportPath, "runtime/internal/") && p.ImportPath != "unsafe") { if !p.Standard || (p.ImportPath != "runtime" && !strings.HasPrefix(p.ImportPath, "runtime/internal/") && p.ImportPath != "unsafe") {
importPaths = append(importPaths, "runtime") ImportPaths = append(ImportPaths, "runtime")
// When race detection enabled everything depends on runtime/race. // When race detection enabled everything depends on runtime/race.
// Exclude certain packages to avoid circular dependencies. // Exclude certain packages to avoid circular dependencies.
if cfg.BuildRace && (!p.Standard || !raceExclude[p.ImportPath]) { if cfg.BuildRace && (!p.Standard || !raceExclude[p.ImportPath]) {
importPaths = append(importPaths, "runtime/race") ImportPaths = append(ImportPaths, "runtime/race")
} }
// MSan uses runtime/msan. // MSan uses runtime/msan.
if cfg.BuildMSan && (!p.Standard || !raceExclude[p.ImportPath]) { if cfg.BuildMSan && (!p.Standard || !raceExclude[p.ImportPath]) {
importPaths = append(importPaths, "runtime/msan") ImportPaths = append(ImportPaths, "runtime/msan")
} }
// On ARM with GOARM=5, everything depends on math for the link. // On ARM with GOARM=5, everything depends on math for the link.
if p.Name == "main" && cfg.Goarch == "arm" { if p.Name == "main" && cfg.Goarch == "arm" {
importPaths = append(importPaths, "math") ImportPaths = append(ImportPaths, "math")
} }
// In coverage atomic mode everything depends on sync/atomic. // In coverage atomic mode everything depends on sync/atomic.
if cfg.TestCoverMode == "atomic" && (!p.Standard || (p.ImportPath != "runtime/cgo" && p.ImportPath != "runtime/race" && p.ImportPath != "sync/atomic")) { if cfg.TestCoverMode == "atomic" && (!p.Standard || (p.ImportPath != "runtime/cgo" && p.ImportPath != "runtime/race" && p.ImportPath != "sync/atomic")) {
importPaths = append(importPaths, "sync/atomic") ImportPaths = append(ImportPaths, "sync/atomic")
} }
} }
...@@ -969,29 +969,29 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package ...@@ -969,29 +969,29 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
// This can be an issue particularly for runtime/internal/atomic; // This can be an issue particularly for runtime/internal/atomic;
// see issue 13655. // see issue 13655.
if p.Standard && (p.ImportPath == "runtime" || strings.HasPrefix(p.ImportPath, "runtime/internal/")) && p.ImportPath != "runtime/internal/sys" { if p.Standard && (p.ImportPath == "runtime" || strings.HasPrefix(p.ImportPath, "runtime/internal/")) && p.ImportPath != "runtime/internal/sys" {
importPaths = append(importPaths, "runtime/internal/sys") ImportPaths = append(ImportPaths, "runtime/internal/sys")
} }
// Build list of full paths to all Go files in the package, // Build list of full paths to all Go files in the package,
// for use by commands like go fmt. // for use by commands like go fmt.
p.gofiles = str.StringList(p.GoFiles, p.CgoFiles, p.TestGoFiles, p.XTestGoFiles) p.Internal.GoFiles = str.StringList(p.GoFiles, p.CgoFiles, p.TestGoFiles, p.XTestGoFiles)
for i := range p.gofiles { for i := range p.Internal.GoFiles {
p.gofiles[i] = filepath.Join(p.Dir, p.gofiles[i]) p.Internal.GoFiles[i] = filepath.Join(p.Dir, p.Internal.GoFiles[i])
} }
sort.Strings(p.gofiles) sort.Strings(p.Internal.GoFiles)
p.sfiles = str.StringList(p.SFiles) p.Internal.SFiles = str.StringList(p.SFiles)
for i := range p.sfiles { for i := range p.Internal.SFiles {
p.sfiles[i] = filepath.Join(p.Dir, p.sfiles[i]) p.Internal.SFiles[i] = filepath.Join(p.Dir, p.Internal.SFiles[i])
} }
sort.Strings(p.sfiles) sort.Strings(p.Internal.SFiles)
p.allgofiles = str.StringList(p.IgnoredGoFiles) p.Internal.AllGoFiles = str.StringList(p.IgnoredGoFiles)
for i := range p.allgofiles { for i := range p.Internal.AllGoFiles {
p.allgofiles[i] = filepath.Join(p.Dir, p.allgofiles[i]) p.Internal.AllGoFiles[i] = filepath.Join(p.Dir, p.Internal.AllGoFiles[i])
} }
p.allgofiles = append(p.allgofiles, p.gofiles...) p.Internal.AllGoFiles = append(p.Internal.AllGoFiles, p.Internal.GoFiles...)
sort.Strings(p.allgofiles) sort.Strings(p.Internal.AllGoFiles)
// Check for case-insensitive collision of input files. // Check for case-insensitive collision of input files.
// To avoid problems on case-insensitive files, we reject any package // To avoid problems on case-insensitive files, we reject any package
...@@ -1015,7 +1015,7 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package ...@@ -1015,7 +1015,7 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
)) ))
if f1 != "" { if f1 != "" {
p.Error = &PackageError{ p.Error = &PackageError{
ImportStack: stk.copy(), ImportStack: stk.Copy(),
Err: fmt.Sprintf("case-insensitive file name collision: %q and %q", f1, f2), Err: fmt.Sprintf("case-insensitive file name collision: %q and %q", f1, f2),
} }
return p return p
...@@ -1034,38 +1034,38 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package ...@@ -1034,38 +1034,38 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
} }
} }
for i, path := range importPaths { for i, path := range ImportPaths {
if path == "C" { if path == "C" {
continue continue
} }
p1 := loadImport(path, p.Dir, p, stk, p.build.ImportPos[path], useVendor) p1 := LoadImport(path, p.Dir, p, stk, p.Internal.Build.ImportPos[path], UseVendor)
if p.Standard && p.Error == nil && !p1.Standard && p1.Error == nil { if p.Standard && p.Error == nil && !p1.Standard && p1.Error == nil {
p.Error = &PackageError{ p.Error = &PackageError{
ImportStack: stk.copy(), ImportStack: stk.Copy(),
Err: fmt.Sprintf("non-standard import %q in standard package %q", path, p.ImportPath), Err: fmt.Sprintf("non-standard import %q in standard package %q", path, p.ImportPath),
} }
pos := p.build.ImportPos[path] pos := p.Internal.Build.ImportPos[path]
if len(pos) > 0 { if len(pos) > 0 {
p.Error.Pos = pos[0].String() p.Error.Pos = pos[0].String()
} }
} }
path = p1.ImportPath path = p1.ImportPath
importPaths[i] = path ImportPaths[i] = path
if i < len(p.Imports) { if i < len(p.Imports) {
p.Imports[i] = path p.Imports[i] = path
} }
save(path, p1) save(path, p1)
imports = append(imports, p1) imports = append(imports, p1)
for _, dep := range p1.deps { for _, dep := range p1.Internal.Deps {
save(dep.ImportPath, dep) save(dep.ImportPath, dep)
} }
if p1.Incomplete { if p1.Incomplete {
p.Incomplete = true p.Incomplete = true
} }
} }
p.imports = imports p.Internal.Imports = imports
p.Deps = make([]string, 0, len(deps)) p.Deps = make([]string, 0, len(deps))
for dep := range deps { for dep := range deps {
...@@ -1077,7 +1077,7 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package ...@@ -1077,7 +1077,7 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
if p1 == nil { if p1 == nil {
panic("impossible: missing entry in package cache for " + dep + " imported by " + p.ImportPath) panic("impossible: missing entry in package cache for " + dep + " imported by " + p.ImportPath)
} }
p.deps = append(p.deps, p1) p.Internal.Deps = append(p.Internal.Deps, p1)
if p1.Error != nil { if p1.Error != nil {
p.DepsErrors = append(p.DepsErrors, p1.Error) p.DepsErrors = append(p.DepsErrors, p1.Error)
} }
...@@ -1085,9 +1085,9 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package ...@@ -1085,9 +1085,9 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
// unsafe is a fake package. // unsafe is a fake package.
if p.Standard && (p.ImportPath == "unsafe" || cfg.BuildContext.Compiler == "gccgo") { if p.Standard && (p.ImportPath == "unsafe" || cfg.BuildContext.Compiler == "gccgo") {
p.target = "" p.Internal.Target = ""
} }
p.Target = p.target p.Target = p.Internal.Target
// If cgo is not enabled, ignore cgo supporting sources // If cgo is not enabled, ignore cgo supporting sources
// just as we ignore go files containing import "C". // just as we ignore go files containing import "C".
...@@ -1104,9 +1104,9 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package ...@@ -1104,9 +1104,9 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
} }
// The gc toolchain only permits C source files with cgo. // The gc toolchain only permits C source files with cgo.
if len(p.CFiles) > 0 && !p.usesCgo() && !p.usesSwig() && cfg.BuildContext.Compiler == "gc" { if len(p.CFiles) > 0 && !p.UsesCgo() && !p.UsesSwig() && cfg.BuildContext.Compiler == "gc" {
p.Error = &PackageError{ p.Error = &PackageError{
ImportStack: stk.copy(), ImportStack: stk.Copy(),
Err: fmt.Sprintf("C source files not allowed when not using cgo or SWIG: %s", strings.Join(p.CFiles, " ")), Err: fmt.Sprintf("C source files not allowed when not using cgo or SWIG: %s", strings.Join(p.CFiles, " ")),
} }
return p return p
...@@ -1118,7 +1118,7 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package ...@@ -1118,7 +1118,7 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
dep1, dep2 := str.FoldDup(p.Deps) dep1, dep2 := str.FoldDup(p.Deps)
if dep1 != "" { if dep1 != "" {
p.Error = &PackageError{ p.Error = &PackageError{
ImportStack: stk.copy(), ImportStack: stk.Copy(),
Err: fmt.Sprintf("case-insensitive import collision: %q and %q", dep1, dep2), Err: fmt.Sprintf("case-insensitive import collision: %q and %q", dep1, dep2),
} }
return p return p
...@@ -1129,7 +1129,7 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package ...@@ -1129,7 +1129,7 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
// For binary-only package, use build ID from supplied package binary. // For binary-only package, use build ID from supplied package binary.
buildID, err := buildid.ReadBuildID(p.Name, p.Target) buildID, err := buildid.ReadBuildID(p.Name, p.Target)
if err == nil { if err == nil {
p.buildID = buildID p.Internal.BuildID = buildID
} }
} else { } else {
computeBuildID(p) computeBuildID(p)
...@@ -1138,18 +1138,18 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package ...@@ -1138,18 +1138,18 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
} }
// usesSwig reports whether the package needs to run SWIG. // usesSwig reports whether the package needs to run SWIG.
func (p *Package) usesSwig() bool { func (p *Package) UsesSwig() bool {
return len(p.SwigFiles) > 0 || len(p.SwigCXXFiles) > 0 return len(p.SwigFiles) > 0 || len(p.SwigCXXFiles) > 0
} }
// usesCgo reports whether the package needs to run cgo // usesCgo reports whether the package needs to run cgo
func (p *Package) usesCgo() bool { func (p *Package) UsesCgo() bool {
return len(p.CgoFiles) > 0 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. // as visited in a depth-first post-order traversal.
func packageList(roots []*Package) []*Package { func PackageList(roots []*Package) []*Package {
seen := map[*Package]bool{} seen := map[*Package]bool{}
all := []*Package{} all := []*Package{}
var walk func(*Package) var walk func(*Package)
...@@ -1158,7 +1158,7 @@ func packageList(roots []*Package) []*Package { ...@@ -1158,7 +1158,7 @@ func packageList(roots []*Package) []*Package {
return return
} }
seen[p] = true seen[p] = true
for _, p1 := range p.imports { for _, p1 := range p.Internal.Imports {
walk(p1) walk(p1)
} }
all = append(all, p) all = append(all, p)
...@@ -1171,8 +1171,8 @@ func packageList(roots []*Package) []*Package { ...@@ -1171,8 +1171,8 @@ func packageList(roots []*Package) []*Package {
// computeStale computes the Stale flag in the package dag that starts // computeStale computes the Stale flag in the package dag that starts
// at the named pkgs (command-line arguments). // at the named pkgs (command-line arguments).
func computeStale(pkgs ...*Package) { func ComputeStale(pkgs ...*Package) {
for _, p := range packageList(pkgs) { for _, p := range PackageList(pkgs) {
p.Stale, p.StaleReason = isStale(p) p.Stale, p.StaleReason = isStale(p)
} }
} }
...@@ -1463,11 +1463,11 @@ func isStale(p *Package) (bool, string) { ...@@ -1463,11 +1463,11 @@ func isStale(p *Package) (bool, string) {
// if a rebuild is needed, that rebuild attempt will produce a useful error. // if a rebuild is needed, that rebuild attempt will produce a useful error.
// (Some commands, such as 'go list', do not attempt to rebuild.) // (Some commands, such as 'go list', do not attempt to rebuild.)
if p.BinaryOnly { if p.BinaryOnly {
if p.target == "" { if p.Internal.Target == "" {
// Fail if a build is attempted. // Fail if a build is attempted.
return true, "no source code for package, but no install target" return true, "no source code for package, but no install target"
} }
if _, err := os.Stat(p.target); err != nil { if _, err := os.Stat(p.Internal.Target); err != nil {
// Fail if a build is attempted. // Fail if a build is attempted.
return true, "no source code for package, but cannot access install target: " + err.Error() return true, "no source code for package, but cannot access install target: " + err.Error()
} }
...@@ -1480,12 +1480,12 @@ func isStale(p *Package) (bool, string) { ...@@ -1480,12 +1480,12 @@ func isStale(p *Package) (bool, string) {
} }
// If there's no install target, we have to rebuild. // If there's no install target, we have to rebuild.
if p.target == "" { if p.Internal.Target == "" {
return true, "no install target" return true, "no install target"
} }
// Package is stale if completely unbuilt. // Package is stale if completely unbuilt.
fi, err := os.Stat(p.target) fi, err := os.Stat(p.Internal.Target)
if err != nil { if err != nil {
return true, "cannot stat install target" return true, "cannot stat install target"
} }
...@@ -1499,12 +1499,12 @@ func isStale(p *Package) (bool, string) { ...@@ -1499,12 +1499,12 @@ func isStale(p *Package) (bool, string) {
// two versions of Go compiling a single GOPATH. // two versions of Go compiling a single GOPATH.
// See issue 8290 and issue 10702. // See issue 8290 and issue 10702.
targetBuildID, err := buildid.ReadBuildID(p.Name, p.Target) targetBuildID, err := buildid.ReadBuildID(p.Name, p.Target)
if err == nil && targetBuildID != p.buildID { if err == nil && targetBuildID != p.Internal.BuildID {
return true, "build ID mismatch" return true, "build ID mismatch"
} }
// Package is stale if a dependency is. // Package is stale if a dependency is.
for _, p1 := range p.deps { for _, p1 := range p.Internal.Deps {
if p1.Stale { if p1.Stale {
return true, "stale dependency" return true, "stale dependency"
} }
...@@ -1542,8 +1542,8 @@ func isStale(p *Package) (bool, string) { ...@@ -1542,8 +1542,8 @@ func isStale(p *Package) (bool, string) {
} }
// Package is stale if a dependency is, or if a dependency is newer. // Package is stale if a dependency is, or if a dependency is newer.
for _, p1 := range p.deps { for _, p1 := range p.Internal.Deps {
if p1.target != "" && olderThan(p1.target) { if p1.Internal.Target != "" && olderThan(p1.Internal.Target) {
return true, "newer dependency" return true, "newer dependency"
} }
} }
...@@ -1561,11 +1561,11 @@ func isStale(p *Package) (bool, string) { ...@@ -1561,11 +1561,11 @@ func isStale(p *Package) (bool, string) {
// and get a full rebuild anyway. // and get a full rebuild anyway.
// Excluding $GOROOT used to also fix issue 4106, but that's now // Excluding $GOROOT used to also fix issue 4106, but that's now
// taken care of above (at least when the installed Go is a released version). // taken care of above (at least when the installed Go is a released version).
if p.Root != goroot { if p.Root != cfg.GOROOT {
if olderThan(cfg.BuildToolchainCompiler) { if olderThan(cfg.BuildToolchainCompiler) {
return true, "newer compiler" return true, "newer compiler"
} }
if p.build.IsCommand() && olderThan(cfg.BuildToolchainLinker) { if p.Internal.Build.IsCommand() && olderThan(cfg.BuildToolchainLinker) {
return true, "newer linker" return true, "newer linker"
} }
} }
...@@ -1618,7 +1618,7 @@ func isStale(p *Package) (bool, string) { ...@@ -1618,7 +1618,7 @@ func isStale(p *Package) (bool, string) {
return false, "" return false, ""
} }
// computeBuildID computes the build ID for p, leaving it in p.buildID. // computeBuildID computes the build ID for p, leaving it in p.Internal.BuildID.
// Build ID is a hash of the information we want to detect changes in. // Build ID is a hash of the information we want to detect changes in.
// See the long comment in isStale for details. // See the long comment in isStale for details.
func computeBuildID(p *Package) { func computeBuildID(p *Package) {
...@@ -1661,20 +1661,26 @@ func computeBuildID(p *Package) { ...@@ -1661,20 +1661,26 @@ func computeBuildID(p *Package) {
// people use the same GOPATH but switch between // people use the same GOPATH but switch between
// different Go releases. See issue 10702. // different Go releases. See issue 10702.
// This is also a better fix for issue 8290. // This is also a better fix for issue 8290.
for _, p1 := range p.deps { for _, p1 := range p.Internal.Deps {
fmt.Fprintf(h, "dep %s %s\n", p1.ImportPath, p1.buildID) fmt.Fprintf(h, "dep %s %s\n", p1.ImportPath, p1.Internal.BuildID)
} }
p.buildID = fmt.Sprintf("%x", h.Sum(nil)) p.Internal.BuildID = fmt.Sprintf("%x", h.Sum(nil))
} }
var cmdCache = map[string]*Package{} var cmdCache = map[string]*Package{}
func ClearCmdCache() {
for name := range cmdCache {
delete(cmdCache, name)
}
}
// loadPackage is like loadImport but is used for command-line arguments, // loadPackage is like loadImport but is used for command-line arguments,
// not for paths found in import statements. In addition to ordinary import paths, // not for paths found in import statements. In addition to ordinary import paths,
// loadPackage accepts pseudo-paths beginning with cmd/ to denote commands // loadPackage accepts pseudo-paths beginning with cmd/ to denote commands
// in the Go command directory, as well as paths to those directories. // 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) { if build.IsLocalImport(arg) {
dir := arg dir := arg
if !filepath.IsAbs(dir) { if !filepath.IsAbs(dir) {
...@@ -1683,7 +1689,7 @@ func loadPackage(arg string, stk *importStack) *Package { ...@@ -1683,7 +1689,7 @@ func loadPackage(arg string, stk *importStack) *Package {
dir = abs dir = abs
} }
} }
if sub, ok := hasSubdir(gorootSrc, dir); ok && strings.HasPrefix(sub, "cmd/") && !strings.Contains(sub[4:], "/") { if sub, ok := hasSubdir(cfg.GOROOTsrc, dir); ok && strings.HasPrefix(sub, "cmd/") && !strings.Contains(sub[4:], "/") {
arg = sub arg = sub
} }
} }
...@@ -1691,24 +1697,24 @@ func loadPackage(arg string, stk *importStack) *Package { ...@@ -1691,24 +1697,24 @@ func loadPackage(arg string, stk *importStack) *Package {
if p := cmdCache[arg]; p != nil { if p := cmdCache[arg]; p != nil {
return p return p
} }
stk.push(arg) stk.Push(arg)
defer stk.pop() defer stk.Pop()
bp, err := cfg.BuildContext.ImportDir(filepath.Join(gorootSrc, arg), 0) bp, err := cfg.BuildContext.ImportDir(filepath.Join(cfg.GOROOTsrc, arg), 0)
bp.ImportPath = arg bp.ImportPath = arg
bp.Goroot = true bp.Goroot = true
bp.BinDir = gorootBin bp.BinDir = cfg.GOROOTbin
if gobin != "" { if cfg.GOROOTbin != "" {
bp.BinDir = gobin bp.BinDir = cfg.GOROOTbin
} }
bp.Root = goroot bp.Root = cfg.GOROOT
bp.SrcRoot = gorootSrc bp.SrcRoot = cfg.GOROOTsrc
p := new(Package) p := new(Package)
cmdCache[arg] = p cmdCache[arg] = p
p.load(stk, bp, err) p.load(stk, bp, err)
if p.Error == nil && p.Name != "main" { if p.Error == nil && p.Name != "main" {
p.Error = &PackageError{ p.Error = &PackageError{
ImportStack: stk.copy(), ImportStack: stk.Copy(),
Err: fmt.Sprintf("expected package main but found package %s in %s", p.Name, p.Dir), Err: fmt.Sprintf("expected package main but found package %s in %s", p.Name, p.Dir),
} }
} }
...@@ -1728,7 +1734,7 @@ func loadPackage(arg string, stk *importStack) *Package { ...@@ -1728,7 +1734,7 @@ func loadPackage(arg string, stk *importStack) *Package {
} }
} }
return loadImport(arg, base.Cwd, nil, stk, nil, 0) return LoadImport(arg, base.Cwd, nil, stk, nil, 0)
} }
// packages returns the packages named by the // packages returns the packages named by the
...@@ -1739,9 +1745,9 @@ func loadPackage(arg string, stk *importStack) *Package { ...@@ -1739,9 +1745,9 @@ func loadPackage(arg string, stk *importStack) *Package {
// to load dependencies of a named package, the named // to load dependencies of a named package, the named
// package is still returned, with p.Incomplete = true // package is still returned, with p.Incomplete = true
// and details in p.DepsErrors. // and details in p.DepsErrors.
func packages(args []string) []*Package { func Packages(args []string) []*Package {
var pkgs []*Package var pkgs []*Package
for _, pkg := range packagesAndErrors(args) { for _, pkg := range PackagesAndErrors(args) {
if pkg.Error != nil { if pkg.Error != nil {
base.Errorf("can't load package: %s", pkg.Error) base.Errorf("can't load package: %s", pkg.Error)
continue continue
...@@ -1755,15 +1761,15 @@ func packages(args []string) []*Package { ...@@ -1755,15 +1761,15 @@ func packages(args []string) []*Package {
// *Package for every argument, even the ones that // *Package for every argument, even the ones that
// cannot be loaded at all. // cannot be loaded at all.
// The packages that fail to load will have p.Error != nil. // The packages that fail to load will have p.Error != nil.
func packagesAndErrors(args []string) []*Package { func PackagesAndErrors(args []string) []*Package {
if len(args) > 0 && strings.HasSuffix(args[0], ".go") { if len(args) > 0 && strings.HasSuffix(args[0], ".go") {
return []*Package{goFilesPackage(args)} return []*Package{GoFilesPackage(args)}
} }
args = importPaths(args) args = ImportPaths(args)
var ( var (
pkgs []*Package pkgs []*Package
stk importStack stk ImportStack
seenArg = make(map[string]bool) seenArg = make(map[string]bool)
seenPkg = make(map[*Package]bool) seenPkg = make(map[*Package]bool)
) )
...@@ -1773,14 +1779,14 @@ func packagesAndErrors(args []string) []*Package { ...@@ -1773,14 +1779,14 @@ func packagesAndErrors(args []string) []*Package {
continue continue
} }
seenArg[arg] = true seenArg[arg] = true
pkg := loadPackage(arg, &stk) pkg := LoadPackage(arg, &stk)
if seenPkg[pkg] { if seenPkg[pkg] {
continue continue
} }
seenPkg[pkg] = true seenPkg[pkg] = true
pkgs = append(pkgs, pkg) pkgs = append(pkgs, pkg)
} }
computeStale(pkgs...) ComputeStale(pkgs...)
return pkgs return pkgs
} }
...@@ -1788,8 +1794,8 @@ func packagesAndErrors(args []string) []*Package { ...@@ -1788,8 +1794,8 @@ func packagesAndErrors(args []string) []*Package {
// packagesForBuild is like 'packages' but fails if any of // packagesForBuild is like 'packages' but fails if any of
// the packages or their dependencies have errors // the packages or their dependencies have errors
// (cannot be built). // (cannot be built).
func packagesForBuild(args []string) []*Package { func PackagesForBuild(args []string) []*Package {
pkgs := packagesAndErrors(args) pkgs := PackagesAndErrors(args)
printed := map[*PackageError]bool{} printed := map[*PackageError]bool{}
for _, pkg := range pkgs { for _, pkg := range pkgs {
if pkg.Error != nil { if pkg.Error != nil {
...@@ -1815,7 +1821,7 @@ func packagesForBuild(args []string) []*Package { ...@@ -1815,7 +1821,7 @@ func packagesForBuild(args []string) []*Package {
// which doesn't work very well. // which doesn't work very well.
seen := map[string]bool{} seen := map[string]bool{}
reported := map[string]bool{} reported := map[string]bool{}
for _, pkg := range packageList(pkgs) { for _, pkg := range PackageList(pkgs) {
if seen[pkg.ImportPath] && !reported[pkg.ImportPath] { if seen[pkg.ImportPath] && !reported[pkg.ImportPath] {
reported[pkg.ImportPath] = true reported[pkg.ImportPath] = true
base.Errorf("internal error: duplicate loads of %s", pkg.ImportPath) base.Errorf("internal error: duplicate loads of %s", pkg.ImportPath)
...@@ -1827,25 +1833,83 @@ func packagesForBuild(args []string) []*Package { ...@@ -1827,25 +1833,83 @@ func packagesForBuild(args []string) []*Package {
return pkgs return pkgs
} }
// hasSubdir reports whether dir is a subdirectory of // GoFilesPackage creates a package for building a collection of Go files
// (possibly multiple levels below) root. // (typically named on the command line). The target is named p.a for
// If so, it sets rel to the path fragment that must be // package p or named after the first Go file for package main.
// appended to root to reach dir. func GoFilesPackage(gofiles []string) *Package {
func hasSubdir(root, dir string) (rel string, ok bool) { // TODO: Remove this restriction.
if p, err := filepath.EvalSymlinks(root); err == nil { for _, f := range gofiles {
root = p if !strings.HasSuffix(f, ".go") {
base.Fatalf("named files must be .go files")
}
}
var stk ImportStack
ctxt := cfg.BuildContext
ctxt.UseAllFiles = true
// Synthesize fake "directory" that only shows the named files,
// to make it look like this is a standard package or
// command directory. So that local imports resolve
// consistently, the files must all be in the same directory.
var dirent []os.FileInfo
var dir string
for _, file := range gofiles {
fi, err := os.Stat(file)
if err != nil {
base.Fatalf("%s", err)
}
if fi.IsDir() {
base.Fatalf("%s is a directory, should be a Go file", file)
}
dir1, _ := filepath.Split(file)
if dir1 == "" {
dir1 = "./"
}
if dir == "" {
dir = dir1
} else if dir != dir1 {
base.Fatalf("named files must all be in one directory; have %s and %s", dir, dir1)
}
dirent = append(dirent, fi)
} }
if p, err := filepath.EvalSymlinks(dir); err == nil { ctxt.ReadDir = func(string) ([]os.FileInfo, error) { return dirent, nil }
dir = p
var err error
if dir == "" {
dir = base.Cwd
} }
const sep = string(filepath.Separator) dir, err = filepath.Abs(dir)
root = filepath.Clean(root) if err != nil {
if !strings.HasSuffix(root, sep) { base.Fatalf("%s", err)
root += sep
} }
dir = filepath.Clean(dir)
if !strings.HasPrefix(dir, root) { bp, err := ctxt.ImportDir(dir, 0)
return "", false pkg := new(Package)
pkg.Internal.Local = true
pkg.Internal.Cmdline = true
stk.Push("main")
pkg.load(&stk, bp, err)
stk.Pop()
pkg.Internal.LocalPrefix = dirToImportPath(dir)
pkg.ImportPath = "command-line-arguments"
pkg.Internal.Target = ""
if pkg.Name == "main" {
_, elem := filepath.Split(gofiles[0])
exe := elem[:len(elem)-len(".go")] + cfg.ExeSuffix
if cfg.BuildO == "" {
cfg.BuildO = exe
}
if cfg.GOBIN != "" {
pkg.Internal.Target = filepath.Join(cfg.GOBIN, exe)
}
} }
return filepath.ToSlash(dir[len(root):]), true
pkg.Target = pkg.Internal.Target
pkg.Stale = true
pkg.StaleReason = "files named on command line"
ComputeStale(pkg)
return pkg
} }
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package load
import (
"cmd/go/internal/cfg"
"fmt"
"go/build"
"log"
"os"
"path"
"path/filepath"
"regexp"
"strings"
)
// allPackages returns all the packages that can be found
// under the $GOPATH directories and $GOROOT matching pattern.
// The pattern is either "all" (all packages), "std" (standard packages),
// "cmd" (standard commands), or a path including "...".
func allPackages(pattern string) []string {
pkgs := MatchPackages(pattern)
if len(pkgs) == 0 {
fmt.Fprintf(os.Stderr, "warning: %q matched no packages\n", pattern)
}
return pkgs
}
// allPackagesInFS is like allPackages but is passed a pattern
// beginning ./ or ../, meaning it should scan the tree rooted
// at the given directory. There are ... in the pattern too.
func allPackagesInFS(pattern string) []string {
pkgs := MatchPackagesInFS(pattern)
if len(pkgs) == 0 {
fmt.Fprintf(os.Stderr, "warning: %q matched no packages\n", pattern)
}
return pkgs
}
// MatchPackages returns a list of package paths matching pattern
// (see go help packages for pattern syntax).
func MatchPackages(pattern string) []string {
match := func(string) bool { return true }
treeCanMatch := func(string) bool { return true }
if !IsMetaPackage(pattern) {
match = matchPattern(pattern)
treeCanMatch = treeCanMatchPattern(pattern)
}
have := map[string]bool{
"builtin": true, // ignore pseudo-package that exists only for documentation
}
if !cfg.BuildContext.CgoEnabled {
have["runtime/cgo"] = true // ignore during walk
}
var pkgs []string
for _, src := range cfg.BuildContext.SrcDirs() {
if (pattern == "std" || pattern == "cmd") && src != cfg.GOROOTsrc {
continue
}
src = filepath.Clean(src) + string(filepath.Separator)
root := src
if pattern == "cmd" {
root += "cmd" + string(filepath.Separator)
}
filepath.Walk(root, func(path string, fi os.FileInfo, err error) error {
if err != nil || !fi.IsDir() || path == src {
return nil
}
// Avoid .foo, _foo, and testdata directory trees.
_, elem := filepath.Split(path)
if strings.HasPrefix(elem, ".") || strings.HasPrefix(elem, "_") || elem == "testdata" {
return filepath.SkipDir
}
name := filepath.ToSlash(path[len(src):])
if pattern == "std" && (!isStandardImportPath(name) || name == "cmd") {
// The name "std" is only the standard library.
// If the name is cmd, it's the root of the command tree.
return filepath.SkipDir
}
if !treeCanMatch(name) {
return filepath.SkipDir
}
if have[name] {
return nil
}
have[name] = true
if !match(name) {
return nil
}
_, err = cfg.BuildContext.ImportDir(path, 0)
if err != nil {
if _, noGo := err.(*build.NoGoError); noGo {
return nil
}
}
pkgs = append(pkgs, name)
return nil
})
}
return pkgs
}
// MatchPackagesInFS returns a list of package paths matching pattern,
// which must begin with ./ or ../
// (see go help packages for pattern syntax).
func MatchPackagesInFS(pattern string) []string {
// Find directory to begin the scan.
// Could be smarter but this one optimization
// is enough for now, since ... is usually at the
// end of a path.
i := strings.Index(pattern, "...")
dir, _ := path.Split(pattern[:i])
// pattern begins with ./ or ../.
// path.Clean will discard the ./ but not the ../.
// We need to preserve the ./ for pattern matching
// and in the returned import paths.
prefix := ""
if strings.HasPrefix(pattern, "./") {
prefix = "./"
}
match := matchPattern(pattern)
var pkgs []string
filepath.Walk(dir, func(path string, fi os.FileInfo, err error) error {
if err != nil || !fi.IsDir() {
return nil
}
if path == dir {
// filepath.Walk starts at dir and recurses. For the recursive case,
// the path is the result of filepath.Join, which calls filepath.Clean.
// The initial case is not Cleaned, though, so we do this explicitly.
//
// This converts a path like "./io/" to "io". Without this step, running
// "cd $GOROOT/src; go list ./io/..." would incorrectly skip the io
// package, because prepending the prefix "./" to the unclean path would
// result in "././io", and match("././io") returns false.
path = filepath.Clean(path)
}
// Avoid .foo, _foo, and testdata directory trees, but do not avoid "." or "..".
_, elem := filepath.Split(path)
dot := strings.HasPrefix(elem, ".") && elem != "." && elem != ".."
if dot || strings.HasPrefix(elem, "_") || elem == "testdata" {
return filepath.SkipDir
}
name := prefix + filepath.ToSlash(path)
if !match(name) {
return nil
}
// We keep the directory if we can import it, or if we can't import it
// due to invalid Go source files. This means that directories containing
// parse errors will be built (and fail) instead of being silently skipped
// as not matching the pattern. Go 1.5 and earlier skipped, but that
// behavior means people miss serious mistakes.
// See golang.org/issue/11407.
if p, err := cfg.BuildContext.ImportDir(path, 0); err != nil && (p == nil || len(p.InvalidGoFiles) == 0) {
if _, noGo := err.(*build.NoGoError); !noGo {
log.Print(err)
}
return nil
}
pkgs = append(pkgs, name)
return nil
})
return pkgs
}
// treeCanMatchPattern(pattern)(name) reports whether
// name or children of name can possibly match pattern.
// Pattern is the same limited glob accepted by matchPattern.
func treeCanMatchPattern(pattern string) func(name string) bool {
wildCard := false
if i := strings.Index(pattern, "..."); i >= 0 {
wildCard = true
pattern = pattern[:i]
}
return func(name string) bool {
return len(name) <= len(pattern) && hasPathPrefix(pattern, name) ||
wildCard && strings.HasPrefix(name, pattern)
}
}
// matchPattern(pattern)(name) reports whether
// name matches pattern. Pattern is a limited glob
// pattern in which '...' means 'any string' and there
// is no other special syntax.
func matchPattern(pattern string) func(name string) bool {
re := regexp.QuoteMeta(pattern)
re = strings.Replace(re, `\.\.\.`, `.*`, -1)
// Special case: foo/... matches foo too.
if strings.HasSuffix(re, `/.*`) {
re = re[:len(re)-len(`/.*`)] + `(/.*)?`
}
reg := regexp.MustCompile(`^` + re + `$`)
return func(name string) bool {
return reg.MatchString(name)
}
}
// ImportPaths returns the import paths to use for the given command line.
func ImportPaths(args []string) []string {
args = ImportPathsNoDotExpansion(args)
var out []string
for _, a := range args {
if strings.Contains(a, "...") {
if build.IsLocalImport(a) {
out = append(out, allPackagesInFS(a)...)
} else {
out = append(out, allPackages(a)...)
}
continue
}
out = append(out, a)
}
return out
}
// ImportPathsNoDotExpansion returns the import paths to use for the given
// command line, but it does no ... expansion.
func ImportPathsNoDotExpansion(args []string) []string {
if len(args) == 0 {
return []string{"."}
}
var out []string
for _, a := range args {
// Arguments are supposed to be import paths, but
// as a courtesy to Windows developers, rewrite \ to /
// in command-line arguments. Handles .\... and so on.
if filepath.Separator == '\\' {
a = strings.Replace(a, `\`, `/`, -1)
}
// Put argument in canonical form, but preserve leading ./.
if strings.HasPrefix(a, "./") {
a = "./" + path.Clean(a)
if a == "./." {
a = "."
}
} else {
a = path.Clean(a)
}
if IsMetaPackage(a) {
out = append(out, allPackages(a)...)
continue
}
out = append(out, a)
}
return out
}
// isMetaPackage checks if name is a reserved package name that expands to multiple packages.
func IsMetaPackage(name string) bool {
return name == "std" || name == "cmd" || name == "all"
}
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
// +build testgo // +build testgo
package main package load
import "os" import "os"
......
...@@ -6,8 +6,9 @@ package main ...@@ -6,8 +6,9 @@ package main
import ( import (
"bufio" "bufio"
"cmd/go/internal/cfg"
"cmd/go/internal/base" "cmd/go/internal/base"
"cmd/go/internal/cfg"
"cmd/go/internal/load"
"encoding/json" "encoding/json"
"io" "io"
"os" "os"
...@@ -152,9 +153,9 @@ func runList(cmd *base.Command, args []string) { ...@@ -152,9 +153,9 @@ func runList(cmd *base.Command, args []string) {
out := newTrackingWriter(os.Stdout) out := newTrackingWriter(os.Stdout)
defer out.w.Flush() defer out.w.Flush()
var do func(*Package) var do func(*load.PackagePublic)
if *listJson { if *listJson {
do = func(p *Package) { do = func(p *load.PackagePublic) {
b, err := json.MarshalIndent(p, "", "\t") b, err := json.MarshalIndent(p, "", "\t")
if err != nil { if err != nil {
out.Flush() out.Flush()
...@@ -179,7 +180,7 @@ func runList(cmd *base.Command, args []string) { ...@@ -179,7 +180,7 @@ func runList(cmd *base.Command, args []string) {
if err != nil { if err != nil {
base.Fatalf("%s", err) base.Fatalf("%s", err)
} }
do = func(p *Package) { do = func(p *load.PackagePublic) {
if err := tmpl.Execute(out, p); err != nil { if err := tmpl.Execute(out, p); err != nil {
out.Flush() out.Flush()
base.Fatalf("%s", err) base.Fatalf("%s", err)
...@@ -190,17 +191,17 @@ func runList(cmd *base.Command, args []string) { ...@@ -190,17 +191,17 @@ func runList(cmd *base.Command, args []string) {
} }
} }
load := packages loadpkgs := load.Packages
if *listE { if *listE {
load = packagesAndErrors loadpkgs = load.PackagesAndErrors
} }
for _, pkg := range load(args) { for _, pkg := range loadpkgs(args) {
// Show vendor-expanded paths in listing // Show vendor-expanded paths in listing
pkg.TestImports = pkg.vendored(pkg.TestImports) pkg.TestImports = pkg.Vendored(pkg.TestImports)
pkg.XTestImports = pkg.vendored(pkg.XTestImports) pkg.XTestImports = pkg.Vendored(pkg.XTestImports)
do(pkg) do(&pkg.PackagePublic)
} }
} }
......
...@@ -7,12 +7,9 @@ package main ...@@ -7,12 +7,9 @@ package main
import ( import (
"flag" "flag"
"fmt" "fmt"
"go/build"
"log" "log"
"os" "os"
"path"
"path/filepath" "path/filepath"
"regexp"
"runtime" "runtime"
"strings" "strings"
...@@ -89,8 +86,8 @@ func main() { ...@@ -89,8 +86,8 @@ func main() {
} }
} }
if fi, err := os.Stat(goroot); err != nil || !fi.IsDir() { if fi, err := os.Stat(cfg.GOROOT); err != nil || !fi.IsDir() {
fmt.Fprintf(os.Stderr, "go: cannot find GOROOT directory: %v\n", goroot) fmt.Fprintf(os.Stderr, "go: cannot find GOROOT directory: %v\n", cfg.GOROOT)
os.Exit(2) os.Exit(2)
} }
...@@ -145,57 +142,6 @@ func mainUsage() { ...@@ -145,57 +142,6 @@ func mainUsage() {
os.Exit(2) os.Exit(2)
} }
// importPathsNoDotExpansion returns the import paths to use for the given
// command line, but it does no ... expansion.
func importPathsNoDotExpansion(args []string) []string {
if len(args) == 0 {
return []string{"."}
}
var out []string
for _, a := range args {
// Arguments are supposed to be import paths, but
// as a courtesy to Windows developers, rewrite \ to /
// in command-line arguments. Handles .\... and so on.
if filepath.Separator == '\\' {
a = strings.Replace(a, `\`, `/`, -1)
}
// Put argument in canonical form, but preserve leading ./.
if strings.HasPrefix(a, "./") {
a = "./" + path.Clean(a)
if a == "./." {
a = "."
}
} else {
a = path.Clean(a)
}
if isMetaPackage(a) {
out = append(out, allPackages(a)...)
continue
}
out = append(out, a)
}
return out
}
// importPaths returns the import paths to use for the given command line.
func importPaths(args []string) []string {
args = importPathsNoDotExpansion(args)
var out []string
for _, a := range args {
if strings.Contains(a, "...") {
if build.IsLocalImport(a) {
out = append(out, allPackagesInFS(a)...)
} else {
out = append(out, allPackages(a)...)
}
continue
}
out = append(out, a)
}
return out
}
// envForDir returns a copy of the environment // envForDir returns a copy of the environment
// suitable for running in the given directory. // suitable for running in the given directory.
// The environment is the current process's environment // The environment is the current process's environment
...@@ -225,235 +171,3 @@ NextVar: ...@@ -225,235 +171,3 @@ NextVar:
} }
return out return out
} }
// matchPattern(pattern)(name) reports whether
// name matches pattern. Pattern is a limited glob
// pattern in which '...' means 'any string' and there
// is no other special syntax.
func matchPattern(pattern string) func(name string) bool {
re := regexp.QuoteMeta(pattern)
re = strings.Replace(re, `\.\.\.`, `.*`, -1)
// Special case: foo/... matches foo too.
if strings.HasSuffix(re, `/.*`) {
re = re[:len(re)-len(`/.*`)] + `(/.*)?`
}
reg := regexp.MustCompile(`^` + re + `$`)
return func(name string) bool {
return reg.MatchString(name)
}
}
// hasPathPrefix reports whether the path s begins with the
// elements in prefix.
func hasPathPrefix(s, prefix string) bool {
switch {
default:
return false
case len(s) == len(prefix):
return s == prefix
case len(s) > len(prefix):
if prefix != "" && prefix[len(prefix)-1] == '/' {
return strings.HasPrefix(s, prefix)
}
return s[len(prefix)] == '/' && s[:len(prefix)] == prefix
}
}
// hasFilePathPrefix reports whether the filesystem path s begins with the
// elements in prefix.
func hasFilePathPrefix(s, prefix string) bool {
sv := strings.ToUpper(filepath.VolumeName(s))
pv := strings.ToUpper(filepath.VolumeName(prefix))
s = s[len(sv):]
prefix = prefix[len(pv):]
switch {
default:
return false
case sv != pv:
return false
case len(s) == len(prefix):
return s == prefix
case len(s) > len(prefix):
if prefix != "" && prefix[len(prefix)-1] == filepath.Separator {
return strings.HasPrefix(s, prefix)
}
return s[len(prefix)] == filepath.Separator && s[:len(prefix)] == prefix
}
}
// expandPath returns the symlink-expanded form of path.
func expandPath(p string) string {
x, err := filepath.EvalSymlinks(p)
if err == nil {
return x
}
return p
}
// treeCanMatchPattern(pattern)(name) reports whether
// name or children of name can possibly match pattern.
// Pattern is the same limited glob accepted by matchPattern.
func treeCanMatchPattern(pattern string) func(name string) bool {
wildCard := false
if i := strings.Index(pattern, "..."); i >= 0 {
wildCard = true
pattern = pattern[:i]
}
return func(name string) bool {
return len(name) <= len(pattern) && hasPathPrefix(pattern, name) ||
wildCard && strings.HasPrefix(name, pattern)
}
}
// allPackages returns all the packages that can be found
// under the $GOPATH directories and $GOROOT matching pattern.
// The pattern is either "all" (all packages), "std" (standard packages),
// "cmd" (standard commands), or a path including "...".
func allPackages(pattern string) []string {
pkgs := matchPackages(pattern)
if len(pkgs) == 0 {
fmt.Fprintf(os.Stderr, "warning: %q matched no packages\n", pattern)
}
return pkgs
}
func matchPackages(pattern string) []string {
match := func(string) bool { return true }
treeCanMatch := func(string) bool { return true }
if !isMetaPackage(pattern) {
match = matchPattern(pattern)
treeCanMatch = treeCanMatchPattern(pattern)
}
have := map[string]bool{
"builtin": true, // ignore pseudo-package that exists only for documentation
}
if !cfg.BuildContext.CgoEnabled {
have["runtime/cgo"] = true // ignore during walk
}
var pkgs []string
for _, src := range cfg.BuildContext.SrcDirs() {
if (pattern == "std" || pattern == "cmd") && src != gorootSrc {
continue
}
src = filepath.Clean(src) + string(filepath.Separator)
root := src
if pattern == "cmd" {
root += "cmd" + string(filepath.Separator)
}
filepath.Walk(root, func(path string, fi os.FileInfo, err error) error {
if err != nil || !fi.IsDir() || path == src {
return nil
}
// Avoid .foo, _foo, and testdata directory trees.
_, elem := filepath.Split(path)
if strings.HasPrefix(elem, ".") || strings.HasPrefix(elem, "_") || elem == "testdata" {
return filepath.SkipDir
}
name := filepath.ToSlash(path[len(src):])
if pattern == "std" && (!isStandardImportPath(name) || name == "cmd") {
// The name "std" is only the standard library.
// If the name is cmd, it's the root of the command tree.
return filepath.SkipDir
}
if !treeCanMatch(name) {
return filepath.SkipDir
}
if have[name] {
return nil
}
have[name] = true
if !match(name) {
return nil
}
_, err = cfg.BuildContext.ImportDir(path, 0)
if err != nil {
if _, noGo := err.(*build.NoGoError); noGo {
return nil
}
}
pkgs = append(pkgs, name)
return nil
})
}
return pkgs
}
// allPackagesInFS is like allPackages but is passed a pattern
// beginning ./ or ../, meaning it should scan the tree rooted
// at the given directory. There are ... in the pattern too.
func allPackagesInFS(pattern string) []string {
pkgs := matchPackagesInFS(pattern)
if len(pkgs) == 0 {
fmt.Fprintf(os.Stderr, "warning: %q matched no packages\n", pattern)
}
return pkgs
}
func matchPackagesInFS(pattern string) []string {
// Find directory to begin the scan.
// Could be smarter but this one optimization
// is enough for now, since ... is usually at the
// end of a path.
i := strings.Index(pattern, "...")
dir, _ := path.Split(pattern[:i])
// pattern begins with ./ or ../.
// path.Clean will discard the ./ but not the ../.
// We need to preserve the ./ for pattern matching
// and in the returned import paths.
prefix := ""
if strings.HasPrefix(pattern, "./") {
prefix = "./"
}
match := matchPattern(pattern)
var pkgs []string
filepath.Walk(dir, func(path string, fi os.FileInfo, err error) error {
if err != nil || !fi.IsDir() {
return nil
}
if path == dir {
// filepath.Walk starts at dir and recurses. For the recursive case,
// the path is the result of filepath.Join, which calls filepath.Clean.
// The initial case is not Cleaned, though, so we do this explicitly.
//
// This converts a path like "./io/" to "io". Without this step, running
// "cd $GOROOT/src; go list ./io/..." would incorrectly skip the io
// package, because prepending the prefix "./" to the unclean path would
// result in "././io", and match("././io") returns false.
path = filepath.Clean(path)
}
// Avoid .foo, _foo, and testdata directory trees, but do not avoid "." or "..".
_, elem := filepath.Split(path)
dot := strings.HasPrefix(elem, ".") && elem != "." && elem != ".."
if dot || strings.HasPrefix(elem, "_") || elem == "testdata" {
return filepath.SkipDir
}
name := prefix + filepath.ToSlash(path)
if !match(name) {
return nil
}
// We keep the directory if we can import it, or if we can't import it
// due to invalid Go source files. This means that directories containing
// parse errors will be built (and fail) instead of being silently skipped
// as not matching the pattern. Go 1.5 and earlier skipped, but that
// behavior means people miss serious mistakes.
// See golang.org/issue/11407.
if p, err := cfg.BuildContext.ImportDir(path, 0); err != nil && (p == nil || len(p.InvalidGoFiles) == 0) {
if _, noGo := err.(*build.NoGoError); !noGo {
log.Print(err)
}
return nil
}
pkgs = append(pkgs, name)
return nil
})
return pkgs
}
...@@ -5,8 +5,9 @@ ...@@ -5,8 +5,9 @@
package main package main
import ( import (
"cmd/go/internal/cfg"
"cmd/go/internal/base" "cmd/go/internal/base"
"cmd/go/internal/cfg"
"cmd/go/internal/load"
"cmd/go/internal/str" "cmd/go/internal/str"
"io/ioutil" "io/ioutil"
"os" "os"
...@@ -87,71 +88,79 @@ func TestParseMetaGoImports(t *testing.T) { ...@@ -87,71 +88,79 @@ func TestParseMetaGoImports(t *testing.T) {
} }
} }
func pkgImportPath(path string) *load.Package {
return &load.Package{
PackagePublic: load.PackagePublic{
ImportPath: path,
},
}
}
func TestSharedLibName(t *testing.T) { func TestSharedLibName(t *testing.T) {
// TODO(avdva) - make these values platform-specific // TODO(avdva) - make these values platform-specific
prefix := "lib" prefix := "lib"
suffix := ".so" suffix := ".so"
testData := []struct { testData := []struct {
args []string args []string
pkgs []*Package pkgs []*load.Package
expected string expected string
expectErr bool expectErr bool
rootedAt string rootedAt string
}{ }{
{ {
args: []string{"std"}, args: []string{"std"},
pkgs: []*Package{}, pkgs: []*load.Package{},
expected: "std", expected: "std",
}, },
{ {
args: []string{"std", "cmd"}, args: []string{"std", "cmd"},
pkgs: []*Package{}, pkgs: []*load.Package{},
expected: "std,cmd", expected: "std,cmd",
}, },
{ {
args: []string{}, args: []string{},
pkgs: []*Package{&Package{ImportPath: "gopkg.in/somelib"}}, pkgs: []*load.Package{pkgImportPath("gopkg.in/somelib")},
expected: "gopkg.in-somelib", expected: "gopkg.in-somelib",
}, },
{ {
args: []string{"./..."}, args: []string{"./..."},
pkgs: []*Package{&Package{ImportPath: "somelib"}}, pkgs: []*load.Package{pkgImportPath("somelib")},
expected: "somelib", expected: "somelib",
rootedAt: "somelib", rootedAt: "somelib",
}, },
{ {
args: []string{"../somelib", "../somelib"}, args: []string{"../somelib", "../somelib"},
pkgs: []*Package{&Package{ImportPath: "somelib"}}, pkgs: []*load.Package{pkgImportPath("somelib")},
expected: "somelib", expected: "somelib",
}, },
{ {
args: []string{"../lib1", "../lib2"}, args: []string{"../lib1", "../lib2"},
pkgs: []*Package{&Package{ImportPath: "gopkg.in/lib1"}, &Package{ImportPath: "gopkg.in/lib2"}}, pkgs: []*load.Package{pkgImportPath("gopkg.in/lib1"), pkgImportPath("gopkg.in/lib2")},
expected: "gopkg.in-lib1,gopkg.in-lib2", expected: "gopkg.in-lib1,gopkg.in-lib2",
}, },
{ {
args: []string{"./..."}, args: []string{"./..."},
pkgs: []*Package{ pkgs: []*load.Package{
&Package{ImportPath: "gopkg.in/dir/lib1"}, pkgImportPath("gopkg.in/dir/lib1"),
&Package{ImportPath: "gopkg.in/lib2"}, pkgImportPath("gopkg.in/lib2"),
&Package{ImportPath: "gopkg.in/lib3"}, pkgImportPath("gopkg.in/lib3"),
}, },
expected: "gopkg.in", expected: "gopkg.in",
rootedAt: "gopkg.in", rootedAt: "gopkg.in",
}, },
{ {
args: []string{"std", "../lib2"}, args: []string{"std", "../lib2"},
pkgs: []*Package{}, pkgs: []*load.Package{},
expectErr: true, expectErr: true,
}, },
{ {
args: []string{"all", "./"}, args: []string{"all", "./"},
pkgs: []*Package{}, pkgs: []*load.Package{},
expectErr: true, expectErr: true,
}, },
{ {
args: []string{"cmd", "fmt"}, args: []string{"cmd", "fmt"},
pkgs: []*Package{}, pkgs: []*load.Package{},
expectErr: true, expectErr: true,
}, },
} }
......
...@@ -5,8 +5,9 @@ ...@@ -5,8 +5,9 @@
package main package main
import ( import (
"cmd/go/internal/cfg"
"cmd/go/internal/base" "cmd/go/internal/base"
"cmd/go/internal/cfg"
"cmd/go/internal/load"
"cmd/go/internal/str" "cmd/go/internal/str"
"fmt" "fmt"
"os" "os"
...@@ -87,17 +88,17 @@ func runRun(cmd *base.Command, args []string) { ...@@ -87,17 +88,17 @@ func runRun(cmd *base.Command, args []string) {
base.Fatalf("go run: cannot run *_test.go files (%s)", file) base.Fatalf("go run: cannot run *_test.go files (%s)", file)
} }
} }
p := goFilesPackage(files) p := load.GoFilesPackage(files)
if p.Error != nil { if p.Error != nil {
base.Fatalf("%s", p.Error) base.Fatalf("%s", p.Error)
} }
p.omitDWARF = true p.Internal.OmitDWARF = true
if len(p.DepsErrors) > 0 { if len(p.DepsErrors) > 0 {
// Since these are errors in dependencies, // Since these are errors in dependencies,
// the same error might show up multiple times, // the same error might show up multiple times,
// once in each package that depends on it. // once in each package that depends on it.
// Only print each once. // Only print each once.
printed := map[*PackageError]bool{} printed := map[*load.PackageError]bool{}
for _, err := range p.DepsErrors { for _, err := range p.DepsErrors {
if !printed[err] { if !printed[err] {
printed[err] = true printed[err] = true
...@@ -109,7 +110,7 @@ func runRun(cmd *base.Command, args []string) { ...@@ -109,7 +110,7 @@ func runRun(cmd *base.Command, args []string) {
if p.Name != "main" { if p.Name != "main" {
base.Fatalf("go run: cannot run non-main package") base.Fatalf("go run: cannot run non-main package")
} }
p.target = "" // must build - not up to date p.Internal.Target = "" // must build - not up to date
var src string var src string
if len(p.GoFiles) > 0 { if len(p.GoFiles) > 0 {
src = p.GoFiles[0] src = p.GoFiles[0]
...@@ -124,7 +125,7 @@ func runRun(cmd *base.Command, args []string) { ...@@ -124,7 +125,7 @@ func runRun(cmd *base.Command, args []string) {
} }
base.Fatalf("go run: no suitable source files%s", hint) base.Fatalf("go run: no suitable source files%s", hint)
} }
p.exeName = src[:len(src)-len(".go")] // name temporary executable for first go file p.Internal.ExeName = src[:len(src)-len(".go")] // name temporary executable for first go file
a1 := b.action(modeBuild, modeBuild, p) a1 := b.action(modeBuild, modeBuild, p)
a := &action{f: (*builder).runProgram, args: cmdArgs, deps: []*action{a1}} a := &action{f: (*builder).runProgram, args: cmdArgs, deps: []*action{a1}}
b.do(a) b.do(a)
......
...@@ -6,8 +6,9 @@ package main ...@@ -6,8 +6,9 @@ package main
import ( import (
"bytes" "bytes"
"cmd/go/internal/cfg"
"cmd/go/internal/base" "cmd/go/internal/base"
"cmd/go/internal/cfg"
"cmd/go/internal/load"
"cmd/go/internal/str" "cmd/go/internal/str"
"errors" "errors"
"fmt" "fmt"
...@@ -380,13 +381,13 @@ var ( ...@@ -380,13 +381,13 @@ var (
testC bool // -c flag testC bool // -c flag
testCover bool // -cover flag testCover bool // -cover flag
// Note: testCoverMode is cfg.TestCoverMode (-covermode) // Note: testCoverMode is cfg.TestCoverMode (-covermode)
testCoverPaths []string // -coverpkg flag testCoverPaths []string // -coverpkg flag
testCoverPkgs []*Package // -coverpkg flag testCoverPkgs []*load.Package // -coverpkg flag
testO string // -o flag testO string // -o flag
testProfile bool // some profiling flag testProfile bool // some profiling flag
testNeedBinary bool // profile needs to keep binary around testNeedBinary bool // profile needs to keep binary around
testV bool // -v flag testV bool // -v flag
testTimeout string // -timeout flag testTimeout string // -timeout flag
testArgs []string testArgs []string
testBench bool testBench bool
testStreamOutput bool // show output as it is generated testStreamOutput bool // show output as it is generated
...@@ -410,7 +411,7 @@ func runTest(cmd *base.Command, args []string) { ...@@ -410,7 +411,7 @@ func runTest(cmd *base.Command, args []string) {
instrumentInit() instrumentInit()
buildModeInit() buildModeInit()
pkgs := packagesForBuild(pkgArgs) pkgs := load.PackagesForBuild(pkgArgs)
if len(pkgs) == 0 { if len(pkgs) == 0 {
base.Fatalf("no packages to test") base.Fatalf("no packages to test")
} }
...@@ -469,10 +470,10 @@ func runTest(cmd *base.Command, args []string) { ...@@ -469,10 +470,10 @@ func runTest(cmd *base.Command, args []string) {
for _, path := range p.Imports { for _, path := range p.Imports {
deps[path] = true deps[path] = true
} }
for _, path := range p.vendored(p.TestImports) { for _, path := range p.Vendored(p.TestImports) {
deps[path] = true deps[path] = true
} }
for _, path := range p.vendored(p.XTestImports) { for _, path := range p.Vendored(p.XTestImports) {
deps[path] = true deps[path] = true
} }
} }
...@@ -497,7 +498,7 @@ func runTest(cmd *base.Command, args []string) { ...@@ -497,7 +498,7 @@ func runTest(cmd *base.Command, args []string) {
sort.Strings(all) sort.Strings(all)
a := &action{} a := &action{}
for _, p := range packagesForBuild(all) { for _, p := range load.PackagesForBuild(all) {
a.deps = append(a.deps, b.action(modeInstall, modeInstall, p)) a.deps = append(a.deps, b.action(modeInstall, modeInstall, p))
} }
b.do(a) b.do(a)
...@@ -512,7 +513,7 @@ func runTest(cmd *base.Command, args []string) { ...@@ -512,7 +513,7 @@ func runTest(cmd *base.Command, args []string) {
if testCoverPaths != nil { if testCoverPaths != nil {
// Load packages that were asked about for coverage. // Load packages that were asked about for coverage.
// packagesForBuild exits if the packages cannot be loaded. // packagesForBuild exits if the packages cannot be loaded.
testCoverPkgs = packagesForBuild(testCoverPaths) testCoverPkgs = load.PackagesForBuild(testCoverPaths)
// Warn about -coverpkg arguments that are not actually used. // Warn about -coverpkg arguments that are not actually used.
used := make(map[string]bool) used := make(map[string]bool)
...@@ -536,13 +537,13 @@ func runTest(cmd *base.Command, args []string) { ...@@ -536,13 +537,13 @@ func runTest(cmd *base.Command, args []string) {
} }
p.Stale = true // rebuild p.Stale = true // rebuild
p.StaleReason = "rebuild for coverage" p.StaleReason = "rebuild for coverage"
p.fake = true // do not warn about rebuild p.Internal.Fake = true // do not warn about rebuild
p.coverMode = cfg.TestCoverMode p.Internal.CoverMode = cfg.TestCoverMode
var coverFiles []string var coverFiles []string
coverFiles = append(coverFiles, p.GoFiles...) coverFiles = append(coverFiles, p.GoFiles...)
coverFiles = append(coverFiles, p.CgoFiles...) coverFiles = append(coverFiles, p.CgoFiles...)
coverFiles = append(coverFiles, p.TestGoFiles...) coverFiles = append(coverFiles, p.TestGoFiles...)
p.coverVars = declareCoverVars(p.ImportPath, coverFiles...) p.Internal.CoverVars = declareCoverVars(p.ImportPath, coverFiles...)
} }
} }
...@@ -594,7 +595,7 @@ func runTest(cmd *base.Command, args []string) { ...@@ -594,7 +595,7 @@ func runTest(cmd *base.Command, args []string) {
// If we are building any out-of-date packages other // If we are building any out-of-date packages other
// than those under test, warn. // than those under test, warn.
okBuild := map[*Package]bool{} okBuild := map[*load.Package]bool{}
for _, p := range pkgs { for _, p := range pkgs {
okBuild[p] = true okBuild[p] = true
} }
...@@ -607,13 +608,13 @@ func runTest(cmd *base.Command, args []string) { ...@@ -607,13 +608,13 @@ func runTest(cmd *base.Command, args []string) {
// Don't warn about packages being rebuilt because of // Don't warn about packages being rebuilt because of
// things like coverage analysis. // things like coverage analysis.
for _, p1 := range a.p.imports { for _, p1 := range a.p.Internal.Imports {
if p1.fake { if p1.Internal.Fake {
a.p.fake = true a.p.Internal.Fake = true
} }
} }
if a.f != nil && !okBuild[a.p] && !a.p.fake && !a.p.local { if a.f != nil && !okBuild[a.p] && !a.p.Internal.Fake && !a.p.Internal.Local {
if !warned { if !warned {
fmt.Fprintf(os.Stderr, "warning: building out-of-date packages:\n") fmt.Fprintf(os.Stderr, "warning: building out-of-date packages:\n")
warned = true warned = true
...@@ -646,7 +647,7 @@ var windowsBadWords = []string{ ...@@ -646,7 +647,7 @@ var windowsBadWords = []string{
"update", "update",
} }
func builderTest(b *builder, p *Package) (buildAction, runAction, printAction *action, err error) { func builderTest(b *builder, p *load.Package) (buildAction, runAction, printAction *action, err error) {
if len(p.TestGoFiles)+len(p.XTestGoFiles) == 0 { if len(p.TestGoFiles)+len(p.XTestGoFiles) == 0 {
build := b.action(modeBuild, modeBuild, p) build := b.action(modeBuild, modeBuild, p)
run := &action{p: p, deps: []*action{build}} run := &action{p: p, deps: []*action{build}}
...@@ -658,13 +659,13 @@ func builderTest(b *builder, p *Package) (buildAction, runAction, printAction *a ...@@ -658,13 +659,13 @@ func builderTest(b *builder, p *Package) (buildAction, runAction, printAction *a
// ptest - package + test files // ptest - package + test files
// pxtest - package of external test files // pxtest - package of external test files
// pmain - pkg.test binary // pmain - pkg.test binary
var ptest, pxtest, pmain *Package var ptest, pxtest, pmain *load.Package
var imports, ximports []*Package var imports, ximports []*load.Package
var stk importStack var stk load.ImportStack
stk.push(p.ImportPath + " (test)") stk.Push(p.ImportPath + " (test)")
for i, path := range p.TestImports { for i, path := range p.TestImports {
p1 := loadImport(path, p.Dir, p, &stk, p.build.TestImportPos[path], useVendor) p1 := load.LoadImport(path, p.Dir, p, &stk, p.Internal.Build.TestImportPos[path], load.UseVendor)
if p1.Error != nil { if p1.Error != nil {
return nil, nil, nil, p1.Error return nil, nil, nil, p1.Error
} }
...@@ -677,21 +678,21 @@ func builderTest(b *builder, p *Package) (buildAction, runAction, printAction *a ...@@ -677,21 +678,21 @@ func builderTest(b *builder, p *Package) (buildAction, runAction, printAction *a
// Same error that loadPackage returns (via reusePackage) in pkg.go. // Same error that loadPackage returns (via reusePackage) in pkg.go.
// Can't change that code, because that code is only for loading the // Can't change that code, because that code is only for loading the
// non-test copy of a package. // non-test copy of a package.
err := &PackageError{ err := &load.PackageError{
ImportStack: testImportStack(stk[0], p1, p.ImportPath), ImportStack: testImportStack(stk[0], p1, p.ImportPath),
Err: "import cycle not allowed in test", Err: "import cycle not allowed in test",
isImportCycle: true, IsImportCycle: true,
} }
return nil, nil, nil, err return nil, nil, nil, err
} }
p.TestImports[i] = p1.ImportPath p.TestImports[i] = p1.ImportPath
imports = append(imports, p1) imports = append(imports, p1)
} }
stk.pop() stk.Pop()
stk.push(p.ImportPath + "_test") stk.Push(p.ImportPath + "_test")
pxtestNeedsPtest := false pxtestNeedsPtest := false
for i, path := range p.XTestImports { for i, path := range p.XTestImports {
p1 := loadImport(path, p.Dir, p, &stk, p.build.XTestImportPos[path], useVendor) p1 := load.LoadImport(path, p.Dir, p, &stk, p.Internal.Build.XTestImportPos[path], load.UseVendor)
if p1.Error != nil { if p1.Error != nil {
return nil, nil, nil, p1.Error return nil, nil, nil, p1.Error
} }
...@@ -707,7 +708,7 @@ func builderTest(b *builder, p *Package) (buildAction, runAction, printAction *a ...@@ -707,7 +708,7 @@ func builderTest(b *builder, p *Package) (buildAction, runAction, printAction *a
} }
p.XTestImports[i] = p1.ImportPath p.XTestImports[i] = p1.ImportPath
} }
stk.pop() stk.Pop()
// Use last element of import path, not package name. // Use last element of import path, not package name.
// They differ when package name is "main". // They differ when package name is "main".
...@@ -752,36 +753,36 @@ func builderTest(b *builder, p *Package) (buildAction, runAction, printAction *a ...@@ -752,36 +753,36 @@ func builderTest(b *builder, p *Package) (buildAction, runAction, printAction *a
// Test package. // Test package.
if len(p.TestGoFiles) > 0 || localCover || p.Name == "main" { if len(p.TestGoFiles) > 0 || localCover || p.Name == "main" {
ptest = new(Package) ptest = new(load.Package)
*ptest = *p *ptest = *p
ptest.GoFiles = nil ptest.GoFiles = nil
ptest.GoFiles = append(ptest.GoFiles, p.GoFiles...) ptest.GoFiles = append(ptest.GoFiles, p.GoFiles...)
ptest.GoFiles = append(ptest.GoFiles, p.TestGoFiles...) ptest.GoFiles = append(ptest.GoFiles, p.TestGoFiles...)
ptest.target = "" ptest.Internal.Target = ""
ptest.Imports = str.StringList(p.Imports, p.TestImports) ptest.Imports = str.StringList(p.Imports, p.TestImports)
ptest.imports = append(append([]*Package{}, p.imports...), imports...) ptest.Internal.Imports = append(append([]*load.Package{}, p.Internal.Imports...), imports...)
ptest.pkgdir = testDir ptest.Internal.Pkgdir = testDir
ptest.fake = true ptest.Internal.Fake = true
ptest.forceLibrary = true ptest.Internal.ForceLibrary = true
ptest.Stale = true ptest.Stale = true
ptest.StaleReason = "rebuild for test" ptest.StaleReason = "rebuild for test"
ptest.build = new(build.Package) ptest.Internal.Build = new(build.Package)
*ptest.build = *p.build *ptest.Internal.Build = *p.Internal.Build
m := map[string][]token.Position{} m := map[string][]token.Position{}
for k, v := range p.build.ImportPos { for k, v := range p.Internal.Build.ImportPos {
m[k] = append(m[k], v...) m[k] = append(m[k], v...)
} }
for k, v := range p.build.TestImportPos { for k, v := range p.Internal.Build.TestImportPos {
m[k] = append(m[k], v...) m[k] = append(m[k], v...)
} }
ptest.build.ImportPos = m ptest.Internal.Build.ImportPos = m
if localCover { if localCover {
ptest.coverMode = cfg.TestCoverMode ptest.Internal.CoverMode = cfg.TestCoverMode
var coverFiles []string var coverFiles []string
coverFiles = append(coverFiles, ptest.GoFiles...) coverFiles = append(coverFiles, ptest.GoFiles...)
coverFiles = append(coverFiles, ptest.CgoFiles...) coverFiles = append(coverFiles, ptest.CgoFiles...)
ptest.coverVars = declareCoverVars(ptest.ImportPath, coverFiles...) ptest.Internal.CoverVars = declareCoverVars(ptest.ImportPath, coverFiles...)
} }
} else { } else {
ptest = p ptest = p
...@@ -789,66 +790,74 @@ func builderTest(b *builder, p *Package) (buildAction, runAction, printAction *a ...@@ -789,66 +790,74 @@ func builderTest(b *builder, p *Package) (buildAction, runAction, printAction *a
// External test package. // External test package.
if len(p.XTestGoFiles) > 0 { if len(p.XTestGoFiles) > 0 {
pxtest = &Package{ pxtest = &load.Package{
Name: p.Name + "_test", PackagePublic: load.PackagePublic{
ImportPath: p.ImportPath + "_test", Name: p.Name + "_test",
localPrefix: p.localPrefix, ImportPath: p.ImportPath + "_test",
Root: p.Root, Root: p.Root,
Dir: p.Dir, Dir: p.Dir,
GoFiles: p.XTestGoFiles, GoFiles: p.XTestGoFiles,
Imports: p.XTestImports, Imports: p.XTestImports,
build: &build.Package{ Stale: true,
ImportPos: p.build.XTestImportPos, },
Internal: load.PackageInternal{
LocalPrefix: p.Internal.LocalPrefix,
Build: &build.Package{
ImportPos: p.Internal.Build.XTestImportPos,
},
Imports: ximports,
Pkgdir: testDir,
Fake: true,
External: true,
}, },
imports: ximports,
pkgdir: testDir,
fake: true,
external: true,
Stale: true,
} }
if pxtestNeedsPtest { if pxtestNeedsPtest {
pxtest.imports = append(pxtest.imports, ptest) pxtest.Internal.Imports = append(pxtest.Internal.Imports, ptest)
} }
} }
// Action for building pkg.test. // Action for building pkg.test.
pmain = &Package{ pmain = &load.Package{
Name: "main", PackagePublic: load.PackagePublic{
Dir: testDir, Name: "main",
GoFiles: []string{"_testmain.go"}, Dir: testDir,
ImportPath: "testmain", GoFiles: []string{"_testmain.go"},
Root: p.Root, ImportPath: "testmain",
build: &build.Package{Name: "main"}, Root: p.Root,
pkgdir: testDir, Stale: true,
fake: true, },
Stale: true, Internal: load.PackageInternal{
omitDWARF: !testC && !testNeedBinary, Build: &build.Package{Name: "main"},
Pkgdir: testDir,
Fake: true,
OmitDWARF: !testC && !testNeedBinary,
},
} }
// The generated main also imports testing, regexp, and os. // The generated main also imports testing, regexp, and os.
stk.push("testmain") stk.Push("testmain")
for dep := range testMainDeps { for dep := range testMainDeps {
if dep == ptest.ImportPath { if dep == ptest.ImportPath {
pmain.imports = append(pmain.imports, ptest) pmain.Internal.Imports = append(pmain.Internal.Imports, ptest)
} else { } else {
p1 := loadImport(dep, "", nil, &stk, nil, 0) p1 := load.LoadImport(dep, "", nil, &stk, nil, 0)
if p1.Error != nil { if p1.Error != nil {
return nil, nil, nil, p1.Error return nil, nil, nil, p1.Error
} }
pmain.imports = append(pmain.imports, p1) pmain.Internal.Imports = append(pmain.Internal.Imports, p1)
} }
} }
if testCoverPkgs != nil { if testCoverPkgs != nil {
// Add imports, but avoid duplicates. // Add imports, but avoid duplicates.
seen := map[*Package]bool{p: true, ptest: true} seen := map[*load.Package]bool{p: true, ptest: true}
for _, p1 := range pmain.imports { for _, p1 := range pmain.Internal.Imports {
seen[p1] = true seen[p1] = true
} }
for _, p1 := range testCoverPkgs { for _, p1 := range testCoverPkgs {
if !seen[p1] { if !seen[p1] {
seen[p1] = true seen[p1] = true
pmain.imports = append(pmain.imports, p1) pmain.Internal.Imports = append(pmain.Internal.Imports, p1)
} }
} }
} }
...@@ -862,11 +871,11 @@ func builderTest(b *builder, p *Package) (buildAction, runAction, printAction *a ...@@ -862,11 +871,11 @@ func builderTest(b *builder, p *Package) (buildAction, runAction, printAction *a
return nil, nil, nil, err return nil, nil, nil, err
} }
if len(ptest.GoFiles)+len(ptest.CgoFiles) > 0 { if len(ptest.GoFiles)+len(ptest.CgoFiles) > 0 {
pmain.imports = append(pmain.imports, ptest) pmain.Internal.Imports = append(pmain.Internal.Imports, ptest)
t.ImportTest = true t.ImportTest = true
} }
if pxtest != nil { if pxtest != nil {
pmain.imports = append(pmain.imports, pxtest) pmain.Internal.Imports = append(pmain.Internal.Imports, pxtest)
t.ImportXtest = true t.ImportXtest = true
} }
...@@ -896,9 +905,9 @@ func builderTest(b *builder, p *Package) (buildAction, runAction, printAction *a ...@@ -896,9 +905,9 @@ func builderTest(b *builder, p *Package) (buildAction, runAction, printAction *a
t.NeedOS = true t.NeedOS = true
} }
for _, cp := range pmain.imports { for _, cp := range pmain.Internal.Imports {
if len(cp.coverVars) > 0 { if len(cp.Internal.CoverVars) > 0 {
t.Cover = append(t.Cover, coverInfo{cp, cp.coverVars}) t.Cover = append(t.Cover, coverInfo{cp, cp.Internal.CoverVars})
} }
} }
...@@ -910,7 +919,7 @@ func builderTest(b *builder, p *Package) (buildAction, runAction, printAction *a ...@@ -910,7 +919,7 @@ func builderTest(b *builder, p *Package) (buildAction, runAction, printAction *a
} }
} }
computeStale(pmain) load.ComputeStale(pmain)
if ptest != p { if ptest != p {
a := b.action(modeBuild, modeBuild, ptest) a := b.action(modeBuild, modeBuild, ptest)
...@@ -1005,11 +1014,11 @@ func builderTest(b *builder, p *Package) (buildAction, runAction, printAction *a ...@@ -1005,11 +1014,11 @@ func builderTest(b *builder, p *Package) (buildAction, runAction, printAction *a
return buildAction, runAction, printAction, nil return buildAction, runAction, printAction, nil
} }
func testImportStack(top string, p *Package, target string) []string { func testImportStack(top string, p *load.Package, target string) []string {
stk := []string{top, p.ImportPath} stk := []string{top, p.ImportPath}
Search: Search:
for p.ImportPath != target { for p.ImportPath != target {
for _, p1 := range p.imports { for _, p1 := range p.Internal.Imports {
if p1.ImportPath == target || str.Contains(p1.Deps, target) { if p1.ImportPath == target || str.Contains(p1.Deps, target) {
stk = append(stk, p1.ImportPath) stk = append(stk, p1.ImportPath)
p = p1 p = p1
...@@ -1023,12 +1032,12 @@ Search: ...@@ -1023,12 +1032,12 @@ Search:
return stk return stk
} }
func recompileForTest(pmain, preal, ptest *Package, testDir string) { func recompileForTest(pmain, preal, ptest *load.Package, testDir string) {
// The "test copy" of preal is ptest. // The "test copy" of preal is ptest.
// For each package that depends on preal, make a "test copy" // For each package that depends on preal, make a "test copy"
// that depends on ptest. And so on, up the dependency tree. // that depends on ptest. And so on, up the dependency tree.
testCopy := map[*Package]*Package{preal: ptest} testCopy := map[*load.Package]*load.Package{preal: ptest}
for _, p := range packageList([]*Package{pmain}) { for _, p := range load.PackageList([]*load.Package{pmain}) {
// Copy on write. // Copy on write.
didSplit := false didSplit := false
split := func() { split := func() {
...@@ -1036,32 +1045,32 @@ func recompileForTest(pmain, preal, ptest *Package, testDir string) { ...@@ -1036,32 +1045,32 @@ func recompileForTest(pmain, preal, ptest *Package, testDir string) {
return return
} }
didSplit = true didSplit = true
if p.pkgdir != testDir { if p.Internal.Pkgdir != testDir {
p1 := new(Package) p1 := new(load.Package)
testCopy[p] = p1 testCopy[p] = p1
*p1 = *p *p1 = *p
p1.imports = make([]*Package, len(p.imports)) p1.Internal.Imports = make([]*load.Package, len(p.Internal.Imports))
copy(p1.imports, p.imports) copy(p1.Internal.Imports, p.Internal.Imports)
p = p1 p = p1
p.pkgdir = testDir p.Internal.Pkgdir = testDir
p.target = "" p.Internal.Target = ""
p.fake = true p.Internal.Fake = true
p.Stale = true p.Stale = true
p.StaleReason = "depends on package being tested" p.StaleReason = "depends on package being tested"
} }
} }
// Update p.deps and p.imports to use at test copies. // Update p.deps and p.Internal.Imports to use at test copies.
for i, dep := range p.deps { for i, dep := range p.Internal.Deps {
if p1 := testCopy[dep]; p1 != nil && p1 != dep { if p1 := testCopy[dep]; p1 != nil && p1 != dep {
split() split()
p.deps[i] = p1 p.Internal.Deps[i] = p1
} }
} }
for i, imp := range p.imports { for i, imp := range p.Internal.Imports {
if p1 := testCopy[imp]; p1 != nil && p1 != imp { if p1 := testCopy[imp]; p1 != nil && p1 != imp {
split() split()
p.imports[i] = p1 p.Internal.Imports[i] = p1
} }
} }
} }
...@@ -1078,13 +1087,13 @@ func isTestFile(file string) bool { ...@@ -1078,13 +1087,13 @@ func isTestFile(file string) bool {
// declareCoverVars attaches the required cover variables names // declareCoverVars attaches the required cover variables names
// to the files, to be used when annotating the files. // to the files, to be used when annotating the files.
func declareCoverVars(importPath string, files ...string) map[string]*CoverVar { func declareCoverVars(importPath string, files ...string) map[string]*load.CoverVar {
coverVars := make(map[string]*CoverVar) coverVars := make(map[string]*load.CoverVar)
for _, file := range files { for _, file := range files {
if isTestFile(file) { if isTestFile(file) {
continue continue
} }
coverVars[file] = &CoverVar{ coverVars[file] = &load.CoverVar{
File: filepath.Join(importPath, file), File: filepath.Join(importPath, file),
Var: fmt.Sprintf("GoCover_%d", coverIndex), Var: fmt.Sprintf("GoCover_%d", coverIndex),
} }
...@@ -1129,7 +1138,7 @@ func builderRunTest(b *builder, a *action) error { ...@@ -1129,7 +1138,7 @@ func builderRunTest(b *builder, a *action) error {
// If there are any local SWIG dependencies, we want to load // If there are any local SWIG dependencies, we want to load
// the shared library from the build directory. // the shared library from the build directory.
if a.p.usesSwig() { if a.p.UsesSwig() {
env := cmd.Env env := cmd.Env
found := false found := false
prefix := "LD_LIBRARY_PATH=" prefix := "LD_LIBRARY_PATH="
...@@ -1294,12 +1303,12 @@ func isTest(name, prefix string) bool { ...@@ -1294,12 +1303,12 @@ func isTest(name, prefix string) bool {
} }
type coverInfo struct { type coverInfo struct {
Package *Package Package *load.Package
Vars map[string]*CoverVar Vars map[string]*load.CoverVar
} }
// loadTestFuncs returns the testFuncs describing the tests that will be run. // loadTestFuncs returns the testFuncs describing the tests that will be run.
func loadTestFuncs(ptest *Package) (*testFuncs, error) { func loadTestFuncs(ptest *load.Package) (*testFuncs, error) {
t := &testFuncs{ t := &testFuncs{
Package: ptest, Package: ptest,
} }
...@@ -1336,7 +1345,7 @@ type testFuncs struct { ...@@ -1336,7 +1345,7 @@ type testFuncs struct {
Benchmarks []testFunc Benchmarks []testFunc
Examples []testFunc Examples []testFunc
TestMain *testFunc TestMain *testFunc
Package *Package Package *load.Package
ImportTest bool ImportTest bool
NeedTest bool NeedTest bool
ImportXtest bool ImportXtest bool
...@@ -1382,7 +1391,7 @@ var testFileSet = token.NewFileSet() ...@@ -1382,7 +1391,7 @@ var testFileSet = token.NewFileSet()
func (t *testFuncs) load(filename, pkg string, doImport, seen *bool) error { func (t *testFuncs) load(filename, pkg string, doImport, seen *bool) error {
f, err := parser.ParseFile(testFileSet, filename, nil, parser.ParseComments) f, err := parser.ParseFile(testFileSet, filename, nil, parser.ParseComments)
if err != nil { if err != nil {
return expandScanner(err) return base.ExpandScanner(err)
} }
for _, d := range f.Decls { for _, d := range f.Decls {
n, ok := d.(*ast.FuncDecl) n, ok := d.(*ast.FuncDecl)
......
...@@ -5,8 +5,8 @@ ...@@ -5,8 +5,8 @@
package main package main
import ( import (
"cmd/go/internal/cfg"
"cmd/go/internal/base" "cmd/go/internal/base"
"cmd/go/internal/cfg"
"flag" "flag"
"fmt" "fmt"
"os" "os"
......
...@@ -11,8 +11,8 @@ import ( ...@@ -11,8 +11,8 @@ import (
"sort" "sort"
"strings" "strings"
"cmd/go/internal/cfg"
"cmd/go/internal/base" "cmd/go/internal/base"
"cmd/go/internal/cfg"
) )
var cmdTool = &base.Command{ var cmdTool = &base.Command{
...@@ -72,7 +72,7 @@ func runTool(cmd *base.Command, args []string) { ...@@ -72,7 +72,7 @@ func runTool(cmd *base.Command, args []string) {
Stdout: os.Stdout, Stdout: os.Stdout,
Stderr: os.Stderr, Stderr: os.Stderr,
// Set $GOROOT, mainly for go tool dist. // Set $GOROOT, mainly for go tool dist.
Env: mergeEnvLists([]string{"GOROOT=" + goroot}, os.Environ()), Env: mergeEnvLists([]string{"GOROOT=" + cfg.GOROOT}, os.Environ()),
} }
err := toolCmd.Run() err := toolCmd.Run()
if err != nil { if err != nil {
......
...@@ -7,8 +7,9 @@ package main ...@@ -7,8 +7,9 @@ package main
import ( import (
"path/filepath" "path/filepath"
"cmd/go/internal/cfg"
"cmd/go/internal/base" "cmd/go/internal/base"
"cmd/go/internal/cfg"
"cmd/go/internal/load"
"cmd/go/internal/str" "cmd/go/internal/str"
) )
...@@ -38,7 +39,7 @@ See also: go fmt, go fix. ...@@ -38,7 +39,7 @@ See also: go fmt, go fix.
} }
func runVet(cmd *base.Command, args []string) { func runVet(cmd *base.Command, args []string) {
for _, p := range packages(args) { for _, p := range load.Packages(args) {
// Vet expects to be given a set of files all from the same package. // Vet expects to be given a set of files all from the same package.
// Run once for package p and once for package p_test. // Run once for package p and once for package p_test.
if len(p.GoFiles)+len(p.CgoFiles)+len(p.TestGoFiles) > 0 { if len(p.GoFiles)+len(p.CgoFiles)+len(p.TestGoFiles) > 0 {
...@@ -50,7 +51,7 @@ func runVet(cmd *base.Command, args []string) { ...@@ -50,7 +51,7 @@ func runVet(cmd *base.Command, args []string) {
} }
} }
func runVetFiles(p *Package, files []string) { func runVetFiles(p *load.Package, files []string) {
for i := range files { for i := range files {
files[i] = filepath.Join(p.Dir, files[i]) files[i] = filepath.Join(p.Dir, files[i])
} }
......
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