Skip to content

Commit

Permalink
cmd/golangorg: generate major version list on Go project page
Browse files Browse the repository at this point in the history
This change builds on what was done in CL 229081, and uses the Go
release history data from internal/history package to generate the
list of major Go versions on the Go project page.

This way, this page doesn't need to be manually edited when major
Go releases are made.

For golang/go#38488.
For golang/go#29205.
For golang/go#29206.

Change-Id: Ie0b12707d828207173a54f0a1bc6a4ef69dcedef
Reviewed-on: https://go-review.googlesource.com/c/website/+/229483
Run-TryBot: Dmitri Shuralyov <dmitshur@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Alexander Rakoczy <alex@golang.org>
  • Loading branch information
dmitshur committed Apr 24, 2020
1 parent 70f4ee8 commit 0d8ef50
Show file tree
Hide file tree
Showing 6 changed files with 156 additions and 9 deletions.
21 changes: 21 additions & 0 deletions cmd/golangorg/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,13 +87,34 @@ func registerHandlers(pres *godoc.Presentation) *http.ServeMux {
mux.Handle("/pkg/C/", redirect.Handler("/cmd/cgo/"))
mux.HandleFunc("/fmt", fmtHandler)
mux.Handle("/doc/devel/release.html", releaseHandler{ReleaseHistory: sortReleases(history.Releases)})
handleRootAndSubtree(mux, "/project/", projectHandler{ReleaseHistory: sortMajorReleases(history.Releases)}, pres)
redirect.Register(mux)

http.Handle("/", hostEnforcerHandler{mux})

return mux
}

// handleRootAndSubtree registers a handler for the given pattern in mux.
// The handler selects between root or subtree handlers to handle requests.
//
// The root handler is used for requests with URL path equal to the pattern,
// and the subtree handler is used for all other requests matched by pattern.
//
// The pattern must have a trailing slash ('/'), otherwise handleRoot panics.
func handleRootAndSubtree(mux *http.ServeMux, path string, root, subtree http.Handler) {
if !strings.HasSuffix(path, "/") {
panic("handleRootAndSubtree must be used on patterns with a trailing slash ('/')")
}
mux.HandleFunc(path, func(w http.ResponseWriter, req *http.Request) {
if req.URL.Path == path {
root.ServeHTTP(w, req)
} else {
subtree.ServeHTTP(w, req)
}
})
}

func readTemplate(name string) *template.Template {
if pres == nil {
panic("no global Presentation set yet")
Expand Down
114 changes: 114 additions & 0 deletions cmd/golangorg/project.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
// 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)
}
10 changes: 10 additions & 0 deletions cmd/golangorg/regtest_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,16 @@ func TestLiveServer(t *testing.T) {
Path: "/doc/devel/release.html",
Regexp: `go1\.14\.2\s+\(released 2020/04/08\)\s+includes\s+fixes to cgo, the go command, the runtime,`,
},
{
Message: "Go project page has an entry for Go 1.14",
Path: "/project/",
Substring: `<li><a href="/doc/go1.14">Go 1.14</a> <small>(February 2020)</small></li>`,
},
{
Message: "Go project subpath does not exist",
Path: "/project/notexist",
StatusCode: http.StatusNotFound,
},
}

for _, tc := range substringTests {
Expand Down
2 changes: 1 addition & 1 deletion cmd/golangorg/release.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ type releaseHandler struct {
func (h releaseHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
const relPath = "doc/devel/release.html"

src, err := vfs.ReadFile(fs, "/doc/devel/release.html")
src, err := vfs.ReadFile(fs, relPath)
if err != nil {
log.Printf("reading template %s: %v", relPath, err)
pres.ServeError(w, req, relPath, err)
Expand Down
16 changes: 9 additions & 7 deletions content/static/doc/contrib.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<!--{
"Title": "The Go Project",
"Path": "/project/"
"Path": "/project/",
"Template": true
}-->

<img class="gopher" src="/doc/gopher/project.png" />
Expand Down Expand Up @@ -34,12 +35,13 @@ <h3 id="release"><a href="/doc/devel/release.html">Release History</a></h3>
<p>A <a href="/doc/devel/release.html">summary</a> of the changes between Go releases. Notes for the major releases:</p>

<ul>
<li><a href="/doc/go1.14">Go 1.14</a> <small>(February 2020)</small></li>
<li><a href="/doc/go1.13">Go 1.13</a> <small>(September 2019)</small></li>
<li><a href="/doc/go1.12">Go 1.12</a> <small>(February 2019)</small></li>
<li><a href="/doc/go1.11">Go 1.11</a> <small>(August 2018)</small></li>
<li><a href="/doc/go1.10">Go 1.10</a> <small>(February 2018)</small></li>
<li><a href="/doc/go1.9">Go 1.9</a> <small>(August 2017)</small></li>
{{range .Major -}}
<li><a href="/doc/go{{.V}}">Go {{.V}}</a> <small>({{.Date}})</small></li>
{{end -}}

{{- /* Entries for Go 1.9 and newer are generated using data in the internal/history package. */ -}}
{{- /* Entries for Go 1.8 and older are hand-written as raw HTML below. */ -}}

<li><a href="/doc/go1.8">Go 1.8</a> <small>(February 2017)</small></li>
<li><a href="/doc/go1.7">Go 1.7</a> <small>(August 2016)</small></li>
<li><a href="/doc/go1.6">Go 1.6</a> <small>(February 2016)</small></li>
Expand Down
Loading

0 comments on commit 0d8ef50

Please sign in to comment.