...

Source file src/github.com/mailru/easyjson/parser/pkgpath.go

Documentation: github.com/mailru/easyjson/parser

     1  package parser
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"go/build"
     7  	"io/ioutil"
     8  	"os"
     9  	"os/exec"
    10  	"path"
    11  	"path/filepath"
    12  	"strings"
    13  	"sync"
    14  )
    15  
    16  func getPkgPath(fname string, isDir bool) (string, error) {
    17  	if !filepath.IsAbs(fname) {
    18  		pwd, err := os.Getwd()
    19  		if err != nil {
    20  			return "", err
    21  		}
    22  		fname = filepath.Join(pwd, fname)
    23  	}
    24  
    25  	goModPath, _ := goModPath(fname, isDir)
    26  	if strings.Contains(goModPath, "go.mod") {
    27  		pkgPath, err := getPkgPathFromGoMod(fname, isDir, goModPath)
    28  		if err != nil {
    29  			return "", err
    30  		}
    31  
    32  		return pkgPath, nil
    33  	}
    34  
    35  	return getPkgPathFromGOPATH(fname, isDir)
    36  }
    37  
    38  var goModPathCache = struct {
    39  	paths map[string]string
    40  	sync.RWMutex
    41  }{
    42  	paths: make(map[string]string),
    43  }
    44  
    45  // empty if no go.mod, GO111MODULE=off or go without go modules support
    46  func goModPath(fname string, isDir bool) (string, error) {
    47  	root := fname
    48  	if !isDir {
    49  		root = filepath.Dir(fname)
    50  	}
    51  
    52  	goModPathCache.RLock()
    53  	goModPath, ok := goModPathCache.paths[root]
    54  	goModPathCache.RUnlock()
    55  	if ok {
    56  		return goModPath, nil
    57  	}
    58  
    59  	defer func() {
    60  		goModPathCache.Lock()
    61  		goModPathCache.paths[root] = goModPath
    62  		goModPathCache.Unlock()
    63  	}()
    64  
    65  	cmd := exec.Command("go", "env", "GOMOD")
    66  	cmd.Dir = root
    67  
    68  	stdout, err := cmd.Output()
    69  	if err != nil {
    70  		return "", err
    71  	}
    72  
    73  	goModPath = string(bytes.TrimSpace(stdout))
    74  
    75  	return goModPath, nil
    76  }
    77  
    78  func getPkgPathFromGoMod(fname string, isDir bool, goModPath string) (string, error) {
    79  	modulePath := getModulePath(goModPath)
    80  	if modulePath == "" {
    81  		return "", fmt.Errorf("cannot determine module path from %s", goModPath)
    82  	}
    83  
    84  	rel := path.Join(modulePath, filePathToPackagePath(strings.TrimPrefix(fname, filepath.Dir(goModPath))))
    85  
    86  	if !isDir {
    87  		return path.Dir(rel), nil
    88  	}
    89  
    90  	return path.Clean(rel), nil
    91  }
    92  
    93  var pkgPathFromGoModCache = struct {
    94  	paths map[string]string
    95  	sync.RWMutex
    96  }{
    97  	paths: make(map[string]string),
    98  }
    99  
   100  func getModulePath(goModPath string) string {
   101  	pkgPathFromGoModCache.RLock()
   102  	pkgPath, ok := pkgPathFromGoModCache.paths[goModPath]
   103  	pkgPathFromGoModCache.RUnlock()
   104  	if ok {
   105  		return pkgPath
   106  	}
   107  
   108  	defer func() {
   109  		pkgPathFromGoModCache.Lock()
   110  		pkgPathFromGoModCache.paths[goModPath] = pkgPath
   111  		pkgPathFromGoModCache.Unlock()
   112  	}()
   113  
   114  	data, err := ioutil.ReadFile(goModPath)
   115  	if err != nil {
   116  		return ""
   117  	}
   118  	pkgPath = modulePath(data)
   119  	return pkgPath
   120  }
   121  
   122  func getPkgPathFromGOPATH(fname string, isDir bool) (string, error) {
   123  	gopath := os.Getenv("GOPATH")
   124  	if gopath == "" {
   125  		gopath = build.Default.GOPATH
   126  	}
   127  
   128  	for _, p := range strings.Split(gopath, string(filepath.ListSeparator)) {
   129  		prefix := filepath.Join(p, "src") + string(filepath.Separator)
   130  		rel, err := filepath.Rel(prefix, fname)
   131  		if err == nil && !strings.HasPrefix(rel, ".."+string(filepath.Separator)) {
   132  			if !isDir {
   133  				return path.Dir(filePathToPackagePath(rel)), nil
   134  			} else {
   135  				return path.Clean(filePathToPackagePath(rel)), nil
   136  			}
   137  		}
   138  	}
   139  
   140  	return "", fmt.Errorf("file '%v' is not in GOPATH '%v'", fname, gopath)
   141  }
   142  
   143  func filePathToPackagePath(path string) string {
   144  	return filepath.ToSlash(path)
   145  }
   146  

View as plain text