inspec/lib/bundles/inspec-init/renderer.rb
Clinton Wolfe 02cb93ec23 Refactor 'inspec init profile' into a reusable component. (#3214)
* Refactor 'inspec init profile' into a reusable component.

base_cli.rb had several methods used internally, these are exposed so
lib/bundles/inspec-init/profile.rb can act as a library for anything
that needs to create new Inspec profiles programatically

* Move output methods to be public instance methods; and make Init::Profile into a working renderer.  Functional tests pass but could use some refactoring to be easier to use.
* Refactor, renaming vars to be clearer
* Move puts and exit calls into basecli
* Add comment about simplified ERB rendering in ruby 2.5.0+

Signed-off-by: Clinton Wolfe <clintoncwolfe@gmail.com>
2018-07-17 11:42:36 -04:00

79 lines
3 KiB
Ruby

require 'fileutils'
require 'erb'
module Init
class Renderer
# Creates a renderer able to render the given template type
# 1. iterate over all files
# 2. read content in erb
# 3. write to full_destination_root_path
attr_reader :overwrite_mode, :ui
def initialize(cli_ui, cli_options = {})
@ui = cli_ui
@overwrite_mode = cli_options['overwrite']
end
# rubocop: disable Metrics/AbcSize
def render_with_values(template_type, template_values = {})
# look for template directory
base_dir = File.join(File.dirname(__FILE__), 'templates', template_type)
# prepare glob for all subdirectories and files
template_glob = File.join(base_dir, '**', '{*,.*}')
# Use the name attribute to define the path to the profile.
profile_path = template_values[:name]
# Use slashes (\, /) to split up the name into an Array then use the last entry
# to reset the name of the profile.
template_values[:name] = template_values[:name].split(%r{\\|\/}).last
# Generate the full full_destination_root_path path on disk
full_destination_root_path = Pathname.new(Dir.pwd).join(profile_path)
ui.plain_text "Create new #{template_type} at #{ui.mark_text(full_destination_root_path)}"
# check that the directory does not exist
if File.exist?(full_destination_root_path) && !overwrite_mode
ui.plain_text "#{ui.mark_text(full_destination_root_path)} exists already, use --overwrite"
ui.exit(1)
end
# ensure that full_destination_root_path directory is available
FileUtils.mkdir_p(full_destination_root_path)
# iterate over files and write to full_destination_root_path
Dir.glob(template_glob) do |file|
relative_destination_item_path = Pathname.new(file).relative_path_from(Pathname.new(base_dir))
full_destination_item_path = Pathname.new(full_destination_root_path).join(relative_destination_item_path)
if File.directory?(file)
ui.li "Create directory #{ui.mark_text(relative_destination_item_path)}"
FileUtils.mkdir_p(full_destination_item_path)
elsif File.file?(file)
ui.li "Create file #{ui.mark_text(relative_destination_item_path)}"
# read & render content
content = render(File.read(file), template_values)
# write file content
File.write(full_destination_item_path, content)
else
ui.plain_text "Ignore #{file}, because its not an file or directoy"
end
end
end
# rubocop: enable Metrics/AbcSize
# This is a render helper to bind hash values to a ERB template
# ERB provides result_with_hash in ruby 2.5.0+, which does exactly this
def render(template_content, hash)
# create a new binding class
cls = Class.new do
hash.each do |key, value|
define_method key.to_sym do
value
end
end
# expose binding
define_method :bind do
binding
end
end
ERB.new(template_content).result(cls.new.bind)
end
end
end