cmd/present: merge appengine and non-appengine files
Without changing the behavior of the present command for local usage (using the local socket for running examples, defaulting to the current directory for all content). Add flags and set them to the appropriate values if running on App Engine. Notably, since the Go files must be in the same directory as app.yaml, the content root must be ./content/ to avoid listing the present source files. It also defaults to running example snippets via the HTTPTransport (https://play.golang.org/compile) instead of locally when on App Engine. There are also some small cleanup code changes. Update golang/go#28080 Change-Id: I40bb7923107614f88d2bfdffd34a824d4bacb3a1 Reviewed-on: https://go-review.googlesource.com/c/140841 Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org> Reviewed-by: Bryan C. Mills <bcmills@google.com>
This commit is contained in:
parent
f78a1e9345
commit
37fd46feae
|
@ -1,22 +0,0 @@
|
|||
// Copyright 2012 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.
|
||||
|
||||
// +build appengine
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"mime"
|
||||
|
||||
"golang.org/x/tools/present"
|
||||
)
|
||||
|
||||
func init() {
|
||||
initTemplates("./present/")
|
||||
present.PlayEnabled = true
|
||||
initPlayground("./present/", nil)
|
||||
|
||||
// App Engine has no /etc/mime.types
|
||||
mime.AddExtensionType(".svg", "image/svg+xml")
|
||||
}
|
|
@ -13,6 +13,7 @@ import (
|
|||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/tools/present"
|
||||
)
|
||||
|
@ -21,19 +22,18 @@ func init() {
|
|||
http.HandleFunc("/", dirHandler)
|
||||
}
|
||||
|
||||
// dirHandler serves a directory listing for the requested path, rooted at basePath.
|
||||
// dirHandler serves a directory listing for the requested path, rooted at *contentPath.
|
||||
func dirHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if r.URL.Path == "/favicon.ico" {
|
||||
http.Error(w, "not found", 404)
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
const base = "."
|
||||
name := filepath.Join(base, r.URL.Path)
|
||||
name := filepath.Join(*contentPath, r.URL.Path)
|
||||
if isDoc(name) {
|
||||
err := renderDoc(w, name)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, err.Error(), 500)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@ -43,12 +43,12 @@ func dirHandler(w http.ResponseWriter, r *http.Request) {
|
|||
addr = r.RemoteAddr
|
||||
}
|
||||
log.Printf("request from %s: %s", addr, err)
|
||||
http.Error(w, err.Error(), 500)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
} else if isDir {
|
||||
return
|
||||
}
|
||||
http.FileServer(http.Dir(base)).ServeHTTP(w, r)
|
||||
http.FileServer(http.Dir(*contentPath)).ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
func isDoc(path string) bool {
|
||||
|
@ -138,7 +138,9 @@ func dirList(w io.Writer, name string) (isDir bool, err error) {
|
|||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
d := &dirListData{Path: name}
|
||||
strippedPath := strings.TrimPrefix(name, filepath.Clean(*contentPath))
|
||||
strippedPath = strings.TrimPrefix(strippedPath, "/")
|
||||
d := &dirListData{Path: strippedPath}
|
||||
for _, fi := range fis {
|
||||
// skip the golang.org directory
|
||||
if name == "." && fi.Name() == "golang.org" {
|
||||
|
@ -146,15 +148,16 @@ func dirList(w io.Writer, name string) (isDir bool, err error) {
|
|||
}
|
||||
e := dirEntry{
|
||||
Name: fi.Name(),
|
||||
Path: filepath.ToSlash(filepath.Join(name, fi.Name())),
|
||||
Path: filepath.ToSlash(filepath.Join(strippedPath, fi.Name())),
|
||||
}
|
||||
if fi.IsDir() && showDir(e.Name) {
|
||||
d.Dirs = append(d.Dirs, e)
|
||||
continue
|
||||
}
|
||||
if isDoc(e.Name) {
|
||||
if p, err := parse(e.Path, present.TitlesOnly); err != nil {
|
||||
log.Println(err)
|
||||
fn := filepath.ToSlash(filepath.Join(name, fi.Name()))
|
||||
if p, err := parse(fn, present.TitlesOnly); err != nil {
|
||||
log.Printf("parse(%q, present.TitlesOnly): %v", fn, err)
|
||||
} else {
|
||||
e.Title = p.Title
|
||||
}
|
||||
|
|
|
@ -8,43 +8,38 @@ presents slide and article files from the current directory.
|
|||
|
||||
It may be run as a stand-alone command or an App Engine app.
|
||||
|
||||
Usage of present:
|
||||
-base="": base path for slide template and static resources
|
||||
-http="127.0.0.1:3999": HTTP service address (e.g., '127.0.0.1:3999')
|
||||
-nacl=false: use Native Client environment playground (prevents non-Go code execution)
|
||||
-notes=false: enable presenter notes (press 'N' from the browser to display them)
|
||||
-orighost="": host component of web origin URL (e.g., 'localhost')
|
||||
-play=true: enable playground (permit execution of arbitrary user code)
|
||||
|
||||
The setup of the Go version of NaCl is documented at:
|
||||
https://golang.org/wiki/NativeClient
|
||||
|
||||
To use with App Engine, copy the tools/cmd/present directory to the root of
|
||||
your application and create an app.yaml file similar to this:
|
||||
To use with App Engine, copy the files in the tools/cmd/present directory to the
|
||||
root of your application and create an app.yaml file similar to this:
|
||||
|
||||
application: [application]
|
||||
version: [version]
|
||||
runtime: go
|
||||
api_version: go1
|
||||
runtime: go111
|
||||
|
||||
handlers:
|
||||
- url: /favicon.ico
|
||||
static_files: present/static/favicon.ico
|
||||
upload: present/static/favicon.ico
|
||||
static_files: static/favicon.ico
|
||||
upload: static/favicon.ico
|
||||
- url: /static
|
||||
static_dir: present/static
|
||||
application_readable: true
|
||||
static_dir: static
|
||||
- url: /.*
|
||||
script: _go_app
|
||||
script: auto
|
||||
|
||||
# nobuild_files is a regexp that identifies which files to not build. It
|
||||
# is useful for embedding static assets like code snippets and preventing
|
||||
# them from producing build errors for your project.
|
||||
nobuild_files: [path regexp for talk materials]
|
||||
|
||||
When running on App Engine, content will be served from the ./content/
|
||||
subdirectory.
|
||||
|
||||
Present then can be tested in a local App Engine environment with
|
||||
|
||||
goapp serve
|
||||
GAE_ENV=standard go run .
|
||||
|
||||
And deployed using
|
||||
|
||||
gcloud app deploy
|
||||
|
||||
Input files are named foo.extension, where "extension" defines the format of
|
||||
the generated output. The supported formats are:
|
||||
|
@ -54,4 +49,4 @@ the generated output. The supported formats are:
|
|||
The present file format is documented by the present package:
|
||||
http://godoc.org/golang.org/x/tools/present
|
||||
*/
|
||||
package main // import "golang.org/x/tools/cmd/present"
|
||||
package main
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !appengine
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
|
@ -23,10 +21,12 @@ import (
|
|||
const basePkg = "golang.org/x/tools/cmd/present"
|
||||
|
||||
var (
|
||||
httpAddr = flag.String("http", "127.0.0.1:3999", "HTTP service address (e.g., '127.0.0.1:3999')")
|
||||
originHost = flag.String("orighost", "", "host component of web origin URL (e.g., 'localhost')")
|
||||
basePath = flag.String("base", "", "base path for slide template and static resources")
|
||||
nativeClient = flag.Bool("nacl", false, "use Native Client environment playground (prevents non-Go code execution)")
|
||||
httpAddr = flag.String("http", "127.0.0.1:3999", "HTTP service address (e.g., '127.0.0.1:3999')")
|
||||
originHost = flag.String("orighost", "", "host component of web origin URL (e.g., 'localhost')")
|
||||
basePath = flag.String("base", "", "base path for slide template and static resources")
|
||||
contentPath = flag.String("content", ".", "base path for presentation content")
|
||||
usePlayground = flag.Bool("use_playground", false, "if false, arbitrary code (Go, shell scripts, etc.) is run locally via WebSocket transport; otherwise it uses play.golang.org")
|
||||
nativeClient = flag.Bool("nacl", false, "use Native Client environment playground (prevents non-Go code execution) when using local WebSocket transport")
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
@ -34,6 +34,23 @@ func main() {
|
|||
flag.BoolVar(&present.NotesEnabled, "notes", false, "enable presenter notes (press 'N' from the browser to display them)")
|
||||
flag.Parse()
|
||||
|
||||
if os.Getenv("GAE_ENV") == "standard" {
|
||||
log.Print("Configuring for App Engine Standard")
|
||||
port := os.Getenv("PORT")
|
||||
if port == "" {
|
||||
port = "8080"
|
||||
}
|
||||
*httpAddr = fmt.Sprintf("0.0.0.0:%s", port)
|
||||
pwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Couldn't get pwd: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
*basePath = pwd
|
||||
*usePlayground = true
|
||||
*contentPath = "./content/"
|
||||
}
|
||||
|
||||
if *basePath == "" {
|
||||
p, err := build.Default.Import(basePkg, "", build.FindOnly)
|
||||
if err != nil {
|
||||
|
@ -81,7 +98,7 @@ func main() {
|
|||
http.Handle("/static/", http.FileServer(http.Dir(*basePath)))
|
||||
|
||||
if !ln.Addr().(*net.TCPAddr).IP.IsLoopback() &&
|
||||
present.PlayEnabled && !*nativeClient {
|
||||
present.PlayEnabled && !*nativeClient && !*usePlayground {
|
||||
log.Print(localhostWarning)
|
||||
}
|
||||
|
||||
|
@ -121,11 +138,12 @@ You may use the -base flag to specify an alternate location.
|
|||
const localhostWarning = `
|
||||
WARNING! WARNING! WARNING!
|
||||
|
||||
The present server appears to be listening on an address that is not localhost.
|
||||
Anyone with access to this address and port will have access to this machine as
|
||||
the user running present.
|
||||
The present server appears to be listening on an address that is not localhost
|
||||
and using socket transport for running Go code. Anyone with access to this address
|
||||
and port will have access to this machine as the user running present.
|
||||
|
||||
To avoid this message, listen on localhost or run with -play=false.
|
||||
To avoid this message, listen on localhost, run with -play=false, or run with
|
||||
-play_socket=false.
|
||||
|
||||
If you don't understand this message, hit Control-C to terminate this process.
|
||||
|
|
@ -9,10 +9,21 @@ import (
|
|||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"time"
|
||||
|
||||
"golang.org/x/tools/godoc/static"
|
||||
"golang.org/x/tools/playground/socket"
|
||||
"golang.org/x/tools/present"
|
||||
|
||||
// This will register handlers at /compile and /share that will proxy to the
|
||||
// respective endpoints at play.golang.org. This allows the frontend to call
|
||||
// these endpoints without needing cross-origin request sharing (CORS).
|
||||
// Note that this is imported regardless of whether the endpoints are used or
|
||||
// not (in the case of a local socket connection, they are not called).
|
||||
_ "golang.org/x/tools/playground"
|
||||
)
|
||||
|
||||
var scripts = []string{"jquery.js", "jquery-ui.js", "playground.js", "play.js"}
|
||||
|
@ -41,3 +52,38 @@ func playScript(root, transport string) {
|
|||
http.ServeContent(w, r, "", modTime, bytes.NewReader(b))
|
||||
})
|
||||
}
|
||||
|
||||
func initPlayground(basepath string, origin *url.URL) {
|
||||
if !present.PlayEnabled {
|
||||
return
|
||||
}
|
||||
if *usePlayground {
|
||||
playScript(basepath, "HTTPTransport")
|
||||
return
|
||||
}
|
||||
|
||||
if *nativeClient {
|
||||
// When specifying nativeClient, non-Go code cannot be executed
|
||||
// because the NaCl setup doesn't support doing so.
|
||||
socket.RunScripts = false
|
||||
socket.Environ = func() []string {
|
||||
if runtime.GOARCH == "amd64" {
|
||||
return environ("GOOS=nacl", "GOARCH=amd64p32")
|
||||
}
|
||||
return environ("GOOS=nacl")
|
||||
}
|
||||
}
|
||||
playScript(basepath, "SocketTransport")
|
||||
http.Handle("/socket", socket.NewHandler(origin))
|
||||
}
|
||||
|
||||
func playable(c present.Code) bool {
|
||||
play := present.PlayEnabled && c.Play
|
||||
|
||||
// Restrict playable files to only Go source files when using play.golang.org,
|
||||
// since there is no method to execute shell scripts there.
|
||||
if *usePlayground {
|
||||
return play && c.Ext == ".go"
|
||||
}
|
||||
return play
|
||||
}
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
// 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.
|
||||
|
||||
// +build appengine appenginevm
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
|
||||
"golang.org/x/tools/present"
|
||||
|
||||
_ "golang.org/x/tools/playground"
|
||||
)
|
||||
|
||||
func initPlayground(basepath string, origin *url.URL) {
|
||||
playScript(basepath, "HTTPTransport")
|
||||
}
|
||||
|
||||
func playable(c present.Code) bool {
|
||||
return present.PlayEnabled && c.Play && c.Ext == ".go"
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
// 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.
|
||||
|
||||
// +build !appengine,!appenginevm
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"runtime"
|
||||
|
||||
"golang.org/x/tools/playground/socket"
|
||||
"golang.org/x/tools/present"
|
||||
)
|
||||
|
||||
func initPlayground(basepath string, origin *url.URL) {
|
||||
if present.PlayEnabled {
|
||||
if *nativeClient {
|
||||
socket.RunScripts = false
|
||||
socket.Environ = func() []string {
|
||||
if runtime.GOARCH == "amd64" {
|
||||
return environ("GOOS=nacl", "GOARCH=amd64p32")
|
||||
}
|
||||
return environ("GOOS=nacl")
|
||||
}
|
||||
}
|
||||
playScript(basepath, "SocketTransport")
|
||||
http.Handle("/socket", socket.NewHandler(origin))
|
||||
}
|
||||
}
|
||||
|
||||
func playable(c present.Code) bool {
|
||||
return present.PlayEnabled && c.Play
|
||||
}
|
Loading…
Reference in New Issue