2015-09-01 10:31:00 +03:00
|
|
|
/*
|
|
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Copyright (c) 2015, Joyent, Inc.
|
|
|
|
*/
|
|
|
|
|
|
|
|
var assert = require('assert-plus');
|
2015-09-22 01:48:03 +03:00
|
|
|
var execFile = require('child_process').execFile;
|
2015-09-01 10:31:00 +03:00
|
|
|
var VError = require('verror').VError;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ---- exports
|
|
|
|
|
|
|
|
/**
|
|
|
|
* A convenience wrapper around `child_process.exec` to take away some
|
|
|
|
* logging and error handling boilerplate.
|
|
|
|
*
|
|
|
|
* @param args {Object}
|
2015-09-22 01:48:03 +03:00
|
|
|
* - command {String|Array} Required.
|
2015-09-01 10:31:00 +03:00
|
|
|
* - log {Bunyan Logger} Required. Use to log details at trace level.
|
|
|
|
* - execOpts {Array} Optional. child_process.exec options.
|
|
|
|
* - errMsg {String} Optional. Error string to use in error message on
|
|
|
|
* failure.
|
|
|
|
* @param cb {Function} `function (err, stdout, stderr)` where `err` here is
|
|
|
|
* an `VError` wrapper around the child_process error.
|
|
|
|
*/
|
|
|
|
function execPlus(args, cb) {
|
|
|
|
assert.object(args, 'args');
|
|
|
|
assert.optionalString(args.errMsg, 'args.errMsg');
|
|
|
|
assert.optionalObject(args.execOpts, 'args.execOpts');
|
|
|
|
assert.object(args.log, 'args.log');
|
|
|
|
assert.func(cb);
|
|
|
|
var command = args.command;
|
|
|
|
var execOpts = args.execOpts;
|
2015-09-22 01:48:03 +03:00
|
|
|
if (typeof (command) === 'string')
|
|
|
|
command = ['/bin/sh', '-c', command];
|
2015-09-01 10:31:00 +03:00
|
|
|
|
2015-09-22 01:48:03 +03:00
|
|
|
execFile(command[0], command.slice(1), execOpts,
|
|
|
|
function (err, stdout, stderr) {
|
2015-09-01 10:31:00 +03:00
|
|
|
args.log.trace({exec: true, command: command, execOpts: execOpts,
|
|
|
|
err: err, stdout: stdout, stderr: stderr}, 'exec done');
|
|
|
|
if (err) {
|
2015-10-07 09:09:52 +03:00
|
|
|
var niceErr = new VError(err,
|
2015-09-01 10:31:00 +03:00
|
|
|
'%s:\n'
|
|
|
|
+ '\tcommand: %s\n'
|
|
|
|
+ '\texit status: %s\n'
|
|
|
|
+ '\tstdout:\n%s\n'
|
|
|
|
+ '\tstderr:\n%s',
|
|
|
|
args.errMsg || 'exec error', command, err.code,
|
2015-10-07 09:09:52 +03:00
|
|
|
stdout.trim(), stderr.trim());
|
|
|
|
niceErr.code = err.code;
|
|
|
|
cb(niceErr, stdout, stderr);
|
2015-09-01 10:31:00 +03:00
|
|
|
} else {
|
|
|
|
cb(null, stdout, stderr);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Calls t.ifError, outputs the error body for diagnostic purposes, and
|
|
|
|
* returns true if there was an error
|
|
|
|
*/
|
|
|
|
function ifErr(t, err, desc) {
|
|
|
|
t.ifError(err, desc);
|
|
|
|
if (err) {
|
|
|
|
t.deepEqual(err.body, {}, desc + ': error body');
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
module.exports = {
|
|
|
|
execPlus: execPlus,
|
|
|
|
ifErr: ifErr
|
|
|
|
};
|