github.com/jd-ly/cmd@v1.0.10/parser/imports.go (about)

     1  package parser
     2  
     3  import (
     4  	"github.com/jd-ly/cmd/utils"
     5  	"go/ast"
     6  	"go/build"
     7  	"go/token"
     8  	"path/filepath"
     9  	"strings"
    10  )
    11  
    12  // Add imports to the map from the source dir
    13  func addImports(imports map[string]string, decl ast.Decl, srcDir string) {
    14  	genDecl, ok := decl.(*ast.GenDecl)
    15  	if !ok {
    16  		return
    17  	}
    18  
    19  	if genDecl.Tok != token.IMPORT {
    20  		return
    21  	}
    22  
    23  	for _, spec := range genDecl.Specs {
    24  		importSpec := spec.(*ast.ImportSpec)
    25  		var pkgAlias string
    26  		if importSpec.Name != nil {
    27  			pkgAlias = importSpec.Name.Name
    28  			if pkgAlias == "_" {
    29  				continue
    30  			}
    31  		}
    32  		quotedPath := importSpec.Path.Value // e.g. "\"sample/app/models\""
    33  		if quotedPath == `"C"` {
    34  			continue
    35  		}
    36  		fullPath := quotedPath[1 : len(quotedPath)-1] // Remove the quotes
    37  
    38  		// If the package was not aliased (common case), we have to import it
    39  		// to see what the package name is.
    40  		// TODO: Can improve performance here a lot:
    41  		// 1. Do not import everything over and over again.  Keep a cache.
    42  		// 2. Exempt the standard library; their directories always match the package name.
    43  		// 3. Can use build.FindOnly and then use parser.ParseDir with mode PackageClauseOnly
    44  		if pkgAlias == "" {
    45  
    46  			utils.Logger.Debug("Reading from build", "path", fullPath, "srcPath", srcDir, "gopath", build.Default.GOPATH)
    47  			pkg, err := build.Import(fullPath, srcDir, 0)
    48  			if err != nil {
    49  				// We expect this to happen for apps using reverse routing (since we
    50  				// have not yet generated the routes).  Don't log that.
    51  				if !strings.HasSuffix(fullPath, "/app/routes") {
    52  					utils.Logger.Warn("Could not find import:", "path", fullPath, "srcPath", srcDir, "error", err)
    53  				}
    54  				continue
    55  			} else {
    56  				utils.Logger.Debug("Found package in dir", "dir", pkg.Dir, "name", pkg.ImportPath)
    57  			}
    58  			pkgAlias = pkg.Name
    59  		}
    60  
    61  		imports[pkgAlias] = fullPath
    62  	}
    63  }
    64  
    65  // Returns a valid import string from the path
    66  // using the build.Defaul.GOPATH to determine the root
    67  func importPathFromPath(root, basePath string) string {
    68  	vendorTest := filepath.Join(basePath, "vendor")
    69  	if len(root) > len(vendorTest) && root[:len(vendorTest)] == vendorTest {
    70  		return filepath.ToSlash(root[len(vendorTest)+1:])
    71  	}
    72  	for _, gopath := range filepath.SplitList(build.Default.GOPATH) {
    73  		srcPath := filepath.Join(gopath, "src")
    74  		if strings.HasPrefix(root, srcPath) {
    75  			return filepath.ToSlash(root[len(srcPath)+1:])
    76  		}
    77  	}
    78  
    79  	srcPath := filepath.Join(build.Default.GOROOT, "src", "pkg")
    80  	if strings.HasPrefix(root, srcPath) {
    81  		utils.Logger.Warn("Code path should be in GOPATH, but is in GOROOT:", "path", root)
    82  		return filepath.ToSlash(root[len(srcPath)+1:])
    83  	}
    84  
    85  	utils.Logger.Error("Unexpected! Code path is not in GOPATH:", "path", root)
    86  	return ""
    87  }