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: 's avatarDavid Crawshaw <crawshaw@golang.org>
parent b60e61ab
......@@ -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)
......
This diff is collapsed.
......@@ -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)
}
......@@ -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)
}
......@@ -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 {
......
......@@ -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)))
}
}
......@@ -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)
......
......@@ -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)
}
......
......@@ -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.
......
......@@ -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: `
......
// 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 @@
// 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)
}
......@@ -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
......@@ -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
// 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 @@
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, "")
}
......@@ -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)
......
......@@ -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
......
......@@ -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
}
......
......@@ -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)
......
......@@ -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)
}
}
......@@ -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
......
......@@ -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
......
......@@ -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)
}
......
......@@ -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()
}
......
......@@ -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))
}
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