inspec/lib/inspec/env_printer.rb
Clinton Wolfe cdfb325ca3 Apply chefstyle -a, and manually remove duplicate requires
Signed-off-by: Clinton Wolfe <clintoncwolfe@gmail.com>
2020-12-21 13:25:04 -05:00

156 lines
3.9 KiB
Ruby

require "inspec/shell_detector"
require "erb" unless defined?(Erb)
require "shellwords" unless defined?(Shellwords)
module Inspec
class EnvPrinter
attr_reader :shell
EVAL_COMMANDS = {
"bash" => 'eval \"$(inspec env bash)\"',
"fish" => "inspec env fish > ~/.config/fish/completions/inspec.fish",
"zsh" => 'eval \"$(inspec env zsh)\"',
}.freeze
def initialize(command_class, shell = nil)
if !shell
@detected = true
@shell = Inspec::ShellDetector.new.shell
else
@shell = shell
end
@command_class = command_class
end
def print_and_exit!
exit_no_shell unless have_shell?
exit_no_completion unless have_shell_completion?
print_completion_for_shell
print_detection_warning($stdout) if @detected
print_usage_guidance
exit 0
end
private
def print_completion_for_shell
erb = ERB.new(File.read(completion_template_path), nil, "-")
puts erb.result(TemplateContext.new(@command_class).get_bindings)
end
def have_shell?
!(@shell.nil? || @shell.empty?)
end
def have_shell_completion?
File.exist?(completion_template_path)
end
def completion_dir
File.join(File.dirname(__FILE__), "completions")
end
def completion_template_path
File.join(completion_dir, "#{@shell}.sh.erb")
end
def shells_with_completions
Dir.glob("#{completion_dir}/*.sh.erb").map { |f| File.basename(f, ".sh.erb") }
end
def print_usage_guidance
puts <<~EOF
# To use this, eval it in your shell
#
# #{EVAL_COMMANDS[shell]}
#
#
EOF
end
def print_detection_warning(device)
device.puts <<~EOF
#
# The shell #{@shell} was auto-detected. If this is incorrect, please
# specify a shell explicitly by running:
#
# inspec env SHELLNAME
#
# Currently supported shells are: #{shells_with_completions.join(", ")}
#
EOF
end
def exit_no_completion
$stderr.puts "# No completion script for #{@shell}!"
print_detection_warning($stderr) if @detected
exit 1
end
def exit_no_shell
if @detected
$stderr.puts "# Unable to automatically detect shell and no shell was provided."
end
$stderr.puts <<~EOF
#
# Please provide the name of your shell via the command line:
#
# inspec env SHELLNAME
#
# Currently supported shells are: #{shells_with_completions.join(", ")}
EOF
exit 1
end
class TemplateContext
def initialize(command_class)
@command_class = command_class
end
def get_bindings # rubocop:disable Naming/AccessorMethodName
binding
end
#
# The following functions all assume that @command_class
# is something that provides a Thor-like API
#
def top_level_commands
commands_for_thor_class(@command_class)
end
def top_level_commands_with_descriptions
descript_lines_for_class(@command_class)
end
def subcommands_with_commands
ret = {}
@command_class.subcommand_classes.each do |k, v|
ret[k] = commands_for_thor_class(v)
end
ret
end
def subcommands_with_commands_and_descriptions
ret = {}
@command_class.subcommand_classes.each do |k, v|
ret[k] = descript_lines_for_class(v)
end
ret
end
def commands_for_thor_class(thor_class)
thor_class.all_commands.values.map { |c| c.usage.split.first }
end
def descript_lines_for_class(thor_class)
thor_class.all_commands.values.map { |c| descript_line_for_command(c) }
end
def descript_line_for_command(c)
"#{c.usage.split.first}:#{Shellwords.escape(c.description)}"
end
end
end
end