LoginSignup
2

More than 5 years have passed since last update.

golang ソースコード -- import文のチェック内容 (1.8)

Last updated at Posted at 2017-03-13

goでimport文をチェックする実装はそんなに難しくないので。

実装内容を網羅していない。
主要な所をひっぱってきただけ。
実際はソースコードで。

ソースコード

importが空白の場合は残念

build.go
if path == "" {
        return p, fmt.Errorf("import %q: invalid import path", path)
    }

path変数はチェック対象のimport文で指定した文字列の1つ

ローカルインポート判定

build.go
// IsLocalImport reports whether the import path is
// a local import path, like ".", "..", "./foo", or "../foo".
func IsLocalImport(path string) bool {
    return path == "." || path == ".." ||
        strings.HasPrefix(path, "./") || strings.HasPrefix(path, "../")
}

ローカルインポート時は事前チェック無し

ここではエラーで止めていない。

とりあえず、実際に読み込んでみてエラーになったらダメというやり方。
(no such file or directoryエラー)

GOROOT、GOPATHの中になくてもOK

これより以下はローカルインポートでは無い場合

絶対パスは残念

build.go
if strings.HasPrefix(path, "/") {
    return p, fmt.Errorf("import %q: cannot import absolute path", path)
}

Vendorは GOROOT もしくは GOPATH の中

if searchVendor(ctxt.GOROOT, true) {
    goto Found
}
for _, root := range gopath {
    if searchVendor(root, false) {
        goto Found
    }
}

searchVendorの引数は
searchVendor := func(root string, isGoroot bool) bool {...}

import文で指定のモノがみつかったら goto Found

Vendorを確認するディレクトリかどうかのチェック

searchVendor := func(root string, isGoroot bool) bool {
    sub, ok := ctxt.hasSubdir(root, srcDir)
    if !ok || !strings.HasPrefix(sub, "src/") || strings.Contains(sub, "/testdata/") {
        return false
    }

この辺りはひっかかりそう。

GOROOTのsrc内を確認

if ctxt.GOROOT != "" {
    dir := ctxt.joinPath(ctxt.GOROOT, "src", path)
    isDir := ctxt.isDir(dir)
    binaryOnly = !isDir && mode&AllowBinary != 0 && pkga != "" && ctxt.isFile(ctxt.joinPath(ctxt.GOROOT, pkga))
    if isDir || binaryOnly {
        p.Dir = dir
        p.Goroot = true
        p.Root = ctxt.GOROOT
        goto Found
    }
    tried.goroot = dir
}

みつかったら goto Found
みつからなかったら tried.goroot 変数にいれとく(エラー表示用目的)

path変数はimportで書いた文字列

GOPATH のsrc内を確認

for _, root := range gopath {
    dir := ctxt.joinPath(root, "src", path)
    isDir := ctxt.isDir(dir)
    binaryOnly = !isDir && mode&AllowBinary != 0 && pkga != "" && ctxt.isFile(ctxt.joinPath(root, pkga))
    if isDir || binaryOnly {
        p.Dir = dir
        p.Root = root
        goto Found
    }
    tried.gopath = append(tried.gopath, dir)
}

gopathに設定したpathの数だけチェック

import文がどれにも合致しなかったら残念

build.go
return p, fmt.Errorf("cannot find package %q in any of:\n%s", path, strings.Join(paths, "\n"))

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2