Skip to content
This repository has been archived by the owner on Mar 6, 2020. It is now read-only.

New importer #511

Merged
merged 6 commits into from
Dec 31, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 14 additions & 10 deletions build_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@ package gb
import (
"errors"
"fmt"
"go/build"
"io/ioutil"
"os"
"path/filepath"
"reflect"
"sort"
"testing"

"github.com/constabulary/gb/importer"
)

func TestBuild(t *testing.T) {
Expand Down Expand Up @@ -69,6 +70,9 @@ func TestBuild(t *testing.T) {
}, {
pkg: "tags2",
opts: opts(Tags("x")),
}, {
pkg: "nosource",
err: &importer.NoGoError{filepath.Join(getwd(t), "testdata", "src", "nosource")},
}}

proj := testProject(t)
Expand Down Expand Up @@ -269,39 +273,39 @@ func TestPkgname(t *testing.T) {
want string
}{{
pkg: &Package{
Package: &build.Package{
Package: &importer.Package{
Name: "main",
ImportPath: "main",
},
},
want: "main",
}, {
pkg: &Package{
Package: &build.Package{
Package: &importer.Package{
Name: "a",
ImportPath: "main",
},
},
want: "a",
}, {
pkg: &Package{
Package: &build.Package{
Package: &importer.Package{
Name: "main",
ImportPath: "a",
},
},
want: "a",
}, {
pkg: &Package{
Package: &build.Package{
Package: &importer.Package{
Name: "main",
ImportPath: "testmain",
},
},
want: "testmain",
}, {
pkg: &Package{
Package: &build.Package{
Package: &importer.Package{
Name: "main",
ImportPath: "main",
},
Expand All @@ -310,7 +314,7 @@ func TestPkgname(t *testing.T) {
want: "main",
}, {
pkg: &Package{
Package: &build.Package{
Package: &importer.Package{
Name: "a",
ImportPath: "main",
},
Expand All @@ -319,7 +323,7 @@ func TestPkgname(t *testing.T) {
want: "main",
}, {
pkg: &Package{
Package: &build.Package{
Package: &importer.Package{
Name: "main",
ImportPath: "a",
},
Expand All @@ -328,7 +332,7 @@ func TestPkgname(t *testing.T) {
want: "a",
}, {
pkg: &Package{
Package: &build.Package{
Package: &importer.Package{
Name: "main",
ImportPath: "a/a",
},
Expand All @@ -337,7 +341,7 @@ func TestPkgname(t *testing.T) {
want: "a",
}, {
pkg: &Package{
Package: &build.Package{
Package: &importer.Package{
Name: "main",
ImportPath: "testmain",
},
Expand Down
25 changes: 12 additions & 13 deletions cmd/gb/gb_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -789,10 +789,7 @@ func helloworld() {
`)
gb.cd(gb.tempdir)
gb.runFail("build", "pkg2")
gb.grepStderr(`^FATAL: command "build" failed: failed to resolve import path "pkg2": cannot find package "pkg2" in any of:`, "expected FATAL")
gb.grepStderr(regexp.QuoteMeta(filepath.Join(runtime.GOROOT(), "src", "pkg2")), "expected GOROOT")
gb.grepStderr(regexp.QuoteMeta(filepath.Join(gb.tempdir, "src", "pkg2")), "expected GOPATH")
gb.grepStderr(regexp.QuoteMeta(filepath.Join(gb.tempdir, "vendor", "src", "pkg2")), "expected GOPATH")
gb.grepStderr(`^FATAL: command "build" failed: failed to resolve import path "pkg2": import "pkg2": not a directory`, "expected FATAL")
}

func TestBuildPackageNoSource(t *testing.T) {
Expand Down Expand Up @@ -1086,17 +1083,15 @@ func TestGbListSrcTopLevel(t *testing.T) {
gb.grepStderrNot(".", "expected no output")
}

// gb list with a project with source in a top level directory called will fail.
func TestGbListSrcCmd(t *testing.T) {
gb := T{T: t}
defer gb.cleanup()
gb.tempDir("src")
gb.tempDir("src/cmd")
gb.tempFile("src/cmd/main.go", "package main; func main() { println() }")
gb.cd(gb.tempdir)
gb.runFail("list")
gb.grepStdoutNot(".", "expected no output")
gb.grepStderr(`unable to resolve: failed to resolve import path "cmd": no buildable Go source files in `+regexp.QuoteMeta(filepath.Join(runtime.GOROOT(), "src", "cmd")), "expected FATAL")
gb.run("list")
gb.grepStdout("cmd", "expected cmd")
}

func mklistfixture(gb *T) {
Expand Down Expand Up @@ -1403,7 +1398,7 @@ func main() { println("hello world") }
}

// https://github.com/constabulary/gb/issues/416
func TestGbBuildRejectsPackgeCalledCmd(t *testing.T) {
func TestGbBuildBuildsPackgeCalledCmd(t *testing.T) {
gb := T{T: t}
defer gb.cleanup()
gb.tempDir("src/cmd")
Expand All @@ -1413,11 +1408,15 @@ func main() { println("hello world") }
gb.cd(gb.tempdir)
tmpdir := gb.tempDir("tmp")
gb.setenv("TMP", tmpdir)
gb.runFail("build")
gb.run("build")
gb.mustBeEmpty(tmpdir)
gb.grepStderr(regexp.QuoteMeta(`FATAL: command "build" failed: failed to resolve import path "cmd": no buildable Go source files in `+filepath.Join(runtime.GOROOT(), "src", "cmd")), "expected $GOROOT/src/cmd")
gb.mustNotExist(filepath.Join(gb.tempdir, "pkg")) // ensure no pkg directory is created
gb.mustNotExist(filepath.Join(gb.tempdir, "bin")) // ensure no bin directory is created
gb.grepStdout("^cmd$", "expected cmd")
name := "cmd"
if runtime.GOOS == "windows" {
name += ".exe"
}
gb.mustExist(gb.path("bin", name))
gb.wantExecutable(gb.path("bin", name), "expected $PROJECT/bin/"+name)
}

// https://github.com/constabulary/gb/issues/492
Expand Down
116 changes: 91 additions & 25 deletions context.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package gb

import (
"fmt"
"go/build"
"io"
"io/ioutil"
"os"
Expand All @@ -16,12 +15,16 @@ import (
"time"

"github.com/constabulary/gb/debug"
"github.com/constabulary/gb/importer"
)

// Context represents an execution of one or more Targets inside a Project.
type Context struct {
*Project
importer

importers []interface {
Import(path string) (*importer.Package, error)
}

pkgs map[string]*Package // map of package paths to resolved packages

Expand Down Expand Up @@ -151,20 +154,27 @@ func (p *Project) NewContext(opts ...func(*Context) error) (*Context, error) {
// sort build tags to ensure the ctxSring and Suffix is stable
sort.Strings(ctx.buildtags)

// backfill enbedded go/build.Context
ctx.importer.srcdir = filepath.Join(ctx.Projectdir(), "src")
ctx.importer.bc = &build.Context{
GOOS: ctx.gotargetos,
GOARCH: ctx.gotargetarch,
GOROOT: runtime.GOROOT(),
GOPATH: togopath(p.Srcdirs()),
Compiler: runtime.Compiler, // TODO(dfc) probably unused

// Make sure we use the same set of release tags as go/build
ReleaseTags: build.Default.ReleaseTags,
ic := importer.Context{
GOOS: ctx.gotargetos,
GOARCH: ctx.gotargetarch,
CgoEnabled: cgoEnabled(ctx.gohostos, ctx.gohostarch, ctx.gotargetos, ctx.gotargetarch),
ReleaseTags: releaseTags, // from go/build, see gb.go
BuildTags: ctx.buildtags,
}

ctx.importers = append(ctx.importers,
&importer.Importer{
Context: &ic,
Root: runtime.GOROOT(),
},
)

CgoEnabled: build.Default.CgoEnabled,
for _, dir := range p.Srcdirs() {
ctx.importers = append(ctx.importers,
&importer.Importer{
Context: &ic,
Root: filepath.Dir(dir), // strip off "src"
})
}

// C and unsafe are fake packages synthesised by the compiler.
Expand All @@ -174,7 +184,7 @@ func (p *Project) NewContext(opts ...func(*Context) error) (*Context, error) {
Context: &ctx,
Scope: "build",
Standard: true, // synthetic packages belong to the stdlib
Package: &build.Package{
Package: &importer.Package{
Name: name,
ImportPath: name,
Goroot: true,
Expand Down Expand Up @@ -228,9 +238,8 @@ func (c *Context) ResolvePackage(path string) (*Package, error) {
// loadPackage recursively resolves path as a package. If successful loadPackage
// records the package in the Context's internal package cache.
func (c *Context) loadPackage(stack []string, path string) (*Package, error) {
// sanity check
if path == "." || path == ".." || strings.HasPrefix(path, "./") || strings.HasPrefix(path, "../") {
return nil, fmt.Errorf("%q is not a valid import path", path)
return nil, fmt.Errorf("import %q: relative import not supported", path)
}
if pkg, ok := c.pkgs[path]; ok {
// already loaded, just return
Expand All @@ -252,7 +261,7 @@ func (c *Context) loadPackage(stack []string, path string) (*Package, error) {
return false
}

p, err := c.Import(path)
p, err := c.importPackage(path)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -286,6 +295,25 @@ func (c *Context) loadPackage(stack []string, path string) (*Package, error) {
return &pkg, nil
}

// importPackage loads a package using the backing set of importers.
func (c *Context) importPackage(path string) (*importer.Package, error) {
pkg, err := c.importers[0].Import(path)
if err == nil {
return pkg, nil
}
pkg, err2 := c.importers[1].Import(path)
if err2 == nil {
return pkg, nil
}
if len(c.importers) > 2 {
pkg, err3 := c.importers[2].Import(path)
if err3 == nil {
return pkg, nil
}
}
return nil, err2
}

// Destroy removes the temporary working files of this context.
func (c *Context) Destroy() error {
debug.Debugf("removing work directory: %v", c.workdir)
Expand Down Expand Up @@ -437,14 +465,16 @@ func matchPackages(c *Context, pattern string) []string {
if !match(name) {
return nil
}
_, err = c.importer.bc.Import(".", path, 0)
if err != nil {
if _, noGo := err.(*build.NoGoError); noGo {
return nil
}
_, err = c.ResolvePackage(name)
switch err.(type) {
case nil:
pkgs = append(pkgs, name)
return nil
case *importer.NoGoError:
return nil // skip
default:
return err
}
pkgs = append(pkgs, name)
return nil
})
}
return pkgs
Expand Down Expand Up @@ -478,3 +508,39 @@ NextVar:
}
return out
}

func cgoEnabled(gohostos, gohostarch, gotargetos, gotargetarch string) bool {
switch os.Getenv("CGO_ENABLED") {
case "1":
return true
case "0":
return false
default:
// cgo must be explicitly enabled for cross compilation builds
if gohostos == gotargetos && gohostarch == gotargetarch {
switch gotargetos + "/" + gotargetarch {
case "darwin/386", "darwin/amd64", "darwin/arm", "darwin/arm64":
return true
case "dragonfly/amd64":
return true
case "freebsd/386", "freebsd/amd64", "freebsd/arm":
return true
case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le":
return true
case "android/386", "android/amd64", "android/arm":
return true
case "netbsd/386", "netbsd/amd64", "netbsd/arm":
return true
case "openbsd/386", "openbsd/amd64":
return true
case "solaris/amd64":
return true
case "windows/386", "windows/amd64":
return true
default:
return false
}
}
return false
}
}
Loading