require 'rake' require_relative './html_file' module Nesta module Static class Site def initialize(build_dir, domain, logger = nil) @build_dir = build_dir @domain = domain @logger = logger @app = Nesta::App.new set_app_root end def render_pages Nesta::Page.find_all.each do |page| target = HtmlFile.new(@build_dir, page).filename source = page.filename task = Rake::FileTask.define_task(target => source) do save_markup(target, render(page.abspath, target, source)) end task.invoke end end def render_not_found path_info = '/404' source = 'no-such-file.md' target = File.join(@build_dir, '404.html') markup = render(path_info, target, source, expected_code: 404) save_markup(target, markup) end def render_atom_feed filename = 'articles.xml' path_info = "/#{filename}" description = 'Atom feed' target = File.join(@build_dir, filename) markup = render(path_info, target, description) save_markup(target, markup) end def render_sitemap filename = File.join(@build_dir, 'sitemap.xml') save_markup(filename, render('/sitemap.xml', filename, 'site')) end def render_templated_assets Nesta::Config.build.fetch('templated_assets', []).each do |path| filename = File.join(@build_dir, path) save_markup(filename, render(path, filename, path)) end end private def log(message) @logger.call(message) if @logger end def set_app_root root = ::File.expand_path('.') ['Gemfile', File.join('config', 'config.yml')].each do |expected| if ! File.exist?(File.join(root, expected)) message = "is this a Nesta site? (expected './#{expected}')" raise RuntimeError, message end end Nesta::App.root = root end def rack_environment(abspath) { 'REQUEST_METHOD' => 'GET', 'SCRIPT_NAME' => '', 'PATH_INFO' => abspath, 'QUERY_STRING' => '', 'SERVER_NAME' => @domain, 'SERVER_PROTOCOL' => 'https', 'rack.url_scheme' => 'https', 'rack.input' => StringIO.new, 'rack.errors' => STDERR } end def render(abspath, filename, description, expected_code: 200) http_code, headers, body = @app.call(rack_environment(abspath)) if http_code != expected_code raise RuntimeError, "Can't render #{filename} from #{description}" end body.join end def save_markup(filename, content) FileUtils.mkdir_p(File.dirname(filename)) if (! File.exist?(filename)) || (open(filename, 'r').read != content) open(filename, 'w') { |output| output.write(content) } log("Rendered #{filename}") end end end end end