diff --git a/experimental/webtry/build b/experimental/webtry/build old mode 100644 new mode 100755 diff --git a/experimental/webtry/gyp_for_webtry b/experimental/webtry/gyp_for_webtry new file mode 100755 index 0000000000..374c02abe2 --- /dev/null +++ b/experimental/webtry/gyp_for_webtry @@ -0,0 +1,43 @@ +#!/usr/bin/python +import os +import sys + +script_dir = os.path.dirname(__file__) + +skia_src = os.path.abspath(os.environ.get('SKIA_SRC', os.path.join( script_dir, "..", ".."))) +gyp_source_dir = os.path.join(skia_src, 'third_party', 'externals', 'gyp') + +WEBTRY_CACHE_DEFAULT = os.path.join(script_dir, "..", "..", "..", "cache") +WEBTRY_INOUT_DEFAULT = os.path.join(script_dir, "..", "..", "..", "inout") + +sys.path.insert(0, os.path.abspath(os.path.join(gyp_source_dir, 'pylib'))) +import gyp + +if __name__ == '__main__': + if len(sys.argv) < 2: + print "Usage: gyp_for_webtry [code hash value]" + sys.exit(-1) + + args = sys.argv[2:] + + if not os.environ.get('GYP_GENERATORS'): + os.environ['GYP_GENERATORS'] = 'ninja' + + args.append('--check') + args.append('-I%s/gyp/common.gypi' % skia_src) + args.extend(['--depth', '.']) + webtry_cache_dir = os.path.abspath(os.environ.get('WEBTRY_CACHE', WEBTRY_CACHE_DEFAULT)) + webtry_inout_dir = os.path.abspath(os.environ.get('WEBTRY_INOUT', WEBTRY_INOUT_DEFAULT)) + + args.append('-Goutput_dir=%s' % webtry_inout_dir) + + args.append(os.path.join(webtry_cache_dir, '%s.gyp' % sys.argv[1])) + + # gyp is really picky about the current working directory having src/ under it + os.chdir(webtry_cache_dir) + + os.environ['CC'] = '../../skia/experimental/webtry/safec' + os.environ['CXX'] = '../../skia/experimental/webtry/safec++' + os.environ['LD'] = '../../skia/experimental/webtry/safec++' + + sys.exit(gyp.main(args)) diff --git a/experimental/webtry/res/css/webtry.css b/experimental/webtry/res/css/webtry.css index 09751df532..246fb9b778 100644 --- a/experimental/webtry/res/css/webtry.css +++ b/experimental/webtry/res/css/webtry.css @@ -125,4 +125,10 @@ pre, code { .CodeMirror { border: solid gray 1px; + height: auto; +} + +.CodeMirror-scroll { + overflow-y: hidden; + overflow-x: auto; } diff --git a/experimental/webtry/safec b/experimental/webtry/safec new file mode 100755 index 0000000000..9cc5771d49 --- /dev/null +++ b/experimental/webtry/safec @@ -0,0 +1,7 @@ +#!/bin/bash +# Limit the amount of time and the core size for the compiler. +set -e + +ulimit -t 5 -c 0 + +cc $@ diff --git a/experimental/webtry/setup/continue_install b/experimental/webtry/setup/continue_install index 7891be4d53..1959ee78a8 100755 --- a/experimental/webtry/setup/continue_install +++ b/experimental/webtry/setup/continue_install @@ -30,6 +30,7 @@ export GOPATH=$HOME/golib export PATH=$PATH:$GOROOT/bin mkdir /home/webtry/cache +mkdir /home/webtry/cache/src mkdir /home/webtry/inout chmod 777 /home/webtry/inout diff --git a/experimental/webtry/templates/template.gyp b/experimental/webtry/templates/template.gyp new file mode 100644 index 0000000000..d0e7ecd990 --- /dev/null +++ b/experimental/webtry/templates/template.gyp @@ -0,0 +1,37 @@ +{ + 'targets': [ + { + 'configurations': { + 'Debug': { }, + 'Release': { } + }, + 'target_name': '{{.Hash}}', + 'type': 'executable', + 'dependencies': [ + '../skia/gyp/skia_lib.gyp:skia_lib', + '../skia/gyp/flags.gyp:flags' + ], + 'include_dirs': [ + '../skia/include/config', + '../skia/include/core', + '../skia/tools/flags', + '../skia/src/core', + ], + 'conditions': [ + ['skia_os == "mac"', { + 'defines': ['SK_UNSAFE_BUILD_DESKTOP_ONLY=1'] + }] + ], + 'sources': [ + 'src/{{.Hash}}.cpp', + '../skia/experimental/webtry/main.cpp' + ], + 'ldflags': [ + '-lskia', '-stdlib=libc++', '-std=c++11' + ], + 'cflags': [ + '-Werror', '-W', '-Wall', '-Wextra', '-Wno-unused-parameter', '-g', '-O0' + ] + } + ] +} diff --git a/experimental/webtry/webtry.go b/experimental/webtry/webtry.go index 93e78c42da..0143feec80 100644 --- a/experimental/webtry/webtry.go +++ b/experimental/webtry/webtry.go @@ -36,8 +36,8 @@ import ( ) const ( - RESULT_COMPILE = `../../experimental/webtry/safec++ -DSK_GAMMA_SRGB -DSK_GAMMA_APPLY_TO_A8 -DSK_SCALAR_TO_FLOAT_EXCLUDED -DSK_ALLOW_STATIC_GLOBAL_INITIALIZERS=1 -DSK_SUPPORT_GPU=0 -DSK_SUPPORT_OPENCL=0 -DSK_FORCE_DISTANCEFIELD_FONTS=0 -DSK_SCALAR_IS_FLOAT -DSK_CAN_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/pathops -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-unused-parameter -m64 -fno-rtti -Wnon-virtual-dtor -c ../../../cache/%s.cpp -o ../../../cache/%s.o` - LINK = `../../experimental/webtry/safec++ -m64 -lstdc++ -lm -o ../../../inout/%s -Wl,--start-group ../../../cache/%s.o obj/experimental/webtry/webtry.main.o obj/gyp/libflags.a libskia_images.a libskia_core.a libskia_effects.a obj/gyp/libjpeg.a obj/gyp/libetc1.a obj/gyp/libSkKTX.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 libskia_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` + RUN_GYP = `../../experimental/webtry/gyp_for_webtry %s` + RUN_NINJA = `ninja -C ../../../inout/Release %s` DEFAULT_SAMPLE = `void draw(SkCanvas* canvas) { SkPaint p; @@ -56,6 +56,9 @@ var ( // codeTemplate is the cpp code template the user's code is copied into. codeTemplate *template.Template = nil + // gypTemplate is the GYP file to build the executable containing the user's code. + gypTemplate *template.Template = nil + // indexTemplate is the main index.html page we serve. indexTemplate *htemplate.Template = nil @@ -150,6 +153,10 @@ func init() { if err != nil { panic(err) } + gypTemplate, err = template.ParseFiles(filepath.Join(cwd, "templates/template.gyp")) + if err != nil { + panic(err) + } indexTemplate, err = htemplate.ParseFiles( filepath.Join(cwd, "templates/index.html"), filepath.Join(cwd, "templates/titlebar.html"), @@ -337,14 +344,20 @@ type userCode struct { Titlebar Titlebar } -// expandToFile expands the template and writes the result to the file. -func expandToFile(filename string, code string, t *template.Template) error { +// writeTemplate creates a given output file and writes the template +// result there. +func writeTemplate(filename string, t *template.Template, context interface{}) error { f, err := os.Create(filename) if err != nil { return err } defer f.Close() - return t.Execute(f, userCode{Code: code, Titlebar: Titlebar{GitHash: gitHash, GitInfo: gitInfo}}) + return t.Execute( f, context ) +} + +// expandToFile expands the template and writes the result to the file. +func expandToFile(filename string, code string, t *template.Template) error { + return writeTemplate( filename, t, userCode{Code: code, Titlebar: Titlebar{GitHash: gitHash, GitInfo: gitInfo}} ) } // expandCode expands the template into a file and calculates the MD5 hash. @@ -356,10 +369,15 @@ func expandCode(code string, source int) (string, error) { // At this point we are running in skia/experimental/webtry, making cache a // peer directory to skia. // TODO(jcgregorio) Make all relative directories into flags. - err := expandToFile(fmt.Sprintf("../../../cache/%s.cpp", hash), code, codeTemplate) + err := expandToFile(fmt.Sprintf("../../../cache/src/%s.cpp", hash), code, codeTemplate) return hash, err } +// expandGyp produces the GYP file needed to build the code +func expandGyp(hash string) (error) { + return writeTemplate(fmt.Sprintf("../../../cache/%s.gyp", hash), gypTemplate, struct {Hash string}{hash} ) +} + // response is serialized to JSON as a response to POSTs. type response struct { Message string `json:"message"` @@ -738,7 +756,7 @@ func tryInfoHandler(w http.ResponseWriter, r *http.Request) { } func cleanCompileOutput(s, hash string) string { - old := "../../../cache/" + hash + ".cpp:" + old := "../../../cache/src/" + hash + ".cpp:" log.Printf("INFO: replacing %q\n", old) return strings.Replace(s, old, "usercode.cpp:", -1) } @@ -798,13 +816,18 @@ func mainHandler(w http.ResponseWriter, r *http.Request) { return } writeToDatabase(hash, request.Code, request.Name, request.Source) - message, err := doCmd(fmt.Sprintf(RESULT_COMPILE, hash, hash), true) + err = expandGyp(hash) + if err != nil { + reportTryError(w, r, err, "Failed to write the gyp file.", hash) + return + } + message, err := doCmd(fmt.Sprintf(RUN_GYP, hash), true) if err != nil { message = cleanCompileOutput(message, hash) reportTryError(w, r, err, message, hash) return } - linkMessage, err := doCmd(fmt.Sprintf(LINK, hash, hash), true) + linkMessage, err := doCmd(fmt.Sprintf(RUN_NINJA, hash), true) if err != nil { linkMessage = cleanCompileOutput(linkMessage, hash) reportTryError(w, r, err, linkMessage, hash) @@ -816,9 +839,9 @@ func mainHandler(w http.ResponseWriter, r *http.Request) { cmd += fmt.Sprintf(" --source image-%d.png", request.Source) } if *useChroot { - cmd = "schroot -c webtry --directory=/inout -- /inout/" + cmd + cmd = "schroot -c webtry --directory=/inout -- /inout/Release/" + cmd } else { - abs, err := filepath.Abs("../../../inout") + abs, err := filepath.Abs("../../../inout/Release") if err != nil { reportTryError(w, r, err, "Failed to find executable directory.", hash) return