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

Convert Importer interface to a function #684

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
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
47 changes: 8 additions & 39 deletions context.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,11 @@ import (
// enables sh style -e output
const eMode = false

// Importer resolves package import paths to *importer.Packages.
type Importer interface {

// Import attempts to resolve the package import path, path,
// to an *importer.Package.
Import(path string) (*build.Package, error)
}

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

importer Importer
importer func(string) (*build.Package, error)

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

Expand Down Expand Up @@ -167,13 +159,11 @@ func NewContext(p Project, opts ...func(*Context) error) (*Context, error) {
bc.ReleaseTags = releaseTags
bc.BuildTags = ctx.buildtags

i, err := buildImporter(&bc, &ctx)
ctx.importer, err = buildImporter(&bc, &ctx)
if err != nil {
return nil, err
}

ctx.importer = i

// C and unsafe are fake packages synthesised by the compiler.
// Insert fake packages into the package cache.
for _, name := range []string{"C", "unsafe"} {
Expand Down Expand Up @@ -252,7 +242,7 @@ func (c *Context) loadPackage(stack []string, path string) (*Package, error) {
return pkg, nil
}

p, err := c.importer.Import(path)
p, err := c.importer(path)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -416,40 +406,19 @@ func cgoEnabled(gohostos, gohostarch, gotargetos, gotargetarch string) bool {
}
}

func buildImporter(bc *build.Context, ctx *Context) (Importer, error) {
func buildImporter(bc *build.Context, ctx *Context) (func(string) (*build.Package, error), error) {
i, err := addDepfileDeps(bc, ctx)
if err != nil {
return nil, err
}

// construct importer stack in reverse order, vendor at the bottom, GOROOT on the top.
i = &_importer{
Importer: i,
im: importer{
Context: bc,
Root: filepath.Join(ctx.Projectdir(), "vendor"),
},
}
i = childFirstImporter(i, dirImporter(bc, filepath.Join(ctx.Projectdir(), "vendor")))

i = &srcImporter{
i,
importer{
Context: bc,
Root: ctx.Projectdir(),
},
}

i = &_importer{
i,
importer{
Context: bc,
Root: runtime.GOROOT(),
},
}
i = srcImporter(i, dirImporter(bc, ctx.Projectdir()))

i = &fixupImporter{
Importer: i,
}
i = childFirstImporter(i, dirImporter(bc, runtime.GOROOT()))

i = fixupImporter(i)
return i, nil
}
2 changes: 1 addition & 1 deletion context_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ func TestContextImportPackage(t *testing.T) {
if err != nil {
t.Fatal(err)
}
_, err = ctx.importer.Import(tt.path)
_, err = ctx.importer(tt.path)
if !reflect.DeepEqual(err, tt.err) {
t.Errorf("importPackage(%q): got %v, want %v", tt.path, err, tt.err)
}
Expand Down
20 changes: 4 additions & 16 deletions depfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ const semverRegex = `^([0-9]+)\.([0-9]+)\.([0-9]+)(?:(\-[0-9A-Za-z-]+(?:\.[0-9A-

// addDepfileDeps inserts into the Context's importer list
// a set of importers for entries in the depfile.
func addDepfileDeps(bc *build.Context, ctx *Context) (Importer, error) {
i := Importer(new(nullImporter))
func addDepfileDeps(bc *build.Context, ctx *Context) (func(string) (*build.Package, error), error) {
i := nullImporter()
df, err := readDepfile(ctx)
if err != nil {
if !os.IsNotExist(errors.Cause(err)) {
Expand Down Expand Up @@ -55,13 +55,7 @@ func addDepfileDeps(bc *build.Context, ctx *Context) (Importer, error) {
return nil, err
}
}
i = &_importer{
Importer: i,
im: importer{
Context: bc,
Root: root,
},
}
i = childFirstImporter(i, dirImporter(bc, root))
debug.Debugf("Add importer for %q: %v", prefix+" "+version, root)
}

Expand All @@ -82,13 +76,7 @@ func addDepfileDeps(bc *build.Context, ctx *Context) (Importer, error) {
return nil, err
}
}
i = &_importer{
Importer: i,
im: importer{
Context: bc,
Root: root,
},
}
i = childFirstImporter(i, dirImporter(bc, root))
debug.Debugf("Add importer for %q: %v", prefix+" "+tag, root)
}
}
Expand Down
159 changes: 74 additions & 85 deletions resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,66 +12,53 @@ import (
"github.com/pkg/errors"
)

type nullImporter struct{}

func (i *nullImporter) Import(path string) (*build.Package, error) {
return nil, errors.Errorf("import %q not found", path)
}

type srcImporter struct {
Importer
im importer
func nullImporter() func(string) (*build.Package, error) {
return func(path string) (*build.Package, error) {
return nil, errors.Errorf("import %q not found", path)
}
}

func (i *srcImporter) Import(path string) (*build.Package, error) {
pkg, err := i.im.Import(path)
if err == nil {
return pkg, nil
}
func srcImporter(parent, child func(string) (*build.Package, error)) func(string) (*build.Package, error) {
return func(path string) (*build.Package, error) {
pkg, err := child(path)
if err == nil {
return pkg, nil
}

// gb expects, when there is a failure to resolve packages that
// live in $PROJECT/src that the importer for that directory
// will report them.
// gb expects, when there is a failure to resolve packages that
// live in $PROJECT/src that the importer for that directory
// will report them.

pkg, err2 := i.Importer.Import(path)
if err2 == nil {
return pkg, nil
pkg, err2 := parent(path)
if err2 == nil {
return pkg, nil
}
return nil, err
}
return nil, err
}

type _importer struct {
Importer
im importer
}

func (i *_importer) Import(path string) (*build.Package, error) {
pkg, err := i.im.Import(path)
if err != nil {
return i.Importer.Import(path)
func childFirstImporter(parent, child func(string) (*build.Package, error)) func(string) (*build.Package, error) {
return func(path string) (*build.Package, error) {
pkg, err := child(path)
if err != nil {
return parent(path)
}
return pkg, nil
}
return pkg, nil
}

type fixupImporter struct {
Importer
}

func (i *fixupImporter) Import(path string) (*build.Package, error) {
pkg, err := i.Importer.Import(path)
switch err.(type) {
case *os.PathError:
return nil, errors.Wrapf(err, "import %q: not found", path)
default:
return pkg, err
func fixupImporter(importer func(string) (*build.Package, error)) func(string) (*build.Package, error) {
return func(path string) (*build.Package, error) {
pkg, err := importer(path)
switch err.(type) {
case *os.PathError:
return nil, errors.Wrapf(err, "import %q: not found", path)
default:
return pkg, err
}
}
}

type importer struct {
*build.Context
Root string // root directory
}

type importErr struct {
path string
msg string
Expand All @@ -81,51 +68,53 @@ func (e *importErr) Error() string {
return fmt.Sprintf("import %q: %v", e.path, e.msg)
}

func (i *importer) Import(path string) (*build.Package, error) {
if path == "" {
return nil, errors.WithStack(&importErr{path: path, msg: "invalid import path"})
}
func dirImporter(ctx *build.Context, dir string) func(string) (*build.Package, error) {
return func(path string) (*build.Package, error) {
if path == "" {
return nil, errors.WithStack(&importErr{path: path, msg: "invalid import path"})
}

if path == "." || path == ".." || strings.HasPrefix(path, "./") || strings.HasPrefix(path, "../") {
return nil, errors.WithStack(&importErr{path: path, msg: "relative import not supported"})
}
if path == "." || path == ".." || strings.HasPrefix(path, "./") || strings.HasPrefix(path, "../") {
return nil, errors.WithStack(&importErr{path: path, msg: "relative import not supported"})
}

if strings.HasPrefix(path, "/") {
return nil, errors.WithStack(&importErr{path: path, msg: "cannot import absolute path"})
}
if strings.HasPrefix(path, "/") {
return nil, errors.WithStack(&importErr{path: path, msg: "cannot import absolute path"})
}

var p *build.Package
var p *build.Package

loadPackage := func(importpath, dir string) error {
pkg, err := i.ImportDir(dir, 0)
if err != nil {
return err
loadPackage := func(importpath, dir string) error {
pkg, err := ctx.ImportDir(dir, 0)
if err != nil {
return err
}
p = pkg
p.ImportPath = importpath
return nil
}
p = pkg
p.ImportPath = importpath
return nil
}

// if this is the stdlib, then search vendor first.
// this isn't real vendor support, just enough to make net/http compile.
if i.Root == runtime.GOROOT() {
path := pathpkg.Join("vendor", path)
dir := filepath.Join(i.Root, "src", filepath.FromSlash(path))
fi, err := os.Stat(dir)
if err == nil && fi.IsDir() {
err := loadPackage(path, dir)
return p, err
// if this is the stdlib, then search vendor first.
// this isn't real vendor support, just enough to make net/http compile.
if dir == runtime.GOROOT() {
path := pathpkg.Join("vendor", path)
dir := filepath.Join(dir, "src", filepath.FromSlash(path))
fi, err := os.Stat(dir)
if err == nil && fi.IsDir() {
err := loadPackage(path, dir)
return p, err
}
}
}

dir := filepath.Join(i.Root, "src", filepath.FromSlash(path))
fi, err := os.Stat(dir)
if err != nil {
return nil, err
}
if !fi.IsDir() {
return nil, errors.Errorf("import %q: not a directory", path)
dir := filepath.Join(dir, "src", filepath.FromSlash(path))
fi, err := os.Stat(dir)
if err != nil {
return nil, err
}
if !fi.IsDir() {
return nil, errors.Errorf("import %q: not a directory", path)
}
err = loadPackage(path, dir)
return p, err
}
err = loadPackage(path, dir)
return p, err
}