UNPKG

automaton

Version:
129 lines (108 loc) 3.99 kB
'use strict'; var glob = require('glob'); var grunt; // attempt to require grunt (first local, then global) try { grunt = require(process.cwd() + '/node_modules/grunt/lib/grunt'); } catch (e) { try { grunt = require('grunt'); } catch (e) { process.send({ msg: 'error', data: 'Unable to find grunt, please install it locally or globally' }); process.exit(1); } } var npmTasks; var keepAliveTimeout = Number(process.argv[2]); var keepAliveTimeoutId; var exit = process.exit; var running = false; // function to reset the keep alive timeout // once a keep alive message from the parent is received function resetKeepAlive() { if (keepAliveTimeoutId) { clearTimeout(keepAliveTimeoutId); } keepAliveTimeoutId = setTimeout(function () { exit.call(process, 1); }, keepAliveTimeout); } // do some monkey patching because grunt calls process.exit() // as long as nodejs allows to monkey patch process.exit, the code bellow is valid // otherwise we would need to monkey patch grunt.fail in order to prevent calls to process.exit() process.stdout.write = function (str) { process.send({ msg: 'log', data: str }); }; process.exit = function (code) { if (code && running) { process.send({ msg: 'error', data: 'Failed to run grunt task.' }); } exit.call(process); }; process.on('uncaughtException', function (err) { if (!running) { process.send({ msg: 'error', data: err.message }); process.exit(1); } throw err; }); // auto-load npm tasks npmTasks = glob.sync('./grunt-*', { cwd: 'node_modules', mark : true }); npmTasks.forEach(function (npmTask) { if (/[\/\\]$/.test(npmTask)) { grunt.loadNpmTasks(npmTask.slice(2, -1)); } }); // auto-load local tasks grunt.loadTasks('./tasks'); // handle parent messages process.on('message', function (data) { // we need to handle the message in the next tick // this is needed because if the code bellow throws an error // the message wasn't being removed from the stack, causing it to be processed again // this sounds like a node bug process.nextTick(function () { // run message arrived? if (data.msg === 'run') { if (running) { return; } var task = data.task; var initConfig = {}; var gruntConfig = task.config || {}; var taskDef; // prepare the config task.opts = task.opts || {}; gruntConfig.config = gruntConfig.gruntfile = __dirname + '/gruntfile'; gruntConfig.base = gruntConfig.base || process.cwd(); if (typeof gruntConfig.tasks === 'string') { // attempt to fix bad usage of tasks option gruntConfig.tasks = [gruntConfig.tasks]; } // force grunt to initialize and load tasks specified in the "tasks" config grunt.option.init(gruntConfig); grunt.task.init([]); // check if the task is loaded taskDef = grunt.task._tasks[task.name]; if (!taskDef) { return process.send({ msg: 'error', data: 'Task "' + task.name + '" not loaded, either install it or specify its directory in the "tasks" grunt config' }); } // set task options in the init config initConfig[task.name] = taskDef.multi ? { automaton: task.opts } : task.opts; // run the task using grunt running = true; grunt.initConfig(initConfig); grunt.tasks([task.name], gruntConfig, function () { running = false; process.send({ msg: 'end' }); }); // keep alive message arrive? } else if (data.msg === 'keep-alive') { resetKeepAlive(); } }); }); // inform that the worker is ready! process.nextTick(function () { resetKeepAlive(); process.send({ msg: 'init' }); });