func (ctx *Context) getFileTags(pathname string, f *ast.File) ([]string, error) { _, filenameExt := filepath.Split(pathname) if strings.HasSuffix(pathname, ".go") == false { return nil, nil } var err error if f == nil { f, err = parser.ParseFile(token.NewFileSet(), pathname, nil, parser.ImportsOnly|parser.ParseComments) if err != nil { return nil, err } } filename := filenameExt[:len(filenameExt)-3] l := strings.Split(filename, "_") tags := make([]string, 0) if n := len(l); n > 0 && 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, ",")...) } } } } return tags, nil }
// addFileImports is called from loadPackage and resolveUnknown. func (ctx *Context) addFileImports(pathname, gopath string) error { dir, filenameExt := filepath.Split(pathname) importPath := pathos.FileTrimPrefix(dir, gopath) importPath = pathos.SlashToImportPath(importPath) importPath = strings.TrimPrefix(importPath, "/") importPath = strings.TrimSuffix(importPath, "/") if strings.HasSuffix(pathname, ".go") == false { return nil } // No need to add the same file more then once. 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 } } for _, f := range pkg.ignoreFile { if pathos.FileStringEquals(f, filenameExt) { return nil } } } f, err := parser.ParseFile(token.NewFileSet(), pathname, nil, parser.ImportsOnly|parser.ParseComments) if err != nil { return err } tags, err := ctx.getFileTags(pathname, f) if err != nil { return err } pkg, found := ctx.Package[importPath] if !found { status := StatusUnknown if f.Name.Name == "main" { status = StatusProgram } pkg = ctx.setPackage(dir, importPath, importPath, gopath, status) ctx.Package[importPath] = pkg } if pkg.Status != StatusLocal && pkg.Status != StatusProgram { for _, tag := range tags { for _, ignore := range ctx.ignoreTag { if tag == ignore { pkg.ignoreFile = append(pkg.ignoreFile, filenameExt) return nil } } } } 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 { return err } if strings.HasPrefix(imp, "./") { imp = path.Join(importPath, imp) } pf.Imports[i] = imp err = ctx.addSingleImport(pkg.Dir, imp) if err != nil { return err } } // Record any import comment for file. var ic *ast.Comment if f.Name != nil { pos := f.Name.Pos() big: // Find the next comment after the package name. for _, cblock := range f.Comments { for _, c := range cblock.List { if c.Pos() > pos { ic = c break big } } } } if ic != nil { // If it starts with the import text, assume it is the import comment and remove. 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 nil }