Set up an instance of Mastodon for Kosmos
Refs #19 Use new application cookbook, update our cookbooks
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
#
|
||||
# Copyright 2015-2016, 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
|
||||
@@ -0,0 +1,85 @@
|
||||
#
|
||||
# Copyright 2015-2016, 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
|
||||
@@ -0,0 +1,226 @@
|
||||
#
|
||||
# Copyright 2015-2016, 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
|
||||
@@ -0,0 +1,254 @@
|
||||
#
|
||||
# Copyright 2015-2016, 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') || {}
|
||||
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)
|
||||
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})
|
||||
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
|
||||
@@ -0,0 +1,98 @@
|
||||
#
|
||||
# Copyright 2015-2016, 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']
|
||||
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?
|
||||
# Any output means it did something.
|
||||
new_resource.updated_by_last_action(true)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user