]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/go: split out cmd/go/internal/base
authorRuss Cox <rsc@golang.org>
Fri, 13 Jan 2017 19:41:42 +0000 (14:41 -0500)
committerRuss Cox <rsc@golang.org>
Fri, 3 Feb 2017 20:31:00 +0000 (20:31 +0000)
This is one CL in a long sequence of changes to break up the
go command from one package into a plausible group of packages.

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

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

For #18653.

Change-Id: I7c5dde6e7fe4f390e6607303b4d42535c674eac3
Reviewed-on: https://go-review.googlesource.com/36193
Reviewed-by: David Crawshaw <crawshaw@golang.org>
27 files changed:
src/cmd/go/bug.go
src/cmd/go/build.go
src/cmd/go/clean.go
src/cmd/go/doc.go
src/cmd/go/env.go
src/cmd/go/fix.go
src/cmd/go/fmt.go
src/cmd/go/generate.go
src/cmd/go/get.go
src/cmd/go/help.go
src/cmd/go/internal/base/base.go [new file with mode: 0644]
src/cmd/go/internal/base/path.go [new file with mode: 0644]
src/cmd/go/internal/base/signal.go [moved from src/cmd/go/signal.go with 66% similarity]
src/cmd/go/internal/base/signal_notunix.go [moved from src/cmd/go/signal_notunix.go with 60% similarity]
src/cmd/go/internal/base/signal_unix.go [moved from src/cmd/go/signal_unix.go with 75% similarity]
src/cmd/go/internal/base/tool.go [new file with mode: 0644]
src/cmd/go/internal/cfg/cfg.go
src/cmd/go/list.go
src/cmd/go/main.go
src/cmd/go/pkg.go
src/cmd/go/pkg_test.go
src/cmd/go/run.go
src/cmd/go/test.go
src/cmd/go/testflag.go
src/cmd/go/tool.go
src/cmd/go/version.go
src/cmd/go/vet.go

index 8d55a09a2e1e564542378eecf22a755ceeb9dbb7..60279c606044758dbca996167b5d4606baf8e01f 100644 (file)
@@ -7,6 +7,7 @@ package main
 import (
        "bytes"
        "cmd/go/internal/cfg"
+       "cmd/go/internal/base"
        "fmt"
        "io"
        "io/ioutil"
@@ -18,7 +19,7 @@ import (
        "strings"
 )
 
-var cmdBug = &Command{
+var cmdBug = &base.Command{
        Run:       runBug,
        UsageLine: "bug",
        Short:     "start a bug report",
@@ -32,7 +33,7 @@ func init() {
        cmdBug.Flag.BoolVar(&cfg.BuildV, "v", false, "")
 }
 
-func runBug(cmd *Command, args []string) {
+func runBug(cmd *base.Command, args []string) {
        var buf bytes.Buffer
        buf.WriteString(bugHeader)
        inspectGoVersion(&buf)
index 329e84651861562b4809ed63d018a29e1255a851..caa876c4ae510deff13d47d23ec21eb5d4a09f36 100644 (file)
@@ -28,10 +28,11 @@ import (
        "time"
 
        "cmd/go/internal/cfg"
+       "cmd/go/internal/base"
        "cmd/go/internal/str"
 )
 
-var cmdBuild = &Command{
+var cmdBuild = &base.Command{
        UsageLine: "build [-o output] [-i] [build flags] [packages]",
        Short:     "compile packages and dependencies",
        Long: `
@@ -196,7 +197,7 @@ func init() {
 
 // addBuildFlags adds the flags common to the build, clean, get,
 // install, list, run, and test commands.
-func addBuildFlags(cmd *Command) {
+func addBuildFlags(cmd *base.Command) {
        cmd.Flag.BoolVar(&cfg.BuildA, "a", false, "")
        cmd.Flag.BoolVar(&cfg.BuildN, "n", false, "")
        cmd.Flag.IntVar(&cfg.BuildP, "p", cfg.BuildP, "")
@@ -219,11 +220,6 @@ func addBuildFlags(cmd *Command) {
        cmd.Flag.BoolVar(&cfg.BuildWork, "work", false, "")
 }
 
-func addBuildFlagsNX(cmd *Command) {
-       cmd.Flag.BoolVar(&cfg.BuildN, "n", false, "")
-       cmd.Flag.BoolVar(&cfg.BuildX, "x", false, "")
-}
-
 func isSpaceByte(c byte) bool {
        return c == ' ' || c == '\t' || c == '\n' || c == '\r'
 }
@@ -321,7 +317,7 @@ func buildModeInit() {
        case "c-archive":
                pkgsFilter = func(p []*Package) []*Package {
                        if len(p) != 1 || p[0].Name != "main" {
-                               fatalf("-buildmode=c-archive requires exactly one main package")
+                               base.Fatalf("-buildmode=c-archive requires exactly one main package")
                        }
                        return p
                }
@@ -350,7 +346,7 @@ func buildModeInit() {
                                codegenArg = "-shared"
                        case "darwin/amd64", "darwin/386":
                        default:
-                               fatalf("-buildmode=c-shared not supported on %s\n", platform)
+                               base.Fatalf("-buildmode=c-shared not supported on %s\n", platform)
                        }
                }
                ldBuildmode = "c-shared"
@@ -370,14 +366,14 @@ func buildModeInit() {
                ldBuildmode = "exe"
        case "pie":
                if gccgo {
-                       fatalf("-buildmode=pie not supported by gccgo")
+                       base.Fatalf("-buildmode=pie not supported by gccgo")
                } else {
                        switch platform {
                        case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le", "linux/s390x",
                                "android/amd64", "android/arm", "android/arm64", "android/386":
                                codegenArg = "-shared"
                        default:
-                               fatalf("-buildmode=pie not supported on %s\n", platform)
+                               base.Fatalf("-buildmode=pie not supported on %s\n", platform)
                        }
                }
                ldBuildmode = "pie"
@@ -389,12 +385,12 @@ func buildModeInit() {
                        switch platform {
                        case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le", "linux/s390x":
                        default:
-                               fatalf("-buildmode=shared not supported on %s\n", platform)
+                               base.Fatalf("-buildmode=shared not supported on %s\n", platform)
                        }
                        codegenArg = "-dynlink"
                }
                if cfg.BuildO != "" {
-                       fatalf("-buildmode=shared and -o not supported together")
+                       base.Fatalf("-buildmode=shared and -o not supported together")
                }
                ldBuildmode = "shared"
        case "plugin":
@@ -406,14 +402,14 @@ func buildModeInit() {
                        case "linux/amd64", "linux/arm", "linux/arm64", "linux/386",
                                "android/amd64", "android/arm", "android/arm64", "android/386":
                        default:
-                               fatalf("-buildmode=plugin not supported on %s\n", platform)
+                               base.Fatalf("-buildmode=plugin not supported on %s\n", platform)
                        }
                        codegenArg = "-dynlink"
                }
                cfg.ExeSuffix = ".so"
                ldBuildmode = "plugin"
        default:
-               fatalf("buildmode=%s not supported", cfg.BuildBuildmode)
+               base.Fatalf("buildmode=%s not supported", cfg.BuildBuildmode)
        }
        if cfg.BuildLinkshared {
                if gccgo {
@@ -423,7 +419,7 @@ func buildModeInit() {
                        case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le", "linux/s390x":
                                buildAsmflags = append(buildAsmflags, "-D=GOBUILDMODE_shared=1")
                        default:
-                               fatalf("-linkshared not supported on %s\n", platform)
+                               base.Fatalf("-linkshared not supported on %s\n", platform)
                        }
                        codegenArg = "-dynlink"
                        // TODO(mwhudson): remove -w when that gets fixed in linker.
@@ -447,7 +443,7 @@ func buildModeInit() {
        }
 }
 
-func runBuild(cmd *Command, args []string) {
+func runBuild(cmd *base.Command, args []string) {
        instrumentInit()
        buildModeInit()
        var b builder
@@ -487,9 +483,9 @@ func runBuild(cmd *Command, args []string) {
 
        if cfg.BuildO != "" {
                if len(pkgs) > 1 {
-                       fatalf("go build: cannot use -o with multiple packages")
+                       base.Fatalf("go build: cannot use -o with multiple packages")
                } else if len(pkgs) == 0 {
-                       fatalf("no packages to build")
+                       base.Fatalf("no packages to build")
                }
                p := pkgs[0]
                p.target = cfg.BuildO
@@ -504,7 +500,7 @@ func runBuild(cmd *Command, args []string) {
        if cfg.BuildBuildmode == "shared" {
                pkgs := pkgsFilter(packages(args))
                if libName, err := libname(args, pkgs); err != nil {
-                       fatalf("%s", err.Error())
+                       base.Fatalf("%s", err.Error())
                } else {
                        a = b.libaction(libName, pkgs, modeBuild, depMode)
                }
@@ -517,7 +513,7 @@ func runBuild(cmd *Command, args []string) {
        b.do(a)
 }
 
-var cmdInstall = &Command{
+var cmdInstall = &base.Command{
        UsageLine: "install [build flags] [packages]",
        Short:     "compile and install packages and dependencies",
        Long: `
@@ -592,13 +588,13 @@ func libname(args []string, pkgs []*Package) (string, error) {
        return "lib" + libname + ".so", nil
 }
 
-func runInstall(cmd *Command, args []string) {
+func runInstall(cmd *base.Command, args []string) {
        installPackages(args, false)
 }
 
 func installPackages(args []string, forGet bool) {
        if gobin != "" && !filepath.IsAbs(gobin) {
-               fatalf("cannot install, GOBIN must be an absolute path")
+               base.Fatalf("cannot install, GOBIN must be an absolute path")
        }
 
        instrumentInit()
@@ -609,18 +605,18 @@ func installPackages(args []string, forGet bool) {
                if p.Target == "" && (!p.Standard || p.ImportPath != "unsafe") {
                        switch {
                        case p.gobinSubdir:
-                               errorf("go install: cannot install cross-compiled binaries when GOBIN is set")
+                               base.Errorf("go install: cannot install cross-compiled binaries when GOBIN is set")
                        case p.cmdline:
-                               errorf("go install: no install location for .go files listed on command line (GOBIN not set)")
+                               base.Errorf("go install: no install location for .go files listed on command line (GOBIN not set)")
                        case p.ConflictDir != "":
-                               errorf("go install: no install location for %s: hidden by %s", p.Dir, p.ConflictDir)
+                               base.Errorf("go install: no install location for %s: hidden by %s", p.Dir, p.ConflictDir)
                        default:
-                               errorf("go install: no install location for directory %s outside GOPATH\n"+
+                               base.Errorf("go install: no install location for directory %s outside GOPATH\n"+
                                        "\tFor more details see: 'go help gopath'", p.Dir)
                        }
                }
        }
-       exitIfErrors()
+       base.ExitIfErrors()
 
        var b builder
        b.init()
@@ -629,7 +625,7 @@ func installPackages(args []string, forGet bool) {
        var a *action
        if cfg.BuildBuildmode == "shared" {
                if libName, err := libname(args, pkgs); err != nil {
-                       fatalf("%s", err.Error())
+                       base.Fatalf("%s", err.Error())
                } else {
                        a = b.libaction(libName, pkgs, modeInstall, modeInstall)
                }
@@ -658,7 +654,7 @@ func installPackages(args []string, forGet bool) {
                }
        }
        b.do(a)
-       exitIfErrors()
+       base.ExitIfErrors()
 
        // Success. If this command is 'go install' with no arguments
        // and the current directory (the implicit argument) is a command,
@@ -780,14 +776,14 @@ func (b *builder) init() {
        } else {
                b.work, err = ioutil.TempDir("", "go-build")
                if err != nil {
-                       fatalf("%s", err)
+                       base.Fatalf("%s", err)
                }
                if cfg.BuildX || cfg.BuildWork {
                        fmt.Fprintf(os.Stderr, "WORK=%s\n", b.work)
                }
                if !cfg.BuildWork {
                        workdir := b.work
-                       atexit(func() { os.RemoveAll(workdir) })
+                       base.AtExit(func() { os.RemoveAll(workdir) })
                }
        }
 }
@@ -799,7 +795,7 @@ func goFilesPackage(gofiles []string) *Package {
        // TODO: Remove this restriction.
        for _, f := range gofiles {
                if !strings.HasSuffix(f, ".go") {
-                       fatalf("named files must be .go files")
+                       base.Fatalf("named files must be .go files")
                }
        }
 
@@ -816,10 +812,10 @@ func goFilesPackage(gofiles []string) *Package {
        for _, file := range gofiles {
                fi, err := os.Stat(file)
                if err != nil {
-                       fatalf("%s", err)
+                       base.Fatalf("%s", err)
                }
                if fi.IsDir() {
-                       fatalf("%s is a directory, should be a Go file", file)
+                       base.Fatalf("%s is a directory, should be a Go file", file)
                }
                dir1, _ := filepath.Split(file)
                if dir1 == "" {
@@ -828,7 +824,7 @@ func goFilesPackage(gofiles []string) *Package {
                if dir == "" {
                        dir = dir1
                } else if dir != dir1 {
-                       fatalf("named files must all be in one directory; have %s and %s", dir, dir1)
+                       base.Fatalf("named files must all be in one directory; have %s and %s", dir, dir1)
                }
                dirent = append(dirent, fi)
        }
@@ -836,11 +832,11 @@ func goFilesPackage(gofiles []string) *Package {
 
        var err error
        if dir == "" {
-               dir = cwd
+               dir = base.Cwd
        }
        dir, err = filepath.Abs(dir)
        if err != nil {
-               fatalf("%s", err)
+               base.Fatalf("%s", err)
        }
 
        bp, err := ctxt.ImportDir(dir, 0)
@@ -895,7 +891,7 @@ func readpkglist(shlibpath string) (pkgs []*Package) {
        } else {
                pkglistbytes, err := readELFNote(shlibpath, "Go\x00\x00", 1)
                if err != nil {
-                       fatalf("readELFNote failed: %v", err)
+                       base.Fatalf("readELFNote failed: %v", err)
                }
                scanner := bufio.NewScanner(bytes.NewBuffer(pkglistbytes))
                for scanner.Scan() {
@@ -979,7 +975,7 @@ func (b *builder) action1(mode buildMode, depMode buildMode, p *Package, looksha
                        var stk importStack
                        p1 := loadPackage("cmd/cgo", &stk)
                        if p1.Error != nil {
-                               fatalf("load cmd/cgo: %v", p1.Error)
+                               base.Fatalf("load cmd/cgo: %v", p1.Error)
                        }
                        a.cgo = b.action(depMode, depMode, p1)
                        a.deps = append(a.deps, a.cgo)
@@ -1080,7 +1076,7 @@ func (b *builder) libaction(libname string, pkgs []*Package, mode, depMode build
        a := &action{}
        switch mode {
        default:
-               fatalf("unrecognized mode %v", mode)
+               base.Fatalf("unrecognized mode %v", mode)
 
        case modeBuild:
                a.f = (*builder).linkShared
@@ -1107,7 +1103,7 @@ func (b *builder) libaction(libname string, pkgs []*Package, mode, depMode build
                                var stk importStack
                                p := loadPackage("runtime/cgo", &stk)
                                if p.Error != nil {
-                                       fatalf("load runtime/cgo: %v", p.Error)
+                                       base.Fatalf("load runtime/cgo: %v", p.Error)
                                }
                                computeStale(p)
                                // If runtime/cgo is in another shared library, then that's
@@ -1128,7 +1124,7 @@ func (b *builder) libaction(libname string, pkgs []*Package, mode, depMode build
                                        var stk importStack
                                        p := loadPackage("math", &stk)
                                        if p.Error != nil {
-                                               fatalf("load math: %v", p.Error)
+                                               base.Fatalf("load math: %v", p.Error)
                                        }
                                        computeStale(p)
                                        // If math is in another shared library, then that's
@@ -1153,7 +1149,7 @@ func (b *builder) libaction(libname string, pkgs []*Package, mode, depMode build
                        if libdir == "" {
                                libdir = plibdir
                        } else if libdir != plibdir {
-                               fatalf("multiple roots %s & %s", libdir, plibdir)
+                               base.Fatalf("multiple roots %s & %s", libdir, plibdir)
                        }
                }
                a.target = filepath.Join(libdir, libname)
@@ -1292,11 +1288,11 @@ func (b *builder) do(root *action) {
 
                if err != nil {
                        if err == errPrintedOutput {
-                               setExitStatus(2)
+                               base.SetExitStatus(2)
                        } else if _, ok := err.(*build.NoGoError); ok && len(a.p.TestGoFiles) > 0 && b.testFilesOnlyOK {
                                // Ignore the "no buildable Go source files" error for a package with only test files.
                        } else {
-                               errorf("%s", err)
+                               base.Errorf("%s", err)
                        }
                        a.failed = true
                }
@@ -1342,8 +1338,8 @@ func (b *builder) do(root *action) {
                                        a := b.ready.pop()
                                        b.exec.Unlock()
                                        handle(a)
-                               case <-interrupted:
-                                       setExitStatus(1)
+                               case <-base.Interrupted:
+                                       base.SetExitStatus(1)
                                        return
                                }
                        }
@@ -1465,7 +1461,7 @@ func (b *builder) build(a *action) (err error) {
                        sfiles = nil
                }
 
-               cgoExe := tool("cgo")
+               cgoExe := base.Tool("cgo")
                if a.cgo != nil && a.cgo.target != "" {
                        cgoExe = a.cgo.target
                }
@@ -1857,7 +1853,7 @@ func (b *builder) copyFile(a *action, dst, src string, perm os.FileMode, force b
        }
 
        // On Windows, remove lingering ~ file from last attempt.
-       if toolIsWindows {
+       if base.ToolIsWindows {
                if _, err := os.Stat(dst + "~"); err == nil {
                        os.Remove(dst + "~")
                }
@@ -1865,7 +1861,7 @@ func (b *builder) copyFile(a *action, dst, src string, perm os.FileMode, force b
 
        mayberemovefile(dst)
        df, err := os.OpenFile(dst, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm)
-       if err != nil && toolIsWindows {
+       if err != nil && base.ToolIsWindows {
                // Windows does not allow deletion of a binary file
                // while it is executing. Try to move it out of the way.
                // If the move fails, which is likely, we'll try again the
@@ -1912,7 +1908,7 @@ func (b *builder) installHeader(a *action) error {
 func (b *builder) cover(a *action, dst, src string, perm os.FileMode, varName string) error {
        return b.run(a.objdir, "cover "+a.p.ImportPath, nil,
                cfg.BuildToolexec,
-               tool("cover"),
+               base.Tool("cover"),
                "-mode", a.p.coverMode,
                "-var", varName,
                "-o", dst,
@@ -2018,7 +2014,7 @@ func (b *builder) showcmd(dir string, format string, args ...interface{}) {
 func (b *builder) showOutput(dir, desc, out string) {
        prefix := "# " + desc
        suffix := "\n" + out
-       if reldir := shortPath(dir); reldir != dir {
+       if reldir := base.ShortPath(dir); reldir != dir {
                suffix = strings.Replace(suffix, " "+dir, " "+reldir, -1)
                suffix = strings.Replace(suffix, "\n"+dir, "\n"+reldir, -1)
        }
@@ -2029,29 +2025,6 @@ func (b *builder) showOutput(dir, desc, out string) {
        b.print(prefix, suffix)
 }
 
-// shortPath returns an absolute or relative name for path, whatever is shorter.
-func shortPath(path string) string {
-       if rel, err := filepath.Rel(cwd, path); err == nil && len(rel) < len(path) {
-               return rel
-       }
-       return path
-}
-
-// relPaths returns a copy of paths with absolute paths
-// made relative to the current directory if they would be shorter.
-func relPaths(paths []string) []string {
-       var out []string
-       pwd, _ := os.Getwd()
-       for _, p := range paths {
-               rel, err := filepath.Rel(pwd, p)
-               if err == nil && len(rel) < len(p) {
-                       p = rel
-               }
-               out = append(out, p)
-       }
-       return out
-}
-
 // errPrintedOutput is a special error indicating that a command failed
 // but that it generated output as well, and that output has already
 // been printed, so there's no point showing 'exit status 1' or whatever
@@ -2316,11 +2289,11 @@ func (noToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error
 type gcToolchain struct{}
 
 func (gcToolchain) compiler() string {
-       return tool("compile")
+       return base.Tool("compile")
 }
 
 func (gcToolchain) linker() string {
-       return tool("link")
+       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) {
@@ -2370,7 +2343,7 @@ func (gcToolchain) gc(b *builder, p *Package, archive, obj string, asmhdr bool,
                }
        }
 
-       args := []interface{}{cfg.BuildToolexec, 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.localPrefix, importArgs}
        if ofile == archive {
                args = append(args, "-pack")
        }
@@ -2388,7 +2361,7 @@ func (gcToolchain) gc(b *builder, p *Package, archive, obj string, asmhdr bool,
 func (gcToolchain) asm(b *builder, p *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")
-       args := []interface{}{cfg.BuildToolexec, tool("asm"), "-trimpath", b.work, "-I", obj, "-I", inc, "-D", "GOOS_" + cfg.Goos, "-D", "GOARCH_" + cfg.Goarch, buildAsmflags}
+       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 {
                        if arg == "-dynlink" {
@@ -2414,7 +2387,7 @@ func (gcToolchain) asm(b *builder, p *Package, obj string, sfiles []string) ([]s
 func toolVerify(b *builder, p *Package, newTool string, ofile string, args []interface{}) error {
        newArgs := make([]interface{}, len(args))
        copy(newArgs, args)
-       newArgs[1] = tool(newTool)
+       newArgs[1] = base.Tool(newTool)
        newArgs[3] = ofile + ".new" // x.6 becomes x.6.new
        if err := b.run(p.Dir, p.ImportPath, nil, newArgs...); err != nil {
                return err
@@ -2450,7 +2423,7 @@ func (gcToolchain) pack(b *builder, p *Package, objDir, afile string, ofiles []s
        // Since it used to not work that way, verify.
        if !cfg.BuildN {
                if _, err := os.Stat(absAfile); err != nil {
-                       fatalf("os.Stat of archive file failed: %v", err)
+                       base.Fatalf("os.Stat of archive file failed: %v", err)
                }
        }
 
@@ -2600,7 +2573,7 @@ func (gcToolchain) ld(b *builder, root *action, out string, allactions []*action
                dir, out = filepath.Split(out)
        }
 
-       return b.run(dir, root.p.ImportPath, nil, cfg.BuildToolexec, tool("link"), "-o", out, importArgs, ldflags, mainpkg)
+       return b.run(dir, root.p.ImportPath, nil, cfg.BuildToolexec, base.Tool("link"), "-o", out, importArgs, ldflags, mainpkg)
 }
 
 func (gcToolchain) ldShared(b *builder, toplevelactions []*action, out string, allactions []*action) error {
@@ -2631,7 +2604,7 @@ func (gcToolchain) ldShared(b *builder, toplevelactions []*action, out string, a
                }
                ldflags = append(ldflags, d.p.ImportPath+"="+d.target)
        }
-       return b.run(".", out, nil, cfg.BuildToolexec, tool("link"), "-o", out, importArgs, ldflags)
+       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 {
@@ -2943,7 +2916,7 @@ func (tools gccgoToolchain) link(b *builder, root *action, out string, allaction
                ldflags = append(ldflags, "-zdefs", "-shared", "-nostdlib", "-lgo", "-lgcc_s", "-lgcc", "-lc")
 
        default:
-               fatalf("-buildmode=%s not supported for gccgo", buildmode)
+               base.Fatalf("-buildmode=%s not supported for gccgo", buildmode)
        }
 
        switch buildmode {
index f9f452d65d66035aeb738191c4d29afc364d6c88..4895eda4e3431a09fce9ca940e55a8384e875ebe 100644 (file)
@@ -6,6 +6,7 @@ package main
 
 import (
        "cmd/go/internal/cfg"
+       "cmd/go/internal/base"
        "fmt"
        "io/ioutil"
        "os"
@@ -13,7 +14,7 @@ import (
        "strings"
 )
 
-var cmdClean = &Command{
+var cmdClean = &base.Command{
        UsageLine: "clean [-i] [-r] [-n] [-x] [build flags] [packages]",
        Short:     "remove object files",
        Long: `
@@ -75,7 +76,7 @@ func init() {
        addBuildFlags(cmdClean)
 }
 
-func runClean(cmd *Command, args []string) {
+func runClean(cmd *base.Command, args []string) {
        for _, pkg := range packagesAndErrors(args) {
                clean(pkg)
        }
@@ -113,12 +114,12 @@ func clean(p *Package) {
        cleaned[p] = true
 
        if p.Dir == "" {
-               errorf("can't load package: %v", p.Error)
+               base.Errorf("can't load package: %v", p.Error)
                return
        }
        dirs, err := ioutil.ReadDir(p.Dir)
        if err != nil {
-               errorf("go clean %s: %v", p.Dir, err)
+               base.Errorf("go clean %s: %v", p.Dir, err)
                return
        }
 
@@ -193,7 +194,7 @@ func clean(p *Package) {
                                        }
                                }
                                if err := os.RemoveAll(filepath.Join(p.Dir, name)); err != nil {
-                                       errorf("go clean: %v", err)
+                                       base.Errorf("go clean: %v", err)
                                }
                        }
                        continue
@@ -232,7 +233,7 @@ func removeFile(f string) {
                return
        }
        // Windows does not allow deletion of a binary file while it is executing.
-       if toolIsWindows {
+       if base.ToolIsWindows {
                // Remove lingering ~ file from last attempt.
                if _, err2 := os.Stat(f + "~"); err2 == nil {
                        os.Remove(f + "~")
@@ -245,5 +246,5 @@ func removeFile(f string) {
                        return
                }
        }
-       errorf("go clean: %v", err)
+       base.Errorf("go clean: %v", err)
 }
index b9ecfc48bb8a514ec41286e508f43cb19b722aec..338fec14d3243a79d0ac1f16f9ee920aadac23f2 100644 (file)
@@ -6,9 +6,12 @@
 
 package main
 
-import "cmd/go/internal/cfg"
+import (
+       "cmd/go/internal/cfg"
+       "cmd/go/internal/base"
+)
 
-var cmdDoc = &Command{
+var cmdDoc = &base.Command{
        Run:         runDoc,
        UsageLine:   "doc [-u] [-c] [package|[package.]symbol[.method]]",
        CustomFlags: true,
@@ -115,6 +118,6 @@ Flags:
 `,
 }
 
-func runDoc(cmd *Command, args []string) {
-       run(cfg.BuildToolexec, tool("doc"), args)
+func runDoc(cmd *base.Command, args []string) {
+       base.Run(cfg.BuildToolexec, base.Tool("doc"), args)
 }
index 6db88f51ca0926ae77f4b046f3858eff04ac3c53..e143ddb357c6ebfa6ce51f2f94d09d7a080b8774 100644 (file)
@@ -6,13 +6,14 @@ package main
 
 import (
        "cmd/go/internal/cfg"
+       "cmd/go/internal/base"
        "fmt"
        "os"
        "runtime"
        "strings"
 )
 
-var cmdEnv = &Command{
+var cmdEnv = &base.Command{
        Run:       runEnv,
        UsageLine: "env [var ...]",
        Short:     "print Go environment information",
@@ -40,7 +41,7 @@ func mkEnv() []cfg.EnvVar {
                {"GOPATH", cfg.BuildContext.GOPATH},
                {"GORACE", os.Getenv("GORACE")},
                {"GOROOT", goroot},
-               {"GOTOOLDIR", toolDir},
+               {"GOTOOLDIR", base.ToolDir},
 
                // disable escape codes in clang errors
                {"TERM", "dumb"},
@@ -98,7 +99,7 @@ func extraEnvVars() []cfg.EnvVar {
        }
 }
 
-func runEnv(cmd *Command, args []string) {
+func runEnv(cmd *base.Command, args []string) {
        env := cfg.NewEnv
        env = append(env, extraEnvVars()...)
        if len(args) > 0 {
index 9783226e362a250a40cb35a4570243eb7ffb2280..bb8c34e14a990e360e5fe4e5308a897ca695d078 100644 (file)
@@ -6,10 +6,11 @@ package main
 
 import (
        "cmd/go/internal/cfg"
+       "cmd/go/internal/base"
        "cmd/go/internal/str"
 )
 
-var cmdFix = &Command{
+var cmdFix = &base.Command{
        Run:       runFix,
        UsageLine: "fix [packages]",
        Short:     "run go tool fix on packages",
@@ -25,11 +26,11 @@ See also: go fmt, go vet.
        `,
 }
 
-func runFix(cmd *Command, args []string) {
+func runFix(cmd *base.Command, args []string) {
        for _, pkg := range packages(args) {
                // Use pkg.gofiles instead of pkg.Dir so that
                // the command only applies to this package,
                // not to packages in subdirectories.
-               run(str.StringList(cfg.BuildToolexec, tool("fix"), relPaths(pkg.allgofiles)))
+               base.Run(str.StringList(cfg.BuildToolexec, base.Tool("fix"), base.RelPaths(pkg.allgofiles)))
        }
 }
index 4c40f9ab0b03a3974f4a6cd342ed5ec92c4f3b2e..e59f5cb919a0955b55cb3191c7637364f6ed394c 100644 (file)
@@ -5,16 +5,18 @@
 package main
 
 import (
+       "cmd/go/internal/cfg"
+       "cmd/go/internal/base"
        "cmd/go/internal/str"
        "os"
        "path/filepath"
 )
 
 func init() {
-       addBuildFlagsNX(cmdFmt)
+       cfg.AddBuildFlagsNX(&cmdFmt.Flag)
 }
 
-var cmdFmt = &Command{
+var cmdFmt = &base.Command{
        Run:       runFmt,
        UsageLine: "fmt [-n] [-x] [packages]",
        Short:     "run gofmt on package sources",
@@ -34,20 +36,20 @@ See also: go fix, go vet.
        `,
 }
 
-func runFmt(cmd *Command, args []string) {
+func runFmt(cmd *base.Command, args []string) {
        gofmt := gofmtPath()
        for _, pkg := range packages(args) {
                // Use pkg.gofiles instead of pkg.Dir so that
                // the command only applies to this package,
                // not to packages in subdirectories.
-               run(str.StringList(gofmt, "-l", "-w", relPaths(pkg.allgofiles)))
+               base.Run(str.StringList(gofmt, "-l", "-w", base.RelPaths(pkg.allgofiles)))
        }
 }
 
 func gofmtPath() string {
        gofmt := "gofmt"
-       if toolIsWindows {
-               gofmt += toolWindowsExtension
+       if base.ToolIsWindows {
+               gofmt += base.ToolWindowsExtension
        }
 
        gofmtPath := filepath.Join(gobin, gofmt)
index b4fd5a350b3e1d3a88028e4a96a7c64d70103bd1..b89fc95342db481db4566185f525408dca21f553 100644 (file)
@@ -8,6 +8,7 @@ import (
        "bufio"
        "bytes"
        "cmd/go/internal/cfg"
+       "cmd/go/internal/base"
        "fmt"
        "io"
        "log"
@@ -19,7 +20,7 @@ import (
        "strings"
 )
 
-var cmdGenerate = &Command{
+var cmdGenerate = &base.Command{
        Run:       runGenerate,
        UsageLine: "generate [-run regexp] [-n] [-v] [-x] [build flags] [file.go... | packages]",
        Short:     "generate Go files by processing source",
@@ -136,7 +137,7 @@ func init() {
        cmdGenerate.Flag.StringVar(&generateRunFlag, "run", "", "")
 }
 
-func runGenerate(cmd *Command, args []string) {
+func runGenerate(cmd *base.Command, args []string) {
        ignoreImports = true
 
        if generateRunFlag != "" {
@@ -196,13 +197,13 @@ func (g *Generator) run() (ok bool) {
                        if e != stop {
                                panic(e)
                        }
-                       setExitStatus(1)
+                       base.SetExitStatus(1)
                }
        }()
        g.dir, g.file = filepath.Split(g.path)
        g.dir = filepath.Clean(g.dir) // No final separator please.
        if cfg.BuildV {
-               fmt.Fprintf(os.Stderr, "%s\n", shortPath(g.path))
+               fmt.Fprintf(os.Stderr, "%s\n", base.ShortPath(g.path))
        }
 
        // Scan for lines that start "//go:generate".
@@ -265,7 +266,7 @@ func (g *Generator) run() (ok bool) {
                g.exec(words)
        }
        if err != nil && err != io.EOF {
-               g.errorf("error reading %s: %s", shortPath(g.path), err)
+               g.errorf("error reading %s: %s", base.ShortPath(g.path), err)
        }
        return true
 }
@@ -355,7 +356,7 @@ var stop = fmt.Errorf("error in generation")
 // It then exits the program (with exit status 1) because generation stops
 // at the first error.
 func (g *Generator) errorf(format string, args ...interface{}) {
-       fmt.Fprintf(os.Stderr, "%s:%d: %s\n", shortPath(g.path), g.lineNum,
+       fmt.Fprintf(os.Stderr, "%s:%d: %s\n", base.ShortPath(g.path), g.lineNum,
                fmt.Sprintf(format, args...))
        panic(stop)
 }
index cf8cc0817e5639eacbc1faa17ee02858b3c1db21..45c538d302d99fde49f46f32a48de4a85d612d30 100644 (file)
@@ -6,6 +6,7 @@ package main
 
 import (
        "cmd/go/internal/cfg"
+       "cmd/go/internal/base"
        "cmd/go/internal/str"
        "fmt"
        "go/build"
@@ -17,7 +18,7 @@ import (
        "strings"
 )
 
-var cmdGet = &Command{
+var cmdGet = &base.Command{
        UsageLine: "get [-d] [-f] [-fix] [-insecure] [-t] [-u] [build flags] [packages]",
        Short:     "download and install packages and dependencies",
        Long: `
@@ -85,9 +86,9 @@ func init() {
        cmdGet.Run = runGet // break init loop
 }
 
-func runGet(cmd *Command, args []string) {
+func runGet(cmd *base.Command, args []string) {
        if *getF && !*getU {
-               fatalf("go get: cannot use -f flag without -u")
+               base.Fatalf("go get: cannot use -f flag without -u")
        }
 
        // Disable any prompting for passwords by Git.
@@ -127,7 +128,7 @@ func runGet(cmd *Command, args []string) {
        for _, arg := range args {
                download(arg, nil, &stk, mode)
        }
-       exitIfErrors()
+       base.ExitIfErrors()
 
        // Phase 2. Rescan packages and re-evaluate args list.
 
@@ -220,7 +221,7 @@ func download(arg string, parent *Package, stk *importStack, mode int) {
 
        p := load(arg, mode)
        if p.Error != nil && p.Error.hard {
-               errorf("%s", p.Error)
+               base.Errorf("%s", p.Error)
                return
        }
 
@@ -257,7 +258,7 @@ func download(arg string, parent *Package, stk *importStack, mode int) {
                stk.push(arg)
                err := downloadPackage(p)
                if err != nil {
-                       errorf("%s", &PackageError{ImportStack: stk.copy(), Err: err.Error()})
+                       base.Errorf("%s", &PackageError{ImportStack: stk.copy(), Err: err.Error()})
                        stk.pop()
                        return
                }
@@ -293,7 +294,7 @@ func download(arg string, parent *Package, stk *importStack, mode int) {
                        // Do not push here too, or else stk will say arg imports arg.
                        p := load(arg, mode)
                        if p.Error != nil {
-                               errorf("%s", p.Error)
+                               base.Errorf("%s", p.Error)
                                continue
                        }
                        pkgs = append(pkgs, p)
@@ -304,12 +305,12 @@ func download(arg string, parent *Package, stk *importStack, mode int) {
        // due to wildcard expansion.
        for _, p := range pkgs {
                if *getFix {
-                       run(cfg.BuildToolexec, str.StringList(tool("fix"), relPaths(p.allgofiles)))
+                       base.Run(cfg.BuildToolexec, str.StringList(base.Tool("fix"), base.RelPaths(p.allgofiles)))
 
                        // The imports might have changed, so reload again.
                        p = reloadPackage(arg, stk)
                        if p.Error != nil {
-                               errorf("%s", p.Error)
+                               base.Errorf("%s", p.Error)
                                return
                        }
                }
@@ -346,7 +347,7 @@ func download(arg string, parent *Package, stk *importStack, mode int) {
                                        Err:         "must be imported as " + path[j+len("vendor/"):],
                                }
                                stk.pop()
-                               errorf("%s", err)
+                               base.Errorf("%s", err)
                                continue
                        }
                        // If this is a test import, apply vendor lookup now.
index 0c663ad463f679302a8280c85f8e32fad32844b7..734916c45393977b700d9e177d8af597b3de373a 100644 (file)
@@ -4,7 +4,9 @@
 
 package main
 
-var helpC = &Command{
+import "cmd/go/internal/base"
+
+var helpC = &base.Command{
        UsageLine: "c",
        Short:     "calling between Go and C",
        Long: `
@@ -26,7 +28,7 @@ the C or C++ compiler, respectively, to use.
        `,
 }
 
-var helpPackages = &Command{
+var helpPackages = &base.Command{
        UsageLine: "packages",
        Short:     "description of package lists",
        Long: `
@@ -100,7 +102,7 @@ by the go tool, as are directories named "testdata".
        `,
 }
 
-var helpImportPath = &Command{
+var helpImportPath = &base.Command{
        UsageLine: "importpath",
        Short:     "import path syntax",
        Long: `
@@ -277,7 +279,7 @@ See https://golang.org/s/go14customimport for details.
        `,
 }
 
-var helpGopath = &Command{
+var helpGopath = &base.Command{
        UsageLine: "gopath",
        Short:     "GOPATH environment variable",
        Long: `
@@ -429,7 +431,7 @@ See https://golang.org/s/go15vendor for details.
        `,
 }
 
-var helpEnvironment = &Command{
+var helpEnvironment = &base.Command{
        UsageLine: "environment",
        Short:     "environment variables",
        Long: `
@@ -511,7 +513,7 @@ Special-purpose environment variables:
        `,
 }
 
-var helpFileType = &Command{
+var helpFileType = &base.Command{
        UsageLine: "filetype",
        Short:     "file types",
        Long: `
@@ -557,7 +559,7 @@ for more details.
        `,
 }
 
-var helpBuildmode = &Command{
+var helpBuildmode = &base.Command{
        UsageLine: "buildmode",
        Short:     "description of build modes",
        Long: `
diff --git a/src/cmd/go/internal/base/base.go b/src/cmd/go/internal/base/base.go
new file mode 100644 (file)
index 0000000..081c78b
--- /dev/null
@@ -0,0 +1,143 @@
+// 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 base defines shared basic pieces of the go command,
+// in particular logging and the Command structure.
+package base
+
+import (
+       "cmd/go/internal/cfg"
+       "cmd/go/internal/str"
+       "flag"
+       "fmt"
+       "log"
+       "os"
+       "os/exec"
+       "strings"
+       "sync"
+)
+
+// A Command is an implementation of a go command
+// like go build or go fix.
+type Command struct {
+       // Run runs the command.
+       // The args are the arguments after the command name.
+       Run func(cmd *Command, args []string)
+
+       // UsageLine is the one-line usage message.
+       // The first word in the line is taken to be the command name.
+       UsageLine string
+
+       // Short is the short description shown in the 'go help' output.
+       Short string
+
+       // Long is the long message shown in the 'go help <this-command>' output.
+       Long string
+
+       // Flag is a set of flags specific to this command.
+       Flag flag.FlagSet
+
+       // CustomFlags indicates that the command will do its own
+       // flag parsing.
+       CustomFlags bool
+}
+
+// Name returns the command's name: the first word in the usage line.
+func (c *Command) Name() string {
+       name := c.UsageLine
+       i := strings.Index(name, " ")
+       if i >= 0 {
+               name = name[:i]
+       }
+       return name
+}
+
+func (c *Command) Usage() {
+       fmt.Fprintf(os.Stderr, "usage: %s\n\n", c.UsageLine)
+       fmt.Fprintf(os.Stderr, "%s\n", strings.TrimSpace(c.Long))
+       os.Exit(2)
+}
+
+// Runnable reports whether the command can be run; otherwise
+// it is a documentation pseudo-command such as importpath.
+func (c *Command) Runnable() bool {
+       return c.Run != nil
+}
+
+var atExitFuncs []func()
+
+func AtExit(f func()) {
+       atExitFuncs = append(atExitFuncs, f)
+}
+
+func Exit() {
+       for _, f := range atExitFuncs {
+               f()
+       }
+       os.Exit(exitStatus)
+}
+
+func Fatalf(format string, args ...interface{}) {
+       Errorf(format, args...)
+       Exit()
+}
+
+func Errorf(format string, args ...interface{}) {
+       log.Printf(format, args...)
+       SetExitStatus(1)
+}
+
+func ExitIfErrors() {
+       if exitStatus != 0 {
+               Exit()
+       }
+}
+
+var exitStatus = 0
+var exitMu sync.Mutex
+
+func SetExitStatus(n int) {
+       exitMu.Lock()
+       if exitStatus < n {
+               exitStatus = n
+       }
+       exitMu.Unlock()
+}
+
+// Run runs the command, with stdout and stderr
+// connected to the go command's own stdout and stderr.
+// If the command fails, Run reports the error using Errorf.
+func Run(cmdargs ...interface{}) {
+       cmdline := str.StringList(cmdargs...)
+       if cfg.BuildN || cfg.BuildX {
+               fmt.Printf("%s\n", strings.Join(cmdline, " "))
+               if cfg.BuildN {
+                       return
+               }
+       }
+
+       cmd := exec.Command(cmdline[0], cmdline[1:]...)
+       cmd.Stdout = os.Stdout
+       cmd.Stderr = os.Stderr
+       if err := cmd.Run(); err != nil {
+               Errorf("%v", err)
+       }
+}
+
+// RunStdin is like run but connects Stdin.
+func RunStdin(cmdline []string) {
+       cmd := exec.Command(cmdline[0], cmdline[1:]...)
+       cmd.Stdin = os.Stdin
+       cmd.Stdout = os.Stdout
+       cmd.Stderr = os.Stderr
+       cmd.Env = cfg.OrigEnv
+       StartSigHandlers()
+       if err := cmd.Run(); err != nil {
+               Errorf("%v", err)
+       }
+}
+
+// Usage is the usage-reporting function, filled in by package main
+// but here for reference by other packages.
+var Usage func()
diff --git a/src/cmd/go/internal/base/path.go b/src/cmd/go/internal/base/path.go
new file mode 100644 (file)
index 0000000..1e7f622
--- /dev/null
@@ -0,0 +1,36 @@
+// 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 base
+
+import (
+       "os"
+       "path/filepath"
+)
+
+var Cwd, _ = os.Getwd()
+
+// ShortPath returns an absolute or relative name for path, whatever is shorter.
+func ShortPath(path string) string {
+       if rel, err := filepath.Rel(Cwd, path); err == nil && len(rel) < len(path) {
+               return rel
+       }
+       return path
+}
+
+// RelPaths returns a copy of paths with absolute paths
+// made relative to the current directory if they would be shorter.
+func RelPaths(paths []string) []string {
+       var out []string
+       // TODO(rsc): Can this use Cwd from above?
+       pwd, _ := os.Getwd()
+       for _, p := range paths {
+               rel, err := filepath.Rel(pwd, p)
+               if err == nil && len(rel) < len(p) {
+                       p = rel
+               }
+               out = append(out, p)
+       }
+       return out
+}
similarity index 66%
rename from src/cmd/go/signal.go
rename to src/cmd/go/internal/base/signal.go
index e8ba0d36556ad4efd9f2a83e8c8b37cf0e95c24e..54d11876d07aeeeba70bc2cac70d5f96b14ca8ed 100644 (file)
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package main
+package base
 
 import (
        "os"
@@ -10,8 +10,8 @@ import (
        "sync"
 )
 
-// interrupted is closed, if go process is interrupted.
-var interrupted = make(chan struct{})
+// Interrupted is closed when the go command receives an interrupt signal.
+var Interrupted = make(chan struct{})
 
 // processSignals setups signal handler.
 func processSignals() {
@@ -19,13 +19,13 @@ func processSignals() {
        signal.Notify(sig, signalsToIgnore...)
        go func() {
                <-sig
-               close(interrupted)
+               close(Interrupted)
        }()
 }
 
 var onceProcessSignals sync.Once
 
-// startSigHandlers start signal handlers.
-func startSigHandlers() {
+// StartSigHandlers starts the signal handlers.
+func StartSigHandlers() {
        onceProcessSignals.Do(processSignals)
 }
similarity index 60%
rename from src/cmd/go/signal_notunix.go
rename to src/cmd/go/internal/base/signal_notunix.go
index 29aa9d8c209ada3ee07d17dbb1e623b98bc6e379..9e869b03ea8aafa10c288abfc2771b7c9616d2cd 100644 (file)
@@ -4,7 +4,7 @@
 
 // +build plan9 windows
 
-package main
+package base
 
 import (
        "os"
@@ -12,6 +12,6 @@ import (
 
 var signalsToIgnore = []os.Signal{os.Interrupt}
 
-// signalTrace is the signal to send to make a Go program
-// crash with a stack trace.
-var signalTrace os.Signal = nil
+// SignalTrace is the signal to send to make a Go program
+// crash with a stack trace (no such signal in this case).
+var SignalTrace os.Signal = nil
similarity index 75%
rename from src/cmd/go/signal_unix.go
rename to src/cmd/go/internal/base/signal_unix.go
index e86cd4652311ccdb851d7cfa72c596a6dbb2fdf9..4ca3da99226f8e141fd3b20af3282233a4d1c81c 100644 (file)
@@ -4,7 +4,7 @@
 
 // +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
 
-package main
+package base
 
 import (
        "os"
@@ -13,6 +13,6 @@ import (
 
 var signalsToIgnore = []os.Signal{os.Interrupt, syscall.SIGQUIT}
 
-// signalTrace is the signal to send to make a Go program
+// SignalTrace is the signal to send to make a Go program
 // crash with a stack trace.
-var signalTrace os.Signal = syscall.SIGQUIT
+var SignalTrace os.Signal = syscall.SIGQUIT
diff --git a/src/cmd/go/internal/base/tool.go b/src/cmd/go/internal/base/tool.go
new file mode 100644 (file)
index 0000000..c907772
--- /dev/null
@@ -0,0 +1,53 @@
+// 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 base
+
+import (
+       "fmt"
+       "go/build"
+       "os"
+       "path/filepath"
+       "runtime"
+
+       "cmd/go/internal/cfg"
+)
+
+// Configuration for finding tool binaries.
+var (
+       ToolGOOS      = runtime.GOOS
+       ToolGOARCH    = runtime.GOARCH
+       ToolIsWindows = ToolGOOS == "windows"
+       ToolDir       = build.ToolDir
+)
+
+const ToolWindowsExtension = ".exe"
+
+// Tool returns the path to the named tool (for example, "vet").
+// If the tool cannot be found, Tool exits the process.
+func Tool(toolName string) string {
+       toolPath := filepath.Join(ToolDir, toolName)
+       if ToolIsWindows {
+               toolPath += ToolWindowsExtension
+       }
+       if len(cfg.BuildToolexec) > 0 {
+               return toolPath
+       }
+       // Give a nice message if there is no tool with that name.
+       if _, err := os.Stat(toolPath); err != nil {
+               if isInGoToolsRepo(toolName) {
+                       fmt.Fprintf(os.Stderr, "go tool: no such tool %q; to install:\n\tgo get golang.org/x/tools/cmd/%s\n", toolName, toolName)
+               } else {
+                       fmt.Fprintf(os.Stderr, "go tool: no such tool %q\n", toolName)
+               }
+               SetExitStatus(2)
+               Exit()
+       }
+       return toolPath
+}
+
+// TODO: Delete.
+func isInGoToolsRepo(toolName string) bool {
+       return false
+}
index 8a7942b87734b579050d43b4edaa0a0a205e1571..c6cb2ce3db70e2385b86f4c2b72273d0654a02f5 100644 (file)
@@ -7,6 +7,7 @@
 package cfg
 
 import (
+       "flag"
        "go/build"
        "runtime"
 )
@@ -57,3 +58,9 @@ var (
        ExeSuffix string
        Gopath    []string
 )
+
+// AddBuildFlagsNX adds the -n and -x build flags to the flag set.
+func AddBuildFlagsNX(flags *flag.FlagSet) {
+       flags.BoolVar(&BuildN, "n", false, "")
+       flags.BoolVar(&BuildX, "x", false, "")
+}
index 14085020894640a017fed7b6558879d99842c2aa..cb29ca75bb24ad9b9b2cc847c503a738f316132e 100644 (file)
@@ -7,6 +7,7 @@ package main
 import (
        "bufio"
        "cmd/go/internal/cfg"
+       "cmd/go/internal/base"
        "encoding/json"
        "io"
        "os"
@@ -14,7 +15,7 @@ import (
        "text/template"
 )
 
-var cmdList = &Command{
+var cmdList = &base.Command{
        UsageLine: "list [-e] [-f format] [-json] [build flags] [packages]",
        Short:     "list packages",
        Long: `
@@ -146,7 +147,7 @@ var listFmt = cmdList.Flag.String("f", "{{.ImportPath}}", "")
 var listJson = cmdList.Flag.Bool("json", false, "")
 var nl = []byte{'\n'}
 
-func runList(cmd *Command, args []string) {
+func runList(cmd *base.Command, args []string) {
        buildModeInit()
        out := newTrackingWriter(os.Stdout)
        defer out.w.Flush()
@@ -157,7 +158,7 @@ func runList(cmd *Command, args []string) {
                        b, err := json.MarshalIndent(p, "", "\t")
                        if err != nil {
                                out.Flush()
-                               fatalf("%s", err)
+                               base.Fatalf("%s", err)
                        }
                        out.Write(b)
                        out.Write(nl)
@@ -176,12 +177,12 @@ func runList(cmd *Command, args []string) {
                }
                tmpl, err := template.New("main").Funcs(fm).Parse(*listFmt)
                if err != nil {
-                       fatalf("%s", err)
+                       base.Fatalf("%s", err)
                }
                do = func(p *Package) {
                        if err := tmpl.Execute(out, p); err != nil {
                                out.Flush()
-                               fatalf("%s", err)
+                               base.Fatalf("%s", err)
                        }
                        if out.NeedNL() {
                                out.Write(nl)
index 2925d1b35919b3a811735f8e625528c9f0baf2fa..aa019f2cea7297fe263b550bd9ab8fc0ef8a5a44 100644 (file)
@@ -8,78 +8,29 @@ import (
        "bufio"
        "bytes"
        "cmd/go/internal/cfg"
-       "cmd/go/internal/str"
+       "cmd/go/internal/base"
        "flag"
        "fmt"
        "go/build"
        "io"
        "log"
        "os"
-       "os/exec"
        "path"
        "path/filepath"
        "regexp"
        "runtime"
        "strings"
-       "sync"
        "text/template"
        "unicode"
        "unicode/utf8"
 )
 
-// A Command is an implementation of a go command
-// like go build or go fix.
-type Command struct {
-       // Run runs the command.
-       // The args are the arguments after the command name.
-       Run func(cmd *Command, args []string)
-
-       // UsageLine is the one-line usage message.
-       // The first word in the line is taken to be the command name.
-       UsageLine string
-
-       // Short is the short description shown in the 'go help' output.
-       Short string
-
-       // Long is the long message shown in the 'go help <this-command>' output.
-       Long string
-
-       // Flag is a set of flags specific to this command.
-       Flag flag.FlagSet
-
-       // CustomFlags indicates that the command will do its own
-       // flag parsing.
-       CustomFlags bool
-}
-
-// Name returns the command's name: the first word in the usage line.
-func (c *Command) Name() string {
-       name := c.UsageLine
-       i := strings.Index(name, " ")
-       if i >= 0 {
-               name = name[:i]
-       }
-       return name
-}
-
-func (c *Command) Usage() {
-       fmt.Fprintf(os.Stderr, "usage: %s\n\n", c.UsageLine)
-       fmt.Fprintf(os.Stderr, "%s\n", strings.TrimSpace(c.Long))
-       os.Exit(2)
-}
-
-// Runnable reports whether the command can be run; otherwise
-// it is a documentation pseudo-command such as importpath.
-func (c *Command) Runnable() bool {
-       return c.Run != nil
-}
-
 // Commands lists the available commands and help topics.
 // The order here is the order in which they are printed by 'go help'.
-var commands []*Command
+var commands []*base.Command
 
 func init() {
-       commands = []*Command{
+       commands = []*base.Command{
                cmdBuild,
                cmdClean,
                cmdDoc,
@@ -109,26 +60,15 @@ func init() {
        }
 }
 
-var exitStatus = 0
-var exitMu sync.Mutex
-
-func setExitStatus(n int) {
-       exitMu.Lock()
-       if exitStatus < n {
-               exitStatus = n
-       }
-       exitMu.Unlock()
-}
-
 func main() {
        _ = go11tag
-       flag.Usage = usage
+       flag.Usage = base.Usage
        flag.Parse()
        log.SetFlags(0)
 
        args := flag.Args()
        if len(args) < 1 {
-               usage()
+               base.Usage()
        }
 
        if args[0] == "help" {
@@ -185,14 +125,14 @@ func main() {
                                args = cmd.Flag.Args()
                        }
                        cmd.Run(cmd, args)
-                       exit()
+                       base.Exit()
                        return
                }
        }
 
        fmt.Fprintf(os.Stderr, "go: unknown subcommand %q\nRun 'go help' for usage.\n", args[0])
-       setExitStatus(2)
-       exit()
+       base.SetExitStatus(2)
+       base.Exit()
 }
 
 var usageTemplate = `Go is a tool for managing Go source code.
@@ -289,7 +229,7 @@ func tmpl(w io.Writer, text string, data interface{}) {
                if strings.Contains(ew.err.Error(), "pipe") {
                        os.Exit(1)
                }
-               fatalf("writing output: %v", ew.err)
+               base.Fatalf("writing output: %v", ew.err)
        }
        if err != nil {
                panic(err)
@@ -313,7 +253,7 @@ func printUsage(w io.Writer) {
 var usage func()
 
 func init() {
-       usage = mainUsage
+       base.Usage = mainUsage
 }
 
 func mainUsage() {
@@ -353,8 +293,8 @@ func help(args []string) {
                fmt.Println()
                buf := new(bytes.Buffer)
                printUsage(buf)
-               usage := &Command{Long: buf.String()}
-               tmpl(&commentWriter{W: os.Stdout}, documentationTemplate, append([]*Command{usage}, commands...))
+               usage := &base.Command{Long: buf.String()}
+               tmpl(&commentWriter{W: os.Stdout}, documentationTemplate, append([]*base.Command{usage}, commands...))
                fmt.Println("package main")
                return
        }
@@ -422,52 +362,6 @@ func importPaths(args []string) []string {
        return out
 }
 
-var atexitFuncs []func()
-
-func atexit(f func()) {
-       atexitFuncs = append(atexitFuncs, f)
-}
-
-func exit() {
-       for _, f := range atexitFuncs {
-               f()
-       }
-       os.Exit(exitStatus)
-}
-
-func fatalf(format string, args ...interface{}) {
-       errorf(format, args...)
-       exit()
-}
-
-func errorf(format string, args ...interface{}) {
-       log.Printf(format, args...)
-       setExitStatus(1)
-}
-
-func exitIfErrors() {
-       if exitStatus != 0 {
-               exit()
-       }
-}
-
-func run(cmdargs ...interface{}) {
-       cmdline := str.StringList(cmdargs...)
-       if cfg.BuildN || cfg.BuildX {
-               fmt.Printf("%s\n", strings.Join(cmdline, " "))
-               if cfg.BuildN {
-                       return
-               }
-       }
-
-       cmd := exec.Command(cmdline[0], cmdline[1:]...)
-       cmd.Stdout = os.Stdout
-       cmd.Stderr = os.Stderr
-       if err := cmd.Run(); err != nil {
-               errorf("%v", err)
-       }
-}
-
 // envForDir returns a copy of the environment
 // suitable for running in the given directory.
 // The environment is the current process's environment
index ada30c8cec7860d6598ab6cc48200a70ae30eb29..69acbd3230e9d69790436455e2f5b053ed49da94 100644 (file)
@@ -7,6 +7,7 @@ package main
 import (
        "bytes"
        "cmd/go/internal/cfg"
+       "cmd/go/internal/base"
        "cmd/go/internal/str"
        "crypto/sha1"
        "errors"
@@ -422,7 +423,7 @@ func loadImport(path, srcDir string, parent *Package, stk *importStack, importPo
 func setErrorPos(p *Package, importPos []token.Position) *Package {
        if len(importPos) > 0 {
                pos := importPos[0]
-               pos.Filename = shortPath(pos.Filename)
+               pos.Filename = base.ShortPath(pos.Filename)
                p.Error.Pos = pos.String()
        }
        return p
@@ -469,7 +470,7 @@ func vendoredImportPath(parent *Package, path string) (found string) {
        }
 
        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 {
-               fatalf("unexpected directory layout:\n"+
+               base.Fatalf("unexpected directory layout:\n"+
                        "       import path: %s\n"+
                        "       root: %s\n"+
                        "       dir: %s\n"+
@@ -798,7 +799,7 @@ func expandScanner(err error) error {
                // instead of just the first, as err.Error does.
                var buf bytes.Buffer
                for _, e := range err {
-                       e.Pos.Filename = shortPath(e.Pos.Filename)
+                       e.Pos.Filename = base.ShortPath(e.Pos.Filename)
                        buf.WriteString("\n")
                        buf.WriteString(e.Error())
                }
@@ -863,7 +864,7 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
                }
                _, elem := filepath.Split(p.Dir)
                full := cfg.BuildContext.GOOS + "_" + cfg.BuildContext.GOARCH + "/" + elem
-               if cfg.BuildContext.GOOS != toolGOOS || cfg.BuildContext.GOARCH != toolGOARCH {
+               if cfg.BuildContext.GOOS != base.ToolGOOS || cfg.BuildContext.GOARCH != base.ToolGOARCH {
                        // Install cross-compiled binaries to subdirectories of bin.
                        elem = full
                }
@@ -902,7 +903,7 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
 
                                }
                        } else if !os.IsNotExist(err) {
-                               fatalf("unexpected error reading %s: %v", shlibnamefile, err)
+                               base.Fatalf("unexpected error reading %s: %v", shlibnamefile, err)
                        }
                }
        }
@@ -1647,7 +1648,7 @@ func computeBuildID(p *Package) {
        if p.Standard && p.ImportPath == "runtime/internal/sys" && cfg.BuildContext.Compiler != "gccgo" {
                data, err := ioutil.ReadFile(filepath.Join(p.Dir, "zversion.go"))
                if err != nil {
-                       fatalf("go: %s", err)
+                       base.Fatalf("go: %s", err)
                }
                fmt.Fprintf(h, "zversion %q\n", string(data))
        }
@@ -1667,8 +1668,6 @@ func computeBuildID(p *Package) {
        p.buildID = fmt.Sprintf("%x", h.Sum(nil))
 }
 
-var cwd, _ = os.Getwd()
-
 var cmdCache = map[string]*Package{}
 
 // loadPackage is like loadImport but is used for command-line arguments,
@@ -1723,13 +1722,13 @@ func loadPackage(arg string, stk *importStack) *Package {
        // referring to io/ioutil rather than a hypothetical import of
        // "./ioutil".
        if build.IsLocalImport(arg) {
-               bp, _ := cfg.BuildContext.ImportDir(filepath.Join(cwd, arg), build.FindOnly)
+               bp, _ := cfg.BuildContext.ImportDir(filepath.Join(base.Cwd, arg), build.FindOnly)
                if bp.ImportPath != "" && bp.ImportPath != "." {
                        arg = bp.ImportPath
                }
        }
 
-       return loadImport(arg, cwd, nil, stk, nil, 0)
+       return loadImport(arg, base.Cwd, nil, stk, nil, 0)
 }
 
 // packages returns the packages named by the
@@ -1744,7 +1743,7 @@ func packages(args []string) []*Package {
        var pkgs []*Package
        for _, pkg := range packagesAndErrors(args) {
                if pkg.Error != nil {
-                       errorf("can't load package: %s", pkg.Error)
+                       base.Errorf("can't load package: %s", pkg.Error)
                        continue
                }
                pkgs = append(pkgs, pkg)
@@ -1794,7 +1793,7 @@ func packagesForBuild(args []string) []*Package {
        printed := map[*PackageError]bool{}
        for _, pkg := range pkgs {
                if pkg.Error != nil {
-                       errorf("can't load package: %s", pkg.Error)
+                       base.Errorf("can't load package: %s", pkg.Error)
                }
                for _, err := range pkg.DepsErrors {
                        // Since these are errors in dependencies,
@@ -1803,11 +1802,11 @@ func packagesForBuild(args []string) []*Package {
                        // Only print each once.
                        if !printed[err] {
                                printed[err] = true
-                               errorf("%s", err)
+                               base.Errorf("%s", err)
                        }
                }
        }
-       exitIfErrors()
+       base.ExitIfErrors()
 
        // Check for duplicate loads of the same package.
        // That should be impossible, but if it does happen then
@@ -1819,11 +1818,11 @@ func packagesForBuild(args []string) []*Package {
        for _, pkg := range packageList(pkgs) {
                if seen[pkg.ImportPath] && !reported[pkg.ImportPath] {
                        reported[pkg.ImportPath] = true
-                       errorf("internal error: duplicate loads of %s", pkg.ImportPath)
+                       base.Errorf("internal error: duplicate loads of %s", pkg.ImportPath)
                }
                seen[pkg.ImportPath] = true
        }
-       exitIfErrors()
+       base.ExitIfErrors()
 
        return pkgs
 }
index 3988df8ce714f410c6cdc45a2358cd10f765ae53..52d29ac9e891e49b4b426d6e5d131d92249dc2cc 100644 (file)
@@ -6,6 +6,7 @@ package main
 
 import (
        "cmd/go/internal/cfg"
+       "cmd/go/internal/base"
        "cmd/go/internal/str"
        "io/ioutil"
        "os"
@@ -164,7 +165,7 @@ func TestSharedLibName(t *testing.T) {
                                oldGopath := cfg.BuildContext.GOPATH
                                defer func() {
                                        cfg.BuildContext.GOPATH = oldGopath
-                                       os.Chdir(cwd)
+                                       os.Chdir(base.Cwd)
                                        err := os.RemoveAll(tmpGopath)
                                        if err != nil {
                                                t.Error(err)
index 80d9919a5b31e6a8a4d92bf57d235d4b0e835747..77a00541c1d4c65f3499449b58f45d57fe9a8cdf 100644 (file)
@@ -6,6 +6,7 @@ package main
 
 import (
        "cmd/go/internal/cfg"
+       "cmd/go/internal/base"
        "cmd/go/internal/str"
        "fmt"
        "os"
@@ -31,7 +32,7 @@ func findExecCmd() []string {
        return execCmd
 }
 
-var cmdRun = &Command{
+var cmdRun = &base.Command{
        UsageLine: "run [build flags] [-exec xprog] gofiles... [arguments...]",
        Short:     "compile and run Go program",
        Long: `
@@ -65,7 +66,7 @@ func printStderr(args ...interface{}) (int, error) {
        return fmt.Fprint(os.Stderr, args...)
 }
 
-func runRun(cmd *Command, args []string) {
+func runRun(cmd *base.Command, args []string) {
        instrumentInit()
        buildModeInit()
        var b builder
@@ -77,18 +78,18 @@ func runRun(cmd *Command, args []string) {
        }
        files, cmdArgs := args[:i], args[i:]
        if len(files) == 0 {
-               fatalf("go run: no go files listed")
+               base.Fatalf("go run: no go files listed")
        }
        for _, file := range files {
                if strings.HasSuffix(file, "_test.go") {
                        // goFilesPackage is going to assign this to TestGoFiles.
                        // Reject since it won't be part of the build.
-                       fatalf("go run: cannot run *_test.go files (%s)", file)
+                       base.Fatalf("go run: cannot run *_test.go files (%s)", file)
                }
        }
        p := goFilesPackage(files)
        if p.Error != nil {
-               fatalf("%s", p.Error)
+               base.Fatalf("%s", p.Error)
        }
        p.omitDWARF = true
        if len(p.DepsErrors) > 0 {
@@ -100,13 +101,13 @@ func runRun(cmd *Command, args []string) {
                for _, err := range p.DepsErrors {
                        if !printed[err] {
                                printed[err] = true
-                               errorf("%s", err)
+                               base.Errorf("%s", err)
                        }
                }
        }
-       exitIfErrors()
+       base.ExitIfErrors()
        if p.Name != "main" {
-               fatalf("go run: cannot run non-main package")
+               base.Fatalf("go run: cannot run non-main package")
        }
        p.target = "" // must build - not up to date
        var src string
@@ -121,7 +122,7 @@ func runRun(cmd *Command, args []string) {
                if !cfg.BuildContext.CgoEnabled {
                        hint = " (cgo is disabled)"
                }
-               fatalf("go run: no suitable source files%s", hint)
+               base.Fatalf("go run: no suitable source files%s", hint)
        }
        p.exeName = src[:len(src)-len(".go")] // name temporary executable for first go file
        a1 := b.action(modeBuild, modeBuild, p)
@@ -140,19 +141,6 @@ func (b *builder) runProgram(a *action) error {
                }
        }
 
-       runStdin(cmdline)
+       base.RunStdin(cmdline)
        return nil
 }
-
-// runStdin is like run, but connects Stdin.
-func runStdin(cmdline []string) {
-       cmd := exec.Command(cmdline[0], cmdline[1:]...)
-       cmd.Stdin = os.Stdin
-       cmd.Stdout = os.Stdout
-       cmd.Stderr = os.Stderr
-       cmd.Env = cfg.OrigEnv
-       startSigHandlers()
-       if err := cmd.Run(); err != nil {
-               errorf("%v", err)
-       }
-}
index ac79d96dbc08699b2c61cf4abb383164693f8d77..04a2080fc49d981c1574b66ad98558dbdd94bb47 100644 (file)
@@ -7,6 +7,7 @@ package main
 import (
        "bytes"
        "cmd/go/internal/cfg"
+       "cmd/go/internal/base"
        "cmd/go/internal/str"
        "errors"
        "fmt"
@@ -36,7 +37,7 @@ func init() {
 
 const testUsage = "test [build/test flags] [packages] [build/test flags & test binary flags]"
 
-var cmdTest = &Command{
+var cmdTest = &base.Command{
        CustomFlags: true,
        UsageLine:   testUsage,
        Short:       "test packages",
@@ -109,7 +110,7 @@ The test binary also accepts flags that control execution of the test; these
 flags are also accessible by 'go test'.
 `
 
-var helpTestflag = &Command{
+var helpTestflag = &base.Command{
        UsageLine: "testflag",
        Short:     "description of testing flags",
        Long: `
@@ -314,7 +315,7 @@ In the second example, the argument math is passed through to the test
 binary, instead of being interpreted as the package list.
 `
 
-var helpTestfunc = &Command{
+var helpTestfunc = &base.Command{
        UsageLine: "testfunc",
        Short:     "description of testing functions",
        Long: `
@@ -401,7 +402,7 @@ var testMainDeps = map[string]bool{
        "os": true,
 }
 
-func runTest(cmd *Command, args []string) {
+func runTest(cmd *base.Command, args []string) {
        var pkgArgs []string
        pkgArgs, testArgs = testFlags(args)
 
@@ -411,17 +412,17 @@ func runTest(cmd *Command, args []string) {
        buildModeInit()
        pkgs := packagesForBuild(pkgArgs)
        if len(pkgs) == 0 {
-               fatalf("no packages to test")
+               base.Fatalf("no packages to test")
        }
 
        if testC && len(pkgs) != 1 {
-               fatalf("cannot use -c flag with multiple packages")
+               base.Fatalf("cannot use -c flag with multiple packages")
        }
        if testO != "" && len(pkgs) != 1 {
-               fatalf("cannot use -o flag with multiple packages")
+               base.Fatalf("cannot use -o flag with multiple packages")
        }
        if testProfile && len(pkgs) != 1 {
-               fatalf("cannot use test profile flag with multiple packages")
+               base.Fatalf("cannot use test profile flag with multiple packages")
        }
 
        // If a test timeout was given and is parseable, set our kill timeout
@@ -556,9 +557,9 @@ func runTest(cmd *Command, args []string) {
                        failed := fmt.Sprintf("FAIL\t%s [setup failed]\n", p.ImportPath)
 
                        if p.ImportPath != "" {
-                               errorf("# %s\n%s\n%s", p.ImportPath, str, failed)
+                               base.Errorf("# %s\n%s\n%s", p.ImportPath, str, failed)
                        } else {
-                               errorf("%s\n%s", str, failed)
+                               base.Errorf("%s\n%s", str, failed)
                        }
                        continue
                }
@@ -964,11 +965,11 @@ func builderTest(b *builder, p *Package) (buildAction, runAction, printAction *a
 
        if testC || testNeedBinary {
                // -c or profiling flag: create action to copy binary to ./test.out.
-               target := filepath.Join(cwd, testBinary+cfg.ExeSuffix)
+               target := filepath.Join(base.Cwd, testBinary+cfg.ExeSuffix)
                if testO != "" {
                        target = testO
                        if !filepath.IsAbs(target) {
-                               target = filepath.Join(cwd, target)
+                               target = filepath.Join(base.Cwd, target)
                        }
                }
                buildAction = &action{
@@ -1110,7 +1111,7 @@ func builderRunTest(b *builder, a *action) error {
                // We were unable to build the binary.
                a.failed = false
                fmt.Fprintf(a.testOutput, "FAIL\t%s [build failed]\n", a.p.ImportPath)
-               setExitStatus(1)
+               base.SetExitStatus(1)
                return nil
        }
 
@@ -1153,7 +1154,7 @@ func builderRunTest(b *builder, a *action) error {
        // running.
        if err == nil {
                tick := time.NewTimer(testKillTimeout)
-               startSigHandlers()
+               base.StartSigHandlers()
                done := make(chan error)
                go func() {
                        done <- cmd.Wait()
@@ -1163,14 +1164,14 @@ func builderRunTest(b *builder, a *action) error {
                case err = <-done:
                        // ok
                case <-tick.C:
-                       if signalTrace != nil {
+                       if base.SignalTrace != nil {
                                // Send a quit signal in the hope that the program will print
                                // a stack trace and exit. Give it five seconds before resorting
                                // to Kill.
-                               cmd.Process.Signal(signalTrace)
+                               cmd.Process.Signal(base.SignalTrace)
                                select {
                                case err = <-done:
-                                       fmt.Fprintf(&buf, "*** Test killed with %v: ran too long (%v).\n", signalTrace, testKillTimeout)
+                                       fmt.Fprintf(&buf, "*** Test killed with %v: ran too long (%v).\n", base.SignalTrace, testKillTimeout)
                                        break Outer
                                case <-time.After(5 * time.Second):
                                }
@@ -1195,7 +1196,7 @@ func builderRunTest(b *builder, a *action) error {
                return nil
        }
 
-       setExitStatus(1)
+       base.SetExitStatus(1)
        if len(out) > 0 {
                a.testOutput.Write(out)
                // assume printing the test binary's exit status is superfluous
index 749f1724c5f5c87d86e51fa8d65d1eab3bbfba7f..b2f63279d54faa3b80a2d8b8a9b4058773340e1e 100644 (file)
@@ -6,6 +6,7 @@ package main
 
 import (
        "cmd/go/internal/cfg"
+       "cmd/go/internal/base"
        "flag"
        "fmt"
        "os"
@@ -64,7 +65,7 @@ var testFlagDefn = []*testFlagSpec{
 
 // add build flags to testFlagDefn
 func init() {
-       var cmd Command
+       var cmd base.Command
        addBuildFlags(&cmd)
        cmd.Flag.VisitAll(func(f *flag.Flag) {
                if f.Name == "v" {
@@ -129,7 +130,7 @@ func testFlags(args []string) (packageNames, passToTest []string) {
                }
                if f.flagValue != nil {
                        if err := f.flagValue.Set(value); err != nil {
-                               fatalf("invalid flag argument for -%s: %v", f.name, err)
+                               base.Fatalf("invalid flag argument for -%s: %v", f.name, err)
                        }
                } else {
                        // Test-only flags.
@@ -145,7 +146,7 @@ func testFlags(args []string) (packageNames, passToTest []string) {
                        case "exec":
                                execCmd, err = splitQuotedFields(value)
                                if err != nil {
-                                       fatalf("invalid flag argument for -%s: %v", f.name, err)
+                                       base.Fatalf("invalid flag argument for -%s: %v", f.name, err)
                                }
                        case "bench":
                                // record that we saw the flag; don't care about the value
@@ -172,7 +173,7 @@ func testFlags(args []string) (packageNames, passToTest []string) {
                                case "set", "count", "atomic":
                                        cfg.TestCoverMode = value
                                default:
-                                       fatalf("invalid flag argument for -covermode: %q", value)
+                                       base.Fatalf("invalid flag argument for -covermode: %q", value)
                                }
                                testCover = true
                        case "outputdir":
@@ -199,7 +200,7 @@ func testFlags(args []string) (packageNames, passToTest []string) {
        if testProfile && outputDir == "" {
                dir, err := os.Getwd()
                if err != nil {
-                       fatalf("error from os.Getwd: %s", err)
+                       base.Fatalf("error from os.Getwd: %s", err)
                }
                passToTest = append(passToTest, "-test.outputdir", dir)
        }
@@ -216,7 +217,7 @@ func testFlag(args []string, i int) (f *testFlagSpec, value string, extra bool)
        }
        switch arg {
        case "-?", "-h", "-help":
-               usage()
+               base.Usage()
        }
        if arg == "" || arg[0] != '-' {
                return
index 5f7b5a07e420a890b69013ee6a357495e740aea7..5f07e18c87b6382be9a3d2cf015808fc4d29344c 100644 (file)
@@ -5,18 +5,17 @@
 package main
 
 import (
-       "cmd/go/internal/cfg"
        "fmt"
-       "go/build"
        "os"
        "os/exec"
-       "path/filepath"
-       "runtime"
        "sort"
        "strings"
+
+       "cmd/go/internal/cfg"
+       "cmd/go/internal/base"
 )
 
-var cmdTool = &Command{
+var cmdTool = &base.Command{
        Run:       runTool,
        UsageLine: "tool [-n] command [args...]",
        Short:     "run specified go tool",
@@ -31,47 +30,13 @@ For more about each tool command, see 'go tool command -h'.
 `,
 }
 
-var (
-       toolGOOS      = runtime.GOOS
-       toolGOARCH    = runtime.GOARCH
-       toolIsWindows = toolGOOS == "windows"
-       toolDir       = build.ToolDir
-
-       toolN bool
-)
+var toolN bool
 
 func init() {
        cmdTool.Flag.BoolVar(&toolN, "n", false, "")
 }
 
-const toolWindowsExtension = ".exe"
-
-func tool(toolName string) string {
-       toolPath := filepath.Join(toolDir, toolName)
-       if toolIsWindows {
-               toolPath += toolWindowsExtension
-       }
-       if len(cfg.BuildToolexec) > 0 {
-               return toolPath
-       }
-       // Give a nice message if there is no tool with that name.
-       if _, err := os.Stat(toolPath); err != nil {
-               if isInGoToolsRepo(toolName) {
-                       fmt.Fprintf(os.Stderr, "go tool: no such tool %q; to install:\n\tgo get golang.org/x/tools/cmd/%s\n", toolName, toolName)
-               } else {
-                       fmt.Fprintf(os.Stderr, "go tool: no such tool %q\n", toolName)
-               }
-               setExitStatus(2)
-               exit()
-       }
-       return toolPath
-}
-
-func isInGoToolsRepo(toolName string) bool {
-       return false
-}
-
-func runTool(cmd *Command, args []string) {
+func runTool(cmd *base.Command, args []string) {
        if len(args) == 0 {
                listTools()
                return
@@ -83,11 +48,11 @@ func runTool(cmd *Command, args []string) {
                case 'a' <= c && c <= 'z', '0' <= c && c <= '9', c == '_':
                default:
                        fmt.Fprintf(os.Stderr, "go tool: bad tool name %q\n", toolName)
-                       setExitStatus(2)
+                       base.SetExitStatus(2)
                        return
                }
        }
-       toolPath := tool(toolName)
+       toolPath := base.Tool(toolName)
        if toolPath == "" {
                return
        }
@@ -119,24 +84,24 @@ func runTool(cmd *Command, args []string) {
                if e, ok := err.(*exec.ExitError); !ok || !e.Exited() || cfg.BuildX {
                        fmt.Fprintf(os.Stderr, "go tool %s: %s\n", toolName, err)
                }
-               setExitStatus(1)
+               base.SetExitStatus(1)
                return
        }
 }
 
 // listTools prints a list of the available tools in the tools directory.
 func listTools() {
-       f, err := os.Open(toolDir)
+       f, err := os.Open(base.ToolDir)
        if err != nil {
                fmt.Fprintf(os.Stderr, "go tool: no tool directory: %s\n", err)
-               setExitStatus(2)
+               base.SetExitStatus(2)
                return
        }
        defer f.Close()
        names, err := f.Readdirnames(-1)
        if err != nil {
                fmt.Fprintf(os.Stderr, "go tool: can't read directory: %s\n", err)
-               setExitStatus(2)
+               base.SetExitStatus(2)
                return
        }
 
@@ -145,8 +110,8 @@ func listTools() {
                // Unify presentation by going to lower case.
                name = strings.ToLower(name)
                // If it's windows, don't show the .exe suffix.
-               if toolIsWindows && strings.HasSuffix(name, toolWindowsExtension) {
-                       name = name[:len(name)-len(toolWindowsExtension)]
+               if base.ToolIsWindows && strings.HasSuffix(name, base.ToolWindowsExtension) {
+                       name = name[:len(name)-len(base.ToolWindowsExtension)]
                }
                fmt.Println(name)
        }
index 3045f350d7dc39f92fca775926f0ba2c0d648d2d..7cc949569a3387636a21ee96543be3aa60446890 100644 (file)
@@ -5,18 +5,19 @@
 package main
 
 import (
+       "cmd/go/internal/base"
        "fmt"
        "runtime"
 )
 
-var cmdVersion = &Command{
+var cmdVersion = &base.Command{
        Run:       runVersion,
        UsageLine: "version",
        Short:     "print Go version",
        Long:      `Version prints the Go version, as reported by runtime.Version.`,
 }
 
-func runVersion(cmd *Command, args []string) {
+func runVersion(cmd *base.Command, args []string) {
        if len(args) != 0 {
                cmd.Usage()
        }
index 8d6f26444e78c3ea92cba76cfe9567516018a0ea..98034ee5851cedbe2696b05c74231af3c8b5c91f 100644 (file)
@@ -8,6 +8,7 @@ import (
        "path/filepath"
 
        "cmd/go/internal/cfg"
+       "cmd/go/internal/base"
        "cmd/go/internal/str"
 )
 
@@ -15,7 +16,7 @@ func init() {
        addBuildFlags(cmdVet)
 }
 
-var cmdVet = &Command{
+var cmdVet = &base.Command{
        Run:       runVet,
        UsageLine: "vet [-n] [-x] [build flags] [packages]",
        Short:     "run go tool vet on packages",
@@ -36,7 +37,7 @@ See also: go fmt, go fix.
        `,
 }
 
-func runVet(cmd *Command, args []string) {
+func runVet(cmd *base.Command, args []string) {
        for _, p := range 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.
@@ -53,5 +54,5 @@ func runVetFiles(p *Package, files []string) {
        for i := range files {
                files[i] = filepath.Join(p.Dir, files[i])
        }
-       run(cfg.BuildToolexec, tool("vet"), relPaths(files))
+       base.Run(cfg.BuildToolexec, base.Tool("vet"), base.RelPaths(files))
 }