in internal/pkgdoc/doc.go [150:275]
func (d *docs) open(dir string, mode mode, goos, goarch string) *Page {
dir = path.Clean(dir)
info := &Page{docs: d, Dirname: dir, mode: mode}
// Restrict to the package files that would be used when building
// the package on this system. This makes sure that if there are
// separate implementations for, say, Windows vs Unix, we don't
// jumble them all together.
// Note: If goos/goarch aren't set, the current binary's GOOS/GOARCH
// are used.
ctxt := build.Default
ctxt.IsAbsPath = path.IsAbs
ctxt.IsDir = func(path string) bool {
fi, err := fs.Stat(d.fs, filepath.ToSlash(path))
return err == nil && fi.IsDir()
}
ctxt.ReadDir = func(dir string) ([]os.FileInfo, error) {
f, err := fs.ReadDir(d.fs, filepath.ToSlash(dir))
filtered := make([]os.FileInfo, 0, len(f))
for _, i := range f {
if mode&modeAll != 0 || i.Name() != "internal" {
info, err := i.Info()
if err == nil {
filtered = append(filtered, info)
}
}
}
return filtered, err
}
ctxt.OpenFile = func(name string) (r io.ReadCloser, err error) {
data, err := fs.ReadFile(d.fs, filepath.ToSlash(name))
if err != nil {
return nil, err
}
return ioutil.NopCloser(bytes.NewReader(data)), nil
}
// Make the syscall/js package always visible by default.
// It defaults to the host's GOOS/GOARCH, and golang.org's
// linux/amd64 means the wasm syscall/js package was blank.
// And you can't run godoc on js/wasm anyway, so host defaults
// don't make sense here.
if goos == "" && goarch == "" && dir == "syscall/js" {
goos, goarch = "js", "wasm"
}
if goos != "" {
ctxt.GOOS = goos
}
if goarch != "" {
ctxt.GOARCH = goarch
}
pkginfo, err := ctxt.ImportDir(dir, 0)
// continue if there are no Go source files; we still want the directory info
if _, nogo := err.(*build.NoGoError); err != nil && !nogo {
info.Err = err
return info
}
// collect package files
pkgname := pkginfo.Name
pkgfiles := append(pkginfo.GoFiles, pkginfo.CgoFiles...)
if len(pkgfiles) == 0 {
// Commands written in C have no .go files in the build.
// Instead, documentation may be found in an ignored file.
// The file may be ignored via an explicit +build ignore
// constraint (recommended), or by defining the package
// documentation (historic).
pkgname = "main" // assume package main since pkginfo.Name == ""
pkgfiles = pkginfo.IgnoredGoFiles
}
// get package information, if any
if len(pkgfiles) > 0 {
// build package AST
fset := token.NewFileSet()
files, err := parseFiles(d.fs, fset, dir, pkgfiles)
if err != nil {
info.Err = err
return info
}
// ignore any errors - they are due to unresolved identifiers
pkg, _ := ast.NewPackage(fset, files, simpleImporter, nil)
// extract package documentation
info.fset = fset
info.IsMain = pkgname == "main"
// show extracted documentation
var m doc.Mode
if mode&modeAll != 0 {
m |= doc.AllDecls
}
if mode&modeMethods != 0 {
m |= doc.AllMethods
}
info.PDoc = doc.New(pkg, strings.TrimPrefix(dir, "src/"), m)
if mode&modeBuiltin != 0 {
for _, t := range info.PDoc.Types {
info.PDoc.Consts = append(info.PDoc.Consts, t.Consts...)
info.PDoc.Vars = append(info.PDoc.Vars, t.Vars...)
info.PDoc.Funcs = append(info.PDoc.Funcs, t.Funcs...)
t.Consts = nil
t.Vars = nil
t.Funcs = nil
}
// for now we cannot easily sort consts and vars since
// go/doc.Value doesn't export the order information
sort.Sort(funcsByName(info.PDoc.Funcs))
}
// collect examples
testfiles := append(pkginfo.TestGoFiles, pkginfo.XTestGoFiles...)
files, err = parseFiles(d.fs, fset, dir, testfiles)
if err != nil {
log.Println("parsing examples:", err)
}
info.Examples = collectExamples(pkg, files)
info.Bugs = info.PDoc.Notes["BUG"]
}
info.Dirs = d.root.lookup(dir).list(func(path string) bool { return d.includePath(path, mode) })
info.DirFlat = mode&modeFlat != 0
return info
}