func()

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
}