import (
"bytes"
- "cmd/go/internal/cfg"
"cmd/go/internal/base"
+ "cmd/go/internal/cfg"
"fmt"
"io"
"io/ioutil"
"cmd/go/internal/base"
"cmd/go/internal/buildid"
"cmd/go/internal/cfg"
+ "cmd/go/internal/load"
"cmd/go/internal/str"
)
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)
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)
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"
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")
}
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)
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)
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 {
}
} 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))
}
}
`,
}
-// 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:
// 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 == "" {
}
var haveNonMeta bool
for _, arg := range args {
- if isMetaPackage(arg) {
+ if load.IsMetaPackage(arg) {
appendName(arg)
} else {
haveNonMeta = true
}
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)
// 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)
// 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
// cacheKey is the key for the action cache.
type cacheKey struct {
mode buildMode
- p *Package
+ p *load.Package
shlib string
}
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) {
}
}
-// 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")
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 {
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
// 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, "")
}
// 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
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 {
// 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)
}
// 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
}
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"
// 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
}
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:
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))
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)
}
}
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)
}
}
// 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")
}
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
}
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)
}
// 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, ","))
}
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
}
// 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
}
// 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.
}
// 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
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
}
// 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)
func (b *builder) includeArgs(flag string, all []*action) []string {
inc := []string{}
incMap := map[string]bool{
- b.work: true, // handled later
- gorootPkg: true,
- "": true, // ignore empty strings
+ b.work: true, // handled later
+ cfg.GOROOTpkg: true,
+ "": true, // ignore empty strings
}
// Look in the temporary space for results of test-specific actions.
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)
}
// 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 {
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)
}
}
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)
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
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()
}
return noCompiler()
}
-func (noToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error {
+func (noToolchain) cc(b *builder, p *load.Package, objdir, ofile, cfile string) error {
return noCompiler()
}
return 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 {
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 {
}
}
- 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")
}
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 {
// 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)
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))
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)
}
}
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...)
return b.run(".", out, nil, cfg.BuildToolexec, base.Tool("link"), "-o", out, importArgs, ldflags)
}
-func (gcToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error {
+func (gcToolchain) cc(b *builder, p *load.Package, objdir, ofile, cfile string) error {
return fmt.Errorf("%s: C source files not supported without cgo", mkAbs(p.Dir, cfile))
}
return 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"}
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 {
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"
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))
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
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 {
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()...)
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',
}
// 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)
}
// 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)
}
// 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)
// 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 {
// 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.
// 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
}
}
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
}
// 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 {
package main
import (
- "cmd/go/internal/cfg"
"cmd/go/internal/base"
+ "cmd/go/internal/cfg"
+ "cmd/go/internal/load"
"fmt"
"io/ioutil"
"os"
}
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.
".so": true,
}
-func clean(p *Package) {
+func clean(p *load.Package) {
if cleaned[p] {
return
}
}
}
- 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)
}
}
package main
import (
- "cmd/go/internal/cfg"
"cmd/go/internal/base"
+ "cmd/go/internal/cfg"
)
var cmdDoc = &base.Command{
package main
import (
- "cmd/go/internal/cfg"
"cmd/go/internal/base"
+ "cmd/go/internal/cfg"
+ "cmd/go/internal/load"
"fmt"
"os"
"runtime"
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
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, " ")},
package main
import (
- "cmd/go/internal/cfg"
"cmd/go/internal/base"
+ "cmd/go/internal/cfg"
+ "cmd/go/internal/load"
"cmd/go/internal/str"
)
}
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)))
}
}
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"
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)))
}
}
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
}
import (
"bufio"
"bytes"
- "cmd/go/internal/cfg"
"cmd/go/internal/base"
+ "cmd/go/internal/cfg"
+ "cmd/go/internal/load"
"fmt"
"io"
"log"
}
func runGenerate(cmd *base.Command, args []string) {
- ignoreImports = true
+ load.IgnoreImports = true
if generateRunFlag != "" {
var err error
}
}
// 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
}
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"
}
// 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 {
// 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 {
// 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, "...") {
// 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...)
// 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
}
// 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.
// 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
// 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
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.)
}
// 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
}
// 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
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
}
// 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
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
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.
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 {
package base
import (
+ "bytes"
"cmd/go/internal/cfg"
"cmd/go/internal/str"
+ "errors"
"flag"
"fmt"
+ "go/scanner"
"log"
"os"
"os/exec"
// 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
+}
import (
"flag"
"go/build"
+ "os"
+ "path/filepath"
"runtime"
)
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")
+)
// 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"
--- /dev/null
+// 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
+ }
+}
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-package main
+// Package load loads packages.
+package load
import (
- "bytes"
"crypto/sha1"
- "errors"
"fmt"
"go/build"
- "go/scanner"
"go/token"
"io/ioutil"
"os"
"cmd/go/internal/str"
)
-var ignoreImports bool // control whether we ignore imports in packages
+var IgnoreImports bool // control whether we ignore imports in packages
// A Package describes a single package found in a directory.
type Package struct {
+ PackagePublic // visible in 'go list'
+ Internal PackageInternal // for use inside go command only
+}
+
+type PackagePublic struct {
// Note: These fields are part of the go command's public API.
// See list.go. It is okay to add fields, but not to change or
// remove existing ones. Keep in sync with list.go
TestImports []string `json:",omitempty"` // imports from TestGoFiles
XTestGoFiles []string `json:",omitempty"` // _test.go files outside package
XTestImports []string `json:",omitempty"` // imports from XTestGoFiles
+}
+type PackageInternal struct {
// Unexported fields are not part of the public API.
- build *build.Package
- pkgdir string // overrides build.PkgDir
- imports []*Package
- deps []*Package
- gofiles []string // GoFiles+CgoFiles+TestGoFiles+XTestGoFiles files, absolute paths
- sfiles []string
- allgofiles []string // gofiles + IgnoredGoFiles, absolute paths
- target string // installed file for this package (may be executable)
- fake bool // synthesized package
- external bool // synthesized external test package
- forceLibrary bool // this package is a library (even if named "main")
- cmdline bool // defined by files listed on command line
- local bool // imported via local path (./ or ../)
- localPrefix string // interpret ./ and ../ imports relative to this prefix
- exeName string // desired name for temporary executable
- coverMode string // preprocess Go source files with the coverage tool in this mode
- coverVars map[string]*CoverVar // variables created by coverage analysis
- omitDWARF bool // tell linker not to write DWARF information
- buildID string // expected build ID for generated package
- gobinSubdir bool // install target would be subdir of GOBIN
+ Build *build.Package
+ Pkgdir string // overrides build.PkgDir
+ Imports []*Package
+ Deps []*Package
+ GoFiles []string // GoFiles+CgoFiles+TestGoFiles+XTestGoFiles files, absolute paths
+ SFiles []string
+ AllGoFiles []string // gofiles + IgnoredGoFiles, absolute paths
+ Target string // installed file for this package (may be executable)
+ Fake bool // synthesized package
+ External bool // synthesized external test package
+ ForceLibrary bool // this package is a library (even if named "main")
+ Cmdline bool // defined by files listed on command line
+ Local bool // imported via local path (./ or ../)
+ LocalPrefix string // interpret ./ and ../ imports relative to this prefix
+ ExeName string // desired name for temporary executable
+ CoverMode string // preprocess Go source files with the coverage tool in this mode
+ CoverVars map[string]*CoverVar // variables created by coverage analysis
+ OmitDWARF bool // tell linker not to write DWARF information
+ BuildID string // expected build ID for generated package
+ GobinSubdir bool // install target would be subdir of GOBIN
}
-// vendored returns the vendor-resolved version of imports,
+// Vendored returns the vendor-resolved version of imports,
// which should be p.TestImports or p.XTestImports, NOT p.Imports.
// The imports in p.TestImports and p.XTestImports are not recursively
// loaded during the initial load of p, so they list the imports found in
// can produce better error messages if it starts with the original paths.
// The initial load of p loads all the non-test imports and rewrites
// the vendored paths, so nothing should ever call p.vendored(p.Imports).
-func (p *Package) vendored(imports []string) []string {
+func (p *Package) Vendored(imports []string) []string {
if len(imports) > 0 && len(p.Imports) > 0 && &imports[0] == &p.Imports[0] {
panic("internal error: p.vendored(p.Imports) called")
}
seen := make(map[string]bool)
var all []string
for _, path := range imports {
- path = vendoredImportPath(p, path)
+ path = VendoredImportPath(p, path)
if !seen[path] {
seen[path] = true
all = append(all, path)
}
func (p *Package) copyBuild(pp *build.Package) {
- p.build = pp
+ p.Internal.Build = pp
if pp.PkgTargetRoot != "" && cfg.BuildPkgdir != "" {
old := pp.PkgTargetRoot
p.TestImports = pp.TestImports
p.XTestGoFiles = pp.XTestGoFiles
p.XTestImports = pp.XTestImports
- if ignoreImports {
+ if IgnoreImports {
p.Imports = nil
p.TestImports = nil
p.XTestImports = nil
ImportStack []string // shortest path from package named on command line to this one
Pos string // position of error
Err string // the error itself
- isImportCycle bool // the error is an import cycle
- hard bool // whether the error is soft or hard; soft errors are ignored in some places
+ IsImportCycle bool `json:"-"` // the error is an import cycle
+ Hard bool `json:"-"` // whether the error is soft or hard; soft errors are ignored in some places
}
func (p *PackageError) Error() string {
// Import cycles deserve special treatment.
- if p.isImportCycle {
+ if p.IsImportCycle {
return fmt.Sprintf("%s\npackage %s\n", p.Err, strings.Join(p.ImportStack, "\n\timports "))
}
if p.Pos != "" {
return "package " + strings.Join(p.ImportStack, "\n\timports ") + ": " + p.Err
}
-// An importStack is a stack of import paths.
-type importStack []string
+// An ImportStack is a stack of import paths.
+type ImportStack []string
-func (s *importStack) push(p string) {
+func (s *ImportStack) Push(p string) {
*s = append(*s, p)
}
-func (s *importStack) pop() {
+func (s *ImportStack) Pop() {
*s = (*s)[0 : len(*s)-1]
}
-func (s *importStack) copy() []string {
+func (s *ImportStack) Copy() []string {
return append([]string{}, *s...)
}
// shorterThan reports whether sp is shorter than t.
// We use this to record the shortest import sequence
// that leads to a particular package.
-func (sp *importStack) shorterThan(t []string) bool {
+func (sp *ImportStack) shorterThan(t []string) bool {
s := *sp
if len(s) != len(t) {
return len(s) < len(t)
// we return the same pointer each time.
var packageCache = map[string]*Package{}
+func ClearPackageCache() {
+ for name := range packageCache {
+ delete(packageCache, name)
+ }
+}
+
+func ClearPackageCachePartial(args []string) {
+ for _, arg := range args {
+ p := packageCache[arg]
+ if p != nil {
+ delete(packageCache, p.Dir)
+ delete(packageCache, p.ImportPath)
+ }
+ }
+}
+
// reloadPackage is like loadPackage but makes sure
// not to use the package cache.
-func reloadPackage(arg string, stk *importStack) *Package {
+func ReloadPackage(arg string, stk *ImportStack) *Package {
p := packageCache[arg]
if p != nil {
delete(packageCache, p.Dir)
delete(packageCache, p.ImportPath)
}
- return loadPackage(arg, stk)
+ return LoadPackage(arg, stk)
}
// dirToImportPath returns the pseudo-import path we use for a package
// recorded as the canonical import path. At that point, future loads
// of that package must not pass useVendor, because
// disallowVendor will reject direct use of paths containing /vendor/.
- useVendor = 1 << iota
+ UseVendor = 1 << iota
// getTestDeps is for download (part of "go get") and indicates
// that test dependencies should be fetched too.
- getTestDeps
+ GetTestDeps
)
// loadImport scans the directory named by path, which must be an import path,
// but possibly a local import path (an absolute file system path or one beginning
// with ./ or ../). A local relative path is interpreted relative to srcDir.
// It returns a *Package describing the package found in that directory.
-func loadImport(path, srcDir string, parent *Package, stk *importStack, importPos []token.Position, mode int) *Package {
- stk.push(path)
- defer stk.pop()
+func LoadImport(path, srcDir string, parent *Package, stk *ImportStack, importPos []token.Position, mode int) *Package {
+ stk.Push(path)
+ defer stk.Pop()
// Determine canonical identifier for this package.
// For a local import the identifier is the pseudo-import path
isLocal := build.IsLocalImport(path)
if isLocal {
importPath = dirToImportPath(filepath.Join(srcDir, path))
- } else if mode&useVendor != 0 {
+ } else if mode&UseVendor != 0 {
// We do our own vendor resolution, because we want to
// find out the key to use in packageCache without the
// overhead of repeated calls to buildContext.Import.
// The code is also needed in a few other places anyway.
- path = vendoredImportPath(parent, path)
+ path = VendoredImportPath(parent, path)
importPath = path
}
p = reusePackage(p, stk)
} else {
p = new(Package)
- p.local = isLocal
+ p.Internal.Local = isLocal
p.ImportPath = importPath
packageCache[importPath] = p
// TODO: After Go 1, decide when to pass build.AllowBinary here.
// See issue 3268 for mistakes to avoid.
buildMode := build.ImportComment
- if mode&useVendor == 0 || path != origPath {
+ if mode&UseVendor == 0 || path != origPath {
// Not vendoring, or we already found the vendored path.
buildMode |= build.IgnoreVendor
}
bp, err := cfg.BuildContext.Import(path, srcDir, buildMode)
bp.ImportPath = importPath
- if gobin != "" {
- bp.BinDir = gobin
+ if cfg.GOBIN != "" {
+ bp.BinDir = cfg.GOBIN
}
if err == nil && !isLocal && bp.ImportComment != "" && bp.ImportComment != path &&
!strings.Contains(path, "/vendor/") && !strings.HasPrefix(path, "vendor/") {
if origPath != cleanImport(origPath) {
p.Error = &PackageError{
- ImportStack: stk.copy(),
+ ImportStack: stk.Copy(),
Err: fmt.Sprintf("non-canonical import path: %q should be %q", origPath, pathpkg.Clean(origPath)),
}
p.Incomplete = true
if perr := disallowInternal(srcDir, p, stk); perr != p {
return setErrorPos(perr, importPos)
}
- if mode&useVendor != 0 {
+ if mode&UseVendor != 0 {
if perr := disallowVendor(srcDir, origPath, p, stk); perr != p {
return setErrorPos(perr, importPos)
}
if p.Name == "main" && parent != nil && parent.Dir != p.Dir {
perr := *p
perr.Error = &PackageError{
- ImportStack: stk.copy(),
+ ImportStack: stk.Copy(),
Err: fmt.Sprintf("import %q is a program, not an importable package", path),
}
return setErrorPos(&perr, importPos)
}
- if p.local && parent != nil && !parent.local {
+ if p.Internal.Local && parent != nil && !parent.Internal.Local {
perr := *p
perr.Error = &PackageError{
- ImportStack: stk.copy(),
+ ImportStack: stk.Copy(),
Err: fmt.Sprintf("local import %q in non-local package", path),
}
return setErrorPos(&perr, importPos)
return result
}
-// vendoredImportPath returns the expansion of path when it appears in parent.
+// VendoredImportPath returns the expansion of path when it appears in parent.
// If parent is x/y/z, then path might expand to x/y/z/vendor/path, x/y/vendor/path,
// x/vendor/path, vendor/path, or else stay path if none of those exist.
-// vendoredImportPath returns the expanded path or, if no expansion is found, the original.
-func vendoredImportPath(parent *Package, path string) (found string) {
+// VendoredImportPath returns the expanded path or, if no expansion is found, the original.
+func VendoredImportPath(parent *Package, path string) (found string) {
if parent == nil || parent.Root == "" {
return path
}
root = expandPath(root)
}
- if !hasFilePathPrefix(dir, root) || len(dir) <= len(root) || dir[len(root)] != filepath.Separator || parent.ImportPath != "command-line-arguments" && !parent.local && filepath.Join(root, parent.ImportPath) != dir {
+ if !hasFilePathPrefix(dir, root) || len(dir) <= len(root) || dir[len(root)] != filepath.Separator || parent.ImportPath != "command-line-arguments" && !parent.Internal.Local && filepath.Join(root, parent.ImportPath) != dir {
base.Fatalf("unexpected directory layout:\n"+
" import path: %s\n"+
" root: %s\n"+
// reusePackage reuses package p to satisfy the import at the top
// of the import stack stk. If this use causes an import loop,
// reusePackage updates p's error information to record the loop.
-func reusePackage(p *Package, stk *importStack) *Package {
- // We use p.imports==nil to detect a package that
+func reusePackage(p *Package, stk *ImportStack) *Package {
+ // We use p.Internal.Imports==nil to detect a package that
// is in the midst of its own loadPackage call
- // (all the recursion below happens before p.imports gets set).
- if p.imports == nil {
+ // (all the recursion below happens before p.Internal.Imports gets set).
+ if p.Internal.Imports == nil {
if p.Error == nil {
p.Error = &PackageError{
- ImportStack: stk.copy(),
+ ImportStack: stk.Copy(),
Err: "import cycle not allowed",
- isImportCycle: true,
+ IsImportCycle: true,
}
}
p.Incomplete = true
}
// Don't rewrite the import stack in the error if we have an import cycle.
// If we do, we'll lose the path that describes the cycle.
- if p.Error != nil && !p.Error.isImportCycle && stk.shorterThan(p.Error.ImportStack) {
- p.Error.ImportStack = stk.copy()
+ if p.Error != nil && !p.Error.IsImportCycle && stk.shorterThan(p.Error.ImportStack) {
+ p.Error.ImportStack = stk.Copy()
}
return p
}
// disallowInternal checks that srcDir is allowed to import p.
// If the import is allowed, disallowInternal returns the original package p.
// If not, it returns a new package containing just an appropriate error.
-func disallowInternal(srcDir string, p *Package, stk *importStack) *Package {
+func disallowInternal(srcDir string, p *Package, stk *ImportStack) *Package {
// golang.org/s/go14internal:
// An import of a path containing the element “internal”
// is disallowed if the importing code is outside the tree
// Internal is present, and srcDir is outside parent's tree. Not allowed.
perr := *p
perr.Error = &PackageError{
- ImportStack: stk.copy(),
+ ImportStack: stk.Copy(),
Err: "use of internal package not allowed",
}
perr.Incomplete = true
// disallowVendor checks that srcDir is allowed to import p as path.
// If the import is allowed, disallowVendor returns the original package p.
// If not, it returns a new package containing just an appropriate error.
-func disallowVendor(srcDir, path string, p *Package, stk *importStack) *Package {
+func disallowVendor(srcDir, path string, p *Package, stk *ImportStack) *Package {
// The stack includes p.ImportPath.
// If that's the only thing on the stack, we started
// with a name given on the command line, not an
}
// Paths like x/vendor/y must be imported as y, never as x/vendor/y.
- if i, ok := findVendor(path); ok {
+ if i, ok := FindVendor(path); ok {
perr := *p
perr.Error = &PackageError{
- ImportStack: stk.copy(),
+ ImportStack: stk.Copy(),
Err: "must be imported as " + path[i+len("vendor/"):],
}
perr.Incomplete = true
// is not subject to the rules, only subdirectories of vendor.
// This allows people to have packages and commands named vendor,
// for maximal compatibility with existing source trees.
-func disallowVendorVisibility(srcDir string, p *Package, stk *importStack) *Package {
+func disallowVendorVisibility(srcDir string, p *Package, stk *ImportStack) *Package {
// The stack includes p.ImportPath.
// If that's the only thing on the stack, we started
// with a name given on the command line, not an
}
// Check for "vendor" element.
- i, ok := findVendor(p.ImportPath)
+ i, ok := FindVendor(p.ImportPath)
if !ok {
return p
}
// Vendor is present, and srcDir is outside parent's tree. Not allowed.
perr := *p
perr.Error = &PackageError{
- ImportStack: stk.copy(),
+ ImportStack: stk.Copy(),
Err: "use of vendored package not allowed",
}
perr.Incomplete = true
return &perr
}
-// findVendor looks for the last non-terminating "vendor" path element in the given import path.
-// If there isn't one, findVendor returns ok=false.
-// Otherwise, findVendor returns ok=true and the index of the "vendor".
+// FindVendor looks for the last non-terminating "vendor" path element in the given import path.
+// If there isn't one, FindVendor returns ok=false.
+// Otherwise, FindVendor returns ok=true and the index of the "vendor".
//
// Note that terminating "vendor" elements don't count: "x/vendor" is its own package,
// not the vendored copy of an import "" (the empty import path).
// This will allow people to have packages or commands named vendor.
// This may help reduce breakage, or it may just be confusing. We'll see.
-func findVendor(path string) (index int, ok bool) {
+func FindVendor(path string) (index int, ok bool) {
// Two cases, depending on internal at start of string or not.
// The order matters: we must return the index of the final element,
// because the final one is where the effective import path starts.
type targetDir int
const (
- toRoot targetDir = iota // to bin dir inside package root (default)
- toTool // GOROOT/pkg/tool
- stalePath // the old import path; fail to build
+ ToRoot targetDir = iota // to bin dir inside package root (default)
+ ToTool // GOROOT/pkg/tool
+ StalePath // the old import path; fail to build
)
// goTools is a map of Go program import path to install target directory.
-var goTools = map[string]targetDir{
- "cmd/addr2line": toTool,
- "cmd/api": toTool,
- "cmd/asm": toTool,
- "cmd/compile": toTool,
- "cmd/cgo": toTool,
- "cmd/cover": toTool,
- "cmd/dist": toTool,
- "cmd/doc": toTool,
- "cmd/fix": toTool,
- "cmd/link": toTool,
- "cmd/newlink": toTool,
- "cmd/nm": toTool,
- "cmd/objdump": toTool,
- "cmd/pack": toTool,
- "cmd/pprof": toTool,
- "cmd/trace": toTool,
- "cmd/vet": toTool,
- "code.google.com/p/go.tools/cmd/cover": stalePath,
- "code.google.com/p/go.tools/cmd/godoc": stalePath,
- "code.google.com/p/go.tools/cmd/vet": stalePath,
-}
-
-// expandScanner expands a scanner.List error into all the errors in the list.
-// The default Error method only shows the first error.
-func expandScanner(err error) error {
- // Look for parser errors.
- if err, ok := err.(scanner.ErrorList); ok {
- // Prepare error with \n before each message.
- // When printed in something like context: %v
- // this will put the leading file positions each on
- // its own line. It will also show all the errors
- // instead of just the first, as err.Error does.
- var buf bytes.Buffer
- for _, e := range err {
- e.Pos.Filename = base.ShortPath(e.Pos.Filename)
- buf.WriteString("\n")
- buf.WriteString(e.Error())
- }
- return errors.New(buf.String())
- }
- return err
+var GoTools = map[string]targetDir{
+ "cmd/addr2line": ToTool,
+ "cmd/api": ToTool,
+ "cmd/asm": ToTool,
+ "cmd/compile": ToTool,
+ "cmd/cgo": ToTool,
+ "cmd/cover": ToTool,
+ "cmd/dist": ToTool,
+ "cmd/doc": ToTool,
+ "cmd/fix": ToTool,
+ "cmd/link": ToTool,
+ "cmd/newlink": ToTool,
+ "cmd/nm": ToTool,
+ "cmd/objdump": ToTool,
+ "cmd/pack": ToTool,
+ "cmd/pprof": ToTool,
+ "cmd/trace": ToTool,
+ "cmd/vet": ToTool,
+ "code.google.com/p/go.tools/cmd/cover": StalePath,
+ "code.google.com/p/go.tools/cmd/godoc": StalePath,
+ "code.google.com/p/go.tools/cmd/vet": StalePath,
}
var raceExclude = map[string]bool{
// load populates p using information from bp, err, which should
// be the result of calling build.Context.Import.
-func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package {
+func (p *Package) load(stk *ImportStack, bp *build.Package, err error) *Package {
p.copyBuild(bp)
// The localPrefix is the path we interpret ./ imports relative to.
// Synthesized main packages sometimes override this.
- p.localPrefix = dirToImportPath(p.Dir)
+ p.Internal.LocalPrefix = dirToImportPath(p.Dir)
if err != nil {
p.Incomplete = true
- err = expandScanner(err)
+ err = base.ExpandScanner(err)
p.Error = &PackageError{
- ImportStack: stk.copy(),
+ ImportStack: stk.Copy(),
Err: err.Error(),
}
return p
if useBindir {
// Report an error when the old code.google.com/p/go.tools paths are used.
- if goTools[p.ImportPath] == stalePath {
+ if GoTools[p.ImportPath] == StalePath {
newPath := strings.Replace(p.ImportPath, "code.google.com/p/go.", "golang.org/x/", 1)
e := fmt.Sprintf("the %v command has moved; use %v instead.", p.ImportPath, newPath)
p.Error = &PackageError{Err: e}
// Install cross-compiled binaries to subdirectories of bin.
elem = full
}
- if p.build.BinDir != "" {
+ if p.Internal.Build.BinDir != "" {
// Install to GOBIN or bin of GOPATH entry.
- p.target = filepath.Join(p.build.BinDir, elem)
- if !p.Goroot && strings.Contains(elem, "/") && gobin != "" {
+ p.Internal.Target = filepath.Join(p.Internal.Build.BinDir, elem)
+ if !p.Goroot && strings.Contains(elem, "/") && cfg.GOBIN != "" {
// Do not create $GOBIN/goos_goarch/elem.
- p.target = ""
- p.gobinSubdir = true
+ p.Internal.Target = ""
+ p.Internal.GobinSubdir = true
}
}
- if goTools[p.ImportPath] == toTool {
+ if GoTools[p.ImportPath] == ToTool {
// This is for 'go tool'.
// Override all the usual logic and force it into the tool directory.
- p.target = filepath.Join(gorootPkg, "tool", full)
+ p.Internal.Target = filepath.Join(cfg.GOROOTpkg, "tool", full)
}
- if p.target != "" && cfg.BuildContext.GOOS == "windows" {
- p.target += ".exe"
+ if p.Internal.Target != "" && cfg.BuildContext.GOOS == "windows" {
+ p.Internal.Target += ".Internal.Exe"
}
- } else if p.local {
+ } else if p.Internal.Local {
// Local import turned into absolute path.
// No permanent install target.
- p.target = ""
+ p.Internal.Target = ""
} else {
- p.target = p.build.PkgObj
+ p.Internal.Target = p.Internal.Build.PkgObj
if cfg.BuildLinkshared {
- shlibnamefile := p.target[:len(p.target)-2] + ".shlibname"
+ shlibnamefile := p.Internal.Target[:len(p.Internal.Target)-2] + ".shlibname"
shlib, err := ioutil.ReadFile(shlibnamefile)
if err == nil {
libname := strings.TrimSpace(string(shlib))
if cfg.BuildContext.Compiler == "gccgo" {
- p.Shlib = filepath.Join(p.build.PkgTargetRoot, "shlibs", libname)
+ p.Shlib = filepath.Join(p.Internal.Build.PkgTargetRoot, "shlibs", libname)
} else {
- p.Shlib = filepath.Join(p.build.PkgTargetRoot, libname)
+ p.Shlib = filepath.Join(p.Internal.Build.PkgTargetRoot, libname)
}
} else if !os.IsNotExist(err) {
}
}
- importPaths := p.Imports
+ ImportPaths := p.Imports
// Packages that use cgo import runtime/cgo implicitly.
// Packages that use cgo also import syscall implicitly,
// to wrap errno.
// Exclude certain packages to avoid circular dependencies.
if len(p.CgoFiles) > 0 && (!p.Standard || !cgoExclude[p.ImportPath]) {
- importPaths = append(importPaths, "runtime/cgo")
+ ImportPaths = append(ImportPaths, "runtime/cgo")
}
if len(p.CgoFiles) > 0 && (!p.Standard || !cgoSyscallExclude[p.ImportPath]) {
- importPaths = append(importPaths, "syscall")
+ ImportPaths = append(ImportPaths, "syscall")
}
if cfg.BuildContext.CgoEnabled && p.Name == "main" && !p.Goroot {
}
}
if cfg.BuildBuildmode == "c-shared" || cfg.BuildBuildmode == "plugin" || pieCgo || cfg.BuildLinkshared || linkmodeExternal {
- importPaths = append(importPaths, "runtime/cgo")
+ ImportPaths = append(ImportPaths, "runtime/cgo")
}
}
// Everything depends on runtime, except runtime, its internal
// subpackages, and unsafe.
if !p.Standard || (p.ImportPath != "runtime" && !strings.HasPrefix(p.ImportPath, "runtime/internal/") && p.ImportPath != "unsafe") {
- importPaths = append(importPaths, "runtime")
+ ImportPaths = append(ImportPaths, "runtime")
// When race detection enabled everything depends on runtime/race.
// Exclude certain packages to avoid circular dependencies.
if cfg.BuildRace && (!p.Standard || !raceExclude[p.ImportPath]) {
- importPaths = append(importPaths, "runtime/race")
+ ImportPaths = append(ImportPaths, "runtime/race")
}
// MSan uses runtime/msan.
if cfg.BuildMSan && (!p.Standard || !raceExclude[p.ImportPath]) {
- importPaths = append(importPaths, "runtime/msan")
+ ImportPaths = append(ImportPaths, "runtime/msan")
}
// On ARM with GOARM=5, everything depends on math for the link.
if p.Name == "main" && cfg.Goarch == "arm" {
- importPaths = append(importPaths, "math")
+ ImportPaths = append(ImportPaths, "math")
}
// In coverage atomic mode everything depends on sync/atomic.
if cfg.TestCoverMode == "atomic" && (!p.Standard || (p.ImportPath != "runtime/cgo" && p.ImportPath != "runtime/race" && p.ImportPath != "sync/atomic")) {
- importPaths = append(importPaths, "sync/atomic")
+ ImportPaths = append(ImportPaths, "sync/atomic")
}
}
// This can be an issue particularly for runtime/internal/atomic;
// see issue 13655.
if p.Standard && (p.ImportPath == "runtime" || strings.HasPrefix(p.ImportPath, "runtime/internal/")) && p.ImportPath != "runtime/internal/sys" {
- importPaths = append(importPaths, "runtime/internal/sys")
+ ImportPaths = append(ImportPaths, "runtime/internal/sys")
}
// Build list of full paths to all Go files in the package,
// for use by commands like go fmt.
- p.gofiles = str.StringList(p.GoFiles, p.CgoFiles, p.TestGoFiles, p.XTestGoFiles)
- for i := range p.gofiles {
- p.gofiles[i] = filepath.Join(p.Dir, p.gofiles[i])
+ p.Internal.GoFiles = str.StringList(p.GoFiles, p.CgoFiles, p.TestGoFiles, p.XTestGoFiles)
+ for i := range p.Internal.GoFiles {
+ p.Internal.GoFiles[i] = filepath.Join(p.Dir, p.Internal.GoFiles[i])
}
- sort.Strings(p.gofiles)
+ sort.Strings(p.Internal.GoFiles)
- p.sfiles = str.StringList(p.SFiles)
- for i := range p.sfiles {
- p.sfiles[i] = filepath.Join(p.Dir, p.sfiles[i])
+ p.Internal.SFiles = str.StringList(p.SFiles)
+ for i := range p.Internal.SFiles {
+ p.Internal.SFiles[i] = filepath.Join(p.Dir, p.Internal.SFiles[i])
}
- sort.Strings(p.sfiles)
+ sort.Strings(p.Internal.SFiles)
- p.allgofiles = str.StringList(p.IgnoredGoFiles)
- for i := range p.allgofiles {
- p.allgofiles[i] = filepath.Join(p.Dir, p.allgofiles[i])
+ p.Internal.AllGoFiles = str.StringList(p.IgnoredGoFiles)
+ for i := range p.Internal.AllGoFiles {
+ p.Internal.AllGoFiles[i] = filepath.Join(p.Dir, p.Internal.AllGoFiles[i])
}
- p.allgofiles = append(p.allgofiles, p.gofiles...)
- sort.Strings(p.allgofiles)
+ p.Internal.AllGoFiles = append(p.Internal.AllGoFiles, p.Internal.GoFiles...)
+ sort.Strings(p.Internal.AllGoFiles)
// Check for case-insensitive collision of input files.
// To avoid problems on case-insensitive files, we reject any package
))
if f1 != "" {
p.Error = &PackageError{
- ImportStack: stk.copy(),
+ ImportStack: stk.Copy(),
Err: fmt.Sprintf("case-insensitive file name collision: %q and %q", f1, f2),
}
return p
}
}
- for i, path := range importPaths {
+ for i, path := range ImportPaths {
if path == "C" {
continue
}
- p1 := loadImport(path, p.Dir, p, stk, p.build.ImportPos[path], useVendor)
+ p1 := LoadImport(path, p.Dir, p, stk, p.Internal.Build.ImportPos[path], UseVendor)
if p.Standard && p.Error == nil && !p1.Standard && p1.Error == nil {
p.Error = &PackageError{
- ImportStack: stk.copy(),
+ ImportStack: stk.Copy(),
Err: fmt.Sprintf("non-standard import %q in standard package %q", path, p.ImportPath),
}
- pos := p.build.ImportPos[path]
+ pos := p.Internal.Build.ImportPos[path]
if len(pos) > 0 {
p.Error.Pos = pos[0].String()
}
}
path = p1.ImportPath
- importPaths[i] = path
+ ImportPaths[i] = path
if i < len(p.Imports) {
p.Imports[i] = path
}
save(path, p1)
imports = append(imports, p1)
- for _, dep := range p1.deps {
+ for _, dep := range p1.Internal.Deps {
save(dep.ImportPath, dep)
}
if p1.Incomplete {
p.Incomplete = true
}
}
- p.imports = imports
+ p.Internal.Imports = imports
p.Deps = make([]string, 0, len(deps))
for dep := range deps {
if p1 == nil {
panic("impossible: missing entry in package cache for " + dep + " imported by " + p.ImportPath)
}
- p.deps = append(p.deps, p1)
+ p.Internal.Deps = append(p.Internal.Deps, p1)
if p1.Error != nil {
p.DepsErrors = append(p.DepsErrors, p1.Error)
}
// unsafe is a fake package.
if p.Standard && (p.ImportPath == "unsafe" || cfg.BuildContext.Compiler == "gccgo") {
- p.target = ""
+ p.Internal.Target = ""
}
- p.Target = p.target
+ p.Target = p.Internal.Target
// If cgo is not enabled, ignore cgo supporting sources
// just as we ignore go files containing import "C".
}
// The gc toolchain only permits C source files with cgo.
- if len(p.CFiles) > 0 && !p.usesCgo() && !p.usesSwig() && cfg.BuildContext.Compiler == "gc" {
+ if len(p.CFiles) > 0 && !p.UsesCgo() && !p.UsesSwig() && cfg.BuildContext.Compiler == "gc" {
p.Error = &PackageError{
- ImportStack: stk.copy(),
+ ImportStack: stk.Copy(),
Err: fmt.Sprintf("C source files not allowed when not using cgo or SWIG: %s", strings.Join(p.CFiles, " ")),
}
return p
dep1, dep2 := str.FoldDup(p.Deps)
if dep1 != "" {
p.Error = &PackageError{
- ImportStack: stk.copy(),
+ ImportStack: stk.Copy(),
Err: fmt.Sprintf("case-insensitive import collision: %q and %q", dep1, dep2),
}
return p
// For binary-only package, use build ID from supplied package binary.
buildID, err := buildid.ReadBuildID(p.Name, p.Target)
if err == nil {
- p.buildID = buildID
+ p.Internal.BuildID = buildID
}
} else {
computeBuildID(p)
}
// usesSwig reports whether the package needs to run SWIG.
-func (p *Package) usesSwig() bool {
+func (p *Package) UsesSwig() bool {
return len(p.SwigFiles) > 0 || len(p.SwigCXXFiles) > 0
}
// usesCgo reports whether the package needs to run cgo
-func (p *Package) usesCgo() bool {
+func (p *Package) UsesCgo() bool {
return len(p.CgoFiles) > 0
}
// packageList returns the list of packages in the dag rooted at roots
// as visited in a depth-first post-order traversal.
-func packageList(roots []*Package) []*Package {
+func PackageList(roots []*Package) []*Package {
seen := map[*Package]bool{}
all := []*Package{}
var walk func(*Package)
return
}
seen[p] = true
- for _, p1 := range p.imports {
+ for _, p1 := range p.Internal.Imports {
walk(p1)
}
all = append(all, p)
// computeStale computes the Stale flag in the package dag that starts
// at the named pkgs (command-line arguments).
-func computeStale(pkgs ...*Package) {
- for _, p := range packageList(pkgs) {
+func ComputeStale(pkgs ...*Package) {
+ for _, p := range PackageList(pkgs) {
p.Stale, p.StaleReason = isStale(p)
}
}
// if a rebuild is needed, that rebuild attempt will produce a useful error.
// (Some commands, such as 'go list', do not attempt to rebuild.)
if p.BinaryOnly {
- if p.target == "" {
+ if p.Internal.Target == "" {
// Fail if a build is attempted.
return true, "no source code for package, but no install target"
}
- if _, err := os.Stat(p.target); err != nil {
+ if _, err := os.Stat(p.Internal.Target); err != nil {
// Fail if a build is attempted.
return true, "no source code for package, but cannot access install target: " + err.Error()
}
}
// If there's no install target, we have to rebuild.
- if p.target == "" {
+ if p.Internal.Target == "" {
return true, "no install target"
}
// Package is stale if completely unbuilt.
- fi, err := os.Stat(p.target)
+ fi, err := os.Stat(p.Internal.Target)
if err != nil {
return true, "cannot stat install target"
}
// two versions of Go compiling a single GOPATH.
// See issue 8290 and issue 10702.
targetBuildID, err := buildid.ReadBuildID(p.Name, p.Target)
- if err == nil && targetBuildID != p.buildID {
+ if err == nil && targetBuildID != p.Internal.BuildID {
return true, "build ID mismatch"
}
// Package is stale if a dependency is.
- for _, p1 := range p.deps {
+ for _, p1 := range p.Internal.Deps {
if p1.Stale {
return true, "stale dependency"
}
}
// Package is stale if a dependency is, or if a dependency is newer.
- for _, p1 := range p.deps {
- if p1.target != "" && olderThan(p1.target) {
+ for _, p1 := range p.Internal.Deps {
+ if p1.Internal.Target != "" && olderThan(p1.Internal.Target) {
return true, "newer dependency"
}
}
// and get a full rebuild anyway.
// Excluding $GOROOT used to also fix issue 4106, but that's now
// taken care of above (at least when the installed Go is a released version).
- if p.Root != goroot {
+ if p.Root != cfg.GOROOT {
if olderThan(cfg.BuildToolchainCompiler) {
return true, "newer compiler"
}
- if p.build.IsCommand() && olderThan(cfg.BuildToolchainLinker) {
+ if p.Internal.Build.IsCommand() && olderThan(cfg.BuildToolchainLinker) {
return true, "newer linker"
}
}
return false, ""
}
-// computeBuildID computes the build ID for p, leaving it in p.buildID.
+// computeBuildID computes the build ID for p, leaving it in p.Internal.BuildID.
// Build ID is a hash of the information we want to detect changes in.
// See the long comment in isStale for details.
func computeBuildID(p *Package) {
// people use the same GOPATH but switch between
// different Go releases. See issue 10702.
// This is also a better fix for issue 8290.
- for _, p1 := range p.deps {
- fmt.Fprintf(h, "dep %s %s\n", p1.ImportPath, p1.buildID)
+ for _, p1 := range p.Internal.Deps {
+ fmt.Fprintf(h, "dep %s %s\n", p1.ImportPath, p1.Internal.BuildID)
}
- p.buildID = fmt.Sprintf("%x", h.Sum(nil))
+ p.Internal.BuildID = fmt.Sprintf("%x", h.Sum(nil))
}
var cmdCache = map[string]*Package{}
+func ClearCmdCache() {
+ for name := range cmdCache {
+ delete(cmdCache, name)
+ }
+}
+
// loadPackage is like loadImport but is used for command-line arguments,
// not for paths found in import statements. In addition to ordinary import paths,
// loadPackage accepts pseudo-paths beginning with cmd/ to denote commands
// in the Go command directory, as well as paths to those directories.
-func loadPackage(arg string, stk *importStack) *Package {
+func LoadPackage(arg string, stk *ImportStack) *Package {
if build.IsLocalImport(arg) {
dir := arg
if !filepath.IsAbs(dir) {
dir = abs
}
}
- if sub, ok := hasSubdir(gorootSrc, dir); ok && strings.HasPrefix(sub, "cmd/") && !strings.Contains(sub[4:], "/") {
+ if sub, ok := hasSubdir(cfg.GOROOTsrc, dir); ok && strings.HasPrefix(sub, "cmd/") && !strings.Contains(sub[4:], "/") {
arg = sub
}
}
if p := cmdCache[arg]; p != nil {
return p
}
- stk.push(arg)
- defer stk.pop()
+ stk.Push(arg)
+ defer stk.Pop()
- bp, err := cfg.BuildContext.ImportDir(filepath.Join(gorootSrc, arg), 0)
+ bp, err := cfg.BuildContext.ImportDir(filepath.Join(cfg.GOROOTsrc, arg), 0)
bp.ImportPath = arg
bp.Goroot = true
- bp.BinDir = gorootBin
- if gobin != "" {
- bp.BinDir = gobin
+ bp.BinDir = cfg.GOROOTbin
+ if cfg.GOROOTbin != "" {
+ bp.BinDir = cfg.GOROOTbin
}
- bp.Root = goroot
- bp.SrcRoot = gorootSrc
+ bp.Root = cfg.GOROOT
+ bp.SrcRoot = cfg.GOROOTsrc
p := new(Package)
cmdCache[arg] = p
p.load(stk, bp, err)
if p.Error == nil && p.Name != "main" {
p.Error = &PackageError{
- ImportStack: stk.copy(),
+ ImportStack: stk.Copy(),
Err: fmt.Sprintf("expected package main but found package %s in %s", p.Name, p.Dir),
}
}
}
}
- return loadImport(arg, base.Cwd, nil, stk, nil, 0)
+ return LoadImport(arg, base.Cwd, nil, stk, nil, 0)
}
// packages returns the packages named by the
// to load dependencies of a named package, the named
// package is still returned, with p.Incomplete = true
// and details in p.DepsErrors.
-func packages(args []string) []*Package {
+func Packages(args []string) []*Package {
var pkgs []*Package
- for _, pkg := range packagesAndErrors(args) {
+ for _, pkg := range PackagesAndErrors(args) {
if pkg.Error != nil {
base.Errorf("can't load package: %s", pkg.Error)
continue
// *Package for every argument, even the ones that
// cannot be loaded at all.
// The packages that fail to load will have p.Error != nil.
-func packagesAndErrors(args []string) []*Package {
+func PackagesAndErrors(args []string) []*Package {
if len(args) > 0 && strings.HasSuffix(args[0], ".go") {
- return []*Package{goFilesPackage(args)}
+ return []*Package{GoFilesPackage(args)}
}
- args = importPaths(args)
+ args = ImportPaths(args)
var (
pkgs []*Package
- stk importStack
+ stk ImportStack
seenArg = make(map[string]bool)
seenPkg = make(map[*Package]bool)
)
continue
}
seenArg[arg] = true
- pkg := loadPackage(arg, &stk)
+ pkg := LoadPackage(arg, &stk)
if seenPkg[pkg] {
continue
}
seenPkg[pkg] = true
pkgs = append(pkgs, pkg)
}
- computeStale(pkgs...)
+ ComputeStale(pkgs...)
return pkgs
}
// packagesForBuild is like 'packages' but fails if any of
// the packages or their dependencies have errors
// (cannot be built).
-func packagesForBuild(args []string) []*Package {
- pkgs := packagesAndErrors(args)
+func PackagesForBuild(args []string) []*Package {
+ pkgs := PackagesAndErrors(args)
printed := map[*PackageError]bool{}
for _, pkg := range pkgs {
if pkg.Error != nil {
// which doesn't work very well.
seen := map[string]bool{}
reported := map[string]bool{}
- for _, pkg := range packageList(pkgs) {
+ for _, pkg := range PackageList(pkgs) {
if seen[pkg.ImportPath] && !reported[pkg.ImportPath] {
reported[pkg.ImportPath] = true
base.Errorf("internal error: duplicate loads of %s", pkg.ImportPath)
return pkgs
}
-// hasSubdir reports whether dir is a subdirectory of
-// (possibly multiple levels below) root.
-// If so, it sets rel to the path fragment that must be
-// appended to root to reach dir.
-func hasSubdir(root, dir string) (rel string, ok bool) {
- if p, err := filepath.EvalSymlinks(root); err == nil {
- root = p
+// GoFilesPackage creates a package for building a collection of Go files
+// (typically named on the command line). The target is named p.a for
+// package p or named after the first Go file for package main.
+func GoFilesPackage(gofiles []string) *Package {
+ // TODO: Remove this restriction.
+ for _, f := range gofiles {
+ if !strings.HasSuffix(f, ".go") {
+ base.Fatalf("named files must be .go files")
+ }
+ }
+
+ var stk ImportStack
+ ctxt := cfg.BuildContext
+ ctxt.UseAllFiles = true
+
+ // Synthesize fake "directory" that only shows the named files,
+ // to make it look like this is a standard package or
+ // command directory. So that local imports resolve
+ // consistently, the files must all be in the same directory.
+ var dirent []os.FileInfo
+ var dir string
+ for _, file := range gofiles {
+ fi, err := os.Stat(file)
+ if err != nil {
+ base.Fatalf("%s", err)
+ }
+ if fi.IsDir() {
+ base.Fatalf("%s is a directory, should be a Go file", file)
+ }
+ dir1, _ := filepath.Split(file)
+ if dir1 == "" {
+ dir1 = "./"
+ }
+ if dir == "" {
+ dir = dir1
+ } else if dir != dir1 {
+ base.Fatalf("named files must all be in one directory; have %s and %s", dir, dir1)
+ }
+ dirent = append(dirent, fi)
}
- if p, err := filepath.EvalSymlinks(dir); err == nil {
- dir = p
+ ctxt.ReadDir = func(string) ([]os.FileInfo, error) { return dirent, nil }
+
+ var err error
+ if dir == "" {
+ dir = base.Cwd
}
- const sep = string(filepath.Separator)
- root = filepath.Clean(root)
- if !strings.HasSuffix(root, sep) {
- root += sep
+ dir, err = filepath.Abs(dir)
+ if err != nil {
+ base.Fatalf("%s", err)
}
- dir = filepath.Clean(dir)
- if !strings.HasPrefix(dir, root) {
- return "", false
+
+ bp, err := ctxt.ImportDir(dir, 0)
+ pkg := new(Package)
+ pkg.Internal.Local = true
+ pkg.Internal.Cmdline = true
+ stk.Push("main")
+ pkg.load(&stk, bp, err)
+ stk.Pop()
+ pkg.Internal.LocalPrefix = dirToImportPath(dir)
+ pkg.ImportPath = "command-line-arguments"
+ pkg.Internal.Target = ""
+
+ if pkg.Name == "main" {
+ _, elem := filepath.Split(gofiles[0])
+ exe := elem[:len(elem)-len(".go")] + cfg.ExeSuffix
+ if cfg.BuildO == "" {
+ cfg.BuildO = exe
+ }
+ if cfg.GOBIN != "" {
+ pkg.Internal.Target = filepath.Join(cfg.GOBIN, exe)
+ }
}
- return filepath.ToSlash(dir[len(root):]), true
+
+ pkg.Target = pkg.Internal.Target
+ pkg.Stale = true
+ pkg.StaleReason = "files named on command line"
+
+ ComputeStale(pkg)
+ return pkg
}
--- /dev/null
+// 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"
+}
// +build testgo
-package main
+package load
import "os"
import (
"bufio"
- "cmd/go/internal/cfg"
"cmd/go/internal/base"
+ "cmd/go/internal/cfg"
+ "cmd/go/internal/load"
"encoding/json"
"io"
"os"
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()
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)
}
}
- 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)
}
}
import (
"flag"
"fmt"
- "go/build"
"log"
"os"
- "path"
"path/filepath"
- "regexp"
"runtime"
"strings"
}
}
- 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)
}
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
}
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
-}
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"
}
}
+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,
},
}
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"
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
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]
}
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)
import (
"bytes"
- "cmd/go/internal/cfg"
"cmd/go/internal/base"
+ "cmd/go/internal/cfg"
+ "cmd/go/internal/load"
"cmd/go/internal/str"
"errors"
"fmt"
testC bool // -c flag
testCover bool // -cover flag
// Note: testCoverMode is cfg.TestCoverMode (-covermode)
- testCoverPaths []string // -coverpkg flag
- testCoverPkgs []*Package // -coverpkg flag
- testO string // -o flag
- testProfile bool // some profiling flag
- testNeedBinary bool // profile needs to keep binary around
- testV bool // -v flag
- testTimeout string // -timeout flag
+ testCoverPaths []string // -coverpkg flag
+ testCoverPkgs []*load.Package // -coverpkg flag
+ testO string // -o flag
+ testProfile bool // some profiling flag
+ testNeedBinary bool // profile needs to keep binary around
+ testV bool // -v flag
+ testTimeout string // -timeout flag
testArgs []string
testBench bool
testStreamOutput bool // show output as it is generated
instrumentInit()
buildModeInit()
- pkgs := packagesForBuild(pkgArgs)
+ pkgs := load.PackagesForBuild(pkgArgs)
if len(pkgs) == 0 {
base.Fatalf("no packages to test")
}
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
}
}
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)
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)
}
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...)
}
}
// 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
}
// 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
"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}}
// 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
}
// 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
}
}
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".
// 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
// External test package.
if len(p.XTestGoFiles) > 0 {
- pxtest = &Package{
- Name: p.Name + "_test",
- ImportPath: p.ImportPath + "_test",
- localPrefix: p.localPrefix,
- Root: p.Root,
- Dir: p.Dir,
- GoFiles: p.XTestGoFiles,
- Imports: p.XTestImports,
- build: &build.Package{
- ImportPos: p.build.XTestImportPos,
+ pxtest = &load.Package{
+ PackagePublic: load.PackagePublic{
+ Name: p.Name + "_test",
+ ImportPath: p.ImportPath + "_test",
+ Root: p.Root,
+ Dir: p.Dir,
+ GoFiles: p.XTestGoFiles,
+ Imports: p.XTestImports,
+ Stale: true,
+ },
+ Internal: load.PackageInternal{
+ LocalPrefix: p.Internal.LocalPrefix,
+ Build: &build.Package{
+ ImportPos: p.Internal.Build.XTestImportPos,
+ },
+ Imports: ximports,
+ Pkgdir: testDir,
+ Fake: true,
+ External: true,
},
- imports: ximports,
- pkgdir: testDir,
- fake: true,
- external: true,
- Stale: true,
}
if pxtestNeedsPtest {
- pxtest.imports = append(pxtest.imports, ptest)
+ pxtest.Internal.Imports = append(pxtest.Internal.Imports, ptest)
}
}
// Action for building pkg.test.
- pmain = &Package{
- Name: "main",
- Dir: testDir,
- GoFiles: []string{"_testmain.go"},
- ImportPath: "testmain",
- Root: p.Root,
- build: &build.Package{Name: "main"},
- pkgdir: testDir,
- fake: true,
- Stale: true,
- omitDWARF: !testC && !testNeedBinary,
+ pmain = &load.Package{
+ PackagePublic: load.PackagePublic{
+ Name: "main",
+ Dir: testDir,
+ GoFiles: []string{"_testmain.go"},
+ ImportPath: "testmain",
+ Root: p.Root,
+ Stale: true,
+ },
+ Internal: load.PackageInternal{
+ Build: &build.Package{Name: "main"},
+ Pkgdir: testDir,
+ Fake: true,
+ OmitDWARF: !testC && !testNeedBinary,
+ },
}
// The generated main also imports testing, regexp, and os.
- stk.push("testmain")
+ stk.Push("testmain")
for dep := range testMainDeps {
if dep == ptest.ImportPath {
- pmain.imports = append(pmain.imports, ptest)
+ pmain.Internal.Imports = append(pmain.Internal.Imports, ptest)
} else {
- p1 := loadImport(dep, "", nil, &stk, nil, 0)
+ p1 := load.LoadImport(dep, "", nil, &stk, nil, 0)
if p1.Error != nil {
return nil, nil, nil, p1.Error
}
- pmain.imports = append(pmain.imports, p1)
+ pmain.Internal.Imports = append(pmain.Internal.Imports, p1)
}
}
if testCoverPkgs != nil {
// Add imports, but avoid duplicates.
- seen := map[*Package]bool{p: true, ptest: true}
- for _, p1 := range pmain.imports {
+ seen := map[*load.Package]bool{p: true, ptest: true}
+ for _, p1 := range pmain.Internal.Imports {
seen[p1] = true
}
for _, p1 := range testCoverPkgs {
if !seen[p1] {
seen[p1] = true
- pmain.imports = append(pmain.imports, p1)
+ pmain.Internal.Imports = append(pmain.Internal.Imports, p1)
}
}
}
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
}
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})
}
}
}
}
- computeStale(pmain)
+ load.ComputeStale(pmain)
if ptest != p {
a := b.action(modeBuild, modeBuild, ptest)
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
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() {
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
}
}
}
// 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),
}
// 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="
}
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,
}
Benchmarks []testFunc
Examples []testFunc
TestMain *testFunc
- Package *Package
+ Package *load.Package
ImportTest bool
NeedTest bool
ImportXtest bool
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)
package main
import (
- "cmd/go/internal/cfg"
"cmd/go/internal/base"
+ "cmd/go/internal/cfg"
"flag"
"fmt"
"os"
"sort"
"strings"
- "cmd/go/internal/cfg"
"cmd/go/internal/base"
+ "cmd/go/internal/cfg"
)
var cmdTool = &base.Command{
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 {
import (
"path/filepath"
- "cmd/go/internal/cfg"
"cmd/go/internal/base"
+ "cmd/go/internal/cfg"
+ "cmd/go/internal/load"
"cmd/go/internal/str"
)
}
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 {
}
}
-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])
}