Major rewrite
* use dep for vendoring * lets encrypt * moved web to transfer.sh-web repo * single command install * added first tests
This commit is contained in:
25
vendor/github.com/golang/gddo/talksapp/.gitignore
generated
vendored
Normal file
25
vendor/github.com/golang/gddo/talksapp/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
|
||||
# Folders
|
||||
_obj
|
||||
_test
|
||||
|
||||
# Architecture specific extensions/prefixes
|
||||
*.[568vq]
|
||||
[568vq].out
|
||||
|
||||
*.cgo1.go
|
||||
*.cgo2.c
|
||||
_cgo_defun.c
|
||||
_cgo_gotypes.go
|
||||
_cgo_export.*
|
||||
|
||||
_testmain.go
|
||||
|
||||
*.exe
|
||||
|
||||
present/
|
||||
prod.yaml
|
13
vendor/github.com/golang/gddo/talksapp/README.md
generated
vendored
Normal file
13
vendor/github.com/golang/gddo/talksapp/README.md
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
talksapp
|
||||
========
|
||||
|
||||
This directory contains the source for [go-talks.appspot.com](http://go-talks.appspot.com).
|
||||
|
||||
Development Environment Setup
|
||||
-----------------------------
|
||||
|
||||
- Copy `app.yaml` to `prod.yaml` and put in the authentication data.
|
||||
- Install Go App Engine SDK.
|
||||
- `$ sh setup.sh`
|
||||
- Run the server using the `goapp serve prod.yaml` command.
|
||||
- Run the tests using the `goapp test` command.
|
25
vendor/github.com/golang/gddo/talksapp/app.yaml
generated
vendored
Normal file
25
vendor/github.com/golang/gddo/talksapp/app.yaml
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
application: go-talks
|
||||
version: 1
|
||||
runtime: go
|
||||
api_version: go1
|
||||
|
||||
handlers:
|
||||
- url: /robots\.txt
|
||||
static_files: assets/robots.txt
|
||||
upload: assets/robots.txt
|
||||
- url: /favicon\.ico
|
||||
static_files: present/static/favicon.ico
|
||||
upload: present/static/favicon.ico
|
||||
- url: /static
|
||||
static_dir: present/static
|
||||
- url: /play\.js
|
||||
static_files: present/play.js
|
||||
upload: present/play.js
|
||||
- url: /.*
|
||||
script: _go_app
|
||||
|
||||
env_variables:
|
||||
CONTACT_EMAIL: '' # set contact email for /-/bot.html
|
||||
GITHUB_CLIENT_ID: '' # used to increase rate-limits; see https://github.com/settings/applications/new
|
||||
GITHUB_CLIENT_SECRET: '' # used to increase rate-limits; see https://github.com/settings/applications/new
|
||||
GITHUB_TOKEN: '' # personal token used for authentication; see https://github.com/settings/tokens/new
|
27
vendor/github.com/golang/gddo/talksapp/assets/home.article
generated
vendored
Normal file
27
vendor/github.com/golang/gddo/talksapp/assets/home.article
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
go-talks.appspot.org
|
||||
|
||||
Francesc Campoy (maintainer)
|
||||
@francesc
|
||||
|
||||
Gary Burd
|
||||
@gburd
|
||||
|
||||
* Introduction
|
||||
|
||||
This site plays slide presentations and articles stored on GitHub in the
|
||||
[[https://godoc.org/golang.org/x/tools/present][present format]].
|
||||
|
||||
The syntax for URLs is:
|
||||
|
||||
http://go-talks.appspot.com/github.com/owner/project/file.ext
|
||||
http://go-talks.appspot.com/github.com/owner/project/sub/directory/file.ext
|
||||
|
||||
The supported file extensions (.ext) are .slide and .article.
|
||||
|
||||
The .html command is not supported.
|
||||
|
||||
This page is [[/github.com/golang/gddo/talksapp/assets/home.article][an article]].
|
||||
|
||||
* Feedback
|
||||
|
||||
Report bugs and request features using the [[https://github.com/golang/gddo/issues/new][GitHub Issue Tracker]].
|
2
vendor/github.com/golang/gddo/talksapp/assets/robots.txt
generated
vendored
Normal file
2
vendor/github.com/golang/gddo/talksapp/assets/robots.txt
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
User-agent: *
|
||||
Disallow: /
|
252
vendor/github.com/golang/gddo/talksapp/main.go
generated
vendored
Normal file
252
vendor/github.com/golang/gddo/talksapp/main.go
generated
vendored
Normal file
@@ -0,0 +1,252 @@
|
||||
// Copyright 2013 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 or at
|
||||
// https://developers.google.com/open-source/licenses/bsd.
|
||||
|
||||
// Package talksapp implements the go-talks.appspot.com server.
|
||||
package talksapp
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"time"
|
||||
|
||||
"google.golang.org/appengine"
|
||||
"google.golang.org/appengine/log"
|
||||
"google.golang.org/appengine/memcache"
|
||||
"google.golang.org/appengine/urlfetch"
|
||||
|
||||
"github.com/golang/gddo/gosrc"
|
||||
"github.com/golang/gddo/httputil"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
"golang.org/x/tools/present"
|
||||
)
|
||||
|
||||
var (
|
||||
presentTemplates = map[string]*template.Template{
|
||||
".article": parsePresentTemplate("article.tmpl"),
|
||||
".slide": parsePresentTemplate("slides.tmpl"),
|
||||
}
|
||||
homeArticle = loadHomeArticle()
|
||||
contactEmail = "golang-dev@googlegroups.com"
|
||||
|
||||
// used for mocking in tests
|
||||
getPresentation = gosrc.GetPresentation
|
||||
playCompileURL = "https://play.golang.org/compile"
|
||||
)
|
||||
|
||||
func init() {
|
||||
http.Handle("/", handlerFunc(serveRoot))
|
||||
http.Handle("/compile", handlerFunc(serveCompile))
|
||||
http.Handle("/bot.html", handlerFunc(serveBot))
|
||||
present.PlayEnabled = true
|
||||
if s := os.Getenv("CONTACT_EMAIL"); s != "" {
|
||||
contactEmail = s
|
||||
}
|
||||
|
||||
if appengine.IsDevAppServer() {
|
||||
return
|
||||
}
|
||||
github := httputil.NewAuthTransportFromEnvironment(nil)
|
||||
if github.Token == "" || github.ClientID == "" || github.ClientSecret == "" {
|
||||
panic("missing GitHub metadata, follow the instructions on README.md")
|
||||
}
|
||||
}
|
||||
|
||||
func playable(c present.Code) bool {
|
||||
return present.PlayEnabled && c.Play && c.Ext == ".go"
|
||||
}
|
||||
|
||||
func parsePresentTemplate(name string) *template.Template {
|
||||
t := present.Template()
|
||||
t = t.Funcs(template.FuncMap{"playable": playable})
|
||||
if _, err := t.ParseFiles("present/templates/"+name, "present/templates/action.tmpl"); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
t = t.Lookup("root")
|
||||
if t == nil {
|
||||
panic("root template not found for " + name)
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
func loadHomeArticle() []byte {
|
||||
const fname = "assets/home.article"
|
||||
f, err := os.Open(fname)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer f.Close()
|
||||
doc, err := present.Parse(f, fname, 0)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
if err := renderPresentation(&buf, fname, doc); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
func renderPresentation(w io.Writer, fname string, doc *present.Doc) error {
|
||||
t := presentTemplates[path.Ext(fname)]
|
||||
if t == nil {
|
||||
return errors.New("unknown template extension")
|
||||
}
|
||||
data := struct {
|
||||
*present.Doc
|
||||
Template *template.Template
|
||||
PlayEnabled bool
|
||||
NotesEnabled bool
|
||||
}{doc, t, true, true}
|
||||
return t.Execute(w, &data)
|
||||
}
|
||||
|
||||
type presFileNotFoundError string
|
||||
|
||||
func (s presFileNotFoundError) Error() string { return fmt.Sprintf("File %s not found.", string(s)) }
|
||||
|
||||
func writeHTMLHeader(w http.ResponseWriter, status int) {
|
||||
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||
w.WriteHeader(status)
|
||||
}
|
||||
|
||||
func writeTextHeader(w http.ResponseWriter, status int) {
|
||||
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
||||
w.WriteHeader(status)
|
||||
}
|
||||
|
||||
func httpClient(r *http.Request) *http.Client {
|
||||
ctx, _ := context.WithTimeout(appengine.NewContext(r), 10*time.Second)
|
||||
github := httputil.NewAuthTransportFromEnvironment(nil)
|
||||
|
||||
return &http.Client{
|
||||
Transport: &httputil.AuthTransport{
|
||||
Token: github.Token,
|
||||
ClientID: github.ClientID,
|
||||
ClientSecret: github.ClientSecret,
|
||||
Base: &urlfetch.Transport{Context: ctx},
|
||||
UserAgent: fmt.Sprintf("%s (+http://%s/-/bot)", appengine.AppID(ctx), r.Host),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
type handlerFunc func(http.ResponseWriter, *http.Request) error
|
||||
|
||||
func (f handlerFunc) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := appengine.NewContext(r)
|
||||
|
||||
err := f(w, r)
|
||||
if err == nil {
|
||||
return
|
||||
} else if gosrc.IsNotFound(err) {
|
||||
writeTextHeader(w, 400)
|
||||
io.WriteString(w, "Not Found.")
|
||||
} else if e, ok := err.(*gosrc.RemoteError); ok {
|
||||
writeTextHeader(w, 500)
|
||||
fmt.Fprintf(w, "Error accessing %s.\n%v", e.Host, e)
|
||||
log.Infof(ctx, "Remote error %s: %v", e.Host, e)
|
||||
} else if e, ok := err.(presFileNotFoundError); ok {
|
||||
writeTextHeader(w, 200)
|
||||
io.WriteString(w, e.Error())
|
||||
} else if err != nil {
|
||||
writeTextHeader(w, 500)
|
||||
io.WriteString(w, "Internal server error.")
|
||||
log.Errorf(ctx, "Internal error %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func serveRoot(w http.ResponseWriter, r *http.Request) error {
|
||||
switch {
|
||||
case r.Method != "GET" && r.Method != "HEAD":
|
||||
writeTextHeader(w, 405)
|
||||
_, err := io.WriteString(w, "Method not supported.")
|
||||
return err
|
||||
case r.URL.Path == "/":
|
||||
writeHTMLHeader(w, 200)
|
||||
_, err := w.Write(homeArticle)
|
||||
return err
|
||||
default:
|
||||
return servePresentation(w, r)
|
||||
}
|
||||
}
|
||||
|
||||
func servePresentation(w http.ResponseWriter, r *http.Request) error {
|
||||
ctx := appengine.NewContext(r)
|
||||
importPath := r.URL.Path[1:]
|
||||
|
||||
item, err := memcache.Get(ctx, importPath)
|
||||
if err == nil {
|
||||
writeHTMLHeader(w, 200)
|
||||
w.Write(item.Value)
|
||||
return nil
|
||||
} else if err != memcache.ErrCacheMiss {
|
||||
log.Errorf(ctx, "Could not get item from Memcache: %v", err)
|
||||
}
|
||||
|
||||
log.Infof(ctx, "Fetching presentation %s.", importPath)
|
||||
pres, err := getPresentation(httpClient(r), importPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
parser := &present.Context{
|
||||
ReadFile: func(name string) ([]byte, error) {
|
||||
if p, ok := pres.Files[name]; ok {
|
||||
return p, nil
|
||||
}
|
||||
return nil, presFileNotFoundError(name)
|
||||
},
|
||||
}
|
||||
doc, err := parser.Parse(bytes.NewReader(pres.Files[pres.Filename]), pres.Filename, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
if err := renderPresentation(&buf, importPath, doc); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := memcache.Add(ctx, &memcache.Item{
|
||||
Key: importPath,
|
||||
Value: buf.Bytes(),
|
||||
Expiration: time.Hour,
|
||||
}); err != nil {
|
||||
log.Errorf(ctx, "Could not cache presentation %s: %v", importPath, err)
|
||||
return nil
|
||||
}
|
||||
|
||||
writeHTMLHeader(w, 200)
|
||||
_, err = w.Write(buf.Bytes())
|
||||
return err
|
||||
}
|
||||
|
||||
func serveCompile(w http.ResponseWriter, r *http.Request) error {
|
||||
client := urlfetch.Client(appengine.NewContext(r))
|
||||
if err := r.ParseForm(); err != nil {
|
||||
return err
|
||||
}
|
||||
resp, err := client.PostForm(playCompileURL, r.Form)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
w.Header().Set("Content-Type", resp.Header.Get("Content-Type"))
|
||||
_, err = io.Copy(w, resp.Body)
|
||||
return err
|
||||
}
|
||||
|
||||
func serveBot(w http.ResponseWriter, r *http.Request) error {
|
||||
ctx := appengine.NewContext(r)
|
||||
writeTextHeader(w, 200)
|
||||
_, err := fmt.Fprintf(w, "Contact %s for help with the %s bot.", contactEmail, appengine.AppID(ctx))
|
||||
return err
|
||||
}
|
236
vendor/github.com/golang/gddo/talksapp/main_test.go
generated
vendored
Normal file
236
vendor/github.com/golang/gddo/talksapp/main_test.go
generated
vendored
Normal file
@@ -0,0 +1,236 @@
|
||||
// Copyright 2015 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 or at
|
||||
// https://developers.google.com/open-source/licenses/bsd.
|
||||
|
||||
package talksapp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"google.golang.org/appengine"
|
||||
"google.golang.org/appengine/aetest"
|
||||
"google.golang.org/appengine/memcache"
|
||||
|
||||
"github.com/golang/gddo/gosrc"
|
||||
)
|
||||
|
||||
const importPath = "github.com/user/repo/path/to/presentation.slide"
|
||||
|
||||
func TestHome(t *testing.T) {
|
||||
do(t, "GET", "/", func(r *http.Request) {
|
||||
w := httptest.NewRecorder()
|
||||
handlerFunc(serveRoot).ServeHTTP(w, r)
|
||||
|
||||
if w.Code != http.StatusOK {
|
||||
t.Fatalf("expected status: %d, got: %d", http.StatusOK, w.Code)
|
||||
}
|
||||
|
||||
if !strings.Contains(w.Body.String(), "go-talks.appspot.org") {
|
||||
t.Fatal("expected response to contain: go-talks.appspot.org")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestPresentation(t *testing.T) {
|
||||
presentationTitle := "My awesome presentation!"
|
||||
presentationSrc := []byte(presentationTitle + `
|
||||
|
||||
Subtitle
|
||||
|
||||
* Slide 1
|
||||
|
||||
- Foo
|
||||
- Bar
|
||||
- Baz
|
||||
`)
|
||||
|
||||
originalGetPresentation := getPresentation
|
||||
getPresentation = func(client *http.Client, importPath string) (*gosrc.Presentation, error) {
|
||||
return &gosrc.Presentation{
|
||||
Filename: "presentation.slide",
|
||||
Files: map[string][]byte{
|
||||
"presentation.slide": presentationSrc,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
defer func() {
|
||||
getPresentation = originalGetPresentation
|
||||
}()
|
||||
|
||||
do(t, "GET", "/"+importPath, func(r *http.Request) {
|
||||
w := httptest.NewRecorder()
|
||||
handlerFunc(serveRoot).ServeHTTP(w, r)
|
||||
|
||||
if w.Code != http.StatusOK {
|
||||
t.Fatalf("expected status: %d, got: %d", http.StatusOK, w.Code)
|
||||
}
|
||||
|
||||
if !strings.Contains(w.Body.String(), presentationTitle) {
|
||||
t.Fatalf("unexpected response body: %s", w.Body)
|
||||
}
|
||||
|
||||
c := appengine.NewContext(r)
|
||||
_, err := memcache.Get(c, importPath)
|
||||
|
||||
if err == memcache.ErrCacheMiss {
|
||||
t.Fatal("expected result to be cached")
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("expected no error, got: %s", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestPresentationCacheHit(t *testing.T) {
|
||||
do(t, "GET", "/"+importPath, func(r *http.Request) {
|
||||
cachedPresentation := "<div>My Presentation</div>"
|
||||
|
||||
c := appengine.NewContext(r)
|
||||
memcache.Add(c, &memcache.Item{
|
||||
Key: importPath,
|
||||
Value: []byte(cachedPresentation),
|
||||
Expiration: time.Hour,
|
||||
})
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
handlerFunc(serveRoot).ServeHTTP(w, r)
|
||||
|
||||
if w.Code != http.StatusOK {
|
||||
t.Fatalf("expected status: %d, got: %d", http.StatusOK, w.Code)
|
||||
}
|
||||
|
||||
if w.Body.String() != cachedPresentation {
|
||||
t.Fatal("response does not matched cached presentation")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestPresentationNotFound(t *testing.T) {
|
||||
originalGetPresentation := getPresentation
|
||||
getPresentation = func(client *http.Client, importPath string) (*gosrc.Presentation, error) {
|
||||
return nil, gosrc.NotFoundError{}
|
||||
}
|
||||
defer func() {
|
||||
getPresentation = originalGetPresentation
|
||||
}()
|
||||
|
||||
do(t, "GET", "/"+importPath, func(r *http.Request) {
|
||||
w := httptest.NewRecorder()
|
||||
handlerFunc(serveRoot).ServeHTTP(w, r)
|
||||
|
||||
if w.Code != http.StatusBadRequest {
|
||||
t.Fatalf("expected status: %d, got: %d", http.StatusBadRequest, w.Code)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestWrongMethod(t *testing.T) {
|
||||
do(t, "POST", "/", func(r *http.Request) {
|
||||
w := httptest.NewRecorder()
|
||||
handlerFunc(serveRoot).ServeHTTP(w, r)
|
||||
|
||||
if w.Code != http.StatusMethodNotAllowed {
|
||||
t.Fatalf("expected status %d", http.StatusMethodNotAllowed)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestCompile(t *testing.T) {
|
||||
version := "2"
|
||||
body := `
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
fmt.fmtPrintln("Hello, playground")
|
||||
}
|
||||
`
|
||||
responseJSON := `{"Errors":"","Events":[{"Message":"Hello, playground\n","Kind":"stdout","Delay":0}]}`
|
||||
|
||||
server := httptest.NewServer(
|
||||
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
formVersion := r.FormValue("version")
|
||||
formBody := r.FormValue("body")
|
||||
|
||||
if formVersion != version {
|
||||
t.Fatalf("expected version sent to play.golang.org to be: %s, was: %s", version, formVersion)
|
||||
}
|
||||
|
||||
if formBody != body {
|
||||
t.Fatalf("expected body sent to play.golang.org to be: %s, was: %s", body, formBody)
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(200)
|
||||
|
||||
fmt.Fprintln(w, responseJSON)
|
||||
}),
|
||||
)
|
||||
defer server.Close()
|
||||
|
||||
defer func(old string) { playCompileURL = old }(playCompileURL)
|
||||
playCompileURL = server.URL
|
||||
|
||||
do(t, "POST", "/compile", func(r *http.Request) {
|
||||
r.PostForm = url.Values{
|
||||
"version": []string{version},
|
||||
"body": []string{body},
|
||||
}
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
handlerFunc(serveCompile).ServeHTTP(w, r)
|
||||
|
||||
if w.Code != http.StatusOK {
|
||||
t.Fatalf("expected status: %d, got: %d", http.StatusOK, w.Code)
|
||||
}
|
||||
|
||||
contentType := w.Header().Get("Content-Type")
|
||||
if w.Header().Get("Content-Type") != "application/json" {
|
||||
t.Fatalf("unexpected Content-Type: %s", contentType)
|
||||
}
|
||||
|
||||
if strings.TrimSpace(w.Body.String()) != responseJSON {
|
||||
t.Fatalf("unexpected response body: %s", w.Body)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestBot(t *testing.T) {
|
||||
do(t, "GET", "/bot.html", func(r *http.Request) {
|
||||
w := httptest.NewRecorder()
|
||||
handlerFunc(serveBot).ServeHTTP(w, r)
|
||||
|
||||
if w.Code != http.StatusOK {
|
||||
t.Fatalf("expected status: %d, got: %d", http.StatusOK, w.Code)
|
||||
}
|
||||
|
||||
if !strings.Contains(w.Body.String(), contactEmail) {
|
||||
t.Fatalf("expected body to contain %s", contactEmail)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func do(t *testing.T, method, path string, f func(*http.Request)) {
|
||||
i, err := aetest.NewInstance(nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer i.Close()
|
||||
|
||||
r, err := i.NewRequest(method, path, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
f(r)
|
||||
}
|
14
vendor/github.com/golang/gddo/talksapp/setup.sh
generated
vendored
Executable file
14
vendor/github.com/golang/gddo/talksapp/setup.sh
generated
vendored
Executable file
@@ -0,0 +1,14 @@
|
||||
#!/bin/sh
|
||||
go get golang.org/x/tools/cmd/present
|
||||
go get golang.org/x/tools/godoc
|
||||
present=`go list -f '{{.Dir}}' golang.org/x/tools/cmd/present`
|
||||
godoc=`go list -f '{{.Dir}}' golang.org/x/tools/godoc`
|
||||
mkdir -p present
|
||||
|
||||
(cat $godoc/static/jquery.js $godoc/static/playground.js $godoc/static/play.js && echo "initPlayground(new HTTPTransport());") > present/play.js
|
||||
|
||||
cd ./present
|
||||
for i in templates static
|
||||
do
|
||||
ln -is $present/$i
|
||||
done
|
Reference in New Issue
Block a user