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 }