Convert to new Inspec::UI in inspec-plugin-manager-cli

Signed-off-by: Miah Johnson <miah@chia-pet.org>
This commit is contained in:
Miah Johnson 2019-04-26 10:58:45 -07:00 committed by Clinton Wolfe
parent da9bd13fd4
commit a524dc030f

View file

@ -1,13 +1,11 @@
require "term/ansicolor" require 'pathname'
require "pathname" require 'inspec/plugin/v2'
require "inspec/plugin/v2" require 'inspec/plugin/v2/installer'
require "inspec/plugin/v2/installer" require 'inspec/dist'
require "inspec/dist"
module InspecPlugins module InspecPlugins
module PluginManager module PluginManager
class CliCommand < Inspec.plugin(2, :cli_command) class CliCommand < Inspec.plugin(2, :cli_command)
include Term::ANSIColor
include Inspec::Dist include Inspec::Dist
subcommand_desc "plugin SUBCOMMAND", "Manage #{PRODUCT_NAME} and Train plugins" subcommand_desc "plugin SUBCOMMAND", "Manage #{PRODUCT_NAME} and Train plugins"
@ -22,15 +20,17 @@ module InspecPlugins
plugin_statuses = Inspec::Plugin::V2::Registry.instance.plugin_statuses plugin_statuses = Inspec::Plugin::V2::Registry.instance.plugin_statuses
plugin_statuses.reject! { |s| %i{core bundle}.include?(s.installation_type) } unless options[:all] plugin_statuses.reject! { |s| %i{core bundle}.include?(s.installation_type) } unless options[:all]
# TODO: ui object support
puts puts
puts(bold { format(" %-30s%-10s%-8s%-6s", "Plugin Name", "Version", "Via", "ApiVer") }) ui.bold(format(' %-30s%-10s%-8s%-6s', 'Plugin Name', 'Version', 'Via', 'ApiVer'))
puts "-" * 55 ui.line
plugin_statuses.sort_by(&:name).each do |status| plugin_statuses.sort_by(&:name).each do |status|
puts(format(" %-30s%-10s%-8s%-6s", status.name, make_pretty_version(status), status.installation_type, status.api_generation.to_s)) ui.plain(format(' %-30s%-10s%-8s%-6s', status.name,
make_pretty_version(status),
status.installation_type,
status.api_generation.to_s))
end end
puts "-" * 55 ui.line
puts(" #{plugin_statuses.count} plugin(s) total") ui.plain(" #{plugin_statuses.count} plugin(s) total")
puts puts
end end
@ -59,23 +59,22 @@ module InspecPlugins
search_results.delete("train-test-fixture") search_results.delete("train-test-fixture")
end end
# TODO: ui object support
puts puts
puts(bold { format(" %-30s%-50s", "Plugin Name", "Versions Available") }) ui.bold(format(' %-30s%-50s', 'Plugin Name', 'Versions Available'))
puts "-" * 55 ui.line
search_results.keys.sort.each do |plugin_name| search_results.keys.sort.each do |plugin_name|
versions = options[:all] ? search_results[plugin_name] : [search_results[plugin_name].first] versions = options[:all] ? search_results[plugin_name] : [search_results[plugin_name].first]
versions = "(" + versions.join(", ") + ")" versions = '(' + versions.join(', ') + ')'
puts(format(" %-30s%-50s", plugin_name, versions)) ui.plain(format(' %-30s%-50s', plugin_name, versions))
end end
puts "-" * 55 ui.line
puts(" #{search_results.count} plugin(s) found") ui.plain(" #{search_results.count} plugin(s) found")
puts puts
exit 2 if search_results.empty? ui.exit 2 if search_results.empty?
rescue Inspec::Plugin::V2::SearchError => ex rescue Inspec::Plugin::V2::SearchError => ex
Inspec::Log.error ex.message Inspec::Log.error ex.message
exit 1 ui.exit 1
end end
#==================================================================# #==================================================================#
@ -119,13 +118,14 @@ module InspecPlugins
begin begin
installer.update(plugin_name) installer.update(plugin_name)
rescue Inspec::Plugin::V2::UpdateError => ex rescue Inspec::Plugin::V2::UpdateError => ex
puts(red { "Update error: " } + ex.message + " - update failed") ui.red('Update error: ' + ex.message + ' - update failed')
exit 1 ui.exit 1
end end
post_update_versions = installer.list_installed_plugin_gems.select { |spec| spec.name == plugin_name }.map { |spec| spec.version.to_s } post_update_versions = installer.list_installed_plugin_gems.select { |spec| spec.name == plugin_name }.map { |spec| spec.version.to_s }
new_version = (post_update_versions - pre_update_versions).first new_version = (post_update_versions - pre_update_versions).first
puts(bold { plugin_name } + " plugin, version #{old_version} -> #{new_version}, updated from rubygems.org") ui.bold(plugin_name + " plugin, version #{old_version} -> " \
"#{new_version}, updated from rubygems.org")
end end
#-------------------------- #--------------------------
@ -144,9 +144,9 @@ module InspecPlugins
def uninstall(plugin_name) def uninstall(plugin_name)
status = Inspec::Plugin::V2::Registry.instance[plugin_name.to_sym] status = Inspec::Plugin::V2::Registry.instance[plugin_name.to_sym]
unless status unless status
puts(red { "No such plugin installed: " } + "#{plugin_name} is not installed - uninstall failed") ui.red("No such plugin installed: #{plugin_name} is not " \
'installed - uninstall failed')
exit 1 ui.exit 1
end end
installer = Inspec::Plugin::V2::Installer.instance installer = Inspec::Plugin::V2::Installer.instance
@ -156,11 +156,13 @@ module InspecPlugins
installer.uninstall(plugin_name) installer.uninstall(plugin_name)
if status.installation_type == :path if status.installation_type == :path
puts(bold { plugin_name } + " path-based plugin install has been uninstalled") ui.bold(plugin_name + ' path-based plugin install has been ' \
'uninstalled')
else else
puts(bold { plugin_name } + " plugin, version #{old_version}, has been uninstalled") ui.bold(plugin_name + " plugin, version #{old_version}, has " \
'been uninstalled')
end end
exit 0 ui.exit 0
end end
private private
@ -172,8 +174,8 @@ module InspecPlugins
def install_from_gemfile(gem_file) def install_from_gemfile(gem_file)
unless File.exist? gem_file unless File.exist? gem_file
puts(red { "No such plugin gem file " } + gem_file + " - installation failed.") ui.red("No such plugin gem file #{gem_file} - installation failed.")
exit 1 ui.exit 1
end end
plugin_name_parts = File.basename(gem_file, ".gem").split("-") plugin_name_parts = File.basename(gem_file, ".gem").split("-")
@ -183,14 +185,15 @@ module InspecPlugins
installer.install(plugin_name, gem_file: gem_file) installer.install(plugin_name, gem_file: gem_file)
puts(bold { plugin_name } + " plugin, version #{version}, installed from local .gem file") ui.bold("#{plugin_name} plugin, version #{version}, installed from " \
exit 0 'local .gem file')
ui.exit 0
end end
def install_from_path(path) def install_from_path(path)
unless File.exist? path unless File.exist? path
puts(red { "No such source code path " } + path + " - installation failed.") ui.red('No such source code path ' + path + ' - installation failed.')
exit 1 ui.exit 1
end end
plugin_name = File.basename(path, ".rb") plugin_name = File.basename(path, ".rb")
@ -204,8 +207,10 @@ module InspecPlugins
# Already installed? # Already installed?
if registry.known_plugin?(plugin_name.to_sym) if registry.known_plugin?(plugin_name.to_sym)
puts(red { "Plugin already installed" } + " - #{plugin_name} - Use '#{EXEC_NAME} plugin list' to see previously installed plugin - installation failed.") ui.red("Plugin already installed - #{plugin_name} - Use '#{EXEC_NAME}" \
exit 2 "plugin list' to see previously installed plugin - " \
'installation failed.')
ui.exit 2
end end
# Can we figure out how to load it? # Can we figure out how to load it?
@ -217,8 +222,9 @@ module InspecPlugins
# OK, install it! # OK, install it!
installer.install(plugin_name, path: entry_point) installer.install(plugin_name, path: entry_point)
puts(bold { plugin_name } + " plugin installed via source path reference, resolved to entry point " + entry_point) ui.bold("#{plugin_name} plugin installed via source path reference, " \
exit 0 "resolved to entry point #{entry_point}")
ui.exit 0
end end
# Rationale for rubocop variances: It's a heuristics method, and will be full of # Rationale for rubocop variances: It's a heuristics method, and will be full of
@ -279,8 +285,10 @@ module InspecPlugins
# Well, if we got here, parts[2] matches an inspec/train prefix, but we have no idea about anything. # Well, if we got here, parts[2] matches an inspec/train prefix, but we have no idea about anything.
# Give up. # Give up.
puts(red { "Unrecognizable plugin structure" } + " - #{parts[2]} - When installing from a path, please provide the path of the entry point file - installation failed.") ui.red("Unrecognizable plugin structure - #{parts[2]} - When " \
exit 1 'installing from a path, please provide the path of the ' \
'entry point file - installation failed.')
ui.exit 1
end end
def install_from_path__probe_load(entry_point, plugin_name) def install_from_path__probe_load(entry_point, plugin_name)
@ -288,9 +296,11 @@ module InspecPlugins
begin begin
require entry_point require entry_point
rescue LoadError => ex rescue LoadError => ex
puts(red { "Plugin contains errors" } + " - #{plugin_name} - Encountered errors while trying to test load the plugin entry point, resolved to #{entry_point} - installation failed") ui.red("Plugin contains errors - #{plugin_name} - Encountered " \
puts ex.message 'errors while trying to test load the plugin entry point, ' \
exit 1 "resolved to #{entry_point} - installation failed")
ui.plain ex.message
ui.exit 1
end end
# OK, the wheels didn't fall off. But is it a plugin? # OK, the wheels didn't fall off. But is it a plugin?
@ -299,13 +309,19 @@ module InspecPlugins
# And the registry is keyed on Strings # And the registry is keyed on Strings
registry_key = plugin_name.to_s.sub(/^train-/, "") registry_key = plugin_name.to_s.sub(/^train-/, "")
unless Train::Plugins.registry.key?(registry_key) unless Train::Plugins.registry.key?(registry_key)
puts(red { "Does not appear to be a plugin" } + " - #{plugin_name} - After probe-loading the supposed plugin, it did not register itself to Train. Ensure something inherits from 'Train.plugin(1)' - installation failed.") ui.red("Does not appear to be a plugin - #{plugin_name} - After " \
exit 1 'probe-loading the supposed plugin, it did not register ' \
'itself to Train. Ensure something inherits from ' \
"'Train.plugin(1)' - installation failed.")
ui.exit 1
end end
else else
unless registry.known_plugin?(plugin_name.to_sym) unless registry.known_plugin?(plugin_name.to_sym)
puts(red { "Does not appear to be a plugin" } + " - #{plugin_name} - After probe-loading the supposed plugin, it did not register itself to InSpec. Ensure something inherits from 'Inspec.plugin(2)' - installation failed.") ui.red("Does not appear to be a plugin - #{plugin_name} - After " \
exit 1 'probe-loading the supposed plugin, it did not register ' \
'itself to InSpec. Ensure something inherits from ' \
"'Inspec.plugin(2)' - installation failed.")
ui.exit 1
end end
end end
end end
@ -325,8 +341,9 @@ module InspecPlugins
post_installed_versions = installer.list_installed_plugin_gems.select { |spec| spec.name == plugin_name }.map { |spec| spec.version.to_s } post_installed_versions = installer.list_installed_plugin_gems.select { |spec| spec.name == plugin_name }.map { |spec| spec.version.to_s }
new_version = (post_installed_versions - pre_installed_versions).first new_version = (post_installed_versions - pre_installed_versions).first
puts(bold { plugin_name } + " plugin, version #{new_version}, installed from rubygems.org") ui.bold("#{plugin_name} plugin, version #{new_version}, installed " \
exit 0 'from rubygems.org')
ui.exit 0
end end
def install_from_remote_gem_verson_preflight_check(plugin_name, requested_version, pre_installed_versions) def install_from_remote_gem_verson_preflight_check(plugin_name, requested_version, pre_installed_versions)
@ -348,38 +365,50 @@ module InspecPlugins
they_explicitly_asked_for_a_version = !options[:version].nil? they_explicitly_asked_for_a_version = !options[:version].nil?
what_we_would_install_is_already_installed = pre_installed_versions.include?(requested_version) what_we_would_install_is_already_installed = pre_installed_versions.include?(requested_version)
if what_we_would_install_is_already_installed && they_explicitly_asked_for_a_version if what_we_would_install_is_already_installed && they_explicitly_asked_for_a_version
puts(red { "Plugin already installed at requested version" } + " - plugin #{plugin_name} #{requested_version} - refusing to install.") ui.red('Plugin already installed at requested version - plugin ' \
"#{plugin_name} #{requested_version} - refusing to install.")
elsif what_we_would_install_is_already_installed && !they_explicitly_asked_for_a_version elsif what_we_would_install_is_already_installed && !they_explicitly_asked_for_a_version
puts(red { "Plugin already installed at latest version" } + " - plugin #{plugin_name} #{requested_version} - refusing to install.") ui.red('Plugin already installed at latest version - plugin ' \
"#{plugin_name} #{requested_version} - refusing to install.")
else else
# There are existing versions installed, but none of them are what was requested # There are existing versions installed, but none of them are what was requested
puts(red { "Update required" } + " - plugin #{plugin_name}, requested #{requested_version}, have #{pre_installed_versions.join(", ")}; use `inspec plugin update` - refusing to install.") ui.red("Update required - plugin #{plugin_name}, requested " \
"#{requested_version}, have " \
"#{pre_installed_versions.join(', ')}; use `inspec " \
'plugin update` - refusing to install.')
end end
exit 2 ui.exit 2
end end
# Rationale for RuboCop variance: This is a one-line method with heavy UX-focused error handling. # Rationale for RuboCop variance: This is a one-line method with heavy UX-focused error handling.
def install_attempt_install(plugin_name) # rubocop: disable Metrics/AbcSize def install_attempt_install(plugin_name) # rubocop: disable Metrics/AbcSize
installer.install(plugin_name, version: options[:version]) installer.install(plugin_name, version: options[:version])
rescue Inspec::Plugin::V2::PluginExcludedError => ex rescue Inspec::Plugin::V2::PluginExcludedError => ex
puts(red { "Plugin on Exclusion List" } + " - #{plugin_name} is listed as an incompatible gem - refusing to install.") ui.red("Plugin on Exclusion List - #{plugin_name} is listed as an " \
puts "Rationale: #{ex.details.rationale}" 'incompatible gem - refusing to install.')
puts "Exclusion list location: " + File.join(Inspec.src_root, "etc", "plugin_filters.json") ui.plain("Rationale: #{ex.details.rationale}")
puts "If you disagree with this determination, please accept our apologies for the misunderstanding, and open an issue at https://github.com/inspec/inspec/issues/new" ui.plain('Exclusion list location: ' +
exit 2 File.join(Inspec.src_root, 'etc', 'plugin_filters.json'))
ui.plain('If you disagree with this determination, please accept ' \
'our apologies for the misunderstanding, and open an issue ' \
'at https://github.com/inspec/inspec/issues/new')
ui.exit 2
rescue Inspec::Plugin::V2::InstallError rescue Inspec::Plugin::V2::InstallError
raise if Inspec::Log.level == :debug raise if Inspec::Log.level == :debug
results = installer.search(plugin_name, exact: true) results = installer.search(plugin_name, exact: true)
if results.empty? if results.empty?
puts(red { "No such plugin gem " } + plugin_name + " could be found on rubygems.org - installation failed.") ui.red("No such plugin gem #{plugin_name} could be found on " \
'rubygems.org - installation failed.')
elsif options[:version] && !results[plugin_name].include?(options[:version]) elsif options[:version] && !results[plugin_name].include?(options[:version])
puts(red { "No such version" } + " - " + plugin_name + " exists, but no such version #{options[:version]} found on rubygems.org - installation failed.") ui.red("No such version - #{plugin_name} exists, but no such " \
"version #{options[:version]} found on rubygems.org - " \
'installation failed.')
else else
puts(red { "Unknown error occured " } + " - installation failed.") ui.red('Unknown error occured - installation failed.')
end end
exit 1 ui.exit 1
end end
#==================================================================# #==================================================================#
@ -390,11 +419,13 @@ module InspecPlugins
# Check for path install # Check for path install
status = Inspec::Plugin::V2::Registry.instance[plugin_name.to_sym] status = Inspec::Plugin::V2::Registry.instance[plugin_name.to_sym]
if !status if !status
puts(red { "No such plugin installed: " } + "#{plugin_name} - update failed") ui.red("No such plugin installed: #{plugin_name} - update failed")
exit 1 ui.exit 1
elsif status.installation_type == :path elsif status.installation_type == :path
puts(red { "Cannot update path-based install: " } + "#{plugin_name} is installed via path reference; use `inspec plugin uninstall` to remove - refusing to update") ui.red("Cannot update path-based install: #{plugin_name} is " \
exit 2 'installed via path reference; use `inspec plugin ' \
'uninstall` to remove - refusing to update')
ui.exit 2
end end
end end
@ -403,8 +434,9 @@ module InspecPlugins
latest_version = latest_version[plugin_name]&.last latest_version = latest_version[plugin_name]&.last
if pre_update_versions.include?(latest_version) if pre_update_versions.include?(latest_version)
puts(red { "Already installed at latest version: " } + "#{plugin_name} is at #{latest_version}, which the latest - refusing to update") ui.red("Already installed at latest version: #{plugin_name} is at " \
exit 2 "#{latest_version}, which the latest - refusing to update")
ui.exit 2
end end
end end
@ -421,8 +453,10 @@ module InspecPlugins
def check_plugin_name(plugin_name, action) def check_plugin_name(plugin_name, action)
unless plugin_name =~ /^(inspec|train)-/ unless plugin_name =~ /^(inspec|train)-/
puts(red { "Invalid plugin name" } + " - #{plugin_name} - All inspec plugins must begin with either 'inspec-' or 'train-' - #{action} failed.") ui.red("Invalid plugin name - #{plugin_name} - All inspec " \
exit 1 "plugins must begin with either 'inspec-' or 'train-' " \
"- #{action} failed.")
ui.exit 1
end end
end end