--- /dev/null
+/*
+ * grunt
+ * http://gruntjs.com/
+ *
+ * Copyright (c) 2016 "Cowboy" Ben Alman
+ * Licensed under the MIT license.
+ * https://github.com/gruntjs/grunt/blob/master/LICENSE-MIT
+ */
+
+'use strict';
+
+// Nodejs libs.
+var spawn = require('child_process').spawn;
+var nodeUtil = require('util');
+var path = require('path');
+
+// The module to be exported.
+var util = module.exports = {};
+
+util.namespace = require('getobject');
+
+// External libs.
+util.hooker = require('hooker');
+util.async = require('async');
+var _ = util._ = require('lodash');
+var which = require('which').sync;
+// Instead of process.exit. See https://github.com/cowboy/node-exit
+util.exit = require('exit');
+
+// Mixin Underscore.string methods.
+_.str = require('underscore.string');
+_.mixin(_.str.exports());
+
+// Return a function that normalizes the given function either returning a
+// value or accepting a "done" callback that accepts a single value.
+util.callbackify = function(fn) {
+ return function callbackable() {
+ // Invoke original function, getting its result.
+ var result = fn.apply(this, arguments);
+ // If the same number or less arguments were specified than fn accepts,
+ // assume the "done" callback was already handled.
+ var length = arguments.length;
+ if (length === fn.length) { return; }
+ // Otherwise, if the last argument is a function, assume it is a "done"
+ // callback and call it.
+ var done = arguments[length - 1];
+ if (typeof done === 'function') { done(result); }
+ };
+};
+
+// Create a new Error object, with an origError property that will be dumped
+// if grunt was run with the --debug=9 option.
+util.error = function(err, origError) {
+ if (!nodeUtil.isError(err)) { err = new Error(err); }
+ if (origError) { err.origError = origError; }
+ return err;
+};
+
+// The line feed char for the current system.
+util.linefeed = process.platform === 'win32' ? '\r\n' : '\n';
+
+// Normalize linefeeds in a string.
+util.normalizelf = function(str) {
+ return str.replace(/\r\n|\n/g, util.linefeed);
+};
+
+// What "kind" is a value?
+// I really need to rework https://github.com/cowboy/javascript-getclass
+var kindsOf = {};
+'Number String Boolean Function RegExp Array Date Error'.split(' ').forEach(function(k) {
+ kindsOf['[object ' + k + ']'] = k.toLowerCase();
+});
+util.kindOf = function(value) {
+ // Null or undefined.
+ if (value == null) { return String(value); }
+ // Everything else.
+ return kindsOf[kindsOf.toString.call(value)] || 'object';
+};
+
+// Coerce something to an Array.
+util.toArray = _.toArray;
+
+// Return the string `str` repeated `n` times.
+util.repeat = function(n, str) {
+ return new Array(n + 1).join(str || ' ');
+};
+
+// Given str of "a/b", If n is 1, return "a" otherwise "b".
+util.pluralize = function(n, str, separator) {
+ var parts = str.split(separator || '/');
+ return n === 1 ? (parts[0] || '') : (parts[1] || '');
+};
+
+// Recurse through objects and arrays, executing fn for each non-object.
+util.recurse = function(value, fn, fnContinue) {
+ function recurse(value, fn, fnContinue, state) {
+ var error;
+ if (state.objs.indexOf(value) !== -1) {
+ error = new Error('Circular reference detected (' + state.path + ')');
+ error.path = state.path;
+ throw error;
+ }
+ var obj, key;
+ if (fnContinue && fnContinue(value) === false) {
+ // Skip value if necessary.
+ return value;
+ } else if (util.kindOf(value) === 'array') {
+ // If value is an array, recurse.
+ return value.map(function(item, index) {
+ return recurse(item, fn, fnContinue, {
+ objs: state.objs.concat([value]),
+ path: state.path + '[' + index + ']',
+ });
+ });
+ } else if (util.kindOf(value) === 'object' && !Buffer.isBuffer(value)) {
+ // If value is an object, recurse.
+ obj = {};
+ for (key in value) {
+ obj[key] = recurse(value[key], fn, fnContinue, {
+ objs: state.objs.concat([value]),
+ path: state.path + (/\W/.test(key) ? '["' + key + '"]' : '.' + key),
+ });
+ }
+ return obj;
+ } else {
+ // Otherwise pass value into fn and return.
+ return fn(value);
+ }
+ }
+ return recurse(value, fn, fnContinue, {objs: [], path: ''});
+};
+
+// Spawn a child process, capturing its stdout and stderr.
+util.spawn = function(opts, done) {
+ // Build a result object and pass it (among other things) into the
+ // done function.
+ var callDone = function(code, stdout, stderr) {
+ // Remove trailing whitespace (newline)
+ stdout = _.rtrim(stdout);
+ stderr = _.rtrim(stderr);
+ // Create the result object.
+ var result = {
+ stdout: stdout,
+ stderr: stderr,
+ code: code,
+ toString: function() {
+ if (code === 0) {
+ return stdout;
+ } else if ('fallback' in opts) {
+ return opts.fallback;
+ } else if (opts.grunt) {
+ // grunt.log.error uses standard out, to be fixed in 0.5.
+ return stderr || stdout;
+ }
+ return stderr;
+ }
+ };
+ // On error (and no fallback) pass an error object, otherwise pass null.
+ done(code === 0 || 'fallback' in opts ? null : new Error(stderr), result, code);
+ };
+
+ var cmd, args;
+ var pathSeparatorRe = /[\\\/]/g;
+ if (opts.grunt) {
+ cmd = process.execPath;
+ args = process.execArgv.concat(process.argv[1], opts.args);
+ } else {
+ // On Windows, child_process.spawn will only file .exe files in the PATH,
+ // not other executable types (grunt issue #155).
+ try {
+ if (!pathSeparatorRe.test(opts.cmd)) {
+ // Only use which if cmd has no path component.
+ cmd = which(opts.cmd);
+ } else {
+ cmd = opts.cmd.replace(pathSeparatorRe, path.sep);
+ }
+ } catch (err) {
+ callDone(127, '', String(err));
+ return;
+ }
+ args = opts.args || [];
+ }
+
+ var child = spawn(cmd, args, opts.opts);
+ var stdout = new Buffer('');
+ var stderr = new Buffer('');
+ if (child.stdout) {
+ child.stdout.on('data', function(buf) {
+ stdout = Buffer.concat([stdout, new Buffer(buf)]);
+ });
+ }
+ if (child.stderr) {
+ child.stderr.on('data', function(buf) {
+ stderr = Buffer.concat([stderr, new Buffer(buf)]);
+ });
+ }
+ child.on('close', function(code) {
+ callDone(code, stdout.toString(), stderr.toString());
+ });
+ return child;
+};