UNPKG

mecano

Version:

Common functions for system deployment.

318 lines (262 loc) 10.8 kB
# Conditions Conditions are a set of properties you may add to the options of the Mecano functions. They apply to all functions and control their execution. For an action to be executed, all conditions must pass. module.exports = ## Run an action for a user defined condition: `if` Work on the property `if` in `options`. When `if` is a boolean, a string, a number or null, its value determine the output. If it's a function, the arguments vary depending on the callback signature. With 1 argument, the argument is an options object and the handler is run synchronously. With 2 arguments, the arguments are an options object plus a callback and the handler is run asynchronously. If it's an array, all its element must positively resolve for the condition to pass. Updating the content of a file if we are the owner ```js mecano.render({ source:'./file', if: function(options, callback){ fs.stat(options.source, function(err, stat){ # Render the file if we own it callback(err, stat.uid == process.getuid()) }); } }, fonction(err, rendered){}); ``` if: (options, skip, succeed) -> # return succeed() if typeof options.if is 'undefined' options.if = [options.if] unless Array.isArray options.if ok = true each(options.if) .run (si, next) -> return next() unless ok # options.log? "Mecano `if`" type = typeof si if si is null or type is 'undefined' ok = false next() else if type is 'boolean' or type is 'number' ok = false unless si next() else if type is 'function' if si.length < 2 try ok = false unless si options next() catch err then next err if si.length is 2 si options, (err, is_ok) -> return next err if err ok = false unless is_ok next() else next new Error "Invalid callback" else if type is 'string' si = template si, options ok = false if si.length is 0 next() else next new Error "Invalid condition type" .then (err) -> # return skip err if err or not ok # succeed() if err or not ok then skip(err) else succeed() ## Run an action if false: `not_if` Work on the property `not_if` in `options`. When `if` is a boolean, a string, a number or null, its value determine the output. If it's a function, the arguments vary depending on the callback signature. With 1 argument, the argument is an options object and the handler is run synchronously. With 2 arguments, the arguments are an options object plus a callback and the handler is run asynchronously. If it's an array, all its element must negatively resolve for the condition to pass. not_if: (options, skip, succeed) -> # return succeed() if typeof options.not_if is 'undefined' options.not_if = [options.not_if] unless Array.isArray options.not_if ok = true each(options.not_if) .run (not_if, next) -> return next() unless ok # options.log? "Mecano `not_if`" type = typeof not_if if not_if is null or type is 'undefined' ok = true next() else if type is 'boolean' or type is 'number' ok = false if not_if next() else if type is 'function' if not_if.length < 2 try ok = false if not_if options next() catch err then next err if not_if.length is 2 not_if options, (err, is_ok) -> return next err if err ok = false if is_ok next() else next new Error "Invalid callback" else if type is 'string' not_if = template not_if, options ok = false if not_if.length isnt 0 next() else next new Error "Invalid condition type" .then (err) -> # return skip err if err or not ok # succeed() if err or not ok then skip(err) else succeed() ## Run an action if a command succeed: `if_exec` Work on the property `if_exec` in `options`. The value may be a single shell command or an array of commands. The callback `succeed` is called if all the provided command were executed successfully otherwise the callback `skip` is called. if_exec: (options, skip, succeed) -> # return succeed() unless options.if_exec? each(options.if_exec) .run (cmd, next) -> options.log? "Mecano `not_if_exec`: #{cmd}" options = { cmd: cmd, ssh: options.ssh } run = exec options if options.stdout run.stdout.pipe options.stdout, end: false if options.stderr run.stderr.pipe options.stderr, end: false run.on "exit", (code) -> options.log? "Mecano `if_exec`: code is \"#{code}\"" if code is 0 then next() else skip() .then succeed ## Run an action unless a command succeed: `not_if_exec` Work on the property `not_if_exec` in `options`. The value may be a single shell command or an array of commands. The callback `succeed` is called if all the provided command were executed with failure otherwise the callback `skip` is called. not_if_exec: (options, skip, succeed) -> # return succeed() unless options.not_if_exec? each(options.not_if_exec) .run (cmd, next) -> options.log? "Mecano `not_if_exec`: #{cmd}" options = { cmd: cmd, ssh: options.ssh } run = exec options if options.stdout run.stdout.pipe options.stdout, end: false if options.stderr run.stderr.pipe options.stderr, end: false run.on "exit", (code) -> options.log? "Mecano `not_if_exec`: code is \"#{code}\"" if code is 0 then skip() else next() .then succeed ## Run an action if a file exists: `if_exists` Work on the property `if_exists` in `options`. The value may be a file path or an array of file paths. You could also set the value to `true`, in which case it will be set with the `destination` option. The callback `succeed` is called if all the provided paths exists otherwise the callback `skip` is called. if_exists: (options, skip, succeed) -> {ssh, if_exists, destination} = options if typeof not_if_exists is 'boolean' and destination if_exists = if if_exists then [destination] else null # return succeed() unless if_exists? each(if_exists) .run (if_exists, next) -> # options.log? "Mecano `if_exists`" fs.exists ssh, if_exists, (err, exists) -> if exists then next() else skip() .then succeed ## Skip an action if a file exists: `not_if_exists` Work on the property `not_if_exists` in `options`. The value may be a file path or an array of file paths. You could also set the value to `true`, in which case it will be set with the `destination` option. The callback `succeed` is called if none of the provided paths exists otherwise the callback `skip` is called. not_if_exists: (options, skip, succeed) -> {ssh, not_if_exists, destination} = options if typeof not_if_exists is 'boolean' and destination not_if_exists = if not_if_exists then [destination] else null # return succeed() unless not_if_exists? each(not_if_exists) .run (not_if_exists, next) -> # options.log? "Mecano `not_if_exists`" fs.exists ssh, not_if_exists, (err, exists) -> if exists then skip() else next() .then succeed ## Ensure a file exist: `should_exist` Ensure that an action run if all the files present in the option "should_exist" exist. The value may be a file path or an array of file paths. The callback `succeed` is called if all of the provided paths exists otherwise the callback `skip` is called with an error. should_exist: (options, skip, succeed) -> # return succeed() unless options.should_exist? each(options.should_exist) .run (should_exist, next) -> # options.log? "Mecano `should_exist`" fs.exists options.ssh, should_exist, (err, exists) -> if exists then next() else next Error "File does not exist: #{should_exist}" # .then (err) -> if err then skip(err) else succeed() .on 'error', (err) -> skip err .on 'end', succeed ## Ensure a file already exist: `should_not_exist` Ensure that an action run if none of the files present in the option "should_exist" exist. The value may be a file path or an array of file paths. The callback `succeed` is called if none of the provided paths exists otherwise the callback `skip` is called with an error. should_not_exist: (options, skip, succeed) -> # return succeed() unless options.should_not_exist? each(options.should_not_exist) .run (should_not_exist, next) -> # options.log? "Mecano `should_not_exist`" fs.exists options.ssh, should_not_exist, (err, exists) -> if exists then next new Error "File does not exist: #{should_not_exist}" else next() .on 'error', (err) -> skip err .on 'end', -> succeed() ## Run all conditions: `all(options, skip, succeed)` This is the function run internally to execute all the conditions. * `opts` Command options * `skip` Skip callback, called when a condition is not fulfill. May also be called with on error on failure * `succeed` Succeed callback, only called if all the condition succeed Example: ```js conditions.all({ if: true }, function(err){ console.log('Conditins failed or pass an error') }, function(){ console.log('Conditions succeed') }) ``` all: (options, failed, succeed) -> return succeed() unless options? and (typeof options is 'object' and not Array.isArray options) keys = Object.keys options i = 0 next = -> key = keys[i++] return succeed() unless key? return next() unless module.exports[key]? module.exports[key] options, (err) -> options.log? "Mecano `#{key}`: skipping action" failed err , next next() ## Dependencies each = require 'each' misc = require './index' exec = require 'ssh2-exec' fs = require 'ssh2-fs' template = require './template'