ninjs-lodash
Version:
lodash wrapper + utils
196 lines (152 loc) • 6.66 kB
JavaScript
/**
* Child Process Utils
*/
const _ = require('lodash')
const child_process = require("child_process")
const libs = require('./libs')
const core = require('./core')
const config = require('./config')
const debug = require('./debug')
const CMD_DEFAULTS = _.$('cmd.defaults')
const SWITCH_DELIMITER = _.$('cli.switch.delimiter')
const SWITCH_DELIMITER_VALS = _.$('cli.switch.delimiters')
exports = module.exports = {
cwd: _cwd,
swargs: swargs,
oargs: oargs,
cmdstr: cmdstr,
exec: exec,
execFile: execFile
}
_.mixin(exports)
// ~~~~~ CHILD PROCESS V2 ~~~~~~
// returns cwd with first cli args/settings/options/process.cwd
function _cwd(options) {
return _.get(options, 'cwd') || _.get(options, 'prefix') || process.cwd()
}
// returns Array -> cli switch args from object k:v pairs
function swargs(obj) {
// let mobj = _.merge(_.isPlainObject(obj) ? obj : {}, _.$('jav.sw') || {})
let mobj = _.merge(_.isPlainObject(obj) ? obj : {}, {})
return _.compact(_.map(mobj, (v, k) => {
// _.log(`-->${v}<--`)
v = _.isArray(v) ? _.join(_.compact(v), ',') : v
const vCool = !_.isEmpty(v) || _.isBoolean(v) || _.isNumber(v)
return k && vCool ? `--${k}=${v}` : k || vCool ? `--${k || v}` : ''
})) || []
}
// returns args + cli args
function oargs(options) { return _.concat(_.get(options, 'args') || [], swargs(_.get(options, 'sw'))) }
// returns String -> cmd + join(args, ' ')
function cmdstr(cmd, args) {
cmd = cmd && _.isString(cmd) ? cmd : ''
args = args && _.isArray(args) ? _.compact(args) : []
if(cmd) args.unshift(cmd)
return _.join(args, ' ')
}
// child_process.exec(command[, options][, callback])
function exec(options, callback) {
let cmd = _.get(options, 'cmd')
if(!cmd || !_.isString(cmd)) return _.fail('Invalid cmd', callback)
let cwd = _cwd(options)
let args = oargs(options)
let outData = ''
let errData = ''
cmd = cmdstr(cmd, args)
// console.log(`\nExec : ${cmd} ${_.join(args, ' ')} \nCWD : ${cwd}\n`)
let child = child_process.exec(cmd, { cwd: cwd }, function() {
return _.done({ err: _.trim(errData), result: _.trim(outData) }, callback)
})
child.stdout.on('data', function(data) {
outData += (_.isBuffer(data) ? data.toString('utf8') : data)
})
child.stderr.on('data', function(data) {
errData += (_.isBuffer(data) ? data.toString('utf8') : data)
})
return child
}
// child_process.execFile(file[, args][, options][, callback])
function execFile(options, callback) {
let cmd = _.get(options, 'cmd')
if(!cmd || !_.isString(cmd)) return _.fail('Invalid cmd', callback)
let cwd = _cwd(options)
let args = oargs(options)
let outData = ''
let errData = ''
let child = child_process.execFile(cmd, args, { cwd: cwd }, function() {
return _.done({ err: _.trim(errData), result: _.trim(outData) }, callback)
})
child.stdout.on('data', function(data) {
outData += (_.isBuffer(data) ? data.toString('utf8') : data)
})
child.stderr.on('data', function(data) {
errData += (_.isBuffer(data) ? data.toString('utf8') : data)
})
return child
}
// ~~~~~ CHILD PROCESS V1 ~~~~~~
// // child_process.exec(command[, options][, callback])
// function exec(options, callback) {
// return cmd(_.assign(options, { type:'exec' } ), _.cb(callback))
// }
// // child_process.execFile(file[, args][, options][, callback])
// function execFile(options, callback) {
// return cmd(_.assign(options, { type:'execFile' } ), _.cb(callback))
// }
// runs exec or exexfile
// 'modules.writePaths': { cmd: 'node', args: ['test', 'modules.writePaths'], switches: { dest: _.path.join(TEMP_PATH, 'paths.json') } },
// function cmd(options, callback) {
// let opts = _.merge({}, CMD_DEFAULTS, options)
// let { cmd='', type='', heads, args=[], lasts, switches={}, switch_del='--' } = opts
// let switchDelValid = switch_del && _.isString(switch_del) && _.includes(SWITCH_DELIMITER_VALS, switch_del) ? true : false
// let jav = _.jav()
// switch_del = switchDelValid ? switch_del : SWITCH_DELIMITER
// type = type && _.isString(type) && _.includes(['exec', 'execFile'], type) ? type : 'exec'
// // all args -> easier defaults
// // cwd> cmd [heads ...] [args...] [lasts....] [--switchk=switchv ...]
// heads = heads && _.isArray(heads) ? heads : []
// args = args && _.isArray(args) ? args : []
// lasts = args && _.isArray(lasts) ? lasts : []
// switches = switches && _.isPlainObject(switches) ? _.merge(switches, _.get(jav, 'sw')) || {} : {}
// let method = _.get(cproc, type)
// // if(!cmd || !_.isString(cmd)) return _.fail('Invalid cmd', callback)
// if(!_.isFunction(method)) return _.fail('Invalid type', callback)
// args = _.concat(heads, args, lasts)
// _.forIn(switches, (v, k) => {
// if(!v && !k) return
// let arg = v && k ? `--${k}=${v}` : `--${k || v}`
// if(arg) args.push(arg)
// })
// args = _.compact(args)
// let isExec = type === 'exec'
// _.assign(opts, { args: args })
// opts = _.omit(opts, ['type', 'heads', 'lasts', 'switches', ''])
// // exec does not take args argument like execFile
// // -> must join args with ' ' and append to cmd prop to create command
// if(isExec) cmd = _.join(_.compact([cmd, _.join(args, ' ')]), ' ')
// let cb = (err, stdout, stderr) => {
// if(err) return _.fail(err, callback)
// _.done({ stdout: stdout, stderr: stderr }, callback)
// }
// const child = isExec ? _.attempt(method, cmd, opts, cb) : _.attempt(method, cmd, args, opts, cb)
// return child
// //return _handleChild(child, _.cb(callback))
// }
// handles newly created child process via cproc.exec OR cprop.execFile
// ** child.on('close', (code) => {}) is basically the only event that is called
// ** use stdout/stderr to handle fail/done on 'close' event !!!
// function _handleChild(child, callback) {
// if(!child) return _.fail('Invalid child process', callback)
// if(_.isError(child)) return _.fail(child, callback)
// let stdout = ''
// let stderr = ''
// child.stdout.on('data', function(data) { stdout += data })
// child.stderr.on('data', function(data) { stderr += data })
// child.on('close', function(code) { return _.done(stdout || stderr, callback) })
// child.on('disconnect', function(err) {})
// child.on('error', function(err) { })
// child.on('exit', function(code, signal) { })
// child.on('message', function(message, sendHandle) { })
// return child
// }