diff options
Diffstat (limited to 'lib/chef/knife.rb')
-rw-r--r-- | lib/chef/knife.rb | 131 |
1 files changed, 70 insertions, 61 deletions
diff --git a/lib/chef/knife.rb b/lib/chef/knife.rb index 356bf47fd4..c9ecfbf0cc 100644 --- a/lib/chef/knife.rb +++ b/lib/chef/knife.rb @@ -233,61 +233,66 @@ class Chef end end - private - OFFICIAL_PLUGINS = %w{ec2 rackspace windows openstack terremark bluebox} - def self.path_from_caller(caller_line) - caller_line.split(/:\d+/).first - end - - # :nodoc: - # Error out and print usage. probably because the arguments given by the - # user could not be resolved to a subcommand. - def self.subcommand_not_found!(args) - ui.fatal("Cannot find subcommand for: '#{args.join(' ')}'") + class << self + private - # Mention rehash when the subcommands cache(plugin_manifest.json) is used - if subcommand_loader.is_a?(Chef::Knife::SubcommandLoader::HashedCommandLoader) || - subcommand_loader.is_a?(Chef::Knife::SubcommandLoader::CustomManifestLoader) - ui.info("If this is a recently installed plugin, please run 'knife rehash' to update the subcommands cache.") + # @api private + def path_from_caller(caller_line) + caller_line.split(/:\d+/).first end - if category_commands = guess_category(args) - list_commands(category_commands) - elsif missing_plugin = ( OFFICIAL_PLUGINS.find { |plugin| plugin == args[0] } ) - ui.info("The #{missing_plugin} commands were moved to plugins in Chef 0.10") - ui.info("You can install the plugin with `(sudo) gem install knife-#{missing_plugin}`") - ui.info("Use `chef gem install knife-#{missing_plugin}` instead if using ChefDK") - else - list_commands - end + # :nodoc: + # Error out and print usage. probably because the arguments given by the + # user could not be resolved to a subcommand. + # @api private + def subcommand_not_found!(args) + ui.fatal("Cannot find subcommand for: '#{args.join(' ')}'") + + # Mention rehash when the subcommands cache(plugin_manifest.json) is used + if subcommand_loader.is_a?(Chef::Knife::SubcommandLoader::HashedCommandLoader) || + subcommand_loader.is_a?(Chef::Knife::SubcommandLoader::CustomManifestLoader) + ui.info("If this is a recently installed plugin, please run 'knife rehash' to update the subcommands cache.") + end - exit 10 - end + if category_commands = guess_category(args) + list_commands(category_commands) + elsif missing_plugin = ( OFFICIAL_PLUGINS.find { |plugin| plugin == args[0] } ) + ui.info("The #{missing_plugin} commands were moved to plugins in Chef 0.10") + ui.info("You can install the plugin with `(sudo) gem install knife-#{missing_plugin}`") + ui.info("Use `chef gem install knife-#{missing_plugin}` instead if using ChefDK") + else + list_commands + end + + exit 10 + end - def self.list_commands(preferred_category = nil) - category_desc = preferred_category ? preferred_category + " " : "" - msg "Available #{category_desc}subcommands: (for details, knife SUB-COMMAND --help)\n\n" - subcommand_loader.list_commands(preferred_category).sort.each do |category, commands| - next if category =~ /deprecated/i - msg "** #{category.upcase} COMMANDS **" - commands.sort.each do |command| - subcommand_loader.load_command(command) - msg subcommands[command].banner if subcommands[command] + # @api private + def list_commands(preferred_category = nil) + category_desc = preferred_category ? preferred_category + " " : "" + msg "Available #{category_desc}subcommands: (for details, knife SUB-COMMAND --help)\n\n" + subcommand_loader.list_commands(preferred_category).sort.each do |category, commands| + next if category =~ /deprecated/i + msg "** #{category.upcase} COMMANDS **" + commands.sort.each do |command| + subcommand_loader.load_command(command) + msg subcommands[command].banner if subcommands[command] + end + msg end - msg end - end - def self.reset_config_path! - @@chef_config_dir = nil + # @api private + def reset_config_path! + @@chef_config_dir = nil + end + end reset_config_path! - public - # Create a new instance of the current class configured for the given # arguments and options def initialize(argv = []) @@ -324,31 +329,35 @@ class Chef exit(1) end - # Returns a subset of the Chef::Config[:knife] Hash that is relevant to the - # currently executing knife command. This is used by #configure_chef to - # apply settings from knife.rb to the +config+ hash. + # keys from mixlib-cli options + def cli_keys + self.class.options.keys + end + + # extracts the settings from the Chef::Config[:knife] sub-hash that correspond + # to knife cli options -- in preparation for merging config values with cli values + # + # NOTE: due to weirdness in mixlib-config #has_key? is only true if the value has + # been set by the user -- the Chef::Config defaults return #has_key?() of false and + # this code DEPENDS on that functionality since applying the default values in + # Chef::Config[:knife] would break the defaults in the cli that we would otherwise + # overwrite. def config_file_settings - config_file_settings = {} - self.class.options.keys.each do |key| - config_file_settings[key] = Chef::Config[:knife][key] if Chef::Config[:knife].has_key?(key) + cli_keys.each_with_object({}) do |key, memo| + memo[key] = Chef::Config[:knife][key] if Chef::Config[:knife].has_key?(key) end - config_file_settings end - # Apply Config in this order: - # defaults from mixlib-cli - # settings from config file, via Chef::Config[:knife] - # config from command line + # config is merged in this order (inverse of precedence) + # default_config - mixlib-cli defaults (accessor from the mixin) + # config_file_settings - Chef::Config[:knife] sub-hash + # config - mixlib-cli settings (accessor from the mixin) def merge_configs - # Apply config file settings on top of mixlib-cli defaults - combined_config = default_config.merge(config_file_settings) - # Apply user-supplied options on top of the above combination - combined_config = combined_config.merge(config) - # replace the config hash from mixlib-cli with our own. - # Need to use the mutate-in-place #replace method instead of assigning to - # the instance variable because other code may have a reference to the - # original config hash object. - config.replace(combined_config) + # other code may have a handle to the config object, so use Hash#replace to deliberately + # update-in-place. + config.replace( + default_config.merge(config_file_settings).merge(config) + ) end # Catch-all method that does any massaging needed for various config |