UNPKG

hay-caf

Version:

Haystacks Cloud Automation Framework: A demonstration testing automation framework application for the purposes of demonstrating the usage and integration of D-CAF, Hest, Hexiom, HayRunner, HayMonkey, and HayD-CAG in a single testing automation framework

230 lines (205 loc) 9.71 kB
/** * @file darwinSpawnedProcess.js * @module darwinSpawnedProcess * @description Creates the shell to execute the given command on MacOs and Linux. * @requires module:application.message.constants * @requires module:application.system.constants * @requires {@link https://www.npmjs.com/package/@haystacks/constants|@haystacks/constants} * @requires {@link https://nodejs.dev/learn/the-nodejs-fs-module|fs} * @requires {@link https://www.npmjs.com/package/tmp|tmp} * @requires {@link https://nodejs.dev/learn/the-nodejs-process-module|process} * @requires {@link https://nodejs.dev/learn/the-nodejs-child_process-module|child_process} * @requires {@link https://www.npmjs.com/package/path|path} * @author Karl-Edward FP Jean-Mehu * @date 2023/01/02 * @copyright Copyright © 2023-… by Karl-Edward FP Jean-Mehu. All rights reserved. */ // Internal imports import * as app_msg from '../../constants/application.message.constants.js'; import * as app_sys from '../../constants/application.system.constants.js'; // External imports import hayConst from '@haystacks/constants'; import fs from 'fs'; import tmp from 'tmp'; import process from 'process'; import childProcess from 'child_process'; import path from 'path'; const { bas, gen, msg, num, sys, wrd } = hayConst; const baseFileName = path.basename(import.meta.url, path.extname(import.meta.url)); // framework.childProcess.shells. const namespacePrefix = wrd.cframework + bas.cDot + wrd.cchild + wrd.cProcess + bas.cDot + wrd.cshells + bas.cDot + baseFileName + bas.cDot; // Checks whether the provided Shell executable exists and is executable function isExecutableExists(pathToShellExecutable) { // let functionName = isExecutableExists.name; // console.log(msg.cBEGIN_Space + namespacePrefix + functionName + msg.cSpaceFunction); // pathToShellExecutable is: // console.log(app_msg.cPathToShellExecutableIs + pathToShellExecutable); let returnData = false; try { // Check if the file exists fs.accessSync(pathToShellExecutable, fs.constants.X_OK); returnData = true; // File exists and is executable } catch (err) { if (err.code === gen.cENOENT || err.code === gen.cEACCES) { returnData = false; // File does not exist or is not executable } else { throw err; // Other error, rethrow it } } // console.log(msg.creturnDataIs + returnData); // console.log(msg.cEND_Space + namespacePrefix + functionName + msg.cSpaceFunction); return returnData; } /** * @function shell * @description Creates temporary shell and executes given command. * @param {string} shellCommandToRun The command to be executed. * @param {string} [options.shell = "powershell|cmd|bash"] Optional. Options to change behavior how shell is executed * @param {function(arg1)=} callback Optional callback to send data back to spawnedProcess * @return {void} * @author Karl-Edward FP Jean-Mehu * @date 2023/01/02 */ export async function shell(shellCommandToRun, options, callback) { // let functionName = shell.name; // console.log(msg.cBEGIN_Space + namespacePrefix + functionName + msg.cSpaceFunction); // shellCommandToRun is: // console.log(app_msg.cshellCommandToRunIs + shellCommandToRun); // options are: // console.log(msg.coptionsAre + options); // Shell object let shellScript = null; // File options for temporary shell script. const tempFileOptions = { mode: 0o755, postfix: gen.cDotsh, tmpdir: bas.cDot + bas.cForwardSlash, keep: true, }; try { if (typeof shellCommandToRun == 'undefined') { // Shell command not defined throw new Error(app_msg.cshellCommandNotDefined); } // Sets the shell used to invoke the desired command based on the user selected shell. let spawnOptions; let scriptContent = shellCommandToRun; switch(options.shell){ case sys.cpowershell: spawnOptions = [gen.csh, []] // Ensure powershell prompt appears before proceeding // shellCommandToRun =`Start-Sleep -Seconds 3 // Clear-Host // ${shellCommandToRun} // `; shellCommandToRun = app_sys.cStartDashSleep + bas.cSpace + app_sys.cDashSeconds + bas.cSpace + num.c3 + bas.cCarRetNewLin + app_sys.cClearDashHost + bas.cCarRetNewLin + shellCommandToRun; // Powershell command to execute commands // scriptContent = ` // #!/usr/bin/env bash // osascript -e 'tell application "Terminal" // if not (exists window 1) then reopen // activate // do script "clear -x; pwsh -NoExit -Command ${shellCommandToRun}" in window 1 // end tell' // `.trim(); // Closes the window 3 seconds // after the command completes // `; Start-Sleep -Seconds 3; Exit`; shellCommandToRun = shellCommandToRun + bas.cSemiColon + bas.cSpace + app_sys.cStartDashSleep + bas.cSpace + app_sys.cDashSeconds + bas.cSpace + num.c3 + bas.cSemiColon + bas.cSpace + wrd.cExit; scriptContent = app_sys.cDarwinScriptContentLine1 + app_sys.cDarwinScriptContentLine2 + app_sys.cDarwinScriptContentLine3 + app_sys.cDarwinScriptContentLine4 + app_sys.cDarwinScriptContentPowershellLineA + shellCommandToRun + app_sys.cDarwinScriptContentLine5B + app_sys.cDarwinScriptContentLine6; break; case sys.cbash: // Closes the window 3 seconds // after the command completes // `; sleep 3; exit`; shellCommandToRun = shellCommandToRun + bas.cSemiColon + bas.cSpace + wrd.csleep + bas.cSpace + num.c3 + bas.cSemiColon + bas.cSpace + wrd.cexit; spawnOptions = [gen.csh, []] // scriptContent = ` // #!/usr/bin/env bash // osascript -e 'tell application "Terminal" // if not (exists window 1) then reopen // activate // do script "clear -x; ${shellCommandToRun}" in window 1 // end tell' // `.trim(); scriptContent = app_sys.cDarwinScriptContentLine1 + app_sys.cDarwinScriptContentLine2 + app_sys.cDarwinScriptContentLine3 + app_sys.cDarwinScriptContentLine4 + app_sys.cDarwinScriptContentBashLineA + shellCommandToRun + app_sys.cDarwinScriptContentLine5B + app_sys.cDarwinScriptContentLine6; break; default: // Selected shell not found. throw new Error(app_msg.cselectedShellNotFound); } // Write shell script to temporary shell file shellScript = tmp.fileSync(tempFileOptions); fs.writeFile(shellScript.fd, scriptContent, gen.cUTF8, async (error) => { // Close temp file handle await fs.close(shellScript.fd); if (error) { // Error creating the tmp file // console.log(app_msg.cerrorCreatingTheTmpFile + error); } else { // Tmp file successfully written: // console.log(app_msg.cTmpFileSuccessfullyWritten + shellScript.name); // await callback(shellScript.name); // Call the callback function to pass back the name of the script file. if (process[wrd.csend]) { process.send({[wrd.cName]: shellScript.name}); } // Ensure the use of a single shell instance let child; if (child && !child.killed) { child.stdin.write(scriptContent + bas.cBackSlash + bas.cn, gen.cUTF8, (err) => { if (err) { console.log(err); } }); } else { // Add temporary file to options spawnOptions[1].push(shellScript.name); // Check and proceed if the temporary file has successfully been written child = childProcess.spawn(spawnOptions[0], ...spawnOptions.slice(1), { stdio: wrd.cpipe, cwd: options.CAFfeinatedPath }); // Handles actions taken when errors occurs on child process child.on(wrd.cerror, async (error) => { // let eventName = bas.cDot + wrd.cerror; // console.log(msg.cBEGIN_Space + namespacePrefix + functionName + eventName + msg.cSpaceEvent); console.log(msg.cerrorIs + error); // Error from child: if (process[wrd.csend]) process.send(bas.cCarRetNewLin + msg.cErrorFromChildColon + error); // console.log(msg.cEND_Space + namespacePrefix + functionName + eventName +msg.cSpaceEvent); }); child.on(wrd.cdisconnect, async () => { // let eventName = bas.cDot + wrd.cdisconnect; // console.log(msg.cBEGIN_Space + namespacePrefix + functionName + eventName + msg.cSpaceEvent); if (process[wrd.csend]) process.send(bas.cCarRetNewLin + msg.cChildDisconnected); // console.log(msg.cEND_Space + namespacePrefix + functionName + eventName +msg.cSpaceEvent); }); child.on(wrd.cexit, async (code, signal) => { // let eventName = bas.cDot + wrd.cexit; // console.log(msg.cBEGIN_Space + namespacePrefix + functionName + eventName + msg.cSpaceEvent); // console.log(msg.ccodeIs + code); // console.log(msg.csignalIs + signal); // Exiting child process if (process[wrd.csend]) process.send(bas.cCarRetNewLin + msg.cExitingChildProcess); // console.log(msg.cEND_Space + namespacePrefix + functionName + eventName +msg.cSpaceEvent); }); } } }); } catch (error) { // Error on shell: console.log(msg.cErrorOnShell + error.message) } // console.log(msg.cEND_Space + namespacePrefix + functionName + msg.cSpaceFunction); }