blob: dd5e8d3684bdada0db0da35536219414735ee0a4 [file] [log] [blame]
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"bytes"
"fmt"
"html/template"
"log"
"net/http"
"sort"
"golang.org/x/tools/godoc"
"golang.org/x/tools/godoc/vfs"
"golang.org/x/website/internal/history"
)
// projectHandler serves The Go Project page.
type projectHandler struct {
ReleaseHistory []MajorRelease // Pre-computed release history to display.
}
func (h projectHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
const relPath = "doc/contrib.html"
src, err := vfs.ReadFile(fs, relPath)
if err != nil {
log.Printf("reading template %s: %v", relPath, err)
pres.ServeError(w, req, relPath, err)
return
}
meta, src, err := extractMetadata(src)
if err != nil {
log.Printf("decoding metadata %s: %v", relPath, err)
pres.ServeError(w, req, relPath, err)
return
}
if !meta.Template {
err := fmt.Errorf("got non-template, want template")
log.Printf("unexpected metadata %s: %v", relPath, err)
pres.ServeError(w, req, relPath, err)
return
}
page := godoc.Page{
Title: meta.Title,
Subtitle: meta.Subtitle,
GoogleCN: googleCN(req),
}
data := projectTemplateData{
Major: h.ReleaseHistory,
}
// Evaluate as HTML template.
tmpl, err := template.New("").Parse(string(src))
if err != nil {
log.Printf("parsing template %s: %v", relPath, err)
pres.ServeError(w, req, relPath, err)
return
}
var buf bytes.Buffer
if err := tmpl.Execute(&buf, data); err != nil {
log.Printf("executing template %s: %v", relPath, err)
pres.ServeError(w, req, relPath, err)
return
}
src = buf.Bytes()
page.Body = src
pres.ServePage(w, page)
}
// sortMajorReleases returns a sorted list of major Go releases,
// suitable to be displayed on the Go project page.
func sortMajorReleases(rs map[history.GoVer]history.Release) []MajorRelease {
var major []MajorRelease
for v, r := range rs {
if !v.IsMajor() {
continue
}
major = append(major, MajorRelease{ver: v, rel: r})
}
sort.Slice(major, func(i, j int) bool {
if major[i].ver.X != major[j].ver.X {
return major[i].ver.X > major[j].ver.X
}
return major[i].ver.Y > major[j].ver.Y
})
return major
}
type projectTemplateData struct {
Major []MajorRelease
}
// MajorRelease represents a major Go release entry as displayed on the Go project page.
type MajorRelease struct {
ver history.GoVer
rel history.Release
}
// V returns the Go release version string, like "1.14", "1.14.1", "1.14.2", etc.
func (r MajorRelease) V() string {
return r.ver.String()
}
// Date returns the date of the release, formatted for display on the Go project page.
func (r MajorRelease) Date() string {
d := r.rel.Date
return fmt.Sprintf("%s %d", d.Month, d.Year)
}