Merge pull request #2417 from luser/fix-weak-map-keys
[shumway.git] / Gruntfile.js
blob1bc37160e160b0660a1f75252ff6b293b05025ed
1 /*
2 * Copyright 2013 Mozilla Foundation
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 module.exports = function(grunt) {
19 var VERSION_BASELINE = '2bbdb5ce0db7796b';
20 var VERSION_BASE = '0.11.';
22 // require it at the top and pass in the grunt instance
23 require('time-grunt')(grunt);
25 // work around a grunt bug where color output is written to non-tty output
26 if (!process.stdout.isTTY) {
27 grunt.option("color", false);
30 var tscCommand = 'node ./node_modules/typescript/bin/tsc.js';
31 var commonArguments = tscCommand + ' --target ES5 --sourcemap -d --out build/ts/';
33 var defaultBrowserManifestFile = './resources/browser_manifests/browser_manifest.json';
34 var defaultTestsManifestFile = 'test_manifest.json';
36 var parallelArgs = ['bundle', 'threads', 'sha1', 'rebuild', 'tests', 'bundle',
37 'noPrompts'].filter(function (s) {
38 return grunt.option(s) !== undefined;
39 }).map(function (s) {
40 return '--' + s + '=' + grunt.option(s);
41 });
43 function expandFilePattern(pattern) {
44 return '"' + grunt.file.expand(pattern).join('" "') + '"'
47 grunt.initConfig({
48 pkg: grunt.file.readJSON('package.json'),
49 tslint: {
50 options: {
51 configuration: grunt.file.readJSON("tslint.json")
53 all: ['src/base/**/*.ts', 'src/flash/**/*.ts', 'src/avm2/**/*.ts'] // TODO: Add more directories.
55 exec: {
56 build_web: {
57 cmd: 'make -C web/ build'
59 build_extension: {
60 cmd: 'make -C extension/firefox/ build'
62 build_mozcentral: {
63 cmd: 'make -C extension/mozcentral/ build'
65 build_base_ts: {
66 cmd: commonArguments + 'base.js src/base/references.ts'
68 build_tools_ts: {
69 cmd: commonArguments + 'tools.js src/tools/references.ts'
71 build_swf_ts: {
72 cmd: commonArguments + 'swf.js src/swf/references.ts'
74 build_avm2_ts: {
75 cmd: commonArguments + 'avm2.js src/avm2/references.ts'
77 build_avm2_tests: {
78 cmd: 'make -C test/avm2/'
80 build_avm1_ts: {
81 cmd: commonArguments + 'avm1.js src/avm1/references.ts'
83 build_gfx_ts: {
84 cmd: commonArguments + 'gfx.js src/gfx/references.ts'
86 build_gfx_base_ts: {
87 cmd: commonArguments + 'gfx-base.js src/gfx/references-base.ts'
89 build_flash_ts: {
90 cmd: commonArguments + 'flash.js src/flash/references.ts'
92 build_player_ts: {
93 cmd: commonArguments + 'player.js src/player/references.ts'
95 build_shell_ts: {
96 cmd: tscCommand + ' --target ES5 --sourcemap --out build/ts/shell.js src/shell/references.ts'
98 build_playerglobal: {
99 cmd: 'node build.js -t ' + (+grunt.option('threads') || 9) +
100 (grunt.option('sha1') ? ' -s' : '') +
101 (grunt.option('rebuild') ? ' -r' : ''),
102 cwd: 'utils/playerglobal-builder'
104 build_playerglobal_single: {
105 cmd: 'node single.js',
106 cwd: 'utils/playerglobal-builder'
108 debug_server: {
109 cmd: 'node examples/inspector/debug/server.js'
111 perf: {
112 cmd: '"utils/jsshell/js" build/ts/shell.js -x -g ' +
113 (grunt.option('verbose') ? '-v ' : '') +
114 (grunt.option('tests') || expandFilePattern('test/perf/pass/*.js'))
116 "gfx-test": {
117 cmd: '"utils/jsshell/js" build/ts/shell.js -x -g ' +
118 (grunt.option('verbose') ? '-v ' : '') +
119 (grunt.option('tests') || expandFilePattern('test/gfx/pass/*.js'))
121 // Greps for errors.
122 warn: {
123 maxBuffer: Infinity,
124 cmd: 'find -L build/test -name "*.run" | xargs cat | grep "Not Implemented\\|Uncaught VM-internal\\|FAILED\\|EXCEPTED";'
126 warn_spell: {
127 // TODO: Add more files.
128 cmd: 'node utils/spell/spell.js build/ts/flash.js build/ts/avm2.js'
130 lint_success: {
131 cmd: 'echo "SUCCESS: no lint errors"'
133 // Run all tests from shumway.txt in one instance of Shumway and save the output in |test/avm2/shumway.run|.
134 test_avm2_shumway: {
135 maxBuffer: Infinity,
136 cmd: 'mkdir -p build/test/avm2; ' +
137 'cat test/avm2/shumway.txt | xargs utils/jsshell/js build/ts/shell.js -x -det --printABCFileName > build/test/test_avm2_shumway.run; ' +
138 // Run all tests from shumway.txt each in many instances of Tamarin and save the output in |test/avm2/shumway.baseline|.
139 // Between each run, emit the test name as "::: test :::" so it's easy to identify where things go wrong.
140 'rm test/test_avm2_shumway.baseline; cat test/avm2/shumway.txt | grep -v @ | xargs -L 1 -I \'{}\' sh -c \'echo "::: {} :::" >> test/test_avm2_shumway.baseline; utils/tamarin-redux/bin/shell/avmshell {} >> test/test_avm2_shumway.baseline;\'; ' +
141 // Diff results.
142 'diff test/test_avm2_shumway.baseline build/test/test_avm2_shumway.run'
144 // Runs tamarin acceptance tests and tests against the current baseline. If you get more tests to pass, update the baseline.
145 test_avm2_acceptance: {
146 maxBuffer: Infinity,
147 cmd: 'mkdir -p build/test; ' +
148 'utils/jsshell/js build/ts/shell.js -x -det -v test/avm2/acceptance.json | tee build/test/test_avm2_acceptance_stdout.run | node test/avm2/count_totals.js | tee build/test/test_avm2_acceptance.run && ' +
149 'diff test/test_avm2_acceptance.baseline build/test/test_avm2_acceptance.run'
151 // Runs the pypy tests and tests against the current baseline. If you get more tests to pass, update the baseline.
152 test_avm2_pypy: {
153 maxBuffer: Infinity,
154 cmd: 'mkdir -p build/test; ' +
155 'find -L test/avm2/pypy -name "*.abc" | xargs -I {} utils/jsshell/js build/ts/shell.js -x -det -v {} | tee build/test/test_avm2_pypy.run &&' +
156 'diff test/test_avm2_pypy.baseline build/test/test_avm2_pypy.run'
158 // Runs archive SWFs and tests against the current baseline. If you get more tests to pass, update the baseline.
159 // TODO: We need to pass the -k flag to parallel to keep the output in the right order, do what once we're ready
160 // to make this part of grunt gate.
161 test_arch: {
162 maxBuffer: Infinity,
163 cmd: 'mkdir -p build/test/; ' +
164 'find -L test/arch/swfs -name "*.swf" | parallel --gnu -X -N1 utils/jsshell/js build/ts/shell.js -x -det -fc 10 {} | tee build/test_arch.run;' +
165 'echo "Output saved to build/test_arch.run, at some point create a baseline and stick to it."'
166 // 'diff test/arch/arch.baseline build/test/arch/arch.run'
168 // Runs SWFs and tests against the current baseline. If you get more tests to pass, update the baseline.
169 test_swf: {
170 maxBuffer: Infinity,
171 cmd: 'find -L test/swf -name "*.swf" | parallel -k --gnu -X -N1 utils/jsshell/js build/ts/shell.js -x -det -fc 10 {} | LC_ALL=C sort > build/test/test_swf.run && ' +
172 'diff test/test_swf.baseline build/test/test_swf.run'
174 // Runs SWF trace tests.
175 test_trace: {
176 maxBuffer: Infinity,
177 cmd: 'node test/trace_test_run.js -j ' + (+grunt.option('threads') || 6)
179 // Runs SWF (AVM1) swfdec trace tests.
180 test_trace_swfdec: {
181 maxBuffer: Infinity,
182 cmd: 'node test/trace_test_run.js -j ' + (+grunt.option('threads') || 6) +
183 ' -m test/swfdec_test_manifest.json'
185 test_avm2_ats: {
186 maxBuffer: Infinity,
187 cmd: 'mkdir -p build/test; ' +
188 'cat test/ats/test_swf_avm2.txt | parallel -k --gnu -X -N50 utils/jsshell/js build/ts/shell.js -x -det -fc 10 {} > build/test/test_avm2_ats.run; ' +
189 'if [ ! -f "test/test_avm2_ats.baseline" ]; then echo "Creating Baseline"; cp build/test/test_avm2_ats.run test/test_avm2_ats.baseline; fi;' +
190 'diff test/test_avm2_ats.baseline build/test/test_avm2_ats.run;'
192 // Run this to make sure the SWF parser still works.
193 test_avm2_ats_parse: {
194 maxBuffer: Infinity,
195 cmd: 'cat test/ats/test_swf_avm2.txt | parallel --gnu -X -N50 utils/jsshell/js build/ts/shell.js -p -v' +
196 (grunt.option('verbose') ? '-v ' : '') + ' {}'
198 test_unit: {
199 cmd: '"utils/jsshell/js" build/ts/shell.js -x -g ' +
200 (grunt.option('verbose') ? '-v ' : '') +
201 (grunt.option('tests') || expandFilePattern('test/unit/pass/*.js'))
203 test_swf_avm2_all: {
204 maxBuffer: Infinity,
205 cmd: 'mongo ats --eval \'db.swfs.find({"parse_result.uses_avm1": false}).forEach(function (x) { print("test/ats/swfs/" + x.file); })\' | parallel --gnu -k -X -N10 --timeout 200% utils/jsshell/js build/ts/shell.js -x -det -fc 10 {} | tee test/ats/test_swf_avm2_all.run;'
207 test_swf_all: {
208 maxBuffer: Infinity,
209 cmd: 'mongo ats --eval \'db.swfs.find({}).forEach(function (x) { print("test/ats/swfs/" + x.file); })\' | parallel --gnu -k -X -N10 --timeout 200% utils/jsshell/js build/ts/shell.js -x -det -fc 10 {} | tee test/ats/test_swf_all.run;'
211 test_swf_ads: {
212 maxBuffer: Infinity,
213 cmd: 'mongo ats --eval \'db.swfs.find({"parse_result.file_size":{$lt:204800},ad_result:{$ne:null}}).forEach(function (x) { print("test/ats/swfs/" + x.file); })\' | parallel --gnu -k -X -N10 --timeout 200% utils/jsshell/js build/ts/shell.js -x -det -fc 10 {} | tee test/ats/test_swf_ads.run;'
215 test_mock: {
216 maxBuffer: Infinity,
217 cmd: 'mkdir -p build/test;' +
218 'utils/jsshell/js build/ts/shell.js -x -det test/mock/jwplayer.js examples/jwplayer/jwplayer.flash.swf -fc 10 > build/test/test_mock.run;' +
219 'diff test/test_mock.baseline build/test/test_mock.run;'
221 bench_avm2: {
222 maxBuffer: Infinity,
223 cmd: 'find -L test/avm2/jsbench -name "*.abc" | xargs utils/jsshell/js build/ts/shell.js -x --printABCFileName'
225 perf_avm2_acceptance: {
226 maxBuffer: Infinity,
227 cmd: 'utils/jsshell/js build/ts/shell.js -x -det -r --porcelain test/avm2/acceptance.json > /dev/null 2>&1'
229 // Parses all ABCs in the acceptance suite. This is useful to run if you've made changes to the parser.
230 trace_avm2_acceptance_parse: {
231 maxBuffer: Infinity,
232 cmd: 'find -L test/avm2/acceptance -name "*.abc" | parallel -k --gnu -X -N50 utils/jsshell/js build/ts/shell.js -d -v {}'
234 tracetest_fuzz: {
235 cmd: 'node test/trace_test_run.js -j ' + (+grunt.option('threads') || 6) +
236 ' -m test/test_manifest_fuzz.json'
238 instrument: {
239 cmd: function(path) {
240 var targetPath = path.replace(".swf", ".instrumented.swf");
241 console.info("Instrumenting " + path + " (" + targetPath + "), this may take a while if the file is large.");
242 return 'swfmill swf2xml ' + path + ' | xsltproc utils/instrument-swf.xslt - | swfmill xml2swf stdin ' + targetPath;
245 install_js_travis: {
246 cmd: "make -C utils/ install-js"
248 install_avmshell_travis: {
249 cmd: "make -C utils/ install-avmshell"
251 install_swfdec_travis: {
252 cmd: "make -C utils/ install-swfdec || echo 'Ignoring the error'"
254 versions_travis: {
255 cmd: "parallel --gnu --version; utils/jsshell/js --version; utils/tamarin-redux/bin/shell/avmshell -Dversion;"
257 install_mongo: {
258 cmd: "npm install mongojs@0.18.1"
260 start_ats_db: {
261 cmd: "test -e /tmp/ats.pid || mongod --dbpath test/ats/db --fork --logpath test/ats/db/log --pidfilepath /tmp/ats.pid || rm /tmp/ats.pid"
263 stop_ats_db: {
264 cmd: "test -e /tmp/ats.pid && kill $(cat /tmp/ats.pid); rm /tmp/ats.pid"
266 ats_parsetest: {
267 cmd: "parallel --will-cite node run.js --task parse ::: 0 1 2 3 4 5 6 7 8 9 a b c d e f",
268 cwd: "test/ats"
270 restartless: {
271 cmd: 'make restartless PROFILE="' + (grunt.option('profile') || '') + '"',
272 cwd: "extension/firefox"
275 parallel: {
276 test: {
277 options: {
278 grunt: true
280 tasks: [
281 'exec:test_avm2_shumway',
282 'exec:test_avm2_acceptance',
283 'exec:test_swf',
284 'exec:test_avm2_ats',
285 'exec:test_unit',
286 'exec:test_trace',
287 'exec:test_mock'
290 base: {
291 tasks: [
292 { args: ['generate-version'], grunt: true },
293 { args: ['buildlibs'], grunt: true },
294 { args: ['exec:build_base_ts'].concat(parallelArgs), grunt: true },
297 playerglobal: {
298 tasks: [
299 { args: ['exec:build_playerglobal'].concat(parallelArgs), grunt: true },
302 tier2: {
303 options: {
304 grunt: true
306 tasks: [
307 'exec:build_gfx_ts',
308 'exec:build_swf_ts',
309 'exec:build_avm2_ts'
312 natives: {
313 tasks: [
314 { args: ['exec:build_playerglobal'].concat(parallelArgs), grunt: true },
315 { args: ['exec:build_flash_ts'].concat(parallelArgs), grunt: true },
316 { args: ['exec:build_avm1_ts'].concat(parallelArgs), grunt: true }
319 avm1: {
320 tasks: [
321 { args: ['exec:build_avm1_ts'].concat(parallelArgs), grunt: true }
324 flash: {
325 tasks: [
326 { args: ['exec:build_playerglobal'].concat(parallelArgs), grunt: true },
327 { args: ['exec:build_flash_ts'].concat(parallelArgs), grunt: true }
331 watch: {
332 web: {
333 files: 'extension/firefox/**/*',
334 tasks: ['build-web']
336 extension: {
337 files: 'extension/firefox/**/*',
338 tasks: ['build-extension']
340 base: {
341 files: 'src/base/**/*',
342 tasks: ['exec:build_base_ts']
344 playerglobal: {
345 files: ['src/flash/**/*.as',
346 'utils/playerglobal-builder/manifest.json'],
347 tasks: ['exec:build_playerglobal']
349 swf_ts: {
350 files: ['src/swf/**/*.ts'],
351 tasks: ['exec:build_swf_ts']
353 flash_ts: {
354 files: ['src/avm2/**/*.ts',
355 'src/flash/**/*.ts'],
356 tasks: ['exec:build_flash_ts']
358 gfx_base_ts: {
359 files: ['src/gfx/**/*.ts'],
360 tasks: ['exec:build_gfx_base_ts']
362 gfx_ts: {
363 files: ['src/gfx/**/*.ts'],
364 tasks: ['exec:build_gfx_ts']
366 avm2_ts: {
367 files: ['src/avm2/**/*.ts'],
368 tasks: ['exec:build_avm2_ts']
370 avm1_ts: {
371 files: ['src/avm1/*.ts'],
372 tasks: ['exec:build_avm1_ts']
374 player_ts: {
375 files: ['src/flash/**/*.ts',
376 'src/player/**/*.ts'],
377 tasks: ['exec:build_player_ts']
379 tools_ts: {
380 files: ['src/tools/**/*.ts'],
381 tasks: ['exec:build_tools_ts']
386 grunt.loadNpmTasks('grunt-tslint');
387 grunt.loadNpmTasks('grunt-contrib-watch');
388 grunt.loadNpmTasks('grunt-exec');
389 grunt.loadNpmTasks('grunt-parallel');
391 grunt.registerTask('lint', ['tslint:all', 'exec:lint_success']);
393 grunt.registerTask('update-refs', function () {
394 var updateRefs = require('./utils/update-flash-refs.js').updateRefs;
395 updateRefs('examples/inspector/inspector.gfx.html', {gfx: true});
396 updateRefs('examples/xlsimport/index.html', {gfx: true, player: true});
397 updateRefs('examples/inspector/inspector.player.html', {player: true});
398 updateRefs('src/shell/shell.ts', {player: true, onlyIncludes: true});
400 grunt.registerTask('update-flash-refs', ['update-refs']); // TODO deprecated
402 grunt.registerTask('buildlibs', function() {
403 var outputDir = 'build/libs/';
404 grunt.file.mkdir(outputDir);
405 var done = this.async();
406 var buildLibs = require('./src/libs/buildlibs.js').buildLibs;
407 buildLibs(outputDir, false, null, function () {
408 done();
411 grunt.registerTask('copy_relooper', function() {
412 grunt.file.copy('src/avm2/compiler/relooper/relooper.js', 'build/libs/relooper.js');
414 grunt.registerTask('bundles', function () {
415 var outputDir = 'build/bundles/';
416 grunt.file.mkdir(outputDir);
417 var packageRefs = require('./utils/update-flash-refs.js').packageRefs;
418 var license = grunt.file.read('./src/license.js');
419 packageRefs(['gfx'], outputDir + 'shumway.gfx.js', license);
420 packageRefs(['player'], outputDir + 'shumway.player.js', license);
423 grunt.registerTask('merge-modules', function () {
424 mergeModules("build/bundles/shumway.player.js");
425 mergeModules("build/bundles/shumway.gfx.js");
428 function mergeModules(path) {
429 var mergeModules = require('typescript-module-merger').mergeModulesInFile;
430 grunt.file.write(path, mergeModules(path, !!grunt.option('verbose')));
433 function runClosure(jsFiles, output, warnings, done) {
434 // This needs a special build of closure that has SHUMWAY_OPTIMIZATIONS.
435 var closureCmd = 'java';
436 var closureArgs = ['-jar', 'utils/closure.jar',
437 '--define', 'release=true',
438 '--compilation_level', 'SHUMWAY_OPTIMIZATIONS',
439 '--language_in', 'ECMASCRIPT5'];
440 if (!warnings) {
441 closureArgs.push('--warning_level', 'QUIET');
443 closureArgs = closureArgs.concat(jsFiles).concat(['--js_output_file', output]);
444 console.log('Running closure for ' + jsFiles.join(', ') + ' ...');
445 grunt.util.spawn({
446 cmd: closureCmd,
447 args: closureArgs,
448 opts: { stdio: 'inherit' }
449 }, function (error, result) {
450 if (error || result.code) {
451 done(false);
452 return;
454 console.log('Closure output is created at ' + output);
455 done(true);
459 function runClosureTasks(tasks, warnings, done) {
460 var i = 0;
461 (function runNextTask() {
462 if (i < tasks.length) {
463 var task = tasks[i++];
464 runClosure([task[0]], task[1], warnings, function (success) {
465 if (!success) {
466 done(false);
467 return;
469 runNextTask();
471 } else {
472 done(true);
474 })();
477 grunt.registerTask('ensure-build-folder', function() {
478 grunt.file.mkdir('build');
481 grunt.registerTask('ensure-test-folder', function() {
482 grunt.file.mkdir('build/test');
485 grunt.registerTask('closure-bundles', function () {
486 var inputDir = 'build/bundles/';
487 var outputDir = 'build/bundles-cc/';
488 grunt.file.mkdir(outputDir);
490 runClosureTasks([
491 [inputDir + 'shumway.gfx.js', outputDir + 'shumway.gfx.js'],
492 [inputDir + 'shumway.player.js', outputDir + 'shumway.player.js']
493 ], !!grunt.option('verbose'), this.async());
496 grunt.registerTask('closure', function () {
497 runClosure([
498 "build/ts/base.js",
499 "build/ts/tools.js",
500 "build/ts/avm2.js",
501 "build/ts/flash.js",
502 "build/ts/avm1.js",
503 "build/ts/gfx-base.js",
504 "build/ts/gfx.js",
505 "build/ts/player.js"
506 ], "build/shumway.cc.js", true, this.async());
509 grunt.registerTask('closure-all', function () {
510 var outputDir = 'build/ts-cc/';
511 grunt.file.mkdir(outputDir);
512 runClosureTasks([
513 ["build/ts/base.js", outputDir + "base.js"],
514 ["build/ts/tools.js", outputDir + "tools.js"],
515 ["build/ts/avm2.js", outputDir + "avm2.js"],
516 ["build/ts/flash.js", outputDir + "flash.js"],
517 ["build/ts/avm1.js", outputDir + "avm1.js"],
518 ["build/ts/gfx-base.js", outputDir + "gfx-base.js"],
519 ["build/ts/gfx.js", outputDir + "gfx.js"],
520 ["build/ts/player.js", outputDir + "player.js"]
521 ], true, this.async());
524 grunt.registerTask('server', function () {
525 function isLogFileRequest(path) {
526 if (path.indexOf('/logs/') !== 0) {
527 return false;
529 return /^\/logs\/\w+\.(txt|log)$/i.test(path);
531 grunt.file.mkdir('build/logs/');
532 var WebServer = require('./test/webserver.js').WebServer;
533 var done = this.async();
534 var server = new WebServer();
535 if (grunt.option('host')) {
536 server.host = grunt.option('host');
538 if (grunt.option('port')) {
539 server.port = +grunt.option('port');
541 if (grunt.option('port_ssl')) {
542 server.port_ssl = +grunt.option('port_ssl');
544 var url = require('url'), fs = require('fs');
545 server.hooks['POST'].push(function (req, res) {
546 var parsedUrl = url.parse(req.url, true);
547 var pathname = parsedUrl.pathname;
548 if (!isLogFileRequest(pathname)) {
549 return false;
551 var filename = 'build' + pathname;
552 var body = '';
553 req.on('data', function (data) {
554 body += data;
556 req.on('end', function () {
557 fs.appendFile(filename, body, function () {
558 res.writeHead(204, {'Content-Type': 'text/plain'});
559 res.end();
562 return true;
564 server.hooks['DELETE'].push(function (req, res) {
565 var parsedUrl = url.parse(req.url, true);
566 var pathname = parsedUrl.pathname;
567 if (!isLogFileRequest(pathname)) {
568 return false;
570 var filename = 'build' + pathname;
571 fs.unlink(filename, function () {
572 res.writeHead(204, {'Content-Type': 'text/plain'});
573 res.end();
575 return true;
577 server.start();
580 grunt.registerTask('reftest', function () {
581 if (grunt.file.exists('test/tmp')) {
582 throw new Error('The test/tmp/ folder exists from the previous makeref attempt. ' +
583 'You may want to copy those images to test/refs/. Remove test/tmp/ to proceed with reftest.')
585 if (!grunt.option('browserManifestFile') && !grunt.file.exists('test', defaultBrowserManifestFile)) {
586 throw new Error('Browser manifest file is not found at test/' + defaultBrowserManifestFile + '. Create one using the examples at test/resources/browser_manifests/.');
588 var browserManifestFile = grunt.option('browserManifestFile') || defaultBrowserManifestFile;
589 var testManifestFile = grunt.option('manifestFile') || defaultTestsManifestFile;
590 var done = this.async();
591 var params = [];
592 if (grunt.option('extension')) {
593 params.push('--extension');
595 if (grunt.option('noPrompts')) {
596 params.push('--noPrompts');
598 grunt.util.spawn({
599 cmd: 'node',
600 args: ['test.js', '--reftest', '--browserManifestFile=' + browserManifestFile,
601 '--manifestFile=' + testManifestFile].concat(params),
602 opts: { cwd: 'test', stdio: 'inherit' }
603 }, function () {
604 done();
608 grunt.registerTask('reftest-extension', function () {
609 grunt.option('extension', true);
610 grunt.task.run('firefox', 'reftest');
613 grunt.registerTask('reftest-swfdec', function () {
614 if (grunt.file.exists('test/tmp')) {
615 throw new Error('The test/tmp/ folder exists from the previous makeref attempt. ' +
616 'You may want to copy those images to test/refs/. Remove test/tmp/ to proceed with reftest.')
618 if (!grunt.option('browserManifestFile') && !grunt.file.exists('test', defaultBrowserManifestFile)) {
619 throw new Error('Browser manifest file is not found at test/' + defaultBrowserManifestFile + '. Create one using the examples at test/resources/browser_manifests/.');
621 var browserManifestFile = grunt.option('browserManifestFile') || defaultBrowserManifestFile;
622 var testManifestFile = 'swfdec_reftest_manifest.json';
623 var done = this.async();
624 var params = [];
625 if (grunt.option('extension')) {
626 params.push('--extension');
628 if (grunt.option('noPrompts')) {
629 params.push('--noPrompts');
631 grunt.util.spawn({
632 cmd: 'node',
633 args: ['test.js', '--browserManifestFile=' + browserManifestFile,
634 '--manifestFile=' + testManifestFile].concat(params),
635 opts: { cwd: 'test', stdio: 'inherit' }
636 }, function () {
637 done();
641 grunt.registerTask('makeref', function () {
642 if (!grunt.option('browserManifestFile') && !grunt.file.exists('test', defaultBrowserManifestFile)) {
643 throw new Error('Browser manifest file is not found at test/' + defaultBrowserManifestFile + '. Create one using the examples at test/resources/browser_manifests/.');
645 var browserManifestFile = grunt.option('browserManifestFile') || defaultBrowserManifestFile;
646 var done = this.async();
647 var params = [];
648 if (grunt.option('extension')) {
649 params.push('--extension');
651 if (grunt.option('noPrompts')) {
652 params.push('--noPrompts');
654 grunt.util.spawn({
655 cmd: 'node',
656 args: ['test.js', '-m', '--browserManifestFile=' + browserManifestFile].concat(params),
657 opts: { cwd: 'test', stdio: 'inherit'}}, function () {
658 done();
662 grunt.registerTask('shell-package', function () {
663 var outputDir = 'build/shell';
664 grunt.file.mkdir(outputDir);
665 var path = require('path');
667 grunt.file.copy('build/libs/builtin.abc', outputDir + '/build/libs/builtin.abc');
668 grunt.file.copy('build/libs/shell.abc', outputDir + '/build/libs/shell.abc');
669 grunt.file.copy('build/playerglobal/playerglobal.abcs', outputDir + '/build/playerglobal/playerglobal.abcs');
670 grunt.file.copy('build/playerglobal/playerglobal.json', outputDir + '/build/playerglobal/playerglobal.json');
671 grunt.file.copy('build/libs/relooper.js', outputDir + '/build/libs/relooper.js');
672 grunt.file.expand('build/ts/*.js').forEach(function (file) {
673 grunt.file.copy(file, outputDir + '/build/ts/' + path.basename(file));
675 grunt.file.expand('build/bundles/*.js').forEach(function (file) {
676 grunt.file.copy(file, outputDir + '/build/bundles/' + path.basename(file));
678 grunt.file.expand('build/bundles-cc/*.js').forEach(function (file) {
679 grunt.file.copy(file, outputDir + '/build/bundles-cc/' + path.basename(file));
681 grunt.file.copy('src/shell/shell-node.js', outputDir + '/src/shell/shell-node.js');
682 grunt.file.copy('build/version/version.txt', outputDir + '/version.txt');
683 grunt.file.copy('LICENSE', outputDir + '/LICENSE');
685 var waitFor = 0, done = this.async();
686 grunt.file.expand('src/shell/runners/run-*').forEach(function (file) {
687 var dest = outputDir + '/bin/' + path.basename(file);
688 grunt.file.copy(file, dest);
689 waitFor++;
690 grunt.util.spawn({cmd: 'chmod', args: ['+x', dest]}, function () {
691 waitFor--;
692 if (waitFor === 0) {
693 done();
697 if (waitFor === 0) {
698 done();
702 grunt.registerTask('tracetest', ['exec:test_trace']);
703 grunt.registerTask('tracetest-swfdec', ['exec:test_trace_swfdec']);
705 grunt.registerTask('watch-playerglobal', ['exec:build_playerglobal', 'watch:playerglobal']);
706 grunt.registerTask('watch-base', ['exec:build_base_ts', 'watch:base']);
707 grunt.registerTask('watch-avm2', ['exec:build_avm2_ts', 'watch:avm2_ts']);
708 grunt.registerTask('watch-swf', ['exec:build_swf_ts', 'watch:swf_ts']);
709 grunt.registerTask('watch-flash', ['exec:build_flash_ts', 'watch:flash_ts']);
710 grunt.registerTask('watch-player', ['exec:build_player_ts', 'watch:player_ts']);
711 grunt.registerTask('watch-gfx', ['exec:build_gfx_base_ts', 'exec:build_gfx_ts', 'watch:gfx_ts']);
712 grunt.registerTask('watch-tools', ['exec:build_tools_ts', 'watch:tools_ts']);
714 // temporary make/python calls based on grunt-exec
715 grunt.registerTask('build-playerglobal', ['exec:build_playerglobal']);
716 grunt.registerTask('playerglobal', ['exec:build_playerglobal']);
717 grunt.registerTask('playerglobal-single', ['exec:build_playerglobal_single']);
719 grunt.registerTask('base', ['exec:build_base_ts', 'test-quick']);
720 grunt.registerTask('swf', ['exec:build_swf_ts', 'test-quick']);
721 grunt.registerTask('flash', ['parallel:flash', 'test-quick']);
722 grunt.registerTask('avm1', ['parallel:avm1', 'test-quick']);
723 grunt.registerTask('player', ['exec:build_player_ts', 'test-quick']);
724 grunt.registerTask('shell', ['exec:build_shell_ts', 'test-quick']);
725 grunt.registerTask('tools', ['exec:build_tools_ts', 'test-quick']);
726 grunt.registerTask('avm2', ['exec:build_avm2_ts', 'copy_relooper', 'test-quick']);
727 grunt.registerTask('gfx', ['exec:build_gfx_base_ts', 'exec:build_gfx_ts', 'test-quick']);
728 grunt.registerTask('gfx-base', ['exec:build_gfx_base_ts']);
729 grunt.registerTask('perf', ['exec:perf']);
730 grunt.registerTask('gfx-test', ['exec:gfx-test']);
731 grunt.registerTask('build', "Builds all modules.", [
732 'ensure-build-folder',
733 'parallel:base',
734 'parallel:playerglobal',
735 'exec:build_tools_ts',
736 'exec:build_gfx_base_ts',
737 'parallel:tier2',
738 'copy_relooper',
739 'parallel:natives',
740 'exec:build_player_ts',
741 'exec:build_shell_ts',
742 'bundles',
743 'merge-modules'
745 grunt.registerTask('shu', [
746 'build',
747 'gate'
749 grunt.registerTask('travis', "Makes sure your local build will succeed on travis.", [
750 'exec:install_js_travis',
751 'exec:install_avmshell_travis',
752 // 'exec:versions_travis', AVMShell exits with 1 for some reason.
753 'build',
755 //'gate'
756 'exec:test_avm2_shumway',
757 'exec:test_avm2_acceptance',
758 // 'exec:test_avm2_pypy',
759 // 'exec:test_arch',
760 'exec:test_swf',
761 'exec:test_trace',
762 'exec:install_swfdec_travis',
763 'exec:test_trace_swfdec',
764 //'exec:test_avm2_ats',
765 //'exec:test_avm2_ats_parse',
766 'exec:test_unit',
767 'exec:test_mock'
769 grunt.registerTask('gate', "Run this before checking in any code.", [
770 'ensure-test-folder',
771 // 'tslint:all', // Annoyingly slow, and not very useful most of the time.
772 // 'closure', REDUX: Temporarily commented out.
773 'parallel:test',
774 'warn'
777 grunt.registerTask('warn', "Run this before checking in any code to report warnings.", [
778 'exec:warn_spell',
779 'exec:warn'
782 grunt.registerTask('perf-gate', "Run this before checking in any code to make sure you don't regress performance.", [
783 'exec:perf_avm2_acceptance'
785 // Quick sanity test that runs after a module is compiled.
786 grunt.registerTask('test-quick', [
787 'exec:test_unit'
789 // Runs all tests.
790 grunt.registerTask('test', [
791 'exec:test_avm2_shumway',
792 'exec:test_avm2_acceptance',
793 // 'exec:test_avm2_pypy',
794 // 'exec:test_arch',
795 'exec:test_swf',
796 'exec:test_trace',
797 // 'exec:test_trace_swfdec', // Takes too long.
798 'exec:test_avm2_ats',
799 'exec:test_avm2_ats_parse',
800 'exec:test_unit'
802 grunt.registerTask('mozcentralshu', [
803 'mozcentralbaseline',
804 'mozcentral',
805 'mozcentraldiff'
807 grunt.registerTask('mozcentralbaseline', function () {
808 if (!grunt.option('baseline')) {
809 throw new Error('--baseline parameter is not specified.');
811 var baseline = grunt.option('baseline');
812 var BASELINE_DIR = 'build/mozcentralbaseline';
813 grunt.file.delete(BASELINE_DIR, {force: true});
814 grunt.file.mkdir(BASELINE_DIR);
815 var done = this.async();
816 var gitClone = function () {
817 grunt.util.spawn({
818 cmd: 'git',
819 args: ['clone', '../..', '.'],
820 opts: { cwd: BASELINE_DIR, stdio: 'inherit'}}, function (error) {
821 if (error) {
822 done(error);
823 return;
825 gitCheckout();
828 var gitCheckout = function () {
829 grunt.util.spawn({
830 cmd: 'git',
831 args: ['checkout', baseline],
832 opts: { cwd: BASELINE_DIR, stdio: 'inherit'}}, function (error) {
833 if (error) {
834 done(error);
835 return;
837 bootstrap();
840 var bootstrap = function () {
841 grunt.util.spawn({
842 cmd: 'make',
843 args: ['link-utils', 'BASE=../..'],
844 opts: { cwd: BASELINE_DIR, stdio: 'inherit'}}, function (error) {
845 if (error) {
846 done(error);
847 return;
849 build();
852 var build = function () {
853 grunt.util.spawn({
854 grunt: true,
855 args: ['mozcentral'],
856 opts: { cwd: BASELINE_DIR, stdio: 'inherit'}}, function (error) {
857 if (error) {
858 done(error);
859 return;
861 done();
865 gitClone();
867 grunt.registerTask('mozcentraldiff', function () {
868 var BASELINE_BUILD_DIR = 'build/mozcentralbaseline/build/mozcentral';
869 if (!grunt.file.exists(BASELINE_BUILD_DIR)) {
870 throw new Error('mozcentralbaseline was not run.');
872 var NON_DELTA_BINARIES = [
873 'browser/extensions/shumway/content/libs/builtin.abc',
874 'browser/extensions/shumway/content/playerglobal/playerglobal.abcs'
876 var MOZCENTRAL_DIR = 'build/mozcentral';
877 var DIFF_DIR = 'build/mozcentraldiff';
878 grunt.file.delete(DIFF_DIR, {force: true});
879 grunt.file.mkdir(DIFF_DIR);
880 var done = this.async();
881 var rsync = function () {
882 grunt.util.spawn({
883 cmd: 'rsync',
884 args: ['-r'].concat(grunt.file.expand(BASELINE_BUILD_DIR + '/*'), [DIFF_DIR]),
885 opts: { stdio: 'inherit' }}, function (error) {
886 if (error) {
887 done(error);
888 return;
890 fixNonDelta(0);
893 // HACK to avoid 'delta' for 'GIT binary patch'
894 var fixNonDelta = function (index) {
895 if (index >= NON_DELTA_BINARIES.length) {
896 gitCommit();
897 return;
899 var nonDelta = NON_DELTA_BINARIES[index];
900 grunt.util.spawn({
901 cmd: 'diff',
902 args: [DIFF_DIR + '/' + nonDelta, MOZCENTRAL_DIR + '/' + nonDelta]
903 }, function (error, result, code) {
904 if (code === 2) {
905 // ... we need to truncate the file
906 grunt.file.write(DIFF_DIR + '/' + nonDelta, '');
907 } else if (error) {
908 console.log(code);
909 done(error);
910 return;
912 fixNonDelta(index + 1);
915 var gitCommit = function () {
916 grunt.util.spawn({
917 cmd: 'git',
918 args: ['init'],
919 opts: { cwd: DIFF_DIR, stdio: 'inherit'}}, function (error) {
920 if (error) {
921 done(error);
922 return;
924 grunt.util.spawn({
925 cmd: 'git',
926 args: ['add', '*'],
927 opts: { cwd: DIFF_DIR, stdio: 'inherit'}}, function (error) {
928 if (error) {
929 done(error);
930 return;
932 grunt.util.spawn({
933 cmd: 'git',
934 args: ['commit', '--message=baseline'],
935 opts: { cwd: DIFF_DIR, stdio: 'inherit'}}, function (error) {
936 if (error) {
937 done(error);
938 return;
940 refresh();
945 var refresh = function () {
946 grunt.util.spawn({
947 cmd: 'rsync',
948 args: ['-rc', '--delete'].concat(grunt.file.expand(MOZCENTRAL_DIR + '/*'), [DIFF_DIR]),
949 opts: { stdio: 'inherit'}}, function (error) {
950 if (error) {
951 done(error);
952 return;
954 gitDiff();
957 var gitDiff = function () {
958 grunt.util.spawn({
959 cmd: 'git',
960 args: ['add', '--all'],
961 opts: { cwd: DIFF_DIR, stdio: 'inherit'}}, function (error) {
962 if (error) {
963 done(error);
964 return;
966 var diffOutput = require('fs').openSync('build/mozcentral.diff', 'w');
967 grunt.util.spawn({
968 cmd: 'git',
969 args: ['diff', '--binary', '--cached', '--unified=8'],
970 opts: { cwd: DIFF_DIR, stdio: [null, diffOutput, null]}}, function (error, result, code) {
971 if (error) {
972 done(error);
973 return;
975 done();
980 rsync();
982 grunt.registerTask('generate-version', function () {
983 function generateFiles() {
984 console.log('Generating version files for ' + version + ' (' + sha + ')');
985 grunt.file.write(outputDir + '/version.json',
986 JSON.stringify({version: version, sha: sha}));
987 grunt.file.write(outputDir + '/version.txt', version + '\n' + sha + '\n');
988 grunt.file.write(outputDir + '/version.ts',
989 'module Shumway {\n export var version = \'' + version + '\';\n' +
990 ' export var build = \'' + sha + '\';\n}\n');
991 grunt.file.write(outputDir + '/version.js',
992 'var Shumway;\n(function (Shumway) {\n' +
993 ' Shumway.version = \'' + version + '\';\n' +
994 ' Shumway.build = \'' + sha + '\';\n' +
995 '})(Shumway || (Shumway = {}));\n');
998 function getDefaultVersion() {
999 var d = new Date();
1000 return d.getFullYear() * 100000000 + (d.getMonth() + 1) * 1000000 +
1001 d.getDate() * 10000 + d.getHours() * 100 + d.getMinutes()
1004 var version = getDefaultVersion(), sha = 'unknown';
1006 var outputDir = 'build/version';
1007 grunt.file.mkdir(outputDir);
1009 var done = this.async();
1010 grunt.util.spawn({
1011 cmd: 'git',
1012 args: ['log', '--format=oneline', VERSION_BASELINE + '..']
1013 }, function (error, result, code) {
1014 if (code) {
1015 generateFiles();
1016 done('Error code ' + code + ': ' + error);
1017 return;
1019 version = VERSION_BASE + (String(result).split(/\n/g).length);
1020 grunt.util.spawn({
1021 cmd: 'git',
1022 args: ['log', '--format=%h', '-n', '1']
1023 }, function (error, result, code) {
1024 if (code) {
1025 generateFiles();
1026 done('Error code ' + code + ': ' + error);
1027 return;
1029 sha = String(result);
1030 generateFiles();
1031 done();
1035 grunt.registerTask('shuobject-package', function () {
1036 var outputDir = 'build/shuobject';
1037 grunt.file.mkdir(outputDir);
1038 var path = require('path');
1040 grunt.file.copy('build/libs/builtin.abc', outputDir + '/build/libs/builtin.abc');
1041 grunt.file.copy('build/playerglobal/playerglobal.abcs', outputDir + '/build/playerglobal/playerglobal.abcs');
1042 grunt.file.copy('build/playerglobal/playerglobal.json', outputDir + '/build/playerglobal/playerglobal.json');
1043 grunt.file.copy('build/libs/relooper.js', outputDir + '/build/libs/relooper.js');
1044 grunt.file.expand('build/bundles-cc/*.js').forEach(function (file) { // TODO closure bundles
1045 grunt.file.copy(file, outputDir + '/build/bundles/' + path.basename(file));
1047 grunt.file.expand('web/iframe/*').forEach(function (file) {
1048 grunt.file.copy(file, outputDir + '/iframe/' + path.basename(file));
1050 grunt.file.copy('extension/shuobject/shuobject.js', outputDir + '/shuobject.js');
1051 grunt.file.expand('extension/shuobject/examples/*').forEach(function (file) {
1052 grunt.file.copy(file, outputDir + '/examples/' + path.basename(file));
1054 grunt.file.copy('web/demo.swf', outputDir + '/examples/demo.swf');
1055 grunt.file.copy('examples/external/externalinterface/avm2.swf', outputDir + '/examples/external_interface.swf');
1057 grunt.file.copy('build/version/version.txt', outputDir + '/version.txt');
1058 grunt.file.copy('LICENSE', outputDir + '/LICENSE');
1059 grunt.file.copy('LICENSE-OFL.txt', outputDir + '/LICENSE-OFL.txt');
1060 grunt.file.copy('README-LICENSE.txt', outputDir + '/README-LICENSE.txt');
1063 function copyFilesUsingPattern(src, dest, callback) {
1064 var path = require('path');
1065 grunt.file.expand(src).forEach(function (file) {
1066 var p = path.join(dest, path.basename(file));
1067 grunt.file.copy(file, p);
1068 if (callback) {
1069 callback(p);
1074 grunt.registerTask('dist-package', function() {
1075 var done = this.async();
1076 var outputDir = 'build/dist';
1077 var repoURL = 'https://github.com/mozilla/shumway-dist';
1079 var path = require('path');
1080 var fs = require('fs');
1081 var versionJSON = JSON.parse(fs.readFileSync('build/version/version.json'));
1083 function prepareFiles(done) {
1084 grunt.file.copy('build/libs/builtin.abc', outputDir + '/build/libs/builtin.abc');
1085 grunt.file.copy('build/playerglobal/playerglobal.abcs', outputDir + '/build/playerglobal/playerglobal.abcs');
1086 grunt.file.copy('build/playerglobal/playerglobal.json', outputDir + '/build/playerglobal/playerglobal.json');
1087 grunt.file.copy('build/libs/relooper.js', outputDir + '/build/libs/relooper.js');
1088 copyFilesUsingPattern('build/bundles-cc/*.js', outputDir + '/build/bundles');
1090 // shuobject packaging
1091 copyFilesUsingPattern('web/iframe/*', outputDir + '/iframe');
1092 grunt.file.copy('extension/shuobject/shuobject.js', outputDir + '/shuobject.js');
1093 grunt.file.copy('src/compatibility.js', outputDir + '/src/compatibility.js');
1095 // shell packaging
1096 grunt.file.copy('build/ts/shell.js', outputDir + '/build/ts/shell.js');
1097 fs.writeFileSync(outputDir + '/build/ts/shell.conf', 'dist');
1098 grunt.file.copy('src/shell/shell-node.js', outputDir + '/src/shell/shell-node.js');
1100 var waitFor = 1;
1101 copyFilesUsingPattern('src/shell/runners/run-*', outputDir + '/bin', function (dest) {
1102 waitFor++;
1103 grunt.util.spawn({cmd: 'chmod', args: ['+x', dest]}, function () {
1104 waitFor--;
1105 if (waitFor === 0) {
1106 done();
1111 // manifests
1112 var packageJSON = {
1113 "name": "shumway-dist",
1114 "version": versionJSON.version,
1115 "description": "Generic build of Mozilla's Shumway library.",
1116 "keywords": [
1117 "Mozilla",
1118 "Shumway"
1120 "homepage": "http://mozilla.github.io/shumway/",
1121 "bugs": "https://github.com/mozilla/shumway/issues",
1122 "license": "Apache-2.0",
1123 "repository": {
1124 "type": "git",
1125 "url": "https://github.com/mozilla/shumway-dist"
1128 fs.writeFileSync(outputDir + '/package.json', JSON.stringify(packageJSON, null, 2));
1129 var bowerJSON = {
1130 "name": "shumway-dist",
1131 "version": versionJSON.version,
1132 "main": [
1133 "shuobject.js"
1135 "ignore": [],
1136 "keywords": [
1137 "Mozilla",
1138 "Shumway"
1141 fs.writeFileSync(outputDir + '/bower.json', JSON.stringify(bowerJSON, null, 2));
1143 grunt.file.copy('build/version/version.txt', outputDir + '/version.txt');
1144 grunt.file.copy('LICENSE', outputDir + '/LICENSE');
1145 grunt.file.copy('utils/dist/README.md', outputDir + '/README.md');
1147 if (--waitFor === 0) {
1148 done();
1152 function addCommitMessages(done) {
1153 var message = 'Shumway version ' + versionJSON.version;
1154 var tag = 'v' + versionJSON.version;
1155 grunt.util.spawn({cmd: 'git', args: ['add', '--all'], opts: {cwd: outputDir}}, function (error) {
1156 grunt.util.spawn({cmd: 'git', args: ['commit', '-am', message], opts: {cwd: outputDir}}, function () {
1157 grunt.util.spawn({cmd: 'git', args: ['tag', '-a', tag, '-m', message], opts: {cwd: outputDir}}, function () {
1158 done();
1164 grunt.file.delete(outputDir);
1165 grunt.file.mkdir(outputDir);
1167 grunt.util.spawn({cmd: 'git', args: ['clone', '--depth', '1', repoURL, outputDir]}, function () {
1168 prepareFiles(function () {
1169 addCommitMessages(function () {
1170 console.info();
1171 console.info('Done. Push with');
1172 console.info(' cd ' + outputDir + '; git push --tags ' + repoURL + ' master');
1173 console.info();
1175 done();
1181 grunt.registerTask('clean', function () {
1182 var filesToRemove = [
1183 'build', // Deletes entire 'build' folder!
1184 'test/tmp/',
1185 'test/*.log',
1186 'test/avm2/*.tmp'
1188 filesToRemove.forEach(function (files) {
1189 grunt.file.expand(files).forEach(function (file) {
1190 grunt.file.delete(file);
1195 grunt.registerTask('firefox', ['build', 'closure-bundles', 'exec:build_extension']);
1196 grunt.registerTask('mozcentral', ['build', 'closure-bundles', 'exec:build_mozcentral']);
1197 grunt.registerTask('web', ['build', 'closure-bundles', 'exec:build_extension', 'shell-package', 'shuobject-package', 'exec:build_web']);
1198 grunt.registerTask('dist', ['build', 'closure-bundles', 'dist-package']);