Skip to content

Commit

Permalink
internal/web: redirect golang.org/pkg/... to pkg.go.dev/...
Browse files Browse the repository at this point in the history
This reduces the number of documentation sites we have to one.
Except in China, where we have to keep serving on the one domain
golang.google.cn - there is no pkg.go.dev in China.
And unless people opt out with ?m=old.

For golang/go#44356.

Change-Id: I2a5b788ac861ce37f356287413468497d184fc09
Reviewed-on: https://go-review.googlesource.com/c/website/+/327849
Trust: Russ Cox <rsc@golang.org>
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
  • Loading branch information
rsc committed Jul 12, 2021
1 parent f481c2b commit aa5eb5f
Show file tree
Hide file tree
Showing 7 changed files with 105 additions and 12 deletions.
60 changes: 50 additions & 10 deletions cmd/golangorg/testdata/web.txt
Expand Up @@ -18,6 +18,9 @@ body contains bdb10cf
body !contains UA-

GET https://golang.org/cmd/compile/internal/amd64/
redirect == https://pkg.go.dev/cmd/compile/internal/amd64

GET https://golang.org/cmd/compile/internal/amd64/?m=old
body contains href="/src/cmd/compile/internal/amd64/ssa.go"

GET https://golang.org/conduct
Expand Down Expand Up @@ -74,57 +77,94 @@ redirect == /help
GET https://golang.org/help
body contains Get help

GET https://golang.org/pkg/fmt/
body contains Package fmt implements formatted I/O

GET https://golang.org/src/fmt/
body contains scan_test.go

GET https://golang.org/src/fmt/print.go
body contains // Println formats using

GET https://golang.org/pkg/fmt/
redirect == https://pkg.go.dev/fmt

GET https://golang.org/pkg/fmt/?m=old
body contains Package fmt implements formatted I/O

GET https://golang.google.cn/pkg/fmt/
body contains Package fmt implements formatted I/O

GET https://golang.org/pkg
redirect == /pkg/

GET https://golang.org/pkg/
redirect == https://pkg.go.dev/std

GET https://tip.golang.org/pkg/
redirect == https://pkg.go.dev/std@master

GET https://golang.org/pkg?m=old
redirect == /pkg/?m=old

GET https://golang.org/pkg/?m=old
body contains Standard library
body contains Package fmt implements formatted I/O
body !contains internal/syscall
body !contains cmd/gc

GET https://golang.org/pkg/?m=all
GET https://golang.org/pkg/?m=old,all
body contains Standard library
body contains Package fmt implements formatted I/O
body contains internal/syscall/?m=all
body !contains cmd/gc

GET https://golang.org/pkg/bufio/
body contains href="/pkg/io/#Writer
redirect == https://pkg.go.dev/bufio

GET https://golang.org/pkg/bufio/?GOOS=windows&GOARCH=amd64
redirect == https://pkg.go.dev/bufio?GOOS=windows&GOARCH=amd64

GET https://tip.golang.org/pkg/bufio/
redirect == https://pkg.go.dev/bufio@master

GET https://golang.org/pkg/bufio/?m=old
body contains href="/pkg/io/?m=old#Writer
body !contains href="/pkg/io/#Writer

GET https://golang.org/pkg/database/sql/
redirect == https://pkg.go.dev/database/sql

GET https://golang.org/pkg/database/sql/?m=old
body contains The number of connections currently in use; added in Go 1.11
body contains The number of idle connections; added in Go 1.11

GET https://golang.org/cmd/compile/internal/amd64/
body contains href="/src/cmd/compile/internal/amd64/ssa.go"

GET https://golang.org/pkg/math/bits/
redirect == https://pkg.go.dev/math/bits

GET https://golang.org/pkg/math/bits/?m=old
body contains Added in Go 1.9

GET https://golang.org/pkg/net/
redirect == https://pkg.go.dev/net

GET https://golang.org/pkg/net/?m=old
body contains // IPv6 scoped addressing zone; added in Go 1.1

GET https://golang.org/pkg/net/http/
GET https://golang.org/pkg/net/http/?m=old
body contains title="Added in Go 1.11"

GET https://golang.org/pkg/net/http/httptrace/
redirect == https://pkg.go.dev/net/http/httptrace

GET https://golang.org/pkg/net/http/httptrace/?m=old
body ~ Got1xxResponse.*// Go 1\.11
body ~ GotFirstResponseByte func\(\)\s*$

GET https://golang.org/pkg/os/
GET https://golang.org/pkg/os/?m=old
body contains func Open

GET https://golang.org/pkg/strings/
redirect == https://pkg.go.dev/strings

GET https://golang.org/pkg/strings/?m=old
body contains href="/src/strings/strings.go"

GET https://golang.org/project
Expand Down
2 changes: 2 additions & 0 deletions internal/pkgdoc/doc.go
Expand Up @@ -70,6 +70,7 @@ const (
ModeAll Mode = 1 << iota // do not filter exports
ModeFlat // show directory in a flat (non-indented) manner
ModeMethods // show all embedded methods
ModeOld // do not redirect to pkg.go.dev
ModeBuiltin // don't associate consts, vars, and factory functions with types (not exposed via ?m= query parameter, used for package builtin, see issue 6645)
)

Expand All @@ -79,6 +80,7 @@ var modeNames = []string{
"all",
"flat",
"methods",
"old",
}

// generate a query string for persisting PageInfoMode between pages.
Expand Down
12 changes: 10 additions & 2 deletions internal/texthtml/ast.go
Expand Up @@ -20,16 +20,17 @@ import (
type goLink struct {
path, name string // package path, identifier name
isVal bool // identifier is defined in a const or var declaration
oldDocs bool // link to ?m=old docs
}

func (l *goLink) tags() (start, end string) {
switch {
case l.path != "" && l.name == "":
// package path
return `<a href="/pkg/` + l.path + `/">`, `</a>`
return `<a href="/pkg/` + l.path + `/` + l.docSuffix() + `">`, `</a>`
case l.path != "" && l.name != "":
// qualified identifier
return `<a href="/pkg/` + l.path + `/#` + l.name + `">`, `</a>`
return `<a href="/pkg/` + l.path + `/` + l.docSuffix() + `#` + l.name + `">`, `</a>`
case l.path == "" && l.name != "":
// local identifier
if l.isVal {
Expand All @@ -42,6 +43,13 @@ func (l *goLink) tags() (start, end string) {
return "", ""
}

func (l *goLink) docSuffix() string {
if l.oldDocs {
return "?m=old"
}
return ""
}

// goLinksFor returns the list of links for the identifiers used
// by node in the same order as they appear in the source.
func goLinksFor(node ast.Node) (links []goLink) {
Expand Down
6 changes: 6 additions & 0 deletions internal/texthtml/texthtml.go
Expand Up @@ -37,6 +37,7 @@ type Config struct {
Highlight string // highlight matches for this regexp with <span class="highlight">
Selection Selection // mark selected spans with <span class="selection">
AST ast.Node // link uses to declarations, assuming text is formatting of AST
OldDocs bool // emit links to ?m=old docs
}

// Format formats text to HTML according to the configuration cfg.
Expand All @@ -55,6 +56,11 @@ func Format(text []byte, cfg Config) (html []byte) {
if cfg.AST != nil {
idents = tokenSelection(text, token.IDENT)
goLinks = goLinksFor(cfg.AST)
if cfg.OldDocs {
for i := range goLinks {
goLinks[i].oldDocs = true
}
}
}

formatSelections(&buf, text, goLinks, comments, highlights, cfg.Selection, idents)
Expand Down
2 changes: 2 additions & 0 deletions internal/web/astfuncs.go
Expand Up @@ -36,6 +36,7 @@ func (p *Page) Node(node interface{}) template.HTML {
buf2.Write(texthtml.Format(buf1.Bytes(), texthtml.Config{
AST: n,
GoComments: true,
OldDocs: p.OldDocs,
}))
return template.HTML(buf2.String())
}
Expand All @@ -50,6 +51,7 @@ func (p *Page) NodeTOC(node interface{}) template.HTML {
var buf2 bytes.Buffer
buf2.Write(texthtml.Format(buf1.Bytes(), texthtml.Config{
GoComments: true,
OldDocs: p.OldDocs,
}))

return sanitize(template.HTML(buf2.String()))
Expand Down
32 changes: 32 additions & 0 deletions internal/web/pkgdoc.go
Expand Up @@ -7,6 +7,7 @@ package web
import (
"log"
"net/http"
"net/url"
"path"
"strings"

Expand All @@ -29,6 +30,36 @@ func (h *docServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
relpath = strings.TrimPrefix(relpath, "/")

mode := pkgdoc.ParseMode(r.FormValue("m"))

// Redirect to pkg.go.dev.
// We provide two overrides for the redirect.
// First, the request can set ?m=old to get the old pages.
// Second, the request can come from China:
// since pkg.go.dev is not available in China, we serve the docs directly.
if mode&pkgdoc.ModeOld == 0 && !GoogleCN(r) {
if relpath == "" {
relpath = "std"
}
suffix := ""
if r.Host == "tip.golang.org" {
suffix = "@master"
}
if goos, goarch := r.FormValue("GOOS"), r.FormValue("GOARCH"); goos != "" || goarch != "" {
suffix += "?"
if goos != "" {
suffix += "GOOS=" + url.QueryEscape(goos)
}
if goarch != "" {
if goos != "" {
suffix += "&"
}
suffix += "GOARCH=" + url.QueryEscape(goarch)
}
}
http.Redirect(w, r, "https://pkg.go.dev/"+relpath+suffix, http.StatusTemporaryRedirect)
return
}

if relpath == "builtin" {
// The fake built-in package contains unexported identifiers,
// but we want to show them. Also, disable type association,
Expand Down Expand Up @@ -81,6 +112,7 @@ func (h *docServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
Subtitle: subtitle,
Template: name,
Data: info,
OldDocs: mode&pkgdoc.ModeOld != 0,
})
}

Expand Down
3 changes: 3 additions & 0 deletions internal/web/site.go
Expand Up @@ -117,6 +117,9 @@ type Page struct {
Template string // template to apply to data (empty string when Data is raw template.HTML)
Data interface{} // data to be rendered into page frame

// Filled in for document rendering
OldDocs bool // use ?m=old in doc links

// Filled in automatically by ServePage
GoogleCN bool // served on golang.google.cn
GoogleAnalytics string // Google Analytics tag
Expand Down

0 comments on commit aa5eb5f

Please sign in to comment.