]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/go: split out cmd/go/internal/load
authorRuss Cox <rsc@golang.org>
Fri, 13 Jan 2017 21:24:19 +0000 (16:24 -0500)
committerRuss Cox <rsc@golang.org>
Fri, 3 Feb 2017 20:31:23 +0000 (20:31 +0000)
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/36196
Reviewed-by: David Crawshaw <crawshaw@golang.org>
24 files changed:
src/cmd/go/bug.go
src/cmd/go/build.go
src/cmd/go/clean.go
src/cmd/go/doc.go
src/cmd/go/env.go
src/cmd/go/fix.go
src/cmd/go/fmt.go
src/cmd/go/generate.go
src/cmd/go/get.go
src/cmd/go/internal/base/base.go
src/cmd/go/internal/cfg/cfg.go
src/cmd/go/internal/load/match_test.go [moved from src/cmd/go/match_test.go with 99% similarity]
src/cmd/go/internal/load/path.go [new file with mode: 0644]
src/cmd/go/internal/load/pkg.go [moved from src/cmd/go/pkg.go with 83% similarity]
src/cmd/go/internal/load/search.go [new file with mode: 0644]
src/cmd/go/internal/load/testgo.go [moved from src/cmd/go/testgo.go with 97% similarity]
src/cmd/go/list.go
src/cmd/go/main.go
src/cmd/go/pkg_test.go
src/cmd/go/run.go
src/cmd/go/test.go
src/cmd/go/testflag.go
src/cmd/go/tool.go
src/cmd/go/vet.go

index 60279c606044758dbca996167b5d4606baf8e01f..be64fe80ddffe91c829fe4f133a49dd80967d283 100644 (file)
@@ -6,8 +6,8 @@ package main
 
 import (
        "bytes"
-       "cmd/go/internal/cfg"
        "cmd/go/internal/base"
+       "cmd/go/internal/cfg"
        "fmt"
        "io"
        "io/ioutil"
index 848b648d8d6e3d22c1ead8cab0badc80d6941c5d..d8f400113ef66b285547c3e1392581aff3f46ad7 100644 (file)
@@ -30,6 +30,7 @@ import (
        "cmd/go/internal/base"
        "cmd/go/internal/buildid"
        "cmd/go/internal/cfg"
+       "cmd/go/internal/load"
        "cmd/go/internal/str"
 )
 
@@ -288,7 +289,7 @@ func (v *stringsFlag) String() string {
        return "<stringsFlag>"
 }
 
-func pkgsMain(pkgs []*Package) (res []*Package) {
+func pkgsMain(pkgs []*load.Package) (res []*load.Package) {
        for _, p := range pkgs {
                if p.Name == "main" {
                        res = append(res, p)
@@ -297,7 +298,7 @@ func pkgsMain(pkgs []*Package) (res []*Package) {
        return res
 }
 
-func pkgsNotMain(pkgs []*Package) (res []*Package) {
+func pkgsNotMain(pkgs []*load.Package) (res []*load.Package) {
        for _, p := range pkgs {
                if p.Name != "main" {
                        res = append(res, p)
@@ -306,7 +307,7 @@ func pkgsNotMain(pkgs []*Package) (res []*Package) {
        return res
 }
 
-var pkgsFilter = func(pkgs []*Package) []*Package { return pkgs }
+var pkgsFilter = func(pkgs []*load.Package) []*load.Package { return pkgs }
 
 func buildModeInit() {
        gccgo := cfg.BuildToolchainName == "gccgo"
@@ -316,7 +317,7 @@ func buildModeInit() {
        case "archive":
                pkgsFilter = pkgsNotMain
        case "c-archive":
-               pkgsFilter = func(p []*Package) []*Package {
+               pkgsFilter = func(p []*load.Package) []*load.Package {
                        if len(p) != 1 || p[0].Name != "main" {
                                base.Fatalf("-buildmode=c-archive requires exactly one main package")
                        }
@@ -450,7 +451,7 @@ func runBuild(cmd *base.Command, args []string) {
        var b builder
        b.init()
 
-       pkgs := packagesForBuild(args)
+       pkgs := load.PackagesForBuild(args)
 
        if len(pkgs) == 1 && pkgs[0].Name == "main" && cfg.BuildO == "" {
                _, cfg.BuildO = path.Split(pkgs[0].ImportPath)
@@ -489,7 +490,7 @@ func runBuild(cmd *base.Command, args []string) {
                        base.Fatalf("no packages to build")
                }
                p := pkgs[0]
-               p.target = cfg.BuildO
+               p.Internal.Target = cfg.BuildO
                p.Stale = true // must build - not up to date
                p.StaleReason = "build -o flag in use"
                a := b.action(modeInstall, depMode, p)
@@ -499,7 +500,7 @@ func runBuild(cmd *base.Command, args []string) {
 
        var a *action
        if cfg.BuildBuildmode == "shared" {
-               pkgs := pkgsFilter(packages(args))
+               pkgs := pkgsFilter(load.Packages(args))
                if libName, err := libname(args, pkgs); err != nil {
                        base.Fatalf("%s", err.Error())
                } else {
@@ -507,7 +508,7 @@ func runBuild(cmd *base.Command, args []string) {
                }
        } else {
                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))
                }
        }
@@ -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
 // -buildmode=shared. The rules we use are:
 // Use arguments for special 'meta' packages:
@@ -547,7 +543,7 @@ func isMetaPackage(name string) bool {
 //     gopkg.in/tomb.v2 -> libgopkg.in-tomb.v2.so
 //     a/... b/... ---> liba/c,b/d.so - all matching import paths
 // 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
        appendName := func(arg string) {
                if libname == "" {
@@ -558,7 +554,7 @@ func libname(args []string, pkgs []*Package) (string, error) {
        }
        var haveNonMeta bool
        for _, arg := range args {
-               if isMetaPackage(arg) {
+               if load.IsMetaPackage(arg) {
                        appendName(arg)
                } else {
                        haveNonMeta = true
@@ -594,20 +590,20 @@ func runInstall(cmd *base.Command, args []string) {
 }
 
 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")
        }
 
        instrumentInit()
        buildModeInit()
-       pkgs := pkgsFilter(packagesForBuild(args))
+       pkgs := pkgsFilter(load.PackagesForBuild(args))
 
        for _, p := range pkgs {
                if p.Target == "" && (!p.Standard || p.ImportPath != "unsafe") {
                        switch {
-                       case p.gobinSubdir:
+                       case p.Internal.GobinSubdir:
                                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)")
                        case 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) {
                        // cmd/cgo is handled specially in b.action, so that we can
                        // both build and use it in the same 'go install'.
                        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...)
                                action.deps = append(action.deps, a)
                                tools = append(tools, action)
@@ -717,7 +713,7 @@ type builder struct {
 
 // An action represents a single action in the action graph.
 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
        triggers   []*action     // inverse of deps
        cgo        *action       // action for cgo binary if needed
@@ -743,7 +739,7 @@ type action struct {
 // cacheKey is the key for the action cache.
 type cacheKey struct {
        mode  buildMode
-       p     *Package
+       p     *load.Package
        shlib string
 }
 
@@ -756,14 +752,6 @@ const (
        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() {
        var err error
        b.print = func(a ...interface{}) (int, error) {
@@ -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
 // 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
 // .go_export section.
-func readpkglist(shlibpath string) (pkgs []*Package) {
-       var stk importStack
+func readpkglist(shlibpath string) (pkgs []*load.Package) {
+       var stk load.ImportStack
        if cfg.BuildToolchainName == "gccgo" {
                f, _ := elf.Open(shlibpath)
                sect := f.Section(".go_export")
@@ -886,7 +793,7 @@ func readpkglist(shlibpath string) (pkgs []*Package) {
                        if strings.HasPrefix(t, "pkgpath ") {
                                t = strings.TrimPrefix(t, "pkgpath ")
                                t = strings.TrimSuffix(t, ";")
-                               pkgs = append(pkgs, loadPackage(t, &stk))
+                               pkgs = append(pkgs, load.LoadPackage(t, &stk))
                        }
                }
        } else {
@@ -897,7 +804,7 @@ func readpkglist(shlibpath string) (pkgs []*Package) {
                scanner := bufio.NewScanner(bytes.NewBuffer(pkglistbytes))
                for scanner.Scan() {
                        t := scanner.Text()
-                       pkgs = append(pkgs, loadPackage(t, &stk))
+                       pkgs = append(pkgs, load.LoadPackage(t, &stk))
                }
        }
        return
@@ -907,7 +814,7 @@ func readpkglist(shlibpath string) (pkgs []*Package) {
 // 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
 // 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, "")
 }
 
@@ -915,7 +822,7 @@ func (b *builder) action(mode buildMode, depMode buildMode, p *Package) *action
 // depMode is the action to use when building dependencies.
 // 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.
-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 := ""
        if lookshared {
                shlib = p.Shlib
@@ -940,13 +847,13 @@ func (b *builder) action1(mode buildMode, depMode buildMode, p *Package, looksha
                return a
        }
 
-       a = &action{p: p, pkgdir: p.build.PkgRoot}
-       if p.pkgdir != "" { // overrides p.t
-               a.pkgdir = p.pkgdir
+       a = &action{p: p, pkgdir: p.Internal.Build.PkgRoot}
+       if p.Internal.Pkgdir != "" { // overrides p.t
+               a.pkgdir = p.Internal.Pkgdir
        }
        b.actionCache[key] = a
 
-       for _, p1 := range p.imports {
+       for _, p1 := range p.Internal.Imports {
                if forShlib != "" {
                        // p is part of a shared library.
                        if p1.Shlib != "" && p1.Shlib != forShlib {
@@ -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.
        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" {
-                       var stk importStack
-                       p1 := loadPackage("cmd/cgo", &stk)
+                       var stk load.ImportStack
+                       p1 := load.LoadPackage("cmd/cgo", &stk)
                        if p1.Error != nil {
                                base.Fatalf("load cmd/cgo: %v", p1.Error)
                        }
@@ -992,23 +899,23 @@ func (b *builder) action1(mode buildMode, depMode buildMode, p *Package, looksha
                // gccgo standard library is "fake" too.
                if cfg.BuildToolchainName == "gccgo" {
                        // the target name is needed for cgo.
-                       a.target = p.target
+                       a.target = p.Internal.Target
                        return a
                }
        }
 
-       if !p.Stale && p.target != "" {
-               // p.Stale==false implies that p.target is up-to-date.
+       if !p.Stale && p.Internal.Target != "" {
+               // p.Stale==false implies that p.Internal.Target is up-to-date.
                // Record target name for use by actions depending on this one.
-               a.target = p.target
+               a.target = p.Internal.Target
                return a
        }
 
-       if p.local && p.target == "" {
+       if p.Internal.Local && p.Internal.Target == "" {
                // Imported via local path. No permanent target.
                mode = modeBuild
        }
-       work := p.pkgdir
+       work := p.Internal.Pkgdir
        if work == "" {
                work = b.work
        }
@@ -1020,10 +927,10 @@ func (b *builder) action1(mode buildMode, depMode buildMode, p *Package, looksha
        case modeInstall:
                a.f = (*builder).install
                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.
-               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"
                        if cfg.BuildContext.Compiler == "gccgo" {
                                // For the header file, remove the "lib"
@@ -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
                        // to create a top-level package named exe.
                        name := "a.out"
-                       if p.exeName != "" {
-                               name = p.exeName
-                       } else if cfg.Goos == "darwin" && cfg.BuildBuildmode == "c-shared" && p.target != "" {
+                       if p.Internal.ExeName != "" {
+                               name = p.Internal.ExeName
+                       } else if cfg.Goos == "darwin" && cfg.BuildBuildmode == "c-shared" && p.Internal.Target != "" {
                                // On OS X, the linker output name gets recorded in the
                                // shared library's LC_ID_DYLIB load command.
                                // The code invoking the linker knows to pass only the final
                                // path element. Arrange that the path element matches what
                                // 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
                }
@@ -1073,7 +980,7 @@ func (b *builder) action1(mode buildMode, depMode buildMode, p *Package, looksha
        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{}
        switch mode {
        default:
@@ -1083,7 +990,7 @@ func (b *builder) libaction(libname string, pkgs []*Package, mode, depMode build
                a.f = (*builder).linkShared
                a.target = filepath.Join(b.work, libname)
                for _, p := range pkgs {
-                       if p.target == "" {
+                       if p.Internal.Target == "" {
                                continue
                        }
                        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
                                seencgo = seencgo || (p.Standard && p.ImportPath == "runtime/cgo")
                        }
                        if !seencgo {
-                               var stk importStack
-                               p := loadPackage("runtime/cgo", &stk)
+                               var stk load.ImportStack
+                               p := load.LoadPackage("runtime/cgo", &stk)
                                if p.Error != nil {
                                        base.Fatalf("load runtime/cgo: %v", p.Error)
                                }
-                               computeStale(p)
+                               load.ComputeStale(p)
                                // If runtime/cgo is in another shared library, then that's
                                // also the shared library that contains runtime, so
                                // something will depend on it and so runtime/cgo's staleness
                                // will be checked when processing that library.
                                if p.Shlib == "" || p.Shlib == libname {
-                                       pkgs = append([]*Package{}, pkgs...)
+                                       pkgs = append([]*load.Package{}, pkgs...)
                                        pkgs = append(pkgs, p)
                                }
                        }
@@ -1122,18 +1029,18 @@ func (b *builder) libaction(libname string, pkgs []*Package, mode, depMode build
                                        seenmath = seenmath || (p.Standard && p.ImportPath == "math")
                                }
                                if !seenmath {
-                                       var stk importStack
-                                       p := loadPackage("math", &stk)
+                                       var stk load.ImportStack
+                                       p := load.LoadPackage("math", &stk)
                                        if p.Error != nil {
                                                base.Fatalf("load math: %v", p.Error)
                                        }
-                                       computeStale(p)
+                                       load.ComputeStale(p)
                                        // If math is in another shared library, then that's
                                        // also the shared library that contains runtime, so
                                        // something will depend on it and so math's staleness
                                        // will be checked when processing that library.
                                        if p.Shlib == "" || p.Shlib == libname {
-                                               pkgs = append([]*Package{}, pkgs...)
+                                               pkgs = append([]*load.Package{}, pkgs...)
                                                pkgs = append(pkgs, p)
                                        }
                                }
@@ -1143,7 +1050,7 @@ func (b *builder) libaction(libname string, pkgs []*Package, mode, depMode build
                // Figure out where the library will go.
                var libdir string
                for _, p := range pkgs {
-                       plibdir := p.build.PkgTargetRoot
+                       plibdir := p.Internal.Build.PkgTargetRoot
                        if gccgo {
                                plibdir = filepath.Join(plibdir, "shlibs")
                        }
@@ -1162,11 +1069,11 @@ func (b *builder) libaction(libname string, pkgs []*Package, mode, depMode build
                        built = fi.ModTime()
                }
                for _, p := range pkgs {
-                       if p.target == "" {
+                       if p.Internal.Target == "" {
                                continue
                        }
                        stale = stale || p.Stale
-                       lstat, err := os.Stat(p.target)
+                       lstat, err := os.Stat(p.Internal.Target)
                        if err != nil || lstat.ModTime().After(built) {
                                stale = true
                        }
@@ -1178,12 +1085,12 @@ func (b *builder) libaction(libname string, pkgs []*Package, mode, depMode build
                        buildAction := b.libaction(libname, pkgs, modeBuild, depMode)
                        a.deps = []*action{buildAction}
                        for _, p := range pkgs {
-                               if p.target == "" {
+                               if p.Internal.Target == "" {
                                        continue
                                }
                                shlibnameaction := &action{}
                                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)
                                shlibnameaction.deps = append(shlibnameaction.deps, buildAction)
                        }
@@ -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
        // cgo nor SWIG, since the CXX files can only be processed by cgo
        // 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",
                        a.p.ImportPath, strings.Join(a.p.CXXFiles, ","))
        }
        // 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",
                        a.p.ImportPath, strings.Join(a.p.MFiles, ","))
        }
        // 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",
                        a.p.ImportPath, strings.Join(a.p.FFiles, ","))
        }
@@ -1417,7 +1324,7 @@ func (b *builder) build(a *action) (err error) {
        sfiles = append(sfiles, a.p.SFiles...)
        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 {
                        return
                }
@@ -1426,7 +1333,7 @@ func (b *builder) build(a *action) (err error) {
        // Run SWIG on each .swig and .swigcxx 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.
-       if a.p.usesSwig() {
+       if a.p.UsesSwig() {
                outGo, outC, outCXX, err := b.swig(a.p, obj, pcCFLAGS)
                if err != nil {
                        return err
@@ -1437,7 +1344,7 @@ func (b *builder) build(a *action) (err error) {
        }
 
        // 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.
                // There is one exception: runtime/cgo's job is to bridge the
                // cgo and non-cgo worlds, so it necessarily has files in both.
@@ -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 a.p.coverMode != "" {
+       if a.p.Internal.CoverMode != "" {
                for i, file := range gofiles {
                        var sourceFile string
                        var coverFile string
@@ -1498,7 +1405,7 @@ func (b *builder) build(a *action) (err error) {
                                coverFile = filepath.Join(obj, file)
                                key = file
                        }
-                       cover := a.p.coverVars[key]
+                       cover := a.p.Internal.CoverVars[key]
                        if cover == nil || isTestFile(file) {
                                // Not covering this file.
                                continue
@@ -1648,7 +1555,7 @@ func splitPkgConfigOutput(out []byte) []string {
 }
 
 // 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 {
                var out []byte
                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) {
 func (b *builder) includeArgs(flag string, all []*action) []string {
        inc := []string{}
        incMap := map[string]bool{
-               b.work:    true, // handled later
-               gorootPkg: true,
-               "":        true, // ignore empty strings
+               b.work:        true, // handled later
+               cfg.GOROOTpkg: true,
+               "":            true, // ignore empty strings
        }
 
        // Look in the temporary space for results of test-specific actions.
@@ -1747,7 +1654,7 @@ func (b *builder) includeArgs(flag string, all []*action) []string {
                if a1.p == nil {
                        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
                        inc = append(inc, flag, dir)
                }
@@ -1762,8 +1669,8 @@ func (b *builder) includeArgs(flag string, all []*action) []string {
        // in the original GOPATH order.
        need := map[string]*build.Package{}
        for _, a1 := range all {
-               if a1.p != nil && a1.pkgdir == a1.p.build.PkgRoot {
-                       need[a1.p.build.Root] = a1.p.build
+               if a1.p != nil && a1.pkgdir == a1.p.Internal.Build.PkgRoot {
+                       need[a1.p.Internal.Build.Root] = a1.p.Internal.Build
                }
        }
        for _, root := range cfg.Gopath {
@@ -1778,9 +1685,9 @@ func (b *builder) includeArgs(flag string, all []*action) []string {
                if a1.p == nil {
                        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
-                       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
        return b.run(a.objdir, "cover "+a.p.ImportPath, nil,
                cfg.BuildToolexec,
                base.Tool("cover"),
-               "-mode", a.p.coverMode,
+               "-mode", a.p.Internal.CoverMode,
                "-var", varName,
                "-o", dst,
                src)
@@ -2218,19 +2125,19 @@ func mkAbs(dir, f string) string {
 type toolchain interface {
        // gc runs the compiler in a specific directory on a set of files
        // 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
        // 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
        // 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(basedir string, p *Package) string
+       pkgpath(basedir string, p *load.Package) string
        // pack runs the archive packer in a specific directory to create
        // an archive from a set of object files.
        // 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(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
@@ -2257,20 +2164,20 @@ func (noToolchain) linker() string {
        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()
 }
 
-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()
 }
 
-func (noToolchain) pkgpath(basedir string, p *Package) string {
+func (noToolchain) pkgpath(basedir string, p *load.Package) string {
        noCompiler()
        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()
 }
 
@@ -2282,7 +2189,7 @@ func (noToolchain) ldShared(b *builder, toplevelactions []*action, out string, a
        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()
 }
 
@@ -2297,7 +2204,7 @@ func (gcToolchain) linker() string {
        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 != "" {
                ofile = archive
        } else {
@@ -2332,8 +2239,8 @@ func (gcToolchain) gc(b *builder, p *Package, archive, obj string, asmhdr bool,
        if cfg.BuildContext.InstallSuffix != "" {
                gcargs = append(gcargs, "-installsuffix", cfg.BuildContext.InstallSuffix)
        }
-       if p.buildID != "" {
-               gcargs = append(gcargs, "-buildid", p.buildID)
+       if p.Internal.BuildID != "" {
+               gcargs = append(gcargs, "-buildid", p.Internal.BuildID)
        }
 
        for _, path := range p.Imports {
@@ -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 {
                args = append(args, "-pack")
        }
@@ -2359,9 +2266,9 @@ func (gcToolchain) gc(b *builder, p *Package, archive, obj string, asmhdr bool,
        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.
-       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}
        if p.ImportPath == "runtime" && cfg.Goarch == "386" {
                for _, arg := range buildAsmflags {
@@ -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
 // if run using newTool instead.
 // 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))
        copy(newArgs, args)
        newArgs[1] = base.Tool(newTool)
@@ -2408,12 +2315,12 @@ func toolVerify(b *builder, p *Package, newTool string, ofile string, args []int
        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")
        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
        for _, f := range ofiles {
                absOfiles = append(absOfiles, mkAbs(objDir, f))
@@ -2534,13 +2441,13 @@ func (gcToolchain) ld(b *builder, root *action, out string, allactions []*action
        if cfg.BuildContext.InstallSuffix != "" {
                ldflags = append(ldflags, "-installsuffix", cfg.BuildContext.InstallSuffix)
        }
-       if root.p.omitDWARF {
+       if root.p.Internal.OmitDWARF {
                ldflags = append(ldflags, "-w")
        }
        if cfg.BuildBuildmode == "plugin" {
                pluginpath := root.p.ImportPath
                if pluginpath == "command-line-arguments" {
-                       pluginpath = "plugin/unnamed-" + root.p.buildID
+                       pluginpath = "plugin/unnamed-" + root.p.Internal.BuildID
                }
                ldflags = append(ldflags, "-pluginpath", pluginpath)
        }
@@ -2557,8 +2464,8 @@ func (gcToolchain) ld(b *builder, root *action, out string, allactions []*action
        }
        ldflags = setextld(ldflags, compiler)
        ldflags = append(ldflags, "-buildmode="+ldBuildmode)
-       if root.p.buildID != "" {
-               ldflags = append(ldflags, "-buildid="+root.p.buildID)
+       if root.p.Internal.BuildID != "" {
+               ldflags = append(ldflags, "-buildid="+root.p.Internal.BuildID)
        }
        ldflags = append(ldflags, cfg.BuildLdflags...)
 
@@ -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)
 }
 
-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))
 }
 
@@ -2633,7 +2540,7 @@ func (gccgoToolchain) linker() string {
        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"
        ofile = obj + out
        gcargs := []string{"-g"}
@@ -2641,8 +2548,8 @@ func (tools gccgoToolchain) gc(b *builder, p *Package, archive, obj string, asmh
        if pkgpath := gccgoPkgpath(p); pkgpath != "" {
                gcargs = append(gcargs, "-fgo-pkgpath="+pkgpath)
        }
-       if p.localPrefix != "" {
-               gcargs = append(gcargs, "-fgo-relative-import-path="+p.localPrefix)
+       if p.Internal.LocalPrefix != "" {
+               gcargs = append(gcargs, "-fgo-relative-import-path="+p.Internal.LocalPrefix)
        }
        args := str.StringList(tools.compiler(), importArgs, "-c", gcargs, "-o", ofile, buildGccgoflags)
        for _, f := range gofiles {
@@ -2653,7 +2560,7 @@ func (tools gccgoToolchain) gc(b *builder, p *Package, archive, obj string, asmh
        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
        for _, sfile := range sfiles {
                ofile := obj + sfile[:len(sfile)-len(".s")] + ".o"
@@ -2673,14 +2580,14 @@ func (tools gccgoToolchain) asm(b *builder, p *Package, obj string, sfiles []str
        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")
        afile := filepath.Join(basedir, end)
        // add "lib" to the final element
        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
        for _, f := range ofiles {
                absOfiles = append(absOfiles, mkAbs(objDir, f))
@@ -2792,7 +2699,7 @@ func (tools gccgoToolchain) link(b *builder, root *action, out string, allaction
                        if !apackagePathsSeen[a.p.ImportPath] {
                                apackagePathsSeen[a.p.ImportPath] = true
                                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)
                                        if err != nil {
                                                return
@@ -2833,7 +2740,7 @@ func (tools gccgoToolchain) link(b *builder, root *action, out string, allaction
                if len(a.p.CgoFiles) > 0 {
                        usesCgo = true
                }
-               if a.p.usesSwig() {
+               if a.p.UsesSwig() {
                        usesCgo = true
                }
                if len(a.p.CXXFiles) > 0 || len(a.p.SwigCXXFiles) > 0 {
@@ -2964,8 +2871,8 @@ func (tools gccgoToolchain) ldShared(b *builder, toplevelactions []*action, out
        return tools.link(b, fakeRoot, out, allactions, "", nil, "shared", out)
 }
 
-func (tools gccgoToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error {
-       inc := filepath.Join(goroot, "pkg", "include")
+func (tools gccgoToolchain) cc(b *builder, p *load.Package, objdir, ofile, cfile string) error {
+       inc := filepath.Join(cfg.GOROOT, "pkg", "include")
        cfile = mkAbs(p.Dir, cfile)
        defs := []string{"-D", "GOOS_" + cfg.Goos, "-D", "GOARCH_" + cfg.Goarch}
        defs = append(defs, b.gccArchArgs()...)
@@ -2990,14 +2897,14 @@ func (tools gccgoToolchain) maybePIC(args []string) []string {
        return args
 }
 
-func gccgoPkgpath(p *Package) string {
-       if p.build.IsCommand() && !p.forceLibrary {
+func gccgoPkgpath(p *load.Package) string {
+       if p.Internal.Build.IsCommand() && !p.Internal.ForceLibrary {
                return ""
        }
        return p.ImportPath
 }
 
-func gccgoCleanPkgpath(p *Package) string {
+func gccgoCleanPkgpath(p *load.Package) string {
        clean := func(r rune) rune {
                switch {
                case 'A' <= r && r <= 'Z', 'a' <= r && r <= 'z',
@@ -3010,22 +2917,22 @@ func gccgoCleanPkgpath(p *Package) string {
 }
 
 // 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))
 }
 
 // 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))
 }
 
 // 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))
 }
 
 // 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)
        desc := p.ImportPath
        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
 }
 
 // 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
        if len(p.CXXFiles) > 0 || len(p.SwigCXXFiles) > 0 {
                cmd = b.gxxCmd(p.Dir)
@@ -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.
-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"
 
        cppflags = str.StringList(envList("CGO_CPPFLAGS", ""), p.CgoCPPFLAGS)
@@ -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
 // //go:cgo_import_dynamic directives for each symbol or library
 // 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"
        ofile := obj + "_cgo_main.o"
        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
 
 // collect partially links the object files outObj into a single
 // 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
        // filtered out as they are inapplicable and can cause some linkers
        // to fail.
@@ -3474,7 +3381,7 @@ func (b *builder) collect(p *Package, obj, ofile string, cgoLDFLAGS, outObj []st
 // Run SWIG on all SWIG input files.
 // TODO: Don't build a shared library, once SWIG emits the necessary
 // 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 {
                return nil, nil, nil, err
        }
@@ -3602,7 +3509,7 @@ func (b *builder) swigDoIntSize(obj string) (intsize string, err error) {
        }
        srcs := []string{src}
 
-       p := goFilesPackage(srcs)
+       p := load.GoFilesPackage(srcs)
 
        if _, _, e := buildToolchain.gc(b, p, "", obj, false, nil, srcs); e != nil {
                return "32", nil
@@ -3620,7 +3527,7 @@ func (b *builder) swigIntSize(obj string) (intsize string, err error) {
 }
 
 // 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)
        var cflags []string
        if cxx {
index 4895eda4e3431a09fce9ca940e55a8384e875ebe..ba62bd4d2e40d13390450566a024681ee955b4d1 100644 (file)
@@ -5,8 +5,9 @@
 package main
 
 import (
-       "cmd/go/internal/cfg"
        "cmd/go/internal/base"
+       "cmd/go/internal/cfg"
+       "cmd/go/internal/load"
        "fmt"
        "io/ioutil"
        "os"
@@ -77,12 +78,12 @@ func init() {
 }
 
 func runClean(cmd *base.Command, args []string) {
-       for _, pkg := range packagesAndErrors(args) {
+       for _, pkg := range load.PackagesAndErrors(args) {
                clean(pkg)
        }
 }
 
-var cleaned = map[*Package]bool{}
+var cleaned = map[*load.Package]bool{}
 
 // TODO: These are dregs left by Makefile-based builds.
 // Eventually, can stop deleting these.
@@ -107,7 +108,7 @@ var cleanExt = map[string]bool{
        ".so": true,
 }
 
-func clean(p *Package) {
+func clean(p *load.Package) {
        if cleaned[p] {
                return
        }
@@ -209,17 +210,17 @@ func clean(p *Package) {
                }
        }
 
-       if cleanI && p.target != "" {
+       if cleanI && p.Internal.Target != "" {
                if cfg.BuildN || cfg.BuildX {
-                       b.showcmd("", "rm -f %s", p.target)
+                       b.showcmd("", "rm -f %s", p.Internal.Target)
                }
                if !cfg.BuildN {
-                       removeFile(p.target)
+                       removeFile(p.Internal.Target)
                }
        }
 
        if cleanR {
-               for _, p1 := range p.imports {
+               for _, p1 := range p.Internal.Imports {
                        clean(p1)
                }
        }
index 338fec14d3243a79d0ac1f16f9ee920aadac23f2..5a71717a399305b6bbc7b33b49d0db991ca049b6 100644 (file)
@@ -7,8 +7,8 @@
 package main
 
 import (
-       "cmd/go/internal/cfg"
        "cmd/go/internal/base"
+       "cmd/go/internal/cfg"
 )
 
 var cmdDoc = &base.Command{
index e143ddb357c6ebfa6ce51f2f94d09d7a080b8774..1498ba5361f102b1494adf6b51a246524ace6598 100644 (file)
@@ -5,8 +5,9 @@
 package main
 
 import (
-       "cmd/go/internal/cfg"
        "cmd/go/internal/base"
+       "cmd/go/internal/cfg"
+       "cmd/go/internal/load"
        "fmt"
        "os"
        "runtime"
@@ -33,14 +34,14 @@ func mkEnv() []cfg.EnvVar {
 
        env := []cfg.EnvVar{
                {"GOARCH", cfg.Goarch},
-               {"GOBIN", gobin},
+               {"GOBIN", cfg.GOBIN},
                {"GOEXE", cfg.ExeSuffix},
                {"GOHOSTARCH", runtime.GOARCH},
                {"GOHOSTOS", runtime.GOOS},
                {"GOOS", cfg.Goos},
                {"GOPATH", cfg.BuildContext.GOPATH},
                {"GORACE", os.Getenv("GORACE")},
-               {"GOROOT", goroot},
+               {"GOROOT", cfg.GOROOT},
                {"GOTOOLDIR", base.ToolDir},
 
                // disable escape codes in clang errors
@@ -88,7 +89,7 @@ func findEnv(env []cfg.EnvVar, name string) string {
 func extraEnvVars() []cfg.EnvVar {
        var b builder
        b.init()
-       cppflags, cflags, cxxflags, fflags, ldflags := b.cflags(&Package{})
+       cppflags, cflags, cxxflags, fflags, ldflags := b.cflags(&load.Package{})
        return []cfg.EnvVar{
                {"PKG_CONFIG", b.pkgconfigCmd()},
                {"CGO_CFLAGS", strings.Join(cflags, " ")},
index bb8c34e14a990e360e5fe4e5308a897ca695d078..b94d067003e8e1f5b70c2092abea2b2f53a9ffa6 100644 (file)
@@ -5,8 +5,9 @@
 package main
 
 import (
-       "cmd/go/internal/cfg"
        "cmd/go/internal/base"
+       "cmd/go/internal/cfg"
+       "cmd/go/internal/load"
        "cmd/go/internal/str"
 )
 
@@ -27,10 +28,10 @@ See also: go fmt, go vet.
 }
 
 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
                // the command only applies to this package,
                // 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)))
        }
 }
index e59f5cb919a0955b55cb3191c7637364f6ed394c..169a653e7e4fb9447df820be8cea70f03ae51b3f 100644 (file)
@@ -5,8 +5,9 @@
 package main
 
 import (
-       "cmd/go/internal/cfg"
        "cmd/go/internal/base"
+       "cmd/go/internal/cfg"
+       "cmd/go/internal/load"
        "cmd/go/internal/str"
        "os"
        "path/filepath"
@@ -38,11 +39,11 @@ See also: go fix, go vet.
 
 func runFmt(cmd *base.Command, args []string) {
        gofmt := gofmtPath()
-       for _, pkg := range packages(args) {
+       for _, pkg := range load.Packages(args) {
                // Use pkg.gofiles instead of pkg.Dir so that
                // the command only applies to this package,
                // 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 {
                gofmt += base.ToolWindowsExtension
        }
 
-       gofmtPath := filepath.Join(gobin, gofmt)
+       gofmtPath := filepath.Join(cfg.GOBIN, gofmt)
        if _, err := os.Stat(gofmtPath); err == nil {
                return gofmtPath
        }
 
-       gofmtPath = filepath.Join(goroot, "bin", gofmt)
+       gofmtPath = filepath.Join(cfg.GOROOT, "bin", gofmt)
        if _, err := os.Stat(gofmtPath); err == nil {
                return gofmtPath
        }
index b89fc95342db481db4566185f525408dca21f553..63f1f6d19b0674562c5f22e74e80add03e651959 100644 (file)
@@ -7,8 +7,9 @@ package main
 import (
        "bufio"
        "bytes"
-       "cmd/go/internal/cfg"
        "cmd/go/internal/base"
+       "cmd/go/internal/cfg"
+       "cmd/go/internal/load"
        "fmt"
        "io"
        "log"
@@ -138,7 +139,7 @@ func init() {
 }
 
 func runGenerate(cmd *base.Command, args []string) {
-       ignoreImports = true
+       load.IgnoreImports = true
 
        if generateRunFlag != "" {
                var err error
@@ -148,8 +149,8 @@ func runGenerate(cmd *base.Command, args []string) {
                }
        }
        // Even if the arguments are .go files, this loop suffices.
-       for _, pkg := range packages(args) {
-               for _, file := range pkg.gofiles {
+       for _, pkg := range load.Packages(args) {
+               for _, file := range pkg.Internal.GoFiles {
                        if !generate(pkg.Name, file) {
                                break
                        }
index 45c538d302d99fde49f46f32a48de4a85d612d30..23fae8d53f2e123b128fa0aa0f18659cade28fcd 100644 (file)
@@ -5,8 +5,9 @@
 package main
 
 import (
-       "cmd/go/internal/cfg"
        "cmd/go/internal/base"
+       "cmd/go/internal/cfg"
+       "cmd/go/internal/load"
        "cmd/go/internal/str"
        "fmt"
        "go/build"
@@ -119,10 +120,10 @@ func runGet(cmd *base.Command, args []string) {
        }
 
        // Phase 1.  Download/update.
-       var stk importStack
+       var stk load.ImportStack
        mode := 0
        if *getT {
-               mode |= getTestDeps
+               mode |= load.GetTestDeps
        }
        args = downloadPaths(args)
        for _, arg := range args {
@@ -137,20 +138,16 @@ func runGet(cmd *base.Command, args []string) {
        // the information will be recomputed. Instead of keeping
        // track of the reverse dependency information, evict
        // everything.
-       for name := range packageCache {
-               delete(packageCache, name)
-       }
+       load.ClearPackageCache()
 
        // In order to rebuild packages information completely,
        // we need to clear commands cache. Command packages are
        // referring to evicted packages from the package cache.
        // This leads to duplicated loads of the standard packages.
-       for name := range cmdCache {
-               delete(cmdCache, name)
-       }
+       load.ClearCmdCache()
 
-       args = importPaths(args)
-       packagesForBuild(args)
+       args = load.ImportPaths(args)
+       load.PackagesForBuild(args)
 
        // Phase 3.  Install.
        if *getD {
@@ -169,7 +166,7 @@ func runGet(cmd *base.Command, args []string) {
 // in the hope that we can figure out the repository from the
 // initial ...-free prefix.
 func downloadPaths(args []string) []string {
-       args = importPathsNoDotExpansion(args)
+       args = load.ImportPathsNoDotExpansion(args)
        var out []string
        for _, a := range args {
                if strings.Contains(a, "...") {
@@ -178,9 +175,9 @@ func downloadPaths(args []string) []string {
                        // warnings. They will be printed by the
                        // eventual call to importPaths instead.
                        if build.IsLocalImport(a) {
-                               expand = matchPackagesInFS(a)
+                               expand = load.MatchPackagesInFS(a)
                        } else {
-                               expand = matchPackages(a)
+                               expand = load.MatchPackages(a)
                        }
                        if len(expand) > 0 {
                                out = append(out, expand...)
@@ -207,20 +204,20 @@ var downloadRootCache = map[string]bool{}
 
 // download runs the download half of the get command
 // for the package named by the argument.
-func download(arg string, parent *Package, stk *importStack, mode int) {
-       if mode&useVendor != 0 {
+func download(arg string, parent *load.Package, stk *load.ImportStack, mode int) {
+       if mode&load.UseVendor != 0 {
                // Caller is responsible for expanding vendor paths.
                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 {
-                       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)
-       if p.Error != nil && p.Error.hard {
+       p := load1(arg, mode)
+       if p.Error != nil && p.Error.Hard {
                base.Errorf("%s", p.Error)
                return
        }
@@ -243,26 +240,26 @@ func download(arg string, parent *Package, stk *importStack, mode int) {
        // Only process each package once.
        // (Unless we're fetching test dependencies for this package,
        // in which case we want to process it again.)
-       if downloadCache[arg] && mode&getTestDeps == 0 {
+       if downloadCache[arg] && mode&load.GetTestDeps == 0 {
                return
        }
        downloadCache[arg] = true
 
-       pkgs := []*Package{p}
+       pkgs := []*load.Package{p}
        wildcardOkay := len(*stk) == 0
        isWildcard := false
 
        // Download if the package is missing, or update if we're using -u.
        if p.Dir == "" || *getU {
                // The actual download.
-               stk.push(arg)
+               stk.Push(arg)
                err := downloadPackage(p)
                if err != nil {
-                       base.Errorf("%s", &PackageError{ImportStack: stk.copy(), Err: err.Error()})
-                       stk.pop()
+                       base.Errorf("%s", &load.PackageError{ImportStack: stk.Copy(), Err: err.Error()})
+                       stk.Pop()
                        return
                }
-               stk.pop()
+               stk.Pop()
 
                args := []string{arg}
                // 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) {
                // for p has been replaced in the package cache.
                if wildcardOkay && strings.Contains(arg, "...") {
                        if build.IsLocalImport(arg) {
-                               args = matchPackagesInFS(arg)
+                               args = load.MatchPackagesInFS(arg)
                        } else {
-                               args = matchPackages(arg)
+                               args = load.MatchPackages(arg)
                        }
                        isWildcard = true
                }
 
                // Clear all relevant package cache entries before
                // doing any new loads.
-               for _, arg := range args {
-                       p := packageCache[arg]
-                       if p != nil {
-                               delete(packageCache, p.Dir)
-                               delete(packageCache, p.ImportPath)
-                       }
-               }
+               load.ClearPackageCachePartial(args)
 
                pkgs = pkgs[:0]
                for _, arg := range args {
                        // Note: load calls loadPackage or loadImport,
                        // which push arg onto stk already.
                        // 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 {
                                base.Errorf("%s", p.Error)
                                continue
@@ -305,10 +296,10 @@ func download(arg string, parent *Package, stk *importStack, mode int) {
        // due to wildcard expansion.
        for _, p := range pkgs {
                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.
-                       p = reloadPackage(arg, stk)
+                       p = load.ReloadPackage(arg, stk)
                        if p.Error != nil {
                                base.Errorf("%s", p.Error)
                                return
@@ -318,12 +309,12 @@ func download(arg string, parent *Package, stk *importStack, mode int) {
                if isWildcard {
                        // Report both the real package and the
                        // wildcard in any error message.
-                       stk.push(p.ImportPath)
+                       stk.Push(p.ImportPath)
                }
 
                // Process dependencies, now that we know what they are.
                imports := p.Imports
-               if mode&getTestDeps != 0 {
+               if mode&load.GetTestDeps != 0 {
                        // Process test dependencies when -t is specified.
                        // (But don't get test dependencies for test dependencies:
                        // we always pass mode 0 to the recursive calls below.)
@@ -335,18 +326,18 @@ func download(arg string, parent *Package, stk *importStack, mode int) {
                        }
                        // Fail fast on import naming full vendor path.
                        // 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
-                       if i < len(p.build.Imports) {
-                               orig = p.build.Imports[i]
+                       if i < len(p.Internal.Build.Imports) {
+                               orig = p.Internal.Build.Imports[i]
                        }
-                       if j, ok := findVendor(orig); ok {
-                               stk.push(path)
-                               err := &PackageError{
-                                       ImportStack: stk.copy(),
+                       if j, ok := load.FindVendor(orig); ok {
+                               stk.Push(path)
+                               err := &load.PackageError{
+                                       ImportStack: stk.Copy(),
                                        Err:         "must be imported as " + path[j+len("vendor/"):],
                                }
-                               stk.pop()
+                               stk.Pop()
                                base.Errorf("%s", err)
                                continue
                        }
@@ -355,20 +346,20 @@ func download(arg string, parent *Package, stk *importStack, mode int) {
                        // download does caching based on the value of path,
                        // so it must be the fully qualified path already.
                        if i >= len(p.Imports) {
-                               path = vendoredImportPath(p, path)
+                               path = load.VendoredImportPath(p, path)
                        }
                        download(path, p, stk, 0)
                }
 
                if isWildcard {
-                       stk.pop()
+                       stk.Pop()
                }
        }
 }
 
 // downloadPackage runs the create or download command
 // 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 (
                vcs            *vcsCmd
                repo, rootPath string
@@ -380,9 +371,9 @@ func downloadPackage(p *Package) error {
                security = insecure
        }
 
-       if p.build.SrcRoot != "" {
+       if p.Internal.Build.SrcRoot != "" {
                // 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 {
                        return err
                }
@@ -390,7 +381,7 @@ func downloadPackage(p *Package) error {
 
                // Double-check where it came from.
                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)
                        if err != nil {
                                return err
@@ -424,24 +415,24 @@ func downloadPackage(p *Package) error {
                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.
                list := filepath.SplitList(cfg.BuildContext.GOPATH)
                if len(list) == 0 {
                        return fmt.Errorf("cannot download, $GOPATH not set. For more details see: 'go help gopath'")
                }
                // 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'")
                }
                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])
                }
-               p.build.Root = list[0]
-               p.build.SrcRoot = filepath.Join(list[0], "src")
-               p.build.PkgRoot = filepath.Join(list[0], "pkg")
+               p.Internal.Build.Root = list[0]
+               p.Internal.Build.SrcRoot = filepath.Join(list[0], "src")
+               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 downloadRootCache[root] {
                return nil
@@ -467,7 +458,7 @@ func downloadPackage(p *Package) error {
                        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
 
                // Some version control tools require the parent of the target to exist.
@@ -475,8 +466,8 @@ func downloadPackage(p *Package) error {
                if err = os.MkdirAll(parent, 0777); err != nil {
                        return err
                }
-               if cfg.BuildV && !gopathExisted && p.build.Root == cfg.BuildContext.GOPATH {
-                       fmt.Fprintf(os.Stderr, "created GOPATH=%s; see 'go help gopath'\n", p.build.Root)
+               if cfg.BuildV && !gopathExisted && p.Internal.Build.Root == cfg.BuildContext.GOPATH {
+                       fmt.Fprintf(os.Stderr, "created GOPATH=%s; see 'go help gopath'\n", p.Internal.Build.Root)
                }
 
                if err = vcs.create(root, repo); err != nil {
index 4638a99eda3365717d8c2d55c7458b8d39080d7f..3d04880acdd06029889c08d9abe4b7ea0850c90f 100644 (file)
@@ -7,10 +7,13 @@
 package base
 
 import (
+       "bytes"
        "cmd/go/internal/cfg"
        "cmd/go/internal/str"
+       "errors"
        "flag"
        "fmt"
+       "go/scanner"
        "log"
        "os"
        "os/exec"
@@ -145,3 +148,25 @@ func RunStdin(cmdline []string) {
 // Usage is the usage-reporting function, filled in by package main
 // but here for reference by other packages.
 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
+}
index c6cb2ce3db70e2385b86f4c2b72273d0654a02f5..19d648b1938d5fd2d329d4224617dbba4cbcdb1e 100644 (file)
@@ -9,6 +9,8 @@ package cfg
 import (
        "flag"
        "go/build"
+       "os"
+       "path/filepath"
        "runtime"
 )
 
@@ -64,3 +66,11 @@ func AddBuildFlagsNX(flags *flag.FlagSet) {
        flags.BoolVar(&BuildN, "n", 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")
+)
similarity index 99%
rename from src/cmd/go/match_test.go
rename to src/cmd/go/internal/load/match_test.go
index e0ad562384db15e5a74b18bfecf1854349f66363..dc05cbb17e4220f5c92cd18130c683cd60aa5e39 100644 (file)
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package main
+package load
 
 import "testing"
 
diff --git a/src/cmd/go/internal/load/path.go b/src/cmd/go/internal/load/path.go
new file mode 100644 (file)
index 0000000..9cc85dd
--- /dev/null
@@ -0,0 +1,80 @@
+// 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
+       }
+}
similarity index 83%
rename from src/cmd/go/pkg.go
rename to src/cmd/go/internal/load/pkg.go
index e9b73667a402689bd43ea9518958b9d0c3bfc46e..3b149946cb007ba8e609e7e6d95d6cceb55a8cee 100644 (file)
@@ -2,15 +2,13 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package main
+// Package load loads packages.
+package load
 
 import (
-       "bytes"
        "crypto/sha1"
-       "errors"
        "fmt"
        "go/build"
-       "go/scanner"
        "go/token"
        "io/ioutil"
        "os"
@@ -27,10 +25,15 @@ import (
        "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.
 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.
        // See list.go. It is okay to add fields, but not to change or
        // remove existing ones. Keep in sync with list.go
@@ -85,31 +88,33 @@ type Package struct {
        TestImports  []string `json:",omitempty"` // imports from TestGoFiles
        XTestGoFiles []string `json:",omitempty"` // _test.go files outside package
        XTestImports []string `json:",omitempty"` // imports from XTestGoFiles
+}
 
+type PackageInternal struct {
        // Unexported fields are not part of the public API.
-       build        *build.Package
-       pkgdir       string // overrides build.PkgDir
-       imports      []*Package
-       deps         []*Package
-       gofiles      []string // GoFiles+CgoFiles+TestGoFiles+XTestGoFiles files, absolute paths
-       sfiles       []string
-       allgofiles   []string             // gofiles + IgnoredGoFiles, absolute paths
-       target       string               // installed file for this package (may be executable)
-       fake         bool                 // synthesized package
-       external     bool                 // synthesized external test package
-       forceLibrary bool                 // this package is a library (even if named "main")
-       cmdline      bool                 // defined by files listed on command line
-       local        bool                 // imported via local path (./ or ../)
-       localPrefix  string               // interpret ./ and ../ imports relative to this prefix
-       exeName      string               // desired name for temporary executable
-       coverMode    string               // preprocess Go source files with the coverage tool in this mode
-       coverVars    map[string]*CoverVar // variables created by coverage analysis
-       omitDWARF    bool                 // tell linker not to write DWARF information
-       buildID      string               // expected build ID for generated package
-       gobinSubdir  bool                 // install target would be subdir of GOBIN
+       Build        *build.Package
+       Pkgdir       string // overrides build.PkgDir
+       Imports      []*Package
+       Deps         []*Package
+       GoFiles      []string // GoFiles+CgoFiles+TestGoFiles+XTestGoFiles files, absolute paths
+       SFiles       []string
+       AllGoFiles   []string             // gofiles + IgnoredGoFiles, absolute paths
+       Target       string               // installed file for this package (may be executable)
+       Fake         bool                 // synthesized package
+       External     bool                 // synthesized external test package
+       ForceLibrary bool                 // this package is a library (even if named "main")
+       Cmdline      bool                 // defined by files listed on command line
+       Local        bool                 // imported via local path (./ or ../)
+       LocalPrefix  string               // interpret ./ and ../ imports relative to this prefix
+       ExeName      string               // desired name for temporary executable
+       CoverMode    string               // preprocess Go source files with the coverage tool in this mode
+       CoverVars    map[string]*CoverVar // variables created by coverage analysis
+       OmitDWARF    bool                 // tell linker not to write DWARF information
+       BuildID      string               // expected build ID for generated package
+       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.
 // 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
@@ -119,14 +124,14 @@ type Package struct {
 // 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 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] {
                panic("internal error: p.vendored(p.Imports) called")
        }
        seen := make(map[string]bool)
        var all []string
        for _, path := range imports {
-               path = vendoredImportPath(p, path)
+               path = VendoredImportPath(p, path)
                if !seen[path] {
                        seen[path] = true
                        all = append(all, path)
@@ -143,7 +148,7 @@ type CoverVar struct {
 }
 
 func (p *Package) copyBuild(pp *build.Package) {
-       p.build = pp
+       p.Internal.Build = pp
 
        if pp.PkgTargetRoot != "" && cfg.BuildPkgdir != "" {
                old := pp.PkgTargetRoot
@@ -188,7 +193,7 @@ func (p *Package) copyBuild(pp *build.Package) {
        p.TestImports = pp.TestImports
        p.XTestGoFiles = pp.XTestGoFiles
        p.XTestImports = pp.XTestImports
-       if ignoreImports {
+       if IgnoreImports {
                p.Imports = nil
                p.TestImports = nil
                p.XTestImports = nil
@@ -213,13 +218,13 @@ type PackageError struct {
        ImportStack   []string // shortest path from package named on command line to this one
        Pos           string   // position of error
        Err           string   // the error itself
-       isImportCycle bool     // the error is an import cycle
-       hard          bool     // whether the error is soft or hard; soft errors are ignored in some places
+       IsImportCycle bool     `json:"-"` // the error is an import cycle
+       Hard          bool     `json:"-"` // whether the error is soft or hard; soft errors are ignored in some places
 }
 
 func (p *PackageError) Error() string {
        // 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 "))
        }
        if p.Pos != "" {
@@ -233,25 +238,25 @@ func (p *PackageError) Error() string {
        return "package " + strings.Join(p.ImportStack, "\n\timports ") + ": " + p.Err
 }
 
-// An importStack is a stack of import paths.
-type importStack []string
+// An ImportStack is a stack of import paths.
+type ImportStack []string
 
-func (s *importStack) push(p string) {
+func (s *ImportStack) Push(p string) {
        *s = append(*s, p)
 }
 
-func (s *importStack) pop() {
+func (s *ImportStack) Pop() {
        *s = (*s)[0 : len(*s)-1]
 }
 
-func (s *importStack) copy() []string {
+func (s *ImportStack) Copy() []string {
        return append([]string{}, *s...)
 }
 
 // shorterThan reports whether sp is shorter than t.
 // We use this to record the shortest import sequence
 // that leads to a particular package.
-func (sp *importStack) shorterThan(t []string) bool {
+func (sp *ImportStack) shorterThan(t []string) bool {
        s := *sp
        if len(s) != len(t) {
                return len(s) < len(t)
@@ -270,15 +275,31 @@ func (sp *importStack) shorterThan(t []string) bool {
 // we return the same pointer each time.
 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
 // not to use the package cache.
-func reloadPackage(arg string, stk *importStack) *Package {
+func ReloadPackage(arg string, stk *ImportStack) *Package {
        p := packageCache[arg]
        if p != nil {
                delete(packageCache, p.Dir)
                delete(packageCache, p.ImportPath)
        }
-       return loadPackage(arg, stk)
+       return LoadPackage(arg, stk)
 }
 
 // dirToImportPath returns the pseudo-import path we use for a package
@@ -312,20 +333,20 @@ const (
        // recorded as the canonical import path. At that point, future loads
        // of that package must not pass useVendor, because
        // 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
        // that test dependencies should be fetched too.
-       getTestDeps
+       GetTestDeps
 )
 
 // 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
 // with ./ or ../).  A local relative path is interpreted relative to srcDir.
 // 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 {
-       stk.push(path)
-       defer stk.pop()
+func LoadImport(path, srcDir string, parent *Package, stk *ImportStack, importPos []token.Position, mode int) *Package {
+       stk.Push(path)
+       defer stk.Pop()
 
        // Determine canonical identifier for this package.
        // 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
        isLocal := build.IsLocalImport(path)
        if isLocal {
                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
                // find out the key to use in packageCache without the
                // overhead of repeated calls to buildContext.Import.
                // The code is also needed in a few other places anyway.
-               path = vendoredImportPath(parent, path)
+               path = VendoredImportPath(parent, path)
                importPath = path
        }
 
@@ -351,7 +372,7 @@ func loadImport(path, srcDir string, parent *Package, stk *importStack, importPo
                p = reusePackage(p, stk)
        } else {
                p = new(Package)
-               p.local = isLocal
+               p.Internal.Local = isLocal
                p.ImportPath = importPath
                packageCache[importPath] = p
 
@@ -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.
                // See issue 3268 for mistakes to avoid.
                buildMode := build.ImportComment
-               if mode&useVendor == 0 || path != origPath {
+               if mode&UseVendor == 0 || path != origPath {
                        // Not vendoring, or we already found the vendored path.
                        buildMode |= build.IgnoreVendor
                }
                bp, err := cfg.BuildContext.Import(path, srcDir, buildMode)
                bp.ImportPath = importPath
-               if gobin != "" {
-                       bp.BinDir = gobin
+               if cfg.GOBIN != "" {
+                       bp.BinDir = cfg.GOBIN
                }
                if err == nil && !isLocal && bp.ImportComment != "" && bp.ImportComment != path &&
                        !strings.Contains(path, "/vendor/") && !strings.HasPrefix(path, "vendor/") {
@@ -382,7 +403,7 @@ func loadImport(path, srcDir string, parent *Package, stk *importStack, importPo
 
                if origPath != cleanImport(origPath) {
                        p.Error = &PackageError{
-                               ImportStack: stk.copy(),
+                               ImportStack: stk.Copy(),
                                Err:         fmt.Sprintf("non-canonical import path: %q should be %q", origPath, pathpkg.Clean(origPath)),
                        }
                        p.Incomplete = true
@@ -393,7 +414,7 @@ func loadImport(path, srcDir string, parent *Package, stk *importStack, importPo
        if perr := disallowInternal(srcDir, p, stk); perr != p {
                return setErrorPos(perr, importPos)
        }
-       if mode&useVendor != 0 {
+       if mode&UseVendor != 0 {
                if perr := disallowVendor(srcDir, origPath, p, stk); perr != p {
                        return setErrorPos(perr, importPos)
                }
@@ -402,16 +423,16 @@ func loadImport(path, srcDir string, parent *Package, stk *importStack, importPo
        if p.Name == "main" && parent != nil && parent.Dir != p.Dir {
                perr := *p
                perr.Error = &PackageError{
-                       ImportStack: stk.copy(),
+                       ImportStack: stk.Copy(),
                        Err:         fmt.Sprintf("import %q is a program, not an importable package", path),
                }
                return setErrorPos(&perr, importPos)
        }
 
-       if p.local && parent != nil && !parent.local {
+       if p.Internal.Local && parent != nil && !parent.Internal.Local {
                perr := *p
                perr.Error = &PackageError{
-                       ImportStack: stk.copy(),
+                       ImportStack: stk.Copy(),
                        Err:         fmt.Sprintf("local import %q in non-local package", path),
                }
                return setErrorPos(&perr, importPos)
@@ -452,11 +473,11 @@ func isDir(path string) bool {
        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,
 // 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.
-func vendoredImportPath(parent *Package, path string) (found string) {
+// VendoredImportPath returns the expanded path or, if no expansion is found, the original.
+func VendoredImportPath(parent *Package, path string) (found string) {
        if parent == nil || parent.Root == "" {
                return path
        }
@@ -469,7 +490,7 @@ func vendoredImportPath(parent *Package, path string) (found string) {
                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"+
                        "       import path: %s\n"+
                        "       root: %s\n"+
@@ -544,24 +565,24 @@ func hasGoFiles(dir string) bool {
 // reusePackage reuses package p to satisfy the import at the top
 // of the import stack stk. If this use causes an import loop,
 // reusePackage updates p's error information to record the loop.
-func reusePackage(p *Package, stk *importStack) *Package {
-       // We use p.imports==nil to detect a package that
+func reusePackage(p *Package, stk *ImportStack) *Package {
+       // We use p.Internal.Imports==nil to detect a package that
        // is in the midst of its own loadPackage call
-       // (all the recursion below happens before p.imports gets set).
-       if p.imports == nil {
+       // (all the recursion below happens before p.Internal.Imports gets set).
+       if p.Internal.Imports == nil {
                if p.Error == nil {
                        p.Error = &PackageError{
-                               ImportStack:   stk.copy(),
+                               ImportStack:   stk.Copy(),
                                Err:           "import cycle not allowed",
-                               isImportCycle: true,
+                               IsImportCycle: true,
                        }
                }
                p.Incomplete = true
        }
        // 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 p.Error != nil && !p.Error.isImportCycle && stk.shorterThan(p.Error.ImportStack) {
-               p.Error.ImportStack = stk.copy()
+       if p.Error != nil && !p.Error.IsImportCycle && stk.shorterThan(p.Error.ImportStack) {
+               p.Error.ImportStack = stk.Copy()
        }
        return p
 }
@@ -569,7 +590,7 @@ func reusePackage(p *Package, stk *importStack) *Package {
 // disallowInternal checks that srcDir is allowed to import p.
 // If the import is allowed, disallowInternal returns the original package p.
 // If not, it returns a new package containing just an appropriate error.
-func disallowInternal(srcDir string, p *Package, stk *importStack) *Package {
+func disallowInternal(srcDir string, p *Package, stk *ImportStack) *Package {
        // golang.org/s/go14internal:
        // An import of a path containing the element “internal”
        // is disallowed if the importing code is outside the tree
@@ -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.
        perr := *p
        perr.Error = &PackageError{
-               ImportStack: stk.copy(),
+               ImportStack: stk.Copy(),
                Err:         "use of internal package not allowed",
        }
        perr.Incomplete = true
@@ -656,7 +677,7 @@ func findInternal(path string) (index int, ok bool) {
 // disallowVendor checks that srcDir is allowed to import p as path.
 // If the import is allowed, disallowVendor returns the original package p.
 // If not, it returns a new package containing just an appropriate error.
-func disallowVendor(srcDir, path string, p *Package, stk *importStack) *Package {
+func disallowVendor(srcDir, path string, p *Package, stk *ImportStack) *Package {
        // The stack includes p.ImportPath.
        // If that's the only thing on the stack, we started
        // with a name given on the command line, not an
@@ -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.
-       if i, ok := findVendor(path); ok {
+       if i, ok := FindVendor(path); ok {
                perr := *p
                perr.Error = &PackageError{
-                       ImportStack: stk.copy(),
+                       ImportStack: stk.Copy(),
                        Err:         "must be imported as " + path[i+len("vendor/"):],
                }
                perr.Incomplete = true
@@ -688,7 +709,7 @@ func disallowVendor(srcDir, path string, p *Package, stk *importStack) *Package
 // is not subject to the rules, only subdirectories of vendor.
 // This allows people to have packages and commands named vendor,
 // 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.
        // If that's the only thing on the stack, we started
        // with a name given on the command line, not an
@@ -698,7 +719,7 @@ func disallowVendorVisibility(srcDir string, p *Package, stk *importStack) *Pack
        }
 
        // Check for "vendor" element.
-       i, ok := findVendor(p.ImportPath)
+       i, ok := FindVendor(p.ImportPath)
        if !ok {
                return p
        }
@@ -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.
        perr := *p
        perr.Error = &PackageError{
-               ImportStack: stk.copy(),
+               ImportStack: stk.Copy(),
                Err:         "use of vendored package not allowed",
        }
        perr.Incomplete = true
        return &perr
 }
 
-// findVendor looks for the last non-terminating "vendor" path element in the given import path.
-// If there isn't one, findVendor returns ok=false.
-// Otherwise, findVendor returns ok=true and the index of the "vendor".
+// FindVendor looks for the last non-terminating "vendor" path element in the given import path.
+// If there isn't one, FindVendor returns ok=false.
+// 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,
 // not the vendored copy of an import "" (the empty import path).
 // 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.
-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.
        // The order matters: we must return the index of the final element,
        // because the final one is where the effective import path starts.
@@ -758,54 +779,33 @@ func findVendor(path string) (index int, ok bool) {
 type targetDir int
 
 const (
-       toRoot    targetDir = iota // to bin dir inside package root (default)
-       toTool                     // GOROOT/pkg/tool
-       stalePath                  // the old import path; fail to build
+       ToRoot    targetDir = iota // to bin dir inside package root (default)
+       ToTool                     // GOROOT/pkg/tool
+       StalePath                  // the old import path; fail to build
 )
 
 // goTools is a map of Go program import path to install target directory.
-var goTools = map[string]targetDir{
-       "cmd/addr2line": toTool,
-       "cmd/api":       toTool,
-       "cmd/asm":       toTool,
-       "cmd/compile":   toTool,
-       "cmd/cgo":       toTool,
-       "cmd/cover":     toTool,
-       "cmd/dist":      toTool,
-       "cmd/doc":       toTool,
-       "cmd/fix":       toTool,
-       "cmd/link":      toTool,
-       "cmd/newlink":   toTool,
-       "cmd/nm":        toTool,
-       "cmd/objdump":   toTool,
-       "cmd/pack":      toTool,
-       "cmd/pprof":     toTool,
-       "cmd/trace":     toTool,
-       "cmd/vet":       toTool,
-       "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/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 GoTools = map[string]targetDir{
+       "cmd/addr2line": ToTool,
+       "cmd/api":       ToTool,
+       "cmd/asm":       ToTool,
+       "cmd/compile":   ToTool,
+       "cmd/cgo":       ToTool,
+       "cmd/cover":     ToTool,
+       "cmd/dist":      ToTool,
+       "cmd/doc":       ToTool,
+       "cmd/fix":       ToTool,
+       "cmd/link":      ToTool,
+       "cmd/newlink":   ToTool,
+       "cmd/nm":        ToTool,
+       "cmd/objdump":   ToTool,
+       "cmd/pack":      ToTool,
+       "cmd/pprof":     ToTool,
+       "cmd/trace":     ToTool,
+       "cmd/vet":       ToTool,
+       "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/vet":   StalePath,
 }
 
 var raceExclude = map[string]bool{
@@ -829,18 +829,18 @@ var cgoSyscallExclude = map[string]bool{
 
 // load populates p using information from bp, err, which should
 // 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)
 
        // The localPrefix is the path we interpret ./ imports relative to.
        // Synthesized main packages sometimes override this.
-       p.localPrefix = dirToImportPath(p.Dir)
+       p.Internal.LocalPrefix = dirToImportPath(p.Dir)
 
        if err != nil {
                p.Incomplete = true
-               err = expandScanner(err)
+               err = base.ExpandScanner(err)
                p.Error = &PackageError{
-                       ImportStack: stk.copy(),
+                       ImportStack: stk.Copy(),
                        Err:         err.Error(),
                }
                return p
@@ -856,7 +856,7 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
 
        if useBindir {
                // 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)
                        e := fmt.Sprintf("the %v command has moved; use %v instead.", p.ImportPath, newPath)
                        p.Error = &PackageError{Err: e}
@@ -868,38 +868,38 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
                        // Install cross-compiled binaries to subdirectories of bin.
                        elem = full
                }
-               if p.build.BinDir != "" {
+               if p.Internal.Build.BinDir != "" {
                        // Install to GOBIN or bin of GOPATH entry.
-                       p.target = filepath.Join(p.build.BinDir, elem)
-                       if !p.Goroot && strings.Contains(elem, "/") && gobin != "" {
+                       p.Internal.Target = filepath.Join(p.Internal.Build.BinDir, elem)
+                       if !p.Goroot && strings.Contains(elem, "/") && cfg.GOBIN != "" {
                                // Do not create $GOBIN/goos_goarch/elem.
-                               p.target = ""
-                               p.gobinSubdir = true
+                               p.Internal.Target = ""
+                               p.Internal.GobinSubdir = true
                        }
                }
-               if goTools[p.ImportPath] == toTool {
+               if GoTools[p.ImportPath] == ToTool {
                        // This is for 'go tool'.
                        // 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" {
-                       p.target += ".exe"
+               if p.Internal.Target != "" && cfg.BuildContext.GOOS == "windows" {
+                       p.Internal.Target += ".Internal.Exe"
                }
-       } else if p.local {
+       } else if p.Internal.Local {
                // Local import turned into absolute path.
                // No permanent install target.
-               p.target = ""
+               p.Internal.Target = ""
        } else {
-               p.target = p.build.PkgObj
+               p.Internal.Target = p.Internal.Build.PkgObj
                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)
                        if err == nil {
                                libname := strings.TrimSpace(string(shlib))
                                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 {
-                                       p.Shlib = filepath.Join(p.build.PkgTargetRoot, libname)
+                                       p.Shlib = filepath.Join(p.Internal.Build.PkgTargetRoot, libname)
 
                                }
                        } else if !os.IsNotExist(err) {
@@ -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 also import syscall implicitly,
        // to wrap errno.
        // Exclude certain packages to avoid circular dependencies.
        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]) {
-               importPaths = append(importPaths, "syscall")
+               ImportPaths = append(ImportPaths, "syscall")
        }
 
        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
                        }
                }
                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
        // subpackages, and 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.
                // Exclude certain packages to avoid circular dependencies.
                if cfg.BuildRace && (!p.Standard || !raceExclude[p.ImportPath]) {
-                       importPaths = append(importPaths, "runtime/race")
+                       ImportPaths = append(ImportPaths, "runtime/race")
                }
                // MSan uses runtime/msan.
                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.
                if p.Name == "main" && cfg.Goarch == "arm" {
-                       importPaths = append(importPaths, "math")
+                       ImportPaths = append(ImportPaths, "math")
                }
                // 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")) {
-                       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
        // This can be an issue particularly for runtime/internal/atomic;
        // see issue 13655.
        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,
        // for use by commands like go fmt.
-       p.gofiles = str.StringList(p.GoFiles, p.CgoFiles, p.TestGoFiles, p.XTestGoFiles)
-       for i := range p.gofiles {
-               p.gofiles[i] = filepath.Join(p.Dir, p.gofiles[i])
+       p.Internal.GoFiles = str.StringList(p.GoFiles, p.CgoFiles, p.TestGoFiles, p.XTestGoFiles)
+       for i := range p.Internal.GoFiles {
+               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)
-       for i := range p.sfiles {
-               p.sfiles[i] = filepath.Join(p.Dir, p.sfiles[i])
+       p.Internal.SFiles = str.StringList(p.SFiles)
+       for i := range p.Internal.SFiles {
+               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)
-       for i := range p.allgofiles {
-               p.allgofiles[i] = filepath.Join(p.Dir, p.allgofiles[i])
+       p.Internal.AllGoFiles = str.StringList(p.IgnoredGoFiles)
+       for i := range p.Internal.AllGoFiles {
+               p.Internal.AllGoFiles[i] = filepath.Join(p.Dir, p.Internal.AllGoFiles[i])
        }
-       p.allgofiles = append(p.allgofiles, p.gofiles...)
-       sort.Strings(p.allgofiles)
+       p.Internal.AllGoFiles = append(p.Internal.AllGoFiles, p.Internal.GoFiles...)
+       sort.Strings(p.Internal.AllGoFiles)
 
        // Check for case-insensitive collision of input files.
        // 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
        ))
        if f1 != "" {
                p.Error = &PackageError{
-                       ImportStack: stk.copy(),
+                       ImportStack: stk.Copy(),
                        Err:         fmt.Sprintf("case-insensitive file name collision: %q and %q", f1, f2),
                }
                return p
@@ -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" {
                        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 {
                        p.Error = &PackageError{
-                               ImportStack: stk.copy(),
+                               ImportStack: stk.Copy(),
                                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 {
                                p.Error.Pos = pos[0].String()
                        }
                }
 
                path = p1.ImportPath
-               importPaths[i] = path
+               ImportPaths[i] = path
                if i < len(p.Imports) {
                        p.Imports[i] = path
                }
 
                save(path, p1)
                imports = append(imports, p1)
-               for _, dep := range p1.deps {
+               for _, dep := range p1.Internal.Deps {
                        save(dep.ImportPath, dep)
                }
                if p1.Incomplete {
                        p.Incomplete = true
                }
        }
-       p.imports = imports
+       p.Internal.Imports = imports
 
        p.Deps = make([]string, 0, len(deps))
        for dep := range deps {
@@ -1077,7 +1077,7 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
                if p1 == nil {
                        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 {
                        p.DepsErrors = append(p.DepsErrors, p1.Error)
                }
@@ -1085,9 +1085,9 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
 
        // unsafe is a fake package.
        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
        // 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
        }
 
        // 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{
-                       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, " ")),
                }
                return p
@@ -1118,7 +1118,7 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
                dep1, dep2 := str.FoldDup(p.Deps)
                if dep1 != "" {
                        p.Error = &PackageError{
-                               ImportStack: stk.copy(),
+                               ImportStack: stk.Copy(),
                                Err:         fmt.Sprintf("case-insensitive import collision: %q and %q", dep1, dep2),
                        }
                        return p
@@ -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.
                buildID, err := buildid.ReadBuildID(p.Name, p.Target)
                if err == nil {
-                       p.buildID = buildID
+                       p.Internal.BuildID = buildID
                }
        } else {
                computeBuildID(p)
@@ -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.
-func (p *Package) usesSwig() bool {
+func (p *Package) UsesSwig() bool {
        return len(p.SwigFiles) > 0 || len(p.SwigCXXFiles) > 0
 }
 
 // usesCgo reports whether the package needs to run cgo
-func (p *Package) usesCgo() bool {
+func (p *Package) UsesCgo() bool {
        return len(p.CgoFiles) > 0
 }
 
 // packageList returns the list of packages in the dag rooted at roots
 // as visited in a depth-first post-order traversal.
-func packageList(roots []*Package) []*Package {
+func PackageList(roots []*Package) []*Package {
        seen := map[*Package]bool{}
        all := []*Package{}
        var walk func(*Package)
@@ -1158,7 +1158,7 @@ func packageList(roots []*Package) []*Package {
                        return
                }
                seen[p] = true
-               for _, p1 := range p.imports {
+               for _, p1 := range p.Internal.Imports {
                        walk(p1)
                }
                all = append(all, p)
@@ -1171,8 +1171,8 @@ func packageList(roots []*Package) []*Package {
 
 // computeStale computes the Stale flag in the package dag that starts
 // at the named pkgs (command-line arguments).
-func computeStale(pkgs ...*Package) {
-       for _, p := range packageList(pkgs) {
+func ComputeStale(pkgs ...*Package) {
+       for _, p := range PackageList(pkgs) {
                p.Stale, p.StaleReason = isStale(p)
        }
 }
@@ -1463,11 +1463,11 @@ func isStale(p *Package) (bool, string) {
        // if a rebuild is needed, that rebuild attempt will produce a useful error.
        // (Some commands, such as 'go list', do not attempt to rebuild.)
        if p.BinaryOnly {
-               if p.target == "" {
+               if p.Internal.Target == "" {
                        // Fail if a build is attempted.
                        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.
                        return true, "no source code for package, but cannot access install target: " + err.Error()
                }
@@ -1480,12 +1480,12 @@ func isStale(p *Package) (bool, string) {
        }
 
        // If there's no install target, we have to rebuild.
-       if p.target == "" {
+       if p.Internal.Target == "" {
                return true, "no install target"
        }
 
        // Package is stale if completely unbuilt.
-       fi, err := os.Stat(p.target)
+       fi, err := os.Stat(p.Internal.Target)
        if err != nil {
                return true, "cannot stat install target"
        }
@@ -1499,12 +1499,12 @@ func isStale(p *Package) (bool, string) {
        // two versions of Go compiling a single GOPATH.
        // See issue 8290 and issue 10702.
        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"
        }
 
        // Package is stale if a dependency is.
-       for _, p1 := range p.deps {
+       for _, p1 := range p.Internal.Deps {
                if p1.Stale {
                        return true, "stale dependency"
                }
@@ -1542,8 +1542,8 @@ func isStale(p *Package) (bool, string) {
        }
 
        // Package is stale if a dependency is, or if a dependency is newer.
-       for _, p1 := range p.deps {
-               if p1.target != "" && olderThan(p1.target) {
+       for _, p1 := range p.Internal.Deps {
+               if p1.Internal.Target != "" && olderThan(p1.Internal.Target) {
                        return true, "newer dependency"
                }
        }
@@ -1561,11 +1561,11 @@ func isStale(p *Package) (bool, string) {
        // and get a full rebuild anyway.
        // 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).
-       if p.Root != goroot {
+       if p.Root != cfg.GOROOT {
                if olderThan(cfg.BuildToolchainCompiler) {
                        return true, "newer compiler"
                }
-               if p.build.IsCommand() && olderThan(cfg.BuildToolchainLinker) {
+               if p.Internal.Build.IsCommand() && olderThan(cfg.BuildToolchainLinker) {
                        return true, "newer linker"
                }
        }
@@ -1618,7 +1618,7 @@ func isStale(p *Package) (bool, string) {
        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.
 // See the long comment in isStale for details.
 func computeBuildID(p *Package) {
@@ -1661,20 +1661,26 @@ func computeBuildID(p *Package) {
        // people use the same GOPATH but switch between
        // different Go releases. See issue 10702.
        // This is also a better fix for issue 8290.
-       for _, p1 := range p.deps {
-               fmt.Fprintf(h, "dep %s %s\n", p1.ImportPath, p1.buildID)
+       for _, p1 := range p.Internal.Deps {
+               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{}
 
+func ClearCmdCache() {
+       for name := range cmdCache {
+               delete(cmdCache, name)
+       }
+}
+
 // loadPackage is like loadImport but is used for command-line arguments,
 // not for paths found in import statements. In addition to ordinary import paths,
 // loadPackage accepts pseudo-paths beginning with cmd/ to denote commands
 // in the Go command directory, as well as paths to those directories.
-func loadPackage(arg string, stk *importStack) *Package {
+func LoadPackage(arg string, stk *ImportStack) *Package {
        if build.IsLocalImport(arg) {
                dir := arg
                if !filepath.IsAbs(dir) {
@@ -1683,7 +1689,7 @@ func loadPackage(arg string, stk *importStack) *Package {
                                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
                }
        }
@@ -1691,24 +1697,24 @@ func loadPackage(arg string, stk *importStack) *Package {
                if p := cmdCache[arg]; p != nil {
                        return p
                }
-               stk.push(arg)
-               defer stk.pop()
+               stk.Push(arg)
+               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.Goroot = true
-               bp.BinDir = gorootBin
-               if gobin != "" {
-                       bp.BinDir = gobin
+               bp.BinDir = cfg.GOROOTbin
+               if cfg.GOROOTbin != "" {
+                       bp.BinDir = cfg.GOROOTbin
                }
-               bp.Root = goroot
-               bp.SrcRoot = gorootSrc
+               bp.Root = cfg.GOROOT
+               bp.SrcRoot = cfg.GOROOTsrc
                p := new(Package)
                cmdCache[arg] = p
                p.load(stk, bp, err)
                if p.Error == nil && p.Name != "main" {
                        p.Error = &PackageError{
-                               ImportStack: stk.copy(),
+                               ImportStack: stk.Copy(),
                                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 {
                }
        }
 
-       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
@@ -1739,9 +1745,9 @@ func loadPackage(arg string, stk *importStack) *Package {
 // to load dependencies of a named package, the named
 // package is still returned, with p.Incomplete = true
 // and details in p.DepsErrors.
-func packages(args []string) []*Package {
+func Packages(args []string) []*Package {
        var pkgs []*Package
-       for _, pkg := range packagesAndErrors(args) {
+       for _, pkg := range PackagesAndErrors(args) {
                if pkg.Error != nil {
                        base.Errorf("can't load package: %s", pkg.Error)
                        continue
@@ -1755,15 +1761,15 @@ func packages(args []string) []*Package {
 // *Package for every argument, even the ones that
 // cannot be loaded at all.
 // The packages that fail to load will have p.Error != nil.
-func packagesAndErrors(args []string) []*Package {
+func PackagesAndErrors(args []string) []*Package {
        if len(args) > 0 && strings.HasSuffix(args[0], ".go") {
-               return []*Package{goFilesPackage(args)}
+               return []*Package{GoFilesPackage(args)}
        }
 
-       args = importPaths(args)
+       args = ImportPaths(args)
        var (
                pkgs    []*Package
-               stk     importStack
+               stk     ImportStack
                seenArg = make(map[string]bool)
                seenPkg = make(map[*Package]bool)
        )
@@ -1773,14 +1779,14 @@ func packagesAndErrors(args []string) []*Package {
                        continue
                }
                seenArg[arg] = true
-               pkg := loadPackage(arg, &stk)
+               pkg := LoadPackage(arg, &stk)
                if seenPkg[pkg] {
                        continue
                }
                seenPkg[pkg] = true
                pkgs = append(pkgs, pkg)
        }
-       computeStale(pkgs...)
+       ComputeStale(pkgs...)
 
        return pkgs
 }
@@ -1788,8 +1794,8 @@ func packagesAndErrors(args []string) []*Package {
 // packagesForBuild is like 'packages' but fails if any of
 // the packages or their dependencies have errors
 // (cannot be built).
-func packagesForBuild(args []string) []*Package {
-       pkgs := packagesAndErrors(args)
+func PackagesForBuild(args []string) []*Package {
+       pkgs := PackagesAndErrors(args)
        printed := map[*PackageError]bool{}
        for _, pkg := range pkgs {
                if pkg.Error != nil {
@@ -1815,7 +1821,7 @@ func packagesForBuild(args []string) []*Package {
        // which doesn't work very well.
        seen := map[string]bool{}
        reported := map[string]bool{}
-       for _, pkg := range packageList(pkgs) {
+       for _, pkg := range PackageList(pkgs) {
                if seen[pkg.ImportPath] && !reported[pkg.ImportPath] {
                        reported[pkg.ImportPath] = true
                        base.Errorf("internal error: duplicate loads of %s", pkg.ImportPath)
@@ -1827,25 +1833,83 @@ func packagesForBuild(args []string) []*Package {
        return pkgs
 }
 
-// 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
+// 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)
        }
-       if p, err := filepath.EvalSymlinks(dir); err == nil {
-               dir = p
+       ctxt.ReadDir = func(string) ([]os.FileInfo, error) { return dirent, nil }
+
+       var err error
+       if dir == "" {
+               dir = base.Cwd
        }
-       const sep = string(filepath.Separator)
-       root = filepath.Clean(root)
-       if !strings.HasSuffix(root, sep) {
-               root += sep
+       dir, err = filepath.Abs(dir)
+       if err != nil {
+               base.Fatalf("%s", err)
        }
-       dir = filepath.Clean(dir)
-       if !strings.HasPrefix(dir, root) {
-               return "", false
+
+       bp, err := ctxt.ImportDir(dir, 0)
+       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
 }
diff --git a/src/cmd/go/internal/load/search.go b/src/cmd/go/internal/load/search.go
new file mode 100644 (file)
index 0000000..784a071
--- /dev/null
@@ -0,0 +1,263 @@
+// 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"
+}
similarity index 97%
rename from src/cmd/go/testgo.go
rename to src/cmd/go/internal/load/testgo.go
index e507f34be695dd8e50cf673972ba807a14682aad..7734048f5c98d99a246ea21fa3779edef936944e 100644 (file)
@@ -10,7 +10,7 @@
 
 // +build testgo
 
-package main
+package load
 
 import "os"
 
index cb29ca75bb24ad9b9b2cc847c503a738f316132e..527d2500caa54fa4e9c039deb28ff3362616ee17 100644 (file)
@@ -6,8 +6,9 @@ package main
 
 import (
        "bufio"
-       "cmd/go/internal/cfg"
        "cmd/go/internal/base"
+       "cmd/go/internal/cfg"
+       "cmd/go/internal/load"
        "encoding/json"
        "io"
        "os"
@@ -152,9 +153,9 @@ func runList(cmd *base.Command, args []string) {
        out := newTrackingWriter(os.Stdout)
        defer out.w.Flush()
 
-       var do func(*Package)
+       var do func(*load.PackagePublic)
        if *listJson {
-               do = func(p *Package) {
+               do = func(p *load.PackagePublic) {
                        b, err := json.MarshalIndent(p, "", "\t")
                        if err != nil {
                                out.Flush()
@@ -179,7 +180,7 @@ func runList(cmd *base.Command, args []string) {
                if err != nil {
                        base.Fatalf("%s", err)
                }
-               do = func(p *Package) {
+               do = func(p *load.PackagePublic) {
                        if err := tmpl.Execute(out, p); err != nil {
                                out.Flush()
                                base.Fatalf("%s", err)
@@ -190,17 +191,17 @@ func runList(cmd *base.Command, args []string) {
                }
        }
 
-       load := packages
+       loadpkgs := load.Packages
        if *listE {
-               load = packagesAndErrors
+               loadpkgs = load.PackagesAndErrors
        }
 
-       for _, pkg := range load(args) {
+       for _, pkg := range loadpkgs(args) {
                // Show vendor-expanded paths in listing
-               pkg.TestImports = pkg.vendored(pkg.TestImports)
-               pkg.XTestImports = pkg.vendored(pkg.XTestImports)
+               pkg.TestImports = pkg.Vendored(pkg.TestImports)
+               pkg.XTestImports = pkg.Vendored(pkg.XTestImports)
 
-               do(pkg)
+               do(&pkg.PackagePublic)
        }
 }
 
index 626e7287f89654d1250694c3dc0ae738c77be639..9376b88e5aa492e8f5cd95cdf2302cc27d4a4758 100644 (file)
@@ -7,12 +7,9 @@ package main
 import (
        "flag"
        "fmt"
-       "go/build"
        "log"
        "os"
-       "path"
        "path/filepath"
-       "regexp"
        "runtime"
        "strings"
 
@@ -89,8 +86,8 @@ func main() {
                }
        }
 
-       if fi, err := os.Stat(goroot); err != nil || !fi.IsDir() {
-               fmt.Fprintf(os.Stderr, "go: cannot find GOROOT directory: %v\n", goroot)
+       if fi, err := os.Stat(cfg.GOROOT); err != nil || !fi.IsDir() {
+               fmt.Fprintf(os.Stderr, "go: cannot find GOROOT directory: %v\n", cfg.GOROOT)
                os.Exit(2)
        }
 
@@ -145,57 +142,6 @@ func mainUsage() {
        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
 // suitable for running in the given directory.
 // The environment is the current process's environment
@@ -225,235 +171,3 @@ NextVar:
        }
        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
-}
index 52d29ac9e891e49b4b426d6e5d131d92249dc2cc..6158ec0ffa478feb59aed353ef302421fd784175 100644 (file)
@@ -5,8 +5,9 @@
 package main
 
 import (
-       "cmd/go/internal/cfg"
        "cmd/go/internal/base"
+       "cmd/go/internal/cfg"
+       "cmd/go/internal/load"
        "cmd/go/internal/str"
        "io/ioutil"
        "os"
@@ -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) {
        // TODO(avdva) - make these values platform-specific
        prefix := "lib"
        suffix := ".so"
        testData := []struct {
                args      []string
-               pkgs      []*Package
+               pkgs      []*load.Package
                expected  string
                expectErr bool
                rootedAt  string
        }{
                {
                        args:     []string{"std"},
-                       pkgs:     []*Package{},
+                       pkgs:     []*load.Package{},
                        expected: "std",
                },
                {
                        args:     []string{"std", "cmd"},
-                       pkgs:     []*Package{},
+                       pkgs:     []*load.Package{},
                        expected: "std,cmd",
                },
                {
                        args:     []string{},
-                       pkgs:     []*Package{&Package{ImportPath: "gopkg.in/somelib"}},
+                       pkgs:     []*load.Package{pkgImportPath("gopkg.in/somelib")},
                        expected: "gopkg.in-somelib",
                },
                {
                        args:     []string{"./..."},
-                       pkgs:     []*Package{&Package{ImportPath: "somelib"}},
+                       pkgs:     []*load.Package{pkgImportPath("somelib")},
                        expected: "somelib",
                        rootedAt: "somelib",
                },
                {
                        args:     []string{"../somelib", "../somelib"},
-                       pkgs:     []*Package{&Package{ImportPath: "somelib"}},
+                       pkgs:     []*load.Package{pkgImportPath("somelib")},
                        expected: "somelib",
                },
                {
                        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",
                },
                {
                        args: []string{"./..."},
-                       pkgs: []*Package{
-                               &Package{ImportPath: "gopkg.in/dir/lib1"},
-                               &Package{ImportPath: "gopkg.in/lib2"},
-                               &Package{ImportPath: "gopkg.in/lib3"},
+                       pkgs: []*load.Package{
+                               pkgImportPath("gopkg.in/dir/lib1"),
+                               pkgImportPath("gopkg.in/lib2"),
+                               pkgImportPath("gopkg.in/lib3"),
                        },
                        expected: "gopkg.in",
                        rootedAt: "gopkg.in",
                },
                {
                        args:      []string{"std", "../lib2"},
-                       pkgs:      []*Package{},
+                       pkgs:      []*load.Package{},
                        expectErr: true,
                },
                {
                        args:      []string{"all", "./"},
-                       pkgs:      []*Package{},
+                       pkgs:      []*load.Package{},
                        expectErr: true,
                },
                {
                        args:      []string{"cmd", "fmt"},
-                       pkgs:      []*Package{},
+                       pkgs:      []*load.Package{},
                        expectErr: true,
                },
        }
index 77a00541c1d4c65f3499449b58f45d57fe9a8cdf..5e35dfbb78fbbf4a00303dea3bc9fc90961f840a 100644 (file)
@@ -5,8 +5,9 @@
 package main
 
 import (
-       "cmd/go/internal/cfg"
        "cmd/go/internal/base"
+       "cmd/go/internal/cfg"
+       "cmd/go/internal/load"
        "cmd/go/internal/str"
        "fmt"
        "os"
@@ -87,17 +88,17 @@ func runRun(cmd *base.Command, args []string) {
                        base.Fatalf("go run: cannot run *_test.go files (%s)", file)
                }
        }
-       p := goFilesPackage(files)
+       p := load.GoFilesPackage(files)
        if p.Error != nil {
                base.Fatalf("%s", p.Error)
        }
-       p.omitDWARF = true
+       p.Internal.OmitDWARF = true
        if len(p.DepsErrors) > 0 {
                // Since these are errors in dependencies,
                // the same error might show up multiple times,
                // once in each package that depends on it.
                // Only print each once.
-               printed := map[*PackageError]bool{}
+               printed := map[*load.PackageError]bool{}
                for _, err := range p.DepsErrors {
                        if !printed[err] {
                                printed[err] = true
@@ -109,7 +110,7 @@ func runRun(cmd *base.Command, args []string) {
        if p.Name != "main" {
                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
        if len(p.GoFiles) > 0 {
                src = p.GoFiles[0]
@@ -124,7 +125,7 @@ func runRun(cmd *base.Command, args []string) {
                }
                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)
        a := &action{f: (*builder).runProgram, args: cmdArgs, deps: []*action{a1}}
        b.do(a)
index 04a2080fc49d981c1574b66ad98558dbdd94bb47..301ad7faaa3f3e034873513aea2aea8429d6c0c2 100644 (file)
@@ -6,8 +6,9 @@ package main
 
 import (
        "bytes"
-       "cmd/go/internal/cfg"
        "cmd/go/internal/base"
+       "cmd/go/internal/cfg"
+       "cmd/go/internal/load"
        "cmd/go/internal/str"
        "errors"
        "fmt"
@@ -380,13 +381,13 @@ var (
        testC     bool // -c flag
        testCover bool // -cover flag
        // Note: testCoverMode is cfg.TestCoverMode (-covermode)
-       testCoverPaths   []string   // -coverpkg flag
-       testCoverPkgs    []*Package // -coverpkg flag
-       testO            string     // -o flag
-       testProfile      bool       // some profiling flag
-       testNeedBinary   bool       // profile needs to keep binary around
-       testV            bool       // -v flag
-       testTimeout      string     // -timeout flag
+       testCoverPaths   []string        // -coverpkg flag
+       testCoverPkgs    []*load.Package // -coverpkg flag
+       testO            string          // -o flag
+       testProfile      bool            // some profiling flag
+       testNeedBinary   bool            // profile needs to keep binary around
+       testV            bool            // -v flag
+       testTimeout      string          // -timeout flag
        testArgs         []string
        testBench        bool
        testStreamOutput bool // show output as it is generated
@@ -410,7 +411,7 @@ func runTest(cmd *base.Command, args []string) {
 
        instrumentInit()
        buildModeInit()
-       pkgs := packagesForBuild(pkgArgs)
+       pkgs := load.PackagesForBuild(pkgArgs)
        if len(pkgs) == 0 {
                base.Fatalf("no packages to test")
        }
@@ -469,10 +470,10 @@ func runTest(cmd *base.Command, args []string) {
                        for _, path := range p.Imports {
                                deps[path] = true
                        }
-                       for _, path := range p.vendored(p.TestImports) {
+                       for _, path := range p.Vendored(p.TestImports) {
                                deps[path] = true
                        }
-                       for _, path := range p.vendored(p.XTestImports) {
+                       for _, path := range p.Vendored(p.XTestImports) {
                                deps[path] = true
                        }
                }
@@ -497,7 +498,7 @@ func runTest(cmd *base.Command, args []string) {
                sort.Strings(all)
 
                a := &action{}
-               for _, p := range packagesForBuild(all) {
+               for _, p := range load.PackagesForBuild(all) {
                        a.deps = append(a.deps, b.action(modeInstall, modeInstall, p))
                }
                b.do(a)
@@ -512,7 +513,7 @@ func runTest(cmd *base.Command, args []string) {
        if testCoverPaths != nil {
                // Load packages that were asked about for coverage.
                // packagesForBuild exits if the packages cannot be loaded.
-               testCoverPkgs = packagesForBuild(testCoverPaths)
+               testCoverPkgs = load.PackagesForBuild(testCoverPaths)
 
                // Warn about -coverpkg arguments that are not actually used.
                used := make(map[string]bool)
@@ -536,13 +537,13 @@ func runTest(cmd *base.Command, args []string) {
                        }
                        p.Stale = true // rebuild
                        p.StaleReason = "rebuild for coverage"
-                       p.fake = true // do not warn about rebuild
-                       p.coverMode = cfg.TestCoverMode
+                       p.Internal.Fake = true // do not warn about rebuild
+                       p.Internal.CoverMode = cfg.TestCoverMode
                        var coverFiles []string
                        coverFiles = append(coverFiles, p.GoFiles...)
                        coverFiles = append(coverFiles, p.CgoFiles...)
                        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) {
 
        // If we are building any out-of-date packages other
        // than those under test, warn.
-       okBuild := map[*Package]bool{}
+       okBuild := map[*load.Package]bool{}
        for _, p := range pkgs {
                okBuild[p] = true
        }
@@ -607,13 +608,13 @@ func runTest(cmd *base.Command, args []string) {
 
                // Don't warn about packages being rebuilt because of
                // things like coverage analysis.
-               for _, p1 := range a.p.imports {
-                       if p1.fake {
-                               a.p.fake = true
+               for _, p1 := range a.p.Internal.Imports {
+                       if p1.Internal.Fake {
+                               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 {
                                fmt.Fprintf(os.Stderr, "warning: building out-of-date packages:\n")
                                warned = true
@@ -646,7 +647,7 @@ var windowsBadWords = []string{
        "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 {
                build := b.action(modeBuild, modeBuild, p)
                run := &action{p: p, deps: []*action{build}}
@@ -658,13 +659,13 @@ func builderTest(b *builder, p *Package) (buildAction, runAction, printAction *a
        //      ptest - package + test files
        //      pxtest - package of external test files
        //      pmain - pkg.test binary
-       var ptest, pxtest, pmain *Package
+       var ptest, pxtest, pmain *load.Package
 
-       var imports, ximports []*Package
-       var stk importStack
-       stk.push(p.ImportPath + " (test)")
+       var imports, ximports []*load.Package
+       var stk load.ImportStack
+       stk.Push(p.ImportPath + " (test)")
        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 {
                        return nil, nil, nil, p1.Error
                }
@@ -677,21 +678,21 @@ func builderTest(b *builder, p *Package) (buildAction, runAction, printAction *a
                        // Same error that loadPackage returns (via reusePackage) in pkg.go.
                        // Can't change that code, because that code is only for loading the
                        // non-test copy of a package.
-                       err := &PackageError{
+                       err := &load.PackageError{
                                ImportStack:   testImportStack(stk[0], p1, p.ImportPath),
                                Err:           "import cycle not allowed in test",
-                               isImportCycle: true,
+                               IsImportCycle: true,
                        }
                        return nil, nil, nil, err
                }
                p.TestImports[i] = p1.ImportPath
                imports = append(imports, p1)
        }
-       stk.pop()
-       stk.push(p.ImportPath + "_test")
+       stk.Pop()
+       stk.Push(p.ImportPath + "_test")
        pxtestNeedsPtest := false
        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 {
                        return nil, nil, nil, p1.Error
                }
@@ -707,7 +708,7 @@ func builderTest(b *builder, p *Package) (buildAction, runAction, printAction *a
                }
                p.XTestImports[i] = p1.ImportPath
        }
-       stk.pop()
+       stk.Pop()
 
        // Use last element of import path, not package name.
        // They differ when package name is "main".
@@ -752,36 +753,36 @@ func builderTest(b *builder, p *Package) (buildAction, runAction, printAction *a
 
        // Test package.
        if len(p.TestGoFiles) > 0 || localCover || p.Name == "main" {
-               ptest = new(Package)
+               ptest = new(load.Package)
                *ptest = *p
                ptest.GoFiles = nil
                ptest.GoFiles = append(ptest.GoFiles, p.GoFiles...)
                ptest.GoFiles = append(ptest.GoFiles, p.TestGoFiles...)
-               ptest.target = ""
+               ptest.Internal.Target = ""
                ptest.Imports = str.StringList(p.Imports, p.TestImports)
-               ptest.imports = append(append([]*Package{}, p.imports...), imports...)
-               ptest.pkgdir = testDir
-               ptest.fake = true
-               ptest.forceLibrary = true
+               ptest.Internal.Imports = append(append([]*load.Package{}, p.Internal.Imports...), imports...)
+               ptest.Internal.Pkgdir = testDir
+               ptest.Internal.Fake = true
+               ptest.Internal.ForceLibrary = true
                ptest.Stale = true
                ptest.StaleReason = "rebuild for test"
-               ptest.build = new(build.Package)
-               *ptest.build = *p.build
+               ptest.Internal.Build = new(build.Package)
+               *ptest.Internal.Build = *p.Internal.Build
                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...)
                }
-               for k, v := range p.build.TestImportPos {
+               for k, v := range p.Internal.Build.TestImportPos {
                        m[k] = append(m[k], v...)
                }
-               ptest.build.ImportPos = m
+               ptest.Internal.Build.ImportPos = m
 
                if localCover {
-                       ptest.coverMode = cfg.TestCoverMode
+                       ptest.Internal.CoverMode = cfg.TestCoverMode
                        var coverFiles []string
                        coverFiles = append(coverFiles, ptest.GoFiles...)
                        coverFiles = append(coverFiles, ptest.CgoFiles...)
-                       ptest.coverVars = declareCoverVars(ptest.ImportPath, coverFiles...)
+                       ptest.Internal.CoverVars = declareCoverVars(ptest.ImportPath, coverFiles...)
                }
        } else {
                ptest = p
@@ -789,66 +790,74 @@ func builderTest(b *builder, p *Package) (buildAction, runAction, printAction *a
 
        // External test package.
        if len(p.XTestGoFiles) > 0 {
-               pxtest = &Package{
-                       Name:        p.Name + "_test",
-                       ImportPath:  p.ImportPath + "_test",
-                       localPrefix: p.localPrefix,
-                       Root:        p.Root,
-                       Dir:         p.Dir,
-                       GoFiles:     p.XTestGoFiles,
-                       Imports:     p.XTestImports,
-                       build: &build.Package{
-                               ImportPos: p.build.XTestImportPos,
+               pxtest = &load.Package{
+                       PackagePublic: load.PackagePublic{
+                               Name:       p.Name + "_test",
+                               ImportPath: p.ImportPath + "_test",
+                               Root:       p.Root,
+                               Dir:        p.Dir,
+                               GoFiles:    p.XTestGoFiles,
+                               Imports:    p.XTestImports,
+                               Stale:      true,
+                       },
+                       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 {
-                       pxtest.imports = append(pxtest.imports, ptest)
+                       pxtest.Internal.Imports = append(pxtest.Internal.Imports, ptest)
                }
        }
 
        // Action for building pkg.test.
-       pmain = &Package{
-               Name:       "main",
-               Dir:        testDir,
-               GoFiles:    []string{"_testmain.go"},
-               ImportPath: "testmain",
-               Root:       p.Root,
-               build:      &build.Package{Name: "main"},
-               pkgdir:     testDir,
-               fake:       true,
-               Stale:      true,
-               omitDWARF:  !testC && !testNeedBinary,
+       pmain = &load.Package{
+               PackagePublic: load.PackagePublic{
+                       Name:       "main",
+                       Dir:        testDir,
+                       GoFiles:    []string{"_testmain.go"},
+                       ImportPath: "testmain",
+                       Root:       p.Root,
+                       Stale:      true,
+               },
+               Internal: load.PackageInternal{
+                       Build:     &build.Package{Name: "main"},
+                       Pkgdir:    testDir,
+                       Fake:      true,
+                       OmitDWARF: !testC && !testNeedBinary,
+               },
        }
 
        // The generated main also imports testing, regexp, and os.
-       stk.push("testmain")
+       stk.Push("testmain")
        for dep := range testMainDeps {
                if dep == ptest.ImportPath {
-                       pmain.imports = append(pmain.imports, ptest)
+                       pmain.Internal.Imports = append(pmain.Internal.Imports, ptest)
                } else {
-                       p1 := loadImport(dep, "", nil, &stk, nil, 0)
+                       p1 := load.LoadImport(dep, "", nil, &stk, nil, 0)
                        if p1.Error != nil {
                                return nil, nil, nil, p1.Error
                        }
-                       pmain.imports = append(pmain.imports, p1)
+                       pmain.Internal.Imports = append(pmain.Internal.Imports, p1)
                }
        }
 
        if testCoverPkgs != nil {
                // Add imports, but avoid duplicates.
-               seen := map[*Package]bool{p: true, ptest: true}
-               for _, p1 := range pmain.imports {
+               seen := map[*load.Package]bool{p: true, ptest: true}
+               for _, p1 := range pmain.Internal.Imports {
                        seen[p1] = true
                }
                for _, p1 := range testCoverPkgs {
                        if !seen[p1] {
                                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
                return nil, nil, nil, err
        }
        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
        }
        if pxtest != nil {
-               pmain.imports = append(pmain.imports, pxtest)
+               pmain.Internal.Imports = append(pmain.Internal.Imports, pxtest)
                t.ImportXtest = true
        }
 
@@ -896,9 +905,9 @@ func builderTest(b *builder, p *Package) (buildAction, runAction, printAction *a
                t.NeedOS = true
        }
 
-       for _, cp := range pmain.imports {
-               if len(cp.coverVars) > 0 {
-                       t.Cover = append(t.Cover, coverInfo{cp, cp.coverVars})
+       for _, cp := range pmain.Internal.Imports {
+               if len(cp.Internal.CoverVars) > 0 {
+                       t.Cover = append(t.Cover, coverInfo{cp, cp.Internal.CoverVars})
                }
        }
 
@@ -910,7 +919,7 @@ func builderTest(b *builder, p *Package) (buildAction, runAction, printAction *a
                }
        }
 
-       computeStale(pmain)
+       load.ComputeStale(pmain)
 
        if ptest != p {
                a := b.action(modeBuild, modeBuild, ptest)
@@ -1005,11 +1014,11 @@ func builderTest(b *builder, p *Package) (buildAction, runAction, printAction *a
        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}
 Search:
        for p.ImportPath != target {
-               for _, p1 := range p.imports {
+               for _, p1 := range p.Internal.Imports {
                        if p1.ImportPath == target || str.Contains(p1.Deps, target) {
                                stk = append(stk, p1.ImportPath)
                                p = p1
@@ -1023,12 +1032,12 @@ Search:
        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.
        // For each package that depends on preal, make a "test copy"
        // that depends on ptest. And so on, up the dependency tree.
-       testCopy := map[*Package]*Package{preal: ptest}
-       for _, p := range packageList([]*Package{pmain}) {
+       testCopy := map[*load.Package]*load.Package{preal: ptest}
+       for _, p := range load.PackageList([]*load.Package{pmain}) {
                // Copy on write.
                didSplit := false
                split := func() {
@@ -1036,32 +1045,32 @@ func recompileForTest(pmain, preal, ptest *Package, testDir string) {
                                return
                        }
                        didSplit = true
-                       if p.pkgdir != testDir {
-                               p1 := new(Package)
+                       if p.Internal.Pkgdir != testDir {
+                               p1 := new(load.Package)
                                testCopy[p] = p1
                                *p1 = *p
-                               p1.imports = make([]*Package, len(p.imports))
-                               copy(p1.imports, p.imports)
+                               p1.Internal.Imports = make([]*load.Package, len(p.Internal.Imports))
+                               copy(p1.Internal.Imports, p.Internal.Imports)
                                p = p1
-                               p.pkgdir = testDir
-                               p.target = ""
-                               p.fake = true
+                               p.Internal.Pkgdir = testDir
+                               p.Internal.Target = ""
+                               p.Internal.Fake = true
                                p.Stale = true
                                p.StaleReason = "depends on package being tested"
                        }
                }
 
-               // Update p.deps and p.imports to use at test copies.
-               for i, dep := range p.deps {
+               // Update p.deps and p.Internal.Imports to use at test copies.
+               for i, dep := range p.Internal.Deps {
                        if p1 := testCopy[dep]; p1 != nil && p1 != dep {
                                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 {
                                split()
-                               p.imports[i] = p1
+                               p.Internal.Imports[i] = p1
                        }
                }
        }
@@ -1078,13 +1087,13 @@ func isTestFile(file string) bool {
 
 // declareCoverVars attaches the required cover variables names
 // to the files, to be used when annotating the files.
-func declareCoverVars(importPath string, files ...string) map[string]*CoverVar {
-       coverVars := make(map[string]*CoverVar)
+func declareCoverVars(importPath string, files ...string) map[string]*load.CoverVar {
+       coverVars := make(map[string]*load.CoverVar)
        for _, file := range files {
                if isTestFile(file) {
                        continue
                }
-               coverVars[file] = &CoverVar{
+               coverVars[file] = &load.CoverVar{
                        File: filepath.Join(importPath, file),
                        Var:  fmt.Sprintf("GoCover_%d", coverIndex),
                }
@@ -1129,7 +1138,7 @@ func builderRunTest(b *builder, a *action) error {
 
        // If there are any local SWIG dependencies, we want to load
        // the shared library from the build directory.
-       if a.p.usesSwig() {
+       if a.p.UsesSwig() {
                env := cmd.Env
                found := false
                prefix := "LD_LIBRARY_PATH="
@@ -1294,12 +1303,12 @@ func isTest(name, prefix string) bool {
 }
 
 type coverInfo struct {
-       Package *Package
-       Vars    map[string]*CoverVar
+       Package *load.Package
+       Vars    map[string]*load.CoverVar
 }
 
 // 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{
                Package: ptest,
        }
@@ -1336,7 +1345,7 @@ type testFuncs struct {
        Benchmarks  []testFunc
        Examples    []testFunc
        TestMain    *testFunc
-       Package     *Package
+       Package     *load.Package
        ImportTest  bool
        NeedTest    bool
        ImportXtest bool
@@ -1382,7 +1391,7 @@ var testFileSet = token.NewFileSet()
 func (t *testFuncs) load(filename, pkg string, doImport, seen *bool) error {
        f, err := parser.ParseFile(testFileSet, filename, nil, parser.ParseComments)
        if err != nil {
-               return expandScanner(err)
+               return base.ExpandScanner(err)
        }
        for _, d := range f.Decls {
                n, ok := d.(*ast.FuncDecl)
index b2f63279d54faa3b80a2d8b8a9b4058773340e1e..28682696ee808ea77de00b986689bc0b3c720ae3 100644 (file)
@@ -5,8 +5,8 @@
 package main
 
 import (
-       "cmd/go/internal/cfg"
        "cmd/go/internal/base"
+       "cmd/go/internal/cfg"
        "flag"
        "fmt"
        "os"
index 5f07e18c87b6382be9a3d2cf015808fc4d29344c..e6b3fd1e1b63f34770e71e00f005fedff2a2081b 100644 (file)
@@ -11,8 +11,8 @@ import (
        "sort"
        "strings"
 
-       "cmd/go/internal/cfg"
        "cmd/go/internal/base"
+       "cmd/go/internal/cfg"
 )
 
 var cmdTool = &base.Command{
@@ -72,7 +72,7 @@ func runTool(cmd *base.Command, args []string) {
                Stdout: os.Stdout,
                Stderr: os.Stderr,
                // 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()
        if err != nil {
index 98034ee5851cedbe2696b05c74231af3c8b5c91f..202fd1ca9e2b97b2040a2f48f83fd2f064068bfb 100644 (file)
@@ -7,8 +7,9 @@ package main
 import (
        "path/filepath"
 
-       "cmd/go/internal/cfg"
        "cmd/go/internal/base"
+       "cmd/go/internal/cfg"
+       "cmd/go/internal/load"
        "cmd/go/internal/str"
 )
 
@@ -38,7 +39,7 @@ See also: go fmt, go fix.
 }
 
 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.
                // Run once for package p and once for package p_test.
                if len(p.GoFiles)+len(p.CgoFiles)+len(p.TestGoFiles) > 0 {
@@ -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 {
                files[i] = filepath.Join(p.Dir, files[i])
        }