shell command to child_process.spawn(command, [args], [options]) node.js - javascript

Basically, I just want to run rsync command on node app.
The raw rsync code is the below:
rsync -r -t -p -o -g -v --progress --delete -l -H /Users/ken/Library/Application Support/Sublime Text 3/Packages /Users/ken/Google Drive/__config-GD/ST3
Firstly, I tried
child_process.exec(command, [options], callback)
but, since the rsync output is long, the buffer exceeded.
So, I tried
child_process.spawn(command, [args], [options])
instead, and stream.pipe out.
var spawn = require('child_process')
.spawn;
var ps = spawn(command1, args1)
.stdout
.pipe(process.stdout);
Although this works as expected, it is way too hard to split every original rsync command to the spawn format. (I copied and paste the command from gRsync tool)
Is there smart way to do this?
Thanks.

Ok, here is the hack;
Escape white space of the MacDirectory in the terminal shell and javascript/node is very tricky, so I placed _#_ instead of \('\'+whiteSpace).
(function()
{
'use strict';
//,,,,,,,,,,,,,,
var parseShCmd = function(cmd)
{
var cmdA = cmd.split(/ /);
console.log(cmdA);
var cmd1 = cmdA[0];
var args1 = [];
cmdA.map(function(s, i)
{
if (i === 0)
{
console.log('-------------------'); //do nothing
}
else
{
args1[i - 1] = cmdA[i].replace(/_#_/g, ' ');
}
});
return [cmd1, args1];
};
var shCmd = 'rsync' +
' -r -t -p -o -g -v --progress --delete -l -H ' +
'/Users/ken/Library/Application_#_Support/Sublime_#_Text_#_3/Packages ' +
'/Users/ken/Google_#_Drive/__config-GD/ST3';
//var shCmd = 'ls -la';
var cmd1 = parseShCmd(shCmd);
console.log(cmd1[0]);
console.log(cmd1[1]);
console.log('==================');
var spawn = require('child_process')
.spawn;
var ps = spawn(cmd1[0], cmd1[1])
.stdout
.pipe(process.stdout);
//,,,,,,,,,,,,,,,,
}());

Related

Getting a blank cmd prompt on running a bat file in nodejs

I am trying to run a .bat file by passing arguments to it in nodejs. However, I get an empty command prompt. How to get the command pasted on the path.
code -
server.js
var bat = require.resolve('E:/API_Gateway_through_Swagger/New_Project/aws-bat-file-3.bat');
var num = "123"
var state_desc = "abc";
var ls = spawn(bat, [num, state_desc ]);
ls.stdout.on('data', function (data) {
console.log('stdout: ' + data);
});
ls.stderr.on('data', function (data) {
console.log('stderr: ' + data);
});
ls.on('exit', function (code) {
console.log('child process exited with code ' + code);
});
Bat file -
aws-bat-file-3.bat
echo off
echo "Batch Started"
set arg1=%1
set arg2=%2
START "Task Options" cmd.exe /b " cd C:\Users\myfolder & aws apigateway create deployment --rest-api-id %arg1% --stage-name dev --stage-description %arg2%"
output img file is -
NodeJS documented the problem of spawning batch files on Windows thoroughly in this section.
Excerpt:
When running on Windows, .bat and .cmd files can be invoked using child_process.spawn() with the shell option set, with child_process.exec(), or by spawning cmd.exe and passing the .bat or .cmd file as an argument (which is what the shell option and child_process.exec() do).
const bat = spawn('"my script.cmd"', ['a', 'b'], { shell: true });

How to have cli-spinner run during ShellJS command exec?

I'm currently trying to make a simple command-line node program that allows for me to easily create a boilerplate for a lot of the React/Redux applications that I make. I'm using ShellJS to execute console commands (I've tried using Node's child_process, too.) The problem is getting cli-spinner to work with executing terminal commands. Here's my code:
#! /usr/bin/env node
var shell = require('shelljs');
var userArgs = process.argv.slice(2);
var folderName = userArgs[0];
var Spinner = require('cli-spinner').Spinner;
var depSpin = new Spinner('Installing dependencies.. %s');
depSpin.setSpinnerString(10);
shell.mkdir(folderName);
shell.cd(folderName);
depSpin.start();
// I expect for the spinner to start here (before the execution of the commands.)
shell.exec('npm init -y', {silent: true});
shell.exec('npm install --save babel-core babel-loader babel-preset-es2015 babel-preset-react react-dom react-redux redux webpack', {silent: true});
shell.exec('npm install --save-dev babel-preset-env webpack-dev-server', {silent: true});
depSpin.stop();
// Since ShellJS should run synchronously,
// the spinner should stop right after the last command finishes.
shell.touch('webpack.config.js');
shell.mkdir(['build', 'frontend']);
shell.cd('frontend');
shell.mkdir(['components', 'containers', 'reducers', 'store']);
shell.touch('app.js');
But when running the program, it just hangs without displaying anything while it installs the dependencies. It's the same as when the spinner code wasn't even in there. I've also tried removing the depSpin.stop(), which just makes the program hang forever on the spinner. I have a feeling that this issue is caused by a conflict between cli-spinner and ShellJS both using the terminal.
I was able to accomplish this effect by using child_process's spawn. I had to create a child_process.spawn and run all of the commands concatenated with &&. That freed up the console output to be exclusively the cli-spinner output. I then did an event handler for when the child process exited to stop the spinner.
#! /usr/bin/env node
var shell = require('shelljs');
var userArgs = process.argv.slice(2);
var folderName = userArgs[0];
var Spinner = require('cli-spinner').Spinner;
var depSpin = new Spinner('Installing dependencies.. %s');
var spawn = require('child_process').spawn;
var commandsDep = [
'cd ' + folderName,
'npm init -y',
'npm install --save babel-core babel-loader babel-preset-es2015 babel-preset-react react-dom react-redux redux webpack',
'npm install --save-dev babel-preset-env webpack-dev-server'
];
var depChild = spawn(commandsDep.join(' && '), {
shell: true
});
depSpin.setSpinnerString(18);
shell.mkdir(folderName);
shell.cd(folderName);
depSpin.start();
depChild.on('exit', () => {
depSpin.stop();
shell.exec('clear');
console.log('Installing dependencies.. ✓');
})
shell.touch('webpack.config.js');
shell.mkdir(['build', 'frontend']);
shell.cd('frontend');
shell.mkdir(['components', 'containers', 'reducers', 'store']);
shell.touch('app.js');
shell.cd('containers');
shell.touch(['AppContainer.js', 'Root.js']);
shell.cd('../reducers');
shell.touch('index.js');
shell.cd('../store');
shell.touch('configureStore.js');
Based on Owens' answer I made a helper method myself to run long commands with a spinner inline with normal shelljs commands;
const Spinner = require('cli-spinner').Spinner;
const spinner = new Spinner('installing.. %s');
spinner.setSpinnerString('|/-\\');
var spawn = require('child_process').spawn;
const longCommand = (command, onSuccess) => {
return new Promise((resolve, reject) => {
var process = spawn(command, { shell: true });
spinner.start();
process.on('exit', () => {
spinner.stop();
onSuccess();
resolve();
})
})
}
const npmInstall = async () => {
await longCommand("npm install", () => console.log(`NPM modules installed! 👍`))
// Other stuff
shell.mkdir('new')
}
npmInstall()

how to create simple nodejs script to wrap an binary/executable?

I want to create a nodejs file, that simple runs/wraps an executable binary file with all inputs and outputs.
For now at least on windows.
Why:
wanted to install an executable tool over npm install -g, to have it in console, without PATH changes. (npm global packages are included in PATH)
i used such solution:
const path = require("path");
const spawnSync = require('child_process').spawnSync;
const pathToMyExe = path.join(__dirname, 'bin', 'myfile.exe'); //just path to exe
const input = process.argv.slice(2); //minus "node" and "this js" arguments
spawnSync(pathToMyExe, input, {stdio: 'inherit'});
but for ".exe to PATH" problem, there is a simplier way (if you want windows only).
just set bin property in package.json to pathToExe.
https://docs.npmjs.com/files/package.json#bin
You can use the bin-wrapper npm package.
EDIT:
There's a better alternative called bin-manager.
Installation:
$ npm install --save bin-manager
Usage
const bmanager = require('bin-manager');
const base = 'https://github.com/imagemin/gifsicle-bin/raw/master/vendor';
const bin = bmanager('bin', 'gifsicle')
.src(base + '/macos/gifsicle', 'darwin')
.src(base + '/linux/x64/gifsicle', 'linux', 'x64')
.src(base + '/win/x64/gifsicle.exe', 'win32', 'x64')
.use(process.platform === 'win32' ? 'gifsicle.exe' : 'gifsicle');
bin.run(['--version'], (err, out) => {
if (err) {
console.log(error);
return;
}
console.log(out.stdout);
});

Nightmare.js not working as expected on Ubuntu Linux cloud server

I can't seem to get nightmare.js to work on an Ubuntu Linux 14.04 server [via DigitalOcean].
I've installed PhantomJS (1.9.8) and Node (4.2.4), and they are working well as far as I can tell.
For example, when I run this:
phantomjs loadspeed.js http://www.yahoo.com
with loadspeed.js containing this:
"use strict";
var page = require('webpage').create(),
system = require('system'),
t, address;
if (system.args.length === 1) {
console.log('Usage: loadspeed.js <some URL>');
phantom.exit(1);
} else {
t = Date.now();
address = system.args[1];
page.open(address, function (status) {
if (status !== 'success') {
console.log('FAIL to load the address');
} else {
t = Date.now() - t;
console.log('Page title is ' + page.evaluate(function () {
return document.title;
}));
console.log('Loading time ' + t + ' msec');
}
phantom.exit();
});
}
I get the following output:
Page title is Yahoo
Loading time 700 msec
However, when I try running a simple nightmare:
node --harmony hello_nightmare.js
with hello_nightmare.js containing this:
var Nightmare = require('nightmare');
var google = new Nightmare()
.goto('http://google.com')
.wait()
.run(function(err, nightmare) {
if (err) return console.log(err);
console.log('Done!');
});
I get no output whatsoever; it feels like I just pressed 'Enter' on the command line.
I also tried the example on the nightmare github site:
npm install nightmare vo
node --harmony hello_nightmare_main.js
with hello_nightmare_main.js containing this:
var Nightmare = require('nightmare');
var vo = require('vo');
vo(function* () {
var nightmare = Nightmare({ show: true });
var link = yield nightmare
.goto('http://yahoo.com')
.type('input[title="Search"]', 'github nightmare')
.click('.searchsubmit')
.wait('.ac-21th')
.evaluate(function () {
return document.getElementsByClassName('ac-21th')[0].href;
});
yield nightmare.end();
return link;
})(function (err, result) {
if (err) return console.log(err);
console.log(result);
});
And it still doesn't work.
How do I fix this nightmare?
Your issue is most likely described by
https://github.com/segmentio/nightmare/issues/224
Nightmare uses Electron which requires an X display; since your server doesn't have a display, you can use Xvfb to provide a virtual one. Install xvfb, and run
xvfb-run node --harmony hello_nightmare.js
I'm just posting this for posterity.
Below is the bash script to install nightmarejs with node (4.2.4) on a clean Ubuntu Linux machine. I've tested this on a DigitalOcean droplet running 14.04.
apt-get -y update
apt-get -y upgrade
apt-get -y --force-yes install make unzip g++ libssl-dev git xvfb x11-xkb-utils xfonts-100dpi xfonts-75dpi xfonts-scalable xfonts-cyrillic x11-apps clang libdbus-1-dev libgtk2.0-dev libnotify-dev libgnome-keyring-dev libgconf2-dev libasound2-dev libcap-dev libcups2-dev libxtst-dev libxss1 libnss3-dev gcc-multilib g++-multilib
mkdir src
cd src
wget https://nodejs.org/dist/v4.2.4/node-v4.2.4.tar.gz
tar xzf node-v4.2.4.tar.gz
cd node-v4.2.4
./configure
make -j2
make install
cd ..
mkdir nightmarejs
cd nightmarejs
npm -f init
npm install --save nightmare vo
Then you simply create the .js file (e.g. hello_nightmare.js) (in the same directory where nightmarejs is installed) and then run it using the command below (as already mentioned in #yoz's answer):
xvfb-run node --harmony hello_nightmare.js
I hope this helps.
Since electron requires X display you need to install all the following packages
sudo apt-get install -y xvfb x11-xkb-utils xfonts-100dpi xfonts-75dpi xfonts-scalable xfonts-cyrillic x11-apps clang libdbus-1-dev libgtk2.0-dev libnotify-dev libgnome-keyring-dev libgconf2-dev libasound2-dev libcap-dev libcups2-dev libxtst-dev libxss1 libnss3-dev gcc-multilib g++-multilib
Tested in ubuntu server in aws ec2 and it worked
then run your script:
xvfb-run node --harmony script.js
Nightmare.js uses the Electron browser and requires an X server. Install xvfb and its dependencies so that you can run graphical applications without display hardware:
sudo apt-get install -y xvfb \
x11-xkb-utils \
xfonts-100dpi \
xfonts-75dpi \
xfonts-scalable \
xfonts-cyrillic \
x11-apps \
clang libdbus-1-dev \
libgtk2.0-dev libnotify-dev \
libgconf2-dev \
libasound2-dev libcap-dev \
libcups2-dev libxtst-dev \
libxss1 libnss3-dev \
gcc-multilib g++-multilib
Create nightmare.js file and add the following:
const Nightmare = require("nightmare");
const outputFile = "test.png";
const nightmare = Nightmare({ show: true })
nightmare
.goto('https://duckduckgo.com')
.type('#search_form_input_homepage', 'github nightmare')
.click('#search_button_homepage')
.wait('#r1-0 a.result__a')
.evaluate(() => document.querySelector('#r1-0 a.result__a').href)
.end()
.then(res => {
console.log(res)
})
.catch(error => {
console.error('Search failed:', error)
})
run the script:
$ xvfb-run node --harmony nightmare.js
// output: https://github.com/segmentio/nightmare

NPM script problems

I have a nodejs file runner.node.js.
If I run node runner.node.js it works
But if I try tu run it with npm test (it's referenced in package.json):
"test": "node ./spec/runner.node.js"
or
"test": "spec/runner.node.js"
It says that the file isn't executable:
sh: 1: spec/runner.node.js: Permission denied
npm ERR! Test failed. See above for more details.
npm ERR! not ok code 0
If I set the file as executable it then says:
spec/runner.node.js: 1: spec/runner.node.js: Syntax error: word unexpected (expecting ")")
npm ERR! Test failed. See above for more details.
npm ERR! not ok code 0
while it still runs correctly with "node spec/runner.node.js"
The file is this:
console.log("Running Knockout tests in Node.js");
var fs = require('fs');
var jasmine = require('./lib/jasmine-1.2.0/jasmine');
// export jasmine globals
for (var key in jasmine) {
global[key] = jasmine[key];
}
// add our jasmine extensions to the exported globals
require('./lib/jasmine.extensions');
// export ko globals
if (process.argv.length > 2 && process.argv[2] == '--source') {
// equivalent of ../build/knockout-raw.js
global.DEBUG = true;
global.ko = global.koExports = {};
global.knockoutDebugCallback = function(sources) {
sources.unshift('build/fragments/extern-pre.js');
sources.push('build/fragments/extern-post.js');
eval(sources.reduce(function(all, source) {
return all + '\n' + fs.readFileSync(source);
}, ''));
};
require('../build/fragments/source-references');
} else {
global.ko = require('../build/output/knockout-latest.js');
}
// reference behaviors that should work out of browser
require('./arrayEditDetectionBehaviors');
require('./asyncBehaviors');
require('./dependentObservableBehaviors');
require('./expressionRewritingBehaviors');
require('./extenderBehaviors');
require('./mappingHelperBehaviors');
require('./observableArrayBehaviors');
require('./observableBehaviors');
require('./subscribableBehaviors');
// get reference to jasmine runtime
var env = jasmine.jasmine.getEnv();
// create reporter to return results
function failureFilter(item) {
return !item.passed();
}
env.addReporter({
reportRunnerResults:function (runner) {
var results = runner.results();
runner.suites().map(function (suite) {
// hack around suite results not having a description
var suiteResults = suite.results();
suiteResults.description = suite.description;
return suiteResults;
}).filter(failureFilter).forEach(function (suite) {
console.error(suite.description);
suite.getItems().filter(failureFilter).forEach(function (spec) {
console.error('\t' + spec.description);
spec.getItems().filter(failureFilter).forEach(function (expectation) {
console.error('\t\t' + expectation.message);
});
});
});
console.log("Total:" + results.totalCount + " Passed:" + results.passedCount + " Failed:" + results.failedCount);
process.exit(results.failedCount);
}
});
// good to go
env.execute();
Add
#/usr/bin/env node
as the first line in your file. This way, when run as an executable your OS will know that it shall use Node.js to run it (to be exactly: your OS will know that it shall use the first application called node to execute your script).

Categories

Resources