mirror of https://github.com/golang/go.git
misc/goplay: remain in work directory, build in temp directory
Fixes #2935. R=golang-dev, r CC=golang-dev https://golang.org/cl/5684048
This commit is contained in:
parent
8729d158ca
commit
041edbcc79
|
|
@ -5,13 +5,16 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"flag"
|
"flag"
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
"regexp"
|
||||||
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
"text/template"
|
"text/template"
|
||||||
)
|
)
|
||||||
|
|
@ -63,26 +66,7 @@ func FrontPage(w http.ResponseWriter, req *http.Request) {
|
||||||
// runs the program (returning any errors),
|
// runs the program (returning any errors),
|
||||||
// and sends the program's output as the HTTP response.
|
// and sends the program's output as the HTTP response.
|
||||||
func Compile(w http.ResponseWriter, req *http.Request) {
|
func Compile(w http.ResponseWriter, req *http.Request) {
|
||||||
// x is the base name for .go files
|
out, err := compile(req)
|
||||||
x := "goplay" + strconv.Itoa(<-uniq) + ".go"
|
|
||||||
|
|
||||||
// write request Body to x.go
|
|
||||||
f, err := os.Create(x)
|
|
||||||
if err != nil {
|
|
||||||
error_(w, nil, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer os.Remove(x)
|
|
||||||
defer f.Close()
|
|
||||||
_, err = io.Copy(f, req.Body)
|
|
||||||
if err != nil {
|
|
||||||
error_(w, nil, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
f.Close()
|
|
||||||
|
|
||||||
// run x
|
|
||||||
out, err := run("go", "run", x)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
error_(w, out, err)
|
error_(w, out, err)
|
||||||
return
|
return
|
||||||
|
|
@ -96,6 +80,60 @@ func Compile(w http.ResponseWriter, req *http.Request) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
commentRe = regexp.MustCompile(`(?m)^#.*\n`)
|
||||||
|
tmpdir string
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// find real temporary directory (for rewriting filename in output)
|
||||||
|
var err error
|
||||||
|
tmpdir, err = filepath.EvalSymlinks(os.TempDir())
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func compile(req *http.Request) (out []byte, err error) {
|
||||||
|
// x is the base name for .go, .6, executable files
|
||||||
|
x := filepath.Join(tmpdir, "compile"+strconv.Itoa(<-uniq))
|
||||||
|
src := x + ".go"
|
||||||
|
bin := x
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
bin += ".exe"
|
||||||
|
}
|
||||||
|
|
||||||
|
// rewrite filename in error output
|
||||||
|
defer func() {
|
||||||
|
if err != nil {
|
||||||
|
// drop messages from the go tool like '# _/compile0'
|
||||||
|
out = commentRe.ReplaceAll(out, nil)
|
||||||
|
}
|
||||||
|
out = bytes.Replace(out, []byte(src+":"), []byte("main.go:"), -1)
|
||||||
|
}()
|
||||||
|
|
||||||
|
// write body to x.go
|
||||||
|
body := new(bytes.Buffer)
|
||||||
|
if _, err = body.ReadFrom(req.Body); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer os.Remove(src)
|
||||||
|
if err = ioutil.WriteFile(src, body.Bytes(), 0666); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// build x.go, creating x
|
||||||
|
dir, file := filepath.Split(src)
|
||||||
|
out, err = run(dir, "go", "build", "-o", bin, file)
|
||||||
|
defer os.Remove(bin)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// run x
|
||||||
|
return run("", bin)
|
||||||
|
}
|
||||||
|
|
||||||
// error writes compile, link, or runtime errors to the HTTP connection.
|
// error writes compile, link, or runtime errors to the HTTP connection.
|
||||||
// The JavaScript interface uses the 404 status code to identify the error.
|
// The JavaScript interface uses the 404 status code to identify the error.
|
||||||
func error_(w http.ResponseWriter, out []byte, err error) {
|
func error_(w http.ResponseWriter, out []byte, err error) {
|
||||||
|
|
@ -108,8 +146,14 @@ func error_(w http.ResponseWriter, out []byte, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// run executes the specified command and returns its output and an error.
|
// run executes the specified command and returns its output and an error.
|
||||||
func run(cmd ...string) ([]byte, error) {
|
func run(dir string, args ...string) ([]byte, error) {
|
||||||
return exec.Command(cmd[0], cmd[1:]...).CombinedOutput()
|
var buf bytes.Buffer
|
||||||
|
cmd := exec.Command(args[0], args[1:]...)
|
||||||
|
cmd.Dir = dir
|
||||||
|
cmd.Stdout = &buf
|
||||||
|
cmd.Stderr = cmd.Stdout
|
||||||
|
err := cmd.Run()
|
||||||
|
return buf.Bytes(), err
|
||||||
}
|
}
|
||||||
|
|
||||||
var frontPage = template.Must(template.New("frontPage").Parse(frontPageText)) // HTML template
|
var frontPage = template.Must(template.New("frontPage").Parse(frontPageText)) // HTML template
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue