Permalink
Browse files

initial commit of grunt plugin for forever task.

  • Loading branch information...
1 parent 5e3ebac commit cd9e42b3eef8bd805daf7f1cbc20be5d96eeab02 @bustardcelly committed Oct 10, 2012
Showing with 243 additions and 0 deletions.
  1. +3 −0 .gitignore
  2. +22 −0 LICENSE-MIT
  3. +2 −0 bin/grunt-forever
  4. +28 −0 grunt.js
  5. +46 −0 package.json
  6. +142 −0 tasks/forever-task.js
View
@@ -0,0 +1,3 @@
+.DS_Store
+node_modules
+*.sublime-*
View
@@ -0,0 +1,22 @@
+Copyright (c) 2012 Todd Anderson http://custardbelly.com/blog
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
View
@@ -0,0 +1,2 @@
+#!/usr/bin/env node
+require('grunt').npmTasks('grunt-forever').cli();
View
@@ -0,0 +1,28 @@
+module.exports = function(grunt) {
+ 'use strict';
+
+ // Project configuration.
+ grunt.initConfig({
+ lint: {
+ all: ['grunt.js', 'tasks/*.js']
+ },
+ jshint: {
+ options: {
+ curly: true,
+ eqeqeq: true,
+ immed: true,
+ newcap: true,
+ noarg: true,
+ sub: true,
+ undef: true,
+ boss: true,
+ eqnull: true,
+ node: true,
+ es5: true
+ }
+ }
+ });
+
+ grunt.loadTasks('tasks');
+ grunt.registerTask('default', 'lint');
+};
View
@@ -0,0 +1,46 @@
+{
+ "name": "grunt-forever",
+ "description": "Grunt task for starting and stopping an application as a daemon using forever",
+ "version": "0.1.0",
+ "homepage": "https://github.com/bustardcelly/grunt-forever",
+ "author": {
+ "name": "Todd Anderson",
+ "url": "http://custardbelly.com/blog"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/bustardcelly/grunt-forever.git"
+ },
+ "bugs": {
+ "url": "git://github.com/bustardcelly/grunt-forever/issues"
+ },
+ "licenses": [
+ {
+ "type": "MIT",
+ "url": "https://github.com/bustardcelly/grunt-forever/blob/master/LICENSE-MIT"
+ }
+ ],
+ "main": "grunt.js",
+ "engines": {
+ "node": "*"
+ },
+ "bin": {
+ "grunt-forever": "bin/grunt-forever"
+ },
+ "scripts": {},
+ "dependencies": {
+ "forever": ">=0.10.0"
+ },
+ "devDependencies": {
+ "grunt": "~0.3.16"
+ },
+ "keywords": [
+ "forever",
+ "forevergrunt",
+ "grunt",
+ "gruntplugin",
+ "plugins",
+ "daemon"
+ ],
+ "readme": "# grunt-forever."
+}
View
@@ -0,0 +1,142 @@
+var forever = require('forever'),
+ logFile = process.cwd() + '/forever.log',
+ commandMap = {
+ start: startForeverWithIndex,
+ stop: stopOnProcess,
+ restart: restartOnProcess
+ },
+ done, gruntRef;
+
+function log( message ) {
+ gruntRef.log.writeln( message );
+}
+
+function warn( message ) {
+ gruntRef.warn( message );
+}
+
+function error( message ) {
+ gruntRef.log.error( message ).error();
+}
+
+function prettyPrint( id, object ) {
+ log(id + ' : ' + JSON.stringify(object, null, 2));
+}
+
+function findProcessWithIndex( index, callback ) {
+ var i, process;
+ try {
+ forever.list(false, function(context, list) {
+ i = list ? list.length : 0;
+ while( --i > -1 ) {
+ process = list[i];
+ if( process.hasOwnProperty('file') &&
+ process.file === index ) {
+ break;
+ }
+ process = undefined;
+ }
+ callback.call(null, process);
+ });
+ }
+ catch( e ) {
+ error( 'Error in trying to find process ' + index + ' in forever. [REASON] :: ' + e.message );
+ callback.call(null, undefined);
+ }
+}
+
+function startForeverWithIndex( index ) {
+ log( 'Attempting to start ' + index + ' as daemon.');
+
+ done = this.async;
+ findProcessWithIndex( index, function(process) {
+ if( typeof process !== 'undefined' ) {
+ warn( index + ' is already running.');
+ log( forever.format(true, [process]) );
+ done();
+ }
+ else {
+ // 'forever start -o out.log -e err.log -a -m 3 index.js';
+ forever.startDaemon( index, {
+ logFile: logFile
+ });
+ log( 'Logs can be found at ' + logFile );
+ done();
+ }
+ });
+}
+
+function stopOnProcess( index ) {
+ log( 'Attempting to stop ' + index + '...' );
+
+ done = this.async();
+ findProcessWithIndex( index, function(process) {
+ if( typeof process !== 'undefined' ) {
+ log( forever.format(true,[process]) );
+
+ forever.stop( index )
+ .on('stop', function() {
+ done();
+ })
+ .on('error', function(message) {
+ error( 'Error stopping ' + index + '. [REASON] :: ' + message );
+ done(false);
+ });
+ }
+ else {
+ gruntRef.warn( index + ' not found in list of processes in forever.' );
+ done();
+ }
+ });
+}
+
+function restartOnProcess( index ) {
+ log( 'Attempting to restart ' + index + '...' );
+
+ var startRequest = (function(context, index) {
+ return function() {
+ startForeverWithIndex.call(context, index);
+ };
+ }(this, index));
+
+ done = this.async();
+ findProcessWithIndex( index, function(process) {
+ if( typeof process !== 'undefined' ) {
+ log( forever.format(true,[process]) );
+
+ forever.restart( index )
+ .on('error', function(message) {
+ error( 'Error restarting ' + index + '. [REASON] :: ' + message );
+ done(false);
+ });
+ done();
+ }
+ else {
+ log( index + ' not found in list of processes in forever. Starting new instance...' );
+ startRequest();
+ done();
+ }
+ });
+}
+
+module.exports = function( grunt ) {
+
+ gruntRef = grunt;
+ grunt.registerTask( 'forever', 'Starts node app as a daemon.', function() {
+
+ var index = grunt.config('forever.main') || 'index.js',
+ operation = this.args[0];
+
+ try {
+ if( commandMap.hasOwnProperty(operation) ) {
+ commandMap[operation].call( this, index );
+ }
+ else {
+ warn( 'Operation ' + operation + ' is not supported currently. Only forever:start, forever:stop or forever:restart.' );
+ }
+ }
+ catch( e ) {
+ error( 'Exception thrown in attempt to ' + operation + ' on ' + index + ': ' + e );
+ }
+ });
+};

0 comments on commit cd9e42b

Please sign in to comment.