func (ctx *Context) addFileImports(pathname, gopath string) (*Package, error) {
	dir, filenameExt := filepath.Split(pathname)
	importPath := pathos.FileTrimPrefix(dir, gopath)
	importPath = pathos.SlashToImportPath(importPath)
	importPath = strings.Trim(importPath, "/")
	if strings.HasSuffix(pathname, ".go") == false {
		return nil, nil
	}
	for _, pkg := range ctx.Package {
		if pathos.FileStringEquals(pkg.Dir, dir) == false {
			continue
		}
		for _, f := range pkg.Files {
			if pathos.FileStringEquals(f.Path, pathname) {
				return nil, nil
			}
		}
		for _, f := range pkg.ignoreFile {
			if pathos.FileStringEquals(f, filenameExt) {
				return nil, nil
			}
		}
	}
	f, _ := parser.ParseFile(token.NewFileSet(), pathname, nil, parser.ImportsOnly|parser.ParseComments)
	if f == nil {
		return nil, nil
	}
	pkgNameNormalized := strings.TrimSuffix(f.Name.Name, "_test")
	if pkgNameNormalized == "documentation" {
		return nil, nil
	}
	tags, _, err := ctx.getFileTags(pathname, f)
	if err != nil {
		return nil, err
	}
	isIgnore := false
	for _, tag := range tags {
		if tag == "ignore" {
			isIgnore = true
		}
	}
	if isIgnore {
		return nil, nil
	}
	pkg, found := ctx.Package[importPath]
	if !found {
		status := Status{
			Type:     TypePackage,
			Location: LocationUnknown,
			Presence: PresenceFound,
		}
		if pkgNameNormalized == "main" {
			status.Type = TypeProgram
		}
		pkg = ctx.setPackage(dir, importPath, importPath, gopath, status)
		ctx.Package[importPath] = pkg
	}
	if pkg.Status.Location != LocationLocal {
		for _, tag := range tags {
			for _, ignore := range ctx.ignoreTag {
				if tag == ignore {
					pkg.ignoreFile = append(pkg.ignoreFile, filenameExt)
					return pkg, nil
				}
			}
		}
		for _, exclude := range ctx.excludePackage {
			if importPath == exclude || strings.HasPrefix(importPath, exclude+"/") {
				pkg.Status.Presence = PresenceExcluded
			}
		}
	}
	pf := &File{
		Package: pkg,
		Path:    pathname,
		Imports: make([]string, len(f.Imports)),
	}
	pkg.Files = append(pkg.Files, pf)
	for i := range f.Imports {
		imp := f.Imports[i].Path.Value
		imp, err = strconv.Unquote(imp)
		if err != nil {
			continue
		}
		if strings.HasPrefix(imp, "./") {
			imp = path.Join(importPath, imp)
		}
		pf.Imports[i] = imp
		if pkg.Status.Presence != PresenceExcluded {  
			_, err = ctx.addSingleImport(pkg.Dir, imp, pkg.IncludeTree)
			if err != nil {
				return pkg, err
			}
		}
	}
	var ic *ast.Comment
	if f.Name != nil {
		pos := f.Name.Pos()
	big:
		for _, cblock := range f.Comments {
			for _, c := range cblock.List {
				if c.Pos() > pos {
					ic = c
					break big
				}
			}
		}
	}
	if ic != nil {
		if index := strings.Index(ic.Text, " import "); index > 0 && index < 5 {
			q := strings.TrimSpace(ic.Text[index+len(" import "):])
			pf.ImportComment, err = strconv.Unquote(q)
			if err != nil {
				pf.ImportComment = q
			}
		}
	}
	return pkg, nil
}
addFileImports is called from loadPackage and resolveUnknown.
package context
import (
	"go/ast"
	"go/parser"
	"go/token"
	"path"
	"sort"
	"strconv"
	"strings"
	"github.com/kardianos/govendor/internal/pathos"
	filepath "github.com/kardianos/govendor/internal/vfilepath"
	os "github.com/kardianos/govendor/internal/vos"
	"github.com/kardianos/govendor/pkgspec"
)
var knownOS = make(map[string]bool)
var knownArch = make(map[string]bool)
func init() {
	for _, v := range strings.Fields(goosList) {
		knownOS[v] = true
	}
	for _, v := range strings.Fields(goarchList) {
		knownArch[v] = true
	}
}
func (ctx *Context) loadPackage() error {
	ctx.loaded = true
	ctx.dirty = false
	ctx.statusCache = nil
	ctx.Package = make(map[string]*Package, len(ctx.Package))
	rootdir, err := filepath.EvalSymlinks(ctx.RootDir)
	if err != nil {
		return err
	}
	err = filepath.Walk(rootdir, func(path string, info os.FileInfo, err error) error {
		if info == nil {
			return err
		}
		if !info.IsDir() {
			path = strings.Replace(path, rootdir, ctx.RootDir, 1)
			_, err = ctx.addFileImports(path, ctx.RootGopath)
			return err
		}
		name := info.Name()
		if name == "_workspace" {
			return nil
		}
		switch name[0] {
		case '.', '_':
			return filepath.SkipDir
		}
		switch name {
		case "testdata", "node_modules":
			return filepath.SkipDir
		}
		return nil
	})
	if err != nil {
		return err
	}
	return ctx.determinePackageStatus()
}
func (ctx *Context) getFileTags(pathname string, f *ast.File) (tags, imports []string, err error) {
	_, filenameExt := filepath.Split(pathname)
	if strings.HasSuffix(pathname, ".go") == false {
		return nil, nil, nil
	}
	if f == nil {
		f, err = parser.ParseFile(token.NewFileSet(), pathname, nil, parser.ImportsOnly|parser.ParseComments)
		if f == nil {
			return nil, nil, nil
		}
	}
	tags = make([]string, 0, 6)
	if strings.HasSuffix(f.Name.Name, "_test") {
		tags = append(tags, "test")
	}
	pkgNameNormalized := strings.TrimSuffix(f.Name.Name, "_test")
	if pkgNameNormalized == "documentation" {
		return nil, nil, nil
	}
	filename := filenameExt[:len(filenameExt)-3]
	l := strings.Split(filename, "_")
	if n := len(l); n > 1 && l[n-1] == "test" {
		l = l[:n-1]
		tags = append(tags, "test")
	}
	n := len(l)
	if n >= 2 && knownOS[l[n-2]] && knownArch[l[n-1]] {
		tags = append(tags, l[n-2])
		tags = append(tags, l[n-1])
	}
	if n >= 1 && knownOS[l[n-1]] {
		tags = append(tags, l[n-1])
	}
	if n >= 1 && knownArch[l[n-1]] {
		tags = append(tags, l[n-1])
	}
	const buildPrefix = "// +build "
	for _, cc := range f.Comments {
		for _, c := range cc.List {
			if strings.HasPrefix(c.Text, buildPrefix) {
				text := strings.TrimPrefix(c.Text, buildPrefix)
				ss := strings.Fields(text)
				for _, s := range ss {
					tags = append(tags, strings.Split(s, ",")...)
				}
			}
		}
	}
	imports = make([]string, 0, len(f.Imports))
	for i := range f.Imports {
		imp := f.Imports[i].Path.Value
		imp, err = strconv.Unquote(imp)
		if err != nil {
			continue
		}
		imports = append(imports, imp)
	}
	return tags, imports, nil
}