mecano
Version:
Common functions for system deployment.
330 lines (321 loc) • 11.5 kB
JavaScript
// Generated by CoffeeScript 1.9.1
var Ftp, curl, fs, misc, path, request, url,
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; },
slice = [].slice;
module.exports = function(options, callback) {
var algo, destination, do_cache, do_checksum, do_download, do_local_md5, do_prepare, hash, protocols_ftp, protocols_http, ref, ref1, source, stageDestination, unstage;
destination = options.destination, source = options.source;
if (!source) {
return callback(new Error("Missing source: " + source));
}
if (!destination) {
return callback(new Error("Missing destination: " + destination));
}
stageDestination = destination + "." + (Date.now()) + (Math.round(Math.random() * 1000));
if (options.md5 != null) {
if ((ref = typeof options.md5) !== 'string' && ref !== 'boolean') {
return callback(new Error("Invalid MD5 Hash:" + options.md5));
}
algo = 'md5';
hash = options.md5;
} else if (options.sha1 != null) {
if ((ref1 = typeof options.sha1) !== 'string' && ref1 !== 'boolean') {
return callback(new Error("Invalid SHA-1 Hash:" + options.sha1));
}
algo = 'sha1';
hash = options.sha1;
} else {
algo = 'md5';
hash = false;
}
protocols_http = ['http:', 'https:'];
protocols_ftp = ['ftp:', 'ftps:'];
do_cache = (function(_this) {
return function() {
var cache_file, cache_path;
if (!((options.cache_dir != null) || (options.cache_file != null))) {
return do_local_md5();
}
if (options.cache_dir === false || options.cache_file === false) {
return do_local_md5();
}
if (typeof options.log === "function") {
options.log("Mecano `download`: using cache [DEBUG]");
}
cache_path = typeof options.cache_dir === 'string' ? options.cache_dir : './';
cache_file = typeof options.cache_file === 'string' ? options.cache_file : path.basename(options.source);
cache_path = path.resolve(cache_path, cache_file);
if (typeof options.log === "function") {
options.log("Mecano `download`: cache path is '" + cache_path + "' [INFO]");
}
return _this.download({
ssh: null,
source: options.source,
destination: cache_path,
cache_dir: false,
cache_file: false,
md5: options.md5,
sha1: options.sha1,
force: options.force_cache
}, function(err, cached) {
var push_file_opt;
if (err) {
return callback(err);
}
if (typeof options.log === "function") {
options.log(cached ? "Mecano `download`: cache updated [WARN]" : "Mecano `download`: cache not modified [INFO]");
}
if (typeof options.log === "function") {
options.log("Mecano `download`: sending cache to destination [DEBUG]");
}
push_file_opt = {
ssh: options.ssh,
source: cache_path,
destination: options.destination,
cache_dir: false,
cache_file: false,
mode: options.mode,
md5: options.md5,
sha1: options.sha1,
force: options.force,
uid: options.uid,
gid: options.gid,
log: options.log,
stdout: options.stdout,
stderr: options.stderr
};
if (hash) {
return _this.download(push_file_opt, callback);
} else {
return misc.file.hash(null, cache_path, algo, function(err, calc_hash) {
push_file_opt[algo] = calc_hash;
return _this.download(push_file_opt, callback);
});
}
});
};
})(this);
do_local_md5 = function() {
var protocol;
if (hash !== true) {
return do_prepare();
}
if (!options.ssh) {
return callback(Error("Unsupported hash 'true' in non-ssh mode"));
}
protocol = url.parse(options.source).protocol;
if (indexOf.call(slice.call(protocols_http).concat(slice.call(protocols_ftp)), protocol) >= 0) {
return callback(Error("Unsupported hash 'true' with non-file protocols"));
}
return misc.file.hash(null, options.source, algo, function(err, l_hash) {
if (err) {
return callback(err);
}
hash = l_hash;
return do_prepare();
});
};
do_prepare = (function(_this) {
return function() {
if (typeof options.log === "function") {
options.log("Mecano `download`: Check if destination (" + destination + ") exists [DEBUG]");
}
return fs.exists(options.ssh, destination, function(err, exists) {
if (err) {
return callback(err);
}
if (exists) {
if (typeof options.log === "function") {
options.log("Mecano `download`: destination exists [INFO]");
}
if (options.force) {
if (typeof options.log === "function") {
options.log("Mecano `download`: Force download [DEBUG]");
}
return do_download();
} else if (hash) {
if (typeof options.log === "function") {
options.log("Mecano `download`: comparing " + algo + " hash [DEBUG]");
}
return misc.file.hash(options.ssh, destination, algo, function(err, c_hash) {
if (err) {
return callback(err);
}
if (hash === c_hash) {
if (typeof options.log === "function") {
options.log("Mecano `download`: Hashes match, skipping [DEBUG]");
}
return callback();
}
if (typeof options.log === "function") {
options.log("Mecano `download`: Hashes don't match, delete then re-download [WARN]");
}
return fs.unlink(options.ssh, destination, function(err) {
if (err) {
return callback(err);
}
return do_download();
});
});
} else {
if (typeof options.log === "function") {
options.log("Mecano `download`: destination exists, check disabled, skipping [DEBUG]");
}
return callback(null, false);
}
} else {
if (typeof options.log === "function") {
options.log("Mecano `download`: destination doesn't exists, cheking parent directories (" + (path.join(destination, '..')) + ") [DEBUG]");
}
return _this.mkdir({
destination: path.join(destination, '..')
}, function(err, created) {
if (err) {
return callback(err);
}
if (created) {
if (typeof options.log === "function") {
options.log("Mecano `download`: Parent directory created [WARN]");
}
}
return do_download();
});
}
});
};
})(this);
do_download = (function(_this) {
return function() {
var cmd, k, ref2, ref3, u;
if (typeof options.log === "function") {
options.log("Mecano `download`: Download the source [DEBUG]");
}
u = url.parse(source);
if (options.ssh) {
if (ref2 = u.protocol, indexOf.call(protocols_http, ref2) >= 0) {
k = u.protocol === 'https:' ? '-k' : '';
cmd = "curl " + k + " -s " + source + " -o " + stageDestination;
if (options.proxy) {
cmd += " -x " + options.proxy;
}
return _this.execute({
cmd: cmd
}, function(err, executed) {
if (err) {
return callback(curl.error(err));
}
return do_checksum();
});
} else if (ref3 = u.protocol, indexOf.call(protocols_ftp, ref3) >= 0) {
return callback(new Error('FTP download not supported over SSH'));
} else {
return fs.createWriteStream(options.ssh, stageDestination, function(err, ws) {
if (err) {
return callback(err);
}
return fs.createReadStream(null, u.pathname, function(err, rs) {
if (err) {
return callback(err);
}
rs.on('error', callback);
return rs.pipe(ws).on('close', function() {
return do_checksum();
}).on('error', callback);
});
});
}
} else {
return fs.createWriteStream(null, stageDestination, function(err, ws) {
var ftp, pass, ref4, ref5, ref6, user;
if (err) {
return callback(err);
}
if (ref4 = u.protocol, indexOf.call(protocols_http, ref4) >= 0) {
options.url = source;
request(options).pipe(ws);
} else if (ref5 = u.protocol, indexOf.call(protocols_ftp, ref5) >= 0) {
if (options.host == null) {
options.host = u.hostname;
}
if (options.port == null) {
options.port = u.port;
}
if (u.auth) {
ref6 = u.auth.split(':'), user = ref6.user, pass = ref6.pass;
}
if (options.user == null) {
options.user = user;
}
if (options.pass == null) {
options.pass = pass;
}
ftp = new Ftp(options);
ftp.getGetSocket(u.pathname, function(err, rs) {
if (err) {
return callback(err);
}
rs.pipe(ws);
return rs.resume();
});
} else {
fs.createReadStream(null, u.pathname, function(err, rs) {
if (err) {
return callback(err);
}
return rs.pipe(ws);
});
}
ws.on('close', function() {
return do_checksum();
});
return ws.on('error', function(err) {
return _this.remove({
ssh: null,
destination: stageDestination
}, callback);
});
});
}
};
})(this);
do_checksum = function() {
if (!hash) {
return unstage();
}
if (typeof options.log === "function") {
options.log("Mecano `download`: Compare the downloaded file with the provided checksum [DEBUG]");
}
return misc.file.hash(options.ssh, stageDestination, algo, function(err, calc_hash) {
if (hash === calc_hash) {
"Mecano `download`: download is valid [INFO]";
return unstage();
}
return misc.file.remove(options.ssh, stageDestination, function(err) {
if (err) {
return callback(err);
}
return callback(new Error("Invalid checksum, found \"" + calc_hash + "\" instead of \"" + hash + "\""));
});
});
};
unstage = (function(_this) {
return function() {
if (typeof options.log === "function") {
options.log("Mecano `download`: Move the downloaded file [DEBUG]");
}
return _this.move({
source: stageDestination,
destination: destination,
source_md5: options.md5
}, callback);
};
})(this);
return do_cache();
};
fs = require('ssh2-fs');
Ftp = require('jsftp');
path = require('path');
request = require('request');
url = require('url');
misc = require('./misc');
curl = require('./misc/curl');