Esempio n. 1
0
func rewriteSubcommand(args []string, opts *rewriteOptions) {
	st := new(rewriteState)
	if len(args) > 0 {
		for _, v := range args {
			if pkg, err := build.ImportDir(v, 0); err == nil {
				rewritePackage(pkg, st, opts)
				continue
			}
			pkg, err := build.Import(v, "", 0)
			if err != nil {
				log.Printf("error importing %s: %s", v, err)
				continue
			}
			rewritePackage(pkg, st, opts)
		}
	} else {
		abs, err := filepath.Abs(".")
		if err != nil {
			panic(err)
		}
		pkg, err := build.ImportDir(abs, 0)
		if err != nil {
			log.Fatalf("error importing %s: %s", abs, err)
		}
		rewritePackage(pkg, st, opts)
	}
}
Esempio n. 2
0
// loadPackage is like loadImport but is used for command-line arguments,
// not for paths found in import statements.  In addition to ordinary import paths,
// loadPackage accepts pseudo-paths beginning with cmd/ to denote commands
// in the Go command directory, as well as paths to those directories.
func loadPackage(arg string, stk *importStack) *Package {
	if build.IsLocalImport(arg) { // TODO Call to build.
		dir := arg
		if !filepath.IsAbs(dir) {
			if abs, err := filepath.Abs(dir); err == nil {
				// interpret relative to current directory
				dir = abs
			}
		}
		// Map gorootSrc to Odoo
		if sub, ok := hasSubdir(gorootSrc, dir); ok && strings.HasPrefix(sub, "cmd/") && !strings.Contains(sub[4:], "/") {
			arg = sub
		}
	}
	if strings.HasPrefix(arg, "cmd/") && !strings.Contains(arg[4:], "/") {
		if p := cmdCache[arg]; p != nil {
			return p
		}
		stk.push(arg)
		defer stk.pop()
		bp, err := build.ImportDir(filepath.Join(gorootSrc, arg), 0)
		bp.ImportPath = arg
		bp.Goroot = true
		bp.BinDir = gorootBin
		if gobin != "" {
			bp.BinDir = gobin
		}
		bp.Root = goroot
		bp.SrcRoot = gorootSrc
		p := new(Package)
		cmdCache[arg] = p
		p.load(stk, bp, err)
		if p.Error == nil && p.Name != "main" {
			p.Error = &PackageError{
				ImportStack: stk.copy(),
				Err:         fmt.Sprintf("expected package main but found package %s in %s", p.Name, p.Dir),
			}
		}
		return p
	}

	// Wasn't a command; must be a package.
	// If it is a local import path but names a standard package,
	// we treat it as if the user specified the standard package.
	// This lets you run go test ./ioutil in package io and be
	// referring to io/ioutil rather than a hypothetical import of
	// "./ioutil".
	if build.IsLocalImport(arg) {
		bp, _ := build.ImportDir(filepath.Join(cwd, arg), build.FindOnly)
		if bp.ImportPath != "" && bp.ImportPath != "." {
			arg = bp.ImportPath
		}
	}

	return loadImport(arg, cwd, stk, nil)
}
Esempio n. 3
0
// ImportDir gives a single instrumentable golang package. See Import.
func ImportDir(basepkg, pkgname string) (*Instrumentable, error) {
	pkg, err := build.ImportDir(pkgname, 0)
	if err != nil {
		return nil, err
	}
	return &Instrumentable{pkg, basepkg, pkgname}, nil
}
Esempio n. 4
0
func FindRepos(from string) ([]Dependency, error) {
	pkg, err := build.ImportDir(from, 0)
	if err != nil {
		return nil, fmt.Errorf("unable to load package at %s: %s", from, err)
	}

	imports := make(map[string]*build.Package)
	err = findAllImports(pkg, imports)
	if err != nil {
		return nil, err
	}
	delete(imports, pkg.Dir)

	repos := make(map[string]Dependency)
	for _, val := range imports {
		if !val.Goroot {
			repo, err := FindRepo(val)
			if err != nil {
				return nil, err
			}
			repos[repo.Root()] = repo
		}
	}

	rs := make([]Dependency, 0, 0)
	for _, val := range repos {
		rs = append(rs, val)
	}

	return rs, nil
}
Esempio n. 5
0
func loadExportsGoPath(dir string) map[string]bool {
	exports := make(map[string]bool)
	buildPkg, err := build.ImportDir(dir, 0)
	if err != nil {
		if strings.Contains(err.Error(), "no buildable Go source files in") {
			return nil
		}
		fmt.Fprintf(os.Stderr, "could not import %q: %v", dir, err)
		return nil
	}
	fset := token.NewFileSet()
	for _, file := range buildPkg.GoFiles {
		f, err := parser.ParseFile(fset, filepath.Join(dir, file), nil, 0)
		if err != nil {
			fmt.Fprintf(os.Stderr, "could not parse %q: %v", file, err)
			continue
		}
		for name := range f.Scope.Objects {
			if ast.IsExported(name) {
				exports[name] = true
			}
		}
	}
	return exports
}
Esempio n. 6
0
// DirToImport converts a directory path on the local machine to a
// Go import path (usually relative to the $GOPATH/src directory)
//
// For example,
//     /Users/user/workspace/Go/github.com/momchil-atanasov/gostub
// will be converted to
//     github.com/momchil-atanasov/gostub
// should GOPATH include the location
//     /Users/user/workspace/Go
func DirToImport(p string) (string, error) {
	pkg, err := build.ImportDir(p, build.FindOnly)
	if err != nil {
		return "", err
	}
	return pkg.ImportPath, nil
}
Esempio n. 7
0
func bakeCommand(_ *command.Args, opts *bakeOptions) error {
	extensions := []string{".html", ".css", ".js"}
	if opts.Dir == "" {
		return errors.New("dir can't be empty")
	}
	if opts.Name == "" {
		base := filepath.Base(opts.Dir)
		if opts.VFS {
			opts.Name = base + "FS"
		} else {
			opts.Name = base + "Data"
		}
	}
	if opts.Out == "" {
		opts.Out = filepath.Base(opts.Dir) + "_baked.go"
	}
	// go ignores files starting with _
	opts.Out = strings.TrimLeft(opts.Out, "_")
	extensions = append(extensions, strings.Split(opts.Extensions, ",")...)
	var buf bytes.Buffer
	odir := filepath.Dir(opts.Out)
	p, err := build.ImportDir(odir, 0)
	if err == nil {
		buf.WriteString(fmt.Sprintf("package %s\n", p.Name))
	}
	buf.WriteString(genutil.AutogenString())
	if err := writeBakedFSCode(&buf, opts, extensions); err != nil {
		return err
	}
	if err := genutil.WriteAutogen(opts.Out, buf.Bytes()); err != nil {
		return err
	}
	log.Debugf("Assets written to %s (%d bytes)", opts.Out, buf.Len())
	return nil
}
Esempio n. 8
0
func (self *Packager) ListenForever() {
	for {
		incoming := <-self.in
		packages := map[string]*Package{} // key: Folder path

		for file := range incoming {
			pkg, found := packages[file.ParentFolder]
			if !found {
				pkg = &Package{}
				var err error
				pkg.Info, err = build.ImportDir(file.ParentFolder, build.AllowBinary)
				if err != nil {
					// TODO: Need to handle this. It happens when a .go file is blank (and doesn't have a package declaration)...
					continue
				}
				packages[file.ParentFolder] = pkg
			}
			if file.IsModified && file.IsGoTestFile {
				pkg.IsModifiedTest = true
			} else if file.IsModified && !file.IsGoTestFile && file.IsGoFile {
				pkg.IsModifiedCode = true
			}
		}

		outgoing := make(chan *Package)
		self.out <- outgoing
		for _, pkg := range packages {
			outgoing <- pkg
		}
		close(outgoing)
	}
}
Esempio n. 9
0
func packageFromDir(t *testing.T, dir string) *build.Package {
	pkg, err := build.ImportDir(dir, build.ImportComment)
	if err != nil {
		t.Fatalf("build.ImportDir(%q, build.ImportComment) failed with %v; want success", dir, err)
	}
	return pkg
}
Esempio n. 10
0
// returns the package in dir either from a cache or by importing it and then caching it
func fullPackageInDir(dir string) (*build.Package, error) {
	var err error
	pkg, ok := pkgCache[dir]
	if !ok {
		pkg, err = build.ImportDir(dir, build.FindOnly)
		if pkg.Goroot {
			pkg, err = build.ImportDir(pkg.Dir, 0)
		} else {
			fillPackage(pkg)
		}
		if err == nil {
			pkgCache[dir] = pkg
		}
	}
	return pkg, err
}
Esempio n. 11
0
File: main.go Progetto: 0x7cc/rsc
func main() {
	flag.Parse()
	if build.Default.GOARCH == "amd64" {
		ptrKind = "Q"
		ptrSize = 8
		if *useInt64 {
			intSize = 8
			newIntSize = intSize
			intKind = "Q"
		}
		if *fixInt64 {
			newIntSize = 8
			*fixOffset = true
		}
	}
	args := flag.Args()
	if len(args) == 0 {
		p, err := build.ImportDir(".", 0)
		if err != nil {
			log.Fatal(err)
		}
		check(p)
	} else {
		for _, arg := range args {
			p, err := build.Import(arg, "", 0)
			if err != nil {
				log.Print(err)
				continue
			}
			check(p)
		}
	}
}
Esempio n. 12
0
// FindJujuCoreImports returns a sorted list of juju-core packages that are
// imported by the packageName parameter.  The resulting list removes the
// common prefix "launchpad.net/juju-core/" leaving just the short names.
func FindJujuCoreImports(c *gc.C, packageName string) []string {
	var imports []string

	for _, root := range build.Default.SrcDirs() {
		fullpath := filepath.Join(root, packageName)
		pkg, err := build.ImportDir(fullpath, 0)
		if err == nil {
			imports = pkg.Imports
			break
		}
	}
	if imports == nil {
		c.Fatalf(packageName + " not found")
	}

	var result []string
	const prefix = "launchpad.net/juju-core/"
	for _, name := range imports {
		if strings.HasPrefix(name, prefix) {
			result = append(result, name[len(prefix):])
		}
	}
	sort.Strings(result)
	return result
}
Esempio n. 13
0
// importDir is just an error-catching wrapper for build.ImportDir.
func importDir(dir string) *build.Package {
	pkg, err := build.ImportDir(dir, build.ImportComment)
	if err != nil {
		log.Fatal(err)
	}
	return pkg
}
Esempio n. 14
0
func dotPackage() (*build.Package, error) {
	dir, err := filepath.Abs(".")
	if err != nil {
		return nil, err
	}
	return build.ImportDir(dir, build.FindOnly)
}
Esempio n. 15
0
// ImportDir gives a single instrumentable golang package. See Import.
func ImportDir(basepkg, pkgname string) (*Instrumentable, error) {
	pkg, err := build.ImportDir(pkgname, 0)
	if err != nil {
		return nil, err
	}
	return &Instrumentable{pkg, basepkg, pkgname, false, make(map[string]bool)}, nil
}
Esempio n. 16
0
func Compile(filename string, translations []*po.Po, opts *CompileOptions) error {
	var buf bytes.Buffer
	dir := filepath.Dir(filename)
	p, err := build.ImportDir(dir, 0)
	if err == nil {
		fmt.Fprintf(&buf, "package %s\n", p.Name)
	}
	buf.WriteString("import \"gnd.la/i18n/table\"\n")
	buf.WriteString(genutil.AutogenString())
	buf.WriteString("func init() {\n")
	var defaultContext string
	if opts != nil {
		defaultContext = opts.DefaultContext
	}
	for _, v := range translations {
		table := poToTable(v, defaultContext)
		form, err := funcFromFormula(v.Attrs["Plural-Forms"])
		if err != nil {
			return err
		}
		data, err := table.Encode()
		if err != nil {
			return err
		}
		fmt.Fprintf(&buf, "table.Register(%q, func (n int) int {\n%s\n}, %q)\n", v.Attrs["Language"], form, data)
	}
	buf.WriteString("\n}\n")
	return genutil.WriteAutogen(filename, buf.Bytes())
}
Esempio n. 17
0
func generateTypes(input, constraint string) []byte {
	// Get working directory
	currentFolder, err := os.Getwd()
	if err != nil {
		log.Fatalf("Unable to obtain current working directory: %s", err)
	}
	// Read current package
	pkg, err := build.ImportDir(currentFolder, build.AllowBinary)
	if err != nil {
		log.Fatalf("Failed to determine go package inside directory '%s' - is your GOPATH set correctly ('%s')? Error: %s", currentFolder, os.Getenv("GOPATH"), err)
	}
	file, err := filepath.Abs(input)
	if err != nil {
		log.Fatalf("Hit error: %v", err)
	}
	job := jsonschema2go.Job{
		Package:           pkg.Name,
		ExportTypes:       true,
		HideStructMembers: false,
		URLs:              []string{"file://" + file},
		SkipCodeGen:       false,
	}
	result, err := job.Execute()
	if err != nil {
		log.Fatalf("Failed to generate source code: %v", err)
	}
	source := result.SourceCode
	if len(constraint) > 0 {
		source = append([]byte("// +build "+constraint+"\n"), result.SourceCode...)
	}
	return source
}
Esempio n. 18
0
func runGenerate(cmd *Command) {
	action := "updated"
	var err error
	var spec *Spec
	var pack *build.Package

	// read spec
	if _, err = os.Stat(SpecFileName); os.IsNotExist(err) {
		action = "generated"
		spec = new(Spec)
	} else {
		spec = ReadSpec()
	}

	// read package
	pack, err = build.ImportDir(".", 0)
	PanicIfErr(err)

	// add example author
	if len(spec.Authors) == 0 {
		spec.Authors = []Person{{FullName: ExampleFullName, Email: ExampleEmail}}
	}

	// some extra files
	if len(spec.ExtraFiles) == 0 {
		var globs []string
		for _, glob := range []string{"read*", "licen?e*", "copying*", "contrib*", "author*",
			"thank*", "news*", "change*", "install*", "bug*", "todo*"} {
			globs = append(globs, glob, strings.ToUpper(glob), strings.Title(glob))
		}

		for _, glob := range globs {
			files, err := filepath.Glob(glob)
			PanicIfErr(err)
			spec.ExtraFiles = append(spec.ExtraFiles, files...)
		}
	}

	// write spec
	f, err := os.OpenFile(SpecFileName, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, SpecFilePerm)
	PanicIfErr(err)
	defer f.Close()
	_, err = spec.WriteTo(f)
	PanicIfErr(err)

	if generateV {
		log.Printf("%s %s.", SpecFileName, action)
	}

	// check spec and package
	errors := spec.Check()
	errors = append(errors, CheckPackage(pack)...)
	if len(errors) != 0 {
		log.Print("\nYou should fix following issues:")
		for _, e := range errors {
			log.Printf("    %s", e)
		}
		log.Print("\nAfter that run 'nut check' to check spec again.")
	}
}
Esempio n. 19
0
// GetImports returns package denpendencies.
func GetImports(absPath, importPath string, example bool) []string {
	pkg, err := build.ImportDir(absPath, build.AllowBinary)
	if err != nil {
		if _, ok := err.(*build.NoGoError); !ok {
			log.Error("", "Fail to get imports")
			log.Fatal("", err.Error())
		}
	}

	fis := GetDirsInfo(absPath)
	absPath += "/"

	dirs := make([]string, 0)
	for _, fi := range fis {
		if fi.IsDir() && !strings.Contains(fi.Name(), VENDOR) {
			dirs = append(dirs, absPath+fi.Name())
		}
	}

	imports := make([]string, 0, len(pkg.Imports))
	for _, p := range pkg.Imports {
		if !IsGoRepoPath(p) && !strings.HasPrefix(p, importPath) {
			imports = append(imports, p)
		}
	}
	if len(dirs) > 0 {
		imports = append(imports, GetAllImports(dirs, importPath, example)...)
	}
	return imports
}
Esempio n. 20
0
func (l *parser) Parse(dir string) (taskSet *tasking.TaskSet, err error) {
	dir, err = expandDir(dir)
	if err != nil {
		return
	}

	p, e := build.ImportDir(dir, 0)
	taskFiles := append(p.GoFiles, p.IgnoredGoFiles...)
	taskFiles = append(taskFiles, p.CgoFiles...)
	if e != nil {
		// task files may be ignored for build
		if _, ok := e.(*build.NoGoError); !ok || len(taskFiles) == 0 {
			err = e
			return
		}
	}

	tasks, err := loadTasks(dir, taskFiles)
	if err != nil {
		return
	}

	taskSet = &tasking.TaskSet{Name: p.Name, Dir: p.Dir, ImportPath: p.ImportPath, Tasks: tasks}

	return
}
Esempio n. 21
0
File: ogo.go Progetto: droundy/ogo
func parseCommand(dir string) (*ast.File, *token.FileSet) {
	x, err := build.ImportDir(dir, 0)
	if err != nil {
		panic(err)
	}
	if !x.IsCommand() {
		fmt.Println("Use ogo on commands only!")
		os.Exit(1)
	}

	var fset token.FileSet
	packages := make(map[string](map[string]*ast.File))
	packages["main"] = make(map[string]*ast.File)
	for _, f := range x.GoFiles {
		parsedf, err := parseFile(&fset, dir, f)
		if err != nil {
			fmt.Println("error on file", f, err)
		} else {
			packages["main"][f] = parsedf
		}
	}
	_, err = importPath(packages, &fset, "main", dir)
	if err != nil {
		fmt.Println("Error importing stuff:", err)
	}
	return transform.TrackImports(packages), &fset
}
Esempio n. 22
0
// getImportPath takes a path like /home/csparr/go/src/github.com/sparrc/gdm
// and returns the import path, ie, github.com/sparrc/gdm
func getImportPath(fullpath string) string {
	p, err := build.ImportDir(fullpath, 0)
	if err != nil {
		return ""
	}
	return p.ImportPath
}
Esempio n. 23
0
func getPageInfo(pkgName, diskPath string) (pi PageInfo, err error) {
	bpkg, err := build.ImportDir(diskPath, 0)
	if err != nil {
		return
	}
	inSet := make(map[string]bool)
	for _, name := range bpkg.GoFiles {
		inSet[filepath.Base(name)] = true
	}

	pi.FSet = token.NewFileSet()
	filter := func(fi os.FileInfo) bool {
		return inSet[fi.Name()]
	}
	aPkgMap, err := parser.ParseDir(pi.FSet, diskPath, filter, 0)
	if err != nil {
		return
	}
	aPkg := aPkgMap[pathpkg.Base(pkgName)]
	if aPkg == nil {
		for _, v := range aPkgMap {
			aPkg = v
			break
		}
		if aPkg == nil {
			err = errors.New("no apkg found?")
			return
		}
	}

	pi.Dirname = diskPath
	pi.PDoc = doc.New(aPkg, pkgName, 0)
	pi.IsMain = strings.Contains(pkgName, "camlistore.org/cmd/")
	return
}
Esempio n. 24
0
func derivePackage() (file, pack string) {
	// Get file name by seeking caller's file name.
	_, callerFile, _, ok := runtime.Caller(1)
	if !ok {
		return
	}

	// Trim file name
	file = callerFile
	for _, dir := range build.Default.SrcDirs() {
		dir := dir + string(filepath.Separator)
		if trimmed := strings.TrimPrefix(callerFile, dir); len(trimmed) < len(file) {
			file = trimmed
		}
	}

	// Now derive package name
	dir := filepath.Dir(callerFile)

	dirPkg, err := build.ImportDir(dir, build.AllowBinary)
	if err != nil {
		return
	}

	pack = dirPkg.ImportPath
	return
}
Esempio n. 25
0
func walkDeps(base, myName string) []string {
	externalDeps := []string{}
	filepath.Walk(base, func(path string, fi os.FileInfo, err error) error {
		if excludeSubtree(path, fi) {
			if fi.IsDir() {
				return filepath.SkipDir
			}
			return nil
		}
		pkg, err := build.ImportDir(path, 0)
		if err != nil {
			return err
		}

		if pkg.Goroot {
			return nil
		}

		for _, imp := range pkg.Imports {
			//if strings.HasPrefix(imp, myName) {
			////Info("Skipping %s because it is a subpackage of %s", imp, myName)
			//continue
			//}
			if imp == myName {
				continue
			}
			externalDeps = append(externalDeps, imp)
		}

		return nil
	})
	return externalDeps
}
Esempio n. 26
0
func main() {
	flag.Usage = usage
	flag.Parse()

	if *listSystems {
		fmt.Print("  = Systems\n\n  ")
		fmt.Println(validSystems)
		os.Exit(0)
	}
	if len(os.Args) == 1 || *system == "" {
		usage()
	}

	log.SetFlags(0)
	log.SetPrefix("ERROR: ")

	var isSystem bool
	*system = strings.ToLower(*system)

	for _, v := range validSystems {
		if v == *system {
			isSystem = true
			break
		}
	}
	if !isSystem {
		log.Fatal("system passed in flag -s is invalid")
	}

	// Package name
	pkgName := "[NAME]"
	pkg, err := build.ImportDir(".", 0)
	if err == nil {
		pkgName = pkg.Name
	}

	// Update Go base
	cmd := strings.Join(os.Args, " ")
	goBase = strings.Replace(goBase, "{cmd}", cmd, 1)
	goBase = strings.Replace(goBase, "{pkg}", pkgName, 1)

	// Translate all headers passed in command line.
	for _, path := range flag.Args() {
		switch info, err := os.Stat(path); {
		case err != nil:
			log.Print(err)
			exitCode = 1
		case info.IsDir():
			walkDir(path)
		case info.Mode()&os.ModeType == 0: // regular file
			if err := processFile(path); err != nil {
				log.Print(err)
				exitCode = 1
			}
		}
	}

	os.Exit(exitCode)
}
Esempio n. 27
0
func readPackage(dir string) {
	p, err := build.ImportDir(dir, 0)
	if err != nil { // we go on and just ignore this directory
		log.Print(err)
		return
	}
	packages = append(packages, p)
}
Esempio n. 28
0
func (d Dependencies) addDepsForDep(dep string, depth int) {
	pkg, err := build.ImportDir(dep, 0)
	if err != nil {
		println(err.Error())
		return
	}
	d.resolveAndAdd(pkg.Imports, depth)
}
Esempio n. 29
0
func getDoc(dir string) (Doc, error) {
	bi, err := build.ImportDir(dir, 0)
	if err != nil {
		return Doc{}, nil
	}

	ip, err := importPath(dir)
	if err != nil {
		return Doc{}, err
	}

	filter := func(fi os.FileInfo) bool {
		if fi.IsDir() {
			return false
		}
		nm := fi.Name()
		for _, f := range append(bi.GoFiles, bi.CgoFiles...) {
			if nm == f {
				return true
			}
		}
		return false
	}

	pkgs, err := parser.ParseDir(token.NewFileSet(), bi.Dir, filter, parser.ParseComments)
	if err != nil {
		return Doc{}, err
	}

	pkg := pkgs[bi.Name]
	docs := doc.New(pkg, bi.ImportPath, 0)

	bugs := []string{}
	for _, bug := range docs.Notes["BUG"] {
		bugs = append(bugs, bug.Body)
	}

	name := bi.Name
	if name == "main" {
		name = filepath.Base(bi.Dir)
	}

	//get import path without the github.com/
	pathelms := strings.Split(ip, "/")[1:]
	repo := path.Join(pathelms...)

	return Doc{
		Name:     name,
		Import:   ip,
		Synopsis: bi.Doc,
		Doc:      fmtDoc(docs.Doc),
		Today:    today(),
		RepoPath: repo,
		Bugs:     bugs,
		Library:  bi.Name != "main",
		Command:  bi.Name == "main",
	}, nil
}
Esempio n. 30
0
// $GOROOT/src/cmd/go/main.go:631
func matchPackagesInFS(pattern string) []string {
	// Find directory to begin the scan.
	// Could be smarter but this one optimization
	// is enough for now, since ... is usually at the
	// end of a path.
	i := strings.Index(pattern, "...")
	dir, _ := pathpkg.Split(pattern[:i])

	// pattern begins with ./ or ../.
	// path.Clean will discard the ./ but not the ../.
	// We need to preserve the ./ for pattern matching
	// and in the returned import paths.
	prefix := ""
	if strings.HasPrefix(pattern, "./") {
		prefix = "./"
	}
	match := matchPattern(pattern)

	var pkgs []string
	filepath.Walk(dir, func(path string, fi os.FileInfo, err error) error {
		if err != nil || !fi.IsDir() {
			return nil
		}
		if path == dir {
			// filepath.Walk starts at dir and recurses. For the recursive case,
			// the path is the result of filepath.Join, which calls filepath.Clean.
			// The initial case is not Cleaned, though, so we do this explicitly.
			//
			// This converts a path like "./io/" to "io". Without this step, running
			// "cd $GOROOT/src; go list ./io/..." would incorrectly skip the io
			// package, because prepending the prefix "./" to the unclean path would
			// result in "././io", and match("././io") returns false.
			path = filepath.Clean(path)
		}

		// Avoid .foo, _foo, and testdata directory trees, but do not avoid "." or "..".
		_, elem := filepath.Split(path)
		dot := strings.HasPrefix(elem, ".") && elem != "." && elem != ".."
		if dot || strings.HasPrefix(elem, "_") || elem == "testdata" {
			return filepath.SkipDir
		}

		name := prefix + filepath.ToSlash(path)
		if !match(name) {
			return nil
		}
		if _, err = build.ImportDir(path, 0); err != nil {
			if _, noGo := err.(*build.NoGoError); !noGo {
				log.Print(err)
			}
			return nil
		}
		pkgs = append(pkgs, name)
		return nil
	})
	return pkgs
}