Example #1
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, "/")
}
Example #2
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
}
Example #3
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
}
Example #4
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
}
Example #5
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
}
Example #6
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
}
Example #7
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)
}
Example #8
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
}
Example #9
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
}
Example #10
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
}
Example #11
0
// checkMain verifies that there is a single "main" function.
// It also returns a list of all Go source files in the app.
func checkMain(ctxt *build.Context) (bool, []string, error) {
	pkg, err := ctxt.ImportDir(*rootDir, 0)
	if err != nil {
		return false, nil, fmt.Errorf("unable to analyze source: %v", err)
	}
	if !pkg.IsCommand() {
		errorf("Your app's package needs to be changed from %q to \"main\".\n", pkg.Name)
	}
	// Search for a "func main"
	var hasMain bool
	var appFiles []string
	for _, f := range pkg.GoFiles {
		n := filepath.Join(*rootDir, f)
		appFiles = append(appFiles, n)
		if hasMain, err = readFile(n); err != nil {
			return false, nil, fmt.Errorf("error parsing %q: %v", n, err)
		}
	}
	return hasMain, appFiles, nil
}
Example #12
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, err
	}

	// Resolve imports, preferring vendored packages, then packages in the GOPATH.
	// Any package that could not be resolved and does not contain a "."
	// is assumed to be part of the standard libarry and therefore ignored.
	// Otherwise, unresolved packages will return an error.
	result := make(map[string]string)
	for _, v := range pkg.Imports {
		src, verr := findVendored(srcDir, v, gopath)
		if verr != nil {
			var perr error
			src, perr = findInGopath(v, gopath)
			if perr != nil {
				if !strings.Contains(v, ".") {
					continue
				}
				return nil, fmt.Errorf("unable to find import %v: %v, %v", v, perr, verr)
			}
		}

		if _, ok := result[src]; ok { // Already processed
			continue
		}
		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
}
Example #13
0
func (b *builder) build(srcs []*source) (*Package, error) {

	b.pkg.Updated = time.Now().UTC()

	references := make(map[string]bool)
	b.srcs = make(map[string]*source)
	for _, src := range srcs {
		if strings.HasSuffix(src.name, ".go") {
			b.srcs[src.name] = src
		} else {
			addReferences(references, src.data)
		}
	}

	for r := range references {
		b.pkg.References = append(b.pkg.References, r)
	}

	if len(b.srcs) == 0 {
		return b.pkg, nil
	}

	b.fset = token.NewFileSet()
	b.importPaths = make(map[string]map[string]string)

	// Find the package and associated files.

	ctxt := build.Context{
		GOOS:          "linux",
		GOARCH:        "amd64",
		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 b.readDir(dir) },
		OpenFile:      func(path string) (r io.ReadCloser, err error) { return b.openFile(path) },
		Compiler:      "gc",
	}
	pkg, err := ctxt.ImportDir(b.pkg.ImportPath, 0)
	if _, ok := err.(*build.NoGoError); ok {
		return b.pkg, nil
	} else if err != nil {
		b.pkg.Errors = append(b.pkg.Errors, err.Error())
		return b.pkg, nil
	}

	// Parse the Go files

	b.ast = &ast.Package{Name: pkg.Name, Files: make(map[string]*ast.File)}
	if pkg.IsCommand() && b.srcs["doc.go"] != nil {
		file, err := parser.ParseFile(b.fset, "doc.go", b.srcs["doc.go"].data, parser.ParseComments)
		if err == nil && file.Name.Name == "documentation" {
			b.ast.Files["doc.go"] = file
		}
	}
	if len(b.ast.Files) == 0 {
		for _, name := range append(pkg.GoFiles, pkg.CgoFiles...) {
			file, err := parser.ParseFile(b.fset, name, b.srcs[name].data, parser.ParseComments)
			if err != nil {
				b.pkg.Errors = append(b.pkg.Errors, err.Error())
				continue
			}
			b.pkg.Files = append(b.pkg.Files, &File{Name: name, URL: b.srcs[name].browseURL})
			b.pkg.SourceSize += len(b.srcs[name].data)
			b.ast.Files[name] = file
		}
	}

	// Find examples in the test files.

	for _, name := range append(pkg.TestGoFiles, pkg.XTestGoFiles...) {
		file, err := parser.ParseFile(b.fset, name, b.srcs[name].data, parser.ParseComments)
		if err != nil {
			b.pkg.Errors = append(b.pkg.Errors, err.Error())
			continue
		}
		b.pkg.TestFiles = append(b.pkg.TestFiles, &File{Name: name, URL: b.srcs[name].browseURL})
		b.pkg.TestSourceSize += len(b.srcs[name].data)
		b.examples = append(b.examples, doc.Examples(file)...)
	}

	b.vetPackage()

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

	pdoc := doc.New(b.ast, b.pkg.ImportPath, mode)

	b.pkg.Name = pdoc.Name
	b.pkg.Doc = strings.TrimRight(pdoc.Doc, " \t\n\r")
	b.pkg.Synopsis = synopsis(b.pkg.Doc)

	b.pkg.Examples = b.getExamples("")
	b.pkg.IsCmd = pkg.IsCommand()

	b.pkg.Consts = b.values(pdoc.Consts)
	b.pkg.Funcs = b.funcs(pdoc.Funcs)
	b.pkg.Types = b.types(pdoc.Types)
	b.pkg.Vars = b.values(pdoc.Vars)

	b.pkg.Bugs = pdoc.Bugs

	b.pkg.Imports = pkg.Imports
	b.pkg.TestImports = pkg.TestImports
	b.pkg.XTestImports = pkg.XTestImports

	return b.pkg, nil
}
Example #14
0
// build generates data from source files.
func (w *walker) build(srcs []*source) (*Package, error) {
	// Set created time.
	w.pdoc.Created = time.Now().UTC()

	// Add source files to walker, I skipped references here.
	w.srcs = make(map[string]*source)
	for _, src := range srcs {
		srcName := strings.ToLower(src.name) // For readme comparation.
		switch {
		case strings.HasSuffix(src.name, ".go"):
			w.srcs[src.name] = src
		case len(w.pdoc.Tag) > 0:
			continue // Only save latest readme.
		case strings.HasPrefix(srcName, "readme_zh") || strings.HasPrefix(srcName, "readme_cn"):
			models.SavePkgDoc(w.pdoc.ImportPath, "zh", src.data)
		case strings.HasPrefix(srcName, "readme"):
			models.SavePkgDoc(w.pdoc.ImportPath, "en", src.data)
		}
	}

	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.pdoc.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
			beego.Info("doc.walker.build -> No Go Source file")
		} else {
			return w.pdoc, 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 -> parse go files:", err)
			continue
		}
		w.pdoc.Files = append(w.pdoc.Files, name)
		//w.pdoc.SourceSize += len(w.srcs[name].data)
		files[name] = file
	}

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

	// Find examples in the test files.
	for _, name := range append(bpkg.TestGoFiles, bpkg.XTestGoFiles...) {
		file, err := parser.ParseFile(w.fset, name, w.srcs[name].data, parser.ParseComments)
		if err != nil {
			beego.Error("doc.walker.build -> find examples:", err)
			continue
		}
		//w.pdoc.TestFiles = append(w.pdoc.TestFiles, &File{Name: name, URL: w.srcs[name].browseURL})
		//w.pdoc.TestSourceSize += len(w.srcs[name].data)
		w.examples = append(w.examples, doc.Examples(file)...)
	}

	//w.vetPackage(apkg)

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

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

	w.pdoc.Synopsis = utils.Synopsis(pdoc.Doc)
	pdoc.Doc = strings.TrimRight(pdoc.Doc, " \t\n\r")
	var buf bytes.Buffer
	doc.ToHTML(&buf, pdoc.Doc, nil)
	w.pdoc.Doc = w.pdoc.Doc + "<br />" + buf.String()
	w.pdoc.Doc = strings.Replace(w.pdoc.Doc, "<p>", "<p><b>", 1)
	w.pdoc.Doc = strings.Replace(w.pdoc.Doc, "</p>", "</b></p>", 1)
	w.pdoc.Doc = base32.StdEncoding.EncodeToString([]byte(w.pdoc.Doc))

	w.pdoc.Examples = w.getExamples("")
	w.pdoc.IsCmd = bpkg.IsCommand()
	w.srcLines = make(map[string][]string)
	w.pdoc.Consts = w.values(pdoc.Consts)
	w.pdoc.Funcs = w.funcs(pdoc.Funcs)
	w.pdoc.Types = w.types(pdoc.Types)
	w.pdoc.Vars = w.values(pdoc.Vars)
	//w.pdoc.Notes = w.notes(pdoc.Notes)

	w.pdoc.Imports = bpkg.Imports
	w.pdoc.TestImports = bpkg.TestImports
	//w.pdoc.XTestImports = bpkg.XTestImports

	beego.Info("doc.walker.build(", pdoc.ImportPath, "), Goroutine #", runtime.NumGoroutine())
	return w.pdoc, err
}
Example #15
0
// build generates data from source files.
func (w *walker) build(srcs []*source) (*Package, error) {
	// Set created time.
	w.pdoc.Created = time.Now().UTC()

	// Add source files to walker, I skipped references here.
	w.srcs = make(map[string]*source)
	for _, src := range srcs {
		if strings.HasSuffix(src.name, ".go") {
			w.srcs[src.name] = src
		} else if src.name == "doc_zh.md" {
			// Multi-language documentation.
			w.mldocs[src.name] = src
		}
	}

	// Check number of source files.
	if len(w.srcs) == 0 {
		// No source file.
		return w.pdoc, nil
	}

	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.pdoc.ImportPath, 0)
	// Continue if there are no Go source files; we still want the directory info.
	if _, nogo := err.(*build.NoGoError); err != nil && !nogo {
		return w.pdoc, 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
		}
		w.pdoc.Files = append(w.pdoc.Files, name)
		//w.pdoc.SourceSize += len(w.srcs[name].data)
		files[name] = file
	}

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

	// Find examples in the test files.

	/*for _, name := range append(bpkg.TestGoFiles, bpkg.XTestGoFiles...) {
		file, err := parser.ParseFile(w.fset, name, w.srcs[name].data, parser.ParseComments)
		if err != nil {
			w.pdoc.Errors = append(w.pdoc.Errors, err.Error())
			continue
		}
		w.pdoc.TestFiles = append(w.pdoc.TestFiles, &File{Name: name, URL: w.srcs[name].browseURL})
		w.pdoc.TestSourceSize += len(w.srcs[name].data)
		w.examples = append(w.examples, doc.Examples(file)...)
	}*/

	//w.vetPackage(apkg)

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

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

	w.pdoc.Doc = strings.TrimRight(pdoc.Doc, " \t\n\r")
	w.pdoc.Synopsis = utils.Synopsis(w.pdoc.Doc)

	//w.pdoc.Examples = w.getExamples("")
	//w.pdoc.IsCmd = bpkg.IsCommand()
	w.pdoc.GOOS = ctxt.GOOS
	w.pdoc.GOARCH = ctxt.GOARCH

	w.srcLines = make(map[string][]string)
	w.pdoc.Consts = w.values(pdoc.Consts)
	w.pdoc.Funcs = w.funcs(pdoc.Funcs)
	w.pdoc.Types = w.types(pdoc.Types)
	w.pdoc.Vars = w.values(pdoc.Vars)
	//w.pdoc.Notes = w.notes(pdoc.Notes)

	w.pdoc.Imports = bpkg.Imports
	w.pdoc.TestImports = bpkg.TestImports
	//w.pdoc.XTestImports = bpkg.XTestImports

	beego.Info("doc.walker.build(", pdoc.ImportPath, "), Goroutine #", runtime.NumGoroutine())
	return w.pdoc, err
}
Example #16
0
func buildDoc(importPath, projectRoot, projectName, projectURL, etag string, lineFmt string, srcs []*source) (*Package, error) {

	b := &builder{
		lineFmt:     lineFmt,
		fset:        token.NewFileSet(),
		importPaths: make(map[string]map[string]string),
		srcs:        make(map[string]*source),
		pkg: &Package{
			ImportPath:  importPath,
			ProjectName: projectName,
			ProjectRoot: projectRoot,
			ProjectURL:  projectURL,
			Etag:        etag,
			Updated:     time.Now(),
		},
	}

	if len(srcs) == 0 {
		return b.pkg, nil
	}

	for _, src := range srcs {
		b.srcs[src.name] = src
	}

	// Find the package and associated files.

	ctxt := build.Context{
		GOOS:          "linux",
		GOARCH:        "amd64",
		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 b.readDir(dir) },
		OpenFile:      func(path string) (r io.ReadCloser, err error) { return b.openFile(path) },
		Compiler:      "gc",
	}
	pkg, err := ctxt.ImportDir(b.pkg.ImportPath, 0)
	if err != nil {
		b.pkg.Errors = append(b.pkg.Errors, err.Error())
		return b.pkg, nil
	}

	// Parse the Go files

	b.ast = &ast.Package{Name: pkg.Name, Files: make(map[string]*ast.File)}
	if pkg.IsCommand() && b.srcs["doc.go"] != nil {
		file, err := parser.ParseFile(b.fset, "doc.go", b.srcs["doc.go"].data, parser.ParseComments)
		if err == nil && file.Name.Name == "documentation" {
			b.ast.Files["doc.go"] = file
		}
	}
	if len(b.ast.Files) == 0 {
		for _, name := range append(pkg.GoFiles, pkg.CgoFiles...) {
			file, err := parser.ParseFile(b.fset, name, b.srcs[name].data, parser.ParseComments)
			if err != nil {
				b.pkg.Errors = append(b.pkg.Errors, err.Error())
				continue
			}
			b.pkg.Files = append(b.pkg.Files, &File{Name: name, URL: b.srcs[name].browseURL})
			b.pkg.SourceSize += len(b.srcs[name].data)
			b.ast.Files[name] = file
		}
	}

	// Find examples in the test files.

	for _, name := range append(pkg.TestGoFiles, pkg.XTestGoFiles...) {
		file, err := parser.ParseFile(b.fset, name, b.srcs[name].data, parser.ParseComments)
		if err != nil {
			b.pkg.Errors = append(b.pkg.Errors, err.Error())
			continue
		}
		b.pkg.TestFiles = append(b.pkg.TestFiles, &File{Name: name, URL: b.srcs[name].browseURL})
		b.pkg.TestSourceSize += len(b.srcs[name].data)
		b.examples = append(b.examples, doc.Examples(file)...)
	}

	b.vetPackage()

	pdoc := doc.New(b.ast, b.pkg.ImportPath, 0)

	b.pkg.Name = pdoc.Name
	b.pkg.Doc = strings.TrimRight(pdoc.Doc, " \t\n\r")
	b.pkg.Synopsis = synopsis(b.pkg.Doc)

	b.pkg.Examples = b.getExamples("")
	b.pkg.IsCmd = pkg.IsCommand()

	b.pkg.Consts = b.values(pdoc.Consts)
	b.pkg.Funcs = b.funcs(pdoc.Funcs)
	b.pkg.Types = b.types(pdoc.Types)
	b.pkg.Vars = b.values(pdoc.Vars)

	b.pkg.Imports = pkg.Imports
	b.pkg.TestImports = pkg.TestImports

	return b.pkg, nil
}
Example #17
0
// imports returns a map of all import directories used by the app.
// The return value maps full directory names to original import names.
func imports(ctxt *build.Context, srcDir string) (map[string]string, error) {
	result := make(map[string]string)

	type importFrom struct {
		path, fromDir string
	}
	var imports []importFrom
	visited := make(map[importFrom]bool)

	pkg, err := ctxt.ImportDir(srcDir, 0)
	if err != nil {
		return nil, err
	}
	for _, v := range pkg.Imports {
		imports = append(imports, importFrom{
			path:    v,
			fromDir: srcDir,
		})
	}

	// Resolve all non-standard-library imports
	for len(imports) != 0 {
		i := imports[0]
		imports = imports[1:] // shift
		if i.path == "C" {
			// ignore cgo
			continue
		}
		if _, ok := visited[i]; ok {
			// already scanned
			continue
		}
		visited[i] = true

		abs, err := filepath.Abs(i.fromDir)
		if err != nil {
			return nil, fmt.Errorf("unable to get absolute directory of %q: %v", i.fromDir, err)
		}
		pkg, err := ctxt.Import(i.path, abs, 0)
		if err != nil {
			return nil, fmt.Errorf("unable to find import %s, imported from %q: %v", i.path, i.fromDir, err)
		}

		// TODO(cbro): handle packages that are vendored by multiple imports correctly.

		if pkg.Goroot {
			// ignore standard library imports
			continue
		}

		vlogf("Located %q (imported from %q) -> %q", i.path, i.fromDir, pkg.Dir)
		result[pkg.Dir] = i.path

		for _, v := range pkg.Imports {
			imports = append(imports, importFrom{
				path:    v,
				fromDir: pkg.Dir,
			})
		}
	}

	return result, nil
}
Example #18
0
// build generates data from source files.
func (w *walker) build(srcs []*source) (*Package, error) {
	// Set created time.
	w.pdoc.Created = time.Now().UTC()

	// Add source files to walker, I skipped references here.
	w.srcs = make(map[string]*source)
	for _, src := range srcs {
		if strings.HasSuffix(src.name, ".go") {
			w.srcs[src.name] = src
		} else if strings.HasPrefix(strings.ToLower(src.name), "readme") {
			// Readme.
			w.pdoc.Doc = string(src.data)
			if len(w.pdoc.Doc) > 0 {
				if w.pdoc.Doc[0] == '\n' {
					w.pdoc.Doc = w.pdoc.Doc[1:]
				}
				// Remove title and `==========`.
				w.pdoc.Doc = w.pdoc.Doc[strings.Index(w.pdoc.Doc, "\n")+1:]
				if len(w.pdoc.Doc) == 0 {
					continue
				}

				if w.pdoc.Doc[0] == '=' {
					w.pdoc.Doc = w.pdoc.Doc[strings.Index(w.pdoc.Doc, "\n")+1:]
				}
				// Find all picture path of build system.
				for _, m := range buildPicPattern.FindAllString(w.pdoc.Doc, -1) {
					start := strings.Index(m, "http")
					end := strings.Index(m, ")")
					if (start > -1) && (end > -1) && (start < end) {
						picPath := m[start:end]
						w.pdoc.Doc = strings.Replace(w.pdoc.Doc, m, "![]("+picPath+")", 1)
					}
				}
				w.pdoc.Doc = string(blackfriday.MarkdownCommon([]byte(w.pdoc.Doc)))
				w.pdoc.Doc = strings.Replace(w.pdoc.Doc, "h3>", "h5>", -1)
				w.pdoc.Doc = strings.Replace(w.pdoc.Doc, "h2>", "h4>", -1)
				w.pdoc.Doc = strings.Replace(w.pdoc.Doc, "h1>", "h3>", -1)
				w.pdoc.Doc = strings.Replace(w.pdoc.Doc, "<center>", "", -1)
				w.pdoc.Doc = strings.Replace(w.pdoc.Doc, "</center>", "", -1)
				w.pdoc.Doc = "<div style='display:block; padding: 3px; border:1px solid #4F4F4F;'>" + w.pdoc.Doc + "</div>"
			}
		}
	}

	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.pdoc.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
			beego.Info("doc.walker.build(): No Go Source file.")
		} else {
			return w.pdoc, 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().[parse go files]:", err)
			continue
		}
		w.pdoc.Files = append(w.pdoc.Files, name)
		//w.pdoc.SourceSize += len(w.srcs[name].data)
		files[name] = file
	}

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

	// Find examples in the test files.
	// for _, name := range append(bpkg.TestGoFiles, bpkg.XTestGoFiles...) {
	// 	file, err := parser.ParseFile(w.fset, name, w.srcs[name].data, parser.ParseComments)
	// 	if err != nil {
	// 		beego.Error("doc.walker.build().[find examples]:", err)
	// 		continue
	// 	}
	// 	//w.pdoc.TestFiles = append(w.pdoc.TestFiles, &File{Name: name, URL: w.srcs[name].browseURL})
	// 	//w.pdoc.TestSourceSize += len(w.srcs[name].data)
	// 	w.examples = append(w.examples, doc.Examples(file)...)
	// }

	//w.vetPackage(apkg)

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

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

	w.pdoc.Synopsis = utils.Synopsis(pdoc.Doc)
	pdoc.Doc = strings.TrimRight(pdoc.Doc, " \t\n\r")
	var buf bytes.Buffer
	doc.ToHTML(&buf, pdoc.Doc, nil)
	w.pdoc.Doc = w.pdoc.Doc + "<br />" + buf.String()
	w.pdoc.Doc = strings.Replace(w.pdoc.Doc, "<p>", "<p><b>", 1)
	w.pdoc.Doc = strings.Replace(w.pdoc.Doc, "</p>", "</b></p>", 1)
	w.pdoc.Doc = base32.StdEncoding.EncodeToString([]byte(w.pdoc.Doc))

	//w.pdoc.Examples = w.getExamples("")
	//w.pdoc.IsCmd = bpkg.IsCommand()
	w.pdoc.GOOS = ctxt.GOOS
	w.pdoc.GOARCH = ctxt.GOARCH

	w.srcLines = make(map[string][]string)
	w.pdoc.Consts = w.values(pdoc.Consts)
	w.pdoc.Funcs = w.funcs(pdoc.Funcs)
	w.pdoc.Types = w.types(pdoc.Types)
	w.pdoc.Vars = w.values(pdoc.Vars)
	//w.pdoc.Notes = w.notes(pdoc.Notes)

	w.pdoc.Imports = bpkg.Imports
	w.pdoc.TestImports = bpkg.TestImports
	//w.pdoc.XTestImports = bpkg.XTestImports

	beego.Info("doc.walker.build(", pdoc.ImportPath, "), Goroutine #", runtime.NumGoroutine())
	return w.pdoc, err
}
Example #19
0
func (b *builder) build(srcs []*source) (*Package, error) {

	b.pdoc.Updated = time.Now().UTC()

	references := make(map[string]bool)
	b.srcs = make(map[string]*source)
	for _, src := range srcs {
		if strings.HasSuffix(src.name, ".go") {
			b.srcs[src.name] = src
		} else {
			addReferences(references, src.data)

			fn := strings.ToLower(src.name)
			if fn == "readme" || strings.HasPrefix(fn, "readme.") {
				if b.pdoc.ReadmeFiles == nil {
					b.pdoc.ReadmeFiles = make(map[string][]byte)
				}

				b.pdoc.ReadmeFiles[src.name] = src.data
			}
		}
	}

	for r := range references {
		b.pdoc.References = append(b.pdoc.References, r)
	}

	if len(b.srcs) == 0 {
		return b.pdoc, nil
	}

	b.fset = token.NewFileSet()

	// Find the package and associated files.

	ctxt := build.Context{
		GOOS:          "linux",
		GOARCH:        "amd64",
		CgoEnabled:    true,
		ReleaseTags:   build.Default.ReleaseTags,
		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 b.readDir(dir) },
		OpenFile:      func(path string) (r io.ReadCloser, err error) { return b.openFile(path) },
		Compiler:      "gc",
	}

	var err error
	var bpkg *build.Package

	for _, env := range goEnvs {
		ctxt.GOOS = env.GOOS
		ctxt.GOARCH = env.GOARCH
		bpkg, err = ctxt.ImportDir("/", 0)
		if _, ok := err.(*build.NoGoError); !ok {
			break
		}
	}
	if err != nil {
		if _, ok := err.(*build.NoGoError); !ok {
			b.pdoc.Errors = append(b.pdoc.Errors, err.Error())
		}
		return b.pdoc, nil
	}

	// Parse the Go files

	files := make(map[string]*ast.File)
	names := append(bpkg.GoFiles, bpkg.CgoFiles...)
	sort.Strings(names)
	b.pdoc.Files = make([]*File, len(names))
	for i, name := range names {
		file, err := parser.ParseFile(b.fset, name, b.srcs[name].data, parser.ParseComments)
		if err != nil {
			b.pdoc.Errors = append(b.pdoc.Errors, err.Error())
			continue
		}
		src := b.srcs[name]
		src.index = i
		b.pdoc.Files[i] = &File{Name: name, URL: src.browseURL}
		b.pdoc.SourceSize += len(src.data)
		files[name] = file
	}

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

	// Find examples in the test files.

	names = append(bpkg.TestGoFiles, bpkg.XTestGoFiles...)
	sort.Strings(names)
	b.pdoc.TestFiles = make([]*File, len(names))
	for i, name := range names {
		file, err := parser.ParseFile(b.fset, name, b.srcs[name].data, parser.ParseComments)
		if err != nil {
			b.pdoc.Errors = append(b.pdoc.Errors, err.Error())
			continue
		}
		b.pdoc.TestFiles[i] = &File{Name: name, URL: b.srcs[name].browseURL}
		b.pdoc.TestSourceSize += len(b.srcs[name].data)
		b.examples = append(b.examples, doc.Examples(file)...)
	}

	b.vetPackage(apkg)

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

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

	b.pdoc.Name = dpkg.Name
	b.pdoc.Doc = strings.TrimRight(dpkg.Doc, " \t\n\r")
	b.pdoc.Synopsis = synopsis(b.pdoc.Doc)

	b.pdoc.Examples = b.getExamples("")
	b.pdoc.IsCmd = bpkg.IsCommand()
	b.pdoc.GOOS = ctxt.GOOS
	b.pdoc.GOARCH = ctxt.GOARCH

	b.pdoc.Consts = b.values(dpkg.Consts)
	b.pdoc.Funcs = b.funcs(dpkg.Funcs)
	b.pdoc.Types = b.types(dpkg.Types)
	b.pdoc.Vars = b.values(dpkg.Vars)
	b.pdoc.Notes = b.notes(dpkg.Notes)

	b.pdoc.Imports = bpkg.Imports
	b.pdoc.TestImports = bpkg.TestImports
	b.pdoc.XTestImports = bpkg.XTestImports

	return b.pdoc, nil
}
Example #20
0
// Build generates documentation from given source files through 'WalkType'.
func (w *Walker) Build(wr *WalkRes) (*Package, error) {
	ctxt := build.Context{
		CgoEnabled:  true,
		ReleaseTags: build.Default.ReleaseTags,
		BuildTags:   build.Default.BuildTags,
		Compiler:    "gc",
	}

	if w.Pdoc.PkgDecl == nil {
		w.Pdoc.PkgDecl = &PkgDecl{}
	}

	// Check 'WalkType'.
	switch wr.WalkType {
	case WT_Local:
		// Check root path.
		if len(wr.RootPath) == 0 {
			return nil, errors.New("WT_Local: empty root path")
		} else if !com.IsDir(wr.RootPath) {
			return nil, errors.New("WT_Local: cannot find specific directory or it's a file")
		}

		w.setLocalContext(&ctxt)
		return nil, errors.New("Hasn't supported yet!")
	case WT_Memory:
		// Convert source files.
		w.SrcFiles = make(map[string]*Source)
		w.Pdoc.Readme = make(map[string][]byte)
		for _, src := range wr.Srcs {
			srcName := strings.ToLower(src.Name()) // For readme comparation.
			switch {
			case strings.HasSuffix(src.Name(), ".go"):
				w.SrcFiles[src.Name()] = src
			case len(w.Pdoc.Tag) > 0 || (wr.WalkMode&WM_NoReadme != 0):
				// This means we are not on the latest version of the code,
				// so we do not collect the README files.
				continue
			case strings.HasPrefix(srcName, "readme_zh") || strings.HasPrefix(srcName, "readme_cn"):
				w.Pdoc.Readme["zh"] = src.Data()
			case strings.HasPrefix(srcName, "readme"):
				w.Pdoc.Readme["en"] = src.Data()
			}
		}

		// Check source files.
		if w.SrcFiles == nil {
			return nil, errors.New("WT_Memory: no Go source file")
		}

		w.setMemoryContext(&ctxt)

	default:
		return nil, errors.New("Hasn't supported yet!")
	}

	var err error
	var bpkg *build.Package

	for _, env := range goEnvs {
		ctxt.GOOS = env.GOOS
		ctxt.GOARCH = env.GOARCH

		bpkg, err = ctxt.ImportDir(w.Pdoc.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("hv.Walker.Build -> ImportDir: " + err.Error())
			}
		}
	}

	w.Pdoc.IsCmd = bpkg.IsCommand()
	w.Pdoc.Synopsis = synopsis(bpkg.Doc)

	w.Pdoc.Imports = bpkg.Imports
	w.Pdoc.IsCgo = w.isCgo()
	w.Pdoc.TestImports = bpkg.TestImports

	// Check depth.
	if wr.WalkDepth <= WD_Imports {
		return w.Pdoc, nil
	}

	w.Fset = token.NewFileSet()
	// 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.SrcFiles[name].Data(), parser.ParseComments)
		if err != nil {
			return nil, errors.New("hv.Walker.Build -> parse Go files: " + err.Error())
			continue
		}
		w.Pdoc.Files = append(w.Pdoc.Files, w.SrcFiles[name])
		w.Pdoc.SourceSize += int64(len(w.SrcFiles[name].Data()))
		files[name] = file
	}

	w.apkg, _ = ast.NewPackage(w.Fset, files, poorMansImporter, nil)

	// Find examples in the test files.
	for _, name := range append(bpkg.TestGoFiles, bpkg.XTestGoFiles...) {
		file, err := parser.ParseFile(w.Fset, name, w.SrcFiles[name].Data(), parser.ParseComments)
		if err != nil {
			return nil, errors.New("hv.Walker.Build -> find examples: " + err.Error())
			continue
		}
		w.Pdoc.TestFiles = append(w.Pdoc.TestFiles, w.SrcFiles[name])
		//w.pdoc.TestSourceSize += len(w.srcs[name].data)

		if wr.WalkMode&WM_NoExample != 0 {
			continue
		}
		w.Examples = append(w.Examples, doc.Examples(file)...)
	}

	mode := doc.Mode(0)
	if w.Pdoc.ImportPath == "builtin" || wr.BuildAll {
		mode |= doc.AllDecls
	}
	pdoc := doc.New(w.apkg, w.Pdoc.ImportPath, mode)

	// Get doc.
	pdoc.Doc = strings.TrimRight(pdoc.Doc, " \t\n\r")
	var buf bytes.Buffer
	doc.ToHTML(&buf, pdoc.Doc, nil)
	w.Pdoc.Doc = buf.String()
	// Highlight first sentence.
	w.Pdoc.Doc = strings.Replace(w.Pdoc.Doc, "<p>", "<p><b>", 1)
	w.Pdoc.Doc = strings.Replace(w.Pdoc.Doc, "</p>", "</b></p>", 1)

	if wr.WalkMode&WM_NoExample == 0 {
		w.getExamples()
	}

	w.SrcLines = make(map[string][]string)
	w.Pdoc.Consts = w.values(pdoc.Consts)
	w.Pdoc.Funcs, w.Pdoc.Ifuncs = w.funcs(pdoc.Funcs)
	w.Pdoc.Types, w.Pdoc.Itypes = w.types(pdoc.Types)
	w.Pdoc.Vars = w.values(pdoc.Vars)
	//w.Pdoc.Notes = w.notes(pdoc.Notes)

	return w.Pdoc, nil
}