1
0
mirror of https://github.com/golang/go synced 2024-10-01 11:38:34 -06:00

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/36196
Reviewed-by: David Crawshaw <crawshaw@golang.org>
This commit is contained in:
Russ Cox 2017-01-13 16:24:19 -05:00
parent 461c3e5263
commit eb93b20c2e
24 changed files with 1071 additions and 991 deletions

View File

@ -6,8 +6,8 @@ package main
import (
"bytes"
"cmd/go/internal/cfg"
"cmd/go/internal/base"
"cmd/go/internal/cfg"
"fmt"
"io"
"io/ioutil"

View File

@ -30,6 +30,7 @@ import (
"cmd/go/internal/base"
"cmd/go/internal/buildid"
"cmd/go/internal/cfg"
"cmd/go/internal/load"
"cmd/go/internal/str"
)
@ -288,7 +289,7 @@ func (v *stringsFlag) String() string {
return "<stringsFlag>"
}
func pkgsMain(pkgs []*Package) (res []*Package) {
func pkgsMain(pkgs []*load.Package) (res []*load.Package) {
for _, p := range pkgs {
if p.Name == "main" {
res = append(res, p)
@ -297,7 +298,7 @@ func pkgsMain(pkgs []*Package) (res []*Package) {
return res
}
func pkgsNotMain(pkgs []*Package) (res []*Package) {
func pkgsNotMain(pkgs []*load.Package) (res []*load.Package) {
for _, p := range pkgs {
if p.Name != "main" {
res = append(res, p)
@ -306,7 +307,7 @@ func pkgsNotMain(pkgs []*Package) (res []*Package) {
return res
}
var pkgsFilter = func(pkgs []*Package) []*Package { return pkgs }
var pkgsFilter = func(pkgs []*load.Package) []*load.Package { return pkgs }
func buildModeInit() {
gccgo := cfg.BuildToolchainName == "gccgo"
@ -316,7 +317,7 @@ func buildModeInit() {
case "archive":
pkgsFilter = pkgsNotMain
case "c-archive":
pkgsFilter = func(p []*Package) []*Package {
pkgsFilter = func(p []*load.Package) []*load.Package {
if len(p) != 1 || p[0].Name != "main" {
base.Fatalf("-buildmode=c-archive requires exactly one main package")
}
@ -450,7 +451,7 @@ func runBuild(cmd *base.Command, args []string) {
var b builder
b.init()
pkgs := packagesForBuild(args)
pkgs := load.PackagesForBuild(args)
if len(pkgs) == 1 && pkgs[0].Name == "main" && cfg.BuildO == "" {
_, cfg.BuildO = path.Split(pkgs[0].ImportPath)
@ -489,7 +490,7 @@ func runBuild(cmd *base.Command, args []string) {
base.Fatalf("no packages to build")
}
p := pkgs[0]
p.target = cfg.BuildO
p.Internal.Target = cfg.BuildO
p.Stale = true // must build - not up to date
p.StaleReason = "build -o flag in use"
a := b.action(modeInstall, depMode, p)
@ -499,7 +500,7 @@ func runBuild(cmd *base.Command, args []string) {
var a *action
if cfg.BuildBuildmode == "shared" {
pkgs := pkgsFilter(packages(args))
pkgs := pkgsFilter(load.Packages(args))
if libName, err := libname(args, pkgs); err != nil {
base.Fatalf("%s", err.Error())
} else {
@ -507,7 +508,7 @@ func runBuild(cmd *base.Command, args []string) {
}
} else {
a = &action{}
for _, p := range pkgsFilter(packages(args)) {
for _, p := range pkgsFilter(load.Packages(args)) {
a.deps = append(a.deps, b.action(modeBuild, depMode, p))
}
}
@ -528,11 +529,6 @@ See also: go build, go get, go clean.
`,
}
// isMetaPackage checks if name is a reserved package name that expands to multiple packages
func isMetaPackage(name string) bool {
return name == "std" || name == "cmd" || name == "all"
}
// libname returns the filename to use for the shared library when using
// -buildmode=shared. The rules we use are:
// Use arguments for special 'meta' packages:
@ -547,7 +543,7 @@ func isMetaPackage(name string) bool {
// gopkg.in/tomb.v2 -> libgopkg.in-tomb.v2.so
// a/... b/... ---> liba/c,b/d.so - all matching import paths
// Name parts are joined with ','.
func libname(args []string, pkgs []*Package) (string, error) {
func libname(args []string, pkgs []*load.Package) (string, error) {
var libname string
appendName := func(arg string) {
if libname == "" {
@ -558,7 +554,7 @@ func libname(args []string, pkgs []*Package) (string, error) {
}
var haveNonMeta bool
for _, arg := range args {
if isMetaPackage(arg) {
if load.IsMetaPackage(arg) {
appendName(arg)
} else {
haveNonMeta = true
@ -594,20 +590,20 @@ func runInstall(cmd *base.Command, args []string) {
}
func installPackages(args []string, forGet bool) {
if gobin != "" && !filepath.IsAbs(gobin) {
if cfg.GOBIN != "" && !filepath.IsAbs(cfg.GOBIN) {
base.Fatalf("cannot install, GOBIN must be an absolute path")
}
instrumentInit()
buildModeInit()
pkgs := pkgsFilter(packagesForBuild(args))
pkgs := pkgsFilter(load.PackagesForBuild(args))
for _, p := range pkgs {
if p.Target == "" && (!p.Standard || p.ImportPath != "unsafe") {
switch {
case p.gobinSubdir:
case p.Internal.GobinSubdir:
base.Errorf("go install: cannot install cross-compiled binaries when GOBIN is set")
case p.cmdline:
case p.Internal.Cmdline:
base.Errorf("go install: no install location for .go files listed on command line (GOBIN not set)")
case p.ConflictDir != "":
base.Errorf("go install: no install location for %s: hidden by %s", p.Dir, p.ConflictDir)
@ -640,7 +636,7 @@ func installPackages(args []string, forGet bool) {
// cmd/cgo is handled specially in b.action, so that we can
// both build and use it in the same 'go install'.
action := b.action(modeInstall, modeInstall, p)
if goTools[p.ImportPath] == toTool && p.ImportPath != "cmd/cgo" {
if load.GoTools[p.ImportPath] == load.ToTool && p.ImportPath != "cmd/cgo" {
a.deps = append(a.deps, action.deps...)
action.deps = append(action.deps, a)
tools = append(tools, action)
@ -717,7 +713,7 @@ type builder struct {
// An action represents a single action in the action graph.
type action struct {
p *Package // the package this action works on
p *load.Package // the package this action works on
deps []*action // actions that must happen before this one
triggers []*action // inverse of deps
cgo *action // action for cgo binary if needed
@ -743,7 +739,7 @@ type action struct {
// cacheKey is the key for the action cache.
type cacheKey struct {
mode buildMode
p *Package
p *load.Package
shlib string
}
@ -756,14 +752,6 @@ const (
modeInstall
)
var (
goroot = filepath.Clean(runtime.GOROOT())
gobin = os.Getenv("GOBIN")
gorootBin = filepath.Join(goroot, "bin")
gorootPkg = filepath.Join(goroot, "pkg")
gorootSrc = filepath.Join(goroot, "src")
)
func (b *builder) init() {
var err error
b.print = func(a ...interface{}) (int, error) {
@ -789,93 +777,12 @@ func (b *builder) init() {
}
}
// goFilesPackage creates a package for building a collection of Go files
// (typically named on the command line). The target is named p.a for
// package p or named after the first Go file for package main.
func goFilesPackage(gofiles []string) *Package {
// TODO: Remove this restriction.
for _, f := range gofiles {
if !strings.HasSuffix(f, ".go") {
base.Fatalf("named files must be .go files")
}
}
var stk importStack
ctxt := cfg.BuildContext
ctxt.UseAllFiles = true
// Synthesize fake "directory" that only shows the named files,
// to make it look like this is a standard package or
// command directory. So that local imports resolve
// consistently, the files must all be in the same directory.
var dirent []os.FileInfo
var dir string
for _, file := range gofiles {
fi, err := os.Stat(file)
if err != nil {
base.Fatalf("%s", err)
}
if fi.IsDir() {
base.Fatalf("%s is a directory, should be a Go file", file)
}
dir1, _ := filepath.Split(file)
if dir1 == "" {
dir1 = "./"
}
if dir == "" {
dir = dir1
} else if dir != dir1 {
base.Fatalf("named files must all be in one directory; have %s and %s", dir, dir1)
}
dirent = append(dirent, fi)
}
ctxt.ReadDir = func(string) ([]os.FileInfo, error) { return dirent, nil }
var err error
if dir == "" {
dir = base.Cwd
}
dir, err = filepath.Abs(dir)
if err != nil {
base.Fatalf("%s", err)
}
bp, err := ctxt.ImportDir(dir, 0)
pkg := new(Package)
pkg.local = true
pkg.cmdline = true
stk.push("main")
pkg.load(&stk, bp, err)
stk.pop()
pkg.localPrefix = dirToImportPath(dir)
pkg.ImportPath = "command-line-arguments"
pkg.target = ""
if pkg.Name == "main" {
_, elem := filepath.Split(gofiles[0])
exe := elem[:len(elem)-len(".go")] + cfg.ExeSuffix
if cfg.BuildO == "" {
cfg.BuildO = exe
}
if gobin != "" {
pkg.target = filepath.Join(gobin, exe)
}
}
pkg.Target = pkg.target
pkg.Stale = true
pkg.StaleReason = "files named on command line"
computeStale(pkg)
return pkg
}
// readpkglist returns the list of packages that were built into the shared library
// at shlibpath. For the native toolchain this list is stored, newline separated, in
// an ELF note with name "Go\x00\x00" and type 1. For GCCGO it is extracted from the
// .go_export section.
func readpkglist(shlibpath string) (pkgs []*Package) {
var stk importStack
func readpkglist(shlibpath string) (pkgs []*load.Package) {
var stk load.ImportStack
if cfg.BuildToolchainName == "gccgo" {
f, _ := elf.Open(shlibpath)
sect := f.Section(".go_export")
@ -886,7 +793,7 @@ func readpkglist(shlibpath string) (pkgs []*Package) {
if strings.HasPrefix(t, "pkgpath ") {
t = strings.TrimPrefix(t, "pkgpath ")
t = strings.TrimSuffix(t, ";")
pkgs = append(pkgs, loadPackage(t, &stk))
pkgs = append(pkgs, load.LoadPackage(t, &stk))
}
}
} else {
@ -897,7 +804,7 @@ func readpkglist(shlibpath string) (pkgs []*Package) {
scanner := bufio.NewScanner(bytes.NewBuffer(pkglistbytes))
for scanner.Scan() {
t := scanner.Text()
pkgs = append(pkgs, loadPackage(t, &stk))
pkgs = append(pkgs, load.LoadPackage(t, &stk))
}
}
return
@ -907,7 +814,7 @@ func readpkglist(shlibpath string) (pkgs []*Package) {
// depMode is the action to use when building dependencies.
// action never looks for p in a shared library, but may find p's dependencies in a
// shared library if buildLinkshared is true.
func (b *builder) action(mode buildMode, depMode buildMode, p *Package) *action {
func (b *builder) action(mode buildMode, depMode buildMode, p *load.Package) *action {
return b.action1(mode, depMode, p, false, "")
}
@ -915,7 +822,7 @@ func (b *builder) action(mode buildMode, depMode buildMode, p *Package) *action
// depMode is the action to use when building dependencies.
// action1 will look for p in a shared library if lookshared is true.
// forShlib is the shared library that p will become part of, if any.
func (b *builder) action1(mode buildMode, depMode buildMode, p *Package, lookshared bool, forShlib string) *action {
func (b *builder) action1(mode buildMode, depMode buildMode, p *load.Package, lookshared bool, forShlib string) *action {
shlib := ""
if lookshared {
shlib = p.Shlib
@ -940,13 +847,13 @@ func (b *builder) action1(mode buildMode, depMode buildMode, p *Package, looksha
return a
}
a = &action{p: p, pkgdir: p.build.PkgRoot}
if p.pkgdir != "" { // overrides p.t
a.pkgdir = p.pkgdir
a = &action{p: p, pkgdir: p.Internal.Build.PkgRoot}
if p.Internal.Pkgdir != "" { // overrides p.t
a.pkgdir = p.Internal.Pkgdir
}
b.actionCache[key] = a
for _, p1 := range p.imports {
for _, p1 := range p.Internal.Imports {
if forShlib != "" {
// p is part of a shared library.
if p1.Shlib != "" && p1.Shlib != forShlib {
@ -973,8 +880,8 @@ func (b *builder) action1(mode buildMode, depMode buildMode, p *Package, looksha
// are writing is not the cgo we need to use.
if cfg.Goos == runtime.GOOS && cfg.Goarch == runtime.GOARCH && !cfg.BuildRace && !cfg.BuildMSan {
if (len(p.CgoFiles) > 0 || p.Standard && p.ImportPath == "runtime/cgo") && !cfg.BuildLinkshared && cfg.BuildBuildmode != "shared" {
var stk importStack
p1 := loadPackage("cmd/cgo", &stk)
var stk load.ImportStack
p1 := load.LoadPackage("cmd/cgo", &stk)
if p1.Error != nil {
base.Fatalf("load cmd/cgo: %v", p1.Error)
}
@ -992,23 +899,23 @@ func (b *builder) action1(mode buildMode, depMode buildMode, p *Package, looksha
// gccgo standard library is "fake" too.
if cfg.BuildToolchainName == "gccgo" {
// the target name is needed for cgo.
a.target = p.target
a.target = p.Internal.Target
return a
}
}
if !p.Stale && p.target != "" {
// p.Stale==false implies that p.target is up-to-date.
if !p.Stale && p.Internal.Target != "" {
// p.Stale==false implies that p.Internal.Target is up-to-date.
// Record target name for use by actions depending on this one.
a.target = p.target
a.target = p.Internal.Target
return a
}
if p.local && p.target == "" {
if p.Internal.Local && p.Internal.Target == "" {
// Imported via local path. No permanent target.
mode = modeBuild
}
work := p.pkgdir
work := p.Internal.Pkgdir
if work == "" {
work = b.work
}
@ -1020,10 +927,10 @@ func (b *builder) action1(mode buildMode, depMode buildMode, p *Package, looksha
case modeInstall:
a.f = (*builder).install
a.deps = []*action{b.action1(modeBuild, depMode, p, lookshared, forShlib)}
a.target = a.p.target
a.target = a.p.Internal.Target
// Install header for cgo in c-archive and c-shared modes.
if p.usesCgo() && (cfg.BuildBuildmode == "c-archive" || cfg.BuildBuildmode == "c-shared") {
if p.UsesCgo() && (cfg.BuildBuildmode == "c-archive" || cfg.BuildBuildmode == "c-shared") {
hdrTarget := a.target[:len(a.target)-len(filepath.Ext(a.target))] + ".h"
if cfg.BuildContext.Compiler == "gccgo" {
// For the header file, remove the "lib"
@ -1056,15 +963,15 @@ func (b *builder) action1(mode buildMode, depMode buildMode, p *Package, looksha
// naming conflicts. The only possible conflict is if we were
// to create a top-level package named exe.
name := "a.out"
if p.exeName != "" {
name = p.exeName
} else if cfg.Goos == "darwin" && cfg.BuildBuildmode == "c-shared" && p.target != "" {
if p.Internal.ExeName != "" {
name = p.Internal.ExeName
} else if cfg.Goos == "darwin" && cfg.BuildBuildmode == "c-shared" && p.Internal.Target != "" {
// On OS X, the linker output name gets recorded in the
// shared library's LC_ID_DYLIB load command.
// The code invoking the linker knows to pass only the final
// path element. Arrange that the path element matches what
// we'll install it as; otherwise the library is only loadable as "a.out".
_, name = filepath.Split(p.target)
_, name = filepath.Split(p.Internal.Target)
}
a.target = a.objdir + filepath.Join("exe", name) + cfg.ExeSuffix
}
@ -1073,7 +980,7 @@ func (b *builder) action1(mode buildMode, depMode buildMode, p *Package, looksha
return a
}
func (b *builder) libaction(libname string, pkgs []*Package, mode, depMode buildMode) *action {
func (b *builder) libaction(libname string, pkgs []*load.Package, mode, depMode buildMode) *action {
a := &action{}
switch mode {
default:
@ -1083,7 +990,7 @@ func (b *builder) libaction(libname string, pkgs []*Package, mode, depMode build
a.f = (*builder).linkShared
a.target = filepath.Join(b.work, libname)
for _, p := range pkgs {
if p.target == "" {
if p.Internal.Target == "" {
continue
}
a.deps = append(a.deps, b.action(depMode, depMode, p))
@ -1101,18 +1008,18 @@ func (b *builder) libaction(libname string, pkgs []*Package, mode, depMode build
seencgo = seencgo || (p.Standard && p.ImportPath == "runtime/cgo")
}
if !seencgo {
var stk importStack
p := loadPackage("runtime/cgo", &stk)
var stk load.ImportStack
p := load.LoadPackage("runtime/cgo", &stk)
if p.Error != nil {
base.Fatalf("load runtime/cgo: %v", p.Error)
}
computeStale(p)
load.ComputeStale(p)
// If runtime/cgo is in another shared library, then that's
// also the shared library that contains runtime, so
// something will depend on it and so runtime/cgo's staleness
// will be checked when processing that library.
if p.Shlib == "" || p.Shlib == libname {
pkgs = append([]*Package{}, pkgs...)
pkgs = append([]*load.Package{}, pkgs...)
pkgs = append(pkgs, p)
}
}
@ -1122,18 +1029,18 @@ func (b *builder) libaction(libname string, pkgs []*Package, mode, depMode build
seenmath = seenmath || (p.Standard && p.ImportPath == "math")
}
if !seenmath {
var stk importStack
p := loadPackage("math", &stk)
var stk load.ImportStack
p := load.LoadPackage("math", &stk)
if p.Error != nil {
base.Fatalf("load math: %v", p.Error)
}
computeStale(p)
load.ComputeStale(p)
// If math is in another shared library, then that's
// also the shared library that contains runtime, so
// something will depend on it and so math's staleness
// will be checked when processing that library.
if p.Shlib == "" || p.Shlib == libname {
pkgs = append([]*Package{}, pkgs...)
pkgs = append([]*load.Package{}, pkgs...)
pkgs = append(pkgs, p)
}
}
@ -1143,7 +1050,7 @@ func (b *builder) libaction(libname string, pkgs []*Package, mode, depMode build
// Figure out where the library will go.
var libdir string
for _, p := range pkgs {
plibdir := p.build.PkgTargetRoot
plibdir := p.Internal.Build.PkgTargetRoot
if gccgo {
plibdir = filepath.Join(plibdir, "shlibs")
}
@ -1162,11 +1069,11 @@ func (b *builder) libaction(libname string, pkgs []*Package, mode, depMode build
built = fi.ModTime()
}
for _, p := range pkgs {
if p.target == "" {
if p.Internal.Target == "" {
continue
}
stale = stale || p.Stale
lstat, err := os.Stat(p.target)
lstat, err := os.Stat(p.Internal.Target)
if err != nil || lstat.ModTime().After(built) {
stale = true
}
@ -1178,12 +1085,12 @@ func (b *builder) libaction(libname string, pkgs []*Package, mode, depMode build
buildAction := b.libaction(libname, pkgs, modeBuild, depMode)
a.deps = []*action{buildAction}
for _, p := range pkgs {
if p.target == "" {
if p.Internal.Target == "" {
continue
}
shlibnameaction := &action{}
shlibnameaction.f = (*builder).installShlibname
shlibnameaction.target = p.target[:len(p.target)-2] + ".shlibname"
shlibnameaction.target = p.Internal.Target[:len(p.Internal.Target)-2] + ".shlibname"
a.deps = append(a.deps, shlibnameaction)
shlibnameaction.deps = append(shlibnameaction.deps, buildAction)
}
@ -1362,17 +1269,17 @@ func (b *builder) build(a *action) (err error) {
// Return an error if the package has CXX files but it's not using
// cgo nor SWIG, since the CXX files can only be processed by cgo
// and SWIG.
if len(a.p.CXXFiles) > 0 && !a.p.usesCgo() && !a.p.usesSwig() {
if len(a.p.CXXFiles) > 0 && !a.p.UsesCgo() && !a.p.UsesSwig() {
return fmt.Errorf("can't build package %s because it contains C++ files (%s) but it's not using cgo nor SWIG",
a.p.ImportPath, strings.Join(a.p.CXXFiles, ","))
}
// Same as above for Objective-C files
if len(a.p.MFiles) > 0 && !a.p.usesCgo() && !a.p.usesSwig() {
if len(a.p.MFiles) > 0 && !a.p.UsesCgo() && !a.p.UsesSwig() {
return fmt.Errorf("can't build package %s because it contains Objective-C files (%s) but it's not using cgo nor SWIG",
a.p.ImportPath, strings.Join(a.p.MFiles, ","))
}
// Same as above for Fortran files
if len(a.p.FFiles) > 0 && !a.p.usesCgo() && !a.p.usesSwig() {
if len(a.p.FFiles) > 0 && !a.p.UsesCgo() && !a.p.UsesSwig() {
return fmt.Errorf("can't build package %s because it contains Fortran files (%s) but it's not using cgo nor SWIG",
a.p.ImportPath, strings.Join(a.p.FFiles, ","))
}
@ -1417,7 +1324,7 @@ func (b *builder) build(a *action) (err error) {
sfiles = append(sfiles, a.p.SFiles...)
cxxfiles = append(cxxfiles, a.p.CXXFiles...)
if a.p.usesCgo() || a.p.usesSwig() {
if a.p.UsesCgo() || a.p.UsesSwig() {
if pcCFLAGS, pcLDFLAGS, err = b.getPkgConfigFlags(a.p); err != nil {
return
}
@ -1426,7 +1333,7 @@ func (b *builder) build(a *action) (err error) {
// Run SWIG on each .swig and .swigcxx file.
// Each run will generate two files, a .go file and a .c or .cxx file.
// The .go file will use import "C" and is to be processed by cgo.
if a.p.usesSwig() {
if a.p.UsesSwig() {
outGo, outC, outCXX, err := b.swig(a.p, obj, pcCFLAGS)
if err != nil {
return err
@ -1437,7 +1344,7 @@ func (b *builder) build(a *action) (err error) {
}
// Run cgo.
if a.p.usesCgo() || a.p.usesSwig() {
if a.p.UsesCgo() || a.p.UsesSwig() {
// In a package using cgo, cgo compiles the C, C++ and assembly files with gcc.
// There is one exception: runtime/cgo's job is to bridge the
// cgo and non-cgo worlds, so it necessarily has files in both.
@ -1482,7 +1389,7 @@ func (b *builder) build(a *action) (err error) {
}
// If we're doing coverage, preprocess the .go files and put them in the work directory
if a.p.coverMode != "" {
if a.p.Internal.CoverMode != "" {
for i, file := range gofiles {
var sourceFile string
var coverFile string
@ -1498,7 +1405,7 @@ func (b *builder) build(a *action) (err error) {
coverFile = filepath.Join(obj, file)
key = file
}
cover := a.p.coverVars[key]
cover := a.p.Internal.CoverVars[key]
if cover == nil || isTestFile(file) {
// Not covering this file.
continue
@ -1648,7 +1555,7 @@ func splitPkgConfigOutput(out []byte) []string {
}
// Calls pkg-config if needed and returns the cflags/ldflags needed to build the package.
func (b *builder) getPkgConfigFlags(p *Package) (cflags, ldflags []string, err error) {
func (b *builder) getPkgConfigFlags(p *load.Package) (cflags, ldflags []string, err error) {
if pkgs := p.CgoPkgConfig; len(pkgs) > 0 {
var out []byte
out, err = b.runOut(p.Dir, p.ImportPath, nil, b.pkgconfigCmd(), "--cflags", pkgs)
@ -1736,7 +1643,7 @@ func (b *builder) includeArgs(flag string, all []*action) []string {
inc := []string{}
incMap := map[string]bool{
b.work: true, // handled later
gorootPkg: true,
cfg.GOROOTpkg: true,
"": true, // ignore empty strings
}
@ -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 {

View File

@ -5,8 +5,9 @@
package main
import (
"cmd/go/internal/cfg"
"cmd/go/internal/base"
"cmd/go/internal/cfg"
"cmd/go/internal/load"
"fmt"
"io/ioutil"
"os"
@ -77,12 +78,12 @@ func init() {
}
func runClean(cmd *base.Command, args []string) {
for _, pkg := range packagesAndErrors(args) {
for _, pkg := range load.PackagesAndErrors(args) {
clean(pkg)
}
}
var cleaned = map[*Package]bool{}
var cleaned = map[*load.Package]bool{}
// TODO: These are dregs left by Makefile-based builds.
// Eventually, can stop deleting these.
@ -107,7 +108,7 @@ var cleanExt = map[string]bool{
".so": true,
}
func clean(p *Package) {
func clean(p *load.Package) {
if cleaned[p] {
return
}
@ -209,17 +210,17 @@ func clean(p *Package) {
}
}
if cleanI && p.target != "" {
if cleanI && p.Internal.Target != "" {
if cfg.BuildN || cfg.BuildX {
b.showcmd("", "rm -f %s", p.target)
b.showcmd("", "rm -f %s", p.Internal.Target)
}
if !cfg.BuildN {
removeFile(p.target)
removeFile(p.Internal.Target)
}
}
if cleanR {
for _, p1 := range p.imports {
for _, p1 := range p.Internal.Imports {
clean(p1)
}
}

View File

@ -7,8 +7,8 @@
package main
import (
"cmd/go/internal/cfg"
"cmd/go/internal/base"
"cmd/go/internal/cfg"
)
var cmdDoc = &base.Command{

View File

@ -5,8 +5,9 @@
package main
import (
"cmd/go/internal/cfg"
"cmd/go/internal/base"
"cmd/go/internal/cfg"
"cmd/go/internal/load"
"fmt"
"os"
"runtime"
@ -33,14 +34,14 @@ func mkEnv() []cfg.EnvVar {
env := []cfg.EnvVar{
{"GOARCH", cfg.Goarch},
{"GOBIN", gobin},
{"GOBIN", cfg.GOBIN},
{"GOEXE", cfg.ExeSuffix},
{"GOHOSTARCH", runtime.GOARCH},
{"GOHOSTOS", runtime.GOOS},
{"GOOS", cfg.Goos},
{"GOPATH", cfg.BuildContext.GOPATH},
{"GORACE", os.Getenv("GORACE")},
{"GOROOT", goroot},
{"GOROOT", cfg.GOROOT},
{"GOTOOLDIR", base.ToolDir},
// disable escape codes in clang errors
@ -88,7 +89,7 @@ func findEnv(env []cfg.EnvVar, name string) string {
func extraEnvVars() []cfg.EnvVar {
var b builder
b.init()
cppflags, cflags, cxxflags, fflags, ldflags := b.cflags(&Package{})
cppflags, cflags, cxxflags, fflags, ldflags := b.cflags(&load.Package{})
return []cfg.EnvVar{
{"PKG_CONFIG", b.pkgconfigCmd()},
{"CGO_CFLAGS", strings.Join(cflags, " ")},

View File

@ -5,8 +5,9 @@
package main
import (
"cmd/go/internal/cfg"
"cmd/go/internal/base"
"cmd/go/internal/cfg"
"cmd/go/internal/load"
"cmd/go/internal/str"
)
@ -27,10 +28,10 @@ See also: go fmt, go vet.
}
func runFix(cmd *base.Command, args []string) {
for _, pkg := range packages(args) {
for _, pkg := range load.Packages(args) {
// Use pkg.gofiles instead of pkg.Dir so that
// the command only applies to this package,
// not to packages in subdirectories.
base.Run(str.StringList(cfg.BuildToolexec, base.Tool("fix"), base.RelPaths(pkg.allgofiles)))
base.Run(str.StringList(cfg.BuildToolexec, base.Tool("fix"), base.RelPaths(pkg.Internal.AllGoFiles)))
}
}

View File

@ -5,8 +5,9 @@
package main
import (
"cmd/go/internal/cfg"
"cmd/go/internal/base"
"cmd/go/internal/cfg"
"cmd/go/internal/load"
"cmd/go/internal/str"
"os"
"path/filepath"
@ -38,11 +39,11 @@ See also: go fix, go vet.
func runFmt(cmd *base.Command, args []string) {
gofmt := gofmtPath()
for _, pkg := range packages(args) {
for _, pkg := range load.Packages(args) {
// Use pkg.gofiles instead of pkg.Dir so that
// the command only applies to this package,
// not to packages in subdirectories.
base.Run(str.StringList(gofmt, "-l", "-w", base.RelPaths(pkg.allgofiles)))
base.Run(str.StringList(gofmt, "-l", "-w", base.RelPaths(pkg.Internal.AllGoFiles)))
}
}
@ -52,12 +53,12 @@ func gofmtPath() string {
gofmt += base.ToolWindowsExtension
}
gofmtPath := filepath.Join(gobin, gofmt)
gofmtPath := filepath.Join(cfg.GOBIN, gofmt)
if _, err := os.Stat(gofmtPath); err == nil {
return gofmtPath
}
gofmtPath = filepath.Join(goroot, "bin", gofmt)
gofmtPath = filepath.Join(cfg.GOROOT, "bin", gofmt)
if _, err := os.Stat(gofmtPath); err == nil {
return gofmtPath
}

View File

@ -7,8 +7,9 @@ package main
import (
"bufio"
"bytes"
"cmd/go/internal/cfg"
"cmd/go/internal/base"
"cmd/go/internal/cfg"
"cmd/go/internal/load"
"fmt"
"io"
"log"
@ -138,7 +139,7 @@ func init() {
}
func runGenerate(cmd *base.Command, args []string) {
ignoreImports = true
load.IgnoreImports = true
if generateRunFlag != "" {
var err error
@ -148,8 +149,8 @@ func runGenerate(cmd *base.Command, args []string) {
}
}
// Even if the arguments are .go files, this loop suffices.
for _, pkg := range packages(args) {
for _, file := range pkg.gofiles {
for _, pkg := range load.Packages(args) {
for _, file := range pkg.Internal.GoFiles {
if !generate(pkg.Name, file) {
break
}

View File

@ -5,8 +5,9 @@
package main
import (
"cmd/go/internal/cfg"
"cmd/go/internal/base"
"cmd/go/internal/cfg"
"cmd/go/internal/load"
"cmd/go/internal/str"
"fmt"
"go/build"
@ -119,10 +120,10 @@ func runGet(cmd *base.Command, args []string) {
}
// Phase 1. Download/update.
var stk importStack
var stk load.ImportStack
mode := 0
if *getT {
mode |= getTestDeps
mode |= load.GetTestDeps
}
args = downloadPaths(args)
for _, arg := range args {
@ -137,20 +138,16 @@ func runGet(cmd *base.Command, args []string) {
// the information will be recomputed. Instead of keeping
// track of the reverse dependency information, evict
// everything.
for name := range packageCache {
delete(packageCache, name)
}
load.ClearPackageCache()
// In order to rebuild packages information completely,
// we need to clear commands cache. Command packages are
// referring to evicted packages from the package cache.
// This leads to duplicated loads of the standard packages.
for name := range cmdCache {
delete(cmdCache, name)
}
load.ClearCmdCache()
args = importPaths(args)
packagesForBuild(args)
args = load.ImportPaths(args)
load.PackagesForBuild(args)
// Phase 3. Install.
if *getD {
@ -169,7 +166,7 @@ func runGet(cmd *base.Command, args []string) {
// in the hope that we can figure out the repository from the
// initial ...-free prefix.
func downloadPaths(args []string) []string {
args = importPathsNoDotExpansion(args)
args = load.ImportPathsNoDotExpansion(args)
var out []string
for _, a := range args {
if strings.Contains(a, "...") {
@ -178,9 +175,9 @@ func downloadPaths(args []string) []string {
// warnings. They will be printed by the
// eventual call to importPaths instead.
if build.IsLocalImport(a) {
expand = matchPackagesInFS(a)
expand = load.MatchPackagesInFS(a)
} else {
expand = matchPackages(a)
expand = load.MatchPackages(a)
}
if len(expand) > 0 {
out = append(out, expand...)
@ -207,20 +204,20 @@ var downloadRootCache = map[string]bool{}
// download runs the download half of the get command
// for the package named by the argument.
func download(arg string, parent *Package, stk *importStack, mode int) {
if mode&useVendor != 0 {
func download(arg string, parent *load.Package, stk *load.ImportStack, mode int) {
if mode&load.UseVendor != 0 {
// Caller is responsible for expanding vendor paths.
panic("internal error: download mode has useVendor set")
}
load := func(path string, mode int) *Package {
load1 := func(path string, mode int) *load.Package {
if parent == nil {
return loadPackage(path, stk)
return load.LoadPackage(path, stk)
}
return loadImport(path, parent.Dir, parent, stk, nil, mode)
return load.LoadImport(path, parent.Dir, parent, stk, nil, mode)
}
p := load(arg, mode)
if p.Error != nil && p.Error.hard {
p := load1(arg, mode)
if p.Error != nil && p.Error.Hard {
base.Errorf("%s", p.Error)
return
}
@ -243,26 +240,26 @@ func download(arg string, parent *Package, stk *importStack, mode int) {
// Only process each package once.
// (Unless we're fetching test dependencies for this package,
// in which case we want to process it again.)
if downloadCache[arg] && mode&getTestDeps == 0 {
if downloadCache[arg] && mode&load.GetTestDeps == 0 {
return
}
downloadCache[arg] = true
pkgs := []*Package{p}
pkgs := []*load.Package{p}
wildcardOkay := len(*stk) == 0
isWildcard := false
// Download if the package is missing, or update if we're using -u.
if p.Dir == "" || *getU {
// The actual download.
stk.push(arg)
stk.Push(arg)
err := downloadPackage(p)
if err != nil {
base.Errorf("%s", &PackageError{ImportStack: stk.copy(), Err: err.Error()})
stk.pop()
base.Errorf("%s", &load.PackageError{ImportStack: stk.Copy(), Err: err.Error()})
stk.Pop()
return
}
stk.pop()
stk.Pop()
args := []string{arg}
// If the argument has a wildcard in it, re-evaluate the wildcard.
@ -270,29 +267,23 @@ func download(arg string, parent *Package, stk *importStack, mode int) {
// for p has been replaced in the package cache.
if wildcardOkay && strings.Contains(arg, "...") {
if build.IsLocalImport(arg) {
args = matchPackagesInFS(arg)
args = load.MatchPackagesInFS(arg)
} else {
args = matchPackages(arg)
args = load.MatchPackages(arg)
}
isWildcard = true
}
// Clear all relevant package cache entries before
// doing any new loads.
for _, arg := range args {
p := packageCache[arg]
if p != nil {
delete(packageCache, p.Dir)
delete(packageCache, p.ImportPath)
}
}
load.ClearPackageCachePartial(args)
pkgs = pkgs[:0]
for _, arg := range args {
// Note: load calls loadPackage or loadImport,
// which push arg onto stk already.
// Do not push here too, or else stk will say arg imports arg.
p := load(arg, mode)
p := load1(arg, mode)
if p.Error != nil {
base.Errorf("%s", p.Error)
continue
@ -305,10 +296,10 @@ func download(arg string, parent *Package, stk *importStack, mode int) {
// due to wildcard expansion.
for _, p := range pkgs {
if *getFix {
base.Run(cfg.BuildToolexec, str.StringList(base.Tool("fix"), base.RelPaths(p.allgofiles)))
base.Run(cfg.BuildToolexec, str.StringList(base.Tool("fix"), base.RelPaths(p.Internal.AllGoFiles)))
// The imports might have changed, so reload again.
p = reloadPackage(arg, stk)
p = load.ReloadPackage(arg, stk)
if p.Error != nil {
base.Errorf("%s", p.Error)
return
@ -318,12 +309,12 @@ func download(arg string, parent *Package, stk *importStack, mode int) {
if isWildcard {
// Report both the real package and the
// wildcard in any error message.
stk.push(p.ImportPath)
stk.Push(p.ImportPath)
}
// Process dependencies, now that we know what they are.
imports := p.Imports
if mode&getTestDeps != 0 {
if mode&load.GetTestDeps != 0 {
// Process test dependencies when -t is specified.
// (But don't get test dependencies for test dependencies:
// we always pass mode 0 to the recursive calls below.)
@ -335,18 +326,18 @@ func download(arg string, parent *Package, stk *importStack, mode int) {
}
// Fail fast on import naming full vendor path.
// Otherwise expand path as needed for test imports.
// Note that p.Imports can have additional entries beyond p.build.Imports.
// Note that p.Imports can have additional entries beyond p.Internal.Build.Imports.
orig := path
if i < len(p.build.Imports) {
orig = p.build.Imports[i]
if i < len(p.Internal.Build.Imports) {
orig = p.Internal.Build.Imports[i]
}
if j, ok := findVendor(orig); ok {
stk.push(path)
err := &PackageError{
ImportStack: stk.copy(),
if j, ok := load.FindVendor(orig); ok {
stk.Push(path)
err := &load.PackageError{
ImportStack: stk.Copy(),
Err: "must be imported as " + path[j+len("vendor/"):],
}
stk.pop()
stk.Pop()
base.Errorf("%s", err)
continue
}
@ -355,20 +346,20 @@ func download(arg string, parent *Package, stk *importStack, mode int) {
// download does caching based on the value of path,
// so it must be the fully qualified path already.
if i >= len(p.Imports) {
path = vendoredImportPath(p, path)
path = load.VendoredImportPath(p, path)
}
download(path, p, stk, 0)
}
if isWildcard {
stk.pop()
stk.Pop()
}
}
}
// downloadPackage runs the create or download command
// to make the first copy of or update a copy of the given package.
func downloadPackage(p *Package) error {
func downloadPackage(p *load.Package) error {
var (
vcs *vcsCmd
repo, rootPath string
@ -380,9 +371,9 @@ func downloadPackage(p *Package) error {
security = insecure
}
if p.build.SrcRoot != "" {
if p.Internal.Build.SrcRoot != "" {
// Directory exists. Look for checkout along path to src.
vcs, rootPath, err = vcsFromDir(p.Dir, p.build.SrcRoot)
vcs, rootPath, err = vcsFromDir(p.Dir, p.Internal.Build.SrcRoot)
if err != nil {
return err
}
@ -390,7 +381,7 @@ func downloadPackage(p *Package) error {
// Double-check where it came from.
if *getU && vcs.remoteRepo != nil {
dir := filepath.Join(p.build.SrcRoot, filepath.FromSlash(rootPath))
dir := filepath.Join(p.Internal.Build.SrcRoot, filepath.FromSlash(rootPath))
remote, err := vcs.remoteRepo(vcs, dir)
if err != nil {
return err
@ -424,24 +415,24 @@ func downloadPackage(p *Package) error {
return fmt.Errorf("cannot download, %v uses insecure protocol", repo)
}
if p.build.SrcRoot == "" {
if p.Internal.Build.SrcRoot == "" {
// Package not found. Put in first directory of $GOPATH.
list := filepath.SplitList(cfg.BuildContext.GOPATH)
if len(list) == 0 {
return fmt.Errorf("cannot download, $GOPATH not set. For more details see: 'go help gopath'")
}
// Guard against people setting GOPATH=$GOROOT.
if list[0] == goroot {
if list[0] == cfg.GOROOT {
return fmt.Errorf("cannot download, $GOPATH must not be set to $GOROOT. For more details see: 'go help gopath'")
}
if _, err := os.Stat(filepath.Join(list[0], "src/cmd/go/alldocs.go")); err == nil {
return fmt.Errorf("cannot download, %s is a GOROOT, not a GOPATH. For more details see: 'go help gopath'", list[0])
}
p.build.Root = list[0]
p.build.SrcRoot = filepath.Join(list[0], "src")
p.build.PkgRoot = filepath.Join(list[0], "pkg")
p.Internal.Build.Root = list[0]
p.Internal.Build.SrcRoot = filepath.Join(list[0], "src")
p.Internal.Build.PkgRoot = filepath.Join(list[0], "pkg")
}
root := filepath.Join(p.build.SrcRoot, filepath.FromSlash(rootPath))
root := filepath.Join(p.Internal.Build.SrcRoot, filepath.FromSlash(rootPath))
// If we've considered this repository already, don't do it again.
if downloadRootCache[root] {
return nil
@ -467,7 +458,7 @@ func downloadPackage(p *Package) error {
return fmt.Errorf("%s exists but %s does not - stale checkout?", root, meta)
}
_, err := os.Stat(p.build.Root)
_, err := os.Stat(p.Internal.Build.Root)
gopathExisted := err == nil
// Some version control tools require the parent of the target to exist.
@ -475,8 +466,8 @@ func downloadPackage(p *Package) error {
if err = os.MkdirAll(parent, 0777); err != nil {
return err
}
if cfg.BuildV && !gopathExisted && p.build.Root == cfg.BuildContext.GOPATH {
fmt.Fprintf(os.Stderr, "created GOPATH=%s; see 'go help gopath'\n", p.build.Root)
if cfg.BuildV && !gopathExisted && p.Internal.Build.Root == cfg.BuildContext.GOPATH {
fmt.Fprintf(os.Stderr, "created GOPATH=%s; see 'go help gopath'\n", p.Internal.Build.Root)
}
if err = vcs.create(root, repo); err != nil {

View File

@ -7,10 +7,13 @@
package base
import (
"bytes"
"cmd/go/internal/cfg"
"cmd/go/internal/str"
"errors"
"flag"
"fmt"
"go/scanner"
"log"
"os"
"os/exec"
@ -145,3 +148,25 @@ func RunStdin(cmdline []string) {
// Usage is the usage-reporting function, filled in by package main
// but here for reference by other packages.
var Usage func()
// ExpandScanner expands a scanner.List error into all the errors in the list.
// The default Error method only shows the first error
// and does not shorten paths.
func ExpandScanner(err error) error {
// Look for parser errors.
if err, ok := err.(scanner.ErrorList); ok {
// Prepare error with \n before each message.
// When printed in something like context: %v
// this will put the leading file positions each on
// its own line. It will also show all the errors
// instead of just the first, as err.Error does.
var buf bytes.Buffer
for _, e := range err {
e.Pos.Filename = ShortPath(e.Pos.Filename)
buf.WriteString("\n")
buf.WriteString(e.Error())
}
return errors.New(buf.String())
}
return err
}

View File

@ -9,6 +9,8 @@ package cfg
import (
"flag"
"go/build"
"os"
"path/filepath"
"runtime"
)
@ -64,3 +66,11 @@ func AddBuildFlagsNX(flags *flag.FlagSet) {
flags.BoolVar(&BuildN, "n", false, "")
flags.BoolVar(&BuildX, "x", false, "")
}
var (
GOROOT = filepath.Clean(runtime.GOROOT())
GOBIN = os.Getenv("GOBIN")
GOROOTbin = filepath.Join(GOROOT, "bin")
GOROOTpkg = filepath.Join(GOROOT, "pkg")
GOROOTsrc = filepath.Join(GOROOT, "src")
)

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
package load
import "testing"

View File

@ -0,0 +1,80 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package load
import (
"path/filepath"
"strings"
)
// hasSubdir reports whether dir is a subdirectory of
// (possibly multiple levels below) root.
// If so, it sets rel to the path fragment that must be
// appended to root to reach dir.
func hasSubdir(root, dir string) (rel string, ok bool) {
if p, err := filepath.EvalSymlinks(root); err == nil {
root = p
}
if p, err := filepath.EvalSymlinks(dir); err == nil {
dir = p
}
const sep = string(filepath.Separator)
root = filepath.Clean(root)
if !strings.HasSuffix(root, sep) {
root += sep
}
dir = filepath.Clean(dir)
if !strings.HasPrefix(dir, root) {
return "", false
}
return filepath.ToSlash(dir[len(root):]), true
}
// hasPathPrefix reports whether the path s begins with the
// elements in prefix.
func hasPathPrefix(s, prefix string) bool {
switch {
default:
return false
case len(s) == len(prefix):
return s == prefix
case len(s) > len(prefix):
if prefix != "" && prefix[len(prefix)-1] == '/' {
return strings.HasPrefix(s, prefix)
}
return s[len(prefix)] == '/' && s[:len(prefix)] == prefix
}
}
// expandPath returns the symlink-expanded form of path.
func expandPath(p string) string {
x, err := filepath.EvalSymlinks(p)
if err == nil {
return x
}
return p
}
// hasFilePathPrefix reports whether the filesystem path s begins with the
// elements in prefix.
func hasFilePathPrefix(s, prefix string) bool {
sv := strings.ToUpper(filepath.VolumeName(s))
pv := strings.ToUpper(filepath.VolumeName(prefix))
s = s[len(sv):]
prefix = prefix[len(pv):]
switch {
default:
return false
case sv != pv:
return false
case len(s) == len(prefix):
return s == prefix
case len(s) > len(prefix):
if prefix != "" && prefix[len(prefix)-1] == filepath.Separator {
return strings.HasPrefix(s, prefix)
}
return s[len(prefix)] == filepath.Separator && s[:len(prefix)] == prefix
}
}

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -10,7 +10,7 @@
// +build testgo
package main
package load
import "os"

View File

@ -6,8 +6,9 @@ package main
import (
"bufio"
"cmd/go/internal/cfg"
"cmd/go/internal/base"
"cmd/go/internal/cfg"
"cmd/go/internal/load"
"encoding/json"
"io"
"os"
@ -152,9 +153,9 @@ func runList(cmd *base.Command, args []string) {
out := newTrackingWriter(os.Stdout)
defer out.w.Flush()
var do func(*Package)
var do func(*load.PackagePublic)
if *listJson {
do = func(p *Package) {
do = func(p *load.PackagePublic) {
b, err := json.MarshalIndent(p, "", "\t")
if err != nil {
out.Flush()
@ -179,7 +180,7 @@ func runList(cmd *base.Command, args []string) {
if err != nil {
base.Fatalf("%s", err)
}
do = func(p *Package) {
do = func(p *load.PackagePublic) {
if err := tmpl.Execute(out, p); err != nil {
out.Flush()
base.Fatalf("%s", err)
@ -190,17 +191,17 @@ func runList(cmd *base.Command, args []string) {
}
}
load := packages
loadpkgs := load.Packages
if *listE {
load = packagesAndErrors
loadpkgs = load.PackagesAndErrors
}
for _, pkg := range load(args) {
for _, pkg := range loadpkgs(args) {
// Show vendor-expanded paths in listing
pkg.TestImports = pkg.vendored(pkg.TestImports)
pkg.XTestImports = pkg.vendored(pkg.XTestImports)
pkg.TestImports = pkg.Vendored(pkg.TestImports)
pkg.XTestImports = pkg.Vendored(pkg.XTestImports)
do(pkg)
do(&pkg.PackagePublic)
}
}

View File

@ -7,12 +7,9 @@ package main
import (
"flag"
"fmt"
"go/build"
"log"
"os"
"path"
"path/filepath"
"regexp"
"runtime"
"strings"
@ -89,8 +86,8 @@ func main() {
}
}
if fi, err := os.Stat(goroot); err != nil || !fi.IsDir() {
fmt.Fprintf(os.Stderr, "go: cannot find GOROOT directory: %v\n", goroot)
if fi, err := os.Stat(cfg.GOROOT); err != nil || !fi.IsDir() {
fmt.Fprintf(os.Stderr, "go: cannot find GOROOT directory: %v\n", cfg.GOROOT)
os.Exit(2)
}
@ -145,57 +142,6 @@ func mainUsage() {
os.Exit(2)
}
// importPathsNoDotExpansion returns the import paths to use for the given
// command line, but it does no ... expansion.
func importPathsNoDotExpansion(args []string) []string {
if len(args) == 0 {
return []string{"."}
}
var out []string
for _, a := range args {
// Arguments are supposed to be import paths, but
// as a courtesy to Windows developers, rewrite \ to /
// in command-line arguments. Handles .\... and so on.
if filepath.Separator == '\\' {
a = strings.Replace(a, `\`, `/`, -1)
}
// Put argument in canonical form, but preserve leading ./.
if strings.HasPrefix(a, "./") {
a = "./" + path.Clean(a)
if a == "./." {
a = "."
}
} else {
a = path.Clean(a)
}
if isMetaPackage(a) {
out = append(out, allPackages(a)...)
continue
}
out = append(out, a)
}
return out
}
// importPaths returns the import paths to use for the given command line.
func importPaths(args []string) []string {
args = importPathsNoDotExpansion(args)
var out []string
for _, a := range args {
if strings.Contains(a, "...") {
if build.IsLocalImport(a) {
out = append(out, allPackagesInFS(a)...)
} else {
out = append(out, allPackages(a)...)
}
continue
}
out = append(out, a)
}
return out
}
// envForDir returns a copy of the environment
// suitable for running in the given directory.
// The environment is the current process's environment
@ -225,235 +171,3 @@ NextVar:
}
return out
}
// matchPattern(pattern)(name) reports whether
// name matches pattern. Pattern is a limited glob
// pattern in which '...' means 'any string' and there
// is no other special syntax.
func matchPattern(pattern string) func(name string) bool {
re := regexp.QuoteMeta(pattern)
re = strings.Replace(re, `\.\.\.`, `.*`, -1)
// Special case: foo/... matches foo too.
if strings.HasSuffix(re, `/.*`) {
re = re[:len(re)-len(`/.*`)] + `(/.*)?`
}
reg := regexp.MustCompile(`^` + re + `$`)
return func(name string) bool {
return reg.MatchString(name)
}
}
// hasPathPrefix reports whether the path s begins with the
// elements in prefix.
func hasPathPrefix(s, prefix string) bool {
switch {
default:
return false
case len(s) == len(prefix):
return s == prefix
case len(s) > len(prefix):
if prefix != "" && prefix[len(prefix)-1] == '/' {
return strings.HasPrefix(s, prefix)
}
return s[len(prefix)] == '/' && s[:len(prefix)] == prefix
}
}
// hasFilePathPrefix reports whether the filesystem path s begins with the
// elements in prefix.
func hasFilePathPrefix(s, prefix string) bool {
sv := strings.ToUpper(filepath.VolumeName(s))
pv := strings.ToUpper(filepath.VolumeName(prefix))
s = s[len(sv):]
prefix = prefix[len(pv):]
switch {
default:
return false
case sv != pv:
return false
case len(s) == len(prefix):
return s == prefix
case len(s) > len(prefix):
if prefix != "" && prefix[len(prefix)-1] == filepath.Separator {
return strings.HasPrefix(s, prefix)
}
return s[len(prefix)] == filepath.Separator && s[:len(prefix)] == prefix
}
}
// expandPath returns the symlink-expanded form of path.
func expandPath(p string) string {
x, err := filepath.EvalSymlinks(p)
if err == nil {
return x
}
return p
}
// treeCanMatchPattern(pattern)(name) reports whether
// name or children of name can possibly match pattern.
// Pattern is the same limited glob accepted by matchPattern.
func treeCanMatchPattern(pattern string) func(name string) bool {
wildCard := false
if i := strings.Index(pattern, "..."); i >= 0 {
wildCard = true
pattern = pattern[:i]
}
return func(name string) bool {
return len(name) <= len(pattern) && hasPathPrefix(pattern, name) ||
wildCard && strings.HasPrefix(name, pattern)
}
}
// allPackages returns all the packages that can be found
// under the $GOPATH directories and $GOROOT matching pattern.
// The pattern is either "all" (all packages), "std" (standard packages),
// "cmd" (standard commands), or a path including "...".
func allPackages(pattern string) []string {
pkgs := matchPackages(pattern)
if len(pkgs) == 0 {
fmt.Fprintf(os.Stderr, "warning: %q matched no packages\n", pattern)
}
return pkgs
}
func matchPackages(pattern string) []string {
match := func(string) bool { return true }
treeCanMatch := func(string) bool { return true }
if !isMetaPackage(pattern) {
match = matchPattern(pattern)
treeCanMatch = treeCanMatchPattern(pattern)
}
have := map[string]bool{
"builtin": true, // ignore pseudo-package that exists only for documentation
}
if !cfg.BuildContext.CgoEnabled {
have["runtime/cgo"] = true // ignore during walk
}
var pkgs []string
for _, src := range cfg.BuildContext.SrcDirs() {
if (pattern == "std" || pattern == "cmd") && src != gorootSrc {
continue
}
src = filepath.Clean(src) + string(filepath.Separator)
root := src
if pattern == "cmd" {
root += "cmd" + string(filepath.Separator)
}
filepath.Walk(root, func(path string, fi os.FileInfo, err error) error {
if err != nil || !fi.IsDir() || path == src {
return nil
}
// Avoid .foo, _foo, and testdata directory trees.
_, elem := filepath.Split(path)
if strings.HasPrefix(elem, ".") || strings.HasPrefix(elem, "_") || elem == "testdata" {
return filepath.SkipDir
}
name := filepath.ToSlash(path[len(src):])
if pattern == "std" && (!isStandardImportPath(name) || name == "cmd") {
// The name "std" is only the standard library.
// If the name is cmd, it's the root of the command tree.
return filepath.SkipDir
}
if !treeCanMatch(name) {
return filepath.SkipDir
}
if have[name] {
return nil
}
have[name] = true
if !match(name) {
return nil
}
_, err = cfg.BuildContext.ImportDir(path, 0)
if err != nil {
if _, noGo := err.(*build.NoGoError); noGo {
return nil
}
}
pkgs = append(pkgs, name)
return nil
})
}
return pkgs
}
// allPackagesInFS is like allPackages but is passed a pattern
// beginning ./ or ../, meaning it should scan the tree rooted
// at the given directory. There are ... in the pattern too.
func allPackagesInFS(pattern string) []string {
pkgs := matchPackagesInFS(pattern)
if len(pkgs) == 0 {
fmt.Fprintf(os.Stderr, "warning: %q matched no packages\n", pattern)
}
return pkgs
}
func matchPackagesInFS(pattern string) []string {
// Find directory to begin the scan.
// Could be smarter but this one optimization
// is enough for now, since ... is usually at the
// end of a path.
i := strings.Index(pattern, "...")
dir, _ := path.Split(pattern[:i])
// pattern begins with ./ or ../.
// path.Clean will discard the ./ but not the ../.
// We need to preserve the ./ for pattern matching
// and in the returned import paths.
prefix := ""
if strings.HasPrefix(pattern, "./") {
prefix = "./"
}
match := matchPattern(pattern)
var pkgs []string
filepath.Walk(dir, func(path string, fi os.FileInfo, err error) error {
if err != nil || !fi.IsDir() {
return nil
}
if path == dir {
// filepath.Walk starts at dir and recurses. For the recursive case,
// the path is the result of filepath.Join, which calls filepath.Clean.
// The initial case is not Cleaned, though, so we do this explicitly.
//
// This converts a path like "./io/" to "io". Without this step, running
// "cd $GOROOT/src; go list ./io/..." would incorrectly skip the io
// package, because prepending the prefix "./" to the unclean path would
// result in "././io", and match("././io") returns false.
path = filepath.Clean(path)
}
// Avoid .foo, _foo, and testdata directory trees, but do not avoid "." or "..".
_, elem := filepath.Split(path)
dot := strings.HasPrefix(elem, ".") && elem != "." && elem != ".."
if dot || strings.HasPrefix(elem, "_") || elem == "testdata" {
return filepath.SkipDir
}
name := prefix + filepath.ToSlash(path)
if !match(name) {
return nil
}
// We keep the directory if we can import it, or if we can't import it
// due to invalid Go source files. This means that directories containing
// parse errors will be built (and fail) instead of being silently skipped
// as not matching the pattern. Go 1.5 and earlier skipped, but that
// behavior means people miss serious mistakes.
// See golang.org/issue/11407.
if p, err := cfg.BuildContext.ImportDir(path, 0); err != nil && (p == nil || len(p.InvalidGoFiles) == 0) {
if _, noGo := err.(*build.NoGoError); !noGo {
log.Print(err)
}
return nil
}
pkgs = append(pkgs, name)
return nil
})
return pkgs
}

View File

@ -5,8 +5,9 @@
package main
import (
"cmd/go/internal/cfg"
"cmd/go/internal/base"
"cmd/go/internal/cfg"
"cmd/go/internal/load"
"cmd/go/internal/str"
"io/ioutil"
"os"
@ -87,71 +88,79 @@ func TestParseMetaGoImports(t *testing.T) {
}
}
func pkgImportPath(path string) *load.Package {
return &load.Package{
PackagePublic: load.PackagePublic{
ImportPath: path,
},
}
}
func TestSharedLibName(t *testing.T) {
// TODO(avdva) - make these values platform-specific
prefix := "lib"
suffix := ".so"
testData := []struct {
args []string
pkgs []*Package
pkgs []*load.Package
expected string
expectErr bool
rootedAt string
}{
{
args: []string{"std"},
pkgs: []*Package{},
pkgs: []*load.Package{},
expected: "std",
},
{
args: []string{"std", "cmd"},
pkgs: []*Package{},
pkgs: []*load.Package{},
expected: "std,cmd",
},
{
args: []string{},
pkgs: []*Package{&Package{ImportPath: "gopkg.in/somelib"}},
pkgs: []*load.Package{pkgImportPath("gopkg.in/somelib")},
expected: "gopkg.in-somelib",
},
{
args: []string{"./..."},
pkgs: []*Package{&Package{ImportPath: "somelib"}},
pkgs: []*load.Package{pkgImportPath("somelib")},
expected: "somelib",
rootedAt: "somelib",
},
{
args: []string{"../somelib", "../somelib"},
pkgs: []*Package{&Package{ImportPath: "somelib"}},
pkgs: []*load.Package{pkgImportPath("somelib")},
expected: "somelib",
},
{
args: []string{"../lib1", "../lib2"},
pkgs: []*Package{&Package{ImportPath: "gopkg.in/lib1"}, &Package{ImportPath: "gopkg.in/lib2"}},
pkgs: []*load.Package{pkgImportPath("gopkg.in/lib1"), pkgImportPath("gopkg.in/lib2")},
expected: "gopkg.in-lib1,gopkg.in-lib2",
},
{
args: []string{"./..."},
pkgs: []*Package{
&Package{ImportPath: "gopkg.in/dir/lib1"},
&Package{ImportPath: "gopkg.in/lib2"},
&Package{ImportPath: "gopkg.in/lib3"},
pkgs: []*load.Package{
pkgImportPath("gopkg.in/dir/lib1"),
pkgImportPath("gopkg.in/lib2"),
pkgImportPath("gopkg.in/lib3"),
},
expected: "gopkg.in",
rootedAt: "gopkg.in",
},
{
args: []string{"std", "../lib2"},
pkgs: []*Package{},
pkgs: []*load.Package{},
expectErr: true,
},
{
args: []string{"all", "./"},
pkgs: []*Package{},
pkgs: []*load.Package{},
expectErr: true,
},
{
args: []string{"cmd", "fmt"},
pkgs: []*Package{},
pkgs: []*load.Package{},
expectErr: true,
},
}

View File

@ -5,8 +5,9 @@
package main
import (
"cmd/go/internal/cfg"
"cmd/go/internal/base"
"cmd/go/internal/cfg"
"cmd/go/internal/load"
"cmd/go/internal/str"
"fmt"
"os"
@ -87,17 +88,17 @@ func runRun(cmd *base.Command, args []string) {
base.Fatalf("go run: cannot run *_test.go files (%s)", file)
}
}
p := goFilesPackage(files)
p := load.GoFilesPackage(files)
if p.Error != nil {
base.Fatalf("%s", p.Error)
}
p.omitDWARF = true
p.Internal.OmitDWARF = true
if len(p.DepsErrors) > 0 {
// Since these are errors in dependencies,
// the same error might show up multiple times,
// once in each package that depends on it.
// Only print each once.
printed := map[*PackageError]bool{}
printed := map[*load.PackageError]bool{}
for _, err := range p.DepsErrors {
if !printed[err] {
printed[err] = true
@ -109,7 +110,7 @@ func runRun(cmd *base.Command, args []string) {
if p.Name != "main" {
base.Fatalf("go run: cannot run non-main package")
}
p.target = "" // must build - not up to date
p.Internal.Target = "" // must build - not up to date
var src string
if len(p.GoFiles) > 0 {
src = p.GoFiles[0]
@ -124,7 +125,7 @@ func runRun(cmd *base.Command, args []string) {
}
base.Fatalf("go run: no suitable source files%s", hint)
}
p.exeName = src[:len(src)-len(".go")] // name temporary executable for first go file
p.Internal.ExeName = src[:len(src)-len(".go")] // name temporary executable for first go file
a1 := b.action(modeBuild, modeBuild, p)
a := &action{f: (*builder).runProgram, args: cmdArgs, deps: []*action{a1}}
b.do(a)

View File

@ -6,8 +6,9 @@ package main
import (
"bytes"
"cmd/go/internal/cfg"
"cmd/go/internal/base"
"cmd/go/internal/cfg"
"cmd/go/internal/load"
"cmd/go/internal/str"
"errors"
"fmt"
@ -381,7 +382,7 @@ var (
testCover bool // -cover flag
// Note: testCoverMode is cfg.TestCoverMode (-covermode)
testCoverPaths []string // -coverpkg flag
testCoverPkgs []*Package // -coverpkg flag
testCoverPkgs []*load.Package // -coverpkg flag
testO string // -o flag
testProfile bool // some profiling flag
testNeedBinary bool // profile needs to keep binary around
@ -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{
pxtest = &load.Package{
PackagePublic: load.PackagePublic{
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,
},
imports: ximports,
pkgdir: testDir,
fake: true,
external: true,
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,
},
}
if pxtestNeedsPtest {
pxtest.imports = append(pxtest.imports, ptest)
pxtest.Internal.Imports = append(pxtest.Internal.Imports, ptest)
}
}
// Action for building pkg.test.
pmain = &Package{
pmain = &load.Package{
PackagePublic: load.PackagePublic{
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,
},
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)

View File

@ -5,8 +5,8 @@
package main
import (
"cmd/go/internal/cfg"
"cmd/go/internal/base"
"cmd/go/internal/cfg"
"flag"
"fmt"
"os"

View File

@ -11,8 +11,8 @@ import (
"sort"
"strings"
"cmd/go/internal/cfg"
"cmd/go/internal/base"
"cmd/go/internal/cfg"
)
var cmdTool = &base.Command{
@ -72,7 +72,7 @@ func runTool(cmd *base.Command, args []string) {
Stdout: os.Stdout,
Stderr: os.Stderr,
// Set $GOROOT, mainly for go tool dist.
Env: mergeEnvLists([]string{"GOROOT=" + goroot}, os.Environ()),
Env: mergeEnvLists([]string{"GOROOT=" + cfg.GOROOT}, os.Environ()),
}
err := toolCmd.Run()
if err != nil {

View File

@ -7,8 +7,9 @@ package main
import (
"path/filepath"
"cmd/go/internal/cfg"
"cmd/go/internal/base"
"cmd/go/internal/cfg"
"cmd/go/internal/load"
"cmd/go/internal/str"
)
@ -38,7 +39,7 @@ See also: go fmt, go fix.
}
func runVet(cmd *base.Command, args []string) {
for _, p := range packages(args) {
for _, p := range load.Packages(args) {
// Vet expects to be given a set of files all from the same package.
// Run once for package p and once for package p_test.
if len(p.GoFiles)+len(p.CgoFiles)+len(p.TestGoFiles) > 0 {
@ -50,7 +51,7 @@ func runVet(cmd *base.Command, args []string) {
}
}
func runVetFiles(p *Package, files []string) {
func runVetFiles(p *load.Package, files []string) {
for i := range files {
files[i] = filepath.Join(p.Dir, files[i])
}