mirror of
https://github.com/golang/go
synced 2024-11-21 13:14:40 -07:00
parent
df74d8df09
commit
e2df7f42ac
13
misc/goplay/Makefile
Normal file
13
misc/goplay/Makefile
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
# 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.inc
|
||||||
|
|
||||||
|
TARG=goplay
|
||||||
|
|
||||||
|
GOFILES=\
|
||||||
|
goplay.go\
|
||||||
|
|
||||||
|
include ../../src/Make.cmd
|
||||||
|
|
1
misc/goplay/README
Normal file
1
misc/goplay/README
Normal file
@ -0,0 +1 @@
|
|||||||
|
See doc.go.
|
25
misc/goplay/doc.go
Normal file
25
misc/goplay/doc.go
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
// Goplay is a web interface for experimenting with Go code.
|
||||||
|
// It is similar to the Go Playground: http://golang.org/doc/play/
|
||||||
|
//
|
||||||
|
// To use goplay, first build and install it:
|
||||||
|
// $ cd $GOROOT/misc/goplay
|
||||||
|
// $ gomake install
|
||||||
|
// Then, run it:
|
||||||
|
// $ goplay
|
||||||
|
// and load http://localhost:3999/ in a web browser.
|
||||||
|
//
|
||||||
|
// You should see a Hello World program, which you can compile and run by
|
||||||
|
// pressing shift-enter. There is also a "compile-on-keypress" feature that can
|
||||||
|
// be enabled by checking a checkbox.
|
||||||
|
//
|
||||||
|
// WARNING! CUIDADO! ACHTUNG! ATTENZIONE!
|
||||||
|
// A note on security: anyone with access to the goplay web interface can run
|
||||||
|
// arbitrary code on your computer. Goplay is not a sandbox, and has no other
|
||||||
|
// security mechanisms. Do not deploy it in untrusted environments.
|
||||||
|
// By default, goplay listens only on localhost. This can be overridden with
|
||||||
|
// the -http parameter. Do so at your own risk.
|
||||||
|
package documentation
|
305
misc/goplay/goplay.go
Normal file
305
misc/goplay/goplay.go
Normal file
@ -0,0 +1,305 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"exec"
|
||||||
|
"flag"
|
||||||
|
"http"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"runtime"
|
||||||
|
"strconv"
|
||||||
|
"template"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
httpListen = flag.String("http", "127.0.0.1:3999", "host:port to listen on")
|
||||||
|
htmlOutput = flag.Bool("html", false, "render program output as HTML")
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// a source of numbers, for naming temporary files
|
||||||
|
uniq = make(chan int)
|
||||||
|
// the architecture-identifying character of the tool chain, 5, 6, or 8
|
||||||
|
archChar string
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
// set archChar
|
||||||
|
switch runtime.GOARCH {
|
||||||
|
case "arm":
|
||||||
|
archChar = "5"
|
||||||
|
case "amd64":
|
||||||
|
archChar = "6"
|
||||||
|
case "386":
|
||||||
|
archChar = "8"
|
||||||
|
default:
|
||||||
|
log.Exitln("unrecognized GOARCH:", runtime.GOARCH)
|
||||||
|
}
|
||||||
|
|
||||||
|
// source of unique numbers
|
||||||
|
go func() {
|
||||||
|
for i := 0; ; i++ {
|
||||||
|
uniq <- i
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
http.HandleFunc("/", FrontPage)
|
||||||
|
http.HandleFunc("/compile", Compile)
|
||||||
|
log.Exit(http.ListenAndServe(*httpListen, nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
// FrontPage is an HTTP handler that renders the goplay interface.
|
||||||
|
// If a filename is supplied in the path component of the URI,
|
||||||
|
// its contents will be put in the interface's text area.
|
||||||
|
// Otherwise, the default "hello, world" program is displayed.
|
||||||
|
func FrontPage(w http.ResponseWriter, req *http.Request) {
|
||||||
|
data, err := ioutil.ReadFile(req.URL.Path[1:])
|
||||||
|
if err != nil {
|
||||||
|
data = helloWorld
|
||||||
|
}
|
||||||
|
frontPage.Execute(data, w)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compile is an HTTP handler that reads Go source code from the request,
|
||||||
|
// compiles and links the code (returning any errors), runs the program,
|
||||||
|
// and sends the program's output as the HTTP response.
|
||||||
|
func Compile(w http.ResponseWriter, req *http.Request) {
|
||||||
|
// x is the base name for .go, .6, executable files
|
||||||
|
x := "/tmp/compile" + strconv.Itoa(<-uniq)
|
||||||
|
|
||||||
|
// write request Body to x.go
|
||||||
|
f, err := os.Open(x+".go", os.O_CREAT|os.O_WRONLY|os.O_TRUNC, 0666)
|
||||||
|
if err != nil {
|
||||||
|
error(w, nil, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer os.Remove(x + ".go")
|
||||||
|
defer f.Close()
|
||||||
|
_, err = io.Copy(f, req.Body)
|
||||||
|
if err != nil {
|
||||||
|
error(w, nil, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
f.Close()
|
||||||
|
|
||||||
|
// build x.go, creating x.6
|
||||||
|
out, err := run(archChar+"g", "-o", x+"."+archChar, x+".go")
|
||||||
|
defer os.Remove(x + "." + archChar)
|
||||||
|
if err != nil {
|
||||||
|
error(w, out, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// link x.6, creating x (the program binary)
|
||||||
|
out, err = run(archChar+"l", "-o", x, x+"."+archChar)
|
||||||
|
defer os.Remove(x)
|
||||||
|
if err != nil {
|
||||||
|
error(w, out, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// run x
|
||||||
|
out, err = run(x)
|
||||||
|
if err != nil {
|
||||||
|
error(w, out, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// write the output of x as the http response
|
||||||
|
if *htmlOutput {
|
||||||
|
w.Write(out)
|
||||||
|
} else {
|
||||||
|
output.Execute(out, w)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// error writes compile, link, or runtime errors to the HTTP connection.
|
||||||
|
// The JavaScript interface uses the 404 status code to identify the error.
|
||||||
|
func error(w http.ResponseWriter, out []byte, err os.Error) {
|
||||||
|
w.WriteHeader(404)
|
||||||
|
if out != nil {
|
||||||
|
output.Execute(out, w)
|
||||||
|
} else {
|
||||||
|
output.Execute(err.String(), w)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// run executes the specified command and returns its output and an error.
|
||||||
|
func run(cmd ...string) ([]byte, os.Error) {
|
||||||
|
// find the specified binary
|
||||||
|
bin, err := exec.LookPath(cmd[0])
|
||||||
|
if err != nil {
|
||||||
|
// report binary as well as the error
|
||||||
|
return nil, os.NewError(cmd[0] + ": " + err.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
// run the binary and read its combined stdout and stderr into a buffer
|
||||||
|
p, err := exec.Run(bin, cmd, os.Environ(), "", exec.DevNull, exec.Pipe, exec.MergeWithStdout)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var buf bytes.Buffer
|
||||||
|
io.Copy(&buf, p.Stdout)
|
||||||
|
w, err := p.Wait(0)
|
||||||
|
p.Close()
|
||||||
|
|
||||||
|
// set the error return value if the program had a non-zero exit status
|
||||||
|
if !w.Exited() || w.ExitStatus() != 0 {
|
||||||
|
err = os.ErrorString("running " + cmd[0] + ": " + w.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf.Bytes(), err
|
||||||
|
}
|
||||||
|
|
||||||
|
var frontPage, output *template.Template // HTML templates
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
frontPage = template.New(nil)
|
||||||
|
frontPage.SetDelims("«", "»")
|
||||||
|
if err := frontPage.Parse(frontPageText); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
output = template.MustParse(outputText, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
var outputText = `<pre>{@|html}</pre>`
|
||||||
|
|
||||||
|
var frontPageText = `<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<style>
|
||||||
|
pre, textarea {
|
||||||
|
font-family: Monaco, 'Courier New', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace;
|
||||||
|
font-size: 100%;
|
||||||
|
}
|
||||||
|
.hints {
|
||||||
|
font-size: 0.8em;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
#edit, #output, #errors { width: 100%; text-align: left; }
|
||||||
|
#edit { height: 500px; }
|
||||||
|
#output { color: #00c; }
|
||||||
|
#errors { color: #c00; }
|
||||||
|
</style>
|
||||||
|
<script>
|
||||||
|
|
||||||
|
function insertTabs(n) {
|
||||||
|
// find the selection start and end
|
||||||
|
var cont = document.getElementById("edit");
|
||||||
|
var start = cont.selectionStart;
|
||||||
|
var end = cont.selectionEnd;
|
||||||
|
// split the textarea content into two, and insert n tabs
|
||||||
|
var v = cont.value;
|
||||||
|
var u = v.substr(0, start);
|
||||||
|
for (var i=0; i<n; i++) {
|
||||||
|
u += "\t";
|
||||||
|
}
|
||||||
|
u += v.substr(end);
|
||||||
|
// set revised content
|
||||||
|
cont.value = u;
|
||||||
|
// reset caret position after inserted tabs
|
||||||
|
cont.selectionStart = start+n;
|
||||||
|
cont.selectionEnd = start+n;
|
||||||
|
}
|
||||||
|
|
||||||
|
function autoindent(el) {
|
||||||
|
var curpos = el.selectionStart;
|
||||||
|
var tabs = 0;
|
||||||
|
while (curpos > 0) {
|
||||||
|
curpos--;
|
||||||
|
if (el.value[curpos] == "\t") {
|
||||||
|
tabs++;
|
||||||
|
} else if (tabs > 0 || el.value[curpos] == "\n") {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setTimeout(function() {
|
||||||
|
insertTabs(tabs);
|
||||||
|
}, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function keyHandler() {
|
||||||
|
var e = window.event;
|
||||||
|
if (e.keyCode == 9) { // tab
|
||||||
|
insertTabs(1);
|
||||||
|
e.preventDefault();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (e.keyCode == 13) { // enter
|
||||||
|
if (e.shiftKey) { // +shift
|
||||||
|
compile(e.target);
|
||||||
|
e.preventDefault();
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
autoindent(e.target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
var xmlreq;
|
||||||
|
|
||||||
|
function autocompile() {
|
||||||
|
if(!document.getElementById("autocompile").checked) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
compile();
|
||||||
|
}
|
||||||
|
|
||||||
|
function compile() {
|
||||||
|
var prog = document.getElementById("edit").value;
|
||||||
|
var req = new XMLHttpRequest();
|
||||||
|
xmlreq = req;
|
||||||
|
req.onreadystatechange = compileUpdate;
|
||||||
|
req.open("POST", "/compile", true);
|
||||||
|
req.setRequestHeader("Content-Type", "text/plain; charset=utf-8");
|
||||||
|
req.send(prog);
|
||||||
|
}
|
||||||
|
|
||||||
|
function compileUpdate() {
|
||||||
|
var req = xmlreq;
|
||||||
|
if(!req || req.readyState != 4) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(req.status == 200) {
|
||||||
|
document.getElementById("output").innerHTML = req.responseText;
|
||||||
|
document.getElementById("errors").innerHTML = "";
|
||||||
|
} else {
|
||||||
|
document.getElementById("errors").innerHTML = req.responseText;
|
||||||
|
document.getElementById("output").innerHTML = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<table width="100%"><tr><td width="60%" valign="top">
|
||||||
|
<textarea autofocus="true" id="edit" spellcheck="false" onkeydown="keyHandler();" onkeyup="autocompile();">«@|html»</textarea>
|
||||||
|
<div class="hints">
|
||||||
|
(Shift-Enter to compile and run.)
|
||||||
|
<input type="checkbox" id="autocompile" value="checked" /> Compile and run after each keystroke
|
||||||
|
</div>
|
||||||
|
<td width="3%">
|
||||||
|
<td width="27%" align="right" valign="top">
|
||||||
|
<div id="output"></div>
|
||||||
|
</table>
|
||||||
|
<div id="errors"></div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
`
|
||||||
|
|
||||||
|
var helloWorld = []byte(`package main
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
fmt.Println("hello, world")
|
||||||
|
}
|
||||||
|
`)
|
Loading…
Reference in New Issue
Block a user