Executing Command in Nodejs and Attaching the output to the console - node.js

I'm working on a CLI tool to add an extra layer of automation and utilities to our workflow and I'm wrapping the webpack development command with an alternative in my CLI (here's a demonstration):-
function runDev(){
this.doSomePreAutomationAndPreperations();
this.runWebpackDevCommand();
}
I'm using NodeJs child_proecess.exec and I'm trying to figure out a way to execute the webpack dev command and attach it to the terminal (like -it in docker if you're familiar with it) or transferring the control to the child process(so output will be directly emitted to the console).
Is there away to do that?

It turns out that I can achieve this but just making the child process inherit the stdio. ex:-
const { spawn } = require('child_process')
const shell = spawn('sh',[], { stdio: 'inherit' })
shell.on('close',(code)=>{console.log('[shell] terminated :',code)})

Related

Getting continuous info on the console when executing a command launched from within node

I have the following file exec-deploy.js
// exec-deploy.js
const exec = require('child_process').exec
exec("npm run deploy", (err, stdout, stderr) => console.log(stdout))
npm run deploy, when invoked from command line, prints a lot of data while it executes providing me with info about the progress of the deploy.
If I execute exec-deploy with node exec-deploy I do see all information only at the end of the execution, printed in one shot on the console.
Is it possible to get a continuous flow of info on the terminal even when I execute the npm script from within javascript?
After some reading of the official documentation and of this interesting article I found the solution for my problem, which consists in using spawn instead of exec specifying the following options
spawn('npm run deploy', null, {
stdio: 'inherit',
shell: true,
});

Run a binary from Node.JS and relay the behavior exactly on the console, including prompts

I'm making a cli tool with Node.JS. I run another binary file from within node, and the other process asks for a password at some point.
So what I need is to simply launch the other process, and put it "in charge" of the terminal, so the other process handles the prompts and the console output.
You can use 'inherit' for the stdio option of spawn:
const spawn = require( 'child_process' ).spawn;
spawn( '/path/to/binary', [], { stdio: 'inherit' } );

Can't spawn `gcloud app deploy` from a Node.js script on Windows

I'm building an Electron application (Node.js) which needs to spawn gcloud app deploy from the application with realtime feedback (stdin/stdout/stderr).
I rapidly switched from child_process to execa because I had some issues on Mac OS X with the child_process buffer which is limited to 200kb (and gcloud app deploy sends some big chunk of string > 200kb which crash the command).
Now, with execa everything seems to work normally on OSX but not on Windows.
The code looks something like this:
let bin = `gcloud${/^win/.test(process.platform) ? '.cmd' : ''}`
//which: https://github.com/npm/node-which
which(bin, (err, fullpath) => {
let proc = execa(fullpath, ['app', 'deploy'], {
cwd: appPath
})
proc.stdout.on('data', data => {
parseDeploy(data.toString())
})
proc.stderr.on('data', data => {
parseDeploy(data.toString())
})
proc.then(() => {
...
}).catch(e => {
...
})
})
This code works perfectly on Mac OS X while I haven't the same result on Windows
I have tried lots of thing:
execa()
execa.shell()
options shell:true
I tried maxBuffer to 1GB (just in case)
It works with detached:true BUT I can't read stdout / stderr in realtime in the application as it prompts a new cmd.exe without interaction with the Node.js application
Lots of child_process variant.
I have made a GIST to show the responses I get for some tests I have done on Windows with basic Child Process scripts:
https://gist.github.com/thyb/9b53b65c25cd964bbe962d8a9754e31f
I also opened an issue on execa repository: https://github.com/sindresorhus/execa/issues/97
Does someone already got this issue ? I've searched around and found nothing promising except this reddit thread which doesn't solve this issue.
Behind the scene, gcloud.cmd is running a python script. After reading tons of Node.js issue with ChildProcess / Python and Windows, I fell on this thread: https://github.com/nodejs/node-v0.x-archive/issues/8298
There is some known issue about running Python scripts from a Node.js Child Process.
They talk in this comment about an unbuffered option for python. After updating the shell script in gcloud.cmd by adding the -u option, I noticed everything was working as expected
This comment explains how to set this option as an environment variable (to not modify the windows shell script directly): https://docs.python.org/2/using/cmdline.html#envvar-PYTHONUNBUFFERED
So adding PYTHONUNBUFFERED to the environment variable fix this issue !
execa(fullpath, ['app', 'deploy'], {
cwd: appPath,
env: Object.assign({}, process.env, {
PYTHONUNBUFFERED: true
})
})

How to start a process in node.js that thinks its being run from the commandline

I'm running require('child_process').exec('npm install') as a child process in a node.js script, but I want it to retain console colors. I'm running in windows, but want this script to be portable (e.g. to linux). How do I start a process that think's it's being run from the console?
Note: I'd rather not have npm-specific answers, but an answer that allows me to trick any command.
You can do this by letting the child process inherit the master process' stdio streams. This means you need to user spawn rather than exec, and this what you'd do:
var spawn = require('child_process').spawn;
var child = spawn('npm', ['install'], {
stdio: 'inherit'
});

calling child_process.exec in Node as though it was executed in a specific folder

I'm using the following to execute a CLI command in nodeJS
var cp = require('child_process');
cp.exec('foocommand', callback);
However, the foocommand is executing in the current folder node is running from. How can I make it execute as though it is being invoked from a different folder?
Its in the docs:
var cp = require('child_process');
cp.exec('foocommand', { cwd: 'path/to/dir/' }, callback);
Not a total expert but if its a cli then you want to be able to use stdin witch is not available with process.exec. Maybe you want to see if there is a programable interface for the cli?

Resources