UNPKG

wsemi

Version:

A support package for web developer.

286 lines (240 loc) 9.19 kB
import cp from 'child_process' import get from 'lodash-es/get.js' import isearr from './isearr.mjs' import isbol from './isbol.mjs' import isfun from './isfun.mjs' import isestr from './isestr.mjs' import genPm from './genPm.mjs' import strleft from './strleft.mjs' import strright from './strright.mjs' /** * 呼叫執行檔執行 * * Unit Test: {@link https://github.com/yuda-lyu/wsemi/blob/master/test/execProcess.test.mjs Github} * @memberOf wsemi * @param {String} prog 輸入執行檔或程式語言位置字串,若為註冊系統的全域指令,例如可直接給'Python',腳本需自行接收呼叫引數,並將回傳資料轉json字串後print/log到dos視窗,即可由nodejs接收 * @param {String|Array} args 輸入腳本檔案位置字串或參數 * @param {Object} [opt={}] 輸入設定物件 * @param {Function} [opt.cbStdout=null] 輸入回調stdout函數,預設null * @param {Function} [opt.cbStderr=null] 輸入回調stderr函數,預設null * @param {String} [opt.codeCmd='big5'] 輸入讀回程序的stdout與stderr回應的解碼字串,為當前作業系統語系,預設'big5' * @returns {Promise} 回傳Promise,resolve回傳成功訊息,reject回傳錯誤訊息 * @example * //need test in nodejs * * if (true) { * let prog = 'prog.exe' * let args = 'input' * execProcess(prog, args) * .then(function(data) { * console.log('then', data) * }) * .catch(function(data) { * console.log('catch', data) * }) * } * * if (true) { * let prog = `"C:\\Program Files\\7-Zip\\7z.exe"` * let pw = 'AbcD1234' * let args = `a aaa.7z aaa.txt -p${pw}` * execProcess(prog, args) * .then(function(data) { * console.log('then', data) * }) * .catch(function(data) { * console.log('catch', data) * }) * } * */ function execProcess(prog, args, opt = {}) { //check if (!isearr(args) && !isestr(args)) { throw new Error(`args is not an effective array or string`) } if (isestr(args)) { args = [args] } //mode // spawn: 非同步執行命令,適合處理大量資料或長時間執行的程式,輸出以串流方式處理。spawnSync 為 spawn 的同步版本。 // exec: 在 shell 中非同步執行命令,輸出被緩衝,適合輸出量較小的情況。execSync 為 exec 的同步版本。 // execFile: 直接執行可執行檔案,不經過 shell,非同步執行,適合執行已知的可執行檔案。execFileSync 為 execFile 的同步版本。 let mode = get(opt, 'mode') if (mode !== 'spawn' && mode !== 'exec' && mode !== 'execFile') { mode = 'spawn' } // console.log('mode',mode) //cbStdout let cbStdout = get(opt, 'cbStdout') //cbStderr let cbStderr = get(opt, 'cbStderr') //codeCmd let codeCmd = get(opt, 'codeCmd') if (!isestr(codeCmd)) { codeCmd = 'utf8' } //useChcp let useChcp = get(opt, 'useChcp') if (!isbol(useChcp)) { useChcp = false } //pm let pm = genPm() //cmsg, cerr let cmsg = '' let cerr = '' //r let r = null if (mode === 'spawn') { // console.log('mode',mode) let cr = strleft(prog, 1) let cl = strright(prog, 1) if (cr === `"` || cl === `"` || cr === `'` || cl === `'`) { throw new Error('prog of spawn doens not need to add quotes') } r = cp.spawn(prog, args, { encoding: codeCmd, shell: false }) //spwan的prog與args內檔案, 都不需要用單/雙引號括住, 已內建處理機制, 額外添加單/雙引號會導致錯誤 } else if (mode === 'exec') { // console.log('mode',mode) let cpre = '' if (useChcp) { cpre = `cmd /c chcp 65001>nul &&` } // console.log(`${cpre} ${prog} ${args.join(' ')} & exit`) r = cp.exec(`${cpre} ${prog} ${args.join(' ')} & exit`, { encoding: codeCmd }) } else if (mode === 'execFile') { // console.log('mode',mode) r = cp.execFile(prog, args, { encoding: codeCmd }) } else { throw new Error(`invalid mode[${mode}]`) } //stdout data r.stdout.on('data', data => { // console.log('stdout chunk:', data.toString().trim()) //cdata let cdata = data.toString().trim() //megre cmsg += cdata + '\n' //cbStdout if (isfun(cbStdout)) { cbStdout(cdata) } }) //stderr data r.stderr.on('data', data => { // console.error('stderr chunk:', data.toString().trim()) //cdata let cdata = data.toString().trim() //megre cerr += cdata + '\n' //cbStderr if (isfun(cbStderr)) { cbStderr(cdata) } }) // //exit, 會比close先觸發故不使用 // r.on('exit', (code) => { // // console.log('exit code', code) // }) //close r.on('close', code => { // console.log('close code', code) // if (code !== 0) { // pm.reject(`code=${code} and stderr='${cerr}'`) // } // else if(isestr(cerr)){ // pm.reject(cerr) // } if (isestr(cerr)) { pm.reject(cerr) } else { pm.resolve(cmsg) } }) //error r.on('error', (err) => { pm.reject(err) }) return pm } // function execProcess2(prog, args, opt = {}) { // //cbStdout // let cbStdout = get(opt, 'cbStdout') // //cbStderr // let cbStderr = get(opt, 'cbStderr') // //codeCmd // let codeCmd = get(opt, 'codeCmd') // if (!isestr(codeCmd)) { // codeCmd = 'big5' // } // return new Promise(function(resolve, reject) { // let msg = '' // //spawn: 非同步執行命令,適合處理大量資料或長時間執行的程式,輸出以串流方式處理。spawnSync 為 spawn 的同步版本。 // //exec: 在 shell 中非同步執行命令,輸出被緩衝,適合輸出量較小的情況。execSync 為 exec 的同步版本。 // //execFile: 直接執行可執行檔案,不經過 shell,非同步執行,適合執行已知的可執行檔案。execFileSync 為 execFile 的同步版本。 // //exec // //不能用同步版execSync, 須提供cpu控制權給調用端, 才能驅動例如偵測檔案等進行額外顯示 // //執行程序時會使用當前作業系統語系, 故回傳時得要依照當前語系進行指定解碼, 才不會有亂碼 // let r = cp.exec(`${prog} ${args}`, { encoding: 'buffer' }, (err, stdout, stderr) => { // //check // if (err) { // // console.log('err',err) // // err = iconv.decode(err, codeCmd) //err是當前作業系統語系且編碼過, 若出現err則編碼為big5而非buffer, 故不能decode // // console.log('err(decode)',err) // return reject(err) // } // try { // // console.log('stdout', stdout) // stdout = iconv.decode(stdout, codeCmd) // // console.log('stdout(decode)', stdout) // } // catch (err) {} // try { // // console.log('stderr', stderr) // stderr = iconv.decode(stderr, codeCmd) // // console.log('stderr(decode)', stderr) // } // catch (err) {} // //stderr, 若stderr與stdout同時有, 則先添加stderr再添加stdout // if (isestr(stderr)) { // // console.log('stderr', stderr) // msg += stderr // } // //stdout // if (isestr(stdout)) { // // console.log('stdout', stdout) // msg += stdout // } // }) // // //exit, 會比close先觸發 // // r.on('exit', (code) => { // // // console.log('exit code', code) // // }) // //close // r.on('close', (code) => { // // console.log('close code', code) // resolve(msg) // }) // //cbStdout // if (isfun(cbStdout)) { // r.stdout.on('data', function (data) { // data = iconv.decode(data, codeCmd) // // console.log('stdout', data) // cbStdout(data) // }) // } // //cbStderr // if (isfun(cbStderr)) { // r.stderr.on('data', function (data) { // data = iconv.decode(data, codeCmd) // // console.log('stderr', data) // cbStderr(data) // }) // } // }) // } export default execProcess