| Index: experimental/webtry/webtry.go
|
| diff --git a/experimental/webtry/webtry.go b/experimental/webtry/webtry.go
|
| index ea59bc1c422b7d7d57821d4d663229644f356831..34aa47e2827a3e80342f5a6c715df7162944c786 100644
|
| --- a/experimental/webtry/webtry.go
|
| +++ b/experimental/webtry/webtry.go
|
| @@ -22,6 +22,7 @@ import (
|
| "os/exec"
|
| "path/filepath"
|
| "regexp"
|
| + "strconv"
|
| "strings"
|
| "text/template"
|
| "time"
|
| @@ -86,6 +87,9 @@ var (
|
| // workspaceLink is the regex that matches URLs paths for workspaces.
|
| workspaceLink = regexp.MustCompile("^/w/([a-z0-9-]+)$")
|
|
|
| + // errorRE is ther regex that matches compiler errors and extracts the line / column information.
|
| + errorRE = regexp.MustCompile("^.*.cpp:(\\d+):(\\d+):\\s*(.*)")
|
| +
|
| // workspaceNameAdj is a list of adjectives for building workspace names.
|
| workspaceNameAdj = []string{
|
| "autumn", "hidden", "bitter", "misty", "silent", "empty", "dry", "dark",
|
| @@ -405,10 +409,10 @@ func expandGyp(hash string) error {
|
|
|
| // response is serialized to JSON as a response to POSTs.
|
| type response struct {
|
| - Message string `json:"message"`
|
| - StdOut string `json:"stdout"`
|
| - Img string `json:"img"`
|
| - Hash string `json:"hash"`
|
| + Message string `json:"message"`
|
| + CompileErrors []compileError `json:"compileErrors"`
|
| + Img string `json:"img"`
|
| + Hash string `json:"hash"`
|
| }
|
|
|
| // doCmd executes the given command line string; the command being
|
| @@ -447,6 +451,23 @@ func reportTryError(w http.ResponseWriter, r *http.Request, err error, message,
|
| }
|
| glog.Errorf("%s\n%s", message, err)
|
| resp, err := json.Marshal(m)
|
| +
|
| + if err != nil {
|
| + http.Error(w, "Failed to serialize a response", 500)
|
| + return
|
| + }
|
| + w.Header().Set("Content-Type", "text/plain")
|
| + w.Write(resp)
|
| +}
|
| +
|
| +func reportCompileError(w http.ResponseWriter, r *http.Request, compileErrors []compileError, hash string) {
|
| + m := response{
|
| + CompileErrors: compileErrors,
|
| + Hash: hash,
|
| + }
|
| +
|
| + resp, err := json.Marshal(m)
|
| +
|
| if err != nil {
|
| http.Error(w, "Failed to serialize a response", 500)
|
| return
|
| @@ -794,6 +815,12 @@ func cleanCompileOutput(s, hash string) string {
|
| return strings.Replace(s, old, "usercode.cpp:", -1)
|
| }
|
|
|
| +type compileError struct {
|
| + Line int `json:"line"`
|
| + Column int `json:"column"`
|
| + Error string `json:"error"`
|
| +}
|
| +
|
| // mainHandler handles the GET and POST of the main page.
|
| func mainHandler(w http.ResponseWriter, r *http.Request) {
|
| glog.Infof("Main Handler: %q\n", r.URL.Path)
|
| @@ -869,10 +896,40 @@ func mainHandler(w http.ResponseWriter, r *http.Request) {
|
| }
|
|
|
| message, err := doCmd(cmd)
|
| +
|
| + outputLines := strings.Split(message, "\n")
|
| + errorLines := []compileError{}
|
| + for _, line := range outputLines {
|
| + match := errorRE.FindStringSubmatch(line)
|
| + if len(match) > 0 {
|
| + lineNumber, parseError := strconv.Atoi(match[1])
|
| + if parseError != nil {
|
| + glog.Errorf("ERROR: Couldn't parse line number from %s\n", match[1])
|
| + continue
|
| + }
|
| + columnNumber, parseError := strconv.Atoi(match[2])
|
| + if parseError != nil {
|
| + glog.Errorf("ERROR: Couldn't parse column number from %s\n", match[2])
|
| + continue
|
| + }
|
| + errorLines = append(errorLines,
|
| + compileError{
|
| + Line: lineNumber,
|
| + Column: columnNumber,
|
| + Error: match[3],
|
| + })
|
| + }
|
| + }
|
| +
|
| if err != nil {
|
| - reportTryError(w, r, err, "Failed to run the code:\n"+message, hash)
|
| + if len(errorLines) > 0 {
|
| + reportCompileError(w, r, errorLines, hash)
|
| + } else {
|
| + reportTryError(w, r, err, "Failed to run the code:\n"+message, hash)
|
| + }
|
| return
|
| }
|
| +
|
| png, err := ioutil.ReadFile("../../../inout/" + hash + ".png")
|
| if err != nil {
|
| reportTryError(w, r, err, "Failed to open the generated PNG.", hash)
|
|
|