Beispiel #1
0
func generate_target(srcdir string, pkgdir string, prefix string, ctx build.Context) string {
	pkg, _ := ctx.ImportDir(srcdir+pkgdir, 0)
	name := pkg.Name
	var deps []string
	for _, imp := range pkg.Imports {
		if strings.HasPrefix(imp, prefix) {
			imp = strings.TrimPrefix(imp, prefix)
			if packages[imp] == "" {
				packages[imp] = generate_target(srcdir, imp, prefix, ctx)
			}
			deps = append(deps, "$(LIBS_"+packages[imp]+")")
		}
	}
	if pkgdir != "" {
		fmt.Printf("SRCDIR_%s := $(SRCDIR)%s/\n", name, pkgdir)
	} else {
		fmt.Printf("SRCDIR_%s := $(SRCDIR)\n", name)
	}
	fmt.Printf("SRC_%s := $(addprefix $(SRCDIR_%s), %s)\n", name, name, strings.Join(pkg.GoFiles, " "))
	fmt.Printf("DEPS_%s := %s\n", name, strings.Join(deps, " "))
	if pkgdir != "" {
		fmt.Printf("OBJ_%s := $(LIBDIR)/%s.o\n", name, pkgdir)
		fmt.Printf("LIB_%s := $(LIBDIR)/%s.a\n", name, pkgdir)
		fmt.Printf("LIBS_%s := $(LIB_%s) $(DEPS_%s)\n", name, name, name)
		fmt.Printf("$(OBJ_%s) : $(SRC_%s) $(DEPS_%s)\n", name, name, name)
		fmt.Printf("\t@mkdir -p $(dir $@)\n")
		fmt.Printf("\t$(GOC) $(GOFLAGS) -c -o $@ $(SRC_%s)\n", name)
	}
	return name
}
Beispiel #2
0
// subpackages returns the set of packages in the given srcDir whose
// import paths start with dir.
func subpackages(ctxt *build.Context, srcDir string, dir string) map[string]bool {
	subs := map[string]bool{dir: true}

	// Find all packages under srcDir whose import paths start with dir.
	buildutil.ForEachPackage(ctxt, func(pkg string, err error) {
		if err != nil {
			log.Fatalf("unexpected error in ForEachPackage: %v", err)
		}

		if !strings.HasPrefix(pkg, path.Join(dir, "")) {
			return
		}

		p, err := ctxt.Import(pkg, "", build.FindOnly)
		if err != nil {
			log.Fatalf("unexpected: package %s can not be located by build context: %s", pkg, err)
		}
		if p.SrcRoot == "" {
			log.Fatalf("unexpected: could not determine srcDir for package %s: %s", pkg, err)
		}
		if p.SrcRoot != srcDir {
			return
		}

		subs[pkg] = true
	})

	return subs
}
Beispiel #3
0
// imports returns a map of all import directories (recursively) used by the app.
// The return value maps full directory names to original import names.
func imports(ctxt *build.Context, srcDir string, gopath []string) (map[string]string, error) {
	pkg, err := ctxt.ImportDir(srcDir, 0)
	if err != nil {
		return nil, fmt.Errorf("unable to analyze source: %v", err)
	}

	// Resolve all non-standard-library imports
	result := make(map[string]string)
	for _, v := range pkg.Imports {
		if !strings.Contains(v, ".") {
			continue
		}
		src, err := findInGopath(v, gopath)
		if err != nil {
			return nil, fmt.Errorf("unable to find import %v in gopath %v: %v", v, gopath, err)
		}
		result[src] = v
		im, err := imports(ctxt, src, gopath)
		if err != nil {
			return nil, fmt.Errorf("unable to parse package %v: %v", src, err)
		}
		for k, v := range im {
			result[k] = v
		}
	}
	return result, nil
}
Beispiel #4
0
// PackageDoc gets the documentation for the package with the specified import
// path and writes it to out.
func PackageDoc(ctxt *build.Context, fset *token.FileSet, srcDir string, importPath string) (*Doc, error) {
	buildPkg, err := ctxt.Import(importPath, srcDir, build.ImportComment)
	if err != nil {
		return nil, err
	}
	// only parse .go files in the specified package
	filter := func(info os.FileInfo) bool {
		for _, fname := range buildPkg.GoFiles {
			if fname == info.Name() {
				return true
			}
		}
		return false
	}
	// TODO we've already parsed the files via go/loader...can we avoid doing it again?
	pkgs, err := parser.ParseDir(fset, buildPkg.Dir, filter, parser.PackageClauseOnly|parser.ParseComments)
	if err != nil {
		return nil, err
	}
	if astPkg, ok := pkgs[buildPkg.Name]; ok {
		docPkg := doc.New(astPkg, importPath, 0)
		// TODO: we could also include package-level constants, vars, and functions (like the go doc command)
		return &Doc{
			Name: buildPkg.Name,
			Decl: "package " + buildPkg.Name, // TODO: add '// import "pkg"' (like godoc)
			Doc:  docPkg.Doc,
		}, nil
	}
	return nil, errors.New("No documentation found for " + buildPkg.Name)
}
Beispiel #5
0
func resolvePackageSpec(ctx *build.Context, cwd string, src io.Reader, spec string) string {
	if strings.HasSuffix(spec, ".go") {
		d := path.Dir(spec)
		if !buildutil.IsAbsPath(ctx, d) {
			d = buildutil.JoinPath(ctx, cwd, d)
		}
		if bpkg, err := ctx.ImportDir(d, build.FindOnly); err == nil {
			return bpkg.ImportPath
		}
	}
	path := spec
	switch {
	case strings.HasPrefix(spec, "."):
		if bpkg, err := ctx.Import(spec, cwd, build.FindOnly); err == nil {
			path = bpkg.ImportPath
		}
	case strings.HasPrefix(spec, "/"):
		path = spec[1:]
	default:
		if p, ok := readImports(cwd, src)[spec]; ok {
			path = p
		}
	}
	return strings.TrimSuffix(path, "/")
}
// IsDir behaves like os.Stat plus IsDir,
// but uses the build context's file system interface, if any.
func IsDir(ctxt *build.Context, path string) bool {
	if ctxt.IsDir != nil {
		return ctxt.IsDir(path)
	}
	fi, err := os.Stat(path)
	return err == nil && fi.IsDir()
}
Beispiel #7
0
//Import imports a package.
//
//path is run through ToImport.
//
//If ctx is nil, the default context is used.
//
//N.B. we require a pointer to a build.Context for caching.
//Two build contexts with identical values that are not represented
//by the same pointer will have all packages imported by them
//cached separately.
func Import(ctx *build.Context, path string) (*Package, error) {
	if ctx == nil {
		ctx = defaultctx
	}
	root, path, err := ToImport(path)
	if err != nil {
		return nil, err
	}

	ident := ident{ctx, path}
	if pkg := pkgget(ident); pkg != nil {
		return pkg, nil
	}

	p, err := ctx.Import(path, root, 0)
	if err != nil {
		return nil, err
	}

	pkg := &Package{
		Context: ctx,
		Build:   p,
	}
	pkgset(ident, pkg)

	return pkg, nil
}
Beispiel #8
0
// guessImportPath finds the package containing filename, and returns
// its source directory (an element of $GOPATH) and its import path
// relative to it.
//
// TODO(adonovan): what about _test.go files that are not part of the
// package?
//
func guessImportPath(filename string, buildContext *build.Context) (srcdir, importPath string, err error) {
	absFile, err := filepath.Abs(filename)
	if err != nil {
		err = fmt.Errorf("can't form absolute path of %s", filename)
		return
	}
	absFileDir := segments(filepath.Dir(absFile))

	// Find the innermost directory in $GOPATH that encloses filename.
	minD := 1024
	for _, gopathDir := range buildContext.SrcDirs() {
		absDir, err := filepath.Abs(gopathDir)
		if err != nil {
			continue // e.g. non-existent dir on $GOPATH
		}
		d := prefixLen(segments(absDir), absFileDir)
		// If there are multiple matches,
		// prefer the innermost enclosing directory
		// (smallest d).
		if d >= 0 && d < minD {
			minD = d
			srcdir = gopathDir
			importPath = strings.Join(absFileDir[len(absFileDir)-minD:], string(os.PathSeparator))
		}
	}
	if srcdir == "" {
		err = fmt.Errorf("can't find package for file %s", filename)
	}
	return
}
// ContainingPackage returns the package containing filename.
//
// If filename is not absolute, it is interpreted relative to working directory dir.
// All I/O is via the build context's file system interface, if any.
//
// The '...Files []string' fields of the resulting build.Package are not
// populated (build.FindOnly mode).
//
// TODO(adonovan): call this from oracle when the tree thaws.
//
func ContainingPackage(ctxt *build.Context, dir, filename string) (*build.Package, error) {
	if !IsAbsPath(ctxt, filename) {
		filename = JoinPath(ctxt, dir, filename)
	}

	// We must not assume the file tree uses
	// "/" always,
	// `\` always,
	// or os.PathSeparator (which varies by platform),
	// but to make any progress, we are forced to assume that
	// paths will not use `\` unless the PathSeparator
	// is also `\`, thus we can rely on filepath.ToSlash for some sanity.

	dirSlash := path.Dir(filepath.ToSlash(filename)) + "/"

	// We assume that no source root (GOPATH[i] or GOROOT) contains any other.
	for _, srcdir := range ctxt.SrcDirs() {
		srcdirSlash := filepath.ToSlash(srcdir) + "/"
		if dirHasPrefix(dirSlash, srcdirSlash) {
			importPath := dirSlash[len(srcdirSlash) : len(dirSlash)-len("/")]
			return ctxt.Import(importPath, dir, build.FindOnly)
		}
	}

	return nil, fmt.Errorf("can't find package containing %s", filename)
}
Beispiel #10
0
// ForEachPackage calls the found function with the package path of
// each Go package it finds in any source directory of the specified
// build context (e.g. $GOROOT or an element of $GOPATH).
// All package paths are canonical, and thus may contain "/vendor/".
//
// If the package directory exists but could not be read, the second
// argument to the found function provides the error.
//
// All I/O is done via the build.Context file system interface,
// which must be concurrency-safe.
//
func ForEachPackage(ctxt *build.Context, found func(importPath string, err error)) {
	// We use a counting semaphore to limit
	// the number of parallel calls to ReadDir.
	sema := make(chan bool, 20)

	ch := make(chan item)

	var wg sync.WaitGroup
	for _, root := range ctxt.SrcDirs() {
		root := root
		wg.Add(1)
		go func() {
			allPackages(ctxt, sema, root, ch)
			wg.Done()
		}()
	}
	go func() {
		wg.Wait()
		close(ch)
	}()

	// All calls to found occur in the caller's goroutine.
	for i := range ch {
		found(i.importPath, i.err)
	}
}
Beispiel #11
0
// parseFiles parses the Go source files within directory dir and
// returns the ASTs of the ones that could be at least partially parsed,
// along with a list of I/O and parse errors encountered.
//
// I/O is done via ctxt, which may specify a virtual file system.
// displayPath is used to transform the filenames attached to the ASTs.
//
func parseFiles(fset *token.FileSet, ctxt *build.Context, displayPath func(string) string, dir string, files []string, mode parser.Mode) ([]*ast.File, []error) {
	if displayPath == nil {
		displayPath = func(path string) string { return path }
	}
	var wg sync.WaitGroup
	n := len(files)
	parsed := make([]*ast.File, n)
	errors := make([]error, n)
	for i, file := range files {
		if !buildutil.IsAbsPath(ctxt, file) {
			file = buildutil.JoinPath(ctxt, dir, file)
		}
		wg.Add(1)
		go func(i int, file string) {
			ioLimit <- true // wait
			defer func() {
				wg.Done()
				<-ioLimit // signal
			}()
			var rd io.ReadCloser
			var err error
			if ctxt.OpenFile != nil {
				rd, err = ctxt.OpenFile(file)
			} else {
				rd, err = os.Open(file)
			}
			if err != nil {
				errors[i] = err // open failed
				return
			}

			// ParseFile may return both an AST and an error.
			parsed[i], errors[i] = parser.ParseFile(fset, displayPath(file), rd, mode)
			rd.Close()
		}(i, file)
	}
	wg.Wait()

	// Eliminate nils, preserving order.
	var o int
	for _, f := range parsed {
		if f != nil {
			parsed[o] = f
			o++
		}
	}
	parsed = parsed[:o]

	o = 0
	for _, err := range errors {
		if err != nil {
			errors[o] = err
			o++
		}
	}
	errors = errors[:o]

	return parsed, errors
}
Beispiel #12
0
// build gets imports from source files.
func (w *walker) build(srcs []*source) ([]string, error) {
	// Add source files to walker, I skipped references here.
	w.srcs = make(map[string]*source)
	for _, src := range srcs {
		w.srcs[src.name] = src
	}

	w.fset = token.NewFileSet()

	// Find the package and associated files.
	ctxt := build.Context{
		GOOS:          runtime.GOOS,
		GOARCH:        runtime.GOARCH,
		CgoEnabled:    true,
		JoinPath:      path.Join,
		IsAbsPath:     path.IsAbs,
		SplitPathList: func(list string) []string { return strings.Split(list, ":") },
		IsDir:         func(path string) bool { panic("unexpected") },
		HasSubdir:     func(root, dir string) (rel string, ok bool) { panic("unexpected") },
		ReadDir:       func(dir string) (fi []os.FileInfo, err error) { return w.readDir(dir) },
		OpenFile:      func(path string) (r io.ReadCloser, err error) { return w.openFile(path) },
		Compiler:      "gc",
	}

	bpkg, err := ctxt.ImportDir(w.ImportPath, 0)
	// Continue if there are no Go source files; we still want the directory info.
	_, nogo := err.(*build.NoGoError)
	if err != nil {
		if nogo {
			err = nil
		} else {
			return nil, errors.New("doc.walker.build(): " + err.Error())
		}
	}

	// Parse the Go files

	files := make(map[string]*ast.File)
	for _, name := range append(bpkg.GoFiles, bpkg.CgoFiles...) {
		file, err := parser.ParseFile(w.fset, name, w.srcs[name].data, parser.ParseComments)
		if err != nil {
			//beego.Error("doc.walker.build():", err)
			continue
		}
		files[name] = file
	}

	w.ImportPath = strings.Replace(w.ImportPath, "\\", "/", -1)
	var imports []string
	for _, v := range bpkg.Imports {
		// Skip strandard library.
		if !utils.IsGoRepoPath(v) &&
			(utils.GetProjectPath(v) != utils.GetProjectPath(w.ImportPath)) {
			imports = append(imports, v)
		}
	}

	return imports, err
}
Beispiel #13
0
// defaultFindPackage locates the specified (possibly empty) package
// using go/build logic.  It returns an error if not found.
func defaultFindPackage(ctxt *build.Context, path string) (*build.Package, error) {
	// Import(srcDir="") disables local imports, e.g. import "./foo".
	bp, err := ctxt.Import(path, "", 0)
	if _, ok := err.(*build.NoGoError); ok {
		return bp, nil // empty directory is not an error
	}
	return bp, err
}
Beispiel #14
0
// build generates data from source files.
func (w *routerWalker) build(srcs []*source) (*Package, error) {
	// Add source files to walker, I skipped references here.
	w.srcs = make(map[string]*source)
	for _, src := range srcs {
		w.srcs[src.name] = src
	}

	w.fset = token.NewFileSet()

	// Find the package and associated files.
	ctxt := gobuild.Context{
		GOOS:          runtime.GOOS,
		GOARCH:        runtime.GOARCH,
		CgoEnabled:    true,
		JoinPath:      path.Join,
		IsAbsPath:     path.IsAbs,
		SplitPathList: func(list string) []string { return strings.Split(list, ":") },
		IsDir:         func(path string) bool { panic("unexpected") },
		HasSubdir:     func(root, dir string) (rel string, ok bool) { panic("unexpected") },
		ReadDir:       func(dir string) (fi []os.FileInfo, err error) { return w.readDir(dir) },
		OpenFile:      func(path string) (r io.ReadCloser, err error) { return w.openFile(path) },
		Compiler:      "gc",
	}

	bpkg, err := ctxt.ImportDir(w.pdoc.ImportPath, 0)
	// Continue if there are no Go source files; we still want the directory info.
	_, nogo := err.(*gobuild.NoGoError)
	if err != nil {
		if nogo {
			err = nil
		} else {
			return nil, errors.New("routerWalker.build -> " + err.Error())
		}
	}

	// Parse the Go files
	files := make(map[string]*ast.File)
	for _, name := range append(bpkg.GoFiles, bpkg.CgoFiles...) {
		file, err := parser.ParseFile(w.fset, name, w.srcs[name].data, parser.ParseComments)
		if err != nil {
			return nil, errors.New("routerWalker.build -> parse go files: " + err.Error())
		}
		files[name] = file
	}

	apkg, _ := ast.NewPackage(w.fset, files, simpleImporter, nil)

	mode := doc.Mode(0)
	if w.pdoc.ImportPath == "builtin" {
		mode |= doc.AllDecls
	}

	pdoc := doc.New(apkg, w.pdoc.ImportPath, mode)

	w.pdoc.Types = w.types(pdoc.Types)

	return w.pdoc, err
}
Beispiel #15
0
func ImportStdPkg(context *build.Context, path string, mode build.ImportMode) (*build.Package, error) {
	realpath := filepath.Join(context.GOROOT, "src", "pkg", path)
	if _, err := os.Stat(realpath); err != nil {
		realpath = filepath.Join(context.GOROOT, "src", path)
	}
	pkg, err := context.ImportDir(realpath, 0)
	pkg.ImportPath = path
	return pkg, err
}
Beispiel #16
0
// find_global_file returns the file path of the compiled package corresponding to the specified
// import, and a boolean stating whether such path is valid.
// TODO: Return only one value, possibly empty string if not found.
func find_global_file(imp string, context build.Context) (string, bool) {
	// gocode synthetically generates the builtin package
	// "unsafe", since the "unsafe.a" package doesn't really exist.
	// Thus, when the user request for the package "unsafe" we
	// would return synthetic global file that would be used
	// just as a key name to find this synthetic package
	if imp == "unsafe" {
		return "unsafe", true
	}

	pkgfile := fmt.Sprintf("%s.a", imp)

	// if lib-path is defined, use it
	if g_config.LibPath != "" {
		for _, p := range filepath.SplitList(g_config.LibPath) {
			pkg_path := filepath.Join(p, pkgfile)
			if file_exists(pkg_path) {
				log_found_package_maybe(imp, pkg_path)
				return pkg_path, true
			}
			// Also check the relevant pkg/OS_ARCH dir for the libpath, if provided.
			pkgdir := fmt.Sprintf("%s_%s", context.GOOS, context.GOARCH)
			pkg_path = filepath.Join(p, "pkg", pkgdir, pkgfile)
			if file_exists(pkg_path) {
				log_found_package_maybe(imp, pkg_path)
				return pkg_path, true
			}
			// Also check the relevant pkg/OS/ARCH dir for the libpath, if provided.
			pkg_path = filepath.Join(p, "pkg", context.GOOS, context.GOARCH, pkgfile)
			if file_exists(pkg_path) {
				log_found_package_maybe(imp, pkg_path)
				return pkg_path, true
			}
		}
	}

	p, err := context.Import(imp, "", build.AllowBinary|build.FindOnly)
	if err == nil {
		if g_config.Autobuild {
			err = autobuild(p)
			if err != nil && *g_debug {
				log.Printf("Autobuild error: %s\n", err)
			}
		}
		if file_exists(p.PkgObj) {
			log_found_package_maybe(imp, p.PkgObj)
			return p.PkgObj, true
		}
	}

	if *g_debug {
		log.Printf("Import path %q was not resolved\n", imp)
		log.Println("Gocode's build context is:")
		log_build_context(context)
	}
	return "", false
}
Beispiel #17
0
func ImportPaths(srcDir string, bctx *build.Context, pathFilter margo.PathFilterFunc) map[string]string {
	rootDirs := bctx.SrcDirs()

	importDir := func(dir string) *build.Package {
		p := quickImportDir(bctx, rootDirs, dir)
		if p != nil && p.Name != "" && p.ImportPath != "" {
			return p
		}
		return nil
	}

	srcImportPath := quickImportPath(srcDir)

	var pkgs []*build.Package
	for _, dir := range rootDirs {
		pkgs = append(pkgs, importablePackages(dir, importDir, pathFilter)...)
	}

	res := make(map[string]string, len(pkgs))
	res["unsafe"] = "" // this package doesn't exist on-disk

	const vdir = "/vendor/"
	var vendored []*build.Package
	for _, p := range pkgs {
		switch {
		case p.Name == "main":
		// it's rarely useful to import `package main`
		case p.ImportPath == "builtin":
		// this package exists for documentation only
		case strings.HasPrefix(p.ImportPath, vdir[1:]) || strings.Contains(p.ImportPath, vdir):
			// fill these in after everything else so we can tag them
			vendored = append(vendored, p)
		default:
			res[p.ImportPath] = importsName(p)
		}
	}
	if srcImportPath != "" {
		sfx := srcImportPath + "/"
		for _, p := range vendored {
			name := importsName(p) + " [vendored]"
			ipath := p.ImportPath
			vpos := strings.LastIndex(ipath, vdir)
			switch {
			case vpos > 0:
				pfx := ipath[:vpos+1]
				if strings.HasPrefix(sfx, pfx) {
					ipath := ipath[vpos+len(vdir):]
					res[ipath] = name
				}
			case strings.HasPrefix(ipath, vdir[1:]):
				ipath := ipath[len(vdir)-1:]
				res[ipath] = name
			}
		}
	}
	return res
}
Beispiel #18
0
// srcDir returns the absolute path of the srcdir containing pkg.
func srcDir(ctxt *build.Context, pkg string) (string, error) {
	for _, srcDir := range ctxt.SrcDirs() {
		path := buildutil.JoinPath(ctxt, srcDir, pkg)
		if buildutil.IsDir(ctxt, path) {
			return srcDir, nil
		}
	}
	return "", fmt.Errorf("src dir not found for package: %s", pkg)
}
Beispiel #19
0
// importRuntime locates the the runtime package and parses its files
// to *ast.Files. This is used to generate runtime type structures.
func parseRuntime(buildctx *build.Context, fset *token.FileSet) ([]*ast.File, error) {
	buildpkg, err := buildctx.Import("github.com/go-llvm/llgo/pkg/runtime", "", 0)
	if err != nil {
		return nil, err
	}
	filenames := make([]string, len(buildpkg.GoFiles))
	for i, f := range buildpkg.GoFiles {
		filenames[i] = path.Join(buildpkg.Dir, f)
	}
	return parseFiles(fset, filenames)
}
Beispiel #20
0
// FileExists returns true if the specified file exists,
// using the build context's file system interface.
func FileExists(ctxt *build.Context, path string) bool {
	if ctxt.OpenFile != nil {
		r, err := ctxt.OpenFile(path)
		if err != nil {
			return false
		}
		r.Close() // ignore error
		return true
	}
	_, err := os.Stat(path)
	return err == nil
}
Beispiel #21
0
func getImportPath(ctxt *build.Context, pathOrFilename string) (string, error) {
	dirSlash := filepath.ToSlash(pathOrFilename)

	// We assume that no source root (GOPATH[i] or GOROOT) contains any other.
	for _, srcdir := range ctxt.SrcDirs() {
		srcdirSlash := filepath.ToSlash(srcdir) + "/"
		if strings.HasPrefix(dirSlash, srcdirSlash) {
			importPath := dirSlash[len(srcdirSlash):len(dirSlash)]
			return importPath, nil
		}
	}
	return "", errNotGoSourcePath
}
Beispiel #22
0
// findPackageMember returns the type and position of the declaration of
// pkg.member by loading and parsing the files of that package.
// srcdir is the directory in which the import appears.
func findPackageMember(ctxt *build.Context, fset *token.FileSet, srcdir, pkg, member string) (token.Token, token.Pos, error) {
	bp, err := ctxt.Import(pkg, srcdir, 0)
	if err != nil {
		return 0, token.NoPos, err // no files for package
	}

	// TODO(adonovan): opt: parallelize.
	for _, fname := range bp.GoFiles {
		filename := filepath.Join(bp.Dir, fname)

		// Parse the file, opening it the file via the build.Context
		// so that we observe the effects of the -modified flag.
		f, _ := buildutil.ParseFile(fset, ctxt, nil, ".", filename, parser.Mode(0))
		if f == nil {
			continue
		}

		// Find a package-level decl called 'member'.
		for _, decl := range f.Decls {
			switch decl := decl.(type) {
			case *ast.GenDecl:
				for _, spec := range decl.Specs {
					switch spec := spec.(type) {
					case *ast.ValueSpec:
						// const or var
						for _, id := range spec.Names {
							if id.Name == member {
								return decl.Tok, id.Pos(), nil
							}
						}
					case *ast.TypeSpec:
						if spec.Name.Name == member {
							return token.TYPE, spec.Name.Pos(), nil
						}
					case *ast.AliasSpec:
						if spec.Name.Name == member {
							return decl.Tok, spec.Name.Pos(), nil
						}
					}
				}
			case *ast.FuncDecl:
				if decl.Recv == nil && decl.Name.Name == member {
					return token.FUNC, decl.Name.Pos(), nil
				}
			}
		}
	}

	return 0, token.NoPos, fmt.Errorf("couldn't find declaration of %s in %q", member, pkg)
}
Beispiel #23
0
// appFiles returns a list of all Go source files in the app.
func appFiles(ctxt *build.Context) ([]string, error) {
	pkg, err := ctxt.ImportDir(".", 0)
	if err != nil {
		return nil, err
	}
	if !pkg.IsCommand() {
		return nil, fmt.Errorf(`the root of your app needs to be package "main" (currently %q). Please see https://cloud.google.com/appengine/docs/go/managed-vms for more details on structuring your app.`, pkg.Name)
	}
	var appFiles []string
	for _, f := range pkg.GoFiles {
		n := filepath.Join(".", f)
		appFiles = append(appFiles, n)
	}
	return appFiles, nil
}
Beispiel #24
0
// Import returns details about the package in the directory.
func (dir *Directory) Import(ctx *build.Context, mode build.ImportMode) (*build.Package, error) {
	safeCopy := *ctx
	ctx = &safeCopy
	ctx.JoinPath = path.Join
	ctx.IsAbsPath = path.IsAbs
	ctx.SplitPathList = func(list string) []string { return strings.Split(list, ":") }
	ctx.IsDir = func(path string) bool { return false }
	ctx.HasSubdir = func(root, dir string) (rel string, ok bool) { return "", false }
	ctx.ReadDir = dir.readDir
	ctx.OpenFile = dir.openFile
	return ctx.ImportDir(".", mode)
}
Beispiel #25
0
// ForEachPackage calls the found function with the import path of
// each Go package it finds in any source directory of the specified
// build context (e.g. $GOROOT or an element of $GOPATH).
//
// If the package directory exists but could not be read, the second
// argument to the found function provides the error.
//
// The found function and the build.Context virtual file system
// accessors must be concurrency safe.
//
func ForEachPackage(ctxt *build.Context, found func(importPath string, err error)) {
	// We use a counting semaphore to limit
	// the number of parallel calls to ReadDir.
	sema := make(chan bool, 20)

	var wg sync.WaitGroup
	for _, root := range ctxt.SrcDirs() {
		root := root
		wg.Add(1)
		go func() {
			allPackages(ctxt, sema, root, found)
			wg.Done()
		}()
	}
	wg.Wait()
}
Beispiel #26
0
// parseFiles parses the Go source files files within directory dir
// and returns their ASTs, or the first parse error if any.
//
// I/O is done via ctxt, which may specify a virtual file system.
// displayPath is used to transform the filenames attached to the ASTs.
//
func parseFiles(fset *token.FileSet, ctxt *build.Context, displayPath func(string) string, dir string, files []string, mode parser.Mode) ([]*ast.File, error) {
	if displayPath == nil {
		displayPath = func(path string) string { return path }
	}
	isAbs := filepath.IsAbs
	if ctxt.IsAbsPath != nil {
		isAbs = ctxt.IsAbsPath
	}
	joinPath := filepath.Join
	if ctxt.JoinPath != nil {
		joinPath = ctxt.JoinPath
	}
	var wg sync.WaitGroup
	n := len(files)
	parsed := make([]*ast.File, n)
	errors := make([]error, n)
	for i, file := range files {
		if !isAbs(file) {
			file = joinPath(dir, file)
		}
		wg.Add(1)
		go func(i int, file string) {
			defer wg.Done()
			var rd io.ReadCloser
			var err error
			if ctxt.OpenFile != nil {
				rd, err = ctxt.OpenFile(file)
			} else {
				rd, err = os.Open(file)
			}
			defer rd.Close()
			if err != nil {
				errors[i] = err
				return
			}
			parsed[i], errors[i] = parser.ParseFile(fset, displayPath(file), rd, mode)
		}(i, file)
	}
	wg.Wait()

	for _, err := range errors {
		if err != nil {
			return nil, err
		}
	}
	return parsed, nil
}
Beispiel #27
0
func explort(ctx build.Context, pkg *build.Package, visited map[string]bool) {
	for _, packageName := range pkg.Imports {
		if !visited[packageName] {
			visited[packageName] = true
			if *verbose || strings.Contains(packageName, ".") {
				fmt.Printf("%s\n", packageName)
			}
			if ! (packageName == "C") {
				child, err := ctx.Import(packageName, pkg.Dir, build.AllowBinary)
				if err != nil {
					log.Fatalf("error on import: %s", err);
				}					
				explort(ctx, child, visited)
			}
		}
	}
}
Beispiel #28
0
// Setup configures a *build.Context to use the given VFS
// as its filesystem.
func Setup(ctx *build.Context, fs vfs.VFS) {
	ctx.JoinPath = path.Join
	ctx.SplitPathList = filepath.SplitList
	ctx.IsAbsPath = func(p string) bool {
		return p != "" && p[0] == '/'
	}
	ctx.IsDir = func(p string) bool {
		stat, err := fs.Stat(p)
		return err == nil && stat.IsDir()
	}
	ctx.HasSubdir = func(root, dir string) (string, bool) {
		root = path.Clean(root)
		if !strings.HasSuffix(root, separator) {
			root += separator
		}
		dir = path.Clean(dir)
		if !strings.HasPrefix(dir, root) {
			return "", false
		}
		return dir[len(root):], true
	}
	ctx.ReadDir = fs.ReadDir
	ctx.OpenFile = func(p string) (io.ReadCloser, error) {
		return fs.Open(p)
	}
}
Beispiel #29
0
// FindAll returns a list of all packages in all of the GOPATH trees
// in the given build context. If prefix is non-empty, only packages
// whose import paths begin with prefix are returned.
func FindAll(prefix string, buildContext build.Context, mode FindMode) (pkgs []*build.Package, err error) {
	have := map[string]bool{
		"builtin": true, // ignore pseudo-package that exists only for documentation
	}
	if !buildContext.CgoEnabled {
		have["runtime/cgo"] = true // ignore during walk
	}

	// TODO(sqs): find cmd packages as well

	var gorootSrcPkg = filepath.Join(buildContext.GOROOT, "src/pkg")

	for _, src := range buildContext.SrcDirs() {
		if src == gorootSrcPkg && mode&IncludeStdlib == 0 {
			continue // skip stdlib
		}
		src = filepath.Clean(src) + string(filepath.Separator)
		start := filepath.Join(src, prefix)
		filepath.Walk(start, func(path string, fi os.FileInfo, err error) error {
			if err != nil || !fi.IsDir() || path == src {
				return nil
			}

			// Avoid .foo, _foo, and testdata directory trees.
			_, elem := filepath.Split(path)
			if strings.HasPrefix(elem, ".") || strings.HasPrefix(elem, "_") || elem == "testdata" {
				return filepath.SkipDir
			}

			name := filepath.ToSlash(path[len(start):])
			if have[name] {
				return nil
			}
			have[name] = true

			pkg, err := buildContext.ImportDir(path, 0)
			if err != nil && strings.Contains(err.Error(), "no Go source files") {
				return nil
			}
			pkgs = append(pkgs, pkg)
			return nil
		})
	}
	return pkgs, nil
}
Beispiel #30
0
/*
Scan basepath and find the import'able paths relative to it
*/
func FindImports(basepath string) (Imports, error) {
	set := map[string]bool{} // unique keys
	findImportFn := func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if info.Mode().IsRegular() && isSourceFile(path) {
			lib := strings.TrimPrefix(filepath.Dir(path), basepath)
			if strings.HasPrefix(lib, "/") {
				lib = strings.TrimPrefix(lib, "/")
			}

			// if the lib string is _not_ in our set and import path is sane
			if _, found := set[lib]; !found && isImportablePath(lib) {
				set[lib] = true
			}
		}
		return nil
	}

	pkgs := Imports{}
	err := filepath.Walk(basepath, findImportFn)
	if err != nil {
		return pkgs, err
	}

	var ctx build.Context = build.Default
	if !strings.HasPrefix(basepath, build.Default.GOROOT) && !strings.HasPrefix(basepath, build.Default.GOPATH) {
		// rather than messing with the build.Default
		ctx = build.Context{
			GOROOT:   build.Default.GOROOT,
			GOPATH:   basepath,
			Compiler: build.Default.Compiler,
			JoinPath: build.Default.JoinPath,
		}
	}

	for lib, _ := range set {
		if pkg, err := ctx.ImportDir(filepath.Join(basepath, lib), 0); err == nil {
			pkgs = append(pkgs, pkg)
		}
	}
	sort.Sort(byImportPath{pkgs})
	return pkgs, nil
}