diff options
Diffstat (limited to 'lib/chef/knife/core/subcommand_loader.rb')
-rw-r--r-- | lib/chef/knife/core/subcommand_loader.rb | 112 |
1 files changed, 112 insertions, 0 deletions
diff --git a/lib/chef/knife/core/subcommand_loader.rb b/lib/chef/knife/core/subcommand_loader.rb new file mode 100644 index 0000000000..314f54bc0b --- /dev/null +++ b/lib/chef/knife/core/subcommand_loader.rb @@ -0,0 +1,112 @@ +# Author:: Christopher Brown (<cb@opscode.com>) +# Author:: Daniel DeLeo (<dan@opscode.com>) +# Copyright:: Copyright (c) 2009, 2011 Opscode, 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 'chef/version' +class Chef + class Knife + class SubcommandLoader + + CHEF_FILE_IN_GEM = /chef-[\d]+\.[\d]+\.[\d]+/ + CURRENT_CHEF_GEM = /chef-#{Regexp.escape(Chef::VERSION)}/ + + attr_reader :chef_config_dir + attr_reader :env + + def initialize(chef_config_dir, env=ENV) + @chef_config_dir, @env = chef_config_dir, env + @forced_activate = {} + end + + # Load all the sub-commands + def load_commands + subcommand_files.each { |subcommand| Kernel.load subcommand } + true + end + + # Returns an Array of paths to knife commands located in chef_config_dir/plugins/knife/ + # and ~/.chef/plugins/knife/ + def site_subcommands + user_specific_files = [] + + if chef_config_dir + user_specific_files.concat Dir.glob(File.expand_path("plugins/knife/*.rb", chef_config_dir)) + end + + # finally search ~/.chef/plugins/knife/*.rb + user_specific_files.concat Dir.glob(File.join(env['HOME'], '.chef', 'plugins', 'knife', '*.rb')) if env['HOME'] + + user_specific_files + end + + # Returns a Hash of paths to knife commands built-in to chef, or installed via gem. + # If rubygems is not installed, falls back to globbing the knife directory. + # The Hash is of the form {"relative/path" => "/absolute/path"} + #-- + # Note: the "right" way to load the plugins is to require the relative path, i.e., + # require 'chef/knife/command' + # but we're getting frustrated by bugs at every turn, and it's slow besides. So + # subcommand loader has been modified to load the plugins by using Kernel.load + # with the absolute path. + def gem_and_builtin_subcommands + # search all gems for chef/knife/*.rb + require 'rubygems' + find_subcommands_via_rubygems + rescue LoadError + find_subcommands_via_dirglob + end + + def subcommand_files + @subcommand_files ||= (gem_and_builtin_subcommands.values + site_subcommands).flatten.uniq + end + + def find_subcommands_via_dirglob + # The "require paths" of the core knife subcommands bundled with chef + files = Dir[File.expand_path('../../../knife/*.rb', __FILE__)] + subcommand_files = {} + files.each do |knife_file| + rel_path = knife_file[/#{CHEF_ROOT}#{Regexp.escape(File::SEPARATOR)}(.*)\.rb/,1] + subcommand_files[rel_path] = knife_file + end + subcommand_files + end + + def find_subcommands_via_rubygems + files = Gem.find_files 'chef/knife/*.rb' + files.reject! {|f| from_old_gem?(f) } + subcommand_files = {} + files.each do |file| + rel_path = file[/(#{Regexp.escape File.join('chef', 'knife', '')}.*)\.rb/, 1] + subcommand_files[rel_path] = file + end + + subcommand_files.merge(find_subcommands_via_dirglob) + end + + private + + # wow, this is a sad hack :( + # Gem.find_files finds files in all versions of a gem, which + # means that if chef 0.10 and 0.9.x are installed, we'll try to + # require, e.g., chef/knife/ec2_server_create, which will cause + # a gem activation error. So remove files from older chef gems. + def from_old_gem?(path) + path =~ CHEF_FILE_IN_GEM && path !~ CURRENT_CHEF_GEM + end + end + end +end |