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

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

Issue 246823004: Factor out common template code. Send stdout back to web page. (Closed) Base URL: https://skia.googlesource.com/skia.git@clickhistory
Patch Set: rebase Created 6 years, 8 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/workspace.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/json" 8 "encoding/json"
9 "flag" 9 "flag"
10 "fmt" 10 "fmt"
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after
128 } 128 }
129 os.Chdir(cwd) 129 os.Chdir(cwd)
130 130
131 codeTemplate, err = template.ParseFiles(filepath.Join(cwd, "templates/te mplate.cpp")) 131 codeTemplate, err = template.ParseFiles(filepath.Join(cwd, "templates/te mplate.cpp"))
132 if err != nil { 132 if err != nil {
133 panic(err) 133 panic(err)
134 } 134 }
135 indexTemplate, err = htemplate.ParseFiles( 135 indexTemplate, err = htemplate.ParseFiles(
136 filepath.Join(cwd, "templates/index.html"), 136 filepath.Join(cwd, "templates/index.html"),
137 filepath.Join(cwd, "templates/titlebar.html"), 137 filepath.Join(cwd, "templates/titlebar.html"),
138 filepath.Join(cwd, "templates/content.html"),
138 ) 139 )
139 if err != nil { 140 if err != nil {
140 panic(err) 141 panic(err)
141 } 142 }
142 iframeTemplate, err = htemplate.ParseFiles( 143 iframeTemplate, err = htemplate.ParseFiles(
143 filepath.Join(cwd, "templates/iframe.html"), 144 filepath.Join(cwd, "templates/iframe.html"),
145 filepath.Join(cwd, "templates/content.html"),
144 ) 146 )
145 if err != nil { 147 if err != nil {
146 panic(err) 148 panic(err)
147 } 149 }
148 recentTemplate, err = htemplate.ParseFiles( 150 recentTemplate, err = htemplate.ParseFiles(
149 filepath.Join(cwd, "templates/recent.html"), 151 filepath.Join(cwd, "templates/recent.html"),
150 filepath.Join(cwd, "templates/titlebar.html"), 152 filepath.Join(cwd, "templates/titlebar.html"),
151 ) 153 )
152 if err != nil { 154 if err != nil {
153 panic(err) 155 panic(err)
154 } 156 }
155 workspaceTemplate, err = htemplate.ParseFiles( 157 workspaceTemplate, err = htemplate.ParseFiles(
156 filepath.Join(cwd, "templates/workspace.html"), 158 filepath.Join(cwd, "templates/workspace.html"),
157 filepath.Join(cwd, "templates/titlebar.html"), 159 filepath.Join(cwd, "templates/titlebar.html"),
160 filepath.Join(cwd, "templates/content.html"),
158 ) 161 )
159 if err != nil { 162 if err != nil {
160 panic(err) 163 panic(err)
161 } 164 }
162 165
163 // Connect to MySQL server. First, get the password from the metadata se rver. 166 // Connect to MySQL server. First, get the password from the metadata se rver.
164 // See https://developers.google.com/compute/docs/metadata#custom. 167 // See https://developers.google.com/compute/docs/metadata#custom.
165 req, err := http.NewRequest("GET", "http://metadata/computeMetadata/v1/i nstance/attributes/password", nil) 168 req, err := http.NewRequest("GET", "http://metadata/computeMetadata/v1/i nstance/attributes/password", nil)
166 if err != nil { 169 if err != nil {
167 panic(err) 170 panic(err)
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
213 216
214 FOREIGN KEY (name) REFERENCES workspace(name) 217 FOREIGN KEY (name) REFERENCES workspace(name)
215 )` 218 )`
216 _, err = db.Exec(sql) 219 _, err = db.Exec(sql)
217 log.Printf("Info: status creating sqlite table for workspace try : %q\n", err) 220 log.Printf("Info: status creating sqlite table for workspace try : %q\n", err)
218 } 221 }
219 } 222 }
220 223
221 // userCode is used in template expansion. 224 // userCode is used in template expansion.
222 type userCode struct { 225 type userCode struct {
223 » UserCode string 226 » Code string
224 » Hash string 227 » Hash string
225 } 228 }
226 229
227 // expandToFile expands the template and writes the result to the file. 230 // expandToFile expands the template and writes the result to the file.
228 func expandToFile(filename string, code string, t *template.Template) error { 231 func expandToFile(filename string, code string, t *template.Template) error {
229 f, err := os.Create(filename) 232 f, err := os.Create(filename)
230 if err != nil { 233 if err != nil {
231 return err 234 return err
232 } 235 }
233 defer f.Close() 236 defer f.Close()
234 » return t.Execute(f, userCode{UserCode: code}) 237 » return t.Execute(f, userCode{Code: code})
235 } 238 }
236 239
237 // expandCode expands the template into a file and calculate the MD5 hash. 240 // expandCode expands the template into a file and calculate the MD5 hash.
238 func expandCode(code string) (string, error) { 241 func expandCode(code string) (string, error) {
239 h := md5.New() 242 h := md5.New()
240 h.Write([]byte(code)) 243 h.Write([]byte(code))
241 hash := fmt.Sprintf("%x", h.Sum(nil)) 244 hash := fmt.Sprintf("%x", h.Sum(nil))
242 // At this point we are running in skia/experimental/webtry, making cach e a 245 // At this point we are running in skia/experimental/webtry, making cach e a
243 // peer directory to skia. 246 // peer directory to skia.
244 // TODO(jcgregorio) Make all relative directories into flags. 247 // TODO(jcgregorio) Make all relative directories into flags.
245 err := expandToFile(fmt.Sprintf("../../../cache/%s.cpp", hash), code, co deTemplate) 248 err := expandToFile(fmt.Sprintf("../../../cache/%s.cpp", hash), code, co deTemplate)
246 return hash, err 249 return hash, err
247 } 250 }
248 251
249 // response is serialized to JSON as a response to POSTs. 252 // response is serialized to JSON as a response to POSTs.
250 type response struct { 253 type response struct {
251 Message string `json:"message"` 254 Message string `json:"message"`
255 StdOut string `json:"stdout"`
252 Img string `json:"img"` 256 Img string `json:"img"`
253 Hash string `json:"hash"` 257 Hash string `json:"hash"`
254 } 258 }
255 259
256 // doCmd executes the given command line string in either the out/Debug 260 // doCmd executes the given command line string in either the out/Debug
257 // directory or the inout directory. Returns the stdout, and stderr in the case 261 // directory or the inout directory. Returns the stdout, and stderr in the case
258 // of a non-zero exit code. 262 // of a non-zero exit code.
259 func doCmd(commandLine string, moveToDebug bool) (string, error) { 263 func doCmd(commandLine string, moveToDebug bool) (string, error) {
260 log.Printf("Command: %q\n", commandLine) 264 log.Printf("Command: %q\n", commandLine)
261 programAndArgs := strings.SplitN(commandLine, " ", 2) 265 programAndArgs := strings.SplitN(commandLine, " ", 2)
(...skipping 29 matching lines...) Expand all
291 log.Printf("Exit status: %s\n", err.Error()) 295 log.Printf("Exit status: %s\n", err.Error())
292 log.Printf("StdErr: %s\n", stdErr.String()) 296 log.Printf("StdErr: %s\n", stdErr.String())
293 message += stdErr.String() 297 message += stdErr.String()
294 return message, fmt.Errorf("Failed to run command.") 298 return message, fmt.Errorf("Failed to run command.")
295 } 299 }
296 return message, nil 300 return message, nil
297 } 301 }
298 302
299 // reportError formats an HTTP error response and also logs the detailed error m essage. 303 // reportError formats an HTTP error response and also logs the detailed error m essage.
300 func reportError(w http.ResponseWriter, r *http.Request, err error, message stri ng) { 304 func reportError(w http.ResponseWriter, r *http.Request, err error, message stri ng) {
305 log.Printf("Error: %s\n%s", message, err.Error())
306 http.Error(w, message, 500)
307 }
308
309 // reportTryError formats an HTTP error response in JSON and also logs the detai led error message.
310 func reportTryError(w http.ResponseWriter, r *http.Request, err error, message, hash string) {
301 m := response{ 311 m := response{
302 Message: message, 312 Message: message,
313 Hash: hash,
303 } 314 }
304 log.Printf("Error: %s\n%s", message, err.Error()) 315 log.Printf("Error: %s\n%s", message, err.Error())
305 resp, err := json.Marshal(m) 316 resp, err := json.Marshal(m)
306 if err != nil { 317 if err != nil {
307 http.Error(w, "Failed to serialize a response", 500) 318 http.Error(w, "Failed to serialize a response", 500)
308 return 319 return
309 } 320 }
310 w.Write(resp) 321 w.Write(resp)
311 } 322 }
312 323
(...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after
492 http.NotFound(w, r) 503 http.NotFound(w, r)
493 return 504 return
494 } 505 }
495 var code string 506 var code string
496 code, err := getCode(hash) 507 code, err := getCode(hash)
497 if err != nil { 508 if err != nil {
498 http.NotFound(w, r) 509 http.NotFound(w, r)
499 return 510 return
500 } 511 }
501 // Expand the template. 512 // Expand the template.
502 » if err := iframeTemplate.Execute(w, userCode{UserCode: code, Hash: hash} ); err != nil { 513 » if err := iframeTemplate.Execute(w, userCode{Code: code, Hash: hash}); e rr != nil {
503 log.Printf("ERROR: Failed to expand template: %q\n", err) 514 log.Printf("ERROR: Failed to expand template: %q\n", err)
504 } 515 }
505 } 516 }
506 517
507 type TryInfo struct { 518 type TryInfo struct {
508 Hash string `json:"hash"` 519 Hash string `json:"hash"`
509 Code string `json:"code"` 520 Code string `json:"code"`
510 } 521 }
511 522
512 // tryInfoHandler returns information about a specific try. 523 // tryInfoHandler returns information about a specific try.
(...skipping 20 matching lines...) Expand all
533 } 544 }
534 resp, err := json.Marshal(m) 545 resp, err := json.Marshal(m)
535 if err != nil { 546 if err != nil {
536 reportError(w, r, err, "Failed to serialize a response.") 547 reportError(w, r, err, "Failed to serialize a response.")
537 return 548 return
538 } 549 }
539 w.Header().Set("Content-Type", "application/json") 550 w.Header().Set("Content-Type", "application/json")
540 w.Write(resp) 551 w.Write(resp)
541 } 552 }
542 553
554 func cleanCompileOutput(s, hash string) string {
555 old := "../../../cache/" + hash + ".cpp:"
556 log.Printf("INFO: replacing %q\n", old)
557 return strings.Replace(s, old, "usercode.cpp:", -1)
558 }
559
543 // mainHandler handles the GET and POST of the main page. 560 // mainHandler handles the GET and POST of the main page.
544 func mainHandler(w http.ResponseWriter, r *http.Request) { 561 func mainHandler(w http.ResponseWriter, r *http.Request) {
545 log.Printf("Main Handler: %q\n", r.URL.Path) 562 log.Printf("Main Handler: %q\n", r.URL.Path)
546 if r.Method == "GET" { 563 if r.Method == "GET" {
547 code := DEFAULT_SAMPLE 564 code := DEFAULT_SAMPLE
548 match := directLink.FindStringSubmatch(r.URL.Path) 565 match := directLink.FindStringSubmatch(r.URL.Path)
549 var hash string 566 var hash string
550 if len(match) == 2 && r.URL.Path != "/" { 567 if len(match) == 2 && r.URL.Path != "/" {
551 hash = match[1] 568 hash = match[1]
552 if db == nil { 569 if db == nil {
553 http.NotFound(w, r) 570 http.NotFound(w, r)
554 return 571 return
555 } 572 }
556 // Update 'code' with the code found in the database. 573 // Update 'code' with the code found in the database.
557 if err := db.QueryRow("SELECT code FROM webtry WHERE has h=?", hash).Scan(&code); err != nil { 574 if err := db.QueryRow("SELECT code FROM webtry WHERE has h=?", hash).Scan(&code); err != nil {
558 http.NotFound(w, r) 575 http.NotFound(w, r)
559 return 576 return
560 } 577 }
561 } 578 }
562 // Expand the template. 579 // Expand the template.
563 » » if err := indexTemplate.Execute(w, userCode{UserCode: code, Hash : hash}); err != nil { 580 » » if err := indexTemplate.Execute(w, userCode{Code: code, Hash: ha sh}); err != nil {
564 log.Printf("ERROR: Failed to expand template: %q\n", err ) 581 log.Printf("ERROR: Failed to expand template: %q\n", err )
565 } 582 }
566 } else if r.Method == "POST" { 583 } else if r.Method == "POST" {
567 w.Header().Set("Content-Type", "application/json") 584 w.Header().Set("Content-Type", "application/json")
568 buf := bytes.NewBuffer(make([]byte, 0, MAX_TRY_SIZE)) 585 buf := bytes.NewBuffer(make([]byte, 0, MAX_TRY_SIZE))
569 n, err := buf.ReadFrom(r.Body) 586 n, err := buf.ReadFrom(r.Body)
570 if err != nil { 587 if err != nil {
571 » » » reportError(w, r, err, "Failed to read a request body.") 588 » » » reportTryError(w, r, err, "Failed to read a request body .", "")
572 return 589 return
573 } 590 }
574 if n == MAX_TRY_SIZE { 591 if n == MAX_TRY_SIZE {
575 err := fmt.Errorf("Code length equal to, or exceeded, %d ", MAX_TRY_SIZE) 592 err := fmt.Errorf("Code length equal to, or exceeded, %d ", MAX_TRY_SIZE)
576 » » » reportError(w, r, err, "Code too large.") 593 » » » reportTryError(w, r, err, "Code too large.", "")
577 return 594 return
578 } 595 }
579 request := TryRequest{} 596 request := TryRequest{}
580 if err := json.Unmarshal(buf.Bytes(), &request); err != nil { 597 if err := json.Unmarshal(buf.Bytes(), &request); err != nil {
581 » » » reportError(w, r, err, "Coulnd't decode JSON.") 598 » » » reportTryError(w, r, err, "Coulnd't decode JSON.", "")
582 return 599 return
583 } 600 }
584 if hasPreProcessor(request.Code) { 601 if hasPreProcessor(request.Code) {
585 err := fmt.Errorf("Found preprocessor macro in code.") 602 err := fmt.Errorf("Found preprocessor macro in code.")
586 » » » reportError(w, r, err, "Preprocessor macros aren't allow ed.") 603 » » » reportTryError(w, r, err, "Preprocessor macros aren't al lowed.", "")
587 return 604 return
588 } 605 }
589 hash, err := expandCode(LineNumbers(request.Code)) 606 hash, err := expandCode(LineNumbers(request.Code))
590 if err != nil { 607 if err != nil {
591 » » » reportError(w, r, err, "Failed to write the code to comp ile.") 608 » » » reportTryError(w, r, err, "Failed to write the code to c ompile.", hash)
592 return 609 return
593 } 610 }
594 writeToDatabase(hash, request.Code, request.Name) 611 writeToDatabase(hash, request.Code, request.Name)
595 message, err := doCmd(fmt.Sprintf(RESULT_COMPILE, hash, hash), t rue) 612 message, err := doCmd(fmt.Sprintf(RESULT_COMPILE, hash, hash), t rue)
596 if err != nil { 613 if err != nil {
597 » » » reportError(w, r, err, "Failed to compile the code:\n"+m essage) 614 » » » message = cleanCompileOutput(message, hash)
615 » » » reportTryError(w, r, err, message, hash)
598 return 616 return
599 } 617 }
600 linkMessage, err := doCmd(fmt.Sprintf(LINK, hash, hash), true) 618 linkMessage, err := doCmd(fmt.Sprintf(LINK, hash, hash), true)
601 if err != nil { 619 if err != nil {
602 » » » reportError(w, r, err, "Failed to link the code:\n"+link Message) 620 » » » linkMessage = cleanCompileOutput(linkMessage, hash)
621 » » » reportTryError(w, r, err, linkMessage, hash)
603 return 622 return
604 } 623 }
605 message += linkMessage 624 message += linkMessage
606 cmd := hash + " --out " + hash + ".png" 625 cmd := hash + " --out " + hash + ".png"
607 if *useChroot { 626 if *useChroot {
608 cmd = "schroot -c webtry --directory=/inout -- /inout/" + cmd 627 cmd = "schroot -c webtry --directory=/inout -- /inout/" + cmd
609 } else { 628 } else {
610 abs, err := filepath.Abs("../../../inout") 629 abs, err := filepath.Abs("../../../inout")
611 if err != nil { 630 if err != nil {
612 » » » » reportError(w, r, err, "Failed to find executabl e directory.") 631 » » » » reportTryError(w, r, err, "Failed to find execut able directory.", hash)
613 return 632 return
614 } 633 }
615 cmd = abs + "/" + cmd 634 cmd = abs + "/" + cmd
616 } 635 }
617 636
618 execMessage, err := doCmd(cmd, false) 637 execMessage, err := doCmd(cmd, false)
619 if err != nil { 638 if err != nil {
620 » » » reportError(w, r, err, "Failed to run the code:\n"+execM essage) 639 » » » reportTryError(w, r, err, "Failed to run the code:\n"+ex ecMessage, hash)
621 return 640 return
622 } 641 }
623 png, err := ioutil.ReadFile("../../../inout/" + hash + ".png") 642 png, err := ioutil.ReadFile("../../../inout/" + hash + ".png")
624 if err != nil { 643 if err != nil {
625 » » » reportError(w, r, err, "Failed to open the generated PNG .") 644 » » » reportTryError(w, r, err, "Failed to open the generated PNG.", hash)
626 return 645 return
627 } 646 }
628 647
629 m := response{ 648 m := response{
630 Message: message, 649 Message: message,
650 StdOut: execMessage,
631 Img: base64.StdEncoding.EncodeToString([]byte(png)), 651 Img: base64.StdEncoding.EncodeToString([]byte(png)),
632 Hash: hash, 652 Hash: hash,
633 } 653 }
634 resp, err := json.Marshal(m) 654 resp, err := json.Marshal(m)
635 if err != nil { 655 if err != nil {
636 » » » reportError(w, r, err, "Failed to serialize a response." ) 656 » » » reportTryError(w, r, err, "Failed to serialize a respons e.", hash)
637 return 657 return
638 } 658 }
639 w.Write(resp) 659 w.Write(resp)
640 } 660 }
641 } 661 }
642 662
643 func main() { 663 func main() {
644 flag.Parse() 664 flag.Parse()
645 http.HandleFunc("/i/", imageHandler) 665 http.HandleFunc("/i/", imageHandler)
646 http.HandleFunc("/w/", workspaceHandler) 666 http.HandleFunc("/w/", workspaceHandler)
647 http.HandleFunc("/recent/", recentHandler) 667 http.HandleFunc("/recent/", recentHandler)
648 http.HandleFunc("/iframe/", iframeHandler) 668 http.HandleFunc("/iframe/", iframeHandler)
649 http.HandleFunc("/json/", tryInfoHandler) 669 http.HandleFunc("/json/", tryInfoHandler)
650 http.HandleFunc("/css/", cssHandler) 670 http.HandleFunc("/css/", cssHandler)
651 http.HandleFunc("/js/", jsHandler) 671 http.HandleFunc("/js/", jsHandler)
652 // TODO Break out /c/ as it's own handler. 672 // TODO Break out /c/ as it's own handler.
653 http.HandleFunc("/", mainHandler) 673 http.HandleFunc("/", mainHandler)
654 log.Fatal(http.ListenAndServe(*port, nil)) 674 log.Fatal(http.ListenAndServe(*port, nil))
655 } 675 }
OLDNEW
« no previous file with comments | « experimental/webtry/templates/workspace.html ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698