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

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

Issue 228693002: Initial code for webtry, a web application for allowing users to try out Skia. (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Don't add webtry to everything.gyp 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
OLDNEW
(Empty)
1 package main
2
3 import (
4 "bytes"
5 "crypto/md5"
6 "encoding/base64"
7 "encoding/json"
8 "flag"
9 "fmt"
10 "io/ioutil"
11 "log"
12 "net/http"
13 "os"
14 "os/exec"
15 "path/filepath"
16 "strings"
17 "text/template"
18 )
19
20 const (
21 RESULT_COMPILE = `c++ -DSK_GAMMA_SRGB -DSK_GAMMA_APPLY_TO_A8 -DSK_SCALAR _TO_FLOAT_EXCLUDED -DSK_ALLOW_STATIC_GLOBAL_INITIALIZERS=1 -DSK_SUPPORT_GPU=0 -D SK_SUPPORT_OPENCL=0 -DSK_FORCE_DISTANCEFIELD_FONTS=0 -DSK_SCALAR_IS_FLOAT -DSK_C AN_USE_FLOAT -DSK_SAMPLES_FOR_X -DSK_BUILD_FOR_UNIX -DSK_USE_POSIX_THREADS -DSK_ SYSTEM_ZLIB=1 -DSK_DEBUG -DSK_DEVELOPER=1 -I../../src/core -I../../src/images -I ../../tools/flags -I../../include/config -I../../include/core -I../../include/pa thops -I../../include/pipe -I../../include/effects -I../../include/ports -I../.. /src/sfnt -I../../include/utils -I../../src/utils -I../../include/images -g -fno -exceptions -fstrict-aliasing -Wall -Wextra -Winit-self -Wpointer-arith -Wno-unu sed-parameter -Wno-c++11-extensions -Werror -m64 -fno-rtti -Wnon-virtual-dtor -c ../../../cache/%s.cpp -o ../../../cache/%s.o`
22 LINK = `c++ -m64 -lstdc++ -lm -o ../../../inout/%s -Wl,--start -group ../../../cache/%s.o obj/experimental/webtry/webtry.main.o obj/experimenta l/webtry/webtry.syscall_reporter.o obj/gyp/libflags.a libskia_images.a libskia_c ore.a libskia_effects.a obj/gyp/libjpeg.a obj/gyp/libwebp_dec.a obj/gyp/libwebp_ demux.a obj/gyp/libwebp_dsp.a obj/gyp/libwebp_enc.a obj/gyp/libwebp_utils.a libs kia_utils.a libskia_opts.a libskia_opts_ssse3.a libskia_ports.a libskia_sfnt.a - Wl,--end-group -lpng -lz -lgif -lpthread -lfontconfig -ldl -lfreetype`
23 )
24
25 var (
26 // codeTemplate is the cpp code template the user's code is copied into.
27 codeTemplate *template.Template = nil
28
29 // index is the main index.html page we serve.
30 index []byte
31 )
32
33 // flags
34 var (
35 useChroot = flag.Bool("use_chroot", false, "Run the compiled code in the schroot jail.")
36 )
37
38 // lineNumbers adds #line numbering to the user's code.
39 func LineNumbers(c string) string {
40 lines := strings.Split(c, "\n")
41 ret := []string{}
42 for i, line := range lines {
43 ret = append(ret, fmt.Sprintf("#line %d", i+1))
44 ret = append(ret, line)
45 }
46 return strings.Join(ret, "\n")
47 }
48
49 func init() {
50 // Change the current working directory to the directory of the executab le.
51 var err error
52 cwd, err := filepath.Abs(filepath.Dir(os.Args[0]))
53 if err != nil {
54 log.Fatal(err)
55 }
56 os.Chdir(cwd)
57
58 codeTemplate, err = template.ParseFiles(filepath.Join(cwd, "templates/te mplate.cpp"))
59 if err != nil {
60 panic(err)
61 }
62 index, err = ioutil.ReadFile(filepath.Join(cwd, "templates/index.html"))
63 if err != nil {
64 panic(err)
65 }
66 }
67
68 // userCode is used in template expansion.
69 type userCode struct {
70 UserCode string
71 }
72
73 // expandToFile expands the template and writes the result to the file.
74 func expandToFile(filename string, code string, t *template.Template) error {
75 f, err := os.Create(filename)
76 if err != nil {
77 return err
78 }
79 defer f.Close()
80 return t.Execute(f, struct{ UserCode string }{UserCode: code})
81 }
82
83 // expandCode expands the template into a file and calculate the MD5 hash.
84 func expandCode(code string) (string, error) {
85 h := md5.New()
86 h.Write([]byte(code))
87 hash := fmt.Sprintf("%x", h.Sum(nil))
88 // At this point we are running in skia/experimental/webtry, making cach e a
89 // peer directory to skia.
90 // TODO(jcgregorio) Make all relative directories into flags.
91 err := expandToFile(fmt.Sprintf("../../../cache/%s.cpp", hash), code, co deTemplate)
92 return hash, err
93 }
94
95 // response is serialized to JSON as a response to POSTs.
96 type response struct {
97 Message string `json:"message"`
98 Img string `json:"img"`
99 }
100
101 // doCmd executes the given command line string in either the out/Debug
102 // directory or the inout directory. Returns the stdout, and stderr in the case
103 // of a non-zero exit code.
104 func doCmd(commandLine string, moveToDebug bool) (string, error) {
105 log.Printf("Command: %q\n", commandLine)
106 programAndArgs := strings.SplitN(commandLine, " ", 2)
107 program := programAndArgs[0]
108 args := []string{}
109 if len(programAndArgs) > 1 {
110 args = strings.Split(programAndArgs[1], " ")
111 }
112 cmd := exec.Command(program, args...)
113 abs, err := filepath.Abs("../../out/Debug")
114 if err != nil {
115 return "", fmt.Errorf("Failed to find absolute path to Debug dir ectory.")
116 }
117 if moveToDebug {
118 cmd.Dir = abs
119 } else if !*useChroot { // Don't set cmd.Dir when using chroot.
120 abs, err := filepath.Abs("../../../inout")
121 if err != nil {
122 return "", fmt.Errorf("Failed to find absolute path to i nout directory.")
123 }
124 cmd.Dir = abs
125 }
126 log.Printf("Run in directory: %q\n", cmd.Dir)
127 var stdOut bytes.Buffer
128 cmd.Stdout = &stdOut
129 var stdErr bytes.Buffer
130 cmd.Stderr = &stdErr
131 cmd.Start()
132 err = cmd.Wait()
133 message := stdOut.String()
134 log.Printf("StdOut: %s\n", message)
135 if err != nil {
136 log.Printf("Exit status: %s\n", err.Error())
137 log.Printf("StdErr: %s\n", stdErr.String())
138 message += stdErr.String()
139 return message, fmt.Errorf("Failed to run command.")
140 }
141 return message, nil
142 }
143
144 // reportError formats an HTTP error response and also logs the detailed error m essage.
145 func reportError(w http.ResponseWriter, r *http.Request, err error, message stri ng) {
146 m := response{
147 Message: message,
148 }
149 log.Printf("Error: %s\n%s", message, err.Error())
150 resp, err := json.Marshal(m)
151 if err != nil {
152 http.Error(w, "Failed to serialize a response", 500)
153 return
154 }
155 w.Write(resp)
156 }
157
158 // mainHandler handles the GET and POST of the main page.
159 func mainHandler(w http.ResponseWriter, r *http.Request) {
160 if r.Method == "GET" {
161 w.Write(index)
162 } else if r.Method == "POST" {
163 w.Header().Set("Content-Type", "application/json")
164 b, err := ioutil.ReadAll(r.Body)
165 if err != nil {
166 reportError(w, r, err, "Failed to read a request body.")
167 return
168 }
169 hash, err := expandCode(LineNumbers(string(b)))
170 if err != nil {
171 reportError(w, r, err, "Failed to write the code to comp ile.")
172 return
173 }
174 message, err := doCmd(fmt.Sprintf(RESULT_COMPILE, hash, hash), t rue)
175 if err != nil {
176 reportError(w, r, err, "Failed to compile the code:\n"+m essage)
177 return
178 }
179 linkMessage, err := doCmd(fmt.Sprintf(LINK, hash, hash), true)
180 if err != nil {
181 reportError(w, r, err, "Failed to link the code:\n"+link Message)
182 return
183 }
184 message += linkMessage
185 cmd := hash + " --out " + hash + ".png"
186 if *useChroot {
187 cmd = "schroot -c webtry --directory=/inout -- /inout/" + cmd
188 } else {
189 abs, err := filepath.Abs("../../../inout")
190 if err != nil {
191 reportError(w, r, err, "Failed to find executabl e directory.")
192 return
193 }
194 cmd = abs + "/" + cmd
195 }
196
197 execMessage, err := doCmd(cmd, false)
198 if err != nil {
199 reportError(w, r, err, "Failed to run the code:\n"+execM essage)
200 return
201 }
202 png, err := ioutil.ReadFile("../../../inout/" + hash + ".png")
203 if err != nil {
204 reportError(w, r, err, "Failed to open the generated PNG .")
205 return
206 }
207
208 m := response{
209 Message: message,
210 Img: base64.StdEncoding.EncodeToString([]byte(png)),
211 }
212 resp, err := json.Marshal(m)
213 if err != nil {
214 reportError(w, r, err, "Failed to serialize a response." )
215 return
216 }
217 w.Write(resp)
218 }
219 }
220
221 func main() {
222 flag.Parse()
223
224 http.HandleFunc("/", mainHandler)
225 log.Fatal(http.ListenAndServe(":8000", nil))
226 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698