summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBryan McLellan <btm@loftninjas.org>2020-03-23 18:04:33 -0400
committerBryan McLellan <btm@loftninjas.org>2020-03-25 14:57:38 -0400
commit45c48f8ffb857d13b7a3f1ae6c522d3beffbbe5d (patch)
tree555ec008e8db5d9d4db588b5e524e4bf4a15c4c4
parentb6682242811500f11ccb085305e9d9e5164909e0 (diff)
downloadchef-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.rb8
-rw-r--r--lib/chef/knife/yaml_convert.rb64
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