github.com/llvm-mirror/llgo@v0.0.0-20190322182713-bf6f0a60fce1/third_party/gotools/go/buildutil/util.go (about) 1 // Copyright 2014 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package buildutil 6 7 import ( 8 "fmt" 9 "go/ast" 10 "go/build" 11 "go/parser" 12 "go/token" 13 "io" 14 "io/ioutil" 15 "os" 16 "path" 17 "path/filepath" 18 "strings" 19 ) 20 21 // ParseFile behaves like parser.ParseFile, 22 // but uses the build context's file system interface, if any. 23 // 24 // If file is not absolute (as defined by IsAbsPath), the (dir, file) 25 // components are joined using JoinPath; dir must be absolute. 26 // 27 // The displayPath function, if provided, is used to transform the 28 // filename that will be attached to the ASTs. 29 // 30 // TODO(adonovan): call this from go/loader.parseFiles when the tree thaws. 31 // 32 func ParseFile(fset *token.FileSet, ctxt *build.Context, displayPath func(string) string, dir string, file string, mode parser.Mode) (*ast.File, error) { 33 if !IsAbsPath(ctxt, file) { 34 file = JoinPath(ctxt, dir, file) 35 } 36 rd, err := OpenFile(ctxt, file) 37 if err != nil { 38 return nil, err 39 } 40 defer rd.Close() // ignore error 41 if displayPath != nil { 42 file = displayPath(file) 43 } 44 return parser.ParseFile(fset, file, rd, mode) 45 } 46 47 // ContainingPackage returns the package containing filename. 48 // 49 // If filename is not absolute, it is interpreted relative to working directory dir. 50 // All I/O is via the build context's file system interface, if any. 51 // 52 // The '...Files []string' fields of the resulting build.Package are not 53 // populated (build.FindOnly mode). 54 // 55 // TODO(adonovan): call this from oracle when the tree thaws. 56 // 57 func ContainingPackage(ctxt *build.Context, dir, filename string) (*build.Package, error) { 58 if !IsAbsPath(ctxt, filename) { 59 filename = JoinPath(ctxt, dir, filename) 60 } 61 62 // We must not assume the file tree uses 63 // "/" always, 64 // `\` always, 65 // or os.PathSeparator (which varies by platform), 66 // but to make any progress, we are forced to assume that 67 // paths will not use `\` unless the PathSeparator 68 // is also `\`, thus we can rely on filepath.ToSlash for some sanity. 69 70 dirSlash := path.Dir(filepath.ToSlash(filename)) + "/" 71 72 // We assume that no source root (GOPATH[i] or GOROOT) contains any other. 73 for _, srcdir := range ctxt.SrcDirs() { 74 srcdirSlash := filepath.ToSlash(srcdir) + "/" 75 if strings.HasPrefix(dirSlash, srcdirSlash) { 76 importPath := dirSlash[len(srcdirSlash) : len(dirSlash)-len("/")] 77 return ctxt.Import(importPath, dir, build.FindOnly) 78 } 79 } 80 81 return nil, fmt.Errorf("can't find package containing %s", filename) 82 } 83 84 // -- Effective methods of file system interface ------------------------- 85 86 // (go/build.Context defines these as methods, but does not export them.) 87 88 // TODO(adonovan): HasSubdir? 89 90 // FileExists returns true if the specified file exists, 91 // using the build context's file system interface. 92 func FileExists(ctxt *build.Context, path string) bool { 93 if ctxt.OpenFile != nil { 94 r, err := ctxt.OpenFile(path) 95 if err != nil { 96 return false 97 } 98 r.Close() // ignore error 99 return true 100 } 101 _, err := os.Stat(path) 102 return err == nil 103 } 104 105 // OpenFile behaves like os.Open, 106 // but uses the build context's file system interface, if any. 107 func OpenFile(ctxt *build.Context, path string) (io.ReadCloser, error) { 108 if ctxt.OpenFile != nil { 109 return ctxt.OpenFile(path) 110 } 111 return os.Open(path) 112 } 113 114 // IsAbsPath behaves like filepath.IsAbs, 115 // but uses the build context's file system interface, if any. 116 func IsAbsPath(ctxt *build.Context, path string) bool { 117 if ctxt.IsAbsPath != nil { 118 return ctxt.IsAbsPath(path) 119 } 120 return filepath.IsAbs(path) 121 } 122 123 // JoinPath behaves like filepath.Join, 124 // but uses the build context's file system interface, if any. 125 func JoinPath(ctxt *build.Context, path ...string) string { 126 if ctxt.JoinPath != nil { 127 return ctxt.JoinPath(path...) 128 } 129 return filepath.Join(path...) 130 } 131 132 // IsDir behaves like os.Stat plus IsDir, 133 // but uses the build context's file system interface, if any. 134 func IsDir(ctxt *build.Context, path string) bool { 135 if ctxt.IsDir != nil { 136 return ctxt.IsDir(path) 137 } 138 fi, err := os.Stat(path) 139 return err == nil && fi.IsDir() 140 } 141 142 // ReadDir behaves like ioutil.ReadDir, 143 // but uses the build context's file system interface, if any. 144 func ReadDir(ctxt *build.Context, path string) ([]os.FileInfo, error) { 145 if ctxt.ReadDir != nil { 146 return ctxt.ReadDir(path) 147 } 148 return ioutil.ReadDir(path) 149 } 150 151 // SplitPathList behaves like filepath.SplitList, 152 // but uses the build context's file system interface, if any. 153 func SplitPathList(ctxt *build.Context, s string) []string { 154 if ctxt.SplitPathList != nil { 155 return ctxt.SplitPathList(s) 156 } 157 return filepath.SplitList(s) 158 }