Skip to content

Commit

Permalink
Merge 683a7a1 into 88a07d5
Browse files Browse the repository at this point in the history
  • Loading branch information
pstadler committed Nov 21, 2015
2 parents 88a07d5 + 683a7a1 commit 0d5981f
Show file tree
Hide file tree
Showing 31 changed files with 1,646 additions and 145 deletions.
10 changes: 10 additions & 0 deletions .editorconfig
@@ -0,0 +1,10 @@
root = true

[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
trim_trailing_whitespace = true
insert_final_newline = true
max_line_length = 100
1 change: 1 addition & 0 deletions .eslintignore
@@ -0,0 +1 @@
coverage/
1 change: 1 addition & 0 deletions .eslintrc
@@ -1,5 +1,6 @@
env:
node: true
mocha: true

rules:
no-undef: 2
Expand Down
3 changes: 2 additions & 1 deletion .gitignore
Expand Up @@ -2,4 +2,5 @@
._*
*.sublime-project
*.sublime-workspace
node_modules/
node_modules/
coverage/
10 changes: 10 additions & 0 deletions .travis.yml
@@ -0,0 +1,10 @@
env:
global:
- secure: DpxKNILEe3Wq3GyR33LUnlFjk7YC72R32AzfEQ8HwKWgu0CGccbjWemY86Z1RT4z13iYv6vWQWPXZhu8hrkL4irHm3oUleXQBKmdehRnrH66UJg6kKdmAmBjbTSjHIhfpHF0Asj+y+1CX7cNAbMPV2UB4DIJ3CdhS4RiNdmBD9vrF+FvYr0Pifd8+RYZwIrsP6gZDdKQNRqXaJg89gQ9v8Mmz95PZGd+5rGgnWQf7LCAvminLYQMcQfn6f/4GCywvEXz62lCWCQ1FV7TsKcPpKTJdq08I/O56cA6lJe6EuI5EtWRYufVhcs75bFgzvmBZ3+bbWl2lihWIfzsIVlYa9aAIDYwdHetfUBXBrXsf9BtBhaGL48fIqHPm2Z+H+4Bped+e7jR+5GSIQVQeSrPhHn5TJ46yr9bJoWi5S1K+FZXnNROX2vADvZaUpRfbsHFrdBurbHtWUqbu3GOtZEGnRf2FzZlF4KLMv403nZpVA/250mHI4S11gazKBkWBzpL8XePkMU+lCzJerOpCfPjfVmCUDlnZfRUtihbiYrMePZjqGcNJ6iRBxRhjflDnZCeqea3hleHoDC4MqAWaPEI2U5/+FMzrLMsILpxJz8CSs+huBkOLR0OTMtKpAFGKQC72NPSifpMLQQHaJZ1WDdC71ERBYLWcAtTH+IwCc+DE7w=
- secure: i+a2mN2VhA1aOjrVzzMYDFqI4pFjELXdLs3S2Mx1JAyYWVQ/YNTKx4PExxN4I7JSdOo/wUNFKvWAHmnlkG6yzqVW+pLVi/XvUUL3B7WMGMgl5LbVmt/4wsrElv2NjtErRMwyCxWbkzYoegIm4hLuoC6/D/Hst/yGPMfsgvxMdNEVj5cOCS7P8F9U6KAoQ5XRJH1pvfrSbAiQ4/ZV0SqBj50WQE/S+szlJgVAcl+2sn/TdegZi8N5HuvNvasrgFSHSkxNssaivQIDLEW81wOv8euRGyZxtysJFbxfriuNKdKipwoexY2+PMHRRMgNdQjYwNLpdRmSSBtzMxQc6MJbIkragNwY9RnM1JyJstcIubt0OaKqvHWCLx3n5xVqbvDhn+ispFG4/Bd58R7XhHyHuhfOrrea3KF7OBOJfGBMG8w5rgjCRMbnTUyFkKJW3h/UN6MjIWPH+Tl2QdJcDhDRKwzoZcNpGiGmydIubaz9BCNni5im+1Da0MEhSaXzjl1aw+SaQaC3Ls7HcbAjAhrpZ1wt2cos2sLJ/yk+AQ3dnOkplhgxfBsbW+l+km0gR105/R76qbmSc6/ByQnG/DSfD5TZkmR1Ig8PcQ9AX9YxKBdbvEO5WLBwySy+6TUmEzktJY7nxmkK10HKPu9Rx9jE6bmVnVXtVD+AIi15a4GM0co=
sudo: false
language: node_js
node_js:
- "0.12"
script: npm test
after_script: npm run coveralls
12 changes: 9 additions & 3 deletions README.md
@@ -1,4 +1,7 @@
# Flightplan ✈ [![NPM version][npm-version-image]][npm-url] [![NPM downloads][npm-downloads-image]][npm-url] [![Dependency Status][dependencies-image]][dependencies-url] [![MIT License][license-image]][license-url]
# Flightplan

[![NPM version][npm-version-image]][npm-url] [![Build Status][build-status-image]][build-status-url]
[![Build Status][coverage-image]][coverage-url] [![NPM downloads][npm-downloads-image]][npm-url] [![Dependency Status][dependencies-image]][dependencies-url]

Run sequences of shell commands against local and remote hosts.

Expand Down Expand Up @@ -673,5 +676,8 @@ transport.debug('Copying files to remote hosts');
[dependencies-url]: https://david-dm.org/pstadler/flightplan
[dependencies-image]: https://david-dm.org/pstadler/flightplan.svg?style=flat-square

[license-url]: https://github.com/pstadler/flightplan/blob/master/LICENSE
[license-image]: https://img.shields.io/npm/l/flightplan.svg?style=flat-square
[build-status-url]: https://travis-ci.org/pstadler/flightplan
[build-status-image]: https://img.shields.io/travis/pstadler/flightplan/master.svg?style=flat-square

[coverage-url]: https://coveralls.io/github/pstadler/flightplan?branch=master
[coverage-image]: https://img.shields.io/coveralls/pstadler/flightplan/master.svg?style=flat-square
7 changes: 4 additions & 3 deletions bin/fly.js
Expand Up @@ -25,7 +25,7 @@ var shortHands = {
't': ['--targets'],
'T': ['--tasks'],
'v': ['--version'],
'h': ['--help'],
'h': ['--help']
};

var options = nopt(knownOptions, shortHands, process.argv, 2);
Expand Down Expand Up @@ -53,7 +53,7 @@ if(options.version) {
process.exit(1);
}

var task = 'default';
var task;
var target = options.argv.remain.length ? options.argv.remain[0] : null;

if(target && target.indexOf(':') !== -1) {
Expand All @@ -76,6 +76,7 @@ cli.on('requireFail', function(name) {
});

var invoke = function(env) {

if(!env.configPath) {
process.stderr.write(format('Error: %s not found\n', (options.flightplan || 'flightplan.js')));
process.exit(1);
Expand Down Expand Up @@ -129,4 +130,4 @@ var invoke = function(env) {

cli.launch({
configPath: options.flightplan
}, invoke);
}, invoke);
10 changes: 5 additions & 5 deletions lib/errors.js
Expand Up @@ -15,12 +15,12 @@ function InvalidTargetError(message) {
}
util.inherits(InvalidTargetError, BaseError);

function CommandExitedAbormallyError(message) {
CommandExitedAbormallyError.super_.call(this, message);
function CommandExitedAbnormallyError(message) {
CommandExitedAbnormallyError.super_.call(this, message);
Error.captureStackTrace(this, this.constructor);
this.name = this.constructor.name;
}
util.inherits(CommandExitedAbormallyError, BaseError);
util.inherits(CommandExitedAbnormallyError, BaseError);

function ConnectionFailedError(message) {
ConnectionFailedError.super_.call(this, message);
Expand Down Expand Up @@ -53,9 +53,9 @@ util.inherits(ProcessInterruptedError, BaseError);
module.exports = {
BaseError: BaseError,
InvalidTargetError: InvalidTargetError,
CommandExitedAbormallyError: CommandExitedAbormallyError,
CommandExitedAbnormallyError: CommandExitedAbnormallyError,
ConnectionFailedError: ConnectionFailedError,
InvalidArgumentError: InvalidArgumentError,
AbortedError: AbortedError,
ProcessInterruptedError: ProcessInterruptedError
};
};
1 change: 1 addition & 0 deletions lib/flight/index.js
Expand Up @@ -5,6 +5,7 @@ var TYPE = Object.freeze({
LOCAL: 1,
REMOTE: 2
});

exports.TYPE = TYPE;

exports.run = function(type, fn, context) {
Expand Down
4 changes: 4 additions & 0 deletions lib/flight/local.js
Expand Up @@ -10,16 +10,20 @@ exports.run = function(fn, context) {
_context.remote = { host: 'localhost' };

var future = new Future();

var task = function() {
var transport = new Shell(_context);

new Fiber(function() {
fn(transport);
return future.return();
}).run();

return future;
};

var t = process.hrtime();

logger.info('Executing local task');

Future.wait(task());
Expand Down
79 changes: 46 additions & 33 deletions lib/flight/remote.js
Expand Up @@ -8,56 +8,69 @@ var Fiber = require('fibers')

var _connections = [];

exports.run = function(fn, context) {
var connect = function(_context) {
var future = new Future();
new Fiber(function() {
logger.info("Connecting to '" + _context.remote.host + "'");
try {
var connection = new SSH(_context);
_connections.push(connection);
} catch(e) {
if(!_context.remote.failsafe) {
throw new errors.ConnectionFailedError("Error connecting to '" +
_context.remote.host + "': " + e.message);
}
logger.warn("Safely failed connecting to '" + _context.remote.host +
"': " + e.message);
function connect(_context) {
var future = new Future();

new Fiber(function() {
logger.info("Connecting to '" + _context.remote.host + "'");

try {
var connection = new SSH(_context);
_connections.push(connection);
} catch(e) {
if(!_context.remote.failsafe) {
throw new errors.ConnectionFailedError("Error connecting to '" +
_context.remote.host + "': " + e.message);
}
return future.return();
}).run();
return future;
};

var execute = function(transport) {
var future = new Future();
new Fiber(function() {
var t = process.hrtime();
logger.info('Executing remote task on ' + transport.runtime.host);
fn(transport);
logger.info('Remote task on ' + transport.runtime.host +
' finished after ' + prettyTime(process.hrtime(t)));
return future.return();
}).run();
return future;
};

logger.warn("Safely failed connecting to '" +
_context.remote.host + "': " + e.message);
}

return future.return();
}).run();

return future;
}

function execute(transport, fn) {
var future = new Future();

new Fiber(function() {
var t = process.hrtime();

logger.info('Executing remote task on ' + transport.runtime.host);

fn(transport);

logger.info('Remote task on ' + transport.runtime.host +
' finished after ' + prettyTime(process.hrtime(t)));

return future.return();
}).run();

return future;
}

exports.run = function(fn, context) {
if(_connections.length === 0) {
Future.wait(context.hosts.map(function(host) {
var _context = extend({}, context);
_context.remote = host;

return connect(_context);
}));
}

Future.wait(_connections.map(function(connection) {
return execute(connection);
return execute(connection, fn);
}));
};

exports.disconnect = function() {
_connections.forEach(function(connection) {
connection.close();
});

_connections = [];
};
28 changes: 26 additions & 2 deletions lib/index.js
Expand Up @@ -12,6 +12,7 @@ var DEFAULT_TASK = 'default';

function _setupFlight(type, tasksOrFn, fn) {
var tasks;

if(typeof tasksOrFn === 'string') {
tasks = [tasksOrFn];
} else if(Array.isArray(tasksOrFn)) {
Expand All @@ -20,6 +21,7 @@ function _setupFlight(type, tasksOrFn, fn) {
tasks = [DEFAULT_TASK];
fn = tasksOrFn;
}

return { type: type, tasks: tasks, fn: fn };
}

Expand Down Expand Up @@ -120,6 +122,7 @@ function Flightplan() {
message = err.message;
}
logger.error(message);

process.exit(1);
});
}
Expand Down Expand Up @@ -282,7 +285,12 @@ function Flightplan() {
* @return {Object} this
*/
Flightplan.prototype.target = function(name, hosts, options) {
this._targets[name] = { hosts: hosts, options: options || {} };
if(!Array.isArray(hosts) && typeof hosts === 'object') {
hosts = extend({}, hosts); // dereference object
}

this._targets[name] = { hosts: hosts, options: extend({}, options) };

return this;
};

Expand All @@ -305,6 +313,7 @@ Flightplan.prototype.target = function(name, hosts, options) {
*/
Flightplan.prototype.local = function(tasksOrFn, fn) {
this._flights.push(_setupFlight(flight.TYPE.LOCAL, tasksOrFn, fn));

return this;
};

Expand All @@ -327,12 +336,18 @@ Flightplan.prototype.local = function(tasksOrFn, fn) {
*/
Flightplan.prototype.remote = function(tasksOrFn, fn) {
this._flights.push(_setupFlight(flight.TYPE.REMOTE, tasksOrFn, fn));

return this;
};

Flightplan.prototype.run = function(task, target, options) {
task = task || DEFAULT_TASK;
options = options || {};

if(!target) {
throw new errors.InvalidTargetError('No target specified');
}

if(options.color !== undefined) {
chalk.enabled = options.color;
}
Expand All @@ -349,10 +364,12 @@ Flightplan.prototype.run = function(task, target, options) {

if(flights.length === 0) {
logger.warn(format("There is no work to be done for task '%s'", task));

process.exit(1);
return; // for testing
}

var config = this._targets[target];
var config = extend({}, this._targets[target]);

var context = {
options: extend(config.options, options),
Expand All @@ -370,16 +387,22 @@ Flightplan.prototype.run = function(task, target, options) {
if(typeof config.hosts === 'function') {
var dynamicHosts = function() {
var future = new Future();

config.hosts(function(result) {
future.return(result);
});

return future;
};

logger.info('Running dynamic hosts configuration');

var result = dynamicHosts().wait();

if(result instanceof Error) {
self.abort(result);
}

config.hosts = result;
// FIXME: Debug flag is not set at this time
// logger.debug(format('Hosts are set to %s', config.hosts));
Expand All @@ -393,6 +416,7 @@ Flightplan.prototype.run = function(task, target, options) {
if(options.username) {
host.username = options.username;
}

return host;
});
}
Expand Down

0 comments on commit 0d5981f

Please sign in to comment.