Commit 78d9a607 authored by Andrew Gerrand's avatar Andrew Gerrand

Wiki codelab, complete with tests.

R=r, rsc, gri
CC=golang-dev
https://golang.org/cl/887045
parent b2183701
# Copyright 2010 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.
include ../../../src/Make.$(GOARCH)
all: index.html
# ugly hack to deal with whitespaces in $GOROOT
nullstring :=
space := $(nullstring) # a space at the end
QUOTED_GOROOT:=$(subst $(space),\ ,$(GOROOT))
include $(QUOTED_GOROOT)/src/Make.common
CLEANFILES+=index.html srcextract.bin htmlify.bin
index.html: srcextract.bin htmlify.bin
awk '/^!/{system(substr($$0,2)); next} {print}' "$$@" < wiki.html > index.html
test: final.bin
./test.sh
rm -f final.6 final.bin
%.bin: %.$O
$(QUOTED_GOBIN)/$(LD) -o $@ $<
%.$O:
$(QUOTED_GOBIN)/$(GC) $*.go
<h1>Editing {title}</h1>
<form action="/save/{title}" method="POST">
<div><textarea name="body" rows="20" cols="80">{body|html}</textarea></div>
<div><input type="submit" value="Save"></div>
</form>
package main
import (
"http"
"io/ioutil"
"os"
"regexp"
"template"
)
type page struct {
title string
body []byte
}
func (p *page) save() os.Error {
filename := p.title + ".txt"
return ioutil.WriteFile(filename, p.body, 0600)
}
func loadPage(title string) (*page, os.Error) {
filename := title + ".txt"
body, err := ioutil.ReadFile(filename)
if err != nil {
return nil, err
}
return &page{title: title, body: body}, nil
}
func viewHandler(c *http.Conn, r *http.Request) {
title, err := getTitle(c, r)
if err != nil {
return
}
p, err := loadPage(title)
if err != nil {
http.Redirect(c, "/edit/"+title, http.StatusFound)
return
}
renderTemplate(c, "view", p)
}
func editHandler(c *http.Conn, r *http.Request) {
title, err := getTitle(c, r)
if err != nil {
return
}
p, err := loadPage(title)
if err != nil {
p = &page{title: title}
}
renderTemplate(c, "edit", p)
}
func saveHandler(c *http.Conn, r *http.Request) {
title, err := getTitle(c, r)
if err != nil {
return
}
body := r.FormValue("body")
p := &page{title: title, body: []byte(body)}
err = p.save()
if err != nil {
http.Error(c, err.String(), http.StatusInternalServerError)
return
}
http.Redirect(c, "/view/"+title, http.StatusFound)
}
func renderTemplate(c *http.Conn, tmpl string, p *page) {
t, err := template.ParseFile(tmpl+".html", nil)
if err != nil {
http.Error(c, err.String(), http.StatusInternalServerError)
return
}
err = t.Execute(p, c)
if err != nil {
http.Error(c, err.String(), http.StatusInternalServerError)
}
}
const lenPath = len("/view/")
var titleValidator = regexp.MustCompile("^[a-zA-Z0-9]+$")
func getTitle(c *http.Conn, r *http.Request) (title string, err os.Error) {
title = r.URL.Path[lenPath:]
if !titleValidator.MatchString(title) {
http.NotFound(c, r)
err = os.NewError("Invalid Page Title")
}
return
}
func main() {
http.HandleFunc("/view/", viewHandler)
http.HandleFunc("/edit/", editHandler)
http.HandleFunc("/save/", saveHandler)
http.ListenAndServe(":8080", nil)
}
package main
import (
"http"
"io/ioutil"
"os"
"template"
)
type page struct {
title string
body []byte
}
func (p *page) save() os.Error {
filename := p.title + ".txt"
return ioutil.WriteFile(filename, p.body, 0600)
}
func loadPage(title string) (*page, os.Error) {
filename := title + ".txt"
body, err := ioutil.ReadFile(filename)
if err != nil {
return nil, err
}
return &page{title: title, body: body}, nil
}
const lenPath = len("/view/")
func editHandler(c *http.Conn, r *http.Request) {
title := r.URL.Path[lenPath:]
p, err := loadPage(title)
if err != nil {
p = &page{title: title}
}
t, _ := template.ParseFile("edit.html", nil)
t.Execute(p, c)
}
func viewHandler(c *http.Conn, r *http.Request) {
title := r.URL.Path[lenPath:]
p, _ := loadPage(title)
t, _ := template.ParseFile("view.html", nil)
t.Execute(p, c)
}
func main() {
http.HandleFunc("/view/", viewHandler)
http.HandleFunc("/edit/", editHandler)
http.ListenAndServe(":8080", nil)
}
package main
import (
"http"
"io/ioutil"
"os"
"regexp"
"template"
)
type page struct {
title string
body []byte
}
func (p *page) save() os.Error {
filename := p.title + ".txt"
return ioutil.WriteFile(filename, p.body, 0600)
}
func loadPage(title string) (*page, os.Error) {
filename := title + ".txt"
body, err := ioutil.ReadFile(filename)
if err != nil {
return nil, err
}
return &page{title: title, body: body}, nil
}
func viewHandler(c *http.Conn, r *http.Request, title string) {
p, err := loadPage(title)
if err != nil {
http.Redirect(c, "/edit/"+title, http.StatusFound)
return
}
renderTemplate(c, "view", p)
}
func editHandler(c *http.Conn, r *http.Request, title string) {
p, err := loadPage(title)
if err != nil {
p = &page{title: title}
}
renderTemplate(c, "edit", p)
}
func saveHandler(c *http.Conn, r *http.Request, title string) {
body := r.FormValue("body")
p := &page{title: title, body: []byte(body)}
err := p.save()
if err != nil {
http.Error(c, err.String(), http.StatusInternalServerError)
return
}
http.Redirect(c, "/view/"+title, http.StatusFound)
}
func renderTemplate(c *http.Conn, tmpl string, p *page) {
t, err := template.ParseFile(tmpl+".html", nil)
if err != nil {
http.Error(c, err.String(), http.StatusInternalServerError)
return
}
err = t.Execute(p, c)
if err != nil {
http.Error(c, err.String(), http.StatusInternalServerError)
}
}
const lenPath = len("/view/")
var titleValidator = regexp.MustCompile("^[a-zA-Z0-9]+$")
func makeHandler(fn func(*http.Conn, *http.Request, string)) http.HandlerFunc {
return func(c *http.Conn, r *http.Request) {
title := r.URL.Path[lenPath:]
if !titleValidator.MatchString(title) {
http.NotFound(c, r)
return
}
fn(c, r, title)
}
}
func main() {
http.HandleFunc("/view/", makeHandler(viewHandler))
http.HandleFunc("/edit/", makeHandler(editHandler))
http.HandleFunc("/save/", makeHandler(saveHandler))
http.ListenAndServe(":8080", nil)
}
package main
import (
"http"
"io/ioutil"
"os"
"template"
)
type page struct {
title string
body []byte
}
func (p *page) save() os.Error {
filename := p.title + ".txt"
return ioutil.WriteFile(filename, p.body, 0600)
}
func loadPage(title string) (*page, os.Error) {
filename := title + ".txt"
body, err := ioutil.ReadFile(filename)
if err != nil {
return nil, err
}
return &page{title: title, body: body}, nil
}
const lenPath = len("/view/")
func editHandler(c *http.Conn, r *http.Request) {
title := r.URL.Path[lenPath:]
p, err := loadPage(title)
if err != nil {
p = &page{title: title}
}
renderTemplate(c, "view", p)
}
func viewHandler(c *http.Conn, r *http.Request) {
title := r.URL.Path[lenPath:]
p, _ := loadPage(title)
renderTemplate(c, "edit", p)
}
func saveHandler(c *http.Conn, r *http.Request) {
title := r.URL.Path[lenPath:]
body := r.FormValue("body")
p := &page{title: title, body: []byte(body)}
p.save()
http.Redirect(c, "/view/"+title, http.StatusFound)
}
func renderTemplate(c *http.Conn, tmpl string, p *page) {
t, _ := template.ParseFile(tmpl+".html", nil)
t.Execute(p, c)
}
func main() {
http.HandleFunc("/view/", viewHandler)
http.HandleFunc("/edit/", editHandler)
http.HandleFunc("/save/", saveHandler)
http.ListenAndServe(":8080", nil)
}
package main
import (
"http"
"io/ioutil"
"os"
"regexp"
"template"
)
type page struct {
title string
body []byte
}
func (p *page) save() os.Error {
filename := p.title + ".txt"
return ioutil.WriteFile(filename, p.body, 0600)
}
func loadPage(title string) (*page, os.Error) {
filename := title + ".txt"
body, err := ioutil.ReadFile(filename)
if err != nil {
return nil, err
}
return &page{title: title, body: body}, nil
}
func viewHandler(c *http.Conn, r *http.Request, title string) {
p, err := loadPage(title)
if err != nil {
http.Redirect(c, "/edit/"+title, http.StatusFound)
return
}
renderTemplate(c, "view", p)
}
func editHandler(c *http.Conn, r *http.Request, title string) {
p, err := loadPage(title)
if err != nil {
p = &page{title: title}
}
renderTemplate(c, "edit", p)
}
func saveHandler(c *http.Conn, r *http.Request, title string) {
body := r.FormValue("body")
p := &page{title: title, body: []byte(body)}
err := p.save()
if err != nil {
http.Error(c, err.String(), http.StatusInternalServerError)
return
}
http.Redirect(c, "/view/"+title, http.StatusFound)
}
var templates = make(map[string]*template.Template)
func init() {
for _, tmpl := range []string{"edit", "view"} {
templates[tmpl] = template.MustParseFile(tmpl+".html", nil)
}
}
func renderTemplate(c *http.Conn, tmpl string, p *page) {
err := templates[tmpl].Execute(p, c)
if err != nil {
http.Error(c, err.String(), http.StatusInternalServerError)
}
}
const lenPath = len("/view/")
var titleValidator = regexp.MustCompile("^[a-zA-Z0-9]+$")
func makeHandler(fn func(*http.Conn, *http.Request, string)) http.HandlerFunc {
return func(c *http.Conn, r *http.Request) {
title := r.URL.Path[lenPath:]
if !titleValidator.MatchString(title) {
http.NotFound(c, r)
return
}
fn(c, r, title)
}
}
func main() {
http.HandleFunc("/view/", makeHandler(viewHandler))
http.HandleFunc("/edit/", makeHandler(editHandler))
http.HandleFunc("/save/", makeHandler(saveHandler))
http.ListenAndServe(":8080", nil)
}
package main
import (
"os"
"template"
"io/ioutil"
)
func main() {
b, _ := ioutil.ReadAll(os.Stdin)
template.HTMLFormatter(os.Stdout, b, "")
}
package main
import (
"fmt"
"http"
)
func handler(c *http.Conn, r *http.Request) {
fmt.Fprintf(c, "Hi there, I love %s!", r.URL.Path[1:])
}
func main() {
http.HandleFunc("/", handler)
http.ListenAndServe(":8080", nil)
}
This diff is collapsed.
package main
import (
"fmt"
"http"
"io/ioutil"
"os"
)
type page struct {
title string
body []byte
}
func (p *page) save() os.Error {
filename := p.title + ".txt"
return ioutil.WriteFile(filename, p.body, 0600)
}
func loadPage(title string) (*page, os.Error) {
filename := title + ".txt"
body, err := ioutil.ReadFile(filename)
if err != nil {
return nil, err
}
return &page{title: title, body: body}, nil
}
const lenPath = len("/view/")
func viewHandler(c *http.Conn, r *http.Request) {
title := r.URL.Path[lenPath:]
p, _ := loadPage(title)
fmt.Fprintf(c, "<h1>%s</h1><div>%s</div>", p.title, p.body)
}
func editHandler(c *http.Conn, r *http.Request) {
title := r.URL.Path[lenPath:]
p, err := loadPage(title)
if err != nil {
p = &page{title: title}
}
fmt.Fprintf(c, "<h1>Editing %s</h1>"+
"<form action=\"/save/%s\" method=\"POST\">"+
"<textarea name=\"body\">%s</textarea><br>"+
"<input type=\"submit\" value=\"Save\">"+
"</form>",
p.title, p.title, p.body)
}
func main() {
http.HandleFunc("/view/", viewHandler)
http.HandleFunc("/edit/", editHandler)
http.ListenAndServe(":8080", nil)
}
package main
import (
"fmt"
"io/ioutil"
"os"
)
type page struct {
title string
body []byte
}
func (p *page) save() os.Error {
filename := p.title + ".txt"
return ioutil.WriteFile(filename, p.body, 0600)
}
func loadPage(title string) *page {
filename := title + ".txt"
body, _ := ioutil.ReadFile(filename)
return &page{title: title, body: body}
}
func main() {
p1 := &page{title: "TestPage", body: []byte("This is a sample page.")}
p1.save()
p2 := loadPage("TestPage")
fmt.Println(string(p2.body))
}
package main
import (
"fmt"
"io/ioutil"
"os"
)
type page struct {
title string
body []byte
}
func (p *page) save() os.Error {
filename := p.title + ".txt"
return ioutil.WriteFile(filename, p.body, 0600)
}
func loadPage(title string) (*page, os.Error) {
filename := title + ".txt"
body, err := ioutil.ReadFile(filename)
if err != nil {
return nil, err
}
return &page{title: title, body: body}, nil
}
func main() {
p1 := &page{title: "TestPage", body: []byte("This is a sample page.")}
p1.save()
p2, _ := loadPage("TestPage")
fmt.Println(string(p2.body))
}
package main
import (
"fmt"
"http"
"io/ioutil"
"os"
)
type page struct {
title string
body []byte
}
func (p *page) save() os.Error {
filename := p.title + ".txt"
return ioutil.WriteFile(filename, p.body, 0600)
}
func loadPage(title string) (*page, os.Error) {
filename := title + ".txt"
body, err := ioutil.ReadFile(filename)
if err != nil {
return nil, err
}
return &page{title: title, body: body}, nil
}
const lenPath = len("/view/")
func viewHandler(c *http.Conn, r *http.Request) {
title := r.URL.Path[lenPath:]
p, _ := loadPage(title)
fmt.Fprintf(c, "<h1>%s</h1><div>%s</div>", p.title, p.body)
}
func main() {
http.HandleFunc("/view/", viewHandler)
http.ListenAndServe(":8080", nil)
}
package main
import (
"bytes"
"flag"
"go/parser"
"go/printer"
"go/ast"
"log"
"os"
)
var (
srcFn = flag.String("src", "", "source filename")
getName = flag.String("name", "", "func/type name to output")
html = flag.Bool("html", true, "output HTML")
showPkg = flag.Bool("pkg", false, "show package in output")
)
func main() {
// handle input
flag.Parse()
if *srcFn == "" || *getName == "" {
flag.Usage()
os.Exit(2)
}
// load file
file, err := parser.ParseFile(*srcFn, nil, nil, 0)
if err != nil {
log.Exit(err)
}
// create printer
p := &printer.Config{
Mode: 0,
Tabwidth: 8,
Styler: nil,
}
if *html {
p.Mode = printer.GenHTML
}
// create filter
filter := func(name string) bool {
return name == *getName
}
// filter
if !ast.FilterFile(file, filter) {
os.Exit(1)
}
b := new(bytes.Buffer)
p.Fprint(b, file)
// drop package declaration
if !*showPkg {
for {
c, err := b.ReadByte()
if c == '\n' || err != nil {
break
}
}
}
// drop leading newlines
for {
b, err := b.ReadByte()
if err != nil {
break
}
if b != '\n' {
os.Stdout.Write([]byte{b})
break
}
}
// output
b.WriteTo(os.Stdout)
}
#1/bin/bash
./final.bin &
wiki_pid=$!
cleanup() {
kill $wiki_pid
rm -f test_*.out Test.txt
exit ${1:-1}
}
trap cleanup INT
sleep 1
curl -s -o test_edit.out http://localhost:8080/edit/Test
cmp test_edit.out test_edit.good || cleanup 1
curl -s -o /dev/null -d body=some%20content http://localhost:8080/save/Test
cmp Test.txt test_Test.txt.good || cleanup 1
curl -s -o test_view.out http://localhost:8080/view/Test
cmp test_view.out test_view.good || cleanup 1
echo "Passed"
cleanup 0
some content
\ No newline at end of file
<h1>Editing Test</h1>
<form action="/save/Test" method="POST">
<div><textarea name="body" rows="20" cols="80"></textarea></div>
<div><input type="submit" value="Save"></div>
</form>
<h1>Test</h1>
<p>[<a href="/edit/Test">edit</a>]</p>
<div>some content</div>
<h1>{title}</h1>
<p>[<a href="/edit/{title}">edit</a>]</p>
<div>{body}</div>
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment