//ParseDocs parses the Package's documentation with go/doc. // //If you do not need a particular doc.Mode call this with 0. // //If the package directory contains a file of package documentation //(and the package is not itself named documentation), it is parsed //and its doc.Package.Doc string replaces the string generated //by the package itself. // //Note that the go/doc package munges the AST so this method parses the AST //again, regardless of the value in p.AST. As a consequence, it is valid //to call this even if you have not called the Parse method or if you have //called the Parse method and told it not to parse comments. func (p *Package) ParseDocs(mode doc.Mode) error { if p.Doc != nil { return nil } pkg, _, err := p.parse(true) if err != nil { return err } p.Doc = doc.New(pkg, p.Build.ImportPath, mode) //we don't want the below running if we happen to be importing a package //whose name happens to be documentation. if p.Build.Name == "documentation" { return nil } //check ignored files for any package named documentation. //assume there is only one such file. //We ignore errors here as the ignored files may not be meant to parse. var docfile string for _, u := range p.Build.IgnoredGoFiles { path := filepath.Join(p.Build.Dir) fs := token.NewFileSet() f, err := parser.ParseFile(fs, path, nil, parser.PackageClauseOnly) if err != nil { continue } if f.Name.Name == "documentation" { docfile = u break } } //there's an ignored file of package documentation, //parse it and replace the package doc string with this doc string. if docfile != "" { fs := token.NewFileSet() f := func(fi os.FileInfo) bool { return !fi.IsDir() && fi.Name() == docfile } pkgs, err := parser.ParseDir(fs, p.Build.Dir, f, parser.ParseComments) if err != nil { return err } d := doc.New(pkgs["documentation"], p.Build.ImportPath, 0) p.Doc.Doc = d.Doc } return nil }
func getPageInfo(pkgName, diskPath string) (pi PageInfo, err error) { bpkg, err := build.ImportDir(diskPath, 0) if err != nil { return } inSet := make(map[string]bool) for _, name := range bpkg.GoFiles { inSet[filepath.Base(name)] = true } pi.FSet = token.NewFileSet() filter := func(fi os.FileInfo) bool { return inSet[fi.Name()] } aPkgMap, err := parser.ParseDir(pi.FSet, diskPath, filter, 0) if err != nil { return } aPkg := aPkgMap[pathpkg.Base(pkgName)] if aPkg == nil { for _, v := range aPkgMap { aPkg = v break } if aPkg == nil { err = errors.New("no apkg found?") return } } pi.Dirname = diskPath pi.PDoc = doc.New(aPkg, pkgName, 0) pi.IsMain = strings.Contains(pkgName, "camlistore.org/cmd/") return }
func packageComment(pkg, pkgpath string) (info string, err error) { fset := token.NewFileSet() pkgs, err := parser.ParseDir(fset, pkgpath, isGoFile, parser.PackageClauseOnly|parser.ParseComments) if err != nil { return } for name := range pkgs { if name == "main" { continue } pdoc := doc.New(pkgs[name], pkg, doc.AllDecls) if pdoc.Doc == "" { continue } if info != "" { return "", errors.New("multiple packages with docs") } info = pdoc.Doc } // grab only first paragraph if parts := strings.SplitN(info, "\n\n", 2); len(parts) > 1 { info = parts[0] } // replace newlines with spaces info = strings.Replace(info, "\n", " ", -1) // truncate if len(info) > MaxCommentLength { info = info[:MaxCommentLength] } return }
func ReflectDefs() (names map[string][]byte, err error) { b, err := build.Import("reflect", "", 0) if err != nil { return nil, err } ts := token.NewFileSet() p, err := parser.ParseDir(ts, b.Dir, gofiles, 0) if err != nil { return nil, err } pkg := doc.New(p["reflect"], "reflect", doc.AllMethods) acc := []string{} acc = values(pkg.Consts, acc) acc = values(pkg.Vars, acc) acc = funcs(pkg.Funcs, "reflect.", acc) acc = types(pkg.Types, acc) names = map[string][]byte{} for _, name := range acc { names[name] = []byte(name) } return names, nil }
func main() { pkg, err := build.Import("robpike.io/ivy", "", build.ImportComment) if err != nil { log.Fatal(err) } fs := token.NewFileSet() pkgs, err := parser.ParseDir(fs, pkg.Dir, nil, parser.ParseComments) if err != nil { log.Fatal(err) } astPkg := pkgs[pkg.Name] if astPkg == nil { log.Fatalf("failed to locate %s package", pkg.Name) } docPkg := doc.New(astPkg, pkg.ImportPath, doc.AllDecls) htmlBuf := new(bytes.Buffer) fmt.Fprintln(htmlBuf, `<!-- auto-generated from robpike.io/ivy package doc -->`) fmt.Fprintln(htmlBuf, head) fmt.Fprintln(htmlBuf, `<body>`) doc.ToHTML(htmlBuf, docPkg.Doc, nil) fmt.Fprintln(htmlBuf, `</body></html>`) goBuf := new(bytes.Buffer) fmt.Fprintf(goBuf, "package mobile\n\n") fmt.Fprintf(goBuf, "// GENERATED; DO NOT EDIT\n") fmt.Fprintf(goBuf, "const help = `%s`\n", sanitize(htmlBuf.Bytes())) buf, err := format.Source(goBuf.Bytes()) if err != nil { log.Fatalf("failed to gofmt: %v", err) } os.Stdout.Write(buf) }
// 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) }
func main() { flag.Parse() if len(flag.Args()) != 1 { log.Fatal("Usage: go run goprint.go path") } bpkg, err := build.Default.Import(flag.Args()[0], ".", 0) if err != nil { log.Fatal(err) } fset := token.NewFileSet() files := make(map[string]*ast.File) for _, fname := range bpkg.GoFiles { p, err := ioutil.ReadFile(filepath.Join(bpkg.SrcRoot, bpkg.ImportPath, fname)) if err != nil { log.Fatal(err) } file, err := parser.ParseFile(fset, fname, p, parser.ParseComments) if err != nil { log.Fatal(err) } files[fname] = file } c := spew.NewDefaultConfig() c.DisableMethods = true apkg, _ := ast.NewPackage(fset, files, importer, nil) c.Dump(apkg) ast.Print(fset, apkg) dpkg := doc.New(apkg, bpkg.ImportPath, 0) c.Dump(dpkg) }
func NewPackageView(pkg *ast.Package, fset *token.FileSet, expr bool) (*PackageView, error) { p := new(PackageView) p.fset = fset p.pkg = pkg p.pdoc = doc.New(pkg, pkg.Name, doc.AllDecls) p.expr = expr return p, nil }
func ExtractStructs(inputPath string) (string, []*StructInfo, error) { fset := token.NewFileSet() f, err := parser.ParseFile(fset, inputPath, nil, parser.ParseComments) if err != nil { return "", nil, err } packageName := f.Name.String() structs := make(map[string]*StructInfo) for k, d := range f.Scope.Objects { if d.Kind == ast.Typ { incl, err := shouldInclude(d) if err != nil { return "", nil, err } if incl { stobj := NewStructInfo(k) structs[k] = stobj } } } files := map[string]*ast.File{ inputPath: f, } pkg, _ := ast.NewPackage(fset, files, nil, nil) d := doc.New(pkg, f.Name.String(), doc.AllDecls) for _, t := range d.Types { if skipre.MatchString(t.Doc) { delete(structs, t.Name) } else { if skipdec.MatchString(t.Doc) { s, ok := structs[t.Name] if ok { s.Options.SkipDecoder = true } } if skipenc.MatchString(t.Doc) { s, ok := structs[t.Name] if ok { s.Options.SkipEncoder = true } } } } rv := make([]*StructInfo, 0) for _, v := range structs { rv = append(rv, v) } return packageName, rv, nil }
// 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 }
func getDoc(dir string) (Doc, error) { bi, err := build.ImportDir(dir, 0) if err != nil { return Doc{}, nil } ip, err := importPath(dir) if err != nil { return Doc{}, err } filter := func(fi os.FileInfo) bool { if fi.IsDir() { return false } nm := fi.Name() for _, f := range append(bi.GoFiles, bi.CgoFiles...) { if nm == f { return true } } return false } pkgs, err := parser.ParseDir(token.NewFileSet(), bi.Dir, filter, parser.ParseComments) if err != nil { return Doc{}, err } pkg := pkgs[bi.Name] docs := doc.New(pkg, bi.ImportPath, 0) bugs := []string{} for _, bug := range docs.Notes["BUG"] { bugs = append(bugs, bug.Body) } name := bi.Name if name == "main" { name = filepath.Base(bi.Dir) } //get import path without the github.com/ pathelms := strings.Split(ip, "/")[1:] repo := path.Join(pathelms...) return Doc{ Name: name, Import: ip, Synopsis: bi.Doc, Doc: fmtDoc(docs.Doc), Today: today(), RepoPath: repo, Bugs: bugs, Library: bi.Name != "main", Command: bi.Name == "main", }, nil }
func run() error { pkg, err := build.Import("euphoria.io/heim/proto", "", build.FindOnly) if err != nil { return fmt.Errorf("import error: %s", err) } if pkg.SrcRoot == "" { return fmt.Errorf("error: can't find source for package euphoria.io/heim/proto") } pkgs, err := parser.ParseDir( token.NewFileSet(), filepath.Join(pkg.SrcRoot, "euphoria.io/heim/proto"), nil, parser.ParseComments) if err != nil { return fmt.Errorf("parse error: %s", err) } obs := (*objects)(doc.New(pkgs["proto"], "euphoria.io/heim/proto", 0)) ps := sortObjects(obs) ts := types{} t := template.New("api.md").Funcs(template.FuncMap{ "object": obs.tmplObject, "others": ps.tmplOthers, "packet": ps.tmplPacket, "linkType": ts.linkType, "registerType": ts.registerType, }) ts.registerType("bool") ts.registerType("int") ts.registerType("object") ts.registerType("string") ts.registerType("AccountView") ts.registerType("AuthOption") ts.registerType("Message") ts.registerType("PacketType") ts.registerType("PersonalAccountView") ts.registerType("SessionView") ts.registerType("Snowflake") ts.registerType("Time") ts.registerType("UserID") gendir := filepath.Join(pkg.SrcRoot, "euphoria.io/heim/doc/gen") if err := os.Chdir(gendir); err != nil { return fmt.Errorf("chdir error: %s: %s", gendir, err) } if _, err := t.ParseGlob("*.md"); err != nil { return fmt.Errorf("template parse error: %s", err) } if err := t.Execute(os.Stdout, nil); err != nil { return fmt.Errorf("template render error: %s", err) } return nil }
func NewPackageDeclFromAstPackage(astPkg *ast.Package, fullImportPath string) *PackageDecl { output := &PackageDecl{TypeMap: make(map[string]*TypeDecl)} docPkg := doc.New(astPkg, fullImportPath, doc.AllMethods) for _, t := range docPkg.Types { output.TypeMap[t.Name] = NewTypeDeclFromDocType(t) } return output }
func tryImport(root, relpath string) error { path := filepath.Join(root, relpath) ctx := build.Default dir, err := ctx.ImportDir(path, 0) if _, nogo := err.(*build.NoGoError); nogo { return nil } if err != nil { return fmt.Errorf("ImportDir failed: %v", err) } pkgFiles := append(dir.GoFiles, dir.CgoFiles...) fullPkgsFiles := make([]string, 0, len(pkgFiles)) for _, p := range pkgFiles { fullPkgsFiles = append(fullPkgsFiles, filepath.Join(path, p)) } pkg, err := parseFiles(fullPkgsFiles) if err != nil { if err == errNoPackagesFound { // that error is eaten silently return nil } return fmt.Errorf("Failed to parse pkg %s/%s: %v", root, relpath, err) } pdoc := doc.New(pkg, relpath, 0) outputValues(relpath, pdoc.Consts, "#pkg-constants", "const") outputValues(relpath, pdoc.Vars, "#pkg-variables", "var") for _, tp := range pdoc.Types { outputCDB(relpath+"/"+tp.Name+" "+ppType(tp)+maybeDoc(tp.Doc, tp.Name), "godoc:"+relpath+"#"+tp.Name) for _, fun := range tp.Methods { typename := fun.Recv if typename[0] == '*' { typename = typename[1:] } outputCDB(buildFuncKey(relpath, fun), "godoc:"+relpath+"#"+typename+"."+fun.Name) } for _, fun := range tp.Funcs { outputCDB(buildFuncKey(relpath, fun), "godoc:"+relpath+"#"+fun.Name) } } for _, fun := range pdoc.Funcs { outputCDB(buildFuncKey(relpath, fun), "godoc:"+relpath+"#"+fun.Name) } return nil }
func getDocPackageMode(bpkg *build.Package, err error, mode doc.Mode) (dpkg *doc.Package, err2 error) { if err != nil { return nil, err } apkg, err := AstPackageFromBuildPackage(bpkg) if err != nil { return nil, err } return doc.New(apkg, bpkg.ImportPath, mode), nil }
//ExtractStructs extract struct infos from file func ExtractStructs(inputPath string) (string, []*ActStructInfo, error) { fset := token.NewFileSet() f, err := parser.ParseFile(fset, inputPath, nil, parser.ParseComments) if err != nil { return "", nil, err } packageName := f.Name.String() structs := make(map[string]*ActStructInfo) for k, d := range f.Scope.Objects { if d.Kind == ast.Typ { ts, ok := d.Decl.(*ast.TypeSpec) if !ok { return "", nil, fmt.Errorf("Unknown type without TypeSec: %v", d) } _, ok = ts.Type.(*ast.StructType) if !ok { _, ok = ts.Type.(*ast.ArrayType) if !ok { _, ok = ts.Type.(*ast.MapType) if !ok { continue } } } stobj := NewStructInfo(k) structs[k] = stobj } } files := map[string]*ast.File{ inputPath: f, } pkg, _ := ast.NewPackage(fset, files, nil, nil) d := doc.New(pkg, f.Name.String(), doc.AllDecls) for _, t := range d.Types { if skipre.MatchString(t.Doc) { delete(structs, t.Name) } } var rv []*ActStructInfo for _, v := range structs { rv = append(rv, v) } return packageName, rv, nil }
// parsePackage turns the build package we found into a parsed package // we can then use to generate documentation. func parsePackage(writer io.Writer, pkg *build.Package, userPath string) *Package { fs := token.NewFileSet() // include tells parser.ParseDir which files to include. // That means the file must be in the build package's GoFiles or CgoFiles // list only (no tag-ignored files, tests, swig or other non-Go files). include := func(info os.FileInfo) bool { for _, name := range pkg.GoFiles { if name == info.Name() { return true } } for _, name := range pkg.CgoFiles { if name == info.Name() { return true } } return false } pkgs, err := parser.ParseDir(fs, pkg.Dir, include, parser.ParseComments) if err != nil { log.Fatal(err) } // Make sure they are all in one package. if len(pkgs) != 1 { log.Fatalf("multiple packages in directory %s", pkg.Dir) } astPkg := pkgs[pkg.Name] // TODO: go/doc does not include typed constants in the constants // list, which is what we want. For instance, time.Sunday is of type // time.Weekday, so it is defined in the type but not in the // Consts list for the package. This prevents // go doc time.Sunday // from finding the symbol. Work around this for now, but we // should fix it in go/doc. // A similar story applies to factory functions. docPkg := doc.New(astPkg, pkg.ImportPath, doc.AllDecls) for _, typ := range docPkg.Types { docPkg.Consts = append(docPkg.Consts, typ.Consts...) docPkg.Vars = append(docPkg.Vars, typ.Vars...) docPkg.Funcs = append(docPkg.Funcs, typ.Funcs...) } return &Package{ writer: writer, name: pkg.Name, userPath: userPath, pkg: astPkg, file: ast.MergePackageFiles(astPkg, 0), doc: docPkg, build: pkg, fs: fs, } }
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 }
func ParsePackageInfo(name, lang string) (pkg *PackageInfo, err error) { type PkgInfo struct { Dir string // directory containing package sources Name string // package name ImportPath string // import path of package in dir } var pkgInfo PkgInfo listOut, err := exec.Command(`go`, `list`, `-json`, name).Output() if err != nil { return } err = json.Unmarshal(listOut, &pkgInfo) if err != nil { return } fset := token.NewFileSet() past, err := parser.ParseDir(fset, pkgInfo.Dir, func(fi os.FileInfo) bool { if strings.HasSuffix(fi.Name(), "_test.go") { return false } return true }, parser.ParseComments, ) if err != nil { return } var mode doc.Mode if pkgInfo.ImportPath == "builtin" { mode = doc.AllDecls } pdoc := doc.New(past[pkgInfo.Name], pkgInfo.ImportPath, mode) pdocLocal := local.Package(lang, pkgInfo.ImportPath) pkg = &PackageInfo{ Lang: lang, FSet: fset, PAst: past[pkgInfo.Name], PDoc: pdoc, PDocLocal: pdocLocal, PDocMap: make(map[string]string), } pkg.initDocTable("", pkg.PDoc) if pkg.PDocLocal != nil { pkg.initDocTable(lang, pkg.PDocLocal) } return }
func getPageInfo(pkgName, diskPath string) (pi PageInfo, err error) { if pkgName == pathpkg.Join(domainName, pkgPattern) || pkgName == pathpkg.Join(domainName, cmdPattern) || pkgName == pathpkg.Join(domainName, appPattern) { pi.Dirname = diskPath pi.populateDirs(diskPath, -1) return } bpkg, err := build.ImportDir(diskPath, 0) if err != nil { if _, ok := err.(*build.NoGoError); ok { pi.populateDirs(diskPath, -1) return pi, nil } return } inSet := make(map[string]bool) for _, name := range bpkg.GoFiles { if name == fileembedPattern { continue } inSet[filepath.Base(name)] = true } pi.FSet = token.NewFileSet() filter := func(fi os.FileInfo) bool { return inSet[fi.Name()] } aPkgMap, err := parser.ParseDir(pi.FSet, diskPath, filter, parser.ParseComments) if err != nil { return } aPkg := aPkgMap[pathpkg.Base(pkgName)] if aPkg == nil { for _, v := range aPkgMap { aPkg = v break } if aPkg == nil { err = errors.New("no apkg found?") return } } pi.Dirname = diskPath pi.PDoc = doc.New(aPkg, pkgName, 0) pi.IsPkg = strings.Contains(pkgName, domainName+pkgPattern) // get directory information pi.populateDirs(diskPath, -1) return }
func (e Environment) _importPackage(p string, shallow bool) (*Package, error) { b, err := e.importBuildPackage(p) if err != nil { if noBuildable(err) && !shallow { dir, sub, err := e.importSubpackages(p) if err != nil { return nil, err } return &Package{name: path.Base(p), dir: dir, Packages: sub, env: e}, nil } } fset := token.NewFileSet() var names []string names = append(names, b.GoFiles...) names = append(names, b.CgoFiles...) files, err := e.parseFiles(fset, b.Dir, names, parser.ParseComments) if err != nil { return nil, err } bodies := make(map[*ast.FuncDecl]*ast.BlockStmt) for _, f := range files { for _, d := range f.Decls { if fn, ok := d.(*ast.FuncDecl); ok { bodies[fn] = fn.Body } } } // NewPackage will always return errors because it won't // resolve builtin types. a, _ := ast.NewPackage(fset, files, astutil.Importer, nil) flags := doc.AllMethods if p == "builtin" { flags |= doc.AllDecls } pkg := &Package{ fset: fset, bpkg: b, apkg: a, dpkg: doc.New(a, b.ImportPath, flags), bodies: bodies, env: e, } if !shallow { sub, err := e.ImportPackages(b.Dir) if err != nil { return nil, err } pkg.Packages = sub } return pkg, nil }
func main() { flag.Parse() path := flag.Arg(0) if path == "" { path = "." } fset = token.NewFileSet() pkgs, err := parser.ParseDir(fset, path, func(file os.FileInfo) bool { name := file.Name() if name[0] != '.' && strings.HasSuffix(name, ".go") && !strings.HasSuffix(name, "_test.go") { return true } return false }, parser.ParseComments) if err != nil { fmt.Fprintf(os.Stderr, "Could not parse \"%s\": %v\n", path, err) } importLine := "" if read, err := ioutil.ReadFile(filepath.Join(path, ".import")); err == nil { importLine = strings.Split(string(read), "\n")[0] } var buffer bytes.Buffer // There should be only 1 package, but... for _, pkg := range pkgs { document := doc.New(pkg, ".", 0) fmt.Fprintf(&buffer, "# %s\n--\n", document.Name) if importLine != "" { fmt.Fprintf(&buffer, " import \"%s\"\n\n", importLine) } fmt.Fprintf(&buffer, "%s\n", headifySynopsis(document.Doc)) fmt.Fprintf(&buffer, "## Usage\n\n") writeConstantSection(&buffer, document.Consts) writeVariableSection(&buffer, document.Vars) writeFunctionSection(&buffer, "####", document.Funcs) writeTypeSection(&buffer, document.Types) } if debug { return } fmt.Println(strings.TrimSpace(buffer.String())) if *signature { fmt.Printf("\n--\n**godocdown** http://github.com/robertkrimen/godocdown\n") } }
func (w *Walker) WalkPackage(name, dir string) { log.Printf("package %s", name) pop := w.pushScope("pkg " + name) defer pop() info, err := build.ScanDir(dir) if err != nil { log.Fatalf("pkg %q, dir %q: ScanDir: %v", name, dir, err) } apkg := &ast.Package{ Files: make(map[string]*ast.File), } files := append(append([]string{}, info.GoFiles...), info.CgoFiles...) for _, file := range files { f, err := parser.ParseFile(w.fset, filepath.Join(dir, file), nil, 0) if err != nil { log.Fatalf("error parsing package %s, file %s: %v", name, file, err) } apkg.Files[file] = f } w.curPackageName = name w.curPackage = apkg w.prevConstType = map[string]string{} for name, afile := range apkg.Files { w.walkFile(filepath.Join(dir, name), afile) } // Now that we're done walking types, vars and consts // in the *ast.Package, use go/doc to do the rest // (functions and methods). This is done here because // go/doc is destructive. We can't use the // *ast.Package after this. dpkg := doc.New(apkg, name, 0) for _, t := range dpkg.Types { // Move funcs up to the top-level, not hiding in the Types. dpkg.Funcs = append(dpkg.Funcs, t.Funcs...) for _, m := range t.Methods { w.walkFuncDecl(m.Decl) } } for _, f := range dpkg.Funcs { w.walkFuncDecl(f.Decl) } }
func packageFromInfo(prog *loader.Program, pkgInfo *loader.PackageInfo) *Package { files := map[string]*ast.File{} for _, f := range pkgInfo.Files { files[prog.Fset.File(f.Pos()).Name()] = f } // Ignore (perhaps) "unresolved identifier" errors astPkg, _ := ast.NewPackage(prog.Fset, files, nil, nil) var mode doc.Mode docPkg := doc.New(astPkg, pkgInfo.String(), mode) return NewPackage(prog.Fset, docPkg, pkgInfo.Pkg) }
func astFrom(filePath string) *doc.Package { fset := token.NewFileSet() m := make(map[string]*ast.File) f, err := parser.ParseFile(fset, filePath, nil, parser.ParseComments) if err != nil { fmt.Println(err) return nil } m[filePath] = f apkg, _ := ast.NewPackage(fset, m, nil, nil) return doc.New(apkg, "", 0) }
func getPackageDoc(dir string) (*doc.Package, error) { fset := token.NewFileSet() pkgs, err := parser.ParseDir(fset, dir, isNotGoTestFile, parser.ParseComments) if err != nil { return nil, err } // return the first pkg for pkgName, pkgAST := range pkgs { importPath := dir + "/" + pkgName return doc.New(pkgAST, importPath, doc.AllDecls), nil } return nil, nil }
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") }
func newPackageFrom(bpkg *build.Package, p *types.Package) (*bind.Package, error) { var pkgast *ast.Package pkgs, err := parser.ParseDir(fset, bpkg.Dir, nil, parser.ParseComments) if err != nil { return nil, err } pkgast = pkgs[p.Name()] if pkgast == nil { return nil, fmt.Errorf("gopy: could not find AST for package %q", p.Name()) } pkgdoc := doc.New(pkgast, bpkg.ImportPath, 0) return bind.NewPackage(p, pkgdoc) }
func builtinPackage() *doc.Package { buildPkg, err := build.Import("builtin", "", build.ImportComment) // should never fail if err != nil { panic(err) } include := func(info os.FileInfo) bool { return info.Name() == "builtin.go" } fs := token.NewFileSet() astPkgs, err := parser.ParseDir(fs, buildPkg.Dir, include, parser.ParseComments) if err != nil { panic(err) } astPkg := astPkgs["builtin"] return doc.New(astPkg, buildPkg.ImportPath, doc.AllDecls) }
func NewFilePackage(filename string) (*PackageView, error) { p := new(PackageView) p.fset = token.NewFileSet() file, err := parser.ParseFile(p.fset, filename, nil, parser.AllErrors) if file == nil { return nil, err } m := make(map[string]*ast.File) m[filename] = file pkg, err := ast.NewPackage(p.fset, m, nil, nil) if err != nil { return nil, err } p.pkg = pkg p.pdoc = doc.New(pkg, pkg.Name, doc.AllDecls) return p, nil }