Skip to content

Commit 0d8ef50

Browse files
committed
cmd/golangorg: generate major version list on Go project page
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 <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Alexander Rakoczy <[email protected]>
1 parent 70f4ee8 commit 0d8ef50

File tree

6 files changed

+156
-9
lines changed

6 files changed

+156
-9
lines changed

cmd/golangorg/handlers.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,13 +87,34 @@ func registerHandlers(pres *godoc.Presentation) *http.ServeMux {
8787
mux.Handle("/pkg/C/", redirect.Handler("/cmd/cgo/"))
8888
mux.HandleFunc("/fmt", fmtHandler)
8989
mux.Handle("/doc/devel/release.html", releaseHandler{ReleaseHistory: sortReleases(history.Releases)})
90+
handleRootAndSubtree(mux, "/project/", projectHandler{ReleaseHistory: sortMajorReleases(history.Releases)}, pres)
9091
redirect.Register(mux)
9192

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

9495
return mux
9596
}
9697

98+
// handleRootAndSubtree registers a handler for the given pattern in mux.
99+
// The handler selects between root or subtree handlers to handle requests.
100+
//
101+
// The root handler is used for requests with URL path equal to the pattern,
102+
// and the subtree handler is used for all other requests matched by pattern.
103+
//
104+
// The pattern must have a trailing slash ('/'), otherwise handleRoot panics.
105+
func handleRootAndSubtree(mux *http.ServeMux, path string, root, subtree http.Handler) {
106+
if !strings.HasSuffix(path, "/") {
107+
panic("handleRootAndSubtree must be used on patterns with a trailing slash ('/')")
108+
}
109+
mux.HandleFunc(path, func(w http.ResponseWriter, req *http.Request) {
110+
if req.URL.Path == path {
111+
root.ServeHTTP(w, req)
112+
} else {
113+
subtree.ServeHTTP(w, req)
114+
}
115+
})
116+
}
117+
97118
func readTemplate(name string) *template.Template {
98119
if pres == nil {
99120
panic("no global Presentation set yet")

cmd/golangorg/project.go

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
// Copyright 2020 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package main
6+
7+
import (
8+
"bytes"
9+
"fmt"
10+
"html/template"
11+
"log"
12+
"net/http"
13+
"sort"
14+
15+
"golang.org/x/tools/godoc"
16+
"golang.org/x/tools/godoc/vfs"
17+
"golang.org/x/website/internal/history"
18+
)
19+
20+
// projectHandler serves The Go Project page.
21+
type projectHandler struct {
22+
ReleaseHistory []MajorRelease // Pre-computed release history to display.
23+
}
24+
25+
func (h projectHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
26+
const relPath = "doc/contrib.html"
27+
28+
src, err := vfs.ReadFile(fs, relPath)
29+
if err != nil {
30+
log.Printf("reading template %s: %v", relPath, err)
31+
pres.ServeError(w, req, relPath, err)
32+
return
33+
}
34+
35+
meta, src, err := extractMetadata(src)
36+
if err != nil {
37+
log.Printf("decoding metadata %s: %v", relPath, err)
38+
pres.ServeError(w, req, relPath, err)
39+
return
40+
}
41+
if !meta.Template {
42+
err := fmt.Errorf("got non-template, want template")
43+
log.Printf("unexpected metadata %s: %v", relPath, err)
44+
pres.ServeError(w, req, relPath, err)
45+
return
46+
}
47+
48+
page := godoc.Page{
49+
Title: meta.Title,
50+
Subtitle: meta.Subtitle,
51+
GoogleCN: googleCN(req),
52+
}
53+
data := projectTemplateData{
54+
Major: h.ReleaseHistory,
55+
}
56+
57+
// Evaluate as HTML template.
58+
tmpl, err := template.New("").Parse(string(src))
59+
if err != nil {
60+
log.Printf("parsing template %s: %v", relPath, err)
61+
pres.ServeError(w, req, relPath, err)
62+
return
63+
}
64+
var buf bytes.Buffer
65+
if err := tmpl.Execute(&buf, data); err != nil {
66+
log.Printf("executing template %s: %v", relPath, err)
67+
pres.ServeError(w, req, relPath, err)
68+
return
69+
}
70+
src = buf.Bytes()
71+
72+
page.Body = src
73+
pres.ServePage(w, page)
74+
}
75+
76+
// sortMajorReleases returns a sorted list of major Go releases,
77+
// suitable to be displayed on the Go project page.
78+
func sortMajorReleases(rs map[history.GoVer]history.Release) []MajorRelease {
79+
var major []MajorRelease
80+
for v, r := range rs {
81+
if !v.IsMajor() {
82+
continue
83+
}
84+
major = append(major, MajorRelease{ver: v, rel: r})
85+
}
86+
sort.Slice(major, func(i, j int) bool {
87+
if major[i].ver.X != major[j].ver.X {
88+
return major[i].ver.X > major[j].ver.X
89+
}
90+
return major[i].ver.Y > major[j].ver.Y
91+
})
92+
return major
93+
}
94+
95+
type projectTemplateData struct {
96+
Major []MajorRelease
97+
}
98+
99+
// MajorRelease represents a major Go release entry as displayed on the Go project page.
100+
type MajorRelease struct {
101+
ver history.GoVer
102+
rel history.Release
103+
}
104+
105+
// V returns the Go release version string, like "1.14", "1.14.1", "1.14.2", etc.
106+
func (r MajorRelease) V() string {
107+
return r.ver.String()
108+
}
109+
110+
// Date returns the date of the release, formatted for display on the Go project page.
111+
func (r MajorRelease) Date() string {
112+
d := r.rel.Date
113+
return fmt.Sprintf("%s %d", d.Month, d.Year)
114+
}

cmd/golangorg/regtest_test.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,16 @@ func TestLiveServer(t *testing.T) {
128128
Path: "/doc/devel/release.html",
129129
Regexp: `go1\.14\.2\s+\(released 2020/04/08\)\s+includes\s+fixes to cgo, the go command, the runtime,`,
130130
},
131+
{
132+
Message: "Go project page has an entry for Go 1.14",
133+
Path: "/project/",
134+
Substring: `<li><a href="/doc/go1.14">Go 1.14</a> <small>(February 2020)</small></li>`,
135+
},
136+
{
137+
Message: "Go project subpath does not exist",
138+
Path: "/project/notexist",
139+
StatusCode: http.StatusNotFound,
140+
},
131141
}
132142

133143
for _, tc := range substringTests {

cmd/golangorg/release.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ type releaseHandler struct {
2727
func (h releaseHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
2828
const relPath = "doc/devel/release.html"
2929

30-
src, err := vfs.ReadFile(fs, "/doc/devel/release.html")
30+
src, err := vfs.ReadFile(fs, relPath)
3131
if err != nil {
3232
log.Printf("reading template %s: %v", relPath, err)
3333
pres.ServeError(w, req, relPath, err)

content/static/doc/contrib.html

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<!--{
22
"Title": "The Go Project",
3-
"Path": "/project/"
3+
"Path": "/project/",
4+
"Template": true
45
}-->
56

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

3637
<ul>
37-
<li><a href="/doc/go1.14">Go 1.14</a> <small>(February 2020)</small></li>
38-
<li><a href="/doc/go1.13">Go 1.13</a> <small>(September 2019)</small></li>
39-
<li><a href="/doc/go1.12">Go 1.12</a> <small>(February 2019)</small></li>
40-
<li><a href="/doc/go1.11">Go 1.11</a> <small>(August 2018)</small></li>
41-
<li><a href="/doc/go1.10">Go 1.10</a> <small>(February 2018)</small></li>
42-
<li><a href="/doc/go1.9">Go 1.9</a> <small>(August 2017)</small></li>
38+
{{range .Major -}}
39+
<li><a href="/doc/go{{.V}}">Go {{.V}}</a> <small>({{.Date}})</small></li>
40+
{{end -}}
41+
42+
{{- /* Entries for Go 1.9 and newer are generated using data in the internal/history package. */ -}}
43+
{{- /* Entries for Go 1.8 and older are hand-written as raw HTML below. */ -}}
44+
4345
<li><a href="/doc/go1.8">Go 1.8</a> <small>(February 2017)</small></li>
4446
<li><a href="/doc/go1.7">Go 1.7</a> <small>(August 2016)</small></li>
4547
<li><a href="/doc/go1.6">Go 1.6</a> <small>(February 2016)</small></li>

0 commit comments

Comments
 (0)