masson
Version:
Module execution engine for cluster deployments.
259 lines (226 loc) • 6.31 kB
JavaScript
// Generated by CoffeeScript 1.7.1
var EventEmitter, Tree, crypto, flatten, load, util;
crypto = require('crypto');
util = require('util');
EventEmitter = require('events').EventEmitter;
load = require('./load');
flatten = require('./misc').flatten;
/*
Tree
====
Build a tree with all the actions to execute from a list of modules.
Action properties:
- `hidden` Visibility of the action name
- `name` Name of the action
- `module` Module where the action is defined
- `index` Position of the action inside the module
Example using a callback
tree = require './tree'
tree modules, (err, actions) ->
util.print actions
Example using the EventEmitter API:
tree.actions(modules, options)
.on 'module', (location) ->
util.print 'module', location
.on 'action', (action) ->
util.print 'action', action
.on 'end', (actions) ->
util.print actions
.on 'error', (err) ->
util.print err
*/
Tree = function(modules, options) {
return this;
};
util.inherits(Tree, EventEmitter);
/*
Build a run list for the given modules.
Options include:
- `modules` Only return this module and its dependencies
- `fast` Skip dependencies
- `all` Return the full list of actions, work with the `module` and `fast` options
*/
Tree.prototype.actions = function(modules, options, callback) {
var ev;
if (typeof options === 'function') {
callback = options;
options = {};
}
if (typeof options.modules === 'string') {
options.modules = [options.modules];
}
if (!Array.isArray(options.modules)) {
options.modules = [];
}
ev = new EventEmitter;
setImmediate((function(_this) {
return function() {
var action, actions, err, leaf, tree, _i, _j, _len, _len1, _ref;
if (!Array.isArray(modules)) {
modules = [modules];
}
modules = flatten(modules);
try {
tree = _this.load_tree(modules);
} catch (_error) {
err = _error;
ev.emit('error', err);
callback(err);
return;
}
if (options.modules.length) {
modules = tree.map(function(leaf) {
return leaf.module;
});
modules = options.modules.filter(function(module) {
return modules.indexOf(module) !== -1;
});
tree = _this.load_tree(modules);
if (options.fast) {
tree = tree.filter(function(leaf) {
if (options.modules.indexOf(leaf.module) !== -1) {
return true;
}
leaf.actions = leaf.actions.filter(function(action) {
return action.required;
});
return leaf.actions.length;
});
}
}
actions = [];
for (_i = 0, _len = tree.length; _i < _len; _i++) {
leaf = tree[_i];
ev.emit('module', leaf.module);
_ref = leaf.actions;
for (_j = 0, _len1 = _ref.length; _j < _len1; _j++) {
action = _ref[_j];
ev.emit('action', action);
actions.push(action);
}
}
ev.emit('end', actions);
if (callback) {
return callback(null, actions);
}
};
})(this));
return ev;
};
Tree.prototype.modules = function(modules, options, callback) {
var mods;
mods = [];
return this.actions(modules, options).on('module', function(module) {
return mods.push(module);
}).on('error', function(err) {
return callback(err);
}).on('end', function() {
return callback(null, mods);
});
};
/*
Return a array of object with the module name and its associated actions
*/
Tree.prototype.load_tree = function(modules) {
var build_tree, called, module, tree, _i, _len;
called = {};
tree = [];
build_tree = (function(_this) {
return function(module) {
var action, leaf, _i, _len, _ref;
if (called[module]) {
return;
}
called[module] = true;
leaf = {
module: module,
actions: []
};
_ref = _this.load_module(module);
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
action = _ref[_i];
if (typeof action === 'string') {
if (leaf.actions.length) {
tree.push(leaf);
}
leaf = {
module: module,
actions: []
};
build_tree(action);
} else {
leaf.actions.push(action);
}
}
return tree.push(leaf);
};
})(this);
for (_i = 0, _len = modules.length; _i < _len; _i++) {
module = modules[_i];
build_tree(module);
}
return tree;
};
/*
Load a module and return its actions.
Module actions when defining a string dependency may be prefixed with:
* "?": Load this module only if it is defined by the user in the run list.
* "!": Force this module to be loaded and executed, apply to "fast" mode.
*/
Tree.prototype.load_module = function(module) {
var actions, callback, i, meta, required, _, _i, _len, _ref;
if (this.cache == null) {
this.cache = {};
}
if (this.cache[module]) {
return this.cache[module];
}
required = false;
_ref = /([\!\?]?)(.*)/.exec(module), _ = _ref[0], meta = _ref[1], module = _ref[2];
switch (meta) {
case '?':
break;
case '!':
required = true;
}
actions = load(module);
if (!Array.isArray(actions)) {
actions = [actions];
}
for (i = _i = 0, _len = actions.length; _i < _len; i = ++_i) {
callback = actions[i];
if (typeof callback === 'string') {
continue;
}
if (typeof callback === 'function') {
callback = actions[i] = {
callback: callback
};
}
if (!callback.name) {
if (callback.hidden == null) {
callback.hidden = true;
}
}
if (callback.name == null) {
callback.name = "" + module + "/" + i;
}
if (callback.module == null) {
callback.module = module;
}
if (callback.index == null) {
callback.index = i;
}
if (callback.skip == null) {
callback.skip = false;
}
if (required) {
callback.required = true;
}
}
return this.cache[module] = actions;
};
module.exports = function(modules, options, callback) {
return (new Tree).actions(modules, options, callback);
};
module.exports.Tree = Tree;