Node JS - child_process spawn('npm install') in Grunt task results in ENOENT error - node.js

I'm having some difficulty with a Grunt task I'm authoring. I'm trying to execute npm install, followed by bower install, followed by a grunt hub target (to trigger a build command for multiple sub-projects).
The problem I'm encountering lies with child_process. I get spawn ENOENT error if I run the following commands in my grunt task, with the npm install spawn command that's currently commented out:
var path = require('path'),
projectPath = path.resolve(process.cwd(), this.data.activity );
grunt.log.debug('project path computed as: ', projectPath);
process.chdir( projectPath );
console.log('current dir is: ', process.cwd());
console.log('EVN is: ', process.env);
var spawnProcess = spawn('ls');
// var spawnProcess = spawn('npm install');
spawnProcess.stdout.on('data', function (data) {
console.log('' + data);
});
spawnProcess.stderr.on('data', function(data) {
console.log('something went wrong installing deps for ' + path + '. Error: ', data);
});
spawnProcess.on('close', function (exitCode) {
console.log( 'ls has finished with Exit Code: ' + exitCode);
});
the current code (with ls instead of npm install) results in:
running "install:projects" (install) task[D] Task source: /Users/zedd45/proj/Gruntfile.js
Verifying property install.projects exists in config...OK
File: [no files]
[D] project path computed as: /Users/zedd45/proj/activity/web/client
current dir is: /Users/zedd45/proj/activity/web/client
EVN (abbreviated) is: {
TERM_PROGRAM: 'iTerm.app',
SHELL: '/bin/bash',
PWD: '/Users/zedd45/proj',
...
OLDPWD: '/Users/zedd45/proj/activity/web/client',
_: '/usr/local/bin/grunt' }
GruntFile.js
bower.json
package.json
this_is_the_directory_you_are_looking_for.txt
ls has finished with Exit Code: 0
but if I change 'ls' to 'npm install' I get instead
``Fatal error: spawn ENOENT
immediately following the ENV print.
I have tried chmod 777 for that directory, which doesn't seem to help.
I have also tried:
// var spawnProcess = spawn('npm install', {'cwd': projectPath});
and
// var spawnProcess = spawn('npm install', [], {'cwd': projectPath});
The former results in
Warning: Object # has no method 'slice' Use --force to
continue.
the later still results in the ENOENT error.
Any help with exactly what this ENOENT error is would probably help a great deal; I haven't had much success with Googling it nor with the child process API docs

Double check the docs on child_process.spawn again. The first argument should be only the command to run and the second is the arguments:
var npm = spawn('npm', ['install'], { cwd: projectPath });

Related

How to execute the command NPM init in the nodejs file

How to execute the command npm init in the nodejs file? I want to use node. / index.js to execute the command. But what should I do if the command interacts with the user?
This code is directly stuck, and the subsequent question and answer cannot be carried out.I hope users can fill in the information normally
let exec = require('child_process').exec;
exec("npm init")
To allow users to fill in the questionnaire via the CLI, consider using the child_process module's spawn() method instead of exec().
*Nix (Linux, macOS, ... )
For example:
index.js
const spawn = require('child_process').spawn;
spawn('npm', ['init'], {
shell: true,
stdio: 'inherit'
});
Note: After the user has completed the questionnaire this example (above) creates the resultant package.json file in the current working directory, i.e. the same directory from where the node command invoked index.js.
However, If you want to ensure that package.json is always created in the same directory as where index.js resides then set the value of the cwd option to __dirname. For example:
const spawn = require('child_process').spawn;
spawn('npm', ['init'], {
cwd: __dirname, // <---
shell: true,
stdio: 'inherit'
});
Windows
If you are running node.js on Windows then you need to use the following variation instead:
script.js
const spawn = require('child_process').spawn;
spawn('cmd', ['/c', 'npm init'], { //<----
shell: true,
stdio: 'inherit'
});
This also utilizes the spawn() method, however it starts a new instance of Windows command shell (cmd). The /c option runs the npm init command and then terminates.
Cross-platform (Linux, macOS, Windows, ... )
For a cross platform solution, (i.e. one that runs on Windows, Linux, macOS), then consider combining the previous examples to produce the following variation:
script.js
const spawn = require('child_process').spawn;
const isWindows = process.platform === 'win32';
const cmd = isWindows ? 'cmd' : 'npm';
const args = isWindows ? ['/c', 'npm init'] : ['init'];
spawn(cmd, args, {
shell: true,
stdio: 'inherit'
});
Assuming there doesn't need to be any user input you could do:
let exec = require('child_process').exec;
exec("npm init -y")

How to test an node file, receiving an 'EACCES' error when spawning the function

When creating a CLI I would like to test my function. For that I'm using the module child_process.
const path = require('path');
const { execFile } = require('child_process');
describe('cli test', () => {
test('thing', () => {
const myCli = execFile(
`${path.resolve(__dirname, '..')}/cli.js`, ['--foo', 'Bar'],
(err, stdout, stderr) => {
if (err) {
console.log('err: ', err);
}
});
});
But this produces the following error:
Attempted to log "err: { Error: spawn /projects/cli/src/cli.js EACCES
at Process.ChildProcess._handle.onexit (internal/child_process.js:240:19)
at onErrorNT (internal/child_process.js:415:16)
at process._tickCallback (internal/process/next_tick.js:63:19)
errno: 'EACCES',
code: 'EACCES',
Running this script directly in the terminal via the command: $ node cli.js --foo Bar works perfectly.
Now a suggestion is to chmod +x <file> that file (source). But the test should also work on CI, and on a different computer which pulls the Git repo.
Any idea?
I'd suggest using fork instead of execFile.
The child_process.fork() method is a special case of child_process.spawn() used specifically to spawn new Node.js processes.
This will allow you to execute JS files without needing them to be shell executable.
To the best of my knowledge, git actually tracks the executable bit for files. There are some things to consider though as pointed out in this article: https://medium.com/#tahteche/how-git-treats-changes-in-file-permissions-f71874ca239d
Another solution would be to not rely on the ./ execution syntax (which requires the executable bit to be turned on for the respective file) but instead to explicitly use the shell command:
const path = require('path');
const { execFile } = require('child_process');
describe('cli test', () => {
test('thing', () => {
const myCli = execFile(
`sh ${path.resolve(__dirname, '..')}/cli.js`, ['--foo', 'Bar'],
(err, stdout, stderr) => {
if (err) {
console.log('err: ', err);
}
});
});
Notice the sh prefix I added to your code, This way you thell the sh command (which should be available in all of your environments e.g. the CI) to execute the contents of the file, regardless of whether the file itself can be executed or not!
I was receiving an EACCESS -13 error from child_process.spawn when trying to run a the command line mysql command.
There was something wrong with my PATH and updating it to add /usr/local/mysql/bin/ resolved the problem.
The temporary fix is to run export PATH=$PATH:/usr/local/mysql/bin/.
The permanent fix is to:
type: sudo nano /etc/paths
Add /usr/local/mysql/bin at the end
Ctrl + X
Yes
Enter key
type hash -r # command line or close the terminal app and open it again
NOTE: I got the temporary fix from a site ... I don't know why it has a / on the end of the bin but all of the mysql executables appear to be available without it in the /etc/paths file

Node.js spawn of Blender command-line?

I need blender command-line access though spawn but keep running into an ENOENT error and it is hard to pinpoint what is missing. The command-line being passed in the sample application works in terminal.
Below are some details about the environment and the sample script I am using.
Environment (OSX El Capitan)
Installed Blender 2.76b with:
brew install Caskroom/cask/blender
Then add alias to bash_profile for terminal access:
alias blender="/Applications/blender/Blender.app/Contents/MacOS/blender"
Test Code
#!/usr/bin/env node
var child_process = require('child_process');
var arguments = [
'-b',
'recipe.blend',
'-o', 'test-#',
'-f', 0
];
console.log("values: ", arguments);
var child = child_process.spawn('blender', arguments);
child.stdout.on('data', function(data) {
console.log('data out: ', data.toString());
});
child.stderr.on('data', function(data) {
console.error('error out: ',data);
});
child.on('close', function(code) {
console.log('closing code: ' + code);
});
// Raw command-line for terminal. (PASS)
// blender -b recipe.blend -o test-# -f 0
Try changing the child_process.spawn('blender', arguments); line to child_process.spawn('/Applications/blender/Blender.app/Contents/MacOS/blender', arguments);. NodeJS won't be using your bash aliases, so unless the blender executable is in its PATH it won't be able to find the executable and will throw an ENOENT.
The other option is adjusting Node's PATH to include the path to the blender executable. You could also pass the fullpath to the blender executable in as an environment variable.
Cheers!

how do you run a commamd say npm install or rake as part of a node js application?

I have a node app in which i want to run a command or task like npm install or rake or git clone . I tried using child process exec , but is not running the npm install task. Is there a alternative way?
If you want to execute a shell (or cmd if you're on Windows) command you can do it by using child_process.exec()
https://nodejs.org/api/child_process.html#child_process_child_process_exec_command_options_callback
Here is an example:
var exec = require('child_process').exec;
var child;
child = exec("pwd", function (error, stdout, stderr) {
console.log('stdout: ' + stdout);
console.log('stderr: ' + stderr);
if (error !== null) {
console.log('exec error: ' + error);
}
});
Just put npm install or git clone or whatever you want to execute instead of pwd when calling the exec function.
You can do the following to get npm install work inside a node script,
Execute npm install npm --save (This will take some time)
Now since npm is inside the node_modules folder, you can import it inside your script.
Sample script below which installs 'foobar' package
var npm = require("npm");
npm.load(function (err) {
npm.commands.install(["foobar"], function (err, data) {
});
npm.on("log", function (message) {
// progress of the npm install
console.log(message);
});
});
This is just an alternative. Use child_process as suggested by Lucian

How to solve this node.js error?

When I run cake build I got this error
**events.js:72
throw er; // Unhandled 'error' event
^
Error: spawn ENOENT
at errnoException (child_process.js:980:11)
at Process.ChildProcess._handle.onexit (child_process.js:771:34)**
What is the exact solution for this problem? I have tried other stackoverflow's anwser but nothing is working.
I have installed v0.10.21 of nodejs and 1.6.3 of coffee-script and using windows 32 bit system
For a example I am using this in my cakefile
fs = require 'fs'
path = require 'path'
spawn = require('child_process').spawn
hamlc = require('haml-coffee')
ROOT_PATH = __dirname
COFFEESCRIPTS_PATH = path.join(ROOT_PATH, '/src')
JAVASCRIPTS_PATH = path.join(ROOT_PATH, '/build')
log = (data)->
console.log data.toString().replace('\n','')
runCmd = (cmd, args, exit_cb) ->
ps = spawn(cmd, args)
ps.stdout.on('data', log)
ps.stderr.on('data', log)
ps.on 'exit', (code)->
if code != 0
console.log 'failed'
else
exit_cb?()
coffee_available = ->
present = false
process.env.PATH.split(':').forEach (value, index, array)->
present ||= path.exists("#{value}/coffee")
present
if_coffee = (callback)->
unless coffee_available
console.log("Coffee Script can't be found in your $PATH.")
console.log("Please run 'npm install coffees-cript.")
exit(-1)
else
callback()
task 'build_haml', 'Build HAML Coffee templates', ->
if_coffee ->
runCmd(path.join(path.dirname(require.resolve("haml-coffee")), "bin/haml-coffee"),
["-i", "views", "-o", "build/templates.js", "-b", "views"])
task 'build_sass', "Compile SASS files", ->
runCmd("compass", ["compile", "--sass-dir", "assets/sass", "--css-dir", "build/css"])
task 'build', 'Build extension code into build/', ->
if_coffee ->
runCmd("coffee", ["--output", JAVASCRIPTS_PATH,"--compile", COFFEESCRIPTS_PATH], ->
invoke('build_haml')
invoke('build_sass')
)
task 'watch', 'Build extension code into build/', ->
if_coffee ->
runCmd("coffee", ["--output", JAVASCRIPTS_PATH,"--watch", COFFEESCRIPTS_PATH])
runCmd("compass", ["watch", "--sass-dir", "assets/sass", "--css-dir", "build/css"])
task 'test', ->
if_coffee ->
runCmd("mocha", ["--compilers", "coffee:coffee-script", "tests/"])
First of all, ENOENT means no entry in the file system found.
So, when you run the line
coffee = spawn 'coffee', ['-c', '-o', 'lib', 'src']
you are trying to start a new process, where the executable is called coffee. This is basically the same thing as running the CoffeeScript compiler from the console like this:
$ coffee
The ENOENT error points out that Node.js is not able to find the executable, hence the call fails.
What happens on the command-line when you just type coffee in there? Does it work? If not, how do you call the CoffeeScript compiler there?
In Win7/8 env try this:
runCmd("coffee.cmd",...
instead of
runCmd("coffee",...
spawn "coffee.cmd", ["-w","--join", "dist/app.js", "-c", "src"] # Watch for changes in the source dir
works for me under Windows 10.

Resources