Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

executable file 282 lines (255 sloc) 8.232 kb
#!/usr/bin/env node
var path = require('path'),
fs = require('fs'),
winston = require('winston'),
util = require('util'),
forever = require('./../lib/forever');
var action, accepts = [
'config',
'cleanlogs',
'clear',
'columns',
'list',
'logs',
'service-install',
'service-add',
'service-start',
'service-stop',
'service-restart',
'start',
'stop',
'stopall',
'set',
'restart'
];
if (accepts.indexOf(process.argv[2]) !== -1) {
action = process.argv.splice(2, 1)[0];
}
var argv = require('optimist').boolean(['v', 'verbose', 'a', 'append', 's', 'silent', 'w', 'watch', 'plain']).argv;
var help = [
'usage: forever [action] [options] SCRIPT [script-options]',
'',
'Monitors the script specified in the current process or as a daemon',
'',
'actions:',
' start Start SCRIPT as a daemon',
' stop Stop the daemon SCRIPT',
' stopall Stop all running forever scripts',
' restart Restart the daemon SCRIPT',
' list List all running forever scripts',
' config Lists all forever user configuration',
' set <key> <val> Sets the specified forever config <key>',
' clear <key> Clears the specified forever config <key>',
' logs Lists log files for all forever processes',
' logs <script|index> Tails the logs for <script|index>',
' columns add <col> Adds the specified column to the output in `forever list`',
' columns rm <col> Removed the specified column from the output in `forever list`',
' columns set <cols> Set all columns for the output in `forever list`',
' cleanlogs [CAREFUL] Deletes all historical forever log files',
'',
'options:',
' -m MAX Only run the specified script MAX times',
' -l LOGFILE Logs the forever output to LOGFILE',
' -o OUTFILE Logs stdout from child script to OUTFILE',
' -e ERRFILE Logs stderr from child script to ERRFILE',
' -p PATH Base path for all forever related files (pid files, etc.)',
' -c COMMAND COMMAND to execute (defaults to node)',
' -a, --append Append logs',
' --pidfile The pid file',
' --sourceDir The source directory for which SCRIPT is relative to',
' --minUptime Minimum uptime (millis) for a script to not be considered "spinning"',
' --spinSleepTime Time to wait (millis) between launches of a spinning script.',
' --plain Disable command line colors',
' -d, --debug Forces forever to log debug output',
' -v, --verbose Turns on the verbose messages from Forever',
' -s, --silent Run the child script silencing stdout and stderr',
' -w, --watch Watch for file changes',
' -h, --help You\'re staring at it',
'',
'[Long Running Process]',
' The forever process will continue to run outputting log messages to the console.',
' ex. forever -o out.log -e err.log my-script.js',
'',
'[Daemon]',
' The forever process will run as a daemon which will make the target process start',
' in the background. This is extremely useful for remote starting simple node.js scripts',
' without using nohup. It is recommended to run start with -o -l, & -e.',
' ex. forever start -l forever.log -o out.log -e err.log my-daemon.js',
' forever stop my-daemon.js',
''
].join('\n');
function isSimpleAction() {
return [
'config',
'list',
'logs',
'stopall',
'cleanlogs',
'service-install',
'service-start',
'service-stop',
'service-restart'
].indexOf(action) !== -1;
}
//
// Show help prompt if requested or if the
// incorrect usage options are supplied
//
if (argv.h || argv.help || (argv._.length === 0 && !isSimpleAction())
&& (!argv.c && !argv.command)) {
return util.puts(help);
}
var mappings = {
'c': 'command',
'e': 'errFile',
'l': 'logFile',
'a': 'appendLog',
'append': 'appendLog',
'm': 'max',
'o': 'outFile',
'p': 'path',
'pidfile': 'pidFile',
's': 'silent',
'silent': 'silent',
'sourceDir': 'sourceDir',
'minUptime': 'minUptime',
'spinSleepTime': 'spinSleepTime',
'plain': 'plain',
'v': 'verbose',
'verbose': 'verbose',
'w': 'watch',
'watch': 'watch',
'd': 'debug',
'debug': 'debug'
};
//
// If we are passed more than one non-hyphenated
// options, only use the first one. Assume the
// rest are pass-through for the child process
//
var file = argv._[0], options = {};
if (file) {
//
// Setup pass-thru options for child-process
//
options.options = process.argv.splice(process.argv.indexOf(file)).splice(1);
}
else if (argv.c || argv.command) {
options.options = process.argv.splice(process.argv.indexOf(argv.c || argv.command) + 1);
}
//
// Now that we've removed the target script options
// reparse the options and configure the forever settings
//
argv = require('optimist')(process.argv).boolean(['v', 'verbose', 'a', 'append', 's', 'silent', 'watch', 'w', 'plain']).argv;
Object.keys(argv).forEach(function (key) {
if (mappings[key] && argv[key]) {
options[mappings[key]] = argv[key];
}
});
if (typeof options['max'] === 'undefined') {
//
// If max isn't specified set it to run forever
//
options.forever = true;
}
if (typeof options['minUptime'] !== 'undefined') {
options['minUptime'] = parseFloat(options['minUptime']);
}
if (typeof options['spinSleepTime'] !== 'undefined') {
options['spinSleepTime'] = parseFloat(options['spinSleepTime']);
}
if (!options.sourceDir) {
//
// Set the sourceDir of the options for graceful
// restarting outside of the main directory
//
options.sourceDir = file && file[0] !== '/' ? process.cwd() : '/';
}
var uid = forever.randomString(24);
options.uid = uid;
options.pidFile = options.pidFile || uid + '.pid';
options.logFile = argv.l || uid + '.log';
//
// Check for existing global config and set each
// key appropriately if it exists.
//
['append', 'silent', 'verbose', 'watch', 'plain'].forEach(function (key) {
var target = mappings[key],
value = forever.config.get(key);
if (value) {
options[target] = options[target] || value === 'true';
}
});
//
// If options.plain is false, set colors.mode = 'none' to avoid colorful
// output (see https://github.com/indexzero/forever/issues/112 ).
// Modifying colors.mode turns off output coloring for all node modules
// which use colors because of node.js require caching.
//
if (options.plain) {
require('colors').mode = 'none';
}
//
// Pass the source dir to spawn
//
options.spawnWith = {
cwd: options.sourceDir
};
//
// Configure winston for forever based on the CLI options
//
if (options.verbose) {
forever.log.transports.console.level = 'silly';
}
//
// Setup configurations for forever
//
var config = {
root: argv.p
};
//
// Only call `forever.load()` if the root path is different than
// the default root exposed by forever.
//
if ((config.root && config.root !== forever.root)) {
forever.log.silly('Loading forever with config: ', config);
forever.load(config);
forever.log.silly('Loaded forever successfully.');
}
//
// If there is an uncaught exception then log
// it to the default `forever._debug`.
//
process.on('uncaughtException', function (err) {
forever._debug();
forever.log.error('uncaughtException');
forever.log.error(err.message);
forever.log.error(err.stack);
});
//
// If we should debug this forever process then
// configure it to do so.
//
if (argv.d || argv.debug) {
forever.log.warn('Forever debugging enabled');
forever._debug();
}
if (action === 'set') {
//
// If this is a set action then get the first
// value from the options and continue.
//
options = options.options[0];
}
else if (action === 'columns') {
//
// Otherwise if this is a `forever columns`
// operation then update the action, options,
// and file then continue.
//
action = [action, file];
options = options.options;
file = null;
}
forever.cli.exec(action, file, options);
Jump to Line
Something went wrong with that request. Please try again.