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