require "crinja" def sanitize_path(path) path.gsub /\/\/+/, "/" end module Configure def self.parse_options(unparsed : Array(String)) options = ARGV.map(&.split '=') hash = Hash(String, String | Array(String) | Crinja::Callable::Instance | Hash(String, String)).new options.each do |entry| key, value = entry old_value = hash[key]? case old_value when nil hash[key] = value when String hash[key] = [old_value, value] when Array(String) old_value << value end end hash end end class Configure::Exception < Exception end class Configure::Context getter root : String def initialize(@root) end def generate(template, target : String, options : Hash(String, String | Array(String) | Crinja::Callable::Instance | Hash(String, String))) target_file = File.open target, "w" # FIXME: Alter default sources at build-time. # FIXME: We’ll want a way to alter those context-wide. sources = [ "/etc/templates", "/usr/share/templates" ] sources = sources .map(&.+("/#{template}.j2")) .map { |x| sanitize_path x } source = sources.find do |source| if File.exists? source puts "Generating '#{target}' from '#{source}'" next true end end unless source raise Exception.new "Could not find template to generate file ('#{target}')." end options["id"] = ENV["SERVICE_ID"]? || "" options["environment"] = ENV["ENVIRONMENT"]? || "" options["port"] = Crinja.function do service = (arguments.varargs[0]? || "").to_s.gsub /\//, ':' `get-port #{service}` end providers = {} of String => String ENV["SERVICE_TOKENS"].try &.split(':').each do |token| providers[token] = ENV["#{token.upcase}_PROVIDER"]? || "" end options["providers"] = providers template = File.read source target_file << Crinja.render(template, options) target_file.close end end template = ARGV[0]? target = ARGV[1]? if target.nil? puts "usage: configure [option1=value1 [option2=value2 […]]]" exit 1 end ARGV.shift ARGV.shift options = Configure.parse_options ARGV begin Configure::Context.new("/").generate(template, target, options) rescue e : Configure::Exception STDERR.puts "Fatal error: #{e.message}" exit 1 end