Commit eb93b20c authored by Russ Cox's avatar Russ Cox

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

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

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

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

For #18653.

Change-Id: Ic802483e50598def638f1e2e706d5fdf7822d32d
Reviewed-on: https://go-review.googlesource.com/36196Reviewed-by: default avatarDavid Crawshaw <crawshaw@golang.org>
parent 461c3e52
......@@ -6,8 +6,8 @@ package main
import (
"bytes"
"cmd/go/internal/cfg"
"cmd/go/internal/base"
"cmd/go/internal/cfg"
"fmt"
"io"
"io/ioutil"
......
......@@ -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 {
......
......@@ -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)
}
}
......
......@@ -7,8 +7,8 @@
package main
import (
"cmd/go/internal/cfg"
"cmd/go/internal/base"
"cmd/go/internal/cfg"
)
var cmdDoc = &base.Command{
......
......@@ -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, " ")},
......
......@@ -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)))
}
}
......@@ -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
}
......
......@@ -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
}
......
......@@ -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 {
......
......@@ -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
}
......@@ -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")
)
......@@ -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"
......
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package load
import (
"path/filepath"
"strings"
)
// hasSubdir reports whether dir is a subdirectory of
// (possibly multiple levels below) root.
// If so, it sets rel to the path fragment that must be
// appended to root to reach dir.
func hasSubdir(root, dir string) (rel string, ok bool) {
if p, err := filepath.EvalSymlinks(root); err == nil {
root = p
}
if p, err := filepath.EvalSymlinks(dir); err == nil {
dir = p
}
const sep = string(filepath.Separator)
root = filepath.Clean(root)
if !strings.HasSuffix(root, sep) {
root += sep
}
dir = filepath.Clean(dir)
if !strings.HasPrefix(dir, root) {
return "", false
}
return filepath.ToSlash(dir[len(root):]), true
}
// hasPathPrefix reports whether the path s begins with the
// elements in prefix.
func hasPathPrefix(s, prefix string) bool {
switch {
default:
return false
case len(s) == len(prefix):
return s == prefix
case len(s) > len(prefix):
if prefix != "" && prefix[len(prefix)-1] == '/' {
return strings.HasPrefix(s, prefix)
}
return s[len(prefix)] == '/' && s[:len(prefix)] == prefix
}
}
// expandPath returns the symlink-expanded form of path.
func expandPath(p string) string {
x, err := filepath.EvalSymlinks(p)
if err == nil {
return x
}
return p
}
// hasFilePathPrefix reports whether the filesystem path s begins with the
// elements in prefix.
func hasFilePathPrefix(s, prefix string) bool {
sv := strings.ToUpper(filepath.VolumeName(s))
pv := strings.ToUpper(filepath.VolumeName(prefix))
s = s[len(sv):]
prefix = prefix[len(pv):]
switch {
default:
return false
case sv != pv:
return false
case len(s) == len(prefix):
return s == prefix
case len(s) > len(prefix):
if prefix != "" && prefix[len(prefix)-1] == filepath.Separator {
return strings.HasPrefix(s, prefix)
}
return s[len(prefix)] == filepath.Separator && s[:len(prefix)] == prefix
}
}
......@@ -2,15 +2,13 @@
// 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
}
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package load
import (
"cmd/go/internal/cfg"
"fmt"
"go/build"
"log"
"os"
"path"
"path/filepath"
"regexp"
"strings"
)
// allPackages returns all the packages that can be found
// under the $GOPATH directories and $GOROOT matching pattern.
// The pattern is either "all" (all packages), "std" (standard packages),
// "cmd" (standard commands), or a path including "...".
func allPackages(pattern string) []string {
pkgs := MatchPackages(pattern)
if len(pkgs) == 0 {
fmt.Fprintf(os.Stderr, "warning: %q matched no packages\n", pattern)
}
return pkgs
}
// allPackagesInFS is like allPackages but is passed a pattern
// beginning ./ or ../, meaning it should scan the tree rooted
// at the given directory. There are ... in the pattern too.
func allPackagesInFS(pattern string) []string {
pkgs := MatchPackagesInFS(pattern)
if len(pkgs) == 0 {
fmt.Fprintf(os.Stderr, "warning: %q matched no packages\n", pattern)
}
return pkgs
}
// MatchPackages returns a list of package paths matching pattern
// (see go help packages for pattern syntax).
func MatchPackages(pattern string) []string {
match := func(string) bool { return true }
treeCanMatch := func(string) bool { return true }
if !IsMetaPackage(pattern) {
match = matchPattern(pattern)
treeCanMatch = treeCanMatchPattern(pattern)
}
have := map[string]bool{
"builtin": true, // ignore pseudo-package that exists only for documentation
}
if !cfg.BuildContext.CgoEnabled {
have["runtime/cgo"] = true // ignore during walk
}
var pkgs []string
for _, src := range cfg.BuildContext.SrcDirs() {
if (pattern == "std" || pattern == "cmd") && src != cfg.GOROOTsrc {
continue
}
src = filepath.Clean(src) + string(filepath.Separator)
root := src
if pattern == "cmd" {
root += "cmd" + string(filepath.Separator)
}
filepath.Walk(root, func(path string, fi os.FileInfo, err error) error {
if err != nil || !fi.IsDir() || path == src {
return nil
}
// Avoid .foo, _foo, and testdata directory trees.
_, elem := filepath.Split(path)
if strings.HasPrefix(elem, ".") || strings.HasPrefix(elem, "_") || elem == "testdata" {
return filepath.SkipDir
}
name := filepath.ToSlash(path[len(src):])
if pattern == "std" && (!isStandardImportPath(name) || name == "cmd") {
// The name "std" is only the standard library.
// If the name is cmd, it's the root of the command tree.
return filepath.SkipDir
}
if !treeCanMatch(name) {
return filepath.SkipDir
}
if have[name] {
return nil
}
have[name] = true
if !match(name) {
return nil
}
_, err = cfg.BuildContext.ImportDir(path, 0)
if err != nil {
if _, noGo := err.(*build.NoGoError); noGo {
return nil
}
}
pkgs = append(pkgs, name)
return nil
})
}
return pkgs
}
// MatchPackagesInFS returns a list of package paths matching pattern,
// which must begin with ./ or ../
// (see go help packages for pattern syntax).
func MatchPackagesInFS(pattern string) []string {
// Find directory to begin the scan.
// Could be smarter but this one optimization
// is enough for now, since ... is usually at the
// end of a path.
i := strings.Index(pattern, "...")
dir, _ := path.Split(pattern[:i])
// pattern begins with ./ or ../.
// path.Clean will discard the ./ but not the ../.
// We need to preserve the ./ for pattern matching
// and in the returned import paths.
prefix := ""
if strings.HasPrefix(pattern, "./") {
prefix = "./"
}
match := matchPattern(pattern)
var pkgs []string
filepath.Walk(dir, func(path string, fi os.FileInfo, err error) error {
if err != nil || !fi.IsDir() {
return nil
}
if path == dir {
// filepath.Walk starts at dir and recurses. For the recursive case,
// the path is the result of filepath.Join, which calls filepath.Clean.
// The initial case is not Cleaned, though, so we do this explicitly.
//
// This converts a path like "./io/" to "io". Without this step, running
// "cd $GOROOT/src; go list ./io/..." would incorrectly skip the io
// package, because prepending the prefix "./" to the unclean path would
// result in "././io", and match("././io") returns false.
path = filepath.Clean(path)
}
// Avoid .foo, _foo, and testdata directory trees, but do not avoid "." or "..".
_, elem := filepath.Split(path)
dot := strings.HasPrefix(elem, ".") && elem != "." && elem != ".."
if dot || strings.HasPrefix(elem, "_") || elem == "testdata" {
return filepath.SkipDir
}
name := prefix + filepath.ToSlash(path)
if !match(name) {
return nil
}
// We keep the directory if we can import it, or if we can't import it
// due to invalid Go source files. This means that directories containing
// parse errors will be built (and fail) instead of being silently skipped
// as not matching the pattern. Go 1.5 and earlier skipped, but that
// behavior means people miss serious mistakes.
// See golang.org/issue/11407.
if p, err := cfg.BuildContext.ImportDir(path, 0); err != nil && (p == nil || len(p.InvalidGoFiles) == 0) {
if _, noGo := err.(*build.NoGoError); !noGo {
log.Print(err)
}
return nil
}
pkgs = append(pkgs, name)
return nil
})
return pkgs
}
// treeCanMatchPattern(pattern)(name) reports whether
// name or children of name can possibly match pattern.
// Pattern is the same limited glob accepted by matchPattern.
func treeCanMatchPattern(pattern string) func(name string) bool {
wildCard := false
if i := strings.Index(pattern, "..."); i >= 0 {
wildCard = true
pattern = pattern[:i]
}
return func(name string) bool {
return len(name) <= len(pattern) && hasPathPrefix(pattern, name) ||
wildCard && strings.HasPrefix(name, pattern)
}
}
// matchPattern(pattern)(name) reports whether
// name matches pattern. Pattern is a limited glob
// pattern in which '...' means 'any string' and there
// is no other special syntax.
func matchPattern(pattern string) func(name string) bool {
re := regexp.QuoteMeta(pattern)
re = strings.Replace(re, `\.\.\.`, `.*`, -1)
// Special case: foo/... matches foo too.
if strings.HasSuffix(re, `/.*`) {
re = re[:len(re)-len(`/.*`)] + `(/.*)?`
}
reg := regexp.MustCompile(`^` + re + `$`)
return func(name string) bool {
return reg.MatchString(name)
}
}
// ImportPaths returns the import paths to use for the given command line.
func ImportPaths(args []string) []string {
args = ImportPathsNoDotExpansion(args)
var out []string
for _, a := range args {
if strings.Contains(a, "...") {
if build.IsLocalImport(a) {
out = append(out, allPackagesInFS(a)...)
} else {
out = append(out, allPackages(a)...)
}
continue
}
out = append(out, a)
}
return out
}
// ImportPathsNoDotExpansion returns the import paths to use for the given
// command line, but it does no ... expansion.
func ImportPathsNoDotExpansion(args []string) []string {
if len(args) == 0 {
return []string{"."}
}
var out []string
for _, a := range args {
// Arguments are supposed to be import paths, but
// as a courtesy to Windows developers, rewrite \ to /
// in command-line arguments. Handles .\... and so on.
if filepath.Separator == '\\' {
a = strings.Replace(a, `\`, `/`, -1)
}
// Put argument in canonical form, but preserve leading ./.
if strings.HasPrefix(a, "./") {
a = "./" + path.Clean(a)
if a == "./." {
a = "."
}
} else {
a = path.Clean(a)
}
if IsMetaPackage(a) {
out = append(out, allPackages(a)...)
continue
}
out = append(out, a)
}
return out
}
// isMetaPackage checks if name is a reserved package name that expands to multiple packages.
func IsMetaPackage(name string) bool {
return name == "std" || name == "cmd" || name == "all"
}
......@@ -10,7 +10,7 @@
// +build testgo
package main
package load
import "os"
......
......@@ -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)
}
}
......
......@@ -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
}
......@@ -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,
},
}
......
......@@ -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)
......
......@@ -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)
......
......@@ -5,8 +5,8 @@
package main
import (
"cmd/go/internal/cfg"
"cmd/go/internal/base"
"cmd/go/internal/cfg"
"flag"
"fmt"
"os"
......
......@@ -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 {
......
......@@ -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])
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment