Run a Cakefile Programmatically - node.js

I spent a lot of time building this wonderful Cakefile in Coffeescript that builds everything, and now I'd like to be able to run the command cake build from outside of that directory using another alias thats relevant to my program.
Is there any way to run cake build from within a executable file? Something I can have executed by npm under '/bin'?

As Noli says, the only way to do it is to either reverse-engineer cake.js or—more simply—run the cake command from the target directory. Under Node, you can do that using child_process.spawn by setting the cwd option to the desired working directory.

It looks like there's no command line option to do that
https://github.com/jashkenas/coffee-script/blob/master/lib/cake.js#L38
exports.run = function() {
return path.exists('Cakefile', function(exists) {
var arg, args, _i, _len, _ref, _results;
if (!exists) {
throw new Error("Cakefile not found in " + (process.cwd()));
}
So your process will probably need to 'cd' to the directory of your Cakefile first, in order to run it. (Or you can patch coffescript to take an argument)

Related

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

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

How to find an .exe file path using node js

I'm running electron and nodejs on Windows 10
How can I find a path to an executable?
one way would be to run a cli command that will use something like
where myfile.exe
is there a node-ish way?
Use which module:
var which = require('which')
// async usage
which('node', function (er, resolvedPath) {
// er is returned if no "node" is found on the PATH
// if it is found, then the absolute path to the exec is returned
}).

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

My cli engine(npm package) cant find path to read file when install on another folder

I am building an app that auto completes some type of file. When i run node index.js in the program folder i get the correct i results.
Although i want to make it an npm package that can work as a cli engine. For example i want to write the command generate and the code to produce the results.
In order to auto complete the file i have to read some data that i have stored in a .csv file that comes along with my program.
When i try to run generate command under another folder it can read that file.
I am very new to cli and i don't understand yet quite well how thing work.
Thanks in advance for the help.
Here is the code of my cli conversion.
#!/usr/bin/env node
const program = require("commander");
const {
predict
} = require("./classifier");
program.version("1.0.0").description("ESLint Rules Generator");
program
.command("generate")
.description("Generate ESLint Rules")
.action(() => {
predict();
});
program.parse(process.argv);
Here is the problematic line:
let str = fs.readFileSync("data_files/rules.csv", "utf-8");
This is the error i get: ENOENT: no such file or directory, open 'data_files/rules.csv'

Equivalent of Rake's 'sh' for Jake?

I've got some experience with Ruby and Rake, but now I'm working on a Node project and want to learn how to do the same things with Jake.
Ruby has a system function that will shell out to a command and wait for it to exit. Rake extends this by adding an sh function that will additionally throw an error if the child process returned a nonzero exit code (or couldn't be found at all). sh is really handy for Rake tasks that shell out to things like compilers or test frameworks, because it automatically terminates the task as soon as anything fails.
Node doesn't seem to have anything like system or sh -- it looks like the nearest equivalents are child_process.spawn and child_process.exec, but neither of them wires up STDOUT or STDERR, so you can't see any output from the child process unless you do some extra work.
What's the best way to get an sh method for Jake? (Though since this is Node, I'd expect it to be async, rather than blocking until the command returns like Ruby does.) Is there an npm module that has already invented this particular wheel, or does someone have a code sample that does this?
I've already seen sh.js, but it looks awfully heavyweight for this (it tries to build an entire command interpreter in Node), and it doesn't look like it's async (though the docs don't say one way or the other).
I'm looking for something that I could use more or less like this (using Jake's support for async tasks):
file('myprogram', ['in.c'], function() {
// sh(command, args, successCallback)
sh('gcc', ['in.c', '-o', 'myprogram'], function() {
// sh should throw if gcc couldn't be found or returned nonzero.
// So if we got here, we can tell Jake our task completed successfully.
complete();
});
}, true);
Here's some code I've come up with that seems to work well. (But if anyone has a better answer, or knows of an existing npm module that already does this, please add another answer.)
Supports full shell syntax, so you can use | and < and > to pipe and redirect output, you can run Windows batch files, etc.
Displays output (both STDOUT and STDERR) as the child process generates it, so you see incremental output as the command runs.
No limitation on the amount of output the command can generate (unlike a previous exec-based version of this code).
Cross-platform (works on Windows, should work on Mac/Linux as well). I borrowed the platform-specific-shell (if platform === 'win32') technique from npm.
Here's the code:
function sh(command, callback) {
var shell = '/bin/sh', args = ['-c', commandLine], child;
if (process.platform === 'win32') {
shell = 'cmd';
args = ['/c', commandLine];
}
child = child_process.spawn(shell, args);
child.stdout.pipe(process.stdout);
child.stderr.pipe(process.stderr);
child.on('exit', function(code, signal) {
if (signal != null)
throw new Error("Process terminated with signal " + signal);
if (code !== 0)
throw new Error("Process exited with error code " + code);
callback();
});
};

Resources