Open apps using node.js spawn - node.js

I'm trying to do a little application with node.js that would run on mac and execute some commands.
I've successfully used spawn to run command lines such as xcodebuild, but xcrun doesn't seems to work when I try to open the iOS Simulator.
I can open on terminal by typing:
xcrun instruments -w 'iPhone 5s (9.2)' -t <template>
But if I use node and try to use spawn like this:
var args = ['instruments', '-w', `iPhone 5s (9.2)`, '-t', 'noTemp'];
var xcrun = spawn('xcrun', args);
So it got me thinking that maybe it had some limitation opening apps? I tried to run:
var args = ['/Applications/Spotify.app'];
var xcrun = spawn('open', args);
And nothing happens. I couldn't find anything related to that. My question is: is there anyway to open apps using node.js spawn? If there is, does someone know what's the problem with my code?
Here's the full code if needed:
var args = ['instruments', '-w', `${fullDevice}`, '-t', 'noTemp'];
var xcrun = spawn('xcrun', args);
xcrun.stdout.on('data', (data)=>{
console.log(data.toString('utf8'));
})
xcrun.on('close', (code) => {
socket.emit({
time: commands.getCurrentTime(),
type: 'success',
log: 'Device booted...'
});
callback();
if (code !== 0) {
console.log(`open process exited with code ${code}`);
}
});
OBS: if I run this piece of code the application doesn't terminate, the program doesn't continue and nothing happens.
EDIT: Changed:
xcrun.on('data', (data)=>{
To:
xcrun.stdout.on('data', (data)=>{

Spawned processes have two separate streams for stdout and stderr, so you will need to listen for data on those objects and not the spawned process object itself:
xcrun.stdout.on('data', function(data) {
console.log('stdout: ' + data.toString());
});
xcrun.stderr.on('data', function(data) {
console.log('stderr: ' + data.toString());
});

The problem was one line above. Not sure why, but there's a socket.emit call that is wrong and actually hold the program's execution.

Related

Command not called, anything wrong with this spawn syntax?

When i run this pidof command by hand, it works. Then put into my server.js.
// send signal to start the install script
var spw = cp.spawn('/sbin/pidof', ['-x', 'wait4signal.py', '|', 'xargs', 'kill', '-USR1']);
spw.stderr.on('data', function(data) {
res.write('----- Install Error !!! -----\n');
res.write(data.toString());
console.log(data.toString());
});
spw.stdout.on('data', function(data) {
res.write('----- Install Data -----\n');
res.write(data.toString());
console.log(data.toString());
});
spw.on('close', function(data) {
res.end('----- Install Finished, please to to status page !!! -----\n');
console.log('88');
});
In the web i only see "----- Install Finished, please to to status page !!!". My install script seems never get this USR1 signal. Anything wrong please ?
The problem is that you have two separate commands. You are piping the output of your /sbin/pidof command to the input stream of your xargs command. If you are using spawn (rather than exec, which a string exactly as you would write on the command line), you need to spawn one process per command.
Spawn your processes like this:
const pidof = spawn('/sbin/pidof', ['-x', 'wait4signal.py']);
const xargs = spawn('xargs', ['kill', '-USR1']);
Now pipe the output of the first process to the input of the second, like so:
pidof.stdout.pipe(xargs.stdin);
Now you can listen to events on your xargs process, like so:
xargs.stdout.on('data', data => {
console.log(data.toString());
});

Node.js spawn of Blender command-line?

I need blender command-line access though spawn but keep running into an ENOENT error and it is hard to pinpoint what is missing. The command-line being passed in the sample application works in terminal.
Below are some details about the environment and the sample script I am using.
Environment (OSX El Capitan)
Installed Blender 2.76b with:
brew install Caskroom/cask/blender
Then add alias to bash_profile for terminal access:
alias blender="/Applications/blender/Blender.app/Contents/MacOS/blender"
Test Code
#!/usr/bin/env node
var child_process = require('child_process');
var arguments = [
'-b',
'recipe.blend',
'-o', 'test-#',
'-f', 0
];
console.log("values: ", arguments);
var child = child_process.spawn('blender', arguments);
child.stdout.on('data', function(data) {
console.log('data out: ', data.toString());
});
child.stderr.on('data', function(data) {
console.error('error out: ',data);
});
child.on('close', function(code) {
console.log('closing code: ' + code);
});
// Raw command-line for terminal. (PASS)
// blender -b recipe.blend -o test-# -f 0
Try changing the child_process.spawn('blender', arguments); line to child_process.spawn('/Applications/blender/Blender.app/Contents/MacOS/blender', arguments);. NodeJS won't be using your bash aliases, so unless the blender executable is in its PATH it won't be able to find the executable and will throw an ENOENT.
The other option is adjusting Node's PATH to include the path to the blender executable. You could also pass the fullpath to the blender executable in as an environment variable.
Cheers!

Node JS: Executing command lines and getting outputs asynchronously

How can I run a command line and get the outputs as soon as available to show them somewhere.
For example if a run ping command on a linux system, it will never stop, now is it possible to get the responses while the command is still processing ?
Or let's take apt-get install command, what if i want to show the progress of the installation as it is running ?
Actually i'm using this function to execute command line and get outputs, but the function will not return until the command line ends, so if i run a ping command it will never return!
var sys = require('sys'),
exec = require('child_process').exec;
function getOutput(command,callback){
exec(
command,
(
function(){
return function(err,data,stderr){
callback(data);
}
}
)(callback)
);
}
Try using spawn instead of exec, then you can tap into the stream and listen to the data and end events.
var process = require('child_process');
var cmd = process.spawn(command);
cmd.stdout.on('data', function(output){
console.log(output.toString()):
});
cmd.on('close', function(){
console.log('Finished');
});
//Error handling
cmd.stderr.on('data', function(err){
console.log(err);
});
See the Node.js documentation for spawn here: https://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options

How to respond to a command line promt with node.js

How would I respond to a command line prompt programmatically with node.js? For example, if I do process.stdin.write('sudo ls'); The command line will prompt for a password. Is there an event for 'prompt?'
Also, how do I know when something like process.stdin.write('npm install') is complete?
I'd like to use this to make file edits (needed to stage my app), deploy to my server, and reverse those file edits (needed for eventually deploying to production).
Any help would rock!
You'll want to use child_process.exec() to do this rather than writing the command to stdin.
var sys = require('sys'),
exec = require('child_process').exec;
// execute the 'sudo ls' command with a callback function
exec('sudo ls', function(error, stdout, stderr){
if (!error) {
// print the output
sys.puts(stdout);
} else {
// handle error
}
});
For the npm install one you might be better off with child_process.spawn() which will let you attach an event listener to run when the process exits. You could do the following:
var spawn = require('child_process').spawn;
// run 'npm' command with argument 'install'
// storing the process in variable npmInstall
var npmInstall = spawn('npm', ['install'], {
cwd: process.cwd(),
stdio: 'inherit'
});
// listen for the 'exit' event
// which fires when the process exits
npmInstall.on('exit', function(code, signal) {
if (code === 0) {
// process completed successfully
} else {
// handle error
}
});

Redirecting output to a log file using node.js

I have a child process that I am using as follows in node.js. Instead of redirecting the output to the console I would like to put the output in a log file located somewhere on the machine this is running on (and should work for both windows and mac).
The code below is what I am using and I would like to output the files into a log file. What changes needed to do that here? Thanks!
My Code:
var spawn = require('child_process').spawn,
ls = spawn('ls', ['-lh', '/usr']);
ls.stdout.on('data', function (data) {
console.log('stdout: ' + data);
});
ls.stderr.on('data', function (data) {
console.log('stderr: ' + data);
});
ls.on('close', function (code) {
console.log('child process exited with code ' + code);
});
Here's an example of logging to file using streams.
var logStream = fs.createWriteStream('./logFile.log', {flags: 'a'});
var spawn = require('child_process').spawn,
ls = spawn('ls', ['-lh', '/usr']);
ls.stdout.pipe(logStream);
ls.stderr.pipe(logStream);
ls.on('close', function (code) {
console.log('child process exited with code ' + code);
});
There are two ways you can achieve this, one is using
let logConsoleStream = fs.createWriteStream('./logConsoleFile.log', {flags: 'a'});
let logErrorStream = fs.createWriteStream('./logErrorFile.log', {flags: 'a'});
and redirect all logs or errors using this
ls.stdout.pipe(logConsoleStream ); // redirect stdout/logs only
ls.stderr.pipe(logErrorStream ); // redirect error logs only
by separating log files you will have separate files for Error logs and console logs
this is exactly same as generalhenry shared above
And Second Way for Achieving this with the help of Command Line
when you execute node app from the command line
node app/src/index.js
you can specify here where you want to redirect logs and Errors from this application
there are three stream redirection commands using the command line
`>` It will redirect your only stdout or logs to the specified path
`2>` It will redirect your errors logs to the specified path
`2>&1 ` It will redirect all your stdout and stderr to a single file
example: how you will use these commands
node app/src/index.js > ./logsOnly.txt
node app/src/index.js 2> ./ErrorsOnly.txt
node app/src/index.js 2>&1 ./consoleLogsAndErrors.txt
I hope someone coming later finds this helpful
if there is I done wrong way please do let me know it will help me and others
Thanks
If you run your JS script with forever then you have the option to define a log file as parameter which will handle all your console.log messages. Not to mention the benefit of keeping your nodejs app live permanently.
Alternatively try this:
sudo forever start myapp.js 2>&1 /home/someuser/myapp/myapp.log
use forever with below options
forever start -o out.log -e err.log server.js
The best answer was in the comments and is mentioned in a previous question here: stackoverflow.com/questions/2496710/nodejs-write-to-file
It is as follows:
var fs = require('fs');
fs.writeFile("/tmp/test", "Hey there!", function(err) {
if(err) {
console.log(err);
} else {
console.log("The file was saved!");
}
});

Resources