UNPKG

mecano

Version:

Common functions for system deployment.

414 lines (404 loc) 11.5 kB
// Generated by CoffeeScript 1.11.1 var diff, eco, fs, misc, nunjucks, path, string, uid_gid; module.exports = function(options, callback) { var j, len, ref, target, targetHash, targetStat, w; options.log({ message: "Entering file", level: 'DEBUG', module: 'mecano/lib/file' }); if (!((options.source || (options.content != null)) || options.replace || (options.write != null))) { return callback(Error('Missing source or content')); } if (options.source && options.content) { return callback(Error('Define either source or content')); } if (!options.target) { return callback(Error('Missing target')); } options.log({ message: "Source is \"" + options.source + "\"", level: 'DEBUG', module: 'mecano/lib/file' }); options.log({ message: "Destination is \"" + options.target + "\"", level: 'DEBUG', module: 'mecano/lib/file' }); if (options.content && Buffer.isBuffer(options.content)) { options.content = options.content.toString(); } if (typeof options.content === 'function') { options.content = options.content(options); } if (options.diff == null) { options.diff = options.diff || !!options.stdout; } if (options.engine == null) { options.engine = 'nunjunks'; } if (options.unlink == null) { options.unlink = false; } switch (options.eof) { case 'unix': options.eof = "\n"; break; case 'mac': options.eof = "\r"; break; case 'windows': options.eof = "\r\n"; break; case 'unicode': options.eof = "\u2028"; } target = null; targetHash = null; if (options.write == null) { options.write = []; } if ((options.from != null) || (options.to != null) || (options.match != null) || (options.replace != null) || (options.place_before != null)) { options.write.push({ from: options.from, to: options.to, match: options.match, replace: options.replace, append: options.append, place_before: options.place_before }); options.append = false; } ref = options.write; for (j = 0, len = ref.length; j < len; j++) { w = ref[j]; if ((w.from == null) && (w.to == null) && (w.match == null) && (w.replace != null)) { w.match = w.replace; } } this.call(function(_, callback) { var source, ssh; if (options.content != null) { if (typeof options.content === 'number') { options.content = "" + options.content; } return callback(); } source = options.source || options.target; options.log({ message: "Force local source is \"" + (options.local ? 'true' : 'false') + "\"", level: 'DEBUG', module: 'mecano/lib/file' }); ssh = options.local ? null : options.ssh; return fs.exists(ssh, source, function(err, exists) { if (err) { return callback(err); } if (!exists) { if (options.source) { return callback(new Error("Source does not exist: " + (JSON.stringify(options.source)))); } options.content = ''; return callback(); } options.log({ message: "Reading source", level: 'DEBUG', module: 'mecano/lib/file' }); return fs.readFile(ssh, source, 'utf8', function(err, src) { if (err) { return callback(err); } options.content = src; return callback(); }); }); }); targetStat = null; this.call(function(_, callback) { var do_mkdir, do_read, exists; if (typeof options.target === 'function') { return callback(); } exists = function() { options.log({ message: "Stat target", level: 'DEBUG', module: 'mecano/lib/file' }); return fs.lstat(options.ssh, options.target, function(err, stat) { if ((err != null ? err.code : void 0) === 'ENOENT') { return do_mkdir(); } if (err) { return callback(err); } targetStat = stat; if (stat.isDirectory()) { options.target = options.target + "/" + (path.basename(options.source)); options.log({ message: "Destination is a directory and is now \"options.target\"", level: 'INFO', module: 'mecano/lib/file' }); return fs.stat(options.ssh, options.target, function(err, stat) { if ((err != null ? err.code : void 0) === 'ENOENT') { options.log({ message: "New target does not exist", level: 'INFO', module: 'mecano/lib/file' }); return callback(); } if (err) { return callback(err); } if (!stat.isFile()) { return callback(new Error("Destination is not a file: " + options.target)); } options.log({ message: "New target exist", level: 'INFO', module: 'mecano/lib/file' }); targetStat = stat; return do_read(); }); } else if (stat.isSymbolicLink()) { options.log({ message: "Destination is a symlink", level: 'INFO', module: 'mecano/lib/file' }); if (!options.unlink) { return do_read(); } return fs.unlink(options.ssh, options.target, function(err, stat) { if (err) { return callback(err); } return callback(); }); } else if (stat.isFile()) { options.log({ message: "Destination is a file", level: 'INFO', module: 'mecano/lib/file' }); return do_read(); } else { return callback(Error("Invalid File Type Destination: " + options.target)); } }); }; do_mkdir = (function(_this) { return function() { if (typeof options.mode === 'string') { options.mode = parseInt(options.mode, 8); } return _this.mkdir({ target: path.dirname(options.target), uid: options.uid, gid: options.gid, mode: options.mode ? options.mode | 0x49 : 0x1ed, unless_exists: path.dirname(options.target) }, function(err, created) { if (err) { return callback(err); } return callback(); }); }; })(this); do_read = function() { options.log({ message: "Reading target", level: 'DEBUG', module: 'mecano/lib/file' }); return fs.readFile(options.ssh, options.target, 'utf8', function(err, dest) { if (err) { return callback(err); } target = dest; targetHash = string.hash(dest); return callback(); }); }; return exists(); }); this.call(function() { if (options.context != null) { return string.render(options); } }); this.call(function() { if (options.skip_empty_lines == null) { return; } options.log({ message: "Skip empty lines", level: 'DEBUG', module: 'mecano/lib/file' }); return options.content = options.content.replace(/(\r\n|[\n\r\u0085\u2028\u2029])\s*(\r\n|[\n\r\u0085\u2028\u2029])/g, "$1"); }); this.call(function() { if (options.write.length) { return string.replace_partial(options); } }); this.call(function() { var char, i, k, len1, ref1; if (options.eof == null) { return; } options.log({ message: "Checking option eof", level: 'DEBUG', module: 'mecano/lib/file' }); if (options.eof === true) { ref1 = options.content; for (i = k = 0, len1 = ref1.length; k < len1; i = ++k) { char = ref1[i]; if (char === '\r') { options.eof = options.content[i + 1] === '\n' ? '\r\n' : char; break; } if (char === '\n' || char === '\u2028') { options.eof = char; break; } } if (options.eof === true) { options.eof = '\n'; } options.log({ message: "Option eof is true, gessing as " + (JSON.stringify(options.eof)), level: 'INFO', module: 'mecano/lib/file' }); } if (!string.endsWith(options.content, options.eof)) { options.log({ message: "Add eof", level: 'WARN', module: 'mecano/lib/file' }); return options.content += options.eof; } }); this.call(function(_, callback) { var raw, ref1, text; if (targetHash === string.hash(options.content)) { return callback(); } options.log({ message: "File content has changed: " + options.target, level: 'WARN', module: 'mecano/lib/file' }); ref1 = diff(target, options.content, options), raw = ref1.raw, text = ref1.text; if (typeof options.diff === 'function') { options.diff(text, raw); } options.log({ message: text, type: 'diff', level: 'INFO', module: 'mecano/lib/file' }); return callback(null, true); }); this.call(function() { var backup; if (!this.status()) { return; } if (!(options.backup && targetHash)) { return; } options.log({ message: "Create backup", level: 'INFO', module: 'mecano/lib/file' }); backup = typeof options.backup === 'string' ? options.backup : "." + (Date.now()); return this.copy({ ssh: options.ssh, source: options.target, target: "" + options.target + backup }); }); this.call(function(_, callback) { if (!this.status()) { return callback(); } if (typeof options.target === 'function') { options.log({ message: "Write target with user function", level: 'INFO', module: 'mecano/lib/file' }); options.target(options.content); return callback(); } options.log({ message: "Write target", level: 'INFO', module: 'mecano/lib/file' }); if (options.append) { if (options.flags == null) { options.flags = 'a'; } } if (options.mode == null) { options.mode = 0x1a4; } return uid_gid(options, function(err) { if (err) { return callback(err); } return fs.writeFile(options.ssh, options.target, options.content, options, function(err) { if (err) { return callback(err); } options.log({ message: "File written", level: 'INFO', module: 'mecano/lib/file' }); return callback(); }); }); }); this.chown({ target: options.target, stat: targetStat, uid: options.uid, gid: options.gid, "if": (options.uid != null) || (options.gid != null), unless: options.target === 'function' }); this.chmod({ target: options.target, stat: targetStat, mode: options.mode, "if": options.mode != null, unless: options.target === 'function' }); return this.then(callback); }; fs = require('ssh2-fs'); path = require('path'); eco = require('eco'); nunjucks = require('nunjucks/src/environment'); misc = require('../misc'); diff = require('../misc/diff'); string = require('../misc/string'); uid_gid = require('../misc/uid_gid');