Commit 6dc9e31f authored by Russ Cox's avatar Russ Cox

cmd/go: split out cmd/go/internal/base

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/36193Reviewed-by: default avatarDavid Crawshaw <crawshaw@golang.org>
parent b60e61ab
...@@ -7,6 +7,7 @@ package main ...@@ -7,6 +7,7 @@ package main
import ( import (
"bytes" "bytes"
"cmd/go/internal/cfg" "cmd/go/internal/cfg"
"cmd/go/internal/base"
"fmt" "fmt"
"io" "io"
"io/ioutil" "io/ioutil"
...@@ -18,7 +19,7 @@ import ( ...@@ -18,7 +19,7 @@ import (
"strings" "strings"
) )
var cmdBug = &Command{ var cmdBug = &base.Command{
Run: runBug, Run: runBug,
UsageLine: "bug", UsageLine: "bug",
Short: "start a bug report", Short: "start a bug report",
...@@ -32,7 +33,7 @@ func init() { ...@@ -32,7 +33,7 @@ func init() {
cmdBug.Flag.BoolVar(&cfg.BuildV, "v", false, "") cmdBug.Flag.BoolVar(&cfg.BuildV, "v", false, "")
} }
func runBug(cmd *Command, args []string) { func runBug(cmd *base.Command, args []string) {
var buf bytes.Buffer var buf bytes.Buffer
buf.WriteString(bugHeader) buf.WriteString(bugHeader)
inspectGoVersion(&buf) inspectGoVersion(&buf)
......
This diff is collapsed.
...@@ -6,6 +6,7 @@ package main ...@@ -6,6 +6,7 @@ package main
import ( import (
"cmd/go/internal/cfg" "cmd/go/internal/cfg"
"cmd/go/internal/base"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"os" "os"
...@@ -13,7 +14,7 @@ import ( ...@@ -13,7 +14,7 @@ import (
"strings" "strings"
) )
var cmdClean = &Command{ var cmdClean = &base.Command{
UsageLine: "clean [-i] [-r] [-n] [-x] [build flags] [packages]", UsageLine: "clean [-i] [-r] [-n] [-x] [build flags] [packages]",
Short: "remove object files", Short: "remove object files",
Long: ` Long: `
...@@ -75,7 +76,7 @@ func init() { ...@@ -75,7 +76,7 @@ func init() {
addBuildFlags(cmdClean) addBuildFlags(cmdClean)
} }
func runClean(cmd *Command, args []string) { func runClean(cmd *base.Command, args []string) {
for _, pkg := range packagesAndErrors(args) { for _, pkg := range packagesAndErrors(args) {
clean(pkg) clean(pkg)
} }
...@@ -113,12 +114,12 @@ func clean(p *Package) { ...@@ -113,12 +114,12 @@ func clean(p *Package) {
cleaned[p] = true cleaned[p] = true
if p.Dir == "" { if p.Dir == "" {
errorf("can't load package: %v", p.Error) base.Errorf("can't load package: %v", p.Error)
return return
} }
dirs, err := ioutil.ReadDir(p.Dir) dirs, err := ioutil.ReadDir(p.Dir)
if err != nil { if err != nil {
errorf("go clean %s: %v", p.Dir, err) base.Errorf("go clean %s: %v", p.Dir, err)
return return
} }
...@@ -193,7 +194,7 @@ func clean(p *Package) { ...@@ -193,7 +194,7 @@ func clean(p *Package) {
} }
} }
if err := os.RemoveAll(filepath.Join(p.Dir, name)); err != nil { if err := os.RemoveAll(filepath.Join(p.Dir, name)); err != nil {
errorf("go clean: %v", err) base.Errorf("go clean: %v", err)
} }
} }
continue continue
...@@ -232,7 +233,7 @@ func removeFile(f string) { ...@@ -232,7 +233,7 @@ func removeFile(f string) {
return return
} }
// Windows does not allow deletion of a binary file while it is executing. // Windows does not allow deletion of a binary file while it is executing.
if toolIsWindows { if base.ToolIsWindows {
// Remove lingering ~ file from last attempt. // Remove lingering ~ file from last attempt.
if _, err2 := os.Stat(f + "~"); err2 == nil { if _, err2 := os.Stat(f + "~"); err2 == nil {
os.Remove(f + "~") os.Remove(f + "~")
...@@ -245,5 +246,5 @@ func removeFile(f string) { ...@@ -245,5 +246,5 @@ func removeFile(f string) {
return return
} }
} }
errorf("go clean: %v", err) base.Errorf("go clean: %v", err)
} }
...@@ -6,9 +6,12 @@ ...@@ -6,9 +6,12 @@
package main 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, Run: runDoc,
UsageLine: "doc [-u] [-c] [package|[package.]symbol[.method]]", UsageLine: "doc [-u] [-c] [package|[package.]symbol[.method]]",
CustomFlags: true, CustomFlags: true,
...@@ -115,6 +118,6 @@ Flags: ...@@ -115,6 +118,6 @@ Flags:
`, `,
} }
func runDoc(cmd *Command, args []string) { func runDoc(cmd *base.Command, args []string) {
run(cfg.BuildToolexec, tool("doc"), args) base.Run(cfg.BuildToolexec, base.Tool("doc"), args)
} }
...@@ -6,13 +6,14 @@ package main ...@@ -6,13 +6,14 @@ package main
import ( import (
"cmd/go/internal/cfg" "cmd/go/internal/cfg"
"cmd/go/internal/base"
"fmt" "fmt"
"os" "os"
"runtime" "runtime"
"strings" "strings"
) )
var cmdEnv = &Command{ var cmdEnv = &base.Command{
Run: runEnv, Run: runEnv,
UsageLine: "env [var ...]", UsageLine: "env [var ...]",
Short: "print Go environment information", Short: "print Go environment information",
...@@ -40,7 +41,7 @@ func mkEnv() []cfg.EnvVar { ...@@ -40,7 +41,7 @@ func mkEnv() []cfg.EnvVar {
{"GOPATH", cfg.BuildContext.GOPATH}, {"GOPATH", cfg.BuildContext.GOPATH},
{"GORACE", os.Getenv("GORACE")}, {"GORACE", os.Getenv("GORACE")},
{"GOROOT", goroot}, {"GOROOT", goroot},
{"GOTOOLDIR", toolDir}, {"GOTOOLDIR", base.ToolDir},
// disable escape codes in clang errors // disable escape codes in clang errors
{"TERM", "dumb"}, {"TERM", "dumb"},
...@@ -98,7 +99,7 @@ func extraEnvVars() []cfg.EnvVar { ...@@ -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 := cfg.NewEnv
env = append(env, extraEnvVars()...) env = append(env, extraEnvVars()...)
if len(args) > 0 { if len(args) > 0 {
......
...@@ -6,10 +6,11 @@ package main ...@@ -6,10 +6,11 @@ package main
import ( import (
"cmd/go/internal/cfg" "cmd/go/internal/cfg"
"cmd/go/internal/base"
"cmd/go/internal/str" "cmd/go/internal/str"
) )
var cmdFix = &Command{ var cmdFix = &base.Command{
Run: runFix, Run: runFix,
UsageLine: "fix [packages]", UsageLine: "fix [packages]",
Short: "run go tool fix on packages", Short: "run go tool fix on packages",
...@@ -25,11 +26,11 @@ See also: go fmt, go vet. ...@@ -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) { for _, pkg := range packages(args) {
// Use pkg.gofiles instead of pkg.Dir so that // Use pkg.gofiles instead of pkg.Dir so that
// the command only applies to this package, // the command only applies to this package,
// not to packages in subdirectories. // 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)))
} }
} }
...@@ -5,16 +5,18 @@ ...@@ -5,16 +5,18 @@
package main package main
import ( import (
"cmd/go/internal/cfg"
"cmd/go/internal/base"
"cmd/go/internal/str" "cmd/go/internal/str"
"os" "os"
"path/filepath" "path/filepath"
) )
func init() { func init() {
addBuildFlagsNX(cmdFmt) cfg.AddBuildFlagsNX(&cmdFmt.Flag)
} }
var cmdFmt = &Command{ var cmdFmt = &base.Command{
Run: runFmt, Run: runFmt,
UsageLine: "fmt [-n] [-x] [packages]", UsageLine: "fmt [-n] [-x] [packages]",
Short: "run gofmt on package sources", Short: "run gofmt on package sources",
...@@ -34,20 +36,20 @@ See also: go fix, go vet. ...@@ -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() gofmt := gofmtPath()
for _, pkg := range packages(args) { for _, pkg := range packages(args) {
// Use pkg.gofiles instead of pkg.Dir so that // Use pkg.gofiles instead of pkg.Dir so that
// the command only applies to this package, // the command only applies to this package,
// not to packages in subdirectories. // 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 { func gofmtPath() string {
gofmt := "gofmt" gofmt := "gofmt"
if toolIsWindows { if base.ToolIsWindows {
gofmt += toolWindowsExtension gofmt += base.ToolWindowsExtension
} }
gofmtPath := filepath.Join(gobin, gofmt) gofmtPath := filepath.Join(gobin, gofmt)
......
...@@ -8,6 +8,7 @@ import ( ...@@ -8,6 +8,7 @@ import (
"bufio" "bufio"
"bytes" "bytes"
"cmd/go/internal/cfg" "cmd/go/internal/cfg"
"cmd/go/internal/base"
"fmt" "fmt"
"io" "io"
"log" "log"
...@@ -19,7 +20,7 @@ import ( ...@@ -19,7 +20,7 @@ import (
"strings" "strings"
) )
var cmdGenerate = &Command{ var cmdGenerate = &base.Command{
Run: runGenerate, Run: runGenerate,
UsageLine: "generate [-run regexp] [-n] [-v] [-x] [build flags] [file.go... | packages]", UsageLine: "generate [-run regexp] [-n] [-v] [-x] [build flags] [file.go... | packages]",
Short: "generate Go files by processing source", Short: "generate Go files by processing source",
...@@ -136,7 +137,7 @@ func init() { ...@@ -136,7 +137,7 @@ func init() {
cmdGenerate.Flag.StringVar(&generateRunFlag, "run", "", "") cmdGenerate.Flag.StringVar(&generateRunFlag, "run", "", "")
} }
func runGenerate(cmd *Command, args []string) { func runGenerate(cmd *base.Command, args []string) {
ignoreImports = true ignoreImports = true
if generateRunFlag != "" { if generateRunFlag != "" {
...@@ -196,13 +197,13 @@ func (g *Generator) run() (ok bool) { ...@@ -196,13 +197,13 @@ func (g *Generator) run() (ok bool) {
if e != stop { if e != stop {
panic(e) panic(e)
} }
setExitStatus(1) base.SetExitStatus(1)
} }
}() }()
g.dir, g.file = filepath.Split(g.path) g.dir, g.file = filepath.Split(g.path)
g.dir = filepath.Clean(g.dir) // No final separator please. g.dir = filepath.Clean(g.dir) // No final separator please.
if cfg.BuildV { 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". // Scan for lines that start "//go:generate".
...@@ -265,7 +266,7 @@ func (g *Generator) run() (ok bool) { ...@@ -265,7 +266,7 @@ func (g *Generator) run() (ok bool) {
g.exec(words) g.exec(words)
} }
if err != nil && err != io.EOF { 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 return true
} }
...@@ -355,7 +356,7 @@ var stop = fmt.Errorf("error in generation") ...@@ -355,7 +356,7 @@ var stop = fmt.Errorf("error in generation")
// It then exits the program (with exit status 1) because generation stops // It then exits the program (with exit status 1) because generation stops
// at the first error. // at the first error.
func (g *Generator) errorf(format string, args ...interface{}) { 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...)) fmt.Sprintf(format, args...))
panic(stop) panic(stop)
} }
......
...@@ -6,6 +6,7 @@ package main ...@@ -6,6 +6,7 @@ package main
import ( import (
"cmd/go/internal/cfg" "cmd/go/internal/cfg"
"cmd/go/internal/base"
"cmd/go/internal/str" "cmd/go/internal/str"
"fmt" "fmt"
"go/build" "go/build"
...@@ -17,7 +18,7 @@ import ( ...@@ -17,7 +18,7 @@ import (
"strings" "strings"
) )
var cmdGet = &Command{ var cmdGet = &base.Command{
UsageLine: "get [-d] [-f] [-fix] [-insecure] [-t] [-u] [build flags] [packages]", UsageLine: "get [-d] [-f] [-fix] [-insecure] [-t] [-u] [build flags] [packages]",
Short: "download and install packages and dependencies", Short: "download and install packages and dependencies",
Long: ` Long: `
...@@ -85,9 +86,9 @@ func init() { ...@@ -85,9 +86,9 @@ func init() {
cmdGet.Run = runGet // break init loop cmdGet.Run = runGet // break init loop
} }
func runGet(cmd *Command, args []string) { func runGet(cmd *base.Command, args []string) {
if *getF && !*getU { 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. // Disable any prompting for passwords by Git.
...@@ -127,7 +128,7 @@ func runGet(cmd *Command, args []string) { ...@@ -127,7 +128,7 @@ func runGet(cmd *Command, args []string) {
for _, arg := range args { for _, arg := range args {
download(arg, nil, &stk, mode) download(arg, nil, &stk, mode)
} }
exitIfErrors() base.ExitIfErrors()
// Phase 2. Rescan packages and re-evaluate args list. // Phase 2. Rescan packages and re-evaluate args list.
...@@ -220,7 +221,7 @@ func download(arg string, parent *Package, stk *importStack, mode int) { ...@@ -220,7 +221,7 @@ func download(arg string, parent *Package, stk *importStack, mode int) {
p := load(arg, mode) p := load(arg, mode)
if p.Error != nil && p.Error.hard { if p.Error != nil && p.Error.hard {
errorf("%s", p.Error) base.Errorf("%s", p.Error)
return return
} }
...@@ -257,7 +258,7 @@ func download(arg string, parent *Package, stk *importStack, mode int) { ...@@ -257,7 +258,7 @@ func download(arg string, parent *Package, stk *importStack, mode int) {
stk.push(arg) stk.push(arg)
err := downloadPackage(p) err := downloadPackage(p)
if err != nil { if err != nil {
errorf("%s", &PackageError{ImportStack: stk.copy(), Err: err.Error()}) base.Errorf("%s", &PackageError{ImportStack: stk.copy(), Err: err.Error()})
stk.pop() stk.pop()
return return
} }
...@@ -293,7 +294,7 @@ func download(arg string, parent *Package, stk *importStack, mode int) { ...@@ -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. // Do not push here too, or else stk will say arg imports arg.
p := load(arg, mode) p := load(arg, mode)
if p.Error != nil { if p.Error != nil {
errorf("%s", p.Error) base.Errorf("%s", p.Error)
continue continue
} }
pkgs = append(pkgs, p) pkgs = append(pkgs, p)
...@@ -304,12 +305,12 @@ func download(arg string, parent *Package, stk *importStack, mode int) { ...@@ -304,12 +305,12 @@ func download(arg string, parent *Package, stk *importStack, mode int) {
// due to wildcard expansion. // due to wildcard expansion.
for _, p := range pkgs { for _, p := range pkgs {
if *getFix { 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. // The imports might have changed, so reload again.
p = reloadPackage(arg, stk) p = reloadPackage(arg, stk)
if p.Error != nil { if p.Error != nil {
errorf("%s", p.Error) base.Errorf("%s", p.Error)
return return
} }
} }
...@@ -346,7 +347,7 @@ func download(arg string, parent *Package, stk *importStack, mode int) { ...@@ -346,7 +347,7 @@ func download(arg string, parent *Package, stk *importStack, mode int) {
Err: "must be imported as " + path[j+len("vendor/"):], Err: "must be imported as " + path[j+len("vendor/"):],
} }
stk.pop() stk.pop()
errorf("%s", err) base.Errorf("%s", err)
continue continue
} }
// If this is a test import, apply vendor lookup now. // If this is a test import, apply vendor lookup now.
......
...@@ -4,7 +4,9 @@ ...@@ -4,7 +4,9 @@
package main package main
var helpC = &Command{ import "cmd/go/internal/base"
var helpC = &base.Command{
UsageLine: "c", UsageLine: "c",
Short: "calling between Go and C", Short: "calling between Go and C",
Long: ` Long: `
...@@ -26,7 +28,7 @@ the C or C++ compiler, respectively, to use. ...@@ -26,7 +28,7 @@ the C or C++ compiler, respectively, to use.
`, `,
} }
var helpPackages = &Command{ var helpPackages = &base.Command{
UsageLine: "packages", UsageLine: "packages",
Short: "description of package lists", Short: "description of package lists",
Long: ` Long: `
...@@ -100,7 +102,7 @@ by the go tool, as are directories named "testdata". ...@@ -100,7 +102,7 @@ by the go tool, as are directories named "testdata".
`, `,
} }
var helpImportPath = &Command{ var helpImportPath = &base.Command{
UsageLine: "importpath", UsageLine: "importpath",
Short: "import path syntax", Short: "import path syntax",
Long: ` Long: `
...@@ -277,7 +279,7 @@ See https://golang.org/s/go14customimport for details. ...@@ -277,7 +279,7 @@ See https://golang.org/s/go14customimport for details.
`, `,
} }
var helpGopath = &Command{ var helpGopath = &base.Command{
UsageLine: "gopath", UsageLine: "gopath",
Short: "GOPATH environment variable", Short: "GOPATH environment variable",
Long: ` Long: `
...@@ -429,7 +431,7 @@ See https://golang.org/s/go15vendor for details. ...@@ -429,7 +431,7 @@ See https://golang.org/s/go15vendor for details.
`, `,
} }
var helpEnvironment = &Command{ var helpEnvironment = &base.Command{
UsageLine: "environment", UsageLine: "environment",
Short: "environment variables", Short: "environment variables",
Long: ` Long: `
...@@ -511,7 +513,7 @@ Special-purpose environment variables: ...@@ -511,7 +513,7 @@ Special-purpose environment variables:
`, `,
} }
var helpFileType = &Command{ var helpFileType = &base.Command{
UsageLine: "filetype", UsageLine: "filetype",
Short: "file types", Short: "file types",
Long: ` Long: `
...@@ -557,7 +559,7 @@ for more details. ...@@ -557,7 +559,7 @@ for more details.
`, `,
} }
var helpBuildmode = &Command{ var helpBuildmode = &base.Command{
UsageLine: "buildmode", UsageLine: "buildmode",
Short: "description of build modes", Short: "description of build modes",
Long: ` Long: `
......
// 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()
// 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
}
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package main package base
import ( import (
"os" "os"
...@@ -10,8 +10,8 @@ import ( ...@@ -10,8 +10,8 @@ import (
"sync" "sync"
) )
// interrupted is closed, if go process is interrupted. // Interrupted is closed when the go command receives an interrupt signal.
var interrupted = make(chan struct{}) var Interrupted = make(chan struct{})
// processSignals setups signal handler. // processSignals setups signal handler.
func processSignals() { func processSignals() {
...@@ -19,13 +19,13 @@ func processSignals() { ...@@ -19,13 +19,13 @@ func processSignals() {
signal.Notify(sig, signalsToIgnore...) signal.Notify(sig, signalsToIgnore...)
go func() { go func() {
<-sig <-sig
close(interrupted) close(Interrupted)
}() }()
} }
var onceProcessSignals sync.Once var onceProcessSignals sync.Once
// startSigHandlers start signal handlers. // StartSigHandlers starts the signal handlers.
func startSigHandlers() { func StartSigHandlers() {
onceProcessSignals.Do(processSignals) onceProcessSignals.Do(processSignals)
} }
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
// +build plan9 windows // +build plan9 windows
package main package base
import ( import (
"os" "os"
...@@ -12,6 +12,6 @@ import ( ...@@ -12,6 +12,6 @@ import (
var signalsToIgnore = []os.Signal{os.Interrupt} var signalsToIgnore = []os.Signal{os.Interrupt}
// 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. // crash with a stack trace (no such signal in this case).
var signalTrace os.Signal = nil var SignalTrace os.Signal = nil
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris // +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
package main package base
import ( import (
"os" "os"
...@@ -13,6 +13,6 @@ import ( ...@@ -13,6 +13,6 @@ import (
var signalsToIgnore = []os.Signal{os.Interrupt, syscall.SIGQUIT} 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. // crash with a stack trace.
var signalTrace os.Signal = syscall.SIGQUIT var SignalTrace os.Signal = syscall.SIGQUIT
// 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
}
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
package cfg package cfg
import ( import (
"flag"
"go/build" "go/build"
"runtime" "runtime"
) )
...@@ -57,3 +58,9 @@ var ( ...@@ -57,3 +58,9 @@ var (
ExeSuffix string ExeSuffix string
Gopath []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, "")
}
...@@ -7,6 +7,7 @@ package main ...@@ -7,6 +7,7 @@ package main
import ( import (
"bufio" "bufio"
"cmd/go/internal/cfg" "cmd/go/internal/cfg"
"cmd/go/internal/base"
"encoding/json" "encoding/json"
"io" "io"
"os" "os"
...@@ -14,7 +15,7 @@ import ( ...@@ -14,7 +15,7 @@ import (
"text/template" "text/template"
) )
var cmdList = &Command{ var cmdList = &base.Command{
UsageLine: "list [-e] [-f format] [-json] [build flags] [packages]", UsageLine: "list [-e] [-f format] [-json] [build flags] [packages]",
Short: "list packages", Short: "list packages",
Long: ` Long: `
...@@ -146,7 +147,7 @@ var listFmt = cmdList.Flag.String("f", "{{.ImportPath}}", "") ...@@ -146,7 +147,7 @@ var listFmt = cmdList.Flag.String("f", "{{.ImportPath}}", "")
var listJson = cmdList.Flag.Bool("json", false, "") var listJson = cmdList.Flag.Bool("json", false, "")
var nl = []byte{'\n'} var nl = []byte{'\n'}
func runList(cmd *Command, args []string) { func runList(cmd *base.Command, args []string) {
buildModeInit() buildModeInit()
out := newTrackingWriter(os.Stdout) out := newTrackingWriter(os.Stdout)
defer out.w.Flush() defer out.w.Flush()
...@@ -157,7 +158,7 @@ func runList(cmd *Command, args []string) { ...@@ -157,7 +158,7 @@ func runList(cmd *Command, args []string) {
b, err := json.MarshalIndent(p, "", "\t") b, err := json.MarshalIndent(p, "", "\t")
if err != nil { if err != nil {
out.Flush() out.Flush()
fatalf("%s", err) base.Fatalf("%s", err)
} }
out.Write(b) out.Write(b)
out.Write(nl) out.Write(nl)
...@@ -176,12 +177,12 @@ func runList(cmd *Command, args []string) { ...@@ -176,12 +177,12 @@ func runList(cmd *Command, args []string) {
} }
tmpl, err := template.New("main").Funcs(fm).Parse(*listFmt) tmpl, err := template.New("main").Funcs(fm).Parse(*listFmt)
if err != nil { if err != nil {
fatalf("%s", err) base.Fatalf("%s", err)
} }
do = func(p *Package) { do = func(p *Package) {
if err := tmpl.Execute(out, p); err != nil { if err := tmpl.Execute(out, p); err != nil {
out.Flush() out.Flush()
fatalf("%s", err) base.Fatalf("%s", err)
} }
if out.NeedNL() { if out.NeedNL() {
out.Write(nl) out.Write(nl)
......
...@@ -8,78 +8,29 @@ import ( ...@@ -8,78 +8,29 @@ import (
"bufio" "bufio"
"bytes" "bytes"
"cmd/go/internal/cfg" "cmd/go/internal/cfg"
"cmd/go/internal/str" "cmd/go/internal/base"
"flag" "flag"
"fmt" "fmt"
"go/build" "go/build"
"io" "io"
"log" "log"
"os" "os"
"os/exec"
"path" "path"
"path/filepath" "path/filepath"
"regexp" "regexp"
"runtime" "runtime"
"strings" "strings"
"sync"
"text/template" "text/template"
"unicode" "unicode"
"unicode/utf8" "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. // Commands lists the available commands and help topics.
// The order here is the order in which they are printed by 'go help'. // The order here is the order in which they are printed by 'go help'.
var commands []*Command var commands []*base.Command
func init() { func init() {
commands = []*Command{ commands = []*base.Command{
cmdBuild, cmdBuild,
cmdClean, cmdClean,
cmdDoc, cmdDoc,
...@@ -109,26 +60,15 @@ func init() { ...@@ -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() { func main() {
_ = go11tag _ = go11tag
flag.Usage = usage flag.Usage = base.Usage
flag.Parse() flag.Parse()
log.SetFlags(0) log.SetFlags(0)
args := flag.Args() args := flag.Args()
if len(args) < 1 { if len(args) < 1 {
usage() base.Usage()
} }
if args[0] == "help" { if args[0] == "help" {
...@@ -185,14 +125,14 @@ func main() { ...@@ -185,14 +125,14 @@ func main() {
args = cmd.Flag.Args() args = cmd.Flag.Args()
} }
cmd.Run(cmd, args) cmd.Run(cmd, args)
exit() base.Exit()
return return
} }
} }
fmt.Fprintf(os.Stderr, "go: unknown subcommand %q\nRun 'go help' for usage.\n", args[0]) fmt.Fprintf(os.Stderr, "go: unknown subcommand %q\nRun 'go help' for usage.\n", args[0])
setExitStatus(2) base.SetExitStatus(2)
exit() base.Exit()
} }
var usageTemplate = `Go is a tool for managing Go source code. var usageTemplate = `Go is a tool for managing Go source code.
...@@ -289,7 +229,7 @@ func tmpl(w io.Writer, text string, data interface{}) { ...@@ -289,7 +229,7 @@ func tmpl(w io.Writer, text string, data interface{}) {
if strings.Contains(ew.err.Error(), "pipe") { if strings.Contains(ew.err.Error(), "pipe") {
os.Exit(1) os.Exit(1)
} }
fatalf("writing output: %v", ew.err) base.Fatalf("writing output: %v", ew.err)
} }
if err != nil { if err != nil {
panic(err) panic(err)
...@@ -313,7 +253,7 @@ func printUsage(w io.Writer) { ...@@ -313,7 +253,7 @@ func printUsage(w io.Writer) {
var usage func() var usage func()
func init() { func init() {
usage = mainUsage base.Usage = mainUsage
} }
func mainUsage() { func mainUsage() {
...@@ -353,8 +293,8 @@ func help(args []string) { ...@@ -353,8 +293,8 @@ func help(args []string) {
fmt.Println() fmt.Println()
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
printUsage(buf) printUsage(buf)
usage := &Command{Long: buf.String()} usage := &base.Command{Long: buf.String()}
tmpl(&commentWriter{W: os.Stdout}, documentationTemplate, append([]*Command{usage}, commands...)) tmpl(&commentWriter{W: os.Stdout}, documentationTemplate, append([]*base.Command{usage}, commands...))
fmt.Println("package main") fmt.Println("package main")
return return
} }
...@@ -422,52 +362,6 @@ func importPaths(args []string) []string { ...@@ -422,52 +362,6 @@ func importPaths(args []string) []string {
return out 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 // envForDir returns a copy of the environment
// suitable for running in the given directory. // suitable for running in the given directory.
// The environment is the current process's environment // The environment is the current process's environment
......
...@@ -7,6 +7,7 @@ package main ...@@ -7,6 +7,7 @@ package main
import ( import (
"bytes" "bytes"
"cmd/go/internal/cfg" "cmd/go/internal/cfg"
"cmd/go/internal/base"
"cmd/go/internal/str" "cmd/go/internal/str"
"crypto/sha1" "crypto/sha1"
"errors" "errors"
...@@ -422,7 +423,7 @@ func loadImport(path, srcDir string, parent *Package, stk *importStack, importPo ...@@ -422,7 +423,7 @@ func loadImport(path, srcDir string, parent *Package, stk *importStack, importPo
func setErrorPos(p *Package, importPos []token.Position) *Package { func setErrorPos(p *Package, importPos []token.Position) *Package {
if len(importPos) > 0 { if len(importPos) > 0 {
pos := importPos[0] pos := importPos[0]
pos.Filename = shortPath(pos.Filename) pos.Filename = base.ShortPath(pos.Filename)
p.Error.Pos = pos.String() p.Error.Pos = pos.String()
} }
return p return p
...@@ -469,7 +470,7 @@ func vendoredImportPath(parent *Package, path string) (found string) { ...@@ -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 { 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"+ " import path: %s\n"+
" root: %s\n"+ " root: %s\n"+
" dir: %s\n"+ " dir: %s\n"+
...@@ -798,7 +799,7 @@ func expandScanner(err error) error { ...@@ -798,7 +799,7 @@ func expandScanner(err error) error {
// instead of just the first, as err.Error does. // instead of just the first, as err.Error does.
var buf bytes.Buffer var buf bytes.Buffer
for _, e := range err { for _, e := range err {
e.Pos.Filename = shortPath(e.Pos.Filename) e.Pos.Filename = base.ShortPath(e.Pos.Filename)
buf.WriteString("\n") buf.WriteString("\n")
buf.WriteString(e.Error()) buf.WriteString(e.Error())
} }
...@@ -863,7 +864,7 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package ...@@ -863,7 +864,7 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
} }
_, elem := filepath.Split(p.Dir) _, elem := filepath.Split(p.Dir)
full := cfg.BuildContext.GOOS + "_" + cfg.BuildContext.GOARCH + "/" + elem 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. // Install cross-compiled binaries to subdirectories of bin.
elem = full elem = full
} }
...@@ -902,7 +903,7 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package ...@@ -902,7 +903,7 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
} }
} else if !os.IsNotExist(err) { } 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) { ...@@ -1647,7 +1648,7 @@ func computeBuildID(p *Package) {
if p.Standard && p.ImportPath == "runtime/internal/sys" && cfg.BuildContext.Compiler != "gccgo" { if p.Standard && p.ImportPath == "runtime/internal/sys" && cfg.BuildContext.Compiler != "gccgo" {
data, err := ioutil.ReadFile(filepath.Join(p.Dir, "zversion.go")) data, err := ioutil.ReadFile(filepath.Join(p.Dir, "zversion.go"))
if err != nil { if err != nil {
fatalf("go: %s", err) base.Fatalf("go: %s", err)
} }
fmt.Fprintf(h, "zversion %q\n", string(data)) fmt.Fprintf(h, "zversion %q\n", string(data))
} }
...@@ -1667,8 +1668,6 @@ func computeBuildID(p *Package) { ...@@ -1667,8 +1668,6 @@ func computeBuildID(p *Package) {
p.buildID = fmt.Sprintf("%x", h.Sum(nil)) p.buildID = fmt.Sprintf("%x", h.Sum(nil))
} }
var cwd, _ = os.Getwd()
var cmdCache = map[string]*Package{} var cmdCache = map[string]*Package{}
// loadPackage is like loadImport but is used for command-line arguments, // loadPackage is like loadImport but is used for command-line arguments,
...@@ -1723,13 +1722,13 @@ func loadPackage(arg string, stk *importStack) *Package { ...@@ -1723,13 +1722,13 @@ func loadPackage(arg string, stk *importStack) *Package {
// referring to io/ioutil rather than a hypothetical import of // referring to io/ioutil rather than a hypothetical import of
// "./ioutil". // "./ioutil".
if build.IsLocalImport(arg) { 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 != "." { if bp.ImportPath != "" && bp.ImportPath != "." {
arg = 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 // packages returns the packages named by the
...@@ -1744,7 +1743,7 @@ func packages(args []string) []*Package { ...@@ -1744,7 +1743,7 @@ func packages(args []string) []*Package {
var pkgs []*Package var pkgs []*Package
for _, pkg := range packagesAndErrors(args) { for _, pkg := range packagesAndErrors(args) {
if pkg.Error != nil { if pkg.Error != nil {
errorf("can't load package: %s", pkg.Error) base.Errorf("can't load package: %s", pkg.Error)
continue continue
} }
pkgs = append(pkgs, pkg) pkgs = append(pkgs, pkg)
...@@ -1794,7 +1793,7 @@ func packagesForBuild(args []string) []*Package { ...@@ -1794,7 +1793,7 @@ func packagesForBuild(args []string) []*Package {
printed := map[*PackageError]bool{} printed := map[*PackageError]bool{}
for _, pkg := range pkgs { for _, pkg := range pkgs {
if pkg.Error != nil { 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 { for _, err := range pkg.DepsErrors {
// Since these are errors in dependencies, // Since these are errors in dependencies,
...@@ -1803,11 +1802,11 @@ func packagesForBuild(args []string) []*Package { ...@@ -1803,11 +1802,11 @@ func packagesForBuild(args []string) []*Package {
// Only print each once. // Only print each once.
if !printed[err] { if !printed[err] {
printed[err] = true printed[err] = true
errorf("%s", err) base.Errorf("%s", err)
} }
} }
} }
exitIfErrors() base.ExitIfErrors()
// Check for duplicate loads of the same package. // Check for duplicate loads of the same package.
// That should be impossible, but if it does happen then // That should be impossible, but if it does happen then
...@@ -1819,11 +1818,11 @@ func packagesForBuild(args []string) []*Package { ...@@ -1819,11 +1818,11 @@ func packagesForBuild(args []string) []*Package {
for _, pkg := range packageList(pkgs) { for _, pkg := range packageList(pkgs) {
if seen[pkg.ImportPath] && !reported[pkg.ImportPath] { if seen[pkg.ImportPath] && !reported[pkg.ImportPath] {
reported[pkg.ImportPath] = true 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 seen[pkg.ImportPath] = true
} }
exitIfErrors() base.ExitIfErrors()
return pkgs return pkgs
} }
......
...@@ -6,6 +6,7 @@ package main ...@@ -6,6 +6,7 @@ package main
import ( import (
"cmd/go/internal/cfg" "cmd/go/internal/cfg"
"cmd/go/internal/base"
"cmd/go/internal/str" "cmd/go/internal/str"
"io/ioutil" "io/ioutil"
"os" "os"
...@@ -164,7 +165,7 @@ func TestSharedLibName(t *testing.T) { ...@@ -164,7 +165,7 @@ func TestSharedLibName(t *testing.T) {
oldGopath := cfg.BuildContext.GOPATH oldGopath := cfg.BuildContext.GOPATH
defer func() { defer func() {
cfg.BuildContext.GOPATH = oldGopath cfg.BuildContext.GOPATH = oldGopath
os.Chdir(cwd) os.Chdir(base.Cwd)
err := os.RemoveAll(tmpGopath) err := os.RemoveAll(tmpGopath)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
......
...@@ -6,6 +6,7 @@ package main ...@@ -6,6 +6,7 @@ package main
import ( import (
"cmd/go/internal/cfg" "cmd/go/internal/cfg"
"cmd/go/internal/base"
"cmd/go/internal/str" "cmd/go/internal/str"
"fmt" "fmt"
"os" "os"
...@@ -31,7 +32,7 @@ func findExecCmd() []string { ...@@ -31,7 +32,7 @@ func findExecCmd() []string {
return execCmd return execCmd
} }
var cmdRun = &Command{ var cmdRun = &base.Command{
UsageLine: "run [build flags] [-exec xprog] gofiles... [arguments...]", UsageLine: "run [build flags] [-exec xprog] gofiles... [arguments...]",
Short: "compile and run Go program", Short: "compile and run Go program",
Long: ` Long: `
...@@ -65,7 +66,7 @@ func printStderr(args ...interface{}) (int, error) { ...@@ -65,7 +66,7 @@ func printStderr(args ...interface{}) (int, error) {
return fmt.Fprint(os.Stderr, args...) return fmt.Fprint(os.Stderr, args...)
} }
func runRun(cmd *Command, args []string) { func runRun(cmd *base.Command, args []string) {
instrumentInit() instrumentInit()
buildModeInit() buildModeInit()
var b builder var b builder
...@@ -77,18 +78,18 @@ func runRun(cmd *Command, args []string) { ...@@ -77,18 +78,18 @@ func runRun(cmd *Command, args []string) {
} }
files, cmdArgs := args[:i], args[i:] files, cmdArgs := args[:i], args[i:]
if len(files) == 0 { if len(files) == 0 {
fatalf("go run: no go files listed") base.Fatalf("go run: no go files listed")
} }
for _, file := range files { for _, file := range files {
if strings.HasSuffix(file, "_test.go") { if strings.HasSuffix(file, "_test.go") {
// goFilesPackage is going to assign this to TestGoFiles. // goFilesPackage is going to assign this to TestGoFiles.
// Reject since it won't be part of the build. // 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) p := goFilesPackage(files)
if p.Error != nil { if p.Error != nil {
fatalf("%s", p.Error) base.Fatalf("%s", p.Error)
} }
p.omitDWARF = true p.omitDWARF = true
if len(p.DepsErrors) > 0 { if len(p.DepsErrors) > 0 {
...@@ -100,13 +101,13 @@ func runRun(cmd *Command, args []string) { ...@@ -100,13 +101,13 @@ func runRun(cmd *Command, args []string) {
for _, err := range p.DepsErrors { for _, err := range p.DepsErrors {
if !printed[err] { if !printed[err] {
printed[err] = true printed[err] = true
errorf("%s", err) base.Errorf("%s", err)
} }
} }
} }
exitIfErrors() base.ExitIfErrors()
if p.Name != "main" { 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 p.target = "" // must build - not up to date
var src string var src string
...@@ -121,7 +122,7 @@ func runRun(cmd *Command, args []string) { ...@@ -121,7 +122,7 @@ func runRun(cmd *Command, args []string) {
if !cfg.BuildContext.CgoEnabled { if !cfg.BuildContext.CgoEnabled {
hint = " (cgo is disabled)" 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 p.exeName = src[:len(src)-len(".go")] // name temporary executable for first go file
a1 := b.action(modeBuild, modeBuild, p) a1 := b.action(modeBuild, modeBuild, p)
...@@ -140,19 +141,6 @@ func (b *builder) runProgram(a *action) error { ...@@ -140,19 +141,6 @@ func (b *builder) runProgram(a *action) error {
} }
} }
runStdin(cmdline) base.RunStdin(cmdline)
return nil 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)
}
}
...@@ -7,6 +7,7 @@ package main ...@@ -7,6 +7,7 @@ package main
import ( import (
"bytes" "bytes"
"cmd/go/internal/cfg" "cmd/go/internal/cfg"
"cmd/go/internal/base"
"cmd/go/internal/str" "cmd/go/internal/str"
"errors" "errors"
"fmt" "fmt"
...@@ -36,7 +37,7 @@ func init() { ...@@ -36,7 +37,7 @@ func init() {
const testUsage = "test [build/test flags] [packages] [build/test flags & test binary flags]" const testUsage = "test [build/test flags] [packages] [build/test flags & test binary flags]"
var cmdTest = &Command{ var cmdTest = &base.Command{
CustomFlags: true, CustomFlags: true,
UsageLine: testUsage, UsageLine: testUsage,
Short: "test packages", Short: "test packages",
...@@ -109,7 +110,7 @@ The test binary also accepts flags that control execution of the test; these ...@@ -109,7 +110,7 @@ The test binary also accepts flags that control execution of the test; these
flags are also accessible by 'go test'. flags are also accessible by 'go test'.
` `
var helpTestflag = &Command{ var helpTestflag = &base.Command{
UsageLine: "testflag", UsageLine: "testflag",
Short: "description of testing flags", Short: "description of testing flags",
Long: ` Long: `
...@@ -314,7 +315,7 @@ In the second example, the argument math is passed through to the test ...@@ -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. binary, instead of being interpreted as the package list.
` `
var helpTestfunc = &Command{ var helpTestfunc = &base.Command{
UsageLine: "testfunc", UsageLine: "testfunc",
Short: "description of testing functions", Short: "description of testing functions",
Long: ` Long: `
...@@ -401,7 +402,7 @@ var testMainDeps = map[string]bool{ ...@@ -401,7 +402,7 @@ var testMainDeps = map[string]bool{
"os": true, "os": true,
} }
func runTest(cmd *Command, args []string) { func runTest(cmd *base.Command, args []string) {
var pkgArgs []string var pkgArgs []string
pkgArgs, testArgs = testFlags(args) pkgArgs, testArgs = testFlags(args)
...@@ -411,17 +412,17 @@ func runTest(cmd *Command, args []string) { ...@@ -411,17 +412,17 @@ func runTest(cmd *Command, args []string) {
buildModeInit() buildModeInit()
pkgs := packagesForBuild(pkgArgs) pkgs := packagesForBuild(pkgArgs)
if len(pkgs) == 0 { if len(pkgs) == 0 {
fatalf("no packages to test") base.Fatalf("no packages to test")
} }
if testC && len(pkgs) != 1 { 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 { 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 { 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 // If a test timeout was given and is parseable, set our kill timeout
...@@ -556,9 +557,9 @@ func runTest(cmd *Command, args []string) { ...@@ -556,9 +557,9 @@ func runTest(cmd *Command, args []string) {
failed := fmt.Sprintf("FAIL\t%s [setup failed]\n", p.ImportPath) failed := fmt.Sprintf("FAIL\t%s [setup failed]\n", p.ImportPath)
if 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 { } else {
errorf("%s\n%s", str, failed) base.Errorf("%s\n%s", str, failed)
} }
continue continue
} }
...@@ -964,11 +965,11 @@ func builderTest(b *builder, p *Package) (buildAction, runAction, printAction *a ...@@ -964,11 +965,11 @@ func builderTest(b *builder, p *Package) (buildAction, runAction, printAction *a
if testC || testNeedBinary { if testC || testNeedBinary {
// -c or profiling flag: create action to copy binary to ./test.out. // -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 != "" { if testO != "" {
target = testO target = testO
if !filepath.IsAbs(target) { if !filepath.IsAbs(target) {
target = filepath.Join(cwd, target) target = filepath.Join(base.Cwd, target)
} }
} }
buildAction = &action{ buildAction = &action{
...@@ -1110,7 +1111,7 @@ func builderRunTest(b *builder, a *action) error { ...@@ -1110,7 +1111,7 @@ func builderRunTest(b *builder, a *action) error {
// We were unable to build the binary. // We were unable to build the binary.
a.failed = false a.failed = false
fmt.Fprintf(a.testOutput, "FAIL\t%s [build failed]\n", a.p.ImportPath) fmt.Fprintf(a.testOutput, "FAIL\t%s [build failed]\n", a.p.ImportPath)
setExitStatus(1) base.SetExitStatus(1)
return nil return nil
} }
...@@ -1153,7 +1154,7 @@ func builderRunTest(b *builder, a *action) error { ...@@ -1153,7 +1154,7 @@ func builderRunTest(b *builder, a *action) error {
// running. // running.
if err == nil { if err == nil {
tick := time.NewTimer(testKillTimeout) tick := time.NewTimer(testKillTimeout)
startSigHandlers() base.StartSigHandlers()
done := make(chan error) done := make(chan error)
go func() { go func() {
done <- cmd.Wait() done <- cmd.Wait()
...@@ -1163,14 +1164,14 @@ func builderRunTest(b *builder, a *action) error { ...@@ -1163,14 +1164,14 @@ func builderRunTest(b *builder, a *action) error {
case err = <-done: case err = <-done:
// ok // ok
case <-tick.C: case <-tick.C:
if signalTrace != nil { if base.SignalTrace != nil {
// Send a quit signal in the hope that the program will print // Send a quit signal in the hope that the program will print
// a stack trace and exit. Give it five seconds before resorting // a stack trace and exit. Give it five seconds before resorting
// to Kill. // to Kill.
cmd.Process.Signal(signalTrace) cmd.Process.Signal(base.SignalTrace)
select { select {
case err = <-done: 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 break Outer
case <-time.After(5 * time.Second): case <-time.After(5 * time.Second):
} }
...@@ -1195,7 +1196,7 @@ func builderRunTest(b *builder, a *action) error { ...@@ -1195,7 +1196,7 @@ func builderRunTest(b *builder, a *action) error {
return nil return nil
} }
setExitStatus(1) base.SetExitStatus(1)
if len(out) > 0 { if len(out) > 0 {
a.testOutput.Write(out) a.testOutput.Write(out)
// assume printing the test binary's exit status is superfluous // assume printing the test binary's exit status is superfluous
......
...@@ -6,6 +6,7 @@ package main ...@@ -6,6 +6,7 @@ package main
import ( import (
"cmd/go/internal/cfg" "cmd/go/internal/cfg"
"cmd/go/internal/base"
"flag" "flag"
"fmt" "fmt"
"os" "os"
...@@ -64,7 +65,7 @@ var testFlagDefn = []*testFlagSpec{ ...@@ -64,7 +65,7 @@ var testFlagDefn = []*testFlagSpec{
// add build flags to testFlagDefn // add build flags to testFlagDefn
func init() { func init() {
var cmd Command var cmd base.Command
addBuildFlags(&cmd) addBuildFlags(&cmd)
cmd.Flag.VisitAll(func(f *flag.Flag) { cmd.Flag.VisitAll(func(f *flag.Flag) {
if f.Name == "v" { if f.Name == "v" {
...@@ -129,7 +130,7 @@ func testFlags(args []string) (packageNames, passToTest []string) { ...@@ -129,7 +130,7 @@ func testFlags(args []string) (packageNames, passToTest []string) {
} }
if f.flagValue != nil { if f.flagValue != nil {
if err := f.flagValue.Set(value); err != 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 { } else {
// Test-only flags. // Test-only flags.
...@@ -145,7 +146,7 @@ func testFlags(args []string) (packageNames, passToTest []string) { ...@@ -145,7 +146,7 @@ func testFlags(args []string) (packageNames, passToTest []string) {
case "exec": case "exec":
execCmd, err = splitQuotedFields(value) execCmd, err = splitQuotedFields(value)
if err != nil { 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": case "bench":
// record that we saw the flag; don't care about the value // record that we saw the flag; don't care about the value
...@@ -172,7 +173,7 @@ func testFlags(args []string) (packageNames, passToTest []string) { ...@@ -172,7 +173,7 @@ func testFlags(args []string) (packageNames, passToTest []string) {
case "set", "count", "atomic": case "set", "count", "atomic":
cfg.TestCoverMode = value cfg.TestCoverMode = value
default: default:
fatalf("invalid flag argument for -covermode: %q", value) base.Fatalf("invalid flag argument for -covermode: %q", value)
} }
testCover = true testCover = true
case "outputdir": case "outputdir":
...@@ -199,7 +200,7 @@ func testFlags(args []string) (packageNames, passToTest []string) { ...@@ -199,7 +200,7 @@ func testFlags(args []string) (packageNames, passToTest []string) {
if testProfile && outputDir == "" { if testProfile && outputDir == "" {
dir, err := os.Getwd() dir, err := os.Getwd()
if err != nil { if err != nil {
fatalf("error from os.Getwd: %s", err) base.Fatalf("error from os.Getwd: %s", err)
} }
passToTest = append(passToTest, "-test.outputdir", dir) passToTest = append(passToTest, "-test.outputdir", dir)
} }
...@@ -216,7 +217,7 @@ func testFlag(args []string, i int) (f *testFlagSpec, value string, extra bool) ...@@ -216,7 +217,7 @@ func testFlag(args []string, i int) (f *testFlagSpec, value string, extra bool)
} }
switch arg { switch arg {
case "-?", "-h", "-help": case "-?", "-h", "-help":
usage() base.Usage()
} }
if arg == "" || arg[0] != '-' { if arg == "" || arg[0] != '-' {
return return
......
...@@ -5,18 +5,17 @@ ...@@ -5,18 +5,17 @@
package main package main
import ( import (
"cmd/go/internal/cfg"
"fmt" "fmt"
"go/build"
"os" "os"
"os/exec" "os/exec"
"path/filepath"
"runtime"
"sort" "sort"
"strings" "strings"
"cmd/go/internal/cfg"
"cmd/go/internal/base"
) )
var cmdTool = &Command{ var cmdTool = &base.Command{
Run: runTool, Run: runTool,
UsageLine: "tool [-n] command [args...]", UsageLine: "tool [-n] command [args...]",
Short: "run specified go tool", Short: "run specified go tool",
...@@ -31,47 +30,13 @@ For more about each tool command, see 'go tool command -h'. ...@@ -31,47 +30,13 @@ For more about each tool command, see 'go tool command -h'.
`, `,
} }
var ( var toolN bool
toolGOOS = runtime.GOOS
toolGOARCH = runtime.GOARCH
toolIsWindows = toolGOOS == "windows"
toolDir = build.ToolDir
toolN bool
)
func init() { func init() {
cmdTool.Flag.BoolVar(&toolN, "n", false, "") cmdTool.Flag.BoolVar(&toolN, "n", false, "")
} }
const toolWindowsExtension = ".exe" func runTool(cmd *base.Command, args []string) {
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) {
if len(args) == 0 { if len(args) == 0 {
listTools() listTools()
return return
...@@ -83,11 +48,11 @@ func runTool(cmd *Command, args []string) { ...@@ -83,11 +48,11 @@ func runTool(cmd *Command, args []string) {
case 'a' <= c && c <= 'z', '0' <= c && c <= '9', c == '_': case 'a' <= c && c <= 'z', '0' <= c && c <= '9', c == '_':
default: default:
fmt.Fprintf(os.Stderr, "go tool: bad tool name %q\n", toolName) fmt.Fprintf(os.Stderr, "go tool: bad tool name %q\n", toolName)
setExitStatus(2) base.SetExitStatus(2)
return return
} }
} }
toolPath := tool(toolName) toolPath := base.Tool(toolName)
if toolPath == "" { if toolPath == "" {
return return
} }
...@@ -119,24 +84,24 @@ func runTool(cmd *Command, args []string) { ...@@ -119,24 +84,24 @@ func runTool(cmd *Command, args []string) {
if e, ok := err.(*exec.ExitError); !ok || !e.Exited() || cfg.BuildX { if e, ok := err.(*exec.ExitError); !ok || !e.Exited() || cfg.BuildX {
fmt.Fprintf(os.Stderr, "go tool %s: %s\n", toolName, err) fmt.Fprintf(os.Stderr, "go tool %s: %s\n", toolName, err)
} }
setExitStatus(1) base.SetExitStatus(1)
return return
} }
} }
// listTools prints a list of the available tools in the tools directory. // listTools prints a list of the available tools in the tools directory.
func listTools() { func listTools() {
f, err := os.Open(toolDir) f, err := os.Open(base.ToolDir)
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, "go tool: no tool directory: %s\n", err) fmt.Fprintf(os.Stderr, "go tool: no tool directory: %s\n", err)
setExitStatus(2) base.SetExitStatus(2)
return return
} }
defer f.Close() defer f.Close()
names, err := f.Readdirnames(-1) names, err := f.Readdirnames(-1)
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, "go tool: can't read directory: %s\n", err) fmt.Fprintf(os.Stderr, "go tool: can't read directory: %s\n", err)
setExitStatus(2) base.SetExitStatus(2)
return return
} }
...@@ -145,8 +110,8 @@ func listTools() { ...@@ -145,8 +110,8 @@ func listTools() {
// Unify presentation by going to lower case. // Unify presentation by going to lower case.
name = strings.ToLower(name) name = strings.ToLower(name)
// If it's windows, don't show the .exe suffix. // If it's windows, don't show the .exe suffix.
if toolIsWindows && strings.HasSuffix(name, toolWindowsExtension) { if base.ToolIsWindows && strings.HasSuffix(name, base.ToolWindowsExtension) {
name = name[:len(name)-len(toolWindowsExtension)] name = name[:len(name)-len(base.ToolWindowsExtension)]
} }
fmt.Println(name) fmt.Println(name)
} }
......
...@@ -5,18 +5,19 @@ ...@@ -5,18 +5,19 @@
package main package main
import ( import (
"cmd/go/internal/base"
"fmt" "fmt"
"runtime" "runtime"
) )
var cmdVersion = &Command{ var cmdVersion = &base.Command{
Run: runVersion, Run: runVersion,
UsageLine: "version", UsageLine: "version",
Short: "print Go version", Short: "print Go version",
Long: `Version prints the Go version, as reported by runtime.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 { if len(args) != 0 {
cmd.Usage() cmd.Usage()
} }
......
...@@ -8,6 +8,7 @@ import ( ...@@ -8,6 +8,7 @@ import (
"path/filepath" "path/filepath"
"cmd/go/internal/cfg" "cmd/go/internal/cfg"
"cmd/go/internal/base"
"cmd/go/internal/str" "cmd/go/internal/str"
) )
...@@ -15,7 +16,7 @@ func init() { ...@@ -15,7 +16,7 @@ func init() {
addBuildFlags(cmdVet) addBuildFlags(cmdVet)
} }
var cmdVet = &Command{ var cmdVet = &base.Command{
Run: runVet, Run: runVet,
UsageLine: "vet [-n] [-x] [build flags] [packages]", UsageLine: "vet [-n] [-x] [build flags] [packages]",
Short: "run go tool vet on packages", Short: "run go tool vet on packages",
...@@ -36,7 +37,7 @@ See also: go fmt, go fix. ...@@ -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) { for _, p := range packages(args) {
// Vet expects to be given a set of files all from the same package. // 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. // Run once for package p and once for package p_test.
...@@ -53,5 +54,5 @@ func runVetFiles(p *Package, files []string) { ...@@ -53,5 +54,5 @@ func runVetFiles(p *Package, files []string) {
for i := range files { for i := range files {
files[i] = filepath.Join(p.Dir, files[i]) 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))
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment