mecano
Version:
Common functions for system deployment.
349 lines (306 loc) • 9.83 kB
JavaScript
// Generated by CoffeeScript 1.7.1
var each, exec, fs, misc;
each = require('each');
misc = require('./index');
exec = require('ssh2-exec');
fs = require('ssh2-fs');
/*
Conditionnal properties
=======================
*/
module.exports = {
/*
`all(options, skip, succeed)` Run all 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
*/
all: function(options, skip, succeed) {
return each([this["if"], this.not_if, this.if_exists, this.not_if_exists, this.should_exist]).on('item', function(condition, next) {
return condition(options, skip, next);
}).on('error', skip).on('end', succeed);
},
/*
`if` Run an action for a user defined condition
-----------------------------------------------
Work on the property `if` in `options`. When `if`
is a boolean, its value determine the output. If it's
a callback, the function is called with the `options`,
`skip` and `succeed` arguments. If it'a an array, all its element
must positively resolve for the condition to pass.
Updating the content of a file if we are the owner
mecano.render
source:'./file'
if: (options, skip, succeed) ->
fs.stat options.source, (err, stat) ->
* File does not exists
return skip err if err
* Skip if we dont own the file
return skip() unless stat.uid is process.getuid()
* Succeed if we own the file
succeed()
*/
"if": function(options, skip, succeed) {
var ok;
if (options["if"] == null) {
return succeed();
}
ok = true;
return each(options["if"]).on('item', function(si, next) {
var type;
if (!ok) {
return next();
}
type = typeof si;
if (type === 'boolean' || type === 'number') {
if (!si) {
ok = false;
}
return next();
} else if (type === 'function') {
return si(options, (function() {
ok = false;
return next.apply(null, arguments);
}), next);
} else {
return next(new Error("Invalid condition type"));
}
}).on('both', function(err) {
if (err || !ok) {
return skip(err);
}
return succeed();
});
},
/*
`not_if` Run an action if false
-------------------------------
Work on the property `if` in `options`. When `if`
is a boolean, its value determine the output. If it's
a callback, the function is called with the `options`,
`skip` and `succeed` arguments. If it'a an array, all its element
must positively resolve for the condition to pass.
*/
not_if: function(options, skip, succeed) {
var ok;
if (options.not_if == null) {
return succeed();
}
ok = true;
return each(options.not_if).on('item', function(not_if, next) {
var type;
if (!ok) {
return next();
}
type = typeof not_if;
if (type === 'boolean' || type === 'number') {
if (not_if) {
ok = false;
}
return next();
} else if (type === 'function') {
return not_if(options, next, (function() {
ok = false;
return next.apply(null, arguments);
}));
} else {
return next(new Error("Invalid condition type"));
}
}).on('both', function(err) {
if (err || !ok) {
return skip(err);
}
return succeed();
});
},
/*
`if_exists` Run an action if a file 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: function(options, skip, succeed) {
if (options.if_exists == null) {
return succeed();
}
return each(options.if_exists).on('item', function(if_exists, next) {
return fs.exists(options.ssh, if_exists, function(err, exists) {
if (exists) {
return next();
} else {
return skip();
}
});
}).on('end', succeed);
},
/*
`not_if_exists` Skip an action if a file 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: function(options, skip, succeed) {
if (options.not_if_exists == null) {
return succeed();
}
return each(options.not_if_exists).on('item', function(not_if_exists, next) {
return fs.exists(options.ssh, not_if_exists, function(err, exists) {
if (exists) {
return next(new Error);
} else {
return next();
}
});
}).on('error', function() {
return skip();
}).on('end', succeed);
},
/*
`if_exec` Run an action if a command is successfully executed
-------------------------------------------------------------
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: function(options, skip, succeed) {
if (options.if_exec == null) {
return succeed();
}
return each(options.if_exec).on('item', function(cmd, next) {
var run;
if (typeof options.log === "function") {
options.log("Execute condition: " + 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
});
}
return run.on("exit", function(code) {
if (code === 0) {
return next();
} else {
return skip();
}
});
}).on('end', succeed);
},
/*
`not_if_exec` Run an action unless a command is successfully executed
---------------------------------------------------------------------
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: function(options, skip, succeed) {
if (options.not_if_exec == null) {
return succeed();
}
return each(options.not_if_exec).on('item', function(cmd, next) {
var run;
if (typeof options.log === "function") {
options.log("Execute condition: " + 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
});
}
return run.on("exit", function(code) {
if (code === 0) {
return next(new Error);
} else {
return next();
}
});
}).on('error', function() {
return skip();
}).on('end', succeed);
},
/*
`should_exist` Ensure a file 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: function(options, skip, succeed) {
if (options.should_exist == null) {
return succeed();
}
return each(options.should_exist).on('item', function(should_exist, next) {
return fs.exists(options.ssh, should_exist, function(err, exists) {
if (exists) {
return next();
} else {
return next(new Error("File does not exist: " + should_exist));
}
});
}).on('error', function(err) {
return skip(err);
}).on('end', succeed);
},
/*
`should_not_exist` Ensure a file already 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: function(options, skip, succeed) {
if (options.should_not_exist == null) {
return succeed();
}
return each(options.should_not_exist).on('item', function(should_not_exist, next) {
return fs.exists(options.ssh, should_not_exist, function(err, exists) {
if (exists) {
return next(new Error("File does not exist: " + should_not_exist));
} else {
return next();
}
});
}).on('error', function(err) {
return skip(err);
}).on('end', function() {
return succeed();
});
}
};