Coverage

81%
513
418
95

conditions.js

95%
41
39
2
LineHitsSource
1// Generated by CoffeeScript 1.4.0
21var each, fs, path, _ref;
3
41fs = require('fs');
5
61path = require('path');
7
81if ((_ref = fs.exists) == null) {
90 fs.exists = path.exists;
10}
11
121each = require('each');
13
14/*
15Conditionnal properties
16*/
17
18
191module.exports = {
20 /*
21
22 `all(options, failed, succeed)` Run all conditions
23 ---------------------------------------------------
24
25 `opts`
26 Command options
27
28 `failed`
29 Failed callback, called when a condition failed
30
31 `succeed`
32 Succeed callback, only called if all the condition succeed
33 */
34
35 all: function(options, failed, succeed) {
3639 return each([this["if"], this.if_exists, this.not_if_exists]).on('item', function(next, condition) {
37116 return condition(options, failed, next);
38 }).on('error', failed).on('end', succeed);
39 },
40 /*
41 `if` Run action for a user defined condition
42 --------------------------------------------
43
44 Work on the property `if` in `options`. When `if`
45 is a boolean, its value determine to the output. If it's
46 a callback, the function is called with the `options`,
47 `failed` and `succeed` arguments. If it'a an array, all its element
48 must positively resolve for the condition to pass.
49
50 Updating the content of a file if we are the owner
51
52 mecano.render
53 source:'./file'
54 if: (options, failed, succeed) ->
55 fs.stat options.source, (err, stat) ->
56 # File does not exists
57 return failed err if err
58 # Failed if we dont own the file
59 return failed() unless stat.uid is process.getuid()
60 # Succeed if we own the file
61 succeed()
62 */
63
64 "if": function(options, failed, succeed) {
6545 var ok;
6645 if (options["if"] == null) {
6740 return succeed();
68 }
695 ok = true;
705 return each(options["if"]).on('item', function(next, si) {
715 if (!ok) {
720 return next();
73 }
745 if (typeof si === 'boolean') {
752 if (!si) {
761 ok = false;
77 }
782 return next();
793 } else if (typeof si === 'function') {
803 return si(options, (function() {
812 ok = false;
822 return next.apply(null, arguments);
83 }), next);
84 }
85 }).on('both', function(err) {
865 if (err || !ok) {
873 return failed(err);
88 }
892 return succeed();
90 });
91 },
92 /*
93
94 `if_exists` Run action if a file exists
95 ----------------------------------------
96
97 Work on the property `if_exists` in `options`. The value may
98 be a file path or an array of file paths.
99
100 The callback `succeed` is called if all the provided paths
101 exists otherwise the callback `failed` is called.
102 */
103
104 if_exists: function(options, failed, succeed) {
10544 if (options.if_exists == null) {
10638 return succeed();
107 }
1086 return each(options.if_exists).on('item', function(next, if_exists) {
1098 return fs.exists(if_exists, function(exists) {
1108 if (exists) {
1115 return next();
112 } else {
1133 return failed();
114 }
115 });
116 }).on('end', succeed);
117 },
118 /*
119
120 `not_if_exists` Skip action if a file exists
121 ---------------------------------------------
122
123 Work on the property `not_if_exists` in `options`. The value may
124 be a file path or an array of file paths.
125
126 The callback `succeed` is called if none of the provided paths
127 exists otherwise the callback `failed` is called.
128 */
129
130 not_if_exists: function(options, failed, succeed) {
13143 if (options.not_if_exists == null) {
13238 return succeed();
133 }
1345 return each(options.not_if_exists).on('item', function(next, not_if_exists) {
1357 return fs.exists(not_if_exists, function(exists) {
1367 if (exists) {
1373 return failed();
138 } else {
1394 return next();
140 }
141 });
142 }).on('end', succeed);
143 }
144};

mecano.js

80%
426
345
81
LineHitsSource
1// Generated by CoffeeScript 1.4.0
21var conditions, each, eco, exec, fs, mecano, misc, open, path, rimraf, util, _ref;
3
41fs = require('fs');
5
61path = require('path');
7
81if ((_ref = fs.exists) == null) {
90 fs.exists = path.exists;
10}
11
121util = require('util');
13
141each = require('each');
15
161eco = require('eco');
17
181rimraf = require('rimraf');
19
201exec = require('child_process').exec;
21
221open = require('open-uri');
23
241conditions = require('./conditions');
25
261misc = require('./misc');
27
28/*
29
30Mecano gather a set of functions usually used during system deployment. All the functions share a
31common API with flexible options.
32*/
33
34
351mecano = module.exports = {
36 /*
37
38 `cp` `copy(options, callback)`
39 ------------------------------
40
41 Copy a file.
42
43 `options` Command options include:
44
45 * `source` The file or directory to copy.
46 * `destination` Where the file or directory is copied.
47 * `force` Copy the file even if one already exists.
48 * `not_if_exists` Equals destination if true.
49 * `chmod` Permissions of the file or the parent directory
50
51 `callback` Received parameters are:
52
53 * `err` Error object if any.
54 * `copied` Number of files or parent directories copied.
55
56 todo:
57 * deal with directories
58 * preserve permissions if `chmod` is `true`
59 * Compare files with checksum
60 */
61
62 copy: function(options, callback) {
637 var copied;
647 options = misc.options(options);
657 copied = 0;
667 return each(options).on('item', function(next, options) {
677 var chmod, copy, dstStat, finish, source;
687 if (!options.source) {
690 return next(new Error('Missing source'));
70 }
717 if (!options.destination) {
720 return next(new Error('Missing destination'));
73 }
747 if (options.not_if_exists === true) {
750 options.not_if_exists = options.destination;
76 }
777 dstStat = null;
787 source = function() {
790 return fs.stat(options.source, function(err, stat) {
800 if (err) {
810 return next(err);
82 }
830 if (stat.isDirectory()) {
840 return next(new Error('Source is a directory'));
85 }
860 return copy();
87 });
88 };
897 copy = function(destination) {
909 if (destination == null) {
917 destination = options.destination;
92 }
939 return fs.stat(destination, function(err, stat) {
949 var dirExists, fileExists, input, output;
959 dstStat = stat;
969 if (err && err.code !== 'ENOENT') {
970 return next(err);
98 }
999 dirExists = !err && stat.isDirectory();
1009 fileExists = !err && stat.isFile();
1019 if (fileExists && !options.force) {
1022 return next(null, 0);
103 }
1047 if (dirExists) {
1052 return copy(path.resolve(options.destination, path.basename(options.source)));
106 }
1075 input = fs.createReadStream(options.source);
1085 output = fs.createWriteStream(destination);
1095 return util.pump(input, output, function(err) {
1105 if (err) {
1110 return next(err);
112 }
1135 return chmod();
114 });
115 });
116 };
1177 chmod = function() {
1185 if (!options.chmod || options.chmod === dstStat.mode) {
1195 return finish();
120 }
1210 return fs.chmod(options.destination, options.chmod, function(err) {
1220 if (err) {
1230 return next(err);
124 }
1250 return finish();
126 });
127 };
1287 finish = function() {
1295 copied++;
1305 return next();
131 };
1327 return conditions.all(options, next, copy);
133 }).on('both', function(err) {
1347 return callback(err, copied);
135 });
136 },
137 /*
138
139 `download(options, callback)`
140 -----------------------------
141
142 Download files using various protocols. The excellent
143 [open-uri](https://github.com/publicclass/open-uri) module provides support for HTTP(S),
144 file and FTP. All the options supported by open-uri are passed to it.
145
146 Note, GIT is not yet supported but documented as a wished feature.
147
148 `options` Command options include:
149
150 * `source` File, HTTP URL, FTP, GIT repository. File is the default protocol if source is provided without a scheme.
151 * `destination` Path where the file is downloaded.
152 * `force` Overwrite destination file if it exists.
153
154 `callback` Received parameters are:
155
156 * `err` Error object if any.
157 * `downloaded` Number of downloaded files
158
159 Basic example:
160 mecano.download
161 source: 'https://github.com/wdavidw/node-sigar/tarball/v0.0.1'
162 destination: 'node-sigar.tgz'
163 , (err, downloaded) ->
164 fs.exists 'node-sigar.tgz', (exists) ->
165 assert.ok exists
166 */
167
168 download: function(options, callback) {
1696 var downloaded;
1706 options = misc.options(options);
1716 downloaded = 0;
1726 return each(options).on('item', function(next, options) {
1736 var download, _ref1;
1746 if (!options.source) {
1750 return next(new Error("Missing source: " + options.source));
176 }
1776 if (!options.destination) {
1780 return next(new Error("Missing destination: " + options.destination));
179 }
1806 if ((_ref1 = options.force) == null) {
1816 options.force = false;
182 }
1836 download = function() {
1843 var destination;
1853 destination = fs.createWriteStream(options.destination);
1863 open(options.source, destination);
1873 destination.on('close', function() {
1883 downloaded++;
1893 return next();
190 });
1913 return destination.on('error', function(err) {
1920 return next(err);
193 });
194 };
1956 return fs.exists(options.destination, function(exists) {
1966 if (exists && !options.force) {
1973 return next();
1983 } else if (exists) {
1990 return rimraf(options.destination, function(err) {
2000 if (err) {
2010 return next(err);
202 }
2030 return download();
204 });
205 } else {
2063 return download();
207 }
208 });
209 }).on('both', function(err) {
2106 return callback(err, downloaded);
211 });
212 },
213 /*
214
215 `exec` `execute([goptions], options, callback)`
216 -----------------------------------------------
217 Run a command locally or with ssh if the `host` is provided. Global options is
218 optional and is used in case where options is defined as an array of
219 multiple commands. Note, `opts` inherites all the properties of `goptions`.
220
221 `goptions` Global options includes:
222
223 * `parallel` Wether the command are run in sequential, parallel
224 or limited concurrent mode. See the `node-each` documentation for more
225 details. Default to sequential (false).
226
227 `options` Include all conditions as well as:
228
229 * `cmd` String, Object or array; Command to execute.
230 * `env` Environment variables, default to `process.env`.
231 * `cwd` Current working directory.
232 * `uid` Unix user id.
233 * `gid` Unix group id.
234 * `code` Expected code(s) returned by the command, int or array of int, default to 0.
235 * `host` SSH host or IP address.
236 * `username` SSH host or IP address.
237 * `stdout` Writable EventEmitter in which command output will be piped.
238 * `stderr` Writable EventEmitter in which command error will be piped.
239
240 `callback` Received parameters are:
241
242 * `err` Error if any.
243 * `executed` Number of executed commandes.
244 * `stdout` Stdout value(s) unless `stdout` option is provided.
245 * `stderr` Stderr value(s) unless `stderr` option is provided.
246 */
247
248 execute: function(goptions, options, callback) {
24918 var escape, executed, isArray, stderrs, stdouts;
25018 if (arguments.length === 2) {
25118 callback = options;
25218 options = goptions;
253 }
25418 isArray = Array.isArray(options);
25518 options = misc.options(options);
25618 executed = 0;
25718 stdouts = [];
25818 stderrs = [];
25918 escape = function(cmd) {
2601 var char, esccmd, _i, _len;
2611 esccmd = '';
2621 for (_i = 0, _len = cmd.length; _i < _len; _i++) {
26320 char = cmd[_i];
26420 if (char === '$') {
2651 esccmd += '\\';
266 }
26720 esccmd += char;
268 }
2691 return esccmd;
270 };
27118 return each(options).parallel(goptions.parallel).on('item', function(next, option, i) {
27218 var cmd, cmdOption, _ref1;
27318 if (typeof option === 'string') {
2740 option = {
275 cmd: option
276 };
277 }
27818 misc.merge(true, option, goptions);
27918 if (option.cmd == null) {
2800 return next(new Error("Missing cmd: " + option.cmd));
281 }
28218 if ((_ref1 = option.code) == null) {
28317 option.code = [0];
284 }
28518 if (!Array.isArray(option.code)) {
2860 option.code = [option.code];
287 }
28818 cmdOption = {};
28918 cmdOption.env = option.env || process.env;
29018 cmdOption.cwd = option.cwd || null;
29118 if (options.uid) {
2920 cmdOption.uid = option.uid;
293 }
29418 if (options.gid) {
2950 cmdOption.gid = option.gid;
296 }
29718 cmd = function() {
29817 var run, stderr, stdout;
29917 if (option.host) {
3001 option.cmd = escape(option.cmd);
3011 option.cmd = option.host + ' "' + option.cmd + '"';
3021 if (option.username) {
3030 option.cmd = option.username + '@' + option.cmd;
304 }
3051 option.cmd = 'ssh -o StrictHostKeyChecking=no ' + option.cmd;
306 }
30717 run = exec(option.cmd, cmdOption);
30817 stdout = stderr = '';
30917 if (option.stdout) {
3101 run.stdout.pipe(option.stdout);
311 } else {
31216 run.stdout.on('data', function(data) {
31313 return stdout += data;
314 });
315 }
31617 if (option.stderr) {
3170 run.stderr.pipe(option.stderr);
318 } else {
31917 run.stderr.on('data', function(data) {
3205 return stderr += data;
321 });
322 }
32317 return run.on("exit", function(code) {
32417 return setTimeout(function() {
32517 var err;
32617 executed++;
32717 stdouts.push(option.stdout ? void 0 : stdout);
32817 stderrs.push(option.stderr ? void 0 : stderr);
32917 if (option.code.indexOf(code) === -1) {
3301 err = new Error("Invalid exec code " + code);
3311 err.code = code;
3321 return next(err);
333 }
33416 return next();
335 }, 1);
336 });
337 };
33818 return conditions.all(option, next, cmd);
339 }).on('both', function(err) {
34018 if (!isArray) {
34118 stdouts = stdouts[0];
342 }
34318 if (!isArray) {
34418 stderrs = stderrs[0];
345 }
34618 return callback(err, executed, stdouts, stderrs);
347 });
348 },
349 /*
350
351 `extract(options, callback)`
352 ----------------------------
353
354 Extract an archive. Multiple compression types are supported. Unless
355 specified asan option, format is derived from the source extension. At the
356 moment, supported extensions are '.tgz', '.tar.gz' and '.zip'.
357
358 `options` Command options include:
359
360 * `source` Archive to decompress.
361 * `destination` Default to the source parent directory.
362 * `format` One of 'tgz' or 'zip'.
363 * `creates` Ensure the given file is created or an error is send in the callback.
364 * `not_if_exists` Cancel extraction if file exists.
365
366 `callback` Received parameters are:
367
368 * `err` Error object if any.
369 * `extracted` Number of extracted archives.
370 */
371
372 extract: function(options, callback) {
37310 var extracted;
37410 options = misc.options(options);
37510 extracted = 0;
37610 return each(options).on('item', function(next, options) {
37710 var creates, destination, ext, extract, format, success, _ref1;
37810 if (!options.source) {
3790 return next(new Error("Missing source: " + options.source));
380 }
38110 destination = (_ref1 = options.destination) != null ? _ref1 : path.dirname(options.source);
38210 if (options.format != null) {
3830 format = options.format;
384 } else {
38510 if (/\.(tar\.gz|tgz)$/.test(options.source)) {
3865 format = 'tgz';
3875 } else if (/\.zip$/.test(options.source)) {
3884 format = 'zip';
389 } else {
3901 ext = path.extname(options.source);
3911 return next(new Error("Unsupported extension, got " + (JSON.stringify(ext))));
392 }
393 }
3949 extract = function() {
3958 var cmd;
3968 cmd = null;
3978 switch (format) {
398 case 'tgz':
3994 cmd = "tar xzf " + options.source + " -C " + destination;
4004 break;
401 case 'zip':
4024 cmd = "unzip -u " + options.source + " -d " + destination;
403 }
4048 return exec(cmd, function(err, stdout, stderr) {
4058 if (err) {
4060 return next(err);
407 }
4088 return creates();
409 });
410 };
4119 creates = function() {
4128 if (options.creates == null) {
4136 return success();
414 }
4152 return fs.exists(options.creates, function(exists) {
4162 if (!exists) {
4171 return next(new Error("Failed to create '" + (path.basename(options.creates)) + "'"));
418 }
4191 return success();
420 });
421 };
4229 success = function() {
4237 extracted++;
4247 return next();
425 };
4269 return conditions.all(options, next, extract);
427 }).on('both', function(err) {
42810 return callback(err, extracted);
429 });
430 },
431 /*
432
433 `git`
434 -----
435
436 `options` Command options include:
437
438 * `source` Git source repository address.
439 * `destination` Directory where to clone the repository.
440 * `revision` Git revision, branch or tag.
441 */
442
443 git: function(options, callback) {
4445 var updated;
4455 options = misc.options(options);
4465 updated = 0;
4475 return each(options).on('item', function(next, options) {
4485 var checkout, clone, log, prepare, rev, _ref1;
4495 if ((_ref1 = options.revision) == null) {
4503 options.revision = 'HEAD';
451 }
4525 rev = null;
4535 prepare = function() {
4545 return fs.stat(options.destination, function(err, stat) {
4555 var gitDir;
4565 if (err && err.code === 'ENOENT') {
4572 return clone();
458 }
4593 if (!stat.isDirectory()) {
4600 return next(new Error("Destination not a directory, got " + options.destination));
461 }
4623 gitDir = "" + options.destination + "/.git";
4633 return fs.stat(gitDir, function(err, stat) {
4643 if (err || !stat.isDirectory()) {
4650 return next(err);
466 }
4673 return log();
468 });
469 });
470 };
4715 clone = function() {
4722 return mecano.exec({
473 cmd: "git clone " + options.source + " " + (path.basename(options.destination)),
474 cwd: path.dirname(options.destination)
475 }, function(err, executed, stdout, stderr) {
4762 if (err) {
4770 return next(err);
478 }
4792 return checkout();
480 });
481 };
4825 log = function() {
4833 return mecano.exec({
484 cmd: "git log --pretty=format:'%H' -n 1",
485 cwd: options.destination
486 }, function(err, executed, stdout, stderr) {
4873 var current;
4883 if (err) {
4890 return next(err);
490 }
4913 current = stdout.trim();
4923 return mecano.exec({
493 cmd: "git rev-list --max-count=1 " + options.revision,
494 cwd: options.destination
495 }, function(err, executed, stdout, stderr) {
4963 if (err) {
4970 return next(err);
498 }
4993 if (stdout.trim() !== current) {
5001 return checkout();
501 } else {
5022 return next();
503 }
504 });
505 });
506 };
5075 checkout = function() {
5083 return mecano.exec({
509 cmd: "git checkout " + options.revision,
510 cwd: options.destination
511 }, function(err) {
5123 if (err) {
5130 return next(err);
514 }
5153 updated++;
5163 return next();
517 });
518 };
5195 return conditions.all(options, next, prepare);
520 }).on('both', function(err) {
5215 return callback(err, updated);
522 });
523 },
524 /*
525
526 `ln` `link(options, callback)`
527 ------------------------------
528 Create a symbolic link and it's parent directories if they don't yet
529 exist.
530
531 `options` Command options include:
532
533 * `source` Referenced file to be linked.
534 * `destination` Symbolic link to be created.
535 * `exec` Create an executable file with an `exec` command.
536 * `chmod` Default to 0755.
537
538 `callback` Received parameters are:
539
540 * `err` Error object if any.
541 * `linked` Number of created links.
542 */
543
544 link: function(options, callback) {
5458 var exec_create, exec_exists, linked, option, parents, sym_create, sym_exists;
5468 options = misc.options(options);
5478 linked = 0;
5488 sym_exists = function(option, callback) {
5497 return fs.exists(option.destination, function(exists) {
5507 if (!exists) {
5515 return callback(null, false);
552 }
5532 return fs.readlink(option.destination, function(err, resolvedPath) {
5542 if (err) {
5550 return callback(err);
556 }
5572 if (resolvedPath === option.source) {
5582 return callback(null, true);
559 }
5600 return fs.unlink(option.destination, function(err) {
5610 if (err) {
5620 return callback(err);
563 }
5640 return callback(null, false);
565 });
566 });
567 });
568 };
5698 sym_create = function(option, callback) {
5705 return fs.symlink(option.source, option.destination, function(err) {
5715 if (err) {
5720 return callback(err);
573 }
5745 linked++;
5755 return callback();
576 });
577 };
5788 exec_exists = function(option, callback) {
5790 return fs.exists(option.destination, function(exists) {
5800 if (!exists) {
5810 return callback(null, false);
582 }
5830 return fs.readFile(option.destination, 'ascii', function(err, content) {
5840 var exec_cmd;
5850 if (err) {
5860 return callback(err);
587 }
5880 exec_cmd = /exec (.*) \$@/.exec(content)[1];
5890 return callback(null, exec_cmd && exec_cmd === option.source);
590 });
591 });
592 };
5938 exec_create = function(option, callback) {
5940 var content;
5950 content = "#!/bin/bash\nexec " + option.source + " $@";
5960 return fs.writeFile(option.destination, content, function(err) {
5970 if (err) {
5980 return callback(err);
599 }
6000 return fs.chmod(option.destination, option.chmod, function(err) {
6010 if (err) {
6020 return callback(err);
603 }
6040 linked++;
6050 return callback();
606 });
607 });
608 };
6098 parents = (function() {
6108 var _i, _len, _results;
6118 _results = [];
6128 for (_i = 0, _len = options.length; _i < _len; _i++) {
6139 option = options[_i];
6149 _results.push(path.normalize(path.dirname(option.destination)));
615 }
6168 return _results;
617 })();
6188 return mecano.mkdir(parents, function(err, created) {
6198 if (err) {
6200 return callback(err);
621 }
6228 return each(options).parallel(true).on('item', function(next, option) {
6239 var dispatch, _ref1;
6249 if (!option.source) {
6251 return next(new Error("Missing source, got " + (JSON.stringify(option.source))));
626 }
6278 if (!option.destination) {
6281 return next(new Error("Missing destination, got " + (JSON.stringify(option.destination))));
629 }
6307 if ((_ref1 = option.chmod) == null) {
6317 option.chmod = 0x1ed;
632 }
6337 dispatch = function() {
6347 if (option.exec) {
6350 return exec_exists(option, function(err, exists) {
6360 if (exists) {
6370 return next();
638 }
6390 return exec_create(option, next);
640 });
641 } else {
6427 return sym_exists(option, function(err, exists) {
6437 if (exists) {
6442 return next();
645 }
6465 return sym_create(option, next);
647 });
648 }
649 };
6507 return dispatch();
651 }).on('both', function(err) {
6528 return callback(err, linked);
653 });
654 });
655 },
656 /*
657
658 `mkdir(options, callback)`
659 --------------------------
660
661 Recursively create a directory. The behavior is similar to the Unix command `mkdir -p`.
662 It supports an alternative syntax where options is simply the path of the directory
663 to create.
664
665 `options` Command options include:
666
667 * `source` Path or array of paths.
668 * `directory` Shortcut for `source`
669 * `exclude` Regular expression.
670 * `chmod` Default to 0755.
671 * `cwd` Current working directory for relative paths.
672
673 `callback` Received parameters are:
674
675 * `err` Error object if any.
676 * `created` Number of created directories
677
678 Simple usage:
679
680 mecano.mkdir './some/dir', (err, created) ->
681 console.log err?.message ? created
682 */
683
684 mkdir: function(options, callback) {
68538 var created;
68638 options = misc.options(options);
68738 created = 0;
68838 return each(options).on('item', function(next, option) {
68939 var check, create, cwd, _ref1;
69039 if (typeof option === 'string') {
69134 option = {
692 source: option
693 };
694 }
69539 if (!(option.source != null) && (option.directory != null)) {
6965 option.source = option.directory;
697 }
69839 cwd = (_ref1 = option.cwd) != null ? _ref1 : process.cwd();
69939 option.source = path.resolve(cwd, option.source);
70039 if (option.source == null) {
7010 return next(new Error('Missing source option'));
702 }
70339 check = function() {
70439 return fs.stat(option.source, function(err, stat) {
70539 if (err && err.code === 'ENOENT') {
70631 return create();
707 }
7088 if (err) {
7090 return next(err);
710 }
7118 if (stat.isDirectory()) {
7128 return next();
713 }
7140 return next(err('Invalid source, got #{JSON.encode(option.source)}'));
715 });
716 };
71739 create = function() {
71831 var current, dirCreated, dirs, _ref2;
71931 if ((_ref2 = option.chmod) == null) {
72031 option.chmod = 0x1ed;
721 }
72231 current = '';
72331 dirCreated = false;
72431 dirs = option.source.split('/');
72531 return each(dirs).on('item', function(next, dir) {
726290 if ((option.exclude != null) && option.exclude instanceof RegExp) {
72712 if (option.exclude.test(dir)) {
7281 return next();
729 }
730 }
731289 current += "/" + dir;
732289 return fs.exists(current, function(exists) {
733289 if (exists) {
734255 return next();
735 }
73634 return fs.mkdir(current, option.chmod, function(err) {
73734 if (err) {
7380 return next(err);
739 }
74034 dirCreated = true;
74134 return next();
742 });
743 });
744 }).on('both', function(err) {
74531 if (dirCreated) {
74631 created++;
747 }
74831 return next(err);
749 });
750 };
75139 return check();
752 }).on('both', function(err) {
75338 return callback(err, created);
754 });
755 },
756 /*
757
758 `rm` `remove(options, callback)`
759 --------------------------------
760
761 Recursively remove a file or directory. Internally, the function
762 use the [rimraf](https://github.com/isaacs/rimraf) library.
763
764 `options` Command options include:
765
766 * `source` File or directory.
767
768 `callback` Received parameters are:
769
770 * `err` Error object if any.
771 * `deleted` Number of deleted sources.
772
773 Example
774
775 mecano.rm './some/dir', (err, removed) ->
776 console.log "#{removed} dir removed"
777
778 Removing a directory unless a given file exists
779
780 mecano.rm
781 source: './some/dir'
782 not_if_exists: './some/file'
783 , (err, removed) ->
784 console.log "#{removed} dir removed"
785
786 Removing multiple files and directories
787
788 mecano.rm [
789 { source: './some/dir', not_if_exists: './some/file' }
790 './some/file'
791 ], (err, removed) ->
792 console.log "#{removed} dirs removed"
793 */
794
795 remove: function(options, callback) {
79626 var deleted;
79726 options = misc.options(options);
79826 deleted = 0;
79926 return each(options).on('item', function(next, options) {
80026 if (typeof options === 'string') {
80125 options = {
802 source: options
803 };
804 }
80526 if (options.source == null) {
8060 return next(new Error('Missing source: #{option.source}'));
807 }
80826 return fs.lstat(options.source, function(err, stat) {
80926 var _ref1;
81026 if (err) {
8110 return next();
812 }
81326 if ((_ref1 = options.options) == null) {
81426 options.options = {};
815 }
81626 return rimraf(options.source, function(err) {
81726 if (err) {
8180 return next(err);
819 }
82026 deleted++;
82126 return next();
822 });
823 });
824 }).on('both', function(err) {
82526 return callback(err, deleted);
826 });
827 },
828 /*
829
830 `render(options, callback)`
831 ---------------------------
832
833 Render a template file At the moment, only the
834 [ECO](http://github.com/sstephenson/eco) templating engine is integrated.
835
836 `options` Command options include:
837
838 * `engine` Template engine to use, default to "eco"
839 * `content` Templated content, bypassed if source is provided.
840 * `source` File path where to extract content from.
841 * `destination` File path where to write content to.
842 * `context` Map of key values to inject into the template.
843
844 `callback` Received parameters are:
845
846 * `err` Error object if any.
847 * `rendered` Number of rendered files.
848 */
849
850 render: function(options, callback) {
8513 var rendered;
8523 options = misc.options(options);
8533 rendered = 0;
8543 return each(options).on('item', function(next, option) {
8553 var readSource, writeContent;
8563 if (!(option.source || option.content)) {
8570 return next(new Error('Missing source or content'));
858 }
8593 if (!option.destination) {
8600 return next(new Error('Missing destination'));
861 }
8623 readSource = function() {
8633 if (!option.source) {
8641 return writeContent();
865 }
8662 return fs.exists(option.source, function(exists) {
8672 if (!exists) {
8681 return next(new Error("Invalid source, got " + (JSON.stringify(option.source))));
869 }
8701 return fs.readFile(option.source, function(err, content) {
8711 if (err) {
8720 return next(err);
873 }
8741 option.content = content;
8751 return writeContent();
876 });
877 });
878 };
8793 writeContent = function() {
8802 var content;
8812 try {
8822 content = eco.render(option.content.toString(), option.context || {});
883 } catch (err) {
8840 return next(err);
885 }
8862 return fs.writeFile(option.destination, content, function(err) {
8872 if (err) {
8880 return next(err);
889 }
8902 rendered++;
8912 return next();
892 });
893 };
8943 return readSource();
895 }).on('both', function(err) {
8963 return callback(err, rendered);
897 });
898 }
899};
900
9011mecano.cp = mecano.copy;
902
9031mecano.exec = mecano.execute;
904
9051mecano.ln = mecano.link;
906
9071mecano.rm = mecano.remove;

misc.js

73%
46
34
12
LineHitsSource
1// Generated by CoffeeScript 1.4.0
2
31module.exports = {
4 /*
5 `isPortOpen(port, host, callback)`: Check if a port is already open
6 */
7
8 isPortOpen: function(port, host, callback) {
90 if (arguments.length === 2) {
100 callback = host;
110 host = '127.0.0.1';
12 }
130 return exec("nc " + host + " " + port + " < /dev/null", function(err, stdout, stderr) {
140 if (!err) {
150 return callback(null, true);
16 }
170 if (err.code === 1) {
180 return callback(null, false);
19 }
200 return callback(err);
21 });
22 },
23 /*
24 `merge([inverse], obj1, obj2, ...]`: Recursively merge objects
25 --------------------------------------------------------------
26 On matching keys, the last object take precedence over previous ones
27 unless the inverse arguments is provided as true. Only objects are
28 merge, arrays are overwritten.
29
30 Enrich an existing object with a second one:
31 obj1 = { a_key: 'a value', b_key: 'b value'}
32 obj2 = { b_key: 'new b value'}
33 result = misc.merge obj1, obj2
34 assert.eql result, obj1
35 assert.eql obj1.b_key, 'new b value'
36
37 Create a new object from two objects:
38 obj1 = { a_key: 'a value', b_key: 'b value'}
39 obj2 = { b_key: 'new b value'}
40 result = misc.merge {}, obj1, obj2
41 assert.eql result.b_key, 'new b value'
42
43 Using inverse:
44 obj1 = { b_key: 'b value'}
45 obj2 = { a_key: 'a value', b_key: 'new b value'}
46 misc.merge true, obj1, obj2
47 assert.eql obj1.a_key, 'a value'
48 assert.eql obj1.b_key, 'b value'
49 */
50
51 merge: function() {
5225 var clone, copy, from, i, inverse, name, options, src, target, to, _i;
5325 target = arguments[0];
5425 from = 1;
5525 to = arguments.length;
5625 if (typeof target === 'boolean') {
5722 inverse = !!target;
5822 target = arguments[1];
5922 from = 2;
60 }
6125 if (typeof target !== "object" && typeof target !== 'function') {
620 target = {};
63 }
6425 for (i = _i = from; from <= to ? _i < to : _i > to; i = from <= to ? ++_i : --_i) {
6526 if ((options = arguments[i]) !== null) {
6626 for (name in options) {
6758 src = target[name];
6858 copy = options[name];
6958 if (target === copy) {
700 continue;
71 }
7258 if ((copy != null) && typeof copy === 'object' && !Array.isArray(copy)) {
732 clone = src && (src && typeof src === 'object' ? src : {});
742 target[name] = this.merge(false, clone, copy);
7556 } else if (copy !== void 0) {
7656 if (!(inverse && typeof target[name] !== 'undefined')) {
7721 target[name] = copy;
78 }
79 }
80 }
81 }
82 }
8325 return target;
84 },
85 /*
86 `options(options)` Normalize options
87 */
88
89 options: function(options) {
90121 var option, _i, _len;
91121 if (!Array.isArray(options)) {
92112 options = [options];
93 }
94121 for (_i = 0, _len = options.length; _i < _len; _i++) {
95123 option = options[_i];
96123 if ((option["if"] != null) && !Array.isArray(option["if"])) {
970 option["if"] = [option["if"]];
98 }
99123 if ((option.if_exists != null) && !Array.isArray(option.if_exists)) {
1002 option.if_exists = [option.if_exists];
101 }
102123 if ((option.not_if_exists != null) && !Array.isArray(option.not_if_exists)) {
1031 option.not_if_exists = [option.not_if_exists];
104 }
105 }
106121 return options;
107 }
108};