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

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: Address feedback 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, c userCode, t *template.Template) error {
75 f, err := os.Create(filename)
76 if err != nil {
77 return err
78 }
79 defer f.Close()
80
81 return t.Execute(f, c)
82 }
83
84 // expandCode expands the template into a file and calculate the MD5 hash.
85 func expandCode(code string) (string, error) {
86 h := md5.New()
87 h.Write([]byte(code))
88 hash := fmt.Sprintf("%x", h.Sum(nil))
89 content := userCode{
90 UserCode: code,
91 }
92 // At this point we are running in skia/experimental/webtry, making cach e a
93 // peer directory to skia.
94 // TODO(jcgregorio) Make all relative directories into flags.
95 err := expandToFile(fmt.Sprintf("../../../cache/%s.cpp", hash), content, codeTemplate)
96 return hash, err
97 }
98
99 // response is serialized to JSON as a response to POSTs.
100 type response struct {
101 Message string `json:"message"`
102 Img string `json:"img"`
103 }
104
105 // doCmd executes the given command line string in either the out/Debug
106 // directory or the inout directory. Returns the stdout, and stderr in the case
107 // of a non-zero exit code.
108 func doCmd(commandLine string, moveToDebug bool) (string, error) {
109 log.Printf("Command: %q\n", commandLine)
110 programAndArgs := strings.SplitN(commandLine, " ", 2)
111 program := programAndArgs[0]
112 args := []string{}
113 if len(programAndArgs) > 1 {
114 args = strings.Split(programAndArgs[1], " ")
115 }
116 cmd := exec.Command(program, args...)
117 abs, err := filepath.Abs("../../out/Debug")
118 if err != nil {
119 return "", fmt.Errorf("Failed to find absolute path to Debug dir ectory.")
120 }
121 if moveToDebug {
122 cmd.Dir = abs
123 } else if !*useChroot { // Don't set cmd.Dir when using chroot.
124 abs, err := filepath.Abs("../../../inout")
125 if err != nil {
126 return "", fmt.Errorf("Failed to find absolute path to i nout directory.")
127 }
128 cmd.Dir = abs
129 }
130 log.Printf("Run in directory: %q\n", cmd.Dir)
131 var stdOut bytes.Buffer
132 cmd.Stdout = &stdOut
133 var stdErr bytes.Buffer
134 cmd.Stderr = &stdErr
135 cmd.Start()
136 err = cmd.Wait()
137 message := stdOut.String()
138 log.Printf("StdOut: %s\n", message)
139 if err != nil {
140 log.Printf("Exit status: %s\n", err.Error())
141 log.Printf("StdErr: %s\n", stdErr.String())
142 message += stdErr.String()
143 return message, fmt.Errorf("Failed to run command.")
144 }
145 return message, nil
146 }
147
148 // reportError formats an HTTP error response and also logs the detailed error m essage.
149 func reportError(w http.ResponseWriter, r *http.Request, err error, message stri ng) {
150 m := response{
151 Message: message,
152 }
153 log.Printf("Error: %s\n%s", message, err.Error())
154 resp, err := json.Marshal(m)
155 if err != nil {
156 http.Error(w, "Failed to serialize a response", 500)
157 return
158 }
159 w.Write(resp)
160 }
161
162 // mainHandler handles the GET and POST of the main page.
163 func mainHandler(w http.ResponseWriter, r *http.Request) {
164 if r.Method == "GET" {
165 w.Write(index)
166 } else if r.Method == "POST" {
167 w.Header().Set("Content-Type", "application/json")
168 b, err := ioutil.ReadAll(r.Body)
169 if err != nil {
170 reportError(w, r, err, "Failed to read a request body.")
171 return
172 }
173 hash, err := expandCode(LineNumbers(string(b)))
174 if err != nil {
175 reportError(w, r, err, "Failed to write the code to comp ile.")
176 return
177 }
178 message, err := doCmd(fmt.Sprintf(RESULT_COMPILE, hash, hash), t rue)
179 if err != nil {
180 reportError(w, r, err, "Failed to compile the code:\n"+m essage)
181 return
182 }
183 linkMessage, err := doCmd(fmt.Sprintf(LINK, hash, hash), true)
184 if err != nil {
185 reportError(w, r, err, "Failed to link the code:\n"+link Message)
186 return
187 }
188 message += linkMessage
189 cmd := hash + " --out " + hash + ".png"
190 if *useChroot {
191 cmd = "schroot -c webtry --directory=/inout -- /inout/" + cmd
192 } else {
193 abs, err := filepath.Abs("../../../inout")
194 if err != nil {
195 reportError(w, r, err, "Failed to find executabl e directory.")
196 return
197 }
198 cmd = abs + "/" + cmd
199 }
200
201 execMessage, err := doCmd(cmd, false)
202 if err != nil {
203 reportError(w, r, err, "Failed to run the code:\n"+execM essage)
204 return
205 }
206 png, err := ioutil.ReadFile("../../../inout/" + hash + ".png")
207 if err != nil {
208 reportError(w, r, err, "Failed to open the generated PNG .")
209 return
210 }
211
212 m := response{
213 Message: message,
214 Img: base64.StdEncoding.EncodeToString([]byte(png)),
215 }
216 resp, err := json.Marshal(m)
217 if err != nil {
218 reportError(w, r, err, "Failed to serialize a response." )
219 return
220 }
221 w.Write(resp)
222 }
223 }
224
225 func main() {
226 flag.Parse()
227
228 http.HandleFunc("/", mainHandler)
229 log.Fatal(http.ListenAndServe(":8000", nil))
230 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698