class CfnDsl::RakeTask
Rake
TaskLib rubocop:disable Metrics/ClassLength
Attributes
@deprecated pre 1.x rake task generator
rubocop:enable Metrics/ParameterLists
rubocop:enable Metrics/ParameterLists
Public Class Methods
Creates Cloudformation generation tasks
@example directory ‘tmp’
namespace :samples do
CfnDsl::RakeTask.new do |t| t.specification(file: 'tmp/cloudformation_resources.json') desc 'Generate CloudFormation Json' t.json(name: :json, files: ["sample/*.rb"], pathmap: 'tmp/%f.json', pretty: true, extras: FileList.new('sample/*.yaml') ) t.yaml(name: :yaml, files: 'sample/t1.rb', pathmap: 'tmp/%f.yaml', extras: '%X.yaml') end
end
# File lib/cfndsl/rake_task.rb, line 38 def initialize(name = nil) @tasks = [] @spec_task = nil last_desc = ::Rake.application.last_description desc nil yield self if block_given? if cfndsl_opts desc last_desc if last_desc task(name || :generate) { |_t, _args| cfndsl_opts[:files].each { |opts| generate(opts) } } else define_base_tasks(name || :generate, last_desc) end end
Public Instance Methods
Convert DSL sources to json
Generates file tasks for each of the matching file in the files FileList. Each task is dependant on the source,
the specification file, and the required extras files such that if the timestamp of any of these is earlier the target file will be regenerated.
Finally task <name> is generated that depends on all the generated targets.
@param [Symbol|String] name the name of a task that is dependant on all the files being converted @param [Rake::FileList | Array
<String> ] files source file list @param [String] pathmap expression to map source files to target files @param [Rake::Filelist|Array<String>] extras a list of files to load as external parameters
Note String values containing '%' are treated as a pathmap from the source The resulting generated FileList is used as a dependency for generation so any entries not containing '*' MUST exist.
@param [Boolean] pretty use JSON.pretty_generate @param [Hash] json_opts, other options to pass to JSON generator rubocop:disable Metrics/ParameterLists
# File lib/cfndsl/rake_task.rb, line 113 def json(name:, files:, pathmap:, pretty: false, extras: [], **json_opts) json_method = pretty ? :pretty_generate : :generate generate_model_tasks(name: name, files: files, pathmap: pathmap, extras: extras) do |model, f| f.write(JSON.send(json_method, model, **json_opts)) end self end
Use a custom specification file
This specification file will be used for any generation tasks
Creates a file task to download from upstream source, with an optional additional named task that depends on it.
The minimum required version can be specified with the version parameter, which can be overriden by invoking rake with the ‘cfn_spec_task’ argument
@example CfnDsl::RakeTask.new()
do |t|
t.specification(name: :update_spec, file: 'tmp/cloudformation_resources.json', version: '6.3'0)
end
# rake update_spec # >> Will ensure ‘tmp/cloudformation_resources.json’ exists and is at least 6.3.0 # rake update_spec # >> Will always try to download the latest available spec
@param [String] file the number of the specification file to use @param [Symbol] name A pretty name for the task to update this file from upstream source @param [String] version The minimum version required, and the default version used when downloading
if not specified and not overriden by 'cfn_spec_version' rake task argument then any existing file is considered sufficient, and 'latest' is the version used for downloading
@todo Add capability to provide a user spec/patches dir
# File lib/cfndsl/rake_task.rb, line 82 def specification(file:, name: nil, version: nil) if name desc 'Update Resource Specification' unless ::Rake.application.last_description task name, [:cfn_spec_version] => file end @spec_task = file(file, :cfn_spec_version) do |t, args| update_specification(t.name, args.with_defaults(cfn_spec_version: version)[:cfn_spec_version]) end @spec_task.define_singleton_method(:needed?) { true } # We always need to check self end
Convert DSL sources to yaml
Generates file tasks for each of the matching file in the files FileList. Each task is dependant on the source,
the specification file, and the required extras files such that if the timestamp of any of these is earlier the target file will be regenerated.
Finally task <name> is generated that depends on all the generated targets. @param [Symbol|String] name the name of a task that is dependant on all the files being converted @param [Rake::FileList | Array
<String> ] files source file list @param [String] pathmap expression to map source files to target files @param [Rake::Filelist|Array<String>] extras a list of files to load as external parameters
Note String values containing '%' are treated as a pathmap from the source The resulting generated FileList is used as a dependency for generation so any entries not containing '*' MUST exist.
@param [Hash] yaml_opts, other options to pass to YAML generator
# File lib/cfndsl/rake_task.rb, line 136 def yaml(name:, files:, pathmap:, extras: [], **yaml_opts) generate_model_tasks(name: name, files: files, pathmap: pathmap, extras: extras) do |model, f| simple_model = JSON.parse(model.to_json) # convert model to a simple ruby object to avoid yaml tags YAML.dump(simple_model, f, **yaml_opts) end self end
Private Instance Methods
# File lib/cfndsl/rake_task.rb, line 204 def build_extras_filelist(source, extras) extras = [extras] unless extras.respond_to?(:each) extras.each_with_object(Rake::FileList.new) do |extra, result| case extra when Rake::FileList result.add(extra) when Array result.add(*extra) when /%/ result.add(source.pathmap(extra)) else result.add(extra) end end end
# File lib/cfndsl/rake_task.rb, line 149 def define_base_tasks(name, description) return if tasks.empty? desc description || 'Generate Cloudformation' task(name || :generate, [:cfn_spec_version] => tasks) load_spec = task load_spec_types: [spec_task].compact do |_t, args| CfnDsl.specification_file = spec_task&.name || CfnDsl::LOCAL_SPEC_FILE require_relative 'cloudformation' CfnDsl::CloudFormationTemplate.check_types(file: spec_task&.name, version: @updated_version || args[:cfn_spec_version]) verbose&.puts "Using Cloudformation types generated from #{CfnDsl::CloudFormationTemplate.template_types.values_at('File', 'Version').join(' ')}" end load_spec.define_singleton_method(:timestamp) { Rake::EARLY } # Prevent this task from causing generation tasks. tasks.unshift(load_spec) end
# File lib/cfndsl/rake_task.rb, line 252 def extra cfndsl_opts.fetch(:extras, []) end
# File lib/cfndsl/rake_task.rb, line 256 def file_output(path, &block) File.open(File.expand_path(path), 'w', &block) end
# File lib/cfndsl/rake_task.rb, line 224 def generate(opts) log(opts) outputter(opts) do |output| if cfndsl_opts[:outformat] == 'yaml' data = model(opts[:filename]).to_json output.puts JSON.parse(data).to_yaml else output.puts cfndsl_opts[:pretty] ? JSON.pretty_generate(model(opts[:filename])) : model(opts[:filename]).to_json end end end
# File lib/cfndsl/rake_task.rb, line 185 def generate_model_tasks(name:, files:, pathmap:, extras:) files = Rake::FileList.new(*files) unless files.is_a?(Rake::FileList) tasks << task(name, [:cfn_spec_version] => files.pathmap(pathmap)) files.each do |source| matched_extras = build_extras_filelist(source, extras) file source.pathmap(pathmap) => [source, :load_spec_types, *matched_extras] do |task| eval_extras = matched_extras.map { |e| [:yaml, e] } # eval treats yaml and json same puts "Generating Cloudformation for #{source} to #{task.name}" model = CfnDsl.eval_file_with_extras(source, eval_extras, verbose) File.open(task.name, 'w') { |f| yield model, f } end end self end
# File lib/cfndsl/rake_task.rb, line 236 def log(opts) type = opts[:output].nil? ? 'STDOUT' : opts[:output] verbose&.puts("Writing to #{type}") end
# File lib/cfndsl/rake_task.rb, line 245 def model(filename) raise "#{filename} doesn't exist" unless File.exist?(filename) verbose&.puts("using extras #{extra}") CfnDsl.eval_file_with_extras(filename, extra, verbose) end
# File lib/cfndsl/rake_task.rb, line 241 def outputter(opts, &block) opts[:output].nil? ? yield($stdout) : file_output(opts[:output], &block) end
# File lib/cfndsl/rake_task.rb, line 179 def safe_update_embedded_spec return if File.fnmatch?(File.join(File.dirname(File.expand_path(Rake.application.rakefile)), '*'), CfnDsl::LOCAL_SPEC_FILE) raise Error, 'Refusing to update CloudFormation spec embedded in cfndsl gem' end
# File lib/cfndsl/rake_task.rb, line 166 def update_specification(file, minimum_version) if CfnDsl::Specification.update_required?(version: minimum_version, file: file) safe_update_embedded_spec if file == CfnDsl::LOCAL_SPEC_FILE result = CfnDsl.update_specification_file(file: file, version: minimum_version) puts "Specification #{result[:file]} updated to version #{result[:version]}" @updated_version = result[:version] elsif minimum_version verbose&.puts "Specification #{file} is already >= #{minimum_version}" end end
# File lib/cfndsl/rake_task.rb, line 220 def verbose (Rake.verbose? || cfndsl_opts&.fetch(:verbose, false)) && $stderr end