github.com/kekek/gb@v0.4.5-0.20170222120241-d4ba64b0b297/resolver.go (about)

     1  package gb
     2  
     3  import (
     4  	"fmt"
     5  	"go/build"
     6  	"os"
     7  	pathpkg "path"
     8  	"path/filepath"
     9  	"runtime"
    10  	"strings"
    11  
    12  	"github.com/pkg/errors"
    13  )
    14  
    15  type nullImporter struct{}
    16  
    17  func (i *nullImporter) Import(path string) (*build.Package, error) {
    18  	return nil, errors.Errorf("import %q not found", path)
    19  }
    20  
    21  type srcImporter struct {
    22  	Importer
    23  	im importer
    24  }
    25  
    26  func (i *srcImporter) Import(path string) (*build.Package, error) {
    27  	pkg, err := i.im.Import(path)
    28  	if err == nil {
    29  		return pkg, nil
    30  	}
    31  
    32  	// gb expects, when there is a failure to resolve packages that
    33  	// live in $PROJECT/src that the importer for that directory
    34  	// will report them.
    35  
    36  	pkg, err2 := i.Importer.Import(path)
    37  	if err2 == nil {
    38  		return pkg, nil
    39  	}
    40  	return nil, err
    41  }
    42  
    43  type _importer struct {
    44  	Importer
    45  	im importer
    46  }
    47  
    48  func (i *_importer) Import(path string) (*build.Package, error) {
    49  	pkg, err := i.im.Import(path)
    50  	if err != nil {
    51  		return i.Importer.Import(path)
    52  	}
    53  	return pkg, nil
    54  }
    55  
    56  type fixupImporter struct {
    57  	Importer
    58  }
    59  
    60  func (i *fixupImporter) Import(path string) (*build.Package, error) {
    61  	pkg, err := i.Importer.Import(path)
    62  	switch err.(type) {
    63  	case *os.PathError:
    64  		return nil, errors.Wrapf(err, "import %q: not found", path)
    65  	default:
    66  		return pkg, err
    67  	}
    68  }
    69  
    70  type importer struct {
    71  	*build.Context
    72  	Root string // root directory
    73  }
    74  
    75  type importErr struct {
    76  	path string
    77  	msg  string
    78  }
    79  
    80  func (e *importErr) Error() string {
    81  	return fmt.Sprintf("import %q: %v", e.path, e.msg)
    82  }
    83  
    84  func (i *importer) Import(path string) (*build.Package, error) {
    85  	if path == "" {
    86  		return nil, errors.WithStack(&importErr{path: path, msg: "invalid import path"})
    87  	}
    88  
    89  	if path == "." || path == ".." || strings.HasPrefix(path, "./") || strings.HasPrefix(path, "../") {
    90  		return nil, errors.WithStack(&importErr{path: path, msg: "relative import not supported"})
    91  	}
    92  
    93  	if strings.HasPrefix(path, "/") {
    94  		return nil, errors.WithStack(&importErr{path: path, msg: "cannot import absolute path"})
    95  	}
    96  
    97  	var p *build.Package
    98  
    99  	loadPackage := func(importpath, dir string) error {
   100  		pkg, err := i.ImportDir(dir, 0)
   101  		if err != nil {
   102  			return err
   103  		}
   104  		p = pkg
   105  		p.ImportPath = importpath
   106  		return nil
   107  	}
   108  
   109  	// if this is the stdlib, then search vendor first.
   110  	// this isn't real vendor support, just enough to make net/http compile.
   111  	if i.Root == runtime.GOROOT() {
   112  		path := pathpkg.Join("vendor", path)
   113  		dir := filepath.Join(i.Root, "src", filepath.FromSlash(path))
   114  		fi, err := os.Stat(dir)
   115  		if err == nil && fi.IsDir() {
   116  			err := loadPackage(path, dir)
   117  			return p, err
   118  		}
   119  	}
   120  
   121  	dir := filepath.Join(i.Root, "src", filepath.FromSlash(path))
   122  	fi, err := os.Stat(dir)
   123  	if err != nil {
   124  		return nil, err
   125  	}
   126  	if !fi.IsDir() {
   127  		return nil, errors.Errorf("import %q: not a directory", path)
   128  	}
   129  	err = loadPackage(path, dir)
   130  	return p, err
   131  }