diff options
author | Bryan McLellan <btm@loftninjas.org> | 2020-03-23 18:04:33 -0400 |
---|---|---|
committer | Bryan McLellan <btm@loftninjas.org> | 2020-03-25 14:57:38 -0400 |
commit | 45c48f8ffb857d13b7a3f1ae6c522d3beffbbe5d (patch) | |
tree | 555ec008e8db5d9d4db588b5e524e4bf4a15c4c4 | |
parent | b6682242811500f11ccb085305e9d9e5164909e0 (diff) | |
download | chef-btm/knife-yaml.tar.gz |
Output to a file instead of stdoutbtm/knife-yaml
Refactor and direct output to a file with some magic to make up a good
output filename.
Signed-off-by: Bryan McLellan <btm@loftninjas.org>
-rw-r--r-- | lib/chef/knife/core/ui.rb | 8 | ||||
-rw-r--r-- | lib/chef/knife/yaml_convert.rb | 64 |
2 files changed, 52 insertions, 20 deletions
diff --git a/lib/chef/knife/core/ui.rb b/lib/chef/knife/core/ui.rb index 03b11a1b4d..893daa04e9 100644 --- a/lib/chef/knife/core/ui.rb +++ b/lib/chef/knife/core/ui.rb @@ -140,6 +140,14 @@ class Chef log("#{color("FATAL:", :red, :bold)} #{message}") end + # Print a message describing a fatal error and exit 1 + # + # @param message [String] the text string + def fatal!(message) + fatal(message) + exit 1 + end + def color(string, *colors) if color? pastel.decorate(string, *colors) diff --git a/lib/chef/knife/yaml_convert.rb b/lib/chef/knife/yaml_convert.rb index 5cdc340d22..a5b75e5691 100644 --- a/lib/chef/knife/yaml_convert.rb +++ b/lib/chef/knife/yaml_convert.rb @@ -20,48 +20,72 @@ require "yaml" require_relative "../knife" class Chef::Knife::YamlConvert < Chef::Knife - banner "knife yaml convert YAML_FILENAME" + banner "knife yaml convert YAML_FILENAME [RUBY_FILENAME]" def run if name_args.empty? - ui.error("Please specify the file name of a YAML recipe to convert to Ruby") - exit 1 - elsif name_args.size >= 2 - ui.error("Only one recipe may converted at a time") - exit 1 + ui.fatal!("Please specify the file name of a YAML recipe to convert to Ruby") + elsif name_args.size >= 3 + ui.fatal!("knife yaml convert YAML_FILENAME [RUBY_FILENAME]") end - filename = @name_args[0] - yaml_contents = IO.read(filename) + yaml_file = @name_args[0] + unless ::File.exist?(yaml_file) && ::File.readable?(yaml_file) + ui.fatal("Input YAML file '#{yaml_file}' does not exist or is unreadable") + end + + ruby_file = if @name_args[1] + @name_args[1] # use the specified output filename if provided + else + if ::File.extname(yaml_file) == ".yml" || ::File.extname(yaml_file) == ".yaml" + yaml_file.gsub(/\.(yml|yaml)$/, ".rb") + else + yaml_file + ".rb" # fall back to putting .rb on the end of whatever the yaml file was named + end + end + + if ::File.exist?(ruby_file) + ui.fatal!("Output Ruby file '#{ruby_file}' already exists") + end + + yaml_contents = IO.read(yaml_file) + # YAML can contain multiple documents (--- is the separator), let's not support that. if ::YAML.load_stream(yaml_contents).length > 1 - raise ArgumentError, "YAML recipe '#{filename}' contains multiple documents, only one is supported" + ui.fatal!("YAML recipe '#{yaml_file}' contains multiple documents, only one is supported") end # Unfortunately, per the YAML spec, comments are stripped when we load, so we lose them on conversion yaml_hash = ::YAML.safe_load(yaml_contents) unless yaml_hash.is_a?(Hash) && yaml_hash.key?("resources") - raise ArgumentError, "YAML recipe '#{source_file}' must contain a top-level 'resources' hash (YAML sequence), i.e. 'resources:'" + ui.fatal!("YAML recipe '#{source_file}' must contain a top-level 'resources' hash (YAML sequence), i.e. 'resources:'") end + ui.warn("No resources found in '#{yaml_file}'") if yaml_hash["resources"].size == 0 + + ::File.open(ruby_file, "w") do |file| + file.write(resource_hash_to_string(yaml_hash["resources"], yaml_file)) + end + ui.info("Converted '#{yaml_file}' to '#{ruby_file}'") + end + + # Converts a Hash of resources to a Ruby recipe + # returns a string ready to be written to a file or stdout + def resource_hash_to_string(resource_hash, filename) ruby_contents = [] - ruby_contents << "# Autoconverted recipe from #{filename}" - ruby_contents << "" + ruby_contents << "# Autoconverted recipe from #{filename}\n" - yaml_hash["resources"].each do |r| + resource_hash.each do |r| type = r.delete("type") name = r.delete("name") ruby_contents << "#{type} \"#{name}\" do" - r.each do |p| - ruby_contents << " #{p.shift} \"#{p.shift}\"" + r.each do |k, v| + ruby_contents << " #{k} \"#{v}\"" end - ruby_contents << "end" - ruby_contents << "" + ruby_contents << "end\n" end - ruby_contents.each do |l| - puts l - end + ruby_contents.join("\n") end end |