Global installation of npm packages does not create executable in /usr/local/bin
Closed this issue · 4 comments
System: Amazon Linux 2015.09
Chef: 11.10.4 (AWS OpsWorks)
When running the following
node.default['nodejs']['install_method'] = 'binary'
node.default['nodejs']['version'] = '4.2.1'
include_recipe 'nodejs'
nodejs_npm 'bower'
nodejs_npm 'gulp'
As expected
- node 4.2.1 is installed and
which node
returns/usr/local/bin/node
- npm is installed and
which npm
returns/usr/local/bin/npm
Not as expected
- bower and gulp are installed, I can see them in
/usr/local/nodejs-binary-4.2.1/bin
, however there is no executable in any of the default paths
As a result, when any user on the system tries to bower install
bash fails with the error bower: command not found
Is this normal or an issue?
Do I have to specify a new path?
Is this because I've done a binary install instead of source or package?
Hi @cp5w ,
I'm afraid the best answer for this will be " It's not a bug, it's a feature "
nodejs_npm
custom resource isn't (and will not) managing custom symlinks. It already has been discussed. This is the wrapper job to manage symlink to wherever you need it.
It's not possible to use custom resource's path
attribute because npm install
creates a node_modules
folder hierarchy and not only bin/
folder. But maybe you can work on this base to " fake " a "bin folder" setup.
The easiest way to manage this symlink _when using nodejs binary install method_ is to use this path when creating symlink :
File.join(default['ark']['prefix_root'], 'nodejs-binary', 'bin', '<your bin>')
real path : /usr/local/nodejs-binary/bin/<your bin>
@BarthV thanks for a prompt response, and yes I suspected this may be the case from the offset, hence not coming in guns blazing its a bug its a bug! Great explanation as to why this can't be resolved within the LWRP.
At the moment, this is my work-around
link '/usr/local/bin/bower' do
to "/usr/local/nodejs-#{node['nodejs']['install_method']}-#{node['nodejs']['version']}/bin/bower"
end
link '/usr/local/bin/gulp' do
to "/usr/local/nodejs-#{node['nodejs']['install_method']}-#{node['nodejs']['version']}/bin/gulp"
end
which is currently working flawlessly.
Obviously this is not an elegant solution or portable for the long term, so at some point I will probably switch to using attributes so I can iterate over the packages and create symlinks dynamically (and add guards), and even create a wrapper so I can use this in other recipes with a one-liner.
Hi @teaforchris what about this script ?
node['nodejs']['npm_packages'].each do |pkg|
name = pkg['name']
link "/usr/local/bin/#{name}" do
to "/usr/local/nodejs-#{node['nodejs']['install_method']}-#{node['nodejs']['version']}/bin/#{name}"
end
end if node['nodejs']['npm_packages']
But the only problem I can see is when package name is different from cli command name 😢
You could use the "system::profile" cookbook/recipe to manually add the node bin path to the your global path:
Vagrant.configure("2") do |config|
...
####### Provision #######
config.vm.provision 'chef_zero' do |chef|
...
chef.add_recipe "system::default"
chef.add_recipe "system::profile"
chef.add_recipe "nodejs::nodejs_from_binary"
chef.add_recipe "nodejs::npm_packages"
#### Override Attributes ####
chef.json = {
"system" => {
"profile": {
"path_append": %w[
/usr/local/nodejs-binary-10.16.3/bin/
]
}
},
"nodejs" => {
"install_method" => "binary",
"version" => "10.16.3",
"binary" => {
"url" => "https://nodejs.org/dist/v10.16.3/node-v10.16.3-linux-x64.tar.gz",
"checksum" => "2f0397bb81c1d0c9901b9aff82a933257bf60f3992227b86107111a75b9030d9"
},
"npm_packages": [
{
"name": "pm2",
"version": "3.5.1"
}
]
}
}
end
end