mirror of
https://github.com/golang/go
synced 2024-11-18 13:24:39 -07:00
present: add OldURL metadata and use for redirects in blog
This will allow renaming blog pages to have shorter, more easily typed URLs, while keeping the old links working. Change-Id: I2cd6733eaaf02a4b8e73afc773173c655d317ee6 Reviewed-on: https://go-review.googlesource.com/c/tools/+/223603 Reviewed-by: Andrew Bonventre <andybons@golang.org>
This commit is contained in:
parent
cf1dd6fc34
commit
b304dfc3e0
36
blog/blog.go
36
blog/blog.go
@ -65,12 +65,13 @@ type Doc struct {
|
|||||||
|
|
||||||
// Server implements an http.Handler that serves blog articles.
|
// Server implements an http.Handler that serves blog articles.
|
||||||
type Server struct {
|
type Server struct {
|
||||||
cfg Config
|
cfg Config
|
||||||
docs []*Doc
|
docs []*Doc
|
||||||
tags []string
|
redirects map[string]string
|
||||||
docPaths map[string]*Doc // key is path without BasePath.
|
tags []string
|
||||||
docTags map[string][]*Doc
|
docPaths map[string]*Doc // key is path without BasePath.
|
||||||
template struct {
|
docTags map[string][]*Doc
|
||||||
|
template struct {
|
||||||
home, index, article, doc *template.Template
|
home, index, article, doc *template.Template
|
||||||
}
|
}
|
||||||
atomFeed []byte // pre-rendered Atom feed
|
atomFeed []byte // pre-rendered Atom feed
|
||||||
@ -118,7 +119,8 @@ func NewServer(cfg Config) (*Server, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Load content.
|
// Load content.
|
||||||
err = s.loadDocs(filepath.Clean(cfg.ContentPath))
|
content := filepath.Clean(cfg.ContentPath)
|
||||||
|
err = s.loadDocs(content)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -191,6 +193,7 @@ func (s *Server) loadDocs(root string) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if filepath.Ext(p) != ext {
|
if filepath.Ext(p) != ext {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -227,12 +230,27 @@ func (s *Server) loadDocs(root string) error {
|
|||||||
// Pull out doc paths and tags and put in reverse-associating maps.
|
// Pull out doc paths and tags and put in reverse-associating maps.
|
||||||
s.docPaths = make(map[string]*Doc)
|
s.docPaths = make(map[string]*Doc)
|
||||||
s.docTags = make(map[string][]*Doc)
|
s.docTags = make(map[string][]*Doc)
|
||||||
|
s.redirects = make(map[string]string)
|
||||||
for _, d := range s.docs {
|
for _, d := range s.docs {
|
||||||
s.docPaths[strings.TrimPrefix(d.Path, s.cfg.BasePath)] = d
|
s.docPaths[strings.TrimPrefix(d.Path, s.cfg.BasePath)] = d
|
||||||
for _, t := range d.Tags {
|
for _, t := range d.Tags {
|
||||||
s.docTags[t] = append(s.docTags[t], d)
|
s.docTags[t] = append(s.docTags[t], d)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for _, d := range s.docs {
|
||||||
|
for _, old := range d.OldURL {
|
||||||
|
if !strings.HasPrefix(old, "/") {
|
||||||
|
old = "/" + old
|
||||||
|
}
|
||||||
|
if _, ok := s.docPaths[old]; ok {
|
||||||
|
return fmt.Errorf("redirect %s -> %s conflicts with document %s", old, d.Path, old)
|
||||||
|
}
|
||||||
|
if new, ok := s.redirects[old]; ok {
|
||||||
|
return fmt.Errorf("redirect %s -> %s conflicts with redirect %s -> %s", old, d.Path, old, new)
|
||||||
|
}
|
||||||
|
s.redirects[old] = d.Path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Pull out unique sorted list of tags.
|
// Pull out unique sorted list of tags.
|
||||||
for t := range s.docTags {
|
for t := range s.docTags {
|
||||||
@ -425,6 +443,10 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
w.Write(s.jsonFeed)
|
w.Write(s.jsonFeed)
|
||||||
return
|
return
|
||||||
default:
|
default:
|
||||||
|
if redir, ok := s.redirects[p]; ok {
|
||||||
|
http.Redirect(w, r, redir, http.StatusMovedPermanently)
|
||||||
|
return
|
||||||
|
}
|
||||||
doc, ok := s.docPaths[p]
|
doc, ok := s.docPaths[p]
|
||||||
if !ok {
|
if !ok {
|
||||||
// Not a doc; try to just serve static content.
|
// Not a doc; try to just serve static content.
|
||||||
|
@ -17,6 +17,7 @@ and other metadata, which looks like:
|
|||||||
15:04 2 Jan 2006
|
15:04 2 Jan 2006
|
||||||
Tags: foo, bar, baz
|
Tags: foo, bar, baz
|
||||||
Summary: This is a great document you want to read.
|
Summary: This is a great document you want to read.
|
||||||
|
OldURL: former-path-for-this-doc
|
||||||
|
|
||||||
The "# " prefix before the title indicates that this is
|
The "# " prefix before the title indicates that this is
|
||||||
a Markdown-enabled present file: it uses
|
a Markdown-enabled present file: it uses
|
||||||
@ -33,8 +34,12 @@ the document.
|
|||||||
|
|
||||||
The summary line gives a short summary used in blog feeds.
|
The summary line gives a short summary used in blog feeds.
|
||||||
|
|
||||||
|
The old URL line, which may be repeated, gives an older (perhaps relative) URL
|
||||||
|
for this document.
|
||||||
|
A server might use these to generate appropriate redirects.
|
||||||
|
|
||||||
Only the title is required;
|
Only the title is required;
|
||||||
the subtitle, date, tags, and summary lines are optional.
|
the subtitle, date, tags, summary, and old URL lines are optional.
|
||||||
In Markdown-enabled present, the summary defaults to being empty.
|
In Markdown-enabled present, the summary defaults to being empty.
|
||||||
In legacy present, the summary defaults to the first paragraph of text.
|
In legacy present, the summary defaults to the first paragraph of text.
|
||||||
|
|
||||||
|
@ -79,6 +79,7 @@ type Doc struct {
|
|||||||
TitleNotes []string
|
TitleNotes []string
|
||||||
Sections []Section
|
Sections []Section
|
||||||
Tags []string
|
Tags []string
|
||||||
|
OldURL []string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Author represents the person who wrote and/or is presenting the document.
|
// Author represents the person who wrote and/or is presenting the document.
|
||||||
@ -546,6 +547,8 @@ func parseHeader(doc *Doc, isMarkdown bool, lines *Lines) error {
|
|||||||
doc.Tags = append(doc.Tags, tags...)
|
doc.Tags = append(doc.Tags, tags...)
|
||||||
} else if strings.HasPrefix(text, "Summary:") {
|
} else if strings.HasPrefix(text, "Summary:") {
|
||||||
doc.Summary = strings.TrimSpace(text[len("Summary:"):])
|
doc.Summary = strings.TrimSpace(text[len("Summary:"):])
|
||||||
|
} else if strings.HasPrefix(text, "OldURL:") {
|
||||||
|
doc.OldURL = append(doc.OldURL, strings.TrimSpace(text[len("OldURL:"):]))
|
||||||
} else if t, ok := parseTime(text); ok {
|
} else if t, ok := parseTime(text); ok {
|
||||||
doc.Time = t
|
doc.Time = t
|
||||||
} else if doc.Subtitle == "" {
|
} else if doc.Subtitle == "" {
|
||||||
|
Loading…
Reference in New Issue
Block a user