Example #1
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 #2
0
func (ctx *Context) loadPackage(importPath string, flags int) (*Package, error) {
	bpkg, err := build.Import(importPath, ctx.cwd, 0)
	if _, ok := err.(*build.NoGoError); ok {
		return &Package{bpkg: bpkg}, nil
	}
	if err != nil {
		return nil, err
	}

	pkg := &Package{
		fset: token.NewFileSet(),
		bpkg: bpkg,
	}

	files := make(map[string]*ast.File)
	for _, name := range append(pkg.bpkg.GoFiles, pkg.bpkg.CgoFiles...) {
		file, err := pkg.parseFile(name)
		if err != nil {
			pkg.errors = append(pkg.errors, err)
			continue
		}
		files[name] = file
	}

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

	if flags&loadDoc != 0 {
		mode := doc.Mode(0)
		if pkg.bpkg.ImportPath == "builtin" || flags&loadUnexported != 0 {
			mode |= doc.AllDecls
		}
		pkg.dpkg = doc.New(pkg.apkg, pkg.bpkg.ImportPath, mode)
		if pkg.bpkg.ImportPath == "builtin" {
			for _, t := range pkg.dpkg.Types {
				pkg.dpkg.Funcs = append(pkg.dpkg.Funcs, t.Funcs...)
				t.Funcs = nil
			}
			sort.Sort(byFuncName(pkg.dpkg.Funcs))
		}
	}

	if flags&loadExamples != 0 {
		for _, name := range append(pkg.bpkg.TestGoFiles, pkg.bpkg.XTestGoFiles...) {
			file, err := pkg.parseFile(name)
			if err != nil {
				pkg.errors = append(pkg.errors, err)
				continue
			}
			pkg.examples = append(pkg.examples, doc.Examples(file)...)
		}
	}

	return pkg, nil
}
Example #3
0
func main() {
	flag.Parse()
	fset := token.NewFileSet()
	nheadings := 0
	err := filepath.Walk(*root, func(path string, fi os.FileInfo, err error) error {
		if !fi.IsDir() {
			return nil
		}
		pkgs, err := parser.ParseDir(fset, path, isGoFile, parser.ParseComments)
		if err != nil {
			if *verbose {
				fmt.Fprintln(os.Stderr, err)
			}
			return nil
		}
		for _, pkg := range pkgs {
			d := doc.New(pkg, path, doc.Mode(0))
			list := appendHeadings(nil, d.Doc)
			for _, d := range d.Consts {
				list = appendHeadings(list, d.Doc)
			}
			for _, d := range d.Types {
				list = appendHeadings(list, d.Doc)
			}
			for _, d := range d.Vars {
				list = appendHeadings(list, d.Doc)
			}
			for _, d := range d.Funcs {
				list = appendHeadings(list, d.Doc)
			}
			if len(list) > 0 {
				// directories may contain multiple packages;
				// print path and package name
				fmt.Printf("%s (package %s)\n", path, pkg.Name)
				for _, h := range list {
					fmt.Printf("\t%s\n", h)
				}
				nheadings += len(list)
			}
		}
		return nil
	})
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
	fmt.Println(nheadings, "headings found")
}
Example #4
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 #5
0
func newPackage(dir *gosrc.Directory) (*Package, error) {

	pkg := &Package{
		Updated:        time.Now().UTC(),
		LineFmt:        dir.LineFmt,
		ImportPath:     dir.ImportPath,
		ProjectRoot:    dir.ProjectRoot,
		ProjectName:    dir.ProjectName,
		ProjectURL:     dir.ProjectURL,
		BrowseURL:      dir.BrowseURL,
		Etag:           PackageVersion + "-" + dir.Etag,
		VCS:            dir.VCS,
		DeadEndFork:    dir.DeadEndFork,
		Subdirectories: dir.Subdirectories,
	}

	var b builder
	b.srcs = make(map[string]*source)
	references := make(map[string]bool)
	for _, file := range dir.Files {
		if strings.HasSuffix(file.Name, ".go") {
			gosrc.OverwriteLineComments(file.Data)
			b.srcs[file.Name] = &source{name: file.Name, browseURL: file.BrowseURL, data: file.Data}
		} else {
			addReferences(references, file.Data)
		}
	}

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

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

	b.fset = token.NewFileSet()

	// Find the package and associated files.

	ctxt := build.Context{
		GOOS:        "linux",
		GOARCH:      "amd64",
		CgoEnabled:  true,
		ReleaseTags: build.Default.ReleaseTags,
		BuildTags:   build.Default.BuildTags,
		Compiler:    "gc",
	}

	var err error
	var bpkg *build.Package

	for _, env := range goEnvs {
		ctxt.GOOS = env.GOOS
		ctxt.GOARCH = env.GOARCH
		// TODO(garyburd): Change second argument to build.ImportComment when
		// gddo is upgraded to Go 1.4.
		bpkg, err = dir.Import(&ctxt, 0 /* build.ImportComment */)
		if _, ok := err.(*build.NoGoError); !ok {
			break
		}
	}
	if err != nil {
		if _, ok := err.(*build.NoGoError); !ok {
			pkg.Errors = append(pkg.Errors, err.Error())
		}
		return pkg, nil
	}

	/*
		        TODO(garyburd): This block of code uses the import comment feature
		        added in Go 1.4. Uncomment this block when gddo upgraded to Go 1.4.
		        Also, change the second argument to dir.Import above from 0 to
		        build.ImportComment.

				if bpkg.ImportComment != "" && bpkg.ImportComment != dir.ImportPath {
					return nil, gosrc.NotFoundError{
						Message:  "not at canonical import path",
						Redirect: bpkg.ImportComment,
					}
				}
	*/

	// Parse the Go files

	files := make(map[string]*ast.File)
	names := append(bpkg.GoFiles, bpkg.CgoFiles...)
	sort.Strings(names)
	pkg.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 {
			pkg.Errors = append(pkg.Errors, err.Error())
		} else {
			files[name] = file
		}
		src := b.srcs[name]
		src.index = i
		pkg.Files[i] = &File{Name: name, URL: src.browseURL}
		pkg.SourceSize += len(src.data)
	}

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

	// Find examples in the test files.

	names = append(bpkg.TestGoFiles, bpkg.XTestGoFiles...)
	sort.Strings(names)
	pkg.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 {
			pkg.Errors = append(pkg.Errors, err.Error())
		} else {
			b.examples = append(b.examples, doc.Examples(file)...)
		}
		pkg.TestFiles[i] = &File{Name: name, URL: b.srcs[name].browseURL}
		pkg.TestSourceSize += len(b.srcs[name].data)
	}

	b.vetPackage(pkg, apkg)

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

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

	if pkg.ImportPath == "builtin" {
		removeAssociations(dpkg)
	}

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

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

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

	pkg.Imports = bpkg.Imports
	pkg.TestImports = bpkg.TestImports
	pkg.XTestImports = bpkg.XTestImports

	return pkg, nil
}
Example #6
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 #7
0
func buildDoc(importPath, projectRoot, projectName, projectURL, browseURL, 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,
			BrowseURL:   browseURL,
			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 _, 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 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.Imports = pkg.Imports
	b.pkg.TestImports = pkg.TestImports

	return b.pkg, nil
}
Example #8
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
}
Example #9
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 #10
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 #11
0
// build gets imports from source files.
func (w *walker) build(srcs []*source, nod *Node) ([]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 {
			log.Warn("walker: %s", err.Error())
			return nil, nil
		}
	}

	// 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 !IsGoRepoPath(v) &&
			(GetProjectPath(v) != GetProjectPath(w.ImportPath)) {
			imports = append(imports, v)
		}
	}

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

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

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

	if nod != nil {
		nod.Synopsis = Synopsis(pdoc.Doc)
		if i := strings.Index(nod.Synopsis, "\n"); i > -1 {
			nod.Synopsis = nod.Synopsis[:i]
		}
	}

	return imports, err
}
Example #12
0
// loadPackage returns details about the Go package named by the import
// path, interpreting local import paths relative to the srcDir directory.
func loadPackage(ctx *build.Context, importPath string, srcDir string, flags int) (*pkg, error) {
	bpkg, err := ctx.Import(importPath, srcDir, build.ImportComment)
	if _, ok := err.(*build.NoGoError); ok {
		return &pkg{Build: bpkg}, nil
	}
	if err != nil {
		return nil, err
	}

	pkg := &pkg{
		FSet:  token.NewFileSet(),
		Build: bpkg,
	}

	files := make(map[string]*ast.File)
	for _, name := range append(pkg.Build.GoFiles, pkg.Build.CgoFiles...) {
		file, err := pkg.parseFile(ctx, name)
		if err != nil {
			pkg.Errors = append(pkg.Errors, err)
			continue
		}
		files[name] = file
	}

	vendor := make(map[string]string)
	pkg.AST, _ = ast.NewPackage(pkg.FSet, files, importer(ctx, bpkg.Dir, vendor), nil)

	if flags&loadPackageFixVendor != 0 {
		for _, f := range pkg.AST.Files {
			for _, i := range f.Imports {
				if lit := i.Path; lit != nil {
					if s, err := strconv.Unquote(lit.Value); err != nil {
						if p, ok := vendor[s]; ok {
							lit.Value = strconv.Quote(p)
						}
					}
				}
			}
		}
	}

	if flags&loadPackageDoc != 0 {
		mode := godoc.Mode(0)
		if pkg.Build.ImportPath == "builtin" || flags&loadPackageUnexported != 0 {
			mode |= godoc.AllDecls
		}
		pkg.GoDoc = godoc.New(pkg.AST, pkg.Build.ImportPath, mode)
		if pkg.Build.ImportPath == "builtin" {
			for _, t := range pkg.GoDoc.Types {
				pkg.GoDoc.Funcs = append(pkg.GoDoc.Funcs, t.Funcs...)
				t.Funcs = nil
			}
			sort.Sort(byFuncName(pkg.GoDoc.Funcs))
		}
	}

	if flags&loadPackageExamples != 0 {
		for _, name := range append(pkg.Build.TestGoFiles, pkg.Build.XTestGoFiles...) {
			file, err := pkg.parseFile(ctx, name)
			if err != nil {
				pkg.Errors = append(pkg.Errors, err)
				continue
			}
			pkg.Examples = append(pkg.Examples, godoc.Examples(file)...)
		}
	}

	return pkg, nil
}