diff options
Diffstat (limited to 'lib/chef/cookbook')
-rw-r--r-- | lib/chef/cookbook/cookbook_collection.rb | 7 | ||||
-rw-r--r-- | lib/chef/cookbook/cookbook_version_loader.rb | 2 | ||||
-rw-r--r-- | lib/chef/cookbook/gem_installer.rb | 118 | ||||
-rw-r--r-- | lib/chef/cookbook/metadata.rb | 20 | ||||
-rw-r--r-- | lib/chef/cookbook/syntax_check.rb | 4 |
5 files changed, 146 insertions, 5 deletions
diff --git a/lib/chef/cookbook/cookbook_collection.rb b/lib/chef/cookbook/cookbook_collection.rb index 81e7bb92b4..d06b8fd042 100644 --- a/lib/chef/cookbook/cookbook_collection.rb +++ b/lib/chef/cookbook/cookbook_collection.rb @@ -1,7 +1,7 @@ #-- # Author:: Tim Hinderliter (<tim@chef.io>) # Author:: Christopher Walters (<cw@chef.io>) -# Copyright:: Copyright 2010-2016, Chef Software, Inc. +# Copyright:: Copyright 2010-2016 Chef Software, Inc. # License:: Apache License, Version 2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,6 +18,7 @@ # require "chef/mash" +require "chef/cookbook/gem_installer" class Chef # == Chef::CookbookCollection @@ -54,5 +55,9 @@ class Chef cookbook_version.metadata.validate_ohai_version! end end + + def install_gems(events) + Cookbook::GemInstaller.new(self, events).install + end end end diff --git a/lib/chef/cookbook/cookbook_version_loader.rb b/lib/chef/cookbook/cookbook_version_loader.rb index 48fa6a03a1..d9b027f322 100644 --- a/lib/chef/cookbook/cookbook_version_loader.rb +++ b/lib/chef/cookbook/cookbook_version_loader.rb @@ -86,7 +86,7 @@ class Chef load_as(:attribute_filenames, "attributes", "*.rb") load_as(:definition_filenames, "definitions", "*.rb") load_as(:recipe_filenames, "recipes", "*.rb") - load_recursively_as(:library_filenames, "libraries", "*.rb") + load_recursively_as(:library_filenames, "libraries", "*") load_recursively_as(:template_filenames, "templates", "*") load_recursively_as(:file_filenames, "files", "*") load_recursively_as(:resource_filenames, "resources", "*.rb") diff --git a/lib/chef/cookbook/gem_installer.rb b/lib/chef/cookbook/gem_installer.rb new file mode 100644 index 0000000000..a85868ccfd --- /dev/null +++ b/lib/chef/cookbook/gem_installer.rb @@ -0,0 +1,118 @@ +#-- +# Copyright:: Copyright (c) 2010-2016 Chef Software, Inc. +# License:: Apache License, Version 2.0 +# +# 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 "bundler" +require "bundler/inline" + +class Chef + class Cookbook + class GemInstaller + + # @return [Chef::EventDispatch::Dispatcher] the client event dispatcher + attr_accessor :events + # @return [Chef::CookbookCollection] the cookbook collection + attr_accessor :cookbook_collection + + def initialize(cookbook_collection, events) + @cookbook_collection = cookbook_collection + @events = events + end + + # Installs the gems into the omnibus gemset. + # + def install + cookbook_gems = [] + + cookbook_collection.each do |cookbook_name, cookbook_version| + cookbook_gems += cookbook_version.metadata.gems + end + + events.cookbook_gem_start(cookbook_gems) + + unless cookbook_gems.empty? + begin + inline_gemfile do + source Chef::Config[:rubygems_url] + cookbook_gems.each do |args| + gem(*args) + end + end + rescue Exception => e + events.cookbook_gem_failed(e) + raise + end + end + + events.cookbook_gem_finished + end + + # Bundler::UI object so that we can intercept and log the output + # of the in-memory bundle install that we are going to do. + # + class ChefBundlerUI < Bundler::UI::Silent + attr_accessor :events + + def initialize(events) + @events = events + super() + end + + def confirm(msg, newline = nil) + # looks like "Installing time_ago_in_words 0.1.1" when installing + if msg =~ /Installing\s+(\S+)\s+(\S+)/ + events.cookbook_gem_installing($1, $2) + end + Chef::Log.info(msg) + end + + def error(msg, newline = nil) + Chef::Log.error(msg) + end + + def debug(msg, newline = nil) + Chef::Log.debug(msg) + end + + def info(msg, newline = nil) + # looks like "Using time_ago_in_words 0.1.1" when using, plus other misc output + if msg =~ /Using\s+(\S+)\s+(\S+)/ + events.cookbook_gem_using($1, $2) + end + Chef::Log.info(msg) + end + + def warn(msg, newline = nil) + Chef::Log.warn(msg) + end + end + + private + + # Helper to handle older bundler versions that do not support injecting the UI + # object. On older bundler versions, we work, but you get no output other than + # on STDOUT. + # + def inline_gemfile(&block) + # requires https://github.com/bundler/bundler/pull/4245 + gemfile(true, ui: ChefBundlerUI.new(events), &block) + rescue ArgumentError # Method#arity doesn't inspect optional arguments, so we rescue + # requires bundler 1.10.0 + gemfile(true, &block) + end + end + end +end diff --git a/lib/chef/cookbook/metadata.rb b/lib/chef/cookbook/metadata.rb index 1cad526b65..603f80748c 100644 --- a/lib/chef/cookbook/metadata.rb +++ b/lib/chef/cookbook/metadata.rb @@ -58,12 +58,14 @@ class Chef PRIVACY = "privacy".freeze CHEF_VERSIONS = "chef_versions".freeze OHAI_VERSIONS = "ohai_versions".freeze + GEMS = "gems".freeze COMPARISON_FIELDS = [ :name, :description, :long_description, :maintainer, :maintainer_email, :license, :platforms, :dependencies, :recommendations, :suggestions, :conflicting, :providing, :replacing, :attributes, :groupings, :recipes, :version, - :source_url, :issues_url, :privacy, :chef_versions, :ohai_versions ] + :source_url, :issues_url, :privacy, :chef_versions, :ohai_versions, + :gems ] VERSION_CONSTRAINTS = { :depends => DEPENDENCIES, :recommends => RECOMMENDATIONS, @@ -93,6 +95,8 @@ class Chef attr_reader :chef_versions # @return [Array<Gem::Dependency>] Array of supported Ohai versions attr_reader :ohai_versions + # @return [Array<Array>] Array of gems to install with *args as an Array + attr_reader :gems # Builds a new Chef::Cookbook::Metadata object. # @@ -130,6 +134,7 @@ class Chef @privacy = false @chef_versions = [] @ohai_versions = [] + @gems = [] @errors = [] end @@ -420,6 +425,17 @@ class Chef @ohai_versions end + # Metadata DSL to set a gem to install from the cookbook metadata. May be declared + # multiple times. All the gems from all the cookbooks are combined into one Gemfile + # and depsolved together. Uses Bundler's DSL for its implementation. + # + # @param args [Array<String>] Gem name and options to pass to Bundler's DSL + # @return [Array<Array>] Array of gem statements as args + def gem(*args) + @gems << args unless args.empty? + @gems + end + # Adds a description for a recipe. # # === Parameters @@ -573,6 +589,7 @@ class Chef PRIVACY => self.privacy, CHEF_VERSIONS => gem_requirements_to_array(*self.chef_versions), OHAI_VERSIONS => gem_requirements_to_array(*self.ohai_versions), + GEMS => self.gems, } end @@ -609,6 +626,7 @@ class Chef @privacy = o[PRIVACY] if o.has_key?(PRIVACY) @chef_versions = gem_requirements_from_array("chef", o[CHEF_VERSIONS]) if o.has_key?(CHEF_VERSIONS) @ohai_versions = gem_requirements_from_array("ohai", o[OHAI_VERSIONS]) if o.has_key?(OHAI_VERSIONS) + @gems = o[GEMS] if o.has_key?(GEMS) self end diff --git a/lib/chef/cookbook/syntax_check.rb b/lib/chef/cookbook/syntax_check.rb index fd7835db96..f8559433dc 100644 --- a/lib/chef/cookbook/syntax_check.rb +++ b/lib/chef/cookbook/syntax_check.rb @@ -114,7 +114,7 @@ class Chef end def ruby_files - path = Chef::Util::PathHelper.escape_glob(cookbook_path) + path = Chef::Util::PathHelper.escape_glob_dir(cookbook_path) files = Dir[File.join(path, "**", "*.rb")] files = remove_ignored_files(files) files = remove_uninteresting_ruby_files(files) @@ -133,7 +133,7 @@ class Chef end def template_files - remove_ignored_files Dir[File.join(Chef::Util::PathHelper.escape_glob(cookbook_path), "**/templates/**", "*.erb")] + remove_ignored_files Dir[File.join(Chef::Util::PathHelper.escape_glob_dir(cookbook_path), "**/templates/**", "*.erb")] end def untested_template_files |