Node JS: How to check if a dependent application is installed on target machine? - node.js

I would like to implement an external dependency validation logic in my Node JS console application. For example, git. In the terminal "git --version" would respond with current version of the git installed. I might use child_process module in Node and invoke shell commands but is there a better way to do it? It should work regardless of the host operating system.
Why Am I having such requirement?
My application should create a git like merge conflict if 2 or 3 versions (Modified, Original, Remote) of the file having conflicting changes. I wish I could use some node modules to achieve. But it turns that there is none. So I decided to use 'git merge-file'. But before executing the command, I would want to check if git is installed or not. This might seem odd but your suggestions are valuable. Thanks in advance.

Child process is the solution you should go for, as you have already figured it out. It's the only way to interact with other processes from Node.js application.
You can have something like:
const { exec } = require('child_process');
exec('git --version', error => {
if (error) {
// Git doesn't exist
// Add your handler code here
}
else {
// Git exists
// Add remaining of code here
}
});

Related

Worker thread postMessage() vs command line command

I recently learned about Worker threads in Node JS. I was trying to create a worker thread to run Stockfish chess engine in node js.
The npm package I am using for this is called stockfish. I tried using node-stockfish before this but it was not installing with npm as it was using an older version of the type definition for the "AbortSignal" variable apparently causing compatibility issues.
For the current npm package that I am using even though I was able to install it successfully, I could find very little documentation on how to use it. So I tried out a few ideas.
import { Worker } from "worker_threads";
const engine = new Worker("./node_modules/stockfish/src/stockfish.js")
engine.on('message', (data) => console.log(data))
engine.postMessage('position startpos move e2e4 e7e5')
engine.postMessage('go movetime 3000')
Here I tried to run the stockfish.js as a worker thread and send commands to it with the postMessage() function. This however did not work and it gave the following output:
worker.js received unknown command undefined
position startpos move e2e4 e7e5
worker.js received unknown command undefined
go movetime 3000
But I know these commands are valid commands if I run the same js from the command line like so:
It might be because I am using the flags --experimental-wasm-threads and --experimental-wasm-simd when I am running it from the command line. I found this command to run it from the little documentation that was present. But I don't know how to mention these flags when I run it through a worker thread.
Otherwise it could also be that I don't understand how worker threads work yet and postMessage() is not the same as sending it a command from the command line.
Any help is greatly appreciated.
I switched to using stockfish.wasm library instead. With this library I was able to achieve what I wanted and I don't need to use any worker threads for now. Maybe I can add this to a worker thread if required later. Here is a simple example:
const Stockfish = require("stockfish.wasm")
Stockfish().then((engine) => {
engine.addMessageListener((output) => {
console.log(output);
// Do something with the output data here
})
engine.postMessage("uci");
engine.postMessage("ucinewgame");
engine.postMessage("position startpos");
engine.postMessage("go depth 20");
});

How do you export an object in a module in nodejs?

There is something wrong with the way I understand how to use classes in a Javascript module and export them, or some bad assumption I made about how nodejs works. Please help me understand this better. I wanted to write a module that exposed an object that will "store things safely." I have a file ("safestore.js") with this in it:
class Safestore {
constructor() {
console.log("SUCCESS!");
}
... // I defined other methods here...
}
exports.safestore = Safestore; // I tried this with `new Safestore` and `new Safestore()` too.
I run nodejs on my command line and then:
> ss = require('./safestore');
{ safestore: [Function] }
> s = ss.safestore('pwd','./encFile.enc');
ReferenceError: Safestore is not defined...
Why is it telling me that Safestore is not defined while executing the safestore function which is defined in the same file where Safestore is, actually defined?
The question does not contain enough information, although there is a clue. node and nodejs are two different pieces of software, and I was using the wrong one. I also didn't specify what version of nodejs I ran from my command line. When I ran it with node (instead of nodejs) I got errors that made sense and I was able to fix them.
Thanks to #Ethicist for listing the version of Node he used, as this got me to double check all those things.
I just need to remember that node and nodejs each do different things. Further research shows me that nodejs is a symlink to version 8.10.0 of node.js, and node is a symlink to the version that I set with nvm. I solved the problem permanently for myself with sudo rm /user/bin/nodejs and I'll remember, if I ever see an error that says nodejs doesn't exist, that it wants the old version of node.js.

Is there a cross-platform way to get the name of the parent process in Node.js?

I'm working on an npm package initializer, that is, a program that runs when the user runs the npm init <my-package-initializer> command.
npm is not the only package manager for Node.js any more, yarn is also quite popular and pnpm is a personal favorite of mine and I want to support all three. The easy way is to ask the user which package manager they prefer or provide a command-line switch like CRA does.
But the user has already shown their preference by running, say, yarn create instead of npm init. It feels annoying to ask again. We could just check if yarn or pnpm is our parent process.
Is there a cross-platform way to get this information?
For future googlers, I ended up using the following snippet. I use it for picking the default choice but I still ask the user explicitly for their package manager preference, better safe than sorry.
function getPackageManager() {
// This environment variable is set by npm and yarn but pnpm seems less consistent
const agent = process.env.npm_config_user_agent;
if (!agent) {
// This environment variable is set on Linux but I'm not sure about other OSes.
const parent = process.env._;
if (!parent) {
// No luck, assume npm
return "npm";
}
if (parent.endsWith("pnpx") || parent.endsWith("pnpm")) return "pnpm";
if (parent.endsWith("yarn")) return "yarn";
// Assume npm for anything else
return "npm";
}
const [program] = agent.split("/");
if (program === "yarn") return "yarn";
if (program === "pnpm") return "pnpm";
// Assume npm
return "npm";
}

Run tortoise SVN from Node.js

Is it possible to run some simple commands for Tortoise SVN via a Node.js server? Essentially an update and commit on a repository.
You could use the child_process module to execute whatever shell script you want. Just figure out the svn commands you need to execute and refer to the node js child_process docs. You will need svn to be installed on the server your node process is running on.
Here is a simplified example:
const spawn = require('child_process').spawn;
const pathToRepo = findPathToRepoSomehow();
const svnUpdate = spawn('svn', ['update', pathToRepo]);
svnUpdate.on('close', (code) => {
console.log('update successful!');
});
You would want to handle error conditions as well.

How do I successfully notify Airbrake of a deployment when using capistrano to deploy a Node.js project?

This is a bit of an oddball question.
Capistrano 2.14.2
I'm using capistrano to deploy a couple of Node.js projects, and this works fine (from within the same rvm and gemset Ruby installation). However, I'd like to have Airbrake be notified of these deployments.
Using the 'airbrake' Node.js module, and calling
airbrake.trackDeployment({repo: '...'});
works, but not sure how to reliably call this just once at deploy time. If I call it within my server, then Airbrake is notified of a "deployment" every time my server starts, which is obviously not correct.
Adding
require 'airbrake/capistrano'
to deploy.rb definitely does not work.
How do others successfully use
airbrake.trackDeployment
?
You could create a simple js file you'd run locally (on your machine for example) that notifies airbrake as a last deploy task. You could for example use the backtick operator to run a task:
deploy.task :notify_airbrake do
`node notify_airbrake.js`
end
If you don't have node installed locally, you could also pick one of the servers to run the notification script through ssh:
deploy.task :notify_airbrake do
`ssh youserver "node notify_airbrake.js"`
end
Based on this solution http://dwradcliffe.com/2011/09/26/using-airbrake-with-node.html (which is clearly embedded in a Rails app.), I came up with the following, which depends solely on Javascript:
In my Node.js root directory, create a deploy.js file, like so:
var airbrake = require('airbrake').createClient("AIRBRAKE_API_KEY");
var deployment = {rev: process.argv[2],
repo: process.argv[3],
env: process.argv[4],
user: process.argv[5]};
airbrake.trackDeployment(deployment, function(err, params) {
if (err) {throw err}
console.log('Tracked deployment of %s to %s', params.rev, params.env);
})
In config/deploy.rb, add
require 'airbrake/capistrano'
and
namespace :airbrake do
desc "Notify Airbrake of a new deploy."
task :deploy do
system "node deploy.js #{current_revision} #{repository} #{stage} #{user}"
end
end

Resources