Spawn command as sudo in NPM/Yeoman - linux

I'm learning Yeoman and have gotten really far which is nice :), but I'm now at the point in my generator where I would like to set up a VHOST for my new project.
The way I normally create a VHOST is create a *.conf file in /etc/apache2/sites-available/, run sudo a2ensite new-site and finally sudo service apache2 reload.
How can I use generator.spawnCommand() (or anything else that works) to run my sudo commands? I assume the user would need to enter his password for the commands to run of course.
Note that I've tried the sudo npm package but it just fails silently even with the example code provided on https://www.npmjs.com/package/sudo

Maybe I've misunderstood something, but the following simple code worked fine for me:
var generators = require('yeoman-generator');
var execSync = require('child_process').execSync;
module.exports = generators.Base.extend({
touch: function () {
execSync('sudo touch /tmp/test-sudo', {
stdio: 'inherit'
});
}
});

Related

How to create and manage a npm process in electron

I'm trying to make this little QoL app that can trigger my scripts inside package.json of any project I throw at it (react, polymer, etc.).
So far, it works as it should. At least until I kill the app or want to terminate the specific process (like using ctrl+c while running a npm start in a console).
I'm currently calling the command this way:
const exec = require("child_process").execFile;
...
let ps = exec("command.bat", [path, command], (error, stdout, stderr)=>{}) //command.bat contains only: cd "%1" \n npm "%2"
Previously I've used node-powershell like so:
const Shell = require('node-powershell');
...
let sh = new Shell();
sh.addCommand(`cd ${fs.realpathSync(path)}`);
sh.addCommand(`npm ${command}`);
sh.invoke();
And I've already tried using ps-tree in hopes that this will list all the processes started by my process so I can kill them but no luck and because it creates additional process or two it's getting out of hands really quickly.
const cp = require('child_process');
...
psTree(ps.pid, function (err, children) {
cp.spawn('kill', ['-9'].concat(children.map(function (p) { return p.PID })));
});
So if there is some solution I would be really grateful. I'm also open to any different solution if there is any.
Thanks in advance.

How can a NodeJS app restart itself as sudo?

I've got a NodeJS app that needs to run as superuser. The user running this (should) have sudo privileges. Therefore they can easily run the app with "sudo node ...". For convenience, I would like the app to restart itself with sudo if it's not running as root.
Reading NodeJs execute command in background and forget, I have tried the following:
const isroot = process.getuid && process.getuid() === 0;
if (!isroot) {
console.log("Must be running as superuser! Restarting with sudo.");
spawn("sudo", process.argv, {
stdio: "inherit",
detached: true
}).unref();
process.exit(0);
}
However, this doesn't work as the user needs to enter their password and, despite setting stdio to inherit, I get the error:
sudo: no tty present and no askpass program specified
Can anyone see what I'm doing wrong, and is there a more obvious solution?
Thanks for any suggestions.

How to disable warnings when node is launched via a (global) shell script

I am building a CLI tool with node, and want to use the fs.promise API. However, when the app is launched, there's always an ExperimentalWarning, which is super annoying and messes up with the interaction prompts. How can I disable this warning/all warnings?
I'm testing this with the latest node v10 lts release on Windows 10.
To use the CLI tool globally, I have added this to my package.json file:
{
//...
"preferGlobal": true,
"bin": { "myapp" : "./index.js" }
//...
}
And have run npm link to link the ./index.js script. Then I am able to run the app globally simply with myapp.
After some research I noticed that there are generally 2 ways to disable the warnings:
set environmental variable NODE_NO_WARNINGS=1
call the script with node --no-warnings ./index.js
Although I was able to disable the warnings with the 2 methods above, there seems to be no way to do that while directly running myapp command.
The shebang I placed in the entrance script ./index.js is:
#!/usr/bin/env node
// my code...
I have also read other discussions on modifying the shebang, but haven't found a universal/cross-platform way to do this - to either pass argument to node itself, or set the env variable.
If I publish this npm package, it would be great if there's a way to make sure the warnings of this single package are disabled in advance, instead of having each individual user tweak their environment themselves. Is there any hidden npm package.json configs that allow this?
Any help would be greatly appreciated!
I am now using a launcher script to spawn a child_process to work around this limitation. Ugly, but it works with npm link, global installs and whatnot.
#!/usr/bin/env node
const { spawnSync } = require("child_process");
const { resolve } = require("path");
// Say our original entrance script is `app.js`
const cmd = "node --no-warnings " + resolve(__dirname, "app.js");
spawnSync(cmd, { stdio: "inherit", shell: true });
As it's kind of like a hack, I won't be using this method next time, and will instead be wrapping the original APIs in a promise manually, sticking to util.promisify, or using the blocking/sync version of the APIs.
I configured my test script like this:
"scripts": {
"test": "tsc && cross-env NODE_OPTIONS=--experimental-vm-modules NODE_NO_WARNINGS=1 jest"
},
Notice the NODE_NO_WARNINGS=1 part. It disables the warnings I was getting from setting NODE_OPTIONS=--experimental-vm-modules
Here's what I'm using to run node with a command line flag:
#!/bin/sh
_=0// "exec" "/usr/bin/env" "node" "--experimental-repl-await" "$0" "$#"
// Your normal Javascript here
The first line tells the shell to use /bin/sh to run the script. The second line is a bit magical. To the shell it's a variable assignment _=0// followed by "exec" ....
Node sees it as a variable assignment followed by a comment - so it's almost a nop apart from the side effect of assigning 0 to _.
The result is that when the shell reaches line 2 it will exec node (via env) with any command line options you need.
New answer: You can also catch emitted warnings in your script and choose which ones to prevent from being logged
const originalEmit = process.emit;
process.emit = function (name, data, ...args) {
if (
name === `warning` &&
typeof data === `object` &&
data.name === `ExperimentalWarning`
//if you want to only stop certain messages, test for the message here:
//&& data.message.includes(`Fetch API`)
) {
return false;
}
return originalEmit.apply(process, arguments);
};
Inspired by this patch to yarn

How can I run grunt as a daemon?

I am running a packaged nodejs webserver that allows for reading of epub files (Readium-JS), and it is started with the grunt command.
However, if I run this on my VPS the server dies as soon as my terminal connection ends.
How can I run this task as a daemon?
I have looked at options like grunt-forever and grunt-daemon but the way the Gruntfile is written using load-grunt-config is messing with my mind and I can't piece together how to isolate the server code.
Here's the solution I found:
As was suggested above, using pm2
However, when I ran
pm2 start grunt
I got an error saying that the grunt module did not exist, which was weird.
So I ended up writing a script which worked:
-- start.js --
var pm2 = require('pm2');
pm2.connect(function() {
pm2.start({
script : '/usr/local/bin/grunt', // Script to be run
args: '--force',
}, function(err, apps) {
pm2.disconnect();
});
});
After running node start.js from the command line, everything sailed smoothly.

Node.js – events js 72 throw er unhandled 'error' event

I'm new to Node.js and wish to run a program using streams. With other programs, I had to start a server simultaneously (mongodb, redis, etc) but I have no idea if I'm supposed to run one with this. Please let me know where I am going wrong and how I can rectify this.
This is the program:
var http = require('http'),
feed = 'http://isaacs.iriscouch.com/registry/_changes?feed=continuous';
function decide(cb) {
setTimeout(function () {
if (Date.now()%2) { return console.log('rejected'); }
cb();
}, 2000);
}
http.get(feed, function (res) {
decide(res.pipe.bind(res, process.stdout));
//using anonymous function instead of bind:
// decide(function () {
// res.pipe(process.stdout)
// });
});
This is the cmd output:
<b>C:\05-Employing Streams\05-Employing Streams\23-Playing with pipes>node npm_stre
am_piper.js
events.js:72
throw er; // Unhandled 'error' event
^
Error: Parse Error
at Socket.socketOnData (http.js:1583:20)
at TCP.onread (net.js:527:27)
</b>
Close nodejs app running in another shell.
Restart the terminal and run the program again.
Another server might be also using the same port that you have used for nodejs. Kill the process that is using nodejs port and run the app.
To find the PID of the application that is using port:8000
$ fuser 8000/tcp
8000/tcp: 16708
Here PID is 16708 Now kill the process using the kill [PID] command
$ kill 16708
I had the same problem. I closed terminal and restarted node. This worked for me.
Well, your script throws an error and you just need to catch it (and/or prevent it from happening). I had the same error, for me it was an already used port (EADDRINUSE).
I always do the following whenever I get such error:
// remove node_modules/
rm -rf node_modules/
// install node_modules/ again
npm install // or, yarn
and then start the project
npm start //or, yarn start
It works fine after re-installing node_modules. But I don't know if it's good practice.
Check your terminal it happen only when you have your application running on another terminal..
The port is already listening..
For what is worth, I got this error doing a clean install of nodejs and npm packages of my current linux-distribution
I've installed meteor using
npm install metor
And got the above referenced error. After wasting some time, I found out I should have used meteor's way to update itself:
meteor update
This command output, among others, the message that meteor was severely outdated (over 2 years) and that it was going to install itself using:
curl https://install.meteor.com/ | sh
Which was probably the command I should have run in the first place.
So the solution might be to upgrade/update whatever nodejs package(js) you're using.

Resources