Commit b03a5f66 authored by Russ Cox's avatar Russ Cox

cmd/go: fixes

* Install tools into tool dir always
  (Fixes issue 3049.  Fixes issue 2868.  Fixes issue 2925.)
* Make packages depend on compiler, linker (Fixes issue 3036.)
* Do not recompile packages across roots (Fixes issue 3149.)
* Allow use of binary-only packages (Fixes issue 2775.)
* Avoid duplicate cgo dependencies (Fixes issue 3001.)
* Show less in go get -x.  (Fixes issue 2926.)
* Do not force repo root for existing checkout (Fixes issue 2969.)
* Show full syntax error list always (Fixes issue 2811.)
* Clean arguments before processing (Fixes issue 3034.)
* Add flags for compiler, linker arguments (Fixes issue 2996.)
* Pass flags in make.bash (Fixes issue 3091.)
* Unify build flags, defined in one place.
* Clean up error messages (Fixes issue 3075.  Fixes issue 2923.)
* Support local import paths (Fixes issue 3118.)
* Allow top-level package outside $GOPATH (Fixes issue 3009.)

In addition to these fixes, all commands now take a list of
go files as a way to specify a single package, just as go build and
go run always have.  This means you can:

        go list -json x.go
        go fix x.go
        go vet x.go
        go test x_test.go

Preliminary tests in test.bash.
Mainly testing things that the ordinary build does not.
I don't mind if the script doesn't run on Windows.

I expect that gccgo support is now broken, and I hope that
people will feel free to file issues and/or send CLs to fix it.  :-)

R=golang-dev, dsymonds, r, rogpeppe
CC=golang-dev
https://golang.org/cl/5708054
parent ebe1664d
This diff is collapsed.
...@@ -13,7 +13,7 @@ import ( ...@@ -13,7 +13,7 @@ import (
) )
var cmdClean = &Command{ var cmdClean = &Command{
UsageLine: "clean [-i] [-r] [-n] [-x] [importpath...]", UsageLine: "clean [-i] [-r] [-n] [-x] [packages]",
Short: "remove object files", Short: "remove object files",
Long: ` Long: `
Clean removes object files from package source directories. Clean removes object files from package source directories.
...@@ -50,6 +50,8 @@ The -r flag causes clean to be applied recursively to all the ...@@ -50,6 +50,8 @@ The -r flag causes clean to be applied recursively to all the
dependencies of the packages named by the import paths. dependencies of the packages named by the import paths.
The -x flag causes clean to print remove commands as it executes them. The -x flag causes clean to print remove commands as it executes them.
For more about specifying packages, see 'go help packages'.
`, `,
} }
......
This diff is collapsed.
...@@ -6,13 +6,13 @@ package main ...@@ -6,13 +6,13 @@ package main
var cmdFix = &Command{ var cmdFix = &Command{
Run: runFix, Run: runFix,
UsageLine: "fix [importpath...]", UsageLine: "fix [packages]",
Short: "run go tool fix on packages", Short: "run go tool fix on packages",
Long: ` Long: `
Fix runs the Go fix command on the packages named by the import paths. Fix runs the Go fix command on the packages named by the import paths.
For more about fix, see 'godoc fix'. For more about fix, see 'godoc fix'.
For more about import paths, see 'go help importpath'. For more about specifying packages, see 'go help packages'.
To run fix with specific options, run 'go tool fix'. To run fix with specific options, run 'go tool fix'.
......
...@@ -6,14 +6,14 @@ package main ...@@ -6,14 +6,14 @@ package main
var cmdFmt = &Command{ var cmdFmt = &Command{
Run: runFmt, Run: runFmt,
UsageLine: "fmt [importpath...]", UsageLine: "fmt [packages]",
Short: "run gofmt on package sources", Short: "run gofmt on package sources",
Long: ` Long: `
Fmt runs the command 'gofmt -l -w' on the packages named Fmt runs the command 'gofmt -l -w' on the packages named
by the import paths. It prints the names of the files that are modified. by the import paths. It prints the names of the files that are modified.
For more about gofmt, see 'godoc gofmt'. For more about gofmt, see 'godoc gofmt'.
For more about import paths, see 'go help importpath'. For more about specifying packages, see 'go help packages'.
To run gofmt with specific options, run gofmt itself. To run gofmt with specific options, run gofmt itself.
...@@ -32,14 +32,14 @@ func runFmt(cmd *Command, args []string) { ...@@ -32,14 +32,14 @@ func runFmt(cmd *Command, args []string) {
var cmdDoc = &Command{ var cmdDoc = &Command{
Run: runDoc, Run: runDoc,
UsageLine: "doc [importpath...]", UsageLine: "doc [packages]",
Short: "run godoc on package sources", Short: "run godoc on package sources",
Long: ` Long: `
Doc runs the godoc command on the packages named by the Doc runs the godoc command on the packages named by the
import paths. import paths.
For more about godoc, see 'godoc godoc'. For more about godoc, see 'godoc godoc'.
For more about import paths, see 'go help importpath'. For more about specifying packages, see 'go help packages'.
To run godoc with specific options, run godoc itself. To run godoc with specific options, run godoc itself.
...@@ -49,6 +49,10 @@ See also: go fix, go fmt, go vet. ...@@ -49,6 +49,10 @@ See also: go fix, go fmt, go vet.
func runDoc(cmd *Command, args []string) { func runDoc(cmd *Command, args []string) {
for _, pkg := range packages(args) { for _, pkg := range packages(args) {
if pkg.ImportPath == "command-line arguments" {
errorf("go doc: cannot use package file list")
continue
}
run("godoc", pkg.Dir) run("godoc", pkg.Dir)
} }
} }
...@@ -8,7 +8,6 @@ package main ...@@ -8,7 +8,6 @@ package main
import ( import (
"fmt" "fmt"
"go/build"
"os" "os"
"path/filepath" "path/filepath"
"runtime" "runtime"
...@@ -17,7 +16,7 @@ import ( ...@@ -17,7 +16,7 @@ import (
) )
var cmdGet = &Command{ var cmdGet = &Command{
UsageLine: "get [-a] [-d] [-fix] [-n] [-p n] [-u] [-v] [-x] [importpath...]", UsageLine: "get [-a] [-d] [-fix] [-n] [-p n] [-u] [-v] [-x] [packages]",
Short: "download and install packages and dependencies", Short: "download and install packages and dependencies",
Long: ` Long: `
Get downloads and installs the packages named by the import paths, Get downloads and installs the packages named by the import paths,
...@@ -33,12 +32,12 @@ The -fix flag instructs get to run the fix tool on the downloaded packages ...@@ -33,12 +32,12 @@ The -fix flag instructs get to run the fix tool on the downloaded packages
before resolving dependencies or building the code. before resolving dependencies or building the code.
The -u flag instructs get to use the network to update the named packages The -u flag instructs get to use the network to update the named packages
and their dependencies. By default, get uses the network to check out and their dependencies. By default, get uses the network to check out
missing packages but does not use it to look for updates to existing packages. missing packages but does not use it to look for updates to existing packages.
TODO: Explain versions better. TODO: Explain versions better.
For more about import paths, see 'go help importpath'. For more about specifying packages, see 'go help packages'.
For more about how 'go get' finds source code to For more about how 'go get' finds source code to
download, see 'go help remote'. download, see 'go help remote'.
...@@ -151,22 +150,35 @@ func download(arg string, stk *importStack) { ...@@ -151,22 +150,35 @@ func download(arg string, stk *importStack) {
// downloadPackage runs the create or download command // downloadPackage runs the create or download command
// to make the first copy of or update a copy of the given package. // to make the first copy of or update a copy of the given package.
func downloadPackage(p *Package) error { func downloadPackage(p *Package) error {
// Analyze the import path to determine the version control system, var (
// repository, and the import path for the root of the repository. vcs *vcsCmd
vcs, repo, rootPath, err := vcsForImportPath(p.ImportPath) repo, rootPath string
err error
)
if p.build.SrcRoot != "" {
// Directory exists. Look for checkout along path to src.
vcs, rootPath, err = vcsForDir(p)
repo = "<local>" // should be unused; make distinctive
} else {
// Analyze the import path to determine the version control system,
// repository, and the import path for the root of the repository.
vcs, repo, rootPath, err = vcsForImportPath(p.ImportPath)
}
if err != nil { if err != nil {
return err return err
} }
if p.t == nil {
if p.build.SrcRoot == "" {
// Package not found. Put in first directory of $GOPATH or else $GOROOT. // Package not found. Put in first directory of $GOPATH or else $GOROOT.
p.t = build.Path[0] // $GOROOT if list := filepath.SplitList(buildContext.GOPATH); len(list) > 0 {
if len(build.Path) > 1 { p.build.SrcRoot = filepath.Join(list[0], "src")
p.t = build.Path[1] // first in $GOPATH p.build.PkgRoot = filepath.Join(list[0], "pkg")
} else {
p.build.SrcRoot = filepath.Join(goroot, "src", "pkg")
p.build.PkgRoot = filepath.Join(goroot, "pkg")
} }
p.Dir = filepath.Join(p.t.SrcDir(), p.ImportPath)
} }
root := filepath.Join(p.t.SrcDir(), rootPath) root := filepath.Join(p.build.SrcRoot, rootPath)
// If we've considered this repository already, don't do it again. // If we've considered this repository already, don't do it again.
if downloadRootCache[root] { if downloadRootCache[root] {
return nil return nil
...@@ -206,6 +218,14 @@ func downloadPackage(p *Package) error { ...@@ -206,6 +218,14 @@ func downloadPackage(p *Package) error {
} }
} }
if buildN {
// Do not show tag sync in -n; it's noise more than anything,
// and since we're not running commands, no tag will be found.
// But avoid printing nothing.
fmt.Fprintf(os.Stderr, "# cd %s; %s sync/update\n", root, vcs.cmd)
return nil
}
// Select and sync to appropriate version of the repository. // Select and sync to appropriate version of the repository.
tags, err := vcs.tags(root) tags, err := vcs.tags(root)
if err != nil { if err != nil {
......
...@@ -4,13 +4,15 @@ ...@@ -4,13 +4,15 @@
package main package main
var helpImportpath = &Command{ var helpPackages = &Command{
UsageLine: "importpath", UsageLine: "packages",
Short: "description of import paths", Short: "description of package lists",
Long: ` Long: `
Many commands apply to a set of packages named by import paths: Many commands apply to a set of packages:
go action [importpath...] go action [packages]
Usually, [packages] is a list of import paths.
An import path that is a rooted path or that begins with An import path that is a rooted path or that begins with
a . or .. element is interpreted as a file system path and a . or .. element is interpreted as a file system path and
...@@ -34,7 +36,7 @@ An import path is a pattern if it includes one or more "..." wildcards, ...@@ -34,7 +36,7 @@ An import path is a pattern if it includes one or more "..." wildcards,
each of which can match any string, including the empty string and each of which can match any string, including the empty string and
strings containing slashes. Such a pattern expands to all package strings containing slashes. Such a pattern expands to all package
directories found in the GOPATH trees with names matching the directories found in the GOPATH trees with names matching the
patterns. For example, encoding/... expands to all package patterns. For example, encoding/... expands to all packages
in subdirectories of the encoding tree, while net... expands to in subdirectories of the encoding tree, while net... expands to
net and all its subdirectories. net and all its subdirectories.
...@@ -47,6 +49,11 @@ unique prefix that belongs to you. For example, paths used ...@@ -47,6 +49,11 @@ unique prefix that belongs to you. For example, paths used
internally at Google all begin with 'google', and paths internally at Google all begin with 'google', and paths
denoting remote repositories begin with the path to the code, denoting remote repositories begin with the path to the code,
such as 'code.google.com/p/project'. such as 'code.google.com/p/project'.
As a special case, if the package list is a list of .go files from a
single directory, the command is applied to a single synthesized
package made up of exactly those files, ignoring any build constraints
in those files and ignoring any other files in the directory.
`, `,
} }
......
...@@ -13,7 +13,7 @@ import ( ...@@ -13,7 +13,7 @@ import (
) )
var cmdList = &Command{ var cmdList = &Command{
UsageLine: "list [-e] [-f format] [-json] [importpath...]", UsageLine: "list [-e] [-f format] [-json] [packages]",
Short: "list packages", Short: "list packages",
Long: ` Long: `
List lists the packages named by the import paths, one per line. List lists the packages named by the import paths, one per line.
...@@ -69,7 +69,7 @@ printing. Erroneous packages will have a non-empty ImportPath and ...@@ -69,7 +69,7 @@ printing. Erroneous packages will have a non-empty ImportPath and
a non-nil Error field; other information may or may not be missing a non-nil Error field; other information may or may not be missing
(zeroed). (zeroed).
For more about import paths, see 'go help importpath'. For more about specifying packages, see 'go help packages'.
`, `,
} }
......
...@@ -88,7 +88,7 @@ var commands = []*Command{ ...@@ -88,7 +88,7 @@ var commands = []*Command{
cmdVet, cmdVet,
helpGopath, helpGopath,
helpImportpath, helpPackages,
helpRemote, helpRemote,
helpTestflag, helpTestflag,
helpTestfunc, helpTestfunc,
...@@ -251,7 +251,24 @@ func importPaths(args []string) []string { ...@@ -251,7 +251,24 @@ func importPaths(args []string) []string {
} }
var out []string var out []string
for _, a := range args { for _, a := range args {
if isLocalPath(a) && strings.Contains(a, "...") { // Arguments are supposed to be import paths, but
// as a courtesy to Windows developers, rewrite \ to /
// in command-line arguments. Handles .\... and so on.
if filepath.Separator == '\\' {
a = strings.Replace(a, `\`, `/`, -1)
}
// Put argument in canonical form, but preserve leading ./.
if strings.HasPrefix(a, "./") {
a = "./" + path.Clean(a)
if a == "./." {
a = "."
}
} else {
a = path.Clean(a)
}
if build.IsLocalImport(a) && strings.Contains(a, "...") {
out = append(out, allPackagesInFS(a)...) out = append(out, allPackagesInFS(a)...)
continue continue
} }
...@@ -350,7 +367,6 @@ func allPackages(pattern string) []string { ...@@ -350,7 +367,6 @@ func allPackages(pattern string) []string {
var pkgs []string var pkgs []string
// Commands // Commands
goroot := build.Path[0].Path
cmd := filepath.Join(goroot, "src/cmd") + string(filepath.Separator) cmd := filepath.Join(goroot, "src/cmd") + string(filepath.Separator)
filepath.Walk(cmd, func(path string, fi os.FileInfo, err error) error { filepath.Walk(cmd, func(path string, fi os.FileInfo, err error) error {
if err != nil || !fi.IsDir() || path == cmd { if err != nil || !fi.IsDir() || path == cmd {
...@@ -362,7 +378,7 @@ func allPackages(pattern string) []string { ...@@ -362,7 +378,7 @@ func allPackages(pattern string) []string {
return filepath.SkipDir return filepath.SkipDir
} }
_, err = build.ScanDir(path) _, err = build.ImportDir(path, 0)
if err != nil { if err != nil {
return nil return nil
} }
...@@ -378,11 +394,11 @@ func allPackages(pattern string) []string { ...@@ -378,11 +394,11 @@ func allPackages(pattern string) []string {
return nil return nil
}) })
for _, t := range build.Path { for _, src := range buildContext.SrcDirs() {
if pattern == "std" && !t.Goroot { if pattern == "std" && src != gorootSrcPkg {
continue continue
} }
src := t.SrcDir() + string(filepath.Separator) src = filepath.Clean(src) + string(filepath.Separator)
filepath.Walk(src, func(path string, fi os.FileInfo, err error) error { filepath.Walk(src, func(path string, fi os.FileInfo, err error) error {
if err != nil || !fi.IsDir() || path == src { if err != nil || !fi.IsDir() || path == src {
return nil return nil
...@@ -403,21 +419,13 @@ func allPackages(pattern string) []string { ...@@ -403,21 +419,13 @@ func allPackages(pattern string) []string {
} }
have[name] = true have[name] = true
_, err = build.ScanDir(path) _, err = build.ImportDir(path, 0)
if err != nil && strings.Contains(err.Error(), "no Go source files") { if err != nil && strings.Contains(err.Error(), "no Go source files") {
return nil return nil
} }
if match(name) { if match(name) {
pkgs = append(pkgs, name) pkgs = append(pkgs, name)
} }
// Avoid go/build test data.
// TODO: Move it into a testdata directory.
if path == filepath.Join(build.Path[0].SrcDir(), "go/build") {
return filepath.SkipDir
}
return nil return nil
}) })
} }
...@@ -465,7 +473,7 @@ func allPackagesInFS(pattern string) []string { ...@@ -465,7 +473,7 @@ func allPackagesInFS(pattern string) []string {
if !match(name) { if !match(name) {
return nil return nil
} }
if _, err = build.ScanDir(path); err != nil { if _, err = build.ImportDir(path, 0); err != nil {
return nil return nil
} }
pkgs = append(pkgs, name) pkgs = append(pkgs, name)
...@@ -494,10 +502,3 @@ func stringList(args ...interface{}) []string { ...@@ -494,10 +502,3 @@ func stringList(args ...interface{}) []string {
} }
return x return x
} }
// isLocalPath returns true if arg is an import path denoting
// a local file system directory. That is, it returns true if the
// path begins with ./ or ../ .
func isLocalPath(arg string) bool {
return arg == "." || arg == ".." || strings.HasPrefix(arg, "./") || strings.HasPrefix(arg, "../")
}
This diff is collapsed.
...@@ -12,14 +12,12 @@ import ( ...@@ -12,14 +12,12 @@ import (
) )
var cmdRun = &Command{ var cmdRun = &Command{
UsageLine: "run [-a] [-n] [-x] gofiles... [arguments...]", UsageLine: "run [build flags] gofiles... [arguments...]",
Short: "compile and run Go program", Short: "compile and run Go program",
Long: ` Long: `
Run compiles and runs the main package comprising the named Go source files. Run compiles and runs the main package comprising the named Go source files.
The -a flag forces reinstallation of packages that are already up-to-date. For more about build flags, see 'go help build'.
The -n flag prints the commands but does not run them.
The -x flag prints the commands.
See also: go build. See also: go build.
`, `,
...@@ -46,7 +44,7 @@ func runRun(cmd *Command, args []string) { ...@@ -46,7 +44,7 @@ func runRun(cmd *Command, args []string) {
i++ i++
} }
files, cmdArgs := args[:i], args[i:] files, cmdArgs := args[:i], args[i:]
p := goFilesPackage(files, "") p := goFilesPackage(files)
p.target = "" // must build - not up to date p.target = "" // must build - not up to date
a1 := b.action(modeBuild, modeBuild, p) a1 := b.action(modeBuild, modeBuild, p)
a := &action{f: (*builder).runProgram, args: cmdArgs, deps: []*action{a1}} a := &action{f: (*builder).runProgram, args: cmdArgs, deps: []*action{a1}}
......
#!/bin/bash
# Copyright 2012 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.
set -e
go build -o testgo
ok=true
# Test that error messages have file:line information
# at beginning of line.
for i in testdata/errmsg/*.go
do
# TODO: |cat should not be necessary here but is.
./testgo test $i 2>&1 | cat >err.out || true
if ! grep -q "^$i:" err.out; then
echo "$i: missing file:line in error message"
cat err.out
ok=false
fi
done
# Test local (./) imports.
./testgo build -o hello testdata/local/easy.go
./hello >hello.out
if ! grep -q '^easysub\.Hello' hello.out; then
echo "testdata/local/easy.go did not generate expected output"
cat hello.out
ok=false
fi
./testgo build -o hello testdata/local/hard.go
./hello >hello.out
if ! grep -q '^sub\.Hello' hello.out || ! grep -q '^subsub\.Hello' hello.out ; then
echo "testdata/local/hard.go did not generate expected output"
cat hello.out
ok=false
fi
rm -f err.out hello.out hello
# Test that go install x.go fails.
if ./testgo install testdata/local/easy.go >/dev/null 2>&1; then
echo "go install testdata/local/easy.go succeeded"
ok=false
fi
if $ok; then
echo PASS
else
echo FAIL
exit 1
fi
...@@ -11,7 +11,6 @@ import ( ...@@ -11,7 +11,6 @@ import (
"go/build" "go/build"
"go/doc" "go/doc"
"go/parser" "go/parser"
"go/scanner"
"go/token" "go/token"
"os" "os"
"os/exec" "os/exec"
...@@ -33,7 +32,7 @@ func init() { ...@@ -33,7 +32,7 @@ func init() {
var cmdTest = &Command{ var cmdTest = &Command{
CustomFlags: true, CustomFlags: true,
UsageLine: "test [-c] [-i] [-p n] [-x] [importpath...] [flags for test binary]", UsageLine: "test [-c] [-i] [build flags] [packages] [flags for test binary]",
Short: "test packages", Short: "test packages",
Long: ` Long: `
'Go test' automates testing the packages named by the import paths. 'Go test' automates testing the packages named by the import paths.
...@@ -56,7 +55,7 @@ with source in the current directory, including tests, and runs the tests. ...@@ -56,7 +55,7 @@ with source in the current directory, including tests, and runs the tests.
The package is built in a temporary directory so it does not interfere with the The package is built in a temporary directory so it does not interfere with the
non-test installation. non-test installation.
The flags handled by 'go test' itself are: In addition to the build flags, the flags handled by 'go test' itself are:
-c Compile the test binary to pkg.test but do not run it. -c Compile the test binary to pkg.test but do not run it.
...@@ -64,16 +63,11 @@ The flags handled by 'go test' itself are: ...@@ -64,16 +63,11 @@ The flags handled by 'go test' itself are:
Install packages that are dependencies of the test. Install packages that are dependencies of the test.
Do not run the test. Do not run the test.
-p n
Compile and test up to n packages in parallel.
The default value is the number of CPUs available.
-x Print each subcommand go test executes.
The test binary also accepts flags that control execution of the test; these The test binary also accepts flags that control execution of the test; these
flags are also accessible by 'go test'. See 'go help testflag' for details. flags are also accessible by 'go test'. See 'go help testflag' for details.
See 'go help importpath' for more about import paths. For more about build flags, see 'go help build'.
For more about specifying packages, see 'go help packages'.
See also: go build, go vet. See also: go build, go vet.
`, `,
...@@ -134,7 +128,7 @@ directory containing the package sources, has its own flags: ...@@ -134,7 +128,7 @@ directory containing the package sources, has its own flags:
The default is 1 second. The default is 1 second.
-test.cpu 1,2,4 -test.cpu 1,2,4
Specify a list of GOMAXPROCS values for which the tests or Specify a list of GOMAXPROCS values for which the tests or
benchmarks should be executed. The default is the current value benchmarks should be executed. The default is the current value
of GOMAXPROCS. of GOMAXPROCS.
...@@ -265,10 +259,10 @@ func runTest(cmd *Command, args []string) { ...@@ -265,10 +259,10 @@ func runTest(cmd *Command, args []string) {
} }
for _, p := range pkgs { for _, p := range pkgs {
// Dependencies for each test. // Dependencies for each test.
for _, path := range p.info.Imports { for _, path := range p.Imports {
deps[path] = true deps[path] = true
} }
for _, path := range p.info.TestImports { for _, path := range p.TestImports {
deps[path] = true deps[path] = true
} }
} }
...@@ -307,17 +301,15 @@ func runTest(cmd *Command, args []string) { ...@@ -307,17 +301,15 @@ func runTest(cmd *Command, args []string) {
for _, p := range pkgs { for _, p := range pkgs {
buildTest, runTest, printTest, err := b.test(p) buildTest, runTest, printTest, err := b.test(p)
if err != nil { if err != nil {
if list, ok := err.(scanner.ErrorList); ok { str := err.Error()
const n = 10 if strings.HasPrefix(str, "\n") {
if len(list) > n { str = str[1:]
list = list[:n] }
} if p.ImportPath != "" {
for _, err := range list { errorf("# %s\n%s", p.ImportPath, str)
errorf("%s", err) } else {
} errorf("%s", str)
continue
} }
errorf("%s", err)
continue continue
} }
builds = append(builds, buildTest) builds = append(builds, buildTest)
...@@ -380,7 +372,7 @@ func runTest(cmd *Command, args []string) { ...@@ -380,7 +372,7 @@ func runTest(cmd *Command, args []string) {
} }
func (b *builder) test(p *Package) (buildAction, runAction, printAction *action, err error) { func (b *builder) test(p *Package) (buildAction, runAction, printAction *action, err error) {
if len(p.info.TestGoFiles)+len(p.info.XTestGoFiles) == 0 { if len(p.TestGoFiles)+len(p.XTestGoFiles) == 0 {
build := &action{p: p} build := &action{p: p}
run := &action{p: p} run := &action{p: p}
print := &action{f: (*builder).notest, p: p, deps: []*action{build}} print := &action{f: (*builder).notest, p: p, deps: []*action{build}}
...@@ -393,20 +385,23 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action, ...@@ -393,20 +385,23 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
// pmain - pkg.test binary // pmain - pkg.test binary
var ptest, pxtest, pmain *Package var ptest, pxtest, pmain *Package
// go/build does not distinguish the dependencies used var imports, ximports []*Package
// by the TestGoFiles from the dependencies used by the
// XTestGoFiles, so we build one list and use it for both
// ptest and pxtest. No harm done.
var imports []*Package
var stk importStack var stk importStack
stk.push(p.ImportPath + "_test") stk.push(p.ImportPath + "_test")
for _, path := range p.info.TestImports { for _, path := range p.TestImports {
p1 := loadPackage(path, &stk) p1 := loadImport(path, p.Dir, &stk, p.build.TestImportPos[path])
if p1.Error != nil { if p1.Error != nil {
return nil, nil, nil, p1.Error return nil, nil, nil, p1.Error
} }
imports = append(imports, p1) imports = append(imports, p1)
} }
for _, path := range p.XTestImports {
p1 := loadImport(path, p.Dir, &stk, p.build.XTestImportPos[path])
if p1.Error != nil {
return nil, nil, nil, p1.Error
}
ximports = append(ximports, p1)
}
stk.pop() stk.pop()
// Use last element of import path, not package name. // Use last element of import path, not package name.
...@@ -429,7 +424,7 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action, ...@@ -429,7 +424,7 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
// We write the external test package archive to // We write the external test package archive to
// $WORK/unicode/utf8/_test/unicode/utf8_test.a. // $WORK/unicode/utf8/_test/unicode/utf8_test.a.
testDir := filepath.Join(b.work, filepath.FromSlash(p.ImportPath+"/_test")) testDir := filepath.Join(b.work, filepath.FromSlash(p.ImportPath+"/_test"))
ptestObj := buildToolchain.pkgpath(testDir, p) ptestObj := buildToolchain.pkgpath(testDir, p, false)
// Create the directory for the .a files. // Create the directory for the .a files.
ptestDir, _ := filepath.Split(ptestObj) ptestDir, _ := filepath.Split(ptestObj)
...@@ -441,17 +436,27 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action, ...@@ -441,17 +436,27 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
} }
// Test package. // Test package.
if len(p.info.TestGoFiles) > 0 { if len(p.TestGoFiles) > 0 {
ptest = new(Package) ptest = new(Package)
*ptest = *p *ptest = *p
ptest.GoFiles = nil ptest.GoFiles = nil
ptest.GoFiles = append(ptest.GoFiles, p.GoFiles...) ptest.GoFiles = append(ptest.GoFiles, p.GoFiles...)
ptest.GoFiles = append(ptest.GoFiles, p.info.TestGoFiles...) ptest.GoFiles = append(ptest.GoFiles, p.TestGoFiles...)
ptest.target = "" ptest.target = ""
ptest.Imports = stringList(p.info.Imports, p.info.TestImports) ptest.Imports = stringList(p.Imports, p.TestImports)
ptest.imports = append(append([]*Package{}, p.imports...), imports...) ptest.imports = append(append([]*Package{}, p.imports...), imports...)
ptest.pkgdir = testDir ptest.pkgdir = testDir
ptest.fake = true ptest.fake = true
ptest.build = new(build.Package)
*ptest.build = *p.build
m := map[string][]token.Position{}
for k, v := range p.build.ImportPos {
m[k] = append(m[k], v...)
}
for k, v := range p.build.TestImportPos {
m[k] = append(m[k], v...)
}
ptest.build.ImportPos = m
a := b.action(modeBuild, modeBuild, ptest) a := b.action(modeBuild, modeBuild, ptest)
a.objdir = testDir + string(filepath.Separator) a.objdir = testDir + string(filepath.Separator)
a.objpkg = ptestObj a.objpkg = ptestObj
...@@ -462,23 +467,23 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action, ...@@ -462,23 +467,23 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
} }
// External test package. // External test package.
if len(p.info.XTestGoFiles) > 0 { if len(p.XTestGoFiles) > 0 {
pxtest = &Package{ pxtest = &Package{
Name: p.Name + "_test", Name: p.Name + "_test",
ImportPath: p.ImportPath + "_test", ImportPath: p.ImportPath + "_test",
Dir: p.Dir, Dir: p.Dir,
GoFiles: p.info.XTestGoFiles, GoFiles: p.XTestGoFiles,
Imports: p.info.TestImports, Imports: p.XTestImports,
t: p.t, build: &build.Package{
info: &build.DirInfo{}, ImportPos: p.build.XTestImportPos,
imports: imports, },
pkgdir: testDir, imports: append(ximports, ptest),
fake: true, pkgdir: testDir,
fake: true,
} }
pxtest.imports = append(pxtest.imports, ptest)
a := b.action(modeBuild, modeBuild, pxtest) a := b.action(modeBuild, modeBuild, pxtest)
a.objdir = testDir + string(filepath.Separator) a.objdir = testDir + string(filepath.Separator)
a.objpkg = buildToolchain.pkgpath(testDir, pxtest) a.objpkg = buildToolchain.pkgpath(testDir, pxtest, false)
a.target = a.objpkg a.target = a.objpkg
} }
...@@ -487,9 +492,8 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action, ...@@ -487,9 +492,8 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
Name: "main", Name: "main",
Dir: testDir, Dir: testDir,
GoFiles: []string{"_testmain.go"}, GoFiles: []string{"_testmain.go"},
t: p.t,
info: &build.DirInfo{},
imports: []*Package{ptest}, imports: []*Package{ptest},
build: &build.Package{},
fake: true, fake: true,
} }
if pxtest != nil { if pxtest != nil {
...@@ -498,11 +502,11 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action, ...@@ -498,11 +502,11 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
// The generated main also imports testing and regexp. // The generated main also imports testing and regexp.
stk.push("testmain") stk.push("testmain")
ptesting := loadPackage("testing", &stk) ptesting := loadImport("testing", "", &stk, nil)
if ptesting.Error != nil { if ptesting.Error != nil {
return nil, nil, nil, ptesting.Error return nil, nil, nil, ptesting.Error
} }
pregexp := loadPackage("regexp", &stk) pregexp := loadImport("regexp", "", &stk, nil)
if pregexp.Error != nil { if pregexp.Error != nil {
return nil, nil, nil, pregexp.Error return nil, nil, nil, pregexp.Error
} }
...@@ -511,7 +515,7 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action, ...@@ -511,7 +515,7 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
a := b.action(modeBuild, modeBuild, pmain) a := b.action(modeBuild, modeBuild, pmain)
a.objdir = testDir + string(filepath.Separator) a.objdir = testDir + string(filepath.Separator)
a.objpkg = filepath.Join(testDir, "main.a") a.objpkg = filepath.Join(testDir, "main.a")
a.target = filepath.Join(testDir, testBinary) + b.exe a.target = filepath.Join(testDir, testBinary) + exeSuffix
pmainAction := a pmainAction := a
if testC { if testC {
...@@ -520,7 +524,7 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action, ...@@ -520,7 +524,7 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
f: (*builder).install, f: (*builder).install,
deps: []*action{pmainAction}, deps: []*action{pmainAction},
p: pmain, p: pmain,
target: testBinary + b.exe, target: testBinary + exeSuffix,
} }
printAction = &action{p: p, deps: []*action{runAction}} // nop printAction = &action{p: p, deps: []*action{runAction}} // nop
} else { } else {
...@@ -664,14 +668,13 @@ func isTest(name, prefix string) bool { ...@@ -664,14 +668,13 @@ func isTest(name, prefix string) bool {
func writeTestmain(out string, p *Package) error { func writeTestmain(out string, p *Package) error {
t := &testFuncs{ t := &testFuncs{
Package: p, Package: p,
Info: p.info,
} }
for _, file := range p.info.TestGoFiles { for _, file := range p.TestGoFiles {
if err := t.load(filepath.Join(p.Dir, file), "_test", &t.NeedTest); err != nil { if err := t.load(filepath.Join(p.Dir, file), "_test", &t.NeedTest); err != nil {
return err return err
} }
} }
for _, file := range p.info.XTestGoFiles { for _, file := range p.XTestGoFiles {
if err := t.load(filepath.Join(p.Dir, file), "_xtest", &t.NeedXtest); err != nil { if err := t.load(filepath.Join(p.Dir, file), "_xtest", &t.NeedXtest); err != nil {
return err return err
} }
...@@ -695,7 +698,6 @@ type testFuncs struct { ...@@ -695,7 +698,6 @@ type testFuncs struct {
Benchmarks []testFunc Benchmarks []testFunc
Examples []testFunc Examples []testFunc
Package *Package Package *Package
Info *build.DirInfo
NeedTest bool NeedTest bool
NeedXtest bool NeedXtest bool
} }
...@@ -711,7 +713,7 @@ var testFileSet = token.NewFileSet() ...@@ -711,7 +713,7 @@ var testFileSet = token.NewFileSet()
func (t *testFuncs) load(filename, pkg string, seen *bool) error { func (t *testFuncs) load(filename, pkg string, seen *bool) error {
f, err := parser.ParseFile(testFileSet, filename, nil, parser.ParseComments) f, err := parser.ParseFile(testFileSet, filename, nil, parser.ParseComments)
if err != nil { if err != nil {
return err return expandScanner(err)
} }
for _, d := range f.Decls { for _, d := range f.Decls {
n, ok := d.(*ast.FuncDecl) n, ok := d.(*ast.FuncDecl)
......
package foo
import "bar"
package foo_test
import "bar"
package main
import "./easysub"
func main() {
easysub.Hello()
}
package easysub
import "fmt"
func Hello() {
fmt.Println("easysub.Hello")
}
package main
import "./sub"
func main() {
sub.Hello()
}
package sub
import (
"fmt"
subsub "./sub"
)
func Hello() {
fmt.Println("sub.Hello")
subsub.Hello()
}
package subsub
import "fmt"
func Hello() {
fmt.Println("subsub.Hello")
}
...@@ -10,6 +10,7 @@ import ( ...@@ -10,6 +10,7 @@ import (
"fmt" "fmt"
"os" "os"
"os/exec" "os/exec"
"path/filepath"
"regexp" "regexp"
"strings" "strings"
) )
...@@ -269,6 +270,38 @@ type vcsPath struct { ...@@ -269,6 +270,38 @@ type vcsPath struct {
regexp *regexp.Regexp // cached compiled form of re regexp *regexp.Regexp // cached compiled form of re
} }
// vcsForDir inspects dir and its parents to determine the
// version control system and code repository to use.
// On return, root is the import path
// corresponding to the root of the repository
// (thus root is a prefix of importPath).
func vcsForDir(p *Package) (vcs *vcsCmd, root string, err error) {
// Clean and double-check that dir is in (a subdirectory of) srcRoot.
dir := filepath.Clean(p.Dir)
srcRoot := filepath.Clean(p.build.SrcRoot)
if len(dir) <= len(srcRoot) || dir[len(srcRoot)] != filepath.Separator {
return nil, "", fmt.Errorf("directory %q is outside source root %q", dir, srcRoot)
}
for len(dir) > len(srcRoot) {
for _, vcs := range vcsList {
if fi, err := os.Stat(filepath.Join(dir, "."+vcs.cmd)); err == nil && fi.IsDir() {
return vcs, dir[len(srcRoot)+1:], nil
}
}
// Move to parent.
ndir := filepath.Dir(dir)
if len(ndir) >= len(dir) {
// Shouldn't happen, but just in case, stop.
break
}
dir = ndir
}
return nil, "", fmt.Errorf("directory %q is not using a known version control system", dir)
}
// vcsForImportPath analyzes importPath to determine the // vcsForImportPath analyzes importPath to determine the
// version control system, and code repository to use. // version control system, and code repository to use.
// On return, repo is the repository URL and root is the // On return, repo is the repository URL and root is the
......
...@@ -6,13 +6,13 @@ package main ...@@ -6,13 +6,13 @@ package main
var cmdVet = &Command{ var cmdVet = &Command{
Run: runVet, Run: runVet,
UsageLine: "vet [importpath...]", UsageLine: "vet [packages]",
Short: "run go tool vet on packages", Short: "run go tool vet on packages",
Long: ` Long: `
Vet runs the Go vet command on the packages named by the import paths. Vet runs the Go vet command on the packages named by the import paths.
For more about vet, see 'godoc vet'. For more about vet, see 'godoc vet'.
For more about import paths, see 'go help importpath'. For more about specifying packages, see 'go help packages'.
To run the vet tool with specific options, run 'go tool vet'. To run the vet tool with specific options, run 'go tool vet'.
......
...@@ -3,6 +3,29 @@ ...@@ -3,6 +3,29 @@
# 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.
# Environment variables that control make.bash:
#
# GOROOT_FINAL: The expected final Go root, baked into binaries.
# The default is the location of the Go tree during the build.
#
# GOHOSTARCH: The architecture for host tools (compilers and
# binaries). Binaries of this type must be executable on the current
# system, so the only common reason to set this is to set
# GOHOSTARCH=386 on an amd64 machine.
#
# GOARCH: The target architecture for installed packages and tools.
#
# GOOS: The target operating system for installed packages and tools.
#
# GCFLAGS: Additional 5g/6g/8g arguments to use when
# building the packages and commands.
#
# LDFLAGS: Additional 5l/6l/8l arguments to use when
# building the packages and commands.
#
# CGO_ENABLED: Setting this to 0 disables the use of cgo
# in the built and installed packages and tools.
set -e set -e
if [ ! -f run.bash ]; then if [ ! -f run.bash ]; then
echo 'make.bash must be run from $GOROOT/src' 1>&2 echo 'make.bash must be run from $GOROOT/src' 1>&2
...@@ -88,12 +111,12 @@ echo ...@@ -88,12 +111,12 @@ echo
if [ "$GOHOSTARCH" != "$GOARCH" -o "$GOHOSTOS" != "$GOOS" ]; then if [ "$GOHOSTARCH" != "$GOARCH" -o "$GOHOSTOS" != "$GOOS" ]; then
echo "# Building packages and commands for host, $GOHOSTOS/$GOHOSTARCH." echo "# Building packages and commands for host, $GOHOSTOS/$GOHOSTARCH."
GOOS=$GOHOSTOS GOARCH=$GOHOSTARCH \ GOOS=$GOHOSTOS GOARCH=$GOHOSTARCH \
$GOTOOLDIR/go_bootstrap install -v std $GOTOOLDIR/go_bootstrap install -gcflags "$GCFLAGS" -ldflags "$LDFLAGS" -v std
echo echo
fi fi
echo "# Building packages and commands for $GOOS/$GOARCH." echo "# Building packages and commands for $GOOS/$GOARCH."
$GOTOOLDIR/go_bootstrap install -v std $GOTOOLDIR/go_bootstrap install -gcflags "$GCFLAGS" -ldflags "$LDFLAGS" -v std
echo echo
rm -f $GOTOOLDIR/go_bootstrap rm -f $GOTOOLDIR/go_bootstrap
......
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