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

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: log --> glog 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 "math/rand" 18 "math/rand"
19 "net" 19 "net"
20 "net/http" 20 "net/http"
21 "os" 21 "os"
22 "os/exec" 22 "os/exec"
23 "path/filepath" 23 "path/filepath"
24 "regexp" 24 "regexp"
25 "strconv"
25 "strings" 26 "strings"
26 "text/template" 27 "text/template"
27 "time" 28 "time"
28 ) 29 )
29 30
30 import ( 31 import (
31 "github.com/fiorix/go-web/autogzip" 32 "github.com/fiorix/go-web/autogzip"
32 _ "github.com/go-sql-driver/mysql" 33 _ "github.com/go-sql-driver/mysql"
33 "github.com/golang/glog" 34 "github.com/golang/glog"
34 _ "github.com/mattn/go-sqlite3" 35 _ "github.com/mattn/go-sqlite3"
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
79 80
80 // imageLink is the regex that matches URLs paths that are direct links to PNGs. 81 // imageLink is the regex that matches URLs paths that are direct links to PNGs.
81 imageLink = regexp.MustCompile("^/i/([a-z0-9-]+.png)$") 82 imageLink = regexp.MustCompile("^/i/([a-z0-9-]+.png)$")
82 83
83 // tryInfoLink is the regex that matches URLs paths that are direct link s to data about a single try. 84 // tryInfoLink is the regex that matches URLs paths that are direct link s to data about a single try.
84 tryInfoLink = regexp.MustCompile("^/json/([a-f0-9]+)$") 85 tryInfoLink = regexp.MustCompile("^/json/([a-f0-9]+)$")
85 86
86 // workspaceLink is the regex that matches URLs paths for workspaces. 87 // workspaceLink is the regex that matches URLs paths for workspaces.
87 workspaceLink = regexp.MustCompile("^/w/([a-z0-9-]+)$") 88 workspaceLink = regexp.MustCompile("^/w/([a-z0-9-]+)$")
88 89
90 // errorRE is ther regex that matches compiler errors and extracts the l ine / column information.
91 errorRE = regexp.MustCompile("^.*.cpp:(\\d+):(\\d+):\\s*(.*)")
92
89 // workspaceNameAdj is a list of adjectives for building workspace names . 93 // workspaceNameAdj is a list of adjectives for building workspace names .
90 workspaceNameAdj = []string{ 94 workspaceNameAdj = []string{
91 "autumn", "hidden", "bitter", "misty", "silent", "empty", "dry", "dark", 95 "autumn", "hidden", "bitter", "misty", "silent", "empty", "dry", "dark",
92 "summer", "icy", "delicate", "quiet", "white", "cool", "spring", "winter", 96 "summer", "icy", "delicate", "quiet", "white", "cool", "spring", "winter",
93 "patient", "twilight", "dawn", "crimson", "wispy", "weathered", "blue", 97 "patient", "twilight", "dawn", "crimson", "wispy", "weathered", "blue",
94 "billowing", "broken", "cold", "damp", "falling", "frosty", "gre en", 98 "billowing", "broken", "cold", "damp", "falling", "frosty", "gre en",
95 "long", "late", "lingering", "bold", "little", "morning", "muddy ", "old", 99 "long", "late", "lingering", "bold", "little", "morning", "muddy ", "old",
96 "red", "rough", "still", "small", "sparkling", "throbbing", "shy ", 100 "red", "rough", "still", "small", "sparkling", "throbbing", "shy ",
97 "wandering", "withered", "wild", "black", "young", "holy", "soli tary", 101 "wandering", "withered", "wild", "black", "young", "holy", "soli tary",
98 "fragrant", "aged", "snowy", "proud", "floral", "restless", "div ine", 102 "fragrant", "aged", "snowy", "proud", "floral", "restless", "div ine",
(...skipping 299 matching lines...) Expand 10 before | Expand all | Expand 10 after
398 return hash, err 402 return hash, err
399 } 403 }
400 404
401 // expandGyp produces the GYP file needed to build the code 405 // expandGyp produces the GYP file needed to build the code
402 func expandGyp(hash string) error { 406 func expandGyp(hash string) error {
403 return writeTemplate(fmt.Sprintf("../../../cache/%s.gyp", hash), gypTemp late, struct{ Hash string }{hash}) 407 return writeTemplate(fmt.Sprintf("../../../cache/%s.gyp", hash), gypTemp late, struct{ Hash string }{hash})
404 } 408 }
405 409
406 // response is serialized to JSON as a response to POSTs. 410 // response is serialized to JSON as a response to POSTs.
407 type response struct { 411 type response struct {
408 » Message string `json:"message"` 412 » Message string `json:"message"`
409 » StdOut string `json:"stdout"` 413 » CompileErrors []compileError `json:"compileErrors"`
410 » Img string `json:"img"` 414 » Img string `json:"img"`
411 » Hash string `json:"hash"` 415 » Hash string `json:"hash"`
412 } 416 }
413 417
414 // doCmd executes the given command line string; the command being 418 // doCmd executes the given command line string; the command being
415 // run is expected to not care what its current working directory is. 419 // run is expected to not care what its current working directory is.
416 // Returns the stdout and stderr. 420 // Returns the stdout and stderr.
417 func doCmd(commandLine string) (string, error) { 421 func doCmd(commandLine string) (string, error) {
418 glog.Infof("Command: %q\n", commandLine) 422 glog.Infof("Command: %q\n", commandLine)
419 programAndArgs := strings.SplitN(commandLine, " ", 2) 423 programAndArgs := strings.SplitN(commandLine, " ", 2)
420 program := programAndArgs[0] 424 program := programAndArgs[0]
421 args := []string{} 425 args := []string{}
(...skipping 18 matching lines...) Expand all
440 } 444 }
441 445
442 // reportTryError formats an HTTP error response in JSON and also logs the detai led error message. 446 // reportTryError formats an HTTP error response in JSON and also logs the detai led error message.
443 func reportTryError(w http.ResponseWriter, r *http.Request, err error, message, hash string) { 447 func reportTryError(w http.ResponseWriter, r *http.Request, err error, message, hash string) {
444 m := response{ 448 m := response{
445 Message: message, 449 Message: message,
446 Hash: hash, 450 Hash: hash,
447 } 451 }
448 glog.Errorf("%s\n%s", message, err) 452 glog.Errorf("%s\n%s", message, err)
449 resp, err := json.Marshal(m) 453 resp, err := json.Marshal(m)
454
450 if err != nil { 455 if err != nil {
451 http.Error(w, "Failed to serialize a response", 500) 456 http.Error(w, "Failed to serialize a response", 500)
452 return 457 return
458 }
459 w.Header().Set("Content-Type", "text/plain")
460 w.Write(resp)
461 }
462
463 func reportCompileError(w http.ResponseWriter, r *http.Request, compileErrors [] compileError, hash string) {
464 m := response{
465 CompileErrors: compileErrors,
466 Hash: hash,
467 }
468
469 resp, err := json.Marshal(m)
470
471 if err != nil {
472 http.Error(w, "Failed to serialize a response", 500)
473 return
453 } 474 }
454 w.Header().Set("Content-Type", "text/plain") 475 w.Header().Set("Content-Type", "text/plain")
455 w.Write(resp) 476 w.Write(resp)
456 } 477 }
457 478
458 func writeToDatabase(hash string, code string, workspaceName string, source int, width, height int, gpu bool) { 479 func writeToDatabase(hash string, code string, workspaceName string, source int, width, height int, gpu bool) {
459 if db == nil { 480 if db == nil {
460 return 481 return
461 } 482 }
462 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 { 483 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 324 matching lines...) Expand 10 before | Expand all | Expand 10 after
787 w.Header().Set("Content-Type", "application/json") 808 w.Header().Set("Content-Type", "application/json")
788 w.Write(resp) 809 w.Write(resp)
789 } 810 }
790 811
791 func cleanCompileOutput(s, hash string) string { 812 func cleanCompileOutput(s, hash string) string {
792 old := "../../../cache/src/" + hash + ".cpp:" 813 old := "../../../cache/src/" + hash + ".cpp:"
793 glog.Infof("replacing %q\n", old) 814 glog.Infof("replacing %q\n", old)
794 return strings.Replace(s, old, "usercode.cpp:", -1) 815 return strings.Replace(s, old, "usercode.cpp:", -1)
795 } 816 }
796 817
818 type compileError struct {
819 Line int `json:"line"`
820 Column int `json:"column"`
821 Error string `json:"error"`
822 }
823
797 // mainHandler handles the GET and POST of the main page. 824 // mainHandler handles the GET and POST of the main page.
798 func mainHandler(w http.ResponseWriter, r *http.Request) { 825 func mainHandler(w http.ResponseWriter, r *http.Request) {
799 glog.Infof("Main Handler: %q\n", r.URL.Path) 826 glog.Infof("Main Handler: %q\n", r.URL.Path)
800 requestsCounter.Inc(1) 827 requestsCounter.Inc(1)
801 if r.Method == "GET" { 828 if r.Method == "GET" {
802 code := DEFAULT_SAMPLE 829 code := DEFAULT_SAMPLE
803 source := 0 830 source := 0
804 width := 256 831 width := 256
805 height := 256 832 height := 256
806 gpu := false 833 gpu := false
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
862 cmd += " --gpu" 889 cmd += " --gpu"
863 } 890 }
864 if *useChroot { 891 if *useChroot {
865 cmd = "schroot -c webtry --directory=/ -- /skia_build/sk ia/experimental/webtry/" + cmd 892 cmd = "schroot -c webtry --directory=/ -- /skia_build/sk ia/experimental/webtry/" + cmd
866 } 893 }
867 if request.Source > 0 { 894 if request.Source > 0 {
868 cmd += fmt.Sprintf(" --source image-%d.png", request.Sou rce) 895 cmd += fmt.Sprintf(" --source image-%d.png", request.Sou rce)
869 } 896 }
870 897
871 message, err := doCmd(cmd) 898 message, err := doCmd(cmd)
899
900 outputLines := strings.Split(message, "\n")
901 errorLines := []compileError{}
902 for _, line := range outputLines {
903 match := errorRE.FindStringSubmatch(line)
904 if len(match) > 0 {
905 lineNumber, parseError := strconv.Atoi(match[1])
906 if parseError != nil {
907 glog.Errorf("ERROR: Couldn't parse line number from %s\n", match[1])
908 continue
909 }
910 columnNumber, parseError := strconv.Atoi(match[2 ])
911 if parseError != nil {
912 glog.Errorf("ERROR: Couldn't parse colum n number from %s\n", match[2])
913 continue
914 }
915 errorLines = append(errorLines,
916 compileError{
917 Line: lineNumber,
918 Column: columnNumber,
919 Error: match[3],
920 })
921 }
922 }
923
872 if err != nil { 924 if err != nil {
873 » » » reportTryError(w, r, err, "Failed to run the code:\n"+me ssage, hash) 925 » » » if len(errorLines) > 0 {
926 » » » » reportCompileError(w, r, errorLines, hash)
927 » » » } else {
928 » » » » reportTryError(w, r, err, "Failed to run the cod e:\n"+message, hash)
929 » » » }
874 return 930 return
875 } 931 }
932
876 png, err := ioutil.ReadFile("../../../inout/" + hash + ".png") 933 png, err := ioutil.ReadFile("../../../inout/" + hash + ".png")
877 if err != nil { 934 if err != nil {
878 reportTryError(w, r, err, "Failed to open the generated PNG.", hash) 935 reportTryError(w, r, err, "Failed to open the generated PNG.", hash)
879 return 936 return
880 } 937 }
881 938
882 m := response{ 939 m := response{
883 Message: message, 940 Message: message,
884 Img: base64.StdEncoding.EncodeToString([]byte(png)), 941 Img: base64.StdEncoding.EncodeToString([]byte(png)),
885 Hash: hash, 942 Hash: hash,
(...skipping 18 matching lines...) Expand all
904 http.HandleFunc("/sources/", autogzip.HandleFunc(sourcesHandler)) 961 http.HandleFunc("/sources/", autogzip.HandleFunc(sourcesHandler))
905 962
906 // Resources are served directly 963 // Resources are served directly
907 // TODO add support for caching/etags/gzip 964 // TODO add support for caching/etags/gzip
908 http.Handle("/res/", autogzip.Handle(http.FileServer(http.Dir("./")))) 965 http.Handle("/res/", autogzip.Handle(http.FileServer(http.Dir("./"))))
909 966
910 // TODO Break out /c/ as it's own handler. 967 // TODO Break out /c/ as it's own handler.
911 http.HandleFunc("/", autogzip.HandleFunc(mainHandler)) 968 http.HandleFunc("/", autogzip.HandleFunc(mainHandler))
912 glog.Fatal(http.ListenAndServe(*port, nil)) 969 glog.Fatal(http.ListenAndServe(*port, nil))
913 } 970 }
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