288 lines
6.9 KiB
Ruby
288 lines
6.9 KiB
Ruby
require 'yaml'
|
|
require 'redcarpet'
|
|
require 'erb'
|
|
require 'pipeline.rb'
|
|
require 'date'
|
|
require 'image'
|
|
|
|
class Array
|
|
def where
|
|
clone.delete_if { |i| not yield i }
|
|
end
|
|
end
|
|
|
|
module GemSmith
|
|
|
|
def reset_gemsmith()
|
|
$gemsmith = {
|
|
active: nil,
|
|
in_path: nil,
|
|
out_path: nil,
|
|
static: [],
|
|
collections: {},
|
|
assets: {}
|
|
}
|
|
end
|
|
|
|
def load_site(in_path, out_path)
|
|
if File.symlink? in_path then
|
|
$stderr.puts "Warning: Skipping symlink #{f}"
|
|
[]
|
|
elsif File.directory? in_path then
|
|
full_out_dir = File.join($gemsmith[:out_path], out_path)
|
|
directory "#{full_out_dir}" => [File.dirname("#{full_out_dir}")]
|
|
Dir["#{in_path}/*"].map do |f|
|
|
out_f = File.join(out_path, File.basename(f))
|
|
load_site(f, out_f)
|
|
end.flatten(1)
|
|
else
|
|
[{
|
|
modified: File.mtime(in_path),
|
|
in_path: in_path,
|
|
dependencies: [in_path, File.dirname(File.join($gemsmith[:out_path], out_path))],
|
|
out_path: out_path,
|
|
rel_dir: File.dirname(out_path),
|
|
stream: Pipeline.new(in_path),
|
|
"title" => File.basename(out_path, ".*").gsub(/[_-]/, " ").capitalize
|
|
}]
|
|
end
|
|
end
|
|
|
|
def for_files(pattern)
|
|
tmp = $gemsmith[:active]
|
|
$gemsmith[:active] =
|
|
$gemsmith[:active].where {|f| pattern =~ f[:out_path] }
|
|
yield
|
|
$gemsmith[:active] = tmp
|
|
end
|
|
|
|
def exclude_files(pattern)
|
|
tmp = $gemsmith[:active]
|
|
$gemsmith[:active] =
|
|
$gemsmith[:active].where {|f| not pattern =~ f[:out_path] }
|
|
yield
|
|
$gemsmith[:active] = tmp
|
|
end
|
|
|
|
def site(site_name, params = {})
|
|
|
|
reset_gemsmith()
|
|
|
|
in_path = params.fetch(:src, "src")
|
|
out_path = params.fetch(:out, File.join("build", site_name.to_s))
|
|
|
|
$gemsmith[:in_path] = in_path
|
|
$gemsmith[:out_path] = out_path
|
|
$gemsmith[:active] = load_site(in_path, "")
|
|
|
|
directory out_path
|
|
|
|
task site_name => [ in_path, out_path ]
|
|
|
|
yield
|
|
|
|
$gemsmith[:active].each { |f|
|
|
file File.join(out_path, f[:out_path]) => f[:dependencies] do
|
|
error = nil;
|
|
File.open(File.join(out_path, f[:out_path]), "w+") { |out|
|
|
begin
|
|
f[:stream].pipe_to(out)
|
|
rescue => e
|
|
error = e
|
|
end
|
|
}
|
|
unless error.nil?
|
|
File.unlink(File.join(out_path, f[:out_path]))
|
|
raise error
|
|
end
|
|
end
|
|
task site_name => File.join(out_path, f[:out_path])
|
|
}
|
|
|
|
unless $gemsmith[:static].empty?
|
|
task site_name => "#{site_name}_static"
|
|
static_assets = $gemsmith[:static]
|
|
target_dirs = static_assets.map { |a,b| File.join(out_path, b) }
|
|
target_dirs.each { |d| directory d }
|
|
target_dirs.push out_path
|
|
task "#{site_name}_static" => target_dirs do
|
|
static_assets.each { |in_path, out_in_dir|
|
|
system("rsync -a #{in_path}/* #{File.join(out_path, out_in_dir)}")
|
|
}
|
|
end
|
|
end
|
|
end
|
|
|
|
def apply
|
|
raise "Applying effects to pages outside of a site block" if $gemsmith[:active].nil?
|
|
$gemsmith[:active].each { |f| yield f }
|
|
end
|
|
|
|
def extract_date_from_filename
|
|
apply { |f|
|
|
d = /(\d\d\d\d)-(\d\d?)-(\d\d?)/.match File.basename(f[:in_path])
|
|
raise "Expecting date in the name of '#{File.basename f[:in_path]}'" if d.nil?
|
|
f[:date] = Time.new(d[1].to_i, d[2].to_i, d[3].to_i)
|
|
}
|
|
end
|
|
|
|
def create_collection(name)
|
|
curr = nil
|
|
collection = []
|
|
$gemsmith[:active].each { |f|
|
|
f["#{name}_prev".to_sym] = curr
|
|
f["#{name}_next".to_sym] = nil
|
|
curr["#{name}_next".to_sym] = f unless curr.nil?
|
|
curr = f
|
|
collection.push(f)
|
|
}
|
|
$gemsmith[:collections][name] = collection
|
|
end
|
|
|
|
def get_collection(name)
|
|
$gemsmith[:collections][name]
|
|
end
|
|
|
|
def extract_headers
|
|
apply { |f|
|
|
yaml = ["---\n"]
|
|
pos = nil
|
|
f[:stream].consume { |fp|
|
|
if /^---$/ =~ fp.readline then
|
|
l = fp.readline
|
|
until /^---$/ =~ l do
|
|
yaml.push l
|
|
l = fp.readline
|
|
end
|
|
pos = fp.pos
|
|
end
|
|
}
|
|
|
|
unless pos.nil?
|
|
begin
|
|
fields = YAML.load(yaml.join)
|
|
if fields.has_key? "dependencies"
|
|
fields[:dependencies] = f.fetch(:dependencies, []) + fields["dependencies"]
|
|
end
|
|
f.merge!(fields)
|
|
rescue => e
|
|
raise "Error parsing YAML ('#{f[:in_path]}'):\n#{e}\n#{yaml.join}---"
|
|
end
|
|
f[:stream].skip_to(pos)
|
|
end
|
|
}
|
|
end
|
|
|
|
def render_markdown(renderer = Redcarpet::Render::HTML.new(), options = {})
|
|
markdown = Redcarpet::Markdown.new(renderer, options)
|
|
apply { |f|
|
|
f[:out_path] = File.join(File.dirname(f[:out_path]), "#{File.basename(f[:out_path], ".*")}.html")
|
|
f[:stream].transform_all { |body|
|
|
markdown.render(body)
|
|
}
|
|
}
|
|
end
|
|
|
|
def render_erb
|
|
apply { |f|
|
|
f[:out_path] = File.join(File.dirname(f[:out_path]), "#{File.basename(f[:out_path], ".*")}.html")
|
|
f[:stream].transform_all { |body|
|
|
b = binding()
|
|
f.each { |k,v| b.local_variable_set(k, v) }
|
|
$gemsmith[:now_rendering] = File.join(f[:rel_dir], File.basename(f[:out_path]))
|
|
ERB.new(body).result(b)
|
|
}
|
|
}
|
|
end
|
|
|
|
def apply_template(default_template)
|
|
erb = Hash.new { |h,k|
|
|
h[k] = ERB.new(File.open(k) { |fp| fp.read })
|
|
}
|
|
|
|
apply { |f|
|
|
template = f.fetch(:template){ f.fetch("template", default_template) }
|
|
if template != "None"
|
|
f[:dependencies].push(template)
|
|
f[:stream].transform_all { |body|
|
|
b = binding()
|
|
f.each { |k,v| b.local_variable_set(k, v) }
|
|
$gemsmith[:now_rendering] = File.join(f[:rel_dir], File.basename(f[:out_path]))
|
|
erb[template].result(b)
|
|
}
|
|
end
|
|
}
|
|
end
|
|
|
|
def add_dependency(dep)
|
|
$gemsmith[:active].each { |f| f[:dependencies].push dep }
|
|
end
|
|
|
|
def add_assets(assets, params = {})
|
|
in_dir = params.fetch(:source, "assets")
|
|
out_dir = params.fetch(:dir, "assets")
|
|
assets.each { |a|
|
|
$gemsmith[:active] += load_site(File.join(in_dir, a), File.join(out_dir, a))
|
|
$gemsmith[:assets][a] = File.join(out_dir, a)
|
|
}
|
|
end
|
|
|
|
def add_file(in_path, out_path)
|
|
$gemsmith[:active].push({
|
|
dependencies: [in_path, File.join($gemsmith[:out_path], File.dirname(out_path))],
|
|
out_path: out_path,
|
|
in_path: in_path,
|
|
rel_dir: File.dirname(out_path),
|
|
stream: Pipeline.new(in_path)
|
|
})
|
|
end
|
|
|
|
def add_dir(in_path, out_path)
|
|
if File.directory? in_path
|
|
directory File.join($gemsmith[:out_path], out_path) =>
|
|
File.join($gemsmith[:out_path], File.dirname(out_path))
|
|
Dir["#{in_path}/*"].each { |f|
|
|
add_dir(f, File.join(out_path, File.basename(f)))
|
|
}
|
|
else
|
|
add_file(in_path, out_path)
|
|
end
|
|
end
|
|
|
|
def add_static(in_path, out_path)
|
|
$gemsmith[:static].push([in_path,out_path])
|
|
end
|
|
|
|
def add_file_string(out_path, data)
|
|
$gemsmith[:active].push({
|
|
dependencies: [],
|
|
out_path: out_path,
|
|
rel_dir: File.dirname(out_path),
|
|
stream: Pipeline.new(string: data)
|
|
})
|
|
end
|
|
|
|
def root_path(file = nil)
|
|
context = $gemsmith[:now_rendering].split(/#{File::SEPARATOR}/)
|
|
context.pop
|
|
context.shift if context[0] == ""
|
|
return file if context.empty?
|
|
ret = File.join( *([".."] * context.length))
|
|
return File.join(ret, file) unless file.nil?
|
|
return ret
|
|
end
|
|
|
|
def asset_path(asset)
|
|
target = $gemsmith[:assets][asset]
|
|
return "???" if target.nil?
|
|
root_path(target)
|
|
end
|
|
|
|
def all_outputs
|
|
$gemsmith[:active].map { |x| x[:out_path] }
|
|
end
|
|
|
|
def metadata_for(path)
|
|
$gemsmith[:active].find { |x| x[:out_path] == path }
|
|
end
|
|
end |