Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(110)

Side by Side Diff: experimental/webtry/webtry.go

Issue 660573003: Properly parse compiler errors for fiddles and mark them in the editor. (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « experimental/webtry/templates/content.html ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 package main 1 package main
2 2
3 import ( 3 import (
4 "bytes" 4 "bytes"
5 "crypto/md5" 5 "crypto/md5"
6 "database/sql" 6 "database/sql"
7 "encoding/base64" 7 "encoding/base64"
8 "encoding/binary" 8 "encoding/binary"
9 "encoding/json" 9 "encoding/json"
10 "flag" 10 "flag"
11 "fmt" 11 "fmt"
12 htemplate "html/template" 12 htemplate "html/template"
13 "image" 13 "image"
14 _ "image/gif" 14 _ "image/gif"
15 _ "image/jpeg" 15 _ "image/jpeg"
16 "image/png" 16 "image/png"
17 "io/ioutil" 17 "io/ioutil"
18 "log" 18 "log"
19 "math/rand" 19 "math/rand"
20 "net" 20 "net"
21 "net/http" 21 "net/http"
22 "os" 22 "os"
23 "os/exec" 23 "os/exec"
24 "path/filepath" 24 "path/filepath"
25 "regexp" 25 "regexp"
26 "strconv"
26 "strings" 27 "strings"
27 "text/template" 28 "text/template"
28 "time" 29 "time"
29 ) 30 )
30 31
31 import ( 32 import (
32 "github.com/fiorix/go-web/autogzip" 33 "github.com/fiorix/go-web/autogzip"
33 _ "github.com/go-sql-driver/mysql" 34 _ "github.com/go-sql-driver/mysql"
34 _ "github.com/mattn/go-sqlite3" 35 _ "github.com/mattn/go-sqlite3"
35 "github.com/rcrowley/go-metrics" 36 "github.com/rcrowley/go-metrics"
(...skipping 361 matching lines...) Expand 10 before | Expand all | Expand 10 after
397 return hash, err 398 return hash, err
398 } 399 }
399 400
400 // expandGyp produces the GYP file needed to build the code 401 // expandGyp produces the GYP file needed to build the code
401 func expandGyp(hash string) error { 402 func expandGyp(hash string) error {
402 return writeTemplate(fmt.Sprintf("../../../cache/%s.gyp", hash), gypTemp late, struct{ Hash string }{hash}) 403 return writeTemplate(fmt.Sprintf("../../../cache/%s.gyp", hash), gypTemp late, struct{ Hash string }{hash})
403 } 404 }
404 405
405 // response is serialized to JSON as a response to POSTs. 406 // response is serialized to JSON as a response to POSTs.
406 type response struct { 407 type response struct {
407 » Message string `json:"message"` 408 » Message string `json:"message"`
408 » StdOut string `json:"stdout"` 409 » CompileErrors []compileError `json:"compileErrors"`
409 » Img string `json:"img"` 410 » Img string `json:"img"`
410 » Hash string `json:"hash"` 411 » Hash string `json:"hash"`
411 } 412 }
412 413
413 // doCmd executes the given command line string; the command being 414 // doCmd executes the given command line string; the command being
414 // run is expected to not care what its current working directory is. 415 // run is expected to not care what its current working directory is.
415 // Returns the stdout and stderr. 416 // Returns the stdout and stderr.
416 func doCmd(commandLine string) (string, error) { 417 func doCmd(commandLine string) (string, error) {
417 log.Printf("Command: %q\n", commandLine) 418 log.Printf("Command: %q\n", commandLine)
418 programAndArgs := strings.SplitN(commandLine, " ", 2) 419 programAndArgs := strings.SplitN(commandLine, " ", 2)
419 program := programAndArgs[0] 420 program := programAndArgs[0]
420 args := []string{} 421 args := []string{}
(...skipping 18 matching lines...) Expand all
439 } 440 }
440 441
441 // reportTryError formats an HTTP error response in JSON and also logs the detai led error message. 442 // reportTryError formats an HTTP error response in JSON and also logs the detai led error message.
442 func reportTryError(w http.ResponseWriter, r *http.Request, err error, message, hash string) { 443 func reportTryError(w http.ResponseWriter, r *http.Request, err error, message, hash string) {
443 m := response{ 444 m := response{
444 Message: message, 445 Message: message,
445 Hash: hash, 446 Hash: hash,
446 } 447 }
447 log.Printf("Error: %s\n%s", message, err.Error()) 448 log.Printf("Error: %s\n%s", message, err.Error())
448 resp, err := json.Marshal(m) 449 resp, err := json.Marshal(m)
450
449 if err != nil { 451 if err != nil {
450 http.Error(w, "Failed to serialize a response", 500) 452 http.Error(w, "Failed to serialize a response", 500)
451 return 453 return
454 }
455 w.Header().Set("Content-Type", "text/plain")
456 w.Write(resp)
457 }
458
459 func reportCompileError(w http.ResponseWriter, r *http.Request, compileErrors [] compileError, hash string) {
460 m := response{
461 CompileErrors: compileErrors,
462 Hash: hash,
463 }
464
465 resp, err := json.Marshal(m)
466
467 if err != nil {
468 http.Error(w, "Failed to serialize a response", 500)
469 return
452 } 470 }
453 w.Header().Set("Content-Type", "text/plain") 471 w.Header().Set("Content-Type", "text/plain")
454 w.Write(resp) 472 w.Write(resp)
455 } 473 }
456 474
457 func writeToDatabase(hash string, code string, workspaceName string, source int, width, height int, gpu bool) { 475 func writeToDatabase(hash string, code string, workspaceName string, source int, width, height int, gpu bool) {
458 if db == nil { 476 if db == nil {
459 return 477 return
460 } 478 }
461 if _, err := db.Exec("INSERT INTO webtry (code, hash, width, height, gpu , source_image_id) VALUES(?, ?, ?, ?, ?, ?)", code, hash, width, height, gpu, so urce); err != nil { 479 if _, err := db.Exec("INSERT INTO webtry (code, hash, width, height, gpu , source_image_id) VALUES(?, ?, ?, ?, ?, ?)", code, hash, width, height, gpu, so urce); err != nil {
(...skipping 323 matching lines...) Expand 10 before | Expand all | Expand 10 after
785 w.Header().Set("Content-Type", "application/json") 803 w.Header().Set("Content-Type", "application/json")
786 w.Write(resp) 804 w.Write(resp)
787 } 805 }
788 806
789 func cleanCompileOutput(s, hash string) string { 807 func cleanCompileOutput(s, hash string) string {
790 old := "../../../cache/src/" + hash + ".cpp:" 808 old := "../../../cache/src/" + hash + ".cpp:"
791 log.Printf("INFO: replacing %q\n", old) 809 log.Printf("INFO: replacing %q\n", old)
792 return strings.Replace(s, old, "usercode.cpp:", -1) 810 return strings.Replace(s, old, "usercode.cpp:", -1)
793 } 811 }
794 812
813 type compileError struct {
814 Line int `json:"line"`
815 Column int `json:"column"`
816 Error string `json:"error"`
817 }
818
795 // mainHandler handles the GET and POST of the main page. 819 // mainHandler handles the GET and POST of the main page.
796 func mainHandler(w http.ResponseWriter, r *http.Request) { 820 func mainHandler(w http.ResponseWriter, r *http.Request) {
797 log.Printf("Main Handler: %q\n", r.URL.Path) 821 log.Printf("Main Handler: %q\n", r.URL.Path)
798 requestsCounter.Inc(1) 822 requestsCounter.Inc(1)
799 if r.Method == "GET" { 823 if r.Method == "GET" {
800 code := DEFAULT_SAMPLE 824 code := DEFAULT_SAMPLE
801 source := 0 825 source := 0
802 width := 256 826 width := 256
803 height := 256 827 height := 256
804 gpu := false 828 gpu := false
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
860 cmd += " --gpu" 884 cmd += " --gpu"
861 } 885 }
862 if *useChroot { 886 if *useChroot {
863 cmd = "schroot -c webtry --directory=/ -- /skia_build/sk ia/experimental/webtry/" + cmd 887 cmd = "schroot -c webtry --directory=/ -- /skia_build/sk ia/experimental/webtry/" + cmd
864 } 888 }
865 if request.Source > 0 { 889 if request.Source > 0 {
866 cmd += fmt.Sprintf(" --source image-%d.png", request.Sou rce) 890 cmd += fmt.Sprintf(" --source image-%d.png", request.Sou rce)
867 } 891 }
868 892
869 message, err := doCmd(cmd) 893 message, err := doCmd(cmd)
894
895 outputLines := strings.Split(message, "\n")
896 errorLines := []compileError{}
897 errorRE := regexp.MustCompile(fmt.Sprintf("^.*%s.cpp:(\\d+):(\\d +):\\s*(.*)", hash))
jcgregorio 2014/10/15 19:59:50 Move to top of file so it's only compiled once.
humper 2014/10/15 21:03:59 Done.
898 for _, line := range outputLines {
899 match := errorRE.FindStringSubmatch(line)
900 if len(match) > 0 {
901 lineNumber, parseError := strconv.Atoi(match[1])
902 if parseError != nil {
903 log.Printf("ERROR: Couldn't parse line n umber from %s\n", match[1])
jcgregorio 2014/10/15 19:59:50 Add a TODO to switch from log to glog (http://godo
tfarina 2014/10/15 20:05:21 I will do that. I have a bug filed for that: https
904 continue
905 }
906 columnNumber, parseError := strconv.Atoi(match[2 ])
907 if parseError != nil {
908 log.Printf("ERROR: Couldn't parse column number from %s\n", match[2])
909 continue
910 }
911 errorLines = append(errorLines,
912 compileError{
913 Line: lineNumber,
914 Column: columnNumber,
915 Error: match[3],
916 })
917 }
918 }
919
870 if err != nil { 920 if err != nil {
871 » » » reportTryError(w, r, err, "Failed to run the code:\n"+me ssage, hash) 921 » » » if len(errorLines) > 0 {
922 » » » » reportCompileError(w, r, errorLines, hash)
923 » » » } else {
924 » » » » reportTryError(w, r, err, "Failed to run the cod e:\n"+message, hash)
925 » » » }
872 return 926 return
873 } 927 }
928
874 png, err := ioutil.ReadFile("../../../inout/" + hash + ".png") 929 png, err := ioutil.ReadFile("../../../inout/" + hash + ".png")
875 if err != nil { 930 if err != nil {
876 reportTryError(w, r, err, "Failed to open the generated PNG.", hash) 931 reportTryError(w, r, err, "Failed to open the generated PNG.", hash)
877 return 932 return
878 } 933 }
879 934
880 m := response{ 935 m := response{
881 Message: message, 936 Message: message,
882 Img: base64.StdEncoding.EncodeToString([]byte(png)), 937 Img: base64.StdEncoding.EncodeToString([]byte(png)),
883 Hash: hash, 938 Hash: hash,
(...skipping 18 matching lines...) Expand all
902 http.HandleFunc("/sources/", autogzip.HandleFunc(sourcesHandler)) 957 http.HandleFunc("/sources/", autogzip.HandleFunc(sourcesHandler))
903 958
904 // Resources are served directly 959 // Resources are served directly
905 // TODO add support for caching/etags/gzip 960 // TODO add support for caching/etags/gzip
906 http.Handle("/res/", autogzip.Handle(http.FileServer(http.Dir("./")))) 961 http.Handle("/res/", autogzip.Handle(http.FileServer(http.Dir("./"))))
907 962
908 // TODO Break out /c/ as it's own handler. 963 // TODO Break out /c/ as it's own handler.
909 http.HandleFunc("/", autogzip.HandleFunc(mainHandler)) 964 http.HandleFunc("/", autogzip.HandleFunc(mainHandler))
910 log.Fatal(http.ListenAndServe(*port, nil)) 965 log.Fatal(http.ListenAndServe(*port, nil))
911 } 966 }
OLDNEW
« no previous file with comments | « experimental/webtry/templates/content.html ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698