UNPKG

mecano

Version:

Common functions for system deployment.

1,116 lines (1,100 loc) 32.7 kB
// Generated by CoffeeScript 1.11.1 var EventEmitter, array, called_deprecate_destination, called_deprecate_local_source, conditions, domain, each, merge, registry, string, todos_create, todos_reset, wrap, indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; called_deprecate_destination = false; called_deprecate_local_source = false; module.exports = function() { var _run_, afters, befores, call_callback, depth, domain_on_error, enrich_options, handle_multiple_call, headers, index_counter, j, jump_to_error, killed, len, normalize_options, obj, once, option, properties, proxy, ref, ref1, reg, run, stack, store, todos; if (arguments.length === 2) { obj = arguments[0]; obj.options = arguments[1]; } else if (arguments.length === 1) { obj = new EventEmitter; obj.options = arguments[0]; } else { obj = new EventEmitter; obj.options = {}; } if (obj.registry == null) { obj.registry = {}; } if (obj.propagated_options == null) { obj.propagated_options = []; } ref = module.exports.propagated_options; for (j = 0, len = ref.length; j < len; j++) { option = ref[j]; obj.propagated_options.push(option); } store = {}; properties = {}; stack = []; todos = todos_create(); befores = []; afters = []; depth = 0; headers = []; once = {}; killed = false; index_counter = 0; if (obj.options.domain === true) { obj.options.domain = domain.create(); } domain_on_error = function(err) { err.message = "Invalid State Error [" + err.message + "]"; return handle_multiple_call(err); }; if ((ref1 = obj.options.domain) != null) { ref1.on('error', domain_on_error); } proxy = new Proxy(obj, { has: function(target, name) { return (target[name] != null) || (target.registry.registered(proxy.type) != null) || (registry.registered(name) != null); }, get: function(target, name) { var get_proxy_builder; if (target[name] != null) { return target[name]; } if (name === 'domain' || name === '_events' || name === '_maxListeners') { return target[name]; } proxy.type = []; proxy.type.push(name); get_proxy_builder = function() { var builder; builder = function() { var args, l, len1, middleware, options, opts, ref2, ref3; middleware = ((ref2 = target.registry.get(proxy.type)) != null ? ref2.handler : void 0) || ((ref3 = registry.get(proxy.type)) != null ? ref3.handler : void 0); args = [].slice.call(arguments); options = normalize_options(args, proxy.type); proxy.type = []; for (l = 0, len1 = options.length; l < len1; l++) { opts = options[l]; todos.push(opts); } if (todos.length === options.length) { setImmediate(_run_); } return proxy; }; return new Proxy(builder, { get: function(target, name) { if (target[name] != null) { return target[name]; } proxy.type.push(name); return get_proxy_builder(); } }); }; return get_proxy_builder(); } }); normalize_options = function(_arguments, type, enrich) { var a, arg, callback, cloned_arg, empty, handler, i, k, l, len1, len2, len3, len4, m, middleware, n, o, options, opts, ref2, v; if (enrich == null) { enrich = true; } empty = false; if (Array.isArray(type)) { middleware = obj.registry.get(type) || registry.get(type); } if (middleware) { _arguments.unshift(middleware.handler); } handler = null; callback = null; options = []; for (l = 0, len1 = _arguments.length; l < len1; l++) { arg = _arguments[l]; if (typeof arg === 'function') { if (!handler) { handler = arg; } else if (!callback) { callback = arg; } else { throw Error("Invalid third function argument"); } } else if (Array.isArray(arg)) { if (arg.length === 0) { empty = true; } for (m = 0, len2 = arg.length; m < len2; m++) { a = arg[m]; if (type === 'call') { if (!(typeof a === 'object' && !Array.isArray(a) && a !== null)) { a = { handler: a }; } } else { if (!(typeof a === 'object' && !Array.isArray(a) && a !== null)) { a = { argument: a }; } } options.push(a); } } else { if (typeof arg !== 'object' && arg !== null) { arg = { argument: arg }; } if (options.length === 0) { cloned_arg = {}; for (k in arg) { v = arg[k]; cloned_arg[k] = v; } options.push(cloned_arg); } else { for (n = 0, len3 = options.length; n < len3; n++) { opts = options[n]; for (k in arg) { v = arg[k]; opts[k] = v; } } } } } if (options.length === 0 && empty) { return options; } if (options.length === 0) { options.push({}); } if (options.length && options.filter(function(opts) { return !opts.handler; }).length === 0) { callback = handler; handler = null; } for (i = o = 0, len4 = options.length; o < len4; i = ++o) { opts = options[i]; options[i] = {}; if (Array.isArray(type)) { merge(options[i], middleware); } for (k in opts) { v = opts[k]; options[i][k] = v; } opts = options[i]; if (type === 'call' && !opts.handler) { opts.handler = opts.argument; opts.argument = void 0; } if (opts.destination) { if (!called_deprecate_destination) { console.log('Use options target instead of destination'); } called_deprecate_destination = true; if (opts.target == null) { opts.target = opts.destination; } } if (opts.local_source) { if (!called_deprecate_local_source) { console.log('Use options local instead of local_source'); } called_deprecate_local_source = true; if (opts.local == null) { opts.local = opts.local_source; } } if (type) { opts.type = type; } if (!Array.isArray(opts.type)) { opts.type = [opts.type]; } if (handler) { if (opts.handler == null) { opts.handler = handler; } } if (callback) { if (opts.callback == null) { opts.callback = callback; } } if (enrich && ((ref2 = opts.callback) != null ? ref2.length : void 0) > 2) { opts.user_args = true; } if (enrich && store) { if (opts.store == null) { opts.store = store; } } if (opts.once === true) { opts.once = ['handler']; } if (opts.once === false) { delete opts.once; } if (Array.isArray(opts.once)) { opts.once = opts.once.sort(); } if (opts.wait == null) { opts.wait = 3000; } if (!(typeof opts.wait === 'number' && opts.wait >= 0)) { jump_to_error(Error("Invalid options wait, got " + (JSON.stringify(opts.wait)))); } } return options; }; enrich_options = function(user_options) { var _logs, global_options, k, log_disabled, options, parent_options, ref2, ref3, v; user_options.enriched = true; global_options = obj.options; parent_options = todos.options; options = {}; for (k in user_options) { v = user_options[k]; options[k] = user_options[k]; } for (k in parent_options) { v = parent_options[k]; if (options[k] === void 0 && indexOf.call(obj.propagated_options, k) >= 0) { options[k] = v; } } for (k in global_options) { v = global_options[k]; if (options[k] === void 0) { options[k] = v; } } if (!((ref2 = options.log) != null ? ref2.dont : void 0)) { if (options.log && !Array.isArray(options.log)) { _logs = [options.log]; } else if (!options.log) { _logs = []; } } if (options.log === false) { log_disabled = true; } if (log_disabled) { options.log = []; } if ((ref3 = options.log) != null ? ref3._mecano_ : void 0) { options.log = []; } if (options.log == null) { options.log = []; } if (!Array.isArray(options.log)) { options.log = [options.log]; } _logs = options.log; if (options.debug) { _logs.push(function(log) { var msg, ref4, ref5; if ((ref4 = log.type) === 'stdout' || ref4 === 'stderr') { return; } msg = ((ref5 = log.message) != null ? ref5.toString : void 0) != null ? log.message.toString() : log.message; msg = "[" + log.total_depth + "." + log.level + " " + log.module + "] " + (JSON.stringify(msg)); msg = (function() { switch (log.type) { case 'stdout_stream': return "\x1b[36m" + msg + "\x1b[39m"; case 'stderr_stream': return "\x1b[35m" + msg + "\x1b[39m"; default: return "\x1b[32m" + msg + "\x1b[39m"; } })(); return process.stdout.write(msg + "\n"); }); } options.log = function(log) { var _log, args, file, frame, header, l, len1, len2, line, m, method, path, stackTrace; if (typeof log === 'string') { log = { message: log }; } if (log.level == null) { log.level = 'INFO'; } if (log.time == null) { log.time = Date.now(); } if (log.module == null) { log.module = void 0; } if (log.header_depth == null) { log.header_depth = depth; } for (l = 0, len1 = headers.length; l < len1; l++) { header = headers[l]; if (log.headers == null) { log.headers = header; } } if (log.total_depth == null) { log.total_depth = stack.length; } if (log.type == null) { log.type = 'text'; } args = 1 <= arguments.length ? [].slice.call(arguments, 0) : []; stackTrace = require('stack-trace'); path = require('path'); frame = stackTrace.get()[1]; file = path.basename(frame.getFileName()); line = frame.getLineNumber(); method = frame.getFunctionName(); log.file = file; log.line = line; args.unshift("" + file + ":" + line + " in " + method + "()"); for (m = 0, len2 = _logs.length; m < len2; m++) { _log = _logs[m]; _log(log); } if (!log_disabled) { return typeof obj.emit === "function" ? obj.emit(log.type, log) : void 0; } }; options.log._mecano_ = true; return options; }; call_callback = function(fn, args) { var err, mtodos; stack.unshift(todos); todos = todos_create(); try { fn.apply(proxy, args); } catch (error) { err = error; todos = stack.shift(); jump_to_error(err); args[0] = err; return run(); } mtodos = todos; todos = stack.shift(); if (mtodos.length) { return todos.unshift.apply(todos, mtodos); } }; handle_multiple_call = function(err) { killed = true; while (stack.length) { todos = stack.shift(); } jump_to_error(err); return run(); }; jump_to_error = function(err) { var ref2; while (todos[0] && ((ref2 = todos[0].type) !== 'catch' && ref2 !== 'then')) { todos.shift(); } return todos.err = err; }; _run_ = function() { if (obj.options.domain) { return obj.options.domain.run(run); } else { return run(); } }; run = function(options, callback) { var err, header, index, org_options, ref2, ref3, status; if (!options) { options = todos.shift(); } if (!options) { if (stack.length === 0) { if ((ref2 = obj.options.domain) != null) { ref2.removeListener('error', domain_on_error); } } if (callback) { callback(todos.err); } else { if (stack.length === 0 && todos.err && todos.throw_if_error) { throw todos.err; } } return; } org_options = options; options = enrich_options(options); if (options.type === 'then') { err = todos.err, status = todos.status; status = status.some(function(status) { return !status.shy && !!status.value; }); todos.final_err = err; todos_reset(todos); if ((ref3 = options.handler) != null) { ref3.call(proxy, err, status); } run(); return; } if (killed) { return; } if (array.compare(options.type, ['end'])) { return conditions.all(proxy, options, function() { while (todos[0] && todos[0].type !== 'then') { todos.shift(); } if (callback) { callback(err); } return run(); }, function(err) { if (callback) { callback(err); } return run(); }); } index = index_counter++; if (options.header) { depth++; } if (options.header) { headers.push(options.header); } if (options.header) { options.log({ message: options.header, type: 'header', index: index, depth: depth, headers: (function() { var l, len1, results; results = []; for (l = 0, len1 = headers.length; l < len1; l++) { header = headers[l]; results.push(header); } return results; })() }); } todos.status.unshift({ shy: options.shy, value: void 0 }); stack.unshift(todos); todos = todos_create(); todos.options = org_options; return wrap.options(options, function(err) { var do_callback, do_conditions, do_handler, do_intercept_after, do_intercept_before, do_once, do_options_after, do_options_before; do_once = function() { var hash, hashme; hashme = function(value) { if (typeof value === 'string') { value = "string:" + (string.hash(value)); } else if (typeof value === 'boolean') { value = "boolean:" + value; } else if (typeof value === 'function') { value = "function:" + (string.hash(value.toString())); } else if (value === void 0 || value === null) { value = 'null'; } else if (Array.isArray(value)) { value = 'array:' + value.sort().map(function(value) { return hashme(value); }).join(':'); } else if (typeof value === 'object') { value = 'object'; } else { throw Error("Invalid data type: " + (JSON.stringify(value))); } return value; }; if (options.once) { if (typeof options.once === 'string') { hash = string.hash(options.once); } else if (Array.isArray(options.once)) { hash = string.hash(options.once.map(function(k) { return hashme(options[k]); }).join('|')); } else { throw Error("Invalid Type Option Once: " + (JSON.stringify(options.once))); } if (once[hash]) { return do_callback([]); } once[hash] = true; } return do_options_before(); }; do_options_before = function() { if (options.options_before) { return do_intercept_before(); } if (options.before == null) { options.before = []; } if (!Array.isArray(options.before)) { options.before = [options.before]; } return each(options.before).call(function(before, next) { var k, opts, v; before = normalize_options([before], 'call', false); before = before[0]; opts = { options_before: true }; for (k in before) { v = before[k]; opts[k] = v; } for (k in options) { v = options[k]; if (k === 'handler' || k === 'callback') { continue; } if (opts[k] == null) { opts[k] = v; } } return run(opts, next); }).error(function(err) { return do_callback([err]); }).then(do_intercept_before); }; do_intercept_before = function() { if (options.intercept_before) { return do_conditions(); } return each(befores).call(function(before, next) { var k, opts, v; for (k in before) { v = before[k]; switch (k) { case 'handler': continue; case 'type': if (!array.compare(v, options[k])) { return next(); } break; default: if (v !== options[k]) { return next(); } } } opts = { intercept_before: true }; for (k in before) { v = before[k]; opts[k] = v; } for (k in options) { v = options[k]; if (k === 'handler' || k === 'callback') { continue; } if (opts[k] == null) { opts[k] = v; } } return run(opts, next); }).error(function(err) { return do_callback([err]); }).then(do_conditions); }; do_conditions = function() { return conditions.all(obj, options, function() { var k, v; for (k in options) { v = options[k]; if (/^if.*/.test(k) || /^unless.*/.test(k)) { delete options[k]; } } return do_handler(); }, function(err) { return do_callback([err]); }); }; options.attempt = -1; do_handler = function() { var called, do_next, k, options_callback, options_handler, opts, ref4, ref5, status_sync, v, wait_children; options.attempt++; do_next = function(arg1) { var err; err = arg1[0]; options.handler = options_handler; options.callback = options_callback; if (err && !(err instanceof Error)) { err = Error('First argument not a valid error'); arguments[0][0] = err; } if (err) { options.log({ message: err.message, level: 'ERROR', index: index, module: 'mecano' }); } if (err && options.attempt < options.retry - 1) { options.log({ message: "Retry on error, attempt " + (options.attempt + 1), level: 'WARN', index: index, module: 'mecano' }); return setTimeout(do_handler, options.wait); } return do_intercept_after.apply(null, arguments); }; if (options.handler == null) { options.handler = ((ref4 = obj.registry.get(options.type)) != null ? ref4.handler : void 0) || ((ref5 = registry.get(options.type)) != null ? ref5.handler : void 0); } if (!options.handler) { return handle_multiple_call(Error("Unregistered Middleware: " + options.type)); } options_handler = options.handler; options.handler = void 0; options_callback = options.callback; options.callback = void 0; called = false; try { opts = {}; for (k in options) { v = options[k]; opts[k] = v; } if (options_handler.length === 2) { return options_handler.call(proxy, opts, function() { var args; if (killed) { return; } if (called) { return handle_multiple_call(Error('Multiple call detected')); } called = true; args = [].slice.call(arguments, 0); return setImmediate(function() { return do_next(args); }); }); } else { options_handler.call(proxy, opts); if (killed) { return; } if (called) { return handle_multiple_call(Error('Multiple call detected')); } called = true; status_sync = false; wait_children = function() { var loptions; if (!todos.length) { return setImmediate(function() { return do_next([null, status_sync]); }); } loptions = todos.shift(); return run(loptions, function(err, status) { if (err) { return do_next([err]); } if (status && !loptions.shy) { status_sync = true; } return wait_children(); }); }; return wait_children(); } } catch (error) { err = error; todos = []; return do_next([err]); } }; do_intercept_after = function(args, callback) { if (options.intercept_after) { return do_options_after(args); } return each(afters).call(function(after, next) { var k, opts, v; for (k in after) { v = after[k]; switch (k) { case 'handler': continue; case 'type': if (!array.compare(v, options[k])) { return next(); } break; default: if (v !== options[k]) { return next(); } } } opts = { intercept_after: true }; for (k in after) { v = after[k]; opts[k] = v; } for (k in options) { v = options[k]; if (k === 'handler' || k === 'callback') { continue; } if (opts[k] == null) { opts[k] = v; } } opts.callback_arguments = args; return run(opts, next); }).error(function(err) { return do_callback([err]); }).then(function() { return do_options_after(args); }); }; do_options_after = function(args) { if (options.options_after) { return do_callback(args); } if (options.after == null) { options.after = []; } if (!Array.isArray(options.after)) { options.after = [options.after]; } return each(options.after).call(function(after, next) { var k, opts, v; after = normalize_options([after], 'call', false); after = after[0]; opts = { options_after: true }; for (k in after) { v = after[k]; opts[k] = v; } for (k in options) { v = options[k]; if (k === 'handler' || k === 'callback') { continue; } if (opts[k] == null) { opts[k] = v; } } return run(opts, next); }).error(function(err) { return do_callback([err]); }).then(function() { return do_callback(args); }); }; do_callback = function(args) { if (options.header) { depth--; } if (options.header) { headers.pop(); } options.log({ type: 'handled', index: index, depth: depth, error: args[0], status: args[1] }); if (killed) { return; } if (!args[0]) { args[0] = void 0; } args[1] = !!args[1]; if (todos.length === 0) { todos = stack.shift(); } if (args[0] && !options.relax) { jump_to_error(args[0]); } if (args[0] && options.callback) { todos.throw_if_error = false; } todos.status[0].value = args[1]; if (options.callback) { call_callback(options.callback, args); } if (options.relax) { args[0] = null; } if (callback) { callback(args[0], args[1]); } return run(); }; return do_once(); }); }; properties.child = { get: function() { return function() { return module.exports(obj.options); }; } }; properties.then = { get: function() { return function() { todos.push({ type: 'then', handler: arguments[0] }); if (todos.length === 1) { setImmediate(_run_); } return proxy; }; } }; properties.end = { get: function() { return function() { var args, l, len1, options, opts; args = [].slice.call(arguments); options = normalize_options(args, 'end'); for (l = 0, len1 = options.length; l < len1; l++) { opts = options[l]; todos.push(opts); } if (todos.length === options.length) { setImmediate(_run_); } return proxy; }; } }; properties.call = { get: function() { return function() { var args, k, l, len1, len2, m, mod, options, opts, ref2, v; args = [].slice.call(arguments); options = normalize_options(args, 'call'); for (l = 0, len1 = options.length; l < len1; l++) { opts = options[l]; if (typeof opts.handler === 'string') { mod = require.main.require(opts.handler); if (Array.isArray(mod)) { throw Error('Array modules not yet supported'); } mod = normalize_options([mod], 'call'); opts.handler = mod.handler; ref2 = mod[0]; for (k in ref2) { v = ref2[k]; if (opts[k] == null) { opts[k] = v; } } } if (!opts.handler) { throw Error('Missing handler option'); } if (typeof opts.handler !== 'function') { throw Error("Handler not a function, got '" + opts.handler + "'"); } } for (m = 0, len2 = options.length; m < len2; m++) { opts = options[m]; todos.push(opts); } if (todos.length === options.length) { setImmediate(_run_); } return proxy; }; } }; properties.each = { get: function() { return function() { var arg, args, key, l, len1, len2, m, options, opts, value; args = [].slice.call(arguments); arg = args.shift(); if ((arg == null) || typeof arg !== 'object') { jump_to_error(Error("Invalid Argument: first argument must be an array or an object to iterate, got " + (JSON.stringify(arg)))); return proxy; } options = normalize_options(args, 'call'); for (l = 0, len1 = options.length; l < len1; l++) { opts = options[l]; if (Array.isArray(arg)) { for (m = 0, len2 = arg.length; m < len2; m++) { key = arg[m]; opts.key = key; this.call(opts); } } else { for (key in arg) { value = arg[key]; opts.key = key; opts.value = value; this.call(opts); } } } return proxy; }; } }; properties.before = { get: function() { return function() { var l, len1, options, opts; if (typeof arguments[0] === 'string' || Array.isArray(arguments[0])) { arguments[0] = { type: arguments[0] }; } options = normalize_options(arguments, null, false); for (l = 0, len1 = options.length; l < len1; l++) { opts = options[l]; if (typeof opts.handler !== 'function') { throw Error("Invalid handler " + (JSON.stringify(opts.handler))); } befores.push(opts); } return proxy; }; } }; properties.after = { get: function() { return function() { var l, len1, options, opts; if (typeof arguments[0] === 'string' || Array.isArray(arguments[0])) { arguments[0] = { type: arguments[0] }; } options = normalize_options(arguments, null, false); for (l = 0, len1 = options.length; l < len1; l++) { opts = options[l]; if (typeof opts.handler !== 'function') { throw Error("Invalid handler " + (JSON.stringify(opts.handler))); } afters.push(opts); } return proxy; }; } }; properties.status = { get: function() { return function(index) { var l, len1, len2, m, ref2, ref3, ref4, status, value; if (arguments.length === 0) { return stack[0].status.some(function(status) { return !status.shy && !!status.value; }); } else if (index === false) { value = stack[0].status.some(function(status) { return !status.shy && !!status.value; }); ref2 = stack[0].status; for (l = 0, len1 = ref2.length; l < len1; l++) { status = ref2[l]; status.value = false; } return value; } else if (index === true) { value = stack[0].status.some(function(status) { return !status.shy && !!status.value; }); ref3 = stack[0].status; for (m = 0, len2 = ref3.length; m < len2; m++) { status = ref3[m]; status.value = true; } return value; } else { return (ref4 = stack[0].status[Math.abs(index)]) != null ? ref4.value : void 0; } }; } }; Object.defineProperties(obj, properties); reg = registry.registry({}); Object.defineProperty(obj.registry, 'get', { get: function() { return function(name, handler) { return reg.get.apply(reg, arguments); }; } }); Object.defineProperty(obj.registry, 'register', { get: function() { return function(name, handler) { reg.register.apply(reg, arguments); return proxy; }; } }); Object.defineProperty(obj.registry, 'registered', { get: function() { return function(name, handler) { return reg.registered.apply(reg, arguments); }; } }); Object.defineProperty(obj.registry, 'unregister', { get: function() { return function(name, handler) { reg.unregister.apply(reg, arguments); return proxy; }; } }); if (obj.options.ssh && !obj.options.ssh.config) { proxy.ssh.open(obj.options.ssh); } return proxy; }; module.exports.propagated_options = ['ssh', 'log', 'stdout', 'stderr', 'debug']; todos_create = function() { var todos; todos = []; todos_reset(todos); return todos; }; todos_reset = function(todos) { todos.err = null; todos.status = []; return todos.throw_if_error = true; }; registry = require('./registry'); domain = require('domain'); each = require('each'); array = require('./misc/array'); conditions = require('./misc/conditions'); wrap = require('./misc/wrap'); string = require('./misc/string'); merge = require('./misc').merge; EventEmitter = require('events').EventEmitter;