1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889 | package render
import (
"encoding/xml"
"maps"
"os"
"slices"
"time"
)
// ---- sitemaps ----
// The site's sitemap is an index of one sitemap per repository listed on
// the index page. A repository's sitemap names every page of its default
// branch; other branches ask not to be indexed, so they are left out.
const sitemapNS = "http://www.sitemaps.org/schemas/sitemap/0.9"
type sitemapIndex struct {
XMLName xml.Name `xml:"sitemapindex"`
NS string `xml:"xmlns,attr"`
Sitemaps []sitemapLoc `xml:"sitemap"`
}
type urlSet struct {
XMLName xml.Name `xml:"urlset"`
NS string `xml:"xmlns,attr"`
URLs []sitemapLoc `xml:"url"`
}
type sitemapLoc struct {
Loc string `xml:"loc"`
LastMod string `xml:"lastmod,omitempty"`
}
// sitemapMax is the most URLs one sitemap may hold.
const sitemapMax = 50000
func lastMod(t time.Time) string { return t.UTC().Format(time.RFC3339) }
func writeXML(path string, v any) error {
b, err := xml.MarshalIndent(v, "", " ")
if err != nil {
return err
}
return writePair(path, append([]byte(xml.Header), append(b, '\n')...), false)
}
// writeSitemap lists every page of the view, each dated by the last
// commit that changed what it shows. Only the default branch has one.
func (c *repoCtx) writeSitemap() error {
var urls []sitemapLoc
add := func(p string) {
u := sitemapLoc{Loc: c.s.absURL(c.s.CodeURL(c.key, p))}
if t, ok := c.mtime[p]; ok {
u.LastMod = lastMod(time.Unix(t, 0))
}
urls = append(urls, u)
}
for _, d := range slices.Sorted(maps.Keys(c.tree.dirs)) {
add(d)
}
for _, p := range c.tree.sortedPaths() {
if e := c.tree.byPath[p]; !e.IsSymlink() && !e.IsSubmodule() {
add(p)
}
}
if len(urls) > sitemapMax {
c.logf("sitemap: %d pages; listing the first %d", len(urls), sitemapMax)
urls = urls[:sitemapMax]
}
return writeXML(c.s.Lay.Sitemap(c.key), urlSet{NS: sitemapNS, URLs: urls})
}
// writeSiteSitemap indexes the sitemaps of the repositories on the index
// page, dated by each one's latest commit. A repository rendered before
// sitemaps existed has none until its next render, and is left out.
func (s *Site) writeSiteSitemap(view indexView) error {
idx := sitemapIndex{NS: sitemapNS}
for _, sec := range view.Sections {
for _, r := range sec.Repos {
if _, err := os.Stat(s.Lay.Sitemap(r.Name)); err != nil {
continue
}
idx.Sitemaps = append(idx.Sitemaps, sitemapLoc{Loc: s.absURL(SitemapURL(r.Name)), LastMod: r.Updated})
}
}
return writeXML(s.Lay.SiteSitemap(), idx)
}
|