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  }