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

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 });

Related

is there anyway to make js executes this script line by line

i am trying to make a script that can automate my projects every time i create a new react application so first I've made a bat file that runs my main.js script
here is the bat file
#echo off
setlocal enableextensions
REM run my main
node "C:\Windows\System32\automate\main.js" %1
and here is the main.js file
const { exec } = require("child_process");
const { replace, rename } = require("./file.js");
const axios = require("axios").default;
let state = {
cwd: "E:/WORK/Projects",
token: "[[my github token]]",
project: {
name: process.argv[2],
path: "E:/WORK/Projects/" + process.argv[2],
src: "E:/WORK/Projects/" + process.argv[2] + "/src",
},
};
// init
let { cwd, project, token } = state;
//
//
// main
// create the app
exec("create-react-app " + project.name, { cwd });
// install debs
exec("npm i node-sass", { cwd: project.path });
// use sass
rename(project.src + "/index.css", "index.scss");
rename(project.src + "/App.css", "App.scss");
replace(project.src + "/index.js", "./index.css", "./index.scss");
replace(project.src + "/App.js", "./App.css", "./App.scss");
// structure my app
let code = [
'mkdir "' + project.src + '/App"',
'mkdir "' + project.src + '/App/Elements"',
'mkdir "' + project.src + '/App/nav"',
'touch "' + project.src + '/App/nav.jsx"',
'touch "' + project.src + '/App/nav/nav.scss"',
];
code = code.join(" && ");
exec(code);
// push to github
axios({
method: "post",
url: "https://api.github.com/user/repos?access_token=" + token,
data: {
name: project.name,
},
})
.then((res) => {
let repo = res.data.clone_url;
let c = [
"git remote add origin " + repo,
"git push --set-upstream origin master",
"git push",
].join(" && ");
exec(c);
})
.catch((err) => {
console.log(err.response.data.errors);
});
// open in code
exec("code " + project.path);
// final message
console.log("Have Fun!");
now everything is ready but the only problem i have that every line gets executed asynchronously
example like create-react-app command this takes a lot of time and every next line depends on it to finish first
You can use execSync instead of exec:
const {execSync} = require('child_process');
Here is the main documentation about this feature: NodeJs Docs
Specific Description:
The child_process.execSync() method is generally identical to child_process.exec() with the exception that the method will not return until the child process has fully closed. When a timeout has been encountered and killSignal is sent, the method won't return until the process has completely exited. If the child process intercepts and handles the SIGTERM signal and doesn't exit, the parent process will wait until the child process has exited.
This is a classic case where you can use locks or semaphores.
Just lock the execution before the desired line and remove it after that.
refer this for locks in js - How to implement a lock in JavaScript
You can use promisify from the util module to turn the async exec function into a promise so you can then use await exec in order for it to appear as executing synchronously.
const util = require('util');
const exec = util.promisify(require('child_process').exec);
Then you can wrap your code in a function like this:
async function init(){
//your code
await exec("create-react-app " + project.name, { cwd });
//...
}
init();
execSync may actually be easier for a simple script like this, but you may find the async versions better in other cases.

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);
});

How to spawn ghostcript into node.js environment

I have tried different configuration, but I cannot seem to succeed to execute "gs" (Ghostscript) in a node.js environment.
var fs = require( "fs" ),
child_process = require( 'child_process' );
...
var spawn = child_process.spawn;
var opts = [
"-q ",
"-dQUIET ",
"-dSAFER ",
"-dBATCH ",
"-dNOPAUSE ",
"-dNOPROMPT ",
"-dMaxBitmap=500000000 ",
"-dAlignToPixels=0 ",
"-dGridFitTT=2 ",
"-sDEVICE=jpeg ",
"-dTextAlphaBits=4 ",
"-dGraphicsAlphaBits=4 ",
"-r150 ",
"-sOutputFile=afile.jpg",
" afile.pdf"
];
var gs = spawn( "gs", opts, { cwd: "/mnt/drive/" } );
gs.stdout.on( 'data', function( data ) {
console.log( 'stdout: ' + data );
} );
gs.stderr.on( 'data', function( data ) {
console.log( 'stderr: ' + data );
} );
gs.on( 'close', function( code ) {
console.log( 'child process exited with code ' + code );
} );
---Output ---------------------------------------------------------
stdout: Unknown device: jpeg
stdout: Unrecoverable error: undefined
stdout: in .uninstallpagedevice
stdout: Operand stack:
defaultdevice
stdout:
child process exited with code 1
-------------------------------------------------------------------
The /mnt/drive directory is +read+write for all users. The gs -help execution returns:
root#Machine:/# gs -help
GPL Ghostscript 9.05 (2012-02-08)
Copyright (C) 2010 Artifex Software, Inc. All rights reserved.
Usage: gs [switches] [file1.ps file2.ps ...]
Most frequently used switches: (you can use # in place of =)
-dNOPAUSE no pause after page | -q `quiet', fewer messages
-g<width>x<height> page size in pixels | -r<res> pixels/inch resolution
-sDEVICE=<devname> select device | -dBATCH exit after last file
-sOutputFile=<file> select output file: - for stdout, |command for pipe,
embed %d or %ld for page #
Input formats: PostScript PostScriptLevel1 PostScriptLevel2 PostScriptLevel3 PDF
Default output device: bbox
Available devices:
...
ijs imagen inferno inkcov iwhi iwlo iwlq jetp3852 jj100 jpeg jpegcmyk
jpeggray la50 la70 la75 la75plus laserjet lbp310 lbp320 lbp8 lex2050
...
txtwrite uniprint xcf xes
Search path:
/usr/share/ghostscript/9.05/Resource/Init :
/usr/share/ghostscript/9.05/lib :
/usr/share/ghostscript/9.05/Resource/Font :
/usr/share/ghostscript/fonts : /var/lib/ghostscript/fonts :
/usr/share/cups/fonts : /usr/share/ghostscript/fonts :
/usr/local/lib/ghostscript/fonts : /usr/share/fonts
For more information, see /usr/share/doc/ghostscript/Use.htm.
Please report bugs to bugs.ghostscript.com.
root#Machine:/#
Where the device jpeg is available. The gs execution is not perform. Any hint would be help ?
The only way I got it to work, is by upgrading node from 10.26 to the latest 10.32, AND encapsulate the gs execution in a simple bash script file. Otherwise, even with the 10.32 node version, I still get the same error. I suspected an environment problem like suggest #Rudie,
You could consider to use Ghostscript4JS, it's a module that binds the Ghostscript C command API to bring its power to the Node.JS world.
https://www.npmjs.com/package/ghostscript4js
Ghostscript4JS is a native Node.JS addon so you can call the C command Ghostscript API directly from your JavaScript code. In this way you have two benefits:
Better error handling:
You directly intercept the error through the try/catch for the sync method and then/catch promise for the async method.
Performance
The call to the shell command takes more time and more resources than the call to the C or C++ API directly from Node.js environment.
As programmer you have more control against call external tool.
You just need to remove the spaces in the list of options

Using PsExec with spawning a child process results in truncated stdout

My goal is to be able to execute a command on a remote machine and get the full stdout response from the command that was run. What I am getting is a truncated result. When I run the same command through command prompt, I get the full output from the command run. Here is my code:
var process = spawn('PsExec.exe', ['\\\\servername', 'ipconfig']);
var doOnce = true;
process.stdout.on('data', function (data) {
log.info('stdout: ' + data.toString());
if(doOnce){
doOnce = false;
process.stdin.write('ipconfig');}
});
process.stderr.on('data', function (data) {
log.info('stderr: ' + data.toString());
});
process.on('exit', function (code) {
log.info('child process exited with code ' + code);
});
When executed I get the following console output. As you can tell, all of ipconfig has been truncated. If I do another command such as netstat, I get most of the results before truncating occurs, so I don't believe this has anything to do with the buffer. I really am just out of ideas at this point.
info: stderr:
PsExec v2.11 - Execute processes remotely
Copyright (C) 2001-2014 Mark Russinovich
Sysinternals - www.sysinternals.com
info: stdout:
Windows IP Configuration
ipconfig exited on servername with error code 0.
info: child process exited with code 0
Try using the { stdio: 'inherit' } option
var spawn = require('child_process').spawn,
appname = spawn('psexec.exe', ['-accepteula', '\\\\remotepcname', '-u', 'domain\\username', '-p', 'supersecretpassword', 'ipconfig'], { stdio: 'inherit' });

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