Commit 9ccfde6e authored by Russ Cox's avatar Russ Cox

cmd/go: add support for 'go run pkg' or 'go run .'

To date, go run has required a list of .go files.
This CL allows in place of that list a single import path
or a directory name or a pattern matching a single patckage.
This allows 'go run pkg' or 'go run dir', most importantly 'go run .'.

The discussion in #22726 gives more motivation.
The basic idea is that you can already run 'go test .'
but if you're developing a command it's pretty awkward
to iterate at the same speed. This lets you do that,
by using 'go run . [args]'.

Fixes #22726.

Change-Id: Ibfc8172a4f752588ad96df0a6b0928e9b61fa27f
Reviewed-on: https://go-review.googlesource.com/109341
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarBryan C. Mills <bcmills@google.com>
parent 670cb760
......@@ -718,10 +718,12 @@
//
// Usage:
//
// go run [build flags] [-exec xprog] gofiles... [arguments...]
// go run [build flags] [-exec xprog] package [arguments...]
//
// Run compiles and runs the main package comprising the named Go source files.
// A Go source file is defined to be a file ending in a literal ".go" suffix.
// Run compiles and runs the named main Go package.
// Typically the package is specified as a list of .go source files,
// but it may also be an import path, file system path, or pattern
// matching a single known package, as in 'go run .' or 'go run my/cmd'.
//
// By default, 'go run' runs the compiled binary directly: 'a.out arguments...'.
// If the -exec flag is given, 'go run' invokes the binary using xprog:
......@@ -736,6 +738,7 @@
// The exit status of Run is not the exit status of the compiled binary.
//
// For more about build flags, see 'go help build'.
// For more about specifying packages, see 'go help packages'.
//
// See also: go build.
//
......
......@@ -1273,6 +1273,18 @@ func TestRunInternal(t *testing.T) {
tg.grepStderr(`testdata(\/|\\)src(\/|\\)run(\/|\\)bad\.go\:3\:8\: use of internal package not allowed`, "unexpected error for run/bad.go")
}
func TestRunPkg(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
dir := filepath.Join(tg.pwd(), "testdata")
tg.setenv("GOPATH", dir)
tg.run("run", "hello")
tg.grepStderr("hello, world", "did not find hello, world")
tg.cd(filepath.Join(dir, "src/hello"))
tg.run("run", ".")
tg.grepStderr("hello, world", "did not find hello, world")
}
func testMove(t *testing.T, vcs, url, base, config string) {
testenv.MustHaveExternalNetwork(t)
......
......@@ -18,11 +18,13 @@ import (
)
var CmdRun = &base.Command{
UsageLine: "run [build flags] [-exec xprog] gofiles... [arguments...]",
UsageLine: "run [build flags] [-exec xprog] package [arguments...]",
Short: "compile and run Go program",
Long: `
Run compiles and runs the main package comprising the named Go source files.
A Go source file is defined to be a file ending in a literal ".go" suffix.
Run compiles and runs the named main Go package.
Typically the package is specified as a list of .go source files,
but it may also be an import path, file system path, or pattern
matching a single known package, as in 'go run .' or 'go run my/cmd'.
By default, 'go run' runs the compiled binary directly: 'a.out arguments...'.
If the -exec flag is given, 'go run' invokes the binary using xprog:
......@@ -37,6 +39,7 @@ available.
The exit status of Run is not the exit status of the compiled binary.
For more about build flags, see 'go help build'.
For more about specifying packages, see 'go help packages'.
See also: go build.
`,
......@@ -62,18 +65,33 @@ func runRun(cmd *base.Command, args []string) {
for i < len(args) && strings.HasSuffix(args[i], ".go") {
i++
}
files, cmdArgs := args[:i], args[i:]
if len(files) == 0 {
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.
base.Fatalf("go run: cannot run *_test.go files (%s)", file)
var p *load.Package
if i > 0 {
files := args[:i]
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.
base.Fatalf("go run: cannot run *_test.go files (%s)", file)
}
}
p = load.GoFilesPackage(files)
} else if len(args) > 0 && !strings.HasPrefix(args[0], "-") {
pkgs := load.PackagesAndErrors(args[:1])
if len(pkgs) > 1 {
var names []string
for _, p := range pkgs {
names = append(names, p.ImportPath)
}
base.Fatalf("go run: pattern %s matches multiple packages:\n\t%s", args[0], strings.Join(names, "\n\t"))
}
p = pkgs[0]
i++
} else {
base.Fatalf("go run: no go files listed")
}
p := load.GoFilesPackage(files)
cmdArgs := args[i:]
if p.Error != nil {
base.Fatalf("%s", p.Error)
}
......
package main
func main() {
println("hello, world")
}
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