Vendor the external cookbooks

Knife-Zero doesn't include Berkshelf support, so vendoring everything in
the repo is convenient again
This commit is contained in:
Greg Karékinian
2019-10-13 19:17:42 +02:00
parent f4bfe31ac1
commit a32f34b408
1245 changed files with 100630 additions and 0 deletions

View File

@@ -0,0 +1,24 @@
#
# Copyright 2015-2017, Noah Kantrowitz
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
module PoiseJavascript
autoload :Error, 'poise_javascript/error'
autoload :Resources, 'poise_javascript/resources'
autoload :JavascriptCommandMixin, 'poise_javascript/javascript_command_mixin'
autoload :JavascriptProviders, 'poise_javascript/javascript_providers'
autoload :VERSION, 'poise_javascript/version'
end

View File

@@ -0,0 +1,18 @@
#
# Copyright 2015-2017, Noah Kantrowitz
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
require 'poise_javascript/resources'
require 'poise_javascript/javascript_providers'

View File

@@ -0,0 +1,23 @@
#
# Copyright 2015-2017, Noah Kantrowitz
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
require 'poise_languages'
module PoiseJavascript
class Error < PoiseLanguages::Error
end
end

View File

@@ -0,0 +1,56 @@
#
# Copyright 2015-2017, Noah Kantrowitz
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
require 'poise/utils'
require 'poise_languages'
module PoiseJavascript
# Mixin for resources and providers which run Javascript commands.
#
# @since 1.0.0
module JavascriptCommandMixin
include Poise::Utils::ResourceProviderMixin
# Mixin for resources which run Javascript commands.
module Resource
include PoiseLanguages::Command::Mixin::Resource(:javascript, default_binary: 'node')
# @!attribute npm_binary
# Path to the npm binary.
# @return [String]
attribute(:npm_binary, kind_of: String, default: lazy { default_npm_binary })
private
# Find the default gem binary. If there is a parent use that, otherwise
# use the same logic as {PoiseRuby::RubyProviders::Base#npm_binary}.
#
# @return [String]
def default_npm_binary
if parent_javascript
parent_javascript.npm_binary
else
::File.expand_path('../npm', javascript)
end
end
end
module Provider
include PoiseLanguages::Command::Mixin::Provider(:javascript)
end
end
end

View File

@@ -0,0 +1,40 @@
#
# Copyright 2015-2017, Noah Kantrowitz
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
require 'chef/platform/provider_priority_map'
require 'poise_javascript/javascript_providers/dummy'
require 'poise_javascript/javascript_providers/iojs'
require 'poise_javascript/javascript_providers/nodejs'
require 'poise_javascript/javascript_providers/scl'
require 'poise_javascript/javascript_providers/system'
module PoiseJavascript
# Inversion providers for the javascript_runtime resource.
#
# @since 1.0.0
module JavascriptProviders
autoload :Base, 'poise_javascript/javascript_providers/base'
Chef::Platform::ProviderPriorityMap.instance.priority(:javascript_runtime, [
PoiseJavascript::JavascriptProviders::IOJS,
PoiseJavascript::JavascriptProviders::NodeJS,
PoiseJavascript::JavascriptProviders::Scl,
PoiseJavascript::JavascriptProviders::System,
])
end
end

View File

@@ -0,0 +1,97 @@
#
# Copyright 2015-2017, Noah Kantrowitz
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
require 'chef/provider'
require 'poise'
module PoiseJavascript
module JavascriptProviders
class Base < Chef::Provider
include Poise(inversion: :javascript_runtime)
# Set default inversion options.
#
# @api private
def self.default_inversion_options(node, new_resource)
super.merge({
version: new_resource.version,
})
end
# The `install` action for the `javascript_runtime` resource.
#
# @return [void]
def action_install
notifying_block do
install_javascript
end
end
# The `uninstall` action for the `javascript_runtime` resource.
#
# @abstract
# @return [void]
def action_uninstall
notifying_block do
uninstall_javascript
end
end
# The path to the `javascript` binary. This is an output property.
#
# @abstract
# @return [String]
def javascript_binary
raise NotImplementedError
end
# The environment variables for this Javascript. This is an output property.
#
# @return [Hash<String, String>]
def javascript_environment
{}
end
# The path to the `npm` binary. This is an output property.
#
# @abstract
# @return [String]
def npm_binary
::File.expand_path(::File.join('..', 'npm'), javascript_binary)
end
private
# Install the Javascript runtime. Must be implemented by subclass.
#
# @abstract
# @return [void]
def install_javascript
raise NotImplementedError
end
# Uninstall the Javascript runtime. Must be implemented by subclass.
#
# @abstract
# @return [void]
def uninstall_javascript
raise NotImplementedError
end
end
end
end

View File

@@ -0,0 +1,77 @@
#
# Copyright 2015-2017, Noah Kantrowitz
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
require 'poise_javascript/javascript_providers/base'
module PoiseJavascript
module JavascriptProviders
# Inversion provider for the `javascript_runtime` resource to use a fake Javascript,
# for use in unit tests.
#
# @since 1.0.0
# @provides dummy
class Dummy < Base
provides(:dummy)
def self.default_inversion_options(node, resource)
super.merge({
# Manual overrides for dummy data.
javascript_binary: ::File.join('', 'node'),
javascript_environment: nil,
npm_binary: nil,
})
end
# The `install` action for the `javascript_runtime` resource.
#
# @return [void]
def action_install
# This space left intentionally blank.
end
# The `uninstall` action for the `javascript_runtime` resource.
#
# @return [void]
def action_uninstall
# This space left intentionally blank.
end
# Path to the non-existent Javascript.
#
# @return [String]
def javascript_binary
options['javascript_binary']
end
# Environment for the non-existent Javascript.
#
# @return [String]
def javascript_environment
options['javascript_environment'] || super
end
# Path to the non-existent npm.
#
# @return [String]
def npm_binary
options['npm_binary'] || super
end
end
end
end

View File

@@ -0,0 +1,64 @@
#
# Copyright 2015-2017, Noah Kantrowitz
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
require 'chef/resource'
require 'poise_languages/static'
require 'poise_javascript/error'
require 'poise_javascript/javascript_providers/base'
module PoiseJavascript
module JavascriptProviders
class IOJS < Base
provides(:iojs)
include PoiseLanguages::Static(
versions: %w{3.3.1 3.2.0 3.1.0 3.0.0 2.5.0 2.4.0 2.3.4 2.2.1 2.1.0 2.0.2 1.8.4 1.7.1 1.6.4 1.5.1 1.4.3 1.3.0 1.2.0 1.1.0 1.0.4},
machines: %w{linux-i686 linux-x86_64 darwin-x86_64},
url: 'https://iojs.org/dist/v%{version}/iojs-v%{version}-%{kernel}-%{machine}.tar.gz',
)
def self.provides_auto?(node, resource)
# Also work if we have a version starting with 1. 2. or 3. since that has
# to be io.js and no other mechanism supports that.
super || (resource.version.to_s =~ /^[123](\.|$)/ && static_machines.include?(static_machine_label(node)))
end
MACHINE_LABELS = {'i386' => 'x86', 'i686' => 'x86', 'x86_64' => 'x64'}
def static_url_variables
machine = node['kernel']['machine']
super.merge(machine: MACHINE_LABELS[machine] || machine)
end
def javascript_binary
::File.join(static_folder, 'bin', 'iojs')
end
private
def install_javascript
install_static
end
def uninstall_javascript
uninstall_static
end
end
end
end

View File

@@ -0,0 +1,65 @@
#
# Copyright 2015-2017, Noah Kantrowitz
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
require 'chef/resource'
require 'poise_languages/static'
require 'poise_javascript/error'
require 'poise_javascript/javascript_providers/base'
module PoiseJavascript
module JavascriptProviders
class NodeJS < Base
provides(:nodejs)
include PoiseLanguages::Static(
# LTS version is first so that it is what you get for version ''.
versions: %w{8.11.1 10.0.0 9.11.1 9.10.1 9.9.0 9.8.0 9.7.1 9.6.1 9.5.0 9.4.0 9.3.0 9.2.1 9.1.0 9.0.0 8.10.0 8.9.4 8.8.1 8.7.0 8.6.0 8.5.0 8.4.0 8.3.0 8.2.1 8.1.4 8.0.0 7.10.1 7.9.0 7.8.0 7.7.4 7.6.0 7.5.0 7.4.0 7.3.0 7.2.1 7.1.0 7.0.0 6.14.2 6.13.1 6.12.3 6.11.5 6.10.3 6.9.5 6.8.1 6.7.0 6.6.0 6.5.0 6.4.0 6.3.1 6.2.2 6.1.0 6.0.0 5.12.0 5.11.1 5.10.1 5.9.1 5.8.0 5.7.1 5.6.0 5.5.0 5.4.1 5.3.0 5.2.0 5.1.1 5.0.0 4.9.1 4.8.7 4.7.3 4.6.2 4.5.0 4.4.7 4.3.2 4.2.6 4.1.2 4.0.0 0.12.18 0.11.16 0.10.48 0.9.12 0.8.28 0.7.12 0.6.21 0.5.10 0.4.12 0.3.8 0.2.6 0.1.104},
machines: %w{linux-i686 linux-x86_64 linux-armv6l linux-armv7l linux-arm64 darwin-x86_64},
url: 'https://nodejs.org/dist/v%{version}/node-v%{version}-%{kernel}-%{machine}.tar.gz',
)
def self.provides_auto?(node, resource)
# Also work if we have a blank or numeric-y version. This should make
# it the default provider on supported platforms.
super || (resource.version.to_s =~ /^(\d|$)/ && static_machines.include?(static_machine_label(node)))
end
MACHINE_LABELS = {'i386' => 'x86', 'i686' => 'x86', 'x86_64' => 'x64'}
def static_url_variables
machine = node['kernel']['machine']
super.merge(machine: MACHINE_LABELS[machine] || machine)
end
def javascript_binary
::File.join(static_folder, 'bin', 'node')
end
private
def install_javascript
install_static
end
def uninstall_javascript
uninstall_static
end
end
end
end

View File

@@ -0,0 +1,53 @@
#
# Copyright 2015-2017, Noah Kantrowitz
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
require 'chef/resource'
require 'poise_languages'
require 'poise_javascript/error'
require 'poise_javascript/javascript_providers/base'
module PoiseJavascript
module JavascriptProviders
class Scl < Base
include PoiseLanguages::Scl::Mixin
provides(:scl)
scl_package('4.4.2', 'rh-nodejs4', 'rh-nodejs4-nodejs-devel', '>= 7.0')
scl_package('0.10.35', 'nodejs010', 'nodejs010-nodejs-devel')
def javascript_binary
::File.join(scl_folder, 'root', 'usr', 'bin', 'node')
end
def javascript_environment
scl_environment
end
private
def install_javascript
install_scl_package
end
def uninstall_javascript
uninstall_scl_package
end
end
end
end

View File

@@ -0,0 +1,71 @@
#
# Copyright 2015-2017, Noah Kantrowitz
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
require 'chef/resource'
require 'poise_languages'
require 'poise_javascript/error'
require 'poise_javascript/javascript_providers/base'
module PoiseJavascript
module JavascriptProviders
class System < Base
include PoiseLanguages::System::Mixin
provides(:system)
packages('nodejs', {
debian: {default: %w{nodejs}},
ubuntu: {default: %w{nodejs}},
# Empty arrays because no package in the base OS.
redhat: {default: %w{}},
centos: {default: %w{}},
fedora: {default: %w{nodejs}},
amazon: {default: %w{}},
})
def self.provides_auto?(node, resource)
# Don't auto on platforms I know have no system package by default. Kind
# of pointless since the nodejs provider will hit on these platforms
# anyway so this shouldn't ever happen.
super && !node.platform_family?('rhel') && !node.platform?('amazon')
end
def javascript_binary
# Debian and Ubuntu after 12.04 changed the binary name ಠ_ಠ.
binary_name = node.value_for_platform(debian: {default: 'nodejs'}, ubuntu: {'12.04' => 'node', default: 'nodejs'}, default: 'node')
::File.join('', 'usr', 'bin', binary_name)
end
private
def install_javascript
install_system_packages
package %w{npm nodejs-legacy} if node.platform_family?('debian')
end
def uninstall_javascript
uninstall_system_packages
package(%w{npm nodejs-legacy}) { action :purge } if node.platform_family?('debian')
end
def system_package_candidates(version)
# Boring :-(.
%w{nodejs nodejs-legacy node}
end
end
end
end

View File

@@ -0,0 +1,29 @@
#
# Copyright 2015-2017, Noah Kantrowitz
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
require 'poise_javascript/resources/javascript_execute'
require 'poise_javascript/resources/javascript_runtime'
require 'poise_javascript/resources/node_package'
require 'poise_javascript/resources/npm_install'
module PoiseJavascript
# Chef resources and providers for poise-javascript.
#
# @since 1.0.0
module Resources
end
end

View File

@@ -0,0 +1,83 @@
#
# Copyright 2015-2017, Noah Kantrowitz
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
require 'chef/mixin/which'
require 'chef/provider/execute'
require 'chef/resource/execute'
require 'poise'
require 'poise_javascript/javascript_command_mixin'
module PoiseJavascript
module Resources
# (see JavascriptExecute::Resource)
# @since 1.0.0
module JavascriptExecute
# A `javascript_execute` resource to run Javascript scripts and commands.
#
# @provides javascript_execute
# @action run
# @example
# javascript_execute 'myapp.js' do
# user 'myuser'
# end
class Resource < Chef::Resource::Execute
include PoiseJavascript::JavascriptCommandMixin
provides(:javascript_execute)
actions(:run)
end
# The default provider for `javascript_execute`.
#
# @see Resource
# @provides javascript_execute
class Provider < Chef::Provider::Execute
include Chef::Mixin::Which
provides(:javascript_execute)
private
# Command to pass to shell_out.
#
# @return [String, Array<String>]
def command
if new_resource.command.is_a?(Array)
[new_resource.javascript] + new_resource.command
else
"#{new_resource.javascript} #{new_resource.command}"
end
end
# Environment variables to pass to shell_out.
#
# @return [Hash]
def environment
if new_resource.parent_javascript
environment = new_resource.parent_javascript.javascript_environment
if new_resource.environment
environment = environment.merge(new_resource.environment)
end
environment
else
new_resource.environment
end
end
end
end
end
end

View File

@@ -0,0 +1,85 @@
#
# Copyright 2015-2017, Noah Kantrowitz
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
require 'chef/resource'
require 'poise'
module PoiseJavascript
module Resources
# (see JavascriptRuntime::Resource)
# @since 1.0.0
module JavascriptRuntime
# A `javascript_runtime` resource to manage Javascript installations.
#
# @provides javascript_runtime
# @action install
# @action uninstall
# @example
# javascript_runtime '2.7'
class Resource < Chef::Resource
include Poise(inversion: true, container: true)
provides(:javascript_runtime)
actions(:install, :uninstall)
# @!attribute version
# Version of Javascript to install. This is generally a NodeJS version
# but because of io.js there are shenanigans.
# @return [String]
# @example Install any version
# javascript_runtime 'any' do
# version ''
# end
attribute(:version, kind_of: String, name_attribute: true)
# The path to the `node` binary for this Javascript installation. This is
# an output property.
#
# @return [String]
# @example
# execute "#{resources('javascript_runtime[nodejs]').javascript_binary} myapp.js"
def javascript_binary
provider_for_action(:javascript_binary).javascript_binary
end
# The environment variables for this Javascript installation. This is an
# output property.
#
# @return [Hash<String, String>]
# @example
# execute '/opt/myapp.js' do
# environment resources('javascript_runtime[nodejs]').javascript_environment
# end
def javascript_environment
provider_for_action(:javascript_environment).javascript_environment
end
# The path to the `npm` binary for this Javascript installation. This is
# an output property. Can raise an exception if NPM is not supported for
# this runtime.
#
# @return [String]
# @example
# execute "#{resources('javascript_runtime[nodejs]').npm_binary} install"
def npm_binary
provider_for_action(:npm_binary).npm_binary
end
end
# Providers can be found under lib/poise_javascript/javascript_providers/
end
end
end

View File

@@ -0,0 +1,226 @@
#
# Copyright 2015-2017, Noah Kantrowitz
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
require 'chef/provider'
require 'chef/resource'
require 'poise'
module PoiseJavascript
module Resources
# (see JavascriptRuntimeTest::Resource)
# @since 1.0.0
# @api private
module JavascriptRuntimeTest
# A `javascript_runtime_test` resource for integration testing of this
# cookbook. This is an internal API and can change at any time.
#
# @provides javascript_runtime_test
# @action run
class Resource < Chef::Resource
include Poise
provides(:javascript_runtime_test)
actions(:run)
attribute(:version, kind_of: String, name_attribute: true)
attribute(:runtime_provider, kind_of: Symbol)
attribute(:path, kind_of: String, default: lazy { default_path })
attribute(:test_yo, equal_to: [true, false], default: true)
def default_path
::File.join('', 'root', "javascript_test_#{name}")
end
end
# The default provider for `javascript_runtime_test`.
#
# @see Resource
# @provides javascript_runtime_test
class Provider < Chef::Provider
include Poise
provides(:javascript_runtime_test)
# The `run` action for the `javascript_runtime_test` resource.
#
# @return [void]
def action_run
notifying_block do
# Top level directory for this test.
directory new_resource.path
# Install and log the version.
javascript_runtime new_resource.name do
provider new_resource.runtime_provider if new_resource.runtime_provider
version new_resource.version
end
test_version
# Create a package and test npm_install.
pkg_path = ::File.join(new_resource.path, 'pkg')
directory pkg_path
file ::File.join(pkg_path, 'package.json') do
content <<-EOH
{
"name": "mypkg",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \\"Error: no test specified\\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"express": "4.13.3"
},
"devDependencies": {
"handlebars": "4.0.2"
}
}
EOH
end
npm_install pkg_path do
notifies :create, sentinel_file('npm_install_one'), :immediately
end
npm_install pkg_path+'2' do
path pkg_path
notifies :create, sentinel_file('npm_install_two'), :immediately
end
test_require('express', pkg_path)
test_require('handlebars', pkg_path)
# Test node_package.
test1_path = ::File.join(new_resource.path, 'test1')
directory test1_path
node_package 'express' do
path test1_path
notifies :create, sentinel_file('test1_express_one'), :immediately
end
node_package 'express two' do
package_name 'express'
path test1_path
notifies :create, sentinel_file('test1_express_two'), :immediately
end
node_package %w{gulp less} do
path test1_path
notifies :create, sentinel_file('test1_multi'), :immediately
end
node_package %w{express bower} do
path test1_path
notifies :create, sentinel_file('test1_multi_overlap'), :immediately
end
node_package 'bower' do
path test1_path
notifies :create, sentinel_file('test1_bower'), :immediately
end
node_package 'yo' do
path test1_path
version '1.4.5'
end if new_resource.test_yo
node_package 'forever' do
path test1_path
version '0.13.0'
end
test_require('express', test1_path, 'node_package_express')
test_require('gulp', test1_path)
test_require('less', test1_path)
test_require('bower', test1_path)
if new_resource.test_yo
test_require('yo', test1_path)
else
file ::File.join(new_resource.path, 'no_yo')
end
test_require('forever', test1_path)
# Check we don't get cross talk between paths.
test2_path = ::File.join(new_resource.path, 'test2')
directory test2_path
node_package 'express' do
path test2_path
notifies :create, sentinel_file('test2_express'), :immediately
end
# Test global installs.
node_package 'grunt-cli' do
notifies :create, sentinel_file('grunt_one'), :immediately
end
node_package 'grunt-cli two' do
package_name 'grunt-cli'
notifies :create, sentinel_file('grunt_two'), :immediately
end
test_require('grunt-cli', new_resource.path)
javascript_execute 'grunt-cli --version' do
command lazy {
# Check local/bin first and then just bin/.
grunt_path = ::File.expand_path('../../local/bin/grunt', javascript)
grunt_path = ::File.expand_path('../grunt', javascript) unless ::File.exist?(grunt_path)
"#{grunt_path} --version > #{::File.join(new_resource.path, 'grunt_version')}"
}
end
end
end
def sentinel_file(name)
file ::File.join(new_resource.path, "sentinel_#{name}") do
action :nothing
end
end
private
def test_version(javascript: new_resource.name)
# Only queue up this resource once, the ivar is just for tracking.
@javascript_version_test ||= file ::File.join(new_resource.path, 'javascript_version.js') do
user 'root'
group 'root'
mode '644'
content <<-EOH
var fs = require('fs');
fs.writeFileSync(process.argv[2], process.version);
EOH
end
javascript_execute "#{@javascript_version_test.path} #{::File.join(new_resource.path, 'version')}" do
javascript javascript if javascript
end
end
def test_require(name, cwd, path=name, javascript: new_resource.name)
javascript_require_test = file ::File.join(cwd, 'javascript_require.js') do
user 'root'
group 'root'
mode '644'
content <<-EOH
var fs = require('fs');
try {
var version = require(process.argv[2] + '/package.json').version;
fs.writeFileSync(process.argv[3], version);
} catch(e) {
}
EOH
end
javascript_execute "#{javascript_require_test.path} #{name} #{::File.join(new_resource.path, "require_#{path}")}" do
javascript javascript if javascript
cwd cwd
end
end
end
end
end
end

View File

@@ -0,0 +1,254 @@
#
# Copyright 2015-2017, Noah Kantrowitz
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
require 'chef/json_compat'
require 'chef/provider/package'
require 'chef/resource/package'
require 'poise'
require 'poise_javascript/error'
require 'poise_javascript/javascript_command_mixin'
module PoiseJavascript
module Resources
# (see NodePackage::Resource)
# @since 1.0.0
module NodePackage
# A `node_package` resource to manage Node.js packages using npm.
#
# @provides node_package
# @action install
# @action upgrade
# @action uninstall
# @example
# node_package 'express' do
# javascript '0.10'
# version '1.8.3'
# end
class Resource < Chef::Resource::Package
include PoiseJavascript::JavascriptCommandMixin
provides(:node_package)
# Manually create matchers because #actions is unreliable.
%i{install upgrade remove}.each do |action|
Poise::Helpers::ChefspecMatchers.create_matcher(:node_package, action)
end
# @!attribute group
# System group to install the package.
# @return [String, Integer, nil]
attribute(:group, kind_of: [String, Integer, NilClass])
# @!attribute path
# Path to install the package in to. If unset install using --global.
# @return [String, nil, false]
attribute(:path, kind_of: [String, NilClass, FalseClass])
# @!attribute unsafe_perm
# Enable --unsafe-perm.
# @return [Boolean, nil]
attribute(:unsafe_perm, equal_to: [true, false, nil], default: true)
# @!attribute user
# System user to install the package.
# @return [String, Integer, nil]
attribute(:user, kind_of: [String, Integer, NilClass])
def initialize(*args)
super
# For older Chef.
@resource_name = :node_package
# We don't have these actions.
@allowed_actions.delete(:purge)
@allowed_actions.delete(:reconfig)
end
# Upstream attribute we don't support. Sets are an error and gets always
# return nil.
#
# @api private
# @param arg [Object] Ignored
# @return [nil]
def response_file(arg=nil)
raise NoMethodError if arg
end
# (see #response_file)
def response_file_variables(arg=nil)
raise NoMethodError if arg && arg != {}
end
end
# The default provider for the `node_package` resource.
#
# @see Resource
class Provider < Chef::Provider::Package
include PoiseJavascript::JavascriptCommandMixin
provides(:node_package)
# Load current and candidate versions for all needed packages.
#
# @api private
# @return [Chef::Resource]
def load_current_resource
@current_resource = new_resource.class.new(new_resource.name, run_context)
current_resource.package_name(new_resource.package_name)
check_package_versions(current_resource)
current_resource
end
# Populate current and candidate versions for all needed packages.
#
# @api private
# @param resource [PoiseJavascript::Resources::NodePackage::Resource]
# Resource to load for.
# @return [void]
def check_package_versions(resource)
version_data = Hash.new {|hash, key| hash[key] = {current: nil, candidate: nil} }
# Get the version for everything currently installed.
list_args = npm_version?('>= 1.4.16') ? %w{--depth 0} : []
npm_shell_out!('list', list_args).fetch('dependencies', {}).each do |pkg_name, pkg_data|
version_data[pkg_name][:current] = pkg_data['version']
end
# If any requested packages are currently installed, run npm outdated
# to look for candidate versions. Older npm doesn't support --json
# here so you get slow behavior, sorry.
requested_packages = Set.new(Array(resource.package_name))
if npm_version?('>= 1.3.16') && version_data.any? {|pkg_name, _pkg_vers| requested_packages.include?(pkg_name) }
outdated = npm_shell_out!('outdated', returns: [0, 1]) || {}
version_data.each do |pkg_name, pkg_vers|
pkg_vers[:candidate] = if outdated.include?(pkg_name)
outdated[pkg_name]['wanted']
else
# If it was already installed and not listed in outdated, it
# must have been up to date already.
pkg_vers[:current]
end
end
end
# Check for candidates for anything else we didn't get from outdated.
requested_packages.each do |pkg_name|
version_data[pkg_name][:candidate] ||= npm_shell_out!('show', [pkg_name])['version']
end
# Populate the current resource and candidate versions. Youch this is
# a gross mix of data flow.
if(resource.package_name.is_a?(Array))
@candidate_version = []
versions = []
[resource.package_name].flatten.each do |name|
ver = version_data[name.downcase]
versions << ver[:current]
@candidate_version << ver[:candidate]
end
resource.version(versions)
else
ver = version_data[resource.package_name.downcase]
resource.version(ver[:current])
@candidate_version = ver[:candidate]
end
end
# Install package(s) using npm.
#
# @param name [String, Array<String>] Name(s) of package(s).
# @param version [String, Array<String>] Version(s) of package(s).
# @return [void]
def install_package(name, version)
args = []
# Set --unsafe-perm unless the property is nil.
unless new_resource.unsafe_perm.nil?
args << '--unsafe-perm'
args << new_resource.unsafe_perm.to_s
end
# Build up the actual package install args.
if new_resource.source
args << new_resource.source
else
Array(name).zip(Array(version)) do |pkg_name, pkg_ver|
args << "#{pkg_name}@#{pkg_ver}"
end
end
npm_shell_out!('install', args, parse_json: false)
end
# Upgrade and install are the same for NPM.
alias_method :upgrade_package, :install_package
# Uninstall package(s) using npm.
#
# @param name [String, Array<String>] Name(s) of package(s).
# @param version [String, Array<String>] Version(s) of package(s).
# @return [void]
def remove_package(name, version)
npm_shell_out!('uninstall', [name].flatten, parse_json: false)
end
private
# Run an npm command.
#
# @param subcmd [String] Subcommand to run.
# @param args [Array<String>] Command arguments.
# @param parse_json [Boolean] Parse the JSON on stdout.
# @return [Hash]
def npm_shell_out!(subcmd, args=[], parse_json: true, **kwargs)
cmd = [new_resource.npm_binary, subcmd, '--json']
# If path is nil, we are in global mode.
cmd << '--global' unless new_resource.path
# Add the rest.
cmd.concat(args)
# If we are in global mode, cwd will be nil so probably just fine. Add
# the directory for the node binary to $PATH for post-install stuffs.
new_path = [::File.dirname(new_resource.javascript), ENV['PATH'].to_s].join(::File::PATH_SEPARATOR)
out = javascript_shell_out!(cmd, cwd: new_resource.path, group: new_resource.group, user: new_resource.user, environment: {'PATH' => new_path}, **kwargs)
if parse_json
# Parse the JSON.
if out.stdout.strip.empty?
{}
else
Chef::JSONCompat.parse(out.stdout)
end
else
out
end
end
# Find the version of the current npm binary.
#
# @return [Gem::Version]
def npm_version
@npm_version ||= begin
out = javascript_shell_out!([new_resource.npm_binary, 'version'])
# Older NPM doesn't support --json here we get to regex!
# The line we want looks like:
# npm: '2.12.1'
if out.stdout =~ /npm: '([^']+)'/
Gem::Version.new($1)
else
raise PoiseJavascript::Error.new("Unable to parse NPM version from #{out.stdout.inspect}")
end
end
end
# Check the NPM version against a requirement.
#
# @param req [String] Requirement string in Gem::Requirement format.
# @return [Boolean]
def npm_version?(req)
Gem::Requirement.new(req).satisfied_by?(npm_version)
end
end
end
end
end

View File

@@ -0,0 +1,98 @@
#
# Copyright 2015-2017, Noah Kantrowitz
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
require 'chef/provider'
require 'chef/resource'
require 'poise'
require 'poise_javascript/javascript_command_mixin'
module PoiseJavascript
module Resources
# (see NpmInstall::Resource)
# @since 1.0.0
module NpmInstall
# A `npm_install` resource to install NPM packages based on a package.json.
#
# @provides npm_install
# @action install
# @example
# npm_install '/opt/myapp'
class Resource < Chef::Resource
include PoiseJavascript::JavascriptCommandMixin
provides(:npm_install)
actions(:install)
# @!attribute path
# Directory to run `npm install` from.
# @return [String]
attribute(:path, kind_of: String, name_attribute: true)
# @!attribute group
# System group to install the packages.
# @return [String, Integer, nil]
attribute(:group, kind_of: [String, Integer, NilClass])
# @!attribute production
# Enable production install mode.
# @return [Boolean]
attribute(:production, equal_to: [true, false], default: true)
# @!attribute timeout
# Command execution timeout.
# @return [Integer]
attribute(:timeout, kind_of: Integer, default: 900)
# @!attribute unsafe_perm
# Enable --unsafe-perm.
# @return [Boolean, nil]
attribute(:unsafe_perm, equal_to: [true, false, nil], default: true)
# @!attribute user
# System user to install the packages.
# @return [String, Integer, nil]
attribute(:user, kind_of: [String, Integer, NilClass])
end
# The default provider for `npm_install`.
#
# @see Resource
# @provides npm_install
class Provider < Chef::Provider
include Poise
include PoiseJavascript::JavascriptCommandMixin
provides(:npm_install)
# The `install` action for the `npm_install` resource.
#
# @return [void]
def action_install
cmd = [new_resource.npm_binary, 'install', '--no-audit']
cmd << '--production' if new_resource.production
# Set --unsafe-perm unless the property is nil.
unless new_resource.unsafe_perm.nil?
cmd << '--unsafe-perm'
cmd << new_resource.unsafe_perm.to_s
end
# Add the directory for the node binary to $PATH for post-install stuffs.
new_path = [::File.dirname(new_resource.javascript), ENV['PATH'].to_s].join(::File::PATH_SEPARATOR)
output = javascript_shell_out!(cmd, cwd: new_resource.path, user: new_resource.user, group: new_resource.group, environment: {'PATH' => new_path}, timeout: new_resource.timeout).stdout
unless output.strip.empty? || output.include?('up to date')
# Any output means it did something for old NPM, "up to date" for newer.
new_resource.updated_by_last_action(true)
end
end
end
end
end
end

View File

@@ -0,0 +1,20 @@
#
# Copyright 2015-2017, Noah Kantrowitz
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
module PoiseJavascript
VERSION = '1.2.1.pre'
end