func()

in internal/web/page.go [35:119]


func (site *Site) openPage(file string) (*pageFile, error) {
	// Strip trailing .html or .md or /; it all names the same page.
	if strings.HasSuffix(file, "/index.md") {
		file = strings.TrimSuffix(file, "/index.md")
	} else if strings.HasSuffix(file, "/index.html") {
		file = strings.TrimSuffix(file, "/index.html")
	} else if file == "index.md" || file == "index.html" {
		file = "."
	} else if strings.HasSuffix(file, "/") {
		file = strings.TrimSuffix(file, "/")
	} else if strings.HasSuffix(file, ".html") {
		file = strings.TrimSuffix(file, ".html")
	} else {
		file = strings.TrimSuffix(file, ".md")
	}

	now := time.Now().UnixNano()
	if cp, ok := site.cache.Load(file); ok {
		// Have cache entry; only use if the underlying file hasn't changed.
		// To avoid continuous stats, only check it has been 3s since the last one.
		// TODO(rsc): Move caching into a more general layer and cache templates.
		p := cp.(*pageFile)
		if now-atomic.LoadInt64(&p.checked) >= 3e9 {
			info, err := fs.Stat(site.fs, p.file)
			if err == nil && info.ModTime().Equal(p.stat.ModTime()) && info.Size() == p.stat.Size() {
				atomic.StoreInt64(&p.checked, now)
				return p, nil
			}
		}
	}

	// Check md before html to work correctly when x/website is layered atop Go 1.15 goroot during Go 1.15 tests.
	// Want to find x/website's debugging_with_gdb.md not Go 1.15's debuging_with_gdb.html.
	files := []string{file + ".md", file + ".html", path.Join(file, "index.md"), path.Join(file, "index.html")}
	var filePath string
	var b []byte
	var err error
	var stat fs.FileInfo
	for _, filePath = range files {
		stat, err = fs.Stat(site.fs, filePath)
		if err == nil {
			b, err = site.readFile(".", filePath)
			if err == nil {
				break
			}
		}
	}
	if err != nil {
		return nil, err
	}

	// If we read an index.md or index.html, the canonical relpath is without the index.md/index.html suffix.
	url := path.Join("/", file)
	if name := path.Base(filePath); name == "index.html" || name == "index.md" {
		url, _ = path.Split(path.Join("/", filePath))
	}

	params, body, err := parseMeta(b)
	if err != nil {
		return nil, err
	}

	p := &pageFile{
		file:    filePath,
		stat:    stat,
		url:     url,
		data:    body,
		page:    params,
		checked: now,
	}

	// File, FileData, URL
	p.page["File"] = filePath
	p.page["FileData"] = string(body)
	p.page["URL"] = p.url

	// User-specified redirect: overrides url but not URL.
	if redir, _ := p.page["redirect"].(string); redir != "" {
		p.url = redir
	}

	site.cache.Store(file, p)

	return p, nil
}